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