1/*
2 * Copyright (c) 2006, Oracle and/or its affiliates.
3 * Copyright 2011 Red Hat, Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24/*
25 * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
26 *
27 * Permission to use, copy, modify, distribute, and sell this software and its
28 * documentation for any purpose is hereby granted without fee, provided that
29 * the above copyright notice appear in all copies and that both that
30 * copyright notice and this permission notice appear in supporting
31 * documentation, and that the name of Keith Packard not be used in
32 * advertising or publicity pertaining to distribution of the software without
33 * specific, written prior permission.  Keith Packard makes no
34 * representations about the suitability of this software for any purpose.  It
35 * is provided "as is" without express or implied warranty.
36 *
37 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
38 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
39 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
40 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
41 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
42 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
43 * PERFORMANCE OF THIS SOFTWARE.
44 */
45
46#ifdef HAVE_CONFIG_H
47#include <config.h>
48#endif
49#include "Xfixesint.h"
50#include <limits.h>
51
52void
53XFixesSelectCursorInput (Display	*dpy,
54			 Window		win,
55			 unsigned long	eventMask)
56{
57    XFixesExtDisplayInfo	    *info = XFixesFindDisplay (dpy);
58    xXFixesSelectCursorInputReq	    *req;
59
60    XFixesSimpleCheckExtension (dpy, info);
61
62    LockDisplay (dpy);
63    GetReq (XFixesSelectCursorInput, req);
64    req->reqType = (CARD8) info->codes->major_opcode;
65    req->xfixesReqType = X_XFixesSelectCursorInput;
66    req->window = (CARD32) win;
67    req->eventMask = (CARD32) eventMask;
68    UnlockDisplay (dpy);
69    SyncHandle ();
70}
71
72XFixesCursorImage *
73XFixesGetCursorImage (Display *dpy)
74{
75    XFixesExtDisplayInfo		*info = XFixesFindDisplay (dpy);
76    xXFixesGetCursorImageAndNameReq	*req;
77    xXFixesGetCursorImageAndNameReply	rep;
78    size_t				npixels;
79    size_t				nbytes_name;
80    size_t				nbytes = 0, nread = 0;
81    XFixesCursorImage			*image;
82    char				*name;
83
84    XFixesCheckExtension (dpy, info, NULL);
85    LockDisplay (dpy);
86    GetReq (XFixesGetCursorImageAndName, req);
87    req->reqType = (CARD8) info->codes->major_opcode;
88    if (info->major_version >= 2)
89	req->xfixesReqType = X_XFixesGetCursorImageAndName;
90    else
91	req->xfixesReqType = X_XFixesGetCursorImage;
92    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
93    {
94	UnlockDisplay (dpy);
95	SyncHandle ();
96	return NULL;
97    }
98    if (info->major_version < 2)
99    {
100	rep.cursorName = None;
101	rep.nbytes = 0;
102    }
103    npixels = rep.width * rep.height;
104    nbytes_name = rep.nbytes;
105    if ((rep.length < (INT_MAX >> 2)) &&
106	npixels < (((INT_MAX >> 3) - sizeof (XFixesCursorImage) - 1)
107		   - nbytes_name)) {
108	size_t	rlength;
109
110	/* reply data length */
111	nbytes = (size_t) rep.length << 2;
112	/* bytes of actual data in the reply */
113	nread = (npixels << 2) + nbytes_name;
114	/* size of data returned to application */
115	rlength = (sizeof (XFixesCursorImage) +
116		   npixels * sizeof (unsigned long) +
117		   nbytes_name + 1);
118
119	image = Xmalloc (rlength);
120    } else
121	image = NULL;
122    if (!image)
123    {
124	_XEatDataWords(dpy, rep.length);
125	UnlockDisplay (dpy);
126	SyncHandle ();
127	return NULL;
128    }
129    image->x = rep.x;
130    image->y = rep.y;
131    image->width = rep.width;
132    image->height = rep.height;
133    image->xhot = rep.xhot;
134    image->yhot = rep.yhot;
135    image->cursor_serial = rep.cursorSerial;
136    image->pixels = (unsigned long *) (image + 1);
137    image->atom = rep.cursorName;
138    name = (char *) (image->pixels + npixels);
139    image->name = name;
140    _XRead32 (dpy, (long *) image->pixels, npixels << 2);
141    _XRead (dpy, name, nbytes_name);
142    name[nbytes_name] = '\0';	/* null-terminate */
143    /* skip any padding */
144    if(nbytes > nread)
145    {
146	_XEatData (dpy, (unsigned long) (nbytes - nread));
147    }
148    UnlockDisplay (dpy);
149    SyncHandle ();
150    return image;
151}
152
153void
154XFixesSetCursorName (Display *dpy, Cursor cursor, const char *name)
155{
156    XFixesExtDisplayInfo	*info = XFixesFindDisplay (dpy);
157    xXFixesSetCursorNameReq	*req;
158    CARD16			nbytes = (CARD16) strlen (name);
159
160    XFixesSimpleCheckExtension (dpy, info);
161    if (info->major_version < 2)
162	return;
163    LockDisplay (dpy);
164    GetReq (XFixesSetCursorName, req);
165    req->reqType = (CARD8) info->codes->major_opcode;
166    req->xfixesReqType = X_XFixesSetCursorName;
167    req->cursor = (CARD32) cursor;
168    req->nbytes = nbytes;
169    req->length += (nbytes + 3) >> 2;
170    Data (dpy, name, nbytes);
171    UnlockDisplay (dpy);
172    SyncHandle ();
173}
174
175const char *
176XFixesGetCursorName (Display *dpy, Cursor cursor, Atom *atom)
177{
178    XFixesExtDisplayInfo	*info = XFixesFindDisplay (dpy);
179    xXFixesGetCursorNameReq	*req;
180    xXFixesGetCursorNameReply	rep;
181    char			*name;
182
183    XFixesCheckExtension (dpy, info, NULL);
184    if (info->major_version < 2)
185	return NULL;
186    LockDisplay (dpy);
187    GetReq (XFixesGetCursorName, req);
188    req->reqType = (CARD8) info->codes->major_opcode;
189    req->xfixesReqType = X_XFixesGetCursorName;
190    req->cursor = (CARD32) cursor;
191    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
192    {
193	UnlockDisplay (dpy);
194	SyncHandle ();
195	return NULL;
196    }
197    *atom = rep.atom;
198    if ((name = Xmalloc(rep.nbytes+1)) != NULL) {
199	_XReadPad(dpy, name, (long)rep.nbytes);
200	name[rep.nbytes] = '\0';
201    } else {
202	_XEatDataWords(dpy, rep.length);
203	name = (char *) NULL;
204    }
205    UnlockDisplay(dpy);
206    SyncHandle();
207    return(name);
208}
209
210void
211XFixesChangeCursor (Display *dpy, Cursor source, Cursor destination)
212{
213    XFixesExtDisplayInfo	*info = XFixesFindDisplay (dpy);
214    xXFixesChangeCursorReq	*req;
215
216    XFixesSimpleCheckExtension (dpy, info);
217    if (info->major_version < 2)
218	return;
219    LockDisplay (dpy);
220    GetReq (XFixesChangeCursor, req);
221    req->reqType = (CARD8) info->codes->major_opcode;
222    req->xfixesReqType = X_XFixesChangeCursor;
223    req->source = (CARD32) source;
224    req->destination = (CARD32) destination;
225    UnlockDisplay(dpy);
226    SyncHandle();
227}
228
229void
230XFixesChangeCursorByName (Display *dpy, Cursor source, const char *name)
231{
232    XFixesExtDisplayInfo	    *info = XFixesFindDisplay (dpy);
233    xXFixesChangeCursorByNameReq    *req;
234    CARD16			    nbytes = (CARD16) strlen (name);
235
236    XFixesSimpleCheckExtension (dpy, info);
237    if (info->major_version < 2)
238	return;
239    LockDisplay (dpy);
240    GetReq (XFixesChangeCursorByName, req);
241    req->reqType = (CARD8) info->codes->major_opcode;
242    req->xfixesReqType = X_XFixesChangeCursorByName;
243    req->source = (CARD32) source;
244    req->nbytes = nbytes;
245    req->length += (nbytes + 3) >> 2;
246    Data (dpy, name, nbytes);
247    UnlockDisplay(dpy);
248    SyncHandle();
249}
250
251void
252XFixesHideCursor (Display *dpy, Window win)
253{
254    XFixesExtDisplayInfo	*info = XFixesFindDisplay (dpy);
255    xXFixesHideCursorReq	*req;
256
257    XFixesSimpleCheckExtension (dpy, info);
258    if (info->major_version < 4)
259	return;
260    LockDisplay (dpy);
261    GetReq (XFixesHideCursor, req);
262    req->reqType = (CARD8) info->codes->major_opcode;
263    req->xfixesReqType = X_XFixesHideCursor;
264    req->window = (CARD32) win;
265    UnlockDisplay (dpy);
266    SyncHandle ();
267}
268
269void
270XFixesShowCursor (Display *dpy, Window win)
271{
272    XFixesExtDisplayInfo	*info = XFixesFindDisplay (dpy);
273    xXFixesShowCursorReq	*req;
274
275    XFixesSimpleCheckExtension (dpy, info);
276    if (info->major_version < 4)
277	return;
278    LockDisplay (dpy);
279    GetReq (XFixesShowCursor, req);
280    req->reqType = (CARD8) info->codes->major_opcode;
281    req->xfixesReqType = X_XFixesShowCursor;
282    req->window = (CARD32) win;
283    UnlockDisplay (dpy);
284    SyncHandle ();
285}
286
287PointerBarrier
288XFixesCreatePointerBarrier(Display *dpy, Window w, int x1, int y1,
289			   int x2, int y2, int directions,
290			   int num_devices, int *devices)
291{
292    XFixesExtDisplayInfo *info = XFixesFindDisplay (dpy);
293    xXFixesCreatePointerBarrierReq *req;
294    PointerBarrier barrier;
295    int extra = 0;
296
297    XFixesCheckExtension (dpy, info, 0);
298    if (info->major_version < 5)
299	return 0;
300
301    if (num_devices)
302	extra = (((2 * num_devices) + 3) / 4) * 4;
303
304    LockDisplay (dpy);
305    GetReqExtra (XFixesCreatePointerBarrier, extra, req);
306    req->reqType = (CARD8) info->codes->major_opcode;
307    req->xfixesReqType = X_XFixesCreatePointerBarrier;
308    barrier = XAllocID (dpy);
309    req->barrier = (CARD32) barrier;
310    req->window = (CARD32) w;
311    req->x1 = (INT16) x1;
312    req->y1 = (INT16) y1;
313    req->x2 = (INT16) x2;
314    req->y2 = (INT16) y2;
315    req->directions = (CARD32) directions;
316    if ((req->num_devices = (CARD16) num_devices)) {
317	int i;
318	CARD16 *devs = (CARD16 *)(req + 1);
319	for (i = 0; i < num_devices; i++)
320	    devs[i] = (CARD16)(devices[i]);
321    }
322
323    UnlockDisplay (dpy);
324    SyncHandle();
325    return barrier;
326}
327
328void
329XFixesDestroyPointerBarrier(Display *dpy, PointerBarrier b)
330{
331    XFixesExtDisplayInfo *info = XFixesFindDisplay (dpy);
332    xXFixesDestroyPointerBarrierReq *req;
333
334    XFixesSimpleCheckExtension (dpy, info);
335    if (info->major_version < 5)
336	return;
337
338    LockDisplay (dpy);
339    GetReq (XFixesDestroyPointerBarrier, req);
340    req->reqType = (CARD8) info->codes->major_opcode;
341    req->xfixesReqType = X_XFixesDestroyPointerBarrier;
342    req->barrier = (CARD32) b;
343    UnlockDisplay (dpy);
344    SyncHandle();
345}
346