Blob Blame History Raw
From 6283d0a786d7fec368d33dfeb25c0342cc5168ec Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 22 Jul 2015 10:05:51 -0400
Subject: [PATCH 1/8] renderer: track activeness

Right now, ply-seat has to handle tracking
renderer activeness on its own.  This commit
moves activeness tracking to ply-renderer
directly.
---
 src/libply-splash-core/ply-renderer.c | 30 ++++++++++++++++++++++++++----
 src/libply-splash-core/ply-renderer.h |  1 +
 src/libply-splash-core/ply-seat.c     | 15 ---------------
 3 files changed, 27 insertions(+), 19 deletions(-)

diff --git a/src/libply-splash-core/ply-renderer.c b/src/libply-splash-core/ply-renderer.c
index 04a99ce..3d9aa43 100644
--- a/src/libply-splash-core/ply-renderer.c
+++ b/src/libply-splash-core/ply-renderer.c
@@ -28,60 +28,61 @@
 #include <assert.h>
 #include <errno.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include "ply-renderer-plugin.h"
 #include "ply-buffer.h"
 #include "ply-terminal.h"
 #include "ply-event-loop.h"
 #include "ply-list.h"
 #include "ply-logger.h"
 #include "ply-utils.h"
 
 struct _ply_renderer
 {
   ply_event_loop_t *loop;
   ply_module_handle_t *module_handle;
   const ply_renderer_plugin_interface_t *plugin_interface;
   ply_renderer_backend_t *backend;
 
   ply_renderer_type_t type;
   char *device_name;
   ply_terminal_t *terminal;
 
   uint32_t input_source_is_open : 1;
   uint32_t is_mapped : 1;
+  uint32_t is_active : 1;
 };
 
 typedef const ply_renderer_plugin_interface_t *
         (* get_backend_interface_function_t) (void);
 
 static void ply_renderer_unload_plugin (ply_renderer_t *renderer);
 
 ply_renderer_t *
 ply_renderer_new (ply_renderer_type_t  renderer_type,
                   const char          *device_name,
                   ply_terminal_t      *terminal)
 {
   ply_renderer_t *renderer;
 
   renderer = calloc (1, sizeof (struct _ply_renderer));
 
   renderer->type = renderer_type;
 
   if (device_name != NULL)
     renderer->device_name = strdup (device_name);
 
   renderer->terminal = terminal;
 
   return renderer;
 }
 
 void
 ply_renderer_free (ply_renderer_t *renderer)
 {
   if (renderer == NULL)
@@ -247,95 +248,116 @@ ply_renderer_open_plugin (ply_renderer_t *renderer,
   if (!ply_renderer_query_device (renderer))
     {
       ply_trace ("could not query rendering device for plugin %s",
                  plugin_path);
       ply_renderer_close_device (renderer);
       ply_renderer_unload_plugin (renderer);
       return false;
     }
 
   ply_trace ("opened renderer plugin %s", plugin_path);
   return true;
 }
 
 bool
 ply_renderer_open (ply_renderer_t *renderer)
 {
   int i;
 
   struct
     {
       ply_renderer_type_t  type;
       const char          *path;
     } known_plugins[] =
     {
       { PLY_RENDERER_TYPE_X11, PLYMOUTH_PLUGIN_PATH "renderers/x11.so" },
       { PLY_RENDERER_TYPE_DRM, PLYMOUTH_PLUGIN_PATH "renderers/drm.so" },
       { PLY_RENDERER_TYPE_FRAME_BUFFER, PLYMOUTH_PLUGIN_PATH "renderers/frame-buffer.so" },
       { PLY_RENDERER_TYPE_NONE, NULL }
     };
 
+  renderer->is_active = false;
   for (i = 0; known_plugins[i].type != PLY_RENDERER_TYPE_NONE; i++)
     {
       if (renderer->type == known_plugins[i].type ||
           renderer->type == PLY_RENDERER_TYPE_AUTO)
         {
           if (ply_renderer_open_plugin (renderer, known_plugins[i].path))
-            return true;
+            {
+              renderer->is_active = true;
+              goto out;
+            }
         }
     }
 
   ply_trace ("could not find suitable rendering plugin");
-  return false;
+
+out:
+  return renderer->is_active;
 }
 
 void
 ply_renderer_close (ply_renderer_t *renderer)
 {
   ply_renderer_unmap_from_device (renderer);
   ply_renderer_close_device (renderer);
+  renderer->is_active = false;
 }
 
 void
 ply_renderer_activate (ply_renderer_t *renderer)
 {
   assert (renderer->plugin_interface != NULL);
 
-  return renderer->plugin_interface->activate (renderer->backend);
+  if (renderer->is_active)
+    return;
+
+  renderer->plugin_interface->activate (renderer->backend);
+  renderer->is_active = true;
 }
 
 void
 ply_renderer_deactivate (ply_renderer_t *renderer)
 {
   assert (renderer->plugin_interface != NULL);
 
-  return renderer->plugin_interface->deactivate (renderer->backend);
+  if (!renderer->is_active)
+    return;
+
+  renderer->plugin_interface->deactivate (renderer->backend);
+  renderer->is_active = false;
+}
+
+bool
+ply_renderer_is_active (ply_renderer_t *renderer)
+{
+  return renderer->is_active;
 }
 
 ply_list_t *
 ply_renderer_get_heads (ply_renderer_t *renderer)
 {
   assert (renderer->plugin_interface != NULL);
 
   return renderer->plugin_interface->get_heads (renderer->backend);
 }
 
 ply_pixel_buffer_t *
 ply_renderer_get_buffer_for_head (ply_renderer_t      *renderer,
                                   ply_renderer_head_t *head)
 {
   assert (renderer != NULL);
   assert (renderer->plugin_interface != NULL);
   assert (head != NULL);
 
   return renderer->plugin_interface->get_buffer_for_head (renderer->backend,
                                                           head);
 }
 
 void
 ply_renderer_flush_head (ply_renderer_t      *renderer,
                          ply_renderer_head_t *head)
 {
   assert (renderer != NULL);
   assert (renderer->plugin_interface != NULL);
   assert (head != NULL);
 
diff --git a/src/libply-splash-core/ply-renderer.h b/src/libply-splash-core/ply-renderer.h
index 3d48341..a47174a 100644
--- a/src/libply-splash-core/ply-renderer.h
+++ b/src/libply-splash-core/ply-renderer.h
@@ -30,52 +30,53 @@
 #include "ply-pixel-buffer.h"
 #include "ply-terminal.h"
 #include "ply-utils.h"
 
 typedef struct _ply_renderer ply_renderer_t;
 typedef struct _ply_renderer_head ply_renderer_head_t;
 typedef struct _ply_renderer_input_source ply_renderer_input_source_t;
 
 typedef enum
 {
   PLY_RENDERER_TYPE_NONE = -1,
   PLY_RENDERER_TYPE_AUTO,
   PLY_RENDERER_TYPE_DRM,
   PLY_RENDERER_TYPE_FRAME_BUFFER,
   PLY_RENDERER_TYPE_X11
 } ply_renderer_type_t;
 
 typedef void (* ply_renderer_input_source_handler_t) (void                        *user_data,
                                                       ply_buffer_t                *key_buffer,
                                                       ply_renderer_input_source_t *input_source);
 
 #ifndef PLY_HIDE_FUNCTION_DECLARATIONS
 ply_renderer_t *ply_renderer_new (ply_renderer_type_t renderer_type,
                                   const char     *device_name,
                                   ply_terminal_t *terminal);
 void ply_renderer_free (ply_renderer_t *renderer);
 bool ply_renderer_open (ply_renderer_t *renderer);
 void ply_renderer_close (ply_renderer_t *renderer);
 void ply_renderer_activate (ply_renderer_t *renderer);
 void ply_renderer_deactivate (ply_renderer_t *renderer);
+bool ply_renderer_is_active (ply_renderer_t *renderer);
 const char *ply_renderer_get_device_name (ply_renderer_t *renderer);
 ply_list_t *ply_renderer_get_heads (ply_renderer_t *renderer);
 ply_pixel_buffer_t *ply_renderer_get_buffer_for_head (ply_renderer_t      *renderer,
                                                       ply_renderer_head_t *head);
 
 void ply_renderer_flush_head (ply_renderer_t      *renderer,
                               ply_renderer_head_t *head);
 
 ply_renderer_input_source_t *ply_renderer_get_input_source (ply_renderer_t *renderer);
 bool ply_renderer_open_input_source (ply_renderer_t              *renderer,
                                      ply_renderer_input_source_t *input_source);
 void ply_renderer_set_handler_for_input_source (ply_renderer_t                      *renderer,
                                                 ply_renderer_input_source_t         *input_source,
                                                 ply_renderer_input_source_handler_t  handler,
                                                 void                                *user_data);
 
 void ply_renderer_close_input_source (ply_renderer_t              *renderer,
                                       ply_renderer_input_source_t *input_source);
 #endif
 
 #endif /* PLY_RENDERER_H */
 /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
diff --git a/src/libply-splash-core/ply-seat.c b/src/libply-splash-core/ply-seat.c
index cd7e5bc..4635889 100644
--- a/src/libply-splash-core/ply-seat.c
+++ b/src/libply-splash-core/ply-seat.c
@@ -22,61 +22,60 @@
 #include "config.h"
 #include "ply-seat.h"
 
 #include <assert.h>
 #include <errno.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 
 #include "ply-boot-splash.h"
 #include "ply-event-loop.h"
 #include "ply-keyboard.h"
 #include "ply-pixel-display.h"
 #include "ply-text-display.h"
 #include "ply-list.h"
 #include "ply-logger.h"
 #include "ply-utils.h"
 
 struct _ply_seat
 {
   ply_event_loop_t *loop;
 
   ply_boot_splash_t *splash;
   ply_terminal_t *terminal;
   ply_renderer_t *renderer;
   ply_keyboard_t *keyboard;
   ply_list_t *text_displays;
   ply_list_t *pixel_displays;
 
-  uint32_t renderer_active : 1;
   uint32_t keyboard_active : 1;
 };
 
 ply_seat_t *
 ply_seat_new (ply_terminal_t *terminal)
 {
   ply_seat_t *seat;
 
   seat = calloc (1, sizeof (ply_seat_t));
 
   seat->loop = ply_event_loop_get_default ();
   seat->terminal = terminal;
   seat->text_displays = ply_list_new ();
   seat->pixel_displays = ply_list_new ();
 
   return seat;
 }
 
 static void
 add_pixel_displays (ply_seat_t *seat)
 {
   ply_list_t *heads;
   ply_list_node_t *node;
 
   heads = ply_renderer_get_heads (seat->renderer);
 
   ply_trace ("Adding displays for %d heads",
              ply_list_get_length (heads));
 
   node = ply_list_get_first_node (heads);
@@ -108,70 +107,66 @@ add_text_displays (ply_seat_t *seat)
         {
           ply_trace ("could not add terminal %s: %m",
                      ply_terminal_get_name (seat->terminal));
           return;
         }
     }
 
   ply_trace ("adding text display for terminal %s",
              ply_terminal_get_name (seat->terminal));
 
   display = ply_text_display_new (seat->terminal);
   ply_list_append_data (seat->text_displays, display);
 }
 
 bool
 ply_seat_open (ply_seat_t          *seat,
                ply_renderer_type_t  renderer_type,
                const char          *device)
 {
   if (renderer_type != PLY_RENDERER_TYPE_NONE)
     {
       ply_renderer_t *renderer;
 
       renderer = ply_renderer_new (renderer_type, device, seat->terminal);
 
       if (!ply_renderer_open (renderer))
         {
           ply_trace ("could not open renderer for %s", device);
           ply_renderer_free (renderer);
 
-          seat->renderer = NULL;
-          seat->renderer_active = false;
-
           if (renderer_type != PLY_RENDERER_TYPE_AUTO)
             return false;
         }
       else
         {
           seat->renderer = renderer;
-          seat->renderer_active = true;
         }
     }
 
   if (seat->renderer != NULL)
     {
       seat->keyboard = ply_keyboard_new_for_renderer (seat->renderer);
       add_pixel_displays (seat);
 
     }
   else if (seat->terminal != NULL)
     {
       seat->keyboard = ply_keyboard_new_for_terminal (seat->terminal);
     }
 
   if (seat->terminal != NULL)
     {
       add_text_displays (seat);
     }
   else
     {
       ply_trace ("not adding text display for seat, since seat has no associated terminal");
     }
 
   if (seat->keyboard != NULL)
     {
       ply_keyboard_watch_for_input (seat->keyboard);
       seat->keyboard_active = true;
     }
   else
     {
@@ -179,100 +174,90 @@ ply_seat_open (ply_seat_t          *seat,
     }
 
   return true;
 }
 
 bool
 ply_seat_is_open (ply_seat_t *seat)
 {
   return ply_list_get_length (seat->pixel_displays) > 0 ||
          ply_list_get_length (seat->text_displays) > 0;
 }
 
 void
 ply_seat_deactivate_keyboard (ply_seat_t *seat)
 {
   if (!seat->keyboard_active)
     return;
 
   seat->keyboard_active = false;
 
   if (seat->keyboard == NULL)
     return;
 
   ply_trace ("deactivating keybord");
   ply_keyboard_stop_watching_for_input (seat->keyboard);
 }
 
 void
 ply_seat_deactivate_renderer (ply_seat_t *seat)
 {
-  if (!seat->renderer_active)
-    return;
-
-  seat->renderer_active = false;
-
   if (seat->renderer == NULL)
     return;
 
   ply_trace ("deactivating renderer");
   ply_renderer_deactivate (seat->renderer);
 }
 
 void
 ply_seat_activate_keyboard (ply_seat_t *seat)
 {
   if (seat->keyboard_active)
     return;
 
   if (seat->keyboard == NULL)
     return;
 
   ply_trace ("activating keyboard");
   ply_keyboard_watch_for_input (seat->keyboard);
 
   seat->keyboard_active = true;
 }
 
 void
 ply_seat_activate_renderer (ply_seat_t *seat)
 {
-  if (seat->renderer_active)
-    return;
-
   if (seat->renderer == NULL)
     return;
 
   ply_trace ("activating renderer");
   ply_renderer_activate (seat->renderer);
-
-  seat->renderer_active = true;
 }
 
 void
 ply_seat_refresh_displays (ply_seat_t *seat)
 {
   ply_list_node_t *node;
 
   node = ply_list_get_first_node (seat->pixel_displays);
   while (node != NULL)
     {
       ply_pixel_display_t *display;
       ply_list_node_t *next_node;
       unsigned long width, height;
 
       display = ply_list_node_get_data (node);
       next_node = ply_list_get_next_node (seat->pixel_displays, node);
 
       width = ply_pixel_display_get_width (display);
       height = ply_pixel_display_get_height (display);
 
       ply_pixel_display_draw_area (display, 0, 0, width, height);
       node = next_node;
     }
 
   node = ply_list_get_first_node (seat->text_displays);
   while (node != NULL)
     {
       ply_text_display_t *display;
       ply_list_node_t *next_node;
       int number_of_columns, number_of_rows;
-- 
2.3.7


From fb294aa5fc8ea8236ce91617a229daad9251a2f8 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 22 Jul 2015 10:05:51 -0400
Subject: [PATCH 2/8] keyboard: track activeness

Right now, ply-seat has to handle tracking
keyboard activeness on its own.  This commit
moves activeness tracking to ply-keyboard
directly.
---
 src/libply-splash-core/ply-keyboard.c | 23 ++++++++++++++++++++---
 src/libply-splash-core/ply-keyboard.h |  1 +
 src/libply-splash-core/ply-seat.c     | 13 -------------
 3 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/src/libply-splash-core/ply-keyboard.c b/src/libply-splash-core/ply-keyboard.c
index 624f906..e2fd814 100644
--- a/src/libply-splash-core/ply-keyboard.c
+++ b/src/libply-splash-core/ply-keyboard.c
@@ -65,60 +65,62 @@ typedef enum
 typedef struct
 {
   ply_terminal_t *terminal;
   ply_buffer_t   *key_buffer;
 } ply_keyboard_terminal_provider_t;
 
 typedef struct
 {
   ply_renderer_t              *renderer;
   ply_renderer_input_source_t *input_source;
 } ply_keyboard_renderer_provider_t;
 
 typedef  union {
   ply_keyboard_renderer_provider_t *if_renderer;
   ply_keyboard_terminal_provider_t *if_terminal;
 } ply_keyboard_provider_t;
 
 struct _ply_keyboard
 {
   ply_event_loop_t *loop;
 
   ply_keyboard_provider_type_t provider_type;
   ply_keyboard_provider_t provider;
 
   ply_buffer_t     *line_buffer;
 
   ply_list_t *keyboard_input_handler_list;
   ply_list_t *backspace_handler_list;
   ply_list_t *escape_handler_list;
   ply_list_t *enter_handler_list;
+
+  uint32_t is_active : 1;
 };
 
 static bool ply_keyboard_watch_for_terminal_input (ply_keyboard_t *keyboard);
 
 ply_keyboard_t *
 ply_keyboard_new_for_terminal (ply_terminal_t *terminal)
 {
   ply_keyboard_t *keyboard;
 
   keyboard = calloc (1, sizeof (ply_keyboard_t));
   keyboard->line_buffer = ply_buffer_new ();
   keyboard->keyboard_input_handler_list = ply_list_new ();
   keyboard->backspace_handler_list = ply_list_new ();
   keyboard->escape_handler_list = ply_list_new ();
   keyboard->enter_handler_list = ply_list_new ();
   keyboard->provider_type = PLY_KEYBOARD_PROVIDER_TYPE_TERMINAL;
   keyboard->provider.if_terminal = calloc (1, sizeof (ply_keyboard_terminal_provider_t));
   keyboard->provider.if_terminal->terminal = terminal;
   keyboard->provider.if_terminal->key_buffer = ply_buffer_new ();
 
   keyboard->loop = ply_event_loop_get_default ();
 
   return keyboard;
 }
 
 ply_keyboard_t *
 ply_keyboard_new_for_renderer (ply_renderer_t *renderer)
 {
   ply_keyboard_t *keyboard;
   ply_renderer_input_source_t *input_source;
@@ -303,135 +305,150 @@ on_key_event (ply_keyboard_t   *keyboard,
 
 static bool
 ply_keyboard_watch_for_renderer_input (ply_keyboard_t *keyboard)
 {
   assert (keyboard != NULL);
 
   if (!ply_renderer_open_input_source (keyboard->provider.if_renderer->renderer,
                                        keyboard->provider.if_renderer->input_source))
     return false;
 
   ply_renderer_set_handler_for_input_source (keyboard->provider.if_renderer->renderer,
                                              keyboard->provider.if_renderer->input_source,
                                              (ply_renderer_input_source_handler_t)
                                              on_key_event,
                                              keyboard);
   return true;
 }
 
 static void
 ply_keyboard_stop_watching_for_renderer_input (ply_keyboard_t *keyboard)
 {
   ply_renderer_set_handler_for_input_source (keyboard->provider.if_renderer->renderer,
                                              keyboard->provider.if_renderer->input_source,
                                              (ply_renderer_input_source_handler_t)
                                              NULL, NULL);
 
   ply_renderer_close_input_source (keyboard->provider.if_renderer->renderer,
                                    keyboard->provider.if_renderer->input_source);
 }
 
+bool
+ply_keyboard_is_active (ply_keyboard_t *keyboard)
+{
+  return keyboard->is_active;
+}
+
 static void
 on_terminal_data (ply_keyboard_t *keyboard)
 {
   int terminal_fd;
 
   terminal_fd = ply_terminal_get_fd (keyboard->provider.if_terminal->terminal);
   ply_buffer_append_from_fd (keyboard->provider.if_terminal->key_buffer,
                              terminal_fd);
   on_key_event (keyboard, keyboard->provider.if_terminal->key_buffer);
 }
 
 static bool
 ply_keyboard_watch_for_terminal_input (ply_keyboard_t *keyboard)
 {
   int terminal_fd;
 
   assert (keyboard != NULL);
 
   terminal_fd = ply_terminal_get_fd (keyboard->provider.if_terminal->terminal);
 
   if (terminal_fd < 0 || !ply_terminal_is_open (keyboard->provider.if_terminal->terminal))
     {
       ply_trace ("terminal associated with keyboard isn't open");
       return false;
     }
 
   ply_terminal_watch_for_input (keyboard->provider.if_terminal->terminal,
                                 (ply_terminal_input_handler_t) on_terminal_data,
                                 keyboard);
 
   return true;
 }
 
 static void
 ply_keyboard_stop_watching_for_terminal_input (ply_keyboard_t *keyboard)
 {
   ply_terminal_stop_watching_for_input (keyboard->provider.if_terminal->terminal,
                                         (ply_terminal_input_handler_t)
                                         on_terminal_data,
                                         keyboard);
 }
 
 bool
 ply_keyboard_watch_for_input (ply_keyboard_t *keyboard)
 {
   assert (keyboard != NULL);
 
+  if (keyboard->is_active)
+    return true;
+
   switch (keyboard->provider_type)
     {
       case PLY_KEYBOARD_PROVIDER_TYPE_RENDERER:
-        return ply_keyboard_watch_for_renderer_input (keyboard);
+        keyboard->is_active = ply_keyboard_watch_for_renderer_input (keyboard);
+        break;
 
       case PLY_KEYBOARD_PROVIDER_TYPE_TERMINAL:
-        return ply_keyboard_watch_for_terminal_input (keyboard);
+        keyboard->is_active = ply_keyboard_watch_for_terminal_input (keyboard);
+        break;
     }
 
-  return false;
+  return keyboard->is_active;
 }
 
 void
 ply_keyboard_stop_watching_for_input (ply_keyboard_t *keyboard)
 {
   assert (keyboard != NULL);
 
+  if (!keyboard->is_active)
+    return;
+
   switch (keyboard->provider_type)
     {
       case PLY_KEYBOARD_PROVIDER_TYPE_RENDERER:
         ply_keyboard_stop_watching_for_renderer_input (keyboard);
         break;
 
       case PLY_KEYBOARD_PROVIDER_TYPE_TERMINAL:
         ply_keyboard_stop_watching_for_terminal_input (keyboard);
         break;
     }
 
+  keyboard->is_active = false;
 }
 
 void
 ply_keyboard_free (ply_keyboard_t *keyboard)
 {
   if (keyboard == NULL)
     return;
 
   ply_keyboard_stop_watching_for_input (keyboard);
 
   ply_buffer_free (keyboard->line_buffer);
 
   if (keyboard->provider_type == PLY_KEYBOARD_PROVIDER_TYPE_RENDERER)
     {
       free (keyboard->provider.if_renderer);
     }
   else
     {
       ply_buffer_free (keyboard->provider.if_terminal->key_buffer);
       free (keyboard->provider.if_terminal);
     }
 
   free (keyboard);
 }
 
 static ply_keyboard_closure_t *
 ply_keyboard_closure_new (ply_keyboard_handler_t  function,
                           void                   *user_data)
 {
   ply_keyboard_closure_t *closure = calloc (1, sizeof (ply_keyboard_closure_t));
diff --git a/src/libply-splash-core/ply-keyboard.h b/src/libply-splash-core/ply-keyboard.h
index 74683cf..19e3d85 100644
--- a/src/libply-splash-core/ply-keyboard.h
+++ b/src/libply-splash-core/ply-keyboard.h
@@ -44,35 +44,36 @@ typedef void (* ply_keyboard_enter_handler_t) (void       *user_data,
                                                const char *line);
 
 #ifndef PLY_HIDE_FUNCTION_DECLARATIONS
 ply_keyboard_t *ply_keyboard_new_for_terminal (ply_terminal_t *terminal);
 ply_keyboard_t *ply_keyboard_new_for_renderer (ply_renderer_t *renderer);
 void ply_keyboard_free (ply_keyboard_t *keyboard);
 
 void ply_keyboard_add_input_handler (ply_keyboard_t               *keyboard,
                                      ply_keyboard_input_handler_t  input_handler,
                                      void                         *user_data);
 void ply_keyboard_remove_input_handler (ply_keyboard_t               *keyboard,
                                         ply_keyboard_input_handler_t  input_handler);
 void ply_keyboard_add_backspace_handler (ply_keyboard_t                   *keyboard,
                                          ply_keyboard_backspace_handler_t  backspace_handler,
                                          void                             *user_data);
 void ply_keyboard_remove_backspace_handler (ply_keyboard_t                   *keyboard,
                                             ply_keyboard_backspace_handler_t  backspace_handler);
 void ply_keyboard_add_escape_handler (ply_keyboard_t                *keyboard,
                                       ply_keyboard_escape_handler_t  escape_handler,
                                       void                          *user_data);
 void ply_keyboard_remove_escape_handler (ply_keyboard_t                *keyboard,
                                          ply_keyboard_escape_handler_t  escape_handler);
 void ply_keyboard_add_enter_handler (ply_keyboard_t               *keyboard,
                                      ply_keyboard_enter_handler_t  enter_handler,
                                      void                         *user_data);
 void ply_keyboard_remove_enter_handler (ply_keyboard_t               *keyboard,
                                         ply_keyboard_enter_handler_t  enter_handler);
 
 bool ply_keyboard_watch_for_input (ply_keyboard_t *keyboard);
 void ply_keyboard_stop_watching_for_input (ply_keyboard_t *keyboard);
+bool ply_keyboard_is_active (ply_keyboard_t *keyboard);
 
 #endif
 
 #endif /* PLY_KEYBOARD_H */
 /* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */
diff --git a/src/libply-splash-core/ply-seat.c b/src/libply-splash-core/ply-seat.c
index 4635889..1c885c2 100644
--- a/src/libply-splash-core/ply-seat.c
+++ b/src/libply-splash-core/ply-seat.c
@@ -21,62 +21,60 @@
  */
 #include "config.h"
 #include "ply-seat.h"
 
 #include <assert.h>
 #include <errno.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 
 #include "ply-boot-splash.h"
 #include "ply-event-loop.h"
 #include "ply-keyboard.h"
 #include "ply-pixel-display.h"
 #include "ply-text-display.h"
 #include "ply-list.h"
 #include "ply-logger.h"
 #include "ply-utils.h"
 
 struct _ply_seat
 {
   ply_event_loop_t *loop;
 
   ply_boot_splash_t *splash;
   ply_terminal_t *terminal;
   ply_renderer_t *renderer;
   ply_keyboard_t *keyboard;
   ply_list_t *text_displays;
   ply_list_t *pixel_displays;
-
-  uint32_t keyboard_active : 1;
 };
 
 ply_seat_t *
 ply_seat_new (ply_terminal_t *terminal)
 {
   ply_seat_t *seat;
 
   seat = calloc (1, sizeof (ply_seat_t));
 
   seat->loop = ply_event_loop_get_default ();
   seat->terminal = terminal;
   seat->text_displays = ply_list_new ();
   seat->pixel_displays = ply_list_new ();
 
   return seat;
 }
 
 static void
 add_pixel_displays (ply_seat_t *seat)
 {
   ply_list_t *heads;
   ply_list_node_t *node;
 
   heads = ply_renderer_get_heads (seat->renderer);
 
   ply_trace ("Adding displays for %d heads",
              ply_list_get_length (heads));
 
   node = ply_list_get_first_node (heads);
   while (node != NULL)
@@ -139,115 +137,104 @@ ply_seat_open (ply_seat_t          *seat,
         }
       else
         {
           seat->renderer = renderer;
         }
     }
 
   if (seat->renderer != NULL)
     {
       seat->keyboard = ply_keyboard_new_for_renderer (seat->renderer);
       add_pixel_displays (seat);
 
     }
   else if (seat->terminal != NULL)
     {
       seat->keyboard = ply_keyboard_new_for_terminal (seat->terminal);
     }
 
   if (seat->terminal != NULL)
     {
       add_text_displays (seat);
     }
   else
     {
       ply_trace ("not adding text display for seat, since seat has no associated terminal");
     }
 
   if (seat->keyboard != NULL)
     {
       ply_keyboard_watch_for_input (seat->keyboard);
-      seat->keyboard_active = true;
     }
   else
     {
       ply_trace ("not watching seat for input");
     }
 
   return true;
 }
 
 bool
 ply_seat_is_open (ply_seat_t *seat)
 {
   return ply_list_get_length (seat->pixel_displays) > 0 ||
          ply_list_get_length (seat->text_displays) > 0;
 }
 
 void
 ply_seat_deactivate_keyboard (ply_seat_t *seat)
 {
-  if (!seat->keyboard_active)
-    return;
-
-  seat->keyboard_active = false;
-
   if (seat->keyboard == NULL)
     return;
 
   ply_trace ("deactivating keybord");
   ply_keyboard_stop_watching_for_input (seat->keyboard);
 }
 
 void
 ply_seat_deactivate_renderer (ply_seat_t *seat)
 {
   if (seat->renderer == NULL)
     return;
 
   ply_trace ("deactivating renderer");
   ply_renderer_deactivate (seat->renderer);
 }
 
 void
 ply_seat_activate_keyboard (ply_seat_t *seat)
 {
-  if (seat->keyboard_active)
-    return;
-
   if (seat->keyboard == NULL)
     return;
 
   ply_trace ("activating keyboard");
   ply_keyboard_watch_for_input (seat->keyboard);
-
-  seat->keyboard_active = true;
 }
 
 void
 ply_seat_activate_renderer (ply_seat_t *seat)
 {
   if (seat->renderer == NULL)
     return;
 
   ply_trace ("activating renderer");
   ply_renderer_activate (seat->renderer);
 }
 
 void
 ply_seat_refresh_displays (ply_seat_t *seat)
 {
   ply_list_node_t *node;
 
   node = ply_list_get_first_node (seat->pixel_displays);
   while (node != NULL)
     {
       ply_pixel_display_t *display;
       ply_list_node_t *next_node;
       unsigned long width, height;
 
       display = ply_list_node_get_data (node);
       next_node = ply_list_get_next_node (seat->pixel_displays, node);
 
       width = ply_pixel_display_get_width (display);
       height = ply_pixel_display_get_height (display);
 
-- 
2.3.7


From 2e32a42370048eda7be2ad616dbdf1bbbe785129 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 22 Jul 2015 14:45:05 -0400
Subject: [PATCH 3/8] pixel-display: add getters for renderer data

These functions are useful for matching a pixel display
to its renderer.
---
 src/libply-splash-core/ply-pixel-display.c | 12 ++++++++++++
 src/libply-splash-core/ply-pixel-display.h |  2 ++
 2 files changed, 14 insertions(+)

diff --git a/src/libply-splash-core/ply-pixel-display.c b/src/libply-splash-core/ply-pixel-display.c
index 3715120..5c5ec69 100644
--- a/src/libply-splash-core/ply-pixel-display.c
+++ b/src/libply-splash-core/ply-pixel-display.c
@@ -55,60 +55,72 @@ struct _ply_pixel_display
   ply_pixel_display_draw_handler_t draw_handler;
   void *draw_handler_user_data;
 
   int pause_count;
 
 };
 
 ply_pixel_display_t *
 ply_pixel_display_new (ply_renderer_t      *renderer,
                        ply_renderer_head_t *head)
 {
   ply_pixel_display_t *display;
   ply_pixel_buffer_t  *pixel_buffer;
   ply_rectangle_t      size;
 
   display = calloc (1, sizeof (ply_pixel_display_t));
 
   display->loop = ply_event_loop_get_default ();
   display->renderer = renderer;
   display->head = head;
 
   pixel_buffer = ply_renderer_get_buffer_for_head (renderer, head);
   ply_pixel_buffer_get_size (pixel_buffer, &size);
 
   display->width = size.width;
   display->height = size.height;
 
   return display;
 }
 
+ply_renderer_t *
+ply_pixel_display_get_renderer (ply_pixel_display_t *display)
+{
+  return display->renderer;
+}
+
+ply_renderer_head_t *
+ply_pixel_display_get_renderer_head (ply_pixel_display_t *display)
+{
+  return display->head;
+}
+
 unsigned long
 ply_pixel_display_get_width (ply_pixel_display_t *display)
 {
   return display->width;
 }
 
 unsigned long
 ply_pixel_display_get_height (ply_pixel_display_t *display)
 {
   return display->height;
 }
 
 static void
 ply_pixel_display_flush (ply_pixel_display_t *display)
 {
   if (display->pause_count > 0)
     return;
 
   ply_renderer_flush_head (display->renderer, display->head);
 }
 
 void
 ply_pixel_display_pause_updates (ply_pixel_display_t *display)
 {
   assert (display != NULL);
 
   display->pause_count++;
 }
 
 void
diff --git a/src/libply-splash-core/ply-pixel-display.h b/src/libply-splash-core/ply-pixel-display.h
index 98a6b3c..92558e9 100644
--- a/src/libply-splash-core/ply-pixel-display.h
+++ b/src/libply-splash-core/ply-pixel-display.h
@@ -16,53 +16,55 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  * 02111-1307, USA.
  *
  * Written By: Ray Strode <rstrode@redhat.com>
  */
 #ifndef PLY_PIXEL_DISPLAY_H
 #define PLY_PIXEL_DISPLAY_H
 
 #include <stdbool.h>
 #include <stdint.h>
 #include <unistd.h>
 
 #include "ply-event-loop.h"
 #include "ply-pixel-buffer.h"
 #include "ply-renderer.h"
 
 typedef struct _ply_pixel_display ply_pixel_display_t;
 
 typedef void (* ply_pixel_display_draw_handler_t) (void               *user_data,
                                                    ply_pixel_buffer_t *pixel_buffer,
                                                    int                 x,
                                                    int                 y,
                                                    int                 width,
                                                    int                 height,
                                                    ply_pixel_display_t *pixel_display);
 
 #ifndef PLY_HIDE_FUNCTION_DECLARATIONS
 ply_pixel_display_t *ply_pixel_display_new (ply_renderer_t      *renderer,
                                             ply_renderer_head_t *head);
+ply_renderer_t      *ply_pixel_display_get_renderer (ply_pixel_display_t *display);
+ply_renderer_head_t *ply_pixel_display_get_renderer_head (ply_pixel_display_t *display);
 
 void ply_pixel_display_free (ply_pixel_display_t *display);
 
 unsigned long ply_pixel_display_get_width  (ply_pixel_display_t *display);
 unsigned long ply_pixel_display_get_height (ply_pixel_display_t *display);
 
 void ply_pixel_display_set_draw_handler (ply_pixel_display_t              *display,
                                          ply_pixel_display_draw_handler_t  draw_handler,
                                          void                             *user_data);
 
 void ply_pixel_display_draw_area (ply_pixel_display_t *display,
                                   int                  x,
                                   int                  y,
                                   int                  width,
                                   int                  height);
 
 void ply_pixel_display_pause_updates (ply_pixel_display_t *display);
 void ply_pixel_display_unpause_updates (ply_pixel_display_t *display);
 
 #endif
 
 #endif /* PLY_PIXEL_DISPLAY_H */
 /* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */
-- 
2.3.7


From d698a677b0007caded1dfb4652d8e8b9928e068b Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 23 Jul 2015 14:16:48 -0400
Subject: [PATCH 4/8] device-manager: drop seat abstraction

The seat abstraction isn't really right, since it forces creating a
link between terminal and video output device, which isn't really
necessary (and other reasons).

This commit drops the abstraction, and moves all the code that was
in ply-seat.c directly to ply-device-manager.c.
---
 src/libply-splash-core/Makefile.am          |   2 -
 src/libply-splash-core/ply-boot-splash.c    | 258 +++++++-------
 src/libply-splash-core/ply-boot-splash.h    |  17 +-
 src/libply-splash-core/ply-device-manager.c | 530 ++++++++++++++++------------
 src/libply-splash-core/ply-device-manager.h |  32 +-
 src/libply-splash-core/ply-seat.c           | 374 --------------------
 src/libply-splash-core/ply-seat.h           |  66 ----
 src/main.c                                  | 235 ++++++++----
 8 files changed, 615 insertions(+), 899 deletions(-)
 delete mode 100644 src/libply-splash-core/ply-seat.c
 delete mode 100644 src/libply-splash-core/ply-seat.h

diff --git a/src/libply-splash-core/Makefile.am b/src/libply-splash-core/Makefile.am
index d07d7f1..7036569 100644
--- a/src/libply-splash-core/Makefile.am
+++ b/src/libply-splash-core/Makefile.am
@@ -1,53 +1,51 @@
 AM_CPPFLAGS = -I$(top_srcdir)                                                 \
            -I$(srcdir)                                                        \
            -I$(srcdir)/../libply                                              \
            -I$(srcdir)/../plugins/controls
 
 if WITH_SYSTEM_ROOT_INSTALL
 librarydir = $(libdir:/usr%=%)
 else
 librarydir = $(libdir)
 endif
 
 library_LTLIBRARIES = libply-splash-core.la
 
 libply_splash_coredir = $(includedir)/plymouth-1/ply-splash-core
 libply_splash_core_HEADERS = \
 		    ply-boot-splash.h                                         \
 		    ply-boot-splash-plugin.h                                  \
 		    ply-device-manager.h                                      \
 		    ply-keyboard.h                                            \
 		    ply-pixel-buffer.h                                        \
 		    ply-pixel-display.h                                       \
 		    ply-renderer.h                                            \
 		    ply-renderer-plugin.h                                     \
-		    ply-seat.h                                                \
 		    ply-terminal.h                                            \
 		    ply-text-display.h                                        \
 		    ply-text-progress-bar.h                                   \
 		    ply-text-step-bar.h
 
 libply_splash_core_la_CFLAGS = $(PLYMOUTH_CFLAGS) $(UDEV_CFLAGS)               \
                              -DPLYMOUTH_BACKGROUND_COLOR=$(background_color)   \
                        -DPLYMOUTH_BACKGROUND_END_COLOR=$(background_end_color) \
                        -DPLYMOUTH_BACKGROUND_START_COLOR=$(background_start_color) \
                        -DPLYMOUTH_PLUGIN_PATH=\"$(PLYMOUTH_PLUGIN_PATH)\"
 libply_splash_core_la_LIBADD = $(PLYMOUTH_LIBS) $(UDEV_LIBS) ../libply/libply.la
 libply_splash_core_la_LDFLAGS = -export-symbols-regex '^[^_].*' \
 		    -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
 		    -no-undefined
 libply_splash_core_la_SOURCES = \
 		    $(libply_splash_core_HEADERS)                              \
 		    ply-device-manager.c                                      \
 		    ply-keyboard.c                                           \
 		    ply-pixel-display.c                                      \
 		    ply-text-display.c                                       \
 		    ply-text-progress-bar.c                                  \
 		    ply-text-step-bar.c                                      \
 		    ply-terminal.c                                           \
 		    ply-pixel-buffer.c                                       \
 		    ply-renderer.c                                           \
-		    ply-seat.c                                               \
 		    ply-boot-splash.c
 
 MAINTAINERCLEANFILES = Makefile.in
diff --git a/src/libply-splash-core/ply-boot-splash.c b/src/libply-splash-core/ply-boot-splash.c
index 160ce45..f7fc70f 100644
--- a/src/libply-splash-core/ply-boot-splash.c
+++ b/src/libply-splash-core/ply-boot-splash.c
@@ -30,259 +30,196 @@
 #include <stdlib.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <wchar.h>
 
 #include "ply-boot-splash-plugin.h"
 #include "ply-terminal.h"
 #include "ply-event-loop.h"
 #include "ply-list.h"
 #include "ply-logger.h"
 #include "ply-trigger.h"
 #include "ply-utils.h"
 #include "ply-progress.h"
 #include "ply-keyboard.h"
 #include "ply-key-file.h"
 
 #ifndef UPDATES_PER_SECOND
 #define UPDATES_PER_SECOND 30
 #endif
 
 struct _ply_boot_splash
 {
   ply_event_loop_t *loop;
   ply_module_handle_t *module_handle;
   const ply_boot_splash_plugin_interface_t *plugin_interface;
   ply_boot_splash_plugin_t *plugin;
   ply_boot_splash_mode_t mode;
   ply_buffer_t *boot_buffer;
   ply_trigger_t *idle_trigger;
-  ply_list_t *seats;
+
+  ply_keyboard_t *keyboard;
+  ply_list_t     *pixel_displays;
+  ply_list_t     *text_displays;
 
   char *theme_path;
   char *plugin_dir;
   char *status;
 
   ply_progress_t *progress;
   ply_boot_splash_on_idle_handler_t idle_handler;
   void *idle_handler_user_data;
 
   uint32_t is_loaded : 1;
   uint32_t should_force_text_mode : 1;
 };
 
 typedef const ply_boot_splash_plugin_interface_t *
         (* get_plugin_interface_function_t) (void);
 
 static void ply_boot_splash_update_progress (ply_boot_splash_t *splash);
 static void ply_boot_splash_detach_from_event_loop (ply_boot_splash_t *splash);
 
 ply_boot_splash_t *
 ply_boot_splash_new (const char     *theme_path,
                      const char     *plugin_dir,
                      ply_buffer_t   *boot_buffer)
 {
   ply_boot_splash_t *splash;
 
   assert (theme_path != NULL);
 
   splash = calloc (1, sizeof (ply_boot_splash_t));
   splash->loop = NULL;
   splash->theme_path = strdup (theme_path);
   splash->plugin_dir = strdup (plugin_dir);
   splash->module_handle = NULL;
   splash->mode = PLY_BOOT_SPLASH_MODE_INVALID;
 
   splash->boot_buffer = boot_buffer;
-  splash->seats = ply_list_new ();
+  splash->pixel_displays = ply_list_new ();
+  splash->text_displays = ply_list_new ();
 
   return splash;
 }
 
-static void
-detach_from_seat (ply_boot_splash_t *splash,
-                  ply_seat_t        *seat)
+void
+ply_boot_splash_set_keyboard (ply_boot_splash_t *splash,
+                              ply_keyboard_t    *keyboard)
 {
-  ply_keyboard_t *keyboard;
-  ply_list_t *displays;
-  ply_list_node_t *node, *next_node;
-
-  ply_trace ("removing keyboard");
-  if (splash->plugin_interface->unset_keyboard != NULL)
-    {
-      keyboard = ply_seat_get_keyboard (seat);
-      splash->plugin_interface->unset_keyboard (splash->plugin, keyboard);
-    }
-
-  ply_trace ("removing pixel displays");
-  displays = ply_seat_get_pixel_displays (seat);
-
-  node = ply_list_get_first_node (displays);
-  while (node != NULL)
-    {
-      ply_pixel_display_t *display;
-      ply_list_node_t *next_node;
-      unsigned long width, height;
-
-      display = ply_list_node_get_data (node);
-      next_node = ply_list_get_next_node (displays, node);
-
-      width = ply_pixel_display_get_width (display);
-      height = ply_pixel_display_get_height (display);
-
-      ply_trace ("Removing %lux%lu pixel display", width, height);
-
-      if (splash->plugin_interface->remove_pixel_display != NULL)
-        splash->plugin_interface->remove_pixel_display (splash->plugin, display);
-
-      node = next_node;
-    }
-
-  ply_trace ("removing text displays");
-  displays = ply_seat_get_text_displays (seat);
-
-  node = ply_list_get_first_node (displays);
-  while (node != NULL)
-    {
-      ply_text_display_t *display;
-      int number_of_columns, number_of_rows;
-
-      display = ply_list_node_get_data (node);
-      next_node = ply_list_get_next_node (displays, node);
-
-      number_of_columns = ply_text_display_get_number_of_columns (display);
-      number_of_rows = ply_text_display_get_number_of_rows (display);
-
-      ply_trace ("Removing %dx%d text display", number_of_columns, number_of_rows);
-
-      if (splash->plugin_interface->remove_text_display != NULL)
-        splash->plugin_interface->remove_text_display (splash->plugin, display);
+  if (splash->plugin_interface->set_keyboard == NULL)
+    return;
 
-      node = next_node;
-    }
+  splash->plugin_interface->set_keyboard (splash->plugin, keyboard);
+  splash->keyboard = keyboard;
 }
 
-static void
-attach_to_seat (ply_boot_splash_t *splash,
-                ply_seat_t        *seat)
+void
+ply_boot_splash_unset_keyboard (ply_boot_splash_t *splash)
 {
-  ply_keyboard_t *keyboard;
-  ply_list_t *displays;
-  ply_list_node_t *node, *next_node;
-
-  if (splash->plugin_interface->set_keyboard != NULL)
-    {
-      keyboard = ply_seat_get_keyboard (seat);
-      splash->plugin_interface->set_keyboard (splash->plugin, keyboard);
-    }
-
-  if (splash->plugin_interface->add_pixel_display != NULL)
-    {
-      displays = ply_seat_get_pixel_displays (seat);
-
-      ply_trace ("adding pixel displays");
-      node = ply_list_get_first_node (displays);
-      while (node != NULL)
-        {
-          ply_pixel_display_t *display;
-          ply_list_node_t *next_node;
-          unsigned long width, height;
-
-          display = ply_list_node_get_data (node);
-          next_node = ply_list_get_next_node (displays, node);
+  if (splash->plugin_interface->unset_keyboard == NULL)
+    return;
 
-          width = ply_pixel_display_get_width (display);
-          height = ply_pixel_display_get_height (display);
+  splash->plugin_interface->unset_keyboard (splash->plugin, splash->keyboard);
+}
 
-          ply_trace ("Adding %lux%lu pixel display", width, height);
+void
+ply_boot_splash_add_pixel_display (ply_boot_splash_t   *splash,
+                                   ply_pixel_display_t *display)
+{
+  unsigned long width, height;
 
-          splash->plugin_interface->add_pixel_display (splash->plugin, display);
+  if (splash->plugin_interface->add_pixel_display == NULL)
+    return;
 
-          node = next_node;
-        }
-    }
+  width = ply_pixel_display_get_width (display);
+  height = ply_pixel_display_get_height (display);
 
-  if (splash->plugin_interface->add_text_display != NULL)
-    {
-      displays = ply_seat_get_text_displays (seat);
+  ply_trace ("Adding %lux%lu pixel display", width, height);
 
-      ply_trace ("adding text displays");
-      node = ply_list_get_first_node (displays);
-      while (node != NULL)
-        {
-          ply_text_display_t *display;
-          int number_of_columns, number_of_rows;
+  splash->plugin_interface->add_pixel_display (splash->plugin, display);
+  ply_list_append_data (splash->pixel_displays, display);
+}
 
-          display = ply_list_node_get_data (node);
-          next_node = ply_list_get_next_node (displays, node);
+void
+ply_boot_splash_remove_pixel_display (ply_boot_splash_t   *splash,
+                                      ply_pixel_display_t *display)
+{
+  unsigned long width, height;
 
-          number_of_columns = ply_text_display_get_number_of_columns (display);
-          number_of_rows = ply_text_display_get_number_of_rows (display);
+  if (splash->plugin_interface->remove_pixel_display == NULL)
+    return;
 
-          ply_trace ("Adding %dx%d text display", number_of_columns, number_of_rows);
+  width = ply_pixel_display_get_width (display);
+  height = ply_pixel_display_get_height (display);
 
-          splash->plugin_interface->add_text_display (splash->plugin, display);
+  ply_trace ("Removing %lux%lu pixel display", width, height);
 
-          node = next_node;
-        }
-    }
+  splash->plugin_interface->remove_pixel_display (splash->plugin, display);
+  ply_list_remove_data (splash->pixel_displays, display);
 }
 
 void
-ply_boot_splash_attach_to_seat (ply_boot_splash_t *splash,
-                                ply_seat_t        *seat)
+ply_boot_splash_add_text_display (ply_boot_splash_t   *splash,
+                                  ply_text_display_t  *display)
 {
-  ply_list_node_t *node;
-
-  node = ply_list_find_node (splash->seats, seat);
+  int number_of_columns, number_of_rows;
 
-  if (node != NULL)
+  if (splash->plugin_interface->add_text_display == NULL)
     return;
 
-  ply_list_append_data (splash->seats, seat);
-  attach_to_seat (splash, seat);
+  number_of_columns = ply_text_display_get_number_of_columns (display);
+  number_of_rows = ply_text_display_get_number_of_rows (display);
+
+  ply_trace ("Adding %dx%d text display", number_of_columns, number_of_rows);
+
+  splash->plugin_interface->add_text_display (splash->plugin, display);
+  ply_list_append_data (splash->text_displays, display);
 }
 
 void
-ply_boot_splash_detach_from_seat (ply_boot_splash_t *splash,
-                                  ply_seat_t        *seat)
+ply_boot_splash_remove_text_display (ply_boot_splash_t  *splash,
+                                     ply_text_display_t *display)
 {
-  ply_list_node_t *node;
+  int number_of_columns, number_of_rows;
 
-  node = ply_list_find_node (splash->seats, seat);
-
-  if (node == NULL)
+  if (splash->plugin_interface->remove_text_display == NULL)
     return;
 
-  ply_list_remove_data (splash->seats, seat);
-  detach_from_seat (splash, seat);
+  number_of_columns = ply_text_display_get_number_of_columns (display);
+  number_of_rows = ply_text_display_get_number_of_rows (display);
+
+  ply_trace ("Removing %dx%d text display", number_of_columns, number_of_rows);
+
+  splash->plugin_interface->remove_text_display (splash->plugin, display);
+  ply_list_remove_data (splash->text_displays, display);
 }
 
 bool
 ply_boot_splash_load (ply_boot_splash_t *splash)
 {
   ply_key_file_t *key_file;
   char *module_name;
   char *module_path;
 
   assert (splash != NULL);
 
   get_plugin_interface_function_t get_boot_splash_plugin_interface;
 
   key_file = ply_key_file_new (splash->theme_path);
 
   if (!ply_key_file_load (key_file))
     return false;
 
   module_name = ply_key_file_get_value (key_file, "Plymouth Theme", "ModuleName");
 
   asprintf (&module_path, "%s%s.so",
             splash->plugin_dir, module_name);
   free (module_name);
 
   splash->module_handle = ply_open_module (module_path);
 
   free (module_path);
 
   if (splash->module_handle == NULL)
     {
@@ -364,106 +301,149 @@ ply_boot_splash_load_built_in (ply_boot_splash_t *splash)
     }
 
   splash->plugin = splash->plugin_interface->create_plugin (NULL);
 
   assert (splash->plugin != NULL);
 
   splash->is_loaded = true;
 
   return true;
 }
 
 void
 ply_boot_splash_unload (ply_boot_splash_t *splash)
 {
   assert (splash != NULL);
   assert (splash->plugin != NULL);
   assert (splash->plugin_interface != NULL);
   assert (splash->module_handle != NULL);
 
   splash->plugin_interface->destroy_plugin (splash->plugin);
   splash->plugin = NULL;
 
   ply_close_module (splash->module_handle);
   splash->plugin_interface = NULL;
   splash->module_handle = NULL;
 
   splash->is_loaded = false;
 }
 
 static void
-detach_from_seats (ply_boot_splash_t *splash)
+remove_pixel_displays (ply_boot_splash_t *splash)
+{
+  ply_list_node_t *node;
+
+  if (splash->plugin_interface->remove_pixel_display == NULL)
+    return;
+
+  ply_trace ("removing pixel displays");
+
+  node = ply_list_get_first_node (splash->pixel_displays);
+  while (node != NULL)
+    {
+      ply_pixel_display_t *display;
+      ply_list_node_t *next_node;
+      unsigned long width, height;
+
+      display = ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (splash->pixel_displays, node);
+
+      width = ply_pixel_display_get_width (display);
+      height = ply_pixel_display_get_height (display);
+
+      ply_trace ("Removing %lux%lu pixel display", width, height);
+
+      splash->plugin_interface->remove_pixel_display (splash->plugin, display);
+
+      node = next_node;
+    }
+}
+
+static void
+remove_text_displays (ply_boot_splash_t *splash)
 {
   ply_list_node_t *node;
 
-  ply_trace ("detaching from seats");
+  if (splash->plugin_interface->remove_text_display == NULL)
+    return;
 
-  node = ply_list_get_first_node (splash->seats);
+  ply_trace ("removing text displays");
+
+  node = ply_list_get_first_node (splash->text_displays);
   while (node != NULL)
     {
-      ply_seat_t *seat;
+      ply_text_display_t *display;
       ply_list_node_t *next_node;
+      int number_of_columns, number_of_rows;
 
-      seat = ply_list_node_get_data (node);
-      next_node = ply_list_get_next_node (splash->seats, node);
+      display = ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (splash->text_displays, node);
 
-      detach_from_seat (splash, seat);
+      number_of_columns = ply_text_display_get_number_of_columns (display);
+      number_of_rows = ply_text_display_get_number_of_rows (display);
 
-      ply_list_remove_node (splash->seats, node);
+      ply_trace ("Removing %dx%d text display", number_of_columns, number_of_rows);
+
+      splash->plugin_interface->remove_text_display (splash->plugin, display);
 
       node = next_node;
     }
 }
 
 void
 ply_boot_splash_free (ply_boot_splash_t *splash)
 {
   ply_trace ("freeing splash");
   if (splash == NULL)
     return;
 
   if (splash->loop != NULL)
     {
       if (splash->plugin_interface->on_boot_progress != NULL)
         {
           ply_event_loop_stop_watching_for_timeout (splash->loop,
                                                     (ply_event_loop_timeout_handler_t)
                                                     ply_boot_splash_update_progress, splash);
         }
 
       ply_event_loop_stop_watching_for_exit (splash->loop, (ply_event_loop_exit_handler_t)
                                              ply_boot_splash_detach_from_event_loop,
                                              splash);
     }
 
-  detach_from_seats (splash);
-  ply_list_free (splash->seats);
+  ply_boot_splash_unset_keyboard (splash);
+
+  remove_pixel_displays (splash);
+  ply_list_free (splash->pixel_displays);
+
+  remove_text_displays (splash);
+  ply_list_free (splash->text_displays);
 
   if (splash->module_handle != NULL)
     ply_boot_splash_unload (splash);
 
   if (splash->idle_trigger != NULL)
     ply_trigger_free (splash->idle_trigger);
 
   free (splash->theme_path);
   free (splash->plugin_dir);
   free (splash);
 }
 
 static void
 ply_boot_splash_update_progress (ply_boot_splash_t *splash)
 {
   double percentage=0.0;
   double time=0.0;
 
   assert (splash != NULL);
 
   if (splash->progress)
     {
       percentage = ply_progress_get_percentage(splash->progress);
       time = ply_progress_get_time(splash->progress);
     }
 
   if (splash->plugin_interface->on_boot_progress != NULL)
     splash->plugin_interface->on_boot_progress (splash->plugin,
                                                 time,
                                                 percentage);
diff --git a/src/libply-splash-core/ply-boot-splash.h b/src/libply-splash-core/ply-boot-splash.h
index 335039b..8937c1f 100644
--- a/src/libply-splash-core/ply-boot-splash.h
+++ b/src/libply-splash-core/ply-boot-splash.h
@@ -6,81 +6,86 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2, or (at your option)
  * any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  * 02111-1307, USA.
  *
  * Written By: Ray Strode <rstrode@redhat.com>
  */
 #ifndef PLY_BOOT_SPLASH_H
 #define PLY_BOOT_SPLASH_H
 
 #include <stdbool.h>
 #include <stdint.h>
 #include <unistd.h>
 
 #include "ply-event-loop.h"
 #include "ply-buffer.h"
 #include "ply-terminal.h"
 #include "ply-keyboard.h"
 #include "ply-pixel-display.h"
 #include "ply-text-display.h"
 #include "ply-progress.h"
-#include "ply-seat.h"
 
 #include "ply-boot-splash-plugin.h"
 
 typedef struct _ply_boot_splash ply_boot_splash_t;
-typedef struct _ply_seat ply_seat_t;
 
 typedef void (* ply_boot_splash_on_idle_handler_t) (void *user_data);
 
 #ifndef PLY_HIDE_FUNCTION_DECLARATIONS
 ply_boot_splash_t *ply_boot_splash_new (const char   *  theme_path,
                                         const char   *  plugin_dir,
                                         ply_buffer_t *  boot_buffer);
 
 bool ply_boot_splash_load (ply_boot_splash_t *splash);
 bool ply_boot_splash_load_built_in (ply_boot_splash_t *splash);
 void ply_boot_splash_unload (ply_boot_splash_t *splash);
-void ply_boot_splash_attach_to_seat (ply_boot_splash_t *splash,
-                                     ply_seat_t        *seat);
-void ply_boot_splash_detach_from_seat (ply_boot_splash_t *splash,
-                                       ply_seat_t        *seat);
+void ply_boot_splash_set_keyboard (ply_boot_splash_t *splash,
+                                   ply_keyboard_t    *keyboard);
+void ply_boot_splash_unset_keyboard (ply_boot_splash_t *splash);
+void ply_boot_splash_add_pixel_display (ply_boot_splash_t   *splash,
+                                        ply_pixel_display_t *pixel_display);
+void ply_boot_splash_remove_pixel_display (ply_boot_splash_t  *splash,
+                                          ply_pixel_display_t *pixel_display);
+void ply_boot_splash_add_text_display (ply_boot_splash_t   *splash,
+                                       ply_text_display_t  *text_display);
+void ply_boot_splash_remove_text_display (ply_boot_splash_t  *splash,
+                                          ply_text_display_t *text_display);
 void ply_boot_splash_free (ply_boot_splash_t *splash);
 bool ply_boot_splash_show (ply_boot_splash_t *splash,
                            ply_boot_splash_mode_t mode);
 bool ply_boot_splash_system_update (ply_boot_splash_t *splash,
                                     int                progress);
 void ply_boot_splash_update_status (ply_boot_splash_t *splash,
                                     const char        *status);
 void ply_boot_splash_update_output (ply_boot_splash_t *splash,
                                     const char        *output,
                                     size_t             size);
 void ply_boot_splash_root_mounted (ply_boot_splash_t *splash);
 void ply_boot_splash_display_message (ply_boot_splash_t *splash,
                                       const char        *message);
 void ply_boot_splash_hide_message (ply_boot_splash_t *splash,
                                    const char        *message);
 void ply_boot_splash_hide (ply_boot_splash_t *splash);
 void ply_boot_splash_display_normal  (ply_boot_splash_t *splash);
 void ply_boot_splash_display_password (ply_boot_splash_t *splash,
                                        const char        *prompt,
                                        int                bullets);
 void ply_boot_splash_display_question (ply_boot_splash_t *splash,
                                        const char        *prompt,
                                        const char        *entry_text);
 void ply_boot_splash_attach_to_event_loop (ply_boot_splash_t *splash,
                                            ply_event_loop_t  *loop);
 void ply_boot_splash_attach_progress (ply_boot_splash_t *splash,
                                       ply_progress_t    *progress);
 void ply_boot_splash_become_idle (ply_boot_splash_t                 *splash,
                                   ply_boot_splash_on_idle_handler_t  idle_handler,
                                   void                              *user_data);
diff --git a/src/libply-splash-core/ply-device-manager.c b/src/libply-splash-core/ply-device-manager.c
index 5766bcb..c7568c1 100644
--- a/src/libply-splash-core/ply-device-manager.c
+++ b/src/libply-splash-core/ply-device-manager.c
@@ -14,597 +14,580 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  * 02111-1307, USA.
  */
 #include "config.h"
 #include "ply-device-manager.h"
 
 #include <assert.h>
 #include <fcntl.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/inotify.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
 #include <libudev.h>
 
 #include "ply-logger.h"
 #include "ply-event-loop.h"
 #include "ply-hashtable.h"
 #include "ply-list.h"
 #include "ply-utils.h"
 
 #define SUBSYSTEM_DRM "drm"
 #define SUBSYSTEM_FRAME_BUFFER "graphics"
 
-static void create_seat_for_terminal_and_renderer_type (ply_device_manager_t *manager,
-                                                        const char           *device_path,
-                                                        ply_terminal_t       *terminal,
-                                                        ply_renderer_type_t   renderer_type);
+static void create_devices_for_terminal_and_renderer_type (ply_device_manager_t *manager,
+                                                           const char           *device_path,
+                                                           ply_terminal_t       *terminal,
+                                                           ply_renderer_type_t   renderer_type);
 struct _ply_device_manager
 {
   ply_device_manager_flags_t  flags;
   ply_event_loop_t           *loop;
   ply_hashtable_t            *terminals;
+  ply_hashtable_t            *renderers;
   ply_terminal_t             *local_console_terminal;
-  ply_seat_t                 *local_console_seat;
-  ply_list_t                 *seats;
+  ply_list_t                 *keyboards;
+  ply_list_t                 *text_displays;
+  ply_list_t                 *pixel_displays;
   struct udev                *udev_context;
   struct udev_queue          *udev_queue;
   int                         udev_queue_fd;
   ply_fd_watch_t             *udev_queue_fd_watch;
   struct udev_monitor        *udev_monitor;
 
-  ply_seat_added_handler_t    seat_added_handler;
-  ply_seat_removed_handler_t  seat_removed_handler;
-  void                       *seat_event_handler_data;
+  ply_keyboard_added_handler_t         keyboard_added_handler;
+  ply_keyboard_removed_handler_t       keyboard_removed_handler;
+  ply_pixel_display_added_handler_t    pixel_display_added_handler;
+  ply_pixel_display_removed_handler_t  pixel_display_removed_handler;
+  ply_text_display_added_handler_t     text_display_added_handler;
+  ply_text_display_removed_handler_t   text_display_removed_handler;
+  void                                *event_handler_data;
+
+  uint32_t                    local_console_managed : 1;
+  uint32_t                    local_console_is_text : 1;
 };
 
 static void
 detach_from_event_loop (ply_device_manager_t *manager)
 {
   assert (manager != NULL);
 
   manager->loop = NULL;
 }
 
 static void
 attach_to_event_loop (ply_device_manager_t *manager,
                       ply_event_loop_t     *loop)
 {
   assert (manager != NULL);
   assert (loop != NULL);
   assert (manager->loop == NULL);
 
   manager->loop = loop;
 
   ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t)
                                  detach_from_event_loop,
                                  manager);
 }
 
 static bool
 device_is_for_local_console (ply_device_manager_t *manager,
                              struct udev_device   *device)
 {
   const char *device_path;
   struct udev_device *bus_device;
   char *bus_device_path;
   const char *boot_vga;
   bool for_local_console;
 
   /* Look at the associated bus device to see if this card is the
    * card the kernel is using for its console. */
   device_path = udev_device_get_syspath (device);
   asprintf (&bus_device_path, "%s/device", device_path);
   bus_device = udev_device_new_from_syspath (manager->udev_context, bus_device_path);
 
   boot_vga = udev_device_get_sysattr_value (bus_device, "boot_vga");
   free (bus_device_path);
 
   if (boot_vga != NULL && strcmp (boot_vga, "1") == 0)
     for_local_console = true;
   else
     for_local_console = false;
 
   return for_local_console;
 }
 
 static bool
 drm_device_in_use (ply_device_manager_t *manager,
                    const char           *device_path)
 {
-  ply_list_node_t *node;
-
-  node = ply_list_get_first_node (manager->seats);
-  while (node != NULL)
-    {
-      ply_seat_t *seat;
-      ply_renderer_t *renderer;
-      ply_list_node_t *next_node;
-      const char *renderer_device_path;
+  ply_renderer_t *renderer;
 
-      seat = ply_list_node_get_data (node);
-      next_node = ply_list_get_next_node (manager->seats, node);
-      renderer = ply_seat_get_renderer (seat);
+  renderer = ply_hashtable_lookup (manager->renderers, (void *) device_path);
 
-      if (renderer != NULL)
-        {
-          renderer_device_path = ply_renderer_get_device_name (renderer);
-
-          if (renderer_device_path != NULL)
-            {
-              if (strcmp (device_path, renderer_device_path) == 0)
-                {
-                  return true;
-                }
-            }
-        }
-
-      node = next_node;
-    }
-
-  return false;
+  return renderer != NULL;
 }
 
 static bool
 fb_device_has_drm_device (ply_device_manager_t *manager,
                           struct udev_device   *fb_device)
 {
   struct udev_enumerate *card_matches;
   struct udev_list_entry *card_entry;
   const char *id_path;
   bool has_drm_device = false;
 
   /* We want to see if the framebuffer is associated with a DRM-capable
    * graphics card, if it is, we'll use the DRM device */
   card_matches = udev_enumerate_new (manager->udev_context);
   udev_enumerate_add_match_is_initialized(card_matches);
   udev_enumerate_add_match_parent (card_matches, udev_device_get_parent (fb_device));
   udev_enumerate_add_match_subsystem (card_matches, "drm");
   id_path = udev_device_get_property_value (fb_device, "ID_PATH");
   udev_enumerate_add_match_property (card_matches, "ID_PATH", id_path);
 
   ply_trace ("trying to find associated drm node for fb device (path: %s)", id_path);
 
   udev_enumerate_scan_devices (card_matches);
 
   /* there should only ever be at most one match so we don't iterate through
    * the list, but just look at the first entry */
   card_entry = udev_enumerate_get_list_entry (card_matches);
 
   if (card_entry != NULL)
     {
       struct udev_device *card_device = NULL;
       const char *card_node;
       const char *card_path;
 
       card_path = udev_list_entry_get_name (card_entry);
       card_device = udev_device_new_from_syspath (manager->udev_context, card_path);
       card_node = udev_device_get_devnode (card_device);
       if (card_node != NULL && drm_device_in_use (manager, card_node))
         has_drm_device = true;
       else
         ply_trace ("no card node!");
 
       udev_device_unref (card_device);
     }
   else
     {
       ply_trace ("no card entry!");
     }
 
   udev_enumerate_unref (card_matches);
   return has_drm_device;
 }
 
 static void
-create_seat_for_udev_device (ply_device_manager_t *manager,
-                             struct udev_device   *device)
+create_devices_for_udev_device (ply_device_manager_t *manager,
+                                struct udev_device   *device)
 {
   bool for_local_console;
   const char *device_path;
   ply_terminal_t *terminal = NULL;
 
   for_local_console = device_is_for_local_console (manager, device);
 
   ply_trace ("device is for local console: %s", for_local_console? "yes" : "no");
 
   if (for_local_console)
     terminal = manager->local_console_terminal;
 
   device_path = udev_device_get_devnode (device);
 
   if (device_path != NULL)
     {
       const char *subsystem;
       ply_renderer_type_t renderer_type = PLY_RENDERER_TYPE_NONE;
 
       subsystem = udev_device_get_subsystem (device);
       ply_trace ("device subsystem is %s", subsystem);
 
       if (subsystem != NULL && strcmp (subsystem, SUBSYSTEM_DRM) == 0)
         {
           ply_trace ("found DRM device %s", device_path);
           renderer_type = PLY_RENDERER_TYPE_DRM;
         }
       else if (strcmp (subsystem, SUBSYSTEM_FRAME_BUFFER) == 0)
         {
           ply_trace ("found frame buffer device %s", device_path);
           if (!fb_device_has_drm_device (manager, device))
             {
               renderer_type = PLY_RENDERER_TYPE_FRAME_BUFFER;
             }
           else
             {
               ply_trace ("ignoring, since there's a DRM device associated with it");
             }
         }
 
       if (renderer_type != PLY_RENDERER_TYPE_NONE)
-        create_seat_for_terminal_and_renderer_type (manager,
-                                                    device_path,
-                                                    terminal,
-                                                    renderer_type);
+        create_devices_for_terminal_and_renderer_type (manager,
+                                                       device_path,
+                                                       terminal,
+                                                       renderer_type);
     }
 }
 
 static void
-free_seat_from_device_path (ply_device_manager_t *manager,
-                            const char           *device_path)
+free_displays_for_renderer (ply_device_manager_t *manager,
+                            ply_renderer_t       *renderer)
 {
   ply_list_node_t *node;
 
-  node = ply_list_get_first_node (manager->seats);
+  node = ply_list_get_first_node (manager->pixel_displays);
   while (node != NULL)
     {
-      ply_seat_t *seat;
-      ply_renderer_t *renderer;
       ply_list_node_t *next_node;
-      const char *renderer_device_path;
+      ply_pixel_display_t *display;
+      ply_renderer_t *display_renderer;
 
-      seat = ply_list_node_get_data (node);
-      next_node = ply_list_get_next_node (manager->seats, node);
-      renderer = ply_seat_get_renderer (seat);
+      display = ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (manager->pixel_displays, node);
+      display_renderer = ply_pixel_display_get_renderer (display);
 
-      if (renderer != NULL)
+      if (display_renderer == renderer)
         {
-          renderer_device_path = ply_renderer_get_device_name (renderer);
+          if (manager->pixel_display_removed_handler != NULL)
+            manager->pixel_display_removed_handler (manager->event_handler_data, display);
 
-          if (renderer_device_path != NULL)
-            {
-              if (strcmp (device_path, renderer_device_path) == 0)
-                {
-                  ply_trace ("removing seat associated with %s", device_path);
-
-                  if (manager->seat_removed_handler != NULL)
-                    manager->seat_removed_handler (manager->seat_event_handler_data, seat);
-
-                  ply_seat_free (seat);
-                  ply_list_remove_node (manager->seats, node);
-                  break;
-                }
-            }
+          ply_pixel_display_free (display);
+          ply_list_remove_node (manager->pixel_displays, node);
         }
 
       node = next_node;
     }
 }
 
 static void
-free_seat_for_udev_device (ply_device_manager_t *manager,
-                           struct udev_device   *device)
+free_devices_from_device_path (ply_device_manager_t *manager,
+                               const char           *device_path)
+{
+  char *key = NULL;
+  ply_renderer_t *renderer = NULL;
+
+  ply_hashtable_lookup_full (manager->renderers,
+                             (void *) device_path,
+                             (void **) &key,
+                             (void **) &renderer);
+
+  if (renderer == NULL)
+    return;
+
+  free_displays_for_renderer (manager, renderer);
+
+  ply_hashtable_remove (manager->renderers, (void *) device_path);
+  free (key);
+  ply_renderer_free (renderer);
+}
+
+static void
+free_devices_for_udev_device (ply_device_manager_t *manager,
+                              struct udev_device   *device)
 {
   const char *device_path;
 
   device_path = udev_device_get_devnode (device);
 
   if (device_path != NULL)
-    free_seat_from_device_path (manager, device_path);
+    free_devices_from_device_path (manager, device_path);
 }
 
 static bool
-create_seats_for_subsystem (ply_device_manager_t *manager,
-                            const char           *subsystem)
+create_devices_for_subsystem (ply_device_manager_t *manager,
+                               const char           *subsystem)
 {
   struct udev_enumerate *matches;
   struct udev_list_entry *entry;
   bool found_device = false;
 
-  ply_trace ("creating seats for %s devices",
+  ply_trace ("creating devices for %s devices",
              strcmp (subsystem, SUBSYSTEM_FRAME_BUFFER) == 0?
              "frame buffer":
              subsystem);
 
   matches = udev_enumerate_new (manager->udev_context);
   udev_enumerate_add_match_subsystem (matches, subsystem);
   udev_enumerate_scan_devices (matches);
 
   udev_list_entry_foreach (entry, udev_enumerate_get_list_entry (matches))
     {
       struct udev_device *device = NULL;
       const char *path;
 
       path = udev_list_entry_get_name (entry);
 
       if (path == NULL)
         {
           ply_trace ("path was null!");
           continue;
         }
 
       ply_trace ("found device %s", path);
 
       device = udev_device_new_from_syspath (manager->udev_context, path);
 
       /* if device isn't fully initialized, we'll get an add event later
        */
       if (udev_device_get_is_initialized (device))
         {
           ply_trace ("device is initialized");
 
           /* We only care about devices assigned to a (any) seat. Floating
            * devices should be ignored.
            */
           if (udev_device_has_tag (device, "seat"))
             {
               const char *node;
               node = udev_device_get_devnode (device);
               if (node != NULL)
                 {
                   ply_trace ("found node %s", node);
                   found_device = true;
-                  create_seat_for_udev_device (manager, device);
+                  create_devices_for_udev_device (manager, device);
                 }
             }
           else
             {
               ply_trace ("device doesn't have a seat tag");
             }
         }
       else
         {
           ply_trace ("it's not initialized");
         }
 
       udev_device_unref (device);
     }
 
   udev_enumerate_unref (matches);
 
   return found_device;
 }
 
 static void
 on_udev_event (ply_device_manager_t *manager)
 {
   struct udev_device *device;
   const char *action;
 
   device = udev_monitor_receive_device (manager->udev_monitor);
   if (device == NULL)
     return;
 
   action = udev_device_get_action (device);
 
   ply_trace ("got %s event for device %s", action, udev_device_get_sysname (device));
 
   if (action == NULL)
     return;
 
   if (strcmp (action, "add") == 0)
     {
       const char *subsystem;
       bool coldplug_complete = manager->udev_queue_fd_watch == NULL;
 
       subsystem = udev_device_get_subsystem (device);
 
       if (strcmp (subsystem, SUBSYSTEM_DRM) == 0 ||
           coldplug_complete)
         {
-          ply_list_t *local_pixel_displays = NULL;
-
-          if (manager->local_console_seat != NULL)
-            local_pixel_displays = ply_seat_get_pixel_displays (manager->local_console_seat);
-
-          if (coldplug_complete && manager->local_console_seat != NULL && local_pixel_displays == NULL)
+          if (coldplug_complete && manager->local_console_managed && manager->local_console_is_text)
             ply_trace ("ignoring since we're already using text splash for local console");
           else
-            create_seat_for_udev_device (manager, device);
+            create_devices_for_udev_device (manager, device);
         }
       else
         {
           ply_trace ("ignoring since we only handle subsystem %s devices after coldplug completes", subsystem);
         }
     }
   else if (strcmp (action, "remove") == 0)
     {
-      free_seat_for_udev_device (manager, device);
+      free_devices_for_udev_device (manager, device);
     }
 
   udev_device_unref (device);
 }
 
 static void
 watch_for_udev_events (ply_device_manager_t *manager)
 {
   int fd;
   assert (manager != NULL);
   assert (manager->udev_monitor == NULL);
 
   ply_trace ("watching for udev graphics device add and remove events");
 
   manager->udev_monitor = udev_monitor_new_from_netlink (manager->udev_context, "udev");
 
   udev_monitor_filter_add_match_subsystem_devtype (manager->udev_monitor, SUBSYSTEM_DRM, NULL);
   udev_monitor_filter_add_match_subsystem_devtype (manager->udev_monitor, SUBSYSTEM_FRAME_BUFFER, NULL);
   udev_monitor_filter_add_match_tag (manager->udev_monitor, "seat");
   udev_monitor_enable_receiving (manager->udev_monitor);
 
   fd = udev_monitor_get_fd (manager->udev_monitor);
   ply_event_loop_watch_fd (manager->loop,
                            fd,
                            PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
                            (ply_event_handler_t)
                            on_udev_event,
                            NULL,
                            manager);
 }
 
 static void
-free_seats (ply_device_manager_t *manager)
-{
-  ply_list_node_t *node;
-
-  ply_trace ("removing seats");
-  node = ply_list_get_first_node (manager->seats);
-  while (node != NULL)
-    {
-      ply_seat_t *seat;
-      ply_list_node_t *next_node;
-
-      seat = ply_list_node_get_data (node);
-      next_node = ply_list_get_next_node (manager->seats, node);
-
-      if (manager->seat_removed_handler != NULL)
-        manager->seat_removed_handler (manager->seat_event_handler_data, seat);
-
-      ply_seat_free (seat);
-      ply_list_remove_node (manager->seats, node);
-
-      node = next_node;
-    }
-}
-
-static void
 free_terminal (char                 *device,
                ply_terminal_t       *terminal,
                ply_device_manager_t *manager)
 {
   ply_hashtable_remove (manager->terminals, device);
 
   ply_terminal_free (terminal);
 }
 
 static void
 free_terminals (ply_device_manager_t *manager)
 {
   ply_hashtable_foreach (manager->terminals,
                          (ply_hashtable_foreach_func_t *)
                          free_terminal,
                          manager);
 }
 
 static ply_terminal_t *
 get_terminal (ply_device_manager_t *manager,
               const char           *device_name)
 {
   char *full_name = NULL;
   ply_terminal_t *terminal;
 
   if (strncmp (device_name, "/dev/", strlen ("/dev/")) == 0)
     full_name = strdup (device_name);
   else
     asprintf (&full_name, "/dev/%s", device_name);
 
   if (strcmp (full_name, "/dev/tty0") == 0 ||
       strcmp (full_name, "/dev/tty") == 0 ||
       strcmp (full_name, ply_terminal_get_name (manager->local_console_terminal)) == 0)
     {
       terminal = manager->local_console_terminal;
 
       ply_hashtable_insert (manager->terminals,
                             (void *) ply_terminal_get_name (terminal),
                             terminal);
       goto done;
     }
 
   terminal = ply_hashtable_lookup (manager->terminals, full_name);
 
   if (terminal == NULL)
     {
       terminal = ply_terminal_new (full_name);
 
       ply_hashtable_insert (manager->terminals,
                             (void *) ply_terminal_get_name (terminal),
                             terminal);
     }
 
 done:
   free (full_name);
   return terminal;
 }
 
+static void
+free_renderer (char                 *device_path,
+               ply_renderer_t       *renderer,
+               ply_device_manager_t *manager)
+{
+  free_devices_from_device_path (manager, device_path);
+}
+
+static void
+free_renderers (ply_device_manager_t *manager)
+{
+  ply_hashtable_foreach (manager->renderers,
+                         (ply_hashtable_foreach_func_t *)
+                         free_renderer,
+                         manager);
+}
+
 ply_device_manager_t *
 ply_device_manager_new (const char                 *default_tty,
                         ply_device_manager_flags_t  flags)
 {
   ply_device_manager_t *manager;
 
   manager = calloc (1, sizeof (ply_device_manager_t));
   manager->loop = NULL;
   manager->terminals = ply_hashtable_new (ply_hashtable_string_hash, ply_hashtable_string_compare);
+  manager->renderers = ply_hashtable_new (ply_hashtable_string_hash, ply_hashtable_string_compare);
   manager->local_console_terminal = ply_terminal_new (default_tty);
-  manager->seats = ply_list_new ();
+  manager->keyboards = ply_list_new ();
+  manager->text_displays = ply_list_new ();
+  manager->pixel_displays = ply_list_new ();
   manager->flags = flags;
 
   if (!(flags & PLY_DEVICE_MANAGER_FLAGS_IGNORE_UDEV))
     manager->udev_context = udev_new ();
 
   attach_to_event_loop (manager, ply_event_loop_get_default ());
 
   return manager;
 }
 
 void
 ply_device_manager_free (ply_device_manager_t *manager)
 {
   ply_trace ("freeing device manager");
 
   if (manager == NULL)
     return;
 
   ply_event_loop_stop_watching_for_exit (manager->loop,
                                          (ply_event_loop_exit_handler_t)
                                          detach_from_event_loop,
                                          manager);
-  free_seats (manager);
-  ply_list_free (manager->seats);
-
   free_terminals (manager);
   ply_hashtable_free (manager->terminals);
 
+  free_renderers (manager);
+  ply_hashtable_free (manager->renderers);
+
   if (manager->udev_monitor != NULL)
     udev_monitor_unref (manager->udev_monitor);
 
   if (manager->udev_context != NULL)
     udev_unref (manager->udev_context);
 
   free (manager);
 }
 
 static bool
 add_consoles_from_file (ply_device_manager_t *manager,
                         const char           *path)
 {
   int fd;
   char contents[512] = "";
   ssize_t contents_length;
   bool has_serial_consoles;
   const char *remaining_file_contents;
 
   ply_trace ("opening %s", path);
   fd = open (path, O_RDONLY);
 
   if (fd < 0)
     {
       ply_trace ("couldn't open it: %m");
       return false;
     }
 
   ply_trace ("reading file");
   contents_length = read (fd, contents, sizeof (contents) - 1);
@@ -638,343 +621,438 @@ add_consoles_from_file (ply_device_manager_t *manager,
 
       /* Find trailing whitespace and NUL terminate.  If strcspn
        * doesn't find whitespace, it gives us the length of the string
        * until the next NUL byte, which we'll just overwrite with
        * another NUL byte anyway. */
       console_length = strcspn (remaining_file_contents, " \n\t\v");
       console = strndup (remaining_file_contents, console_length);
 
       terminal = get_terminal (manager, console);
       console_device = ply_terminal_get_name (terminal);
 
       free (console);
 
       ply_trace ("console %s found!", console_device);
 
       if (terminal != manager->local_console_terminal)
         has_serial_consoles = true;
 
       /* Move past the parsed console string, and the whitespace we
        * may have found above.  If we found a NUL above and not whitespace,
        * then we're going to jump past the end of the buffer and the loop
        * will terminate
        */
       remaining_file_contents += console_length + 1;
     }
 
   return has_serial_consoles;
 }
 
 static void
-create_seat_for_terminal_and_renderer_type (ply_device_manager_t *manager,
-                                            const char           *device_path,
-                                            ply_terminal_t       *terminal,
-                                            ply_renderer_type_t   renderer_type)
+create_pixel_displays_for_renderer (ply_device_manager_t *manager,
+                                    ply_renderer_t       *renderer)
+{
+  ply_list_t *heads;
+  ply_list_node_t *node;
+
+  heads = ply_renderer_get_heads (renderer);
+
+  ply_trace ("Adding displays for %d heads",
+             ply_list_get_length (heads));
+
+  node = ply_list_get_first_node (heads);
+  while (node != NULL)
+    {
+      ply_list_node_t *next_node;
+      ply_renderer_head_t *head;
+      ply_pixel_display_t *display;
+
+      head = ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (heads, node);
+
+      display = ply_pixel_display_new (renderer, head);
+
+      ply_list_append_data (manager->pixel_displays, display);
+
+      if (manager->pixel_display_added_handler != NULL)
+        manager->pixel_display_added_handler (manager->event_handler_data, display);
+      node = next_node;
+    }
+}
+
+static void
+create_text_displays_for_terminal (ply_device_manager_t *manager,
+                                   ply_terminal_t       *terminal)
 {
-  ply_seat_t *seat;
+  ply_text_display_t *display;
+
+  if (!ply_terminal_is_open (terminal))
+    {
+      if (!ply_terminal_open (terminal))
+        {
+          ply_trace ("could not add terminal %s: %m",
+                     ply_terminal_get_name (terminal));
+          return;
+        }
+    }
+
+  ply_trace ("adding text display for terminal %s",
+             ply_terminal_get_name (terminal));
+
+  display = ply_text_display_new (terminal);
+  ply_list_append_data (manager->text_displays, display);
+
+  if (manager->text_display_added_handler != NULL)
+    manager->text_display_added_handler (manager->event_handler_data, display);
+}
+
+static void
+create_devices_for_terminal_and_renderer_type (ply_device_manager_t *manager,
+                                               const char           *device_path,
+                                               ply_terminal_t       *terminal,
+                                               ply_renderer_type_t   renderer_type)
+{
+  ply_renderer_t *renderer = NULL;
+  ply_keyboard_t *keyboard = NULL;
+
   bool is_local_terminal = false;
 
   if (terminal != NULL && manager->local_console_terminal == terminal)
     is_local_terminal = true;
 
-  if (is_local_terminal && manager->local_console_seat != NULL)
+  if (is_local_terminal && manager->local_console_managed)
     {
-      ply_trace ("trying to create seat for local console when one already exists");
+      ply_trace ("trying to create devices for local console when one already exists");
       return;
     }
 
-  ply_trace ("creating seat for %s (renderer type: %u) (terminal: %s)",
+  ply_trace ("creating devices for %s (renderer type: %u) (terminal: %s)",
              device_path? : "", renderer_type, terminal? ply_terminal_get_name (terminal): "none");
-  seat = ply_seat_new (terminal);
 
-  if (!ply_seat_open (seat, renderer_type, device_path))
+  if (renderer_type != PLY_RENDERER_TYPE_NONE)
     {
-      ply_trace ("could not create seat");
-      ply_seat_free (seat);
-      return;
+      renderer = ply_renderer_new (renderer_type, device_path, terminal);
+
+      if (!ply_renderer_open (renderer))
+        {
+          ply_trace ("could not open renderer for %s", device_path);
+          ply_renderer_free (renderer);
+          renderer = NULL;
+          if (renderer_type != PLY_RENDERER_TYPE_AUTO)
+            return;
+        }
+    }
+
+  if (renderer != NULL)
+    {
+      keyboard = ply_keyboard_new_for_renderer (renderer);
+      ply_list_append_data (manager->keyboards, keyboard);
+
+      if (manager->keyboard_added_handler != NULL)
+        manager->keyboard_added_handler (manager->event_handler_data, keyboard);
+
+      create_pixel_displays_for_renderer (manager, renderer);
+      ply_hashtable_insert (manager->renderers, strdup (device_path), renderer);
+    }
+  else if (terminal != NULL)
+    {
+      keyboard = ply_keyboard_new_for_terminal (terminal);
+      ply_list_append_data (manager->keyboards, keyboard);
+
+      if (manager->keyboard_added_handler != NULL)
+        manager->keyboard_added_handler (manager->event_handler_data, keyboard);
+    }
+
+  if (terminal != NULL)
+    {
+      create_text_displays_for_terminal (manager, terminal);
+
+      if (is_local_terminal)
+        {
+          manager->local_console_is_text = true;
+        }
     }
 
-  ply_list_append_data (manager->seats, seat);
+  if (keyboard != NULL)
+    {
+      ply_keyboard_watch_for_input (keyboard);
+    }
 
   if (is_local_terminal)
-    manager->local_console_seat = seat;
+    manager->local_console_managed = true;
 
-  if (manager->seat_added_handler != NULL)
-    manager->seat_added_handler (manager->seat_event_handler_data, seat);
 }
 
 static void
-create_seat_for_terminal (const char           *device_path,
-                          ply_terminal_t       *terminal,
-                          ply_device_manager_t *manager)
+create_devices_for_terminal (const char           *device_path,
+                             ply_terminal_t       *terminal,
+                             ply_device_manager_t *manager)
 {
-  create_seat_for_terminal_and_renderer_type (manager,
-                                              device_path,
-                                              terminal,
-                                              PLY_RENDERER_TYPE_NONE);
+  create_devices_for_terminal_and_renderer_type (manager,
+                                                 device_path,
+                                                 terminal,
+                                                 PLY_RENDERER_TYPE_NONE);
 }
 static bool
-create_seats_from_terminals (ply_device_manager_t *manager)
+create_devices_from_terminals (ply_device_manager_t *manager)
 {
   bool has_serial_consoles;
 
   ply_trace ("checking for consoles");
 
   if (manager->flags & PLY_DEVICE_MANAGER_FLAGS_IGNORE_SERIAL_CONSOLES)
     {
       has_serial_consoles = false;
       ply_trace ("ignoring all consoles but default console because explicitly told to.");
     }
   else
     {
       has_serial_consoles = add_consoles_from_file (manager, "/sys/class/tty/console/active");
     }
 
   if (has_serial_consoles)
     {
       ply_trace ("serial consoles detected, managing them with details forced");
       ply_hashtable_foreach (manager->terminals,
                              (ply_hashtable_foreach_func_t *)
-                             create_seat_for_terminal,
+                             create_devices_for_terminal,
                              manager);
       return true;
     }
 
   return false;
 }
 
 static void
-create_seats_from_udev (ply_device_manager_t *manager)
+create_devices_from_udev (ply_device_manager_t *manager)
 {
   bool found_drm_device, found_fb_device;
 
   ply_trace ("Looking for devices from udev");
 
-  found_drm_device = create_seats_for_subsystem (manager, SUBSYSTEM_DRM);
-  found_fb_device = create_seats_for_subsystem (manager, SUBSYSTEM_FRAME_BUFFER);
+  found_drm_device = create_devices_for_subsystem (manager, SUBSYSTEM_DRM);
+  found_fb_device = create_devices_for_subsystem (manager, SUBSYSTEM_FRAME_BUFFER);
 
   if (found_drm_device || found_fb_device)
     return;
 
-  ply_trace ("Creating non-graphical seat, since there's no suitable graphics hardware");
-  create_seat_for_terminal_and_renderer_type (manager,
-                                              ply_terminal_get_name (manager->local_console_terminal),
-                                              manager->local_console_terminal,
-                                              PLY_RENDERER_TYPE_NONE);
+  ply_trace ("Creating non-graphical devices, since there's no suitable graphics hardware");
+  create_devices_for_terminal_and_renderer_type (manager,
+                                                 ply_terminal_get_name (manager->local_console_terminal),
+                                                 manager->local_console_terminal,
+                                                 PLY_RENDERER_TYPE_NONE);
 }
 
 static void
-create_fallback_seat (ply_device_manager_t *manager)
+create_fallback_devices (ply_device_manager_t *manager)
 {
-  create_seat_for_terminal_and_renderer_type (manager,
-                                              ply_terminal_get_name (manager->local_console_terminal),
-                                              manager->local_console_terminal,
-                                              PLY_RENDERER_TYPE_AUTO);
+  create_devices_for_terminal_and_renderer_type (manager,
+                                                 ply_terminal_get_name (manager->local_console_terminal),
+                                                 manager->local_console_terminal,
+                                                 PLY_RENDERER_TYPE_AUTO);
 }
 
 static void
 on_udev_queue_changed (ply_device_manager_t *manager)
 {
 
   if (!udev_queue_get_queue_is_empty (manager->udev_queue))
     return;
 
   ply_trace ("udev coldplug complete");
   ply_event_loop_stop_watching_fd (manager->loop, manager->udev_queue_fd_watch);
   manager->udev_queue_fd_watch = NULL;
   udev_queue_unref (manager->udev_queue);
 
   close (manager->udev_queue_fd);
   manager->udev_queue_fd = -1;
 
   manager->udev_queue = NULL;
 
-  create_seats_from_udev (manager);
+  create_devices_from_udev (manager);
 }
 
 static void
 watch_for_coldplug_completion (ply_device_manager_t *manager)
 {
   int fd;
   int result;
 
   manager->udev_queue = udev_queue_new (manager->udev_context);
 
   if (udev_queue_get_queue_is_empty (manager->udev_queue))
     {
       ply_trace ("udev coldplug completed already ");
-      create_seats_from_udev (manager);
+      create_devices_from_udev (manager);
       return;
     }
 
   fd = inotify_init1 (IN_CLOEXEC);
   result = inotify_add_watch (fd, "/run/udev", IN_MOVED_TO| IN_DELETE);
 
   if (result < 0)
     {
       ply_trace ("could not watch for udev to show up: %m");
       close (fd);
 
-      create_fallback_seat (manager);
+      create_fallback_devices (manager);
       return;
     }
 
   manager->udev_queue_fd = fd;
 
   manager->udev_queue_fd_watch = ply_event_loop_watch_fd (manager->loop,
                                                           fd,
                                                           PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
                                                           (ply_event_handler_t)
                                                           on_udev_queue_changed,
                                                           NULL,
                                                           manager);
 
 }
 
 void
-ply_device_manager_watch_seats (ply_device_manager_t       *manager,
-                                ply_seat_added_handler_t    seat_added_handler,
-                                ply_seat_removed_handler_t  seat_removed_handler,
-                                void                       *data)
+ply_device_manager_watch_devices (ply_device_manager_t                *manager,
+                                  ply_keyboard_added_handler_t         keyboard_added_handler,
+                                  ply_keyboard_removed_handler_t       keyboard_removed_handler,
+                                  ply_pixel_display_added_handler_t    pixel_display_added_handler,
+                                  ply_pixel_display_removed_handler_t  pixel_display_removed_handler,
+                                  ply_text_display_added_handler_t     text_display_added_handler,
+                                  ply_text_display_removed_handler_t   text_display_removed_handler,
+                                  void                                *data)
 {
-  bool done_with_initial_seat_setup;
+  bool done_with_initial_devices_setup;
 
-  manager->seat_added_handler = seat_added_handler;
-  manager->seat_removed_handler = seat_removed_handler;
-  manager->seat_event_handler_data = data;
+  manager->keyboard_added_handler = keyboard_added_handler;
+  manager->keyboard_removed_handler = keyboard_removed_handler;
+  manager->pixel_display_added_handler = pixel_display_added_handler;
+  manager->pixel_display_removed_handler = pixel_display_removed_handler;
+  manager->text_display_added_handler = text_display_added_handler;
+  manager->text_display_removed_handler = text_display_removed_handler;
+  manager->event_handler_data = data;
 
-  /* Try to create seats for each serial device right away, if possible
+  /* Try to create devices for each serial device right away, if possible
    */
-  done_with_initial_seat_setup = create_seats_from_terminals (manager);
+  done_with_initial_devices_setup = create_devices_from_terminals (manager);
 
-  if (done_with_initial_seat_setup)
+  if (done_with_initial_devices_setup)
     return;
 
   if ((manager->flags & PLY_DEVICE_MANAGER_FLAGS_IGNORE_UDEV))
     {
-      ply_trace ("udev support disabled, creating fallback seat");
-      create_fallback_seat (manager);
+      ply_trace ("udev support disabled, creating fallback devices");
+      create_fallback_devices (manager);
       return;
     }
 
   watch_for_udev_events (manager);
   watch_for_coldplug_completion (manager);
 }
 
 bool
-ply_device_manager_has_open_seats (ply_device_manager_t *manager)
+ply_device_manager_has_displays (ply_device_manager_t *manager)
 {
-  ply_list_node_t *node;
-
-  node = ply_list_get_first_node (manager->seats);
-  while (node != NULL)
-    {
-      ply_seat_t *seat;
-      ply_list_node_t *next_node;
-
-      seat = ply_list_node_get_data (node);
-      next_node = ply_list_get_next_node (manager->seats, node);
-
-      if (ply_seat_is_open (seat))
-        return true;
+  return ply_list_get_length (manager->pixel_displays) > 0 ||
+         ply_list_get_length (manager->text_displays) > 0;
+}
 
-      node = next_node;
-    }
+ply_list_t *
+ply_device_manager_get_keyboards (ply_device_manager_t *manager)
+{
+  return manager->keyboards;
+}
 
-  return false;
+ply_list_t *
+ply_device_manager_get_pixel_displays (ply_device_manager_t *manager)
+{
+  return manager->pixel_displays;
 }
 
 ply_list_t *
-ply_device_manager_get_seats (ply_device_manager_t *manager)
+ply_device_manager_get_text_displays (ply_device_manager_t *manager)
 {
-  return manager->seats;
+  return manager->text_displays;
 }
 
 ply_terminal_t *
 ply_device_manager_get_default_terminal (ply_device_manager_t *manager)
 {
   return manager->local_console_terminal;
 }
 
+static void
+activate_renderer (char                 *device_path,
+                   ply_renderer_t       *renderer,
+                   ply_device_manager_t *manager)
+{
+  ply_renderer_activate (renderer);
+}
+
 void
 ply_device_manager_activate_renderers (ply_device_manager_t *manager)
 {
-  ply_list_node_t *node;
-
   ply_trace ("activating renderers");
-  node = ply_list_get_first_node (manager->seats);
-  while (node != NULL)
-    {
-      ply_seat_t *seat;
-      ply_list_node_t *next_node;
-
-      seat = ply_list_node_get_data (node);
-      next_node = ply_list_get_next_node (manager->seats, node);
-
-      ply_seat_activate_renderer (seat);
+  ply_hashtable_foreach (manager->renderers,
+                         (ply_hashtable_foreach_func_t *)
+                         activate_renderer,
+                         manager);
+}
 
-      node = next_node;
-    }
+static void
+deactivate_renderer (char                 *device_path,
+                     ply_renderer_t       *renderer,
+                     ply_device_manager_t *manager)
+{
+  ply_renderer_deactivate (renderer);
 }
 
 void
 ply_device_manager_deactivate_renderers (ply_device_manager_t *manager)
 {
-  ply_list_node_t *node;
-
   ply_trace ("deactivating renderers");
-  node = ply_list_get_first_node (manager->seats);
-  while (node != NULL)
-    {
-      ply_seat_t *seat;
-      ply_list_node_t *next_node;
-
-      seat = ply_list_node_get_data (node);
-      next_node = ply_list_get_next_node (manager->seats, node);
-
-      ply_seat_deactivate_renderer (seat);
-
-      node = next_node;
-    }
+  ply_hashtable_foreach (manager->renderers,
+                         (ply_hashtable_foreach_func_t *)
+                         deactivate_renderer,
+                         manager);
 }
 
 void
 ply_device_manager_activate_keyboards (ply_device_manager_t *manager)
 {
   ply_list_node_t *node;
 
   ply_trace ("activating keyboards");
-  node = ply_list_get_first_node (manager->seats);
+  node = ply_list_get_first_node (manager->keyboards);
   while (node != NULL)
     {
-      ply_seat_t *seat;
+      ply_keyboard_t *keyboard;
       ply_list_node_t *next_node;
 
-      seat = ply_list_node_get_data (node);
-      next_node = ply_list_get_next_node (manager->seats, node);
+      keyboard = ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (manager->keyboards, node);
 
-      ply_seat_activate_keyboard (seat);
+      ply_keyboard_watch_for_input (keyboard);
 
       node = next_node;
     }
 }
 
 void
 ply_device_manager_deactivate_keyboards (ply_device_manager_t *manager)
 {
   ply_list_node_t *node;
 
   ply_trace ("deactivating keyboards");
-  node = ply_list_get_first_node (manager->seats);
+  node = ply_list_get_first_node (manager->keyboards);
   while (node != NULL)
     {
-      ply_seat_t *seat;
+      ply_keyboard_t *keyboard;
       ply_list_node_t *next_node;
 
-      seat = ply_list_node_get_data (node);
-      next_node = ply_list_get_next_node (manager->seats, node);
+      keyboard = ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (manager->keyboards, node);
 
-      ply_seat_deactivate_keyboard (seat);
+      ply_keyboard_stop_watching_for_input (keyboard);
 
       node = next_node;
     }
 }
diff --git a/src/libply-splash-core/ply-device-manager.h b/src/libply-splash-core/ply-device-manager.h
index d9c58e8..b628e41 100644
--- a/src/libply-splash-core/ply-device-manager.h
+++ b/src/libply-splash-core/ply-device-manager.h
@@ -1,56 +1,70 @@
 /* ply-device-manager.h - udev monitor
  *
  * Copyright (C) 2013 Red Hat, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2, or (at your option)
  * any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  * 02111-1307, USA.
  */
 #ifndef PLY_DEVICE_MANAGER_H
 #define PLY_DEVICE_MANAGER_H
 
 #include <stdbool.h>
-#include "ply-seat.h"
+
+#include "ply-keyboard.h"
+#include "ply-pixel-display.h"
+#include "ply-renderer.h"
+#include "ply-text-display.h"
 
 typedef enum
 {
   PLY_DEVICE_MANAGER_FLAGS_NONE                   = 0,
   PLY_DEVICE_MANAGER_FLAGS_IGNORE_SERIAL_CONSOLES = 1 << 0,
   PLY_DEVICE_MANAGER_FLAGS_IGNORE_UDEV            = 1 << 1
 } ply_device_manager_flags_t;
 
 typedef struct _ply_device_manager ply_device_manager_t;
-typedef void (* ply_seat_added_handler_t) (void *, ply_seat_t *);
-typedef void (* ply_seat_removed_handler_t) (void *, ply_seat_t *);
+typedef void (* ply_keyboard_added_handler_t) (void *, ply_keyboard_t *);
+typedef void (* ply_keyboard_removed_handler_t) (void *, ply_keyboard_t *);
+typedef void (* ply_pixel_display_added_handler_t) (void *, ply_pixel_display_t *);
+typedef void (* ply_pixel_display_removed_handler_t) (void *, ply_pixel_display_t *);
+typedef void (* ply_text_display_added_handler_t) (void *, ply_text_display_t *);
+typedef void (* ply_text_display_removed_handler_t) (void *, ply_text_display_t *);
 
 #ifndef PLY_HIDE_FUNCTION_DECLARATIONS
 ply_device_manager_t *ply_device_manager_new (const char                 *default_tty,
                                               ply_device_manager_flags_t  flags);
-void ply_device_manager_watch_seats (ply_device_manager_t *manager,
-                                     ply_seat_added_handler_t seat_added_handler,
-                                     ply_seat_removed_handler_t seat_removed_handler,
-                                     void *data);
-bool ply_device_manager_has_open_seats (ply_device_manager_t *manager);
-ply_list_t *ply_device_manager_get_seats (ply_device_manager_t *manager);
+void ply_device_manager_watch_devices (ply_device_manager_t                *manager,
+                                       ply_keyboard_added_handler_t         keyboard_added_handler,
+                                       ply_keyboard_removed_handler_t       keyboard_removed_handler,
+                                       ply_pixel_display_added_handler_t    pixel_display_added_handler,
+                                       ply_pixel_display_removed_handler_t  pixel_display_removed_handler,
+                                       ply_text_display_added_handler_t     text_display_added_handler,
+                                       ply_text_display_removed_handler_t   text_display_removed_handler,
+                                       void                                *data);
+bool ply_device_manager_has_displays (ply_device_manager_t *manager);
+ply_list_t *ply_device_manager_get_keyboards (ply_device_manager_t *manager);
+ply_list_t *ply_device_manager_get_pixel_displays (ply_device_manager_t *manager);
+ply_list_t *ply_device_manager_get_text_displays (ply_device_manager_t *manager);
 void ply_device_manager_free (ply_device_manager_t *manager);
 void ply_device_manager_activate_keyboards (ply_device_manager_t *manager);
 void ply_device_manager_deactivate_keyboards (ply_device_manager_t *manager);
 void ply_device_manager_activate_renderers (ply_device_manager_t *manager);
 void ply_device_manager_deactivate_renderers (ply_device_manager_t *manager);
 ply_terminal_t *ply_device_manager_get_default_terminal (ply_device_manager_t *manager);
 
 #endif
 
 #endif
 /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
diff --git a/src/libply-splash-core/ply-seat.c b/src/libply-splash-core/ply-seat.c
deleted file mode 100644
index 1c885c2..0000000
--- a/src/libply-splash-core/ply-seat.c
+++ /dev/null
@@ -1,374 +0,0 @@
-/* ply-seat.c - APIs for encapsulating a keyboard and one or more displays
- *
- * Copyright (C) 2013 Red Hat, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * Written by: Ray Strode <rstrode@redhat.com>
- */
-#include "config.h"
-#include "ply-seat.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "ply-boot-splash.h"
-#include "ply-event-loop.h"
-#include "ply-keyboard.h"
-#include "ply-pixel-display.h"
-#include "ply-text-display.h"
-#include "ply-list.h"
-#include "ply-logger.h"
-#include "ply-utils.h"
-
-struct _ply_seat
-{
-  ply_event_loop_t *loop;
-
-  ply_boot_splash_t *splash;
-  ply_terminal_t *terminal;
-  ply_renderer_t *renderer;
-  ply_keyboard_t *keyboard;
-  ply_list_t *text_displays;
-  ply_list_t *pixel_displays;
-};
-
-ply_seat_t *
-ply_seat_new (ply_terminal_t *terminal)
-{
-  ply_seat_t *seat;
-
-  seat = calloc (1, sizeof (ply_seat_t));
-
-  seat->loop = ply_event_loop_get_default ();
-  seat->terminal = terminal;
-  seat->text_displays = ply_list_new ();
-  seat->pixel_displays = ply_list_new ();
-
-  return seat;
-}
-
-static void
-add_pixel_displays (ply_seat_t *seat)
-{
-  ply_list_t *heads;
-  ply_list_node_t *node;
-
-  heads = ply_renderer_get_heads (seat->renderer);
-
-  ply_trace ("Adding displays for %d heads",
-             ply_list_get_length (heads));
-
-  node = ply_list_get_first_node (heads);
-  while (node != NULL)
-    {
-      ply_list_node_t *next_node;
-      ply_renderer_head_t *head;
-      ply_pixel_display_t *display;
-
-      head = ply_list_node_get_data (node);
-      next_node = ply_list_get_next_node (heads, node);
-
-      display = ply_pixel_display_new (seat->renderer, head);
-
-      ply_list_append_data (seat->pixel_displays, display);
-
-      node = next_node;
-    }
-}
-
-static void
-add_text_displays (ply_seat_t *seat)
-{
-  ply_text_display_t *display;
-
-  if (!ply_terminal_is_open (seat->terminal))
-    {
-      if (!ply_terminal_open (seat->terminal))
-        {
-          ply_trace ("could not add terminal %s: %m",
-                     ply_terminal_get_name (seat->terminal));
-          return;
-        }
-    }
-
-  ply_trace ("adding text display for terminal %s",
-             ply_terminal_get_name (seat->terminal));
-
-  display = ply_text_display_new (seat->terminal);
-  ply_list_append_data (seat->text_displays, display);
-}
-
-bool
-ply_seat_open (ply_seat_t          *seat,
-               ply_renderer_type_t  renderer_type,
-               const char          *device)
-{
-  if (renderer_type != PLY_RENDERER_TYPE_NONE)
-    {
-      ply_renderer_t *renderer;
-
-      renderer = ply_renderer_new (renderer_type, device, seat->terminal);
-
-      if (!ply_renderer_open (renderer))
-        {
-          ply_trace ("could not open renderer for %s", device);
-          ply_renderer_free (renderer);
-
-          if (renderer_type != PLY_RENDERER_TYPE_AUTO)
-            return false;
-        }
-      else
-        {
-          seat->renderer = renderer;
-        }
-    }
-
-  if (seat->renderer != NULL)
-    {
-      seat->keyboard = ply_keyboard_new_for_renderer (seat->renderer);
-      add_pixel_displays (seat);
-
-    }
-  else if (seat->terminal != NULL)
-    {
-      seat->keyboard = ply_keyboard_new_for_terminal (seat->terminal);
-    }
-
-  if (seat->terminal != NULL)
-    {
-      add_text_displays (seat);
-    }
-  else
-    {
-      ply_trace ("not adding text display for seat, since seat has no associated terminal");
-    }
-
-  if (seat->keyboard != NULL)
-    {
-      ply_keyboard_watch_for_input (seat->keyboard);
-    }
-  else
-    {
-      ply_trace ("not watching seat for input");
-    }
-
-  return true;
-}
-
-bool
-ply_seat_is_open (ply_seat_t *seat)
-{
-  return ply_list_get_length (seat->pixel_displays) > 0 ||
-         ply_list_get_length (seat->text_displays) > 0;
-}
-
-void
-ply_seat_deactivate_keyboard (ply_seat_t *seat)
-{
-  if (seat->keyboard == NULL)
-    return;
-
-  ply_trace ("deactivating keybord");
-  ply_keyboard_stop_watching_for_input (seat->keyboard);
-}
-
-void
-ply_seat_deactivate_renderer (ply_seat_t *seat)
-{
-  if (seat->renderer == NULL)
-    return;
-
-  ply_trace ("deactivating renderer");
-  ply_renderer_deactivate (seat->renderer);
-}
-
-void
-ply_seat_activate_keyboard (ply_seat_t *seat)
-{
-  if (seat->keyboard == NULL)
-    return;
-
-  ply_trace ("activating keyboard");
-  ply_keyboard_watch_for_input (seat->keyboard);
-}
-
-void
-ply_seat_activate_renderer (ply_seat_t *seat)
-{
-  if (seat->renderer == NULL)
-    return;
-
-  ply_trace ("activating renderer");
-  ply_renderer_activate (seat->renderer);
-}
-
-void
-ply_seat_refresh_displays (ply_seat_t *seat)
-{
-  ply_list_node_t *node;
-
-  node = ply_list_get_first_node (seat->pixel_displays);
-  while (node != NULL)
-    {
-      ply_pixel_display_t *display;
-      ply_list_node_t *next_node;
-      unsigned long width, height;
-
-      display = ply_list_node_get_data (node);
-      next_node = ply_list_get_next_node (seat->pixel_displays, node);
-
-      width = ply_pixel_display_get_width (display);
-      height = ply_pixel_display_get_height (display);
-
-      ply_pixel_display_draw_area (display, 0, 0, width, height);
-      node = next_node;
-    }
-
-  node = ply_list_get_first_node (seat->text_displays);
-  while (node != NULL)
-    {
-      ply_text_display_t *display;
-      ply_list_node_t *next_node;
-      int number_of_columns, number_of_rows;
-
-      display = ply_list_node_get_data (node);
-      next_node = ply_list_get_next_node (seat->text_displays, node);
-
-      number_of_columns = ply_text_display_get_number_of_columns (display);
-      number_of_rows = ply_text_display_get_number_of_rows (display);
-
-      ply_text_display_draw_area (display, 0, 0,
-                                  number_of_columns,
-                                  number_of_rows);
-      node = next_node;
-    }
-}
-
-void
-ply_seat_close (ply_seat_t *seat)
-{
-  if (seat->renderer == NULL)
-    return;
-
-  ply_trace ("destroying renderer");
-  ply_renderer_close (seat->renderer);
-  ply_renderer_free (seat->renderer);
-  seat->renderer = NULL;
-}
-
-void
-ply_seat_set_splash (ply_seat_t        *seat,
-                     ply_boot_splash_t *splash)
-{
-  if (seat->splash == splash)
-    return;
-
-  if (seat->splash != NULL)
-    ply_boot_splash_detach_from_seat (splash, seat);
-
-  if (splash != NULL)
-    ply_boot_splash_attach_to_seat (splash, seat);
-
-  seat->splash = splash;
-}
-
-static void
-free_pixel_displays (ply_seat_t *seat)
-{
-  ply_list_node_t *node;
-
-  ply_trace ("freeing %d pixel displays", ply_list_get_length (seat->pixel_displays));
-  node = ply_list_get_first_node (seat->pixel_displays);
-  while (node != NULL)
-    {
-      ply_list_node_t *next_node;
-      ply_pixel_display_t *display;
-
-      next_node = ply_list_get_next_node (seat->pixel_displays, node);
-      display = ply_list_node_get_data (node);
-      ply_pixel_display_free (display);
-
-      ply_list_remove_node (seat->pixel_displays, node);
-
-      node = next_node;
-    }
-}
-
-static void
-free_text_displays (ply_seat_t *seat)
-{
-  ply_list_node_t *node;
-
-  ply_trace ("freeing %d text displays", ply_list_get_length (seat->text_displays));
-  node = ply_list_get_first_node (seat->text_displays);
-  while (node != NULL)
-    {
-      ply_list_node_t *next_node;
-      ply_text_display_t *display;
-
-      next_node = ply_list_get_next_node (seat->text_displays, node);
-      display = ply_list_node_get_data (node);
-      ply_text_display_free (display);
-
-      ply_list_remove_node (seat->text_displays, node);
-
-      node = next_node;
-    }
-}
-
-void
-ply_seat_free (ply_seat_t *seat)
-{
-  if (seat == NULL)
-    return;
-
-  free_pixel_displays (seat);
-  free_text_displays (seat);
-  ply_keyboard_free (seat->keyboard);
-
-  free (seat);
-}
-
-ply_list_t *
-ply_seat_get_pixel_displays (ply_seat_t *seat)
-{
-  return seat->pixel_displays;
-}
-
-ply_list_t *
-ply_seat_get_text_displays (ply_seat_t *seat)
-{
-  return seat->text_displays;
-}
-
-ply_keyboard_t *
-ply_seat_get_keyboard (ply_seat_t *seat)
-{
-  return seat->keyboard;
-}
-
-ply_renderer_t *
-ply_seat_get_renderer (ply_seat_t *seat)
-{
-  return seat->renderer;
-}
-
-/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */
diff --git a/src/libply-splash-core/ply-seat.h b/src/libply-splash-core/ply-seat.h
deleted file mode 100644
index d5d3397..0000000
--- a/src/libply-splash-core/ply-seat.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* ply-seat.h - APIs for encapsulating a keyboard and one or more displays
- *
- * Copyright (C) 2013 Red Hat, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * Written By: Ray Strode <rstrode@redhat.com>
- */
-#ifndef PLY_SEAT_H
-#define PLY_SEAT_H
-
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <unistd.h>
-
-#include "ply-boot-splash.h"
-#include "ply-buffer.h"
-#include "ply-event-loop.h"
-#include "ply-keyboard.h"
-#include "ply-list.h"
-#include "ply-pixel-display.h"
-#include "ply-terminal.h"
-#include "ply-text-display.h"
-
-typedef struct _ply_boot_splash ply_boot_splash_t;
-typedef struct _ply_seat ply_seat_t;
-
-#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
-ply_seat_t *ply_seat_new (ply_terminal_t *terminal);
-
-void ply_seat_free (ply_seat_t *seat);
-bool ply_seat_open (ply_seat_t          *seat,
-                    ply_renderer_type_t  renderer_type,
-                    const char          *device);
-bool ply_seat_is_open (ply_seat_t *seat);
-void ply_seat_deactivate_keyboard (ply_seat_t *seat);
-void ply_seat_activate_keyboard (ply_seat_t *seat);
-void ply_seat_deactivate_renderer (ply_seat_t *seat);
-void ply_seat_activate_renderer (ply_seat_t *seat);
-void ply_seat_refresh_displays (ply_seat_t *seat);
-void ply_seat_close (ply_seat_t *seat);
-void ply_seat_set_splash (ply_seat_t        *seat,
-                          ply_boot_splash_t *splash);
-
-ply_list_t *ply_seat_get_pixel_displays (ply_seat_t *seat);
-ply_list_t *ply_seat_get_text_displays (ply_seat_t *seat);
-ply_keyboard_t *ply_seat_get_keyboard (ply_seat_t *seat);
-ply_renderer_t *ply_seat_get_renderer (ply_seat_t *seat);
-#endif
-
-#endif /* PLY_SEAT_H */
-/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */
diff --git a/src/main.c b/src/main.c
index db5c281..ec46199 100644
--- a/src/main.c
+++ b/src/main.c
@@ -108,62 +108,62 @@ typedef struct
   double splash_delay;
 
   char kernel_command_line[PLY_MAX_COMMAND_LINE_SIZE];
   uint32_t kernel_command_line_is_set : 1;
   uint32_t no_boot_log : 1;
   uint32_t showing_details : 1;
   uint32_t system_initialized : 1;
   uint32_t is_redirected : 1;
   uint32_t is_attached : 1;
   uint32_t should_be_attached : 1;
   uint32_t should_retain_splash : 1;
   uint32_t is_inactive : 1;
   uint32_t is_shown : 1;
   uint32_t should_force_details : 1;
 
   char *override_splash_path;
   char *system_default_splash_path;
   char *distribution_default_splash_path;
   const char *default_tty;
 
   int number_of_errors;
 } state_t;
 
 static void show_splash (state_t *state);
 static ply_boot_splash_t *load_built_in_theme (state_t *state);
 static ply_boot_splash_t *load_theme (state_t    *state,
                                       const char *theme_path);
 static ply_boot_splash_t *show_theme (state_t    *state,
                                       const char *theme_path);
 
-static void attach_splash_to_seats (state_t           *state,
-                                    ply_boot_splash_t *splash);
+static void attach_splash_to_devices (state_t           *state,
+                                      ply_boot_splash_t *splash);
 static bool attach_to_running_session (state_t *state);
 static void detach_from_running_session (state_t *state);
 static void on_escape_pressed (state_t *state);
 static void dump_details_and_quit_splash (state_t *state);
 static void update_display (state_t *state);
 
 static void on_error_message (ply_buffer_t *debug_buffer,
                               const void   *bytes,
                               size_t        number_of_bytes);
 static ply_buffer_t *debug_buffer;
 static char *debug_buffer_path = NULL;
 static char *pid_file = NULL;
 static void toggle_between_splash_and_details (state_t *state);
 #ifdef PLY_ENABLE_SYSTEMD_INTEGRATION
 static void tell_systemd_to_print_details (state_t *state);
 static void tell_systemd_to_stop_printing_details (state_t *state);
 #endif
 static const char * get_cache_file_for_mode (ply_mode_t mode);
 static void on_escape_pressed (state_t *state);
 static void on_enter (state_t    *state,
                       const char *line);
 static void on_keyboard_input (state_t    *state,
                                const char *keyboard_input,
                                size_t      character_size);
 static void on_backspace (state_t *state);
 static void on_quit (state_t       *state,
                      bool           retain_splash,
                      ply_trigger_t *quit_trigger);
 static bool sh_is_init (state_t *state);
 
@@ -486,69 +486,69 @@ show_default_splash (state_t *state)
   update_display (state);
 }
 
 static void
 cancel_pending_delayed_show (state_t *state)
 {
   if (isnan (state->splash_delay))
     return;
 
   ply_event_loop_stop_watching_for_timeout (state->loop,
                                             (ply_event_loop_timeout_handler_t)
                                             show_splash,
                                             state);
   state->splash_delay = NAN;
 }
 
 static void
 on_ask_for_password (state_t      *state,
                      const char   *prompt,
                      ply_trigger_t *answer)
 {
   ply_entry_trigger_t *entry_trigger;
 
   if (state->boot_splash == NULL)
     {
       /* Waiting to be shown, boot splash will
        * arrive shortly so just sit tight
        */
       if (state->is_shown)
         {
-          bool has_open_seats;
+          bool has_displays;
 
           cancel_pending_delayed_show (state);
 
-          has_open_seats = ply_device_manager_has_open_seats (state->device_manager);
+          has_displays = ply_device_manager_has_displays (state->device_manager);
 
-          if (has_open_seats)
+          if (has_displays)
             {
-              ply_trace ("seats open now, showing splash immediately");
+              ply_trace ("displays available now, showing splash immediately");
               show_splash (state);
             }
           else
             {
               ply_trace ("splash still coming up, waiting a bit");
             }
         }
       else
         {
           /* No splash, client will have to get password */
           ply_trace ("no splash loaded, replying immediately with no password");
           ply_trigger_pull (answer, NULL);
           return;
         }
     }
 
   entry_trigger = calloc (1, sizeof (ply_entry_trigger_t));
   entry_trigger->type = PLY_ENTRY_TRIGGER_TYPE_PASSWORD;
   entry_trigger->prompt = prompt;
   entry_trigger->trigger = answer;
   ply_trace ("queuing password request with boot splash");
   ply_list_append_data (state->entry_triggers, entry_trigger);
   update_display (state);
 }
 
 static void
 on_ask_question (state_t      *state,
                  const char   *prompt,
                  ply_trigger_t *answer)
 {
@@ -873,224 +873,273 @@ plymouth_should_show_default_splash (state_t *state)
     {
       ply_trace ("no default splash because kernel command line has option \"splash=verbose\"");
       return false;
     }
 
   if (command_line_has_argument (state->kernel_command_line, "rhgb"))
     {
       ply_trace ("using default splash because kernel command line has option \"rhgb\"");
       return true;
     }
 
   if (command_line_has_argument (state->kernel_command_line, "splash"))
     {
       ply_trace ("using default splash because kernel command line has option \"splash\"");
       return true;
     }
 
   if (command_line_has_argument (state->kernel_command_line, "splash=silent"))
     {
       ply_trace ("using default splash because kernel command line has option \"splash=slient\"");
       return true;
     }
 
   ply_trace ("no default splash because kernel command line lacks \"splash\" or \"rhgb\"");
   return false;
 }
 
 static void
 on_show_splash (state_t *state)
 {
-  bool has_open_seats;
+  bool has_displays;
 
   if (state->is_shown)
     {
       ply_trace ("show splash called while already shown");
       return;
     }
 
   if (state->is_inactive)
     {
       ply_trace ("show splash called while inactive");
       return;
     }
 
   if (plymouth_should_ignore_show_splash_calls (state))
     {
       ply_trace ("show splash called while ignoring show splash calls");
       dump_details_and_quit_splash (state);
       return;
     }
 
   state->is_shown = true;
-  has_open_seats = ply_device_manager_has_open_seats (state->device_manager);
+  has_displays = ply_device_manager_has_displays (state->device_manager);
 
-  if (!state->is_attached && state->should_be_attached && has_open_seats)
+  if (!state->is_attached && state->should_be_attached && has_displays)
     attach_to_running_session (state);
 
-  if (has_open_seats)
+  if (has_displays)
     {
-      ply_trace ("at least one seat already open, so loading splash");
+      ply_trace ("at least one display already available, so loading splash");
       show_splash (state);
     }
   else
     {
-      ply_trace ("no seats available to show splash on, waiting...");
+      ply_trace ("no displays available to show splash on, waiting...");
     }
 }
 
 static void
-on_seat_removed (state_t    *state,
-                 ply_seat_t *seat)
-{
-  ply_keyboard_t *keyboard;
-
-  keyboard = ply_seat_get_keyboard (seat);
-
-  ply_trace ("no longer listening for keystrokes");
-  ply_keyboard_remove_input_handler (keyboard,
-                                     (ply_keyboard_input_handler_t)
-                                     on_keyboard_input);
-  ply_trace ("no longer listening for escape");
-  ply_keyboard_remove_escape_handler (keyboard,
-                                      (ply_keyboard_escape_handler_t)
-                                      on_escape_pressed);
-  ply_trace ("no longer listening for backspace");
-  ply_keyboard_remove_backspace_handler (keyboard,
-                                         (ply_keyboard_backspace_handler_t)
-                                         on_backspace);
-  ply_trace ("no longer listening for enter");
-  ply_keyboard_remove_enter_handler (keyboard,
-                                     (ply_keyboard_enter_handler_t)
-                                     on_enter);
-
-  if (state->boot_splash != NULL)
-   ply_boot_splash_detach_from_seat (state->boot_splash, seat);
-}
-
-static void
 show_splash (state_t *state)
 {
   if (state->boot_splash != NULL)
     return;
 
   if (!isnan (state->splash_delay))
     {
       double now, running_time;
 
       now = ply_get_timestamp ();
       running_time = now - state->start_time;
       if (state->splash_delay > running_time)
         {
           double time_left = state->splash_delay - running_time;
 
           ply_trace ("delaying show splash for %lf seconds",
                      time_left);
           ply_event_loop_stop_watching_for_timeout (state->loop,
                                                     (ply_event_loop_timeout_handler_t)
                                                     show_splash,
                                                     state);
           ply_event_loop_watch_for_timeout (state->loop,
                                             time_left,
                                             (ply_event_loop_timeout_handler_t)
                                             show_splash,
                                             state);
           return;
         }
     }
 
   if (plymouth_should_show_default_splash (state))
     {
       show_default_splash (state);
       state->showing_details = false;
     }
   else
     {
       show_detailed_splash (state);
       state->showing_details = true;
     }
 }
 
 static void
-on_seat_added (state_t    *state,
-               ply_seat_t *seat)
+on_keyboard_added (state_t        *state,
+                   ply_keyboard_t *keyboard)
 {
-  ply_keyboard_t *keyboard;
-
-  if (state->is_shown)
-    {
-      if (state->boot_splash == NULL)
-        {
-          ply_trace ("seat added before splash loaded, so loading splash now");
-          show_splash (state);
-        }
-      else
-        {
-          ply_trace ("seat added after splash loaded, so attaching to splash");
-          ply_boot_splash_attach_to_seat (state->boot_splash, seat);
-        }
-    }
-
-  keyboard = ply_seat_get_keyboard (seat);
-
   ply_trace ("listening for keystrokes");
   ply_keyboard_add_input_handler (keyboard,
                                   (ply_keyboard_input_handler_t)
                                   on_keyboard_input, state);
   ply_trace ("listening for escape");
   ply_keyboard_add_escape_handler (keyboard,
                                    (ply_keyboard_escape_handler_t)
                                    on_escape_pressed, state);
   ply_trace ("listening for backspace");
   ply_keyboard_add_backspace_handler (keyboard,
                                       (ply_keyboard_backspace_handler_t)
                                       on_backspace, state);
   ply_trace ("listening for enter");
   ply_keyboard_add_enter_handler (keyboard,
                                   (ply_keyboard_enter_handler_t)
                                   on_enter, state);
 
+  if (state->boot_splash != NULL)
+    {
+      ply_trace ("keyboard set after splash loaded, so attaching to splash");
+      ply_boot_splash_set_keyboard (state->boot_splash, keyboard);
+    }
+}
+
+static void
+on_keyboard_removed (state_t        *state,
+                     ply_keyboard_t *keyboard)
+{
+  ply_trace ("no longer listening for keystrokes");
+  ply_keyboard_remove_input_handler (keyboard,
+                                     (ply_keyboard_input_handler_t)
+                                     on_keyboard_input);
+  ply_trace ("no longer listening for escape");
+  ply_keyboard_remove_escape_handler (keyboard,
+                                      (ply_keyboard_escape_handler_t)
+                                      on_escape_pressed);
+  ply_trace ("no longer listening for backspace");
+  ply_keyboard_remove_backspace_handler (keyboard,
+                                         (ply_keyboard_backspace_handler_t)
+                                         on_backspace);
+  ply_trace ("no longer listening for enter");
+  ply_keyboard_remove_enter_handler (keyboard,
+                                     (ply_keyboard_enter_handler_t)
+                                     on_enter);
+
+  if (state->boot_splash != NULL)
+    ply_boot_splash_unset_keyboard (state->boot_splash);
+}
+
+static void
+on_pixel_display_added (state_t                    *state,
+                        ply_pixel_display_t *display)
+{
+  if (state->is_shown)
+    {
+      if (state->boot_splash == NULL)
+        {
+          ply_trace ("pixel display added before splash loaded, so loading splash now");
+          show_splash (state);
+        }
+      else
+        {
+          ply_trace ("pixel display added after splash loaded, so attaching to splash");
+          ply_boot_splash_add_pixel_display (state->boot_splash, display);
+        }
+    }
+}
+
+static void
+on_pixel_display_removed (state_t                    *state,
+                          ply_pixel_display_t *display)
+{
+  if (state->boot_splash == NULL)
+    return;
+
+  ply_boot_splash_remove_pixel_display (state->boot_splash, display);
+}
+
+static void
+on_text_display_added (state_t                   *state,
+                       ply_text_display_t *display)
+{
+  if (state->is_shown)
+    {
+      if (state->boot_splash == NULL)
+        {
+          ply_trace ("text display added before splash loaded, so loading splash now");
+          show_splash (state);
+        }
+      else
+        {
+          ply_trace ("text display added after splash loaded, so attaching to splash");
+          ply_boot_splash_add_text_display (state->boot_splash, display);
+        }
+    }
+}
+
+static void
+on_text_display_removed (state_t                   *state,
+                         ply_text_display_t *display)
+{
+  if (state->boot_splash == NULL)
+    return;
+
+  ply_boot_splash_remove_text_display (state->boot_splash, display);
 }
 
 static void
 load_devices (state_t                    *state,
               ply_device_manager_flags_t  flags)
 {
   state->device_manager = ply_device_manager_new (state->default_tty, flags);
   state->local_console_terminal = ply_device_manager_get_default_terminal (state->device_manager);
 
-  ply_device_manager_watch_seats (state->device_manager,
-                                  (ply_seat_added_handler_t)
-                                  on_seat_added,
-                                  (ply_seat_removed_handler_t)
-                                  on_seat_removed,
-                                  state);
+  ply_device_manager_watch_devices (state->device_manager,
+                                    (ply_keyboard_added_handler_t)
+                                    on_keyboard_added,
+                                    (ply_keyboard_removed_handler_t)
+                                    on_keyboard_removed,
+                                    (ply_pixel_display_added_handler_t)
+                                    on_pixel_display_added,
+                                    (ply_pixel_display_removed_handler_t)
+                                    on_pixel_display_removed,
+                                    (ply_text_display_added_handler_t)
+                                    on_text_display_added,
+                                    (ply_text_display_removed_handler_t)
+                                    on_text_display_removed,
+                                    state);
 }
 
 static void
 quit_splash (state_t *state)
 {
   ply_trace ("quiting splash");
   if (state->boot_splash != NULL)
     {
       ply_trace ("freeing splash");
       ply_boot_splash_free (state->boot_splash);
       state->boot_splash = NULL;
     }
 
   ply_device_manager_deactivate_keyboards (state->device_manager);
 
   if (state->local_console_terminal != NULL)
     {
       if (!state->should_retain_splash)
         {
           ply_trace ("Not retaining splash, so deallocating VT");
           ply_terminal_deactivate_vt (state->local_console_terminal);
           ply_terminal_close (state->local_console_terminal);
         }
     }
 
   detach_from_running_session (state);
 }
 
 static void
 hide_splash (state_t *state)
@@ -1548,78 +1597,110 @@ on_enter (state_t                  *state,
   node = ply_list_get_first_node (state->entry_triggers);
   if (node)
     {
       ply_entry_trigger_t* entry_trigger = ply_list_node_get_data (node);
       const char* reply_text = ply_buffer_get_bytes (state->entry_buffer);
       ply_trigger_pull (entry_trigger->trigger, reply_text);
       ply_buffer_clear (state->entry_buffer);
       ply_list_remove_node (state->entry_triggers, node);
       free (entry_trigger);
       update_display (state);
     }
   else
     {
       for (node = ply_list_get_first_node (state->keystroke_triggers); node;
                         node = ply_list_get_next_node (state->keystroke_triggers, node))
         {
           ply_keystroke_watch_t* keystroke_trigger = ply_list_node_get_data (node);
           if (!keystroke_trigger->keys || strstr(keystroke_trigger->keys, "\n"))  /* assume strstr works on utf8 arrays */
             {
               ply_trigger_pull (keystroke_trigger->trigger, line);
               ply_list_remove_node (state->keystroke_triggers, node);
               free(keystroke_trigger);
               return;
             }
         }
       return;
     }
 }
 
 static void
-attach_splash_to_seats (state_t           *state,
-                        ply_boot_splash_t *splash)
+attach_splash_to_devices (state_t           *state,
+                          ply_boot_splash_t *splash)
 {
 
-  ply_list_t *seats;
+  ply_list_t *keyboards;
+  ply_list_t *pixel_displays;
+  ply_list_t *text_displays;
   ply_list_node_t *node;
 
-  seats = ply_device_manager_get_seats (state->device_manager);
-  node = ply_list_get_first_node (seats);
+  keyboards = ply_device_manager_get_keyboards (state->device_manager);
+  node = ply_list_get_first_node (keyboards);
+  while (node != NULL)
+    {
+      ply_keyboard_t *keyboard;
+      ply_list_node_t *next_node;
+
+      keyboard = ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (keyboards, node);
+
+      ply_boot_splash_set_keyboard (splash, keyboard);
+
+      node = next_node;
+    }
+
+  pixel_displays = ply_device_manager_get_pixel_displays (state->device_manager);
+  node = ply_list_get_first_node (pixel_displays);
+  while (node != NULL)
+    {
+      ply_pixel_display_t *pixel_display;
+      ply_list_node_t *next_node;
+
+      pixel_display = ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (pixel_displays, node);
+
+      ply_boot_splash_add_pixel_display (splash, pixel_display);
+
+      node = next_node;
+    }
+
+  text_displays = ply_device_manager_get_text_displays (state->device_manager);
+  node = ply_list_get_first_node (text_displays);
   while (node != NULL)
     {
-      ply_seat_t *seat;
+      ply_text_display_t *text_display;
       ply_list_node_t *next_node;
 
-      seat = ply_list_node_get_data (node);
-      next_node = ply_list_get_next_node (seats, node);
+      text_display = ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (text_displays, node);
 
-      ply_boot_splash_attach_to_seat (splash, seat);
+      ply_boot_splash_add_text_display (splash, text_display);
 
       node = next_node;
     }
 }
 
 #ifdef PLY_ENABLE_SYSTEMD_INTEGRATION
 static void
 tell_systemd_to_print_details (state_t *state)
 {
   ply_trace ("telling systemd to start printing details");
   if (kill (1, SIGRTMIN + 20) < 0)
     ply_trace ("could not tell systemd to print details: %m");
 }
 
 static void
 tell_systemd_to_stop_printing_details (state_t *state)
 {
   ply_trace ("telling systemd to stop printing details");
   if (kill (1, SIGRTMIN + 21) < 0)
     ply_trace ("could not tell systemd to stop printing details: %m");
 }
 #endif
 
 static ply_boot_splash_t *
 load_built_in_theme (state_t *state)
 {
   ply_boot_splash_t *splash;
   bool is_loaded;
 
   ply_trace ("Loading built-in theme");
@@ -1668,61 +1749,61 @@ load_theme (state_t    *state,
       ply_save_errno ();
       ply_boot_splash_free (splash);
       ply_restore_errno ();
       return NULL;
     }
 
   ply_trace ("attaching plugin to event loop");
   ply_boot_splash_attach_to_event_loop (splash, state->loop);
 
   ply_trace ("attaching progress to plugin");
   ply_boot_splash_attach_progress (splash, state->progress);
 
   return splash;
 }
 
 static ply_boot_splash_t *
 show_theme (state_t           *state,
             const char        *theme_path)
 {
   ply_boot_splash_mode_t splash_mode;
   ply_boot_splash_t *splash;
 
   if (theme_path != NULL)
     splash = load_theme (state, theme_path);
   else
     splash = load_built_in_theme (state);
 
   if (splash == NULL)
     return NULL;
 
-  attach_splash_to_seats (state, splash);
+  attach_splash_to_devices (state, splash);
   ply_device_manager_activate_renderers (state->device_manager);
 
   if (state->mode == PLY_MODE_SHUTDOWN)
     splash_mode = PLY_BOOT_SPLASH_MODE_SHUTDOWN;
   else
     splash_mode = PLY_BOOT_SPLASH_MODE_BOOT_UP;
 
   if (!ply_boot_splash_show (splash, splash_mode))
     {
       ply_save_errno ();
       ply_boot_splash_free (splash);
       ply_restore_errno ();
       return NULL;
     }
 
 #ifdef PLY_ENABLE_SYSTEMD_INTEGRATION
   if (state->is_attached)
     tell_systemd_to_print_details (state);
 #endif
 
   ply_device_manager_activate_keyboards (state->device_manager);
   show_messages (state);
 
   return splash;
 }
 
 static bool
 attach_to_running_session (state_t *state)
 {
   ply_terminal_session_t *session;
-- 
2.3.7


From 8ae7a1af26bfdd367c2a926a0050e03db5dfb87e Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 24 Jul 2015 14:12:40 -0400
Subject: [PATCH 5/8] device-manager: decouple local console from output device

The code currently does a faulty heuristic to figure out which
drm device is associated with the tty.  We shouldn't actually
even need an accurate association, so this commit just makes
sure the terminal gets used for the first device.
---
 src/libply-splash-core/ply-device-manager.c | 73 +++++++++--------------------
 1 file changed, 21 insertions(+), 52 deletions(-)

diff --git a/src/libply-splash-core/ply-device-manager.c b/src/libply-splash-core/ply-device-manager.c
index c7568c1..b90a0f6 100644
--- a/src/libply-splash-core/ply-device-manager.c
+++ b/src/libply-splash-core/ply-device-manager.c
@@ -70,87 +70,60 @@ struct _ply_device_manager
   void                                *event_handler_data;
 
   uint32_t                    local_console_managed : 1;
   uint32_t                    local_console_is_text : 1;
 };
 
 static void
 detach_from_event_loop (ply_device_manager_t *manager)
 {
   assert (manager != NULL);
 
   manager->loop = NULL;
 }
 
 static void
 attach_to_event_loop (ply_device_manager_t *manager,
                       ply_event_loop_t     *loop)
 {
   assert (manager != NULL);
   assert (loop != NULL);
   assert (manager->loop == NULL);
 
   manager->loop = loop;
 
   ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t)
                                  detach_from_event_loop,
                                  manager);
 }
 
 static bool
-device_is_for_local_console (ply_device_manager_t *manager,
-                             struct udev_device   *device)
-{
-  const char *device_path;
-  struct udev_device *bus_device;
-  char *bus_device_path;
-  const char *boot_vga;
-  bool for_local_console;
-
-  /* Look at the associated bus device to see if this card is the
-   * card the kernel is using for its console. */
-  device_path = udev_device_get_syspath (device);
-  asprintf (&bus_device_path, "%s/device", device_path);
-  bus_device = udev_device_new_from_syspath (manager->udev_context, bus_device_path);
-
-  boot_vga = udev_device_get_sysattr_value (bus_device, "boot_vga");
-  free (bus_device_path);
-
-  if (boot_vga != NULL && strcmp (boot_vga, "1") == 0)
-    for_local_console = true;
-  else
-    for_local_console = false;
-
-  return for_local_console;
-}
-
-static bool
 drm_device_in_use (ply_device_manager_t *manager,
                    const char           *device_path)
 {
   ply_renderer_t *renderer;
 
   renderer = ply_hashtable_lookup (manager->renderers, (void *) device_path);
 
   return renderer != NULL;
 }
 
 static bool
 fb_device_has_drm_device (ply_device_manager_t *manager,
                           struct udev_device   *fb_device)
 {
   struct udev_enumerate *card_matches;
   struct udev_list_entry *card_entry;
   const char *id_path;
   bool has_drm_device = false;
 
   /* We want to see if the framebuffer is associated with a DRM-capable
    * graphics card, if it is, we'll use the DRM device */
   card_matches = udev_enumerate_new (manager->udev_context);
   udev_enumerate_add_match_is_initialized(card_matches);
   udev_enumerate_add_match_parent (card_matches, udev_device_get_parent (fb_device));
   udev_enumerate_add_match_subsystem (card_matches, "drm");
   id_path = udev_device_get_property_value (fb_device, "ID_PATH");
   udev_enumerate_add_match_property (card_matches, "ID_PATH", id_path);
 
   ply_trace ("trying to find associated drm node for fb device (path: %s)", id_path);
 
@@ -162,104 +135,105 @@ fb_device_has_drm_device (ply_device_manager_t *manager,
 
   if (card_entry != NULL)
     {
       struct udev_device *card_device = NULL;
       const char *card_node;
       const char *card_path;
 
       card_path = udev_list_entry_get_name (card_entry);
       card_device = udev_device_new_from_syspath (manager->udev_context, card_path);
       card_node = udev_device_get_devnode (card_device);
       if (card_node != NULL && drm_device_in_use (manager, card_node))
         has_drm_device = true;
       else
         ply_trace ("no card node!");
 
       udev_device_unref (card_device);
     }
   else
     {
       ply_trace ("no card entry!");
     }
 
   udev_enumerate_unref (card_matches);
   return has_drm_device;
 }
 
 static void
 create_devices_for_udev_device (ply_device_manager_t *manager,
                                 struct udev_device   *device)
 {
-  bool for_local_console;
   const char *device_path;
-  ply_terminal_t *terminal = NULL;
-
-  for_local_console = device_is_for_local_console (manager, device);
-
-  ply_trace ("device is for local console: %s", for_local_console? "yes" : "no");
-
-  if (for_local_console)
-    terminal = manager->local_console_terminal;
 
   device_path = udev_device_get_devnode (device);
 
   if (device_path != NULL)
     {
       const char *subsystem;
+
       ply_renderer_type_t renderer_type = PLY_RENDERER_TYPE_NONE;
 
       subsystem = udev_device_get_subsystem (device);
       ply_trace ("device subsystem is %s", subsystem);
 
       if (subsystem != NULL && strcmp (subsystem, SUBSYSTEM_DRM) == 0)
         {
           ply_trace ("found DRM device %s", device_path);
           renderer_type = PLY_RENDERER_TYPE_DRM;
         }
       else if (strcmp (subsystem, SUBSYSTEM_FRAME_BUFFER) == 0)
         {
           ply_trace ("found frame buffer device %s", device_path);
           if (!fb_device_has_drm_device (manager, device))
             {
               renderer_type = PLY_RENDERER_TYPE_FRAME_BUFFER;
             }
           else
             {
               ply_trace ("ignoring, since there's a DRM device associated with it");
             }
         }
 
       if (renderer_type != PLY_RENDERER_TYPE_NONE)
-        create_devices_for_terminal_and_renderer_type (manager,
-                                                       device_path,
-                                                       terminal,
-                                                       renderer_type);
+        {
+          ply_terminal_t *terminal = NULL;
+
+          if (!manager->local_console_managed)
+            {
+              terminal = manager->local_console_terminal;
+            }
+
+          create_devices_for_terminal_and_renderer_type (manager,
+                                                         device_path,
+                                                         terminal,
+                                                         renderer_type);
+       }
     }
 }
 
 static void
 free_displays_for_renderer (ply_device_manager_t *manager,
                             ply_renderer_t       *renderer)
 {
   ply_list_node_t *node;
 
   node = ply_list_get_first_node (manager->pixel_displays);
   while (node != NULL)
     {
       ply_list_node_t *next_node;
       ply_pixel_display_t *display;
       ply_renderer_t *display_renderer;
 
       display = ply_list_node_get_data (node);
       next_node = ply_list_get_next_node (manager->pixel_displays, node);
       display_renderer = ply_pixel_display_get_renderer (display);
 
       if (display_renderer == renderer)
         {
           if (manager->pixel_display_removed_handler != NULL)
             manager->pixel_display_removed_handler (manager->event_handler_data, display);
 
           ply_pixel_display_free (display);
           ply_list_remove_node (manager->pixel_displays, node);
         }
 
       node = next_node;
@@ -687,126 +661,121 @@ create_text_displays_for_terminal (ply_device_manager_t *manager,
 
   if (!ply_terminal_is_open (terminal))
     {
       if (!ply_terminal_open (terminal))
         {
           ply_trace ("could not add terminal %s: %m",
                      ply_terminal_get_name (terminal));
           return;
         }
     }
 
   ply_trace ("adding text display for terminal %s",
              ply_terminal_get_name (terminal));
 
   display = ply_text_display_new (terminal);
   ply_list_append_data (manager->text_displays, display);
 
   if (manager->text_display_added_handler != NULL)
     manager->text_display_added_handler (manager->event_handler_data, display);
 }
 
 static void
 create_devices_for_terminal_and_renderer_type (ply_device_manager_t *manager,
                                                const char           *device_path,
                                                ply_terminal_t       *terminal,
                                                ply_renderer_type_t   renderer_type)
 {
   ply_renderer_t *renderer = NULL;
   ply_keyboard_t *keyboard = NULL;
 
-  bool is_local_terminal = false;
-
-  if (terminal != NULL && manager->local_console_terminal == terminal)
-    is_local_terminal = true;
+  renderer = ply_hashtable_lookup (manager->renderers, (void *) device_path);
 
-  if (is_local_terminal && manager->local_console_managed)
+  if (renderer != NULL)
     {
-      ply_trace ("trying to create devices for local console when one already exists");
+      ply_trace ("ignoring device %s since it's already managed",
+                 device_path);
       return;
     }
 
   ply_trace ("creating devices for %s (renderer type: %u) (terminal: %s)",
              device_path? : "", renderer_type, terminal? ply_terminal_get_name (terminal): "none");
 
   if (renderer_type != PLY_RENDERER_TYPE_NONE)
     {
       renderer = ply_renderer_new (renderer_type, device_path, terminal);
 
       if (!ply_renderer_open (renderer))
         {
           ply_trace ("could not open renderer for %s", device_path);
           ply_renderer_free (renderer);
           renderer = NULL;
           if (renderer_type != PLY_RENDERER_TYPE_AUTO)
             return;
         }
     }
 
   if (renderer != NULL)
     {
       keyboard = ply_keyboard_new_for_renderer (renderer);
       ply_list_append_data (manager->keyboards, keyboard);
 
       if (manager->keyboard_added_handler != NULL)
         manager->keyboard_added_handler (manager->event_handler_data, keyboard);
 
       create_pixel_displays_for_renderer (manager, renderer);
       ply_hashtable_insert (manager->renderers, strdup (device_path), renderer);
     }
   else if (terminal != NULL)
     {
       keyboard = ply_keyboard_new_for_terminal (terminal);
       ply_list_append_data (manager->keyboards, keyboard);
 
       if (manager->keyboard_added_handler != NULL)
         manager->keyboard_added_handler (manager->event_handler_data, keyboard);
     }
 
   if (terminal != NULL)
     {
       create_text_displays_for_terminal (manager, terminal);
 
-      if (is_local_terminal)
+      if (terminal == manager->local_console_terminal)
         {
-          manager->local_console_is_text = true;
+          manager->local_console_is_text = renderer == NULL;
+          manager->local_console_managed = true;
         }
     }
 
   if (keyboard != NULL)
     {
       ply_keyboard_watch_for_input (keyboard);
     }
-
-  if (is_local_terminal)
-    manager->local_console_managed = true;
-
 }
 
 static void
 create_devices_for_terminal (const char           *device_path,
                              ply_terminal_t       *terminal,
                              ply_device_manager_t *manager)
 {
   create_devices_for_terminal_and_renderer_type (manager,
                                                  device_path,
                                                  terminal,
                                                  PLY_RENDERER_TYPE_NONE);
 }
 static bool
 create_devices_from_terminals (ply_device_manager_t *manager)
 {
   bool has_serial_consoles;
 
   ply_trace ("checking for consoles");
 
   if (manager->flags & PLY_DEVICE_MANAGER_FLAGS_IGNORE_SERIAL_CONSOLES)
     {
       has_serial_consoles = false;
       ply_trace ("ignoring all consoles but default console because explicitly told to.");
     }
   else
     {
       has_serial_consoles = add_consoles_from_file (manager, "/sys/class/tty/console/active");
     }
 
   if (has_serial_consoles)
-- 
2.3.7


From 595557cfde30b99fc9d1789b305c2f80a576c502 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 24 Jul 2015 16:23:00 -0400
Subject: [PATCH 6/8] device-manager: force details if serial consoles are used

it's better to skip trying to load the default splash rather than
relying on it failing and falling back.
---
 src/libply-splash-core/ply-device-manager.c | 9 +++++++++
 src/libply-splash-core/ply-device-manager.h | 1 +
 src/main.c                                  | 3 +++
 3 files changed, 13 insertions(+)

diff --git a/src/libply-splash-core/ply-device-manager.c b/src/libply-splash-core/ply-device-manager.c
index b90a0f6..787e67c 100644
--- a/src/libply-splash-core/ply-device-manager.c
+++ b/src/libply-splash-core/ply-device-manager.c
@@ -44,60 +44,61 @@
 static void create_devices_for_terminal_and_renderer_type (ply_device_manager_t *manager,
                                                            const char           *device_path,
                                                            ply_terminal_t       *terminal,
                                                            ply_renderer_type_t   renderer_type);
 struct _ply_device_manager
 {
   ply_device_manager_flags_t  flags;
   ply_event_loop_t           *loop;
   ply_hashtable_t            *terminals;
   ply_hashtable_t            *renderers;
   ply_terminal_t             *local_console_terminal;
   ply_list_t                 *keyboards;
   ply_list_t                 *text_displays;
   ply_list_t                 *pixel_displays;
   struct udev                *udev_context;
   struct udev_queue          *udev_queue;
   int                         udev_queue_fd;
   ply_fd_watch_t             *udev_queue_fd_watch;
   struct udev_monitor        *udev_monitor;
 
   ply_keyboard_added_handler_t         keyboard_added_handler;
   ply_keyboard_removed_handler_t       keyboard_removed_handler;
   ply_pixel_display_added_handler_t    pixel_display_added_handler;
   ply_pixel_display_removed_handler_t  pixel_display_removed_handler;
   ply_text_display_added_handler_t     text_display_added_handler;
   ply_text_display_removed_handler_t   text_display_removed_handler;
   void                                *event_handler_data;
 
   uint32_t                    local_console_managed : 1;
   uint32_t                    local_console_is_text : 1;
+  uint32_t                    serial_consoles_detected : 1;
 };
 
 static void
 detach_from_event_loop (ply_device_manager_t *manager)
 {
   assert (manager != NULL);
 
   manager->loop = NULL;
 }
 
 static void
 attach_to_event_loop (ply_device_manager_t *manager,
                       ply_event_loop_t     *loop)
 {
   assert (manager != NULL);
   assert (loop != NULL);
   assert (manager->loop == NULL);
 
   manager->loop = loop;
 
   ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t)
                                  detach_from_event_loop,
                                  manager);
 }
 
 static bool
 drm_device_in_use (ply_device_manager_t *manager,
                    const char           *device_path)
 {
   ply_renderer_t *renderer;
@@ -754,60 +755,62 @@ create_devices_for_terminal_and_renderer_type (ply_device_manager_t *manager,
 static void
 create_devices_for_terminal (const char           *device_path,
                              ply_terminal_t       *terminal,
                              ply_device_manager_t *manager)
 {
   create_devices_for_terminal_and_renderer_type (manager,
                                                  device_path,
                                                  terminal,
                                                  PLY_RENDERER_TYPE_NONE);
 }
 static bool
 create_devices_from_terminals (ply_device_manager_t *manager)
 {
   bool has_serial_consoles;
 
   ply_trace ("checking for consoles");
 
   if (manager->flags & PLY_DEVICE_MANAGER_FLAGS_IGNORE_SERIAL_CONSOLES)
     {
       has_serial_consoles = false;
       ply_trace ("ignoring all consoles but default console because explicitly told to.");
     }
   else
     {
       has_serial_consoles = add_consoles_from_file (manager, "/sys/class/tty/console/active");
     }
 
   if (has_serial_consoles)
     {
       ply_trace ("serial consoles detected, managing them with details forced");
+      manager->serial_consoles_detected = true;
+
       ply_hashtable_foreach (manager->terminals,
                              (ply_hashtable_foreach_func_t *)
                              create_devices_for_terminal,
                              manager);
       return true;
     }
 
   return false;
 }
 
 static void
 create_devices_from_udev (ply_device_manager_t *manager)
 {
   bool found_drm_device, found_fb_device;
 
   ply_trace ("Looking for devices from udev");
 
   found_drm_device = create_devices_for_subsystem (manager, SUBSYSTEM_DRM);
   found_fb_device = create_devices_for_subsystem (manager, SUBSYSTEM_FRAME_BUFFER);
 
   if (found_drm_device || found_fb_device)
     return;
 
   ply_trace ("Creating non-graphical devices, since there's no suitable graphics hardware");
   create_devices_for_terminal_and_renderer_type (manager,
                                                  ply_terminal_get_name (manager->local_console_terminal),
                                                  manager->local_console_terminal,
                                                  PLY_RENDERER_TYPE_NONE);
 }
 
@@ -921,60 +924,66 @@ bool
 ply_device_manager_has_displays (ply_device_manager_t *manager)
 {
   return ply_list_get_length (manager->pixel_displays) > 0 ||
          ply_list_get_length (manager->text_displays) > 0;
 }
 
 ply_list_t *
 ply_device_manager_get_keyboards (ply_device_manager_t *manager)
 {
   return manager->keyboards;
 }
 
 ply_list_t *
 ply_device_manager_get_pixel_displays (ply_device_manager_t *manager)
 {
   return manager->pixel_displays;
 }
 
 ply_list_t *
 ply_device_manager_get_text_displays (ply_device_manager_t *manager)
 {
   return manager->text_displays;
 }
 
 ply_terminal_t *
 ply_device_manager_get_default_terminal (ply_device_manager_t *manager)
 {
   return manager->local_console_terminal;
 }
 
+bool
+ply_device_manager_has_serial_consoles (ply_device_manager_t *manager)
+{
+  return manager->serial_consoles_detected;
+}
+
 static void
 activate_renderer (char                 *device_path,
                    ply_renderer_t       *renderer,
                    ply_device_manager_t *manager)
 {
   ply_renderer_activate (renderer);
 }
 
 void
 ply_device_manager_activate_renderers (ply_device_manager_t *manager)
 {
   ply_trace ("activating renderers");
   ply_hashtable_foreach (manager->renderers,
                          (ply_hashtable_foreach_func_t *)
                          activate_renderer,
                          manager);
 }
 
 static void
 deactivate_renderer (char                 *device_path,
                      ply_renderer_t       *renderer,
                      ply_device_manager_t *manager)
 {
   ply_renderer_deactivate (renderer);
 }
 
 void
 ply_device_manager_deactivate_renderers (ply_device_manager_t *manager)
 {
   ply_trace ("deactivating renderers");
diff --git a/src/libply-splash-core/ply-device-manager.h b/src/libply-splash-core/ply-device-manager.h
index b628e41..558aabe 100644
--- a/src/libply-splash-core/ply-device-manager.h
+++ b/src/libply-splash-core/ply-device-manager.h
@@ -26,45 +26,46 @@
 #include "ply-pixel-display.h"
 #include "ply-renderer.h"
 #include "ply-text-display.h"
 
 typedef enum
 {
   PLY_DEVICE_MANAGER_FLAGS_NONE                   = 0,
   PLY_DEVICE_MANAGER_FLAGS_IGNORE_SERIAL_CONSOLES = 1 << 0,
   PLY_DEVICE_MANAGER_FLAGS_IGNORE_UDEV            = 1 << 1
 } ply_device_manager_flags_t;
 
 typedef struct _ply_device_manager ply_device_manager_t;
 typedef void (* ply_keyboard_added_handler_t) (void *, ply_keyboard_t *);
 typedef void (* ply_keyboard_removed_handler_t) (void *, ply_keyboard_t *);
 typedef void (* ply_pixel_display_added_handler_t) (void *, ply_pixel_display_t *);
 typedef void (* ply_pixel_display_removed_handler_t) (void *, ply_pixel_display_t *);
 typedef void (* ply_text_display_added_handler_t) (void *, ply_text_display_t *);
 typedef void (* ply_text_display_removed_handler_t) (void *, ply_text_display_t *);
 
 #ifndef PLY_HIDE_FUNCTION_DECLARATIONS
 ply_device_manager_t *ply_device_manager_new (const char                 *default_tty,
                                               ply_device_manager_flags_t  flags);
 void ply_device_manager_watch_devices (ply_device_manager_t                *manager,
                                        ply_keyboard_added_handler_t         keyboard_added_handler,
                                        ply_keyboard_removed_handler_t       keyboard_removed_handler,
                                        ply_pixel_display_added_handler_t    pixel_display_added_handler,
                                        ply_pixel_display_removed_handler_t  pixel_display_removed_handler,
                                        ply_text_display_added_handler_t     text_display_added_handler,
                                        ply_text_display_removed_handler_t   text_display_removed_handler,
                                        void                                *data);
+bool ply_device_manager_has_serial_consoles (ply_device_manager_t *manager);
 bool ply_device_manager_has_displays (ply_device_manager_t *manager);
 ply_list_t *ply_device_manager_get_keyboards (ply_device_manager_t *manager);
 ply_list_t *ply_device_manager_get_pixel_displays (ply_device_manager_t *manager);
 ply_list_t *ply_device_manager_get_text_displays (ply_device_manager_t *manager);
 void ply_device_manager_free (ply_device_manager_t *manager);
 void ply_device_manager_activate_keyboards (ply_device_manager_t *manager);
 void ply_device_manager_deactivate_keyboards (ply_device_manager_t *manager);
 void ply_device_manager_activate_renderers (ply_device_manager_t *manager);
 void ply_device_manager_deactivate_renderers (ply_device_manager_t *manager);
 ply_terminal_t *ply_device_manager_get_default_terminal (ply_device_manager_t *manager);
 
 #endif
 
 #endif
 /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
diff --git a/src/main.c b/src/main.c
index ec46199..875dd1a 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1086,60 +1086,63 @@ static void
 on_text_display_removed (state_t                   *state,
                          ply_text_display_t *display)
 {
   if (state->boot_splash == NULL)
     return;
 
   ply_boot_splash_remove_text_display (state->boot_splash, display);
 }
 
 static void
 load_devices (state_t                    *state,
               ply_device_manager_flags_t  flags)
 {
   state->device_manager = ply_device_manager_new (state->default_tty, flags);
   state->local_console_terminal = ply_device_manager_get_default_terminal (state->device_manager);
 
   ply_device_manager_watch_devices (state->device_manager,
                                     (ply_keyboard_added_handler_t)
                                     on_keyboard_added,
                                     (ply_keyboard_removed_handler_t)
                                     on_keyboard_removed,
                                     (ply_pixel_display_added_handler_t)
                                     on_pixel_display_added,
                                     (ply_pixel_display_removed_handler_t)
                                     on_pixel_display_removed,
                                     (ply_text_display_added_handler_t)
                                     on_text_display_added,
                                     (ply_text_display_removed_handler_t)
                                     on_text_display_removed,
                                     state);
+
+  if (ply_device_manager_has_serial_consoles (state->device_manager))
+    state->should_force_details = true;
 }
 
 static void
 quit_splash (state_t *state)
 {
   ply_trace ("quiting splash");
   if (state->boot_splash != NULL)
     {
       ply_trace ("freeing splash");
       ply_boot_splash_free (state->boot_splash);
       state->boot_splash = NULL;
     }
 
   ply_device_manager_deactivate_keyboards (state->device_manager);
 
   if (state->local_console_terminal != NULL)
     {
       if (!state->should_retain_splash)
         {
           ply_trace ("Not retaining splash, so deallocating VT");
           ply_terminal_deactivate_vt (state->local_console_terminal);
           ply_terminal_close (state->local_console_terminal);
         }
     }
 
   detach_from_running_session (state);
 }
 
 static void
 hide_splash (state_t *state)
-- 
2.3.7


From 6c06eb9a42df75b637b7390ef60e06a3f6c7965c Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 28 Jul 2015 10:00:25 -0400
Subject: [PATCH 7/8] animation,throbber: allow calling stop after animation is
 stopped

Right now if a user calls ply_throbber_stop or ply_animation_stop
after the animation is stopped things malfunction.  In the case
of the throbber we end up never calling the stop completion handler
passed in, and in the case of the animation, we end up setting
some state that shouldn't be set.

This commit checks if the animation and throbber objects are stopped,
and if so does the necessary steps to process the late stop request.
---
 src/libply-splash-graphics/ply-animation.c |  6 ++++++
 src/libply-splash-graphics/ply-throbber.c  | 10 ++++++++++
 2 files changed, 16 insertions(+)

diff --git a/src/libply-splash-graphics/ply-animation.c b/src/libply-splash-graphics/ply-animation.c
index bba8490..2f24812 100644
--- a/src/libply-splash-graphics/ply-animation.c
+++ b/src/libply-splash-graphics/ply-animation.c
@@ -348,60 +348,66 @@ ply_animation_start (ply_animation_t    *animation,
 
   ply_event_loop_watch_for_timeout (animation->loop,
                                     1.0 / FRAMES_PER_SECOND,
                                     (ply_event_loop_timeout_handler_t)
                                     on_timeout, animation);
 
   return true;
 }
 
 static void
 ply_animation_stop_now (ply_animation_t *animation)
 {
   animation->is_stopped = true;
 
   ply_trace ("stopping animation now");
 
   if (animation->loop != NULL)
     {
       ply_event_loop_stop_watching_for_timeout (animation->loop,
                                                 (ply_event_loop_timeout_handler_t)
                                                 on_timeout, animation);
       animation->loop = NULL;
     }
 
   animation->display = NULL;
 }
 
 void
 ply_animation_stop (ply_animation_t *animation)
 {
+  if (animation->is_stopped)
+    {
+      ply_trace ("animation already stopped, ignoring stop request");
+      return;
+    }
+
   if (animation->stop_trigger == NULL)
     {
       ply_animation_stop_now (animation);
       return;
     }
 
   ply_trace ("stopping animation next time through the loop");
   animation->stop_requested = true;
 }
 
 bool
 ply_animation_is_stopped (ply_animation_t *animation)
 {
   return animation->is_stopped;
 }
 
 void
 ply_animation_draw_area (ply_animation_t    *animation,
                          ply_pixel_buffer_t *buffer,
                          long                x,
                          long                y,
                          unsigned long       width,
                          unsigned long       height)
 {
   ply_pixel_buffer_t * const * frames;
   int number_of_frames;
   int frame_index;
   
   if (animation->is_stopped)
     return;
diff --git a/src/libply-splash-graphics/ply-throbber.c b/src/libply-splash-graphics/ply-throbber.c
index 42044ba..d4594b8 100644
--- a/src/libply-splash-graphics/ply-throbber.c
+++ b/src/libply-splash-graphics/ply-throbber.c
@@ -320,60 +320,70 @@ ply_throbber_start (ply_throbber_t       *throbber,
                                     (ply_event_loop_timeout_handler_t)
                                     on_timeout, throbber);
 
   return true;
 }
 
 static void
 ply_throbber_stop_now (ply_throbber_t *throbber)
 {
   throbber->is_stopped = true;
 
   ply_pixel_display_draw_area (throbber->display,
                                throbber->x,
                                throbber->y,
                                throbber->frame_area.width,
                                throbber->frame_area.height);
   if (throbber->loop != NULL)
     {
       ply_event_loop_stop_watching_for_timeout (throbber->loop,
                                                 (ply_event_loop_timeout_handler_t)
                                                 on_timeout, throbber);
       throbber->loop = NULL;
     }
   throbber->display = NULL;
 }
 
 void
 ply_throbber_stop (ply_throbber_t *throbber,
                    ply_trigger_t  *stop_trigger)
 {
+  if (throbber->is_stopped)
+    {
+      ply_trace ("throbber already stopped");
+      if (stop_trigger != NULL)
+        {
+          ply_trace ("pulling stop trigger right away");
+          ply_trigger_pull (stop_trigger, NULL);
+        }
+      return;
+    }
 
   if (stop_trigger == NULL)
     {
       ply_throbber_stop_now (throbber);
       return;
     }
 
   throbber->stop_trigger = stop_trigger;
 }
 
 bool
 ply_throbber_is_stopped (ply_throbber_t *throbber)
 {
   return throbber->is_stopped;
 }
 
 void
 ply_throbber_draw_area (ply_throbber_t     *throbber,
                         ply_pixel_buffer_t *buffer,
                         long                x,
                         long                y,
                         unsigned long       width,
                         unsigned long       height)
 {
   ply_pixel_buffer_t * const * frames;
 
   if (throbber->is_stopped)
     return;
 
   frames = (ply_pixel_buffer_t * const *) ply_array_get_pointer_elements (throbber->frames);
-- 
2.3.7

From 80e71304093c163e338168d27bfdb3552c9aa242 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 10 Aug 2015 10:11:32 -0400
Subject: [PATCH 8/8] boot-splash: don't crash in free if module not loaded

ply_boot_splash_free currently calls some code that depends
on a module being loaded.  We call ply_boot_splash_free to
clean up the boot splash object if a module can't be loaded,
leading to crash.

This commit addresses that issue by only calling the module
specific destruction code in ply_boot_splash_free in the case
where a module is loaded.

https://bugs.freedesktop.org/show_bug.cgi?id=91590
---
 src/libply-splash-core/ply-boot-splash.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/src/libply-splash-core/ply-boot-splash.c b/src/libply-splash-core/ply-boot-splash.c
index f7fc70f..664acc3 100644
--- a/src/libply-splash-core/ply-boot-splash.c
+++ b/src/libply-splash-core/ply-boot-splash.c
@@ -383,70 +383,72 @@ remove_text_displays (ply_boot_splash_t *splash)
 
       ply_trace ("Removing %dx%d text display", number_of_columns, number_of_rows);
 
       splash->plugin_interface->remove_text_display (splash->plugin, display);
 
       node = next_node;
     }
 }
 
 void
 ply_boot_splash_free (ply_boot_splash_t *splash)
 {
   ply_trace ("freeing splash");
   if (splash == NULL)
     return;
 
   if (splash->loop != NULL)
     {
       if (splash->plugin_interface->on_boot_progress != NULL)
         {
           ply_event_loop_stop_watching_for_timeout (splash->loop,
                                                     (ply_event_loop_timeout_handler_t)
                                                     ply_boot_splash_update_progress, splash);
         }
 
       ply_event_loop_stop_watching_for_exit (splash->loop, (ply_event_loop_exit_handler_t)
                                              ply_boot_splash_detach_from_event_loop,
                                              splash);
     }
 
-  ply_boot_splash_unset_keyboard (splash);
+  if (splash->module_handle != NULL)
+    {
+      ply_boot_splash_unset_keyboard (splash);
 
-  remove_pixel_displays (splash);
-  ply_list_free (splash->pixel_displays);
+      remove_pixel_displays (splash);
+      ply_list_free (splash->pixel_displays);
 
-  remove_text_displays (splash);
-  ply_list_free (splash->text_displays);
+      remove_text_displays (splash);
+      ply_list_free (splash->text_displays);
 
-  if (splash->module_handle != NULL)
-    ply_boot_splash_unload (splash);
+      ply_boot_splash_unload (splash);
+    }
 
   if (splash->idle_trigger != NULL)
     ply_trigger_free (splash->idle_trigger);
 
   free (splash->theme_path);
   free (splash->plugin_dir);
   free (splash);
 }
 
 static void
 ply_boot_splash_update_progress (ply_boot_splash_t *splash)
 {
   double percentage=0.0;
   double time=0.0;
 
   assert (splash != NULL);
 
   if (splash->progress)
     {
       percentage = ply_progress_get_percentage(splash->progress);
       time = ply_progress_get_time(splash->progress);
     }
 
   if (splash->plugin_interface->on_boot_progress != NULL)
     splash->plugin_interface->on_boot_progress (splash->plugin,
                                                 time,
                                                 percentage);
 
   ply_event_loop_watch_for_timeout (splash->loop,
                                    1.0 / UPDATES_PER_SECOND,
-- 
2.5.0