diff --git a/api/lua/window.lua b/api/lua/window.lua index b0e5669..e2f4549 100644 --- a/api/lua/window.lua +++ b/api/lua/window.lua @@ -224,6 +224,7 @@ end ---Get the currently focused window. ---@return Window|nil function window_module.get_focused() + -- TODO: get focused on output local windows = window_module.get_all() for _, w in pairs(windows) do @@ -238,8 +239,7 @@ end ---Get all windows. ---@return Window[] function window_module.get_all() - local window_ids = - Request("GetWindows").RequestResponse.response.Windows.window_ids + local window_ids = Request("GetWindows").RequestResponse.response.Windows.window_ids ---@type Window[] local windows = {} @@ -513,8 +513,7 @@ function window_module.fullscreen(win) window_id = win:id(), }, }) - local fom = - response.RequestResponse.response.WindowProps.fullscreen_or_maximized + local fom = response.RequestResponse.response.WindowProps.fullscreen_or_maximized return fom == "Fullscreen" end @@ -528,8 +527,7 @@ function window_module.maximized(win) window_id = win:id(), }, }) - local fom = - response.RequestResponse.response.WindowProps.fullscreen_or_maximized + local fom = response.RequestResponse.response.WindowProps.fullscreen_or_maximized return fom == "Maximized" end diff --git a/src/focus.rs b/src/focus.rs index 54d38e0..f87e4f3 100644 --- a/src/focus.rs +++ b/src/focus.rs @@ -13,7 +13,10 @@ use smithay::{ wayland::seat::WaylandFocus, }; -use crate::{state::State, window::WindowElement}; +use crate::{ + state::{State, WithState}, + window::WindowElement, +}; #[derive(Default)] pub struct FocusState { @@ -21,23 +24,30 @@ pub struct FocusState { pub focused_output: Option, } +impl State { + /// Get the currently focused window on `output`, if any. + pub fn current_focus(&mut self, output: &Output) -> Option { + self.focus_state.focus_stack.retain(|win| win.alive()); + + let mut windows = self.focus_state.focus_stack.iter().rev().filter(|win| { + let win_tags = win.with_state(|state| state.tags.clone()); + let output_tags = + output.with_state(|state| state.focused_tags().cloned().collect::>()); + + win_tags + .iter() + .any(|win_tag| output_tags.iter().any(|op_tag| win_tag == op_tag)) + }); + + windows.next().cloned() + } +} + impl FocusState { pub fn new() -> Self { Default::default() } - // TODO: how does this work with unmapped windows? - /// Get the currently focused window. If there is none, the previous focus is returned. - pub fn current_focus(&mut self) -> Option { - while let Some(window) = self.focus_stack.last() { - if window.alive() { - return Some(window.clone()); - } - self.focus_stack.pop(); - } - None - } - /// Set the currently focused window. pub fn set_focus(&mut self, window: WindowElement) { self.focus_stack.retain(|win| win != &window); @@ -46,8 +56,8 @@ impl FocusState { /// Fix focus layering for all windows in the `focus_stack`. /// - /// This will call `space.map_element` on all windows from front - /// to back to correct their z locations. + /// This will call `space.raise_element` on all windows from back + /// to front to correct their z locations. pub fn fix_up_focus(&self, space: &mut Space) { for win in self.focus_stack.iter() { space.raise_element(win, false); diff --git a/src/handlers.rs b/src/handlers.rs index ab5118f..736b0d9 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -328,10 +328,13 @@ impl SeatHandler for State { } fn focus_changed(&mut self, seat: &Seat, focused: Option<&Self::KeyboardFocus>) { - if let Some(focus) = + if let Some(win) = focused.and_then(|focused| self.window_for_surface(&focused.wl_surface()?)) { - self.focus_state.set_focus(focus); + if let WindowElement::Wayland(win) = &win { + win.set_activated(true); + } + self.focus_state.set_focus(win); } let focus_client = focused.and_then(|foc_target| { self.display_handle diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs index 27cad85..35247ef 100644 --- a/src/handlers/xdg_shell.rs +++ b/src/handlers/xdg_shell.rs @@ -121,16 +121,31 @@ impl XdgShellHandler for State { .wl_surface() .is_some_and(|surf| &surf != surface.wl_surface()) }); - if let Some(focused_output) = self.focus_state.focused_output.as_ref().cloned() { - self.update_windows(&focused_output); + self.focus_state.focus_stack.retain(|window| { + window + .wl_surface() + .is_some_and(|surf| &surf != surface.wl_surface()) + }); + + let Some(window) = self.window_for_surface(surface.wl_surface()) else { + return; + }; + + if let Some(output) = window.output(self) { + self.update_windows(&output); + let focus = self.current_focus(&output).map(FocusTarget::Window); + if let Some(FocusTarget::Window(win)) = &focus { + tracing::debug!("Focusing on prev win"); + self.space.raise_element(win, true); + if let WindowElement::Wayland(win) = &win { + win.toplevel().send_configure(); + } + } + self.seat + .get_keyboard() + .expect("Seat had no keyboard") + .set_focus(self, focus, SERIAL_COUNTER.next_serial()); } - - let focus = self.focus_state.current_focus().map(FocusTarget::Window); - - self.seat - .get_keyboard() - .expect("Seat had no keyboard") - .set_focus(self, focus, SERIAL_COUNTER.next_serial()); } fn new_popup(&mut self, surface: PopupSurface, _positioner: PositionerState) { diff --git a/src/input.rs b/src/input.rs index 594d7ff..4b8b3f6 100644 --- a/src/input.rs +++ b/src/input.rs @@ -268,16 +268,10 @@ impl State { let pointer = self.seat.get_pointer().expect("Seat has no pointer"); // FIXME: handle err let keyboard = self.seat.get_keyboard().expect("Seat has no keyboard"); // FIXME: handle err - // A serial is a number sent with a event that is sent back to the - // server by the clients in further requests. This allows the server to - // keep track of which event caused which requests. It is an AtomicU32 - // that increments when next_serial is called. let serial = SERIAL_COUNTER.next_serial(); - // Returns which button on the pointer was used. let button = event.button_code(); - // The state, either released or pressed. let button_state = event.state(); let pointer_loc = pointer.current_location(); @@ -390,21 +384,7 @@ impl State { }); if let FocusTarget::Window(window) = &focus { - let focused_name = match &window { - WindowElement::Wayland(win) => { - compositor::with_states(win.toplevel().wl_surface(), |states| { - let lock = states - .data_map - .get::() - .expect("XdgToplevelSurfaceData wasn't in surface's data map") - .lock() - .expect("failed to acquire lock"); - lock.app_id.clone().unwrap_or_default() - }) - } - WindowElement::X11(surf) => surf.class(), - }; - tracing::debug!("setting keyboard focus to {focused_name}"); + tracing::debug!("setting keyboard focus to {:?}", window.class()); } } } else { diff --git a/src/layout.rs b/src/layout.rs index 0c1336b..28bb7c9 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -166,7 +166,6 @@ impl State { // schedule on all idle self.schedule( move |_dt| { - tracing::debug!("Waiting for all to be idle"); let all_idle = pending_wins .iter() .filter(|(_, win)| win.alive()) @@ -178,8 +177,6 @@ impl State { .filter(|(_, win)| !win.with_state(|state| state.loc_request_state.is_idle())) .count(); - tracing::debug!("{num_not_idle} not idle"); - all_idle }, move |dt| { diff --git a/src/state/api_handlers.rs b/src/state/api_handlers.rs index 63fe377..fcfc1c0 100644 --- a/src/state/api_handlers.rs +++ b/src/state/api_handlers.rs @@ -271,7 +271,8 @@ impl State { .api_state .stream .as_ref() - .expect("Stream doesn't exist"); + .expect("Stream doesn't exist") + .clone(); let mut stream = stream.lock().expect("Couldn't lock stream"); match request { Request::GetWindows => { @@ -319,9 +320,8 @@ impl State { WindowElement::X11(surface) => (Some(surface.class()), Some(surface.title())), }); let focused = window.as_ref().and_then(|win| { - self.focus_state - .current_focus() // TODO: actual focus - .map(|foc_win| win == &foc_win) + let output = win.output(self)?; + self.current_focus(&output).map(|foc_win| win == &foc_win) }); let floating = window .as_ref()