diff options
Diffstat (limited to 'src/Xpresent.c')
-rw-r--r-- | src/Xpresent.c | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/src/Xpresent.c b/src/Xpresent.c new file mode 100644 index 0000000..ffe82d7 --- /dev/null +++ b/src/Xpresent.c @@ -0,0 +1,481 @@ +/* + * Copyright © 2013 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdint.h> +#include <stdio.h> +#include <X11/Xlib.h> +#include <X11/Xlibint.h> +#include <X11/Xutil.h> + +#include <X11/extensions/extutil.h> +#include <X11/extensions/geproto.h> +#include <X11/extensions/ge.h> +#include <X11/extensions/Xge.h> + +#include <X11/extensions/Xpresent.h> +#include <X11/extensions/presentproto.h> + +typedef struct _XPresentExtDisplayInfo { + struct _XPresentExtDisplayInfo *next; /* keep a linked list */ + Display *display; /* which display this is */ + XExtCodes *codes; /* the extension protocol codes */ + int major_version; /* -1 means we don't know */ + int minor_version; /* -1 means we don't know */ +} XPresentExtDisplayInfo; + +/* replaces XExtensionInfo */ +typedef struct _XPresentExtInfo { + XPresentExtDisplayInfo *head; /* start of the list */ + XPresentExtDisplayInfo *cur; /* most recently used */ + int ndisplays; /* number of displays */ +} XPresentExtInfo; + +extern XPresentExtInfo XPresentExtensionInfo; +extern char XPresentExtensionName[]; + +XPresentExtDisplayInfo * +XPresentFindDisplay (Display *dpy); + +#define XPresentHasExtension(i) ((i) && ((i)->codes)) + +#define XPresentCheckExtension(dpy,i,val) \ + if (!XPresentHasExtension(i)) { return val; } + +#define XPresentSimpleCheckExtension(dpy,i) \ + if (!XPresentHasExtension(i)) { return; } + +XPresentExtInfo XPresentExtensionInfo; +char XPresentExtensionName[] = PRESENT_NAME; + +static int +XPresentCloseDisplay (Display *dpy, XExtCodes *codes); + +static Bool +XPresentCopyCookie(Display *dpy, + XGenericEventCookie *in, + XGenericEventCookie *out) +{ + int ret = True; + XPresentExtDisplayInfo *info = XPresentFindDisplay(dpy); + + if (in->extension != info->codes->major_opcode) + { + printf("XFixesCopyCookie: wrong extension opcode %d\n", + in->extension); + return False; + } + + *out = *in; + out->data = NULL; + out->cookie = 0; + + switch(in->evtype) { + case PresentConfigureNotify: + case PresentCompleteNotify: + case PresentRedirectNotify: + break; + default: + printf("XPresentCopyCookie: unknown evtype %d\n", in->evtype); + ret = False; + } + + if (!ret) + printf("XPresentCopyCookie: Failed to copy evtype %d", in->evtype); + return ret; +} + +static Bool +XPresentWireToCookie(Display *dpy, + XGenericEventCookie *cookie, + xEvent *wire_event) +{ + XPresentExtDisplayInfo *info = XPresentFindDisplay(dpy); + xGenericEvent *ge = (xGenericEvent*)wire_event; + + if (ge->extension != info->codes->major_opcode) + { + printf("XInputWireToCookie: wrong extension opcode %d\n", + ge->extension); + return False; + } + + cookie->type = ge->type & 0x7f; + cookie->serial = _XSetLastRequestRead(dpy, (xGenericReply *) ge); + cookie->send_event = ((ge->type & 0x80) != 0); + cookie->display = dpy; + cookie->extension = ge->extension; + cookie->evtype = ge->evtype; + + switch(ge->evtype) { + case PresentConfigureNotify: { + xPresentConfigureNotify *proto = (xPresentConfigureNotify *) ge; + XPresentConfigureNotifyEvent *ce = malloc (sizeof (XPresentConfigureNotifyEvent)); + cookie->data = ce; + + ce->type = cookie->type; + ce->serial = cookie->serial; + ce->send_event = cookie->send_event; + ce->display = cookie->display; + ce->extension = cookie->extension; + ce->evtype = cookie->evtype; + + ce->eid = proto->eid; + ce->window = proto->window; + ce->x = proto->x; + ce->y = proto->y; + ce->width = proto->width; + ce->height = proto->height; + ce->off_x = proto->off_x; + ce->off_y = proto->off_y; + ce->pixmap_width = proto->pixmap_width; + ce->pixmap_height = proto->pixmap_height; + ce->pixmap_flags = proto->pixmap_flags; + + break; + } + case PresentCompleteNotify: { + xPresentCompleteNotify *proto = (xPresentCompleteNotify *) ge; + XPresentCompleteNotifyEvent *ce = malloc (sizeof (XPresentCompleteNotifyEvent)); + cookie->data = ce; + + ce->type = cookie->type; + ce->serial = cookie->serial; + ce->send_event = cookie->send_event; + ce->display = cookie->display; + ce->extension = cookie->extension; + ce->evtype = cookie->evtype; + + ce->eid = proto->eid; + ce->window = proto->window; + ce->serial_number = proto->serial; + ce->ust = proto->ust; + ce->msc = proto->msc; + + break; + } + case PresentRedirectNotify: + break; + default: + printf("XPresentWireToCookie: Unknown generic event. type %d\n", ge->evtype); + + } + return False; +} + +/* + * XPresentExtAddDisplay - add a display to this extension. (Replaces + * XextAddDisplay) + */ +static XPresentExtDisplayInfo * +XPresentExtAddDisplay (XPresentExtInfo *extinfo, + Display *dpy, + char *ext_name) +{ + XPresentExtDisplayInfo *info; + + info = (XPresentExtDisplayInfo *) Xmalloc (sizeof (XPresentExtDisplayInfo)); + if (!info) return NULL; + info->display = dpy; + + info->codes = XInitExtension (dpy, ext_name); + + /* + * if the server has the extension, then we can initialize the + * appropriate function vectors + */ + if (info->codes) { + xPresentQueryVersionReply rep; + xPresentQueryVersionReq *req; + + XESetCloseDisplay (dpy, info->codes->extension, XPresentCloseDisplay); + + XESetWireToEventCookie(dpy, info->codes->major_opcode, XPresentWireToCookie); + XESetCopyEventCookie(dpy, info->codes->major_opcode, XPresentCopyCookie); + + /* + * Get the version info + */ + LockDisplay (dpy); + GetReq (PresentQueryVersion, req); + req->reqType = info->codes->major_opcode; + req->presentReqType = X_PresentQueryVersion; + req->majorVersion = PRESENT_MAJOR; + req->minorVersion = PRESENT_MINOR; + if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) + { + UnlockDisplay (dpy); + SyncHandle (); + Xfree(info); + return NULL; + } + info->major_version = rep.majorVersion; + info->minor_version = rep.minorVersion; + UnlockDisplay (dpy); + SyncHandle (); + } else { + /* The server doesn't have this extension. + * Use a private Xlib-internal extension to hang the close_display + * hook on so that the "cache" (extinfo->cur) is properly cleaned. + * (XBUG 7955) + */ + XExtCodes *codes = XAddExtension(dpy); + if (!codes) { + XFree(info); + return NULL; + } + XESetCloseDisplay (dpy, codes->extension, XPresentCloseDisplay); + } + + /* + * now, chain it onto the list + */ + _XLockMutex(_Xglobal_lock); + info->next = extinfo->head; + extinfo->head = info; + extinfo->cur = info; + extinfo->ndisplays++; + _XUnlockMutex(_Xglobal_lock); + return info; +} + + +/* + * XPresentExtRemoveDisplay - remove the indicated display from the + * extension object. (Replaces XextRemoveDisplay.) + */ +static int +XPresentExtRemoveDisplay (XPresentExtInfo *extinfo, Display *dpy) +{ + XPresentExtDisplayInfo *info, *prev; + + /* + * locate this display and its back link so that it can be removed + */ + _XLockMutex(_Xglobal_lock); + prev = NULL; + for (info = extinfo->head; info; info = info->next) { + if (info->display == dpy) break; + prev = info; + } + if (!info) { + _XUnlockMutex(_Xglobal_lock); + return 0; /* hmm, actually an error */ + } + + /* + * remove the display from the list; handles going to zero + */ + if (prev) + prev->next = info->next; + else + extinfo->head = info->next; + + extinfo->ndisplays--; + if (info == extinfo->cur) extinfo->cur = NULL; /* flush cache */ + _XUnlockMutex(_Xglobal_lock); + + Xfree ((char *) info); + return 1; +} + +/* + * XPresentExtFindDisplay - look for a display in this extension; keeps a + * cache of the most-recently used for efficiency. (Replaces + * XextFindDisplay.) + */ +static XPresentExtDisplayInfo * +XPresentExtFindDisplay (XPresentExtInfo *extinfo, + Display *dpy) +{ + XPresentExtDisplayInfo *info; + + /* + * see if this was the most recently accessed display + */ + if ((info = extinfo->cur) && info->display == dpy) + return info; + + /* + * look for display in list + */ + _XLockMutex(_Xglobal_lock); + for (info = extinfo->head; info; info = info->next) { + if (info->display == dpy) { + extinfo->cur = info; /* cache most recently used */ + _XUnlockMutex(_Xglobal_lock); + return info; + } + } + _XUnlockMutex(_Xglobal_lock); + + return NULL; +} + +XPresentExtDisplayInfo * +XPresentFindDisplay (Display *dpy) +{ + XPresentExtDisplayInfo *info; + + info = XPresentExtFindDisplay (&XPresentExtensionInfo, dpy); + if (!info) + info = XPresentExtAddDisplay (&XPresentExtensionInfo, dpy, + XPresentExtensionName); + return info; +} + +static int +XPresentCloseDisplay (Display *dpy, XExtCodes *codes) +{ + return XPresentExtRemoveDisplay (&XPresentExtensionInfo, dpy); +} + +Bool +XPresentQueryExtension (Display *dpy, + int *major_opcode_return, + int *event_base_return, + int *error_base_return) +{ + XPresentExtDisplayInfo *info = XPresentFindDisplay (dpy); + + if (XPresentHasExtension(info)) + { + if (major_opcode_return) + *major_opcode_return = info->codes->major_opcode; + if (event_base_return) + *event_base_return = info->codes->first_event; + if (error_base_return) + *error_base_return = info->codes->first_error; + return True; + } + else + return False; +} + +Status +XPresentQueryVersion (Display *dpy, + int *major_version_return, + int *minor_version_return) +{ + XPresentExtDisplayInfo *info = XPresentFindDisplay (dpy); + + XPresentCheckExtension (dpy, info, 0); + + *major_version_return = info->major_version; + *minor_version_return = info->minor_version; + return 1; +} + +int +XPresentVersion (void) +{ + return PRESENT_VERSION; +} + +void +XPresentRegion(Display *dpy, + Window window, + Pixmap pixmap, + uint32_t serial, + XserverRegion valid, + XserverRegion update, + int x_off, + int y_off, + XID idle_fence, + uint64_t target_msc, + uint64_t divisor, + uint64_t remainder) +{ + XPresentExtDisplayInfo *info = XPresentFindDisplay (dpy); + xPresentRegionReq *req; + + XPresentSimpleCheckExtension (dpy, info); + + LockDisplay (dpy); + GetReq(PresentRegion, req); + req->reqType = info->codes->major_opcode; + req->presentReqType = X_PresentRegion; + req->window = window; + req->pixmap = pixmap; + req->serial = serial; + req->valid = valid; + req->update = update; + req->x_off = x_off; + req->y_off = y_off; + req->idle_fence = idle_fence; + req->target_msc = target_msc; + req->divisor = divisor; + req->remainder = remainder; + UnlockDisplay (dpy); + SyncHandle(); +} + +void +XPresentNotifyMSC(Display *dpy, + Window window, + uint32_t serial, + uint64_t target_msc, + uint64_t divisor, + uint64_t remainder) +{ + XPresentExtDisplayInfo *info = XPresentFindDisplay (dpy); + xPresentNotifyMSCReq *req; + + XPresentSimpleCheckExtension (dpy, info); + + LockDisplay (dpy); + GetReq(PresentNotifyMSC, req); + req->reqType = info->codes->major_opcode; + req->presentReqType = X_PresentNotifyMSC; + req->window = window; + req->serial = serial; + req->target_msc = target_msc; + req->divisor = divisor; + req->remainder = remainder; + UnlockDisplay (dpy); + SyncHandle(); +} + +XID +XPresentSelectInput(Display *dpy, + Window window, + unsigned event_mask) +{ + XPresentExtDisplayInfo *info = XPresentFindDisplay (dpy); + XID eid; + xPresentSelectInputReq *req; + + XPresentCheckExtension (dpy, info, 0); + LockDisplay (dpy); + GetReq(PresentSelectInput, req); + req->reqType = info->codes->major_opcode; + req->presentReqType = X_PresentSelectInput; + req->eid = eid = XAllocID(dpy); + req->window = window; + req->eventMask = event_mask; + UnlockDisplay (dpy); + SyncHandle(); + return eid; +} |