summaryrefslogtreecommitdiff
path: root/Xi
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2009-02-23 15:12:32 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2009-03-20 15:17:55 +1000
commitdfa2e8e966b699f9d292628119d5a9cbd2dbdf5a (patch)
treef5f5b1ad367a69f56545a0ec3c454fa47e291745 /Xi
parent560c58b53e4e60ebd26e0c66dd00399c438bd619 (diff)
Xi: add XIQueryDevice request handling.
Diffstat (limited to 'Xi')
-rw-r--r--Xi/Makefile.am2
-rw-r--r--Xi/extinit.c9
-rw-r--r--Xi/querydev.c443
-rw-r--r--Xi/querydev.h42
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 */