Xfixes.c revision a7e741d5
14456fccdSmrg/*
24456fccdSmrg *
34456fccdSmrg * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
44456fccdSmrg *
54456fccdSmrg * Permission to use, copy, modify, distribute, and sell this software and its
64456fccdSmrg * documentation for any purpose is hereby granted without fee, provided that
74456fccdSmrg * the above copyright notice appear in all copies and that both that
84456fccdSmrg * copyright notice and this permission notice appear in supporting
94456fccdSmrg * documentation, and that the name of Keith Packard not be used in
104456fccdSmrg * advertising or publicity pertaining to distribution of the software without
114456fccdSmrg * specific, written prior permission.  Keith Packard makes no
124456fccdSmrg * representations about the suitability of this software for any purpose.  It
134456fccdSmrg * is provided "as is" without express or implied warranty.
144456fccdSmrg *
154456fccdSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
164456fccdSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
174456fccdSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
184456fccdSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
194456fccdSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
204456fccdSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
214456fccdSmrg * PERFORMANCE OF THIS SOFTWARE.
224456fccdSmrg */
234456fccdSmrg
244456fccdSmrg#ifdef HAVE_CONFIG_H
254456fccdSmrg#include <config.h>
264456fccdSmrg#endif
27a7e741d5Smrg#include <X11/Xfuncproto.h>
284456fccdSmrg#include "Xfixesint.h"
294456fccdSmrg
304456fccdSmrgXFixesExtInfo XFixesExtensionInfo;
314456fccdSmrgchar XFixesExtensionName[] = XFIXES_NAME;
324456fccdSmrg
334456fccdSmrgstatic int
344456fccdSmrgXFixesCloseDisplay (Display *dpy, XExtCodes *codes);
353e6c936aSmrg
364456fccdSmrgstatic Bool
374456fccdSmrgXFixesWireToEvent(Display *dpy, XEvent *event, xEvent *wire);
384456fccdSmrg
394456fccdSmrgstatic Status
404456fccdSmrgXFixesEventToWire(Display *dpy, XEvent *event, xEvent *wire);
414456fccdSmrg
424456fccdSmrg/*
434456fccdSmrg * XFixesExtAddDisplay - add a display to this extension. (Replaces
444456fccdSmrg * XextAddDisplay)
454456fccdSmrg */
464456fccdSmrgstatic XFixesExtDisplayInfo *
474456fccdSmrgXFixesExtAddDisplay (XFixesExtInfo *extinfo,
484456fccdSmrg                      Display        *dpy,
494456fccdSmrg                      char           *ext_name)
504456fccdSmrg{
514456fccdSmrg    XFixesExtDisplayInfo    *info;
524456fccdSmrg
53a7e741d5Smrg    info = Xmalloc (sizeof (XFixesExtDisplayInfo));
544456fccdSmrg    if (!info) return NULL;
554456fccdSmrg    info->display = dpy;
564456fccdSmrg
574456fccdSmrg    info->codes = XInitExtension (dpy, ext_name);
584456fccdSmrg
594456fccdSmrg    /*
603e6c936aSmrg     * if the server has the extension, then we can initialize the
614456fccdSmrg     * appropriate function vectors
624456fccdSmrg     */
634456fccdSmrg    if (info->codes) {
644456fccdSmrg	xXFixesQueryVersionReply	rep;
654456fccdSmrg	xXFixesQueryVersionReq	*req;
663e6c936aSmrg        XESetCloseDisplay (dpy, info->codes->extension,
674456fccdSmrg                           XFixesCloseDisplay);
68a7e741d5Smrg	for (int ev = info->codes->first_event;
694456fccdSmrg	     ev < info->codes->first_event + XFixesNumberEvents;
704456fccdSmrg	     ev++)
714456fccdSmrg	{
724456fccdSmrg	    XESetWireToEvent (dpy, ev, XFixesWireToEvent);
734456fccdSmrg	    XESetEventToWire (dpy, ev, XFixesEventToWire);
744456fccdSmrg	}
754456fccdSmrg	/*
764456fccdSmrg	 * Get the version info
774456fccdSmrg	 */
784456fccdSmrg	LockDisplay (dpy);
794456fccdSmrg	GetReq (XFixesQueryVersion, req);
80a7e741d5Smrg	req->reqType = (CARD8) info->codes->major_opcode;
814456fccdSmrg	req->xfixesReqType = X_XFixesQueryVersion;
824456fccdSmrg	req->majorVersion = XFIXES_MAJOR;
834456fccdSmrg	req->minorVersion = XFIXES_MINOR;
843e6c936aSmrg	if (!_XReply (dpy, (xReply *) &rep, 0, xTrue))
854456fccdSmrg	{
864456fccdSmrg	    UnlockDisplay (dpy);
874456fccdSmrg	    SyncHandle ();
884456fccdSmrg	    Xfree(info);
8942d69509Smrg	    return NULL;
904456fccdSmrg	}
91a7e741d5Smrg	info->major_version = (int) rep.majorVersion;
92a7e741d5Smrg	info->minor_version = (int) rep.minorVersion;
934456fccdSmrg	UnlockDisplay (dpy);
94521070a0Smrg	SyncHandle ();
954456fccdSmrg    } else {
964456fccdSmrg	/* The server doesn't have this extension.
974456fccdSmrg	 * Use a private Xlib-internal extension to hang the close_display
984456fccdSmrg	 * hook on so that the "cache" (extinfo->cur) is properly cleaned.
994456fccdSmrg	 * (XBUG 7955)
1004456fccdSmrg	 */
1014456fccdSmrg	XExtCodes *codes = XAddExtension(dpy);
1024456fccdSmrg	if (!codes) {
1034456fccdSmrg	    XFree(info);
1044456fccdSmrg	    return NULL;
1054456fccdSmrg	}
1064456fccdSmrg        XESetCloseDisplay (dpy, codes->extension, XFixesCloseDisplay);
1074456fccdSmrg    }
1084456fccdSmrg
1094456fccdSmrg    /*
1104456fccdSmrg     * now, chain it onto the list
1114456fccdSmrg     */
1124456fccdSmrg    _XLockMutex(_Xglobal_lock);
1134456fccdSmrg    info->next = extinfo->head;
1144456fccdSmrg    extinfo->head = info;
1154456fccdSmrg    extinfo->cur = info;
1164456fccdSmrg    extinfo->ndisplays++;
1174456fccdSmrg    _XUnlockMutex(_Xglobal_lock);
1184456fccdSmrg    return info;
1194456fccdSmrg}
1204456fccdSmrg
1214456fccdSmrg
1224456fccdSmrg/*
1234456fccdSmrg * XFixesExtRemoveDisplay - remove the indicated display from the
1244456fccdSmrg * extension object. (Replaces XextRemoveDisplay.)
1254456fccdSmrg */
1263e6c936aSmrgstatic int
127a7e741d5SmrgXFixesExtRemoveDisplay (XFixesExtInfo *extinfo, const Display *dpy)
1284456fccdSmrg{
1294456fccdSmrg    XFixesExtDisplayInfo *info, *prev;
1304456fccdSmrg
1314456fccdSmrg    /*
1324456fccdSmrg     * locate this display and its back link so that it can be removed
1334456fccdSmrg     */
1344456fccdSmrg    _XLockMutex(_Xglobal_lock);
1354456fccdSmrg    prev = NULL;
1364456fccdSmrg    for (info = extinfo->head; info; info = info->next) {
1374456fccdSmrg	if (info->display == dpy) break;
1384456fccdSmrg	prev = info;
1394456fccdSmrg    }
1404456fccdSmrg    if (!info) {
1414456fccdSmrg	_XUnlockMutex(_Xglobal_lock);
1424456fccdSmrg	return 0;		/* hmm, actually an error */
1434456fccdSmrg    }
1444456fccdSmrg
1454456fccdSmrg    /*
1464456fccdSmrg     * remove the display from the list; handles going to zero
1474456fccdSmrg     */
1484456fccdSmrg    if (prev)
1494456fccdSmrg	prev->next = info->next;
1504456fccdSmrg    else
1514456fccdSmrg	extinfo->head = info->next;
1524456fccdSmrg
1534456fccdSmrg    extinfo->ndisplays--;
1544456fccdSmrg    if (info == extinfo->cur) extinfo->cur = NULL;  /* flush cache */
1554456fccdSmrg    _XUnlockMutex(_Xglobal_lock);
1564456fccdSmrg
157a7e741d5Smrg    Xfree (info);
1584456fccdSmrg    return 1;
1594456fccdSmrg}
1604456fccdSmrg
1614456fccdSmrg/*
1624456fccdSmrg * XFixesExtFindDisplay - look for a display in this extension; keeps a
1634456fccdSmrg * cache of the most-recently used for efficiency. (Replaces
1644456fccdSmrg * XextFindDisplay.)
1654456fccdSmrg */
1664456fccdSmrgstatic XFixesExtDisplayInfo *
1673e6c936aSmrgXFixesExtFindDisplay (XFixesExtInfo *extinfo,
168a7e741d5Smrg		      const Display *dpy)
1694456fccdSmrg{
1704456fccdSmrg    XFixesExtDisplayInfo *info;
1714456fccdSmrg
1724456fccdSmrg    /*
1734456fccdSmrg     * see if this was the most recently accessed display
1744456fccdSmrg     */
1753e6c936aSmrg    if ((info = extinfo->cur) && info->display == dpy)
1764456fccdSmrg	return info;
1774456fccdSmrg
1784456fccdSmrg    /*
1794456fccdSmrg     * look for display in list
1804456fccdSmrg     */
1814456fccdSmrg    _XLockMutex(_Xglobal_lock);
1824456fccdSmrg    for (info = extinfo->head; info; info = info->next) {
1834456fccdSmrg	if (info->display == dpy) {
1844456fccdSmrg	    extinfo->cur = info;     /* cache most recently used */
1854456fccdSmrg	    _XUnlockMutex(_Xglobal_lock);
1864456fccdSmrg	    return info;
1874456fccdSmrg	}
1884456fccdSmrg    }
1894456fccdSmrg    _XUnlockMutex(_Xglobal_lock);
1904456fccdSmrg
1914456fccdSmrg    return NULL;
1924456fccdSmrg}
1934456fccdSmrg
1944456fccdSmrgXFixesExtDisplayInfo *
1954456fccdSmrgXFixesFindDisplay (Display *dpy)
1964456fccdSmrg{
1974456fccdSmrg    XFixesExtDisplayInfo *info;
1984456fccdSmrg
1994456fccdSmrg    info = XFixesExtFindDisplay (&XFixesExtensionInfo, dpy);
2004456fccdSmrg    if (!info)
2013e6c936aSmrg	info = XFixesExtAddDisplay (&XFixesExtensionInfo, dpy,
2024456fccdSmrg				    XFixesExtensionName);
2034456fccdSmrg    return info;
2044456fccdSmrg}
2053e6c936aSmrg
2064456fccdSmrgstatic int
207a7e741d5SmrgXFixesCloseDisplay (Display *dpy, _X_UNUSED XExtCodes *codes)
2084456fccdSmrg{
2094456fccdSmrg    return XFixesExtRemoveDisplay (&XFixesExtensionInfo, dpy);
2104456fccdSmrg}
2114456fccdSmrg
2124456fccdSmrgstatic Bool
2134456fccdSmrgXFixesWireToEvent(Display *dpy, XEvent *event, xEvent *wire)
2144456fccdSmrg{
2154456fccdSmrg    XFixesExtDisplayInfo *info = XFixesFindDisplay(dpy);
2164456fccdSmrg
2174456fccdSmrg    XFixesCheckExtension(dpy, info, False);
2184456fccdSmrg
2194456fccdSmrg    switch ((wire->u.u.type & 0x7F) - info->codes->first_event)
2204456fccdSmrg    {
2214456fccdSmrg    case XFixesSelectionNotify: {
2224456fccdSmrg	XFixesSelectionNotifyEvent *aevent;
2234456fccdSmrg	xXFixesSelectionNotifyEvent *awire;
2244456fccdSmrg	awire = (xXFixesSelectionNotifyEvent *) wire;
2254456fccdSmrg	aevent = (XFixesSelectionNotifyEvent *) event;
2264456fccdSmrg	aevent->type = awire->type & 0x7F;
2274456fccdSmrg	aevent->subtype = awire->subtype;
2284456fccdSmrg	aevent->serial = _XSetLastRequestRead(dpy,
2294456fccdSmrg					      (xGenericReply *) wire);
2304456fccdSmrg	aevent->send_event = (awire->type & 0x80) != 0;
2314456fccdSmrg	aevent->display = dpy;
2324456fccdSmrg	aevent->window = awire->window;
2334456fccdSmrg	aevent->owner = awire->owner;
2344456fccdSmrg	aevent->selection = awire->selection;
2354456fccdSmrg	aevent->timestamp = awire->timestamp;
2364456fccdSmrg	aevent->selection_timestamp = awire->selectionTimestamp;
2374456fccdSmrg	return True;
2384456fccdSmrg    }
2394456fccdSmrg    case XFixesCursorNotify: {
2404456fccdSmrg	XFixesCursorNotifyEvent *aevent;
2414456fccdSmrg	xXFixesCursorNotifyEvent *awire;
2424456fccdSmrg	awire = (xXFixesCursorNotifyEvent *) wire;
2434456fccdSmrg	aevent = (XFixesCursorNotifyEvent *) event;
2444456fccdSmrg	aevent->type = awire->type & 0x7F;
2454456fccdSmrg	aevent->subtype = awire->subtype;
2464456fccdSmrg	aevent->serial = _XSetLastRequestRead(dpy,
2474456fccdSmrg					      (xGenericReply *) wire);
2484456fccdSmrg	aevent->send_event = (awire->type & 0x80) != 0;
2494456fccdSmrg	aevent->display = dpy;
2504456fccdSmrg	aevent->window = awire->window;
2514456fccdSmrg	aevent->cursor_serial = awire->cursorSerial;
2524456fccdSmrg	aevent->timestamp = awire->timestamp;
2534456fccdSmrg	aevent->cursor_name = awire->name;
2544456fccdSmrg	return True;
2554456fccdSmrg    }
2564456fccdSmrg    }
2574456fccdSmrg    return False;
2584456fccdSmrg}
2594456fccdSmrg
2604456fccdSmrgstatic Status
2614456fccdSmrgXFixesEventToWire(Display *dpy, XEvent *event, xEvent *wire)
2624456fccdSmrg{
2634456fccdSmrg    XFixesExtDisplayInfo *info = XFixesFindDisplay(dpy);
2644456fccdSmrg
2654456fccdSmrg    XFixesCheckExtension(dpy, info, False);
2664456fccdSmrg
2674456fccdSmrg    switch ((event->type & 0x7F) - info->codes->first_event)
2684456fccdSmrg    {
2694456fccdSmrg    case XFixesSelectionNotify: {
2704456fccdSmrg	XFixesSelectionNotifyEvent *aevent;
2714456fccdSmrg	xXFixesSelectionNotifyEvent *awire;
2724456fccdSmrg	awire = (xXFixesSelectionNotifyEvent *) wire;
2734456fccdSmrg	aevent = (XFixesSelectionNotifyEvent *) event;
274a7e741d5Smrg	awire->type = (CARD8) (aevent->type | (aevent->send_event ? 0x80 : 0));
275a7e741d5Smrg	awire->subtype = (CARD8) aevent->subtype;
276a7e741d5Smrg	awire->window = (CARD32) aevent->window;
277a7e741d5Smrg	awire->owner = (CARD32) aevent->owner;
278a7e741d5Smrg	awire->selection = (CARD32) aevent->selection;
279a7e741d5Smrg	awire->timestamp = (CARD32) aevent->timestamp;
280a7e741d5Smrg	awire->selectionTimestamp = (CARD32) aevent->selection_timestamp;
2814456fccdSmrg	return True;
2824456fccdSmrg    }
2834456fccdSmrg    case XFixesCursorNotify: {
2844456fccdSmrg	XFixesCursorNotifyEvent *aevent;
2854456fccdSmrg	xXFixesCursorNotifyEvent *awire;
2864456fccdSmrg	awire = (xXFixesCursorNotifyEvent *) wire;
2874456fccdSmrg	aevent = (XFixesCursorNotifyEvent *) event;
288a7e741d5Smrg	awire->type = (CARD8) (aevent->type | (aevent->send_event ? 0x80 : 0));
289a7e741d5Smrg	awire->subtype = (CARD8) aevent->subtype;
290a7e741d5Smrg	awire->window = (CARD32) aevent->window;
291a7e741d5Smrg	awire->timestamp = (CARD32) aevent->timestamp;
292a7e741d5Smrg	awire->cursorSerial = (CARD32) aevent->cursor_serial;
293a7e741d5Smrg	awire->name = (CARD32) aevent->cursor_name;
2944456fccdSmrg    }
2954456fccdSmrg    }
2964456fccdSmrg    return False;
2974456fccdSmrg}
2984456fccdSmrg
2993e6c936aSmrgBool
30042d69509SmrgXFixesQueryExtension (Display *dpy,
30142d69509Smrg			int *event_base_return,
30242d69509Smrg			int *error_base_return)
3034456fccdSmrg{
3044456fccdSmrg    XFixesExtDisplayInfo *info = XFixesFindDisplay (dpy);
3054456fccdSmrg
3063e6c936aSmrg    if (XFixesHasExtension(info))
3074456fccdSmrg    {
30842d69509Smrg	*event_base_return = info->codes->first_event;
30942d69509Smrg	*error_base_return = info->codes->first_error;
3104456fccdSmrg	return True;
3113e6c936aSmrg    }
3124456fccdSmrg    else
3134456fccdSmrg	return False;
3144456fccdSmrg}
3154456fccdSmrg
3163e6c936aSmrgStatus
3174456fccdSmrgXFixesQueryVersion (Display *dpy,
31842d69509Smrg		    int	    *major_version_return,
31942d69509Smrg		    int	    *minor_version_return)
3204456fccdSmrg{
3214456fccdSmrg    XFixesExtDisplayInfo	*info = XFixesFindDisplay (dpy);
3224456fccdSmrg
3234456fccdSmrg    XFixesCheckExtension (dpy, info, 0);
3244456fccdSmrg
32542d69509Smrg    *major_version_return = info->major_version;
32642d69509Smrg    *minor_version_return = info->minor_version;
3274456fccdSmrg    return 1;
3284456fccdSmrg}
3294456fccdSmrg
3304456fccdSmrgint
3314456fccdSmrgXFixesVersion (void)
3324456fccdSmrg{
3334456fccdSmrg    return XFIXES_VERSION;
3344456fccdSmrg}
335