eis-client: Handle unbinding device types
A EIS client might want to unbind a device capability; doing so should effectively remove the device, which we didn't. Instead we always created devices that a seat bind event had capabilities set for. Fix this by explicitly keeping track of what is our "keyboard", our "pointer", and whether we have a set of abs pointers, and don't create duplicates if we already have devices created. For absolute pointer devices, just keep track if we should have them, because we might have many, or none, if we happen to be headless at the time being. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4064>
This commit is contained in:
@ -52,6 +52,10 @@ struct _MetaEisClient
|
||||
struct eis_seat *eis_seat;
|
||||
|
||||
GHashTable *eis_devices; /* eis_device => MetaEisDevice*/
|
||||
MetaEisDevice *pointer_device;
|
||||
MetaEisDevice *keyboard_device;
|
||||
gulong keymap_changed_handler_id;
|
||||
gboolean have_abs_pointer_devices;
|
||||
|
||||
gulong viewports_changed_handler_id;
|
||||
};
|
||||
@ -161,6 +165,19 @@ drop_device (gpointer htkey,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
drop_abs_devices (gpointer key,
|
||||
gpointer value,
|
||||
gpointer data)
|
||||
{
|
||||
struct eis_device *eis_device = key;
|
||||
|
||||
if (!eis_device_has_capability (eis_device, EIS_DEVICE_CAP_POINTER_ABSOLUTE))
|
||||
return FALSE;
|
||||
|
||||
return drop_device (key, value, data);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_eis_device_free (MetaEisDevice *device)
|
||||
{
|
||||
@ -308,6 +325,10 @@ create_device (MetaEisClient *client,
|
||||
struct eis_device *eis_device;
|
||||
gchar *name;
|
||||
|
||||
meta_topic (META_DEBUG_EIS,
|
||||
"Creating device '%s'",
|
||||
name_suffix);
|
||||
|
||||
virtual_device = clutter_seat_create_virtual_device (seat, type);
|
||||
eis_device = eis_seat_new_device (eis_seat);
|
||||
name = g_strdup_printf ("%s %s", eis_client_get_name (client->eis_client),
|
||||
@ -582,33 +603,25 @@ handle_key (MetaEisClient *client,
|
||||
notify_key (device, key, is_press);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
drop_kbd_devices (gpointer htkey,
|
||||
gpointer value,
|
||||
gpointer data)
|
||||
{
|
||||
struct eis_device *eis_device = htkey;
|
||||
|
||||
if (!eis_device_has_capability (eis_device, EIS_DEVICE_CAP_KEYBOARD))
|
||||
return FALSE;
|
||||
|
||||
return drop_device (htkey, value, data);
|
||||
}
|
||||
|
||||
static void
|
||||
on_keymap_changed (MetaBackend *backend,
|
||||
gpointer data)
|
||||
{
|
||||
MetaEisClient *client = data;
|
||||
MetaEisDevice *keyboard;
|
||||
|
||||
/* Changing the keymap means we have to remove our device and recreate it
|
||||
* with the new keymap.
|
||||
*/
|
||||
g_hash_table_foreach_remove (client->eis_devices,
|
||||
drop_kbd_devices,
|
||||
client);
|
||||
|
||||
add_device (client,
|
||||
meta_topic (META_DEBUG_EIS,
|
||||
"Recreating keyboard device with new keyboard");
|
||||
|
||||
keyboard = g_steal_pointer (&client->keyboard_device);
|
||||
g_hash_table_remove (client->eis_devices,
|
||||
keyboard->eis_device);
|
||||
|
||||
client->keyboard_device = add_device (client,
|
||||
client->eis_seat,
|
||||
CLUTTER_KEYBOARD_DEVICE,
|
||||
"virtual keyboard",
|
||||
@ -616,12 +629,18 @@ on_keymap_changed (MetaBackend *backend,
|
||||
}
|
||||
|
||||
static void
|
||||
add_abs_pointer_devices (MetaEisClient *client)
|
||||
add_viewport_devices (MetaEisClient *client,
|
||||
ClutterInputDeviceType type,
|
||||
const char *name_suffix,
|
||||
MetaEisDeviceConfigFunc extra_config_func)
|
||||
{
|
||||
MetaEisDevice *shared_device = NULL;
|
||||
GList *viewports;
|
||||
GList *l;
|
||||
|
||||
g_return_if_fail (eis_seat_has_capability (client->eis_seat,
|
||||
EIS_DEVICE_CAP_POINTER_ABSOLUTE));
|
||||
|
||||
viewports = meta_eis_peek_viewports (client->eis);
|
||||
if (!viewports)
|
||||
return; /* FIXME: should be an error */
|
||||
@ -633,12 +652,14 @@ add_abs_pointer_devices (MetaEisClient *client)
|
||||
if (meta_eis_viewport_is_standalone (viewport))
|
||||
{
|
||||
MetaEisDevice *device;
|
||||
g_autofree char *name = NULL;
|
||||
|
||||
name = g_strdup_printf ("standalone %s", name_suffix);
|
||||
device = add_device (client,
|
||||
client->eis_seat,
|
||||
CLUTTER_POINTER_DEVICE,
|
||||
"standalone virtual absolute pointer",
|
||||
configure_abs,
|
||||
type,
|
||||
name,
|
||||
extra_config_func,
|
||||
viewport);
|
||||
device->viewport = viewport;
|
||||
}
|
||||
@ -646,11 +667,14 @@ add_abs_pointer_devices (MetaEisClient *client)
|
||||
{
|
||||
if (!shared_device)
|
||||
{
|
||||
g_autofree char *name = NULL;
|
||||
|
||||
name = g_strdup_printf ("shared %s", name_suffix);
|
||||
shared_device = create_device (client,
|
||||
client->eis_seat,
|
||||
CLUTTER_POINTER_DEVICE,
|
||||
"shared virtual absolute pointer",
|
||||
configure_abs,
|
||||
type,
|
||||
name,
|
||||
extra_config_func,
|
||||
viewport);
|
||||
}
|
||||
else
|
||||
@ -664,47 +688,128 @@ add_abs_pointer_devices (MetaEisClient *client)
|
||||
propagate_device (shared_device);
|
||||
}
|
||||
|
||||
static void
|
||||
add_abs_pointer_devices (MetaEisClient *client)
|
||||
{
|
||||
add_viewport_devices (client,
|
||||
CLUTTER_POINTER_DEVICE,
|
||||
"virtual absolute pointer",
|
||||
configure_abs);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_eis_client_process_event (MetaEisClient *client,
|
||||
struct eis_event *event)
|
||||
{
|
||||
enum eis_event_type type = eis_event_get_type (event);
|
||||
struct eis_seat *eis_seat;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case EIS_EVENT_SEAT_BIND:
|
||||
eis_seat = eis_event_get_seat (event);
|
||||
if (eis_event_seat_has_capability (event, EIS_DEVICE_CAP_POINTER))
|
||||
{
|
||||
add_device (client,
|
||||
struct eis_seat *eis_seat;
|
||||
gboolean wants_pointer_device;
|
||||
gboolean wants_keyboard_device;
|
||||
gboolean wants_abs_pointer_devices;
|
||||
|
||||
eis_seat = eis_event_get_seat (event);
|
||||
|
||||
wants_pointer_device =
|
||||
eis_event_seat_has_capability (event, EIS_DEVICE_CAP_POINTER);
|
||||
wants_keyboard_device =
|
||||
eis_event_seat_has_capability (event, EIS_DEVICE_CAP_KEYBOARD);
|
||||
wants_abs_pointer_devices =
|
||||
eis_event_seat_has_capability (event, EIS_DEVICE_CAP_POINTER_ABSOLUTE);
|
||||
|
||||
if (wants_pointer_device && !client->pointer_device)
|
||||
{
|
||||
meta_topic (META_DEBUG_EIS,
|
||||
"Seat %s bindings updated, creating pointer device",
|
||||
eis_seat_get_name (eis_seat));
|
||||
client->pointer_device = add_device (client,
|
||||
eis_seat,
|
||||
CLUTTER_POINTER_DEVICE,
|
||||
"virtual pointer",
|
||||
configure_rel, NULL);
|
||||
}
|
||||
if (eis_event_seat_has_capability (event, EIS_DEVICE_CAP_KEYBOARD))
|
||||
else if (!wants_pointer_device && client->pointer_device)
|
||||
{
|
||||
add_device (client,
|
||||
MetaEisDevice *pointer;
|
||||
|
||||
meta_topic (META_DEBUG_EIS,
|
||||
"Seat %s bindings updated, destroying pointer device",
|
||||
eis_seat_get_name (eis_seat));
|
||||
pointer = g_steal_pointer (&client->pointer_device);
|
||||
remove_device (client, pointer->eis_device, TRUE);
|
||||
}
|
||||
|
||||
if (wants_keyboard_device && !client->keyboard_device)
|
||||
{
|
||||
meta_topic (META_DEBUG_EIS,
|
||||
"Seat %s bindings updated, creating keyboard device",
|
||||
eis_seat_get_name (eis_seat));
|
||||
|
||||
client->keyboard_device = add_device (client,
|
||||
eis_seat,
|
||||
CLUTTER_KEYBOARD_DEVICE,
|
||||
"virtual keyboard",
|
||||
configure_keyboard, NULL);
|
||||
|
||||
client->keymap_changed_handler_id =
|
||||
g_signal_connect (meta_eis_get_backend (client->eis),
|
||||
"keymap-changed",
|
||||
G_CALLBACK (on_keymap_changed),
|
||||
client);
|
||||
}
|
||||
else if (!wants_keyboard_device && client->keyboard_device)
|
||||
{
|
||||
MetaEisDevice *keyboard;
|
||||
|
||||
meta_topic (META_DEBUG_EIS,
|
||||
"Seat %s bindings updated, destroying keyboard device",
|
||||
eis_seat_get_name (eis_seat));
|
||||
|
||||
keyboard = g_steal_pointer (&client->keyboard_device);
|
||||
remove_device (client, keyboard->eis_device, TRUE);
|
||||
g_clear_signal_handler (&client->keymap_changed_handler_id,
|
||||
meta_eis_get_backend (client->eis));
|
||||
}
|
||||
|
||||
if (wants_abs_pointer_devices && !client->have_abs_pointer_devices)
|
||||
{
|
||||
meta_topic (META_DEBUG_EIS,
|
||||
"Seat %s bindings updated, enabling absolute pointer devices",
|
||||
eis_seat_get_name (eis_seat));
|
||||
|
||||
add_abs_pointer_devices (client);
|
||||
break;
|
||||
client->have_abs_pointer_devices = TRUE;
|
||||
}
|
||||
else if (!wants_abs_pointer_devices && client->have_abs_pointer_devices)
|
||||
{
|
||||
meta_topic (META_DEBUG_EIS,
|
||||
"Seat %s bindings updated, destroying absolute pointer devices",
|
||||
eis_seat_get_name (eis_seat));
|
||||
|
||||
/* We only have one seat, so if the client unbinds from that
|
||||
* just disconnect it, no point keeping it alive */
|
||||
case EIS_EVENT_DEVICE_CLOSED:
|
||||
remove_device (client, eis_event_get_device (event), TRUE);
|
||||
g_hash_table_foreach_remove (client->eis_devices,
|
||||
drop_abs_devices,
|
||||
client);
|
||||
client->have_abs_pointer_devices = FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EIS_EVENT_DEVICE_CLOSED:
|
||||
{
|
||||
struct eis_device *eis_device = eis_event_get_device (event);
|
||||
MetaEisDevice *device = eis_device_get_user_data (eis_device);
|
||||
|
||||
if (client->pointer_device == device)
|
||||
client->pointer_device = NULL;
|
||||
else if (client->keyboard_device == device)
|
||||
client->keyboard_device = NULL;
|
||||
remove_device (client, eis_device, TRUE);
|
||||
|
||||
break;
|
||||
}
|
||||
case EIS_EVENT_POINTER_MOTION:
|
||||
handle_motion_relative (client, event);
|
||||
break;
|
||||
@ -744,25 +849,16 @@ meta_eis_client_process_event (MetaEisClient *client,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
drop_abs_devices (gpointer key,
|
||||
gpointer value,
|
||||
gpointer data)
|
||||
{
|
||||
struct eis_device *eis_device = key;
|
||||
|
||||
if (!eis_device_has_capability (eis_device, EIS_DEVICE_CAP_POINTER_ABSOLUTE))
|
||||
return FALSE;
|
||||
|
||||
return drop_device (key, value, data);
|
||||
}
|
||||
|
||||
static void
|
||||
update_viewports (MetaEisClient *client)
|
||||
{
|
||||
meta_topic (META_DEBUG_EIS, "Updating viewports");
|
||||
|
||||
g_hash_table_foreach_remove (client->eis_devices,
|
||||
drop_abs_devices,
|
||||
client);
|
||||
|
||||
if (client->have_abs_pointer_devices)
|
||||
add_abs_pointer_devices (client);
|
||||
}
|
||||
|
||||
@ -832,7 +928,6 @@ meta_eis_client_new (MetaEis *eis,
|
||||
g_signal_connect (eis, "viewports-changed",
|
||||
G_CALLBACK (on_viewports_changed),
|
||||
client);
|
||||
update_viewports (client);
|
||||
|
||||
return client;
|
||||
}
|
||||
@ -847,9 +942,8 @@ meta_eis_client_finalize (GObject *object)
|
||||
{
|
||||
MetaEisClient *client = META_EIS_CLIENT (object);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (meta_eis_get_backend (client->eis),
|
||||
on_keymap_changed,
|
||||
client);
|
||||
g_clear_signal_handler (&client->keymap_changed_handler_id,
|
||||
meta_eis_get_backend (client->eis));
|
||||
meta_eis_client_disconnect (client);
|
||||
|
||||
G_OBJECT_CLASS (meta_eis_client_parent_class)->finalize (object);
|
||||
|
Reference in New Issue
Block a user