pinnacle/src/focus.rs

143 lines
4.1 KiB
Rust
Raw Normal View History

2023-08-01 11:06:35 -05:00
// SPDX-License-Identifier: GPL-3.0-or-later
2023-06-25 17:18:50 -05:00
2024-05-02 23:34:21 -05:00
use smithay::{desktop::space::SpaceElement, output::Output, utils::SERIAL_COUNTER};
2024-03-04 20:38:20 -06:00
use tracing::warn;
2023-07-24 18:59:05 -05:00
2023-09-09 22:47:59 -05:00
use crate::{
2024-04-26 19:58:02 -05:00
state::{Pinnacle, State, WithState},
2023-09-09 22:47:59 -05:00
window::WindowElement,
};
2023-06-17 21:02:58 -05:00
pub mod keyboard;
pub mod pointer;
2023-09-09 22:47:59 -05:00
impl State {
2024-04-26 19:58:02 -05:00
/// Update the keyboard focus.
2024-05-02 23:34:21 -05:00
pub fn update_keyboard_focus(&mut self, output: &Output) {
2024-04-26 19:58:02 -05:00
let current_focus = self.pinnacle.focused_window(output);
if let Some(win) = &current_focus {
assert!(!win.is_x11_override_redirect());
2024-05-02 23:34:21 -05:00
let wins = output.with_state(|state| state.focus_stack.stack.clone());
for win in wins.iter() {
win.set_activate(false);
if let Some(toplevel) = win.toplevel() {
toplevel.send_configure();
}
}
win.set_activate(true);
2024-04-26 19:58:02 -05:00
if let Some(toplevel) = win.toplevel() {
toplevel.send_configure();
}
}
self.pinnacle
.seat
.get_keyboard()
.expect("no keyboard")
.set_focus(
self,
current_focus.map(|win| win.into()),
SERIAL_COUNTER.next_serial(),
);
}
}
impl Pinnacle {
2024-03-04 19:16:10 -06:00
/// Get the currently focused window on `output`.
///
/// This returns the topmost window on the keyboard focus stack that is on an active tag.
pub fn focused_window(&self, output: &Output) -> Option<WindowElement> {
// TODO: see if the below is necessary
// output.with_state(|state| state.focus_stack.stack.retain(|win| win.alive()));
2023-09-09 22:47:59 -05:00
output
.with_state(|state| {
state.focus_stack.focused.then(|| {
state
.focus_stack
.stack
.iter()
.rev()
.filter(|win| win.is_on_active_tag())
.find(|win| !win.is_x11_override_redirect())
.cloned()
})
})
.flatten()
2023-09-09 22:47:59 -05:00
}
2023-09-12 09:38:34 -05:00
2024-03-04 20:38:20 -06:00
pub fn fixup_z_layering(&mut self) {
2024-04-26 19:58:02 -05:00
for win in self.z_index_stack.iter() {
self.space.raise_element(win, false);
}
2023-09-12 09:38:34 -05:00
}
2024-03-04 19:16:10 -06:00
2024-03-04 20:38:20 -06:00
/// 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) {
2024-04-26 19:58:02 -05:00
if self.space.elements().all(|win| win != &window) {
2024-03-04 20:38:20 -06:00
warn!("Tried to raise an unmapped window");
return;
}
2024-04-26 19:58:02 -05:00
self.space.raise_element(&window, activate);
2024-03-04 20:38:20 -06:00
2024-04-26 19:58:02 -05:00
self.z_index_stack.retain(|win| win != &window);
self.z_index_stack.push(window);
2024-04-19 15:02:16 -05:00
self.fixup_xwayland_window_layering();
2024-03-04 20:38:20 -06:00
}
2024-03-04 19:16:10 -06:00
/// Get the currently focused output, or the first mapped output if there is none, or None.
pub fn focused_output(&self) -> Option<&Output> {
2024-04-26 19:58:02 -05:00
self.output_focus_stack
2024-03-04 19:16:10 -06:00
.stack
.last()
2024-04-26 19:58:02 -05:00
.or_else(|| self.space.outputs().next())
2024-03-04 19:16:10 -06:00
}
2023-09-09 22:47:59 -05:00
}
2024-03-04 19:16:10 -06:00
#[derive(Debug, Clone, Default)]
pub struct OutputFocusStack {
stack: Vec<Output>,
}
2023-06-17 21:02:58 -05:00
2024-03-04 19:16:10 -06:00
impl OutputFocusStack {
// Set the new focused output.
pub fn set_focus(&mut self, output: Output) {
self.stack.retain(|op| op != &output);
self.stack.push(output);
2023-06-17 21:02:58 -05:00
}
}
2023-08-11 18:48:51 -05:00
2024-03-04 19:16:10 -06:00
/// A stack of windows, with the top one being the one in focus.
#[derive(Debug, Default)]
pub struct WindowKeyboardFocusStack {
pub stack: Vec<WindowElement>,
focused: bool,
}
impl WindowKeyboardFocusStack {
/// Set `window` to be focused.
2023-08-11 18:48:51 -05:00
///
/// If it's already in the stack, it will be removed then pushed.
/// If it isn't, it will just be pushed.
2024-03-04 19:16:10 -06:00
pub fn set_focus(&mut self, window: WindowElement) {
self.stack.retain(|win| win != &window);
self.stack.push(window);
self.focused = true;
}
2024-03-04 19:16:10 -06:00
/// Unset the focus by marking this stack as unfocused.
///
/// This will cause [`Self::current_focus`] to return `None`.
pub fn unset_focus(&mut self) {
self.focused = false;
}
2023-06-17 21:02:58 -05:00
}