diff --git a/src/focus.rs b/src/focus.rs index 0913383..6693541 100644 --- a/src/focus.rs +++ b/src/focus.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later use smithay::{output::Output, utils::SERIAL_COUNTER}; +use tracing::warn; use crate::{ state::{State, WithState}, @@ -53,12 +54,27 @@ impl State { ); } - pub fn fixup_focus(&mut self) { - for win in self.z_index_stack.stack.iter() { + pub fn fixup_z_layering(&mut self) { + for win in self.z_index_stack.iter() { self.space.raise_element(win, false); } } + /// Raise a window to the top of the z-index stack. + /// + /// This does nothing if the window is unmapped. + pub fn raise_window(&mut self, window: WindowElement, activate: bool) { + if self.space.elements().all(|win| win != &window) { + warn!("Tried to raise an unmapped window"); + return; + } + + self.space.raise_element(&window, activate); + + self.z_index_stack.retain(|win| win != &window); + self.z_index_stack.push(window); + } + /// Get the currently focused output, or the first mapped output if there is none, or None. pub fn focused_output(&self) -> Option<&Output> { self.output_focus_stack diff --git a/src/grab/move_grab.rs b/src/grab/move_grab.rs index 37452a4..3a665e2 100644 --- a/src/grab/move_grab.rs +++ b/src/grab/move_grab.rs @@ -49,7 +49,8 @@ impl PointerGrab for MoveSurfaceGrab { return; } - state.space.raise_element(&self.window, false); + state.raise_window(self.window.clone(), false); + if let Some(surface) = self.window.x11_surface() { // INFO: can you raise OR windows or no idk if !surface.is_override_redirect() { diff --git a/src/handlers.rs b/src/handlers.rs index a1839e2..111405a 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -143,7 +143,6 @@ impl CompositorHandler for State { if is_mapped { self.new_windows.retain(|win| win != &new_window); self.windows.push(new_window.clone()); - self.z_index_stack.set_focus(new_window.clone()); if let Some(output) = self.focused_output() { tracing::debug!("Placing toplevel"); @@ -157,6 +156,8 @@ impl CompositorHandler for State { self.space .map_element(new_window.clone(), (1000000, 0), true); + self.raise_window(new_window.clone(), true); + self.apply_window_rules(&new_window); if let Some(focused_output) = self.focused_output().cloned() { diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs index 88f71ad..8af860e 100644 --- a/src/handlers/xdg_shell.rs +++ b/src/handlers/xdg_shell.rs @@ -56,7 +56,7 @@ impl XdgShellHandler for State { .is_some_and(|surf| &surf != surface.wl_surface()) }); - self.z_index_stack.stack.retain(|window| { + self.z_index_stack.retain(|window| { window .wl_surface() .is_some_and(|surf| &surf != surface.wl_surface()) @@ -81,12 +81,11 @@ impl XdgShellHandler for State { let focus = self .focused_window(&output) .map(KeyboardFocusTarget::Window); - if let Some(KeyboardFocusTarget::Window(win)) = &focus { + if let Some(KeyboardFocusTarget::Window(window)) = &focus { tracing::debug!("Focusing on prev win"); // TODO: - self.space.raise_element(win, true); - self.z_index_stack.set_focus(win.clone()); - if let Some(toplevel) = win.toplevel() { + self.raise_window(window.clone(), true); + if let Some(toplevel) = window.toplevel() { toplevel.send_configure(); } } diff --git a/src/handlers/xwayland.rs b/src/handlers/xwayland.rs index 43125dd..ef691e2 100644 --- a/src/handlers/xwayland.rs +++ b/src/handlers/xwayland.rs @@ -97,7 +97,7 @@ impl XwmHandler for State { // TODO: will an unmap -> map duplicate the window self.windows.push(window.clone()); - self.z_index_stack.set_focus(window.clone()); + self.raise_window(window.clone(), true); self.apply_window_rules(&window); @@ -129,7 +129,6 @@ impl XwmHandler for State { let window = WindowElement::new(Window::new_x11_window(surface)); self.windows.push(window.clone()); - self.z_index_stack.set_focus(window.clone()); if let Some(output) = self.focused_output() { window.place_on_output(output); @@ -138,7 +137,8 @@ impl XwmHandler for State { output.with_state_mut(|state| state.focus_stack.set_focus(window.clone())) } - self.space.map_element(window, loc, true); + self.space.map_element(window.clone(), loc, true); + self.raise_window(window.clone(), true); } fn unmapped_window(&mut self, _xwm: XwmId, surface: X11Surface) { @@ -161,7 +161,6 @@ impl XwmHandler for State { self.windows .retain(|elem| win.wl_surface() != elem.wl_surface()); self.z_index_stack - .stack .retain(|elem| win.wl_surface() != elem.wl_surface()); self.space.unmap_elem(&win); @@ -174,8 +173,7 @@ impl XwmHandler for State { .map(KeyboardFocusTarget::Window); if let Some(KeyboardFocusTarget::Window(win)) = &focus { - self.space.raise_element(win, true); - self.z_index_stack.set_focus(win.clone()); + self.raise_window(win.clone(), true); if let Some(toplevel) = win.toplevel() { toplevel.send_configure(); } @@ -226,7 +224,6 @@ impl XwmHandler for State { .retain(|elem| win.wl_surface() != elem.wl_surface()); self.z_index_stack - .stack .retain(|elem| win.wl_surface() != elem.wl_surface()); if let Some(output) = win.output(self) { @@ -237,8 +234,7 @@ impl XwmHandler for State { .map(KeyboardFocusTarget::Window); if let Some(KeyboardFocusTarget::Window(win)) = &focus { - self.space.raise_element(win, true); - self.z_index_stack.set_focus(win.clone()); + self.raise_window(win.clone(), true); if let Some(toplevel) = win.toplevel() { toplevel.send_configure(); } diff --git a/src/input.rs b/src/input.rs index 5479e0c..5c31d14 100644 --- a/src/input.rs +++ b/src/input.rs @@ -375,8 +375,7 @@ impl State { // TODO: use update_keyboard_focus from anvil if let Some(window) = focus.window_for(self) { - self.space.raise_element(&window, true); - self.z_index_stack.set_focus(window.clone()); + self.raise_window(window.clone(), true); if let Some(output) = window.output(self) { output.with_state_mut(|state| state.focus_stack.set_focus(window.clone())); } diff --git a/src/layout.rs b/src/layout.rs index 0a9d9f5..1011798 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -150,7 +150,7 @@ impl State { self.space.map_element(window, loc, false); } - self.fixup_focus(); + self.fixup_z_layering(); } } diff --git a/src/main.rs b/src/main.rs index 2ba2d6c..a2c8eac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -143,13 +143,22 @@ async fn main() -> anyhow::Result<()> { }; event_loop.run(None, &mut state, |state| { - state.fixup_focus(); + state.fixup_z_layering(); state.space.refresh(); state.popup_manager.cleanup(); + state .display_handle .flush_clients() .expect("failed to flush client buffers"); + + // TODO: couple these or something, this is really error-prone + assert_eq!( + state.windows.len(), + state.z_index_stack.len(), + "Length of `windows` and `z_index_stack` are different. \ + If you see this, report it to the developer." + ); })?; Ok(()) diff --git a/src/state.rs b/src/state.rs index be1ad81..a69e3c9 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,13 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later use crate::{ - api::signal::SignalState, - backend::Backend, - config::Config, - cursor::Cursor, - focus::{OutputFocusStack, WindowKeyboardFocusStack}, - grab::resize_grab::ResizeSurfaceState, - window::WindowElement, + api::signal::SignalState, backend::Backend, config::Config, cursor::Cursor, + focus::OutputFocusStack, grab::resize_grab::ResizeSurfaceState, window::WindowElement, }; use anyhow::Context; use smithay::{ @@ -77,7 +72,7 @@ pub struct State { pub input_state: InputState, pub output_focus_stack: OutputFocusStack, - pub z_index_stack: WindowKeyboardFocusStack, + pub z_index_stack: Vec, pub popup_manager: PopupManager, @@ -255,7 +250,7 @@ impl State { input_state: InputState::new(), output_focus_stack: OutputFocusStack::default(), - z_index_stack: WindowKeyboardFocusStack::default(), + z_index_stack: Vec::new(), config: Config::new(no_config, config_dir),