/*
* 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
#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;
#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) {
.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++) {
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
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:
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
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)
{
if (pRepair) {
if (pParts)
RegionIntersect(pParts, DamageRegion(pDamage), pRepair);
- if (DamageSubtract(pDamage, pRepair))
+ if (DamageExtSubtract(pDamageExt, pRepair))
DamageExtReport(pDamage, DamageRegion(pDamage),
(void *) pDamageExt);
}
DamageEmpty(pDamage);
}
}
+
return Success;
}
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)
{
(EventSwapPtr) SDamageNotifyEvent;
SetResourceTypeErrorValue(DamageExtType,
extEntry->errorBase + BadDamage);
+#ifdef PANORAMIX
+ if (XRT_DAMAGE)
+ SetResourceTypeErrorValue(XRT_DAMAGE,
+ extEntry->errorBase + BadDamage);
+#endif
}
}