Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. | |
3 | * Copyright 2010 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 | * Copyright © 2002 Keith Packard | |
25 | * | |
26 | * Permission to use, copy, modify, distribute, and sell this software and its | |
27 | * documentation for any purpose is hereby granted without fee, provided that | |
28 | * the above copyright notice appear in all copies and that both that | |
29 | * copyright notice and this permission notice appear in supporting | |
30 | * documentation, and that the name of Keith Packard not be used in | |
31 | * advertising or publicity pertaining to distribution of the software without | |
32 | * specific, written prior permission. Keith Packard makes no | |
33 | * representations about the suitability of this software for any purpose. It | |
34 | * is provided "as is" without express or implied warranty. | |
35 | * | |
36 | * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | |
37 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | |
38 | * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR | |
39 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | |
40 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | |
41 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |
42 | * PERFORMANCE OF THIS SOFTWARE. | |
43 | */ | |
44 | ||
45 | #ifdef HAVE_DIX_CONFIG_H | |
46 | #include <dix-config.h> | |
47 | #endif | |
48 | ||
49 | #include "xfixesint.h" | |
50 | #include "scrnintstr.h" | |
51 | #include "cursorstr.h" | |
52 | #include "dixevents.h" | |
53 | #include "servermd.h" | |
54 | #include "mipointer.h" | |
55 | #include "inputstr.h" | |
56 | #include "windowstr.h" | |
57 | #include "xace.h" | |
58 | #include "list.h" | |
59 | #include "xibarriers.h" | |
60 | ||
61 | static RESTYPE CursorClientType; | |
62 | static RESTYPE CursorHideCountType; | |
63 | static RESTYPE CursorWindowType; | |
64 | static CursorPtr CursorCurrent[MAXDEVICES]; | |
65 | ||
66 | static DevPrivateKeyRec CursorScreenPrivateKeyRec; | |
67 | ||
68 | #define CursorScreenPrivateKey (&CursorScreenPrivateKeyRec) | |
69 | ||
70 | static void deleteCursorHideCountsForScreen(ScreenPtr pScreen); | |
71 | ||
72 | #define VERIFY_CURSOR(pCursor, cursor, client, access) \ | |
73 | do { \ | |
74 | int err; \ | |
75 | err = dixLookupResourceByType((pointer *) &pCursor, cursor, \ | |
76 | RT_CURSOR, client, access); \ | |
77 | if (err != Success) { \ | |
78 | client->errorValue = cursor; \ | |
79 | return err; \ | |
80 | } \ | |
81 | } while (0) | |
82 | ||
83 | /* | |
84 | * There is a global list of windows selecting for cursor events | |
85 | */ | |
86 | ||
87 | typedef struct _CursorEvent *CursorEventPtr; | |
88 | ||
89 | typedef struct _CursorEvent { | |
90 | CursorEventPtr next; | |
91 | CARD32 eventMask; | |
92 | ClientPtr pClient; | |
93 | WindowPtr pWindow; | |
94 | XID clientResource; | |
95 | } CursorEventRec; | |
96 | ||
97 | static CursorEventPtr cursorEvents; | |
98 | ||
99 | /* | |
100 | * Each screen has a list of clients which have requested | |
101 | * that the cursor be hid, and the number of times each | |
102 | * client has requested. | |
103 | */ | |
104 | ||
105 | typedef struct _CursorHideCountRec *CursorHideCountPtr; | |
106 | ||
107 | typedef struct _CursorHideCountRec { | |
108 | CursorHideCountPtr pNext; | |
109 | ClientPtr pClient; | |
110 | ScreenPtr pScreen; | |
111 | int hideCount; | |
112 | XID resource; | |
113 | } CursorHideCountRec; | |
114 | ||
115 | /* | |
116 | * Wrap DisplayCursor to catch cursor change events | |
117 | */ | |
118 | ||
119 | typedef struct _CursorScreen { | |
120 | DisplayCursorProcPtr DisplayCursor; | |
121 | CloseScreenProcPtr CloseScreen; | |
122 | CursorHideCountPtr pCursorHideCounts; | |
123 | } CursorScreenRec, *CursorScreenPtr; | |
124 | ||
125 | #define GetCursorScreen(s) ((CursorScreenPtr)dixLookupPrivate(&(s)->devPrivates, CursorScreenPrivateKey)) | |
126 | #define GetCursorScreenIfSet(s) GetCursorScreen(s) | |
127 | #define SetCursorScreen(s,p) dixSetPrivate(&(s)->devPrivates, CursorScreenPrivateKey, p) | |
128 | #define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func) | |
129 | #define Unwrap(as,s,elt,backup) (((backup) = (s)->elt), (s)->elt = (as)->elt) | |
130 | ||
131 | /* The cursor doesn't show up until the first XDefineCursor() */ | |
132 | Bool CursorVisible = FALSE; | |
133 | Bool EnableCursor = TRUE; | |
134 | ||
135 | static Bool | |
136 | CursorDisplayCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) | |
137 | { | |
138 | CursorScreenPtr cs = GetCursorScreen(pScreen); | |
139 | Bool ret; | |
140 | DisplayCursorProcPtr backupProc; | |
141 | ||
142 | Unwrap(cs, pScreen, DisplayCursor, backupProc); | |
143 | ||
144 | CursorVisible = CursorVisible && EnableCursor; | |
145 | ||
146 | if (cs->pCursorHideCounts != NULL || !CursorVisible) { | |
147 | ret = (*pScreen->DisplayCursor) (pDev, pScreen, NullCursor); | |
148 | } | |
149 | else { | |
150 | ret = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor); | |
151 | } | |
152 | ||
153 | if (pCursor != CursorCurrent[pDev->id]) { | |
154 | CursorEventPtr e; | |
155 | ||
156 | CursorCurrent[pDev->id] = pCursor; | |
157 | for (e = cursorEvents; e; e = e->next) { | |
158 | if ((e->eventMask & XFixesDisplayCursorNotifyMask)) { | |
159 | xXFixesCursorNotifyEvent ev = { | |
160 | .type = XFixesEventBase + XFixesCursorNotify, | |
161 | .subtype = XFixesDisplayCursorNotify, | |
162 | .window = e->pWindow->drawable.id, | |
163 | .cursorSerial = pCursor ? pCursor->serialNumber : 0, | |
164 | .timestamp = currentTime.milliseconds, | |
165 | .name = pCursor ? pCursor->name : None | |
166 | }; | |
167 | WriteEventsToClient(e->pClient, 1, (xEvent *) &ev); | |
168 | } | |
169 | } | |
170 | } | |
171 | Wrap(cs, pScreen, DisplayCursor, backupProc); | |
172 | ||
173 | return ret; | |
174 | } | |
175 | ||
176 | static Bool | |
177 | CursorCloseScreen(ScreenPtr pScreen) | |
178 | { | |
179 | CursorScreenPtr cs = GetCursorScreen(pScreen); | |
180 | Bool ret; | |
181 | _X_UNUSED CloseScreenProcPtr close_proc; | |
182 | _X_UNUSED DisplayCursorProcPtr display_proc; | |
183 | ||
184 | Unwrap(cs, pScreen, CloseScreen, close_proc); | |
185 | Unwrap(cs, pScreen, DisplayCursor, display_proc); | |
186 | deleteCursorHideCountsForScreen(pScreen); | |
187 | ret = (*pScreen->CloseScreen) (pScreen); | |
188 | free(cs); | |
189 | return ret; | |
190 | } | |
191 | ||
192 | #define CursorAllEvents (XFixesDisplayCursorNotifyMask) | |
193 | ||
194 | static int | |
195 | XFixesSelectCursorInput(ClientPtr pClient, WindowPtr pWindow, CARD32 eventMask) | |
196 | { | |
197 | CursorEventPtr *prev, e; | |
198 | pointer val; | |
199 | int rc; | |
200 | ||
201 | for (prev = &cursorEvents; (e = *prev); prev = &e->next) { | |
202 | if (e->pClient == pClient && e->pWindow == pWindow) { | |
203 | break; | |
204 | } | |
205 | } | |
206 | if (!eventMask) { | |
207 | if (e) { | |
208 | FreeResource(e->clientResource, 0); | |
209 | } | |
210 | return Success; | |
211 | } | |
212 | if (!e) { | |
213 | e = (CursorEventPtr) malloc(sizeof(CursorEventRec)); | |
214 | if (!e) | |
215 | return BadAlloc; | |
216 | ||
217 | e->next = 0; | |
218 | e->pClient = pClient; | |
219 | e->pWindow = pWindow; | |
220 | e->clientResource = FakeClientID(pClient->index); | |
221 | ||
222 | /* | |
223 | * Add a resource hanging from the window to | |
224 | * catch window destroy | |
225 | */ | |
226 | rc = dixLookupResourceByType(&val, pWindow->drawable.id, | |
227 | CursorWindowType, serverClient, | |
228 | DixGetAttrAccess); | |
229 | if (rc != Success) | |
230 | if (!AddResource(pWindow->drawable.id, CursorWindowType, | |
231 | (pointer) pWindow)) { | |
232 | free(e); | |
233 | return BadAlloc; | |
234 | } | |
235 | ||
236 | if (!AddResource(e->clientResource, CursorClientType, (pointer) e)) | |
237 | return BadAlloc; | |
238 | ||
239 | *prev = e; | |
240 | } | |
241 | e->eventMask = eventMask; | |
242 | return Success; | |
243 | } | |
244 | ||
245 | int | |
246 | ProcXFixesSelectCursorInput(ClientPtr client) | |
247 | { | |
248 | REQUEST(xXFixesSelectCursorInputReq); | |
249 | WindowPtr pWin; | |
250 | int rc; | |
251 | ||
252 | REQUEST_SIZE_MATCH(xXFixesSelectCursorInputReq); | |
253 | rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); | |
254 | if (rc != Success) | |
255 | return rc; | |
256 | if (stuff->eventMask & ~CursorAllEvents) { | |
257 | client->errorValue = stuff->eventMask; | |
258 | return BadValue; | |
259 | } | |
260 | return XFixesSelectCursorInput(client, pWin, stuff->eventMask); | |
261 | } | |
262 | ||
263 | static int | |
264 | GetBit(unsigned char *line, int x) | |
265 | { | |
266 | unsigned char mask; | |
267 | ||
268 | if (screenInfo.bitmapBitOrder == LSBFirst) | |
269 | mask = (1 << (x & 7)); | |
270 | else | |
271 | mask = (0x80 >> (x & 7)); | |
272 | /* XXX assumes byte order is host byte order */ | |
273 | line += (x >> 3); | |
274 | if (*line & mask) | |
275 | return 1; | |
276 | return 0; | |
277 | } | |
278 | ||
279 | int | |
280 | SProcXFixesSelectCursorInput(ClientPtr client) | |
281 | { | |
282 | REQUEST(xXFixesSelectCursorInputReq); | |
283 | ||
284 | swaps(&stuff->length); | |
285 | swapl(&stuff->window); | |
286 | swapl(&stuff->eventMask); | |
287 | return (*ProcXFixesVector[stuff->xfixesReqType]) (client); | |
288 | } | |
289 | ||
290 | void | |
291 | SXFixesCursorNotifyEvent(xXFixesCursorNotifyEvent * from, | |
292 | xXFixesCursorNotifyEvent * to) | |
293 | { | |
294 | to->type = from->type; | |
295 | cpswaps(from->sequenceNumber, to->sequenceNumber); | |
296 | cpswapl(from->window, to->window); | |
297 | cpswapl(from->cursorSerial, to->cursorSerial); | |
298 | cpswapl(from->timestamp, to->timestamp); | |
299 | cpswapl(from->name, to->name); | |
300 | } | |
301 | ||
302 | static void | |
303 | CopyCursorToImage(CursorPtr pCursor, CARD32 *image) | |
304 | { | |
305 | int width = pCursor->bits->width; | |
306 | int height = pCursor->bits->height; | |
307 | int npixels = width * height; | |
308 | ||
309 | #ifdef ARGB_CURSOR | |
310 | if (pCursor->bits->argb) | |
311 | memcpy(image, pCursor->bits->argb, npixels * sizeof(CARD32)); | |
312 | else | |
313 | #endif | |
314 | { | |
315 | unsigned char *srcLine = pCursor->bits->source; | |
316 | unsigned char *mskLine = pCursor->bits->mask; | |
317 | int stride = BitmapBytePad(width); | |
318 | int x, y; | |
319 | CARD32 fg, bg; | |
320 | ||
321 | fg = (0xff000000 | | |
322 | ((pCursor->foreRed & 0xff00) << 8) | | |
323 | (pCursor->foreGreen & 0xff00) | (pCursor->foreBlue >> 8)); | |
324 | bg = (0xff000000 | | |
325 | ((pCursor->backRed & 0xff00) << 8) | | |
326 | (pCursor->backGreen & 0xff00) | (pCursor->backBlue >> 8)); | |
327 | for (y = 0; y < height; y++) { | |
328 | for (x = 0; x < width; x++) { | |
329 | if (GetBit(mskLine, x)) { | |
330 | if (GetBit(srcLine, x)) | |
331 | *image++ = fg; | |
332 | else | |
333 | *image++ = bg; | |
334 | } | |
335 | else | |
336 | *image++ = 0; | |
337 | } | |
338 | srcLine += stride; | |
339 | mskLine += stride; | |
340 | } | |
341 | } | |
342 | } | |
343 | ||
344 | int | |
345 | ProcXFixesGetCursorImage(ClientPtr client) | |
346 | { | |
347 | /* REQUEST(xXFixesGetCursorImageReq); */ | |
348 | xXFixesGetCursorImageReply *rep; | |
349 | CursorPtr pCursor; | |
350 | CARD32 *image; | |
351 | int npixels, width, height, rc, x, y; | |
352 | ||
353 | REQUEST_SIZE_MATCH(xXFixesGetCursorImageReq); | |
354 | pCursor = CursorCurrent[PickPointer(client)->id]; | |
355 | if (!pCursor) | |
356 | return BadCursor; | |
357 | rc = XaceHook(XACE_RESOURCE_ACCESS, client, pCursor->id, RT_CURSOR, | |
358 | pCursor, RT_NONE, NULL, DixReadAccess); | |
359 | if (rc != Success) | |
360 | return rc; | |
361 | GetSpritePosition(PickPointer(client), &x, &y); | |
362 | width = pCursor->bits->width; | |
363 | height = pCursor->bits->height; | |
364 | npixels = width * height; | |
365 | rep = calloc(sizeof(xXFixesGetCursorImageReply) + npixels * sizeof(CARD32), | |
366 | 1); | |
367 | if (!rep) | |
368 | return BadAlloc; | |
369 | ||
370 | rep->type = X_Reply; | |
371 | rep->sequenceNumber = client->sequence; | |
372 | rep->length = npixels; | |
373 | rep->width = width; | |
374 | rep->height = height; | |
375 | rep->x = x; | |
376 | rep->y = y; | |
377 | rep->xhot = pCursor->bits->xhot; | |
378 | rep->yhot = pCursor->bits->yhot; | |
379 | rep->cursorSerial = pCursor->serialNumber; | |
380 | ||
381 | image = (CARD32 *) (rep + 1); | |
382 | CopyCursorToImage(pCursor, image); | |
383 | if (client->swapped) { | |
384 | swaps(&rep->sequenceNumber); | |
385 | swapl(&rep->length); | |
386 | swaps(&rep->x); | |
387 | swaps(&rep->y); | |
388 | swaps(&rep->width); | |
389 | swaps(&rep->height); | |
390 | swaps(&rep->xhot); | |
391 | swaps(&rep->yhot); | |
392 | swapl(&rep->cursorSerial); | |
393 | SwapLongs(image, npixels); | |
394 | } | |
395 | WriteToClient(client, | |
396 | sizeof(xXFixesGetCursorImageReply) + (npixels << 2), rep); | |
397 | free(rep); | |
398 | return Success; | |
399 | } | |
400 | ||
401 | int | |
402 | SProcXFixesGetCursorImage(ClientPtr client) | |
403 | { | |
404 | REQUEST(xXFixesGetCursorImageReq); | |
405 | swaps(&stuff->length); | |
406 | return (*ProcXFixesVector[stuff->xfixesReqType]) (client); | |
407 | } | |
408 | ||
409 | int | |
410 | ProcXFixesSetCursorName(ClientPtr client) | |
411 | { | |
412 | CursorPtr pCursor; | |
413 | char *tchar; | |
414 | ||
415 | REQUEST(xXFixesSetCursorNameReq); | |
416 | Atom atom; | |
417 | ||
418 | REQUEST_AT_LEAST_SIZE(xXFixesSetCursorNameReq); | |
419 | VERIFY_CURSOR(pCursor, stuff->cursor, client, DixSetAttrAccess); | |
420 | tchar = (char *) &stuff[1]; | |
421 | atom = MakeAtom(tchar, stuff->nbytes, TRUE); | |
422 | if (atom == BAD_RESOURCE) | |
423 | return BadAlloc; | |
424 | ||
425 | pCursor->name = atom; | |
426 | return Success; | |
427 | } | |
428 | ||
429 | int | |
430 | SProcXFixesSetCursorName(ClientPtr client) | |
431 | { | |
432 | REQUEST(xXFixesSetCursorNameReq); | |
433 | ||
434 | swaps(&stuff->length); | |
435 | REQUEST_AT_LEAST_SIZE(xXFixesSetCursorNameReq); | |
436 | swapl(&stuff->cursor); | |
437 | swaps(&stuff->nbytes); | |
438 | return (*ProcXFixesVector[stuff->xfixesReqType]) (client); | |
439 | } | |
440 | ||
441 | int | |
442 | ProcXFixesGetCursorName(ClientPtr client) | |
443 | { | |
444 | CursorPtr pCursor; | |
445 | xXFixesGetCursorNameReply reply; | |
446 | ||
447 | REQUEST(xXFixesGetCursorNameReq); | |
448 | const char *str; | |
449 | int len; | |
450 | ||
451 | REQUEST_SIZE_MATCH(xXFixesGetCursorNameReq); | |
452 | VERIFY_CURSOR(pCursor, stuff->cursor, client, DixGetAttrAccess); | |
453 | if (pCursor->name) | |
454 | str = NameForAtom(pCursor->name); | |
455 | else | |
456 | str = ""; | |
457 | len = strlen(str); | |
458 | ||
459 | reply = (xXFixesGetCursorNameReply) { | |
460 | .type = X_Reply, | |
461 | .sequenceNumber = client->sequence, | |
462 | .length = bytes_to_int32(len), | |
463 | .atom = pCursor->name, | |
464 | .nbytes = len | |
465 | }; | |
466 | if (client->swapped) { | |
467 | swaps(&reply.sequenceNumber); | |
468 | swapl(&reply.length); | |
469 | swapl(&reply.atom); | |
470 | swaps(&reply.nbytes); | |
471 | } | |
472 | WriteReplyToClient(client, sizeof(xXFixesGetCursorNameReply), &reply); | |
473 | WriteToClient(client, len, str); | |
474 | ||
475 | return Success; | |
476 | } | |
477 | ||
478 | int | |
479 | SProcXFixesGetCursorName(ClientPtr client) | |
480 | { | |
481 | REQUEST(xXFixesGetCursorNameReq); | |
482 | ||
483 | swaps(&stuff->length); | |
484 | REQUEST_SIZE_MATCH(xXFixesGetCursorNameReq); | |
485 | swapl(&stuff->cursor); | |
486 | return (*ProcXFixesVector[stuff->xfixesReqType]) (client); | |
487 | } | |
488 | ||
489 | int | |
490 | ProcXFixesGetCursorImageAndName(ClientPtr client) | |
491 | { | |
492 | /* REQUEST(xXFixesGetCursorImageAndNameReq); */ | |
493 | xXFixesGetCursorImageAndNameReply *rep; | |
494 | CursorPtr pCursor; | |
495 | CARD32 *image; | |
496 | int npixels; | |
497 | const char *name; | |
498 | int nbytes, nbytesRound; | |
499 | int width, height; | |
500 | int rc, x, y; | |
501 | ||
502 | REQUEST_SIZE_MATCH(xXFixesGetCursorImageAndNameReq); | |
503 | pCursor = CursorCurrent[PickPointer(client)->id]; | |
504 | if (!pCursor) | |
505 | return BadCursor; | |
506 | rc = XaceHook(XACE_RESOURCE_ACCESS, client, pCursor->id, RT_CURSOR, | |
507 | pCursor, RT_NONE, NULL, DixReadAccess | DixGetAttrAccess); | |
508 | if (rc != Success) | |
509 | return rc; | |
510 | GetSpritePosition(PickPointer(client), &x, &y); | |
511 | width = pCursor->bits->width; | |
512 | height = pCursor->bits->height; | |
513 | npixels = width * height; | |
514 | name = pCursor->name ? NameForAtom(pCursor->name) : ""; | |
515 | nbytes = strlen(name); | |
516 | nbytesRound = pad_to_int32(nbytes); | |
517 | rep = calloc(sizeof(xXFixesGetCursorImageAndNameReply) + | |
518 | npixels * sizeof(CARD32) + nbytesRound, 1); | |
519 | if (!rep) | |
520 | return BadAlloc; | |
521 | ||
522 | rep->type = X_Reply; | |
523 | rep->sequenceNumber = client->sequence; | |
524 | rep->length = npixels + bytes_to_int32(nbytesRound); | |
525 | rep->width = width; | |
526 | rep->height = height; | |
527 | rep->x = x; | |
528 | rep->y = y; | |
529 | rep->xhot = pCursor->bits->xhot; | |
530 | rep->yhot = pCursor->bits->yhot; | |
531 | rep->cursorSerial = pCursor->serialNumber; | |
532 | rep->cursorName = pCursor->name; | |
533 | rep->nbytes = nbytes; | |
534 | ||
535 | image = (CARD32 *) (rep + 1); | |
536 | CopyCursorToImage(pCursor, image); | |
537 | memcpy((image + npixels), name, nbytes); | |
538 | if (client->swapped) { | |
539 | swaps(&rep->sequenceNumber); | |
540 | swapl(&rep->length); | |
541 | swaps(&rep->x); | |
542 | swaps(&rep->y); | |
543 | swaps(&rep->width); | |
544 | swaps(&rep->height); | |
545 | swaps(&rep->xhot); | |
546 | swaps(&rep->yhot); | |
547 | swapl(&rep->cursorSerial); | |
548 | swapl(&rep->cursorName); | |
549 | swaps(&rep->nbytes); | |
550 | SwapLongs(image, npixels); | |
551 | } | |
552 | WriteToClient(client, sizeof(xXFixesGetCursorImageAndNameReply) + | |
553 | (npixels << 2) + nbytesRound, rep); | |
554 | free(rep); | |
555 | return Success; | |
556 | } | |
557 | ||
558 | int | |
559 | SProcXFixesGetCursorImageAndName(ClientPtr client) | |
560 | { | |
561 | REQUEST(xXFixesGetCursorImageAndNameReq); | |
562 | swaps(&stuff->length); | |
563 | return (*ProcXFixesVector[stuff->xfixesReqType]) (client); | |
564 | } | |
565 | ||
566 | /* | |
567 | * Find every cursor reference in the system, ask testCursor | |
568 | * whether it should be replaced with a reference to pCursor. | |
569 | */ | |
570 | ||
571 | typedef Bool (*TestCursorFunc) (CursorPtr pOld, pointer closure); | |
572 | ||
573 | typedef struct { | |
574 | RESTYPE type; | |
575 | TestCursorFunc testCursor; | |
576 | CursorPtr pNew; | |
577 | pointer closure; | |
578 | } ReplaceCursorLookupRec, *ReplaceCursorLookupPtr; | |
579 | ||
580 | static const RESTYPE CursorRestypes[] = { | |
581 | RT_WINDOW, RT_PASSIVEGRAB, RT_CURSOR | |
582 | }; | |
583 | ||
584 | #define NUM_CURSOR_RESTYPES (sizeof (CursorRestypes) / sizeof (CursorRestypes[0])) | |
585 | ||
586 | static Bool | |
587 | ReplaceCursorLookup(pointer value, XID id, pointer closure) | |
588 | { | |
589 | ReplaceCursorLookupPtr rcl = (ReplaceCursorLookupPtr) closure; | |
590 | WindowPtr pWin; | |
591 | GrabPtr pGrab; | |
592 | CursorPtr pCursor = 0, *pCursorRef = 0; | |
593 | XID cursor = 0; | |
594 | ||
595 | switch (rcl->type) { | |
596 | case RT_WINDOW: | |
597 | pWin = (WindowPtr) value; | |
598 | if (pWin->optional) { | |
599 | pCursorRef = &pWin->optional->cursor; | |
600 | pCursor = *pCursorRef; | |
601 | } | |
602 | break; | |
603 | case RT_PASSIVEGRAB: | |
604 | pGrab = (GrabPtr) value; | |
605 | pCursorRef = &pGrab->cursor; | |
606 | pCursor = *pCursorRef; | |
607 | break; | |
608 | case RT_CURSOR: | |
609 | pCursorRef = 0; | |
610 | pCursor = (CursorPtr) value; | |
611 | cursor = id; | |
612 | break; | |
613 | } | |
614 | if (pCursor && pCursor != rcl->pNew) { | |
615 | if ((*rcl->testCursor) (pCursor, rcl->closure)) { | |
616 | CursorPtr curs = RefCursor(rcl->pNew); | |
617 | /* either redirect reference or update resource database */ | |
618 | if (pCursorRef) | |
619 | *pCursorRef = curs; | |
620 | else | |
621 | ChangeResourceValue(id, RT_CURSOR, curs); | |
622 | FreeCursor(pCursor, cursor); | |
623 | } | |
624 | } | |
625 | return FALSE; /* keep walking */ | |
626 | } | |
627 | ||
628 | static void | |
629 | ReplaceCursor(CursorPtr pCursor, TestCursorFunc testCursor, pointer closure) | |
630 | { | |
631 | int clientIndex; | |
632 | int resIndex; | |
633 | ReplaceCursorLookupRec rcl; | |
634 | ||
635 | /* | |
636 | * Cursors exist only in the resource database, windows and grabs. | |
637 | * All of these are always pointed at by the resource database. Walk | |
638 | * the whole thing looking for cursors | |
639 | */ | |
640 | rcl.testCursor = testCursor; | |
641 | rcl.pNew = pCursor; | |
642 | rcl.closure = closure; | |
643 | ||
644 | /* for each client */ | |
645 | for (clientIndex = 0; clientIndex < currentMaxClients; clientIndex++) { | |
646 | if (!clients[clientIndex]) | |
647 | continue; | |
648 | for (resIndex = 0; resIndex < NUM_CURSOR_RESTYPES; resIndex++) { | |
649 | rcl.type = CursorRestypes[resIndex]; | |
650 | /* | |
651 | * This function walks the entire client resource database | |
652 | */ | |
653 | LookupClientResourceComplex(clients[clientIndex], | |
654 | rcl.type, | |
655 | ReplaceCursorLookup, (pointer) &rcl); | |
656 | } | |
657 | } | |
658 | /* this "knows" that WindowHasNewCursor doesn't depend on it's argument */ | |
659 | WindowHasNewCursor(screenInfo.screens[0]->root); | |
660 | } | |
661 | ||
662 | static Bool | |
663 | TestForCursor(CursorPtr pCursor, pointer closure) | |
664 | { | |
665 | return (pCursor == (CursorPtr) closure); | |
666 | } | |
667 | ||
668 | int | |
669 | ProcXFixesChangeCursor(ClientPtr client) | |
670 | { | |
671 | CursorPtr pSource, pDestination; | |
672 | ||
673 | REQUEST(xXFixesChangeCursorReq); | |
674 | ||
675 | REQUEST_SIZE_MATCH(xXFixesChangeCursorReq); | |
676 | VERIFY_CURSOR(pSource, stuff->source, client, | |
677 | DixReadAccess | DixGetAttrAccess); | |
678 | VERIFY_CURSOR(pDestination, stuff->destination, client, | |
679 | DixWriteAccess | DixSetAttrAccess); | |
680 | ||
681 | ReplaceCursor(pSource, TestForCursor, (pointer) pDestination); | |
682 | return Success; | |
683 | } | |
684 | ||
685 | int | |
686 | SProcXFixesChangeCursor(ClientPtr client) | |
687 | { | |
688 | REQUEST(xXFixesChangeCursorReq); | |
689 | ||
690 | swaps(&stuff->length); | |
691 | REQUEST_SIZE_MATCH(xXFixesChangeCursorReq); | |
692 | swapl(&stuff->source); | |
693 | swapl(&stuff->destination); | |
694 | return (*ProcXFixesVector[stuff->xfixesReqType]) (client); | |
695 | } | |
696 | ||
697 | static Bool | |
698 | TestForCursorName(CursorPtr pCursor, pointer closure) | |
699 | { | |
700 | Atom *pName = closure; | |
701 | ||
702 | return pCursor->name == *pName; | |
703 | } | |
704 | ||
705 | int | |
706 | ProcXFixesChangeCursorByName(ClientPtr client) | |
707 | { | |
708 | CursorPtr pSource; | |
709 | Atom name; | |
710 | char *tchar; | |
711 | ||
712 | REQUEST(xXFixesChangeCursorByNameReq); | |
713 | ||
714 | REQUEST_FIXED_SIZE(xXFixesChangeCursorByNameReq, stuff->nbytes); | |
715 | VERIFY_CURSOR(pSource, stuff->source, client, | |
716 | DixReadAccess | DixGetAttrAccess); | |
717 | tchar = (char *) &stuff[1]; | |
718 | name = MakeAtom(tchar, stuff->nbytes, FALSE); | |
719 | if (name) | |
720 | ReplaceCursor(pSource, TestForCursorName, &name); | |
721 | return Success; | |
722 | } | |
723 | ||
724 | int | |
725 | SProcXFixesChangeCursorByName(ClientPtr client) | |
726 | { | |
727 | REQUEST(xXFixesChangeCursorByNameReq); | |
728 | ||
729 | swaps(&stuff->length); | |
730 | REQUEST_AT_LEAST_SIZE(xXFixesChangeCursorByNameReq); | |
731 | swapl(&stuff->source); | |
732 | swaps(&stuff->nbytes); | |
733 | return (*ProcXFixesVector[stuff->xfixesReqType]) (client); | |
734 | } | |
735 | ||
736 | /* | |
737 | * Routines for manipulating the per-screen hide counts list. | |
738 | * This list indicates which clients have requested cursor hiding | |
739 | * for that screen. | |
740 | */ | |
741 | ||
742 | /* Return the screen's hide-counts list element for the given client */ | |
743 | static CursorHideCountPtr | |
744 | findCursorHideCount(ClientPtr pClient, ScreenPtr pScreen) | |
745 | { | |
746 | CursorScreenPtr cs = GetCursorScreen(pScreen); | |
747 | CursorHideCountPtr pChc; | |
748 | ||
749 | for (pChc = cs->pCursorHideCounts; pChc != NULL; pChc = pChc->pNext) { | |
750 | if (pChc->pClient == pClient) { | |
751 | return pChc; | |
752 | } | |
753 | } | |
754 | ||
755 | return NULL; | |
756 | } | |
757 | ||
758 | static int | |
759 | createCursorHideCount(ClientPtr pClient, ScreenPtr pScreen) | |
760 | { | |
761 | CursorScreenPtr cs = GetCursorScreen(pScreen); | |
762 | CursorHideCountPtr pChc; | |
763 | ||
764 | pChc = (CursorHideCountPtr) malloc(sizeof(CursorHideCountRec)); | |
765 | if (pChc == NULL) { | |
766 | return BadAlloc; | |
767 | } | |
768 | pChc->pClient = pClient; | |
769 | pChc->pScreen = pScreen; | |
770 | pChc->hideCount = 1; | |
771 | pChc->resource = FakeClientID(pClient->index); | |
772 | pChc->pNext = cs->pCursorHideCounts; | |
773 | cs->pCursorHideCounts = pChc; | |
774 | ||
775 | /* | |
776 | * Create a resource for this element so it can be deleted | |
777 | * when the client goes away. | |
778 | */ | |
779 | if (!AddResource(pChc->resource, CursorHideCountType, (pointer) pChc)) { | |
780 | free(pChc); | |
781 | return BadAlloc; | |
782 | } | |
783 | ||
784 | return Success; | |
785 | } | |
786 | ||
787 | /* | |
788 | * Delete the given hide-counts list element from its screen list. | |
789 | */ | |
790 | static void | |
791 | deleteCursorHideCount(CursorHideCountPtr pChcToDel, ScreenPtr pScreen) | |
792 | { | |
793 | CursorScreenPtr cs = GetCursorScreen(pScreen); | |
794 | CursorHideCountPtr pChc, pNext; | |
795 | CursorHideCountPtr pChcLast = NULL; | |
796 | ||
797 | pChc = cs->pCursorHideCounts; | |
798 | while (pChc != NULL) { | |
799 | pNext = pChc->pNext; | |
800 | if (pChc == pChcToDel) { | |
801 | free(pChc); | |
802 | if (pChcLast == NULL) { | |
803 | cs->pCursorHideCounts = pNext; | |
804 | } | |
805 | else { | |
806 | pChcLast->pNext = pNext; | |
807 | } | |
808 | return; | |
809 | } | |
810 | pChcLast = pChc; | |
811 | pChc = pNext; | |
812 | } | |
813 | } | |
814 | ||
815 | /* | |
816 | * Delete all the hide-counts list elements for this screen. | |
817 | */ | |
818 | static void | |
819 | deleteCursorHideCountsForScreen(ScreenPtr pScreen) | |
820 | { | |
821 | CursorScreenPtr cs = GetCursorScreen(pScreen); | |
822 | CursorHideCountPtr pChc, pTmp; | |
823 | ||
824 | pChc = cs->pCursorHideCounts; | |
825 | while (pChc != NULL) { | |
826 | pTmp = pChc->pNext; | |
827 | FreeResource(pChc->resource, 0); | |
828 | pChc = pTmp; | |
829 | } | |
830 | cs->pCursorHideCounts = NULL; | |
831 | } | |
832 | ||
833 | int | |
834 | ProcXFixesHideCursor(ClientPtr client) | |
835 | { | |
836 | WindowPtr pWin; | |
837 | CursorHideCountPtr pChc; | |
838 | ||
839 | REQUEST(xXFixesHideCursorReq); | |
840 | int ret; | |
841 | ||
842 | REQUEST_SIZE_MATCH(xXFixesHideCursorReq); | |
843 | ||
844 | ret = dixLookupResourceByType((pointer *) &pWin, stuff->window, RT_WINDOW, | |
845 | client, DixGetAttrAccess); | |
846 | if (ret != Success) { | |
847 | client->errorValue = stuff->window; | |
848 | return ret; | |
849 | } | |
850 | ||
851 | /* | |
852 | * Has client hidden the cursor before on this screen? | |
853 | * If so, just increment the count. | |
854 | */ | |
855 | ||
856 | pChc = findCursorHideCount(client, pWin->drawable.pScreen); | |
857 | if (pChc != NULL) { | |
858 | pChc->hideCount++; | |
859 | return Success; | |
860 | } | |
861 | ||
862 | /* | |
863 | * This is the first time this client has hid the cursor | |
864 | * for this screen. | |
865 | */ | |
866 | ret = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen, | |
867 | DixHideAccess); | |
868 | if (ret != Success) | |
869 | return ret; | |
870 | ||
871 | ret = createCursorHideCount(client, pWin->drawable.pScreen); | |
872 | ||
873 | if (ret == Success) { | |
874 | DeviceIntPtr dev; | |
875 | ||
876 | for (dev = inputInfo.devices; dev; dev = dev->next) { | |
877 | if (IsMaster(dev) && IsPointerDevice(dev)) | |
878 | CursorDisplayCursor(dev, pWin->drawable.pScreen, | |
879 | CursorCurrent[dev->id]); | |
880 | } | |
881 | } | |
882 | ||
883 | return ret; | |
884 | } | |
885 | ||
886 | int | |
887 | SProcXFixesHideCursor(ClientPtr client) | |
888 | { | |
889 | REQUEST(xXFixesHideCursorReq); | |
890 | ||
891 | swaps(&stuff->length); | |
892 | REQUEST_SIZE_MATCH(xXFixesHideCursorReq); | |
893 | swapl(&stuff->window); | |
894 | return (*ProcXFixesVector[stuff->xfixesReqType]) (client); | |
895 | } | |
896 | ||
897 | int | |
898 | ProcXFixesShowCursor(ClientPtr client) | |
899 | { | |
900 | WindowPtr pWin; | |
901 | CursorHideCountPtr pChc; | |
902 | int rc; | |
903 | ||
904 | REQUEST(xXFixesShowCursorReq); | |
905 | ||
906 | REQUEST_SIZE_MATCH(xXFixesShowCursorReq); | |
907 | ||
908 | rc = dixLookupResourceByType((pointer *) &pWin, stuff->window, RT_WINDOW, | |
909 | client, DixGetAttrAccess); | |
910 | if (rc != Success) { | |
911 | client->errorValue = stuff->window; | |
912 | return rc; | |
913 | } | |
914 | ||
915 | /* | |
916 | * Has client hidden the cursor on this screen? | |
917 | * If not, generate an error. | |
918 | */ | |
919 | pChc = findCursorHideCount(client, pWin->drawable.pScreen); | |
920 | if (pChc == NULL) { | |
921 | return BadMatch; | |
922 | } | |
923 | ||
924 | rc = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen, | |
925 | DixShowAccess); | |
926 | if (rc != Success) | |
927 | return rc; | |
928 | ||
929 | pChc->hideCount--; | |
930 | if (pChc->hideCount <= 0) { | |
931 | FreeResource(pChc->resource, 0); | |
932 | } | |
933 | ||
934 | return Success; | |
935 | } | |
936 | ||
937 | int | |
938 | SProcXFixesShowCursor(ClientPtr client) | |
939 | { | |
940 | REQUEST(xXFixesShowCursorReq); | |
941 | ||
942 | swaps(&stuff->length); | |
943 | REQUEST_SIZE_MATCH(xXFixesShowCursorReq); | |
944 | swapl(&stuff->window); | |
945 | return (*ProcXFixesVector[stuff->xfixesReqType]) (client); | |
946 | } | |
947 | ||
948 | static int | |
949 | CursorFreeClient(pointer data, XID id) | |
950 | { | |
951 | CursorEventPtr old = (CursorEventPtr) data; | |
952 | CursorEventPtr *prev, e; | |
953 | ||
954 | for (prev = &cursorEvents; (e = *prev); prev = &e->next) { | |
955 | if (e == old) { | |
956 | *prev = e->next; | |
957 | free(e); | |
958 | break; | |
959 | } | |
960 | } | |
961 | return 1; | |
962 | } | |
963 | ||
964 | static int | |
965 | CursorFreeHideCount(pointer data, XID id) | |
966 | { | |
967 | CursorHideCountPtr pChc = (CursorHideCountPtr) data; | |
968 | ScreenPtr pScreen = pChc->pScreen; | |
969 | DeviceIntPtr dev; | |
970 | ||
971 | deleteCursorHideCount(pChc, pChc->pScreen); | |
972 | for (dev = inputInfo.devices; dev; dev = dev->next) { | |
973 | if (IsMaster(dev) && IsPointerDevice(dev)) | |
974 | CursorDisplayCursor(dev, pScreen, CursorCurrent[dev->id]); | |
975 | } | |
976 | ||
977 | return 1; | |
978 | } | |
979 | ||
980 | static int | |
981 | CursorFreeWindow(pointer data, XID id) | |
982 | { | |
983 | WindowPtr pWindow = (WindowPtr) data; | |
984 | CursorEventPtr e, next; | |
985 | ||
986 | for (e = cursorEvents; e; e = next) { | |
987 | next = e->next; | |
988 | if (e->pWindow == pWindow) { | |
989 | FreeResource(e->clientResource, 0); | |
990 | } | |
991 | } | |
992 | return 1; | |
993 | } | |
994 | ||
995 | int | |
996 | ProcXFixesCreatePointerBarrier(ClientPtr client) | |
997 | { | |
998 | REQUEST(xXFixesCreatePointerBarrierReq); | |
999 | ||
1000 | REQUEST_FIXED_SIZE(xXFixesCreatePointerBarrierReq, pad_to_int32(stuff->num_devices)); | |
1001 | LEGAL_NEW_RESOURCE(stuff->barrier, client); | |
1002 | ||
1003 | return XICreatePointerBarrier(client, stuff); | |
1004 | } | |
1005 | ||
1006 | int | |
1007 | SProcXFixesCreatePointerBarrier(ClientPtr client) | |
1008 | { | |
1009 | REQUEST(xXFixesCreatePointerBarrierReq); | |
1010 | int i; | |
1011 | CARD16 *in_devices = (CARD16 *) &stuff[1]; | |
1012 | ||
1013 | swaps(&stuff->length); | |
1014 | swaps(&stuff->num_devices); | |
1015 | REQUEST_FIXED_SIZE(xXFixesCreatePointerBarrierReq, pad_to_int32(stuff->num_devices)); | |
1016 | ||
1017 | swapl(&stuff->barrier); | |
1018 | swapl(&stuff->window); | |
1019 | swaps(&stuff->x1); | |
1020 | swaps(&stuff->y1); | |
1021 | swaps(&stuff->x2); | |
1022 | swaps(&stuff->y2); | |
1023 | swapl(&stuff->directions); | |
1024 | for (i = 0; i < stuff->num_devices; i++) { | |
1025 | swaps(in_devices + i); | |
1026 | } | |
1027 | ||
1028 | return ProcXFixesVector[stuff->xfixesReqType] (client); | |
1029 | } | |
1030 | ||
1031 | int | |
1032 | ProcXFixesDestroyPointerBarrier(ClientPtr client) | |
1033 | { | |
1034 | REQUEST(xXFixesDestroyPointerBarrierReq); | |
1035 | ||
1036 | REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq); | |
1037 | ||
1038 | return XIDestroyPointerBarrier(client, stuff); | |
1039 | } | |
1040 | ||
1041 | int | |
1042 | SProcXFixesDestroyPointerBarrier(ClientPtr client) | |
1043 | { | |
1044 | REQUEST(xXFixesDestroyPointerBarrierReq); | |
1045 | ||
1046 | swaps(&stuff->length); | |
1047 | REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq); | |
1048 | swapl(&stuff->barrier); | |
1049 | return ProcXFixesVector[stuff->xfixesReqType] (client); | |
1050 | } | |
1051 | ||
1052 | Bool | |
1053 | XFixesCursorInit(void) | |
1054 | { | |
1055 | int i; | |
1056 | ||
1057 | if (party_like_its_1989) | |
1058 | CursorVisible = EnableCursor; | |
1059 | ||
1060 | if (!dixRegisterPrivateKey(&CursorScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) | |
1061 | return FALSE; | |
1062 | ||
1063 | for (i = 0; i < screenInfo.numScreens; i++) { | |
1064 | ScreenPtr pScreen = screenInfo.screens[i]; | |
1065 | CursorScreenPtr cs; | |
1066 | ||
1067 | cs = (CursorScreenPtr) calloc(1, sizeof(CursorScreenRec)); | |
1068 | if (!cs) | |
1069 | return FALSE; | |
1070 | Wrap(cs, pScreen, CloseScreen, CursorCloseScreen); | |
1071 | Wrap(cs, pScreen, DisplayCursor, CursorDisplayCursor); | |
1072 | cs->pCursorHideCounts = NULL; | |
1073 | SetCursorScreen(pScreen, cs); | |
1074 | } | |
1075 | CursorClientType = CreateNewResourceType(CursorFreeClient, | |
1076 | "XFixesCursorClient"); | |
1077 | CursorHideCountType = CreateNewResourceType(CursorFreeHideCount, | |
1078 | "XFixesCursorHideCount"); | |
1079 | CursorWindowType = CreateNewResourceType(CursorFreeWindow, | |
1080 | "XFixesCursorWindow"); | |
1081 | ||
1082 | return CursorClientType && CursorHideCountType && CursorWindowType; | |
1083 | } |