summaryrefslogtreecommitdiff
path: root/randr/rrproviderproperty.c
diff options
context:
space:
mode:
Diffstat (limited to 'randr/rrproviderproperty.c')
-rw-r--r--randr/rrproviderproperty.c716
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;
+}