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