Imported Upstream version 1.15.1
[deb_xorg-server.git] / Xext / shape.c
CommitLineData
a09e091a
JB
1/************************************************************
2
3Copyright 1989, 1998 The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25********************************************************/
26
27#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#endif
30
31#include <stdlib.h>
32
33#include <X11/X.h>
34#include <X11/Xproto.h>
35#include "misc.h"
36#include "os.h"
37#include "windowstr.h"
38#include "scrnintstr.h"
39#include "pixmapstr.h"
40#include "extnsionst.h"
41#include "dixstruct.h"
42#include "resource.h"
43#include "opaque.h"
44#include <X11/extensions/shapeproto.h>
45#include "regionstr.h"
46#include "gcstruct.h"
47#include "extinit.h"
48#include "protocol-versions.h"
49
50typedef RegionPtr (*CreateDftPtr) (WindowPtr /* pWin */
51 );
52
53static int ShapeFreeClient(pointer /* data */ ,
54 XID /* id */
55 );
56static int ShapeFreeEvents(pointer /* data */ ,
57 XID /* id */
58 );
59static void SShapeNotifyEvent(xShapeNotifyEvent * /* from */ ,
60 xShapeNotifyEvent * /* to */
61 );
62
63/* SendShapeNotify, CreateBoundingShape and CreateClipShape are used
64 * externally by the Xfixes extension and are now defined in window.h
65 */
66
67#ifdef PANORAMIX
68#include "panoramiX.h"
69#include "panoramiXsrv.h"
70#endif
71
72static int ShapeEventBase = 0;
73static RESTYPE ClientType, ShapeEventType; /* resource types for event masks */
74
75/*
76 * each window has a list of clients requesting
77 * ShapeNotify events. Each client has a resource
78 * for each window it selects ShapeNotify input for,
79 * this resource is used to delete the ShapeNotifyRec
80 * entry from the per-window queue.
81 */
82
83typedef struct _ShapeEvent *ShapeEventPtr;
84
85typedef struct _ShapeEvent {
86 ShapeEventPtr next;
87 ClientPtr client;
88 WindowPtr window;
89 XID clientResource;
90} ShapeEventRec;
91
92/****************
93 * ShapeExtensionInit
94 *
95 * Called from InitExtensions in main() or from QueryExtension() if the
96 * extension is dynamically loaded.
97 *
98 ****************/
99
100static int
101RegionOperate(ClientPtr client,
102 WindowPtr pWin,
103 int kind,
104 RegionPtr *destRgnp,
105 RegionPtr srcRgn, int op, int xoff, int yoff, CreateDftPtr create)
106{
107 if (srcRgn && (xoff || yoff))
108 RegionTranslate(srcRgn, xoff, yoff);
109 if (!pWin->parent) {
110 if (srcRgn)
111 RegionDestroy(srcRgn);
112 return Success;
113 }
114
115 /* May/30/2001:
116 * The shape.PS specs say if src is None, existing shape is to be
117 * removed (and so the op-code has no meaning in such removal);
118 * see shape.PS, page 3, ShapeMask.
119 */
120 if (srcRgn == NULL) {
121 if (*destRgnp != NULL) {
122 RegionDestroy(*destRgnp);
123 *destRgnp = 0;
124 /* go on to remove shape and generate ShapeNotify */
125 }
126 else {
127 /* May/30/2001:
128 * The target currently has no shape in effect, so nothing to
129 * do here. The specs say that ShapeNotify is generated whenever
130 * the client region is "modified"; since no modification is done
131 * here, we do not generate that event. The specs does not say
132 * "it is an error to request removal when there is no shape in
133 * effect", so we return good status.
134 */
135 return Success;
136 }
137 }
138 else
139 switch (op) {
140 case ShapeSet:
141 if (*destRgnp)
142 RegionDestroy(*destRgnp);
143 *destRgnp = srcRgn;
144 srcRgn = 0;
145 break;
146 case ShapeUnion:
147 if (*destRgnp)
148 RegionUnion(*destRgnp, *destRgnp, srcRgn);
149 break;
150 case ShapeIntersect:
151 if (*destRgnp)
152 RegionIntersect(*destRgnp, *destRgnp, srcRgn);
153 else {
154 *destRgnp = srcRgn;
155 srcRgn = 0;
156 }
157 break;
158 case ShapeSubtract:
159 if (!*destRgnp)
160 *destRgnp = (*create) (pWin);
161 RegionSubtract(*destRgnp, *destRgnp, srcRgn);
162 break;
163 case ShapeInvert:
164 if (!*destRgnp)
165 *destRgnp = RegionCreate((BoxPtr) 0, 0);
166 else
167 RegionSubtract(*destRgnp, srcRgn, *destRgnp);
168 break;
169 default:
170 client->errorValue = op;
171 return BadValue;
172 }
173 if (srcRgn)
174 RegionDestroy(srcRgn);
175 (*pWin->drawable.pScreen->SetShape) (pWin, kind);
176 SendShapeNotify(pWin, kind);
177 return Success;
178}
179
180RegionPtr
181CreateBoundingShape(WindowPtr pWin)
182{
183 BoxRec extents;
184
185 extents.x1 = -wBorderWidth(pWin);
186 extents.y1 = -wBorderWidth(pWin);
187 extents.x2 = pWin->drawable.width + wBorderWidth(pWin);
188 extents.y2 = pWin->drawable.height + wBorderWidth(pWin);
189 return RegionCreate(&extents, 1);
190}
191
192RegionPtr
193CreateClipShape(WindowPtr pWin)
194{
195 BoxRec extents;
196
197 extents.x1 = 0;
198 extents.y1 = 0;
199 extents.x2 = pWin->drawable.width;
200 extents.y2 = pWin->drawable.height;
201 return RegionCreate(&extents, 1);
202}
203
204static int
205ProcShapeQueryVersion(ClientPtr client)
206{
207 xShapeQueryVersionReply rep = {
208 .type = X_Reply,
209 .sequenceNumber = client->sequence,
210 .length = 0,
211 .majorVersion = SERVER_SHAPE_MAJOR_VERSION,
212 .minorVersion = SERVER_SHAPE_MINOR_VERSION
213 };
214
215 REQUEST_SIZE_MATCH(xShapeQueryVersionReq);
216
217 if (client->swapped) {
218 swaps(&rep.sequenceNumber);
219 swapl(&rep.length);
220 swaps(&rep.majorVersion);
221 swaps(&rep.minorVersion);
222 }
223 WriteToClient(client, sizeof(xShapeQueryVersionReply), &rep);
224 return Success;
225}
226
227/*****************
228 * ProcShapeRectangles
229 *
230 *****************/
231
232static int
233ProcShapeRectangles(ClientPtr client)
234{
235 WindowPtr pWin;
236
237 REQUEST(xShapeRectanglesReq);
238 xRectangle *prects;
239 int nrects, ctype, rc;
240 RegionPtr srcRgn;
241 RegionPtr *destRgn;
242 CreateDftPtr createDefault;
243
244 REQUEST_AT_LEAST_SIZE(xShapeRectanglesReq);
245 UpdateCurrentTime();
246 rc = dixLookupWindow(&pWin, stuff->dest, client, DixSetAttrAccess);
247 if (rc != Success)
248 return rc;
249 switch (stuff->destKind) {
250 case ShapeBounding:
251 createDefault = CreateBoundingShape;
252 break;
253 case ShapeClip:
254 createDefault = CreateClipShape;
255 break;
256 case ShapeInput:
257 createDefault = CreateBoundingShape;
258 break;
259 default:
260 client->errorValue = stuff->destKind;
261 return BadValue;
262 }
263 if ((stuff->ordering != Unsorted) && (stuff->ordering != YSorted) &&
264 (stuff->ordering != YXSorted) && (stuff->ordering != YXBanded)) {
265 client->errorValue = stuff->ordering;
266 return BadValue;
267 }
268 nrects = ((stuff->length << 2) - sizeof(xShapeRectanglesReq));
269 if (nrects & 4)
270 return BadLength;
271 nrects >>= 3;
272 prects = (xRectangle *) &stuff[1];
273 ctype = VerifyRectOrder(nrects, prects, (int) stuff->ordering);
274 if (ctype < 0)
275 return BadMatch;
276 srcRgn = RegionFromRects(nrects, prects, ctype);
277
278 if (!pWin->optional)
279 MakeWindowOptional(pWin);
280 switch (stuff->destKind) {
281 case ShapeBounding:
282 destRgn = &pWin->optional->boundingShape;
283 break;
284 case ShapeClip:
285 destRgn = &pWin->optional->clipShape;
286 break;
287 case ShapeInput:
288 destRgn = &pWin->optional->inputShape;
289 break;
290 default:
291 return BadValue;
292 }
293
294 return RegionOperate(client, pWin, (int) stuff->destKind,
295 destRgn, srcRgn, (int) stuff->op,
296 stuff->xOff, stuff->yOff, createDefault);
297}
298
299#ifdef PANORAMIX
300static int
301ProcPanoramiXShapeRectangles(ClientPtr client)
302{
303 REQUEST(xShapeRectanglesReq);
304 PanoramiXRes *win;
305 int j, result;
306
307 REQUEST_AT_LEAST_SIZE(xShapeRectanglesReq);
308
309 result = dixLookupResourceByType((pointer *) &win, stuff->dest, XRT_WINDOW,
310 client, DixWriteAccess);
311 if (result != Success)
312 return result;
313
314 FOR_NSCREENS(j) {
315 stuff->dest = win->info[j].id;
316 result = ProcShapeRectangles(client);
317 if (result != Success)
318 break;
319 }
320 return result;
321}
322#endif
323
324/**************
325 * ProcShapeMask
326 **************/
327
328static int
329ProcShapeMask(ClientPtr client)
330{
331 WindowPtr pWin;
332 ScreenPtr pScreen;
333
334 REQUEST(xShapeMaskReq);
335 RegionPtr srcRgn;
336 RegionPtr *destRgn;
337 PixmapPtr pPixmap;
338 CreateDftPtr createDefault;
339 int rc;
340
341 REQUEST_SIZE_MATCH(xShapeMaskReq);
342 UpdateCurrentTime();
343 rc = dixLookupWindow(&pWin, stuff->dest, client, DixSetAttrAccess);
344 if (rc != Success)
345 return rc;
346 switch (stuff->destKind) {
347 case ShapeBounding:
348 createDefault = CreateBoundingShape;
349 break;
350 case ShapeClip:
351 createDefault = CreateClipShape;
352 break;
353 case ShapeInput:
354 createDefault = CreateBoundingShape;
355 break;
356 default:
357 client->errorValue = stuff->destKind;
358 return BadValue;
359 }
360 pScreen = pWin->drawable.pScreen;
361 if (stuff->src == None)
362 srcRgn = 0;
363 else {
364 rc = dixLookupResourceByType((pointer *) &pPixmap, stuff->src,
365 RT_PIXMAP, client, DixReadAccess);
366 if (rc != Success)
367 return rc;
368 if (pPixmap->drawable.pScreen != pScreen ||
369 pPixmap->drawable.depth != 1)
370 return BadMatch;
371 srcRgn = BitmapToRegion(pScreen, pPixmap);
372 if (!srcRgn)
373 return BadAlloc;
374 }
375
376 if (!pWin->optional)
377 MakeWindowOptional(pWin);
378 switch (stuff->destKind) {
379 case ShapeBounding:
380 destRgn = &pWin->optional->boundingShape;
381 break;
382 case ShapeClip:
383 destRgn = &pWin->optional->clipShape;
384 break;
385 case ShapeInput:
386 destRgn = &pWin->optional->inputShape;
387 break;
388 default:
389 return BadValue;
390 }
391
392 return RegionOperate(client, pWin, (int) stuff->destKind,
393 destRgn, srcRgn, (int) stuff->op,
394 stuff->xOff, stuff->yOff, createDefault);
395}
396
397#ifdef PANORAMIX
398static int
399ProcPanoramiXShapeMask(ClientPtr client)
400{
401 REQUEST(xShapeMaskReq);
402 PanoramiXRes *win, *pmap;
403 int j, result;
404
405 REQUEST_SIZE_MATCH(xShapeMaskReq);
406
407 result = dixLookupResourceByType((pointer *) &win, stuff->dest, XRT_WINDOW,
408 client, DixWriteAccess);
409 if (result != Success)
410 return result;
411
412 if (stuff->src != None) {
413 result = dixLookupResourceByType((pointer *) &pmap, stuff->src,
414 XRT_PIXMAP, client, DixReadAccess);
415 if (result != Success)
416 return result;
417 }
418 else
419 pmap = NULL;
420
421 FOR_NSCREENS(j) {
422 stuff->dest = win->info[j].id;
423 if (pmap)
424 stuff->src = pmap->info[j].id;
425 result = ProcShapeMask(client);
426 if (result != Success)
427 break;
428 }
429 return result;
430}
431#endif
432
433/************
434 * ProcShapeCombine
435 ************/
436
437static int
438ProcShapeCombine(ClientPtr client)
439{
440 WindowPtr pSrcWin, pDestWin;
441
442 REQUEST(xShapeCombineReq);
443 RegionPtr srcRgn;
444 RegionPtr *destRgn;
445 CreateDftPtr createDefault;
446 CreateDftPtr createSrc;
447 RegionPtr tmp;
448 int rc;
449
450 REQUEST_SIZE_MATCH(xShapeCombineReq);
451 UpdateCurrentTime();
452 rc = dixLookupWindow(&pDestWin, stuff->dest, client, DixSetAttrAccess);
453 if (rc != Success)
454 return rc;
455 if (!pDestWin->optional)
456 MakeWindowOptional(pDestWin);
457 switch (stuff->destKind) {
458 case ShapeBounding:
459 createDefault = CreateBoundingShape;
460 break;
461 case ShapeClip:
462 createDefault = CreateClipShape;
463 break;
464 case ShapeInput:
465 createDefault = CreateBoundingShape;
466 break;
467 default:
468 client->errorValue = stuff->destKind;
469 return BadValue;
470 }
471
472 rc = dixLookupWindow(&pSrcWin, stuff->src, client, DixGetAttrAccess);
473 if (rc != Success)
474 return rc;
475 switch (stuff->srcKind) {
476 case ShapeBounding:
477 srcRgn = wBoundingShape(pSrcWin);
478 createSrc = CreateBoundingShape;
479 break;
480 case ShapeClip:
481 srcRgn = wClipShape(pSrcWin);
482 createSrc = CreateClipShape;
483 break;
484 case ShapeInput:
485 srcRgn = wInputShape(pSrcWin);
486 createSrc = CreateBoundingShape;
487 break;
488 default:
489 client->errorValue = stuff->srcKind;
490 return BadValue;
491 }
492 if (pSrcWin->drawable.pScreen != pDestWin->drawable.pScreen) {
493 return BadMatch;
494 }
495
496 if (srcRgn) {
497 tmp = RegionCreate((BoxPtr) 0, 0);
498 RegionCopy(tmp, srcRgn);
499 srcRgn = tmp;
500 }
501 else
502 srcRgn = (*createSrc) (pSrcWin);
503
504 if (!pDestWin->optional)
505 MakeWindowOptional(pDestWin);
506 switch (stuff->destKind) {
507 case ShapeBounding:
508 destRgn = &pDestWin->optional->boundingShape;
509 break;
510 case ShapeClip:
511 destRgn = &pDestWin->optional->clipShape;
512 break;
513 case ShapeInput:
514 destRgn = &pDestWin->optional->inputShape;
515 break;
516 default:
517 return BadValue;
518 }
519
520 return RegionOperate(client, pDestWin, (int) stuff->destKind,
521 destRgn, srcRgn, (int) stuff->op,
522 stuff->xOff, stuff->yOff, createDefault);
523}
524
525#ifdef PANORAMIX
526static int
527ProcPanoramiXShapeCombine(ClientPtr client)
528{
529 REQUEST(xShapeCombineReq);
530 PanoramiXRes *win, *win2;
531 int j, result;
532
533 REQUEST_AT_LEAST_SIZE(xShapeCombineReq);
534
535 result = dixLookupResourceByType((pointer *) &win, stuff->dest, XRT_WINDOW,
536 client, DixWriteAccess);
537 if (result != Success)
538 return result;
539
540 result = dixLookupResourceByType((pointer *) &win2, stuff->src, XRT_WINDOW,
541 client, DixReadAccess);
542 if (result != Success)
543 return result;
544
545 FOR_NSCREENS(j) {
546 stuff->dest = win->info[j].id;
547 stuff->src = win2->info[j].id;
548 result = ProcShapeCombine(client);
549 if (result != Success)
550 break;
551 }
552 return result;
553}
554#endif
555
556/*************
557 * ProcShapeOffset
558 *************/
559
560static int
561ProcShapeOffset(ClientPtr client)
562{
563 WindowPtr pWin;
564
565 REQUEST(xShapeOffsetReq);
566 RegionPtr srcRgn;
567 int rc;
568
569 REQUEST_SIZE_MATCH(xShapeOffsetReq);
570 UpdateCurrentTime();
571 rc = dixLookupWindow(&pWin, stuff->dest, client, DixSetAttrAccess);
572 if (rc != Success)
573 return rc;
574 switch (stuff->destKind) {
575 case ShapeBounding:
576 srcRgn = wBoundingShape(pWin);
577 break;
578 case ShapeClip:
579 srcRgn = wClipShape(pWin);
580 break;
581 case ShapeInput:
582 srcRgn = wInputShape(pWin);
583 break;
584 default:
585 client->errorValue = stuff->destKind;
586 return BadValue;
587 }
588 if (srcRgn) {
589 RegionTranslate(srcRgn, stuff->xOff, stuff->yOff);
590 (*pWin->drawable.pScreen->SetShape) (pWin, stuff->destKind);
591 }
592 SendShapeNotify(pWin, (int) stuff->destKind);
593 return Success;
594}
595
596#ifdef PANORAMIX
597static int
598ProcPanoramiXShapeOffset(ClientPtr client)
599{
600 REQUEST(xShapeOffsetReq);
601 PanoramiXRes *win;
602 int j, result;
603
604 REQUEST_AT_LEAST_SIZE(xShapeOffsetReq);
605
606 result = dixLookupResourceByType((pointer *) &win, stuff->dest, XRT_WINDOW,
607 client, DixWriteAccess);
608 if (result != Success)
609 return result;
610
611 FOR_NSCREENS(j) {
612 stuff->dest = win->info[j].id;
613 result = ProcShapeOffset(client);
614 if (result != Success)
615 break;
616 }
617 return result;
618}
619#endif
620
621static int
622ProcShapeQueryExtents(ClientPtr client)
623{
624 REQUEST(xShapeQueryExtentsReq);
625 WindowPtr pWin;
626 xShapeQueryExtentsReply rep;
627 BoxRec extents, *pExtents;
628 int rc;
629 RegionPtr region;
630
631 REQUEST_SIZE_MATCH(xShapeQueryExtentsReq);
632 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
633 if (rc != Success)
634 return rc;
635 rep = (xShapeQueryExtentsReply) {
636 .type = X_Reply,
637 .sequenceNumber = client->sequence,
638 .length = 0,
639 .boundingShaped = (wBoundingShape(pWin) != 0),
640 .clipShaped = (wClipShape(pWin) != 0)
641 };
642 if ((region = wBoundingShape(pWin))) {
643 /* this is done in two steps because of a compiler bug on SunOS 4.1.3 */
644 pExtents = RegionExtents(region);
645 extents = *pExtents;
646 }
647 else {
648 extents.x1 = -wBorderWidth(pWin);
649 extents.y1 = -wBorderWidth(pWin);
650 extents.x2 = pWin->drawable.width + wBorderWidth(pWin);
651 extents.y2 = pWin->drawable.height + wBorderWidth(pWin);
652 }
653 rep.xBoundingShape = extents.x1;
654 rep.yBoundingShape = extents.y1;
655 rep.widthBoundingShape = extents.x2 - extents.x1;
656 rep.heightBoundingShape = extents.y2 - extents.y1;
657 if ((region = wClipShape(pWin))) {
658 /* this is done in two steps because of a compiler bug on SunOS 4.1.3 */
659 pExtents = RegionExtents(region);
660 extents = *pExtents;
661 }
662 else {
663 extents.x1 = 0;
664 extents.y1 = 0;
665 extents.x2 = pWin->drawable.width;
666 extents.y2 = pWin->drawable.height;
667 }
668 rep.xClipShape = extents.x1;
669 rep.yClipShape = extents.y1;
670 rep.widthClipShape = extents.x2 - extents.x1;
671 rep.heightClipShape = extents.y2 - extents.y1;
672 if (client->swapped) {
673 swaps(&rep.sequenceNumber);
674 swapl(&rep.length);
675 swaps(&rep.xBoundingShape);
676 swaps(&rep.yBoundingShape);
677 swaps(&rep.widthBoundingShape);
678 swaps(&rep.heightBoundingShape);
679 swaps(&rep.xClipShape);
680 swaps(&rep.yClipShape);
681 swaps(&rep.widthClipShape);
682 swaps(&rep.heightClipShape);
683 }
684 WriteToClient(client, sizeof(xShapeQueryExtentsReply), &rep);
685 return Success;
686}
687
688 /*ARGSUSED*/ static int
689ShapeFreeClient(pointer data, XID id)
690{
691 ShapeEventPtr pShapeEvent;
692 WindowPtr pWin;
693 ShapeEventPtr *pHead, pCur, pPrev;
694 int rc;
695
696 pShapeEvent = (ShapeEventPtr) data;
697 pWin = pShapeEvent->window;
698 rc = dixLookupResourceByType((pointer *) &pHead, pWin->drawable.id,
699 ShapeEventType, serverClient, DixReadAccess);
700 if (rc == Success) {
701 pPrev = 0;
702 for (pCur = *pHead; pCur && pCur != pShapeEvent; pCur = pCur->next)
703 pPrev = pCur;
704 if (pCur) {
705 if (pPrev)
706 pPrev->next = pShapeEvent->next;
707 else
708 *pHead = pShapeEvent->next;
709 }
710 }
711 free((pointer) pShapeEvent);
712 return 1;
713}
714
715 /*ARGSUSED*/ static int
716ShapeFreeEvents(pointer data, XID id)
717{
718 ShapeEventPtr *pHead, pCur, pNext;
719
720 pHead = (ShapeEventPtr *) data;
721 for (pCur = *pHead; pCur; pCur = pNext) {
722 pNext = pCur->next;
723 FreeResource(pCur->clientResource, ClientType);
724 free((pointer) pCur);
725 }
726 free((pointer) pHead);
727 return 1;
728}
729
730static int
731ProcShapeSelectInput(ClientPtr client)
732{
733 REQUEST(xShapeSelectInputReq);
734 WindowPtr pWin;
735 ShapeEventPtr pShapeEvent, pNewShapeEvent, *pHead;
736 XID clientResource;
737 int rc;
738
739 REQUEST_SIZE_MATCH(xShapeSelectInputReq);
740 rc = dixLookupWindow(&pWin, stuff->window, client, DixReceiveAccess);
741 if (rc != Success)
742 return rc;
743 rc = dixLookupResourceByType((pointer *) &pHead, pWin->drawable.id,
744 ShapeEventType, client, DixWriteAccess);
745 if (rc != Success && rc != BadValue)
746 return rc;
747
748 switch (stuff->enable) {
749 case xTrue:
750 if (pHead) {
751
752 /* check for existing entry. */
753 for (pShapeEvent = *pHead;
754 pShapeEvent; pShapeEvent = pShapeEvent->next) {
755 if (pShapeEvent->client == client)
756 return Success;
757 }
758 }
759
760 /* build the entry */
761 pNewShapeEvent = malloc(sizeof(ShapeEventRec));
762 if (!pNewShapeEvent)
763 return BadAlloc;
764 pNewShapeEvent->next = 0;
765 pNewShapeEvent->client = client;
766 pNewShapeEvent->window = pWin;
767 /*
768 * add a resource that will be deleted when
769 * the client goes away
770 */
771 clientResource = FakeClientID(client->index);
772 pNewShapeEvent->clientResource = clientResource;
773 if (!AddResource(clientResource, ClientType, (pointer) pNewShapeEvent))
774 return BadAlloc;
775 /*
776 * create a resource to contain a pointer to the list
777 * of clients selecting input. This must be indirect as
778 * the list may be arbitrarily rearranged which cannot be
779 * done through the resource database.
780 */
781 if (!pHead) {
782 pHead = malloc(sizeof(ShapeEventPtr));
783 if (!pHead ||
784 !AddResource(pWin->drawable.id, ShapeEventType,
785 (pointer) pHead)) {
786 FreeResource(clientResource, RT_NONE);
787 return BadAlloc;
788 }
789 *pHead = 0;
790 }
791 pNewShapeEvent->next = *pHead;
792 *pHead = pNewShapeEvent;
793 break;
794 case xFalse:
795 /* delete the interest */
796 if (pHead) {
797 pNewShapeEvent = 0;
798 for (pShapeEvent = *pHead; pShapeEvent;
799 pShapeEvent = pShapeEvent->next) {
800 if (pShapeEvent->client == client)
801 break;
802 pNewShapeEvent = pShapeEvent;
803 }
804 if (pShapeEvent) {
805 FreeResource(pShapeEvent->clientResource, ClientType);
806 if (pNewShapeEvent)
807 pNewShapeEvent->next = pShapeEvent->next;
808 else
809 *pHead = pShapeEvent->next;
810 free(pShapeEvent);
811 }
812 }
813 break;
814 default:
815 client->errorValue = stuff->enable;
816 return BadValue;
817 }
818 return Success;
819}
820
821/*
822 * deliver the event
823 */
824
825void
826SendShapeNotify(WindowPtr pWin, int which)
827{
828 ShapeEventPtr *pHead, pShapeEvent;
829 BoxRec extents;
830 RegionPtr region;
831 BYTE shaped;
832 int rc;
833
834 rc = dixLookupResourceByType((pointer *) &pHead, pWin->drawable.id,
835 ShapeEventType, serverClient, DixReadAccess);
836 if (rc != Success)
837 return;
838 switch (which) {
839 case ShapeBounding:
840 region = wBoundingShape(pWin);
841 if (region) {
842 extents = *RegionExtents(region);
843 shaped = xTrue;
844 }
845 else {
846 extents.x1 = -wBorderWidth(pWin);
847 extents.y1 = -wBorderWidth(pWin);
848 extents.x2 = pWin->drawable.width + wBorderWidth(pWin);
849 extents.y2 = pWin->drawable.height + wBorderWidth(pWin);
850 shaped = xFalse;
851 }
852 break;
853 case ShapeClip:
854 region = wClipShape(pWin);
855 if (region) {
856 extents = *RegionExtents(region);
857 shaped = xTrue;
858 }
859 else {
860 extents.x1 = 0;
861 extents.y1 = 0;
862 extents.x2 = pWin->drawable.width;
863 extents.y2 = pWin->drawable.height;
864 shaped = xFalse;
865 }
866 break;
867 case ShapeInput:
868 region = wInputShape(pWin);
869 if (region) {
870 extents = *RegionExtents(region);
871 shaped = xTrue;
872 }
873 else {
874 extents.x1 = -wBorderWidth(pWin);
875 extents.y1 = -wBorderWidth(pWin);
876 extents.x2 = pWin->drawable.width + wBorderWidth(pWin);
877 extents.y2 = pWin->drawable.height + wBorderWidth(pWin);
878 shaped = xFalse;
879 }
880 break;
881 default:
882 return;
883 }
884 for (pShapeEvent = *pHead; pShapeEvent; pShapeEvent = pShapeEvent->next) {
885 xShapeNotifyEvent se = {
886 .type = ShapeNotify + ShapeEventBase,
887 .kind = which,
888 .window = pWin->drawable.id,
889 .x = extents.x1,
890 .y = extents.y1,
891 .width = extents.x2 - extents.x1,
892 .height = extents.y2 - extents.y1,
893 .time = currentTime.milliseconds,
894 .shaped = shaped
895 };
896 WriteEventsToClient(pShapeEvent->client, 1, (xEvent *) &se);
897 }
898}
899
900static int
901ProcShapeInputSelected(ClientPtr client)
902{
903 REQUEST(xShapeInputSelectedReq);
904 WindowPtr pWin;
905 ShapeEventPtr pShapeEvent, *pHead;
906 int enabled, rc;
907 xShapeInputSelectedReply rep;
908
909 REQUEST_SIZE_MATCH(xShapeInputSelectedReq);
910 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
911 if (rc != Success)
912 return rc;
913 rc = dixLookupResourceByType((pointer *) &pHead, pWin->drawable.id,
914 ShapeEventType, client, DixReadAccess);
915 if (rc != Success && rc != BadValue)
916 return rc;
917 enabled = xFalse;
918 if (pHead) {
919 for (pShapeEvent = *pHead; pShapeEvent; pShapeEvent = pShapeEvent->next) {
920 if (pShapeEvent->client == client) {
921 enabled = xTrue;
922 break;
923 }
924 }
925 }
926 rep = (xShapeInputSelectedReply) {
927 .type = X_Reply,
928 .enabled = enabled,
929 .sequenceNumber = client->sequence,
930 .length = 0
931 };
932 if (client->swapped) {
933 swaps(&rep.sequenceNumber);
934 swapl(&rep.length);
935 }
936 WriteToClient(client, sizeof(xShapeInputSelectedReply), &rep);
937 return Success;
938}
939
940static int
941ProcShapeGetRectangles(ClientPtr client)
942{
943 REQUEST(xShapeGetRectanglesReq);
944 WindowPtr pWin;
945 xShapeGetRectanglesReply rep;
946 xRectangle *rects;
947 int nrects, i, rc;
948 RegionPtr region;
949
950 REQUEST_SIZE_MATCH(xShapeGetRectanglesReq);
951 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
952 if (rc != Success)
953 return rc;
954 switch (stuff->kind) {
955 case ShapeBounding:
956 region = wBoundingShape(pWin);
957 break;
958 case ShapeClip:
959 region = wClipShape(pWin);
960 break;
961 case ShapeInput:
962 region = wInputShape(pWin);
963 break;
964 default:
965 client->errorValue = stuff->kind;
966 return BadValue;
967 }
968 if (!region) {
969 nrects = 1;
970 rects = malloc(sizeof(xRectangle));
971 if (!rects)
972 return BadAlloc;
973 switch (stuff->kind) {
974 case ShapeBounding:
975 rects->x = -(int) wBorderWidth(pWin);
976 rects->y = -(int) wBorderWidth(pWin);
977 rects->width = pWin->drawable.width + wBorderWidth(pWin);
978 rects->height = pWin->drawable.height + wBorderWidth(pWin);
979 break;
980 case ShapeClip:
981 rects->x = 0;
982 rects->y = 0;
983 rects->width = pWin->drawable.width;
984 rects->height = pWin->drawable.height;
985 break;
986 case ShapeInput:
987 rects->x = -(int) wBorderWidth(pWin);
988 rects->y = -(int) wBorderWidth(pWin);
989 rects->width = pWin->drawable.width + wBorderWidth(pWin);
990 rects->height = pWin->drawable.height + wBorderWidth(pWin);
991 break;
992 }
993 }
994 else {
995 BoxPtr box;
996
997 nrects = RegionNumRects(region);
998 box = RegionRects(region);
999 rects = malloc(nrects * sizeof(xRectangle));
1000 if (!rects && nrects)
1001 return BadAlloc;
1002 for (i = 0; i < nrects; i++, box++) {
1003 rects[i].x = box->x1;
1004 rects[i].y = box->y1;
1005 rects[i].width = box->x2 - box->x1;
1006 rects[i].height = box->y2 - box->y1;
1007 }
1008 }
1009 rep = (xShapeGetRectanglesReply) {
1010 .type = X_Reply,
1011 .ordering = YXBanded,
1012 .sequenceNumber = client->sequence,
1013 .length = bytes_to_int32(nrects * sizeof(xRectangle)),
1014 .nrects = nrects
1015 };
1016 if (client->swapped) {
1017 swaps(&rep.sequenceNumber);
1018 swapl(&rep.length);
1019 swapl(&rep.nrects);
1020 SwapShorts((short *) rects, (unsigned long) nrects * 4);
1021 }
1022 WriteToClient(client, sizeof(rep), &rep);
1023 WriteToClient(client, nrects * sizeof(xRectangle), rects);
1024 free(rects);
1025 return Success;
1026}
1027
1028static int
1029ProcShapeDispatch(ClientPtr client)
1030{
1031 REQUEST(xReq);
1032 switch (stuff->data) {
1033 case X_ShapeQueryVersion:
1034 return ProcShapeQueryVersion(client);
1035 case X_ShapeRectangles:
1036#ifdef PANORAMIX
1037 if (!noPanoramiXExtension)
1038 return ProcPanoramiXShapeRectangles(client);
1039 else
1040#endif
1041 return ProcShapeRectangles(client);
1042 case X_ShapeMask:
1043#ifdef PANORAMIX
1044 if (!noPanoramiXExtension)
1045 return ProcPanoramiXShapeMask(client);
1046 else
1047#endif
1048 return ProcShapeMask(client);
1049 case X_ShapeCombine:
1050#ifdef PANORAMIX
1051 if (!noPanoramiXExtension)
1052 return ProcPanoramiXShapeCombine(client);
1053 else
1054#endif
1055 return ProcShapeCombine(client);
1056 case X_ShapeOffset:
1057#ifdef PANORAMIX
1058 if (!noPanoramiXExtension)
1059 return ProcPanoramiXShapeOffset(client);
1060 else
1061#endif
1062 return ProcShapeOffset(client);
1063 case X_ShapeQueryExtents:
1064 return ProcShapeQueryExtents(client);
1065 case X_ShapeSelectInput:
1066 return ProcShapeSelectInput(client);
1067 case X_ShapeInputSelected:
1068 return ProcShapeInputSelected(client);
1069 case X_ShapeGetRectangles:
1070 return ProcShapeGetRectangles(client);
1071 default:
1072 return BadRequest;
1073 }
1074}
1075
1076static void
1077SShapeNotifyEvent(xShapeNotifyEvent * from, xShapeNotifyEvent * to)
1078{
1079 to->type = from->type;
1080 to->kind = from->kind;
1081 cpswapl(from->window, to->window);
1082 cpswaps(from->sequenceNumber, to->sequenceNumber);
1083 cpswaps(from->x, to->x);
1084 cpswaps(from->y, to->y);
1085 cpswaps(from->width, to->width);
1086 cpswaps(from->height, to->height);
1087 cpswapl(from->time, to->time);
1088 to->shaped = from->shaped;
1089}
1090
1091static int
1092SProcShapeQueryVersion(ClientPtr client)
1093{
1094 REQUEST(xShapeQueryVersionReq);
1095
1096 swaps(&stuff->length);
1097 return ProcShapeQueryVersion(client);
1098}
1099
1100static int
1101SProcShapeRectangles(ClientPtr client)
1102{
1103 REQUEST(xShapeRectanglesReq);
1104
1105 swaps(&stuff->length);
1106 REQUEST_AT_LEAST_SIZE(xShapeRectanglesReq);
1107 swapl(&stuff->dest);
1108 swaps(&stuff->xOff);
1109 swaps(&stuff->yOff);
1110 SwapRestS(stuff);
1111 return ProcShapeRectangles(client);
1112}
1113
1114static int
1115SProcShapeMask(ClientPtr client)
1116{
1117 REQUEST(xShapeMaskReq);
1118
1119 swaps(&stuff->length);
1120 REQUEST_SIZE_MATCH(xShapeMaskReq);
1121 swapl(&stuff->dest);
1122 swaps(&stuff->xOff);
1123 swaps(&stuff->yOff);
1124 swapl(&stuff->src);
1125 return ProcShapeMask(client);
1126}
1127
1128static int
1129SProcShapeCombine(ClientPtr client)
1130{
1131 REQUEST(xShapeCombineReq);
1132
1133 swaps(&stuff->length);
1134 REQUEST_SIZE_MATCH(xShapeCombineReq);
1135 swapl(&stuff->dest);
1136 swaps(&stuff->xOff);
1137 swaps(&stuff->yOff);
1138 swapl(&stuff->src);
1139 return ProcShapeCombine(client);
1140}
1141
1142static int
1143SProcShapeOffset(ClientPtr client)
1144{
1145 REQUEST(xShapeOffsetReq);
1146
1147 swaps(&stuff->length);
1148 REQUEST_SIZE_MATCH(xShapeOffsetReq);
1149 swapl(&stuff->dest);
1150 swaps(&stuff->xOff);
1151 swaps(&stuff->yOff);
1152 return ProcShapeOffset(client);
1153}
1154
1155static int
1156SProcShapeQueryExtents(ClientPtr client)
1157{
1158 REQUEST(xShapeQueryExtentsReq);
1159
1160 swaps(&stuff->length);
1161 REQUEST_SIZE_MATCH(xShapeQueryExtentsReq);
1162 swapl(&stuff->window);
1163 return ProcShapeQueryExtents(client);
1164}
1165
1166static int
1167SProcShapeSelectInput(ClientPtr client)
1168{
1169 REQUEST(xShapeSelectInputReq);
1170
1171 swaps(&stuff->length);
1172 REQUEST_SIZE_MATCH(xShapeSelectInputReq);
1173 swapl(&stuff->window);
1174 return ProcShapeSelectInput(client);
1175}
1176
1177static int
1178SProcShapeInputSelected(ClientPtr client)
1179{
1180 REQUEST(xShapeInputSelectedReq);
1181
1182 swaps(&stuff->length);
1183 REQUEST_SIZE_MATCH(xShapeInputSelectedReq);
1184 swapl(&stuff->window);
1185 return ProcShapeInputSelected(client);
1186}
1187
1188static int
1189SProcShapeGetRectangles(ClientPtr client)
1190{
1191 REQUEST(xShapeGetRectanglesReq);
1192 swaps(&stuff->length);
1193 REQUEST_SIZE_MATCH(xShapeGetRectanglesReq);
1194 swapl(&stuff->window);
1195 return ProcShapeGetRectangles(client);
1196}
1197
1198static int
1199SProcShapeDispatch(ClientPtr client)
1200{
1201 REQUEST(xReq);
1202 switch (stuff->data) {
1203 case X_ShapeQueryVersion:
1204 return SProcShapeQueryVersion(client);
1205 case X_ShapeRectangles:
1206 return SProcShapeRectangles(client);
1207 case X_ShapeMask:
1208 return SProcShapeMask(client);
1209 case X_ShapeCombine:
1210 return SProcShapeCombine(client);
1211 case X_ShapeOffset:
1212 return SProcShapeOffset(client);
1213 case X_ShapeQueryExtents:
1214 return SProcShapeQueryExtents(client);
1215 case X_ShapeSelectInput:
1216 return SProcShapeSelectInput(client);
1217 case X_ShapeInputSelected:
1218 return SProcShapeInputSelected(client);
1219 case X_ShapeGetRectangles:
1220 return SProcShapeGetRectangles(client);
1221 default:
1222 return BadRequest;
1223 }
1224}
1225
1226void
1227ShapeExtensionInit(void)
1228{
1229 ExtensionEntry *extEntry;
1230
1231 ClientType = CreateNewResourceType(ShapeFreeClient, "ShapeClient");
1232 ShapeEventType = CreateNewResourceType(ShapeFreeEvents, "ShapeEvent");
1233 if (ClientType && ShapeEventType &&
1234 (extEntry = AddExtension(SHAPENAME, ShapeNumberEvents, 0,
1235 ProcShapeDispatch, SProcShapeDispatch,
1236 NULL, StandardMinorOpcode))) {
1237 ShapeEventBase = extEntry->eventBase;
1238 EventSwapVector[ShapeEventBase] = (EventSwapPtr) SShapeNotifyEvent;
1239 }
1240}