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