1/*
2 *
3 * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of Keith Packard not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission.  Keith Packard makes no
12 * representations about the suitability of this software for any purpose.  It
13 * is provided "as is" without express or implied warranty.
14 *
15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27#include <X11/Xfuncproto.h>
28#include "Xfixesint.h"
29
30XFixesExtInfo XFixesExtensionInfo;
31char XFixesExtensionName[] = XFIXES_NAME;
32
33static int
34XFixesCloseDisplay (Display *dpy, XExtCodes *codes);
35
36static Bool
37XFixesWireToEvent(Display *dpy, XEvent *event, xEvent *wire);
38
39static Status
40XFixesEventToWire(Display *dpy, XEvent *event, xEvent *wire);
41
42/*
43 * XFixesExtAddDisplay - add a display to this extension. (Replaces
44 * XextAddDisplay)
45 */
46static XFixesExtDisplayInfo *
47XFixesExtAddDisplay (XFixesExtInfo *extinfo,
48                      Display        *dpy,
49                      char           *ext_name)
50{
51    XFixesExtDisplayInfo    *info;
52
53    info = Xmalloc (sizeof (XFixesExtDisplayInfo));
54    if (!info) return NULL;
55    info->display = dpy;
56
57    info->codes = XInitExtension (dpy, ext_name);
58
59    /*
60     * if the server has the extension, then we can initialize the
61     * appropriate function vectors
62     */
63    if (info->codes) {
64	xXFixesQueryVersionReply	rep;
65	xXFixesQueryVersionReq	*req;
66        XESetCloseDisplay (dpy, info->codes->extension,
67                           XFixesCloseDisplay);
68	for (int ev = info->codes->first_event;
69	     ev < info->codes->first_event + XFixesNumberEvents;
70	     ev++)
71	{
72	    XESetWireToEvent (dpy, ev, XFixesWireToEvent);
73	    XESetEventToWire (dpy, ev, XFixesEventToWire);
74	}
75	/*
76	 * Get the version info
77	 */
78	LockDisplay (dpy);
79	GetReq (XFixesQueryVersion, req);
80	req->reqType = (CARD8) info->codes->major_opcode;
81	req->xfixesReqType = X_XFixesQueryVersion;
82	req->majorVersion = XFIXES_MAJOR;
83	req->minorVersion = XFIXES_MINOR;
84	if (!_XReply (dpy, (xReply *) &rep, 0, xTrue))
85	{
86	    UnlockDisplay (dpy);
87	    SyncHandle ();
88	    Xfree(info);
89	    return NULL;
90	}
91	info->major_version = (int) rep.majorVersion;
92	info->minor_version = (int) rep.minorVersion;
93	UnlockDisplay (dpy);
94	SyncHandle ();
95    } else {
96	/* The server doesn't have this extension.
97	 * Use a private Xlib-internal extension to hang the close_display
98	 * hook on so that the "cache" (extinfo->cur) is properly cleaned.
99	 * (XBUG 7955)
100	 */
101	XExtCodes *codes = XAddExtension(dpy);
102	if (!codes) {
103	    XFree(info);
104	    return NULL;
105	}
106        XESetCloseDisplay (dpy, codes->extension, XFixesCloseDisplay);
107    }
108
109    /*
110     * now, chain it onto the list
111     */
112    _XLockMutex(_Xglobal_lock);
113    info->next = extinfo->head;
114    extinfo->head = info;
115    extinfo->cur = info;
116    extinfo->ndisplays++;
117    _XUnlockMutex(_Xglobal_lock);
118    return info;
119}
120
121
122/*
123 * XFixesExtRemoveDisplay - remove the indicated display from the
124 * extension object. (Replaces XextRemoveDisplay.)
125 */
126static int
127XFixesExtRemoveDisplay (XFixesExtInfo *extinfo, const Display *dpy)
128{
129    XFixesExtDisplayInfo *info, *prev;
130
131    /*
132     * locate this display and its back link so that it can be removed
133     */
134    _XLockMutex(_Xglobal_lock);
135    prev = NULL;
136    for (info = extinfo->head; info; info = info->next) {
137	if (info->display == dpy) break;
138	prev = info;
139    }
140    if (!info) {
141	_XUnlockMutex(_Xglobal_lock);
142	return 0;		/* hmm, actually an error */
143    }
144
145    /*
146     * remove the display from the list; handles going to zero
147     */
148    if (prev)
149	prev->next = info->next;
150    else
151	extinfo->head = info->next;
152
153    extinfo->ndisplays--;
154    if (info == extinfo->cur) extinfo->cur = NULL;  /* flush cache */
155    _XUnlockMutex(_Xglobal_lock);
156
157    Xfree (info);
158    return 1;
159}
160
161/*
162 * XFixesExtFindDisplay - look for a display in this extension; keeps a
163 * cache of the most-recently used for efficiency. (Replaces
164 * XextFindDisplay.)
165 */
166static XFixesExtDisplayInfo *
167XFixesExtFindDisplay (XFixesExtInfo *extinfo,
168		      const Display *dpy)
169{
170    XFixesExtDisplayInfo *info;
171
172    /*
173     * see if this was the most recently accessed display
174     */
175    if ((info = extinfo->cur) && info->display == dpy)
176	return info;
177
178    /*
179     * look for display in list
180     */
181    _XLockMutex(_Xglobal_lock);
182    for (info = extinfo->head; info; info = info->next) {
183	if (info->display == dpy) {
184	    extinfo->cur = info;     /* cache most recently used */
185	    _XUnlockMutex(_Xglobal_lock);
186	    return info;
187	}
188    }
189    _XUnlockMutex(_Xglobal_lock);
190
191    return NULL;
192}
193
194XFixesExtDisplayInfo *
195XFixesFindDisplay (Display *dpy)
196{
197    XFixesExtDisplayInfo *info;
198
199    info = XFixesExtFindDisplay (&XFixesExtensionInfo, dpy);
200    if (!info)
201	info = XFixesExtAddDisplay (&XFixesExtensionInfo, dpy,
202				    XFixesExtensionName);
203    return info;
204}
205
206static int
207XFixesCloseDisplay (Display *dpy, _X_UNUSED XExtCodes *codes)
208{
209    return XFixesExtRemoveDisplay (&XFixesExtensionInfo, dpy);
210}
211
212static Bool
213XFixesWireToEvent(Display *dpy, XEvent *event, xEvent *wire)
214{
215    XFixesExtDisplayInfo *info = XFixesFindDisplay(dpy);
216
217    XFixesCheckExtension(dpy, info, False);
218
219    switch ((wire->u.u.type & 0x7F) - info->codes->first_event)
220    {
221    case XFixesSelectionNotify: {
222	XFixesSelectionNotifyEvent *aevent;
223	xXFixesSelectionNotifyEvent *awire;
224	awire = (xXFixesSelectionNotifyEvent *) wire;
225	aevent = (XFixesSelectionNotifyEvent *) event;
226	aevent->type = awire->type & 0x7F;
227	aevent->subtype = awire->subtype;
228	aevent->serial = _XSetLastRequestRead(dpy,
229					      (xGenericReply *) wire);
230	aevent->send_event = (awire->type & 0x80) != 0;
231	aevent->display = dpy;
232	aevent->window = awire->window;
233	aevent->owner = awire->owner;
234	aevent->selection = awire->selection;
235	aevent->timestamp = awire->timestamp;
236	aevent->selection_timestamp = awire->selectionTimestamp;
237	return True;
238    }
239    case XFixesCursorNotify: {
240	XFixesCursorNotifyEvent *aevent;
241	xXFixesCursorNotifyEvent *awire;
242	awire = (xXFixesCursorNotifyEvent *) wire;
243	aevent = (XFixesCursorNotifyEvent *) event;
244	aevent->type = awire->type & 0x7F;
245	aevent->subtype = awire->subtype;
246	aevent->serial = _XSetLastRequestRead(dpy,
247					      (xGenericReply *) wire);
248	aevent->send_event = (awire->type & 0x80) != 0;
249	aevent->display = dpy;
250	aevent->window = awire->window;
251	aevent->cursor_serial = awire->cursorSerial;
252	aevent->timestamp = awire->timestamp;
253	aevent->cursor_name = awire->name;
254	return True;
255    }
256    }
257    return False;
258}
259
260static Status
261XFixesEventToWire(Display *dpy, XEvent *event, xEvent *wire)
262{
263    XFixesExtDisplayInfo *info = XFixesFindDisplay(dpy);
264
265    XFixesCheckExtension(dpy, info, False);
266
267    switch ((event->type & 0x7F) - info->codes->first_event)
268    {
269    case XFixesSelectionNotify: {
270	XFixesSelectionNotifyEvent *aevent;
271	xXFixesSelectionNotifyEvent *awire;
272	awire = (xXFixesSelectionNotifyEvent *) wire;
273	aevent = (XFixesSelectionNotifyEvent *) event;
274	awire->type = (CARD8) (aevent->type | (aevent->send_event ? 0x80 : 0));
275	awire->subtype = (CARD8) aevent->subtype;
276	awire->window = (CARD32) aevent->window;
277	awire->owner = (CARD32) aevent->owner;
278	awire->selection = (CARD32) aevent->selection;
279	awire->timestamp = (CARD32) aevent->timestamp;
280	awire->selectionTimestamp = (CARD32) aevent->selection_timestamp;
281	return True;
282    }
283    case XFixesCursorNotify: {
284	XFixesCursorNotifyEvent *aevent;
285	xXFixesCursorNotifyEvent *awire;
286	awire = (xXFixesCursorNotifyEvent *) wire;
287	aevent = (XFixesCursorNotifyEvent *) event;
288	awire->type = (CARD8) (aevent->type | (aevent->send_event ? 0x80 : 0));
289	awire->subtype = (CARD8) aevent->subtype;
290	awire->window = (CARD32) aevent->window;
291	awire->timestamp = (CARD32) aevent->timestamp;
292	awire->cursorSerial = (CARD32) aevent->cursor_serial;
293	awire->name = (CARD32) aevent->cursor_name;
294    }
295    }
296    return False;
297}
298
299Bool
300XFixesQueryExtension (Display *dpy,
301			int *event_base_return,
302			int *error_base_return)
303{
304    XFixesExtDisplayInfo *info = XFixesFindDisplay (dpy);
305
306    if (XFixesHasExtension(info))
307    {
308	*event_base_return = info->codes->first_event;
309	*error_base_return = info->codes->first_error;
310	return True;
311    }
312    else
313	return False;
314}
315
316Status
317XFixesQueryVersion (Display *dpy,
318		    int	    *major_version_return,
319		    int	    *minor_version_return)
320{
321    XFixesExtDisplayInfo	*info = XFixesFindDisplay (dpy);
322
323    XFixesCheckExtension (dpy, info, 0);
324
325    *major_version_return = info->major_version;
326    *minor_version_return = info->minor_version;
327    return 1;
328}
329
330int
331XFixesVersion (void)
332{
333    return XFIXES_VERSION;
334}
335