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:
+37
-52
@@ -32,32 +32,31 @@ pub struct FingerprintListener {
|
||||
}
|
||||
|
||||
impl FingerprintListener {
|
||||
/// Create a new FingerprintListener.
|
||||
/// Connects to fprintd synchronously — call before creating GTK windows.
|
||||
/// Create a lightweight FingerprintListener without any D-Bus calls.
|
||||
/// Call `init_async().await` afterwards to connect to fprintd.
|
||||
pub fn new() -> Self {
|
||||
let mut listener = FingerprintListener {
|
||||
FingerprintListener {
|
||||
device_proxy: None,
|
||||
signal_id: None,
|
||||
running: false,
|
||||
failed_attempts: 0,
|
||||
on_success: None,
|
||||
on_failure: None,
|
||||
};
|
||||
listener.init_device();
|
||||
listener
|
||||
}
|
||||
}
|
||||
|
||||
/// Connect to fprintd and get the default device.
|
||||
fn init_device(&mut self) {
|
||||
let manager = match gio::DBusProxy::for_bus_sync(
|
||||
/// Connect to fprintd and get the default device asynchronously.
|
||||
pub async fn init_async(&mut self) {
|
||||
let manager = match gio::DBusProxy::for_bus_future(
|
||||
gio::BusType::System,
|
||||
gio::DBusProxyFlags::NONE,
|
||||
None,
|
||||
FPRINTD_BUS_NAME,
|
||||
FPRINTD_MANAGER_PATH,
|
||||
FPRINTD_MANAGER_IFACE,
|
||||
gio::Cancellable::NONE,
|
||||
) {
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
log::debug!("fprintd manager not available: {e}");
|
||||
@@ -66,13 +65,10 @@ impl FingerprintListener {
|
||||
};
|
||||
|
||||
// Call GetDefaultDevice
|
||||
let result = match manager.call_sync(
|
||||
"GetDefaultDevice",
|
||||
None,
|
||||
gio::DBusCallFlags::NONE,
|
||||
-1,
|
||||
gio::Cancellable::NONE,
|
||||
) {
|
||||
let result = match manager
|
||||
.call_future("GetDefaultDevice", None, gio::DBusCallFlags::NONE, -1)
|
||||
.await
|
||||
{
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
log::debug!("fprintd GetDefaultDevice failed: {e}");
|
||||
@@ -86,15 +82,16 @@ impl FingerprintListener {
|
||||
return;
|
||||
}
|
||||
|
||||
match gio::DBusProxy::for_bus_sync(
|
||||
match gio::DBusProxy::for_bus_future(
|
||||
gio::BusType::System,
|
||||
gio::DBusProxyFlags::NONE,
|
||||
None,
|
||||
FPRINTD_BUS_NAME,
|
||||
&device_path,
|
||||
FPRINTD_DEVICE_IFACE,
|
||||
gio::Cancellable::NONE,
|
||||
) {
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(proxy) => {
|
||||
self.device_proxy = Some(proxy);
|
||||
}
|
||||
@@ -104,21 +101,18 @@ impl FingerprintListener {
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if fprintd is available and the user has enrolled fingerprints.
|
||||
pub fn is_available(&self, username: &str) -> bool {
|
||||
/// Check if fprintd is available and the user has enrolled fingerprints (async).
|
||||
pub async fn is_available_async(&self, username: &str) -> bool {
|
||||
let proxy = match &self.device_proxy {
|
||||
Some(p) => p,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
let args = glib::Variant::from((&username,));
|
||||
match proxy.call_sync(
|
||||
"ListEnrolledFingers",
|
||||
Some(&args),
|
||||
gio::DBusCallFlags::NONE,
|
||||
-1,
|
||||
gio::Cancellable::NONE,
|
||||
) {
|
||||
match proxy
|
||||
.call_future("ListEnrolledFingers", Some(&args), gio::DBusCallFlags::NONE, -1)
|
||||
.await
|
||||
{
|
||||
Ok(result) => {
|
||||
// Result is a tuple of (array of strings)
|
||||
let fingers: Vec<String> = result.child_get::<Vec<String>>(0);
|
||||
@@ -129,9 +123,10 @@ impl FingerprintListener {
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// 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>>,
|
||||
username: &str,
|
||||
on_success: F,
|
||||
@@ -156,34 +151,24 @@ impl FingerprintListener {
|
||||
|
||||
// Claim the device
|
||||
let args = glib::Variant::from((&username,));
|
||||
if let Err(e) = proxy.call_sync(
|
||||
"Claim",
|
||||
Some(&args),
|
||||
gio::DBusCallFlags::NONE,
|
||||
-1,
|
||||
gio::Cancellable::NONE,
|
||||
) {
|
||||
if let Err(e) = proxy
|
||||
.call_future("Claim", Some(&args), gio::DBusCallFlags::NONE, -1)
|
||||
.await
|
||||
{
|
||||
log::error!("Failed to claim fingerprint device: {e}");
|
||||
return;
|
||||
}
|
||||
|
||||
// Start verification
|
||||
let start_args = glib::Variant::from((&"any",));
|
||||
if let Err(e) = proxy.call_sync(
|
||||
"VerifyStart",
|
||||
Some(&start_args),
|
||||
gio::DBusCallFlags::NONE,
|
||||
-1,
|
||||
gio::Cancellable::NONE,
|
||||
) {
|
||||
if let Err(e) = proxy
|
||||
.call_future("VerifyStart", Some(&start_args), gio::DBusCallFlags::NONE, -1)
|
||||
.await
|
||||
{
|
||||
log::error!("Failed to start fingerprint verification: {e}");
|
||||
let _ = proxy.call_sync(
|
||||
"Release",
|
||||
None,
|
||||
gio::DBusCallFlags::NONE,
|
||||
-1,
|
||||
gio::Cancellable::NONE,
|
||||
);
|
||||
let _ = proxy
|
||||
.call_future("Release", None, gio::DBusCallFlags::NONE, -1)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user