Make focus tag-specific

This commit is contained in:
Ottatop 2023-09-09 22:47:59 -05:00
parent 03d57e4b5d
commit 0f42e403ae
7 changed files with 63 additions and 60 deletions

View file

@ -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

View file

@ -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<Output>,
}
impl State {
/// Get the currently focused window on `output`, if any.
pub fn current_focus(&mut self, output: &Output) -> Option<WindowElement> {
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::<Vec<_>>());
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<WindowElement> {
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<WindowElement>) {
for win in self.focus_stack.iter() {
space.raise_element(win, false);

View file

@ -328,10 +328,13 @@ impl SeatHandler for State {
}
fn focus_changed(&mut self, seat: &Seat<Self>, 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

View file

@ -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) {

View file

@ -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::<smithay::wayland::shell::xdg::XdgToplevelSurfaceData>()
.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 {

View file

@ -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| {

View file

@ -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()