[PATCH 01/21] [terminal] merge console and terminal code

Scott James Remnant scott at ubuntu.com
Wed Mar 17 20:21:01 PDT 2010


This removes the separation in code of "console" functions and
"terminal" functions; this never really made sense, and doesn't
particularly map to the behaviour of Linux virtual terminals.

The three principle operations that Plymouth was using "console"
for were:

 * changing the active VT
 * notification of changes to the active VT through VT_PROCESS
 * switching between text and graphics mode

And it was using the "foreground terminal" alias /dev/tty0 to do
this.  While this is fine for the first of those, since any console
device will do, it's always wrong for the latter two which should
always be on the actual VT we want Plymouth to run from.

If running on tty7, only tty7 should be in VT_PROCESS mode (since
we want to know when we enter this VT and leave this VT), and
certainly only tty7 should be in graphics mode.

Since you can use that same tty to obtain the current active VT,
and switch VT, you don't need another; so the need for a separate
"console" functionality goes away.
---
 src/libply-splash-core/ply-terminal.c |  285 ++++++++++++++++++++++++++++++---
 src/libply-splash-core/ply-terminal.h |   24 +++
 2 files changed, 288 insertions(+), 21 deletions(-)

diff --git a/src/libply-splash-core/ply-terminal.c b/src/libply-splash-core/ply-terminal.c
index ea9349c..ed08657 100644
--- a/src/libply-splash-core/ply-terminal.c
+++ b/src/libply-splash-core/ply-terminal.c
@@ -50,6 +50,12 @@
 #define TEXT_PALETTE_SIZE 48
 #endif
 
+typedef struct
+{
+  ply_terminal_active_vt_changed_handler_t handler;
+  void *user_data;
+} ply_terminal_active_vt_changed_closure_t;
+
 struct _ply_terminal
 {
   ply_event_loop_t *loop;
@@ -59,7 +65,10 @@ struct _ply_terminal
   char *name;
   int   fd;
   int   vt_number;
+  int   active_vt;
+  int   next_active_vt;
 
+  ply_list_t *vt_change_closures;
   ply_fd_watch_t *fd_watch;
   ply_terminal_color_t foreground_color;
   ply_terminal_color_t background_color;
@@ -73,6 +82,8 @@ struct _ply_terminal
   uint32_t original_term_attributes_saved : 1;
   uint32_t supports_text_color : 1;
   uint32_t is_open : 1;
+  uint32_t is_watching_for_vt_changes : 1;
+  uint32_t should_ignore_mode_changes : 1;
 };
 
 static bool ply_terminal_open_device (ply_terminal_t *terminal);
@@ -85,6 +96,7 @@ ply_terminal_new (const char *device_name)
   terminal = calloc (1, sizeof (ply_terminal_t));
 
   terminal->loop = ply_event_loop_get_default ();
+  terminal->vt_change_closures = ply_list_new ();
   if (device_name != NULL)
     {
       if (strncmp (device_name, "/dev/", strlen ("/dev/")) == 0)
@@ -243,27 +255,6 @@ on_tty_disconnected (ply_terminal_t *terminal)
     }
 }
 
-static int
-get_active_vt (void)
-{
-  int console_fd;
-  struct vt_stat console_state = { 0 };
-
-  console_fd = open ("/dev/tty0", O_RDONLY | O_NOCTTY);
-
-  if (console_fd < 0)
-    goto out;
-
-  if (ioctl (console_fd, VT_GETSTATE, &console_state) < 0)
-    goto out;
-
-out:
-  if (console_fd >= 0)
-    close (console_fd);
-
-  return console_state.v_active;
-}
-
 static bool
 ply_terminal_look_up_geometry (ply_terminal_t *terminal)
 {
@@ -310,6 +301,133 @@ ply_terminal_check_for_vt (ply_terminal_t *terminal)
     terminal->vt_number = -1;
 }
 
+static int
+get_active_vt (void)
+{
+  int console_fd;
+  struct vt_stat console_state = { 0 };
+
+  console_fd = open ("/dev/tty0", O_RDONLY | O_NOCTTY);
+
+  if (console_fd < 0)
+    goto out;
+
+  if (ioctl (console_fd, VT_GETSTATE, &console_state) < 0)
+    goto out;
+
+out:
+  if (console_fd >= 0)
+    close (console_fd);
+
+  return console_state.v_active;
+}
+
+static void
+ply_terminal_look_up_active_vt (ply_terminal_t *terminal)
+{
+  struct vt_stat terminal_state = { 0 };
+
+  if (ioctl (terminal->fd, VT_GETSTATE, &terminal_state) < 0)
+    return;
+
+  terminal->active_vt = terminal_state.v_active;
+}
+
+static void
+do_active_vt_changed (ply_terminal_t *terminal)
+{
+  ply_list_node_t *node;
+
+  node = ply_list_get_first_node (terminal->vt_change_closures);
+  while (node != NULL)
+    {
+      ply_terminal_active_vt_changed_closure_t *closure;
+      ply_list_node_t *next_node;
+
+      closure = ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (terminal->vt_change_closures, node);
+
+      if (closure->handler != NULL)
+        closure->handler (closure->user_data, terminal);
+
+      node = next_node;
+    }
+}
+
+static void
+on_leave_vt (ply_terminal_t *terminal)
+{
+  ioctl (terminal->fd, VT_RELDISP, 1);
+
+  if (terminal->next_active_vt > 0)
+    {
+      ioctl (terminal->fd, VT_WAITACTIVE, terminal->next_active_vt);
+      terminal->next_active_vt = 0;
+    }
+
+  ply_terminal_look_up_active_vt (terminal);
+  do_active_vt_changed (terminal);
+}
+
+static void
+on_enter_vt (ply_terminal_t *terminal)
+{
+  ioctl (terminal->fd, VT_RELDISP, VT_ACKACQ);
+
+  ply_terminal_look_up_active_vt (terminal);
+  do_active_vt_changed (terminal);
+}
+
+static void
+ply_terminal_watch_for_vt_changes (ply_terminal_t *terminal)
+{
+  assert (terminal != NULL);
+
+  struct vt_mode mode = { 0 };
+
+  if (terminal->fd < 0)
+    return;
+
+  if (terminal->is_watching_for_vt_changes)
+    return;
+
+  mode.mode = VT_PROCESS;
+  mode.relsig = SIGUSR1;
+  mode.acqsig = SIGUSR2;
+
+  if (ioctl (terminal->fd, VT_SETMODE, &mode) < 0)
+    return;
+
+  ply_event_loop_watch_signal (terminal->loop,
+                               SIGUSR1,
+                               (ply_event_handler_t)
+                               on_leave_vt, terminal);
+
+  ply_event_loop_watch_signal (terminal->loop,
+                               SIGUSR2,
+                               (ply_event_handler_t)
+                               on_enter_vt, terminal);
+
+  terminal->is_watching_for_vt_changes = true;
+}
+
+static void
+ply_terminal_stop_watching_for_vt_changes (ply_terminal_t *terminal)
+{
+  struct vt_mode mode = { 0 };
+
+  if (!terminal->is_watching_for_vt_changes)
+    return;
+
+  terminal->is_watching_for_vt_changes = false;
+
+  ply_event_loop_stop_watching_signal (terminal->loop, SIGUSR1);
+  ply_event_loop_stop_watching_signal (terminal->loop, SIGUSR2);
+
+  mode.mode = VT_AUTO;
+  ioctl (terminal->fd, VT_SETMODE, &mode);
+}
+
 static bool
 ply_terminal_open_device (ply_terminal_t *terminal)
 {
@@ -330,6 +448,7 @@ ply_terminal_open_device (ply_terminal_t *terminal)
                                                    terminal);
 
   ply_terminal_check_for_vt (terminal);
+  ply_terminal_look_up_active_vt (terminal);
 
   if (!ply_terminal_set_unbuffered_input (terminal))
     ply_trace ("terminal '%s' will be line buffered", terminal->name);
@@ -376,6 +495,8 @@ ply_terminal_open (ply_terminal_t *terminal)
                                ply_terminal_look_up_geometry,
                                terminal);
 
+  ply_terminal_watch_for_vt_changes (terminal);
+
   terminal->is_open = true;
 
   return true;
@@ -398,6 +519,8 @@ ply_terminal_close (ply_terminal_t *terminal)
 {
   terminal->is_open = false;
 
+  ply_terminal_stop_watching_for_vt_changes (terminal);
+
   ply_trace ("restoring color palette");
   ply_terminal_restore_color_palette (terminal);
 
@@ -479,6 +602,38 @@ ply_terminal_supports_color (ply_terminal_t *terminal)
   return terminal->supports_text_color;
 }
 
+void
+ply_terminal_set_mode (ply_terminal_t     *terminal,
+                       ply_terminal_mode_t mode)
+{
+
+  assert (terminal != NULL);
+  assert (mode == PLY_TERMINAL_MODE_TEXT || mode == PLY_TERMINAL_MODE_GRAPHICS);
+
+  if (terminal->should_ignore_mode_changes)
+    return;
+
+  switch (mode)
+    {
+      case PLY_TERMINAL_MODE_TEXT:
+        if (ioctl (terminal->fd, KDSETMODE, KD_TEXT) < 0)
+          return;
+        break;
+
+      case PLY_TERMINAL_MODE_GRAPHICS:
+        if (ioctl (terminal->fd, KDSETMODE, KD_GRAPHICS) < 0)
+          return;
+        break;
+    }
+}
+
+void
+ply_terminal_ignore_mode_changes (ply_terminal_t *terminal,
+                                  bool            should_ignore)
+{
+  terminal->should_ignore_mode_changes = should_ignore;
+}
+
 static void
 ply_terminal_detach_from_event_loop (ply_terminal_t *terminal)
 {
@@ -487,6 +642,26 @@ ply_terminal_detach_from_event_loop (ply_terminal_t *terminal)
   terminal->fd_watch = NULL;
 }
 
+static void
+free_vt_change_closures (ply_terminal_t *terminal)
+{
+  ply_list_node_t *node;
+
+  node = ply_list_get_first_node (terminal->vt_change_closures);
+  while (node != NULL)
+    {
+      ply_terminal_active_vt_changed_closure_t *closure;
+      ply_list_node_t *next_node;
+
+      closure = ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (terminal->vt_change_closures, node);
+
+      free (closure);
+      node = next_node;
+    }
+  ply_list_free (terminal->vt_change_closures);
+}
+
 void
 ply_terminal_free (ply_terminal_t *terminal)
 {
@@ -504,6 +679,7 @@ ply_terminal_free (ply_terminal_t *terminal)
   if (terminal->is_open)
     ply_terminal_close (terminal);
 
+  free_vt_change_closures (terminal);
   free (terminal);
 }
 
@@ -513,4 +689,71 @@ ply_terminal_get_vt_number (ply_terminal_t *terminal)
   return terminal->vt_number;
 }
 
+int
+ply_terminal_get_active_vt (ply_terminal_t *terminal)
+{
+  return terminal->active_vt;
+}
+
+bool
+ply_terminal_set_active_vt (ply_terminal_t *terminal,
+                            int             vt_number)
+{
+  assert (terminal != NULL);
+
+  if (vt_number <= 0)
+    return false;
+
+  if (vt_number == terminal->active_vt)
+    return true;
+
+  if (ioctl (terminal->fd, VT_ACTIVATE, vt_number) < 0)
+    return false;
+
+  terminal->next_active_vt = vt_number;
+
+  return true;
+}
+
+void
+ply_terminal_watch_for_active_vt_change (ply_terminal_t *terminal,
+                                         ply_terminal_active_vt_changed_handler_t active_vt_changed_handler,
+                                         void *user_data)
+{
+  ply_terminal_active_vt_changed_closure_t *closure;
+
+  closure = calloc (1, sizeof (*closure));
+  closure->handler = active_vt_changed_handler;
+  closure->user_data = user_data;
+
+  ply_list_append_data (terminal->vt_change_closures, closure);
+}
+
+void
+ply_terminal_stop_watching_for_active_vt_change (ply_terminal_t *terminal,
+                                                 ply_terminal_active_vt_changed_handler_t active_vt_changed_handler,
+                                                 void *user_data)
+{
+  ply_list_node_t *node;
+
+  node = ply_list_get_first_node (terminal->vt_change_closures);
+  while (node != NULL)
+    {
+      ply_terminal_active_vt_changed_closure_t *closure;
+      ply_list_node_t *next_node;
+
+      closure = ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (terminal->vt_change_closures, node);
+
+      if (closure->handler == active_vt_changed_handler &&
+          closure->user_data == user_data)
+        {
+          free (closure);
+          ply_list_remove_node (terminal->vt_change_closures, node);
+        }
+
+      node = next_node;
+    }
+}
+
 /* 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-terminal.h b/src/libply-splash-core/ply-terminal.h
index 21689d1..4b9ef5a 100644
--- a/src/libply-splash-core/ply-terminal.h
+++ b/src/libply-splash-core/ply-terminal.h
@@ -31,6 +31,8 @@
 #include "ply-event-loop.h"
 
 typedef struct _ply_terminal ply_terminal_t;
+typedef void (* ply_terminal_active_vt_changed_handler_t) (void           *user_data,
+                                                           ply_terminal_t *terminal);
 
 typedef enum
 {
@@ -45,6 +47,12 @@ typedef enum
   PLY_TERMINAL_COLOR_DEFAULT = PLY_TERMINAL_COLOR_WHITE + 2
 } ply_terminal_color_t;
 
+typedef enum
+{
+  PLY_TERMINAL_MODE_TEXT,
+  PLY_TERMINAL_MODE_GRAPHICS
+} ply_terminal_mode_t;
+
 #ifndef PLY_HIDE_FUNCTION_DECLARATIONS
 ply_terminal_t *ply_terminal_new (const char *device_name);
 
@@ -74,7 +82,23 @@ void ply_terminal_set_color_hex_value (ply_terminal_t       *terminal,
                                        ply_terminal_color_t  color,
                                        uint32_t              hex_value);
 
+void ply_terminal_set_mode (ply_terminal_t     *terminal,
+                            ply_terminal_mode_t mode);
+
+void ply_terminal_ignore_mode_changes (ply_terminal_t *terminal,
+                                       bool            should_ignore);
+
 int ply_terminal_get_vt_number (ply_terminal_t *terminal);
+int ply_terminal_get_active_vt (ply_terminal_t *terminal);
+bool ply_terminal_set_active_vt (ply_terminal_t *terminal,
+                                 int             vt_number);
+
+void ply_terminal_watch_for_active_vt_change (ply_terminal_t *terminal,
+                                              ply_terminal_active_vt_changed_handler_t active_vt_changed_handler,
+                                              void *user_data);
+void ply_terminal_stop_watching_for_active_vt_change (ply_terminal_t *terminal,
+                                                      ply_terminal_active_vt_changed_handler_t active_vt_changed_handler,
+                                                      void *user_data);
 
 #endif
 
-- 
1.7.0



More information about the plymouth mailing list