backends/native: Add input thread inside MetaSeatImpl

This (now) doesn't change anything in regards to the API that the UI
thread should access from the MetaSeatImpl. The MetaInputDeviceNative,
MetaInputSettings and MetaKeymap objects are now considered owned by
the input thread, as well as all of libinput objects.

The MetaEventSource now dispatches events in a GMainContext that is
the thread default to this thread, and all UI-thread-accessible API
(seat and virtual input device API) will be handled in a serialized
manner by that same input thread.

The MetaSeatImpl itself is still considered to be owned by the caller
thread, and all the signals that this object emits will be emitted in
the GMainContext that is default at the time of calling
meta_seat_impl_new().

The MetaInputSettings configuration changes will likewise be handled
in the input thread, close to libinput devices.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
This commit is contained in:
Carlos Garnacho 2020-08-12 18:04:34 +02:00
parent 548e5138fc
commit 208e292df1
2 changed files with 145 additions and 58 deletions

View File

@ -118,7 +118,11 @@ enum
static guint signals[N_SIGNALS] = { 0 }; static guint signals[N_SIGNALS] = { 0 };
G_DEFINE_TYPE (MetaSeatImpl, meta_seat_impl, G_TYPE_OBJECT) static void meta_seat_impl_initable_iface_init (GInitableIface *iface);
G_DEFINE_TYPE_WITH_CODE (MetaSeatImpl, meta_seat_impl, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
meta_seat_impl_initable_iface_init))
static void process_events (MetaSeatImpl *seat); static void process_events (MetaSeatImpl *seat);
void meta_seat_impl_constrain_pointer (MetaSeatImpl *seat, void meta_seat_impl_constrain_pointer (MetaSeatImpl *seat,
@ -314,6 +318,50 @@ update_button_count (MetaSeatImpl *seat,
} }
} }
typedef struct
{
MetaSeatImpl *seat;
guint signal_id;
guint arg1;
guint arg2;
} MetaSeatSignalData;
static gboolean
emit_signal_main (MetaSeatSignalData *data)
{
g_signal_emit (data->seat,
data->signal_id,
0,
data->arg1,
data->arg2);
return G_SOURCE_REMOVE;
}
static void
emit_signal (MetaSeatImpl *seat,
guint signal_id,
guint arg1,
guint arg2)
{
MetaSeatSignalData *emit_signal_data;
GSource *source;
emit_signal_data = g_new0 (MetaSeatSignalData, 1);
emit_signal_data->seat = seat;
emit_signal_data->signal_id = signal_id;
emit_signal_data->arg1 = arg1;
emit_signal_data->arg2 = arg2;
source = g_idle_source_new ();
g_source_set_priority (source, G_PRIORITY_HIGH);
g_source_set_callback (source,
(GSourceFunc) emit_signal_main,
emit_signal_data,
g_free);
g_source_attach (source, seat->caller_context);
}
void void
meta_seat_impl_notify_key (MetaSeatImpl *seat, meta_seat_impl_notify_key (MetaSeatImpl *seat,
ClutterInputDevice *device, ClutterInputDevice *device,
@ -364,7 +412,7 @@ meta_seat_impl_notify_key (MetaSeatImpl *seat,
if (update_keys && (changed_state & XKB_STATE_LEDS)) if (update_keys && (changed_state & XKB_STATE_LEDS))
{ {
g_signal_emit (seat, signals[MODS_STATE_CHANGED], 0); emit_signal (seat, signals[MODS_STATE_CHANGED], 0, 0);
meta_seat_impl_sync_leds (seat); meta_seat_impl_sync_leds (seat);
meta_input_device_native_a11y_maybe_notify_toggle_keys (META_INPUT_DEVICE_NATIVE (seat->core_keyboard)); meta_input_device_native_a11y_maybe_notify_toggle_keys (META_INPUT_DEVICE_NATIVE (seat->core_keyboard));
} }
@ -873,26 +921,13 @@ meta_seat_impl_notify_touch_event (MetaSeatImpl *seat,
/* /*
* MetaEventSource for reading input devices * MetaEventSource for reading input devices
*/ */
static gboolean
meta_event_prepare (GSource *source,
gint *timeout)
{
gboolean retval;
*timeout = -1;
retval = clutter_events_pending ();
return retval;
}
static gboolean static gboolean
meta_event_check (GSource *source) meta_event_check (GSource *source)
{ {
MetaEventSource *event_source = (MetaEventSource *) source; MetaEventSource *event_source = (MetaEventSource *) source;
gboolean retval; gboolean retval;
retval = ((event_source->event_poll_fd.revents & G_IO_IN) || retval = !!(event_source->event_poll_fd.revents & G_IO_IN);
clutter_events_pending ());
return retval; return retval;
} }
@ -1372,19 +1407,13 @@ meta_event_dispatch (GSource *g_source,
seat = source->seat_impl; seat = source->seat_impl;
/* Don't queue more events if we haven't finished handling the previous batch
*/
if (clutter_events_pending ())
goto queue_event;
dispatch_libinput (seat); dispatch_libinput (seat);
queue_event:
return TRUE; return TRUE;
} }
static GSourceFuncs event_funcs = { static GSourceFuncs event_funcs = {
meta_event_prepare, NULL,
meta_event_check, meta_event_check,
meta_event_dispatch, meta_event_dispatch,
NULL NULL
@ -1411,7 +1440,7 @@ meta_event_source_new (MetaSeatImpl *seat)
g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS); g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS);
g_source_add_poll (source, &event_source->event_poll_fd); g_source_add_poll (source, &event_source->event_poll_fd);
g_source_set_can_recurse (source, TRUE); g_source_set_can_recurse (source, TRUE);
g_source_attach (source, NULL); g_source_attach (source, seat->input_context);
return event_source; return event_source;
} }
@ -1467,7 +1496,7 @@ update_touch_mode (MetaSeatImpl *seat)
if (seat->touch_mode != touch_mode) if (seat->touch_mode != touch_mode)
{ {
seat->touch_mode = touch_mode; seat->touch_mode = touch_mode;
g_signal_emit (seat, signals[TOUCH_MODE], 0, touch_mode); emit_signal (seat, signals[TOUCH_MODE], touch_mode, 0);
} }
} }
@ -2466,36 +2495,21 @@ static const struct libinput_interface libinput_interface = {
close_restricted close_restricted
}; };
static void static gpointer
meta_seat_impl_constructed (GObject *object) input_thread (MetaSeatImpl *seat)
{ {
MetaSeatImpl *seat = META_SEAT_IMPL (object);
ClutterInputDevice *device;
MetaEventSource *source; MetaEventSource *source;
struct udev *udev; struct udev *udev;
struct xkb_keymap *xkb_keymap; struct xkb_keymap *xkb_keymap;
g_rw_lock_writer_lock (&seat->state_lock); g_main_context_push_thread_default (seat->input_context);
device = meta_input_device_native_new_virtual (
seat, CLUTTER_POINTER_DEVICE,
CLUTTER_INPUT_MODE_MASTER);
seat->pointer_x = INITIAL_POINTER_X;
seat->pointer_y = INITIAL_POINTER_Y;
meta_input_device_native_update_coords (META_INPUT_DEVICE_NATIVE (device),
seat->pointer_x, seat->pointer_y);
seat->core_pointer = device;
device = meta_input_device_native_new_virtual (
seat, CLUTTER_KEYBOARD_DEVICE,
CLUTTER_INPUT_MODE_MASTER);
seat->core_keyboard = device;
udev = udev_new (); udev = udev_new ();
if (G_UNLIKELY (udev == NULL)) if (G_UNLIKELY (udev == NULL))
{ {
g_warning ("Failed to create udev object"); g_warning ("Failed to create udev object");
return; seat->input_thread_initialized = TRUE;
return NULL;
} }
seat->libinput = libinput_udev_create_context (&libinput_interface, seat->libinput = libinput_udev_create_context (&libinput_interface,
@ -2503,7 +2517,8 @@ meta_seat_impl_constructed (GObject *object)
if (seat->libinput == NULL) if (seat->libinput == NULL)
{ {
g_critical ("Failed to create the libinput object."); g_critical ("Failed to create the libinput object.");
return; seat->input_thread_initialized = TRUE;
return NULL;
} }
if (libinput_udev_assign_seat (seat->libinput, seat->seat_id) == -1) if (libinput_udev_assign_seat (seat->libinput, seat->seat_id) == -1)
@ -2511,19 +2526,20 @@ meta_seat_impl_constructed (GObject *object)
g_critical ("Failed to assign a seat to the libinput object."); g_critical ("Failed to assign a seat to the libinput object.");
libinput_unref (seat->libinput); libinput_unref (seat->libinput);
seat->libinput = NULL; seat->libinput = NULL;
return; seat->input_thread_initialized = TRUE;
return NULL;
} }
udev_unref (udev); udev_unref (udev);
seat->input_settings = meta_input_settings_native_new (seat); seat->input_settings = meta_input_settings_native_new (seat);
seat->udev_client = g_udev_client_new ((const gchar *[]) { "input", NULL });
source = meta_event_source_new (seat); source = meta_event_source_new (seat);
seat->event_source = source; seat->event_source = source;
seat->keymap = g_object_new (META_TYPE_KEYMAP_NATIVE, NULL); seat->keymap = g_object_new (META_TYPE_KEYMAP_NATIVE, NULL);
g_rw_lock_writer_lock (&seat->state_lock);
xkb_keymap = meta_keymap_native_get_keyboard_map (seat->keymap); xkb_keymap = meta_keymap_native_get_keyboard_map (seat->keymap);
if (xkb_keymap) if (xkb_keymap)
@ -2543,6 +2559,63 @@ meta_seat_impl_constructed (GObject *object)
seat->has_touchscreen = has_touchscreen (seat); seat->has_touchscreen = has_touchscreen (seat);
update_touch_mode (seat); update_touch_mode (seat);
seat->input_thread_initialized = TRUE;
seat->input_loop = g_main_loop_new (seat->input_context, FALSE);
g_main_loop_run (seat->input_loop);
g_main_loop_unref (seat->input_loop);
g_main_context_pop_thread_default (seat->input_context);
return NULL;
}
static gboolean
meta_seat_impl_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
MetaSeatImpl *seat = META_SEAT_IMPL (initable);
seat->input_context = g_main_context_new ();
seat->caller_context = g_main_context_ref_thread_default ();
seat->input_thread =
g_thread_try_new ("Mutter Input Thread",
(GThreadFunc) input_thread,
initable,
error);
if (!seat->input_thread)
return FALSE;
while (!seat->input_thread_initialized)
g_usleep (100);
return TRUE;
}
static void
meta_seat_impl_constructed (GObject *object)
{
MetaSeatImpl *seat = META_SEAT_IMPL (object);
ClutterInputDevice *device;
device = meta_input_device_native_new_virtual (
seat, CLUTTER_POINTER_DEVICE,
CLUTTER_INPUT_MODE_MASTER);
seat->pointer_x = INITIAL_POINTER_X;
seat->pointer_y = INITIAL_POINTER_Y;
meta_input_device_native_update_coords (META_INPUT_DEVICE_NATIVE (device),
seat->pointer_x, seat->pointer_y);
seat->core_pointer = device;
device = meta_input_device_native_new_virtual (
seat, CLUTTER_KEYBOARD_DEVICE,
CLUTTER_INPUT_MODE_MASTER);
seat->core_keyboard = device;
seat->udev_client = g_udev_client_new ((const gchar *[]) { "input", NULL });
if (G_OBJECT_CLASS (meta_seat_impl_parent_class)->constructed) if (G_OBJECT_CLASS (meta_seat_impl_parent_class)->constructed)
G_OBJECT_CLASS (meta_seat_impl_parent_class)->constructed (object); G_OBJECT_CLASS (meta_seat_impl_parent_class)->constructed (object);
} }
@ -2609,6 +2682,9 @@ meta_seat_impl_finalize (GObject *object)
MetaSeatImpl *seat = META_SEAT_IMPL (object); MetaSeatImpl *seat = META_SEAT_IMPL (object);
GSList *iter; GSList *iter;
g_main_loop_quit (seat->input_loop);
g_thread_join (seat->input_thread);
for (iter = seat->devices; iter; iter = g_slist_next (iter)) for (iter = seat->devices; iter; iter = g_slist_next (iter))
{ {
ClutterInputDevice *device = iter->data; ClutterInputDevice *device = iter->data;
@ -2769,6 +2845,12 @@ meta_seat_impl_query_state (MetaSeatImpl *seat,
return retval; return retval;
} }
static void
meta_seat_impl_initable_iface_init (GInitableIface *iface)
{
iface->init = meta_seat_impl_initable_init;
}
static void static void
meta_seat_impl_class_init (MetaSeatImplClass *klass) meta_seat_impl_class_init (MetaSeatImplClass *klass)
{ {
@ -3304,7 +3386,8 @@ MetaSeatImpl *
meta_seat_impl_new (MetaSeatNative *seat, meta_seat_impl_new (MetaSeatNative *seat,
const gchar *seat_id) const gchar *seat_id)
{ {
return g_object_new (META_TYPE_SEAT_IMPL, return g_initable_new (META_TYPE_SEAT_IMPL,
NULL, NULL,
"seat", seat, "seat", seat,
"seat-id", seat_id, "seat-id", seat_id,
NULL); NULL);
@ -3320,8 +3403,7 @@ meta_seat_impl_notify_kbd_a11y_flags_changed (MetaSeatImpl *impl,
input_settings = impl->input_settings; input_settings = impl->input_settings;
meta_input_settings_notify_kbd_a11y_change (input_settings, meta_input_settings_notify_kbd_a11y_change (input_settings,
new_flags, what_changed); new_flags, what_changed);
g_signal_emit (impl, signals[KBD_A11Y_FLAGS_CHANGED], 0, emit_signal (impl, signals[KBD_A11Y_FLAGS_CHANGED], new_flags, what_changed);
new_flags, what_changed);
} }
void void
@ -3329,14 +3411,14 @@ meta_seat_impl_notify_kbd_a11y_mods_state_changed (MetaSeatImpl *impl,
xkb_mod_mask_t new_latched_mods, xkb_mod_mask_t new_latched_mods,
xkb_mod_mask_t new_locked_mods) xkb_mod_mask_t new_locked_mods)
{ {
g_signal_emit (impl, signals[KBD_A11Y_MODS_STATE_CHANGED], 0, emit_signal (impl, signals[KBD_A11Y_MODS_STATE_CHANGED],
new_latched_mods, new_locked_mods); new_latched_mods, new_locked_mods);
} }
void void
meta_seat_impl_notify_bell (MetaSeatImpl *impl) meta_seat_impl_notify_bell (MetaSeatImpl *impl)
{ {
g_signal_emit (impl, signals[BELL], 0); emit_signal (impl, signals[BELL], 0, 0);
} }
MetaInputSettings * MetaInputSettings *

View File

@ -54,7 +54,11 @@ struct _MetaSeatImpl
{ {
GObject parent_instance; GObject parent_instance;
GMainContext *caller_context;
GMainContext *input_context; GMainContext *input_context;
GMainLoop *input_loop;
GThread *input_thread;
MetaSeatNative *seat; MetaSeatNative *seat;
char *seat_id; char *seat_id;
MetaEventSource *event_source; MetaEventSource *event_source;
@ -94,6 +98,7 @@ struct _MetaSeatImpl
guint has_touchscreen : 1; guint has_touchscreen : 1;
guint has_tablet_switch : 1; guint has_tablet_switch : 1;
guint touch_mode : 1; guint touch_mode : 1;
guint input_thread_initialized : 1;
/* keyboard repeat */ /* keyboard repeat */
gboolean repeat; gboolean repeat;