xiproperty.c revision 4642e01f
14642e01fSmrg/*
24642e01fSmrg * Copyright © 2006 Keith Packard
34642e01fSmrg * Copyright © 2008 Peter Hutterer
44642e01fSmrg *
54642e01fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
64642e01fSmrg * copy of this software and associated documentation files (the "Software"),
74642e01fSmrg * to deal in the Software without restriction, including without limitation
84642e01fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
94642e01fSmrg * and/or sell copies of the Software, and to permit persons to whom the
104642e01fSmrg * Software is furnished to do so, subject to the following conditions:
114642e01fSmrg *
124642e01fSmrg * The above copyright notice and this permission notice (including the next
134642e01fSmrg * paragraph) shall be included in all copies or substantial portions of the
144642e01fSmrg * Software.
154642e01fSmrg *
164642e01fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WAXIANTY OF ANY KIND, EXPRESS OR
174642e01fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WAXIANTIES OF MERCHANTABILITY,
184642e01fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
194642e01fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
204642e01fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
214642e01fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
224642e01fSmrg * DEALINGS IN THE SOFTWARE.
234642e01fSmrg *
244642e01fSmrg */
254642e01fSmrg
264642e01fSmrg/* This code is a modified version of randr/rrproperty.c */
274642e01fSmrg
284642e01fSmrg#ifdef HAVE_DIX_CONFIG_H
294642e01fSmrg#include <dix-config.h>
304642e01fSmrg#endif
314642e01fSmrg
324642e01fSmrg#include "dix.h"
334642e01fSmrg#include "inputstr.h"
344642e01fSmrg#include <X11/extensions/XI.h>
354642e01fSmrg#include <X11/Xatom.h>
364642e01fSmrg#include <X11/extensions/XIproto.h>
374642e01fSmrg#include "exglobals.h"
384642e01fSmrg#include "exevents.h"
394642e01fSmrg#include "swaprep.h"
404642e01fSmrg
414642e01fSmrg#include "xiproperty.h"
424642e01fSmrg#include "xserver-properties.h"
434642e01fSmrg
444642e01fSmrg/**
454642e01fSmrg * Properties used or alloced from inside the server.
464642e01fSmrg */
474642e01fSmrgstatic struct dev_properties
484642e01fSmrg{
494642e01fSmrg    Atom type;
504642e01fSmrg    char *name;
514642e01fSmrg} dev_properties[] = {
524642e01fSmrg    {0, XI_PROP_ENABLED},
534642e01fSmrg    {0, XATOM_FLOAT}
544642e01fSmrg};
554642e01fSmrg
564642e01fSmrgstatic long XIPropHandlerID = 1;
574642e01fSmrg
584642e01fSmrg/**
594642e01fSmrg * Return the type assigned to the specified atom or 0 if the atom isn't known
604642e01fSmrg * to the DIX.
614642e01fSmrg *
624642e01fSmrg * If name is NULL, None is returned.
634642e01fSmrg */
644642e01fSmrg_X_EXPORT Atom
654642e01fSmrgXIGetKnownProperty(char *name)
664642e01fSmrg{
674642e01fSmrg    int i;
684642e01fSmrg
694642e01fSmrg    if (!name)
704642e01fSmrg        return None;
714642e01fSmrg
724642e01fSmrg    for (i = 0; i < (sizeof(dev_properties)/sizeof(struct dev_properties)); i++)
734642e01fSmrg    {
744642e01fSmrg        if (strcmp(name, dev_properties[i].name) == 0)
754642e01fSmrg            return dev_properties[i].type;
764642e01fSmrg    }
774642e01fSmrg
784642e01fSmrg    return 0;
794642e01fSmrg}
804642e01fSmrg
814642e01fSmrg/**
824642e01fSmrg * Convert the given property's value(s) into @nelem_return integer values and
834642e01fSmrg * store them in @buf_return. If @nelem_return is larger than the number of
844642e01fSmrg * values in the property, @nelem_return is set to the number of values in the
854642e01fSmrg * property.
864642e01fSmrg *
874642e01fSmrg * If *@buf_return is NULL and @nelem_return is 0, memory is allocated
884642e01fSmrg * automatically and must be freed by the caller.
894642e01fSmrg *
904642e01fSmrg * Possible return codes.
914642e01fSmrg * Success ... No error.
924642e01fSmrg * BadMatch ... Wrong atom type, atom is not XA_INTEGER
934642e01fSmrg * BadAlloc ... NULL passed as buffer and allocation failed.
944642e01fSmrg * BadLength ... @buff is NULL but @nelem_return is non-zero.
954642e01fSmrg *
964642e01fSmrg * @param val The property value
974642e01fSmrg * @param nelem_return The maximum number of elements to return.
984642e01fSmrg * @param buf_return Pointer to an array of at least @nelem_return values.
994642e01fSmrg * @return Success or the error code if an error occured.
1004642e01fSmrg */
1014642e01fSmrg_X_EXPORT int
1024642e01fSmrgXIPropToInt(XIPropertyValuePtr val, int *nelem_return, int **buf_return)
1034642e01fSmrg{
1044642e01fSmrg    int i;
1054642e01fSmrg    int *buf;
1064642e01fSmrg
1074642e01fSmrg    if (val->type != XA_INTEGER)
1084642e01fSmrg        return BadMatch;
1094642e01fSmrg    if (!*buf_return && *nelem_return)
1104642e01fSmrg        return BadLength;
1114642e01fSmrg
1124642e01fSmrg    switch(val->format)
1134642e01fSmrg    {
1144642e01fSmrg        case 8:
1154642e01fSmrg        case 16:
1164642e01fSmrg        case 32:
1174642e01fSmrg            break;
1184642e01fSmrg        default:
1194642e01fSmrg            return BadValue;
1204642e01fSmrg    }
1214642e01fSmrg
1224642e01fSmrg    buf = *buf_return;
1234642e01fSmrg
1244642e01fSmrg    if (!buf && !(*nelem_return))
1254642e01fSmrg    {
1264642e01fSmrg        buf = xcalloc(val->size, sizeof(int));
1274642e01fSmrg        if (!buf)
1284642e01fSmrg            return BadAlloc;
1294642e01fSmrg        *buf_return = buf;
1304642e01fSmrg        *nelem_return = val->size;
1314642e01fSmrg    } else if (val->size < *nelem_return)
1324642e01fSmrg        *nelem_return = val->size;
1334642e01fSmrg
1344642e01fSmrg    for (i = 0; i < val->size && i < *nelem_return; i++)
1354642e01fSmrg    {
1364642e01fSmrg        switch(val->format)
1374642e01fSmrg        {
1384642e01fSmrg            case 8:  buf[i] = ((CARD8*)val->data)[i]; break;
1394642e01fSmrg            case 16: buf[i] = ((CARD16*)val->data)[i]; break;
1404642e01fSmrg            case 32: buf[i] = ((CARD32*)val->data)[i]; break;
1414642e01fSmrg        }
1424642e01fSmrg    }
1434642e01fSmrg
1444642e01fSmrg    return Success;
1454642e01fSmrg}
1464642e01fSmrg
1474642e01fSmrg/**
1484642e01fSmrg * Convert the given property's value(s) into @nelem_return float values and
1494642e01fSmrg * store them in @buf_return. If @nelem_return is larger than the number of
1504642e01fSmrg * values in the property, @nelem_return is set to the number of values in the
1514642e01fSmrg * property.
1524642e01fSmrg *
1534642e01fSmrg * If *@buf_return is NULL and @nelem_return is 0, memory is allocated
1544642e01fSmrg * automatically and must be freed by the caller.
1554642e01fSmrg *
1564642e01fSmrg * Possible errors returned:
1574642e01fSmrg * Success
1584642e01fSmrg * BadMatch ... Wrong atom type, atom is not XA_FLOAT
1594642e01fSmrg * BadValue ... Wrong format, format is not 32
1604642e01fSmrg * BadAlloc ... NULL passed as buffer and allocation failed.
1614642e01fSmrg * BadLength ... @buff is NULL but @nelem_return is non-zero.
1624642e01fSmrg *
1634642e01fSmrg * @param val The property value
1644642e01fSmrg * @param nelem_return The maximum number of elements to return.
1654642e01fSmrg * @param buf_return Pointer to an array of at least @nelem_return values.
1664642e01fSmrg * @return Success or the error code if an error occured.
1674642e01fSmrg */
1684642e01fSmrg_X_EXPORT int
1694642e01fSmrgXIPropToFloat(XIPropertyValuePtr val, int *nelem_return, float **buf_return)
1704642e01fSmrg{
1714642e01fSmrg    int i;
1724642e01fSmrg    float *buf;
1734642e01fSmrg
1744642e01fSmrg    if (!val->type || val->type != XIGetKnownProperty(XATOM_FLOAT))
1754642e01fSmrg        return BadMatch;
1764642e01fSmrg
1774642e01fSmrg    if (val->format != 32)
1784642e01fSmrg        return BadValue;
1794642e01fSmrg    if (!*buf_return && *nelem_return)
1804642e01fSmrg        return BadLength;
1814642e01fSmrg
1824642e01fSmrg    buf = *buf_return;
1834642e01fSmrg
1844642e01fSmrg    if (!buf && !(*nelem_return))
1854642e01fSmrg    {
1864642e01fSmrg        buf = xcalloc(val->size, sizeof(float));
1874642e01fSmrg        if (!buf)
1884642e01fSmrg            return BadAlloc;
1894642e01fSmrg        *buf_return = buf;
1904642e01fSmrg        *nelem_return = val->size;
1914642e01fSmrg    } else if (val->size < *nelem_return)
1924642e01fSmrg        *nelem_return = val->size;
1934642e01fSmrg
1944642e01fSmrg    for (i = 0; i < val->size && i < *nelem_return; i++)
1954642e01fSmrg           buf[i] = ((float*)val->data)[i];
1964642e01fSmrg
1974642e01fSmrg    return Success;
1984642e01fSmrg}
1994642e01fSmrg
2004642e01fSmrg/**
2014642e01fSmrg * Init those properties that are allocated by the server and most likely used
2024642e01fSmrg * by the DIX or the DDX.
2034642e01fSmrg */
2044642e01fSmrgvoid
2054642e01fSmrgXIInitKnownProperties(void)
2064642e01fSmrg{
2074642e01fSmrg    int i;
2084642e01fSmrg    for (i = 0; i < (sizeof(dev_properties)/sizeof(struct dev_properties)); i++)
2094642e01fSmrg    {
2104642e01fSmrg        dev_properties[i].type =
2114642e01fSmrg            MakeAtom(dev_properties[i].name,
2124642e01fSmrg                     strlen(dev_properties[i].name),
2134642e01fSmrg                     TRUE);
2144642e01fSmrg    }
2154642e01fSmrg}
2164642e01fSmrg
2174642e01fSmrg
2184642e01fSmrg/* Registers a new property handler on the given device and returns a unique
2194642e01fSmrg * identifier for this handler. This identifier is required to unregister the
2204642e01fSmrg * property handler again.
2214642e01fSmrg * @return The handler's identifier or 0 if an error occured.
2224642e01fSmrg */
2234642e01fSmrglong
2244642e01fSmrgXIRegisterPropertyHandler(DeviceIntPtr         dev,
2254642e01fSmrg                          int (*SetProperty) (DeviceIntPtr dev,
2264642e01fSmrg                                              Atom property,
2274642e01fSmrg                                              XIPropertyValuePtr prop,
2284642e01fSmrg                                              BOOL checkonly),
2294642e01fSmrg                          int (*GetProperty) (DeviceIntPtr dev,
2304642e01fSmrg                                              Atom property),
2314642e01fSmrg                          int (*DeleteProperty) (DeviceIntPtr dev,
2324642e01fSmrg                                                 Atom property))
2334642e01fSmrg{
2344642e01fSmrg    XIPropertyHandlerPtr new_handler;
2354642e01fSmrg
2364642e01fSmrg    new_handler = xcalloc(1, sizeof(XIPropertyHandler));
2374642e01fSmrg    if (!new_handler)
2384642e01fSmrg        return 0;
2394642e01fSmrg
2404642e01fSmrg    new_handler->id = XIPropHandlerID++;
2414642e01fSmrg    new_handler->SetProperty = SetProperty;
2424642e01fSmrg    new_handler->GetProperty = GetProperty;
2434642e01fSmrg    new_handler->DeleteProperty = DeleteProperty;
2444642e01fSmrg    new_handler->next = dev->properties.handlers;
2454642e01fSmrg    dev->properties.handlers = new_handler;
2464642e01fSmrg
2474642e01fSmrg    return new_handler->id;
2484642e01fSmrg}
2494642e01fSmrg
2504642e01fSmrgvoid
2514642e01fSmrgXIUnregisterPropertyHandler(DeviceIntPtr dev, long id)
2524642e01fSmrg{
2534642e01fSmrg    XIPropertyHandlerPtr curr, prev = NULL;
2544642e01fSmrg
2554642e01fSmrg    curr = dev->properties.handlers;
2564642e01fSmrg    while(curr && curr->id != id)
2574642e01fSmrg    {
2584642e01fSmrg        prev = curr;
2594642e01fSmrg        curr = curr->next;
2604642e01fSmrg    }
2614642e01fSmrg
2624642e01fSmrg    if (!curr)
2634642e01fSmrg        return;
2644642e01fSmrg
2654642e01fSmrg    if (!prev) /* first one */
2664642e01fSmrg        dev->properties.handlers = curr->next;
2674642e01fSmrg    else
2684642e01fSmrg        prev->next = curr->next;
2694642e01fSmrg
2704642e01fSmrg    xfree(curr);
2714642e01fSmrg}
2724642e01fSmrg
2734642e01fSmrgstatic XIPropertyPtr
2744642e01fSmrgXICreateDeviceProperty (Atom property)
2754642e01fSmrg{
2764642e01fSmrg    XIPropertyPtr   prop;
2774642e01fSmrg
2784642e01fSmrg    prop = (XIPropertyPtr)xalloc(sizeof(XIPropertyRec));
2794642e01fSmrg    if (!prop)
2804642e01fSmrg        return NULL;
2814642e01fSmrg
2824642e01fSmrg    prop->next          = NULL;
2834642e01fSmrg    prop->propertyName  = property;
2844642e01fSmrg    prop->value.type   = None;
2854642e01fSmrg    prop->value.format = 0;
2864642e01fSmrg    prop->value.size   = 0;
2874642e01fSmrg    prop->value.data   = NULL;
2884642e01fSmrg    prop->deletable    = TRUE;
2894642e01fSmrg
2904642e01fSmrg    return prop;
2914642e01fSmrg}
2924642e01fSmrg
2934642e01fSmrgstatic XIPropertyPtr
2944642e01fSmrgXIFetchDeviceProperty(DeviceIntPtr dev, Atom property)
2954642e01fSmrg{
2964642e01fSmrg    XIPropertyPtr   prop;
2974642e01fSmrg
2984642e01fSmrg    for (prop = dev->properties.properties; prop; prop = prop->next)
2994642e01fSmrg        if (prop->propertyName == property)
3004642e01fSmrg            return prop;
3014642e01fSmrg    return NULL;
3024642e01fSmrg}
3034642e01fSmrg
3044642e01fSmrgstatic void
3054642e01fSmrgXIDestroyDeviceProperty (XIPropertyPtr prop)
3064642e01fSmrg{
3074642e01fSmrg    if (prop->value.data)
3084642e01fSmrg        xfree(prop->value.data);
3094642e01fSmrg    xfree(prop);
3104642e01fSmrg}
3114642e01fSmrg
3124642e01fSmrg/* This function destroys all of the device's property-related stuff,
3134642e01fSmrg * including removing all device handlers.
3144642e01fSmrg * DO NOT CALL FROM THE DRIVER.
3154642e01fSmrg */
3164642e01fSmrgvoid
3174642e01fSmrgXIDeleteAllDeviceProperties (DeviceIntPtr device)
3184642e01fSmrg{
3194642e01fSmrg    XIPropertyPtr               prop, next;
3204642e01fSmrg    XIPropertyHandlerPtr        curr_handler, next_handler;
3214642e01fSmrg    devicePropertyNotify        event;
3224642e01fSmrg
3234642e01fSmrg    for (prop = device->properties.properties; prop; prop = next)
3244642e01fSmrg    {
3254642e01fSmrg        next = prop->next;
3264642e01fSmrg
3274642e01fSmrg        event.type      = DevicePropertyNotify;
3284642e01fSmrg        event.deviceid  = device->id;
3294642e01fSmrg        event.state     = PropertyDelete;
3304642e01fSmrg        event.atom      = prop->propertyName;
3314642e01fSmrg        event.time      = currentTime.milliseconds;
3324642e01fSmrg        SendEventToAllWindows(device, DevicePropertyNotifyMask,
3334642e01fSmrg                (xEvent*)&event, 1);
3344642e01fSmrg
3354642e01fSmrg        XIDestroyDeviceProperty(prop);
3364642e01fSmrg    }
3374642e01fSmrg
3384642e01fSmrg    /* Now free all handlers */
3394642e01fSmrg    curr_handler = device->properties.handlers;
3404642e01fSmrg    while(curr_handler)
3414642e01fSmrg    {
3424642e01fSmrg        next_handler = curr_handler->next;
3434642e01fSmrg        xfree(curr_handler);
3444642e01fSmrg        curr_handler = next_handler;
3454642e01fSmrg    }
3464642e01fSmrg}
3474642e01fSmrg
3484642e01fSmrg
3494642e01fSmrgint
3504642e01fSmrgXIDeleteDeviceProperty (DeviceIntPtr device, Atom property, Bool fromClient)
3514642e01fSmrg{
3524642e01fSmrg    XIPropertyPtr               prop, *prev;
3534642e01fSmrg    devicePropertyNotify        event;
3544642e01fSmrg    int                         rc = Success;
3554642e01fSmrg
3564642e01fSmrg    for (prev = &device->properties.properties; (prop = *prev); prev = &(prop->next))
3574642e01fSmrg        if (prop->propertyName == property)
3584642e01fSmrg            break;
3594642e01fSmrg
3604642e01fSmrg    if (fromClient && !prop->deletable)
3614642e01fSmrg        return BadAccess;
3624642e01fSmrg
3634642e01fSmrg    /* Ask handlers if we may delete the property */
3644642e01fSmrg    if (device->properties.handlers)
3654642e01fSmrg    {
3664642e01fSmrg        XIPropertyHandlerPtr handler = device->properties.handlers;
3674642e01fSmrg        while(handler)
3684642e01fSmrg        {
3694642e01fSmrg            if (handler->DeleteProperty)
3704642e01fSmrg                rc = handler->DeleteProperty(device, prop->propertyName);
3714642e01fSmrg            if (rc != Success)
3724642e01fSmrg                return (rc);
3734642e01fSmrg            handler = handler->next;
3744642e01fSmrg        }
3754642e01fSmrg    }
3764642e01fSmrg
3774642e01fSmrg    if (prop)
3784642e01fSmrg    {
3794642e01fSmrg        *prev = prop->next;
3804642e01fSmrg        event.type      = DevicePropertyNotify;
3814642e01fSmrg        event.deviceid  = device->id;
3824642e01fSmrg        event.state     = PropertyDelete;
3834642e01fSmrg        event.atom      = prop->propertyName;
3844642e01fSmrg        event.time      = currentTime.milliseconds;
3854642e01fSmrg        SendEventToAllWindows(device, DevicePropertyNotifyMask,
3864642e01fSmrg                              (xEvent*)&event, 1);
3874642e01fSmrg        XIDestroyDeviceProperty (prop);
3884642e01fSmrg    }
3894642e01fSmrg
3904642e01fSmrg    return Success;
3914642e01fSmrg}
3924642e01fSmrg
3934642e01fSmrgint
3944642e01fSmrgXIChangeDeviceProperty (DeviceIntPtr dev, Atom property, Atom type,
3954642e01fSmrg                        int format, int mode, unsigned long len,
3964642e01fSmrg                        pointer value, Bool sendevent)
3974642e01fSmrg{
3984642e01fSmrg    XIPropertyPtr               prop;
3994642e01fSmrg    devicePropertyNotify        event;
4004642e01fSmrg    int                         size_in_bytes;
4014642e01fSmrg    int                         total_size;
4024642e01fSmrg    unsigned long               total_len;
4034642e01fSmrg    XIPropertyValuePtr          prop_value;
4044642e01fSmrg    XIPropertyValueRec          new_value;
4054642e01fSmrg    Bool                        add = FALSE;
4064642e01fSmrg    int                         rc;
4074642e01fSmrg
4084642e01fSmrg    size_in_bytes = format >> 3;
4094642e01fSmrg
4104642e01fSmrg    /* first see if property already exists */
4114642e01fSmrg    prop = XIFetchDeviceProperty (dev, property);
4124642e01fSmrg    if (!prop)   /* just add to list */
4134642e01fSmrg    {
4144642e01fSmrg        prop = XICreateDeviceProperty (property);
4154642e01fSmrg        if (!prop)
4164642e01fSmrg            return(BadAlloc);
4174642e01fSmrg        add = TRUE;
4184642e01fSmrg        mode = PropModeReplace;
4194642e01fSmrg    }
4204642e01fSmrg    prop_value = &prop->value;
4214642e01fSmrg
4224642e01fSmrg    /* To append or prepend to a property the request format and type
4234642e01fSmrg     must match those of the already defined property.  The
4244642e01fSmrg     existing format and type are irrelevant when using the mode
4254642e01fSmrg     "PropModeReplace" since they will be written over. */
4264642e01fSmrg
4274642e01fSmrg    if ((format != prop_value->format) && (mode != PropModeReplace))
4284642e01fSmrg        return(BadMatch);
4294642e01fSmrg    if ((prop_value->type != type) && (mode != PropModeReplace))
4304642e01fSmrg        return(BadMatch);
4314642e01fSmrg    new_value = *prop_value;
4324642e01fSmrg    if (mode == PropModeReplace)
4334642e01fSmrg        total_len = len;
4344642e01fSmrg    else
4354642e01fSmrg        total_len = prop_value->size + len;
4364642e01fSmrg
4374642e01fSmrg    if (mode == PropModeReplace || len > 0)
4384642e01fSmrg    {
4394642e01fSmrg        pointer            new_data = NULL, old_data = NULL;
4404642e01fSmrg
4414642e01fSmrg        total_size = total_len * size_in_bytes;
4424642e01fSmrg        new_value.data = (pointer)xalloc (total_size);
4434642e01fSmrg        if (!new_value.data && total_size)
4444642e01fSmrg        {
4454642e01fSmrg            if (add)
4464642e01fSmrg                XIDestroyDeviceProperty (prop);
4474642e01fSmrg            return BadAlloc;
4484642e01fSmrg        }
4494642e01fSmrg        new_value.size = len;
4504642e01fSmrg        new_value.type = type;
4514642e01fSmrg        new_value.format = format;
4524642e01fSmrg
4534642e01fSmrg        switch (mode) {
4544642e01fSmrg        case PropModeReplace:
4554642e01fSmrg            new_data = new_value.data;
4564642e01fSmrg            old_data = NULL;
4574642e01fSmrg            break;
4584642e01fSmrg        case PropModeAppend:
4594642e01fSmrg            new_data = (pointer) (((char *) new_value.data) +
4604642e01fSmrg                                  (prop_value->size * size_in_bytes));
4614642e01fSmrg            old_data = new_value.data;
4624642e01fSmrg            break;
4634642e01fSmrg        case PropModePrepend:
4644642e01fSmrg            new_data = new_value.data;
4654642e01fSmrg            old_data = (pointer) (((char *) new_value.data) +
4664642e01fSmrg                                  (prop_value->size * size_in_bytes));
4674642e01fSmrg            break;
4684642e01fSmrg        }
4694642e01fSmrg        if (new_data)
4704642e01fSmrg            memcpy ((char *) new_data, (char *) value, len * size_in_bytes);
4714642e01fSmrg        if (old_data)
4724642e01fSmrg            memcpy ((char *) old_data, (char *) prop_value->data,
4734642e01fSmrg                    prop_value->size * size_in_bytes);
4744642e01fSmrg
4754642e01fSmrg        if (dev->properties.handlers)
4764642e01fSmrg        {
4774642e01fSmrg            XIPropertyHandlerPtr handler;
4784642e01fSmrg            BOOL checkonly = TRUE;
4794642e01fSmrg            /* run through all handlers with checkonly TRUE, then again with
4804642e01fSmrg             * checkonly FALSE. Handlers MUST return error codes on the
4814642e01fSmrg             * checkonly run, errors on the second run are ignored */
4824642e01fSmrg            do
4834642e01fSmrg            {
4844642e01fSmrg                handler = dev->properties.handlers;
4854642e01fSmrg                while(handler)
4864642e01fSmrg                {
4874642e01fSmrg                    if (handler->SetProperty)
4884642e01fSmrg                    {
4894642e01fSmrg                        rc = handler->SetProperty(dev, prop->propertyName,
4904642e01fSmrg                                &new_value, checkonly);
4914642e01fSmrg                        if (checkonly && rc != Success)
4924642e01fSmrg                        {
4934642e01fSmrg                            if (new_value.data)
4944642e01fSmrg                                xfree (new_value.data);
4954642e01fSmrg                            return (rc);
4964642e01fSmrg                        }
4974642e01fSmrg                    }
4984642e01fSmrg                    handler = handler->next;
4994642e01fSmrg                }
5004642e01fSmrg                checkonly = !checkonly;
5014642e01fSmrg            } while (!checkonly);
5024642e01fSmrg        }
5034642e01fSmrg        if (prop_value->data)
5044642e01fSmrg            xfree (prop_value->data);
5054642e01fSmrg        *prop_value = new_value;
5064642e01fSmrg    } else if (len == 0)
5074642e01fSmrg    {
5084642e01fSmrg        /* do nothing */
5094642e01fSmrg    }
5104642e01fSmrg
5114642e01fSmrg    if (add)
5124642e01fSmrg    {
5134642e01fSmrg        prop->next = dev->properties.properties;
5144642e01fSmrg        dev->properties.properties = prop;
5154642e01fSmrg    }
5164642e01fSmrg
5174642e01fSmrg    if (sendevent)
5184642e01fSmrg    {
5194642e01fSmrg        event.type      = DevicePropertyNotify;
5204642e01fSmrg        event.deviceid  = dev->id;
5214642e01fSmrg        event.state     = PropertyNewValue;
5224642e01fSmrg        event.atom      = prop->propertyName;
5234642e01fSmrg        event.time      = currentTime.milliseconds;
5244642e01fSmrg        SendEventToAllWindows(dev, DevicePropertyNotifyMask,
5254642e01fSmrg                              (xEvent*)&event, 1);
5264642e01fSmrg    }
5274642e01fSmrg    return(Success);
5284642e01fSmrg}
5294642e01fSmrg
5304642e01fSmrgint
5314642e01fSmrgXIGetDeviceProperty (DeviceIntPtr dev, Atom property, XIPropertyValuePtr *value)
5324642e01fSmrg{
5334642e01fSmrg    XIPropertyPtr   prop = XIFetchDeviceProperty (dev, property);
5344642e01fSmrg    int rc;
5354642e01fSmrg
5364642e01fSmrg    if (!prop)
5374642e01fSmrg    {
5384642e01fSmrg        *value = NULL;
5394642e01fSmrg        return BadAtom;
5404642e01fSmrg    }
5414642e01fSmrg
5424642e01fSmrg    /* If we can, try to update the property value first */
5434642e01fSmrg    if (dev->properties.handlers)
5444642e01fSmrg    {
5454642e01fSmrg        XIPropertyHandlerPtr handler = dev->properties.handlers;
5464642e01fSmrg        while(handler)
5474642e01fSmrg        {
5484642e01fSmrg            if (handler->GetProperty)
5494642e01fSmrg            {
5504642e01fSmrg                rc = handler->GetProperty(dev, prop->propertyName);
5514642e01fSmrg                if (rc != Success)
5524642e01fSmrg                {
5534642e01fSmrg                    *value = NULL;
5544642e01fSmrg                    return rc;
5554642e01fSmrg                }
5564642e01fSmrg            }
5574642e01fSmrg            handler = handler->next;
5584642e01fSmrg        }
5594642e01fSmrg    }
5604642e01fSmrg
5614642e01fSmrg    *value = &prop->value;
5624642e01fSmrg    return Success;
5634642e01fSmrg}
5644642e01fSmrg
5654642e01fSmrgint
5664642e01fSmrgXISetDevicePropertyDeletable(DeviceIntPtr dev, Atom property, Bool deletable)
5674642e01fSmrg{
5684642e01fSmrg    XIPropertyPtr prop = XIFetchDeviceProperty(dev, property);
5694642e01fSmrg
5704642e01fSmrg    if (!prop)
5714642e01fSmrg        return BadAtom;
5724642e01fSmrg
5734642e01fSmrg    prop->deletable = deletable;
5744642e01fSmrg    return Success;
5754642e01fSmrg}
5764642e01fSmrg
5774642e01fSmrgint
5784642e01fSmrgProcXListDeviceProperties (ClientPtr client)
5794642e01fSmrg{
5804642e01fSmrg    Atom                        *pAtoms = NULL, *temppAtoms;
5814642e01fSmrg    xListDevicePropertiesReply  rep;
5824642e01fSmrg    int                         numProps = 0;
5834642e01fSmrg    DeviceIntPtr                dev;
5844642e01fSmrg    XIPropertyPtr               prop;
5854642e01fSmrg    int                         rc = Success;
5864642e01fSmrg
5874642e01fSmrg    REQUEST(xListDevicePropertiesReq);
5884642e01fSmrg    REQUEST_SIZE_MATCH(xListDevicePropertiesReq);
5894642e01fSmrg
5904642e01fSmrg    rc = dixLookupDevice (&dev, stuff->deviceid, client, DixReadAccess);
5914642e01fSmrg    if (rc != Success)
5924642e01fSmrg        return rc;
5934642e01fSmrg
5944642e01fSmrg    for (prop = dev->properties.properties; prop; prop = prop->next)
5954642e01fSmrg        numProps++;
5964642e01fSmrg    if (numProps)
5974642e01fSmrg        if(!(pAtoms = (Atom *)xalloc(numProps * sizeof(Atom))))
5984642e01fSmrg            return(BadAlloc);
5994642e01fSmrg
6004642e01fSmrg    rep.repType = X_Reply;
6014642e01fSmrg    rep.RepType = X_ListDeviceProperties;
6024642e01fSmrg    rep.length = (numProps * sizeof(Atom)) >> 2;
6034642e01fSmrg    rep.sequenceNumber = client->sequence;
6044642e01fSmrg    rep.nAtoms = numProps;
6054642e01fSmrg    if (client->swapped)
6064642e01fSmrg    {
6074642e01fSmrg        int n;
6084642e01fSmrg        swaps (&rep.sequenceNumber, n);
6094642e01fSmrg        swapl (&rep.length, n);
6104642e01fSmrg        swaps (&rep.nAtoms, n);
6114642e01fSmrg    }
6124642e01fSmrg    temppAtoms = pAtoms;
6134642e01fSmrg    for (prop = dev->properties.properties; prop; prop = prop->next)
6144642e01fSmrg        *temppAtoms++ = prop->propertyName;
6154642e01fSmrg
6164642e01fSmrg    WriteReplyToClient(client, sizeof(xListDevicePropertiesReply), &rep);
6174642e01fSmrg    if (numProps)
6184642e01fSmrg    {
6194642e01fSmrg        client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write;
6204642e01fSmrg        WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms);
6214642e01fSmrg        xfree(pAtoms);
6224642e01fSmrg    }
6234642e01fSmrg    return rc;
6244642e01fSmrg}
6254642e01fSmrg
6264642e01fSmrgint
6274642e01fSmrgProcXChangeDeviceProperty (ClientPtr client)
6284642e01fSmrg{
6294642e01fSmrg    REQUEST(xChangeDevicePropertyReq);
6304642e01fSmrg    DeviceIntPtr        dev;
6314642e01fSmrg    char                format, mode;
6324642e01fSmrg    unsigned long       len;
6334642e01fSmrg    int                 sizeInBytes;
6344642e01fSmrg    int                 totalSize;
6354642e01fSmrg    int                 rc;
6364642e01fSmrg
6374642e01fSmrg    REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq);
6384642e01fSmrg    UpdateCurrentTime();
6394642e01fSmrg    format = stuff->format;
6404642e01fSmrg    mode = stuff->mode;
6414642e01fSmrg    if ((mode != PropModeReplace) && (mode != PropModeAppend) &&
6424642e01fSmrg        (mode != PropModePrepend))
6434642e01fSmrg    {
6444642e01fSmrg        client->errorValue = mode;
6454642e01fSmrg        return BadValue;
6464642e01fSmrg    }
6474642e01fSmrg    if ((format != 8) && (format != 16) && (format != 32))
6484642e01fSmrg    {
6494642e01fSmrg        client->errorValue = format;
6504642e01fSmrg        return BadValue;
6514642e01fSmrg    }
6524642e01fSmrg    len = stuff->nUnits;
6534642e01fSmrg    if (len > ((0xffffffff - sizeof(xChangePropertyReq)) >> 2))
6544642e01fSmrg        return BadLength;
6554642e01fSmrg    sizeInBytes = format>>3;
6564642e01fSmrg    totalSize = len * sizeInBytes;
6574642e01fSmrg    REQUEST_FIXED_SIZE(xChangeDevicePropertyReq, totalSize);
6584642e01fSmrg
6594642e01fSmrg    rc = dixLookupDevice (&dev, stuff->deviceid, client, DixWriteAccess);
6604642e01fSmrg    if (rc != Success)
6614642e01fSmrg        return rc;
6624642e01fSmrg
6634642e01fSmrg    if (!ValidAtom(stuff->property))
6644642e01fSmrg    {
6654642e01fSmrg        client->errorValue = stuff->property;
6664642e01fSmrg        return(BadAtom);
6674642e01fSmrg    }
6684642e01fSmrg    if (!ValidAtom(stuff->type))
6694642e01fSmrg    {
6704642e01fSmrg        client->errorValue = stuff->type;
6714642e01fSmrg        return(BadAtom);
6724642e01fSmrg    }
6734642e01fSmrg
6744642e01fSmrg    rc = XIChangeDeviceProperty(dev, stuff->property,
6754642e01fSmrg                                 stuff->type, (int)format,
6764642e01fSmrg                                 (int)mode, len, (pointer)&stuff[1], TRUE);
6774642e01fSmrg
6784642e01fSmrg    if (rc != Success)
6794642e01fSmrg        client->errorValue = stuff->property;
6804642e01fSmrg    return rc;
6814642e01fSmrg}
6824642e01fSmrg
6834642e01fSmrgint
6844642e01fSmrgProcXDeleteDeviceProperty (ClientPtr client)
6854642e01fSmrg{
6864642e01fSmrg    REQUEST(xDeleteDevicePropertyReq);
6874642e01fSmrg    DeviceIntPtr        dev;
6884642e01fSmrg    int                 rc;
6894642e01fSmrg
6904642e01fSmrg    REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq);
6914642e01fSmrg    UpdateCurrentTime();
6924642e01fSmrg    rc =  dixLookupDevice (&dev, stuff->deviceid, client, DixWriteAccess);
6934642e01fSmrg    if (rc != Success)
6944642e01fSmrg        return rc;
6954642e01fSmrg
6964642e01fSmrg    if (!ValidAtom(stuff->property))
6974642e01fSmrg    {
6984642e01fSmrg        client->errorValue = stuff->property;
6994642e01fSmrg        return (BadAtom);
7004642e01fSmrg    }
7014642e01fSmrg
7024642e01fSmrg    rc = XIDeleteDeviceProperty(dev, stuff->property, TRUE);
7034642e01fSmrg    return rc;
7044642e01fSmrg}
7054642e01fSmrg
7064642e01fSmrgint
7074642e01fSmrgProcXGetDeviceProperty (ClientPtr client)
7084642e01fSmrg{
7094642e01fSmrg    REQUEST(xGetDevicePropertyReq);
7104642e01fSmrg    XIPropertyPtr               prop, *prev;
7114642e01fSmrg    XIPropertyValuePtr          prop_value;
7124642e01fSmrg    unsigned long               n, len, ind;
7134642e01fSmrg    DeviceIntPtr                dev;
7144642e01fSmrg    xGetDevicePropertyReply     reply;
7154642e01fSmrg    int                         rc;
7164642e01fSmrg
7174642e01fSmrg    REQUEST_SIZE_MATCH(xGetDevicePropertyReq);
7184642e01fSmrg    if (stuff->delete)
7194642e01fSmrg        UpdateCurrentTime();
7204642e01fSmrg    rc = dixLookupDevice (&dev, stuff->deviceid, client,
7214642e01fSmrg                           stuff->delete ? DixWriteAccess :
7224642e01fSmrg                           DixReadAccess);
7234642e01fSmrg    if (rc != Success)
7244642e01fSmrg        return rc;
7254642e01fSmrg
7264642e01fSmrg    if (!ValidAtom(stuff->property))
7274642e01fSmrg    {
7284642e01fSmrg        client->errorValue = stuff->property;
7294642e01fSmrg        return(BadAtom);
7304642e01fSmrg    }
7314642e01fSmrg    if ((stuff->delete != xTrue) && (stuff->delete != xFalse))
7324642e01fSmrg    {
7334642e01fSmrg        client->errorValue = stuff->delete;
7344642e01fSmrg        return(BadValue);
7354642e01fSmrg    }
7364642e01fSmrg    if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type))
7374642e01fSmrg    {
7384642e01fSmrg        client->errorValue = stuff->type;
7394642e01fSmrg        return(BadAtom);
7404642e01fSmrg    }
7414642e01fSmrg
7424642e01fSmrg    for (prev = &dev->properties.properties; (prop = *prev); prev = &prop->next)
7434642e01fSmrg        if (prop->propertyName == stuff->property)
7444642e01fSmrg            break;
7454642e01fSmrg
7464642e01fSmrg    reply.repType = X_Reply;
7474642e01fSmrg    reply.RepType = X_GetDeviceProperty;
7484642e01fSmrg    reply.sequenceNumber = client->sequence;
7494642e01fSmrg    reply.deviceid = dev->id;
7504642e01fSmrg    if (!prop)
7514642e01fSmrg    {
7524642e01fSmrg        reply.nItems = 0;
7534642e01fSmrg        reply.length = 0;
7544642e01fSmrg        reply.bytesAfter = 0;
7554642e01fSmrg        reply.propertyType = None;
7564642e01fSmrg        reply.format = 0;
7574642e01fSmrg        WriteReplyToClient(client, sizeof(xGetDevicePropertyReply), &reply);
7584642e01fSmrg        return(client->noClientException);
7594642e01fSmrg    }
7604642e01fSmrg
7614642e01fSmrg    rc = XIGetDeviceProperty(dev, stuff->property, &prop_value);
7624642e01fSmrg    if (rc != Success)
7634642e01fSmrg    {
7644642e01fSmrg        client->errorValue = stuff->property;
7654642e01fSmrg        return rc;
7664642e01fSmrg    }
7674642e01fSmrg
7684642e01fSmrg    /* If the request type and actual type don't match. Return the
7694642e01fSmrg    property information, but not the data. */
7704642e01fSmrg
7714642e01fSmrg    if (((stuff->type != prop_value->type) &&
7724642e01fSmrg         (stuff->type != AnyPropertyType))
7734642e01fSmrg       )
7744642e01fSmrg    {
7754642e01fSmrg        reply.bytesAfter = prop_value->size;
7764642e01fSmrg        reply.format = prop_value->format;
7774642e01fSmrg        reply.length = 0;
7784642e01fSmrg        reply.nItems = 0;
7794642e01fSmrg        reply.propertyType = prop_value->type;
7804642e01fSmrg        WriteReplyToClient(client, sizeof(xGetDevicePropertyReply), &reply);
7814642e01fSmrg        return(client->noClientException);
7824642e01fSmrg    }
7834642e01fSmrg
7844642e01fSmrg/*
7854642e01fSmrg *  Return type, format, value to client
7864642e01fSmrg */
7874642e01fSmrg    n = (prop_value->format/8) * prop_value->size; /* size (bytes) of prop */
7884642e01fSmrg    ind = stuff->longOffset << 2;
7894642e01fSmrg
7904642e01fSmrg   /* If longOffset is invalid such that it causes "len" to
7914642e01fSmrg            be negative, it's a value error. */
7924642e01fSmrg
7934642e01fSmrg    if (n < ind)
7944642e01fSmrg    {
7954642e01fSmrg        client->errorValue = stuff->longOffset;
7964642e01fSmrg        return BadValue;
7974642e01fSmrg    }
7984642e01fSmrg
7994642e01fSmrg    len = min(n - ind, 4 * stuff->longLength);
8004642e01fSmrg
8014642e01fSmrg    reply.bytesAfter = n - (ind + len);
8024642e01fSmrg    reply.format = prop_value->format;
8034642e01fSmrg    reply.length = (len + 3) >> 2;
8044642e01fSmrg    if (prop_value->format)
8054642e01fSmrg        reply.nItems = len / (prop_value->format / 8);
8064642e01fSmrg    else
8074642e01fSmrg        reply.nItems = 0;
8084642e01fSmrg    reply.propertyType = prop_value->type;
8094642e01fSmrg
8104642e01fSmrg    if (stuff->delete && (reply.bytesAfter == 0))
8114642e01fSmrg    {
8124642e01fSmrg        devicePropertyNotify    event;
8134642e01fSmrg
8144642e01fSmrg        event.type      = DevicePropertyNotify;
8154642e01fSmrg        event.deviceid  = dev->id;
8164642e01fSmrg        event.state     = PropertyDelete;
8174642e01fSmrg        event.atom      = prop->propertyName;
8184642e01fSmrg        event.time      = currentTime.milliseconds;
8194642e01fSmrg        SendEventToAllWindows(dev, DevicePropertyNotifyMask,
8204642e01fSmrg                              (xEvent*)&event, 1);
8214642e01fSmrg    }
8224642e01fSmrg
8234642e01fSmrg    WriteReplyToClient(client, sizeof(xGenericReply), &reply);
8244642e01fSmrg    if (len)
8254642e01fSmrg    {
8264642e01fSmrg        switch (reply.format) {
8274642e01fSmrg        case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break;
8284642e01fSmrg        case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break;
8294642e01fSmrg        default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break;
8304642e01fSmrg        }
8314642e01fSmrg        WriteSwappedDataToClient(client, len,
8324642e01fSmrg                                 (char *)prop_value->data + ind);
8334642e01fSmrg    }
8344642e01fSmrg
8354642e01fSmrg    if (stuff->delete && (reply.bytesAfter == 0))
8364642e01fSmrg    { /* delete the Property */
8374642e01fSmrg        *prev = prop->next;
8384642e01fSmrg        XIDestroyDeviceProperty (prop);
8394642e01fSmrg    }
8404642e01fSmrg    return(client->noClientException);
8414642e01fSmrg}
8424642e01fSmrg
8434642e01fSmrg
8444642e01fSmrgint
8454642e01fSmrgSProcXListDeviceProperties (ClientPtr client)
8464642e01fSmrg{
8474642e01fSmrg    char n;
8484642e01fSmrg    REQUEST(xListDevicePropertiesReq);
8494642e01fSmrg
8504642e01fSmrg    swaps(&stuff->length, n);
8514642e01fSmrg
8524642e01fSmrg    REQUEST_SIZE_MATCH(xListDevicePropertiesReq);
8534642e01fSmrg    return (ProcXListDeviceProperties(client));
8544642e01fSmrg}
8554642e01fSmrg
8564642e01fSmrgint
8574642e01fSmrgSProcXChangeDeviceProperty (ClientPtr client)
8584642e01fSmrg{
8594642e01fSmrg    char n;
8604642e01fSmrg    REQUEST(xChangeDevicePropertyReq);
8614642e01fSmrg
8624642e01fSmrg    swaps(&stuff->length, n);
8634642e01fSmrg    swapl(&stuff->property, n);
8644642e01fSmrg    swapl(&stuff->type, n);
8654642e01fSmrg    swapl(&stuff->nUnits, n);
8664642e01fSmrg    REQUEST_SIZE_MATCH(xChangeDevicePropertyReq);
8674642e01fSmrg    return (ProcXChangeDeviceProperty(client));
8684642e01fSmrg}
8694642e01fSmrg
8704642e01fSmrgint
8714642e01fSmrgSProcXDeleteDeviceProperty (ClientPtr client)
8724642e01fSmrg{
8734642e01fSmrg    char n;
8744642e01fSmrg    REQUEST(xDeleteDevicePropertyReq);
8754642e01fSmrg
8764642e01fSmrg    swaps(&stuff->length, n);
8774642e01fSmrg    swapl(&stuff->property, n);
8784642e01fSmrg    REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq);
8794642e01fSmrg    return (ProcXDeleteDeviceProperty(client));
8804642e01fSmrg}
8814642e01fSmrg
8824642e01fSmrgint
8834642e01fSmrgSProcXGetDeviceProperty (ClientPtr client)
8844642e01fSmrg{
8854642e01fSmrg    char n;
8864642e01fSmrg    REQUEST(xGetDevicePropertyReq);
8874642e01fSmrg
8884642e01fSmrg    swaps(&stuff->length, n);
8894642e01fSmrg    swapl(&stuff->property, n);
8904642e01fSmrg    swapl(&stuff->type, n);
8914642e01fSmrg    swapl(&stuff->longOffset, n);
8924642e01fSmrg    swapl(&stuff->longLength, n);
8934642e01fSmrg    REQUEST_SIZE_MATCH(xGetDevicePropertyReq);
8944642e01fSmrg    return (ProcXGetDeviceProperty(client));
8954642e01fSmrg}
8964642e01fSmrg
8974642e01fSmrg
8984642e01fSmrg/* Reply swapping */
8994642e01fSmrg
9004642e01fSmrgvoid
9014642e01fSmrgSRepXListDeviceProperties(ClientPtr client, int size,
9024642e01fSmrg                          xListDevicePropertiesReply *rep)
9034642e01fSmrg{
9044642e01fSmrg    char n;
9054642e01fSmrg    swaps(&rep->sequenceNumber, n);
9064642e01fSmrg    swapl(&rep->length, n);
9074642e01fSmrg    swaps(&rep->nAtoms, n);
9084642e01fSmrg    /* properties will be swapped later, see ProcXListDeviceProperties */
9094642e01fSmrg    WriteToClient(client, size, (char*)rep);
9104642e01fSmrg}
9114642e01fSmrg
9124642e01fSmrgvoid
9134642e01fSmrgSRepXGetDeviceProperty(ClientPtr client, int size,
9144642e01fSmrg                       xGetDevicePropertyReply *rep)
9154642e01fSmrg{
9164642e01fSmrg    char n;
9174642e01fSmrg
9184642e01fSmrg    swaps(&rep->sequenceNumber, n);
9194642e01fSmrg    swapl(&rep->length, n);
9204642e01fSmrg    swapl(&rep->propertyType, n);
9214642e01fSmrg    swapl(&rep->bytesAfter, n);
9224642e01fSmrg    swapl(&rep->nItems, n);
9234642e01fSmrg    /* data will be swapped, see ProcXGetDeviceProperty */
9244642e01fSmrg    WriteToClient(client, size, (char*)rep);
9254642e01fSmrg}
926