Home | History | Annotate | Line # | Download | only in src
      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