Imported Upstream version 1.15.1
[deb_xorg-server.git] / xfixes / cursor.c
CommitLineData
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
61static RESTYPE CursorClientType;
62static RESTYPE CursorHideCountType;
63static RESTYPE CursorWindowType;
64static CursorPtr CursorCurrent[MAXDEVICES];
65
66static DevPrivateKeyRec CursorScreenPrivateKeyRec;
67
68#define CursorScreenPrivateKey (&CursorScreenPrivateKeyRec)
69
70static 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
87typedef struct _CursorEvent *CursorEventPtr;
88
89typedef struct _CursorEvent {
90 CursorEventPtr next;
91 CARD32 eventMask;
92 ClientPtr pClient;
93 WindowPtr pWindow;
94 XID clientResource;
95} CursorEventRec;
96
97static 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
105typedef struct _CursorHideCountRec *CursorHideCountPtr;
106
107typedef 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
119typedef 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() */
132Bool CursorVisible = FALSE;
133Bool EnableCursor = TRUE;
134
135static Bool
136CursorDisplayCursor(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
176static Bool
177CursorCloseScreen(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
194static int
195XFixesSelectCursorInput(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
245int
246ProcXFixesSelectCursorInput(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
263static int
264GetBit(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
279int
280SProcXFixesSelectCursorInput(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
290void
291SXFixesCursorNotifyEvent(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
302static void
303CopyCursorToImage(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
344int
345ProcXFixesGetCursorImage(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
401int
402SProcXFixesGetCursorImage(ClientPtr client)
403{
404 REQUEST(xXFixesGetCursorImageReq);
405 swaps(&stuff->length);
406 return (*ProcXFixesVector[stuff->xfixesReqType]) (client);
407}
408
409int
410ProcXFixesSetCursorName(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
429int
430SProcXFixesSetCursorName(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
441int
442ProcXFixesGetCursorName(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
478int
479SProcXFixesGetCursorName(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
489int
490ProcXFixesGetCursorImageAndName(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
558int
559SProcXFixesGetCursorImageAndName(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
571typedef Bool (*TestCursorFunc) (CursorPtr pOld, pointer closure);
572
573typedef struct {
574 RESTYPE type;
575 TestCursorFunc testCursor;
576 CursorPtr pNew;
577 pointer closure;
578} ReplaceCursorLookupRec, *ReplaceCursorLookupPtr;
579
580static const RESTYPE CursorRestypes[] = {
581 RT_WINDOW, RT_PASSIVEGRAB, RT_CURSOR
582};
583
584#define NUM_CURSOR_RESTYPES (sizeof (CursorRestypes) / sizeof (CursorRestypes[0]))
585
586static Bool
587ReplaceCursorLookup(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
628static void
629ReplaceCursor(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
662static Bool
663TestForCursor(CursorPtr pCursor, pointer closure)
664{
665 return (pCursor == (CursorPtr) closure);
666}
667
668int
669ProcXFixesChangeCursor(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
685int
686SProcXFixesChangeCursor(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
697static Bool
698TestForCursorName(CursorPtr pCursor, pointer closure)
699{
700 Atom *pName = closure;
701
702 return pCursor->name == *pName;
703}
704
705int
706ProcXFixesChangeCursorByName(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
724int
725SProcXFixesChangeCursorByName(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 */
743static CursorHideCountPtr
744findCursorHideCount(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
758static int
759createCursorHideCount(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 */
790static void
791deleteCursorHideCount(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 */
818static void
819deleteCursorHideCountsForScreen(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
833int
834ProcXFixesHideCursor(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
886int
887SProcXFixesHideCursor(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
897int
898ProcXFixesShowCursor(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
937int
938SProcXFixesShowCursor(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
948static int
949CursorFreeClient(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
964static int
965CursorFreeHideCount(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
980static int
981CursorFreeWindow(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
995int
996ProcXFixesCreatePointerBarrier(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
1006int
1007SProcXFixesCreatePointerBarrier(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
1031int
1032ProcXFixesDestroyPointerBarrier(ClientPtr client)
1033{
1034 REQUEST(xXFixesDestroyPointerBarrierReq);
1035
1036 REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq);
1037
1038 return XIDestroyPointerBarrier(client, stuff);
1039}
1040
1041int
1042SProcXFixesDestroyPointerBarrier(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
1052Bool
1053XFixesCursorInit(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}