shape.c revision f7df2e56
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(void * /* data */ ,
54                           XID    /* id */
55    );
56static int ShapeFreeEvents(void * /* 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((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
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((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
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((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
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((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
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((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
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(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
716ShapeFreeEvents(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
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((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
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((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    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((void **) &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 = xallocarray(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}
1241