perf: async fprintd initialization for instant window display
Move all fprintd D-Bus calls (init, availability check, claim, verify) from synchronous to async using gio futures. Windows now appear immediately without waiting for D-Bus — fingerprint label fades in once fprintd is ready. Single shared FingerprintListener across all monitors instead of one per monitor.
This commit is contained in:
parent
58c076198f
commit
13b329cd98
@ -32,32 +32,31 @@ pub struct FingerprintListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FingerprintListener {
|
impl FingerprintListener {
|
||||||
/// Create a new FingerprintListener.
|
/// Create a lightweight FingerprintListener without any D-Bus calls.
|
||||||
/// Connects to fprintd synchronously — call before creating GTK windows.
|
/// Call `init_async().await` afterwards to connect to fprintd.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut listener = FingerprintListener {
|
FingerprintListener {
|
||||||
device_proxy: None,
|
device_proxy: None,
|
||||||
signal_id: None,
|
signal_id: None,
|
||||||
running: false,
|
running: false,
|
||||||
failed_attempts: 0,
|
failed_attempts: 0,
|
||||||
on_success: None,
|
on_success: None,
|
||||||
on_failure: None,
|
on_failure: None,
|
||||||
};
|
}
|
||||||
listener.init_device();
|
|
||||||
listener
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Connect to fprintd and get the default device.
|
/// Connect to fprintd and get the default device asynchronously.
|
||||||
fn init_device(&mut self) {
|
pub async fn init_async(&mut self) {
|
||||||
let manager = match gio::DBusProxy::for_bus_sync(
|
let manager = match gio::DBusProxy::for_bus_future(
|
||||||
gio::BusType::System,
|
gio::BusType::System,
|
||||||
gio::DBusProxyFlags::NONE,
|
gio::DBusProxyFlags::NONE,
|
||||||
None,
|
None,
|
||||||
FPRINTD_BUS_NAME,
|
FPRINTD_BUS_NAME,
|
||||||
FPRINTD_MANAGER_PATH,
|
FPRINTD_MANAGER_PATH,
|
||||||
FPRINTD_MANAGER_IFACE,
|
FPRINTD_MANAGER_IFACE,
|
||||||
gio::Cancellable::NONE,
|
)
|
||||||
) {
|
.await
|
||||||
|
{
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::debug!("fprintd manager not available: {e}");
|
log::debug!("fprintd manager not available: {e}");
|
||||||
@ -66,13 +65,10 @@ impl FingerprintListener {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Call GetDefaultDevice
|
// Call GetDefaultDevice
|
||||||
let result = match manager.call_sync(
|
let result = match manager
|
||||||
"GetDefaultDevice",
|
.call_future("GetDefaultDevice", None, gio::DBusCallFlags::NONE, -1)
|
||||||
None,
|
.await
|
||||||
gio::DBusCallFlags::NONE,
|
{
|
||||||
-1,
|
|
||||||
gio::Cancellable::NONE,
|
|
||||||
) {
|
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::debug!("fprintd GetDefaultDevice failed: {e}");
|
log::debug!("fprintd GetDefaultDevice failed: {e}");
|
||||||
@ -86,15 +82,16 @@ impl FingerprintListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match gio::DBusProxy::for_bus_sync(
|
match gio::DBusProxy::for_bus_future(
|
||||||
gio::BusType::System,
|
gio::BusType::System,
|
||||||
gio::DBusProxyFlags::NONE,
|
gio::DBusProxyFlags::NONE,
|
||||||
None,
|
None,
|
||||||
FPRINTD_BUS_NAME,
|
FPRINTD_BUS_NAME,
|
||||||
&device_path,
|
&device_path,
|
||||||
FPRINTD_DEVICE_IFACE,
|
FPRINTD_DEVICE_IFACE,
|
||||||
gio::Cancellable::NONE,
|
)
|
||||||
) {
|
.await
|
||||||
|
{
|
||||||
Ok(proxy) => {
|
Ok(proxy) => {
|
||||||
self.device_proxy = Some(proxy);
|
self.device_proxy = Some(proxy);
|
||||||
}
|
}
|
||||||
@ -104,21 +101,18 @@ impl FingerprintListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if fprintd is available and the user has enrolled fingerprints.
|
/// Check if fprintd is available and the user has enrolled fingerprints (async).
|
||||||
pub fn is_available(&self, username: &str) -> bool {
|
pub async fn is_available_async(&self, username: &str) -> bool {
|
||||||
let proxy = match &self.device_proxy {
|
let proxy = match &self.device_proxy {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
None => return false,
|
None => return false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let args = glib::Variant::from((&username,));
|
let args = glib::Variant::from((&username,));
|
||||||
match proxy.call_sync(
|
match proxy
|
||||||
"ListEnrolledFingers",
|
.call_future("ListEnrolledFingers", Some(&args), gio::DBusCallFlags::NONE, -1)
|
||||||
Some(&args),
|
.await
|
||||||
gio::DBusCallFlags::NONE,
|
{
|
||||||
-1,
|
|
||||||
gio::Cancellable::NONE,
|
|
||||||
) {
|
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
// Result is a tuple of (array of strings)
|
// Result is a tuple of (array of strings)
|
||||||
let fingers: Vec<String> = result.child_get::<Vec<String>>(0);
|
let fingers: Vec<String> = result.child_get::<Vec<String>>(0);
|
||||||
@ -129,9 +123,10 @@ impl FingerprintListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Start listening for fingerprint verification.
|
/// Start listening for fingerprint verification.
|
||||||
|
/// Claims the device and starts verification using async D-Bus calls.
|
||||||
/// Connects the D-Bus g-signal handler internally. The `listener` parameter
|
/// Connects the D-Bus g-signal handler internally. The `listener` parameter
|
||||||
/// must be the same `Rc<RefCell<FingerprintListener>>` that owns `self`.
|
/// must be the same `Rc<RefCell<FingerprintListener>>` that owns `self`.
|
||||||
pub fn start<F, G>(
|
pub async fn start_async<F, G>(
|
||||||
listener: &Rc<RefCell<FingerprintListener>>,
|
listener: &Rc<RefCell<FingerprintListener>>,
|
||||||
username: &str,
|
username: &str,
|
||||||
on_success: F,
|
on_success: F,
|
||||||
@ -156,34 +151,24 @@ impl FingerprintListener {
|
|||||||
|
|
||||||
// Claim the device
|
// Claim the device
|
||||||
let args = glib::Variant::from((&username,));
|
let args = glib::Variant::from((&username,));
|
||||||
if let Err(e) = proxy.call_sync(
|
if let Err(e) = proxy
|
||||||
"Claim",
|
.call_future("Claim", Some(&args), gio::DBusCallFlags::NONE, -1)
|
||||||
Some(&args),
|
.await
|
||||||
gio::DBusCallFlags::NONE,
|
{
|
||||||
-1,
|
|
||||||
gio::Cancellable::NONE,
|
|
||||||
) {
|
|
||||||
log::error!("Failed to claim fingerprint device: {e}");
|
log::error!("Failed to claim fingerprint device: {e}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start verification
|
// Start verification
|
||||||
let start_args = glib::Variant::from((&"any",));
|
let start_args = glib::Variant::from((&"any",));
|
||||||
if let Err(e) = proxy.call_sync(
|
if let Err(e) = proxy
|
||||||
"VerifyStart",
|
.call_future("VerifyStart", Some(&start_args), gio::DBusCallFlags::NONE, -1)
|
||||||
Some(&start_args),
|
.await
|
||||||
gio::DBusCallFlags::NONE,
|
{
|
||||||
-1,
|
|
||||||
gio::Cancellable::NONE,
|
|
||||||
) {
|
|
||||||
log::error!("Failed to start fingerprint verification: {e}");
|
log::error!("Failed to start fingerprint verification: {e}");
|
||||||
let _ = proxy.call_sync(
|
let _ = proxy
|
||||||
"Release",
|
.call_future("Release", None, gio::DBusCallFlags::NONE, -1)
|
||||||
None,
|
.await;
|
||||||
gio::DBusCallFlags::NONE,
|
|
||||||
-1,
|
|
||||||
gio::Cancellable::NONE,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,23 +19,33 @@ use crate::i18n::{faillock_warning, load_strings, Strings};
|
|||||||
use crate::power::{self, PowerError};
|
use crate::power::{self, PowerError};
|
||||||
use crate::users;
|
use crate::users;
|
||||||
|
|
||||||
|
/// Handles returned from create_lockscreen_window for post-creation wiring.
|
||||||
|
pub struct LockscreenHandles {
|
||||||
|
pub window: gtk::ApplicationWindow,
|
||||||
|
pub fp_label: gtk::Label,
|
||||||
|
pub password_entry: gtk::PasswordEntry,
|
||||||
|
pub unlock_callback: Rc<dyn Fn()>,
|
||||||
|
pub username: String,
|
||||||
|
state: Rc<RefCell<LockscreenState>>,
|
||||||
|
}
|
||||||
|
|
||||||
const AVATAR_SIZE: i32 = 128;
|
const AVATAR_SIZE: i32 = 128;
|
||||||
const FAILLOCK_MAX_ATTEMPTS: u32 = 3;
|
const FAILLOCK_MAX_ATTEMPTS: u32 = 3;
|
||||||
|
|
||||||
/// Shared mutable state for the lockscreen.
|
/// Shared mutable state for the lockscreen.
|
||||||
struct LockscreenState {
|
struct LockscreenState {
|
||||||
failed_attempts: u32,
|
failed_attempts: u32,
|
||||||
fp_listener: FingerprintListener,
|
|
||||||
fp_listener_rc: Option<Rc<RefCell<FingerprintListener>>>,
|
fp_listener_rc: Option<Rc<RefCell<FingerprintListener>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a lockscreen window for a single monitor.
|
/// Create a lockscreen window for a single monitor.
|
||||||
|
/// Fingerprint is not initialized here — use `wire_fingerprint()` after async init.
|
||||||
pub fn create_lockscreen_window(
|
pub fn create_lockscreen_window(
|
||||||
bg_path: &Path,
|
bg_path: &Path,
|
||||||
config: &Config,
|
_config: &Config,
|
||||||
app: >k::Application,
|
app: >k::Application,
|
||||||
unlock_callback: Rc<dyn Fn()>,
|
unlock_callback: Rc<dyn Fn()>,
|
||||||
) -> gtk::ApplicationWindow {
|
) -> LockscreenHandles {
|
||||||
let window = gtk::ApplicationWindow::builder()
|
let window = gtk::ApplicationWindow::builder()
|
||||||
.application(app)
|
.application(app)
|
||||||
.build();
|
.build();
|
||||||
@ -46,17 +56,24 @@ pub fn create_lockscreen_window(
|
|||||||
Some(u) => u,
|
Some(u) => u,
|
||||||
None => {
|
None => {
|
||||||
log::error!("Failed to get current user");
|
log::error!("Failed to get current user");
|
||||||
return window;
|
let fp_label = gtk::Label::new(None);
|
||||||
|
fp_label.set_visible(false);
|
||||||
|
return LockscreenHandles {
|
||||||
|
window,
|
||||||
|
fp_label,
|
||||||
|
password_entry: gtk::PasswordEntry::new(),
|
||||||
|
unlock_callback,
|
||||||
|
username: String::new(),
|
||||||
|
state: Rc::new(RefCell::new(LockscreenState {
|
||||||
|
failed_attempts: 0,
|
||||||
|
fp_listener_rc: None,
|
||||||
|
})),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let fp_listener = FingerprintListener::new();
|
|
||||||
let fp_available = config.fingerprint_enabled
|
|
||||||
&& fp_listener.is_available(&user.username);
|
|
||||||
|
|
||||||
let state = Rc::new(RefCell::new(LockscreenState {
|
let state = Rc::new(RefCell::new(LockscreenState {
|
||||||
failed_attempts: 0,
|
failed_attempts: 0,
|
||||||
fp_listener,
|
|
||||||
fp_listener_rc: None,
|
fp_listener_rc: None,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -119,15 +136,10 @@ pub fn create_lockscreen_window(
|
|||||||
error_label.set_visible(false);
|
error_label.set_visible(false);
|
||||||
login_box.append(&error_label);
|
login_box.append(&error_label);
|
||||||
|
|
||||||
// Fingerprint label
|
// Fingerprint label — hidden until async fprintd init completes
|
||||||
let fp_label = gtk::Label::new(None);
|
let fp_label = gtk::Label::new(None);
|
||||||
fp_label.add_css_class("fingerprint-label");
|
fp_label.add_css_class("fingerprint-label");
|
||||||
if fp_available {
|
fp_label.set_visible(false);
|
||||||
fp_label.set_text(strings.fingerprint_prompt);
|
|
||||||
fp_label.set_visible(true);
|
|
||||||
} else {
|
|
||||||
fp_label.set_visible(false);
|
|
||||||
}
|
|
||||||
login_box.append(&fp_label);
|
login_box.append(&fp_label);
|
||||||
|
|
||||||
// Confirm box area (for power confirm)
|
// Confirm box area (for power confirm)
|
||||||
@ -293,61 +305,6 @@ pub fn create_lockscreen_window(
|
|||||||
));
|
));
|
||||||
window.add_controller(key_controller);
|
window.add_controller(key_controller);
|
||||||
|
|
||||||
// Start fingerprint listener
|
|
||||||
if fp_available {
|
|
||||||
let unlock_cb_fp = unlock_callback.clone();
|
|
||||||
let fp_label_success = fp_label.clone();
|
|
||||||
let fp_label_fail = fp_label.clone();
|
|
||||||
|
|
||||||
let on_success = move || {
|
|
||||||
let label = fp_label_success.clone();
|
|
||||||
let cb = unlock_cb_fp.clone();
|
|
||||||
glib::idle_add_local_once(move || {
|
|
||||||
label.set_text(load_strings(None).fingerprint_success);
|
|
||||||
label.add_css_class("success");
|
|
||||||
cb();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
let on_failure = move || {
|
|
||||||
let label = fp_label_fail.clone();
|
|
||||||
glib::idle_add_local_once(clone!(
|
|
||||||
#[weak]
|
|
||||||
label,
|
|
||||||
move || {
|
|
||||||
let strings = load_strings(None);
|
|
||||||
label.set_text(strings.fingerprint_failed);
|
|
||||||
label.add_css_class("failed");
|
|
||||||
// Reset after 2 seconds
|
|
||||||
glib::timeout_add_local_once(
|
|
||||||
std::time::Duration::from_secs(2),
|
|
||||||
clone!(
|
|
||||||
#[weak]
|
|
||||||
label,
|
|
||||||
move || {
|
|
||||||
label.set_text(load_strings(None).fingerprint_prompt);
|
|
||||||
label.remove_css_class("success");
|
|
||||||
label.remove_css_class("failed");
|
|
||||||
}
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Extract the fp_listener into its own Rc<RefCell<>> for signal self-wiring
|
|
||||||
let fp_rc = {
|
|
||||||
let mut s = state.borrow_mut();
|
|
||||||
let listener = std::mem::replace(&mut s.fp_listener, FingerprintListener::new());
|
|
||||||
Rc::new(RefCell::new(listener))
|
|
||||||
};
|
|
||||||
|
|
||||||
FingerprintListener::start(&fp_rc, &user.username, on_success, on_failure);
|
|
||||||
|
|
||||||
// Store back the Rc reference for stop() on unlock
|
|
||||||
state.borrow_mut().fp_listener_rc = Some(fp_rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fade-in on map
|
// Fade-in on map
|
||||||
window.connect_map(|w| {
|
window.connect_map(|w| {
|
||||||
glib::idle_add_local_once(clone!(
|
glib::idle_add_local_once(clone!(
|
||||||
@ -370,7 +327,81 @@ pub fn create_lockscreen_window(
|
|||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
window
|
LockscreenHandles {
|
||||||
|
window,
|
||||||
|
fp_label,
|
||||||
|
password_entry: password_entry.clone(),
|
||||||
|
unlock_callback,
|
||||||
|
username: user.username,
|
||||||
|
state: state.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Show the fingerprint label and store the listener reference for stop-on-unlock.
|
||||||
|
/// Does NOT start verification — call `start_fingerprint()` on one monitor for that.
|
||||||
|
pub fn show_fingerprint_label(
|
||||||
|
handles: &LockscreenHandles,
|
||||||
|
fp_rc: &Rc<RefCell<FingerprintListener>>,
|
||||||
|
) {
|
||||||
|
let strings = load_strings(None);
|
||||||
|
handles.fp_label.set_text(strings.fingerprint_prompt);
|
||||||
|
handles.fp_label.set_visible(true);
|
||||||
|
|
||||||
|
// Store the Rc reference for stop() on unlock
|
||||||
|
handles.state.borrow_mut().fp_listener_rc = Some(fp_rc.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Start fingerprint verification on a single monitor's handles.
|
||||||
|
/// Wires up on_success/on_failure callbacks and calls start_async.
|
||||||
|
pub fn start_fingerprint(
|
||||||
|
handles: &LockscreenHandles,
|
||||||
|
fp_rc: &Rc<RefCell<FingerprintListener>>,
|
||||||
|
) {
|
||||||
|
let fp_label_success = handles.fp_label.clone();
|
||||||
|
let fp_label_fail = handles.fp_label.clone();
|
||||||
|
let unlock_cb_fp = handles.unlock_callback.clone();
|
||||||
|
|
||||||
|
let on_success = move || {
|
||||||
|
let label = fp_label_success.clone();
|
||||||
|
let cb = unlock_cb_fp.clone();
|
||||||
|
glib::idle_add_local_once(move || {
|
||||||
|
label.set_text(load_strings(None).fingerprint_success);
|
||||||
|
label.add_css_class("success");
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let on_failure = move || {
|
||||||
|
let label = fp_label_fail.clone();
|
||||||
|
glib::idle_add_local_once(clone!(
|
||||||
|
#[weak]
|
||||||
|
label,
|
||||||
|
move || {
|
||||||
|
let strings = load_strings(None);
|
||||||
|
label.set_text(strings.fingerprint_failed);
|
||||||
|
label.add_css_class("failed");
|
||||||
|
// Reset after 2 seconds
|
||||||
|
glib::timeout_add_local_once(
|
||||||
|
std::time::Duration::from_secs(2),
|
||||||
|
clone!(
|
||||||
|
#[weak]
|
||||||
|
label,
|
||||||
|
move || {
|
||||||
|
label.set_text(load_strings(None).fingerprint_prompt);
|
||||||
|
label.remove_css_class("success");
|
||||||
|
label.remove_css_class("failed");
|
||||||
|
}
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
let username = handles.username.clone();
|
||||||
|
let fp_rc_clone = fp_rc.clone();
|
||||||
|
glib::spawn_future_local(async move {
|
||||||
|
FingerprintListener::start_async(&fp_rc_clone, &username, on_success, on_failure).await;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a Picture widget for the wallpaper background.
|
/// Create a Picture widget for the wallpaper background.
|
||||||
|
|||||||
60
src/main.rs
60
src/main.rs
@ -13,9 +13,12 @@ use gdk4 as gdk;
|
|||||||
use gtk4::prelude::*;
|
use gtk4::prelude::*;
|
||||||
use gtk4::{self as gtk, gio};
|
use gtk4::{self as gtk, gio};
|
||||||
use gtk4_session_lock;
|
use gtk4_session_lock;
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use crate::fingerprint::FingerprintListener;
|
||||||
|
|
||||||
fn load_css(display: &gdk::Display) {
|
fn load_css(display: &gdk::Display) {
|
||||||
let css_provider = gtk::CssProvider::new();
|
let css_provider = gtk::CssProvider::new();
|
||||||
css_provider.load_from_resource("/dev/moonarch/moonlock/style.css");
|
css_provider.load_from_resource("/dev/moonarch/moonlock/style.css");
|
||||||
@ -75,27 +78,67 @@ fn activate_with_session_lock(
|
|||||||
app_clone.quit();
|
app_clone.quit();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Create all monitor windows immediately — no D-Bus calls here
|
||||||
|
let mut all_handles = Vec::new();
|
||||||
let mut created_any = false;
|
let mut created_any = false;
|
||||||
for i in 0..monitors.n_items() {
|
for i in 0..monitors.n_items() {
|
||||||
if let Some(monitor) = monitors
|
if let Some(monitor) = monitors
|
||||||
.item(i)
|
.item(i)
|
||||||
.and_then(|obj| obj.downcast::<gdk::Monitor>().ok())
|
.and_then(|obj| obj.downcast::<gdk::Monitor>().ok())
|
||||||
{
|
{
|
||||||
let window = lockscreen::create_lockscreen_window(
|
let handles = lockscreen::create_lockscreen_window(
|
||||||
bg_path,
|
bg_path,
|
||||||
config,
|
config,
|
||||||
app,
|
app,
|
||||||
unlock_callback.clone(),
|
unlock_callback.clone(),
|
||||||
);
|
);
|
||||||
lock.assign_window_to_monitor(&window, &monitor);
|
lock.assign_window_to_monitor(&handles.window, &monitor);
|
||||||
window.present();
|
handles.window.present();
|
||||||
|
all_handles.push(handles);
|
||||||
created_any = true;
|
created_any = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !created_any {
|
if !created_any {
|
||||||
log::error!("No lockscreen windows created — screen stays locked (compositor policy)");
|
log::error!("No lockscreen windows created — screen stays locked (compositor policy)");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Async fprintd initialization — runs after windows are visible
|
||||||
|
if config.fingerprint_enabled {
|
||||||
|
init_fingerprint_async(all_handles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize fprintd asynchronously after windows are visible.
|
||||||
|
/// Uses a single FingerprintListener shared across all monitors —
|
||||||
|
/// only the first monitor's handles get the fingerprint UI wired up.
|
||||||
|
fn init_fingerprint_async(all_handles: Vec<lockscreen::LockscreenHandles>) {
|
||||||
|
glib::spawn_future_local(async move {
|
||||||
|
let mut listener = FingerprintListener::new();
|
||||||
|
listener.init_async().await;
|
||||||
|
|
||||||
|
// Use the first monitor's username to check enrollment
|
||||||
|
let username = &all_handles[0].username;
|
||||||
|
if username.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !listener.is_available_async(username).await {
|
||||||
|
log::debug!("fprintd not available or no enrolled fingers");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let fp_rc = Rc::new(RefCell::new(listener));
|
||||||
|
|
||||||
|
// Show fingerprint label on all monitors
|
||||||
|
for handles in &all_handles {
|
||||||
|
lockscreen::show_fingerprint_label(handles, &fp_rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start verification listener on the first monitor only
|
||||||
|
lockscreen::start_fingerprint(&all_handles[0], &fp_rc);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
@ -109,14 +152,19 @@ fn activate_without_lock(
|
|||||||
app_clone.quit();
|
app_clone.quit();
|
||||||
});
|
});
|
||||||
|
|
||||||
let window = lockscreen::create_lockscreen_window(
|
let handles = lockscreen::create_lockscreen_window(
|
||||||
bg_path,
|
bg_path,
|
||||||
config,
|
config,
|
||||||
app,
|
app,
|
||||||
unlock_callback,
|
unlock_callback,
|
||||||
);
|
);
|
||||||
window.set_default_size(800, 600);
|
handles.window.set_default_size(800, 600);
|
||||||
window.present();
|
handles.window.present();
|
||||||
|
|
||||||
|
// Async fprintd initialization for development mode
|
||||||
|
if config.fingerprint_enabled {
|
||||||
|
init_fingerprint_async(vec![handles]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_logging() {
|
fn setup_logging() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user