forked from AuroraMiddleware/gtk
xi2: Improve device hierarchy handling
The xi2 device manager now handles slaves being detached and/or attached to a master. gdk_device_list_slaves() has been added so it is possible to know how slaves relate with masters. The other backends (X11 and not) don't neeed to to anything special here since their hierarchy is fully flat.
This commit is contained in:
parent
9f41101ccc
commit
be7de347bf
102
gdk/gdkdevice.c
102
gdk/gdkdevice.c
@ -59,7 +59,13 @@ struct _GdkDevicePrivate
|
||||
GdkDeviceKey *keys;
|
||||
GdkDeviceManager *device_manager;
|
||||
GdkDisplay *display;
|
||||
|
||||
/* Paired master for master,
|
||||
* associated master for slaves
|
||||
*/
|
||||
GdkDevice *associated;
|
||||
|
||||
GList *slaves;
|
||||
GdkDeviceType type;
|
||||
GArray *axes;
|
||||
};
|
||||
@ -290,6 +296,9 @@ gdk_device_dispose (GObject *object)
|
||||
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);
|
||||
@ -820,6 +829,24 @@ gdk_device_get_associated_device (GdkDevice *device)
|
||||
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)
|
||||
@ -842,6 +869,81 @@ _gdk_device_set_associated_device (GdkDevice *device,
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -222,6 +222,7 @@ gboolean gdk_device_get_axis (GdkDevice *device,
|
||||
GdkDisplay * gdk_device_get_display (GdkDevice *device);
|
||||
|
||||
GdkDevice * gdk_device_get_associated_device (GdkDevice *device);
|
||||
GList * gdk_device_list_slave_devices (GdkDevice *device);
|
||||
|
||||
GdkDeviceType gdk_device_get_device_type (GdkDevice *device);
|
||||
|
||||
|
@ -183,12 +183,16 @@ gdk_device_manager_class_init (GdkDeviceManagerClass *klass)
|
||||
* @device_manager: the object on which the signal is emitted
|
||||
* @device: the #GdkDevice that changed.
|
||||
*
|
||||
* The ::device-changed signal is emitted either when some
|
||||
* #GdkDevice has changed the number of either axes or keys.
|
||||
* For example In X this will normally happen when the slave
|
||||
* device routing events through the master device changes,
|
||||
* in that case the master device will change to reflect the
|
||||
* new slave device axes and keys.
|
||||
* The ::device-changed signal is emitted whenever a device
|
||||
* has changed in the hierarchy, either slave devices being
|
||||
* disconnected from their master device or connected to
|
||||
* another one, or master devices being added or removed
|
||||
* a slave device.
|
||||
*
|
||||
* If a slave device is detached from all master devices
|
||||
* (gdk_device_get_associated_device() returns %NULL), its
|
||||
* #GdkDeviceType will change to %GDK_DEVICE_TYPE_FLOATING,
|
||||
* if it's attached, it will change to %GDK_DEVICE_TYPE_SLAVE.
|
||||
*/
|
||||
signals [DEVICE_CHANGED] =
|
||||
g_signal_new (g_intern_static_string ("device-changed"),
|
||||
|
@ -125,6 +125,10 @@ GdkTimeCoord ** _gdk_device_allocate_history (GdkDevice *device,
|
||||
|
||||
void _gdk_input_check_extension_events (GdkDevice *device);
|
||||
|
||||
void _gdk_device_add_slave (GdkDevice *device,
|
||||
GdkDevice *slave);
|
||||
void _gdk_device_remove_slave (GdkDevice *device,
|
||||
GdkDevice *slave);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -263,15 +263,29 @@ add_device (GdkDeviceManagerXI2 *device_manager,
|
||||
|
||||
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;
|
||||
}
|
||||
@ -289,7 +303,6 @@ remove_device (GdkDeviceManagerXI2 *device_manager,
|
||||
{
|
||||
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);
|
||||
|
||||
@ -301,7 +314,7 @@ remove_device (GdkDeviceManagerXI2 *device_manager,
|
||||
}
|
||||
|
||||
static void
|
||||
relate_devices (gpointer key,
|
||||
relate_masters (gpointer key,
|
||||
gpointer value,
|
||||
gpointer user_data)
|
||||
{
|
||||
@ -316,13 +329,29 @@ relate_devices (gpointer key,
|
||||
_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;
|
||||
@ -332,7 +361,9 @@ gdk_device_manager_xi2_constructed (GObject *object)
|
||||
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);
|
||||
|
||||
@ -347,7 +378,14 @@ gdk_device_manager_xi2_constructed (GObject *object)
|
||||
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));
|
||||
}
|
||||
@ -356,8 +394,11 @@ gdk_device_manager_xi2_constructed (GObject *object)
|
||||
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);
|
||||
@ -388,10 +429,6 @@ gdk_device_manager_xi2_dispose (GObject *object)
|
||||
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);
|
||||
@ -416,10 +453,21 @@ gdk_device_manager_xi2_list_devices (GdkDeviceManager *device_manager,
|
||||
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 ();
|
||||
@ -457,32 +505,61 @@ static void
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,6 @@ struct _GdkDeviceManagerXI2
|
||||
|
||||
GList *master_devices;
|
||||
GList *slave_devices;
|
||||
GList *floating_devices;
|
||||
|
||||
GdkDevice *client_pointer;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user