xref: /OK3568_Linux_fs/external/xserver/Xi/xiproperty.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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