[gnome-flashback] screensaver: add GfUnlockDialog
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback] screensaver: add GfUnlockDialog
- Date: Sun, 9 Feb 2020 12:47:19 +0000 (UTC)
commit 885c6853af63f9fc8204c9e24d1ee2a212f7f340
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Sat Feb 8 21:45:34 2020 +0200
screensaver: add GfUnlockDialog
gnome-flashback/libscreensaver/Makefile.am | 3 +
gnome-flashback/libscreensaver/gf-unlock-dialog.c | 1042 +++++++++++++++++++++
gnome-flashback/libscreensaver/gf-unlock-dialog.h | 48 +
po/POTFILES.in | 1 +
4 files changed, 1094 insertions(+)
---
diff --git a/gnome-flashback/libscreensaver/Makefile.am b/gnome-flashback/libscreensaver/Makefile.am
index 28ada70..054347d 100644
--- a/gnome-flashback/libscreensaver/Makefile.am
+++ b/gnome-flashback/libscreensaver/Makefile.am
@@ -38,6 +38,8 @@ libscreensaver_la_SOURCES = \
gf-screensaver.h \
gf-screensaver-utils.c \
gf-screensaver-utils.h \
+ gf-unlock-dialog.c \
+ gf-unlock-dialog.h \
gf-user-image.c \
gf-user-image.h \
gf-watcher.c \
@@ -58,6 +60,7 @@ libscreensaver_la_LIBADD = \
ENUM_TYPES = \
$(srcdir)/gf-auth.h \
+ $(srcdir)/gf-unlock-dialog.h \
$(NULL)
gf-screensaver-enum-types.c: gf-screensaver-enum-types.c.in gf-screensaver-enum-types.h $(ENUM_TYPES)
diff --git a/gnome-flashback/libscreensaver/gf-unlock-dialog.c
b/gnome-flashback/libscreensaver/gf-unlock-dialog.c
new file mode 100644
index 0000000..7b21c61
--- /dev/null
+++ b/gnome-flashback/libscreensaver/gf-unlock-dialog.c
@@ -0,0 +1,1042 @@
+/*
+ * Copyright (C) 2004-2008 William Jon McCann
+ * Copyright (C) 2008-2011 Red Hat, Inc.
+ * Copyright (C) 2020 Alberts Muktupāvels
+ *
+ * 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include "gf-unlock-dialog.h"
+
+#include <gdm/gdm-user-switching.h>
+#include <glib/gi18n.h>
+#include <systemd/sd-login.h>
+
+#include "dbus/gf-dm-seat-gen.h"
+#include "dbus/gf-login-seat-gen.h"
+#include "gf-auth.h"
+#include "gf-user-image.h"
+#include "gf-screensaver-enum-types.h"
+#include "gf-screensaver-utils.h"
+
+#define DIALOG_TIMEOUT_MSEC 60000
+#define MAX_FAILURES 5
+
+struct _GfUnlockDialog
+{
+ GtkBox parent;
+
+ GCancellable *cancellable;
+
+ GfDmSeatGen *dm_seat;
+ GfLoginSeatGen *login_seat;
+
+ GfAuth *auth;
+
+ GtkWidget *face_image;
+ GtkWidget *prompt_label;
+ GtkWidget *prompt_entry;
+ GtkWidget *capslock_label;
+
+ GtkWidget *message_label;
+
+ GtkWidget *buttons_box;
+ GtkWidget *switch_button;
+ GtkWidget *unlock_button;
+
+ gboolean user_switch_enabled;
+
+ gulong keymap_state_changed_id;
+
+ guint cancel_timeout_id;
+ guint emit_cancel_id;
+
+ GtkWidget *indicator_box;
+ GtkWidget *input_source_button;
+
+ guint failure_count;
+
+ guint shake_timeout_id;
+
+ guint reset_timeout_id;
+};
+
+enum
+{
+ RESPONSE,
+ CLOSE,
+
+ LAST_SIGNAL
+};
+
+static guint unlock_dialog_signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GfUnlockDialog, gf_unlock_dialog, GTK_TYPE_BOX)
+
+static void
+set_sensitive (GfUnlockDialog *self,
+ gboolean sensitive)
+{
+ gtk_widget_set_sensitive (self->prompt_entry, sensitive);
+ gtk_widget_set_sensitive (self->indicator_box, sensitive);
+ gtk_widget_set_sensitive (self->buttons_box, sensitive);
+}
+
+static void
+set_message (GfUnlockDialog *self,
+ const char *message)
+{
+ if (message == NULL)
+ message = "";
+
+ gtk_label_set_text (GTK_LABEL (self->message_label), message);
+}
+
+static void
+set_busy (GfUnlockDialog *self)
+{
+ GdkDisplay *display;
+ GtkWidget *toplevel;
+ GdkWindow *window;
+ GdkCursor *cursor;
+
+ display = gtk_widget_get_display (GTK_WIDGET (self));
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
+ window = gtk_widget_get_window (toplevel);
+
+ cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
+ gdk_window_set_cursor (window, cursor);
+ g_clear_object (&cursor);
+}
+
+static void
+set_ready (GfUnlockDialog *self)
+{
+ GdkDisplay *display;
+ GtkWidget *toplevel;
+ GdkWindow *window;
+ GdkCursor *cursor;
+
+ display = gtk_widget_get_display (GTK_WIDGET (self));
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
+ window = gtk_widget_get_window (toplevel);
+
+ cursor = gdk_cursor_new_for_display (display, GDK_LEFT_PTR);
+ gdk_window_set_cursor (window, cursor);
+ g_clear_object (&cursor);
+}
+
+static gboolean
+emit_cancel_cb (gpointer user_data)
+{
+ GfUnlockDialog *self;
+
+ self = GF_UNLOCK_DIALOG (user_data);
+ self->emit_cancel_id = 0;
+
+ gtk_entry_set_text (GTK_ENTRY (self->prompt_entry), "");
+
+ g_signal_emit (self, unlock_dialog_signals[RESPONSE], 0,
+ GF_UNLOCK_DIALOG_RESPONSE_CANCEL);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+emit_cancel_remove (GfUnlockDialog *self)
+{
+ if (self->emit_cancel_id == 0)
+ return;
+
+ g_source_remove (self->emit_cancel_id);
+ self->emit_cancel_id = 0;
+}
+
+static void
+emit_cancel_add (GfUnlockDialog *self)
+{
+ g_assert (self->emit_cancel_id == 0);
+ self->emit_cancel_id = g_timeout_add_seconds (2, emit_cancel_cb, self);
+
+ g_source_set_name_by_id (self->emit_cancel_id,
+ "[gnome-flashback] emit_cancel_cb");
+}
+
+static void
+switch_to_greeter_failed (GfUnlockDialog *self)
+{
+ set_sensitive (self, FALSE);
+ set_message (self, _("Failed to switch to greeter!"));
+
+ emit_cancel_add (self);
+}
+
+static void
+switch_to_greeter_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *error;
+ GfUnlockDialog *self;
+
+ error = NULL;
+ gf_dm_seat_gen_call_switch_to_greeter_finish (GF_DM_SEAT_GEN (object),
+ res, &error);
+
+ if (error != NULL)
+ {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ {
+ g_warning ("%s", error->message);
+ switch_to_greeter_failed (GF_UNLOCK_DIALOG (user_data));
+ }
+
+ g_error_free (error);
+ return;
+ }
+
+ self = GF_UNLOCK_DIALOG (user_data);
+
+ emit_cancel_add (self);
+ set_ready (self);
+}
+
+static void
+switch_user (GfUnlockDialog *self)
+{
+ if (self->dm_seat != NULL)
+ {
+ gf_dm_seat_gen_call_switch_to_greeter (self->dm_seat,
+ self->cancellable,
+ switch_to_greeter_cb,
+ self);
+ }
+ else
+ {
+ GError *error;
+
+ error = NULL;
+ if (!gdm_goto_login_session_sync (NULL, &error))
+ {
+ g_warning ("Failed to switch to greeter: %s", error->message);
+ switch_to_greeter_failed (self);
+ }
+ else
+ {
+ emit_cancel_add (self);
+ set_ready (self);
+ }
+
+ g_clear_error (&error);
+ }
+}
+
+static gboolean
+cancel_timeout_cb (gpointer user_data)
+{
+ GfUnlockDialog *self;
+
+ self = GF_UNLOCK_DIALOG (user_data);
+ self->cancel_timeout_id = 0;
+
+ set_sensitive (self, FALSE);
+ set_message (self, _("Time has expired."));
+
+ emit_cancel_remove (self);
+ emit_cancel_add (self);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+cancel_timeout_remove (GfUnlockDialog *self)
+{
+ if (self->cancel_timeout_id == 0)
+ return;
+
+ g_source_remove (self->cancel_timeout_id);
+ self->cancel_timeout_id = 0;
+}
+
+static void
+cancel_timeout_add (GfUnlockDialog *self)
+{
+ g_assert (self->cancel_timeout_id == 0);
+ self->cancel_timeout_id = g_timeout_add (DIALOG_TIMEOUT_MSEC,
+ cancel_timeout_cb,
+ self);
+
+ g_source_set_name_by_id (self->cancel_timeout_id,
+ "[gnome-flashback] cancel_timeout_cb");
+}
+
+static void
+cancel_timeout_restart (GfUnlockDialog *self)
+{
+ cancel_timeout_remove (self);
+ cancel_timeout_add (self);
+}
+
+static void
+disable_prompt (GfUnlockDialog *self)
+{
+ set_sensitive (self, FALSE);
+}
+
+static void
+enable_prompt (GfUnlockDialog *self,
+ const char *message,
+ gboolean visible)
+{
+ char *markup;
+
+ g_debug ("Setting prompt to: %s", message);
+
+ markup = g_strdup_printf ("<b><big>%s</big></b>", message);
+ gtk_label_set_markup (GTK_LABEL (self->prompt_label), markup);
+ gtk_widget_show (self->prompt_label);
+ g_free (markup);
+
+ gtk_entry_set_visibility (GTK_ENTRY (self->prompt_entry), visible);
+ set_sensitive (self, TRUE);
+
+ if (!gtk_widget_has_focus (self->prompt_entry))
+ gtk_widget_grab_focus (self->prompt_entry);
+
+ gtk_widget_grab_default (self->unlock_button);
+
+ cancel_timeout_restart (self);
+}
+
+static void
+clear_clipboards (GfUnlockDialog *self)
+{
+ GtkClipboard *clipboard;
+
+ clipboard = gtk_widget_get_clipboard (GTK_WIDGET (self),
+ GDK_SELECTION_PRIMARY);
+
+ gtk_clipboard_clear (clipboard);
+ gtk_clipboard_set_text (clipboard, "", -1);
+
+ clipboard = gtk_widget_get_clipboard (GTK_WIDGET (self),
+ GDK_SELECTION_CLIPBOARD);
+
+ gtk_clipboard_clear (clipboard);
+ gtk_clipboard_set_text (clipboard, "", -1);
+}
+
+static gboolean
+prompt_entry_button_press_event_cb (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
+ return TRUE;
+
+ return FALSE;
+}
+
+static GtkWidget *
+create_page_one_content (GfUnlockDialog *self)
+{
+ GtkWidget *hbox;
+ GtkWidget *grid;
+ char *markup;
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+
+ grid = gtk_grid_new ();
+ gtk_box_pack_start (GTK_BOX (hbox), grid, TRUE, TRUE, 0);
+ gtk_grid_set_column_spacing (GTK_GRID (grid), 16);
+ gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
+ gtk_widget_show (grid);
+
+ self->face_image = gf_user_image_new ();
+ gtk_grid_attach (GTK_GRID (grid), self->face_image, 0, 0, 1, 2);
+ gtk_widget_set_valign (self->face_image, GTK_ALIGN_END);
+
+ markup = g_strdup_printf ("%s", _("_Password:"));
+ self->prompt_label = gtk_label_new (NULL);
+ gtk_label_set_markup_with_mnemonic (GTK_LABEL (self->prompt_label), markup);
+ gtk_label_set_xalign (GTK_LABEL (self->prompt_label), 0.0);
+ gtk_label_set_yalign (GTK_LABEL (self->prompt_label), 0.0);
+ gtk_grid_attach (GTK_GRID (grid), self->prompt_label, 1, 0, 1, 1);
+ gtk_widget_set_valign (self->prompt_label, GTK_ALIGN_END);
+ gtk_widget_set_vexpand (self->prompt_label, TRUE);
+ gtk_widget_show (self->prompt_label);
+ g_free (markup);
+
+ self->prompt_entry = gtk_entry_new ();
+ gtk_entry_set_visibility (GTK_ENTRY (self->prompt_entry), FALSE);
+ gtk_entry_set_activates_default (GTK_ENTRY (self->prompt_entry), TRUE);
+ gtk_grid_attach (GTK_GRID (grid), self->prompt_entry, 1, 1, 1, 1);
+ gtk_widget_set_hexpand (self->prompt_entry, TRUE);
+ gtk_widget_set_valign (self->prompt_entry, GTK_ALIGN_END);
+ gtk_widget_show (self->prompt_entry);
+
+ self->indicator_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_grid_attach (GTK_GRID (grid), self->indicator_box, 2, 1, 1, 1);
+ gtk_widget_set_valign (self->indicator_box, GTK_ALIGN_END);
+
+ self->capslock_label = gtk_label_new (NULL);
+ gtk_grid_attach (GTK_GRID (grid), self->capslock_label, 1, 2, 1, 1);
+ gtk_widget_show (self->capslock_label);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (self->prompt_label),
+ self->prompt_entry);
+
+ /* button press handler used to inhibit popup menu */
+ g_signal_connect (self->prompt_entry, "button-press-event",
+ G_CALLBACK (prompt_entry_button_press_event_cb),
+ NULL);
+
+ return hbox;
+}
+
+static void
+update_user_switch_button (GfUnlockDialog *self)
+{
+ gboolean enabled;
+
+ enabled = self->user_switch_enabled;
+
+ /*
+ * CanSwitch might be true even if it is not possible:
+ *
https://github.com/canonical/lightdm/blob/03f218981733e50d810767f9d04e42ee156f7feb/src/lightdm.c#L411-L416
+ * https://bugs.launchpad.net/bugs/1371250
+ */
+ if (enabled && self->dm_seat != NULL)
+ enabled = gf_dm_seat_gen_get_can_switch (self->dm_seat);
+
+ if (enabled && self->login_seat != NULL)
+ enabled = gf_login_seat_gen_get_can_multi_session (self->login_seat);
+
+ gtk_widget_set_visible (self->switch_button, enabled);
+}
+
+static void
+dm_seat_ready_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+
+{
+ GError *error;
+ GfDmSeatGen *seat;
+ GfUnlockDialog *self;
+
+ error = NULL;
+ seat = gf_dm_seat_gen_proxy_new_for_bus_finish (res, &error);
+
+ if (error != NULL)
+ {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("%s", error->message);
+
+ g_error_free (error);
+ return;
+ }
+
+ self = GF_UNLOCK_DIALOG (user_data);
+ self->dm_seat = seat;
+
+ update_user_switch_button (self);
+}
+
+static void
+login_seat_ready_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *error;
+ GfLoginSeatGen *seat;
+ GfUnlockDialog *self;
+
+ error = NULL;
+ seat = gf_login_seat_gen_proxy_new_for_bus_finish (res, &error);
+
+ if (error != NULL)
+ {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("%s", error->message);
+
+ g_error_free (error);
+ return;
+ }
+
+ self = GF_UNLOCK_DIALOG (user_data);
+ self->login_seat = seat;
+
+ update_user_switch_button (self);
+}
+
+static void
+switch_button_clicked_cb (GtkButton *button,
+ GfUnlockDialog *self)
+{
+ set_sensitive (self, FALSE);
+ set_busy (self);
+
+ cancel_timeout_remove (self);
+ emit_cancel_remove (self);
+
+ switch_user (self);
+}
+
+static void
+unlock_button_clicked_cb (GtkButton *button,
+ GfUnlockDialog *self)
+{
+ if (gf_auth_awaits_response (self->auth))
+ {
+ const char *text;
+
+ set_sensitive (self, FALSE);
+ set_message (self, _("Checking…"));
+
+ text = gtk_entry_get_text (GTK_ENTRY (self->prompt_entry));
+
+ gf_auth_set_response (self->auth, text);
+ }
+
+ cancel_timeout_remove (self);
+ emit_cancel_remove (self);
+
+ gtk_entry_set_text (GTK_ENTRY (self->prompt_entry), "");
+
+ disable_prompt (self);
+ set_busy (self);
+}
+
+static GtkWidget *
+create_page_one_buttons (GfUnlockDialog *self)
+{
+ GtkWidget *hbox;
+
+ hbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
+ gtk_box_set_spacing (GTK_BOX (hbox), 5);
+
+ self->switch_button = gtk_button_new_with_mnemonic (_("S_witch User…"));
+ gtk_widget_set_focus_on_click (self->switch_button, FALSE);
+ gtk_widget_set_can_default (self->switch_button, TRUE);
+ gtk_box_pack_end (GTK_BOX (hbox), self->switch_button, FALSE, TRUE, 0);
+ gtk_widget_show (self->switch_button);
+
+ g_signal_connect (self->switch_button, "clicked",
+ G_CALLBACK (switch_button_clicked_cb), self);
+
+ self->unlock_button = gtk_button_new_with_mnemonic (_("_Unlock"));
+ gtk_widget_set_focus_on_click (self->unlock_button, FALSE);
+ gtk_widget_set_can_default (self->unlock_button, TRUE);
+ gtk_box_pack_end (GTK_BOX (hbox), self->unlock_button, FALSE, TRUE, 0);
+ gtk_widget_show (self->unlock_button);
+
+ g_signal_connect (self->unlock_button, "clicked",
+ G_CALLBACK (unlock_button_clicked_cb), self);
+
+ gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (hbox),
+ self->switch_button,
+ TRUE);
+
+ update_user_switch_button (self);
+
+ return hbox;
+}
+
+static GtkWidget *
+create_page_one (GfUnlockDialog *self)
+{
+ GtkWidget *vbox;
+ GtkWidget *content;
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+
+ content = create_page_one_content (self);
+ gtk_box_pack_start (GTK_BOX (vbox), content, FALSE, FALSE, 0);
+ gtk_widget_show (content);
+
+ self->message_label = gtk_label_new (NULL);
+ gtk_box_pack_start (GTK_BOX (vbox), self->message_label, FALSE, FALSE, 0);
+ gtk_widget_show (self->message_label);
+
+ self->buttons_box = create_page_one_buttons (self);
+ gtk_box_pack_end (GTK_BOX (vbox), self->buttons_box, FALSE, FALSE, 0);
+ gtk_widget_show (self->buttons_box);
+
+ return vbox;
+}
+
+static void
+auth_message_cb (GfAuth *auth,
+ GfAuthMessageType type,
+ const char *message,
+ GfUnlockDialog *self)
+{
+ g_debug ("Got message: type - %d, message - %s", type, message);
+
+ gtk_widget_show (GTK_WIDGET (self));
+ set_ready (self);
+
+ switch (type)
+ {
+ case GF_AUTH_MESSAGE_PROMPT_ECHO_ON:
+ case GF_AUTH_MESSAGE_PROMPT_ECHO_OFF:
+ set_sensitive (self, TRUE);
+ enable_prompt (self, message, type == GF_AUTH_MESSAGE_PROMPT_ECHO_ON);
+ break;
+
+ case GF_AUTH_MESSAGE_ERROR_MSG:
+ case GF_AUTH_MESSAGE_TEXT_INFO:
+ set_message (self, message);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+typedef void (* ShakeDoneFunc) (GfUnlockDialog *self);
+
+typedef struct
+{
+ GfUnlockDialog *self;
+ ShakeDoneFunc done_func;
+ guint count;
+} ShakeData;
+
+static gboolean
+reset_idle_cb (gpointer user_data)
+{
+ GfUnlockDialog *self;
+
+ self = GF_UNLOCK_DIALOG (user_data);
+ self->reset_timeout_id = 0;
+
+ set_sensitive (self, TRUE);
+ set_message (self, NULL);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+try_again (GfUnlockDialog *self)
+{
+ g_debug ("Authentication failed, retrying (%u)", self->failure_count);
+
+ if (self->reset_timeout_id != 0)
+ g_source_remove (self->reset_timeout_id);
+
+ self->reset_timeout_id = g_timeout_add_seconds (3, reset_idle_cb, self);
+
+ g_source_set_name_by_id (self->reset_timeout_id,
+ "[gnome-flashback] reset_idle_cb");
+
+ disable_prompt (self);
+ set_busy (self);
+
+ gf_auth_verify (self->auth);
+}
+
+static void
+max_failures (GfUnlockDialog *self)
+{
+ g_debug ("Authentication failed, quitting (max failures)");
+ g_signal_emit (self, unlock_dialog_signals[CLOSE], 0);
+}
+
+static gboolean
+shake_cb (gpointer user_data)
+{
+ ShakeData *data;
+ GfUnlockDialog *self;
+
+ data = user_data;
+ self = data->self;
+
+ if (data->count < 9)
+ {
+ if (data->count % 2 == 0)
+ {
+ gtk_widget_set_margin_start (GTK_WIDGET (self), 30);
+ gtk_widget_set_margin_end (GTK_WIDGET (self), 0);
+ }
+ else
+ {
+ gtk_widget_set_margin_start (GTK_WIDGET (self), 0);
+ gtk_widget_set_margin_end (GTK_WIDGET (self), 30);
+ }
+
+ data->count++;
+ return G_SOURCE_CONTINUE;
+ }
+
+ data->done_func (self);
+
+ self->shake_timeout_id = 0;
+ return G_SOURCE_REMOVE;
+}
+
+static void
+shake_dialog (GfUnlockDialog *self,
+ ShakeDoneFunc done_func)
+{
+ ShakeData *data;
+
+ data = g_new0 (ShakeData, 1);
+ data->self = self;
+ data->done_func = done_func;
+
+ g_assert (self->shake_timeout_id == 0);
+ self->shake_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT,
+ 10,
+ shake_cb,
+ data,
+ g_free);
+
+ g_source_set_name_by_id (self->shake_timeout_id,
+ "[gnome-flashback] shake_cb");
+}
+
+static void
+auth_complete_cb (GfAuth *auth,
+ gboolean verified,
+ const char *message,
+ GfUnlockDialog *self)
+{
+ if (verified)
+ {
+ g_signal_emit (self,
+ unlock_dialog_signals[RESPONSE],
+ 0,
+ GF_UNLOCK_DIALOG_RESPONSE_OK);
+ }
+ else
+ {
+ set_message (self, message);
+
+ self->failure_count++;
+
+ if (self->failure_count < MAX_FAILURES)
+ shake_dialog (self, try_again);
+ else
+ shake_dialog (self, max_failures);
+ }
+}
+
+static void
+update_capslock_label (GfUnlockDialog *self)
+{
+ GdkDisplay *display;
+ GdkKeymap *keymap;
+
+ display = gtk_widget_get_display (GTK_WIDGET (self));
+ keymap = gdk_keymap_get_for_display (display);
+
+ if (gdk_keymap_get_caps_lock_state (keymap))
+ {
+ gtk_label_set_text (GTK_LABEL (self->capslock_label),
+ _("You have the Caps Lock key on."));
+ }
+ else
+ {
+ gtk_label_set_text (GTK_LABEL (self->capslock_label), "");
+ }
+}
+
+static void
+keymap_state_changed_cb (GdkKeymap *keymap,
+ GfUnlockDialog *self)
+{
+ update_capslock_label (self);
+}
+
+static void
+gf_unlock_dialog_constructed (GObject *object)
+{
+ GfUnlockDialog *self;
+ GdkDisplay *display;
+ GdkKeymap *keymap;
+ const char *username;
+ const char *env_display;
+
+ self = GF_UNLOCK_DIALOG (object);
+
+ G_OBJECT_CLASS (gf_unlock_dialog_parent_class)->constructed (object);
+
+ display = gtk_widget_get_display (GTK_WIDGET (self));
+ keymap = gdk_keymap_get_for_display (display);
+
+ self->keymap_state_changed_id = g_signal_connect (keymap,
+ "state-changed",
+ G_CALLBACK (keymap_state_changed_cb),
+ self);
+
+ username = g_get_user_name ();
+ env_display = g_getenv ("DISPLAY");
+
+ if (env_display == NULL)
+ env_display = ":0.0";
+
+ self->auth = gf_auth_new (username, env_display);
+
+ g_signal_connect (self->auth,
+ "message",
+ G_CALLBACK (auth_message_cb),
+ self);
+
+ g_signal_connect (self->auth,
+ "complete",
+ G_CALLBACK (auth_complete_cb),
+ self);
+
+ gf_auth_verify (self->auth);
+}
+
+static void
+gf_unlock_dialog_dispose (GObject *object)
+{
+ GfUnlockDialog *self;
+
+ self = GF_UNLOCK_DIALOG (object);
+
+ g_cancellable_cancel (self->cancellable);
+ g_clear_object (&self->cancellable);
+
+ g_clear_object (&self->dm_seat);
+ g_clear_object (&self->login_seat);
+
+ g_clear_object (&self->auth);
+
+ G_OBJECT_CLASS (gf_unlock_dialog_parent_class)->dispose (object);
+}
+
+static void
+gf_unlock_dialog_finalize (GObject *object)
+{
+ GfUnlockDialog *self;
+
+ self = GF_UNLOCK_DIALOG (object);
+
+ if (self->keymap_state_changed_id != 0)
+ {
+ GdkDisplay *display;
+ GdkKeymap *keymap;
+
+ display = gtk_widget_get_display (GTK_WIDGET (self));
+ keymap = gdk_keymap_get_for_display (display);
+
+ g_signal_handler_disconnect (keymap, self->keymap_state_changed_id);
+ self->keymap_state_changed_id = 0;
+ }
+
+ cancel_timeout_remove (self);
+ emit_cancel_remove (self);
+
+ if (self->shake_timeout_id != 0)
+ {
+ g_source_remove (self->shake_timeout_id);
+ self->shake_timeout_id = 0;
+ }
+
+ if (self->reset_timeout_id != 0)
+ {
+ g_source_remove (self->reset_timeout_id);
+ self->reset_timeout_id = 0;
+ }
+
+ G_OBJECT_CLASS (gf_unlock_dialog_parent_class)->finalize (object);
+}
+
+static void
+gf_unlock_dialog_show (GtkWidget *widget)
+{
+ GfUnlockDialog *self;
+
+ self = GF_UNLOCK_DIALOG (widget);
+
+ clear_clipboards (self);
+
+ GTK_WIDGET_CLASS (gf_unlock_dialog_parent_class)->show (widget);
+
+ update_capslock_label (self);
+
+ gtk_widget_grab_default (self->unlock_button);
+ gtk_widget_grab_focus (self->prompt_entry);
+ cancel_timeout_add (self);
+}
+
+static void
+install_signals (void)
+{
+ unlock_dialog_signals[RESPONSE] =
+ g_signal_new ("response", GF_TYPE_UNLOCK_DIALOG,
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 1, GF_TYPE_UNLOCK_DIALOG_RESPONSE);
+
+ unlock_dialog_signals[CLOSE] =
+ g_signal_new ("close", GF_TYPE_UNLOCK_DIALOG,
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+}
+
+static void
+gf_unlock_dialog_class_init (GfUnlockDialogClass *self_class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkBindingSet *binding_set;
+
+ object_class = G_OBJECT_CLASS (self_class);
+ widget_class = GTK_WIDGET_CLASS (self_class);
+
+ object_class->constructed = gf_unlock_dialog_constructed;
+ object_class->dispose = gf_unlock_dialog_dispose;
+ object_class->finalize = gf_unlock_dialog_finalize;
+
+ widget_class->show = gf_unlock_dialog_show;
+
+ install_signals ();
+
+ gtk_widget_class_set_css_name (widget_class, "gf-unlock-dialog");
+
+ binding_set = gtk_binding_set_by_class (widget_class);
+ gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "close", 0);
+}
+
+static void
+gf_unlock_dialog_init (GfUnlockDialog *self)
+{
+ const gchar *xdg_seat_path;
+ char *session_id;
+ GtkStyleContext *style;
+ GtkWidget *frame;
+ GtkWidget *vbox;
+ GtkWidget *notebook;
+ GtkWidget *page;
+
+ self->cancellable = g_cancellable_new ();
+
+ xdg_seat_path = g_getenv ("XDG_SEAT_PATH");
+ if (xdg_seat_path != NULL && *xdg_seat_path != '\0')
+ {
+ gf_dm_seat_gen_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ "org.freedesktop.DisplayManager",
+ xdg_seat_path,
+ self->cancellable,
+ dm_seat_ready_cb,
+ self);
+ }
+
+ session_id = NULL;
+ if (gf_find_systemd_session (&session_id))
+ {
+ char *seat;
+
+ seat = NULL;
+ if (sd_session_get_seat (session_id, &seat) >= 0)
+ {
+ char *seat_path;
+
+ seat_path = g_strdup_printf ("/org/freedesktop/login1/seat/%s", seat);
+ free (seat);
+
+ gf_login_seat_gen_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ "org.freedesktop.login1",
+ seat_path,
+ self->cancellable,
+ login_seat_ready_cb,
+ self);
+
+ g_free (seat_path);
+ }
+
+ g_free (session_id);
+ }
+
+ gtk_widget_set_size_request (GTK_WIDGET (self), 450, -1);
+
+ style = gtk_widget_get_style_context (GTK_WIDGET (self));
+ gtk_style_context_add_class (style, GTK_STYLE_CLASS_BACKGROUND);
+
+ frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
+ gtk_container_add (GTK_CONTAINER (self), frame);
+ gtk_widget_show (frame);
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 24);
+ gtk_container_add (GTK_CONTAINER (frame), vbox);
+ gtk_widget_show (vbox);
+
+ notebook = gtk_notebook_new ();
+ gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE);
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE);
+ gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);
+ gtk_widget_show (notebook);
+
+ page = create_page_one (self);
+ gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, NULL);
+ gtk_widget_show (page);
+}
+
+GtkWidget *
+gf_unlock_dialog_new (void)
+{
+ return g_object_new (GF_TYPE_UNLOCK_DIALOG,
+ "halign", GTK_ALIGN_CENTER,
+ "orientation", GTK_ORIENTATION_VERTICAL,
+ "valign", GTK_ALIGN_CENTER,
+ NULL);
+}
+
+void
+gf_unlock_dialog_set_input_sources (GfUnlockDialog *self,
+ GfInputSources *input_sources)
+{
+ if (self->input_source_button != NULL)
+ {
+ gtk_widget_hide (self->indicator_box);
+ gtk_widget_destroy (self->input_source_button);
+ self->input_source_button = NULL;
+ return;
+ }
+
+ if (input_sources == NULL)
+ return;
+
+ self->input_source_button = gf_input_sources_create_button (input_sources);
+ gtk_container_add (GTK_CONTAINER (self->indicator_box),
+ self->input_source_button);
+
+ gtk_widget_show (self->input_source_button);
+ gtk_widget_show (self->indicator_box);
+}
+
+void
+gf_unlock_dialog_set_user_switch_enabled (GfUnlockDialog *self,
+ gboolean user_switch_enabled)
+{
+ if (self->user_switch_enabled == user_switch_enabled)
+ return;
+
+ self->user_switch_enabled = user_switch_enabled;
+
+ update_user_switch_button (self);
+}
diff --git a/gnome-flashback/libscreensaver/gf-unlock-dialog.h
b/gnome-flashback/libscreensaver/gf-unlock-dialog.h
new file mode 100644
index 0000000..2719c40
--- /dev/null
+++ b/gnome-flashback/libscreensaver/gf-unlock-dialog.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 Alberts Muktupāvels
+ *
+ * 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 3 of the License, 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 PURPOgf_unlock_dialog_newSE. 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GF_UNLOCK_DIALOG_H
+#define GF_UNLOCK_DIALOG_H
+
+#include <gtk/gtk.h>
+#include <libinput-sources/gf-input-sources.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ GF_UNLOCK_DIALOG_RESPONSE_NONE,
+
+ GF_UNLOCK_DIALOG_RESPONSE_OK,
+ GF_UNLOCK_DIALOG_RESPONSE_CANCEL
+} GfUnlockDialogResponse;
+
+#define GF_TYPE_UNLOCK_DIALOG (gf_unlock_dialog_get_type ())
+G_DECLARE_FINAL_TYPE (GfUnlockDialog, gf_unlock_dialog,
+ GF, UNLOCK_DIALOG, GtkBox)
+
+GtkWidget *gf_unlock_dialog_new (void);
+
+void gf_unlock_dialog_set_input_sources (GfUnlockDialog *self,
+ GfInputSources *input_sources);
+
+void gf_unlock_dialog_set_user_switch_enabled (GfUnlockDialog *self,
+ gboolean user_switch_enabled);
+
+G_END_DECLS
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 610810e..c26b7b5 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -38,6 +38,7 @@ gnome-flashback/libpolkit/flashback-listener.c
gnome-flashback/libpolkit/flashback-polkit-dialog.c
gnome-flashback/libpolkit/flashback-polkit-dialog.ui
gnome-flashback/libscreensaver/gf-auth.c
+gnome-flashback/libscreensaver/gf-unlock-dialog.c
gvc/gvc/gvc-mixer-control.c
system-indicators/si-bluetooth.c
system-indicators/si-desktop-menu-item.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]