From 10821eea73baa73dac6d5b00f8324d415e52b8ab Mon Sep 17 00:00:00 2001 From: lenemter Date: Tue, 7 Jul 2026 18:05:24 +0300 Subject: [PATCH 1/4] Use AccountService for user info --- src/Application.vala | 5 ++- src/Cards/UserCard.vala | 64 ++++++++++++++++++------------------ src/MainWindow.vala | 72 +++++++++++++++++++---------------------- src/meson.build | 3 +- 4 files changed, 73 insertions(+), 71 deletions(-) diff --git a/src/Application.vala b/src/Application.vala index ba7440ee..162211b5 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -1,5 +1,5 @@ /* - * Copyright 2018-2024 elementary, Inc. (https://elementary.io) + * Copyright 2018-2026 elementary, Inc. (https://elementary.io) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public @@ -111,6 +111,9 @@ public class Greeter.Application : Gtk.Application { } public static int main (string[] args) { + // Connect to UserManager as early as possible + Act.UserManager.get_default (); + return new Greeter.Application ().run (args); } } diff --git a/src/Cards/UserCard.vala b/src/Cards/UserCard.vala index d60d00cd..01fca9ba 100644 --- a/src/Cards/UserCard.vala +++ b/src/Cards/UserCard.vala @@ -1,12 +1,16 @@ /* - * Copyright 2018-2025 elementary, Inc. (https://elementary.io) + * Copyright 2018-2026 elementary, Inc. (https://elementary.io) * SPDX-License-Identifier: GPL-3.0-or-later * * Authors: Corentin Noël */ public class Greeter.UserCard : Greeter.BaseCard { - public LightDM.User lightdm_user { get; construct; } + /** + * We use Act.User instead of LightDM.User because lightdm is unmaintained + * and lacks some fields from Act.User such as `password_mode`. + */ + public Act.User 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 @@ -15,7 +19,6 @@ public class Greeter.UserCard : Greeter.BaseCard { private Pantheon.AccountsService greeter_act; private Pantheon.SettingsDaemon.AccountsService settings_act; - private Gtk.Label username_label; private Gtk.Revealer form_revealer; private Gtk.Stack login_stack; private Greeter.PasswordEntry password_entry; @@ -23,14 +26,14 @@ public class Greeter.UserCard : Greeter.BaseCard { private SelectionCheck logged_in; - public UserCard (LightDM.User lightdm_user) { - Object (lightdm_user: lightdm_user); + public UserCard (Act.User user) requires (user.is_loaded) { + Object (user: user); } construct { need_password = true; - username_label = new Gtk.Label (lightdm_user.display_name) { + var username_label = new Gtk.Label (user.real_name) { hexpand = true, margin_top = 24, margin_bottom = 12, @@ -38,6 +41,7 @@ public class Greeter.UserCard : Greeter.BaseCard { margin_end = 24, }; username_label.get_style_context ().add_class (Granite.STYLE_CLASS_H2_LABEL); + user.bind_property ("locked", username_label, "sensitive", SYNC_CREATE); password_entry = new Greeter.PasswordEntry (); bind_property ("connecting", password_entry, "sensitive", INVERT_BOOLEAN); @@ -108,12 +112,12 @@ public class Greeter.UserCard : Greeter.BaseCard { update_collapsed_class (); - var avatar = new Hdy.Avatar (64, lightdm_user.display_name, true) { + var avatar = new Hdy.Avatar (64, user.real_name, true) { margin_top = 6, margin_bottom = 6, margin_start = 6, margin_end = 6, - loadable_icon = new FileIcon (File.new_for_path (lightdm_user.image)) + loadable_icon = new FileIcon (File.new_for_path (user.icon_file)) }; var avatar_overlay = new Gtk.Overlay () { @@ -128,7 +132,7 @@ public class Greeter.UserCard : Greeter.BaseCard { valign = END }; - if (lightdm_user.logged_in) { + if (user.is_logged_in ()) { avatar_overlay.add_overlay (logged_in); password_session_button.sensitive = false; @@ -150,7 +154,7 @@ public class Greeter.UserCard : Greeter.BaseCard { child = card_overlay; connect_to_dbus_interfaces (); - lightdm_user.changed.connect (update_is_locked_ui); + user.changed.connect (update_is_locked_ui); notify["need-password"].connect (update_is_locked_ui); click_gesture = new Gtk.GestureMultiPress (this); @@ -168,24 +172,27 @@ public class Greeter.UserCard : Greeter.BaseCard { logged_in.get_style_context ().add_class (accent_to_string (settings_act.accent_color)); } + private string generate_background_image_path () { + if (settings_act.picture_options == 0) { + return ""; + } + + var path = Path.build_filename ("/", "var", "lib", "lightdm-data", user.user_name, "wallpaper"); + if (FileUtils.test (path, EXISTS) && FileUtils.test (path, IS_REGULAR)) { + return path; + } + + return "/usr/share/backgrounds/elementaryos-default"; + } + private void set_background_image () { Greeter.BackgroundImage background_image; - var background_path = lightdm_user.background; - var background_exists = ( - background_path != null && - FileUtils.test (background_path, EXISTS) && - FileUtils.test (background_path, IS_REGULAR) - ); - - if (!background_exists) { - background_path = Path.build_filename ("/", "var", "lib", "lightdm-data", lightdm_user.name, "wallpaper"); - background_exists = FileUtils.test (background_path, EXISTS) && FileUtils.test (background_path, IS_REGULAR); - } + var background_path = generate_background_image_path (); - if (settings_act.picture_options != 0 && background_exists) { + if (settings_act.picture_options != 0) { background_image = new Greeter.BackgroundImage.from_path (background_path); - } else if (settings_act.picture_options == 0 && settings_act.primary_color != null) { + } else if (settings_act.primary_color != null) { background_image = new Greeter.BackgroundImage.from_color (settings_act.primary_color); } else { background_image = new Greeter.BackgroundImage.from_path (null); @@ -223,7 +230,7 @@ public class Greeter.UserCard : Greeter.BaseCard { } private void connect_to_dbus_interfaces () { - var account_path = "/org/freedesktop/Accounts/User%d".printf ((int )lightdm_user.uid); + var account_path = "/org/freedesktop/Accounts/User%d".printf (user.uid); try { greeter_act = Bus.get_proxy_sync ( SYSTEM, @@ -250,12 +257,7 @@ public class Greeter.UserCard : Greeter.BaseCard { } private void update_is_locked_ui () { - // lightdm_user.is_locked prints warnings so let's use a getter method here - var is_locked = lightdm_user.get_is_locked (); - - username_label.sensitive = !is_locked; - - if (is_locked) { + if (user.locked) { login_stack.visible_child_name = "disabled"; } else if (need_password) { login_stack.visible_child_name = "password"; @@ -378,7 +380,7 @@ public class Greeter.UserCard : Greeter.BaseCard { var background_settings = new GLib.Settings ("org.gnome.desktop.background"); background_settings.set_enum ("picture-options", settings_act.picture_options); - set_or_reset_settings_key (background_settings, "picture-uri", lightdm_user.background); + set_or_reset_settings_key (background_settings, "picture-uri", generate_background_image_path ()); set_or_reset_settings_key (background_settings, "primary-color", settings_act.primary_color); } diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 616ae938..a38cb050 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -1,6 +1,6 @@ /* * SPDX-License-Identifier: GPL-2.0-or-later - * SPDX-FileCopyrightText: 2018-2025 elementary, Inc. (https://elementary.io) + * SPDX-FileCopyrightText: 2018-2026 elementary, Inc. (https://elementary.io) * * Authors: Corentin Noël */ @@ -16,7 +16,6 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { private GLib.Settings gsettings; private Gtk.Revealer datetime_revealer; private Greeter.DateTimeWidget datetime_widget; - private unowned LightDM.UserList lightdm_user_list; private int current_user_card_index = -1; private unowned Greeter.BaseCard? current_card = null; @@ -116,7 +115,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { current_card = user_cards.peek_nth (current_user_card_index); try { - lightdm_greeter.authenticate (((UserCard) current_card).lightdm_user.name); + lightdm_greeter.authenticate (((UserCard) current_card).user.user_name); } catch (Error e) { critical (e.message); } @@ -138,10 +137,14 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { lightdm_greeter.bind_property ("hide-users-hint", manual_login_button, "sensitive", GLib.BindingFlags.SYNC_CREATE | GLib.BindingFlags.INVERT_BOOLEAN); lightdm_greeter.bind_property ("hide-users-hint", manual_login_button, "active", GLib.BindingFlags.SYNC_CREATE); - lightdm_user_list = LightDM.UserList.get_instance (); - lightdm_user_list.user_added.connect (() => { - load_users.begin (); - }); + unowned var user_manager = Act.UserManager.get_default (); + user_manager.user_added.connect (() => load_users.begin ()); + + if (user_manager.is_loaded) { + load_users.begin (show_greeter_window); + } else { + user_manager.notify["is-loaded"].connect (() => load_users.begin (show_greeter_window)); + } manual_card.do_connect_username.connect (do_connect_username); manual_card.do_connect.connect (do_connect); @@ -182,21 +185,6 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { carousel.page_changed.connect (handle_page_changed); - load_users.begin (() => { - /* A significant delay is required in order for the window and card to be focused at - * at boot. TODO: Find whether boot sequence can be tweaked to fix this. - */ - Timeout.add (500, () => { - get_style_context ().add_class ("initialized"); - - if (current_card != null) { - current_card.grab_focus (); - } - - return Source.REMOVE; - }); - }); - maximize (); if (settings.activate_numlock) { @@ -210,6 +198,19 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { main_box.realize.connect (init_panel); } + /* A significant delay is required in order for the window and card to be focused at boot. + * TODO: Find whether boot sequence can be tweaked to fix this. + */ + private void show_greeter_window () { + Timeout.add (500, () => { + get_style_context ().add_class ("initialized"); + + current_card?.grab_focus (); + + return Source.REMOVE; + }); + } + private void init_panel () { if (Gdk.Display.get_default () is Gdk.Wayland.Display) { // We have to wrap in Idle otherwise the Meta.Window of the WaylandSurface in Gala is still null @@ -292,7 +293,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { private void authentication_complete () { var user_card = current_card as Greeter.UserCard; if (user_card != null) { - gsettings.set_string ("last-user", user_card.lightdm_user.name); + gsettings.set_string ("last-user", user_card.user.user_name); } if (lightdm_greeter.is_authenticated) { @@ -330,7 +331,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { if (user_card != null) { try { - lightdm_greeter.authenticate (user_card.lightdm_user.name); + lightdm_greeter.authenticate (user_card.user.user_name); } catch (Error e) { critical (e.message); } @@ -341,26 +342,25 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { carousel.interactive = true; } - private async void load_users () { + private async void load_users () requires (Act.UserManager.get_default ().is_loaded) { // Check if the installer is installed var installer_desktop = new DesktopAppInfo ("io.elementary.installer.desktop"); if (installer_desktop != null) { installer_mode = true; } - if (lightdm_user_list.length > 0) { - datetime_revealer.reveal_child = true; + var users_list = Act.UserManager.get_default ().list_users (); + if (users_list.length () > 0) { + users_list.foreach (add_card); - lightdm_user_list.users.foreach ((user) => { - add_card (user); - }); + datetime_revealer.reveal_child = true; unowned string? select_user = lightdm_greeter.select_user_hint; var user_to_select = select_user != null ? select_user : gsettings.get_string ("last-user"); bool user_selected = false; user_cards.head.foreach ((card) => { - if (card.lightdm_user.name == user_to_select) { + if (card.user.user_name == user_to_select) { carousel.scroll_to (card); user_selected = true; } @@ -399,8 +399,8 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { } } - private void add_card (LightDM.User lightdm_user) { - var user_card = new Greeter.UserCard (lightdm_user); + private void add_card (Act.User user) { + var user_card = new Greeter.UserCard (user); user_card.show_all (); user_card.do_connect.connect (do_connect); user_card.click_gesture.pressed.connect ((gesture, n_press, x, y) => { @@ -456,10 +456,6 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { user_card.show_input = true; user_card.grab_focus (); - if (user_card.lightdm_user.session != null) { - application.activate_action ("select-session", new GLib.Variant.string (user_card.lightdm_user.session)); - } - if (lightdm_greeter.in_authentication) { try { lightdm_greeter.cancel_authentication (); @@ -469,7 +465,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { } try { - lightdm_greeter.authenticate (user_card.lightdm_user.name); + lightdm_greeter.authenticate (user_card.user.user_name); } catch (Error e) { critical (e.message); } diff --git a/src/meson.build b/src/meson.build index 4b5059d6..50c87f9d 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,3 +1,4 @@ +accountsservice_dep = dependency('accountsservice') gobject_dep = dependency('gobject-2.0') glib_dep = dependency('glib-2.0') gdk_wl_dep = dependency('gdk-wayland-3.0') @@ -31,7 +32,7 @@ executable( 'Widgets/PasswordEntry.vala', 'Widgets/SessionButton.vala', config_header, - dependencies: [ gobject_dep, glib_dep, gdk_wl_dep, gdk_x11_dep, gtk_dep, granite_dep, hdy_dep, lightdm_dep, m_dep, pantheon_desktop_shell_dep, wl_client_dep, x11_dep ], + dependencies: [ accountsservice_dep, gobject_dep, glib_dep, gdk_wl_dep, gdk_x11_dep, gtk_dep, granite_dep, hdy_dep, lightdm_dep, m_dep, pantheon_desktop_shell_dep, wl_client_dep, x11_dep ], install : true, install_dir: install_path ) From 4d84b8436d23b8deee74a70326b0923cc4375119 Mon Sep 17 00:00:00 2001 From: lenemter Date: Wed, 8 Jul 2026 11:10:20 +0300 Subject: [PATCH 2/4] Update CI --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7e2d7354..6dcfb8a8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -32,7 +32,7 @@ jobs: - name: Install Dependencies run: | apt update - apt install -y desktop-file-utils libgdk-pixbuf-2.0-dev libgnome-desktop-3-dev libgranite-dev libgtk-3-dev libhandy-1-dev libjson-glib-dev liblightdm-gobject-1-dev ${{ matrix.mutter_pkg }} libsoup-3.0-dev libx11-dev ${{ matrix.lightdm_vala }} meson valac + apt install -y desktop-file-utils libaccountsservice-dev libgdk-pixbuf-2.0-dev libgnome-desktop-3-dev libgranite-dev libgtk-3-dev libhandy-1-dev libjson-glib-dev liblightdm-gobject-1-dev ${{ matrix.mutter_pkg }} libsoup-3.0-dev libx11-dev ${{ matrix.lightdm_vala }} meson valac - name: Build env: DESTDIR: out @@ -50,7 +50,7 @@ jobs: - uses: actions/checkout@v7 - name: Install Dependencies run: | - dnf install -y desktop-file-utils gdk-pixbuf2-devel gnome-desktop3-devel granite-devel gtk3-devel libhandy-devel lightdm-gobject-devel mutter-devel libX11-devel meson valac + dnf install -y accountsservice-devel desktop-file-utils gdk-pixbuf2-devel gnome-desktop3-devel granite-devel gtk3-devel libhandy-devel lightdm-gobject-devel mutter-devel libX11-devel meson valac - name: Build env: DESTDIR: out @@ -69,7 +69,7 @@ jobs: run: | zypper addrepo https://download.opensuse.org/repositories/X11:Pantheon/16.0/X11:Pantheon.repo zypper --gpg-auto-import-keys refresh - zypper --non-interactive install tar git desktop-file-utils gdk-pixbuf-devel libgnome-desktop-3-devel granite6-devel gtk3-devel libhandy-devel lightdm-gobject-devel mutter-devel meson vala gcc + zypper --non-interactive install accountsservice-devel accountsservice-vala tar git desktop-file-utils gdk-pixbuf-devel libgnome-desktop-3-devel granite6-devel gtk3-devel libhandy-devel lightdm-gobject-devel mutter-devel meson vala gcc - uses: actions/checkout@v7 - name: Build env: From aababcb60500d544fe720452a51b561f2d300b5e Mon Sep 17 00:00:00 2001 From: lenemter Date: Wed, 8 Jul 2026 23:11:21 +0200 Subject: [PATCH 3/4] Refactor authentication --- src/Cards/BaseCard.vala | 8 +++- src/Cards/ManualCard.vala | 8 ++-- src/Cards/UserCard.vala | 40 +++++++++---------- src/MainWindow.vala | 82 ++++++++++----------------------------- 4 files changed, 48 insertions(+), 90 deletions(-) diff --git a/src/Cards/BaseCard.vala b/src/Cards/BaseCard.vala index 2128e511..5c54c515 100644 --- a/src/Cards/BaseCard.vala +++ b/src/Cards/BaseCard.vala @@ -1,12 +1,13 @@ /* * SPDX-License-Identifier: GPL-2.0-or-later - * SPDX-FileCopyrightText: 2018-2025 elementary, Inc. (https://elementary.io) + * SPDX-FileCopyrightText: 2018-2026 elementary, Inc. (https://elementary.io) * * Authors: Corentin Noël */ public abstract class Greeter.BaseCard : Gtk.Bin { - public signal void do_connect (string? credential = null); + public signal void start_authentication (string username); + public signal void provide_credential (string credential); public signal void go_left (); public signal void go_right (); @@ -34,5 +35,8 @@ public abstract class Greeter.BaseCard : Gtk.Bin { return base.focus (direction); } + public virtual void on_selected () {} + public virtual void on_deselected () {} + public abstract void wrong_credentials (); } diff --git a/src/Cards/ManualCard.vala b/src/Cards/ManualCard.vala index cae3c34a..1084d447 100644 --- a/src/Cards/ManualCard.vala +++ b/src/Cards/ManualCard.vala @@ -1,11 +1,9 @@ /* - * Copyright 2018-2023 elementary, Inc. (https://elementary.io) + * Copyright 2018-2026 elementary, Inc. (https://elementary.io) * SPDX-License-Identifier: GPL-2.0-or-later */ public class Greeter.ManualCard : Greeter.BaseCard { - public signal void do_connect_username (string username); - private Greeter.PasswordEntry password_entry; private Gtk.Entry username_entry; private Gtk.Box main_box; @@ -70,7 +68,7 @@ public class Greeter.ManualCard : Greeter.BaseCard { username_entry.focus_out_event.connect (() => { if (username_entry.text != "") { - do_connect_username (username_entry.text); + start_authentication (username_entry.text); } }); @@ -83,7 +81,7 @@ public class Greeter.ManualCard : Greeter.BaseCard { } connecting = true; - do_connect (password_entry.text); + provide_credential (password_entry.text); } public override void wrong_credentials () { diff --git a/src/Cards/UserCard.vala b/src/Cards/UserCard.vala index 01fca9ba..37ecd08c 100644 --- a/src/Cards/UserCard.vala +++ b/src/Cards/UserCard.vala @@ -11,7 +11,6 @@ public class Greeter.UserCard : Greeter.BaseCard { * and lacks some fields from Act.User such as `password_mode`. */ public Act.User 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 public Gtk.GestureMultiPress click_gesture { get; private set; } @@ -95,11 +94,10 @@ public class Greeter.UserCard : Greeter.BaseCard { form_revealer = new Gtk.Revealer () { margin_bottom = 12, - reveal_child = true, + reveal_child = false, transition_type = SLIDE_DOWN, child = login_stack }; - bind_property ("show-input", form_revealer, "reveal-child", SYNC_CREATE); main_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0) { margin_bottom = 48 @@ -109,8 +107,7 @@ public class Greeter.UserCard : Greeter.BaseCard { main_box.pack_end (username_label); main_box.get_style_context ().add_class (Granite.STYLE_CLASS_CARD); main_box.get_style_context ().add_class (Granite.STYLE_CLASS_ROUNDED); - - update_collapsed_class (); + main_box.get_style_context ().add_class ("collapsed"); var avatar = new Hdy.Avatar (64, user.real_name, true) { margin_top = 6, @@ -159,8 +156,6 @@ public class Greeter.UserCard : Greeter.BaseCard { click_gesture = new Gtk.GestureMultiPress (this); - notify["show-input"].connect (update_collapsed_class); - password_entry.activate.connect (on_login); login_button.clicked.connect (on_login); @@ -272,22 +267,10 @@ public class Greeter.UserCard : Greeter.BaseCard { } connecting = true; - if (need_password) { - do_connect (password_entry.text); - } else { - do_connect (); - } - } - - private void update_collapsed_class () { - if (show_input) { - main_box.get_style_context ().remove_class ("collapsed"); - } else { - main_box.get_style_context ().add_class ("collapsed"); - } + provide_credential (need_password ? password_entry.text : ""); } - public void set_settings () { + private void set_settings () { set_keyboard_layouts (); set_mouse_touchpad_settings (); set_interface_settings (); @@ -428,6 +411,21 @@ public class Greeter.UserCard : Greeter.BaseCard { SettingsPortal.get_default ().prefers_color_scheme = greeter_act.prefers_color_scheme; } + public override void on_selected () { + form_revealer.reveal_child = true; + main_box.get_style_context ().remove_class ("collapsed"); + + set_settings (); + grab_focus (); + + start_authentication (user.user_name); + } + + public override void on_deselected () { + form_revealer.reveal_child = false; + main_box.get_style_context ().add_class ("collapsed"); + } + 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/MainWindow.vala b/src/MainWindow.vala index a38cb050..db87a78e 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -91,26 +91,12 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { child = main_box; manual_login_button.toggled.connect (() => { - if (manual_login_button.active) { - if (lightdm_greeter.in_authentication) { - try { - lightdm_greeter.cancel_authentication (); - } catch (Error e) { - critical (e.message); - } - } + cancel_authentication (); + if (manual_login_button.active) { manual_login_stack.visible_child = manual_card; current_card = manual_card; } else { - if (lightdm_greeter.in_authentication) { - try { - lightdm_greeter.cancel_authentication (); - } catch (Error e) { - critical (e.message); - } - } - manual_login_stack.visible_child = carousel; current_card = user_cards.peek_nth (current_user_card_index); @@ -146,8 +132,8 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { user_manager.notify["is-loaded"].connect (() => load_users.begin (show_greeter_window)); } - manual_card.do_connect_username.connect (do_connect_username); - manual_card.do_connect.connect (do_connect); + manual_card.start_authentication.connect (do_connect_username); + manual_card.provide_credential.connect (do_connect); key_controller = new Gtk.EventControllerKey (this) { propagation_phase = CAPTURE @@ -358,7 +344,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { unowned string? select_user = lightdm_greeter.select_user_hint; var user_to_select = select_user != null ? select_user : gsettings.get_string ("last-user"); - bool user_selected = false; + var user_selected = false; user_cards.head.foreach ((card) => { if (card.user.user_name == user_to_select) { carousel.scroll_to (card); @@ -367,9 +353,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { }); if (!user_selected) { - unowned var user_card = user_cards.peek_head (); - user_card.show_input = true; - carousel.scroll_to (user_card); + carousel.scroll_to (user_cards.peek_head ()); } } else { datetime_revealer.reveal_child = false; @@ -402,16 +386,9 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { private void add_card (Act.User user) { var user_card = new Greeter.UserCard (user); user_card.show_all (); - user_card.do_connect.connect (do_connect); - user_card.click_gesture.pressed.connect ((gesture, n_press, x, y) => { - assert (gesture.widget is UserCard); - - var _user_card = (UserCard) gesture.widget; - if (!_user_card.show_input) { - carousel.scroll_to (_user_card); - _user_card.grab_focus (); - } - }); + user_card.start_authentication.connect (do_connect_username); + user_card.provide_credential.connect (do_connect); + user_card.click_gesture.pressed.connect ((gesture, n_press, x, y) => carousel.scroll_to (gesture.widget)); user_card.go_left.connect (() => { if (Gtk.StateFlags.DIR_LTR in get_state_flags ()) { go_previous (); @@ -434,28 +411,24 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { } private void handle_page_changed (uint index) { - if (index == current_user_card_index) { - return; - } + cancel_authentication (); unowned var user_card = user_cards.peek_nth (index); if (user_card == null) { return; } - if (current_card != null && current_card is UserCard) { - ((UserCard) current_card).show_input = false; - } + current_card?.on_deselected (); current_user_card_index = (int) index; current_card = user_card; datetime_widget.is_24h = user_card.is_24h; - user_card.set_settings (); - user_card.show_input = true; - user_card.grab_focus (); + user_card.on_selected (); + } + private void cancel_authentication () { if (lightdm_greeter.in_authentication) { try { lightdm_greeter.cancel_authentication (); @@ -463,22 +436,10 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { critical (e.message); } } - - try { - lightdm_greeter.authenticate (user_card.user.user_name); - } catch (Error e) { - critical (e.message); - } } private void do_connect_username (string username) { - if (lightdm_greeter.in_authentication) { - try { - lightdm_greeter.cancel_authentication (); - } catch (Error e) { - critical (e.message); - } - } + cancel_authentication (); try { lightdm_greeter.authenticate (username); @@ -487,17 +448,14 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { } } - private void do_connect (string? credential) { - if (credential != null) { - try { - lightdm_greeter.respond (credential); - } catch (Error e) { - critical (e.message); - } + private void do_connect (string credential) { + try { + lightdm_greeter.respond (credential); + } catch (Error e) { + critical (e.message); } carousel.interactive = false; - carousel.scroll_to (current_card); } private void go_previous () { From d4735766f5264c7654e3034bf3cbe841d4c2a8cc Mon Sep 17 00:00:00 2001 From: lenemter Date: Thu, 9 Jul 2026 00:50:59 +0300 Subject: [PATCH 4/4] Support password-less login --- src/Cards/BaseCard.vala | 1 - src/Cards/UserCard.vala | 36 +++++++++++++++++++++++++----------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/Cards/BaseCard.vala b/src/Cards/BaseCard.vala index 5c54c515..d7d61392 100644 --- a/src/Cards/BaseCard.vala +++ b/src/Cards/BaseCard.vala @@ -14,7 +14,6 @@ public abstract class Greeter.BaseCard : Gtk.Bin { protected const int ERROR_SHAKE_DURATION = 450; public bool connecting { get; set; default = false; } - public bool need_password { get; set; default = false; } public bool use_fingerprint { get; set; default = false; } construct { diff --git a/src/Cards/UserCard.vala b/src/Cards/UserCard.vala index 37ecd08c..d620a3cd 100644 --- a/src/Cards/UserCard.vala +++ b/src/Cards/UserCard.vala @@ -6,6 +6,10 @@ */ public class Greeter.UserCard : Greeter.BaseCard { + private const int PASSWORD_MODE_REGULAR = 0; + private const int PASSWORD_MODE_SET_AT_NEXT_LOGIN = 1; + private const int PASSWORD_MODE_NO_PASSWORD = 2; + /** * We use Act.User instead of LightDM.User because lightdm is unmaintained * and lacks some fields from Act.User such as `password_mode`. @@ -30,8 +34,6 @@ public class Greeter.UserCard : Greeter.BaseCard { } construct { - need_password = true; - var username_label = new Gtk.Label (user.real_name) { hexpand = true, margin_top = 24, @@ -62,7 +64,9 @@ public class Greeter.UserCard : Greeter.BaseCard { password_grid.attach (password_session_button, 2, 0); password_grid.attach (new Greeter.CapsLockRevealer (), 0, 1, 3); - var login_button = new Gtk.Button.with_label (_("Log In")); + var login_button = new Gtk.Button.with_label (_("Log In")) { + hexpand = true + }; login_button.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); bind_property ("connecting", login_button, "sensitive", INVERT_BOOLEAN); @@ -89,7 +93,7 @@ public class Greeter.UserCard : Greeter.BaseCard { margin_end = 24 }; login_stack.add_named (password_grid, "password"); - login_stack.add_named (login_button, "button"); + login_stack.add_named (login_box, "button"); login_stack.add_named (disabled_box, "disabled"); form_revealer = new Gtk.Revealer () { @@ -150,9 +154,11 @@ public class Greeter.UserCard : Greeter.BaseCard { child = card_overlay; - connect_to_dbus_interfaces (); - user.changed.connect (update_is_locked_ui); - notify["need-password"].connect (update_is_locked_ui); + show_all (); + + user.notify["locked"].connect (update_is_locked_ui); + user.notify["password-mode"].connect (update_is_locked_ui); + update_is_locked_ui (); click_gesture = new Gtk.GestureMultiPress (this); @@ -160,6 +166,8 @@ public class Greeter.UserCard : Greeter.BaseCard { login_button.clicked.connect (on_login); grab_focus.connect (password_entry.grab_focus_without_selecting); + + connect_to_dbus_interfaces (); } private void set_check_style () { @@ -248,13 +256,12 @@ public class Greeter.UserCard : Greeter.BaseCard { set_background_image (); set_check_style (); - update_is_locked_ui (); } private void update_is_locked_ui () { if (user.locked) { login_stack.visible_child_name = "disabled"; - } else if (need_password) { + } else if (user.password_mode != PASSWORD_MODE_NO_PASSWORD) { login_stack.visible_child_name = "password"; } else { login_stack.visible_child_name = "button"; @@ -267,7 +274,12 @@ public class Greeter.UserCard : Greeter.BaseCard { } connecting = true; - provide_credential (need_password ? password_entry.text : ""); + + if (user.password_mode != PASSWORD_MODE_NO_PASSWORD) { + provide_credential (password_entry.text); + } else { + start_authentication (user.user_name); + } } private void set_settings () { @@ -418,7 +430,9 @@ public class Greeter.UserCard : Greeter.BaseCard { set_settings (); grab_focus (); - start_authentication (user.user_name); + if (user.password_mode != PASSWORD_MODE_NO_PASSWORD) { + start_authentication (user.user_name); + } } public override void on_deselected () {