diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2009-02-23 15:12:32 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2009-03-20 15:17:55 +1000 |
commit | dfa2e8e966b699f9d292628119d5a9cbd2dbdf5a (patch) | |
tree | f5f5b1ad367a69f56545a0ec3c454fa47e291745 /Xi | |
parent | 560c58b53e4e60ebd26e0c66dd00399c438bd619 (diff) |
Xi: add XIQueryDevice request handling.
Diffstat (limited to 'Xi')
-rw-r--r-- | Xi/Makefile.am | 2 | ||||
-rw-r--r-- | Xi/extinit.c | 9 | ||||
-rw-r--r-- | Xi/querydev.c | 443 | ||||
-rw-r--r-- | Xi/querydev.h | 42 |
4 files changed, 494 insertions, 2 deletions
diff --git a/Xi/Makefile.am b/Xi/Makefile.am index 316fd2925..10521fd7a 100644 --- a/Xi/Makefile.am +++ b/Xi/Makefile.am @@ -60,6 +60,8 @@ libXi_la_SOURCES = \ listdev.h \ opendev.c \ opendev.h \ + querydev.c \ + querydev.h \ queryversion.h \ queryversion.c \ querydp.c \ diff --git a/Xi/extinit.c b/Xi/extinit.c index 988ed0b9b..9acbdfe45 100644 --- a/Xi/extinit.c +++ b/Xi/extinit.c @@ -104,6 +104,7 @@ SOFTWARE. #include "opendev.h" #include "querydp.h" #include "queryst.h" +#include "querydev.h" #include "queryversion.h" #include "selectev.h" #include "sendexev.h" @@ -237,7 +238,8 @@ static int (*ProcIVector[])(ClientPtr) = { ProcXISetClientPointer, /* 44 */ ProcXIGetClientPointer, /* 45 */ ProcXiSelectEvent, /* 46 */ - ProcXIQueryVersion /* 47 */ + ProcXIQueryVersion, /* 47 */ + ProcXIQueryDevice /* 48 */ }; /* For swapped clients */ @@ -289,7 +291,8 @@ static int (*SProcIVector[])(ClientPtr) = { SProcXISetClientPointer, /* 44 */ SProcXIGetClientPointer, /* 45 */ SProcXiSelectEvent, /* 46 */ - SProcXIQueryVersion /* 47 */ + SProcXIQueryVersion, /* 47 */ + SProcXIQueryDevice /* 48 */ }; /***************************************************************** @@ -480,6 +483,8 @@ SReplyIDispatch(ClientPtr client, int len, xGrabDeviceReply * rep) (xXIQueryDevicePointerReply *) rep); else if (rep->RepType == X_XIGetClientPointer) SRepXIGetClientPointer(client, len, (xXIGetClientPointerReply*) rep); + else if (rep->RepType == X_XIQueryDevice) + SRepXIQueryDevice(client, len, (xXIQueryDeviceReply*)rep); else { FatalError("XINPUT confused sending swapped reply"); } diff --git a/Xi/querydev.c b/Xi/querydev.c new file mode 100644 index 000000000..0d90fa926 --- /dev/null +++ b/Xi/querydev.c @@ -0,0 +1,443 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Peter Hutterer + * + */ + +/** + * @file Protocol handling for the XIQueryDevice request/reply. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "inputstr.h" +#include <X11/X.h> +#include <X11/extensions/XI2proto.h> +#include "xkbstr.h" +#include "xkbsrv.h" +#include "xserver-properties.h" +#include "exevents.h" + +#include "querydev.h" + +static int ListDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info); +static int SizeDeviceInfo(DeviceIntPtr dev); +static void SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info); +int +SProcXIQueryDevice(ClientPtr client) +{ + char n; + + REQUEST(xXIQueryDeviceReq); + + swaps(&stuff->length, n); + swaps(&stuff->deviceid, n); + + return ProcXIQueryDevice(client); +} + +int +ProcXIQueryDevice(ClientPtr client) +{ + xXIQueryDeviceReply rep; + DeviceIntPtr dev = NULL; + int rc = Success; + int len = 0; + char *info, *ptr; + + REQUEST(xXIQueryDeviceReq); + REQUEST_SIZE_MATCH(xXIQueryDeviceReq); + + if (stuff->deviceid != AllDevices && stuff->deviceid != AllMasterDevices) + { + rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess); + if (rc != Success) + { + client->errorValue = stuff->deviceid; + return rc; + } + } + + if (dev) + len += SizeDeviceInfo(dev); + else + { + len = 0; + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (stuff->deviceid == AllDevices || + (stuff->deviceid == AllMasterDevices && dev->isMaster)) + len += SizeDeviceInfo(dev); + } + + for (dev = inputInfo.off_devices; dev; dev = dev->next) + { + if (stuff->deviceid == AllDevices || + (stuff->deviceid == AllMasterDevices && dev->isMaster)) + len += SizeDeviceInfo(dev); + } + + dev = NULL; + } + + info = xcalloc(1, len); + if (!info) + return BadAlloc; + + memset(&rep, 0, sizeof(xXIQueryDeviceReply)); + rep.repType = X_Reply; + rep.RepType = X_XIQueryDevice; + rep.sequenceNumber = client->sequence; + rep.length = len/4; + rep.num_devices = 0; + + ptr = info; + if (dev) + { + len = ListDeviceInfo(dev, (xXIDeviceInfo*)info); + if (client->swapped) + SwapDeviceInfo(dev, (xXIDeviceInfo*)info); + info += len; + rep.num_devices = 1; + } else + { + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (stuff->deviceid == AllDevices || + (stuff->deviceid == AllMasterDevices && dev->isMaster)) + { + len = ListDeviceInfo(dev, (xXIDeviceInfo*)info); + if (client->swapped) + SwapDeviceInfo(dev, (xXIDeviceInfo*)info); + info += len; + rep.num_devices++; + } + } + + for (dev = inputInfo.off_devices; dev; dev = dev->next) + { + if (stuff->deviceid == AllDevices || + (stuff->deviceid == AllMasterDevices && dev->isMaster)) + { + len = ListDeviceInfo(dev, (xXIDeviceInfo*)info); + if (client->swapped) + SwapDeviceInfo(dev, (xXIDeviceInfo*)info); + info += len; + rep.num_devices++; + } + } + } + + WriteReplyToClient(client, sizeof(xXIQueryDeviceReply), &rep); + WriteToClient(client, rep.length * 4, ptr); + return rc; +} + +void +SRepXIQueryDevice(ClientPtr client, int size, xXIQueryDeviceReply *rep) +{ + char n; + + swaps(&rep->sequenceNumber, n); + swapl(&rep->length, n); + swaps(&rep->num_devices, n); + + /* Device info is already swapped, see ProcXIQueryDevice */ + + WriteToClient(client, size, (char *)rep); +} + + + +/** + * @return The number of bytes needed to store this device's xXIDeviceInfo + * (and its classes). + */ +static int +SizeDeviceInfo(DeviceIntPtr dev) +{ + int len = sizeof(xXIDeviceInfo); + + /* 4-padded name */ + len += (((strlen(dev->name) + 3)/4)*4); + + return len + SizeDeviceClasses(dev); + +} + +/* + * @return The number of bytes needed to store this device's classes. + */ +int +SizeDeviceClasses(DeviceIntPtr dev) +{ + int len = 0; + + if (dev->button) + { + len += sizeof(xXIButtonInfo); + len += dev->button->numButtons * sizeof(Atom); + } + + if (dev->key) + { + XkbDescPtr xkb = dev->key->xkbInfo->desc; + len += sizeof(xXIKeyInfo); + len += (xkb->max_key_code - xkb->min_key_code + 1) * sizeof(uint32_t); + } + + if (dev->valuator) + len += sizeof(xXIValuatorInfo) * dev->valuator->numAxes; + + return len; +} + + +/** + * Write button information into info. + * @return Number of bytes written into info. + */ +static int +ListButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info) +{ + info->type = ButtonClass; + info->num_buttons = dev->button->numButtons; + info->length = 2 + info->num_buttons; + + /** XXX: button labels */ + + return info->length * 4; +} + +static void +SwapButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info) +{ + char n; + Atom *btn; + int i; + swaps(&info->type, n); + swaps(&info->length, n); + + for (i = 0, btn = (Atom*)&info[1]; i < info->num_buttons; i++, btn++) + swaps(btn, n); + + swaps(&info->num_buttons, n); +} + +/** + * Write key information into info. + * @return Number of bytes written into info. + */ +static int +ListKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info) +{ + int i; + XkbDescPtr xkb = dev->key->xkbInfo->desc; + uint32_t *kc; + + info->type = KeyClass; + info->num_keycodes = xkb->max_key_code - xkb->min_key_code + 1; + info->length = 2 + info->num_keycodes; + + kc = (uint32_t*)&info[1]; + for (i = xkb->min_key_code; i <= xkb->max_key_code; i++, kc++) + *kc = i; + + return info->length * 4; +} + +static void +SwapKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info) +{ + char n; + uint32_t *key; + int i; + swaps(&info->type, n); + swaps(&info->length, n); + + for (i = 0, key = (uint32_t*)&info[1]; i < info->num_keycodes; i++, key++) + swaps(key, n); + + swaps(&info->num_keycodes, n); +} + +/** + * List axis information for the given axis. + * + * @return The number of bytes written into info. + */ +static int +ListValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info, int axisnumber) +{ + ValuatorClassPtr v = dev->valuator; + + info->type = ValuatorClass; + info->length = sizeof(xXIValuatorInfo)/4; + info->name = XIGetKnownProperty(AXIS_LABEL_PROP_REL_MISC); /* XXX */ + info->min.integral = v->axes[axisnumber].min_value; + info->min.frac = 0; + info->max.integral = v->axes[axisnumber].max_value; + info->max.frac = 0; + info->resolution = v->axes[axisnumber].resolution; + info->number = axisnumber; + info->mode = v->mode; /* Server doesn't have per-axis mode yet */ + + return info->length * 4; +} + +static void +SwapValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info) +{ + char n; + swaps(&info->type, n); + swaps(&info->length, n); + swapl(&info->name, n); + swapl(&info->min.integral, n); + swapl(&info->min.frac, n); + swapl(&info->max.integral, n); + swapl(&info->max.frac, n); + swaps(&info->number, n); +} + +int GetDeviceUse(DeviceIntPtr dev, uint16_t *attachment) +{ + DeviceIntPtr master = dev->u.master; + int use; + + if (dev->isMaster) + { + DeviceIntPtr paired = GetPairedDevice(dev); + use = IsPointerDevice(dev) ? MasterPointer : MasterKeyboard; + *attachment = (paired ? paired->id : 0); + } else if (master) + { + use = IsPointerDevice(master) ? SlavePointer : SlaveKeyboard; + *attachment = master->id; + } else + use = FloatingSlave; + + return use; +} + +/** + * Write the info for device dev into the buffer pointed to by info. + * + * @return The number of bytes used. + */ +static int +ListDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info) +{ + char *any = (char*)&info[1]; + int len = 0, total_len = 0; + + info->deviceid = dev->id; + info->use = GetDeviceUse(dev, &info->attachment); + info->num_classes = 0; + info->name_len = strlen(dev->name); + info->enabled = dev->enabled; + total_len = sizeof(xXIDeviceInfo); + + strncpy(any, dev->name, info->name_len); + len = ((info->name_len + 3)/4) * 4; + any += len; + total_len += len; + + return total_len + ListDeviceClasses(dev, any, &info->num_classes); +} + +/** + * Write the class info of the device into the memory pointed to by any, set + * nclasses to the number of classes in total and return the number of bytes + * written. + */ +int +ListDeviceClasses(DeviceIntPtr dev, char *any, uint16_t *nclasses) +{ + int total_len = 0; + int len; + int i; + + if (dev->button) + { + (*nclasses)++; + len = ListButtonInfo(dev, (xXIButtonInfo*)any); + any += len; + total_len += len; + } + + if (dev->key) + { + (*nclasses)++; + len = ListKeyInfo(dev, (xXIKeyInfo*)any); + any += len; + total_len += len; + } + + for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++) + { + (*nclasses)++; + len = ListValuatorInfo(dev, (xXIValuatorInfo*)any, i); + any += len; + total_len += len; + } + + return total_len; +} + +static void +SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info) +{ + char n; + char *any = (char*)&info[1]; + int i; + + /* Skip over name */ + any += (((info->name_len + 3)/4) * 4); + + for (i = 0; i < info->num_classes; i++) + { + switch(((xXIAnyInfo*)any)->type) + { + case ButtonClass: + SwapButtonInfo(dev, (xXIButtonInfo*)any); + break; + case KeyClass: + SwapKeyInfo(dev, (xXIKeyInfo*)any); + break; + case ValuatorClass: + SwapValuatorInfo(dev, (xXIValuatorInfo*)any); + break; + } + + any += (((xXIAnyInfo*)any)->length * 4); + } + + swaps(&info->deviceid, n); + swaps(&info->use, n); + swaps(&info->attachment, n); + swaps(&info->num_classes, n); + swaps(&info->name_len, n); + +} diff --git a/Xi/querydev.h b/Xi/querydev.h new file mode 100644 index 000000000..92ab2bd77 --- /dev/null +++ b/Xi/querydev.h @@ -0,0 +1,42 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Peter Hutterer + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifndef QUERYDEV_H +#define QUERYDEV_H 1 + +#include <X11/extensions/XI2proto.h> + +int SProcXIQueryDevice(ClientPtr client); +int ProcXIQueryDevice(ClientPtr client); +void SRepXIQueryDevice(ClientPtr client, int size, xXIQueryDeviceReply *rep); +int SizeDeviceClasses(DeviceIntPtr dev); +int ListDeviceClasses(DeviceIntPtr dev, char* any, uint16_t* nclasses); +int GetDeviceUse(DeviceIntPtr dev, uint16_t *attachment); +#endif /* QUERYDEV_H */ |