xiproperty.c revision 52397711
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 "exglobals.h"
38#include "exevents.h"
39#include "swaprep.h"
40
41#include "xiproperty.h"
42#include "xserver-properties.h"
43
44/**
45 * Properties used or alloced from inside the server.
46 */
47static struct dev_properties
48{
49    Atom type;
50    char *name;
51} dev_properties[] = {
52    {0, XI_PROP_ENABLED},
53    {0, XATOM_FLOAT}
54};
55
56static long XIPropHandlerID = 1;
57
58/**
59 * Return the type assigned to the specified atom or 0 if the atom isn't known
60 * to the DIX.
61 *
62 * If name is NULL, None is returned.
63 */
64_X_EXPORT Atom
65XIGetKnownProperty(char *name)
66{
67    int i;
68
69    if (!name)
70        return None;
71
72    for (i = 0; i < (sizeof(dev_properties)/sizeof(struct dev_properties)); i++)
73    {
74        if (strcmp(name, dev_properties[i].name) == 0)
75            return dev_properties[i].type;
76    }
77
78    return 0;
79}
80
81/**
82 * Convert the given property's value(s) into @nelem_return integer values and
83 * store them in @buf_return. If @nelem_return is larger than the number of
84 * values in the property, @nelem_return is set to the number of values in the
85 * property.
86 *
87 * If *@buf_return is NULL and @nelem_return is 0, memory is allocated
88 * automatically and must be freed by the caller.
89 *
90 * Possible return codes.
91 * Success ... No error.
92 * BadMatch ... Wrong atom type, atom is not XA_INTEGER
93 * BadAlloc ... NULL passed as buffer and allocation failed.
94 * BadLength ... @buff is NULL but @nelem_return is non-zero.
95 *
96 * @param val The property value
97 * @param nelem_return The maximum number of elements to return.
98 * @param buf_return Pointer to an array of at least @nelem_return values.
99 * @return Success or the error code if an error occured.
100 */
101_X_EXPORT int
102XIPropToInt(XIPropertyValuePtr val, int *nelem_return, int **buf_return)
103{
104    int i;
105    int *buf;
106
107    if (val->type != XA_INTEGER)
108        return BadMatch;
109    if (!*buf_return && *nelem_return)
110        return BadLength;
111
112    switch(val->format)
113    {
114        case 8:
115        case 16:
116        case 32:
117            break;
118        default:
119            return BadValue;
120    }
121
122    buf = *buf_return;
123
124    if (!buf && !(*nelem_return))
125    {
126        buf = xcalloc(val->size, sizeof(int));
127        if (!buf)
128            return BadAlloc;
129        *buf_return = buf;
130        *nelem_return = val->size;
131    } else if (val->size < *nelem_return)
132        *nelem_return = val->size;
133
134    for (i = 0; i < val->size && i < *nelem_return; i++)
135    {
136        switch(val->format)
137        {
138            case 8:  buf[i] = ((CARD8*)val->data)[i]; break;
139            case 16: buf[i] = ((CARD16*)val->data)[i]; break;
140            case 32: buf[i] = ((CARD32*)val->data)[i]; break;
141        }
142    }
143
144    return Success;
145}
146
147/**
148 * Convert the given property's value(s) into @nelem_return float values and
149 * store them in @buf_return. If @nelem_return is larger than the number of
150 * values in the property, @nelem_return is set to the number of values in the
151 * property.
152 *
153 * If *@buf_return is NULL and @nelem_return is 0, memory is allocated
154 * automatically and must be freed by the caller.
155 *
156 * Possible errors returned:
157 * Success
158 * BadMatch ... Wrong atom type, atom is not XA_FLOAT
159 * BadValue ... Wrong format, format is not 32
160 * BadAlloc ... NULL passed as buffer and allocation failed.
161 * BadLength ... @buff is NULL but @nelem_return is non-zero.
162 *
163 * @param val The property value
164 * @param nelem_return The maximum number of elements to return.
165 * @param buf_return Pointer to an array of at least @nelem_return values.
166 * @return Success or the error code if an error occured.
167 */
168_X_EXPORT int
169XIPropToFloat(XIPropertyValuePtr val, int *nelem_return, float **buf_return)
170{
171    int i;
172    float *buf;
173
174    if (!val->type || val->type != XIGetKnownProperty(XATOM_FLOAT))
175        return BadMatch;
176
177    if (val->format != 32)
178        return BadValue;
179    if (!*buf_return && *nelem_return)
180        return BadLength;
181
182    buf = *buf_return;
183
184    if (!buf && !(*nelem_return))
185    {
186        buf = xcalloc(val->size, sizeof(float));
187        if (!buf)
188            return BadAlloc;
189        *buf_return = buf;
190        *nelem_return = val->size;
191    } else if (val->size < *nelem_return)
192        *nelem_return = val->size;
193
194    for (i = 0; i < val->size && i < *nelem_return; i++)
195           buf[i] = ((float*)val->data)[i];
196
197    return Success;
198}
199
200/**
201 * Init those properties that are allocated by the server and most likely used
202 * by the DIX or the DDX.
203 */
204void
205XIInitKnownProperties(void)
206{
207    int i;
208    for (i = 0; i < (sizeof(dev_properties)/sizeof(struct dev_properties)); i++)
209    {
210        dev_properties[i].type =
211            MakeAtom(dev_properties[i].name,
212                     strlen(dev_properties[i].name),
213                     TRUE);
214    }
215}
216
217
218/* Registers a new property handler on the given device and returns a unique
219 * identifier for this handler. This identifier is required to unregister the
220 * property handler again.
221 * @return The handler's identifier or 0 if an error occured.
222 */
223long
224XIRegisterPropertyHandler(DeviceIntPtr         dev,
225                          int (*SetProperty) (DeviceIntPtr dev,
226                                              Atom property,
227                                              XIPropertyValuePtr prop,
228                                              BOOL checkonly),
229                          int (*GetProperty) (DeviceIntPtr dev,
230                                              Atom property),
231                          int (*DeleteProperty) (DeviceIntPtr dev,
232                                                 Atom property))
233{
234    XIPropertyHandlerPtr new_handler;
235
236    new_handler = xcalloc(1, sizeof(XIPropertyHandler));
237    if (!new_handler)
238        return 0;
239
240    new_handler->id = XIPropHandlerID++;
241    new_handler->SetProperty = SetProperty;
242    new_handler->GetProperty = GetProperty;
243    new_handler->DeleteProperty = DeleteProperty;
244    new_handler->next = dev->properties.handlers;
245    dev->properties.handlers = new_handler;
246
247    return new_handler->id;
248}
249
250void
251XIUnregisterPropertyHandler(DeviceIntPtr dev, long id)
252{
253    XIPropertyHandlerPtr curr, prev = NULL;
254
255    curr = dev->properties.handlers;
256    while(curr && curr->id != id)
257    {
258        prev = curr;
259        curr = curr->next;
260    }
261
262    if (!curr)
263        return;
264
265    if (!prev) /* first one */
266        dev->properties.handlers = curr->next;
267    else
268        prev->next = curr->next;
269
270    xfree(curr);
271}
272
273static XIPropertyPtr
274XICreateDeviceProperty (Atom property)
275{
276    XIPropertyPtr   prop;
277
278    prop = (XIPropertyPtr)xalloc(sizeof(XIPropertyRec));
279    if (!prop)
280        return NULL;
281
282    prop->next          = NULL;
283    prop->propertyName  = property;
284    prop->value.type   = None;
285    prop->value.format = 0;
286    prop->value.size   = 0;
287    prop->value.data   = NULL;
288    prop->deletable    = TRUE;
289
290    return prop;
291}
292
293static XIPropertyPtr
294XIFetchDeviceProperty(DeviceIntPtr dev, Atom property)
295{
296    XIPropertyPtr   prop;
297
298    for (prop = dev->properties.properties; prop; prop = prop->next)
299        if (prop->propertyName == property)
300            return prop;
301    return NULL;
302}
303
304static void
305XIDestroyDeviceProperty (XIPropertyPtr prop)
306{
307    if (prop->value.data)
308        xfree(prop->value.data);
309    xfree(prop);
310}
311
312/* This function destroys all of the device's property-related stuff,
313 * including removing all device handlers.
314 * DO NOT CALL FROM THE DRIVER.
315 */
316void
317XIDeleteAllDeviceProperties (DeviceIntPtr device)
318{
319    XIPropertyPtr               prop, next;
320    XIPropertyHandlerPtr        curr_handler, next_handler;
321    devicePropertyNotify        event;
322
323    for (prop = device->properties.properties; prop; prop = next)
324    {
325        next = prop->next;
326
327        event.type      = DevicePropertyNotify;
328        event.deviceid  = device->id;
329        event.state     = PropertyDelete;
330        event.atom      = prop->propertyName;
331        event.time      = currentTime.milliseconds;
332        SendEventToAllWindows(device, DevicePropertyNotifyMask,
333                (xEvent*)&event, 1);
334
335        XIDestroyDeviceProperty(prop);
336    }
337
338    /* Now free all handlers */
339    curr_handler = device->properties.handlers;
340    while(curr_handler)
341    {
342        next_handler = curr_handler->next;
343        xfree(curr_handler);
344        curr_handler = next_handler;
345    }
346}
347
348
349int
350XIDeleteDeviceProperty (DeviceIntPtr device, Atom property, Bool fromClient)
351{
352    XIPropertyPtr               prop, *prev;
353    devicePropertyNotify        event;
354    int                         rc = Success;
355
356    for (prev = &device->properties.properties; (prop = *prev); prev = &(prop->next))
357        if (prop->propertyName == property)
358            break;
359
360    if (fromClient && !prop->deletable)
361        return BadAccess;
362
363    /* Ask handlers if we may delete the property */
364    if (device->properties.handlers)
365    {
366        XIPropertyHandlerPtr handler = device->properties.handlers;
367        while(handler)
368        {
369            if (handler->DeleteProperty)
370                rc = handler->DeleteProperty(device, prop->propertyName);
371            if (rc != Success)
372                return (rc);
373            handler = handler->next;
374        }
375    }
376
377    if (prop)
378    {
379        *prev = prop->next;
380        event.type      = DevicePropertyNotify;
381        event.deviceid  = device->id;
382        event.state     = PropertyDelete;
383        event.atom      = prop->propertyName;
384        event.time      = currentTime.milliseconds;
385        SendEventToAllWindows(device, DevicePropertyNotifyMask,
386                              (xEvent*)&event, 1);
387        XIDestroyDeviceProperty (prop);
388    }
389
390    return Success;
391}
392
393int
394XIChangeDeviceProperty (DeviceIntPtr dev, Atom property, Atom type,
395                        int format, int mode, unsigned long len,
396                        pointer value, Bool sendevent)
397{
398    XIPropertyPtr               prop;
399    devicePropertyNotify        event;
400    int                         size_in_bytes;
401    int                         total_size;
402    unsigned long               total_len;
403    XIPropertyValuePtr          prop_value;
404    XIPropertyValueRec          new_value;
405    Bool                        add = FALSE;
406    int                         rc;
407
408    size_in_bytes = format >> 3;
409
410    /* first see if property already exists */
411    prop = XIFetchDeviceProperty (dev, property);
412    if (!prop)   /* just add to list */
413    {
414        prop = XICreateDeviceProperty (property);
415        if (!prop)
416            return(BadAlloc);
417        add = TRUE;
418        mode = PropModeReplace;
419    }
420    prop_value = &prop->value;
421
422    /* To append or prepend to a property the request format and type
423     must match those of the already defined property.  The
424     existing format and type are irrelevant when using the mode
425     "PropModeReplace" since they will be written over. */
426
427    if ((format != prop_value->format) && (mode != PropModeReplace))
428        return(BadMatch);
429    if ((prop_value->type != type) && (mode != PropModeReplace))
430        return(BadMatch);
431    new_value = *prop_value;
432    if (mode == PropModeReplace)
433        total_len = len;
434    else
435        total_len = prop_value->size + len;
436
437    if (mode == PropModeReplace || len > 0)
438    {
439        pointer            new_data = NULL, old_data = NULL;
440
441        total_size = total_len * size_in_bytes;
442        new_value.data = (pointer)xalloc (total_size);
443        if (!new_value.data && total_size)
444        {
445            if (add)
446                XIDestroyDeviceProperty (prop);
447            return BadAlloc;
448        }
449        new_value.size = len;
450        new_value.type = type;
451        new_value.format = format;
452
453        switch (mode) {
454        case PropModeReplace:
455            new_data = new_value.data;
456            old_data = NULL;
457            break;
458        case PropModeAppend:
459            new_data = (pointer) (((char *) new_value.data) +
460                                  (prop_value->size * size_in_bytes));
461            old_data = new_value.data;
462            break;
463        case PropModePrepend:
464            new_data = new_value.data;
465            old_data = (pointer) (((char *) new_value.data) +
466                                  (prop_value->size * size_in_bytes));
467            break;
468        }
469        if (new_data)
470            memcpy ((char *) new_data, (char *) value, len * size_in_bytes);
471        if (old_data)
472            memcpy ((char *) old_data, (char *) prop_value->data,
473                    prop_value->size * size_in_bytes);
474
475        if (dev->properties.handlers)
476        {
477            XIPropertyHandlerPtr handler;
478            BOOL checkonly = TRUE;
479            /* run through all handlers with checkonly TRUE, then again with
480             * checkonly FALSE. Handlers MUST return error codes on the
481             * checkonly run, errors on the second run are ignored */
482            do
483            {
484                handler = dev->properties.handlers;
485                while(handler)
486                {
487                    if (handler->SetProperty)
488                    {
489                        rc = handler->SetProperty(dev, prop->propertyName,
490                                &new_value, checkonly);
491                        if (checkonly && rc != Success)
492                        {
493                            if (new_value.data)
494                                xfree (new_value.data);
495                            return (rc);
496                        }
497                    }
498                    handler = handler->next;
499                }
500                checkonly = !checkonly;
501            } while (!checkonly);
502        }
503        if (prop_value->data)
504            xfree (prop_value->data);
505        *prop_value = new_value;
506    } else if (len == 0)
507    {
508        /* do nothing */
509    }
510
511    if (add)
512    {
513        prop->next = dev->properties.properties;
514        dev->properties.properties = prop;
515    }
516
517    if (sendevent)
518    {
519        event.type      = DevicePropertyNotify;
520        event.deviceid  = dev->id;
521        event.state     = PropertyNewValue;
522        event.atom      = prop->propertyName;
523        event.time      = currentTime.milliseconds;
524        SendEventToAllWindows(dev, DevicePropertyNotifyMask,
525                              (xEvent*)&event, 1);
526    }
527    return(Success);
528}
529
530int
531XIGetDeviceProperty (DeviceIntPtr dev, Atom property, XIPropertyValuePtr *value)
532{
533    XIPropertyPtr   prop = XIFetchDeviceProperty (dev, property);
534    int rc;
535
536    if (!prop)
537    {
538        *value = NULL;
539        return BadAtom;
540    }
541
542    /* If we can, try to update the property value first */
543    if (dev->properties.handlers)
544    {
545        XIPropertyHandlerPtr handler = dev->properties.handlers;
546        while(handler)
547        {
548            if (handler->GetProperty)
549            {
550                rc = handler->GetProperty(dev, prop->propertyName);
551                if (rc != Success)
552                {
553                    *value = NULL;
554                    return rc;
555                }
556            }
557            handler = handler->next;
558        }
559    }
560
561    *value = &prop->value;
562    return Success;
563}
564
565int
566XISetDevicePropertyDeletable(DeviceIntPtr dev, Atom property, Bool deletable)
567{
568    XIPropertyPtr prop = XIFetchDeviceProperty(dev, property);
569
570    if (!prop)
571        return BadAtom;
572
573    prop->deletable = deletable;
574    return Success;
575}
576
577int
578ProcXListDeviceProperties (ClientPtr client)
579{
580    Atom                        *pAtoms = NULL, *temppAtoms;
581    xListDevicePropertiesReply  rep;
582    int                         numProps = 0;
583    DeviceIntPtr                dev;
584    XIPropertyPtr               prop;
585    int                         rc = Success;
586
587    REQUEST(xListDevicePropertiesReq);
588    REQUEST_SIZE_MATCH(xListDevicePropertiesReq);
589
590    rc = dixLookupDevice (&dev, stuff->deviceid, client, DixReadAccess);
591    if (rc != Success)
592        return rc;
593
594    for (prop = dev->properties.properties; prop; prop = prop->next)
595        numProps++;
596    if (numProps)
597        if(!(pAtoms = (Atom *)xalloc(numProps * sizeof(Atom))))
598            return(BadAlloc);
599
600    rep.repType = X_Reply;
601    rep.RepType = X_ListDeviceProperties;
602    rep.length = (numProps * sizeof(Atom)) >> 2;
603    rep.sequenceNumber = client->sequence;
604    rep.nAtoms = numProps;
605    temppAtoms = pAtoms;
606    for (prop = dev->properties.properties; prop; prop = prop->next)
607        *temppAtoms++ = prop->propertyName;
608
609    WriteReplyToClient(client, sizeof(xListDevicePropertiesReply), &rep);
610    if (numProps)
611    {
612        client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write;
613        WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms);
614        xfree(pAtoms);
615    }
616    return rc;
617}
618
619int
620ProcXChangeDeviceProperty (ClientPtr client)
621{
622    REQUEST(xChangeDevicePropertyReq);
623    DeviceIntPtr        dev;
624    char                format, mode;
625    unsigned long       len;
626    int                 sizeInBytes;
627    int                 totalSize;
628    int                 rc;
629
630    REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq);
631    UpdateCurrentTime();
632    format = stuff->format;
633    mode = stuff->mode;
634    if ((mode != PropModeReplace) && (mode != PropModeAppend) &&
635        (mode != PropModePrepend))
636    {
637        client->errorValue = mode;
638        return BadValue;
639    }
640    if ((format != 8) && (format != 16) && (format != 32))
641    {
642        client->errorValue = format;
643        return BadValue;
644    }
645    len = stuff->nUnits;
646    if (len > ((0xffffffff - sizeof(xChangeDevicePropertyReq)) >> 2))
647        return BadLength;
648    sizeInBytes = format>>3;
649    totalSize = len * sizeInBytes;
650    REQUEST_FIXED_SIZE(xChangeDevicePropertyReq, totalSize);
651
652    rc = dixLookupDevice (&dev, stuff->deviceid, client, DixWriteAccess);
653    if (rc != Success)
654        return rc;
655
656    if (!ValidAtom(stuff->property))
657    {
658        client->errorValue = stuff->property;
659        return(BadAtom);
660    }
661    if (!ValidAtom(stuff->type))
662    {
663        client->errorValue = stuff->type;
664        return(BadAtom);
665    }
666
667    rc = XIChangeDeviceProperty(dev, stuff->property,
668                                 stuff->type, (int)format,
669                                 (int)mode, len, (pointer)&stuff[1], TRUE);
670
671    if (rc != Success)
672        client->errorValue = stuff->property;
673    return rc;
674}
675
676int
677ProcXDeleteDeviceProperty (ClientPtr client)
678{
679    REQUEST(xDeleteDevicePropertyReq);
680    DeviceIntPtr        dev;
681    int                 rc;
682
683    REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq);
684    UpdateCurrentTime();
685    rc =  dixLookupDevice (&dev, stuff->deviceid, client, DixWriteAccess);
686    if (rc != Success)
687        return rc;
688
689    if (!ValidAtom(stuff->property))
690    {
691        client->errorValue = stuff->property;
692        return (BadAtom);
693    }
694
695    rc = XIDeleteDeviceProperty(dev, stuff->property, TRUE);
696    return rc;
697}
698
699int
700ProcXGetDeviceProperty (ClientPtr client)
701{
702    REQUEST(xGetDevicePropertyReq);
703    XIPropertyPtr               prop, *prev;
704    XIPropertyValuePtr          prop_value;
705    unsigned long               n, len, ind;
706    DeviceIntPtr                dev;
707    xGetDevicePropertyReply     reply;
708    int                         rc;
709
710    REQUEST_SIZE_MATCH(xGetDevicePropertyReq);
711    if (stuff->delete)
712        UpdateCurrentTime();
713    rc = dixLookupDevice (&dev, stuff->deviceid, client,
714                           stuff->delete ? DixWriteAccess :
715                           DixReadAccess);
716    if (rc != Success)
717        return rc;
718
719    if (!ValidAtom(stuff->property))
720    {
721        client->errorValue = stuff->property;
722        return(BadAtom);
723    }
724    if ((stuff->delete != xTrue) && (stuff->delete != xFalse))
725    {
726        client->errorValue = stuff->delete;
727        return(BadValue);
728    }
729    if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type))
730    {
731        client->errorValue = stuff->type;
732        return(BadAtom);
733    }
734
735    for (prev = &dev->properties.properties; (prop = *prev); prev = &prop->next)
736        if (prop->propertyName == stuff->property)
737            break;
738
739    reply.repType = X_Reply;
740    reply.RepType = X_GetDeviceProperty;
741    reply.sequenceNumber = client->sequence;
742    reply.deviceid = dev->id;
743    if (!prop)
744    {
745        reply.nItems = 0;
746        reply.length = 0;
747        reply.bytesAfter = 0;
748        reply.propertyType = None;
749        reply.format = 0;
750        WriteReplyToClient(client, sizeof(xGetDevicePropertyReply), &reply);
751        return(client->noClientException);
752    }
753
754    rc = XIGetDeviceProperty(dev, stuff->property, &prop_value);
755    if (rc != Success)
756    {
757        client->errorValue = stuff->property;
758        return rc;
759    }
760
761    /* If the request type and actual type don't match. Return the
762    property information, but not the data. */
763
764    if (((stuff->type != prop_value->type) &&
765         (stuff->type != AnyPropertyType))
766       )
767    {
768        reply.bytesAfter = prop_value->size;
769        reply.format = prop_value->format;
770        reply.length = 0;
771        reply.nItems = 0;
772        reply.propertyType = prop_value->type;
773        WriteReplyToClient(client, sizeof(xGetDevicePropertyReply), &reply);
774        return(client->noClientException);
775    }
776
777/*
778 *  Return type, format, value to client
779 */
780    n = (prop_value->format/8) * prop_value->size; /* size (bytes) of prop */
781    ind = stuff->longOffset << 2;
782
783   /* If longOffset is invalid such that it causes "len" to
784            be negative, it's a value error. */
785
786    if (n < ind)
787    {
788        client->errorValue = stuff->longOffset;
789        return BadValue;
790    }
791
792    len = min(n - ind, 4 * stuff->longLength);
793
794    reply.bytesAfter = n - (ind + len);
795    reply.format = prop_value->format;
796    reply.length = (len + 3) >> 2;
797    if (prop_value->format)
798        reply.nItems = len / (prop_value->format / 8);
799    else
800        reply.nItems = 0;
801    reply.propertyType = prop_value->type;
802
803    if (stuff->delete && (reply.bytesAfter == 0))
804    {
805        devicePropertyNotify    event;
806
807        event.type      = DevicePropertyNotify;
808        event.deviceid  = dev->id;
809        event.state     = PropertyDelete;
810        event.atom      = prop->propertyName;
811        event.time      = currentTime.milliseconds;
812        SendEventToAllWindows(dev, DevicePropertyNotifyMask,
813                              (xEvent*)&event, 1);
814    }
815
816    WriteReplyToClient(client, sizeof(xGenericReply), &reply);
817    if (len)
818    {
819        switch (reply.format) {
820        case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break;
821        case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break;
822        default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break;
823        }
824        WriteSwappedDataToClient(client, len,
825                                 (char *)prop_value->data + ind);
826    }
827
828    if (stuff->delete && (reply.bytesAfter == 0))
829    { /* delete the Property */
830        *prev = prop->next;
831        XIDestroyDeviceProperty (prop);
832    }
833    return(client->noClientException);
834}
835
836
837int
838SProcXListDeviceProperties (ClientPtr client)
839{
840    char n;
841    REQUEST(xListDevicePropertiesReq);
842
843    swaps(&stuff->length, n);
844
845    REQUEST_SIZE_MATCH(xListDevicePropertiesReq);
846    return (ProcXListDeviceProperties(client));
847}
848
849int
850SProcXChangeDeviceProperty (ClientPtr client)
851{
852    char n;
853    REQUEST(xChangeDevicePropertyReq);
854
855    swaps(&stuff->length, n);
856    swapl(&stuff->property, n);
857    swapl(&stuff->type, n);
858    swapl(&stuff->nUnits, n);
859    REQUEST_SIZE_MATCH(xChangeDevicePropertyReq);
860    return (ProcXChangeDeviceProperty(client));
861}
862
863int
864SProcXDeleteDeviceProperty (ClientPtr client)
865{
866    char n;
867    REQUEST(xDeleteDevicePropertyReq);
868
869    swaps(&stuff->length, n);
870    swapl(&stuff->property, n);
871    REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq);
872    return (ProcXDeleteDeviceProperty(client));
873}
874
875int
876SProcXGetDeviceProperty (ClientPtr client)
877{
878    char n;
879    REQUEST(xGetDevicePropertyReq);
880
881    swaps(&stuff->length, n);
882    swapl(&stuff->property, n);
883    swapl(&stuff->type, n);
884    swapl(&stuff->longOffset, n);
885    swapl(&stuff->longLength, n);
886    REQUEST_SIZE_MATCH(xGetDevicePropertyReq);
887    return (ProcXGetDeviceProperty(client));
888}
889
890
891/* Reply swapping */
892
893void
894SRepXListDeviceProperties(ClientPtr client, int size,
895                          xListDevicePropertiesReply *rep)
896{
897    char n;
898    swaps(&rep->sequenceNumber, n);
899    swapl(&rep->length, n);
900    swaps(&rep->nAtoms, n);
901    /* properties will be swapped later, see ProcXListDeviceProperties */
902    WriteToClient(client, size, (char*)rep);
903}
904
905void
906SRepXGetDeviceProperty(ClientPtr client, int size,
907                       xGetDevicePropertyReply *rep)
908{
909    char n;
910
911    swaps(&rep->sequenceNumber, n);
912    swapl(&rep->length, n);
913    swapl(&rep->propertyType, n);
914    swapl(&rep->bytesAfter, n);
915    swapl(&rep->nItems, n);
916    /* data will be swapped, see ProcXGetDeviceProperty */
917    WriteToClient(client, size, (char*)rep);
918}
919