From 5e0645d1c2223916397b8aa99b4e9a27e6b82d7f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 15 Aug 2025 09:23:29 -0600 Subject: [PATCH] Filter window events by window id, fixes #1118 --- src/app.rs | 157 ++++++++++++++++++++++++++--------------------------- 1 file changed, 78 insertions(+), 79 deletions(-) diff --git a/src/app.rs b/src/app.rs index b405eea..d4150d6 100644 --- a/src/app.rs +++ b/src/app.rs @@ -325,10 +325,10 @@ pub enum Message { ExtractToResult(DialogResult), #[cfg(all(feature = "wayland", feature = "desktop-applet"))] Focused(window::Id), - Key(Modifiers, Key, Option), + Key(window::Id, Modifiers, Key, Option), LaunchUrl(String), MaybeExit, - ModifiersChanged(Modifiers), + ModifiersChanged(window::Id, Modifiers), MounterItems(MounterKey, MounterItems), MountResult(MounterKey, MounterItem, Result), NavBarClose(Entity), @@ -357,7 +357,7 @@ pub enum Message { OpenWithDialog(Option), OpenWithSelection(usize), #[cfg(all(feature = "wayland", feature = "desktop-applet"))] - Overlap(OverlapNotifyEvent, window::Id), + Overlap(window::Id, OverlapNotifyEvent), Paste(Option), PasteContents(PathBuf, ClipboardPaste), PendingCancel(u64), @@ -383,7 +383,7 @@ pub enum Message { SetShowDetails(bool), SetTypeToSearch(TypeToSearch), SystemThemeModeChange, - Size(Size), + Size(window::Id, Size), TabActivate(Entity), TabNext, TabPrev, @@ -410,7 +410,6 @@ pub enum Message { WindowCloseRequested(window::Id), WindowMaximize(window::Id, bool), WindowNew, - WindowUnfocus, ZoomDefault(Option), ZoomIn(Option), ZoomOut(Option), @@ -673,7 +672,6 @@ pub struct App { surface_names: HashMap, toasts: widget::toaster::Toasts, watcher_opt: Option<(Debouncer, HashSet)>, - pub(crate) window_id_opt: Option, windows: HashMap, nav_dnd_hover: Option<(Location, Instant)>, tab_dnd_hover: Option<(Entity, Instant)>, @@ -1553,8 +1551,8 @@ impl App { Some(tab_title) => format!("{tab_title} — {}", fl!("cosmic-files")), None => fl!("cosmic-files"), }; - if let Some(window_id) = &self.window_id_opt { - self.set_window_title(window_title, *window_id) + if let Some(window_id) = self.core.main_window_id() { + self.set_window_title(window_title, window_id) } else { Task::none() } @@ -2099,8 +2097,6 @@ impl Application for App { Mode::Desktop => tab::Mode::Desktop, }); - let window_id_opt = core.main_window_id(); - // Create a dedicated thread for the compio runtime to handle operations on. // Supports io_uring on Linux, IOPC on Windows, and polling everywhere else. let (compio_tx, mut compio_rx) = mpsc::channel(1); @@ -2156,7 +2152,6 @@ impl Application for App { surface_names: HashMap::new(), toasts: widget::toaster::Toasts::new(Message::CloseToast), watcher_opt: None, - window_id_opt, windows: HashMap::new(), nav_dnd_hover: None, tab_dnd_hover: None, @@ -2207,7 +2202,7 @@ impl Application for App { } fn nav_bar(&self) -> Option>> { - if !self.core().nav_bar_active() { + if !self.core.nav_bar_active() { return None; } @@ -2235,7 +2230,7 @@ impl Application for App { ) .into_container(); - if !self.core().is_condensed() { + if !self.core.is_condensed() { nav = nav.max_width(280); } @@ -2942,40 +2937,46 @@ impl Application for App { return dialog.update(dialog_message); } } - Message::Key(modifiers, key, text) => { - let entity = self.tab_model.active(); - for (key_bind, action) in self.key_binds.iter() { - if key_bind.matches(modifiers, &key) { - return self.update(action.message(Some(entity))); + Message::Key(window_id, modifiers, key, text) => { + if self.core.main_window_id() == Some(window_id) { + let entity = self.tab_model.active(); + for (key_bind, action) in self.key_binds.iter() { + if key_bind.matches(modifiers, &key) { + return self.update(action.message(Some(entity))); + } } - } - // Uncaptured keys with only shift modifiers go to the search or location box - if !modifiers.logo() - && !modifiers.control() - && !modifiers.alt() - && matches!(key, Key::Character(_)) - { - if let Some(text) = text { - match self.config.type_to_search { - TypeToSearch::Recursive => { - let mut term = self.search_get().unwrap_or_default().to_string(); - term.push_str(&text); - return self.search_set_active(Some(term)); - } - TypeToSearch::EnterPath => { - if let Some(tab) = self.tab_model.data_mut::(entity) { - let location = tab.edit_location.as_ref().map_or_else( - || tab.location.clone(), - |x| x.location.clone(), - ); - // Try to add text to end of location - if let Some(path) = location.path_opt() { - let mut path_string = path.to_string_lossy().to_string(); - path_string.push_str(&text); - tab.edit_location = Some( - location.with_path(PathBuf::from(path_string)).into(), + // Uncaptured keys with only shift modifiers go to the search or location box + if !modifiers.logo() + && !modifiers.control() + && !modifiers.alt() + && matches!(key, Key::Character(_)) + { + if let Some(text) = text { + match self.config.type_to_search { + TypeToSearch::Recursive => { + let mut term = + self.search_get().unwrap_or_default().to_string(); + term.push_str(&text); + return self.search_set_active(Some(term)); + } + TypeToSearch::EnterPath => { + if let Some(tab) = self.tab_model.data_mut::(entity) { + let location = tab.edit_location.as_ref().map_or_else( + || tab.location.clone(), + |x| x.location.clone(), ); + // Try to add text to end of location + if let Some(path) = location.path_opt() { + let mut path_string = + path.to_string_lossy().to_string(); + path_string.push_str(&text); + tab.edit_location = Some( + location + .with_path(PathBuf::from(path_string)) + .into(), + ); + } } } } @@ -2984,7 +2985,7 @@ impl Application for App { } } Message::MaybeExit => { - if self.window_id_opt.is_none() && self.pending_operations.is_empty() { + if self.core.main_window_id().is_none() && self.pending_operations.is_empty() { // Exit if window is closed and there are no pending operations process::exit(0); } @@ -2995,13 +2996,15 @@ impl Application for App { log::warn!("failed to open {:?}: {}", url, err); } }, - Message::ModifiersChanged(modifiers) => { - self.modifiers = modifiers; - let entity = self.tab_model.active(); - return self.update(Message::TabMessage( - Some(entity), - tab::Message::ModifiersChanged(modifiers), - )); + Message::ModifiersChanged(window_id, modifiers) => { + if self.core.main_window_id() == Some(window_id) { + self.modifiers = modifiers; + let entity = self.tab_model.active(); + return self.update(Message::TabMessage( + Some(entity), + tab::Message::ModifiersChanged(modifiers), + )); + } } Message::MounterItems(mounter_key, mounter_items) => { // Check for unmounted folders @@ -3802,8 +3805,8 @@ impl Application for App { // If that was the last tab, close window if self.tab_model.iter().next().is_none() { - if let Some(window_id) = &self.window_id_opt { - return window::close(*window_id); + if let Some(window_id) = self.core.main_window_id() { + return window::close(window_id); } } @@ -3914,7 +3917,8 @@ impl Application for App { }; SctkPopupSettings { parent: parent_id.unwrap_or( - app.window_id_opt + app.core + .main_window_id() .unwrap_or_else(|| WindowId::NONE), ), id: window_id, @@ -4002,13 +4006,13 @@ impl Application for App { commands.push(self.operation(Operation::SetPermissions { path, mode })); } tab::Command::WindowDrag => { - if let Some(window_id) = &self.window_id_opt { - commands.push(window::drag(*window_id)); + if let Some(window_id) = self.core.main_window_id() { + commands.push(window::drag(window_id)); } } tab::Command::WindowToggleMaximize => { - if let Some(window_id) = &self.window_id_opt { - commands.push(window::toggle_maximize(*window_id)); + if let Some(window_id) = self.core.main_window_id() { + commands.push(window::toggle_maximize(window_id)); } } tab::Command::SetSort(location, heading_options, direction) => { @@ -4168,7 +4172,8 @@ impl Application for App { return self.operation(Operation::Restore { items }); } Message::WindowClose => { - if let Some(window_id) = self.window_id_opt.take() { + if let Some(window_id) = self.core.main_window_id() { + self.core.set_main_window_id(None); return Task::batch([ window::close(window_id), Task::perform( @@ -4178,14 +4183,6 @@ impl Application for App { ]); } } - Message::WindowUnfocus => { - /*TODO - let tab_entity = self.tab_model.active(); - if let Some(tab) = self.tab_model.data_mut::(tab_entity) { - tab.context_menu = None; - } - */ - } Message::WindowCloseRequested(id) => { self.remove_window(&id); } @@ -4621,7 +4618,7 @@ impl Application for App { } Message::None => {} #[cfg(all(feature = "wayland", feature = "desktop-applet"))] - Message::Overlap(overlap_notify_event, w_id) => match overlap_notify_event { + Message::Overlap(w_id, overlap_notify_event) => match overlap_notify_event { OverlapNotifyEvent::OverlapLayerAdd { identifier, namespace, @@ -4640,9 +4637,11 @@ impl Application for App { } _ => {} }, - Message::Size(size) => { - self.size = Some(size); - self.handle_overlap(); + Message::Size(window_id, size) => { + if self.core.main_window_id() == Some(window_id) { + self.size = Some(size); + self.handle_overlap(); + } } Message::Eject => { #[cfg(feature = "gvfs")] @@ -5818,6 +5817,7 @@ impl Application for App { struct RecentsWatcherSubscription; let mut subscriptions = vec![ + //TODO: filter more events by window id event::listen_with(|event, status, window_id| match event { Event::Keyboard(KeyEvent::KeyPressed { key, @@ -5825,20 +5825,19 @@ impl Application for App { text, .. }) => match status { - event::Status::Ignored => Some(Message::Key(modifiers, key, text)), + event::Status::Ignored => Some(Message::Key(window_id, modifiers, key, text)), event::Status::Captured => None, }, Event::Keyboard(KeyEvent::ModifiersChanged(modifiers)) => { - Some(Message::ModifiersChanged(modifiers)) + Some(Message::ModifiersChanged(window_id, modifiers)) } - Event::Window(WindowEvent::Unfocused) => Some(Message::WindowUnfocus), #[cfg(all(feature = "wayland", feature = "desktop-applet"))] Event::Window(WindowEvent::Focused) => Some(Message::Focused(window_id)), Event::Window(WindowEvent::CloseRequested) => Some(Message::WindowClose), Event::Window(WindowEvent::Opened { position: _, size }) => { - Some(Message::Size(size)) + Some(Message::Size(window_id, size)) } - Event::Window(WindowEvent::Resized(s)) => Some(Message::Size(s)), + Event::Window(WindowEvent::Resized(s)) => Some(Message::Size(window_id, s)), #[cfg(all(feature = "wayland", feature = "desktop-applet"))] Event::PlatformSpecific(event::PlatformSpecific::Wayland(wayland_event)) => { match wayland_event { @@ -5847,7 +5846,7 @@ impl Application for App { } #[cfg(feature = "desktop")] WaylandEvent::OverlapNotify(event) => { - Some(Message::Overlap(event, window_id)) + Some(Message::Overlap(window_id, event)) } _ => None, } @@ -6125,7 +6124,7 @@ impl Application for App { if !self.pending_operations.is_empty() { //TODO: inhibit suspend/shutdown? - if self.window_id_opt.is_some() { + if self.core.main_window_id().is_some() { // Force refresh the UI every 100ms while an operation is active. if self .pending_operations