1 /* 2 * Copyright 2013 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of the copyright holders not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. The copyright holders make no representations 11 * about the suitability of this software for any purpose. It is provided "as 12 * is" without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 * OF THIS SOFTWARE. 21 */ 22 23 #ifdef HAVE_CONFIG_H 24 #include <config.h> 25 #endif 26 27 #include <stdint.h> 28 #include <stdio.h> 29 #include <X11/Xlib.h> 30 #include <X11/Xlibint.h> 31 #include <X11/Xutil.h> 32 33 #include <X11/extensions/extutil.h> 34 #include <X11/extensions/geproto.h> 35 #include <X11/extensions/ge.h> 36 #include <X11/extensions/Xge.h> 37 38 #include <X11/extensions/Xpresent.h> 39 #include <X11/extensions/presentproto.h> 40 41 typedef struct _XPresentExtDisplayInfo { 42 struct _XPresentExtDisplayInfo *next; /* keep a linked list */ 43 Display *display; /* which display this is */ 44 XExtCodes *codes; /* the extension protocol codes */ 45 int major_version; /* -1 means we don't know */ 46 int minor_version; /* -1 means we don't know */ 47 } XPresentExtDisplayInfo; 48 49 /* replaces XExtensionInfo */ 50 typedef struct _XPresentExtInfo { 51 XPresentExtDisplayInfo *head; /* start of the list */ 52 XPresentExtDisplayInfo *cur; /* most recently used */ 53 int ndisplays; /* number of displays */ 54 } XPresentExtInfo; 55 56 extern XPresentExtInfo XPresentExtensionInfo; 57 extern char XPresentExtensionName[]; 58 59 XPresentExtDisplayInfo * 60 XPresentFindDisplay (Display *dpy); 61 62 #define XPresentHasExtension(i) ((i) && ((i)->codes)) 63 64 #define XPresentCheckExtension(dpy,i,val) \ 65 if (!XPresentHasExtension(i)) { return val; } 66 67 #define XPresentSimpleCheckExtension(dpy,i) \ 68 if (!XPresentHasExtension(i)) { return; } 69 70 XPresentExtInfo XPresentExtensionInfo; 71 char XPresentExtensionName[] = PRESENT_NAME; 72 73 static int 74 XPresentCloseDisplay (Display *dpy, XExtCodes *codes); 75 76 static Bool 77 XPresentCopyCookie(Display *dpy, 78 XGenericEventCookie *in, 79 XGenericEventCookie *out) 80 { 81 int ret = True; 82 XPresentExtDisplayInfo *info = XPresentFindDisplay(dpy); 83 84 if (in->extension != info->codes->major_opcode) 85 { 86 printf("XFixesCopyCookie: wrong extension opcode %d\n", 87 in->extension); 88 return False; 89 } 90 91 *out = *in; 92 out->data = NULL; 93 out->cookie = 0; 94 95 switch(in->evtype) { 96 case PresentConfigureNotify: 97 case PresentCompleteNotify: 98 #if PRESENT_FUTURE_VERSION 99 case PresentRedirectNotify: 100 #endif 101 break; 102 default: 103 printf("XPresentCopyCookie: unknown evtype %d\n", in->evtype); 104 ret = False; 105 } 106 107 if (!ret) 108 printf("XPresentCopyCookie: Failed to copy evtype %d", in->evtype); 109 return ret; 110 } 111 112 static Bool 113 XPresentWireToCookie(Display *dpy, 114 XGenericEventCookie *cookie, 115 xEvent *wire_event) 116 { 117 XPresentExtDisplayInfo *info = XPresentFindDisplay(dpy); 118 xGenericEvent *ge = (xGenericEvent*)wire_event; 119 120 if (ge->extension != info->codes->major_opcode) 121 { 122 printf("XInputWireToCookie: wrong extension opcode %d\n", 123 ge->extension); 124 return False; 125 } 126 127 cookie->type = ge->type & 0x7f; 128 cookie->serial = _XSetLastRequestRead(dpy, (xGenericReply *) ge); 129 cookie->send_event = ((ge->type & 0x80) != 0); 130 cookie->display = dpy; 131 cookie->extension = ge->extension; 132 cookie->evtype = ge->evtype; 133 134 switch(ge->evtype) { 135 case PresentConfigureNotify: { 136 xPresentConfigureNotify *proto = (xPresentConfigureNotify *) ge; 137 XPresentConfigureNotifyEvent *ce = malloc (sizeof (XPresentConfigureNotifyEvent)); 138 cookie->data = ce; 139 if (ce == NULL) 140 break; 141 142 ce->type = cookie->type; 143 ce->serial = cookie->serial; 144 ce->send_event = cookie->send_event; 145 ce->display = cookie->display; 146 ce->extension = cookie->extension; 147 ce->evtype = cookie->evtype; 148 149 ce->eid = proto->eid; 150 ce->window = proto->window; 151 ce->x = proto->x; 152 ce->y = proto->y; 153 ce->width = proto->width; 154 ce->height = proto->height; 155 ce->off_x = proto->off_x; 156 ce->off_y = proto->off_y; 157 ce->pixmap_width = proto->pixmap_width; 158 ce->pixmap_height = proto->pixmap_height; 159 ce->pixmap_flags = proto->pixmap_flags; 160 161 break; 162 } 163 case PresentCompleteNotify: { 164 xPresentCompleteNotify *proto = (xPresentCompleteNotify *) ge; 165 XPresentCompleteNotifyEvent *ce = malloc (sizeof (XPresentCompleteNotifyEvent)); 166 cookie->data = ce; 167 if (ce == NULL) 168 break; 169 170 ce->type = cookie->type; 171 ce->serial = cookie->serial; 172 ce->send_event = cookie->send_event; 173 ce->display = cookie->display; 174 ce->extension = cookie->extension; 175 ce->evtype = cookie->evtype; 176 177 ce->eid = proto->eid; 178 ce->window = proto->window; 179 ce->serial_number = proto->serial; 180 ce->ust = proto->ust; 181 ce->msc = proto->msc; 182 ce->kind = proto->kind; 183 ce->mode = proto->mode; 184 185 break; 186 } 187 case PresentIdleNotify: { 188 xPresentIdleNotify *proto = (xPresentIdleNotify *) ge; 189 XPresentIdleNotifyEvent *ce = malloc (sizeof (XPresentIdleNotifyEvent)); 190 cookie->data = ce; 191 if (ce == NULL) 192 break; 193 194 ce->type = cookie->type; 195 ce->serial = cookie->serial; 196 ce->send_event = cookie->send_event; 197 ce->display = cookie->display; 198 ce->extension = cookie->extension; 199 ce->evtype = cookie->evtype; 200 201 ce->eid = proto->eid; 202 ce->window = proto->window; 203 ce->serial_number = proto->serial; 204 ce->pixmap = proto->pixmap; 205 ce->idle_fence = proto->idle_fence; 206 207 break; 208 } 209 #if PRESENT_FUTURE_VERSION 210 case PresentRedirectNotify: { 211 xPresentRedirectNotify *proto = (xPresentRedirectNotify *) ge; 212 xPresentNotify *xNotify = (xPresentNotify *) (proto + 1); 213 int nnotifies = (((proto->length + 8) - (sizeof (xPresentRedirectNotify) >> 2))) >> 1; 214 XPresentRedirectNotifyEvent *re = malloc (sizeof (XPresentRedirectNotifyEvent) + nnotifies * sizeof (XPresentNotify)); 215 XPresentNotify *XNotify = (XPresentNotify *) (re + 1); 216 int i; 217 cookie->data = re; 218 if (re == NULL) 219 break; 220 221 re->type = cookie->type; 222 re->serial = cookie->serial; 223 re->send_event = cookie->send_event; 224 re->display = cookie->display; 225 re->extension = cookie->extension; 226 re->evtype = cookie->evtype; 227 228 re->eid = proto->eid; 229 re->event_window = proto->event_window; 230 231 re->window = proto->window; 232 re->pixmap = proto->pixmap; 233 re->serial_number = proto->serial; 234 235 re->valid_region = proto->valid_region; 236 re->update_region = proto->update_region; 237 238 re->valid_rect = *(XRectangle *) &(proto->valid_rect); 239 re->update_rect = *(XRectangle *) &(proto->update_rect); 240 241 re->x_off = proto->x_off; 242 re->y_off = proto->y_off; 243 re->target_crtc = proto->target_crtc; 244 245 re->wait_fence = proto->wait_fence; 246 re->idle_fence = proto->idle_fence; 247 248 re->options = proto->options; 249 250 re->target_msc = proto->target_msc; 251 re->divisor = proto->divisor; 252 re->remainder = proto->remainder; 253 254 re->nnotifies = nnotifies; 255 re->notifies = XNotify; 256 for (i = 0; i < nnotifies; i++) { 257 XNotify[i].window = xNotify[i].window; 258 XNotify[i].serial = xNotify[i].serial; 259 } 260 break; 261 } 262 #endif 263 default: 264 printf("XPresentWireToCookie: Unknown generic event. type %d\n", ge->evtype); 265 266 } 267 return False; 268 } 269 270 /* 271 * XPresentExtAddDisplay - add a display to this extension. (Replaces 272 * XextAddDisplay) 273 */ 274 static XPresentExtDisplayInfo * 275 XPresentExtAddDisplay (XPresentExtInfo *extinfo, 276 Display *dpy, 277 char *ext_name) 278 { 279 XPresentExtDisplayInfo *info; 280 281 info = (XPresentExtDisplayInfo *) Xmalloc (sizeof (XPresentExtDisplayInfo)); 282 if (!info) return NULL; 283 info->display = dpy; 284 285 info->codes = XInitExtension (dpy, ext_name); 286 287 /* 288 * if the server has the extension, then we can initialize the 289 * appropriate function vectors 290 */ 291 if (info->codes) { 292 xPresentQueryVersionReply rep; 293 xPresentQueryVersionReq *req; 294 295 XESetCloseDisplay (dpy, info->codes->extension, XPresentCloseDisplay); 296 297 XESetWireToEventCookie(dpy, info->codes->major_opcode, XPresentWireToCookie); 298 XESetCopyEventCookie(dpy, info->codes->major_opcode, XPresentCopyCookie); 299 300 /* 301 * Get the version info 302 */ 303 LockDisplay (dpy); 304 GetReq (PresentQueryVersion, req); 305 req->reqType = info->codes->major_opcode; 306 req->presentReqType = X_PresentQueryVersion; 307 req->majorVersion = PRESENT_MAJOR; 308 req->minorVersion = PRESENT_MINOR; 309 if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) 310 { 311 UnlockDisplay (dpy); 312 SyncHandle (); 313 Xfree(info); 314 return NULL; 315 } 316 info->major_version = rep.majorVersion; 317 info->minor_version = rep.minorVersion; 318 UnlockDisplay (dpy); 319 SyncHandle (); 320 } else { 321 /* The server doesn't have this extension. 322 * Use a private Xlib-internal extension to hang the close_display 323 * hook on so that the "cache" (extinfo->cur) is properly cleaned. 324 * (XBUG 7955) 325 */ 326 XExtCodes *codes = XAddExtension(dpy); 327 if (!codes) { 328 XFree(info); 329 return NULL; 330 } 331 XESetCloseDisplay (dpy, codes->extension, XPresentCloseDisplay); 332 } 333 334 /* 335 * now, chain it onto the list 336 */ 337 _XLockMutex(_Xglobal_lock); 338 info->next = extinfo->head; 339 extinfo->head = info; 340 extinfo->cur = info; 341 extinfo->ndisplays++; 342 _XUnlockMutex(_Xglobal_lock); 343 return info; 344 } 345 346 347 /* 348 * XPresentExtRemoveDisplay - remove the indicated display from the 349 * extension object. (Replaces XextRemoveDisplay.) 350 */ 351 static int 352 XPresentExtRemoveDisplay (XPresentExtInfo *extinfo, Display *dpy) 353 { 354 XPresentExtDisplayInfo *info, *prev; 355 356 /* 357 * locate this display and its back link so that it can be removed 358 */ 359 _XLockMutex(_Xglobal_lock); 360 prev = NULL; 361 for (info = extinfo->head; info; info = info->next) { 362 if (info->display == dpy) break; 363 prev = info; 364 } 365 if (!info) { 366 _XUnlockMutex(_Xglobal_lock); 367 return 0; /* hmm, actually an error */ 368 } 369 370 /* 371 * remove the display from the list; handles going to zero 372 */ 373 if (prev) 374 prev->next = info->next; 375 else 376 extinfo->head = info->next; 377 378 extinfo->ndisplays--; 379 if (info == extinfo->cur) extinfo->cur = NULL; /* flush cache */ 380 _XUnlockMutex(_Xglobal_lock); 381 382 Xfree ((char *) info); 383 return 1; 384 } 385 386 /* 387 * XPresentExtFindDisplay - look for a display in this extension; keeps a 388 * cache of the most-recently used for efficiency. (Replaces 389 * XextFindDisplay.) 390 */ 391 static XPresentExtDisplayInfo * 392 XPresentExtFindDisplay (XPresentExtInfo *extinfo, 393 Display *dpy) 394 { 395 XPresentExtDisplayInfo *info; 396 397 /* 398 * see if this was the most recently accessed display 399 */ 400 if ((info = extinfo->cur) && info->display == dpy) 401 return info; 402 403 /* 404 * look for display in list 405 */ 406 _XLockMutex(_Xglobal_lock); 407 for (info = extinfo->head; info; info = info->next) { 408 if (info->display == dpy) { 409 extinfo->cur = info; /* cache most recently used */ 410 _XUnlockMutex(_Xglobal_lock); 411 return info; 412 } 413 } 414 _XUnlockMutex(_Xglobal_lock); 415 416 return NULL; 417 } 418 419 XPresentExtDisplayInfo * 420 XPresentFindDisplay (Display *dpy) 421 { 422 XPresentExtDisplayInfo *info; 423 424 info = XPresentExtFindDisplay (&XPresentExtensionInfo, dpy); 425 if (!info) 426 info = XPresentExtAddDisplay (&XPresentExtensionInfo, dpy, 427 XPresentExtensionName); 428 return info; 429 } 430 431 static int 432 XPresentCloseDisplay (Display *dpy, XExtCodes *codes) 433 { 434 return XPresentExtRemoveDisplay (&XPresentExtensionInfo, dpy); 435 } 436 437 Bool 438 XPresentQueryExtension (Display *dpy, 439 int *major_opcode_return, 440 int *event_base_return, 441 int *error_base_return) 442 { 443 XPresentExtDisplayInfo *info = XPresentFindDisplay (dpy); 444 445 if (XPresentHasExtension(info)) 446 { 447 if (major_opcode_return) 448 *major_opcode_return = info->codes->major_opcode; 449 if (event_base_return) 450 *event_base_return = info->codes->first_event; 451 if (error_base_return) 452 *error_base_return = info->codes->first_error; 453 return True; 454 } 455 else 456 return False; 457 } 458 459 Status 460 XPresentQueryVersion (Display *dpy, 461 int *major_version_return, 462 int *minor_version_return) 463 { 464 XPresentExtDisplayInfo *info = XPresentFindDisplay (dpy); 465 466 XPresentCheckExtension (dpy, info, 0); 467 468 *major_version_return = info->major_version; 469 *minor_version_return = info->minor_version; 470 return 1; 471 } 472 473 int 474 XPresentVersion (void) 475 { 476 return PRESENT_VERSION; 477 } 478 479 void 480 XPresentPixmap(Display *dpy, 481 Window window, 482 Pixmap pixmap, 483 uint32_t serial, 484 XserverRegion valid, 485 XserverRegion update, 486 int x_off, 487 int y_off, 488 RRCrtc target_crtc, 489 XSyncFence wait_fence, 490 XSyncFence idle_fence, 491 uint32_t options, 492 uint64_t target_msc, 493 uint64_t divisor, 494 uint64_t remainder, 495 XPresentNotify *notifies, 496 int nnotifies) 497 { 498 XPresentExtDisplayInfo *info = XPresentFindDisplay (dpy); 499 xPresentPixmapReq *req; 500 long len = ((long) nnotifies) << 1; 501 502 XPresentSimpleCheckExtension (dpy, info); 503 504 LockDisplay (dpy); 505 GetReq(PresentPixmap, req); 506 req->reqType = info->codes->major_opcode; 507 req->presentReqType = X_PresentPixmap; 508 req->window = window; 509 req->pixmap = pixmap; 510 req->serial = serial; 511 req->valid = valid; 512 req->update = update; 513 req->x_off = x_off; 514 req->y_off = y_off; 515 req->target_crtc = target_crtc; 516 req->wait_fence = wait_fence; 517 req->idle_fence = idle_fence; 518 req->options = options; 519 req->target_msc = target_msc; 520 req->divisor = divisor; 521 req->remainder = remainder; 522 SetReqLen(req, len, len); 523 Data32(dpy, (CARD32 *) notifies, len); 524 UnlockDisplay (dpy); 525 SyncHandle(); 526 } 527 528 void 529 XPresentNotifyMSC(Display *dpy, 530 Window window, 531 uint32_t serial, 532 uint64_t target_msc, 533 uint64_t divisor, 534 uint64_t remainder) 535 { 536 XPresentExtDisplayInfo *info = XPresentFindDisplay (dpy); 537 xPresentNotifyMSCReq *req; 538 539 XPresentSimpleCheckExtension (dpy, info); 540 541 LockDisplay (dpy); 542 GetReq(PresentNotifyMSC, req); 543 req->reqType = info->codes->major_opcode; 544 req->presentReqType = X_PresentNotifyMSC; 545 req->window = window; 546 req->serial = serial; 547 req->target_msc = target_msc; 548 req->divisor = divisor; 549 req->remainder = remainder; 550 UnlockDisplay (dpy); 551 SyncHandle(); 552 } 553 554 XID 555 XPresentSelectInput(Display *dpy, 556 Window window, 557 unsigned event_mask) 558 { 559 XPresentExtDisplayInfo *info = XPresentFindDisplay (dpy); 560 XID eid; 561 xPresentSelectInputReq *req; 562 563 XPresentCheckExtension (dpy, info, 0); 564 LockDisplay (dpy); 565 GetReq(PresentSelectInput, req); 566 req->reqType = info->codes->major_opcode; 567 req->presentReqType = X_PresentSelectInput; 568 req->eid = eid = XAllocID(dpy); 569 req->window = window; 570 req->eventMask = event_mask; 571 UnlockDisplay (dpy); 572 SyncHandle(); 573 return eid; 574 } 575 576 void 577 XPresentFreeInput(Display *dpy, 578 Window window, 579 XID event_id) 580 { 581 XPresentExtDisplayInfo *info = XPresentFindDisplay (dpy); 582 xPresentSelectInputReq *req; 583 584 XPresentSimpleCheckExtension (dpy, info); 585 LockDisplay (dpy); 586 GetReq(PresentSelectInput, req); 587 req->reqType = info->codes->major_opcode; 588 req->presentReqType = X_PresentSelectInput; 589 req->eid = event_id; 590 req->window = window; 591 req->eventMask = 0; 592 UnlockDisplay (dpy); 593 SyncHandle(); 594 } 595 596 uint32_t 597 XPresentQueryCapabilities(Display *dpy, 598 XID target) 599 { 600 XPresentExtDisplayInfo *info = XPresentFindDisplay (dpy); 601 xPresentQueryCapabilitiesReq *req; 602 xPresentQueryCapabilitiesReply rep; 603 604 XPresentCheckExtension (dpy, info, 0); 605 LockDisplay (dpy); 606 GetReq(PresentQueryCapabilities, req); 607 req->reqType = info->codes->major_opcode; 608 req->presentReqType = X_PresentQueryCapabilities; 609 req->target = target; 610 611 if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) { 612 UnlockDisplay (dpy); 613 SyncHandle (); 614 return 0; 615 } 616 617 UnlockDisplay (dpy); 618 SyncHandle(); 619 return rep.capabilities; 620 } 621 622