GdkDeviceKey *keys;
GdkDeviceManager *device_manager;
GdkDisplay *display;
+
+ /* Paired master for master,
+ * associated master for slaves
+ */
GdkDevice *associated;
+
+ GList *slaves;
GdkDeviceType type;
GArray *axes;
};
device = GDK_DEVICE (object);
priv = device->priv;
+ if (priv->type == GDK_DEVICE_TYPE_SLAVE)
+ _gdk_device_remove_slave (priv->associated, device);
+
if (priv->associated)
{
_gdk_device_set_associated_device (priv->associated, NULL);
return priv->associated;
}
+static void
+_gdk_device_set_device_type (GdkDevice *device,
+ GdkDeviceType type)
+{
+ GdkDevicePrivate *priv;
+
+ priv = device->priv;
+
+ if (priv->type != type)
+ {
+ priv->type = type;
+
+ g_print ("Setting device type to %d\n", type);
+
+ g_object_notify (G_OBJECT (device), "type");
+ }
+}
+
void
_gdk_device_set_associated_device (GdkDevice *device,
GdkDevice *associated)
if (associated)
priv->associated = g_object_ref (associated);
+
+ if (priv->type != GDK_DEVICE_TYPE_MASTER)
+ {
+ if (priv->associated)
+ _gdk_device_set_device_type (device, GDK_DEVICE_TYPE_SLAVE);
+ else
+ _gdk_device_set_device_type (device, GDK_DEVICE_TYPE_FLOATING);
+ }
+}
+
+/**
+ * gdk_device_list_slave_devices:
+ * @device: a #GdkDevice
+ *
+ * If the device if of type %GDK_DEVICE_TYPE_MASTER, it will return
+ * the list of slave devices attached to it, otherwise it will return
+ * %NULL
+ *
+ * Returns: (transfer container): the list of slave devices, or %NULL. The
+ * list must be freed with g_list_free(), the contents of the list
+ * are owned by GTK+ and should not be freed.
+ **/
+GList *
+gdk_device_list_slave_devices (GdkDevice *device)
+{
+ GdkDevicePrivate *priv;
+
+ g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER, NULL);
+
+ priv = device->priv;
+
+ return g_list_copy (priv->slaves);
+}
+
+void
+_gdk_device_add_slave (GdkDevice *device,
+ GdkDevice *slave)
+{
+ GdkDevicePrivate *priv;
+
+ g_return_if_fail (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER);
+ g_return_if_fail (gdk_device_get_device_type (slave) != GDK_DEVICE_TYPE_MASTER);
+
+ priv = device->priv;
+
+ g_print ("Adding %s ---> %s\n",
+ gdk_device_get_name (slave),
+ gdk_device_get_name (device));
+
+ if (!g_list_find (priv->slaves, slave))
+ priv->slaves = g_list_prepend (priv->slaves, slave);
+}
+
+void
+_gdk_device_remove_slave (GdkDevice *device,
+ GdkDevice *slave)
+{
+ GdkDevicePrivate *priv;
+ GList *elem;
+
+ g_return_if_fail (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER);
+ g_return_if_fail (gdk_device_get_device_type (slave) != GDK_DEVICE_TYPE_MASTER);
+
+ priv = device->priv;
+ elem = g_list_find (priv->slaves, slave);
+
+ if (!elem)
+ return;
+
+ g_print ("Removing %s ---> %s\n",
+ gdk_device_get_name (slave),
+ gdk_device_get_name (device));
+
+ priv->slaves = g_list_delete_link (priv->slaves, elem);
}
/**
if (dev->use == XIMasterPointer || dev->use == XIMasterKeyboard)
device_manager->master_devices = g_list_append (device_manager->master_devices, device);
- else if (dev->use == XISlavePointer || dev->use == XISlaveKeyboard)
+ else if (dev->use == XISlavePointer || dev->use == XISlaveKeyboard || dev->use == XIFloatingSlave)
device_manager->slave_devices = g_list_append (device_manager->slave_devices, device);
- else if (dev->use == XIFloatingSlave)
- device_manager->floating_devices = g_list_append (device_manager->floating_devices, device);
else
g_warning ("Unhandled device: %s\n", gdk_device_get_name (device));
if (emit_signal)
- g_signal_emit_by_name (device_manager, "device-added", device);
+ {
+ if (dev->use == XISlavePointer || dev->use == XISlaveKeyboard)
+ {
+ GdkDevice *master;
+
+ /* The device manager is already constructed, then
+ * keep the hierarchy coherent for the added device.
+ */
+ master = g_hash_table_lookup (device_manager->id_table,
+ GINT_TO_POINTER (dev->attachment));
+
+ _gdk_device_set_associated_device (device, master);
+ _gdk_device_add_slave (master, device);
+ }
+
+ g_signal_emit_by_name (device_manager, "device-added", device);
+ }
return device;
}
{
device_manager->master_devices = g_list_remove (device_manager->master_devices, device);
device_manager->slave_devices = g_list_remove (device_manager->slave_devices, device);
- device_manager->floating_devices = g_list_remove (device_manager->floating_devices, device);
g_signal_emit_by_name (device_manager, "device-removed", device);
}
static void
-relate_devices (gpointer key,
+relate_masters (gpointer key,
gpointer value,
gpointer user_data)
{
_gdk_device_set_associated_device (relative, device);
}
+static void
+relate_slaves (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ GdkDeviceManagerXI2 *device_manager;
+ GdkDevice *slave, *master;
+
+ device_manager = user_data;
+ slave = g_hash_table_lookup (device_manager->id_table, key);
+ master = g_hash_table_lookup (device_manager->id_table, value);
+
+ _gdk_device_set_associated_device (slave, master);
+ _gdk_device_add_slave (master, slave);
+}
+
static void
gdk_device_manager_xi2_constructed (GObject *object)
{
GdkDeviceManagerXI2 *device_manager_xi2;
GdkDisplay *display;
GdkScreen *screen;
- GHashTable *relations;
+ GHashTable *masters, *slaves;
Display *xdisplay;
XIDeviceInfo *info, *dev;
int ndevices, i;
device_manager_xi2 = GDK_DEVICE_MANAGER_XI2 (object);
display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
xdisplay = GDK_DISPLAY_XDISPLAY (display);
- relations = g_hash_table_new (NULL, NULL);
+
+ masters = g_hash_table_new (NULL, NULL);
+ slaves = g_hash_table_new (NULL, NULL);
info = XIQueryDevice(xdisplay, XIAllDevices, &ndevices);
if (dev->use == XIMasterPointer ||
dev->use == XIMasterKeyboard)
{
- g_hash_table_insert (relations,
+ g_hash_table_insert (masters,
+ GINT_TO_POINTER (dev->deviceid),
+ GINT_TO_POINTER (dev->attachment));
+ }
+ else if (dev->use == XISlavePointer ||
+ dev->use == XISlaveKeyboard)
+ {
+ g_hash_table_insert (slaves,
GINT_TO_POINTER (dev->deviceid),
GINT_TO_POINTER (dev->attachment));
}
XIFreeDeviceInfo(info);
/* Stablish relationships between devices */
- g_hash_table_foreach (relations, relate_devices, object);
- g_hash_table_destroy (relations);
+ g_hash_table_foreach (masters, relate_masters, object);
+ g_hash_table_destroy (masters);
+
+ g_hash_table_foreach (slaves, relate_slaves, object);
+ g_hash_table_destroy (slaves);
/* Connect to hierarchy change events */
screen = gdk_display_get_default_screen (display);
g_list_free (device_manager_xi2->slave_devices);
device_manager_xi2->slave_devices = NULL;
- g_list_foreach (device_manager_xi2->floating_devices, (GFunc) g_object_unref, NULL);
- g_list_free (device_manager_xi2->floating_devices);
- device_manager_xi2->floating_devices = NULL;
-
if (device_manager_xi2->id_table)
{
g_hash_table_destroy (device_manager_xi2->id_table);
list = device_manager_xi2->master_devices;
break;
case GDK_DEVICE_TYPE_SLAVE:
- list = device_manager_xi2->slave_devices;
- break;
case GDK_DEVICE_TYPE_FLOATING:
- list = device_manager_xi2->floating_devices;
+ {
+ GList *devs = device_manager_xi2->slave_devices;
+
+ while (devs)
+ {
+ GdkDevice *dev;
+
+ dev = devs->data;
+ devs = devs->next;
+
+ if (type == gdk_device_get_device_type (dev))
+ list = g_list_prepend (list, dev);
+ }
+ }
break;
default:
g_assert_not_reached ();
handle_hierarchy_changed (GdkDeviceManagerXI2 *device_manager,
XIHierarchyEvent *ev)
{
+ GdkDisplay *display;
+ Display *xdisplay;
GdkDevice *device;
+ XIDeviceInfo *info;
+ int ndevices;
gint i;
- /* We only care about enabled devices */
- if (!(ev->flags & XIDeviceEnabled) &&
- !(ev->flags & XIDeviceDisabled))
- return;
+ display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
+ xdisplay = GDK_DISPLAY_XDISPLAY (display);
for (i = 0; i < ev->num_info; i++)
{
if (ev->info[i].flags & XIDeviceEnabled)
{
- GdkDisplay *display;
- Display *xdisplay;
- XIDeviceInfo *info;
- int ndevices;
-
- display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager));
- xdisplay = GDK_DISPLAY_XDISPLAY (display);
-
info = XIQueryDevice(xdisplay, ev->info[i].deviceid, &ndevices);
device = add_device (device_manager, &info[0], TRUE);
XIFreeDeviceInfo(info);
}
else if (ev->info[i].flags & XIDeviceDisabled)
remove_device (device_manager, ev->info[i].deviceid);
+ else if (ev->info[i].flags & XISlaveAttached ||
+ ev->info[i].flags & XISlaveDetached)
+ {
+ GdkDevice *master, *slave;
+
+ slave = g_hash_table_lookup (device_manager->id_table,
+ GINT_TO_POINTER (ev->info[i].deviceid));
+
+ /* Remove old master info */
+ master = gdk_device_get_associated_device (slave);
+
+ if (master)
+ {
+ _gdk_device_remove_slave (master, slave);
+ _gdk_device_set_associated_device (slave, NULL);
+
+ g_signal_emit_by_name (device_manager, "device-changed", master);
+ }
+
+ /* Add new master if it's an attachment event */
+ if (ev->info[i].flags & XISlaveAttached)
+ {
+ info = XIQueryDevice(xdisplay, ev->info[i].deviceid, &ndevices);
+
+ master = g_hash_table_lookup (device_manager->id_table,
+ GINT_TO_POINTER (info->attachment));
+
+ _gdk_device_set_associated_device (slave, master);
+ _gdk_device_add_slave (master, slave);
+
+ g_signal_emit_by_name (device_manager, "device-changed", master);
+ }
+
+ g_signal_emit_by_name (device_manager, "device-changed", slave);
+ }
}
}