virtual.c revision 13496ba1
142542f5fSchristos/* 242542f5fSchristos * Copyright © 2013 Intel Corporation 342542f5fSchristos * 442542f5fSchristos * Permission is hereby granted, free of charge, to any person obtaining a 542542f5fSchristos * copy of this software and associated documentation files (the "Software"), 642542f5fSchristos * to deal in the Software without restriction, including without limitation 742542f5fSchristos * the rights to use, copy, modify, merge, publish, distribute, sublicense, 842542f5fSchristos * and/or sell copies of the Software, and to permit persons to whom the 942542f5fSchristos * Software is furnished to do so, subject to the following conditions: 1042542f5fSchristos * 1142542f5fSchristos * The above copyright notice and this permission notice (including the next 1242542f5fSchristos * paragraph) shall be included in all copies or substantial portions of the 1342542f5fSchristos * Software. 1442542f5fSchristos * 1542542f5fSchristos * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1642542f5fSchristos * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1742542f5fSchristos * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1842542f5fSchristos * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1942542f5fSchristos * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2042542f5fSchristos * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2142542f5fSchristos * IN THE SOFTWARE. 2242542f5fSchristos * 2342542f5fSchristos */ 2442542f5fSchristos 2542542f5fSchristos#ifdef HAVE_CONFIG_H 2642542f5fSchristos#include "config.h" 2742542f5fSchristos#endif 2842542f5fSchristos 2942542f5fSchristos#include <X11/Xlib.h> 3042542f5fSchristos#include <X11/Xatom.h> 3142542f5fSchristos 3242542f5fSchristos#include <X11/Xlibint.h> 3342542f5fSchristos#include <X11/extensions/record.h> 3442542f5fSchristos#include <X11/extensions/XShm.h> 3542542f5fSchristos#if HAVE_X11_EXTENSIONS_SHMPROTO_H 3642542f5fSchristos#include <X11/extensions/shmproto.h> 3742542f5fSchristos#elif HAVE_X11_EXTENSIONS_SHMSTR_H 3842542f5fSchristos#include <X11/extensions/shmstr.h> 3942542f5fSchristos#else 4042542f5fSchristos#error Failed to find the right header for X11 MIT-SHM protocol definitions 4142542f5fSchristos#endif 4242542f5fSchristos#include <X11/extensions/Xdamage.h> 4342542f5fSchristos#if HAVE_X11_EXTENSIONS_XINERAMA_H 4442542f5fSchristos#include <X11/extensions/Xinerama.h> 4542542f5fSchristos#define USE_XINERAMA 4642542f5fSchristos#endif 4742542f5fSchristos#include <X11/extensions/Xrandr.h> 4842542f5fSchristos#include <X11/extensions/Xrender.h> 4942542f5fSchristos#include <X11/Xcursor/Xcursor.h> 5042542f5fSchristos#include <pixman.h> 5142542f5fSchristos 5242542f5fSchristos#include <sys/types.h> 5342542f5fSchristos#include <sys/ipc.h> 5442542f5fSchristos#include <sys/shm.h> 5542542f5fSchristos#include <sys/timerfd.h> 5642542f5fSchristos#include <sys/poll.h> 5742542f5fSchristos#include <sys/socket.h> 5842542f5fSchristos#include <sys/un.h> 5942542f5fSchristos 6042542f5fSchristos#include <stdarg.h> 6142542f5fSchristos#include <stdio.h> 6242542f5fSchristos#include <stdlib.h> 6342542f5fSchristos#include <stdint.h> 6442542f5fSchristos#include <signal.h> 6542542f5fSchristos#include <getopt.h> 6642542f5fSchristos#include <limits.h> 6742542f5fSchristos#include <unistd.h> 6842542f5fSchristos#include <fcntl.h> 6942542f5fSchristos#include <assert.h> 7042542f5fSchristos 7142542f5fSchristos#define FORCE_FULL_REDRAW 0 7242542f5fSchristos#define FORCE_16BIT_XFER 0 7342542f5fSchristos 7442542f5fSchristos#define DBG(v, x) if (verbose & v) printf x 7542542f5fSchristosstatic int verbose; 7642542f5fSchristos#define X11 0x1 7742542f5fSchristos#define XRR 0x1 7842542f5fSchristos#define TIMER 0x4 7942542f5fSchristos#define DRAW 0x8 8042542f5fSchristos#define DAMAGE 0x10 8142542f5fSchristos#define CURSOR 0x20 8242542f5fSchristos#define POLL 0x40 8342542f5fSchristos 8442542f5fSchristosstruct display { 8542542f5fSchristos Display *dpy; 8642542f5fSchristos struct clone *clone; 8742542f5fSchristos struct context *ctx; 8842542f5fSchristos 8942542f5fSchristos int damage_event, damage_error; 9042542f5fSchristos int xfixes_event, xfixes_error; 9142542f5fSchristos int rr_event, rr_error, rr_active; 9242542f5fSchristos int xinerama_event, xinerama_error, xinerama_active; 9342542f5fSchristos int dri3_active; 9442542f5fSchristos Window root; 9542542f5fSchristos Visual *visual; 9642542f5fSchristos Damage damage; 9742542f5fSchristos 9842542f5fSchristos int width; 9942542f5fSchristos int height; 10042542f5fSchristos int depth; 10142542f5fSchristos 10242542f5fSchristos XRenderPictFormat *root_format; 10342542f5fSchristos XRenderPictFormat *rgb16_format; 10442542f5fSchristos XRenderPictFormat *rgb24_format; 10542542f5fSchristos 10642542f5fSchristos int has_shm; 10742542f5fSchristos int has_shm_pixmap; 10842542f5fSchristos int shm_opcode; 10942542f5fSchristos int shm_event; 11042542f5fSchristos 11142542f5fSchristos Cursor invisible_cursor; 11242542f5fSchristos Cursor visible_cursor; 11342542f5fSchristos 11442542f5fSchristos XcursorImage cursor_image; 11542542f5fSchristos int cursor_serial; 11642542f5fSchristos int cursor_x; 11742542f5fSchristos int cursor_y; 11842542f5fSchristos int cursor_moved; 11942542f5fSchristos int cursor_visible; 12042542f5fSchristos int cursor; 12142542f5fSchristos 12242542f5fSchristos int flush; 12342542f5fSchristos int send; 12442542f5fSchristos int skip_clone; 12542542f5fSchristos int skip_frame; 12642542f5fSchristos}; 12742542f5fSchristos 12842542f5fSchristosstruct output { 12942542f5fSchristos struct display *display; 13042542f5fSchristos Display *dpy; 13142542f5fSchristos char *name; 13242542f5fSchristos RROutput rr_output; 13342542f5fSchristos RRCrtc rr_crtc; 13442542f5fSchristos Window window; 13542542f5fSchristos Picture win_picture; 13642542f5fSchristos Picture pix_picture; 13742542f5fSchristos Pixmap pixmap; 13842542f5fSchristos GC gc; 13942542f5fSchristos 14042542f5fSchristos long serial; 14142542f5fSchristos int use_shm; 14242542f5fSchristos int use_shm_pixmap; 14342542f5fSchristos XShmSegmentInfo shm; 14442542f5fSchristos 14542542f5fSchristos XRenderPictFormat *use_render; 14642542f5fSchristos 14742542f5fSchristos int x, y; 14842542f5fSchristos XRRModeInfo mode; 14942542f5fSchristos Rotation rotation; 15042542f5fSchristos}; 15142542f5fSchristos 15242542f5fSchristosstruct clone { 15342542f5fSchristos struct clone *next; 15442542f5fSchristos struct clone *active; 15542542f5fSchristos 15642542f5fSchristos struct output src, dst; 15742542f5fSchristos long timestamp; 15842542f5fSchristos 15942542f5fSchristos XShmSegmentInfo shm; 16042542f5fSchristos XImage image; 16142542f5fSchristos 16242542f5fSchristos int width, height, depth; 16342542f5fSchristos struct { int x1, x2, y1, y2; } damaged; 16442542f5fSchristos int rr_update; 16542542f5fSchristos 16642542f5fSchristos struct dri3_fence { 16742542f5fSchristos XID xid; 16842542f5fSchristos void *addr; 16942542f5fSchristos } dri3; 17042542f5fSchristos}; 17142542f5fSchristos 17242542f5fSchristosstruct context { 17342542f5fSchristos struct display *display; 17442542f5fSchristos struct clone *clones; 17542542f5fSchristos struct clone *active; 17642542f5fSchristos struct pollfd *pfd; 17742542f5fSchristos#define timer pfd[0].fd 17842542f5fSchristos Display *record; 17942542f5fSchristos int nclone; 18042542f5fSchristos int ndisplay; 18142542f5fSchristos int nfd; 18242542f5fSchristos 18342542f5fSchristos int timer_active; 18442542f5fSchristos 18542542f5fSchristos long timestamp; 18642542f5fSchristos long configTimestamp; 18742542f5fSchristos 18842542f5fSchristos Atom singleton; 18942542f5fSchristos char command[1024]; 19042542f5fSchristos int command_continuation; 19142542f5fSchristos}; 19242542f5fSchristos 19342542f5fSchristosstatic inline int is_power_of_2(unsigned long n) 19442542f5fSchristos{ 19542542f5fSchristos return n && ((n & (n - 1)) == 0); 19642542f5fSchristos} 19742542f5fSchristos 19842542f5fSchristosstatic int xlib_vendor_is_xorg(Display *dpy) 19942542f5fSchristos{ 20042542f5fSchristos const char *const vendor = ServerVendor(dpy); 20142542f5fSchristos return strstr(vendor, "X.Org") || strstr(vendor, "Xorg"); 20242542f5fSchristos} 20342542f5fSchristos 20442542f5fSchristosstatic inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window) 20542542f5fSchristos{ 20642542f5fSchristos XRRScreenResources *res; 20742542f5fSchristos 20842542f5fSchristos res = XRRGetScreenResourcesCurrent(dpy, window); 20942542f5fSchristos if (res == NULL) 21042542f5fSchristos res = XRRGetScreenResources(dpy, window); 21142542f5fSchristos 21242542f5fSchristos return res; 21342542f5fSchristos} 21442542f5fSchristos 21542542f5fSchristos#define XORG_VERSION_ENCODE(major,minor,patch,snap) \ 21642542f5fSchristos (((major) * 10000000) + ((minor) * 100000) + ((patch) * 1000) + snap) 21742542f5fSchristos 21842542f5fSchristosstatic int _x_error_occurred; 21942542f5fSchristos 22042542f5fSchristosstatic int 22142542f5fSchristos_check_error_handler(Display *display, 22242542f5fSchristos XErrorEvent *event) 22342542f5fSchristos{ 22442542f5fSchristos DBG(X11, ("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n", 22542542f5fSchristos DisplayString(display), 22642542f5fSchristos event->serial, 22742542f5fSchristos event->error_code, 22842542f5fSchristos event->request_code, 22942542f5fSchristos event->minor_code)); 23042542f5fSchristos _x_error_occurred = 1; 23142542f5fSchristos return False; /* ignored */ 23242542f5fSchristos} 23342542f5fSchristos 23442542f5fSchristosstatic int 23542542f5fSchristoscan_use_shm(Display *dpy, 23642542f5fSchristos Window window, 23742542f5fSchristos int *shm_event, 23842542f5fSchristos int *shm_opcode, 23942542f5fSchristos int *shm_pixmap) 24042542f5fSchristos{ 24142542f5fSchristos XShmSegmentInfo shm; 24242542f5fSchristos Status success; 24342542f5fSchristos XExtCodes *codes; 24442542f5fSchristos int major, minor, has_shm, has_pixmap; 24542542f5fSchristos 24642542f5fSchristos if (!XShmQueryExtension(dpy)) 24742542f5fSchristos return 0; 24842542f5fSchristos 24942542f5fSchristos XShmQueryVersion(dpy, &major, &minor, &has_pixmap); 25042542f5fSchristos 25142542f5fSchristos shm.shmid = shmget(IPC_PRIVATE, 0x1000, IPC_CREAT | 0600); 25242542f5fSchristos if (shm.shmid == -1) 25342542f5fSchristos return 0; 25442542f5fSchristos 25542542f5fSchristos shm.readOnly = 0; 25642542f5fSchristos shm.shmaddr = shmat(shm.shmid, NULL, 0); 25742542f5fSchristos if (shm.shmaddr == (char *) -1) { 25842542f5fSchristos shmctl(shm.shmid, IPC_RMID, NULL); 25942542f5fSchristos return 0; 26042542f5fSchristos } 26142542f5fSchristos 26242542f5fSchristos XSync(dpy, False); 26342542f5fSchristos _x_error_occurred = 0; 26442542f5fSchristos 26542542f5fSchristos success = XShmAttach(dpy, &shm); 26642542f5fSchristos 26742542f5fSchristos XSync(dpy, False); 26842542f5fSchristos has_shm = success && _x_error_occurred == 0; 26942542f5fSchristos 27042542f5fSchristos /* As libXext sets the SEND_EVENT bit in the ShmCompletionEvent, 27142542f5fSchristos * the Xserver may crash if it does not take care when processing 27242542f5fSchristos * the event type. For instance versions of Xorg prior to 1.11.1 27342542f5fSchristos * exhibited this bug, and was fixed by: 27442542f5fSchristos * 27542542f5fSchristos * commit 2d2dce558d24eeea0eb011ec9ebaa6c5c2273c39 27642542f5fSchristos * Author: Sam Spilsbury <sam.spilsbury@canonical.com> 27742542f5fSchristos * Date: Wed Sep 14 09:58:34 2011 +0800 27842542f5fSchristos * 27942542f5fSchristos * Remove the SendEvent bit (0x80) before doing range checks on event type. 28042542f5fSchristos */ 28142542f5fSchristos codes = 0; 28242542f5fSchristos if (has_shm) 28342542f5fSchristos codes = XInitExtension(dpy, SHMNAME); 28442542f5fSchristos if (xlib_vendor_is_xorg(dpy) && 28542542f5fSchristos VendorRelease(dpy) < XORG_VERSION_ENCODE(1,11,0,1)) 28642542f5fSchristos codes = 0; 28742542f5fSchristos if (codes) { 28842542f5fSchristos XShmCompletionEvent e; 28942542f5fSchristos 29042542f5fSchristos memset(&e, 0, sizeof(e)); 29142542f5fSchristos 29242542f5fSchristos e.type = codes->first_event; 29342542f5fSchristos e.send_event = 1; 29442542f5fSchristos e.serial = 1; 29542542f5fSchristos e.drawable = window; 29642542f5fSchristos e.major_code = codes->major_opcode; 29742542f5fSchristos e.minor_code = X_ShmPutImage; 29842542f5fSchristos 29942542f5fSchristos e.shmseg = shm.shmid; 30042542f5fSchristos e.offset = 0; 30142542f5fSchristos 30242542f5fSchristos XSendEvent(dpy, e.drawable, False, 0, (XEvent *)&e); 30342542f5fSchristos XSync(dpy, False); 30442542f5fSchristos 30542542f5fSchristos if (_x_error_occurred == 0) { 30642542f5fSchristos *shm_opcode = codes->major_opcode; 30742542f5fSchristos *shm_event = codes->first_event; 30842542f5fSchristos *shm_pixmap = has_pixmap; 30942542f5fSchristos } 31042542f5fSchristos } 31142542f5fSchristos 31242542f5fSchristos XShmDetach(dpy, &shm); 31342542f5fSchristos shmctl(shm.shmid, IPC_RMID, NULL); 31442542f5fSchristos shmdt(shm.shmaddr); 31542542f5fSchristos 31642542f5fSchristos return has_shm; 31742542f5fSchristos} 31842542f5fSchristos 31942542f5fSchristos#ifdef DRI3 32042542f5fSchristos#include <X11/Xlib-xcb.h> 32142542f5fSchristos#include <X11/xshmfence.h> 32242542f5fSchristos#include <xcb/xcb.h> 32342542f5fSchristos#include <xcb/dri3.h> 32442542f5fSchristos#include <xcb/sync.h> 32542542f5fSchristosstatic Pixmap dri3_create_pixmap(Display *dpy, 32642542f5fSchristos Drawable draw, 32742542f5fSchristos int width, int height, int depth, 32842542f5fSchristos int fd, int bpp, int stride, int size) 32942542f5fSchristos{ 33042542f5fSchristos xcb_connection_t *c = XGetXCBConnection(dpy); 33142542f5fSchristos xcb_pixmap_t pixmap = xcb_generate_id(c); 33242542f5fSchristos xcb_dri3_pixmap_from_buffer(c, pixmap, draw, size, width, height, stride, depth, bpp, fd); 33342542f5fSchristos return pixmap; 33442542f5fSchristos} 33542542f5fSchristos 33642542f5fSchristosstatic int dri3_create_fd(Display *dpy, 33742542f5fSchristos Pixmap pixmap, 33842542f5fSchristos int *stride) 33942542f5fSchristos{ 34042542f5fSchristos xcb_connection_t *c = XGetXCBConnection(dpy); 34142542f5fSchristos xcb_dri3_buffer_from_pixmap_cookie_t cookie; 34242542f5fSchristos xcb_dri3_buffer_from_pixmap_reply_t *reply; 34342542f5fSchristos 34442542f5fSchristos cookie = xcb_dri3_buffer_from_pixmap(c, pixmap); 34542542f5fSchristos reply = xcb_dri3_buffer_from_pixmap_reply(c, cookie, NULL); 34642542f5fSchristos if (!reply) 34742542f5fSchristos return -1; 34842542f5fSchristos 34942542f5fSchristos if (reply->nfd != 1) 35042542f5fSchristos return -1; 35142542f5fSchristos 35242542f5fSchristos *stride = reply->stride; 35342542f5fSchristos return xcb_dri3_buffer_from_pixmap_reply_fds(c, reply)[0]; 35442542f5fSchristos} 35542542f5fSchristos 35642542f5fSchristosstatic int dri3_query_version(Display *dpy, int *major, int *minor) 35742542f5fSchristos{ 35842542f5fSchristos xcb_connection_t *c = XGetXCBConnection(dpy); 35942542f5fSchristos xcb_dri3_query_version_reply_t *reply; 36042542f5fSchristos 36142542f5fSchristos *major = *minor = -1; 36242542f5fSchristos 36342542f5fSchristos reply = xcb_dri3_query_version_reply(c, 36442542f5fSchristos xcb_dri3_query_version(c, 36542542f5fSchristos XCB_DRI3_MAJOR_VERSION, 36642542f5fSchristos XCB_DRI3_MINOR_VERSION), 36742542f5fSchristos NULL); 36842542f5fSchristos if (reply == NULL) 36942542f5fSchristos return -1; 37042542f5fSchristos 37142542f5fSchristos *major = reply->major_version; 37242542f5fSchristos *minor = reply->minor_version; 37342542f5fSchristos free(reply); 37442542f5fSchristos 37542542f5fSchristos return 0; 37642542f5fSchristos} 37742542f5fSchristos 37842542f5fSchristosstatic int dri3_exists(Display *dpy) 37942542f5fSchristos{ 38042542f5fSchristos int major, minor; 38142542f5fSchristos 38242542f5fSchristos if (dri3_query_version(dpy, &major, &minor) < 0) 38342542f5fSchristos return 0; 38442542f5fSchristos 38542542f5fSchristos return major >= 0; 38642542f5fSchristos} 38742542f5fSchristos 38842542f5fSchristosstatic void dri3_create_fence(Display *dpy, Drawable d, struct dri3_fence *fence) 38942542f5fSchristos{ 39042542f5fSchristos xcb_connection_t *c = XGetXCBConnection(dpy); 39142542f5fSchristos struct dri3_fence f; 39242542f5fSchristos int fd; 39342542f5fSchristos 39442542f5fSchristos fd = xshmfence_alloc_shm(); 39542542f5fSchristos if (fd < 0) 39642542f5fSchristos return; 39742542f5fSchristos 39842542f5fSchristos f.addr = xshmfence_map_shm(fd); 39942542f5fSchristos if (f.addr == NULL) { 40042542f5fSchristos close(fd); 40142542f5fSchristos return; 40242542f5fSchristos } 40342542f5fSchristos 40442542f5fSchristos f.xid = xcb_generate_id(c); 40542542f5fSchristos xcb_dri3_fence_from_fd(c, d, f.xid, 0, fd); 40642542f5fSchristos 40742542f5fSchristos *fence = f; 40842542f5fSchristos} 40942542f5fSchristos 41042542f5fSchristosstatic void dri3_fence_flush(Display *dpy, struct dri3_fence *fence) 41142542f5fSchristos{ 41242542f5fSchristos xcb_sync_trigger_fence(XGetXCBConnection(dpy), fence->xid); 41342542f5fSchristos} 41442542f5fSchristos 41542542f5fSchristosstatic void dri3_fence_free(Display *dpy, struct dri3_fence *fence) 41642542f5fSchristos{ 41742542f5fSchristos xshmfence_unmap_shm(fence->addr); 41842542f5fSchristos xcb_sync_destroy_fence(XGetXCBConnection(dpy), fence->xid); 41942542f5fSchristos} 42042542f5fSchristos 42142542f5fSchristos#else 42242542f5fSchristos 42342542f5fSchristosstatic int dri3_exists(Display *dpy) 42442542f5fSchristos{ 42542542f5fSchristos return 0; 42642542f5fSchristos} 42742542f5fSchristos 42842542f5fSchristosstatic void dri3_create_fence(Display *dpy, Drawable d, struct dri3_fence *fence) 42942542f5fSchristos{ 43042542f5fSchristos} 43142542f5fSchristos 43242542f5fSchristosstatic void dri3_fence_flush(Display *dpy, struct dri3_fence *fence) 43342542f5fSchristos{ 43442542f5fSchristos} 43542542f5fSchristos 43642542f5fSchristosstatic void dri3_fence_free(Display *dpy, struct dri3_fence *fence) 43742542f5fSchristos{ 43842542f5fSchristos} 43942542f5fSchristos 44042542f5fSchristosstatic Pixmap dri3_create_pixmap(Display *dpy, 44142542f5fSchristos Drawable draw, 44242542f5fSchristos int width, int height, int depth, 44342542f5fSchristos int fd, int bpp, int stride, int size) 44442542f5fSchristos{ 44542542f5fSchristos return None; 44642542f5fSchristos} 44742542f5fSchristos 44842542f5fSchristosstatic int dri3_create_fd(Display *dpy, 44942542f5fSchristos Pixmap pixmap, 45042542f5fSchristos int *stride) 45142542f5fSchristos{ 45242542f5fSchristos return -1; 45342542f5fSchristos} 45442542f5fSchristos#endif 45542542f5fSchristos 45642542f5fSchristosstatic int timerfd(int hz) 45742542f5fSchristos{ 45842542f5fSchristos struct itimerspec it; 45942542f5fSchristos int fd; 46042542f5fSchristos 46142542f5fSchristos fd = -1; 46242542f5fSchristos#ifdef CLOCK_MONOTONIC_COARSE 46342542f5fSchristos fd = timerfd_create(CLOCK_MONOTONIC_COARSE, TFD_NONBLOCK); 46442542f5fSchristos#endif 46542542f5fSchristos if (fd < 0) 46642542f5fSchristos fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); 46742542f5fSchristos if (fd < 0) 46842542f5fSchristos return -ETIME; 46942542f5fSchristos 47042542f5fSchristos it.it_interval.tv_sec = 0; 47142542f5fSchristos it.it_interval.tv_nsec = 1000000000 / hz; 47242542f5fSchristos it.it_value = it.it_interval; 47342542f5fSchristos if (timerfd_settime(fd, 0, &it, NULL) < 0) { 47442542f5fSchristos close(fd); 47542542f5fSchristos return -ETIME; 47642542f5fSchristos } 47742542f5fSchristos 47842542f5fSchristos return fd; 47942542f5fSchristos} 48042542f5fSchristos 48142542f5fSchristosstatic int context_init(struct context *ctx) 48242542f5fSchristos{ 48342542f5fSchristos struct pollfd *pfd; 48442542f5fSchristos 48542542f5fSchristos memset(ctx, 0, sizeof(*ctx)); 48642542f5fSchristos 48742542f5fSchristos ctx->pfd = malloc(2*sizeof(struct pollfd)); 48842542f5fSchristos if (ctx->pfd == NULL) 48942542f5fSchristos return -ENOMEM; 49042542f5fSchristos 49142542f5fSchristos ctx->clones = malloc(sizeof(struct clone)); 49242542f5fSchristos if (ctx->clones == NULL) 49342542f5fSchristos return -ENOMEM; 49442542f5fSchristos 49542542f5fSchristos ctx->display = malloc(sizeof(struct display)); 49642542f5fSchristos if (ctx->display == NULL) 49742542f5fSchristos return -ENOMEM; 49842542f5fSchristos 49942542f5fSchristos pfd = memset(&ctx->pfd[ctx->nfd++], 0, sizeof(struct pollfd)); 50042542f5fSchristos pfd->fd = timerfd(60); 50142542f5fSchristos if (pfd->fd < 0) 50242542f5fSchristos return pfd->fd; 50342542f5fSchristos pfd->events = POLLIN; 50442542f5fSchristos 50542542f5fSchristos return 0; 50642542f5fSchristos} 50742542f5fSchristos 50842542f5fSchristosstatic void context_enable_timer(struct context *ctx) 50942542f5fSchristos{ 51042542f5fSchristos uint64_t count; 51142542f5fSchristos 51242542f5fSchristos DBG(TIMER, ("%s timer active? %d\n", __func__, ctx->timer_active)); 51342542f5fSchristos 51442542f5fSchristos if (ctx->timer_active) 51542542f5fSchristos return; 51642542f5fSchristos 51742542f5fSchristos /* reset timer */ 51842542f5fSchristos count = read(ctx->timer, &count, sizeof(count)); 51942542f5fSchristos 52042542f5fSchristos ctx->timer_active = 1; 52142542f5fSchristos} 52242542f5fSchristos 52342542f5fSchristosstatic int add_fd(struct context *ctx, int fd) 52442542f5fSchristos{ 52542542f5fSchristos struct pollfd *pfd; 52642542f5fSchristos 52742542f5fSchristos if (fd < 0) 52842542f5fSchristos return fd; 52942542f5fSchristos 53042542f5fSchristos if (is_power_of_2(ctx->nfd)) { 53142542f5fSchristos ctx->pfd = realloc(ctx->pfd, 2*ctx->nfd*sizeof(struct pollfd)); 53242542f5fSchristos if (ctx->pfd == NULL) 53342542f5fSchristos return -ENOMEM; 53442542f5fSchristos } 53542542f5fSchristos 53642542f5fSchristos pfd = memset(&ctx->pfd[ctx->nfd++], 0, sizeof(struct pollfd)); 53742542f5fSchristos pfd->fd = fd; 53842542f5fSchristos pfd->events = POLLIN; 53942542f5fSchristos return 0; 54042542f5fSchristos} 54142542f5fSchristos 54242542f5fSchristosstatic void display_mark_flush(struct display *display) 54342542f5fSchristos{ 54442542f5fSchristos DBG(DRAW, ("%s mark flush (flush=%d)\n", 54542542f5fSchristos DisplayString(display->dpy), display->flush)); 54642542f5fSchristos 54742542f5fSchristos if (display->flush) 54842542f5fSchristos return; 54942542f5fSchristos 55042542f5fSchristos context_enable_timer(display->ctx); 55142542f5fSchristos display->flush = 1; 55242542f5fSchristos} 55342542f5fSchristos 55442542f5fSchristosstatic int mode_equal(const XRRModeInfo *a, const XRRModeInfo *b) 55542542f5fSchristos{ 55642542f5fSchristos return (a->width == b->width && 55742542f5fSchristos a->height == b->height && 55842542f5fSchristos a->dotClock == b->dotClock && 55942542f5fSchristos a->hSyncStart == b->hSyncStart && 56042542f5fSchristos a->hSyncEnd == b->hSyncEnd && 56142542f5fSchristos a->hTotal == b->hTotal && 56242542f5fSchristos a->hSkew == b->hSkew && 56342542f5fSchristos a->vSyncStart == b->vSyncStart && 56442542f5fSchristos a->vSyncEnd == b->vSyncEnd && 56542542f5fSchristos a->vTotal == b->vTotal && 56642542f5fSchristos a->modeFlags == b->modeFlags); 56742542f5fSchristos} 56842542f5fSchristos 56942542f5fSchristosstatic XRRModeInfo *lookup_mode(XRRScreenResources *res, int id) 57042542f5fSchristos{ 57142542f5fSchristos int i; 57242542f5fSchristos 57342542f5fSchristos for (i = 0; i < res->nmode; i++) { 57442542f5fSchristos if (res->modes[i].id == id) 57542542f5fSchristos return &res->modes[i]; 57642542f5fSchristos } 57742542f5fSchristos 57842542f5fSchristos return NULL; 57942542f5fSchristos} 58042542f5fSchristos 58142542f5fSchristosstatic void clone_update_edid(struct clone *clone) 58242542f5fSchristos{ 58342542f5fSchristos unsigned long nitems, after; 58442542f5fSchristos unsigned char *data; 58542542f5fSchristos int format; 58642542f5fSchristos Atom type; 58742542f5fSchristos 58842542f5fSchristos if (XRRGetOutputProperty(clone->dst.dpy, clone->dst.rr_output, 58942542f5fSchristos XInternAtom(clone->dst.dpy, "EDID", False), 59042542f5fSchristos 0, 100, False, False, AnyPropertyType, 59142542f5fSchristos &type, &format, &nitems, &after, &data) == Success) { 59242542f5fSchristos XRRChangeOutputProperty(clone->src.dpy, clone->src.rr_output, 59342542f5fSchristos XInternAtom(clone->src.dpy, "EDID", False), 59442542f5fSchristos type, format, PropModeReplace, data, nitems); 59542542f5fSchristos } 59642542f5fSchristos} 59742542f5fSchristos 59842542f5fSchristosstatic int disable_crtc(Display *dpy, XRRScreenResources *res, RRCrtc crtc) 59942542f5fSchristos{ 60042542f5fSchristos XRRPanning panning; 60142542f5fSchristos 60242542f5fSchristos if (crtc) { 60342542f5fSchristos XRRSetPanning(dpy, res, crtc, memset(&panning, 0, sizeof(panning))); 60442542f5fSchristos 60542542f5fSchristos if (XRRSetCrtcConfig(dpy, res, crtc, CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0) != Success) 60642542f5fSchristos return 0; 60742542f5fSchristos 60842542f5fSchristos if (XRRSetPanning(dpy, res, crtc, memset(&panning, 0, sizeof(panning))) != Success) { 60942542f5fSchristos DBG(XRR, ("%s failed to clear panning on CRTC:%ld\n", DisplayString(dpy), (long)crtc)); 61042542f5fSchristos if (verbose) { 61142542f5fSchristos XRRCrtcInfo *c; 61242542f5fSchristos XRRPanning *p; 61342542f5fSchristos 61442542f5fSchristos c = XRRGetCrtcInfo(dpy, res, crtc); 61542542f5fSchristos if (c) { 61642542f5fSchristos DBG(XRR, ("%s CRTC:%ld x=%d, y=%d, rotation=%d, mode=%ld\n", 61742542f5fSchristos DisplayString(dpy), (long)crtc, 61842542f5fSchristos c->x, c->y, c->rotation, c->mode)); 61942542f5fSchristos XRRFreeCrtcInfo(c); 62042542f5fSchristos } 62142542f5fSchristos 62242542f5fSchristos p = XRRGetPanning(dpy, res, crtc); 62342542f5fSchristos if (p) { 62442542f5fSchristos DBG(XRR, ("%s CRTC:%ld panning (%d, %d)x(%d, %d), tracking (%d, %d)x(%d, %d), border (%d, %d),(%d, %d)\n", 62542542f5fSchristos DisplayString(dpy), (long)crtc, 62642542f5fSchristos p->left, p->top, p->width, p->height, 62742542f5fSchristos p->track_left, p->track_top, p->track_width, p->track_height, 62842542f5fSchristos p->border_left, p->border_top, p->border_right, p->border_bottom)); 62942542f5fSchristos XRRFreePanning(p); 63042542f5fSchristos } 63142542f5fSchristos } 63242542f5fSchristos } 63342542f5fSchristos } 63442542f5fSchristos 63542542f5fSchristos return 1; 63642542f5fSchristos} 63742542f5fSchristos 63842542f5fSchristosstatic int clone_update_modes__randr(struct clone *clone) 63942542f5fSchristos{ 64042542f5fSchristos XRRScreenResources *from_res = NULL, *to_res = NULL; 64142542f5fSchristos XRROutputInfo *from_info = NULL, *to_info = NULL; 64242542f5fSchristos int i, j, ret = ENOENT; 64342542f5fSchristos 64442542f5fSchristos assert(clone->src.rr_output); 64542542f5fSchristos assert(clone->dst.rr_output); 64642542f5fSchristos assert(clone->dst.display->rr_event); 64742542f5fSchristos 64842542f5fSchristos from_res = _XRRGetScreenResourcesCurrent(clone->dst.dpy, clone->dst.window); 64942542f5fSchristos if (from_res == NULL) 65042542f5fSchristos goto err; 65142542f5fSchristos 65242542f5fSchristos from_info = XRRGetOutputInfo(clone->dst.dpy, from_res, clone->dst.rr_output); 65342542f5fSchristos if (from_info == NULL) 65442542f5fSchristos goto err; 65542542f5fSchristos 65642542f5fSchristos DBG(XRR, ("%s(%s-%s <- %s-%s): timestamp %ld (last %ld)\n", __func__, 65742542f5fSchristos DisplayString(clone->src.dpy), clone->src.name, 65842542f5fSchristos DisplayString(clone->dst.dpy), clone->dst.name, 65942542f5fSchristos from_info->timestamp, clone->timestamp)); 66042542f5fSchristos 66142542f5fSchristos to_res = _XRRGetScreenResourcesCurrent(clone->src.dpy, clone->src.window); 66242542f5fSchristos if (to_res == NULL) 66342542f5fSchristos goto err; 66442542f5fSchristos 66542542f5fSchristos to_info = XRRGetOutputInfo(clone->src.dpy, to_res, clone->src.rr_output); 66642542f5fSchristos if (to_info == NULL) 66742542f5fSchristos goto err; 66842542f5fSchristos 66942542f5fSchristos DBG(XRR, ("%s: dst.rr_crtc=%ld, now %ld\n", 67042542f5fSchristos __func__, (long)clone->dst.rr_crtc, (long)from_info->crtc)); 67142542f5fSchristos if (clone->dst.rr_crtc == from_info->crtc) { 67242542f5fSchristos for (i = 0; i < to_info->nmode; i++) { 67342542f5fSchristos XRRModeInfo *mode, *old; 67442542f5fSchristos 67542542f5fSchristos mode = lookup_mode(to_res, to_info->modes[i]); 67642542f5fSchristos if (mode == NULL) 67742542f5fSchristos break; 67842542f5fSchristos 67942542f5fSchristos DBG(XRR, ("%s(%s-%s): lookup mode %s\n", __func__, 68042542f5fSchristos DisplayString(clone->src.dpy), clone->src.name, 68142542f5fSchristos mode->name)); 68242542f5fSchristos 68342542f5fSchristos for (j = 0; j < from_info->nmode; j++) { 68442542f5fSchristos old = lookup_mode(from_res, from_info->modes[j]); 68542542f5fSchristos if (old && mode_equal(mode, old)) { 68642542f5fSchristos mode = NULL; 68742542f5fSchristos break; 68842542f5fSchristos } 68942542f5fSchristos } 69042542f5fSchristos if (mode) { 69142542f5fSchristos DBG(XRR, ("%s(%s-%s): unknown mode %s\n", __func__, 69242542f5fSchristos DisplayString(clone->src.dpy), clone->src.name, 69342542f5fSchristos mode->name)); 69442542f5fSchristos break; 69542542f5fSchristos } 69642542f5fSchristos } 69742542f5fSchristos if (i == from_info->nmode && i == to_info->nmode) { 69842542f5fSchristos DBG(XRR, ("%s(%s-%s): no change in output\n", __func__, 69942542f5fSchristos DisplayString(clone->src.dpy), clone->src.name)); 70042542f5fSchristos goto done; 70142542f5fSchristos } 70242542f5fSchristos } 70342542f5fSchristos 70442542f5fSchristos /* Disable the remote output */ 70542542f5fSchristos if (from_info->crtc != clone->dst.rr_crtc) { 70642542f5fSchristos DBG(XRR, ("%s(%s-%s): disabling active CRTC\n", __func__, 70742542f5fSchristos DisplayString(clone->dst.dpy), clone->dst.name)); 70842542f5fSchristos if (disable_crtc(clone->dst.dpy, from_res, from_info->crtc)) { 70942542f5fSchristos clone->dst.rr_crtc = 0; 71042542f5fSchristos clone->dst.mode.id = 0; 71142542f5fSchristos } else { 71242542f5fSchristos XRRCrtcInfo *c = XRRGetCrtcInfo(clone->dst.dpy, from_res, from_info->crtc); 71342542f5fSchristos if (c) { 71442542f5fSchristos clone->dst.x = c->x; 71542542f5fSchristos clone->dst.y = c->y; 71642542f5fSchristos clone->dst.rotation = c->rotation; 71742542f5fSchristos clone->dst.mode.id = c->mode; 71842542f5fSchristos XRRFreeCrtcInfo(c); 71942542f5fSchristos } 72042542f5fSchristos } 72142542f5fSchristos } 72242542f5fSchristos 72342542f5fSchristos /* Create matching modes for the real output on the virtual */ 72442542f5fSchristos XGrabServer(clone->src.dpy); 72542542f5fSchristos 72642542f5fSchristos /* Clear all current UserModes on the output, including any active ones */ 72742542f5fSchristos if (to_info->crtc) { 72842542f5fSchristos DBG(XRR, ("%s(%s-%s): disabling active CRTC\n", __func__, 72942542f5fSchristos DisplayString(clone->src.dpy), clone->src.name)); 73042542f5fSchristos disable_crtc(clone->src.dpy, to_res, to_info->crtc); 73142542f5fSchristos } 73242542f5fSchristos for (i = 0; i < to_info->nmode; i++) { 73342542f5fSchristos DBG(XRR, ("%s(%s-%s): deleting mode %ld\n", __func__, 73442542f5fSchristos DisplayString(clone->src.dpy), clone->src.name, (long)to_info->modes[i])); 73542542f5fSchristos XRRDeleteOutputMode(clone->src.dpy, clone->src.rr_output, to_info->modes[i]); 73642542f5fSchristos } 73742542f5fSchristos 73842542f5fSchristos clone->src.rr_crtc = 0; 73942542f5fSchristos 74042542f5fSchristos for (i = 0; i < from_info->nmode; i++) { 74142542f5fSchristos XRRModeInfo *mode, *old; 74242542f5fSchristos RRMode id; 74342542f5fSchristos 74442542f5fSchristos mode = lookup_mode(from_res, from_info->modes[i]); 74542542f5fSchristos if (mode == NULL) 74642542f5fSchristos continue; 74742542f5fSchristos for (j = 0; j < i; j++) { 74842542f5fSchristos old = lookup_mode(from_res, from_info->modes[j]); 74942542f5fSchristos if (old && mode_equal(mode, old)) { 75042542f5fSchristos mode = NULL; 75142542f5fSchristos break; 75242542f5fSchristos } 75342542f5fSchristos } 75442542f5fSchristos if (mode == NULL) 75542542f5fSchristos continue; 75642542f5fSchristos 75742542f5fSchristos id = 0; 75842542f5fSchristos for (j = 0; j < to_res->nmode; j++) { 75942542f5fSchristos old = &to_res->modes[j]; 76042542f5fSchristos if (mode_equal(mode, old)) { 76142542f5fSchristos id = old->id; 76242542f5fSchristos DBG(XRR, ("%s(%s-%s): reusing mode %ld: %s\n", __func__, 76342542f5fSchristos DisplayString(clone->src.dpy), clone->src.name, id, mode->name)); 76442542f5fSchristos break; 76542542f5fSchristos } 76642542f5fSchristos } 76742542f5fSchristos if (id == 0) { 76842542f5fSchristos XRRModeInfo m; 76942542f5fSchristos char buf[256]; 77042542f5fSchristos 77142542f5fSchristos /* XXX User names must be unique! */ 77242542f5fSchristos m = *mode; 77342542f5fSchristos m.nameLength = snprintf(buf, sizeof(buf), 77442542f5fSchristos "%s.%ld-%s", clone->src.name, (long)from_info->modes[i], mode->name); 77542542f5fSchristos m.name = buf; 77642542f5fSchristos 77742542f5fSchristos id = XRRCreateMode(clone->src.dpy, clone->src.window, &m); 77842542f5fSchristos DBG(XRR, ("%s(%s-%s): adding mode %ld: %s\n", __func__, 77942542f5fSchristos DisplayString(clone->src.dpy), clone->src.name, id, mode->name)); 78042542f5fSchristos } 78142542f5fSchristos 78242542f5fSchristos XRRAddOutputMode(clone->src.dpy, clone->src.rr_output, id); 78342542f5fSchristos } 78442542f5fSchristos clone_update_edid(clone); 78542542f5fSchristos XUngrabServer(clone->src.dpy); 78642542f5fSchristosdone: 78742542f5fSchristos ret = 0; 78842542f5fSchristos clone->timestamp = from_info->timestamp; 78942542f5fSchristos 79042542f5fSchristoserr: 79142542f5fSchristos if (to_info) 79242542f5fSchristos XRRFreeOutputInfo(to_info); 79342542f5fSchristos if (to_res) 79442542f5fSchristos XRRFreeScreenResources(to_res); 79542542f5fSchristos if (from_info) 79642542f5fSchristos XRRFreeOutputInfo(from_info); 79742542f5fSchristos if (from_res) 79842542f5fSchristos XRRFreeScreenResources(from_res); 79942542f5fSchristos 80042542f5fSchristos return ret; 80142542f5fSchristos} 80242542f5fSchristos 80342542f5fSchristosstatic int clone_update_modes__fixed(struct clone *clone) 80442542f5fSchristos{ 80542542f5fSchristos char mode_name[80]; 80642542f5fSchristos XRRScreenResources *res = NULL; 80742542f5fSchristos XRROutputInfo *info = NULL; 80842542f5fSchristos XRRModeInfo mode; 80942542f5fSchristos RRMode id; 81042542f5fSchristos int i, j, ret = ENOENT; 81142542f5fSchristos 81242542f5fSchristos assert(clone->src.rr_output); 81342542f5fSchristos 81442542f5fSchristos res = _XRRGetScreenResourcesCurrent(clone->src.dpy, clone->src.window); 81542542f5fSchristos if (res == NULL) 81642542f5fSchristos goto err; 81742542f5fSchristos 81842542f5fSchristos info = XRRGetOutputInfo(clone->src.dpy, res, clone->src.rr_output); 81942542f5fSchristos if (info == NULL) 82042542f5fSchristos goto err; 82142542f5fSchristos 82242542f5fSchristos XGrabServer(clone->src.dpy); 82342542f5fSchristos 82442542f5fSchristos /* Clear all current UserModes on the output, including any active ones */ 82542542f5fSchristos if (info->crtc) { 82642542f5fSchristos DBG(XRR, ("%s(%s-%s): disabling active CRTC\n", __func__, 82742542f5fSchristos DisplayString(clone->src.dpy), clone->src.name)); 82842542f5fSchristos disable_crtc(clone->src.dpy, res, info->crtc); 82942542f5fSchristos } 83042542f5fSchristos for (i = 0; i < info->nmode; i++) { 83142542f5fSchristos DBG(XRR, ("%s(%s-%s): deleting mode %ld\n", __func__, 83242542f5fSchristos DisplayString(clone->src.dpy), clone->src.name, (long)info->modes[i])); 83342542f5fSchristos XRRDeleteOutputMode(clone->src.dpy, clone->src.rr_output, info->modes[i]); 83442542f5fSchristos } 83542542f5fSchristos 83642542f5fSchristos clone->src.rr_crtc = 0; 83742542f5fSchristos 83842542f5fSchristos /* Create matching mode for the real output on the virtual */ 83942542f5fSchristos memset(&mode, 0, sizeof(mode)); 84042542f5fSchristos mode.width = clone->width; 84142542f5fSchristos mode.height = clone->height; 84242542f5fSchristos mode.nameLength = sprintf(mode_name, "FAKE-%dx%d", mode.width, mode.height); 84342542f5fSchristos mode.name = mode_name; 84442542f5fSchristos 84542542f5fSchristos id = 0; 84642542f5fSchristos for (j = 0; j < res->nmode; j++) { 84742542f5fSchristos if (mode_equal(&mode, &res->modes[j])) { 84842542f5fSchristos id = res->modes[j].id; 84942542f5fSchristos break; 85042542f5fSchristos } 85142542f5fSchristos } 85242542f5fSchristos if (id == 0) 85342542f5fSchristos id = XRRCreateMode(clone->src.dpy, clone->src.window, &mode); 85442542f5fSchristos 85542542f5fSchristos XRRAddOutputMode(clone->src.dpy, clone->src.rr_output, id); 85642542f5fSchristos 85742542f5fSchristos XUngrabServer(clone->src.dpy); 85842542f5fSchristos ret = 0; 85942542f5fSchristoserr: 86042542f5fSchristos if (info) 86142542f5fSchristos XRRFreeOutputInfo(info); 86242542f5fSchristos if (res) 86342542f5fSchristos XRRFreeScreenResources(res); 86442542f5fSchristos 86542542f5fSchristos return ret; 86642542f5fSchristos} 86742542f5fSchristos 86842542f5fSchristosstatic RROutput claim_virtual(struct display *display, char *output_name, int nclone) 86942542f5fSchristos{ 87042542f5fSchristos char mode_name[] = "ClaimVirtualHead"; 87142542f5fSchristos Display *dpy = display->dpy; 87242542f5fSchristos XRRScreenResources *res; 87342542f5fSchristos XRROutputInfo *output; 87442542f5fSchristos XRRModeInfo mode; 87542542f5fSchristos RRMode id; 87642542f5fSchristos RROutput rr_output = 0; 87742542f5fSchristos int i; 87842542f5fSchristos 87942542f5fSchristos DBG(X11, ("%s(%d)\n", __func__, nclone)); 88042542f5fSchristos XGrabServer(dpy); 88142542f5fSchristos 88242542f5fSchristos res = _XRRGetScreenResourcesCurrent(dpy, display->root); 88342542f5fSchristos if (res == NULL) 88442542f5fSchristos goto out; 88542542f5fSchristos 88642542f5fSchristos sprintf(output_name, "VIRTUAL%d", nclone); 88742542f5fSchristos 88842542f5fSchristos for (i = rr_output = 0; rr_output == 0 && i < res->noutput; i++) { 88942542f5fSchristos output = XRRGetOutputInfo(dpy, res, res->outputs[i]); 89042542f5fSchristos if (output == NULL) 89142542f5fSchristos continue; 89242542f5fSchristos 89342542f5fSchristos if (strcmp(output->name, output_name) == 0) 89442542f5fSchristos rr_output = res->outputs[i]; 89542542f5fSchristos 89642542f5fSchristos XRRFreeOutputInfo(output); 89742542f5fSchristos } 89842542f5fSchristos for (i = id = 0; id == 0 && i < res->nmode; i++) { 89942542f5fSchristos if (strcmp(res->modes[i].name, mode_name) == 0) 90042542f5fSchristos id = res->modes[i].id; 90142542f5fSchristos } 90242542f5fSchristos XRRFreeScreenResources(res); 90342542f5fSchristos 90442542f5fSchristos DBG(XRR, ("%s(%s): rr_output=%ld\n", __func__, output_name, (long)rr_output)); 90542542f5fSchristos if (rr_output == 0) 90642542f5fSchristos goto out; 90742542f5fSchristos 90842542f5fSchristos /* Set any mode on the VirtualHead to make the Xserver allocate another */ 90942542f5fSchristos memset(&mode, 0, sizeof(mode)); 91042542f5fSchristos mode.width = 1024; 91142542f5fSchristos mode.height = 768; 91242542f5fSchristos mode.name = mode_name; 91342542f5fSchristos mode.nameLength = sizeof(mode_name) - 1; 91442542f5fSchristos 91542542f5fSchristos if (id == 0) 91642542f5fSchristos id = XRRCreateMode(dpy, display->root, &mode); 91742542f5fSchristos XRRAddOutputMode(dpy, rr_output, id); 91842542f5fSchristos 91942542f5fSchristos /* Force a redetection for the ddx to spot the new outputs */ 92042542f5fSchristos res = XRRGetScreenResources(dpy, display->root); 92142542f5fSchristos if (res == NULL) 92242542f5fSchristos goto out; 92342542f5fSchristos 92442542f5fSchristos /* Some else may have interrupted us and installed that new mode! */ 92542542f5fSchristos output = XRRGetOutputInfo(dpy, res, rr_output); 92642542f5fSchristos if (output) { 92742542f5fSchristos disable_crtc(dpy, res, output->crtc); 92842542f5fSchristos XRRFreeOutputInfo(output); 92942542f5fSchristos } 93042542f5fSchristos XRRFreeScreenResources(res); 93142542f5fSchristos 93242542f5fSchristos XRRDeleteOutputMode(dpy, rr_output, id); 93342542f5fSchristos XRRDestroyMode(dpy, id); 93442542f5fSchristos 93542542f5fSchristos /* And hide it again */ 93642542f5fSchristos res = XRRGetScreenResources(dpy, display->root); 93742542f5fSchristos if (res != NULL) 93842542f5fSchristos XRRFreeScreenResources(res); 93942542f5fSchristosout: 94042542f5fSchristos XUngrabServer(dpy); 94142542f5fSchristos 94242542f5fSchristos return rr_output; 94342542f5fSchristos} 94442542f5fSchristos 94542542f5fSchristosstatic int stride_for_depth(int width, int depth) 94642542f5fSchristos{ 94742542f5fSchristos if (depth == 24) 94842542f5fSchristos depth = 32; 94942542f5fSchristos return ((width * depth + 7) / 8 + 3) & ~3; 95042542f5fSchristos} 95142542f5fSchristos 95242542f5fSchristosstatic void init_image(struct clone *clone) 95342542f5fSchristos{ 95442542f5fSchristos XImage *image = &clone->image; 95542542f5fSchristos int ret; 95642542f5fSchristos 95742542f5fSchristos image->width = clone->width; 95842542f5fSchristos image->height = clone->height; 95942542f5fSchristos image->format = ZPixmap; 96042542f5fSchristos image->xoffset = 0; 96142542f5fSchristos image->byte_order = LSBFirst; 96242542f5fSchristos image->bitmap_unit = 32; 96342542f5fSchristos image->bitmap_bit_order = LSBFirst; 96442542f5fSchristos image->bitmap_pad = 32; 96542542f5fSchristos image->data = clone->shm.shmaddr; 96642542f5fSchristos image->bytes_per_line = stride_for_depth(clone->width, clone->depth); 96742542f5fSchristos switch (clone->depth) { 96842542f5fSchristos case 24: 96942542f5fSchristos image->red_mask = 0xff << 16; 97042542f5fSchristos image->green_mask = 0xff << 8; 97142542f5fSchristos image->blue_mask = 0xff << 0;; 97242542f5fSchristos image->depth = 24; 97342542f5fSchristos image->bits_per_pixel = 32; 97442542f5fSchristos break; 97542542f5fSchristos case 16: 97642542f5fSchristos image->red_mask = 0x1f << 11; 97742542f5fSchristos image->green_mask = 0x3f << 5; 97842542f5fSchristos image->blue_mask = 0x1f << 0;; 97942542f5fSchristos image->depth = 16; 98042542f5fSchristos image->bits_per_pixel = 16; 98142542f5fSchristos break; 98242542f5fSchristos } 98342542f5fSchristos 98442542f5fSchristos ret = XInitImage(image); 98542542f5fSchristos assert(ret); 98642542f5fSchristos (void)ret; 98742542f5fSchristos} 98842542f5fSchristos 98942542f5fSchristosstatic int mode_height(const XRRModeInfo *mode, Rotation rotation) 99042542f5fSchristos{ 99142542f5fSchristos switch (rotation & 0xf) { 99242542f5fSchristos case RR_Rotate_0: 99342542f5fSchristos case RR_Rotate_180: 99442542f5fSchristos return mode->height; 99542542f5fSchristos case RR_Rotate_90: 99642542f5fSchristos case RR_Rotate_270: 99742542f5fSchristos return mode->width; 99842542f5fSchristos default: 99942542f5fSchristos return 0; 100042542f5fSchristos } 100142542f5fSchristos} 100242542f5fSchristos 100342542f5fSchristosstatic int mode_width(const XRRModeInfo *mode, Rotation rotation) 100442542f5fSchristos{ 100542542f5fSchristos switch (rotation & 0xf) { 100642542f5fSchristos case RR_Rotate_0: 100742542f5fSchristos case RR_Rotate_180: 100842542f5fSchristos return mode->width; 100942542f5fSchristos case RR_Rotate_90: 101042542f5fSchristos case RR_Rotate_270: 101142542f5fSchristos return mode->height; 101242542f5fSchristos default: 101342542f5fSchristos return 0; 101442542f5fSchristos } 101542542f5fSchristos} 101642542f5fSchristos 101742542f5fSchristosstatic void output_init_xfer(struct clone *clone, struct output *output) 101842542f5fSchristos{ 101942542f5fSchristos if (output->pixmap == None && output->use_shm_pixmap) { 102042542f5fSchristos DBG(DRAW, ("%s-%s: creating shm pixmap\n", DisplayString(output->dpy), output->name)); 102142542f5fSchristos XSync(output->dpy, False); 102242542f5fSchristos _x_error_occurred = 0; 102342542f5fSchristos 102442542f5fSchristos output->pixmap = XShmCreatePixmap(output->dpy, output->window, 102542542f5fSchristos clone->shm.shmaddr, &output->shm, 102642542f5fSchristos clone->width, clone->height, clone->depth); 102742542f5fSchristos if (output->pix_picture) { 102842542f5fSchristos XRenderFreePicture(output->dpy, output->pix_picture); 102942542f5fSchristos output->pix_picture = None; 103042542f5fSchristos } 103142542f5fSchristos 103242542f5fSchristos XSync(output->dpy, False); 103342542f5fSchristos if (_x_error_occurred) { 103442542f5fSchristos XFreePixmap(output->dpy, output->pixmap); 103542542f5fSchristos output->pixmap = None; 103642542f5fSchristos output->use_shm_pixmap = 0; 103742542f5fSchristos } 103842542f5fSchristos } 103942542f5fSchristos if (output->use_render) { 104042542f5fSchristos DBG(DRAW, ("%s-%s: creating picture\n", DisplayString(output->dpy), output->name)); 104142542f5fSchristos if (output->win_picture == None) 104242542f5fSchristos output->win_picture = XRenderCreatePicture(output->dpy, output->window, 104342542f5fSchristos output->display->root_format, 0, NULL); 104442542f5fSchristos if (output->pixmap == None) 104542542f5fSchristos output->pixmap = XCreatePixmap(output->dpy, output->window, 104642542f5fSchristos clone->width, clone->height, clone->depth); 104742542f5fSchristos if (output->pix_picture == None) 104842542f5fSchristos output->pix_picture = XRenderCreatePicture(output->dpy, output->pixmap, 104942542f5fSchristos output->use_render, 0, NULL); 105042542f5fSchristos } 105142542f5fSchristos 105242542f5fSchristos if (output->gc == None) { 105342542f5fSchristos XGCValues gcv; 105442542f5fSchristos 105542542f5fSchristos DBG(DRAW, ("%s-%s: creating gc\n", DisplayString(output->dpy), output->name)); 105642542f5fSchristos 105742542f5fSchristos gcv.graphics_exposures = False; 105842542f5fSchristos gcv.subwindow_mode = IncludeInferiors; 105942542f5fSchristos 106042542f5fSchristos output->gc = XCreateGC(output->dpy, output->pixmap ?: output->window, GCGraphicsExposures | GCSubwindowMode, &gcv); 106142542f5fSchristos } 106242542f5fSchristos} 106342542f5fSchristos 106442542f5fSchristosstatic int bpp_for_depth(int depth) 106542542f5fSchristos{ 106642542f5fSchristos switch (depth) { 106742542f5fSchristos case 1: return 1; 106842542f5fSchristos case 8: return 8; 106942542f5fSchristos case 15: return 16; 107042542f5fSchristos case 16: return 16; 107142542f5fSchristos case 24: return 24; 107242542f5fSchristos case 32: return 32; 107342542f5fSchristos default: return 0; 107442542f5fSchristos } 107542542f5fSchristos} 107642542f5fSchristos 107742542f5fSchristosstatic int clone_init_xfer(struct clone *clone) 107842542f5fSchristos{ 107942542f5fSchristos int width, height; 108042542f5fSchristos 108142542f5fSchristos if (clone->dst.mode.id == 0) { 108213496ba1Ssnj width = 0; 108313496ba1Ssnj height = 0; 108442542f5fSchristos } else if (clone->dri3.xid) { 108542542f5fSchristos width = clone->dst.display->width; 108642542f5fSchristos height = clone->dst.display->height; 108742542f5fSchristos } else { 108842542f5fSchristos width = mode_width(&clone->src.mode, clone->src.rotation); 108942542f5fSchristos height = mode_height(&clone->src.mode, clone->src.rotation); 109042542f5fSchristos } 109142542f5fSchristos 109242542f5fSchristos if (width == clone->width && height == clone->height) 109342542f5fSchristos return 0; 109442542f5fSchristos 109542542f5fSchristos DBG(DRAW, ("%s-%s create xfer, %dx%d\n", 109642542f5fSchristos DisplayString(clone->dst.dpy), clone->dst.name, 109742542f5fSchristos width, height)); 109842542f5fSchristos 109942542f5fSchristos if (clone->shm.shmaddr) { 110042542f5fSchristos if (clone->src.use_shm) 110142542f5fSchristos XShmDetach(clone->src.dpy, &clone->src.shm); 110242542f5fSchristos if (clone->dst.use_shm) 110342542f5fSchristos XShmDetach(clone->dst.dpy, &clone->dst.shm); 110442542f5fSchristos 110542542f5fSchristos shmdt(clone->shm.shmaddr); 110642542f5fSchristos clone->shm.shmaddr = NULL; 110742542f5fSchristos } 110842542f5fSchristos 110942542f5fSchristos if (clone->src.pixmap) { 111042542f5fSchristos XFreePixmap(clone->src.dpy, clone->src.pixmap); 111142542f5fSchristos clone->src.pixmap = 0; 111242542f5fSchristos } 111342542f5fSchristos 111442542f5fSchristos if (clone->dst.pixmap) { 111542542f5fSchristos XFreePixmap(clone->dst.dpy, clone->dst.pixmap); 111642542f5fSchristos clone->dst.pixmap = 0; 111742542f5fSchristos } 111842542f5fSchristos 111942542f5fSchristos if ((width | height) == 0) { 112042542f5fSchristos clone->damaged.x2 = clone->damaged.y2 = INT_MIN; 112142542f5fSchristos clone->damaged.x1 = clone->damaged.y1 = INT_MAX; 112242542f5fSchristos return 0; 112342542f5fSchristos } 112442542f5fSchristos 112542542f5fSchristos if (clone->dri3.xid) { 112642542f5fSchristos int fd, stride; 112742542f5fSchristos Pixmap src; 112842542f5fSchristos 112942542f5fSchristos _x_error_occurred = 0; 113042542f5fSchristos 113142542f5fSchristos DBG(DRAW, ("%s-%s create xfer, trying DRI3\n", 113242542f5fSchristos DisplayString(clone->dst.dpy), clone->dst.name)); 113342542f5fSchristos 113442542f5fSchristos fd = dri3_create_fd(clone->dst.dpy, clone->dst.window, &stride); 113542542f5fSchristos if (fd < 0) 113642542f5fSchristos goto disable_dri3; 113742542f5fSchristos 113842542f5fSchristos DBG(DRAW, ("%s-%s create xfer, DRI3 fd=%d, stride=%d\n", 113942542f5fSchristos DisplayString(clone->dst.dpy), clone->dst.name, 114042542f5fSchristos fd, stride)); 114142542f5fSchristos 114242542f5fSchristos src = dri3_create_pixmap(clone->src.dpy, clone->src.window, 114342542f5fSchristos width, height, clone->depth, 114442542f5fSchristos fd, bpp_for_depth(clone->depth), 114542542f5fSchristos stride, lseek(fd, 0, SEEK_END)); 114642542f5fSchristos 114742542f5fSchristos XSync(clone->src.dpy, False); 114842542f5fSchristos if (!_x_error_occurred) { 114942542f5fSchristos clone->src.pixmap = src; 115042542f5fSchristos clone->width = width; 115142542f5fSchristos clone->height = height; 115242542f5fSchristos } else { 115342542f5fSchristos XFreePixmap(clone->src.dpy, src); 115442542f5fSchristos close(fd); 115542542f5fSchristosdisable_dri3: 115642542f5fSchristos dri3_fence_free(clone->src.dpy, &clone->dri3); 115742542f5fSchristos clone->dri3.xid = 0; 115842542f5fSchristos 115942542f5fSchristos DBG(DRAW, ("%s-%s create xfer, DRI3 failed\n", 116042542f5fSchristos DisplayString(clone->dst.dpy), clone->dst.name)); 116142542f5fSchristos } 116242542f5fSchristos } 116342542f5fSchristos 116442542f5fSchristos width = mode_width(&clone->src.mode, clone->src.rotation); 116542542f5fSchristos height = mode_height(&clone->src.mode, clone->src.rotation); 116642542f5fSchristos 116742542f5fSchristos if (!clone->dri3.xid) { 116842542f5fSchristos DBG(DRAW, ("%s-%s create xfer, trying SHM\n", 116942542f5fSchristos DisplayString(clone->dst.dpy), clone->dst.name)); 117042542f5fSchristos 117142542f5fSchristos clone->shm.shmid = shmget(IPC_PRIVATE, 117242542f5fSchristos height * stride_for_depth(width, clone->depth), 117342542f5fSchristos IPC_CREAT | 0666); 117442542f5fSchristos if (clone->shm.shmid == -1) 117542542f5fSchristos return errno; 117642542f5fSchristos 117742542f5fSchristos clone->shm.shmaddr = shmat(clone->shm.shmid, 0, 0); 117842542f5fSchristos if (clone->shm.shmaddr == (char *) -1) { 117942542f5fSchristos shmctl(clone->shm.shmid, IPC_RMID, NULL); 118042542f5fSchristos return ENOMEM; 118142542f5fSchristos } 118242542f5fSchristos 118342542f5fSchristos if (clone->src.use_shm) { 118442542f5fSchristos clone->src.shm = clone->shm; 118542542f5fSchristos clone->src.shm.readOnly = False; 118642542f5fSchristos XShmAttach(clone->src.dpy, &clone->src.shm); 118742542f5fSchristos XSync(clone->src.dpy, False); 118842542f5fSchristos } 118942542f5fSchristos if (clone->dst.use_shm) { 119042542f5fSchristos clone->dst.shm = clone->shm; 119142542f5fSchristos clone->dst.shm.readOnly = !clone->dst.use_shm_pixmap; 119242542f5fSchristos XShmAttach(clone->dst.dpy, &clone->dst.shm); 119342542f5fSchristos XSync(clone->dst.dpy, False); 119442542f5fSchristos } 119542542f5fSchristos 119642542f5fSchristos shmctl(clone->shm.shmid, IPC_RMID, NULL); 119742542f5fSchristos 119842542f5fSchristos clone->width = width; 119942542f5fSchristos clone->height = height; 120042542f5fSchristos 120142542f5fSchristos init_image(clone); 120242542f5fSchristos } 120342542f5fSchristos 120442542f5fSchristos output_init_xfer(clone, &clone->src); 120542542f5fSchristos output_init_xfer(clone, &clone->dst); 120642542f5fSchristos 120742542f5fSchristos clone->damaged.x1 = clone->src.x; 120842542f5fSchristos clone->damaged.x2 = clone->src.x + width; 120942542f5fSchristos clone->damaged.y1 = clone->src.y; 121042542f5fSchristos clone->damaged.y2 = clone->src.y + height; 121142542f5fSchristos 121242542f5fSchristos display_mark_flush(clone->dst.display); 121342542f5fSchristos return 0; 121442542f5fSchristos} 121542542f5fSchristos 121642542f5fSchristosstatic void clone_update(struct clone *clone) 121742542f5fSchristos{ 121842542f5fSchristos if (!clone->rr_update) 121942542f5fSchristos return; 122042542f5fSchristos 122142542f5fSchristos DBG(X11, ("%s-%s cloning modes\n", 122242542f5fSchristos DisplayString(clone->dst.dpy), clone->dst.name)); 122342542f5fSchristos 122442542f5fSchristos clone_update_modes__randr(clone); 122542542f5fSchristos clone->rr_update = 0; 122642542f5fSchristos} 122742542f5fSchristos 122842542f5fSchristosstatic int context_update(struct context *ctx) 122942542f5fSchristos{ 123042542f5fSchristos Display *dpy = ctx->display->dpy; 123142542f5fSchristos XRRScreenResources *res; 123242542f5fSchristos int context_changed = 0; 123342542f5fSchristos int i, n; 123442542f5fSchristos 123542542f5fSchristos DBG(X11, ("%s\n", __func__)); 123642542f5fSchristos 123742542f5fSchristos res = _XRRGetScreenResourcesCurrent(dpy, ctx->display->root); 123842542f5fSchristos if (res == NULL) 123942542f5fSchristos return 0; 124042542f5fSchristos 124142542f5fSchristos DBG(XRR, ("%s timestamp %ld (last %ld), config %ld (last %ld)\n", 124242542f5fSchristos DisplayString(dpy), 124342542f5fSchristos res->timestamp, ctx->timestamp, 124442542f5fSchristos res->configTimestamp, ctx->configTimestamp)); 124542542f5fSchristos if (res->timestamp == ctx->timestamp && 124642542f5fSchristos res->configTimestamp == ctx->configTimestamp && 124742542f5fSchristos res->timestamp != res->configTimestamp) { /* mutter be damned */ 124842542f5fSchristos XRRFreeScreenResources(res); 124942542f5fSchristos return 0; 125042542f5fSchristos } 125142542f5fSchristos 125242542f5fSchristos ctx->timestamp = res->timestamp; 125342542f5fSchristos ctx->configTimestamp = res->configTimestamp; 125442542f5fSchristos 125542542f5fSchristos for (n = 0; n < ctx->nclone; n++) { 125642542f5fSchristos struct output *output = &ctx->clones[n].src; 125742542f5fSchristos XRROutputInfo *o; 125842542f5fSchristos XRRCrtcInfo *c; 125942542f5fSchristos RRMode mode = 0; 126042542f5fSchristos int changed = 0; 126142542f5fSchristos 126242542f5fSchristos o = XRRGetOutputInfo(dpy, res, output->rr_output); 126342542f5fSchristos if (o == NULL) 126442542f5fSchristos continue; 126542542f5fSchristos 126642542f5fSchristos c = NULL; 126742542f5fSchristos if (o->crtc) 126842542f5fSchristos c = XRRGetCrtcInfo(dpy, res, o->crtc); 126942542f5fSchristos if (c) { 127042542f5fSchristos DBG(XRR, ("%s-%s: (x=%d, y=%d, rotation=%d, mode=%ld) -> (x=%d, y=%d, rotation=%d, mode=%ld)\n", 127142542f5fSchristos DisplayString(dpy), output->name, 127242542f5fSchristos output->x, output->y, output->rotation, output->mode.id, 127342542f5fSchristos c->x, c->y, c->rotation, c->mode)); 127442542f5fSchristos 127542542f5fSchristos changed |= output->rotation != c->rotation; 127642542f5fSchristos output->rotation = c->rotation; 127742542f5fSchristos 127842542f5fSchristos changed |= output->x != c->x; 127942542f5fSchristos output->x = c->x; 128042542f5fSchristos 128142542f5fSchristos changed |= output->y != c->y; 128242542f5fSchristos output->y = c->y; 128342542f5fSchristos 128442542f5fSchristos changed |= output->mode.id != c->mode; 128542542f5fSchristos mode = c->mode; 128642542f5fSchristos XRRFreeCrtcInfo(c); 128742542f5fSchristos } else { 128842542f5fSchristos DBG(XRR, ("%s-%s: (x=%d, y=%d, rotation=%d, mode=%ld) -> off\n", 128942542f5fSchristos DisplayString(dpy), output->name, 129042542f5fSchristos output->x, output->y, output->rotation, output->mode.id)); 129142542f5fSchristos } 129242542f5fSchristos output->rr_crtc = o->crtc; 129342542f5fSchristos XRRFreeOutputInfo(o); 129442542f5fSchristos 129542542f5fSchristos DBG(XRR, ("%s-%s crtc changed? %d\n", 129642542f5fSchristos DisplayString(ctx->clones[n].dst.display->dpy), ctx->clones[n].dst.name, changed)); 129742542f5fSchristos 129842542f5fSchristos if (mode) { 129942542f5fSchristos if (output->mode.id != mode) { 130042542f5fSchristos for (i = 0; i < res->nmode; i++) { 130142542f5fSchristos if (res->modes[i].id == mode) { 130242542f5fSchristos output->mode = res->modes[i]; 130342542f5fSchristos break; 130442542f5fSchristos } 130542542f5fSchristos } 130642542f5fSchristos } 130742542f5fSchristos } else { 130842542f5fSchristos changed = output->mode.id != 0; 130942542f5fSchristos output->mode.id = 0; 131042542f5fSchristos } 131142542f5fSchristos 131242542f5fSchristos DBG(XRR, ("%s-%s output changed? %d\n", 131342542f5fSchristos DisplayString(ctx->clones[n].dst.display->dpy), ctx->clones[n].dst.name, changed)); 131442542f5fSchristos 131542542f5fSchristos context_changed |= changed; 131642542f5fSchristos } 131742542f5fSchristos XRRFreeScreenResources(res); 131842542f5fSchristos 131942542f5fSchristos DBG(XRR, ("%s changed? %d\n", DisplayString(dpy), context_changed)); 132042542f5fSchristos if (!context_changed) 132142542f5fSchristos return 0; 132242542f5fSchristos 132342542f5fSchristos for (n = 1; n < ctx->ndisplay; n++) { 132442542f5fSchristos struct display *display = &ctx->display[n]; 132542542f5fSchristos struct clone *clone; 132642542f5fSchristos int x1, x2, y1, y2; 132742542f5fSchristos 132842542f5fSchristos if (display->rr_active == 0) 132942542f5fSchristos continue; 133042542f5fSchristos 133142542f5fSchristos x1 = y1 = INT_MAX; 133242542f5fSchristos x2 = y2 = INT_MIN; 133342542f5fSchristos 133442542f5fSchristos for (clone = display->clone; clone; clone = clone->next) { 133542542f5fSchristos struct output *output = &clone->src; 133642542f5fSchristos int v; 133742542f5fSchristos 133842542f5fSchristos assert(clone->dst.display == display); 133942542f5fSchristos 134042542f5fSchristos if (output->mode.id == 0) 134142542f5fSchristos continue; 134242542f5fSchristos 134342542f5fSchristos DBG(XRR, ("%s: source %s enabled (%d, %d)x(%d, %d)\n", 134442542f5fSchristos DisplayString(clone->dst.dpy), output->name, 134542542f5fSchristos output->x, output->y, 134642542f5fSchristos mode_width(&output->mode, output->rotation), 134742542f5fSchristos mode_height(&output->mode, output->rotation))); 134842542f5fSchristos 134942542f5fSchristos if (output->x < x1) 135042542f5fSchristos x1 = output->x; 135142542f5fSchristos if (output->y < y1) 135242542f5fSchristos y1 = output->y; 135342542f5fSchristos 135442542f5fSchristos v = (int)output->x + mode_width(&output->mode, output->rotation); 135542542f5fSchristos if (v > x2) 135642542f5fSchristos x2 = v; 135742542f5fSchristos v = (int)output->y + mode_height(&output->mode, output->rotation); 135842542f5fSchristos if (v > y2) 135942542f5fSchristos y2 = v; 136042542f5fSchristos } 136142542f5fSchristos 136242542f5fSchristos DBG(XRR, ("%s fb bounds (%d, %d)x(%d, %d)\n", DisplayString(display->dpy), 136342542f5fSchristos x1, y1, x2, y2)); 136442542f5fSchristos 136542542f5fSchristos XGrabServer(display->dpy); 136642542f5fSchristos res = _XRRGetScreenResourcesCurrent(display->dpy, display->root); 136742542f5fSchristos if (res == NULL) 136842542f5fSchristos goto ungrab; 136942542f5fSchristos 137042542f5fSchristos if (x2 <= x1 || y2 <= y1) { 137142542f5fSchristos /* Nothing enabled, preserve the current fb, and turn everything off */ 137242542f5fSchristos for (clone = display->clone; clone; clone = clone->next) { 137342542f5fSchristos struct output *dst = &clone->dst; 137442542f5fSchristos 137542542f5fSchristos if (!dst->rr_crtc) 137642542f5fSchristos continue; 137742542f5fSchristos 137842542f5fSchristos DBG(XRR, ("%s: disabling output '%s'\n", 137942542f5fSchristos DisplayString(display->dpy), dst->name)); 138042542f5fSchristos assert(clone->dst.display == display); 138142542f5fSchristos if (disable_crtc(display->dpy, res, dst->rr_crtc)) { 138242542f5fSchristos dst->rr_crtc = 0; 138342542f5fSchristos dst->mode.id = 0; 138442542f5fSchristos } 138542542f5fSchristos } 138642542f5fSchristos goto free_res; 138742542f5fSchristos } 138842542f5fSchristos 138942542f5fSchristos x2 -= x1; 139042542f5fSchristos y2 -= y1; 139142542f5fSchristos DBG(XRR, ("%s: current size %dx%d, need %dx%d\n", 139242542f5fSchristos DisplayString(display->dpy), 139342542f5fSchristos display->width, display->height, 139442542f5fSchristos x2, y2)); 139542542f5fSchristos 139642542f5fSchristos if (display->width != x2 || display->height != y2) { 139742542f5fSchristos /* When shrinking we have to manually resize the fb */ 139842542f5fSchristos for (clone = display->clone; clone; clone = clone->next) { 139942542f5fSchristos struct output *dst = &clone->dst; 140042542f5fSchristos 140142542f5fSchristos if (!dst->rr_crtc) 140242542f5fSchristos continue; 140342542f5fSchristos 140442542f5fSchristos DBG(XRR, ("%s: disabling output '%s'\n", 140542542f5fSchristos DisplayString(display->dpy), dst->name)); 140642542f5fSchristos assert(clone->dst.display == display); 140742542f5fSchristos if (disable_crtc(display->dpy, res, dst->rr_crtc)) { 140842542f5fSchristos dst->rr_crtc = 0; 140942542f5fSchristos dst->mode.id = 0; 141042542f5fSchristos } 141142542f5fSchristos } 141242542f5fSchristos 141342542f5fSchristos DBG(XRR, ("%s: XRRSetScreenSize %dx%d\n", DisplayString(display->dpy), x2, y2)); 141442542f5fSchristos XRRSetScreenSize(display->dpy, display->root, x2, y2, x2 * 96 / 25.4, y2 * 96 / 25.4); 141542542f5fSchristos display->width = x2; 141642542f5fSchristos display->height = y2; 141742542f5fSchristos } 141842542f5fSchristos 141942542f5fSchristos for (clone = display->clone; clone; clone = clone->next) { 142042542f5fSchristos struct output *src = &clone->src; 142142542f5fSchristos struct output *dst = &clone->dst; 142242542f5fSchristos XRROutputInfo *o; 142342542f5fSchristos XRRPanning panning; 142442542f5fSchristos struct clone *set; 142542542f5fSchristos RRCrtc rr_crtc; 142642542f5fSchristos Status ret; 142742542f5fSchristos 142842542f5fSchristos DBG(XRR, ("%s: copying configuration from %s (mode=%ld: %dx%d) to %s\n", 142942542f5fSchristos DisplayString(display->dpy), 143042542f5fSchristos src->name, (long)src->mode.id, src->mode.width, src->mode.height, 143142542f5fSchristos dst->name)); 143242542f5fSchristos 143342542f5fSchristos if (src->mode.id == 0) { 143442542f5fSchristoserr: 143542542f5fSchristos if (dst->rr_crtc) { 143642542f5fSchristos DBG(XRR, ("%s: disabling unused output '%s'\n", 143742542f5fSchristos DisplayString(display->dpy), dst->name)); 143842542f5fSchristos assert(clone->dst.display == display); 143942542f5fSchristos if (disable_crtc(display->dpy, res, dst->rr_crtc)) { 144042542f5fSchristos dst->rr_crtc = 0; 144142542f5fSchristos dst->mode.id = 0; 144242542f5fSchristos } 144342542f5fSchristos } 144442542f5fSchristos continue; 144542542f5fSchristos } 144642542f5fSchristos 144742542f5fSchristos dst->x = src->x - x1; 144842542f5fSchristos dst->y = src->y - y1; 144942542f5fSchristos dst->rotation = src->rotation; 145042542f5fSchristos dst->mode = src->mode; 145142542f5fSchristos 145242542f5fSchristos dst->mode.id = 0; 145342542f5fSchristos for (i = 0; i < res->nmode; i++) { 145442542f5fSchristos if (mode_equal(&src->mode, &res->modes[i])) { 145542542f5fSchristos dst->mode.id = res->modes[i].id; 145642542f5fSchristos break; 145742542f5fSchristos } 145842542f5fSchristos } 145942542f5fSchristos if (dst->mode.id == 0) { 146042542f5fSchristos XRRModeInfo m; 146142542f5fSchristos char buf[256]; 146242542f5fSchristos RRMode id; 146342542f5fSchristos 146442542f5fSchristos /* XXX User names must be unique! */ 146542542f5fSchristos m = src->mode; 146642542f5fSchristos m.nameLength = snprintf(buf, sizeof(buf), 146742542f5fSchristos "%s.%ld-%dx%d", src->name, 146842542f5fSchristos (long)src->mode.id, 146942542f5fSchristos src->mode.width, 147042542f5fSchristos src->mode.height); 147142542f5fSchristos m.name = buf; 147242542f5fSchristos 147342542f5fSchristos id = XRRCreateMode(dst->dpy, dst->window, &m); 147442542f5fSchristos if (id) { 147542542f5fSchristos DBG(XRR, ("%s: adding mode %ld: %dx%d to %s, new mode %ld\n", 147642542f5fSchristos DisplayString(dst->dpy), 147742542f5fSchristos (long)src->mode.id, 147842542f5fSchristos src->mode.width, 147942542f5fSchristos src->mode.height, 148042542f5fSchristos dst->name, (long)id)); 148142542f5fSchristos XRRAddOutputMode(dst->dpy, dst->rr_output, id); 148242542f5fSchristos dst->mode.id = id; 148342542f5fSchristos } else { 148442542f5fSchristos DBG(XRR, ("%s: failed to find suitable mode for %s\n", 148542542f5fSchristos DisplayString(dst->dpy), dst->name)); 148642542f5fSchristos goto err; 148742542f5fSchristos } 148842542f5fSchristos } 148942542f5fSchristos 149042542f5fSchristos rr_crtc = dst->rr_crtc; 149142542f5fSchristos if (rr_crtc) { 149242542f5fSchristos for (set = display->clone; set != clone; set = set->next) { 149342542f5fSchristos if (set->dst.rr_crtc == rr_crtc) { 149442542f5fSchristos DBG(XRR, ("%s: CRTC reassigned from %s\n", 149542542f5fSchristos DisplayString(dst->dpy), dst->name)); 149642542f5fSchristos rr_crtc = 0; 149742542f5fSchristos break; 149842542f5fSchristos } 149942542f5fSchristos } 150042542f5fSchristos } 150142542f5fSchristos if (rr_crtc == 0) { 150242542f5fSchristos o = XRRGetOutputInfo(dst->dpy, res, dst->rr_output); 150342542f5fSchristos for (i = 0; i < o->ncrtc; i++) { 150442542f5fSchristos DBG(XRR, ("%s: checking whether CRTC:%ld is available\n", 150542542f5fSchristos DisplayString(dst->dpy), (long)o->crtcs[i])); 150642542f5fSchristos for (set = display->clone; set != clone; set = set->next) { 150742542f5fSchristos if (set->dst.rr_crtc == o->crtcs[i]) { 150842542f5fSchristos DBG(XRR, ("%s: CRTC:%ld already assigned to %s\n", 150942542f5fSchristos DisplayString(dst->dpy), (long)o->crtcs[i], set->dst.name)); 151042542f5fSchristos break; 151142542f5fSchristos } 151242542f5fSchristos } 151342542f5fSchristos if (set == clone) { 151442542f5fSchristos rr_crtc = o->crtcs[i]; 151542542f5fSchristos break; 151642542f5fSchristos } 151742542f5fSchristos } 151842542f5fSchristos XRRFreeOutputInfo(o); 151942542f5fSchristos } 152042542f5fSchristos if (rr_crtc == 0) { 152142542f5fSchristos DBG(XRR, ("%s: failed to find available CRTC for %s\n", 152242542f5fSchristos DisplayString(dst->dpy), dst->name)); 152342542f5fSchristos goto err; 152442542f5fSchristos } 152542542f5fSchristos 152642542f5fSchristos DBG(XRR, ("%s: enabling output '%s' (%d,%d)x(%d,%d), rotation %d, on CRTC:%ld, using mode %ld\n", 152742542f5fSchristos DisplayString(dst->dpy), dst->name, 152842542f5fSchristos dst->x, dst->y, dst->mode.width, dst->mode.height, 152942542f5fSchristos dst->rotation, (long)rr_crtc, dst->mode.id)); 153042542f5fSchristos 153142542f5fSchristos ret = XRRSetPanning(dst->dpy, res, rr_crtc, memset(&panning, 0, sizeof(panning))); 153242542f5fSchristos DBG(XRR, ("%s-%s: XRRSetPanning %s\n", DisplayString(dst->dpy), dst->name, ret ? "failed" : "success")); 153342542f5fSchristos (void)ret; 153442542f5fSchristos 153542542f5fSchristos ret = XRRSetCrtcConfig(dst->dpy, res, rr_crtc, CurrentTime, 153642542f5fSchristos dst->x, dst->y, dst->mode.id, dst->rotation, 153742542f5fSchristos &dst->rr_output, 1); 153842542f5fSchristos DBG(XRR, ("%s-%s: XRRSetCrtcConfig %s\n", DisplayString(dst->dpy), dst->name, ret ? "failed" : "success")); 153942542f5fSchristos if (ret) 154042542f5fSchristos goto err; 154142542f5fSchristos 154242542f5fSchristos if (verbose & XRR) { 154342542f5fSchristos XRRCrtcInfo *c; 154442542f5fSchristos XRRPanning *p; 154542542f5fSchristos 154642542f5fSchristos c = XRRGetCrtcInfo(dst->dpy, res, rr_crtc); 154742542f5fSchristos if (c) { 154842542f5fSchristos DBG(XRR, ("%s-%s: x=%d, y=%d, rotation=%d, mode=%ld\n", 154942542f5fSchristos DisplayString(dst->dpy), dst->name, 155042542f5fSchristos c->x, c->y, c->rotation, c->mode)); 155142542f5fSchristos XRRFreeCrtcInfo(c); 155242542f5fSchristos } 155342542f5fSchristos 155442542f5fSchristos p = XRRGetPanning(dst->dpy, res, rr_crtc); 155542542f5fSchristos if (p) { 155642542f5fSchristos DBG(XRR, ("%s-%s: panning (%d, %d)x(%d, %d), tracking (%d, %d)x(%d, %d), border (%d, %d),(%d, %d)\n", 155742542f5fSchristos DisplayString(dst->dpy), dst->name, 155842542f5fSchristos p->left, p->top, p->width, p->height, 155942542f5fSchristos p->track_left, p->track_top, p->track_width, p->track_height, 156042542f5fSchristos p->border_left, p->border_top, p->border_right, p->border_bottom)); 156142542f5fSchristos XRRFreePanning(p); 156242542f5fSchristos } 156342542f5fSchristos } 156442542f5fSchristos 156542542f5fSchristos dst->rr_crtc = rr_crtc; 156642542f5fSchristos } 156742542f5fSchristosfree_res: 156842542f5fSchristos XRRFreeScreenResources(res); 156942542f5fSchristosungrab: 157042542f5fSchristos XUngrabServer(display->dpy); 157142542f5fSchristos } 157242542f5fSchristos 157342542f5fSchristos ctx->active = NULL; 157442542f5fSchristos for (n = 0; n < ctx->nclone; n++) { 157542542f5fSchristos struct clone *clone = &ctx->clones[n]; 157642542f5fSchristos 157742542f5fSchristos clone_init_xfer(clone); 157842542f5fSchristos 157942542f5fSchristos if (clone->dst.rr_crtc == 0) 158042542f5fSchristos continue; 158142542f5fSchristos 158242542f5fSchristos DBG(XRR, ("%s-%s: added to active list\n", 158342542f5fSchristos DisplayString(clone->dst.display->dpy), clone->dst.name)); 158442542f5fSchristos 158542542f5fSchristos clone->active = ctx->active; 158642542f5fSchristos ctx->active = clone; 158742542f5fSchristos } 158842542f5fSchristos 158942542f5fSchristos return 1; 159042542f5fSchristos} 159142542f5fSchristos 159242542f5fSchristosstatic Cursor display_load_invisible_cursor(struct display *display) 159342542f5fSchristos{ 159442542f5fSchristos char zero[8] = {}; 159542542f5fSchristos XColor black = {}; 159642542f5fSchristos Pixmap bitmap = XCreateBitmapFromData(display->dpy, display->root, zero, 8, 8); 159742542f5fSchristos return XCreatePixmapCursor(display->dpy, bitmap, bitmap, &black, &black, 0, 0); 159842542f5fSchristos} 159942542f5fSchristos 160042542f5fSchristosstatic Cursor display_get_visible_cursor(struct display *display) 160142542f5fSchristos{ 160242542f5fSchristos if (display->cursor_serial != display->cursor_image.size) { 160342542f5fSchristos DBG(CURSOR, ("%s updating cursor\n", DisplayString(display->dpy))); 160442542f5fSchristos 160542542f5fSchristos if (display->visible_cursor) 160642542f5fSchristos XFreeCursor(display->dpy, display->visible_cursor); 160742542f5fSchristos 160842542f5fSchristos display->visible_cursor = XcursorImageLoadCursor(display->dpy, &display->cursor_image); 160942542f5fSchristos display->cursor_serial = display->cursor_image.size; 161042542f5fSchristos } 161142542f5fSchristos 161242542f5fSchristos return display->visible_cursor; 161342542f5fSchristos} 161442542f5fSchristos 161542542f5fSchristosstatic void display_load_visible_cursor(struct display *display, XFixesCursorImage *cur) 161642542f5fSchristos{ 161742542f5fSchristos unsigned long *src; /* XXX deep sigh */ 161842542f5fSchristos XcursorPixel *dst; 161942542f5fSchristos unsigned n; 162042542f5fSchristos 162142542f5fSchristos if (cur->width != display->cursor_image.width || 162242542f5fSchristos cur->height != display->cursor_image.height) 162342542f5fSchristos display->cursor_image.pixels = realloc(display->cursor_image.pixels, 162442542f5fSchristos 4 * cur->width * cur->height); 162542542f5fSchristos if (display->cursor_image.pixels == NULL) 162642542f5fSchristos return; 162742542f5fSchristos 162842542f5fSchristos display->cursor_image.width = cur->width; 162942542f5fSchristos display->cursor_image.height = cur->height; 163042542f5fSchristos display->cursor_image.xhot = cur->xhot; 163142542f5fSchristos display->cursor_image.yhot = cur->yhot; 163242542f5fSchristos display->cursor_image.size++; 163342542f5fSchristos 163442542f5fSchristos n = cur->width*cur->height; 163542542f5fSchristos src = cur->pixels; 163642542f5fSchristos dst = display->cursor_image.pixels; 163742542f5fSchristos while (n--) 163842542f5fSchristos *dst++ = *src++; 163942542f5fSchristos 164042542f5fSchristos DBG(CURSOR, ("%s marking cursor changed\n", DisplayString(display->dpy))); 164142542f5fSchristos display->cursor_moved++; 164242542f5fSchristos if (display->cursor != display->invisible_cursor) { 164342542f5fSchristos display->cursor_visible++; 164442542f5fSchristos context_enable_timer(display->ctx); 164542542f5fSchristos } 164642542f5fSchristos} 164742542f5fSchristos 164842542f5fSchristosstatic void display_cursor_move(struct display *display, int x, int y, int visible) 164942542f5fSchristos{ 165042542f5fSchristos DBG(CURSOR, ("%s cursor moved (visible=%d, (%d, %d))\n", 165142542f5fSchristos DisplayString(display->dpy), visible, x, y)); 165242542f5fSchristos display->cursor_moved++; 165342542f5fSchristos display->cursor_visible += visible; 165442542f5fSchristos if (visible) { 165542542f5fSchristos display->cursor_x = x; 165642542f5fSchristos display->cursor_y = y; 165742542f5fSchristos } 165842542f5fSchristos 165942542f5fSchristos context_enable_timer(display->ctx); 166042542f5fSchristos} 166142542f5fSchristos 166242542f5fSchristosstatic void display_flush_cursor(struct display *display) 166342542f5fSchristos{ 166442542f5fSchristos Cursor cursor; 166542542f5fSchristos int x, y; 166642542f5fSchristos 166742542f5fSchristos if (!display->cursor_moved) 166842542f5fSchristos return; 166942542f5fSchristos 167042542f5fSchristos if (display->cursor_visible) { 167142542f5fSchristos x = display->cursor_x; 167242542f5fSchristos y = display->cursor_y; 167342542f5fSchristos } else { 167442542f5fSchristos x = display->cursor_x++ & 31; 167542542f5fSchristos y = display->cursor_y++ & 31; 167642542f5fSchristos } 167742542f5fSchristos 167842542f5fSchristos DBG(CURSOR, ("%s setting cursor position (%d, %d), visible? %d\n", 167942542f5fSchristos DisplayString(display->dpy), x, y, display->cursor_visible)); 168042542f5fSchristos XWarpPointer(display->dpy, None, display->root, 0, 0, 0, 0, x, y); 168142542f5fSchristos 168242542f5fSchristos cursor = None; 168342542f5fSchristos if (display->cursor_visible) 168442542f5fSchristos cursor = display_get_visible_cursor(display); 168542542f5fSchristos if (cursor == None) 168642542f5fSchristos cursor = display->invisible_cursor; 168742542f5fSchristos if (cursor != display->cursor) { 168842542f5fSchristos XDefineCursor(display->dpy, display->root, cursor); 168942542f5fSchristos display->cursor = cursor; 169042542f5fSchristos } 169142542f5fSchristos 169242542f5fSchristos display_mark_flush(display); 169342542f5fSchristos 169442542f5fSchristos display->cursor_moved = 0; 169542542f5fSchristos display->cursor_visible = 0; 169642542f5fSchristos} 169742542f5fSchristos 169842542f5fSchristosstatic void clone_move_cursor(struct clone *c, int x, int y) 169942542f5fSchristos{ 170042542f5fSchristos int visible; 170142542f5fSchristos 170242542f5fSchristos DBG(CURSOR, ("%s-%s moving cursor (%d, %d) [(%d, %d), (%d, %d)]\n", 170342542f5fSchristos DisplayString(c->dst.dpy), c->dst.name, 170442542f5fSchristos x, y, 170542542f5fSchristos c->src.x, c->src.y, 170642542f5fSchristos c->src.x + c->width, c->src.y + c->height)); 170742542f5fSchristos 170842542f5fSchristos visible = (x >= c->src.x && x < c->src.x + c->width && 170942542f5fSchristos y >= c->src.y && y < c->src.y + c->height); 171042542f5fSchristos 171142542f5fSchristos x += c->dst.x - c->src.x; 171242542f5fSchristos y += c->dst.y - c->src.y; 171342542f5fSchristos 171442542f5fSchristos display_cursor_move(c->dst.display, x, y, visible); 171542542f5fSchristos} 171642542f5fSchristos 171742542f5fSchristosstatic int clone_output_init(struct clone *clone, struct output *output, 171842542f5fSchristos struct display *display, const char *name, 171942542f5fSchristos RROutput rr_output) 172042542f5fSchristos{ 172142542f5fSchristos Display *dpy = display->dpy; 172242542f5fSchristos int depth; 172342542f5fSchristos 172442542f5fSchristos DBG(X11, ("%s(%s, %s)\n", __func__, DisplayString(dpy), name)); 172542542f5fSchristos 172642542f5fSchristos output->name = strdup(name); 172742542f5fSchristos if (output->name == NULL) 172842542f5fSchristos return -ENOMEM; 172942542f5fSchristos 173042542f5fSchristos output->display = display; 173142542f5fSchristos output->dpy = dpy; 173242542f5fSchristos 173342542f5fSchristos output->rr_output = rr_output; 173442542f5fSchristos output->rotation = RR_Rotate_0; 173542542f5fSchristos 173642542f5fSchristos output->window = display->root; 173742542f5fSchristos output->use_shm = display->has_shm; 173842542f5fSchristos output->use_shm_pixmap = display->has_shm_pixmap; 173942542f5fSchristos 174042542f5fSchristos DBG(X11, ("%s-%s use shm? %d (use shm pixmap? %d)\n", 174142542f5fSchristos DisplayString(dpy), name, display->has_shm, display->has_shm_pixmap)); 174242542f5fSchristos 174342542f5fSchristos depth = output->use_shm && !FORCE_16BIT_XFER ? display->depth : 16; 174442542f5fSchristos if (depth < clone->depth) 174542542f5fSchristos clone->depth = depth; 174642542f5fSchristos 174742542f5fSchristos return 0; 174842542f5fSchristos} 174942542f5fSchristos 175042542f5fSchristosstatic void ximage_prepare(XImage *image, int width, int height) 175142542f5fSchristos{ 175242542f5fSchristos image->width = width; 175342542f5fSchristos image->height = height; 175442542f5fSchristos image->bytes_per_line = stride_for_depth(width, image->depth); 175542542f5fSchristos} 175642542f5fSchristos 175742542f5fSchristosstatic void get_src(struct clone *c, const XRectangle *clip) 175842542f5fSchristos{ 175942542f5fSchristos DBG(DRAW,("%s-%s get_src(%d,%d)x(%d,%d)\n", DisplayString(c->dst.dpy), c->dst.name, 176042542f5fSchristos clip->x, clip->y, clip->width, clip->height)); 176142542f5fSchristos 176242542f5fSchristos c->image.obdata = (char *)&c->src.shm; 176342542f5fSchristos 176442542f5fSchristos if (c->src.use_render) { 176542542f5fSchristos XRenderComposite(c->src.dpy, PictOpSrc, 176642542f5fSchristos c->src.win_picture, 0, c->src.pix_picture, 176742542f5fSchristos clip->x, clip->y, 176842542f5fSchristos 0, 0, 176942542f5fSchristos 0, 0, 177042542f5fSchristos clip->width, clip->height); 177142542f5fSchristos if (c->src.use_shm_pixmap) { 177242542f5fSchristos XSync(c->src.dpy, False); 177342542f5fSchristos } else if (c->src.use_shm) { 177442542f5fSchristos ximage_prepare(&c->image, clip->width, clip->height); 177542542f5fSchristos XShmGetImage(c->src.dpy, c->src.pixmap, &c->image, 177642542f5fSchristos clip->x, clip->y, AllPlanes); 177742542f5fSchristos } else { 177842542f5fSchristos ximage_prepare(&c->image, c->width, c->height); 177942542f5fSchristos XGetSubImage(c->src.dpy, c->src.pixmap, 178042542f5fSchristos clip->x, clip->y, clip->width, clip->height, 178142542f5fSchristos AllPlanes, ZPixmap, 178242542f5fSchristos &c->image, 0, 0); 178342542f5fSchristos } 178442542f5fSchristos } else if (c->src.pixmap) { 178542542f5fSchristos XCopyArea(c->src.dpy, c->src.window, c->src.pixmap, c->src.gc, 178642542f5fSchristos clip->x, clip->y, 178742542f5fSchristos clip->width, clip->height, 178842542f5fSchristos 0, 0); 178942542f5fSchristos XSync(c->src.dpy, False); 179042542f5fSchristos } else if (c->src.use_shm) { 179142542f5fSchristos ximage_prepare(&c->image, clip->width, clip->height); 179242542f5fSchristos XShmGetImage(c->src.dpy, c->src.window, &c->image, 179342542f5fSchristos clip->x, clip->y, AllPlanes); 179442542f5fSchristos } else { 179542542f5fSchristos ximage_prepare(&c->image, c->width, c->height); 179642542f5fSchristos XGetSubImage(c->src.dpy, c->src.window, 179742542f5fSchristos clip->x, clip->y, clip->width, clip->height, 179842542f5fSchristos AllPlanes, ZPixmap, 179942542f5fSchristos &c->image, 0, 0); 180042542f5fSchristos } 180142542f5fSchristos c->src.display->flush = 0; 180242542f5fSchristos} 180342542f5fSchristos 180442542f5fSchristosstatic void put_dst(struct clone *c, const XRectangle *clip) 180542542f5fSchristos{ 180642542f5fSchristos DBG(DRAW, ("%s-%s put_dst(%d,%d)x(%d,%d)\n", DisplayString(c->dst.dpy), c->dst.name, 180742542f5fSchristos clip->x, clip->y, clip->width, clip->height)); 180842542f5fSchristos 180942542f5fSchristos c->image.obdata = (char *)&c->dst.shm; 181042542f5fSchristos 181142542f5fSchristos if (c->dst.use_render) { 181242542f5fSchristos if (c->dst.use_shm_pixmap) { 181342542f5fSchristos DBG(DRAW, ("%s-%s using SHM pixmap composite\n", 181442542f5fSchristos DisplayString(c->dst.dpy), c->dst.name)); 181542542f5fSchristos } else if (c->dst.use_shm) { 181642542f5fSchristos DBG(DRAW, ("%s-%s using SHM image composite\n", 181742542f5fSchristos DisplayString(c->dst.dpy), c->dst.name)); 181842542f5fSchristos XShmPutImage(c->dst.dpy, c->dst.pixmap, c->dst.gc, &c->image, 181942542f5fSchristos 0, 0, 182042542f5fSchristos 0, 0, 182142542f5fSchristos clip->width, clip->height, 182242542f5fSchristos False); 182342542f5fSchristos } else { 182442542f5fSchristos DBG(DRAW, ("%s-%s using composite\n", 182542542f5fSchristos DisplayString(c->dst.dpy), c->dst.name)); 182642542f5fSchristos XPutImage(c->dst.dpy, c->dst.pixmap, c->dst.gc, &c->image, 182742542f5fSchristos 0, 0, 182842542f5fSchristos 0, 0, 182942542f5fSchristos clip->width, clip->height); 183042542f5fSchristos } 183142542f5fSchristos if (c->dst.use_shm) 183242542f5fSchristos c->dst.serial = NextRequest(c->dst.dpy); 183342542f5fSchristos XRenderComposite(c->dst.dpy, PictOpSrc, 183442542f5fSchristos c->dst.pix_picture, 0, c->dst.win_picture, 183542542f5fSchristos 0, 0, 183642542f5fSchristos 0, 0, 183742542f5fSchristos clip->x, clip->y, 183842542f5fSchristos clip->width, clip->height); 183942542f5fSchristos c->dst.display->send |= c->dst.use_shm; 184042542f5fSchristos } else if (c->dst.pixmap) { 184142542f5fSchristos DBG(DRAW, ("%s-%s using SHM pixmap\n", 184242542f5fSchristos DisplayString(c->dst.dpy), c->dst.name)); 184342542f5fSchristos c->dst.serial = NextRequest(c->dst.dpy); 184442542f5fSchristos XCopyArea(c->dst.dpy, c->dst.pixmap, c->dst.window, c->dst.gc, 184542542f5fSchristos 0, 0, 184642542f5fSchristos clip->width, clip->height, 184742542f5fSchristos clip->x, clip->y); 184842542f5fSchristos c->dst.display->send = 1; 184942542f5fSchristos } else if (c->dst.use_shm) { 185042542f5fSchristos DBG(DRAW, ("%s-%s using SHM image\n", 185142542f5fSchristos DisplayString(c->dst.dpy), c->dst.name)); 185242542f5fSchristos c->dst.serial = NextRequest(c->dst.dpy); 185342542f5fSchristos XShmPutImage(c->dst.dpy, c->dst.window, c->dst.gc, &c->image, 185442542f5fSchristos 0, 0, 185542542f5fSchristos clip->x, clip->y, 185642542f5fSchristos clip->width, clip->height, 185742542f5fSchristos True); 185842542f5fSchristos } else { 185942542f5fSchristos DBG(DRAW, ("%s-%s using image\n", 186042542f5fSchristos DisplayString(c->dst.dpy), c->dst.name)); 186142542f5fSchristos XPutImage(c->dst.dpy, c->dst.window, c->dst.gc, &c->image, 186242542f5fSchristos 0, 0, 186342542f5fSchristos clip->x, clip->y, 186442542f5fSchristos clip->width, clip->height); 186542542f5fSchristos c->dst.serial = 0; 186642542f5fSchristos } 186742542f5fSchristos} 186842542f5fSchristos 186942542f5fSchristosstatic int clone_paint(struct clone *c) 187042542f5fSchristos{ 187142542f5fSchristos XRectangle clip; 187242542f5fSchristos 187342542f5fSchristos DBG(DRAW, ("%s-%s paint clone, damaged (%d, %d), (%d, %d) [(%d, %d), (%d, %d)]\n", 187442542f5fSchristos DisplayString(c->dst.dpy), c->dst.name, 187542542f5fSchristos c->damaged.x1, c->damaged.y1, 187642542f5fSchristos c->damaged.x2, c->damaged.y2, 187742542f5fSchristos c->src.x, c->src.y, 187842542f5fSchristos c->src.x + c->width, c->src.y + c->height)); 187942542f5fSchristos 188042542f5fSchristos if (c->damaged.x1 < c->src.x) 188142542f5fSchristos c->damaged.x1 = c->src.x; 188242542f5fSchristos if (c->damaged.x2 > c->src.x + c->width) 188342542f5fSchristos c->damaged.x2 = c->src.x + c->width; 188442542f5fSchristos if (c->damaged.x2 <= c->damaged.x1) 188542542f5fSchristos goto done; 188642542f5fSchristos 188742542f5fSchristos if (c->damaged.y1 < c->src.y) 188842542f5fSchristos c->damaged.y1 = c->src.y; 188942542f5fSchristos if (c->damaged.y2 > c->src.y + c->height) 189042542f5fSchristos c->damaged.y2 = c->src.y + c->height; 189142542f5fSchristos if (c->damaged.y2 <= c->damaged.y1) 189242542f5fSchristos goto done; 189342542f5fSchristos 189442542f5fSchristos DBG(DRAW, ("%s-%s is damaged, last SHM serial: %ld, now %ld\n", 189542542f5fSchristos DisplayString(c->dst.dpy), c->dst.name, 189642542f5fSchristos (long)c->dst.serial, (long)LastKnownRequestProcessed(c->dst.dpy))); 189742542f5fSchristos if (c->dst.serial > LastKnownRequestProcessed(c->dst.dpy)) { 189842542f5fSchristos struct pollfd pfd; 189942542f5fSchristos 190042542f5fSchristos pfd.fd = ConnectionNumber(c->dst.dpy); 190142542f5fSchristos pfd.events = POLLIN; 190242542f5fSchristos XEventsQueued(c->dst.dpy, 190342542f5fSchristos poll(&pfd, 1, 0) ? QueuedAfterReading : QueuedAfterFlush); 190442542f5fSchristos 190542542f5fSchristos if (c->dst.serial > LastKnownRequestProcessed(c->dst.dpy)) { 190642542f5fSchristos c->dst.display->skip_clone++; 190742542f5fSchristos return EAGAIN; 190842542f5fSchristos } 190942542f5fSchristos } 191042542f5fSchristos 191142542f5fSchristos c->dst.display->skip_clone = 0; 191242542f5fSchristos c->dst.display->skip_frame = 0; 191342542f5fSchristos 191442542f5fSchristos if (FORCE_FULL_REDRAW) { 191542542f5fSchristos c->damaged.x1 = c->src.x; 191642542f5fSchristos c->damaged.y1 = c->src.y; 191742542f5fSchristos c->damaged.x2 = c->src.x + c->width; 191842542f5fSchristos c->damaged.y2 = c->src.y + c->height; 191942542f5fSchristos } 192042542f5fSchristos 192142542f5fSchristos if (c->dri3.xid) { 192242542f5fSchristos if (c->src.use_render) { 192342542f5fSchristos XRenderComposite(c->src.dpy, PictOpSrc, 192442542f5fSchristos c->src.win_picture, 0, c->src.pix_picture, 192542542f5fSchristos c->damaged.x1, c->damaged.y1, 192642542f5fSchristos 0, 0, 192742542f5fSchristos c->damaged.x1 + c->dst.x - c->src.x, 192842542f5fSchristos c->damaged.y1 + c->dst.y - c->src.y, 192942542f5fSchristos c->damaged.x2 - c->damaged.x1, 193042542f5fSchristos c->damaged.y2 - c->damaged.y1); 193142542f5fSchristos } else { 193242542f5fSchristos XCopyArea(c->src.dpy, c->src.window, c->src.pixmap, c->src.gc, 193342542f5fSchristos c->damaged.x1, c->damaged.y1, 193442542f5fSchristos c->damaged.x2 - c->damaged.x1, 193542542f5fSchristos c->damaged.y2 - c->damaged.y1, 193642542f5fSchristos c->damaged.x1 + c->dst.x - c->src.x, 193742542f5fSchristos c->damaged.y1 + c->dst.y - c->src.y); 193842542f5fSchristos } 193942542f5fSchristos dri3_fence_flush(c->src.dpy, &c->dri3); 194042542f5fSchristos } else { 194142542f5fSchristos clip.x = c->damaged.x1; 194242542f5fSchristos clip.y = c->damaged.y1; 194342542f5fSchristos clip.width = c->damaged.x2 - c->damaged.x1; 194442542f5fSchristos clip.height = c->damaged.y2 - c->damaged.y1; 194542542f5fSchristos get_src(c, &clip); 194642542f5fSchristos 194742542f5fSchristos clip.x += c->dst.x - c->src.x; 194842542f5fSchristos clip.y += c->dst.y - c->src.y; 194942542f5fSchristos put_dst(c, &clip); 195042542f5fSchristos } 195142542f5fSchristos display_mark_flush(c->dst.display); 195242542f5fSchristos 195342542f5fSchristosdone: 195442542f5fSchristos c->damaged.x2 = c->damaged.y2 = INT_MIN; 195542542f5fSchristos c->damaged.x1 = c->damaged.y1 = INT_MAX; 195642542f5fSchristos return 0; 195742542f5fSchristos} 195842542f5fSchristos 195942542f5fSchristosstatic void clone_damage(struct clone *c, const XRectangle *rec) 196042542f5fSchristos{ 196142542f5fSchristos int v; 196242542f5fSchristos 196342542f5fSchristos if ((v = rec->x) < c->damaged.x1) 196442542f5fSchristos c->damaged.x1 = v; 196542542f5fSchristos if ((v = (int)rec->x + rec->width) > c->damaged.x2) 196642542f5fSchristos c->damaged.x2 = v; 196742542f5fSchristos if ((v = rec->y) < c->damaged.y1) 196842542f5fSchristos c->damaged.y1 = v; 196942542f5fSchristos if ((v = (int)rec->y + rec->height) > c->damaged.y2) 197042542f5fSchristos c->damaged.y2 = v; 197142542f5fSchristos 197242542f5fSchristos DBG(DAMAGE, ("%s-%s damaged: (%d, %d), (%d, %d)\n", 197342542f5fSchristos DisplayString(c->dst.display->dpy), c->dst.name, 197442542f5fSchristos c->damaged.x1, c->damaged.y1, 197542542f5fSchristos c->damaged.x2, c->damaged.y2)); 197642542f5fSchristos} 197742542f5fSchristos 197842542f5fSchristosstatic void usage(const char *arg0) 197942542f5fSchristos{ 198042542f5fSchristos printf("Usage: %s [OPTION]... [TARGET_DISPLAY]...\n", arg0); 198142542f5fSchristos printf(" -d <source display> source display\n"); 198242542f5fSchristos printf(" -f keep in foreground (do not detach from console and daemonize)\n"); 198342542f5fSchristos printf(" -b start bumblebee\n"); 198442542f5fSchristos printf(" -a connect to all local displays (e.g. :1, :2, etc)\n"); 198542542f5fSchristos printf(" -S disable use of a singleton and launch a fresh intel-virtual-output process\n"); 198642542f5fSchristos printf(" -v all verbose output, implies -f\n"); 198742542f5fSchristos printf(" -V <category> specific verbose output, implies -f\n"); 198842542f5fSchristos printf(" -h this help\n"); 198942542f5fSchristos printf("If no target displays are parsed on the commandline, \n"); 199042542f5fSchristos printf("intel-virtual-output will attempt to connect to any local display\n"); 199142542f5fSchristos printf("and then start bumblebee.\n"); 199242542f5fSchristos} 199342542f5fSchristos 199442542f5fSchristosstatic void record_callback(XPointer closure, XRecordInterceptData *data) 199542542f5fSchristos{ 199642542f5fSchristos struct context *ctx = (struct context *)closure; 199742542f5fSchristos 199842542f5fSchristos DBG(X11, ("%s\n", __func__)); 199942542f5fSchristos 200042542f5fSchristos if (data->category == XRecordFromServer) { 200142542f5fSchristos const xEvent *e = (const xEvent *)data->data; 200242542f5fSchristos 200342542f5fSchristos DBG(X11, ("%s -- from server, event type %d, root %ld (ours? %d)\n", 200442542f5fSchristos __func__, e->u.u.type, (long)e->u.keyButtonPointer.root, 200542542f5fSchristos ctx->display->root == e->u.keyButtonPointer.root)); 200642542f5fSchristos 200742542f5fSchristos if (e->u.u.type == MotionNotify && 200842542f5fSchristos e->u.keyButtonPointer.root == ctx->display->root) { 200942542f5fSchristos struct clone *clone; 201042542f5fSchristos 201142542f5fSchristos for (clone = ctx->active; clone; clone = clone->active) 201242542f5fSchristos clone_move_cursor(clone, 201342542f5fSchristos e->u.keyButtonPointer.rootX, 201442542f5fSchristos e->u.keyButtonPointer.rootY); 201542542f5fSchristos } 201642542f5fSchristos } 201742542f5fSchristos 201842542f5fSchristos XRecordFreeData(data); 201942542f5fSchristos} 202042542f5fSchristos 202142542f5fSchristosstatic int record_mouse(struct context *ctx) 202242542f5fSchristos{ 202342542f5fSchristos Display *dpy; 202442542f5fSchristos XRecordRange *rr; 202542542f5fSchristos XRecordClientSpec rcs; 202642542f5fSchristos XRecordContext rc; 202742542f5fSchristos 202842542f5fSchristos DBG(X11, ("%s(%s)\n", __func__, DisplayString(ctx->display->dpy))); 202942542f5fSchristos 203042542f5fSchristos dpy = XOpenDisplay(DisplayString(ctx->display->dpy)); 203142542f5fSchristos if (dpy == NULL) 203242542f5fSchristos return -ECONNREFUSED; 203342542f5fSchristos 203442542f5fSchristos rr = XRecordAllocRange(); 203542542f5fSchristos if (rr == NULL) 203642542f5fSchristos return -ENOMEM; 203742542f5fSchristos 203842542f5fSchristos rr->device_events.first = rr->device_events.last = MotionNotify; 203942542f5fSchristos 204042542f5fSchristos rcs = XRecordAllClients; 204142542f5fSchristos rc = XRecordCreateContext(dpy, 0, &rcs, 1, &rr, 1); 204242542f5fSchristos 204342542f5fSchristos XSync(dpy, False); 204442542f5fSchristos 204542542f5fSchristos if (!XRecordEnableContextAsync(dpy, rc, record_callback, (XPointer)ctx)) 204642542f5fSchristos return -EINVAL; 204742542f5fSchristos 204842542f5fSchristos ctx->record = dpy; 204942542f5fSchristos return ConnectionNumber(dpy); 205042542f5fSchristos} 205142542f5fSchristos 205242542f5fSchristosstatic int bad_visual(Visual *visual, int depth) 205342542f5fSchristos{ 205442542f5fSchristos DBG(X11, ("%s? depth=%d, visual: class=%d, bits_per_rgb=%d, red_mask=%08lx, green_mask=%08lx, blue_mask=%08lx\n", 205542542f5fSchristos __func__, depth, 205642542f5fSchristos visual->class, 205742542f5fSchristos visual->bits_per_rgb, 205842542f5fSchristos visual->red_mask, 205942542f5fSchristos visual->green_mask, 206042542f5fSchristos visual->blue_mask)); 206142542f5fSchristos 206242542f5fSchristos if (!(visual->class == TrueColor || visual->class == DirectColor)) 206342542f5fSchristos return 1; 206442542f5fSchristos 206542542f5fSchristos switch (depth) { 206642542f5fSchristos case 16: return (/* visual->bits_per_rgb != 6 || */ 206742542f5fSchristos visual->red_mask != 0x1f << 11 || 206842542f5fSchristos visual->green_mask != 0x3f << 5 || 206942542f5fSchristos visual->blue_mask != 0x1f << 0); 207042542f5fSchristos 207142542f5fSchristos case 24: return (/* visual->bits_per_rgb != 8 || */ 207242542f5fSchristos visual->red_mask != 0xff << 16 || 207342542f5fSchristos visual->green_mask != 0xff << 8 || 207442542f5fSchristos visual->blue_mask != 0xff << 0); 207542542f5fSchristos 207642542f5fSchristos default: return 1; 207742542f5fSchristos } 207842542f5fSchristos} 207942542f5fSchristos 208042542f5fSchristosstatic XRenderPictFormat * 208142542f5fSchristosfind_xrender_format(Display *dpy, pixman_format_code_t format) 208242542f5fSchristos{ 208342542f5fSchristos XRenderPictFormat tmpl; 208442542f5fSchristos int mask; 208542542f5fSchristos 208642542f5fSchristos#define MASK(x) ((1<<(x))-1) 208742542f5fSchristos 208842542f5fSchristos memset(&tmpl, 0, sizeof(tmpl)); 208942542f5fSchristos 209042542f5fSchristos tmpl.depth = PIXMAN_FORMAT_DEPTH(format); 209142542f5fSchristos mask = PictFormatType | PictFormatDepth; 209242542f5fSchristos 209342542f5fSchristos DBG(X11, ("%s(0x%08lx)\n", __func__, (long)format)); 209442542f5fSchristos 209542542f5fSchristos switch (PIXMAN_FORMAT_TYPE(format)) { 209642542f5fSchristos case PIXMAN_TYPE_ARGB: 209742542f5fSchristos tmpl.type = PictTypeDirect; 209842542f5fSchristos 209942542f5fSchristos if (PIXMAN_FORMAT_A(format)) { 210042542f5fSchristos tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format)); 210142542f5fSchristos tmpl.direct.alpha = (PIXMAN_FORMAT_R(format) + 210242542f5fSchristos PIXMAN_FORMAT_G(format) + 210342542f5fSchristos PIXMAN_FORMAT_B(format)); 210442542f5fSchristos } 210542542f5fSchristos 210642542f5fSchristos tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format)); 210742542f5fSchristos tmpl.direct.red = (PIXMAN_FORMAT_G(format) + 210842542f5fSchristos PIXMAN_FORMAT_B(format)); 210942542f5fSchristos 211042542f5fSchristos tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format)); 211142542f5fSchristos tmpl.direct.green = PIXMAN_FORMAT_B(format); 211242542f5fSchristos 211342542f5fSchristos tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format)); 211442542f5fSchristos tmpl.direct.blue = 0; 211542542f5fSchristos 211642542f5fSchristos mask |= PictFormatRed | PictFormatRedMask; 211742542f5fSchristos mask |= PictFormatGreen | PictFormatGreenMask; 211842542f5fSchristos mask |= PictFormatBlue | PictFormatBlueMask; 211942542f5fSchristos mask |= PictFormatAlpha | PictFormatAlphaMask; 212042542f5fSchristos break; 212142542f5fSchristos 212242542f5fSchristos case PIXMAN_TYPE_ABGR: 212342542f5fSchristos tmpl.type = PictTypeDirect; 212442542f5fSchristos 212542542f5fSchristos if (tmpl.direct.alphaMask) { 212642542f5fSchristos tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format)); 212742542f5fSchristos tmpl.direct.alpha = (PIXMAN_FORMAT_B(format) + 212842542f5fSchristos PIXMAN_FORMAT_G(format) + 212942542f5fSchristos PIXMAN_FORMAT_R(format)); 213042542f5fSchristos } 213142542f5fSchristos 213242542f5fSchristos tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format)); 213342542f5fSchristos tmpl.direct.blue = (PIXMAN_FORMAT_G(format) + 213442542f5fSchristos PIXMAN_FORMAT_R(format)); 213542542f5fSchristos 213642542f5fSchristos tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format)); 213742542f5fSchristos tmpl.direct.green = PIXMAN_FORMAT_R(format); 213842542f5fSchristos 213942542f5fSchristos tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format)); 214042542f5fSchristos tmpl.direct.red = 0; 214142542f5fSchristos 214242542f5fSchristos mask |= PictFormatRed | PictFormatRedMask; 214342542f5fSchristos mask |= PictFormatGreen | PictFormatGreenMask; 214442542f5fSchristos mask |= PictFormatBlue | PictFormatBlueMask; 214542542f5fSchristos mask |= PictFormatAlpha | PictFormatAlphaMask; 214642542f5fSchristos break; 214742542f5fSchristos 214842542f5fSchristos case PIXMAN_TYPE_BGRA: 214942542f5fSchristos tmpl.type = PictTypeDirect; 215042542f5fSchristos 215142542f5fSchristos tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format)); 215242542f5fSchristos tmpl.direct.blue = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format)); 215342542f5fSchristos 215442542f5fSchristos tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format)); 215542542f5fSchristos tmpl.direct.green = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) - 215642542f5fSchristos PIXMAN_FORMAT_G(format)); 215742542f5fSchristos 215842542f5fSchristos tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format)); 215942542f5fSchristos tmpl.direct.red = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) - 216042542f5fSchristos PIXMAN_FORMAT_G(format) - PIXMAN_FORMAT_R(format)); 216142542f5fSchristos 216242542f5fSchristos if (tmpl.direct.alphaMask) { 216342542f5fSchristos tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format)); 216442542f5fSchristos tmpl.direct.alpha = 0; 216542542f5fSchristos } 216642542f5fSchristos 216742542f5fSchristos mask |= PictFormatRed | PictFormatRedMask; 216842542f5fSchristos mask |= PictFormatGreen | PictFormatGreenMask; 216942542f5fSchristos mask |= PictFormatBlue | PictFormatBlueMask; 217042542f5fSchristos mask |= PictFormatAlpha | PictFormatAlphaMask; 217142542f5fSchristos break; 217242542f5fSchristos 217342542f5fSchristos case PIXMAN_TYPE_A: 217442542f5fSchristos tmpl.type = PictTypeDirect; 217542542f5fSchristos 217642542f5fSchristos tmpl.direct.alpha = 0; 217742542f5fSchristos tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format)); 217842542f5fSchristos 217942542f5fSchristos mask |= PictFormatAlpha | PictFormatAlphaMask; 218042542f5fSchristos break; 218142542f5fSchristos 218242542f5fSchristos case PIXMAN_TYPE_COLOR: 218342542f5fSchristos case PIXMAN_TYPE_GRAY: 218442542f5fSchristos /* XXX Find matching visual/colormap */ 218542542f5fSchristos tmpl.type = PictTypeIndexed; 218642542f5fSchristos //tmpl.colormap = screen->visuals[PIXMAN_FORMAT_VIS(format)].vid; 218742542f5fSchristos //mask |= PictFormatColormap; 218842542f5fSchristos return NULL; 218942542f5fSchristos } 219042542f5fSchristos#undef MASK 219142542f5fSchristos 219242542f5fSchristos return XRenderFindFormat(dpy, mask, &tmpl, 0); 219342542f5fSchristos} 219442542f5fSchristos 219542542f5fSchristosstatic int display_init_render(struct display *display, int depth, XRenderPictFormat **use_render) 219642542f5fSchristos{ 219742542f5fSchristos Display *dpy = display->dpy; 219842542f5fSchristos int major, minor; 219942542f5fSchristos 220042542f5fSchristos DBG(X11, ("%s is depth %d, want %d\n", DisplayString(dpy), display->depth, depth)); 220142542f5fSchristos 220242542f5fSchristos *use_render = 0; 220342542f5fSchristos if (depth == display->depth && !bad_visual(display->visual, depth)) 220442542f5fSchristos return 0; 220542542f5fSchristos 220642542f5fSchristos if (display->root_format == 0) { 220742542f5fSchristos if (!XRenderQueryVersion(dpy, &major, &minor)) { 220842542f5fSchristos fprintf(stderr, "Render extension not supported by %s\n", DisplayString(dpy)); 220942542f5fSchristos return -EINVAL; 221042542f5fSchristos } 221142542f5fSchristos 221242542f5fSchristos display->root_format = XRenderFindVisualFormat(dpy, display->visual); 221342542f5fSchristos display->rgb16_format = find_xrender_format(dpy, PIXMAN_r5g6b5); 221442542f5fSchristos display->rgb24_format = XRenderFindStandardFormat(dpy, PictStandardRGB24); 221542542f5fSchristos 221642542f5fSchristos DBG(X11, ("%s: root format=%lx, rgb16 format=%lx, rgb24 format=%lx\n", 221742542f5fSchristos DisplayString(dpy), 221842542f5fSchristos (long)display->root_format, 221942542f5fSchristos (long)display->rgb16_format, 222042542f5fSchristos (long)display->rgb24_format)); 222142542f5fSchristos } 222242542f5fSchristos 222342542f5fSchristos switch (depth) { 222442542f5fSchristos case 16: *use_render = display->rgb16_format; break; 222542542f5fSchristos case 24: *use_render = display->rgb24_format; break; 222642542f5fSchristos } 222742542f5fSchristos if (*use_render == 0) 222842542f5fSchristos return -ENOENT; 222942542f5fSchristos 223042542f5fSchristos return 0; 223142542f5fSchristos} 223242542f5fSchristos 223342542f5fSchristosstatic int clone_init_depth(struct clone *clone) 223442542f5fSchristos{ 223542542f5fSchristos int ret, depth; 223642542f5fSchristos 223742542f5fSchristos DBG(X11,("%s-%s wants depth %d\n", 223842542f5fSchristos DisplayString(clone->dst.dpy), clone->dst.name, clone->depth)); 223942542f5fSchristos 224042542f5fSchristos ret = -1; 224142542f5fSchristos for (depth = clone->depth; depth <= 24; depth += 8) { 224242542f5fSchristos ret = display_init_render(clone->src.display, depth, &clone->src.use_render); 224342542f5fSchristos if (ret) 224442542f5fSchristos continue; 224542542f5fSchristos 224642542f5fSchristos ret = display_init_render(clone->dst.display, depth, &clone->dst.use_render); 224742542f5fSchristos if (ret) 224842542f5fSchristos continue; 224942542f5fSchristos 225042542f5fSchristos break; 225142542f5fSchristos } 225242542f5fSchristos if (ret) 225342542f5fSchristos return ret; 225442542f5fSchristos 225542542f5fSchristos DBG(X11, ("%s-%s using depth %d, requires xrender for src? %d, for dst? %d\n", 225642542f5fSchristos DisplayString(clone->dst.dpy), clone->dst.name, 225742542f5fSchristos clone->depth, 225842542f5fSchristos clone->src.use_render != NULL, 225942542f5fSchristos clone->dst.use_render != NULL)); 226042542f5fSchristos 226142542f5fSchristos if (!clone->dst.use_render && 226242542f5fSchristos clone->src.display->dri3_active && 226342542f5fSchristos clone->dst.display->dri3_active) 226442542f5fSchristos dri3_create_fence(clone->src.dpy, clone->src.window, &clone->dri3); 226542542f5fSchristos 226642542f5fSchristos return 0; 226742542f5fSchristos} 226842542f5fSchristos 226942542f5fSchristos#if defined(USE_XINERAMA) 227042542f5fSchristosstatic int xinerama_active(struct display *display) 227142542f5fSchristos{ 227242542f5fSchristos int active = 0; 227342542f5fSchristos if (XineramaQueryExtension(display->dpy, &display->xinerama_event, &display->xinerama_error)) 227442542f5fSchristos active = XineramaIsActive(display->dpy); 227542542f5fSchristos return active; 227642542f5fSchristos} 227742542f5fSchristos#else 227842542f5fSchristos#define xinerama_active(d) 0 227942542f5fSchristos#endif 228042542f5fSchristos 228142542f5fSchristosstatic int add_display(struct context *ctx, Display *dpy) 228242542f5fSchristos{ 228342542f5fSchristos struct display *display; 228442542f5fSchristos int first_display = ctx->ndisplay == 0; 228542542f5fSchristos 228642542f5fSchristos if (is_power_of_2(ctx->ndisplay)) { 228742542f5fSchristos struct display *new_display; 228842542f5fSchristos 228942542f5fSchristos new_display = realloc(ctx->display, 2*ctx->ndisplay*sizeof(struct display)); 229042542f5fSchristos if (new_display == NULL) 229142542f5fSchristos return -ENOMEM; 229242542f5fSchristos 229342542f5fSchristos if (new_display != ctx->display) { 229442542f5fSchristos int n; 229542542f5fSchristos 229642542f5fSchristos for (n = 0; n < ctx->nclone; n++) { 229742542f5fSchristos struct clone *clone = &ctx->clones[n]; 229842542f5fSchristos clone->src.display = new_display + (clone->src.display - ctx->display); 229942542f5fSchristos clone->dst.display = new_display + (clone->dst.display - ctx->display); 230042542f5fSchristos } 230142542f5fSchristos } 230242542f5fSchristos 230342542f5fSchristos ctx->display = new_display; 230442542f5fSchristos } 230542542f5fSchristos 230642542f5fSchristos display = memset(&ctx->display[ctx->ndisplay++], 0, sizeof(struct display)); 230742542f5fSchristos 230842542f5fSchristos display->dpy = dpy; 230942542f5fSchristos display->ctx = ctx; 231042542f5fSchristos 231142542f5fSchristos display->root = DefaultRootWindow(dpy); 231242542f5fSchristos display->depth = DefaultDepth(dpy, DefaultScreen(dpy)); 231342542f5fSchristos display->visual = DefaultVisual(dpy, DefaultScreen(dpy)); 231442542f5fSchristos 231542542f5fSchristos display->has_shm = can_use_shm(dpy, display->root, 231642542f5fSchristos &display->shm_event, 231742542f5fSchristos &display->shm_opcode, 231842542f5fSchristos &display->has_shm_pixmap); 231942542f5fSchristos DBG(X11, ("%s: has_shm?=%d, event=%d, opcode=%d, has_pixmap?=%d\n", 232042542f5fSchristos DisplayString(dpy), 232142542f5fSchristos display->has_shm, 232242542f5fSchristos display->shm_event, 232342542f5fSchristos display->shm_opcode, 232442542f5fSchristos display->has_shm_pixmap)); 232542542f5fSchristos 232642542f5fSchristos display->rr_active = XRRQueryExtension(dpy, &display->rr_event, &display->rr_error); 232742542f5fSchristos DBG(X11, ("%s: randr_active?=%d, event=%d, error=%d\n", 232842542f5fSchristos DisplayString(dpy), 232942542f5fSchristos display->rr_active, 233042542f5fSchristos display->rr_event, 233142542f5fSchristos display->rr_error)); 233242542f5fSchristos 233342542f5fSchristos display->xinerama_active = xinerama_active(display); 233442542f5fSchristos DBG(X11, ("%s: xinerama_active?=%d, event=%d, error=%d\n", 233542542f5fSchristos DisplayString(dpy), 233642542f5fSchristos display->xinerama_active, 233742542f5fSchristos display->xinerama_event, 233842542f5fSchristos display->xinerama_error)); 233942542f5fSchristos 234042542f5fSchristos display->dri3_active = dri3_exists(dpy); 234142542f5fSchristos DBG(X11, ("%s: dri3_active?=%d\n", 234242542f5fSchristos DisplayString(dpy), 234342542f5fSchristos display->dri3_active)); 234442542f5fSchristos 234542542f5fSchristos /* first display (source) is slightly special */ 234642542f5fSchristos if (!first_display) { 234742542f5fSchristos display->invisible_cursor = display_load_invisible_cursor(display); 234842542f5fSchristos display_cursor_move(display, 0, 0, 0); 234942542f5fSchristos } 235042542f5fSchristos 235142542f5fSchristos return ConnectionNumber(dpy); 235242542f5fSchristos} 235342542f5fSchristos 235442542f5fSchristosstatic int display_open(struct context *ctx, const char *name) 235542542f5fSchristos{ 235642542f5fSchristos Display *dpy; 235742542f5fSchristos int n; 235842542f5fSchristos 235942542f5fSchristos DBG(X11, ("%s(%s)\n", __func__, name)); 236042542f5fSchristos 236142542f5fSchristos dpy = XOpenDisplay(name); 236242542f5fSchristos if (dpy == NULL) 236342542f5fSchristos return -ECONNREFUSED; 236442542f5fSchristos 236542542f5fSchristos /* Prevent cloning the same display twice */ 236642542f5fSchristos for (n = 0; n < ctx->ndisplay; n++) { 236742542f5fSchristos if (strcmp(DisplayString(dpy), DisplayString(ctx->display[n].dpy)) == 0) { 236842542f5fSchristos DBG(X11, ("%s %s is already connected\n", __func__, name)); 236942542f5fSchristos XCloseDisplay(dpy); 237042542f5fSchristos return -EBUSY; 237142542f5fSchristos } 237242542f5fSchristos } 237342542f5fSchristos 237442542f5fSchristos return add_display(ctx, dpy); 237542542f5fSchristos} 237642542f5fSchristos 237742542f5fSchristosstatic int bumblebee_open(struct context *ctx) 237842542f5fSchristos{ 237942542f5fSchristos char buf[256]; 238042542f5fSchristos struct sockaddr_un addr; 238142542f5fSchristos int fd, len; 238242542f5fSchristos 238342542f5fSchristos fd = socket(PF_UNIX, SOCK_STREAM, 0); 238442542f5fSchristos if (fd < 0) { 238542542f5fSchristos DBG(X11, ("%s unable to create a socket: %d\n", __func__, errno)); 238642542f5fSchristos return -ECONNREFUSED; 238742542f5fSchristos } 238842542f5fSchristos 238942542f5fSchristos addr.sun_family = AF_UNIX; 239042542f5fSchristos snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", 239142542f5fSchristos optarg && *optarg ? optarg : "/var/run/bumblebee.socket"); 239242542f5fSchristos if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 239342542f5fSchristos DBG(X11, ("%s unable to create a socket: %d\n", __func__, errno)); 239442542f5fSchristos goto err; 239542542f5fSchristos } 239642542f5fSchristos 239742542f5fSchristos /* Ask bumblebee to start the second server */ 239842542f5fSchristos buf[0] = 'C'; 239942542f5fSchristos if (send(fd, &buf, 1, 0) != 1 || (len = recv(fd, &buf, 255, 0)) <= 0) { 240042542f5fSchristos DBG(X11, ("%s startup send/recv failed: %d\n", __func__, errno)); 240142542f5fSchristos goto err; 240242542f5fSchristos } 240342542f5fSchristos buf[len] = '\0'; 240442542f5fSchristos 240542542f5fSchristos /* Query the display name */ 240642542f5fSchristos strcpy(buf, "Q VirtualDisplay"); 240742542f5fSchristos if (send(fd, buf, 17, 0) != 17 || (len = recv(fd, buf, 255, 0)) <= 0) { 240842542f5fSchristos DBG(X11, ("%s query send/recv failed: %d\n", __func__, errno)); 240942542f5fSchristos goto err; 241042542f5fSchristos } 241142542f5fSchristos buf[len] = '\0'; 241242542f5fSchristos 241342542f5fSchristos DBG(X11, ("%s query result '%s'\n", __func__, buf)); 241442542f5fSchristos 241542542f5fSchristos if (strncmp(buf, "Value: ", 7)) 241642542f5fSchristos goto err; 241742542f5fSchristos 241842542f5fSchristos len = 7; 241942542f5fSchristos while (buf[len] != '\n' && buf[len] != '\0') 242042542f5fSchristos len++; 242142542f5fSchristos buf[len] = '\0'; 242242542f5fSchristos 242342542f5fSchristos /* XXX We must keep the control socket open whilst we want to keep 242442542f5fSchristos * the display around. 242542542f5fSchristos * 242642542f5fSchristos * So what we need to do is listen for new bumblee Xservers and 242742542f5fSchristos * bind only for their duration. 242842542f5fSchristos */ 242942542f5fSchristos 243042542f5fSchristos return display_open(ctx, buf+7); 243142542f5fSchristos 243242542f5fSchristoserr: 243342542f5fSchristos close(fd); 243442542f5fSchristos return -ECONNREFUSED; 243542542f5fSchristos} 243642542f5fSchristos 243742542f5fSchristosstatic int display_init_damage(struct display *display) 243842542f5fSchristos{ 243942542f5fSchristos DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy))); 244042542f5fSchristos 244142542f5fSchristos if (!XDamageQueryExtension(display->dpy, &display->damage_event, &display->damage_error) || 244242542f5fSchristos !XFixesQueryExtension(display->dpy, &display->xfixes_event, &display->xfixes_error)) { 244342542f5fSchristos fprintf(stderr, "Damage/Fixes extension not supported by %s\n", DisplayString(display->dpy)); 244442542f5fSchristos return EINVAL; 244542542f5fSchristos } 244642542f5fSchristos 244742542f5fSchristos display->damage = XDamageCreate(display->dpy, display->root, XDamageReportBoundingBox); 244842542f5fSchristos if (display->damage == 0) 244942542f5fSchristos return EACCES; 245042542f5fSchristos 245142542f5fSchristos return 0; 245242542f5fSchristos} 245342542f5fSchristos 245442542f5fSchristosstatic void display_reset_damage(struct display *display) 245542542f5fSchristos{ 245642542f5fSchristos Damage damage; 245742542f5fSchristos 245842542f5fSchristos damage = XDamageCreate(display->dpy, display->root, XDamageReportBoundingBox); 245942542f5fSchristos if (damage) { 246042542f5fSchristos XDamageDestroy(display->dpy, display->damage); 246142542f5fSchristos display->damage = damage; 246242542f5fSchristos XFlush(display->dpy); 246342542f5fSchristos display->flush = 0; 246442542f5fSchristos } 246542542f5fSchristos} 246642542f5fSchristos 246742542f5fSchristosstatic void display_init_randr_hpd(struct display *display) 246842542f5fSchristos{ 246942542f5fSchristos int major, minor; 247042542f5fSchristos 247142542f5fSchristos DBG(X11,("%s(%s)\n", __func__, DisplayString(display->dpy))); 247242542f5fSchristos 247342542f5fSchristos if (!XRRQueryVersion(display->dpy, &major, &minor)) 247442542f5fSchristos return; 247542542f5fSchristos 247642542f5fSchristos DBG(X11, ("%s - randr version %d.%d\n", DisplayString(display->dpy), major, minor)); 247742542f5fSchristos if (major > 1 || (major == 1 && minor >= 2)) 247842542f5fSchristos XRRSelectInput(display->dpy, display->root, RROutputChangeNotifyMask); 247942542f5fSchristos} 248042542f5fSchristos 248142542f5fSchristosstatic void rebuild_clones(struct context *ctx, struct clone *new_clones) 248242542f5fSchristos{ 248342542f5fSchristos int n, m; 248442542f5fSchristos 248542542f5fSchristos for (n = 1; n < ctx->ndisplay; n++) { 248642542f5fSchristos struct display *d = &ctx->display[n]; 248742542f5fSchristos 248842542f5fSchristos d->clone = NULL; 248942542f5fSchristos for (m = 0; m < ctx->nclone; m++) { 249042542f5fSchristos struct clone *c = &new_clones[m]; 249142542f5fSchristos 249242542f5fSchristos if (c->dst.display != d) 249342542f5fSchristos continue; 249442542f5fSchristos 249542542f5fSchristos c->next = d->clone; 249642542f5fSchristos d->clone = c; 249742542f5fSchristos } 249842542f5fSchristos } 249942542f5fSchristos 250042542f5fSchristos ctx->clones = new_clones; 250142542f5fSchristos} 250242542f5fSchristos 250342542f5fSchristosstatic struct clone *add_clone(struct context *ctx) 250442542f5fSchristos{ 250542542f5fSchristos if (is_power_of_2(ctx->nclone)) { 250642542f5fSchristos struct clone *new_clones; 250742542f5fSchristos 250842542f5fSchristos new_clones = realloc(ctx->clones, 2*ctx->nclone*sizeof(struct clone)); 250942542f5fSchristos if (new_clones == NULL) 251042542f5fSchristos return NULL; 251142542f5fSchristos 251242542f5fSchristos if (new_clones != ctx->clones) 251342542f5fSchristos rebuild_clones(ctx, new_clones); 251442542f5fSchristos } 251542542f5fSchristos 251642542f5fSchristos return memset(&ctx->clones[ctx->nclone++], 0, sizeof(struct clone)); 251742542f5fSchristos} 251842542f5fSchristos 251942542f5fSchristosstatic struct display *last_display(struct context *ctx) 252042542f5fSchristos{ 252142542f5fSchristos return &ctx->display[ctx->ndisplay-1]; 252242542f5fSchristos} 252342542f5fSchristos 252442542f5fSchristosstatic void reverse_clone_list(struct display *display) 252542542f5fSchristos{ 252642542f5fSchristos struct clone *list = NULL; 252742542f5fSchristos 252842542f5fSchristos while (display->clone) { 252942542f5fSchristos struct clone *clone = display->clone; 253042542f5fSchristos display->clone = clone->next; 253142542f5fSchristos clone->next = list; 253242542f5fSchristos list = clone; 253342542f5fSchristos } 253442542f5fSchristos 253542542f5fSchristos display->clone = list; 253642542f5fSchristos} 253742542f5fSchristos 253842542f5fSchristosstatic int last_display_add_clones__randr(struct context *ctx) 253942542f5fSchristos{ 254042542f5fSchristos struct display *display = last_display(ctx); 254142542f5fSchristos XRRScreenResources *res; 254242542f5fSchristos char buf[80]; 254342542f5fSchristos int i, ret; 254442542f5fSchristos 254542542f5fSchristos DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy))); 254642542f5fSchristos 254742542f5fSchristos display_init_randr_hpd(display); 254842542f5fSchristos 254942542f5fSchristos /* Force a probe of outputs on initial connection */ 255042542f5fSchristos res = XRRGetScreenResources(display->dpy, display->root); 255142542f5fSchristos if (res == NULL) 255242542f5fSchristos return -ENOMEM; 255342542f5fSchristos 255442542f5fSchristos DBG(X11, ("%s - noutputs=%d\n", DisplayString(display->dpy), res->noutput)); 255542542f5fSchristos for (i = 0; i < res->noutput; i++) { 255642542f5fSchristos XRROutputInfo *o = XRRGetOutputInfo(display->dpy, res, res->outputs[i]); 255742542f5fSchristos struct clone *clone = add_clone(ctx); 255842542f5fSchristos RROutput id; 255942542f5fSchristos 256042542f5fSchristos if (clone == NULL) 256142542f5fSchristos return -ENOMEM; 256242542f5fSchristos 256342542f5fSchristos clone->depth = 24; 256442542f5fSchristos clone->next = display->clone; 256542542f5fSchristos display->clone = clone; 256642542f5fSchristos 256742542f5fSchristos id = claim_virtual(ctx->display, buf, ctx->nclone); 256842542f5fSchristos if (id == 0) { 256942542f5fSchristos fprintf(stderr, "Failed to find available VirtualHead \"%s\" for \"%s\" on display \"%s\"\n", 257042542f5fSchristos buf, o->name, DisplayString(display->dpy)); 257142542f5fSchristos return -ENOSPC; 257242542f5fSchristos } 257342542f5fSchristos 257442542f5fSchristos ret = clone_output_init(clone, &clone->src, ctx->display, buf, id); 257542542f5fSchristos if (ret) { 257642542f5fSchristos fprintf(stderr, "Failed to add output \"%s\" on display \"%s\"\n", 257742542f5fSchristos buf, DisplayString(ctx->display->dpy)); 257842542f5fSchristos return ret; 257942542f5fSchristos } 258042542f5fSchristos 258142542f5fSchristos ret = clone_output_init(clone, &clone->dst, display, o->name, res->outputs[i]); 258242542f5fSchristos if (ret) { 258342542f5fSchristos fprintf(stderr, "Failed to add output \"%s\" on display \"%s\"\n", 258442542f5fSchristos o->name, DisplayString(display->dpy)); 258542542f5fSchristos return ret; 258642542f5fSchristos } 258742542f5fSchristos 258842542f5fSchristos ret = clone_init_depth(clone); 258942542f5fSchristos if (ret) { 259042542f5fSchristos fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n", 259142542f5fSchristos DisplayString(display->dpy)); 259242542f5fSchristos return ret; 259342542f5fSchristos } 259442542f5fSchristos 259542542f5fSchristos ret = clone_update_modes__randr(clone); 259642542f5fSchristos if (ret) { 259742542f5fSchristos fprintf(stderr, "Failed to clone output \"%s\" from display \"%s\"\n", 259842542f5fSchristos o->name, DisplayString(display->dpy)); 259942542f5fSchristos return ret; 260042542f5fSchristos } 260142542f5fSchristos 260242542f5fSchristos 260342542f5fSchristos if (o->crtc) { 260442542f5fSchristos DBG(X11, ("%s - disabling active output\n", DisplayString(display->dpy))); 260542542f5fSchristos disable_crtc(display->dpy, res, o->crtc); 260642542f5fSchristos } 260742542f5fSchristos 260842542f5fSchristos XRRFreeOutputInfo(o); 260942542f5fSchristos } 261042542f5fSchristos XRRFreeScreenResources(res); 261142542f5fSchristos 261242542f5fSchristos reverse_clone_list(display); 261342542f5fSchristos return 0; 261442542f5fSchristos} 261542542f5fSchristos 261642542f5fSchristos#if defined(USE_XINERAMA) 261742542f5fSchristosstatic int last_display_add_clones__xinerama(struct context *ctx) 261842542f5fSchristos{ 261942542f5fSchristos struct display *display = last_display(ctx); 262042542f5fSchristos Display *dpy = display->dpy; 262142542f5fSchristos XineramaScreenInfo *xi; 262242542f5fSchristos char buf[80]; 262342542f5fSchristos int n, count, ret; 262442542f5fSchristos 262542542f5fSchristos DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy))); 262642542f5fSchristos 262742542f5fSchristos count = 0; 262842542f5fSchristos xi = XineramaQueryScreens(dpy, &count); 262942542f5fSchristos for (n = 0; n < count; n++) { 263042542f5fSchristos struct clone *clone = add_clone(ctx); 263142542f5fSchristos RROutput id; 263242542f5fSchristos 263342542f5fSchristos if (clone == NULL) 263442542f5fSchristos return -ENOMEM; 263542542f5fSchristos 263642542f5fSchristos if (xi[n].width == 0 || xi[n].height == 0) 263742542f5fSchristos continue; 263842542f5fSchristos 263942542f5fSchristos clone->depth = 24; 264042542f5fSchristos clone->next = display->clone; 264142542f5fSchristos display->clone = clone; 264242542f5fSchristos 264342542f5fSchristos id = claim_virtual(ctx->display, buf, ctx->nclone); 264442542f5fSchristos if (id == 0) { 264542542f5fSchristos fprintf(stderr, "Failed to find available VirtualHead \"%s\" for Xinerama screen %d on display \"%s\"\n", 264642542f5fSchristos buf, n, DisplayString(dpy)); 264742542f5fSchristos } 264842542f5fSchristos ret = clone_output_init(clone, &clone->src, ctx->display, buf, id); 264942542f5fSchristos if (ret) { 265042542f5fSchristos fprintf(stderr, "Failed to add Xinerama screen %d on display \"%s\"\n", 265142542f5fSchristos n, DisplayString(ctx->display->dpy)); 265242542f5fSchristos return ret; 265342542f5fSchristos } 265442542f5fSchristos 265542542f5fSchristos sprintf(buf, "XINERAMA%d", n); 265642542f5fSchristos ret = clone_output_init(clone, &clone->dst, display, buf, 0); 265742542f5fSchristos if (ret) { 265842542f5fSchristos fprintf(stderr, "Failed to add Xinerama screen %d on display \"%s\"\n", 265942542f5fSchristos n, DisplayString(dpy)); 266042542f5fSchristos return ret; 266142542f5fSchristos } 266242542f5fSchristos 266342542f5fSchristos ret = clone_init_depth(clone); 266442542f5fSchristos if (ret) { 266542542f5fSchristos fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n", 266642542f5fSchristos DisplayString(display->dpy)); 266742542f5fSchristos return ret; 266842542f5fSchristos } 266942542f5fSchristos 267042542f5fSchristos /* Replace the modes on the local VIRTUAL output with the remote Screen */ 267142542f5fSchristos clone->width = xi[n].width; 267242542f5fSchristos clone->height = xi[n].height; 267342542f5fSchristos clone->dst.x = xi[n].x_org; 267442542f5fSchristos clone->dst.y = xi[n].y_org; 267542542f5fSchristos clone->dst.rr_crtc = -1; 267642542f5fSchristos ret = clone_update_modes__fixed(clone); 267742542f5fSchristos if (ret) { 267842542f5fSchristos fprintf(stderr, "Failed to clone Xinerama screen %d from display \"%s\"\n", 267942542f5fSchristos n, DisplayString(display->dpy)); 268042542f5fSchristos return ret; 268142542f5fSchristos } 268242542f5fSchristos 268342542f5fSchristos clone->active = ctx->active; 268442542f5fSchristos ctx->active = clone; 268542542f5fSchristos } 268642542f5fSchristos XFree(xi); 268742542f5fSchristos 268842542f5fSchristos reverse_clone_list(display); 268942542f5fSchristos return 0; 269042542f5fSchristos} 269142542f5fSchristos#else 269242542f5fSchristos#define last_display_add_clones__xinerama(ctx) -1 269342542f5fSchristos#endif 269442542f5fSchristos 269542542f5fSchristosstatic int last_display_add_clones__display(struct context *ctx) 269642542f5fSchristos{ 269742542f5fSchristos struct display *display = last_display(ctx); 269842542f5fSchristos Display *dpy = display->dpy; 269942542f5fSchristos struct clone *clone; 270042542f5fSchristos Screen *scr; 270142542f5fSchristos char buf[80]; 270242542f5fSchristos int ret; 270342542f5fSchristos RROutput id; 270442542f5fSchristos 270542542f5fSchristos 270642542f5fSchristos DBG(X11, ("%s(%s)\n", __func__, DisplayString(dpy))); 270742542f5fSchristos clone = add_clone(ctx); 270842542f5fSchristos if (clone == NULL) 270942542f5fSchristos return -ENOMEM; 271042542f5fSchristos 271142542f5fSchristos clone->depth = 24; 271242542f5fSchristos clone->next = display->clone; 271342542f5fSchristos display->clone = clone; 271442542f5fSchristos 271542542f5fSchristos id = claim_virtual(ctx->display, buf, ctx->nclone); 271642542f5fSchristos if (id == 0) { 271742542f5fSchristos fprintf(stderr, "Failed to find available VirtualHead \"%s\" for on display \"%s\"\n", 271842542f5fSchristos buf, DisplayString(dpy)); 271942542f5fSchristos } 272042542f5fSchristos ret = clone_output_init(clone, &clone->src, ctx->display, buf, id); 272142542f5fSchristos if (ret) { 272242542f5fSchristos fprintf(stderr, "Failed to add display \"%s\"\n", 272342542f5fSchristos DisplayString(ctx->display->dpy)); 272442542f5fSchristos return ret; 272542542f5fSchristos } 272642542f5fSchristos 272742542f5fSchristos sprintf(buf, "WHOLE"); 272842542f5fSchristos ret = clone_output_init(clone, &clone->dst, display, buf, 0); 272942542f5fSchristos if (ret) { 273042542f5fSchristos fprintf(stderr, "Failed to add display \"%s\"\n", 273142542f5fSchristos DisplayString(dpy)); 273242542f5fSchristos return ret; 273342542f5fSchristos } 273442542f5fSchristos 273542542f5fSchristos ret = clone_init_depth(clone); 273642542f5fSchristos if (ret) { 273742542f5fSchristos fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n", 273842542f5fSchristos DisplayString(dpy)); 273942542f5fSchristos return ret; 274042542f5fSchristos } 274142542f5fSchristos 274242542f5fSchristos /* Replace the modes on the local VIRTUAL output with the remote Screen */ 274342542f5fSchristos scr = ScreenOfDisplay(dpy, DefaultScreen(dpy)); 274442542f5fSchristos clone->width = scr->width; 274542542f5fSchristos clone->height = scr->height; 274642542f5fSchristos clone->dst.x = 0; 274742542f5fSchristos clone->dst.y = 0; 274842542f5fSchristos clone->dst.rr_crtc = -1; 274942542f5fSchristos ret = clone_update_modes__fixed(clone); 275042542f5fSchristos if (ret) { 275142542f5fSchristos fprintf(stderr, "Failed to clone display \"%s\"\n", 275242542f5fSchristos DisplayString(dpy)); 275342542f5fSchristos return ret; 275442542f5fSchristos } 275542542f5fSchristos 275642542f5fSchristos clone->active = ctx->active; 275742542f5fSchristos ctx->active = clone; 275842542f5fSchristos 275942542f5fSchristos return 0; 276042542f5fSchristos} 276142542f5fSchristos 276242542f5fSchristosstatic int last_display_add_clones(struct context *ctx) 276342542f5fSchristos{ 276442542f5fSchristos struct display *display = last_display(ctx); 276542542f5fSchristos 276642542f5fSchristos display->width = DisplayWidth(display->dpy, DefaultScreen(display->dpy)); 276742542f5fSchristos display->height = DisplayHeight(display->dpy, DefaultScreen(display->dpy)); 276842542f5fSchristos DBG(X11, ("%s - initial size %dx%d\n", DisplayString(display->dpy), display->width, display->height)); 276942542f5fSchristos 277042542f5fSchristos if (display->rr_active) 277142542f5fSchristos return last_display_add_clones__randr(ctx); 277242542f5fSchristos 277342542f5fSchristos if (display->xinerama_active) 277442542f5fSchristos return last_display_add_clones__xinerama(ctx); 277542542f5fSchristos 277642542f5fSchristos return last_display_add_clones__display(ctx); 277742542f5fSchristos} 277842542f5fSchristos 277942542f5fSchristosstatic int last_display_clone(struct context *ctx, int fd) 278042542f5fSchristos{ 278142542f5fSchristos fd = add_fd(ctx, fd); 278242542f5fSchristos if (fd < 0) 278342542f5fSchristos return fd; 278442542f5fSchristos 278542542f5fSchristos fd = last_display_add_clones(ctx); 278642542f5fSchristos if (fd) 278742542f5fSchristos return fd; 278842542f5fSchristos 278942542f5fSchristos return 0; 279042542f5fSchristos} 279142542f5fSchristos 279242542f5fSchristosstatic int first_display_has_singleton(struct context *ctx) 279342542f5fSchristos{ 279442542f5fSchristos struct display *display = ctx->display; 279542542f5fSchristos unsigned long nitems, bytes; 279642542f5fSchristos unsigned char *prop; 279742542f5fSchristos int format; 279842542f5fSchristos Atom type; 279942542f5fSchristos 280042542f5fSchristos ctx->singleton = XInternAtom(display->dpy, "intel-virtual-output-singleton", False); 280142542f5fSchristos 280242542f5fSchristos XGetWindowProperty(display->dpy, display->root, ctx->singleton, 280342542f5fSchristos 0, 0, 0, AnyPropertyType, &type, &format, &nitems, &bytes, &prop); 280442542f5fSchristos DBG(X11, ("%s: singleton registered? %d\n", DisplayString(display->dpy), type != None)); 280542542f5fSchristos return type != None; 280642542f5fSchristos} 280742542f5fSchristos 280842542f5fSchristosstatic int first_display_wait_for_ack(struct context *ctx, int timeout, int id) 280942542f5fSchristos{ 281042542f5fSchristos struct display *display = ctx->display; 281142542f5fSchristos struct pollfd pfd; 281242542f5fSchristos char expect[6]; /* "1234R\0" */ 281342542f5fSchristos 281442542f5fSchristos sprintf(expect, "%04xR", id); 281542542f5fSchristos DBG(X11, ("%s: wait for act '%c%c%c%c%c'\n", 281642542f5fSchristos DisplayString(display->dpy), 281742542f5fSchristos expect[0], expect[1], expect[2], expect[3], expect[4])); 281842542f5fSchristos 281942542f5fSchristos XFlush(display->dpy); 282042542f5fSchristos 282142542f5fSchristos pfd.fd = ConnectionNumber(display->dpy); 282242542f5fSchristos pfd.events = POLLIN; 282342542f5fSchristos do { 282442542f5fSchristos if (poll(&pfd, 1, timeout) <= 0) 282542542f5fSchristos return -ETIME; 282642542f5fSchristos 282742542f5fSchristos while (XPending(display->dpy)) { 282842542f5fSchristos XEvent e; 282942542f5fSchristos XClientMessageEvent *cme; 283042542f5fSchristos 283142542f5fSchristos XNextEvent(display->dpy, &e); 283242542f5fSchristos DBG(X11, ("%s: reading event type %d\n", DisplayString(display->dpy), e.type)); 283342542f5fSchristos 283442542f5fSchristos if (e.type != ClientMessage) 283542542f5fSchristos continue; 283642542f5fSchristos 283742542f5fSchristos cme = (XClientMessageEvent *)&e; 283842542f5fSchristos if (cme->message_type != ctx->singleton) 283942542f5fSchristos continue; 284042542f5fSchristos if (cme->format != 8) 284142542f5fSchristos continue; 284242542f5fSchristos 284342542f5fSchristos DBG(X11, ("%s: client message '%c%c%c%c%c'\n", 284442542f5fSchristos DisplayString(display->dpy), 284542542f5fSchristos cme->data.b[0], 284642542f5fSchristos cme->data.b[1], 284742542f5fSchristos cme->data.b[2], 284842542f5fSchristos cme->data.b[3], 284942542f5fSchristos cme->data.b[4])); 285042542f5fSchristos if (memcmp(cme->data.b, expect, 5)) 285142542f5fSchristos continue; 285242542f5fSchristos 285342542f5fSchristos return -atoi(cme->data.b + 5); 285442542f5fSchristos } 285542542f5fSchristos } while (1); 285642542f5fSchristos} 285742542f5fSchristos 285842542f5fSchristos#if defined(__GNUC__) && (__GNUC__ > 3) 285942542f5fSchristos__attribute__((format(gnu_printf, 3, 4))) 286042542f5fSchristos#endif 286142542f5fSchristosstatic int first_display_send_command(struct context *ctx, int timeout, 286242542f5fSchristos const char *format, 286342542f5fSchristos ...) 286442542f5fSchristos{ 286542542f5fSchristos struct display *display = ctx->display; 286642542f5fSchristos char buf[1024], *b; 286742542f5fSchristos int len, id; 286842542f5fSchristos va_list va; 286942542f5fSchristos 287042542f5fSchristos id = rand() & 0xffff; 287142542f5fSchristos sprintf(buf, "%04x", id); 287242542f5fSchristos va_start(va, format); 287342542f5fSchristos len = vsnprintf(buf+4, sizeof(buf)-4, format, va)+5; 287442542f5fSchristos va_end(va); 287542542f5fSchristos assert(len < sizeof(buf)); 287642542f5fSchristos 287742542f5fSchristos DBG(X11, ("%s: send command '%s'\n", DisplayString(display->dpy), buf)); 287842542f5fSchristos 287942542f5fSchristos b = buf; 288042542f5fSchristos while (len) { 288142542f5fSchristos XClientMessageEvent msg; 288242542f5fSchristos int n = len; 288342542f5fSchristos if (n > sizeof(msg.data.b)) 288442542f5fSchristos n = sizeof(msg.data.b); 288542542f5fSchristos len -= n; 288642542f5fSchristos 288742542f5fSchristos msg.type = ClientMessage; 288842542f5fSchristos msg.serial = 0; 288942542f5fSchristos msg.message_type = ctx->singleton; 289042542f5fSchristos msg.format = 8; 289142542f5fSchristos memcpy(msg.data.b, b, n); 289242542f5fSchristos b += n; 289342542f5fSchristos 289442542f5fSchristos XSendEvent(display->dpy, display->root, False, PropertyChangeMask, (XEvent *)&msg); 289542542f5fSchristos } 289642542f5fSchristos 289742542f5fSchristos return first_display_wait_for_ack(ctx, timeout, id); 289842542f5fSchristos} 289942542f5fSchristos 290042542f5fSchristosstatic void first_display_reply(struct context *ctx, int result) 290142542f5fSchristos{ 290242542f5fSchristos struct display *display = ctx->display; 290342542f5fSchristos XClientMessageEvent msg; 290442542f5fSchristos 290542542f5fSchristos sprintf(msg.data.b, "%c%c%c%cR%d", 290642542f5fSchristos ctx->command[0], 290742542f5fSchristos ctx->command[1], 290842542f5fSchristos ctx->command[2], 290942542f5fSchristos ctx->command[3], 291042542f5fSchristos -result); 291142542f5fSchristos 291242542f5fSchristos DBG(X11, ("%s: send reply '%s'\n", DisplayString(display->dpy), msg.data.b)); 291342542f5fSchristos 291442542f5fSchristos msg.type = ClientMessage; 291542542f5fSchristos msg.serial = 0; 291642542f5fSchristos msg.message_type = ctx->singleton; 291742542f5fSchristos msg.format = 8; 291842542f5fSchristos 291942542f5fSchristos XSendEvent(display->dpy, display->root, False, PropertyChangeMask, (XEvent *)&msg); 292042542f5fSchristos XFlush(display->dpy); 292142542f5fSchristos} 292242542f5fSchristos 292342542f5fSchristosstatic void first_display_handle_command(struct context *ctx, 292442542f5fSchristos const char *msg) 292542542f5fSchristos{ 292642542f5fSchristos int len; 292742542f5fSchristos 292842542f5fSchristos DBG(X11, ("client message!\n")); 292942542f5fSchristos 293042542f5fSchristos for (len = 0; len < 20 && msg[len]; len++) 293142542f5fSchristos ; 293242542f5fSchristos 293342542f5fSchristos if (ctx->command_continuation + len > sizeof(ctx->command)) { 293442542f5fSchristos ctx->command_continuation = 0; 293542542f5fSchristos return; 293642542f5fSchristos } 293742542f5fSchristos 293842542f5fSchristos memcpy(ctx->command + ctx->command_continuation, msg, len); 293942542f5fSchristos ctx->command_continuation += len; 294042542f5fSchristos 294142542f5fSchristos if (len < 20) { 294242542f5fSchristos ctx->command[ctx->command_continuation] = 0; 294342542f5fSchristos DBG(X11, ("client command complete! '%s'\n", ctx->command)); 294442542f5fSchristos switch (ctx->command[4]) { 294542542f5fSchristos case 'B': 294642542f5fSchristos first_display_reply(ctx, last_display_clone(ctx, bumblebee_open(ctx))); 294742542f5fSchristos break; 294842542f5fSchristos case 'C': 294942542f5fSchristos first_display_reply(ctx, last_display_clone(ctx, display_open(ctx, ctx->command + 5))); 295042542f5fSchristos break; 295142542f5fSchristos case 'P': 295242542f5fSchristos first_display_reply(ctx, 0); 295342542f5fSchristos break; 295442542f5fSchristos case 'R': 295542542f5fSchristos break; 295642542f5fSchristos } 295742542f5fSchristos ctx->command_continuation = 0; 295842542f5fSchristos return; 295942542f5fSchristos } 296042542f5fSchristos} 296142542f5fSchristos 296242542f5fSchristosstatic int first_display_register_as_singleton(struct context *ctx) 296342542f5fSchristos{ 296442542f5fSchristos struct display *display = ctx->display; 296542542f5fSchristos struct pollfd pfd; 296642542f5fSchristos 296742542f5fSchristos XChangeProperty(display->dpy, display->root, ctx->singleton, 296842542f5fSchristos XA_STRING, 8, PropModeReplace, (unsigned char *)".", 1); 296942542f5fSchristos XFlush(display->dpy); 297042542f5fSchristos 297142542f5fSchristos /* And eat the notify (presuming that it is ours!) */ 297242542f5fSchristos 297342542f5fSchristos pfd.fd = ConnectionNumber(display->dpy); 297442542f5fSchristos pfd.events = POLLIN; 297542542f5fSchristos do { 297642542f5fSchristos if (poll(&pfd, 1, 1000) <= 0) { 297742542f5fSchristos fprintf(stderr, "Failed to register as singleton\n"); 297842542f5fSchristos return EBUSY; 297942542f5fSchristos } 298042542f5fSchristos 298142542f5fSchristos while (XPending(display->dpy)) { 298242542f5fSchristos XEvent e; 298342542f5fSchristos 298442542f5fSchristos XNextEvent(display->dpy, &e); 298542542f5fSchristos DBG(X11, ("%s: reading event type %d\n", DisplayString(display->dpy), e.type)); 298642542f5fSchristos 298742542f5fSchristos if (e.type == PropertyNotify && 298842542f5fSchristos ((XPropertyEvent *)&e)->atom == ctx->singleton) 298942542f5fSchristos return 0; 299042542f5fSchristos } 299142542f5fSchristos } while (1); 299242542f5fSchristos} 299342542f5fSchristos 299442542f5fSchristosstatic void display_flush_send(struct display *display) 299542542f5fSchristos{ 299642542f5fSchristos XShmCompletionEvent e; 299742542f5fSchristos 299842542f5fSchristos if (!display->send) 299942542f5fSchristos return; 300042542f5fSchristos 300142542f5fSchristos DBG(X11, ("%s flushing send (serial now %ld) (has shm send? %d)\n", 300242542f5fSchristos DisplayString(display->dpy), 300342542f5fSchristos (long)NextRequest(display->dpy), 300442542f5fSchristos display->shm_event)); 300542542f5fSchristos 300642542f5fSchristos display->send = 0; 300742542f5fSchristos 300842542f5fSchristos if (display->shm_event == 0) { 300942542f5fSchristos XSync(display->dpy, False); 301042542f5fSchristos display->flush = 0; 301142542f5fSchristos return; 301242542f5fSchristos } 301342542f5fSchristos 301442542f5fSchristos memset(&e, 0, sizeof(e)); 301542542f5fSchristos e.type = display->shm_event; 301642542f5fSchristos e.send_event = 1; 301742542f5fSchristos e.drawable = display->root; 301842542f5fSchristos e.major_code = display->shm_opcode; 301942542f5fSchristos e.minor_code = X_ShmPutImage; 302042542f5fSchristos 302142542f5fSchristos XSendEvent(display->dpy, display->root, False, 0, (XEvent *)&e); 302242542f5fSchristos display_mark_flush(display); 302342542f5fSchristos} 302442542f5fSchristos 302542542f5fSchristosstatic void display_sync(struct display *display) 302642542f5fSchristos{ 302742542f5fSchristos if (display->skip_clone == 0) 302842542f5fSchristos return; 302942542f5fSchristos 303042542f5fSchristos if (display->skip_frame++ < 2) 303142542f5fSchristos return; 303242542f5fSchristos 303342542f5fSchristos DBG(X11, ("%s forcing sync\n", DisplayString(display->dpy))); 303442542f5fSchristos XSync(display->dpy, False); 303542542f5fSchristos 303642542f5fSchristos display->flush = 0; 303742542f5fSchristos display->send = 0; 303842542f5fSchristos 303942542f5fSchristos /* Event tracking proven unreliable, disable */ 304042542f5fSchristos display->shm_event = 0; 304142542f5fSchristos} 304242542f5fSchristos 304342542f5fSchristosstatic void display_flush(struct display *display) 304442542f5fSchristos{ 304542542f5fSchristos display_flush_cursor(display); 304642542f5fSchristos display_flush_send(display); 304742542f5fSchristos 304842542f5fSchristos display_sync(display); 304942542f5fSchristos 305042542f5fSchristos if (!display->flush) 305142542f5fSchristos return; 305242542f5fSchristos 305342542f5fSchristos DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy))); 305442542f5fSchristos 305542542f5fSchristos XFlush(display->dpy); 305642542f5fSchristos display->flush = 0; 305742542f5fSchristos} 305842542f5fSchristos 305942542f5fSchristosstatic int first_display_first_sibling(struct context *ctx) 306042542f5fSchristos{ 306142542f5fSchristos const char *str, *colon; 306242542f5fSchristos int dpy, scr, len; 306342542f5fSchristos 306442542f5fSchristos str = DisplayString(ctx->display->dpy); 306542542f5fSchristos colon = strrchr(str, ':'); 306642542f5fSchristos if (colon == NULL) 306742542f5fSchristos return -1; 306842542f5fSchristos 306942542f5fSchristos if (sscanf(colon + 1, "%d.%d", &dpy, &scr) == 1) 307042542f5fSchristos scr = 0; 307142542f5fSchristos 307242542f5fSchristos len = (colon - str) + 1; 307342542f5fSchristos memcpy(ctx->command, str, len); 307442542f5fSchristos len += sprintf(ctx->command + len, "%d.", dpy); 307542542f5fSchristos ctx->command_continuation = len; 307642542f5fSchristos 307742542f5fSchristos return scr + 1; 307842542f5fSchristos} 307942542f5fSchristos 308042542f5fSchristosstatic int first_display_sibling(struct context *ctx, int i) 308142542f5fSchristos{ 308242542f5fSchristos if (i < 0) 308342542f5fSchristos return 0; 308442542f5fSchristos 308542542f5fSchristos sprintf(ctx->command + ctx->command_continuation, "%d", i); 308642542f5fSchristos return 1; 308742542f5fSchristos} 308842542f5fSchristos 308942542f5fSchristos#define first_display_for_each_sibling(CTX, i) \ 309042542f5fSchristos for (i = first_display_first_sibling(CTX); first_display_sibling(CTX, i); i++) 309142542f5fSchristos 309242542f5fSchristosstatic void display_cleanup(struct display *display) 309342542f5fSchristos{ 309442542f5fSchristos Display *dpy = display->dpy; 309542542f5fSchristos XRRScreenResources *res; 309642542f5fSchristos int n; 309742542f5fSchristos 309842542f5fSchristos XGrabServer(dpy); 309942542f5fSchristos 310042542f5fSchristos res = _XRRGetScreenResourcesCurrent(dpy, display->root); 310142542f5fSchristos if (res != NULL) { 310242542f5fSchristos for (n = 0; n < res->ncrtc; n++) 310342542f5fSchristos disable_crtc(display->dpy, res, res->crtcs[n]); 310442542f5fSchristos 310542542f5fSchristos XRRFreeScreenResources(res); 310642542f5fSchristos } 310742542f5fSchristos 310842542f5fSchristos XUngrabServer(dpy); 310942542f5fSchristos} 311042542f5fSchristos 311142542f5fSchristosstatic void context_cleanup(struct context *ctx) 311242542f5fSchristos{ 311342542f5fSchristos Display *dpy = ctx->display->dpy; 311442542f5fSchristos XRRScreenResources *res; 311542542f5fSchristos int i, j; 311642542f5fSchristos 311742542f5fSchristos for (i = 1; i < ctx->ndisplay; i++) 311842542f5fSchristos display_cleanup(&ctx->display[i]); 311942542f5fSchristos 312013496ba1Ssnj if (dpy == NULL) 312113496ba1Ssnj return; 312213496ba1Ssnj 312342542f5fSchristos res = _XRRGetScreenResourcesCurrent(dpy, ctx->display->root); 312442542f5fSchristos if (res == NULL) 312542542f5fSchristos return; 312642542f5fSchristos 312742542f5fSchristos XGrabServer(dpy); 312842542f5fSchristos 312942542f5fSchristos for (i = 0; i < ctx->nclone; i++) { 313042542f5fSchristos struct clone *clone = &ctx->clones[i]; 313142542f5fSchristos XRROutputInfo *output; 313242542f5fSchristos 313342542f5fSchristos assert(clone->src.display == ctx->display); 313442542f5fSchristos 313542542f5fSchristos output = XRRGetOutputInfo(dpy, res, clone->src.rr_output); 313642542f5fSchristos if (output == NULL) 313742542f5fSchristos continue; 313842542f5fSchristos 313942542f5fSchristos disable_crtc(dpy, res, output->crtc); 314042542f5fSchristos for (j = 0; j < output->nmode; j++) 314142542f5fSchristos XRRDeleteOutputMode(dpy, clone->src.rr_output, output->modes[j]); 314242542f5fSchristos 314342542f5fSchristos XRRFreeOutputInfo(output); 314442542f5fSchristos } 314542542f5fSchristos 314642542f5fSchristos for (i = 0; i < res->nmode; i++) { 314742542f5fSchristos if (strncmp(res->modes[i].name, "VIRTUAL", 7) == 0) { 314842542f5fSchristos XRRDestroyMode(dpy, res->modes[i].id); 314942542f5fSchristos continue; 315042542f5fSchristos } 315142542f5fSchristos 315242542f5fSchristos if (strcmp(res->modes[i].name, "ClaimVirtualHead") == 0) { 315342542f5fSchristos XRRDestroyMode(dpy, res->modes[i].id); 315442542f5fSchristos continue; 315542542f5fSchristos } 315642542f5fSchristos } 315742542f5fSchristos XRRFreeScreenResources(res); 315842542f5fSchristos 315942542f5fSchristos /* And hide them again */ 316042542f5fSchristos res = XRRGetScreenResources(dpy, ctx->display->root); 316142542f5fSchristos if (res != NULL) 316242542f5fSchristos XRRFreeScreenResources(res); 316342542f5fSchristos 316442542f5fSchristos XUngrabServer(dpy); 316542542f5fSchristos 316642542f5fSchristos if (ctx->singleton) 316742542f5fSchristos XDeleteProperty(dpy, ctx->display->root, ctx->singleton); 316842542f5fSchristos XCloseDisplay(dpy); 316942542f5fSchristos} 317042542f5fSchristos 317142542f5fSchristosstatic int done; 317242542f5fSchristos 317342542f5fSchristosstatic void signal_handler(int sig) 317442542f5fSchristos{ 317542542f5fSchristos done = sig; 317642542f5fSchristos} 317742542f5fSchristos 317842542f5fSchristosint main(int argc, char **argv) 317942542f5fSchristos{ 318042542f5fSchristos struct context ctx; 318142542f5fSchristos const char *src_name = NULL; 318242542f5fSchristos uint64_t count; 318342542f5fSchristos int daemonize = 1, bumblebee = 0, siblings = 0, singleton = 1; 318442542f5fSchristos int i, ret, open, fail; 318542542f5fSchristos 318642542f5fSchristos signal(SIGPIPE, SIG_IGN); 318742542f5fSchristos 318842542f5fSchristos while ((i = getopt(argc, argv, "abd:fhSvV:")) != -1) { 318942542f5fSchristos switch (i) { 319042542f5fSchristos case 'd': 319142542f5fSchristos src_name = optarg; 319242542f5fSchristos break; 319342542f5fSchristos case 'f': 319442542f5fSchristos daemonize = 0; 319542542f5fSchristos break; 319642542f5fSchristos case 'b': 319742542f5fSchristos bumblebee = 1; 319842542f5fSchristos break; 319942542f5fSchristos case 's': 320042542f5fSchristos siblings = 1; 320142542f5fSchristos break; 320242542f5fSchristos case 'S': 320342542f5fSchristos singleton = 0; 320442542f5fSchristos break; 320542542f5fSchristos case 'v': 320642542f5fSchristos verbose = ~0; 320742542f5fSchristos daemonize = 0; 320842542f5fSchristos break; 320942542f5fSchristos case 'V': 321042542f5fSchristos verbose = strtol(optarg, NULL, 0); 321142542f5fSchristos daemonize = 0; 321242542f5fSchristos break; 321342542f5fSchristos case 'h': 321442542f5fSchristos default: 321542542f5fSchristos usage(argv[0]); 321642542f5fSchristos exit(0); 321742542f5fSchristos } 321842542f5fSchristos } 321942542f5fSchristos 322013496ba1Ssnj if (verbose) 322113496ba1Ssnj printf("intel-virtual-output: version %d.%d.%d\n", 322213496ba1Ssnj PACKAGE_VERSION_MAJOR, 322313496ba1Ssnj PACKAGE_VERSION_MINOR, 322413496ba1Ssnj PACKAGE_VERSION_PATCHLEVEL); 322513496ba1Ssnj 322642542f5fSchristos ret = context_init(&ctx); 322742542f5fSchristos if (ret) 322842542f5fSchristos return -ret; 322942542f5fSchristos 323042542f5fSchristos XSetErrorHandler(_check_error_handler); 323142542f5fSchristos 323242542f5fSchristos ret = add_fd(&ctx, display_open(&ctx, src_name)); 323342542f5fSchristos if (ret) { 323442542f5fSchristos fprintf(stderr, "Unable to connect to \"%s\".\n", src_name ?: getenv("DISPLAY") ?: 323542542f5fSchristos "<unspecified>, set either the DISPLAY environment variable or pass -d <display name> on the commandline"); 323642542f5fSchristos ret = -ret; 323742542f5fSchristos goto out; 323842542f5fSchristos } 323942542f5fSchristos 324042542f5fSchristos if (singleton) { 324142542f5fSchristos XSelectInput(ctx.display->dpy, ctx.display->root, PropertyChangeMask); 324242542f5fSchristos if (first_display_has_singleton(&ctx)) { 324342542f5fSchristos DBG(X11, ("%s: pinging singleton\n", DisplayString(ctx.display->dpy))); 324442542f5fSchristos ret = first_display_send_command(&ctx, 2000, "P"); 324542542f5fSchristos if (ret) { 324642542f5fSchristos if (ret != -ETIME) { 324742542f5fSchristos ret = -ret; 324842542f5fSchristos goto out; 324942542f5fSchristos } 325042542f5fSchristos DBG(X11, ("No reply from singleton; assuming control\n")); 325142542f5fSchristos } else { 325242542f5fSchristos DBG(X11, ("%s: singleton active, sending open commands\n", DisplayString(ctx.display->dpy))); 325342542f5fSchristos 325442542f5fSchristos open = fail = 0; 325542542f5fSchristos for (i = optind; i < argc; i++) { 325642542f5fSchristos ret = first_display_send_command(&ctx, 5000, "C%s", argv[i]); 325742542f5fSchristos if (ret && ret != -EBUSY) { 325842542f5fSchristos fprintf(stderr, "Unable to connect to \"%s\".\n", argv[i]); 325942542f5fSchristos fail++; 326042542f5fSchristos } else 326142542f5fSchristos open++; 326242542f5fSchristos } 326342542f5fSchristos if (siblings || (optind == argc && !bumblebee)) { 326442542f5fSchristos first_display_for_each_sibling(&ctx, i) { 326542542f5fSchristos ret = first_display_send_command(&ctx, 5000, "C%s", ctx.command); 326642542f5fSchristos if (ret && ret != -EBUSY) 326742542f5fSchristos break; 326842542f5fSchristos else 326942542f5fSchristos open++; 327042542f5fSchristos } 327142542f5fSchristos } 327242542f5fSchristos if (bumblebee || (optind == argc && !siblings)) { 327342542f5fSchristos ret = first_display_send_command(&ctx, 5000, "B"); 327442542f5fSchristos if (ret && ret != -EBUSY) { 327542542f5fSchristos if (bumblebee) 327642542f5fSchristos fprintf(stderr, "Unable to connect to bumblebee.\n"); 327742542f5fSchristos fail++; 327842542f5fSchristos } else 327942542f5fSchristos open++; 328042542f5fSchristos } 328142542f5fSchristos ret = open || !fail ? 0 : ECONNREFUSED; 328242542f5fSchristos goto out; 328342542f5fSchristos } 328442542f5fSchristos } 328542542f5fSchristos ret = first_display_register_as_singleton(&ctx); 328642542f5fSchristos if (ret) 328742542f5fSchristos goto out; 328842542f5fSchristos } 328942542f5fSchristos 329042542f5fSchristos ret = display_init_damage(ctx.display); 329142542f5fSchristos if (ret) 329242542f5fSchristos goto out; 329342542f5fSchristos 329442542f5fSchristos if ((ctx.display->rr_event | ctx.display->rr_error) == 0) { 329542542f5fSchristos fprintf(stderr, "RandR extension not supported by %s\n", DisplayString(ctx.display->dpy)); 329642542f5fSchristos ret = EINVAL; 329742542f5fSchristos goto out; 329842542f5fSchristos } 329942542f5fSchristos XRRSelectInput(ctx.display->dpy, ctx.display->root, RRScreenChangeNotifyMask); 330042542f5fSchristos XFixesSelectCursorInput(ctx.display->dpy, ctx.display->root, XFixesDisplayCursorNotifyMask); 330142542f5fSchristos 330242542f5fSchristos ret = add_fd(&ctx, record_mouse(&ctx)); 330342542f5fSchristos if (ret) { 330442542f5fSchristos fprintf(stderr, "XTEST extension not supported by display \"%s\"\n", DisplayString(ctx.display->dpy)); 330542542f5fSchristos ret = -ret; 330642542f5fSchristos goto out; 330742542f5fSchristos } 330842542f5fSchristos 330942542f5fSchristos open = fail = 0; 331042542f5fSchristos for (i = optind; i < argc; i++) { 331142542f5fSchristos ret = last_display_clone(&ctx, display_open(&ctx, argv[i])); 331242542f5fSchristos if (ret && ret != -EBUSY) { 331342542f5fSchristos fprintf(stderr, "Unable to connect to \"%s\".\n", argv[i]); 331442542f5fSchristos fail++; 331542542f5fSchristos } else 331642542f5fSchristos open++; 331742542f5fSchristos } 331842542f5fSchristos if (siblings || (optind == argc && !bumblebee)) { 331942542f5fSchristos first_display_for_each_sibling(&ctx, i) { 332042542f5fSchristos ret = last_display_clone(&ctx, display_open(&ctx, ctx.command)); 332142542f5fSchristos if (ret && ret != -EBUSY) 332242542f5fSchristos break; 332342542f5fSchristos else 332442542f5fSchristos open++; 332542542f5fSchristos } 332642542f5fSchristos } 332742542f5fSchristos if (bumblebee || (optind == argc && !siblings)) { 332842542f5fSchristos ret = last_display_clone(&ctx, bumblebee_open(&ctx)); 332942542f5fSchristos if (ret && ret != -EBUSY) { 333042542f5fSchristos if (bumblebee) 333142542f5fSchristos fprintf(stderr, "Unable to connect to bumblebee.\n"); 333242542f5fSchristos fail++; 333342542f5fSchristos } else 333442542f5fSchristos open++; 333542542f5fSchristos } 333642542f5fSchristos if (open == 0) { 333742542f5fSchristos ret = fail ? ECONNREFUSED : 0; 333842542f5fSchristos goto out; 333942542f5fSchristos } 334042542f5fSchristos 334142542f5fSchristos if (daemonize && daemon(0, 0)) { 334242542f5fSchristos ret = EINVAL; 334342542f5fSchristos goto out; 334442542f5fSchristos } 334542542f5fSchristos 334642542f5fSchristos signal(SIGHUP, signal_handler); 334742542f5fSchristos signal(SIGINT, signal_handler); 334842542f5fSchristos signal(SIGTERM, signal_handler); 334942542f5fSchristos 335042542f5fSchristos ctx.command_continuation = 0; 335142542f5fSchristos while (!done) { 335242542f5fSchristos XEvent e; 335342542f5fSchristos int reconfigure = 0; 335442542f5fSchristos int rr_update = 0; 335542542f5fSchristos 335642542f5fSchristos DBG(POLL, ("polling - enable timer? %d, nfd=%d, ndisplay=%d\n", ctx.timer_active, ctx.nfd, ctx.ndisplay)); 335742542f5fSchristos ret = poll(ctx.pfd + !ctx.timer_active, ctx.nfd - !ctx.timer_active, -1); 335842542f5fSchristos if (ret <= 0) 335942542f5fSchristos break; 336042542f5fSchristos 336142542f5fSchristos /* pfd[0] is the timer, pfd[1] is the local display, pfd[2] is the mouse, pfd[3+] are the remotes */ 336242542f5fSchristos 336342542f5fSchristos DBG(POLL, ("poll reports %d fd awake\n", ret)); 336442542f5fSchristos if (ctx.pfd[1].revents || XPending(ctx.display[0].dpy)) { 336542542f5fSchristos DBG(POLL,("%s woken up\n", DisplayString(ctx.display[0].dpy))); 336642542f5fSchristos do { 336742542f5fSchristos XNextEvent(ctx.display->dpy, &e); 336842542f5fSchristos 336942542f5fSchristos if (e.type == ctx.display->damage_event + XDamageNotify ) { 337042542f5fSchristos const XDamageNotifyEvent *de = (const XDamageNotifyEvent *)&e; 337142542f5fSchristos struct clone *clone; 337242542f5fSchristos 337342542f5fSchristos DBG(DAMAGE, ("%s damaged: (%d, %d)x(%d, %d)\n", 337442542f5fSchristos DisplayString(ctx.display->dpy), 337542542f5fSchristos de->area.x, de->area.y, de->area.width, de->area.height)); 337642542f5fSchristos 337742542f5fSchristos for (clone = ctx.active; clone; clone = clone->active) 337842542f5fSchristos clone_damage(clone, &de->area); 337942542f5fSchristos 338042542f5fSchristos if (ctx.active) 338142542f5fSchristos context_enable_timer(&ctx); 338242542f5fSchristos } else if (e.type == ctx.display->xfixes_event + XFixesCursorNotify) { 338342542f5fSchristos XFixesCursorImage *cur; 338442542f5fSchristos 338542542f5fSchristos DBG(CURSOR, ("%s cursor changed\n", 338642542f5fSchristos DisplayString(ctx.display->dpy))); 338742542f5fSchristos 338842542f5fSchristos cur = XFixesGetCursorImage(ctx.display->dpy); 338942542f5fSchristos if (cur == NULL) 339042542f5fSchristos continue; 339142542f5fSchristos 339242542f5fSchristos for (i = 1; i < ctx.ndisplay; i++) 339342542f5fSchristos display_load_visible_cursor(&ctx.display[i], cur); 339442542f5fSchristos 339542542f5fSchristos XFree(cur); 339642542f5fSchristos } else if (e.type == ctx.display->rr_event + RRScreenChangeNotify) { 339742542f5fSchristos DBG(XRR, ("%s screen changed (reconfigure pending? %d)\n", 339842542f5fSchristos DisplayString(ctx.display->dpy), reconfigure)); 339942542f5fSchristos reconfigure = 1; 340042542f5fSchristos } else if (e.type == PropertyNotify) { 340142542f5fSchristos XPropertyEvent *pe = (XPropertyEvent *)&e; 340242542f5fSchristos if (pe->atom == ctx.singleton) { 340342542f5fSchristos DBG(X11, ("lost control of singleton\n")); 340442542f5fSchristos return 0; 340542542f5fSchristos } 340642542f5fSchristos } else if (e.type == ClientMessage) { 340742542f5fSchristos XClientMessageEvent *cme; 340842542f5fSchristos 340942542f5fSchristos DBG(X11, ("%s client message\n", 341042542f5fSchristos DisplayString(ctx.display->dpy))); 341142542f5fSchristos 341242542f5fSchristos cme = (XClientMessageEvent *)&e; 341342542f5fSchristos if (cme->message_type != ctx.singleton) 341442542f5fSchristos continue; 341542542f5fSchristos if (cme->format != 8) 341642542f5fSchristos continue; 341742542f5fSchristos 341842542f5fSchristos first_display_handle_command(&ctx, cme->data.b); 341942542f5fSchristos } else { 342042542f5fSchristos DBG(X11, ("unknown event %d\n", e.type)); 342142542f5fSchristos } 342242542f5fSchristos } while (XEventsQueued(ctx.display->dpy, QueuedAfterReading)); 342342542f5fSchristos } 342442542f5fSchristos 342542542f5fSchristos for (i = 1; i < ctx.ndisplay; i++) { 342642542f5fSchristos if (ctx.pfd[i+2].revents == 0 && !XPending(ctx.display[i].dpy)) 342742542f5fSchristos continue; 342842542f5fSchristos 342942542f5fSchristos DBG(POLL, ("%s woken up\n", DisplayString(ctx.display[i].dpy))); 343042542f5fSchristos do { 343142542f5fSchristos XNextEvent(ctx.display[i].dpy, &e); 343242542f5fSchristos 343342542f5fSchristos DBG(POLL, ("%s received event %d\n", DisplayString(ctx.display[i].dpy), e.type)); 343442542f5fSchristos if (ctx.display[i].rr_active && e.type == ctx.display[i].rr_event + RRNotify) { 343542542f5fSchristos XRRNotifyEvent *re = (XRRNotifyEvent *)&e; 343642542f5fSchristos 343742542f5fSchristos DBG(XRR, ("%s received RRNotify, type %d\n", DisplayString(ctx.display[i].dpy), re->subtype)); 343842542f5fSchristos if (re->subtype == RRNotify_OutputChange) { 343942542f5fSchristos XRROutputPropertyNotifyEvent *ro = (XRROutputPropertyNotifyEvent *)re; 344042542f5fSchristos struct clone *clone; 344142542f5fSchristos 344242542f5fSchristos DBG(XRR, ("%s RRNotify_OutputChange, timestamp %ld\n", DisplayString(ctx.display[i].dpy), ro->timestamp)); 344342542f5fSchristos for (clone = ctx.display[i].clone; clone; clone = clone->next) { 344442542f5fSchristos if (clone->dst.rr_output == ro->output) 344542542f5fSchristos rr_update = clone->rr_update = 1; 344642542f5fSchristos } 344742542f5fSchristos } 344842542f5fSchristos } 344942542f5fSchristos } while (XEventsQueued(ctx.display[i].dpy, QueuedAfterReading)); 345042542f5fSchristos } 345142542f5fSchristos 345242542f5fSchristos if (rr_update) { 345342542f5fSchristos for (i = 0; i < ctx.nclone; i++) 345442542f5fSchristos clone_update(&ctx.clones[i]); 345542542f5fSchristos } 345642542f5fSchristos 345742542f5fSchristos if (reconfigure && context_update(&ctx)) 345842542f5fSchristos display_reset_damage(ctx.display); 345942542f5fSchristos 346042542f5fSchristos while (XPending(ctx.record)) /* discard all implicit events */ 346142542f5fSchristos XNextEvent(ctx.record, &e); 346242542f5fSchristos 346342542f5fSchristos if (ctx.timer_active && read(ctx.timer, &count, sizeof(count)) > 0) { 346442542f5fSchristos struct clone *clone; 346542542f5fSchristos 346642542f5fSchristos DBG(TIMER, ("%s timer expired (count=%ld)\n", DisplayString(ctx.display->dpy), (long)count)); 346742542f5fSchristos ret = 0; 346842542f5fSchristos 346942542f5fSchristos if (ctx.active) { 347042542f5fSchristos DBG(DAMAGE, ("%s clearing damage\n", DisplayString(ctx.display->dpy))); 347142542f5fSchristos XDamageSubtract(ctx.display->dpy, ctx.display->damage, None, None); 347242542f5fSchristos ctx.display->flush = 1; 347342542f5fSchristos } 347442542f5fSchristos 347542542f5fSchristos for (clone = ctx.active; clone; clone = clone->active) 347642542f5fSchristos ret |= clone_paint(clone); 347742542f5fSchristos 347842542f5fSchristos for (i = 0; i < ctx.ndisplay; i++) 347942542f5fSchristos display_flush(&ctx.display[i]); 348042542f5fSchristos 348142542f5fSchristos DBG(TIMER, ("%s timer still active? %d\n", DisplayString(ctx.display->dpy), ret != 0)); 348242542f5fSchristos ctx.timer_active = ret != 0; 348342542f5fSchristos } 348442542f5fSchristos } 348542542f5fSchristos 348642542f5fSchristos ret = 0; 348742542f5fSchristosout: 348842542f5fSchristos context_cleanup(&ctx); 348942542f5fSchristos return ret; 349042542f5fSchristos} 3491