1
0
Fork 0
forked from wry/wry

config: add focus-below and focus-above actions

This commit is contained in:
Julian Orth 2025-07-19 22:01:50 +02:00
parent c034ea7604
commit bd85db5b59
12 changed files with 211 additions and 19 deletions

View file

@ -54,7 +54,7 @@ use {
Axis, Direction, Workspace,
client::{Client as ConfigClient, ClientMatcher},
input::{
FocusFollowsMouseMode, InputDevice, Seat, Timeline,
FocusFollowsMouseMode, InputDevice, LayerDirection, Seat, Timeline,
acceleration::{ACCEL_PROFILE_ADAPTIVE, ACCEL_PROFILE_FLAT, AccelProfile},
capability::{
CAP_GESTURE, CAP_KEYBOARD, CAP_POINTER, CAP_SWITCH, CAP_TABLET_PAD,
@ -2185,6 +2185,19 @@ impl ConfigProxyHandler {
Ok(())
}
fn handle_seat_focus_layer_rel(
&self,
seat: Seat,
direction: LayerDirection,
) -> Result<(), CphError> {
let seat = self.get_seat(seat)?;
match direction {
LayerDirection::Below => seat.focus_layer_below(),
LayerDirection::Above => seat.focus_layer_above(),
}
Ok(())
}
fn spaces_change(&self) {
struct V;
impl NodeVisitorBase for V {
@ -3039,6 +3052,9 @@ impl ConfigProxyHandler {
} => self
.handle_seat_focus_history_set_same_workspace(seat, same_workspace)
.wrn("seat_focus_history_set_same_workspace")?,
ClientMessage::SeatFocusLayerRel { seat, direction } => self
.handle_seat_focus_layer_rel(seat, direction)
.wrn("seat_focus_layer_rel")?,
}
Ok(())
}

View file

@ -70,6 +70,7 @@ use {
dnd_icon::DndIcon,
tray::{DynTrayItem, TrayItemId},
xdg_surface::xdg_popup::XdgPopup,
zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
},
xdg_toplevel_drag_v1::XdgToplevelDragV1,
},
@ -80,9 +81,10 @@ use {
rect::Rect,
state::{DeviceHandlerData, State},
tree::{
ContainerNode, ContainerSplit, Direction, FoundNode, Node, NodeId, NodeLocation,
OutputNode, ToplevelNode, WorkspaceNode, generic_node_visitor, toplevel_create_split,
toplevel_parent_container, toplevel_set_floating, toplevel_set_workspace,
ContainerNode, ContainerSplit, Direction, FoundNode, Node, NodeId, NodeLayer,
NodeLayerLink, NodeLocation, OutputNode, StackedNode, ToplevelNode, WorkspaceNode,
generic_node_visitor, toplevel_create_split, toplevel_parent_container,
toplevel_set_floating, toplevel_set_workspace,
},
utils::{
asyncevent::AsyncEvent,
@ -801,6 +803,139 @@ impl WlSeatGlobal {
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);
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);
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 => 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);
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(),
);
}
fn set_selection_<T, X, S>(
self: &Rc<Self>,
field: &CloneCell<Option<Rc<dyn DynDataSource>>>,

View file

@ -141,22 +141,21 @@ pub enum NodeLayer {
pub enum NodeLayerLink {
Display,
Layer0(#[expect(dead_code)] NodeRef<Rc<ZwlrLayerSurfaceV1>>),
Layer1(#[expect(dead_code)] NodeRef<Rc<ZwlrLayerSurfaceV1>>),
Layer0(NodeRef<Rc<ZwlrLayerSurfaceV1>>),
Layer1(NodeRef<Rc<ZwlrLayerSurfaceV1>>),
Output,
Workspace,
Tiled,
Fullscreen,
Stacked(#[expect(dead_code)] NodeRef<Rc<dyn StackedNode>>),
Layer2(#[expect(dead_code)] NodeRef<Rc<ZwlrLayerSurfaceV1>>),
Layer3(#[expect(dead_code)] NodeRef<Rc<ZwlrLayerSurfaceV1>>),
StackedAboveLayers(#[expect(dead_code)] NodeRef<Rc<dyn StackedNode>>),
Stacked(NodeRef<Rc<dyn StackedNode>>),
Layer2(NodeRef<Rc<ZwlrLayerSurfaceV1>>),
Layer3(NodeRef<Rc<ZwlrLayerSurfaceV1>>),
StackedAboveLayers(NodeRef<Rc<dyn StackedNode>>),
Lock,
InputMethod,
}
impl NodeLayerLink {
#[expect(dead_code)]
pub fn layer(&self) -> NodeLayer {
macro_rules! map {
($($id:ident,)*) => {
@ -186,7 +185,6 @@ impl NodeLayerLink {
}
impl NodeLayer {
#[expect(dead_code)]
pub fn prev(self) -> Self {
if self == NodeLayer::Display {
return NodeLayer::InputMethod;
@ -194,7 +192,6 @@ impl NodeLayer {
Self::from_linear(self.linearize() - 1).unwrap_or(NodeLayer::InputMethod)
}
#[expect(dead_code)]
pub fn next(self) -> Self {
Self::from_linear(self.linearize() + 1).unwrap_or(NodeLayer::Display)
}
@ -216,7 +213,6 @@ pub trait Node: 'static {
let _ = title;
}
#[expect(dead_code)]
fn node_accepts_focus(&self) -> bool {
true
}