From 8d89be29643e1e47d8296f08229af619f9b55f5b Mon Sep 17 00:00:00 2001 From: "Enrico Weigelt, metux IT consult" Date: Fri, 14 Mar 2025 13:40:44 +0100 Subject: [PATCH] dix: hook for intercepting window property calls This hook allows extensions to intercept client requests for changing window attributes. It can either change the parameters or skip the entire call (eg. handle all itself) so just the hook provided result code is returned to the client. Signed-off-by: Enrico Weigelt, metux IT consult --- dix/property.c | 159 +++++++++++++++++++++++++++++--------------- dix/property_priv.h | 30 +++++++++ 2 files changed, 135 insertions(+), 54 deletions(-) diff --git a/dix/property.c b/dix/property.c index eb51e662d..2b0368c92 100644 --- a/dix/property.c +++ b/dix/property.c @@ -152,6 +152,7 @@ no_panoramix: } CallbackListPtr PropertyStateCallback; +CallbackListPtr PropertyFilterCallback; static void deliverPropertyNotifyEvent(WindowPtr pWin, int state, PropertyPtr pProp) @@ -178,58 +179,71 @@ deliverPropertyNotifyEvent(WindowPtr pWin, int state, PropertyPtr pProp) int ProcRotateProperties(ClientPtr client) { - int i, j, delta, rc; + int delta, rc; REQUEST(xRotatePropertiesReq); - WindowPtr pWin; - Atom *atoms; PropertyPtr *props; /* array of pointer */ PropertyPtr pProp, saved; REQUEST_FIXED_SIZE(xRotatePropertiesReq, stuff->nAtoms << 2); UpdateCurrentTime(); - rc = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess); + + PropertyFilterParam p = { + .client = client, + .window = stuff->window, + .access_mode = DixWriteAccess, + .atoms = (Atom *) &stuff[1], + .nAtoms = stuff->nAtoms, + .nPositions = stuff->nPositions, + }; + + CallCallbacks(&PropertyFilterCallback, &p); + if (p.skip) + return p.status; + + WindowPtr pWin; + rc = dixLookupWindow(&pWin, p.window, p.client, DixSetPropAccess); if (rc != Success || stuff->nAtoms <= 0) return rc; - atoms = (Atom *) &stuff[1]; - props = calloc(stuff->nAtoms, sizeof(PropertyPtr)); - saved = calloc(stuff->nAtoms, sizeof(PropertyRec)); + props = calloc(p.nAtoms, sizeof(PropertyPtr)); + saved = calloc(p.nAtoms, sizeof(PropertyRec)); if (!props || !saved) { rc = BadAlloc; goto out; } - for (i = 0; i < stuff->nAtoms; i++) { - if (!ValidAtom(atoms[i])) { + for (int i = 0; i < p.nAtoms; i++) { + if (!ValidAtom(p.atoms[i])) { rc = BadAtom; - client->errorValue = atoms[i]; + client->errorValue = p.atoms[i]; goto out; } - for (j = i + 1; j < stuff->nAtoms; j++) - if (atoms[j] == atoms[i]) { + for (int j = i + 1; j < p.nAtoms; j++) + if (p.atoms[j] == p.atoms[i]) { rc = BadMatch; goto out; } - rc = dixLookupProperty(&pProp, pWin, atoms[i], client, + rc = dixLookupProperty(&pProp, pWin, p.atoms[i], p.client, DixReadAccess | DixWriteAccess); + if (rc != Success) goto out; props[i] = pProp; saved[i] = *pProp; } - delta = stuff->nPositions; + delta = p.nPositions; /* If the rotation is a complete 360 degrees, then moving the properties around and generating PropertyNotify events should be skipped. */ - if (abs(delta) % stuff->nAtoms) { + if (abs(delta) % p.nAtoms) { while (delta < 0) /* faster if abs value is small */ - delta += stuff->nAtoms; - for (i = 0; i < stuff->nAtoms; i++) { - j = (i + delta) % stuff->nAtoms; + delta += p.nAtoms; + for (int i = 0; i < p.nAtoms; i++) { + int j = (i + delta) % p.nAtoms; deliverPropertyNotifyEvent(pWin, PropertyNewValue, props[i]); notifyVRRMode(client, pWin, PropertyNewValue, props[i]); @@ -249,7 +263,6 @@ ProcRotateProperties(ClientPtr client) int ProcChangeProperty(ClientPtr client) { - WindowPtr pWin; char format, mode; unsigned long len; int sizeInBytes, err; @@ -277,9 +290,6 @@ ProcChangeProperty(ClientPtr client) totalSize = len * sizeInBytes; REQUEST_FIXED_SIZE(xChangePropertyReq, totalSize); - err = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess); - if (err != Success) - return err; if (!ValidAtom(stuff->property)) { client->errorValue = stuff->property; return BadAtom; @@ -289,13 +299,30 @@ ProcChangeProperty(ClientPtr client) return BadAtom; } - err = dixChangeWindowProperty(client, pWin, stuff->property, stuff->type, - (int) format, (int) mode, len, &stuff[1], - TRUE); + PropertyFilterParam p = { + .client = client, + .window = stuff->window, + .property = stuff->property, + .type = stuff->type, + .format = format, + .mode = mode, + .len = len, + .value = &stuff[1], + .sendevent = TRUE, + .access_mode = DixWriteAccess, + }; + + CallCallbacks(&PropertyFilterCallback, &p); + if (p.skip) + return p.status; + + WindowPtr pWin; + err = dixLookupWindow(&pWin, p.window, p.client, DixSetPropAccess); if (err != Success) return err; - else - return Success; + + return dixChangeWindowProperty(p.client, pWin, p.property, p.type, p.format, + p.mode, p.len, p.value, p.sendevent); } int @@ -482,20 +509,10 @@ ProcGetProperty(ClientPtr client) PropertyPtr pProp, prevProp; unsigned long n, len, ind; int rc; - WindowPtr pWin; Mask win_mode = DixGetPropAccess, prop_mode = DixReadAccess; REQUEST(xGetPropertyReq); - REQUEST_SIZE_MATCH(xGetPropertyReq); - if (stuff->delete) { - UpdateCurrentTime(); - win_mode |= DixSetPropAccess; - prop_mode |= DixDestroyAccess; - } - rc = dixLookupWindow(&pWin, stuff->window, client, win_mode); - if (rc != Success) - return rc; if (!ValidAtom(stuff->property)) { client->errorValue = stuff->property; @@ -510,7 +527,33 @@ ProcGetProperty(ClientPtr client) return BadAtom; } - rc = dixLookupProperty(&pProp, pWin, stuff->property, client, prop_mode); + PropertyFilterParam p = { + .client = client, + .window = stuff->window, + .property = stuff->property, + .type = stuff->type, + .delete = stuff->delete, + .access_mode = prop_mode, + .longOffset = stuff->longOffset, + .longLength = stuff->longLength, + }; + + CallCallbacks(&PropertyFilterCallback, &p); + if (p.skip) + return p.status; + + if (p.delete) { + UpdateCurrentTime(); + win_mode |= DixSetPropAccess; + prop_mode |= DixDestroyAccess; + } + + WindowPtr pWin; + rc = dixLookupWindow(&pWin, p.window, p.client, win_mode); + if (rc != Success) + return rc; + + rc = dixLookupProperty(&pProp, pWin, p.property, p.client, prop_mode); if (rc == BadMatch) { xGetPropertyReply rep = { .type = X_Reply, @@ -528,8 +571,7 @@ ProcGetProperty(ClientPtr client) /* If the request type and actual type don't match. Return the property information, but not the data. */ - if (((stuff->type != pProp->type) && (stuff->type != AnyPropertyType)) - ) { + if (((p.type != pProp->type) && (p.type != AnyPropertyType))) { xGetPropertyReply rep = { .type = X_Reply, .sequenceNumber = client->sequence, @@ -550,17 +592,17 @@ ProcGetProperty(ClientPtr client) * Return type, format, value to client */ n = (pProp->format / 8) * pProp->size; /* size (bytes) of prop */ - ind = stuff->longOffset << 2; + ind = p.longOffset << 2; /* If longOffset is invalid such that it causes "len" to be negative, it's a value error. */ if (n < ind) { - client->errorValue = stuff->longOffset; + client->errorValue = p.longOffset; return BadValue; } - len = min(n - ind, 4 * stuff->longLength); + len = min(n - ind, 4 * p.longLength); xGetPropertyReply rep = { .type = X_Reply, @@ -572,8 +614,7 @@ ProcGetProperty(ClientPtr client) .propertyType = pProp->type }; - if (stuff->delete && (rep.bytesAfter == 0)) - { + if (p.delete && (rep.bytesAfter == 0)) { deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp); notifyVRRMode(client, pWin, PropertyDelete, pProp); } @@ -583,7 +624,7 @@ ProcGetProperty(ClientPtr client) return BadAlloc; memcpy(payload, (char*)(pProp->data) + ind, len); - if (stuff->delete && (rep.bytesAfter == 0)) { + if (p.delete && (rep.bytesAfter == 0)) { /* Delete the Property */ if (pWin->properties == pProp) { /* Takes care of head */ @@ -679,20 +720,30 @@ ProcListProperties(ClientPtr client) int ProcDeleteProperty(ClientPtr client) { - WindowPtr pWin; - REQUEST(xDeletePropertyReq); - int result; - REQUEST_SIZE_MATCH(xDeletePropertyReq); + UpdateCurrentTime(); - result = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess); - if (result != Success) - return result; if (!ValidAtom(stuff->property)) { client->errorValue = stuff->property; return BadAtom; } - return DeleteProperty(client, pWin, stuff->property); + PropertyFilterParam p = { + .client = client, + .window = stuff->window, + .property = stuff->property, + .access_mode = DixRemoveAccess, + }; + + CallCallbacks(&PropertyFilterCallback, &p); + if (p.skip) + return p.status; + + WindowPtr pWin; + int result = dixLookupWindow(&pWin, p.window, p.client, DixSetPropAccess); + if (result != Success) + return result; + + return DeleteProperty(p.client, pWin, p.property); } diff --git a/dix/property_priv.h b/dix/property_priv.h index 38ad2da4b..c99baa9b7 100644 --- a/dix/property_priv.h +++ b/dix/property_priv.h @@ -63,7 +63,37 @@ typedef struct _PropertyStateRec { int state; } PropertyStateRec; +typedef struct _PropertyFilterParam { + // used by all requests + ClientPtr client; + Window window; + Atom property; + Atom type; + + // in case of RotateProperties + Atom *atoms; + size_t nAtoms; + size_t nPositions; + + // caller notification + Bool skip; // TRUE if the call shouldn't be executed + int status; // the status code to return when skip = TRUE + Mask access_mode; + + int format; + int mode; + unsigned long len; + const void *value; + Bool sendevent; + + // only for GetProperty + BOOL delete; + CARD32 longOffset; + CARD32 longLength; +} PropertyFilterParam; + extern CallbackListPtr PropertyStateCallback; +extern CallbackListPtr PropertyFilterCallback; int dixLookupProperty(PropertyPtr *result, WindowPtr pWin, Atom proprty, ClientPtr pClient, Mask access_mode);