4f58590a42
Tested by naddy@, jsg@ & kettenis@
1241 lines
34 KiB
C
1241 lines
34 KiB
C
/************************************************************
|
|
|
|
Copyright 1989, 1998 The Open Group
|
|
|
|
Permission to use, copy, modify, distribute, and sell this software and its
|
|
documentation for any purpose is hereby granted without fee, provided that
|
|
the above copyright notice appear in all copies and that both that
|
|
copyright notice and this permission notice appear in supporting
|
|
documentation.
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of The Open Group shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from The Open Group.
|
|
|
|
********************************************************/
|
|
|
|
#ifdef HAVE_DIX_CONFIG_H
|
|
#include <dix-config.h>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <X11/X.h>
|
|
#include <X11/Xproto.h>
|
|
#include "misc.h"
|
|
#include "os.h"
|
|
#include "windowstr.h"
|
|
#include "scrnintstr.h"
|
|
#include "pixmapstr.h"
|
|
#include "extnsionst.h"
|
|
#include "dixstruct.h"
|
|
#include "resource.h"
|
|
#include "opaque.h"
|
|
#include <X11/extensions/shapeproto.h>
|
|
#include "regionstr.h"
|
|
#include "gcstruct.h"
|
|
#include "extinit.h"
|
|
#include "protocol-versions.h"
|
|
|
|
typedef RegionPtr (*CreateDftPtr) (WindowPtr /* pWin */
|
|
);
|
|
|
|
static int ShapeFreeClient(void * /* data */ ,
|
|
XID /* id */
|
|
);
|
|
static int ShapeFreeEvents(void * /* data */ ,
|
|
XID /* id */
|
|
);
|
|
static void SShapeNotifyEvent(xShapeNotifyEvent * /* from */ ,
|
|
xShapeNotifyEvent * /* to */
|
|
);
|
|
|
|
/* SendShapeNotify, CreateBoundingShape and CreateClipShape are used
|
|
* externally by the Xfixes extension and are now defined in window.h
|
|
*/
|
|
|
|
#ifdef PANORAMIX
|
|
#include "panoramiX.h"
|
|
#include "panoramiXsrv.h"
|
|
#endif
|
|
|
|
static int ShapeEventBase = 0;
|
|
static RESTYPE ClientType, ShapeEventType; /* resource types for event masks */
|
|
|
|
/*
|
|
* each window has a list of clients requesting
|
|
* ShapeNotify events. Each client has a resource
|
|
* for each window it selects ShapeNotify input for,
|
|
* this resource is used to delete the ShapeNotifyRec
|
|
* entry from the per-window queue.
|
|
*/
|
|
|
|
typedef struct _ShapeEvent *ShapeEventPtr;
|
|
|
|
typedef struct _ShapeEvent {
|
|
ShapeEventPtr next;
|
|
ClientPtr client;
|
|
WindowPtr window;
|
|
XID clientResource;
|
|
} ShapeEventRec;
|
|
|
|
/****************
|
|
* ShapeExtensionInit
|
|
*
|
|
* Called from InitExtensions in main() or from QueryExtension() if the
|
|
* extension is dynamically loaded.
|
|
*
|
|
****************/
|
|
|
|
static int
|
|
RegionOperate(ClientPtr client,
|
|
WindowPtr pWin,
|
|
int kind,
|
|
RegionPtr *destRgnp,
|
|
RegionPtr srcRgn, int op, int xoff, int yoff, CreateDftPtr create)
|
|
{
|
|
if (srcRgn && (xoff || yoff))
|
|
RegionTranslate(srcRgn, xoff, yoff);
|
|
if (!pWin->parent) {
|
|
if (srcRgn)
|
|
RegionDestroy(srcRgn);
|
|
return Success;
|
|
}
|
|
|
|
/* May/30/2001:
|
|
* The shape.PS specs say if src is None, existing shape is to be
|
|
* removed (and so the op-code has no meaning in such removal);
|
|
* see shape.PS, page 3, ShapeMask.
|
|
*/
|
|
if (srcRgn == NULL) {
|
|
if (*destRgnp != NULL) {
|
|
RegionDestroy(*destRgnp);
|
|
*destRgnp = 0;
|
|
/* go on to remove shape and generate ShapeNotify */
|
|
}
|
|
else {
|
|
/* May/30/2001:
|
|
* The target currently has no shape in effect, so nothing to
|
|
* do here. The specs say that ShapeNotify is generated whenever
|
|
* the client region is "modified"; since no modification is done
|
|
* here, we do not generate that event. The specs does not say
|
|
* "it is an error to request removal when there is no shape in
|
|
* effect", so we return good status.
|
|
*/
|
|
return Success;
|
|
}
|
|
}
|
|
else
|
|
switch (op) {
|
|
case ShapeSet:
|
|
if (*destRgnp)
|
|
RegionDestroy(*destRgnp);
|
|
*destRgnp = srcRgn;
|
|
srcRgn = 0;
|
|
break;
|
|
case ShapeUnion:
|
|
if (*destRgnp)
|
|
RegionUnion(*destRgnp, *destRgnp, srcRgn);
|
|
break;
|
|
case ShapeIntersect:
|
|
if (*destRgnp)
|
|
RegionIntersect(*destRgnp, *destRgnp, srcRgn);
|
|
else {
|
|
*destRgnp = srcRgn;
|
|
srcRgn = 0;
|
|
}
|
|
break;
|
|
case ShapeSubtract:
|
|
if (!*destRgnp)
|
|
*destRgnp = (*create) (pWin);
|
|
RegionSubtract(*destRgnp, *destRgnp, srcRgn);
|
|
break;
|
|
case ShapeInvert:
|
|
if (!*destRgnp)
|
|
*destRgnp = RegionCreate((BoxPtr) 0, 0);
|
|
else
|
|
RegionSubtract(*destRgnp, srcRgn, *destRgnp);
|
|
break;
|
|
default:
|
|
client->errorValue = op;
|
|
return BadValue;
|
|
}
|
|
if (srcRgn)
|
|
RegionDestroy(srcRgn);
|
|
(*pWin->drawable.pScreen->SetShape) (pWin, kind);
|
|
SendShapeNotify(pWin, kind);
|
|
return Success;
|
|
}
|
|
|
|
RegionPtr
|
|
CreateBoundingShape(WindowPtr pWin)
|
|
{
|
|
BoxRec extents;
|
|
|
|
extents.x1 = -wBorderWidth(pWin);
|
|
extents.y1 = -wBorderWidth(pWin);
|
|
extents.x2 = pWin->drawable.width + wBorderWidth(pWin);
|
|
extents.y2 = pWin->drawable.height + wBorderWidth(pWin);
|
|
return RegionCreate(&extents, 1);
|
|
}
|
|
|
|
RegionPtr
|
|
CreateClipShape(WindowPtr pWin)
|
|
{
|
|
BoxRec extents;
|
|
|
|
extents.x1 = 0;
|
|
extents.y1 = 0;
|
|
extents.x2 = pWin->drawable.width;
|
|
extents.y2 = pWin->drawable.height;
|
|
return RegionCreate(&extents, 1);
|
|
}
|
|
|
|
static int
|
|
ProcShapeQueryVersion(ClientPtr client)
|
|
{
|
|
xShapeQueryVersionReply rep = {
|
|
.type = X_Reply,
|
|
.sequenceNumber = client->sequence,
|
|
.length = 0,
|
|
.majorVersion = SERVER_SHAPE_MAJOR_VERSION,
|
|
.minorVersion = SERVER_SHAPE_MINOR_VERSION
|
|
};
|
|
|
|
REQUEST_SIZE_MATCH(xShapeQueryVersionReq);
|
|
|
|
if (client->swapped) {
|
|
swaps(&rep.sequenceNumber);
|
|
swapl(&rep.length);
|
|
swaps(&rep.majorVersion);
|
|
swaps(&rep.minorVersion);
|
|
}
|
|
WriteToClient(client, sizeof(xShapeQueryVersionReply), &rep);
|
|
return Success;
|
|
}
|
|
|
|
/*****************
|
|
* ProcShapeRectangles
|
|
*
|
|
*****************/
|
|
|
|
static int
|
|
ProcShapeRectangles(ClientPtr client)
|
|
{
|
|
WindowPtr pWin;
|
|
|
|
REQUEST(xShapeRectanglesReq);
|
|
xRectangle *prects;
|
|
int nrects, ctype, rc;
|
|
RegionPtr srcRgn;
|
|
RegionPtr *destRgn;
|
|
CreateDftPtr createDefault;
|
|
|
|
REQUEST_AT_LEAST_SIZE(xShapeRectanglesReq);
|
|
UpdateCurrentTime();
|
|
rc = dixLookupWindow(&pWin, stuff->dest, client, DixSetAttrAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
switch (stuff->destKind) {
|
|
case ShapeBounding:
|
|
createDefault = CreateBoundingShape;
|
|
break;
|
|
case ShapeClip:
|
|
createDefault = CreateClipShape;
|
|
break;
|
|
case ShapeInput:
|
|
createDefault = CreateBoundingShape;
|
|
break;
|
|
default:
|
|
client->errorValue = stuff->destKind;
|
|
return BadValue;
|
|
}
|
|
if ((stuff->ordering != Unsorted) && (stuff->ordering != YSorted) &&
|
|
(stuff->ordering != YXSorted) && (stuff->ordering != YXBanded)) {
|
|
client->errorValue = stuff->ordering;
|
|
return BadValue;
|
|
}
|
|
nrects = ((stuff->length << 2) - sizeof(xShapeRectanglesReq));
|
|
if (nrects & 4)
|
|
return BadLength;
|
|
nrects >>= 3;
|
|
prects = (xRectangle *) &stuff[1];
|
|
ctype = VerifyRectOrder(nrects, prects, (int) stuff->ordering);
|
|
if (ctype < 0)
|
|
return BadMatch;
|
|
srcRgn = RegionFromRects(nrects, prects, ctype);
|
|
|
|
if (!pWin->optional)
|
|
MakeWindowOptional(pWin);
|
|
switch (stuff->destKind) {
|
|
case ShapeBounding:
|
|
destRgn = &pWin->optional->boundingShape;
|
|
break;
|
|
case ShapeClip:
|
|
destRgn = &pWin->optional->clipShape;
|
|
break;
|
|
case ShapeInput:
|
|
destRgn = &pWin->optional->inputShape;
|
|
break;
|
|
default:
|
|
return BadValue;
|
|
}
|
|
|
|
return RegionOperate(client, pWin, (int) stuff->destKind,
|
|
destRgn, srcRgn, (int) stuff->op,
|
|
stuff->xOff, stuff->yOff, createDefault);
|
|
}
|
|
|
|
#ifdef PANORAMIX
|
|
static int
|
|
ProcPanoramiXShapeRectangles(ClientPtr client)
|
|
{
|
|
REQUEST(xShapeRectanglesReq);
|
|
PanoramiXRes *win;
|
|
int j, result;
|
|
|
|
REQUEST_AT_LEAST_SIZE(xShapeRectanglesReq);
|
|
|
|
result = dixLookupResourceByType((void **) &win, stuff->dest, XRT_WINDOW,
|
|
client, DixWriteAccess);
|
|
if (result != Success)
|
|
return result;
|
|
|
|
FOR_NSCREENS(j) {
|
|
stuff->dest = win->info[j].id;
|
|
result = ProcShapeRectangles(client);
|
|
if (result != Success)
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
/**************
|
|
* ProcShapeMask
|
|
**************/
|
|
|
|
static int
|
|
ProcShapeMask(ClientPtr client)
|
|
{
|
|
WindowPtr pWin;
|
|
ScreenPtr pScreen;
|
|
|
|
REQUEST(xShapeMaskReq);
|
|
RegionPtr srcRgn;
|
|
RegionPtr *destRgn;
|
|
PixmapPtr pPixmap;
|
|
CreateDftPtr createDefault;
|
|
int rc;
|
|
|
|
REQUEST_SIZE_MATCH(xShapeMaskReq);
|
|
UpdateCurrentTime();
|
|
rc = dixLookupWindow(&pWin, stuff->dest, client, DixSetAttrAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
switch (stuff->destKind) {
|
|
case ShapeBounding:
|
|
createDefault = CreateBoundingShape;
|
|
break;
|
|
case ShapeClip:
|
|
createDefault = CreateClipShape;
|
|
break;
|
|
case ShapeInput:
|
|
createDefault = CreateBoundingShape;
|
|
break;
|
|
default:
|
|
client->errorValue = stuff->destKind;
|
|
return BadValue;
|
|
}
|
|
pScreen = pWin->drawable.pScreen;
|
|
if (stuff->src == None)
|
|
srcRgn = 0;
|
|
else {
|
|
rc = dixLookupResourceByType((void **) &pPixmap, stuff->src,
|
|
RT_PIXMAP, client, DixReadAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
if (pPixmap->drawable.pScreen != pScreen ||
|
|
pPixmap->drawable.depth != 1)
|
|
return BadMatch;
|
|
srcRgn = BitmapToRegion(pScreen, pPixmap);
|
|
if (!srcRgn)
|
|
return BadAlloc;
|
|
}
|
|
|
|
if (!pWin->optional)
|
|
MakeWindowOptional(pWin);
|
|
switch (stuff->destKind) {
|
|
case ShapeBounding:
|
|
destRgn = &pWin->optional->boundingShape;
|
|
break;
|
|
case ShapeClip:
|
|
destRgn = &pWin->optional->clipShape;
|
|
break;
|
|
case ShapeInput:
|
|
destRgn = &pWin->optional->inputShape;
|
|
break;
|
|
default:
|
|
return BadValue;
|
|
}
|
|
|
|
return RegionOperate(client, pWin, (int) stuff->destKind,
|
|
destRgn, srcRgn, (int) stuff->op,
|
|
stuff->xOff, stuff->yOff, createDefault);
|
|
}
|
|
|
|
#ifdef PANORAMIX
|
|
static int
|
|
ProcPanoramiXShapeMask(ClientPtr client)
|
|
{
|
|
REQUEST(xShapeMaskReq);
|
|
PanoramiXRes *win, *pmap;
|
|
int j, result;
|
|
|
|
REQUEST_SIZE_MATCH(xShapeMaskReq);
|
|
|
|
result = dixLookupResourceByType((void **) &win, stuff->dest, XRT_WINDOW,
|
|
client, DixWriteAccess);
|
|
if (result != Success)
|
|
return result;
|
|
|
|
if (stuff->src != None) {
|
|
result = dixLookupResourceByType((void **) &pmap, stuff->src,
|
|
XRT_PIXMAP, client, DixReadAccess);
|
|
if (result != Success)
|
|
return result;
|
|
}
|
|
else
|
|
pmap = NULL;
|
|
|
|
FOR_NSCREENS(j) {
|
|
stuff->dest = win->info[j].id;
|
|
if (pmap)
|
|
stuff->src = pmap->info[j].id;
|
|
result = ProcShapeMask(client);
|
|
if (result != Success)
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
/************
|
|
* ProcShapeCombine
|
|
************/
|
|
|
|
static int
|
|
ProcShapeCombine(ClientPtr client)
|
|
{
|
|
WindowPtr pSrcWin, pDestWin;
|
|
|
|
REQUEST(xShapeCombineReq);
|
|
RegionPtr srcRgn;
|
|
RegionPtr *destRgn;
|
|
CreateDftPtr createDefault;
|
|
CreateDftPtr createSrc;
|
|
RegionPtr tmp;
|
|
int rc;
|
|
|
|
REQUEST_SIZE_MATCH(xShapeCombineReq);
|
|
UpdateCurrentTime();
|
|
rc = dixLookupWindow(&pDestWin, stuff->dest, client, DixSetAttrAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
if (!pDestWin->optional)
|
|
MakeWindowOptional(pDestWin);
|
|
switch (stuff->destKind) {
|
|
case ShapeBounding:
|
|
createDefault = CreateBoundingShape;
|
|
break;
|
|
case ShapeClip:
|
|
createDefault = CreateClipShape;
|
|
break;
|
|
case ShapeInput:
|
|
createDefault = CreateBoundingShape;
|
|
break;
|
|
default:
|
|
client->errorValue = stuff->destKind;
|
|
return BadValue;
|
|
}
|
|
|
|
rc = dixLookupWindow(&pSrcWin, stuff->src, client, DixGetAttrAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
switch (stuff->srcKind) {
|
|
case ShapeBounding:
|
|
srcRgn = wBoundingShape(pSrcWin);
|
|
createSrc = CreateBoundingShape;
|
|
break;
|
|
case ShapeClip:
|
|
srcRgn = wClipShape(pSrcWin);
|
|
createSrc = CreateClipShape;
|
|
break;
|
|
case ShapeInput:
|
|
srcRgn = wInputShape(pSrcWin);
|
|
createSrc = CreateBoundingShape;
|
|
break;
|
|
default:
|
|
client->errorValue = stuff->srcKind;
|
|
return BadValue;
|
|
}
|
|
if (pSrcWin->drawable.pScreen != pDestWin->drawable.pScreen) {
|
|
return BadMatch;
|
|
}
|
|
|
|
if (srcRgn) {
|
|
tmp = RegionCreate((BoxPtr) 0, 0);
|
|
RegionCopy(tmp, srcRgn);
|
|
srcRgn = tmp;
|
|
}
|
|
else
|
|
srcRgn = (*createSrc) (pSrcWin);
|
|
|
|
if (!pDestWin->optional)
|
|
MakeWindowOptional(pDestWin);
|
|
switch (stuff->destKind) {
|
|
case ShapeBounding:
|
|
destRgn = &pDestWin->optional->boundingShape;
|
|
break;
|
|
case ShapeClip:
|
|
destRgn = &pDestWin->optional->clipShape;
|
|
break;
|
|
case ShapeInput:
|
|
destRgn = &pDestWin->optional->inputShape;
|
|
break;
|
|
default:
|
|
return BadValue;
|
|
}
|
|
|
|
return RegionOperate(client, pDestWin, (int) stuff->destKind,
|
|
destRgn, srcRgn, (int) stuff->op,
|
|
stuff->xOff, stuff->yOff, createDefault);
|
|
}
|
|
|
|
#ifdef PANORAMIX
|
|
static int
|
|
ProcPanoramiXShapeCombine(ClientPtr client)
|
|
{
|
|
REQUEST(xShapeCombineReq);
|
|
PanoramiXRes *win, *win2;
|
|
int j, result;
|
|
|
|
REQUEST_AT_LEAST_SIZE(xShapeCombineReq);
|
|
|
|
result = dixLookupResourceByType((void **) &win, stuff->dest, XRT_WINDOW,
|
|
client, DixWriteAccess);
|
|
if (result != Success)
|
|
return result;
|
|
|
|
result = dixLookupResourceByType((void **) &win2, stuff->src, XRT_WINDOW,
|
|
client, DixReadAccess);
|
|
if (result != Success)
|
|
return result;
|
|
|
|
FOR_NSCREENS(j) {
|
|
stuff->dest = win->info[j].id;
|
|
stuff->src = win2->info[j].id;
|
|
result = ProcShapeCombine(client);
|
|
if (result != Success)
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
/*************
|
|
* ProcShapeOffset
|
|
*************/
|
|
|
|
static int
|
|
ProcShapeOffset(ClientPtr client)
|
|
{
|
|
WindowPtr pWin;
|
|
|
|
REQUEST(xShapeOffsetReq);
|
|
RegionPtr srcRgn;
|
|
int rc;
|
|
|
|
REQUEST_SIZE_MATCH(xShapeOffsetReq);
|
|
UpdateCurrentTime();
|
|
rc = dixLookupWindow(&pWin, stuff->dest, client, DixSetAttrAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
switch (stuff->destKind) {
|
|
case ShapeBounding:
|
|
srcRgn = wBoundingShape(pWin);
|
|
break;
|
|
case ShapeClip:
|
|
srcRgn = wClipShape(pWin);
|
|
break;
|
|
case ShapeInput:
|
|
srcRgn = wInputShape(pWin);
|
|
break;
|
|
default:
|
|
client->errorValue = stuff->destKind;
|
|
return BadValue;
|
|
}
|
|
if (srcRgn) {
|
|
RegionTranslate(srcRgn, stuff->xOff, stuff->yOff);
|
|
(*pWin->drawable.pScreen->SetShape) (pWin, stuff->destKind);
|
|
}
|
|
SendShapeNotify(pWin, (int) stuff->destKind);
|
|
return Success;
|
|
}
|
|
|
|
#ifdef PANORAMIX
|
|
static int
|
|
ProcPanoramiXShapeOffset(ClientPtr client)
|
|
{
|
|
REQUEST(xShapeOffsetReq);
|
|
PanoramiXRes *win;
|
|
int j, result;
|
|
|
|
REQUEST_AT_LEAST_SIZE(xShapeOffsetReq);
|
|
|
|
result = dixLookupResourceByType((void **) &win, stuff->dest, XRT_WINDOW,
|
|
client, DixWriteAccess);
|
|
if (result != Success)
|
|
return result;
|
|
|
|
FOR_NSCREENS(j) {
|
|
stuff->dest = win->info[j].id;
|
|
result = ProcShapeOffset(client);
|
|
if (result != Success)
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
static int
|
|
ProcShapeQueryExtents(ClientPtr client)
|
|
{
|
|
REQUEST(xShapeQueryExtentsReq);
|
|
WindowPtr pWin;
|
|
xShapeQueryExtentsReply rep;
|
|
BoxRec extents, *pExtents;
|
|
int rc;
|
|
RegionPtr region;
|
|
|
|
REQUEST_SIZE_MATCH(xShapeQueryExtentsReq);
|
|
rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
rep = (xShapeQueryExtentsReply) {
|
|
.type = X_Reply,
|
|
.sequenceNumber = client->sequence,
|
|
.length = 0,
|
|
.boundingShaped = (wBoundingShape(pWin) != 0),
|
|
.clipShaped = (wClipShape(pWin) != 0)
|
|
};
|
|
if ((region = wBoundingShape(pWin))) {
|
|
/* this is done in two steps because of a compiler bug on SunOS 4.1.3 */
|
|
pExtents = RegionExtents(region);
|
|
extents = *pExtents;
|
|
}
|
|
else {
|
|
extents.x1 = -wBorderWidth(pWin);
|
|
extents.y1 = -wBorderWidth(pWin);
|
|
extents.x2 = pWin->drawable.width + wBorderWidth(pWin);
|
|
extents.y2 = pWin->drawable.height + wBorderWidth(pWin);
|
|
}
|
|
rep.xBoundingShape = extents.x1;
|
|
rep.yBoundingShape = extents.y1;
|
|
rep.widthBoundingShape = extents.x2 - extents.x1;
|
|
rep.heightBoundingShape = extents.y2 - extents.y1;
|
|
if ((region = wClipShape(pWin))) {
|
|
/* this is done in two steps because of a compiler bug on SunOS 4.1.3 */
|
|
pExtents = RegionExtents(region);
|
|
extents = *pExtents;
|
|
}
|
|
else {
|
|
extents.x1 = 0;
|
|
extents.y1 = 0;
|
|
extents.x2 = pWin->drawable.width;
|
|
extents.y2 = pWin->drawable.height;
|
|
}
|
|
rep.xClipShape = extents.x1;
|
|
rep.yClipShape = extents.y1;
|
|
rep.widthClipShape = extents.x2 - extents.x1;
|
|
rep.heightClipShape = extents.y2 - extents.y1;
|
|
if (client->swapped) {
|
|
swaps(&rep.sequenceNumber);
|
|
swapl(&rep.length);
|
|
swaps(&rep.xBoundingShape);
|
|
swaps(&rep.yBoundingShape);
|
|
swaps(&rep.widthBoundingShape);
|
|
swaps(&rep.heightBoundingShape);
|
|
swaps(&rep.xClipShape);
|
|
swaps(&rep.yClipShape);
|
|
swaps(&rep.widthClipShape);
|
|
swaps(&rep.heightClipShape);
|
|
}
|
|
WriteToClient(client, sizeof(xShapeQueryExtentsReply), &rep);
|
|
return Success;
|
|
}
|
|
|
|
/*ARGSUSED*/ static int
|
|
ShapeFreeClient(void *data, XID id)
|
|
{
|
|
ShapeEventPtr pShapeEvent;
|
|
WindowPtr pWin;
|
|
ShapeEventPtr *pHead, pCur, pPrev;
|
|
int rc;
|
|
|
|
pShapeEvent = (ShapeEventPtr) data;
|
|
pWin = pShapeEvent->window;
|
|
rc = dixLookupResourceByType((void **) &pHead, pWin->drawable.id,
|
|
ShapeEventType, serverClient, DixReadAccess);
|
|
if (rc == Success) {
|
|
pPrev = 0;
|
|
for (pCur = *pHead; pCur && pCur != pShapeEvent; pCur = pCur->next)
|
|
pPrev = pCur;
|
|
if (pCur) {
|
|
if (pPrev)
|
|
pPrev->next = pShapeEvent->next;
|
|
else
|
|
*pHead = pShapeEvent->next;
|
|
}
|
|
}
|
|
free((void *) pShapeEvent);
|
|
return 1;
|
|
}
|
|
|
|
/*ARGSUSED*/ static int
|
|
ShapeFreeEvents(void *data, XID id)
|
|
{
|
|
ShapeEventPtr *pHead, pCur, pNext;
|
|
|
|
pHead = (ShapeEventPtr *) data;
|
|
for (pCur = *pHead; pCur; pCur = pNext) {
|
|
pNext = pCur->next;
|
|
FreeResource(pCur->clientResource, ClientType);
|
|
free((void *) pCur);
|
|
}
|
|
free((void *) pHead);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
ProcShapeSelectInput(ClientPtr client)
|
|
{
|
|
REQUEST(xShapeSelectInputReq);
|
|
WindowPtr pWin;
|
|
ShapeEventPtr pShapeEvent, pNewShapeEvent, *pHead;
|
|
XID clientResource;
|
|
int rc;
|
|
|
|
REQUEST_SIZE_MATCH(xShapeSelectInputReq);
|
|
rc = dixLookupWindow(&pWin, stuff->window, client, DixReceiveAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
rc = dixLookupResourceByType((void **) &pHead, pWin->drawable.id,
|
|
ShapeEventType, client, DixWriteAccess);
|
|
if (rc != Success && rc != BadValue)
|
|
return rc;
|
|
|
|
switch (stuff->enable) {
|
|
case xTrue:
|
|
if (pHead) {
|
|
|
|
/* check for existing entry. */
|
|
for (pShapeEvent = *pHead;
|
|
pShapeEvent; pShapeEvent = pShapeEvent->next) {
|
|
if (pShapeEvent->client == client)
|
|
return Success;
|
|
}
|
|
}
|
|
|
|
/* build the entry */
|
|
pNewShapeEvent = malloc(sizeof(ShapeEventRec));
|
|
if (!pNewShapeEvent)
|
|
return BadAlloc;
|
|
pNewShapeEvent->next = 0;
|
|
pNewShapeEvent->client = client;
|
|
pNewShapeEvent->window = pWin;
|
|
/*
|
|
* add a resource that will be deleted when
|
|
* the client goes away
|
|
*/
|
|
clientResource = FakeClientID(client->index);
|
|
pNewShapeEvent->clientResource = clientResource;
|
|
if (!AddResource(clientResource, ClientType, (void *) pNewShapeEvent))
|
|
return BadAlloc;
|
|
/*
|
|
* create a resource to contain a void *to the list
|
|
* of clients selecting input. This must be indirect as
|
|
* the list may be arbitrarily rearranged which cannot be
|
|
* done through the resource database.
|
|
*/
|
|
if (!pHead) {
|
|
pHead = malloc(sizeof(ShapeEventPtr));
|
|
if (!pHead ||
|
|
!AddResource(pWin->drawable.id, ShapeEventType,
|
|
(void *) pHead)) {
|
|
FreeResource(clientResource, RT_NONE);
|
|
return BadAlloc;
|
|
}
|
|
*pHead = 0;
|
|
}
|
|
pNewShapeEvent->next = *pHead;
|
|
*pHead = pNewShapeEvent;
|
|
break;
|
|
case xFalse:
|
|
/* delete the interest */
|
|
if (pHead) {
|
|
pNewShapeEvent = 0;
|
|
for (pShapeEvent = *pHead; pShapeEvent;
|
|
pShapeEvent = pShapeEvent->next) {
|
|
if (pShapeEvent->client == client)
|
|
break;
|
|
pNewShapeEvent = pShapeEvent;
|
|
}
|
|
if (pShapeEvent) {
|
|
FreeResource(pShapeEvent->clientResource, ClientType);
|
|
if (pNewShapeEvent)
|
|
pNewShapeEvent->next = pShapeEvent->next;
|
|
else
|
|
*pHead = pShapeEvent->next;
|
|
free(pShapeEvent);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
client->errorValue = stuff->enable;
|
|
return BadValue;
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
/*
|
|
* deliver the event
|
|
*/
|
|
|
|
void
|
|
SendShapeNotify(WindowPtr pWin, int which)
|
|
{
|
|
ShapeEventPtr *pHead, pShapeEvent;
|
|
BoxRec extents;
|
|
RegionPtr region;
|
|
BYTE shaped;
|
|
int rc;
|
|
|
|
rc = dixLookupResourceByType((void **) &pHead, pWin->drawable.id,
|
|
ShapeEventType, serverClient, DixReadAccess);
|
|
if (rc != Success)
|
|
return;
|
|
switch (which) {
|
|
case ShapeBounding:
|
|
region = wBoundingShape(pWin);
|
|
if (region) {
|
|
extents = *RegionExtents(region);
|
|
shaped = xTrue;
|
|
}
|
|
else {
|
|
extents.x1 = -wBorderWidth(pWin);
|
|
extents.y1 = -wBorderWidth(pWin);
|
|
extents.x2 = pWin->drawable.width + wBorderWidth(pWin);
|
|
extents.y2 = pWin->drawable.height + wBorderWidth(pWin);
|
|
shaped = xFalse;
|
|
}
|
|
break;
|
|
case ShapeClip:
|
|
region = wClipShape(pWin);
|
|
if (region) {
|
|
extents = *RegionExtents(region);
|
|
shaped = xTrue;
|
|
}
|
|
else {
|
|
extents.x1 = 0;
|
|
extents.y1 = 0;
|
|
extents.x2 = pWin->drawable.width;
|
|
extents.y2 = pWin->drawable.height;
|
|
shaped = xFalse;
|
|
}
|
|
break;
|
|
case ShapeInput:
|
|
region = wInputShape(pWin);
|
|
if (region) {
|
|
extents = *RegionExtents(region);
|
|
shaped = xTrue;
|
|
}
|
|
else {
|
|
extents.x1 = -wBorderWidth(pWin);
|
|
extents.y1 = -wBorderWidth(pWin);
|
|
extents.x2 = pWin->drawable.width + wBorderWidth(pWin);
|
|
extents.y2 = pWin->drawable.height + wBorderWidth(pWin);
|
|
shaped = xFalse;
|
|
}
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
for (pShapeEvent = *pHead; pShapeEvent; pShapeEvent = pShapeEvent->next) {
|
|
xShapeNotifyEvent se = {
|
|
.type = ShapeNotify + ShapeEventBase,
|
|
.kind = which,
|
|
.window = pWin->drawable.id,
|
|
.x = extents.x1,
|
|
.y = extents.y1,
|
|
.width = extents.x2 - extents.x1,
|
|
.height = extents.y2 - extents.y1,
|
|
.time = currentTime.milliseconds,
|
|
.shaped = shaped
|
|
};
|
|
WriteEventsToClient(pShapeEvent->client, 1, (xEvent *) &se);
|
|
}
|
|
}
|
|
|
|
static int
|
|
ProcShapeInputSelected(ClientPtr client)
|
|
{
|
|
REQUEST(xShapeInputSelectedReq);
|
|
WindowPtr pWin;
|
|
ShapeEventPtr pShapeEvent, *pHead;
|
|
int enabled, rc;
|
|
xShapeInputSelectedReply rep;
|
|
|
|
REQUEST_SIZE_MATCH(xShapeInputSelectedReq);
|
|
rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
rc = dixLookupResourceByType((void **) &pHead, pWin->drawable.id,
|
|
ShapeEventType, client, DixReadAccess);
|
|
if (rc != Success && rc != BadValue)
|
|
return rc;
|
|
enabled = xFalse;
|
|
if (pHead) {
|
|
for (pShapeEvent = *pHead; pShapeEvent; pShapeEvent = pShapeEvent->next) {
|
|
if (pShapeEvent->client == client) {
|
|
enabled = xTrue;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
rep = (xShapeInputSelectedReply) {
|
|
.type = X_Reply,
|
|
.enabled = enabled,
|
|
.sequenceNumber = client->sequence,
|
|
.length = 0
|
|
};
|
|
if (client->swapped) {
|
|
swaps(&rep.sequenceNumber);
|
|
swapl(&rep.length);
|
|
}
|
|
WriteToClient(client, sizeof(xShapeInputSelectedReply), &rep);
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
ProcShapeGetRectangles(ClientPtr client)
|
|
{
|
|
REQUEST(xShapeGetRectanglesReq);
|
|
WindowPtr pWin;
|
|
xShapeGetRectanglesReply rep;
|
|
xRectangle *rects;
|
|
int nrects, i, rc;
|
|
RegionPtr region;
|
|
|
|
REQUEST_SIZE_MATCH(xShapeGetRectanglesReq);
|
|
rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
switch (stuff->kind) {
|
|
case ShapeBounding:
|
|
region = wBoundingShape(pWin);
|
|
break;
|
|
case ShapeClip:
|
|
region = wClipShape(pWin);
|
|
break;
|
|
case ShapeInput:
|
|
region = wInputShape(pWin);
|
|
break;
|
|
default:
|
|
client->errorValue = stuff->kind;
|
|
return BadValue;
|
|
}
|
|
if (!region) {
|
|
nrects = 1;
|
|
rects = malloc(sizeof(xRectangle));
|
|
if (!rects)
|
|
return BadAlloc;
|
|
switch (stuff->kind) {
|
|
case ShapeBounding:
|
|
rects->x = -(int) wBorderWidth(pWin);
|
|
rects->y = -(int) wBorderWidth(pWin);
|
|
rects->width = pWin->drawable.width + wBorderWidth(pWin);
|
|
rects->height = pWin->drawable.height + wBorderWidth(pWin);
|
|
break;
|
|
case ShapeClip:
|
|
rects->x = 0;
|
|
rects->y = 0;
|
|
rects->width = pWin->drawable.width;
|
|
rects->height = pWin->drawable.height;
|
|
break;
|
|
case ShapeInput:
|
|
rects->x = -(int) wBorderWidth(pWin);
|
|
rects->y = -(int) wBorderWidth(pWin);
|
|
rects->width = pWin->drawable.width + wBorderWidth(pWin);
|
|
rects->height = pWin->drawable.height + wBorderWidth(pWin);
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
BoxPtr box;
|
|
|
|
nrects = RegionNumRects(region);
|
|
box = RegionRects(region);
|
|
rects = malloc(nrects * sizeof(xRectangle));
|
|
if (!rects && nrects)
|
|
return BadAlloc;
|
|
for (i = 0; i < nrects; i++, box++) {
|
|
rects[i].x = box->x1;
|
|
rects[i].y = box->y1;
|
|
rects[i].width = box->x2 - box->x1;
|
|
rects[i].height = box->y2 - box->y1;
|
|
}
|
|
}
|
|
rep = (xShapeGetRectanglesReply) {
|
|
.type = X_Reply,
|
|
.ordering = YXBanded,
|
|
.sequenceNumber = client->sequence,
|
|
.length = bytes_to_int32(nrects * sizeof(xRectangle)),
|
|
.nrects = nrects
|
|
};
|
|
if (client->swapped) {
|
|
swaps(&rep.sequenceNumber);
|
|
swapl(&rep.length);
|
|
swapl(&rep.nrects);
|
|
SwapShorts((short *) rects, (unsigned long) nrects * 4);
|
|
}
|
|
WriteToClient(client, sizeof(rep), &rep);
|
|
WriteToClient(client, nrects * sizeof(xRectangle), rects);
|
|
free(rects);
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
ProcShapeDispatch(ClientPtr client)
|
|
{
|
|
REQUEST(xReq);
|
|
switch (stuff->data) {
|
|
case X_ShapeQueryVersion:
|
|
return ProcShapeQueryVersion(client);
|
|
case X_ShapeRectangles:
|
|
#ifdef PANORAMIX
|
|
if (!noPanoramiXExtension)
|
|
return ProcPanoramiXShapeRectangles(client);
|
|
else
|
|
#endif
|
|
return ProcShapeRectangles(client);
|
|
case X_ShapeMask:
|
|
#ifdef PANORAMIX
|
|
if (!noPanoramiXExtension)
|
|
return ProcPanoramiXShapeMask(client);
|
|
else
|
|
#endif
|
|
return ProcShapeMask(client);
|
|
case X_ShapeCombine:
|
|
#ifdef PANORAMIX
|
|
if (!noPanoramiXExtension)
|
|
return ProcPanoramiXShapeCombine(client);
|
|
else
|
|
#endif
|
|
return ProcShapeCombine(client);
|
|
case X_ShapeOffset:
|
|
#ifdef PANORAMIX
|
|
if (!noPanoramiXExtension)
|
|
return ProcPanoramiXShapeOffset(client);
|
|
else
|
|
#endif
|
|
return ProcShapeOffset(client);
|
|
case X_ShapeQueryExtents:
|
|
return ProcShapeQueryExtents(client);
|
|
case X_ShapeSelectInput:
|
|
return ProcShapeSelectInput(client);
|
|
case X_ShapeInputSelected:
|
|
return ProcShapeInputSelected(client);
|
|
case X_ShapeGetRectangles:
|
|
return ProcShapeGetRectangles(client);
|
|
default:
|
|
return BadRequest;
|
|
}
|
|
}
|
|
|
|
static void
|
|
SShapeNotifyEvent(xShapeNotifyEvent * from, xShapeNotifyEvent * to)
|
|
{
|
|
to->type = from->type;
|
|
to->kind = from->kind;
|
|
cpswapl(from->window, to->window);
|
|
cpswaps(from->sequenceNumber, to->sequenceNumber);
|
|
cpswaps(from->x, to->x);
|
|
cpswaps(from->y, to->y);
|
|
cpswaps(from->width, to->width);
|
|
cpswaps(from->height, to->height);
|
|
cpswapl(from->time, to->time);
|
|
to->shaped = from->shaped;
|
|
}
|
|
|
|
static int
|
|
SProcShapeQueryVersion(ClientPtr client)
|
|
{
|
|
REQUEST(xShapeQueryVersionReq);
|
|
|
|
swaps(&stuff->length);
|
|
return ProcShapeQueryVersion(client);
|
|
}
|
|
|
|
static int
|
|
SProcShapeRectangles(ClientPtr client)
|
|
{
|
|
REQUEST(xShapeRectanglesReq);
|
|
|
|
swaps(&stuff->length);
|
|
REQUEST_AT_LEAST_SIZE(xShapeRectanglesReq);
|
|
swapl(&stuff->dest);
|
|
swaps(&stuff->xOff);
|
|
swaps(&stuff->yOff);
|
|
SwapRestS(stuff);
|
|
return ProcShapeRectangles(client);
|
|
}
|
|
|
|
static int
|
|
SProcShapeMask(ClientPtr client)
|
|
{
|
|
REQUEST(xShapeMaskReq);
|
|
|
|
swaps(&stuff->length);
|
|
REQUEST_SIZE_MATCH(xShapeMaskReq);
|
|
swapl(&stuff->dest);
|
|
swaps(&stuff->xOff);
|
|
swaps(&stuff->yOff);
|
|
swapl(&stuff->src);
|
|
return ProcShapeMask(client);
|
|
}
|
|
|
|
static int
|
|
SProcShapeCombine(ClientPtr client)
|
|
{
|
|
REQUEST(xShapeCombineReq);
|
|
|
|
swaps(&stuff->length);
|
|
REQUEST_SIZE_MATCH(xShapeCombineReq);
|
|
swapl(&stuff->dest);
|
|
swaps(&stuff->xOff);
|
|
swaps(&stuff->yOff);
|
|
swapl(&stuff->src);
|
|
return ProcShapeCombine(client);
|
|
}
|
|
|
|
static int
|
|
SProcShapeOffset(ClientPtr client)
|
|
{
|
|
REQUEST(xShapeOffsetReq);
|
|
|
|
swaps(&stuff->length);
|
|
REQUEST_SIZE_MATCH(xShapeOffsetReq);
|
|
swapl(&stuff->dest);
|
|
swaps(&stuff->xOff);
|
|
swaps(&stuff->yOff);
|
|
return ProcShapeOffset(client);
|
|
}
|
|
|
|
static int
|
|
SProcShapeQueryExtents(ClientPtr client)
|
|
{
|
|
REQUEST(xShapeQueryExtentsReq);
|
|
|
|
swaps(&stuff->length);
|
|
REQUEST_SIZE_MATCH(xShapeQueryExtentsReq);
|
|
swapl(&stuff->window);
|
|
return ProcShapeQueryExtents(client);
|
|
}
|
|
|
|
static int
|
|
SProcShapeSelectInput(ClientPtr client)
|
|
{
|
|
REQUEST(xShapeSelectInputReq);
|
|
|
|
swaps(&stuff->length);
|
|
REQUEST_SIZE_MATCH(xShapeSelectInputReq);
|
|
swapl(&stuff->window);
|
|
return ProcShapeSelectInput(client);
|
|
}
|
|
|
|
static int
|
|
SProcShapeInputSelected(ClientPtr client)
|
|
{
|
|
REQUEST(xShapeInputSelectedReq);
|
|
|
|
swaps(&stuff->length);
|
|
REQUEST_SIZE_MATCH(xShapeInputSelectedReq);
|
|
swapl(&stuff->window);
|
|
return ProcShapeInputSelected(client);
|
|
}
|
|
|
|
static int
|
|
SProcShapeGetRectangles(ClientPtr client)
|
|
{
|
|
REQUEST(xShapeGetRectanglesReq);
|
|
swaps(&stuff->length);
|
|
REQUEST_SIZE_MATCH(xShapeGetRectanglesReq);
|
|
swapl(&stuff->window);
|
|
return ProcShapeGetRectangles(client);
|
|
}
|
|
|
|
static int
|
|
SProcShapeDispatch(ClientPtr client)
|
|
{
|
|
REQUEST(xReq);
|
|
switch (stuff->data) {
|
|
case X_ShapeQueryVersion:
|
|
return SProcShapeQueryVersion(client);
|
|
case X_ShapeRectangles:
|
|
return SProcShapeRectangles(client);
|
|
case X_ShapeMask:
|
|
return SProcShapeMask(client);
|
|
case X_ShapeCombine:
|
|
return SProcShapeCombine(client);
|
|
case X_ShapeOffset:
|
|
return SProcShapeOffset(client);
|
|
case X_ShapeQueryExtents:
|
|
return SProcShapeQueryExtents(client);
|
|
case X_ShapeSelectInput:
|
|
return SProcShapeSelectInput(client);
|
|
case X_ShapeInputSelected:
|
|
return SProcShapeInputSelected(client);
|
|
case X_ShapeGetRectangles:
|
|
return SProcShapeGetRectangles(client);
|
|
default:
|
|
return BadRequest;
|
|
}
|
|
}
|
|
|
|
void
|
|
ShapeExtensionInit(void)
|
|
{
|
|
ExtensionEntry *extEntry;
|
|
|
|
ClientType = CreateNewResourceType(ShapeFreeClient, "ShapeClient");
|
|
ShapeEventType = CreateNewResourceType(ShapeFreeEvents, "ShapeEvent");
|
|
if (ClientType && ShapeEventType &&
|
|
(extEntry = AddExtension(SHAPENAME, ShapeNumberEvents, 0,
|
|
ProcShapeDispatch, SProcShapeDispatch,
|
|
NULL, StandardMinorOpcode))) {
|
|
ShapeEventBase = extEntry->eventBase;
|
|
EventSwapVector[ShapeEventBase] = (EventSwapPtr) SShapeNotifyEvent;
|
|
}
|
|
}
|