1 /*
2 * Copyright © 2006 Keith Packard
3 * Copyright © 2008 Peter Hutterer
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WAXIANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WAXIANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 */
25
26 /* This code is a modified version of randr/rrproperty.c */
27
28 #ifdef HAVE_DIX_CONFIG_H
29 #include <dix-config.h>
30 #endif
31
32 #include "dix.h"
33 #include "inputstr.h"
34 #include <X11/extensions/XI.h>
35 #include <X11/Xatom.h>
36 #include <X11/extensions/XIproto.h>
37 #include <X11/extensions/XI2proto.h>
38 #include "exglobals.h"
39 #include "exevents.h"
40 #include "swaprep.h"
41
42 #include "xiproperty.h"
43 #include "xserver-properties.h"
44
45 /**
46 * Properties used or alloced from inside the server.
47 */
48 static struct dev_properties {
49 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
182 static long XIPropHandlerID = 1;
183
184 static void
send_property_event(DeviceIntPtr dev,Atom property,int what)185 send_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
212 static int
list_atoms(DeviceIntPtr dev,int * natoms,Atom ** atoms_return)213 list_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 = xallocarray(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
237 static int
get_property(ClientPtr client,DeviceIntPtr dev,Atom property,Atom type,BOOL delete,int offset,int length,int * bytes_after,Atom * type_return,int * format,int * nitems,int * length_return,char ** data)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)
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
321 static int
check_change_property(ClientPtr client,Atom property,Atom type,int format,int mode,int nitems)322 check_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
347 static int
change_property(ClientPtr client,DeviceIntPtr dev,Atom property,Atom type,int format,int mode,int len,void * data)348 change_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 */
367 Atom
XIGetKnownProperty(const char * name)368 XIGetKnownProperty(const char *name)
369 {
370 int i;
371
372 if (!name)
373 return None;
374
375 for (i = 0; i < ARRAY_SIZE(dev_properties); i++) {
376 if (strcmp(name, dev_properties[i].name) == 0) {
377 if (dev_properties[i].type == None) {
378 dev_properties[i].type =
379 MakeAtom(dev_properties[i].name,
380 strlen(dev_properties[i].name), TRUE);
381 }
382
383 return dev_properties[i].type;
384 }
385 }
386
387 return 0;
388 }
389
390 void
XIResetProperties(void)391 XIResetProperties(void)
392 {
393 int i;
394
395 for (i = 0; i < ARRAY_SIZE(dev_properties); i++)
396 dev_properties[i].type = None;
397 }
398
399 /**
400 * Convert the given property's value(s) into @nelem_return integer values and
401 * store them in @buf_return. If @nelem_return is larger than the number of
402 * values in the property, @nelem_return is set to the number of values in the
403 * property.
404 *
405 * If *@buf_return is NULL and @nelem_return is 0, memory is allocated
406 * automatically and must be freed by the caller.
407 *
408 * Possible return codes.
409 * Success ... No error.
410 * BadMatch ... Wrong atom type, atom is not XA_INTEGER
411 * BadAlloc ... NULL passed as buffer and allocation failed.
412 * BadLength ... @buff is NULL but @nelem_return is non-zero.
413 *
414 * @param val The property value
415 * @param nelem_return The maximum number of elements to return.
416 * @param buf_return Pointer to an array of at least @nelem_return values.
417 * @return Success or the error code if an error occured.
418 */
419 _X_EXPORT int
XIPropToInt(XIPropertyValuePtr val,int * nelem_return,int ** buf_return)420 XIPropToInt(XIPropertyValuePtr val, int *nelem_return, int **buf_return)
421 {
422 int i;
423 int *buf;
424
425 if (val->type != XA_INTEGER)
426 return BadMatch;
427 if (!*buf_return && *nelem_return)
428 return BadLength;
429
430 switch (val->format) {
431 case 8:
432 case 16:
433 case 32:
434 break;
435 default:
436 return BadValue;
437 }
438
439 buf = *buf_return;
440
441 if (!buf && !(*nelem_return)) {
442 buf = calloc(val->size, sizeof(int));
443 if (!buf)
444 return BadAlloc;
445 *buf_return = buf;
446 *nelem_return = val->size;
447 }
448 else if (val->size < *nelem_return)
449 *nelem_return = val->size;
450
451 for (i = 0; i < val->size && i < *nelem_return; i++) {
452 switch (val->format) {
453 case 8:
454 buf[i] = ((CARD8 *) val->data)[i];
455 break;
456 case 16:
457 buf[i] = ((CARD16 *) val->data)[i];
458 break;
459 case 32:
460 buf[i] = ((CARD32 *) val->data)[i];
461 break;
462 }
463 }
464
465 return Success;
466 }
467
468 /**
469 * Convert the given property's value(s) into @nelem_return float values and
470 * store them in @buf_return. If @nelem_return is larger than the number of
471 * values in the property, @nelem_return is set to the number of values in the
472 * property.
473 *
474 * If *@buf_return is NULL and @nelem_return is 0, memory is allocated
475 * automatically and must be freed by the caller.
476 *
477 * Possible errors returned:
478 * Success
479 * BadMatch ... Wrong atom type, atom is not XA_FLOAT
480 * BadValue ... Wrong format, format is not 32
481 * BadAlloc ... NULL passed as buffer and allocation failed.
482 * BadLength ... @buff is NULL but @nelem_return is non-zero.
483 *
484 * @param val The property value
485 * @param nelem_return The maximum number of elements to return.
486 * @param buf_return Pointer to an array of at least @nelem_return values.
487 * @return Success or the error code if an error occured.
488 */
489 _X_EXPORT int
XIPropToFloat(XIPropertyValuePtr val,int * nelem_return,float ** buf_return)490 XIPropToFloat(XIPropertyValuePtr val, int *nelem_return, float **buf_return)
491 {
492 int i;
493 float *buf;
494
495 if (!val->type || val->type != XIGetKnownProperty(XATOM_FLOAT))
496 return BadMatch;
497
498 if (val->format != 32)
499 return BadValue;
500 if (!*buf_return && *nelem_return)
501 return BadLength;
502
503 buf = *buf_return;
504
505 if (!buf && !(*nelem_return)) {
506 buf = calloc(val->size, sizeof(float));
507 if (!buf)
508 return BadAlloc;
509 *buf_return = buf;
510 *nelem_return = val->size;
511 }
512 else if (val->size < *nelem_return)
513 *nelem_return = val->size;
514
515 for (i = 0; i < val->size && i < *nelem_return; i++)
516 buf[i] = ((float *) val->data)[i];
517
518 return Success;
519 }
520
521 /* Registers a new property handler on the given device and returns a unique
522 * identifier for this handler. This identifier is required to unregister the
523 * property handler again.
524 * @return The handler's identifier or 0 if an error occured.
525 */
526 long
XIRegisterPropertyHandler(DeviceIntPtr dev,int (* SetProperty)(DeviceIntPtr dev,Atom property,XIPropertyValuePtr prop,BOOL checkonly),int (* GetProperty)(DeviceIntPtr dev,Atom property),int (* DeleteProperty)(DeviceIntPtr dev,Atom property))527 XIRegisterPropertyHandler(DeviceIntPtr dev,
528 int (*SetProperty) (DeviceIntPtr dev,
529 Atom property,
530 XIPropertyValuePtr prop,
531 BOOL checkonly),
532 int (*GetProperty) (DeviceIntPtr dev,
533 Atom property),
534 int (*DeleteProperty) (DeviceIntPtr dev,
535 Atom property))
536 {
537 XIPropertyHandlerPtr new_handler;
538
539 new_handler = calloc(1, sizeof(XIPropertyHandler));
540 if (!new_handler)
541 return 0;
542
543 new_handler->id = XIPropHandlerID++;
544 new_handler->SetProperty = SetProperty;
545 new_handler->GetProperty = GetProperty;
546 new_handler->DeleteProperty = DeleteProperty;
547 new_handler->next = dev->properties.handlers;
548 dev->properties.handlers = new_handler;
549
550 return new_handler->id;
551 }
552
553 void
XIUnregisterPropertyHandler(DeviceIntPtr dev,long id)554 XIUnregisterPropertyHandler(DeviceIntPtr dev, long id)
555 {
556 XIPropertyHandlerPtr curr, prev = NULL;
557
558 curr = dev->properties.handlers;
559 while (curr && curr->id != id) {
560 prev = curr;
561 curr = curr->next;
562 }
563
564 if (!curr)
565 return;
566
567 if (!prev) /* first one */
568 dev->properties.handlers = curr->next;
569 else
570 prev->next = curr->next;
571
572 free(curr);
573 }
574
575 static XIPropertyPtr
XICreateDeviceProperty(Atom property)576 XICreateDeviceProperty(Atom property)
577 {
578 XIPropertyPtr prop;
579
580 prop = (XIPropertyPtr) malloc(sizeof(XIPropertyRec));
581 if (!prop)
582 return NULL;
583
584 prop->next = NULL;
585 prop->propertyName = property;
586 prop->value.type = None;
587 prop->value.format = 0;
588 prop->value.size = 0;
589 prop->value.data = NULL;
590 prop->deletable = TRUE;
591
592 return prop;
593 }
594
595 static XIPropertyPtr
XIFetchDeviceProperty(DeviceIntPtr dev,Atom property)596 XIFetchDeviceProperty(DeviceIntPtr dev, Atom property)
597 {
598 XIPropertyPtr prop;
599
600 for (prop = dev->properties.properties; prop; prop = prop->next)
601 if (prop->propertyName == property)
602 return prop;
603 return NULL;
604 }
605
606 static void
XIDestroyDeviceProperty(XIPropertyPtr prop)607 XIDestroyDeviceProperty(XIPropertyPtr prop)
608 {
609 free(prop->value.data);
610 free(prop);
611 }
612
613 /* This function destroys all of the device's property-related stuff,
614 * including removing all device handlers.
615 * DO NOT CALL FROM THE DRIVER.
616 */
617 void
XIDeleteAllDeviceProperties(DeviceIntPtr device)618 XIDeleteAllDeviceProperties(DeviceIntPtr device)
619 {
620 XIPropertyPtr prop, next;
621 XIPropertyHandlerPtr curr_handler, next_handler;
622
623 UpdateCurrentTimeIf();
624 for (prop = device->properties.properties; prop; prop = next) {
625 next = prop->next;
626 send_property_event(device, prop->propertyName, XIPropertyDeleted);
627 XIDestroyDeviceProperty(prop);
628 }
629
630 device->properties.properties = NULL;
631
632 /* Now free all handlers */
633 curr_handler = device->properties.handlers;
634 while (curr_handler) {
635 next_handler = curr_handler->next;
636 free(curr_handler);
637 curr_handler = next_handler;
638 }
639
640 device->properties.handlers = NULL;
641 }
642
643 int
XIDeleteDeviceProperty(DeviceIntPtr device,Atom property,Bool fromClient)644 XIDeleteDeviceProperty(DeviceIntPtr device, Atom property, Bool fromClient)
645 {
646 XIPropertyPtr prop, *prev;
647 int rc = Success;
648
649 for (prev = &device->properties.properties; (prop = *prev);
650 prev = &(prop->next))
651 if (prop->propertyName == property)
652 break;
653
654 if (!prop)
655 return Success;
656
657 if (fromClient && !prop->deletable)
658 return BadAccess;
659
660 /* Ask handlers if we may delete the property */
661 if (device->properties.handlers) {
662 XIPropertyHandlerPtr handler = device->properties.handlers;
663
664 while (handler) {
665 if (handler->DeleteProperty)
666 rc = handler->DeleteProperty(device, prop->propertyName);
667 if (rc != Success)
668 return rc;
669 handler = handler->next;
670 }
671 }
672
673 if (prop) {
674 UpdateCurrentTimeIf();
675 *prev = prop->next;
676 send_property_event(device, prop->propertyName, XIPropertyDeleted);
677 XIDestroyDeviceProperty(prop);
678 }
679
680 return Success;
681 }
682
683 int
XIChangeDeviceProperty(DeviceIntPtr dev,Atom property,Atom type,int format,int mode,unsigned long len,const void * value,Bool sendevent)684 XIChangeDeviceProperty(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 unsigned long total_len;
691 XIPropertyValuePtr prop_value;
692 XIPropertyValueRec new_value;
693 Bool add = FALSE;
694 int rc;
695
696 size_in_bytes = format >> 3;
697
698 /* first see if property already exists */
699 prop = XIFetchDeviceProperty(dev, property);
700 if (!prop) { /* just add to list */
701 prop = XICreateDeviceProperty(property);
702 if (!prop)
703 return BadAlloc;
704 add = TRUE;
705 mode = PropModeReplace;
706 }
707 prop_value = &prop->value;
708
709 /* To append or prepend to a property the request format and type
710 must match those of the already defined property. The
711 existing format and type are irrelevant when using the mode
712 "PropModeReplace" since they will be written over. */
713
714 if ((format != prop_value->format) && (mode != PropModeReplace))
715 return BadMatch;
716 if ((prop_value->type != type) && (mode != PropModeReplace))
717 return BadMatch;
718 new_value = *prop_value;
719 if (mode == PropModeReplace)
720 total_len = len;
721 else
722 total_len = prop_value->size + len;
723
724 if (mode == PropModeReplace || len > 0) {
725 void *new_data = NULL, *old_data = NULL;
726
727 new_value.data = xallocarray(total_len, size_in_bytes);
728 if (!new_value.data && total_len && size_in_bytes) {
729 if (add)
730 XIDestroyDeviceProperty(prop);
731 return BadAlloc;
732 }
733 new_value.size = len;
734 new_value.type = type;
735 new_value.format = format;
736
737 switch (mode) {
738 case PropModeReplace:
739 new_data = new_value.data;
740 old_data = NULL;
741 break;
742 case PropModeAppend:
743 new_data = (void *) (((char *) new_value.data) +
744 (prop_value->size * size_in_bytes));
745 old_data = new_value.data;
746 break;
747 case PropModePrepend:
748 new_data = new_value.data;
749 old_data = (void *) (((char *) new_value.data) +
750 (prop_value->size * size_in_bytes));
751 break;
752 }
753 if (new_data)
754 memcpy((char *) new_data, value, len * size_in_bytes);
755 if (old_data)
756 memcpy((char *) old_data, (char *) prop_value->data,
757 prop_value->size * size_in_bytes);
758
759 if (dev->properties.handlers) {
760 XIPropertyHandlerPtr handler;
761 BOOL checkonly = TRUE;
762
763 /* run through all handlers with checkonly TRUE, then again with
764 * checkonly FALSE. Handlers MUST return error codes on the
765 * checkonly run, errors on the second run are ignored */
766 do {
767 handler = dev->properties.handlers;
768 while (handler) {
769 if (handler->SetProperty) {
770 input_lock();
771 rc = handler->SetProperty(dev, prop->propertyName,
772 &new_value, checkonly);
773 input_unlock();
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 UpdateCurrentTimeIf();
800 send_property_event(dev, prop->propertyName,
801 (add) ? XIPropertyCreated : XIPropertyModified);
802 }
803
804 return Success;
805 }
806
807 int
XIGetDeviceProperty(DeviceIntPtr dev,Atom property,XIPropertyValuePtr * value)808 XIGetDeviceProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr *value)
809 {
810 XIPropertyPtr prop = XIFetchDeviceProperty(dev, property);
811 int rc;
812
813 if (!prop) {
814 *value = NULL;
815 return BadAtom;
816 }
817
818 /* If we can, try to update the property value first */
819 if (dev->properties.handlers) {
820 XIPropertyHandlerPtr handler = dev->properties.handlers;
821
822 while (handler) {
823 if (handler->GetProperty) {
824 rc = handler->GetProperty(dev, prop->propertyName);
825 if (rc != Success) {
826 *value = NULL;
827 return rc;
828 }
829 }
830 handler = handler->next;
831 }
832 }
833
834 *value = &prop->value;
835 return Success;
836 }
837
838 int
XISetDevicePropertyDeletable(DeviceIntPtr dev,Atom property,Bool deletable)839 XISetDevicePropertyDeletable(DeviceIntPtr dev, Atom property, Bool deletable)
840 {
841 XIPropertyPtr prop = XIFetchDeviceProperty(dev, property);
842
843 if (!prop)
844 return BadAtom;
845
846 prop->deletable = deletable;
847 return Success;
848 }
849
850 int
ProcXListDeviceProperties(ClientPtr client)851 ProcXListDeviceProperties(ClientPtr client)
852 {
853 Atom *atoms;
854 xListDevicePropertiesReply rep;
855 int natoms;
856 DeviceIntPtr dev;
857 int rc = Success;
858
859 REQUEST(xListDevicePropertiesReq);
860 REQUEST_SIZE_MATCH(xListDevicePropertiesReq);
861
862 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixListPropAccess);
863 if (rc != Success)
864 return rc;
865
866 rc = list_atoms(dev, &natoms, &atoms);
867 if (rc != Success)
868 return rc;
869
870 rep = (xListDevicePropertiesReply) {
871 .repType = X_Reply,
872 .RepType = X_ListDeviceProperties,
873 .sequenceNumber = client->sequence,
874 .length = natoms,
875 .nAtoms = natoms
876 };
877
878 WriteReplyToClient(client, sizeof(xListDevicePropertiesReply), &rep);
879 if (natoms) {
880 client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
881 WriteSwappedDataToClient(client, natoms * sizeof(Atom), atoms);
882 free(atoms);
883 }
884 return rc;
885 }
886
887 int
ProcXChangeDeviceProperty(ClientPtr client)888 ProcXChangeDeviceProperty(ClientPtr client)
889 {
890 REQUEST(xChangeDevicePropertyReq);
891 DeviceIntPtr dev;
892 unsigned long len;
893 int totalSize;
894 int rc;
895
896 REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq);
897 UpdateCurrentTime();
898
899 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixSetPropAccess);
900 if (rc != Success)
901 return rc;
902
903 rc = check_change_property(client, stuff->property, stuff->type,
904 stuff->format, stuff->mode, stuff->nUnits);
905
906 len = stuff->nUnits;
907 if (len > (bytes_to_int32(0xffffffff - sizeof(xChangeDevicePropertyReq))))
908 return BadLength;
909
910 totalSize = len * (stuff->format / 8);
911 REQUEST_FIXED_SIZE(xChangeDevicePropertyReq, totalSize);
912
913 rc = change_property(client, dev, stuff->property, stuff->type,
914 stuff->format, stuff->mode, len, (void *) &stuff[1]);
915 return rc;
916 }
917
918 int
ProcXDeleteDeviceProperty(ClientPtr client)919 ProcXDeleteDeviceProperty(ClientPtr client)
920 {
921 REQUEST(xDeleteDevicePropertyReq);
922 DeviceIntPtr dev;
923 int rc;
924
925 REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq);
926 UpdateCurrentTime();
927 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixSetPropAccess);
928 if (rc != Success)
929 return rc;
930
931 if (!ValidAtom(stuff->property)) {
932 client->errorValue = stuff->property;
933 return BadAtom;
934 }
935
936 rc = XIDeleteDeviceProperty(dev, stuff->property, TRUE);
937 return rc;
938 }
939
940 int
ProcXGetDeviceProperty(ClientPtr client)941 ProcXGetDeviceProperty(ClientPtr client)
942 {
943 REQUEST(xGetDevicePropertyReq);
944 DeviceIntPtr dev;
945 int length;
946 int rc, format, nitems, bytes_after;
947 char *data;
948 Atom type;
949 xGetDevicePropertyReply reply;
950
951 REQUEST_SIZE_MATCH(xGetDevicePropertyReq);
952 if (stuff->delete)
953 UpdateCurrentTime();
954 rc = dixLookupDevice(&dev, stuff->deviceid, client,
955 stuff->delete ? DixSetPropAccess : DixGetPropAccess);
956 if (rc != Success)
957 return rc;
958
959 rc = get_property(client, dev, stuff->property, stuff->type,
960 stuff->delete, stuff->longOffset, stuff->longLength,
961 &bytes_after, &type, &format, &nitems, &length, &data);
962
963 if (rc != Success)
964 return rc;
965
966 reply = (xGetDevicePropertyReply) {
967 .repType = X_Reply,
968 .RepType = X_GetDeviceProperty,
969 .sequenceNumber = client->sequence,
970 .length = bytes_to_int32(length),
971 .propertyType = type,
972 .bytesAfter = bytes_after,
973 .nItems = nitems,
974 .format = format,
975 .deviceid = dev->id
976 };
977
978 if (stuff->delete && (reply.bytesAfter == 0))
979 send_property_event(dev, stuff->property, XIPropertyDeleted);
980
981 WriteReplyToClient(client, sizeof(xGenericReply), &reply);
982
983 if (length) {
984 switch (reply.format) {
985 case 32:
986 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write;
987 break;
988 case 16:
989 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write;
990 break;
991 default:
992 client->pSwapReplyFunc = (ReplySwapPtr) WriteToClient;
993 break;
994 }
995 WriteSwappedDataToClient(client, length, data);
996 }
997
998 /* delete the Property */
999 if (stuff->delete && (reply.bytesAfter == 0)) {
1000 XIPropertyPtr prop, *prev;
1001
1002 for (prev = &dev->properties.properties; (prop = *prev);
1003 prev = &prop->next) {
1004 if (prop->propertyName == stuff->property) {
1005 *prev = prop->next;
1006 XIDestroyDeviceProperty(prop);
1007 break;
1008 }
1009 }
1010 }
1011 return Success;
1012 }
1013
1014 int _X_COLD
SProcXListDeviceProperties(ClientPtr client)1015 SProcXListDeviceProperties(ClientPtr client)
1016 {
1017 REQUEST(xListDevicePropertiesReq);
1018 REQUEST_SIZE_MATCH(xListDevicePropertiesReq);
1019
1020 swaps(&stuff->length);
1021 return (ProcXListDeviceProperties(client));
1022 }
1023
1024 int _X_COLD
SProcXChangeDeviceProperty(ClientPtr client)1025 SProcXChangeDeviceProperty(ClientPtr client)
1026 {
1027 REQUEST(xChangeDevicePropertyReq);
1028
1029 REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq);
1030 swaps(&stuff->length);
1031 swapl(&stuff->property);
1032 swapl(&stuff->type);
1033 swapl(&stuff->nUnits);
1034 return (ProcXChangeDeviceProperty(client));
1035 }
1036
1037 int _X_COLD
SProcXDeleteDeviceProperty(ClientPtr client)1038 SProcXDeleteDeviceProperty(ClientPtr client)
1039 {
1040 REQUEST(xDeleteDevicePropertyReq);
1041 REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq);
1042
1043 swaps(&stuff->length);
1044 swapl(&stuff->property);
1045 return (ProcXDeleteDeviceProperty(client));
1046 }
1047
1048 int _X_COLD
SProcXGetDeviceProperty(ClientPtr client)1049 SProcXGetDeviceProperty(ClientPtr client)
1050 {
1051 REQUEST(xGetDevicePropertyReq);
1052 REQUEST_SIZE_MATCH(xGetDevicePropertyReq);
1053
1054 swaps(&stuff->length);
1055 swapl(&stuff->property);
1056 swapl(&stuff->type);
1057 swapl(&stuff->longOffset);
1058 swapl(&stuff->longLength);
1059 return (ProcXGetDeviceProperty(client));
1060 }
1061
1062 /* Reply swapping */
1063
1064 void _X_COLD
SRepXListDeviceProperties(ClientPtr client,int size,xListDevicePropertiesReply * rep)1065 SRepXListDeviceProperties(ClientPtr client, int size,
1066 xListDevicePropertiesReply * rep)
1067 {
1068 swaps(&rep->sequenceNumber);
1069 swapl(&rep->length);
1070 swaps(&rep->nAtoms);
1071 /* properties will be swapped later, see ProcXListDeviceProperties */
1072 WriteToClient(client, size, rep);
1073 }
1074
1075 void _X_COLD
SRepXGetDeviceProperty(ClientPtr client,int size,xGetDevicePropertyReply * rep)1076 SRepXGetDeviceProperty(ClientPtr client, int size,
1077 xGetDevicePropertyReply * rep)
1078 {
1079 swaps(&rep->sequenceNumber);
1080 swapl(&rep->length);
1081 swapl(&rep->propertyType);
1082 swapl(&rep->bytesAfter);
1083 swapl(&rep->nItems);
1084 /* data will be swapped, see ProcXGetDeviceProperty */
1085 WriteToClient(client, size, rep);
1086 }
1087
1088 /* XI2 Request/reply handling */
1089 int
ProcXIListProperties(ClientPtr client)1090 ProcXIListProperties(ClientPtr client)
1091 {
1092 Atom *atoms;
1093 xXIListPropertiesReply rep;
1094 int natoms;
1095 DeviceIntPtr dev;
1096 int rc = Success;
1097
1098 REQUEST(xXIListPropertiesReq);
1099 REQUEST_SIZE_MATCH(xXIListPropertiesReq);
1100
1101 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixListPropAccess);
1102 if (rc != Success)
1103 return rc;
1104
1105 rc = list_atoms(dev, &natoms, &atoms);
1106 if (rc != Success)
1107 return rc;
1108
1109 rep = (xXIListPropertiesReply) {
1110 .repType = X_Reply,
1111 .RepType = X_XIListProperties,
1112 .sequenceNumber = client->sequence,
1113 .length = natoms,
1114 .num_properties = natoms
1115 };
1116
1117 WriteReplyToClient(client, sizeof(xXIListPropertiesReply), &rep);
1118 if (natoms) {
1119 client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
1120 WriteSwappedDataToClient(client, natoms * sizeof(Atom), atoms);
1121 free(atoms);
1122 }
1123 return rc;
1124 }
1125
1126 int
ProcXIChangeProperty(ClientPtr client)1127 ProcXIChangeProperty(ClientPtr client)
1128 {
1129 int rc;
1130 DeviceIntPtr dev;
1131 int totalSize;
1132 unsigned long len;
1133
1134 REQUEST(xXIChangePropertyReq);
1135 REQUEST_AT_LEAST_SIZE(xXIChangePropertyReq);
1136 UpdateCurrentTime();
1137
1138 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixSetPropAccess);
1139 if (rc != Success)
1140 return rc;
1141
1142 rc = check_change_property(client, stuff->property, stuff->type,
1143 stuff->format, stuff->mode, stuff->num_items);
1144 len = stuff->num_items;
1145 if (len > bytes_to_int32(0xffffffff - sizeof(xXIChangePropertyReq)))
1146 return BadLength;
1147
1148 totalSize = len * (stuff->format / 8);
1149 REQUEST_FIXED_SIZE(xXIChangePropertyReq, totalSize);
1150
1151 rc = change_property(client, dev, stuff->property, stuff->type,
1152 stuff->format, stuff->mode, len, (void *) &stuff[1]);
1153 return rc;
1154 }
1155
1156 int
ProcXIDeleteProperty(ClientPtr client)1157 ProcXIDeleteProperty(ClientPtr client)
1158 {
1159 DeviceIntPtr dev;
1160 int rc;
1161
1162 REQUEST(xXIDeletePropertyReq);
1163
1164 REQUEST_SIZE_MATCH(xXIDeletePropertyReq);
1165 UpdateCurrentTime();
1166 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixSetPropAccess);
1167 if (rc != Success)
1168 return rc;
1169
1170 if (!ValidAtom(stuff->property)) {
1171 client->errorValue = stuff->property;
1172 return BadAtom;
1173 }
1174
1175 rc = XIDeleteDeviceProperty(dev, stuff->property, TRUE);
1176 return rc;
1177 }
1178
1179 int
ProcXIGetProperty(ClientPtr client)1180 ProcXIGetProperty(ClientPtr client)
1181 {
1182 REQUEST(xXIGetPropertyReq);
1183 DeviceIntPtr dev;
1184 xXIGetPropertyReply reply;
1185 int length;
1186 int rc, format, nitems, bytes_after;
1187 char *data;
1188 Atom type;
1189
1190 REQUEST_SIZE_MATCH(xXIGetPropertyReq);
1191 if (stuff->delete)
1192 UpdateCurrentTime();
1193 rc = dixLookupDevice(&dev, stuff->deviceid, client,
1194 stuff->delete ? DixSetPropAccess : DixGetPropAccess);
1195 if (rc != Success)
1196 return rc;
1197
1198 rc = get_property(client, dev, stuff->property, stuff->type,
1199 stuff->delete, stuff->offset, stuff->len,
1200 &bytes_after, &type, &format, &nitems, &length, &data);
1201
1202 if (rc != Success)
1203 return rc;
1204
1205 reply = (xXIGetPropertyReply) {
1206 .repType = X_Reply,
1207 .RepType = X_XIGetProperty,
1208 .sequenceNumber = client->sequence,
1209 .length = bytes_to_int32(length),
1210 .type = type,
1211 .bytes_after = bytes_after,
1212 .num_items = nitems,
1213 .format = format
1214 };
1215
1216 if (length && stuff->delete && (reply.bytes_after == 0))
1217 send_property_event(dev, stuff->property, XIPropertyDeleted);
1218
1219 WriteReplyToClient(client, sizeof(xXIGetPropertyReply), &reply);
1220
1221 if (length) {
1222 switch (reply.format) {
1223 case 32:
1224 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write;
1225 break;
1226 case 16:
1227 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write;
1228 break;
1229 default:
1230 client->pSwapReplyFunc = (ReplySwapPtr) WriteToClient;
1231 break;
1232 }
1233 WriteSwappedDataToClient(client, length, data);
1234 }
1235
1236 /* delete the Property */
1237 if (stuff->delete && (reply.bytes_after == 0)) {
1238 XIPropertyPtr prop, *prev;
1239
1240 for (prev = &dev->properties.properties; (prop = *prev);
1241 prev = &prop->next) {
1242 if (prop->propertyName == stuff->property) {
1243 *prev = prop->next;
1244 XIDestroyDeviceProperty(prop);
1245 break;
1246 }
1247 }
1248 }
1249
1250 return Success;
1251 }
1252
1253 int _X_COLD
SProcXIListProperties(ClientPtr client)1254 SProcXIListProperties(ClientPtr client)
1255 {
1256 REQUEST(xXIListPropertiesReq);
1257 REQUEST_SIZE_MATCH(xXIListPropertiesReq);
1258
1259 swaps(&stuff->length);
1260 swaps(&stuff->deviceid);
1261 return (ProcXIListProperties(client));
1262 }
1263
1264 int _X_COLD
SProcXIChangeProperty(ClientPtr client)1265 SProcXIChangeProperty(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
1278 int _X_COLD
SProcXIDeleteProperty(ClientPtr client)1279 SProcXIDeleteProperty(ClientPtr client)
1280 {
1281 REQUEST(xXIDeletePropertyReq);
1282 REQUEST_SIZE_MATCH(xXIDeletePropertyReq);
1283
1284 swaps(&stuff->length);
1285 swaps(&stuff->deviceid);
1286 swapl(&stuff->property);
1287 return (ProcXIDeleteProperty(client));
1288 }
1289
1290 int _X_COLD
SProcXIGetProperty(ClientPtr client)1291 SProcXIGetProperty(ClientPtr client)
1292 {
1293 REQUEST(xXIGetPropertyReq);
1294 REQUEST_SIZE_MATCH(xXIGetPropertyReq);
1295
1296 swaps(&stuff->length);
1297 swaps(&stuff->deviceid);
1298 swapl(&stuff->property);
1299 swapl(&stuff->type);
1300 swapl(&stuff->offset);
1301 swapl(&stuff->len);
1302 return (ProcXIGetProperty(client));
1303 }
1304
1305 void _X_COLD
SRepXIListProperties(ClientPtr client,int size,xXIListPropertiesReply * rep)1306 SRepXIListProperties(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
1315 void _X_COLD
SRepXIGetProperty(ClientPtr client,int size,xXIGetPropertyReply * rep)1316 SRepXIGetProperty(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 }
1326