Filter window events by window id, fixes #1118

This commit is contained in:
Jeremy Soller 2025-08-15 09:23:29 -06:00
parent 30a0836018
commit 5e0645d1c2
No known key found for this signature in database
GPG key ID: 670FDFB5428E05CA

View file

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