Imported Upstream version 1.11.4
[ubuntu-omap:xserver.git] / Xi / xiproperty.c
1 /*
2  * Copyright © 2006 Keith Packard
3  * Copyright © 2008 Peter Hutterer
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WAXIANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WAXIANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  */
25
26 /* This code is a modified version of randr/rrproperty.c */
27
28 #ifdef HAVE_DIX_CONFIG_H
29 #include <dix-config.h>
30 #endif
31
32 #include "dix.h"
33 #include "inputstr.h"
34 #include <X11/extensions/XI.h>
35 #include <X11/Xatom.h>
36 #include <X11/extensions/XIproto.h>
37 #include <X11/extensions/XI2proto.h>
38 #include "exglobals.h"
39 #include "exevents.h"
40 #include "swaprep.h"
41
42 #include "xiproperty.h"
43 #include "xserver-properties.h"
44
45 /**
46  * Properties used or alloced from inside the server.
47  */
48 static struct dev_properties
49 {
50     Atom type;
51     char *name;
52 } dev_properties[] = {
53     {0, XI_PROP_ENABLED},
54     {0, XI_PROP_XTEST_DEVICE},
55     {0, XATOM_FLOAT},
56     {0, ACCEL_PROP_PROFILE_NUMBER},
57     {0, ACCEL_PROP_CONSTANT_DECELERATION},
58     {0, ACCEL_PROP_ADAPTIVE_DECELERATION},
59     {0, ACCEL_PROP_VELOCITY_SCALING},
60     {0, AXIS_LABEL_PROP},
61     {0, AXIS_LABEL_PROP_REL_X},
62     {0, AXIS_LABEL_PROP_REL_Y},
63     {0, AXIS_LABEL_PROP_REL_Z},
64     {0, AXIS_LABEL_PROP_REL_RX},
65     {0, AXIS_LABEL_PROP_REL_RY},
66     {0, AXIS_LABEL_PROP_REL_RZ},
67     {0, AXIS_LABEL_PROP_REL_HWHEEL},
68     {0, AXIS_LABEL_PROP_REL_DIAL},
69     {0, AXIS_LABEL_PROP_REL_WHEEL},
70     {0, AXIS_LABEL_PROP_REL_MISC},
71     {0, AXIS_LABEL_PROP_ABS_X},
72     {0, AXIS_LABEL_PROP_ABS_Y},
73     {0, AXIS_LABEL_PROP_ABS_Z},
74     {0, AXIS_LABEL_PROP_ABS_RX},
75     {0, AXIS_LABEL_PROP_ABS_RY},
76     {0, AXIS_LABEL_PROP_ABS_RZ},
77     {0, AXIS_LABEL_PROP_ABS_THROTTLE},
78     {0, AXIS_LABEL_PROP_ABS_RUDDER},
79     {0, AXIS_LABEL_PROP_ABS_WHEEL},
80     {0, AXIS_LABEL_PROP_ABS_GAS},
81     {0, AXIS_LABEL_PROP_ABS_BRAKE},
82     {0, AXIS_LABEL_PROP_ABS_HAT0X},
83     {0, AXIS_LABEL_PROP_ABS_HAT0Y},
84     {0, AXIS_LABEL_PROP_ABS_HAT1X},
85     {0, AXIS_LABEL_PROP_ABS_HAT1Y},
86     {0, AXIS_LABEL_PROP_ABS_HAT2X},
87     {0, AXIS_LABEL_PROP_ABS_HAT2Y},
88     {0, AXIS_LABEL_PROP_ABS_HAT3X},
89     {0, AXIS_LABEL_PROP_ABS_HAT3Y},
90     {0, AXIS_LABEL_PROP_ABS_PRESSURE},
91     {0, AXIS_LABEL_PROP_ABS_DISTANCE},
92     {0, AXIS_LABEL_PROP_ABS_TILT_X},
93     {0, AXIS_LABEL_PROP_ABS_TILT_Y},
94     {0, AXIS_LABEL_PROP_ABS_TOOL_WIDTH},
95     {0, AXIS_LABEL_PROP_ABS_VOLUME},
96     {0, AXIS_LABEL_PROP_ABS_MT_TOUCH_MAJOR},
97     {0, AXIS_LABEL_PROP_ABS_MT_TOUCH_MINOR},
98     {0, AXIS_LABEL_PROP_ABS_MT_WIDTH_MAJOR},
99     {0, AXIS_LABEL_PROP_ABS_MT_WIDTH_MINOR},
100     {0, AXIS_LABEL_PROP_ABS_MT_ORIENTATION},
101     {0, AXIS_LABEL_PROP_ABS_MT_POSITION_X},
102     {0, AXIS_LABEL_PROP_ABS_MT_POSITION_Y},
103     {0, AXIS_LABEL_PROP_ABS_MT_TOOL_TYPE},
104     {0, AXIS_LABEL_PROP_ABS_MT_BLOB_ID},
105     {0, AXIS_LABEL_PROP_ABS_MT_TRACKING_ID},
106     {0, AXIS_LABEL_PROP_ABS_MT_PRESSURE},
107     {0, AXIS_LABEL_PROP_ABS_MISC},
108
109     {0, BTN_LABEL_PROP},
110     {0, BTN_LABEL_PROP_BTN_UNKNOWN},
111     {0, BTN_LABEL_PROP_BTN_WHEEL_UP},
112     {0, BTN_LABEL_PROP_BTN_WHEEL_DOWN},
113     {0, BTN_LABEL_PROP_BTN_HWHEEL_LEFT},
114     {0, BTN_LABEL_PROP_BTN_HWHEEL_RIGHT},
115     {0, BTN_LABEL_PROP_BTN_0},
116     {0, BTN_LABEL_PROP_BTN_1},
117     {0, BTN_LABEL_PROP_BTN_2},
118     {0, BTN_LABEL_PROP_BTN_3},
119     {0, BTN_LABEL_PROP_BTN_4},
120     {0, BTN_LABEL_PROP_BTN_5},
121     {0, BTN_LABEL_PROP_BTN_6},
122     {0, BTN_LABEL_PROP_BTN_7},
123     {0, BTN_LABEL_PROP_BTN_8},
124     {0, BTN_LABEL_PROP_BTN_9},
125
126     {0, BTN_LABEL_PROP_BTN_LEFT},
127     {0, BTN_LABEL_PROP_BTN_RIGHT},
128     {0, BTN_LABEL_PROP_BTN_MIDDLE},
129     {0, BTN_LABEL_PROP_BTN_SIDE},
130     {0, BTN_LABEL_PROP_BTN_EXTRA},
131     {0, BTN_LABEL_PROP_BTN_FORWARD},
132     {0, BTN_LABEL_PROP_BTN_BACK},
133     {0, BTN_LABEL_PROP_BTN_TASK},
134
135     {0, BTN_LABEL_PROP_BTN_TRIGGER},
136     {0, BTN_LABEL_PROP_BTN_THUMB},
137     {0, BTN_LABEL_PROP_BTN_THUMB2},
138     {0, BTN_LABEL_PROP_BTN_TOP},
139     {0, BTN_LABEL_PROP_BTN_TOP2},
140     {0, BTN_LABEL_PROP_BTN_PINKIE},
141     {0, BTN_LABEL_PROP_BTN_BASE},
142     {0, BTN_LABEL_PROP_BTN_BASE2},
143     {0, BTN_LABEL_PROP_BTN_BASE3},
144     {0, BTN_LABEL_PROP_BTN_BASE4},
145     {0, BTN_LABEL_PROP_BTN_BASE5},
146     {0, BTN_LABEL_PROP_BTN_BASE6},
147     {0, BTN_LABEL_PROP_BTN_DEAD},
148
149     {0, BTN_LABEL_PROP_BTN_A},
150     {0, BTN_LABEL_PROP_BTN_B},
151     {0, BTN_LABEL_PROP_BTN_C},
152     {0, BTN_LABEL_PROP_BTN_X},
153     {0, BTN_LABEL_PROP_BTN_Y},
154     {0, BTN_LABEL_PROP_BTN_Z},
155     {0, BTN_LABEL_PROP_BTN_TL},
156     {0, BTN_LABEL_PROP_BTN_TR},
157     {0, BTN_LABEL_PROP_BTN_TL2},
158     {0, BTN_LABEL_PROP_BTN_TR2},
159     {0, BTN_LABEL_PROP_BTN_SELECT},
160     {0, BTN_LABEL_PROP_BTN_START},
161     {0, BTN_LABEL_PROP_BTN_MODE},
162     {0, BTN_LABEL_PROP_BTN_THUMBL},
163     {0, BTN_LABEL_PROP_BTN_THUMBR},
164
165     {0, BTN_LABEL_PROP_BTN_TOOL_PEN},
166     {0, BTN_LABEL_PROP_BTN_TOOL_RUBBER},
167     {0, BTN_LABEL_PROP_BTN_TOOL_BRUSH},
168     {0, BTN_LABEL_PROP_BTN_TOOL_PENCIL},
169     {0, BTN_LABEL_PROP_BTN_TOOL_AIRBRUSH},
170     {0, BTN_LABEL_PROP_BTN_TOOL_FINGER},
171     {0, BTN_LABEL_PROP_BTN_TOOL_MOUSE},
172     {0, BTN_LABEL_PROP_BTN_TOOL_LENS},
173     {0, BTN_LABEL_PROP_BTN_TOUCH},
174     {0, BTN_LABEL_PROP_BTN_STYLUS},
175     {0, BTN_LABEL_PROP_BTN_STYLUS2},
176     {0, BTN_LABEL_PROP_BTN_TOOL_DOUBLETAP},
177     {0, BTN_LABEL_PROP_BTN_TOOL_TRIPLETAP},
178
179     {0, BTN_LABEL_PROP_BTN_GEAR_DOWN},
180     {0, BTN_LABEL_PROP_BTN_GEAR_UP},
181
182     {0, XI_PROP_TRANSFORM}
183 };
184
185 static long XIPropHandlerID = 1;
186
187 static void send_property_event(DeviceIntPtr dev, Atom property, int what)
188 {
189         devicePropertyNotify    event;
190         xXIPropertyEvent        xi2;
191         int state;
192
193         if (what == XIPropertyDeleted)
194             state = PropertyDelete;
195         else
196             state = PropertyNewValue;
197
198         event.type      = DevicePropertyNotify;
199         event.deviceid  = dev->id;
200         event.state     = state;
201         event.atom      = property;
202         event.time      = currentTime.milliseconds;
203         SendEventToAllWindows(dev, DevicePropertyNotifyMask,
204                               (xEvent*)&event, 1);
205
206         xi2.type        = GenericEvent;
207         xi2.extension   = IReqCode;
208         xi2.length      = 0;
209         xi2.evtype      = XI_PropertyEvent;
210         xi2.deviceid    = dev->id;
211         xi2.time        = currentTime.milliseconds;
212         xi2.property    = property;
213         xi2.what        = what;
214         SendEventToAllWindows(dev, GetEventFilter(dev, (xEvent*)&xi2),
215                               (xEvent*)&xi2, 1);
216 }
217
218 static int list_atoms(DeviceIntPtr dev, int *natoms, Atom **atoms_return)
219 {
220     XIPropertyPtr prop;
221     Atom *atoms         = NULL;
222     int nprops          = 0;
223
224     for (prop = dev->properties.properties; prop; prop = prop->next)
225         nprops++;
226     if (nprops)
227     {
228         Atom *a;
229
230         atoms = malloc(nprops * sizeof(Atom));
231         if(!atoms)
232             return BadAlloc;
233         a = atoms;
234         for (prop = dev->properties.properties; prop; prop = prop->next, a++)
235             *a = prop->propertyName;
236     }
237
238     *natoms = nprops;
239     *atoms_return = atoms;
240     return Success;
241 }
242
243 static int
244 get_property(ClientPtr client, DeviceIntPtr dev, Atom property, Atom type,
245              BOOL delete, int offset, int length,
246              int *bytes_after, Atom *type_return, int *format, int *nitems,
247              int *length_return, char **data)
248 {
249     unsigned long n, len, ind;
250     int rc;
251     XIPropertyPtr prop;
252     XIPropertyValuePtr prop_value;
253
254     if (!ValidAtom(property))
255     {
256         client->errorValue = property;
257         return BadAtom;
258     }
259     if ((delete != xTrue) && (delete != xFalse))
260     {
261         client->errorValue = delete;
262         return BadValue;
263     }
264
265     if ((type != AnyPropertyType) && !ValidAtom(type))
266     {
267         client->errorValue = type;
268         return BadAtom;
269     }
270
271     for (prop = dev->properties.properties; prop; prop = prop->next)
272         if (prop->propertyName == property)
273             break;
274
275     if (!prop)
276     {
277         *bytes_after = 0;
278         *type_return = None;
279         *format = 0;
280         *nitems = 0;
281         *length_return = 0;
282         return Success;
283     }
284
285     rc = XIGetDeviceProperty(dev, property, &prop_value);
286     if (rc != Success)
287     {
288         client->errorValue = property;
289         return rc;
290     }
291
292     /* If the request type and actual type don't match. Return the
293     property information, but not the data. */
294
295     if (((type != prop_value->type) && (type != AnyPropertyType)))
296     {
297         *bytes_after = prop_value->size;
298         *format = prop_value->format;
299         *length_return = 0;
300         *nitems = 0;
301         *type_return = prop_value->type;
302         return Success;
303     }
304
305     /* Return type, format, value to client */
306     n = (prop_value->format/8) * prop_value->size; /* size (bytes) of prop */
307     ind = offset << 2;
308
309    /* If offset is invalid such that it causes "len" to
310             be negative, it's a value error. */
311
312     if (n < ind)
313     {
314         client->errorValue = offset;
315         return BadValue;
316     }
317
318     len = min(n - ind, 4 * length);
319
320     *bytes_after = n - (ind + len);
321     *format = prop_value->format;
322     *length_return = len;
323     if (prop_value->format)
324         *nitems = len / (prop_value->format / 8);
325     else
326         *nitems = 0;
327     *type_return = prop_value->type;
328
329     *data = (char*)prop_value->data + ind;
330
331     return Success;
332 }
333
334 static int
335 check_change_property(ClientPtr client, Atom property, Atom type, int format,
336                       int mode, int nitems)
337 {
338     if ((mode != PropModeReplace) && (mode != PropModeAppend) &&
339         (mode != PropModePrepend))
340     {
341         client->errorValue = mode;
342         return BadValue;
343     }
344     if ((format != 8) && (format != 16) && (format != 32))
345     {
346         client->errorValue = format;
347         return BadValue;
348     }
349
350     if (!ValidAtom(property))
351     {
352         client->errorValue = property;
353         return BadAtom;
354     }
355     if (!ValidAtom(type))
356     {
357         client->errorValue = type;
358         return BadAtom;
359     }
360
361     return Success;
362 }
363
364 static int
365 change_property(ClientPtr client, DeviceIntPtr dev, Atom property, Atom type,
366                 int format, int mode, int len, void *data)
367 {
368     int rc = Success;
369
370     rc = XIChangeDeviceProperty(dev, property, type, format, mode, len, data, TRUE);
371     if (rc != Success)
372         client->errorValue = property;
373
374     return rc;
375 }
376
377 /**
378  * Return the atom assigned to the specified string or 0 if the atom isn't known
379  * to the DIX.
380  *
381  * If name is NULL, None is returned.
382  */
383 Atom
384 XIGetKnownProperty(char *name)
385 {
386     int i;
387
388     if (!name)
389         return None;
390
391     for (i = 0; i < (sizeof(dev_properties)/sizeof(struct dev_properties)); i++)
392     {
393         if (strcmp(name, dev_properties[i].name) == 0){
394             if (dev_properties[i].type == None){
395                 dev_properties[i].type =
396                             MakeAtom(dev_properties[i].name,
397                                      strlen(dev_properties[i].name),
398                                      TRUE);
399             }
400
401             return dev_properties[i].type;
402         }
403     }
404
405     return 0;
406 }
407
408 void
409 XIResetProperties(void)
410 {
411     int i;
412
413     for (i = 0; i < (sizeof(dev_properties)/sizeof(struct dev_properties)); i++)
414         dev_properties[i].type = None;
415 }
416
417 /**
418  * Convert the given property's value(s) into @nelem_return integer values and
419  * store them in @buf_return. If @nelem_return is larger than the number of
420  * values in the property, @nelem_return is set to the number of values in the
421  * property.
422  *
423  * If *@buf_return is NULL and @nelem_return is 0, memory is allocated
424  * automatically and must be freed by the caller.
425  *
426  * Possible return codes.
427  * Success ... No error.
428  * BadMatch ... Wrong atom type, atom is not XA_INTEGER
429  * BadAlloc ... NULL passed as buffer and allocation failed.
430  * BadLength ... @buff is NULL but @nelem_return is non-zero.
431  *
432  * @param val The property value
433  * @param nelem_return The maximum number of elements to return.
434  * @param buf_return Pointer to an array of at least @nelem_return values.
435  * @return Success or the error code if an error occured.
436  */
437 _X_EXPORT int
438 XIPropToInt(XIPropertyValuePtr val, int *nelem_return, int **buf_return)
439 {
440     int i;
441     int *buf;
442
443     if (val->type != XA_INTEGER)
444         return BadMatch;
445     if (!*buf_return && *nelem_return)
446         return BadLength;
447
448     switch(val->format)
449     {
450         case 8:
451         case 16:
452         case 32:
453             break;
454         default:
455             return BadValue;
456     }
457
458     buf = *buf_return;
459
460     if (!buf && !(*nelem_return))
461     {
462         buf = calloc(val->size, sizeof(int));
463         if (!buf)
464             return BadAlloc;
465         *buf_return = buf;
466         *nelem_return = val->size;
467     } else if (val->size < *nelem_return)
468         *nelem_return = val->size;
469
470     for (i = 0; i < val->size && i < *nelem_return; i++)
471     {
472         switch(val->format)
473         {
474             case 8:  buf[i] = ((CARD8*)val->data)[i]; break;
475             case 16: buf[i] = ((CARD16*)val->data)[i]; break;
476             case 32: buf[i] = ((CARD32*)val->data)[i]; break;
477         }
478     }
479
480     return Success;
481 }
482
483 /**
484  * Convert the given property's value(s) into @nelem_return float values and
485  * store them in @buf_return. If @nelem_return is larger than the number of
486  * values in the property, @nelem_return is set to the number of values in the
487  * property.
488  *
489  * If *@buf_return is NULL and @nelem_return is 0, memory is allocated
490  * automatically and must be freed by the caller.
491  *
492  * Possible errors returned:
493  * Success
494  * BadMatch ... Wrong atom type, atom is not XA_FLOAT
495  * BadValue ... Wrong format, format is not 32
496  * BadAlloc ... NULL passed as buffer and allocation failed.
497  * BadLength ... @buff is NULL but @nelem_return is non-zero.
498  *
499  * @param val The property value
500  * @param nelem_return The maximum number of elements to return.
501  * @param buf_return Pointer to an array of at least @nelem_return values.
502  * @return Success or the error code if an error occured.
503  */
504 _X_EXPORT int
505 XIPropToFloat(XIPropertyValuePtr val, int *nelem_return, float **buf_return)
506 {
507     int i;
508     float *buf;
509
510     if (!val->type || val->type != XIGetKnownProperty(XATOM_FLOAT))
511         return BadMatch;
512
513     if (val->format != 32)
514         return BadValue;
515     if (!*buf_return && *nelem_return)
516         return BadLength;
517
518     buf = *buf_return;
519
520     if (!buf && !(*nelem_return))
521     {
522         buf = calloc(val->size, sizeof(float));
523         if (!buf)
524             return BadAlloc;
525         *buf_return = buf;
526         *nelem_return = val->size;
527     } else if (val->size < *nelem_return)
528         *nelem_return = val->size;
529
530     for (i = 0; i < val->size && i < *nelem_return; i++)
531            buf[i] = ((float*)val->data)[i];
532
533     return Success;
534 }
535
536 /* Registers a new property handler on the given device and returns a unique
537  * identifier for this handler. This identifier is required to unregister the
538  * property handler again.
539  * @return The handler's identifier or 0 if an error occured.
540  */
541 long
542 XIRegisterPropertyHandler(DeviceIntPtr         dev,
543                           int (*SetProperty) (DeviceIntPtr dev,
544                                               Atom property,
545                                               XIPropertyValuePtr prop,
546                                               BOOL checkonly),
547                           int (*GetProperty) (DeviceIntPtr dev,
548                                               Atom property),
549                           int (*DeleteProperty) (DeviceIntPtr dev,
550                                                  Atom property))
551 {
552     XIPropertyHandlerPtr new_handler;
553
554     new_handler = calloc(1, sizeof(XIPropertyHandler));
555     if (!new_handler)
556         return 0;
557
558     new_handler->id = XIPropHandlerID++;
559     new_handler->SetProperty = SetProperty;
560     new_handler->GetProperty = GetProperty;
561     new_handler->DeleteProperty = DeleteProperty;
562     new_handler->next = dev->properties.handlers;
563     dev->properties.handlers = new_handler;
564
565     return new_handler->id;
566 }
567
568 void
569 XIUnregisterPropertyHandler(DeviceIntPtr dev, long id)
570 {
571     XIPropertyHandlerPtr curr, prev = NULL;
572
573     curr = dev->properties.handlers;
574     while(curr && curr->id != id)
575     {
576         prev = curr;
577         curr = curr->next;
578     }
579
580     if (!curr)
581         return;
582
583     if (!prev) /* first one */
584         dev->properties.handlers = curr->next;
585     else
586         prev->next = curr->next;
587
588     free(curr);
589 }
590
591 static XIPropertyPtr
592 XICreateDeviceProperty (Atom property)
593 {
594     XIPropertyPtr   prop;
595
596     prop = (XIPropertyPtr)malloc(sizeof(XIPropertyRec));
597     if (!prop)
598         return NULL;
599
600     prop->next          = NULL;
601     prop->propertyName  = property;
602     prop->value.type   = None;
603     prop->value.format = 0;
604     prop->value.size   = 0;
605     prop->value.data   = NULL;
606     prop->deletable    = TRUE;
607
608     return prop;
609 }
610
611 static XIPropertyPtr
612 XIFetchDeviceProperty(DeviceIntPtr dev, Atom property)
613 {
614     XIPropertyPtr   prop;
615
616     for (prop = dev->properties.properties; prop; prop = prop->next)
617         if (prop->propertyName == property)
618             return prop;
619     return NULL;
620 }
621
622 static void
623 XIDestroyDeviceProperty (XIPropertyPtr prop)
624 {
625     free(prop->value.data);
626     free(prop);
627 }
628
629 /* This function destroys all of the device's property-related stuff,
630  * including removing all device handlers.
631  * DO NOT CALL FROM THE DRIVER.
632  */
633 void
634 XIDeleteAllDeviceProperties (DeviceIntPtr device)
635 {
636     XIPropertyPtr               prop, next;
637     XIPropertyHandlerPtr        curr_handler, next_handler;
638
639     for (prop = device->properties.properties; prop; prop = next)
640     {
641         next = prop->next;
642         send_property_event(device, prop->propertyName, XIPropertyDeleted);
643         XIDestroyDeviceProperty(prop);
644     }
645
646     device->properties.properties = NULL;
647
648     /* Now free all handlers */
649     curr_handler = device->properties.handlers;
650     while(curr_handler)
651     {
652         next_handler = curr_handler->next;
653         free(curr_handler);
654         curr_handler = next_handler;
655     }
656
657     device->properties.handlers = NULL;
658 }
659
660
661 int
662 XIDeleteDeviceProperty (DeviceIntPtr device, Atom property, Bool fromClient)
663 {
664     XIPropertyPtr               prop, *prev;
665     int                         rc = Success;
666
667     for (prev = &device->properties.properties; (prop = *prev); prev = &(prop->next))
668         if (prop->propertyName == property)
669             break;
670
671     if (!prop)
672         return Success;
673
674     if (fromClient && !prop->deletable)
675         return BadAccess;
676
677     /* Ask handlers if we may delete the property */
678     if (device->properties.handlers)
679     {
680         XIPropertyHandlerPtr handler = device->properties.handlers;
681         while(handler)
682         {
683             if (handler->DeleteProperty)
684                 rc = handler->DeleteProperty(device, prop->propertyName);
685             if (rc != Success)
686                 return rc;
687             handler = handler->next;
688         }
689     }
690
691     if (prop)
692     {
693         *prev = prop->next;
694         send_property_event(device, prop->propertyName, XIPropertyDeleted);
695         XIDestroyDeviceProperty (prop);
696     }
697
698     return Success;
699 }
700
701 int
702 XIChangeDeviceProperty (DeviceIntPtr dev, Atom property, Atom type,
703                         int format, int mode, unsigned long len,
704                         const pointer value, Bool sendevent)
705 {
706     XIPropertyPtr               prop;
707     int                         size_in_bytes;
708     int                         total_size;
709     unsigned long               total_len;
710     XIPropertyValuePtr          prop_value;
711     XIPropertyValueRec          new_value;
712     Bool                        add = FALSE;
713     int                         rc;
714
715     size_in_bytes = format >> 3;
716
717     /* first see if property already exists */
718     prop = XIFetchDeviceProperty (dev, property);
719     if (!prop)   /* just add to list */
720     {
721         prop = XICreateDeviceProperty (property);
722         if (!prop)
723             return BadAlloc;
724         add = TRUE;
725         mode = PropModeReplace;
726     }
727     prop_value = &prop->value;
728
729     /* To append or prepend to a property the request format and type
730      must match those of the already defined property.  The
731      existing format and type are irrelevant when using the mode
732      "PropModeReplace" since they will be written over. */
733
734     if ((format != prop_value->format) && (mode != PropModeReplace))
735         return BadMatch;
736     if ((prop_value->type != type) && (mode != PropModeReplace))
737         return BadMatch;
738     new_value = *prop_value;
739     if (mode == PropModeReplace)
740         total_len = len;
741     else
742         total_len = prop_value->size + len;
743
744     if (mode == PropModeReplace || len > 0)
745     {
746         pointer            new_data = NULL, old_data = NULL;
747
748         total_size = total_len * size_in_bytes;
749         new_value.data = (pointer)malloc(total_size);
750         if (!new_value.data && total_size)
751         {
752             if (add)
753                 XIDestroyDeviceProperty (prop);
754             return BadAlloc;
755         }
756         new_value.size = len;
757         new_value.type = type;
758         new_value.format = format;
759
760         switch (mode) {
761         case PropModeReplace:
762             new_data = new_value.data;
763             old_data = NULL;
764             break;
765         case PropModeAppend:
766             new_data = (pointer) (((char *) new_value.data) +
767                                   (prop_value->size * size_in_bytes));
768             old_data = new_value.data;
769             break;
770         case PropModePrepend:
771             new_data = new_value.data;
772             old_data = (pointer) (((char *) new_value.data) +
773                                   (prop_value->size * size_in_bytes));
774             break;
775         }
776         if (new_data)
777             memcpy ((char *) new_data, (char *) value, len * size_in_bytes);
778         if (old_data)
779             memcpy ((char *) old_data, (char *) prop_value->data,
780                     prop_value->size * size_in_bytes);
781
782         if (dev->properties.handlers)
783         {
784             XIPropertyHandlerPtr handler;
785             BOOL checkonly = TRUE;
786             /* run through all handlers with checkonly TRUE, then again with
787              * checkonly FALSE. Handlers MUST return error codes on the
788              * checkonly run, errors on the second run are ignored */
789             do
790             {
791                 handler = dev->properties.handlers;
792                 while(handler)
793                 {
794                     if (handler->SetProperty)
795                     {
796                         rc = handler->SetProperty(dev, prop->propertyName,
797                                 &new_value, checkonly);
798                         if (checkonly && rc != Success)
799                         {
800                             free(new_value.data);
801                             return rc;
802                         }
803                     }
804                     handler = handler->next;
805                 }
806                 checkonly = !checkonly;
807             } while (!checkonly);
808         }
809         free(prop_value->data);
810         *prop_value = new_value;
811     } else if (len == 0)
812     {
813         /* do nothing */
814     }
815
816     if (add)
817     {
818         prop->next = dev->properties.properties;
819         dev->properties.properties = prop;
820     }
821
822     if (sendevent)
823         send_property_event(dev, prop->propertyName,
824                             (add) ?  XIPropertyCreated : XIPropertyModified);
825
826     return Success;
827 }
828
829 int
830 XIGetDeviceProperty (DeviceIntPtr dev, Atom property, XIPropertyValuePtr *value)
831 {
832     XIPropertyPtr   prop = XIFetchDeviceProperty (dev, property);
833     int rc;
834
835     if (!prop)
836     {
837         *value = NULL;
838         return BadAtom;
839     }
840
841     /* If we can, try to update the property value first */
842     if (dev->properties.handlers)
843     {
844         XIPropertyHandlerPtr handler = dev->properties.handlers;
845         while(handler)
846         {
847             if (handler->GetProperty)
848             {
849                 rc = handler->GetProperty(dev, prop->propertyName);
850                 if (rc != Success)
851                 {
852                     *value = NULL;
853                     return rc;
854                 }
855             }
856             handler = handler->next;
857         }
858     }
859
860     *value = &prop->value;
861     return Success;
862 }
863
864 int
865 XISetDevicePropertyDeletable(DeviceIntPtr dev, Atom property, Bool deletable)
866 {
867     XIPropertyPtr prop = XIFetchDeviceProperty(dev, property);
868
869     if (!prop)
870         return BadAtom;
871
872     prop->deletable = deletable;
873     return Success;
874 }
875
876 int
877 ProcXListDeviceProperties (ClientPtr client)
878 {
879     Atom                        *atoms;
880     xListDevicePropertiesReply  rep;
881     int                         natoms;
882     DeviceIntPtr                dev;
883     int                         rc = Success;
884
885     REQUEST(xListDevicePropertiesReq);
886     REQUEST_SIZE_MATCH(xListDevicePropertiesReq);
887
888     rc = dixLookupDevice (&dev, stuff->deviceid, client, DixListPropAccess);
889     if (rc != Success)
890         return rc;
891
892     rc = list_atoms(dev, &natoms, &atoms);
893     if (rc != Success)
894         return rc;
895
896     rep.repType = X_Reply;
897     rep.RepType = X_ListDeviceProperties;
898     rep.length = natoms;
899     rep.sequenceNumber = client->sequence;
900     rep.nAtoms = natoms;
901
902     WriteReplyToClient(client, sizeof(xListDevicePropertiesReply), &rep);
903     if (natoms)
904     {
905         client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write;
906         WriteSwappedDataToClient(client, natoms * sizeof(Atom), atoms);
907         free(atoms);
908     }
909     return rc;
910 }
911
912 int
913 ProcXChangeDeviceProperty (ClientPtr client)
914 {
915     REQUEST(xChangeDevicePropertyReq);
916     DeviceIntPtr        dev;
917     unsigned long       len;
918     int                 totalSize;
919     int                 rc;
920
921     REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq);
922     UpdateCurrentTime();
923
924     rc = dixLookupDevice (&dev, stuff->deviceid, client, DixSetPropAccess);
925     if (rc != Success)
926         return rc;
927
928     rc = check_change_property(client, stuff->property, stuff->type,
929                                stuff->format, stuff->mode, stuff->nUnits);
930
931     len = stuff->nUnits;
932     if (len > (bytes_to_int32(0xffffffff - sizeof(xChangeDevicePropertyReq))))
933         return BadLength;
934
935     totalSize = len * (stuff->format/8);
936     REQUEST_FIXED_SIZE(xChangeDevicePropertyReq, totalSize);
937
938     rc = change_property(client, dev, stuff->property, stuff->type,
939                          stuff->format, stuff->mode, len, (void*)&stuff[1]);
940     return rc;
941 }
942
943 int
944 ProcXDeleteDeviceProperty (ClientPtr client)
945 {
946     REQUEST(xDeleteDevicePropertyReq);
947     DeviceIntPtr        dev;
948     int                 rc;
949
950     REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq);
951     UpdateCurrentTime();
952     rc =  dixLookupDevice (&dev, stuff->deviceid, client, DixSetPropAccess);
953     if (rc != Success)
954         return rc;
955
956     if (!ValidAtom(stuff->property))
957     {
958         client->errorValue = stuff->property;
959         return BadAtom;
960     }
961
962     rc = XIDeleteDeviceProperty(dev, stuff->property, TRUE);
963     return rc;
964 }
965
966 int
967 ProcXGetDeviceProperty (ClientPtr client)
968 {
969     REQUEST(xGetDevicePropertyReq);
970     DeviceIntPtr                dev;
971     int                         length;
972     int                         rc, format, nitems, bytes_after;
973     char                        *data;
974     Atom                        type;
975     xGetDevicePropertyReply     reply;
976
977     REQUEST_SIZE_MATCH(xGetDevicePropertyReq);
978     if (stuff->delete)
979         UpdateCurrentTime();
980     rc = dixLookupDevice (&dev, stuff->deviceid, client,
981                            stuff->delete ? DixSetPropAccess :
982                            DixGetPropAccess);
983     if (rc != Success)
984         return rc;
985
986     rc = get_property(client, dev, stuff->property, stuff->type,
987             stuff->delete, stuff->longOffset, stuff->longLength,
988             &bytes_after, &type, &format, &nitems, &length, &data);
989
990     if (rc != Success)
991         return rc;
992
993     reply.repType = X_Reply;
994     reply.RepType = X_GetDeviceProperty;
995     reply.sequenceNumber = client->sequence;
996     reply.deviceid = dev->id;
997     reply.nItems = nitems;
998     reply.format = format;
999     reply.bytesAfter = bytes_after;
1000     reply.propertyType = type;
1001     reply.length = bytes_to_int32(length);
1002
1003     if (stuff->delete && (reply.bytesAfter == 0))
1004         send_property_event(dev, stuff->property, XIPropertyDeleted);
1005
1006     WriteReplyToClient(client, sizeof(xGenericReply), &reply);
1007
1008     if (length)
1009     {
1010         switch (reply.format) {
1011             case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break;
1012             case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break;
1013             default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break;
1014         }
1015         WriteSwappedDataToClient(client, length, data);
1016     }
1017
1018     /* delete the Property */
1019     if (stuff->delete && (reply.bytesAfter == 0))
1020     {
1021         XIPropertyPtr prop, *prev;
1022         for (prev = &dev->properties.properties; (prop = *prev); prev = &prop->next)
1023         {
1024             if (prop->propertyName == stuff->property)
1025             {
1026                 *prev = prop->next;
1027                 XIDestroyDeviceProperty(prop);
1028                 break;
1029             }
1030         }
1031     }
1032     return Success;
1033 }
1034
1035
1036 int
1037 SProcXListDeviceProperties (ClientPtr client)
1038 {
1039     char n;
1040     REQUEST(xListDevicePropertiesReq);
1041
1042     swaps(&stuff->length, n);
1043
1044     REQUEST_SIZE_MATCH(xListDevicePropertiesReq);
1045     return (ProcXListDeviceProperties(client));
1046 }
1047
1048 int
1049 SProcXChangeDeviceProperty (ClientPtr client)
1050 {
1051     char n;
1052     REQUEST(xChangeDevicePropertyReq);
1053
1054     REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq);
1055     swaps(&stuff->length, n);
1056     swapl(&stuff->property, n);
1057     swapl(&stuff->type, n);
1058     swapl(&stuff->nUnits, n);
1059     return (ProcXChangeDeviceProperty(client));
1060 }
1061
1062 int
1063 SProcXDeleteDeviceProperty (ClientPtr client)
1064 {
1065     char n;
1066     REQUEST(xDeleteDevicePropertyReq);
1067
1068     swaps(&stuff->length, n);
1069     swapl(&stuff->property, n);
1070     REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq);
1071     return (ProcXDeleteDeviceProperty(client));
1072 }
1073
1074 int
1075 SProcXGetDeviceProperty (ClientPtr client)
1076 {
1077     char n;
1078     REQUEST(xGetDevicePropertyReq);
1079
1080     swaps(&stuff->length, n);
1081     swapl(&stuff->property, n);
1082     swapl(&stuff->type, n);
1083     swapl(&stuff->longOffset, n);
1084     swapl(&stuff->longLength, n);
1085     REQUEST_SIZE_MATCH(xGetDevicePropertyReq);
1086     return (ProcXGetDeviceProperty(client));
1087 }
1088
1089
1090 /* Reply swapping */
1091
1092 void
1093 SRepXListDeviceProperties(ClientPtr client, int size,
1094                           xListDevicePropertiesReply *rep)
1095 {
1096     char n;
1097     swaps(&rep->sequenceNumber, n);
1098     swapl(&rep->length, n);
1099     swaps(&rep->nAtoms, n);
1100     /* properties will be swapped later, see ProcXListDeviceProperties */
1101     WriteToClient(client, size, (char*)rep);
1102 }
1103
1104 void
1105 SRepXGetDeviceProperty(ClientPtr client, int size,
1106                        xGetDevicePropertyReply *rep)
1107 {
1108     char n;
1109
1110     swaps(&rep->sequenceNumber, n);
1111     swapl(&rep->length, n);
1112     swapl(&rep->propertyType, n);
1113     swapl(&rep->bytesAfter, n);
1114     swapl(&rep->nItems, n);
1115     /* data will be swapped, see ProcXGetDeviceProperty */
1116     WriteToClient(client, size, (char*)rep);
1117 }
1118
1119 /* XI2 Request/reply handling */
1120 int
1121 ProcXIListProperties(ClientPtr client)
1122 {
1123     Atom                        *atoms;
1124     xXIListPropertiesReply      rep;
1125     int                         natoms;
1126     DeviceIntPtr                dev;
1127     int                         rc = Success;
1128
1129     REQUEST(xXIListPropertiesReq);
1130     REQUEST_SIZE_MATCH(xXIListPropertiesReq);
1131
1132     rc = dixLookupDevice (&dev, stuff->deviceid, client, DixListPropAccess);
1133     if (rc != Success)
1134         return rc;
1135
1136     rc = list_atoms(dev, &natoms, &atoms);
1137     if (rc != Success)
1138         return rc;
1139
1140     rep.repType = X_Reply;
1141     rep.RepType = X_XIListProperties;
1142     rep.length = natoms;
1143     rep.sequenceNumber = client->sequence;
1144     rep.num_properties = natoms;
1145
1146     WriteReplyToClient(client, sizeof(xXIListPropertiesReply), &rep);
1147     if (natoms)
1148     {
1149         client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write;
1150         WriteSwappedDataToClient(client, natoms * sizeof(Atom), atoms);
1151         free(atoms);
1152     }
1153     return rc;
1154 }
1155
1156 int
1157 ProcXIChangeProperty(ClientPtr client)
1158 {
1159     int                 rc;
1160     DeviceIntPtr        dev;
1161     int                 totalSize;
1162     unsigned long       len;
1163
1164     REQUEST(xXIChangePropertyReq);
1165     REQUEST_AT_LEAST_SIZE(xXIChangePropertyReq);
1166     UpdateCurrentTime();
1167
1168     rc = dixLookupDevice (&dev, stuff->deviceid, client, DixSetPropAccess);
1169     if (rc != Success)
1170         return rc;
1171
1172     rc = check_change_property(client, stuff->property, stuff->type,
1173                                stuff->format, stuff->mode, stuff->num_items);
1174     len = stuff->num_items;
1175     if (len > bytes_to_int32(0xffffffff - sizeof(xXIChangePropertyReq)))
1176         return BadLength;
1177
1178     totalSize = len * (stuff->format/8);
1179     REQUEST_FIXED_SIZE(xXIChangePropertyReq, totalSize);
1180
1181     rc = change_property(client, dev, stuff->property, stuff->type,
1182                          stuff->format, stuff->mode, len, (void*)&stuff[1]);
1183     return rc;
1184 }
1185
1186 int
1187 ProcXIDeleteProperty(ClientPtr client)
1188 {
1189     DeviceIntPtr        dev;
1190     int                 rc;
1191     REQUEST(xXIDeletePropertyReq);
1192
1193     REQUEST_SIZE_MATCH(xXIDeletePropertyReq);
1194     UpdateCurrentTime();
1195     rc =  dixLookupDevice (&dev, stuff->deviceid, client, DixSetPropAccess);
1196     if (rc != Success)
1197         return rc;
1198
1199     if (!ValidAtom(stuff->property))
1200     {
1201         client->errorValue = stuff->property;
1202         return BadAtom;
1203     }
1204
1205     rc = XIDeleteDeviceProperty(dev, stuff->property, TRUE);
1206     return rc;
1207 }
1208
1209
1210 int
1211 ProcXIGetProperty(ClientPtr client)
1212 {
1213     REQUEST(xXIGetPropertyReq);
1214     DeviceIntPtr                dev;
1215     xXIGetPropertyReply         reply;
1216     int                         length;
1217     int                         rc, format, nitems, bytes_after;
1218     char                        *data;
1219     Atom                        type;
1220
1221     REQUEST_SIZE_MATCH(xXIGetPropertyReq);
1222     if (stuff->delete)
1223         UpdateCurrentTime();
1224     rc = dixLookupDevice (&dev, stuff->deviceid, client,
1225                            stuff->delete ? DixSetPropAccess :
1226                            DixGetPropAccess);
1227     if (rc != Success)
1228         return rc;
1229
1230     rc = get_property(client, dev, stuff->property, stuff->type,
1231             stuff->delete, stuff->offset, stuff->len,
1232             &bytes_after, &type, &format, &nitems, &length, &data);
1233
1234     if (rc != Success)
1235         return rc;
1236
1237     reply.repType = X_Reply;
1238     reply.RepType = X_XIGetProperty;
1239     reply.sequenceNumber = client->sequence;
1240     reply.num_items = nitems;
1241     reply.format = format;
1242     reply.bytes_after = bytes_after;
1243     reply.type = type;
1244     reply.length = bytes_to_int32(length);
1245
1246     if (length && stuff->delete && (reply.bytes_after == 0))
1247         send_property_event(dev, stuff->property, XIPropertyDeleted);
1248
1249     WriteReplyToClient(client, sizeof(xXIGetPropertyReply), &reply);
1250
1251     if (length)
1252     {
1253         switch (reply.format) {
1254             case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break;
1255             case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break;
1256             default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break;
1257         }
1258         WriteSwappedDataToClient(client, length, data);
1259     }
1260
1261     /* delete the Property */
1262     if (stuff->delete && (reply.bytes_after == 0))
1263     {
1264         XIPropertyPtr prop, *prev;
1265         for (prev = &dev->properties.properties; (prop = *prev); prev = &prop->next)
1266         {
1267             if (prop->propertyName == stuff->property)
1268             {
1269                 *prev = prop->next;
1270                 XIDestroyDeviceProperty(prop);
1271                 break;
1272             }
1273         }
1274     }
1275
1276     return Success;
1277 }
1278
1279 int
1280 SProcXIListProperties(ClientPtr client)
1281 {
1282     char n;
1283     REQUEST(xXIListPropertiesReq);
1284
1285     swaps(&stuff->length, n);
1286     swaps(&stuff->deviceid, n);
1287
1288     REQUEST_SIZE_MATCH(xXIListPropertiesReq);
1289     return (ProcXIListProperties(client));
1290 }
1291
1292 int
1293 SProcXIChangeProperty(ClientPtr client)
1294 {
1295     char n;
1296     REQUEST(xXIChangePropertyReq);
1297
1298     REQUEST_AT_LEAST_SIZE(xXIChangePropertyReq);
1299     swaps(&stuff->length, n);
1300     swaps(&stuff->deviceid, n);
1301     swapl(&stuff->property, n);
1302     swapl(&stuff->type, n);
1303     swapl(&stuff->num_items, n);
1304     return (ProcXIChangeProperty(client));
1305 }
1306
1307 int
1308 SProcXIDeleteProperty(ClientPtr client)
1309 {
1310     char n;
1311     REQUEST(xXIDeletePropertyReq);
1312
1313     swaps(&stuff->length, n);
1314     swaps(&stuff->deviceid, n);
1315     swapl(&stuff->property, n);
1316     REQUEST_SIZE_MATCH(xXIDeletePropertyReq);
1317     return (ProcXIDeleteProperty(client));
1318 }
1319
1320 int
1321 SProcXIGetProperty(ClientPtr client)
1322 {
1323     char n;
1324     REQUEST(xXIGetPropertyReq);
1325
1326     swaps(&stuff->length, n);
1327     swaps(&stuff->deviceid, n);
1328     swapl(&stuff->property, n);
1329     swapl(&stuff->type, n);
1330     swapl(&stuff->offset, n);
1331     swapl(&stuff->len, n);
1332     REQUEST_SIZE_MATCH(xXIGetPropertyReq);
1333     return (ProcXIGetProperty(client));
1334 }
1335
1336
1337 void
1338 SRepXIListProperties(ClientPtr client, int size,
1339                      xXIListPropertiesReply *rep)
1340 {
1341     char n;
1342     swaps(&rep->sequenceNumber, n);
1343     swapl(&rep->length, n);
1344     swaps(&rep->num_properties, n);
1345     /* properties will be swapped later, see ProcXIListProperties */
1346     WriteToClient(client, size, (char*)rep);
1347 }
1348
1349 void
1350 SRepXIGetProperty(ClientPtr client, int size,
1351                   xXIGetPropertyReply *rep)
1352 {
1353     char n;
1354
1355     swaps(&rep->sequenceNumber, n);
1356     swapl(&rep->length, n);
1357     swapl(&rep->type, n);
1358     swapl(&rep->bytes_after, n);
1359     swapl(&rep->num_items, n);
1360     /* data will be swapped, see ProcXIGetProperty */
1361     WriteToClient(client, size, (char*)rep);
1362 }