[gnome-control-center] user-accounts: Implement new designed fingerprint dialog
- From: Robert Ancell <rancell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-control-center] user-accounts: Implement new designed fingerprint dialog
- Date: Fri, 26 Jun 2020 01:59:48 +0000 (UTC)
commit d517a092aacbf678c0dfeed4d78df42a48cdd19a
Author: Marco Trevisan (Treviño) <mail 3v1n0 net>
Date: Fri Apr 10 16:40:27 2020 +0200
user-accounts: Implement new designed fingerprint dialog
Implement the new designed interface for fingerprint enrollment, so that the
dialog is now based on a stack of views:
- A list of devices to choose (shown only if multiple are available)
- A gallery of enrolled prints available where manage them
- An enrollment progress view when enrolling a new finger
Move part of the logic into a new FingerprintManager (to manage gdbus proxies
generated via gdbus-codegen) that is created when configuring the current
user and that tracks the devices states, while move most of the UI into a new
CcFingerprintDialog that does all the operations in async way.
Due to fprintd lack of APIs, there are few features missing, compared to
the final design (none is a regression):
- Identify the finger when the enroll dialog is visible
- Delete a single fingerprint
- Highlight the finger when the sensor is touched during enrollment
- Add customized labels to fingerprints
- Devices hotpluging
However most of the code has been written considering these, and so they could
be easily implemented in future re-iterations once newer APIs are defined for
such bits.
Closes https://gitlab.gnome.org/Teams/Design/settings-mockups/-/issues/18
panels/user-accounts/cc-fingerprint-dialog.c | 1438 ++++++++++++++++++++
panels/user-accounts/cc-fingerprint-dialog.h | 37 +
panels/user-accounts/cc-fingerprint-dialog.ui | 461 +++++++
panels/user-accounts/cc-user-panel.c | 23 +-
panels/user-accounts/data/account-fingerprint.ui | 238 ----
.../user-accounts/data/cc-fingerprint-dialog.css | 61 +
.../fingerprint-detection-complete-symbolic.svg | 3 +
.../data/icons/fingerprint-detection-symbolic.svg | 3 +
.../fingerprint-detection-warning-symbolic.svg | 3 +
.../user-accounts/data/icons/left-index-finger.png | Bin 1515 -> 0 bytes
.../data/icons/left-little-finger.png | Bin 1500 -> 0 bytes
.../data/icons/left-middle-finger.png | Bin 1483 -> 0 bytes
.../user-accounts/data/icons/left-ring-finger.png | Bin 1512 -> 0 bytes
panels/user-accounts/data/icons/left-thumb.png | Bin 1512 -> 0 bytes
panels/user-accounts/data/icons/print_error.png | Bin 4160 -> 0 bytes
panels/user-accounts/data/icons/print_ok.png | Bin 3677 -> 0 bytes
.../data/icons/right-index-finger.png | Bin 1506 -> 0 bytes
.../data/icons/right-little-finger.png | Bin 1479 -> 0 bytes
.../data/icons/right-middle-finger.png | Bin 1468 -> 0 bytes
.../user-accounts/data/icons/right-ring-finger.png | Bin 1506 -> 0 bytes
panels/user-accounts/data/icons/right-thumb.png | Bin 1486 -> 0 bytes
panels/user-accounts/meson.build | 20 +-
panels/user-accounts/um-fingerprint-dialog.c | 778 -----------
panels/user-accounts/um-fingerprint-dialog.h | 27 -
panels/user-accounts/user-accounts.gresource.xml | 21 +-
po/POTFILES.in | 4 +-
26 files changed, 2030 insertions(+), 1087 deletions(-)
---
diff --git a/panels/user-accounts/cc-fingerprint-dialog.c b/panels/user-accounts/cc-fingerprint-dialog.c
new file mode 100644
index 000000000..f3f5229c8
--- /dev/null
+++ b/panels/user-accounts/cc-fingerprint-dialog.c
@@ -0,0 +1,1438 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2020 Canonical Ltd.
+ *
+ * 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 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * Authors: Marco Trevisan <marco trevisan canonical com>
+ */
+
+#include <glib/gi18n.h>
+#include <cairo/cairo.h>
+
+#include "cc-fingerprint-dialog.h"
+
+#include "cc-fingerprint-manager.h"
+#include "cc-fprintd-generated.h"
+#include "cc-list-row.h"
+
+#include "config.h"
+
+/* Translate fprintd strings */
+#define TR(s) dgettext ("fprintd", s)
+#include "fingerprint-strings.h"
+
+struct _CcFingerprintDialog
+{
+ GtkWindow parent_instance;
+
+ GtkButton *back_button;
+ GtkButton *cancel_button;
+ GtkButton *delete_prints_button;
+ GtkButton *done_button;
+ GtkContainer *add_print_popover_box;
+ GtkEntry *enroll_print_entry;
+ GtkFlowBox *prints_gallery;
+ GtkHeaderBar *titlebar;
+ GtkImage *enroll_result_image;
+ GtkLabel *enroll_message;
+ GtkLabel *enroll_result_message;
+ GtkLabel *infobar_error;
+ GtkLabel *title;
+ GtkListBox *devices_list;
+ GtkPopoverMenu *add_print_popover;
+ GtkPopoverMenu *print_popover;
+ GtkSpinner *spinner;
+ GtkStack *stack;
+ GtkWidget *add_print_icon;
+ GtkWidget *delete_confirmation_infobar;
+ GtkWidget *device_selector;
+ GtkWidget *enroll_print_bin;
+ GtkWidget *enroll_result_icon;
+ GtkWidget *enrollment_view;
+ GtkWidget *error_infobar;
+ GtkWidget *no_devices_found;
+ GtkWidget *prints_manager;
+
+ CcFingerprintManager *manager;
+ CcFprintdDevice *device;
+ gboolean device_claimed;
+ gulong device_signal_id;
+ gulong device_name_owner_id;
+ GCancellable *cancellable;
+ GStrv enrolled_fingers;
+ const char *enrolling_finger;
+ guint enroll_stages_passed;
+ guint enroll_stage_passed_id;
+ gdouble enroll_progress;
+};
+
+/* TODO - fprintd and API changes required:
+ - Identify the finger when the enroll dialog is visible
+ + Only if device supports identification
+ · And only in such case support enrolling more than one finger
+ - Delete a single fingerprint | and remove the "Delete all" button
+ - Highlight the finger when the sensor is touched during enrollment
+ - Add customized labels to fingerprints
+ - Devices hotplug (object manager)
+ */
+
+G_DEFINE_TYPE (CcFingerprintDialog, cc_fingerprint_dialog, GTK_TYPE_WINDOW)
+
+enum {
+ PROP_0,
+ PROP_MANAGER,
+ N_PROPS
+};
+
+#define N_VALID_FINGERS G_N_ELEMENTS (FINGER_IDS) - 1
+/* The order of the fingers here will affect the UI order */
+const char * FINGER_IDS[] = {
+ "right-index-finger",
+ "left-index-finger",
+ "right-thumb",
+ "right-middle-finger",
+ "right-ring-finger",
+ "right-little-finger",
+ "left-thumb",
+ "left-middle-finger",
+ "left-ring-finger",
+ "left-little-finger",
+ "any",
+};
+
+typedef enum {
+ ENROLL_STATE_NORMAL,
+ ENROLL_STATE_SUCCESS,
+ ENROLL_STATE_WARNING,
+ ENROLL_STATE_ERROR,
+ ENROLL_STATE_COMPLETED,
+ N_ENROLL_STATES,
+} EnrollState;
+
+const char * ENROLL_STATE_CLASSES[N_ENROLL_STATES] = {
+ "",
+ "success",
+ "warning",
+ "error",
+ "completed",
+};
+
+static GParamSpec *properties[N_PROPS];
+
+CcFingerprintDialog *
+cc_fingerprint_dialog_new (CcFingerprintManager *manager)
+{
+ return g_object_new (CC_TYPE_FINGERPRINT_DIALOG,
+ "fingerprint-manager", manager,
+ NULL);
+}
+
+static void
+disconnect_device_signals (CcFingerprintDialog *self)
+{
+ if (!self->device)
+ return;
+
+ if (self->device_signal_id)
+ {
+ g_signal_handler_disconnect (self->device, self->device_signal_id);
+ self->device_signal_id = 0;
+ }
+
+ if (self->device_name_owner_id)
+ {
+ g_signal_handler_disconnect (self->device, self->device_name_owner_id);
+ self->device_name_owner_id = 0;
+ }
+}
+
+static void
+cc_fingerprint_dialog_dispose (GObject *object)
+{
+ CcFingerprintDialog *self = CC_FINGERPRINT_DIALOG (object);
+
+ g_clear_handle_id (&self->enroll_stage_passed_id, g_source_remove);
+
+ if (self->device && self->device_claimed)
+ {
+ disconnect_device_signals (self);
+
+ if (self->enrolling_finger)
+ cc_fprintd_device_call_enroll_stop_sync (self->device, NULL, NULL);
+ cc_fprintd_device_call_release (self->device, NULL, NULL, NULL);
+ }
+
+ g_clear_object (&self->manager);
+ g_clear_object (&self->device);
+ g_clear_pointer (&self->enrolled_fingers, g_strfreev);
+
+ g_cancellable_cancel (self->cancellable);
+ g_clear_object (&self->cancellable);
+
+ G_OBJECT_CLASS (cc_fingerprint_dialog_parent_class)->dispose (object);
+}
+
+static void
+cc_fingerprint_dialog_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ CcFingerprintDialog *self = CC_FINGERPRINT_DIALOG (object);
+
+ switch (prop_id)
+ {
+ case PROP_MANAGER:
+ g_value_set_object (value, self->manager);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+cc_fingerprint_dialog_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ CcFingerprintDialog *self = CC_FINGERPRINT_DIALOG (object);
+
+ switch (prop_id)
+ {
+ case PROP_MANAGER:
+ g_set_object (&self->manager, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+notify_error (CcFingerprintDialog *self,
+ const char *error_message)
+{
+ if (error_message)
+ gtk_label_set_label (self->infobar_error, error_message);
+
+ gtk_widget_set_visible (self->error_infobar, error_message != NULL);
+}
+
+static gboolean
+fingerprint_icon_draw (GtkWidget *widget,
+ cairo_t *cr,
+ gdouble *progress_data)
+{
+ gdouble progress = 0.0f;
+
+ if (progress_data)
+ progress = *progress_data;
+
+ if (G_APPROX_VALUE (progress, 0.f, FLT_EPSILON) || progress > 1)
+ return FALSE;
+
+ GTK_WIDGET_GET_CLASS (widget)->draw (widget, cr);
+
+ if (progress > 0)
+ {
+ g_autoptr(GdkRGBA) outline_color = NULL;
+ GtkStyleContext *context;
+ GtkStateFlags state;
+ int outline_width;
+ int outline_offset;
+ int width;
+ int height;
+ int radius;
+ int delta;
+
+ context = gtk_widget_get_style_context (widget);
+ gtk_style_context_save (context);
+
+ state = gtk_style_context_get_state (context);
+
+ gtk_style_context_add_class (context, "progress");
+ gtk_style_context_get (context, state,
+ "outline-width", &outline_width,
+ "outline-offset", &outline_offset,
+ "outline-color", &outline_color,
+ NULL);
+
+ width = gtk_widget_get_allocated_width (widget);
+ height = gtk_widget_get_allocated_height (widget);
+ radius = MIN (width / 2, height / 2) + outline_offset;
+ delta = radius - outline_width / 2;
+
+ cairo_arc (cr, width / 2., height / 2., delta,
+ 1.5 * G_PI, (1.5 + progress * 2) * G_PI);
+ gdk_cairo_set_source_rgba (cr, outline_color);
+
+ cairo_set_line_width (cr, MIN (outline_width, radius));
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
+ cairo_stroke (cr);
+
+ gtk_style_context_restore (context);
+ }
+
+ return TRUE;
+}
+
+static GtkWidget *
+fingerprint_icon_new (const char *icon_name,
+ const char *label_text,
+ GType icon_widget_type,
+ gpointer progress_data,
+ GtkWidget **out_icon,
+ GtkWidget **out_label)
+{
+ GtkStyleContext *context;
+ GtkWidget *box;
+ GtkWidget *label;
+ GtkWidget *image;
+ GtkWidget *icon_widget;
+
+ g_return_val_if_fail (g_type_is_a (icon_widget_type, GTK_TYPE_WIDGET), NULL);
+
+ box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
+ gtk_widget_set_name (box, "fingerprint-box");
+ gtk_widget_set_halign (box, GTK_ALIGN_CENTER);
+
+ image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_DND);
+
+ if (icon_widget_type == GTK_TYPE_IMAGE)
+ icon_widget = image;
+ else
+ icon_widget = g_object_new (icon_widget_type, NULL);
+
+ if (progress_data)
+ g_signal_connect (image, "draw", G_CALLBACK (fingerprint_icon_draw),
+ progress_data);
+
+ if (g_type_is_a (icon_widget_type, GTK_TYPE_BUTTON))
+ {
+ gtk_button_set_image (GTK_BUTTON (icon_widget), image);
+ gtk_button_set_relief (GTK_BUTTON (icon_widget), GTK_RELIEF_NONE);
+ gtk_widget_set_can_focus (icon_widget, FALSE);
+ }
+
+ gtk_widget_set_halign (icon_widget, GTK_ALIGN_CENTER);
+ gtk_widget_set_valign (icon_widget, GTK_ALIGN_CENTER);
+ gtk_widget_set_name (icon_widget, "fingerprint-image");
+
+ gtk_container_add (GTK_CONTAINER (box), icon_widget);
+
+ context = gtk_widget_get_style_context (icon_widget);
+ gtk_style_context_add_class (context, "fingerprint-image");
+
+ label = gtk_label_new_with_mnemonic (label_text);
+ gtk_container_add (GTK_CONTAINER (box), label);
+
+ context = gtk_widget_get_style_context (box);
+ gtk_style_context_add_class (context, "fingerprint-icon");
+
+ if (out_icon)
+ *out_icon = icon_widget;
+
+ if (out_label)
+ *out_label = label;
+
+ return box;
+}
+
+static GtkWidget *
+fingerprint_menu_button (const char *icon_name,
+ const char *label_text)
+{
+ GtkWidget *flowbox_child;
+ GtkWidget *button;
+ GtkWidget *label;
+ GtkWidget *box;
+
+ box = fingerprint_icon_new (icon_name, label_text, GTK_TYPE_MENU_BUTTON, NULL,
+ &button, &label);
+
+ flowbox_child = gtk_flow_box_child_new ();
+ gtk_widget_set_focus_on_click (flowbox_child, FALSE);
+ gtk_widget_set_name (flowbox_child, "fingerprint-flowbox");
+
+ gtk_container_add (GTK_CONTAINER (flowbox_child), box);
+
+ g_object_set_data (G_OBJECT (flowbox_child), "button", button);
+ g_object_set_data (G_OBJECT (flowbox_child), "icon",
+ gtk_button_get_image (GTK_BUTTON (button)));
+ g_object_set_data (G_OBJECT (flowbox_child), "label", label);
+ g_object_set_data (G_OBJECT (button), "flowbox-child", flowbox_child);
+
+ return flowbox_child;
+}
+
+static gboolean
+prints_visibility_filter (GtkFlowBoxChild *child,
+ gpointer user_data)
+{
+ CcFingerprintDialog *self = user_data;
+ const char *finger_id;
+
+ if (gtk_stack_get_visible_child (self->stack) != self->prints_manager)
+ return FALSE;
+
+ finger_id = g_object_get_data (G_OBJECT (child), "finger-id");
+
+ if (!finger_id)
+ return TRUE;
+
+ if (!self->enrolled_fingers)
+ return FALSE;
+
+ return g_strv_contains ((const gchar **) self->enrolled_fingers, finger_id);
+}
+
+static void
+update_prints_to_add_visibility (CcFingerprintDialog *self)
+{
+ g_autoptr(GList) print_buttons = NULL;
+ GList *l;
+ guint i;
+
+ print_buttons = gtk_container_get_children (self->add_print_popover_box);
+
+ for (i = 0, l = print_buttons; i < N_VALID_FINGERS && l; ++i, l = l->next)
+ {
+ GtkWidget *button = l->data;
+ gboolean enrolled;
+
+ enrolled = self->enrolled_fingers &&
+ g_strv_contains ((const gchar **) self->enrolled_fingers,
+ FINGER_IDS[i]);
+
+ gtk_widget_set_visible (button, !enrolled);
+ }
+}
+
+static void
+update_prints_visibility (CcFingerprintDialog *self)
+{
+ update_prints_to_add_visibility (self);
+
+ gtk_flow_box_invalidate_filter (self->prints_gallery);
+}
+
+static void
+list_enrolled_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ g_auto(GStrv) enrolled_fingers = NULL;
+ g_autoptr(GError) error = NULL;
+ CcFprintdDevice *fprintd_device = CC_FPRINTD_DEVICE (object);
+ CcFingerprintDialog *self = user_data;
+ guint n_enrolled_fingers = 0;
+
+ cc_fprintd_device_call_list_enrolled_fingers_finish (fprintd_device,
+ &enrolled_fingers,
+ res, &error);
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ return;
+
+ gtk_spinner_stop (self->spinner);
+ gtk_widget_set_sensitive (GTK_WIDGET (self->add_print_icon), TRUE);
+
+ if (self->device_claimed)
+ gtk_widget_set_sensitive (GTK_WIDGET (self->prints_manager), TRUE);
+
+ if (error)
+ {
+ g_autofree char *dbus_error = g_dbus_error_get_remote_error (error);
+
+ if (!dbus_error || !g_str_has_suffix (dbus_error, ".Error.NoEnrolledPrints"))
+ {
+ g_autofree char *error_message = NULL;
+
+ g_dbus_error_strip_remote_error (error);
+ error_message = g_strdup_printf (_("Failed to list fingerprints: %s"),
+ error->message);
+ g_warning ("Listing of fingerprints on device %s failed: %s",
+ cc_fprintd_device_get_name (self->device), error->message);
+ notify_error (self, error_message);
+ return;
+ }
+ }
+ else
+ {
+ n_enrolled_fingers = g_strv_length (enrolled_fingers);
+ }
+
+ self->enrolled_fingers = g_steal_pointer (&enrolled_fingers);
+ gtk_flow_box_set_max_children_per_line (self->prints_gallery,
+ MIN (3, n_enrolled_fingers + 1));
+
+ update_prints_visibility (self);
+
+ if (n_enrolled_fingers == N_VALID_FINGERS)
+ gtk_widget_set_sensitive (self->add_print_icon, FALSE);
+
+ if (n_enrolled_fingers > 0)
+ gtk_widget_show (GTK_WIDGET (self->delete_prints_button));
+}
+
+static void
+update_prints_store (CcFingerprintDialog *self)
+{
+ ActUser *user;
+
+ g_assert_true (CC_FPRINTD_IS_DEVICE (self->device));
+
+ gtk_spinner_start (self->spinner);
+ gtk_widget_set_sensitive (GTK_WIDGET (self->add_print_icon), FALSE);
+ gtk_widget_hide (GTK_WIDGET (self->delete_prints_button));
+
+ g_clear_pointer (&self->enrolled_fingers, g_strfreev);
+
+ user = cc_fingerprint_manager_get_user (self->manager);
+ cc_fprintd_device_call_list_enrolled_fingers (self->device,
+ act_user_get_user_name (user),
+ self->cancellable,
+ list_enrolled_cb,
+ self);
+}
+
+static void
+delete_prints_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ g_autoptr(GError) error = NULL;
+ CcFprintdDevice *fprintd_device = CC_FPRINTD_DEVICE (object);
+ CcFingerprintDialog *self = user_data;
+
+ cc_fprintd_device_call_delete_enrolled_fingers2_finish (fprintd_device, res, &error);
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ return;
+
+ if (error)
+ {
+ g_autofree char *error_message = NULL;
+
+ g_dbus_error_strip_remote_error (error);
+ error_message = g_strdup_printf (_("Failed to delete saved fingerprints: %s"),
+ error->message);
+ g_warning ("Deletion of fingerprints on device %s failed: %s",
+ cc_fprintd_device_get_name (self->device), error->message);
+ notify_error (self, error_message);
+ }
+
+ update_prints_store (self);
+ cc_fingerprint_manager_update_state (self->manager, NULL, NULL);
+}
+
+static void
+delete_enrolled_prints (CcFingerprintDialog *self)
+{
+ g_return_if_fail (self->device_claimed);
+
+ gtk_widget_set_sensitive (GTK_WIDGET (self->prints_manager), FALSE);
+ gtk_spinner_start (self->spinner);
+
+ cc_fprintd_device_call_delete_enrolled_fingers2 (self->device,
+ self->cancellable,
+ delete_prints_cb,
+ self);
+}
+
+static const char *
+get_finger_name (const char *finger_id)
+{
+ if (g_str_equal (finger_id, "left-thumb"))
+ return _("Left thumb");
+ if (g_str_equal (finger_id, "left-middle-finger"))
+ return _("Left middle finger");
+ if (g_str_equal (finger_id, "left-index-finger"))
+ return _("_Left index finger");
+ if (g_str_equal (finger_id, "left-ring-finger"))
+ return _("Left ring finger");
+ if (g_str_equal (finger_id, "left-little-finger"))
+ return _("Left little finger");
+ if (g_str_equal (finger_id, "right-thumb"))
+ return _("Right thumb");
+ if (g_str_equal (finger_id, "right-middle-finger"))
+ return _("Right middle finger");
+ if (g_str_equal (finger_id, "right-index-finger"))
+ return _("_Right index finger");
+ if (g_str_equal (finger_id, "right-ring-finger"))
+ return _("Right ring finger");
+ if (g_str_equal (finger_id, "right-little-finger"))
+ return _("Right little finger");
+
+ g_return_val_if_reached (_("Unknown Finger"));
+}
+
+static gboolean
+have_multiple_devices (CcFingerprintDialog *self)
+{
+ g_autoptr(GList) devices_rows = NULL;
+
+ devices_rows = gtk_container_get_children (GTK_CONTAINER (self->devices_list));
+
+ return devices_rows && devices_rows->next;
+}
+
+static void
+set_enroll_result_message (CcFingerprintDialog *self,
+ EnrollState enroll_state,
+ const char *message)
+{
+ GtkStyleContext *style_context;
+ const char *icon_name;
+ guint i;
+
+ g_return_if_fail (enroll_state >= 0 && enroll_state < N_ENROLL_STATES);
+
+ style_context = gtk_widget_get_style_context (self->enroll_result_icon);
+
+ switch (enroll_state)
+ {
+ case ENROLL_STATE_WARNING:
+ case ENROLL_STATE_ERROR:
+ icon_name = "fingerprint-detection-warning-symbolic";
+ break;
+ case ENROLL_STATE_COMPLETED:
+ icon_name = "fingerprint-detection-complete-symbolic";
+ break;
+ default:
+ icon_name = "fingerprint-detection-symbolic";
+ }
+
+ for (i = 0; i < N_ENROLL_STATES; ++i)
+ gtk_style_context_remove_class (style_context, ENROLL_STATE_CLASSES[i]);
+
+ gtk_style_context_add_class (style_context, ENROLL_STATE_CLASSES[enroll_state]);
+
+ gtk_image_set_from_icon_name (self->enroll_result_image, icon_name, GTK_ICON_SIZE_DND);
+ gtk_label_set_label (self->enroll_result_message, message);
+}
+
+static gboolean
+stage_passed_timeout_cb (gpointer user_data)
+{
+ CcFingerprintDialog *self = user_data;
+
+ set_enroll_result_message (self, ENROLL_STATE_NORMAL, NULL);
+ self->enroll_stage_passed_id = 0;
+
+ return FALSE;
+}
+
+static void
+handle_enroll_signal (CcFingerprintDialog *self,
+ const char *result,
+ gboolean done)
+{
+ gboolean completed;
+
+ g_return_if_fail (self->enrolling_finger);
+
+ g_debug ("Device enroll result message: %s, done: %d", result, done);
+
+ completed = g_str_equal (result, "enroll-completed");
+ g_clear_handle_id (&self->enroll_stage_passed_id, g_source_remove);
+
+ if (g_str_equal (result, "enroll-stage-passed") || completed)
+ {
+ guint enroll_stages;
+
+ enroll_stages = cc_fprintd_device_get_num_enroll_stages (self->device);
+
+ self->enroll_stages_passed++;
+
+ if (enroll_stages > 0)
+ self->enroll_progress =
+ MIN (1.0f, self->enroll_stages_passed / (double) enroll_stages);
+ else
+ g_warning ("The device %s requires an invalid number of enroll stages (%u)",
+ cc_fprintd_device_get_name (self->device), enroll_stages);
+
+ g_debug ("Enroll state passed, %u/%u (%.2f%%)",
+ self->enroll_stages_passed, (guint) enroll_stages,
+ self->enroll_progress);
+
+ if (!completed)
+ {
+ set_enroll_result_message (self, ENROLL_STATE_SUCCESS, NULL);
+
+ self->enroll_stage_passed_id =
+ g_timeout_add (750, stage_passed_timeout_cb, self);
+ }
+ else
+ {
+ if (!G_APPROX_VALUE (self->enroll_progress, 1.0f, FLT_EPSILON))
+ {
+ g_warning ("Device marked enroll as completed, but progress is at %.2f",
+ self->enroll_progress);
+ self->enroll_progress = 1.0f;
+ }
+ }
+ }
+ else if (!done)
+ {
+ const char *scan_type;
+ const char *message;
+ gboolean is_swipe;
+
+ scan_type = cc_fprintd_device_get_scan_type (self->device);
+ is_swipe = g_str_equal (scan_type, "swipe");
+
+ message = TR (enroll_result_str_to_msg (result, is_swipe));
+ set_enroll_result_message (self, ENROLL_STATE_NORMAL, message);
+ }
+
+ if (done)
+ {
+ if (completed)
+ {
+ /* TRANSLATORS: This is the message shown when the fingerprint
+ * enrollment has been completed successfully */
+ set_enroll_result_message (self, ENROLL_STATE_COMPLETED,
+ C_("Fingerprint enroll state", "Complete"));
+ gtk_widget_set_sensitive (GTK_WIDGET (self->cancel_button), FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (self->done_button), TRUE);
+ gtk_widget_grab_focus (GTK_WIDGET (self->done_button));
+ }
+ else
+ {
+ const char *message;
+
+ if (g_str_equal (result, "enroll-disconnected"))
+ message = _("Fingerprint device disconnected");
+ else if (g_str_equal (result, "enroll-data-full"))
+ message = _("Fingerprint device storage is full");
+ else
+ message = _("Failed to enroll new fingerprint");
+
+ self->enrolling_finger = NULL;
+ set_enroll_result_message (self, ENROLL_STATE_WARNING, message);
+ }
+ }
+}
+
+static void
+enroll_start_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ g_autoptr(GError) error = NULL;
+ CcFprintdDevice *fprintd_device = CC_FPRINTD_DEVICE (object);
+ CcFingerprintDialog *self = user_data;
+
+ cc_fprintd_device_call_enroll_start_finish (fprintd_device, res, &error);
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ return;
+
+ gtk_spinner_stop (self->spinner);
+
+ if (error)
+ {
+ g_autofree char *error_message = NULL;
+
+ self->enrolling_finger = NULL;
+
+ g_dbus_error_strip_remote_error (error);
+ error_message = g_strdup_printf (_("Failed to start enrollment: %s"),
+ error->message);
+ g_warning ("Enrollment on device %s failed: %s",
+ cc_fprintd_device_get_name (self->device), error->message);
+ notify_error (self, error_message);
+
+ set_enroll_result_message (self, ENROLL_STATE_ERROR,
+ C_("Fingerprint enroll state",
+ "Failed to enroll new fingerprint"));
+ gtk_widget_set_sensitive (self->enrollment_view, FALSE);
+
+ return;
+ }
+}
+
+static void
+enroll_stop_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ g_autoptr(GError) error = NULL;
+ CcFprintdDevice *fprintd_device = CC_FPRINTD_DEVICE (object);
+ CcFingerprintDialog *self = user_data;
+
+ cc_fprintd_device_call_enroll_stop_finish (fprintd_device, res, &error);
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ return;
+
+ self->enrolling_finger = NULL;
+ gtk_spinner_stop (self->spinner);
+ gtk_widget_set_sensitive (self->enrollment_view, TRUE);
+ gtk_stack_set_visible_child (self->stack, self->prints_manager);
+
+ if (error)
+ {
+ g_autofree char *error_message = NULL;
+
+ g_dbus_error_strip_remote_error (error);
+ error_message = g_strdup_printf (_("Failed to stop enrollment: %s"),
+ error->message);
+ g_warning ("Stopping enrollment on device %s failed: %s",
+ cc_fprintd_device_get_name (self->device), error->message);
+ notify_error (self, error_message);
+
+ return;
+ }
+
+ cc_fingerprint_manager_update_state (self->manager, NULL, NULL);
+}
+
+static void
+enroll_stop (CcFingerprintDialog *self)
+{
+ g_return_if_fail (self->enrolling_finger);
+
+ gtk_spinner_start (self->spinner);
+ gtk_widget_set_sensitive (self->enrollment_view, FALSE);
+ cc_fprintd_device_call_enroll_stop (self->device, self->cancellable,
+ enroll_stop_cb, self);
+}
+
+static char *
+get_enrollment_string (CcFingerprintDialog *self,
+ const char *finger_id)
+{
+ char *ret;
+ const char *scan_type;
+ const char *device_name;
+ gboolean is_swipe;
+
+ device_name = NULL;
+ scan_type = cc_fprintd_device_get_scan_type (self->device);
+ is_swipe = g_str_equal (scan_type, "swipe");
+
+ if (have_multiple_devices (self))
+ device_name = cc_fprintd_device_get_name (self->device);
+
+ ret = TR (finger_str_to_msg (finger_id, device_name, is_swipe));
+
+ if (ret)
+ return ret;
+
+ return g_strdup (_("Repeatedly lift and place your finger on the reader to enroll your fingerprint"));
+}
+
+static void
+enroll_finger (CcFingerprintDialog *self,
+ const char *finger_id)
+{
+ g_auto(GStrv) tmp_finger_name = NULL;
+ g_autofree char *enroll_message = NULL;
+ g_autofree char *finger_name = NULL;
+
+ g_return_if_fail (finger_id);
+
+ self->enrolling_finger = finger_id;
+ self->enroll_progress = 0;
+ self->enroll_stages_passed = 0;
+
+ g_debug ("Enrolling finger %s", finger_id);
+
+ enroll_message = TR (get_enrollment_string (self, finger_id));
+ tmp_finger_name = g_strsplit (get_finger_name (finger_id), "_", -1);
+ finger_name = g_strjoinv ("", tmp_finger_name);
+
+ set_enroll_result_message (self, ENROLL_STATE_NORMAL, NULL);
+ gtk_stack_set_visible_child (self->stack, self->enrollment_view);
+ gtk_label_set_label (self->enroll_message, enroll_message);
+ gtk_entry_set_text (self->enroll_print_entry, finger_name);
+ gtk_spinner_start (self->spinner);
+
+ cc_fprintd_device_call_enroll_start (self->device, finger_id, self->cancellable,
+ enroll_start_cb, self);
+}
+
+static void
+populate_enrollment_view (CcFingerprintDialog *self)
+{
+ GtkStyleContext *style_context;
+
+ self->enroll_result_icon =
+ fingerprint_icon_new ("fingerprint-detection-symbolic",
+ NULL,
+ GTK_TYPE_IMAGE,
+ &self->enroll_progress,
+ (GtkWidget **) &self->enroll_result_image,
+ (GtkWidget **) &self->enroll_result_message);
+
+ gtk_container_add (GTK_CONTAINER (self->enroll_print_bin), self->enroll_result_icon);
+
+ style_context = gtk_widget_get_style_context (self->enroll_result_icon);
+ gtk_style_context_add_class (style_context, "enroll-status");
+
+ gtk_widget_show_all (self->enroll_print_bin);
+}
+
+static void
+reenroll_finger_cb (CcFingerprintDialog *self)
+{
+ GtkWidget *button;
+ GtkWidget *flowbox_child;
+ const char *finger_id;
+
+ button = gtk_popover_get_relative_to (GTK_POPOVER (self->print_popover));
+ flowbox_child = g_object_get_data (G_OBJECT (button), "flowbox-child");
+ finger_id = g_object_get_data (G_OBJECT (flowbox_child), "finger-id");
+
+ enroll_finger (self, finger_id);
+}
+
+static void
+on_print_activated_cb (GtkFlowBox *flowbox,
+ GtkFlowBoxChild *child,
+ CcFingerprintDialog *self)
+{
+ GtkWidget *selected_button;
+
+ selected_button = g_object_get_data (G_OBJECT (child), "button");
+ gtk_button_clicked (GTK_BUTTON (selected_button));
+}
+
+static void
+on_enroll_cb (CcFingerprintDialog *self,
+ GtkModelButton *button)
+{
+ const char *finger_id;
+
+ finger_id = g_object_get_data (G_OBJECT (button), "finger-id");
+ enroll_finger (self, finger_id);
+}
+
+static void
+populate_add_print_popover (CcFingerprintDialog *self)
+{
+ guint i;
+
+ for (i = 0; i < N_VALID_FINGERS; ++i)
+ {
+ GtkWidget *finger_item;
+
+ finger_item = gtk_model_button_new ();
+ gtk_button_set_label (GTK_BUTTON (finger_item), get_finger_name (FINGER_IDS[i]));
+ gtk_button_set_use_underline (GTK_BUTTON (finger_item), TRUE);
+ g_object_set_data (G_OBJECT (finger_item), "finger-id", (gpointer) FINGER_IDS[i]);
+ gtk_container_add (self->add_print_popover_box, finger_item);
+
+ g_signal_connect_object (finger_item, "clicked", G_CALLBACK (on_enroll_cb),
+ self, G_CONNECT_SWAPPED);
+ }
+}
+
+static void
+populate_prints_gallery (CcFingerprintDialog *self)
+{
+ const char *add_print_label;
+ GtkWidget *button;
+ GtkStyleContext *style_context;
+ guint i;
+
+ g_return_if_fail (!GTK_IS_WIDGET (self->add_print_icon));
+
+ for (i = 0; i < N_VALID_FINGERS; ++i)
+ {
+ GtkWidget *flowbox_child;
+
+ flowbox_child = fingerprint_menu_button ("fingerprint-detection-symbolic",
+ get_finger_name (FINGER_IDS[i]));
+
+ button = g_object_get_data (G_OBJECT (flowbox_child), "button");
+
+ gtk_menu_button_set_popover (GTK_MENU_BUTTON (button),
+ GTK_WIDGET (self->print_popover));
+ /* Move the popover on click, so we can just reuse the same instance */
+ g_signal_connect_object (button, "clicked",
+ G_CALLBACK (gtk_popover_set_relative_to),
+ self->print_popover, G_CONNECT_SWAPPED);
+
+ g_object_set_data (G_OBJECT (flowbox_child), "finger-id",
+ (gpointer) FINGER_IDS[i]);
+
+ gtk_flow_box_insert (self->prints_gallery, flowbox_child, i);
+ }
+
+ /* TRANSLATORS: This is the label for the button to enroll a new finger */
+ add_print_label = _("Scan new fingerprint");
+ self->add_print_icon = fingerprint_menu_button ("list-add-symbolic",
+ add_print_label);
+ style_context = gtk_widget_get_style_context (self->add_print_icon);
+ gtk_style_context_add_class (style_context, "fingerprint-print-add");
+
+ populate_add_print_popover (self);
+ button = g_object_get_data (G_OBJECT (self->add_print_icon), "button");
+ gtk_menu_button_set_popover (GTK_MENU_BUTTON (button),
+ GTK_WIDGET (self->add_print_popover));
+
+ gtk_flow_box_insert (self->prints_gallery, self->add_print_icon, -1);
+ gtk_flow_box_set_max_children_per_line (self->prints_gallery, 1);
+
+ gtk_widget_show_all (GTK_WIDGET (self->prints_gallery));
+ gtk_flow_box_set_filter_func (self->prints_gallery, prints_visibility_filter,
+ self, NULL);
+
+ update_prints_visibility (self);
+}
+
+static void
+release_device_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ g_autoptr(GError) error = NULL;
+ CcFprintdDevice *fprintd_device = CC_FPRINTD_DEVICE (object);
+ CcFingerprintDialog *self = user_data;
+
+ cc_fprintd_device_call_release_finish (fprintd_device, res, &error);
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ return;
+
+ if (error)
+ {
+ g_autofree char *error_message = NULL;
+
+ g_dbus_error_strip_remote_error (error);
+ error_message = g_strdup_printf (_("Failed to release fingerprint device %s: %s"),
+ cc_fprintd_device_get_name (self->device),
+ error->message);
+ g_warning ("%s", error_message);
+
+ notify_error (self, error_message);
+ return;
+ }
+
+ self->device_claimed = FALSE;
+}
+
+static void
+release_device (CcFingerprintDialog *self)
+{
+ if (!self->device || !self->device_claimed)
+ return;
+
+ disconnect_device_signals (self);
+
+ cc_fprintd_device_call_release (self->device,
+ self->cancellable,
+ release_device_cb,
+ self);
+}
+
+static void
+on_device_signal (CcFingerprintDialog *self,
+ gchar *sender_name,
+ gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ if (g_str_equal (signal_name, "EnrollStatus"))
+ {
+ const char *result;
+ gboolean done;
+
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sb)")))
+ {
+ g_warning ("Unexpected enroll parameters type %s",
+ g_variant_get_type_string (parameters));
+ return;
+ }
+
+ g_variant_get (parameters, "(&sb)", &result, &done);
+ handle_enroll_signal (self, result, done);
+ }
+}
+
+static void claim_device (CcFingerprintDialog *self);
+
+static void
+on_device_owner_changed (CcFprintdDevice *device,
+ GParamSpec *spec,
+ CcFingerprintDialog *self)
+{
+ g_autofree char *name_owner = NULL;
+
+ name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (device));
+
+ if (!name_owner)
+ {
+ if (self->device_claimed)
+ {
+ disconnect_device_signals (self);
+
+ if (self->enrolling_finger)
+ {
+ set_enroll_result_message (self, ENROLL_STATE_ERROR,
+ C_("Fingerprint enroll state",
+ "Problem Reading Device"));
+ self->enrolling_finger = NULL;
+ }
+
+ self->device_claimed = FALSE;
+ claim_device (self);
+ }
+ }
+}
+
+static void
+claim_device_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ g_autoptr(GError) error = NULL;
+ CcFprintdDevice *fprintd_device = CC_FPRINTD_DEVICE (object);
+ CcFingerprintDialog *self = user_data;
+
+ cc_fprintd_device_call_claim_finish (fprintd_device, res, &error);
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ return;
+
+ if (error)
+ {
+ g_autofree char *dbus_error = g_dbus_error_get_remote_error (error);
+ g_autofree char *error_message = NULL;
+
+ if (dbus_error && g_str_has_suffix (dbus_error, ".Error.AlreadyInUse"))
+ self->device_claimed = TRUE;
+
+ g_dbus_error_strip_remote_error (error);
+ error_message = g_strdup_printf (_("Failed to claim fingerprint device %s: %s"),
+ cc_fprintd_device_get_name (self->device),
+ error->message);
+ g_warning ("%s", error_message);
+ notify_error (self, error_message);
+ return;
+ }
+
+ gtk_widget_set_sensitive (self->prints_manager, TRUE);
+ self->device_claimed = TRUE;
+ self->device_signal_id = g_signal_connect_object (self->device, "g-signal",
+ G_CALLBACK (on_device_signal),
+ self, G_CONNECT_SWAPPED);
+ self->device_name_owner_id = g_signal_connect_object (self->device, "notify::g-name-owner",
+ G_CALLBACK (on_device_owner_changed),
+ self, 0);
+}
+
+static void
+claim_device (CcFingerprintDialog *self)
+{
+ ActUser *user;
+
+ user = cc_fingerprint_manager_get_user (self->manager);
+ gtk_widget_set_sensitive (self->prints_manager, FALSE);
+
+ cc_fprintd_device_call_claim (self->device,
+ act_user_get_user_name (user),
+ self->cancellable,
+ claim_device_cb,
+ self);
+}
+
+static void
+on_stack_child_changed (CcFingerprintDialog *self)
+{
+ GtkWidget *visible_child = gtk_stack_get_visible_child (self->stack);
+
+ g_debug ("Fingerprint dialog child changed: %s",
+ gtk_stack_get_visible_child_name (self->stack));
+
+ gtk_widget_hide (GTK_WIDGET (self->back_button));
+ gtk_widget_hide (GTK_WIDGET (self->cancel_button));
+ gtk_widget_hide (GTK_WIDGET (self->done_button));
+
+ gtk_header_bar_set_show_close_button (self->titlebar, TRUE);
+ gtk_flow_box_invalidate_filter (self->prints_gallery);
+
+ if (visible_child == self->prints_manager)
+ {
+ gtk_widget_set_visible (GTK_WIDGET (self->back_button),
+ have_multiple_devices (self));
+ notify_error (self, NULL);
+ update_prints_store (self);
+
+ if (!self->device_claimed)
+ claim_device (self);
+ }
+ else if (visible_child == self->enrollment_view)
+ {
+ gtk_header_bar_set_show_close_button (self->titlebar, FALSE);
+
+ gtk_widget_show (GTK_WIDGET (self->cancel_button));
+ gtk_widget_set_sensitive (GTK_WIDGET (self->cancel_button), TRUE);
+
+ gtk_widget_show (GTK_WIDGET (self->done_button));
+ gtk_widget_set_sensitive (GTK_WIDGET (self->done_button), FALSE);
+ }
+ else
+ {
+ release_device (self);
+ g_clear_object (&self->device);
+ }
+}
+
+static void
+cc_fingerprint_dialog_init (CcFingerprintDialog *self)
+{
+ g_autoptr(GtkCssProvider) provider = NULL;
+
+ self->cancellable = g_cancellable_new ();
+
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ provider = gtk_css_provider_new ();
+ gtk_css_provider_load_from_resource (provider,
+ "/org/gnome/control-center/user-accounts/cc-fingerprint-dialog.css");
+ gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+ GTK_STYLE_PROVIDER (provider),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+ on_stack_child_changed (self);
+ g_signal_connect_object (self->stack, "notify::visible-child",
+ G_CALLBACK (on_stack_child_changed), self,
+ G_CONNECT_SWAPPED);
+
+ g_object_bind_property (self->stack, "visible-child-name",
+ self->title, "label", G_BINDING_SYNC_CREATE);
+
+ populate_prints_gallery (self);
+ populate_enrollment_view (self);
+}
+
+static void
+select_device_row (CcFingerprintDialog *self,
+ GtkListBoxRow *row,
+ GtkListBox *listbox)
+{
+ CcFprintdDevice *device = g_object_get_data (G_OBJECT (row), "device");
+
+ g_return_if_fail (CC_FPRINTD_DEVICE (device));
+
+ g_set_object (&self->device, device);
+ gtk_stack_set_visible_child (self->stack, self->prints_manager);
+}
+
+static void
+on_devices_list (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ g_autolist (CcFprintdDevice) fprintd_devices = NULL;
+ g_autoptr(GError) error = NULL;
+ CcFingerprintManager *fingerprint_manager = CC_FINGERPRINT_MANAGER (object);
+ CcFingerprintDialog *self = CC_FINGERPRINT_DIALOG (user_data);
+
+ fprintd_devices = cc_fingerprint_manager_get_devices_finish (fingerprint_manager,
+ res, &error);
+ gtk_spinner_stop (self->spinner);
+
+ if (fprintd_devices == NULL)
+ {
+ if (error)
+ {
+ g_autofree char *error_message = NULL;
+
+ g_dbus_error_strip_remote_error (error);
+ error_message = g_strdup_printf (_("Failed to get fingerprint devices: %s"),
+ error->message);
+ g_warning ("%s", error_message);
+ notify_error (self, error_message);
+ }
+
+ gtk_stack_set_visible_child (self->stack, GTK_WIDGET (self->no_devices_found));
+ }
+ else if (fprintd_devices->next == NULL)
+ {
+ /* We have just one device... Skip devices selection */
+ self->device = g_object_ref (fprintd_devices->data);
+ gtk_stack_set_visible_child (self->stack, self->prints_manager);
+ }
+ else
+ {
+ GList *l;
+
+ for (l = fprintd_devices; l; l = l->next)
+ {
+ CcFprintdDevice *device = l->data;
+ CcListRow *device_row;
+
+ device_row = g_object_new (CC_TYPE_LIST_ROW,
+ "visible", TRUE,
+ "icon-name", "go-next-symbolic",
+ "title", cc_fprintd_device_get_name (device),
+ NULL);
+
+ gtk_list_box_insert (self->devices_list, GTK_WIDGET (device_row), -1);
+ g_object_set_data_full (G_OBJECT (device_row), "device",
+ g_object_ref (device), g_object_unref);
+ }
+
+ gtk_stack_set_visible_child (self->stack, self->device_selector);
+ }
+}
+
+static void
+cc_fingerprint_dialog_constructed (GObject *object)
+{
+ CcFingerprintDialog *self = CC_FINGERPRINT_DIALOG (object);
+
+ bindtextdomain ("fprintd", GNOMELOCALEDIR);
+ bind_textdomain_codeset ("fprintd", "UTF-8");
+
+ gtk_spinner_start (self->spinner);
+ cc_fingerprint_manager_get_devices (self->manager, self->cancellable,
+ on_devices_list, self);
+}
+
+static void
+back_button_clicked_cb (CcFingerprintDialog *self)
+{
+ if (gtk_stack_get_visible_child (self->stack) == self->prints_manager)
+ {
+ notify_error (self, NULL);
+ gtk_stack_set_visible_child (self->stack, self->device_selector);
+ return;
+ }
+
+ g_return_if_reached ();
+}
+
+static void
+confirm_deletion_button_clicked_cb (CcFingerprintDialog *self)
+{
+ gtk_widget_hide (self->delete_confirmation_infobar);
+ delete_enrolled_prints (self);
+}
+
+static void
+cancel_deletion_button_clicked_cb (CcFingerprintDialog *self)
+{
+ gtk_widget_set_sensitive (self->prints_manager, TRUE);
+ gtk_widget_hide (self->delete_confirmation_infobar);
+}
+
+static void
+delete_prints_button_clicked_cb (CcFingerprintDialog *self)
+{
+ gtk_widget_set_sensitive (self->prints_manager, FALSE);
+ gtk_widget_show (self->delete_confirmation_infobar);
+}
+
+static void
+cancel_button_clicked_cb (CcFingerprintDialog *self)
+{
+ if (self->enrolling_finger)
+ {
+ g_cancellable_cancel (self->cancellable);
+ g_set_object (&self->cancellable, g_cancellable_new ());
+
+ g_debug ("Cancelling enroll operation");
+ enroll_stop (self);
+ }
+ else
+ {
+ gtk_stack_set_visible_child (self->stack, self->prints_manager);
+ }
+}
+
+static void
+done_button_clicked_cb (CcFingerprintDialog *self)
+{
+ g_return_if_fail (self->enrolling_finger);
+
+ g_debug ("Completeing enroll operation");
+ enroll_stop (self);
+}
+
+static void
+fingerprint_dialog_delete_cb (CcFingerprintDialog *self)
+{
+ cc_fingerprint_manager_update_state (self->manager, NULL, NULL);
+ gtk_widget_destroy (GTK_WIDGET (self));
+}
+
+static void
+cc_fingerprint_dialog_class_init (CcFingerprintDialogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ gtk_widget_class_set_template_from_resource (widget_class,
+ "/org/gnome/control-center/user-accounts/cc-fingerprint-dialog.ui");
+
+ object_class->constructed = cc_fingerprint_dialog_constructed;
+ object_class->dispose = cc_fingerprint_dialog_dispose;
+ object_class->get_property = cc_fingerprint_dialog_get_property;
+ object_class->set_property = cc_fingerprint_dialog_set_property;
+
+ properties[PROP_MANAGER] =
+ g_param_spec_object ("fingerprint-manager",
+ "FingerprintManager",
+ "The CC fingerprint manager",
+ CC_TYPE_FINGERPRINT_MANAGER,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, add_print_popover);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, add_print_popover_box);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, back_button);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, cancel_button);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, delete_confirmation_infobar);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, delete_prints_button);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, device_selector);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, devices_list);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, done_button);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, enroll_message);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, enroll_print_bin);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, enroll_print_entry);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, enrollment_view);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, error_infobar);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, infobar_error);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, no_devices_found);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, print_popover);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, prints_gallery);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, prints_manager);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, spinner);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, stack);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, title);
+ gtk_widget_class_bind_template_child (widget_class, CcFingerprintDialog, titlebar);
+
+ gtk_widget_class_bind_template_callback (widget_class, back_button_clicked_cb);
+ gtk_widget_class_bind_template_callback (widget_class, cancel_button_clicked_cb);
+ gtk_widget_class_bind_template_callback (widget_class, cancel_deletion_button_clicked_cb);
+ gtk_widget_class_bind_template_callback (widget_class, confirm_deletion_button_clicked_cb);
+ gtk_widget_class_bind_template_callback (widget_class, delete_prints_button_clicked_cb);
+ gtk_widget_class_bind_template_callback (widget_class, done_button_clicked_cb);
+ gtk_widget_class_bind_template_callback (widget_class, fingerprint_dialog_delete_cb);
+ gtk_widget_class_bind_template_callback (widget_class, on_print_activated_cb);
+ gtk_widget_class_bind_template_callback (widget_class, reenroll_finger_cb);
+ gtk_widget_class_bind_template_callback (widget_class, select_device_row);
+}
diff --git a/panels/user-accounts/cc-fingerprint-dialog.h b/panels/user-accounts/cc-fingerprint-dialog.h
new file mode 100644
index 000000000..9afac0ba7
--- /dev/null
+++ b/panels/user-accounts/cc-fingerprint-dialog.h
@@ -0,0 +1,37 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2020 Canonical Ltd.
+ *
+ * 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 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * Authors: Marco Trevisan <marco trevisan canonical com>
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+#include "cc-fingerprint-manager.h"
+
+G_BEGIN_DECLS
+
+#define CC_TYPE_FINGERPRINT_DIALOG (cc_fingerprint_dialog_get_type ())
+
+G_DECLARE_FINAL_TYPE (CcFingerprintDialog, cc_fingerprint_dialog,
+ CC, FINGERPRINT_DIALOG, GtkWindow)
+
+CcFingerprintDialog *cc_fingerprint_dialog_new (CcFingerprintManager *manager);
+
+G_END_DECLS
diff --git a/panels/user-accounts/cc-fingerprint-dialog.ui b/panels/user-accounts/cc-fingerprint-dialog.ui
new file mode 100644
index 000000000..076625740
--- /dev/null
+++ b/panels/user-accounts/cc-fingerprint-dialog.ui
@@ -0,0 +1,461 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="CcFingerprintDialog" parent="GtkWindow">
+ <style>
+ <class name="fingerprint" />
+ </style>
+ <property name="name">fingerprint-dialog</property>
+ <property name="title" translatable="yes">Fingerprint Manager</property>
+ <property name="type-hint">dialog</property>
+ <property name="window-position">center-on-parent</property>
+ <property name="destroy-with-parent">True</property>
+ <property name="default-width">600</property>
+ <property name="default-height">400</property>
+ <property name="modal">True</property>
+ <signal name="delete-event" handler="fingerprint_dialog_delete_cb"/>
+ <child type="titlebar">
+ <object class="GtkHeaderBar" id="titlebar">
+ <property name="visible">True</property>
+ <property name="show-close-button">True</property>
+ <child type="title">
+ <object class="GtkLabel" id="title">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Fingerprint</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel_button">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="receives_default">False</property>
+ <property name="valign">center</property>
+ <property name="use-underline">True</property>
+ <property name="label" translatable="yes">_Cancel</property>
+ <signal name="clicked" handler="cancel_button_clicked_cb" object="CcFingerprintDialog"
swapped="yes" />
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="back_button">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="receives_default">False</property>
+ <property name="valign">center</property>
+ <property name="use-underline">True</property>
+ <signal name="clicked" handler="back_button_clicked_cb" object="CcFingerprintDialog"
swapped="yes" />
+ <style>
+ <class name="image-button"/>
+ </style>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="a11y-back">
+ <property name="accessible-name" translatable="yes">Back</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">go-previous-symbolic</property>
+ <property name="icon_size">1</property>
+ </object>
+ </child>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkButton" id="done_button">
+ <property name="use-underline">True</property>
+ <property name="can-default">True</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="label" translatable="yes">_Done</property>
+ <signal name="clicked" handler="done_button_clicked_cb" object="CcFingerprintDialog"
swapped="yes" />
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
+
+ <child>
+ <object class="GtkSpinner" id="spinner">
+ <property name="visible">True</property>
+ <property name="active">False</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+
+ <child>
+ <object class="GtkInfoBar" id="delete_confirmation_infobar">
+ <property name="visible">False</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">0</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">5</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton">
+ <signal name="clicked" handler="cancel_deletion_button_clicked_cb"
object="CcFingerprintDialog" swapped="yes"/>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_No</property>
+ <property name="use-underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton">
+ <signal name="clicked" handler="confirm_deletion_button_clicked_cb"
object="CcFingerprintDialog" swapped="yes"/>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">_Yes</property>
+ <property name="use-underline">True</property>
+ <style>
+ <class name="destructive-action"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child internal-child="content_area">
+ <object class="GtkBox">
+ <property name="can_focus">False</property>
+ <property name="spacing">16</property>
+ <property name="margin-start">12</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="hexpand">False</property>
+ <property name="wrap">True</property>
+ <property name="label" translatable="yes">Do you want to delete your registered
fingerprints so fingerprint login is disabled?</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+
+ <child>
+ <object class="GtkInfoBar" id="error_infobar">
+ <property name="name">error_infobar</property>
+ <property name="visible">False</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">0</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <style>
+ <class name="error"/>
+ </style>
+ <child internal-child="content_area">
+ <object class="GtkBox">
+ <property name="can_focus">False</property>
+ <property name="spacing">16</property>
+ <child>
+ <object class="GtkLabel" id="infobar_error">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="hexpand">False</property>
+ <property name="wrap">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="halign">fill</property>
+ <property name="valign">fill</property>
+ <property name="propagate-natural-width">True</property>
+ <property name="can-focus">False</property>
+ <property name="hscrollbar-policy">never</property>
+
+ <child>
+ <object class="GtkStack" id="stack">
+ <property name="visible">True</property>
+ <property name="transition_duration">300</property>
+ <property name="margin-start">20</property>
+ <property name="margin-end">20</property>
+ <property name="margin-top">30</property>
+ <property name="margin-bottom">30</property>
+ <property name="width_request">360</property>
+ <property name="halign">center</property>
+
+ <child>
+ <object class="GtkBox" id="no_devices_found">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="valign">center</property>
+ <property name="spacing">12</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="icon_name">fingerprint-detection-symbolic</property>
+ <property name="pixel_size">192</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" comments="Translators: This is the empty
state page label which states that there are no devices ready.">No Fingerprint device</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ <attribute name="scale" value="1.6"/>
+ </attributes>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Ensure the device is properly
connected.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name" translatable="yes">No fingerprint device</property>
+ </packing>
+ </child>
+
+ <child>
+ <object class="GtkBox" id="device_selector">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="spacing">10</property>
+ <property name="orientation">vertical</property>
+
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Choose the fingerprint device you want to
configure</property>
+ <property name="halign">start</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="propagate-natural-height">True</property>
+ <child>
+ <object class="GtkListBox" id="devices_list">
+ <property name="visible">True</property>
+ <property name="selection-mode">none</property>
+ <property name="valign">center</property>
+ <signal name="row-activated" handler="select_device_row"
object="CcFingerprintDialog" swapped="yes"/>
+ <style>
+ <class name="frame" />
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name" translatable="yes">Fingerprint Device</property>
+ </packing>
+ </child>
+
+ <child>
+ <object class="GtkBox" id="prints_manager">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="valign">fill</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Fingerprint login allows you to unlock and
log into your computer with your finger</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkFlowBox" id="prints_gallery">
+ <style>
+ <class name="prints-gallery" />
+ </style>
+ <property name="visible">True</property>
+ <property name="margin">12</property>
+ <property name="column-spacing">12</property>
+ <property name="row-spacing">12</property>
+ <property name="homogeneous">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="vexpand">True</property>
+ <property name="min-children-per-line">1</property>
+ <property name="max-children-per-line">3</property>
+ <property name="activate-on-single-click">True</property>
+ <property name="selection-mode">none</property>
+ <signal name="child-activated" handler="on_print_activated_cb"
object="CcFingerprintDialog" swapped="no" />
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkButton" id="delete_prints_button">
+ <property name="visible">False</property>
+ <property name="can_focus">True</property>
+ <property name="halign">end</property>
+ <property name="use-underline">True</property>
+ <property name="label" translatable="yes">_Delete Fingerprints</property>
+ <property name="margin-top">10</property>
+ <property name="margin-bottom">10</property>
+ <signal name="clicked" handler="delete_prints_button_clicked_cb"
object="CcFingerprintDialog" swapped="yes"/>
+ <style>
+ <class name="destructive-action"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name" translatable="yes">Fingerprint Login</property>
+ </packing>
+ </child>
+
+ <child>
+ <object class="GtkBox" id="enrollment_view">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="valign">fill</property>
+ <property name="spacing">12</property>
+ <style>
+ <class name="enrollment" />
+ </style>
+ <child>
+ <object class="GtkLabel" id="enroll_message">
+ <property name="visible">True</property>
+ <property name="wrap">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="margin">12</property>
+ <property name="spacing">12</property>
+ <property name="halign">fill</property>
+ <property name="valign">center</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox" id="enroll_print_bin">
+ <property name="halign">center</property>
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkEntry" id="enroll_print_entry">
+ <property name="valign">end</property>
+ <property name="visible">True</property>
+ <property name="halign">center</property>
+ <property name="editable">False</property>
+ <property name="sensitive">False</property>
+ <property name="width-request">200</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name" translatable="yes">Fingerprint Enroll</property>
+ </packing>
+ </child>
+
+ </object>
+ </child>
+ </object>
+ </child>
+
+ </object>
+ </child>
+ </template>
+
+ <object class="GtkPopoverMenu" id="print_popover">
+ <property name="position">bottom</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin">12</property>
+ <property name="spacing">6</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkModelButton">
+ <property name="label" translatable="yes">_Re-enroll this finger…</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0.0</property>
+ <signal name="clicked" handler="reenroll_finger_cb" object="CcFingerprintDialog" swapped="yes"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+
+ <object class="GtkPopoverMenu" id="add_print_popover">
+ <property name="position">bottom</property>
+ <child>
+ <object class="GtkBox" id="add_print_popover_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin">12</property>
+ <property name="spacing">6</property>
+ <property name="orientation">vertical</property>
+ </object>
+ </child>
+ </object>
+
+</interface>
diff --git a/panels/user-accounts/cc-user-panel.c b/panels/user-accounts/cc-user-panel.c
index 81ad6825f..5a9b5c221 100644
--- a/panels/user-accounts/cc-user-panel.c
+++ b/panels/user-accounts/cc-user-panel.c
@@ -21,7 +21,6 @@
#include "config.h"
#include "cc-user-panel.h"
-#include "cc-fingerprint-manager.h"
#include <stdlib.h>
#include <string.h>
@@ -53,7 +52,8 @@
#include "cc-realm-manager.h"
#include "cc-user-accounts-resources.h"
#include "cc-user-image.h"
-#include "um-fingerprint-dialog.h"
+#include "cc-fingerprint-manager.h"
+#include "cc-fingerprint-dialog.h"
#include "user-utils.h"
#include "cc-common-language.h"
@@ -113,7 +113,6 @@ struct _CcUserPanel {
CcAvatarChooser *avatar_chooser;
- GCancellable *fingerprint_cancellable;
CcFingerprintManager *fingerprint_manager;
gint other_accounts;
@@ -928,7 +927,6 @@ show_user (ActUser *user, CcUserPanel *self)
if (show) {
if (!self->fingerprint_manager) {
self->fingerprint_manager = cc_fingerprint_manager_new (user);
- fingerprint_set_manager (self->fingerprint_manager);
g_signal_connect_object (self->fingerprint_manager,
"notify::state",
G_CALLBACK (update_fingerprint_row_state),
@@ -1181,19 +1179,17 @@ static void
change_fingerprint (CcUserPanel *self)
{
ActUser *user;
+ GtkWindow *top_level;
+ CcFingerprintDialog *dialog;
user = get_selected_user (self);
+ top_level = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self)));
g_assert (g_strcmp0 (g_get_user_name (), act_user_get_user_name (user)) == 0);
- g_cancellable_cancel (self->fingerprint_cancellable);
- g_clear_object (&self->fingerprint_cancellable);
-
- self->fingerprint_cancellable = g_cancellable_new ();
-
- fingerprint_button_clicked (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))),
- GTK_WIDGET (self->fingerprint_row),
- self->fingerprint_cancellable);
+ dialog = cc_fingerprint_dialog_new (self->fingerprint_manager);
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), top_level);
+ gtk_widget_show (GTK_WIDGET (dialog));
}
static void
@@ -1602,9 +1598,6 @@ cc_user_panel_dispose (GObject *object)
g_clear_object (&self->login_screen_settings);
- g_cancellable_cancel (self->fingerprint_cancellable);
- g_clear_object (&self->fingerprint_cancellable);
-
g_clear_pointer ((GtkWidget **)&self->language_chooser, gtk_widget_destroy);
g_clear_object (&self->permission);
G_OBJECT_CLASS (cc_user_panel_parent_class)->dispose (object);
diff --git a/panels/user-accounts/data/cc-fingerprint-dialog.css
b/panels/user-accounts/data/cc-fingerprint-dialog.css
new file mode 100644
index 000000000..9f8ea1770
--- /dev/null
+++ b/panels/user-accounts/data/cc-fingerprint-dialog.css
@@ -0,0 +1,61 @@
+.fingerprint-icon {
+ padding: 3px;
+}
+
+.fingerprint-icon > button,
+.fingerprint-icon > image {
+ padding: 15px;
+ min-width: 32px;
+ min-height: 32px;
+ border-radius: 64px;
+ border: 1px solid @borders;
+ background-color: @theme_base_color;
+ color: @insensitive_fg_color;
+}
+
+.fingerprint-print-add image:not(:disabled):not(:backdrop),
+.fingerprint-print-add button:not(:disabled):not(:backdrop) {
+ color: @theme_fg_color;
+}
+
+.fingerprint-icon.enroll-status image {
+ outline-color: @theme_selected_bg_color;
+ outline-offset: 0px;
+ outline-width: 4px;
+}
+
+.fingerprint-icon.enroll-status image:backdrop {
+ outline-color: @theme_unfocused_selected_bg_color;
+}
+
+.fingerprint-icon.enroll-status {
+ font-weight: bold;
+}
+
+.fingerprint-icon.enroll-status.completed image {
+ outline-color: @success_color;
+}
+
+.fingerprint-icon.enroll-status.warning image {
+ outline-color: @warning_color;
+}
+
+.fingerprint-icon.enroll-status.error image {
+ outline-color: @error_color;
+ /* Given we don't have an error image, we can just recolorize the warning one */
+ -gtk-icon-palette: warning @error_color;
+}
+
+.fingerprint-icon.enroll-status.success image:not(:backdrop) {
+ color: @theme_selected_bg_color;
+}
+
+.fingerprint-icon.enroll-status.warning image:not(:backdrop),
+.fingerprint-icon.enroll-status.warning label:not(:backdrop) {
+ color: @warning_color;
+}
+
+.fingerprint-icon.enroll-status.error image:not(:backdrop),
+.fingerprint-icon.enroll-status.error label:not(:backdrop) {
+ color: @error_color;
+}
diff --git a/panels/user-accounts/data/icons/fingerprint-detection-complete-symbolic.svg
b/panels/user-accounts/data/icons/fingerprint-detection-complete-symbolic.svg
new file mode 100644
index 000000000..a22538465
--- /dev/null
+++ b/panels/user-accounts/data/icons/fingerprint-detection-complete-symbolic.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 8.467 8.467">
+ <path
style="line-height:normal;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000;text-transform:none;text-orientation:mixed;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1"
d="M 16.132812,0.99023438 C 13.902514,0.96755721 11.66847,1.5168081 9.65625,2.6425781 8.4831917,3.288913
9.4616217,5.0473362 10.628906,4.390625 14.036766,2.4839667 18.198267,2.527856 21.566406,4.5039062
24.934547,6.4799188 27,10.08815 27,13.994141 v 2 c -5.97e-4,1.33435 1.999403,1.33435 2,0 v -2 c
3.54e-4,-0.03325 -9.56e-4,-0.06649 -0.0039,-0.09961 C 28.961052,9.320245 26.52689,5.092052
22.578125,2.7753906 20.589365,1.6086127 18.363092,1.0130627 16.132812,0.99023438 Z M 5.7617188,6.640625 C
5.4310747,6.6594699 5.1312075,6.
840853 4.9609375,7.125 3.6959444,9.158537 3.0222407,11.500805 3.0039062,13.894531 3.00095,13.927649
2.9996462,13.960893 3,13.994141 v 10.128906 c 0,1.333754 2,1.333754 2,0 V 13.994141 C 5,11.939136
5.5747962,9.9244686 6.6601562,8.1796875 7.1014645,7.4921558 6.5771855,6.5940433 5.7617188,6.640625 Z M
16,6.9921875 c -3.813165,0 -6.9283277,3.0816025 -6.9941406,6.8808595 -0.0044,0.04021 -0.00636,0.08065
-0.00586,0.121094 v 2 c 5.96e-4,1.333157 2.000596,1.333157 2,0 v -2 c 0,-2.774325 2.22666,-5.0019535
5,-5.0019535 2.77334,0 5,2.2276285 5,5.0019535 V 22.125 c 0.426667,0.161975 0.81076,0.41915 1.123047,0.751953
L 23,23.753906 v -9.759765 c 2.65e-4,-0.03849 -0.0017,-0.07697 -0.0059,-0.115235 C 22.931551,10.076928
19.815145,6.9921875 16,6.9921875 Z m -0.01563,5.9863285 C 15.43218,12.98705 14.991449,13.441767 15,13.994141
v 10.003906 c 0,0 -5.87e-4,1.09432 0.269531,2.445312 0.2701,1.350992 0.787778,3.027578 2.023438,4.263672
0.942205,0.981983 2.395438,-0.47125 1.414062,-1.414062 -0.690333,-
0.690533 -1.138586,-1.835412 -1.390625,-2.898438 l -0.002,-0.002 C 16.951575,25.742041 16.843618,24.979658
17.011719,24.253906 17.009401,24.177001 17,23.998047 17,23.998047 V 13.994141 c 0.0087,-0.564623
-0.451183,-1.024549 -1.015625,-1.015625 z m -6,8.001953 C 9.4321797,20.989003 8.9914495,21.44372 9,21.996094
v 6.001953 c -5.966e-4,1.33435 1.999403,1.33435 2,0 v -6.001953 c 0.0087,-0.564623 -0.451183,-1.024549
-1.015625,-1.015625 z m 20.998047,0.0059 a 1.0001,1.0001 0 0 0 -0.6875,0.302734 l -6.296875,6.289063
-3.291016,-3.292969 a 1.0001,1.0001 0 1 0 -1.410156,1.417969 l 4.701172,4.703125 7.707031,-7.707031 a
1.0001,1.0001 0 0 0 -0.722656,-1.712891 z" transform="scale(.26458)" class="success" color="#000"
font-weight="400" font-family="sans-serif" overflow="visible" fill="#33d17a"/>
+</svg>
diff --git a/panels/user-accounts/data/icons/fingerprint-detection-symbolic.svg
b/panels/user-accounts/data/icons/fingerprint-detection-symbolic.svg
new file mode 100644
index 000000000..00e31cce2
--- /dev/null
+++ b/panels/user-accounts/data/icons/fingerprint-detection-symbolic.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 8.467 8.467">
+ <path d="m 4.2684727,288.79533 c -0.5901,-0.006 -1.1811905,0.13932 -1.7135904,0.43718 a
0.26457931,0.26466281 0 1 0 0.2573486,0.46251 c 0.9016629,-0.50447 2.0027268,-0.49283 2.8938802,0.03
0.8911538,0.52282 1.4376385,1.4775 1.4376385,2.51096 v 0.52916 a 0.26458335,0.26466684 0 1 0 0.5291667,0 v
-0.52916 a 0.26456806,0.26465154 0 0 0 -0.00103,-0.0264 c -0.00927,-1.21028 -0.6533118,-2.32899
-1.6980893,-2.94194 -0.5261927,-0.30871 -1.1152275,-0.46628 -1.7053224,-0.47232 z m -2.7440185,1.495 a
0.26456806,0.26465154 0 0 0 -0.2118734,0.12816 c -0.3346961,0.53804 -0.51294685,1.15776 -0.51779785,1.7911 a
0.26456806,0.26465154 0 0 0 -0.001034,0.0264 v 2.67994 a 0.26458334,0.26466683 0 0 0 0.52916665,0 v -2.67994
c 0,-0.54372 0.1520815,-1.07677 0.4392497,-1.53841 a 0.26456806,0.26465154 0 0 0 -0.2377116,-0.40721 z m
2.7088787,0.093 c -1.0089,0 -1.8331201,0.81534 -1.8505331,1.82056 a 0.26456806,0.26465154 0 0 0
-0.00155,0.032 v 0.52916 a 0.26458335,0.26466684 0 1 0 0.5291667,0 v -0.52916 c
0,-0.73404 0.5891371,-1.32344 1.3229167,-1.32344 0.7337795,0 1.3229167,0.5894 1.3229167,1.32344 v 2.64686 c
0,0 0.00212,0.18248 0.079582,0.41445 0.077301,0.23197 0.2313432,0.5351 0.5270998,0.83096 a
0.26456806,0.26465154 0 1 0 0.3741372,-0.37414 c -0.2334101,-0.23348 -0.3439509,-0.45923 -0.3989419,-0.62425
-0.054991,-0.16503 -0.05271,-0.24702 -0.05271,-0.24702 v -2.64686 a 0.26456806,0.26465154 0 0 0
-0.00156,-0.0305 c -0.016571,-1.00594 -0.8410985,-1.82211 -1.8505223,-1.82211 z m -0.00414,1.58388 a
0.26456806,0.26465154 0 0 0 -0.2604479,0.26872 v 2.64686 c 0,0 -1.558e-4,0.28954 0.071313,0.64699
0.071464,0.35745 0.208433,0.80105 0.535368,1.1281 a 0.26456806,0.26465154 0 1 0 0.3741373,-0.37414 c
-0.2022317,-0.20229 -0.329846,-0.55309 -0.3906737,-0.85731 -0.060823,-0.30422 -0.060978,-0.54364
-0.060978,-0.54364 v -2.64686 a 0.26456806,0.26465154 0 0 0 -0.2687175,-0.26872 z m -1.5875,2.11718 a
0.26456806,0.26465154 0 0 0 -0.2604479,0.26872 v 1.58802 a 0.26458335,0.26466684 0 1 0 0.5291
667,0 v -1.58802 a 0.26456806,0.26465154 0 0 0 -0.2687175,-0.26872 z m 4.7625001,0 a 0.26456806,0.26465154 0
0 0 -0.2604479,0.26769 v 0.52968 a 0.26458335,0.26466684 0 1 0 0.5291667,0 v -0.52968 a 0.26456806,0.26465154
0 0 0 -0.2687175,-0.26769 z"
style="line-height:normal;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000;text-transform:none;text-orientation:mixed;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1"
color="#000" font-weight="400" font-family="sans-serif" overflow="visible" fill="#3d3846"
transform="translate(0 -288.533)"/>
+</svg>
diff --git a/panels/user-accounts/data/icons/fingerprint-detection-warning-symbolic.svg
b/panels/user-accounts/data/icons/fingerprint-detection-warning-symbolic.svg
new file mode 100644
index 000000000..5b3fa81fa
--- /dev/null
+++ b/panels/user-accounts/data/icons/fingerprint-detection-warning-symbolic.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 8.467 8.467">
+ <path overflow="visible" font-weight="400" d="m 4.2684194,0.26199621 c -0.5900922,-0.006
-1.1811756,0.13932088 -1.7135688,0.4371771 A 0.26457597,0.26465948 0 1 0 2.8121959,1.1616716 C
3.7138475,0.65720791 4.8148975,0.66882014 5.7060397,1.1916435 6.5971824,1.7144569 7.14366,2.6691227
7.14366,3.7025698 v 0.52916 a 0.26458003,0.2646635 0 1 0 0.52916,0 v -0.52916 A 0.26456472,0.26464821 0 0 0
7.6717881,3.676215 C 7.6625167,2.4659504 7.0184846,1.3472551 5.9737203,0.73431284 5.4475342,0.42560675
4.8585069,0.26803613 4.2684194,0.26199621 Z M 1.5244356,1.7569766 A 0.26456472,0.26464821 0 0 0
1.3125648,1.8851325 C 0.97787297,2.4231657 0.79962444,3.042883 0.7947735,3.676215 A 0.26456472,0.26464821 0 0
0 0.79374,3.7025698 v 2.679906 a 0.26458,0.2646635 0 0 0 0.52916,0 v -2.679906 c 0,-0.5437132
0.1520796,-1.0767539 0.4392441,-1.5383881 A 0.26456472,0.26464821 0 0 0 1.5244356,1.7569766 Z M
4.23328,1.849993 c -1.0088872,0 -1.8330969,0.8153304 -1.8505097,1.8205378 a 0.26456472,0.26464821 0 0
0 -0.00155,0.032039 v 0.52916 a 0.26458003,0.2646635 0 0 0 0.52916,0 v -0.52916 c 0,-0.7340309
0.5891297,-1.3234168 1.3229,-1.3234168 0.7337703,0 1.3229,0.5893859 1.3229,1.3234168 V 4.4110447 C
5.6854821,4.2368203 5.8715938,4.0894366 6.08534,4.0260602 V 3.7025698 A 0.26456472,0.26464821 0 0 0
6.083779,3.6720809 C 6.0672189,2.6661536 5.2426911,1.849993 4.23328,1.849993 Z M 4.22914,3.4338558 A
0.26456472,0.26464821 0 0 0 3.9687,3.7025698 v 2.6468335 c 0,0 -1.553e-4,0.2895352 0.071312,0.6469806
0.00877,0.043848 0.022106,0.091907 0.033073,0.1379745 L 4.49786,6.3468194 V 3.7025698 A 0.26456472,0.26464821
0 0 0 4.2291459,3.4338558 Z M 6.3251097,4.5226644 C 6.1860729,4.5146644 6.0504148,4.5975684
5.944776,4.7789762 L 4.2911556,7.8464506 C 4.1500114,8.1013375 4.3039147,8.46656 4.5805412,8.46656 h
3.4808807 c 0.2597435,0 0.5035248,-0.3067533 0.3224568,-0.6201094 L 6.7137175,4.7955125 C 6.6082242,4.6245446
6.4641524,4.5302343 6.3251156,4.5226644 Z M 2.6416659,5.5510125 A 0.26456472,0.26464821
0 0 0 2.38122,5.8197266 v 1.5879967 a 0.26458003,0.2646635 0 1 0 0.52916,0 V 5.8197266 A
0.26456472,0.26464821 0 0 0 2.6416659,5.5510125 Z m 3.699986,0.013436 C 6.4857104,5.5594481
6.6190614,5.693238 6.6145,5.8372962 V 6.87908 C 6.61635,7.0188682 6.4897161,7.14366 6.34992,7.14366
6.2101265,7.14366 6.0833636,7.0188682 6.08534,6.87908 V 5.8372962 c -0.00212,-0.1234583 0.093688,-0.2414303
0.2149712,-0.26458 0.01352,-0.004 0.027371,-0.00675 0.041341,-0.00775 z M 6.34992,7.40824 c 0.1461236,0
0.26458,0.1184617 0.26458,0.26458 0,0.1461281 -0.1184564,0.26458 -0.26458,0.26458 -0.1461236,0
-0.26458,-0.1184519 -0.26458,-0.26458 0,-0.1461183 0.1184564,-0.26458 0.26458,-0.26458 z"
style="line-height:normal;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000;text-tra
nsform:none;text-orientation:mixed;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000;solid-opacity:1"
class="warning" color="#000" font-family="sans-serif" fill="#ff7800"/>
+</svg>
diff --git a/panels/user-accounts/meson.build b/panels/user-accounts/meson.build
index de54ee14e..b8ee9d98e 100644
--- a/panels/user-accounts/meson.build
+++ b/panels/user-accounts/meson.build
@@ -107,22 +107,14 @@ resource_data = files(
'cc-login-history-dialog.ui',
'cc-password-dialog.ui',
'cc-user-panel.ui',
- 'data/icons/left-index-finger.png',
- 'data/icons/left-little-finger.png',
- 'data/icons/left-middle-finger.png',
- 'data/icons/left-ring-finger.png',
- 'data/icons/left-thumb.png',
- 'data/icons/print_error.png',
- 'data/icons/print_ok.png',
- 'data/icons/right-index-finger.png',
- 'data/icons/right-little-finger.png',
- 'data/icons/right-middle-finger.png',
- 'data/icons/right-ring-finger.png',
- 'data/icons/right-thumb.png',
- 'data/account-fingerprint.ui',
+ 'cc-fingerprint-dialog.ui',
+ 'data/icons/fingerprint-detection-complete-symbolic.svg',
+ 'data/icons/fingerprint-detection-symbolic.svg',
+ 'data/icons/fingerprint-detection-warning-symbolic.svg',
'data/carousel.css',
'data/join-dialog.ui',
'data/user-accounts-dialog.css',
+ 'data/cc-fingerprint-dialog.css',
)
common_sources += gnome.compile_resources(
@@ -165,12 +157,12 @@ sources = common_sources + files(
'cc-carousel.c',
'cc-crop-area.c',
'cc-fingerprint-manager.c',
+ 'cc-fingerprint-dialog.c',
'cc-login-history-dialog.c',
'cc-password-dialog.c',
'cc-user-image.c',
'cc-user-panel.c',
'run-passwd.c',
- 'um-fingerprint-dialog.c',
)
sources += gnome.mkenums_simple(
diff --git a/panels/user-accounts/user-accounts.gresource.xml
b/panels/user-accounts/user-accounts.gresource.xml
index 351080783..fcd1a7fbc 100644
--- a/panels/user-accounts/user-accounts.gresource.xml
+++ b/panels/user-accounts/user-accounts.gresource.xml
@@ -7,21 +7,16 @@
<file preprocess="xml-stripblanks">cc-login-history-dialog.ui</file>
<file preprocess="xml-stripblanks">cc-password-dialog.ui</file>
<file preprocess="xml-stripblanks">cc-user-panel.ui</file>
+ <file preprocess="xml-stripblanks">cc-fingerprint-dialog.ui</file>
<file alias="join-dialog.ui" preprocess="xml-stripblanks">data/join-dialog.ui</file>
- <file alias="account-fingerprint.ui" preprocess="xml-stripblanks">data/account-fingerprint.ui</file>
<file alias="user-accounts-dialog.css">data/user-accounts-dialog.css</file>
<file alias="carousel.css">data/carousel.css</file>
- <file alias="left-index-finger.png">data/icons/left-index-finger.png</file>
- <file alias="left-middle-finger.png">data/icons/left-middle-finger.png</file>
- <file alias="left-little-finger.png">data/icons/left-little-finger.png</file>
- <file alias="left-ring-finger.png">data/icons/left-ring-finger.png</file>
- <file alias="left-thumb.png">data/icons/left-thumb.png</file>
- <file alias="print_error.png">data/icons/print_error.png</file>
- <file alias="print_ok.png">data/icons/print_ok.png</file>
- <file alias="right-index-finger.png">data/icons/right-index-finger.png</file>
- <file alias="right-middle-finger.png">data/icons/right-middle-finger.png</file>
- <file alias="right-little-finger.png">data/icons/right-little-finger.png</file>
- <file alias="right-ring-finger.png">data/icons/right-ring-finger.png</file>
- <file alias="right-thumb.png">data/icons/right-thumb.png</file>
+ <file alias="cc-fingerprint-dialog.css">data/cc-fingerprint-dialog.css</file>
+ </gresource>
+
+ <gresource prefix="/org/gnome/ControlCenter/icons/scalable/status">
+ <file preprocess="xml-stripblanks"
alias="fingerprint-detection-complete-symbolic.svg">data/icons/fingerprint-detection-complete-symbolic.svg</file>
+ <file preprocess="xml-stripblanks"
alias="fingerprint-detection-symbolic.svg">data/icons/fingerprint-detection-symbolic.svg</file>
+ <file preprocess="xml-stripblanks"
alias="fingerprint-detection-warning-symbolic.svg">data/icons/fingerprint-detection-warning-symbolic.svg</file>
</gresource>
</gresources>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index fdebe09fa..0f809aaf0 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -222,6 +222,8 @@ panels/user-accounts/cc-add-user-dialog.c
panels/user-accounts/cc-add-user-dialog.ui
panels/user-accounts/cc-avatar-chooser.c
panels/user-accounts/cc-avatar-chooser.ui
+panels/user-accounts/cc-fingerprint-dialog.ui
+panels/user-accounts/cc-fingerprint-dialog.c
panels/user-accounts/cc-login-history-dialog.c
panels/user-accounts/cc-login-history-dialog.ui
panels/user-accounts/cc-password-dialog.c
@@ -229,13 +231,11 @@ panels/user-accounts/cc-password-dialog.ui
panels/user-accounts/cc-realm-manager.c
panels/user-accounts/cc-user-panel.c
panels/user-accounts/cc-user-panel.ui
-panels/user-accounts/data/account-fingerprint.ui
panels/user-accounts/data/gnome-user-accounts-panel.desktop.in.in
panels/user-accounts/data/join-dialog.ui
panels/user-accounts/org.gnome.controlcenter.user-accounts.policy.in
panels/user-accounts/pw-utils.c
panels/user-accounts/run-passwd.c
-panels/user-accounts/um-fingerprint-dialog.c
panels/user-accounts/user-utils.c
panels/wacom/button-mapping.ui
panels/wacom/calibrator/calibrator.ui
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]