diff --git a/Xi/exevents.c b/Xi/exevents.c index 4c57fd017..617aef7b4 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -73,6 +73,7 @@ SOFTWARE. #include "dixevents.h" /* DeliverFocusedEvent */ #include "dixgrabs.h" /* CreateGrab() */ #include "scrnintstr.h" +#include "listdev.h" /* for CopySwapXXXClass */ #ifdef XKB #include "xkbsrv.h" @@ -127,6 +128,62 @@ ProcessOtherEvent(xEventPtr xE, DeviceIntPtr device, int count) xEvent core; int coretype = 0; + /* This event is always the first we get, before the actual events with + * the data. However, the way how the DDX is set up, "device" will + * actually be the slave device that caused the event. + */ + if (GEIsType(xE, IReqCode, XI_DeviceClassesChangedNotify)) + { + deviceClassesChangedEvent* dcce = (deviceClassesChangedEvent*)xE; + DeviceIntPtr master = device->u.master; + char* classbuff; + + if (device->isMaster) + return; + + if (!master) /* if device was set floating between SIGIO and now */ + return; + + dcce->deviceid = master->id; + dcce->num_classes = 0; + + 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; + + /* event is already correct size, see comment in GetPointerEvents */ + classbuff = (char*)&xE[1]; + if (master->key) + { + /* we don't actually swap here, swapping is done later */ + CopySwapKeyClass(NullClient, master->key, &classbuff); + dcce->num_classes++; + } + if (master->button) + { + CopySwapButtonClass(NullClient, master->button, &classbuff); + dcce->num_classes++; + } + if (master->valuator) + { + CopySwapValuatorClass(NullClient, master->valuator, &classbuff); + dcce->num_classes++; + } + + SendEventToAllWindows(master, XI_DeviceClassesChangedMask, + xE, 1); + return; + } + coretype = XItoCoreType(xE->u.u.type); if (device->isMaster && device->coreEvents && coretype) sendCore = TRUE; diff --git a/Xi/extinit.c b/Xi/extinit.c index 0ecb421f0..017b6935a 100644 --- a/Xi/extinit.c +++ b/Xi/extinit.c @@ -703,6 +703,53 @@ SRawDeviceEvent(rawDeviceEvent* from, rawDeviceEvent *to) swapl(valptr, n); } +static void +SDeviceClassesChangedEvent(deviceClassesChangedEvent* from, + deviceClassesChangedEvent* to) +{ + char n; + int i, j; + xAnyClassPtr any; + + *to = *from; + memcpy(&to[1], &from[1], from->length * 4); + + swaps(&to->sequenceNumber, n); + swapl(&to->length, n); + swapl(&to->time, n); + + /* now swap the actual classes */ + any = (xAnyClassPtr)&to[1]; + for (i = 0; i < to->num_classes; i++) + { + switch(any->class) + { + case KeyClass: + swaps(&((xKeyInfoPtr)any)->num_keys, n); + break; + case ButtonClass: + swaps(&((xButtonInfoPtr)any)->num_buttons, n); + break; + case ValuatorClass: + { + xValuatorInfoPtr v = (xValuatorInfoPtr)any; + xAxisInfoPtr a = (xAxisInfoPtr)&v[1]; + + swapl(&v->motion_buffer_size, n); + for (j = 0; j < v->num_axes; j++) + { + swapl(&a->min_value, n); + swapl(&a->max_value, n); + swapl(&a->resolution, n); + a++; + } + } + break; + } + any = (xAnyClassPtr)((char*)any + any->length); + } +} + /************************************************************************** * * Allow the specified event to have its propagation suppressed. @@ -1153,6 +1200,10 @@ XIGEEventSwap(xGenericEvent* from, xGenericEvent* to) case XI_RawDeviceEvent: SRawDeviceEvent((rawDeviceEvent*)from, (rawDeviceEvent*)to); break; + case XI_DeviceClassesChangedNotify: + SDeviceClassesChangedEvent((deviceClassesChangedEvent*)from, + (deviceClassesChangedEvent*)to); + break; } } diff --git a/Xi/listdev.c b/Xi/listdev.c index 8753b292c..962998efe 100644 --- a/Xi/listdev.c +++ b/Xi/listdev.c @@ -68,7 +68,6 @@ SOFTWARE. #include "listdev.h" -#define VPC 20 /* Max # valuators per chunk */ /*********************************************************************** * @@ -143,7 +142,7 @@ CopyDeviceName(char **namebuf, char *name) * */ -static void +void CopySwapButtonClass(ClientPtr client, ButtonClassPtr b, char **buf) { char n; @@ -153,7 +152,7 @@ CopySwapButtonClass(ClientPtr client, ButtonClassPtr b, char **buf) b2->class = ButtonClass; b2->length = sizeof(xButtonInfo); b2->num_buttons = b->numButtons; - if (client->swapped) { + if (client && client->swapped) { swaps(&b2->num_buttons, n); /* macro - braces are required */ } *buf += sizeof(xButtonInfo); @@ -202,7 +201,7 @@ CopySwapDevice(ClientPtr client, DeviceIntPtr d, int num_classes, * */ -static void +void CopySwapKeyClass(ClientPtr client, KeyClassPtr k, char **buf) { char n; @@ -214,7 +213,7 @@ CopySwapKeyClass(ClientPtr client, KeyClassPtr k, char **buf) k2->min_keycode = k->curKeySyms.minKeyCode; k2->max_keycode = k->curKeySyms.maxKeyCode; k2->num_keys = k2->max_keycode - k2->min_keycode + 1; - if (client->swapped) { + if (client && client->swapped) { swaps(&k2->num_keys, n); } *buf += sizeof(xKeyInfo); @@ -232,7 +231,7 @@ CopySwapKeyClass(ClientPtr client, KeyClassPtr k, char **buf) * */ -static int +int CopySwapValuatorClass(ClientPtr client, ValuatorClassPtr v, char **buf) { int i, j, axes, t_axes; @@ -252,7 +251,7 @@ CopySwapValuatorClass(ClientPtr client, ValuatorClassPtr v, char **buf) v2->num_axes = t_axes; v2->mode = v->mode & DeviceMode; v2->motion_buffer_size = v->numMotionEvents; - if (client->swapped) { + if (client && client->swapped) { swapl(&v2->motion_buffer_size, n); } *buf += sizeof(xValuatorInfo); @@ -262,7 +261,7 @@ CopySwapValuatorClass(ClientPtr client, ValuatorClassPtr v, char **buf) a2->min_value = a->min_value; a2->max_value = a->max_value; a2->resolution = a->resolution; - if (client->swapped) { + if (client && client->swapped) { swapl(&a2->min_value, n); swapl(&a2->max_value, n); swapl(&a2->resolution, n); diff --git a/Xi/listdev.h b/Xi/listdev.h index db376decf..afdcd6992 100644 --- a/Xi/listdev.h +++ b/Xi/listdev.h @@ -30,6 +30,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef LISTDEV_H #define LISTDEV_H 1 +#define VPC 20 /* Max # valuators per chunk */ + int SProcXListInputDevices(ClientPtr /* client */ ); @@ -41,4 +43,16 @@ void SRepXListInputDevices(ClientPtr /* client */ , xListInputDevicesReply * /* rep */ ); +void +CopySwapKeyClass(ClientPtr /* client */, + KeyClassPtr /* k */, + char** /* buf */); +void +CopySwapButtonClass(ClientPtr /* client */, + ButtonClassPtr /* b */, + char** /* buf */); +int +CopySwapValuatorClass(ClientPtr /* client */, + ValuatorClassPtr /* v */, + char** /* buf */); #endif /* LISTDEV_H */ diff --git a/dix/devices.c b/dix/devices.c index c9831ea92..b42337820 100644 --- a/dix/devices.c +++ b/dix/devices.c @@ -84,8 +84,25 @@ SOFTWARE. * This file handles input device-related stuff. */ +typedef struct { + KeyClassPtr key; + ValuatorClassPtr valuator; + ButtonClassPtr button; + FocusClassPtr focus; + ProximityClassPtr proximity; + AbsoluteClassPtr absolute; + KbdFeedbackPtr kbdfeed; + PtrFeedbackPtr ptrfeed; + IntegerFeedbackPtr intfeed; + StringFeedbackPtr stringfeed; + BellFeedbackPtr bell; + LedFeedbackPtr leds; +} ClassesRec, *ClassesPtr; + + int CoreDevicePrivatesIndex = 0; static int CoreDevicePrivatesGeneration = -1; +int MasterDevClassesPrivIdx = -1; /* The client that is allowed to change pointer-keyboard pairings. */ static ClientPtr pairingClient = NULL; @@ -385,9 +402,16 @@ CoreKeyboardProc(DeviceIntPtr pDev, int what) #ifdef XKB XkbComponentNamesRec names; #endif + ClassesPtr classes; switch (what) { case DEVICE_INIT: + if (MasterDevClassesPrivIdx == -1) + MasterDevClassesPrivIdx = AllocateDevicePrivateIndex(); + + if (!AllocateDevicePrivate(pDev, MasterDevClassesPrivIdx) || + !(classes = xcalloc(1, sizeof(ClassesRec)))) + keySyms.minKeyCode = 8; keySyms.maxKeyCode = 255; keySyms.mapWidth = 4; @@ -425,6 +449,19 @@ CoreKeyboardProc(DeviceIntPtr pDev, int what) xfree(keySyms.map); xfree(modMap); + classes->key = pDev->key; + classes->valuator = pDev->valuator; + classes->button = pDev->button; + classes->focus = pDev->focus; + classes->proximity = pDev->proximity; + classes->absolute = pDev->absolute; + classes->kbdfeed = pDev->kbdfeed; + classes->ptrfeed = pDev->ptrfeed; + classes->intfeed = pDev->intfeed; + classes->stringfeed = pDev->stringfeed; + classes->bell = pDev->bell; + classes->leds = pDev->leds; + pDev->devPrivates[MasterDevClassesPrivIdx].ptr = classes; break; case DEVICE_CLOSE: @@ -439,15 +476,27 @@ 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 (MasterDevClassesPrivIdx == -1) + MasterDevClassesPrivIdx = AllocateDevicePrivateIndex(); + + if (!AllocateDevicePrivate(pDev, MasterDevClassesPrivIdx) || + !(classes = xcalloc(1, sizeof(ClassesRec)))) + return BadAlloc; + for (i = 1; i <= 32; i++) map[i] = i; InitPointerDeviceStruct((DevicePtr)pDev, map, 32, @@ -457,6 +506,21 @@ CorePointerProc(DeviceIntPtr pDev, int what) pDev->valuator->lastx = pDev->valuator->axisVal[0]; pDev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2; pDev->valuator->lasty = pDev->valuator->axisVal[1]; + + classes->key = pDev->key; + classes->valuator = pDev->valuator; + classes->button = pDev->button; + classes->focus = pDev->focus; + classes->proximity = pDev->proximity; + classes->absolute = pDev->absolute; + classes->kbdfeed = pDev->kbdfeed; + classes->ptrfeed = pDev->ptrfeed; + classes->intfeed = pDev->intfeed; + classes->stringfeed = pDev->stringfeed; + classes->bell = pDev->bell; + classes->leds = pDev->leds; + + pDev->devPrivates[MasterDevClassesPrivIdx].ptr = classes; break; case DEVICE_CLOSE: @@ -574,6 +638,7 @@ CloseDevice(DeviceIntPtr dev) BellFeedbackPtr b, bnext; LedFeedbackPtr l, lnext; ScreenPtr screen = screenInfo.screens[0]; + ClassesPtr classes; int j; if (!dev) @@ -588,41 +653,46 @@ CloseDevice(DeviceIntPtr dev) xfree(dev->name); - if (dev->key) { + if (dev->isMaster) + classes = (ClassesPtr)dev->devPrivates[MasterDevClassesPrivIdx].ptr; + else + classes = (ClassesPtr)&dev->key; + + if (classes->key) { #ifdef XKB - if (dev->key->xkbInfo) - XkbFreeInfo(dev->key->xkbInfo); + if (classes->key->xkbInfo) + XkbFreeInfo(classes->key->xkbInfo); #endif - xfree(dev->key->curKeySyms.map); - xfree(dev->key->modifierKeyMap); - xfree(dev->key); + xfree(classes->key->curKeySyms.map); + xfree(classes->key->modifierKeyMap); + xfree(classes->key); } - if (dev->valuator) { + if (classes->valuator) { /* Counterpart to 'biggest hack ever' in init. */ - if (dev->valuator->motion && - dev->valuator->GetMotionProc == GetMotionHistory) - xfree(dev->valuator->motion); - xfree(dev->valuator); + if (classes->valuator->motion && + classes->valuator->GetMotionProc == GetMotionHistory) + xfree(classes->valuator->motion); + xfree(classes->valuator); } - if (dev->button) { + if (classes->button) { #ifdef XKB - if (dev->button->xkb_acts) - xfree(dev->button->xkb_acts); + if (classes->button->xkb_acts) + xfree(classes->button->xkb_acts); #endif - xfree(dev->button); + xfree(classes->button); } - if (dev->focus) { - xfree(dev->focus->trace); - xfree(dev->focus); + if (classes->focus) { + xfree(classes->focus->trace); + xfree(classes->focus); } - if (dev->proximity) - xfree(dev->proximity); + if (classes->proximity) + xfree(classes->proximity); - for (k = dev->kbdfeed; k; k = knext) { + for (k = classes->kbdfeed; k; k = knext) { knext = k->next; #ifdef XKB if (k->xkb_sli) @@ -631,29 +701,29 @@ CloseDevice(DeviceIntPtr dev) xfree(k); } - for (p = dev->ptrfeed; p; p = pnext) { + for (p = classes->ptrfeed; p; p = pnext) { pnext = p->next; xfree(p); } - for (i = dev->intfeed; i; i = inext) { + for (i = classes->intfeed; i; i = inext) { inext = i->next; xfree(i); } - for (s = dev->stringfeed; s; s = snext) { + for (s = classes->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) { + for (b = classes->bell; b; b = bnext) { bnext = b->next; xfree(b); } - for (l = dev->leds; l; l = lnext) { + for (l = classes->leds; l; l = lnext) { lnext = l->next; #ifdef XKB if (l->xkb_sli) diff --git a/dix/getevents.c b/dix/getevents.c index a23eabea2..425b60234 100644 --- a/dix/getevents.c +++ b/dix/getevents.c @@ -67,6 +67,7 @@ extern Bool XkbCopyKeymap(XkbDescPtr src, XkbDescPtr dst, Bool sendNotifies); #include "exevents.h" #include "exglobals.h" #include "extnsionst.h" +#include "listdev.h" /* for sizing up DeviceClassesChangedEvent */ /* Maximum number of valuators, divided by six, rounded up, to get number * of events. */ @@ -110,6 +111,52 @@ key_autorepeats(DeviceIntPtr pDev, int key_code) (1 << (key_code & 7))); } +static void +CreateClassesChangedEvent(EventList* event, + DeviceIntPtr master, + DeviceIntPtr slave) +{ + deviceClassesChangedEvent *dcce; + int len = sizeof(xEvent); + CARD32 ms = GetTimeInMillis(); + + /* XXX: ok, this is a bit weird. We need to alloc enough size for the + * event so it can be filled in in POE lateron. Reason being that if + * we realloc the event in POE we can get SIGABRT when we try to free + * or realloc the original pointer. + * We can only do it here as we don't have the EventList in the event + * processing any more. + * + * Code is basically same as in Xi/listdev.c + */ + if (slave->key) + len += sizeof(xKeyInfo); + if (slave->button) + len += sizeof(xButtonInfo); + if (slave->valuator) + { + int chunks = ((int)slave->valuator->numAxes + 19) / VPC; + len += (chunks * sizeof(xValuatorInfo) + + slave->valuator->numAxes * sizeof(xAxisInfo)); + } + if (event->evlen < len) + { + event->event = realloc(event->event, len); + if (!event->event) + FatalError("[dix] Cannot allocate memory for " + "DeviceClassesChangedEvent.\n"); + event->evlen = len; + } + + dcce = (deviceClassesChangedEvent*)event->event; + dcce->type = GenericEvent; + dcce->extension = IReqCode; + dcce->evtype = XI_DeviceClassesChangedNotify; + dcce->time = ms; + dcce->new_slave = slave->id; + dcce->length = (len - sizeof(xEvent))/4; +} + /** * Allocate the motion history buffer. */ @@ -415,6 +462,7 @@ GetKeyboardValuatorEvents(EventList *events, DeviceIntPtr pDev, int type, KeySym *map = pDev->key->curKeySyms.map; KeySym sym = map[key_code * pDev->key->curKeySyms.mapWidth]; deviceKeyButtonPointer *kbp = NULL; + DeviceIntPtr master; if (!events) return 0; @@ -432,6 +480,18 @@ GetKeyboardValuatorEvents(EventList *events, DeviceIntPtr pDev, int type, if (key_code < 8 || key_code > 255) return 0; + master = pDev->u.master; + if (master && master->u.lastSlave != pDev) + { + CreateClassesChangedEvent(events, master, pDev); + + pDev->valuator->lastx = master->valuator->lastx; + pDev->valuator->lasty = master->valuator->lasty; + master->u.lastSlave = pDev; + numEvents++; + events++; + } + if (num_valuators) { if ((num_valuators / 6) + 1 > MAX_VALUATOR_EVENTS) num_valuators = MAX_VALUATOR_EVENTS; @@ -606,37 +666,14 @@ GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons, master = pDev->u.master; if (master && master->u.lastSlave != pDev) { -#if 0 - /* XXX: we should enqueue the state changed event here */ - devStateEvent *state; - num_events++; - state = events->event; + CreateClassesChangedEvent(events, master, pDev); - state->type = GenericEvent; - state->extension = IReqCode; - state->evtype = XI_DeviceStateChangedNotify; - state->deviceid = master->deviceid; - state->new_slave = pDev->id; - state->time = ms; - events++; - -#endif - - /* now we need to update our device to the master's device - welcome - * to hell. - * We need to match each device's capabilities to the previous - * capabilities as used by the master. Valuator[N] of master has to - * be written into valuator[N] of pDev. For all relative valuators. - * Otherwise we get jumpy valuators. - * - * However, this if iffy, if pDev->num_valuators != - * master->num_valuators. What do we do with the others? - * - * XXX: just do lastx/y for now. - */ pDev->valuator->lastx = master->valuator->lastx; pDev->valuator->lasty = master->valuator->lasty; master->u.lastSlave = pDev; + + num_events++; + events++; } /* Do we need to send a DeviceValuator event? */ @@ -652,8 +689,6 @@ GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons, if (first_valuator < 0 || final_valuator > pDev->valuator->numAxes) return 0; - - /* fill up the raw event, after checking that it is large enough to * accommodate all valuators. */ diff --git a/mi/mieq.c b/mi/mieq.c index 26eab6f44..7ea12fe8c 100644 --- a/mi/mieq.c +++ b/mi/mieq.c @@ -243,12 +243,13 @@ ChangeDeviceID(DeviceIntPtr dev, xEvent* event) else if (type == GenericEvent) { /* FIXME: need to put something into XGE to make this saner */ - xGenericEvent* generic = (xGenericEvent*)event; - if (generic->extension == IReqCode - && generic->evtype == XI_RawDeviceEvent) + if (GEIsType(event, IReqCode, XI_RawDeviceEvent)) { rawDeviceEvent* raw = (rawDeviceEvent*)event; raw->deviceid = dev->id; + } else if (GEIsType(event, IReqCode, XI_DeviceClassesChangedNotify)) + { + // do nothing or drink a beer. your choice. } else ErrorF("[mi] Unknown generic event, cannot change id.\n"); } else