shape.c revision 7e31ba66
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    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
901static int
902ProcShapeInputSelected(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
941static int
942ProcShapeGetRectangles(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
1029static int
1030ProcShapeDispatch(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
1077static void _X_COLD
1078SShapeNotifyEvent(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
1092static int _X_COLD
1093SProcShapeQueryVersion(ClientPtr client)
1094{
1095    REQUEST(xShapeQueryVersionReq);
1096
1097    swaps(&stuff->length);
1098    return ProcShapeQueryVersion(client);
1099}
1100
1101static int _X_COLD
1102SProcShapeRectangles(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
1115static int _X_COLD
1116SProcShapeMask(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
1129static int _X_COLD
1130SProcShapeCombine(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
1143static int _X_COLD
1144SProcShapeOffset(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
1156static int _X_COLD
1157SProcShapeQueryExtents(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
1167static int _X_COLD
1168SProcShapeSelectInput(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
1178static int _X_COLD
1179SProcShapeInputSelected(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
1189static int _X_COLD
1190SProcShapeGetRectangles(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
1199static int _X_COLD
1200SProcShapeDispatch(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
1227void
1228ShapeExtensionInit(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