Edit

IABSD.fr/xenocara/lib/libXpresent/src/Xpresent.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2025-10-26 09:59:34
    Hash : 1cfb4088
    Message : Update to libXpresent 1.0.2

  • lib/libXpresent/src/Xpresent.c
  • /*
     * 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:
    #if PRESENT_FUTURE_VERSION
        case PresentRedirectNotify:
    #endif
            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;
            if (ce == NULL)
                break;
    
            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;
            if (ce == NULL)
                break;
    
            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;
            ce->kind = proto->kind;
            ce->mode = proto->mode;
    
            break;
        }
        case PresentIdleNotify: {
            xPresentIdleNotify *proto = (xPresentIdleNotify *) ge;
            XPresentIdleNotifyEvent *ce = malloc (sizeof (XPresentIdleNotifyEvent));
            cookie->data = ce;
            if (ce == NULL)
                break;
    
            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->pixmap = proto->pixmap;
            ce->idle_fence = proto->idle_fence;
    
            break;
        }
    #if PRESENT_FUTURE_VERSION
        case PresentRedirectNotify: {
            xPresentRedirectNotify *proto = (xPresentRedirectNotify *) ge;
            xPresentNotify *xNotify = (xPresentNotify *) (proto + 1);
            int nnotifies = (((proto->length + 8) - (sizeof (xPresentRedirectNotify) >> 2))) >> 1;
            XPresentRedirectNotifyEvent *re = malloc (sizeof (XPresentRedirectNotifyEvent) + nnotifies * sizeof (XPresentNotify));
            XPresentNotify *XNotify = (XPresentNotify *) (re + 1);
            int i;
            cookie->data = re;
            if (re == NULL)
                break;
    
            re->type = cookie->type;
            re->serial = cookie->serial;
            re->send_event = cookie->send_event;
            re->display = cookie->display;
            re->extension = cookie->extension;
            re->evtype = cookie->evtype;
    
            re->eid = proto->eid;
            re->event_window = proto->event_window;
    
            re->window = proto->window;
            re->pixmap = proto->pixmap;
            re->serial_number = proto->serial;
    
            re->valid_region = proto->valid_region;
            re->update_region = proto->update_region;
    
            re->valid_rect = *(XRectangle *) &(proto->valid_rect);
            re->update_rect = *(XRectangle *) &(proto->update_rect);
    
            re->x_off = proto->x_off;
            re->y_off = proto->y_off;
            re->target_crtc = proto->target_crtc;
    
            re->wait_fence = proto->wait_fence;
            re->idle_fence = proto->idle_fence;
    
            re->options = proto->options;
    
            re->target_msc = proto->target_msc;
            re->divisor = proto->divisor;
            re->remainder = proto->remainder;
    
            re->nnotifies = nnotifies;
            re->notifies = XNotify;
            for (i = 0; i < nnotifies; i++) {
                XNotify[i].window = xNotify[i].window;
                XNotify[i].serial = xNotify[i].serial;
            }
            break;
        }
    #endif
        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
    XPresentPixmap(Display *dpy,
                   Window window,
                   Pixmap pixmap,
                   uint32_t serial,
                   XserverRegion valid,
                   XserverRegion update,
                   int x_off,
                   int y_off,
                   RRCrtc target_crtc,
                   XSyncFence wait_fence,
                   XSyncFence idle_fence,
                   uint32_t options,
                   uint64_t target_msc,
                   uint64_t divisor,
                   uint64_t remainder,
                   XPresentNotify *notifies,
                   int nnotifies)
    {
        XPresentExtDisplayInfo	*info = XPresentFindDisplay (dpy);
        xPresentPixmapReq           *req;
        long                        len = ((long) nnotifies) << 1;
    
        XPresentSimpleCheckExtension (dpy, info);
    
        LockDisplay (dpy);
        GetReq(PresentPixmap, req);
        req->reqType = info->codes->major_opcode;
        req->presentReqType = X_PresentPixmap;
        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->target_crtc = target_crtc;
        req->wait_fence = wait_fence;
        req->idle_fence = idle_fence;
        req->options = options;
        req->target_msc = target_msc;
        req->divisor = divisor;
        req->remainder = remainder;
        SetReqLen(req, len, len);
        Data32(dpy, (CARD32 *) notifies, len);
        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;
    }
    
    void
    XPresentFreeInput(Display *dpy,
                      Window window,
                      XID event_id)
    {
        XPresentExtDisplayInfo	*info = XPresentFindDisplay (dpy);
        xPresentSelectInputReq      *req;
    
        XPresentSimpleCheckExtension (dpy, info);
        LockDisplay (dpy);
        GetReq(PresentSelectInput, req);
        req->reqType = info->codes->major_opcode;
        req->presentReqType = X_PresentSelectInput;
        req->eid = event_id;
        req->window = window;
        req->eventMask = 0;
        UnlockDisplay (dpy);
        SyncHandle();
    }
    
    uint32_t
    XPresentQueryCapabilities(Display *dpy,
                              XID target)
    {
        XPresentExtDisplayInfo	        *info = XPresentFindDisplay (dpy);
        xPresentQueryCapabilitiesReq        *req;
        xPresentQueryCapabilitiesReply      rep;
    
        XPresentCheckExtension (dpy, info, 0);
        LockDisplay (dpy);
        GetReq(PresentQueryCapabilities, req);
        req->reqType = info->codes->major_opcode;
        req->presentReqType = X_PresentQueryCapabilities;
        req->target = target;
    
        if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
    	UnlockDisplay (dpy);
    	SyncHandle ();
            return 0;
        }
    
        UnlockDisplay (dpy);
        SyncHandle();
        return rep.capabilities;
    }