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