Xi: When switching MD classes, make a deep copy instead of pointer flip.
Turns out it's really really hard synchronising device state across multiple duplicated events if they all share the same struct. So instead of doing so, when the SD changes deep-copy all it's classes into the MD. The MD then has the same capabilities, but the state can be set separately. This should fix xkb, key state, repeat etc. problems. Updating the device state allows us to remove the SwitchCoreKeyboard from the event gathering, it's all done during event processing now.
This commit is contained in:
parent
cc4586df60
commit
64711a0948
214
Xi/exevents.c
214
Xi/exevents.c
|
@ -76,7 +76,9 @@ SOFTWARE.
|
|||
#include "listdev.h" /* for CopySwapXXXClass */
|
||||
|
||||
#ifdef XKB
|
||||
#include <X11/extensions/XKBproto.h>
|
||||
#include "xkbsrv.h"
|
||||
extern Bool XkbCopyKeymap(XkbDescPtr src, XkbDescPtr dst, Bool sendNotifies);
|
||||
#endif
|
||||
|
||||
#define WID(w) ((w) ? ((w)->drawable.id) : 0)
|
||||
|
@ -102,6 +104,154 @@ RegisterOtherDevice(DeviceIntPtr device)
|
|||
device->public.realInputProc = ProcessOtherEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the device->key into master->key and send a mapping notify to the
|
||||
* clients if appropriate.
|
||||
* master->key needs to be allocated by the caller.
|
||||
*
|
||||
* Device is the slave device. If it is attached to a master device, we may
|
||||
* need to send a mapping notify to the client because it causes the MD
|
||||
* to change state.
|
||||
*
|
||||
* Mapping notify needs to be sent in the following cases:
|
||||
* - different slave device on same master
|
||||
* - different master
|
||||
*
|
||||
* XXX: They way how the code is we also send a map notify if the slave device
|
||||
* stays the same, but the master changes. This isn't really necessary though.
|
||||
*
|
||||
* XXX: this gives you funny behaviour with the ClientPointer. When a
|
||||
* MappingNotify is sent to the client, the client usually responds with a
|
||||
* GetKeyboardMapping. This will retrieve the ClientPointer's keyboard
|
||||
* mapping, regardless of which keyboard sent the last mapping notify request.
|
||||
* So depending on the CP setting, your keyboard may change layout in each
|
||||
* app...
|
||||
*
|
||||
* This code is basically the old SwitchCoreKeyboard.
|
||||
*/
|
||||
|
||||
static void
|
||||
CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master)
|
||||
{
|
||||
static DeviceIntPtr lastMapNotifyDevice = NULL;
|
||||
KeyClassPtr mk, dk; /* master, device */
|
||||
BOOL sendNotify = FALSE;
|
||||
int i;
|
||||
|
||||
if (device == master)
|
||||
return;
|
||||
|
||||
dk = device->key;
|
||||
mk = master->key;
|
||||
|
||||
if (master->devPrivates[CoreDevicePrivatesIndex].ptr != device) {
|
||||
memcpy(mk->modifierMap, dk->modifierMap, MAP_LENGTH);
|
||||
|
||||
mk->modifierKeyMap = xcalloc(8, dk->maxKeysPerModifier);
|
||||
if (!mk->modifierKeyMap)
|
||||
FatalError("[Xi] no memory for class shift.\n");
|
||||
memcpy(mk->modifierKeyMap, dk->modifierKeyMap,
|
||||
(8 * dk->maxKeysPerModifier));
|
||||
|
||||
mk->maxKeysPerModifier = dk->maxKeysPerModifier;
|
||||
mk->curKeySyms.minKeyCode = dk->curKeySyms.minKeyCode;
|
||||
mk->curKeySyms.maxKeyCode = dk->curKeySyms.maxKeyCode;
|
||||
SetKeySymsMap(&mk->curKeySyms, &dk->curKeySyms);
|
||||
|
||||
/*
|
||||
* Copy state from the extended keyboard to core. If you omit this,
|
||||
* holding Ctrl on keyboard one, and pressing Q on keyboard two, will
|
||||
* cause your app to quit. This feels wrong to me, hence the below
|
||||
* code.
|
||||
*
|
||||
* XXX: If you synthesise core modifier events, the state will get
|
||||
* clobbered here. You'll have to work out something sensible
|
||||
* to fix that. Good luck.
|
||||
*/
|
||||
|
||||
#define KEYBOARD_MASK (ShiftMask | LockMask | ControlMask | Mod1Mask | \
|
||||
Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)
|
||||
mk->state &= ~(KEYBOARD_MASK);
|
||||
mk->state |= (dk->state & KEYBOARD_MASK);
|
||||
#undef KEYBOARD_MASK
|
||||
for (i = 0; i < 8; i++)
|
||||
mk->modifierKeyCount[i] = dk->modifierKeyCount[i];
|
||||
|
||||
#ifdef XKB
|
||||
if (!mk->xkbInfo || !mk->xkbInfo->desc)
|
||||
XkbInitDevice(master);
|
||||
if (!noXkbExtension && dk->xkbInfo && dk->xkbInfo->desc) {
|
||||
if (!XkbCopyKeymap(dk->xkbInfo->desc, mk->xkbInfo->desc, True))
|
||||
FatalError("Couldn't pivot keymap from device to core!\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
master->devPrivates[CoreDevicePrivatesIndex].ptr = device;
|
||||
sendNotify = TRUE;
|
||||
} else if (lastMapNotifyDevice != master)
|
||||
sendNotify = TRUE;
|
||||
|
||||
if (sendNotify)
|
||||
{
|
||||
SendMappingNotify(master, MappingKeyboard,
|
||||
mk->curKeySyms.minKeyCode,
|
||||
(mk->curKeySyms.maxKeyCode -
|
||||
mk->curKeySyms.minKeyCode),
|
||||
serverClient);
|
||||
lastMapNotifyDevice = master;
|
||||
}
|
||||
}
|
||||
|
||||
_X_EXPORT void
|
||||
DeepCopyDeviceClasses(DeviceIntPtr from, DeviceIntPtr to)
|
||||
{
|
||||
#define ALLOC_COPY_CLASS_IF(field, type) \
|
||||
if (from->field)\
|
||||
{ \
|
||||
to->field = xcalloc(1, sizeof(type)); \
|
||||
if (!to->field) \
|
||||
FatalError("[Xi] no memory for class shift.\n"); \
|
||||
memcpy(to->field, from->field, sizeof(type)); \
|
||||
}
|
||||
|
||||
ALLOC_COPY_CLASS_IF(key, KeyClassRec);
|
||||
if (to->key)
|
||||
{
|
||||
#ifdef XKB
|
||||
to->key->xkbInfo = NULL;
|
||||
#endif
|
||||
CopyKeyClass(from, to);
|
||||
}
|
||||
|
||||
if (from->valuator)
|
||||
{
|
||||
ValuatorClassPtr v;
|
||||
to->valuator = xalloc(sizeof(ValuatorClassRec) +
|
||||
from->valuator->numAxes * sizeof(AxisInfo) +
|
||||
from->valuator->numAxes * sizeof(unsigned int));
|
||||
v = to->valuator;
|
||||
if (!v)
|
||||
FatalError("[Xi] no memory for class shift.\n");
|
||||
memcpy(v, from->valuator, sizeof(ValuatorClassRec));
|
||||
v->axes = (AxisInfoPtr)&v[1];
|
||||
memcpy(v->axes, from->valuator->axes, v->numAxes * sizeof(AxisInfo));
|
||||
}
|
||||
|
||||
ALLOC_COPY_CLASS_IF(button, ButtonClassRec);
|
||||
/* XXX: XkbAction needs to be copied */
|
||||
ALLOC_COPY_CLASS_IF(focus, FocusClassRec);
|
||||
ALLOC_COPY_CLASS_IF(proximity, ProximityClassRec);
|
||||
ALLOC_COPY_CLASS_IF(absolute, AbsoluteClassRec);
|
||||
ALLOC_COPY_CLASS_IF(kbdfeed, KbdFeedbackClassRec);
|
||||
/* XXX: XkbSrvLedInfo needs to be copied*/
|
||||
ALLOC_COPY_CLASS_IF(ptrfeed, PtrFeedbackClassRec);
|
||||
ALLOC_COPY_CLASS_IF(intfeed, IntegerFeedbackClassRec);
|
||||
ALLOC_COPY_CLASS_IF(stringfeed, StringFeedbackClassRec);
|
||||
ALLOC_COPY_CLASS_IF(bell, BellFeedbackClassRec);
|
||||
ALLOC_COPY_CLASS_IF(leds, LedFeedbackClassRec);
|
||||
/* XXX: XkbSrvLedInfo needs to be copied. */
|
||||
}
|
||||
|
||||
static void
|
||||
ChangeMasterDeviceClasses(DeviceIntPtr device,
|
||||
deviceClassesChangedEvent *dcce)
|
||||
|
@ -119,21 +269,31 @@ ChangeMasterDeviceClasses(DeviceIntPtr device,
|
|||
dcce->num_classes = 0;
|
||||
|
||||
master->public.devicePrivate = device->public.devicePrivate;
|
||||
master->key = device->key;
|
||||
master->valuator = device->valuator;
|
||||
master->button = device->button;
|
||||
master->focus = device->focus;
|
||||
master->proximity = device->proximity;
|
||||
master->absolute = device->absolute;
|
||||
master->kbdfeed = device->kbdfeed;
|
||||
master->ptrfeed = device->ptrfeed;
|
||||
master->intfeed = device->intfeed;
|
||||
master->stringfeed = device->stringfeed;
|
||||
master->bell = device->bell;
|
||||
master->leds = device->leds;
|
||||
|
||||
if (master->key)
|
||||
xfree(master->key->modifierKeyMap);
|
||||
#ifdef XKB
|
||||
if (master->key && master->key->xkbInfo)
|
||||
XkbFreeInfo(master->key->xkbInfo);
|
||||
#endif
|
||||
xfree(master->key); master->key = NULL;
|
||||
xfree(master->valuator); master->valuator = NULL;
|
||||
xfree(master->button); master->button = NULL;
|
||||
xfree(master->focus); master->focus = NULL;
|
||||
xfree(master->proximity); master->proximity = NULL;
|
||||
xfree(master->absolute); master->absolute = NULL;
|
||||
xfree(master->kbdfeed); master->kbdfeed = NULL;
|
||||
xfree(master->ptrfeed); master->ptrfeed = NULL;
|
||||
xfree(master->stringfeed); master->stringfeed = NULL;
|
||||
xfree(master->bell); master->bell = NULL;
|
||||
xfree(master->leds); master->leds = NULL;
|
||||
xfree(master->intfeed); master->intfeed = NULL;
|
||||
|
||||
DeepCopyDeviceClasses(device, master);
|
||||
|
||||
/* event is already correct size, see comment in GetPointerEvents */
|
||||
classbuff = (char*)&dcce[1];
|
||||
|
||||
/* we don't actually swap if there's a NullClient, swapping is done
|
||||
* later when event is delivered. */
|
||||
CopySwapClasses(NullClient, master, &dcce->num_classes, &classbuff);
|
||||
|
@ -159,9 +319,9 @@ UpdateDeviceState(DeviceIntPtr device, xEvent* xE, int count)
|
|||
int key = 0,
|
||||
bit = 0;
|
||||
|
||||
KeyClassPtr k = device->key;
|
||||
ButtonClassPtr b = device->button;
|
||||
ValuatorClassPtr v = device->valuator;
|
||||
KeyClassPtr k = NULL;
|
||||
ButtonClassPtr b = NULL;
|
||||
ValuatorClassPtr v = NULL;
|
||||
deviceValuator *xV = (deviceValuator *) xE;
|
||||
BYTE *kptr = NULL;
|
||||
CARD16 modifiers = 0,
|
||||
|
@ -181,6 +341,11 @@ UpdateDeviceState(DeviceIntPtr device, xEvent* xE, int count)
|
|||
if (xE->u.u.type == GenericEvent)
|
||||
return DEFAULT;
|
||||
|
||||
k = device->key;
|
||||
v = device->valuator;
|
||||
b = device->button;
|
||||
|
||||
|
||||
if (xE->u.u.type != DeviceValuator)
|
||||
{
|
||||
key = xE->u.u.detail;
|
||||
|
@ -272,10 +437,9 @@ UpdateDeviceState(DeviceIntPtr device, xEvent* xE, int count)
|
|||
*kptr |= bit;
|
||||
if (device->valuator)
|
||||
device->valuator->motionHintWindow = NullWindow;
|
||||
if (!device->isMaster)
|
||||
b->buttonsDown++;
|
||||
b->buttonsDown++;
|
||||
b->motionMask = DeviceButtonMotionMask;
|
||||
if (!device->isMaster && !b->map[key]) /* bit already unset for MDs */
|
||||
if (!b->map[key])
|
||||
return DONT_PROCESS;
|
||||
if (b->map[key] <= 5)
|
||||
b->state |= (Button1Mask >> 1) << b->map[key];
|
||||
|
@ -290,9 +454,7 @@ UpdateDeviceState(DeviceIntPtr device, xEvent* xE, int count)
|
|||
*kptr &= ~bit;
|
||||
if (device->valuator)
|
||||
device->valuator->motionHintWindow = NullWindow;
|
||||
if (!device->isMaster)
|
||||
b->buttonsDown--;
|
||||
if (b->buttonsDown >= 1 && !b->buttonsDown)
|
||||
if (b->buttonsDown >= 1 && !--b->buttonsDown)
|
||||
b->motionMask = 0;
|
||||
if (!b->map[key])
|
||||
return DONT_PROCESS;
|
||||
|
@ -323,9 +485,9 @@ ProcessOtherEvent(xEventPtr xE, DeviceIntPtr device, int count)
|
|||
GrabPtr grab = device->deviceGrab.grab;
|
||||
Bool deactivateDeviceGrab = FALSE;
|
||||
int key = 0, rootX, rootY;
|
||||
ButtonClassPtr b = device->button;
|
||||
KeyClassPtr k = device->key;
|
||||
ValuatorClassPtr v = device->valuator;
|
||||
ButtonClassPtr b;
|
||||
KeyClassPtr k;
|
||||
ValuatorClassPtr v;
|
||||
deviceValuator *xV = (deviceValuator *) xE;
|
||||
BOOL sendCore = FALSE;
|
||||
xEvent core;
|
||||
|
@ -336,6 +498,10 @@ ProcessOtherEvent(xEventPtr xE, DeviceIntPtr device, int count)
|
|||
if (ret == DONT_PROCESS)
|
||||
return;
|
||||
|
||||
v = device->valuator;
|
||||
b = device->button;
|
||||
k = device->key;
|
||||
|
||||
coretype = XItoCoreType(xE->u.u.type);
|
||||
if (device->isMaster && device->coreEvents && coretype)
|
||||
sendCore = TRUE;
|
||||
|
|
|
@ -865,63 +865,6 @@ GetProximityEvents(EventList *events, DeviceIntPtr pDev, int type,
|
|||
return num_events;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pDev is the slave device that is about to send an event. If it is attached
|
||||
* to a master device, then we need to send a mapping notify to the client.
|
||||
* To do so, we need to remember the last master device that sent a mapping
|
||||
* event.
|
||||
*
|
||||
* Mapping notify needs to be sent in the following cases:
|
||||
* - different slave device on same master
|
||||
* - different master
|
||||
*
|
||||
* Call this just before processInputProc.
|
||||
*
|
||||
* XXX: They way how the code is we also send a map notify if the slave device
|
||||
* stays the same, but the master changes. This isn't really necessary though.
|
||||
*
|
||||
* XXX: this gives you funny behaviour with the ClientPointer. When a
|
||||
* MappingNotify is sent to the client, the client usually responds with a
|
||||
* GetKeyboardMapping. This will retrieve the ClientPointer's keyboard
|
||||
* mapping, regardless of which keyboard sent the last mapping notify request.
|
||||
* So depending on the CP setting, your keyboard may change layout in each
|
||||
* app...
|
||||
*/
|
||||
_X_EXPORT void
|
||||
SwitchCoreKeyboard(DeviceIntPtr pDev)
|
||||
{
|
||||
static DeviceIntPtr lastMapNotifyDevice = NULL;
|
||||
DeviceIntPtr master;
|
||||
KeyClassPtr ckeyc;
|
||||
int i = 0;
|
||||
BOOL sendNotify = FALSE;
|
||||
|
||||
if (pDev->isMaster || !pDev->u.master)
|
||||
return;
|
||||
|
||||
master = pDev->u.master;
|
||||
ckeyc = master->key;
|
||||
|
||||
if (master->devPrivates[CoreDevicePrivatesIndex].ptr != pDev) {
|
||||
master->devPrivates[CoreDevicePrivatesIndex].ptr = pDev;
|
||||
sendNotify = TRUE;
|
||||
}
|
||||
|
||||
if (lastMapNotifyDevice != master)
|
||||
sendNotify = TRUE;
|
||||
|
||||
if (sendNotify)
|
||||
{
|
||||
SendMappingNotify(pDev, MappingKeyboard, ckeyc->curKeySyms.minKeyCode,
|
||||
(ckeyc->curKeySyms.maxKeyCode -
|
||||
ckeyc->curKeySyms.minKeyCode),
|
||||
serverClient);
|
||||
lastMapNotifyDevice = master;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Note that pDev was the last function to send a core pointer event.
|
||||
* Currently a no-op.
|
||||
|
|
|
@ -458,7 +458,6 @@ extern int GetMotionHistory(
|
|||
unsigned long stop,
|
||||
ScreenPtr pScreen);
|
||||
|
||||
extern void SwitchCoreKeyboard(DeviceIntPtr pDev);
|
||||
extern void SwitchCorePointer(DeviceIntPtr pDev);
|
||||
|
||||
extern DeviceIntPtr LookupDeviceIntRec(
|
||||
|
@ -483,6 +482,8 @@ extern DeviceIntPtr NextFreePointerDevice(void);
|
|||
extern int AllocMasterDevice(char* name,
|
||||
DeviceIntPtr* ptr,
|
||||
DeviceIntPtr* keybd);
|
||||
extern void DeepCopyDeviceClasses(DeviceIntPtr from,
|
||||
DeviceIntPtr to);
|
||||
|
||||
/* Window/device based access control */
|
||||
extern Bool ACRegisterClient(ClientPtr client);
|
||||
|
|
Loading…
Reference in New Issue