diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index 3fcdcffb..bbf03945 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -2,6 +2,7 @@ mod event_handling; mod device_handler; pub mod ext_transient_seat_manager_v1; pub mod ext_transient_seat_v1; +mod focus; mod gesture_owner; mod kb_owner; mod pointer_owner; @@ -73,7 +74,6 @@ use { dnd_icon::DndIcon, tray::{DynTrayItem, TrayItemId}, xdg_surface::{xdg_popup::XdgPopup, xdg_toplevel::ResizeEdges}, - zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, }, xdg_toplevel_drag_v1::XdgToplevelDragV1, }, @@ -84,9 +84,8 @@ use { rect::Rect, state::{DeviceHandlerData, State}, tree::{ - Direction, FoundNode, Node, NodeId, NodeLayer, NodeLayerLink, NodeLocation, OutputNode, - StackedNode, ToplevelNode, WorkspaceNode, generic_node_visitor, - toplevel_set_workspace, + FoundNode, Node, NodeId, NodeLocation, OutputNode, ToplevelNode, WorkspaceNode, + generic_node_visitor, toplevel_set_workspace, }, utils::{ asyncevent::AsyncEvent, @@ -94,9 +93,9 @@ use { clonecell::CloneCell, copyhashmap::CopyHashMap, event_listener::{EventListener, EventSource}, - linkedlist::{LinkedList, LinkedNode, NodeRef}, + linkedlist::{LinkedList, LinkedNode}, numcell::NumCell, - rc_eq::{rc_eq, rc_weak_eq}, + rc_eq::rc_eq, smallmap::SmallMap, static_text::StaticText, }, @@ -114,13 +113,12 @@ use { }, kbvm::Keycode, linearize::Linearize, - run_on_drop::on_drop, smallvec::SmallVec, std::{ cell::{Cell, RefCell}, collections::hash_map::Entry, mem, - ops::{Deref, DerefMut}, + ops::DerefMut, rc::{Rc, Weak}, }, thiserror::Error, @@ -733,459 +731,6 @@ impl WlSeatGlobal { } } - pub fn close(self: &Rc) { - let kb_node = self.keyboard_node.get(); - if let Some(tl) = kb_node.node_toplevel() { - tl.tl_close(); - } - } - - pub fn move_focus(self: &Rc, direction: Direction) { - let tl = match self.keyboard_node.get().node_toplevel() { - Some(tl) => tl, - _ => { - if let Some(ws) = self.keyboard_node.get().node_into_workspace() - && let Some(target) = self - .state - .find_output_in_direction(&ws.output.get(), direction) - { - target.take_keyboard_navigation_focus(self, direction); - self.maybe_schedule_warp_mouse_to_focus(); - } - return; - } - }; - if direction == Direction::Down && tl.node_is_container() { - tl.node_do_focus(self, direction); - } else { - let data = tl.tl_data(); - if data.is_fullscreen.get() - && let Some(output) = data.output_opt() - && let Some(target) = self.state.find_output_in_direction(&output, direction) - { - target.take_keyboard_navigation_focus(self, direction); - } else if let Some(p) = data.parent.get() - && let Some(c) = p.node_into_container() - { - c.move_focus_from_child(self, tl.deref(), direction); - } else if let Some(float) = data.float.get() { - let ws = float.workspace.get(); - let floats: Vec<_> = ws - .stacked - .iter() - .filter_map(|node| (*node).clone().node_into_float()) - .filter(|f| f.child.get().is_some()) - .collect(); - if let Some(pos) = floats.iter().position(|f| f.id == float.id) { - let target = match direction { - Direction::Left | Direction::Down => { - if pos == 0 { - floats.last() - } else { - floats.get(pos - 1) - } - } - _ => { - if pos + 1 >= floats.len() { - floats.first() - } else { - floats.get(pos + 1) - } - } - }; - if let Some(f) = target - && f.id != float.id - { - f.clone().node_do_focus(self, Direction::Unspecified); - } - } - } - } - self.maybe_schedule_warp_mouse_to_focus(); - } - - pub fn maybe_schedule_warp_mouse_to_focus(self: &Rc) { - if self.mouse_follows_focus() { - self.warp_mouse_to_focus_skip_target_check.set(true); - self.schedule_warp_mouse_to_focus(); - } - } - - pub fn schedule_warp_mouse_to_focus(self: &Rc) { - if !self.warp_mouse_to_focus_scheduled.replace(true) { - self.state.pending_warp_mouse_to_focus.push(self.clone()); - } - } - - pub fn move_focused(self: &Rc, direction: Direction) { - let kb_node = self.keyboard_node.get(); - let Some(tl) = kb_node.node_toplevel() else { - if let Some(ws) = self.keyboard_node.get().node_into_workspace() - && let Some(target) = self - .state - .find_output_in_direction(&ws.output.get(), direction) - { - self.state.move_ws_to_output(&ws, &target); - } - return; - }; - let data = tl.tl_data(); - if data.is_fullscreen.get() - && let Some(output) = data.output_opt() - && let Some(target) = self.state.find_output_in_direction(&output, direction) - { - let ws = target.ensure_workspace(); - toplevel_set_workspace(&self.state, tl, &ws); - self.maybe_schedule_warp_mouse_to_focus(); - } else if let Some(parent) = data.parent.get() - && let Some(c) = parent.node_into_container() - { - c.move_child(tl, direction); - self.maybe_schedule_warp_mouse_to_focus(); - } else if let Some(float) = data.float.get() { - float.move_by_direction(direction); - self.maybe_schedule_warp_mouse_to_focus(); - } - } - - pub fn get_last_focus_on_workspace(&self, ws: &WorkspaceNode) -> Option> { - let mut node = self.focus_history.last()?; - loop { - if let Some(node) = node.node.upgrade() - && let Some(NodeLocation::Workspace(_, new)) = node.node_location() - && new == ws.id - { - return Some(node); - } - node = node.prev()?; - } - } - - fn get_focus_history( - &self, - next: impl Fn(&NodeRef) -> Option>, - first: impl FnOnce(&LinkedList) -> Option>, - ) -> Option<(Rc, bool)> { - let original = self.keyboard_node.get(); - let mut output = None; - let mut workspace = None; - if let Some(old) = original.node_location() { - match old { - NodeLocation::Workspace(o, w) => { - workspace = Some(w); - output = Some(o); - } - NodeLocation::Output(o) => { - output = Some(o); - } - } - } - if (output.is_none() || workspace.is_none()) - && let Some(old) = self.last_focus_location.get() - { - match old { - NodeLocation::Workspace(o, w) => { - workspace = workspace.or(Some(w)); - output = output.or(Some(o)); - } - NodeLocation::Output(o) => { - output = output.or(Some(o)); - } - } - } - if workspace.is_none() - && let Some(output) = original.node_output() - && let Some(ws) = output.workspace.get() - { - workspace = Some(ws.id); - } - let matches = |node: &FocusHistoryData| { - let visible = node.visible.get(); - if self.focus_history_visible_only.get() && !visible { - return None; - } - let node = node.node.upgrade()?; - if self.focus_history_same_workspace.get() { - let new = node.node_location()?; - let o = match new { - NodeLocation::Workspace(o, w) => { - if workspace != Some(w) { - return None; - } - o - } - NodeLocation::Output(o) => o, - }; - if output != Some(o) { - return None; - } - } - Some((node, visible)) - }; - let node = original.node_seat_state().get_focus_history(self); - if let Some(mut node) = node { - loop { - node = match next(&node) { - Some(n) => n, - _ => break, - }; - if let Some(matches) = matches(&node) { - return Some(matches); - } - } - } - let mut node = first(&self.focus_history)?; - loop { - if rc_weak_eq(&original, &node.node) { - return None; - } - if let Some(matches) = matches(&node) { - return Some(matches); - } - node = next(&node)?; - } - } - - fn focus_history( - self: &Rc, - next: impl Fn(&NodeRef) -> Option>, - first: impl FnOnce(&LinkedList) -> Option>, - ) { - let Some((node, visible)) = self.get_focus_history(next, first) else { - return; - }; - self.focus_history_rotate.fetch_add(1); - let _reset = on_drop(|| { - self.focus_history_rotate.fetch_sub(1); - }); - if !visible { - node.clone().node_make_visible(); - if !node.node_visible() { - return; - } - } - self.focus_node(node); - self.maybe_schedule_warp_mouse_to_focus(); - } - - pub fn focus_prev(self: &Rc) { - self.focus_history(|s| s.prev(), |l| l.last()); - } - - pub fn focus_next(self: &Rc) { - self.focus_history(|s| s.next(), |l| l.first()); - } - - pub fn focus_history_set_visible(&self, visible: bool) { - self.focus_history_visible_only.set(visible); - } - - pub fn focus_history_set_same_workspace(&self, same_workspace: bool) { - self.focus_history_same_workspace.set(same_workspace); - } - - fn focus_layer_rel( - self: &Rc, - next_layer: impl Fn(NodeLayer) -> NodeLayer, - layer_node_next: impl Fn( - &NodeRef>, - ) -> Option>>, - stacked_node_next: impl Fn( - &NodeRef>, - ) -> Option>>, - layer_list_iter: impl Fn(&LinkedList>) -> LI, - stacked_list_iter: impl Fn(&LinkedList>) -> SI, - ) where - LI: Iterator>>, - SI: Iterator>>, - { - fn node_viable(n: &(impl Node + ?Sized)) -> bool { - n.node_visible() && n.node_accepts_focus() - } - - let current = self.keyboard_node.get(); - let Some(output) = current.node_output() else { - return; - }; - let current_layer = current.node_layer(); - match ¤t_layer { - NodeLayerLink::Layer0(l) - | NodeLayerLink::Layer1(l) - | NodeLayerLink::Layer2(l) - | NodeLayerLink::Layer3(l) => { - if let Some(n) = layer_node_next(l) - && node_viable(&**n) - { - n.deref() - .clone() - .node_do_focus(self, Direction::Unspecified); - self.maybe_schedule_warp_mouse_to_focus(); - return; - } - } - NodeLayerLink::Stacked(l) | NodeLayerLink::StackedAboveLayers(l) => { - if let Some(n) = stacked_node_next(l) - && node_viable(&**n) - && n.node_output().map(|o| o.id) == Some(output.id) - { - n.deref() - .clone() - .node_do_focus(self, Direction::Unspecified); - self.maybe_schedule_warp_mouse_to_focus(); - return; - } - } - NodeLayerLink::Display => {} - NodeLayerLink::Output => {} - NodeLayerLink::Workspace => {} - NodeLayerLink::Tiled => {} - NodeLayerLink::Fullscreen => {} - NodeLayerLink::Lock => {} - NodeLayerLink::InputMethod => {} - } - let handle_layer_shell = |l: &LinkedList>| { - for n in layer_list_iter(l) { - if node_viable(&**n) { - return Some(n.deref().clone() as Rc); - } - } - None - }; - let handle_stacked = |l: &LinkedList>| { - for n in stacked_list_iter(l) { - if node_viable(&**n) && n.node_output().map(|o| o.id) == Some(output.id) { - return Some(n.deref().clone() as Rc); - } - } - None - }; - let ws = output.workspace.get(); - let first = next_layer(current_layer.layer()); - let mut layer = first; - loop { - let node = match layer { - NodeLayer::Display => None, - NodeLayer::Layer0 => handle_layer_shell(&output.layers[0]), - NodeLayer::Layer1 => handle_layer_shell(&output.layers[1]), - NodeLayer::Output => None, - NodeLayer::Workspace => { - if let Some(ws) = &ws - && ws.container_visible() - { - self.focus_node(ws.clone()); - self.maybe_schedule_warp_mouse_to_focus(); - return; - } - None - } - NodeLayer::Tiled => ws - .as_ref() - .and_then(|w| w.container.get()) - .map(|n| n as Rc), - NodeLayer::Fullscreen => ws - .as_ref() - .and_then(|w| w.fullscreen.get()) - .map(|n| n as Rc), - NodeLayer::Stacked => handle_stacked(&self.state.root.stacked), - NodeLayer::Layer2 => handle_layer_shell(&output.layers[2]), - NodeLayer::Layer3 => handle_layer_shell(&output.layers[3]), - NodeLayer::StackedAboveLayers => { - handle_stacked(&self.state.root.stacked_above_layers) - } - NodeLayer::Lock => None, - NodeLayer::InputMethod => None, - }; - if let Some(n) = node { - if node_viable(&*n) { - n.node_do_focus(self, Direction::Unspecified); - self.maybe_schedule_warp_mouse_to_focus(); - return; - } - } - layer = next_layer(layer); - if layer == first { - return; - } - } - } - - pub fn focus_layer_below(self: &Rc) { - self.focus_layer_rel( - |l| l.prev(), - |n| n.prev(), - |n| n.prev(), - |l| l.rev_iter(), - |l| l.rev_iter(), - ); - } - - pub fn focus_layer_above(self: &Rc) { - self.focus_layer_rel( - |l| l.next(), - |n| n.next(), - |n| n.next(), - |l| l.iter(), - |l| l.iter(), - ); - } - - pub fn toggle_focus_float_tiled(self: &Rc) { - let current = self.keyboard_node.get(); - match current.node_layer().layer() { - NodeLayer::Tiled | NodeLayer::Fullscreen => self.focus_floats(), - _ => self.focus_tiles(), - } - self.maybe_schedule_warp_mouse_to_focus(); - } - - pub fn focus_floats(self: &Rc) { - let current = self.keyboard_node.get(); - if current.node_layer().layer() == NodeLayer::Stacked { - return; - } - let Some(output) = current.node_output() else { - return; - }; - let Some(ws) = output.workspace.get() else { - return; - }; - if let Some(child) = ws - .stacked - .rev_iter() - .filter_map(|node| (*node).clone().node_into_float()) - .find_map(|float| float.child.get()) - { - child.node_do_focus(self, Direction::Unspecified); - } - } - - pub fn focus_tiles(self: &Rc) { - let current = self.keyboard_node.get(); - if matches!( - current.node_layer().layer(), - NodeLayer::Tiled | NodeLayer::Fullscreen, - ) { - return; - } - let Some(output) = current.node_output() else { - return; - }; - let Some(ws) = output.workspace.get() else { - return; - }; - let node = match ws.fullscreen.get() { - Some(fs) => fs as Rc, - _ => match ws.container.get() { - Some(c) => c, - _ => return, - }, - }; - if node.node_visible() && node.node_accepts_focus() { - node.node_do_focus(self, Direction::Unspecified); - self.maybe_schedule_warp_mouse_to_focus(); - } - } - pub fn start_drag( self: &Rc, origin: &Rc, diff --git a/src/ifs/wl_seat/focus.rs b/src/ifs/wl_seat/focus.rs new file mode 100644 index 00000000..edcb550e --- /dev/null +++ b/src/ifs/wl_seat/focus.rs @@ -0,0 +1,471 @@ +use { + super::{WlSeatGlobal, event_handling::FocusHistoryData}, + crate::{ + ifs::wl_surface::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, + tree::{ + Direction, Node, NodeLayer, NodeLayerLink, NodeLocation, StackedNode, WorkspaceNode, + toplevel_set_workspace, + }, + utils::{ + linkedlist::{LinkedList, NodeRef}, + rc_eq::rc_weak_eq, + }, + }, + run_on_drop::on_drop, + std::{ops::Deref, rc::Rc}, +}; + +impl WlSeatGlobal { + pub fn close(self: &Rc) { + let kb_node = self.keyboard_node.get(); + if let Some(tl) = kb_node.node_toplevel() { + tl.tl_close(); + } + } + + pub fn move_focus(self: &Rc, direction: Direction) { + let tl = match self.keyboard_node.get().node_toplevel() { + Some(tl) => tl, + _ => { + if let Some(ws) = self.keyboard_node.get().node_into_workspace() + && let Some(target) = self + .state + .find_output_in_direction(&ws.output.get(), direction) + { + target.take_keyboard_navigation_focus(self, direction); + self.maybe_schedule_warp_mouse_to_focus(); + } + return; + } + }; + if direction == Direction::Down && tl.node_is_container() { + tl.node_do_focus(self, direction); + } else { + let data = tl.tl_data(); + if data.is_fullscreen.get() + && let Some(output) = data.output_opt() + && let Some(target) = self.state.find_output_in_direction(&output, direction) + { + target.take_keyboard_navigation_focus(self, direction); + } else if let Some(p) = data.parent.get() + && let Some(c) = p.node_into_container() + { + c.move_focus_from_child(self, tl.deref(), direction); + } else if let Some(float) = data.float.get() { + let ws = float.workspace.get(); + let floats: Vec<_> = ws + .stacked + .iter() + .filter_map(|node| (*node).clone().node_into_float()) + .filter(|f| f.child.get().is_some()) + .collect(); + if let Some(pos) = floats.iter().position(|f| f.id == float.id) { + let target = match direction { + Direction::Left | Direction::Down => { + if pos == 0 { + floats.last() + } else { + floats.get(pos - 1) + } + } + _ => { + if pos + 1 >= floats.len() { + floats.first() + } else { + floats.get(pos + 1) + } + } + }; + if let Some(f) = target + && f.id != float.id + { + f.clone().node_do_focus(self, Direction::Unspecified); + } + } + } + } + self.maybe_schedule_warp_mouse_to_focus(); + } + + pub fn maybe_schedule_warp_mouse_to_focus(self: &Rc) { + if self.mouse_follows_focus() { + self.warp_mouse_to_focus_skip_target_check.set(true); + self.schedule_warp_mouse_to_focus(); + } + } + + pub fn schedule_warp_mouse_to_focus(self: &Rc) { + if !self.warp_mouse_to_focus_scheduled.replace(true) { + self.state.pending_warp_mouse_to_focus.push(self.clone()); + } + } + + pub fn move_focused(self: &Rc, direction: Direction) { + let kb_node = self.keyboard_node.get(); + let Some(tl) = kb_node.node_toplevel() else { + if let Some(ws) = self.keyboard_node.get().node_into_workspace() + && let Some(target) = self + .state + .find_output_in_direction(&ws.output.get(), direction) + { + self.state.move_ws_to_output(&ws, &target); + } + return; + }; + let data = tl.tl_data(); + if data.is_fullscreen.get() + && let Some(output) = data.output_opt() + && let Some(target) = self.state.find_output_in_direction(&output, direction) + { + let ws = target.ensure_workspace(); + toplevel_set_workspace(&self.state, tl, &ws); + self.maybe_schedule_warp_mouse_to_focus(); + } else if let Some(parent) = data.parent.get() + && let Some(c) = parent.node_into_container() + { + c.move_child(tl, direction); + self.maybe_schedule_warp_mouse_to_focus(); + } else if let Some(float) = data.float.get() { + float.move_by_direction(direction); + self.maybe_schedule_warp_mouse_to_focus(); + } + } + + pub fn get_last_focus_on_workspace(&self, ws: &WorkspaceNode) -> Option> { + let mut node = self.focus_history.last()?; + loop { + if let Some(node) = node.node.upgrade() + && let Some(NodeLocation::Workspace(_, new)) = node.node_location() + && new == ws.id + { + return Some(node); + } + node = node.prev()?; + } + } + + fn get_focus_history( + &self, + next: impl Fn(&NodeRef) -> Option>, + first: impl FnOnce(&LinkedList) -> Option>, + ) -> Option<(Rc, bool)> { + let original = self.keyboard_node.get(); + let mut output = None; + let mut workspace = None; + if let Some(old) = original.node_location() { + match old { + NodeLocation::Workspace(o, w) => { + workspace = Some(w); + output = Some(o); + } + NodeLocation::Output(o) => { + output = Some(o); + } + } + } + if (output.is_none() || workspace.is_none()) + && let Some(old) = self.last_focus_location.get() + { + match old { + NodeLocation::Workspace(o, w) => { + workspace = workspace.or(Some(w)); + output = output.or(Some(o)); + } + NodeLocation::Output(o) => { + output = output.or(Some(o)); + } + } + } + if workspace.is_none() + && let Some(output) = original.node_output() + && let Some(ws) = output.workspace.get() + { + workspace = Some(ws.id); + } + let matches = |node: &FocusHistoryData| { + let visible = node.visible.get(); + if self.focus_history_visible_only.get() && !visible { + return None; + } + let node = node.node.upgrade()?; + if self.focus_history_same_workspace.get() { + let new = node.node_location()?; + let o = match new { + NodeLocation::Workspace(o, w) => { + if workspace != Some(w) { + return None; + } + o + } + NodeLocation::Output(o) => o, + }; + if output != Some(o) { + return None; + } + } + Some((node, visible)) + }; + let node = original.node_seat_state().get_focus_history(self); + if let Some(mut node) = node { + loop { + node = match next(&node) { + Some(n) => n, + _ => break, + }; + if let Some(matches) = matches(&node) { + return Some(matches); + } + } + } + let mut node = first(&self.focus_history)?; + loop { + if rc_weak_eq(&original, &node.node) { + return None; + } + if let Some(matches) = matches(&node) { + return Some(matches); + } + node = next(&node)?; + } + } + + fn focus_history( + self: &Rc, + next: impl Fn(&NodeRef) -> Option>, + first: impl FnOnce(&LinkedList) -> Option>, + ) { + let Some((node, visible)) = self.get_focus_history(next, first) else { + return; + }; + self.focus_history_rotate.fetch_add(1); + let _reset = on_drop(|| { + self.focus_history_rotate.fetch_sub(1); + }); + if !visible { + node.clone().node_make_visible(); + if !node.node_visible() { + return; + } + } + self.focus_node(node); + self.maybe_schedule_warp_mouse_to_focus(); + } + + pub fn focus_prev(self: &Rc) { + self.focus_history(|s| s.prev(), |l| l.last()); + } + + pub fn focus_next(self: &Rc) { + self.focus_history(|s| s.next(), |l| l.first()); + } + + pub fn focus_history_set_visible(&self, visible: bool) { + self.focus_history_visible_only.set(visible); + } + + pub fn focus_history_set_same_workspace(&self, same_workspace: bool) { + self.focus_history_same_workspace.set(same_workspace); + } + + fn focus_layer_rel( + self: &Rc, + next_layer: impl Fn(NodeLayer) -> NodeLayer, + layer_node_next: impl Fn( + &NodeRef>, + ) -> Option>>, + stacked_node_next: impl Fn( + &NodeRef>, + ) -> Option>>, + layer_list_iter: impl Fn(&LinkedList>) -> LI, + stacked_list_iter: impl Fn(&LinkedList>) -> SI, + ) where + LI: Iterator>>, + SI: Iterator>>, + { + fn node_viable(n: &(impl Node + ?Sized)) -> bool { + n.node_visible() && n.node_accepts_focus() + } + + let current = self.keyboard_node.get(); + let Some(output) = current.node_output() else { + return; + }; + let current_layer = current.node_layer(); + match ¤t_layer { + NodeLayerLink::Layer0(l) + | NodeLayerLink::Layer1(l) + | NodeLayerLink::Layer2(l) + | NodeLayerLink::Layer3(l) => { + if let Some(n) = layer_node_next(l) + && node_viable(&**n) + { + n.deref() + .clone() + .node_do_focus(self, Direction::Unspecified); + self.maybe_schedule_warp_mouse_to_focus(); + return; + } + } + NodeLayerLink::Stacked(l) | NodeLayerLink::StackedAboveLayers(l) => { + if let Some(n) = stacked_node_next(l) + && node_viable(&**n) + && n.node_output().map(|o| o.id) == Some(output.id) + { + n.deref() + .clone() + .node_do_focus(self, Direction::Unspecified); + self.maybe_schedule_warp_mouse_to_focus(); + return; + } + } + NodeLayerLink::Display => {} + NodeLayerLink::Output => {} + NodeLayerLink::Workspace => {} + NodeLayerLink::Tiled => {} + NodeLayerLink::Fullscreen => {} + NodeLayerLink::Lock => {} + NodeLayerLink::InputMethod => {} + } + let handle_layer_shell = |l: &LinkedList>| { + for n in layer_list_iter(l) { + if node_viable(&**n) { + return Some(n.deref().clone() as Rc); + } + } + None + }; + let handle_stacked = |l: &LinkedList>| { + for n in stacked_list_iter(l) { + if node_viable(&**n) && n.node_output().map(|o| o.id) == Some(output.id) { + return Some(n.deref().clone() as Rc); + } + } + None + }; + let ws = output.workspace.get(); + let first = next_layer(current_layer.layer()); + let mut layer = first; + loop { + let node = match layer { + NodeLayer::Display => None, + NodeLayer::Layer0 => handle_layer_shell(&output.layers[0]), + NodeLayer::Layer1 => handle_layer_shell(&output.layers[1]), + NodeLayer::Output => None, + NodeLayer::Workspace => { + if let Some(ws) = &ws + && ws.container_visible() + { + self.focus_node(ws.clone()); + self.maybe_schedule_warp_mouse_to_focus(); + return; + } + None + } + NodeLayer::Tiled => ws + .as_ref() + .and_then(|w| w.container.get()) + .map(|n| n as Rc), + NodeLayer::Fullscreen => ws + .as_ref() + .and_then(|w| w.fullscreen.get()) + .map(|n| n as Rc), + NodeLayer::Stacked => handle_stacked(&self.state.root.stacked), + NodeLayer::Layer2 => handle_layer_shell(&output.layers[2]), + NodeLayer::Layer3 => handle_layer_shell(&output.layers[3]), + NodeLayer::StackedAboveLayers => { + handle_stacked(&self.state.root.stacked_above_layers) + } + NodeLayer::Lock => None, + NodeLayer::InputMethod => None, + }; + if let Some(n) = node { + if node_viable(&*n) { + n.node_do_focus(self, Direction::Unspecified); + self.maybe_schedule_warp_mouse_to_focus(); + return; + } + } + layer = next_layer(layer); + if layer == first { + return; + } + } + } + + pub fn focus_layer_below(self: &Rc) { + self.focus_layer_rel( + |l| l.prev(), + |n| n.prev(), + |n| n.prev(), + |l| l.rev_iter(), + |l| l.rev_iter(), + ); + } + + pub fn focus_layer_above(self: &Rc) { + self.focus_layer_rel( + |l| l.next(), + |n| n.next(), + |n| n.next(), + |l| l.iter(), + |l| l.iter(), + ); + } + + pub fn toggle_focus_float_tiled(self: &Rc) { + let current = self.keyboard_node.get(); + match current.node_layer().layer() { + NodeLayer::Tiled | NodeLayer::Fullscreen => self.focus_floats(), + _ => self.focus_tiles(), + } + self.maybe_schedule_warp_mouse_to_focus(); + } + + pub fn focus_floats(self: &Rc) { + let current = self.keyboard_node.get(); + if current.node_layer().layer() == NodeLayer::Stacked { + return; + } + let Some(output) = current.node_output() else { + return; + }; + let Some(ws) = output.workspace.get() else { + return; + }; + if let Some(child) = ws + .stacked + .rev_iter() + .filter_map(|node| (*node).clone().node_into_float()) + .find_map(|float| float.child.get()) + { + child.node_do_focus(self, Direction::Unspecified); + } + } + + pub fn focus_tiles(self: &Rc) { + let current = self.keyboard_node.get(); + if matches!( + current.node_layer().layer(), + NodeLayer::Tiled | NodeLayer::Fullscreen, + ) { + return; + } + let Some(output) = current.node_output() else { + return; + }; + let Some(ws) = output.workspace.get() else { + return; + }; + let node = match ws.fullscreen.get() { + Some(fs) => fs as Rc, + _ => match ws.container.get() { + Some(c) => c, + _ => return, + }, + }; + if node.node_visible() && node.node_accepts_focus() { + node.node_do_focus(self, Direction::Unspecified); + self.maybe_schedule_warp_mouse_to_focus(); + } + } +}