1
0
Fork 0
forked from wry/wry

wl-seat: split focus navigation

This commit is contained in:
kossLAN 2026-05-29 21:58:14 -04:00
parent c4e9011714
commit c5dd462a6e
No known key found for this signature in database
2 changed files with 477 additions and 461 deletions

View file

@ -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<Self>) {
let kb_node = self.keyboard_node.get();
if let Some(tl) = kb_node.node_toplevel() {
tl.tl_close();
}
}
pub fn move_focus(self: &Rc<Self>, 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<Self>) {
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<Self>) {
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<Self>, 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<Rc<dyn Node>> {
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<FocusHistoryData>) -> Option<NodeRef<FocusHistoryData>>,
first: impl FnOnce(&LinkedList<FocusHistoryData>) -> Option<NodeRef<FocusHistoryData>>,
) -> Option<(Rc<dyn Node>, 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<Self>,
next: impl Fn(&NodeRef<FocusHistoryData>) -> Option<NodeRef<FocusHistoryData>>,
first: impl FnOnce(&LinkedList<FocusHistoryData>) -> Option<NodeRef<FocusHistoryData>>,
) {
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>) {
self.focus_history(|s| s.prev(), |l| l.last());
}
pub fn focus_next(self: &Rc<Self>) {
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<LI, SI>(
self: &Rc<Self>,
next_layer: impl Fn(NodeLayer) -> NodeLayer,
layer_node_next: impl Fn(
&NodeRef<Rc<ZwlrLayerSurfaceV1>>,
) -> Option<NodeRef<Rc<ZwlrLayerSurfaceV1>>>,
stacked_node_next: impl Fn(
&NodeRef<Rc<dyn StackedNode>>,
) -> Option<NodeRef<Rc<dyn StackedNode>>>,
layer_list_iter: impl Fn(&LinkedList<Rc<ZwlrLayerSurfaceV1>>) -> LI,
stacked_list_iter: impl Fn(&LinkedList<Rc<dyn StackedNode>>) -> SI,
) where
LI: Iterator<Item = NodeRef<Rc<ZwlrLayerSurfaceV1>>>,
SI: Iterator<Item = NodeRef<Rc<dyn StackedNode>>>,
{
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 &current_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<Rc<ZwlrLayerSurfaceV1>>| {
for n in layer_list_iter(l) {
if node_viable(&**n) {
return Some(n.deref().clone() as Rc<dyn Node>);
}
}
None
};
let handle_stacked = |l: &LinkedList<Rc<dyn StackedNode>>| {
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<dyn Node>);
}
}
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<dyn Node>),
NodeLayer::Fullscreen => ws
.as_ref()
.and_then(|w| w.fullscreen.get())
.map(|n| n as Rc<dyn Node>),
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>) {
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>) {
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<Self>) {
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<Self>) {
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<Self>) {
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<dyn Node>,
_ => 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<Self>,
origin: &Rc<WlSurface>,

471
src/ifs/wl_seat/focus.rs Normal file
View file

@ -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<Self>) {
let kb_node = self.keyboard_node.get();
if let Some(tl) = kb_node.node_toplevel() {
tl.tl_close();
}
}
pub fn move_focus(self: &Rc<Self>, 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<Self>) {
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<Self>) {
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<Self>, 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<Rc<dyn Node>> {
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<FocusHistoryData>) -> Option<NodeRef<FocusHistoryData>>,
first: impl FnOnce(&LinkedList<FocusHistoryData>) -> Option<NodeRef<FocusHistoryData>>,
) -> Option<(Rc<dyn Node>, 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<Self>,
next: impl Fn(&NodeRef<FocusHistoryData>) -> Option<NodeRef<FocusHistoryData>>,
first: impl FnOnce(&LinkedList<FocusHistoryData>) -> Option<NodeRef<FocusHistoryData>>,
) {
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>) {
self.focus_history(|s| s.prev(), |l| l.last());
}
pub fn focus_next(self: &Rc<Self>) {
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<LI, SI>(
self: &Rc<Self>,
next_layer: impl Fn(NodeLayer) -> NodeLayer,
layer_node_next: impl Fn(
&NodeRef<Rc<ZwlrLayerSurfaceV1>>,
) -> Option<NodeRef<Rc<ZwlrLayerSurfaceV1>>>,
stacked_node_next: impl Fn(
&NodeRef<Rc<dyn StackedNode>>,
) -> Option<NodeRef<Rc<dyn StackedNode>>>,
layer_list_iter: impl Fn(&LinkedList<Rc<ZwlrLayerSurfaceV1>>) -> LI,
stacked_list_iter: impl Fn(&LinkedList<Rc<dyn StackedNode>>) -> SI,
) where
LI: Iterator<Item = NodeRef<Rc<ZwlrLayerSurfaceV1>>>,
SI: Iterator<Item = NodeRef<Rc<dyn StackedNode>>>,
{
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 &current_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<Rc<ZwlrLayerSurfaceV1>>| {
for n in layer_list_iter(l) {
if node_viable(&**n) {
return Some(n.deref().clone() as Rc<dyn Node>);
}
}
None
};
let handle_stacked = |l: &LinkedList<Rc<dyn StackedNode>>| {
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<dyn Node>);
}
}
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<dyn Node>),
NodeLayer::Fullscreen => ws
.as_ref()
.and_then(|w| w.fullscreen.get())
.map(|n| n as Rc<dyn Node>),
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>) {
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>) {
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<Self>) {
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<Self>) {
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<Self>) {
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<dyn Node>,
_ => 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();
}
}
}