xenocara/xserver/damageext/damageext.c

500 lines
15 KiB
C
Raw Normal View History

2006-11-26 11:13:41 -07:00
/*
* Copyright © 2002 Keith Packard
*
* 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, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "damageextint.h"
#include "protocol-versions.h"
2006-11-26 11:13:41 -07:00
static unsigned char DamageReqCode;
static int DamageEventBase;
static RESTYPE DamageExtType;
static RESTYPE DamageExtWinType;
2007-11-24 10:55:21 -07:00
static DevPrivateKeyRec DamageClientPrivateKeyRec;
#define DamageClientPrivateKey (&DamageClientPrivateKeyRec)
2006-11-26 11:13:41 -07:00
static void
DamageExtNotify(DamageExtPtr pDamageExt, BoxPtr pBoxes, int nBoxes)
2006-11-26 11:13:41 -07:00
{
ClientPtr pClient = pDamageExt->pClient;
DamageClientPtr pDamageClient = GetDamageClient(pClient);
DrawablePtr pDrawable = pDamageExt->pDrawable;
xDamageNotifyEvent ev;
int i;
2006-11-26 11:13:41 -07:00
UpdateCurrentTimeIf();
2006-11-26 11:13:41 -07:00
ev.type = DamageEventBase + XDamageNotify;
ev.level = pDamageExt->level;
ev.drawable = pDamageExt->drawable;
2006-11-26 11:13:41 -07:00
ev.damage = pDamageExt->id;
ev.timestamp = currentTime.milliseconds;
ev.geometry.x = pDrawable->x;
ev.geometry.y = pDrawable->y;
ev.geometry.width = pDrawable->width;
ev.geometry.height = pDrawable->height;
if (pBoxes) {
for (i = 0; i < nBoxes; i++) {
ev.level = pDamageExt->level;
if (i < nBoxes - 1)
ev.level |= DamageNotifyMore;
ev.area.x = pBoxes[i].x1;
ev.area.y = pBoxes[i].y1;
ev.area.width = pBoxes[i].x2 - pBoxes[i].x1;
ev.area.height = pBoxes[i].y2 - pBoxes[i].y1;
WriteEventsToClient(pClient, 1, (xEvent *) &ev);
}
2006-11-26 11:13:41 -07:00
}
else {
ev.area.x = 0;
ev.area.y = 0;
ev.area.width = pDrawable->width;
ev.area.height = pDrawable->height;
WriteEventsToClient(pClient, 1, (xEvent *) &ev);
2006-11-26 11:13:41 -07:00
}
/* Composite extension marks clients with manual Subwindows as critical */
if (pDamageClient->critical > 0) {
SetCriticalOutputPending();
pClient->smart_priority = SMART_MAX_PRIORITY;
2006-11-26 11:13:41 -07:00
}
}
static void
DamageExtReport(DamagePtr pDamage, RegionPtr pRegion, void *closure)
2006-11-26 11:13:41 -07:00
{
DamageExtPtr pDamageExt = closure;
2006-11-26 11:13:41 -07:00
switch (pDamageExt->level) {
case DamageReportRawRegion:
case DamageReportDeltaRegion:
DamageExtNotify(pDamageExt, RegionRects(pRegion),
RegionNumRects(pRegion));
break;
2006-11-26 11:13:41 -07:00
case DamageReportBoundingBox:
DamageExtNotify(pDamageExt, RegionExtents(pRegion), 1);
break;
2006-11-26 11:13:41 -07:00
case DamageReportNonEmpty:
DamageExtNotify(pDamageExt, NullBox, 0);
break;
2006-11-26 11:13:41 -07:00
case DamageReportNone:
break;
2006-11-26 11:13:41 -07:00
}
}
static void
DamageExtDestroy(DamagePtr pDamage, void *closure)
2006-11-26 11:13:41 -07:00
{
DamageExtPtr pDamageExt = closure;
2006-11-26 11:13:41 -07:00
pDamageExt->pDamage = 0;
if (pDamageExt->id)
FreeResource(pDamageExt->id, RT_NONE);
2006-11-26 11:13:41 -07:00
}
void
DamageExtSetCritical(ClientPtr pClient, Bool critical)
2006-11-26 11:13:41 -07:00
{
DamageClientPtr pDamageClient = GetDamageClient(pClient);
2006-11-26 11:13:41 -07:00
if (pDamageClient)
pDamageClient->critical += critical ? 1 : -1;
2006-11-26 11:13:41 -07:00
}
static int
ProcDamageQueryVersion(ClientPtr client)
{
DamageClientPtr pDamageClient = GetDamageClient(client);
2006-11-26 11:13:41 -07:00
xDamageQueryVersionReply rep;
2006-11-26 11:13:41 -07:00
REQUEST(xDamageQueryVersionReq);
REQUEST_SIZE_MATCH(xDamageQueryVersionReq);
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
if (stuff->majorVersion < SERVER_DAMAGE_MAJOR_VERSION) {
rep.majorVersion = stuff->majorVersion;
rep.minorVersion = stuff->minorVersion;
}
else {
rep.majorVersion = SERVER_DAMAGE_MAJOR_VERSION;
if (stuff->majorVersion == SERVER_DAMAGE_MAJOR_VERSION &&
stuff->minorVersion < SERVER_DAMAGE_MINOR_VERSION)
rep.minorVersion = stuff->minorVersion;
else
rep.minorVersion = SERVER_DAMAGE_MINOR_VERSION;
2006-11-26 11:13:41 -07:00
}
pDamageClient->major_version = rep.majorVersion;
pDamageClient->minor_version = rep.minorVersion;
if (client->swapped) {
swaps(&rep.sequenceNumber);
swapl(&rep.length);
swapl(&rep.majorVersion);
swapl(&rep.minorVersion);
2006-11-26 11:13:41 -07:00
}
WriteToClient(client, sizeof(xDamageQueryVersionReply), (char *) &rep);
return Success;
2006-11-26 11:13:41 -07:00
}
static int
ProcDamageCreate(ClientPtr client)
2006-11-26 11:13:41 -07:00
{
DrawablePtr pDrawable;
DamageExtPtr pDamageExt;
DamageReportLevel level;
RegionPtr pRegion;
int rc;
2006-11-26 11:13:41 -07:00
REQUEST(xDamageCreateReq);
REQUEST_SIZE_MATCH(xDamageCreateReq);
LEGAL_NEW_RESOURCE(stuff->damage, client);
2007-11-24 10:55:21 -07:00
rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
DixGetAttrAccess | DixReadAccess);
2007-11-24 10:55:21 -07:00
if (rc != Success)
return rc;
2007-11-24 10:55:21 -07:00
2006-11-26 11:13:41 -07:00
switch (stuff->level) {
case XDamageReportRawRectangles:
level = DamageReportRawRegion;
break;
2006-11-26 11:13:41 -07:00
case XDamageReportDeltaRectangles:
level = DamageReportDeltaRegion;
break;
2006-11-26 11:13:41 -07:00
case XDamageReportBoundingBox:
level = DamageReportBoundingBox;
break;
2006-11-26 11:13:41 -07:00
case XDamageReportNonEmpty:
level = DamageReportNonEmpty;
break;
2006-11-26 11:13:41 -07:00
default:
client->errorValue = stuff->level;
return BadValue;
2006-11-26 11:13:41 -07:00
}
pDamageExt = malloc(sizeof(DamageExtRec));
2006-11-26 11:13:41 -07:00
if (!pDamageExt)
return BadAlloc;
2006-11-26 11:13:41 -07:00
pDamageExt->id = stuff->damage;
pDamageExt->drawable = stuff->drawable;
2006-11-26 11:13:41 -07:00
pDamageExt->pDrawable = pDrawable;
pDamageExt->level = level;
pDamageExt->pClient = client;
pDamageExt->pDamage = DamageCreate(DamageExtReport,
DamageExtDestroy,
level,
FALSE, pDrawable->pScreen, pDamageExt);
if (!pDamageExt->pDamage) {
free(pDamageExt);
return BadAlloc;
2006-11-26 11:13:41 -07:00
}
if (!AddResource(stuff->damage, DamageExtType, (pointer) pDamageExt))
return BadAlloc;
2006-11-26 11:13:41 -07:00
DamageSetReportAfterOp(pDamageExt->pDamage, TRUE);
DamageRegister(pDamageExt->pDrawable, pDamageExt->pDamage);
2006-11-26 11:13:41 -07:00
if (pDrawable->type == DRAWABLE_WINDOW) {
pRegion = &((WindowPtr) pDrawable)->borderClip;
DamageReportDamage(pDamageExt->pDamage, pRegion);
2006-11-26 11:13:41 -07:00
}
return Success;
2006-11-26 11:13:41 -07:00
}
static int
ProcDamageDestroy(ClientPtr client)
2006-11-26 11:13:41 -07:00
{
REQUEST(xDamageDestroyReq);
DamageExtPtr pDamageExt;
2006-11-26 11:13:41 -07:00
REQUEST_SIZE_MATCH(xDamageDestroyReq);
2007-11-24 10:55:21 -07:00
VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, DixWriteAccess);
FreeResource(stuff->damage, RT_NONE);
return Success;
2006-11-26 11:13:41 -07:00
}
static int
ProcDamageSubtract(ClientPtr client)
2006-11-26 11:13:41 -07:00
{
REQUEST(xDamageSubtractReq);
DamageExtPtr pDamageExt;
RegionPtr pRepair;
RegionPtr pParts;
2006-11-26 11:13:41 -07:00
REQUEST_SIZE_MATCH(xDamageSubtractReq);
2007-11-24 10:55:21 -07:00
VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, DixWriteAccess);
VERIFY_REGION_OR_NONE(pRepair, stuff->repair, client, DixWriteAccess);
VERIFY_REGION_OR_NONE(pParts, stuff->parts, client, DixWriteAccess);
2006-11-26 11:13:41 -07:00
if (pDamageExt->level != DamageReportRawRegion) {
DamagePtr pDamage = pDamageExt->pDamage;
if (pRepair) {
if (pParts)
RegionIntersect(pParts, DamageRegion(pDamage), pRepair);
if (DamageSubtract(pDamage, pRepair))
DamageExtReport(pDamage, DamageRegion(pDamage),
(void *) pDamageExt);
}
else {
if (pParts)
RegionCopy(pParts, DamageRegion(pDamage));
DamageEmpty(pDamage);
}
2006-11-26 11:13:41 -07:00
}
return Success;
2006-11-26 11:13:41 -07:00
}
2007-11-24 10:55:21 -07:00
static int
ProcDamageAdd(ClientPtr client)
2007-11-24 10:55:21 -07:00
{
REQUEST(xDamageAddReq);
DrawablePtr pDrawable;
RegionPtr pRegion;
int rc;
2007-11-24 10:55:21 -07:00
REQUEST_SIZE_MATCH(xDamageAddReq);
VERIFY_REGION(pRegion, stuff->region, client, DixWriteAccess);
rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
DixWriteAccess);
2007-11-24 10:55:21 -07:00
if (rc != Success)
return rc;
2007-11-24 10:55:21 -07:00
/* The region is relative to the drawable origin, so translate it out to
* screen coordinates like damage expects.
*/
RegionTranslate(pRegion, pDrawable->x, pDrawable->y);
DamageDamageRegion(pDrawable, pRegion);
RegionTranslate(pRegion, -pDrawable->x, -pDrawable->y);
2007-11-24 10:55:21 -07:00
return Success;
2007-11-24 10:55:21 -07:00
}
2006-11-26 11:13:41 -07:00
/* Major version controls available requests */
static const int version_requests[] = {
X_DamageQueryVersion, /* before client sends QueryVersion */
X_DamageAdd, /* Version 1 */
2006-11-26 11:13:41 -07:00
};
#define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0]))
static int (*ProcDamageVector[XDamageNumberRequests]) (ClientPtr) = {
2006-11-26 11:13:41 -07:00
/*************** Version 1 ******************/
ProcDamageQueryVersion,
ProcDamageCreate, ProcDamageDestroy, ProcDamageSubtract,
2007-11-24 10:55:21 -07:00
/*************** Version 1.1 ****************/
ProcDamageAdd,};
2006-11-26 11:13:41 -07:00
static int
ProcDamageDispatch(ClientPtr client)
2006-11-26 11:13:41 -07:00
{
REQUEST(xDamageReq);
DamageClientPtr pDamageClient = GetDamageClient(client);
2006-11-26 11:13:41 -07:00
if (pDamageClient->major_version >= NUM_VERSION_REQUESTS)
return BadRequest;
2006-11-26 11:13:41 -07:00
if (stuff->damageReqType > version_requests[pDamageClient->major_version])
return BadRequest;
2006-11-26 11:13:41 -07:00
return (*ProcDamageVector[stuff->damageReqType]) (client);
}
static int
SProcDamageQueryVersion(ClientPtr client)
{
REQUEST(xDamageQueryVersionReq);
swaps(&stuff->length);
2006-11-26 11:13:41 -07:00
REQUEST_SIZE_MATCH(xDamageQueryVersionReq);
swapl(&stuff->majorVersion);
swapl(&stuff->minorVersion);
2006-11-26 11:13:41 -07:00
return (*ProcDamageVector[stuff->damageReqType]) (client);
}
static int
SProcDamageCreate(ClientPtr client)
2006-11-26 11:13:41 -07:00
{
REQUEST(xDamageCreateReq);
swaps(&stuff->length);
2006-11-26 11:13:41 -07:00
REQUEST_SIZE_MATCH(xDamageCreateReq);
swapl(&stuff->damage);
swapl(&stuff->drawable);
2006-11-26 11:13:41 -07:00
return (*ProcDamageVector[stuff->damageReqType]) (client);
}
static int
SProcDamageDestroy(ClientPtr client)
2006-11-26 11:13:41 -07:00
{
REQUEST(xDamageDestroyReq);
swaps(&stuff->length);
2006-11-26 11:13:41 -07:00
REQUEST_SIZE_MATCH(xDamageDestroyReq);
swapl(&stuff->damage);
2006-11-26 11:13:41 -07:00
return (*ProcDamageVector[stuff->damageReqType]) (client);
}
static int
SProcDamageSubtract(ClientPtr client)
2006-11-26 11:13:41 -07:00
{
REQUEST(xDamageSubtractReq);
swaps(&stuff->length);
2006-11-26 11:13:41 -07:00
REQUEST_SIZE_MATCH(xDamageSubtractReq);
swapl(&stuff->damage);
swapl(&stuff->repair);
swapl(&stuff->parts);
2006-11-26 11:13:41 -07:00
return (*ProcDamageVector[stuff->damageReqType]) (client);
}
2007-11-24 10:55:21 -07:00
static int
SProcDamageAdd(ClientPtr client)
2007-11-24 10:55:21 -07:00
{
REQUEST(xDamageAddReq);
swaps(&stuff->length);
2007-11-24 10:55:21 -07:00
REQUEST_SIZE_MATCH(xDamageSubtractReq);
swapl(&stuff->drawable);
swapl(&stuff->region);
2007-11-24 10:55:21 -07:00
return (*ProcDamageVector[stuff->damageReqType]) (client);
}
static int (*SProcDamageVector[XDamageNumberRequests]) (ClientPtr) = {
2006-11-26 11:13:41 -07:00
/*************** Version 1 ******************/
SProcDamageQueryVersion,
SProcDamageCreate, SProcDamageDestroy, SProcDamageSubtract,
2007-11-24 10:55:21 -07:00
/*************** Version 1.1 ****************/
SProcDamageAdd,};
2006-11-26 11:13:41 -07:00
static int
SProcDamageDispatch(ClientPtr client)
2006-11-26 11:13:41 -07:00
{
REQUEST(xDamageReq);
if (stuff->damageReqType >= XDamageNumberRequests)
return BadRequest;
2006-11-26 11:13:41 -07:00
return (*SProcDamageVector[stuff->damageReqType]) (client);
}
static void
DamageClientCallback(CallbackListPtr *list, pointer closure, pointer data)
2006-11-26 11:13:41 -07:00
{
NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
ClientPtr pClient = clientinfo->client;
DamageClientPtr pDamageClient = GetDamageClient(pClient);
2006-11-26 11:13:41 -07:00
pDamageClient->critical = 0;
pDamageClient->major_version = 0;
pDamageClient->minor_version = 0;
}
/*ARGSUSED*/ static void
DamageResetProc(ExtensionEntry * extEntry)
2006-11-26 11:13:41 -07:00
{
DeleteCallback(&ClientStateCallback, DamageClientCallback, 0);
2006-11-26 11:13:41 -07:00
}
static int
FreeDamageExt(pointer value, XID did)
2006-11-26 11:13:41 -07:00
{
DamageExtPtr pDamageExt = (DamageExtPtr) value;
2006-11-26 11:13:41 -07:00
/*
* Get rid of the resource table entry hanging from the window id
*/
pDamageExt->id = 0;
if (WindowDrawable(pDamageExt->pDrawable->type))
FreeResourceByType(pDamageExt->pDrawable->id, DamageExtWinType, TRUE);
if (pDamageExt->pDamage) {
DamageUnregister(pDamageExt->pDrawable, pDamageExt->pDamage);
DamageDestroy(pDamageExt->pDamage);
2006-11-26 11:13:41 -07:00
}
free(pDamageExt);
2006-11-26 11:13:41 -07:00
return Success;
}
static int
FreeDamageExtWin(pointer value, XID wid)
2006-11-26 11:13:41 -07:00
{
DamageExtPtr pDamageExt = (DamageExtPtr) value;
2006-11-26 11:13:41 -07:00
if (pDamageExt->id)
FreeResource(pDamageExt->id, RT_NONE);
2006-11-26 11:13:41 -07:00
return Success;
}
2007-11-24 10:55:21 -07:00
static void
SDamageNotifyEvent(xDamageNotifyEvent * from, xDamageNotifyEvent * to)
2006-11-26 11:13:41 -07:00
{
to->type = from->type;
cpswaps(from->sequenceNumber, to->sequenceNumber);
cpswapl(from->drawable, to->drawable);
cpswapl(from->damage, to->damage);
cpswaps(from->area.x, to->area.x);
cpswaps(from->area.y, to->area.y);
cpswaps(from->area.width, to->area.width);
cpswaps(from->area.height, to->area.height);
cpswaps(from->geometry.x, to->geometry.x);
cpswaps(from->geometry.y, to->geometry.y);
cpswaps(from->geometry.width, to->geometry.width);
cpswaps(from->geometry.height, to->geometry.height);
2006-11-26 11:13:41 -07:00
}
void
DamageExtensionInit(void)
{
ExtensionEntry *extEntry;
int s;
2006-11-26 11:13:41 -07:00
for (s = 0; s < screenInfo.numScreens; s++)
DamageSetup(screenInfo.screens[s]);
2006-11-26 11:13:41 -07:00
DamageExtType = CreateNewResourceType(FreeDamageExt, "DamageExt");
2006-11-26 11:13:41 -07:00
if (!DamageExtType)
return;
2006-11-26 11:13:41 -07:00
DamageExtWinType = CreateNewResourceType(FreeDamageExtWin, "DamageExtWin");
2006-11-26 11:13:41 -07:00
if (!DamageExtWinType)
return;
if (!dixRegisterPrivateKey
(&DamageClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(DamageClientRec)))
return;
if (!AddCallback(&ClientStateCallback, DamageClientCallback, 0))
return;
if ((extEntry = AddExtension(DAMAGE_NAME, XDamageNumberEvents,
XDamageNumberErrors,
ProcDamageDispatch, SProcDamageDispatch,
DamageResetProc, StandardMinorOpcode)) != 0) {
DamageReqCode = (unsigned char) extEntry->base;
DamageEventBase = extEntry->eventBase;
EventSwapVector[DamageEventBase + XDamageNotify] =
(EventSwapPtr) SDamageNotifyEvent;
SetResourceTypeErrorValue(DamageExtType,
extEntry->errorBase + BadDamage);
2006-11-26 11:13:41 -07:00
}
}