diff --git a/Xi/exevents.c b/Xi/exevents.c index 8b69a3ad3..e54af094e 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -588,6 +588,8 @@ DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to) } else xfree(to->button->xkb_acts); + memcpy(to->button->labels, from->button->labels, + from->button->numButtons * sizeof(Atom)); to->button->sourceid = from->id; } else if (to->button && !from->button) { @@ -670,10 +672,7 @@ DeepCopyDeviceClasses(DeviceIntPtr from, DeviceIntPtr to, DeviceChangedEvent *dc /** - * Change MD to look like SD by copying all classes over. An event is sent to - * all interested clients. - * @param device The slave device - * @param dcce Pointer to the event struct. + * Send an XI2 DeviceChangedEvent to all interested clients. */ void XISendDeviceChangedEvent(DeviceIntPtr device, DeviceIntPtr master, DeviceChangedEvent *dce) @@ -700,7 +699,7 @@ XISendDeviceChangedEvent(DeviceIntPtr device, DeviceIntPtr master, DeviceChanged len += sizeof(CARD32) * nkeys; /* keycodes */ } - dcce = xalloc(len); + dcce = xcalloc(1, len); if (!dcce) { ErrorF("[Xi] BadAlloc in SendDeviceChangedEvent.\n"); @@ -713,7 +712,7 @@ XISendDeviceChangedEvent(DeviceIntPtr device, DeviceIntPtr master, DeviceChanged dcce->time = GetTimeInMillis(); dcce->deviceid = master->id; dcce->sourceid = device->id; - dcce->reason = XISlaveSwitch; + dcce->reason = (dce->flags & DEVCHANGE_DEVICE_CHANGE) ? XIDeviceChange : XISlaveSwitch; dcce->num_classes = 0; dcce->length = (len - sizeof(xEvent))/4; diff --git a/dix/devices.c b/dix/devices.c index 3d190657e..b237e03b1 100644 --- a/dix/devices.c +++ b/dix/devices.c @@ -109,6 +109,7 @@ DevPrivateKey XTstDevicePrivateKey = &XTstDevicePrivateKeyIndex; */ DeviceIntPtr vxtstpointer, vxtstkeyboard; +static void RecalculateMasterButtons(DeviceIntPtr slave); /** * DIX property handler. @@ -369,6 +370,8 @@ EnableDevice(DeviceIntPtr dev, BOOL sendevent) XISendDeviceHierarchyEvent(flags); } + RecalculateMasterButtons(dev); + return TRUE; } @@ -460,6 +463,9 @@ DisableDevice(DeviceIntPtr dev, BOOL sendevent) flags[dev->id] = XIDeviceDisabled; XISendDeviceHierarchyEvent(flags); } + + RecalculateMasterButtons(dev); + return TRUE; } @@ -2260,6 +2266,77 @@ ProcQueryKeymap(ClientPtr client) 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) || + dev->u.master != master || + !dev->button) + continue; + + maxbuttons = max(maxbuttons, dev->button->numButtons); + } + + if (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 = CurrentTime; + 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; + /* This should, eventually, be a per-axis mode */ + event.valuators[i].mode = master->valuator->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); + } +} + /** * Attach device 'dev' to device 'master'. * Client is set to the client that issued the request, or NULL if it comes @@ -2323,6 +2400,8 @@ AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master) dev->spriteInfo->paired = master; dev->spriteInfo->spriteOwner = FALSE; + RecalculateMasterButtons(master); + if (!oldmaster) { /* Attaching a floating SD makes it disappear to XI 1 clients */ diff --git a/include/events.h b/include/events.h index d44188b67..f6405c5c2 100644 --- a/include/events.h +++ b/include/events.h @@ -119,6 +119,8 @@ typedef struct * pointer event or a keyboard event */ #define DEVCHANGE_POINTER_EVENT 0x4 #define DEVCHANGE_KEYBOARD_EVENT 0x8 +/* device capabilities changed */ +#define DEVCHANGE_DEVICE_CHANGE 0x10 /** * Sent whenever a device's capabilities have changed.