e22087
From a54df38f86a534b28c1b664bc283e9b8d17be8a1 Mon Sep 17 00:00:00 2001
e22087
From: Ray Strode <rstrode@redhat.com>
e22087
Date: Thu, 16 Jan 2014 15:44:50 -0500
e22087
Subject: [PATCH 1/2] main: don't rely on show_trigger to cancel show delay
e22087
e22087
We're going to be getting rid of show_trigger in a subsequent
e22087
commit, so this commit changes the code to use the is_shown
e22087
flag instead.
e22087
---
e22087
 src/main.c | 29 ++++++++++++++++-------------
e22087
 1 file changed, 16 insertions(+), 13 deletions(-)
e22087
e22087
diff --git a/src/main.c b/src/main.c
e22087
index bbd74f9..d9032a5 100644
e22087
--- a/src/main.c
e22087
+++ b/src/main.c
e22087
@@ -482,74 +482,77 @@ show_default_splash (state_t *state)
e22087
 
e22087
 static void
e22087
 cancel_pending_delayed_show (state_t *state)
e22087
 {
e22087
   bool has_open_seats;
e22087
 
e22087
   if (isnan (state->splash_delay))
e22087
     return;
e22087
 
e22087
   ply_event_loop_stop_watching_for_timeout (state->loop,
e22087
                                             (ply_event_loop_timeout_handler_t)
e22087
                                             show_splash,
e22087
                                             state);
e22087
   state->splash_delay = NAN;
e22087
   has_open_seats = ply_device_manager_has_open_seats (state->device_manager);
e22087
 
e22087
   if (state->is_shown && has_open_seats)
e22087
     {
e22087
       ply_trace ("splash delay cancelled, showing splash immediately");
e22087
       show_splash (state);
e22087
     }
e22087
 }
e22087
 
e22087
 static void
e22087
 on_ask_for_password (state_t      *state,
e22087
                      const char   *prompt,
e22087
                      ply_trigger_t *answer)
e22087
 {
e22087
   ply_entry_trigger_t *entry_trigger;
e22087
 
e22087
-  /* Waiting to be shown, boot splash will
e22087
-   * arrive shortly so just sit tight
e22087
-   */
e22087
-  if (state->show_trigger != NULL)
e22087
-    {
e22087
-      ply_trace ("splash still coming up, waiting a bit");
e22087
-      cancel_pending_delayed_show (state);
e22087
-    }
e22087
-  else if (state->boot_splash == NULL)
e22087
+  if (state->boot_splash == NULL)
e22087
     {
e22087
-      /* No splash, client will have to get password */
e22087
-      ply_trace ("no splash loaded, replying immediately with no password");
e22087
-      ply_trigger_pull (answer, NULL);
e22087
-      return;
e22087
+      /* Waiting to be shown, boot splash will
e22087
+       * arrive shortly so just sit tight
e22087
+       */
e22087
+      if (state->is_shown)
e22087
+        {
e22087
+          ply_trace ("splash still coming up, waiting a bit");
e22087
+          cancel_pending_delayed_show (state);
e22087
+        }
e22087
+      else
e22087
+        {
e22087
+          /* No splash, client will have to get password */
e22087
+          ply_trace ("no splash loaded, replying immediately with no password");
e22087
+          ply_trigger_pull (answer, NULL);
e22087
+          return;
e22087
+        }
e22087
     }
e22087
 
e22087
   entry_trigger = calloc (1, sizeof (ply_entry_trigger_t));
e22087
   entry_trigger->type = PLY_ENTRY_TRIGGER_TYPE_PASSWORD;
e22087
   entry_trigger->prompt = prompt;
e22087
   entry_trigger->trigger = answer;
e22087
   ply_trace ("queuing password request with boot splash");
e22087
   ply_list_append_data (state->entry_triggers, entry_trigger);
e22087
   update_display (state);
e22087
 }
e22087
 
e22087
 static void
e22087
 on_ask_question (state_t      *state,
e22087
                  const char   *prompt,
e22087
                  ply_trigger_t *answer)
e22087
 {
e22087
   ply_entry_trigger_t *entry_trigger;
e22087
 
e22087
   entry_trigger = calloc (1, sizeof (ply_entry_trigger_t));
e22087
   entry_trigger->type = PLY_ENTRY_TRIGGER_TYPE_QUESTION;
e22087
   entry_trigger->prompt = prompt;
e22087
   entry_trigger->trigger = answer;
e22087
   ply_trace ("queuing question with boot splash");
e22087
   ply_list_append_data (state->entry_triggers, entry_trigger);
e22087
   update_display (state);
e22087
 }
e22087
 
e22087
 static void
e22087
 on_display_message (state_t       *state,
e22087
                     const char    *message)
e22087
-- 
e22087
1.8.3.1
e22087
e22087
e22087
From cdff09d1a2297501f294141182d8d8efcaf6fff3 Mon Sep 17 00:00:00 2001
e22087
From: Ray Strode <rstrode@redhat.com>
e22087
Date: Thu, 16 Jan 2014 15:38:05 -0500
e22087
Subject: [PATCH 2/2] Revert "boot-server: defer show-splash reply until splash
e22087
 shown"
e22087
e22087
This reverts commit 126345af8704a9b10481657d79d66cbea93e1647.
e22087
e22087
If plymouth show-splash blocks until the splash screen is shown,
e22087
then systemd-ask-for-password-plymouth will block for 5 seconds
e22087
before asking for the password (which would have canceled the 5
e22087
second delay if it weren't for the dependency on plymouth-start.service)
e22087
---
e22087
 src/main.c            | 12 +-----------
e22087
 src/ply-boot-server.c | 28 +---------------------------
e22087
 src/ply-boot-server.h |  1 -
e22087
 3 files changed, 2 insertions(+), 39 deletions(-)
e22087
e22087
diff --git a/src/main.c b/src/main.c
e22087
index d9032a5..db1fd0a 100644
e22087
--- a/src/main.c
e22087
+++ b/src/main.c
e22087
@@ -74,61 +74,60 @@ typedef struct
e22087
   const char    *keys;
e22087
   ply_trigger_t *trigger;
e22087
 } ply_keystroke_watch_t;
e22087
 
e22087
 typedef struct 
e22087
 {
e22087
   enum {PLY_ENTRY_TRIGGER_TYPE_PASSWORD,
e22087
         PLY_ENTRY_TRIGGER_TYPE_QUESTION}
e22087
         type;
e22087
   const char    *prompt;
e22087
   ply_trigger_t *trigger;
e22087
 } ply_entry_trigger_t;
e22087
 
e22087
 typedef struct
e22087
 {
e22087
   ply_event_loop_t *loop;
e22087
   ply_boot_server_t *boot_server;
e22087
   ply_boot_splash_t *boot_splash;
e22087
   ply_terminal_session_t *session;
e22087
   ply_buffer_t *boot_buffer;
e22087
   ply_progress_t *progress;
e22087
   ply_list_t *keystroke_triggers;
e22087
   ply_list_t *entry_triggers;
e22087
   ply_buffer_t *entry_buffer;
e22087
   ply_list_t *messages;
e22087
   ply_command_parser_t *command_parser;
e22087
   ply_mode_t mode;
e22087
   ply_terminal_t *local_console_terminal;
e22087
   ply_device_manager_t *device_manager;
e22087
 
e22087
-  ply_trigger_t *show_trigger;
e22087
   ply_trigger_t *deactivate_trigger;
e22087
   ply_trigger_t *quit_trigger;
e22087
 
e22087
   double start_time;
e22087
   double splash_delay;
e22087
 
e22087
   char kernel_command_line[PLY_MAX_COMMAND_LINE_SIZE];
e22087
   uint32_t kernel_command_line_is_set : 1;
e22087
   uint32_t no_boot_log : 1;
e22087
   uint32_t showing_details : 1;
e22087
   uint32_t system_initialized : 1;
e22087
   uint32_t is_redirected : 1;
e22087
   uint32_t is_attached : 1;
e22087
   uint32_t should_be_attached : 1;
e22087
   uint32_t should_retain_splash : 1;
e22087
   uint32_t is_inactive : 1;
e22087
   uint32_t is_shown : 1;
e22087
   uint32_t should_force_details : 1;
e22087
 
e22087
   char *override_splash_path;
e22087
   char *system_default_splash_path;
e22087
   char *distribution_default_splash_path;
e22087
   const char *default_tty;
e22087
 
e22087
   int number_of_errors;
e22087
 } state_t;
e22087
 
e22087
 static void show_splash (state_t *state);
e22087
 static ply_boot_splash_t *load_built_in_theme (state_t *state);
e22087
 static ply_boot_splash_t *load_theme (state_t    *state,
e22087
@@ -848,85 +847,83 @@ plymouth_should_show_default_splash (state_t *state)
e22087
 
e22087
   if (command_line_has_argument (state->kernel_command_line, "splash=verbose"))
e22087
     {
e22087
       ply_trace ("no default splash because kernel command line has option \"splash=verbose\"");
e22087
       return false;
e22087
     }
e22087
 
e22087
   if (command_line_has_argument (state->kernel_command_line, "rhgb"))
e22087
     {
e22087
       ply_trace ("using default splash because kernel command line has option \"rhgb\"");
e22087
       return true;
e22087
     }
e22087
 
e22087
   if (command_line_has_argument (state->kernel_command_line, "splash"))
e22087
     {
e22087
       ply_trace ("using default splash because kernel command line has option \"splash\"");
e22087
       return true;
e22087
     }
e22087
 
e22087
   if (command_line_has_argument (state->kernel_command_line, "splash=silent"))
e22087
     {
e22087
       ply_trace ("using default splash because kernel command line has option \"splash=slient\"");
e22087
       return true;
e22087
     }
e22087
 
e22087
   ply_trace ("no default splash because kernel command line lacks \"splash\" or \"rhgb\"");
e22087
   return false;
e22087
 }
e22087
 
e22087
 static void
e22087
-on_show_splash (state_t       *state,
e22087
-                ply_trigger_t *show_trigger)
e22087
+on_show_splash (state_t *state)
e22087
 {
e22087
   bool has_open_seats;
e22087
 
e22087
   if (state->is_shown)
e22087
     {
e22087
       ply_trace ("show splash called while already shown");
e22087
       return;
e22087
     }
e22087
 
e22087
   if (state->is_inactive)
e22087
     {
e22087
       ply_trace ("show splash called while inactive");
e22087
       return;
e22087
     }
e22087
 
e22087
   if (plymouth_should_ignore_show_splash_calls (state))
e22087
     {
e22087
       ply_trace ("show splash called while ignoring show splash calls");
e22087
       dump_details_and_quit_splash (state);
e22087
       return;
e22087
     }
e22087
 
e22087
-  state->show_trigger = show_trigger;
e22087
   state->is_shown = true;
e22087
   has_open_seats = ply_device_manager_has_open_seats (state->device_manager);
e22087
 
e22087
   if (!state->is_attached && state->should_be_attached && has_open_seats)
e22087
     attach_to_running_session (state);
e22087
 
e22087
   if (has_open_seats)
e22087
     {
e22087
       ply_trace ("at least one seat already open, so loading splash");
e22087
       show_splash (state);
e22087
     }
e22087
   else
e22087
     {
e22087
       ply_trace ("no seats available to show splash on, waiting...");
e22087
     }
e22087
 }
e22087
 
e22087
 static void
e22087
 on_seat_removed (state_t    *state,
e22087
                  ply_seat_t *seat)
e22087
 {
e22087
   ply_keyboard_t *keyboard;
e22087
 
e22087
   keyboard = ply_seat_get_keyboard (seat);
e22087
 
e22087
   ply_trace ("no longer listening for keystrokes");
e22087
   ply_keyboard_remove_input_handler (keyboard,
e22087
                                      (ply_keyboard_input_handler_t)
e22087
                                      on_keyboard_input);
e22087
   ply_trace ("no longer listening for escape");
e22087
@@ -960,67 +957,60 @@ show_splash (state_t *state)
e22087
       running_time = now - state->start_time;
e22087
       if (state->splash_delay > running_time)
e22087
         {
e22087
           double time_left = state->splash_delay - running_time;
e22087
 
e22087
           ply_trace ("delaying show splash for %lf seconds",
e22087
                      time_left);
e22087
           ply_event_loop_stop_watching_for_timeout (state->loop,
e22087
                                                     (ply_event_loop_timeout_handler_t)
e22087
                                                     show_splash,
e22087
                                                     state);
e22087
           ply_event_loop_watch_for_timeout (state->loop,
e22087
                                             time_left,
e22087
                                             (ply_event_loop_timeout_handler_t)
e22087
                                             show_splash,
e22087
                                             state);
e22087
           return;
e22087
         }
e22087
     }
e22087
 
e22087
   if (plymouth_should_show_default_splash (state))
e22087
     {
e22087
       show_default_splash (state);
e22087
       state->showing_details = false;
e22087
     }
e22087
   else
e22087
     {
e22087
       show_detailed_splash (state);
e22087
       state->showing_details = true;
e22087
     }
e22087
-
e22087
-  if (state->show_trigger != NULL)
e22087
-    {
e22087
-      ply_trace ("telling boot server about completed show operation");
e22087
-      ply_trigger_pull (state->show_trigger, NULL);
e22087
-      state->show_trigger = NULL;
e22087
-    }
e22087
 }
e22087
 
e22087
 static void
e22087
 on_seat_added (state_t    *state,
e22087
                ply_seat_t *seat)
e22087
 {
e22087
   ply_keyboard_t *keyboard;
e22087
 
e22087
   if (state->is_shown)
e22087
     {
e22087
       if (state->boot_splash == NULL)
e22087
         {
e22087
           ply_trace ("seat added before splash loaded, so loading splash now");
e22087
           show_splash (state);
e22087
         }
e22087
       else
e22087
         {
e22087
           ply_trace ("seat added after splash loaded, so attaching to splash");
e22087
           ply_boot_splash_attach_to_seat (state->boot_splash, seat);
e22087
         }
e22087
     }
e22087
 
e22087
   keyboard = ply_seat_get_keyboard (seat);
e22087
 
e22087
   ply_trace ("listening for keystrokes");
e22087
   ply_keyboard_add_input_handler (keyboard,
e22087
                                   (ply_keyboard_input_handler_t)
e22087
                                   on_keyboard_input, state);
e22087
   ply_trace ("listening for escape");
e22087
   ply_keyboard_add_escape_handler (keyboard,
e22087
diff --git a/src/ply-boot-server.c b/src/ply-boot-server.c
e22087
index 78c9c52..3e67bfb 100644
e22087
--- a/src/ply-boot-server.c
e22087
+++ b/src/ply-boot-server.c
e22087
@@ -283,72 +283,60 @@ ply_boot_connection_send_answer (ply_boot_connection_t *connection,
e22087
     {
e22087
       size = strlen (answer);
e22087
 
e22087
       if (!ply_write (connection->fd,
e22087
                       PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ANSWER,
e22087
                       strlen (PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ANSWER)) ||
e22087
           !ply_write_uint32 (connection->fd,
e22087
                              size) ||
e22087
           !ply_write (connection->fd,
e22087
                       answer, size))
e22087
           ply_trace ("could not finish writing answer: %m");
e22087
 
e22087
     }
e22087
 
e22087
 }
e22087
 
e22087
 static void
e22087
 ply_boot_connection_on_password_answer (ply_boot_connection_t *connection,
e22087
                                         const char            *password)
e22087
 {
e22087
   ply_trace ("got password answer");
e22087
 
e22087
   ply_boot_connection_send_answer (connection, password);
e22087
   if (password != NULL)
e22087
     ply_list_append_data (connection->server->cached_passwords,
e22087
                           strdup (password));
e22087
 
e22087
 }
e22087
 
e22087
 static void
e22087
-ply_boot_connection_on_splash_shown (ply_boot_connection_t *connection)
e22087
-{
e22087
-  ply_trace ("shown");
e22087
-  if (!ply_write (connection->fd,
e22087
-                  PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK,
e22087
-                  strlen (PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK)))
e22087
-    {
e22087
-      ply_trace ("could not finish writing deactivate reply: %m");
e22087
-    }
e22087
-}
e22087
-
e22087
-static void
e22087
 ply_boot_connection_on_deactivated (ply_boot_connection_t *connection)
e22087
 {
e22087
   ply_trace ("deactivated");
e22087
   if (!ply_write (connection->fd,
e22087
                   PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK,
e22087
                   strlen (PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK)))
e22087
     {
e22087
       ply_trace ("could not finish writing deactivate reply: %m");
e22087
     }
e22087
 }
e22087
 
e22087
 static void
e22087
 ply_boot_connection_on_quit_complete (ply_boot_connection_t *connection)
e22087
 {
e22087
   ply_trace ("quit complete");
e22087
   if (!ply_write (connection->fd,
e22087
                   PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK,
e22087
                   strlen (PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK)))
e22087
     {
e22087
       ply_trace ("could not finish writing quit reply: %m");
e22087
     }
e22087
 }
e22087
 
e22087
 static void
e22087
 ply_boot_connection_on_question_answer (ply_boot_connection_t *connection,
e22087
                                         const char             *answer)
e22087
 {
e22087
   ply_trace ("got question answer: %s", answer);
e22087
   ply_boot_connection_send_answer (connection, answer);
e22087
 }
e22087
@@ -462,77 +450,63 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
e22087
           ply_error ("failed to parse percentage %s", argument);
e22087
           value = 0;
e22087
         }
e22087
 
e22087
       ply_trace ("got system-update notification %li%%", value);
e22087
       if (!ply_write (connection->fd,
e22087
                       PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK,
e22087
                       strlen (PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK)))
e22087
         ply_trace ("could not finish writing update reply: %m");
e22087
 
e22087
       if (server->system_update_handler != NULL)
e22087
         server->system_update_handler (server->user_data, value, server);
e22087
       free (argument);
e22087
       free (command);
e22087
       return;
e22087
     }
e22087
   else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_SYSTEM_INITIALIZED) == 0)
e22087
     {
e22087
       ply_trace ("got system initialized notification");
e22087
       if (server->system_initialized_handler != NULL)
e22087
         server->system_initialized_handler (server->user_data, server);
e22087
     }
e22087
   else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_ERROR) == 0)
e22087
     {
e22087
       ply_trace ("got error notification");
e22087
       if (server->error_handler != NULL)
e22087
         server->error_handler (server->user_data, server);
e22087
     }
e22087
   else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_SHOW_SPLASH) == 0)
e22087
     {
e22087
-      ply_trigger_t *show_trigger;
e22087
-
e22087
       ply_trace ("got show splash request");
e22087
-
e22087
-      show_trigger = ply_trigger_new (NULL);
e22087
-
e22087
-      ply_trigger_add_handler (show_trigger,
e22087
-                               (ply_trigger_handler_t)
e22087
-                               ply_boot_connection_on_splash_shown,
e22087
-                               connection);
e22087
-
e22087
       if (server->show_splash_handler != NULL)
e22087
-        server->show_splash_handler (server->user_data, show_trigger, server);
e22087
-
e22087
-      free (argument);
e22087
-      free (command);
e22087
-      return;
e22087
+        server->show_splash_handler (server->user_data, server);
e22087
     }
e22087
   else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_HIDE_SPLASH) == 0)
e22087
     {
e22087
       ply_trace ("got hide splash request");
e22087
       if (server->hide_splash_handler != NULL)
e22087
         server->hide_splash_handler (server->user_data, server);
e22087
     }
e22087
   else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_DEACTIVATE) == 0)
e22087
     {
e22087
       ply_trigger_t *deactivate_trigger;
e22087
 
e22087
       ply_trace ("got deactivate request");
e22087
 
e22087
       deactivate_trigger = ply_trigger_new (NULL);
e22087
 
e22087
       ply_trigger_add_handler (deactivate_trigger,
e22087
                                (ply_trigger_handler_t)
e22087
                                ply_boot_connection_on_deactivated,
e22087
                                connection);
e22087
 
e22087
       if (server->deactivate_handler != NULL)
e22087
         server->deactivate_handler (server->user_data, deactivate_trigger, server);
e22087
 
e22087
       free (argument);
e22087
       free (command);
e22087
       return;
e22087
     }
e22087
   else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_REACTIVATE) == 0)
e22087
     {
e22087
       ply_trace ("got reactivate request");
e22087
diff --git a/src/ply-boot-server.h b/src/ply-boot-server.h
e22087
index 4436be8..b885a81 100644
e22087
--- a/src/ply-boot-server.h
e22087
+++ b/src/ply-boot-server.h
e22087
@@ -22,61 +22,60 @@
e22087
 #ifndef PLY_BOOT_SERVER_H
e22087
 #define PLY_BOOT_SERVER_H
e22087
 
e22087
 #include <stdbool.h>
e22087
 #include <stdint.h>
e22087
 #include <unistd.h>
e22087
 
e22087
 #include "ply-trigger.h"
e22087
 #include "ply-boot-protocol.h"
e22087
 #include "ply-event-loop.h"
e22087
 
e22087
 typedef struct _ply_boot_server ply_boot_server_t;
e22087
 
e22087
 typedef void (* ply_boot_server_update_handler_t) (void              *user_data,
e22087
                                                    const char        *status,
e22087
                                                    ply_boot_server_t *server);
e22087
 
e22087
 typedef void (* ply_boot_server_change_mode_handler_t) (void              *user_data,
e22087
                                                         const char        *mode,
e22087
                                                         ply_boot_server_t *server);
e22087
 
e22087
 typedef void (* ply_boot_server_system_update_handler_t) (void              *user_data,
e22087
                                                           int                progress,
e22087
                                                           ply_boot_server_t *server);
e22087
 
e22087
 typedef void (* ply_boot_server_newroot_handler_t) (void              *user_data,
e22087
                                                     const char        *root_dir,
e22087
                                                     ply_boot_server_t *server);
e22087
 
e22087
 typedef void (* ply_boot_server_show_splash_handler_t) (void              *user_data,
e22087
-                                                        ply_trigger_t     *show_trigger,
e22087
                                                         ply_boot_server_t *server);
e22087
 
e22087
 typedef void (* ply_boot_server_hide_splash_handler_t) (void              *user_data,
e22087
                                                         ply_boot_server_t *server);
e22087
 
e22087
 typedef void (* ply_boot_server_password_answer_handler_t) (void              *answer_data,
e22087
                                                             const char        *password,
e22087
                                                             ply_boot_server_t *server);
e22087
 typedef void (* ply_boot_server_ask_for_password_handler_t) (void              *user_data,
e22087
                                                              const char        *prompt,
e22087
                                                              ply_trigger_t     *answer,
e22087
                                                              ply_boot_server_t *server);
e22087
 typedef void (* ply_boot_server_question_answer_handler_t) (void               *answer_data,
e22087
                                                             const char         *answer,
e22087
                                                             ply_boot_server_t  *server);
e22087
 typedef void (* ply_boot_server_ask_question_handler_t)      (void              *user_data,
e22087
                                                               const char        *prompt,
e22087
                                                               ply_trigger_t     *answer,
e22087
                                                               ply_boot_server_t *server);
e22087
 typedef void (* ply_boot_server_display_message_handler_t)   (void              *user_data,
e22087
                                                               const char        *message,
e22087
                                                               ply_boot_server_t *server);
e22087
 typedef void (* ply_boot_server_hide_message_handler_t)   (void              *user_data,
e22087
                                                            const char        *message,
e22087
                                                            ply_boot_server_t *server);
e22087
 typedef void (* ply_boot_server_watch_for_keystroke_handler_t) (void              *user_data,
e22087
                                                                 const char        *keys,
e22087
                                                                 ply_trigger_t     *answer,
e22087
                                                                 ply_boot_server_t *server);
e22087
 typedef void (* ply_boot_server_ignore_keystroke_handler_t) (void              *user_data,
e22087
-- 
e22087
1.8.3.1
e22087