From 120140ed941a251db5d592a186af3b283af20cdd Mon Sep 17 00:00:00 2001 From: Vishal Rao Date: Tue, 30 Jun 2026 09:02:25 +0530 Subject: [PATCH 1/5] Remove legacy fprint handling --- src/FPrintUtils.vala | 91 -------------------------------------------- src/MainWindow.vala | 15 -------- 2 files changed, 106 deletions(-) diff --git a/src/FPrintUtils.vala b/src/FPrintUtils.vala index dce21136..76124493 100644 --- a/src/FPrintUtils.vala +++ b/src/FPrintUtils.vala @@ -6,95 +6,4 @@ */ namespace Greeter.FPrintUtils { - public enum MessageText { - FPRINT_SWIPE, - FPRINT_SWIPE_AGAIN, - FPRINT_SWIPE_TOO_SHORT, - FPRINT_NOT_CENTERED, - FPRINT_REMOVE, - FPRINT_PLACE, - FPRINT_PLACE_AGAIN, - FPRINT_NO_MATCH, - FPRINT_TIMEOUT, - FPRINT_ERROR, - FAILED, - OTHER - } - - private inline string fprintd_message (string message) { - // TODO: Translate message using GLib.dgettext - return message; - } - - public MessageText string_to_messagetext (string text) { - // Ideally this would query PAM and ask which module is currently active, - // but since we're running through LightDM we don't have that ability. - // There should at be a state machine to transition to and from the - // active module depending on the messages received. But, this is can go - // wrong quickly. - // The reason why this is needed is, for example, we can get the "An - // unknown error occurred" message from pam_fprintd, but we can get it - // from some other random module as well. You never know. - // Maybe it's worth adding some LightDM/PAM functionality for this? - // The PAM "feature" which makes it all tricky is that modules can send - // arbitrary messages to the stream and it's hard to analyze or keep track - // of them programmatically. - // Also, there doesn't seem to be a way to give the user a choice over - // which module he wants to use to authenticate (ie. maybe today I have - // a bandaid over my finger and I can't scan it so I have to wait for it - // time out, if I didn't disable that in the settings) - // - // These messages are taken from here: - // - https://gitlab.freedesktop.org/libfprint/fprintd/blob/master/pam/fingerprint-strings.h - // - https://gitlab.freedesktop.org/libfprint/fprintd/blob/master/pam/pam_fprintd.c - - if (text == fprintd_message ("An unknown error occurred")) { - return MessageText.FPRINT_ERROR; - } else if (text == fprintd_message ("An unknown error occurred")) { - return MessageText.FPRINT_ERROR; - } else if (check_fprintd_string (text, "Swipe", "across")) { - return MessageText.FPRINT_SWIPE; - } else if (text == fprintd_message ("Swipe your finger again")) { - return MessageText.FPRINT_SWIPE_AGAIN; - } else if (text == fprintd_message ("Swipe was too short, try again")) { - return MessageText.FPRINT_SWIPE_TOO_SHORT; - } else if (text == fprintd_message ("Your finger was not centered, try swiping your finger again")) { - return MessageText.FPRINT_NOT_CENTERED; - } else if (text == fprintd_message ("Remove your finger, and try swiping your finger again")) { - return MessageText.FPRINT_REMOVE; - } else if (check_fprintd_string (text, "Place", "on")) { - return MessageText.FPRINT_PLACE; - } else if (text == fprintd_message ("Place your finger on the reader again")) { - return MessageText.FPRINT_PLACE_AGAIN; - } else if (text == fprintd_message ("Failed to match fingerprint")) { - return MessageText.FPRINT_NO_MATCH; - } else if (text == fprintd_message ("Verification timed out")) { - return MessageText.FPRINT_TIMEOUT; - } else if (text == "Login failed") { - return MessageText.FAILED; - } - - return MessageText.OTHER; - } - - private bool check_fprintd_string (string text, string action, string position) { - const string[] FINGERS = { - "finger", - "left thumb", "left index finger", "left middle finger", "left ring finger", "left little finger", - "right thumb", "right index finger", "right middle finger", "right ring finger", "right little finger" - }; - - foreach (unowned string finger in FINGERS) { - // Place your finger on %s - var english_string = action.concat (" your ", finger, " ", position, " %s"); - - if (text.has_prefix (fprintd_message (english_string)) || - text.has_prefix (fprintd_message (english_string.printf ("the fingerprint reader")))) { - return true; - } - - } - - return false; - } } diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 616ae938..7da82a73 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -37,7 +37,6 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { gsettings = new GLib.Settings ("io.elementary.greeter"); settings = new Greeter.Settings (); - lightdm_greeter.show_message.connect (show_message); lightdm_greeter.show_prompt.connect (show_prompt); lightdm_greeter.authentication_complete.connect (authentication_complete); @@ -264,20 +263,6 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { } } - private void show_message (string text, LightDM.MessageType type) { - var messagetext = Greeter.FPrintUtils.string_to_messagetext (text); - switch (messagetext) { - case Greeter.FPrintUtils.MessageText.FPRINT_TIMEOUT: - case Greeter.FPrintUtils.MessageText.FPRINT_ERROR: - case Greeter.FPrintUtils.MessageText.OTHER: - current_card.use_fingerprint = false; - break; - default: - current_card.use_fingerprint = true; - break; - } - } - private void show_prompt (string text, LightDM.PromptType type = LightDM.PromptType.QUESTION) { if (current_card is ManualCard) { if (type == LightDM.PromptType.SECRET) { From 48aeebeb1547a4a5778d1f55e440d3348b7f2c9b Mon Sep 17 00:00:00 2001 From: Vishal Rao Date: Tue, 30 Jun 2026 10:41:29 +0530 Subject: [PATCH 2/5] Add fprint dbus util --- src/FPrintUtils.vala | 96 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/src/FPrintUtils.vala b/src/FPrintUtils.vala index 76124493..fc1f65c8 100644 --- a/src/FPrintUtils.vala +++ b/src/FPrintUtils.vala @@ -5,5 +5,99 @@ * Authors: Corentin Noël */ -namespace Greeter.FPrintUtils { +[DBus (name = "net.reactivated.Fprint.Manager")] +public interface FPrintManager : GLib.Object { + public abstract ObjectPath get_default_device () throws GLib.Error; + public abstract ObjectPath[] get_devices (); +} + +[DBus (name = "net.reactivated.Fprint.Device")] +public interface FPrintDevice : GLib.Object { + public abstract string name { owned get; } + public abstract void claim (string username) throws GLib.Error; + public abstract void release () throws GLib.Error; + public abstract void verify_start (string finger) throws GLib.Error; + public abstract void verify_stop () throws GLib.Error; + public signal void verify_status (string result, bool done); +} + +class FPrintUtil { + private unowned FPrintManager manager; + private FPrintDevice[] devices = {}; + + public signal void verify_passed (); + public signal void verify_failed (); + + public bool start (string username) { + + bool any_started = false; + + try { + manager = Bus.get_proxy_sync ( + BusType.SYSTEM, + "net.reactivated.Fprint", + "/net/reactivated/Fprint/Manager", + DBusProxyFlags.NONE + ); + } catch (Error e) { + debug (e.message); + return false; + } + + var device_paths = manager.get_devices (); + + foreach (var device_path in device_paths) { + FPrintDevice device; + try { + device = GLib.Bus.get_proxy_sync ( + GLib.BusType.SYSTEM, + "net.reactivated.Fprint", + device_path + ); + } catch (Error e) { + debug (e.message); + continue; + } + devices += device; + } + + foreach (var device in devices) { + try { + device.claim (username); + device.verify_status.connect(status); + device.verify_start ("any"); + any_started = true; + } catch (Error e) { + debug ("%s: %s", e.message, device.name); + } + } + + return any_started; + } + + public void stop () { + foreach (var device in devices) { + try { + device.release (); + } catch (Error e) { + debug ("%s: %s", e.message, device.name); + } + } + } + + private void status (string result, bool done) { + if (result == "verify-match") { + foreach (var device in devices) { + try { + device.verify_stop (); + } catch (GLib.Error e) { + debug ("Device stop error: %s\n%s", device.name, e.message); + } + } + stop (); + verify_passed (); + } else { + verify_failed (); + } + } } From fe903e36258afc9b05fcc377717b39e2e5be0636 Mon Sep 17 00:00:00 2001 From: Vishal Rao Date: Tue, 30 Jun 2026 11:05:42 +0530 Subject: [PATCH 3/5] Make FPrintUtil a GLib Object --- src/FPrintUtils.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FPrintUtils.vala b/src/FPrintUtils.vala index fc1f65c8..d8c42034 100644 --- a/src/FPrintUtils.vala +++ b/src/FPrintUtils.vala @@ -21,7 +21,7 @@ public interface FPrintDevice : GLib.Object { public signal void verify_status (string result, bool done); } -class FPrintUtil { +class FPrintUtil : GLib.Object { private unowned FPrintManager manager; private FPrintDevice[] devices = {}; From c016842a7896b37c60cb31f26ea06abeb80a391a Mon Sep 17 00:00:00 2001 From: Vishal Rao Date: Tue, 30 Jun 2026 11:39:29 +0530 Subject: [PATCH 4/5] Wire up FPrintUtil --- src/Cards/UserCard.vala | 22 ++++++++++++++++++---- src/FPrintUtils.vala | 2 +- src/MainWindow.vala | 6 +++++- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/Cards/UserCard.vala b/src/Cards/UserCard.vala index d60d00cd..bab634e8 100644 --- a/src/Cards/UserCard.vala +++ b/src/Cards/UserCard.vala @@ -9,7 +9,7 @@ public class Greeter.UserCard : Greeter.BaseCard { public LightDM.User lightdm_user { get; construct; } public bool show_input { get; set; default = false; } public bool is_24h { get; set; default = true; } - // TODO: In Gtk4 remove this gesture and move it to MainWindow + // TODO: In Gtk4 remove this gesture and move it to MainWindow public Gtk.GestureMultiPress click_gesture { get; private set; } private Pantheon.AccountsService greeter_act; @@ -23,8 +23,13 @@ public class Greeter.UserCard : Greeter.BaseCard { private SelectionCheck logged_in; - public UserCard (LightDM.User lightdm_user) { - Object (lightdm_user: lightdm_user); + public unowned FPrintUtil fprint_util { get; construct; } + + public UserCard (LightDM.User lightdm_user, FPrintUtil fprint_util) { + Object ( + lightdm_user: lightdm_user, + fprint_util: fprint_util + ); } construct { @@ -160,6 +165,9 @@ public class Greeter.UserCard : Greeter.BaseCard { password_entry.activate.connect (on_login); login_button.clicked.connect (on_login); + fprint_util.verify_passed.connect (on_login); + fprint_util.verify_failed.connect (wrong_credentials); + grab_focus.connect (password_entry.grab_focus_without_selecting); } @@ -319,7 +327,7 @@ public class Greeter.UserCard : Greeter.BaseCard { settings.set_value ("xkb-options", options); } - /* + /* * When we get string typed settings from our settings daemon account service we might get a null value. * In this case we reset the value to avoid criticals and unwanted behaviour. */ @@ -426,6 +434,12 @@ public class Greeter.UserCard : Greeter.BaseCard { SettingsPortal.get_default ().prefers_color_scheme = greeter_act.prefers_color_scheme; } + public override bool focus (Gtk.DirectionType direction) { + use_fingerprint = false; + fprint_util.stop (); + return base.focus (direction); + } + public override void wrong_credentials () { password_entry.get_style_context ().add_class (Gtk.STYLE_CLASS_ERROR); main_box.get_style_context ().add_class ("shake"); diff --git a/src/FPrintUtils.vala b/src/FPrintUtils.vala index d8c42034..6991ca2f 100644 --- a/src/FPrintUtils.vala +++ b/src/FPrintUtils.vala @@ -21,7 +21,7 @@ public interface FPrintDevice : GLib.Object { public signal void verify_status (string result, bool done); } -class FPrintUtil : GLib.Object { +public class FPrintUtil : GLib.Object { private unowned FPrintManager manager; private FPrintDevice[] devices = {}; diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 7da82a73..2db5b174 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -21,6 +21,8 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { private int current_user_card_index = -1; private unowned Greeter.BaseCard? current_card = null; + private FPrintUtil fprint_util; + private bool installer_mode = false; private Gtk.EventControllerKey key_controller; @@ -385,7 +387,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { } private void add_card (LightDM.User lightdm_user) { - var user_card = new Greeter.UserCard (lightdm_user); + var user_card = new Greeter.UserCard (lightdm_user, fprint_util); user_card.show_all (); user_card.do_connect.connect (do_connect); user_card.click_gesture.pressed.connect ((gesture, n_press, x, y) => { @@ -497,6 +499,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { unowned Greeter.UserCard? next_card = user_cards.peek_nth (current_user_card_index - 1); if (next_card != null) { carousel.scroll_to (next_card); + fprint_util.start (next_card.lightdm_user.name); } } @@ -508,6 +511,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { unowned Greeter.UserCard? next_card = user_cards.peek_nth (current_user_card_index + 1); if (next_card != null) { carousel.scroll_to (next_card); + fprint_util.start (next_card.lightdm_user.name); } } } From d2a45582968279310e0414cf223b8a38f5fa9496 Mon Sep 17 00:00:00 2001 From: Vishal Rao Date: Sat, 4 Jul 2026 17:38:13 +0530 Subject: [PATCH 5/5] Dunno what to do --- src/Cards/UserCard.vala | 8 ++++++-- src/FPrintUtils.vala | 15 +++++++++++---- src/MainWindow.vala | 9 +++++++-- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/Cards/UserCard.vala b/src/Cards/UserCard.vala index bab634e8..ca79bc6a 100644 --- a/src/Cards/UserCard.vala +++ b/src/Cards/UserCard.vala @@ -23,7 +23,8 @@ public class Greeter.UserCard : Greeter.BaseCard { private SelectionCheck logged_in; - public unowned FPrintUtil fprint_util { get; construct; } + public FPrintUtil fprint_util { get; construct; } + public signal void do_fprint_login (string username); public UserCard (LightDM.User lightdm_user, FPrintUtil fprint_util) { Object ( @@ -165,7 +166,10 @@ public class Greeter.UserCard : Greeter.BaseCard { password_entry.activate.connect (on_login); login_button.clicked.connect (on_login); - fprint_util.verify_passed.connect (on_login); + fprint_util.verify_passed.connect (() => { + do_fprint_login (lightdm_user.name); + }); + fprint_util.verify_failed.connect (wrong_credentials); grab_focus.connect (password_entry.grab_focus_without_selecting); diff --git a/src/FPrintUtils.vala b/src/FPrintUtils.vala index 6991ca2f..e2bc5529 100644 --- a/src/FPrintUtils.vala +++ b/src/FPrintUtils.vala @@ -8,7 +8,7 @@ [DBus (name = "net.reactivated.Fprint.Manager")] public interface FPrintManager : GLib.Object { public abstract ObjectPath get_default_device () throws GLib.Error; - public abstract ObjectPath[] get_devices (); + public abstract ObjectPath[] get_devices () throws GLib.Error; } [DBus (name = "net.reactivated.Fprint.Device")] @@ -22,7 +22,7 @@ public interface FPrintDevice : GLib.Object { } public class FPrintUtil : GLib.Object { - private unowned FPrintManager manager; + private FPrintManager manager; private FPrintDevice[] devices = {}; public signal void verify_passed (); @@ -44,7 +44,14 @@ public class FPrintUtil : GLib.Object { return false; } - var device_paths = manager.get_devices (); + ObjectPath[]? device_paths = null; + + try { + device_paths = manager.get_devices (); + } catch (Error e) { + debug (e.message); + return false; + } foreach (var device_path in device_paths) { FPrintDevice device; @@ -91,7 +98,7 @@ public class FPrintUtil : GLib.Object { try { device.verify_stop (); } catch (GLib.Error e) { - debug ("Device stop error: %s\n%s", device.name, e.message); + debug ("%s: %s", device.name, e.message); } } stop (); diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 2db5b174..1bcc6ba5 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -42,6 +42,8 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { lightdm_greeter.show_prompt.connect (show_prompt); lightdm_greeter.authentication_complete.connect (authentication_complete); + fprint_util = new FPrintUtil (); + var guest_login_button = new Gtk.Button.with_label (_("Log in as Guest")); var manual_login_button = new Gtk.ToggleButton.with_label (_("Manual Login…")); @@ -349,6 +351,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { user_cards.head.foreach ((card) => { if (card.lightdm_user.name == user_to_select) { carousel.scroll_to (card); + card.use_fingerprint = fprint_util.start (card.lightdm_user.name); user_selected = true; } }); @@ -357,6 +360,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { unowned var user_card = user_cards.peek_head (); user_card.show_input = true; carousel.scroll_to (user_card); + user_card.use_fingerprint = fprint_util.start (user_card.lightdm_user.name); } } else { datetime_revealer.reveal_child = false; @@ -390,6 +394,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { var user_card = new Greeter.UserCard (lightdm_user, fprint_util); user_card.show_all (); user_card.do_connect.connect (do_connect); + user_card.do_fprint_login.connect (do_connect_username); user_card.click_gesture.pressed.connect ((gesture, n_press, x, y) => { assert (gesture.widget is UserCard); @@ -499,7 +504,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { unowned Greeter.UserCard? next_card = user_cards.peek_nth (current_user_card_index - 1); if (next_card != null) { carousel.scroll_to (next_card); - fprint_util.start (next_card.lightdm_user.name); + next_card.use_fingerprint = fprint_util.start (next_card.lightdm_user.name); } } @@ -511,7 +516,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { unowned Greeter.UserCard? next_card = user_cards.peek_nth (current_user_card_index + 1); if (next_card != null) { carousel.scroll_to (next_card); - fprint_util.start (next_card.lightdm_user.name); + next_card.use_fingerprint = fprint_util.start (next_card.lightdm_user.name); } } }