diff --git a/cosmic-config/src/lib.rs b/cosmic-config/src/lib.rs index 1a3ec66a..e408eac5 100644 --- a/cosmic-config/src/lib.rs +++ b/cosmic-config/src/lib.rs @@ -10,7 +10,6 @@ use std::{ io::Write, path::{Path, PathBuf}, sync::Mutex, - time::Duration, }; #[cfg(feature = "subscription")] diff --git a/src/app/cosmic.rs b/src/app/cosmic.rs index 3a75871d..a2cdeb87 100644 --- a/src/app/cosmic.rs +++ b/src/app/cosmic.rs @@ -17,6 +17,8 @@ use iced::Application as IcedApplication; use iced::event::wayland; use iced::{Task, window}; use iced_futures::event::listen_with; +#[cfg(feature = "wayland")] +use iced_winit::SurfaceIdWrapper; use palette::color_difference::EuclideanDistance; #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] @@ -84,7 +86,11 @@ pub struct Cosmic { #[cfg(feature = "wayland")] pub surface_views: HashMap< window::Id, - Box Fn(&'a App) -> Element<'a, crate::Action>>, + ( + Option, + SurfaceIdWrapper, + Box Fn(&'a App) -> Element<'a, crate::Action>>, + ), >, } @@ -449,7 +455,7 @@ where #[cfg(feature = "multi-window")] pub fn view(&self, id: window::Id) -> Element> { #[cfg(feature = "wayland")] - if let Some(v) = self.surface_views.get(&id) { + if let Some((_, _, v)) = self.surface_views.get(&id) { return v(&self.app); } if self @@ -841,13 +847,45 @@ impl Cosmic { } Action::Focus(f) => { - self.app.core_mut().focused_window = Some(f); + #[cfg(all( + feature = "wayland", + feature = "multi-window", + feature = "surface-message" + ))] + if let Some(( + parent, + SurfaceIdWrapper::Subsurface(_) | SurfaceIdWrapper::Popup(_), + _, + )) = self.surface_views.get(&f) + { + // If the parent is already focused, push the new focus + // to the end of the focus chain. + if parent.is_some_and(|p| self.app.core().focused_window.last() == Some(&p)) { + self.app.core_mut().focused_window.push(f); + return iced::Task::none(); + } else { + // set the whole parent chain to the focus chain + let mut parent_chain = vec![f]; + let mut cur = *parent; + while let Some(p) = cur { + parent_chain.push(p); + cur = self + .surface_views + .get(&p) + .and_then(|(parent, _, _)| *parent); + } + parent_chain.reverse(); + self.app.core_mut().focused_window = parent_chain; + return iced::Task::none(); + } + } + self.app.core_mut().focused_window = vec![f]; } Action::Unfocus(id) => { let core = self.app.core_mut(); - if core.focused_window.as_ref().is_some_and(|cur| *cur == id) { - core.focused_window = None; + if core.focused_window().as_ref().is_some_and(|cur| *cur == id) { + core.focused_window.pop(); } } #[cfg(feature = "applet")] @@ -886,7 +924,14 @@ impl Cosmic { ) -> Task> { use iced_winit::commands::subsurface::get_subsurface; - self.surface_views.insert(settings.id, view); + self.surface_views.insert( + settings.id, + ( + Some(settings.parent), + SurfaceIdWrapper::Subsurface(settings.id), + view, + ), + ); get_subsurface(settings) } @@ -901,7 +946,14 @@ impl Cosmic { ) -> Task> { use iced_winit::commands::popup::get_popup; - self.surface_views.insert(settings.id, view); + self.surface_views.insert( + settings.id, + ( + Some(settings.parent), + SurfaceIdWrapper::Popup(settings.id), + view, + ), + ); get_popup(settings) } } diff --git a/src/app/mod.rs b/src/app/mod.rs index 890a3429..35b55f02 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -548,8 +548,9 @@ impl ApplicationExt for App { let show_context = core.window.show_context; let nav_bar_active = core.nav_bar_active(); let focused = core - .focused_window() - .is_some_and(|i| Some(i) == self.core().main_window_id()); + .focus_chain() + .iter() + .any(|i| Some(*i) == self.core().main_window_id()); let border_padding = if sharp_corners { 8 } else { 7 }; diff --git a/src/core.rs b/src/core.rs index 744b33b7..4b9811ec 100644 --- a/src/core.rs +++ b/src/core.rs @@ -64,7 +64,7 @@ pub struct Core { scale_factor: f32, /// Window focus state - pub(super) focused_window: Option, + pub(super) focused_window: Vec, pub(super) theme_sub_counter: u64, /// Last known system theme @@ -141,7 +141,7 @@ impl Default for Core { height: 0., width: 0., }, - focused_window: None, + focused_window: Vec::new(), #[cfg(feature = "applet")] applet: crate::applet::Context::default(), #[cfg(feature = "single-instance")] @@ -384,8 +384,15 @@ impl Core { /// Get the current focused window if it exists #[must_use] #[inline] - pub const fn focused_window(&self) -> Option { - self.focused_window + pub fn focused_window(&self) -> Option { + self.focused_window.last().copied() + } + + /// Get the current focus chain of windows + #[must_use] + #[inline] + pub fn focus_chain(&self) -> &[window::Id] { + &self.focused_window } /// Whether the application should use a dark theme, according to the system