diff options
Diffstat (limited to 'damageext/damageext.c')
-rw-r--r-- | damageext/damageext.c | 387 |
1 files changed, 335 insertions, 52 deletions
diff --git a/damageext/damageext.c b/damageext/damageext.c index 9521c2676..d6469230d 100644 --- a/damageext/damageext.c +++ b/damageext/damageext.c @@ -1,5 +1,6 @@ /* * Copyright © 2002 Keith Packard + * Copyright 2013 Red Hat, Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -25,9 +26,24 @@ #endif #include "damageextint.h" +#include "damagestr.h" #include "protocol-versions.h" #include "extinit.h" +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" + +typedef struct { + DamageExtPtr ext; + DamagePtr damage[MAXSCREENS]; +} PanoramiXDamageRes; + +static RESTYPE XRT_DAMAGE; +static int (*PanoramiXSaveDamageCreate) (ClientPtr); + +#endif + static unsigned char DamageReqCode; static int DamageEventBase; static RESTYPE DamageExtType; @@ -37,13 +53,49 @@ static DevPrivateKeyRec DamageClientPrivateKeyRec; #define DamageClientPrivateKey (&DamageClientPrivateKeyRec) static void +DamageNoteCritical(ClientPtr pClient) +{ + DamageClientPtr pDamageClient = GetDamageClient(pClient); + + /* Composite extension marks clients with manual Subwindows as critical */ + if (pDamageClient->critical > 0) { + SetCriticalOutputPending(); + pClient->smart_priority = SMART_MAX_PRIORITY; + } +} + +static void +damageGetGeometry(DrawablePtr draw, int *x, int *y, int *w, int *h) +{ +#ifdef PANORAMIX + if (!noPanoramiXExtension && draw->type == DRAWABLE_WINDOW) { + WindowPtr win = (WindowPtr)draw; + + if (!win->parent) { + *x = screenInfo.x; + *y = screenInfo.y; + *w = screenInfo.width; + *h = screenInfo.height; + return; + } + } +#endif + + *x = draw->x; + *y = draw->y; + *w = draw->width; + *h = draw->height; +} + +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; + int i, x, y, w, h; + + damageGetGeometry(pDrawable, &x, &y, &w, &h); UpdateCurrentTimeIf(); ev = (xDamageNotifyEvent) { @@ -52,10 +104,10 @@ DamageExtNotify(DamageExtPtr pDamageExt, BoxPtr pBoxes, int nBoxes) .drawable = pDamageExt->drawable, .damage = pDamageExt->id, .timestamp = currentTime.milliseconds, - .geometry.x = pDrawable->x, - .geometry.y = pDrawable->y, - .geometry.width = pDrawable->width, - .geometry.height = pDrawable->height + .geometry.x = x, + .geometry.y = y, + .geometry.width = w, + .geometry.height = h }; if (pBoxes) { for (i = 0; i < nBoxes; i++) { @@ -72,15 +124,12 @@ DamageExtNotify(DamageExtPtr pDamageExt, BoxPtr pBoxes, int nBoxes) else { ev.area.x = 0; ev.area.y = 0; - ev.area.width = pDrawable->width; - ev.area.height = pDrawable->height; + ev.area.width = w; + ev.area.height = h; WriteEventsToClient(pClient, 1, (xEvent *) &ev); } - /* Composite extension marks clients with manual Subwindows as critical */ - if (pDamageClient->critical > 0) { - SetCriticalOutputPending(); - pClient->smart_priority = SMART_MAX_PRIORITY; - } + + DamageNoteCritical(pClient); } static void @@ -162,23 +211,62 @@ ProcDamageQueryVersion(ClientPtr client) return Success; } -static int -ProcDamageCreate(ClientPtr client) +static void +DamageExtRegister(DrawablePtr pDrawable, DamagePtr pDamage, Bool report) +{ + DamageSetReportAfterOp(pDamage, TRUE); + DamageRegister(pDrawable, pDamage); + + if (report) { + RegionPtr pRegion = &((WindowPtr) pDrawable)->borderClip; + RegionTranslate(pRegion, -pDrawable->x, -pDrawable->y); + DamageReportDamage(pDamage, pRegion); + RegionTranslate(pRegion, pDrawable->x, pDrawable->y); + } +} + +static DamageExtPtr +DamageExtCreate(DrawablePtr pDrawable, DamageReportLevel level, + ClientPtr client, XID id, XID drawable) +{ + DamageExtPtr pDamageExt = malloc(sizeof(DamageExtRec)); + if (!pDamageExt) + return NULL; + + pDamageExt->id = id; + pDamageExt->drawable = drawable; + 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 NULL; + } + + if (!AddResource(id, DamageExtType, (pointer) pDamageExt)) + return NULL; + + DamageExtRegister(pDrawable, pDamageExt->pDamage, + pDrawable->type == DRAWABLE_WINDOW); + + return pDamageExt; +} + +static DamageExtPtr +doDamageCreate(ClientPtr client, int *rc) { DrawablePtr pDrawable; DamageExtPtr pDamageExt; DamageReportLevel level; - RegionPtr pRegion; - int rc; REQUEST(xDamageCreateReq); - REQUEST_SIZE_MATCH(xDamageCreateReq); - LEGAL_NEW_RESOURCE(stuff->damage, client); - rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, - DixGetAttrAccess | DixReadAccess); - if (rc != Success) - return rc; + *rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, + DixGetAttrAccess | DixReadAccess); + if (*rc != Success) + return NULL; switch (stuff->level) { case XDamageReportRawRectangles: @@ -195,39 +283,27 @@ ProcDamageCreate(ClientPtr client) break; default: client->errorValue = stuff->level; - return BadValue; + *rc = BadValue; + return NULL; } - pDamageExt = malloc(sizeof(DamageExtRec)); + pDamageExt = DamageExtCreate(pDrawable, level, client, stuff->damage, + stuff->drawable); if (!pDamageExt) - return BadAlloc; - pDamageExt->id = stuff->damage; - pDamageExt->drawable = stuff->drawable; - 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; - } - if (!AddResource(stuff->damage, DamageExtType, (pointer) pDamageExt)) - return BadAlloc; - - DamageSetReportAfterOp(pDamageExt->pDamage, TRUE); - DamageRegister(pDamageExt->pDrawable, pDamageExt->pDamage); + *rc = BadAlloc; - if (pDrawable->type == DRAWABLE_WINDOW) { - pRegion = &((WindowPtr) pDrawable)->borderClip; - RegionTranslate(pRegion, -pDrawable->x, -pDrawable->y); - DamageReportDamage(pDamageExt->pDamage, pRegion); - RegionTranslate(pRegion, pDrawable->x, pDrawable->y); - } + return pDamageExt; +} - return Success; +static int +ProcDamageCreate(ClientPtr client) +{ + int rc; + REQUEST(xDamageCreateReq); + REQUEST_SIZE_MATCH(xDamageCreateReq); + LEGAL_NEW_RESOURCE(stuff->damage, client); + doDamageCreate(client, &rc); + return rc; } static int @@ -242,6 +318,88 @@ ProcDamageDestroy(ClientPtr client) return Success; } +#ifdef PANORAMIX +static RegionPtr +DamageExtSubtractWindowClip(DamageExtPtr pDamageExt) +{ + WindowPtr win = (WindowPtr)pDamageExt->pDrawable; + PanoramiXRes *res = NULL; + RegionPtr ret; + int i; + + if (!win->parent) + return &PanoramiXScreenRegion; + + dixLookupResourceByType((void **)&res, win->drawable.id, XRT_WINDOW, + serverClient, DixReadAccess); + if (!res) + return NULL; + + ret = RegionCreate(NULL, 0); + if (!ret) + return NULL; + + FOR_NSCREENS_FORWARD(i) { + ScreenPtr screen; + if (Success != dixLookupWindow(&win, res->info[i].id, serverClient, + DixReadAccess)) + goto out; + + screen = win->drawable.pScreen; + + RegionTranslate(ret, -screen->x, -screen->y); + if (!RegionUnion(ret, ret, &win->borderClip)) + goto out; + RegionTranslate(ret, screen->x, screen->y); + } + + return ret; + +out: + RegionDestroy(ret); + return NULL; +} + +static void +DamageExtFreeWindowClip(RegionPtr reg) +{ + if (reg != &PanoramiXScreenRegion) + RegionDestroy(reg); +} +#endif + +/* + * DamageSubtract intersects with borderClip, so we must reconstruct the + * protocol's perspective of same... + */ +static Bool +DamageExtSubtract(DamageExtPtr pDamageExt, const RegionPtr pRegion) +{ + DamagePtr pDamage = pDamageExt->pDamage; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + RegionPtr damage = DamageRegion(pDamage); + RegionSubtract(damage, damage, pRegion); + + if (pDamageExt->pDrawable->type == DRAWABLE_WINDOW) { + DrawablePtr pDraw = pDamageExt->pDrawable; + RegionPtr clip = DamageExtSubtractWindowClip(pDamageExt); + if (clip) { + RegionTranslate(clip, -pDraw->x, -pDraw->y); + RegionIntersect(damage, damage, clip); + RegionTranslate(clip, pDraw->x, pDraw->y); + DamageExtFreeWindowClip(clip); + } + } + + return RegionNotEmpty(damage); + } +#endif + + return DamageSubtract(pDamage, pRegion); +} + static int ProcDamageSubtract(ClientPtr client) { @@ -261,7 +419,7 @@ ProcDamageSubtract(ClientPtr client) if (pRepair) { if (pParts) RegionIntersect(pParts, DamageRegion(pDamage), pRepair); - if (DamageSubtract(pDamage, pRepair)) + if (DamageExtSubtract(pDamageExt, pRepair)) DamageExtReport(pDamage, DamageRegion(pDamage), (void *) pDamageExt); } @@ -271,6 +429,7 @@ ProcDamageSubtract(ClientPtr client) DamageEmpty(pDamage); } } + return Success; } @@ -460,6 +619,125 @@ SDamageNotifyEvent(xDamageNotifyEvent * from, xDamageNotifyEvent * to) cpswaps(from->geometry.height, to->geometry.height); } +#ifdef PANORAMIX + +static void +PanoramiXDamageReport(DamagePtr pDamage, RegionPtr pRegion, void *closure) +{ + PanoramiXDamageRes *res = closure; + DamageExtPtr pDamageExt = res->ext; + WindowPtr pWin = (WindowPtr)pDamage->pDrawable; + ScreenPtr pScreen = pDamage->pScreen; + + /* happens on unmap? sigh xinerama */ + if (RegionNil(pRegion)) + return; + + /* translate root windows if necessary */ + if (!pWin->parent) + RegionTranslate(pRegion, pScreen->x, pScreen->y); + + /* add our damage to the protocol view */ + DamageReportDamage(pDamageExt->pDamage, pRegion); + + /* empty our view */ + DamageEmpty(pDamage); +} + +static void +PanoramiXDamageExtDestroy(DamagePtr pDamage, void *closure) +{ + PanoramiXDamageRes *damage = closure; + damage->damage[pDamage->pScreen->myNum] = NULL; +} + +static int +PanoramiXDamageCreate(ClientPtr client) +{ + PanoramiXDamageRes *damage; + PanoramiXRes *draw; + int i, rc; + + REQUEST(xDamageCreateReq); + + REQUEST_SIZE_MATCH(xDamageCreateReq); + LEGAL_NEW_RESOURCE(stuff->damage, client); + rc = dixLookupResourceByClass((void **)&draw, stuff->drawable, XRC_DRAWABLE, + client, DixGetAttrAccess | DixReadAccess); + if (rc != Success) + return rc; + + if (!(damage = calloc(1, sizeof(PanoramiXDamageRes)))) + return BadAlloc; + + if (!AddResource(stuff->damage, XRT_DAMAGE, damage)) + return BadAlloc; + + damage->ext = doDamageCreate(client, &rc); + if (rc == Success && draw->type == XRT_WINDOW) { + FOR_NSCREENS_FORWARD(i) { + DrawablePtr pDrawable; + DamagePtr pDamage = DamageCreate(PanoramiXDamageReport, + PanoramiXDamageExtDestroy, + DamageReportRawRegion, + FALSE, + screenInfo.screens[i], + damage); + if (!pDamage) { + rc = BadAlloc; + } else { + damage->damage[i] = pDamage; + rc = dixLookupDrawable(&pDrawable, draw->info[i].id, client, + M_WINDOW, + DixGetAttrAccess | DixReadAccess); + } + if (rc != Success) + break; + + DamageExtRegister(pDrawable, pDamage, i != 0); + } + } + + if (rc != Success) + FreeResource(stuff->damage, RT_NONE); + + return rc; +} + +static int +PanoramiXDamageDelete(void *res, XID id) +{ + int i; + PanoramiXDamageRes *damage = res; + + FOR_NSCREENS_BACKWARD(i) { + if (damage->damage[i]) { + DamageDestroy(damage->damage[i]); + damage->damage[i] = NULL; + } + } + + free(damage); + return 1; +} + +void +PanoramiXDamageInit(void) +{ + XRT_DAMAGE = CreateNewResourceType(PanoramiXDamageDelete, "XineramaDamage"); + + PanoramiXSaveDamageCreate = ProcDamageVector[X_DamageCreate]; + ProcDamageVector[X_DamageCreate] = PanoramiXDamageCreate; +} + +void +PanoramiXDamageReset(void) +{ + ProcDamageVector[X_DamageCreate] = PanoramiXSaveDamageCreate; +} + +#endif /* PANORAMIX */ + void DamageExtensionInit(void) { @@ -490,5 +768,10 @@ DamageExtensionInit(void) (EventSwapPtr) SDamageNotifyEvent; SetResourceTypeErrorValue(DamageExtType, extEntry->errorBase + BadDamage); +#ifdef PANORAMIX + if (XRT_DAMAGE) + SetResourceTypeErrorValue(XRT_DAMAGE, + extEntry->errorBase + BadDamage); +#endif } } |