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