aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/dix
diff options
context:
space:
mode:
authormarha <marha@users.sourceforge.net>2011-03-15 21:35:41 +0000
committermarha <marha@users.sourceforge.net>2011-03-15 21:35:41 +0000
commit5e633abcca598289d0423d89bb400b41e6417259 (patch)
tree74258f0d1f9f5f2b171d16fd9654a13803216c6f /xorg-server/dix
parentb5d1fd89898edb34f73679b542c754d837d44cf8 (diff)
downloadvcxsrv-5e633abcca598289d0423d89bb400b41e6417259.tar.gz
vcxsrv-5e633abcca598289d0423d89bb400b41e6417259.tar.bz2
vcxsrv-5e633abcca598289d0423d89bb400b41e6417259.zip
xserver libX11 libxcb mesa git update 15 Mar 2011
Diffstat (limited to 'xorg-server/dix')
-rw-r--r--xorg-server/dix/devices.c5258
-rw-r--r--xorg-server/dix/eventconvert.c1537
-rw-r--r--xorg-server/dix/getevents.c2638
-rw-r--r--xorg-server/dix/ptrveloc.c2413
4 files changed, 5930 insertions, 5916 deletions
diff --git a/xorg-server/dix/devices.c b/xorg-server/dix/devices.c
index e57c27b00..7f500d63d 100644
--- a/xorg-server/dix/devices.c
+++ b/xorg-server/dix/devices.c
@@ -1,2628 +1,2630 @@
-/************************************************************
-
-Copyright 1987, 1998 The Open Group
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that
-the above copyright notice appear in all copies and that both that
-copyright notice and this permission notice appear in supporting
-documentation.
-
-The above copyright notice and this permission notice 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
-OPEN GROUP 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.
-
-Except as contained in this notice, the name of The Open Group shall not be
-used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization from The Open Group.
-
-
-Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
-
- All Rights Reserved
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted,
-provided that the above copyright notice appear in all copies and that
-both that copyright notice and this permission notice appear in
-supporting documentation, and that the name of Digital not be
-used in advertising or publicity pertaining to distribution of the
-software without specific, written prior permission.
-
-DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
-ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
-DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
-ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
-ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
-SOFTWARE.
-
-********************************************************/
-
-
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <X11/X.h>
-#include "misc.h"
-#include "resource.h"
-#include <X11/Xproto.h>
-#include <X11/Xatom.h>
-#include "windowstr.h"
-#include "inputstr.h"
-#include "scrnintstr.h"
-#include "cursorstr.h"
-#include "dixstruct.h"
-#include "ptrveloc.h"
-#include "site.h"
-#include "xkbsrv.h"
-#include "privates.h"
-#include "xace.h"
-#include "mi.h"
-
-#include "dispatch.h"
-#include "swaprep.h"
-#include "dixevents.h"
-#include "mipointer.h"
-#include "eventstr.h"
-
-#include <X11/extensions/XI.h>
-#include <X11/extensions/XI2.h>
-#include <X11/extensions/XIproto.h>
-#include <math.h>
-#include <pixman.h>
-#include "exglobals.h"
-#include "exevents.h"
-#include "xiquerydevice.h" /* for SizeDeviceClasses */
-#include "xiproperty.h"
-#include "enterleave.h" /* for EnterWindow() */
-#include "xserver-properties.h"
-#include "xichangehierarchy.h" /* For XISendDeviceHierarchyEvent */
-
-/** @file
- * This file handles input device-related stuff.
- */
-
-static void RecalculateMasterButtons(DeviceIntPtr slave);
-
-static void
-DeviceSetTransform(DeviceIntPtr dev, float *transform)
-{
- struct pixman_f_transform scale;
- double sx, sy;
- int x, y;
-
- /**
- * calculate combined transformation matrix:
- *
- * M = InvScale * Transform * Scale
- *
- * So we can later transform points using M * p
- *
- * Where:
- * Scale scales coordinates into 0..1 range
- * Transform is the user supplied (affine) transform
- * InvScale scales coordinates back up into their native range
- */
- sx = dev->valuator->axes[0].max_value - dev->valuator->axes[0].min_value;
- sy = dev->valuator->axes[1].max_value - dev->valuator->axes[1].min_value;
-
- /* invscale */
- pixman_f_transform_init_scale(&scale, sx, sy);
- scale.m[0][2] = dev->valuator->axes[0].min_value;
- scale.m[1][2] = dev->valuator->axes[1].min_value;
-
- /* transform */
- for (y=0; y<3; y++)
- for (x=0; x<3; x++)
- dev->transform.m[y][x] = *transform++;
-
- pixman_f_transform_multiply(&dev->transform, &scale, &dev->transform);
-
- /* scale */
- pixman_f_transform_init_scale(&scale, 1.0 / sx, 1.0 / sy);
- scale.m[0][2] = -dev->valuator->axes[0].min_value / sx;
- scale.m[1][2] = -dev->valuator->axes[1].min_value / sy;
-
- pixman_f_transform_multiply(&dev->transform, &dev->transform, &scale);
-}
-
-/**
- * DIX property handler.
- */
-static int
-DeviceSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
- BOOL checkonly)
-{
- if (property == XIGetKnownProperty(XI_PROP_ENABLED))
- {
- if (prop->format != 8 || prop->type != XA_INTEGER || prop->size != 1)
- return BadValue;
-
- /* Don't allow disabling of VCP/VCK */
- if ((dev == inputInfo.pointer || dev == inputInfo.keyboard) &&
- !(*(CARD8*)prop->data))
- return BadAccess;
-
- if (!checkonly)
- {
- if ((*((CARD8*)prop->data)) && !dev->enabled)
- EnableDevice(dev, TRUE);
- else if (!(*((CARD8*)prop->data)) && dev->enabled)
- DisableDevice(dev, TRUE);
- }
- } else if (property == XIGetKnownProperty(XI_PROP_TRANSFORM))
- {
- float *f = (float*)prop->data;
- int i;
-
- if (prop->format != 32 || prop->size != 9 ||
- prop->type != XIGetKnownProperty(XATOM_FLOAT))
- return BadValue;
-
- for (i=0; i<9; i++)
- if (!isfinite(f[i]))
- return BadValue;
-
- if (!checkonly)
- DeviceSetTransform(dev, f);
- }
-
- return Success;
-}
-
-/* Pair the keyboard to the pointer device. Keyboard events will follow the
- * pointer sprite. Only applicable for master devices.
- * If the client is set, the request to pair comes from some client. In this
- * case, we need to check for access. If the client is NULL, it's from an
- * internal automatic pairing, we must always permit this.
- */
-static int
-PairDevices(ClientPtr client, DeviceIntPtr ptr, DeviceIntPtr kbd)
-{
- if (!ptr)
- return BadDevice;
-
- /* Don't allow pairing for slave devices */
- if (!IsMaster(ptr) || !IsMaster(kbd))
- return BadDevice;
-
- if (ptr->spriteInfo->paired)
- return BadDevice;
-
- if (kbd->spriteInfo->spriteOwner)
- {
- free(kbd->spriteInfo->sprite);
- kbd->spriteInfo->sprite = NULL;
- kbd->spriteInfo->spriteOwner = FALSE;
- }
-
- kbd->spriteInfo->sprite = ptr->spriteInfo->sprite;
- kbd->spriteInfo->paired = ptr;
- ptr->spriteInfo->paired = kbd;
- return Success;
-}
-
-
-/**
- * Find and return the next unpaired MD pointer device.
- */
-static DeviceIntPtr
-NextFreePointerDevice(void)
-{
- DeviceIntPtr dev;
- for (dev = inputInfo.devices; dev; dev = dev->next)
- if (IsMaster(dev) &&
- dev->spriteInfo->spriteOwner &&
- !dev->spriteInfo->paired)
- return dev;
- return NULL;
-}
-
-/**
- * Create a new input device and init it to sane values. The device is added
- * to the server's off_devices list.
- *
- * @param deviceProc Callback for device control function (switch dev on/off).
- * @return The newly created device.
- */
-DeviceIntPtr
-AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart)
-{
- DeviceIntPtr dev, *prev; /* not a typo */
- DeviceIntPtr devtmp;
- int devid;
- char devind[MAXDEVICES];
- BOOL enabled;
- float transform[9];
-
- /* Find next available id, 0 and 1 are reserved */
- memset(devind, 0, sizeof(char)*MAXDEVICES);
- for (devtmp = inputInfo.devices; devtmp; devtmp = devtmp->next)
- devind[devtmp->id]++;
- for (devtmp = inputInfo.off_devices; devtmp; devtmp = devtmp->next)
- devind[devtmp->id]++;
- for (devid = 2; devid < MAXDEVICES && devind[devid]; devid++)
- ;
-
- if (devid >= MAXDEVICES)
- return (DeviceIntPtr)NULL;
- dev = _dixAllocateObjectWithPrivates(sizeof(DeviceIntRec) + sizeof(SpriteInfoRec),
- sizeof(DeviceIntRec) + sizeof(SpriteInfoRec),
- offsetof(DeviceIntRec, devPrivates), PRIVATE_DEVICE);
- if (!dev)
- return (DeviceIntPtr)NULL;
- dev->id = devid;
- dev->public.processInputProc = ProcessOtherEvent;
- dev->public.realInputProc = ProcessOtherEvent;
- dev->public.enqueueInputProc = EnqueueEvent;
- dev->deviceProc = deviceProc;
- dev->startup = autoStart;
-
- /* device grab defaults */
- dev->deviceGrab.grabTime = currentTime;
- dev->deviceGrab.ActivateGrab = ActivateKeyboardGrab;
- dev->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab;
-
- XkbSetExtension(dev, ProcessKeyboardEvent);
-
- dev->coreEvents = TRUE;
-
- /* sprite defaults */
- dev->spriteInfo = (SpriteInfoPtr)&dev[1];
-
- /* security creation/labeling check
- */
- if (XaceHook(XACE_DEVICE_ACCESS, client, dev, DixCreateAccess)) {
- free(dev);
- return NULL;
- }
-
- inputInfo.numDevices++;
-
- for (prev = &inputInfo.off_devices; *prev; prev = &(*prev)->next)
- ;
- *prev = dev;
- dev->next = NULL;
-
- enabled = FALSE;
- XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED),
- XA_INTEGER, 8, PropModeReplace, 1, &enabled,
- FALSE);
- XISetDevicePropertyDeletable(dev, XIGetKnownProperty(XI_PROP_ENABLED), FALSE);
-
- /* unity matrix */
- memset(transform, 0, sizeof(transform));
- transform[0] = transform[4] = transform[8] = 1.0f;
-
- XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_TRANSFORM),
- XIGetKnownProperty(XATOM_FLOAT), 32,
- PropModeReplace, 9, transform, FALSE);
- XISetDevicePropertyDeletable(dev, XIGetKnownProperty(XI_PROP_TRANSFORM),
- FALSE);
-
- XIRegisterPropertyHandler(dev, DeviceSetProperty, NULL, NULL);
-
- return dev;
-}
-
-void
-SendDevicePresenceEvent(int deviceid, int type)
-{
- DeviceIntRec dummyDev;
- devicePresenceNotify ev;
-
- memset(&dummyDev, 0, sizeof(DeviceIntRec));
- ev.type = DevicePresenceNotify;
- ev.time = currentTime.milliseconds;
- ev.devchange = type;
- ev.deviceid = deviceid;
- dummyDev.id = XIAllDevices;
- SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask,
- (xEvent*)&ev, 1);
-}
-
-/**
- * Enable the device through the driver, add the device to the device list.
- * Switch device ON through the driver and push it onto the global device
- * list. Initialize the DIX sprite or pair the device. All clients are
- * notified about the device being enabled.
- *
- * A master pointer device needs to be enabled before a master keyboard
- * device.
- *
- * @param The device to be enabled.
- * @param sendevent True if an XI2 event should be sent.
- * @return TRUE on success or FALSE otherwise.
- */
-Bool
-EnableDevice(DeviceIntPtr dev, BOOL sendevent)
-{
- DeviceIntPtr *prev;
- int ret;
- DeviceIntPtr other;
- BOOL enabled;
- int flags[MAXDEVICES] = {0};
-
- for (prev = &inputInfo.off_devices;
- *prev && (*prev != dev);
- prev = &(*prev)->next)
- ;
-
- if (!dev->spriteInfo->sprite)
- {
- if (IsMaster(dev))
- {
- /* Sprites appear on first root window, so we can hardcode it */
- if (dev->spriteInfo->spriteOwner)
- {
- InitializeSprite(dev, screenInfo.screens[0]->root);
- /* mode doesn't matter */
- EnterWindow(dev, screenInfo.screens[0]->root, NotifyAncestor);
- }
- else if ((other = NextFreePointerDevice()) == NULL)
- {
- ErrorF("[dix] cannot find pointer to pair with. "
- "This is a bug.\n");
- return FALSE;
- } else
- PairDevices(NULL, other, dev);
- } else
- {
- if (dev->coreEvents)
- other = (IsPointerDevice(dev)) ? inputInfo.pointer :
- inputInfo.keyboard;
- else
- other = NULL; /* auto-float non-core devices */
- AttachDevice(NULL, dev, other);
- }
- }
-
- if ((*prev != dev) || !dev->inited ||
- ((ret = (*dev->deviceProc)(dev, DEVICE_ON)) != Success)) {
- ErrorF("[dix] couldn't enable device %d\n", dev->id);
- return FALSE;
- }
- dev->enabled = TRUE;
- *prev = dev->next;
-
- for (prev = &inputInfo.devices; *prev; prev = &(*prev)->next)
- ;
- *prev = dev;
- dev->next = NULL;
-
- enabled = TRUE;
- XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED),
- XA_INTEGER, 8, PropModeReplace, 1, &enabled,
- TRUE);
-
- SendDevicePresenceEvent(dev->id, DeviceEnabled);
- if (sendevent)
- {
- flags[dev->id] |= XIDeviceEnabled;
- XISendDeviceHierarchyEvent(flags);
- }
-
- RecalculateMasterButtons(dev);
-
- return TRUE;
-}
-
-/**
- * Switch a device off through the driver and push it onto the off_devices
- * list. A device will not send events while disabled. All clients are
- * notified about the device being disabled.
- *
- * Master keyboard devices have to be disabled before master pointer devices
- * otherwise things turn bad.
- *
- * @param sendevent True if an XI2 event should be sent.
- * @return TRUE on success or FALSE otherwise.
- */
-Bool
-DisableDevice(DeviceIntPtr dev, BOOL sendevent)
-{
- DeviceIntPtr *prev, other;
- BOOL enabled;
- int flags[MAXDEVICES] = {0};
-
- for (prev = &inputInfo.devices;
- *prev && (*prev != dev);
- prev = &(*prev)->next)
- ;
- if (*prev != dev)
- return FALSE;
-
- /* float attached devices */
- if (IsMaster(dev))
- {
- for (other = inputInfo.devices; other; other = other->next)
- {
- if (!IsMaster(other) && GetMaster(other, MASTER_ATTACHED) == dev)
- {
- AttachDevice(NULL, other, NULL);
- flags[other->id] |= XISlaveDetached;
- }
- }
- }
- else
- {
- for (other = inputInfo.devices; other; other = other->next)
- {
- if (IsMaster(other) && other->lastSlave == dev)
- other->lastSlave = NULL;
- }
- }
-
- if (IsMaster(dev) && dev->spriteInfo->sprite)
- {
- for (other = inputInfo.devices; other; other = other->next)
- {
- if (other->spriteInfo->paired == dev)
- {
- ErrorF("[dix] cannot disable device, still paired. "
- "This is a bug. \n");
- return FALSE;
- }
- }
- }
-
- (void)(*dev->deviceProc)(dev, DEVICE_OFF);
- dev->enabled = FALSE;
-
- /* now that the device is disabled, we can reset the signal handler's
- * last.slave */
- OsBlockSignals();
- for (other = inputInfo.devices; other; other = other->next)
- {
- if (other->last.slave == dev)
- other->last.slave = NULL;
- }
- OsReleaseSignals();
-
- LeaveWindow(dev);
- SetFocusOut(dev);
-
- *prev = dev->next;
- dev->next = inputInfo.off_devices;
- inputInfo.off_devices = dev;
-
- enabled = FALSE;
- XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED),
- XA_INTEGER, 8, PropModeReplace, 1, &enabled,
- TRUE);
-
- SendDevicePresenceEvent(dev->id, DeviceDisabled);
- if (sendevent)
- {
- flags[dev->id] = XIDeviceDisabled;
- XISendDeviceHierarchyEvent(flags);
- }
-
- RecalculateMasterButtons(dev);
-
- return TRUE;
-}
-
-/**
- * Initialise a new device through the driver and tell all clients about the
- * new device.
- *
- * Must be called before EnableDevice.
- * The device will NOT send events until it is enabled!
- *
- * @param sendevent True if an XI2 event should be sent.
- * @return Success or an error code on failure.
- */
-int
-ActivateDevice(DeviceIntPtr dev, BOOL sendevent)
-{
- int ret = Success;
- ScreenPtr pScreen = screenInfo.screens[0];
-
- if (!dev || !dev->deviceProc)
- return BadImplementation;
-
- ret = (*dev->deviceProc) (dev, DEVICE_INIT);
- dev->inited = (ret == Success);
- if (!dev->inited)
- return ret;
-
- /* Initialize memory for sprites. */
- if (IsMaster(dev) && dev->spriteInfo->spriteOwner)
- if (!pScreen->DeviceCursorInitialize(dev, pScreen))
- ret = BadAlloc;
-
- SendDevicePresenceEvent(dev->id, DeviceAdded);
- if (sendevent)
- {
- int flags[MAXDEVICES] = {0};
- flags[dev->id] = XISlaveAdded;
- XISendDeviceHierarchyEvent(flags);
- }
- return ret;
-}
-
-/**
- * Ring the bell.
- * The actual task of ringing the bell is the job of the DDX.
- */
-static void
-CoreKeyboardBell(int volume, DeviceIntPtr pDev, pointer arg, int something)
-{
- KeybdCtrl *ctrl = arg;
-
- DDXRingBell(volume, ctrl->bell_pitch, ctrl->bell_duration);
-}
-
-static void
-CoreKeyboardCtl(DeviceIntPtr pDev, KeybdCtrl *ctrl)
-{
- return;
-}
-
-/**
- * Device control function for the Virtual Core Keyboard.
- */
-int
-CoreKeyboardProc(DeviceIntPtr pDev, int what)
-{
-
- switch (what) {
- case DEVICE_INIT:
- if (!InitKeyboardDeviceStruct(pDev, NULL, CoreKeyboardBell,
- CoreKeyboardCtl))
- {
- ErrorF("Keyboard initialization failed. This could be a missing "
- "or incorrect setup of xkeyboard-config.\n");
- return BadValue;
- }
- return Success;
-
- case DEVICE_ON:
- case DEVICE_OFF:
- return Success;
-
- case DEVICE_CLOSE:
- return Success;
- }
-
- return BadMatch;
-}
-
-/**
- * Device control function for the Virtual Core Pointer.
- */
-int
-CorePointerProc(DeviceIntPtr pDev, int what)
-{
-#define NBUTTONS 10
-#define NAXES 2
- BYTE map[NBUTTONS + 1];
- int i = 0;
- Atom btn_labels[NBUTTONS] = {0};
- Atom axes_labels[NAXES] = {0};
-
- switch (what) {
- case DEVICE_INIT:
- for (i = 1; i <= NBUTTONS; i++)
- map[i] = i;
-
- btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
- btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
- btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
- btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
- btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
- btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
- btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
- /* don't know about the rest */
-
- axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
- axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
-
- if (!InitPointerDeviceStruct((DevicePtr)pDev, map, NBUTTONS, btn_labels,
- (PtrCtrlProcPtr)NoopDDA,
- GetMotionHistorySize(), NAXES, axes_labels))
- {
- ErrorF("Could not initialize device '%s'. Out of memory.\n",
- pDev->name);
- return BadAlloc; /* IPDS only fails on allocs */
- }
- pDev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2;
- pDev->last.valuators[0] = pDev->valuator->axisVal[0];
- pDev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2;
- pDev->last.valuators[1] = pDev->valuator->axisVal[1];
- break;
-
- case DEVICE_CLOSE:
- break;
-
- default:
- break;
- }
-
- return Success;
-
-#undef NBUTTONS
-#undef NAXES
-}
-
-/**
- * Initialise the two core devices, VCP and VCK (see events.c).
- * Both devices are not tied to physical devices, but guarantee that there is
- * always a keyboard and a pointer present and keep the protocol semantics.
- *
- * Note that the server MUST have two core devices at all times, even if there
- * is no physical device connected.
- */
-void
-InitCoreDevices(void)
-{
- if (AllocDevicePair(serverClient, "Virtual core",
- &inputInfo.pointer, &inputInfo.keyboard,
- CorePointerProc, CoreKeyboardProc,
- TRUE) != Success)
- FatalError("Failed to allocate core devices");
-
- if (ActivateDevice(inputInfo.pointer, TRUE) != Success ||
- ActivateDevice(inputInfo.keyboard, TRUE) != Success)
- FatalError("Failed to activate core devices.");
- if (!EnableDevice(inputInfo.pointer, TRUE) ||
- !EnableDevice(inputInfo.keyboard, TRUE))
- FatalError("Failed to enable core devices.");
-
- InitXTestDevices();
-}
-
-/**
- * Activate all switched-off devices and then enable all those devices.
- *
- * Will return an error if no core keyboard or core pointer is present.
- * In theory this should never happen if you call InitCoreDevices() first.
- *
- * InitAndStartDevices needs to be called AFTER the windows are initialized.
- * Devices will start sending events after InitAndStartDevices() has
- * completed.
- *
- * @return Success or error code on failure.
- */
-int
-InitAndStartDevices(void)
-{
- DeviceIntPtr dev, next;
-
- for (dev = inputInfo.off_devices; dev; dev = dev->next) {
- DebugF("(dix) initialising device %d\n", dev->id);
- if (!dev->inited)
- ActivateDevice(dev, TRUE);
- }
-
- /* enable real devices */
- for (dev = inputInfo.off_devices; dev; dev = next)
- {
- DebugF("(dix) enabling device %d\n", dev->id);
- next = dev->next;
- if (dev->inited && dev->startup)
- EnableDevice(dev, TRUE);
- }
-
- return Success;
-}
-
-/**
- * Free the given device class and reset the pointer to NULL.
- */
-static void
-FreeDeviceClass(int type, pointer *class)
-{
- if (!(*class))
- return;
-
- switch(type)
- {
- case KeyClass:
- {
- KeyClassPtr* k = (KeyClassPtr*)class;
- if ((*k)->xkbInfo)
- {
- XkbFreeInfo((*k)->xkbInfo);
- (*k)->xkbInfo = NULL;
- }
- free((*k));
- break;
- }
- case ButtonClass:
- {
- ButtonClassPtr *b = (ButtonClassPtr*)class;
- free((*b)->xkb_acts);
- free((*b));
- break;
- }
- case ValuatorClass:
- {
- ValuatorClassPtr *v = (ValuatorClassPtr*)class;
-
- free((*v)->motion);
- free((*v));
- break;
- }
- case FocusClass:
- {
- FocusClassPtr *f = (FocusClassPtr*)class;
- free((*f)->trace);
- free((*f));
- break;
- }
- case ProximityClass:
- {
- ProximityClassPtr *p = (ProximityClassPtr*)class;
- free((*p));
- break;
- }
- }
- *class = NULL;
-}
-
-static void
-FreeFeedbackClass(int type, pointer *class)
-{
- if (!(*class))
- return;
-
- switch(type)
- {
- case KbdFeedbackClass:
- {
- KbdFeedbackPtr *kbdfeed = (KbdFeedbackPtr*)class;
- KbdFeedbackPtr k, knext;
- for (k = (*kbdfeed); k; k = knext) {
- knext = k->next;
- if (k->xkb_sli)
- XkbFreeSrvLedInfo(k->xkb_sli);
- free(k);
- }
- break;
- }
- case PtrFeedbackClass:
- {
- PtrFeedbackPtr *ptrfeed = (PtrFeedbackPtr*)class;
- PtrFeedbackPtr p, pnext;
-
- for (p = (*ptrfeed); p; p = pnext) {
- pnext = p->next;
- free(p);
- }
- break;
- }
- case IntegerFeedbackClass:
- {
- IntegerFeedbackPtr *intfeed = (IntegerFeedbackPtr*)class;
- IntegerFeedbackPtr i, inext;
-
- for (i = (*intfeed); i; i = inext) {
- inext = i->next;
- free(i);
- }
- break;
- }
- case StringFeedbackClass:
- {
- StringFeedbackPtr *stringfeed = (StringFeedbackPtr*)class;
- StringFeedbackPtr s, snext;
-
- for (s = (*stringfeed); s; s = snext) {
- snext = s->next;
- free(s->ctrl.symbols_supported);
- free(s->ctrl.symbols_displayed);
- free(s);
- }
- break;
- }
- case BellFeedbackClass:
- {
- BellFeedbackPtr *bell = (BellFeedbackPtr*)class;
- BellFeedbackPtr b, bnext;
-
- for (b = (*bell); b; b = bnext) {
- bnext = b->next;
- free(b);
- }
- break;
- }
- case LedFeedbackClass:
- {
- LedFeedbackPtr *leds = (LedFeedbackPtr*)class;
- LedFeedbackPtr l, lnext;
-
- for (l = (*leds); l; l = lnext) {
- lnext = l->next;
- if (l->xkb_sli)
- XkbFreeSrvLedInfo(l->xkb_sli);
- free(l);
- }
- break;
- }
- }
- *class = NULL;
-}
-
-static void
-FreeAllDeviceClasses(ClassesPtr classes)
-{
- if (!classes)
- return;
-
- FreeDeviceClass(KeyClass, (pointer)&classes->key);
- FreeDeviceClass(ValuatorClass, (pointer)&classes->valuator);
- FreeDeviceClass(ButtonClass, (pointer)&classes->button);
- FreeDeviceClass(FocusClass, (pointer)&classes->focus);
- FreeDeviceClass(ProximityClass, (pointer)&classes->proximity);
-
- FreeFeedbackClass(KbdFeedbackClass, (pointer)&classes->kbdfeed);
- FreeFeedbackClass(PtrFeedbackClass, (pointer)&classes->ptrfeed);
- FreeFeedbackClass(IntegerFeedbackClass, (pointer)&classes->intfeed);
- FreeFeedbackClass(StringFeedbackClass, (pointer)&classes->stringfeed);
- FreeFeedbackClass(BellFeedbackClass, (pointer)&classes->bell);
- FreeFeedbackClass(LedFeedbackClass, (pointer)&classes->leds);
-
-}
-
-/**
- * Close down a device and free all resources.
- * Once closed down, the driver will probably not expect you that you'll ever
- * enable it again and free associated structs. If you want the device to just
- * be disabled, DisableDevice().
- * Don't call this function directly, use RemoveDevice() instead.
- */
-static void
-CloseDevice(DeviceIntPtr dev)
-{
- ScreenPtr screen = screenInfo.screens[0];
- ClassesPtr classes;
- int j;
-
- if (!dev)
- return;
-
- XIDeleteAllDeviceProperties(dev);
-
- if (dev->inited)
- (void)(*dev->deviceProc)(dev, DEVICE_CLOSE);
-
- /* free sprite memory */
- if (IsMaster(dev) && dev->spriteInfo->sprite)
- screen->DeviceCursorCleanup(dev, screen);
-
- /* free acceleration info */
- if(dev->valuator && dev->valuator->accelScheme.AccelCleanupProc)
- dev->valuator->accelScheme.AccelCleanupProc(dev);
-
- while (dev->xkb_interest)
- XkbRemoveResourceClient((DevicePtr)dev,dev->xkb_interest->resource);
-
- free(dev->name);
-
- classes = (ClassesPtr)&dev->key;
- FreeAllDeviceClasses(classes);
-
- if (IsMaster(dev))
- {
- classes = dev->unused_classes;
- FreeAllDeviceClasses(classes);
- free(classes);
- }
-
- if (DevHasCursor(dev) && dev->spriteInfo->sprite) {
- if (dev->spriteInfo->sprite->current)
- FreeCursor(dev->spriteInfo->sprite->current, None);
- free(dev->spriteInfo->sprite->spriteTrace);
- free(dev->spriteInfo->sprite);
- }
-
- /* a client may have the device set as client pointer */
- for (j = 0; j < currentMaxClients; j++)
- {
- if (clients[j] && clients[j]->clientPtr == dev)
- {
- clients[j]->clientPtr = NULL;
- clients[j]->clientPtr = PickPointer(clients[j]);
- }
- }
-
- free(dev->deviceGrab.sync.event);
- dixFreeObjectWithPrivates(dev, PRIVATE_DEVICE);
-}
-
-/**
- * Shut down all devices of one list and free all resources.
- */
-static
-void
-CloseDeviceList(DeviceIntPtr *listHead)
-{
- /* Used to mark devices that we tried to free */
- Bool freedIds[MAXDEVICES];
- DeviceIntPtr dev;
- int i;
-
- if (listHead == NULL)
- return;
-
- for (i = 0; i < MAXDEVICES; i++)
- freedIds[i] = FALSE;
-
- dev = *listHead;
- while (dev != NULL)
- {
- freedIds[dev->id] = TRUE;
- DeleteInputDeviceRequest(dev);
-
- dev = *listHead;
- while (dev != NULL && freedIds[dev->id])
- dev = dev->next;
- }
-}
-
-/**
- * Shut down all devices, free all resources, etc.
- * Only useful if you're shutting down the server!
- */
-void
-CloseDownDevices(void)
-{
- DeviceIntPtr dev;
-
- /* Float all SDs before closing them. Note that at this point resources
- * (e.g. cursors) have been freed already, so we can't just call
- * AttachDevice(NULL, dev, NULL). Instead, we have to forcibly set master
- * to NULL and pretend nothing happened.
- */
- for (dev = inputInfo.devices; dev; dev = dev->next)
- {
- if (!IsMaster(dev) && !IsFloating(dev))
- dev->master = NULL;
- }
-
- CloseDeviceList(&inputInfo.devices);
- CloseDeviceList(&inputInfo.off_devices);
-
- CloseDevice(inputInfo.pointer);
- CloseDevice(inputInfo.keyboard);
-
- inputInfo.devices = NULL;
- inputInfo.off_devices = NULL;
- inputInfo.keyboard = NULL;
- inputInfo.pointer = NULL;
- XkbDeleteRulesDflts();
-}
-
-/**
- * Remove the cursor sprite for all devices. This needs to be done before any
- * resources are freed or any device is deleted.
- */
-void
-UndisplayDevices(void)
-{
- DeviceIntPtr dev;
- ScreenPtr screen = screenInfo.screens[0];
-
- for (dev = inputInfo.devices; dev; dev = dev->next)
- screen->DisplayCursor(dev, screen, NullCursor);
-}
-
-/**
- * Remove a device from the device list, closes it and thus frees all
- * resources.
- * Removes both enabled and disabled devices and notifies all devices about
- * the removal of the device.
- *
- * No PresenceNotify is sent for device that the client never saw. This can
- * happen if a malloc fails during the addition of master devices. If
- * dev->init is FALSE it means the client never received a DeviceAdded event,
- * so let's not send a DeviceRemoved event either.
- *
- * @param sendevent True if an XI2 event should be sent.
- */
-int
-RemoveDevice(DeviceIntPtr dev, BOOL sendevent)
-{
- DeviceIntPtr prev,tmp,next;
- int ret = BadMatch;
- ScreenPtr screen = screenInfo.screens[0];
- int deviceid;
- int initialized;
- int flags[MAXDEVICES] = {0};
-
- DebugF("(dix) removing device %d\n", dev->id);
-
- if (!dev || dev == inputInfo.keyboard || dev == inputInfo.pointer)
- return BadImplementation;
-
- initialized = dev->inited;
- deviceid = dev->id;
-
- if (initialized)
- {
- if (DevHasCursor(dev))
- screen->DisplayCursor(dev, screen, NullCursor);
-
- DisableDevice(dev, sendevent);
- flags[dev->id] = XIDeviceDisabled;
- }
-
- prev = NULL;
- for (tmp = inputInfo.devices; tmp; (prev = tmp), (tmp = next)) {
- next = tmp->next;
- if (tmp == dev) {
-
- if (prev==NULL)
- inputInfo.devices = next;
- else
- prev->next = next;
-
- flags[tmp->id] = IsMaster(tmp) ? XIMasterRemoved : XISlaveRemoved;
- CloseDevice(tmp);
- ret = Success;
- }
- }
-
- prev = NULL;
- for (tmp = inputInfo.off_devices; tmp; (prev = tmp), (tmp = next)) {
- next = tmp->next;
- if (tmp == dev) {
- flags[tmp->id] = IsMaster(tmp) ? XIMasterRemoved : XISlaveRemoved;
- CloseDevice(tmp);
-
- if (prev == NULL)
- inputInfo.off_devices = next;
- else
- prev->next = next;
-
- ret = Success;
- }
- }
-
- if (ret == Success && initialized) {
- inputInfo.numDevices--;
- SendDevicePresenceEvent(deviceid, DeviceRemoved);
- if (sendevent)
- XISendDeviceHierarchyEvent(flags);
- }
-
- return ret;
-}
-
-int
-NumMotionEvents(void)
-{
- /* only called to fill data in initial connection reply.
- * VCP is ok here, it is the only fixed device we have. */
- return inputInfo.pointer->valuator->numMotionEvents;
-}
-
-int
-dixLookupDevice(DeviceIntPtr *pDev, int id, ClientPtr client, Mask access_mode)
-{
- DeviceIntPtr dev;
- int rc;
- *pDev = NULL;
-
- for (dev=inputInfo.devices; dev; dev=dev->next) {
- if (dev->id == id)
- goto found;
- }
- for (dev=inputInfo.off_devices; dev; dev=dev->next) {
- if (dev->id == id)
- goto found;
- }
- return BadDevice;
-
-found:
- rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode);
- if (rc == Success)
- *pDev = dev;
- return rc;
-}
-
-void
-QueryMinMaxKeyCodes(KeyCode *minCode, KeyCode *maxCode)
-{
- if (inputInfo.keyboard) {
- *minCode = inputInfo.keyboard->key->xkbInfo->desc->min_key_code;
- *maxCode = inputInfo.keyboard->key->xkbInfo->desc->max_key_code;
- }
-}
-
-/* Notably, this function does not expand the destination's keycode range, or
- * notify clients. */
-Bool
-SetKeySymsMap(KeySymsPtr dst, KeySymsPtr src)
-{
- int i, j;
- KeySym *tmp;
- int rowDif = src->minKeyCode - dst->minKeyCode;
-
- /* if keysym map size changes, grow map first */
- if (src->mapWidth < dst->mapWidth) {
- for (i = src->minKeyCode; i <= src->maxKeyCode; i++) {
-#define SI(r, c) (((r - src->minKeyCode) * src->mapWidth) + (c))
-#define DI(r, c) (((r - dst->minKeyCode) * dst->mapWidth) + (c))
- for (j = 0; j < src->mapWidth; j++)
- dst->map[DI(i, j)] = src->map[SI(i, j)];
- for (j = src->mapWidth; j < dst->mapWidth; j++)
- dst->map[DI(i, j)] = NoSymbol;
-#undef SI
-#undef DI
- }
- return TRUE;
- }
- else if (src->mapWidth > dst->mapWidth) {
- i = sizeof(KeySym) * src->mapWidth *
- (dst->maxKeyCode - dst->minKeyCode + 1);
- tmp = calloc(sizeof(KeySym), i);
- if (!tmp)
- return FALSE;
-
- if (dst->map) {
- for (i = 0; i <= dst->maxKeyCode-dst->minKeyCode; i++)
- memmove(&tmp[i * src->mapWidth], &dst->map[i * dst->mapWidth],
- dst->mapWidth * sizeof(KeySym));
- free(dst->map);
- }
- dst->mapWidth = src->mapWidth;
- dst->map = tmp;
- }
- else if (!dst->map) {
- i = sizeof(KeySym) * src->mapWidth *
- (dst->maxKeyCode - dst->minKeyCode + 1);
- tmp = calloc(sizeof(KeySym), i);
- if (!tmp)
- return FALSE;
-
- dst->map = tmp;
- dst->mapWidth = src->mapWidth;
- }
-
- memmove(&dst->map[rowDif * dst->mapWidth], src->map,
- (src->maxKeyCode - src->minKeyCode + 1) *
- dst->mapWidth * sizeof(KeySym));
-
- return TRUE;
-}
-
-Bool
-InitButtonClassDeviceStruct(DeviceIntPtr dev, int numButtons, Atom* labels,
- CARD8 *map)
-{
- ButtonClassPtr butc;
- int i;
-
- butc = calloc(1, sizeof(ButtonClassRec));
- if (!butc)
- return FALSE;
- butc->numButtons = numButtons;
- butc->sourceid = dev->id;
- for (i = 1; i <= numButtons; i++)
- butc->map[i] = map[i];
- for (i = numButtons + 1; i < MAP_LENGTH; i++)
- butc->map[i] = i;
- memcpy(butc->labels, labels, numButtons * sizeof(Atom));
- dev->button = butc;
- return TRUE;
-}
-
-Bool
-InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, Atom *labels,
- int numMotionEvents, int mode)
-{
- int i;
- ValuatorClassPtr valc;
- union align_u { ValuatorClassRec valc; double d; } *align;
-
- if (!dev)
- return FALSE;
-
- if (numAxes > MAX_VALUATORS)
- {
- LogMessage(X_WARNING,
- "Device '%s' has %d axes, only using first %d.\n",
- dev->name, numAxes, MAX_VALUATORS);
- numAxes = MAX_VALUATORS;
- }
-
- align = (union align_u *) calloc(1, sizeof(union align_u) +
- numAxes * sizeof(double) +
- numAxes * sizeof(AxisInfo));
- if (!align)
- return FALSE;
-
- valc = &align->valc;
- valc->sourceid = dev->id;
- valc->motion = NULL;
- valc->first_motion = 0;
- valc->last_motion = 0;
-
- valc->numMotionEvents = numMotionEvents;
- valc->motionHintWindow = NullWindow;
- valc->numAxes = numAxes;
- valc->axisVal = (double *)(align + 1);
- valc->axes = (AxisInfoPtr)(valc->axisVal + numAxes);
-
- if (mode & OutOfProximity)
- InitProximityClassDeviceStruct(dev);
-
- dev->valuator = valc;
-
- AllocateMotionHistory(dev);
-
- for (i=0; i<numAxes; i++) {
- InitValuatorAxisStruct(dev, i, labels[i], NO_AXIS_LIMITS, NO_AXIS_LIMITS,
- 0, 0, 0, mode);
- valc->axisVal[i]=0;
- }
-
- dev->last.numValuators = numAxes;
-
- if (IsMaster(dev) || /* do not accelerate master or xtest devices */
- IsXTestDevice(dev, NULL))
- InitPointerAccelerationScheme(dev, PtrAccelNoOp);
- else
- InitPointerAccelerationScheme(dev, PtrAccelDefault);
- return TRUE;
-}
-
-/* global list of acceleration schemes */
-ValuatorAccelerationRec pointerAccelerationScheme[] = {
- {PtrAccelNoOp, NULL, NULL, NULL, NULL},
- {PtrAccelPredictable, acceleratePointerPredictable, NULL,
- InitPredictableAccelerationScheme, AccelerationDefaultCleanup},
- {PtrAccelLightweight, acceleratePointerLightweight, NULL, NULL, NULL},
- {-1, NULL, NULL, NULL, NULL} /* terminator */
-};
-
-/**
- * install an acceleration scheme. returns TRUE on success, and should not
- * change anything if unsuccessful.
- */
-Bool
-InitPointerAccelerationScheme(DeviceIntPtr dev,
- int scheme)
-{
- int x, i = -1;
- ValuatorClassPtr val;
-
- val = dev->valuator;
-
- if (!val)
- return FALSE;
-
- if (IsMaster(dev) && scheme != PtrAccelNoOp)
- return FALSE;
-
- for (x = 0; pointerAccelerationScheme[x].number >= 0; x++) {
- if(pointerAccelerationScheme[x].number == scheme){
- i = x;
- break;
- }
- }
-
- if (-1 == i)
- return FALSE;
-
- if (val->accelScheme.AccelCleanupProc)
- val->accelScheme.AccelCleanupProc(dev);
-
- if (pointerAccelerationScheme[i].AccelInitProc) {
- if (!pointerAccelerationScheme[i].AccelInitProc(dev,
- &pointerAccelerationScheme[i])) {
- return FALSE;
- }
- } else {
- val->accelScheme = pointerAccelerationScheme[i];
- }
- return TRUE;
-}
-
-Bool
-InitAbsoluteClassDeviceStruct(DeviceIntPtr dev)
-{
- AbsoluteClassPtr abs;
-
- abs = malloc(sizeof(AbsoluteClassRec));
- if (!abs)
- return FALSE;
-
- /* we don't do anything sensible with these, but should */
- abs->min_x = NO_AXIS_LIMITS;
- abs->min_y = NO_AXIS_LIMITS;
- abs->max_x = NO_AXIS_LIMITS;
- abs->max_y = NO_AXIS_LIMITS;
- abs->flip_x = 0;
- abs->flip_y = 0;
- abs->rotation = 0;
- abs->button_threshold = 0;
-
- abs->offset_x = 0;
- abs->offset_y = 0;
- abs->width = NO_AXIS_LIMITS;
- abs->height = NO_AXIS_LIMITS;
- abs->following = 0;
- abs->screen = 0;
-
- abs->sourceid = dev->id;
-
- dev->absolute = abs;
-
- return TRUE;
-}
-
-Bool
-InitFocusClassDeviceStruct(DeviceIntPtr dev)
-{
- FocusClassPtr focc;
-
- focc = malloc(sizeof(FocusClassRec));
- if (!focc)
- return FALSE;
- focc->win = PointerRootWin;
- focc->revert = None;
- focc->time = currentTime;
- focc->trace = (WindowPtr *)NULL;
- focc->traceSize = 0;
- focc->traceGood = 0;
- focc->sourceid = dev->id;
- dev->focus = focc;
- return TRUE;
-}
-
-Bool
-InitPtrFeedbackClassDeviceStruct(DeviceIntPtr dev, PtrCtrlProcPtr controlProc)
-{
- PtrFeedbackPtr feedc;
-
- feedc = malloc(sizeof(PtrFeedbackClassRec));
- if (!feedc)
- return FALSE;
- feedc->CtrlProc = controlProc;
- feedc->ctrl = defaultPointerControl;
- feedc->ctrl.id = 0;
- if ( (feedc->next = dev->ptrfeed) )
- feedc->ctrl.id = dev->ptrfeed->ctrl.id + 1;
- dev->ptrfeed = feedc;
- (*controlProc)(dev, &feedc->ctrl);
- return TRUE;
-}
-
-
-static LedCtrl defaultLedControl = {
- DEFAULT_LEDS, DEFAULT_LEDS_MASK, 0};
-
-static BellCtrl defaultBellControl = {
- DEFAULT_BELL,
- DEFAULT_BELL_PITCH,
- DEFAULT_BELL_DURATION,
- 0};
-
-static IntegerCtrl defaultIntegerControl = {
- DEFAULT_INT_RESOLUTION,
- DEFAULT_INT_MIN_VALUE,
- DEFAULT_INT_MAX_VALUE,
- DEFAULT_INT_DISPLAYED,
- 0};
-
-Bool
-InitStringFeedbackClassDeviceStruct (
- DeviceIntPtr dev, StringCtrlProcPtr controlProc,
- int max_symbols, int num_symbols_supported, KeySym *symbols)
-{
- int i;
- StringFeedbackPtr feedc;
-
- feedc = malloc(sizeof(StringFeedbackClassRec));
- if (!feedc)
- return FALSE;
- feedc->CtrlProc = controlProc;
- feedc->ctrl.num_symbols_supported = num_symbols_supported;
- feedc->ctrl.num_symbols_displayed = 0;
- feedc->ctrl.max_symbols = max_symbols;
- feedc->ctrl.symbols_supported = malloc(sizeof (KeySym) * num_symbols_supported);
- feedc->ctrl.symbols_displayed = malloc(sizeof (KeySym) * max_symbols);
- if (!feedc->ctrl.symbols_supported || !feedc->ctrl.symbols_displayed)
- {
- free(feedc->ctrl.symbols_supported);
- free(feedc->ctrl.symbols_displayed);
- free(feedc);
- return FALSE;
- }
- for (i=0; i<num_symbols_supported; i++)
- *(feedc->ctrl.symbols_supported+i) = *symbols++;
- for (i=0; i<max_symbols; i++)
- *(feedc->ctrl.symbols_displayed+i) = (KeySym) 0;
- feedc->ctrl.id = 0;
- if ( (feedc->next = dev->stringfeed) )
- feedc->ctrl.id = dev->stringfeed->ctrl.id + 1;
- dev->stringfeed = feedc;
- (*controlProc)(dev, &feedc->ctrl);
- return TRUE;
-}
-
-Bool
-InitBellFeedbackClassDeviceStruct (DeviceIntPtr dev, BellProcPtr bellProc,
- BellCtrlProcPtr controlProc)
-{
- BellFeedbackPtr feedc;
-
- feedc = malloc(sizeof(BellFeedbackClassRec));
- if (!feedc)
- return FALSE;
- feedc->CtrlProc = controlProc;
- feedc->BellProc = bellProc;
- feedc->ctrl = defaultBellControl;
- feedc->ctrl.id = 0;
- if ( (feedc->next = dev->bell) )
- feedc->ctrl.id = dev->bell->ctrl.id + 1;
- dev->bell = feedc;
- (*controlProc)(dev, &feedc->ctrl);
- return TRUE;
-}
-
-Bool
-InitLedFeedbackClassDeviceStruct (DeviceIntPtr dev, LedCtrlProcPtr controlProc)
-{
- LedFeedbackPtr feedc;
-
- feedc = malloc(sizeof(LedFeedbackClassRec));
- if (!feedc)
- return FALSE;
- feedc->CtrlProc = controlProc;
- feedc->ctrl = defaultLedControl;
- feedc->ctrl.id = 0;
- if ( (feedc->next = dev->leds) )
- feedc->ctrl.id = dev->leds->ctrl.id + 1;
- feedc->xkb_sli= NULL;
- dev->leds = feedc;
- (*controlProc)(dev, &feedc->ctrl);
- return TRUE;
-}
-
-Bool
-InitIntegerFeedbackClassDeviceStruct (DeviceIntPtr dev, IntegerCtrlProcPtr controlProc)
-{
- IntegerFeedbackPtr feedc;
-
- feedc = malloc(sizeof(IntegerFeedbackClassRec));
- if (!feedc)
- return FALSE;
- feedc->CtrlProc = controlProc;
- feedc->ctrl = defaultIntegerControl;
- feedc->ctrl.id = 0;
- if ( (feedc->next = dev->intfeed) )
- feedc->ctrl.id = dev->intfeed->ctrl.id + 1;
- dev->intfeed = feedc;
- (*controlProc)(dev, &feedc->ctrl);
- return TRUE;
-}
-
-Bool
-InitPointerDeviceStruct(DevicePtr device, CARD8 *map, int numButtons, Atom* btn_labels,
- PtrCtrlProcPtr controlProc, int numMotionEvents,
- int numAxes, Atom *axes_labels)
-{
- DeviceIntPtr dev = (DeviceIntPtr)device;
-
- return(InitButtonClassDeviceStruct(dev, numButtons, btn_labels, map) &&
- InitValuatorClassDeviceStruct(dev, numAxes, axes_labels,
- numMotionEvents, Relative) &&
- InitPtrFeedbackClassDeviceStruct(dev, controlProc));
-}
-
-/*
- * Check if the given buffer contains elements between low (inclusive) and
- * high (inclusive) only.
- *
- * @return TRUE if the device map is invalid, FALSE otherwise.
- */
-Bool
-BadDeviceMap(BYTE *buff, int length, unsigned low, unsigned high, XID *errval)
-{
- int i;
-
- for (i = 0; i < length; i++)
- if (buff[i]) /* only check non-zero elements */
- {
- if ((low > buff[i]) || (high < buff[i]))
- {
- *errval = buff[i];
- return TRUE;
- }
- }
- return FALSE;
-}
-
-int
-ProcSetModifierMapping(ClientPtr client)
-{
- xSetModifierMappingReply rep;
- int rc;
- REQUEST(xSetModifierMappingReq);
- REQUEST_AT_LEAST_SIZE(xSetModifierMappingReq);
-
- if (client->req_len != ((stuff->numKeyPerModifier << 1) +
- bytes_to_int32(sizeof(xSetModifierMappingReq))))
- return BadLength;
-
- rep.type = X_Reply;
- rep.length = 0;
- rep.sequenceNumber = client->sequence;
-
- rc = change_modmap(client, PickKeyboard(client), (KeyCode *)&stuff[1],
- stuff->numKeyPerModifier);
- if (rc == MappingFailed || rc == -1)
- return BadValue;
- if (rc != Success && rc != MappingSuccess && rc != MappingFailed &&
- rc != MappingBusy)
- return rc;
-
- rep.success = rc;
-
- WriteReplyToClient(client, sizeof(xSetModifierMappingReply), &rep);
- return Success;
-}
-
-int
-ProcGetModifierMapping(ClientPtr client)
-{
- xGetModifierMappingReply rep;
- int max_keys_per_mod = 0;
- KeyCode *modkeymap = NULL;
- REQUEST_SIZE_MATCH(xReq);
-
- generate_modkeymap(client, PickKeyboard(client), &modkeymap,
- &max_keys_per_mod);
-
- memset(&rep, 0, sizeof(xGetModifierMappingReply));
- rep.type = X_Reply;
- rep.numKeyPerModifier = max_keys_per_mod;
- rep.sequenceNumber = client->sequence;
- /* length counts 4 byte quantities - there are 8 modifiers 1 byte big */
- rep.length = max_keys_per_mod << 1;
-
- WriteReplyToClient(client, sizeof(xGetModifierMappingReply), &rep);
- (void)WriteToClient(client, max_keys_per_mod * 8, (char *) modkeymap);
-
- free(modkeymap);
-
- return Success;
-}
-
-int
-ProcChangeKeyboardMapping(ClientPtr client)
-{
- REQUEST(xChangeKeyboardMappingReq);
- unsigned len;
- KeySymsRec keysyms;
- DeviceIntPtr pDev, tmp;
- int rc;
- REQUEST_AT_LEAST_SIZE(xChangeKeyboardMappingReq);
-
- len = client->req_len - bytes_to_int32(sizeof(xChangeKeyboardMappingReq));
- if (len != (stuff->keyCodes * stuff->keySymsPerKeyCode))
- return BadLength;
-
- pDev = PickKeyboard(client);
-
- if ((stuff->firstKeyCode < pDev->key->xkbInfo->desc->min_key_code) ||
- (stuff->firstKeyCode > pDev->key->xkbInfo->desc->max_key_code)) {
- client->errorValue = stuff->firstKeyCode;
- return BadValue;
-
- }
- if (((unsigned)(stuff->firstKeyCode + stuff->keyCodes - 1) >
- pDev->key->xkbInfo->desc->max_key_code) ||
- (stuff->keySymsPerKeyCode == 0)) {
- client->errorValue = stuff->keySymsPerKeyCode;
- return BadValue;
- }
-
- keysyms.minKeyCode = stuff->firstKeyCode;
- keysyms.maxKeyCode = stuff->firstKeyCode + stuff->keyCodes - 1;
- keysyms.mapWidth = stuff->keySymsPerKeyCode;
- keysyms.map = (KeySym *) &stuff[1];
-
- rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess);
- if (rc != Success)
- return rc;
-
- XkbApplyMappingChange(pDev, &keysyms, stuff->firstKeyCode,
- stuff->keyCodes, NULL, client);
-
- for (tmp = inputInfo.devices; tmp; tmp = tmp->next) {
- if (IsMaster(tmp) || GetMaster(tmp, MASTER_KEYBOARD) != pDev)
- continue;
- if (!tmp->key)
- continue;
-
- rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess);
- if (rc != Success)
- continue;
-
- XkbApplyMappingChange(tmp, &keysyms, stuff->firstKeyCode,
- stuff->keyCodes, NULL, client);
- }
-
- return Success;
-}
-
-int
-ProcSetPointerMapping(ClientPtr client)
-{
- BYTE *map;
- int ret;
- int i, j;
- DeviceIntPtr ptr = PickPointer(client);
- xSetPointerMappingReply rep;
- REQUEST(xSetPointerMappingReq);
- REQUEST_AT_LEAST_SIZE(xSetPointerMappingReq);
-
- if (client->req_len !=
- bytes_to_int32(sizeof(xSetPointerMappingReq) + stuff->nElts))
- return BadLength;
- rep.type = X_Reply;
- rep.length = 0;
- rep.sequenceNumber = client->sequence;
- rep.success = MappingSuccess;
- map = (BYTE *)&stuff[1];
-
- /* So we're bounded here by the number of core buttons. This check
- * probably wants disabling through XFixes. */
- /* MPX: With ClientPointer, we can return the right number of buttons.
- * Let's just hope nobody changed ClientPointer between GetPointerMapping
- * and SetPointerMapping
- */
- if (stuff->nElts != ptr->button->numButtons) {
- client->errorValue = stuff->nElts;
- return BadValue;
- }
-
- /* Core protocol specs don't allow for duplicate mappings; this check
- * almost certainly wants disabling through XFixes too. */
- for (i = 0; i < stuff->nElts; i++) {
- for (j = i + 1; j < stuff->nElts; j++) {
- if (map[i] && map[i] == map[j]) {
- client->errorValue = map[i];
- return BadValue;
- }
- }
- }
-
- ret = ApplyPointerMapping(ptr, map, stuff->nElts, client);
- if (ret == MappingBusy)
- rep.success = ret;
- else if (ret == -1)
- return BadValue;
- else if (ret != Success)
- return ret;
-
- WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep);
- return Success;
-}
-
-int
-ProcGetKeyboardMapping(ClientPtr client)
-{
- xGetKeyboardMappingReply rep;
- DeviceIntPtr kbd = PickKeyboard(client);
- XkbDescPtr xkb;
- KeySymsPtr syms;
- int rc;
- REQUEST(xGetKeyboardMappingReq);
- REQUEST_SIZE_MATCH(xGetKeyboardMappingReq);
-
- rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetAttrAccess);
- if (rc != Success)
- return rc;
-
- xkb = kbd->key->xkbInfo->desc;
-
- if ((stuff->firstKeyCode < xkb->min_key_code) ||
- (stuff->firstKeyCode > xkb->max_key_code)) {
- client->errorValue = stuff->firstKeyCode;
- return BadValue;
- }
- if (stuff->firstKeyCode + stuff->count > xkb->max_key_code + 1) {
- client->errorValue = stuff->count;
- return BadValue;
- }
-
- syms = XkbGetCoreMap(kbd);
- if (!syms)
- return BadAlloc;
-
- memset(&rep, 0, sizeof(xGetKeyboardMappingReply));
- rep.type = X_Reply;
- rep.sequenceNumber = client->sequence;
- rep.keySymsPerKeyCode = syms->mapWidth;
- /* length is a count of 4 byte quantities and KeySyms are 4 bytes */
- rep.length = syms->mapWidth * stuff->count;
- WriteReplyToClient(client, sizeof(xGetKeyboardMappingReply), &rep);
- client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write;
- WriteSwappedDataToClient(client,
- syms->mapWidth * stuff->count * sizeof(KeySym),
- &syms->map[syms->mapWidth * (stuff->firstKeyCode -
- syms->minKeyCode)]);
- free(syms->map);
- free(syms);
-
- return Success;
-}
-
-int
-ProcGetPointerMapping(ClientPtr client)
-{
- xGetPointerMappingReply rep;
- /* Apps may get different values each time they call GetPointerMapping as
- * the ClientPointer could change. */
- DeviceIntPtr ptr = PickPointer(client);
- ButtonClassPtr butc = ptr->button;
- int rc;
- REQUEST_SIZE_MATCH(xReq);
-
- rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, DixGetAttrAccess);
- if (rc != Success)
- return rc;
-
- rep.type = X_Reply;
- rep.sequenceNumber = client->sequence;
- rep.nElts = (butc) ? butc->numButtons : 0;
- rep.length = ((unsigned)rep.nElts + (4-1))/4;
- WriteReplyToClient(client, sizeof(xGetPointerMappingReply), &rep);
- if (butc)
- WriteToClient(client, (int)rep.nElts, (char *)&butc->map[1]);
- return Success;
-}
-
-void
-NoteLedState(DeviceIntPtr keybd, int led, Bool on)
-{
- KeybdCtrl *ctrl = &keybd->kbdfeed->ctrl;
- if (on)
- ctrl->leds |= ((Leds)1 << (led - 1));
- else
- ctrl->leds &= ~((Leds)1 << (led - 1));
-}
-
-int
-Ones(unsigned long mask) /* HACKMEM 169 */
-{
- unsigned long y;
-
- y = (mask >> 1) &033333333333;
- y = mask - y - ((y >>1) & 033333333333);
- return (((y + (y >> 3)) & 030707070707) % 077);
-}
-
-static int
-DoChangeKeyboardControl (ClientPtr client, DeviceIntPtr keybd, XID *vlist,
- BITS32 vmask)
-{
-#define DO_ALL (-1)
- KeybdCtrl ctrl;
- int t;
- int led = DO_ALL;
- int key = DO_ALL;
- BITS32 index2;
- int mask = vmask, i;
- XkbEventCauseRec cause;
-
- ctrl = keybd->kbdfeed->ctrl;
- while (vmask) {
- index2 = (BITS32) lowbit (vmask);
- vmask &= ~index2;
- switch (index2) {
- case KBKeyClickPercent:
- t = (INT8)*vlist;
- vlist++;
- if (t == -1) {
- t = defaultKeyboardControl.click;
- }
- else if (t < 0 || t > 100) {
- client->errorValue = t;
- return BadValue;
- }
- ctrl.click = t;
- break;
- case KBBellPercent:
- t = (INT8)*vlist;
- vlist++;
- if (t == -1) {
- t = defaultKeyboardControl.bell;
- }
- else if (t < 0 || t > 100) {
- client->errorValue = t;
- return BadValue;
- }
- ctrl.bell = t;
- break;
- case KBBellPitch:
- t = (INT16)*vlist;
- vlist++;
- if (t == -1) {
- t = defaultKeyboardControl.bell_pitch;
- }
- else if (t < 0) {
- client->errorValue = t;
- return BadValue;
- }
- ctrl.bell_pitch = t;
- break;
- case KBBellDuration:
- t = (INT16)*vlist;
- vlist++;
- if (t == -1)
- t = defaultKeyboardControl.bell_duration;
- else if (t < 0) {
- client->errorValue = t;
- return BadValue;
- }
- ctrl.bell_duration = t;
- break;
- case KBLed:
- led = (CARD8)*vlist;
- vlist++;
- if (led < 1 || led > 32) {
- client->errorValue = led;
- return BadValue;
- }
- if (!(mask & KBLedMode))
- return BadMatch;
- break;
- case KBLedMode:
- t = (CARD8)*vlist;
- vlist++;
- if (t == LedModeOff) {
- if (led == DO_ALL)
- ctrl.leds = 0x0;
- else
- ctrl.leds &= ~(((Leds)(1)) << (led - 1));
- }
- else if (t == LedModeOn) {
- if (led == DO_ALL)
- ctrl.leds = ~0L;
- else
- ctrl.leds |= (((Leds)(1)) << (led - 1));
- }
- else {
- client->errorValue = t;
- return BadValue;
- }
-
- XkbSetCauseCoreReq(&cause,X_ChangeKeyboardControl,client);
- XkbSetIndicators(keybd,((led == DO_ALL) ? ~0L : (1L<<(led-1))),
- ctrl.leds, &cause);
- ctrl.leds = keybd->kbdfeed->ctrl.leds;
-
- break;
- case KBKey:
- key = (KeyCode)*vlist;
- vlist++;
- if ((KeyCode)key < keybd->key->xkbInfo->desc->min_key_code ||
- (KeyCode)key > keybd->key->xkbInfo->desc->max_key_code) {
- client->errorValue = key;
- return BadValue;
- }
- if (!(mask & KBAutoRepeatMode))
- return BadMatch;
- break;
- case KBAutoRepeatMode:
- i = (key >> 3);
- mask = (1 << (key & 7));
- t = (CARD8)*vlist;
- vlist++;
- if (key != DO_ALL)
- XkbDisableComputedAutoRepeats(keybd,key);
- if (t == AutoRepeatModeOff) {
- if (key == DO_ALL)
- ctrl.autoRepeat = FALSE;
- else
- ctrl.autoRepeats[i] &= ~mask;
- }
- else if (t == AutoRepeatModeOn) {
- if (key == DO_ALL)
- ctrl.autoRepeat = TRUE;
- else
- ctrl.autoRepeats[i] |= mask;
- }
- else if (t == AutoRepeatModeDefault) {
- if (key == DO_ALL)
- ctrl.autoRepeat = defaultKeyboardControl.autoRepeat;
- else
- ctrl.autoRepeats[i] =
- (ctrl.autoRepeats[i] & ~mask) |
- (defaultKeyboardControl.autoRepeats[i] & mask);
- }
- else {
- client->errorValue = t;
- return BadValue;
- }
- break;
- default:
- client->errorValue = mask;
- return BadValue;
- }
- }
- keybd->kbdfeed->ctrl = ctrl;
-
- /* The XKB RepeatKeys control and core protocol global autorepeat */
- /* value are linked */
- XkbSetRepeatKeys(keybd, key, keybd->kbdfeed->ctrl.autoRepeat);
-
- return Success;
-
-#undef DO_ALL
-}
-
-/**
- * Changes kbd control on the ClientPointer and all attached SDs.
- */
-int
-ProcChangeKeyboardControl (ClientPtr client)
-{
- XID *vlist;
- BITS32 vmask;
- int ret = Success, error = Success;
- DeviceIntPtr pDev = NULL, keyboard;
- REQUEST(xChangeKeyboardControlReq);
-
- REQUEST_AT_LEAST_SIZE(xChangeKeyboardControlReq);
-
- vmask = stuff->mask;
- vlist = (XID *)&stuff[1];
-
- if (client->req_len != (sizeof(xChangeKeyboardControlReq)>>2)+Ones(vmask))
- return BadLength;
-
- keyboard = PickKeyboard(client);
-
- for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
- if ((pDev == keyboard ||
- (!IsMaster(pDev) && GetMaster(pDev, MASTER_KEYBOARD) == keyboard))
- && pDev->kbdfeed && pDev->kbdfeed->CtrlProc) {
- ret = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess);
- if (ret != Success)
- return ret;
- }
- }
-
- for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
- if ((pDev == keyboard ||
- (!IsMaster(pDev) && GetMaster(pDev, MASTER_KEYBOARD) == keyboard))
- && pDev->kbdfeed && pDev->kbdfeed->CtrlProc) {
- ret = DoChangeKeyboardControl(client, pDev, vlist, vmask);
- if (ret != Success)
- error = ret;
- }
- }
-
- return error;
-}
-
-int
-ProcGetKeyboardControl (ClientPtr client)
-{
- int rc, i;
- DeviceIntPtr kbd = PickKeyboard(client);
- KeybdCtrl *ctrl = &kbd->kbdfeed->ctrl;
- xGetKeyboardControlReply rep;
- REQUEST_SIZE_MATCH(xReq);
-
- rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetAttrAccess);
- if (rc != Success)
- return rc;
-
- rep.type = X_Reply;
- rep.length = 5;
- rep.sequenceNumber = client->sequence;
- rep.globalAutoRepeat = ctrl->autoRepeat;
- rep.keyClickPercent = ctrl->click;
- rep.bellPercent = ctrl->bell;
- rep.bellPitch = ctrl->bell_pitch;
- rep.bellDuration = ctrl->bell_duration;
- rep.ledMask = ctrl->leds;
- for (i = 0; i < 32; i++)
- rep.map[i] = ctrl->autoRepeats[i];
- WriteReplyToClient(client, sizeof(xGetKeyboardControlReply), &rep);
- return Success;
-}
-
-int
-ProcBell(ClientPtr client)
-{
- DeviceIntPtr dev, keybd = PickKeyboard(client);
- int base = keybd->kbdfeed->ctrl.bell;
- int newpercent;
- int rc;
- REQUEST(xBellReq);
- REQUEST_SIZE_MATCH(xBellReq);
-
- if (stuff->percent < -100 || stuff->percent > 100) {
- client->errorValue = stuff->percent;
- return BadValue;
- }
-
- newpercent = (base * stuff->percent) / 100;
- if (stuff->percent < 0)
- newpercent = base + newpercent;
- else
- newpercent = base - newpercent + stuff->percent;
-
- for (dev = inputInfo.devices; dev; dev = dev->next) {
- if ((dev == keybd ||
- (!IsMaster(dev) && GetMaster(dev, MASTER_KEYBOARD) == keybd)) &&
- dev->kbdfeed && dev->kbdfeed->BellProc) {
-
- rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixBellAccess);
- if (rc != Success)
- return rc;
- XkbHandleBell(FALSE, FALSE, dev, newpercent,
- &dev->kbdfeed->ctrl, 0, None, NULL, client);
- }
- }
-
- return Success;
-}
-
-int
-ProcChangePointerControl(ClientPtr client)
-{
- DeviceIntPtr dev, mouse = PickPointer(client);
- PtrCtrl ctrl; /* might get BadValue part way through */
- int rc;
- REQUEST(xChangePointerControlReq);
- REQUEST_SIZE_MATCH(xChangePointerControlReq);
-
- ctrl = mouse->ptrfeed->ctrl;
- if ((stuff->doAccel != xTrue) && (stuff->doAccel != xFalse)) {
- client->errorValue = stuff->doAccel;
- return BadValue;
- }
- if ((stuff->doThresh != xTrue) && (stuff->doThresh != xFalse)) {
- client->errorValue = stuff->doThresh;
- return BadValue;
- }
- if (stuff->doAccel) {
- if (stuff->accelNum == -1) {
- ctrl.num = defaultPointerControl.num;
- }
- else if (stuff->accelNum < 0) {
- client->errorValue = stuff->accelNum;
- return BadValue;
- }
- else {
- ctrl.num = stuff->accelNum;
- }
-
- if (stuff->accelDenum == -1) {
- ctrl.den = defaultPointerControl.den;
- }
- else if (stuff->accelDenum <= 0) {
- client->errorValue = stuff->accelDenum;
- return BadValue;
- }
- else {
- ctrl.den = stuff->accelDenum;
- }
- }
- if (stuff->doThresh) {
- if (stuff->threshold == -1) {
- ctrl.threshold = defaultPointerControl.threshold;
- }
- else if (stuff->threshold < 0) {
- client->errorValue = stuff->threshold;
- return BadValue;
- }
- else {
- ctrl.threshold = stuff->threshold;
- }
- }
-
- for (dev = inputInfo.devices; dev; dev = dev->next) {
- if ((dev == mouse ||
- (!IsMaster(dev) && GetMaster(dev, MASTER_POINTER) == mouse)) &&
- dev->ptrfeed) {
- rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess);
- if (rc != Success)
- return rc;
- }
- }
-
- for (dev = inputInfo.devices; dev; dev = dev->next) {
- if ((dev == mouse ||
- (!IsMaster(dev) && GetMaster(dev, MASTER_POINTER) == mouse)) &&
- dev->ptrfeed) {
- dev->ptrfeed->ctrl = ctrl;
- }
- }
-
- return Success;
-}
-
-int
-ProcGetPointerControl(ClientPtr client)
-{
- DeviceIntPtr ptr = PickPointer(client);
- PtrCtrl *ctrl = &ptr->ptrfeed->ctrl;
- xGetPointerControlReply rep;
- int rc;
- REQUEST_SIZE_MATCH(xReq);
-
- rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, DixGetAttrAccess);
- if (rc != Success)
- return rc;
-
- rep.type = X_Reply;
- rep.length = 0;
- rep.sequenceNumber = client->sequence;
- rep.threshold = ctrl->threshold;
- rep.accelNumerator = ctrl->num;
- rep.accelDenominator = ctrl->den;
- WriteReplyToClient(client, sizeof(xGenericReply), &rep);
- return Success;
-}
-
-void
-MaybeStopHint(DeviceIntPtr dev, ClientPtr client)
-{
- GrabPtr grab = dev->deviceGrab.grab;
-
- if ((grab && SameClient(grab, client) &&
- ((grab->eventMask & PointerMotionHintMask) ||
- (grab->ownerEvents &&
- (EventMaskForClient(dev->valuator->motionHintWindow, client) &
- PointerMotionHintMask)))) ||
- (!grab &&
- (EventMaskForClient(dev->valuator->motionHintWindow, client) &
- PointerMotionHintMask)))
- dev->valuator->motionHintWindow = NullWindow;
-}
-
-int
-ProcGetMotionEvents(ClientPtr client)
-{
- WindowPtr pWin;
- xTimecoord * coords = (xTimecoord *) NULL;
- xGetMotionEventsReply rep;
- int i, count, xmin, xmax, ymin, ymax, rc;
- unsigned long nEvents;
- DeviceIntPtr mouse = PickPointer(client);
- TimeStamp start, stop;
- REQUEST(xGetMotionEventsReq);
- REQUEST_SIZE_MATCH(xGetMotionEventsReq);
-
- rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
- if (rc != Success)
- return rc;
- rc = XaceHook(XACE_DEVICE_ACCESS, client, mouse, DixReadAccess);
- if (rc != Success)
- return rc;
-
- if (mouse->valuator->motionHintWindow)
- MaybeStopHint(mouse, client);
- rep.type = X_Reply;
- rep.sequenceNumber = client->sequence;
- nEvents = 0;
- start = ClientTimeToServerTime(stuff->start);
- stop = ClientTimeToServerTime(stuff->stop);
- if ((CompareTimeStamps(start, stop) != LATER) &&
- (CompareTimeStamps(start, currentTime) != LATER) &&
- mouse->valuator->numMotionEvents)
- {
- if (CompareTimeStamps(stop, currentTime) == LATER)
- stop = currentTime;
- count = GetMotionHistory(mouse, &coords, start.milliseconds,
- stop.milliseconds, pWin->drawable.pScreen,
- TRUE);
- xmin = pWin->drawable.x - wBorderWidth (pWin);
- xmax = pWin->drawable.x + (int)pWin->drawable.width +
- wBorderWidth (pWin);
- ymin = pWin->drawable.y - wBorderWidth (pWin);
- ymax = pWin->drawable.y + (int)pWin->drawable.height +
- wBorderWidth (pWin);
- for (i = 0; i < count; i++)
- if ((xmin <= coords[i].x) && (coords[i].x < xmax) &&
- (ymin <= coords[i].y) && (coords[i].y < ymax))
- {
- coords[nEvents].time = coords[i].time;
- coords[nEvents].x = coords[i].x - pWin->drawable.x;
- coords[nEvents].y = coords[i].y - pWin->drawable.y;
- nEvents++;
- }
- }
- rep.length = nEvents * bytes_to_int32(sizeof(xTimecoord));
- rep.nEvents = nEvents;
- WriteReplyToClient(client, sizeof(xGetMotionEventsReply), &rep);
- if (nEvents)
- {
- client->pSwapReplyFunc = (ReplySwapPtr) SwapTimeCoordWrite;
- WriteSwappedDataToClient(client, nEvents * sizeof(xTimecoord),
- (char *)coords);
- }
- free(coords);
- return Success;
-}
-
-int
-ProcQueryKeymap(ClientPtr client)
-{
- xQueryKeymapReply rep;
- int rc, i;
- DeviceIntPtr keybd = PickKeyboard(client);
- CARD8 *down = keybd->key->down;
-
- REQUEST_SIZE_MATCH(xReq);
- rep.type = X_Reply;
- rep.sequenceNumber = client->sequence;
- rep.length = 2;
-
- rc = XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixReadAccess);
- if (rc != Success && rc != BadAccess)
- return rc;
-
- for (i = 0; i<32; i++)
- rep.map[i] = down[i];
-
- if (rc == BadAccess)
- memset(rep.map, 0, 32);
-
- WriteReplyToClient(client, sizeof(xQueryKeymapReply), &rep);
-
- return Success;
-}
-
-
-/**
- * Recalculate the number of buttons for the master device. The number of
- * buttons on the master device is equal to the number of buttons on the
- * slave device with the highest number of buttons.
- */
-static void
-RecalculateMasterButtons(DeviceIntPtr slave)
-{
- DeviceIntPtr dev, master;
- int maxbuttons = 0;
-
- if (!slave->button || IsMaster(slave))
- return;
-
- master = GetMaster(slave, MASTER_POINTER);
- if (!master)
- return;
-
- for (dev = inputInfo.devices; dev; dev = dev->next)
- {
- if (IsMaster(dev) ||
- GetMaster(dev, MASTER_ATTACHED) != master ||
- !dev->button)
- continue;
-
- maxbuttons = max(maxbuttons, dev->button->numButtons);
- }
-
- if (master->button && master->button->numButtons != maxbuttons)
- {
- int i;
- DeviceChangedEvent event;
-
- memset(&event, 0, sizeof(event));
-
- master->button->numButtons = maxbuttons;
-
- event.header = ET_Internal;
- event.type = ET_DeviceChanged;
- event.time = GetTimeInMillis();
- event.deviceid = master->id;
- event.flags = DEVCHANGE_POINTER_EVENT | DEVCHANGE_DEVICE_CHANGE;
- event.buttons.num_buttons = maxbuttons;
- memcpy(&event.buttons.names, master->button->labels, maxbuttons *
- sizeof(Atom));
-
- if (master->valuator)
- {
- event.num_valuators = master->valuator->numAxes;
- for (i = 0; i < event.num_valuators; i++)
- {
- event.valuators[i].min = master->valuator->axes[i].min_value;
- event.valuators[i].max = master->valuator->axes[i].max_value;
- event.valuators[i].resolution = master->valuator->axes[i].resolution;
- event.valuators[i].mode = master->valuator->axes[i].mode;
- event.valuators[i].name = master->valuator->axes[i].label;
- }
- }
-
- if (master->key)
- {
- event.keys.min_keycode = master->key->xkbInfo->desc->min_key_code;
- event.keys.max_keycode = master->key->xkbInfo->desc->max_key_code;
- }
-
- XISendDeviceChangedEvent(master, master, &event);
- }
-}
-
-/**
- * Generate release events for all keys/button currently down on this
- * device.
- */
-static void
-ReleaseButtonsAndKeys(DeviceIntPtr dev)
-{
- EventListPtr eventlist = InitEventList(GetMaximumEventsNum());
- ButtonClassPtr b = dev->button;
- KeyClassPtr k = dev->key;
- int i, j, nevents;
-
- if (!eventlist) /* no release events for you */
- return;
-
- /* Release all buttons */
- for (i = 0; b && i < b->numButtons; i++)
- {
- if (BitIsOn(b->down, i))
- {
- nevents = GetPointerEvents(eventlist, dev, ButtonRelease, i, 0, NULL);
- for (j = 0; j < nevents; j++)
- mieqProcessDeviceEvent(dev, (InternalEvent*)(eventlist+j)->event, NULL);
- }
- }
-
- /* Release all keys */
- for (i = 0; k && i < MAP_LENGTH; i++)
- {
- if (BitIsOn(k->down, i))
- {
- nevents = GetKeyboardEvents(eventlist, dev, KeyRelease, i);
- for (j = 0; j < nevents; j++)
- mieqProcessDeviceEvent(dev, (InternalEvent*)(eventlist+j)->event, NULL);
- }
- }
-
- FreeEventList(eventlist, GetMaximumEventsNum());
-}
-
-/**
- * Attach device 'dev' to device 'master'.
- * Client is set to the client that issued the request, or NULL if it comes
- * from some internal automatic pairing.
- *
- * Master may be NULL to set the device floating.
- *
- * We don't allow multi-layer hierarchies right now. You can't attach a slave
- * to another slave.
- */
-int
-AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master)
-{
- ScreenPtr screen;
- DeviceIntPtr oldmaster;
- if (!dev || IsMaster(dev))
- return BadDevice;
-
- if (master && !IsMaster(master)) /* can't attach to slaves */
- return BadDevice;
-
- /* set from floating to floating? */
- if (IsFloating(dev) && !master && dev->enabled)
- return Success;
-
- /* free the existing sprite. */
- if (IsFloating(dev) && dev->spriteInfo->paired == dev)
- {
- screen = miPointerGetScreen(dev);
- screen->DeviceCursorCleanup(dev, screen);
- free(dev->spriteInfo->sprite);
- }
-
- ReleaseButtonsAndKeys(dev);
-
- oldmaster = GetMaster(dev, MASTER_ATTACHED);
- dev->master = master;
-
- /* If device is set to floating, we need to create a sprite for it,
- * otherwise things go bad. However, we don't want to render the cursor,
- * so we reset spriteOwner.
- * Sprite has to be forced to NULL first, otherwise InitializeSprite won't
- * alloc new memory but overwrite the previous one.
- */
- if (!master)
- {
- WindowPtr currentRoot;
-
- if (dev->spriteInfo->sprite)
- currentRoot = GetCurrentRootWindow(dev);
- else /* new device auto-set to floating */
- currentRoot = screenInfo.screens[0]->root;
-
- /* we need to init a fake sprite */
- screen = currentRoot->drawable.pScreen;
- screen->DeviceCursorInitialize(dev, screen);
- dev->spriteInfo->sprite = NULL;
- InitializeSprite(dev, currentRoot);
- dev->spriteInfo->spriteOwner = FALSE;
- dev->spriteInfo->paired = dev;
- } else
- {
- dev->spriteInfo->sprite = master->spriteInfo->sprite;
- dev->spriteInfo->paired = master;
- dev->spriteInfo->spriteOwner = FALSE;
-
- RecalculateMasterButtons(master);
- }
-
- /* XXX: in theory, the MD should change back to its old, original
- * classes when the last SD is detached. Thanks to the XTEST devices,
- * we'll always have an SD attached until the MD is removed.
- * So let's not worry about that.
- */
-
- return Success;
-}
-
-/**
- * Return the device paired with the given device or NULL.
- * Returns the device paired with the parent master if the given device is a
- * slave device.
- */
-DeviceIntPtr
-GetPairedDevice(DeviceIntPtr dev)
-{
- if (!IsMaster(dev) && !IsFloating(dev))
- dev = GetMaster(dev, MASTER_ATTACHED);
-
- return dev->spriteInfo->paired;
-}
-
-
-/**
- * Returns the right master for the type of event needed. If the event is a
- * keyboard event.
- * This function may be called with a master device as argument. If so, the
- * returned master is either the device itself or the paired master device.
- * If dev is a floating slave device, NULL is returned.
- *
- * @type ::MASTER_KEYBOARD or ::MASTER_POINTER or ::MASTER_ATTACHED
- * @return The requested master device. In the case of MASTER_ATTACHED, this
- * is the directly attached master to this device, regardless of the type.
- * Otherwise, it is either the master keyboard or pointer for this device.
- */
-DeviceIntPtr
-GetMaster(DeviceIntPtr dev, int which)
-{
- DeviceIntPtr master;
-
- if (IsMaster(dev))
- master = dev;
- else
- master = dev->master;
-
- if (master && which != MASTER_ATTACHED)
- {
- if (which == MASTER_KEYBOARD)
- {
- if (master->type != MASTER_KEYBOARD)
- master = GetPairedDevice(master);
- } else
- {
- if (master->type != MASTER_POINTER)
- master = GetPairedDevice(master);
- }
- }
-
- return master;
-}
-
-/**
- * Create a new device pair (== one pointer, one keyboard device).
- * Only allocates the devices, you will need to call ActivateDevice() and
- * EnableDevice() manually.
- * Either a master or a slave device can be created depending on
- * the value for master.
- */
-int
-AllocDevicePair (ClientPtr client, char* name,
- DeviceIntPtr* ptr,
- DeviceIntPtr* keybd,
- DeviceProc ptr_proc,
- DeviceProc keybd_proc,
- Bool master)
-{
- DeviceIntPtr pointer;
- DeviceIntPtr keyboard;
- *ptr = *keybd = NULL;
-
- pointer = AddInputDevice(client, ptr_proc, TRUE);
- if (!pointer)
- return BadAlloc;
-
- if (asprintf(&pointer->name, "%s pointer", name) == -1) {
- pointer->name = NULL;
- RemoveDevice(pointer, FALSE);
- return BadAlloc;
- }
-
- pointer->public.processInputProc = ProcessOtherEvent;
- pointer->public.realInputProc = ProcessOtherEvent;
- XkbSetExtension(pointer, ProcessPointerEvent);
- pointer->deviceGrab.ActivateGrab = ActivatePointerGrab;
- pointer->deviceGrab.DeactivateGrab = DeactivatePointerGrab;
- pointer->coreEvents = TRUE;
- pointer->spriteInfo->spriteOwner = TRUE;
-
- pointer->lastSlave = NULL;
- pointer->last.slave = NULL;
- pointer->type = (master) ? MASTER_POINTER : SLAVE;
-
- keyboard = AddInputDevice(client, keybd_proc, TRUE);
- if (!keyboard)
- {
- RemoveDevice(pointer, FALSE);
- return BadAlloc;
- }
-
- if (asprintf(&keyboard->name, "%s keyboard", name) == -1) {
- keyboard->name = NULL;
- RemoveDevice(keyboard, FALSE);
- RemoveDevice(pointer, FALSE);
- return BadAlloc;
- }
-
- keyboard->public.processInputProc = ProcessOtherEvent;
- keyboard->public.realInputProc = ProcessOtherEvent;
- XkbSetExtension(keyboard, ProcessKeyboardEvent);
- keyboard->deviceGrab.ActivateGrab = ActivateKeyboardGrab;
- keyboard->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab;
- keyboard->coreEvents = TRUE;
- keyboard->spriteInfo->spriteOwner = FALSE;
-
- keyboard->lastSlave = NULL;
- keyboard->last.slave = NULL;
- keyboard->type = (master) ? MASTER_KEYBOARD : SLAVE;
-
- /* The ClassesRec stores the device classes currently not used. */
- pointer->unused_classes = calloc(1, sizeof(ClassesRec));
- keyboard->unused_classes = calloc(1, sizeof(ClassesRec));
-
- *ptr = pointer;
- *keybd = keyboard;
-
- return Success;
-}
-
-/**
- * Return Relative or Absolute for the device.
- */
-int valuator_get_mode(DeviceIntPtr dev, int axis)
-{
- return (dev->valuator->axes[axis].mode & DeviceMode);
-}
-
-/**
- * Set the given mode for the axis. If axis is VALUATOR_MODE_ALL_AXES, then
- * set the mode for all axes.
- */
-void valuator_set_mode(DeviceIntPtr dev, int axis, int mode)
-{
- if (axis != VALUATOR_MODE_ALL_AXES)
- dev->valuator->axes[axis].mode = mode;
- else {
- int i;
- for (i = 0; i < dev->valuator->numAxes; i++)
- dev->valuator->axes[i].mode = mode;
- }
-}
+/************************************************************
+
+Copyright 1987, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice 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
+OPEN GROUP 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.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+********************************************************/
+
+
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include "misc.h"
+#include "resource.h"
+#include <X11/Xproto.h>
+#include <X11/Xatom.h>
+#include "windowstr.h"
+#include "inputstr.h"
+#include "scrnintstr.h"
+#include "cursorstr.h"
+#include "dixstruct.h"
+#include "ptrveloc.h"
+#include "site.h"
+#include "xkbsrv.h"
+#include "privates.h"
+#include "xace.h"
+#include "mi.h"
+
+#include "dispatch.h"
+#include "swaprep.h"
+#include "dixevents.h"
+#include "mipointer.h"
+#include "eventstr.h"
+
+#include <X11/extensions/XI.h>
+#include <X11/extensions/XI2.h>
+#include <X11/extensions/XIproto.h>
+#include <math.h>
+#include <pixman.h>
+#include "exglobals.h"
+#include "exevents.h"
+#include "xiquerydevice.h" /* for SizeDeviceClasses */
+#include "xiproperty.h"
+#include "enterleave.h" /* for EnterWindow() */
+#include "xserver-properties.h"
+#include "xichangehierarchy.h" /* For XISendDeviceHierarchyEvent */
+
+/** @file
+ * This file handles input device-related stuff.
+ */
+
+static void RecalculateMasterButtons(DeviceIntPtr slave);
+
+static void
+DeviceSetTransform(DeviceIntPtr dev, float *transform)
+{
+ struct pixman_f_transform scale;
+ double sx, sy;
+ int x, y;
+
+ /**
+ * calculate combined transformation matrix:
+ *
+ * M = InvScale * Transform * Scale
+ *
+ * So we can later transform points using M * p
+ *
+ * Where:
+ * Scale scales coordinates into 0..1 range
+ * Transform is the user supplied (affine) transform
+ * InvScale scales coordinates back up into their native range
+ */
+ sx = dev->valuator->axes[0].max_value - dev->valuator->axes[0].min_value;
+ sy = dev->valuator->axes[1].max_value - dev->valuator->axes[1].min_value;
+
+ /* invscale */
+ pixman_f_transform_init_scale(&scale, sx, sy);
+ scale.m[0][2] = dev->valuator->axes[0].min_value;
+ scale.m[1][2] = dev->valuator->axes[1].min_value;
+
+ /* transform */
+ for (y=0; y<3; y++)
+ for (x=0; x<3; x++)
+ dev->transform.m[y][x] = *transform++;
+
+ pixman_f_transform_multiply(&dev->transform, &scale, &dev->transform);
+
+ /* scale */
+ pixman_f_transform_init_scale(&scale, 1.0 / sx, 1.0 / sy);
+ scale.m[0][2] = -dev->valuator->axes[0].min_value / sx;
+ scale.m[1][2] = -dev->valuator->axes[1].min_value / sy;
+
+ pixman_f_transform_multiply(&dev->transform, &dev->transform, &scale);
+}
+
+/**
+ * DIX property handler.
+ */
+static int
+DeviceSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
+ BOOL checkonly)
+{
+ if (property == XIGetKnownProperty(XI_PROP_ENABLED))
+ {
+ if (prop->format != 8 || prop->type != XA_INTEGER || prop->size != 1)
+ return BadValue;
+
+ /* Don't allow disabling of VCP/VCK */
+ if ((dev == inputInfo.pointer || dev == inputInfo.keyboard) &&
+ !(*(CARD8*)prop->data))
+ return BadAccess;
+
+ if (!checkonly)
+ {
+ if ((*((CARD8*)prop->data)) && !dev->enabled)
+ EnableDevice(dev, TRUE);
+ else if (!(*((CARD8*)prop->data)) && dev->enabled)
+ DisableDevice(dev, TRUE);
+ }
+ } else if (property == XIGetKnownProperty(XI_PROP_TRANSFORM))
+ {
+ float *f = (float*)prop->data;
+ int i;
+
+ if (prop->format != 32 || prop->size != 9 ||
+ prop->type != XIGetKnownProperty(XATOM_FLOAT))
+ return BadValue;
+
+ for (i=0; i<9; i++)
+ if (!isfinite(f[i]))
+ return BadValue;
+
+ if (!checkonly)
+ DeviceSetTransform(dev, f);
+ }
+
+ return Success;
+}
+
+/* Pair the keyboard to the pointer device. Keyboard events will follow the
+ * pointer sprite. Only applicable for master devices.
+ * If the client is set, the request to pair comes from some client. In this
+ * case, we need to check for access. If the client is NULL, it's from an
+ * internal automatic pairing, we must always permit this.
+ */
+static int
+PairDevices(ClientPtr client, DeviceIntPtr ptr, DeviceIntPtr kbd)
+{
+ if (!ptr)
+ return BadDevice;
+
+ /* Don't allow pairing for slave devices */
+ if (!IsMaster(ptr) || !IsMaster(kbd))
+ return BadDevice;
+
+ if (ptr->spriteInfo->paired)
+ return BadDevice;
+
+ if (kbd->spriteInfo->spriteOwner)
+ {
+ free(kbd->spriteInfo->sprite);
+ kbd->spriteInfo->sprite = NULL;
+ kbd->spriteInfo->spriteOwner = FALSE;
+ }
+
+ kbd->spriteInfo->sprite = ptr->spriteInfo->sprite;
+ kbd->spriteInfo->paired = ptr;
+ ptr->spriteInfo->paired = kbd;
+ return Success;
+}
+
+
+/**
+ * Find and return the next unpaired MD pointer device.
+ */
+static DeviceIntPtr
+NextFreePointerDevice(void)
+{
+ DeviceIntPtr dev;
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ if (IsMaster(dev) &&
+ dev->spriteInfo->spriteOwner &&
+ !dev->spriteInfo->paired)
+ return dev;
+ return NULL;
+}
+
+/**
+ * Create a new input device and init it to sane values. The device is added
+ * to the server's off_devices list.
+ *
+ * @param deviceProc Callback for device control function (switch dev on/off).
+ * @return The newly created device.
+ */
+DeviceIntPtr
+AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart)
+{
+ DeviceIntPtr dev, *prev; /* not a typo */
+ DeviceIntPtr devtmp;
+ int devid;
+ char devind[MAXDEVICES];
+ BOOL enabled;
+ float transform[9];
+
+ /* Find next available id, 0 and 1 are reserved */
+ memset(devind, 0, sizeof(char)*MAXDEVICES);
+ for (devtmp = inputInfo.devices; devtmp; devtmp = devtmp->next)
+ devind[devtmp->id]++;
+ for (devtmp = inputInfo.off_devices; devtmp; devtmp = devtmp->next)
+ devind[devtmp->id]++;
+ for (devid = 2; devid < MAXDEVICES && devind[devid]; devid++)
+ ;
+
+ if (devid >= MAXDEVICES)
+ return (DeviceIntPtr)NULL;
+ dev = _dixAllocateObjectWithPrivates(sizeof(DeviceIntRec) + sizeof(SpriteInfoRec),
+ sizeof(DeviceIntRec) + sizeof(SpriteInfoRec),
+ offsetof(DeviceIntRec, devPrivates), PRIVATE_DEVICE);
+ if (!dev)
+ return (DeviceIntPtr)NULL;
+ dev->id = devid;
+ dev->public.processInputProc = ProcessOtherEvent;
+ dev->public.realInputProc = ProcessOtherEvent;
+ dev->public.enqueueInputProc = EnqueueEvent;
+ dev->deviceProc = deviceProc;
+ dev->startup = autoStart;
+
+ /* device grab defaults */
+ dev->deviceGrab.grabTime = currentTime;
+ dev->deviceGrab.ActivateGrab = ActivateKeyboardGrab;
+ dev->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab;
+
+ XkbSetExtension(dev, ProcessKeyboardEvent);
+
+ dev->coreEvents = TRUE;
+
+ /* sprite defaults */
+ dev->spriteInfo = (SpriteInfoPtr)&dev[1];
+
+ /* security creation/labeling check
+ */
+ if (XaceHook(XACE_DEVICE_ACCESS, client, dev, DixCreateAccess)) {
+ free(dev);
+ return NULL;
+ }
+
+ inputInfo.numDevices++;
+
+ for (prev = &inputInfo.off_devices; *prev; prev = &(*prev)->next)
+ ;
+ *prev = dev;
+ dev->next = NULL;
+
+ enabled = FALSE;
+ XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED),
+ XA_INTEGER, 8, PropModeReplace, 1, &enabled,
+ FALSE);
+ XISetDevicePropertyDeletable(dev, XIGetKnownProperty(XI_PROP_ENABLED), FALSE);
+
+ /* unity matrix */
+ memset(transform, 0, sizeof(transform));
+ transform[0] = transform[4] = transform[8] = 1.0f;
+
+ XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_TRANSFORM),
+ XIGetKnownProperty(XATOM_FLOAT), 32,
+ PropModeReplace, 9, transform, FALSE);
+ XISetDevicePropertyDeletable(dev, XIGetKnownProperty(XI_PROP_TRANSFORM),
+ FALSE);
+
+ XIRegisterPropertyHandler(dev, DeviceSetProperty, NULL, NULL);
+
+ return dev;
+}
+
+void
+SendDevicePresenceEvent(int deviceid, int type)
+{
+ DeviceIntRec dummyDev;
+ devicePresenceNotify ev;
+
+ memset(&dummyDev, 0, sizeof(DeviceIntRec));
+ ev.type = DevicePresenceNotify;
+ ev.time = currentTime.milliseconds;
+ ev.devchange = type;
+ ev.deviceid = deviceid;
+ dummyDev.id = XIAllDevices;
+ SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask,
+ (xEvent*)&ev, 1);
+}
+
+/**
+ * Enable the device through the driver, add the device to the device list.
+ * Switch device ON through the driver and push it onto the global device
+ * list. Initialize the DIX sprite or pair the device. All clients are
+ * notified about the device being enabled.
+ *
+ * A master pointer device needs to be enabled before a master keyboard
+ * device.
+ *
+ * @param The device to be enabled.
+ * @param sendevent True if an XI2 event should be sent.
+ * @return TRUE on success or FALSE otherwise.
+ */
+Bool
+EnableDevice(DeviceIntPtr dev, BOOL sendevent)
+{
+ DeviceIntPtr *prev;
+ int ret;
+ DeviceIntPtr other;
+ BOOL enabled;
+ int flags[MAXDEVICES] = {0};
+
+ for (prev = &inputInfo.off_devices;
+ *prev && (*prev != dev);
+ prev = &(*prev)->next)
+ ;
+
+ if (!dev->spriteInfo->sprite)
+ {
+ if (IsMaster(dev))
+ {
+ /* Sprites appear on first root window, so we can hardcode it */
+ if (dev->spriteInfo->spriteOwner)
+ {
+ InitializeSprite(dev, screenInfo.screens[0]->root);
+ /* mode doesn't matter */
+ EnterWindow(dev, screenInfo.screens[0]->root, NotifyAncestor);
+ }
+ else if ((other = NextFreePointerDevice()) == NULL)
+ {
+ ErrorF("[dix] cannot find pointer to pair with. "
+ "This is a bug.\n");
+ return FALSE;
+ } else
+ PairDevices(NULL, other, dev);
+ } else
+ {
+ if (dev->coreEvents)
+ other = (IsPointerDevice(dev)) ? inputInfo.pointer :
+ inputInfo.keyboard;
+ else
+ other = NULL; /* auto-float non-core devices */
+ AttachDevice(NULL, dev, other);
+ }
+ }
+
+ if ((*prev != dev) || !dev->inited ||
+ ((ret = (*dev->deviceProc)(dev, DEVICE_ON)) != Success)) {
+ ErrorF("[dix] couldn't enable device %d\n", dev->id);
+ return FALSE;
+ }
+ dev->enabled = TRUE;
+ *prev = dev->next;
+
+ for (prev = &inputInfo.devices; *prev; prev = &(*prev)->next)
+ ;
+ *prev = dev;
+ dev->next = NULL;
+
+ enabled = TRUE;
+ XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED),
+ XA_INTEGER, 8, PropModeReplace, 1, &enabled,
+ TRUE);
+
+ SendDevicePresenceEvent(dev->id, DeviceEnabled);
+ if (sendevent)
+ {
+ flags[dev->id] |= XIDeviceEnabled;
+ XISendDeviceHierarchyEvent(flags);
+ }
+
+ RecalculateMasterButtons(dev);
+
+ return TRUE;
+}
+
+/**
+ * Switch a device off through the driver and push it onto the off_devices
+ * list. A device will not send events while disabled. All clients are
+ * notified about the device being disabled.
+ *
+ * Master keyboard devices have to be disabled before master pointer devices
+ * otherwise things turn bad.
+ *
+ * @param sendevent True if an XI2 event should be sent.
+ * @return TRUE on success or FALSE otherwise.
+ */
+Bool
+DisableDevice(DeviceIntPtr dev, BOOL sendevent)
+{
+ DeviceIntPtr *prev, other;
+ BOOL enabled;
+ int flags[MAXDEVICES] = {0};
+
+ for (prev = &inputInfo.devices;
+ *prev && (*prev != dev);
+ prev = &(*prev)->next)
+ ;
+ if (*prev != dev)
+ return FALSE;
+
+ /* float attached devices */
+ if (IsMaster(dev))
+ {
+ for (other = inputInfo.devices; other; other = other->next)
+ {
+ if (!IsMaster(other) && GetMaster(other, MASTER_ATTACHED) == dev)
+ {
+ AttachDevice(NULL, other, NULL);
+ flags[other->id] |= XISlaveDetached;
+ }
+ }
+ }
+ else
+ {
+ for (other = inputInfo.devices; other; other = other->next)
+ {
+ if (IsMaster(other) && other->lastSlave == dev)
+ other->lastSlave = NULL;
+ }
+ }
+
+ if (IsMaster(dev) && dev->spriteInfo->sprite)
+ {
+ for (other = inputInfo.devices; other; other = other->next)
+ {
+ if (other->spriteInfo->paired == dev)
+ {
+ ErrorF("[dix] cannot disable device, still paired. "
+ "This is a bug. \n");
+ return FALSE;
+ }
+ }
+ }
+
+ (void)(*dev->deviceProc)(dev, DEVICE_OFF);
+ dev->enabled = FALSE;
+
+ /* now that the device is disabled, we can reset the signal handler's
+ * last.slave */
+ OsBlockSignals();
+ for (other = inputInfo.devices; other; other = other->next)
+ {
+ if (other->last.slave == dev)
+ other->last.slave = NULL;
+ }
+ OsReleaseSignals();
+
+ LeaveWindow(dev);
+ SetFocusOut(dev);
+
+ *prev = dev->next;
+ dev->next = inputInfo.off_devices;
+ inputInfo.off_devices = dev;
+
+ enabled = FALSE;
+ XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED),
+ XA_INTEGER, 8, PropModeReplace, 1, &enabled,
+ TRUE);
+
+ SendDevicePresenceEvent(dev->id, DeviceDisabled);
+ if (sendevent)
+ {
+ flags[dev->id] = XIDeviceDisabled;
+ XISendDeviceHierarchyEvent(flags);
+ }
+
+ RecalculateMasterButtons(dev);
+
+ return TRUE;
+}
+
+/**
+ * Initialise a new device through the driver and tell all clients about the
+ * new device.
+ *
+ * Must be called before EnableDevice.
+ * The device will NOT send events until it is enabled!
+ *
+ * @param sendevent True if an XI2 event should be sent.
+ * @return Success or an error code on failure.
+ */
+int
+ActivateDevice(DeviceIntPtr dev, BOOL sendevent)
+{
+ int ret = Success;
+ ScreenPtr pScreen = screenInfo.screens[0];
+
+ if (!dev || !dev->deviceProc)
+ return BadImplementation;
+
+ ret = (*dev->deviceProc) (dev, DEVICE_INIT);
+ dev->inited = (ret == Success);
+ if (!dev->inited)
+ return ret;
+
+ /* Initialize memory for sprites. */
+ if (IsMaster(dev) && dev->spriteInfo->spriteOwner)
+ if (!pScreen->DeviceCursorInitialize(dev, pScreen))
+ ret = BadAlloc;
+
+ SendDevicePresenceEvent(dev->id, DeviceAdded);
+ if (sendevent)
+ {
+ int flags[MAXDEVICES] = {0};
+ flags[dev->id] = XISlaveAdded;
+ XISendDeviceHierarchyEvent(flags);
+ }
+ return ret;
+}
+
+/**
+ * Ring the bell.
+ * The actual task of ringing the bell is the job of the DDX.
+ */
+static void
+CoreKeyboardBell(int volume, DeviceIntPtr pDev, pointer arg, int something)
+{
+ KeybdCtrl *ctrl = arg;
+
+ DDXRingBell(volume, ctrl->bell_pitch, ctrl->bell_duration);
+}
+
+static void
+CoreKeyboardCtl(DeviceIntPtr pDev, KeybdCtrl *ctrl)
+{
+ return;
+}
+
+/**
+ * Device control function for the Virtual Core Keyboard.
+ */
+int
+CoreKeyboardProc(DeviceIntPtr pDev, int what)
+{
+
+ switch (what) {
+ case DEVICE_INIT:
+ if (!InitKeyboardDeviceStruct(pDev, NULL, CoreKeyboardBell,
+ CoreKeyboardCtl))
+ {
+ ErrorF("Keyboard initialization failed. This could be a missing "
+ "or incorrect setup of xkeyboard-config.\n");
+ return BadValue;
+ }
+ return Success;
+
+ case DEVICE_ON:
+ case DEVICE_OFF:
+ return Success;
+
+ case DEVICE_CLOSE:
+ return Success;
+ }
+
+ return BadMatch;
+}
+
+/**
+ * Device control function for the Virtual Core Pointer.
+ */
+int
+CorePointerProc(DeviceIntPtr pDev, int what)
+{
+#define NBUTTONS 10
+#define NAXES 2
+ BYTE map[NBUTTONS + 1];
+ int i = 0;
+ Atom btn_labels[NBUTTONS] = {0};
+ Atom axes_labels[NAXES] = {0};
+
+ switch (what) {
+ case DEVICE_INIT:
+ for (i = 1; i <= NBUTTONS; i++)
+ map[i] = i;
+
+ btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
+ btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
+ btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
+ btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
+ btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
+ btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
+ btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
+ /* don't know about the rest */
+
+ axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
+ axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
+
+ if (!InitPointerDeviceStruct((DevicePtr)pDev, map, NBUTTONS, btn_labels,
+ (PtrCtrlProcPtr)NoopDDA,
+ GetMotionHistorySize(), NAXES, axes_labels))
+ {
+ ErrorF("Could not initialize device '%s'. Out of memory.\n",
+ pDev->name);
+ return BadAlloc; /* IPDS only fails on allocs */
+ }
+ pDev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2;
+ pDev->last.valuators[0] = pDev->valuator->axisVal[0];
+ pDev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2;
+ pDev->last.valuators[1] = pDev->valuator->axisVal[1];
+ break;
+
+ case DEVICE_CLOSE:
+ break;
+
+ default:
+ break;
+ }
+
+ return Success;
+
+#undef NBUTTONS
+#undef NAXES
+}
+
+/**
+ * Initialise the two core devices, VCP and VCK (see events.c).
+ * Both devices are not tied to physical devices, but guarantee that there is
+ * always a keyboard and a pointer present and keep the protocol semantics.
+ *
+ * Note that the server MUST have two core devices at all times, even if there
+ * is no physical device connected.
+ */
+void
+InitCoreDevices(void)
+{
+ if (AllocDevicePair(serverClient, "Virtual core",
+ &inputInfo.pointer, &inputInfo.keyboard,
+ CorePointerProc, CoreKeyboardProc,
+ TRUE) != Success)
+ FatalError("Failed to allocate core devices");
+
+ if (ActivateDevice(inputInfo.pointer, TRUE) != Success ||
+ ActivateDevice(inputInfo.keyboard, TRUE) != Success)
+ FatalError("Failed to activate core devices.");
+ if (!EnableDevice(inputInfo.pointer, TRUE) ||
+ !EnableDevice(inputInfo.keyboard, TRUE))
+ FatalError("Failed to enable core devices.");
+
+ InitXTestDevices();
+}
+
+/**
+ * Activate all switched-off devices and then enable all those devices.
+ *
+ * Will return an error if no core keyboard or core pointer is present.
+ * In theory this should never happen if you call InitCoreDevices() first.
+ *
+ * InitAndStartDevices needs to be called AFTER the windows are initialized.
+ * Devices will start sending events after InitAndStartDevices() has
+ * completed.
+ *
+ * @return Success or error code on failure.
+ */
+int
+InitAndStartDevices(void)
+{
+ DeviceIntPtr dev, next;
+
+ for (dev = inputInfo.off_devices; dev; dev = dev->next) {
+ DebugF("(dix) initialising device %d\n", dev->id);
+ if (!dev->inited)
+ ActivateDevice(dev, TRUE);
+ }
+
+ /* enable real devices */
+ for (dev = inputInfo.off_devices; dev; dev = next)
+ {
+ DebugF("(dix) enabling device %d\n", dev->id);
+ next = dev->next;
+ if (dev->inited && dev->startup)
+ EnableDevice(dev, TRUE);
+ }
+
+ return Success;
+}
+
+/**
+ * Free the given device class and reset the pointer to NULL.
+ */
+static void
+FreeDeviceClass(int type, pointer *class)
+{
+ if (!(*class))
+ return;
+
+ switch(type)
+ {
+ case KeyClass:
+ {
+ KeyClassPtr* k = (KeyClassPtr*)class;
+ if ((*k)->xkbInfo)
+ {
+ XkbFreeInfo((*k)->xkbInfo);
+ (*k)->xkbInfo = NULL;
+ }
+ free((*k));
+ break;
+ }
+ case ButtonClass:
+ {
+ ButtonClassPtr *b = (ButtonClassPtr*)class;
+ free((*b)->xkb_acts);
+ free((*b));
+ break;
+ }
+ case ValuatorClass:
+ {
+ ValuatorClassPtr *v = (ValuatorClassPtr*)class;
+
+ free((*v)->motion);
+ free((*v));
+ break;
+ }
+ case FocusClass:
+ {
+ FocusClassPtr *f = (FocusClassPtr*)class;
+ free((*f)->trace);
+ free((*f));
+ break;
+ }
+ case ProximityClass:
+ {
+ ProximityClassPtr *p = (ProximityClassPtr*)class;
+ free((*p));
+ break;
+ }
+ }
+ *class = NULL;
+}
+
+static void
+FreeFeedbackClass(int type, pointer *class)
+{
+ if (!(*class))
+ return;
+
+ switch(type)
+ {
+ case KbdFeedbackClass:
+ {
+ KbdFeedbackPtr *kbdfeed = (KbdFeedbackPtr*)class;
+ KbdFeedbackPtr k, knext;
+ for (k = (*kbdfeed); k; k = knext) {
+ knext = k->next;
+ if (k->xkb_sli)
+ XkbFreeSrvLedInfo(k->xkb_sli);
+ free(k);
+ }
+ break;
+ }
+ case PtrFeedbackClass:
+ {
+ PtrFeedbackPtr *ptrfeed = (PtrFeedbackPtr*)class;
+ PtrFeedbackPtr p, pnext;
+
+ for (p = (*ptrfeed); p; p = pnext) {
+ pnext = p->next;
+ free(p);
+ }
+ break;
+ }
+ case IntegerFeedbackClass:
+ {
+ IntegerFeedbackPtr *intfeed = (IntegerFeedbackPtr*)class;
+ IntegerFeedbackPtr i, inext;
+
+ for (i = (*intfeed); i; i = inext) {
+ inext = i->next;
+ free(i);
+ }
+ break;
+ }
+ case StringFeedbackClass:
+ {
+ StringFeedbackPtr *stringfeed = (StringFeedbackPtr*)class;
+ StringFeedbackPtr s, snext;
+
+ for (s = (*stringfeed); s; s = snext) {
+ snext = s->next;
+ free(s->ctrl.symbols_supported);
+ free(s->ctrl.symbols_displayed);
+ free(s);
+ }
+ break;
+ }
+ case BellFeedbackClass:
+ {
+ BellFeedbackPtr *bell = (BellFeedbackPtr*)class;
+ BellFeedbackPtr b, bnext;
+
+ for (b = (*bell); b; b = bnext) {
+ bnext = b->next;
+ free(b);
+ }
+ break;
+ }
+ case LedFeedbackClass:
+ {
+ LedFeedbackPtr *leds = (LedFeedbackPtr*)class;
+ LedFeedbackPtr l, lnext;
+
+ for (l = (*leds); l; l = lnext) {
+ lnext = l->next;
+ if (l->xkb_sli)
+ XkbFreeSrvLedInfo(l->xkb_sli);
+ free(l);
+ }
+ break;
+ }
+ }
+ *class = NULL;
+}
+
+static void
+FreeAllDeviceClasses(ClassesPtr classes)
+{
+ if (!classes)
+ return;
+
+ FreeDeviceClass(KeyClass, (pointer)&classes->key);
+ FreeDeviceClass(ValuatorClass, (pointer)&classes->valuator);
+ FreeDeviceClass(ButtonClass, (pointer)&classes->button);
+ FreeDeviceClass(FocusClass, (pointer)&classes->focus);
+ FreeDeviceClass(ProximityClass, (pointer)&classes->proximity);
+
+ FreeFeedbackClass(KbdFeedbackClass, (pointer)&classes->kbdfeed);
+ FreeFeedbackClass(PtrFeedbackClass, (pointer)&classes->ptrfeed);
+ FreeFeedbackClass(IntegerFeedbackClass, (pointer)&classes->intfeed);
+ FreeFeedbackClass(StringFeedbackClass, (pointer)&classes->stringfeed);
+ FreeFeedbackClass(BellFeedbackClass, (pointer)&classes->bell);
+ FreeFeedbackClass(LedFeedbackClass, (pointer)&classes->leds);
+
+}
+
+/**
+ * Close down a device and free all resources.
+ * Once closed down, the driver will probably not expect you that you'll ever
+ * enable it again and free associated structs. If you want the device to just
+ * be disabled, DisableDevice().
+ * Don't call this function directly, use RemoveDevice() instead.
+ */
+static void
+CloseDevice(DeviceIntPtr dev)
+{
+ ScreenPtr screen = screenInfo.screens[0];
+ ClassesPtr classes;
+ int j;
+
+ if (!dev)
+ return;
+
+ XIDeleteAllDeviceProperties(dev);
+
+ if (dev->inited)
+ (void)(*dev->deviceProc)(dev, DEVICE_CLOSE);
+
+ /* free sprite memory */
+ if (IsMaster(dev) && dev->spriteInfo->sprite)
+ screen->DeviceCursorCleanup(dev, screen);
+
+ /* free acceleration info */
+ if(dev->valuator && dev->valuator->accelScheme.AccelCleanupProc)
+ dev->valuator->accelScheme.AccelCleanupProc(dev);
+
+ while (dev->xkb_interest)
+ XkbRemoveResourceClient((DevicePtr)dev,dev->xkb_interest->resource);
+
+ free(dev->name);
+
+ classes = (ClassesPtr)&dev->key;
+ FreeAllDeviceClasses(classes);
+
+ if (IsMaster(dev))
+ {
+ classes = dev->unused_classes;
+ FreeAllDeviceClasses(classes);
+ free(classes);
+ }
+
+ if (DevHasCursor(dev) && dev->spriteInfo->sprite) {
+ if (dev->spriteInfo->sprite->current)
+ FreeCursor(dev->spriteInfo->sprite->current, None);
+ free(dev->spriteInfo->sprite->spriteTrace);
+ free(dev->spriteInfo->sprite);
+ }
+
+ /* a client may have the device set as client pointer */
+ for (j = 0; j < currentMaxClients; j++)
+ {
+ if (clients[j] && clients[j]->clientPtr == dev)
+ {
+ clients[j]->clientPtr = NULL;
+ clients[j]->clientPtr = PickPointer(clients[j]);
+ }
+ }
+
+ free(dev->deviceGrab.sync.event);
+ free(dev->config_info); /* Allocated in xf86ActivateDevice. */
+ dev->config_info = NULL;
+ dixFreeObjectWithPrivates(dev, PRIVATE_DEVICE);
+}
+
+/**
+ * Shut down all devices of one list and free all resources.
+ */
+static
+void
+CloseDeviceList(DeviceIntPtr *listHead)
+{
+ /* Used to mark devices that we tried to free */
+ Bool freedIds[MAXDEVICES];
+ DeviceIntPtr dev;
+ int i;
+
+ if (listHead == NULL)
+ return;
+
+ for (i = 0; i < MAXDEVICES; i++)
+ freedIds[i] = FALSE;
+
+ dev = *listHead;
+ while (dev != NULL)
+ {
+ freedIds[dev->id] = TRUE;
+ DeleteInputDeviceRequest(dev);
+
+ dev = *listHead;
+ while (dev != NULL && freedIds[dev->id])
+ dev = dev->next;
+ }
+}
+
+/**
+ * Shut down all devices, free all resources, etc.
+ * Only useful if you're shutting down the server!
+ */
+void
+CloseDownDevices(void)
+{
+ DeviceIntPtr dev;
+
+ /* Float all SDs before closing them. Note that at this point resources
+ * (e.g. cursors) have been freed already, so we can't just call
+ * AttachDevice(NULL, dev, NULL). Instead, we have to forcibly set master
+ * to NULL and pretend nothing happened.
+ */
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ {
+ if (!IsMaster(dev) && !IsFloating(dev))
+ dev->master = NULL;
+ }
+
+ CloseDeviceList(&inputInfo.devices);
+ CloseDeviceList(&inputInfo.off_devices);
+
+ CloseDevice(inputInfo.pointer);
+ CloseDevice(inputInfo.keyboard);
+
+ inputInfo.devices = NULL;
+ inputInfo.off_devices = NULL;
+ inputInfo.keyboard = NULL;
+ inputInfo.pointer = NULL;
+ XkbDeleteRulesDflts();
+}
+
+/**
+ * Remove the cursor sprite for all devices. This needs to be done before any
+ * resources are freed or any device is deleted.
+ */
+void
+UndisplayDevices(void)
+{
+ DeviceIntPtr dev;
+ ScreenPtr screen = screenInfo.screens[0];
+
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ screen->DisplayCursor(dev, screen, NullCursor);
+}
+
+/**
+ * Remove a device from the device list, closes it and thus frees all
+ * resources.
+ * Removes both enabled and disabled devices and notifies all devices about
+ * the removal of the device.
+ *
+ * No PresenceNotify is sent for device that the client never saw. This can
+ * happen if a malloc fails during the addition of master devices. If
+ * dev->init is FALSE it means the client never received a DeviceAdded event,
+ * so let's not send a DeviceRemoved event either.
+ *
+ * @param sendevent True if an XI2 event should be sent.
+ */
+int
+RemoveDevice(DeviceIntPtr dev, BOOL sendevent)
+{
+ DeviceIntPtr prev,tmp,next;
+ int ret = BadMatch;
+ ScreenPtr screen = screenInfo.screens[0];
+ int deviceid;
+ int initialized;
+ int flags[MAXDEVICES] = {0};
+
+ DebugF("(dix) removing device %d\n", dev->id);
+
+ if (!dev || dev == inputInfo.keyboard || dev == inputInfo.pointer)
+ return BadImplementation;
+
+ initialized = dev->inited;
+ deviceid = dev->id;
+
+ if (initialized)
+ {
+ if (DevHasCursor(dev))
+ screen->DisplayCursor(dev, screen, NullCursor);
+
+ DisableDevice(dev, sendevent);
+ flags[dev->id] = XIDeviceDisabled;
+ }
+
+ prev = NULL;
+ for (tmp = inputInfo.devices; tmp; (prev = tmp), (tmp = next)) {
+ next = tmp->next;
+ if (tmp == dev) {
+
+ if (prev==NULL)
+ inputInfo.devices = next;
+ else
+ prev->next = next;
+
+ flags[tmp->id] = IsMaster(tmp) ? XIMasterRemoved : XISlaveRemoved;
+ CloseDevice(tmp);
+ ret = Success;
+ }
+ }
+
+ prev = NULL;
+ for (tmp = inputInfo.off_devices; tmp; (prev = tmp), (tmp = next)) {
+ next = tmp->next;
+ if (tmp == dev) {
+ flags[tmp->id] = IsMaster(tmp) ? XIMasterRemoved : XISlaveRemoved;
+ CloseDevice(tmp);
+
+ if (prev == NULL)
+ inputInfo.off_devices = next;
+ else
+ prev->next = next;
+
+ ret = Success;
+ }
+ }
+
+ if (ret == Success && initialized) {
+ inputInfo.numDevices--;
+ SendDevicePresenceEvent(deviceid, DeviceRemoved);
+ if (sendevent)
+ XISendDeviceHierarchyEvent(flags);
+ }
+
+ return ret;
+}
+
+int
+NumMotionEvents(void)
+{
+ /* only called to fill data in initial connection reply.
+ * VCP is ok here, it is the only fixed device we have. */
+ return inputInfo.pointer->valuator->numMotionEvents;
+}
+
+int
+dixLookupDevice(DeviceIntPtr *pDev, int id, ClientPtr client, Mask access_mode)
+{
+ DeviceIntPtr dev;
+ int rc;
+ *pDev = NULL;
+
+ for (dev=inputInfo.devices; dev; dev=dev->next) {
+ if (dev->id == id)
+ goto found;
+ }
+ for (dev=inputInfo.off_devices; dev; dev=dev->next) {
+ if (dev->id == id)
+ goto found;
+ }
+ return BadDevice;
+
+found:
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode);
+ if (rc == Success)
+ *pDev = dev;
+ return rc;
+}
+
+void
+QueryMinMaxKeyCodes(KeyCode *minCode, KeyCode *maxCode)
+{
+ if (inputInfo.keyboard) {
+ *minCode = inputInfo.keyboard->key->xkbInfo->desc->min_key_code;
+ *maxCode = inputInfo.keyboard->key->xkbInfo->desc->max_key_code;
+ }
+}
+
+/* Notably, this function does not expand the destination's keycode range, or
+ * notify clients. */
+Bool
+SetKeySymsMap(KeySymsPtr dst, KeySymsPtr src)
+{
+ int i, j;
+ KeySym *tmp;
+ int rowDif = src->minKeyCode - dst->minKeyCode;
+
+ /* if keysym map size changes, grow map first */
+ if (src->mapWidth < dst->mapWidth) {
+ for (i = src->minKeyCode; i <= src->maxKeyCode; i++) {
+#define SI(r, c) (((r - src->minKeyCode) * src->mapWidth) + (c))
+#define DI(r, c) (((r - dst->minKeyCode) * dst->mapWidth) + (c))
+ for (j = 0; j < src->mapWidth; j++)
+ dst->map[DI(i, j)] = src->map[SI(i, j)];
+ for (j = src->mapWidth; j < dst->mapWidth; j++)
+ dst->map[DI(i, j)] = NoSymbol;
+#undef SI
+#undef DI
+ }
+ return TRUE;
+ }
+ else if (src->mapWidth > dst->mapWidth) {
+ i = sizeof(KeySym) * src->mapWidth *
+ (dst->maxKeyCode - dst->minKeyCode + 1);
+ tmp = calloc(sizeof(KeySym), i);
+ if (!tmp)
+ return FALSE;
+
+ if (dst->map) {
+ for (i = 0; i <= dst->maxKeyCode-dst->minKeyCode; i++)
+ memmove(&tmp[i * src->mapWidth], &dst->map[i * dst->mapWidth],
+ dst->mapWidth * sizeof(KeySym));
+ free(dst->map);
+ }
+ dst->mapWidth = src->mapWidth;
+ dst->map = tmp;
+ }
+ else if (!dst->map) {
+ i = sizeof(KeySym) * src->mapWidth *
+ (dst->maxKeyCode - dst->minKeyCode + 1);
+ tmp = calloc(sizeof(KeySym), i);
+ if (!tmp)
+ return FALSE;
+
+ dst->map = tmp;
+ dst->mapWidth = src->mapWidth;
+ }
+
+ memmove(&dst->map[rowDif * dst->mapWidth], src->map,
+ (src->maxKeyCode - src->minKeyCode + 1) *
+ dst->mapWidth * sizeof(KeySym));
+
+ return TRUE;
+}
+
+Bool
+InitButtonClassDeviceStruct(DeviceIntPtr dev, int numButtons, Atom* labels,
+ CARD8 *map)
+{
+ ButtonClassPtr butc;
+ int i;
+
+ butc = calloc(1, sizeof(ButtonClassRec));
+ if (!butc)
+ return FALSE;
+ butc->numButtons = numButtons;
+ butc->sourceid = dev->id;
+ for (i = 1; i <= numButtons; i++)
+ butc->map[i] = map[i];
+ for (i = numButtons + 1; i < MAP_LENGTH; i++)
+ butc->map[i] = i;
+ memcpy(butc->labels, labels, numButtons * sizeof(Atom));
+ dev->button = butc;
+ return TRUE;
+}
+
+Bool
+InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, Atom *labels,
+ int numMotionEvents, int mode)
+{
+ int i;
+ ValuatorClassPtr valc;
+ union align_u { ValuatorClassRec valc; double d; } *align;
+
+ if (!dev)
+ return FALSE;
+
+ if (numAxes > MAX_VALUATORS)
+ {
+ LogMessage(X_WARNING,
+ "Device '%s' has %d axes, only using first %d.\n",
+ dev->name, numAxes, MAX_VALUATORS);
+ numAxes = MAX_VALUATORS;
+ }
+
+ align = (union align_u *) calloc(1, sizeof(union align_u) +
+ numAxes * sizeof(double) +
+ numAxes * sizeof(AxisInfo));
+ if (!align)
+ return FALSE;
+
+ valc = &align->valc;
+ valc->sourceid = dev->id;
+ valc->motion = NULL;
+ valc->first_motion = 0;
+ valc->last_motion = 0;
+
+ valc->numMotionEvents = numMotionEvents;
+ valc->motionHintWindow = NullWindow;
+ valc->numAxes = numAxes;
+ valc->axisVal = (double *)(align + 1);
+ valc->axes = (AxisInfoPtr)(valc->axisVal + numAxes);
+
+ if (mode & OutOfProximity)
+ InitProximityClassDeviceStruct(dev);
+
+ dev->valuator = valc;
+
+ AllocateMotionHistory(dev);
+
+ for (i=0; i<numAxes; i++) {
+ InitValuatorAxisStruct(dev, i, labels[i], NO_AXIS_LIMITS, NO_AXIS_LIMITS,
+ 0, 0, 0, mode);
+ valc->axisVal[i]=0;
+ }
+
+ dev->last.numValuators = numAxes;
+
+ if (IsMaster(dev) || /* do not accelerate master or xtest devices */
+ IsXTestDevice(dev, NULL))
+ InitPointerAccelerationScheme(dev, PtrAccelNoOp);
+ else
+ InitPointerAccelerationScheme(dev, PtrAccelDefault);
+ return TRUE;
+}
+
+/* global list of acceleration schemes */
+ValuatorAccelerationRec pointerAccelerationScheme[] = {
+ {PtrAccelNoOp, NULL, NULL, NULL, NULL},
+ {PtrAccelPredictable, acceleratePointerPredictable, NULL,
+ InitPredictableAccelerationScheme, AccelerationDefaultCleanup},
+ {PtrAccelLightweight, acceleratePointerLightweight, NULL, NULL, NULL},
+ {-1, NULL, NULL, NULL, NULL} /* terminator */
+};
+
+/**
+ * install an acceleration scheme. returns TRUE on success, and should not
+ * change anything if unsuccessful.
+ */
+Bool
+InitPointerAccelerationScheme(DeviceIntPtr dev,
+ int scheme)
+{
+ int x, i = -1;
+ ValuatorClassPtr val;
+
+ val = dev->valuator;
+
+ if (!val)
+ return FALSE;
+
+ if (IsMaster(dev) && scheme != PtrAccelNoOp)
+ return FALSE;
+
+ for (x = 0; pointerAccelerationScheme[x].number >= 0; x++) {
+ if(pointerAccelerationScheme[x].number == scheme){
+ i = x;
+ break;
+ }
+ }
+
+ if (-1 == i)
+ return FALSE;
+
+ if (val->accelScheme.AccelCleanupProc)
+ val->accelScheme.AccelCleanupProc(dev);
+
+ if (pointerAccelerationScheme[i].AccelInitProc) {
+ if (!pointerAccelerationScheme[i].AccelInitProc(dev,
+ &pointerAccelerationScheme[i])) {
+ return FALSE;
+ }
+ } else {
+ val->accelScheme = pointerAccelerationScheme[i];
+ }
+ return TRUE;
+}
+
+Bool
+InitAbsoluteClassDeviceStruct(DeviceIntPtr dev)
+{
+ AbsoluteClassPtr abs;
+
+ abs = malloc(sizeof(AbsoluteClassRec));
+ if (!abs)
+ return FALSE;
+
+ /* we don't do anything sensible with these, but should */
+ abs->min_x = NO_AXIS_LIMITS;
+ abs->min_y = NO_AXIS_LIMITS;
+ abs->max_x = NO_AXIS_LIMITS;
+ abs->max_y = NO_AXIS_LIMITS;
+ abs->flip_x = 0;
+ abs->flip_y = 0;
+ abs->rotation = 0;
+ abs->button_threshold = 0;
+
+ abs->offset_x = 0;
+ abs->offset_y = 0;
+ abs->width = NO_AXIS_LIMITS;
+ abs->height = NO_AXIS_LIMITS;
+ abs->following = 0;
+ abs->screen = 0;
+
+ abs->sourceid = dev->id;
+
+ dev->absolute = abs;
+
+ return TRUE;
+}
+
+Bool
+InitFocusClassDeviceStruct(DeviceIntPtr dev)
+{
+ FocusClassPtr focc;
+
+ focc = malloc(sizeof(FocusClassRec));
+ if (!focc)
+ return FALSE;
+ focc->win = PointerRootWin;
+ focc->revert = None;
+ focc->time = currentTime;
+ focc->trace = (WindowPtr *)NULL;
+ focc->traceSize = 0;
+ focc->traceGood = 0;
+ focc->sourceid = dev->id;
+ dev->focus = focc;
+ return TRUE;
+}
+
+Bool
+InitPtrFeedbackClassDeviceStruct(DeviceIntPtr dev, PtrCtrlProcPtr controlProc)
+{
+ PtrFeedbackPtr feedc;
+
+ feedc = malloc(sizeof(PtrFeedbackClassRec));
+ if (!feedc)
+ return FALSE;
+ feedc->CtrlProc = controlProc;
+ feedc->ctrl = defaultPointerControl;
+ feedc->ctrl.id = 0;
+ if ( (feedc->next = dev->ptrfeed) )
+ feedc->ctrl.id = dev->ptrfeed->ctrl.id + 1;
+ dev->ptrfeed = feedc;
+ (*controlProc)(dev, &feedc->ctrl);
+ return TRUE;
+}
+
+
+static LedCtrl defaultLedControl = {
+ DEFAULT_LEDS, DEFAULT_LEDS_MASK, 0};
+
+static BellCtrl defaultBellControl = {
+ DEFAULT_BELL,
+ DEFAULT_BELL_PITCH,
+ DEFAULT_BELL_DURATION,
+ 0};
+
+static IntegerCtrl defaultIntegerControl = {
+ DEFAULT_INT_RESOLUTION,
+ DEFAULT_INT_MIN_VALUE,
+ DEFAULT_INT_MAX_VALUE,
+ DEFAULT_INT_DISPLAYED,
+ 0};
+
+Bool
+InitStringFeedbackClassDeviceStruct (
+ DeviceIntPtr dev, StringCtrlProcPtr controlProc,
+ int max_symbols, int num_symbols_supported, KeySym *symbols)
+{
+ int i;
+ StringFeedbackPtr feedc;
+
+ feedc = malloc(sizeof(StringFeedbackClassRec));
+ if (!feedc)
+ return FALSE;
+ feedc->CtrlProc = controlProc;
+ feedc->ctrl.num_symbols_supported = num_symbols_supported;
+ feedc->ctrl.num_symbols_displayed = 0;
+ feedc->ctrl.max_symbols = max_symbols;
+ feedc->ctrl.symbols_supported = malloc(sizeof (KeySym) * num_symbols_supported);
+ feedc->ctrl.symbols_displayed = malloc(sizeof (KeySym) * max_symbols);
+ if (!feedc->ctrl.symbols_supported || !feedc->ctrl.symbols_displayed)
+ {
+ free(feedc->ctrl.symbols_supported);
+ free(feedc->ctrl.symbols_displayed);
+ free(feedc);
+ return FALSE;
+ }
+ for (i=0; i<num_symbols_supported; i++)
+ *(feedc->ctrl.symbols_supported+i) = *symbols++;
+ for (i=0; i<max_symbols; i++)
+ *(feedc->ctrl.symbols_displayed+i) = (KeySym) 0;
+ feedc->ctrl.id = 0;
+ if ( (feedc->next = dev->stringfeed) )
+ feedc->ctrl.id = dev->stringfeed->ctrl.id + 1;
+ dev->stringfeed = feedc;
+ (*controlProc)(dev, &feedc->ctrl);
+ return TRUE;
+}
+
+Bool
+InitBellFeedbackClassDeviceStruct (DeviceIntPtr dev, BellProcPtr bellProc,
+ BellCtrlProcPtr controlProc)
+{
+ BellFeedbackPtr feedc;
+
+ feedc = malloc(sizeof(BellFeedbackClassRec));
+ if (!feedc)
+ return FALSE;
+ feedc->CtrlProc = controlProc;
+ feedc->BellProc = bellProc;
+ feedc->ctrl = defaultBellControl;
+ feedc->ctrl.id = 0;
+ if ( (feedc->next = dev->bell) )
+ feedc->ctrl.id = dev->bell->ctrl.id + 1;
+ dev->bell = feedc;
+ (*controlProc)(dev, &feedc->ctrl);
+ return TRUE;
+}
+
+Bool
+InitLedFeedbackClassDeviceStruct (DeviceIntPtr dev, LedCtrlProcPtr controlProc)
+{
+ LedFeedbackPtr feedc;
+
+ feedc = malloc(sizeof(LedFeedbackClassRec));
+ if (!feedc)
+ return FALSE;
+ feedc->CtrlProc = controlProc;
+ feedc->ctrl = defaultLedControl;
+ feedc->ctrl.id = 0;
+ if ( (feedc->next = dev->leds) )
+ feedc->ctrl.id = dev->leds->ctrl.id + 1;
+ feedc->xkb_sli= NULL;
+ dev->leds = feedc;
+ (*controlProc)(dev, &feedc->ctrl);
+ return TRUE;
+}
+
+Bool
+InitIntegerFeedbackClassDeviceStruct (DeviceIntPtr dev, IntegerCtrlProcPtr controlProc)
+{
+ IntegerFeedbackPtr feedc;
+
+ feedc = malloc(sizeof(IntegerFeedbackClassRec));
+ if (!feedc)
+ return FALSE;
+ feedc->CtrlProc = controlProc;
+ feedc->ctrl = defaultIntegerControl;
+ feedc->ctrl.id = 0;
+ if ( (feedc->next = dev->intfeed) )
+ feedc->ctrl.id = dev->intfeed->ctrl.id + 1;
+ dev->intfeed = feedc;
+ (*controlProc)(dev, &feedc->ctrl);
+ return TRUE;
+}
+
+Bool
+InitPointerDeviceStruct(DevicePtr device, CARD8 *map, int numButtons, Atom* btn_labels,
+ PtrCtrlProcPtr controlProc, int numMotionEvents,
+ int numAxes, Atom *axes_labels)
+{
+ DeviceIntPtr dev = (DeviceIntPtr)device;
+
+ return(InitButtonClassDeviceStruct(dev, numButtons, btn_labels, map) &&
+ InitValuatorClassDeviceStruct(dev, numAxes, axes_labels,
+ numMotionEvents, Relative) &&
+ InitPtrFeedbackClassDeviceStruct(dev, controlProc));
+}
+
+/*
+ * Check if the given buffer contains elements between low (inclusive) and
+ * high (inclusive) only.
+ *
+ * @return TRUE if the device map is invalid, FALSE otherwise.
+ */
+Bool
+BadDeviceMap(BYTE *buff, int length, unsigned low, unsigned high, XID *errval)
+{
+ int i;
+
+ for (i = 0; i < length; i++)
+ if (buff[i]) /* only check non-zero elements */
+ {
+ if ((low > buff[i]) || (high < buff[i]))
+ {
+ *errval = buff[i];
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+int
+ProcSetModifierMapping(ClientPtr client)
+{
+ xSetModifierMappingReply rep;
+ int rc;
+ REQUEST(xSetModifierMappingReq);
+ REQUEST_AT_LEAST_SIZE(xSetModifierMappingReq);
+
+ if (client->req_len != ((stuff->numKeyPerModifier << 1) +
+ bytes_to_int32(sizeof(xSetModifierMappingReq))))
+ return BadLength;
+
+ rep.type = X_Reply;
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+
+ rc = change_modmap(client, PickKeyboard(client), (KeyCode *)&stuff[1],
+ stuff->numKeyPerModifier);
+ if (rc == MappingFailed || rc == -1)
+ return BadValue;
+ if (rc != Success && rc != MappingSuccess && rc != MappingFailed &&
+ rc != MappingBusy)
+ return rc;
+
+ rep.success = rc;
+
+ WriteReplyToClient(client, sizeof(xSetModifierMappingReply), &rep);
+ return Success;
+}
+
+int
+ProcGetModifierMapping(ClientPtr client)
+{
+ xGetModifierMappingReply rep;
+ int max_keys_per_mod = 0;
+ KeyCode *modkeymap = NULL;
+ REQUEST_SIZE_MATCH(xReq);
+
+ generate_modkeymap(client, PickKeyboard(client), &modkeymap,
+ &max_keys_per_mod);
+
+ memset(&rep, 0, sizeof(xGetModifierMappingReply));
+ rep.type = X_Reply;
+ rep.numKeyPerModifier = max_keys_per_mod;
+ rep.sequenceNumber = client->sequence;
+ /* length counts 4 byte quantities - there are 8 modifiers 1 byte big */
+ rep.length = max_keys_per_mod << 1;
+
+ WriteReplyToClient(client, sizeof(xGetModifierMappingReply), &rep);
+ (void)WriteToClient(client, max_keys_per_mod * 8, (char *) modkeymap);
+
+ free(modkeymap);
+
+ return Success;
+}
+
+int
+ProcChangeKeyboardMapping(ClientPtr client)
+{
+ REQUEST(xChangeKeyboardMappingReq);
+ unsigned len;
+ KeySymsRec keysyms;
+ DeviceIntPtr pDev, tmp;
+ int rc;
+ REQUEST_AT_LEAST_SIZE(xChangeKeyboardMappingReq);
+
+ len = client->req_len - bytes_to_int32(sizeof(xChangeKeyboardMappingReq));
+ if (len != (stuff->keyCodes * stuff->keySymsPerKeyCode))
+ return BadLength;
+
+ pDev = PickKeyboard(client);
+
+ if ((stuff->firstKeyCode < pDev->key->xkbInfo->desc->min_key_code) ||
+ (stuff->firstKeyCode > pDev->key->xkbInfo->desc->max_key_code)) {
+ client->errorValue = stuff->firstKeyCode;
+ return BadValue;
+
+ }
+ if (((unsigned)(stuff->firstKeyCode + stuff->keyCodes - 1) >
+ pDev->key->xkbInfo->desc->max_key_code) ||
+ (stuff->keySymsPerKeyCode == 0)) {
+ client->errorValue = stuff->keySymsPerKeyCode;
+ return BadValue;
+ }
+
+ keysyms.minKeyCode = stuff->firstKeyCode;
+ keysyms.maxKeyCode = stuff->firstKeyCode + stuff->keyCodes - 1;
+ keysyms.mapWidth = stuff->keySymsPerKeyCode;
+ keysyms.map = (KeySym *) &stuff[1];
+
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess);
+ if (rc != Success)
+ return rc;
+
+ XkbApplyMappingChange(pDev, &keysyms, stuff->firstKeyCode,
+ stuff->keyCodes, NULL, client);
+
+ for (tmp = inputInfo.devices; tmp; tmp = tmp->next) {
+ if (IsMaster(tmp) || GetMaster(tmp, MASTER_KEYBOARD) != pDev)
+ continue;
+ if (!tmp->key)
+ continue;
+
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess);
+ if (rc != Success)
+ continue;
+
+ XkbApplyMappingChange(tmp, &keysyms, stuff->firstKeyCode,
+ stuff->keyCodes, NULL, client);
+ }
+
+ return Success;
+}
+
+int
+ProcSetPointerMapping(ClientPtr client)
+{
+ BYTE *map;
+ int ret;
+ int i, j;
+ DeviceIntPtr ptr = PickPointer(client);
+ xSetPointerMappingReply rep;
+ REQUEST(xSetPointerMappingReq);
+ REQUEST_AT_LEAST_SIZE(xSetPointerMappingReq);
+
+ if (client->req_len !=
+ bytes_to_int32(sizeof(xSetPointerMappingReq) + stuff->nElts))
+ return BadLength;
+ rep.type = X_Reply;
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+ rep.success = MappingSuccess;
+ map = (BYTE *)&stuff[1];
+
+ /* So we're bounded here by the number of core buttons. This check
+ * probably wants disabling through XFixes. */
+ /* MPX: With ClientPointer, we can return the right number of buttons.
+ * Let's just hope nobody changed ClientPointer between GetPointerMapping
+ * and SetPointerMapping
+ */
+ if (stuff->nElts != ptr->button->numButtons) {
+ client->errorValue = stuff->nElts;
+ return BadValue;
+ }
+
+ /* Core protocol specs don't allow for duplicate mappings; this check
+ * almost certainly wants disabling through XFixes too. */
+ for (i = 0; i < stuff->nElts; i++) {
+ for (j = i + 1; j < stuff->nElts; j++) {
+ if (map[i] && map[i] == map[j]) {
+ client->errorValue = map[i];
+ return BadValue;
+ }
+ }
+ }
+
+ ret = ApplyPointerMapping(ptr, map, stuff->nElts, client);
+ if (ret == MappingBusy)
+ rep.success = ret;
+ else if (ret == -1)
+ return BadValue;
+ else if (ret != Success)
+ return ret;
+
+ WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep);
+ return Success;
+}
+
+int
+ProcGetKeyboardMapping(ClientPtr client)
+{
+ xGetKeyboardMappingReply rep;
+ DeviceIntPtr kbd = PickKeyboard(client);
+ XkbDescPtr xkb;
+ KeySymsPtr syms;
+ int rc;
+ REQUEST(xGetKeyboardMappingReq);
+ REQUEST_SIZE_MATCH(xGetKeyboardMappingReq);
+
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ xkb = kbd->key->xkbInfo->desc;
+
+ if ((stuff->firstKeyCode < xkb->min_key_code) ||
+ (stuff->firstKeyCode > xkb->max_key_code)) {
+ client->errorValue = stuff->firstKeyCode;
+ return BadValue;
+ }
+ if (stuff->firstKeyCode + stuff->count > xkb->max_key_code + 1) {
+ client->errorValue = stuff->count;
+ return BadValue;
+ }
+
+ syms = XkbGetCoreMap(kbd);
+ if (!syms)
+ return BadAlloc;
+
+ memset(&rep, 0, sizeof(xGetKeyboardMappingReply));
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.keySymsPerKeyCode = syms->mapWidth;
+ /* length is a count of 4 byte quantities and KeySyms are 4 bytes */
+ rep.length = syms->mapWidth * stuff->count;
+ WriteReplyToClient(client, sizeof(xGetKeyboardMappingReply), &rep);
+ client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write;
+ WriteSwappedDataToClient(client,
+ syms->mapWidth * stuff->count * sizeof(KeySym),
+ &syms->map[syms->mapWidth * (stuff->firstKeyCode -
+ syms->minKeyCode)]);
+ free(syms->map);
+ free(syms);
+
+ return Success;
+}
+
+int
+ProcGetPointerMapping(ClientPtr client)
+{
+ xGetPointerMappingReply rep;
+ /* Apps may get different values each time they call GetPointerMapping as
+ * the ClientPointer could change. */
+ DeviceIntPtr ptr = PickPointer(client);
+ ButtonClassPtr butc = ptr->button;
+ int rc;
+ REQUEST_SIZE_MATCH(xReq);
+
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.nElts = (butc) ? butc->numButtons : 0;
+ rep.length = ((unsigned)rep.nElts + (4-1))/4;
+ WriteReplyToClient(client, sizeof(xGetPointerMappingReply), &rep);
+ if (butc)
+ WriteToClient(client, (int)rep.nElts, (char *)&butc->map[1]);
+ return Success;
+}
+
+void
+NoteLedState(DeviceIntPtr keybd, int led, Bool on)
+{
+ KeybdCtrl *ctrl = &keybd->kbdfeed->ctrl;
+ if (on)
+ ctrl->leds |= ((Leds)1 << (led - 1));
+ else
+ ctrl->leds &= ~((Leds)1 << (led - 1));
+}
+
+int
+Ones(unsigned long mask) /* HACKMEM 169 */
+{
+ unsigned long y;
+
+ y = (mask >> 1) &033333333333;
+ y = mask - y - ((y >>1) & 033333333333);
+ return (((y + (y >> 3)) & 030707070707) % 077);
+}
+
+static int
+DoChangeKeyboardControl (ClientPtr client, DeviceIntPtr keybd, XID *vlist,
+ BITS32 vmask)
+{
+#define DO_ALL (-1)
+ KeybdCtrl ctrl;
+ int t;
+ int led = DO_ALL;
+ int key = DO_ALL;
+ BITS32 index2;
+ int mask = vmask, i;
+ XkbEventCauseRec cause;
+
+ ctrl = keybd->kbdfeed->ctrl;
+ while (vmask) {
+ index2 = (BITS32) lowbit (vmask);
+ vmask &= ~index2;
+ switch (index2) {
+ case KBKeyClickPercent:
+ t = (INT8)*vlist;
+ vlist++;
+ if (t == -1) {
+ t = defaultKeyboardControl.click;
+ }
+ else if (t < 0 || t > 100) {
+ client->errorValue = t;
+ return BadValue;
+ }
+ ctrl.click = t;
+ break;
+ case KBBellPercent:
+ t = (INT8)*vlist;
+ vlist++;
+ if (t == -1) {
+ t = defaultKeyboardControl.bell;
+ }
+ else if (t < 0 || t > 100) {
+ client->errorValue = t;
+ return BadValue;
+ }
+ ctrl.bell = t;
+ break;
+ case KBBellPitch:
+ t = (INT16)*vlist;
+ vlist++;
+ if (t == -1) {
+ t = defaultKeyboardControl.bell_pitch;
+ }
+ else if (t < 0) {
+ client->errorValue = t;
+ return BadValue;
+ }
+ ctrl.bell_pitch = t;
+ break;
+ case KBBellDuration:
+ t = (INT16)*vlist;
+ vlist++;
+ if (t == -1)
+ t = defaultKeyboardControl.bell_duration;
+ else if (t < 0) {
+ client->errorValue = t;
+ return BadValue;
+ }
+ ctrl.bell_duration = t;
+ break;
+ case KBLed:
+ led = (CARD8)*vlist;
+ vlist++;
+ if (led < 1 || led > 32) {
+ client->errorValue = led;
+ return BadValue;
+ }
+ if (!(mask & KBLedMode))
+ return BadMatch;
+ break;
+ case KBLedMode:
+ t = (CARD8)*vlist;
+ vlist++;
+ if (t == LedModeOff) {
+ if (led == DO_ALL)
+ ctrl.leds = 0x0;
+ else
+ ctrl.leds &= ~(((Leds)(1)) << (led - 1));
+ }
+ else if (t == LedModeOn) {
+ if (led == DO_ALL)
+ ctrl.leds = ~0L;
+ else
+ ctrl.leds |= (((Leds)(1)) << (led - 1));
+ }
+ else {
+ client->errorValue = t;
+ return BadValue;
+ }
+
+ XkbSetCauseCoreReq(&cause,X_ChangeKeyboardControl,client);
+ XkbSetIndicators(keybd,((led == DO_ALL) ? ~0L : (1L<<(led-1))),
+ ctrl.leds, &cause);
+ ctrl.leds = keybd->kbdfeed->ctrl.leds;
+
+ break;
+ case KBKey:
+ key = (KeyCode)*vlist;
+ vlist++;
+ if ((KeyCode)key < keybd->key->xkbInfo->desc->min_key_code ||
+ (KeyCode)key > keybd->key->xkbInfo->desc->max_key_code) {
+ client->errorValue = key;
+ return BadValue;
+ }
+ if (!(mask & KBAutoRepeatMode))
+ return BadMatch;
+ break;
+ case KBAutoRepeatMode:
+ i = (key >> 3);
+ mask = (1 << (key & 7));
+ t = (CARD8)*vlist;
+ vlist++;
+ if (key != DO_ALL)
+ XkbDisableComputedAutoRepeats(keybd,key);
+ if (t == AutoRepeatModeOff) {
+ if (key == DO_ALL)
+ ctrl.autoRepeat = FALSE;
+ else
+ ctrl.autoRepeats[i] &= ~mask;
+ }
+ else if (t == AutoRepeatModeOn) {
+ if (key == DO_ALL)
+ ctrl.autoRepeat = TRUE;
+ else
+ ctrl.autoRepeats[i] |= mask;
+ }
+ else if (t == AutoRepeatModeDefault) {
+ if (key == DO_ALL)
+ ctrl.autoRepeat = defaultKeyboardControl.autoRepeat;
+ else
+ ctrl.autoRepeats[i] =
+ (ctrl.autoRepeats[i] & ~mask) |
+ (defaultKeyboardControl.autoRepeats[i] & mask);
+ }
+ else {
+ client->errorValue = t;
+ return BadValue;
+ }
+ break;
+ default:
+ client->errorValue = mask;
+ return BadValue;
+ }
+ }
+ keybd->kbdfeed->ctrl = ctrl;
+
+ /* The XKB RepeatKeys control and core protocol global autorepeat */
+ /* value are linked */
+ XkbSetRepeatKeys(keybd, key, keybd->kbdfeed->ctrl.autoRepeat);
+
+ return Success;
+
+#undef DO_ALL
+}
+
+/**
+ * Changes kbd control on the ClientPointer and all attached SDs.
+ */
+int
+ProcChangeKeyboardControl (ClientPtr client)
+{
+ XID *vlist;
+ BITS32 vmask;
+ int ret = Success, error = Success;
+ DeviceIntPtr pDev = NULL, keyboard;
+ REQUEST(xChangeKeyboardControlReq);
+
+ REQUEST_AT_LEAST_SIZE(xChangeKeyboardControlReq);
+
+ vmask = stuff->mask;
+ vlist = (XID *)&stuff[1];
+
+ if (client->req_len != (sizeof(xChangeKeyboardControlReq)>>2)+Ones(vmask))
+ return BadLength;
+
+ keyboard = PickKeyboard(client);
+
+ for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
+ if ((pDev == keyboard ||
+ (!IsMaster(pDev) && GetMaster(pDev, MASTER_KEYBOARD) == keyboard))
+ && pDev->kbdfeed && pDev->kbdfeed->CtrlProc) {
+ ret = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess);
+ if (ret != Success)
+ return ret;
+ }
+ }
+
+ for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
+ if ((pDev == keyboard ||
+ (!IsMaster(pDev) && GetMaster(pDev, MASTER_KEYBOARD) == keyboard))
+ && pDev->kbdfeed && pDev->kbdfeed->CtrlProc) {
+ ret = DoChangeKeyboardControl(client, pDev, vlist, vmask);
+ if (ret != Success)
+ error = ret;
+ }
+ }
+
+ return error;
+}
+
+int
+ProcGetKeyboardControl (ClientPtr client)
+{
+ int rc, i;
+ DeviceIntPtr kbd = PickKeyboard(client);
+ KeybdCtrl *ctrl = &kbd->kbdfeed->ctrl;
+ xGetKeyboardControlReply rep;
+ REQUEST_SIZE_MATCH(xReq);
+
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ rep.type = X_Reply;
+ rep.length = 5;
+ rep.sequenceNumber = client->sequence;
+ rep.globalAutoRepeat = ctrl->autoRepeat;
+ rep.keyClickPercent = ctrl->click;
+ rep.bellPercent = ctrl->bell;
+ rep.bellPitch = ctrl->bell_pitch;
+ rep.bellDuration = ctrl->bell_duration;
+ rep.ledMask = ctrl->leds;
+ for (i = 0; i < 32; i++)
+ rep.map[i] = ctrl->autoRepeats[i];
+ WriteReplyToClient(client, sizeof(xGetKeyboardControlReply), &rep);
+ return Success;
+}
+
+int
+ProcBell(ClientPtr client)
+{
+ DeviceIntPtr dev, keybd = PickKeyboard(client);
+ int base = keybd->kbdfeed->ctrl.bell;
+ int newpercent;
+ int rc;
+ REQUEST(xBellReq);
+ REQUEST_SIZE_MATCH(xBellReq);
+
+ if (stuff->percent < -100 || stuff->percent > 100) {
+ client->errorValue = stuff->percent;
+ return BadValue;
+ }
+
+ newpercent = (base * stuff->percent) / 100;
+ if (stuff->percent < 0)
+ newpercent = base + newpercent;
+ else
+ newpercent = base - newpercent + stuff->percent;
+
+ for (dev = inputInfo.devices; dev; dev = dev->next) {
+ if ((dev == keybd ||
+ (!IsMaster(dev) && GetMaster(dev, MASTER_KEYBOARD) == keybd)) &&
+ dev->kbdfeed && dev->kbdfeed->BellProc) {
+
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixBellAccess);
+ if (rc != Success)
+ return rc;
+ XkbHandleBell(FALSE, FALSE, dev, newpercent,
+ &dev->kbdfeed->ctrl, 0, None, NULL, client);
+ }
+ }
+
+ return Success;
+}
+
+int
+ProcChangePointerControl(ClientPtr client)
+{
+ DeviceIntPtr dev, mouse = PickPointer(client);
+ PtrCtrl ctrl; /* might get BadValue part way through */
+ int rc;
+ REQUEST(xChangePointerControlReq);
+ REQUEST_SIZE_MATCH(xChangePointerControlReq);
+
+ ctrl = mouse->ptrfeed->ctrl;
+ if ((stuff->doAccel != xTrue) && (stuff->doAccel != xFalse)) {
+ client->errorValue = stuff->doAccel;
+ return BadValue;
+ }
+ if ((stuff->doThresh != xTrue) && (stuff->doThresh != xFalse)) {
+ client->errorValue = stuff->doThresh;
+ return BadValue;
+ }
+ if (stuff->doAccel) {
+ if (stuff->accelNum == -1) {
+ ctrl.num = defaultPointerControl.num;
+ }
+ else if (stuff->accelNum < 0) {
+ client->errorValue = stuff->accelNum;
+ return BadValue;
+ }
+ else {
+ ctrl.num = stuff->accelNum;
+ }
+
+ if (stuff->accelDenum == -1) {
+ ctrl.den = defaultPointerControl.den;
+ }
+ else if (stuff->accelDenum <= 0) {
+ client->errorValue = stuff->accelDenum;
+ return BadValue;
+ }
+ else {
+ ctrl.den = stuff->accelDenum;
+ }
+ }
+ if (stuff->doThresh) {
+ if (stuff->threshold == -1) {
+ ctrl.threshold = defaultPointerControl.threshold;
+ }
+ else if (stuff->threshold < 0) {
+ client->errorValue = stuff->threshold;
+ return BadValue;
+ }
+ else {
+ ctrl.threshold = stuff->threshold;
+ }
+ }
+
+ for (dev = inputInfo.devices; dev; dev = dev->next) {
+ if ((dev == mouse ||
+ (!IsMaster(dev) && GetMaster(dev, MASTER_POINTER) == mouse)) &&
+ dev->ptrfeed) {
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess);
+ if (rc != Success)
+ return rc;
+ }
+ }
+
+ for (dev = inputInfo.devices; dev; dev = dev->next) {
+ if ((dev == mouse ||
+ (!IsMaster(dev) && GetMaster(dev, MASTER_POINTER) == mouse)) &&
+ dev->ptrfeed) {
+ dev->ptrfeed->ctrl = ctrl;
+ }
+ }
+
+ return Success;
+}
+
+int
+ProcGetPointerControl(ClientPtr client)
+{
+ DeviceIntPtr ptr = PickPointer(client);
+ PtrCtrl *ctrl = &ptr->ptrfeed->ctrl;
+ xGetPointerControlReply rep;
+ int rc;
+ REQUEST_SIZE_MATCH(xReq);
+
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+
+ rep.type = X_Reply;
+ rep.length = 0;
+ rep.sequenceNumber = client->sequence;
+ rep.threshold = ctrl->threshold;
+ rep.accelNumerator = ctrl->num;
+ rep.accelDenominator = ctrl->den;
+ WriteReplyToClient(client, sizeof(xGenericReply), &rep);
+ return Success;
+}
+
+void
+MaybeStopHint(DeviceIntPtr dev, ClientPtr client)
+{
+ GrabPtr grab = dev->deviceGrab.grab;
+
+ if ((grab && SameClient(grab, client) &&
+ ((grab->eventMask & PointerMotionHintMask) ||
+ (grab->ownerEvents &&
+ (EventMaskForClient(dev->valuator->motionHintWindow, client) &
+ PointerMotionHintMask)))) ||
+ (!grab &&
+ (EventMaskForClient(dev->valuator->motionHintWindow, client) &
+ PointerMotionHintMask)))
+ dev->valuator->motionHintWindow = NullWindow;
+}
+
+int
+ProcGetMotionEvents(ClientPtr client)
+{
+ WindowPtr pWin;
+ xTimecoord * coords = (xTimecoord *) NULL;
+ xGetMotionEventsReply rep;
+ int i, count, xmin, xmax, ymin, ymax, rc;
+ unsigned long nEvents;
+ DeviceIntPtr mouse = PickPointer(client);
+ TimeStamp start, stop;
+ REQUEST(xGetMotionEventsReq);
+ REQUEST_SIZE_MATCH(xGetMotionEventsReq);
+
+ rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
+ if (rc != Success)
+ return rc;
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, mouse, DixReadAccess);
+ if (rc != Success)
+ return rc;
+
+ if (mouse->valuator->motionHintWindow)
+ MaybeStopHint(mouse, client);
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ nEvents = 0;
+ start = ClientTimeToServerTime(stuff->start);
+ stop = ClientTimeToServerTime(stuff->stop);
+ if ((CompareTimeStamps(start, stop) != LATER) &&
+ (CompareTimeStamps(start, currentTime) != LATER) &&
+ mouse->valuator->numMotionEvents)
+ {
+ if (CompareTimeStamps(stop, currentTime) == LATER)
+ stop = currentTime;
+ count = GetMotionHistory(mouse, &coords, start.milliseconds,
+ stop.milliseconds, pWin->drawable.pScreen,
+ TRUE);
+ xmin = pWin->drawable.x - wBorderWidth (pWin);
+ xmax = pWin->drawable.x + (int)pWin->drawable.width +
+ wBorderWidth (pWin);
+ ymin = pWin->drawable.y - wBorderWidth (pWin);
+ ymax = pWin->drawable.y + (int)pWin->drawable.height +
+ wBorderWidth (pWin);
+ for (i = 0; i < count; i++)
+ if ((xmin <= coords[i].x) && (coords[i].x < xmax) &&
+ (ymin <= coords[i].y) && (coords[i].y < ymax))
+ {
+ coords[nEvents].time = coords[i].time;
+ coords[nEvents].x = coords[i].x - pWin->drawable.x;
+ coords[nEvents].y = coords[i].y - pWin->drawable.y;
+ nEvents++;
+ }
+ }
+ rep.length = nEvents * bytes_to_int32(sizeof(xTimecoord));
+ rep.nEvents = nEvents;
+ WriteReplyToClient(client, sizeof(xGetMotionEventsReply), &rep);
+ if (nEvents)
+ {
+ client->pSwapReplyFunc = (ReplySwapPtr) SwapTimeCoordWrite;
+ WriteSwappedDataToClient(client, nEvents * sizeof(xTimecoord),
+ (char *)coords);
+ }
+ free(coords);
+ return Success;
+}
+
+int
+ProcQueryKeymap(ClientPtr client)
+{
+ xQueryKeymapReply rep;
+ int rc, i;
+ DeviceIntPtr keybd = PickKeyboard(client);
+ CARD8 *down = keybd->key->down;
+
+ REQUEST_SIZE_MATCH(xReq);
+ rep.type = X_Reply;
+ rep.sequenceNumber = client->sequence;
+ rep.length = 2;
+
+ rc = XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixReadAccess);
+ if (rc != Success && rc != BadAccess)
+ return rc;
+
+ for (i = 0; i<32; i++)
+ rep.map[i] = down[i];
+
+ if (rc == BadAccess)
+ memset(rep.map, 0, 32);
+
+ WriteReplyToClient(client, sizeof(xQueryKeymapReply), &rep);
+
+ return Success;
+}
+
+
+/**
+ * Recalculate the number of buttons for the master device. The number of
+ * buttons on the master device is equal to the number of buttons on the
+ * slave device with the highest number of buttons.
+ */
+static void
+RecalculateMasterButtons(DeviceIntPtr slave)
+{
+ DeviceIntPtr dev, master;
+ int maxbuttons = 0;
+
+ if (!slave->button || IsMaster(slave))
+ return;
+
+ master = GetMaster(slave, MASTER_POINTER);
+ if (!master)
+ return;
+
+ for (dev = inputInfo.devices; dev; dev = dev->next)
+ {
+ if (IsMaster(dev) ||
+ GetMaster(dev, MASTER_ATTACHED) != master ||
+ !dev->button)
+ continue;
+
+ maxbuttons = max(maxbuttons, dev->button->numButtons);
+ }
+
+ if (master->button && master->button->numButtons != maxbuttons)
+ {
+ int i;
+ DeviceChangedEvent event;
+
+ memset(&event, 0, sizeof(event));
+
+ master->button->numButtons = maxbuttons;
+
+ event.header = ET_Internal;
+ event.type = ET_DeviceChanged;
+ event.time = GetTimeInMillis();
+ event.deviceid = master->id;
+ event.flags = DEVCHANGE_POINTER_EVENT | DEVCHANGE_DEVICE_CHANGE;
+ event.buttons.num_buttons = maxbuttons;
+ memcpy(&event.buttons.names, master->button->labels, maxbuttons *
+ sizeof(Atom));
+
+ if (master->valuator)
+ {
+ event.num_valuators = master->valuator->numAxes;
+ for (i = 0; i < event.num_valuators; i++)
+ {
+ event.valuators[i].min = master->valuator->axes[i].min_value;
+ event.valuators[i].max = master->valuator->axes[i].max_value;
+ event.valuators[i].resolution = master->valuator->axes[i].resolution;
+ event.valuators[i].mode = master->valuator->axes[i].mode;
+ event.valuators[i].name = master->valuator->axes[i].label;
+ }
+ }
+
+ if (master->key)
+ {
+ event.keys.min_keycode = master->key->xkbInfo->desc->min_key_code;
+ event.keys.max_keycode = master->key->xkbInfo->desc->max_key_code;
+ }
+
+ XISendDeviceChangedEvent(master, master, &event);
+ }
+}
+
+/**
+ * Generate release events for all keys/button currently down on this
+ * device.
+ */
+static void
+ReleaseButtonsAndKeys(DeviceIntPtr dev)
+{
+ EventListPtr eventlist = InitEventList(GetMaximumEventsNum());
+ ButtonClassPtr b = dev->button;
+ KeyClassPtr k = dev->key;
+ int i, j, nevents;
+
+ if (!eventlist) /* no release events for you */
+ return;
+
+ /* Release all buttons */
+ for (i = 0; b && i < b->numButtons; i++)
+ {
+ if (BitIsOn(b->down, i))
+ {
+ nevents = GetPointerEvents(eventlist, dev, ButtonRelease, i, 0, NULL);
+ for (j = 0; j < nevents; j++)
+ mieqProcessDeviceEvent(dev, (InternalEvent*)(eventlist+j)->event, NULL);
+ }
+ }
+
+ /* Release all keys */
+ for (i = 0; k && i < MAP_LENGTH; i++)
+ {
+ if (BitIsOn(k->down, i))
+ {
+ nevents = GetKeyboardEvents(eventlist, dev, KeyRelease, i);
+ for (j = 0; j < nevents; j++)
+ mieqProcessDeviceEvent(dev, (InternalEvent*)(eventlist+j)->event, NULL);
+ }
+ }
+
+ FreeEventList(eventlist, GetMaximumEventsNum());
+}
+
+/**
+ * Attach device 'dev' to device 'master'.
+ * Client is set to the client that issued the request, or NULL if it comes
+ * from some internal automatic pairing.
+ *
+ * Master may be NULL to set the device floating.
+ *
+ * We don't allow multi-layer hierarchies right now. You can't attach a slave
+ * to another slave.
+ */
+int
+AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master)
+{
+ ScreenPtr screen;
+ DeviceIntPtr oldmaster;
+ if (!dev || IsMaster(dev))
+ return BadDevice;
+
+ if (master && !IsMaster(master)) /* can't attach to slaves */
+ return BadDevice;
+
+ /* set from floating to floating? */
+ if (IsFloating(dev) && !master && dev->enabled)
+ return Success;
+
+ /* free the existing sprite. */
+ if (IsFloating(dev) && dev->spriteInfo->paired == dev)
+ {
+ screen = miPointerGetScreen(dev);
+ screen->DeviceCursorCleanup(dev, screen);
+ free(dev->spriteInfo->sprite);
+ }
+
+ ReleaseButtonsAndKeys(dev);
+
+ oldmaster = GetMaster(dev, MASTER_ATTACHED);
+ dev->master = master;
+
+ /* If device is set to floating, we need to create a sprite for it,
+ * otherwise things go bad. However, we don't want to render the cursor,
+ * so we reset spriteOwner.
+ * Sprite has to be forced to NULL first, otherwise InitializeSprite won't
+ * alloc new memory but overwrite the previous one.
+ */
+ if (!master)
+ {
+ WindowPtr currentRoot;
+
+ if (dev->spriteInfo->sprite)
+ currentRoot = GetCurrentRootWindow(dev);
+ else /* new device auto-set to floating */
+ currentRoot = screenInfo.screens[0]->root;
+
+ /* we need to init a fake sprite */
+ screen = currentRoot->drawable.pScreen;
+ screen->DeviceCursorInitialize(dev, screen);
+ dev->spriteInfo->sprite = NULL;
+ InitializeSprite(dev, currentRoot);
+ dev->spriteInfo->spriteOwner = FALSE;
+ dev->spriteInfo->paired = dev;
+ } else
+ {
+ dev->spriteInfo->sprite = master->spriteInfo->sprite;
+ dev->spriteInfo->paired = master;
+ dev->spriteInfo->spriteOwner = FALSE;
+
+ RecalculateMasterButtons(master);
+ }
+
+ /* XXX: in theory, the MD should change back to its old, original
+ * classes when the last SD is detached. Thanks to the XTEST devices,
+ * we'll always have an SD attached until the MD is removed.
+ * So let's not worry about that.
+ */
+
+ return Success;
+}
+
+/**
+ * Return the device paired with the given device or NULL.
+ * Returns the device paired with the parent master if the given device is a
+ * slave device.
+ */
+DeviceIntPtr
+GetPairedDevice(DeviceIntPtr dev)
+{
+ if (!IsMaster(dev) && !IsFloating(dev))
+ dev = GetMaster(dev, MASTER_ATTACHED);
+
+ return dev->spriteInfo->paired;
+}
+
+
+/**
+ * Returns the right master for the type of event needed. If the event is a
+ * keyboard event.
+ * This function may be called with a master device as argument. If so, the
+ * returned master is either the device itself or the paired master device.
+ * If dev is a floating slave device, NULL is returned.
+ *
+ * @type ::MASTER_KEYBOARD or ::MASTER_POINTER or ::MASTER_ATTACHED
+ * @return The requested master device. In the case of MASTER_ATTACHED, this
+ * is the directly attached master to this device, regardless of the type.
+ * Otherwise, it is either the master keyboard or pointer for this device.
+ */
+DeviceIntPtr
+GetMaster(DeviceIntPtr dev, int which)
+{
+ DeviceIntPtr master;
+
+ if (IsMaster(dev))
+ master = dev;
+ else
+ master = dev->master;
+
+ if (master && which != MASTER_ATTACHED)
+ {
+ if (which == MASTER_KEYBOARD)
+ {
+ if (master->type != MASTER_KEYBOARD)
+ master = GetPairedDevice(master);
+ } else
+ {
+ if (master->type != MASTER_POINTER)
+ master = GetPairedDevice(master);
+ }
+ }
+
+ return master;
+}
+
+/**
+ * Create a new device pair (== one pointer, one keyboard device).
+ * Only allocates the devices, you will need to call ActivateDevice() and
+ * EnableDevice() manually.
+ * Either a master or a slave device can be created depending on
+ * the value for master.
+ */
+int
+AllocDevicePair (ClientPtr client, char* name,
+ DeviceIntPtr* ptr,
+ DeviceIntPtr* keybd,
+ DeviceProc ptr_proc,
+ DeviceProc keybd_proc,
+ Bool master)
+{
+ DeviceIntPtr pointer;
+ DeviceIntPtr keyboard;
+ *ptr = *keybd = NULL;
+
+ pointer = AddInputDevice(client, ptr_proc, TRUE);
+ if (!pointer)
+ return BadAlloc;
+
+ if (asprintf(&pointer->name, "%s pointer", name) == -1) {
+ pointer->name = NULL;
+ RemoveDevice(pointer, FALSE);
+ return BadAlloc;
+ }
+
+ pointer->public.processInputProc = ProcessOtherEvent;
+ pointer->public.realInputProc = ProcessOtherEvent;
+ XkbSetExtension(pointer, ProcessPointerEvent);
+ pointer->deviceGrab.ActivateGrab = ActivatePointerGrab;
+ pointer->deviceGrab.DeactivateGrab = DeactivatePointerGrab;
+ pointer->coreEvents = TRUE;
+ pointer->spriteInfo->spriteOwner = TRUE;
+
+ pointer->lastSlave = NULL;
+ pointer->last.slave = NULL;
+ pointer->type = (master) ? MASTER_POINTER : SLAVE;
+
+ keyboard = AddInputDevice(client, keybd_proc, TRUE);
+ if (!keyboard)
+ {
+ RemoveDevice(pointer, FALSE);
+ return BadAlloc;
+ }
+
+ if (asprintf(&keyboard->name, "%s keyboard", name) == -1) {
+ keyboard->name = NULL;
+ RemoveDevice(keyboard, FALSE);
+ RemoveDevice(pointer, FALSE);
+ return BadAlloc;
+ }
+
+ keyboard->public.processInputProc = ProcessOtherEvent;
+ keyboard->public.realInputProc = ProcessOtherEvent;
+ XkbSetExtension(keyboard, ProcessKeyboardEvent);
+ keyboard->deviceGrab.ActivateGrab = ActivateKeyboardGrab;
+ keyboard->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab;
+ keyboard->coreEvents = TRUE;
+ keyboard->spriteInfo->spriteOwner = FALSE;
+
+ keyboard->lastSlave = NULL;
+ keyboard->last.slave = NULL;
+ keyboard->type = (master) ? MASTER_KEYBOARD : SLAVE;
+
+ /* The ClassesRec stores the device classes currently not used. */
+ pointer->unused_classes = calloc(1, sizeof(ClassesRec));
+ keyboard->unused_classes = calloc(1, sizeof(ClassesRec));
+
+ *ptr = pointer;
+ *keybd = keyboard;
+
+ return Success;
+}
+
+/**
+ * Return Relative or Absolute for the device.
+ */
+int valuator_get_mode(DeviceIntPtr dev, int axis)
+{
+ return (dev->valuator->axes[axis].mode & DeviceMode);
+}
+
+/**
+ * Set the given mode for the axis. If axis is VALUATOR_MODE_ALL_AXES, then
+ * set the mode for all axes.
+ */
+void valuator_set_mode(DeviceIntPtr dev, int axis, int mode)
+{
+ if (axis != VALUATOR_MODE_ALL_AXES)
+ dev->valuator->axes[axis].mode = mode;
+ else {
+ int i;
+ for (i = 0; i < dev->valuator->numAxes; i++)
+ dev->valuator->axes[i].mode = mode;
+ }
+}
diff --git a/xorg-server/dix/eventconvert.c b/xorg-server/dix/eventconvert.c
index 760729beb..d5ac54796 100644
--- a/xorg-server/dix/eventconvert.c
+++ b/xorg-server/dix/eventconvert.c
@@ -1,767 +1,770 @@
-/*
- * 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.
- *
- */
-
-/**
- * @file eventconvert.c
- * This file contains event conversion routines from InternalEvent to the
- * matching protocol events.
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <stdint.h>
-#include <X11/X.h>
-#include <X11/extensions/XIproto.h>
-#include <X11/extensions/XI2proto.h>
-#include <X11/extensions/XI.h>
-#include <X11/extensions/XI2.h>
-
-#include "dix.h"
-#include "inputstr.h"
-#include "misc.h"
-#include "eventstr.h"
-#include "exglobals.h"
-#include "eventconvert.h"
-#include "xiquerydevice.h"
-#include "xkbsrv.h"
-
-
-static int countValuators(DeviceEvent *ev, int *first);
-static int getValuatorEvents(DeviceEvent *ev, deviceValuator *xv);
-static int eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count);
-static int eventToDeviceChanged(DeviceChangedEvent *ev, xEvent **dcce);
-static int eventToDeviceEvent(DeviceEvent *ev, xEvent **xi);
-static int eventToRawEvent(RawDeviceEvent *ev, xEvent **xi);
-
-/* Do not use, read comments below */
-BOOL EventIsKeyRepeat(xEvent *event);
-
-/**
- * Hack to allow detectable autorepeat for core and XI1 events.
- * The sequence number is unused until we send to the client and can be
- * misused to store data. More or less, anyway.
- *
- * Do not use this. It may change any time without warning, eat your babies
- * and piss on your cat.
- */
-static void
-EventSetKeyRepeatFlag(xEvent *event, BOOL on)
-{
- event->u.u.sequenceNumber = on;
-}
-
-/**
- * Check if the event was marked as a repeat event before.
- * NOTE: This is a nasty hack and should NOT be used by anyone else but
- * TryClientEvents.
- */
-BOOL
-EventIsKeyRepeat(xEvent *event)
-{
- return !!event->u.u.sequenceNumber;
-}
-
-/**
- * Convert the given event to the respective core event.
- *
- * Return values:
- * Success ... core contains the matching core event.
- * BadValue .. One or more values in the internal event are invalid.
- * BadMatch .. The event has no core equivalent.
- *
- * @param[in] event The event to convert into a core event.
- * @param[in] core The memory location to store the core event at.
- * @return Success or the matching error code.
- */
-int
-EventToCore(InternalEvent *event, xEvent **core_out, int *count_out)
-{
- xEvent *core = NULL;
- int count = 0;
- int ret = BadImplementation;
-
- switch(event->any.type)
- {
- case ET_Motion:
- {
- DeviceEvent *e = &event->device_event;
- /* Don't create core motion event if neither x nor y are
- * present */
- if (!BitIsOn(e->valuators.mask, 0) &&
- !BitIsOn(e->valuators.mask, 1))
- {
- ret = BadMatch;
- goto out;
- }
- }
- /* fallthrough */
- case ET_ButtonPress:
- case ET_ButtonRelease:
- case ET_KeyPress:
- case ET_KeyRelease:
- {
- DeviceEvent *e = &event->device_event;
-
- if (e->detail.key > 0xFF)
- {
- ret = BadMatch;
- goto out;
- }
-
- core = calloc(1, sizeof(*core));
- if (!core)
- return BadAlloc;
- count = 1;
- core->u.u.type = e->type - ET_KeyPress + KeyPress;
- core->u.u.detail = e->detail.key & 0xFF;
- core->u.keyButtonPointer.time = e->time;
- core->u.keyButtonPointer.rootX = e->root_x;
- core->u.keyButtonPointer.rootY = e->root_y;
- core->u.keyButtonPointer.state = e->corestate;
- core->u.keyButtonPointer.root = e->root;
- EventSetKeyRepeatFlag(core,
- (e->type == ET_KeyPress &&
- e->key_repeat));
- ret = Success;
- }
- break;
- case ET_ProximityIn:
- case ET_ProximityOut:
- case ET_RawKeyPress:
- case ET_RawKeyRelease:
- case ET_RawButtonPress:
- case ET_RawButtonRelease:
- case ET_RawMotion:
- ret = BadMatch;
- goto out;
- default:
- /* XXX: */
- ErrorF("[dix] EventToCore: Not implemented yet \n");
- ret = BadImplementation;
- }
-
-out:
- *core_out = core;
- *count_out = count;
- return ret;
-}
-
-/**
- * Convert the given event to the respective XI 1.x event and store it in
- * xi. xi is allocated on demand and must be freed by the caller.
- * count returns the number of events in xi. If count is 1, and the type of
- * xi is GenericEvent, then xi may be larger than 32 bytes.
- *
- * Return values:
- * Success ... core contains the matching core event.
- * BadValue .. One or more values in the internal event are invalid.
- * BadMatch .. The event has no XI equivalent.
- *
- * @param[in] ev The event to convert into an XI 1 event.
- * @param[out] xi Future memory location for the XI event.
- * @param[out] count Number of elements in xi.
- *
- * @return Success or the error code.
- */
-int
-EventToXI(InternalEvent *ev, xEvent **xi, int *count)
-{
- switch (ev->any.type)
- {
- case ET_Motion:
- case ET_ButtonPress:
- case ET_ButtonRelease:
- case ET_KeyPress:
- case ET_KeyRelease:
- case ET_ProximityIn:
- case ET_ProximityOut:
- return eventToKeyButtonPointer(&ev->device_event, xi, count);
- case ET_DeviceChanged:
- case ET_RawKeyPress:
- case ET_RawKeyRelease:
- case ET_RawButtonPress:
- case ET_RawButtonRelease:
- case ET_RawMotion:
- *count = 0;
- *xi = NULL;
- return BadMatch;
- default:
- break;
- }
-
- ErrorF("[dix] EventToXI: Not implemented for %d \n", ev->any.type);
- return BadImplementation;
-}
-
-/**
- * Convert the given event to the respective XI 2.x event and store it in xi.
- * xi is allocated on demand and must be freed by the caller.
- *
- * Return values:
- * Success ... core contains the matching core event.
- * BadValue .. One or more values in the internal event are invalid.
- * BadMatch .. The event has no XI2 equivalent.
- *
- * @param[in] ev The event to convert into an XI2 event
- * @param[out] xi Future memory location for the XI2 event.
- *
- * @return Success or the error code.
- */
-int
-EventToXI2(InternalEvent *ev, xEvent **xi)
-{
- switch (ev->any.type)
- {
- /* Enter/FocusIn are for grabs. We don't need an actual event, since
- * the real events delivered are triggered elsewhere */
- case ET_Enter:
- case ET_FocusIn:
- *xi = NULL;
- return Success;
- case ET_Motion:
- case ET_ButtonPress:
- case ET_ButtonRelease:
- case ET_KeyPress:
- case ET_KeyRelease:
- return eventToDeviceEvent(&ev->device_event, xi);
- case ET_ProximityIn:
- case ET_ProximityOut:
- *xi = NULL;
- return BadMatch;
- case ET_DeviceChanged:
- return eventToDeviceChanged(&ev->changed_event, xi);
- case ET_RawKeyPress:
- case ET_RawKeyRelease:
- case ET_RawButtonPress:
- case ET_RawButtonRelease:
- case ET_RawMotion:
- return eventToRawEvent(&ev->raw_event, xi);
- default:
- break;
- }
-
- ErrorF("[dix] EventToXI2: Not implemented for %d \n", ev->any.type);
- return BadImplementation;
-}
-
-static int
-eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count)
-{
- int num_events;
- int first; /* dummy */
- deviceKeyButtonPointer *kbp;
-
- /* Sorry, XI 1.x protocol restrictions. */
- if (ev->detail.button > 0xFF || ev->deviceid >= 0x80)
- {
- *count = 0;
- return Success;
- }
-
- num_events = (countValuators(ev, &first) + 5)/6; /* valuator ev */
- if (num_events <= 0)
- {
- switch (ev->type)
- {
- case ET_KeyPress:
- case ET_KeyRelease:
- case ET_ButtonPress:
- case ET_ButtonRelease:
- /* no axes is ok */
- break;
- case ET_Motion:
- case ET_ProximityIn:
- case ET_ProximityOut:
- *count = 0;
- return BadMatch;
- }
- }
-
- num_events++; /* the actual event event */
-
- *xi = calloc(num_events, sizeof(xEvent));
- if (!(*xi))
- {
- return BadAlloc;
- }
-
- kbp = (deviceKeyButtonPointer*)(*xi);
- kbp->detail = ev->detail.button;
- kbp->time = ev->time;
- kbp->root = ev->root;
- kbp->root_x = ev->root_x;
- kbp->root_y = ev->root_y;
- kbp->deviceid = ev->deviceid;
- kbp->state = ev->corestate;
- EventSetKeyRepeatFlag((xEvent*)kbp,
- (ev->type == ET_KeyPress && ev->key_repeat));
-
- if (num_events > 1)
- kbp->deviceid |= MORE_EVENTS;
-
- switch(ev->type)
- {
- case ET_Motion: kbp->type = DeviceMotionNotify; break;
- case ET_ButtonPress: kbp->type = DeviceButtonPress; break;
- case ET_ButtonRelease: kbp->type = DeviceButtonRelease; break;
- case ET_KeyPress: kbp->type = DeviceKeyPress; break;
- case ET_KeyRelease: kbp->type = DeviceKeyRelease; break;
- case ET_ProximityIn: kbp->type = ProximityIn; break;
- case ET_ProximityOut: kbp->type = ProximityOut; break;
- default:
- break;
- }
-
- if (num_events > 1)
- {
- getValuatorEvents(ev, (deviceValuator*)(kbp + 1));
- }
-
- *count = num_events;
- return Success;
-}
-
-
-/**
- * Set first to the first valuator in the event ev and return the number of
- * valuators from first to the last set valuator.
- */
-static int
-countValuators(DeviceEvent *ev, int *first)
-{
- int first_valuator = -1, last_valuator = -1, num_valuators = 0;
- int i;
-
- for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++)
- {
- if (BitIsOn(ev->valuators.mask, i))
- {
- if (first_valuator == -1)
- first_valuator = i;
- last_valuator = i;
- }
- }
-
- if (first_valuator != -1)
- {
- num_valuators = last_valuator - first_valuator + 1;
- *first = first_valuator;
- }
-
- return num_valuators;
-}
-
-static int
-getValuatorEvents(DeviceEvent *ev, deviceValuator *xv)
-{
- int i;
- int state = 0;
- int first_valuator, num_valuators;
-
-
- num_valuators = countValuators(ev, &first_valuator);
- if (num_valuators > 0)
- {
- DeviceIntPtr dev = NULL;
- dixLookupDevice(&dev, ev->deviceid, serverClient, DixUseAccess);
- /* State needs to be assembled BEFORE the device is updated. */
- state = (dev && dev->key) ? XkbStateFieldFromRec(&dev->key->xkbInfo->state) : 0;
- state |= (dev && dev->button) ? (dev->button->state) : 0;
- }
-
- /* FIXME: non-continuous valuator data in internal events*/
- for (i = 0; i < num_valuators; i += 6, xv++) {
- xv->type = DeviceValuator;
- xv->first_valuator = first_valuator + i;
- xv->num_valuators = ((num_valuators - i) > 6) ? 6 : (num_valuators - i);
- xv->deviceid = ev->deviceid;
- xv->device_state = state;
- switch (xv->num_valuators) {
- case 6:
- xv->valuator5 = ev->valuators.data[xv->first_valuator + 5];
- case 5:
- xv->valuator4 = ev->valuators.data[xv->first_valuator + 4];
- case 4:
- xv->valuator3 = ev->valuators.data[xv->first_valuator + 3];
- case 3:
- xv->valuator2 = ev->valuators.data[xv->first_valuator + 2];
- case 2:
- xv->valuator1 = ev->valuators.data[xv->first_valuator + 1];
- case 1:
- xv->valuator0 = ev->valuators.data[xv->first_valuator + 0];
- }
-
- if (i + 6 < num_valuators)
- xv->deviceid |= MORE_EVENTS;
- }
-
- return (num_valuators + 5) / 6;
-}
-
-
-static int
-appendKeyInfo(DeviceChangedEvent *dce, xXIKeyInfo* info)
-{
- uint32_t *kc;
- int i;
-
- info->type = XIKeyClass;
- info->num_keycodes = dce->keys.max_keycode - dce->keys.min_keycode + 1;
- info->length = sizeof(xXIKeyInfo)/4 + info->num_keycodes;
- info->sourceid = dce->sourceid;
-
- kc = (uint32_t*)&info[1];
- for (i = 0; i < info->num_keycodes; i++)
- *kc++ = i + dce->keys.min_keycode;
-
- return info->length * 4;
-}
-
-static int
-appendButtonInfo(DeviceChangedEvent *dce, xXIButtonInfo *info)
-{
- unsigned char *bits;
- int mask_len;
-
- mask_len = bytes_to_int32(bits_to_bytes(dce->buttons.num_buttons));
-
- info->type = XIButtonClass;
- info->num_buttons = dce->buttons.num_buttons;
- info->length = bytes_to_int32(sizeof(xXIButtonInfo)) +
- info->num_buttons + mask_len;
- info->sourceid = dce->sourceid;
-
- bits = (unsigned char*)&info[1];
- memset(bits, 0, mask_len * 4);
- /* FIXME: is_down? */
-
- bits += mask_len * 4;
- memcpy(bits, dce->buttons.names, dce->buttons.num_buttons * sizeof(Atom));
-
- return info->length * 4;
-}
-
-static int
-appendValuatorInfo(DeviceChangedEvent *dce, xXIValuatorInfo *info, int axisnumber)
-{
- info->type = XIValuatorClass;
- info->length = sizeof(xXIValuatorInfo)/4;
- info->label = dce->valuators[axisnumber].name;
- info->min.integral = dce->valuators[axisnumber].min;
- info->min.frac = 0;
- info->max.integral = dce->valuators[axisnumber].max;
- info->max.frac = 0;
- /* FIXME: value */
- info->value.integral = 0;
- info->value.frac = 0;
- info->resolution = dce->valuators[axisnumber].resolution;
- info->number = axisnumber;
- info->mode = dce->valuators[axisnumber].mode;
- info->sourceid = dce->sourceid;
-
- return info->length * 4;
-}
-
-static int
-eventToDeviceChanged(DeviceChangedEvent *dce, xEvent **xi)
-{
- xXIDeviceChangedEvent *dcce;
- int len = sizeof(xXIDeviceChangedEvent);
- int nkeys;
- char *ptr;
-
- if (dce->buttons.num_buttons)
- {
- len += sizeof(xXIButtonInfo);
- len += dce->buttons.num_buttons * sizeof(Atom); /* button names */
- len += pad_to_int32(bits_to_bytes(dce->buttons.num_buttons));
- }
- if (dce->num_valuators)
- len += sizeof(xXIValuatorInfo) * dce->num_valuators;
-
- nkeys = (dce->keys.max_keycode > 0) ?
- dce->keys.max_keycode - dce->keys.min_keycode + 1 : 0;
- if (nkeys > 0)
- {
- len += sizeof(xXIKeyInfo);
- len += sizeof(CARD32) * nkeys; /* keycodes */
- }
-
- dcce = calloc(1, len);
- if (!dcce)
- {
- ErrorF("[Xi] BadAlloc in SendDeviceChangedEvent.\n");
- return BadAlloc;
- }
-
- dcce->type = GenericEvent;
- dcce->extension = IReqCode;
- dcce->evtype = XI_DeviceChanged;
- dcce->time = dce->time;
- dcce->deviceid = dce->deviceid;
- dcce->sourceid = dce->sourceid;
- dcce->reason = (dce->flags & DEVCHANGE_DEVICE_CHANGE) ? XIDeviceChange : XISlaveSwitch;
- dcce->num_classes = 0;
- dcce->length = bytes_to_int32(len - sizeof(xEvent));
-
- ptr = (char*)&dcce[1];
- if (dce->buttons.num_buttons)
- {
- dcce->num_classes++;
- ptr += appendButtonInfo(dce, (xXIButtonInfo*)ptr);
- }
-
- if (nkeys)
- {
- dcce->num_classes++;
- ptr += appendKeyInfo(dce, (xXIKeyInfo*)ptr);
- }
-
- if (dce->num_valuators)
- {
- int i;
-
- dcce->num_classes += dce->num_valuators;
- for (i = 0; i < dce->num_valuators; i++)
- ptr += appendValuatorInfo(dce, (xXIValuatorInfo*)ptr, i);
- }
-
- *xi = (xEvent*)dcce;
-
- return Success;
-}
-
-static int count_bits(unsigned char* ptr, int len)
-{
- int bits = 0;
- unsigned int i;
- unsigned char x;
-
- for (i = 0; i < len; i++)
- {
- x = ptr[i];
- while(x > 0)
- {
- bits += (x & 0x1);
- x >>= 1;
- }
- }
- return bits;
-}
-
-static int
-eventToDeviceEvent(DeviceEvent *ev, xEvent **xi)
-{
- int len = sizeof(xXIDeviceEvent);
- xXIDeviceEvent *xde;
- int i, btlen, vallen;
- char *ptr;
- FP3232 *axisval;
-
- /* FIXME: this should just send the buttons we have, not MAX_BUTTONs. Same
- * with MAX_VALUATORS below */
- /* btlen is in 4 byte units */
- btlen = bytes_to_int32(bits_to_bytes(MAX_BUTTONS));
- len += btlen * 4; /* buttonmask len */
-
-
- vallen = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask)/sizeof(ev->valuators.mask[0]));
- len += vallen * 2 * sizeof(uint32_t); /* axisvalues */
- vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS));
- len += vallen * 4; /* valuators mask */
-
- *xi = calloc(1, len);
- xde = (xXIDeviceEvent*)*xi;
- xde->type = GenericEvent;
- xde->extension = IReqCode;
- xde->evtype = GetXI2Type((InternalEvent*)ev);
- xde->time = ev->time;
- xde->length = bytes_to_int32(len - sizeof(xEvent));
- xde->detail = ev->detail.button;
- xde->root = ev->root;
- xde->buttons_len = btlen;
- xde->valuators_len = vallen;
- xde->deviceid = ev->deviceid;
- xde->sourceid = ev->sourceid;
- xde->root_x = FP1616(ev->root_x, ev->root_x_frac);
- xde->root_y = FP1616(ev->root_y, ev->root_y_frac);
-
- if (ev->key_repeat)
- xde->flags |= XIKeyRepeat;
-
- xde->mods.base_mods = ev->mods.base;
- xde->mods.latched_mods = ev->mods.latched;
- xde->mods.locked_mods = ev->mods.locked;
- xde->mods.effective_mods = ev->mods.effective;
-
- xde->group.base_group = ev->group.base;
- xde->group.latched_group = ev->group.latched;
- xde->group.locked_group = ev->group.locked;
- xde->group.effective_group = ev->group.effective;
-
- ptr = (char*)&xde[1];
- for (i = 0; i < sizeof(ev->buttons) * 8; i++)
- {
- if (BitIsOn(ev->buttons, i))
- SetBit(ptr, i);
- }
-
- ptr += xde->buttons_len * 4;
- axisval = (FP3232*)(ptr + xde->valuators_len * 4);
- for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++)
- {
- if (BitIsOn(ev->valuators.mask, i))
- {
- SetBit(ptr, i);
- axisval->integral = ev->valuators.data[i];
- axisval->frac = ev->valuators.data_frac[i];
- axisval++;
- }
- }
-
- return Success;
-}
-
-static int
-eventToRawEvent(RawDeviceEvent *ev, xEvent **xi)
-{
- xXIRawEvent* raw;
- int vallen, nvals;
- int i, len = sizeof(xXIRawEvent);
- char *ptr;
- FP3232 *axisval;
-
- nvals = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask));
- len += nvals * sizeof(FP3232) * 2; /* 8 byte per valuator, once
- raw, once processed */
- vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS));
- len += vallen * 4; /* valuators mask */
-
- *xi = calloc(1, len);
- raw = (xXIRawEvent*)*xi;
- raw->type = GenericEvent;
- raw->extension = IReqCode;
- raw->evtype = GetXI2Type((InternalEvent*)ev);
- raw->time = ev->time;
- raw->length = bytes_to_int32(len - sizeof(xEvent));
- raw->detail = ev->detail.button;
- raw->deviceid = ev->deviceid;
- raw->valuators_len = vallen;
-
- ptr = (char*)&raw[1];
- axisval = (FP3232*)(ptr + raw->valuators_len * 4);
- for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++)
- {
- if (BitIsOn(ev->valuators.mask, i))
- {
- SetBit(ptr, i);
- axisval->integral = ev->valuators.data[i];
- axisval->frac = ev->valuators.data_frac[i];
- (axisval + nvals)->integral = ev->valuators.data_raw[i];
- (axisval + nvals)->frac = ev->valuators.data_raw_frac[i];
- axisval++;
- }
- }
-
- return Success;
-}
-
-/**
- * Return the corresponding core type for the given event or 0 if no core
- * equivalent exists.
- */
-int
-GetCoreType(InternalEvent *event)
-{
- int coretype = 0;
- switch(event->any.type)
- {
- case ET_Motion: coretype = MotionNotify; break;
- case ET_ButtonPress: coretype = ButtonPress; break;
- case ET_ButtonRelease: coretype = ButtonRelease; break;
- case ET_KeyPress: coretype = KeyPress; break;
- case ET_KeyRelease: coretype = KeyRelease; break;
- default:
- break;
- }
- return coretype;
-}
-
-/**
- * Return the corresponding XI 1.x type for the given event or 0 if no
- * equivalent exists.
- */
-int
-GetXIType(InternalEvent *event)
-{
- int xitype = 0;
- switch(event->any.type)
- {
- case ET_Motion: xitype = DeviceMotionNotify; break;
- case ET_ButtonPress: xitype = DeviceButtonPress; break;
- case ET_ButtonRelease: xitype = DeviceButtonRelease; break;
- case ET_KeyPress: xitype = DeviceKeyPress; break;
- case ET_KeyRelease: xitype = DeviceKeyRelease; break;
- case ET_ProximityIn: xitype = ProximityIn; break;
- case ET_ProximityOut: xitype = ProximityOut; break;
- default:
- break;
- }
- return xitype;
-}
-
-/**
- * Return the corresponding XI 2.x type for the given event or 0 if no
- * equivalent exists.
- */
-int
-GetXI2Type(InternalEvent *event)
-{
- int xi2type = 0;
-
- switch(event->any.type)
- {
- case ET_Motion: xi2type = XI_Motion; break;
- case ET_ButtonPress: xi2type = XI_ButtonPress; break;
- case ET_ButtonRelease: xi2type = XI_ButtonRelease; break;
- case ET_KeyPress: xi2type = XI_KeyPress; break;
- case ET_KeyRelease: xi2type = XI_KeyRelease; break;
- case ET_Enter: xi2type = XI_Enter; break;
- case ET_Leave: xi2type = XI_Leave; break;
- case ET_Hierarchy: xi2type = XI_HierarchyChanged; break;
- case ET_DeviceChanged: xi2type = XI_DeviceChanged; break;
- case ET_RawKeyPress: xi2type = XI_RawKeyPress; break;
- case ET_RawKeyRelease: xi2type = XI_RawKeyRelease; break;
- case ET_RawButtonPress: xi2type = XI_RawButtonPress; break;
- case ET_RawButtonRelease: xi2type = XI_RawButtonRelease; break;
- case ET_RawMotion: xi2type = XI_RawMotion; break;
- case ET_FocusIn: xi2type = XI_FocusIn; break;
- case ET_FocusOut: xi2type = XI_FocusOut; break;
- default:
- break;
- }
- return xi2type;
-}
+/*
+ * 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.
+ *
+ */
+
+/**
+ * @file eventconvert.c
+ * This file contains event conversion routines from InternalEvent to the
+ * matching protocol events.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdint.h>
+#include <X11/X.h>
+#include <X11/extensions/XIproto.h>
+#include <X11/extensions/XI2proto.h>
+#include <X11/extensions/XI.h>
+#include <X11/extensions/XI2.h>
+
+#include "dix.h"
+#include "inputstr.h"
+#include "misc.h"
+#include "eventstr.h"
+#include "exglobals.h"
+#include "eventconvert.h"
+#include "xiquerydevice.h"
+#include "xkbsrv.h"
+
+
+static int countValuators(DeviceEvent *ev, int *first);
+static int getValuatorEvents(DeviceEvent *ev, deviceValuator *xv);
+static int eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count);
+static int eventToDeviceChanged(DeviceChangedEvent *ev, xEvent **dcce);
+static int eventToDeviceEvent(DeviceEvent *ev, xEvent **xi);
+static int eventToRawEvent(RawDeviceEvent *ev, xEvent **xi);
+
+/* Do not use, read comments below */
+BOOL EventIsKeyRepeat(xEvent *event);
+
+/**
+ * Hack to allow detectable autorepeat for core and XI1 events.
+ * The sequence number is unused until we send to the client and can be
+ * misused to store data. More or less, anyway.
+ *
+ * Do not use this. It may change any time without warning, eat your babies
+ * and piss on your cat.
+ */
+static void
+EventSetKeyRepeatFlag(xEvent *event, BOOL on)
+{
+ event->u.u.sequenceNumber = on;
+}
+
+/**
+ * Check if the event was marked as a repeat event before.
+ * NOTE: This is a nasty hack and should NOT be used by anyone else but
+ * TryClientEvents.
+ */
+BOOL
+EventIsKeyRepeat(xEvent *event)
+{
+ return !!event->u.u.sequenceNumber;
+}
+
+/**
+ * Convert the given event to the respective core event.
+ *
+ * Return values:
+ * Success ... core contains the matching core event.
+ * BadValue .. One or more values in the internal event are invalid.
+ * BadMatch .. The event has no core equivalent.
+ *
+ * @param[in] event The event to convert into a core event.
+ * @param[in] core The memory location to store the core event at.
+ * @return Success or the matching error code.
+ */
+int
+EventToCore(InternalEvent *event, xEvent **core_out, int *count_out)
+{
+ xEvent *core = NULL;
+ int count = 0;
+ int ret = BadImplementation;
+
+ switch(event->any.type)
+ {
+ case ET_Motion:
+ {
+ DeviceEvent *e = &event->device_event;
+ /* Don't create core motion event if neither x nor y are
+ * present */
+ if (!BitIsOn(e->valuators.mask, 0) &&
+ !BitIsOn(e->valuators.mask, 1))
+ {
+ ret = BadMatch;
+ goto out;
+ }
+ }
+ /* fallthrough */
+ case ET_ButtonPress:
+ case ET_ButtonRelease:
+ case ET_KeyPress:
+ case ET_KeyRelease:
+ {
+ DeviceEvent *e = &event->device_event;
+
+ if (e->detail.key > 0xFF)
+ {
+ ret = BadMatch;
+ goto out;
+ }
+
+ core = calloc(1, sizeof(*core));
+ if (!core)
+ return BadAlloc;
+ count = 1;
+ core->u.u.type = e->type - ET_KeyPress + KeyPress;
+ core->u.u.detail = e->detail.key & 0xFF;
+ core->u.keyButtonPointer.time = e->time;
+ core->u.keyButtonPointer.rootX = e->root_x;
+ core->u.keyButtonPointer.rootY = e->root_y;
+ core->u.keyButtonPointer.state = e->corestate;
+ core->u.keyButtonPointer.root = e->root;
+ EventSetKeyRepeatFlag(core,
+ (e->type == ET_KeyPress &&
+ e->key_repeat));
+ ret = Success;
+ }
+ break;
+ case ET_ProximityIn:
+ case ET_ProximityOut:
+ case ET_RawKeyPress:
+ case ET_RawKeyRelease:
+ case ET_RawButtonPress:
+ case ET_RawButtonRelease:
+ case ET_RawMotion:
+ ret = BadMatch;
+ goto out;
+ default:
+ /* XXX: */
+ ErrorF("[dix] EventToCore: Not implemented yet \n");
+ ret = BadImplementation;
+ }
+
+out:
+ *core_out = core;
+ *count_out = count;
+ return ret;
+}
+
+/**
+ * Convert the given event to the respective XI 1.x event and store it in
+ * xi. xi is allocated on demand and must be freed by the caller.
+ * count returns the number of events in xi. If count is 1, and the type of
+ * xi is GenericEvent, then xi may be larger than 32 bytes.
+ *
+ * Return values:
+ * Success ... core contains the matching core event.
+ * BadValue .. One or more values in the internal event are invalid.
+ * BadMatch .. The event has no XI equivalent.
+ *
+ * @param[in] ev The event to convert into an XI 1 event.
+ * @param[out] xi Future memory location for the XI event.
+ * @param[out] count Number of elements in xi.
+ *
+ * @return Success or the error code.
+ */
+int
+EventToXI(InternalEvent *ev, xEvent **xi, int *count)
+{
+ switch (ev->any.type)
+ {
+ case ET_Motion:
+ case ET_ButtonPress:
+ case ET_ButtonRelease:
+ case ET_KeyPress:
+ case ET_KeyRelease:
+ case ET_ProximityIn:
+ case ET_ProximityOut:
+ return eventToKeyButtonPointer(&ev->device_event, xi, count);
+ case ET_DeviceChanged:
+ case ET_RawKeyPress:
+ case ET_RawKeyRelease:
+ case ET_RawButtonPress:
+ case ET_RawButtonRelease:
+ case ET_RawMotion:
+ *count = 0;
+ *xi = NULL;
+ return BadMatch;
+ default:
+ break;
+ }
+
+ ErrorF("[dix] EventToXI: Not implemented for %d \n", ev->any.type);
+ return BadImplementation;
+}
+
+/**
+ * Convert the given event to the respective XI 2.x event and store it in xi.
+ * xi is allocated on demand and must be freed by the caller.
+ *
+ * Return values:
+ * Success ... core contains the matching core event.
+ * BadValue .. One or more values in the internal event are invalid.
+ * BadMatch .. The event has no XI2 equivalent.
+ *
+ * @param[in] ev The event to convert into an XI2 event
+ * @param[out] xi Future memory location for the XI2 event.
+ *
+ * @return Success or the error code.
+ */
+int
+EventToXI2(InternalEvent *ev, xEvent **xi)
+{
+ switch (ev->any.type)
+ {
+ /* Enter/FocusIn are for grabs. We don't need an actual event, since
+ * the real events delivered are triggered elsewhere */
+ case ET_Enter:
+ case ET_FocusIn:
+ *xi = NULL;
+ return Success;
+ case ET_Motion:
+ case ET_ButtonPress:
+ case ET_ButtonRelease:
+ case ET_KeyPress:
+ case ET_KeyRelease:
+ return eventToDeviceEvent(&ev->device_event, xi);
+ case ET_ProximityIn:
+ case ET_ProximityOut:
+ *xi = NULL;
+ return BadMatch;
+ case ET_DeviceChanged:
+ return eventToDeviceChanged(&ev->changed_event, xi);
+ case ET_RawKeyPress:
+ case ET_RawKeyRelease:
+ case ET_RawButtonPress:
+ case ET_RawButtonRelease:
+ case ET_RawMotion:
+ return eventToRawEvent(&ev->raw_event, xi);
+ default:
+ break;
+ }
+
+ ErrorF("[dix] EventToXI2: Not implemented for %d \n", ev->any.type);
+ return BadImplementation;
+}
+
+static int
+eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count)
+{
+ int num_events;
+ int first; /* dummy */
+ deviceKeyButtonPointer *kbp;
+
+ /* Sorry, XI 1.x protocol restrictions. */
+ if (ev->detail.button > 0xFF || ev->deviceid >= 0x80)
+ {
+ *count = 0;
+ return Success;
+ }
+
+ num_events = (countValuators(ev, &first) + 5)/6; /* valuator ev */
+ if (num_events <= 0)
+ {
+ switch (ev->type)
+ {
+ case ET_KeyPress:
+ case ET_KeyRelease:
+ case ET_ButtonPress:
+ case ET_ButtonRelease:
+ /* no axes is ok */
+ break;
+ case ET_Motion:
+ case ET_ProximityIn:
+ case ET_ProximityOut:
+ *count = 0;
+ return BadMatch;
+ default:
+ *count = 0;
+ return BadImplementation;
+ }
+ }
+
+ num_events++; /* the actual event event */
+
+ *xi = calloc(num_events, sizeof(xEvent));
+ if (!(*xi))
+ {
+ return BadAlloc;
+ }
+
+ kbp = (deviceKeyButtonPointer*)(*xi);
+ kbp->detail = ev->detail.button;
+ kbp->time = ev->time;
+ kbp->root = ev->root;
+ kbp->root_x = ev->root_x;
+ kbp->root_y = ev->root_y;
+ kbp->deviceid = ev->deviceid;
+ kbp->state = ev->corestate;
+ EventSetKeyRepeatFlag((xEvent*)kbp,
+ (ev->type == ET_KeyPress && ev->key_repeat));
+
+ if (num_events > 1)
+ kbp->deviceid |= MORE_EVENTS;
+
+ switch(ev->type)
+ {
+ case ET_Motion: kbp->type = DeviceMotionNotify; break;
+ case ET_ButtonPress: kbp->type = DeviceButtonPress; break;
+ case ET_ButtonRelease: kbp->type = DeviceButtonRelease; break;
+ case ET_KeyPress: kbp->type = DeviceKeyPress; break;
+ case ET_KeyRelease: kbp->type = DeviceKeyRelease; break;
+ case ET_ProximityIn: kbp->type = ProximityIn; break;
+ case ET_ProximityOut: kbp->type = ProximityOut; break;
+ default:
+ break;
+ }
+
+ if (num_events > 1)
+ {
+ getValuatorEvents(ev, (deviceValuator*)(kbp + 1));
+ }
+
+ *count = num_events;
+ return Success;
+}
+
+
+/**
+ * Set first to the first valuator in the event ev and return the number of
+ * valuators from first to the last set valuator.
+ */
+static int
+countValuators(DeviceEvent *ev, int *first)
+{
+ int first_valuator = -1, last_valuator = -1, num_valuators = 0;
+ int i;
+
+ for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++)
+ {
+ if (BitIsOn(ev->valuators.mask, i))
+ {
+ if (first_valuator == -1)
+ first_valuator = i;
+ last_valuator = i;
+ }
+ }
+
+ if (first_valuator != -1)
+ {
+ num_valuators = last_valuator - first_valuator + 1;
+ *first = first_valuator;
+ }
+
+ return num_valuators;
+}
+
+static int
+getValuatorEvents(DeviceEvent *ev, deviceValuator *xv)
+{
+ int i;
+ int state = 0;
+ int first_valuator, num_valuators;
+
+
+ num_valuators = countValuators(ev, &first_valuator);
+ if (num_valuators > 0)
+ {
+ DeviceIntPtr dev = NULL;
+ dixLookupDevice(&dev, ev->deviceid, serverClient, DixUseAccess);
+ /* State needs to be assembled BEFORE the device is updated. */
+ state = (dev && dev->key) ? XkbStateFieldFromRec(&dev->key->xkbInfo->state) : 0;
+ state |= (dev && dev->button) ? (dev->button->state) : 0;
+ }
+
+ /* FIXME: non-continuous valuator data in internal events*/
+ for (i = 0; i < num_valuators; i += 6, xv++) {
+ xv->type = DeviceValuator;
+ xv->first_valuator = first_valuator + i;
+ xv->num_valuators = ((num_valuators - i) > 6) ? 6 : (num_valuators - i);
+ xv->deviceid = ev->deviceid;
+ xv->device_state = state;
+ switch (xv->num_valuators) {
+ case 6:
+ xv->valuator5 = ev->valuators.data[xv->first_valuator + 5];
+ case 5:
+ xv->valuator4 = ev->valuators.data[xv->first_valuator + 4];
+ case 4:
+ xv->valuator3 = ev->valuators.data[xv->first_valuator + 3];
+ case 3:
+ xv->valuator2 = ev->valuators.data[xv->first_valuator + 2];
+ case 2:
+ xv->valuator1 = ev->valuators.data[xv->first_valuator + 1];
+ case 1:
+ xv->valuator0 = ev->valuators.data[xv->first_valuator + 0];
+ }
+
+ if (i + 6 < num_valuators)
+ xv->deviceid |= MORE_EVENTS;
+ }
+
+ return (num_valuators + 5) / 6;
+}
+
+
+static int
+appendKeyInfo(DeviceChangedEvent *dce, xXIKeyInfo* info)
+{
+ uint32_t *kc;
+ int i;
+
+ info->type = XIKeyClass;
+ info->num_keycodes = dce->keys.max_keycode - dce->keys.min_keycode + 1;
+ info->length = sizeof(xXIKeyInfo)/4 + info->num_keycodes;
+ info->sourceid = dce->sourceid;
+
+ kc = (uint32_t*)&info[1];
+ for (i = 0; i < info->num_keycodes; i++)
+ *kc++ = i + dce->keys.min_keycode;
+
+ return info->length * 4;
+}
+
+static int
+appendButtonInfo(DeviceChangedEvent *dce, xXIButtonInfo *info)
+{
+ unsigned char *bits;
+ int mask_len;
+
+ mask_len = bytes_to_int32(bits_to_bytes(dce->buttons.num_buttons));
+
+ info->type = XIButtonClass;
+ info->num_buttons = dce->buttons.num_buttons;
+ info->length = bytes_to_int32(sizeof(xXIButtonInfo)) +
+ info->num_buttons + mask_len;
+ info->sourceid = dce->sourceid;
+
+ bits = (unsigned char*)&info[1];
+ memset(bits, 0, mask_len * 4);
+ /* FIXME: is_down? */
+
+ bits += mask_len * 4;
+ memcpy(bits, dce->buttons.names, dce->buttons.num_buttons * sizeof(Atom));
+
+ return info->length * 4;
+}
+
+static int
+appendValuatorInfo(DeviceChangedEvent *dce, xXIValuatorInfo *info, int axisnumber)
+{
+ info->type = XIValuatorClass;
+ info->length = sizeof(xXIValuatorInfo)/4;
+ info->label = dce->valuators[axisnumber].name;
+ info->min.integral = dce->valuators[axisnumber].min;
+ info->min.frac = 0;
+ info->max.integral = dce->valuators[axisnumber].max;
+ info->max.frac = 0;
+ /* FIXME: value */
+ info->value.integral = 0;
+ info->value.frac = 0;
+ info->resolution = dce->valuators[axisnumber].resolution;
+ info->number = axisnumber;
+ info->mode = dce->valuators[axisnumber].mode;
+ info->sourceid = dce->sourceid;
+
+ return info->length * 4;
+}
+
+static int
+eventToDeviceChanged(DeviceChangedEvent *dce, xEvent **xi)
+{
+ xXIDeviceChangedEvent *dcce;
+ int len = sizeof(xXIDeviceChangedEvent);
+ int nkeys;
+ char *ptr;
+
+ if (dce->buttons.num_buttons)
+ {
+ len += sizeof(xXIButtonInfo);
+ len += dce->buttons.num_buttons * sizeof(Atom); /* button names */
+ len += pad_to_int32(bits_to_bytes(dce->buttons.num_buttons));
+ }
+ if (dce->num_valuators)
+ len += sizeof(xXIValuatorInfo) * dce->num_valuators;
+
+ nkeys = (dce->keys.max_keycode > 0) ?
+ dce->keys.max_keycode - dce->keys.min_keycode + 1 : 0;
+ if (nkeys > 0)
+ {
+ len += sizeof(xXIKeyInfo);
+ len += sizeof(CARD32) * nkeys; /* keycodes */
+ }
+
+ dcce = calloc(1, len);
+ if (!dcce)
+ {
+ ErrorF("[Xi] BadAlloc in SendDeviceChangedEvent.\n");
+ return BadAlloc;
+ }
+
+ dcce->type = GenericEvent;
+ dcce->extension = IReqCode;
+ dcce->evtype = XI_DeviceChanged;
+ dcce->time = dce->time;
+ dcce->deviceid = dce->deviceid;
+ dcce->sourceid = dce->sourceid;
+ dcce->reason = (dce->flags & DEVCHANGE_DEVICE_CHANGE) ? XIDeviceChange : XISlaveSwitch;
+ dcce->num_classes = 0;
+ dcce->length = bytes_to_int32(len - sizeof(xEvent));
+
+ ptr = (char*)&dcce[1];
+ if (dce->buttons.num_buttons)
+ {
+ dcce->num_classes++;
+ ptr += appendButtonInfo(dce, (xXIButtonInfo*)ptr);
+ }
+
+ if (nkeys)
+ {
+ dcce->num_classes++;
+ ptr += appendKeyInfo(dce, (xXIKeyInfo*)ptr);
+ }
+
+ if (dce->num_valuators)
+ {
+ int i;
+
+ dcce->num_classes += dce->num_valuators;
+ for (i = 0; i < dce->num_valuators; i++)
+ ptr += appendValuatorInfo(dce, (xXIValuatorInfo*)ptr, i);
+ }
+
+ *xi = (xEvent*)dcce;
+
+ return Success;
+}
+
+static int count_bits(unsigned char* ptr, int len)
+{
+ int bits = 0;
+ unsigned int i;
+ unsigned char x;
+
+ for (i = 0; i < len; i++)
+ {
+ x = ptr[i];
+ while(x > 0)
+ {
+ bits += (x & 0x1);
+ x >>= 1;
+ }
+ }
+ return bits;
+}
+
+static int
+eventToDeviceEvent(DeviceEvent *ev, xEvent **xi)
+{
+ int len = sizeof(xXIDeviceEvent);
+ xXIDeviceEvent *xde;
+ int i, btlen, vallen;
+ char *ptr;
+ FP3232 *axisval;
+
+ /* FIXME: this should just send the buttons we have, not MAX_BUTTONs. Same
+ * with MAX_VALUATORS below */
+ /* btlen is in 4 byte units */
+ btlen = bytes_to_int32(bits_to_bytes(MAX_BUTTONS));
+ len += btlen * 4; /* buttonmask len */
+
+
+ vallen = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask)/sizeof(ev->valuators.mask[0]));
+ len += vallen * 2 * sizeof(uint32_t); /* axisvalues */
+ vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS));
+ len += vallen * 4; /* valuators mask */
+
+ *xi = calloc(1, len);
+ xde = (xXIDeviceEvent*)*xi;
+ xde->type = GenericEvent;
+ xde->extension = IReqCode;
+ xde->evtype = GetXI2Type((InternalEvent*)ev);
+ xde->time = ev->time;
+ xde->length = bytes_to_int32(len - sizeof(xEvent));
+ xde->detail = ev->detail.button;
+ xde->root = ev->root;
+ xde->buttons_len = btlen;
+ xde->valuators_len = vallen;
+ xde->deviceid = ev->deviceid;
+ xde->sourceid = ev->sourceid;
+ xde->root_x = FP1616(ev->root_x, ev->root_x_frac);
+ xde->root_y = FP1616(ev->root_y, ev->root_y_frac);
+
+ if (ev->key_repeat)
+ xde->flags |= XIKeyRepeat;
+
+ xde->mods.base_mods = ev->mods.base;
+ xde->mods.latched_mods = ev->mods.latched;
+ xde->mods.locked_mods = ev->mods.locked;
+ xde->mods.effective_mods = ev->mods.effective;
+
+ xde->group.base_group = ev->group.base;
+ xde->group.latched_group = ev->group.latched;
+ xde->group.locked_group = ev->group.locked;
+ xde->group.effective_group = ev->group.effective;
+
+ ptr = (char*)&xde[1];
+ for (i = 0; i < sizeof(ev->buttons) * 8; i++)
+ {
+ if (BitIsOn(ev->buttons, i))
+ SetBit(ptr, i);
+ }
+
+ ptr += xde->buttons_len * 4;
+ axisval = (FP3232*)(ptr + xde->valuators_len * 4);
+ for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++)
+ {
+ if (BitIsOn(ev->valuators.mask, i))
+ {
+ SetBit(ptr, i);
+ axisval->integral = ev->valuators.data[i];
+ axisval->frac = ev->valuators.data_frac[i];
+ axisval++;
+ }
+ }
+
+ return Success;
+}
+
+static int
+eventToRawEvent(RawDeviceEvent *ev, xEvent **xi)
+{
+ xXIRawEvent* raw;
+ int vallen, nvals;
+ int i, len = sizeof(xXIRawEvent);
+ char *ptr;
+ FP3232 *axisval;
+
+ nvals = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask));
+ len += nvals * sizeof(FP3232) * 2; /* 8 byte per valuator, once
+ raw, once processed */
+ vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS));
+ len += vallen * 4; /* valuators mask */
+
+ *xi = calloc(1, len);
+ raw = (xXIRawEvent*)*xi;
+ raw->type = GenericEvent;
+ raw->extension = IReqCode;
+ raw->evtype = GetXI2Type((InternalEvent*)ev);
+ raw->time = ev->time;
+ raw->length = bytes_to_int32(len - sizeof(xEvent));
+ raw->detail = ev->detail.button;
+ raw->deviceid = ev->deviceid;
+ raw->valuators_len = vallen;
+
+ ptr = (char*)&raw[1];
+ axisval = (FP3232*)(ptr + raw->valuators_len * 4);
+ for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++)
+ {
+ if (BitIsOn(ev->valuators.mask, i))
+ {
+ SetBit(ptr, i);
+ axisval->integral = ev->valuators.data[i];
+ axisval->frac = ev->valuators.data_frac[i];
+ (axisval + nvals)->integral = ev->valuators.data_raw[i];
+ (axisval + nvals)->frac = ev->valuators.data_raw_frac[i];
+ axisval++;
+ }
+ }
+
+ return Success;
+}
+
+/**
+ * Return the corresponding core type for the given event or 0 if no core
+ * equivalent exists.
+ */
+int
+GetCoreType(InternalEvent *event)
+{
+ int coretype = 0;
+ switch(event->any.type)
+ {
+ case ET_Motion: coretype = MotionNotify; break;
+ case ET_ButtonPress: coretype = ButtonPress; break;
+ case ET_ButtonRelease: coretype = ButtonRelease; break;
+ case ET_KeyPress: coretype = KeyPress; break;
+ case ET_KeyRelease: coretype = KeyRelease; break;
+ default:
+ break;
+ }
+ return coretype;
+}
+
+/**
+ * Return the corresponding XI 1.x type for the given event or 0 if no
+ * equivalent exists.
+ */
+int
+GetXIType(InternalEvent *event)
+{
+ int xitype = 0;
+ switch(event->any.type)
+ {
+ case ET_Motion: xitype = DeviceMotionNotify; break;
+ case ET_ButtonPress: xitype = DeviceButtonPress; break;
+ case ET_ButtonRelease: xitype = DeviceButtonRelease; break;
+ case ET_KeyPress: xitype = DeviceKeyPress; break;
+ case ET_KeyRelease: xitype = DeviceKeyRelease; break;
+ case ET_ProximityIn: xitype = ProximityIn; break;
+ case ET_ProximityOut: xitype = ProximityOut; break;
+ default:
+ break;
+ }
+ return xitype;
+}
+
+/**
+ * Return the corresponding XI 2.x type for the given event or 0 if no
+ * equivalent exists.
+ */
+int
+GetXI2Type(InternalEvent *event)
+{
+ int xi2type = 0;
+
+ switch(event->any.type)
+ {
+ case ET_Motion: xi2type = XI_Motion; break;
+ case ET_ButtonPress: xi2type = XI_ButtonPress; break;
+ case ET_ButtonRelease: xi2type = XI_ButtonRelease; break;
+ case ET_KeyPress: xi2type = XI_KeyPress; break;
+ case ET_KeyRelease: xi2type = XI_KeyRelease; break;
+ case ET_Enter: xi2type = XI_Enter; break;
+ case ET_Leave: xi2type = XI_Leave; break;
+ case ET_Hierarchy: xi2type = XI_HierarchyChanged; break;
+ case ET_DeviceChanged: xi2type = XI_DeviceChanged; break;
+ case ET_RawKeyPress: xi2type = XI_RawKeyPress; break;
+ case ET_RawKeyRelease: xi2type = XI_RawKeyRelease; break;
+ case ET_RawButtonPress: xi2type = XI_RawButtonPress; break;
+ case ET_RawButtonRelease: xi2type = XI_RawButtonRelease; break;
+ case ET_RawMotion: xi2type = XI_RawMotion; break;
+ case ET_FocusIn: xi2type = XI_FocusIn; break;
+ case ET_FocusOut: xi2type = XI_FocusOut; break;
+ default:
+ break;
+ }
+ return xi2type;
+}
diff --git a/xorg-server/dix/getevents.c b/xorg-server/dix/getevents.c
index 5b8e3798d..2361810a0 100644
--- a/xorg-server/dix/getevents.c
+++ b/xorg-server/dix/getevents.c
@@ -1,1324 +1,1314 @@
-/*
- * Copyright © 2006 Nokia Corporation
- * Copyright © 2006-2007 Daniel Stone
- * Copyright © 2008 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: Daniel Stone <daniel@fooishbar.org>
- * Peter Hutterer <peter.hutterer@who-t.net>
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <X11/X.h>
-#include <X11/keysym.h>
-#include <X11/Xproto.h>
-#include <math.h>
-
-#include "misc.h"
-#include "resource.h"
-#include "inputstr.h"
-#include "scrnintstr.h"
-#include "cursorstr.h"
-#include "dixstruct.h"
-#include "globals.h"
-#include "dixevents.h"
-#include "mipointer.h"
-#include "eventstr.h"
-#include "eventconvert.h"
-#include "inpututils.h"
-
-#include <X11/extensions/XKBproto.h>
-#include "xkbsrv.h"
-
-#ifdef PANORAMIX
-#include "panoramiX.h"
-#include "panoramiXsrv.h"
-#endif
-
-#include <X11/extensions/XI.h>
-#include <X11/extensions/XIproto.h>
-#include <pixman.h>
-#include "exglobals.h"
-#include "exevents.h"
-#include "exglobals.h"
-#include "extnsionst.h"
-#include "listdev.h" /* for sizing up DeviceClassesChangedEvent */
-
-/* Number of motion history events to store. */
-#define MOTION_HISTORY_SIZE 256
-
-/* InputEventList is the container list for all input events generated by the
- * DDX. The DDX is expected to call GetEventList() and then pass the list into
- * Get{Pointer|Keyboard}Events.
- */
-EventListPtr InputEventList = NULL;
-int InputEventListLen = 0;
-
-int
-GetEventList(EventListPtr* list)
-{
- *list = InputEventList;
- return InputEventListLen;
-}
-
-/**
- * Pick some arbitrary size for Xi motion history.
- */
-int
-GetMotionHistorySize(void)
-{
- return MOTION_HISTORY_SIZE;
-}
-
-void
-set_button_down(DeviceIntPtr pDev, int button, int type)
-{
- if (type == BUTTON_PROCESSED)
- SetBit(pDev->button->down, button);
- else
- SetBit(pDev->button->postdown, button);
-}
-
-void
-set_button_up(DeviceIntPtr pDev, int button, int type)
-{
- if (type == BUTTON_PROCESSED)
- ClearBit(pDev->button->down, button);
- else
- ClearBit(pDev->button->postdown, button);
-}
-
-Bool
-button_is_down(DeviceIntPtr pDev, int button, int type)
-{
- Bool ret = FALSE;
-
- if (type & BUTTON_PROCESSED)
- ret = ret || BitIsOn(pDev->button->down, button);
- if (type & BUTTON_POSTED)
- ret = ret || BitIsOn(pDev->button->postdown, button);
-
- return ret;
-}
-
-void
-set_key_down(DeviceIntPtr pDev, int key_code, int type)
-{
- if (type == KEY_PROCESSED)
- SetBit(pDev->key->down, key_code);
- else
- SetBit(pDev->key->postdown, key_code);
-}
-
-void
-set_key_up(DeviceIntPtr pDev, int key_code, int type)
-{
- if (type == KEY_PROCESSED)
- ClearBit(pDev->key->down, key_code);
- else
- ClearBit(pDev->key->postdown, key_code);
-}
-
-Bool
-key_is_down(DeviceIntPtr pDev, int key_code, int type)
-{
- Bool ret = FALSE;
-
- if (type & KEY_PROCESSED)
- ret = ret || BitIsOn(pDev->key->down, key_code);
- if (type & KEY_POSTED)
- ret = ret || BitIsOn(pDev->key->postdown, key_code);
-
- return ret;
-}
-
-static Bool
-key_autorepeats(DeviceIntPtr pDev, int key_code)
-{
- return !!(pDev->kbdfeed->ctrl.autoRepeats[key_code >> 3] &
- (1 << (key_code & 7)));
-}
-
-static void
-init_event(DeviceIntPtr dev, DeviceEvent* event, Time ms)
-{
- memset(event, 0, sizeof(DeviceEvent));
- event->header = ET_Internal;
- event->length = sizeof(DeviceEvent);
- event->time = ms;
- event->deviceid = dev->id;
- event->sourceid = dev->id;
-}
-
-static void
-init_raw(DeviceIntPtr dev, RawDeviceEvent *event, Time ms, int type, int detail)
-{
- memset(event, 0, sizeof(RawDeviceEvent));
- event->header = ET_Internal;
- event->length = sizeof(RawDeviceEvent);
- event->type = ET_RawKeyPress - ET_KeyPress + type;
- event->time = ms;
- event->deviceid = dev->id;
- event->sourceid = dev->id;
- event->detail.button = detail;
-}
-
-static void
-set_raw_valuators(RawDeviceEvent *event, ValuatorMask *mask, int32_t* data)
-{
- int i;
-
- for (i = 0; i < valuator_mask_size(mask); i++)
- {
- if (valuator_mask_isset(mask, i))
- {
- SetBit(event->valuators.mask, i);
- data[i] = valuator_mask_get(mask, i);
- }
- }
-}
-
-
-static void
-set_valuators(DeviceIntPtr dev, DeviceEvent* event, ValuatorMask *mask)
-{
- int i;
-
- for (i = 0; i < valuator_mask_size(mask); i++)
- {
- if (valuator_mask_isset(mask, i))
- {
- SetBit(event->valuators.mask, i);
- if (valuator_get_mode(dev, i) == Absolute)
- SetBit(event->valuators.mode, i);
- event->valuators.data[i] = valuator_mask_get(mask, i);
- event->valuators.data_frac[i] =
- dev->last.remainder[i] * (1 << 16) * (1 << 16);
- }
- }
-}
-
-void
-CreateClassesChangedEvent(EventList* event,
- DeviceIntPtr master,
- DeviceIntPtr slave,
- int type)
-{
- int i;
- DeviceChangedEvent *dce;
- CARD32 ms = GetTimeInMillis();
-
- dce = (DeviceChangedEvent*)event->event;
- memset(dce, 0, sizeof(DeviceChangedEvent));
- dce->deviceid = slave->id;
- dce->masterid = master->id;
- dce->header = ET_Internal;
- dce->length = sizeof(DeviceChangedEvent);
- dce->type = ET_DeviceChanged;
- dce->time = ms;
- dce->flags = type;
- dce->flags |= DEVCHANGE_SLAVE_SWITCH;
- dce->sourceid = slave->id;
-
- if (slave->button)
- {
- dce->buttons.num_buttons = slave->button->numButtons;
- for (i = 0; i < dce->buttons.num_buttons; i++)
- dce->buttons.names[i] = slave->button->labels[i];
- }
- if (slave->valuator)
- {
- dce->num_valuators = slave->valuator->numAxes;
- for (i = 0; i < dce->num_valuators; i++)
- {
- dce->valuators[i].min = slave->valuator->axes[i].min_value;
- dce->valuators[i].max = slave->valuator->axes[i].max_value;
- dce->valuators[i].resolution = slave->valuator->axes[i].resolution;
- dce->valuators[i].mode = slave->valuator->axes[i].mode;
- dce->valuators[i].name = slave->valuator->axes[i].label;
- }
- }
- if (slave->key)
- {
- dce->keys.min_keycode = slave->key->xkbInfo->desc->min_key_code;
- dce->keys.max_keycode = slave->key->xkbInfo->desc->max_key_code;
- }
-}
-
-/**
- * Rescale the coord between the two axis ranges.
- */
-static int
-rescaleValuatorAxis(int coord, float remainder, float *remainder_return, AxisInfoPtr from, AxisInfoPtr to,
- int defmax)
-{
- int fmin = 0, tmin = 0, fmax = defmax, tmax = defmax, coord_return;
- float value;
-
- if(from && from->min_value < from->max_value) {
- fmin = from->min_value;
- fmax = from->max_value;
- }
- if(to && to->min_value < to->max_value) {
- tmin = to->min_value;
- tmax = to->max_value;
- }
-
- if(fmin == tmin && fmax == tmax) {
- if (remainder_return)
- *remainder_return = remainder;
- return coord;
- }
-
- if(fmax == fmin) { /* avoid division by 0 */
- if (remainder_return)
- *remainder_return = 0.0;
- return 0;
- }
-
- value = (coord + remainder - fmin) * (tmax - tmin) / (fmax - fmin) + tmin;
- coord_return = lroundf(value);
- if (remainder_return)
- *remainder_return = value - coord_return;
- return coord_return;
-}
-
-/**
- * Update all coordinates when changing to a different SD
- * to ensure that relative reporting will work as expected
- * without loss of precision.
- *
- * pDev->last.valuators will be in absolute device coordinates after this
- * function.
- */
-static void
-updateSlaveDeviceCoords(DeviceIntPtr master, DeviceIntPtr pDev)
-{
- ScreenPtr scr = miPointerGetScreen(pDev);
- int i;
- DeviceIntPtr lastSlave;
-
- /* master->last.valuators[0]/[1] is in screen coords and the actual
- * position of the pointer */
- pDev->last.valuators[0] = master->last.valuators[0];
- pDev->last.valuators[1] = master->last.valuators[1];
-
- if (!pDev->valuator)
- return;
-
- /* scale back to device coordinates */
- if(pDev->valuator->numAxes > 0)
- pDev->last.valuators[0] = rescaleValuatorAxis(pDev->last.valuators[0], pDev->last.remainder[0],
- &pDev->last.remainder[0], NULL, pDev->valuator->axes + 0, scr->width);
- if(pDev->valuator->numAxes > 1)
- pDev->last.valuators[1] = rescaleValuatorAxis(pDev->last.valuators[1], pDev->last.remainder[1],
- &pDev->last.remainder[1], NULL, pDev->valuator->axes + 1, scr->height);
-
- /* calculate the other axis as well based on info from the old
- * slave-device. If the old slave had less axes than this one,
- * last.valuators is reset to 0.
- */
- if ((lastSlave = master->last.slave) && lastSlave->valuator) {
- for (i = 2; i < pDev->valuator->numAxes; i++) {
- if (i >= lastSlave->valuator->numAxes)
- pDev->last.valuators[i] = 0;
- else
- pDev->last.valuators[i] =
- rescaleValuatorAxis(pDev->last.valuators[i],
- pDev->last.remainder[i],
- &pDev->last.remainder[i],
- lastSlave->valuator->axes + i,
- pDev->valuator->axes + i, 0);
- }
- }
-
-}
-
-/**
- * Allocate the motion history buffer.
- */
-void
-AllocateMotionHistory(DeviceIntPtr pDev)
-{
- int size;
- free(pDev->valuator->motion);
-
- if (pDev->valuator->numMotionEvents < 1)
- return;
-
- /* An MD must have a motion history size large enough to keep all
- * potential valuators, plus the respective range of the valuators.
- * 3 * INT32 for (min_val, max_val, curr_val))
- */
- if (IsMaster(pDev))
- size = sizeof(INT32) * 3 * MAX_VALUATORS;
- else {
- ValuatorClassPtr v = pDev->valuator;
- int numAxes;
- /* XI1 doesn't understand mixed mode devices */
- for (numAxes = 0; numAxes < v->numAxes; numAxes++)
- if (valuator_get_mode(pDev, numAxes) != valuator_get_mode(pDev, 0))
- break;
- size = sizeof(INT32) * numAxes;
- }
-
- size += sizeof(Time);
-
- pDev->valuator->motion = calloc(pDev->valuator->numMotionEvents, size);
- pDev->valuator->first_motion = 0;
- pDev->valuator->last_motion = 0;
- if (!pDev->valuator->motion)
- ErrorF("[dix] %s: Failed to alloc motion history (%d bytes).\n",
- pDev->name, size * pDev->valuator->numMotionEvents);
-}
-
-/**
- * Dump the motion history between start and stop into the supplied buffer.
- * Only records the event for a given screen in theory, but in practice, we
- * sort of ignore this.
- *
- * If core is set, we only generate x/y, in INT16, scaled to screen coords.
- */
-int
-GetMotionHistory(DeviceIntPtr pDev, xTimecoord **buff, unsigned long start,
- unsigned long stop, ScreenPtr pScreen, BOOL core)
-{
- char *ibuff = NULL, *obuff;
- int i = 0, ret = 0;
- int j, coord;
- Time current;
- /* The size of a single motion event. */
- int size;
- int dflt;
- AxisInfo from, *to; /* for scaling */
- INT32 *ocbuf, *icbuf; /* pointer to coordinates for copying */
- INT16 *corebuf;
- AxisInfo core_axis = {0};
-
- if (!pDev->valuator || !pDev->valuator->numMotionEvents)
- return 0;
-
- if (core && !pScreen)
- return 0;
-
- if (IsMaster(pDev))
- size = (sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(Time);
- else
- size = (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
-
- *buff = malloc(size * pDev->valuator->numMotionEvents);
- if (!(*buff))
- return 0;
- obuff = (char *)*buff;
-
- for (i = pDev->valuator->first_motion;
- i != pDev->valuator->last_motion;
- i = (i + 1) % pDev->valuator->numMotionEvents) {
- /* We index the input buffer by which element we're accessing, which
- * is not monotonic, and the output buffer by how many events we've
- * written so far. */
- ibuff = (char *) pDev->valuator->motion + (i * size);
- memcpy(&current, ibuff, sizeof(Time));
-
- if (current > stop) {
- return ret;
- }
- else if (current >= start) {
- if (core)
- {
- memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */
-
- icbuf = (INT32*)(ibuff + sizeof(Time));
- corebuf = (INT16*)(obuff + sizeof(Time));
-
- /* fetch x coordinate + range */
- memcpy(&from.min_value, icbuf++, sizeof(INT32));
- memcpy(&from.max_value, icbuf++, sizeof(INT32));
- memcpy(&coord, icbuf++, sizeof(INT32));
-
- /* scale to screen coords */
- to = &core_axis;
- to->max_value = pScreen->width;
- coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, pScreen->width);
-
- memcpy(corebuf, &coord, sizeof(INT16));
- corebuf++;
-
- /* fetch y coordinate + range */
- memcpy(&from.min_value, icbuf++, sizeof(INT32));
- memcpy(&from.max_value, icbuf++, sizeof(INT32));
- memcpy(&coord, icbuf++, sizeof(INT32));
-
- to->max_value = pScreen->height;
- coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, pScreen->height);
- memcpy(corebuf, &coord, sizeof(INT16));
-
- } else if (IsMaster(pDev))
- {
- memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */
-
- ocbuf = (INT32*)(obuff + sizeof(Time));
- icbuf = (INT32*)(ibuff + sizeof(Time));
- for (j = 0; j < MAX_VALUATORS; j++)
- {
- if (j >= pDev->valuator->numAxes)
- break;
-
- /* fetch min/max/coordinate */
- memcpy(&from.min_value, icbuf++, sizeof(INT32));
- memcpy(&from.max_value, icbuf++, sizeof(INT32));
- memcpy(&coord, icbuf++, sizeof(INT32));
-
- to = (j < pDev->valuator->numAxes) ? &pDev->valuator->axes[j] : NULL;
-
- /* x/y scaled to screen if no range is present */
- if (j == 0 && (from.max_value < from.min_value))
- from.max_value = pScreen->width;
- else if (j == 1 && (from.max_value < from.min_value))
- from.max_value = pScreen->height;
-
- if (j == 0 && (to->max_value < to->min_value))
- dflt = pScreen->width;
- else if (j == 1 && (to->max_value < to->min_value))
- dflt = pScreen->height;
- else
- dflt = 0;
-
- /* scale from stored range into current range */
- coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, 0);
- memcpy(ocbuf, &coord, sizeof(INT32));
- ocbuf++;
- }
- } else
- memcpy(obuff, ibuff, size);
-
- /* don't advance by size here. size may be different to the
- * actually written size if the MD has less valuators than MAX */
- if (core)
- obuff += sizeof(INT32) + sizeof(Time);
- else
- obuff += (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
- ret++;
- }
- }
-
- return ret;
-}
-
-
-/**
- * Update the motion history for a specific device, with the list of
- * valuators.
- *
- * Layout of the history buffer:
- * for SDs: [time] [val0] [val1] ... [valn]
- * for MDs: [time] [min_val0] [max_val0] [val0] [min_val1] ... [valn]
- *
- * For events that have some valuators unset:
- * min_val == max_val == val == 0.
- */
-static void
-updateMotionHistory(DeviceIntPtr pDev, CARD32 ms, ValuatorMask *mask,
- int *valuators)
-{
- char *buff = (char *) pDev->valuator->motion;
- ValuatorClassPtr v;
- int i;
-
- if (!pDev->valuator->numMotionEvents)
- return;
-
- v = pDev->valuator;
- if (IsMaster(pDev))
- {
- buff += ((sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(CARD32)) *
- v->last_motion;
-
- memcpy(buff, &ms, sizeof(Time));
- buff += sizeof(Time);
-
- memset(buff, 0, sizeof(INT32) * 3 * MAX_VALUATORS);
-
- for (i = 0; i < v->numAxes; i++)
- {
- /* XI1 doesn't support mixed mode devices */
- if (valuator_get_mode(pDev, i) != valuator_get_mode(pDev, 0))
- break;
- if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i))
- {
- buff += 3 * sizeof(INT32);
- continue;
- }
- memcpy(buff, &v->axes[i].min_value, sizeof(INT32));
- buff += sizeof(INT32);
- memcpy(buff, &v->axes[i].max_value, sizeof(INT32));
- buff += sizeof(INT32);
- memcpy(buff, &valuators[i], sizeof(INT32));
- buff += sizeof(INT32);
- }
- } else
- {
-
- buff += ((sizeof(INT32) * pDev->valuator->numAxes) + sizeof(CARD32)) *
- pDev->valuator->last_motion;
-
- memcpy(buff, &ms, sizeof(Time));
- buff += sizeof(Time);
-
- memset(buff, 0, sizeof(INT32) * pDev->valuator->numAxes);
-
- for (i = 0; i < MAX_VALUATORS; i++)
- {
- if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i))
- {
- buff += sizeof(INT32);
- continue;
- }
- memcpy(buff, &valuators[i], sizeof(INT32));
- buff += sizeof(INT32);
- }
- }
-
- pDev->valuator->last_motion = (pDev->valuator->last_motion + 1) %
- pDev->valuator->numMotionEvents;
- /* If we're wrapping around, just keep the circular buffer going. */
- if (pDev->valuator->first_motion == pDev->valuator->last_motion)
- pDev->valuator->first_motion = (pDev->valuator->first_motion + 1) %
- pDev->valuator->numMotionEvents;
-
- return;
-}
-
-
-/**
- * Returns the maximum number of events GetKeyboardEvents,
- * GetKeyboardValuatorEvents, and GetPointerEvents will ever return.
- *
- * This MUST be absolutely constant, from init until exit.
- */
-int
-GetMaximumEventsNum(void) {
- /* One raw event
- * One device event
- * One possible device changed event
- */
- return 3;
-}
-
-
-/**
- * Clip an axis to its bounds, which are declared in the call to
- * InitValuatorAxisClassStruct.
- */
-static void
-clipAxis(DeviceIntPtr pDev, int axisNum, int *val)
-{
- AxisInfoPtr axis;
-
- if (axisNum >= pDev->valuator->numAxes)
- return;
-
- axis = pDev->valuator->axes + axisNum;
-
- /* If a value range is defined, clip. If not, do nothing */
- if (axis->max_value <= axis->min_value)
- return;
-
- if (*val < axis->min_value)
- *val = axis->min_value;
- if (*val > axis->max_value)
- *val = axis->max_value;
-}
-
-/**
- * Clip every axis in the list of valuators to its bounds.
- */
-static void
-clipValuators(DeviceIntPtr pDev, ValuatorMask *mask)
-{
- int i;
-
- for (i = 0; i < valuator_mask_size(mask); i++)
- if (valuator_mask_isset(mask, i))
- {
- int val = valuator_mask_get(mask, i);
- clipAxis(pDev, i, &val);
- valuator_mask_set(mask, i, val);
- }
-}
-
-/**
- * Create the DCCE event (does not update the master's device state yet, this
- * is done in the event processing).
- * Pull in the coordinates from the MD if necessary.
- *
- * @param events Pointer to a pre-allocated event list.
- * @param dev The slave device that generated an event.
- * @param type Either DEVCHANGE_POINTER_EVENT and/or DEVCHANGE_KEYBOARD_EVENT
- * @param num_events The current number of events, returns the number of
- * events if a DCCE was generated.
- * @return The updated @events pointer.
- */
-EventListPtr
-UpdateFromMaster(EventListPtr events, DeviceIntPtr dev, int type, int *num_events)
-{
- DeviceIntPtr master;
-
- master = GetMaster(dev, (type & DEVCHANGE_POINTER_EVENT) ? MASTER_POINTER : MASTER_KEYBOARD);
-
- if (master && master->last.slave != dev)
- {
- CreateClassesChangedEvent(events, master, dev, type);
- if (IsPointerDevice(master))
- {
- updateSlaveDeviceCoords(master, dev);
- master->last.numValuators = dev->last.numValuators;
- }
- master->last.slave = dev;
- (*num_events)++;
- events++;
- }
- return events;
-}
-
-/**
- * Move the device's pointer to the position given in the valuators.
- *
- * @param dev The device which's pointer is to be moved.
- * @param x Returns the x position of the pointer after the move.
- * @param y Returns the y position of the pointer after the move.
- * @param mask Bit mask of valid valuators.
- * @param valuators Valuator data for each axis between @first and
- * @first+@num.
- */
-static void
-moveAbsolute(DeviceIntPtr dev, int *x, int *y, ValuatorMask *mask)
-{
- int i;
-
- if (valuator_mask_isset(mask, 0))
- *x = valuator_mask_get(mask, 0);
- else
- *x = dev->last.valuators[0];
-
- if (valuator_mask_isset(mask, 1))
- *y = valuator_mask_get(mask, 1);
- else
- *y = dev->last.valuators[1];
-
- clipAxis(dev, 0, x);
- clipAxis(dev, 1, y);
-
- for (i = 2; i < valuator_mask_size(mask); i++)
- {
- if (valuator_mask_isset(mask, i))
- {
- dev->last.valuators[i] = valuator_mask_get(mask, i);
- clipAxis(dev, i, &dev->last.valuators[i]);
- }
- }
-}
-
-/**
- * Move the device's pointer by the values given in @valuators.
- *
- * @param dev The device which's pointer is to be moved.
- * @param x Returns the x position of the pointer after the move.
- * @param y Returns the y position of the pointer after the move.
- * @param mask Bit mask of valid valuators.
- * @param valuators Valuator data for each axis between @first and
- * @first+@num.
- */
-static void
-moveRelative(DeviceIntPtr dev, int *x, int *y, ValuatorMask *mask)
-{
- int i;
-
- *x = dev->last.valuators[0];
- *y = dev->last.valuators[1];
-
- if (valuator_mask_isset(mask, 0))
- *x += valuator_mask_get(mask, 0);
-
- if (valuator_mask_isset(mask, 1))
- *y += valuator_mask_get(mask, 1);
-
- /* if attached, clip both x and y to the defined limits (usually
- * co-ord space limit). If it is attached, we need x/y to go over the
- * limits to be able to change screens. */
- if(dev->valuator && IsMaster(dev) || !IsFloating(dev)) {
- if (valuator_get_mode(dev, 0) == Absolute)
- clipAxis(dev, 0, x);
- if (valuator_get_mode(dev, 1) == Absolute)
- clipAxis(dev, 1, y);
- }
-
- /* calc other axes, clip, drop back into valuators */
- for (i = 2; i < valuator_mask_size(mask); i++)
- {
- if (valuator_mask_isset(mask, i))
- {
- dev->last.valuators[i] += valuator_mask_get(mask, i);
- if (valuator_get_mode(dev, i) == Absolute)
- clipAxis(dev, i, &dev->last.valuators[i]);
- valuator_mask_set(mask, i, dev->last.valuators[i]);
- }
- }
-}
-
-/**
- * Accelerate the data in valuators based on the device's acceleration scheme.
- *
- * @param dev The device which's pointer is to be moved.
- * @param first The first valuator in @valuators
- * @param num Total number of valuators in @valuators.
- * @param valuators Valuator data for each axis between @first and
- * @first+@num.
- * @param ms Current time.
- */
-static void
-accelPointer(DeviceIntPtr dev, int first, int num, int *valuators, CARD32 ms)
-{
- if (dev->valuator->accelScheme.AccelSchemeProc)
- dev->valuator->accelScheme.AccelSchemeProc(dev, first, num, valuators, ms);
-}
-
-/**
- * If we have HW cursors, this actually moves the visible sprite. If not, we
- * just do all the screen crossing, etc.
- *
- * We scale from device to screen coordinates here, call
- * miPointerSetPosition() and then scale back into device coordinates (if
- * needed). miPSP will change x/y if the screen was crossed.
- *
- * @param dev The device to be moved.
- * @param x Pointer to current x-axis value, may be modified.
- * @param y Pointer to current y-axis value, may be modified.
- * @param x_frac Fractional part of current x-axis value, may be modified.
- * @param y_frac Fractional part of current y-axis value, may be modified.
- * @param scr Screen the device's sprite is currently on.
- * @param screenx Screen x coordinate the sprite is on after the update.
- * @param screeny Screen y coordinate the sprite is on after the update.
- * @param screenx_frac Fractional part of screen x coordinate, as above.
- * @param screeny_frac Fractional part of screen y coordinate, as above.
- */
-static void
-positionSprite(DeviceIntPtr dev, int *x, int *y, float x_frac, float y_frac,
- ScreenPtr scr, int *screenx, int *screeny, float *screenx_frac, float *screeny_frac)
-{
- int old_screenx, old_screeny;
-
- /* scale x&y to screen */
- if (dev->valuator && dev->valuator->numAxes > 0) {
- *screenx = rescaleValuatorAxis(*x, x_frac, screenx_frac,
- dev->valuator->axes + 0, NULL, scr->width);
- } else {
- *screenx = dev->last.valuators[0];
- *screenx_frac = dev->last.remainder[0];
- }
-
- if (dev->valuator && dev->valuator->numAxes > 1) {
- *screeny = rescaleValuatorAxis(*y, y_frac, screeny_frac,
- dev->valuator->axes + 1, NULL, scr->height);
- } else {
- *screeny = dev->last.valuators[1];
- *screeny_frac = dev->last.remainder[1];
- }
-
- /* Hit the left screen edge? */
- if (*screenx <= 0 && *screenx_frac < 0.0f)
- {
- *screenx_frac = 0.0f;
- x_frac = 0.0f;
- }
- if (*screeny <= 0 && *screeny_frac < 0.0f)
- {
- *screeny_frac = 0.0f;
- y_frac = 0.0f;
- }
-
-
- old_screenx = *screenx;
- old_screeny = *screeny;
- /* This takes care of crossing screens for us, as well as clipping
- * to the current screen. */
- miPointerSetPosition(dev, screenx, screeny);
-
- if(!IsMaster(dev) || !IsFloating(dev)) {
- DeviceIntPtr master = GetMaster(dev, MASTER_POINTER);
- master->last.valuators[0] = *screenx;
- master->last.valuators[1] = *screeny;
- master->last.remainder[0] = *screenx_frac;
- master->last.remainder[1] = *screeny_frac;
- }
-
- if (dev->valuator)
- {
- /* Crossed screen? Scale back to device coordiantes */
- if(*screenx != old_screenx)
- {
- scr = miPointerGetScreen(dev);
- *x = rescaleValuatorAxis(*screenx, *screenx_frac, &x_frac, NULL,
- dev->valuator->axes + 0, scr->width);
- }
- if(*screeny != old_screeny)
- {
- scr = miPointerGetScreen(dev);
- *y = rescaleValuatorAxis(*screeny, *screeny_frac, &y_frac, NULL,
- dev->valuator->axes + 1, scr->height);
- }
- }
-
- /* dropy x/y (device coordinates) back into valuators for next event */
- dev->last.valuators[0] = *x;
- dev->last.valuators[1] = *y;
- dev->last.remainder[0] = x_frac;
- dev->last.remainder[1] = y_frac;
-}
-
-/**
- * Update the motion history for the device and (if appropriate) for its
- * master device.
- * @param dev Slave device to update.
- * @param mask Bit mask of valid valuators to append to history.
- * @param num Total number of valuators to append to history.
- * @param ms Current time
- */
-static void
-updateHistory(DeviceIntPtr dev, ValuatorMask *mask, CARD32 ms)
-{
- if (!dev->valuator)
- return;
-
- updateMotionHistory(dev, ms, mask, dev->last.valuators);
- if(!IsMaster(dev) || !IsFloating(dev))
- {
- DeviceIntPtr master = GetMaster(dev, MASTER_POINTER);
- updateMotionHistory(master, ms, mask, dev->last.valuators);
- }
-}
-
-/**
- * Convenience wrapper around GetKeyboardValuatorEvents, that takes no
- * valuators.
- */
-int
-GetKeyboardEvents(EventList *events, DeviceIntPtr pDev, int type, int key_code) {
- ValuatorMask mask;
-
- valuator_mask_zero(&mask);
- return GetKeyboardValuatorEvents(events, pDev, type, key_code, &mask);
-}
-
-
-/**
- * Returns a set of InternalEvents for KeyPress/KeyRelease, optionally
- * also with valuator events.
- *
- * events is not NULL-terminated; the return value is the number of events.
- * The DDX is responsible for allocating the event structure in the first
- * place via GetMaximumEventsNum(), and for freeing it.
- */
-int
-GetKeyboardValuatorEvents(EventList *events, DeviceIntPtr pDev, int type,
- int key_code, const ValuatorMask *mask_in) {
- int num_events = 0;
- CARD32 ms = 0;
- DeviceEvent *event;
- RawDeviceEvent *raw;
- ValuatorMask mask;
-
- /* refuse events from disabled devices */
- if (!pDev->enabled)
- return 0;
-
- if (!events ||!pDev->key || !pDev->focus || !pDev->kbdfeed ||
- (type != KeyPress && type != KeyRelease) ||
- (key_code < 8 || key_code > 255))
- return 0;
-
- num_events = 1;
-
- events = UpdateFromMaster(events, pDev, DEVCHANGE_KEYBOARD_EVENT, &num_events);
-
- /* Handle core repeating, via press/release/press/release. */
- if (type == KeyPress && key_is_down(pDev, key_code, KEY_POSTED)) {
- /* If autorepeating is disabled either globally or just for that key,
- * or we have a modifier, don't generate a repeat event. */
- if (!pDev->kbdfeed->ctrl.autoRepeat ||
- !key_autorepeats(pDev, key_code) ||
- pDev->key->xkbInfo->desc->map->modmap[key_code])
- return 0;
- }
-
- ms = GetTimeInMillis();
-
- raw = (RawDeviceEvent*)events->event;
- events++;
- num_events++;
-
- valuator_mask_copy(&mask, mask_in);
-
- init_raw(pDev, raw, ms, type, key_code);
- set_raw_valuators(raw, &mask, raw->valuators.data_raw);
-
- clipValuators(pDev, &mask);
-
- set_raw_valuators(raw, &mask, raw->valuators.data);
-
- event = (DeviceEvent*) events->event;
- init_event(pDev, event, ms);
- event->detail.key = key_code;
-
- if (type == KeyPress) {
- event->type = ET_KeyPress;
- set_key_down(pDev, key_code, KEY_POSTED);
- }
- else if (type == KeyRelease) {
- event->type = ET_KeyRelease;
- set_key_up(pDev, key_code, KEY_POSTED);
- }
-
- clipValuators(pDev, &mask);
-
- set_valuators(pDev, event, &mask);
-
- return num_events;
-}
-
-/**
- * Initialize an event list and fill with 32 byte sized events.
- * This event list is to be passed into GetPointerEvents() and
- * GetKeyboardEvents().
- *
- * @param num_events Number of elements in list.
- */
-EventListPtr
-InitEventList(int num_events)
-{
- EventListPtr events;
- int i;
-
- events = (EventListPtr)calloc(num_events, sizeof(EventList));
- if (!events)
- return NULL;
-
- for (i = 0; i < num_events; i++)
- {
- events[i].evlen = sizeof(InternalEvent);
- events[i].event = calloc(1, sizeof(InternalEvent));
- if (!events[i].event)
- {
- /* rollback */
- while(i--)
- free(events[i].event);
- free(events);
- events = NULL;
- break;
- }
- }
-
- return events;
-}
-
-/**
- * Free an event list.
- *
- * @param list The list to be freed.
- * @param num_events Number of elements in list.
- */
-void
-FreeEventList(EventListPtr list, int num_events)
-{
- if (!list)
- return;
- while(num_events--)
- free(list[num_events].event);
- free(list);
-}
-
-static void
-transformAbsolute(DeviceIntPtr dev, ValuatorMask *mask)
-{
- struct pixman_f_vector p;
-
- /* p' = M * p in homogeneous coordinates */
- p.v[0] = (valuator_mask_isset(mask, 0) ? valuator_mask_get(mask, 0) :
- dev->last.valuators[0]);
- p.v[1] = (valuator_mask_isset(mask, 1) ? valuator_mask_get(mask, 1) :
- dev->last.valuators[1]);
- p.v[2] = 1.0;
-
- pixman_f_transform_point(&dev->transform, &p);
-
- if (lround(p.v[0]) != dev->last.valuators[0])
- valuator_mask_set(mask, 0, lround(p.v[0]));
- if (lround(p.v[1]) != dev->last.valuators[1])
- valuator_mask_set(mask, 1, lround(p.v[1]));
-}
-
-/**
- * Generate a series of InternalEvents (filled into the EventList)
- * representing pointer motion, or button presses.
- *
- * events is not NULL-terminated; the return value is the number of events.
- * The DDX is responsible for allocating the event structure in the first
- * place via InitEventList() and GetMaximumEventsNum(), and for freeing it.
- *
- * In the generated events rootX/Y will be in absolute screen coords and
- * the valuator information in the absolute or relative device coords.
- *
- * last.valuators[x] of the device is always in absolute device coords.
- * last.valuators[x] of the master device is in absolute screen coords.
- *
- * master->last.valuators[x] for x > 2 is undefined.
- */
-int
-GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons,
- int flags, const ValuatorMask *mask_in) {
- int num_events = 1;
- CARD32 ms;
- DeviceEvent *event;
- RawDeviceEvent *raw;
- int x = 0, y = 0, /* device coords */
- cx, cy; /* only screen coordinates */
- float x_frac = 0.0, y_frac = 0.0, cx_frac, cy_frac;
- ScreenPtr scr = miPointerGetScreen(pDev);
- ValuatorMask mask;
-
- /* refuse events from disabled devices */
- if (!pDev->enabled)
- return 0;
-
- if (!scr)
- return 0;
-
- switch (type)
- {
- case MotionNotify:
- if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0)
- return 0;
- break;
- case ButtonPress:
- case ButtonRelease:
- if (!pDev->button || !buttons)
- return 0;
- break;
- default:
- return 0;
- }
-
- ms = GetTimeInMillis(); /* before pointer update to help precision */
-
- events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events);
-
- raw = (RawDeviceEvent*)events->event;
- events++;
- num_events++;
-
- valuator_mask_copy(&mask, mask_in);
-
- init_raw(pDev, raw, ms, type, buttons);
- set_raw_valuators(raw, &mask, raw->valuators.data_raw);
-
- if (flags & POINTER_ABSOLUTE)
- {
- if (flags & POINTER_SCREEN) /* valuators are in screen coords */
- {
- int scaled;
-
- if (valuator_mask_isset(&mask, 0))
- {
- scaled = rescaleValuatorAxis(valuator_mask_get(&mask, 0),
- 0.0, &x_frac, NULL,
- pDev->valuator->axes + 0,
- scr->width);
- valuator_mask_set(&mask, 0, scaled);
- }
- if (valuator_mask_isset(&mask, 1))
- {
- scaled = rescaleValuatorAxis(valuator_mask_get(&mask, 1),
- 0.0, &y_frac, NULL,
- pDev->valuator->axes + 1,
- scr->height);
- valuator_mask_set(&mask, 1, scaled);
- }
- }
-
- transformAbsolute(pDev, &mask);
- moveAbsolute(pDev, &x, &y, &mask);
- } else {
- if (flags & POINTER_ACCELERATE) {
- /* FIXME: Pointer acceleration only requires X and Y values. This
- * should be converted to masked valuators. */
- int vals[2];
- vals[0] = valuator_mask_isset(&mask, 0) ?
- valuator_mask_get(&mask, 0) : 0;
- vals[1] = valuator_mask_isset(&mask, 1) ?
- valuator_mask_get(&mask, 1) : 0;
- accelPointer(pDev, 0, 2, vals, ms);
-
- if (valuator_mask_isset(&mask, 0))
- valuator_mask_set(&mask, 0, vals[0]);
- if (valuator_mask_isset(&mask, 1))
- valuator_mask_set(&mask, 1, vals[1]);
-
- /* The pointer acceleration code modifies the fractional part
- * in-place, so we need to extract this information first */
- x_frac = pDev->last.remainder[0];
- y_frac = pDev->last.remainder[1];
- }
- moveRelative(pDev, &x, &y, &mask);
- }
-
- set_raw_valuators(raw, &mask, raw->valuators.data);
-
- positionSprite(pDev, &x, &y, x_frac, y_frac, scr, &cx, &cy, &cx_frac, &cy_frac);
- updateHistory(pDev, &mask, ms);
-
- /* Update the valuators with the true value sent to the client*/
- if (valuator_mask_isset(&mask, 0))
- valuator_mask_set(&mask, 0, x);
- if (valuator_mask_isset(&mask, 1))
- valuator_mask_set(&mask, 1, y);
-
- clipValuators(pDev, &mask);
-
- event = (DeviceEvent*) events->event;
- init_event(pDev, event, ms);
-
- if (type == MotionNotify) {
- event->type = ET_Motion;
- event->detail.button = 0;
- }
- else {
- if (type == ButtonPress) {
- event->type = ET_ButtonPress;
- set_button_down(pDev, buttons, BUTTON_POSTED);
- }
- else if (type == ButtonRelease) {
- event->type = ET_ButtonRelease;
- set_button_up(pDev, buttons, BUTTON_POSTED);
- }
- event->detail.button = buttons;
- }
-
- event->root_x = cx; /* root_x/y always in screen coords */
- event->root_y = cy;
- event->root_x_frac = cx_frac;
- event->root_y_frac = cy_frac;
-
- set_valuators(pDev, event, &mask);
-
- return num_events;
-}
-
-
-/**
- * Generate ProximityIn/ProximityOut InternalEvents, accompanied by
- * valuators.
- *
- * events is not NULL-terminated; the return value is the number of events.
- * The DDX is responsible for allocating the event structure in the first
- * place via GetMaximumEventsNum(), and for freeing it.
- */
-int
-GetProximityEvents(EventList *events, DeviceIntPtr pDev, int type, const ValuatorMask *mask_in)
-{
- int num_events = 1, i;
- DeviceEvent *event;
- ValuatorMask mask;
-
- /* refuse events from disabled devices */
- if (!pDev->enabled)
- return 0;
-
- /* Sanity checks. */
- if ((type != ProximityIn && type != ProximityOut) || !mask_in)
- return 0;
- if (!pDev->valuator)
- return 0;
-
- valuator_mask_copy(&mask, mask_in);
-
- /* ignore relative axes for proximity. */
- for (i = 0; i < valuator_mask_size(&mask); i++)
- {
- if (valuator_mask_isset(&mask, i) &&
- valuator_get_mode(pDev, i) == Relative)
- valuator_mask_unset(&mask, i);
- }
-
- /* FIXME: posting proximity events with relative valuators only results
- * in an empty event, EventToXI() will fail to convert → no event sent
- * to client. */
-
- events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events);
-
- event = (DeviceEvent *) events->event;
- init_event(pDev, event, GetTimeInMillis());
- event->type = (type == ProximityIn) ? ET_ProximityIn : ET_ProximityOut;
-
- clipValuators(pDev, &mask);
-
- set_valuators(pDev, event, &mask);
-
- return num_events;
-}
-
-/**
- * Synthesize a single motion event for the core pointer.
- *
- * Used in cursor functions, e.g. when cursor confinement changes, and we need
- * to shift the pointer to get it inside the new bounds.
- */
-void
-PostSyntheticMotion(DeviceIntPtr pDev,
- int x,
- int y,
- int screen,
- unsigned long time)
-{
- DeviceEvent ev;
-
-#ifdef PANORAMIX
- /* Translate back to the sprite screen since processInputProc
- will translate from sprite screen to screen 0 upon reentry
- to the DIX layer. */
- if (!noPanoramiXExtension) {
- x += screenInfo.screens[0]->x - screenInfo.screens[screen]->x;
- y += screenInfo.screens[0]->y - screenInfo.screens[screen]->y;
- }
-#endif
-
- memset(&ev, 0, sizeof(DeviceEvent));
- init_event(pDev, &ev, time);
- ev.root_x = x;
- ev.root_y = y;
- ev.type = ET_Motion;
- ev.time = time;
-
- /* FIXME: MD/SD considerations? */
- (*pDev->public.processInputProc)((InternalEvent*)&ev, pDev);
-}
+/*
+ * Copyright © 2006 Nokia Corporation
+ * Copyright © 2006-2007 Daniel Stone
+ * Copyright © 2008 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: Daniel Stone <daniel@fooishbar.org>
+ * Peter Hutterer <peter.hutterer@who-t.net>
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/keysym.h>
+#include <X11/Xproto.h>
+#include <math.h>
+
+#include "misc.h"
+#include "resource.h"
+#include "inputstr.h"
+#include "scrnintstr.h"
+#include "cursorstr.h"
+#include "dixstruct.h"
+#include "globals.h"
+#include "dixevents.h"
+#include "mipointer.h"
+#include "eventstr.h"
+#include "eventconvert.h"
+#include "inpututils.h"
+
+#include <X11/extensions/XKBproto.h>
+#include "xkbsrv.h"
+
+#ifdef PANORAMIX
+#include "panoramiX.h"
+#include "panoramiXsrv.h"
+#endif
+
+#include <X11/extensions/XI.h>
+#include <X11/extensions/XIproto.h>
+#include <pixman.h>
+#include "exglobals.h"
+#include "exevents.h"
+#include "exglobals.h"
+#include "extnsionst.h"
+#include "listdev.h" /* for sizing up DeviceClassesChangedEvent */
+
+/* Number of motion history events to store. */
+#define MOTION_HISTORY_SIZE 256
+
+/* InputEventList is the container list for all input events generated by the
+ * DDX. The DDX is expected to call GetEventList() and then pass the list into
+ * Get{Pointer|Keyboard}Events.
+ */
+EventListPtr InputEventList = NULL;
+int InputEventListLen = 0;
+
+int
+GetEventList(EventListPtr* list)
+{
+ *list = InputEventList;
+ return InputEventListLen;
+}
+
+/**
+ * Pick some arbitrary size for Xi motion history.
+ */
+int
+GetMotionHistorySize(void)
+{
+ return MOTION_HISTORY_SIZE;
+}
+
+void
+set_button_down(DeviceIntPtr pDev, int button, int type)
+{
+ if (type == BUTTON_PROCESSED)
+ SetBit(pDev->button->down, button);
+ else
+ SetBit(pDev->button->postdown, button);
+}
+
+void
+set_button_up(DeviceIntPtr pDev, int button, int type)
+{
+ if (type == BUTTON_PROCESSED)
+ ClearBit(pDev->button->down, button);
+ else
+ ClearBit(pDev->button->postdown, button);
+}
+
+Bool
+button_is_down(DeviceIntPtr pDev, int button, int type)
+{
+ Bool ret = FALSE;
+
+ if (type & BUTTON_PROCESSED)
+ ret = ret || BitIsOn(pDev->button->down, button);
+ if (type & BUTTON_POSTED)
+ ret = ret || BitIsOn(pDev->button->postdown, button);
+
+ return ret;
+}
+
+void
+set_key_down(DeviceIntPtr pDev, int key_code, int type)
+{
+ if (type == KEY_PROCESSED)
+ SetBit(pDev->key->down, key_code);
+ else
+ SetBit(pDev->key->postdown, key_code);
+}
+
+void
+set_key_up(DeviceIntPtr pDev, int key_code, int type)
+{
+ if (type == KEY_PROCESSED)
+ ClearBit(pDev->key->down, key_code);
+ else
+ ClearBit(pDev->key->postdown, key_code);
+}
+
+Bool
+key_is_down(DeviceIntPtr pDev, int key_code, int type)
+{
+ Bool ret = FALSE;
+
+ if (type & KEY_PROCESSED)
+ ret = ret || BitIsOn(pDev->key->down, key_code);
+ if (type & KEY_POSTED)
+ ret = ret || BitIsOn(pDev->key->postdown, key_code);
+
+ return ret;
+}
+
+static Bool
+key_autorepeats(DeviceIntPtr pDev, int key_code)
+{
+ return !!(pDev->kbdfeed->ctrl.autoRepeats[key_code >> 3] &
+ (1 << (key_code & 7)));
+}
+
+static void
+init_event(DeviceIntPtr dev, DeviceEvent* event, Time ms)
+{
+ memset(event, 0, sizeof(DeviceEvent));
+ event->header = ET_Internal;
+ event->length = sizeof(DeviceEvent);
+ event->time = ms;
+ event->deviceid = dev->id;
+ event->sourceid = dev->id;
+}
+
+static void
+init_raw(DeviceIntPtr dev, RawDeviceEvent *event, Time ms, int type, int detail)
+{
+ memset(event, 0, sizeof(RawDeviceEvent));
+ event->header = ET_Internal;
+ event->length = sizeof(RawDeviceEvent);
+ event->type = ET_RawKeyPress - ET_KeyPress + type;
+ event->time = ms;
+ event->deviceid = dev->id;
+ event->sourceid = dev->id;
+ event->detail.button = detail;
+}
+
+static void
+set_raw_valuators(RawDeviceEvent *event, ValuatorMask *mask, int32_t* data)
+{
+ int i;
+
+ for (i = 0; i < valuator_mask_size(mask); i++)
+ {
+ if (valuator_mask_isset(mask, i))
+ {
+ SetBit(event->valuators.mask, i);
+ data[i] = valuator_mask_get(mask, i);
+ }
+ }
+}
+
+
+static void
+set_valuators(DeviceIntPtr dev, DeviceEvent* event, ValuatorMask *mask)
+{
+ int i;
+
+ for (i = 0; i < valuator_mask_size(mask); i++)
+ {
+ if (valuator_mask_isset(mask, i))
+ {
+ SetBit(event->valuators.mask, i);
+ if (valuator_get_mode(dev, i) == Absolute)
+ SetBit(event->valuators.mode, i);
+ event->valuators.data[i] = valuator_mask_get(mask, i);
+ event->valuators.data_frac[i] =
+ dev->last.remainder[i] * (1 << 16) * (1 << 16);
+ }
+ }
+}
+
+void
+CreateClassesChangedEvent(EventList* event,
+ DeviceIntPtr master,
+ DeviceIntPtr slave,
+ int type)
+{
+ int i;
+ DeviceChangedEvent *dce;
+ CARD32 ms = GetTimeInMillis();
+
+ dce = (DeviceChangedEvent*)event->event;
+ memset(dce, 0, sizeof(DeviceChangedEvent));
+ dce->deviceid = slave->id;
+ dce->masterid = master->id;
+ dce->header = ET_Internal;
+ dce->length = sizeof(DeviceChangedEvent);
+ dce->type = ET_DeviceChanged;
+ dce->time = ms;
+ dce->flags = type;
+ dce->flags |= DEVCHANGE_SLAVE_SWITCH;
+ dce->sourceid = slave->id;
+
+ if (slave->button)
+ {
+ dce->buttons.num_buttons = slave->button->numButtons;
+ for (i = 0; i < dce->buttons.num_buttons; i++)
+ dce->buttons.names[i] = slave->button->labels[i];
+ }
+ if (slave->valuator)
+ {
+ dce->num_valuators = slave->valuator->numAxes;
+ for (i = 0; i < dce->num_valuators; i++)
+ {
+ dce->valuators[i].min = slave->valuator->axes[i].min_value;
+ dce->valuators[i].max = slave->valuator->axes[i].max_value;
+ dce->valuators[i].resolution = slave->valuator->axes[i].resolution;
+ dce->valuators[i].mode = slave->valuator->axes[i].mode;
+ dce->valuators[i].name = slave->valuator->axes[i].label;
+ }
+ }
+ if (slave->key)
+ {
+ dce->keys.min_keycode = slave->key->xkbInfo->desc->min_key_code;
+ dce->keys.max_keycode = slave->key->xkbInfo->desc->max_key_code;
+ }
+}
+
+/**
+ * Rescale the coord between the two axis ranges.
+ */
+static int
+rescaleValuatorAxis(int coord, float remainder, float *remainder_return, AxisInfoPtr from, AxisInfoPtr to,
+ int defmax)
+{
+ int fmin = 0, tmin = 0, fmax = defmax, tmax = defmax, coord_return;
+ float value;
+
+ if(from && from->min_value < from->max_value) {
+ fmin = from->min_value;
+ fmax = from->max_value;
+ }
+ if(to && to->min_value < to->max_value) {
+ tmin = to->min_value;
+ tmax = to->max_value;
+ }
+
+ if(fmin == tmin && fmax == tmax) {
+ if (remainder_return)
+ *remainder_return = remainder;
+ return coord;
+ }
+
+ if(fmax == fmin) { /* avoid division by 0 */
+ if (remainder_return)
+ *remainder_return = 0.0;
+ return 0;
+ }
+
+ value = (coord + remainder - fmin) * (tmax - tmin) / (fmax - fmin) + tmin;
+ coord_return = lroundf(value);
+ if (remainder_return)
+ *remainder_return = value - coord_return;
+ return coord_return;
+}
+
+/**
+ * Update all coordinates when changing to a different SD
+ * to ensure that relative reporting will work as expected
+ * without loss of precision.
+ *
+ * pDev->last.valuators will be in absolute device coordinates after this
+ * function.
+ */
+static void
+updateSlaveDeviceCoords(DeviceIntPtr master, DeviceIntPtr pDev)
+{
+ ScreenPtr scr = miPointerGetScreen(pDev);
+ int i;
+ DeviceIntPtr lastSlave;
+
+ /* master->last.valuators[0]/[1] is in screen coords and the actual
+ * position of the pointer */
+ pDev->last.valuators[0] = master->last.valuators[0];
+ pDev->last.valuators[1] = master->last.valuators[1];
+
+ if (!pDev->valuator)
+ return;
+
+ /* scale back to device coordinates */
+ if(pDev->valuator->numAxes > 0)
+ pDev->last.valuators[0] = rescaleValuatorAxis(pDev->last.valuators[0], pDev->last.remainder[0],
+ &pDev->last.remainder[0], NULL, pDev->valuator->axes + 0, scr->width);
+ if(pDev->valuator->numAxes > 1)
+ pDev->last.valuators[1] = rescaleValuatorAxis(pDev->last.valuators[1], pDev->last.remainder[1],
+ &pDev->last.remainder[1], NULL, pDev->valuator->axes + 1, scr->height);
+
+ /* calculate the other axis as well based on info from the old
+ * slave-device. If the old slave had less axes than this one,
+ * last.valuators is reset to 0.
+ */
+ if ((lastSlave = master->last.slave) && lastSlave->valuator) {
+ for (i = 2; i < pDev->valuator->numAxes; i++) {
+ if (i >= lastSlave->valuator->numAxes)
+ pDev->last.valuators[i] = 0;
+ else
+ pDev->last.valuators[i] =
+ rescaleValuatorAxis(pDev->last.valuators[i],
+ pDev->last.remainder[i],
+ &pDev->last.remainder[i],
+ lastSlave->valuator->axes + i,
+ pDev->valuator->axes + i, 0);
+ }
+ }
+
+}
+
+/**
+ * Allocate the motion history buffer.
+ */
+void
+AllocateMotionHistory(DeviceIntPtr pDev)
+{
+ int size;
+ free(pDev->valuator->motion);
+
+ if (pDev->valuator->numMotionEvents < 1)
+ return;
+
+ /* An MD must have a motion history size large enough to keep all
+ * potential valuators, plus the respective range of the valuators.
+ * 3 * INT32 for (min_val, max_val, curr_val))
+ */
+ if (IsMaster(pDev))
+ size = sizeof(INT32) * 3 * MAX_VALUATORS;
+ else {
+ ValuatorClassPtr v = pDev->valuator;
+ int numAxes;
+ /* XI1 doesn't understand mixed mode devices */
+ for (numAxes = 0; numAxes < v->numAxes; numAxes++)
+ if (valuator_get_mode(pDev, numAxes) != valuator_get_mode(pDev, 0))
+ break;
+ size = sizeof(INT32) * numAxes;
+ }
+
+ size += sizeof(Time);
+
+ pDev->valuator->motion = calloc(pDev->valuator->numMotionEvents, size);
+ pDev->valuator->first_motion = 0;
+ pDev->valuator->last_motion = 0;
+ if (!pDev->valuator->motion)
+ ErrorF("[dix] %s: Failed to alloc motion history (%d bytes).\n",
+ pDev->name, size * pDev->valuator->numMotionEvents);
+}
+
+/**
+ * Dump the motion history between start and stop into the supplied buffer.
+ * Only records the event for a given screen in theory, but in practice, we
+ * sort of ignore this.
+ *
+ * If core is set, we only generate x/y, in INT16, scaled to screen coords.
+ */
+int
+GetMotionHistory(DeviceIntPtr pDev, xTimecoord **buff, unsigned long start,
+ unsigned long stop, ScreenPtr pScreen, BOOL core)
+{
+ char *ibuff = NULL, *obuff;
+ int i = 0, ret = 0;
+ int j, coord;
+ Time current;
+ /* The size of a single motion event. */
+ int size;
+ int dflt;
+ AxisInfo from, *to; /* for scaling */
+ INT32 *ocbuf, *icbuf; /* pointer to coordinates for copying */
+ INT16 *corebuf;
+ AxisInfo core_axis = {0};
+
+ if (!pDev->valuator || !pDev->valuator->numMotionEvents)
+ return 0;
+
+ if (core && !pScreen)
+ return 0;
+
+ if (IsMaster(pDev))
+ size = (sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(Time);
+ else
+ size = (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
+
+ *buff = malloc(size * pDev->valuator->numMotionEvents);
+ if (!(*buff))
+ return 0;
+ obuff = (char *)*buff;
+
+ for (i = pDev->valuator->first_motion;
+ i != pDev->valuator->last_motion;
+ i = (i + 1) % pDev->valuator->numMotionEvents) {
+ /* We index the input buffer by which element we're accessing, which
+ * is not monotonic, and the output buffer by how many events we've
+ * written so far. */
+ ibuff = (char *) pDev->valuator->motion + (i * size);
+ memcpy(&current, ibuff, sizeof(Time));
+
+ if (current > stop) {
+ return ret;
+ }
+ else if (current >= start) {
+ if (core)
+ {
+ memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */
+
+ icbuf = (INT32*)(ibuff + sizeof(Time));
+ corebuf = (INT16*)(obuff + sizeof(Time));
+
+ /* fetch x coordinate + range */
+ memcpy(&from.min_value, icbuf++, sizeof(INT32));
+ memcpy(&from.max_value, icbuf++, sizeof(INT32));
+ memcpy(&coord, icbuf++, sizeof(INT32));
+
+ /* scale to screen coords */
+ to = &core_axis;
+ to->max_value = pScreen->width;
+ coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, pScreen->width);
+
+ memcpy(corebuf, &coord, sizeof(INT16));
+ corebuf++;
+
+ /* fetch y coordinate + range */
+ memcpy(&from.min_value, icbuf++, sizeof(INT32));
+ memcpy(&from.max_value, icbuf++, sizeof(INT32));
+ memcpy(&coord, icbuf++, sizeof(INT32));
+
+ to->max_value = pScreen->height;
+ coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, pScreen->height);
+ memcpy(corebuf, &coord, sizeof(INT16));
+
+ } else if (IsMaster(pDev))
+ {
+ memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */
+
+ ocbuf = (INT32*)(obuff + sizeof(Time));
+ icbuf = (INT32*)(ibuff + sizeof(Time));
+ for (j = 0; j < MAX_VALUATORS; j++)
+ {
+ if (j >= pDev->valuator->numAxes)
+ break;
+
+ /* fetch min/max/coordinate */
+ memcpy(&from.min_value, icbuf++, sizeof(INT32));
+ memcpy(&from.max_value, icbuf++, sizeof(INT32));
+ memcpy(&coord, icbuf++, sizeof(INT32));
+
+ to = (j < pDev->valuator->numAxes) ? &pDev->valuator->axes[j] : NULL;
+
+ /* x/y scaled to screen if no range is present */
+ if (j == 0 && (from.max_value < from.min_value))
+ from.max_value = pScreen->width;
+ else if (j == 1 && (from.max_value < from.min_value))
+ from.max_value = pScreen->height;
+
+ if (j == 0 && (to->max_value < to->min_value))
+ dflt = pScreen->width;
+ else if (j == 1 && (to->max_value < to->min_value))
+ dflt = pScreen->height;
+ else
+ dflt = 0;
+
+ /* scale from stored range into current range */
+ coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, 0);
+ memcpy(ocbuf, &coord, sizeof(INT32));
+ ocbuf++;
+ }
+ } else
+ memcpy(obuff, ibuff, size);
+
+ /* don't advance by size here. size may be different to the
+ * actually written size if the MD has less valuators than MAX */
+ if (core)
+ obuff += sizeof(INT32) + sizeof(Time);
+ else
+ obuff += (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
+ ret++;
+ }
+ }
+
+ return ret;
+}
+
+
+/**
+ * Update the motion history for a specific device, with the list of
+ * valuators.
+ *
+ * Layout of the history buffer:
+ * for SDs: [time] [val0] [val1] ... [valn]
+ * for MDs: [time] [min_val0] [max_val0] [val0] [min_val1] ... [valn]
+ *
+ * For events that have some valuators unset:
+ * min_val == max_val == val == 0.
+ */
+static void
+updateMotionHistory(DeviceIntPtr pDev, CARD32 ms, ValuatorMask *mask,
+ int *valuators)
+{
+ char *buff = (char *) pDev->valuator->motion;
+ ValuatorClassPtr v;
+ int i;
+
+ if (!pDev->valuator->numMotionEvents)
+ return;
+
+ v = pDev->valuator;
+ if (IsMaster(pDev))
+ {
+ buff += ((sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(CARD32)) *
+ v->last_motion;
+
+ memcpy(buff, &ms, sizeof(Time));
+ buff += sizeof(Time);
+
+ memset(buff, 0, sizeof(INT32) * 3 * MAX_VALUATORS);
+
+ for (i = 0; i < v->numAxes; i++)
+ {
+ /* XI1 doesn't support mixed mode devices */
+ if (valuator_get_mode(pDev, i) != valuator_get_mode(pDev, 0))
+ break;
+ if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i))
+ {
+ buff += 3 * sizeof(INT32);
+ continue;
+ }
+ memcpy(buff, &v->axes[i].min_value, sizeof(INT32));
+ buff += sizeof(INT32);
+ memcpy(buff, &v->axes[i].max_value, sizeof(INT32));
+ buff += sizeof(INT32);
+ memcpy(buff, &valuators[i], sizeof(INT32));
+ buff += sizeof(INT32);
+ }
+ } else
+ {
+
+ buff += ((sizeof(INT32) * pDev->valuator->numAxes) + sizeof(CARD32)) *
+ pDev->valuator->last_motion;
+
+ memcpy(buff, &ms, sizeof(Time));
+ buff += sizeof(Time);
+
+ memset(buff, 0, sizeof(INT32) * pDev->valuator->numAxes);
+
+ for (i = 0; i < MAX_VALUATORS; i++)
+ {
+ if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i))
+ {
+ buff += sizeof(INT32);
+ continue;
+ }
+ memcpy(buff, &valuators[i], sizeof(INT32));
+ buff += sizeof(INT32);
+ }
+ }
+
+ pDev->valuator->last_motion = (pDev->valuator->last_motion + 1) %
+ pDev->valuator->numMotionEvents;
+ /* If we're wrapping around, just keep the circular buffer going. */
+ if (pDev->valuator->first_motion == pDev->valuator->last_motion)
+ pDev->valuator->first_motion = (pDev->valuator->first_motion + 1) %
+ pDev->valuator->numMotionEvents;
+
+ return;
+}
+
+
+/**
+ * Returns the maximum number of events GetKeyboardEvents,
+ * GetKeyboardValuatorEvents, and GetPointerEvents will ever return.
+ *
+ * This MUST be absolutely constant, from init until exit.
+ */
+int
+GetMaximumEventsNum(void) {
+ /* One raw event
+ * One device event
+ * One possible device changed event
+ */
+ return 3;
+}
+
+
+/**
+ * Clip an axis to its bounds, which are declared in the call to
+ * InitValuatorAxisClassStruct.
+ */
+static void
+clipAxis(DeviceIntPtr pDev, int axisNum, int *val)
+{
+ AxisInfoPtr axis;
+
+ if (axisNum >= pDev->valuator->numAxes)
+ return;
+
+ axis = pDev->valuator->axes + axisNum;
+
+ /* If a value range is defined, clip. If not, do nothing */
+ if (axis->max_value <= axis->min_value)
+ return;
+
+ if (*val < axis->min_value)
+ *val = axis->min_value;
+ if (*val > axis->max_value)
+ *val = axis->max_value;
+}
+
+/**
+ * Clip every axis in the list of valuators to its bounds.
+ */
+static void
+clipValuators(DeviceIntPtr pDev, ValuatorMask *mask)
+{
+ int i;
+
+ for (i = 0; i < valuator_mask_size(mask); i++)
+ if (valuator_mask_isset(mask, i))
+ {
+ int val = valuator_mask_get(mask, i);
+ clipAxis(pDev, i, &val);
+ valuator_mask_set(mask, i, val);
+ }
+}
+
+/**
+ * Create the DCCE event (does not update the master's device state yet, this
+ * is done in the event processing).
+ * Pull in the coordinates from the MD if necessary.
+ *
+ * @param events Pointer to a pre-allocated event list.
+ * @param dev The slave device that generated an event.
+ * @param type Either DEVCHANGE_POINTER_EVENT and/or DEVCHANGE_KEYBOARD_EVENT
+ * @param num_events The current number of events, returns the number of
+ * events if a DCCE was generated.
+ * @return The updated @events pointer.
+ */
+EventListPtr
+UpdateFromMaster(EventListPtr events, DeviceIntPtr dev, int type, int *num_events)
+{
+ DeviceIntPtr master;
+
+ master = GetMaster(dev, (type & DEVCHANGE_POINTER_EVENT) ? MASTER_POINTER : MASTER_KEYBOARD);
+
+ if (master && master->last.slave != dev)
+ {
+ CreateClassesChangedEvent(events, master, dev, type);
+ if (IsPointerDevice(master))
+ {
+ updateSlaveDeviceCoords(master, dev);
+ master->last.numValuators = dev->last.numValuators;
+ }
+ master->last.slave = dev;
+ (*num_events)++;
+ events++;
+ }
+ return events;
+}
+
+/**
+ * Move the device's pointer to the position given in the valuators.
+ *
+ * @param dev The device which's pointer is to be moved.
+ * @param x Returns the x position of the pointer after the move.
+ * @param y Returns the y position of the pointer after the move.
+ * @param mask Bit mask of valid valuators.
+ * @param valuators Valuator data for each axis between @first and
+ * @first+@num.
+ */
+static void
+moveAbsolute(DeviceIntPtr dev, int *x, int *y, ValuatorMask *mask)
+{
+ int i;
+
+ if (valuator_mask_isset(mask, 0))
+ *x = valuator_mask_get(mask, 0);
+ else
+ *x = dev->last.valuators[0];
+
+ if (valuator_mask_isset(mask, 1))
+ *y = valuator_mask_get(mask, 1);
+ else
+ *y = dev->last.valuators[1];
+
+ clipAxis(dev, 0, x);
+ clipAxis(dev, 1, y);
+
+ for (i = 2; i < valuator_mask_size(mask); i++)
+ {
+ if (valuator_mask_isset(mask, i))
+ {
+ dev->last.valuators[i] = valuator_mask_get(mask, i);
+ clipAxis(dev, i, &dev->last.valuators[i]);
+ }
+ }
+}
+
+/**
+ * Move the device's pointer by the values given in @valuators.
+ *
+ * @param dev The device which's pointer is to be moved.
+ * @param x Returns the x position of the pointer after the move.
+ * @param y Returns the y position of the pointer after the move.
+ * @param mask Bit mask of valid valuators.
+ * @param valuators Valuator data for each axis between @first and
+ * @first+@num.
+ */
+static void
+moveRelative(DeviceIntPtr dev, int *x, int *y, ValuatorMask *mask)
+{
+ int i;
+
+ *x = dev->last.valuators[0];
+ *y = dev->last.valuators[1];
+
+ if (valuator_mask_isset(mask, 0))
+ *x += valuator_mask_get(mask, 0);
+
+ if (valuator_mask_isset(mask, 1))
+ *y += valuator_mask_get(mask, 1);
+
+ /* if attached, clip both x and y to the defined limits (usually
+ * co-ord space limit). If it is attached, we need x/y to go over the
+ * limits to be able to change screens. */
+ if (dev->valuator && (IsMaster(dev) || !IsFloating(dev))) {
+ if (valuator_get_mode(dev, 0) == Absolute)
+ clipAxis(dev, 0, x);
+ if (valuator_get_mode(dev, 1) == Absolute)
+ clipAxis(dev, 1, y);
+ }
+
+ /* calc other axes, clip, drop back into valuators */
+ for (i = 2; i < valuator_mask_size(mask); i++)
+ {
+ if (valuator_mask_isset(mask, i))
+ {
+ dev->last.valuators[i] += valuator_mask_get(mask, i);
+ if (valuator_get_mode(dev, i) == Absolute)
+ clipAxis(dev, i, &dev->last.valuators[i]);
+ valuator_mask_set(mask, i, dev->last.valuators[i]);
+ }
+ }
+}
+
+/**
+ * Accelerate the data in valuators based on the device's acceleration scheme.
+ *
+ * @param dev The device which's pointer is to be moved.
+ * @param valuators Valuator mask
+ * @param ms Current time.
+ */
+static void
+accelPointer(DeviceIntPtr dev, ValuatorMask* valuators, CARD32 ms)
+{
+ if (dev->valuator->accelScheme.AccelSchemeProc)
+ dev->valuator->accelScheme.AccelSchemeProc(dev, valuators, ms);
+}
+
+/**
+ * If we have HW cursors, this actually moves the visible sprite. If not, we
+ * just do all the screen crossing, etc.
+ *
+ * We scale from device to screen coordinates here, call
+ * miPointerSetPosition() and then scale back into device coordinates (if
+ * needed). miPSP will change x/y if the screen was crossed.
+ *
+ * The coordinates provided are always absolute. The parameter mode whether
+ * it was relative or absolute movement that landed us at those coordinates.
+ *
+ * @param dev The device to be moved.
+ * @param mode Movement mode (Absolute or Relative)
+ * @param x Pointer to current x-axis value, may be modified.
+ * @param y Pointer to current y-axis value, may be modified.
+ * @param x_frac Fractional part of current x-axis value, may be modified.
+ * @param y_frac Fractional part of current y-axis value, may be modified.
+ * @param scr Screen the device's sprite is currently on.
+ * @param screenx Screen x coordinate the sprite is on after the update.
+ * @param screeny Screen y coordinate the sprite is on after the update.
+ * @param screenx_frac Fractional part of screen x coordinate, as above.
+ * @param screeny_frac Fractional part of screen y coordinate, as above.
+ */
+static void
+positionSprite(DeviceIntPtr dev, int mode,
+ int *x, int *y, float x_frac, float y_frac,
+ ScreenPtr scr, int *screenx, int *screeny, float *screenx_frac, float *screeny_frac)
+{
+ int old_screenx, old_screeny;
+
+ /* scale x&y to screen */
+ if (dev->valuator && dev->valuator->numAxes > 0) {
+ *screenx = rescaleValuatorAxis(*x, x_frac, screenx_frac,
+ dev->valuator->axes + 0, NULL, scr->width);
+ } else {
+ *screenx = dev->last.valuators[0];
+ *screenx_frac = dev->last.remainder[0];
+ }
+
+ if (dev->valuator && dev->valuator->numAxes > 1) {
+ *screeny = rescaleValuatorAxis(*y, y_frac, screeny_frac,
+ dev->valuator->axes + 1, NULL, scr->height);
+ } else {
+ *screeny = dev->last.valuators[1];
+ *screeny_frac = dev->last.remainder[1];
+ }
+
+ /* Hit the left screen edge? */
+ if (*screenx <= 0 && *screenx_frac < 0.0f)
+ {
+ *screenx_frac = 0.0f;
+ x_frac = 0.0f;
+ }
+ if (*screeny <= 0 && *screeny_frac < 0.0f)
+ {
+ *screeny_frac = 0.0f;
+ y_frac = 0.0f;
+ }
+
+
+ old_screenx = *screenx;
+ old_screeny = *screeny;
+ /* This takes care of crossing screens for us, as well as clipping
+ * to the current screen. */
+ miPointerSetPosition(dev, mode, screenx, screeny);
+
+ if(!IsMaster(dev) || !IsFloating(dev)) {
+ DeviceIntPtr master = GetMaster(dev, MASTER_POINTER);
+ master->last.valuators[0] = *screenx;
+ master->last.valuators[1] = *screeny;
+ master->last.remainder[0] = *screenx_frac;
+ master->last.remainder[1] = *screeny_frac;
+ }
+
+ if (dev->valuator)
+ {
+ /* Crossed screen? Scale back to device coordiantes */
+ if(*screenx != old_screenx)
+ {
+ scr = miPointerGetScreen(dev);
+ *x = rescaleValuatorAxis(*screenx, *screenx_frac, &x_frac, NULL,
+ dev->valuator->axes + 0, scr->width);
+ }
+ if(*screeny != old_screeny)
+ {
+ scr = miPointerGetScreen(dev);
+ *y = rescaleValuatorAxis(*screeny, *screeny_frac, &y_frac, NULL,
+ dev->valuator->axes + 1, scr->height);
+ }
+ }
+
+ /* dropy x/y (device coordinates) back into valuators for next event */
+ dev->last.valuators[0] = *x;
+ dev->last.valuators[1] = *y;
+ dev->last.remainder[0] = x_frac;
+ dev->last.remainder[1] = y_frac;
+}
+
+/**
+ * Update the motion history for the device and (if appropriate) for its
+ * master device.
+ * @param dev Slave device to update.
+ * @param mask Bit mask of valid valuators to append to history.
+ * @param num Total number of valuators to append to history.
+ * @param ms Current time
+ */
+static void
+updateHistory(DeviceIntPtr dev, ValuatorMask *mask, CARD32 ms)
+{
+ if (!dev->valuator)
+ return;
+
+ updateMotionHistory(dev, ms, mask, dev->last.valuators);
+ if(!IsMaster(dev) || !IsFloating(dev))
+ {
+ DeviceIntPtr master = GetMaster(dev, MASTER_POINTER);
+ updateMotionHistory(master, ms, mask, dev->last.valuators);
+ }
+}
+
+/**
+ * Convenience wrapper around GetKeyboardValuatorEvents, that takes no
+ * valuators.
+ */
+int
+GetKeyboardEvents(EventList *events, DeviceIntPtr pDev, int type, int key_code) {
+ ValuatorMask mask;
+
+ valuator_mask_zero(&mask);
+ return GetKeyboardValuatorEvents(events, pDev, type, key_code, &mask);
+}
+
+
+/**
+ * Returns a set of InternalEvents for KeyPress/KeyRelease, optionally
+ * also with valuator events.
+ *
+ * events is not NULL-terminated; the return value is the number of events.
+ * The DDX is responsible for allocating the event structure in the first
+ * place via GetMaximumEventsNum(), and for freeing it.
+ */
+int
+GetKeyboardValuatorEvents(EventList *events, DeviceIntPtr pDev, int type,
+ int key_code, const ValuatorMask *mask_in) {
+ int num_events = 0;
+ CARD32 ms = 0;
+ DeviceEvent *event;
+ RawDeviceEvent *raw;
+ ValuatorMask mask;
+
+ /* refuse events from disabled devices */
+ if (!pDev->enabled)
+ return 0;
+
+ if (!events ||!pDev->key || !pDev->focus || !pDev->kbdfeed ||
+ (type != KeyPress && type != KeyRelease) ||
+ (key_code < 8 || key_code > 255))
+ return 0;
+
+ num_events = 1;
+
+ events = UpdateFromMaster(events, pDev, DEVCHANGE_KEYBOARD_EVENT, &num_events);
+
+ /* Handle core repeating, via press/release/press/release. */
+ if (type == KeyPress && key_is_down(pDev, key_code, KEY_POSTED)) {
+ /* If autorepeating is disabled either globally or just for that key,
+ * or we have a modifier, don't generate a repeat event. */
+ if (!pDev->kbdfeed->ctrl.autoRepeat ||
+ !key_autorepeats(pDev, key_code) ||
+ pDev->key->xkbInfo->desc->map->modmap[key_code])
+ return 0;
+ }
+
+ ms = GetTimeInMillis();
+
+ raw = (RawDeviceEvent*)events->event;
+ events++;
+ num_events++;
+
+ valuator_mask_copy(&mask, mask_in);
+
+ init_raw(pDev, raw, ms, type, key_code);
+ set_raw_valuators(raw, &mask, raw->valuators.data_raw);
+
+ clipValuators(pDev, &mask);
+
+ set_raw_valuators(raw, &mask, raw->valuators.data);
+
+ event = (DeviceEvent*) events->event;
+ init_event(pDev, event, ms);
+ event->detail.key = key_code;
+
+ if (type == KeyPress) {
+ event->type = ET_KeyPress;
+ set_key_down(pDev, key_code, KEY_POSTED);
+ }
+ else if (type == KeyRelease) {
+ event->type = ET_KeyRelease;
+ set_key_up(pDev, key_code, KEY_POSTED);
+ }
+
+ clipValuators(pDev, &mask);
+
+ set_valuators(pDev, event, &mask);
+
+ return num_events;
+}
+
+/**
+ * Initialize an event list and fill with 32 byte sized events.
+ * This event list is to be passed into GetPointerEvents() and
+ * GetKeyboardEvents().
+ *
+ * @param num_events Number of elements in list.
+ */
+EventListPtr
+InitEventList(int num_events)
+{
+ EventListPtr events;
+ int i;
+
+ events = (EventListPtr)calloc(num_events, sizeof(EventList));
+ if (!events)
+ return NULL;
+
+ for (i = 0; i < num_events; i++)
+ {
+ events[i].evlen = sizeof(InternalEvent);
+ events[i].event = calloc(1, sizeof(InternalEvent));
+ if (!events[i].event)
+ {
+ /* rollback */
+ while(i--)
+ free(events[i].event);
+ free(events);
+ events = NULL;
+ break;
+ }
+ }
+
+ return events;
+}
+
+/**
+ * Free an event list.
+ *
+ * @param list The list to be freed.
+ * @param num_events Number of elements in list.
+ */
+void
+FreeEventList(EventListPtr list, int num_events)
+{
+ if (!list)
+ return;
+ while(num_events--)
+ free(list[num_events].event);
+ free(list);
+}
+
+static void
+transformAbsolute(DeviceIntPtr dev, ValuatorMask *mask)
+{
+ struct pixman_f_vector p;
+
+ /* p' = M * p in homogeneous coordinates */
+ p.v[0] = (valuator_mask_isset(mask, 0) ? valuator_mask_get(mask, 0) :
+ dev->last.valuators[0]);
+ p.v[1] = (valuator_mask_isset(mask, 1) ? valuator_mask_get(mask, 1) :
+ dev->last.valuators[1]);
+ p.v[2] = 1.0;
+
+ pixman_f_transform_point(&dev->transform, &p);
+
+ if (lround(p.v[0]) != dev->last.valuators[0])
+ valuator_mask_set(mask, 0, lround(p.v[0]));
+ if (lround(p.v[1]) != dev->last.valuators[1])
+ valuator_mask_set(mask, 1, lround(p.v[1]));
+}
+
+/**
+ * Generate a series of InternalEvents (filled into the EventList)
+ * representing pointer motion, or button presses.
+ *
+ * events is not NULL-terminated; the return value is the number of events.
+ * The DDX is responsible for allocating the event structure in the first
+ * place via InitEventList() and GetMaximumEventsNum(), and for freeing it.
+ *
+ * In the generated events rootX/Y will be in absolute screen coords and
+ * the valuator information in the absolute or relative device coords.
+ *
+ * last.valuators[x] of the device is always in absolute device coords.
+ * last.valuators[x] of the master device is in absolute screen coords.
+ *
+ * master->last.valuators[x] for x > 2 is undefined.
+ */
+int
+GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons,
+ int flags, const ValuatorMask *mask_in) {
+ int num_events = 1;
+ CARD32 ms;
+ DeviceEvent *event;
+ RawDeviceEvent *raw;
+ int x = 0, y = 0, /* device coords */
+ cx, cy; /* only screen coordinates */
+ float x_frac = 0.0, y_frac = 0.0, cx_frac, cy_frac;
+ ScreenPtr scr = miPointerGetScreen(pDev);
+ ValuatorMask mask;
+
+ /* refuse events from disabled devices */
+ if (!pDev->enabled)
+ return 0;
+
+ if (!scr)
+ return 0;
+
+ switch (type)
+ {
+ case MotionNotify:
+ if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0)
+ return 0;
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ if (!pDev->button || !buttons)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+
+ ms = GetTimeInMillis(); /* before pointer update to help precision */
+
+ events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events);
+
+ raw = (RawDeviceEvent*)events->event;
+ events++;
+ num_events++;
+
+ valuator_mask_copy(&mask, mask_in);
+
+ init_raw(pDev, raw, ms, type, buttons);
+ set_raw_valuators(raw, &mask, raw->valuators.data_raw);
+
+ if (flags & POINTER_ABSOLUTE)
+ {
+ if (flags & POINTER_SCREEN) /* valuators are in screen coords */
+ {
+ int scaled;
+
+ if (valuator_mask_isset(&mask, 0))
+ {
+ scaled = rescaleValuatorAxis(valuator_mask_get(&mask, 0),
+ 0.0, &x_frac, NULL,
+ pDev->valuator->axes + 0,
+ scr->width);
+ valuator_mask_set(&mask, 0, scaled);
+ }
+ if (valuator_mask_isset(&mask, 1))
+ {
+ scaled = rescaleValuatorAxis(valuator_mask_get(&mask, 1),
+ 0.0, &y_frac, NULL,
+ pDev->valuator->axes + 1,
+ scr->height);
+ valuator_mask_set(&mask, 1, scaled);
+ }
+ }
+
+ transformAbsolute(pDev, &mask);
+ moveAbsolute(pDev, &x, &y, &mask);
+ } else {
+ if (flags & POINTER_ACCELERATE) {
+ accelPointer(pDev, &mask, ms);
+ /* The pointer acceleration code modifies the fractional part
+ * in-place, so we need to extract this information first */
+ x_frac = pDev->last.remainder[0];
+ y_frac = pDev->last.remainder[1];
+ }
+ moveRelative(pDev, &x, &y, &mask);
+ }
+
+ set_raw_valuators(raw, &mask, raw->valuators.data);
+
+ positionSprite(pDev, (flags & POINTER_ABSOLUTE) ? Absolute : Relative,
+ &x, &y, x_frac, y_frac, scr, &cx, &cy, &cx_frac, &cy_frac);
+ updateHistory(pDev, &mask, ms);
+
+ /* Update the valuators with the true value sent to the client*/
+ if (valuator_mask_isset(&mask, 0))
+ valuator_mask_set(&mask, 0, x);
+ if (valuator_mask_isset(&mask, 1))
+ valuator_mask_set(&mask, 1, y);
+
+ clipValuators(pDev, &mask);
+
+ event = (DeviceEvent*) events->event;
+ init_event(pDev, event, ms);
+
+ if (type == MotionNotify) {
+ event->type = ET_Motion;
+ event->detail.button = 0;
+ }
+ else {
+ if (type == ButtonPress) {
+ event->type = ET_ButtonPress;
+ set_button_down(pDev, buttons, BUTTON_POSTED);
+ }
+ else if (type == ButtonRelease) {
+ event->type = ET_ButtonRelease;
+ set_button_up(pDev, buttons, BUTTON_POSTED);
+ }
+ event->detail.button = buttons;
+ }
+
+ event->root_x = cx; /* root_x/y always in screen coords */
+ event->root_y = cy;
+ event->root_x_frac = cx_frac;
+ event->root_y_frac = cy_frac;
+
+ set_valuators(pDev, event, &mask);
+
+ return num_events;
+}
+
+
+/**
+ * Generate ProximityIn/ProximityOut InternalEvents, accompanied by
+ * valuators.
+ *
+ * events is not NULL-terminated; the return value is the number of events.
+ * The DDX is responsible for allocating the event structure in the first
+ * place via GetMaximumEventsNum(), and for freeing it.
+ */
+int
+GetProximityEvents(EventList *events, DeviceIntPtr pDev, int type, const ValuatorMask *mask_in)
+{
+ int num_events = 1, i;
+ DeviceEvent *event;
+ ValuatorMask mask;
+
+ /* refuse events from disabled devices */
+ if (!pDev->enabled)
+ return 0;
+
+ /* Sanity checks. */
+ if ((type != ProximityIn && type != ProximityOut) || !mask_in)
+ return 0;
+ if (!pDev->valuator)
+ return 0;
+
+ valuator_mask_copy(&mask, mask_in);
+
+ /* ignore relative axes for proximity. */
+ for (i = 0; i < valuator_mask_size(&mask); i++)
+ {
+ if (valuator_mask_isset(&mask, i) &&
+ valuator_get_mode(pDev, i) == Relative)
+ valuator_mask_unset(&mask, i);
+ }
+
+ /* FIXME: posting proximity events with relative valuators only results
+ * in an empty event, EventToXI() will fail to convert → no event sent
+ * to client. */
+
+ events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events);
+
+ event = (DeviceEvent *) events->event;
+ init_event(pDev, event, GetTimeInMillis());
+ event->type = (type == ProximityIn) ? ET_ProximityIn : ET_ProximityOut;
+
+ clipValuators(pDev, &mask);
+
+ set_valuators(pDev, event, &mask);
+
+ return num_events;
+}
+
+/**
+ * Synthesize a single motion event for the core pointer.
+ *
+ * Used in cursor functions, e.g. when cursor confinement changes, and we need
+ * to shift the pointer to get it inside the new bounds.
+ */
+void
+PostSyntheticMotion(DeviceIntPtr pDev,
+ int x,
+ int y,
+ int screen,
+ unsigned long time)
+{
+ DeviceEvent ev;
+
+#ifdef PANORAMIX
+ /* Translate back to the sprite screen since processInputProc
+ will translate from sprite screen to screen 0 upon reentry
+ to the DIX layer. */
+ if (!noPanoramiXExtension) {
+ x += screenInfo.screens[0]->x - screenInfo.screens[screen]->x;
+ y += screenInfo.screens[0]->y - screenInfo.screens[screen]->y;
+ }
+#endif
+
+ memset(&ev, 0, sizeof(DeviceEvent));
+ init_event(pDev, &ev, time);
+ ev.root_x = x;
+ ev.root_y = y;
+ ev.type = ET_Motion;
+ ev.time = time;
+
+ /* FIXME: MD/SD considerations? */
+ (*pDev->public.processInputProc)((InternalEvent*)&ev, pDev);
+}
diff --git a/xorg-server/dix/ptrveloc.c b/xorg-server/dix/ptrveloc.c
index e6ac2ed14..e95d804c2 100644
--- a/xorg-server/dix/ptrveloc.c
+++ b/xorg-server/dix/ptrveloc.c
@@ -1,1197 +1,1216 @@
-/*
- *
- * Copyright © 2006-2009 Simon Thum simon dot thum at gmx dot de
- *
- * 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.
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <math.h>
-#include <ptrveloc.h>
-#include <exevents.h>
-#include <X11/Xatom.h>
-
-#include <xserver-properties.h>
-
-/*****************************************************************************
- * Predictable pointer acceleration
- *
- * 2006-2009 by Simon Thum (simon [dot] thum [at] gmx de)
- *
- * Serves 3 complementary functions:
- * 1) provide a sophisticated ballistic velocity estimate to improve
- * the relation between velocity (of the device) and acceleration
- * 2) make arbitrary acceleration profiles possible
- * 3) decelerate by two means (constant and adaptive) if enabled
- *
- * Important concepts are the
- *
- * - Scheme
- * which selects the basic algorithm
- * (see devices.c/InitPointerAccelerationScheme)
- * - Profile
- * which returns an acceleration
- * for a given velocity
- *
- * The profile can be selected by the user at runtime.
- * The classic profile is intended to cleanly perform old-style
- * function selection (threshold =/!= 0)
- *
- ****************************************************************************/
-
-/* fwds */
-int
-SetAccelerationProfile(DeviceVelocityPtr vel, int profile_num);
-static float
-SimpleSmoothProfile(DeviceIntPtr dev, DeviceVelocityPtr vel, float velocity,
- float threshold, float acc);
-static PointerAccelerationProfileFunc
-GetAccelerationProfile(DeviceVelocityPtr vel, int profile_num);
-static BOOL
-InitializePredictableAccelerationProperties(DeviceIntPtr dev);
-static BOOL
-DeletePredictableAccelerationProperties(DeviceIntPtr dev);
-
-/*#define PTRACCEL_DEBUGGING*/
-
-#ifdef PTRACCEL_DEBUGGING
-#define DebugAccelF ErrorF
-#else
-#define DebugAccelF(...) /* */
-#endif
-
-/********************************
- * Init/Uninit
- *******************************/
-
-/* some int which is not a profile number */
-#define PROFILE_UNINITIALIZE (-100)
-
-
-/**
- * Init DeviceVelocity struct so it should match the average case
- */
-void
-InitVelocityData(DeviceVelocityPtr vel)
-{
- memset(vel, 0, sizeof(DeviceVelocityRec));
-
- vel->corr_mul = 10.0; /* dots per 10 milisecond should be usable */
- vel->const_acceleration = 1.0; /* no acceleration/deceleration */
- vel->reset_time = 300;
- vel->use_softening = 1;
- vel->min_acceleration = 1.0; /* don't decelerate */
- vel->max_rel_diff = 0.2;
- vel->max_diff = 1.0;
- vel->initial_range = 2;
- vel->average_accel = TRUE;
- SetAccelerationProfile(vel, AccelProfileClassic);
- InitTrackers(vel, 16);
-}
-
-
-/**
- * Clean up DeviceVelocityRec
- */
-void
-FreeVelocityData(DeviceVelocityPtr vel){
- free(vel->tracker);
- SetAccelerationProfile(vel, PROFILE_UNINITIALIZE);
-}
-
-
-/**
- * Init predictable scheme
- */
-Bool
-InitPredictableAccelerationScheme(DeviceIntPtr dev,
- ValuatorAccelerationPtr protoScheme) {
- DeviceVelocityPtr vel;
- ValuatorAccelerationRec scheme;
- scheme = *protoScheme;
- vel = calloc(1, sizeof(DeviceVelocityRec));
- if (!vel)
- return FALSE;
- InitVelocityData(vel);
- scheme.accelData = vel;
- dev->valuator->accelScheme = scheme;
- InitializePredictableAccelerationProperties(dev);
- return TRUE;
-}
-
-
-/**
- * Uninit scheme
- */
-void
-AccelerationDefaultCleanup(DeviceIntPtr dev)
-{
- /*sanity check*/
- if( dev->valuator->accelScheme.AccelSchemeProc == acceleratePointerPredictable
- && dev->valuator->accelScheme.accelData != NULL){
- dev->valuator->accelScheme.AccelSchemeProc = NULL;
- FreeVelocityData(dev->valuator->accelScheme.accelData);
- free(dev->valuator->accelScheme.accelData);
- dev->valuator->accelScheme.accelData = NULL;
- DeletePredictableAccelerationProperties(dev);
- }
-}
-
-
-/*************************
- * Input property support
- ************************/
-
-/**
- * choose profile
- */
-static int
-AccelSetProfileProperty(DeviceIntPtr dev, Atom atom,
- XIPropertyValuePtr val, BOOL checkOnly)
-{
- DeviceVelocityPtr vel;
- int profile, *ptr = &profile;
- int rc;
- int nelem = 1;
-
- if (atom != XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER))
- return Success;
-
- vel = GetDevicePredictableAccelData(dev);
- if (!vel)
- return BadValue;
- rc = XIPropToInt(val, &nelem, &ptr);
-
- if(checkOnly)
- {
- if (rc)
- return rc;
-
- if (GetAccelerationProfile(vel, profile) == NULL)
- return BadValue;
- } else
- SetAccelerationProfile(vel, profile);
-
- return Success;
-}
-
-static long
-AccelInitProfileProperty(DeviceIntPtr dev, DeviceVelocityPtr vel)
-{
- int profile = vel->statistics.profile_number;
- Atom prop_profile_number = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER);
-
- XIChangeDeviceProperty(dev, prop_profile_number, XA_INTEGER, 32,
- PropModeReplace, 1, &profile, FALSE);
- XISetDevicePropertyDeletable(dev, prop_profile_number, FALSE);
- return XIRegisterPropertyHandler(dev, AccelSetProfileProperty, NULL, NULL);
-}
-
-/**
- * constant deceleration
- */
-static int
-AccelSetDecelProperty(DeviceIntPtr dev, Atom atom,
- XIPropertyValuePtr val, BOOL checkOnly)
-{
- DeviceVelocityPtr vel;
- float v, *ptr = &v;
- int rc;
- int nelem = 1;
-
- if (atom != XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION))
- return Success;
-
- vel = GetDevicePredictableAccelData(dev);
- if (!vel)
- return BadValue;
- rc = XIPropToFloat(val, &nelem, &ptr);
-
- if(checkOnly)
- {
- if (rc)
- return rc;
- return (v >= 1.0f) ? Success : BadValue;
- }
-
- if(v >= 1.0f)
- vel->const_acceleration = 1/v;
-
- return Success;
-}
-
-static long
-AccelInitDecelProperty(DeviceIntPtr dev, DeviceVelocityPtr vel)
-{
- float fval = 1.0/vel->const_acceleration;
- Atom prop_const_decel = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION);
- XIChangeDeviceProperty(dev, prop_const_decel,
- XIGetKnownProperty(XATOM_FLOAT), 32,
- PropModeReplace, 1, &fval, FALSE);
- XISetDevicePropertyDeletable(dev, prop_const_decel, FALSE);
- return XIRegisterPropertyHandler(dev, AccelSetDecelProperty, NULL, NULL);
-}
-
-
-/**
- * adaptive deceleration
- */
-static int
-AccelSetAdaptDecelProperty(DeviceIntPtr dev, Atom atom,
- XIPropertyValuePtr val, BOOL checkOnly)
-{
- DeviceVelocityPtr veloc;
- float v, *ptr = &v;
- int rc;
- int nelem = 1;
-
- if (atom != XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION))
- return Success;
-
- veloc = GetDevicePredictableAccelData(dev);
- if (!veloc)
- return BadValue;
- rc = XIPropToFloat(val, &nelem, &ptr);
-
- if(checkOnly)
- {
- if (rc)
- return rc;
- return (v >= 1.0f) ? Success : BadValue;
- }
-
- if(v >= 1.0f)
- veloc->min_acceleration = 1/v;
-
- return Success;
-}
-
-static long
-AccelInitAdaptDecelProperty(DeviceIntPtr dev, DeviceVelocityPtr vel)
-{
- float fval = 1.0/vel->min_acceleration;
- Atom prop_adapt_decel = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION);
-
- XIChangeDeviceProperty(dev, prop_adapt_decel, XIGetKnownProperty(XATOM_FLOAT), 32,
- PropModeReplace, 1, &fval, FALSE);
- XISetDevicePropertyDeletable(dev, prop_adapt_decel, FALSE);
- return XIRegisterPropertyHandler(dev, AccelSetAdaptDecelProperty, NULL, NULL);
-}
-
-
-/**
- * velocity scaling
- */
-static int
-AccelSetScaleProperty(DeviceIntPtr dev, Atom atom,
- XIPropertyValuePtr val, BOOL checkOnly)
-{
- DeviceVelocityPtr vel;
- float v, *ptr = &v;
- int rc;
- int nelem = 1;
-
- if (atom != XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING))
- return Success;
-
- vel = GetDevicePredictableAccelData(dev);
- if (!vel)
- return BadValue;
- rc = XIPropToFloat(val, &nelem, &ptr);
-
- if (checkOnly)
- {
- if (rc)
- return rc;
-
- return (v > 0) ? Success : BadValue;
- }
-
- if(v > 0)
- vel->corr_mul = v;
-
- return Success;
-}
-
-static long
-AccelInitScaleProperty(DeviceIntPtr dev, DeviceVelocityPtr vel)
-{
- float fval = vel->corr_mul;
- Atom prop_velo_scale = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING);
-
- XIChangeDeviceProperty(dev, prop_velo_scale, XIGetKnownProperty(XATOM_FLOAT), 32,
- PropModeReplace, 1, &fval, FALSE);
- XISetDevicePropertyDeletable(dev, prop_velo_scale, FALSE);
- return XIRegisterPropertyHandler(dev, AccelSetScaleProperty, NULL, NULL);
-}
-
-BOOL
-InitializePredictableAccelerationProperties(DeviceIntPtr dev)
-{
- DeviceVelocityPtr vel = GetDevicePredictableAccelData(dev);
-
- if(!vel)
- return FALSE;
-
- vel->prop_handlers[0] = AccelInitProfileProperty(dev, vel);
- vel->prop_handlers[1] = AccelInitDecelProperty(dev, vel);
- vel->prop_handlers[2] = AccelInitAdaptDecelProperty(dev, vel);
- vel->prop_handlers[3] = AccelInitScaleProperty(dev, vel);
-
- return TRUE;
-}
-
-BOOL
-DeletePredictableAccelerationProperties(DeviceIntPtr dev)
-{
- DeviceVelocityPtr vel;
- Atom prop;
- int i;
-
- prop = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING);
- XIDeleteDeviceProperty(dev, prop, FALSE);
- prop = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION);
- XIDeleteDeviceProperty(dev, prop, FALSE);
- prop = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION);
- XIDeleteDeviceProperty(dev, prop, FALSE);
- prop = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER);
- XIDeleteDeviceProperty(dev, prop, FALSE);
-
- vel = GetDevicePredictableAccelData(dev);
- for (i = 0; vel && i < NPROPS_PREDICTABLE_ACCEL; i++)
- if (vel->prop_handlers[i])
- XIUnregisterPropertyHandler(dev, vel->prop_handlers[i]);
-
- return TRUE;
-}
-
-/*********************
- * Tracking logic
- ********************/
-
-void
-InitTrackers(DeviceVelocityPtr vel, int ntracker)
-{
- if(ntracker < 1){
- ErrorF("(dix ptracc) invalid number of trackers\n");
- return;
- }
- free(vel->tracker);
- vel->tracker = (MotionTrackerPtr)malloc(ntracker * sizeof(MotionTracker));
- memset(vel->tracker, 0, ntracker * sizeof(MotionTracker));
- vel->num_tracker = ntracker;
-}
-
-/**
- * return a bit field of possible directions.
- * 0 = N, 2 = E, 4 = S, 6 = W, in-between is as you guess.
- * There's no reason against widening to more precise directions (<45 degrees),
- * should it not perform well. All this is needed for is sort out non-linear
- * motion, so precision isn't paramount. However, one should not flag direction
- * too narrow, since it would then cut the linear segment to zero size way too
- * often.
- */
-static int
-DoGetDirection(int dx, int dy){
- float r;
- int i1, i2;
- /* on insignificant mickeys, flag 135 degrees */
- if(abs(dx) < 2 && abs(dy < 2)){
- /* first check diagonal cases */
- if(dx > 0 && dy > 0)
- return 4+8+16;
- if(dx > 0 && dy < 0)
- return 1+2+4;
- if(dx < 0 && dy < 0)
- return 1+128+64;
- if(dx < 0 && dy > 0)
- return 16+32+64;
- /* check axis-aligned directions */
- if(dx > 0)
- return 2+4+8; /*E*/
- if(dx < 0)
- return 128+64+32; /*W*/
- if(dy > 0)
- return 32+16+8; /*S*/
- if(dy < 0)
- return 128+1+2; /*N*/
- return 255; /* shouldn't happen */
- }
- /* else, compute angle and set appropriate flags */
-#ifdef _ISOC99_SOURCE
- r = atan2f(dy, dx);
-#else
- r = atan2(dy, dx);
-#endif
- /* find direction. We avoid r to become negative,
- * since C has no well-defined modulo for such cases. */
- r = (r+(M_PI*2.5))/(M_PI/4);
- /* this intends to flag 2 directions (90 degrees),
- * except on very well-aligned mickeys. */
- i1 = (int)(r+0.1) % 8;
- i2 = (int)(r+0.9) % 8;
- if(i1 < 0 || i1 > 7 || i2 < 0 || i2 > 7)
- return 255; /* shouldn't happen */
- return 1 << i1 | 1 << i2;
-}
-
-#define DIRECTION_CACHE_RANGE 5
-#define DIRECTION_CACHE_SIZE (DIRECTION_CACHE_RANGE*2+1)
-
-/* cache DoGetDirection(). */
-static int
-GetDirection(int dx, int dy){
- static int cache[DIRECTION_CACHE_SIZE][DIRECTION_CACHE_SIZE];
- int i;
- if (abs(dx) <= DIRECTION_CACHE_RANGE &&
- abs(dy) <= DIRECTION_CACHE_RANGE) {
- /* cacheable */
- i = cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy];
- if(i != 0){
- return i;
- }else{
- i = DoGetDirection(dx, dy);
- cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy] = i;
- return i;
- }
- }else{
- /* non-cacheable */
- return DoGetDirection(dx, dy);
- }
-}
-
-#undef DIRECTION_CACHE_RANGE
-#undef DIRECTION_CACHE_SIZE
-
-
-/* convert offset (age) to array index */
-#define TRACKER_INDEX(s, d) (((s)->num_tracker + (s)->cur_tracker - (d)) % (s)->num_tracker)
-
-static inline void
-FeedTrackers(DeviceVelocityPtr vel, int dx, int dy, int cur_t)
-{
- int n;
- for(n = 0; n < vel->num_tracker; n++){
- vel->tracker[n].dx += dx;
- vel->tracker[n].dy += dy;
- }
- n = (vel->cur_tracker + 1) % vel->num_tracker;
- vel->tracker[n].dx = 0;
- vel->tracker[n].dy = 0;
- vel->tracker[n].time = cur_t;
- vel->tracker[n].dir = GetDirection(dx, dy);
- DebugAccelF("(dix prtacc) motion [dx: %i dy: %i dir:%i diff: %i]\n",
- dx, dy, vel->tracker[n].dir,
- cur_t - vel->tracker[vel->cur_tracker].time);
- vel->cur_tracker = n;
-}
-
-/**
- * calc velocity for given tracker, with
- * velocity scaling.
- * This assumes linear motion.
- */
-static float
-CalcTracker(DeviceVelocityPtr vel, int offset, int cur_t){
- int index = TRACKER_INDEX(vel, offset);
- float dist = sqrt( vel->tracker[index].dx * vel->tracker[index].dx
- + vel->tracker[index].dy * vel->tracker[index].dy);
- int dtime = cur_t - vel->tracker[index].time;
- if(dtime > 0)
- return dist / dtime;
- else
- return 0;/* synonymous for NaN, since we're not C99 */
-}
-
-/* find the most plausible velocity. That is, the most distant
- * (in time) tracker which isn't too old, beyond a linear partition,
- * or simply too much off initial velocity.
- *
- * May return 0.
- */
-static float
-QueryTrackers(DeviceVelocityPtr vel, int cur_t){
- int n, offset, dir = 255, i = -1, age_ms;
- /* initial velocity: a low-offset, valid velocity */
- float iveloc = 0, res = 0, tmp, vdiff;
- float vfac = vel->corr_mul * vel->const_acceleration; /* premultiply */
- /* loop from current to older data */
- for(offset = 1; offset < vel->num_tracker; offset++){
- n = TRACKER_INDEX(vel, offset);
-
- age_ms = cur_t - vel->tracker[n].time;
-
- /* bail out if data is too old and protect from overrun */
- if (age_ms >= vel->reset_time || age_ms < 0) {
- DebugAccelF("(dix prtacc) query: tracker too old\n");
- break;
- }
-
- /*
- * this heuristic avoids using the linear-motion velocity formula
- * in CalcTracker() on motion that isn't exactly linear. So to get
- * even more precision we could subdivide as a final step, so possible
- * non-linearities are accounted for.
- */
- dir &= vel->tracker[n].dir;
- if(dir == 0){
- DebugAccelF("(dix prtacc) query: no longer linear\n");
- /* instead of breaking it we might also inspect the partition after,
- * but actual improvement with this is probably rare. */
- break;
- }
-
- tmp = CalcTracker(vel, offset, cur_t) * vfac;
-
- if ((iveloc == 0 || offset <= vel->initial_range) && tmp != 0) {
- /* set initial velocity and result */
- res = iveloc = tmp;
- i = offset;
- } else if (iveloc != 0 && tmp != 0) {
- vdiff = fabs(iveloc - tmp);
- if (vdiff <= vel->max_diff ||
- vdiff/(iveloc + tmp) < vel->max_rel_diff) {
- /* we're in range with the initial velocity,
- * so this result is likely better
- * (it contains more information). */
- res = tmp;
- i = offset;
- }else{
- /* we're not in range, quit - it won't get better. */
- DebugAccelF("(dix prtacc) query: tracker too different:"
- " old %2.2f initial %2.2f diff: %2.2f\n",
- tmp, iveloc, vdiff);
- break;
- }
- }
- }
- if(offset == vel->num_tracker){
- DebugAccelF("(dix prtacc) query: last tracker in effect\n");
- i = vel->num_tracker-1;
- }
- if(i>=0){
- n = TRACKER_INDEX(vel, i);
- DebugAccelF("(dix prtacc) result: offset %i [dx: %i dy: %i diff: %i]\n",
- i,
- vel->tracker[n].dx,
- vel->tracker[n].dy,
- cur_t - vel->tracker[n].time);
- }
- return res;
-}
-
-#undef TRACKER_INDEX
-
-/**
- * Perform velocity approximation based on 2D 'mickeys' (mouse motion delta).
- * return true if non-visible state reset is suggested
- */
-short
-ProcessVelocityData2D(
- DeviceVelocityPtr vel,
- int dx,
- int dy,
- int time)
-{
- float velocity;
-
- vel->last_velocity = vel->velocity;
-
- FeedTrackers(vel, dx, dy, time);
-
- velocity = QueryTrackers(vel, time);
-
- vel->velocity = velocity;
- return velocity == 0;
-}
-
-/**
- * this flattens significant ( > 1) mickeys a little bit for more steady
- * constant-velocity response
- */
-static inline float
-ApplySimpleSoftening(int od, int d)
-{
- float res = d;
- if (d <= 1 && d >= -1)
- return res;
- if (d > od)
- res -= 0.5;
- else if (d < od)
- res += 0.5;
- return res;
-}
-
-
-static void
-ApplySofteningAndConstantDeceleration(
- DeviceVelocityPtr vel,
- int dx,
- int dy,
- float* fdx,
- float* fdy,
- short do_soften)
-{
- if (do_soften && vel->use_softening) {
- *fdx = ApplySimpleSoftening(vel->last_dx, dx);
- *fdy = ApplySimpleSoftening(vel->last_dy, dy);
- } else {
- *fdx = dx;
- *fdy = dy;
- }
-
- *fdx *= vel->const_acceleration;
- *fdy *= vel->const_acceleration;
-}
-
-/*
- * compute the acceleration for given velocity and enforce min_acceleartion
- */
-float
-BasicComputeAcceleration(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float velocity,
- float threshold,
- float acc){
-
- float result;
- result = vel->Profile(dev, vel, velocity, threshold, acc);
-
- /* enforce min_acceleration */
- if (result < vel->min_acceleration)
- result = vel->min_acceleration;
- return result;
-}
-
-/**
- * Compute acceleration. Takes into account averaging, nv-reset, etc.
- */
-static float
-ComputeAcceleration(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float threshold,
- float acc){
- float res;
-
- if(vel->velocity <= 0){
- DebugAccelF("(dix ptracc) profile skipped\n");
- /*
- * If we have no idea about device velocity, don't pretend it.
- */
- return 1;
- }
-
- if(vel->average_accel && vel->velocity != vel->last_velocity){
- /* use simpson's rule to average acceleration between
- * current and previous velocity.
- * Though being the more natural choice, it causes a minor delay
- * in comparison, so it can be disabled. */
- res = BasicComputeAcceleration(
- dev, vel, vel->velocity, threshold, acc);
- res += BasicComputeAcceleration(
- dev, vel, vel->last_velocity, threshold, acc);
- res += 4.0f * BasicComputeAcceleration(dev, vel,
- (vel->last_velocity + vel->velocity) / 2,
- threshold, acc);
- res /= 6.0f;
- DebugAccelF("(dix ptracc) profile average [%.2f ... %.2f] is %.3f\n",
- vel->velocity, vel->last_velocity, res);
- return res;
- }else{
- res = BasicComputeAcceleration(dev, vel,
- vel->velocity, threshold, acc);
- DebugAccelF("(dix ptracc) profile sample [%.2f] is %.3f\n",
- vel->velocity, res);
- return res;
- }
-}
-
-
-/*****************************************
- * Acceleration functions and profiles
- ****************************************/
-
-/**
- * Polynomial function similar previous one, but with f(1) = 1
- */
-static float
-PolynomialAccelerationProfile(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float velocity,
- float ignored,
- float acc)
-{
- return pow(velocity, (acc - 1.0) * 0.5);
-}
-
-
-/**
- * returns acceleration for velocity.
- * This profile selects the two functions like the old scheme did
- */
-static float
-ClassicProfile(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float velocity,
- float threshold,
- float acc)
-{
- if (threshold > 0) {
- return SimpleSmoothProfile (dev,
- vel,
- velocity,
- threshold,
- acc);
- } else {
- return PolynomialAccelerationProfile (dev,
- vel,
- velocity,
- 0,
- acc);
- }
-}
-
-
-/**
- * Power profile
- * This has a completely smooth transition curve, i.e. no jumps in the
- * derivatives.
- *
- * This has the expense of overall response dependency on min-acceleration.
- * In effect, min_acceleration mimics const_acceleration in this profile.
- */
-static float
-PowerProfile(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float velocity,
- float threshold,
- float acc)
-{
- float vel_dist;
-
- acc = (acc-1.0) * 0.1f + 1.0; /* without this, acc of 2 is unuseable */
-
- if (velocity <= threshold)
- return vel->min_acceleration;
- vel_dist = velocity - threshold;
- return (pow(acc, vel_dist)) * vel->min_acceleration;
-}
-
-
-/**
- * just a smooth function in [0..1] -> [0..1]
- * - point symmetry at 0.5
- * - f'(0) = f'(1) = 0
- * - starts faster than a sinoid
- * - smoothness C1 (Cinf if you dare to ignore endpoints)
- */
-static inline float
-CalcPenumbralGradient(float x){
- x *= 2.0f;
- x -= 1.0f;
- return 0.5f + (x * sqrt(1.0f - x*x) + asin(x))/M_PI;
-}
-
-
-/**
- * acceleration function similar to classic accelerated/unaccelerated,
- * but with smooth transition in between (and towards zero for adaptive dec.).
- */
-static float
-SimpleSmoothProfile(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float velocity,
- float threshold,
- float acc)
-{
- if(velocity < 1.0f)
- return CalcPenumbralGradient(0.5 + velocity*0.5) * 2.0f - 1.0f;
- if(threshold < 1.0f)
- threshold = 1.0f;
- if (velocity <= threshold)
- return 1;
- velocity /= threshold;
- if (velocity >= acc)
- return acc;
- else
- return 1.0f + (CalcPenumbralGradient(velocity/acc) * (acc - 1.0f));
-}
-
-
-/**
- * This profile uses the first half of the penumbral gradient as a start
- * and then scales linearly.
- */
-static float
-SmoothLinearProfile(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float velocity,
- float threshold,
- float acc)
-{
- float res, nv;
-
- if(acc > 1.0f)
- acc -= 1.0f; /*this is so acc = 1 is no acceleration */
- else
- return 1.0f;
-
- nv = (velocity - threshold) * acc * 0.5f;
-
- if(nv < 0){
- res = 0;
- }else if(nv < 2){
- res = CalcPenumbralGradient(nv*0.25f)*2.0f;
- }else{
- nv -= 2.0f;
- res = nv * 2.0f / M_PI /* steepness of gradient at 0.5 */
- + 1.0f; /* gradient crosses 2|1 */
- }
- res += vel->min_acceleration;
- return res;
-}
-
-
-/**
- * From 0 to threshold, the response graduates smoothly from min_accel to
- * acceleration. Beyond threshold it is exactly the specified acceleration.
- */
-static float
-SmoothLimitedProfile(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float velocity,
- float threshold,
- float acc)
-{
- float res;
-
- if(velocity >= threshold || threshold == 0.0f)
- return acc;
-
- velocity /= threshold; /* should be [0..1[ now */
-
- res = CalcPenumbralGradient(velocity) * (acc - vel->min_acceleration);
-
- return vel->min_acceleration + res;
-}
-
-
-static float
-LinearProfile(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float velocity,
- float threshold,
- float acc)
-{
- return acc * velocity;
-}
-
-static float
-NoProfile(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float velocity,
- float threshold,
- float acc)
-{
- return 1.0f;
-}
-
-static PointerAccelerationProfileFunc
-GetAccelerationProfile(
- DeviceVelocityPtr vel,
- int profile_num)
-{
- switch(profile_num){
- case AccelProfileClassic:
- return ClassicProfile;
- case AccelProfileDeviceSpecific:
- return vel->deviceSpecificProfile;
- case AccelProfilePolynomial:
- return PolynomialAccelerationProfile;
- case AccelProfileSmoothLinear:
- return SmoothLinearProfile;
- case AccelProfileSimple:
- return SimpleSmoothProfile;
- case AccelProfilePower:
- return PowerProfile;
- case AccelProfileLinear:
- return LinearProfile;
- case AccelProfileSmoothLimited:
- return SmoothLimitedProfile;
- case AccelProfileNone:
- return NoProfile;
- default:
- return NULL;
- }
-}
-
-/**
- * Set the profile by number.
- * Intended to make profiles exchangeable at runtime.
- * If you created a profile, give it a number here and in the header to
- * make it selectable. In case some profile-specific init is needed, here
- * would be a good place, since FreeVelocityData() also calls this with
- * PROFILE_UNINITIALIZE.
- *
- * returns FALSE if profile number is unavailable, TRUE otherwise.
- */
-int
-SetAccelerationProfile(
- DeviceVelocityPtr vel,
- int profile_num)
-{
- PointerAccelerationProfileFunc profile;
- profile = GetAccelerationProfile(vel, profile_num);
-
- if(profile == NULL && profile_num != PROFILE_UNINITIALIZE)
- return FALSE;
-
- /* Here one could free old profile-private data */
- free(vel->profile_private);
- vel->profile_private = NULL;
- /* Here one could init profile-private data */
- vel->Profile = profile;
- vel->statistics.profile_number = profile_num;
- return TRUE;
-}
-
-/**********************************************
- * driver interaction
- **********************************************/
-
-
-/**
- * device-specific profile
- *
- * The device-specific profile is intended as a hook for a driver
- * which may want to provide an own acceleration profile.
- * It should not rely on profile-private data, instead
- * it should do init/uninit in the driver (ie. with DEVICE_INIT and friends).
- * Users may override or choose it.
- */
-void
-SetDeviceSpecificAccelerationProfile(
- DeviceVelocityPtr vel,
- PointerAccelerationProfileFunc profile)
-{
- if(vel)
- vel->deviceSpecificProfile = profile;
-}
-
-/**
- * Use this function to obtain a DeviceVelocityPtr for a device. Will return NULL if
- * the predictable acceleration scheme is not in effect.
- */
-DeviceVelocityPtr
-GetDevicePredictableAccelData(
- DeviceIntPtr dev)
-{
- /*sanity check*/
- if(!dev){
- ErrorF("[dix] accel: DeviceIntPtr was NULL");
- return NULL;
- }
- if( dev->valuator &&
- dev->valuator->accelScheme.AccelSchemeProc ==
- acceleratePointerPredictable &&
- dev->valuator->accelScheme.accelData != NULL){
-
- return (DeviceVelocityPtr)dev->valuator->accelScheme.accelData;
- }
- return NULL;
-}
-
-/********************************
- * acceleration schemes
- *******************************/
-
-/**
- * Modifies valuators in-place.
- * This version employs a velocity approximation algorithm to
- * enable fine-grained predictable acceleration profiles.
- */
-void
-acceleratePointerPredictable(
- DeviceIntPtr dev,
- int first_valuator,
- int num_valuators,
- int *valuators,
- int evtime)
-{
- float fdx, fdy, tmp, mult; /* no need to init */
- int dx = 0, dy = 0;
- int *px = NULL, *py = NULL;
- DeviceVelocityPtr velocitydata = GetDevicePredictableAccelData(dev);
- Bool soften = TRUE;
-
- if (!num_valuators || !valuators || !velocitydata)
- return;
-
- if (velocitydata->statistics.profile_number == AccelProfileNone &&
- velocitydata->const_acceleration == 1.0f) {
- return; /*we're inactive anyway, so skip the whole thing.*/
- }
-
- if (first_valuator == 0) {
- dx = valuators[0];
- px = &valuators[0];
- }
- if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) {
- dy = valuators[1 - first_valuator];
- py = &valuators[1 - first_valuator];
- }
-
- if (dx || dy){
- /* reset non-visible state? */
- if (ProcessVelocityData2D(velocitydata, dx , dy, evtime)) {
- soften = FALSE;
- }
-
- if (dev->ptrfeed && dev->ptrfeed->ctrl.num) {
- /* invoke acceleration profile to determine acceleration */
- mult = ComputeAcceleration (dev, velocitydata,
- dev->ptrfeed->ctrl.threshold,
- (float)dev->ptrfeed->ctrl.num /
- (float)dev->ptrfeed->ctrl.den);
-
- if(mult != 1.0f || velocitydata->const_acceleration != 1.0f) {
- ApplySofteningAndConstantDeceleration( velocitydata,
- dx, dy,
- &fdx, &fdy,
- (mult > 1.0f) && soften);
-
- if (dx) {
- tmp = mult * fdx + dev->last.remainder[0];
- /* Since it may not be apparent: lrintf() does not offer
- * strong statements about rounding; however because we
- * process each axis conditionally, there's no danger
- * of a toggling remainder. Its lack of guarantees likely
- * makes it faster on the average target. */
- *px = lrintf(tmp);
- dev->last.remainder[0] = tmp - (float)*px;
- }
- if (dy) {
- tmp = mult * fdy + dev->last.remainder[1];
- *py = lrintf(tmp);
- dev->last.remainder[1] = tmp - (float)*py;
- }
- DebugAccelF("pos (%i | %i) remainders x: %.3f y: %.3f delta x:%.3f y:%.3f\n",
- *px, *py, dev->last.remainder[0], dev->last.remainder[1], fdx, fdy);
- }
- }
- }
- /* remember last motion delta (for softening/slow movement treatment) */
- velocitydata->last_dx = dx;
- velocitydata->last_dy = dy;
-}
-
-
-
-/**
- * Originally a part of xf86PostMotionEvent; modifies valuators
- * in-place. Retained mostly for embedded scenarios.
- */
-void
-acceleratePointerLightweight(
- DeviceIntPtr dev,
- int first_valuator,
- int num_valuators,
- int *valuators,
- int ignored)
-{
- float mult = 0.0;
- int dx = 0, dy = 0;
- int *px = NULL, *py = NULL;
-
- if (!num_valuators || !valuators)
- return;
-
- if (first_valuator == 0) {
- dx = valuators[0];
- px = &valuators[0];
- }
- if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) {
- dy = valuators[1 - first_valuator];
- py = &valuators[1 - first_valuator];
- }
-
- if (!dx && !dy)
- return;
-
- if (dev->ptrfeed && dev->ptrfeed->ctrl.num) {
- /* modeled from xf86Events.c */
- if (dev->ptrfeed->ctrl.threshold) {
- if ((abs(dx) + abs(dy)) >= dev->ptrfeed->ctrl.threshold) {
- dev->last.remainder[0] = ((float)dx *
- (float)(dev->ptrfeed->ctrl.num)) /
- (float)(dev->ptrfeed->ctrl.den) +
- dev->last.remainder[0];
- if (px) {
- *px = (int)dev->last.remainder[0];
- dev->last.remainder[0] = dev->last.remainder[0] -
- (float)(*px);
- }
-
- dev->last.remainder[1] = ((float)dy *
- (float)(dev->ptrfeed->ctrl.num)) /
- (float)(dev->ptrfeed->ctrl.den) +
- dev->last.remainder[1];
- if (py) {
- *py = (int)dev->last.remainder[1];
- dev->last.remainder[1] = dev->last.remainder[1] -
- (float)(*py);
- }
- }
- }
- else {
- mult = pow((float)dx * (float)dx + (float)dy * (float)dy,
- ((float)(dev->ptrfeed->ctrl.num) /
- (float)(dev->ptrfeed->ctrl.den) - 1.0) /
- 2.0) / 2.0;
- if (dx) {
- dev->last.remainder[0] = mult * (float)dx +
- dev->last.remainder[0];
- *px = (int)dev->last.remainder[0];
- dev->last.remainder[0] = dev->last.remainder[0] -
- (float)(*px);
- }
- if (dy) {
- dev->last.remainder[1] = mult * (float)dy +
- dev->last.remainder[1];
- *py = (int)dev->last.remainder[1];
- dev->last.remainder[1] = dev->last.remainder[1] -
- (float)(*py);
- }
- }
- }
-}
+/*
+ *
+ * Copyright © 2006-2009 Simon Thum simon dot thum at gmx dot de
+ *
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <math.h>
+#include <ptrveloc.h>
+#include <exevents.h>
+#include <X11/Xatom.h>
+#include <os.h>
+
+#include <xserver-properties.h>
+
+/*****************************************************************************
+ * Predictable pointer acceleration
+ *
+ * 2006-2009 by Simon Thum (simon [dot] thum [at] gmx de)
+ *
+ * Serves 3 complementary functions:
+ * 1) provide a sophisticated ballistic velocity estimate to improve
+ * the relation between velocity (of the device) and acceleration
+ * 2) make arbitrary acceleration profiles possible
+ * 3) decelerate by two means (constant and adaptive) if enabled
+ *
+ * Important concepts are the
+ *
+ * - Scheme
+ * which selects the basic algorithm
+ * (see devices.c/InitPointerAccelerationScheme)
+ * - Profile
+ * which returns an acceleration
+ * for a given velocity
+ *
+ * The profile can be selected by the user at runtime.
+ * The classic profile is intended to cleanly perform old-style
+ * function selection (threshold =/!= 0)
+ *
+ ****************************************************************************/
+
+/* fwds */
+int
+SetAccelerationProfile(DeviceVelocityPtr vel, int profile_num);
+static float
+SimpleSmoothProfile(DeviceIntPtr dev, DeviceVelocityPtr vel, float velocity,
+ float threshold, float acc);
+static PointerAccelerationProfileFunc
+GetAccelerationProfile(DeviceVelocityPtr vel, int profile_num);
+static BOOL
+InitializePredictableAccelerationProperties(DeviceIntPtr,
+ DeviceVelocityPtr,
+ PredictableAccelSchemePtr);
+static BOOL
+DeletePredictableAccelerationProperties(DeviceIntPtr,
+ PredictableAccelSchemePtr);
+
+/*#define PTRACCEL_DEBUGGING*/
+
+#ifdef PTRACCEL_DEBUGGING
+#define DebugAccelF ErrorF
+#else
+#define DebugAccelF(...) /* */
+#endif
+
+/********************************
+ * Init/Uninit
+ *******************************/
+
+/* some int which is not a profile number */
+#define PROFILE_UNINITIALIZE (-100)
+
+/**
+ * Init DeviceVelocity struct so it should match the average case
+ */
+void
+InitVelocityData(DeviceVelocityPtr vel)
+{
+ memset(vel, 0, sizeof(DeviceVelocityRec));
+
+ vel->corr_mul = 10.0; /* dots per 10 milisecond should be usable */
+ vel->const_acceleration = 1.0; /* no acceleration/deceleration */
+ vel->reset_time = 300;
+ vel->use_softening = 1;
+ vel->min_acceleration = 1.0; /* don't decelerate */
+ vel->max_rel_diff = 0.2;
+ vel->max_diff = 1.0;
+ vel->initial_range = 2;
+ vel->average_accel = TRUE;
+ SetAccelerationProfile(vel, AccelProfileClassic);
+ InitTrackers(vel, 16);
+}
+
+
+/**
+ * Clean up DeviceVelocityRec
+ */
+void
+FreeVelocityData(DeviceVelocityPtr vel){
+ free(vel->tracker);
+ SetAccelerationProfile(vel, PROFILE_UNINITIALIZE);
+}
+
+
+/**
+ * Init predictable scheme
+ */
+Bool
+InitPredictableAccelerationScheme(DeviceIntPtr dev,
+ ValuatorAccelerationPtr protoScheme) {
+ DeviceVelocityPtr vel;
+ ValuatorAccelerationRec scheme;
+ PredictableAccelSchemePtr schemeData;
+ scheme = *protoScheme;
+ vel = calloc(1, sizeof(DeviceVelocityRec));
+ schemeData = calloc(1, sizeof(PredictableAccelSchemeRec));
+ if (!vel || !schemeData)
+ return FALSE;
+ InitVelocityData(vel);
+ schemeData->vel = vel;
+ scheme.accelData = schemeData;
+ if (!InitializePredictableAccelerationProperties(dev, vel, schemeData))
+ return FALSE;
+ /* all fine, assign scheme to device */
+ dev->valuator->accelScheme = scheme;
+ return TRUE;
+}
+
+
+/**
+ * Uninit scheme
+ */
+void
+AccelerationDefaultCleanup(DeviceIntPtr dev)
+{
+ DeviceVelocityPtr vel = GetDevicePredictableAccelData(dev);
+ if (vel) {
+ /* the proper guarantee would be that we're not inside of
+ * AccelSchemeProc(), but that seems impossible. Schemes don't get
+ * switched often anyway.
+ */
+ OsBlockSignals();
+ dev->valuator->accelScheme.AccelSchemeProc = NULL;
+ FreeVelocityData(vel);
+ free(vel);
+ DeletePredictableAccelerationProperties(dev,
+ (PredictableAccelSchemePtr) dev->valuator->accelScheme.accelData);
+ free(dev->valuator->accelScheme.accelData);
+ dev->valuator->accelScheme.accelData = NULL;
+ OsReleaseSignals();
+ }
+}
+
+
+/*************************
+ * Input property support
+ ************************/
+
+/**
+ * choose profile
+ */
+static int
+AccelSetProfileProperty(DeviceIntPtr dev, Atom atom,
+ XIPropertyValuePtr val, BOOL checkOnly)
+{
+ DeviceVelocityPtr vel;
+ int profile, *ptr = &profile;
+ int rc;
+ int nelem = 1;
+
+ if (atom != XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER))
+ return Success;
+
+ vel = GetDevicePredictableAccelData(dev);
+ if (!vel)
+ return BadValue;
+ rc = XIPropToInt(val, &nelem, &ptr);
+
+ if(checkOnly)
+ {
+ if (rc)
+ return rc;
+
+ if (GetAccelerationProfile(vel, profile) == NULL)
+ return BadValue;
+ } else
+ SetAccelerationProfile(vel, profile);
+
+ return Success;
+}
+
+static long
+AccelInitProfileProperty(DeviceIntPtr dev, DeviceVelocityPtr vel)
+{
+ int profile = vel->statistics.profile_number;
+ Atom prop_profile_number = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER);
+
+ XIChangeDeviceProperty(dev, prop_profile_number, XA_INTEGER, 32,
+ PropModeReplace, 1, &profile, FALSE);
+ XISetDevicePropertyDeletable(dev, prop_profile_number, FALSE);
+ return XIRegisterPropertyHandler(dev, AccelSetProfileProperty, NULL, NULL);
+}
+
+/**
+ * constant deceleration
+ */
+static int
+AccelSetDecelProperty(DeviceIntPtr dev, Atom atom,
+ XIPropertyValuePtr val, BOOL checkOnly)
+{
+ DeviceVelocityPtr vel;
+ float v, *ptr = &v;
+ int rc;
+ int nelem = 1;
+
+ if (atom != XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION))
+ return Success;
+
+ vel = GetDevicePredictableAccelData(dev);
+ if (!vel)
+ return BadValue;
+ rc = XIPropToFloat(val, &nelem, &ptr);
+
+ if(checkOnly)
+ {
+ if (rc)
+ return rc;
+ return (v >= 1.0f) ? Success : BadValue;
+ }
+
+ if(v >= 1.0f)
+ vel->const_acceleration = 1/v;
+
+ return Success;
+}
+
+static long
+AccelInitDecelProperty(DeviceIntPtr dev, DeviceVelocityPtr vel)
+{
+ float fval = 1.0/vel->const_acceleration;
+ Atom prop_const_decel = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION);
+ XIChangeDeviceProperty(dev, prop_const_decel,
+ XIGetKnownProperty(XATOM_FLOAT), 32,
+ PropModeReplace, 1, &fval, FALSE);
+ XISetDevicePropertyDeletable(dev, prop_const_decel, FALSE);
+ return XIRegisterPropertyHandler(dev, AccelSetDecelProperty, NULL, NULL);
+}
+
+
+/**
+ * adaptive deceleration
+ */
+static int
+AccelSetAdaptDecelProperty(DeviceIntPtr dev, Atom atom,
+ XIPropertyValuePtr val, BOOL checkOnly)
+{
+ DeviceVelocityPtr veloc;
+ float v, *ptr = &v;
+ int rc;
+ int nelem = 1;
+
+ if (atom != XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION))
+ return Success;
+
+ veloc = GetDevicePredictableAccelData(dev);
+ if (!veloc)
+ return BadValue;
+ rc = XIPropToFloat(val, &nelem, &ptr);
+
+ if(checkOnly)
+ {
+ if (rc)
+ return rc;
+ return (v >= 1.0f) ? Success : BadValue;
+ }
+
+ if(v >= 1.0f)
+ veloc->min_acceleration = 1/v;
+
+ return Success;
+}
+
+static long
+AccelInitAdaptDecelProperty(DeviceIntPtr dev, DeviceVelocityPtr vel)
+{
+ float fval = 1.0/vel->min_acceleration;
+ Atom prop_adapt_decel = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION);
+
+ XIChangeDeviceProperty(dev, prop_adapt_decel, XIGetKnownProperty(XATOM_FLOAT), 32,
+ PropModeReplace, 1, &fval, FALSE);
+ XISetDevicePropertyDeletable(dev, prop_adapt_decel, FALSE);
+ return XIRegisterPropertyHandler(dev, AccelSetAdaptDecelProperty, NULL, NULL);
+}
+
+
+/**
+ * velocity scaling
+ */
+static int
+AccelSetScaleProperty(DeviceIntPtr dev, Atom atom,
+ XIPropertyValuePtr val, BOOL checkOnly)
+{
+ DeviceVelocityPtr vel;
+ float v, *ptr = &v;
+ int rc;
+ int nelem = 1;
+
+ if (atom != XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING))
+ return Success;
+
+ vel = GetDevicePredictableAccelData(dev);
+ if (!vel)
+ return BadValue;
+ rc = XIPropToFloat(val, &nelem, &ptr);
+
+ if (checkOnly)
+ {
+ if (rc)
+ return rc;
+
+ return (v > 0) ? Success : BadValue;
+ }
+
+ if(v > 0)
+ vel->corr_mul = v;
+
+ return Success;
+}
+
+static long
+AccelInitScaleProperty(DeviceIntPtr dev, DeviceVelocityPtr vel)
+{
+ float fval = vel->corr_mul;
+ Atom prop_velo_scale = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING);
+
+ XIChangeDeviceProperty(dev, prop_velo_scale, XIGetKnownProperty(XATOM_FLOAT), 32,
+ PropModeReplace, 1, &fval, FALSE);
+ XISetDevicePropertyDeletable(dev, prop_velo_scale, FALSE);
+ return XIRegisterPropertyHandler(dev, AccelSetScaleProperty, NULL, NULL);
+}
+
+static BOOL
+InitializePredictableAccelerationProperties(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ PredictableAccelSchemePtr schemeData)
+{
+ int num_handlers = 4;
+ if(!vel)
+ return FALSE;
+
+ schemeData->prop_handlers = calloc(num_handlers, sizeof(long));
+ if (!schemeData->prop_handlers)
+ return FALSE;
+ schemeData->num_prop_handlers = num_handlers;
+ schemeData->prop_handlers[0] = AccelInitProfileProperty(dev, vel);
+ schemeData->prop_handlers[1] = AccelInitDecelProperty(dev, vel);
+ schemeData->prop_handlers[2] = AccelInitAdaptDecelProperty(dev, vel);
+ schemeData->prop_handlers[3] = AccelInitScaleProperty(dev, vel);
+
+ return TRUE;
+}
+
+BOOL
+DeletePredictableAccelerationProperties(
+ DeviceIntPtr dev,
+ PredictableAccelSchemePtr scheme)
+{
+ DeviceVelocityPtr vel;
+ Atom prop;
+ int i;
+
+ prop = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING);
+ XIDeleteDeviceProperty(dev, prop, FALSE);
+ prop = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION);
+ XIDeleteDeviceProperty(dev, prop, FALSE);
+ prop = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION);
+ XIDeleteDeviceProperty(dev, prop, FALSE);
+ prop = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER);
+ XIDeleteDeviceProperty(dev, prop, FALSE);
+
+ vel = GetDevicePredictableAccelData(dev);
+ if (vel) {
+ for (i = 0; i < scheme->num_prop_handlers; i++)
+ if (scheme->prop_handlers[i])
+ XIUnregisterPropertyHandler(dev, scheme->prop_handlers[i]);
+ }
+
+ free(scheme->prop_handlers);
+ scheme->prop_handlers = NULL;
+ scheme->num_prop_handlers = 0;
+ return TRUE;
+}
+
+/*********************
+ * Tracking logic
+ ********************/
+
+void
+InitTrackers(DeviceVelocityPtr vel, int ntracker)
+{
+ if(ntracker < 1){
+ ErrorF("(dix ptracc) invalid number of trackers\n");
+ return;
+ }
+ free(vel->tracker);
+ vel->tracker = (MotionTrackerPtr)calloc(ntracker, sizeof(MotionTracker));
+ vel->num_tracker = ntracker;
+}
+
+/**
+ * return a bit field of possible directions.
+ * 0 = N, 2 = E, 4 = S, 6 = W, in-between is as you guess.
+ * There's no reason against widening to more precise directions (<45 degrees),
+ * should it not perform well. All this is needed for is sort out non-linear
+ * motion, so precision isn't paramount. However, one should not flag direction
+ * too narrow, since it would then cut the linear segment to zero size way too
+ * often.
+ */
+static int
+DoGetDirection(int dx, int dy){
+ float r;
+ int i1, i2;
+ /* on insignificant mickeys, flag 135 degrees */
+ if(abs(dx) < 2 && abs(dy < 2)){
+ /* first check diagonal cases */
+ if(dx > 0 && dy > 0)
+ return 4+8+16;
+ if(dx > 0 && dy < 0)
+ return 1+2+4;
+ if(dx < 0 && dy < 0)
+ return 1+128+64;
+ if(dx < 0 && dy > 0)
+ return 16+32+64;
+ /* check axis-aligned directions */
+ if(dx > 0)
+ return 2+4+8; /*E*/
+ if(dx < 0)
+ return 128+64+32; /*W*/
+ if(dy > 0)
+ return 32+16+8; /*S*/
+ if(dy < 0)
+ return 128+1+2; /*N*/
+ return 255; /* shouldn't happen */
+ }
+ /* else, compute angle and set appropriate flags */
+#ifdef _ISOC99_SOURCE
+ r = atan2f(dy, dx);
+#else
+ r = atan2(dy, dx);
+#endif
+ /* find direction. We avoid r to become negative,
+ * since C has no well-defined modulo for such cases. */
+ r = (r+(M_PI*2.5))/(M_PI/4);
+ /* this intends to flag 2 directions (90 degrees),
+ * except on very well-aligned mickeys. */
+ i1 = (int)(r+0.1) % 8;
+ i2 = (int)(r+0.9) % 8;
+ if(i1 < 0 || i1 > 7 || i2 < 0 || i2 > 7)
+ return 255; /* shouldn't happen */
+ return 1 << i1 | 1 << i2;
+}
+
+#define DIRECTION_CACHE_RANGE 5
+#define DIRECTION_CACHE_SIZE (DIRECTION_CACHE_RANGE*2+1)
+
+/* cache DoGetDirection(). */
+static int
+GetDirection(int dx, int dy){
+ static int cache[DIRECTION_CACHE_SIZE][DIRECTION_CACHE_SIZE];
+ int i;
+ if (abs(dx) <= DIRECTION_CACHE_RANGE &&
+ abs(dy) <= DIRECTION_CACHE_RANGE) {
+ /* cacheable */
+ i = cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy];
+ if(i != 0){
+ return i;
+ }else{
+ i = DoGetDirection(dx, dy);
+ cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy] = i;
+ return i;
+ }
+ }else{
+ /* non-cacheable */
+ return DoGetDirection(dx, dy);
+ }
+}
+
+#undef DIRECTION_CACHE_RANGE
+#undef DIRECTION_CACHE_SIZE
+
+
+/* convert offset (age) to array index */
+#define TRACKER_INDEX(s, d) (((s)->num_tracker + (s)->cur_tracker - (d)) % (s)->num_tracker)
+
+static inline void
+FeedTrackers(DeviceVelocityPtr vel, int dx, int dy, int cur_t)
+{
+ int n;
+ for(n = 0; n < vel->num_tracker; n++){
+ vel->tracker[n].dx += dx;
+ vel->tracker[n].dy += dy;
+ }
+ n = (vel->cur_tracker + 1) % vel->num_tracker;
+ vel->tracker[n].dx = 0;
+ vel->tracker[n].dy = 0;
+ vel->tracker[n].time = cur_t;
+ vel->tracker[n].dir = GetDirection(dx, dy);
+ DebugAccelF("(dix prtacc) motion [dx: %i dy: %i dir:%i diff: %i]\n",
+ dx, dy, vel->tracker[n].dir,
+ cur_t - vel->tracker[vel->cur_tracker].time);
+ vel->cur_tracker = n;
+}
+
+/**
+ * calc velocity for given tracker, with
+ * velocity scaling.
+ * This assumes linear motion.
+ */
+static float
+CalcTracker(DeviceVelocityPtr vel, int offset, int cur_t){
+ int index = TRACKER_INDEX(vel, offset);
+ float dist = sqrt( vel->tracker[index].dx * vel->tracker[index].dx
+ + vel->tracker[index].dy * vel->tracker[index].dy);
+ int dtime = cur_t - vel->tracker[index].time;
+ if(dtime > 0)
+ return dist / dtime;
+ else
+ return 0;/* synonymous for NaN, since we're not C99 */
+}
+
+/* find the most plausible velocity. That is, the most distant
+ * (in time) tracker which isn't too old, beyond a linear partition,
+ * or simply too much off initial velocity.
+ *
+ * May return 0.
+ */
+static float
+QueryTrackers(DeviceVelocityPtr vel, int cur_t){
+ int n, offset, dir = 255, i = -1, age_ms;
+ /* initial velocity: a low-offset, valid velocity */
+ float iveloc = 0, res = 0, tmp, vdiff;
+ float vfac = vel->corr_mul * vel->const_acceleration; /* premultiply */
+ /* loop from current to older data */
+ for(offset = 1; offset < vel->num_tracker; offset++){
+ n = TRACKER_INDEX(vel, offset);
+
+ age_ms = cur_t - vel->tracker[n].time;
+
+ /* bail out if data is too old and protect from overrun */
+ if (age_ms >= vel->reset_time || age_ms < 0) {
+ DebugAccelF("(dix prtacc) query: tracker too old\n");
+ break;
+ }
+
+ /*
+ * this heuristic avoids using the linear-motion velocity formula
+ * in CalcTracker() on motion that isn't exactly linear. So to get
+ * even more precision we could subdivide as a final step, so possible
+ * non-linearities are accounted for.
+ */
+ dir &= vel->tracker[n].dir;
+ if(dir == 0){
+ DebugAccelF("(dix prtacc) query: no longer linear\n");
+ /* instead of breaking it we might also inspect the partition after,
+ * but actual improvement with this is probably rare. */
+ break;
+ }
+
+ tmp = CalcTracker(vel, offset, cur_t) * vfac;
+
+ if ((iveloc == 0 || offset <= vel->initial_range) && tmp != 0) {
+ /* set initial velocity and result */
+ res = iveloc = tmp;
+ i = offset;
+ } else if (iveloc != 0 && tmp != 0) {
+ vdiff = fabs(iveloc - tmp);
+ if (vdiff <= vel->max_diff ||
+ vdiff/(iveloc + tmp) < vel->max_rel_diff) {
+ /* we're in range with the initial velocity,
+ * so this result is likely better
+ * (it contains more information). */
+ res = tmp;
+ i = offset;
+ }else{
+ /* we're not in range, quit - it won't get better. */
+ DebugAccelF("(dix prtacc) query: tracker too different:"
+ " old %2.2f initial %2.2f diff: %2.2f\n",
+ tmp, iveloc, vdiff);
+ break;
+ }
+ }
+ }
+ if(offset == vel->num_tracker){
+ DebugAccelF("(dix prtacc) query: last tracker in effect\n");
+ i = vel->num_tracker-1;
+ }
+ if(i>=0){
+ n = TRACKER_INDEX(vel, i);
+ DebugAccelF("(dix prtacc) result: offset %i [dx: %i dy: %i diff: %i]\n",
+ i,
+ vel->tracker[n].dx,
+ vel->tracker[n].dy,
+ cur_t - vel->tracker[n].time);
+ }
+ return res;
+}
+
+#undef TRACKER_INDEX
+
+/**
+ * Perform velocity approximation based on 2D 'mickeys' (mouse motion delta).
+ * return true if non-visible state reset is suggested
+ */
+short
+ProcessVelocityData2D(
+ DeviceVelocityPtr vel,
+ int dx,
+ int dy,
+ int time)
+{
+ float velocity;
+
+ vel->last_velocity = vel->velocity;
+
+ FeedTrackers(vel, dx, dy, time);
+
+ velocity = QueryTrackers(vel, time);
+
+ vel->velocity = velocity;
+ return velocity == 0;
+}
+
+/**
+ * this flattens significant ( > 1) mickeys a little bit for more steady
+ * constant-velocity response
+ */
+static inline float
+ApplySimpleSoftening(int od, int d)
+{
+ float res = d;
+ if (d <= 1 && d >= -1)
+ return res;
+ if (d > od)
+ res -= 0.5;
+ else if (d < od)
+ res += 0.5;
+ return res;
+}
+
+
+static void
+ApplySofteningAndConstantDeceleration(
+ DeviceVelocityPtr vel,
+ int dx,
+ int dy,
+ float* fdx,
+ float* fdy,
+ short do_soften)
+{
+ if (do_soften && vel->use_softening) {
+ *fdx = ApplySimpleSoftening(vel->last_dx, dx);
+ *fdy = ApplySimpleSoftening(vel->last_dy, dy);
+ } else {
+ *fdx = dx;
+ *fdy = dy;
+ }
+
+ *fdx *= vel->const_acceleration;
+ *fdy *= vel->const_acceleration;
+}
+
+/*
+ * compute the acceleration for given velocity and enforce min_acceleartion
+ */
+float
+BasicComputeAcceleration(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float threshold,
+ float acc){
+
+ float result;
+ result = vel->Profile(dev, vel, velocity, threshold, acc);
+
+ /* enforce min_acceleration */
+ if (result < vel->min_acceleration)
+ result = vel->min_acceleration;
+ return result;
+}
+
+/**
+ * Compute acceleration. Takes into account averaging, nv-reset, etc.
+ */
+static float
+ComputeAcceleration(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float threshold,
+ float acc){
+ float res;
+
+ if(vel->velocity <= 0){
+ DebugAccelF("(dix ptracc) profile skipped\n");
+ /*
+ * If we have no idea about device velocity, don't pretend it.
+ */
+ return 1;
+ }
+
+ if(vel->average_accel && vel->velocity != vel->last_velocity){
+ /* use simpson's rule to average acceleration between
+ * current and previous velocity.
+ * Though being the more natural choice, it causes a minor delay
+ * in comparison, so it can be disabled. */
+ res = BasicComputeAcceleration(
+ dev, vel, vel->velocity, threshold, acc);
+ res += BasicComputeAcceleration(
+ dev, vel, vel->last_velocity, threshold, acc);
+ res += 4.0f * BasicComputeAcceleration(dev, vel,
+ (vel->last_velocity + vel->velocity) / 2,
+ threshold, acc);
+ res /= 6.0f;
+ DebugAccelF("(dix ptracc) profile average [%.2f ... %.2f] is %.3f\n",
+ vel->velocity, vel->last_velocity, res);
+ return res;
+ }else{
+ res = BasicComputeAcceleration(dev, vel,
+ vel->velocity, threshold, acc);
+ DebugAccelF("(dix ptracc) profile sample [%.2f] is %.3f\n",
+ vel->velocity, res);
+ return res;
+ }
+}
+
+
+/*****************************************
+ * Acceleration functions and profiles
+ ****************************************/
+
+/**
+ * Polynomial function similar previous one, but with f(1) = 1
+ */
+static float
+PolynomialAccelerationProfile(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float ignored,
+ float acc)
+{
+ return pow(velocity, (acc - 1.0) * 0.5);
+}
+
+
+/**
+ * returns acceleration for velocity.
+ * This profile selects the two functions like the old scheme did
+ */
+static float
+ClassicProfile(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float threshold,
+ float acc)
+{
+ if (threshold > 0) {
+ return SimpleSmoothProfile (dev,
+ vel,
+ velocity,
+ threshold,
+ acc);
+ } else {
+ return PolynomialAccelerationProfile (dev,
+ vel,
+ velocity,
+ 0,
+ acc);
+ }
+}
+
+
+/**
+ * Power profile
+ * This has a completely smooth transition curve, i.e. no jumps in the
+ * derivatives.
+ *
+ * This has the expense of overall response dependency on min-acceleration.
+ * In effect, min_acceleration mimics const_acceleration in this profile.
+ */
+static float
+PowerProfile(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float threshold,
+ float acc)
+{
+ float vel_dist;
+
+ acc = (acc-1.0) * 0.1f + 1.0; /* without this, acc of 2 is unuseable */
+
+ if (velocity <= threshold)
+ return vel->min_acceleration;
+ vel_dist = velocity - threshold;
+ return (pow(acc, vel_dist)) * vel->min_acceleration;
+}
+
+
+/**
+ * just a smooth function in [0..1] -> [0..1]
+ * - point symmetry at 0.5
+ * - f'(0) = f'(1) = 0
+ * - starts faster than a sinoid
+ * - smoothness C1 (Cinf if you dare to ignore endpoints)
+ */
+static inline float
+CalcPenumbralGradient(float x){
+ x *= 2.0f;
+ x -= 1.0f;
+ return 0.5f + (x * sqrt(1.0f - x*x) + asin(x))/M_PI;
+}
+
+
+/**
+ * acceleration function similar to classic accelerated/unaccelerated,
+ * but with smooth transition in between (and towards zero for adaptive dec.).
+ */
+static float
+SimpleSmoothProfile(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float threshold,
+ float acc)
+{
+ if(velocity < 1.0f)
+ return CalcPenumbralGradient(0.5 + velocity*0.5) * 2.0f - 1.0f;
+ if(threshold < 1.0f)
+ threshold = 1.0f;
+ if (velocity <= threshold)
+ return 1;
+ velocity /= threshold;
+ if (velocity >= acc)
+ return acc;
+ else
+ return 1.0f + (CalcPenumbralGradient(velocity/acc) * (acc - 1.0f));
+}
+
+
+/**
+ * This profile uses the first half of the penumbral gradient as a start
+ * and then scales linearly.
+ */
+static float
+SmoothLinearProfile(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float threshold,
+ float acc)
+{
+ float res, nv;
+
+ if(acc > 1.0f)
+ acc -= 1.0f; /*this is so acc = 1 is no acceleration */
+ else
+ return 1.0f;
+
+ nv = (velocity - threshold) * acc * 0.5f;
+
+ if(nv < 0){
+ res = 0;
+ }else if(nv < 2){
+ res = CalcPenumbralGradient(nv*0.25f)*2.0f;
+ }else{
+ nv -= 2.0f;
+ res = nv * 2.0f / M_PI /* steepness of gradient at 0.5 */
+ + 1.0f; /* gradient crosses 2|1 */
+ }
+ res += vel->min_acceleration;
+ return res;
+}
+
+
+/**
+ * From 0 to threshold, the response graduates smoothly from min_accel to
+ * acceleration. Beyond threshold it is exactly the specified acceleration.
+ */
+static float
+SmoothLimitedProfile(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float threshold,
+ float acc)
+{
+ float res;
+
+ if(velocity >= threshold || threshold == 0.0f)
+ return acc;
+
+ velocity /= threshold; /* should be [0..1[ now */
+
+ res = CalcPenumbralGradient(velocity) * (acc - vel->min_acceleration);
+
+ return vel->min_acceleration + res;
+}
+
+
+static float
+LinearProfile(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float threshold,
+ float acc)
+{
+ return acc * velocity;
+}
+
+static float
+NoProfile(
+ DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float threshold,
+ float acc)
+{
+ return 1.0f;
+}
+
+static PointerAccelerationProfileFunc
+GetAccelerationProfile(
+ DeviceVelocityPtr vel,
+ int profile_num)
+{
+ switch(profile_num){
+ case AccelProfileClassic:
+ return ClassicProfile;
+ case AccelProfileDeviceSpecific:
+ return vel->deviceSpecificProfile;
+ case AccelProfilePolynomial:
+ return PolynomialAccelerationProfile;
+ case AccelProfileSmoothLinear:
+ return SmoothLinearProfile;
+ case AccelProfileSimple:
+ return SimpleSmoothProfile;
+ case AccelProfilePower:
+ return PowerProfile;
+ case AccelProfileLinear:
+ return LinearProfile;
+ case AccelProfileSmoothLimited:
+ return SmoothLimitedProfile;
+ case AccelProfileNone:
+ return NoProfile;
+ default:
+ return NULL;
+ }
+}
+
+/**
+ * Set the profile by number.
+ * Intended to make profiles exchangeable at runtime.
+ * If you created a profile, give it a number here and in the header to
+ * make it selectable. In case some profile-specific init is needed, here
+ * would be a good place, since FreeVelocityData() also calls this with
+ * PROFILE_UNINITIALIZE.
+ *
+ * returns FALSE if profile number is unavailable, TRUE otherwise.
+ */
+int
+SetAccelerationProfile(
+ DeviceVelocityPtr vel,
+ int profile_num)
+{
+ PointerAccelerationProfileFunc profile;
+ profile = GetAccelerationProfile(vel, profile_num);
+
+ if(profile == NULL && profile_num != PROFILE_UNINITIALIZE)
+ return FALSE;
+
+ /* Here one could free old profile-private data */
+ free(vel->profile_private);
+ vel->profile_private = NULL;
+ /* Here one could init profile-private data */
+ vel->Profile = profile;
+ vel->statistics.profile_number = profile_num;
+ return TRUE;
+}
+
+/**********************************************
+ * driver interaction
+ **********************************************/
+
+
+/**
+ * device-specific profile
+ *
+ * The device-specific profile is intended as a hook for a driver
+ * which may want to provide an own acceleration profile.
+ * It should not rely on profile-private data, instead
+ * it should do init/uninit in the driver (ie. with DEVICE_INIT and friends).
+ * Users may override or choose it.
+ */
+void
+SetDeviceSpecificAccelerationProfile(
+ DeviceVelocityPtr vel,
+ PointerAccelerationProfileFunc profile)
+{
+ if(vel)
+ vel->deviceSpecificProfile = profile;
+}
+
+/**
+ * Use this function to obtain a DeviceVelocityPtr for a device. Will return NULL if
+ * the predictable acceleration scheme is not in effect.
+ */
+DeviceVelocityPtr
+GetDevicePredictableAccelData(
+ DeviceIntPtr dev)
+{
+ /*sanity check*/
+ if(!dev){
+ ErrorF("[dix] accel: DeviceIntPtr was NULL");
+ return NULL;
+ }
+ if( dev->valuator &&
+ dev->valuator->accelScheme.AccelSchemeProc ==
+ acceleratePointerPredictable &&
+ dev->valuator->accelScheme.accelData != NULL){
+
+ return ((PredictableAccelSchemePtr)
+ dev->valuator->accelScheme.accelData)->vel;
+ }
+ return NULL;
+}
+
+/********************************
+ * acceleration schemes
+ *******************************/
+
+/**
+ * Modifies valuators in-place.
+ * This version employs a velocity approximation algorithm to
+ * enable fine-grained predictable acceleration profiles.
+ */
+void
+acceleratePointerPredictable(
+ DeviceIntPtr dev,
+ ValuatorMask* val,
+ CARD32 evtime)
+{
+ float fdx, fdy, tmp, mult; /* no need to init */
+ int dx = 0, dy = 0, tmpi;
+ DeviceVelocityPtr velocitydata = GetDevicePredictableAccelData(dev);
+ Bool soften = TRUE;
+
+ if (!velocitydata)
+ return;
+
+ if (velocitydata->statistics.profile_number == AccelProfileNone &&
+ velocitydata->const_acceleration == 1.0f) {
+ return; /*we're inactive anyway, so skip the whole thing.*/
+ }
+
+ if (valuator_mask_isset(val, 0)) {
+ dx = valuator_mask_get(val, 0);
+ }
+
+ if (valuator_mask_isset(val, 1)) {
+ dy = valuator_mask_get(val, 1);
+ }
+
+ if (dx || dy){
+ /* reset non-visible state? */
+ if (ProcessVelocityData2D(velocitydata, dx , dy, evtime)) {
+ soften = FALSE;
+ }
+
+ if (dev->ptrfeed && dev->ptrfeed->ctrl.num) {
+ /* invoke acceleration profile to determine acceleration */
+ mult = ComputeAcceleration (dev, velocitydata,
+ dev->ptrfeed->ctrl.threshold,
+ (float)dev->ptrfeed->ctrl.num /
+ (float)dev->ptrfeed->ctrl.den);
+
+ if(mult != 1.0f || velocitydata->const_acceleration != 1.0f) {
+ ApplySofteningAndConstantDeceleration(velocitydata,
+ dx, dy,
+ &fdx, &fdy,
+ (mult > 1.0f) && soften);
+
+ if (dx) {
+ tmp = mult * fdx + dev->last.remainder[0];
+ /* Since it may not be apparent: lrintf() does not offer
+ * strong statements about rounding; however because we
+ * process each axis conditionally, there's no danger
+ * of a toggling remainder. Its lack of guarantees likely
+ * makes it faster on the average target. */
+ tmpi = lrintf(tmp);
+ valuator_mask_set(val, 0, tmpi);
+ dev->last.remainder[0] = tmp - (float)tmpi;
+ }
+ if (dy) {
+ tmp = mult * fdy + dev->last.remainder[1];
+ tmpi = lrintf(tmp);
+ valuator_mask_set(val, 1, tmpi);
+ dev->last.remainder[1] = tmp - (float)tmpi;
+ }
+ DebugAccelF("pos (%i | %i) remainders x: %.3f y: %.3f delta x:%.3f y:%.3f\n",
+ *px, *py, dev->last.remainder[0], dev->last.remainder[1], fdx, fdy);
+ }
+ }
+ }
+ /* remember last motion delta (for softening/slow movement treatment) */
+ velocitydata->last_dx = dx;
+ velocitydata->last_dy = dy;
+}
+
+
+
+/**
+ * Originally a part of xf86PostMotionEvent; modifies valuators
+ * in-place. Retained mostly for embedded scenarios.
+ */
+void
+acceleratePointerLightweight(
+ DeviceIntPtr dev,
+ ValuatorMask* val,
+ CARD32 ignored)
+{
+ float mult = 0.0, tmpf;
+ int dx = 0, dy = 0, tmpi;
+
+ if (valuator_mask_isset(val, 0)) {
+ dx = valuator_mask_get(val, 0);
+ }
+
+ if (valuator_mask_isset(val, 1)) {
+ dy = valuator_mask_get(val, 1);
+ }
+
+ if (!dx && !dy)
+ return;
+
+ if (dev->ptrfeed && dev->ptrfeed->ctrl.num) {
+ /* modeled from xf86Events.c */
+ if (dev->ptrfeed->ctrl.threshold) {
+ if ((abs(dx) + abs(dy)) >= dev->ptrfeed->ctrl.threshold) {
+ tmpf = ((float)dx *
+ (float)(dev->ptrfeed->ctrl.num)) /
+ (float)(dev->ptrfeed->ctrl.den) +
+ dev->last.remainder[0];
+ if (dx) {
+ tmpi = (int) tmpf;
+ valuator_mask_set(val, 0, tmpi);
+ dev->last.remainder[0] = tmpf - (float)tmpi;
+ }
+
+ tmpf = ((float)dy *
+ (float)(dev->ptrfeed->ctrl.num)) /
+ (float)(dev->ptrfeed->ctrl.den) +
+ dev->last.remainder[1];
+ if (dy) {
+ tmpi = (int) tmpf;
+ valuator_mask_set(val, 1, tmpi);
+ dev->last.remainder[1] = tmpf - (float)tmpi;
+ }
+ }
+ }
+ else {
+ mult = pow((float)dx * (float)dx + (float)dy * (float)dy,
+ ((float)(dev->ptrfeed->ctrl.num) /
+ (float)(dev->ptrfeed->ctrl.den) - 1.0) /
+ 2.0) / 2.0;
+ if (dx) {
+ tmpf = mult * (float)dx +
+ dev->last.remainder[0];
+ tmpi = (int) tmpf;
+ valuator_mask_set(val, 0, tmpi);
+ dev->last.remainder[0] = tmpf - (float)tmpi;
+ }
+ if (dy) {
+ tmpf = mult * (float)dy +
+ dev->last.remainder[1];
+ tmpi = (int)tmpf;
+ valuator_mask_set(val, 1, tmpi);
+ dev->last.remainder[1] = tmpf - (float)tmpi;
+ }
+ }
+ }
+}