2 * Copyright © 2006 Keith Packard
3 * Copyright © 2008 Peter Hutterer
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:
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
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.
26 /* This code is a modified version of randr/rrproperty.c */
28 #ifdef HAVE_DIX_CONFIG_H
29 #include <dix-config.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"
42 #include "xiproperty.h"
43 #include "xserver-properties.h"
46 * Properties used or alloced from inside the server.
48 static struct dev_properties
{
51 } dev_properties
[] = {
53 {0, XI_PROP_XTEST_DEVICE
},
55 {0, ACCEL_PROP_PROFILE_NUMBER
},
56 {0, ACCEL_PROP_CONSTANT_DECELERATION
},
57 {0, ACCEL_PROP_ADAPTIVE_DECELERATION
},
58 {0, ACCEL_PROP_VELOCITY_SCALING
},
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
},
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
}
182 static long XIPropHandlerID
= 1;
185 send_property_event(DeviceIntPtr dev
, Atom property
, int what
)
187 int state
= (what
== XIPropertyDeleted
) ? PropertyDelete
: PropertyNewValue
;
188 devicePropertyNotify event
= {
189 .type
= DevicePropertyNotify
,
193 .time
= currentTime
.milliseconds
195 xXIPropertyEvent xi2
= {
196 .type
= GenericEvent
,
197 .extension
= IReqCode
,
199 .evtype
= XI_PropertyEvent
,
201 .time
= currentTime
.milliseconds
,
202 .property
= property
,
206 SendEventToAllWindows(dev
, DevicePropertyNotifyMask
, (xEvent
*) &event
, 1);
208 SendEventToAllWindows(dev
, GetEventFilter(dev
, (xEvent
*) &xi2
),
213 list_atoms(DeviceIntPtr dev
, int *natoms
, Atom
**atoms_return
)
219 for (prop
= dev
->properties
.properties
; prop
; prop
= prop
->next
)
224 atoms
= malloc(nprops
* sizeof(Atom
));
228 for (prop
= dev
->properties
.properties
; prop
; prop
= prop
->next
, a
++)
229 *a
= prop
->propertyName
;
233 *atoms_return
= atoms
;
238 get_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
)
243 unsigned long n
, len
, ind
;
246 XIPropertyValuePtr prop_value
;
248 if (!ValidAtom(property
)) {
249 client
->errorValue
= property
;
252 if ((delete != xTrue
) && (delete != xFalse
)) {
253 client
->errorValue
= delete;
257 if ((type
!= AnyPropertyType
) && !ValidAtom(type
)) {
258 client
->errorValue
= type
;
262 for (prop
= dev
->properties
.properties
; prop
; prop
= prop
->next
)
263 if (prop
->propertyName
== property
)
275 rc
= XIGetDeviceProperty(dev
, property
, &prop_value
);
277 client
->errorValue
= property
;
281 /* If the request type and actual type don't match. Return the
282 property information, but not the data. */
284 if (((type
!= prop_value
->type
) && (type
!= AnyPropertyType
))) {
285 *bytes_after
= prop_value
->size
;
286 *format
= prop_value
->format
;
289 *type_return
= prop_value
->type
;
293 /* Return type, format, value to client */
294 n
= (prop_value
->format
/ 8) * prop_value
->size
; /* size (bytes) of prop */
297 /* If offset is invalid such that it causes "len" to
298 be negative, it's a value error. */
301 client
->errorValue
= offset
;
305 len
= min(n
- ind
, 4 * length
);
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);
314 *type_return
= prop_value
->type
;
316 *data
= (char *) prop_value
->data
+ ind
;
322 check_change_property(ClientPtr client
, Atom property
, Atom type
, int format
,
323 int mode
, int nitems
)
325 if ((mode
!= PropModeReplace
) && (mode
!= PropModeAppend
) &&
326 (mode
!= PropModePrepend
)) {
327 client
->errorValue
= mode
;
330 if ((format
!= 8) && (format
!= 16) && (format
!= 32)) {
331 client
->errorValue
= format
;
335 if (!ValidAtom(property
)) {
336 client
->errorValue
= property
;
339 if (!ValidAtom(type
)) {
340 client
->errorValue
= type
;
348 change_property(ClientPtr client
, DeviceIntPtr dev
, Atom property
, Atom type
,
349 int format
, int mode
, int len
, void *data
)
353 rc
= XIChangeDeviceProperty(dev
, property
, type
, format
, mode
, len
, data
,
356 client
->errorValue
= property
;
362 * Return the atom assigned to the specified string or 0 if the atom isn't known
365 * If name is NULL, None is returned.
368 XIGetKnownProperty(const char *name
)
375 for (i
= 0; i
< (sizeof(dev_properties
) / sizeof(struct dev_properties
));
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
);
384 return dev_properties
[i
].type
;
392 XIResetProperties(void)
396 for (i
= 0; i
< (sizeof(dev_properties
) / sizeof(struct dev_properties
));
398 dev_properties
[i
].type
= None
;
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
407 * If *@buf_return is NULL and @nelem_return is 0, memory is allocated
408 * automatically and must be freed by the caller.
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.
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.
422 XIPropToInt(XIPropertyValuePtr val
, int *nelem_return
, int **buf_return
)
427 if (val
->type
!= XA_INTEGER
)
429 if (!*buf_return
&& *nelem_return
)
432 switch (val
->format
) {
443 if (!buf
&& !(*nelem_return
)) {
444 buf
= calloc(val
->size
, sizeof(int));
448 *nelem_return
= val
->size
;
450 else if (val
->size
< *nelem_return
)
451 *nelem_return
= val
->size
;
453 for (i
= 0; i
< val
->size
&& i
< *nelem_return
; i
++) {
454 switch (val
->format
) {
456 buf
[i
] = ((CARD8
*) val
->data
)[i
];
459 buf
[i
] = ((CARD16
*) val
->data
)[i
];
462 buf
[i
] = ((CARD32
*) val
->data
)[i
];
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
476 * If *@buf_return is NULL and @nelem_return is 0, memory is allocated
477 * automatically and must be freed by the caller.
479 * Possible errors returned:
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.
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.
492 XIPropToFloat(XIPropertyValuePtr val
, int *nelem_return
, float **buf_return
)
497 if (!val
->type
|| val
->type
!= XIGetKnownProperty(XATOM_FLOAT
))
500 if (val
->format
!= 32)
502 if (!*buf_return
&& *nelem_return
)
507 if (!buf
&& !(*nelem_return
)) {
508 buf
= calloc(val
->size
, sizeof(float));
512 *nelem_return
= val
->size
;
514 else if (val
->size
< *nelem_return
)
515 *nelem_return
= val
->size
;
517 for (i
= 0; i
< val
->size
&& i
< *nelem_return
; i
++)
518 buf
[i
] = ((float *) val
->data
)[i
];
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.
529 XIRegisterPropertyHandler(DeviceIntPtr dev
,
530 int (*SetProperty
) (DeviceIntPtr dev
,
532 XIPropertyValuePtr prop
,
534 int (*GetProperty
) (DeviceIntPtr dev
,
536 int (*DeleteProperty
) (DeviceIntPtr dev
,
539 XIPropertyHandlerPtr new_handler
;
541 new_handler
= calloc(1, sizeof(XIPropertyHandler
));
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
;
552 return new_handler
->id
;
556 XIUnregisterPropertyHandler(DeviceIntPtr dev
, long id
)
558 XIPropertyHandlerPtr curr
, prev
= NULL
;
560 curr
= dev
->properties
.handlers
;
561 while (curr
&& curr
->id
!= id
) {
569 if (!prev
) /* first one */
570 dev
->properties
.handlers
= curr
->next
;
572 prev
->next
= curr
->next
;
578 XICreateDeviceProperty(Atom property
)
582 prop
= (XIPropertyPtr
) malloc(sizeof(XIPropertyRec
));
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
;
598 XIFetchDeviceProperty(DeviceIntPtr dev
, Atom property
)
602 for (prop
= dev
->properties
.properties
; prop
; prop
= prop
->next
)
603 if (prop
->propertyName
== property
)
609 XIDestroyDeviceProperty(XIPropertyPtr prop
)
611 free(prop
->value
.data
);
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.
620 XIDeleteAllDeviceProperties(DeviceIntPtr device
)
622 XIPropertyPtr prop
, next
;
623 XIPropertyHandlerPtr curr_handler
, next_handler
;
625 for (prop
= device
->properties
.properties
; prop
; prop
= next
) {
627 send_property_event(device
, prop
->propertyName
, XIPropertyDeleted
);
628 XIDestroyDeviceProperty(prop
);
631 device
->properties
.properties
= NULL
;
633 /* Now free all handlers */
634 curr_handler
= device
->properties
.handlers
;
635 while (curr_handler
) {
636 next_handler
= curr_handler
->next
;
638 curr_handler
= next_handler
;
641 device
->properties
.handlers
= NULL
;
645 XIDeleteDeviceProperty(DeviceIntPtr device
, Atom property
, Bool fromClient
)
647 XIPropertyPtr prop
, *prev
;
650 for (prev
= &device
->properties
.properties
; (prop
= *prev
);
651 prev
= &(prop
->next
))
652 if (prop
->propertyName
== property
)
658 if (fromClient
&& !prop
->deletable
)
661 /* Ask handlers if we may delete the property */
662 if (device
->properties
.handlers
) {
663 XIPropertyHandlerPtr handler
= device
->properties
.handlers
;
666 if (handler
->DeleteProperty
)
667 rc
= handler
->DeleteProperty(device
, prop
->propertyName
);
670 handler
= handler
->next
;
676 send_property_event(device
, prop
->propertyName
, XIPropertyDeleted
);
677 XIDestroyDeviceProperty(prop
);
684 XIChangeDeviceProperty(DeviceIntPtr dev
, Atom property
, Atom type
,
685 int format
, int mode
, unsigned long len
,
686 const void *value
, Bool sendevent
)
691 unsigned long total_len
;
692 XIPropertyValuePtr prop_value
;
693 XIPropertyValueRec new_value
;
697 size_in_bytes
= format
>> 3;
699 /* first see if property already exists */
700 prop
= XIFetchDeviceProperty(dev
, property
);
701 if (!prop
) { /* just add to list */
702 prop
= XICreateDeviceProperty(property
);
706 mode
= PropModeReplace
;
708 prop_value
= &prop
->value
;
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. */
715 if ((format
!= prop_value
->format
) && (mode
!= PropModeReplace
))
717 if ((prop_value
->type
!= type
) && (mode
!= PropModeReplace
))
719 new_value
= *prop_value
;
720 if (mode
== PropModeReplace
)
723 total_len
= prop_value
->size
+ len
;
725 if (mode
== PropModeReplace
|| len
> 0) {
726 pointer new_data
= NULL
, old_data
= NULL
;
728 total_size
= total_len
* size_in_bytes
;
729 new_value
.data
= (pointer
) malloc(total_size
);
730 if (!new_value
.data
&& total_size
) {
732 XIDestroyDeviceProperty(prop
);
735 new_value
.size
= len
;
736 new_value
.type
= type
;
737 new_value
.format
= format
;
740 case PropModeReplace
:
741 new_data
= new_value
.data
;
745 new_data
= (pointer
) (((char *) new_value
.data
) +
746 (prop_value
->size
* size_in_bytes
));
747 old_data
= new_value
.data
;
749 case PropModePrepend
:
750 new_data
= new_value
.data
;
751 old_data
= (pointer
) (((char *) new_value
.data
) +
752 (prop_value
->size
* size_in_bytes
));
756 memcpy((char *) new_data
, value
, len
* size_in_bytes
);
758 memcpy((char *) old_data
, (char *) prop_value
->data
,
759 prop_value
->size
* size_in_bytes
);
761 if (dev
->properties
.handlers
) {
762 XIPropertyHandlerPtr handler
;
763 BOOL checkonly
= TRUE
;
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 */
769 handler
= dev
->properties
.handlers
;
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
);
777 XIDestroyDeviceProperty(prop
);
781 handler
= handler
->next
;
783 checkonly
= !checkonly
;
784 } while (!checkonly
);
786 free(prop_value
->data
);
787 *prop_value
= new_value
;
794 prop
->next
= dev
->properties
.properties
;
795 dev
->properties
.properties
= prop
;
799 send_property_event(dev
, prop
->propertyName
,
800 (add
) ? XIPropertyCreated
: XIPropertyModified
);
806 XIGetDeviceProperty(DeviceIntPtr dev
, Atom property
, XIPropertyValuePtr
*value
)
808 XIPropertyPtr prop
= XIFetchDeviceProperty(dev
, property
);
816 /* If we can, try to update the property value first */
817 if (dev
->properties
.handlers
) {
818 XIPropertyHandlerPtr handler
= dev
->properties
.handlers
;
821 if (handler
->GetProperty
) {
822 rc
= handler
->GetProperty(dev
, prop
->propertyName
);
828 handler
= handler
->next
;
832 *value
= &prop
->value
;
837 XISetDevicePropertyDeletable(DeviceIntPtr dev
, Atom property
, Bool deletable
)
839 XIPropertyPtr prop
= XIFetchDeviceProperty(dev
, property
);
844 prop
->deletable
= deletable
;
849 ProcXListDeviceProperties(ClientPtr client
)
852 xListDevicePropertiesReply rep
;
857 REQUEST(xListDevicePropertiesReq
);
858 REQUEST_SIZE_MATCH(xListDevicePropertiesReq
);
860 rc
= dixLookupDevice(&dev
, stuff
->deviceid
, client
, DixListPropAccess
);
864 rc
= list_atoms(dev
, &natoms
, &atoms
);
868 rep
= (xListDevicePropertiesReply
) {
870 .RepType
= X_ListDeviceProperties
,
871 .sequenceNumber
= client
->sequence
,
876 WriteReplyToClient(client
, sizeof(xListDevicePropertiesReply
), &rep
);
878 client
->pSwapReplyFunc
= (ReplySwapPtr
) Swap32Write
;
879 WriteSwappedDataToClient(client
, natoms
* sizeof(Atom
), atoms
);
886 ProcXChangeDeviceProperty(ClientPtr client
)
888 REQUEST(xChangeDevicePropertyReq
);
894 REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq
);
897 rc
= dixLookupDevice(&dev
, stuff
->deviceid
, client
, DixSetPropAccess
);
901 rc
= check_change_property(client
, stuff
->property
, stuff
->type
,
902 stuff
->format
, stuff
->mode
, stuff
->nUnits
);
905 if (len
> (bytes_to_int32(0xffffffff - sizeof(xChangeDevicePropertyReq
))))
908 totalSize
= len
* (stuff
->format
/ 8);
909 REQUEST_FIXED_SIZE(xChangeDevicePropertyReq
, totalSize
);
911 rc
= change_property(client
, dev
, stuff
->property
, stuff
->type
,
912 stuff
->format
, stuff
->mode
, len
, (void *) &stuff
[1]);
917 ProcXDeleteDeviceProperty(ClientPtr client
)
919 REQUEST(xDeleteDevicePropertyReq
);
923 REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq
);
925 rc
= dixLookupDevice(&dev
, stuff
->deviceid
, client
, DixSetPropAccess
);
929 if (!ValidAtom(stuff
->property
)) {
930 client
->errorValue
= stuff
->property
;
934 rc
= XIDeleteDeviceProperty(dev
, stuff
->property
, TRUE
);
939 ProcXGetDeviceProperty(ClientPtr client
)
941 REQUEST(xGetDevicePropertyReq
);
944 int rc
, format
, nitems
, bytes_after
;
947 xGetDevicePropertyReply reply
;
949 REQUEST_SIZE_MATCH(xGetDevicePropertyReq
);
952 rc
= dixLookupDevice(&dev
, stuff
->deviceid
, client
,
953 stuff
->delete ? DixSetPropAccess
: DixGetPropAccess
);
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
);
964 reply
= (xGetDevicePropertyReply
) {
966 .RepType
= X_GetDeviceProperty
,
967 .sequenceNumber
= client
->sequence
,
968 .length
= bytes_to_int32(length
),
969 .propertyType
= type
,
970 .bytesAfter
= bytes_after
,
976 if (stuff
->delete && (reply
.bytesAfter
== 0))
977 send_property_event(dev
, stuff
->property
, XIPropertyDeleted
);
979 WriteReplyToClient(client
, sizeof(xGenericReply
), &reply
);
982 switch (reply
.format
) {
984 client
->pSwapReplyFunc
= (ReplySwapPtr
) CopySwap32Write
;
987 client
->pSwapReplyFunc
= (ReplySwapPtr
) CopySwap16Write
;
990 client
->pSwapReplyFunc
= (ReplySwapPtr
) WriteToClient
;
993 WriteSwappedDataToClient(client
, length
, data
);
996 /* delete the Property */
997 if (stuff
->delete && (reply
.bytesAfter
== 0)) {
998 XIPropertyPtr prop
, *prev
;
1000 for (prev
= &dev
->properties
.properties
; (prop
= *prev
);
1001 prev
= &prop
->next
) {
1002 if (prop
->propertyName
== stuff
->property
) {
1004 XIDestroyDeviceProperty(prop
);
1013 SProcXListDeviceProperties(ClientPtr client
)
1015 REQUEST(xListDevicePropertiesReq
);
1017 swaps(&stuff
->length
);
1019 REQUEST_SIZE_MATCH(xListDevicePropertiesReq
);
1020 return (ProcXListDeviceProperties(client
));
1024 SProcXChangeDeviceProperty(ClientPtr client
)
1026 REQUEST(xChangeDevicePropertyReq
);
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
));
1037 SProcXDeleteDeviceProperty(ClientPtr client
)
1039 REQUEST(xDeleteDevicePropertyReq
);
1041 swaps(&stuff
->length
);
1042 swapl(&stuff
->property
);
1043 REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq
);
1044 return (ProcXDeleteDeviceProperty(client
));
1048 SProcXGetDeviceProperty(ClientPtr client
)
1050 REQUEST(xGetDevicePropertyReq
);
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
));
1061 /* Reply swapping */
1064 SRepXListDeviceProperties(ClientPtr client
, int size
,
1065 xListDevicePropertiesReply
* rep
)
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
);
1075 SRepXGetDeviceProperty(ClientPtr client
, int size
,
1076 xGetDevicePropertyReply
* rep
)
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
);
1087 /* XI2 Request/reply handling */
1089 ProcXIListProperties(ClientPtr client
)
1092 xXIListPropertiesReply rep
;
1097 REQUEST(xXIListPropertiesReq
);
1098 REQUEST_SIZE_MATCH(xXIListPropertiesReq
);
1100 rc
= dixLookupDevice(&dev
, stuff
->deviceid
, client
, DixListPropAccess
);
1104 rc
= list_atoms(dev
, &natoms
, &atoms
);
1108 rep
= (xXIListPropertiesReply
) {
1110 .RepType
= X_XIListProperties
,
1111 .sequenceNumber
= client
->sequence
,
1113 .num_properties
= natoms
1116 WriteReplyToClient(client
, sizeof(xXIListPropertiesReply
), &rep
);
1118 client
->pSwapReplyFunc
= (ReplySwapPtr
) Swap32Write
;
1119 WriteSwappedDataToClient(client
, natoms
* sizeof(Atom
), atoms
);
1126 ProcXIChangeProperty(ClientPtr client
)
1133 REQUEST(xXIChangePropertyReq
);
1134 REQUEST_AT_LEAST_SIZE(xXIChangePropertyReq
);
1135 UpdateCurrentTime();
1137 rc
= dixLookupDevice(&dev
, stuff
->deviceid
, client
, DixSetPropAccess
);
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
)))
1147 totalSize
= len
* (stuff
->format
/ 8);
1148 REQUEST_FIXED_SIZE(xXIChangePropertyReq
, totalSize
);
1150 rc
= change_property(client
, dev
, stuff
->property
, stuff
->type
,
1151 stuff
->format
, stuff
->mode
, len
, (void *) &stuff
[1]);
1156 ProcXIDeleteProperty(ClientPtr client
)
1161 REQUEST(xXIDeletePropertyReq
);
1163 REQUEST_SIZE_MATCH(xXIDeletePropertyReq
);
1164 UpdateCurrentTime();
1165 rc
= dixLookupDevice(&dev
, stuff
->deviceid
, client
, DixSetPropAccess
);
1169 if (!ValidAtom(stuff
->property
)) {
1170 client
->errorValue
= stuff
->property
;
1174 rc
= XIDeleteDeviceProperty(dev
, stuff
->property
, TRUE
);
1179 ProcXIGetProperty(ClientPtr client
)
1181 REQUEST(xXIGetPropertyReq
);
1183 xXIGetPropertyReply reply
;
1185 int rc
, format
, nitems
, bytes_after
;
1189 REQUEST_SIZE_MATCH(xXIGetPropertyReq
);
1191 UpdateCurrentTime();
1192 rc
= dixLookupDevice(&dev
, stuff
->deviceid
, client
,
1193 stuff
->delete ? DixSetPropAccess
: DixGetPropAccess
);
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
);
1204 reply
= (xXIGetPropertyReply
) {
1206 .RepType
= X_XIGetProperty
,
1207 .sequenceNumber
= client
->sequence
,
1208 .length
= bytes_to_int32(length
),
1210 .bytes_after
= bytes_after
,
1211 .num_items
= nitems
,
1215 if (length
&& stuff
->delete && (reply
.bytes_after
== 0))
1216 send_property_event(dev
, stuff
->property
, XIPropertyDeleted
);
1218 WriteReplyToClient(client
, sizeof(xXIGetPropertyReply
), &reply
);
1221 switch (reply
.format
) {
1223 client
->pSwapReplyFunc
= (ReplySwapPtr
) CopySwap32Write
;
1226 client
->pSwapReplyFunc
= (ReplySwapPtr
) CopySwap16Write
;
1229 client
->pSwapReplyFunc
= (ReplySwapPtr
) WriteToClient
;
1232 WriteSwappedDataToClient(client
, length
, data
);
1235 /* delete the Property */
1236 if (stuff
->delete && (reply
.bytes_after
== 0)) {
1237 XIPropertyPtr prop
, *prev
;
1239 for (prev
= &dev
->properties
.properties
; (prop
= *prev
);
1240 prev
= &prop
->next
) {
1241 if (prop
->propertyName
== stuff
->property
) {
1243 XIDestroyDeviceProperty(prop
);
1253 SProcXIListProperties(ClientPtr client
)
1255 REQUEST(xXIListPropertiesReq
);
1257 swaps(&stuff
->length
);
1258 swaps(&stuff
->deviceid
);
1260 REQUEST_SIZE_MATCH(xXIListPropertiesReq
);
1261 return (ProcXIListProperties(client
));
1265 SProcXIChangeProperty(ClientPtr client
)
1267 REQUEST(xXIChangePropertyReq
);
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
));
1279 SProcXIDeleteProperty(ClientPtr client
)
1281 REQUEST(xXIDeletePropertyReq
);
1283 swaps(&stuff
->length
);
1284 swaps(&stuff
->deviceid
);
1285 swapl(&stuff
->property
);
1286 REQUEST_SIZE_MATCH(xXIDeletePropertyReq
);
1287 return (ProcXIDeleteProperty(client
));
1291 SProcXIGetProperty(ClientPtr client
)
1293 REQUEST(xXIGetPropertyReq
);
1295 swaps(&stuff
->length
);
1296 swaps(&stuff
->deviceid
);
1297 swapl(&stuff
->property
);
1298 swapl(&stuff
->type
);
1299 swapl(&stuff
->offset
);
1301 REQUEST_SIZE_MATCH(xXIGetPropertyReq
);
1302 return (ProcXIGetProperty(client
));
1306 SRepXIListProperties(ClientPtr client
, int size
, xXIListPropertiesReply
* rep
)
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
);
1316 SRepXIGetProperty(ClientPtr client
, int size
, xXIGetPropertyReply
* rep
)
1318 swaps(&rep
->sequenceNumber
);
1319 swapl(&rep
->length
);
1321 swapl(&rep
->bytes_after
);
1322 swapl(&rep
->num_items
);
1323 /* data will be swapped, see ProcXIGetProperty */
1324 WriteToClient(client
, size
, rep
);