config: add focus-below and focus-above actions
This commit is contained in:
parent
c034ea7604
commit
bd85db5b59
12 changed files with 211 additions and 19 deletions
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ¤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);
|
||||
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>>>,
|
||||
|
|
|
|||
16
src/tree.rs
16
src/tree.rs
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue