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