[mutter/wip/carlosg/input-thread: 159/159] backends/native: Add input thread inside MetaSeatImpl




commit b27b4f3a9bc83056f871a7b29b30d7c3feb3e045
Author: Carlos Garnacho <carlosg gnome org>
Date:   Wed Aug 12 18:04:34 2020 +0200

    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.

 src/backends/native/meta-seat-impl.c | 163 +++++++++++++++++++++++++++--------
 src/backends/native/meta-seat-impl.h |   4 +
 2 files changed, 131 insertions(+), 36 deletions(-)
---
diff --git a/src/backends/native/meta-seat-impl.c b/src/backends/native/meta-seat-impl.c
index 1a0df28f45..2891016b74 100644
--- a/src/backends/native/meta-seat-impl.c
+++ b/src/backends/native/meta-seat-impl.c
@@ -118,7 +118,11 @@ enum
 
 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);
 void meta_seat_impl_constrain_pointer (MetaSeatImpl       *seat,
@@ -314,6 +318,48 @@ 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,
+                 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->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
 meta_seat_impl_notify_key (MetaSeatImpl       *seat,
                            ClutterInputDevice *device,
@@ -364,7 +410,7 @@ meta_seat_impl_notify_key (MetaSeatImpl       *seat,
 
   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_input_device_native_a11y_maybe_notify_toggle_keys (META_INPUT_DEVICE_NATIVE 
(seat->core_keyboard));
     }
@@ -1411,7 +1457,7 @@ meta_event_source_new (MetaSeatImpl *seat)
   g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS);
   g_source_add_poll (source, &event_source->event_poll_fd);
   g_source_set_can_recurse (source, TRUE);
-  g_source_attach (source, NULL);
+  g_source_attach (source, seat->input_context);
 
   return event_source;
 }
@@ -1467,7 +1513,7 @@ update_touch_mode (MetaSeatImpl *seat)
   if (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 +2512,20 @@ static const struct libinput_interface libinput_interface = {
   close_restricted
 };
 
-static void
-meta_seat_impl_constructed (GObject *object)
+static gpointer
+input_thread (MetaSeatImpl *seat)
 {
-  MetaSeatImpl *seat = META_SEAT_IMPL (object);
-  ClutterInputDevice *device;
   MetaEventSource *source;
   struct udev *udev;
   struct xkb_keymap *xkb_keymap;
 
-  g_rw_lock_writer_lock (&seat->state_lock);
-
-  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;
+  g_main_context_push_thread_default (seat->input_context);
 
   udev = udev_new ();
   if (G_UNLIKELY (udev == NULL))
     {
       g_warning ("Failed to create udev object");
-      return;
+      return NULL;
     }
 
   seat->libinput = libinput_udev_create_context (&libinput_interface,
@@ -2503,7 +2533,7 @@ meta_seat_impl_constructed (GObject *object)
   if (seat->libinput == NULL)
     {
       g_critical ("Failed to create the libinput object.");
-      return;
+      return NULL;
     }
 
   if (libinput_udev_assign_seat (seat->libinput, seat->seat_id) == -1)
@@ -2511,7 +2541,7 @@ meta_seat_impl_constructed (GObject *object)
       g_critical ("Failed to assign a seat to the libinput object.");
       libinput_unref (seat->libinput);
       seat->libinput = NULL;
-      return;
+      return NULL;
     }
 
   udev_unref (udev);
@@ -2519,12 +2549,12 @@ meta_seat_impl_constructed (GObject *object)
   seat->input_settings = g_object_new (META_TYPE_INPUT_SETTINGS_NATIVE,
                                        NULL);
 
-  seat->udev_client = g_udev_client_new ((const gchar *[]) { "input", NULL });
-
   source = meta_event_source_new (seat);
   seat->event_source = source;
 
   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);
 
   if (xkb_keymap)
@@ -2544,6 +2574,58 @@ meta_seat_impl_constructed (GObject *object)
   seat->has_touchscreen = has_touchscreen (seat);
   update_touch_mode (seat);
 
+  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;
+
+  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)
     G_OBJECT_CLASS (meta_seat_impl_parent_class)->constructed (object);
 }
@@ -2610,6 +2692,9 @@ meta_seat_impl_finalize (GObject *object)
   MetaSeatImpl *seat = META_SEAT_IMPL (object);
   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))
     {
       ClutterInputDevice *device = iter->data;
@@ -2770,6 +2855,12 @@ meta_seat_impl_query_state (MetaSeatImpl         *seat,
   return retval;
 }
 
+static void
+meta_seat_impl_initable_iface_init (GInitableIface *iface)
+{
+  iface->init = meta_seat_impl_initable_init;
+}
+
 static void
 meta_seat_impl_class_init (MetaSeatImplClass *klass)
 {
@@ -3301,10 +3392,11 @@ MetaSeatImpl *
 meta_seat_impl_new (MetaSeatNative *seat,
                     const gchar    *seat_id)
 {
-  return g_object_new (META_TYPE_SEAT_IMPL,
-                       "seat", seat,
-                       "seat-id", seat_id,
-                       NULL);
+  return g_initable_new (META_TYPE_SEAT_IMPL,
+                         NULL, NULL,
+                         "seat", seat,
+                         "seat-id", seat_id,
+                         NULL);
 }
 
 void
@@ -3317,8 +3409,7 @@ meta_seat_impl_notify_kbd_a11y_flags_changed (MetaSeatImpl          *impl,
   input_settings = impl->input_settings;
   meta_input_settings_notify_kbd_a11y_change (input_settings,
                                               new_flags, what_changed);
-  g_signal_emit (impl, signals[KBD_A11Y_FLAGS_CHANGED], 0,
-                 new_flags, what_changed);
+  emit_signal (impl, signals[KBD_A11Y_FLAGS_CHANGED], new_flags, what_changed);
 }
 
 void
@@ -3326,14 +3417,14 @@ meta_seat_impl_notify_kbd_a11y_mods_state_changed (MetaSeatImpl   *impl,
                                                    xkb_mod_mask_t  new_latched_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);
 }
 
 void
 meta_seat_impl_notify_bell (MetaSeatImpl *impl)
 {
-  g_signal_emit (impl, signals[BELL], 0);
+  emit_signal (impl, signals[BELL], 0, 0);
 }
 
 MetaInputSettings *
diff --git a/src/backends/native/meta-seat-impl.h b/src/backends/native/meta-seat-impl.h
index 76795493ac..158d077a67 100644
--- a/src/backends/native/meta-seat-impl.h
+++ b/src/backends/native/meta-seat-impl.h
@@ -54,7 +54,11 @@ struct _MetaSeatImpl
 {
   GObject parent_instance;
 
+  GMainContext *caller_context;
   GMainContext *input_context;
+  GMainLoop *input_loop;
+  GThread *input_thread;
+
   MetaSeatNative *seat;
   char *seat_id;
   MetaEventSource *event_source;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]