From 8ced50639e89b0005a91a2bf942a693aedb0265f Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Wed, 4 Dec 2024 21:23:45 -0500 Subject: [PATCH] refactor: reactivate windows after a user switches outputs. Alt tab relies on changes to the activated state, but if there is a single window on each output, they are always activated. This forces activation state changes so that the events are sent to indicate the focus change. --- Cargo.toml | 60 +++++++++++++-------- src/input/actions.rs | 3 ++ src/input/mod.rs | 1 + src/shell/focus/mod.rs | 23 ++++++-- src/shell/mod.rs | 22 +++++++- src/wayland/handlers/toplevel_management.rs | 13 ++++- 6 files changed, 94 insertions(+), 28 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6b8e669d..4aebe422 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,49 +6,65 @@ name = "cosmic-comp" version = "0.1.0" [workspace] -members = [ - "cosmic-comp-config", -] +members = ["cosmic-comp-config"] [dependencies] -anyhow = {version = "1.0.51", features = ["backtrace"]} +anyhow = { version = "1.0.51", features = ["backtrace"] } bitflags = "2.4" bytemuck = "1.12" -calloop = {version = "0.14.1", features = ["executor"]} -cosmic-comp-config = {path = "cosmic-comp-config"} -cosmic-config = {git = "https://github.com/pop-os/libcosmic/", features = ["calloop", "macro"]} -cosmic-protocols = {git = "https://github.com/pop-os/cosmic-protocols", branch = "main", default-features = false, features = ["server"]} +calloop = { version = "0.14.1", features = ["executor"] } +cosmic-comp-config = { path = "cosmic-comp-config" } +cosmic-config = { git = "https://github.com/pop-os/libcosmic/", features = [ + "calloop", + "macro", +] } +cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", branch = "main", default-features = false, features = [ + "server", +] } cosmic-settings-config = { git = "https://github.com/pop-os/cosmic-settings-daemon" } -edid-rs = {version = "0.1"} -egui = {version = "0.29.0", optional = true} -egui_plot = {version = "0.29.0", optional = true} +edid-rs = { version = "0.1" } +egui = { version = "0.29.0", optional = true } +egui_plot = { version = "0.29.0", optional = true } glow = "0.12.0" -i18n-embed = {version = "0.14", features = ["fluent-system", "desktop-requester"]} +i18n-embed = { version = "0.14", features = [ + "fluent-system", + "desktop-requester", +] } i18n-embed-fl = "0.8" -iced_tiny_skia = {git = "https://github.com/pop-os/libcosmic/"} +iced_tiny_skia = { git = "https://github.com/pop-os/libcosmic/" } indexmap = "2.0" keyframe = "1.1.1" lazy_static = "1.4.0" libc = "0.2.149" -libcosmic = {git = "https://github.com/pop-os/libcosmic/", default-features = false} -libsystemd = {version = "0.7", optional = true} -log-panics = {version = "2", features = ["with-backtrace"]} +libcosmic = { git = "https://github.com/pop-os/libcosmic/", default-features = false } +libsystemd = { version = "0.7", optional = true } +log-panics = { version = "2", features = ["with-backtrace"] } once_cell = "1.18.0" ordered-float = "4.0" png = "0.17.5" regex = "1" ron = "0.8" -rust-embed = {version = "8.0", features = ["debug-embed"]} +rust-embed = { version = "8.0", features = ["debug-embed"] } sanitize-filename = "0.5.0" sendfd = "0.4.1" -serde = {version = "1", features = ["derive"]} +serde = { version = "1", features = ["derive"] } serde_json = "1" thiserror = "1.0.26" -time = {version = "0.3.30", features = ["macros", "formatting", "local-offset"]} +time = { version = "0.3.30", features = [ + "macros", + "formatting", + "local-offset", +] } tiny-skia = "0.11" -tracing = { version = "0.1.37", features = ["max_level_debug", "release_max_level_info"] } +tracing = { version = "0.1.37", features = [ + "max_level_debug", + "release_max_level_info", +] } tracing-journald = "0.3.0" -tracing-subscriber = {version = "0.3.16", features = ["env-filter", "tracing-log"]} +tracing-subscriber = { version = "0.3.16", features = [ + "env-filter", + "tracing-log", +] } wayland-backend = "0.3.3" wayland-scanner = "0.31.1" xcursor = "0.3.3" @@ -116,7 +132,7 @@ debug = true inherits = "release" [profile.release] -lto = "fat" +opt-level = 2 [patch."https://github.com/Smithay/smithay.git"] smithay = { git = "https://github.com/smithay//smithay", rev = "bc1d732" } diff --git a/src/input/actions.rs b/src/input/actions.rs index a85cf8a0..17f07e93 100644 --- a/src/input/actions.rs +++ b/src/input/actions.rs @@ -403,6 +403,7 @@ impl State { &mut self.common.workspace_state.update(), ); seat.set_active_output(&next_output); + shell.swapped_output = true; if let Ok(Some(new_pos)) = res { let new_target = shell @@ -490,6 +491,7 @@ impl State { &mut self.common.workspace_state.update(), ); seat.set_active_output(&next_output); + shell.swapped_output = true; if let Ok(Some(new_pos)) = res { let new_target = shell @@ -549,6 +551,7 @@ impl State { &mut self.common.workspace_state.update(), ); seat.set_active_output(&prev_output); + shell.swapped_output = true; if let Ok(Some(new_pos)) = res { let new_target = shell diff --git a/src/input/mod.rs b/src/input/mod.rs index 8b40908e..ee649a86 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -507,6 +507,7 @@ impl State { session.set_cursor_pos(None); } seat.set_active_output(&output); + shell.swapped_output = true; } for session in cursor_sessions_for_output(&shell, &output) { diff --git a/src/shell/focus/mod.rs b/src/shell/focus/mod.rs index 6ab2e857..f6b5c42c 100644 --- a/src/shell/focus/mod.rs +++ b/src/shell/focus/mod.rs @@ -169,6 +169,8 @@ impl Shell { fn update_active(&mut self) { // update activate status + let mut focused_output = None; + let focused_windows = self .seats .iter() @@ -179,6 +181,9 @@ impl Shell { ) { return None; } + focused_output = self + .swapped_output + .then_some(seat.focused_or_active_output()); Some(self.outputs().flat_map(|o| { let space = self.active_space(o); @@ -188,7 +193,7 @@ impl Shell { }) .flatten() .collect::>(); - + self.swapped_output = false; for output in self.outputs().cloned().collect::>().into_iter() { let set = self.workspaces.sets.get_mut(&output).unwrap(); for focused in focused_windows.iter() { @@ -208,7 +213,17 @@ impl Shell { raise_with_children(&mut workspace.floating_layer, focused); } for window in workspace.mapped() { - window.set_activated(focused_windows.contains(&window)); + let focused = focused_windows.contains(&window); + window.set_activated(focused); + + if focused + && window.is_activated(false) + && focused_output.as_ref().is_some_and(|f| *f == output) + { + self.active_window_needs_reset = Some(window.clone()); + window.set_activated(false); + } + window.configure(); } for m in workspace.minimized_windows.iter() { @@ -223,7 +238,7 @@ impl Shell { for window in workspace.mapped() { window.set_activated(false); window.configure(); - } + } } } } @@ -355,6 +370,8 @@ impl Common { if let Some(other) = shell.outputs().next() { seat.set_active_output(other); } + shell.swapped_output = true; + continue; } diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 8e52c73c..17d84547 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -255,6 +255,8 @@ pub struct Shell { )>, resize_indicator: Option, tiling_exceptions: TilingExceptions, + active_window_needs_reset: Option, + pub swapped_output: bool, #[cfg(feature = "debug")] pub debug_active: bool, @@ -721,6 +723,8 @@ impl Workspaces { for seat in seats { if &seat.active_output() == output { seat.set_active_output(&new_output); + // TODO do we need to mark swap output here? + // Maybe not because the results are going to be weird anyways? } } @@ -1187,11 +1191,22 @@ impl Common { self.xdg_activation_state.retain_tokens(|_, data| { Instant::now().duration_since(data.timestamp) < Duration::from_secs(5) }); - self.shell.write().unwrap().refresh( + let mut guard = self.shell.write().unwrap(); + guard.refresh( &self.xdg_activation_state, &mut self.workspace_state.update(), ); + // check current active and ensure it is called twice if it is already activated and needs reactivation + if let Some(w) = guard.active_window_needs_reset.take() { + drop(guard); + + self.toplevel_info_state.refresh(&self.workspace_state); + w.set_activated(true); + } else { + drop(guard); + } self.popups.cleanup(); + self.toplevel_info_state.refresh(&self.workspace_state); self.refresh_idle_inhibit(); } @@ -1279,11 +1294,13 @@ impl Shell { theme, active_hint: config.cosmic_conf.active_hint, + active_window_needs_reset: None, overview_mode: OverviewMode::None, swap_indicator: None, resize_mode: ResizeMode::None, resize_state: None, resize_indicator: None, + swapped_output: false, tiling_exceptions, #[cfg(feature = "debug")] @@ -2340,6 +2357,7 @@ impl Shell { let new_pos = if follow { if let Some(seat) = seat { seat.set_active_output(&to_output); + self.swapped_output = true; } self.workspaces .idx_for_handle(&to_output, to) @@ -2455,6 +2473,8 @@ impl Shell { })) => { let new_pos = if follow { seat.set_active_output(&to_output); + self.swapped_output = true; + self.workspaces .idx_for_handle(&to_output, &to) .and_then(|to_idx| { diff --git a/src/wayland/handlers/toplevel_management.rs b/src/wayland/handlers/toplevel_management.rs index 7bed781f..414c7523 100644 --- a/src/wayland/handlers/toplevel_management.rs +++ b/src/wayland/handlers/toplevel_management.rs @@ -59,14 +59,17 @@ impl ToplevelManagementHandler for State { WorkspaceDelta::new_shortcut(), &mut self.common.workspace_state.update(), ); - std::mem::drop(shell); if seat.active_output() != *output { match res { Ok(Some(new_pos)) => { seat.set_active_output(&output); + shell.swapped_output = true; + std::mem::drop(shell); + if let Some(ptr) = seat.get_pointer() { let serial = SERIAL_COUNTER.next_serial(); + ptr.motion( self, None, @@ -81,9 +84,15 @@ impl ToplevelManagementHandler for State { } Ok(None) => { seat.set_active_output(&output); + shell.swapped_output = true; + std::mem::drop(shell); + } + _ => { + std::mem::drop(shell); } - _ => {} } + } else { + std::mem::drop(shell); } mapped.focus_window(window);