diff --git a/Cargo.lock b/Cargo.lock index 88d3241..72b61b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -905,7 +905,7 @@ dependencies = [ [[package]] name = "cosmic-config" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#6b7fa3d4767bbf21b39d07b3bdba4a49e6375dd1" +source = "git+https://github.com/pop-os/libcosmic#0dca2e046887922563236f0b22b55313efc80319" dependencies = [ "atomicwrites", "calloop", @@ -923,7 +923,7 @@ dependencies = [ [[package]] name = "cosmic-config-derive" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#6b7fa3d4767bbf21b39d07b3bdba4a49e6375dd1" +source = "git+https://github.com/pop-os/libcosmic#0dca2e046887922563236f0b22b55313efc80319" dependencies = [ "quote", "syn 1.0.109", @@ -1026,7 +1026,7 @@ dependencies = [ [[package]] name = "cosmic-theme" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#6b7fa3d4767bbf21b39d07b3bdba4a49e6375dd1" +source = "git+https://github.com/pop-os/libcosmic#0dca2e046887922563236f0b22b55313efc80319" dependencies = [ "almost", "cosmic-config", @@ -2247,7 +2247,7 @@ dependencies = [ [[package]] name = "iced" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#6b7fa3d4767bbf21b39d07b3bdba4a49e6375dd1" +source = "git+https://github.com/pop-os/libcosmic#0dca2e046887922563236f0b22b55313efc80319" dependencies = [ "dnd", "iced_accessibility", @@ -2265,7 +2265,7 @@ dependencies = [ [[package]] name = "iced_accessibility" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#6b7fa3d4767bbf21b39d07b3bdba4a49e6375dd1" +source = "git+https://github.com/pop-os/libcosmic#0dca2e046887922563236f0b22b55313efc80319" dependencies = [ "accesskit", "accesskit_unix", @@ -2274,7 +2274,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#6b7fa3d4767bbf21b39d07b3bdba4a49e6375dd1" +source = "git+https://github.com/pop-os/libcosmic#0dca2e046887922563236f0b22b55313efc80319" dependencies = [ "bitflags 1.3.2", "dnd", @@ -2296,7 +2296,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#6b7fa3d4767bbf21b39d07b3bdba4a49e6375dd1" +source = "git+https://github.com/pop-os/libcosmic#0dca2e046887922563236f0b22b55313efc80319" dependencies = [ "futures", "iced_core", @@ -2309,7 +2309,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#6b7fa3d4767bbf21b39d07b3bdba4a49e6375dd1" +source = "git+https://github.com/pop-os/libcosmic#0dca2e046887922563236f0b22b55313efc80319" dependencies = [ "bitflags 1.3.2", "bytemuck", @@ -2333,7 +2333,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#6b7fa3d4767bbf21b39d07b3bdba4a49e6375dd1" +source = "git+https://github.com/pop-os/libcosmic#0dca2e046887922563236f0b22b55313efc80319" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -2345,7 +2345,7 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#6b7fa3d4767bbf21b39d07b3bdba4a49e6375dd1" +source = "git+https://github.com/pop-os/libcosmic#0dca2e046887922563236f0b22b55313efc80319" dependencies = [ "dnd", "iced_accessibility", @@ -2359,7 +2359,7 @@ dependencies = [ [[package]] name = "iced_sctk" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#6b7fa3d4767bbf21b39d07b3bdba4a49e6375dd1" +source = "git+https://github.com/pop-os/libcosmic#0dca2e046887922563236f0b22b55313efc80319" dependencies = [ "enum-repr", "float-cmp", @@ -2385,7 +2385,7 @@ dependencies = [ [[package]] name = "iced_style" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#6b7fa3d4767bbf21b39d07b3bdba4a49e6375dd1" +source = "git+https://github.com/pop-os/libcosmic#0dca2e046887922563236f0b22b55313efc80319" dependencies = [ "iced_core", "once_cell", @@ -2395,7 +2395,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#6b7fa3d4767bbf21b39d07b3bdba4a49e6375dd1" +source = "git+https://github.com/pop-os/libcosmic#0dca2e046887922563236f0b22b55313efc80319" dependencies = [ "bytemuck", "cosmic-text", @@ -2412,7 +2412,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#6b7fa3d4767bbf21b39d07b3bdba4a49e6375dd1" +source = "git+https://github.com/pop-os/libcosmic#0dca2e046887922563236f0b22b55313efc80319" dependencies = [ "bitflags 1.3.2", "bytemuck", @@ -2431,7 +2431,7 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#6b7fa3d4767bbf21b39d07b3bdba4a49e6375dd1" +source = "git+https://github.com/pop-os/libcosmic#0dca2e046887922563236f0b22b55313efc80319" dependencies = [ "dnd", "iced_renderer", @@ -2676,7 +2676,7 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libcosmic" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#6b7fa3d4767bbf21b39d07b3bdba4a49e6375dd1" +source = "git+https://github.com/pop-os/libcosmic#0dca2e046887922563236f0b22b55313efc80319" dependencies = [ "apply", "ashpd 0.7.0", diff --git a/src/locker.rs b/src/locker.rs index eba25e9..8297317 100644 --- a/src/locker.rs +++ b/src/locker.rs @@ -195,20 +195,29 @@ pub enum Message { SessionLockEvent(SessionLockEvent), Channel(mpsc::Sender), BackgroundState(cosmic_bg_config::state::State), - LogindLock, NetworkIcon(Option<&'static str>), PowerInfo(Option<(String, f64)>), Prompt(String, bool, Option), Submit, Suspend, Error(String), + Lock, Unlock, } +#[derive(Clone, Debug)] +enum State { + Locking, + Locked, + Unlocking, + Unlocked, +} + /// The [`App`] stores application-specific state. pub struct App { core: Core, flags: Flags, + state: State, surface_ids: HashMap, active_surface_id_opt: Option, surface_images: HashMap, @@ -303,6 +312,7 @@ impl cosmic::Application for App { App { core, flags, + state: State::Unlocked, surface_ids: HashMap::new(), active_surface_id_opt: None, surface_images: HashMap::new(), @@ -314,7 +324,13 @@ impl cosmic::Application for App { prompt_opt: None, error_opt: None, }, - lock(), + if cfg!(feature = "logind") { + // When logind feature is used, wait for lock signal + Command::none() + } else { + // When logind feature not used, lock immediately + lock() + }, ) } @@ -360,10 +376,12 @@ impl cosmic::Application for App { self.text_input_ids .insert(surface_id, text_input_id.clone()); - return Command::batch([ - get_lock_surface(surface_id, output), - widget::text_input::focus(text_input_id), - ]); + if matches!(self.state, State::Locked) { + return Command::batch([ + get_lock_surface(surface_id, output), + widget::text_input::focus(text_input_id), + ]); + } } OutputEvent::Removed => { log::info!("output {}: removed", output.id()); @@ -372,15 +390,17 @@ impl cosmic::Application for App { self.surface_images.remove(&surface_id); self.surface_names.remove(&surface_id); self.text_input_ids.remove(&surface_id); - return destroy_lock_surface(surface_id); + if matches!(self.state, State::Locked) { + return destroy_lock_surface(surface_id); + } } None => { log::warn!("output {}: no surface found", output.id()); } } } - OutputEvent::InfoUpdate(output_info) => { - log::info!("output {}: info update {:#?}", output.id(), output_info); + OutputEvent::InfoUpdate(_output_info) => { + log::info!("output {}: info update", output.id()); } } } @@ -392,10 +412,27 @@ impl cosmic::Application for App { return widget::text_input::focus(text_input_id.clone()); } } - SessionLockEvent::Unlocked => { - //TODO: cleaner method to exit? - process::exit(0); + SessionLockEvent::Locked => { + log::info!("session locked"); + self.state = State::Locked; + let mut commands = Vec::with_capacity(self.surface_ids.len()); + for (output, surface_id) in self.surface_ids.iter() { + commands.push(get_lock_surface(*surface_id, output.clone())); + } + return Command::batch(commands); } + SessionLockEvent::Unlocked => { + log::info!("session unlocked"); + self.state = State::Unlocked; + if cfg!(feature = "logind") { + // When using logind feature, stick around for more lock signals + } else { + // When not using logind feature, exit immediately after unlocking + //TODO: cleaner method to exit? + process::exit(0); + } + } + //TODO: handle finished signal _ => {} }, Message::Channel(value_tx) => { @@ -406,9 +443,6 @@ impl cosmic::Application for App { self.surface_images.clear(); self.update_wallpapers(); } - Message::LogindLock => { - log::warn!("TODO: LogindLock"); - } Message::NetworkIcon(network_icon_opt) => { self.network_icon_opt = network_icon_opt; } @@ -430,6 +464,8 @@ impl cosmic::Application for App { Some((_prompt, _secret, value_opt)) => match value_opt { Some(value) => match self.value_tx_opt.take() { Some(value_tx) => { + // Clear errors + self.error_opt = None; return Command::perform( async move { value_tx.send(value).await.unwrap(); @@ -462,17 +498,47 @@ impl cosmic::Application for App { Message::Error(error) => { self.error_opt = Some(error); } - Message::Unlock => { - let mut commands = Vec::new(); - for (_output, surface_id) in self.surface_ids.drain() { - self.surface_images.remove(&surface_id); - self.surface_names.remove(&surface_id); - self.text_input_ids.remove(&surface_id); - commands.push(destroy_lock_surface(surface_id)); + Message::Lock => match self.state { + State::Unlocked => { + log::info!("session locking"); + self.state = State::Locking; + // Clear errors + self.error_opt = None; + // Clear value_tx + self.value_tx_opt = None; + return lock(); + } + State::Unlocking => { + log::info!("session still unlocking"); + } + State::Locking | State::Locked => { + log::info!("session already locking or locked"); + } + }, + Message::Unlock => { + match self.state { + State::Locked => { + log::info!("sessing unlocking"); + self.state = State::Unlocking; + // Clear errors + self.error_opt = None; + // Clear value_tx + self.value_tx_opt = None; + let mut commands = Vec::with_capacity(self.surface_ids.len() + 1); + for (_output, surface_id) in self.surface_ids.iter() { + commands.push(destroy_lock_surface(*surface_id)); + } + commands.push(unlock()); + // Wait to exit until `Unlocked` event, when server has processed unlock + return Command::batch(commands); + } + State::Locking => { + log::info!("session still locking"); + } + State::Unlocking | State::Unlocked => { + log::info!("session already unlocking or unlocked"); + } } - commands.push(unlock()); - // Wait to exit until `Unlocked` event, when server has processed unlock - return Command::batch(commands); } } Command::none() @@ -659,53 +725,23 @@ impl cosmic::Application for App { } fn subscription(&self) -> Subscription { - struct BackgroundSubscription; - struct HeartbeatSubscription; - struct PamSubscription; + let mut subscriptions = Vec::with_capacity(7); - //TODO: just use one vec for all subscriptions - let mut extra_subscriptions = Vec::with_capacity(3); - - #[cfg(feature = "logind")] - { - extra_subscriptions.push(crate::logind::subscription().map(|lock| { - if lock { - Message::LogindLock - } else { - Message::Unlock + subscriptions.push(event::listen_with(|event, _| match event { + iced::Event::PlatformSpecific(iced::event::PlatformSpecific::Wayland( + wayland_event, + )) => match wayland_event { + WaylandEvent::Output(output_event, output) => { + Some(Message::OutputEvent(output_event, output)) } - })); - } - - #[cfg(feature = "networkmanager")] - { - extra_subscriptions.push( - crate::networkmanager::subscription() - .map(|icon_opt| Message::NetworkIcon(icon_opt)), - ); - } - - #[cfg(feature = "upower")] - { - extra_subscriptions - .push(crate::upower::subscription().map(|info_opt| Message::PowerInfo(info_opt))); - } - - //TODO: how to avoid cloning this on every time subscription is called? - let username = self.flags.current_user.name.clone(); - Subscription::batch([ - event::listen_with(|event, _| match event { - iced::Event::PlatformSpecific(iced::event::PlatformSpecific::Wayland( - wayland_event, - )) => match wayland_event { - WaylandEvent::Output(output_event, output) => { - Some(Message::OutputEvent(output_event, output)) - } - WaylandEvent::SessionLock(evt) => Some(Message::SessionLockEvent(evt)), - _ => None, - }, + WaylandEvent::SessionLock(evt) => Some(Message::SessionLockEvent(evt)), _ => None, - }), + }, + _ => None, + })); + + struct BackgroundSubscription; + subscriptions.push( cosmic_config::config_state_subscription( TypeId::of::(), cosmic_bg_config::NAME.into(), @@ -717,7 +753,11 @@ impl cosmic::Application for App { } Message::BackgroundState(res.config) }), - subscription::channel( + ); + + if matches!(self.state, State::Locked) { + struct HeartbeatSubscription; + subscriptions.push(subscription::channel( TypeId::of::(), 16, |mut msg_tx| async move { @@ -728,8 +768,12 @@ impl cosmic::Application for App { time::sleep(time::Duration::new(1, 0)).await; } }, - ), - subscription::channel( + )); + + struct PamSubscription; + //TODO: how to avoid cloning this on every time subscription is called? + let username = self.flags.current_user.name.clone(); + subscriptions.push(subscription::channel( TypeId::of::(), 16, |mut msg_tx| async move { @@ -764,8 +808,34 @@ impl cosmic::Application for App { time::sleep(time::Duration::new(60, 0)).await; } }, - ), - Subscription::batch(extra_subscriptions), - ]) + )); + } + + #[cfg(feature = "logind")] + { + subscriptions.push(crate::logind::subscription().map(|lock| { + if lock { + Message::Lock + } else { + Message::Unlock + } + })); + } + + #[cfg(feature = "networkmanager")] + { + subscriptions.push( + crate::networkmanager::subscription() + .map(|icon_opt| Message::NetworkIcon(icon_opt)), + ); + } + + #[cfg(feature = "upower")] + { + subscriptions + .push(crate::upower::subscription().map(|info_opt| Message::PowerInfo(info_opt))); + } + + Subscription::batch(subscriptions) } }