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