]> git.ipfire.org Git - thirdparty/plymouth.git/commitdiff
drm: Add support for new /dev/input feature
authorDiego Augusto <diego.augusto@protonmail.com>
Sat, 15 Oct 2022 17:53:34 +0000 (13:53 -0400)
committerRay Strode <rstrode@redhat.com>
Tue, 29 Nov 2022 14:22:06 +0000 (09:22 -0500)
Now that the core plymouth code supports /dev/input, the renderer
plugins need to support it as well.

As a first step, this commit adds such support to the drm renderer
plugin.

Some contributions by n3rdopolis and Ray Strode.

src/plugins/renderers/drm/plugin.c

index fb0c7e8add0d9eb7d38f715e38008d7be790f556..56c9f8981552882c79e0dce0e216c6b03bfb5073 100644 (file)
@@ -51,6 +51,7 @@
 #include "ply-array.h"
 #include "ply-buffer.h"
 #include "ply-event-loop.h"
+#include "ply-input-device.h"
 #include "ply-list.h"
 #include "ply-logger.h"
 #include "ply-hashtable.h"
@@ -94,6 +95,7 @@ struct _ply_renderer_input_source
 {
         ply_renderer_backend_t             *backend;
         ply_fd_watch_t                     *terminal_input_watch;
+        ply_list_t                         *input_devices;
 
         ply_buffer_t                       *key_buffer;
 
@@ -158,6 +160,7 @@ struct _ply_renderer_backend
 
         uint32_t                    is_active : 1;
         uint32_t                    requires_explicit_flushing : 1;
+        uint32_t                    input_source_is_open : 1;
 
         int                         panel_width;
         int                         panel_height;
@@ -166,6 +169,8 @@ struct _ply_renderer_backend
 };
 
 ply_renderer_plugin_interface_t *ply_renderer_backend_get_interface (void);
+
+static bool using_input_device (ply_renderer_input_source_t *backend);
 static bool open_input_source (ply_renderer_backend_t      *backend,
                                ply_renderer_input_source_t *input_source);
 static void flush_head (ply_renderer_backend_t *backend,
@@ -884,6 +889,7 @@ create_backend (const char     *device_name,
         backend->loop = ply_event_loop_get_default ();
         backend->heads = ply_list_new ();
         backend->input_source.key_buffer = ply_buffer_new ();
+        backend->input_source.input_devices = ply_list_new ();
         backend->terminal = terminal;
         backend->requires_explicit_flushing = true;
         backend->output_buffers = ply_hashtable_new (ply_hashtable_direct_hash,
@@ -908,6 +914,7 @@ destroy_backend (ply_renderer_backend_t *backend)
         free (backend->device_name);
         ply_hashtable_free (backend->output_buffers);
         ply_hashtable_free (backend->heads_by_controller_id);
+        ply_list_free (backend->input_source.input_devices);
 
         free (backend->outputs);
         free (backend);
@@ -1236,14 +1243,12 @@ find_controller_for_output (ply_renderer_backend_t *backend,
 
                 if (!(possible_controllers & (1 << i)))
                         continue; /* controller not usable for this connector */
-
                 for (j = 0; j < outputs_len; j++) {
                         if (outputs[j].controller_id == controller_id)
                                 break;
                 }
                 if (j < outputs_len)
                         continue; /* controller already in use */
-
                 return controller_id;
         }
 
@@ -1744,9 +1749,18 @@ get_input_source (ply_renderer_backend_t *backend)
 }
 
 static void
-on_key_event (ply_renderer_input_source_t *input_source,
-              int                          terminal_fd)
+on_terminal_key_event (ply_renderer_input_source_t *input_source)
 {
+        ply_renderer_backend_t *backend = input_source->backend;
+        int terminal_fd;
+
+        if (using_input_device (input_source)) {
+                ply_terminal_flush_input (backend->terminal);
+                return;
+        }
+
+        terminal_fd = ply_terminal_get_fd (backend->terminal);
+
         ply_buffer_append_from_fd (input_source->key_buffer,
                                    terminal_fd);
 
@@ -1754,6 +1768,34 @@ on_key_event (ply_renderer_input_source_t *input_source,
                 input_source->handler (input_source->user_data, input_source->key_buffer, input_source);
 }
 
+static void
+on_input_device_key (ply_renderer_input_source_t *input_source,
+                     ply_input_device_t          *input_device,
+                     const char                  *text)
+{
+        int len = strlen (text);
+        if (len > 0)
+                ply_buffer_append_bytes (input_source->key_buffer, text, len);
+
+        if (input_source->handler != NULL)
+                input_source->handler (input_source->user_data, input_source->key_buffer, input_source);
+}
+
+static void
+on_input_leds_changed (ply_renderer_input_source_t *input_source,
+                       ply_input_device_t          *input_device)
+{
+        ply_xkb_keyboard_state_t *state;
+        ply_list_node_t *node;
+
+        state = ply_input_device_get_state (input_device);
+
+        ply_list_foreach (input_source->input_devices, node) {
+                ply_input_device_t *set_input_device = ply_list_node_get_data (node);
+                ply_input_device_set_state (set_input_device, state);
+        }
+}
+
 static void
 on_input_source_disconnected (ply_renderer_input_source_t *input_source)
 {
@@ -1762,6 +1804,37 @@ on_input_source_disconnected (ply_renderer_input_source_t *input_source)
         open_input_source (input_source->backend, input_source);
 }
 
+static bool
+using_input_device (ply_renderer_input_source_t *input_source)
+{
+        return ply_list_get_length (input_source->input_devices) > 0;
+}
+
+static void
+watch_input_device (ply_renderer_backend_t *backend,
+                    ply_input_device_t     *input_device)
+{
+        ply_trace ("Listening for keys from device '%s'", ply_input_device_get_name (input_device));
+
+        ply_input_device_watch_for_input (input_device,
+                                          (ply_input_device_input_handler_t) on_input_device_key,
+                                          (ply_input_device_leds_changed_handler_t) on_input_leds_changed,
+                                          &backend->input_source);
+}
+
+static void
+watch_input_devices (ply_renderer_backend_t *backend)
+{
+        ply_list_node_t *node;
+        ply_renderer_input_source_t *input_source = &backend->input_source;
+
+        ply_list_foreach (input_source->input_devices, node) {
+                ply_input_device_t *input_device = ply_list_node_get_data (node);
+
+                watch_input_device (backend, input_device);
+        }
+}
+
 static bool
 open_input_source (ply_renderer_backend_t      *backend,
                    ply_renderer_input_source_t *input_source)
@@ -1771,16 +1844,24 @@ open_input_source (ply_renderer_backend_t      *backend,
         assert (backend != NULL);
         assert (has_input_source (backend, input_source));
 
+        if (!backend->input_source_is_open)
+                watch_input_devices (backend);
+
         if (backend->terminal == NULL)
                 return false;
 
-        terminal_fd = ply_terminal_get_fd (backend->terminal);
+        if (backend->terminal != NULL) {
+                terminal_fd = ply_terminal_get_fd (backend->terminal);
+
+                input_source->terminal_input_watch = ply_event_loop_watch_fd (backend->loop, terminal_fd, PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
+                                                                              (ply_event_handler_t) on_terminal_key_event,
+                                                                              (ply_event_handler_t)
+                                                                              on_input_source_disconnected, input_source);
+        }
 
         input_source->backend = backend;
-        input_source->terminal_input_watch = ply_event_loop_watch_fd (backend->loop, terminal_fd, PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
-                                                                      (ply_event_handler_t) on_key_event,
-                                                                      (ply_event_handler_t)
-                                                                      on_input_source_disconnected, input_source);
+        backend->input_source_is_open = true;
+
         return true;
 }
 
@@ -1804,12 +1885,28 @@ close_input_source (ply_renderer_backend_t      *backend,
         assert (backend != NULL);
         assert (has_input_source (backend, input_source));
 
-        if (backend->terminal == NULL)
+        if (!backend->input_source_is_open)
                 return;
 
-        ply_event_loop_stop_watching_fd (backend->loop, input_source->terminal_input_watch);
-        input_source->terminal_input_watch = NULL;
+        if (using_input_device (input_source)) {
+                ply_list_node_t *node;
+                ply_list_foreach (input_source->input_devices, node) {
+                        ply_input_device_t *input_device = ply_list_node_get_data (node);
+                        ply_input_device_stop_watching_for_input (input_device,
+                                                                  (ply_input_device_input_handler_t) on_input_device_key,
+                                                                  (ply_input_device_leds_changed_handler_t) on_input_leds_changed,
+                                                                  &backend->input_source);
+                }
+        }
+
+        if (input_source->terminal_input_watch != NULL) {
+                ply_event_loop_stop_watching_fd (backend->loop, input_source->terminal_input_watch);
+                input_source->terminal_input_watch = NULL;
+        }
+
         input_source->backend = NULL;
+
+        backend->input_source_is_open = false;
 }
 
 static bool
@@ -1829,9 +1926,30 @@ get_panel_properties (ply_renderer_backend_t      *backend,
         return true;
 }
 
+static ply_input_device_t *
+get_any_input_device_with_leds (ply_renderer_backend_t *backend)
+{
+        ply_list_node_t *node;
+
+        ply_list_foreach (backend->input_source.input_devices, node) {
+                ply_input_device_t *input_device;
+
+                input_device = ply_list_node_get_data (node);
+
+                if (ply_input_device_is_keyboard_with_leds (input_device))
+                        return input_device;
+        }
+
+        return NULL;
+}
+
 static bool
 get_capslock_state (ply_renderer_backend_t *backend)
 {
+        if (using_input_device (&backend->input_source)) {
+                ply_input_device_t *dev = get_any_input_device_with_leds (backend);
+                return ply_input_device_get_capslock_state (dev);
+        }
         if (!backend->terminal)
                 return false;
 
@@ -1841,12 +1959,64 @@ get_capslock_state (ply_renderer_backend_t *backend)
 static const char *
 get_keymap (ply_renderer_backend_t *backend)
 {
+        if (using_input_device (&backend->input_source)) {
+                ply_input_device_t *dev = get_any_input_device_with_leds (backend);
+                const char *keymap = ply_input_device_get_keymap (dev);
+                if (keymap != NULL) {
+                        return keymap;
+                }
+        }
         if (!backend->terminal)
                 return NULL;
 
         return ply_terminal_get_keymap (backend->terminal);
 }
 
+static void
+sync_input_devices (ply_renderer_backend_t *backend)
+{
+        ply_list_node_t *node;
+        ply_xkb_keyboard_state_t *xkb_state;
+        ply_input_device_t *source_input_device;
+
+        source_input_device = get_any_input_device_with_leds (backend);
+
+        if (source_input_device == NULL)
+                return;
+
+        xkb_state = ply_input_device_get_state (source_input_device);
+
+        ply_list_foreach (backend->input_source.input_devices, node) {
+                ply_input_device_t *target_input_device = ply_list_node_get_data (node);
+
+                if (source_input_device == target_input_device)
+                        continue;
+
+                ply_input_device_set_state (target_input_device, xkb_state);
+        }
+}
+
+static void
+add_input_device (ply_renderer_backend_t *backend,
+                  ply_input_device_t     *input_device)
+{
+        ply_list_append_data (backend->input_source.input_devices, input_device);
+
+        if (backend->input_source_is_open)
+                watch_input_device (backend, input_device);
+
+        sync_input_devices (backend);
+}
+
+static void
+remove_input_device (ply_renderer_backend_t *backend,
+                     ply_input_device_t     *input_device)
+{
+        ply_list_remove_data (backend->input_source.input_devices, input_device);
+
+        sync_input_devices (backend);
+}
+
 ply_renderer_plugin_interface_t *
 ply_renderer_backend_get_interface (void)
 {
@@ -1873,8 +2043,9 @@ ply_renderer_backend_get_interface (void)
                 .get_panel_properties         = get_panel_properties,
                 .get_capslock_state           = get_capslock_state,
                 .get_keymap                   = get_keymap,
+                .add_input_device             = add_input_device,
+                .remove_input_device          = remove_input_device,
         };
 
         return &plugin_interface;
 }
-