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:
parent
d2325f1507
commit
6a1e1d74e5
@ -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,46 +603,44 @@ 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,
|
||||
client->eis_seat,
|
||||
CLUTTER_KEYBOARD_DEVICE,
|
||||
"virtual keyboard",
|
||||
configure_keyboard, NULL);
|
||||
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",
|
||||
configure_keyboard, NULL);
|
||||
}
|
||||
|
||||
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,
|
||||
eis_seat,
|
||||
CLUTTER_POINTER_DEVICE,
|
||||
"virtual pointer",
|
||||
configure_rel, NULL);
|
||||
}
|
||||
if (eis_event_seat_has_capability (event, EIS_DEVICE_CAP_KEYBOARD))
|
||||
{
|
||||
add_device (client,
|
||||
eis_seat,
|
||||
CLUTTER_KEYBOARD_DEVICE,
|
||||
"virtual keyboard",
|
||||
configure_keyboard, NULL);
|
||||
{
|
||||
struct eis_seat *eis_seat;
|
||||
gboolean wants_pointer_device;
|
||||
gboolean wants_keyboard_device;
|
||||
gboolean wants_abs_pointer_devices;
|
||||
|
||||
g_signal_connect (meta_eis_get_backend (client->eis),
|
||||
"keymap-changed",
|
||||
G_CALLBACK (on_keymap_changed),
|
||||
client);
|
||||
}
|
||||
eis_seat = eis_event_get_seat (event);
|
||||
|
||||
add_abs_pointer_devices (client);
|
||||
break;
|
||||
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);
|
||||
|
||||
/* We only have one seat, so if the client unbinds from that
|
||||
* just disconnect it, no point keeping it alive */
|
||||
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);
|
||||
}
|
||||
else if (!wants_pointer_device && client->pointer_device)
|
||||
{
|
||||
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);
|
||||
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));
|
||||
|
||||
g_hash_table_foreach_remove (client->eis_devices,
|
||||
drop_abs_devices,
|
||||
client);
|
||||
client->have_abs_pointer_devices = FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EIS_EVENT_DEVICE_CLOSED:
|
||||
remove_device (client, eis_event_get_device (event), TRUE);
|
||||
break;
|
||||
{
|
||||
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,26 +849,17 @@ 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);
|
||||
add_abs_pointer_devices (client);
|
||||
|
||||
if (client->have_abs_pointer_devices)
|
||||
add_abs_pointer_devices (client);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user