1706f2543Smrg/*
2706f2543Smrg * Copyright © 2006 Keith Packard
3706f2543Smrg * Copyright © 2008 Peter Hutterer
4706f2543Smrg *
5706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
6706f2543Smrg * copy of this software and associated documentation files (the "Software"),
7706f2543Smrg * to deal in the Software without restriction, including without limitation
8706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
10706f2543Smrg * Software is furnished to do so, subject to the following conditions:
11706f2543Smrg *
12706f2543Smrg * The above copyright notice and this permission notice (including the next
13706f2543Smrg * paragraph) shall be included in all copies or substantial portions of the
14706f2543Smrg * Software.
15706f2543Smrg *
16706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WAXIANTY OF ANY KIND, EXPRESS OR
17706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WAXIANTIES OF MERCHANTABILITY,
18706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19706f2543Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20706f2543Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21706f2543Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22706f2543Smrg * DEALINGS IN THE SOFTWARE.
23706f2543Smrg *
24706f2543Smrg */
25706f2543Smrg
26706f2543Smrg/* This code is a modified version of randr/rrproperty.c */
27706f2543Smrg
28706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
29706f2543Smrg#include <dix-config.h>
30706f2543Smrg#endif
31706f2543Smrg
32706f2543Smrg#include "dix.h"
33706f2543Smrg#include "inputstr.h"
34706f2543Smrg#include <X11/extensions/XI.h>
35706f2543Smrg#include <X11/Xatom.h>
36706f2543Smrg#include <X11/extensions/XIproto.h>
37706f2543Smrg#include <X11/extensions/XI2proto.h>
38706f2543Smrg#include "exglobals.h"
39706f2543Smrg#include "exevents.h"
40706f2543Smrg#include "swaprep.h"
41706f2543Smrg
42706f2543Smrg#include "xiproperty.h"
43706f2543Smrg#include "xserver-properties.h"
44706f2543Smrg
45706f2543Smrg/**
46706f2543Smrg * Properties used or alloced from inside the server.
47706f2543Smrg */
48706f2543Smrgstatic struct dev_properties
49706f2543Smrg{
50706f2543Smrg    Atom type;
51706f2543Smrg    char *name;
52706f2543Smrg} dev_properties[] = {
53706f2543Smrg    {0, XI_PROP_ENABLED},
54706f2543Smrg    {0, XI_PROP_XTEST_DEVICE},
55706f2543Smrg    {0, XATOM_FLOAT},
56706f2543Smrg    {0, ACCEL_PROP_PROFILE_NUMBER},
57706f2543Smrg    {0, ACCEL_PROP_CONSTANT_DECELERATION},
58706f2543Smrg    {0, ACCEL_PROP_ADAPTIVE_DECELERATION},
59706f2543Smrg    {0, ACCEL_PROP_VELOCITY_SCALING},
60706f2543Smrg    {0, AXIS_LABEL_PROP},
61706f2543Smrg    {0, AXIS_LABEL_PROP_REL_X},
62706f2543Smrg    {0, AXIS_LABEL_PROP_REL_Y},
63706f2543Smrg    {0, AXIS_LABEL_PROP_REL_Z},
64706f2543Smrg    {0, AXIS_LABEL_PROP_REL_RX},
65706f2543Smrg    {0, AXIS_LABEL_PROP_REL_RY},
66706f2543Smrg    {0, AXIS_LABEL_PROP_REL_RZ},
67706f2543Smrg    {0, AXIS_LABEL_PROP_REL_HWHEEL},
68706f2543Smrg    {0, AXIS_LABEL_PROP_REL_DIAL},
69706f2543Smrg    {0, AXIS_LABEL_PROP_REL_WHEEL},
70706f2543Smrg    {0, AXIS_LABEL_PROP_REL_MISC},
71706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_X},
72706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_Y},
73706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_Z},
74706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_RX},
75706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_RY},
76706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_RZ},
77706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_THROTTLE},
78706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_RUDDER},
79706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_WHEEL},
80706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_GAS},
81706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_BRAKE},
82706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_HAT0X},
83706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_HAT0Y},
84706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_HAT1X},
85706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_HAT1Y},
86706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_HAT2X},
87706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_HAT2Y},
88706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_HAT3X},
89706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_HAT3Y},
90706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_PRESSURE},
91706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_DISTANCE},
92706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_TILT_X},
93706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_TILT_Y},
94706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_TOOL_WIDTH},
95706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_VOLUME},
96706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_MT_TOUCH_MAJOR},
97706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_MT_TOUCH_MINOR},
98706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_MT_WIDTH_MAJOR},
99706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_MT_WIDTH_MINOR},
100706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_MT_ORIENTATION},
101706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_MT_POSITION_X},
102706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_MT_POSITION_Y},
103706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_MT_TOOL_TYPE},
104706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_MT_BLOB_ID},
105706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_MT_TRACKING_ID},
106706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_MT_PRESSURE},
107706f2543Smrg    {0, AXIS_LABEL_PROP_ABS_MISC},
108706f2543Smrg
109706f2543Smrg    {0, BTN_LABEL_PROP},
110706f2543Smrg    {0, BTN_LABEL_PROP_BTN_UNKNOWN},
111706f2543Smrg    {0, BTN_LABEL_PROP_BTN_WHEEL_UP},
112706f2543Smrg    {0, BTN_LABEL_PROP_BTN_WHEEL_DOWN},
113706f2543Smrg    {0, BTN_LABEL_PROP_BTN_HWHEEL_LEFT},
114706f2543Smrg    {0, BTN_LABEL_PROP_BTN_HWHEEL_RIGHT},
115706f2543Smrg    {0, BTN_LABEL_PROP_BTN_0},
116706f2543Smrg    {0, BTN_LABEL_PROP_BTN_1},
117706f2543Smrg    {0, BTN_LABEL_PROP_BTN_2},
118706f2543Smrg    {0, BTN_LABEL_PROP_BTN_3},
119706f2543Smrg    {0, BTN_LABEL_PROP_BTN_4},
120706f2543Smrg    {0, BTN_LABEL_PROP_BTN_5},
121706f2543Smrg    {0, BTN_LABEL_PROP_BTN_6},
122706f2543Smrg    {0, BTN_LABEL_PROP_BTN_7},
123706f2543Smrg    {0, BTN_LABEL_PROP_BTN_8},
124706f2543Smrg    {0, BTN_LABEL_PROP_BTN_9},
125706f2543Smrg
126706f2543Smrg    {0, BTN_LABEL_PROP_BTN_LEFT},
127706f2543Smrg    {0, BTN_LABEL_PROP_BTN_RIGHT},
128706f2543Smrg    {0, BTN_LABEL_PROP_BTN_MIDDLE},
129706f2543Smrg    {0, BTN_LABEL_PROP_BTN_SIDE},
130706f2543Smrg    {0, BTN_LABEL_PROP_BTN_EXTRA},
131706f2543Smrg    {0, BTN_LABEL_PROP_BTN_FORWARD},
132706f2543Smrg    {0, BTN_LABEL_PROP_BTN_BACK},
133706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TASK},
134706f2543Smrg
135706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TRIGGER},
136706f2543Smrg    {0, BTN_LABEL_PROP_BTN_THUMB},
137706f2543Smrg    {0, BTN_LABEL_PROP_BTN_THUMB2},
138706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TOP},
139706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TOP2},
140706f2543Smrg    {0, BTN_LABEL_PROP_BTN_PINKIE},
141706f2543Smrg    {0, BTN_LABEL_PROP_BTN_BASE},
142706f2543Smrg    {0, BTN_LABEL_PROP_BTN_BASE2},
143706f2543Smrg    {0, BTN_LABEL_PROP_BTN_BASE3},
144706f2543Smrg    {0, BTN_LABEL_PROP_BTN_BASE4},
145706f2543Smrg    {0, BTN_LABEL_PROP_BTN_BASE5},
146706f2543Smrg    {0, BTN_LABEL_PROP_BTN_BASE6},
147706f2543Smrg    {0, BTN_LABEL_PROP_BTN_DEAD},
148706f2543Smrg
149706f2543Smrg    {0, BTN_LABEL_PROP_BTN_A},
150706f2543Smrg    {0, BTN_LABEL_PROP_BTN_B},
151706f2543Smrg    {0, BTN_LABEL_PROP_BTN_C},
152706f2543Smrg    {0, BTN_LABEL_PROP_BTN_X},
153706f2543Smrg    {0, BTN_LABEL_PROP_BTN_Y},
154706f2543Smrg    {0, BTN_LABEL_PROP_BTN_Z},
155706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TL},
156706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TR},
157706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TL2},
158706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TR2},
159706f2543Smrg    {0, BTN_LABEL_PROP_BTN_SELECT},
160706f2543Smrg    {0, BTN_LABEL_PROP_BTN_START},
161706f2543Smrg    {0, BTN_LABEL_PROP_BTN_MODE},
162706f2543Smrg    {0, BTN_LABEL_PROP_BTN_THUMBL},
163706f2543Smrg    {0, BTN_LABEL_PROP_BTN_THUMBR},
164706f2543Smrg
165706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TOOL_PEN},
166706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TOOL_RUBBER},
167706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TOOL_BRUSH},
168706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TOOL_PENCIL},
169706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TOOL_AIRBRUSH},
170706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TOOL_FINGER},
171706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TOOL_MOUSE},
172706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TOOL_LENS},
173706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TOUCH},
174706f2543Smrg    {0, BTN_LABEL_PROP_BTN_STYLUS},
175706f2543Smrg    {0, BTN_LABEL_PROP_BTN_STYLUS2},
176706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TOOL_DOUBLETAP},
177706f2543Smrg    {0, BTN_LABEL_PROP_BTN_TOOL_TRIPLETAP},
178706f2543Smrg
179706f2543Smrg    {0, BTN_LABEL_PROP_BTN_GEAR_DOWN},
180706f2543Smrg    {0, BTN_LABEL_PROP_BTN_GEAR_UP},
181706f2543Smrg
182706f2543Smrg    {0, XI_PROP_TRANSFORM}
183706f2543Smrg};
184706f2543Smrg
185706f2543Smrgstatic long XIPropHandlerID = 1;
186706f2543Smrg
187706f2543Smrgstatic void send_property_event(DeviceIntPtr dev, Atom property, int what)
188706f2543Smrg{
189706f2543Smrg        devicePropertyNotify    event;
190706f2543Smrg        xXIPropertyEvent        xi2;
191706f2543Smrg        int state;
192706f2543Smrg
193706f2543Smrg        if (what == XIPropertyDeleted)
194706f2543Smrg            state = PropertyDelete;
195706f2543Smrg        else
196706f2543Smrg            state = PropertyNewValue;
197706f2543Smrg
198706f2543Smrg        event.type      = DevicePropertyNotify;
199706f2543Smrg        event.deviceid  = dev->id;
200706f2543Smrg        event.state     = state;
201706f2543Smrg        event.atom      = property;
202706f2543Smrg        event.time      = currentTime.milliseconds;
203706f2543Smrg        SendEventToAllWindows(dev, DevicePropertyNotifyMask,
204706f2543Smrg                              (xEvent*)&event, 1);
205706f2543Smrg
206706f2543Smrg        xi2.type        = GenericEvent;
207706f2543Smrg        xi2.extension   = IReqCode;
208706f2543Smrg        xi2.length      = 0;
209706f2543Smrg        xi2.evtype      = XI_PropertyEvent;
210706f2543Smrg        xi2.deviceid    = dev->id;
211706f2543Smrg        xi2.time        = currentTime.milliseconds;
212706f2543Smrg        xi2.property    = property;
213706f2543Smrg        xi2.what        = what;
214706f2543Smrg        SendEventToAllWindows(dev, GetEventFilter(dev, (xEvent*)&xi2),
215706f2543Smrg                              (xEvent*)&xi2, 1);
216706f2543Smrg}
217706f2543Smrg
218706f2543Smrgstatic int list_atoms(DeviceIntPtr dev, int *natoms, Atom **atoms_return)
219706f2543Smrg{
220706f2543Smrg    XIPropertyPtr prop;
221706f2543Smrg    Atom *atoms         = NULL;
222706f2543Smrg    int nprops          = 0;
223706f2543Smrg
224706f2543Smrg    for (prop = dev->properties.properties; prop; prop = prop->next)
225706f2543Smrg        nprops++;
226706f2543Smrg    if (nprops)
227706f2543Smrg    {
228706f2543Smrg        Atom *a;
229706f2543Smrg
230706f2543Smrg        atoms = malloc(nprops * sizeof(Atom));
231706f2543Smrg        if(!atoms)
232706f2543Smrg            return BadAlloc;
233706f2543Smrg        a = atoms;
234706f2543Smrg        for (prop = dev->properties.properties; prop; prop = prop->next, a++)
235706f2543Smrg            *a = prop->propertyName;
236706f2543Smrg    }
237706f2543Smrg
238706f2543Smrg    *natoms = nprops;
239706f2543Smrg    *atoms_return = atoms;
240706f2543Smrg    return Success;
241706f2543Smrg}
242706f2543Smrg
243706f2543Smrgstatic int
244706f2543Smrgget_property(ClientPtr client, DeviceIntPtr dev, Atom property, Atom type,
245706f2543Smrg             BOOL delete, int offset, int length,
246706f2543Smrg             int *bytes_after, Atom *type_return, int *format, int *nitems,
247706f2543Smrg             int *length_return, char **data)
248706f2543Smrg{
249706f2543Smrg    unsigned long n, len, ind;
250706f2543Smrg    int rc;
251706f2543Smrg    XIPropertyPtr prop;
252706f2543Smrg    XIPropertyValuePtr prop_value;
253706f2543Smrg
254706f2543Smrg    if (!ValidAtom(property))
255706f2543Smrg    {
256706f2543Smrg        client->errorValue = property;
257706f2543Smrg        return BadAtom;
258706f2543Smrg    }
259706f2543Smrg    if ((delete != xTrue) && (delete != xFalse))
260706f2543Smrg    {
261706f2543Smrg        client->errorValue = delete;
262706f2543Smrg        return BadValue;
263706f2543Smrg    }
264706f2543Smrg
265706f2543Smrg    if ((type != AnyPropertyType) && !ValidAtom(type))
266706f2543Smrg    {
267706f2543Smrg        client->errorValue = type;
268706f2543Smrg        return BadAtom;
269706f2543Smrg    }
270706f2543Smrg
271706f2543Smrg    for (prop = dev->properties.properties; prop; prop = prop->next)
272706f2543Smrg        if (prop->propertyName == property)
273706f2543Smrg            break;
274706f2543Smrg
275706f2543Smrg    if (!prop)
276706f2543Smrg    {
277706f2543Smrg        *bytes_after = 0;
278706f2543Smrg        *type_return = None;
279706f2543Smrg        *format = 0;
280706f2543Smrg        *nitems = 0;
281706f2543Smrg        *length_return = 0;
282706f2543Smrg        return Success;
283706f2543Smrg    }
284706f2543Smrg
285706f2543Smrg    rc = XIGetDeviceProperty(dev, property, &prop_value);
286706f2543Smrg    if (rc != Success)
287706f2543Smrg    {
288706f2543Smrg        client->errorValue = property;
289706f2543Smrg        return rc;
290706f2543Smrg    }
291706f2543Smrg
292706f2543Smrg    /* If the request type and actual type don't match. Return the
293706f2543Smrg    property information, but not the data. */
294706f2543Smrg
295706f2543Smrg    if (((type != prop_value->type) && (type != AnyPropertyType)))
296706f2543Smrg    {
297706f2543Smrg        *bytes_after = prop_value->size;
298706f2543Smrg        *format = prop_value->format;
299706f2543Smrg        *length_return = 0;
300706f2543Smrg        *nitems = 0;
301706f2543Smrg        *type_return = prop_value->type;
302706f2543Smrg        return Success;
303706f2543Smrg    }
304706f2543Smrg
305706f2543Smrg    /* Return type, format, value to client */
306706f2543Smrg    n = (prop_value->format/8) * prop_value->size; /* size (bytes) of prop */
307706f2543Smrg    ind = offset << 2;
308706f2543Smrg
309706f2543Smrg   /* If offset is invalid such that it causes "len" to
310706f2543Smrg            be negative, it's a value error. */
311706f2543Smrg
312706f2543Smrg    if (n < ind)
313706f2543Smrg    {
314706f2543Smrg        client->errorValue = offset;
315706f2543Smrg        return BadValue;
316706f2543Smrg    }
317706f2543Smrg
318706f2543Smrg    len = min(n - ind, 4 * length);
319706f2543Smrg
320706f2543Smrg    *bytes_after = n - (ind + len);
321706f2543Smrg    *format = prop_value->format;
322706f2543Smrg    *length_return = len;
323706f2543Smrg    if (prop_value->format)
324706f2543Smrg        *nitems = len / (prop_value->format / 8);
325706f2543Smrg    else
326706f2543Smrg        *nitems = 0;
327706f2543Smrg    *type_return = prop_value->type;
328706f2543Smrg
329706f2543Smrg    *data = (char*)prop_value->data + ind;
330706f2543Smrg
331706f2543Smrg    return Success;
332706f2543Smrg}
333706f2543Smrg
334706f2543Smrgstatic int
335706f2543Smrgcheck_change_property(ClientPtr client, Atom property, Atom type, int format,
336706f2543Smrg                      int mode, int nitems)
337706f2543Smrg{
338706f2543Smrg    if ((mode != PropModeReplace) && (mode != PropModeAppend) &&
339706f2543Smrg        (mode != PropModePrepend))
340706f2543Smrg    {
341706f2543Smrg        client->errorValue = mode;
342706f2543Smrg        return BadValue;
343706f2543Smrg    }
344706f2543Smrg    if ((format != 8) && (format != 16) && (format != 32))
345706f2543Smrg    {
346706f2543Smrg        client->errorValue = format;
347706f2543Smrg        return BadValue;
348706f2543Smrg    }
349706f2543Smrg
350706f2543Smrg    if (!ValidAtom(property))
351706f2543Smrg    {
352706f2543Smrg        client->errorValue = property;
353706f2543Smrg        return BadAtom;
354706f2543Smrg    }
355706f2543Smrg    if (!ValidAtom(type))
356706f2543Smrg    {
357706f2543Smrg        client->errorValue = type;
358706f2543Smrg        return BadAtom;
359706f2543Smrg    }
360706f2543Smrg
361706f2543Smrg    return Success;
362706f2543Smrg}
363706f2543Smrg
364706f2543Smrgstatic int
365706f2543Smrgchange_property(ClientPtr client, DeviceIntPtr dev, Atom property, Atom type,
366706f2543Smrg                int format, int mode, int len, void *data)
367706f2543Smrg{
368706f2543Smrg    int rc = Success;
369706f2543Smrg
370706f2543Smrg    rc = XIChangeDeviceProperty(dev, property, type, format, mode, len, data, TRUE);
371706f2543Smrg    if (rc != Success)
372706f2543Smrg        client->errorValue = property;
373706f2543Smrg
374706f2543Smrg    return rc;
375706f2543Smrg}
376706f2543Smrg
377706f2543Smrg/**
378706f2543Smrg * Return the atom assigned to the specified string or 0 if the atom isn't known
379706f2543Smrg * to the DIX.
380706f2543Smrg *
381706f2543Smrg * If name is NULL, None is returned.
382706f2543Smrg */
383706f2543SmrgAtom
384706f2543SmrgXIGetKnownProperty(char *name)
385706f2543Smrg{
386706f2543Smrg    int i;
387706f2543Smrg
388706f2543Smrg    if (!name)
389706f2543Smrg        return None;
390706f2543Smrg
391706f2543Smrg    for (i = 0; i < (sizeof(dev_properties)/sizeof(struct dev_properties)); i++)
392706f2543Smrg    {
393706f2543Smrg        if (strcmp(name, dev_properties[i].name) == 0){
394706f2543Smrg            if (dev_properties[i].type == None){
395706f2543Smrg		dev_properties[i].type =
396706f2543Smrg			    MakeAtom(dev_properties[i].name,
397706f2543Smrg			             strlen(dev_properties[i].name),
398706f2543Smrg			             TRUE);
399706f2543Smrg            }
400706f2543Smrg
401706f2543Smrg            return dev_properties[i].type;
402706f2543Smrg        }
403706f2543Smrg    }
404706f2543Smrg
405706f2543Smrg    return 0;
406706f2543Smrg}
407706f2543Smrg
408706f2543Smrgvoid
409706f2543SmrgXIResetProperties(void)
410706f2543Smrg{
411706f2543Smrg    int i;
412706f2543Smrg
413706f2543Smrg    for (i = 0; i < (sizeof(dev_properties)/sizeof(struct dev_properties)); i++)
414706f2543Smrg        dev_properties[i].type = None;
415706f2543Smrg}
416706f2543Smrg
417706f2543Smrg/**
418706f2543Smrg * Convert the given property's value(s) into @nelem_return integer values and
419706f2543Smrg * store them in @buf_return. If @nelem_return is larger than the number of
420706f2543Smrg * values in the property, @nelem_return is set to the number of values in the
421706f2543Smrg * property.
422706f2543Smrg *
423706f2543Smrg * If *@buf_return is NULL and @nelem_return is 0, memory is allocated
424706f2543Smrg * automatically and must be freed by the caller.
425706f2543Smrg *
426706f2543Smrg * Possible return codes.
427706f2543Smrg * Success ... No error.
428706f2543Smrg * BadMatch ... Wrong atom type, atom is not XA_INTEGER
429706f2543Smrg * BadAlloc ... NULL passed as buffer and allocation failed.
430706f2543Smrg * BadLength ... @buff is NULL but @nelem_return is non-zero.
431706f2543Smrg *
432706f2543Smrg * @param val The property value
433706f2543Smrg * @param nelem_return The maximum number of elements to return.
434706f2543Smrg * @param buf_return Pointer to an array of at least @nelem_return values.
435706f2543Smrg * @return Success or the error code if an error occured.
436706f2543Smrg */
437706f2543Smrg_X_EXPORT int
438706f2543SmrgXIPropToInt(XIPropertyValuePtr val, int *nelem_return, int **buf_return)
439706f2543Smrg{
440706f2543Smrg    int i;
441706f2543Smrg    int *buf;
442706f2543Smrg
443706f2543Smrg    if (val->type != XA_INTEGER)
444706f2543Smrg        return BadMatch;
445706f2543Smrg    if (!*buf_return && *nelem_return)
446706f2543Smrg        return BadLength;
447706f2543Smrg
448706f2543Smrg    switch(val->format)
449706f2543Smrg    {
450706f2543Smrg        case 8:
451706f2543Smrg        case 16:
452706f2543Smrg        case 32:
453706f2543Smrg            break;
454706f2543Smrg        default:
455706f2543Smrg            return BadValue;
456706f2543Smrg    }
457706f2543Smrg
458706f2543Smrg    buf = *buf_return;
459706f2543Smrg
460706f2543Smrg    if (!buf && !(*nelem_return))
461706f2543Smrg    {
462706f2543Smrg        buf = calloc(val->size, sizeof(int));
463706f2543Smrg        if (!buf)
464706f2543Smrg            return BadAlloc;
465706f2543Smrg        *buf_return = buf;
466706f2543Smrg        *nelem_return = val->size;
467706f2543Smrg    } else if (val->size < *nelem_return)
468706f2543Smrg        *nelem_return = val->size;
469706f2543Smrg
470706f2543Smrg    for (i = 0; i < val->size && i < *nelem_return; i++)
471706f2543Smrg    {
472706f2543Smrg        switch(val->format)
473706f2543Smrg        {
474706f2543Smrg            case 8:  buf[i] = ((CARD8*)val->data)[i]; break;
475706f2543Smrg            case 16: buf[i] = ((CARD16*)val->data)[i]; break;
476706f2543Smrg            case 32: buf[i] = ((CARD32*)val->data)[i]; break;
477706f2543Smrg        }
478706f2543Smrg    }
479706f2543Smrg
480706f2543Smrg    return Success;
481706f2543Smrg}
482706f2543Smrg
483706f2543Smrg/**
484706f2543Smrg * Convert the given property's value(s) into @nelem_return float values and
485706f2543Smrg * store them in @buf_return. If @nelem_return is larger than the number of
486706f2543Smrg * values in the property, @nelem_return is set to the number of values in the
487706f2543Smrg * property.
488706f2543Smrg *
489706f2543Smrg * If *@buf_return is NULL and @nelem_return is 0, memory is allocated
490706f2543Smrg * automatically and must be freed by the caller.
491706f2543Smrg *
492706f2543Smrg * Possible errors returned:
493706f2543Smrg * Success
494706f2543Smrg * BadMatch ... Wrong atom type, atom is not XA_FLOAT
495706f2543Smrg * BadValue ... Wrong format, format is not 32
496706f2543Smrg * BadAlloc ... NULL passed as buffer and allocation failed.
497706f2543Smrg * BadLength ... @buff is NULL but @nelem_return is non-zero.
498706f2543Smrg *
499706f2543Smrg * @param val The property value
500706f2543Smrg * @param nelem_return The maximum number of elements to return.
501706f2543Smrg * @param buf_return Pointer to an array of at least @nelem_return values.
502706f2543Smrg * @return Success or the error code if an error occured.
503706f2543Smrg */
504706f2543Smrg_X_EXPORT int
505706f2543SmrgXIPropToFloat(XIPropertyValuePtr val, int *nelem_return, float **buf_return)
506706f2543Smrg{
507706f2543Smrg    int i;
508706f2543Smrg    float *buf;
509706f2543Smrg
510706f2543Smrg    if (!val->type || val->type != XIGetKnownProperty(XATOM_FLOAT))
511706f2543Smrg        return BadMatch;
512706f2543Smrg
513706f2543Smrg    if (val->format != 32)
514706f2543Smrg        return BadValue;
515706f2543Smrg    if (!*buf_return && *nelem_return)
516706f2543Smrg        return BadLength;
517706f2543Smrg
518706f2543Smrg    buf = *buf_return;
519706f2543Smrg
520706f2543Smrg    if (!buf && !(*nelem_return))
521706f2543Smrg    {
522706f2543Smrg        buf = calloc(val->size, sizeof(float));
523706f2543Smrg        if (!buf)
524706f2543Smrg            return BadAlloc;
525706f2543Smrg        *buf_return = buf;
526706f2543Smrg        *nelem_return = val->size;
527706f2543Smrg    } else if (val->size < *nelem_return)
528706f2543Smrg        *nelem_return = val->size;
529706f2543Smrg
530706f2543Smrg    for (i = 0; i < val->size && i < *nelem_return; i++)
531706f2543Smrg           buf[i] = ((float*)val->data)[i];
532706f2543Smrg
533706f2543Smrg    return Success;
534706f2543Smrg}
535706f2543Smrg
536706f2543Smrg/* Registers a new property handler on the given device and returns a unique
537706f2543Smrg * identifier for this handler. This identifier is required to unregister the
538706f2543Smrg * property handler again.
539706f2543Smrg * @return The handler's identifier or 0 if an error occured.
540706f2543Smrg */
541706f2543Smrglong
542706f2543SmrgXIRegisterPropertyHandler(DeviceIntPtr         dev,
543706f2543Smrg                          int (*SetProperty) (DeviceIntPtr dev,
544706f2543Smrg                                              Atom property,
545706f2543Smrg                                              XIPropertyValuePtr prop,
546706f2543Smrg                                              BOOL checkonly),
547706f2543Smrg                          int (*GetProperty) (DeviceIntPtr dev,
548706f2543Smrg                                              Atom property),
549706f2543Smrg                          int (*DeleteProperty) (DeviceIntPtr dev,
550706f2543Smrg                                                 Atom property))
551706f2543Smrg{
552706f2543Smrg    XIPropertyHandlerPtr new_handler;
553706f2543Smrg
554706f2543Smrg    new_handler = calloc(1, sizeof(XIPropertyHandler));
555706f2543Smrg    if (!new_handler)
556706f2543Smrg        return 0;
557706f2543Smrg
558706f2543Smrg    new_handler->id = XIPropHandlerID++;
559706f2543Smrg    new_handler->SetProperty = SetProperty;
560706f2543Smrg    new_handler->GetProperty = GetProperty;
561706f2543Smrg    new_handler->DeleteProperty = DeleteProperty;
562706f2543Smrg    new_handler->next = dev->properties.handlers;
563706f2543Smrg    dev->properties.handlers = new_handler;
564706f2543Smrg
565706f2543Smrg    return new_handler->id;
566706f2543Smrg}
567706f2543Smrg
568706f2543Smrgvoid
569706f2543SmrgXIUnregisterPropertyHandler(DeviceIntPtr dev, long id)
570706f2543Smrg{
571706f2543Smrg    XIPropertyHandlerPtr curr, prev = NULL;
572706f2543Smrg
573706f2543Smrg    curr = dev->properties.handlers;
574706f2543Smrg    while(curr && curr->id != id)
575706f2543Smrg    {
576706f2543Smrg        prev = curr;
577706f2543Smrg        curr = curr->next;
578706f2543Smrg    }
579706f2543Smrg
580706f2543Smrg    if (!curr)
581706f2543Smrg        return;
582706f2543Smrg
583706f2543Smrg    if (!prev) /* first one */
584706f2543Smrg        dev->properties.handlers = curr->next;
585706f2543Smrg    else
586706f2543Smrg        prev->next = curr->next;
587706f2543Smrg
588706f2543Smrg    free(curr);
589706f2543Smrg}
590706f2543Smrg
591706f2543Smrgstatic XIPropertyPtr
592706f2543SmrgXICreateDeviceProperty (Atom property)
593706f2543Smrg{
594706f2543Smrg    XIPropertyPtr   prop;
595706f2543Smrg
596706f2543Smrg    prop = (XIPropertyPtr)malloc(sizeof(XIPropertyRec));
597706f2543Smrg    if (!prop)
598706f2543Smrg        return NULL;
599706f2543Smrg
600706f2543Smrg    prop->next          = NULL;
601706f2543Smrg    prop->propertyName  = property;
602706f2543Smrg    prop->value.type   = None;
603706f2543Smrg    prop->value.format = 0;
604706f2543Smrg    prop->value.size   = 0;
605706f2543Smrg    prop->value.data   = NULL;
606706f2543Smrg    prop->deletable    = TRUE;
607706f2543Smrg
608706f2543Smrg    return prop;
609706f2543Smrg}
610706f2543Smrg
611706f2543Smrgstatic XIPropertyPtr
612706f2543SmrgXIFetchDeviceProperty(DeviceIntPtr dev, Atom property)
613706f2543Smrg{
614706f2543Smrg    XIPropertyPtr   prop;
615706f2543Smrg
616706f2543Smrg    for (prop = dev->properties.properties; prop; prop = prop->next)
617706f2543Smrg        if (prop->propertyName == property)
618706f2543Smrg            return prop;
619706f2543Smrg    return NULL;
620706f2543Smrg}
621706f2543Smrg
622706f2543Smrgstatic void
623706f2543SmrgXIDestroyDeviceProperty (XIPropertyPtr prop)
624706f2543Smrg{
625706f2543Smrg    free(prop->value.data);
626706f2543Smrg    free(prop);
627706f2543Smrg}
628706f2543Smrg
629706f2543Smrg/* This function destroys all of the device's property-related stuff,
630706f2543Smrg * including removing all device handlers.
631706f2543Smrg * DO NOT CALL FROM THE DRIVER.
632706f2543Smrg */
633706f2543Smrgvoid
634706f2543SmrgXIDeleteAllDeviceProperties (DeviceIntPtr device)
635706f2543Smrg{
636706f2543Smrg    XIPropertyPtr               prop, next;
637706f2543Smrg    XIPropertyHandlerPtr        curr_handler, next_handler;
638706f2543Smrg
639706f2543Smrg    for (prop = device->properties.properties; prop; prop = next)
640706f2543Smrg    {
641706f2543Smrg        next = prop->next;
642706f2543Smrg        send_property_event(device, prop->propertyName, XIPropertyDeleted);
643706f2543Smrg        XIDestroyDeviceProperty(prop);
644706f2543Smrg    }
645706f2543Smrg
646706f2543Smrg    device->properties.properties = NULL;
647706f2543Smrg
648706f2543Smrg    /* Now free all handlers */
649706f2543Smrg    curr_handler = device->properties.handlers;
650706f2543Smrg    while(curr_handler)
651706f2543Smrg    {
652706f2543Smrg        next_handler = curr_handler->next;
653706f2543Smrg        free(curr_handler);
654706f2543Smrg        curr_handler = next_handler;
655706f2543Smrg    }
656706f2543Smrg
657706f2543Smrg    device->properties.handlers = NULL;
658706f2543Smrg}
659706f2543Smrg
660706f2543Smrg
661706f2543Smrgint
662706f2543SmrgXIDeleteDeviceProperty (DeviceIntPtr device, Atom property, Bool fromClient)
663706f2543Smrg{
664706f2543Smrg    XIPropertyPtr               prop, *prev;
665706f2543Smrg    int                         rc = Success;
666706f2543Smrg
667706f2543Smrg    for (prev = &device->properties.properties; (prop = *prev); prev = &(prop->next))
668706f2543Smrg        if (prop->propertyName == property)
669706f2543Smrg            break;
670706f2543Smrg
671706f2543Smrg    if (!prop)
672706f2543Smrg        return Success;
673706f2543Smrg
674706f2543Smrg    if (fromClient && !prop->deletable)
675706f2543Smrg        return BadAccess;
676706f2543Smrg
677706f2543Smrg    /* Ask handlers if we may delete the property */
678706f2543Smrg    if (device->properties.handlers)
679706f2543Smrg    {
680706f2543Smrg        XIPropertyHandlerPtr handler = device->properties.handlers;
681706f2543Smrg        while(handler)
682706f2543Smrg        {
683706f2543Smrg            if (handler->DeleteProperty)
684706f2543Smrg                rc = handler->DeleteProperty(device, prop->propertyName);
685706f2543Smrg            if (rc != Success)
686706f2543Smrg                return rc;
687706f2543Smrg            handler = handler->next;
688706f2543Smrg        }
689706f2543Smrg    }
690706f2543Smrg
691706f2543Smrg    if (prop)
692706f2543Smrg    {
693706f2543Smrg        *prev = prop->next;
694706f2543Smrg        send_property_event(device, prop->propertyName, XIPropertyDeleted);
695706f2543Smrg        XIDestroyDeviceProperty (prop);
696706f2543Smrg    }
697706f2543Smrg
698706f2543Smrg    return Success;
699706f2543Smrg}
700706f2543Smrg
701706f2543Smrgint
702706f2543SmrgXIChangeDeviceProperty (DeviceIntPtr dev, Atom property, Atom type,
703706f2543Smrg                        int format, int mode, unsigned long len,
704706f2543Smrg                        const pointer value, Bool sendevent)
705706f2543Smrg{
706706f2543Smrg    XIPropertyPtr               prop;
707706f2543Smrg    int                         size_in_bytes;
708706f2543Smrg    int                         total_size;
709706f2543Smrg    unsigned long               total_len;
710706f2543Smrg    XIPropertyValuePtr          prop_value;
711706f2543Smrg    XIPropertyValueRec          new_value;
712706f2543Smrg    Bool                        add = FALSE;
713706f2543Smrg    int                         rc;
714706f2543Smrg
715706f2543Smrg    size_in_bytes = format >> 3;
716706f2543Smrg
717706f2543Smrg    /* first see if property already exists */
718706f2543Smrg    prop = XIFetchDeviceProperty (dev, property);
719706f2543Smrg    if (!prop)   /* just add to list */
720706f2543Smrg    {
721706f2543Smrg        prop = XICreateDeviceProperty (property);
722706f2543Smrg        if (!prop)
723706f2543Smrg            return BadAlloc;
724706f2543Smrg        add = TRUE;
725706f2543Smrg        mode = PropModeReplace;
726706f2543Smrg    }
727706f2543Smrg    prop_value = &prop->value;
728706f2543Smrg
729706f2543Smrg    /* To append or prepend to a property the request format and type
730706f2543Smrg     must match those of the already defined property.  The
731706f2543Smrg     existing format and type are irrelevant when using the mode
732706f2543Smrg     "PropModeReplace" since they will be written over. */
733706f2543Smrg
734706f2543Smrg    if ((format != prop_value->format) && (mode != PropModeReplace))
735706f2543Smrg        return BadMatch;
736706f2543Smrg    if ((prop_value->type != type) && (mode != PropModeReplace))
737706f2543Smrg        return BadMatch;
738706f2543Smrg    new_value = *prop_value;
739706f2543Smrg    if (mode == PropModeReplace)
740706f2543Smrg        total_len = len;
741706f2543Smrg    else
742706f2543Smrg        total_len = prop_value->size + len;
743706f2543Smrg
744706f2543Smrg    if (mode == PropModeReplace || len > 0)
745706f2543Smrg    {
746706f2543Smrg        pointer            new_data = NULL, old_data = NULL;
747706f2543Smrg
748706f2543Smrg        total_size = total_len * size_in_bytes;
749706f2543Smrg        new_value.data = (pointer)malloc(total_size);
750706f2543Smrg        if (!new_value.data && total_size)
751706f2543Smrg        {
752706f2543Smrg            if (add)
753706f2543Smrg                XIDestroyDeviceProperty (prop);
754706f2543Smrg            return BadAlloc;
755706f2543Smrg        }
756bc1411c9Smrg        new_value.size = total_len;
757706f2543Smrg        new_value.type = type;
758706f2543Smrg        new_value.format = format;
759706f2543Smrg
760706f2543Smrg        switch (mode) {
761706f2543Smrg        case PropModeReplace:
762706f2543Smrg            new_data = new_value.data;
763706f2543Smrg            old_data = NULL;
764706f2543Smrg            break;
765706f2543Smrg        case PropModeAppend:
766706f2543Smrg            new_data = (pointer) (((char *) new_value.data) +
767706f2543Smrg                                  (prop_value->size * size_in_bytes));
768706f2543Smrg            old_data = new_value.data;
769706f2543Smrg            break;
770706f2543Smrg        case PropModePrepend:
771706f2543Smrg            new_data = new_value.data;
772706f2543Smrg            old_data = (pointer) (((char *) new_value.data) +
773bc1411c9Smrg                                  (len * size_in_bytes));
774706f2543Smrg            break;
775706f2543Smrg        }
776706f2543Smrg        if (new_data)
777706f2543Smrg            memcpy ((char *) new_data, (char *) value, len * size_in_bytes);
778706f2543Smrg        if (old_data)
779706f2543Smrg            memcpy ((char *) old_data, (char *) prop_value->data,
780706f2543Smrg                    prop_value->size * size_in_bytes);
781706f2543Smrg
782706f2543Smrg        if (dev->properties.handlers)
783706f2543Smrg        {
784706f2543Smrg            XIPropertyHandlerPtr handler;
785706f2543Smrg            BOOL checkonly = TRUE;
786706f2543Smrg            /* run through all handlers with checkonly TRUE, then again with
787706f2543Smrg             * checkonly FALSE. Handlers MUST return error codes on the
788706f2543Smrg             * checkonly run, errors on the second run are ignored */
789706f2543Smrg            do
790706f2543Smrg            {
791706f2543Smrg                handler = dev->properties.handlers;
792706f2543Smrg                while(handler)
793706f2543Smrg                {
794706f2543Smrg                    if (handler->SetProperty)
795706f2543Smrg                    {
796706f2543Smrg                        rc = handler->SetProperty(dev, prop->propertyName,
797706f2543Smrg                                &new_value, checkonly);
798706f2543Smrg                        if (checkonly && rc != Success)
799706f2543Smrg                        {
800706f2543Smrg                            free(new_value.data);
801706f2543Smrg                            return rc;
802706f2543Smrg                        }
803706f2543Smrg                    }
804706f2543Smrg                    handler = handler->next;
805706f2543Smrg                }
806706f2543Smrg                checkonly = !checkonly;
807706f2543Smrg            } while (!checkonly);
808706f2543Smrg        }
809706f2543Smrg        free(prop_value->data);
810706f2543Smrg        *prop_value = new_value;
811706f2543Smrg    } else if (len == 0)
812706f2543Smrg    {
813706f2543Smrg        /* do nothing */
814706f2543Smrg    }
815706f2543Smrg
816706f2543Smrg    if (add)
817706f2543Smrg    {
818706f2543Smrg        prop->next = dev->properties.properties;
819706f2543Smrg        dev->properties.properties = prop;
820706f2543Smrg    }
821706f2543Smrg
822706f2543Smrg    if (sendevent)
823706f2543Smrg        send_property_event(dev, prop->propertyName,
824706f2543Smrg                            (add) ?  XIPropertyCreated : XIPropertyModified);
825706f2543Smrg
826706f2543Smrg    return Success;
827706f2543Smrg}
828706f2543Smrg
829706f2543Smrgint
830706f2543SmrgXIGetDeviceProperty (DeviceIntPtr dev, Atom property, XIPropertyValuePtr *value)
831706f2543Smrg{
832706f2543Smrg    XIPropertyPtr   prop = XIFetchDeviceProperty (dev, property);
833706f2543Smrg    int rc;
834706f2543Smrg
835706f2543Smrg    if (!prop)
836706f2543Smrg    {
837706f2543Smrg        *value = NULL;
838706f2543Smrg        return BadAtom;
839706f2543Smrg    }
840706f2543Smrg
841706f2543Smrg    /* If we can, try to update the property value first */
842706f2543Smrg    if (dev->properties.handlers)
843706f2543Smrg    {
844706f2543Smrg        XIPropertyHandlerPtr handler = dev->properties.handlers;
845706f2543Smrg        while(handler)
846706f2543Smrg        {
847706f2543Smrg            if (handler->GetProperty)
848706f2543Smrg            {
849706f2543Smrg                rc = handler->GetProperty(dev, prop->propertyName);
850706f2543Smrg                if (rc != Success)
851706f2543Smrg                {
852706f2543Smrg                    *value = NULL;
853706f2543Smrg                    return rc;
854706f2543Smrg                }
855706f2543Smrg            }
856706f2543Smrg            handler = handler->next;
857706f2543Smrg        }
858706f2543Smrg    }
859706f2543Smrg
860706f2543Smrg    *value = &prop->value;
861706f2543Smrg    return Success;
862706f2543Smrg}
863706f2543Smrg
864706f2543Smrgint
865706f2543SmrgXISetDevicePropertyDeletable(DeviceIntPtr dev, Atom property, Bool deletable)
866706f2543Smrg{
867706f2543Smrg    XIPropertyPtr prop = XIFetchDeviceProperty(dev, property);
868706f2543Smrg
869706f2543Smrg    if (!prop)
870706f2543Smrg        return BadAtom;
871706f2543Smrg
872706f2543Smrg    prop->deletable = deletable;
873706f2543Smrg    return Success;
874706f2543Smrg}
875706f2543Smrg
876706f2543Smrgint
877706f2543SmrgProcXListDeviceProperties (ClientPtr client)
878706f2543Smrg{
879706f2543Smrg    Atom                        *atoms;
880706f2543Smrg    xListDevicePropertiesReply  rep;
881706f2543Smrg    int                         natoms;
882706f2543Smrg    DeviceIntPtr                dev;
883706f2543Smrg    int                         rc = Success;
884706f2543Smrg
885706f2543Smrg    REQUEST(xListDevicePropertiesReq);
886706f2543Smrg    REQUEST_SIZE_MATCH(xListDevicePropertiesReq);
887706f2543Smrg
888706f2543Smrg    rc = dixLookupDevice (&dev, stuff->deviceid, client, DixListPropAccess);
889706f2543Smrg    if (rc != Success)
890706f2543Smrg        return rc;
891706f2543Smrg
892706f2543Smrg    rc = list_atoms(dev, &natoms, &atoms);
893706f2543Smrg    if (rc != Success)
894706f2543Smrg        return rc;
895706f2543Smrg
896706f2543Smrg    rep.repType = X_Reply;
897706f2543Smrg    rep.RepType = X_ListDeviceProperties;
898706f2543Smrg    rep.length = natoms;
899706f2543Smrg    rep.sequenceNumber = client->sequence;
900706f2543Smrg    rep.nAtoms = natoms;
901706f2543Smrg
902706f2543Smrg    WriteReplyToClient(client, sizeof(xListDevicePropertiesReply), &rep);
903706f2543Smrg    if (natoms)
904706f2543Smrg    {
905706f2543Smrg        client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write;
906706f2543Smrg        WriteSwappedDataToClient(client, natoms * sizeof(Atom), atoms);
907706f2543Smrg        free(atoms);
908706f2543Smrg    }
909706f2543Smrg    return rc;
910706f2543Smrg}
911706f2543Smrg
912706f2543Smrgint
913706f2543SmrgProcXChangeDeviceProperty (ClientPtr client)
914706f2543Smrg{
915706f2543Smrg    REQUEST(xChangeDevicePropertyReq);
916706f2543Smrg    DeviceIntPtr        dev;
917706f2543Smrg    unsigned long       len;
918c8c3bf63Smrg    uint64_t            totalSize;
919706f2543Smrg    int                 rc;
920706f2543Smrg
921706f2543Smrg    REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq);
922706f2543Smrg    UpdateCurrentTime();
923706f2543Smrg
924706f2543Smrg    rc = dixLookupDevice (&dev, stuff->deviceid, client, DixSetPropAccess);
925706f2543Smrg    if (rc != Success)
926706f2543Smrg        return rc;
927706f2543Smrg
928706f2543Smrg    rc = check_change_property(client, stuff->property, stuff->type,
929706f2543Smrg                               stuff->format, stuff->mode, stuff->nUnits);
930706f2543Smrg
931706f2543Smrg    len = stuff->nUnits;
932706f2543Smrg    if (len > (bytes_to_int32(0xffffffff - sizeof(xChangeDevicePropertyReq))))
933706f2543Smrg        return BadLength;
934706f2543Smrg
935706f2543Smrg    totalSize = len * (stuff->format/8);
936706f2543Smrg    REQUEST_FIXED_SIZE(xChangeDevicePropertyReq, totalSize);
937706f2543Smrg
938706f2543Smrg    rc = change_property(client, dev, stuff->property, stuff->type,
939706f2543Smrg                         stuff->format, stuff->mode, len, (void*)&stuff[1]);
940706f2543Smrg    return rc;
941706f2543Smrg}
942706f2543Smrg
943706f2543Smrgint
944706f2543SmrgProcXDeleteDeviceProperty (ClientPtr client)
945706f2543Smrg{
946706f2543Smrg    REQUEST(xDeleteDevicePropertyReq);
947706f2543Smrg    DeviceIntPtr        dev;
948706f2543Smrg    int                 rc;
949706f2543Smrg
950706f2543Smrg    REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq);
951706f2543Smrg    UpdateCurrentTime();
952706f2543Smrg    rc =  dixLookupDevice (&dev, stuff->deviceid, client, DixSetPropAccess);
953706f2543Smrg    if (rc != Success)
954706f2543Smrg        return rc;
955706f2543Smrg
956706f2543Smrg    if (!ValidAtom(stuff->property))
957706f2543Smrg    {
958706f2543Smrg        client->errorValue = stuff->property;
959706f2543Smrg        return BadAtom;
960706f2543Smrg    }
961706f2543Smrg
962706f2543Smrg    rc = XIDeleteDeviceProperty(dev, stuff->property, TRUE);
963706f2543Smrg    return rc;
964706f2543Smrg}
965706f2543Smrg
966706f2543Smrgint
967706f2543SmrgProcXGetDeviceProperty (ClientPtr client)
968706f2543Smrg{
969706f2543Smrg    REQUEST(xGetDevicePropertyReq);
970706f2543Smrg    DeviceIntPtr                dev;
971706f2543Smrg    int                         length;
972706f2543Smrg    int                         rc, format, nitems, bytes_after;
973706f2543Smrg    char                        *data;
974706f2543Smrg    Atom                        type;
975706f2543Smrg    xGetDevicePropertyReply     reply;
976706f2543Smrg
977706f2543Smrg    REQUEST_SIZE_MATCH(xGetDevicePropertyReq);
978706f2543Smrg    if (stuff->delete)
979706f2543Smrg        UpdateCurrentTime();
980706f2543Smrg    rc = dixLookupDevice (&dev, stuff->deviceid, client,
981706f2543Smrg                           stuff->delete ? DixSetPropAccess :
982706f2543Smrg                           DixGetPropAccess);
983706f2543Smrg    if (rc != Success)
984706f2543Smrg        return rc;
985706f2543Smrg
986706f2543Smrg    rc = get_property(client, dev, stuff->property, stuff->type,
987706f2543Smrg            stuff->delete, stuff->longOffset, stuff->longLength,
988706f2543Smrg            &bytes_after, &type, &format, &nitems, &length, &data);
989706f2543Smrg
990706f2543Smrg    if (rc != Success)
991706f2543Smrg        return rc;
992706f2543Smrg
993706f2543Smrg    reply.repType = X_Reply;
994706f2543Smrg    reply.RepType = X_GetDeviceProperty;
995706f2543Smrg    reply.sequenceNumber = client->sequence;
996706f2543Smrg    reply.deviceid = dev->id;
997706f2543Smrg    reply.nItems = nitems;
998706f2543Smrg    reply.format = format;
999706f2543Smrg    reply.bytesAfter = bytes_after;
1000706f2543Smrg    reply.propertyType = type;
1001706f2543Smrg    reply.length = bytes_to_int32(length);
1002706f2543Smrg
1003706f2543Smrg    if (stuff->delete && (reply.bytesAfter == 0))
1004706f2543Smrg        send_property_event(dev, stuff->property, XIPropertyDeleted);
1005706f2543Smrg
1006706f2543Smrg    WriteReplyToClient(client, sizeof(xGenericReply), &reply);
1007706f2543Smrg
1008706f2543Smrg    if (length)
1009706f2543Smrg    {
1010706f2543Smrg        switch (reply.format) {
1011706f2543Smrg            case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break;
1012706f2543Smrg            case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break;
1013706f2543Smrg            default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break;
1014706f2543Smrg        }
1015706f2543Smrg        WriteSwappedDataToClient(client, length, data);
1016706f2543Smrg    }
1017706f2543Smrg
1018706f2543Smrg    /* delete the Property */
1019706f2543Smrg    if (stuff->delete && (reply.bytesAfter == 0))
1020706f2543Smrg    {
1021706f2543Smrg        XIPropertyPtr prop, *prev;
1022706f2543Smrg        for (prev = &dev->properties.properties; (prop = *prev); prev = &prop->next)
1023706f2543Smrg        {
1024706f2543Smrg            if (prop->propertyName == stuff->property)
1025706f2543Smrg            {
1026706f2543Smrg                *prev = prop->next;
1027706f2543Smrg                XIDestroyDeviceProperty(prop);
1028706f2543Smrg                break;
1029706f2543Smrg            }
1030706f2543Smrg        }
1031706f2543Smrg    }
1032706f2543Smrg    return Success;
1033706f2543Smrg}
1034706f2543Smrg
1035706f2543Smrg
1036706f2543Smrgint
1037706f2543SmrgSProcXListDeviceProperties (ClientPtr client)
1038706f2543Smrg{
1039706f2543Smrg    char n;
1040706f2543Smrg    REQUEST(xListDevicePropertiesReq);
1041706f2543Smrg    REQUEST_SIZE_MATCH(xListDevicePropertiesReq);
1042706f2543Smrg
1043706f2543Smrg    swaps(&stuff->length, n);
1044706f2543Smrg    return (ProcXListDeviceProperties(client));
1045706f2543Smrg}
1046706f2543Smrg
1047706f2543Smrgint
1048706f2543SmrgSProcXChangeDeviceProperty (ClientPtr client)
1049706f2543Smrg{
1050706f2543Smrg    char n;
1051706f2543Smrg    REQUEST(xChangeDevicePropertyReq);
1052706f2543Smrg
1053706f2543Smrg    REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq);
1054706f2543Smrg    swaps(&stuff->length, n);
1055706f2543Smrg    swapl(&stuff->property, n);
1056706f2543Smrg    swapl(&stuff->type, n);
1057706f2543Smrg    swapl(&stuff->nUnits, n);
1058706f2543Smrg    return (ProcXChangeDeviceProperty(client));
1059706f2543Smrg}
1060706f2543Smrg
1061706f2543Smrgint
1062706f2543SmrgSProcXDeleteDeviceProperty (ClientPtr client)
1063706f2543Smrg{
1064706f2543Smrg    char n;
1065706f2543Smrg    REQUEST(xDeleteDevicePropertyReq);
1066706f2543Smrg    REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq);
1067706f2543Smrg
1068706f2543Smrg    swaps(&stuff->length, n);
1069706f2543Smrg    swapl(&stuff->property, n);
1070706f2543Smrg    return (ProcXDeleteDeviceProperty(client));
1071706f2543Smrg}
1072706f2543Smrg
1073706f2543Smrgint
1074706f2543SmrgSProcXGetDeviceProperty (ClientPtr client)
1075706f2543Smrg{
1076706f2543Smrg    char n;
1077706f2543Smrg    REQUEST(xGetDevicePropertyReq);
1078706f2543Smrg    REQUEST_SIZE_MATCH(xGetDevicePropertyReq);
1079706f2543Smrg
1080706f2543Smrg    swaps(&stuff->length, n);
1081706f2543Smrg    swapl(&stuff->property, n);
1082706f2543Smrg    swapl(&stuff->type, n);
1083706f2543Smrg    swapl(&stuff->longOffset, n);
1084706f2543Smrg    swapl(&stuff->longLength, n);
1085706f2543Smrg    return (ProcXGetDeviceProperty(client));
1086706f2543Smrg}
1087706f2543Smrg
1088706f2543Smrg
1089706f2543Smrg/* Reply swapping */
1090706f2543Smrg
1091706f2543Smrgvoid
1092706f2543SmrgSRepXListDeviceProperties(ClientPtr client, int size,
1093706f2543Smrg                          xListDevicePropertiesReply *rep)
1094706f2543Smrg{
1095706f2543Smrg    char n;
1096706f2543Smrg    swaps(&rep->sequenceNumber, n);
1097706f2543Smrg    swapl(&rep->length, n);
1098706f2543Smrg    swaps(&rep->nAtoms, n);
1099706f2543Smrg    /* properties will be swapped later, see ProcXListDeviceProperties */
1100706f2543Smrg    WriteToClient(client, size, (char*)rep);
1101706f2543Smrg}
1102706f2543Smrg
1103706f2543Smrgvoid
1104706f2543SmrgSRepXGetDeviceProperty(ClientPtr client, int size,
1105706f2543Smrg                       xGetDevicePropertyReply *rep)
1106706f2543Smrg{
1107706f2543Smrg    char n;
1108706f2543Smrg
1109706f2543Smrg    swaps(&rep->sequenceNumber, n);
1110706f2543Smrg    swapl(&rep->length, n);
1111706f2543Smrg    swapl(&rep->propertyType, n);
1112706f2543Smrg    swapl(&rep->bytesAfter, n);
1113706f2543Smrg    swapl(&rep->nItems, n);
1114706f2543Smrg    /* data will be swapped, see ProcXGetDeviceProperty */
1115706f2543Smrg    WriteToClient(client, size, (char*)rep);
1116706f2543Smrg}
1117706f2543Smrg
1118706f2543Smrg/* XI2 Request/reply handling */
1119706f2543Smrgint
1120706f2543SmrgProcXIListProperties(ClientPtr client)
1121706f2543Smrg{
1122706f2543Smrg    Atom                        *atoms;
1123706f2543Smrg    xXIListPropertiesReply      rep;
1124706f2543Smrg    int                         natoms;
1125706f2543Smrg    DeviceIntPtr                dev;
1126706f2543Smrg    int                         rc = Success;
1127706f2543Smrg
1128706f2543Smrg    REQUEST(xXIListPropertiesReq);
1129706f2543Smrg    REQUEST_SIZE_MATCH(xXIListPropertiesReq);
1130706f2543Smrg
1131706f2543Smrg    rc = dixLookupDevice (&dev, stuff->deviceid, client, DixListPropAccess);
1132706f2543Smrg    if (rc != Success)
1133706f2543Smrg        return rc;
1134706f2543Smrg
1135706f2543Smrg    rc = list_atoms(dev, &natoms, &atoms);
1136706f2543Smrg    if (rc != Success)
1137706f2543Smrg        return rc;
1138706f2543Smrg
1139706f2543Smrg    rep.repType = X_Reply;
1140706f2543Smrg    rep.RepType = X_XIListProperties;
1141706f2543Smrg    rep.length = natoms;
1142706f2543Smrg    rep.sequenceNumber = client->sequence;
1143706f2543Smrg    rep.num_properties = natoms;
1144706f2543Smrg
1145706f2543Smrg    WriteReplyToClient(client, sizeof(xXIListPropertiesReply), &rep);
1146706f2543Smrg    if (natoms)
1147706f2543Smrg    {
1148706f2543Smrg        client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write;
1149706f2543Smrg        WriteSwappedDataToClient(client, natoms * sizeof(Atom), atoms);
1150706f2543Smrg        free(atoms);
1151706f2543Smrg    }
1152706f2543Smrg    return rc;
1153706f2543Smrg}
1154706f2543Smrg
1155706f2543Smrgint
1156706f2543SmrgProcXIChangeProperty(ClientPtr client)
1157706f2543Smrg{
1158706f2543Smrg    int                 rc;
1159706f2543Smrg    DeviceIntPtr        dev;
1160c8c3bf63Smrg    uint64_t            totalSize;
1161706f2543Smrg    unsigned long       len;
1162706f2543Smrg
1163706f2543Smrg    REQUEST(xXIChangePropertyReq);
1164706f2543Smrg    REQUEST_AT_LEAST_SIZE(xXIChangePropertyReq);
1165706f2543Smrg    UpdateCurrentTime();
1166706f2543Smrg
1167706f2543Smrg    rc = dixLookupDevice (&dev, stuff->deviceid, client, DixSetPropAccess);
1168706f2543Smrg    if (rc != Success)
1169706f2543Smrg        return rc;
1170706f2543Smrg
1171706f2543Smrg    rc = check_change_property(client, stuff->property, stuff->type,
1172706f2543Smrg                               stuff->format, stuff->mode, stuff->num_items);
1173706f2543Smrg    len = stuff->num_items;
1174706f2543Smrg    if (len > bytes_to_int32(0xffffffff - sizeof(xXIChangePropertyReq)))
1175706f2543Smrg        return BadLength;
1176706f2543Smrg
1177706f2543Smrg    totalSize = len * (stuff->format/8);
1178706f2543Smrg    REQUEST_FIXED_SIZE(xXIChangePropertyReq, totalSize);
1179706f2543Smrg
1180706f2543Smrg    rc = change_property(client, dev, stuff->property, stuff->type,
1181706f2543Smrg                         stuff->format, stuff->mode, len, (void*)&stuff[1]);
1182706f2543Smrg    return rc;
1183706f2543Smrg}
1184706f2543Smrg
1185706f2543Smrgint
1186706f2543SmrgProcXIDeleteProperty(ClientPtr client)
1187706f2543Smrg{
1188706f2543Smrg    DeviceIntPtr        dev;
1189706f2543Smrg    int                 rc;
1190706f2543Smrg    REQUEST(xXIDeletePropertyReq);
1191706f2543Smrg
1192706f2543Smrg    REQUEST_SIZE_MATCH(xXIDeletePropertyReq);
1193706f2543Smrg    UpdateCurrentTime();
1194706f2543Smrg    rc =  dixLookupDevice (&dev, stuff->deviceid, client, DixSetPropAccess);
1195706f2543Smrg    if (rc != Success)
1196706f2543Smrg        return rc;
1197706f2543Smrg
1198706f2543Smrg    if (!ValidAtom(stuff->property))
1199706f2543Smrg    {
1200706f2543Smrg        client->errorValue = stuff->property;
1201706f2543Smrg        return BadAtom;
1202706f2543Smrg    }
1203706f2543Smrg
1204706f2543Smrg    rc = XIDeleteDeviceProperty(dev, stuff->property, TRUE);
1205706f2543Smrg    return rc;
1206706f2543Smrg}
1207706f2543Smrg
1208706f2543Smrg
1209706f2543Smrgint
1210706f2543SmrgProcXIGetProperty(ClientPtr client)
1211706f2543Smrg{
1212706f2543Smrg    REQUEST(xXIGetPropertyReq);
1213706f2543Smrg    DeviceIntPtr                dev;
1214706f2543Smrg    xXIGetPropertyReply         reply;
1215706f2543Smrg    int                         length;
1216706f2543Smrg    int                         rc, format, nitems, bytes_after;
1217706f2543Smrg    char                        *data;
1218706f2543Smrg    Atom                        type;
1219706f2543Smrg
1220706f2543Smrg    REQUEST_SIZE_MATCH(xXIGetPropertyReq);
1221706f2543Smrg    if (stuff->delete)
1222706f2543Smrg        UpdateCurrentTime();
1223706f2543Smrg    rc = dixLookupDevice (&dev, stuff->deviceid, client,
1224706f2543Smrg                           stuff->delete ? DixSetPropAccess :
1225706f2543Smrg                           DixGetPropAccess);
1226706f2543Smrg    if (rc != Success)
1227706f2543Smrg        return rc;
1228706f2543Smrg
1229706f2543Smrg    rc = get_property(client, dev, stuff->property, stuff->type,
1230706f2543Smrg            stuff->delete, stuff->offset, stuff->len,
1231706f2543Smrg            &bytes_after, &type, &format, &nitems, &length, &data);
1232706f2543Smrg
1233706f2543Smrg    if (rc != Success)
1234706f2543Smrg        return rc;
1235706f2543Smrg
1236706f2543Smrg    reply.repType = X_Reply;
1237706f2543Smrg    reply.RepType = X_XIGetProperty;
1238706f2543Smrg    reply.sequenceNumber = client->sequence;
1239706f2543Smrg    reply.num_items = nitems;
1240706f2543Smrg    reply.format = format;
1241706f2543Smrg    reply.bytes_after = bytes_after;
1242706f2543Smrg    reply.type = type;
1243706f2543Smrg    reply.length = bytes_to_int32(length);
1244706f2543Smrg
1245706f2543Smrg    if (length && stuff->delete && (reply.bytes_after == 0))
1246706f2543Smrg        send_property_event(dev, stuff->property, XIPropertyDeleted);
1247706f2543Smrg
1248706f2543Smrg    WriteReplyToClient(client, sizeof(xXIGetPropertyReply), &reply);
1249706f2543Smrg
1250706f2543Smrg    if (length)
1251706f2543Smrg    {
1252706f2543Smrg        switch (reply.format) {
1253706f2543Smrg            case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break;
1254706f2543Smrg            case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break;
1255706f2543Smrg            default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break;
1256706f2543Smrg        }
1257706f2543Smrg        WriteSwappedDataToClient(client, length, data);
1258706f2543Smrg    }
1259706f2543Smrg
1260706f2543Smrg    /* delete the Property */
1261706f2543Smrg    if (stuff->delete && (reply.bytes_after == 0))
1262706f2543Smrg    {
1263706f2543Smrg        XIPropertyPtr prop, *prev;
1264706f2543Smrg        for (prev = &dev->properties.properties; (prop = *prev); prev = &prop->next)
1265706f2543Smrg        {
1266706f2543Smrg            if (prop->propertyName == stuff->property)
1267706f2543Smrg            {
1268706f2543Smrg                *prev = prop->next;
1269706f2543Smrg                XIDestroyDeviceProperty(prop);
1270706f2543Smrg                break;
1271706f2543Smrg            }
1272706f2543Smrg        }
1273706f2543Smrg    }
1274706f2543Smrg
1275706f2543Smrg    return Success;
1276706f2543Smrg}
1277706f2543Smrg
1278706f2543Smrgint
1279706f2543SmrgSProcXIListProperties(ClientPtr client)
1280706f2543Smrg{
1281706f2543Smrg    char n;
1282706f2543Smrg    REQUEST(xXIListPropertiesReq);
1283706f2543Smrg    REQUEST_SIZE_MATCH(xXIListPropertiesReq);
1284706f2543Smrg
1285706f2543Smrg    swaps(&stuff->length, n);
1286706f2543Smrg    swaps(&stuff->deviceid, n);
1287706f2543Smrg    return (ProcXIListProperties(client));
1288706f2543Smrg}
1289706f2543Smrg
1290706f2543Smrgint
1291706f2543SmrgSProcXIChangeProperty(ClientPtr client)
1292706f2543Smrg{
1293706f2543Smrg    char n;
1294706f2543Smrg    REQUEST(xXIChangePropertyReq);
1295706f2543Smrg
1296706f2543Smrg    REQUEST_AT_LEAST_SIZE(xXIChangePropertyReq);
1297706f2543Smrg    swaps(&stuff->length, n);
1298706f2543Smrg    swaps(&stuff->deviceid, n);
1299706f2543Smrg    swapl(&stuff->property, n);
1300706f2543Smrg    swapl(&stuff->type, n);
1301706f2543Smrg    swapl(&stuff->num_items, n);
1302706f2543Smrg    return (ProcXIChangeProperty(client));
1303706f2543Smrg}
1304706f2543Smrg
1305706f2543Smrgint
1306706f2543SmrgSProcXIDeleteProperty(ClientPtr client)
1307706f2543Smrg{
1308706f2543Smrg    char n;
1309706f2543Smrg    REQUEST(xXIDeletePropertyReq);
1310706f2543Smrg    REQUEST_SIZE_MATCH(xXIDeletePropertyReq);
1311706f2543Smrg
1312706f2543Smrg    swaps(&stuff->length, n);
1313706f2543Smrg    swaps(&stuff->deviceid, n);
1314706f2543Smrg    swapl(&stuff->property, n);
1315706f2543Smrg    return (ProcXIDeleteProperty(client));
1316706f2543Smrg}
1317706f2543Smrg
1318706f2543Smrgint
1319706f2543SmrgSProcXIGetProperty(ClientPtr client)
1320706f2543Smrg{
1321706f2543Smrg    char n;
1322706f2543Smrg    REQUEST(xXIGetPropertyReq);
1323706f2543Smrg    REQUEST_SIZE_MATCH(xXIGetPropertyReq);
1324706f2543Smrg
1325706f2543Smrg    swaps(&stuff->length, n);
1326706f2543Smrg    swaps(&stuff->deviceid, n);
1327706f2543Smrg    swapl(&stuff->property, n);
1328706f2543Smrg    swapl(&stuff->type, n);
1329706f2543Smrg    swapl(&stuff->offset, n);
1330706f2543Smrg    swapl(&stuff->len, n);
1331706f2543Smrg    return (ProcXIGetProperty(client));
1332706f2543Smrg}
1333706f2543Smrg
1334706f2543Smrg
1335706f2543Smrgvoid
1336706f2543SmrgSRepXIListProperties(ClientPtr client, int size,
1337706f2543Smrg                     xXIListPropertiesReply *rep)
1338706f2543Smrg{
1339706f2543Smrg    char n;
1340706f2543Smrg    swaps(&rep->sequenceNumber, n);
1341706f2543Smrg    swapl(&rep->length, n);
1342706f2543Smrg    swaps(&rep->num_properties, n);
1343706f2543Smrg    /* properties will be swapped later, see ProcXIListProperties */
1344706f2543Smrg    WriteToClient(client, size, (char*)rep);
1345706f2543Smrg}
1346706f2543Smrg
1347706f2543Smrgvoid
1348706f2543SmrgSRepXIGetProperty(ClientPtr client, int size,
1349706f2543Smrg                  xXIGetPropertyReply *rep)
1350706f2543Smrg{
1351706f2543Smrg    char n;
1352706f2543Smrg
1353706f2543Smrg    swaps(&rep->sequenceNumber, n);
1354706f2543Smrg    swapl(&rep->length, n);
1355706f2543Smrg    swapl(&rep->type, n);
1356706f2543Smrg    swapl(&rep->bytes_after, n);
1357706f2543Smrg    swapl(&rep->num_items, n);
1358706f2543Smrg    /* data will be swapped, see ProcXIGetProperty */
1359706f2543Smrg    WriteToClient(client, size, (char*)rep);
1360706f2543Smrg}
1361