diff options
Diffstat (limited to 'randr/rrproviderproperty.c')
-rw-r--r-- | randr/rrproviderproperty.c | 716 |
1 files changed, 716 insertions, 0 deletions
diff --git a/randr/rrproviderproperty.c b/randr/rrproviderproperty.c new file mode 100644 index 000000000..5e04fab8f --- /dev/null +++ b/randr/rrproviderproperty.c @@ -0,0 +1,716 @@ +/* + * Copyright © 2006 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 the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS 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. + */ + +#include "randrstr.h" +#include "propertyst.h" +#include "swaprep.h" + +static int +DeliverPropertyEvent(WindowPtr pWin, void *value) +{ + xRRProviderPropertyNotifyEvent *event = value; + RREventPtr *pHead, pRREvent; + + dixLookupResourceByType((pointer *) &pHead, pWin->drawable.id, + RREventType, serverClient, DixReadAccess); + if (!pHead) + return WT_WALKCHILDREN; + + for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) { + if (!(pRREvent->mask & RRProviderPropertyNotifyMask)) + continue; + + event->window = pRREvent->window->drawable.id; + WriteEventsToClient(pRREvent->client, 1, (xEvent *) event); + } + + return WT_WALKCHILDREN; +} + +static void +RRDeliverPropertyEvent(ScreenPtr pScreen, xEvent *event) +{ + if (!(dispatchException & (DE_RESET | DE_TERMINATE))) + WalkTree(pScreen, DeliverPropertyEvent, event); +} + +static void +RRDestroyProviderProperty(RRPropertyPtr prop) +{ + free(prop->valid_values); + free(prop->current.data); + free(prop->pending.data); + free(prop); +} + +static void +RRDeleteProperty(RRProviderRec * provider, RRPropertyRec * prop) +{ + xRRProviderPropertyNotifyEvent event; + + event.type = RREventBase + RRNotify; + event.subCode = RRNotify_ProviderProperty; + event.provider = provider->id; + event.state = PropertyDelete; + event.atom = prop->propertyName; + event.timestamp = currentTime.milliseconds; + + RRDeliverPropertyEvent(provider->pScreen, (xEvent *) &event); + + RRDestroyProviderProperty(prop); +} + +void +RRDeleteAllProviderProperties(RRProviderPtr provider) +{ + RRPropertyPtr prop, next; + + for (prop = provider->properties; prop; prop = next) { + next = prop->next; + RRDeleteProperty(provider, prop); + } +} + +static void +RRInitProviderPropertyValue(RRPropertyValuePtr property_value) +{ + property_value->type = None; + property_value->format = 0; + property_value->size = 0; + property_value->data = NULL; +} + +static RRPropertyPtr +RRCreateProviderProperty(Atom property) +{ + RRPropertyPtr prop; + + prop = (RRPropertyPtr) malloc(sizeof(RRPropertyRec)); + if (!prop) + return NULL; + prop->next = NULL; + prop->propertyName = property; + prop->is_pending = FALSE; + prop->range = FALSE; + prop->immutable = FALSE; + prop->num_valid = 0; + prop->valid_values = NULL; + RRInitProviderPropertyValue(&prop->current); + RRInitProviderPropertyValue(&prop->pending); + return prop; +} + +void +RRDeleteProviderProperty(RRProviderPtr provider, Atom property) +{ + RRPropertyRec *prop, **prev; + + for (prev = &provider->properties; (prop = *prev); prev = &(prop->next)) + if (prop->propertyName == property) { + *prev = prop->next; + RRDeleteProperty(provider, prop); + return; + } +} + +int +RRChangeProviderProperty(RRProviderPtr provider, Atom property, Atom type, + int format, int mode, unsigned long len, + pointer value, Bool sendevent, Bool pending) +{ + RRPropertyPtr prop; + xRRProviderPropertyNotifyEvent event; + rrScrPrivPtr pScrPriv = rrGetScrPriv(provider->pScreen); + int size_in_bytes; + int total_size; + unsigned long total_len; + RRPropertyValuePtr prop_value; + RRPropertyValueRec new_value; + Bool add = FALSE; + + size_in_bytes = format >> 3; + + /* first see if property already exists */ + prop = RRQueryProviderProperty(provider, property); + if (!prop) { /* just add to list */ + prop = RRCreateProviderProperty(property); + if (!prop) + return BadAlloc; + add = TRUE; + mode = PropModeReplace; + } + if (pending && prop->is_pending) + prop_value = &prop->pending; + else + prop_value = &prop->current; + + /* To append or prepend to a property the request format and type + must match those of the already defined property. The + existing format and type are irrelevant when using the mode + "PropModeReplace" since they will be written over. */ + + if ((format != prop_value->format) && (mode != PropModeReplace)) + return BadMatch; + if ((prop_value->type != type) && (mode != PropModeReplace)) + return BadMatch; + new_value = *prop_value; + if (mode == PropModeReplace) + total_len = len; + else + total_len = prop_value->size + len; + + if (mode == PropModeReplace || len > 0) { + pointer new_data = NULL, old_data = NULL; + + total_size = total_len * size_in_bytes; + new_value.data = (pointer) malloc(total_size); + if (!new_value.data && total_size) { + if (add) + RRDestroyProviderProperty(prop); + return BadAlloc; + } + new_value.size = len; + new_value.type = type; + new_value.format = format; + + switch (mode) { + case PropModeReplace: + new_data = new_value.data; + old_data = NULL; + break; + case PropModeAppend: + new_data = (pointer) (((char *) new_value.data) + + (prop_value->size * size_in_bytes)); + old_data = new_value.data; + break; + case PropModePrepend: + new_data = new_value.data; + old_data = (pointer) (((char *) new_value.data) + + (prop_value->size * size_in_bytes)); + break; + } + if (new_data) + memcpy((char *) new_data, (char *) value, len * size_in_bytes); + if (old_data) + memcpy((char *) old_data, (char *) prop_value->data, + prop_value->size * size_in_bytes); + + if (pending && pScrPriv->rrProviderSetProperty && + !pScrPriv->rrProviderSetProperty(provider->pScreen, provider, + prop->propertyName, &new_value)) { + free(new_value.data); + return BadValue; + } + free(prop_value->data); + *prop_value = new_value; + } + + else if (len == 0) { + /* do nothing */ + } + + if (add) { + prop->next = provider->properties; + provider->properties = prop; + } + + if (pending && prop->is_pending) + provider->pendingProperties = TRUE; + + if (sendevent) { + event.type = RREventBase + RRNotify; + event.subCode = RRNotify_ProviderProperty; + event.provider = provider->id; + event.state = PropertyNewValue; + event.atom = prop->propertyName; + event.timestamp = currentTime.milliseconds; + RRDeliverPropertyEvent(provider->pScreen, (xEvent *) &event); + } + return Success; +} + +Bool +RRPostProviderPendingProperties(RRProviderPtr provider) +{ + RRPropertyValuePtr pending_value; + RRPropertyValuePtr current_value; + RRPropertyPtr property; + Bool ret = TRUE; + + if (!provider->pendingProperties) + return TRUE; + + provider->pendingProperties = FALSE; + for (property = provider->properties; property; property = property->next) { + /* Skip non-pending properties */ + if (!property->is_pending) + continue; + + pending_value = &property->pending; + current_value = &property->current; + + /* + * If the pending and current values are equal, don't mark it + * as changed (which would deliver an event) + */ + if (pending_value->type == current_value->type && + pending_value->format == current_value->format && + pending_value->size == current_value->size && + !memcmp(pending_value->data, current_value->data, + pending_value->size * (pending_value->format / 8))) + continue; + + if (RRChangeProviderProperty(provider, property->propertyName, + pending_value->type, pending_value->format, + PropModeReplace, pending_value->size, + pending_value->data, TRUE, FALSE) != Success) + ret = FALSE; + } + return ret; +} + +RRPropertyPtr +RRQueryProviderProperty(RRProviderPtr provider, Atom property) +{ + RRPropertyPtr prop; + + for (prop = provider->properties; prop; prop = prop->next) + if (prop->propertyName == property) + return prop; + return NULL; +} + +RRPropertyValuePtr +RRGetProviderProperty(RRProviderPtr provider, Atom property, Bool pending) +{ + RRPropertyPtr prop = RRQueryProviderProperty(provider, property); + rrScrPrivPtr pScrPriv = rrGetScrPriv(provider->pScreen); + + if (!prop) + return NULL; + if (pending && prop->is_pending) + return &prop->pending; + else { +#if RANDR_13_INTERFACE + /* If we can, try to update the property value first */ + if (pScrPriv->rrProviderGetProperty) + pScrPriv->rrProviderGetProperty(provider->pScreen, provider, + prop->propertyName); +#endif + return &prop->current; + } +} + +int +RRConfigureProviderProperty(RRProviderPtr provider, Atom property, + Bool pending, Bool range, Bool immutable, + int num_values, INT32 *values) +{ + RRPropertyPtr prop = RRQueryProviderProperty(provider, property); + Bool add = FALSE; + INT32 *new_values; + + if (!prop) { + prop = RRCreateProviderProperty(property); + if (!prop) + return BadAlloc; + add = TRUE; + } + else if (prop->immutable && !immutable) + return BadAccess; + + /* + * ranges must have even number of values + */ + if (range && (num_values & 1)) + return BadMatch; + + new_values = malloc(num_values * sizeof(INT32)); + if (!new_values && num_values) + return BadAlloc; + if (num_values) + memcpy(new_values, values, num_values * sizeof(INT32)); + + /* + * Property moving from pending to non-pending + * loses any pending values + */ + if (prop->is_pending && !pending) { + free(prop->pending.data); + RRInitProviderPropertyValue(&prop->pending); + } + + prop->is_pending = pending; + prop->range = range; + prop->immutable = immutable; + prop->num_valid = num_values; + free(prop->valid_values); + prop->valid_values = new_values; + + if (add) { + prop->next = provider->properties; + provider->properties = prop; + } + + return Success; +} + +int +ProcRRListProviderProperties(ClientPtr client) +{ + REQUEST(xRRListProviderPropertiesReq); + Atom *pAtoms = NULL, *temppAtoms; + xRRListProviderPropertiesReply rep; + int numProps = 0; + RRProviderPtr provider; + RRPropertyPtr prop; + + REQUEST_SIZE_MATCH(xRRListProviderPropertiesReq); + + VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); + + for (prop = provider->properties; prop; prop = prop->next) + numProps++; + if (numProps) + if (!(pAtoms = (Atom *) malloc(numProps * sizeof(Atom)))) + return BadAlloc; + + rep.type = X_Reply; + rep.length = bytes_to_int32(numProps * sizeof(Atom)); + rep.sequenceNumber = client->sequence; + rep.nAtoms = numProps; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swaps(&rep.nAtoms); + } + temppAtoms = pAtoms; + for (prop = provider->properties; prop; prop = prop->next) + *temppAtoms++ = prop->propertyName; + + WriteToClient(client, sizeof(xRRListProviderPropertiesReply), (char *) &rep); + if (numProps) { + client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; + WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms); + free(pAtoms); + } + return Success; +} + +int +ProcRRQueryProviderProperty(ClientPtr client) +{ + REQUEST(xRRQueryProviderPropertyReq); + xRRQueryProviderPropertyReply rep; + RRProviderPtr provider; + RRPropertyPtr prop; + char *extra = NULL; + + REQUEST_SIZE_MATCH(xRRQueryProviderPropertyReq); + + VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); + + prop = RRQueryProviderProperty(provider, stuff->property); + if (!prop) + return BadName; + + if (prop->num_valid) { + extra = malloc(prop->num_valid * sizeof(INT32)); + if (!extra) + return BadAlloc; + } + rep.type = X_Reply; + rep.length = prop->num_valid; + rep.sequenceNumber = client->sequence; + rep.pending = prop->is_pending; + rep.range = prop->range; + rep.immutable = prop->immutable; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + } + WriteToClient(client, sizeof(xRRQueryProviderPropertyReply), (char *) &rep); + if (prop->num_valid) { + memcpy(extra, prop->valid_values, prop->num_valid * sizeof(INT32)); + client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; + WriteSwappedDataToClient(client, prop->num_valid * sizeof(INT32), + extra); + free(extra); + } + return Success; +} + +int +ProcRRConfigureProviderProperty(ClientPtr client) +{ + REQUEST(xRRConfigureProviderPropertyReq); + RRProviderPtr provider; + int num_valid; + + REQUEST_AT_LEAST_SIZE(xRRConfigureProviderPropertyReq); + + VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); + + num_valid = + stuff->length - bytes_to_int32(sizeof(xRRConfigureProviderPropertyReq)); + return RRConfigureProviderProperty(provider, stuff->property, stuff->pending, + stuff->range, FALSE, num_valid, + (INT32 *) (stuff + 1)); +} + +int +ProcRRChangeProviderProperty(ClientPtr client) +{ + REQUEST(xRRChangeProviderPropertyReq); + RRProviderPtr provider; + char format, mode; + unsigned long len; + int sizeInBytes; + int totalSize; + int err; + + REQUEST_AT_LEAST_SIZE(xRRChangeProviderPropertyReq); + UpdateCurrentTime(); + format = stuff->format; + mode = stuff->mode; + if ((mode != PropModeReplace) && (mode != PropModeAppend) && + (mode != PropModePrepend)) { + client->errorValue = mode; + return BadValue; + } + if ((format != 8) && (format != 16) && (format != 32)) { + client->errorValue = format; + return BadValue; + } + len = stuff->nUnits; + if (len > bytes_to_int32((0xffffffff - sizeof(xChangePropertyReq)))) + return BadLength; + sizeInBytes = format >> 3; + totalSize = len * sizeInBytes; + REQUEST_FIXED_SIZE(xRRChangeProviderPropertyReq, totalSize); + + VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); + + if (!ValidAtom(stuff->property)) { + client->errorValue = stuff->property; + return BadAtom; + } + if (!ValidAtom(stuff->type)) { + client->errorValue = stuff->type; + return BadAtom; + } + + err = RRChangeProviderProperty(provider, stuff->property, + stuff->type, (int) format, + (int) mode, len, (pointer) &stuff[1], TRUE, + TRUE); + if (err != Success) + return err; + else + return Success; +} + +int +ProcRRDeleteProviderProperty(ClientPtr client) +{ + REQUEST(xRRDeleteProviderPropertyReq); + RRProviderPtr provider; + RRPropertyPtr prop; + + REQUEST_SIZE_MATCH(xRRDeleteProviderPropertyReq); + UpdateCurrentTime(); + VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); + + if (!ValidAtom(stuff->property)) { + client->errorValue = stuff->property; + return BadAtom; + } + + prop = RRQueryProviderProperty(provider, stuff->property); + if (!prop) { + client->errorValue = stuff->property; + return BadName; + } + + if (prop->immutable) { + client->errorValue = stuff->property; + return BadAccess; + } + + RRDeleteProviderProperty(provider, stuff->property); + return Success; +} + +int +ProcRRGetProviderProperty(ClientPtr client) +{ + REQUEST(xRRGetProviderPropertyReq); + RRPropertyPtr prop, *prev; + RRPropertyValuePtr prop_value; + unsigned long n, len, ind; + RRProviderPtr provider; + xRRGetProviderPropertyReply reply; + char *extra = NULL; + + REQUEST_SIZE_MATCH(xRRGetProviderPropertyReq); + if (stuff->delete) + UpdateCurrentTime(); + VERIFY_RR_PROVIDER(stuff->provider, provider, + stuff->delete ? DixWriteAccess : DixReadAccess); + + if (!ValidAtom(stuff->property)) { + client->errorValue = stuff->property; + return BadAtom; + } + if ((stuff->delete != xTrue) && (stuff->delete != xFalse)) { + client->errorValue = stuff->delete; + return BadValue; + } + if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type)) { + client->errorValue = stuff->type; + return BadAtom; + } + + for (prev = &provider->properties; (prop = *prev); prev = &prop->next) + if (prop->propertyName == stuff->property) + break; + + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + if (!prop) { + reply.nItems = 0; + reply.length = 0; + reply.bytesAfter = 0; + reply.propertyType = None; + reply.format = 0; + if (client->swapped) { + swaps(&reply.sequenceNumber); + swapl(&reply.length); + swapl(&reply.propertyType); + swapl(&reply.bytesAfter); + swapl(&reply.nItems); + } + WriteToClient(client, sizeof(xRRGetProviderPropertyReply), &reply); + return Success; + } + + if (prop->immutable && stuff->delete) + return BadAccess; + + prop_value = RRGetProviderProperty(provider, stuff->property, stuff->pending); + if (!prop_value) + return BadAtom; + + /* If the request type and actual type don't match. Return the + property information, but not the data. */ + + if (((stuff->type != prop_value->type) && (stuff->type != AnyPropertyType)) + ) { + reply.bytesAfter = prop_value->size; + reply.format = prop_value->format; + reply.length = 0; + reply.nItems = 0; + reply.propertyType = prop_value->type; + if (client->swapped) { + swaps(&reply.sequenceNumber); + swapl(&reply.length); + swapl(&reply.propertyType); + swapl(&reply.bytesAfter); + swapl(&reply.nItems); + } + WriteToClient(client, sizeof(xRRGetProviderPropertyReply), &reply); + return Success; + } + +/* + * Return type, format, value to client + */ + n = (prop_value->format / 8) * prop_value->size; /* size (bytes) of prop */ + ind = stuff->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; + return BadValue; + } + + len = min(n - ind, 4 * stuff->longLength); + + if (len) { + extra = malloc(len); + if (!extra) + return BadAlloc; + } + reply.bytesAfter = n - (ind + len); + reply.format = prop_value->format; + reply.length = bytes_to_int32(len); + if (prop_value->format) + reply.nItems = len / (prop_value->format / 8); + else + reply.nItems = 0; + reply.propertyType = prop_value->type; + + if (stuff->delete && (reply.bytesAfter == 0)) { + xRRProviderPropertyNotifyEvent event; + + event.type = RREventBase + RRNotify; + event.subCode = RRNotify_ProviderProperty; + event.provider = provider->id; + event.state = PropertyDelete; + event.atom = prop->propertyName; + event.timestamp = currentTime.milliseconds; + RRDeliverPropertyEvent(provider->pScreen, (xEvent *) &event); + } + + if (client->swapped) { + swaps(&reply.sequenceNumber); + swapl(&reply.length); + swapl(&reply.propertyType); + swapl(&reply.bytesAfter); + swapl(&reply.nItems); + } + WriteToClient(client, sizeof(xGenericReply), &reply); + if (len) { + memcpy(extra, (char *) prop_value->data + ind, len); + switch (reply.format) { + case 32: + client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; + break; + case 16: + client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write; + break; + default: + client->pSwapReplyFunc = (ReplySwapPtr) WriteToClient; + break; + } + WriteSwappedDataToClient(client, len, extra); + free(extra); + } + + if (stuff->delete && (reply.bytesAfter == 0)) { /* delete the Property */ + *prev = prop->next; + RRDestroyProviderProperty(prop); + } + return Success; +} |