1/* 2 * Copyright © 2013 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 * 23 */ 24 25#ifdef HAVE_CONFIG_H 26#include "config.h" 27#endif 28 29#include <X11/Xlib.h> 30#include <X11/Xatom.h> 31 32#include <X11/Xlibint.h> 33#include <X11/extensions/record.h> 34#include <X11/extensions/XShm.h> 35#if HAVE_X11_EXTENSIONS_SHMPROTO_H 36#include <X11/extensions/shmproto.h> 37#elif HAVE_X11_EXTENSIONS_SHMSTR_H 38#include <X11/extensions/shmstr.h> 39#else 40#error Failed to find the right header for X11 MIT-SHM protocol definitions 41#endif 42#include <X11/extensions/Xdamage.h> 43#if HAVE_X11_EXTENSIONS_XINERAMA_H 44#include <X11/extensions/Xinerama.h> 45#define USE_XINERAMA 46#endif 47#include <X11/extensions/Xrandr.h> 48#include <X11/extensions/Xrender.h> 49#include <X11/Xcursor/Xcursor.h> 50#include <pixman.h> 51 52#include <sys/types.h> 53#include <sys/ipc.h> 54#include <sys/shm.h> 55#include <sys/timerfd.h> 56#include <sys/poll.h> 57#include <sys/socket.h> 58#include <sys/un.h> 59 60#include <stdarg.h> 61#include <stdio.h> 62#include <stdlib.h> 63#include <stdint.h> 64#include <signal.h> 65#include <getopt.h> 66#include <limits.h> 67#include <unistd.h> 68#include <fcntl.h> 69#include <assert.h> 70 71#define FORCE_FULL_REDRAW 0 72#define FORCE_16BIT_XFER 0 73 74#define DBG(v, x) if (verbose & v) printf x 75static int verbose; 76#define X11 0x1 77#define XRR 0x1 78#define TIMER 0x4 79#define DRAW 0x8 80#define DAMAGE 0x10 81#define CURSOR 0x20 82#define POLL 0x40 83 84struct display { 85 Display *dpy; 86 struct clone *clone; 87 struct context *ctx; 88 89 int damage_event, damage_error; 90 int xfixes_event, xfixes_error; 91 int rr_event, rr_error, rr_active; 92 int xinerama_event, xinerama_error, xinerama_active; 93 int dri3_active; 94 Window root; 95 Visual *visual; 96 Damage damage; 97 98 int width; 99 int height; 100 int depth; 101 102 XRenderPictFormat *root_format; 103 XRenderPictFormat *rgb16_format; 104 XRenderPictFormat *rgb24_format; 105 106 int has_shm; 107 int has_shm_pixmap; 108 int shm_opcode; 109 int shm_event; 110 111 Cursor invisible_cursor; 112 Cursor visible_cursor; 113 114 XcursorImage cursor_image; 115 int cursor_serial; 116 int cursor_x; 117 int cursor_y; 118 int cursor_moved; 119 int cursor_visible; 120 int cursor; 121 122 int flush; 123 int send; 124 int skip_clone; 125 int skip_frame; 126}; 127 128struct output { 129 struct display *display; 130 Display *dpy; 131 char *name; 132 RROutput rr_output; 133 RRCrtc rr_crtc; 134 Window window; 135 Picture win_picture; 136 Picture pix_picture; 137 Pixmap pixmap; 138 GC gc; 139 140 long serial; 141 int use_shm; 142 int use_shm_pixmap; 143 XShmSegmentInfo shm; 144 145 XRenderPictFormat *use_render; 146 147 int x, y; 148 XRRModeInfo mode; 149 Rotation rotation; 150}; 151 152struct clone { 153 struct clone *next; 154 struct clone *active; 155 156 struct output src, dst; 157 long timestamp; 158 159 XShmSegmentInfo shm; 160 XImage image; 161 162 int width, height, depth; 163 struct { int x1, x2, y1, y2; } damaged; 164 int rr_update; 165 166 struct dri3_fence { 167 XID xid; 168 void *addr; 169 } dri3; 170}; 171 172struct context { 173 struct display *display; 174 struct clone *clones; 175 struct clone *active; 176 struct pollfd *pfd; 177#define timer pfd[0].fd 178 Display *record; 179 int nclone; 180 int ndisplay; 181 int nfd; 182 183 int timer_active; 184 185 long timestamp; 186 long configTimestamp; 187 188 Atom singleton; 189 char command[1024]; 190 int command_continuation; 191}; 192 193static inline int is_power_of_2(unsigned long n) 194{ 195 return n && ((n & (n - 1)) == 0); 196} 197 198static int xlib_vendor_is_xorg(Display *dpy) 199{ 200 const char *const vendor = ServerVendor(dpy); 201 return strstr(vendor, "X.Org") || strstr(vendor, "Xorg"); 202} 203 204static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window) 205{ 206 XRRScreenResources *res; 207 208 res = XRRGetScreenResourcesCurrent(dpy, window); 209 if (res == NULL) 210 res = XRRGetScreenResources(dpy, window); 211 212 return res; 213} 214 215#define XORG_VERSION_ENCODE(major,minor,patch,snap) \ 216 (((major) * 10000000) + ((minor) * 100000) + ((patch) * 1000) + snap) 217 218static int _x_error_occurred; 219 220static int 221_check_error_handler(Display *display, 222 XErrorEvent *event) 223{ 224 DBG(X11, ("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n", 225 DisplayString(display), 226 event->serial, 227 event->error_code, 228 event->request_code, 229 event->minor_code)); 230 _x_error_occurred = 1; 231 return False; /* ignored */ 232} 233 234static int 235can_use_shm(Display *dpy, 236 Window window, 237 int *shm_event, 238 int *shm_opcode, 239 int *shm_pixmap) 240{ 241 XShmSegmentInfo shm; 242 Status success; 243 XExtCodes *codes; 244 int major, minor, has_shm, has_pixmap; 245 246 if (!XShmQueryExtension(dpy)) 247 return 0; 248 249 XShmQueryVersion(dpy, &major, &minor, &has_pixmap); 250 251 shm.shmid = shmget(IPC_PRIVATE, 0x1000, IPC_CREAT | 0600); 252 if (shm.shmid == -1) 253 return 0; 254 255 shm.readOnly = 0; 256 shm.shmaddr = shmat(shm.shmid, NULL, 0); 257 if (shm.shmaddr == (char *) -1) { 258 shmctl(shm.shmid, IPC_RMID, NULL); 259 return 0; 260 } 261 262 XSync(dpy, False); 263 _x_error_occurred = 0; 264 265 success = XShmAttach(dpy, &shm); 266 267 XSync(dpy, False); 268 has_shm = success && _x_error_occurred == 0; 269 270 /* As libXext sets the SEND_EVENT bit in the ShmCompletionEvent, 271 * the Xserver may crash if it does not take care when processing 272 * the event type. For instance versions of Xorg prior to 1.11.1 273 * exhibited this bug, and was fixed by: 274 * 275 * commit 2d2dce558d24eeea0eb011ec9ebaa6c5c2273c39 276 * Author: Sam Spilsbury <sam.spilsbury@canonical.com> 277 * Date: Wed Sep 14 09:58:34 2011 +0800 278 * 279 * Remove the SendEvent bit (0x80) before doing range checks on event type. 280 */ 281 codes = 0; 282 if (has_shm) 283 codes = XInitExtension(dpy, SHMNAME); 284 if (xlib_vendor_is_xorg(dpy) && 285 VendorRelease(dpy) < XORG_VERSION_ENCODE(1,11,0,1)) 286 codes = 0; 287 if (codes) { 288 XShmCompletionEvent e; 289 290 memset(&e, 0, sizeof(e)); 291 292 e.type = codes->first_event; 293 e.send_event = 1; 294 e.serial = 1; 295 e.drawable = window; 296 e.major_code = codes->major_opcode; 297 e.minor_code = X_ShmPutImage; 298 299 e.shmseg = shm.shmid; 300 e.offset = 0; 301 302 XSendEvent(dpy, e.drawable, False, 0, (XEvent *)&e); 303 XSync(dpy, False); 304 305 if (_x_error_occurred == 0) { 306 *shm_opcode = codes->major_opcode; 307 *shm_event = codes->first_event; 308 *shm_pixmap = has_pixmap; 309 } 310 } 311 312 XShmDetach(dpy, &shm); 313 shmctl(shm.shmid, IPC_RMID, NULL); 314 shmdt(shm.shmaddr); 315 316 return has_shm; 317} 318 319#ifdef DRI3 320#include <X11/Xlib-xcb.h> 321#include <X11/xshmfence.h> 322#include <xcb/xcb.h> 323#include <xcb/dri3.h> 324#include <xcb/sync.h> 325static Pixmap dri3_create_pixmap(Display *dpy, 326 Drawable draw, 327 int width, int height, int depth, 328 int fd, int bpp, int stride, int size) 329{ 330 xcb_connection_t *c = XGetXCBConnection(dpy); 331 xcb_pixmap_t pixmap = xcb_generate_id(c); 332 xcb_dri3_pixmap_from_buffer(c, pixmap, draw, size, width, height, stride, depth, bpp, fd); 333 return pixmap; 334} 335 336static int dri3_create_fd(Display *dpy, 337 Pixmap pixmap, 338 int *stride) 339{ 340 xcb_connection_t *c = XGetXCBConnection(dpy); 341 xcb_dri3_buffer_from_pixmap_cookie_t cookie; 342 xcb_dri3_buffer_from_pixmap_reply_t *reply; 343 344 cookie = xcb_dri3_buffer_from_pixmap(c, pixmap); 345 reply = xcb_dri3_buffer_from_pixmap_reply(c, cookie, NULL); 346 if (!reply) 347 return -1; 348 349 if (reply->nfd != 1) 350 return -1; 351 352 *stride = reply->stride; 353 return xcb_dri3_buffer_from_pixmap_reply_fds(c, reply)[0]; 354} 355 356static int dri3_query_version(Display *dpy, int *major, int *minor) 357{ 358 xcb_connection_t *c = XGetXCBConnection(dpy); 359 xcb_dri3_query_version_reply_t *reply; 360 361 *major = *minor = -1; 362 363 reply = xcb_dri3_query_version_reply(c, 364 xcb_dri3_query_version(c, 365 XCB_DRI3_MAJOR_VERSION, 366 XCB_DRI3_MINOR_VERSION), 367 NULL); 368 if (reply == NULL) 369 return -1; 370 371 *major = reply->major_version; 372 *minor = reply->minor_version; 373 free(reply); 374 375 return 0; 376} 377 378static int dri3_exists(Display *dpy) 379{ 380 int major, minor; 381 382 if (dri3_query_version(dpy, &major, &minor) < 0) 383 return 0; 384 385 return major >= 0; 386} 387 388static void dri3_create_fence(Display *dpy, Drawable d, struct dri3_fence *fence) 389{ 390 xcb_connection_t *c = XGetXCBConnection(dpy); 391 struct dri3_fence f; 392 int fd; 393 394 fd = xshmfence_alloc_shm(); 395 if (fd < 0) 396 return; 397 398 f.addr = xshmfence_map_shm(fd); 399 if (f.addr == NULL) { 400 close(fd); 401 return; 402 } 403 404 f.xid = xcb_generate_id(c); 405 xcb_dri3_fence_from_fd(c, d, f.xid, 0, fd); 406 407 *fence = f; 408} 409 410static void dri3_fence_flush(Display *dpy, struct dri3_fence *fence) 411{ 412 xcb_sync_trigger_fence(XGetXCBConnection(dpy), fence->xid); 413} 414 415static void dri3_fence_free(Display *dpy, struct dri3_fence *fence) 416{ 417 xshmfence_unmap_shm(fence->addr); 418 xcb_sync_destroy_fence(XGetXCBConnection(dpy), fence->xid); 419} 420 421#else 422 423static int dri3_exists(Display *dpy) 424{ 425 return 0; 426} 427 428static void dri3_create_fence(Display *dpy, Drawable d, struct dri3_fence *fence) 429{ 430} 431 432static void dri3_fence_flush(Display *dpy, struct dri3_fence *fence) 433{ 434} 435 436static void dri3_fence_free(Display *dpy, struct dri3_fence *fence) 437{ 438} 439 440static Pixmap dri3_create_pixmap(Display *dpy, 441 Drawable draw, 442 int width, int height, int depth, 443 int fd, int bpp, int stride, int size) 444{ 445 return None; 446} 447 448static int dri3_create_fd(Display *dpy, 449 Pixmap pixmap, 450 int *stride) 451{ 452 return -1; 453} 454#endif 455 456static int timerfd(int hz) 457{ 458 struct itimerspec it; 459 int fd; 460 461 fd = -1; 462#ifdef CLOCK_MONOTONIC_COARSE 463 fd = timerfd_create(CLOCK_MONOTONIC_COARSE, TFD_NONBLOCK); 464#endif 465 if (fd < 0) 466 fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); 467 if (fd < 0) 468 return -ETIME; 469 470 it.it_interval.tv_sec = 0; 471 it.it_interval.tv_nsec = 1000000000 / hz; 472 it.it_value = it.it_interval; 473 if (timerfd_settime(fd, 0, &it, NULL) < 0) { 474 close(fd); 475 return -ETIME; 476 } 477 478 return fd; 479} 480 481static int context_init(struct context *ctx) 482{ 483 struct pollfd *pfd; 484 485 memset(ctx, 0, sizeof(*ctx)); 486 487 ctx->pfd = malloc(2*sizeof(struct pollfd)); 488 if (ctx->pfd == NULL) 489 return -ENOMEM; 490 491 ctx->clones = malloc(sizeof(struct clone)); 492 if (ctx->clones == NULL) 493 return -ENOMEM; 494 495 ctx->display = malloc(sizeof(struct display)); 496 if (ctx->display == NULL) 497 return -ENOMEM; 498 499 pfd = memset(&ctx->pfd[ctx->nfd++], 0, sizeof(struct pollfd)); 500 pfd->fd = timerfd(60); 501 if (pfd->fd < 0) 502 return pfd->fd; 503 pfd->events = POLLIN; 504 505 return 0; 506} 507 508static void context_enable_timer(struct context *ctx) 509{ 510 uint64_t count; 511 512 DBG(TIMER, ("%s timer active? %d\n", __func__, ctx->timer_active)); 513 514 if (ctx->timer_active) 515 return; 516 517 /* reset timer */ 518 count = read(ctx->timer, &count, sizeof(count)); 519 520 ctx->timer_active = 1; 521} 522 523static int add_fd(struct context *ctx, int fd) 524{ 525 struct pollfd *pfd; 526 527 if (fd < 0) 528 return fd; 529 530 if (is_power_of_2(ctx->nfd)) { 531 ctx->pfd = realloc(ctx->pfd, 2*ctx->nfd*sizeof(struct pollfd)); 532 if (ctx->pfd == NULL) 533 return -ENOMEM; 534 } 535 536 pfd = memset(&ctx->pfd[ctx->nfd++], 0, sizeof(struct pollfd)); 537 pfd->fd = fd; 538 pfd->events = POLLIN; 539 return 0; 540} 541 542static void display_mark_flush(struct display *display) 543{ 544 DBG(DRAW, ("%s mark flush (flush=%d)\n", 545 DisplayString(display->dpy), display->flush)); 546 547 if (display->flush) 548 return; 549 550 context_enable_timer(display->ctx); 551 display->flush = 1; 552} 553 554static int mode_equal(const XRRModeInfo *a, const XRRModeInfo *b) 555{ 556 return (a->width == b->width && 557 a->height == b->height && 558 a->dotClock == b->dotClock && 559 a->hSyncStart == b->hSyncStart && 560 a->hSyncEnd == b->hSyncEnd && 561 a->hTotal == b->hTotal && 562 a->hSkew == b->hSkew && 563 a->vSyncStart == b->vSyncStart && 564 a->vSyncEnd == b->vSyncEnd && 565 a->vTotal == b->vTotal && 566 a->modeFlags == b->modeFlags); 567} 568 569static XRRModeInfo *lookup_mode(XRRScreenResources *res, int id) 570{ 571 int i; 572 573 for (i = 0; i < res->nmode; i++) { 574 if (res->modes[i].id == id) 575 return &res->modes[i]; 576 } 577 578 return NULL; 579} 580 581static void clone_update_edid(struct clone *clone) 582{ 583 unsigned long nitems, after; 584 unsigned char *data; 585 int format; 586 Atom type; 587 588 if (XRRGetOutputProperty(clone->dst.dpy, clone->dst.rr_output, 589 XInternAtom(clone->dst.dpy, "EDID", False), 590 0, 100, False, False, AnyPropertyType, 591 &type, &format, &nitems, &after, &data) == Success) { 592 XRRChangeOutputProperty(clone->src.dpy, clone->src.rr_output, 593 XInternAtom(clone->src.dpy, "EDID", False), 594 type, format, PropModeReplace, data, nitems); 595 } 596} 597 598static int disable_crtc(Display *dpy, XRRScreenResources *res, RRCrtc crtc) 599{ 600 XRRPanning panning; 601 602 if (crtc) { 603 XRRSetPanning(dpy, res, crtc, memset(&panning, 0, sizeof(panning))); 604 605 if (XRRSetCrtcConfig(dpy, res, crtc, CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0) != Success) 606 return 0; 607 608 if (XRRSetPanning(dpy, res, crtc, memset(&panning, 0, sizeof(panning))) != Success) { 609 DBG(XRR, ("%s failed to clear panning on CRTC:%ld\n", DisplayString(dpy), (long)crtc)); 610 if (verbose) { 611 XRRCrtcInfo *c; 612 XRRPanning *p; 613 614 c = XRRGetCrtcInfo(dpy, res, crtc); 615 if (c) { 616 DBG(XRR, ("%s CRTC:%ld x=%d, y=%d, rotation=%d, mode=%ld\n", 617 DisplayString(dpy), (long)crtc, 618 c->x, c->y, c->rotation, c->mode)); 619 XRRFreeCrtcInfo(c); 620 } 621 622 p = XRRGetPanning(dpy, res, crtc); 623 if (p) { 624 DBG(XRR, ("%s CRTC:%ld panning (%d, %d)x(%d, %d), tracking (%d, %d)x(%d, %d), border (%d, %d),(%d, %d)\n", 625 DisplayString(dpy), (long)crtc, 626 p->left, p->top, p->width, p->height, 627 p->track_left, p->track_top, p->track_width, p->track_height, 628 p->border_left, p->border_top, p->border_right, p->border_bottom)); 629 XRRFreePanning(p); 630 } 631 } 632 } 633 } 634 635 return 1; 636} 637 638static int clone_update_modes__randr(struct clone *clone) 639{ 640 XRRScreenResources *from_res = NULL, *to_res = NULL; 641 XRROutputInfo *from_info = NULL, *to_info = NULL; 642 int i, j, ret = ENOENT; 643 644 assert(clone->src.rr_output); 645 assert(clone->dst.rr_output); 646 assert(clone->dst.display->rr_event); 647 648 from_res = _XRRGetScreenResourcesCurrent(clone->dst.dpy, clone->dst.window); 649 if (from_res == NULL) 650 goto err; 651 652 from_info = XRRGetOutputInfo(clone->dst.dpy, from_res, clone->dst.rr_output); 653 if (from_info == NULL) 654 goto err; 655 656 DBG(XRR, ("%s(%s-%s <- %s-%s): timestamp %ld (last %ld)\n", __func__, 657 DisplayString(clone->src.dpy), clone->src.name, 658 DisplayString(clone->dst.dpy), clone->dst.name, 659 from_info->timestamp, clone->timestamp)); 660 661 to_res = _XRRGetScreenResourcesCurrent(clone->src.dpy, clone->src.window); 662 if (to_res == NULL) 663 goto err; 664 665 to_info = XRRGetOutputInfo(clone->src.dpy, to_res, clone->src.rr_output); 666 if (to_info == NULL) 667 goto err; 668 669 DBG(XRR, ("%s: dst.rr_crtc=%ld, now %ld\n", 670 __func__, (long)clone->dst.rr_crtc, (long)from_info->crtc)); 671 if (clone->dst.rr_crtc == from_info->crtc) { 672 for (i = 0; i < to_info->nmode; i++) { 673 XRRModeInfo *mode, *old; 674 675 mode = lookup_mode(to_res, to_info->modes[i]); 676 if (mode == NULL) 677 break; 678 679 DBG(XRR, ("%s(%s-%s): lookup mode %s\n", __func__, 680 DisplayString(clone->src.dpy), clone->src.name, 681 mode->name)); 682 683 for (j = 0; j < from_info->nmode; j++) { 684 old = lookup_mode(from_res, from_info->modes[j]); 685 if (old && mode_equal(mode, old)) { 686 mode = NULL; 687 break; 688 } 689 } 690 if (mode) { 691 DBG(XRR, ("%s(%s-%s): unknown mode %s\n", __func__, 692 DisplayString(clone->src.dpy), clone->src.name, 693 mode->name)); 694 break; 695 } 696 } 697 if (i == from_info->nmode && i == to_info->nmode) { 698 DBG(XRR, ("%s(%s-%s): no change in output\n", __func__, 699 DisplayString(clone->src.dpy), clone->src.name)); 700 goto done; 701 } 702 } 703 704 /* Disable the remote output */ 705 if (from_info->crtc != clone->dst.rr_crtc) { 706 DBG(XRR, ("%s(%s-%s): disabling active CRTC\n", __func__, 707 DisplayString(clone->dst.dpy), clone->dst.name)); 708 if (disable_crtc(clone->dst.dpy, from_res, from_info->crtc)) { 709 clone->dst.rr_crtc = 0; 710 clone->dst.mode.id = 0; 711 } else { 712 XRRCrtcInfo *c = XRRGetCrtcInfo(clone->dst.dpy, from_res, from_info->crtc); 713 if (c) { 714 clone->dst.x = c->x; 715 clone->dst.y = c->y; 716 clone->dst.rotation = c->rotation; 717 clone->dst.mode.id = c->mode; 718 XRRFreeCrtcInfo(c); 719 } 720 } 721 } 722 723 /* Create matching modes for the real output on the virtual */ 724 XGrabServer(clone->src.dpy); 725 726 /* Clear all current UserModes on the output, including any active ones */ 727 if (to_info->crtc) { 728 DBG(XRR, ("%s(%s-%s): disabling active CRTC\n", __func__, 729 DisplayString(clone->src.dpy), clone->src.name)); 730 disable_crtc(clone->src.dpy, to_res, to_info->crtc); 731 } 732 for (i = 0; i < to_info->nmode; i++) { 733 DBG(XRR, ("%s(%s-%s): deleting mode %ld\n", __func__, 734 DisplayString(clone->src.dpy), clone->src.name, (long)to_info->modes[i])); 735 XRRDeleteOutputMode(clone->src.dpy, clone->src.rr_output, to_info->modes[i]); 736 } 737 738 clone->src.rr_crtc = 0; 739 740 for (i = 0; i < from_info->nmode; i++) { 741 XRRModeInfo *mode, *old; 742 RRMode id; 743 744 mode = lookup_mode(from_res, from_info->modes[i]); 745 if (mode == NULL) 746 continue; 747 for (j = 0; j < i; j++) { 748 old = lookup_mode(from_res, from_info->modes[j]); 749 if (old && mode_equal(mode, old)) { 750 mode = NULL; 751 break; 752 } 753 } 754 if (mode == NULL) 755 continue; 756 757 id = 0; 758 for (j = 0; j < to_res->nmode; j++) { 759 old = &to_res->modes[j]; 760 if (mode_equal(mode, old)) { 761 id = old->id; 762 DBG(XRR, ("%s(%s-%s): reusing mode %ld: %s\n", __func__, 763 DisplayString(clone->src.dpy), clone->src.name, id, mode->name)); 764 break; 765 } 766 } 767 if (id == 0) { 768 XRRModeInfo m; 769 char buf[256]; 770 771 /* XXX User names must be unique! */ 772 m = *mode; 773 m.nameLength = snprintf(buf, sizeof(buf), 774 "%s.%ld-%s", clone->src.name, (long)from_info->modes[i], mode->name); 775 m.name = buf; 776 777 id = XRRCreateMode(clone->src.dpy, clone->src.window, &m); 778 DBG(XRR, ("%s(%s-%s): adding mode %ld: %s\n", __func__, 779 DisplayString(clone->src.dpy), clone->src.name, id, mode->name)); 780 } 781 782 XRRAddOutputMode(clone->src.dpy, clone->src.rr_output, id); 783 } 784 clone_update_edid(clone); 785 XUngrabServer(clone->src.dpy); 786done: 787 ret = 0; 788 clone->timestamp = from_info->timestamp; 789 790err: 791 if (to_info) 792 XRRFreeOutputInfo(to_info); 793 if (to_res) 794 XRRFreeScreenResources(to_res); 795 if (from_info) 796 XRRFreeOutputInfo(from_info); 797 if (from_res) 798 XRRFreeScreenResources(from_res); 799 800 return ret; 801} 802 803static int clone_update_modes__fixed(struct clone *clone) 804{ 805 char mode_name[80]; 806 XRRScreenResources *res = NULL; 807 XRROutputInfo *info = NULL; 808 XRRModeInfo mode; 809 RRMode id; 810 int i, j, ret = ENOENT; 811 812 assert(clone->src.rr_output); 813 814 res = _XRRGetScreenResourcesCurrent(clone->src.dpy, clone->src.window); 815 if (res == NULL) 816 goto err; 817 818 info = XRRGetOutputInfo(clone->src.dpy, res, clone->src.rr_output); 819 if (info == NULL) 820 goto err; 821 822 XGrabServer(clone->src.dpy); 823 824 /* Clear all current UserModes on the output, including any active ones */ 825 if (info->crtc) { 826 DBG(XRR, ("%s(%s-%s): disabling active CRTC\n", __func__, 827 DisplayString(clone->src.dpy), clone->src.name)); 828 disable_crtc(clone->src.dpy, res, info->crtc); 829 } 830 for (i = 0; i < info->nmode; i++) { 831 DBG(XRR, ("%s(%s-%s): deleting mode %ld\n", __func__, 832 DisplayString(clone->src.dpy), clone->src.name, (long)info->modes[i])); 833 XRRDeleteOutputMode(clone->src.dpy, clone->src.rr_output, info->modes[i]); 834 } 835 836 clone->src.rr_crtc = 0; 837 838 /* Create matching mode for the real output on the virtual */ 839 memset(&mode, 0, sizeof(mode)); 840 mode.width = clone->width; 841 mode.height = clone->height; 842 mode.nameLength = sprintf(mode_name, "FAKE-%dx%d", mode.width, mode.height); 843 mode.name = mode_name; 844 845 id = 0; 846 for (j = 0; j < res->nmode; j++) { 847 if (mode_equal(&mode, &res->modes[j])) { 848 id = res->modes[j].id; 849 break; 850 } 851 } 852 if (id == 0) 853 id = XRRCreateMode(clone->src.dpy, clone->src.window, &mode); 854 855 XRRAddOutputMode(clone->src.dpy, clone->src.rr_output, id); 856 857 XUngrabServer(clone->src.dpy); 858 ret = 0; 859err: 860 if (info) 861 XRRFreeOutputInfo(info); 862 if (res) 863 XRRFreeScreenResources(res); 864 865 return ret; 866} 867 868static RROutput claim_virtual(struct display *display, char *output_name, int nclone) 869{ 870 char mode_name[] = "ClaimVirtualHead"; 871 Display *dpy = display->dpy; 872 XRRScreenResources *res; 873 XRROutputInfo *output; 874 XRRModeInfo mode; 875 RRMode id; 876 RROutput rr_output = 0; 877 int i; 878 879 DBG(X11, ("%s(%d)\n", __func__, nclone)); 880 XGrabServer(dpy); 881 882 res = _XRRGetScreenResourcesCurrent(dpy, display->root); 883 if (res == NULL) 884 goto out; 885 886 sprintf(output_name, "VIRTUAL%d", nclone); 887 888 for (i = rr_output = 0; rr_output == 0 && i < res->noutput; i++) { 889 output = XRRGetOutputInfo(dpy, res, res->outputs[i]); 890 if (output == NULL) 891 continue; 892 893 if (strcmp(output->name, output_name) == 0) 894 rr_output = res->outputs[i]; 895 896 XRRFreeOutputInfo(output); 897 } 898 for (i = id = 0; id == 0 && i < res->nmode; i++) { 899 if (strcmp(res->modes[i].name, mode_name) == 0) 900 id = res->modes[i].id; 901 } 902 XRRFreeScreenResources(res); 903 904 DBG(XRR, ("%s(%s): rr_output=%ld\n", __func__, output_name, (long)rr_output)); 905 if (rr_output == 0) 906 goto out; 907 908 /* Set any mode on the VirtualHead to make the Xserver allocate another */ 909 memset(&mode, 0, sizeof(mode)); 910 mode.width = 1024; 911 mode.height = 768; 912 mode.name = mode_name; 913 mode.nameLength = sizeof(mode_name) - 1; 914 915 if (id == 0) 916 id = XRRCreateMode(dpy, display->root, &mode); 917 XRRAddOutputMode(dpy, rr_output, id); 918 919 /* Force a redetection for the ddx to spot the new outputs */ 920 res = XRRGetScreenResources(dpy, display->root); 921 if (res == NULL) 922 goto out; 923 924 /* Some else may have interrupted us and installed that new mode! */ 925 output = XRRGetOutputInfo(dpy, res, rr_output); 926 if (output) { 927 disable_crtc(dpy, res, output->crtc); 928 XRRFreeOutputInfo(output); 929 } 930 XRRFreeScreenResources(res); 931 932 XRRDeleteOutputMode(dpy, rr_output, id); 933 XRRDestroyMode(dpy, id); 934 935 /* And hide it again */ 936 res = XRRGetScreenResources(dpy, display->root); 937 if (res != NULL) 938 XRRFreeScreenResources(res); 939out: 940 XUngrabServer(dpy); 941 942 return rr_output; 943} 944 945static int stride_for_depth(int width, int depth) 946{ 947 if (depth == 24) 948 depth = 32; 949 return ((width * depth + 7) / 8 + 3) & ~3; 950} 951 952static void init_image(struct clone *clone) 953{ 954 XImage *image = &clone->image; 955 int ret; 956 957 image->width = clone->width; 958 image->height = clone->height; 959 image->format = ZPixmap; 960 image->xoffset = 0; 961 image->byte_order = LSBFirst; 962 image->bitmap_unit = 32; 963 image->bitmap_bit_order = LSBFirst; 964 image->bitmap_pad = 32; 965 image->data = clone->shm.shmaddr; 966 image->bytes_per_line = stride_for_depth(clone->width, clone->depth); 967 switch (clone->depth) { 968 case 24: 969 image->red_mask = 0xff << 16; 970 image->green_mask = 0xff << 8; 971 image->blue_mask = 0xff << 0;; 972 image->depth = 24; 973 image->bits_per_pixel = 32; 974 break; 975 case 16: 976 image->red_mask = 0x1f << 11; 977 image->green_mask = 0x3f << 5; 978 image->blue_mask = 0x1f << 0;; 979 image->depth = 16; 980 image->bits_per_pixel = 16; 981 break; 982 } 983 984 ret = XInitImage(image); 985 assert(ret); 986 (void)ret; 987} 988 989static int mode_height(const XRRModeInfo *mode, Rotation rotation) 990{ 991 switch (rotation & 0xf) { 992 case RR_Rotate_0: 993 case RR_Rotate_180: 994 return mode->height; 995 case RR_Rotate_90: 996 case RR_Rotate_270: 997 return mode->width; 998 default: 999 return 0; 1000 } 1001} 1002 1003static int mode_width(const XRRModeInfo *mode, Rotation rotation) 1004{ 1005 switch (rotation & 0xf) { 1006 case RR_Rotate_0: 1007 case RR_Rotate_180: 1008 return mode->width; 1009 case RR_Rotate_90: 1010 case RR_Rotate_270: 1011 return mode->height; 1012 default: 1013 return 0; 1014 } 1015} 1016 1017static void output_init_xfer(struct clone *clone, struct output *output) 1018{ 1019 if (output->pixmap == None && output->use_shm_pixmap) { 1020 DBG(DRAW, ("%s-%s: creating shm pixmap\n", DisplayString(output->dpy), output->name)); 1021 XSync(output->dpy, False); 1022 _x_error_occurred = 0; 1023 1024 output->pixmap = XShmCreatePixmap(output->dpy, output->window, 1025 clone->shm.shmaddr, &output->shm, 1026 clone->width, clone->height, clone->depth); 1027 if (output->pix_picture) { 1028 XRenderFreePicture(output->dpy, output->pix_picture); 1029 output->pix_picture = None; 1030 } 1031 1032 XSync(output->dpy, False); 1033 if (_x_error_occurred) { 1034 XFreePixmap(output->dpy, output->pixmap); 1035 output->pixmap = None; 1036 output->use_shm_pixmap = 0; 1037 } 1038 } 1039 if (output->use_render) { 1040 DBG(DRAW, ("%s-%s: creating picture\n", DisplayString(output->dpy), output->name)); 1041 if (output->win_picture == None) 1042 output->win_picture = XRenderCreatePicture(output->dpy, output->window, 1043 output->display->root_format, 0, NULL); 1044 if (output->pixmap == None) 1045 output->pixmap = XCreatePixmap(output->dpy, output->window, 1046 clone->width, clone->height, clone->depth); 1047 if (output->pix_picture == None) 1048 output->pix_picture = XRenderCreatePicture(output->dpy, output->pixmap, 1049 output->use_render, 0, NULL); 1050 } 1051 1052 if (output->gc == None) { 1053 XGCValues gcv; 1054 1055 DBG(DRAW, ("%s-%s: creating gc\n", DisplayString(output->dpy), output->name)); 1056 1057 gcv.graphics_exposures = False; 1058 gcv.subwindow_mode = IncludeInferiors; 1059 1060 output->gc = XCreateGC(output->dpy, output->pixmap ?: output->window, GCGraphicsExposures | GCSubwindowMode, &gcv); 1061 } 1062} 1063 1064static int bpp_for_depth(int depth) 1065{ 1066 switch (depth) { 1067 case 1: return 1; 1068 case 8: return 8; 1069 case 15: return 16; 1070 case 16: return 16; 1071 case 24: return 24; 1072 case 32: return 32; 1073 default: return 0; 1074 } 1075} 1076 1077static int clone_init_xfer(struct clone *clone) 1078{ 1079 int width, height; 1080 1081 if (clone->dst.mode.id == 0) { 1082 width = 0; 1083 height = 0; 1084 } else if (clone->dri3.xid) { 1085 width = clone->dst.display->width; 1086 height = clone->dst.display->height; 1087 } else { 1088 width = mode_width(&clone->src.mode, clone->src.rotation); 1089 height = mode_height(&clone->src.mode, clone->src.rotation); 1090 } 1091 1092 if (width == clone->width && height == clone->height) 1093 return 0; 1094 1095 DBG(DRAW, ("%s-%s create xfer, %dx%d\n", 1096 DisplayString(clone->dst.dpy), clone->dst.name, 1097 width, height)); 1098 1099 if (clone->shm.shmaddr) { 1100 if (clone->src.use_shm) 1101 XShmDetach(clone->src.dpy, &clone->src.shm); 1102 if (clone->dst.use_shm) 1103 XShmDetach(clone->dst.dpy, &clone->dst.shm); 1104 1105 shmdt(clone->shm.shmaddr); 1106 clone->shm.shmaddr = NULL; 1107 } 1108 1109 if (clone->src.pixmap) { 1110 XFreePixmap(clone->src.dpy, clone->src.pixmap); 1111 clone->src.pixmap = 0; 1112 } 1113 1114 if (clone->dst.pixmap) { 1115 XFreePixmap(clone->dst.dpy, clone->dst.pixmap); 1116 clone->dst.pixmap = 0; 1117 } 1118 1119 if ((width | height) == 0) { 1120 clone->damaged.x2 = clone->damaged.y2 = INT_MIN; 1121 clone->damaged.x1 = clone->damaged.y1 = INT_MAX; 1122 return 0; 1123 } 1124 1125 if (clone->dri3.xid) { 1126 int fd, stride; 1127 Pixmap src; 1128 1129 _x_error_occurred = 0; 1130 1131 DBG(DRAW, ("%s-%s create xfer, trying DRI3\n", 1132 DisplayString(clone->dst.dpy), clone->dst.name)); 1133 1134 fd = dri3_create_fd(clone->dst.dpy, clone->dst.window, &stride); 1135 if (fd < 0) 1136 goto disable_dri3; 1137 1138 DBG(DRAW, ("%s-%s create xfer, DRI3 fd=%d, stride=%d\n", 1139 DisplayString(clone->dst.dpy), clone->dst.name, 1140 fd, stride)); 1141 1142 src = dri3_create_pixmap(clone->src.dpy, clone->src.window, 1143 width, height, clone->depth, 1144 fd, bpp_for_depth(clone->depth), 1145 stride, lseek(fd, 0, SEEK_END)); 1146 1147 XSync(clone->src.dpy, False); 1148 if (!_x_error_occurred) { 1149 clone->src.pixmap = src; 1150 clone->width = width; 1151 clone->height = height; 1152 } else { 1153 XFreePixmap(clone->src.dpy, src); 1154 close(fd); 1155disable_dri3: 1156 dri3_fence_free(clone->src.dpy, &clone->dri3); 1157 clone->dri3.xid = 0; 1158 1159 DBG(DRAW, ("%s-%s create xfer, DRI3 failed\n", 1160 DisplayString(clone->dst.dpy), clone->dst.name)); 1161 } 1162 } 1163 1164 width = mode_width(&clone->src.mode, clone->src.rotation); 1165 height = mode_height(&clone->src.mode, clone->src.rotation); 1166 1167 if (!clone->dri3.xid) { 1168 DBG(DRAW, ("%s-%s create xfer, trying SHM\n", 1169 DisplayString(clone->dst.dpy), clone->dst.name)); 1170 1171 clone->shm.shmid = shmget(IPC_PRIVATE, 1172 height * stride_for_depth(width, clone->depth), 1173 IPC_CREAT | 0666); 1174 if (clone->shm.shmid == -1) 1175 return errno; 1176 1177 clone->shm.shmaddr = shmat(clone->shm.shmid, 0, 0); 1178 if (clone->shm.shmaddr == (char *) -1) { 1179 shmctl(clone->shm.shmid, IPC_RMID, NULL); 1180 return ENOMEM; 1181 } 1182 1183 if (clone->src.use_shm) { 1184 clone->src.shm = clone->shm; 1185 clone->src.shm.readOnly = False; 1186 XShmAttach(clone->src.dpy, &clone->src.shm); 1187 XSync(clone->src.dpy, False); 1188 } 1189 if (clone->dst.use_shm) { 1190 clone->dst.shm = clone->shm; 1191 clone->dst.shm.readOnly = !clone->dst.use_shm_pixmap; 1192 XShmAttach(clone->dst.dpy, &clone->dst.shm); 1193 XSync(clone->dst.dpy, False); 1194 } 1195 1196 shmctl(clone->shm.shmid, IPC_RMID, NULL); 1197 1198 clone->width = width; 1199 clone->height = height; 1200 1201 init_image(clone); 1202 } 1203 1204 output_init_xfer(clone, &clone->src); 1205 output_init_xfer(clone, &clone->dst); 1206 1207 clone->damaged.x1 = clone->src.x; 1208 clone->damaged.x2 = clone->src.x + width; 1209 clone->damaged.y1 = clone->src.y; 1210 clone->damaged.y2 = clone->src.y + height; 1211 1212 display_mark_flush(clone->dst.display); 1213 return 0; 1214} 1215 1216static void clone_update(struct clone *clone) 1217{ 1218 if (!clone->rr_update) 1219 return; 1220 1221 DBG(X11, ("%s-%s cloning modes\n", 1222 DisplayString(clone->dst.dpy), clone->dst.name)); 1223 1224 clone_update_modes__randr(clone); 1225 clone->rr_update = 0; 1226} 1227 1228static int context_update(struct context *ctx) 1229{ 1230 Display *dpy = ctx->display->dpy; 1231 XRRScreenResources *res; 1232 int context_changed = 0; 1233 int i, n; 1234 1235 DBG(X11, ("%s\n", __func__)); 1236 1237 res = _XRRGetScreenResourcesCurrent(dpy, ctx->display->root); 1238 if (res == NULL) 1239 return 0; 1240 1241 DBG(XRR, ("%s timestamp %ld (last %ld), config %ld (last %ld)\n", 1242 DisplayString(dpy), 1243 res->timestamp, ctx->timestamp, 1244 res->configTimestamp, ctx->configTimestamp)); 1245 if (res->timestamp == ctx->timestamp && 1246 res->configTimestamp == ctx->configTimestamp && 1247 res->timestamp != res->configTimestamp) { /* mutter be damned */ 1248 XRRFreeScreenResources(res); 1249 return 0; 1250 } 1251 1252 ctx->timestamp = res->timestamp; 1253 ctx->configTimestamp = res->configTimestamp; 1254 1255 for (n = 0; n < ctx->nclone; n++) { 1256 struct output *output = &ctx->clones[n].src; 1257 XRROutputInfo *o; 1258 XRRCrtcInfo *c; 1259 RRMode mode = 0; 1260 int changed = 0; 1261 1262 o = XRRGetOutputInfo(dpy, res, output->rr_output); 1263 if (o == NULL) 1264 continue; 1265 1266 c = NULL; 1267 if (o->crtc) 1268 c = XRRGetCrtcInfo(dpy, res, o->crtc); 1269 if (c) { 1270 DBG(XRR, ("%s-%s: (x=%d, y=%d, rotation=%d, mode=%ld) -> (x=%d, y=%d, rotation=%d, mode=%ld)\n", 1271 DisplayString(dpy), output->name, 1272 output->x, output->y, output->rotation, output->mode.id, 1273 c->x, c->y, c->rotation, c->mode)); 1274 1275 changed |= output->rotation != c->rotation; 1276 output->rotation = c->rotation; 1277 1278 changed |= output->x != c->x; 1279 output->x = c->x; 1280 1281 changed |= output->y != c->y; 1282 output->y = c->y; 1283 1284 changed |= output->mode.id != c->mode; 1285 mode = c->mode; 1286 XRRFreeCrtcInfo(c); 1287 } else { 1288 DBG(XRR, ("%s-%s: (x=%d, y=%d, rotation=%d, mode=%ld) -> off\n", 1289 DisplayString(dpy), output->name, 1290 output->x, output->y, output->rotation, output->mode.id)); 1291 } 1292 output->rr_crtc = o->crtc; 1293 XRRFreeOutputInfo(o); 1294 1295 DBG(XRR, ("%s-%s crtc changed? %d\n", 1296 DisplayString(ctx->clones[n].dst.display->dpy), ctx->clones[n].dst.name, changed)); 1297 1298 if (mode) { 1299 if (output->mode.id != mode) { 1300 for (i = 0; i < res->nmode; i++) { 1301 if (res->modes[i].id == mode) { 1302 output->mode = res->modes[i]; 1303 break; 1304 } 1305 } 1306 } 1307 } else { 1308 changed = output->mode.id != 0; 1309 output->mode.id = 0; 1310 } 1311 1312 DBG(XRR, ("%s-%s output changed? %d\n", 1313 DisplayString(ctx->clones[n].dst.display->dpy), ctx->clones[n].dst.name, changed)); 1314 1315 context_changed |= changed; 1316 } 1317 XRRFreeScreenResources(res); 1318 1319 DBG(XRR, ("%s changed? %d\n", DisplayString(dpy), context_changed)); 1320 if (!context_changed) 1321 return 0; 1322 1323 for (n = 1; n < ctx->ndisplay; n++) { 1324 struct display *display = &ctx->display[n]; 1325 struct clone *clone; 1326 int x1, x2, y1, y2; 1327 1328 if (display->rr_active == 0) 1329 continue; 1330 1331 x1 = y1 = INT_MAX; 1332 x2 = y2 = INT_MIN; 1333 1334 for (clone = display->clone; clone; clone = clone->next) { 1335 struct output *output = &clone->src; 1336 int v; 1337 1338 assert(clone->dst.display == display); 1339 1340 if (output->mode.id == 0) 1341 continue; 1342 1343 DBG(XRR, ("%s: source %s enabled (%d, %d)x(%d, %d)\n", 1344 DisplayString(clone->dst.dpy), output->name, 1345 output->x, output->y, 1346 mode_width(&output->mode, output->rotation), 1347 mode_height(&output->mode, output->rotation))); 1348 1349 if (output->x < x1) 1350 x1 = output->x; 1351 if (output->y < y1) 1352 y1 = output->y; 1353 1354 v = (int)output->x + mode_width(&output->mode, output->rotation); 1355 if (v > x2) 1356 x2 = v; 1357 v = (int)output->y + mode_height(&output->mode, output->rotation); 1358 if (v > y2) 1359 y2 = v; 1360 } 1361 1362 DBG(XRR, ("%s fb bounds (%d, %d)x(%d, %d)\n", DisplayString(display->dpy), 1363 x1, y1, x2, y2)); 1364 1365 XGrabServer(display->dpy); 1366 res = _XRRGetScreenResourcesCurrent(display->dpy, display->root); 1367 if (res == NULL) 1368 goto ungrab; 1369 1370 if (x2 <= x1 || y2 <= y1) { 1371 /* Nothing enabled, preserve the current fb, and turn everything off */ 1372 for (clone = display->clone; clone; clone = clone->next) { 1373 struct output *dst = &clone->dst; 1374 1375 if (!dst->rr_crtc) 1376 continue; 1377 1378 DBG(XRR, ("%s: disabling output '%s'\n", 1379 DisplayString(display->dpy), dst->name)); 1380 assert(clone->dst.display == display); 1381 if (disable_crtc(display->dpy, res, dst->rr_crtc)) { 1382 dst->rr_crtc = 0; 1383 dst->mode.id = 0; 1384 } 1385 } 1386 goto free_res; 1387 } 1388 1389 x2 -= x1; 1390 y2 -= y1; 1391 DBG(XRR, ("%s: current size %dx%d, need %dx%d\n", 1392 DisplayString(display->dpy), 1393 display->width, display->height, 1394 x2, y2)); 1395 1396 if (display->width != x2 || display->height != y2) { 1397 /* When shrinking we have to manually resize the fb */ 1398 for (clone = display->clone; clone; clone = clone->next) { 1399 struct output *dst = &clone->dst; 1400 1401 if (!dst->rr_crtc) 1402 continue; 1403 1404 DBG(XRR, ("%s: disabling output '%s'\n", 1405 DisplayString(display->dpy), dst->name)); 1406 assert(clone->dst.display == display); 1407 if (disable_crtc(display->dpy, res, dst->rr_crtc)) { 1408 dst->rr_crtc = 0; 1409 dst->mode.id = 0; 1410 } 1411 } 1412 1413 DBG(XRR, ("%s: XRRSetScreenSize %dx%d\n", DisplayString(display->dpy), x2, y2)); 1414 XRRSetScreenSize(display->dpy, display->root, x2, y2, x2 * 96 / 25.4, y2 * 96 / 25.4); 1415 display->width = x2; 1416 display->height = y2; 1417 } 1418 1419 for (clone = display->clone; clone; clone = clone->next) { 1420 struct output *src = &clone->src; 1421 struct output *dst = &clone->dst; 1422 XRROutputInfo *o; 1423 XRRPanning panning; 1424 struct clone *set; 1425 RRCrtc rr_crtc; 1426 Status ret; 1427 1428 DBG(XRR, ("%s: copying configuration from %s (mode=%ld: %dx%d) to %s\n", 1429 DisplayString(display->dpy), 1430 src->name, (long)src->mode.id, src->mode.width, src->mode.height, 1431 dst->name)); 1432 1433 if (src->mode.id == 0) { 1434err: 1435 if (dst->rr_crtc) { 1436 DBG(XRR, ("%s: disabling unused output '%s'\n", 1437 DisplayString(display->dpy), dst->name)); 1438 assert(clone->dst.display == display); 1439 if (disable_crtc(display->dpy, res, dst->rr_crtc)) { 1440 dst->rr_crtc = 0; 1441 dst->mode.id = 0; 1442 } 1443 } 1444 continue; 1445 } 1446 1447 dst->x = src->x - x1; 1448 dst->y = src->y - y1; 1449 dst->rotation = src->rotation; 1450 dst->mode = src->mode; 1451 1452 dst->mode.id = 0; 1453 for (i = 0; i < res->nmode; i++) { 1454 if (mode_equal(&src->mode, &res->modes[i])) { 1455 dst->mode.id = res->modes[i].id; 1456 break; 1457 } 1458 } 1459 if (dst->mode.id == 0) { 1460 XRRModeInfo m; 1461 char buf[256]; 1462 RRMode id; 1463 1464 /* XXX User names must be unique! */ 1465 m = src->mode; 1466 m.nameLength = snprintf(buf, sizeof(buf), 1467 "%s.%ld-%dx%d", src->name, 1468 (long)src->mode.id, 1469 src->mode.width, 1470 src->mode.height); 1471 m.name = buf; 1472 1473 id = XRRCreateMode(dst->dpy, dst->window, &m); 1474 if (id) { 1475 DBG(XRR, ("%s: adding mode %ld: %dx%d to %s, new mode %ld\n", 1476 DisplayString(dst->dpy), 1477 (long)src->mode.id, 1478 src->mode.width, 1479 src->mode.height, 1480 dst->name, (long)id)); 1481 XRRAddOutputMode(dst->dpy, dst->rr_output, id); 1482 dst->mode.id = id; 1483 } else { 1484 DBG(XRR, ("%s: failed to find suitable mode for %s\n", 1485 DisplayString(dst->dpy), dst->name)); 1486 goto err; 1487 } 1488 } 1489 1490 rr_crtc = dst->rr_crtc; 1491 if (rr_crtc) { 1492 for (set = display->clone; set != clone; set = set->next) { 1493 if (set->dst.rr_crtc == rr_crtc) { 1494 DBG(XRR, ("%s: CRTC reassigned from %s\n", 1495 DisplayString(dst->dpy), dst->name)); 1496 rr_crtc = 0; 1497 break; 1498 } 1499 } 1500 } 1501 if (rr_crtc == 0) { 1502 o = XRRGetOutputInfo(dst->dpy, res, dst->rr_output); 1503 for (i = 0; i < o->ncrtc; i++) { 1504 DBG(XRR, ("%s: checking whether CRTC:%ld is available\n", 1505 DisplayString(dst->dpy), (long)o->crtcs[i])); 1506 for (set = display->clone; set != clone; set = set->next) { 1507 if (set->dst.rr_crtc == o->crtcs[i]) { 1508 DBG(XRR, ("%s: CRTC:%ld already assigned to %s\n", 1509 DisplayString(dst->dpy), (long)o->crtcs[i], set->dst.name)); 1510 break; 1511 } 1512 } 1513 if (set == clone) { 1514 rr_crtc = o->crtcs[i]; 1515 break; 1516 } 1517 } 1518 XRRFreeOutputInfo(o); 1519 } 1520 if (rr_crtc == 0) { 1521 DBG(XRR, ("%s: failed to find available CRTC for %s\n", 1522 DisplayString(dst->dpy), dst->name)); 1523 goto err; 1524 } 1525 1526 DBG(XRR, ("%s: enabling output '%s' (%d,%d)x(%d,%d), rotation %d, on CRTC:%ld, using mode %ld\n", 1527 DisplayString(dst->dpy), dst->name, 1528 dst->x, dst->y, dst->mode.width, dst->mode.height, 1529 dst->rotation, (long)rr_crtc, dst->mode.id)); 1530 1531 ret = XRRSetPanning(dst->dpy, res, rr_crtc, memset(&panning, 0, sizeof(panning))); 1532 DBG(XRR, ("%s-%s: XRRSetPanning %s\n", DisplayString(dst->dpy), dst->name, ret ? "failed" : "success")); 1533 (void)ret; 1534 1535 ret = XRRSetCrtcConfig(dst->dpy, res, rr_crtc, CurrentTime, 1536 dst->x, dst->y, dst->mode.id, dst->rotation, 1537 &dst->rr_output, 1); 1538 DBG(XRR, ("%s-%s: XRRSetCrtcConfig %s\n", DisplayString(dst->dpy), dst->name, ret ? "failed" : "success")); 1539 if (ret) 1540 goto err; 1541 1542 if (verbose & XRR) { 1543 XRRCrtcInfo *c; 1544 XRRPanning *p; 1545 1546 c = XRRGetCrtcInfo(dst->dpy, res, rr_crtc); 1547 if (c) { 1548 DBG(XRR, ("%s-%s: x=%d, y=%d, rotation=%d, mode=%ld\n", 1549 DisplayString(dst->dpy), dst->name, 1550 c->x, c->y, c->rotation, c->mode)); 1551 XRRFreeCrtcInfo(c); 1552 } 1553 1554 p = XRRGetPanning(dst->dpy, res, rr_crtc); 1555 if (p) { 1556 DBG(XRR, ("%s-%s: panning (%d, %d)x(%d, %d), tracking (%d, %d)x(%d, %d), border (%d, %d),(%d, %d)\n", 1557 DisplayString(dst->dpy), dst->name, 1558 p->left, p->top, p->width, p->height, 1559 p->track_left, p->track_top, p->track_width, p->track_height, 1560 p->border_left, p->border_top, p->border_right, p->border_bottom)); 1561 XRRFreePanning(p); 1562 } 1563 } 1564 1565 dst->rr_crtc = rr_crtc; 1566 } 1567free_res: 1568 XRRFreeScreenResources(res); 1569ungrab: 1570 XUngrabServer(display->dpy); 1571 } 1572 1573 ctx->active = NULL; 1574 for (n = 0; n < ctx->nclone; n++) { 1575 struct clone *clone = &ctx->clones[n]; 1576 1577 clone_init_xfer(clone); 1578 1579 if (clone->dst.rr_crtc == 0) 1580 continue; 1581 1582 DBG(XRR, ("%s-%s: added to active list\n", 1583 DisplayString(clone->dst.display->dpy), clone->dst.name)); 1584 1585 clone->active = ctx->active; 1586 ctx->active = clone; 1587 } 1588 1589 return 1; 1590} 1591 1592static Cursor display_load_invisible_cursor(struct display *display) 1593{ 1594 char zero[8] = {}; 1595 XColor black = {}; 1596 Pixmap bitmap = XCreateBitmapFromData(display->dpy, display->root, zero, 8, 8); 1597 return XCreatePixmapCursor(display->dpy, bitmap, bitmap, &black, &black, 0, 0); 1598} 1599 1600static Cursor display_get_visible_cursor(struct display *display) 1601{ 1602 if (display->cursor_serial != display->cursor_image.size) { 1603 DBG(CURSOR, ("%s updating cursor\n", DisplayString(display->dpy))); 1604 1605 if (display->visible_cursor) 1606 XFreeCursor(display->dpy, display->visible_cursor); 1607 1608 display->visible_cursor = XcursorImageLoadCursor(display->dpy, &display->cursor_image); 1609 display->cursor_serial = display->cursor_image.size; 1610 } 1611 1612 return display->visible_cursor; 1613} 1614 1615static void display_load_visible_cursor(struct display *display, XFixesCursorImage *cur) 1616{ 1617 unsigned long *src; /* XXX deep sigh */ 1618 XcursorPixel *dst; 1619 unsigned n; 1620 1621 if (cur->width != display->cursor_image.width || 1622 cur->height != display->cursor_image.height) 1623 display->cursor_image.pixels = realloc(display->cursor_image.pixels, 1624 4 * cur->width * cur->height); 1625 if (display->cursor_image.pixels == NULL) 1626 return; 1627 1628 display->cursor_image.width = cur->width; 1629 display->cursor_image.height = cur->height; 1630 display->cursor_image.xhot = cur->xhot; 1631 display->cursor_image.yhot = cur->yhot; 1632 display->cursor_image.size++; 1633 1634 n = cur->width*cur->height; 1635 src = cur->pixels; 1636 dst = display->cursor_image.pixels; 1637 while (n--) 1638 *dst++ = *src++; 1639 1640 DBG(CURSOR, ("%s marking cursor changed\n", DisplayString(display->dpy))); 1641 display->cursor_moved++; 1642 if (display->cursor != display->invisible_cursor) { 1643 display->cursor_visible++; 1644 context_enable_timer(display->ctx); 1645 } 1646} 1647 1648static void display_cursor_move(struct display *display, int x, int y, int visible) 1649{ 1650 DBG(CURSOR, ("%s cursor moved (visible=%d, (%d, %d))\n", 1651 DisplayString(display->dpy), visible, x, y)); 1652 display->cursor_moved++; 1653 display->cursor_visible += visible; 1654 if (visible) { 1655 display->cursor_x = x; 1656 display->cursor_y = y; 1657 } 1658 1659 context_enable_timer(display->ctx); 1660} 1661 1662static void display_flush_cursor(struct display *display) 1663{ 1664 Cursor cursor; 1665 int x, y; 1666 1667 if (!display->cursor_moved) 1668 return; 1669 1670 if (display->cursor_visible) { 1671 x = display->cursor_x; 1672 y = display->cursor_y; 1673 } else { 1674 x = display->cursor_x++ & 31; 1675 y = display->cursor_y++ & 31; 1676 } 1677 1678 DBG(CURSOR, ("%s setting cursor position (%d, %d), visible? %d\n", 1679 DisplayString(display->dpy), x, y, display->cursor_visible)); 1680 XWarpPointer(display->dpy, None, display->root, 0, 0, 0, 0, x, y); 1681 1682 cursor = None; 1683 if (display->cursor_visible) 1684 cursor = display_get_visible_cursor(display); 1685 if (cursor == None) 1686 cursor = display->invisible_cursor; 1687 if (cursor != display->cursor) { 1688 XDefineCursor(display->dpy, display->root, cursor); 1689 display->cursor = cursor; 1690 } 1691 1692 display_mark_flush(display); 1693 1694 display->cursor_moved = 0; 1695 display->cursor_visible = 0; 1696} 1697 1698static void clone_move_cursor(struct clone *c, int x, int y) 1699{ 1700 int visible; 1701 1702 DBG(CURSOR, ("%s-%s moving cursor (%d, %d) [(%d, %d), (%d, %d)]\n", 1703 DisplayString(c->dst.dpy), c->dst.name, 1704 x, y, 1705 c->src.x, c->src.y, 1706 c->src.x + c->width, c->src.y + c->height)); 1707 1708 visible = (x >= c->src.x && x < c->src.x + c->width && 1709 y >= c->src.y && y < c->src.y + c->height); 1710 1711 x += c->dst.x - c->src.x; 1712 y += c->dst.y - c->src.y; 1713 1714 display_cursor_move(c->dst.display, x, y, visible); 1715} 1716 1717static int clone_output_init(struct clone *clone, struct output *output, 1718 struct display *display, const char *name, 1719 RROutput rr_output) 1720{ 1721 Display *dpy = display->dpy; 1722 int depth; 1723 1724 DBG(X11, ("%s(%s, %s)\n", __func__, DisplayString(dpy), name)); 1725 1726 output->name = strdup(name); 1727 if (output->name == NULL) 1728 return -ENOMEM; 1729 1730 output->display = display; 1731 output->dpy = dpy; 1732 1733 output->rr_output = rr_output; 1734 output->rotation = RR_Rotate_0; 1735 1736 output->window = display->root; 1737 output->use_shm = display->has_shm; 1738 output->use_shm_pixmap = display->has_shm_pixmap; 1739 1740 DBG(X11, ("%s-%s use shm? %d (use shm pixmap? %d)\n", 1741 DisplayString(dpy), name, display->has_shm, display->has_shm_pixmap)); 1742 1743 depth = output->use_shm && !FORCE_16BIT_XFER ? display->depth : 16; 1744 if (depth < clone->depth) 1745 clone->depth = depth; 1746 1747 return 0; 1748} 1749 1750static void ximage_prepare(XImage *image, int width, int height) 1751{ 1752 image->width = width; 1753 image->height = height; 1754 image->bytes_per_line = stride_for_depth(width, image->depth); 1755} 1756 1757static void get_src(struct clone *c, const XRectangle *clip) 1758{ 1759 DBG(DRAW,("%s-%s get_src(%d,%d)x(%d,%d)\n", DisplayString(c->dst.dpy), c->dst.name, 1760 clip->x, clip->y, clip->width, clip->height)); 1761 1762 c->image.obdata = (char *)&c->src.shm; 1763 1764 if (c->src.use_render) { 1765 XRenderComposite(c->src.dpy, PictOpSrc, 1766 c->src.win_picture, 0, c->src.pix_picture, 1767 clip->x, clip->y, 1768 0, 0, 1769 0, 0, 1770 clip->width, clip->height); 1771 if (c->src.use_shm_pixmap) { 1772 XSync(c->src.dpy, False); 1773 } else if (c->src.use_shm) { 1774 ximage_prepare(&c->image, clip->width, clip->height); 1775 XShmGetImage(c->src.dpy, c->src.pixmap, &c->image, 1776 clip->x, clip->y, AllPlanes); 1777 } else { 1778 ximage_prepare(&c->image, c->width, c->height); 1779 XGetSubImage(c->src.dpy, c->src.pixmap, 1780 clip->x, clip->y, clip->width, clip->height, 1781 AllPlanes, ZPixmap, 1782 &c->image, 0, 0); 1783 } 1784 } else if (c->src.pixmap) { 1785 XCopyArea(c->src.dpy, c->src.window, c->src.pixmap, c->src.gc, 1786 clip->x, clip->y, 1787 clip->width, clip->height, 1788 0, 0); 1789 XSync(c->src.dpy, False); 1790 } else if (c->src.use_shm) { 1791 ximage_prepare(&c->image, clip->width, clip->height); 1792 XShmGetImage(c->src.dpy, c->src.window, &c->image, 1793 clip->x, clip->y, AllPlanes); 1794 } else { 1795 ximage_prepare(&c->image, c->width, c->height); 1796 XGetSubImage(c->src.dpy, c->src.window, 1797 clip->x, clip->y, clip->width, clip->height, 1798 AllPlanes, ZPixmap, 1799 &c->image, 0, 0); 1800 } 1801 c->src.display->flush = 0; 1802} 1803 1804static void put_dst(struct clone *c, const XRectangle *clip) 1805{ 1806 DBG(DRAW, ("%s-%s put_dst(%d,%d)x(%d,%d)\n", DisplayString(c->dst.dpy), c->dst.name, 1807 clip->x, clip->y, clip->width, clip->height)); 1808 1809 c->image.obdata = (char *)&c->dst.shm; 1810 1811 if (c->dst.use_render) { 1812 if (c->dst.use_shm_pixmap) { 1813 DBG(DRAW, ("%s-%s using SHM pixmap composite\n", 1814 DisplayString(c->dst.dpy), c->dst.name)); 1815 } else if (c->dst.use_shm) { 1816 DBG(DRAW, ("%s-%s using SHM image composite\n", 1817 DisplayString(c->dst.dpy), c->dst.name)); 1818 XShmPutImage(c->dst.dpy, c->dst.pixmap, c->dst.gc, &c->image, 1819 0, 0, 1820 0, 0, 1821 clip->width, clip->height, 1822 False); 1823 } else { 1824 DBG(DRAW, ("%s-%s using composite\n", 1825 DisplayString(c->dst.dpy), c->dst.name)); 1826 XPutImage(c->dst.dpy, c->dst.pixmap, c->dst.gc, &c->image, 1827 0, 0, 1828 0, 0, 1829 clip->width, clip->height); 1830 } 1831 if (c->dst.use_shm) 1832 c->dst.serial = NextRequest(c->dst.dpy); 1833 XRenderComposite(c->dst.dpy, PictOpSrc, 1834 c->dst.pix_picture, 0, c->dst.win_picture, 1835 0, 0, 1836 0, 0, 1837 clip->x, clip->y, 1838 clip->width, clip->height); 1839 c->dst.display->send |= c->dst.use_shm; 1840 } else if (c->dst.pixmap) { 1841 DBG(DRAW, ("%s-%s using SHM pixmap\n", 1842 DisplayString(c->dst.dpy), c->dst.name)); 1843 c->dst.serial = NextRequest(c->dst.dpy); 1844 XCopyArea(c->dst.dpy, c->dst.pixmap, c->dst.window, c->dst.gc, 1845 0, 0, 1846 clip->width, clip->height, 1847 clip->x, clip->y); 1848 c->dst.display->send = 1; 1849 } else if (c->dst.use_shm) { 1850 DBG(DRAW, ("%s-%s using SHM image\n", 1851 DisplayString(c->dst.dpy), c->dst.name)); 1852 c->dst.serial = NextRequest(c->dst.dpy); 1853 XShmPutImage(c->dst.dpy, c->dst.window, c->dst.gc, &c->image, 1854 0, 0, 1855 clip->x, clip->y, 1856 clip->width, clip->height, 1857 True); 1858 } else { 1859 DBG(DRAW, ("%s-%s using image\n", 1860 DisplayString(c->dst.dpy), c->dst.name)); 1861 XPutImage(c->dst.dpy, c->dst.window, c->dst.gc, &c->image, 1862 0, 0, 1863 clip->x, clip->y, 1864 clip->width, clip->height); 1865 c->dst.serial = 0; 1866 } 1867} 1868 1869static int clone_paint(struct clone *c) 1870{ 1871 XRectangle clip; 1872 1873 DBG(DRAW, ("%s-%s paint clone, damaged (%d, %d), (%d, %d) [(%d, %d), (%d, %d)]\n", 1874 DisplayString(c->dst.dpy), c->dst.name, 1875 c->damaged.x1, c->damaged.y1, 1876 c->damaged.x2, c->damaged.y2, 1877 c->src.x, c->src.y, 1878 c->src.x + c->width, c->src.y + c->height)); 1879 1880 if (c->damaged.x1 < c->src.x) 1881 c->damaged.x1 = c->src.x; 1882 if (c->damaged.x2 > c->src.x + c->width) 1883 c->damaged.x2 = c->src.x + c->width; 1884 if (c->damaged.x2 <= c->damaged.x1) 1885 goto done; 1886 1887 if (c->damaged.y1 < c->src.y) 1888 c->damaged.y1 = c->src.y; 1889 if (c->damaged.y2 > c->src.y + c->height) 1890 c->damaged.y2 = c->src.y + c->height; 1891 if (c->damaged.y2 <= c->damaged.y1) 1892 goto done; 1893 1894 DBG(DRAW, ("%s-%s is damaged, last SHM serial: %ld, now %ld\n", 1895 DisplayString(c->dst.dpy), c->dst.name, 1896 (long)c->dst.serial, (long)LastKnownRequestProcessed(c->dst.dpy))); 1897 if (c->dst.serial > LastKnownRequestProcessed(c->dst.dpy)) { 1898 struct pollfd pfd; 1899 1900 pfd.fd = ConnectionNumber(c->dst.dpy); 1901 pfd.events = POLLIN; 1902 XEventsQueued(c->dst.dpy, 1903 poll(&pfd, 1, 0) ? QueuedAfterReading : QueuedAfterFlush); 1904 1905 if (c->dst.serial > LastKnownRequestProcessed(c->dst.dpy)) { 1906 c->dst.display->skip_clone++; 1907 return EAGAIN; 1908 } 1909 } 1910 1911 c->dst.display->skip_clone = 0; 1912 c->dst.display->skip_frame = 0; 1913 1914 if (FORCE_FULL_REDRAW) { 1915 c->damaged.x1 = c->src.x; 1916 c->damaged.y1 = c->src.y; 1917 c->damaged.x2 = c->src.x + c->width; 1918 c->damaged.y2 = c->src.y + c->height; 1919 } 1920 1921 if (c->dri3.xid) { 1922 if (c->src.use_render) { 1923 XRenderComposite(c->src.dpy, PictOpSrc, 1924 c->src.win_picture, 0, c->src.pix_picture, 1925 c->damaged.x1, c->damaged.y1, 1926 0, 0, 1927 c->damaged.x1 + c->dst.x - c->src.x, 1928 c->damaged.y1 + c->dst.y - c->src.y, 1929 c->damaged.x2 - c->damaged.x1, 1930 c->damaged.y2 - c->damaged.y1); 1931 } else { 1932 XCopyArea(c->src.dpy, c->src.window, c->src.pixmap, c->src.gc, 1933 c->damaged.x1, c->damaged.y1, 1934 c->damaged.x2 - c->damaged.x1, 1935 c->damaged.y2 - c->damaged.y1, 1936 c->damaged.x1 + c->dst.x - c->src.x, 1937 c->damaged.y1 + c->dst.y - c->src.y); 1938 } 1939 dri3_fence_flush(c->src.dpy, &c->dri3); 1940 } else { 1941 clip.x = c->damaged.x1; 1942 clip.y = c->damaged.y1; 1943 clip.width = c->damaged.x2 - c->damaged.x1; 1944 clip.height = c->damaged.y2 - c->damaged.y1; 1945 get_src(c, &clip); 1946 1947 clip.x += c->dst.x - c->src.x; 1948 clip.y += c->dst.y - c->src.y; 1949 put_dst(c, &clip); 1950 } 1951 display_mark_flush(c->dst.display); 1952 1953done: 1954 c->damaged.x2 = c->damaged.y2 = INT_MIN; 1955 c->damaged.x1 = c->damaged.y1 = INT_MAX; 1956 return 0; 1957} 1958 1959static void clone_damage(struct clone *c, const XRectangle *rec) 1960{ 1961 int v; 1962 1963 if ((v = rec->x) < c->damaged.x1) 1964 c->damaged.x1 = v; 1965 if ((v = (int)rec->x + rec->width) > c->damaged.x2) 1966 c->damaged.x2 = v; 1967 if ((v = rec->y) < c->damaged.y1) 1968 c->damaged.y1 = v; 1969 if ((v = (int)rec->y + rec->height) > c->damaged.y2) 1970 c->damaged.y2 = v; 1971 1972 DBG(DAMAGE, ("%s-%s damaged: (%d, %d), (%d, %d)\n", 1973 DisplayString(c->dst.display->dpy), c->dst.name, 1974 c->damaged.x1, c->damaged.y1, 1975 c->damaged.x2, c->damaged.y2)); 1976} 1977 1978static void usage(const char *arg0) 1979{ 1980 printf("Usage: %s [OPTION]... [TARGET_DISPLAY]...\n", arg0); 1981 printf(" -d <source display> source display\n"); 1982 printf(" -f keep in foreground (do not detach from console and daemonize)\n"); 1983 printf(" -b start bumblebee\n"); 1984 printf(" -a connect to all local displays (e.g. :1, :2, etc)\n"); 1985 printf(" -S disable use of a singleton and launch a fresh intel-virtual-output process\n"); 1986 printf(" -v all verbose output, implies -f\n"); 1987 printf(" -V <category> specific verbose output, implies -f\n"); 1988 printf(" -h this help\n"); 1989 printf("If no target displays are parsed on the commandline, \n"); 1990 printf("intel-virtual-output will attempt to connect to any local display\n"); 1991 printf("and then start bumblebee.\n"); 1992} 1993 1994static void record_callback(XPointer closure, XRecordInterceptData *data) 1995{ 1996 struct context *ctx = (struct context *)closure; 1997 1998 DBG(X11, ("%s\n", __func__)); 1999 2000 if (data->category == XRecordFromServer) { 2001 const xEvent *e = (const xEvent *)data->data; 2002 2003 DBG(X11, ("%s -- from server, event type %d, root %ld (ours? %d)\n", 2004 __func__, e->u.u.type, (long)e->u.keyButtonPointer.root, 2005 ctx->display->root == e->u.keyButtonPointer.root)); 2006 2007 if (e->u.u.type == MotionNotify && 2008 e->u.keyButtonPointer.root == ctx->display->root) { 2009 struct clone *clone; 2010 2011 for (clone = ctx->active; clone; clone = clone->active) 2012 clone_move_cursor(clone, 2013 e->u.keyButtonPointer.rootX, 2014 e->u.keyButtonPointer.rootY); 2015 } 2016 } 2017 2018 XRecordFreeData(data); 2019} 2020 2021static int record_mouse(struct context *ctx) 2022{ 2023 Display *dpy; 2024 XRecordRange *rr; 2025 XRecordClientSpec rcs; 2026 XRecordContext rc; 2027 2028 DBG(X11, ("%s(%s)\n", __func__, DisplayString(ctx->display->dpy))); 2029 2030 dpy = XOpenDisplay(DisplayString(ctx->display->dpy)); 2031 if (dpy == NULL) 2032 return -ECONNREFUSED; 2033 2034 rr = XRecordAllocRange(); 2035 if (rr == NULL) 2036 return -ENOMEM; 2037 2038 rr->device_events.first = rr->device_events.last = MotionNotify; 2039 2040 rcs = XRecordAllClients; 2041 rc = XRecordCreateContext(dpy, 0, &rcs, 1, &rr, 1); 2042 2043 XSync(dpy, False); 2044 2045 if (!XRecordEnableContextAsync(dpy, rc, record_callback, (XPointer)ctx)) 2046 return -EINVAL; 2047 2048 ctx->record = dpy; 2049 return ConnectionNumber(dpy); 2050} 2051 2052static int bad_visual(Visual *visual, int depth) 2053{ 2054 DBG(X11, ("%s? depth=%d, visual: class=%d, bits_per_rgb=%d, red_mask=%08lx, green_mask=%08lx, blue_mask=%08lx\n", 2055 __func__, depth, 2056 visual->class, 2057 visual->bits_per_rgb, 2058 visual->red_mask, 2059 visual->green_mask, 2060 visual->blue_mask)); 2061 2062 if (!(visual->class == TrueColor || visual->class == DirectColor)) 2063 return 1; 2064 2065 switch (depth) { 2066 case 16: return (/* visual->bits_per_rgb != 6 || */ 2067 visual->red_mask != 0x1f << 11 || 2068 visual->green_mask != 0x3f << 5 || 2069 visual->blue_mask != 0x1f << 0); 2070 2071 case 24: return (/* visual->bits_per_rgb != 8 || */ 2072 visual->red_mask != 0xff << 16 || 2073 visual->green_mask != 0xff << 8 || 2074 visual->blue_mask != 0xff << 0); 2075 2076 default: return 1; 2077 } 2078} 2079 2080static XRenderPictFormat * 2081find_xrender_format(Display *dpy, pixman_format_code_t format) 2082{ 2083 XRenderPictFormat tmpl; 2084 int mask; 2085 2086#define MASK(x) ((1<<(x))-1) 2087 2088 memset(&tmpl, 0, sizeof(tmpl)); 2089 2090 tmpl.depth = PIXMAN_FORMAT_DEPTH(format); 2091 mask = PictFormatType | PictFormatDepth; 2092 2093 DBG(X11, ("%s(0x%08lx)\n", __func__, (long)format)); 2094 2095 switch (PIXMAN_FORMAT_TYPE(format)) { 2096 case PIXMAN_TYPE_ARGB: 2097 tmpl.type = PictTypeDirect; 2098 2099 if (PIXMAN_FORMAT_A(format)) { 2100 tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format)); 2101 tmpl.direct.alpha = (PIXMAN_FORMAT_R(format) + 2102 PIXMAN_FORMAT_G(format) + 2103 PIXMAN_FORMAT_B(format)); 2104 } 2105 2106 tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format)); 2107 tmpl.direct.red = (PIXMAN_FORMAT_G(format) + 2108 PIXMAN_FORMAT_B(format)); 2109 2110 tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format)); 2111 tmpl.direct.green = PIXMAN_FORMAT_B(format); 2112 2113 tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format)); 2114 tmpl.direct.blue = 0; 2115 2116 mask |= PictFormatRed | PictFormatRedMask; 2117 mask |= PictFormatGreen | PictFormatGreenMask; 2118 mask |= PictFormatBlue | PictFormatBlueMask; 2119 mask |= PictFormatAlpha | PictFormatAlphaMask; 2120 break; 2121 2122 case PIXMAN_TYPE_ABGR: 2123 tmpl.type = PictTypeDirect; 2124 2125 if (tmpl.direct.alphaMask) { 2126 tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format)); 2127 tmpl.direct.alpha = (PIXMAN_FORMAT_B(format) + 2128 PIXMAN_FORMAT_G(format) + 2129 PIXMAN_FORMAT_R(format)); 2130 } 2131 2132 tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format)); 2133 tmpl.direct.blue = (PIXMAN_FORMAT_G(format) + 2134 PIXMAN_FORMAT_R(format)); 2135 2136 tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format)); 2137 tmpl.direct.green = PIXMAN_FORMAT_R(format); 2138 2139 tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format)); 2140 tmpl.direct.red = 0; 2141 2142 mask |= PictFormatRed | PictFormatRedMask; 2143 mask |= PictFormatGreen | PictFormatGreenMask; 2144 mask |= PictFormatBlue | PictFormatBlueMask; 2145 mask |= PictFormatAlpha | PictFormatAlphaMask; 2146 break; 2147 2148 case PIXMAN_TYPE_BGRA: 2149 tmpl.type = PictTypeDirect; 2150 2151 tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format)); 2152 tmpl.direct.blue = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format)); 2153 2154 tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format)); 2155 tmpl.direct.green = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) - 2156 PIXMAN_FORMAT_G(format)); 2157 2158 tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format)); 2159 tmpl.direct.red = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) - 2160 PIXMAN_FORMAT_G(format) - PIXMAN_FORMAT_R(format)); 2161 2162 if (tmpl.direct.alphaMask) { 2163 tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format)); 2164 tmpl.direct.alpha = 0; 2165 } 2166 2167 mask |= PictFormatRed | PictFormatRedMask; 2168 mask |= PictFormatGreen | PictFormatGreenMask; 2169 mask |= PictFormatBlue | PictFormatBlueMask; 2170 mask |= PictFormatAlpha | PictFormatAlphaMask; 2171 break; 2172 2173 case PIXMAN_TYPE_A: 2174 tmpl.type = PictTypeDirect; 2175 2176 tmpl.direct.alpha = 0; 2177 tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format)); 2178 2179 mask |= PictFormatAlpha | PictFormatAlphaMask; 2180 break; 2181 2182 case PIXMAN_TYPE_COLOR: 2183 case PIXMAN_TYPE_GRAY: 2184 /* XXX Find matching visual/colormap */ 2185 tmpl.type = PictTypeIndexed; 2186 //tmpl.colormap = screen->visuals[PIXMAN_FORMAT_VIS(format)].vid; 2187 //mask |= PictFormatColormap; 2188 return NULL; 2189 } 2190#undef MASK 2191 2192 return XRenderFindFormat(dpy, mask, &tmpl, 0); 2193} 2194 2195static int display_init_render(struct display *display, int depth, XRenderPictFormat **use_render) 2196{ 2197 Display *dpy = display->dpy; 2198 int major, minor; 2199 2200 DBG(X11, ("%s is depth %d, want %d\n", DisplayString(dpy), display->depth, depth)); 2201 2202 *use_render = 0; 2203 if (depth == display->depth && !bad_visual(display->visual, depth)) 2204 return 0; 2205 2206 if (display->root_format == 0) { 2207 if (!XRenderQueryVersion(dpy, &major, &minor)) { 2208 fprintf(stderr, "Render extension not supported by %s\n", DisplayString(dpy)); 2209 return -EINVAL; 2210 } 2211 2212 display->root_format = XRenderFindVisualFormat(dpy, display->visual); 2213 display->rgb16_format = find_xrender_format(dpy, PIXMAN_r5g6b5); 2214 display->rgb24_format = XRenderFindStandardFormat(dpy, PictStandardRGB24); 2215 2216 DBG(X11, ("%s: root format=%lx, rgb16 format=%lx, rgb24 format=%lx\n", 2217 DisplayString(dpy), 2218 (long)display->root_format, 2219 (long)display->rgb16_format, 2220 (long)display->rgb24_format)); 2221 } 2222 2223 switch (depth) { 2224 case 16: *use_render = display->rgb16_format; break; 2225 case 24: *use_render = display->rgb24_format; break; 2226 } 2227 if (*use_render == 0) 2228 return -ENOENT; 2229 2230 return 0; 2231} 2232 2233static int clone_init_depth(struct clone *clone) 2234{ 2235 int ret, depth; 2236 2237 DBG(X11,("%s-%s wants depth %d\n", 2238 DisplayString(clone->dst.dpy), clone->dst.name, clone->depth)); 2239 2240 ret = -1; 2241 for (depth = clone->depth; depth <= 24; depth += 8) { 2242 ret = display_init_render(clone->src.display, depth, &clone->src.use_render); 2243 if (ret) 2244 continue; 2245 2246 ret = display_init_render(clone->dst.display, depth, &clone->dst.use_render); 2247 if (ret) 2248 continue; 2249 2250 break; 2251 } 2252 if (ret) 2253 return ret; 2254 2255 DBG(X11, ("%s-%s using depth %d, requires xrender for src? %d, for dst? %d\n", 2256 DisplayString(clone->dst.dpy), clone->dst.name, 2257 clone->depth, 2258 clone->src.use_render != NULL, 2259 clone->dst.use_render != NULL)); 2260 2261 if (!clone->dst.use_render && 2262 clone->src.display->dri3_active && 2263 clone->dst.display->dri3_active) 2264 dri3_create_fence(clone->src.dpy, clone->src.window, &clone->dri3); 2265 2266 return 0; 2267} 2268 2269#if defined(USE_XINERAMA) 2270static int xinerama_active(struct display *display) 2271{ 2272 int active = 0; 2273 if (XineramaQueryExtension(display->dpy, &display->xinerama_event, &display->xinerama_error)) 2274 active = XineramaIsActive(display->dpy); 2275 return active; 2276} 2277#else 2278#define xinerama_active(d) 0 2279#endif 2280 2281static int add_display(struct context *ctx, Display *dpy) 2282{ 2283 struct display *display; 2284 int first_display = ctx->ndisplay == 0; 2285 2286 if (is_power_of_2(ctx->ndisplay)) { 2287 struct display *new_display; 2288 2289 new_display = realloc(ctx->display, 2*ctx->ndisplay*sizeof(struct display)); 2290 if (new_display == NULL) 2291 return -ENOMEM; 2292 2293 if (new_display != ctx->display) { 2294 int n; 2295 2296 for (n = 0; n < ctx->nclone; n++) { 2297 struct clone *clone = &ctx->clones[n]; 2298 clone->src.display = new_display + (clone->src.display - ctx->display); 2299 clone->dst.display = new_display + (clone->dst.display - ctx->display); 2300 } 2301 } 2302 2303 ctx->display = new_display; 2304 } 2305 2306 display = memset(&ctx->display[ctx->ndisplay++], 0, sizeof(struct display)); 2307 2308 display->dpy = dpy; 2309 display->ctx = ctx; 2310 2311 display->root = DefaultRootWindow(dpy); 2312 display->depth = DefaultDepth(dpy, DefaultScreen(dpy)); 2313 display->visual = DefaultVisual(dpy, DefaultScreen(dpy)); 2314 2315 display->has_shm = can_use_shm(dpy, display->root, 2316 &display->shm_event, 2317 &display->shm_opcode, 2318 &display->has_shm_pixmap); 2319 DBG(X11, ("%s: has_shm?=%d, event=%d, opcode=%d, has_pixmap?=%d\n", 2320 DisplayString(dpy), 2321 display->has_shm, 2322 display->shm_event, 2323 display->shm_opcode, 2324 display->has_shm_pixmap)); 2325 2326 display->rr_active = XRRQueryExtension(dpy, &display->rr_event, &display->rr_error); 2327 DBG(X11, ("%s: randr_active?=%d, event=%d, error=%d\n", 2328 DisplayString(dpy), 2329 display->rr_active, 2330 display->rr_event, 2331 display->rr_error)); 2332 2333 display->xinerama_active = xinerama_active(display); 2334 DBG(X11, ("%s: xinerama_active?=%d, event=%d, error=%d\n", 2335 DisplayString(dpy), 2336 display->xinerama_active, 2337 display->xinerama_event, 2338 display->xinerama_error)); 2339 2340 display->dri3_active = dri3_exists(dpy); 2341 DBG(X11, ("%s: dri3_active?=%d\n", 2342 DisplayString(dpy), 2343 display->dri3_active)); 2344 2345 /* first display (source) is slightly special */ 2346 if (!first_display) { 2347 display->invisible_cursor = display_load_invisible_cursor(display); 2348 display_cursor_move(display, 0, 0, 0); 2349 } 2350 2351 return ConnectionNumber(dpy); 2352} 2353 2354static int display_open(struct context *ctx, const char *name) 2355{ 2356 Display *dpy; 2357 int n; 2358 2359 DBG(X11, ("%s(%s)\n", __func__, name)); 2360 2361 dpy = XOpenDisplay(name); 2362 if (dpy == NULL) 2363 return -ECONNREFUSED; 2364 2365 /* Prevent cloning the same display twice */ 2366 for (n = 0; n < ctx->ndisplay; n++) { 2367 if (strcmp(DisplayString(dpy), DisplayString(ctx->display[n].dpy)) == 0) { 2368 DBG(X11, ("%s %s is already connected\n", __func__, name)); 2369 XCloseDisplay(dpy); 2370 return -EBUSY; 2371 } 2372 } 2373 2374 return add_display(ctx, dpy); 2375} 2376 2377static int bumblebee_open(struct context *ctx) 2378{ 2379 char buf[256]; 2380 struct sockaddr_un addr; 2381 int fd, len; 2382 2383 fd = socket(PF_UNIX, SOCK_STREAM, 0); 2384 if (fd < 0) { 2385 DBG(X11, ("%s unable to create a socket: %d\n", __func__, errno)); 2386 return -ECONNREFUSED; 2387 } 2388 2389 addr.sun_family = AF_UNIX; 2390 snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", 2391 optarg && *optarg ? optarg : "/var/run/bumblebee.socket"); 2392 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 2393 DBG(X11, ("%s unable to create a socket: %d\n", __func__, errno)); 2394 goto err; 2395 } 2396 2397 /* Ask bumblebee to start the second server */ 2398 buf[0] = 'C'; 2399 if (send(fd, &buf, 1, 0) != 1 || (len = recv(fd, &buf, 255, 0)) <= 0) { 2400 DBG(X11, ("%s startup send/recv failed: %d\n", __func__, errno)); 2401 goto err; 2402 } 2403 buf[len] = '\0'; 2404 2405 /* Query the display name */ 2406 strcpy(buf, "Q VirtualDisplay"); 2407 if (send(fd, buf, 17, 0) != 17 || (len = recv(fd, buf, 255, 0)) <= 0) { 2408 DBG(X11, ("%s query send/recv failed: %d\n", __func__, errno)); 2409 goto err; 2410 } 2411 buf[len] = '\0'; 2412 2413 DBG(X11, ("%s query result '%s'\n", __func__, buf)); 2414 2415 if (strncmp(buf, "Value: ", 7)) 2416 goto err; 2417 2418 len = 7; 2419 while (buf[len] != '\n' && buf[len] != '\0') 2420 len++; 2421 buf[len] = '\0'; 2422 2423 /* XXX We must keep the control socket open whilst we want to keep 2424 * the display around. 2425 * 2426 * So what we need to do is listen for new bumblee Xservers and 2427 * bind only for their duration. 2428 */ 2429 2430 return display_open(ctx, buf+7); 2431 2432err: 2433 close(fd); 2434 return -ECONNREFUSED; 2435} 2436 2437static int display_init_damage(struct display *display) 2438{ 2439 DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy))); 2440 2441 if (!XDamageQueryExtension(display->dpy, &display->damage_event, &display->damage_error) || 2442 !XFixesQueryExtension(display->dpy, &display->xfixes_event, &display->xfixes_error)) { 2443 fprintf(stderr, "Damage/Fixes extension not supported by %s\n", DisplayString(display->dpy)); 2444 return EINVAL; 2445 } 2446 2447 display->damage = XDamageCreate(display->dpy, display->root, XDamageReportBoundingBox); 2448 if (display->damage == 0) 2449 return EACCES; 2450 2451 return 0; 2452} 2453 2454static void display_reset_damage(struct display *display) 2455{ 2456 Damage damage; 2457 2458 damage = XDamageCreate(display->dpy, display->root, XDamageReportBoundingBox); 2459 if (damage) { 2460 XDamageDestroy(display->dpy, display->damage); 2461 display->damage = damage; 2462 XFlush(display->dpy); 2463 display->flush = 0; 2464 } 2465} 2466 2467static void display_init_randr_hpd(struct display *display) 2468{ 2469 int major, minor; 2470 2471 DBG(X11,("%s(%s)\n", __func__, DisplayString(display->dpy))); 2472 2473 if (!XRRQueryVersion(display->dpy, &major, &minor)) 2474 return; 2475 2476 DBG(X11, ("%s - randr version %d.%d\n", DisplayString(display->dpy), major, minor)); 2477 if (major > 1 || (major == 1 && minor >= 2)) 2478 XRRSelectInput(display->dpy, display->root, RROutputChangeNotifyMask); 2479} 2480 2481static void rebuild_clones(struct context *ctx, struct clone *new_clones) 2482{ 2483 int n, m; 2484 2485 for (n = 1; n < ctx->ndisplay; n++) { 2486 struct display *d = &ctx->display[n]; 2487 2488 d->clone = NULL; 2489 for (m = 0; m < ctx->nclone; m++) { 2490 struct clone *c = &new_clones[m]; 2491 2492 if (c->dst.display != d) 2493 continue; 2494 2495 c->next = d->clone; 2496 d->clone = c; 2497 } 2498 } 2499 2500 ctx->clones = new_clones; 2501} 2502 2503static struct clone *add_clone(struct context *ctx) 2504{ 2505 if (is_power_of_2(ctx->nclone)) { 2506 struct clone *new_clones; 2507 2508 new_clones = realloc(ctx->clones, 2*ctx->nclone*sizeof(struct clone)); 2509 if (new_clones == NULL) 2510 return NULL; 2511 2512 if (new_clones != ctx->clones) 2513 rebuild_clones(ctx, new_clones); 2514 } 2515 2516 return memset(&ctx->clones[ctx->nclone++], 0, sizeof(struct clone)); 2517} 2518 2519static struct display *last_display(struct context *ctx) 2520{ 2521 return &ctx->display[ctx->ndisplay-1]; 2522} 2523 2524static void reverse_clone_list(struct display *display) 2525{ 2526 struct clone *list = NULL; 2527 2528 while (display->clone) { 2529 struct clone *clone = display->clone; 2530 display->clone = clone->next; 2531 clone->next = list; 2532 list = clone; 2533 } 2534 2535 display->clone = list; 2536} 2537 2538static int last_display_add_clones__randr(struct context *ctx) 2539{ 2540 struct display *display = last_display(ctx); 2541 XRRScreenResources *res; 2542 char buf[80]; 2543 int i, ret; 2544 2545 DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy))); 2546 2547 display_init_randr_hpd(display); 2548 2549 /* Force a probe of outputs on initial connection */ 2550 res = XRRGetScreenResources(display->dpy, display->root); 2551 if (res == NULL) 2552 return -ENOMEM; 2553 2554 DBG(X11, ("%s - noutputs=%d\n", DisplayString(display->dpy), res->noutput)); 2555 for (i = 0; i < res->noutput; i++) { 2556 XRROutputInfo *o = XRRGetOutputInfo(display->dpy, res, res->outputs[i]); 2557 struct clone *clone = add_clone(ctx); 2558 RROutput id; 2559 2560 if (clone == NULL) 2561 return -ENOMEM; 2562 2563 clone->depth = 24; 2564 clone->next = display->clone; 2565 display->clone = clone; 2566 2567 id = claim_virtual(ctx->display, buf, ctx->nclone); 2568 if (id == 0) { 2569 fprintf(stderr, "Failed to find available VirtualHead \"%s\" for \"%s\" on display \"%s\"\n", 2570 buf, o->name, DisplayString(display->dpy)); 2571 return -ENOSPC; 2572 } 2573 2574 ret = clone_output_init(clone, &clone->src, ctx->display, buf, id); 2575 if (ret) { 2576 fprintf(stderr, "Failed to add output \"%s\" on display \"%s\"\n", 2577 buf, DisplayString(ctx->display->dpy)); 2578 return ret; 2579 } 2580 2581 ret = clone_output_init(clone, &clone->dst, display, o->name, res->outputs[i]); 2582 if (ret) { 2583 fprintf(stderr, "Failed to add output \"%s\" on display \"%s\"\n", 2584 o->name, DisplayString(display->dpy)); 2585 return ret; 2586 } 2587 2588 ret = clone_init_depth(clone); 2589 if (ret) { 2590 fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n", 2591 DisplayString(display->dpy)); 2592 return ret; 2593 } 2594 2595 ret = clone_update_modes__randr(clone); 2596 if (ret) { 2597 fprintf(stderr, "Failed to clone output \"%s\" from display \"%s\"\n", 2598 o->name, DisplayString(display->dpy)); 2599 return ret; 2600 } 2601 2602 2603 if (o->crtc) { 2604 DBG(X11, ("%s - disabling active output\n", DisplayString(display->dpy))); 2605 disable_crtc(display->dpy, res, o->crtc); 2606 } 2607 2608 XRRFreeOutputInfo(o); 2609 } 2610 XRRFreeScreenResources(res); 2611 2612 reverse_clone_list(display); 2613 return 0; 2614} 2615 2616#if defined(USE_XINERAMA) 2617static int last_display_add_clones__xinerama(struct context *ctx) 2618{ 2619 struct display *display = last_display(ctx); 2620 Display *dpy = display->dpy; 2621 XineramaScreenInfo *xi; 2622 char buf[80]; 2623 int n, count, ret; 2624 2625 DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy))); 2626 2627 count = 0; 2628 xi = XineramaQueryScreens(dpy, &count); 2629 for (n = 0; n < count; n++) { 2630 struct clone *clone = add_clone(ctx); 2631 RROutput id; 2632 2633 if (clone == NULL) 2634 return -ENOMEM; 2635 2636 if (xi[n].width == 0 || xi[n].height == 0) 2637 continue; 2638 2639 clone->depth = 24; 2640 clone->next = display->clone; 2641 display->clone = clone; 2642 2643 id = claim_virtual(ctx->display, buf, ctx->nclone); 2644 if (id == 0) { 2645 fprintf(stderr, "Failed to find available VirtualHead \"%s\" for Xinerama screen %d on display \"%s\"\n", 2646 buf, n, DisplayString(dpy)); 2647 } 2648 ret = clone_output_init(clone, &clone->src, ctx->display, buf, id); 2649 if (ret) { 2650 fprintf(stderr, "Failed to add Xinerama screen %d on display \"%s\"\n", 2651 n, DisplayString(ctx->display->dpy)); 2652 return ret; 2653 } 2654 2655 sprintf(buf, "XINERAMA%d", n); 2656 ret = clone_output_init(clone, &clone->dst, display, buf, 0); 2657 if (ret) { 2658 fprintf(stderr, "Failed to add Xinerama screen %d on display \"%s\"\n", 2659 n, DisplayString(dpy)); 2660 return ret; 2661 } 2662 2663 ret = clone_init_depth(clone); 2664 if (ret) { 2665 fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n", 2666 DisplayString(display->dpy)); 2667 return ret; 2668 } 2669 2670 /* Replace the modes on the local VIRTUAL output with the remote Screen */ 2671 clone->width = xi[n].width; 2672 clone->height = xi[n].height; 2673 clone->dst.x = xi[n].x_org; 2674 clone->dst.y = xi[n].y_org; 2675 clone->dst.rr_crtc = -1; 2676 ret = clone_update_modes__fixed(clone); 2677 if (ret) { 2678 fprintf(stderr, "Failed to clone Xinerama screen %d from display \"%s\"\n", 2679 n, DisplayString(display->dpy)); 2680 return ret; 2681 } 2682 2683 clone->active = ctx->active; 2684 ctx->active = clone; 2685 } 2686 XFree(xi); 2687 2688 reverse_clone_list(display); 2689 return 0; 2690} 2691#else 2692#define last_display_add_clones__xinerama(ctx) -1 2693#endif 2694 2695static int last_display_add_clones__display(struct context *ctx) 2696{ 2697 struct display *display = last_display(ctx); 2698 Display *dpy = display->dpy; 2699 struct clone *clone; 2700 Screen *scr; 2701 char buf[80]; 2702 int ret; 2703 RROutput id; 2704 2705 2706 DBG(X11, ("%s(%s)\n", __func__, DisplayString(dpy))); 2707 clone = add_clone(ctx); 2708 if (clone == NULL) 2709 return -ENOMEM; 2710 2711 clone->depth = 24; 2712 clone->next = display->clone; 2713 display->clone = clone; 2714 2715 id = claim_virtual(ctx->display, buf, ctx->nclone); 2716 if (id == 0) { 2717 fprintf(stderr, "Failed to find available VirtualHead \"%s\" for on display \"%s\"\n", 2718 buf, DisplayString(dpy)); 2719 } 2720 ret = clone_output_init(clone, &clone->src, ctx->display, buf, id); 2721 if (ret) { 2722 fprintf(stderr, "Failed to add display \"%s\"\n", 2723 DisplayString(ctx->display->dpy)); 2724 return ret; 2725 } 2726 2727 sprintf(buf, "WHOLE"); 2728 ret = clone_output_init(clone, &clone->dst, display, buf, 0); 2729 if (ret) { 2730 fprintf(stderr, "Failed to add display \"%s\"\n", 2731 DisplayString(dpy)); 2732 return ret; 2733 } 2734 2735 ret = clone_init_depth(clone); 2736 if (ret) { 2737 fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n", 2738 DisplayString(dpy)); 2739 return ret; 2740 } 2741 2742 /* Replace the modes on the local VIRTUAL output with the remote Screen */ 2743 scr = ScreenOfDisplay(dpy, DefaultScreen(dpy)); 2744 clone->width = scr->width; 2745 clone->height = scr->height; 2746 clone->dst.x = 0; 2747 clone->dst.y = 0; 2748 clone->dst.rr_crtc = -1; 2749 ret = clone_update_modes__fixed(clone); 2750 if (ret) { 2751 fprintf(stderr, "Failed to clone display \"%s\"\n", 2752 DisplayString(dpy)); 2753 return ret; 2754 } 2755 2756 clone->active = ctx->active; 2757 ctx->active = clone; 2758 2759 return 0; 2760} 2761 2762static int last_display_add_clones(struct context *ctx) 2763{ 2764 struct display *display = last_display(ctx); 2765 2766 display->width = DisplayWidth(display->dpy, DefaultScreen(display->dpy)); 2767 display->height = DisplayHeight(display->dpy, DefaultScreen(display->dpy)); 2768 DBG(X11, ("%s - initial size %dx%d\n", DisplayString(display->dpy), display->width, display->height)); 2769 2770 if (display->rr_active) 2771 return last_display_add_clones__randr(ctx); 2772 2773 if (display->xinerama_active) 2774 return last_display_add_clones__xinerama(ctx); 2775 2776 return last_display_add_clones__display(ctx); 2777} 2778 2779static int last_display_clone(struct context *ctx, int fd) 2780{ 2781 fd = add_fd(ctx, fd); 2782 if (fd < 0) 2783 return fd; 2784 2785 fd = last_display_add_clones(ctx); 2786 if (fd) 2787 return fd; 2788 2789 return 0; 2790} 2791 2792static int first_display_has_singleton(struct context *ctx) 2793{ 2794 struct display *display = ctx->display; 2795 unsigned long nitems, bytes; 2796 unsigned char *prop; 2797 int format; 2798 Atom type; 2799 2800 ctx->singleton = XInternAtom(display->dpy, "intel-virtual-output-singleton", False); 2801 2802 XGetWindowProperty(display->dpy, display->root, ctx->singleton, 2803 0, 0, 0, AnyPropertyType, &type, &format, &nitems, &bytes, &prop); 2804 DBG(X11, ("%s: singleton registered? %d\n", DisplayString(display->dpy), type != None)); 2805 return type != None; 2806} 2807 2808static int first_display_wait_for_ack(struct context *ctx, int timeout, int id) 2809{ 2810 struct display *display = ctx->display; 2811 struct pollfd pfd; 2812 char expect[6]; /* "1234R\0" */ 2813 2814 sprintf(expect, "%04xR", id); 2815 DBG(X11, ("%s: wait for act '%c%c%c%c%c'\n", 2816 DisplayString(display->dpy), 2817 expect[0], expect[1], expect[2], expect[3], expect[4])); 2818 2819 XFlush(display->dpy); 2820 2821 pfd.fd = ConnectionNumber(display->dpy); 2822 pfd.events = POLLIN; 2823 do { 2824 if (poll(&pfd, 1, timeout) <= 0) 2825 return -ETIME; 2826 2827 while (XPending(display->dpy)) { 2828 XEvent e; 2829 XClientMessageEvent *cme; 2830 2831 XNextEvent(display->dpy, &e); 2832 DBG(X11, ("%s: reading event type %d\n", DisplayString(display->dpy), e.type)); 2833 2834 if (e.type != ClientMessage) 2835 continue; 2836 2837 cme = (XClientMessageEvent *)&e; 2838 if (cme->message_type != ctx->singleton) 2839 continue; 2840 if (cme->format != 8) 2841 continue; 2842 2843 DBG(X11, ("%s: client message '%c%c%c%c%c'\n", 2844 DisplayString(display->dpy), 2845 cme->data.b[0], 2846 cme->data.b[1], 2847 cme->data.b[2], 2848 cme->data.b[3], 2849 cme->data.b[4])); 2850 if (memcmp(cme->data.b, expect, 5)) 2851 continue; 2852 2853 return -atoi(cme->data.b + 5); 2854 } 2855 } while (1); 2856} 2857 2858#if defined(__GNUC__) && (__GNUC__ > 3) 2859__attribute__((format(gnu_printf, 3, 4))) 2860#endif 2861static int first_display_send_command(struct context *ctx, int timeout, 2862 const char *format, 2863 ...) 2864{ 2865 struct display *display = ctx->display; 2866 char buf[1024], *b; 2867 int len, id; 2868 va_list va; 2869 2870 id = rand() & 0xffff; 2871 sprintf(buf, "%04x", id); 2872 va_start(va, format); 2873 len = vsnprintf(buf+4, sizeof(buf)-4, format, va)+5; 2874 va_end(va); 2875 assert(len < sizeof(buf)); 2876 2877 DBG(X11, ("%s: send command '%s'\n", DisplayString(display->dpy), buf)); 2878 2879 b = buf; 2880 while (len) { 2881 XClientMessageEvent msg; 2882 int n = len; 2883 if (n > sizeof(msg.data.b)) 2884 n = sizeof(msg.data.b); 2885 len -= n; 2886 2887 msg.type = ClientMessage; 2888 msg.serial = 0; 2889 msg.message_type = ctx->singleton; 2890 msg.format = 8; 2891 memcpy(msg.data.b, b, n); 2892 b += n; 2893 2894 XSendEvent(display->dpy, display->root, False, PropertyChangeMask, (XEvent *)&msg); 2895 } 2896 2897 return first_display_wait_for_ack(ctx, timeout, id); 2898} 2899 2900static void first_display_reply(struct context *ctx, int result) 2901{ 2902 struct display *display = ctx->display; 2903 XClientMessageEvent msg; 2904 2905 sprintf(msg.data.b, "%c%c%c%cR%d", 2906 ctx->command[0], 2907 ctx->command[1], 2908 ctx->command[2], 2909 ctx->command[3], 2910 -result); 2911 2912 DBG(X11, ("%s: send reply '%s'\n", DisplayString(display->dpy), msg.data.b)); 2913 2914 msg.type = ClientMessage; 2915 msg.serial = 0; 2916 msg.message_type = ctx->singleton; 2917 msg.format = 8; 2918 2919 XSendEvent(display->dpy, display->root, False, PropertyChangeMask, (XEvent *)&msg); 2920 XFlush(display->dpy); 2921} 2922 2923static void first_display_handle_command(struct context *ctx, 2924 const char *msg) 2925{ 2926 int len; 2927 2928 DBG(X11, ("client message!\n")); 2929 2930 for (len = 0; len < 20 && msg[len]; len++) 2931 ; 2932 2933 if (ctx->command_continuation + len > sizeof(ctx->command)) { 2934 ctx->command_continuation = 0; 2935 return; 2936 } 2937 2938 memcpy(ctx->command + ctx->command_continuation, msg, len); 2939 ctx->command_continuation += len; 2940 2941 if (len < 20) { 2942 ctx->command[ctx->command_continuation] = 0; 2943 DBG(X11, ("client command complete! '%s'\n", ctx->command)); 2944 switch (ctx->command[4]) { 2945 case 'B': 2946 first_display_reply(ctx, last_display_clone(ctx, bumblebee_open(ctx))); 2947 break; 2948 case 'C': 2949 first_display_reply(ctx, last_display_clone(ctx, display_open(ctx, ctx->command + 5))); 2950 break; 2951 case 'P': 2952 first_display_reply(ctx, 0); 2953 break; 2954 case 'R': 2955 break; 2956 } 2957 ctx->command_continuation = 0; 2958 return; 2959 } 2960} 2961 2962static int first_display_register_as_singleton(struct context *ctx) 2963{ 2964 struct display *display = ctx->display; 2965 struct pollfd pfd; 2966 2967 XChangeProperty(display->dpy, display->root, ctx->singleton, 2968 XA_STRING, 8, PropModeReplace, (unsigned char *)".", 1); 2969 XFlush(display->dpy); 2970 2971 /* And eat the notify (presuming that it is ours!) */ 2972 2973 pfd.fd = ConnectionNumber(display->dpy); 2974 pfd.events = POLLIN; 2975 do { 2976 if (poll(&pfd, 1, 1000) <= 0) { 2977 fprintf(stderr, "Failed to register as singleton\n"); 2978 return EBUSY; 2979 } 2980 2981 while (XPending(display->dpy)) { 2982 XEvent e; 2983 2984 XNextEvent(display->dpy, &e); 2985 DBG(X11, ("%s: reading event type %d\n", DisplayString(display->dpy), e.type)); 2986 2987 if (e.type == PropertyNotify && 2988 ((XPropertyEvent *)&e)->atom == ctx->singleton) 2989 return 0; 2990 } 2991 } while (1); 2992} 2993 2994static void display_flush_send(struct display *display) 2995{ 2996 XShmCompletionEvent e; 2997 2998 if (!display->send) 2999 return; 3000 3001 DBG(X11, ("%s flushing send (serial now %ld) (has shm send? %d)\n", 3002 DisplayString(display->dpy), 3003 (long)NextRequest(display->dpy), 3004 display->shm_event)); 3005 3006 display->send = 0; 3007 3008 if (display->shm_event == 0) { 3009 XSync(display->dpy, False); 3010 display->flush = 0; 3011 return; 3012 } 3013 3014 memset(&e, 0, sizeof(e)); 3015 e.type = display->shm_event; 3016 e.send_event = 1; 3017 e.drawable = display->root; 3018 e.major_code = display->shm_opcode; 3019 e.minor_code = X_ShmPutImage; 3020 3021 XSendEvent(display->dpy, display->root, False, 0, (XEvent *)&e); 3022 display_mark_flush(display); 3023} 3024 3025static void display_sync(struct display *display) 3026{ 3027 if (display->skip_clone == 0) 3028 return; 3029 3030 if (display->skip_frame++ < 2) 3031 return; 3032 3033 DBG(X11, ("%s forcing sync\n", DisplayString(display->dpy))); 3034 XSync(display->dpy, False); 3035 3036 display->flush = 0; 3037 display->send = 0; 3038 3039 /* Event tracking proven unreliable, disable */ 3040 display->shm_event = 0; 3041} 3042 3043static void display_flush(struct display *display) 3044{ 3045 display_flush_cursor(display); 3046 display_flush_send(display); 3047 3048 display_sync(display); 3049 3050 if (!display->flush) 3051 return; 3052 3053 DBG(X11, ("%s(%s)\n", __func__, DisplayString(display->dpy))); 3054 3055 XFlush(display->dpy); 3056 display->flush = 0; 3057} 3058 3059static int first_display_first_sibling(struct context *ctx) 3060{ 3061 const char *str, *colon; 3062 int dpy, scr, len; 3063 3064 str = DisplayString(ctx->display->dpy); 3065 colon = strrchr(str, ':'); 3066 if (colon == NULL) 3067 return -1; 3068 3069 if (sscanf(colon + 1, "%d.%d", &dpy, &scr) == 1) 3070 scr = 0; 3071 3072 len = (colon - str) + 1; 3073 memcpy(ctx->command, str, len); 3074 len += sprintf(ctx->command + len, "%d.", dpy); 3075 ctx->command_continuation = len; 3076 3077 return scr + 1; 3078} 3079 3080static int first_display_sibling(struct context *ctx, int i) 3081{ 3082 if (i < 0) 3083 return 0; 3084 3085 sprintf(ctx->command + ctx->command_continuation, "%d", i); 3086 return 1; 3087} 3088 3089#define first_display_for_each_sibling(CTX, i) \ 3090 for (i = first_display_first_sibling(CTX); first_display_sibling(CTX, i); i++) 3091 3092static void display_cleanup(struct display *display) 3093{ 3094 Display *dpy = display->dpy; 3095 XRRScreenResources *res; 3096 int n; 3097 3098 XGrabServer(dpy); 3099 3100 res = _XRRGetScreenResourcesCurrent(dpy, display->root); 3101 if (res != NULL) { 3102 for (n = 0; n < res->ncrtc; n++) 3103 disable_crtc(display->dpy, res, res->crtcs[n]); 3104 3105 XRRFreeScreenResources(res); 3106 } 3107 3108 XUngrabServer(dpy); 3109} 3110 3111static void context_cleanup(struct context *ctx) 3112{ 3113 Display *dpy = ctx->display->dpy; 3114 XRRScreenResources *res; 3115 int i, j; 3116 3117 for (i = 1; i < ctx->ndisplay; i++) 3118 display_cleanup(&ctx->display[i]); 3119 3120 if (dpy == NULL) 3121 return; 3122 3123 res = _XRRGetScreenResourcesCurrent(dpy, ctx->display->root); 3124 if (res == NULL) 3125 return; 3126 3127 XGrabServer(dpy); 3128 3129 for (i = 0; i < ctx->nclone; i++) { 3130 struct clone *clone = &ctx->clones[i]; 3131 XRROutputInfo *output; 3132 3133 assert(clone->src.display == ctx->display); 3134 3135 output = XRRGetOutputInfo(dpy, res, clone->src.rr_output); 3136 if (output == NULL) 3137 continue; 3138 3139 disable_crtc(dpy, res, output->crtc); 3140 for (j = 0; j < output->nmode; j++) 3141 XRRDeleteOutputMode(dpy, clone->src.rr_output, output->modes[j]); 3142 3143 XRRFreeOutputInfo(output); 3144 } 3145 3146 for (i = 0; i < res->nmode; i++) { 3147 if (strncmp(res->modes[i].name, "VIRTUAL", 7) == 0) { 3148 XRRDestroyMode(dpy, res->modes[i].id); 3149 continue; 3150 } 3151 3152 if (strcmp(res->modes[i].name, "ClaimVirtualHead") == 0) { 3153 XRRDestroyMode(dpy, res->modes[i].id); 3154 continue; 3155 } 3156 } 3157 XRRFreeScreenResources(res); 3158 3159 /* And hide them again */ 3160 res = XRRGetScreenResources(dpy, ctx->display->root); 3161 if (res != NULL) 3162 XRRFreeScreenResources(res); 3163 3164 XUngrabServer(dpy); 3165 3166 if (ctx->singleton) 3167 XDeleteProperty(dpy, ctx->display->root, ctx->singleton); 3168 XCloseDisplay(dpy); 3169} 3170 3171static int done; 3172 3173static void signal_handler(int sig) 3174{ 3175 done = sig; 3176} 3177 3178int main(int argc, char **argv) 3179{ 3180 struct context ctx; 3181 const char *src_name = NULL; 3182 uint64_t count; 3183 int daemonize = 1, bumblebee = 0, siblings = 0, singleton = 1; 3184 int i, ret, open, fail; 3185 3186 signal(SIGPIPE, SIG_IGN); 3187 3188 while ((i = getopt(argc, argv, "abd:fhSvV:")) != -1) { 3189 switch (i) { 3190 case 'd': 3191 src_name = optarg; 3192 break; 3193 case 'f': 3194 daemonize = 0; 3195 break; 3196 case 'b': 3197 bumblebee = 1; 3198 break; 3199 case 's': 3200 siblings = 1; 3201 break; 3202 case 'S': 3203 singleton = 0; 3204 break; 3205 case 'v': 3206 verbose = ~0; 3207 daemonize = 0; 3208 break; 3209 case 'V': 3210 verbose = strtol(optarg, NULL, 0); 3211 daemonize = 0; 3212 break; 3213 case 'h': 3214 default: 3215 usage(argv[0]); 3216 exit(0); 3217 } 3218 } 3219 3220 if (verbose) 3221 printf("intel-virtual-output: version %d.%d.%d\n", 3222 PACKAGE_VERSION_MAJOR, 3223 PACKAGE_VERSION_MINOR, 3224 PACKAGE_VERSION_PATCHLEVEL); 3225 3226 ret = context_init(&ctx); 3227 if (ret) 3228 return -ret; 3229 3230 XSetErrorHandler(_check_error_handler); 3231 3232 ret = add_fd(&ctx, display_open(&ctx, src_name)); 3233 if (ret) { 3234 fprintf(stderr, "Unable to connect to \"%s\".\n", src_name ?: getenv("DISPLAY") ?: 3235 "<unspecified>, set either the DISPLAY environment variable or pass -d <display name> on the commandline"); 3236 ret = -ret; 3237 goto out; 3238 } 3239 3240 if (singleton) { 3241 XSelectInput(ctx.display->dpy, ctx.display->root, PropertyChangeMask); 3242 if (first_display_has_singleton(&ctx)) { 3243 DBG(X11, ("%s: pinging singleton\n", DisplayString(ctx.display->dpy))); 3244 ret = first_display_send_command(&ctx, 2000, "P"); 3245 if (ret) { 3246 if (ret != -ETIME) { 3247 ret = -ret; 3248 goto out; 3249 } 3250 DBG(X11, ("No reply from singleton; assuming control\n")); 3251 } else { 3252 DBG(X11, ("%s: singleton active, sending open commands\n", DisplayString(ctx.display->dpy))); 3253 3254 open = fail = 0; 3255 for (i = optind; i < argc; i++) { 3256 ret = first_display_send_command(&ctx, 5000, "C%s", argv[i]); 3257 if (ret && ret != -EBUSY) { 3258 fprintf(stderr, "Unable to connect to \"%s\".\n", argv[i]); 3259 fail++; 3260 } else 3261 open++; 3262 } 3263 if (siblings || (optind == argc && !bumblebee)) { 3264 first_display_for_each_sibling(&ctx, i) { 3265 ret = first_display_send_command(&ctx, 5000, "C%s", ctx.command); 3266 if (ret && ret != -EBUSY) 3267 break; 3268 else 3269 open++; 3270 } 3271 } 3272 if (bumblebee || (optind == argc && !siblings)) { 3273 ret = first_display_send_command(&ctx, 5000, "B"); 3274 if (ret && ret != -EBUSY) { 3275 if (bumblebee) 3276 fprintf(stderr, "Unable to connect to bumblebee.\n"); 3277 fail++; 3278 } else 3279 open++; 3280 } 3281 ret = open || !fail ? 0 : ECONNREFUSED; 3282 goto out; 3283 } 3284 } 3285 ret = first_display_register_as_singleton(&ctx); 3286 if (ret) 3287 goto out; 3288 } 3289 3290 ret = display_init_damage(ctx.display); 3291 if (ret) 3292 goto out; 3293 3294 if ((ctx.display->rr_event | ctx.display->rr_error) == 0) { 3295 fprintf(stderr, "RandR extension not supported by %s\n", DisplayString(ctx.display->dpy)); 3296 ret = EINVAL; 3297 goto out; 3298 } 3299 XRRSelectInput(ctx.display->dpy, ctx.display->root, RRScreenChangeNotifyMask); 3300 XFixesSelectCursorInput(ctx.display->dpy, ctx.display->root, XFixesDisplayCursorNotifyMask); 3301 3302 ret = add_fd(&ctx, record_mouse(&ctx)); 3303 if (ret) { 3304 fprintf(stderr, "XTEST extension not supported by display \"%s\"\n", DisplayString(ctx.display->dpy)); 3305 ret = -ret; 3306 goto out; 3307 } 3308 3309 open = fail = 0; 3310 for (i = optind; i < argc; i++) { 3311 ret = last_display_clone(&ctx, display_open(&ctx, argv[i])); 3312 if (ret && ret != -EBUSY) { 3313 fprintf(stderr, "Unable to connect to \"%s\".\n", argv[i]); 3314 fail++; 3315 } else 3316 open++; 3317 } 3318 if (siblings || (optind == argc && !bumblebee)) { 3319 first_display_for_each_sibling(&ctx, i) { 3320 ret = last_display_clone(&ctx, display_open(&ctx, ctx.command)); 3321 if (ret && ret != -EBUSY) 3322 break; 3323 else 3324 open++; 3325 } 3326 } 3327 if (bumblebee || (optind == argc && !siblings)) { 3328 ret = last_display_clone(&ctx, bumblebee_open(&ctx)); 3329 if (ret && ret != -EBUSY) { 3330 if (bumblebee) 3331 fprintf(stderr, "Unable to connect to bumblebee.\n"); 3332 fail++; 3333 } else 3334 open++; 3335 } 3336 if (open == 0) { 3337 ret = fail ? ECONNREFUSED : 0; 3338 goto out; 3339 } 3340 3341 if (daemonize && daemon(0, 0)) { 3342 ret = EINVAL; 3343 goto out; 3344 } 3345 3346 signal(SIGHUP, signal_handler); 3347 signal(SIGINT, signal_handler); 3348 signal(SIGTERM, signal_handler); 3349 3350 ctx.command_continuation = 0; 3351 while (!done) { 3352 XEvent e; 3353 int reconfigure = 0; 3354 int rr_update = 0; 3355 3356 DBG(POLL, ("polling - enable timer? %d, nfd=%d, ndisplay=%d\n", ctx.timer_active, ctx.nfd, ctx.ndisplay)); 3357 ret = poll(ctx.pfd + !ctx.timer_active, ctx.nfd - !ctx.timer_active, -1); 3358 if (ret <= 0) 3359 break; 3360 3361 /* pfd[0] is the timer, pfd[1] is the local display, pfd[2] is the mouse, pfd[3+] are the remotes */ 3362 3363 DBG(POLL, ("poll reports %d fd awake\n", ret)); 3364 if (ctx.pfd[1].revents || XPending(ctx.display[0].dpy)) { 3365 DBG(POLL,("%s woken up\n", DisplayString(ctx.display[0].dpy))); 3366 do { 3367 XNextEvent(ctx.display->dpy, &e); 3368 3369 if (e.type == ctx.display->damage_event + XDamageNotify ) { 3370 const XDamageNotifyEvent *de = (const XDamageNotifyEvent *)&e; 3371 struct clone *clone; 3372 3373 DBG(DAMAGE, ("%s damaged: (%d, %d)x(%d, %d)\n", 3374 DisplayString(ctx.display->dpy), 3375 de->area.x, de->area.y, de->area.width, de->area.height)); 3376 3377 for (clone = ctx.active; clone; clone = clone->active) 3378 clone_damage(clone, &de->area); 3379 3380 if (ctx.active) 3381 context_enable_timer(&ctx); 3382 } else if (e.type == ctx.display->xfixes_event + XFixesCursorNotify) { 3383 XFixesCursorImage *cur; 3384 3385 DBG(CURSOR, ("%s cursor changed\n", 3386 DisplayString(ctx.display->dpy))); 3387 3388 cur = XFixesGetCursorImage(ctx.display->dpy); 3389 if (cur == NULL) 3390 continue; 3391 3392 for (i = 1; i < ctx.ndisplay; i++) 3393 display_load_visible_cursor(&ctx.display[i], cur); 3394 3395 XFree(cur); 3396 } else if (e.type == ctx.display->rr_event + RRScreenChangeNotify) { 3397 DBG(XRR, ("%s screen changed (reconfigure pending? %d)\n", 3398 DisplayString(ctx.display->dpy), reconfigure)); 3399 reconfigure = 1; 3400 } else if (e.type == PropertyNotify) { 3401 XPropertyEvent *pe = (XPropertyEvent *)&e; 3402 if (pe->atom == ctx.singleton) { 3403 DBG(X11, ("lost control of singleton\n")); 3404 return 0; 3405 } 3406 } else if (e.type == ClientMessage) { 3407 XClientMessageEvent *cme; 3408 3409 DBG(X11, ("%s client message\n", 3410 DisplayString(ctx.display->dpy))); 3411 3412 cme = (XClientMessageEvent *)&e; 3413 if (cme->message_type != ctx.singleton) 3414 continue; 3415 if (cme->format != 8) 3416 continue; 3417 3418 first_display_handle_command(&ctx, cme->data.b); 3419 } else { 3420 DBG(X11, ("unknown event %d\n", e.type)); 3421 } 3422 } while (XEventsQueued(ctx.display->dpy, QueuedAfterReading)); 3423 } 3424 3425 for (i = 1; i < ctx.ndisplay; i++) { 3426 if (ctx.pfd[i+2].revents == 0 && !XPending(ctx.display[i].dpy)) 3427 continue; 3428 3429 DBG(POLL, ("%s woken up\n", DisplayString(ctx.display[i].dpy))); 3430 do { 3431 XNextEvent(ctx.display[i].dpy, &e); 3432 3433 DBG(POLL, ("%s received event %d\n", DisplayString(ctx.display[i].dpy), e.type)); 3434 if (ctx.display[i].rr_active && e.type == ctx.display[i].rr_event + RRNotify) { 3435 XRRNotifyEvent *re = (XRRNotifyEvent *)&e; 3436 3437 DBG(XRR, ("%s received RRNotify, type %d\n", DisplayString(ctx.display[i].dpy), re->subtype)); 3438 if (re->subtype == RRNotify_OutputChange) { 3439 XRROutputPropertyNotifyEvent *ro = (XRROutputPropertyNotifyEvent *)re; 3440 struct clone *clone; 3441 3442 DBG(XRR, ("%s RRNotify_OutputChange, timestamp %ld\n", DisplayString(ctx.display[i].dpy), ro->timestamp)); 3443 for (clone = ctx.display[i].clone; clone; clone = clone->next) { 3444 if (clone->dst.rr_output == ro->output) 3445 rr_update = clone->rr_update = 1; 3446 } 3447 } 3448 } 3449 } while (XEventsQueued(ctx.display[i].dpy, QueuedAfterReading)); 3450 } 3451 3452 if (rr_update) { 3453 for (i = 0; i < ctx.nclone; i++) 3454 clone_update(&ctx.clones[i]); 3455 } 3456 3457 if (reconfigure && context_update(&ctx)) 3458 display_reset_damage(ctx.display); 3459 3460 while (XPending(ctx.record)) /* discard all implicit events */ 3461 XNextEvent(ctx.record, &e); 3462 3463 if (ctx.timer_active && read(ctx.timer, &count, sizeof(count)) > 0) { 3464 struct clone *clone; 3465 3466 DBG(TIMER, ("%s timer expired (count=%ld)\n", DisplayString(ctx.display->dpy), (long)count)); 3467 ret = 0; 3468 3469 if (ctx.active) { 3470 DBG(DAMAGE, ("%s clearing damage\n", DisplayString(ctx.display->dpy))); 3471 XDamageSubtract(ctx.display->dpy, ctx.display->damage, None, None); 3472 ctx.display->flush = 1; 3473 } 3474 3475 for (clone = ctx.active; clone; clone = clone->active) 3476 ret |= clone_paint(clone); 3477 3478 for (i = 0; i < ctx.ndisplay; i++) 3479 display_flush(&ctx.display[i]); 3480 3481 DBG(TIMER, ("%s timer still active? %d\n", DisplayString(ctx.display->dpy), ret != 0)); 3482 ctx.timer_active = ret != 0; 3483 } 3484 } 3485 3486 ret = 0; 3487out: 3488 context_cleanup(&ctx); 3489 return ret; 3490} 3491