diff options
author | root <root@zombrain.(none)> | 2011-07-25 08:54:41 (GMT) |
---|---|---|
committer | root <root@zombrain.(none)> | 2011-07-25 08:54:41 (GMT) |
commit | ab4fcaad149d4bdccefa8f693c2a8e044b40dd4c (patch) | |
tree | c95c280caabc70e7aedbde723e38820047357be7 /Xi/xiproperty.c |
initial state (xorg-server 1.10.2)
Diffstat (limited to 'Xi/xiproperty.c')
-rw-r--r-- | Xi/xiproperty.c | 1362 |
1 files changed, 1362 insertions, 0 deletions
diff --git a/Xi/xiproperty.c b/Xi/xiproperty.c new file mode 100644 index 0000000..83ce930 --- /dev/null +++ b/Xi/xiproperty.c @@ -0,0 +1,1362 @@ +/* + * Copyright © 2006 Keith Packard + * Copyright © 2008 Peter Hutterer + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WAXIANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WAXIANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +/* This code is a modified version of randr/rrproperty.c */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "dix.h" +#include "inputstr.h" +#include <X11/extensions/XI.h> +#include <X11/Xatom.h> +#include <X11/extensions/XIproto.h> +#include <X11/extensions/XI2proto.h> +#include "exglobals.h" +#include "exevents.h" +#include "swaprep.h" + +#include "xiproperty.h" +#include "xserver-properties.h" + +/** + * Properties used or alloced from inside the server. + */ +static struct dev_properties +{ + Atom type; + char *name; +} dev_properties[] = { + {0, XI_PROP_ENABLED}, + {0, XI_PROP_XTEST_DEVICE}, + {0, XATOM_FLOAT}, + {0, ACCEL_PROP_PROFILE_NUMBER}, + {0, ACCEL_PROP_CONSTANT_DECELERATION}, + {0, ACCEL_PROP_ADAPTIVE_DECELERATION}, + {0, ACCEL_PROP_VELOCITY_SCALING}, + {0, AXIS_LABEL_PROP}, + {0, AXIS_LABEL_PROP_REL_X}, + {0, AXIS_LABEL_PROP_REL_Y}, + {0, AXIS_LABEL_PROP_REL_Z}, + {0, AXIS_LABEL_PROP_REL_RX}, + {0, AXIS_LABEL_PROP_REL_RY}, + {0, AXIS_LABEL_PROP_REL_RZ}, + {0, AXIS_LABEL_PROP_REL_HWHEEL}, + {0, AXIS_LABEL_PROP_REL_DIAL}, + {0, AXIS_LABEL_PROP_REL_WHEEL}, + {0, AXIS_LABEL_PROP_REL_MISC}, + {0, AXIS_LABEL_PROP_ABS_X}, + {0, AXIS_LABEL_PROP_ABS_Y}, + {0, AXIS_LABEL_PROP_ABS_Z}, + {0, AXIS_LABEL_PROP_ABS_RX}, + {0, AXIS_LABEL_PROP_ABS_RY}, + {0, AXIS_LABEL_PROP_ABS_RZ}, + {0, AXIS_LABEL_PROP_ABS_THROTTLE}, + {0, AXIS_LABEL_PROP_ABS_RUDDER}, + {0, AXIS_LABEL_PROP_ABS_WHEEL}, + {0, AXIS_LABEL_PROP_ABS_GAS}, + {0, AXIS_LABEL_PROP_ABS_BRAKE}, + {0, AXIS_LABEL_PROP_ABS_HAT0X}, + {0, AXIS_LABEL_PROP_ABS_HAT0Y}, + {0, AXIS_LABEL_PROP_ABS_HAT1X}, + {0, AXIS_LABEL_PROP_ABS_HAT1Y}, + {0, AXIS_LABEL_PROP_ABS_HAT2X}, + {0, AXIS_LABEL_PROP_ABS_HAT2Y}, + {0, AXIS_LABEL_PROP_ABS_HAT3X}, + {0, AXIS_LABEL_PROP_ABS_HAT3Y}, + {0, AXIS_LABEL_PROP_ABS_PRESSURE}, + {0, AXIS_LABEL_PROP_ABS_DISTANCE}, + {0, AXIS_LABEL_PROP_ABS_TILT_X}, + {0, AXIS_LABEL_PROP_ABS_TILT_Y}, + {0, AXIS_LABEL_PROP_ABS_TOOL_WIDTH}, + {0, AXIS_LABEL_PROP_ABS_VOLUME}, + {0, AXIS_LABEL_PROP_ABS_MT_TOUCH_MAJOR}, + {0, AXIS_LABEL_PROP_ABS_MT_TOUCH_MINOR}, + {0, AXIS_LABEL_PROP_ABS_MT_WIDTH_MAJOR}, + {0, AXIS_LABEL_PROP_ABS_MT_WIDTH_MINOR}, + {0, AXIS_LABEL_PROP_ABS_MT_ORIENTATION}, + {0, AXIS_LABEL_PROP_ABS_MT_POSITION_X}, + {0, AXIS_LABEL_PROP_ABS_MT_POSITION_Y}, + {0, AXIS_LABEL_PROP_ABS_MT_TOOL_TYPE}, + {0, AXIS_LABEL_PROP_ABS_MT_BLOB_ID}, + {0, AXIS_LABEL_PROP_ABS_MT_TRACKING_ID}, + {0, AXIS_LABEL_PROP_ABS_MT_PRESSURE}, + {0, AXIS_LABEL_PROP_ABS_MISC}, + + {0, BTN_LABEL_PROP}, + {0, BTN_LABEL_PROP_BTN_UNKNOWN}, + {0, BTN_LABEL_PROP_BTN_WHEEL_UP}, + {0, BTN_LABEL_PROP_BTN_WHEEL_DOWN}, + {0, BTN_LABEL_PROP_BTN_HWHEEL_LEFT}, + {0, BTN_LABEL_PROP_BTN_HWHEEL_RIGHT}, + {0, BTN_LABEL_PROP_BTN_0}, + {0, BTN_LABEL_PROP_BTN_1}, + {0, BTN_LABEL_PROP_BTN_2}, + {0, BTN_LABEL_PROP_BTN_3}, + {0, BTN_LABEL_PROP_BTN_4}, + {0, BTN_LABEL_PROP_BTN_5}, + {0, BTN_LABEL_PROP_BTN_6}, + {0, BTN_LABEL_PROP_BTN_7}, + {0, BTN_LABEL_PROP_BTN_8}, + {0, BTN_LABEL_PROP_BTN_9}, + + {0, BTN_LABEL_PROP_BTN_LEFT}, + {0, BTN_LABEL_PROP_BTN_RIGHT}, + {0, BTN_LABEL_PROP_BTN_MIDDLE}, + {0, BTN_LABEL_PROP_BTN_SIDE}, + {0, BTN_LABEL_PROP_BTN_EXTRA}, + {0, BTN_LABEL_PROP_BTN_FORWARD}, + {0, BTN_LABEL_PROP_BTN_BACK}, + {0, BTN_LABEL_PROP_BTN_TASK}, + + {0, BTN_LABEL_PROP_BTN_TRIGGER}, + {0, BTN_LABEL_PROP_BTN_THUMB}, + {0, BTN_LABEL_PROP_BTN_THUMB2}, + {0, BTN_LABEL_PROP_BTN_TOP}, + {0, BTN_LABEL_PROP_BTN_TOP2}, + {0, BTN_LABEL_PROP_BTN_PINKIE}, + {0, BTN_LABEL_PROP_BTN_BASE}, + {0, BTN_LABEL_PROP_BTN_BASE2}, + {0, BTN_LABEL_PROP_BTN_BASE3}, + {0, BTN_LABEL_PROP_BTN_BASE4}, + {0, BTN_LABEL_PROP_BTN_BASE5}, + {0, BTN_LABEL_PROP_BTN_BASE6}, + {0, BTN_LABEL_PROP_BTN_DEAD}, + + {0, BTN_LABEL_PROP_BTN_A}, + {0, BTN_LABEL_PROP_BTN_B}, + {0, BTN_LABEL_PROP_BTN_C}, + {0, BTN_LABEL_PROP_BTN_X}, + {0, BTN_LABEL_PROP_BTN_Y}, + {0, BTN_LABEL_PROP_BTN_Z}, + {0, BTN_LABEL_PROP_BTN_TL}, + {0, BTN_LABEL_PROP_BTN_TR}, + {0, BTN_LABEL_PROP_BTN_TL2}, + {0, BTN_LABEL_PROP_BTN_TR2}, + {0, BTN_LABEL_PROP_BTN_SELECT}, + {0, BTN_LABEL_PROP_BTN_START}, + {0, BTN_LABEL_PROP_BTN_MODE}, + {0, BTN_LABEL_PROP_BTN_THUMBL}, + {0, BTN_LABEL_PROP_BTN_THUMBR}, + + {0, BTN_LABEL_PROP_BTN_TOOL_PEN}, + {0, BTN_LABEL_PROP_BTN_TOOL_RUBBER}, + {0, BTN_LABEL_PROP_BTN_TOOL_BRUSH}, + {0, BTN_LABEL_PROP_BTN_TOOL_PENCIL}, + {0, BTN_LABEL_PROP_BTN_TOOL_AIRBRUSH}, + {0, BTN_LABEL_PROP_BTN_TOOL_FINGER}, + {0, BTN_LABEL_PROP_BTN_TOOL_MOUSE}, + {0, BTN_LABEL_PROP_BTN_TOOL_LENS}, + {0, BTN_LABEL_PROP_BTN_TOUCH}, + {0, BTN_LABEL_PROP_BTN_STYLUS}, + {0, BTN_LABEL_PROP_BTN_STYLUS2}, + {0, BTN_LABEL_PROP_BTN_TOOL_DOUBLETAP}, + {0, BTN_LABEL_PROP_BTN_TOOL_TRIPLETAP}, + + {0, BTN_LABEL_PROP_BTN_GEAR_DOWN}, + {0, BTN_LABEL_PROP_BTN_GEAR_UP}, + + {0, XI_PROP_TRANSFORM} +}; + +static long XIPropHandlerID = 1; + +static void send_property_event(DeviceIntPtr dev, Atom property, int what) +{ + devicePropertyNotify event; + xXIPropertyEvent xi2; + int state; + + if (what == XIPropertyDeleted) + state = PropertyDelete; + else + state = PropertyNewValue; + + event.type = DevicePropertyNotify; + event.deviceid = dev->id; + event.state = state; + event.atom = property; + event.time = currentTime.milliseconds; + SendEventToAllWindows(dev, DevicePropertyNotifyMask, + (xEvent*)&event, 1); + + xi2.type = GenericEvent; + xi2.extension = IReqCode; + xi2.length = 0; + xi2.evtype = XI_PropertyEvent; + xi2.deviceid = dev->id; + xi2.time = currentTime.milliseconds; + xi2.property = property; + xi2.what = what; + SendEventToAllWindows(dev, GetEventFilter(dev, (xEvent*)&xi2), + (xEvent*)&xi2, 1); +} + +static int list_atoms(DeviceIntPtr dev, int *natoms, Atom **atoms_return) +{ + XIPropertyPtr prop; + Atom *atoms = NULL; + int nprops = 0; + + for (prop = dev->properties.properties; prop; prop = prop->next) + nprops++; + if (nprops) + { + Atom *a; + + atoms = malloc(nprops * sizeof(Atom)); + if(!atoms) + return BadAlloc; + a = atoms; + for (prop = dev->properties.properties; prop; prop = prop->next, a++) + *a = prop->propertyName; + } + + *natoms = nprops; + *atoms_return = atoms; + return Success; +} + +static int +get_property(ClientPtr client, DeviceIntPtr dev, Atom property, Atom type, + BOOL delete, int offset, int length, + int *bytes_after, Atom *type_return, int *format, int *nitems, + int *length_return, char **data) +{ + unsigned long n, len, ind; + int rc; + XIPropertyPtr prop; + XIPropertyValuePtr prop_value; + + if (!ValidAtom(property)) + { + client->errorValue = property; + return BadAtom; + } + if ((delete != xTrue) && (delete != xFalse)) + { + client->errorValue = delete; + return BadValue; + } + + if ((type != AnyPropertyType) && !ValidAtom(type)) + { + client->errorValue = type; + return BadAtom; + } + + for (prop = dev->properties.properties; prop; prop = prop->next) + if (prop->propertyName == property) + break; + + if (!prop) + { + *bytes_after = 0; + *type_return = None; + *format = 0; + *nitems = 0; + *length_return = 0; + return Success; + } + + rc = XIGetDeviceProperty(dev, property, &prop_value); + if (rc != Success) + { + client->errorValue = property; + return rc; + } + + /* If the request type and actual type don't match. Return the + property information, but not the data. */ + + if (((type != prop_value->type) && (type != AnyPropertyType))) + { + *bytes_after = prop_value->size; + *format = prop_value->format; + *length_return = 0; + *nitems = 0; + *type_return = prop_value->type; + return Success; + } + + /* Return type, format, value to client */ + n = (prop_value->format/8) * prop_value->size; /* size (bytes) of prop */ + ind = offset << 2; + + /* If offset is invalid such that it causes "len" to + be negative, it's a value error. */ + + if (n < ind) + { + client->errorValue = offset; + return BadValue; + } + + len = min(n - ind, 4 * length); + + *bytes_after = n - (ind + len); + *format = prop_value->format; + *length_return = len; + if (prop_value->format) + *nitems = len / (prop_value->format / 8); + else + *nitems = 0; + *type_return = prop_value->type; + + *data = (char*)prop_value->data + ind; + + return Success; +} + +static int +check_change_property(ClientPtr client, Atom property, Atom type, int format, + int mode, int nitems) +{ + if ((mode != PropModeReplace) && (mode != PropModeAppend) && + (mode != PropModePrepend)) + { + client->errorValue = mode; + return BadValue; + } + if ((format != 8) && (format != 16) && (format != 32)) + { + client->errorValue = format; + return BadValue; + } + + if (!ValidAtom(property)) + { + client->errorValue = property; + return BadAtom; + } + if (!ValidAtom(type)) + { + client->errorValue = type; + return BadAtom; + } + + return Success; +} + +static int +change_property(ClientPtr client, DeviceIntPtr dev, Atom property, Atom type, + int format, int mode, int len, void *data) +{ + int rc = Success; + + rc = XIChangeDeviceProperty(dev, property, type, format, mode, len, data, TRUE); + if (rc != Success) + client->errorValue = property; + + return rc; +} + +/** + * Return the atom assigned to the specified string or 0 if the atom isn't known + * to the DIX. + * + * If name is NULL, None is returned. + */ +Atom +XIGetKnownProperty(char *name) +{ + int i; + + if (!name) + return None; + + for (i = 0; i < (sizeof(dev_properties)/sizeof(struct dev_properties)); i++) + { + if (strcmp(name, dev_properties[i].name) == 0){ + if (dev_properties[i].type == None){ + dev_properties[i].type = + MakeAtom(dev_properties[i].name, + strlen(dev_properties[i].name), + TRUE); + } + + return dev_properties[i].type; + } + } + + return 0; +} + +void +XIResetProperties(void) +{ + int i; + + for (i = 0; i < (sizeof(dev_properties)/sizeof(struct dev_properties)); i++) + dev_properties[i].type = None; +} + +/** + * Convert the given property's value(s) into @nelem_return integer values and + * store them in @buf_return. If @nelem_return is larger than the number of + * values in the property, @nelem_return is set to the number of values in the + * property. + * + * If *@buf_return is NULL and @nelem_return is 0, memory is allocated + * automatically and must be freed by the caller. + * + * Possible return codes. + * Success ... No error. + * BadMatch ... Wrong atom type, atom is not XA_INTEGER + * BadAlloc ... NULL passed as buffer and allocation failed. + * BadLength ... @buff is NULL but @nelem_return is non-zero. + * + * @param val The property value + * @param nelem_return The maximum number of elements to return. + * @param buf_return Pointer to an array of at least @nelem_return values. + * @return Success or the error code if an error occured. + */ +_X_EXPORT int +XIPropToInt(XIPropertyValuePtr val, int *nelem_return, int **buf_return) +{ + int i; + int *buf; + + if (val->type != XA_INTEGER) + return BadMatch; + if (!*buf_return && *nelem_return) + return BadLength; + + switch(val->format) + { + case 8: + case 16: + case 32: + break; + default: + return BadValue; + } + + buf = *buf_return; + + if (!buf && !(*nelem_return)) + { + buf = calloc(val->size, sizeof(int)); + if (!buf) + return BadAlloc; + *buf_return = buf; + *nelem_return = val->size; + } else if (val->size < *nelem_return) + *nelem_return = val->size; + + for (i = 0; i < val->size && i < *nelem_return; i++) + { + switch(val->format) + { + case 8: buf[i] = ((CARD8*)val->data)[i]; break; + case 16: buf[i] = ((CARD16*)val->data)[i]; break; + case 32: buf[i] = ((CARD32*)val->data)[i]; break; + } + } + + return Success; +} + +/** + * Convert the given property's value(s) into @nelem_return float values and + * store them in @buf_return. If @nelem_return is larger than the number of + * values in the property, @nelem_return is set to the number of values in the + * property. + * + * If *@buf_return is NULL and @nelem_return is 0, memory is allocated + * automatically and must be freed by the caller. + * + * Possible errors returned: + * Success + * BadMatch ... Wrong atom type, atom is not XA_FLOAT + * BadValue ... Wrong format, format is not 32 + * BadAlloc ... NULL passed as buffer and allocation failed. + * BadLength ... @buff is NULL but @nelem_return is non-zero. + * + * @param val The property value + * @param nelem_return The maximum number of elements to return. + * @param buf_return Pointer to an array of at least @nelem_return values. + * @return Success or the error code if an error occured. + */ +_X_EXPORT int +XIPropToFloat(XIPropertyValuePtr val, int *nelem_return, float **buf_return) +{ + int i; + float *buf; + + if (!val->type || val->type != XIGetKnownProperty(XATOM_FLOAT)) + return BadMatch; + + if (val->format != 32) + return BadValue; + if (!*buf_return && *nelem_return) + return BadLength; + + buf = *buf_return; + + if (!buf && !(*nelem_return)) + { + buf = calloc(val->size, sizeof(float)); + if (!buf) + return BadAlloc; + *buf_return = buf; + *nelem_return = val->size; + } else if (val->size < *nelem_return) + *nelem_return = val->size; + + for (i = 0; i < val->size && i < *nelem_return; i++) + buf[i] = ((float*)val->data)[i]; + + return Success; +} + +/* Registers a new property handler on the given device and returns a unique + * identifier for this handler. This identifier is required to unregister the + * property handler again. + * @return The handler's identifier or 0 if an error occured. + */ +long +XIRegisterPropertyHandler(DeviceIntPtr dev, + int (*SetProperty) (DeviceIntPtr dev, + Atom property, + XIPropertyValuePtr prop, + BOOL checkonly), + int (*GetProperty) (DeviceIntPtr dev, + Atom property), + int (*DeleteProperty) (DeviceIntPtr dev, + Atom property)) +{ + XIPropertyHandlerPtr new_handler; + + new_handler = calloc(1, sizeof(XIPropertyHandler)); + if (!new_handler) + return 0; + + new_handler->id = XIPropHandlerID++; + new_handler->SetProperty = SetProperty; + new_handler->GetProperty = GetProperty; + new_handler->DeleteProperty = DeleteProperty; + new_handler->next = dev->properties.handlers; + dev->properties.handlers = new_handler; + + return new_handler->id; +} + +void +XIUnregisterPropertyHandler(DeviceIntPtr dev, long id) +{ + XIPropertyHandlerPtr curr, prev = NULL; + + curr = dev->properties.handlers; + while(curr && curr->id != id) + { + prev = curr; + curr = curr->next; + } + + if (!curr) + return; + + if (!prev) /* first one */ + dev->properties.handlers = curr->next; + else + prev->next = curr->next; + + free(curr); +} + +static XIPropertyPtr +XICreateDeviceProperty (Atom property) +{ + XIPropertyPtr prop; + + prop = (XIPropertyPtr)malloc(sizeof(XIPropertyRec)); + if (!prop) + return NULL; + + prop->next = NULL; + prop->propertyName = property; + prop->value.type = None; + prop->value.format = 0; + prop->value.size = 0; + prop->value.data = NULL; + prop->deletable = TRUE; + + return prop; +} + +static XIPropertyPtr +XIFetchDeviceProperty(DeviceIntPtr dev, Atom property) +{ + XIPropertyPtr prop; + + for (prop = dev->properties.properties; prop; prop = prop->next) + if (prop->propertyName == property) + return prop; + return NULL; +} + +static void +XIDestroyDeviceProperty (XIPropertyPtr prop) +{ + free(prop->value.data); + free(prop); +} + +/* This function destroys all of the device's property-related stuff, + * including removing all device handlers. + * DO NOT CALL FROM THE DRIVER. + */ +void +XIDeleteAllDeviceProperties (DeviceIntPtr device) +{ + XIPropertyPtr prop, next; + XIPropertyHandlerPtr curr_handler, next_handler; + + for (prop = device->properties.properties; prop; prop = next) + { + next = prop->next; + send_property_event(device, prop->propertyName, XIPropertyDeleted); + XIDestroyDeviceProperty(prop); + } + + device->properties.properties = NULL; + + /* Now free all handlers */ + curr_handler = device->properties.handlers; + while(curr_handler) + { + next_handler = curr_handler->next; + free(curr_handler); + curr_handler = next_handler; + } + + device->properties.handlers = NULL; +} + + +int +XIDeleteDeviceProperty (DeviceIntPtr device, Atom property, Bool fromClient) +{ + XIPropertyPtr prop, *prev; + int rc = Success; + + for (prev = &device->properties.properties; (prop = *prev); prev = &(prop->next)) + if (prop->propertyName == property) + break; + + if (!prop) + return Success; + + if (fromClient && !prop->deletable) + return BadAccess; + + /* Ask handlers if we may delete the property */ + if (device->properties.handlers) + { + XIPropertyHandlerPtr handler = device->properties.handlers; + while(handler) + { + if (handler->DeleteProperty) + rc = handler->DeleteProperty(device, prop->propertyName); + if (rc != Success) + return rc; + handler = handler->next; + } + } + + if (prop) + { + *prev = prop->next; + send_property_event(device, prop->propertyName, XIPropertyDeleted); + XIDestroyDeviceProperty (prop); + } + + return Success; +} + +int +XIChangeDeviceProperty (DeviceIntPtr dev, Atom property, Atom type, + int format, int mode, unsigned long len, + const pointer value, Bool sendevent) +{ + XIPropertyPtr prop; + int size_in_bytes; + int total_size; + unsigned long total_len; + XIPropertyValuePtr prop_value; + XIPropertyValueRec new_value; + Bool add = FALSE; + int rc; + + size_in_bytes = format >> 3; + + /* first see if property already exists */ + prop = XIFetchDeviceProperty (dev, property); + if (!prop) /* just add to list */ + { + prop = XICreateDeviceProperty (property); + if (!prop) + return BadAlloc; + add = TRUE; + mode = PropModeReplace; + } + prop_value = &prop->value; + + /* 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) + XIDestroyDeviceProperty (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 (dev->properties.handlers) + { + XIPropertyHandlerPtr handler; + BOOL checkonly = TRUE; + /* run through all handlers with checkonly TRUE, then again with + * checkonly FALSE. Handlers MUST return error codes on the + * checkonly run, errors on the second run are ignored */ + do + { + handler = dev->properties.handlers; + while(handler) + { + if (handler->SetProperty) + { + rc = handler->SetProperty(dev, prop->propertyName, + &new_value, checkonly); + if (checkonly && rc != Success) + { + free(new_value.data); + return rc; + } + } + handler = handler->next; + } + checkonly = !checkonly; + } while (!checkonly); + } + free(prop_value->data); + *prop_value = new_value; + } else if (len == 0) + { + /* do nothing */ + } + + if (add) + { + prop->next = dev->properties.properties; + dev->properties.properties = prop; + } + + if (sendevent) + send_property_event(dev, prop->propertyName, + (add) ? XIPropertyCreated : XIPropertyModified); + + return Success; +} + +int +XIGetDeviceProperty (DeviceIntPtr dev, Atom property, XIPropertyValuePtr *value) +{ + XIPropertyPtr prop = XIFetchDeviceProperty (dev, property); + int rc; + + if (!prop) + { + *value = NULL; + return BadAtom; + } + + /* If we can, try to update the property value first */ + if (dev->properties.handlers) + { + XIPropertyHandlerPtr handler = dev->properties.handlers; + while(handler) + { + if (handler->GetProperty) + { + rc = handler->GetProperty(dev, prop->propertyName); + if (rc != Success) + { + *value = NULL; + return rc; + } + } + handler = handler->next; + } + } + + *value = &prop->value; + return Success; +} + +int +XISetDevicePropertyDeletable(DeviceIntPtr dev, Atom property, Bool deletable) +{ + XIPropertyPtr prop = XIFetchDeviceProperty(dev, property); + + if (!prop) + return BadAtom; + + prop->deletable = deletable; + return Success; +} + +int +ProcXListDeviceProperties (ClientPtr client) +{ + Atom *atoms; + xListDevicePropertiesReply rep; + int natoms; + DeviceIntPtr dev; + int rc = Success; + + REQUEST(xListDevicePropertiesReq); + REQUEST_SIZE_MATCH(xListDevicePropertiesReq); + + rc = dixLookupDevice (&dev, stuff->deviceid, client, DixListPropAccess); + if (rc != Success) + return rc; + + rc = list_atoms(dev, &natoms, &atoms); + if (rc != Success) + return rc; + + rep.repType = X_Reply; + rep.RepType = X_ListDeviceProperties; + rep.length = natoms; + rep.sequenceNumber = client->sequence; + rep.nAtoms = natoms; + + WriteReplyToClient(client, sizeof(xListDevicePropertiesReply), &rep); + if (natoms) + { + client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write; + WriteSwappedDataToClient(client, natoms * sizeof(Atom), atoms); + free(atoms); + } + return rc; +} + +int +ProcXChangeDeviceProperty (ClientPtr client) +{ + REQUEST(xChangeDevicePropertyReq); + DeviceIntPtr dev; + unsigned long len; + int totalSize; + int rc; + + REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq); + UpdateCurrentTime(); + + rc = dixLookupDevice (&dev, stuff->deviceid, client, DixSetPropAccess); + if (rc != Success) + return rc; + + rc = check_change_property(client, stuff->property, stuff->type, + stuff->format, stuff->mode, stuff->nUnits); + + len = stuff->nUnits; + if (len > (bytes_to_int32(0xffffffff - sizeof(xChangeDevicePropertyReq)))) + return BadLength; + + totalSize = len * (stuff->format/8); + REQUEST_FIXED_SIZE(xChangeDevicePropertyReq, totalSize); + + rc = change_property(client, dev, stuff->property, stuff->type, + stuff->format, stuff->mode, len, (void*)&stuff[1]); + return rc; +} + +int +ProcXDeleteDeviceProperty (ClientPtr client) +{ + REQUEST(xDeleteDevicePropertyReq); + DeviceIntPtr dev; + int rc; + + REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq); + UpdateCurrentTime(); + rc = dixLookupDevice (&dev, stuff->deviceid, client, DixSetPropAccess); + if (rc != Success) + return rc; + + if (!ValidAtom(stuff->property)) + { + client->errorValue = stuff->property; + return BadAtom; + } + + rc = XIDeleteDeviceProperty(dev, stuff->property, TRUE); + return rc; +} + +int +ProcXGetDeviceProperty (ClientPtr client) +{ + REQUEST(xGetDevicePropertyReq); + DeviceIntPtr dev; + int length; + int rc, format, nitems, bytes_after; + char *data; + Atom type; + xGetDevicePropertyReply reply; + + REQUEST_SIZE_MATCH(xGetDevicePropertyReq); + if (stuff->delete) + UpdateCurrentTime(); + rc = dixLookupDevice (&dev, stuff->deviceid, client, + stuff->delete ? DixSetPropAccess : + DixGetPropAccess); + if (rc != Success) + return rc; + + rc = get_property(client, dev, stuff->property, stuff->type, + stuff->delete, stuff->longOffset, stuff->longLength, + &bytes_after, &type, &format, &nitems, &length, &data); + + if (rc != Success) + return rc; + + reply.repType = X_Reply; + reply.RepType = X_GetDeviceProperty; + reply.sequenceNumber = client->sequence; + reply.deviceid = dev->id; + reply.nItems = nitems; + reply.format = format; + reply.bytesAfter = bytes_after; + reply.propertyType = type; + reply.length = bytes_to_int32(length); + + if (stuff->delete && (reply.bytesAfter == 0)) + send_property_event(dev, stuff->property, XIPropertyDeleted); + + WriteReplyToClient(client, sizeof(xGenericReply), &reply); + + if (length) + { + 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, length, data); + } + + /* delete the Property */ + if (stuff->delete && (reply.bytesAfter == 0)) + { + XIPropertyPtr prop, *prev; + for (prev = &dev->properties.properties; (prop = *prev); prev = &prop->next) + { + if (prop->propertyName == stuff->property) + { + *prev = prop->next; + XIDestroyDeviceProperty(prop); + break; + } + } + } + return Success; +} + + +int +SProcXListDeviceProperties (ClientPtr client) +{ + char n; + REQUEST(xListDevicePropertiesReq); + + swaps(&stuff->length, n); + + REQUEST_SIZE_MATCH(xListDevicePropertiesReq); + return (ProcXListDeviceProperties(client)); +} + +int +SProcXChangeDeviceProperty (ClientPtr client) +{ + char n; + REQUEST(xChangeDevicePropertyReq); + + REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq); + swaps(&stuff->length, n); + swapl(&stuff->property, n); + swapl(&stuff->type, n); + swapl(&stuff->nUnits, n); + return (ProcXChangeDeviceProperty(client)); +} + +int +SProcXDeleteDeviceProperty (ClientPtr client) +{ + char n; + REQUEST(xDeleteDevicePropertyReq); + + swaps(&stuff->length, n); + swapl(&stuff->property, n); + REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq); + return (ProcXDeleteDeviceProperty(client)); +} + +int +SProcXGetDeviceProperty (ClientPtr client) +{ + char n; + REQUEST(xGetDevicePropertyReq); + + swaps(&stuff->length, n); + swapl(&stuff->property, n); + swapl(&stuff->type, n); + swapl(&stuff->longOffset, n); + swapl(&stuff->longLength, n); + REQUEST_SIZE_MATCH(xGetDevicePropertyReq); + return (ProcXGetDeviceProperty(client)); +} + + +/* Reply swapping */ + +void +SRepXListDeviceProperties(ClientPtr client, int size, + xListDevicePropertiesReply *rep) +{ + char n; + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swaps(&rep->nAtoms, n); + /* properties will be swapped later, see ProcXListDeviceProperties */ + WriteToClient(client, size, (char*)rep); +} + +void +SRepXGetDeviceProperty(ClientPtr client, int size, + xGetDevicePropertyReply *rep) +{ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swapl(&rep->propertyType, n); + swapl(&rep->bytesAfter, n); + swapl(&rep->nItems, n); + /* data will be swapped, see ProcXGetDeviceProperty */ + WriteToClient(client, size, (char*)rep); +} + +/* XI2 Request/reply handling */ +int +ProcXIListProperties(ClientPtr client) +{ + Atom *atoms; + xXIListPropertiesReply rep; + int natoms; + DeviceIntPtr dev; + int rc = Success; + + REQUEST(xXIListPropertiesReq); + REQUEST_SIZE_MATCH(xXIListPropertiesReq); + + rc = dixLookupDevice (&dev, stuff->deviceid, client, DixListPropAccess); + if (rc != Success) + return rc; + + rc = list_atoms(dev, &natoms, &atoms); + if (rc != Success) + return rc; + + rep.repType = X_Reply; + rep.RepType = X_XIListProperties; + rep.length = natoms; + rep.sequenceNumber = client->sequence; + rep.num_properties = natoms; + + WriteReplyToClient(client, sizeof(xXIListPropertiesReply), &rep); + if (natoms) + { + client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write; + WriteSwappedDataToClient(client, natoms * sizeof(Atom), atoms); + free(atoms); + } + return rc; +} + +int +ProcXIChangeProperty(ClientPtr client) +{ + int rc; + DeviceIntPtr dev; + int totalSize; + unsigned long len; + + REQUEST(xXIChangePropertyReq); + REQUEST_AT_LEAST_SIZE(xXIChangePropertyReq); + UpdateCurrentTime(); + + rc = dixLookupDevice (&dev, stuff->deviceid, client, DixSetPropAccess); + if (rc != Success) + return rc; + + rc = check_change_property(client, stuff->property, stuff->type, + stuff->format, stuff->mode, stuff->num_items); + len = stuff->num_items; + if (len > bytes_to_int32(0xffffffff - sizeof(xXIChangePropertyReq))) + return BadLength; + + totalSize = len * (stuff->format/8); + REQUEST_FIXED_SIZE(xXIChangePropertyReq, totalSize); + + rc = change_property(client, dev, stuff->property, stuff->type, + stuff->format, stuff->mode, len, (void*)&stuff[1]); + return rc; +} + +int +ProcXIDeleteProperty(ClientPtr client) +{ + DeviceIntPtr dev; + int rc; + REQUEST(xXIDeletePropertyReq); + + REQUEST_SIZE_MATCH(xXIDeletePropertyReq); + UpdateCurrentTime(); + rc = dixLookupDevice (&dev, stuff->deviceid, client, DixSetPropAccess); + if (rc != Success) + return rc; + + if (!ValidAtom(stuff->property)) + { + client->errorValue = stuff->property; + return BadAtom; + } + + rc = XIDeleteDeviceProperty(dev, stuff->property, TRUE); + return rc; +} + + +int +ProcXIGetProperty(ClientPtr client) +{ + REQUEST(xXIGetPropertyReq); + DeviceIntPtr dev; + xXIGetPropertyReply reply; + int length; + int rc, format, nitems, bytes_after; + char *data; + Atom type; + + REQUEST_SIZE_MATCH(xXIGetPropertyReq); + if (stuff->delete) + UpdateCurrentTime(); + rc = dixLookupDevice (&dev, stuff->deviceid, client, + stuff->delete ? DixSetPropAccess : + DixGetPropAccess); + if (rc != Success) + return rc; + + rc = get_property(client, dev, stuff->property, stuff->type, + stuff->delete, stuff->offset, stuff->len, + &bytes_after, &type, &format, &nitems, &length, &data); + + if (rc != Success) + return rc; + + reply.repType = X_Reply; + reply.RepType = X_XIGetProperty; + reply.sequenceNumber = client->sequence; + reply.num_items = nitems; + reply.format = format; + reply.bytes_after = bytes_after; + reply.type = type; + reply.length = bytes_to_int32(length); + + if (length && stuff->delete && (reply.bytes_after == 0)) + send_property_event(dev, stuff->property, XIPropertyDeleted); + + WriteReplyToClient(client, sizeof(xXIGetPropertyReply), &reply); + + if (length) + { + 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, length, data); + } + + /* delete the Property */ + if (stuff->delete && (reply.bytes_after == 0)) + { + XIPropertyPtr prop, *prev; + for (prev = &dev->properties.properties; (prop = *prev); prev = &prop->next) + { + if (prop->propertyName == stuff->property) + { + *prev = prop->next; + XIDestroyDeviceProperty(prop); + break; + } + } + } + + return Success; +} + +int +SProcXIListProperties(ClientPtr client) +{ + char n; + REQUEST(xXIListPropertiesReq); + + swaps(&stuff->length, n); + swaps(&stuff->deviceid, n); + + REQUEST_SIZE_MATCH(xXIListPropertiesReq); + return (ProcXIListProperties(client)); +} + +int +SProcXIChangeProperty(ClientPtr client) +{ + char n; + REQUEST(xXIChangePropertyReq); + + REQUEST_AT_LEAST_SIZE(xXIChangePropertyReq); + swaps(&stuff->length, n); + swaps(&stuff->deviceid, n); + swapl(&stuff->property, n); + swapl(&stuff->type, n); + swapl(&stuff->num_items, n); + return (ProcXIChangeProperty(client)); +} + +int +SProcXIDeleteProperty(ClientPtr client) +{ + char n; + REQUEST(xXIDeletePropertyReq); + + swaps(&stuff->length, n); + swaps(&stuff->deviceid, n); + swapl(&stuff->property, n); + REQUEST_SIZE_MATCH(xXIDeletePropertyReq); + return (ProcXIDeleteProperty(client)); +} + +int +SProcXIGetProperty(ClientPtr client) +{ + char n; + REQUEST(xXIGetPropertyReq); + + swaps(&stuff->length, n); + swaps(&stuff->deviceid, n); + swapl(&stuff->property, n); + swapl(&stuff->type, n); + swapl(&stuff->offset, n); + swapl(&stuff->len, n); + REQUEST_SIZE_MATCH(xXIGetPropertyReq); + return (ProcXIGetProperty(client)); +} + + +void +SRepXIListProperties(ClientPtr client, int size, + xXIListPropertiesReply *rep) +{ + char n; + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swaps(&rep->num_properties, n); + /* properties will be swapped later, see ProcXIListProperties */ + WriteToClient(client, size, (char*)rep); +} + +void +SRepXIGetProperty(ClientPtr client, int size, + xXIGetPropertyReply *rep) +{ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swapl(&rep->type, n); + swapl(&rep->bytes_after, n); + swapl(&rep->num_items, n); + /* data will be swapped, see ProcXIGetProperty */ + WriteToClient(client, size, (char*)rep); +} |