1 /************************************************************
2
3 Copyright 1989, 1998 The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in 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
50 typedef RegionPtr (*CreateDftPtr) (WindowPtr /* pWin */
51 );
52
53 static int ShapeFreeClient(void * /* data */ ,
54 XID /* id */
55 );
56 static int ShapeFreeEvents(void * /* data */ ,
57 XID /* id */
58 );
59 static 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
72 static int ShapeEventBase = 0;
73 static 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
83 typedef struct _ShapeEvent *ShapeEventPtr;
84
85 typedef 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
100 static int
RegionOperate(ClientPtr client,WindowPtr pWin,int kind,RegionPtr * destRgnp,RegionPtr srcRgn,int op,int xoff,int yoff,CreateDftPtr create)101 RegionOperate(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
180 RegionPtr
CreateBoundingShape(WindowPtr pWin)181 CreateBoundingShape(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
192 RegionPtr
CreateClipShape(WindowPtr pWin)193 CreateClipShape(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
204 static int
ProcShapeQueryVersion(ClientPtr client)205 ProcShapeQueryVersion(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
232 static int
ProcShapeRectangles(ClientPtr client)233 ProcShapeRectangles(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
300 static int
ProcPanoramiXShapeRectangles(ClientPtr client)301 ProcPanoramiXShapeRectangles(ClientPtr client)
302 {
303 REQUEST(xShapeRectanglesReq);
304 PanoramiXRes *win;
305 int j, result;
306
307 REQUEST_AT_LEAST_SIZE(xShapeRectanglesReq);
308
309 result = dixLookupResourceByType((void **) &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
328 static int
ProcShapeMask(ClientPtr client)329 ProcShapeMask(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((void **) &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
398 static int
ProcPanoramiXShapeMask(ClientPtr client)399 ProcPanoramiXShapeMask(ClientPtr client)
400 {
401 REQUEST(xShapeMaskReq);
402 PanoramiXRes *win, *pmap;
403 int j, result;
404
405 REQUEST_SIZE_MATCH(xShapeMaskReq);
406
407 result = dixLookupResourceByType((void **) &win, stuff->dest, XRT_WINDOW,
408 client, DixWriteAccess);
409 if (result != Success)
410 return result;
411
412 if (stuff->src != None) {
413 result = dixLookupResourceByType((void **) &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
437 static int
ProcShapeCombine(ClientPtr client)438 ProcShapeCombine(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
526 static int
ProcPanoramiXShapeCombine(ClientPtr client)527 ProcPanoramiXShapeCombine(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((void **) &win, stuff->dest, XRT_WINDOW,
536 client, DixWriteAccess);
537 if (result != Success)
538 return result;
539
540 result = dixLookupResourceByType((void **) &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
560 static int
ProcShapeOffset(ClientPtr client)561 ProcShapeOffset(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
597 static int
ProcPanoramiXShapeOffset(ClientPtr client)598 ProcPanoramiXShapeOffset(ClientPtr client)
599 {
600 REQUEST(xShapeOffsetReq);
601 PanoramiXRes *win;
602 int j, result;
603
604 REQUEST_AT_LEAST_SIZE(xShapeOffsetReq);
605
606 result = dixLookupResourceByType((void **) &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
621 static int
ProcShapeQueryExtents(ClientPtr client)622 ProcShapeQueryExtents(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
ShapeFreeClient(void * data,XID id)689 ShapeFreeClient(void *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((void **) &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((void *) pShapeEvent);
712 return 1;
713 }
714
715 /*ARGSUSED*/ static int
ShapeFreeEvents(void * data,XID id)716 ShapeFreeEvents(void *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((void *) pCur);
725 }
726 free((void *) pHead);
727 return 1;
728 }
729
730 static int
ProcShapeSelectInput(ClientPtr client)731 ProcShapeSelectInput(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((void **) &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, (void *) pNewShapeEvent))
774 return BadAlloc;
775 /*
776 * create a resource to contain a void *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 (void *) 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
825 void
SendShapeNotify(WindowPtr pWin,int which)826 SendShapeNotify(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((void **) &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 UpdateCurrentTimeIf();
885 for (pShapeEvent = *pHead; pShapeEvent; pShapeEvent = pShapeEvent->next) {
886 xShapeNotifyEvent se = {
887 .type = ShapeNotify + ShapeEventBase,
888 .kind = which,
889 .window = pWin->drawable.id,
890 .x = extents.x1,
891 .y = extents.y1,
892 .width = extents.x2 - extents.x1,
893 .height = extents.y2 - extents.y1,
894 .time = currentTime.milliseconds,
895 .shaped = shaped
896 };
897 WriteEventsToClient(pShapeEvent->client, 1, (xEvent *) &se);
898 }
899 }
900
901 static int
ProcShapeInputSelected(ClientPtr client)902 ProcShapeInputSelected(ClientPtr client)
903 {
904 REQUEST(xShapeInputSelectedReq);
905 WindowPtr pWin;
906 ShapeEventPtr pShapeEvent, *pHead;
907 int enabled, rc;
908 xShapeInputSelectedReply rep;
909
910 REQUEST_SIZE_MATCH(xShapeInputSelectedReq);
911 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
912 if (rc != Success)
913 return rc;
914 rc = dixLookupResourceByType((void **) &pHead, pWin->drawable.id,
915 ShapeEventType, client, DixReadAccess);
916 if (rc != Success && rc != BadValue)
917 return rc;
918 enabled = xFalse;
919 if (pHead) {
920 for (pShapeEvent = *pHead; pShapeEvent; pShapeEvent = pShapeEvent->next) {
921 if (pShapeEvent->client == client) {
922 enabled = xTrue;
923 break;
924 }
925 }
926 }
927 rep = (xShapeInputSelectedReply) {
928 .type = X_Reply,
929 .enabled = enabled,
930 .sequenceNumber = client->sequence,
931 .length = 0
932 };
933 if (client->swapped) {
934 swaps(&rep.sequenceNumber);
935 swapl(&rep.length);
936 }
937 WriteToClient(client, sizeof(xShapeInputSelectedReply), &rep);
938 return Success;
939 }
940
941 static int
ProcShapeGetRectangles(ClientPtr client)942 ProcShapeGetRectangles(ClientPtr client)
943 {
944 REQUEST(xShapeGetRectanglesReq);
945 WindowPtr pWin;
946 xShapeGetRectanglesReply rep;
947 xRectangle *rects;
948 int nrects, i, rc;
949 RegionPtr region;
950
951 REQUEST_SIZE_MATCH(xShapeGetRectanglesReq);
952 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
953 if (rc != Success)
954 return rc;
955 switch (stuff->kind) {
956 case ShapeBounding:
957 region = wBoundingShape(pWin);
958 break;
959 case ShapeClip:
960 region = wClipShape(pWin);
961 break;
962 case ShapeInput:
963 region = wInputShape(pWin);
964 break;
965 default:
966 client->errorValue = stuff->kind;
967 return BadValue;
968 }
969 if (!region) {
970 nrects = 1;
971 rects = malloc(sizeof(xRectangle));
972 if (!rects)
973 return BadAlloc;
974 switch (stuff->kind) {
975 case ShapeBounding:
976 rects->x = -(int) wBorderWidth(pWin);
977 rects->y = -(int) wBorderWidth(pWin);
978 rects->width = pWin->drawable.width + wBorderWidth(pWin);
979 rects->height = pWin->drawable.height + wBorderWidth(pWin);
980 break;
981 case ShapeClip:
982 rects->x = 0;
983 rects->y = 0;
984 rects->width = pWin->drawable.width;
985 rects->height = pWin->drawable.height;
986 break;
987 case ShapeInput:
988 rects->x = -(int) wBorderWidth(pWin);
989 rects->y = -(int) wBorderWidth(pWin);
990 rects->width = pWin->drawable.width + wBorderWidth(pWin);
991 rects->height = pWin->drawable.height + wBorderWidth(pWin);
992 break;
993 }
994 }
995 else {
996 BoxPtr box;
997
998 nrects = RegionNumRects(region);
999 box = RegionRects(region);
1000 rects = xallocarray(nrects, sizeof(xRectangle));
1001 if (!rects && nrects)
1002 return BadAlloc;
1003 for (i = 0; i < nrects; i++, box++) {
1004 rects[i].x = box->x1;
1005 rects[i].y = box->y1;
1006 rects[i].width = box->x2 - box->x1;
1007 rects[i].height = box->y2 - box->y1;
1008 }
1009 }
1010 rep = (xShapeGetRectanglesReply) {
1011 .type = X_Reply,
1012 .ordering = YXBanded,
1013 .sequenceNumber = client->sequence,
1014 .length = bytes_to_int32(nrects * sizeof(xRectangle)),
1015 .nrects = nrects
1016 };
1017 if (client->swapped) {
1018 swaps(&rep.sequenceNumber);
1019 swapl(&rep.length);
1020 swapl(&rep.nrects);
1021 SwapShorts((short *) rects, (unsigned long) nrects * 4);
1022 }
1023 WriteToClient(client, sizeof(rep), &rep);
1024 WriteToClient(client, nrects * sizeof(xRectangle), rects);
1025 free(rects);
1026 return Success;
1027 }
1028
1029 static int
ProcShapeDispatch(ClientPtr client)1030 ProcShapeDispatch(ClientPtr client)
1031 {
1032 REQUEST(xReq);
1033 switch (stuff->data) {
1034 case X_ShapeQueryVersion:
1035 return ProcShapeQueryVersion(client);
1036 case X_ShapeRectangles:
1037 #ifdef PANORAMIX
1038 if (!noPanoramiXExtension)
1039 return ProcPanoramiXShapeRectangles(client);
1040 else
1041 #endif
1042 return ProcShapeRectangles(client);
1043 case X_ShapeMask:
1044 #ifdef PANORAMIX
1045 if (!noPanoramiXExtension)
1046 return ProcPanoramiXShapeMask(client);
1047 else
1048 #endif
1049 return ProcShapeMask(client);
1050 case X_ShapeCombine:
1051 #ifdef PANORAMIX
1052 if (!noPanoramiXExtension)
1053 return ProcPanoramiXShapeCombine(client);
1054 else
1055 #endif
1056 return ProcShapeCombine(client);
1057 case X_ShapeOffset:
1058 #ifdef PANORAMIX
1059 if (!noPanoramiXExtension)
1060 return ProcPanoramiXShapeOffset(client);
1061 else
1062 #endif
1063 return ProcShapeOffset(client);
1064 case X_ShapeQueryExtents:
1065 return ProcShapeQueryExtents(client);
1066 case X_ShapeSelectInput:
1067 return ProcShapeSelectInput(client);
1068 case X_ShapeInputSelected:
1069 return ProcShapeInputSelected(client);
1070 case X_ShapeGetRectangles:
1071 return ProcShapeGetRectangles(client);
1072 default:
1073 return BadRequest;
1074 }
1075 }
1076
1077 static void _X_COLD
SShapeNotifyEvent(xShapeNotifyEvent * from,xShapeNotifyEvent * to)1078 SShapeNotifyEvent(xShapeNotifyEvent * from, xShapeNotifyEvent * to)
1079 {
1080 to->type = from->type;
1081 to->kind = from->kind;
1082 cpswapl(from->window, to->window);
1083 cpswaps(from->sequenceNumber, to->sequenceNumber);
1084 cpswaps(from->x, to->x);
1085 cpswaps(from->y, to->y);
1086 cpswaps(from->width, to->width);
1087 cpswaps(from->height, to->height);
1088 cpswapl(from->time, to->time);
1089 to->shaped = from->shaped;
1090 }
1091
1092 static int _X_COLD
SProcShapeQueryVersion(ClientPtr client)1093 SProcShapeQueryVersion(ClientPtr client)
1094 {
1095 REQUEST(xShapeQueryVersionReq);
1096
1097 swaps(&stuff->length);
1098 return ProcShapeQueryVersion(client);
1099 }
1100
1101 static int _X_COLD
SProcShapeRectangles(ClientPtr client)1102 SProcShapeRectangles(ClientPtr client)
1103 {
1104 REQUEST(xShapeRectanglesReq);
1105
1106 swaps(&stuff->length);
1107 REQUEST_AT_LEAST_SIZE(xShapeRectanglesReq);
1108 swapl(&stuff->dest);
1109 swaps(&stuff->xOff);
1110 swaps(&stuff->yOff);
1111 SwapRestS(stuff);
1112 return ProcShapeRectangles(client);
1113 }
1114
1115 static int _X_COLD
SProcShapeMask(ClientPtr client)1116 SProcShapeMask(ClientPtr client)
1117 {
1118 REQUEST(xShapeMaskReq);
1119
1120 swaps(&stuff->length);
1121 REQUEST_SIZE_MATCH(xShapeMaskReq);
1122 swapl(&stuff->dest);
1123 swaps(&stuff->xOff);
1124 swaps(&stuff->yOff);
1125 swapl(&stuff->src);
1126 return ProcShapeMask(client);
1127 }
1128
1129 static int _X_COLD
SProcShapeCombine(ClientPtr client)1130 SProcShapeCombine(ClientPtr client)
1131 {
1132 REQUEST(xShapeCombineReq);
1133
1134 swaps(&stuff->length);
1135 REQUEST_SIZE_MATCH(xShapeCombineReq);
1136 swapl(&stuff->dest);
1137 swaps(&stuff->xOff);
1138 swaps(&stuff->yOff);
1139 swapl(&stuff->src);
1140 return ProcShapeCombine(client);
1141 }
1142
1143 static int _X_COLD
SProcShapeOffset(ClientPtr client)1144 SProcShapeOffset(ClientPtr client)
1145 {
1146 REQUEST(xShapeOffsetReq);
1147
1148 swaps(&stuff->length);
1149 REQUEST_SIZE_MATCH(xShapeOffsetReq);
1150 swapl(&stuff->dest);
1151 swaps(&stuff->xOff);
1152 swaps(&stuff->yOff);
1153 return ProcShapeOffset(client);
1154 }
1155
1156 static int _X_COLD
SProcShapeQueryExtents(ClientPtr client)1157 SProcShapeQueryExtents(ClientPtr client)
1158 {
1159 REQUEST(xShapeQueryExtentsReq);
1160
1161 swaps(&stuff->length);
1162 REQUEST_SIZE_MATCH(xShapeQueryExtentsReq);
1163 swapl(&stuff->window);
1164 return ProcShapeQueryExtents(client);
1165 }
1166
1167 static int _X_COLD
SProcShapeSelectInput(ClientPtr client)1168 SProcShapeSelectInput(ClientPtr client)
1169 {
1170 REQUEST(xShapeSelectInputReq);
1171
1172 swaps(&stuff->length);
1173 REQUEST_SIZE_MATCH(xShapeSelectInputReq);
1174 swapl(&stuff->window);
1175 return ProcShapeSelectInput(client);
1176 }
1177
1178 static int _X_COLD
SProcShapeInputSelected(ClientPtr client)1179 SProcShapeInputSelected(ClientPtr client)
1180 {
1181 REQUEST(xShapeInputSelectedReq);
1182
1183 swaps(&stuff->length);
1184 REQUEST_SIZE_MATCH(xShapeInputSelectedReq);
1185 swapl(&stuff->window);
1186 return ProcShapeInputSelected(client);
1187 }
1188
1189 static int _X_COLD
SProcShapeGetRectangles(ClientPtr client)1190 SProcShapeGetRectangles(ClientPtr client)
1191 {
1192 REQUEST(xShapeGetRectanglesReq);
1193 swaps(&stuff->length);
1194 REQUEST_SIZE_MATCH(xShapeGetRectanglesReq);
1195 swapl(&stuff->window);
1196 return ProcShapeGetRectangles(client);
1197 }
1198
1199 static int _X_COLD
SProcShapeDispatch(ClientPtr client)1200 SProcShapeDispatch(ClientPtr client)
1201 {
1202 REQUEST(xReq);
1203 switch (stuff->data) {
1204 case X_ShapeQueryVersion:
1205 return SProcShapeQueryVersion(client);
1206 case X_ShapeRectangles:
1207 return SProcShapeRectangles(client);
1208 case X_ShapeMask:
1209 return SProcShapeMask(client);
1210 case X_ShapeCombine:
1211 return SProcShapeCombine(client);
1212 case X_ShapeOffset:
1213 return SProcShapeOffset(client);
1214 case X_ShapeQueryExtents:
1215 return SProcShapeQueryExtents(client);
1216 case X_ShapeSelectInput:
1217 return SProcShapeSelectInput(client);
1218 case X_ShapeInputSelected:
1219 return SProcShapeInputSelected(client);
1220 case X_ShapeGetRectangles:
1221 return SProcShapeGetRectangles(client);
1222 default:
1223 return BadRequest;
1224 }
1225 }
1226
1227 void
ShapeExtensionInit(void)1228 ShapeExtensionInit(void)
1229 {
1230 ExtensionEntry *extEntry;
1231
1232 ClientType = CreateNewResourceType(ShapeFreeClient, "ShapeClient");
1233 ShapeEventType = CreateNewResourceType(ShapeFreeEvents, "ShapeEvent");
1234 if (ClientType && ShapeEventType &&
1235 (extEntry = AddExtension(SHAPENAME, ShapeNumberEvents, 0,
1236 ProcShapeDispatch, SProcShapeDispatch,
1237 NULL, StandardMinorOpcode))) {
1238 ShapeEventBase = extEntry->eventBase;
1239 EventSwapVector[ShapeEventBase] = (EventSwapPtr) SShapeNotifyEvent;
1240 }
1241 }
1242