[gnome-flashback] screensaver: queue key events while unlock dialog is not ready



commit 33d3dba4de3913d258201b670ed1073740955ae9
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Thu Apr 23 20:28:09 2020 +0300

    screensaver: queue key events while unlock dialog is not ready
    
    Unlock dialog is created in idle after keyboard and/or mouse
    activity and its visibility/readiness depends on PAM.
    
    This means that first key event will never reach unlock dialog if
    it was not already created/ready. If user is fast enough more key
    events might not reach dialog.
    
    Queue key events in this case and forward to password entry when
    dialog becomes visible.
    
    https://gitlab.gnome.org/GNOME/gnome-flashback/-/issues/49

 gnome-flashback/libscreensaver/gf-unlock-dialog.c |  7 ++++
 gnome-flashback/libscreensaver/gf-unlock-dialog.h |  3 ++
 gnome-flashback/libscreensaver/gf-window.c        | 46 +++++++++++++++++++++++
 3 files changed, 56 insertions(+)
---
diff --git a/gnome-flashback/libscreensaver/gf-unlock-dialog.c 
b/gnome-flashback/libscreensaver/gf-unlock-dialog.c
index 5e07bbd..c13380e 100644
--- a/gnome-flashback/libscreensaver/gf-unlock-dialog.c
+++ b/gnome-flashback/libscreensaver/gf-unlock-dialog.c
@@ -1049,3 +1049,10 @@ gf_unlock_dialog_set_user_switch_enabled (GfUnlockDialog *self,
 
   update_user_switch_button (self);
 }
+
+void
+gf_unlock_dialog_forward_key_event (GfUnlockDialog *self,
+                                    GdkEvent       *event)
+{
+  gtk_widget_event (self->prompt_entry, event);
+}
diff --git a/gnome-flashback/libscreensaver/gf-unlock-dialog.h 
b/gnome-flashback/libscreensaver/gf-unlock-dialog.h
index 2719c40..8a9afc8 100644
--- a/gnome-flashback/libscreensaver/gf-unlock-dialog.h
+++ b/gnome-flashback/libscreensaver/gf-unlock-dialog.h
@@ -43,6 +43,9 @@ void       gf_unlock_dialog_set_input_sources       (GfUnlockDialog *self,
 void       gf_unlock_dialog_set_user_switch_enabled (GfUnlockDialog *self,
                                                      gboolean        user_switch_enabled);
 
+void       gf_unlock_dialog_forward_key_event       (GfUnlockDialog *self,
+                                                     GdkEvent       *event);
+
 G_END_DECLS
 
 #endif
diff --git a/gnome-flashback/libscreensaver/gf-window.c b/gnome-flashback/libscreensaver/gf-window.c
index cd5a5a5..3c3d832 100644
--- a/gnome-flashback/libscreensaver/gf-window.c
+++ b/gnome-flashback/libscreensaver/gf-window.c
@@ -26,6 +26,8 @@
 #include "gf-panel.h"
 #include "gf-unlock-dialog.h"
 
+#define MAX_QUEUED_EVENTS 16
+
 struct _GfWindow
 {
   GtkWindow        parent;
@@ -41,6 +43,8 @@ struct _GfWindow
 
   GfInputSources  *input_sources;
 
+  GList           *key_events;
+
   gboolean         lock_enabled;
   gboolean         user_switch_enabled;
 
@@ -177,6 +181,21 @@ unlock_dialog_close_cb (GfUnlockDialog *dialog,
   popdown_dialog (self);
 }
 
+static void
+unlock_dialog_show_cb (GtkWidget *widget,
+                       GfWindow  *self)
+{
+  GList *l;
+
+  self->key_events = g_list_reverse (self->key_events);
+
+  for (l = self->key_events; l != NULL; l = l->next)
+    gf_unlock_dialog_forward_key_event (GF_UNLOCK_DIALOG (widget), l->data);
+
+  g_list_free_full (self->key_events, (GDestroyNotify) gdk_event_free);
+  self->key_events = NULL;
+}
+
 static void
 popup_dialog (GfWindow *self)
 {
@@ -199,6 +218,9 @@ popup_dialog (GfWindow *self)
   g_signal_connect (self->unlock_dialog, "close",
                     G_CALLBACK (unlock_dialog_close_cb), self);
 
+  g_signal_connect (self->unlock_dialog, "show",
+                    G_CALLBACK (unlock_dialog_show_cb), self);
+
   gtk_box_pack_start (GTK_BOX (self->vbox), self->unlock_dialog, TRUE, TRUE, 0);
 }
 
@@ -285,6 +307,12 @@ gf_window_finalize (GObject *object)
 
   g_clear_pointer (&self->surface, cairo_surface_destroy);
 
+  if (self->key_events != NULL)
+    {
+      g_list_free_full (self->key_events, (GDestroyNotify) gdk_event_free);
+      self->key_events = NULL;
+    }
+
   if (self->emit_deactivated_idle_id != 0)
     {
       g_source_remove (self->emit_deactivated_idle_id);
@@ -392,6 +420,24 @@ gf_window_key_press_event (GtkWidget   *widget,
         return TRUE;
     }
 
+  if (self->unlock_dialog == NULL ||
+      !gtk_widget_is_visible (self->unlock_dialog))
+    {
+      /* Only cache MAX_QUEUED_EVENTS key events. If there are any more
+       * than this then something is wrong.
+       *
+       * Don't queue keys that may cause focus navigation in the dialog.
+       */
+      if (g_list_length (self->key_events) < MAX_QUEUED_EVENTS &&
+          event->keyval != GDK_KEY_Tab &&
+          event->keyval != GDK_KEY_Up &&
+          event->keyval != GDK_KEY_Down)
+        {
+          self->key_events = g_list_prepend (self->key_events,
+                                             gdk_event_copy ((GdkEvent *) event));
+        }
+    }
+
   return GTK_WIDGET_CLASS (gf_window_parent_class)->key_press_event (widget,
                                                                      event);
 }


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