1
/* gnome-about-me-fingerprint.h
2
* Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2, or (at your option)
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20
#include <glib/gi18n.h>
22
#include <dbus/dbus-glib-bindings.h>
24
#include "fingerprint-strings.h"
25
#include "capplet-util.h"
27
/* This must match the number of images on the 2nd page in the UI file */
28
#define MAX_ENROLL_STAGES 5
30
/* Translate fprintd strings */
31
#define TR(s) dgettext("fprintd", s)
33
static DBusGProxy *manager = NULL;
34
static DBusGConnection *connection = NULL;
35
static gboolean is_disable = FALSE;
52
int num_enroll_stages;
59
static void create_manager (void)
63
connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
64
if (connection == NULL) {
65
g_warning ("Failed to connect to session bus: %s", error->message);
69
manager = dbus_g_proxy_new_for_name (connection,
70
"net.reactivated.Fprint",
71
"/net/reactivated/Fprint/Manager",
72
"net.reactivated.Fprint.Manager");
76
get_first_device (void)
81
if (!dbus_g_proxy_call (manager, "GetDefaultDevice", NULL, G_TYPE_INVALID,
82
DBUS_TYPE_G_OBJECT_PATH, &device_str, G_TYPE_INVALID)) {
86
device = dbus_g_proxy_new_for_name(connection,
87
"net.reactivated.Fprint",
89
"net.reactivated.Fprint.Device");
97
get_reason_for_error (const char *dbus_error)
99
if (g_str_equal (dbus_error, "net.reactivated.Fprint.Error.PermissionDenied"))
100
return N_("You are not allowed to access the device. Contact your system administrator.");
101
if (g_str_equal (dbus_error, "net.reactivated.Fprint.Error.AlreadyInUse"))
102
return N_("The device is already in use.");
103
if (g_str_equal (dbus_error, "net.reactivated.Fprint.Error.Internal"))
104
return N_("An internal error occured");
110
get_error_dialog (const char *title,
111
const char *dbus_error,
114
GtkWidget *error_dialog;
117
if (dbus_error == NULL)
118
g_warning ("get_error_dialog called with reason == NULL");
121
gtk_message_dialog_new (parent,
126
reason = get_reason_for_error (dbus_error);
127
gtk_message_dialog_format_secondary_text
128
(GTK_MESSAGE_DIALOG (error_dialog), "%s", reason ? _(reason) : _(dbus_error));
130
gtk_window_set_title (GTK_WINDOW (error_dialog), ""); /* as per HIG */
131
gtk_container_set_border_width (GTK_CONTAINER (error_dialog), 5);
132
gtk_dialog_set_default_response (GTK_DIALOG (error_dialog),
134
gtk_window_set_modal (GTK_WINDOW (error_dialog), TRUE);
135
gtk_window_set_position (GTK_WINDOW (error_dialog), GTK_WIN_POS_CENTER_ON_PARENT);
141
set_fingerprint_label (GtkWidget *enable, GtkWidget *disable)
145
GError *error = NULL;
147
gtk_widget_set_no_show_all (enable, TRUE);
148
gtk_widget_set_no_show_all (disable, TRUE);
150
if (manager == NULL) {
152
if (manager == NULL) {
153
gtk_widget_hide (enable);
154
gtk_widget_hide (disable);
159
device = get_first_device ();
160
if (device == NULL) {
161
gtk_widget_hide (enable);
162
gtk_widget_hide (disable);
166
if (!dbus_g_proxy_call (device, "ListEnrolledFingers", &error, G_TYPE_STRING, "", G_TYPE_INVALID,
167
G_TYPE_STRV, &fingers, G_TYPE_INVALID)) {
168
if (dbus_g_error_has_name (error, "net.reactivated.Fprint.Error.NoEnrolledPrints") == FALSE) {
169
gtk_widget_hide (enable);
170
gtk_widget_hide (disable);
171
g_object_unref (device);
177
if (fingers == NULL || g_strv_length (fingers) == 0) {
178
gtk_widget_hide (disable);
179
gtk_widget_show (enable);
182
gtk_widget_hide (enable);
183
gtk_widget_show (disable);
187
g_strfreev (fingers);
188
g_object_unref (device);
192
delete_fingerprints (void)
196
if (manager == NULL) {
202
device = get_first_device ();
206
dbus_g_proxy_call (device, "DeleteEnrolledFingers", NULL, G_TYPE_STRING, "", G_TYPE_INVALID, G_TYPE_INVALID);
208
g_object_unref (device);
212
delete_fingerprints_question (GtkBuilder *dialog, GtkWidget *enable, GtkWidget *disable)
217
question = gtk_message_dialog_new (GTK_WINDOW (WID ("about-me-dialog")),
219
GTK_MESSAGE_QUESTION,
221
_("Delete registered fingerprints?"));
222
gtk_dialog_add_button (GTK_DIALOG (question), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
224
button = gtk_button_new_with_mnemonic (_("_Delete Fingerprints"));
225
gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_stock (GTK_STOCK_DELETE, GTK_ICON_SIZE_BUTTON));
226
gtk_widget_set_can_default (button, TRUE);
227
gtk_widget_show (button);
228
gtk_dialog_add_action_widget (GTK_DIALOG (question), button, GTK_RESPONSE_OK);
230
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (question),
231
_("Do you want to delete your registered fingerprints so fingerprint login is disabled?"));
232
gtk_container_set_border_width (GTK_CONTAINER (question), 5);
233
gtk_dialog_set_default_response (GTK_DIALOG (question), GTK_RESPONSE_OK);
234
gtk_window_set_position (GTK_WINDOW (question), GTK_WIN_POS_CENTER_ON_PARENT);
235
gtk_window_set_modal (GTK_WINDOW (question), TRUE);
237
if (gtk_dialog_run (GTK_DIALOG (question)) == GTK_RESPONSE_OK) {
238
delete_fingerprints ();
239
set_fingerprint_label (enable, disable);
242
gtk_widget_destroy (question);
246
enroll_data_destroy (EnrollData *data)
248
switch (data->state) {
249
case STATE_ENROLLING:
250
dbus_g_proxy_call(data->device, "EnrollStop", NULL, G_TYPE_INVALID, G_TYPE_INVALID);
253
dbus_g_proxy_call(data->device, "Release", NULL, G_TYPE_INVALID, G_TYPE_INVALID);
257
g_object_unref (data->device);
258
g_object_unref (data->dialog);
259
gtk_widget_destroy (data->ass);
266
selected_finger (GtkBuilder *dialog)
270
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (WID ("radiobutton1")))) {
271
gtk_widget_set_sensitive (WID ("finger_combobox"), FALSE);
272
return "right-index-finger";
274
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (WID ("radiobutton2")))) {
275
gtk_widget_set_sensitive (WID ("finger_combobox"), FALSE);
276
return "left-index-finger";
278
gtk_widget_set_sensitive (WID ("finger_combobox"), TRUE);
279
index = gtk_combo_box_get_active (GTK_COMBO_BOX (WID ("finger_combobox")));
284
return "left-middle-finger";
286
return "left-ring-finger";
288
return "left-little-finger";
290
return "right-thumb";
292
return "right-middle-finger";
294
return "right-ring-finger";
296
return "right-little-finger";
298
g_assert_not_reached ();
305
finger_radio_button_toggled (GtkToggleButton *button, EnrollData *data)
307
GtkBuilder *dialog = data->dialog;
310
data->finger = selected_finger (data->dialog);
312
msg = g_strdup_printf (TR(finger_str_to_msg (data->finger, data->is_swipe)), data->name);
313
gtk_label_set_text (GTK_LABEL (WID("enroll-label")), msg);
318
finger_combobox_changed (GtkComboBox *combobox, EnrollData *data)
320
GtkBuilder *dialog = data->dialog;
323
data->finger = selected_finger (data->dialog);
325
msg = g_strdup_printf (TR(finger_str_to_msg (data->finger, data->is_swipe)), data->name);
326
gtk_label_set_text (GTK_LABEL (WID("enroll-label")), msg);
331
assistant_cancelled (GtkAssistant *ass, EnrollData *data)
333
GtkWidget *enable, *disable;
335
enable = data->enable;
336
disable = data->disable;
338
enroll_data_destroy (data);
339
set_fingerprint_label (enable, disable);
343
enroll_result (GObject *object, const char *result, gboolean done, EnrollData *data)
345
GtkBuilder *dialog = data->dialog;
348
if (g_str_equal (result, "enroll-completed") || g_str_equal (result, "enroll-stage-passed")) {
351
data->num_stages_done++;
352
name = g_strdup_printf ("image%d", data->num_stages_done);
353
path = g_build_filename (GNOMECC_PIXMAP_DIR, "print_ok.png", NULL);
354
gtk_image_set_from_file (GTK_IMAGE (WID (name)), path);
358
if (g_str_equal (result, "enroll-completed")) {
359
gtk_label_set_text (GTK_LABEL (WID ("status-label")), _("Done!"));
360
gtk_assistant_set_page_complete (GTK_ASSISTANT (data->ass), WID ("page2"), TRUE);
364
dbus_g_proxy_call(data->device, "EnrollStop", NULL, G_TYPE_INVALID, G_TYPE_INVALID);
365
data->state = STATE_CLAIMED;
366
if (g_str_equal (result, "enroll-completed") == FALSE) {
367
/* The enrollment failed, restart it */
368
dbus_g_proxy_call(data->device, "EnrollStart", NULL, G_TYPE_STRING, data->finger, G_TYPE_INVALID, G_TYPE_INVALID);
369
data->state = STATE_ENROLLING;
370
result = "enroll-retry-scan";
376
msg = g_strdup_printf (TR(enroll_result_str_to_msg (result, data->is_swipe)), data->name);
377
gtk_label_set_text (GTK_LABEL (WID ("status-label")), msg);
382
assistant_prepare (GtkAssistant *ass, GtkWidget *page, EnrollData *data)
386
name = g_object_get_data (G_OBJECT (page), "name");
390
if (g_str_equal (name, "enroll")) {
392
GError *error = NULL;
393
GtkBuilder *dialog = data->dialog;
396
GValue value = { 0, };
398
if (!dbus_g_proxy_call (data->device, "Claim", &error, G_TYPE_STRING, "", G_TYPE_INVALID, G_TYPE_INVALID)) {
403
* The variable is the name of the device, for example:
404
* "Could you not access "Digital Persona U.are.U 4000/4000B" device */
405
msg = g_strdup_printf (_("Could not access '%s' device"), data->name);
406
d = get_error_dialog (msg, dbus_g_error_get_name (error), GTK_WINDOW (data->ass));
407
g_error_free (error);
408
gtk_dialog_run (GTK_DIALOG (d));
409
gtk_widget_destroy (d);
412
enroll_data_destroy (data);
416
data->state = STATE_CLAIMED;
418
p = dbus_g_proxy_new_from_proxy (data->device, "org.freedesktop.DBus.Properties", NULL);
419
if (!dbus_g_proxy_call (p, "Get", NULL, G_TYPE_STRING, "net.reactivated.Fprint.Device", G_TYPE_STRING, "num-enroll-stages", G_TYPE_INVALID,
420
G_TYPE_VALUE, &value, G_TYPE_INVALID) || g_value_get_int (&value) < 1) {
425
* The variable is the name of the device, for example:
426
* "Could you not access "Digital Persona U.are.U 4000/4000B" device */
427
msg = g_strdup_printf (_("Could not access '%s' device"), data->name);
428
d = get_error_dialog (msg, "net.reactivated.Fprint.Error.Internal", GTK_WINDOW (data->ass));
429
gtk_dialog_run (GTK_DIALOG (d));
430
gtk_widget_destroy (d);
433
enroll_data_destroy (data);
440
data->num_enroll_stages = g_value_get_int (&value);
442
/* Hide the extra "bulbs" if not needed */
443
for (i = MAX_ENROLL_STAGES; i > data->num_enroll_stages; i--) {
446
name = g_strdup_printf ("image%d", i);
447
gtk_widget_hide (WID (name));
450
/* And set the right image */
454
filename = g_strdup_printf ("%s.png", data->finger);
455
path = g_build_filename (GNOMECC_PIXMAP_DIR, filename, NULL);
458
for (i = 1; i <= data->num_enroll_stages; i++) {
460
name = g_strdup_printf ("image%d", i);
461
gtk_image_set_from_file (GTK_IMAGE (WID (name)), path);
466
dbus_g_proxy_add_signal(data->device, "EnrollStatus", G_TYPE_STRING, G_TYPE_BOOLEAN, NULL);
467
dbus_g_proxy_connect_signal(data->device, "EnrollStatus", G_CALLBACK(enroll_result), data, NULL);
469
if (!dbus_g_proxy_call(data->device, "EnrollStart", &error, G_TYPE_STRING, data->finger, G_TYPE_INVALID, G_TYPE_INVALID)) {
474
* The variable is the name of the device, for example:
475
* "Could you not access "Digital Persona U.are.U 4000/4000B" device */
476
msg = g_strdup_printf (_("Could not start finger capture on '%s' device"), data->name);
477
d = get_error_dialog (msg, dbus_g_error_get_name (error), GTK_WINDOW (data->ass));
478
g_error_free (error);
479
gtk_dialog_run (GTK_DIALOG (d));
480
gtk_widget_destroy (d);
483
enroll_data_destroy (data);
487
data->state = STATE_ENROLLING;;
489
if (data->state == STATE_ENROLLING) {
490
dbus_g_proxy_call(data->device, "EnrollStop", NULL, G_TYPE_INVALID, G_TYPE_INVALID);
491
data->state = STATE_CLAIMED;
493
if (data->state == STATE_CLAIMED) {
494
dbus_g_proxy_call(data->device, "Release", NULL, G_TYPE_INVALID, G_TYPE_INVALID);
495
data->state = STATE_NONE;
501
enroll_fingerprints (GtkWindow *parent, GtkWidget *enable, GtkWidget *disable)
503
DBusGProxy *device, *p;
512
if (manager == NULL) {
515
device = get_first_device ();
517
device = get_first_device ();
520
if (manager == NULL || device == NULL) {
523
d = get_error_dialog (_("Could not access any fingerprint readers"),
524
_("Please contact your system administrator for help."),
526
gtk_dialog_run (GTK_DIALOG (d));
527
gtk_widget_destroy (d);
531
data = g_new0 (EnrollData, 1);
532
data->device = device;
533
data->enable = enable;
534
data->disable = disable;
536
/* Get some details about the device */
537
p = dbus_g_proxy_new_from_proxy (device, "org.freedesktop.DBus.Properties", NULL);
538
if (dbus_g_proxy_call (p, "GetAll", NULL, G_TYPE_STRING, "net.reactivated.Fprint.Device", G_TYPE_INVALID,
539
dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &props, G_TYPE_INVALID)) {
540
const char *scan_type;
541
data->name = g_value_dup_string (g_hash_table_lookup (props, "name"));
542
scan_type = g_value_dup_string (g_hash_table_lookup (props, "scan-type"));
543
if (g_str_equal (scan_type, "swipe"))
544
data->is_swipe = TRUE;
545
g_hash_table_destroy (props);
549
dialog = gtk_builder_new ();
550
gtk_builder_add_from_file (dialog, GNOMECC_UI_DIR "/gnome-about-me-fingerprint.ui", NULL);
551
data->dialog = dialog;
553
ass = WID ("assistant");
554
gtk_window_set_title (GTK_WINDOW (ass), _("Enable Fingerprint Login"));
555
gtk_window_set_transient_for (GTK_WINDOW (ass), parent);
556
gtk_window_set_position (GTK_WINDOW (ass), GTK_WIN_POS_CENTER_ON_PARENT);
557
g_signal_connect (G_OBJECT (ass), "cancel",
558
G_CALLBACK (assistant_cancelled), data);
559
g_signal_connect (G_OBJECT (ass), "close",
560
G_CALLBACK (assistant_cancelled), data);
561
g_signal_connect (G_OBJECT (ass), "prepare",
562
G_CALLBACK (assistant_prepare), data);
565
gtk_combo_box_set_active (GTK_COMBO_BOX (WID ("finger_combobox")), 0);
567
g_signal_connect (G_OBJECT (WID ("radiobutton1")), "toggled",
568
G_CALLBACK (finger_radio_button_toggled), data);
569
g_signal_connect (G_OBJECT (WID ("radiobutton2")), "toggled",
570
G_CALLBACK (finger_radio_button_toggled), data);
571
g_signal_connect (G_OBJECT (WID ("radiobutton3")), "toggled",
572
G_CALLBACK (finger_radio_button_toggled), data);
573
g_signal_connect (G_OBJECT (WID ("finger_combobox")), "changed",
574
G_CALLBACK (finger_combobox_changed), data);
576
data->finger = selected_finger (dialog);
578
g_object_set_data (G_OBJECT (WID("page1")), "name", "intro");
581
* The variable is the name of the device, for example:
582
* "To enable fingerprint login, you need to save one of your fingerprints, using the
583
* 'Digital Persona U.are.U 4000/4000B' device." */
584
msg = g_strdup_printf (_("To enable fingerprint login, you need to save one of your fingerprints, using the '%s' device."),
586
gtk_label_set_text (GTK_LABEL (WID("intro-label")), msg);
589
gtk_assistant_set_page_complete (GTK_ASSISTANT (ass), WID("page1"), TRUE);
592
if (data->is_swipe != FALSE)
593
gtk_assistant_set_page_title (GTK_ASSISTANT (ass), WID("page2"), _("Swipe finger on reader"));
595
gtk_assistant_set_page_title (GTK_ASSISTANT (ass), WID("page2"), _("Place finger on reader"));
597
g_object_set_data (G_OBJECT (WID("page2")), "name", "enroll");
599
msg = g_strdup_printf (TR(finger_str_to_msg (data->finger, data->is_swipe)), data->name);
600
gtk_label_set_text (GTK_LABEL (WID("enroll-label")), msg);
604
g_object_set_data (G_OBJECT (WID("page3")), "name", "summary");
607
gtk_widget_show_all (ass);
611
fingerprint_button_clicked (GtkBuilder *dialog,
615
bindtextdomain ("fprintd", GNOMELOCALEDIR);
616
bind_textdomain_codeset ("fprintd", "UTF-8");
618
if (is_disable != FALSE) {
619
delete_fingerprints_question (dialog, enable, disable);
621
enroll_fingerprints (GTK_WINDOW (WID ("about-me-dialog")), enable, disable);