1428d7b3dSmrg/* 2428d7b3dSmrg * Copyright © 2013 Intel Corporation 3428d7b3dSmrg * 4428d7b3dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 5428d7b3dSmrg * copy of this software and associated documentation files (the "Software"), 6428d7b3dSmrg * to deal in the Software without restriction, including without limitation 7428d7b3dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8428d7b3dSmrg * and/or sell copies of the Software, and to permit persons to whom the 9428d7b3dSmrg * Software is furnished to do so, subject to the following conditions: 10428d7b3dSmrg * 11428d7b3dSmrg * The above copyright notice and this permission notice (including the next 12428d7b3dSmrg * paragraph) shall be included in all copies or substantial portions of the 13428d7b3dSmrg * Software. 14428d7b3dSmrg * 15428d7b3dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16428d7b3dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17428d7b3dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18428d7b3dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19428d7b3dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20428d7b3dSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21428d7b3dSmrg * IN THE SOFTWARE. 22428d7b3dSmrg * 23428d7b3dSmrg */ 24428d7b3dSmrg 25428d7b3dSmrg#ifdef HAVE_CONFIG_H 26428d7b3dSmrg#include "config.h" 27428d7b3dSmrg#endif 28428d7b3dSmrg 29428d7b3dSmrg#include <X11/Xlib.h> 30428d7b3dSmrg#include <X11/Xatom.h> 31428d7b3dSmrg 32428d7b3dSmrg#include <X11/Xlibint.h> 33428d7b3dSmrg#include <X11/extensions/record.h> 34428d7b3dSmrg#include <X11/extensions/XShm.h> 35428d7b3dSmrg#if HAVE_X11_EXTENSIONS_SHMPROTO_H 36428d7b3dSmrg#include <X11/extensions/shmproto.h> 37428d7b3dSmrg#elif HAVE_X11_EXTENSIONS_SHMSTR_H 38428d7b3dSmrg#include <X11/extensions/shmstr.h> 39428d7b3dSmrg#else 40428d7b3dSmrg#error Failed to find the right header for X11 MIT-SHM protocol definitions 41428d7b3dSmrg#endif 42428d7b3dSmrg#include <X11/extensions/Xdamage.h> 43428d7b3dSmrg#if HAVE_X11_EXTENSIONS_XINERAMA_H 44428d7b3dSmrg#include <X11/extensions/Xinerama.h> 45428d7b3dSmrg#define USE_XINERAMA 46428d7b3dSmrg#endif 47428d7b3dSmrg#include <X11/extensions/Xrandr.h> 48428d7b3dSmrg#include <X11/extensions/Xrender.h> 49428d7b3dSmrg#include <X11/Xcursor/Xcursor.h> 50428d7b3dSmrg#include <pixman.h> 51428d7b3dSmrg 52428d7b3dSmrg#include <sys/types.h> 53428d7b3dSmrg#include <sys/ipc.h> 54428d7b3dSmrg#include <sys/shm.h> 55428d7b3dSmrg#include <sys/timerfd.h> 56428d7b3dSmrg#include <sys/poll.h> 57428d7b3dSmrg#include <sys/socket.h> 58428d7b3dSmrg#include <sys/un.h> 59428d7b3dSmrg 60428d7b3dSmrg#include <stdarg.h> 61428d7b3dSmrg#include <stdio.h> 62428d7b3dSmrg#include <stdlib.h> 63428d7b3dSmrg#include <stdint.h> 64428d7b3dSmrg#include <signal.h> 65428d7b3dSmrg#include <getopt.h> 66428d7b3dSmrg#include <limits.h> 67428d7b3dSmrg#include <unistd.h> 68428d7b3dSmrg#include <fcntl.h> 69428d7b3dSmrg#include <assert.h> 70428d7b3dSmrg 71428d7b3dSmrg#define FORCE_FULL_REDRAW 0 72428d7b3dSmrg#define FORCE_16BIT_XFER 0 73428d7b3dSmrg 74428d7b3dSmrg#define DBG(v, x) if (verbose & v) printf x 75428d7b3dSmrgstatic int verbose; 76428d7b3dSmrg#define X11 0x1 77428d7b3dSmrg#define XRR 0x1 78428d7b3dSmrg#define TIMER 0x4 79428d7b3dSmrg#define DRAW 0x8 80428d7b3dSmrg#define DAMAGE 0x10 81428d7b3dSmrg#define CURSOR 0x20 82428d7b3dSmrg#define POLL 0x40 83428d7b3dSmrg 84428d7b3dSmrgstruct display { 85428d7b3dSmrg Display *dpy; 86428d7b3dSmrg struct clone *clone; 87428d7b3dSmrg struct context *ctx; 88428d7b3dSmrg 89428d7b3dSmrg int damage_event, damage_error; 90428d7b3dSmrg int xfixes_event, xfixes_error; 91428d7b3dSmrg int rr_event, rr_error, rr_active; 92428d7b3dSmrg int xinerama_event, xinerama_error, xinerama_active; 93428d7b3dSmrg int dri3_active; 94428d7b3dSmrg Window root; 95428d7b3dSmrg Visual *visual; 96428d7b3dSmrg Damage damage; 97428d7b3dSmrg 98428d7b3dSmrg int width; 99428d7b3dSmrg int height; 100428d7b3dSmrg int depth; 101428d7b3dSmrg 102428d7b3dSmrg XRenderPictFormat *root_format; 103428d7b3dSmrg XRenderPictFormat *rgb16_format; 104428d7b3dSmrg XRenderPictFormat *rgb24_format; 105428d7b3dSmrg 106428d7b3dSmrg int has_shm; 107428d7b3dSmrg int has_shm_pixmap; 108428d7b3dSmrg int shm_opcode; 109428d7b3dSmrg int shm_event; 110428d7b3dSmrg 111428d7b3dSmrg Cursor invisible_cursor; 112428d7b3dSmrg Cursor visible_cursor; 113428d7b3dSmrg 114428d7b3dSmrg XcursorImage cursor_image; 115428d7b3dSmrg int cursor_serial; 116428d7b3dSmrg int cursor_x; 117428d7b3dSmrg int cursor_y; 118428d7b3dSmrg int cursor_moved; 119428d7b3dSmrg int cursor_visible; 120428d7b3dSmrg int cursor; 121428d7b3dSmrg 122428d7b3dSmrg int flush; 123428d7b3dSmrg int send; 124428d7b3dSmrg int skip_clone; 125428d7b3dSmrg int skip_frame; 126428d7b3dSmrg}; 127428d7b3dSmrg 128428d7b3dSmrgstruct output { 129428d7b3dSmrg struct display *display; 130428d7b3dSmrg Display *dpy; 131428d7b3dSmrg char *name; 132428d7b3dSmrg RROutput rr_output; 133428d7b3dSmrg RRCrtc rr_crtc; 134428d7b3dSmrg Window window; 135428d7b3dSmrg Picture win_picture; 136428d7b3dSmrg Picture pix_picture; 137428d7b3dSmrg Pixmap pixmap; 138428d7b3dSmrg GC gc; 139428d7b3dSmrg 140428d7b3dSmrg long serial; 141428d7b3dSmrg int use_shm; 142428d7b3dSmrg int use_shm_pixmap; 143428d7b3dSmrg XShmSegmentInfo shm; 144428d7b3dSmrg 145428d7b3dSmrg XRenderPictFormat *use_render; 146428d7b3dSmrg 147428d7b3dSmrg int x, y; 148428d7b3dSmrg XRRModeInfo mode; 149428d7b3dSmrg Rotation rotation; 150428d7b3dSmrg}; 151428d7b3dSmrg 152428d7b3dSmrgstruct clone { 153428d7b3dSmrg struct clone *next; 154428d7b3dSmrg struct clone *active; 155428d7b3dSmrg 156428d7b3dSmrg struct output src, dst; 157428d7b3dSmrg long timestamp; 158428d7b3dSmrg 159428d7b3dSmrg XShmSegmentInfo shm; 160428d7b3dSmrg XImage image; 161428d7b3dSmrg 162428d7b3dSmrg int width, height, depth; 163428d7b3dSmrg struct { int x1, x2, y1, y2; } damaged; 164428d7b3dSmrg int rr_update; 165428d7b3dSmrg 166428d7b3dSmrg struct dri3_fence { 167428d7b3dSmrg XID xid; 168428d7b3dSmrg void *addr; 169428d7b3dSmrg } dri3; 170428d7b3dSmrg}; 171428d7b3dSmrg 172428d7b3dSmrgstruct context { 173428d7b3dSmrg struct display *display; 174428d7b3dSmrg struct clone *clones; 175428d7b3dSmrg struct clone *active; 176428d7b3dSmrg struct pollfd *pfd; 177428d7b3dSmrg#define timer pfd[0].fd 178428d7b3dSmrg Display *record; 179428d7b3dSmrg int nclone; 180428d7b3dSmrg int ndisplay; 181428d7b3dSmrg int nfd; 182428d7b3dSmrg 183428d7b3dSmrg int timer_active; 184428d7b3dSmrg 185428d7b3dSmrg long timestamp; 186428d7b3dSmrg long configTimestamp; 187428d7b3dSmrg 188428d7b3dSmrg Atom singleton; 189428d7b3dSmrg char command[1024]; 190428d7b3dSmrg int command_continuation; 191428d7b3dSmrg}; 192428d7b3dSmrg 193428d7b3dSmrgstatic inline int is_power_of_2(unsigned long n) 194428d7b3dSmrg{ 195428d7b3dSmrg return n && ((n & (n - 1)) == 0); 196428d7b3dSmrg} 197428d7b3dSmrg 198428d7b3dSmrgstatic int xlib_vendor_is_xorg(Display *dpy) 199428d7b3dSmrg{ 200428d7b3dSmrg const char *const vendor = ServerVendor(dpy); 201428d7b3dSmrg return strstr(vendor, "X.Org") || strstr(vendor, "Xorg"); 202428d7b3dSmrg} 203428d7b3dSmrg 204428d7b3dSmrgstatic inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window) 205428d7b3dSmrg{ 206428d7b3dSmrg XRRScreenResources *res; 207428d7b3dSmrg 208428d7b3dSmrg res = XRRGetScreenResourcesCurrent(dpy, window); 209428d7b3dSmrg if (res == NULL) 210428d7b3dSmrg res = XRRGetScreenResources(dpy, window); 211428d7b3dSmrg 212428d7b3dSmrg return res; 213428d7b3dSmrg} 214428d7b3dSmrg 215428d7b3dSmrg#define XORG_VERSION_ENCODE(major,minor,patch,snap) \ 216428d7b3dSmrg (((major) * 10000000) + ((minor) * 100000) + ((patch) * 1000) + snap) 217428d7b3dSmrg 218428d7b3dSmrgstatic int _x_error_occurred; 219428d7b3dSmrg 220428d7b3dSmrgstatic int 221428d7b3dSmrg_check_error_handler(Display *display, 222428d7b3dSmrg XErrorEvent *event) 223428d7b3dSmrg{ 224428d7b3dSmrg DBG(X11, ("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n", 225428d7b3dSmrg DisplayString(display), 226428d7b3dSmrg event->serial, 227428d7b3dSmrg event->error_code, 228428d7b3dSmrg event->request_code, 229428d7b3dSmrg event->minor_code)); 230428d7b3dSmrg _x_error_occurred = 1; 231428d7b3dSmrg return False; /* ignored */ 232428d7b3dSmrg} 233428d7b3dSmrg 234428d7b3dSmrgstatic int 235428d7b3dSmrgcan_use_shm(Display *dpy, 236428d7b3dSmrg Window window, 237428d7b3dSmrg int *shm_event, 238428d7b3dSmrg int *shm_opcode, 239428d7b3dSmrg int *shm_pixmap) 240428d7b3dSmrg{ 241428d7b3dSmrg XShmSegmentInfo shm; 242428d7b3dSmrg Status success; 243428d7b3dSmrg XExtCodes *codes; 244428d7b3dSmrg int major, minor, has_shm, has_pixmap; 245428d7b3dSmrg 246428d7b3dSmrg if (!XShmQueryExtension(dpy)) 247428d7b3dSmrg return 0; 248428d7b3dSmrg 249428d7b3dSmrg XShmQueryVersion(dpy, &major, &minor, &has_pixmap); 250428d7b3dSmrg 251428d7b3dSmrg shm.shmid = shmget(IPC_PRIVATE, 0x1000, IPC_CREAT | 0600); 252428d7b3dSmrg if (shm.shmid == -1) 253428d7b3dSmrg return 0; 254428d7b3dSmrg 255428d7b3dSmrg shm.readOnly = 0; 256428d7b3dSmrg shm.shmaddr = shmat(shm.shmid, NULL, 0); 257428d7b3dSmrg if (shm.shmaddr == (char *) -1) { 258428d7b3dSmrg shmctl(shm.shmid, IPC_RMID, NULL); 259428d7b3dSmrg return 0; 260428d7b3dSmrg } 261428d7b3dSmrg 262428d7b3dSmrg XSync(dpy, False); 263428d7b3dSmrg _x_error_occurred = 0; 264428d7b3dSmrg 265428d7b3dSmrg success = XShmAttach(dpy, &shm); 266428d7b3dSmrg 267428d7b3dSmrg XSync(dpy, False); 268428d7b3dSmrg has_shm = success && _x_error_occurred == 0; 269428d7b3dSmrg 270428d7b3dSmrg /* As libXext sets the SEND_EVENT bit in the ShmCompletionEvent, 271428d7b3dSmrg * the Xserver may crash if it does not take care when processing 272428d7b3dSmrg * the event type. For instance versions of Xorg prior to 1.11.1 273428d7b3dSmrg * exhibited this bug, and was fixed by: 274428d7b3dSmrg * 275428d7b3dSmrg * commit 2d2dce558d24eeea0eb011ec9ebaa6c5c2273c39 276428d7b3dSmrg * Author: Sam Spilsbury <sam.spilsbury@canonical.com> 277428d7b3dSmrg * Date: Wed Sep 14 09:58:34 2011 +0800 278428d7b3dSmrg * 279428d7b3dSmrg * Remove the SendEvent bit (0x80) before doing range checks on event type. 280428d7b3dSmrg */ 281428d7b3dSmrg codes = 0; 282428d7b3dSmrg if (has_shm) 283428d7b3dSmrg codes = XInitExtension(dpy, SHMNAME); 284428d7b3dSmrg if (xlib_vendor_is_xorg(dpy) && 285428d7b3dSmrg VendorRelease(dpy) < XORG_VERSION_ENCODE(1,11,0,1)) 286428d7b3dSmrg codes = 0; 287428d7b3dSmrg if (codes) { 288428d7b3dSmrg XShmCompletionEvent e; 289428d7b3dSmrg 290428d7b3dSmrg memset(&e, 0, sizeof(e)); 291428d7b3dSmrg 292428d7b3dSmrg e.type = codes->first_event; 293428d7b3dSmrg e.send_event = 1; 294428d7b3dSmrg e.serial = 1; 295428d7b3dSmrg e.drawable = window; 296428d7b3dSmrg e.major_code = codes->major_opcode; 297428d7b3dSmrg e.minor_code = X_ShmPutImage; 298428d7b3dSmrg 299428d7b3dSmrg e.shmseg = shm.shmid; 300428d7b3dSmrg e.offset = 0; 301428d7b3dSmrg 302428d7b3dSmrg XSendEvent(dpy, e.drawable, False, 0, (XEvent *)&e); 303428d7b3dSmrg XSync(dpy, False); 304428d7b3dSmrg 305428d7b3dSmrg if (_x_error_occurred == 0) { 306428d7b3dSmrg *shm_opcode = codes->major_opcode; 307428d7b3dSmrg *shm_event = codes->first_event; 308428d7b3dSmrg *shm_pixmap = has_pixmap; 309428d7b3dSmrg } 310428d7b3dSmrg } 311428d7b3dSmrg 312428d7b3dSmrg XShmDetach(dpy, &shm); 313428d7b3dSmrg shmctl(shm.shmid, IPC_RMID, NULL); 314428d7b3dSmrg shmdt(shm.shmaddr); 315428d7b3dSmrg 316428d7b3dSmrg return has_shm; 317428d7b3dSmrg} 318428d7b3dSmrg 319428d7b3dSmrg#ifdef DRI3 320428d7b3dSmrg#include <X11/Xlib-xcb.h> 321428d7b3dSmrg#include <X11/xshmfence.h> 322428d7b3dSmrg#include <xcb/xcb.h> 323428d7b3dSmrg#include <xcb/dri3.h> 324428d7b3dSmrg#include <xcb/sync.h> 325428d7b3dSmrgstatic Pixmap dri3_create_pixmap(Display *dpy, 326428d7b3dSmrg Drawable draw, 327428d7b3dSmrg int width, int height, int depth, 328428d7b3dSmrg int fd, int bpp, int stride, int size) 329428d7b3dSmrg{ 330428d7b3dSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 331428d7b3dSmrg xcb_pixmap_t pixmap = xcb_generate_id(c); 332428d7b3dSmrg xcb_dri3_pixmap_from_buffer(c, pixmap, draw, size, width, height, stride, depth, bpp, fd); 333428d7b3dSmrg return pixmap; 334428d7b3dSmrg} 335428d7b3dSmrg 336428d7b3dSmrgstatic int dri3_create_fd(Display *dpy, 337428d7b3dSmrg Pixmap pixmap, 338428d7b3dSmrg int *stride) 339428d7b3dSmrg{ 340428d7b3dSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 341428d7b3dSmrg xcb_dri3_buffer_from_pixmap_cookie_t cookie; 342428d7b3dSmrg xcb_dri3_buffer_from_pixmap_reply_t *reply; 343428d7b3dSmrg 344428d7b3dSmrg cookie = xcb_dri3_buffer_from_pixmap(c, pixmap); 345428d7b3dSmrg reply = xcb_dri3_buffer_from_pixmap_reply(c, cookie, NULL); 346428d7b3dSmrg if (!reply) 347428d7b3dSmrg return -1; 348428d7b3dSmrg 349428d7b3dSmrg if (reply->nfd != 1) 350428d7b3dSmrg return -1; 351428d7b3dSmrg 352428d7b3dSmrg *stride = reply->stride; 353428d7b3dSmrg return xcb_dri3_buffer_from_pixmap_reply_fds(c, reply)[0]; 354428d7b3dSmrg} 355428d7b3dSmrg 356428d7b3dSmrgstatic int dri3_query_version(Display *dpy, int *major, int *minor) 357428d7b3dSmrg{ 358428d7b3dSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 359428d7b3dSmrg xcb_dri3_query_version_reply_t *reply; 360428d7b3dSmrg 361428d7b3dSmrg *major = *minor = -1; 362428d7b3dSmrg 363428d7b3dSmrg reply = xcb_dri3_query_version_reply(c, 364428d7b3dSmrg xcb_dri3_query_version(c, 365428d7b3dSmrg XCB_DRI3_MAJOR_VERSION, 366428d7b3dSmrg XCB_DRI3_MINOR_VERSION), 367428d7b3dSmrg NULL); 368428d7b3dSmrg if (reply == NULL) 369428d7b3dSmrg return -1; 370428d7b3dSmrg 371428d7b3dSmrg *major = reply->major_version; 372428d7b3dSmrg *minor = reply->minor_version; 373428d7b3dSmrg free(reply); 374428d7b3dSmrg 375428d7b3dSmrg return 0; 376428d7b3dSmrg} 377428d7b3dSmrg 378428d7b3dSmrgstatic int dri3_exists(Display *dpy) 379428d7b3dSmrg{ 380428d7b3dSmrg int major, minor; 381428d7b3dSmrg 382428d7b3dSmrg if (dri3_query_version(dpy, &major, &minor) < 0) 383428d7b3dSmrg return 0; 384428d7b3dSmrg 385428d7b3dSmrg return major >= 0; 386428d7b3dSmrg} 387428d7b3dSmrg 388428d7b3dSmrgstatic void dri3_create_fence(Display *dpy, Drawable d, struct dri3_fence *fence) 389428d7b3dSmrg{ 390428d7b3dSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 391428d7b3dSmrg struct dri3_fence f; 392428d7b3dSmrg int fd; 393428d7b3dSmrg 394428d7b3dSmrg fd = xshmfence_alloc_shm(); 395428d7b3dSmrg if (fd < 0) 396428d7b3dSmrg return; 397428d7b3dSmrg 398428d7b3dSmrg f.addr = xshmfence_map_shm(fd); 399428d7b3dSmrg if (f.addr == NULL) { 400428d7b3dSmrg close(fd); 401428d7b3dSmrg return; 402428d7b3dSmrg } 403428d7b3dSmrg 404428d7b3dSmrg f.xid = xcb_generate_id(c); 405428d7b3dSmrg xcb_dri3_fence_from_fd(c, d, f.xid, 0, fd); 406428d7b3dSmrg 407428d7b3dSmrg *fence = f; 408428d7b3dSmrg} 409428d7b3dSmrg 410428d7b3dSmrgstatic void dri3_fence_flush(Display *dpy, struct dri3_fence *fence) 411428d7b3dSmrg{ 412428d7b3dSmrg xcb_sync_trigger_fence(XGetXCBConnection(dpy), fence->xid); 413428d7b3dSmrg} 414428d7b3dSmrg 415428d7b3dSmrgstatic void dri3_fence_free(Display *dpy, struct dri3_fence *fence) 416428d7b3dSmrg{ 417428d7b3dSmrg xshmfence_unmap_shm(fence->addr); 418428d7b3dSmrg xcb_sync_destroy_fence(XGetXCBConnection(dpy), fence->xid); 419428d7b3dSmrg} 420428d7b3dSmrg 421428d7b3dSmrg#else 422428d7b3dSmrg 423428d7b3dSmrgstatic int dri3_exists(Display *dpy) 424428d7b3dSmrg{ 425428d7b3dSmrg return 0; 426428d7b3dSmrg} 427428d7b3dSmrg 428428d7b3dSmrgstatic void dri3_create_fence(Display *dpy, Drawable d, struct dri3_fence *fence) 429428d7b3dSmrg{ 430428d7b3dSmrg} 431428d7b3dSmrg 432428d7b3dSmrgstatic void dri3_fence_flush(Display *dpy, struct dri3_fence *fence) 433428d7b3dSmrg{ 434428d7b3dSmrg} 435428d7b3dSmrg 436428d7b3dSmrgstatic void dri3_fence_free(Display *dpy, struct dri3_fence *fence) 437428d7b3dSmrg{ 438428d7b3dSmrg} 439428d7b3dSmrg 440428d7b3dSmrgstatic Pixmap dri3_create_pixmap(Display *dpy, 441428d7b3dSmrg Drawable draw, 442428d7b3dSmrg int width, int height, int depth, 443428d7b3dSmrg int fd, int bpp, int stride, int size) 444428d7b3dSmrg{ 445428d7b3dSmrg return None; 446428d7b3dSmrg} 447428d7b3dSmrg 448428d7b3dSmrgstatic int dri3_create_fd(Display *dpy, 449428d7b3dSmrg Pixmap pixmap, 450428d7b3dSmrg int *stride) 451428d7b3dSmrg{ 452428d7b3dSmrg return -1; 453428d7b3dSmrg} 454428d7b3dSmrg#endif 455428d7b3dSmrg 456428d7b3dSmrgstatic int timerfd(int hz) 457428d7b3dSmrg{ 458428d7b3dSmrg struct itimerspec it; 459428d7b3dSmrg int fd; 460428d7b3dSmrg 461428d7b3dSmrg fd = -1; 462428d7b3dSmrg#ifdef CLOCK_MONOTONIC_COARSE 463428d7b3dSmrg fd = timerfd_create(CLOCK_MONOTONIC_COARSE, TFD_NONBLOCK); 464428d7b3dSmrg#endif 465428d7b3dSmrg if (fd < 0) 466428d7b3dSmrg fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); 467428d7b3dSmrg if (fd < 0) 468428d7b3dSmrg return -ETIME; 469428d7b3dSmrg 470428d7b3dSmrg it.it_interval.tv_sec = 0; 471428d7b3dSmrg it.it_interval.tv_nsec = 1000000000 / hz; 472428d7b3dSmrg it.it_value = it.it_interval; 473428d7b3dSmrg if (timerfd_settime(fd, 0, &it, NULL) < 0) { 474428d7b3dSmrg close(fd); 475428d7b3dSmrg return -ETIME; 476428d7b3dSmrg } 477428d7b3dSmrg 478428d7b3dSmrg return fd; 479428d7b3dSmrg} 480428d7b3dSmrg 481428d7b3dSmrgstatic int context_init(struct context *ctx) 482428d7b3dSmrg{ 483428d7b3dSmrg struct pollfd *pfd; 484428d7b3dSmrg 485428d7b3dSmrg memset(ctx, 0, sizeof(*ctx)); 486428d7b3dSmrg 487428d7b3dSmrg ctx->pfd = malloc(2*sizeof(struct pollfd)); 488428d7b3dSmrg if (ctx->pfd == NULL) 489428d7b3dSmrg return -ENOMEM; 490428d7b3dSmrg 491428d7b3dSmrg ctx->clones = malloc(sizeof(struct clone)); 492428d7b3dSmrg if (ctx->clones == NULL) 493428d7b3dSmrg return -ENOMEM; 494428d7b3dSmrg 495428d7b3dSmrg ctx->display = malloc(sizeof(struct display)); 496428d7b3dSmrg if (ctx->display == NULL) 497428d7b3dSmrg return -ENOMEM; 498428d7b3dSmrg 499428d7b3dSmrg pfd = memset(&ctx->pfd[ctx->nfd++], 0, sizeof(struct pollfd)); 500428d7b3dSmrg pfd->fd = timerfd(60); 501428d7b3dSmrg if (pfd->fd < 0) 502428d7b3dSmrg return pfd->fd; 503428d7b3dSmrg pfd->events = POLLIN; 504428d7b3dSmrg 505428d7b3dSmrg return 0; 506428d7b3dSmrg} 507428d7b3dSmrg 508428d7b3dSmrgstatic void context_enable_timer(struct context *ctx) 509428d7b3dSmrg{ 510428d7b3dSmrg uint64_t count; 511428d7b3dSmrg 512428d7b3dSmrg DBG(TIMER, ("%s timer active? %d\n", __func__, ctx->timer_active)); 513428d7b3dSmrg 514428d7b3dSmrg if (ctx->timer_active) 515428d7b3dSmrg return; 516428d7b3dSmrg 517428d7b3dSmrg /* reset timer */ 518428d7b3dSmrg count = read(ctx->timer, &count, sizeof(count)); 519428d7b3dSmrg 520428d7b3dSmrg ctx->timer_active = 1; 521428d7b3dSmrg} 522428d7b3dSmrg 523428d7b3dSmrgstatic int add_fd(struct context *ctx, int fd) 524428d7b3dSmrg{ 525428d7b3dSmrg struct pollfd *pfd; 526428d7b3dSmrg 527428d7b3dSmrg if (fd < 0) 528428d7b3dSmrg return fd; 529428d7b3dSmrg 530428d7b3dSmrg if (is_power_of_2(ctx->nfd)) { 531428d7b3dSmrg ctx->pfd = realloc(ctx->pfd, 2*ctx->nfd*sizeof(struct pollfd)); 532428d7b3dSmrg if (ctx->pfd == NULL) 533428d7b3dSmrg return -ENOMEM; 534428d7b3dSmrg } 535428d7b3dSmrg 536428d7b3dSmrg pfd = memset(&ctx->pfd[ctx->nfd++], 0, sizeof(struct pollfd)); 537428d7b3dSmrg pfd->fd = fd; 538428d7b3dSmrg pfd->events = POLLIN; 539428d7b3dSmrg return 0; 540428d7b3dSmrg} 541428d7b3dSmrg 542428d7b3dSmrgstatic void display_mark_flush(struct display *display) 543428d7b3dSmrg{ 544428d7b3dSmrg DBG(DRAW, ("%s mark flush (flush=%d)\n", 545428d7b3dSmrg DisplayString(display->dpy), display->flush)); 546428d7b3dSmrg 547428d7b3dSmrg if (display->flush) 548428d7b3dSmrg return; 549428d7b3dSmrg 550428d7b3dSmrg context_enable_timer(display->ctx); 551428d7b3dSmrg display->flush = 1; 552428d7b3dSmrg} 553428d7b3dSmrg 554428d7b3dSmrgstatic int mode_equal(const XRRModeInfo *a, const XRRModeInfo *b) 555428d7b3dSmrg{ 556428d7b3dSmrg return (a->width == b->width && 557428d7b3dSmrg a->height == b->height && 558428d7b3dSmrg a->dotClock == b->dotClock && 559428d7b3dSmrg a->hSyncStart == b->hSyncStart && 560428d7b3dSmrg a->hSyncEnd == b->hSyncEnd && 561428d7b3dSmrg a->hTotal == b->hTotal && 562428d7b3dSmrg a->hSkew == b->hSkew && 563428d7b3dSmrg a->vSyncStart == b->vSyncStart && 564428d7b3dSmrg a->vSyncEnd == b->vSyncEnd && 565428d7b3dSmrg a->vTotal == b->vTotal && 566428d7b3dSmrg a->modeFlags == b->modeFlags); 567428d7b3dSmrg} 568428d7b3dSmrg 569428d7b3dSmrgstatic XRRModeInfo *lookup_mode(XRRScreenResources *res, int id) 570428d7b3dSmrg{ 571428d7b3dSmrg int i; 572428d7b3dSmrg 573428d7b3dSmrg for (i = 0; i < res->nmode; i++) { 574428d7b3dSmrg if (res->modes[i].id == id) 575428d7b3dSmrg return &res->modes[i]; 576428d7b3dSmrg } 577428d7b3dSmrg 578428d7b3dSmrg return NULL; 579428d7b3dSmrg} 580428d7b3dSmrg 581428d7b3dSmrgstatic void clone_update_edid(struct clone *clone) 582428d7b3dSmrg{ 583428d7b3dSmrg unsigned long nitems, after; 584428d7b3dSmrg unsigned char *data; 585428d7b3dSmrg int format; 586428d7b3dSmrg Atom type; 587428d7b3dSmrg 588428d7b3dSmrg if (XRRGetOutputProperty(clone->dst.dpy, clone->dst.rr_output, 589428d7b3dSmrg XInternAtom(clone->dst.dpy, "EDID", False), 590428d7b3dSmrg 0, 100, False, False, AnyPropertyType, 591428d7b3dSmrg &type, &format, &nitems, &after, &data) == Success) { 592428d7b3dSmrg XRRChangeOutputProperty(clone->src.dpy, clone->src.rr_output, 593428d7b3dSmrg XInternAtom(clone->src.dpy, "EDID", False), 594428d7b3dSmrg type, format, PropModeReplace, data, nitems); 595428d7b3dSmrg } 596428d7b3dSmrg} 597428d7b3dSmrg 598428d7b3dSmrgstatic int disable_crtc(Display *dpy, XRRScreenResources *res, RRCrtc crtc) 599428d7b3dSmrg{ 600428d7b3dSmrg XRRPanning panning; 601428d7b3dSmrg 602428d7b3dSmrg if (crtc) { 603428d7b3dSmrg XRRSetPanning(dpy, res, crtc, memset(&panning, 0, sizeof(panning))); 604428d7b3dSmrg 605428d7b3dSmrg if (XRRSetCrtcConfig(dpy, res, crtc, CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0) != Success) 606428d7b3dSmrg return 0; 607428d7b3dSmrg 608428d7b3dSmrg if (XRRSetPanning(dpy, res, crtc, memset(&panning, 0, sizeof(panning))) != Success) { 609428d7b3dSmrg DBG(XRR, ("%s failed to clear panning on CRTC:%ld\n", DisplayString(dpy), (long)crtc)); 610428d7b3dSmrg if (verbose) { 611428d7b3dSmrg XRRCrtcInfo *c; 612428d7b3dSmrg XRRPanning *p; 613428d7b3dSmrg 614428d7b3dSmrg c = XRRGetCrtcInfo(dpy, res, crtc); 615428d7b3dSmrg if (c) { 616428d7b3dSmrg DBG(XRR, ("%s CRTC:%ld x=%d, y=%d, rotation=%d, mode=%ld\n", 617428d7b3dSmrg DisplayString(dpy), (long)crtc, 618428d7b3dSmrg c->x, c->y, c->rotation, c->mode)); 619428d7b3dSmrg XRRFreeCrtcInfo(c); 620428d7b3dSmrg } 621428d7b3dSmrg 622428d7b3dSmrg p = XRRGetPanning(dpy, res, crtc); 623428d7b3dSmrg if (p) { 624428d7b3dSmrg DBG(XRR, ("%s CRTC:%ld panning (%d, %d)x(%d, %d), tracking (%d, %d)x(%d, %d), border (%d, %d),(%d, %d)\n", 625428d7b3dSmrg DisplayString(dpy), (long)crtc, 626428d7b3dSmrg p->left, p->top, p->width, p->height, 627428d7b3dSmrg p->track_left, p->track_top, p->track_width, p->track_height, 628428d7b3dSmrg p->border_left, p->border_top, p->border_right, p->border_bottom)); 629428d7b3dSmrg XRRFreePanning(p); 630428d7b3dSmrg } 631428d7b3dSmrg } 632428d7b3dSmrg } 633428d7b3dSmrg } 634428d7b3dSmrg 635428d7b3dSmrg return 1; 636428d7b3dSmrg} 637428d7b3dSmrg 638428d7b3dSmrgstatic int clone_update_modes__randr(struct clone *clone) 639428d7b3dSmrg{ 640428d7b3dSmrg XRRScreenResources *from_res = NULL, *to_res = NULL; 641428d7b3dSmrg XRROutputInfo *from_info = NULL, *to_info = NULL; 642428d7b3dSmrg int i, j, ret = ENOENT; 643428d7b3dSmrg 644428d7b3dSmrg assert(clone->src.rr_output); 645428d7b3dSmrg assert(clone->dst.rr_output); 646428d7b3dSmrg assert(clone->dst.display->rr_event); 647428d7b3dSmrg 648428d7b3dSmrg from_res = _XRRGetScreenResourcesCurrent(clone->dst.dpy, clone->dst.window); 649428d7b3dSmrg if (from_res == NULL) 650428d7b3dSmrg goto err; 651428d7b3dSmrg 652428d7b3dSmrg from_info = XRRGetOutputInfo(clone->dst.dpy, from_res, clone->dst.rr_output); 653428d7b3dSmrg if (from_info == NULL) 654428d7b3dSmrg goto err; 655428d7b3dSmrg 656428d7b3dSmrg DBG(XRR, ("%s(%s-%s <- %s-%s): timestamp %ld (last %ld)\n", __func__, 657428d7b3dSmrg DisplayString(clone->src.dpy), clone->src.name, 658428d7b3dSmrg DisplayString(clone->dst.dpy), clone->dst.name, 659428d7b3dSmrg from_info->timestamp, clone->timestamp)); 660428d7b3dSmrg 661428d7b3dSmrg to_res = _XRRGetScreenResourcesCurrent(clone->src.dpy, clone->src.window); 662428d7b3dSmrg if (to_res == NULL) 663428d7b3dSmrg goto err; 664428d7b3dSmrg 665428d7b3dSmrg to_info = XRRGetOutputInfo(clone->src.dpy, to_res, clone->src.rr_output); 666428d7b3dSmrg if (to_info == NULL) 667428d7b3dSmrg goto err; 668428d7b3dSmrg 669428d7b3dSmrg DBG(XRR, ("%s: dst.rr_crtc=%ld, now %ld\n", 670428d7b3dSmrg __func__, (long)clone->dst.rr_crtc, (long)from_info->crtc)); 671428d7b3dSmrg if (clone->dst.rr_crtc == from_info->crtc) { 672428d7b3dSmrg for (i = 0; i < to_info->nmode; i++) { 673428d7b3dSmrg XRRModeInfo *mode, *old; 674428d7b3dSmrg 675428d7b3dSmrg mode = lookup_mode(to_res, to_info->modes[i]); 676428d7b3dSmrg if (mode == NULL) 677428d7b3dSmrg break; 678428d7b3dSmrg 679428d7b3dSmrg DBG(XRR, ("%s(%s-%s): lookup mode %s\n", __func__, 680428d7b3dSmrg DisplayString(clone->src.dpy), clone->src.name, 681428d7b3dSmrg mode->name)); 682428d7b3dSmrg 683428d7b3dSmrg for (j = 0; j < from_info->nmode; j++) { 684428d7b3dSmrg old = lookup_mode(from_res, from_info->modes[j]); 685428d7b3dSmrg if (old && mode_equal(mode, old)) { 686428d7b3dSmrg mode = NULL; 687428d7b3dSmrg break; 688428d7b3dSmrg } 689428d7b3dSmrg } 690428d7b3dSmrg if (mode) { 691428d7b3dSmrg DBG(XRR, ("%s(%s-%s): unknown mode %s\n", __func__, 692428d7b3dSmrg DisplayString(clone->src.dpy), clone->src.name, 693428d7b3dSmrg mode->name)); 694428d7b3dSmrg break; 695428d7b3dSmrg } 696428d7b3dSmrg } 697428d7b3dSmrg if (i == from_info->nmode && i == to_info->nmode) { 698428d7b3dSmrg DBG(XRR, ("%s(%s-%s): no change in output\n", __func__, 699428d7b3dSmrg DisplayString(clone->src.dpy), clone->src.name)); 700428d7b3dSmrg goto done; 701428d7b3dSmrg } 702428d7b3dSmrg } 703428d7b3dSmrg 704428d7b3dSmrg /* Disable the remote output */ 705428d7b3dSmrg if (from_info->crtc != clone->dst.rr_crtc) { 706428d7b3dSmrg DBG(XRR, ("%s(%s-%s): disabling active CRTC\n", __func__, 707428d7b3dSmrg DisplayString(clone->dst.dpy), clone->dst.name)); 708428d7b3dSmrg if (disable_crtc(clone->dst.dpy, from_res, from_info->crtc)) { 709428d7b3dSmrg clone->dst.rr_crtc = 0; 710428d7b3dSmrg clone->dst.mode.id = 0; 711428d7b3dSmrg } else { 712428d7b3dSmrg XRRCrtcInfo *c = XRRGetCrtcInfo(clone->dst.dpy, from_res, from_info->crtc); 713428d7b3dSmrg if (c) { 714428d7b3dSmrg clone->dst.x = c->x; 715428d7b3dSmrg clone->dst.y = c->y; 716428d7b3dSmrg clone->dst.rotation = c->rotation; 717428d7b3dSmrg clone->dst.mode.id = c->mode; 718428d7b3dSmrg XRRFreeCrtcInfo(c); 719428d7b3dSmrg } 720428d7b3dSmrg } 721428d7b3dSmrg } 722428d7b3dSmrg 723428d7b3dSmrg /* Create matching modes for the real output on the virtual */ 724428d7b3dSmrg XGrabServer(clone->src.dpy); 725428d7b3dSmrg 726428d7b3dSmrg /* Clear all current UserModes on the output, including any active ones */ 727428d7b3dSmrg if (to_info->crtc) { 728428d7b3dSmrg DBG(XRR, ("%s(%s-%s): disabling active CRTC\n", __func__, 729428d7b3dSmrg DisplayString(clone->src.dpy), clone->src.name)); 730428d7b3dSmrg disable_crtc(clone->src.dpy, to_res, to_info->crtc); 731428d7b3dSmrg } 732428d7b3dSmrg for (i = 0; i < to_info->nmode; i++) { 733428d7b3dSmrg DBG(XRR, ("%s(%s-%s): deleting mode %ld\n", __func__, 734428d7b3dSmrg DisplayString(clone->src.dpy), clone->src.name, (long)to_info->modes[i])); 735428d7b3dSmrg XRRDeleteOutputMode(clone->src.dpy, clone->src.rr_output, to_info->modes[i]); 736428d7b3dSmrg } 737428d7b3dSmrg 738428d7b3dSmrg clone->src.rr_crtc = 0; 739428d7b3dSmrg 740428d7b3dSmrg for (i = 0; i < from_info->nmode; i++) { 741428d7b3dSmrg XRRModeInfo *mode, *old; 742428d7b3dSmrg RRMode id; 743428d7b3dSmrg 744428d7b3dSmrg mode = lookup_mode(from_res, from_info->modes[i]); 745428d7b3dSmrg if (mode == NULL) 746428d7b3dSmrg continue; 747428d7b3dSmrg for (j = 0; j < i; j++) { 748428d7b3dSmrg old = lookup_mode(from_res, from_info->modes[j]); 749428d7b3dSmrg if (old && mode_equal(mode, old)) { 750428d7b3dSmrg mode = NULL; 751428d7b3dSmrg break; 752428d7b3dSmrg } 753428d7b3dSmrg } 754428d7b3dSmrg if (mode == NULL) 755428d7b3dSmrg continue; 756428d7b3dSmrg 757428d7b3dSmrg id = 0; 758428d7b3dSmrg for (j = 0; j < to_res->nmode; j++) { 759428d7b3dSmrg old = &to_res->modes[j]; 760428d7b3dSmrg if (mode_equal(mode, old)) { 761428d7b3dSmrg id = old->id; 762428d7b3dSmrg DBG(XRR, ("%s(%s-%s): reusing mode %ld: %s\n", __func__, 763428d7b3dSmrg DisplayString(clone->src.dpy), clone->src.name, id, mode->name)); 764428d7b3dSmrg break; 765428d7b3dSmrg } 766428d7b3dSmrg } 767428d7b3dSmrg if (id == 0) { 768428d7b3dSmrg XRRModeInfo m; 769428d7b3dSmrg char buf[256]; 770428d7b3dSmrg 771428d7b3dSmrg /* XXX User names must be unique! */ 772428d7b3dSmrg m = *mode; 773428d7b3dSmrg m.nameLength = snprintf(buf, sizeof(buf), 774428d7b3dSmrg "%s.%ld-%s", clone->src.name, (long)from_info->modes[i], mode->name); 775428d7b3dSmrg m.name = buf; 776428d7b3dSmrg 777428d7b3dSmrg id = XRRCreateMode(clone->src.dpy, clone->src.window, &m); 778428d7b3dSmrg DBG(XRR, ("%s(%s-%s): adding mode %ld: %s\n", __func__, 779428d7b3dSmrg DisplayString(clone->src.dpy), clone->src.name, id, mode->name)); 780428d7b3dSmrg } 781428d7b3dSmrg 782428d7b3dSmrg XRRAddOutputMode(clone->src.dpy, clone->src.rr_output, id); 783428d7b3dSmrg } 784428d7b3dSmrg clone_update_edid(clone); 785428d7b3dSmrg XUngrabServer(clone->src.dpy); 786428d7b3dSmrgdone: 787428d7b3dSmrg ret = 0; 788428d7b3dSmrg clone->timestamp = from_info->timestamp; 789428d7b3dSmrg 790428d7b3dSmrgerr: 791428d7b3dSmrg if (to_info) 792428d7b3dSmrg XRRFreeOutputInfo(to_info); 793428d7b3dSmrg if (to_res) 794428d7b3dSmrg XRRFreeScreenResources(to_res); 795428d7b3dSmrg if (from_info) 796428d7b3dSmrg XRRFreeOutputInfo(from_info); 797428d7b3dSmrg if (from_res) 798428d7b3dSmrg XRRFreeScreenResources(from_res); 799428d7b3dSmrg 800428d7b3dSmrg return ret; 801428d7b3dSmrg} 802428d7b3dSmrg 803428d7b3dSmrgstatic int clone_update_modes__fixed(struct clone *clone) 804428d7b3dSmrg{ 805428d7b3dSmrg char mode_name[80]; 806428d7b3dSmrg XRRScreenResources *res = NULL; 807428d7b3dSmrg XRROutputInfo *info = NULL; 808428d7b3dSmrg XRRModeInfo mode; 809428d7b3dSmrg RRMode id; 810428d7b3dSmrg int i, j, ret = ENOENT; 811428d7b3dSmrg 812428d7b3dSmrg assert(clone->src.rr_output); 813428d7b3dSmrg 814428d7b3dSmrg res = _XRRGetScreenResourcesCurrent(clone->src.dpy, clone->src.window); 815428d7b3dSmrg if (res == NULL) 816428d7b3dSmrg goto err; 817428d7b3dSmrg 818428d7b3dSmrg info = XRRGetOutputInfo(clone->src.dpy, res, clone->src.rr_output); 819428d7b3dSmrg if (info == NULL) 820428d7b3dSmrg goto err; 821428d7b3dSmrg 822428d7b3dSmrg XGrabServer(clone->src.dpy); 823428d7b3dSmrg 824428d7b3dSmrg /* Clear all current UserModes on the output, including any active ones */ 825428d7b3dSmrg if (info->crtc) { 826428d7b3dSmrg DBG(XRR, ("%s(%s-%s): disabling active CRTC\n", __func__, 827428d7b3dSmrg DisplayString(clone->src.dpy), clone->src.name)); 828428d7b3dSmrg disable_crtc(clone->src.dpy, res, info->crtc); 829428d7b3dSmrg } 830428d7b3dSmrg for (i = 0; i < info->nmode; i++) { 831428d7b3dSmrg DBG(XRR, ("%s(%s-%s): deleting mode %ld\n", __func__, 832428d7b3dSmrg DisplayString(clone->src.dpy), clone->src.name, (long)info->modes[i])); 833428d7b3dSmrg XRRDeleteOutputMode(clone->src.dpy, clone->src.rr_output, info->modes[i]); 834428d7b3dSmrg } 835428d7b3dSmrg 836428d7b3dSmrg clone->src.rr_crtc = 0; 837428d7b3dSmrg 838428d7b3dSmrg /* Create matching mode for the real output on the virtual */ 839428d7b3dSmrg memset(&mode, 0, sizeof(mode)); 840428d7b3dSmrg mode.width = clone->width; 841428d7b3dSmrg mode.height = clone->height; 842428d7b3dSmrg mode.nameLength = sprintf(mode_name, "FAKE-%dx%d", mode.width, mode.height); 843428d7b3dSmrg mode.name = mode_name; 844428d7b3dSmrg 845428d7b3dSmrg id = 0; 846428d7b3dSmrg for (j = 0; j < res->nmode; j++) { 847428d7b3dSmrg if (mode_equal(&mode, &res->modes[j])) { 848428d7b3dSmrg id = res->modes[j].id; 849428d7b3dSmrg break; 850428d7b3dSmrg } 851428d7b3dSmrg } 852428d7b3dSmrg if (id == 0) 853428d7b3dSmrg id = XRRCreateMode(clone->src.dpy, clone->src.window, &mode); 854428d7b3dSmrg 855428d7b3dSmrg XRRAddOutputMode(clone->src.dpy, clone->src.rr_output, id); 856428d7b3dSmrg 857428d7b3dSmrg XUngrabServer(clone->src.dpy); 858428d7b3dSmrg ret = 0; 859428d7b3dSmrgerr: 860428d7b3dSmrg if (info) 861428d7b3dSmrg XRRFreeOutputInfo(info); 862428d7b3dSmrg if (res) 863428d7b3dSmrg XRRFreeScreenResources(res); 864428d7b3dSmrg 865428d7b3dSmrg return ret; 866428d7b3dSmrg} 867428d7b3dSmrg 868428d7b3dSmrgstatic RROutput claim_virtual(struct display *display, char *output_name, int nclone) 869428d7b3dSmrg{ 870428d7b3dSmrg char mode_name[] = "ClaimVirtualHead"; 871428d7b3dSmrg Display *dpy = display->dpy; 872428d7b3dSmrg XRRScreenResources *res; 873428d7b3dSmrg XRROutputInfo *output; 874428d7b3dSmrg XRRModeInfo mode; 875428d7b3dSmrg RRMode id; 876428d7b3dSmrg RROutput rr_output = 0; 877428d7b3dSmrg int i; 878428d7b3dSmrg 879428d7b3dSmrg DBG(X11, ("%s(%d)\n", __func__, nclone)); 880428d7b3dSmrg XGrabServer(dpy); 881428d7b3dSmrg 882428d7b3dSmrg res = _XRRGetScreenResourcesCurrent(dpy, display->root); 883428d7b3dSmrg if (res == NULL) 884428d7b3dSmrg goto out; 885428d7b3dSmrg 886428d7b3dSmrg sprintf(output_name, "VIRTUAL%d", nclone); 887428d7b3dSmrg 888428d7b3dSmrg for (i = rr_output = 0; rr_output == 0 && i < res->noutput; i++) { 889428d7b3dSmrg output = XRRGetOutputInfo(dpy, res, res->outputs[i]); 890428d7b3dSmrg if (output == NULL) 891428d7b3dSmrg continue; 892428d7b3dSmrg 893428d7b3dSmrg if (strcmp(output->name, output_name) == 0) 894428d7b3dSmrg rr_output = res->outputs[i]; 895428d7b3dSmrg 896428d7b3dSmrg XRRFreeOutputInfo(output); 897428d7b3dSmrg } 898428d7b3dSmrg for (i = id = 0; id == 0 && i < res->nmode; i++) { 899428d7b3dSmrg if (strcmp(res->modes[i].name, mode_name) == 0) 900428d7b3dSmrg id = res->modes[i].id; 901428d7b3dSmrg } 902428d7b3dSmrg XRRFreeScreenResources(res); 903428d7b3dSmrg 904428d7b3dSmrg DBG(XRR, ("%s(%s): rr_output=%ld\n", __func__, output_name, (long)rr_output)); 905428d7b3dSmrg if (rr_output == 0) 906428d7b3dSmrg goto out; 907428d7b3dSmrg 908428d7b3dSmrg /* Set any mode on the VirtualHead to make the Xserver allocate another */ 909428d7b3dSmrg memset(&mode, 0, sizeof(mode)); 910428d7b3dSmrg mode.width = 1024; 911428d7b3dSmrg mode.height = 768; 912428d7b3dSmrg mode.name = mode_name; 913428d7b3dSmrg mode.nameLength = sizeof(mode_name) - 1; 914428d7b3dSmrg 915428d7b3dSmrg if (id == 0) 916428d7b3dSmrg id = XRRCreateMode(dpy, display->root, &mode); 917428d7b3dSmrg XRRAddOutputMode(dpy, rr_output, id); 918428d7b3dSmrg 919428d7b3dSmrg /* Force a redetection for the ddx to spot the new outputs */ 920428d7b3dSmrg res = XRRGetScreenResources(dpy, display->root); 921428d7b3dSmrg if (res == NULL) 922428d7b3dSmrg goto out; 923428d7b3dSmrg 924428d7b3dSmrg /* Some else may have interrupted us and installed that new mode! */ 925428d7b3dSmrg output = XRRGetOutputInfo(dpy, res, rr_output); 926428d7b3dSmrg if (output) { 927428d7b3dSmrg disable_crtc(dpy, res, output->crtc); 928428d7b3dSmrg XRRFreeOutputInfo(output); 929428d7b3dSmrg } 930428d7b3dSmrg XRRFreeScreenResources(res); 931428d7b3dSmrg 932428d7b3dSmrg XRRDeleteOutputMode(dpy, rr_output, id); 933428d7b3dSmrg XRRDestroyMode(dpy, id); 934428d7b3dSmrg 935428d7b3dSmrg /* And hide it again */ 936428d7b3dSmrg res = XRRGetScreenResources(dpy, display->root); 937428d7b3dSmrg if (res != NULL) 938428d7b3dSmrg XRRFreeScreenResources(res); 939428d7b3dSmrgout: 940428d7b3dSmrg XUngrabServer(dpy); 941428d7b3dSmrg 942428d7b3dSmrg return rr_output; 943428d7b3dSmrg} 944428d7b3dSmrg 945428d7b3dSmrgstatic int stride_for_depth(int width, int depth) 946428d7b3dSmrg{ 947428d7b3dSmrg if (depth == 24) 948428d7b3dSmrg depth = 32; 949428d7b3dSmrg return ((width * depth + 7) / 8 + 3) & ~3; 950428d7b3dSmrg} 951428d7b3dSmrg 952428d7b3dSmrgstatic void init_image(struct clone *clone) 953428d7b3dSmrg{ 954428d7b3dSmrg XImage *image = &clone->image; 955428d7b3dSmrg int ret; 956428d7b3dSmrg 957428d7b3dSmrg image->width = clone->width; 958428d7b3dSmrg image->height = clone->height; 959428d7b3dSmrg image->format = ZPixmap; 960428d7b3dSmrg image->xoffset = 0; 961428d7b3dSmrg image->byte_order = LSBFirst; 962428d7b3dSmrg image->bitmap_unit = 32; 963428d7b3dSmrg image->bitmap_bit_order = LSBFirst; 964428d7b3dSmrg image->bitmap_pad = 32; 965428d7b3dSmrg image->data = clone->shm.shmaddr; 966428d7b3dSmrg image->bytes_per_line = stride_for_depth(clone->width, clone->depth); 967428d7b3dSmrg switch (clone->depth) { 968428d7b3dSmrg case 24: 969428d7b3dSmrg image->red_mask = 0xff << 16; 970428d7b3dSmrg image->green_mask = 0xff << 8; 971428d7b3dSmrg image->blue_mask = 0xff << 0;; 972428d7b3dSmrg image->depth = 24; 973428d7b3dSmrg image->bits_per_pixel = 32; 974428d7b3dSmrg break; 975428d7b3dSmrg case 16: 976428d7b3dSmrg image->red_mask = 0x1f << 11; 977428d7b3dSmrg image->green_mask = 0x3f << 5; 978428d7b3dSmrg image->blue_mask = 0x1f << 0;; 979428d7b3dSmrg image->depth = 16; 980428d7b3dSmrg image->bits_per_pixel = 16; 981428d7b3dSmrg break; 982428d7b3dSmrg } 983428d7b3dSmrg 984428d7b3dSmrg ret = XInitImage(image); 985428d7b3dSmrg assert(ret); 986428d7b3dSmrg (void)ret; 987428d7b3dSmrg} 988428d7b3dSmrg 989428d7b3dSmrgstatic int mode_height(const XRRModeInfo *mode, Rotation rotation) 990428d7b3dSmrg{ 991428d7b3dSmrg switch (rotation & 0xf) { 992428d7b3dSmrg case RR_Rotate_0: 993428d7b3dSmrg case RR_Rotate_180: 994428d7b3dSmrg return mode->height; 995428d7b3dSmrg case RR_Rotate_90: 996428d7b3dSmrg case RR_Rotate_270: 997428d7b3dSmrg return mode->width; 998428d7b3dSmrg default: 999428d7b3dSmrg return 0; 1000428d7b3dSmrg } 1001428d7b3dSmrg} 1002428d7b3dSmrg 1003428d7b3dSmrgstatic int mode_width(const XRRModeInfo *mode, Rotation rotation) 1004428d7b3dSmrg{ 1005428d7b3dSmrg switch (rotation & 0xf) { 1006428d7b3dSmrg case RR_Rotate_0: 1007428d7b3dSmrg case RR_Rotate_180: 1008428d7b3dSmrg return mode->width; 1009428d7b3dSmrg case RR_Rotate_90: 1010428d7b3dSmrg case RR_Rotate_270: 1011428d7b3dSmrg return mode->height; 1012428d7b3dSmrg default: 1013428d7b3dSmrg return 0; 1014428d7b3dSmrg } 1015428d7b3dSmrg} 1016428d7b3dSmrg 1017428d7b3dSmrgstatic void output_init_xfer(struct clone *clone, struct output *output) 1018428d7b3dSmrg{ 1019428d7b3dSmrg if (output->pixmap == None && output->use_shm_pixmap) { 1020428d7b3dSmrg DBG(DRAW, ("%s-%s: creating shm pixmap\n", DisplayString(output->dpy), output->name)); 1021428d7b3dSmrg XSync(output->dpy, False); 1022428d7b3dSmrg _x_error_occurred = 0; 1023428d7b3dSmrg 1024428d7b3dSmrg output->pixmap = XShmCreatePixmap(output->dpy, output->window, 1025428d7b3dSmrg clone->shm.shmaddr, &output->shm, 1026428d7b3dSmrg clone->width, clone->height, clone->depth); 1027428d7b3dSmrg if (output->pix_picture) { 1028428d7b3dSmrg XRenderFreePicture(output->dpy, output->pix_picture); 1029428d7b3dSmrg output->pix_picture = None; 1030428d7b3dSmrg } 1031428d7b3dSmrg 1032428d7b3dSmrg XSync(output->dpy, False); 1033428d7b3dSmrg if (_x_error_occurred) { 1034428d7b3dSmrg XFreePixmap(output->dpy, output->pixmap); 1035428d7b3dSmrg output->pixmap = None; 1036428d7b3dSmrg output->use_shm_pixmap = 0; 1037428d7b3dSmrg } 1038428d7b3dSmrg } 1039428d7b3dSmrg if (output->use_render) { 1040428d7b3dSmrg DBG(DRAW, ("%s-%s: creating picture\n", DisplayString(output->dpy), output->name)); 1041428d7b3dSmrg if (output->win_picture == None) 1042428d7b3dSmrg output->win_picture = XRenderCreatePicture(output->dpy, output->window, 1043428d7b3dSmrg output->display->root_format, 0, NULL); 1044428d7b3dSmrg if (output->pixmap == None) 1045428d7b3dSmrg output->pixmap = XCreatePixmap(output->dpy, output->window, 1046428d7b3dSmrg clone->width, clone->height, clone->depth); 1047428d7b3dSmrg if (output->pix_picture == None) 1048428d7b3dSmrg output->pix_picture = XRenderCreatePicture(output->dpy, output->pixmap, 1049428d7b3dSmrg output->use_render, 0, NULL); 1050428d7b3dSmrg } 1051428d7b3dSmrg 1052428d7b3dSmrg if (output->gc == None) { 1053428d7b3dSmrg XGCValues gcv; 1054428d7b3dSmrg 1055428d7b3dSmrg DBG(DRAW, ("%s-%s: creating gc\n", DisplayString(output->dpy), output->name)); 1056428d7b3dSmrg 1057428d7b3dSmrg gcv.graphics_exposures = False; 1058428d7b3dSmrg gcv.subwindow_mode = IncludeInferiors; 1059428d7b3dSmrg 1060428d7b3dSmrg output->gc = XCreateGC(output->dpy, output->pixmap ?: output->window, GCGraphicsExposures | GCSubwindowMode, &gcv); 1061428d7b3dSmrg } 1062428d7b3dSmrg} 1063428d7b3dSmrg 1064428d7b3dSmrgstatic int bpp_for_depth(int depth) 1065428d7b3dSmrg{ 1066428d7b3dSmrg switch (depth) { 1067428d7b3dSmrg case 1: return 1; 1068428d7b3dSmrg case 8: return 8; 1069428d7b3dSmrg case 15: return 16; 1070428d7b3dSmrg case 16: return 16; 1071428d7b3dSmrg case 24: return 24; 1072428d7b3dSmrg case 32: return 32; 1073428d7b3dSmrg default: return 0; 1074428d7b3dSmrg } 1075428d7b3dSmrg} 1076428d7b3dSmrg 1077428d7b3dSmrgstatic int clone_init_xfer(struct clone *clone) 1078428d7b3dSmrg{ 1079428d7b3dSmrg int width, height; 1080428d7b3dSmrg 1081428d7b3dSmrg if (clone->dst.mode.id == 0) { 1082428d7b3dSmrg width = 0; 1083428d7b3dSmrg height = 0; 1084428d7b3dSmrg } else if (clone->dri3.xid) { 1085428d7b3dSmrg width = clone->dst.display->width; 1086428d7b3dSmrg height = clone->dst.display->height; 1087428d7b3dSmrg } else { 1088428d7b3dSmrg width = mode_width(&clone->src.mode, clone->src.rotation); 1089428d7b3dSmrg height = mode_height(&clone->src.mode, clone->src.rotation); 1090428d7b3dSmrg } 1091428d7b3dSmrg 1092428d7b3dSmrg if (width == clone->width && height == clone->height) 1093428d7b3dSmrg return 0; 1094428d7b3dSmrg 1095428d7b3dSmrg DBG(DRAW, ("%s-%s create xfer, %dx%d\n", 1096428d7b3dSmrg DisplayString(clone->dst.dpy), clone->dst.name, 1097428d7b3dSmrg width, height)); 1098428d7b3dSmrg 1099428d7b3dSmrg if (clone->shm.shmaddr) { 1100428d7b3dSmrg if (clone->src.use_shm) 1101428d7b3dSmrg XShmDetach(clone->src.dpy, &clone->src.shm); 1102428d7b3dSmrg if (clone->dst.use_shm) 1103428d7b3dSmrg XShmDetach(clone->dst.dpy, &clone->dst.shm); 1104428d7b3dSmrg 1105428d7b3dSmrg shmdt(clone->shm.shmaddr); 1106428d7b3dSmrg clone->shm.shmaddr = NULL; 1107428d7b3dSmrg } 1108428d7b3dSmrg 1109428d7b3dSmrg if (clone->src.pixmap) { 1110428d7b3dSmrg XFreePixmap(clone->src.dpy, clone->src.pixmap); 1111428d7b3dSmrg clone->src.pixmap = 0; 1112428d7b3dSmrg } 1113428d7b3dSmrg 1114428d7b3dSmrg if (clone->dst.pixmap) { 1115428d7b3dSmrg XFreePixmap(clone->dst.dpy, clone->dst.pixmap); 1116428d7b3dSmrg clone->dst.pixmap = 0; 1117428d7b3dSmrg } 1118428d7b3dSmrg 1119428d7b3dSmrg if ((width | height) == 0) { 1120428d7b3dSmrg clone->damaged.x2 = clone->damaged.y2 = INT_MIN; 1121428d7b3dSmrg clone->damaged.x1 = clone->damaged.y1 = INT_MAX; 1122428d7b3dSmrg return 0; 1123428d7b3dSmrg } 1124428d7b3dSmrg 1125428d7b3dSmrg if (clone->dri3.xid) { 1126428d7b3dSmrg int fd, stride; 1127428d7b3dSmrg Pixmap src; 1128428d7b3dSmrg 1129428d7b3dSmrg _x_error_occurred = 0; 1130428d7b3dSmrg 1131428d7b3dSmrg DBG(DRAW, ("%s-%s create xfer, trying DRI3\n", 1132428d7b3dSmrg DisplayString(clone->dst.dpy), clone->dst.name)); 1133428d7b3dSmrg 1134428d7b3dSmrg fd = dri3_create_fd(clone->dst.dpy, clone->dst.window, &stride); 1135428d7b3dSmrg if (fd < 0) 1136428d7b3dSmrg goto disable_dri3; 1137428d7b3dSmrg 1138428d7b3dSmrg DBG(DRAW, ("%s-%s create xfer, DRI3 fd=%d, stride=%d\n", 1139428d7b3dSmrg DisplayString(clone->dst.dpy), clone->dst.name, 1140428d7b3dSmrg fd, stride)); 1141428d7b3dSmrg 1142428d7b3dSmrg src = dri3_create_pixmap(clone->src.dpy, clone->src.window, 1143428d7b3dSmrg width, height, clone->depth, 1144428d7b3dSmrg fd, bpp_for_depth(clone->depth), 1145428d7b3dSmrg stride, lseek(fd, 0, SEEK_END)); 1146428d7b3dSmrg 1147428d7b3dSmrg XSync(clone->src.dpy, False); 1148428d7b3dSmrg if (!_x_error_occurred) { 1149428d7b3dSmrg clone->src.pixmap = src; 1150428d7b3dSmrg clone->width = width; 1151428d7b3dSmrg clone->height = height; 1152428d7b3dSmrg } else { 1153428d7b3dSmrg XFreePixmap(clone->src.dpy, src); 1154428d7b3dSmrg close(fd); 1155428d7b3dSmrgdisable_dri3: 1156428d7b3dSmrg dri3_fence_free(clone->src.dpy, &clone->dri3); 1157428d7b3dSmrg clone->dri3.xid = 0; 1158428d7b3dSmrg 1159428d7b3dSmrg DBG(DRAW, ("%s-%s create xfer, DRI3 failed\n", 1160428d7b3dSmrg DisplayString(clone->dst.dpy), clone->dst.name)); 1161428d7b3dSmrg } 1162428d7b3dSmrg } 1163428d7b3dSmrg 1164428d7b3dSmrg width = mode_width(&clone->src.mode, clone->src.rotation); 1165428d7b3dSmrg height = mode_height(&clone->src.mode, clone->src.rotation); 1166428d7b3dSmrg 1167428d7b3dSmrg if (!clone->dri3.xid) { 1168428d7b3dSmrg DBG(DRAW, ("%s-%s create xfer, trying SHM\n", 1169428d7b3dSmrg DisplayString(clone->dst.dpy), clone->dst.name)); 1170428d7b3dSmrg 1171428d7b3dSmrg clone->shm.shmid = shmget(IPC_PRIVATE, 1172428d7b3dSmrg height * stride_for_depth(width, clone->depth), 1173428d7b3dSmrg IPC_CREAT | 0666); 1174428d7b3dSmrg if (clone->shm.shmid == -1) 1175428d7b3dSmrg return errno; 1176428d7b3dSmrg 1177428d7b3dSmrg clone->shm.shmaddr = shmat(clone->shm.shmid, 0, 0); 1178428d7b3dSmrg if (clone->shm.shmaddr == (char *) -1) { 1179428d7b3dSmrg shmctl(clone->shm.shmid, IPC_RMID, NULL); 1180428d7b3dSmrg return ENOMEM; 1181428d7b3dSmrg } 1182428d7b3dSmrg 1183428d7b3dSmrg if (clone->src.use_shm) { 1184428d7b3dSmrg clone->src.shm = clone->shm; 1185428d7b3dSmrg clone->src.shm.readOnly = False; 1186428d7b3dSmrg XShmAttach(clone->src.dpy, &clone->src.shm); 1187428d7b3dSmrg XSync(clone->src.dpy, False); 1188428d7b3dSmrg } 1189428d7b3dSmrg if (clone->dst.use_shm) { 1190428d7b3dSmrg clone->dst.shm = clone->shm; 1191428d7b3dSmrg clone->dst.shm.readOnly = !clone->dst.use_shm_pixmap; 1192428d7b3dSmrg XShmAttach(clone->dst.dpy, &clone->dst.shm); 1193428d7b3dSmrg XSync(clone->dst.dpy, False); 1194428d7b3dSmrg } 1195428d7b3dSmrg 1196428d7b3dSmrg shmctl(clone->shm.shmid, IPC_RMID, NULL); 1197428d7b3dSmrg 1198428d7b3dSmrg clone->width = width; 1199428d7b3dSmrg clone->height = height; 1200428d7b3dSmrg 1201428d7b3dSmrg init_image(clone); 1202428d7b3dSmrg } 1203428d7b3dSmrg 1204428d7b3dSmrg output_init_xfer(clone, &clone->src); 1205428d7b3dSmrg output_init_xfer(clone, &clone->dst); 1206428d7b3dSmrg 1207428d7b3dSmrg clone->damaged.x1 = clone->src.x; 1208428d7b3dSmrg clone->damaged.x2 = clone->src.x + width; 1209428d7b3dSmrg clone->damaged.y1 = clone->src.y; 1210428d7b3dSmrg clone->damaged.y2 = clone->src.y + height; 1211428d7b3dSmrg 1212428d7b3dSmrg display_mark_flush(clone->dst.display); 1213428d7b3dSmrg return 0; 1214428d7b3dSmrg} 1215428d7b3dSmrg 1216428d7b3dSmrgstatic void clone_update(struct clone *clone) 1217428d7b3dSmrg{ 1218428d7b3dSmrg if (!clone->rr_update) 1219428d7b3dSmrg return; 1220428d7b3dSmrg 1221428d7b3dSmrg DBG(X11, ("%s-%s cloning modes\n", 1222428d7b3dSmrg DisplayString(clone->dst.dpy), clone->dst.name)); 1223428d7b3dSmrg 1224428d7b3dSmrg clone_update_modes__randr(clone); 1225428d7b3dSmrg clone->rr_update = 0; 1226428d7b3dSmrg} 1227428d7b3dSmrg 1228428d7b3dSmrgstatic int context_update(struct context *ctx) 1229428d7b3dSmrg{ 1230428d7b3dSmrg Display *dpy = ctx->display->dpy; 1231428d7b3dSmrg XRRScreenResources *res; 1232428d7b3dSmrg int context_changed = 0; 1233428d7b3dSmrg int i, n; 1234428d7b3dSmrg 1235428d7b3dSmrg DBG(X11, ("%s\n", __func__)); 1236428d7b3dSmrg 1237428d7b3dSmrg res = _XRRGetScreenResourcesCurrent(dpy, ctx->display->root); 1238428d7b3dSmrg if (res == NULL) 1239428d7b3dSmrg return 0; 1240428d7b3dSmrg 1241428d7b3dSmrg DBG(XRR, ("%s timestamp %ld (last %ld), config %ld (last %ld)\n", 1242428d7b3dSmrg DisplayString(dpy), 1243428d7b3dSmrg res->timestamp, ctx->timestamp, 1244428d7b3dSmrg res->configTimestamp, ctx->configTimestamp)); 1245428d7b3dSmrg if (res->timestamp == ctx->timestamp && 1246428d7b3dSmrg res->configTimestamp == ctx->configTimestamp && 1247428d7b3dSmrg res->timestamp != res->configTimestamp) { /* mutter be damned */ 1248428d7b3dSmrg XRRFreeScreenResources(res); 1249428d7b3dSmrg return 0; 1250428d7b3dSmrg } 1251428d7b3dSmrg 1252428d7b3dSmrg ctx->timestamp = res->timestamp; 1253428d7b3dSmrg ctx->configTimestamp = res->configTimestamp; 1254428d7b3dSmrg 1255428d7b3dSmrg for (n = 0; n < ctx->nclone; n++) { 1256428d7b3dSmrg struct output *output = &ctx->clones[n].src; 1257428d7b3dSmrg XRROutputInfo *o; 1258428d7b3dSmrg XRRCrtcInfo *c; 1259428d7b3dSmrg RRMode mode = 0; 1260428d7b3dSmrg int changed = 0; 1261428d7b3dSmrg 1262428d7b3dSmrg o = XRRGetOutputInfo(dpy, res, output->rr_output); 1263428d7b3dSmrg if (o == NULL) 1264428d7b3dSmrg continue; 1265428d7b3dSmrg 1266428d7b3dSmrg c = NULL; 1267428d7b3dSmrg if (o->crtc) 1268428d7b3dSmrg c = XRRGetCrtcInfo(dpy, res, o->crtc); 1269428d7b3dSmrg if (c) { 1270428d7b3dSmrg DBG(XRR, ("%s-%s: (x=%d, y=%d, rotation=%d, mode=%ld) -> (x=%d, y=%d, rotation=%d, mode=%ld)\n", 1271428d7b3dSmrg DisplayString(dpy), output->name, 1272428d7b3dSmrg output->x, output->y, output->rotation, output->mode.id, 1273428d7b3dSmrg c->x, c->y, c->rotation, c->mode)); 1274428d7b3dSmrg 1275428d7b3dSmrg changed |= output->rotation != c->rotation; 1276428d7b3dSmrg output->rotation = c->rotation; 1277428d7b3dSmrg 1278428d7b3dSmrg changed |= output->x != c->x; 1279428d7b3dSmrg output->x = c->x; 1280428d7b3dSmrg 1281428d7b3dSmrg changed |= output->y != c->y; 1282428d7b3dSmrg output->y = c->y; 1283428d7b3dSmrg 1284428d7b3dSmrg changed |= output->mode.id != c->mode; 1285428d7b3dSmrg mode = c->mode; 1286428d7b3dSmrg XRRFreeCrtcInfo(c); 1287428d7b3dSmrg } else { 1288428d7b3dSmrg DBG(XRR, ("%s-%s: (x=%d, y=%d, rotation=%d, mode=%ld) -> off\n", 1289428d7b3dSmrg DisplayString(dpy), output->name, 1290428d7b3dSmrg output->x, output->y, output->rotation, output->mode.id)); 1291428d7b3dSmrg } 1292428d7b3dSmrg output->rr_crtc = o->crtc; 1293428d7b3dSmrg XRRFreeOutputInfo(o); 1294428d7b3dSmrg 1295428d7b3dSmrg DBG(XRR, ("%s-%s crtc changed? %d\n", 1296428d7b3dSmrg DisplayString(ctx->clones[n].dst.display->dpy), ctx->clones[n].dst.name, changed)); 1297428d7b3dSmrg 1298428d7b3dSmrg if (mode) { 1299428d7b3dSmrg if (output->mode.id != mode) { 1300428d7b3dSmrg for (i = 0; i < res->nmode; i++) { 1301428d7b3dSmrg if (res->modes[i].id == mode) { 1302428d7b3dSmrg output->mode = res->modes[i]; 1303428d7b3dSmrg break; 1304428d7b3dSmrg } 1305428d7b3dSmrg } 1306428d7b3dSmrg } 1307428d7b3dSmrg } else { 1308428d7b3dSmrg changed = output->mode.id != 0; 1309428d7b3dSmrg output->mode.id = 0; 1310428d7b3dSmrg } 1311428d7b3dSmrg 1312428d7b3dSmrg DBG(XRR, ("%s-%s output changed? %d\n", 1313428d7b3dSmrg DisplayString(ctx->clones[n].dst.display->dpy), ctx->clones[n].dst.name, changed)); 1314428d7b3dSmrg 1315428d7b3dSmrg context_changed |= changed; 1316428d7b3dSmrg } 1317428d7b3dSmrg XRRFreeScreenResources(res); 1318428d7b3dSmrg 1319428d7b3dSmrg DBG(XRR, ("%s changed? %d\n", DisplayString(dpy), context_changed)); 1320428d7b3dSmrg if (!context_changed) 1321428d7b3dSmrg return 0; 1322428d7b3dSmrg 1323428d7b3dSmrg for (n = 1; n < ctx->ndisplay; n++) { 1324428d7b3dSmrg struct display *display = &ctx->display[n]; 1325428d7b3dSmrg struct clone *clone; 1326428d7b3dSmrg int x1, x2, y1, y2; 1327428d7b3dSmrg 1328428d7b3dSmrg if (display->rr_active == 0) 1329428d7b3dSmrg continue; 1330428d7b3dSmrg 1331428d7b3dSmrg x1 = y1 = INT_MAX; 1332428d7b3dSmrg x2 = y2 = INT_MIN; 1333428d7b3dSmrg 1334428d7b3dSmrg for (clone = display->clone; clone; clone = clone->next) { 1335428d7b3dSmrg struct output *output = &clone->src; 1336428d7b3dSmrg int v; 1337428d7b3dSmrg 1338428d7b3dSmrg assert(clone->dst.display == display); 1339428d7b3dSmrg 1340428d7b3dSmrg if (output->mode.id == 0) 1341428d7b3dSmrg continue; 1342428d7b3dSmrg 1343428d7b3dSmrg DBG(XRR, ("%s: source %s enabled (%d, %d)x(%d, %d)\n", 1344428d7b3dSmrg DisplayString(clone->dst.dpy), output->name, 1345428d7b3dSmrg output->x, output->y, 1346428d7b3dSmrg mode_width(&output->mode, output->rotation), 1347428d7b3dSmrg mode_height(&output->mode, output->rotation))); 1348428d7b3dSmrg 1349428d7b3dSmrg if (output->x < x1) 1350428d7b3dSmrg x1 = output->x; 1351428d7b3dSmrg if (output->y < y1) 1352428d7b3dSmrg y1 = output->y; 1353428d7b3dSmrg 1354428d7b3dSmrg v = (int)output->x + mode_width(&output->mode, output->rotation); 1355428d7b3dSmrg if (v > x2) 1356428d7b3dSmrg x2 = v; 1357428d7b3dSmrg v = (int)output->y + mode_height(&output->mode, output->rotation); 1358428d7b3dSmrg if (v > y2) 1359428d7b3dSmrg y2 = v; 1360428d7b3dSmrg } 1361428d7b3dSmrg 1362428d7b3dSmrg DBG(XRR, ("%s fb bounds (%d, %d)x(%d, %d)\n", DisplayString(display->dpy), 1363428d7b3dSmrg x1, y1, x2, y2)); 1364428d7b3dSmrg 1365428d7b3dSmrg XGrabServer(display->dpy); 1366428d7b3dSmrg res = _XRRGetScreenResourcesCurrent(display->dpy, display->root); 1367428d7b3dSmrg if (res == NULL) 1368428d7b3dSmrg goto ungrab; 1369428d7b3dSmrg 1370428d7b3dSmrg if (x2 <= x1 || y2 <= y1) { 1371428d7b3dSmrg /* Nothing enabled, preserve the current fb, and turn everything off */ 1372428d7b3dSmrg for (clone = display->clone; clone; clone = clone->next) { 1373428d7b3dSmrg struct output *dst = &clone->dst; 1374428d7b3dSmrg 1375428d7b3dSmrg if (!dst->rr_crtc) 1376428d7b3dSmrg continue; 1377428d7b3dSmrg 1378428d7b3dSmrg DBG(XRR, ("%s: disabling output '%s'\n", 1379428d7b3dSmrg DisplayString(display->dpy), dst->name)); 1380428d7b3dSmrg assert(clone->dst.display == display); 1381428d7b3dSmrg if (disable_crtc(display->dpy, res, dst->rr_crtc)) { 1382428d7b3dSmrg dst->rr_crtc = 0; 1383428d7b3dSmrg dst->mode.id = 0; 1384428d7b3dSmrg } 1385428d7b3dSmrg } 1386428d7b3dSmrg goto free_res; 1387428d7b3dSmrg } 1388428d7b3dSmrg 1389428d7b3dSmrg x2 -= x1; 1390428d7b3dSmrg y2 -= y1; 1391428d7b3dSmrg DBG(XRR, ("%s: current size %dx%d, need %dx%d\n", 1392428d7b3dSmrg DisplayString(display->dpy), 1393428d7b3dSmrg display->width, display->height, 1394428d7b3dSmrg x2, y2)); 1395428d7b3dSmrg 1396428d7b3dSmrg if (display->width != x2 || display->height != y2) { 1397428d7b3dSmrg /* When shrinking we have to manually resize the fb */ 1398428d7b3dSmrg for (clone = display->clone; clone; clone = clone->next) { 1399428d7b3dSmrg struct output *dst = &clone->dst; 1400428d7b3dSmrg 1401428d7b3dSmrg if (!dst->rr_crtc) 1402428d7b3dSmrg continue; 1403428d7b3dSmrg 1404428d7b3dSmrg DBG(XRR, ("%s: disabling output '%s'\n", 1405428d7b3dSmrg DisplayString(display->dpy), dst->name)); 1406428d7b3dSmrg assert(clone->dst.display == display); 1407428d7b3dSmrg if (disable_crtc(display->dpy, res, dst->rr_crtc)) { 1408428d7b3dSmrg dst->rr_crtc = 0; 1409428d7b3dSmrg dst->mode.id = 0; 1410428d7b3dSmrg } 1411428d7b3dSmrg } 1412428d7b3dSmrg 1413428d7b3dSmrg DBG(XRR, ("%s: XRRSetScreenSize %dx%d\n", DisplayString(display->dpy), x2, y2)); 1414428d7b3dSmrg XRRSetScreenSize(display->dpy, display->root, x2, y2, x2 * 96 / 25.4, y2 * 96 / 25.4); 1415428d7b3dSmrg display->width = x2; 1416428d7b3dSmrg display->height = y2; 1417428d7b3dSmrg } 1418428d7b3dSmrg 1419428d7b3dSmrg for (clone = display->clone; clone; clone = clone->next) { 1420428d7b3dSmrg struct output *src = &clone->src; 1421428d7b3dSmrg struct output *dst = &clone->dst; 1422428d7b3dSmrg XRROutputInfo *o; 1423428d7b3dSmrg XRRPanning panning; 1424428d7b3dSmrg struct clone *set; 1425428d7b3dSmrg RRCrtc rr_crtc; 1426428d7b3dSmrg Status ret; 1427428d7b3dSmrg 1428428d7b3dSmrg DBG(XRR, ("%s: copying configuration from %s (mode=%ld: %dx%d) to %s\n", 1429428d7b3dSmrg DisplayString(display->dpy), 1430428d7b3dSmrg src->name, (long)src->mode.id, src->mode.width, src->mode.height, 1431428d7b3dSmrg dst->name)); 1432428d7b3dSmrg 1433428d7b3dSmrg if (src->mode.id == 0) { 1434428d7b3dSmrgerr: 1435428d7b3dSmrg if (dst->rr_crtc) { 1436428d7b3dSmrg DBG(XRR, ("%s: disabling unused output '%s'\n", 1437428d7b3dSmrg DisplayString(display->dpy), dst->name)); 1438428d7b3dSmrg assert(clone->dst.display == display); 1439428d7b3dSmrg if (disable_crtc(display->dpy, res, dst->rr_crtc)) { 1440428d7b3dSmrg dst->rr_crtc = 0; 1441428d7b3dSmrg dst->mode.id = 0; 1442428d7b3dSmrg } 1443428d7b3dSmrg } 1444428d7b3dSmrg continue; 1445428d7b3dSmrg } 1446428d7b3dSmrg 1447428d7b3dSmrg dst->x = src->x - x1; 1448428d7b3dSmrg dst->y = src->y - y1; 1449428d7b3dSmrg dst->rotation = src->rotation; 1450428d7b3dSmrg dst->mode = src->mode; 1451428d7b3dSmrg 1452428d7b3dSmrg dst->mode.id = 0; 1453428d7b3dSmrg for (i = 0; i < res->nmode; i++) { 1454428d7b3dSmrg if (mode_equal(&src->mode, &res->modes[i])) { 1455428d7b3dSmrg dst->mode.id = res->modes[i].id; 1456428d7b3dSmrg break; 1457428d7b3dSmrg } 1458428d7b3dSmrg } 1459428d7b3dSmrg if (dst->mode.id == 0) { 1460428d7b3dSmrg XRRModeInfo m; 1461428d7b3dSmrg char buf[256]; 1462428d7b3dSmrg RRMode id; 1463428d7b3dSmrg 1464428d7b3dSmrg /* XXX User names must be unique! */ 1465428d7b3dSmrg m = src->mode; 1466428d7b3dSmrg m.nameLength = snprintf(buf, sizeof(buf), 1467428d7b3dSmrg "%s.%ld-%dx%d", src->name, 1468428d7b3dSmrg (long)src->mode.id, 1469428d7b3dSmrg src->mode.width, 1470428d7b3dSmrg src->mode.height); 1471428d7b3dSmrg m.name = buf; 1472428d7b3dSmrg 1473428d7b3dSmrg id = XRRCreateMode(dst->dpy, dst->window, &m); 1474428d7b3dSmrg if (id) { 1475428d7b3dSmrg DBG(XRR, ("%s: adding mode %ld: %dx%d to %s, new mode %ld\n", 1476428d7b3dSmrg DisplayString(dst->dpy), 1477428d7b3dSmrg (long)src->mode.id, 1478428d7b3dSmrg src->mode.width, 1479428d7b3dSmrg src->mode.height, 1480428d7b3dSmrg dst->name, (long)id)); 1481428d7b3dSmrg XRRAddOutputMode(dst->dpy, dst->rr_output, id); 1482428d7b3dSmrg dst->mode.id = id; 1483428d7b3dSmrg } else { 1484428d7b3dSmrg DBG(XRR, ("%s: failed to find suitable mode for %s\n", 1485428d7b3dSmrg DisplayString(dst->dpy), dst->name)); 1486428d7b3dSmrg goto err; 1487428d7b3dSmrg } 1488428d7b3dSmrg } 1489428d7b3dSmrg 1490428d7b3dSmrg rr_crtc = dst->rr_crtc; 1491428d7b3dSmrg if (rr_crtc) { 1492428d7b3dSmrg for (set = display->clone; set != clone; set = set->next) { 1493428d7b3dSmrg if (set->dst.rr_crtc == rr_crtc) { 1494428d7b3dSmrg DBG(XRR, ("%s: CRTC reassigned from %s\n", 1495428d7b3dSmrg DisplayString(dst->dpy), dst->name)); 1496428d7b3dSmrg rr_crtc = 0; 1497428d7b3dSmrg break; 1498428d7b3dSmrg } 1499428d7b3dSmrg } 1500428d7b3dSmrg } 1501428d7b3dSmrg if (rr_crtc == 0) { 1502428d7b3dSmrg o = XRRGetOutputInfo(dst->dpy, res, dst->rr_output); 1503428d7b3dSmrg for (i = 0; i < o->ncrtc; i++) { 1504428d7b3dSmrg DBG(XRR, ("%s: checking whether CRTC:%ld is available\n", 1505428d7b3dSmrg DisplayString(dst->dpy), (long)o->crtcs[i])); 1506428d7b3dSmrg for (set = display->clone; set != clone; set = set->next) { 1507428d7b3dSmrg if (set->dst.rr_crtc == o->crtcs[i]) { 1508428d7b3dSmrg DBG(XRR, ("%s: CRTC:%ld already assigned to %s\n", 1509428d7b3dSmrg DisplayString(dst->dpy), (long)o->crtcs[i], set->dst.name)); 1510428d7b3dSmrg break; 1511428d7b3dSmrg } 1512428d7b3dSmrg } 1513428d7b3dSmrg if (set == clone) { 1514428d7b3dSmrg rr_crtc = o->crtcs[i]; 1515428d7b3dSmrg break; 1516428d7b3dSmrg } 1517428d7b3dSmrg } 1518428d7b3dSmrg XRRFreeOutputInfo(o); 1519428d7b3dSmrg } 1520428d7b3dSmrg if (rr_crtc == 0) { 1521428d7b3dSmrg DBG(XRR, ("%s: failed to find available CRTC for %s\n", 1522428d7b3dSmrg DisplayString(dst->dpy), dst->name)); 1523428d7b3dSmrg goto err; 1524428d7b3dSmrg } 1525428d7b3dSmrg 1526428d7b3dSmrg DBG(XRR, ("%s: enabling output '%s' (%d,%d)x(%d,%d), rotation %d, on CRTC:%ld, using mode %ld\n", 1527428d7b3dSmrg DisplayString(dst->dpy), dst->name, 1528428d7b3dSmrg dst->x, dst->y, dst->mode.width, dst->mode.height, 1529428d7b3dSmrg dst->rotation, (long)rr_crtc, dst->mode.id)); 1530428d7b3dSmrg 1531428d7b3dSmrg ret = XRRSetPanning(dst->dpy, res, rr_crtc, memset(&panning, 0, sizeof(panning))); 1532428d7b3dSmrg DBG(XRR, ("%s-%s: XRRSetPanning %s\n", DisplayString(dst->dpy), dst->name, ret ? "failed" : "success")); 1533428d7b3dSmrg (void)ret; 1534428d7b3dSmrg 1535428d7b3dSmrg ret = XRRSetCrtcConfig(dst->dpy, res, rr_crtc, CurrentTime, 1536428d7b3dSmrg dst->x, dst->y, dst->mode.id, dst->rotation, 1537428d7b3dSmrg &dst->rr_output, 1); 1538428d7b3dSmrg DBG(XRR, ("%s-%s: XRRSetCrtcConfig %s\n", DisplayString(dst->dpy), dst->name, ret ? "failed" : "success")); 1539428d7b3dSmrg if (ret) 1540428d7b3dSmrg goto err; 1541428d7b3dSmrg 1542428d7b3dSmrg if (verbose & XRR) { 1543428d7b3dSmrg XRRCrtcInfo *c; 1544428d7b3dSmrg XRRPanning *p; 1545428d7b3dSmrg 1546428d7b3dSmrg c = XRRGetCrtcInfo(dst->dpy, res, rr_crtc); 1547428d7b3dSmrg if (c) { 1548428d7b3dSmrg DBG(XRR, ("%s-%s: x=%d, y=%d, rotation=%d, mode=%ld\n", 1549428d7b3dSmrg DisplayString(dst->dpy), dst->name, 1550428d7b3dSmrg c->x, c->y, c->rotation, c->mode)); 1551428d7b3dSmrg XRRFreeCrtcInfo(c); 1552428d7b3dSmrg } 1553428d7b3dSmrg 1554428d7b3dSmrg p = XRRGetPanning(dst->dpy, res, rr_crtc); 1555428d7b3dSmrg if (p) { 1556428d7b3dSmrg DBG(XRR, ("%s-%s: panning (%d, %d)x(%d, %d), tracking (%d, %d)x(%d, %d), border (%d, %d),(%d, %d)\n", 1557428d7b3dSmrg DisplayString(dst->dpy), dst->name, 1558428d7b3dSmrg p->left, p->top, p->width, p->height, 1559428d7b3dSmrg p->track_left, p->track_top, p->track_width, p->track_height, 1560428d7b3dSmrg p->border_left, p->border_top, p->border_right, p->border_bottom)); 1561428d7b3dSmrg XRRFreePanning(p); 1562428d7b3dSmrg } 1563428d7b3dSmrg } 1564428d7b3dSmrg 1565428d7b3dSmrg dst->rr_crtc = rr_crtc; 1566428d7b3dSmrg } 1567428d7b3dSmrgfree_res: 1568428d7b3dSmrg XRRFreeScreenResources(res); 1569428d7b3dSmrgungrab: 1570428d7b3dSmrg XUngrabServer(display->dpy); 1571428d7b3dSmrg } 1572428d7b3dSmrg 1573428d7b3dSmrg ctx->active = NULL; 1574428d7b3dSmrg for (n = 0; n < ctx->nclone; n++) { 1575428d7b3dSmrg struct clone *clone = &ctx->clones[n]; 1576428d7b3dSmrg 1577428d7b3dSmrg clone_init_xfer(clone); 1578428d7b3dSmrg 1579428d7b3dSmrg if (clone->dst.rr_crtc == 0) 1580428d7b3dSmrg continue; 1581428d7b3dSmrg 1582428d7b3dSmrg DBG(XRR, ("%s-%s: added to active list\n", 1583428d7b3dSmrg DisplayString(clone->dst.display->dpy), clone->dst.name)); 1584428d7b3dSmrg 1585428d7b3dSmrg clone->active = ctx->active; 1586428d7b3dSmrg ctx->active = clone; 1587428d7b3dSmrg } 1588428d7b3dSmrg 1589428d7b3dSmrg return 1; 1590428d7b3dSmrg} 1591428d7b3dSmrg 1592428d7b3dSmrgstatic Cursor display_load_invisible_cursor(struct display *display) 1593428d7b3dSmrg{ 1594428d7b3dSmrg char zero[8] = {}; 1595428d7b3dSmrg XColor black = {}; 1596428d7b3dSmrg Pixmap bitmap = XCreateBitmapFromData(display->dpy, display->root, zero, 8, 8); 1597428d7b3dSmrg return XCreatePixmapCursor(display->dpy, bitmap, bitmap, &black, &black, 0, 0); 1598428d7b3dSmrg} 1599428d7b3dSmrg 1600428d7b3dSmrgstatic Cursor display_get_visible_cursor(struct display *display) 1601428d7b3dSmrg{ 1602428d7b3dSmrg if (display->cursor_serial != display->cursor_image.size) { 1603428d7b3dSmrg DBG(CURSOR, ("%s updating cursor\n", DisplayString(display->dpy))); 1604428d7b3dSmrg 1605428d7b3dSmrg if (display->visible_cursor) 1606428d7b3dSmrg XFreeCursor(display->dpy, display->visible_cursor); 1607428d7b3dSmrg 1608428d7b3dSmrg display->visible_cursor = XcursorImageLoadCursor(display->dpy, &display->cursor_image); 1609428d7b3dSmrg display->cursor_serial = display->cursor_image.size; 1610428d7b3dSmrg } 1611428d7b3dSmrg 1612428d7b3dSmrg return display->visible_cursor; 1613428d7b3dSmrg} 1614428d7b3dSmrg 1615428d7b3dSmrgstatic void display_load_visible_cursor(struct display *display, XFixesCursorImage *cur) 1616428d7b3dSmrg{ 1617428d7b3dSmrg unsigned long *src; /* XXX deep sigh */ 1618428d7b3dSmrg XcursorPixel *dst; 1619428d7b3dSmrg unsigned n; 1620428d7b3dSmrg 1621428d7b3dSmrg if (cur->width != display->cursor_image.width || 1622428d7b3dSmrg cur->height != display->cursor_image.height) 1623428d7b3dSmrg display->cursor_image.pixels = realloc(display->cursor_image.pixels, 1624428d7b3dSmrg 4 * cur->width * cur->height); 1625428d7b3dSmrg if (display->cursor_image.pixels == NULL) 1626428d7b3dSmrg return; 1627428d7b3dSmrg 1628428d7b3dSmrg display->cursor_image.width = cur->width; 1629428d7b3dSmrg display->cursor_image.height = cur->height; 1630428d7b3dSmrg display->cursor_image.xhot = cur->xhot; 1631428d7b3dSmrg display->cursor_image.yhot = cur->yhot; 1632428d7b3dSmrg display->cursor_image.size++; 1633428d7b3dSmrg 1634428d7b3dSmrg n = cur->width*cur->height; 1635428d7b3dSmrg src = cur->pixels; 1636428d7b3dSmrg dst = display->cursor_image.pixels; 1637428d7b3dSmrg while (n--) 1638428d7b3dSmrg *dst++ = *src++; 1639428d7b3dSmrg 1640428d7b3dSmrg DBG(CURSOR, ("%s marking cursor changed\n", DisplayString(display->dpy))); 1641428d7b3dSmrg display->cursor_moved++; 1642428d7b3dSmrg if (display->cursor != display->invisible_cursor) { 1643428d7b3dSmrg display->cursor_visible++; 1644428d7b3dSmrg context_enable_timer(display->ctx); 1645428d7b3dSmrg } 1646428d7b3dSmrg} 1647428d7b3dSmrg 1648428d7b3dSmrgstatic void display_cursor_move(struct display *display, int x, int y, int visible) 1649428d7b3dSmrg{ 1650428d7b3dSmrg DBG(CURSOR, ("%s cursor moved (visible=%d, (%d, %d))\n", 1651428d7b3dSmrg DisplayString(display->dpy), visible, x, y)); 1652428d7b3dSmrg display->cursor_moved++; 1653428d7b3dSmrg display->cursor_visible += visible; 1654428d7b3dSmrg if (visible) { 1655428d7b3dSmrg display->cursor_x = x; 1656428d7b3dSmrg display->cursor_y = y; 1657428d7b3dSmrg } 1658428d7b3dSmrg 1659428d7b3dSmrg context_enable_timer(display->ctx); 1660428d7b3dSmrg} 1661428d7b3dSmrg 1662428d7b3dSmrgstatic void display_flush_cursor(struct display *display) 1663428d7b3dSmrg{ 1664428d7b3dSmrg Cursor cursor; 1665428d7b3dSmrg int x, y; 1666428d7b3dSmrg 1667428d7b3dSmrg if (!display->cursor_moved) 1668428d7b3dSmrg return; 1669428d7b3dSmrg 1670428d7b3dSmrg if (display->cursor_visible) { 1671428d7b3dSmrg x = display->cursor_x; 1672428d7b3dSmrg y = display->cursor_y; 1673428d7b3dSmrg } else { 1674428d7b3dSmrg x = display->cursor_x++ & 31; 1675428d7b3dSmrg y = display->cursor_y++ & 31; 1676428d7b3dSmrg } 1677428d7b3dSmrg 1678428d7b3dSmrg DBG(CURSOR, ("%s setting cursor position (%d, %d), visible? %d\n", 1679428d7b3dSmrg DisplayString(display->dpy), x, y, display->cursor_visible)); 1680428d7b3dSmrg XWarpPointer(display->dpy, None, display->root, 0, 0, 0, 0, x, y); 1681428d7b3dSmrg 1682428d7b3dSmrg cursor = None; 1683428d7b3dSmrg if (display->cursor_visible) 1684428d7b3dSmrg cursor = display_get_visible_cursor(display); 1685428d7b3dSmrg if (cursor == None) 1686428d7b3dSmrg cursor = display->invisible_cursor; 1687428d7b3dSmrg if (cursor != display->cursor) { 1688428d7b3dSmrg XDefineCursor(display->dpy, display->root, cursor); 1689428d7b3dSmrg display->cursor = cursor; 1690428d7b3dSmrg } 1691428d7b3dSmrg 1692428d7b3dSmrg display_mark_flush(display); 1693428d7b3dSmrg 1694428d7b3dSmrg display->cursor_moved = 0; 1695428d7b3dSmrg display->cursor_visible = 0; 1696428d7b3dSmrg} 1697428d7b3dSmrg 1698428d7b3dSmrgstatic void clone_move_cursor(struct clone *c, int x, int y) 1699428d7b3dSmrg{ 1700428d7b3dSmrg int visible; 1701428d7b3dSmrg 1702428d7b3dSmrg DBG(CURSOR, ("%s-%s moving cursor (%d, %d) [(%d, %d), (%d, %d)]\n", 1703428d7b3dSmrg DisplayString(c->dst.dpy), c->dst.name, 1704428d7b3dSmrg x, y, 1705428d7b3dSmrg c->src.x, c->src.y, 1706428d7b3dSmrg c->src.x + c->width, c->src.y + c->height)); 1707428d7b3dSmrg 1708428d7b3dSmrg visible = (x >= c->src.x && x < c->src.x + c->width && 1709428d7b3dSmrg y >= c->src.y && y < c->src.y + c->height); 1710428d7b3dSmrg 1711428d7b3dSmrg x += c->dst.x - c->src.x; 1712428d7b3dSmrg y += c->dst.y - c->src.y; 1713428d7b3dSmrg 1714428d7b3dSmrg display_cursor_move(c->dst.display, x, y, visible); 1715428d7b3dSmrg} 1716428d7b3dSmrg 1717428d7b3dSmrgstatic int clone_output_init(struct clone *clone, struct output *output, 1718428d7b3dSmrg struct display *display, const char *name, 1719428d7b3dSmrg RROutput rr_output) 1720428d7b3dSmrg{ 1721428d7b3dSmrg Display *dpy = display->dpy; 1722428d7b3dSmrg int depth; 1723428d7b3dSmrg 1724428d7b3dSmrg DBG(X11, ("%s(%s, %s)\n", __func__, DisplayString(dpy), name)); 1725428d7b3dSmrg 1726428d7b3dSmrg output->name = strdup(name); 1727428d7b3dSmrg if (output->name == NULL) 1728428d7b3dSmrg return -ENOMEM; 1729428d7b3dSmrg 1730428d7b3dSmrg output->display = display; 1731428d7b3dSmrg output->dpy = dpy; 1732428d7b3dSmrg 1733428d7b3dSmrg output->rr_output = rr_output; 1734428d7b3dSmrg output->rotation = RR_Rotate_0; 1735428d7b3dSmrg 1736428d7b3dSmrg output->window = display->root; 1737428d7b3dSmrg output->use_shm = display->has_shm; 1738428d7b3dSmrg output->use_shm_pixmap = display->has_shm_pixmap; 1739428d7b3dSmrg 1740428d7b3dSmrg DBG(X11, ("%s-%s use shm? %d (use shm pixmap? %d)\n", 1741428d7b3dSmrg DisplayString(dpy), name, display->has_shm, display->has_shm_pixmap)); 1742428d7b3dSmrg 1743428d7b3dSmrg depth = output->use_shm && !FORCE_16BIT_XFER ? display->depth : 16; 1744428d7b3dSmrg if (depth < clone->depth) 1745428d7b3dSmrg clone->depth = depth; 1746428d7b3dSmrg 1747428d7b3dSmrg return 0; 1748428d7b3dSmrg} 1749428d7b3dSmrg 1750428d7b3dSmrgstatic void ximage_prepare(XImage *image, int width, int height) 1751428d7b3dSmrg{ 1752428d7b3dSmrg image->width = width; 1753428d7b3dSmrg image->height = height; 1754428d7b3dSmrg image->bytes_per_line = stride_for_depth(width, image->depth); 1755428d7b3dSmrg} 1756428d7b3dSmrg 1757428d7b3dSmrgstatic void get_src(struct clone *c, const XRectangle *clip) 1758428d7b3dSmrg{ 1759428d7b3dSmrg DBG(DRAW,("%s-%s get_src(%d,%d)x(%d,%d)\n", DisplayString(c->dst.dpy), c->dst.name, 1760428d7b3dSmrg clip->x, clip->y, clip->width, clip->height)); 1761428d7b3dSmrg 1762428d7b3dSmrg c->image.obdata = (char *)&c->src.shm; 1763428d7b3dSmrg 1764428d7b3dSmrg if (c->src.use_render) { 1765428d7b3dSmrg XRenderComposite(c->src.dpy, PictOpSrc, 1766428d7b3dSmrg c->src.win_picture, 0, c->src.pix_picture, 1767428d7b3dSmrg clip->x, clip->y, 1768428d7b3dSmrg 0, 0, 1769428d7b3dSmrg 0, 0, 1770428d7b3dSmrg clip->width, clip->height); 1771428d7b3dSmrg if (c->src.use_shm_pixmap) { 1772428d7b3dSmrg XSync(c->src.dpy, False); 1773428d7b3dSmrg } else if (c->src.use_shm) { 1774428d7b3dSmrg ximage_prepare(&c->image, clip->width, clip->height); 1775428d7b3dSmrg XShmGetImage(c->src.dpy, c->src.pixmap, &c->image, 1776428d7b3dSmrg clip->x, clip->y, AllPlanes); 1777428d7b3dSmrg } else { 1778428d7b3dSmrg ximage_prepare(&c->image, c->width, c->height); 1779428d7b3dSmrg XGetSubImage(c->src.dpy, c->src.pixmap, 1780428d7b3dSmrg clip->x, clip->y, clip->width, clip->height, 1781428d7b3dSmrg AllPlanes, ZPixmap, 1782428d7b3dSmrg &c->image, 0, 0); 1783428d7b3dSmrg } 1784428d7b3dSmrg } else if (c->src.pixmap) { 1785428d7b3dSmrg XCopyArea(c->src.dpy, c->src.window, c->src.pixmap, c->src.gc, 1786428d7b3dSmrg clip->x, clip->y, 1787428d7b3dSmrg clip->width, clip->height, 1788428d7b3dSmrg 0, 0); 1789428d7b3dSmrg XSync(c->src.dpy, False); 1790428d7b3dSmrg } else if (c->src.use_shm) { 1791428d7b3dSmrg ximage_prepare(&c->image, clip->width, clip->height); 1792428d7b3dSmrg XShmGetImage(c->src.dpy, c->src.window, &c->image, 1793428d7b3dSmrg clip->x, clip->y, AllPlanes); 1794428d7b3dSmrg } else { 1795428d7b3dSmrg ximage_prepare(&c->image, c->width, c->height); 1796428d7b3dSmrg XGetSubImage(c->src.dpy, c->src.window, 1797428d7b3dSmrg clip->x, clip->y, clip->width, clip->height, 1798428d7b3dSmrg AllPlanes, ZPixmap, 1799428d7b3dSmrg &c->image, 0, 0); 1800428d7b3dSmrg } 1801428d7b3dSmrg c->src.display->flush = 0; 1802428d7b3dSmrg} 1803428d7b3dSmrg 1804428d7b3dSmrgstatic void put_dst(struct clone *c, const XRectangle *clip) 1805428d7b3dSmrg{ 1806428d7b3dSmrg DBG(DRAW, ("%s-%s put_dst(%d,%d)x(%d,%d)\n", DisplayString(c->dst.dpy), c->dst.name, 1807428d7b3dSmrg clip->x, clip->y, clip->width, clip->height)); 1808428d7b3dSmrg 1809428d7b3dSmrg c->image.obdata = (char *)&c->dst.shm; 1810428d7b3dSmrg 1811428d7b3dSmrg if (c->dst.use_render) { 1812428d7b3dSmrg if (c->dst.use_shm_pixmap) { 1813428d7b3dSmrg DBG(DRAW, ("%s-%s using SHM pixmap composite\n", 1814428d7b3dSmrg DisplayString(c->dst.dpy), c->dst.name)); 1815428d7b3dSmrg } else if (c->dst.use_shm) { 1816428d7b3dSmrg DBG(DRAW, ("%s-%s using SHM image composite\n", 1817428d7b3dSmrg DisplayString(c->dst.dpy), c->dst.name)); 1818428d7b3dSmrg XShmPutImage(c->dst.dpy, c->dst.pixmap, c->dst.gc, &c->image, 1819428d7b3dSmrg 0, 0, 1820428d7b3dSmrg 0, 0, 1821428d7b3dSmrg clip->width, clip->height, 1822428d7b3dSmrg False); 1823428d7b3dSmrg } else { 1824428d7b3dSmrg DBG(DRAW, ("%s-%s using composite\n", 1825428d7b3dSmrg DisplayString(c->dst.dpy), c->dst.name)); 1826428d7b3dSmrg XPutImage(c->dst.dpy, c->dst.pixmap, c->dst.gc, &c->image, 1827428d7b3dSmrg 0, 0, 1828428d7b3dSmrg 0, 0, 1829428d7b3dSmrg clip->width, clip->height); 1830428d7b3dSmrg } 1831428d7b3dSmrg if (c->dst.use_shm) 1832428d7b3dSmrg c->dst.serial = NextRequest(c->dst.dpy); 1833428d7b3dSmrg XRenderComposite(c->dst.dpy, PictOpSrc, 1834428d7b3dSmrg c->dst.pix_picture, 0, c->dst.win_picture, 1835428d7b3dSmrg 0, 0, 1836428d7b3dSmrg 0, 0, 1837428d7b3dSmrg clip->x, clip->y, 1838428d7b3dSmrg clip->width, clip->height); 1839428d7b3dSmrg c->dst.display->send |= c->dst.use_shm; 1840428d7b3dSmrg } else if (c->dst.pixmap) { 1841428d7b3dSmrg DBG(DRAW, ("%s-%s using SHM pixmap\n", 1842428d7b3dSmrg DisplayString(c->dst.dpy), c->dst.name)); 1843428d7b3dSmrg c->dst.serial = NextRequest(c->dst.dpy); 1844428d7b3dSmrg XCopyArea(c->dst.dpy, c->dst.pixmap, c->dst.window, c->dst.gc, 1845428d7b3dSmrg 0, 0, 1846428d7b3dSmrg clip->width, clip->height, 1847428d7b3dSmrg clip->x, clip->y); 1848428d7b3dSmrg c->dst.display->send = 1; 1849428d7b3dSmrg } else if (c->dst.use_shm) { 1850428d7b3dSmrg DBG(DRAW, ("%s-%s using SHM image\n", 1851428d7b3dSmrg DisplayString(c->dst.dpy), c->dst.name)); 1852428d7b3dSmrg c->dst.serial = NextRequest(c->dst.dpy); 1853428d7b3dSmrg XShmPutImage(c->dst.dpy, c->dst.window, c->dst.gc, &c->image, 1854428d7b3dSmrg 0, 0, 1855428d7b3dSmrg clip->x, clip->y, 1856428d7b3dSmrg clip->width, clip->height, 1857428d7b3dSmrg True); 1858428d7b3dSmrg } else { 1859428d7b3dSmrg DBG(DRAW, ("%s-%s using image\n", 1860428d7b3dSmrg DisplayString(c->dst.dpy), c->dst.name)); 1861428d7b3dSmrg XPutImage(c->dst.dpy, c->dst.window, c->dst.gc, &c->image, 1862428d7b3dSmrg 0, 0, 1863428d7b3dSmrg clip->x, clip->y, 1864428d7b3dSmrg clip->width, clip->height); 1865428d7b3dSmrg c->dst.serial = 0; 1866428d7b3dSmrg } 1867428d7b3dSmrg} 1868428d7b3dSmrg 1869428d7b3dSmrgstatic int clone_paint(struct clone *c) 1870428d7b3dSmrg{ 1871428d7b3dSmrg XRectangle clip; 1872428d7b3dSmrg 1873428d7b3dSmrg DBG(DRAW, ("%s-%s paint clone, damaged (%d, %d), (%d, %d) [(%d, %d), (%d, %d)]\n", 1874428d7b3dSmrg DisplayString(c->dst.dpy), c->dst.name, 1875428d7b3dSmrg c->damaged.x1, c->damaged.y1, 1876428d7b3dSmrg c->damaged.x2, c->damaged.y2, 1877428d7b3dSmrg c->src.x, c->src.y, 1878428d7b3dSmrg c->src.x + c->width, c->src.y + c->height)); 1879428d7b3dSmrg 1880428d7b3dSmrg if (c->damaged.x1 < c->src.x) 1881428d7b3dSmrg c->damaged.x1 = c->src.x; 1882428d7b3dSmrg if (c->damaged.x2 > c->src.x + c->width) 1883428d7b3dSmrg c->damaged.x2 = c->src.x + c->width; 1884428d7b3dSmrg if (c->damaged.x2 <= c->damaged.x1) 1885428d7b3dSmrg goto done; 1886428d7b3dSmrg 1887428d7b3dSmrg if (c->damaged.y1 < c->src.y) 1888428d7b3dSmrg c->damaged.y1 = c->src.y; 1889428d7b3dSmrg if (c->damaged.y2 > c->src.y + c->height) 1890428d7b3dSmrg c->damaged.y2 = c->src.y + c->height; 1891428d7b3dSmrg if (c->damaged.y2 <= c->damaged.y1) 1892428d7b3dSmrg goto done; 1893428d7b3dSmrg 1894428d7b3dSmrg DBG(DRAW, ("%s-%s is damaged, last SHM serial: %ld, now %ld\n", 1895428d7b3dSmrg DisplayString(c->dst.dpy), c->dst.name, 1896428d7b3dSmrg (long)c->dst.serial, (long)LastKnownRequestProcessed(c->dst.dpy))); 1897428d7b3dSmrg if (c->dst.serial > LastKnownRequestProcessed(c->dst.dpy)) { 1898428d7b3dSmrg struct pollfd pfd; 1899428d7b3dSmrg 1900428d7b3dSmrg pfd.fd = ConnectionNumber(c->dst.dpy); 1901428d7b3dSmrg pfd.events = POLLIN; 1902428d7b3dSmrg XEventsQueued(c->dst.dpy, 1903428d7b3dSmrg poll(&pfd, 1, 0) ? QueuedAfterReading : QueuedAfterFlush); 1904428d7b3dSmrg 1905428d7b3dSmrg if (c->dst.serial > LastKnownRequestProcessed(c->dst.dpy)) { 1906428d7b3dSmrg c->dst.display->skip_clone++; 1907428d7b3dSmrg return EAGAIN; 1908428d7b3dSmrg } 1909428d7b3dSmrg } 1910428d7b3dSmrg 1911428d7b3dSmrg c->dst.display->skip_clone = 0; 1912428d7b3dSmrg c->dst.display->skip_frame = 0; 1913428d7b3dSmrg 1914428d7b3dSmrg if (FORCE_FULL_REDRAW) { 1915428d7b3dSmrg c->damaged.x1 = c->src.x; 1916428d7b3dSmrg c->damaged.y1 = c->src.y; 1917428d7b3dSmrg c->damaged.x2 = c->src.x + c->width; 1918428d7b3dSmrg c->damaged.y2 = c->src.y + c->height; 1919428d7b3dSmrg } 1920428d7b3dSmrg 1921428d7b3dSmrg if (c->dri3.xid) { 1922428d7b3dSmrg if (c->src.use_render) { 1923428d7b3dSmrg XRenderComposite(c->src.dpy, PictOpSrc, 1924428d7b3dSmrg c->src.win_picture, 0, c->src.pix_picture, 1925428d7b3dSmrg c->damaged.x1, c->damaged.y1, 1926428d7b3dSmrg 0, 0, 1927428d7b3dSmrg c->damaged.x1 + c->dst.x - c->src.x, 1928428d7b3dSmrg c->damaged.y1 + c->dst.y - c->src.y, 1929428d7b3dSmrg c->damaged.x2 - c->damaged.x1, 1930428d7b3dSmrg c->damaged.y2 - c->damaged.y1); 1931428d7b3dSmrg } else { 1932428d7b3dSmrg XCopyArea(c->src.dpy, c->src.window, c->src.pixmap, c->src.gc, 1933428d7b3dSmrg c->damaged.x1, c->damaged.y1, 1934428d7b3dSmrg c->damaged.x2 - c->damaged.x1, 1935428d7b3dSmrg c->damaged.y2 - c->damaged.y1, 1936428d7b3dSmrg c->damaged.x1 + c->dst.x - c->src.x, 1937428d7b3dSmrg c->damaged.y1 + c->dst.y - c->src.y); 1938428d7b3dSmrg } 1939428d7b3dSmrg dri3_fence_flush(c->src.dpy, &c->dri3); 1940428d7b3dSmrg } else { 1941428d7b3dSmrg clip.x = c->damaged.x1; 1942428d7b3dSmrg clip.y = c->damaged.y1; 1943428d7b3dSmrg clip.width = c->damaged.x2 - c->damaged.x1; 1944428d7b3dSmrg clip.height = c->damaged.y2 - c->damaged.y1; 1945428d7b3dSmrg get_src(c, &clip); 1946428d7b3dSmrg 1947428d7b3dSmrg clip.x += c->dst.x - c->src.x; 1948428d7b3dSmrg clip.y += c->dst.y - c->src.y; 1949428d7b3dSmrg put_dst(c, &clip); 1950428d7b3dSmrg } 1951428d7b3dSmrg display_mark_flush(c->dst.display); 1952428d7b3dSmrg 1953428d7b3dSmrgdone: 1954428d7b3dSmrg c->damaged.x2 = c->damaged.y2 = INT_MIN; 1955428d7b3dSmrg c->damaged.x1 = c->damaged.y1 = INT_MAX; 1956428d7b3dSmrg return 0; 1957428d7b3dSmrg} 1958428d7b3dSmrg 1959428d7b3dSmrgstatic void clone_damage(struct clone *c, const XRectangle *rec) 1960428d7b3dSmrg{ 1961428d7b3dSmrg int v; 1962428d7b3dSmrg 1963428d7b3dSmrg if ((v = rec->x) < c->damaged.x1) 1964428d7b3dSmrg c->damaged.x1 = v; 1965428d7b3dSmrg if ((v = (int)rec->x + rec->width) > c->damaged.x2) 1966428d7b3dSmrg c->damaged.x2 = v; 1967428d7b3dSmrg if ((v = rec->y) < c->damaged.y1) 1968428d7b3dSmrg c->damaged.y1 = v; 1969428d7b3dSmrg if ((v = (int)rec->y + rec->height) > c->damaged.y2) 1970428d7b3dSmrg c->damaged.y2 = v; 1971428d7b3dSmrg 1972428d7b3dSmrg DBG(DAMAGE, ("%s-%s damaged: (%d, %d), (%d, %d)\n", 1973428d7b3dSmrg DisplayString(c->dst.display->dpy), c->dst.name, 1974428d7b3dSmrg c->damaged.x1, c->damaged.y1, 1975428d7b3dSmrg c->damaged.x2, c->damaged.y2)); 1976428d7b3dSmrg} 1977428d7b3dSmrg 1978428d7b3dSmrgstatic void usage(const char *arg0) 1979428d7b3dSmrg{ 1980428d7b3dSmrg printf("Usage: %s [OPTION]... [TARGET_DISPLAY]...\n", arg0); 1981428d7b3dSmrg printf(" -d <source display> source display\n"); 1982428d7b3dSmrg printf(" -f keep in foreground (do not detach from console and daemonize)\n"); 1983428d7b3dSmrg printf(" -b start bumblebee\n"); 1984428d7b3dSmrg printf(" -a connect to all local displays (e.g. :1, :2, etc)\n"); 1985428d7b3dSmrg printf(" -S disable use of a singleton and launch a fresh intel-virtual-output process\n"); 1986428d7b3dSmrg printf(" -v all verbose output, implies -f\n"); 1987428d7b3dSmrg printf(" -V <category> specific verbose output, implies -f\n"); 1988428d7b3dSmrg printf(" -h this help\n"); 1989428d7b3dSmrg printf("If no target displays are parsed on the commandline, \n"); 1990428d7b3dSmrg printf("intel-virtual-output will attempt to connect to any local display\n"); 1991428d7b3dSmrg printf("and then start bumblebee.\n"); 1992428d7b3dSmrg} 1993428d7b3dSmrg 1994428d7b3dSmrgstatic void record_callback(XPointer closure, XRecordInterceptData *data) 1995428d7b3dSmrg{ 1996428d7b3dSmrg struct context *ctx = (struct context *)closure; 1997428d7b3dSmrg 1998428d7b3dSmrg DBG(X11, ("%s\n", __func__)); 1999428d7b3dSmrg 2000428d7b3dSmrg if (data->category == XRecordFromServer) { 2001428d7b3dSmrg const xEvent *e = (const xEvent *)data->data; 2002428d7b3dSmrg 2003428d7b3dSmrg DBG(X11, ("%s -- from server, event type %d, root %ld (ours? %d)\n", 2004428d7b3dSmrg __func__, e->u.u.type, (long)e->u.keyButtonPointer.root, 2005428d7b3dSmrg ctx->display->root == e->u.keyButtonPointer.root)); 2006428d7b3dSmrg 2007428d7b3dSmrg if (e->u.u.type == MotionNotify && 2008428d7b3dSmrg e->u.keyButtonPointer.root == ctx->display->root) { 2009428d7b3dSmrg struct clone *clone; 2010428d7b3dSmrg 2011428d7b3dSmrg for (clone = ctx->active; clone; clone = clone->active) 2012428d7b3dSmrg clone_move_cursor(clone, 2013428d7b3dSmrg e->u.keyButtonPointer.rootX, 2014428d7b3dSmrg e->u.keyButtonPointer.rootY); 2015428d7b3dSmrg } 2016428d7b3dSmrg } 2017428d7b3dSmrg 2018428d7b3dSmrg XRecordFreeData(data); 2019428d7b3dSmrg} 2020428d7b3dSmrg 2021428d7b3dSmrgstatic int record_mouse(struct context *ctx) 2022428d7b3dSmrg{ 2023428d7b3dSmrg Display *dpy; 2024428d7b3dSmrg XRecordRange *rr; 2025428d7b3dSmrg XRecordClientSpec rcs; 2026428d7b3dSmrg XRecordContext rc; 2027428d7b3dSmrg 2028428d7b3dSmrg DBG(X11, ("%s(%s)\n", __func__, DisplayString(ctx->display->dpy))); 2029428d7b3dSmrg 2030428d7b3dSmrg dpy = XOpenDisplay(DisplayString(ctx->display->dpy)); 2031428d7b3dSmrg if (dpy == NULL) 2032428d7b3dSmrg return -ECONNREFUSED; 2033428d7b3dSmrg 2034428d7b3dSmrg rr = XRecordAllocRange(); 2035428d7b3dSmrg if (rr == NULL) 2036428d7b3dSmrg return -ENOMEM; 2037428d7b3dSmrg 2038428d7b3dSmrg rr->device_events.first = rr->device_events.last = MotionNotify; 2039428d7b3dSmrg 2040428d7b3dSmrg rcs = XRecordAllClients; 2041428d7b3dSmrg rc = XRecordCreateContext(dpy, 0, &rcs, 1, &rr, 1); 2042428d7b3dSmrg 2043428d7b3dSmrg XSync(dpy, False); 2044428d7b3dSmrg 2045428d7b3dSmrg if (!XRecordEnableContextAsync(dpy, rc, record_callback, (XPointer)ctx)) 2046428d7b3dSmrg return -EINVAL; 2047428d7b3dSmrg 2048428d7b3dSmrg ctx->record = dpy; 2049428d7b3dSmrg return ConnectionNumber(dpy); 2050428d7b3dSmrg} 2051428d7b3dSmrg 2052428d7b3dSmrgstatic int bad_visual(Visual *visual, int depth) 2053428d7b3dSmrg{ 2054428d7b3dSmrg DBG(X11, ("%s? depth=%d, visual: class=%d, bits_per_rgb=%d, red_mask=%08lx, green_mask=%08lx, blue_mask=%08lx\n", 2055428d7b3dSmrg __func__, depth, 2056428d7b3dSmrg visual->class, 2057428d7b3dSmrg visual->bits_per_rgb, 2058428d7b3dSmrg visual->red_mask, 2059428d7b3dSmrg visual->green_mask, 2060428d7b3dSmrg visual->blue_mask)); 2061428d7b3dSmrg 2062428d7b3dSmrg if (!(visual->class == TrueColor || visual->class == DirectColor)) 2063428d7b3dSmrg return 1; 2064428d7b3dSmrg 2065428d7b3dSmrg switch (depth) { 2066428d7b3dSmrg case 16: return (/* visual->bits_per_rgb != 6 || */ 2067428d7b3dSmrg visual->red_mask != 0x1f << 11 || 2068428d7b3dSmrg visual->green_mask != 0x3f << 5 || 2069428d7b3dSmrg visual->blue_mask != 0x1f << 0); 2070428d7b3dSmrg 2071428d7b3dSmrg case 24: return (/* visual->bits_per_rgb != 8 || */ 2072428d7b3dSmrg visual->red_mask != 0xff << 16 || 2073428d7b3dSmrg visual->green_mask != 0xff << 8 || 2074428d7b3dSmrg visual->blue_mask != 0xff << 0); 2075428d7b3dSmrg 2076428d7b3dSmrg default: return 1; 2077428d7b3dSmrg } 2078428d7b3dSmrg} 2079428d7b3dSmrg 2080428d7b3dSmrgstatic XRenderPictFormat * 2081428d7b3dSmrgfind_xrender_format(Display *dpy, pixman_format_code_t format) 2082428d7b3dSmrg{ 2083428d7b3dSmrg XRenderPictFormat tmpl; 2084428d7b3dSmrg int mask; 2085428d7b3dSmrg 2086428d7b3dSmrg#define MASK(x) ((1<<(x))-1) 2087428d7b3dSmrg 2088428d7b3dSmrg memset(&tmpl, 0, sizeof(tmpl)); 2089428d7b3dSmrg 2090428d7b3dSmrg tmpl.depth = PIXMAN_FORMAT_DEPTH(format); 2091428d7b3dSmrg mask = PictFormatType | PictFormatDepth; 2092428d7b3dSmrg 2093428d7b3dSmrg DBG(X11, ("%s(0x%08lx)\n", __func__, (long)format)); 2094428d7b3dSmrg 2095428d7b3dSmrg switch (PIXMAN_FORMAT_TYPE(format)) { 2096428d7b3dSmrg case PIXMAN_TYPE_ARGB: 2097428d7b3dSmrg tmpl.type = PictTypeDirect; 2098428d7b3dSmrg 2099428d7b3dSmrg if (PIXMAN_FORMAT_A(format)) { 2100428d7b3dSmrg tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format)); 2101428d7b3dSmrg tmpl.direct.alpha = (PIXMAN_FORMAT_R(format) + 2102428d7b3dSmrg PIXMAN_FORMAT_G(format) + 2103428d7b3dSmrg PIXMAN_FORMAT_B(format)); 2104428d7b3dSmrg } 2105428d7b3dSmrg 2106428d7b3dSmrg tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format)); 2107428d7b3dSmrg tmpl.direct.red = (PIXMAN_FORMAT_G(format) + 2108428d7b3dSmrg PIXMAN_FORMAT_B(format)); 2109428d7b3dSmrg 2110428d7b3dSmrg tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format)); 2111428d7b3dSmrg tmpl.direct.green = PIXMAN_FORMAT_B(format); 2112428d7b3dSmrg 2113428d7b3dSmrg tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format)); 2114428d7b3dSmrg tmpl.direct.blue = 0; 2115428d7b3dSmrg 2116428d7b3dSmrg mask |= PictFormatRed | PictFormatRedMask; 2117428d7b3dSmrg mask |= PictFormatGreen | PictFormatGreenMask; 2118428d7b3dSmrg mask |= PictFormatBlue | PictFormatBlueMask; 2119428d7b3dSmrg mask |= PictFormatAlpha | PictFormatAlphaMask; 2120428d7b3dSmrg break; 2121428d7b3dSmrg 2122428d7b3dSmrg case PIXMAN_TYPE_ABGR: 2123428d7b3dSmrg tmpl.type = PictTypeDirect; 2124428d7b3dSmrg 2125428d7b3dSmrg if (tmpl.direct.alphaMask) { 2126428d7b3dSmrg tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format)); 2127428d7b3dSmrg tmpl.direct.alpha = (PIXMAN_FORMAT_B(format) + 2128428d7b3dSmrg PIXMAN_FORMAT_G(format) + 2129428d7b3dSmrg PIXMAN_FORMAT_R(format)); 2130428d7b3dSmrg } 2131428d7b3dSmrg 2132428d7b3dSmrg tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format)); 2133428d7b3dSmrg tmpl.direct.blue = (PIXMAN_FORMAT_G(format) + 2134428d7b3dSmrg PIXMAN_FORMAT_R(format)); 2135428d7b3dSmrg 2136428d7b3dSmrg tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format)); 2137428d7b3dSmrg tmpl.direct.green = PIXMAN_FORMAT_R(format); 2138428d7b3dSmrg 2139428d7b3dSmrg tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format)); 2140428d7b3dSmrg tmpl.direct.red = 0; 2141428d7b3dSmrg 2142428d7b3dSmrg mask |= PictFormatRed | PictFormatRedMask; 2143428d7b3dSmrg mask |= PictFormatGreen | PictFormatGreenMask; 2144428d7b3dSmrg mask |= PictFormatBlue | PictFormatBlueMask; 2145428d7b3dSmrg mask |= PictFormatAlpha | PictFormatAlphaMask; 2146428d7b3dSmrg break; 2147428d7b3dSmrg 2148428d7b3dSmrg case PIXMAN_TYPE_BGRA: 2149428d7b3dSmrg tmpl.type = PictTypeDirect; 2150428d7b3dSmrg 2151428d7b3dSmrg tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format)); 2152428d7b3dSmrg tmpl.direct.blue = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format)); 2153428d7b3dSmrg 2154428d7b3dSmrg tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format)); 2155428d7b3dSmrg tmpl.direct.green = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) - 2156428d7b3dSmrg PIXMAN_FORMAT_G(format)); 2157428d7b3dSmrg 2158428d7b3dSmrg tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format)); 2159428d7b3dSmrg tmpl.direct.red = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) - 2160428d7b3dSmrg PIXMAN_FORMAT_G(format) - PIXMAN_FORMAT_R(format)); 2161428d7b3dSmrg 2162428d7b3dSmrg if (tmpl.direct.alphaMask) { 2163428d7b3dSmrg tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format)); 2164428d7b3dSmrg tmpl.direct.alpha = 0; 2165428d7b3dSmrg } 2166428d7b3dSmrg 2167428d7b3dSmrg mask |= PictFormatRed | PictFormatRedMask; 2168428d7b3dSmrg mask |= PictFormatGreen | PictFormatGreenMask; 2169428d7b3dSmrg mask |= PictFormatBlue | PictFormatBlueMask; 2170428d7b3dSmrg mask |= PictFormatAlpha | PictFormatAlphaMask; 2171428d7b3dSmrg break; 2172428d7b3dSmrg 2173428d7b3dSmrg case PIXMAN_TYPE_A: 2174428d7b3dSmrg tmpl.type = PictTypeDirect; 2175428d7b3dSmrg 2176428d7b3dSmrg tmpl.direct.alpha = 0; 2177428d7b3dSmrg tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format)); 2178428d7b3dSmrg 2179428d7b3dSmrg mask |= PictFormatAlpha | PictFormatAlphaMask; 2180428d7b3dSmrg break; 2181428d7b3dSmrg 2182428d7b3dSmrg case PIXMAN_TYPE_COLOR: 2183428d7b3dSmrg case PIXMAN_TYPE_GRAY: 2184428d7b3dSmrg /* XXX Find matching visual/colormap */ 2185428d7b3dSmrg tmpl.type = PictTypeIndexed; 2186428d7b3dSmrg //tmpl.colormap = screen->visuals[PIXMAN_FORMAT_VIS(format)].vid; 2187428d7b3dSmrg //mask |= PictFormatColormap; 2188428d7b3dSmrg return NULL; 2189428d7b3dSmrg } 2190428d7b3dSmrg#undef MASK 2191428d7b3dSmrg 2192428d7b3dSmrg return XRenderFindFormat(dpy, mask, &tmpl, 0); 2193428d7b3dSmrg} 2194428d7b3dSmrg 2195428d7b3dSmrgstatic int display_init_render(struct display *display, int depth, XRenderPictFormat **use_render) 2196428d7b3dSmrg{ 2197428d7b3dSmrg Display *dpy = display->dpy; 2198428d7b3dSmrg int major, minor; 2199428d7b3dSmrg 2200428d7b3dSmrg DBG(X11, ("%s is depth %d, want %d\n", DisplayString(dpy), display->depth, depth)); 2201428d7b3dSmrg 2202428d7b3dSmrg *use_render = 0; 2203428d7b3dSmrg if (depth == display->depth && !bad_visual(display->visual, depth)) 2204428d7b3dSmrg return 0; 2205428d7b3dSmrg 2206428d7b3dSmrg if (display->root_format == 0) { 2207428d7b3dSmrg if (!XRenderQueryVersion(dpy, &major, &minor)) { 2208428d7b3dSmrg fprintf(stderr, "Render extension not supported by %s\n", DisplayString(dpy)); 2209428d7b3dSmrg return -EINVAL; 2210428d7b3dSmrg } 2211428d7b3dSmrg 2212428d7b3dSmrg display->root_format = XRenderFindVisualFormat(dpy, display->visual); 2213428d7b3dSmrg display->rgb16_format = find_xrender_format(dpy, PIXMAN_r5g6b5); 2214428d7b3dSmrg display->rgb24_format = XRenderFindStandardFormat(dpy, PictStandardRGB24); 2215428d7b3dSmrg 2216428d7b3dSmrg DBG(X11, ("%s: root format=%lx, rgb16 format=%lx, rgb24 format=%lx\n", 2217428d7b3dSmrg DisplayString(dpy), 2218428d7b3dSmrg (long)display->root_format, 2219428d7b3dSmrg (long)display->rgb16_format, 2220428d7b3dSmrg (long)display->rgb24_format)); 2221428d7b3dSmrg } 2222428d7b3dSmrg 2223428d7b3dSmrg switch (depth) { 2224428d7b3dSmrg case 16: *use_render = display->rgb16_format; break; 2225428d7b3dSmrg case 24: *use_render = display->rgb24_format; break; 2226428d7b3dSmrg } 2227428d7b3dSmrg if (*use_render == 0) 2228428d7b3dSmrg return -ENOENT; 2229428d7b3dSmrg 2230428d7b3dSmrg return 0; 2231428d7b3dSmrg} 2232428d7b3dSmrg 2233428d7b3dSmrgstatic int clone_init_depth(struct clone *clone) 2234428d7b3dSmrg{ 2235428d7b3dSmrg int ret, depth; 2236428d7b3dSmrg 2237428d7b3dSmrg DBG(X11,("%s-%s wants depth %d\n", 2238428d7b3dSmrg DisplayString(clone->dst.dpy), clone->dst.name, clone->depth)); 2239428d7b3dSmrg 2240428d7b3dSmrg ret = -1; 2241428d7b3dSmrg for (depth = clone->depth; depth <= 24; depth += 8) { 2242428d7b3dSmrg ret = display_init_render(clone->src.display, depth, &clone->src.use_render); 2243428d7b3dSmrg if (ret) 2244428d7b3dSmrg continue; 2245428d7b3dSmrg 2246428d7b3dSmrg ret = display_init_render(clone->dst.display, depth, &clone->dst.use_render); 2247428d7b3dSmrg if (ret) 2248428d7b3dSmrg continue; 2249428d7b3dSmrg 2250428d7b3dSmrg break; 2251428d7b3dSmrg } 2252428d7b3dSmrg if (ret) 2253428d7b3dSmrg return ret; 2254428d7b3dSmrg 2255428d7b3dSmrg DBG(X11, ("%s-%s using depth %d, requires xrender for src? %d, for dst? %d\n", 2256428d7b3dSmrg DisplayString(clone->dst.dpy), clone->dst.name, 2257428d7b3dSmrg clone->depth, 2258428d7b3dSmrg clone->src.use_render != NULL, 2259428d7b3dSmrg clone->dst.use_render != NULL)); 2260428d7b3dSmrg 2261428d7b3dSmrg if (!clone->dst.use_render && 2262428d7b3dSmrg clone->src.display->dri3_active && 2263428d7b3dSmrg clone->dst.display->dri3_active) 2264428d7b3dSmrg dri3_create_fence(clone->src.dpy, clone->src.window, &clone->dri3); 2265428d7b3dSmrg 2266428d7b3dSmrg return 0; 2267428d7b3dSmrg} 2268428d7b3dSmrg 2269428d7b3dSmrg#if defined(USE_XINERAMA) 2270428d7b3dSmrgstatic int xinerama_active(struct display *display) 2271428d7b3dSmrg{ 2272428d7b3dSmrg int active = 0; 2273428d7b3dSmrg if (XineramaQueryExtension(display->dpy, &display->xinerama_event, &display->xinerama_error)) 2274428d7b3dSmrg active = XineramaIsActive(display->dpy); 2275428d7b3dSmrg return active; 2276428d7b3dSmrg} 2277428d7b3dSmrg#else 2278428d7b3dSmrg#define xinerama_active(d) 0 2279428d7b3dSmrg#endif 2280428d7b3dSmrg 2281428d7b3dSmrgstatic int add_display(struct context *ctx, Display *dpy) 2282428d7b3dSmrg{ 2283428d7b3dSmrg struct display *display; 2284428d7b3dSmrg int first_display = ctx->ndisplay == 0; 2285428d7b3dSmrg 2286428d7b3dSmrg if (is_power_of_2(ctx->ndisplay)) { 2287428d7b3dSmrg struct display *new_display; 2288428d7b3dSmrg 2289428d7b3dSmrg new_display = realloc(ctx->display, 2*ctx->ndisplay*sizeof(struct display)); 2290428d7b3dSmrg if (new_display == NULL) 2291428d7b3dSmrg return -ENOMEM; 2292428d7b3dSmrg 2293428d7b3dSmrg if (new_display != ctx->display) { 2294428d7b3dSmrg int n; 2295428d7b3dSmrg 2296428d7b3dSmrg for (n = 0; n < ctx->nclone; n++) { 2297428d7b3dSmrg struct clone *clone = &ctx->clones[n]; 2298428d7b3dSmrg clone->src.display = new_display + (clone->src.display - ctx->display); 2299428d7b3dSmrg clone->dst.display = new_display + (clone->dst.display - ctx->display); 2300428d7b3dSmrg } 2301428d7b3dSmrg } 2302428d7b3dSmrg 2303428d7b3dSmrg ctx->display = new_display; 2304428d7b3dSmrg } 2305428d7b3dSmrg 2306428d7b3dSmrg display = memset(&ctx->display[ctx->ndisplay++], 0, sizeof(struct display)); 2307428d7b3dSmrg 2308428d7b3dSmrg display->dpy = dpy; 2309428d7b3dSmrg display->ctx = ctx; 2310428d7b3dSmrg 2311428d7b3dSmrg display->root = DefaultRootWindow(dpy); 2312428d7b3dSmrg display->depth = DefaultDepth(dpy, DefaultScreen(dpy)); 2313428d7b3dSmrg display->visual = DefaultVisual(dpy, DefaultScreen(dpy)); 2314428d7b3dSmrg 2315428d7b3dSmrg display->has_shm = can_use_shm(dpy, display->root, 2316428d7b3dSmrg &display->shm_event, 2317428d7b3dSmrg &display->shm_opcode, 2318428d7b3dSmrg &display->has_shm_pixmap); 2319428d7b3dSmrg DBG(X11, ("%s: has_shm?=%d, event=%d, opcode=%d, has_pixmap?=%d\n", 2320428d7b3dSmrg DisplayString(dpy), 2321428d7b3dSmrg display->has_shm, 2322428d7b3dSmrg display->shm_event, 2323428d7b3dSmrg display->shm_opcode, 2324428d7b3dSmrg display->has_shm_pixmap)); 2325428d7b3dSmrg 2326428d7b3dSmrg display->rr_active = XRRQueryExtension(dpy, &display->rr_event, &display->rr_error); 2327428d7b3dSmrg DBG(X11, ("%s: randr_active?=%d, event=%d, error=%d\n", 2328428d7b3dSmrg DisplayString(dpy), 2329428d7b3dSmrg display->rr_active, 2330428d7b3dSmrg display->rr_event, 2331428d7b3dSmrg display->rr_error)); 2332428d7b3dSmrg 2333428d7b3dSmrg display->xinerama_active = xinerama_active(display); 2334428d7b3dSmrg DBG(X11, ("%s: xinerama_active?=%d, event=%d, error=%d\n", 2335428d7b3dSmrg DisplayString(dpy), 2336428d7b3dSmrg display->xinerama_active, 2337428d7b3dSmrg display->xinerama_event, 2338428d7b3dSmrg display->xinerama_error)); 2339428d7b3dSmrg 2340428d7b3dSmrg display->dri3_active = dri3_exists(dpy); 2341428d7b3dSmrg DBG(X11, ("%s: dri3_active?=%d\n", 2342428d7b3dSmrg DisplayString(dpy), 2343428d7b3dSmrg display->dri3_active)); 2344428d7b3dSmrg 2345428d7b3dSmrg /* first display (source) is slightly special */ 2346428d7b3dSmrg if (!first_display) { 2347428d7b3dSmrg display->invisible_cursor = display_load_invisible_cursor(display); 2348428d7b3dSmrg display_cursor_move(display, 0, 0, 0); 2349428d7b3dSmrg } 2350428d7b3dSmrg 2351428d7b3dSmrg return ConnectionNumber(dpy); 2352428d7b3dSmrg} 2353428d7b3dSmrg 2354428d7b3dSmrgstatic int display_open(struct context *ctx, const char *name) 2355428d7b3dSmrg{ 2356428d7b3dSmrg Display *dpy; 2357428d7b3dSmrg int n; 2358428d7b3dSmrg 2359428d7b3dSmrg DBG(X11, ("%s(%s)\n", __func__, name)); 2360428d7b3dSmrg 2361428d7b3dSmrg dpy = XOpenDisplay(name); 2362428d7b3dSmrg if (dpy == NULL) 2363428d7b3dSmrg return -ECONNREFUSED; 2364428d7b3dSmrg 2365428d7b3dSmrg /* Prevent cloning the same display twice */ 2366428d7b3dSmrg for (n = 0; n < ctx->ndisplay; n++) { 2367428d7b3dSmrg if (strcmp(DisplayString(dpy), DisplayString(ctx->display[n].dpy)) == 0) { 2368428d7b3dSmrg DBG(X11, ("%s %s is already connected\n", __func__, name)); 2369428d7b3dSmrg XCloseDisplay(dpy); 2370428d7b3dSmrg return -EBUSY; 2371428d7b3dSmrg } 2372428d7b3dSmrg } 2373428d7b3dSmrg 2374428d7b3dSmrg return add_display(ctx, dpy); 2375428d7b3dSmrg} 2376428d7b3dSmrg 2377428d7b3dSmrgstatic int bumblebee_open(struct context *ctx) 2378428d7b3dSmrg{ 2379428d7b3dSmrg char buf[256]; 2380428d7b3dSmrg struct sockaddr_un addr; 2381428d7b3dSmrg int fd, len; 2382428d7b3dSmrg 2383428d7b3dSmrg fd = socket(PF_UNIX, SOCK_STREAM, 0); 2384428d7b3dSmrg if (fd < 0) { 2385428d7b3dSmrg DBG(X11, ("%s unable to create a socket: %d\n", __func__, errno)); 2386428d7b3dSmrg return -ECONNREFUSED; 2387428d7b3dSmrg } 2388428d7b3dSmrg 2389428d7b3dSmrg addr.sun_family = AF_UNIX; 2390428d7b3dSmrg snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", 2391428d7b3dSmrg optarg && *optarg ? optarg : "/var/run/bumblebee.socket"); 2392428d7b3dSmrg if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 2393428d7b3dSmrg DBG(X11, ("%s unable to create a socket: %d\n", __func__, errno)); 2394428d7b3dSmrg goto err; 2395428d7b3dSmrg } 2396428d7b3dSmrg 2397428d7b3dSmrg /* Ask bumblebee to start the second server */ 2398428d7b3dSmrg buf[0] = 'C'; 2399428d7b3dSmrg if (send(fd, &buf, 1, 0) != 1 || (len = recv(fd, &buf, 255, 0)) <= 0) { 2400428d7b3dSmrg DBG(X11, ("%s startup send/recv failed: %d\n", __func__, errno)); 2401428d7b3dSmrg goto err; 2402428d7b3dSmrg } 2403428d7b3dSmrg buf[len] = '\0'; 2404428d7b3dSmrg 2405428d7b3dSmrg /* Query the display name */ 2406428d7b3dSmrg strcpy(buf, "Q VirtualDisplay"); 2407428d7b3dSmrg if (send(fd, buf, 17, 0) != 17 || (len = recv(fd, buf, 255, 0)) <= 0) { 2408428d7b3dSmrg DBG(X11, ("%s query send/recv failed: %d\n", __func__, errno)); 2409428d7b3dSmrg goto err; 2410428d7b3dSmrg } 2411428d7b3dSmrg buf[len] = '\0'; 2412428d7b3dSmrg 2413428d7b3dSmrg DBG(X11, ("%s query result '%s'\n", __func__, buf)); 2414428d7b3dSmrg 2415428d7b3dSmrg if (strncmp(buf, "Value: ", 7)) 2416428d7b3dSmrg goto err; 2417428d7b3dSmrg 2418428d7b3dSmrg len = 7; 2419428d7b3dSmrg while (buf[len] != '\n' && buf[len] != '\0') 2420428d7b3dSmrg len++; 2421428d7b3dSmrg buf[len] = '\0'; 2422428d7b3dSmrg 2423428d7b3dSmrg /* XXX We must keep the control socket open whilst we want to keep 2424428d7b3dSmrg * the display around. 2425428d7b3dSmrg * 2426428d7b3dSmrg * So what we need to do is listen for new bumblee Xservers and 2427428d7b3dSmrg * bind only for their duration. 2428428d7b3dSmrg */ 2429428d7b3dSmrg 2430428d7b3dSmrg return display_open(ctx, buf+7); 2431428d7b3dSmrg 2432428d7b3dSmrgerr: 2433428d7b3dSmrg close(fd); 2434428d7b3dSmrg return -ECONNREFUSED; 2435428d7b3dSmrg} 2436428d7b3dSmrg 2437428d7b3dSmrgstatic int display_init_damage(struct display *display) 2438428d7b3dSmrg{ 2439428d7b3dSmrg DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy))); 2440428d7b3dSmrg 2441428d7b3dSmrg if (!XDamageQueryExtension(display->dpy, &display->damage_event, &display->damage_error) || 2442428d7b3dSmrg !XFixesQueryExtension(display->dpy, &display->xfixes_event, &display->xfixes_error)) { 2443428d7b3dSmrg fprintf(stderr, "Damage/Fixes extension not supported by %s\n", DisplayString(display->dpy)); 2444428d7b3dSmrg return EINVAL; 2445428d7b3dSmrg } 2446428d7b3dSmrg 2447428d7b3dSmrg display->damage = XDamageCreate(display->dpy, display->root, XDamageReportBoundingBox); 2448428d7b3dSmrg if (display->damage == 0) 2449428d7b3dSmrg return EACCES; 2450428d7b3dSmrg 2451428d7b3dSmrg return 0; 2452428d7b3dSmrg} 2453428d7b3dSmrg 2454428d7b3dSmrgstatic void display_reset_damage(struct display *display) 2455428d7b3dSmrg{ 2456428d7b3dSmrg Damage damage; 2457428d7b3dSmrg 2458428d7b3dSmrg damage = XDamageCreate(display->dpy, display->root, XDamageReportBoundingBox); 2459428d7b3dSmrg if (damage) { 2460428d7b3dSmrg XDamageDestroy(display->dpy, display->damage); 2461428d7b3dSmrg display->damage = damage; 2462428d7b3dSmrg XFlush(display->dpy); 2463428d7b3dSmrg display->flush = 0; 2464428d7b3dSmrg } 2465428d7b3dSmrg} 2466428d7b3dSmrg 2467428d7b3dSmrgstatic void display_init_randr_hpd(struct display *display) 2468428d7b3dSmrg{ 2469428d7b3dSmrg int major, minor; 2470428d7b3dSmrg 2471428d7b3dSmrg DBG(X11,("%s(%s)\n", __func__, DisplayString(display->dpy))); 2472428d7b3dSmrg 2473428d7b3dSmrg if (!XRRQueryVersion(display->dpy, &major, &minor)) 2474428d7b3dSmrg return; 2475428d7b3dSmrg 2476428d7b3dSmrg DBG(X11, ("%s - randr version %d.%d\n", DisplayString(display->dpy), major, minor)); 2477428d7b3dSmrg if (major > 1 || (major == 1 && minor >= 2)) 2478428d7b3dSmrg XRRSelectInput(display->dpy, display->root, RROutputChangeNotifyMask); 2479428d7b3dSmrg} 2480428d7b3dSmrg 2481428d7b3dSmrgstatic void rebuild_clones(struct context *ctx, struct clone *new_clones) 2482428d7b3dSmrg{ 2483428d7b3dSmrg int n, m; 2484428d7b3dSmrg 2485428d7b3dSmrg for (n = 1; n < ctx->ndisplay; n++) { 2486428d7b3dSmrg struct display *d = &ctx->display[n]; 2487428d7b3dSmrg 2488428d7b3dSmrg d->clone = NULL; 2489428d7b3dSmrg for (m = 0; m < ctx->nclone; m++) { 2490428d7b3dSmrg struct clone *c = &new_clones[m]; 2491428d7b3dSmrg 2492428d7b3dSmrg if (c->dst.display != d) 2493428d7b3dSmrg continue; 2494428d7b3dSmrg 2495428d7b3dSmrg c->next = d->clone; 2496428d7b3dSmrg d->clone = c; 2497428d7b3dSmrg } 2498428d7b3dSmrg } 2499428d7b3dSmrg 2500428d7b3dSmrg ctx->clones = new_clones; 2501428d7b3dSmrg} 2502428d7b3dSmrg 2503428d7b3dSmrgstatic struct clone *add_clone(struct context *ctx) 2504428d7b3dSmrg{ 2505428d7b3dSmrg if (is_power_of_2(ctx->nclone)) { 2506428d7b3dSmrg struct clone *new_clones; 2507428d7b3dSmrg 2508428d7b3dSmrg new_clones = realloc(ctx->clones, 2*ctx->nclone*sizeof(struct clone)); 2509428d7b3dSmrg if (new_clones == NULL) 2510428d7b3dSmrg return NULL; 2511428d7b3dSmrg 2512428d7b3dSmrg if (new_clones != ctx->clones) 2513428d7b3dSmrg rebuild_clones(ctx, new_clones); 2514428d7b3dSmrg } 2515428d7b3dSmrg 2516428d7b3dSmrg return memset(&ctx->clones[ctx->nclone++], 0, sizeof(struct clone)); 2517428d7b3dSmrg} 2518428d7b3dSmrg 2519428d7b3dSmrgstatic struct display *last_display(struct context *ctx) 2520428d7b3dSmrg{ 2521428d7b3dSmrg return &ctx->display[ctx->ndisplay-1]; 2522428d7b3dSmrg} 2523428d7b3dSmrg 2524428d7b3dSmrgstatic void reverse_clone_list(struct display *display) 2525428d7b3dSmrg{ 2526428d7b3dSmrg struct clone *list = NULL; 2527428d7b3dSmrg 2528428d7b3dSmrg while (display->clone) { 2529428d7b3dSmrg struct clone *clone = display->clone; 2530428d7b3dSmrg display->clone = clone->next; 2531428d7b3dSmrg clone->next = list; 2532428d7b3dSmrg list = clone; 2533428d7b3dSmrg } 2534428d7b3dSmrg 2535428d7b3dSmrg display->clone = list; 2536428d7b3dSmrg} 2537428d7b3dSmrg 2538428d7b3dSmrgstatic int last_display_add_clones__randr(struct context *ctx) 2539428d7b3dSmrg{ 2540428d7b3dSmrg struct display *display = last_display(ctx); 2541428d7b3dSmrg XRRScreenResources *res; 2542428d7b3dSmrg char buf[80]; 2543428d7b3dSmrg int i, ret; 2544428d7b3dSmrg 2545428d7b3dSmrg DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy))); 2546428d7b3dSmrg 2547428d7b3dSmrg display_init_randr_hpd(display); 2548428d7b3dSmrg 2549428d7b3dSmrg /* Force a probe of outputs on initial connection */ 2550428d7b3dSmrg res = XRRGetScreenResources(display->dpy, display->root); 2551428d7b3dSmrg if (res == NULL) 2552428d7b3dSmrg return -ENOMEM; 2553428d7b3dSmrg 2554428d7b3dSmrg DBG(X11, ("%s - noutputs=%d\n", DisplayString(display->dpy), res->noutput)); 2555428d7b3dSmrg for (i = 0; i < res->noutput; i++) { 2556428d7b3dSmrg XRROutputInfo *o = XRRGetOutputInfo(display->dpy, res, res->outputs[i]); 2557428d7b3dSmrg struct clone *clone = add_clone(ctx); 2558428d7b3dSmrg RROutput id; 2559428d7b3dSmrg 2560428d7b3dSmrg if (clone == NULL) 2561428d7b3dSmrg return -ENOMEM; 2562428d7b3dSmrg 2563428d7b3dSmrg clone->depth = 24; 2564428d7b3dSmrg clone->next = display->clone; 2565428d7b3dSmrg display->clone = clone; 2566428d7b3dSmrg 2567428d7b3dSmrg id = claim_virtual(ctx->display, buf, ctx->nclone); 2568428d7b3dSmrg if (id == 0) { 2569428d7b3dSmrg fprintf(stderr, "Failed to find available VirtualHead \"%s\" for \"%s\" on display \"%s\"\n", 2570428d7b3dSmrg buf, o->name, DisplayString(display->dpy)); 2571428d7b3dSmrg return -ENOSPC; 2572428d7b3dSmrg } 2573428d7b3dSmrg 2574428d7b3dSmrg ret = clone_output_init(clone, &clone->src, ctx->display, buf, id); 2575428d7b3dSmrg if (ret) { 2576428d7b3dSmrg fprintf(stderr, "Failed to add output \"%s\" on display \"%s\"\n", 2577428d7b3dSmrg buf, DisplayString(ctx->display->dpy)); 2578428d7b3dSmrg return ret; 2579428d7b3dSmrg } 2580428d7b3dSmrg 2581428d7b3dSmrg ret = clone_output_init(clone, &clone->dst, display, o->name, res->outputs[i]); 2582428d7b3dSmrg if (ret) { 2583428d7b3dSmrg fprintf(stderr, "Failed to add output \"%s\" on display \"%s\"\n", 2584428d7b3dSmrg o->name, DisplayString(display->dpy)); 2585428d7b3dSmrg return ret; 2586428d7b3dSmrg } 2587428d7b3dSmrg 2588428d7b3dSmrg ret = clone_init_depth(clone); 2589428d7b3dSmrg if (ret) { 2590428d7b3dSmrg fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n", 2591428d7b3dSmrg DisplayString(display->dpy)); 2592428d7b3dSmrg return ret; 2593428d7b3dSmrg } 2594428d7b3dSmrg 2595428d7b3dSmrg ret = clone_update_modes__randr(clone); 2596428d7b3dSmrg if (ret) { 2597428d7b3dSmrg fprintf(stderr, "Failed to clone output \"%s\" from display \"%s\"\n", 2598428d7b3dSmrg o->name, DisplayString(display->dpy)); 2599428d7b3dSmrg return ret; 2600428d7b3dSmrg } 2601428d7b3dSmrg 2602428d7b3dSmrg 2603428d7b3dSmrg if (o->crtc) { 2604428d7b3dSmrg DBG(X11, ("%s - disabling active output\n", DisplayString(display->dpy))); 2605428d7b3dSmrg disable_crtc(display->dpy, res, o->crtc); 2606428d7b3dSmrg } 2607428d7b3dSmrg 2608428d7b3dSmrg XRRFreeOutputInfo(o); 2609428d7b3dSmrg } 2610428d7b3dSmrg XRRFreeScreenResources(res); 2611428d7b3dSmrg 2612428d7b3dSmrg reverse_clone_list(display); 2613428d7b3dSmrg return 0; 2614428d7b3dSmrg} 2615428d7b3dSmrg 2616428d7b3dSmrg#if defined(USE_XINERAMA) 2617428d7b3dSmrgstatic int last_display_add_clones__xinerama(struct context *ctx) 2618428d7b3dSmrg{ 2619428d7b3dSmrg struct display *display = last_display(ctx); 2620428d7b3dSmrg Display *dpy = display->dpy; 2621428d7b3dSmrg XineramaScreenInfo *xi; 2622428d7b3dSmrg char buf[80]; 2623428d7b3dSmrg int n, count, ret; 2624428d7b3dSmrg 2625428d7b3dSmrg DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy))); 2626428d7b3dSmrg 2627428d7b3dSmrg count = 0; 2628428d7b3dSmrg xi = XineramaQueryScreens(dpy, &count); 2629428d7b3dSmrg for (n = 0; n < count; n++) { 2630428d7b3dSmrg struct clone *clone = add_clone(ctx); 2631428d7b3dSmrg RROutput id; 2632428d7b3dSmrg 2633428d7b3dSmrg if (clone == NULL) 2634428d7b3dSmrg return -ENOMEM; 2635428d7b3dSmrg 2636428d7b3dSmrg if (xi[n].width == 0 || xi[n].height == 0) 2637428d7b3dSmrg continue; 2638428d7b3dSmrg 2639428d7b3dSmrg clone->depth = 24; 2640428d7b3dSmrg clone->next = display->clone; 2641428d7b3dSmrg display->clone = clone; 2642428d7b3dSmrg 2643428d7b3dSmrg id = claim_virtual(ctx->display, buf, ctx->nclone); 2644428d7b3dSmrg if (id == 0) { 2645428d7b3dSmrg fprintf(stderr, "Failed to find available VirtualHead \"%s\" for Xinerama screen %d on display \"%s\"\n", 2646428d7b3dSmrg buf, n, DisplayString(dpy)); 2647428d7b3dSmrg } 2648428d7b3dSmrg ret = clone_output_init(clone, &clone->src, ctx->display, buf, id); 2649428d7b3dSmrg if (ret) { 2650428d7b3dSmrg fprintf(stderr, "Failed to add Xinerama screen %d on display \"%s\"\n", 2651428d7b3dSmrg n, DisplayString(ctx->display->dpy)); 2652428d7b3dSmrg return ret; 2653428d7b3dSmrg } 2654428d7b3dSmrg 2655428d7b3dSmrg sprintf(buf, "XINERAMA%d", n); 2656428d7b3dSmrg ret = clone_output_init(clone, &clone->dst, display, buf, 0); 2657428d7b3dSmrg if (ret) { 2658428d7b3dSmrg fprintf(stderr, "Failed to add Xinerama screen %d on display \"%s\"\n", 2659428d7b3dSmrg n, DisplayString(dpy)); 2660428d7b3dSmrg return ret; 2661428d7b3dSmrg } 2662428d7b3dSmrg 2663428d7b3dSmrg ret = clone_init_depth(clone); 2664428d7b3dSmrg if (ret) { 2665428d7b3dSmrg fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n", 2666428d7b3dSmrg DisplayString(display->dpy)); 2667428d7b3dSmrg return ret; 2668428d7b3dSmrg } 2669428d7b3dSmrg 2670428d7b3dSmrg /* Replace the modes on the local VIRTUAL output with the remote Screen */ 2671428d7b3dSmrg clone->width = xi[n].width; 2672428d7b3dSmrg clone->height = xi[n].height; 2673428d7b3dSmrg clone->dst.x = xi[n].x_org; 2674428d7b3dSmrg clone->dst.y = xi[n].y_org; 2675428d7b3dSmrg clone->dst.rr_crtc = -1; 2676428d7b3dSmrg ret = clone_update_modes__fixed(clone); 2677428d7b3dSmrg if (ret) { 2678428d7b3dSmrg fprintf(stderr, "Failed to clone Xinerama screen %d from display \"%s\"\n", 2679428d7b3dSmrg n, DisplayString(display->dpy)); 2680428d7b3dSmrg return ret; 2681428d7b3dSmrg } 2682428d7b3dSmrg 2683428d7b3dSmrg clone->active = ctx->active; 2684428d7b3dSmrg ctx->active = clone; 2685428d7b3dSmrg } 2686428d7b3dSmrg XFree(xi); 2687428d7b3dSmrg 2688428d7b3dSmrg reverse_clone_list(display); 2689428d7b3dSmrg return 0; 2690428d7b3dSmrg} 2691428d7b3dSmrg#else 2692428d7b3dSmrg#define last_display_add_clones__xinerama(ctx) -1 2693428d7b3dSmrg#endif 2694428d7b3dSmrg 2695428d7b3dSmrgstatic int last_display_add_clones__display(struct context *ctx) 2696428d7b3dSmrg{ 2697428d7b3dSmrg struct display *display = last_display(ctx); 2698428d7b3dSmrg Display *dpy = display->dpy; 2699428d7b3dSmrg struct clone *clone; 2700428d7b3dSmrg Screen *scr; 2701428d7b3dSmrg char buf[80]; 2702428d7b3dSmrg int ret; 2703428d7b3dSmrg RROutput id; 2704428d7b3dSmrg 2705428d7b3dSmrg 2706428d7b3dSmrg DBG(X11, ("%s(%s)\n", __func__, DisplayString(dpy))); 2707428d7b3dSmrg clone = add_clone(ctx); 2708428d7b3dSmrg if (clone == NULL) 2709428d7b3dSmrg return -ENOMEM; 2710428d7b3dSmrg 2711428d7b3dSmrg clone->depth = 24; 2712428d7b3dSmrg clone->next = display->clone; 2713428d7b3dSmrg display->clone = clone; 2714428d7b3dSmrg 2715428d7b3dSmrg id = claim_virtual(ctx->display, buf, ctx->nclone); 2716428d7b3dSmrg if (id == 0) { 2717428d7b3dSmrg fprintf(stderr, "Failed to find available VirtualHead \"%s\" for on display \"%s\"\n", 2718428d7b3dSmrg buf, DisplayString(dpy)); 2719428d7b3dSmrg } 2720428d7b3dSmrg ret = clone_output_init(clone, &clone->src, ctx->display, buf, id); 2721428d7b3dSmrg if (ret) { 2722428d7b3dSmrg fprintf(stderr, "Failed to add display \"%s\"\n", 2723428d7b3dSmrg DisplayString(ctx->display->dpy)); 2724428d7b3dSmrg return ret; 2725428d7b3dSmrg } 2726428d7b3dSmrg 2727428d7b3dSmrg sprintf(buf, "WHOLE"); 2728428d7b3dSmrg ret = clone_output_init(clone, &clone->dst, display, buf, 0); 2729428d7b3dSmrg if (ret) { 2730428d7b3dSmrg fprintf(stderr, "Failed to add display \"%s\"\n", 2731428d7b3dSmrg DisplayString(dpy)); 2732428d7b3dSmrg return ret; 2733428d7b3dSmrg } 2734428d7b3dSmrg 2735428d7b3dSmrg ret = clone_init_depth(clone); 2736428d7b3dSmrg if (ret) { 2737428d7b3dSmrg fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n", 2738428d7b3dSmrg DisplayString(dpy)); 2739428d7b3dSmrg return ret; 2740428d7b3dSmrg } 2741428d7b3dSmrg 2742428d7b3dSmrg /* Replace the modes on the local VIRTUAL output with the remote Screen */ 2743428d7b3dSmrg scr = ScreenOfDisplay(dpy, DefaultScreen(dpy)); 2744428d7b3dSmrg clone->width = scr->width; 2745428d7b3dSmrg clone->height = scr->height; 2746428d7b3dSmrg clone->dst.x = 0; 2747428d7b3dSmrg clone->dst.y = 0; 2748428d7b3dSmrg clone->dst.rr_crtc = -1; 2749428d7b3dSmrg ret = clone_update_modes__fixed(clone); 2750428d7b3dSmrg if (ret) { 2751428d7b3dSmrg fprintf(stderr, "Failed to clone display \"%s\"\n", 2752428d7b3dSmrg DisplayString(dpy)); 2753428d7b3dSmrg return ret; 2754428d7b3dSmrg } 2755428d7b3dSmrg 2756428d7b3dSmrg clone->active = ctx->active; 2757428d7b3dSmrg ctx->active = clone; 2758428d7b3dSmrg 2759428d7b3dSmrg return 0; 2760428d7b3dSmrg} 2761428d7b3dSmrg 2762428d7b3dSmrgstatic int last_display_add_clones(struct context *ctx) 2763428d7b3dSmrg{ 2764428d7b3dSmrg struct display *display = last_display(ctx); 2765428d7b3dSmrg 2766428d7b3dSmrg display->width = DisplayWidth(display->dpy, DefaultScreen(display->dpy)); 2767428d7b3dSmrg display->height = DisplayHeight(display->dpy, DefaultScreen(display->dpy)); 2768428d7b3dSmrg DBG(X11, ("%s - initial size %dx%d\n", DisplayString(display->dpy), display->width, display->height)); 2769428d7b3dSmrg 2770428d7b3dSmrg if (display->rr_active) 2771428d7b3dSmrg return last_display_add_clones__randr(ctx); 2772428d7b3dSmrg 2773428d7b3dSmrg if (display->xinerama_active) 2774428d7b3dSmrg return last_display_add_clones__xinerama(ctx); 2775428d7b3dSmrg 2776428d7b3dSmrg return last_display_add_clones__display(ctx); 2777428d7b3dSmrg} 2778428d7b3dSmrg 2779428d7b3dSmrgstatic int last_display_clone(struct context *ctx, int fd) 2780428d7b3dSmrg{ 2781428d7b3dSmrg fd = add_fd(ctx, fd); 2782428d7b3dSmrg if (fd < 0) 2783428d7b3dSmrg return fd; 2784428d7b3dSmrg 2785428d7b3dSmrg fd = last_display_add_clones(ctx); 2786428d7b3dSmrg if (fd) 2787428d7b3dSmrg return fd; 2788428d7b3dSmrg 2789428d7b3dSmrg return 0; 2790428d7b3dSmrg} 2791428d7b3dSmrg 2792428d7b3dSmrgstatic int first_display_has_singleton(struct context *ctx) 2793428d7b3dSmrg{ 2794428d7b3dSmrg struct display *display = ctx->display; 2795428d7b3dSmrg unsigned long nitems, bytes; 2796428d7b3dSmrg unsigned char *prop; 2797428d7b3dSmrg int format; 2798428d7b3dSmrg Atom type; 2799428d7b3dSmrg 2800428d7b3dSmrg ctx->singleton = XInternAtom(display->dpy, "intel-virtual-output-singleton", False); 2801428d7b3dSmrg 2802428d7b3dSmrg XGetWindowProperty(display->dpy, display->root, ctx->singleton, 2803428d7b3dSmrg 0, 0, 0, AnyPropertyType, &type, &format, &nitems, &bytes, &prop); 2804428d7b3dSmrg DBG(X11, ("%s: singleton registered? %d\n", DisplayString(display->dpy), type != None)); 2805428d7b3dSmrg return type != None; 2806428d7b3dSmrg} 2807428d7b3dSmrg 2808428d7b3dSmrgstatic int first_display_wait_for_ack(struct context *ctx, int timeout, int id) 2809428d7b3dSmrg{ 2810428d7b3dSmrg struct display *display = ctx->display; 2811428d7b3dSmrg struct pollfd pfd; 2812428d7b3dSmrg char expect[6]; /* "1234R\0" */ 2813428d7b3dSmrg 2814428d7b3dSmrg sprintf(expect, "%04xR", id); 2815428d7b3dSmrg DBG(X11, ("%s: wait for act '%c%c%c%c%c'\n", 2816428d7b3dSmrg DisplayString(display->dpy), 2817428d7b3dSmrg expect[0], expect[1], expect[2], expect[3], expect[4])); 2818428d7b3dSmrg 2819428d7b3dSmrg XFlush(display->dpy); 2820428d7b3dSmrg 2821428d7b3dSmrg pfd.fd = ConnectionNumber(display->dpy); 2822428d7b3dSmrg pfd.events = POLLIN; 2823428d7b3dSmrg do { 2824428d7b3dSmrg if (poll(&pfd, 1, timeout) <= 0) 2825428d7b3dSmrg return -ETIME; 2826428d7b3dSmrg 2827428d7b3dSmrg while (XPending(display->dpy)) { 2828428d7b3dSmrg XEvent e; 2829428d7b3dSmrg XClientMessageEvent *cme; 2830428d7b3dSmrg 2831428d7b3dSmrg XNextEvent(display->dpy, &e); 2832428d7b3dSmrg DBG(X11, ("%s: reading event type %d\n", DisplayString(display->dpy), e.type)); 2833428d7b3dSmrg 2834428d7b3dSmrg if (e.type != ClientMessage) 2835428d7b3dSmrg continue; 2836428d7b3dSmrg 2837428d7b3dSmrg cme = (XClientMessageEvent *)&e; 2838428d7b3dSmrg if (cme->message_type != ctx->singleton) 2839428d7b3dSmrg continue; 2840428d7b3dSmrg if (cme->format != 8) 2841428d7b3dSmrg continue; 2842428d7b3dSmrg 2843428d7b3dSmrg DBG(X11, ("%s: client message '%c%c%c%c%c'\n", 2844428d7b3dSmrg DisplayString(display->dpy), 2845428d7b3dSmrg cme->data.b[0], 2846428d7b3dSmrg cme->data.b[1], 2847428d7b3dSmrg cme->data.b[2], 2848428d7b3dSmrg cme->data.b[3], 2849428d7b3dSmrg cme->data.b[4])); 2850428d7b3dSmrg if (memcmp(cme->data.b, expect, 5)) 2851428d7b3dSmrg continue; 2852428d7b3dSmrg 2853428d7b3dSmrg return -atoi(cme->data.b + 5); 2854428d7b3dSmrg } 2855428d7b3dSmrg } while (1); 2856428d7b3dSmrg} 2857428d7b3dSmrg 2858428d7b3dSmrg#if defined(__GNUC__) && (__GNUC__ > 3) 2859428d7b3dSmrg__attribute__((format(gnu_printf, 3, 4))) 2860428d7b3dSmrg#endif 2861428d7b3dSmrgstatic int first_display_send_command(struct context *ctx, int timeout, 2862428d7b3dSmrg const char *format, 2863428d7b3dSmrg ...) 2864428d7b3dSmrg{ 2865428d7b3dSmrg struct display *display = ctx->display; 2866428d7b3dSmrg char buf[1024], *b; 2867428d7b3dSmrg int len, id; 2868428d7b3dSmrg va_list va; 2869428d7b3dSmrg 2870428d7b3dSmrg id = rand() & 0xffff; 2871428d7b3dSmrg sprintf(buf, "%04x", id); 2872428d7b3dSmrg va_start(va, format); 2873428d7b3dSmrg len = vsnprintf(buf+4, sizeof(buf)-4, format, va)+5; 2874428d7b3dSmrg va_end(va); 2875428d7b3dSmrg assert(len < sizeof(buf)); 2876428d7b3dSmrg 2877428d7b3dSmrg DBG(X11, ("%s: send command '%s'\n", DisplayString(display->dpy), buf)); 2878428d7b3dSmrg 2879428d7b3dSmrg b = buf; 2880428d7b3dSmrg while (len) { 2881428d7b3dSmrg XClientMessageEvent msg; 2882428d7b3dSmrg int n = len; 2883428d7b3dSmrg if (n > sizeof(msg.data.b)) 2884428d7b3dSmrg n = sizeof(msg.data.b); 2885428d7b3dSmrg len -= n; 2886428d7b3dSmrg 2887428d7b3dSmrg msg.type = ClientMessage; 2888428d7b3dSmrg msg.serial = 0; 2889428d7b3dSmrg msg.message_type = ctx->singleton; 2890428d7b3dSmrg msg.format = 8; 2891428d7b3dSmrg memcpy(msg.data.b, b, n); 2892428d7b3dSmrg b += n; 2893428d7b3dSmrg 2894428d7b3dSmrg XSendEvent(display->dpy, display->root, False, PropertyChangeMask, (XEvent *)&msg); 2895428d7b3dSmrg } 2896428d7b3dSmrg 2897428d7b3dSmrg return first_display_wait_for_ack(ctx, timeout, id); 2898428d7b3dSmrg} 2899428d7b3dSmrg 2900428d7b3dSmrgstatic void first_display_reply(struct context *ctx, int result) 2901428d7b3dSmrg{ 2902428d7b3dSmrg struct display *display = ctx->display; 2903428d7b3dSmrg XClientMessageEvent msg; 2904428d7b3dSmrg 2905428d7b3dSmrg sprintf(msg.data.b, "%c%c%c%cR%d", 2906428d7b3dSmrg ctx->command[0], 2907428d7b3dSmrg ctx->command[1], 2908428d7b3dSmrg ctx->command[2], 2909428d7b3dSmrg ctx->command[3], 2910428d7b3dSmrg -result); 2911428d7b3dSmrg 2912428d7b3dSmrg DBG(X11, ("%s: send reply '%s'\n", DisplayString(display->dpy), msg.data.b)); 2913428d7b3dSmrg 2914428d7b3dSmrg msg.type = ClientMessage; 2915428d7b3dSmrg msg.serial = 0; 2916428d7b3dSmrg msg.message_type = ctx->singleton; 2917428d7b3dSmrg msg.format = 8; 2918428d7b3dSmrg 2919428d7b3dSmrg XSendEvent(display->dpy, display->root, False, PropertyChangeMask, (XEvent *)&msg); 2920428d7b3dSmrg XFlush(display->dpy); 2921428d7b3dSmrg} 2922428d7b3dSmrg 2923428d7b3dSmrgstatic void first_display_handle_command(struct context *ctx, 2924428d7b3dSmrg const char *msg) 2925428d7b3dSmrg{ 2926428d7b3dSmrg int len; 2927428d7b3dSmrg 2928428d7b3dSmrg DBG(X11, ("client message!\n")); 2929428d7b3dSmrg 2930428d7b3dSmrg for (len = 0; len < 20 && msg[len]; len++) 2931428d7b3dSmrg ; 2932428d7b3dSmrg 2933428d7b3dSmrg if (ctx->command_continuation + len > sizeof(ctx->command)) { 2934428d7b3dSmrg ctx->command_continuation = 0; 2935428d7b3dSmrg return; 2936428d7b3dSmrg } 2937428d7b3dSmrg 2938428d7b3dSmrg memcpy(ctx->command + ctx->command_continuation, msg, len); 2939428d7b3dSmrg ctx->command_continuation += len; 2940428d7b3dSmrg 2941428d7b3dSmrg if (len < 20) { 2942428d7b3dSmrg ctx->command[ctx->command_continuation] = 0; 2943428d7b3dSmrg DBG(X11, ("client command complete! '%s'\n", ctx->command)); 2944428d7b3dSmrg switch (ctx->command[4]) { 2945428d7b3dSmrg case 'B': 2946428d7b3dSmrg first_display_reply(ctx, last_display_clone(ctx, bumblebee_open(ctx))); 2947428d7b3dSmrg break; 2948428d7b3dSmrg case 'C': 2949428d7b3dSmrg first_display_reply(ctx, last_display_clone(ctx, display_open(ctx, ctx->command + 5))); 2950428d7b3dSmrg break; 2951428d7b3dSmrg case 'P': 2952428d7b3dSmrg first_display_reply(ctx, 0); 2953428d7b3dSmrg break; 2954428d7b3dSmrg case 'R': 2955428d7b3dSmrg break; 2956428d7b3dSmrg } 2957428d7b3dSmrg ctx->command_continuation = 0; 2958428d7b3dSmrg return; 2959428d7b3dSmrg } 2960428d7b3dSmrg} 2961428d7b3dSmrg 2962428d7b3dSmrgstatic int first_display_register_as_singleton(struct context *ctx) 2963428d7b3dSmrg{ 2964428d7b3dSmrg struct display *display = ctx->display; 2965428d7b3dSmrg struct pollfd pfd; 2966428d7b3dSmrg 2967428d7b3dSmrg XChangeProperty(display->dpy, display->root, ctx->singleton, 2968428d7b3dSmrg XA_STRING, 8, PropModeReplace, (unsigned char *)".", 1); 2969428d7b3dSmrg XFlush(display->dpy); 2970428d7b3dSmrg 2971428d7b3dSmrg /* And eat the notify (presuming that it is ours!) */ 2972428d7b3dSmrg 2973428d7b3dSmrg pfd.fd = ConnectionNumber(display->dpy); 2974428d7b3dSmrg pfd.events = POLLIN; 2975428d7b3dSmrg do { 2976428d7b3dSmrg if (poll(&pfd, 1, 1000) <= 0) { 2977428d7b3dSmrg fprintf(stderr, "Failed to register as singleton\n"); 2978428d7b3dSmrg return EBUSY; 2979428d7b3dSmrg } 2980428d7b3dSmrg 2981428d7b3dSmrg while (XPending(display->dpy)) { 2982428d7b3dSmrg XEvent e; 2983428d7b3dSmrg 2984428d7b3dSmrg XNextEvent(display->dpy, &e); 2985428d7b3dSmrg DBG(X11, ("%s: reading event type %d\n", DisplayString(display->dpy), e.type)); 2986428d7b3dSmrg 2987428d7b3dSmrg if (e.type == PropertyNotify && 2988428d7b3dSmrg ((XPropertyEvent *)&e)->atom == ctx->singleton) 2989428d7b3dSmrg return 0; 2990428d7b3dSmrg } 2991428d7b3dSmrg } while (1); 2992428d7b3dSmrg} 2993428d7b3dSmrg 2994428d7b3dSmrgstatic void display_flush_send(struct display *display) 2995428d7b3dSmrg{ 2996428d7b3dSmrg XShmCompletionEvent e; 2997428d7b3dSmrg 2998428d7b3dSmrg if (!display->send) 2999428d7b3dSmrg return; 3000428d7b3dSmrg 3001428d7b3dSmrg DBG(X11, ("%s flushing send (serial now %ld) (has shm send? %d)\n", 3002428d7b3dSmrg DisplayString(display->dpy), 3003428d7b3dSmrg (long)NextRequest(display->dpy), 3004428d7b3dSmrg display->shm_event)); 3005428d7b3dSmrg 3006428d7b3dSmrg display->send = 0; 3007428d7b3dSmrg 3008428d7b3dSmrg if (display->shm_event == 0) { 3009428d7b3dSmrg XSync(display->dpy, False); 3010428d7b3dSmrg display->flush = 0; 3011428d7b3dSmrg return; 3012428d7b3dSmrg } 3013428d7b3dSmrg 3014428d7b3dSmrg memset(&e, 0, sizeof(e)); 3015428d7b3dSmrg e.type = display->shm_event; 3016428d7b3dSmrg e.send_event = 1; 3017428d7b3dSmrg e.drawable = display->root; 3018428d7b3dSmrg e.major_code = display->shm_opcode; 3019428d7b3dSmrg e.minor_code = X_ShmPutImage; 3020428d7b3dSmrg 3021428d7b3dSmrg XSendEvent(display->dpy, display->root, False, 0, (XEvent *)&e); 3022428d7b3dSmrg display_mark_flush(display); 3023428d7b3dSmrg} 3024428d7b3dSmrg 3025428d7b3dSmrgstatic void display_sync(struct display *display) 3026428d7b3dSmrg{ 3027428d7b3dSmrg if (display->skip_clone == 0) 3028428d7b3dSmrg return; 3029428d7b3dSmrg 3030428d7b3dSmrg if (display->skip_frame++ < 2) 3031428d7b3dSmrg return; 3032428d7b3dSmrg 3033428d7b3dSmrg DBG(X11, ("%s forcing sync\n", DisplayString(display->dpy))); 3034428d7b3dSmrg XSync(display->dpy, False); 3035428d7b3dSmrg 3036428d7b3dSmrg display->flush = 0; 3037428d7b3dSmrg display->send = 0; 3038428d7b3dSmrg 3039428d7b3dSmrg /* Event tracking proven unreliable, disable */ 3040428d7b3dSmrg display->shm_event = 0; 3041428d7b3dSmrg} 3042428d7b3dSmrg 3043428d7b3dSmrgstatic void display_flush(struct display *display) 3044428d7b3dSmrg{ 3045428d7b3dSmrg display_flush_cursor(display); 3046428d7b3dSmrg display_flush_send(display); 3047428d7b3dSmrg 3048428d7b3dSmrg display_sync(display); 3049428d7b3dSmrg 3050428d7b3dSmrg if (!display->flush) 3051428d7b3dSmrg return; 3052428d7b3dSmrg 3053428d7b3dSmrg DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy))); 3054428d7b3dSmrg 3055428d7b3dSmrg XFlush(display->dpy); 3056428d7b3dSmrg display->flush = 0; 3057428d7b3dSmrg} 3058428d7b3dSmrg 3059428d7b3dSmrgstatic int first_display_first_sibling(struct context *ctx) 3060428d7b3dSmrg{ 3061428d7b3dSmrg const char *str, *colon; 3062428d7b3dSmrg int dpy, scr, len; 3063428d7b3dSmrg 3064428d7b3dSmrg str = DisplayString(ctx->display->dpy); 3065428d7b3dSmrg colon = strrchr(str, ':'); 3066428d7b3dSmrg if (colon == NULL) 3067428d7b3dSmrg return -1; 3068428d7b3dSmrg 3069428d7b3dSmrg if (sscanf(colon + 1, "%d.%d", &dpy, &scr) == 1) 3070428d7b3dSmrg scr = 0; 3071428d7b3dSmrg 3072428d7b3dSmrg len = (colon - str) + 1; 3073428d7b3dSmrg memcpy(ctx->command, str, len); 3074428d7b3dSmrg len += sprintf(ctx->command + len, "%d.", dpy); 3075428d7b3dSmrg ctx->command_continuation = len; 3076428d7b3dSmrg 3077428d7b3dSmrg return scr + 1; 3078428d7b3dSmrg} 3079428d7b3dSmrg 3080428d7b3dSmrgstatic int first_display_sibling(struct context *ctx, int i) 3081428d7b3dSmrg{ 3082428d7b3dSmrg if (i < 0) 3083428d7b3dSmrg return 0; 3084428d7b3dSmrg 3085428d7b3dSmrg sprintf(ctx->command + ctx->command_continuation, "%d", i); 3086428d7b3dSmrg return 1; 3087428d7b3dSmrg} 3088428d7b3dSmrg 3089428d7b3dSmrg#define first_display_for_each_sibling(CTX, i) \ 3090428d7b3dSmrg for (i = first_display_first_sibling(CTX); first_display_sibling(CTX, i); i++) 3091428d7b3dSmrg 3092428d7b3dSmrgstatic void display_cleanup(struct display *display) 3093428d7b3dSmrg{ 3094428d7b3dSmrg Display *dpy = display->dpy; 3095428d7b3dSmrg XRRScreenResources *res; 3096428d7b3dSmrg int n; 3097428d7b3dSmrg 3098428d7b3dSmrg XGrabServer(dpy); 3099428d7b3dSmrg 3100428d7b3dSmrg res = _XRRGetScreenResourcesCurrent(dpy, display->root); 3101428d7b3dSmrg if (res != NULL) { 3102428d7b3dSmrg for (n = 0; n < res->ncrtc; n++) 3103428d7b3dSmrg disable_crtc(display->dpy, res, res->crtcs[n]); 3104428d7b3dSmrg 3105428d7b3dSmrg XRRFreeScreenResources(res); 3106428d7b3dSmrg } 3107428d7b3dSmrg 3108428d7b3dSmrg XUngrabServer(dpy); 3109428d7b3dSmrg} 3110428d7b3dSmrg 3111428d7b3dSmrgstatic void context_cleanup(struct context *ctx) 3112428d7b3dSmrg{ 3113428d7b3dSmrg Display *dpy = ctx->display->dpy; 3114428d7b3dSmrg XRRScreenResources *res; 3115428d7b3dSmrg int i, j; 3116428d7b3dSmrg 3117428d7b3dSmrg for (i = 1; i < ctx->ndisplay; i++) 3118428d7b3dSmrg display_cleanup(&ctx->display[i]); 3119428d7b3dSmrg 3120428d7b3dSmrg if (dpy == NULL) 3121428d7b3dSmrg return; 3122428d7b3dSmrg 3123428d7b3dSmrg res = _XRRGetScreenResourcesCurrent(dpy, ctx->display->root); 3124428d7b3dSmrg if (res == NULL) 3125428d7b3dSmrg return; 3126428d7b3dSmrg 3127428d7b3dSmrg XGrabServer(dpy); 3128428d7b3dSmrg 3129428d7b3dSmrg for (i = 0; i < ctx->nclone; i++) { 3130428d7b3dSmrg struct clone *clone = &ctx->clones[i]; 3131428d7b3dSmrg XRROutputInfo *output; 3132428d7b3dSmrg 3133428d7b3dSmrg assert(clone->src.display == ctx->display); 3134428d7b3dSmrg 3135428d7b3dSmrg output = XRRGetOutputInfo(dpy, res, clone->src.rr_output); 3136428d7b3dSmrg if (output == NULL) 3137428d7b3dSmrg continue; 3138428d7b3dSmrg 3139428d7b3dSmrg disable_crtc(dpy, res, output->crtc); 3140428d7b3dSmrg for (j = 0; j < output->nmode; j++) 3141428d7b3dSmrg XRRDeleteOutputMode(dpy, clone->src.rr_output, output->modes[j]); 3142428d7b3dSmrg 3143428d7b3dSmrg XRRFreeOutputInfo(output); 3144428d7b3dSmrg } 3145428d7b3dSmrg 3146428d7b3dSmrg for (i = 0; i < res->nmode; i++) { 3147428d7b3dSmrg if (strncmp(res->modes[i].name, "VIRTUAL", 7) == 0) { 3148428d7b3dSmrg XRRDestroyMode(dpy, res->modes[i].id); 3149428d7b3dSmrg continue; 3150428d7b3dSmrg } 3151428d7b3dSmrg 3152428d7b3dSmrg if (strcmp(res->modes[i].name, "ClaimVirtualHead") == 0) { 3153428d7b3dSmrg XRRDestroyMode(dpy, res->modes[i].id); 3154428d7b3dSmrg continue; 3155428d7b3dSmrg } 3156428d7b3dSmrg } 3157428d7b3dSmrg XRRFreeScreenResources(res); 3158428d7b3dSmrg 3159428d7b3dSmrg /* And hide them again */ 3160428d7b3dSmrg res = XRRGetScreenResources(dpy, ctx->display->root); 3161428d7b3dSmrg if (res != NULL) 3162428d7b3dSmrg XRRFreeScreenResources(res); 3163428d7b3dSmrg 3164428d7b3dSmrg XUngrabServer(dpy); 3165428d7b3dSmrg 3166428d7b3dSmrg if (ctx->singleton) 3167428d7b3dSmrg XDeleteProperty(dpy, ctx->display->root, ctx->singleton); 3168428d7b3dSmrg XCloseDisplay(dpy); 3169428d7b3dSmrg} 3170428d7b3dSmrg 3171428d7b3dSmrgstatic int done; 3172428d7b3dSmrg 3173428d7b3dSmrgstatic void signal_handler(int sig) 3174428d7b3dSmrg{ 3175428d7b3dSmrg done = sig; 3176428d7b3dSmrg} 3177428d7b3dSmrg 3178428d7b3dSmrgint main(int argc, char **argv) 3179428d7b3dSmrg{ 3180428d7b3dSmrg struct context ctx; 3181428d7b3dSmrg const char *src_name = NULL; 3182428d7b3dSmrg uint64_t count; 3183428d7b3dSmrg int daemonize = 1, bumblebee = 0, siblings = 0, singleton = 1; 3184428d7b3dSmrg int i, ret, open, fail; 3185428d7b3dSmrg 3186428d7b3dSmrg signal(SIGPIPE, SIG_IGN); 3187428d7b3dSmrg 3188428d7b3dSmrg while ((i = getopt(argc, argv, "abd:fhSvV:")) != -1) { 3189428d7b3dSmrg switch (i) { 3190428d7b3dSmrg case 'd': 3191428d7b3dSmrg src_name = optarg; 3192428d7b3dSmrg break; 3193428d7b3dSmrg case 'f': 3194428d7b3dSmrg daemonize = 0; 3195428d7b3dSmrg break; 3196428d7b3dSmrg case 'b': 3197428d7b3dSmrg bumblebee = 1; 3198428d7b3dSmrg break; 3199428d7b3dSmrg case 's': 3200428d7b3dSmrg siblings = 1; 3201428d7b3dSmrg break; 3202428d7b3dSmrg case 'S': 3203428d7b3dSmrg singleton = 0; 3204428d7b3dSmrg break; 3205428d7b3dSmrg case 'v': 3206428d7b3dSmrg verbose = ~0; 3207428d7b3dSmrg daemonize = 0; 3208428d7b3dSmrg break; 3209428d7b3dSmrg case 'V': 3210428d7b3dSmrg verbose = strtol(optarg, NULL, 0); 3211428d7b3dSmrg daemonize = 0; 3212428d7b3dSmrg break; 3213428d7b3dSmrg case 'h': 3214428d7b3dSmrg default: 3215428d7b3dSmrg usage(argv[0]); 3216428d7b3dSmrg exit(0); 3217428d7b3dSmrg } 3218428d7b3dSmrg } 3219428d7b3dSmrg 3220428d7b3dSmrg if (verbose) 3221428d7b3dSmrg printf("intel-virtual-output: version %d.%d.%d\n", 3222428d7b3dSmrg PACKAGE_VERSION_MAJOR, 3223428d7b3dSmrg PACKAGE_VERSION_MINOR, 3224428d7b3dSmrg PACKAGE_VERSION_PATCHLEVEL); 3225428d7b3dSmrg 3226428d7b3dSmrg ret = context_init(&ctx); 3227428d7b3dSmrg if (ret) 3228428d7b3dSmrg return -ret; 3229428d7b3dSmrg 3230428d7b3dSmrg XSetErrorHandler(_check_error_handler); 3231428d7b3dSmrg 3232428d7b3dSmrg ret = add_fd(&ctx, display_open(&ctx, src_name)); 3233428d7b3dSmrg if (ret) { 3234428d7b3dSmrg fprintf(stderr, "Unable to connect to \"%s\".\n", src_name ?: getenv("DISPLAY") ?: 3235428d7b3dSmrg "<unspecified>, set either the DISPLAY environment variable or pass -d <display name> on the commandline"); 3236428d7b3dSmrg ret = -ret; 3237428d7b3dSmrg goto out; 3238428d7b3dSmrg } 3239428d7b3dSmrg 3240428d7b3dSmrg if (singleton) { 3241428d7b3dSmrg XSelectInput(ctx.display->dpy, ctx.display->root, PropertyChangeMask); 3242428d7b3dSmrg if (first_display_has_singleton(&ctx)) { 3243428d7b3dSmrg DBG(X11, ("%s: pinging singleton\n", DisplayString(ctx.display->dpy))); 3244428d7b3dSmrg ret = first_display_send_command(&ctx, 2000, "P"); 3245428d7b3dSmrg if (ret) { 3246428d7b3dSmrg if (ret != -ETIME) { 3247428d7b3dSmrg ret = -ret; 3248428d7b3dSmrg goto out; 3249428d7b3dSmrg } 3250428d7b3dSmrg DBG(X11, ("No reply from singleton; assuming control\n")); 3251428d7b3dSmrg } else { 3252428d7b3dSmrg DBG(X11, ("%s: singleton active, sending open commands\n", DisplayString(ctx.display->dpy))); 3253428d7b3dSmrg 3254428d7b3dSmrg open = fail = 0; 3255428d7b3dSmrg for (i = optind; i < argc; i++) { 3256428d7b3dSmrg ret = first_display_send_command(&ctx, 5000, "C%s", argv[i]); 3257428d7b3dSmrg if (ret && ret != -EBUSY) { 3258428d7b3dSmrg fprintf(stderr, "Unable to connect to \"%s\".\n", argv[i]); 3259428d7b3dSmrg fail++; 3260428d7b3dSmrg } else 3261428d7b3dSmrg open++; 3262428d7b3dSmrg } 3263428d7b3dSmrg if (siblings || (optind == argc && !bumblebee)) { 3264428d7b3dSmrg first_display_for_each_sibling(&ctx, i) { 3265428d7b3dSmrg ret = first_display_send_command(&ctx, 5000, "C%s", ctx.command); 3266428d7b3dSmrg if (ret && ret != -EBUSY) 3267428d7b3dSmrg break; 3268428d7b3dSmrg else 3269428d7b3dSmrg open++; 3270428d7b3dSmrg } 3271428d7b3dSmrg } 3272428d7b3dSmrg if (bumblebee || (optind == argc && !siblings)) { 3273428d7b3dSmrg ret = first_display_send_command(&ctx, 5000, "B"); 3274428d7b3dSmrg if (ret && ret != -EBUSY) { 3275428d7b3dSmrg if (bumblebee) 3276428d7b3dSmrg fprintf(stderr, "Unable to connect to bumblebee.\n"); 3277428d7b3dSmrg fail++; 3278428d7b3dSmrg } else 3279428d7b3dSmrg open++; 3280428d7b3dSmrg } 3281428d7b3dSmrg ret = open || !fail ? 0 : ECONNREFUSED; 3282428d7b3dSmrg goto out; 3283428d7b3dSmrg } 3284428d7b3dSmrg } 3285428d7b3dSmrg ret = first_display_register_as_singleton(&ctx); 3286428d7b3dSmrg if (ret) 3287428d7b3dSmrg goto out; 3288428d7b3dSmrg } 3289428d7b3dSmrg 3290428d7b3dSmrg ret = display_init_damage(ctx.display); 3291428d7b3dSmrg if (ret) 3292428d7b3dSmrg goto out; 3293428d7b3dSmrg 3294428d7b3dSmrg if ((ctx.display->rr_event | ctx.display->rr_error) == 0) { 3295428d7b3dSmrg fprintf(stderr, "RandR extension not supported by %s\n", DisplayString(ctx.display->dpy)); 3296428d7b3dSmrg ret = EINVAL; 3297428d7b3dSmrg goto out; 3298428d7b3dSmrg } 3299428d7b3dSmrg XRRSelectInput(ctx.display->dpy, ctx.display->root, RRScreenChangeNotifyMask); 3300428d7b3dSmrg XFixesSelectCursorInput(ctx.display->dpy, ctx.display->root, XFixesDisplayCursorNotifyMask); 3301428d7b3dSmrg 3302428d7b3dSmrg ret = add_fd(&ctx, record_mouse(&ctx)); 3303428d7b3dSmrg if (ret) { 3304428d7b3dSmrg fprintf(stderr, "XTEST extension not supported by display \"%s\"\n", DisplayString(ctx.display->dpy)); 3305428d7b3dSmrg ret = -ret; 3306428d7b3dSmrg goto out; 3307428d7b3dSmrg } 3308428d7b3dSmrg 3309428d7b3dSmrg open = fail = 0; 3310428d7b3dSmrg for (i = optind; i < argc; i++) { 3311428d7b3dSmrg ret = last_display_clone(&ctx, display_open(&ctx, argv[i])); 3312428d7b3dSmrg if (ret && ret != -EBUSY) { 3313428d7b3dSmrg fprintf(stderr, "Unable to connect to \"%s\".\n", argv[i]); 3314428d7b3dSmrg fail++; 3315428d7b3dSmrg } else 3316428d7b3dSmrg open++; 3317428d7b3dSmrg } 3318428d7b3dSmrg if (siblings || (optind == argc && !bumblebee)) { 3319428d7b3dSmrg first_display_for_each_sibling(&ctx, i) { 3320428d7b3dSmrg ret = last_display_clone(&ctx, display_open(&ctx, ctx.command)); 3321428d7b3dSmrg if (ret && ret != -EBUSY) 3322428d7b3dSmrg break; 3323428d7b3dSmrg else 3324428d7b3dSmrg open++; 3325428d7b3dSmrg } 3326428d7b3dSmrg } 3327428d7b3dSmrg if (bumblebee || (optind == argc && !siblings)) { 3328428d7b3dSmrg ret = last_display_clone(&ctx, bumblebee_open(&ctx)); 3329428d7b3dSmrg if (ret && ret != -EBUSY) { 3330428d7b3dSmrg if (bumblebee) 3331428d7b3dSmrg fprintf(stderr, "Unable to connect to bumblebee.\n"); 3332428d7b3dSmrg fail++; 3333428d7b3dSmrg } else 3334428d7b3dSmrg open++; 3335428d7b3dSmrg } 3336428d7b3dSmrg if (open == 0) { 3337428d7b3dSmrg ret = fail ? ECONNREFUSED : 0; 3338428d7b3dSmrg goto out; 3339428d7b3dSmrg } 3340428d7b3dSmrg 3341428d7b3dSmrg if (daemonize && daemon(0, 0)) { 3342428d7b3dSmrg ret = EINVAL; 3343428d7b3dSmrg goto out; 3344428d7b3dSmrg } 3345428d7b3dSmrg 3346428d7b3dSmrg signal(SIGHUP, signal_handler); 3347428d7b3dSmrg signal(SIGINT, signal_handler); 3348428d7b3dSmrg signal(SIGTERM, signal_handler); 3349428d7b3dSmrg 3350428d7b3dSmrg ctx.command_continuation = 0; 3351428d7b3dSmrg while (!done) { 3352428d7b3dSmrg XEvent e; 3353428d7b3dSmrg int reconfigure = 0; 3354428d7b3dSmrg int rr_update = 0; 3355428d7b3dSmrg 3356428d7b3dSmrg DBG(POLL, ("polling - enable timer? %d, nfd=%d, ndisplay=%d\n", ctx.timer_active, ctx.nfd, ctx.ndisplay)); 3357428d7b3dSmrg ret = poll(ctx.pfd + !ctx.timer_active, ctx.nfd - !ctx.timer_active, -1); 3358428d7b3dSmrg if (ret <= 0) 3359428d7b3dSmrg break; 3360428d7b3dSmrg 3361428d7b3dSmrg /* pfd[0] is the timer, pfd[1] is the local display, pfd[2] is the mouse, pfd[3+] are the remotes */ 3362428d7b3dSmrg 3363428d7b3dSmrg DBG(POLL, ("poll reports %d fd awake\n", ret)); 3364428d7b3dSmrg if (ctx.pfd[1].revents || XPending(ctx.display[0].dpy)) { 3365428d7b3dSmrg DBG(POLL,("%s woken up\n", DisplayString(ctx.display[0].dpy))); 3366428d7b3dSmrg do { 3367428d7b3dSmrg XNextEvent(ctx.display->dpy, &e); 3368428d7b3dSmrg 3369428d7b3dSmrg if (e.type == ctx.display->damage_event + XDamageNotify ) { 3370428d7b3dSmrg const XDamageNotifyEvent *de = (const XDamageNotifyEvent *)&e; 3371428d7b3dSmrg struct clone *clone; 3372428d7b3dSmrg 3373428d7b3dSmrg DBG(DAMAGE, ("%s damaged: (%d, %d)x(%d, %d)\n", 3374428d7b3dSmrg DisplayString(ctx.display->dpy), 3375428d7b3dSmrg de->area.x, de->area.y, de->area.width, de->area.height)); 3376428d7b3dSmrg 3377428d7b3dSmrg for (clone = ctx.active; clone; clone = clone->active) 3378428d7b3dSmrg clone_damage(clone, &de->area); 3379428d7b3dSmrg 3380428d7b3dSmrg if (ctx.active) 3381428d7b3dSmrg context_enable_timer(&ctx); 3382428d7b3dSmrg } else if (e.type == ctx.display->xfixes_event + XFixesCursorNotify) { 3383428d7b3dSmrg XFixesCursorImage *cur; 3384428d7b3dSmrg 3385428d7b3dSmrg DBG(CURSOR, ("%s cursor changed\n", 3386428d7b3dSmrg DisplayString(ctx.display->dpy))); 3387428d7b3dSmrg 3388428d7b3dSmrg cur = XFixesGetCursorImage(ctx.display->dpy); 3389428d7b3dSmrg if (cur == NULL) 3390428d7b3dSmrg continue; 3391428d7b3dSmrg 3392428d7b3dSmrg for (i = 1; i < ctx.ndisplay; i++) 3393428d7b3dSmrg display_load_visible_cursor(&ctx.display[i], cur); 3394428d7b3dSmrg 3395428d7b3dSmrg XFree(cur); 3396428d7b3dSmrg } else if (e.type == ctx.display->rr_event + RRScreenChangeNotify) { 3397428d7b3dSmrg DBG(XRR, ("%s screen changed (reconfigure pending? %d)\n", 3398428d7b3dSmrg DisplayString(ctx.display->dpy), reconfigure)); 3399428d7b3dSmrg reconfigure = 1; 3400428d7b3dSmrg } else if (e.type == PropertyNotify) { 3401428d7b3dSmrg XPropertyEvent *pe = (XPropertyEvent *)&e; 3402428d7b3dSmrg if (pe->atom == ctx.singleton) { 3403428d7b3dSmrg DBG(X11, ("lost control of singleton\n")); 3404428d7b3dSmrg return 0; 3405428d7b3dSmrg } 3406428d7b3dSmrg } else if (e.type == ClientMessage) { 3407428d7b3dSmrg XClientMessageEvent *cme; 3408428d7b3dSmrg 3409428d7b3dSmrg DBG(X11, ("%s client message\n", 3410428d7b3dSmrg DisplayString(ctx.display->dpy))); 3411428d7b3dSmrg 3412428d7b3dSmrg cme = (XClientMessageEvent *)&e; 3413428d7b3dSmrg if (cme->message_type != ctx.singleton) 3414428d7b3dSmrg continue; 3415428d7b3dSmrg if (cme->format != 8) 3416428d7b3dSmrg continue; 3417428d7b3dSmrg 3418428d7b3dSmrg first_display_handle_command(&ctx, cme->data.b); 3419428d7b3dSmrg } else { 3420428d7b3dSmrg DBG(X11, ("unknown event %d\n", e.type)); 3421428d7b3dSmrg } 3422428d7b3dSmrg } while (XEventsQueued(ctx.display->dpy, QueuedAfterReading)); 3423428d7b3dSmrg } 3424428d7b3dSmrg 3425428d7b3dSmrg for (i = 1; i < ctx.ndisplay; i++) { 3426428d7b3dSmrg if (ctx.pfd[i+2].revents == 0 && !XPending(ctx.display[i].dpy)) 3427428d7b3dSmrg continue; 3428428d7b3dSmrg 3429428d7b3dSmrg DBG(POLL, ("%s woken up\n", DisplayString(ctx.display[i].dpy))); 3430428d7b3dSmrg do { 3431428d7b3dSmrg XNextEvent(ctx.display[i].dpy, &e); 3432428d7b3dSmrg 3433428d7b3dSmrg DBG(POLL, ("%s received event %d\n", DisplayString(ctx.display[i].dpy), e.type)); 3434428d7b3dSmrg if (ctx.display[i].rr_active && e.type == ctx.display[i].rr_event + RRNotify) { 3435428d7b3dSmrg XRRNotifyEvent *re = (XRRNotifyEvent *)&e; 3436428d7b3dSmrg 3437428d7b3dSmrg DBG(XRR, ("%s received RRNotify, type %d\n", DisplayString(ctx.display[i].dpy), re->subtype)); 3438428d7b3dSmrg if (re->subtype == RRNotify_OutputChange) { 3439428d7b3dSmrg XRROutputPropertyNotifyEvent *ro = (XRROutputPropertyNotifyEvent *)re; 3440428d7b3dSmrg struct clone *clone; 3441428d7b3dSmrg 3442428d7b3dSmrg DBG(XRR, ("%s RRNotify_OutputChange, timestamp %ld\n", DisplayString(ctx.display[i].dpy), ro->timestamp)); 3443428d7b3dSmrg for (clone = ctx.display[i].clone; clone; clone = clone->next) { 3444428d7b3dSmrg if (clone->dst.rr_output == ro->output) 3445428d7b3dSmrg rr_update = clone->rr_update = 1; 3446428d7b3dSmrg } 3447428d7b3dSmrg } 3448428d7b3dSmrg } 3449428d7b3dSmrg } while (XEventsQueued(ctx.display[i].dpy, QueuedAfterReading)); 3450428d7b3dSmrg } 3451428d7b3dSmrg 3452428d7b3dSmrg if (rr_update) { 3453428d7b3dSmrg for (i = 0; i < ctx.nclone; i++) 3454428d7b3dSmrg clone_update(&ctx.clones[i]); 3455428d7b3dSmrg } 3456428d7b3dSmrg 3457428d7b3dSmrg if (reconfigure && context_update(&ctx)) 3458428d7b3dSmrg display_reset_damage(ctx.display); 3459428d7b3dSmrg 3460428d7b3dSmrg while (XPending(ctx.record)) /* discard all implicit events */ 3461428d7b3dSmrg XNextEvent(ctx.record, &e); 3462428d7b3dSmrg 3463428d7b3dSmrg if (ctx.timer_active && read(ctx.timer, &count, sizeof(count)) > 0) { 3464428d7b3dSmrg struct clone *clone; 3465428d7b3dSmrg 3466428d7b3dSmrg DBG(TIMER, ("%s timer expired (count=%ld)\n", DisplayString(ctx.display->dpy), (long)count)); 3467428d7b3dSmrg ret = 0; 3468428d7b3dSmrg 3469428d7b3dSmrg if (ctx.active) { 3470428d7b3dSmrg DBG(DAMAGE, ("%s clearing damage\n", DisplayString(ctx.display->dpy))); 3471428d7b3dSmrg XDamageSubtract(ctx.display->dpy, ctx.display->damage, None, None); 3472428d7b3dSmrg ctx.display->flush = 1; 3473428d7b3dSmrg } 3474428d7b3dSmrg 3475428d7b3dSmrg for (clone = ctx.active; clone; clone = clone->active) 3476428d7b3dSmrg ret |= clone_paint(clone); 3477428d7b3dSmrg 3478428d7b3dSmrg for (i = 0; i < ctx.ndisplay; i++) 3479428d7b3dSmrg display_flush(&ctx.display[i]); 3480428d7b3dSmrg 3481428d7b3dSmrg DBG(TIMER, ("%s timer still active? %d\n", DisplayString(ctx.display->dpy), ret != 0)); 3482428d7b3dSmrg ctx.timer_active = ret != 0; 3483428d7b3dSmrg } 3484428d7b3dSmrg } 3485428d7b3dSmrg 3486428d7b3dSmrg ret = 0; 3487428d7b3dSmrgout: 3488428d7b3dSmrg context_cleanup(&ctx); 3489428d7b3dSmrg return ret; 3490428d7b3dSmrg} 3491