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