/* * $Id: damageext.c,v 1.1 2006/11/26 18:14:42 matthieu Exp $ * * 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 #endif #include "damageextint.h" unsigned char DamageReqCode; int DamageEventBase; int DamageErrorBase; int DamageClientPrivateIndex; RESTYPE DamageExtType; RESTYPE DamageExtWinType; #define prScreen screenInfo.screens[0] static void DamageExtNotify (DamageExtPtr pDamageExt, BoxPtr pBoxes, int nBoxes) { ClientPtr pClient = pDamageExt->pClient; DamageClientPtr pDamageClient = GetDamageClient (pClient); DrawablePtr pDrawable = pDamageExt->pDrawable; xDamageNotifyEvent ev; int i; UpdateCurrentTimeIf (); ev.type = DamageEventBase + XDamageNotify; ev.level = pDamageExt->level; ev.sequenceNumber = pClient->sequence; ev.drawable = pDrawable->id; 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; if (!pClient->clientGone) WriteEventsToClient (pClient, 1, (xEvent *) &ev); } } else { ev.area.x = 0; ev.area.y = 0; ev.area.width = pDrawable->width; ev.area.height = pDrawable->height; if (!pClient->clientGone) WriteEventsToClient (pClient, 1, (xEvent *) &ev); } /* Composite extension marks clients with manual Subwindows as critical */ if (pDamageClient->critical > 0) { SetCriticalOutputPending (); #ifdef SMART_SCHEDULE pClient->smart_priority = SMART_MAX_PRIORITY; #endif } } static void DamageExtReport (DamagePtr pDamage, RegionPtr pRegion, void *closure) { DamageExtPtr pDamageExt = closure; switch (pDamageExt->level) { case DamageReportRawRegion: case DamageReportDeltaRegion: DamageExtNotify (pDamageExt, REGION_RECTS(pRegion), REGION_NUM_RECTS(pRegion)); break; case DamageReportBoundingBox: DamageExtNotify (pDamageExt, REGION_EXTENTS(prScreen, pRegion), 1); break; case DamageReportNonEmpty: DamageExtNotify (pDamageExt, NullBox, 0); break; case DamageReportNone: break; } } static void DamageExtDestroy (DamagePtr pDamage, void *closure) { DamageExtPtr pDamageExt = closure; pDamageExt->pDamage = 0; if (pDamageExt->id) FreeResource (pDamageExt->id, RT_NONE); } void DamageExtSetCritical (ClientPtr pClient, Bool critical) { DamageClientPtr pDamageClient = GetDamageClient (pClient); if (pDamageClient) pDamageClient->critical += critical ? 1 : -1; } static int ProcDamageQueryVersion(ClientPtr client) { DamageClientPtr pDamageClient = GetDamageClient (client); xDamageQueryVersionReply rep; register int n; REQUEST(xDamageQueryVersionReq); REQUEST_SIZE_MATCH(xDamageQueryVersionReq); rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; if (stuff->majorVersion < DAMAGE_MAJOR) { rep.majorVersion = stuff->majorVersion; rep.minorVersion = stuff->minorVersion; } else { rep.majorVersion = DAMAGE_MAJOR; if (stuff->majorVersion == DAMAGE_MAJOR && stuff->minorVersion < DAMAGE_MINOR) rep.minorVersion = stuff->minorVersion; else rep.minorVersion = DAMAGE_MINOR; } pDamageClient->major_version = rep.majorVersion; pDamageClient->minor_version = rep.minorVersion; if (client->swapped) { swaps(&rep.sequenceNumber, n); swapl(&rep.length, n); swapl(&rep.majorVersion, n); swapl(&rep.minorVersion, n); } WriteToClient(client, sizeof(xDamageQueryVersionReply), (char *)&rep); return(client->noClientException); } static int ProcDamageCreate (ClientPtr client) { DrawablePtr pDrawable; DamageExtPtr pDamageExt; DamageReportLevel level; RegionPtr pRegion; REQUEST(xDamageCreateReq); REQUEST_SIZE_MATCH(xDamageCreateReq); LEGAL_NEW_RESOURCE(stuff->damage, client); SECURITY_VERIFY_DRAWABLE (pDrawable, stuff->drawable, client, SecurityReadAccess); switch (stuff->level) { case XDamageReportRawRectangles: level = DamageReportRawRegion; break; case XDamageReportDeltaRectangles: level = DamageReportDeltaRegion; break; case XDamageReportBoundingBox: level = DamageReportBoundingBox; break; case XDamageReportNonEmpty: level = DamageReportNonEmpty; break; default: client->errorValue = stuff->level; return BadValue; } pDamageExt = xalloc (sizeof (DamageExtRec)); if (!pDamageExt) return BadAlloc; pDamageExt->id = stuff->damage; pDamageExt->pDrawable = pDrawable; pDamageExt->level = level; pDamageExt->pClient = client; pDamageExt->pDamage = DamageCreate (DamageExtReport, DamageExtDestroy, level, FALSE, pDrawable->pScreen, pDamageExt); if (!pDamageExt->pDamage) { xfree (pDamageExt); return BadAlloc; } if (!AddResource (stuff->damage, DamageExtType, (pointer) pDamageExt)) return BadAlloc; DamageRegister (pDamageExt->pDrawable, pDamageExt->pDamage); if (pDrawable->type == DRAWABLE_WINDOW) { pRegion = &((WindowPtr) pDrawable)->borderClip; DamageDamageRegion (pDrawable, pRegion); } return (client->noClientException); } static int ProcDamageDestroy (ClientPtr client) { REQUEST(xDamageDestroyReq); DamageExtPtr pDamageExt; REQUEST_SIZE_MATCH(xDamageDestroyReq); VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, SecurityWriteAccess); FreeResource (stuff->damage, RT_NONE); return (client->noClientException); } static int ProcDamageSubtract (ClientPtr client) { REQUEST(xDamageSubtractReq); DamageExtPtr pDamageExt; RegionPtr pRepair; RegionPtr pParts; REQUEST_SIZE_MATCH(xDamageSubtractReq); VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, SecurityWriteAccess); VERIFY_REGION_OR_NONE(pRepair, stuff->repair, client, SecurityWriteAccess); VERIFY_REGION_OR_NONE(pParts, stuff->parts, client, SecurityWriteAccess); if (pDamageExt->level != DamageReportRawRegion) { DamagePtr pDamage = pDamageExt->pDamage; if (pRepair) { if (pParts) REGION_INTERSECT (prScreen, pParts, DamageRegion (pDamage), pRepair); if (DamageSubtract (pDamage, pRepair)) DamageExtReport (pDamage, DamageRegion (pDamage), (void *) pDamageExt); } else { if (pParts) REGION_COPY (prScreen, pParts, DamageRegion (pDamage)); DamageEmpty (pDamage); } } return (client->noClientException); } /* Major version controls available requests */ static const int version_requests[] = { X_DamageQueryVersion, /* before client sends QueryVersion */ X_DamageSubtract, /* Version 1 */ }; #define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0])) int (*ProcDamageVector[XDamageNumberRequests])(ClientPtr) = { /*************** Version 1 ******************/ ProcDamageQueryVersion, ProcDamageCreate, ProcDamageDestroy, ProcDamageSubtract, }; static int ProcDamageDispatch (ClientPtr client) { REQUEST(xDamageReq); DamageClientPtr pDamageClient = GetDamageClient (client); if (pDamageClient->major_version >= NUM_VERSION_REQUESTS) return BadRequest; if (stuff->damageReqType > version_requests[pDamageClient->major_version]) return BadRequest; return (*ProcDamageVector[stuff->damageReqType]) (client); } static int SProcDamageQueryVersion(ClientPtr client) { register int n; REQUEST(xDamageQueryVersionReq); swaps(&stuff->length, n); REQUEST_SIZE_MATCH(xDamageQueryVersionReq); swapl(&stuff->majorVersion, n); swapl(&stuff->minorVersion, n); return (*ProcDamageVector[stuff->damageReqType]) (client); } static int SProcDamageCreate (ClientPtr client) { register int n; REQUEST(xDamageCreateReq); swaps (&stuff->length, n); REQUEST_SIZE_MATCH(xDamageCreateReq); swapl (&stuff->damage, n); swapl (&stuff->drawable, n); return (*ProcDamageVector[stuff->damageReqType]) (client); } static int SProcDamageDestroy (ClientPtr client) { register int n; REQUEST(xDamageDestroyReq); swaps (&stuff->length, n); REQUEST_SIZE_MATCH(xDamageDestroyReq); swapl (&stuff->damage, n); return (*ProcDamageVector[stuff->damageReqType]) (client); } static int SProcDamageSubtract (ClientPtr client) { register int n; REQUEST(xDamageSubtractReq); swaps (&stuff->length, n); REQUEST_SIZE_MATCH(xDamageSubtractReq); swapl (&stuff->damage, n); swapl (&stuff->repair, n); swapl (&stuff->parts, n); return (*ProcDamageVector[stuff->damageReqType]) (client); } int (*SProcDamageVector[XDamageNumberRequests])(ClientPtr) = { /*************** Version 1 ******************/ SProcDamageQueryVersion, SProcDamageCreate, SProcDamageDestroy, SProcDamageSubtract, }; static int SProcDamageDispatch (ClientPtr client) { REQUEST(xDamageReq); if (stuff->damageReqType >= XDamageNumberRequests) return BadRequest; return (*SProcDamageVector[stuff->damageReqType]) (client); } static void DamageClientCallback (CallbackListPtr *list, pointer closure, pointer data) { NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; ClientPtr pClient = clientinfo->client; DamageClientPtr pDamageClient = GetDamageClient (pClient); pDamageClient->critical = 0; pDamageClient->major_version = 0; pDamageClient->minor_version = 0; } /*ARGSUSED*/ static void DamageResetProc (ExtensionEntry *extEntry) { DeleteCallback (&ClientStateCallback, DamageClientCallback, 0); } static int FreeDamageExt (pointer value, XID did) { DamageExtPtr pDamageExt = (DamageExtPtr) value; /* * 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); } xfree (pDamageExt); return Success; } static int FreeDamageExtWin (pointer value, XID wid) { DamageExtPtr pDamageExt = (DamageExtPtr) value; if (pDamageExt->id) FreeResource (pDamageExt->id, RT_NONE); return Success; } void SDamageNotifyEvent (xDamageNotifyEvent *from, xDamageNotifyEvent *to) { 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); } void DamageExtensionInit(void) { ExtensionEntry *extEntry; int s; for (s = 0; s < screenInfo.numScreens; s++) DamageSetup (screenInfo.screens[s]); DamageExtType = CreateNewResourceType (FreeDamageExt); if (!DamageExtType) return; DamageExtWinType = CreateNewResourceType (FreeDamageExtWin); if (!DamageExtWinType) return; DamageClientPrivateIndex = AllocateClientPrivateIndex (); if (!AllocateClientPrivate (DamageClientPrivateIndex, 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; DamageErrorBase = extEntry->errorBase; EventSwapVector[DamageEventBase + XDamageNotify] = (EventSwapPtr) SDamageNotifyEvent; } }