diff options
Diffstat (limited to 'xorg-server/dix/devices.c')
-rw-r--r-- | xorg-server/dix/devices.c | 1255 |
1 files changed, 899 insertions, 356 deletions
diff --git a/xorg-server/dix/devices.c b/xorg-server/dix/devices.c index 5a726afe8..3b8d544da 100644 --- a/xorg-server/dix/devices.c +++ b/xorg-server/dix/devices.c @@ -27,13 +27,13 @@ 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, +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 +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. +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 @@ -57,11 +57,13 @@ SOFTWARE. #define NEED_EVENTS #define NEED_REPLIES #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" #ifndef XKB_IN_SERVER #define XKB_IN_SERVER @@ -71,21 +73,109 @@ SOFTWARE. #endif #include "privates.h" #include "xace.h" +#include "mi.h" #include "dispatch.h" #include "swaprep.h" #include "dixevents.h" +#include "mipointer.h" #include <X11/extensions/XI.h> #include <X11/extensions/XIproto.h> #include "exglobals.h" #include "exevents.h" +#include "listdev.h" /* for CopySwapXXXClass */ +#include "xiproperty.h" +#include "enterleave.h" /* for EnterWindow() */ +#include "xserver-properties.h" /** @file * This file handles input device-related stuff. */ -DevPrivateKey CoreDevicePrivateKey = &CoreDevicePrivateKey; +static int CoreDevicePrivateKeyIndex; +DevPrivateKey CoreDevicePrivateKey = &CoreDevicePrivateKeyIndex; +/* Used to sture classes currently not in use by an MD */ +static int UnusedClassesPrivateKeyIndex; +DevPrivateKey UnusedClassesPrivateKey = &UnusedClassesPrivateKeyIndex; + + +/** + * 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); + else if (!(*((CARD8*)prop->data)) && dev->enabled) + DisableDevice(dev); + } + } + + 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 (!ptr->isMaster || !kbd->isMaster) + return BadDevice; + + if (ptr->spriteInfo->paired) + return BadDevice; + + if (kbd->spriteInfo->spriteOwner) + { + xfree(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 (dev->isMaster && + 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 @@ -95,69 +185,48 @@ DevPrivateKey CoreDevicePrivateKey = &CoreDevicePrivateKey; * @return The newly created device. */ DeviceIntPtr -AddInputDevice(DeviceProc deviceProc, Bool autoStart) +AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart) { DeviceIntPtr dev, *prev; /* not a typo */ DeviceIntPtr devtmp; int devid; - char devind[MAX_DEVICES]; + char devind[MAXDEVICES]; + BOOL enabled; /* Find next available id */ - memset(devind, 0, sizeof(char)*MAX_DEVICES); + 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 = 0; devid < MAX_DEVICES && devind[devid]; devid++) + for (devid = 0; devid < MAXDEVICES && devind[devid]; devid++) ; - if (devid >= MAX_DEVICES) + if (devid >= MAXDEVICES) return (DeviceIntPtr)NULL; - dev = (DeviceIntPtr) xcalloc(sizeof(DeviceIntRec), 1); + dev = xcalloc(sizeof(DeviceIntRec) + sizeof(SpriteInfoRec), 1); if (!dev) return (DeviceIntPtr)NULL; - dev->name = (char *)NULL; - dev->type = 0; dev->id = devid; - dev->public.on = FALSE; dev->public.processInputProc = (ProcessInputProc)NoopDDA; dev->public.realInputProc = (ProcessInputProc)NoopDDA; dev->public.enqueueInputProc = EnqueueEvent; dev->deviceProc = deviceProc; dev->startup = autoStart; - dev->sync.frozen = FALSE; - dev->sync.other = NullGrab; - dev->sync.state = NOT_GRABBED; - dev->sync.event = (xEvent *) NULL; - dev->sync.evcount = 0; - dev->grab = NullGrab; - dev->grabTime = currentTime; - dev->fromPassiveGrab = FALSE; - dev->key = (KeyClassPtr)NULL; - dev->valuator = (ValuatorClassPtr)NULL; - dev->button = (ButtonClassPtr)NULL; - dev->focus = (FocusClassPtr)NULL; - dev->proximity = (ProximityClassPtr)NULL; - dev->absolute = (AbsoluteClassPtr)NULL; - dev->kbdfeed = (KbdFeedbackPtr)NULL; - dev->ptrfeed = (PtrFeedbackPtr)NULL; - dev->intfeed = (IntegerFeedbackPtr)NULL; - dev->stringfeed = (StringFeedbackPtr)NULL; - dev->bell = (BellFeedbackPtr)NULL; - dev->leds = (LedFeedbackPtr)NULL; -#ifdef XKB - dev->xkb_interest = NULL; -#endif - dev->config_info = NULL; - dev->devPrivates = NULL; - dev->unwrapProc = NULL; + + /* device grab defaults */ + dev->deviceGrab.grabTime = currentTime; + dev->deviceGrab.ActivateGrab = ActivateKeyboardGrab; + dev->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab; + dev->coreEvents = TRUE; - dev->inited = FALSE; - dev->enabled = FALSE; + + /* sprite defaults */ + dev->spriteInfo = (SpriteInfoPtr)&dev[1]; /* security creation/labeling check */ - if (XaceHook(XACE_DEVICE_ACCESS, serverClient, dev, DixCreateAccess)) { + if (XaceHook(XACE_DEVICE_ACCESS, client, dev, DixCreateAccess)) { xfree(dev); return NULL; } @@ -169,14 +238,24 @@ AddInputDevice(DeviceProc deviceProc, Bool autoStart) *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); + XIRegisterPropertyHandler(dev, DeviceSetProperty, NULL, NULL); + return dev; } /** + * 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. All clients are notified about the device being enabled. + * list. Initialize the DIX sprite or pair the device. All clients are + * notified about the device being enabled. * - * A device will send events once enabled. + * A master pointer device needs to be enabled before a master keyboard + * device. * * @param The device to be enabled. * @return TRUE on success or FALSE otherwise. @@ -187,15 +266,62 @@ EnableDevice(DeviceIntPtr dev) DeviceIntPtr *prev; int ret; DeviceIntRec dummyDev; + DeviceIntPtr other; devicePresenceNotify ev; + int namelen = 0; /* dummy */ + int evsize = sizeof(xEvent); + int listlen; + EventListPtr evlist; + BOOL enabled; for (prev = &inputInfo.off_devices; *prev && (*prev != dev); prev = &(*prev)->next) ; + + if (!dev->spriteInfo->sprite) + { + if (dev->isMaster) + { + /* Sprites appear on first root window, so we can hardcode it */ + if (dev->spriteInfo->spriteOwner) + { + InitializeSprite(dev, WindowTable[0]); + /* mode doesn't matter */ + EnterWindow(dev, WindowTable[0], 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 + { + other = (IsPointerDevice(dev)) ? inputInfo.pointer : + inputInfo.keyboard; + AttachDevice(NULL, dev, other); + } + } + + /* Before actually enabling the device, we need to make sure the event + * list's events have enough memory for a ClassesChangedEvent from the + * device + */ + + SizeDeviceInfo(dev, &namelen, &evsize); + + listlen = GetEventList(&evlist); + OsBlockSignals(); + SetMinimumEventSize(evlist, listlen, evsize); + mieqResizeEvents(evsize); + OsReleaseSignals(); + + if ((*prev != dev) || !dev->inited || ((ret = (*dev->deviceProc)(dev, DEVICE_ON)) != Success)) { - ErrorF("couldn't enable device %d\n", dev->id); + ErrorF("[dix] couldn't enable device %d\n", dev->id); return FALSE; } dev->enabled = TRUE; @@ -206,11 +332,16 @@ EnableDevice(DeviceIntPtr dev) *prev = dev; dev->next = NULL; + enabled = TRUE; + XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED), + XA_INTEGER, 8, PropModeReplace, 1, &enabled, + TRUE); + ev.type = DevicePresenceNotify; ev.time = currentTime.milliseconds; ev.devchange = DeviceEnabled; ev.deviceid = dev->id; - dummyDev.id = 0; + dummyDev.id = MAXDEVICES; SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask, (xEvent *) &ev, 1); @@ -222,14 +353,18 @@ EnableDevice(DeviceIntPtr dev) * 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. + * * @return TRUE on success or FALSE otherwise. */ Bool DisableDevice(DeviceIntPtr dev) { - DeviceIntPtr *prev; + DeviceIntPtr *prev, other; DeviceIntRec dummyDev; devicePresenceNotify ev; + BOOL enabled; for (prev = &inputInfo.devices; *prev && (*prev != dev); @@ -237,17 +372,54 @@ DisableDevice(DeviceIntPtr dev) ; if (*prev != dev) return FALSE; + + /* float attached devices */ + if (dev->isMaster) + { + for (other = inputInfo.devices; other; other = other->next) + { + if (other->u.master == dev) + AttachDevice(NULL, other, NULL); + } + } + else + { + for (other = inputInfo.devices; other; other = other->next) + { + if (other->isMaster && other->u.lastSlave == dev) + other->u.lastSlave = NULL; + } + } + + if (dev->isMaster && 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; *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); + ev.type = DevicePresenceNotify; ev.time = currentTime.milliseconds; ev.devchange = DeviceDisabled; ev.deviceid = dev->id; - dummyDev.id = 0; + dummyDev.id = MAXDEVICES; SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask, (xEvent *) &ev, 1); @@ -257,7 +429,8 @@ DisableDevice(DeviceIntPtr dev) /** * 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! * * @return Success or an error code on failure. @@ -268,18 +441,27 @@ ActivateDevice(DeviceIntPtr dev) int ret = Success; devicePresenceNotify ev; DeviceIntRec dummyDev; + 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 (dev->isMaster && dev->spriteInfo->spriteOwner) + pScreen->DeviceCursorInitialize(dev, pScreen); + ev.type = DevicePresenceNotify; ev.time = currentTime.milliseconds; ev.devchange = DeviceAdded; ev.deviceid = dev->id; - dummyDev.id = 0; + + memset(&dummyDev, 0, sizeof(DeviceIntRec)); + dummyDev.id = MAXDEVICES; SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask, (xEvent *) &ev, 1); @@ -305,7 +487,7 @@ CoreKeyboardCtl(DeviceIntPtr pDev, KeybdCtrl *ctrl) } /** - * Device control function for the Virtual Core Keyboard. + * Device control function for the Virtual Core Keyboard. */ static int CoreKeyboardProc(DeviceIntPtr pDev, int what) @@ -315,9 +497,16 @@ CoreKeyboardProc(DeviceIntPtr pDev, int what) #ifdef XKB XkbComponentNamesRec names; #endif + ClassesPtr classes; switch (what) { case DEVICE_INIT: + if (!(classes = xcalloc(1, sizeof(ClassesRec)))) + { + ErrorF("[dix] Could not allocate device classes.\n"); + return BadAlloc; + } + keySyms.minKeyCode = 8; keySyms.maxKeyCode = 255; keySyms.mapWidth = 4; @@ -326,21 +515,21 @@ CoreKeyboardProc(DeviceIntPtr pDev, int what) keySyms.minKeyCode + 1) * keySyms.mapWidth); if (!keySyms.map) { - ErrorF("Couldn't allocate core keymap\n"); + ErrorF("[dix] Couldn't allocate core keymap\n"); + xfree(classes); return BadAlloc; } - modMap = (CARD8 *)xalloc(MAP_LENGTH); + modMap = xcalloc(1, MAP_LENGTH); if (!modMap) { - ErrorF("Couldn't allocate core modifier map\n"); + ErrorF("[dix] Couldn't allocate core modifier map\n"); + xfree(classes); return BadAlloc; } - bzero((char *)modMap, MAP_LENGTH); #ifdef XKB if (!noXkbExtension) { bzero(&names, sizeof(names)); - XkbSetRulesDflts("base", "pc105", "us", NULL, NULL); XkbInitKeyboardDeviceStruct(pDev, &names, &keySyms, modMap, CoreKeyboardBell, CoreKeyboardCtl); } @@ -354,11 +543,9 @@ CoreKeyboardProc(DeviceIntPtr pDev, int what) xfree(keySyms.map); xfree(modMap); - break; case DEVICE_CLOSE: - dixSetPrivate(&pDev->devPrivates, CoreDevicePrivateKey, NULL); break; default: @@ -369,28 +556,34 @@ CoreKeyboardProc(DeviceIntPtr pDev, int what) /** * Device control function for the Virtual Core Pointer. + * + * Aside from initialisation, it backs up the original device classes into the + * devicePrivates. This only needs to be done for master devices. */ static int CorePointerProc(DeviceIntPtr pDev, int what) { BYTE map[33]; int i = 0; + ClassesPtr classes; switch (what) { case DEVICE_INIT: + if (!(classes = xcalloc(1, sizeof(ClassesRec)))) + return BadAlloc; + for (i = 1; i <= 32; i++) map[i] = i; InitPointerDeviceStruct((DevicePtr)pDev, map, 32, - GetMotionHistory, (PtrCtrlProcPtr)NoopDDA, + (PtrCtrlProcPtr)NoopDDA, GetMotionHistorySize(), 2); pDev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2; - pDev->valuator->lastx = pDev->valuator->axisVal[0]; + pDev->last.valuators[0] = pDev->valuator->axisVal[0]; pDev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2; - pDev->valuator->lasty = pDev->valuator->axisVal[1]; + pDev->last.valuators[1] = pDev->valuator->axisVal[1]; break; case DEVICE_CLOSE: - dixSetPrivate(&pDev->devPrivates, CoreDevicePrivateKey, NULL); break; default: @@ -402,68 +595,41 @@ CorePointerProc(DeviceIntPtr pDev, int what) /** * Initialise the two core devices, VCP and VCK (see events.c). - * The devices are activated but not enabled. + * 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) { - DeviceIntPtr dev; + if (AllocMasterDevice(serverClient, "Virtual core", + &inputInfo.pointer, + &inputInfo.keyboard) != Success) + FatalError("Failed to allocate core devices"); + + ActivateDevice(inputInfo.pointer); + ActivateDevice(inputInfo.keyboard); + EnableDevice(inputInfo.pointer); + EnableDevice(inputInfo.keyboard); - if (!inputInfo.keyboard) { - dev = AddInputDevice(CoreKeyboardProc, TRUE); - if (!dev) - FatalError("Failed to allocate core keyboard"); - dev->name = strdup("Virtual core keyboard"); -#ifdef XKB - dev->public.processInputProc = CoreProcessKeyboardEvent; - dev->public.realInputProc = CoreProcessKeyboardEvent; - if (!noXkbExtension) - XkbSetExtension(dev, ProcessKeyboardEvent); -#else - dev->public.processInputProc = ProcessKeyboardEvent; - dev->public.realInputProc = ProcessKeyboardEvent; -#endif - dev->ActivateGrab = ActivateKeyboardGrab; - dev->DeactivateGrab = DeactivateKeyboardGrab; - dev->coreEvents = FALSE; - (void)ActivateDevice(dev); - inputInfo.keyboard = dev; - } - - if (!inputInfo.pointer) { - dev = AddInputDevice(CorePointerProc, TRUE); - if (!dev) - FatalError("Failed to allocate core pointer"); - dev->name = strdup("Virtual core pointer"); -#ifdef XKB - dev->public.processInputProc = CoreProcessPointerEvent; - dev->public.realInputProc = CoreProcessPointerEvent; - if (!noXkbExtension) - XkbSetExtension(dev, ProcessPointerEvent); -#else - dev->public.processInputProc = ProcessPointerEvent; - dev->public.realInputProc = ProcessPointerEvent; -#endif - dev->ActivateGrab = ActivatePointerGrab; - dev->DeactivateGrab = DeactivatePointerGrab; - dev->coreEvents = FALSE; - (void)ActivateDevice(dev); - inputInfo.pointer = dev; - } } /** * 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) +InitAndStartDevices() { DeviceIntPtr dev, next; @@ -472,6 +638,8 @@ InitAndStartDevices(void) if (!dev->inited) ActivateDevice(dev); } + + /* enable real devices */ for (dev = inputInfo.off_devices; dev; dev = next) { DebugF("(dix) enabling device %d\n", dev->id); @@ -479,27 +647,183 @@ InitAndStartDevices(void) if (dev->inited && dev->startup) (void)EnableDevice(dev); } - for (dev = inputInfo.devices; - dev && (dev != inputInfo.keyboard); - dev = dev->next) - ; - if (!dev || (dev != inputInfo.keyboard)) { - ErrorF("No core keyboard\n"); - return BadImplementation; + + 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; +#ifdef XKB + if ((*k)->xkbInfo) + { + XkbFreeInfo((*k)->xkbInfo); + (*k)->xkbInfo = NULL; + } +#endif + xfree((*k)->curKeySyms.map); + xfree((*k)->modifierKeyMap); + xfree((*k)); + break; + } + case ButtonClass: + { + ButtonClassPtr *b = (ButtonClassPtr*)class; +#ifdef XKB + if ((*b)->xkb_acts) + xfree((*b)->xkb_acts); +#endif + xfree((*b)); + break; + } + case ValuatorClass: + { + ValuatorClassPtr *v = (ValuatorClassPtr*)class; + + /* Counterpart to 'biggest hack ever' in init. */ + if ((*v)->motion) + xfree((*v)->motion); + xfree((*v)); + break; + } + case FocusClass: + { + FocusClassPtr *f = (FocusClassPtr*)class; + xfree((*f)->trace); + xfree((*f)); + break; + } + case ProximityClass: + { + ProximityClassPtr *p = (ProximityClassPtr*)class; + xfree((*p)); + break; + } } - for (dev = inputInfo.devices; - dev && (dev != inputInfo.pointer); - dev = dev->next) - ; - if (!dev || (dev != inputInfo.pointer)) { - ErrorF("No core pointer\n"); - return BadImplementation; + *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; +#ifdef XKB + if (k->xkb_sli) + XkbFreeSrvLedInfo(k->xkb_sli); +#endif + xfree(k); + } + break; + } + case PtrFeedbackClass: + { + PtrFeedbackPtr *ptrfeed = (PtrFeedbackPtr*)class; + PtrFeedbackPtr p, pnext; + + for (p = (*ptrfeed); p; p = pnext) { + pnext = p->next; + xfree(p); + } + break; + } + case IntegerFeedbackClass: + { + IntegerFeedbackPtr *intfeed = (IntegerFeedbackPtr*)class; + IntegerFeedbackPtr i, inext; + + for (i = (*intfeed); i; i = inext) { + inext = i->next; + xfree(i); + } + break; + } + case StringFeedbackClass: + { + StringFeedbackPtr *stringfeed = (StringFeedbackPtr*)class; + StringFeedbackPtr s, snext; + + for (s = (*stringfeed); s; s = snext) { + snext = s->next; + xfree(s->ctrl.symbols_supported); + xfree(s->ctrl.symbols_displayed); + xfree(s); + } + break; + } + case BellFeedbackClass: + { + BellFeedbackPtr *bell = (BellFeedbackPtr*)class; + BellFeedbackPtr b, bnext; + + for (b = (*bell); b; b = bnext) { + bnext = b->next; + xfree(b); + } + break; + } + case LedFeedbackClass: + { + LedFeedbackPtr *leds = (LedFeedbackPtr*)class; + LedFeedbackPtr l, lnext; + + for (l = (*leds); l; l = lnext) { + lnext = l->next; +#ifdef XKB + if (l->xkb_sli) + XkbFreeSrvLedInfo(l->xkb_sli); +#endif + xfree(l); + } + break; + } } - return Success; + *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. + * 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(). @@ -508,106 +832,65 @@ InitAndStartDevices(void) static void CloseDevice(DeviceIntPtr dev) { - KbdFeedbackPtr k, knext; - PtrFeedbackPtr p, pnext; - IntegerFeedbackPtr i, inext; - StringFeedbackPtr s, snext; - BellFeedbackPtr b, bnext; - LedFeedbackPtr l, lnext; + ScreenPtr screen = screenInfo.screens[0]; + ClassesPtr classes; + int j; + + if (!dev) + return; + + XIDeleteAllDeviceProperties(dev); if (dev->inited) (void)(*dev->deviceProc)(dev, DEVICE_CLOSE); - xfree(dev->name); + /* free sprite memory */ + if (dev->isMaster && dev->spriteInfo->sprite) + screen->DeviceCursorCleanup(dev, screen); - if (dev->key) { -#ifdef XKB - if (dev->key->xkbInfo) - XkbFreeInfo(dev->key->xkbInfo); -#endif - dev->key->xkbInfo = NULL; - xfree(dev->key->curKeySyms.map); - xfree(dev->key->modifierKeyMap); - xfree(dev->key); - dev->key = NULL; - } + /* free acceleration info */ + if(dev->valuator && dev->valuator->accelScheme.AccelCleanupProc) + dev->valuator->accelScheme.AccelCleanupProc(dev); - if (dev->valuator) { - /* Counterpart to 'biggest hack ever' in init. */ - if (dev->valuator->motion && - dev->valuator->GetMotionProc == GetMotionHistory) - xfree(dev->valuator->motion); - xfree(dev->valuator); - } + xfree(dev->name); - if (dev->button) { -#ifdef XKB - if (dev->button->xkb_acts) - xfree(dev->button->xkb_acts); -#endif - xfree(dev->button); - } + classes = (ClassesPtr)&dev->key; + FreeAllDeviceClasses(classes); - if (dev->focus) { - xfree(dev->focus->trace); - xfree(dev->focus); + if (dev->isMaster) + { + classes = dixLookupPrivate(&dev->devPrivates, UnusedClassesPrivateKey); + FreeAllDeviceClasses(classes); } - if (dev->proximity) - xfree(dev->proximity); - for (k = dev->kbdfeed; k; k = knext) { - knext = k->next; #ifdef XKB - if (k->xkb_sli) - XkbFreeSrvLedInfo(k->xkb_sli); + while (dev->xkb_interest) + XkbRemoveResourceClient((DevicePtr)dev,dev->xkb_interest->resource); #endif - xfree(k); - } - for (p = dev->ptrfeed; p; p = pnext) { - pnext = p->next; - xfree(p); - } - - for (i = dev->intfeed; i; i = inext) { - inext = i->next; - xfree(i); + if (DevHasCursor(dev) && dev->spriteInfo->sprite) { + xfree(dev->spriteInfo->sprite->spriteTrace); + xfree(dev->spriteInfo->sprite); } - for (s = dev->stringfeed; s; s = snext) { - snext = s->next; - xfree(s->ctrl.symbols_supported); - xfree(s->ctrl.symbols_displayed); - xfree(s); - } - - for (b = dev->bell; b; b = bnext) { - bnext = b->next; - xfree(b); - } - - for (l = dev->leds; l; l = lnext) { - lnext = l->next; -#ifdef XKB - if (l->xkb_sli) - XkbFreeSrvLedInfo(l->xkb_sli); -#endif - xfree(l); + /* 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]); + } } -#ifdef XKB - while (dev->xkb_interest) - XkbRemoveResourceClient((DevicePtr)dev,dev->xkb_interest->resource); -#endif - - xfree(dev->sync.event); + xfree(dev->deviceGrab.sync.event); dixFreePrivates(dev->devPrivates); xfree(dev); } /** - * Shut down all devices, free all resources, etc. + * Shut down all devices, free all resources, etc. * Only useful if you're shutting down the server! */ void @@ -615,6 +898,17 @@ CloseDownDevices(void) { DeviceIntPtr dev, next; + /* 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 (!dev->isMaster && dev->u.master) + dev->u.master = NULL; + } + for (dev = inputInfo.devices; dev; dev = next) { next = dev->next; @@ -625,17 +919,40 @@ CloseDownDevices(void) next = dev->next; DeleteInputDeviceRequest(dev); } + inputInfo.devices = NULL; inputInfo.off_devices = NULL; inputInfo.keyboard = NULL; inputInfo.pointer = NULL; +#ifdef XKB + XkbDeleteRulesDflts(); +#endif +} + +/** + * Remove the cursor sprite for all devices. This needs to be done before any + * resources are freed or any device is deleted. + */ +void +UndisplayDevices() +{ + 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. + * 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. */ int RemoveDevice(DeviceIntPtr dev) @@ -644,13 +961,19 @@ RemoveDevice(DeviceIntPtr dev) int ret = BadMatch; devicePresenceNotify ev; DeviceIntRec dummyDev; + ScreenPtr screen = screenInfo.screens[0]; int deviceid; + int initialized; DebugF("(dix) removing device %d\n", dev->id); if (!dev || dev == inputInfo.keyboard || dev == inputInfo.pointer) return BadImplementation; + initialized = dev->inited; + if (DevHasCursor(dev)) + screen->DisplayCursor(dev, screen, NullCursor); + deviceid = dev->id; DisableDevice(dev); @@ -658,13 +981,13 @@ RemoveDevice(DeviceIntPtr dev) for (tmp = inputInfo.devices; tmp; (prev = tmp), (tmp = next)) { next = tmp->next; if (tmp == dev) { - CloseDevice(tmp); if (prev==NULL) inputInfo.devices = next; else prev->next = next; + CloseDevice(tmp); ret = Success; } } @@ -683,14 +1006,14 @@ RemoveDevice(DeviceIntPtr dev) ret = Success; } } - - if (ret == Success) { + + if (ret == Success && initialized) { inputInfo.numDevices--; ev.type = DevicePresenceNotify; ev.time = currentTime.milliseconds; ev.devchange = DeviceRemoved; ev.deviceid = deviceid; - dummyDev.id = 0; + dummyDev.id = MAXDEVICES; SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask, (xEvent *) &ev, 1); } @@ -701,6 +1024,8 @@ RemoveDevice(DeviceIntPtr dev) 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; } @@ -776,10 +1101,9 @@ SetKeySymsMap(KeySymsPtr dst, KeySymsPtr src) KeySym *map; int bytes = sizeof(KeySym) * src->mapWidth * (dst->maxKeyCode - dst->minKeyCode + 1); - map = (KeySym *)xalloc(bytes); + map = (KeySym *)xcalloc(1, bytes); if (!map) return FALSE; - bzero((char *)map, bytes); if (dst->map) { for (i = 0; i <= dst->maxKeyCode-dst->minKeyCode; i++) @@ -790,6 +1114,16 @@ SetKeySymsMap(KeySymsPtr dst, KeySymsPtr src) } dst->mapWidth = src->mapWidth; dst->map = map; + } else if (!dst->map) + { + KeySym *map; + int bytes = sizeof(KeySym) * src->mapWidth * + (dst->maxKeyCode - dst->minKeyCode + 1); + map = (KeySym *)xcalloc(1, bytes); + if (!map) + return FALSE; + dst->map = map; + dst->mapWidth = src->mapWidth; } memmove((char *)&dst->map[rowDif * dst->mapWidth], (char *)src->map, @@ -819,10 +1153,9 @@ InitModMap(KeyClassPtr keyc) } } } - keyc->modifierKeyMap = (KeyCode *)xalloc(8*keyc->maxKeysPerModifier); + keyc->modifierKeyMap = xcalloc(8, keyc->maxKeysPerModifier); if (!keyc->modifierKeyMap && keyc->maxKeysPerModifier) return (FALSE); - bzero((char *)keyc->modifierKeyMap, 8*(int)keyc->maxKeysPerModifier); for (i = 0; i < 8; i++) keysPerModifier[i] = 0; for (i = 8; i < MAP_LENGTH; i++) @@ -843,27 +1176,15 @@ InitModMap(KeyClassPtr keyc) _X_EXPORT Bool InitKeyClassDeviceStruct(DeviceIntPtr dev, KeySymsPtr pKeySyms, CARD8 pModifiers[]) { - int i; KeyClassPtr keyc; - - keyc = (KeyClassPtr)xalloc(sizeof(KeyClassRec)); + + keyc = xcalloc(1, sizeof(KeyClassRec)); if (!keyc) return FALSE; - keyc->curKeySyms.map = (KeySym *)NULL; - keyc->curKeySyms.mapWidth = 0; keyc->curKeySyms.minKeyCode = pKeySyms->minKeyCode; keyc->curKeySyms.maxKeyCode = pKeySyms->maxKeyCode; - keyc->modifierKeyMap = (KeyCode *)NULL; - keyc->state = 0; - keyc->prev_state = 0; if (pModifiers) memmove((char *)keyc->modifierMap, (char *)pModifiers, MAP_LENGTH); - else - bzero((char *)keyc->modifierMap, MAP_LENGTH); - bzero((char *)keyc->down, DOWN_LENGTH); - bzero((char *)keyc->postdown, DOWN_LENGTH); - for (i = 0; i < 8; i++) - keyc->modifierKeyCount[i] = 0; if (!SetKeySymsMap(&keyc->curKeySyms, pKeySyms) || !InitModMap(keyc)) { xfree(keyc->curKeySyms.map); @@ -880,32 +1201,24 @@ InitKeyClassDeviceStruct(DeviceIntPtr dev, KeySymsPtr pKeySyms, CARD8 pModifiers } _X_EXPORT Bool -InitButtonClassDeviceStruct(DeviceIntPtr dev, int numButtons, +InitButtonClassDeviceStruct(DeviceIntPtr dev, int numButtons, CARD8 *map) { ButtonClassPtr butc; int i; - butc = (ButtonClassPtr)xalloc(sizeof(ButtonClassRec)); + butc = xcalloc(1, sizeof(ButtonClassRec)); if (!butc) return FALSE; butc->numButtons = numButtons; for (i = 1; i <= numButtons; i++) butc->map[i] = map[i]; - butc->buttonsDown = 0; - butc->state = 0; - butc->motionMask = 0; - bzero((char *)butc->down, DOWN_LENGTH); -#ifdef XKB - butc->xkb_acts= NULL; -#endif dev->button = butc; return TRUE; } _X_EXPORT Bool -InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, - ValuatorMotionProcPtr motionProc, +InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, int numMotionEvents, int mode) { int i; @@ -914,7 +1227,7 @@ InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, if (!dev) return FALSE; - valc = (ValuatorClassPtr)xalloc(sizeof(ValuatorClassRec) + + valc = (ValuatorClassPtr)xcalloc(1, sizeof(ValuatorClassRec) + numAxes * sizeof(AxisInfo) + numAxes * sizeof(unsigned int)); if (!valc) @@ -923,7 +1236,6 @@ InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, valc->motion = NULL; valc->first_motion = 0; valc->last_motion = 0; - valc->GetMotionProc = motionProc; valc->numMotionEvents = numMotionEvents; valc->motionHintWindow = NullWindow; @@ -931,20 +1243,82 @@ InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, valc->mode = mode; valc->axes = (AxisInfoPtr)(valc + 1); valc->axisVal = (int *)(valc->axes + numAxes); - valc->lastx = 0; - valc->lasty = 0; - valc->dxremaind = 0; - valc->dyremaind = 0; dev->valuator = valc; - /* biggest hack ever. */ - if (motionProc == GetMotionHistory) - AllocateMotionHistory(dev); + AllocateMotionHistory(dev); for (i=0; i<numAxes; i++) { - InitValuatorAxisStruct(dev, i, 0, -1, 0, 0, 0); + InitValuatorAxisStruct(dev, i, NO_AXIS_LIMITS, NO_AXIS_LIMITS, + 0, 0, 0); valc->axisVal[i]=0; } + + dev->last.numValuators = numAxes; + if(dev->isMaster) /* master devs do not accelerate */ + InitPointerAccelerationScheme(dev, PtrAccelNoOp); + else + InitPointerAccelerationScheme(dev, PtrAccelDefault); + return TRUE; +} + +/* global list of acceleration schemes */ +ValuatorAccelerationRec pointerAccelerationScheme[] = { + {PtrAccelNoOp, NULL, NULL, NULL}, + {PtrAccelPredictable, acceleratePointerPredictable, NULL, AccelerationDefaultCleanup}, + {PtrAccelLightweight, acceleratePointerLightweight, NULL, NULL}, + {-1, NULL, NULL, NULL} /* terminator */ +}; + +/** + * install an acceleration scheme. returns TRUE on success, and should not + * change anything if unsuccessful. + */ +_X_EXPORT Bool +InitPointerAccelerationScheme(DeviceIntPtr dev, + int scheme) +{ + int x, i = -1; + void* data = NULL; + ValuatorClassPtr val; + + val = dev->valuator; + + if(!val) + return FALSE; + + if(dev->isMaster && (scheme != PtrAccelNoOp)) + scheme = PtrAccelNoOp; /* no accel for master devices */ + + for(x = 0; pointerAccelerationScheme[x].number >= 0; x++) { + if(pointerAccelerationScheme[x].number == scheme){ + i = x; + break; + } + } + + if(-1 == i) + return FALSE; + + + /* init scheme-specific data */ + switch(scheme){ + case PtrAccelPredictable: + { + DeviceVelocityPtr s; + s = (DeviceVelocityPtr)xalloc(sizeof(DeviceVelocityRec)); + if(!s) + return FALSE; + InitVelocityData(s); + data = s; + break; + } + default: + break; + } + + val->accelScheme = pointerAccelerationScheme[i]; + val->accelScheme.accelData = data; + return TRUE; } @@ -958,10 +1332,10 @@ InitAbsoluteClassDeviceStruct(DeviceIntPtr dev) return FALSE; /* we don't do anything sensible with these, but should */ - abs->min_x = -1; - abs->min_y = -1; - abs->max_x = -1; - abs->max_y = -1; + 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; @@ -969,8 +1343,8 @@ InitAbsoluteClassDeviceStruct(DeviceIntPtr dev) abs->offset_x = 0; abs->offset_y = 0; - abs->width = -1; - abs->height = -1; + abs->width = NO_AXIS_LIMITS; + abs->height = NO_AXIS_LIMITS; abs->following = 0; abs->screen = 0; @@ -998,7 +1372,7 @@ InitFocusClassDeviceStruct(DeviceIntPtr dev) } _X_EXPORT Bool -InitKbdFeedbackClassDeviceStruct(DeviceIntPtr dev, BellProcPtr bellProc, +InitKbdFeedbackClassDeviceStruct(DeviceIntPtr dev, BellProcPtr bellProc, KbdCtrlProcPtr controlProc) { KbdFeedbackPtr feedc; @@ -1062,7 +1436,7 @@ static IntegerCtrl defaultIntegerControl = { _X_EXPORT Bool InitStringFeedbackClassDeviceStruct ( - DeviceIntPtr dev, StringCtrlProcPtr controlProc, + DeviceIntPtr dev, StringCtrlProcPtr controlProc, int max_symbols, int num_symbols_supported, KeySym *symbols) { int i; @@ -1075,9 +1449,9 @@ InitStringFeedbackClassDeviceStruct ( feedc->ctrl.num_symbols_supported = num_symbols_supported; feedc->ctrl.num_symbols_displayed = 0; feedc->ctrl.max_symbols = max_symbols; - feedc->ctrl.symbols_supported = (KeySym *) + feedc->ctrl.symbols_supported = (KeySym *) xalloc (sizeof (KeySym) * num_symbols_supported); - feedc->ctrl.symbols_displayed = (KeySym *) + feedc->ctrl.symbols_displayed = (KeySym *) xalloc (sizeof (KeySym) * max_symbols); if (!feedc->ctrl.symbols_supported || !feedc->ctrl.symbols_displayed) { @@ -1101,7 +1475,7 @@ InitStringFeedbackClassDeviceStruct ( } _X_EXPORT Bool -InitBellFeedbackClassDeviceStruct (DeviceIntPtr dev, BellProcPtr bellProc, +InitBellFeedbackClassDeviceStruct (DeviceIntPtr dev, BellProcPtr bellProc, BellCtrlProcPtr controlProc) { BellFeedbackPtr feedc; @@ -1160,23 +1534,22 @@ InitIntegerFeedbackClassDeviceStruct (DeviceIntPtr dev, IntegerCtrlProcPtr contr } _X_EXPORT Bool -InitPointerDeviceStruct(DevicePtr device, CARD8 *map, int numButtons, - ValuatorMotionProcPtr motionProc, +InitPointerDeviceStruct(DevicePtr device, CARD8 *map, int numButtons, PtrCtrlProcPtr controlProc, int numMotionEvents, int numAxes) { DeviceIntPtr dev = (DeviceIntPtr)device; return(InitButtonClassDeviceStruct(dev, numButtons, map) && - InitValuatorClassDeviceStruct(dev, numAxes, motionProc, + InitValuatorClassDeviceStruct(dev, numAxes, numMotionEvents, 0) && InitPtrFeedbackClassDeviceStruct(dev, controlProc)); } _X_EXPORT Bool -InitKeyboardDeviceStruct(DevicePtr device, KeySymsPtr pKeySyms, - CARD8 pModifiers[], BellProcPtr bellProc, - KbdCtrlProcPtr controlProc) +InitKeyboardDeviceStruct(DevicePtr device, KeySymsPtr pKeySyms, + CARD8 pModifiers[], BellProcPtr bellProc, + KbdCtrlProcPtr controlProc) { DeviceIntPtr dev = (DeviceIntPtr)device; @@ -1186,8 +1559,8 @@ InitKeyboardDeviceStruct(DevicePtr device, KeySymsPtr pKeySyms, } _X_EXPORT void -SendMappingNotify(unsigned request, unsigned firstKeyCode, unsigned count, - ClientPtr client) +SendMappingNotify(DeviceIntPtr pDev, unsigned request, unsigned firstKeyCode, + unsigned count, ClientPtr client) { int i; xEvent event; @@ -1201,9 +1574,9 @@ SendMappingNotify(unsigned request, unsigned firstKeyCode, unsigned count, } #ifdef XKB if (!noXkbExtension && - ((request == MappingKeyboard) || (request == MappingModifier))) - XkbApplyMappingChange(inputInfo.keyboard, request, firstKeyCode, count, - client); + ((request == MappingKeyboard) || (request == MappingModifier))) { + XkbApplyMappingChange(pDev,request,firstKeyCode,count, client); + } #endif /* 0 is the server client */ @@ -1225,13 +1598,15 @@ SendMappingNotify(unsigned request, unsigned firstKeyCode, unsigned count, } /* - * n-squared algorithm. n < 255 and don't want to copy the whole thing and - * sort it to do the checking. How often is it called? Just being lazy? + * 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, j; + int i; for (i = 0; i < length; i++) if (buff[i]) /* only check non-zero elements */ @@ -1241,12 +1616,6 @@ BadDeviceMap(BYTE *buff, int length, unsigned low, unsigned high, XID *errval) *errval = buff[i]; return TRUE; } - for (j = i + 1; j < length; j++) - if (buff[i] == buff[j]) - { - *errval = buff[i]; - return TRUE; - } } return FALSE; } @@ -1281,10 +1650,11 @@ DoSetModifierMapping(ClientPtr client, KeyCode *inputMap, int numKeyPerModifier, xSetModifierMappingReply *rep) { DeviceIntPtr pDev = NULL; + DeviceIntPtr cp = PickKeyboard(client); /* ClientPointer keyboard */ int rc, i = 0, inputMapLen = numKeyPerModifier * 8; for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { - if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key) { + if (pDev == cp || (!pDev->isMaster && (pDev->u.master == cp) && pDev->key)) { for (i = 0; i < inputMapLen; i++) { /* Check that all the new modifiers fall within the advertised * keycode range, and are okay with the DDX. */ @@ -1350,7 +1720,7 @@ DoSetModifierMapping(ClientPtr client, KeyCode *inputMap, return Success; } -int +int ProcSetModifierMapping(ClientPtr client) { xSetModifierMappingReply rep; @@ -1372,7 +1742,6 @@ ProcSetModifierMapping(ClientPtr client) if (rc != Success) return rc; - SendMappingNotify(MappingModifier, 0, 0, client); for (dev = inputInfo.devices; dev; dev = dev->next) if (dev->key && dev->coreEvents) SendDeviceMappingNotify(client, MappingModifier, 0, 0, dev); @@ -1384,12 +1753,12 @@ int ProcGetModifierMapping(ClientPtr client) { xGetModifierMappingReply rep; - KeyClassPtr keyc = inputInfo.keyboard->key; + DeviceIntPtr dev = PickKeyboard(client); + KeyClassPtr keyc = dev->key; int rc; REQUEST_SIZE_MATCH(xReq); - rc = XaceHook(XACE_DEVICE_ACCESS, client, inputInfo.keyboard, - DixGetAttrAccess); + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess); if (rc != Success) return rc; @@ -1413,12 +1782,12 @@ ProcChangeKeyboardMapping(ClientPtr client) REQUEST(xChangeKeyboardMappingReq); unsigned len; KeySymsRec keysyms; - KeySymsPtr curKeySyms = &inputInfo.keyboard->key->curKeySyms; + KeySymsPtr curKeySyms = &PickKeyboard(client)->key->curKeySyms; DeviceIntPtr pDev = NULL; int rc; REQUEST_AT_LEAST_SIZE(xChangeKeyboardMappingReq); - len = client->req_len - (sizeof(xChangeKeyboardMappingReq) >> 2); + len = client->req_len - (sizeof(xChangeKeyboardMappingReq) >> 2); if (len != (stuff->keyCodes * stuff->keySymsPerKeyCode)) return BadLength; @@ -1451,8 +1820,6 @@ ProcChangeKeyboardMapping(ClientPtr client) if (!SetKeySymsMap(&pDev->key->curKeySyms, &keysyms)) return BadAlloc; - SendMappingNotify(MappingKeyboard, stuff->firstKeyCode, stuff->keyCodes, - client); for (pDev = inputInfo.devices; pDev; pDev = pDev->next) if (pDev->key && pDev->coreEvents) SendDeviceMappingNotify(client, MappingKeyboard, @@ -1466,36 +1833,23 @@ static int DoSetPointerMapping(ClientPtr client, DeviceIntPtr device, BYTE *map, int n) { int rc, i = 0; - DeviceIntPtr dev = NULL; if (!device || !device->button) return BadDevice; - for (dev = inputInfo.devices; dev; dev = dev->next) { - if ((dev->coreEvents || dev == inputInfo.pointer) && dev->button) { - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess); - if (rc != Success) - return rc; - } - } + rc = XaceHook(XACE_DEVICE_ACCESS, client, device, DixManageAccess); + if (rc != Success) + return rc; - for (dev = inputInfo.devices; dev; dev = dev->next) { - if ((dev->coreEvents || dev == inputInfo.pointer) && dev->button) { - for (i = 0; i < n; i++) { - if ((device->button->map[i + 1] != map[i]) && - BitIsOn(device->button->down, i + 1)) { - return MappingBusy; - } - } + for (i = 0; i < n; i++) { + if ((device->button->map[i + 1] != map[i]) && + BitIsOn(device->button->down, i + 1)) { + return MappingBusy; } } - for (dev = inputInfo.devices; dev; dev = dev->next) { - if ((dev->coreEvents || dev == inputInfo.pointer) && dev->button) { - for (i = 0; i < n; i++) - dev->button->map[i + 1] = map[i]; - } - } + for (i = 0; i < n; i++) + device->button->map[i + 1] = map[i]; return Success; } @@ -1505,6 +1859,8 @@ ProcSetPointerMapping(ClientPtr client) { BYTE *map; int ret; + int i, j; + DeviceIntPtr ptr = PickPointer(client); xSetPointerMappingReply rep; REQUEST(xSetPointerMappingReq); REQUEST_AT_LEAST_SIZE(xSetPointerMappingReq); @@ -1516,25 +1872,41 @@ ProcSetPointerMapping(ClientPtr client) 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. */ - if (stuff->nElts != inputInfo.pointer->button->numButtons) { + /* 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; } if (BadDeviceMap(&map[0], (int)stuff->nElts, 1, 255, &client->errorValue)) return BadValue; - ret = DoSetPointerMapping(client, inputInfo.pointer, map, stuff->nElts); + /* core protocol specs don't allow for duplicate mappings. */ + 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 = DoSetPointerMapping(client, ptr, map, stuff->nElts); if (ret != Success) { rep.success = ret; WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep); return Success; } - /* FIXME: Send mapping notifies for all the extended devices as well. */ - SendMappingNotify(MappingPointer, 0, 0, client); + SendMappingNotify(ptr, MappingPointer, 0, 0, client); WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep); return Success; } @@ -1543,13 +1915,13 @@ int ProcGetKeyboardMapping(ClientPtr client) { xGetKeyboardMappingReply rep; - KeySymsPtr curKeySyms = &inputInfo.keyboard->key->curKeySyms; + DeviceIntPtr kbd = PickKeyboard(client); + KeySymsPtr curKeySyms = &kbd->key->curKeySyms; int rc; REQUEST(xGetKeyboardMappingReq); REQUEST_SIZE_MATCH(xGetKeyboardMappingReq); - rc = XaceHook(XACE_DEVICE_ACCESS, client, inputInfo.keyboard, - DixGetAttrAccess); + rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetAttrAccess); if (rc != Success) return rc; @@ -1584,12 +1956,14 @@ int ProcGetPointerMapping(ClientPtr client) { xGetPointerMappingReply rep; - ButtonClassPtr butc = inputInfo.pointer->button; + /* 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, inputInfo.pointer, - DixGetAttrAccess); + rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, DixGetAttrAccess); if (rc != Success) return rc; @@ -1599,7 +1973,7 @@ ProcGetPointerMapping(ClientPtr client) rep.length = ((unsigned)rep.nElts + (4-1))/4; WriteReplyToClient(client, sizeof(xGetPointerMappingReply), &rep); (void)WriteToClient(client, (int)rep.nElts, (char *)&butc->map[1]); - return Success; + return Success; } void @@ -1639,7 +2013,7 @@ DoChangeKeyboardControl (ClientPtr client, DeviceIntPtr keybd, XID *vlist, index2 = (BITS32) lowbit (vmask); vmask &= ~index2; switch (index2) { - case KBKeyClickPercent: + case KBKeyClickPercent: t = (INT8)*vlist; vlist++; if (t == -1) { @@ -1728,8 +2102,8 @@ DoChangeKeyboardControl (ClientPtr client, DeviceIntPtr keybd, XID *vlist, case KBKey: key = (KeyCode)*vlist; vlist++; - if ((KeyCode)key < inputInfo.keyboard->key->curKeySyms.minKeyCode || - (KeyCode)key > inputInfo.keyboard->key->curKeySyms.maxKeyCode) { + if ((KeyCode)key < keybd->key->curKeySyms.minKeyCode || + (KeyCode)key > keybd->key->curKeySyms.maxKeyCode) { client->errorValue = key; return BadValue; } @@ -1789,7 +2163,7 @@ DoChangeKeyboardControl (ClientPtr client, DeviceIntPtr keybd, XID *vlist, return Success; #undef DO_ALL -} +} int ProcChangeKeyboardControl (ClientPtr client) @@ -1833,12 +2207,12 @@ int ProcGetKeyboardControl (ClientPtr client) { int rc, i; - KeybdCtrl *ctrl = &inputInfo.keyboard->kbdfeed->ctrl; + DeviceIntPtr kbd = PickKeyboard(client); + KeybdCtrl *ctrl = &kbd->kbdfeed->ctrl; xGetKeyboardControlReply rep; REQUEST_SIZE_MATCH(xReq); - rc = XaceHook(XACE_DEVICE_ACCESS, client, inputInfo.keyboard, - DixGetAttrAccess); + rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetAttrAccess); if (rc != Success) return rc; @@ -1855,21 +2229,26 @@ ProcGetKeyboardControl (ClientPtr client) rep.map[i] = ctrl->autoRepeats[i]; WriteReplyToClient(client, sizeof(xGetKeyboardControlReply), &rep); return Success; -} +} int ProcBell(ClientPtr client) { - DeviceIntPtr keybd = inputInfo.keyboard; + DeviceIntPtr keybd = PickKeyboard(client); int base = keybd->kbdfeed->ctrl.bell; int newpercent; int rc; REQUEST(xBellReq); REQUEST_SIZE_MATCH(xBellReq); + /* Seems like no keyboard actually has the BellProc set. Returning + * BadDevice (previous code) will make apps crash badly. The man pages + * doesn't say anything about a BadDevice being returned either. + * So just quietly do nothing and pretend everything has worked. + */ if (!keybd->kbdfeed->BellProc) - return BadDevice; - + return Success; + if (stuff->percent < -100 || stuff->percent > 100) { client->errorValue = stuff->percent; return BadValue; @@ -1879,7 +2258,7 @@ ProcBell(ClientPtr client) if (stuff->percent < 0) newpercent = base + newpercent; else - newpercent = base - newpercent + stuff->percent; + newpercent = base - newpercent + stuff->percent; for (keybd = inputInfo.devices; keybd; keybd = keybd->next) { if ((keybd->coreEvents || keybd == inputInfo.keyboard) && @@ -1900,20 +2279,20 @@ ProcBell(ClientPtr client) } return Success; -} +} int ProcChangePointerControl(ClientPtr client) { - DeviceIntPtr mouse = inputInfo.pointer; + DeviceIntPtr mouse = PickPointer(client); PtrCtrl ctrl; /* might get BadValue part way through */ int rc; REQUEST(xChangePointerControlReq); REQUEST_SIZE_MATCH(xChangePointerControlReq); - + if (!mouse->ptrfeed->CtrlProc) return BadDevice; - + ctrl = mouse->ptrfeed->ctrl; if ((stuff->doAccel != xTrue) && (stuff->doAccel != xFalse)) { client->errorValue = stuff->doAccel; @@ -1969,7 +2348,7 @@ ProcChangePointerControl(ClientPtr client) } for (mouse = inputInfo.devices; mouse; mouse = mouse->next) { - if ((mouse->coreEvents || mouse == inputInfo.pointer) && + if ((mouse->coreEvents || mouse == PickPointer(client)) && mouse->ptrfeed && mouse->ptrfeed->CtrlProc) { mouse->ptrfeed->ctrl = ctrl; (*mouse->ptrfeed->CtrlProc)(mouse, &mouse->ptrfeed->ctrl); @@ -1977,18 +2356,18 @@ ProcChangePointerControl(ClientPtr client) } return Success; -} +} int ProcGetPointerControl(ClientPtr client) { - PtrCtrl *ctrl = &inputInfo.pointer->ptrfeed->ctrl; + DeviceIntPtr ptr = PickPointer(client); + PtrCtrl *ctrl = &ptr->ptrfeed->ctrl; xGetPointerControlReply rep; int rc; REQUEST_SIZE_MATCH(xReq); - rc = XaceHook(XACE_DEVICE_ACCESS, client, inputInfo.pointer, - DixGetAttrAccess); + rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, DixGetAttrAccess); if (rc != Success) return rc; @@ -2005,7 +2384,7 @@ ProcGetPointerControl(ClientPtr client) void MaybeStopHint(DeviceIntPtr dev, ClientPtr client) { - GrabPtr grab = dev->grab; + GrabPtr grab = dev->deviceGrab.grab; if ((grab && SameClient(grab, client) && ((grab->eventMask & PointerMotionHintMask) || @@ -2026,7 +2405,7 @@ ProcGetMotionEvents(ClientPtr client) xGetMotionEventsReply rep; int i, count, xmin, xmax, ymin, ymax, rc; unsigned long nEvents; - DeviceIntPtr mouse = inputInfo.pointer; + DeviceIntPtr mouse = PickPointer(client); TimeStamp start, stop; REQUEST(xGetMotionEventsReq); REQUEST_SIZE_MATCH(xGetMotionEventsReq); @@ -2051,14 +2430,9 @@ ProcGetMotionEvents(ClientPtr client) { if (CompareTimeStamps(stop, currentTime) == LATER) stop = currentTime; - coords = (xTimecoord *)xalloc(mouse->valuator->numMotionEvents - * sizeof(xTimecoord)); - if (!coords) - return BadAlloc; - count = (*mouse->valuator->GetMotionProc) (mouse, coords, - start.milliseconds, - stop.milliseconds, - pWin->drawable.pScreen); + 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); @@ -2094,15 +2468,15 @@ ProcQueryKeymap(ClientPtr client) { xQueryKeymapReply rep; int rc, i; - CARD8 *down = inputInfo.keyboard->key->down; + 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, inputInfo.keyboard, - DixReadAccess); + rc = XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixReadAccess); if (rc != Success) return rc; @@ -2110,5 +2484,174 @@ ProcQueryKeymap(ClientPtr client) rep.map[i] = down[i]; WriteReplyToClient(client, sizeof(xQueryKeymapReply), &rep); + + return Success; +} + +/** + * 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 || dev->isMaster) + return BadDevice; + + if (master && !master->isMaster) /* can't attach to slaves */ + return BadDevice; + + /* set from floating to floating? */ + if (!dev->u.master && !master) + return Success; + + /* free the existing sprite. */ + if (!dev->u.master && dev->spriteInfo->paired == dev) + { + screen = miPointerGetScreen(dev); + screen->DeviceCursorCleanup(dev, screen); + xfree(dev->spriteInfo->sprite); + } + + oldmaster = dev->u.master; + dev->u.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 = dev->spriteInfo->sprite->spriteTrace[0]; + /* 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; + } + + /* If we were connected to master device before, this MD may need to + * change back to it's original classes. + */ + if (oldmaster) + { + DeviceIntPtr it; + for (it = inputInfo.devices; it; it = it->next) + if (!it->isMaster && it->u.master == oldmaster) + break; + } + + 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. + */ +_X_EXPORT DeviceIntPtr +GetPairedDevice(DeviceIntPtr dev) +{ + if (!dev->isMaster && dev->u.master) + dev = dev->u.master; + + return dev->spriteInfo->paired; +} + + +/** + * Create a new master device (== one pointer, one keyboard device). + * Only allocates the devices, you will need to call ActivateDevice() and + * EnableDevice() manually. + */ +int +AllocMasterDevice(ClientPtr client, char* name, DeviceIntPtr* ptr, DeviceIntPtr* keybd) +{ + DeviceIntPtr pointer; + DeviceIntPtr keyboard; + ClassesPtr classes; + *ptr = *keybd = NULL; + + pointer = AddInputDevice(client, CorePointerProc, TRUE); + if (!pointer) + return BadAlloc; + + pointer->name = xcalloc(strlen(name) + strlen(" pointer") + 1, sizeof(char)); + strcpy(pointer->name, name); + strcat(pointer->name, " pointer"); + +#ifdef XKB + pointer->public.processInputProc = ProcessOtherEvent; + pointer->public.realInputProc = ProcessOtherEvent; + if (!noXkbExtension) + XkbSetExtension(pointer, ProcessPointerEvent); +#else + pointer->public.processInputProc = ProcessPointerEvent; + pointer->public.realInputProc = ProcessPointerEvent; +#endif + pointer->deviceGrab.ActivateGrab = ActivatePointerGrab; + pointer->deviceGrab.DeactivateGrab = DeactivatePointerGrab; + pointer->coreEvents = TRUE; + pointer->spriteInfo->spriteOwner = TRUE; + + pointer->u.lastSlave = NULL; + pointer->isMaster = TRUE; + + keyboard = AddInputDevice(client, CoreKeyboardProc, TRUE); + if (!keyboard) + { + RemoveDevice(pointer); + return BadAlloc; + } + + keyboard->name = xcalloc(strlen(name) + strlen(" keyboard") + 1, sizeof(char)); + strcpy(keyboard->name, name); + strcat(keyboard->name, " keyboard"); + +#ifdef XKB + keyboard->public.processInputProc = ProcessOtherEvent; + keyboard->public.realInputProc = ProcessOtherEvent; + if (!noXkbExtension) + XkbSetExtension(keyboard, ProcessKeyboardEvent); +#else + keyboard->public.processInputProc = ProcessKeyboardEvent; + keyboard->public.realInputProc = ProcessKeyboardEvent; +#endif + keyboard->deviceGrab.ActivateGrab = ActivateKeyboardGrab; + keyboard->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab; + keyboard->coreEvents = TRUE; + keyboard->spriteInfo->spriteOwner = FALSE; + + keyboard->u.lastSlave = NULL; + keyboard->isMaster = TRUE; + + + /* The ClassesRec stores the device classes currently not used. */ + classes = xcalloc(1, sizeof(ClassesRec)); + dixSetPrivate(&pointer->devPrivates, UnusedClassesPrivateKey, classes); + classes = xcalloc(1, sizeof(ClassesRec)); + dixSetPrivate(&keyboard->devPrivates, UnusedClassesPrivateKey, classes); + + *ptr = pointer; + *keybd = keyboard; + return Success; } |