diff --git a/default-config/src/lib.rs b/default-config/src/lib.rs index 6051b48c..524a0859 100644 --- a/default-config/src/lib.rs +++ b/default-config/src/lib.rs @@ -1,5 +1,5 @@ use i4config::keyboard::mods::{ALT, CTRL, Modifiers, SHIFT}; -use i4config::keyboard::syms::{SYM_Super_L, SYM_h, SYM_j, SYM_k, SYM_l, SYM_plus, SYM_minus, SYM_r}; +use i4config::keyboard::syms::{SYM_Super_L, SYM_h, SYM_j, SYM_k, SYM_l, SYM_plus, SYM_minus, SYM_r, SYM_t}; use i4config::Direction::{Down, Left, Right, Up}; use i4config::{config, shell, Seat, create_seat, input_devices, on_new_input_device}; @@ -23,6 +23,10 @@ fn configure_seat(s: Seat) { s.bind(CTRL | SYM_k, move || s.focus(Up)); s.bind(CTRL | SYM_l, move || s.focus(Right)); + s.bind(CTRL | SYM_t, move || { + s.set_split(s.split().other()); + }); + s.bind(MOD | SHIFT | SYM_h, move || s.move_(Left)); s.bind(MOD | SHIFT | SYM_j, move || s.move_(Down)); s.bind(MOD | SHIFT | SYM_k, move || s.move_(Up)); diff --git a/i4config/src/_private/client.rs b/i4config/src/_private/client.rs index 3fde047a..db8cea35 100644 --- a/i4config/src/_private/client.rs +++ b/i4config/src/_private/client.rs @@ -1,6 +1,6 @@ use crate::_private::ipc::{InitMessage, Request, Response}; use crate::_private::{bincode_ops, logging, Config, ConfigEntry, ConfigEntryGen, VERSION}; -use crate::{Direction, InputDevice, LogLevel, ModifiedKeySym, Seat}; +use crate::{Axis, Direction, InputDevice, LogLevel, ModifiedKeySym, Seat}; use std::cell::{Cell, RefCell}; use std::collections::hash_map::Entry; use std::collections::HashMap; @@ -171,6 +171,21 @@ impl Client { } } + pub fn split(&self, seat: Seat) -> Axis { + let res = self.with_response(|| self.send(&Request::GetSplit { seat })); + match res { + Response::GetSplit { axis } => axis, + _ => { + log::error!("Server did not send a response to a get_split request"); + Axis::Horizontal + }, + } + } + + pub fn set_split(&self, seat: Seat, axis: Axis) { + self.send(&Request::SetSplit { seat, axis }); + } + pub fn create_seat(&self, name: &str) -> Seat { let response = self.with_response(|| self.send(&Request::CreateSeat { name })); match response { diff --git a/i4config/src/_private/ipc.rs b/i4config/src/_private/ipc.rs index 0523abaa..81cf245f 100644 --- a/i4config/src/_private/ipc.rs +++ b/i4config/src/_private/ipc.rs @@ -1,6 +1,6 @@ use crate::keyboard::mods::Modifiers; use crate::keyboard::syms::KeySym; -use crate::{Direction, InputDevice, LogLevel, Seat}; +use crate::{Axis, Direction, InputDevice, LogLevel, Seat}; use bincode::{BorrowDecode, Decode, Encode}; use crate::keyboard::keymap::Keymap; @@ -38,6 +38,13 @@ pub enum Request<'a> { rate: i32, delay: i32, }, + GetSplit { + seat: Seat, + }, + SetSplit { + seat: Seat, + axis: Axis, + }, RemoveSeat { seat: Seat, }, @@ -81,6 +88,7 @@ pub enum Request<'a> { pub enum Response { None, GetSeats { seats: Vec }, + GetSplit { axis: Axis }, GetRepeatRate { rate: i32, delay: i32 }, ParseKeymap { keymap: Keymap, }, CreateSeat { seat: Seat }, diff --git a/i4config/src/lib.rs b/i4config/src/lib.rs index 3c0b24a1..5415afdf 100644 --- a/i4config/src/lib.rs +++ b/i4config/src/lib.rs @@ -56,6 +56,21 @@ impl InputDevice { } } +#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)] +pub enum Axis { + Horizontal, + Vertical, +} + +impl Axis { + pub fn other(self) -> Self { + match self { + Self::Horizontal => Self::Vertical, + Self::Vertical => Self::Horizontal, + } + } +} + impl Seat { #[doc(hidden)] pub fn raw(self) -> u64 { @@ -87,15 +102,25 @@ impl Seat { get!().seat_set_keymap(self, keymap) } - pub fn set_repeat_rate(self, rate: i32, delay: i32) { - get!().seat_set_repeat_rate(self, rate, delay) - } - pub fn repeat_rate(self) -> (i32, i32) { let mut res = (25, 250); (|| res = get!().seat_get_repeat_rate(self))(); res } + + pub fn set_repeat_rate(self, rate: i32, delay: i32) { + get!().seat_set_repeat_rate(self, rate, delay) + } + + pub fn split(self) -> Axis { + let mut res = Axis::Horizontal; + (|| res = get!().split(self))(); + res + } + + pub fn set_split(self, axis: Axis) { + get!().set_split(self, axis) + } } pub fn get_seats() -> Vec { diff --git a/src/config/handler.rs b/src/config/handler.rs index 26d5ff95..1aa82510 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -7,13 +7,14 @@ use thiserror::Error; use i4config::_private::bincode_ops; use i4config::_private::ipc::{Request, Response}; use i4config::keyboard::keymap::Keymap; -use i4config::{Direction, InputDevice, Keyboard, LogLevel, Mouse, Seat}; +use i4config::{Axis, Direction, InputDevice, Keyboard, LogLevel, Mouse, Seat}; use i4config::keyboard::mods::Modifiers; use i4config::keyboard::syms::KeySym; use crate::{ErrorFmt, NumCell, State}; use crate::backend::{KeyboardId, MouseId}; use crate::ifs::wl_seat::WlSeatGlobal; use crate::state::DeviceHandlerData; +use crate::tree::ContainerSplit; use crate::utils::copyhashmap::CopyHashMap; use crate::utils::debug_fn::debug_fn; use crate::utils::stack::Stack; @@ -181,6 +182,22 @@ impl ConfigProxyHandler { Ok(()) } + fn handle_get_split(&self, seat: Seat) -> Result<(), GetSplitError> { + let seat = self.get_seat(seat)?; + self.send(&Request::Response { + response: Response::GetSplit { + axis: seat.get_split().unwrap_or(ContainerSplit::Horizontal).into(), + } + }); + Ok(()) + } + + fn handle_set_split(&self, seat: Seat, axis: Axis) -> Result<(), SetSplitError> { + let seat = self.get_seat(seat)?; + seat.set_split(axis.into()); + Ok(()) + } + fn handle_add_shortcut(&self, seat: Seat, mods: Modifiers, sym: KeySym) -> Result<(), AddShortcutError> { let seat = self.get_seat(seat)?; seat.add_shortcut(mods, sym); @@ -245,6 +262,8 @@ impl ConfigProxyHandler { Request::SeatGetRepeatRate { seat } => self.handle_get_repeat_rate(seat)?, Request::SeatSetRepeatRate { seat, rate, delay } => self.handle_set_repeat_rate(seat, rate, delay)?, Request::SetSeat { device, seat } => self.handle_set_seat(device, seat)?, + Request::GetSplit { seat } => self.handle_get_split(seat)?, + Request::SetSplit { seat, axis } => self.handle_set_split(seat, axis)?, Request::AddShortcut { seat, mods, @@ -285,6 +304,10 @@ enum CphError { SeatSetRepeatRateError(#[from] SeatSetRepeatRateError), #[error("Could not process a `focus` request")] FocusError(#[from] FocusError), + #[error("Could not process a `set_split` request")] + SetSplitError(#[from] SetSplitError), + #[error("Could not process a `get_split` request")] + GetSplitError(#[from] GetSplitError), #[error("Device {0:?} does not exist")] DeviceDoesNotExist(InputDevice), #[error("Device {0:?} does not exist")] @@ -368,3 +391,17 @@ enum FocusError { CphError(#[from] Box), } efrom!(FocusError, CphError); + +#[derive(Debug, Error)] +enum SetSplitError { + #[error(transparent)] + CphError(#[from] Box), +} +efrom!(SetSplitError, CphError); + +#[derive(Debug, Error)] +enum GetSplitError { + #[error(transparent)] + CphError(#[from] Box), +} +efrom!(GetSplitError, CphError); diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index a8d62fbd..04702a40 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -22,7 +22,7 @@ use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel; use crate::ifs::wl_surface::WlSurface; use crate::leaks::Tracker; use crate::object::{Object, ObjectId}; -use crate::tree::{FloatNode, FoundNode, Node}; +use crate::tree::{ContainerSplit, FloatNode, FoundNode, Node}; use crate::utils::asyncevent::AsyncEvent; use crate::utils::buffd::MsgParser; use crate::utils::buffd::MsgParserError; @@ -45,7 +45,7 @@ use std::ops::DerefMut; use std::rc::Rc; use thiserror::Error; use uapi::{c, Errno, OwnedFd}; -use i4config::Direction; +use i4config::{ Direction}; use crate::async_engine::SpawnedFuture; const POINTER: u32 = 1; @@ -190,6 +190,14 @@ impl WlSeatGlobal { } } + pub fn get_split(&self) -> Option { + self.keyboard_node.get().get_parent_split() + } + + pub fn set_split(&self, axis: ContainerSplit) { + self.keyboard_node.get().set_parent_split(axis) + } + pub fn get_rate(&self) -> (i32, i32) { self.repeat_rate.get() } diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index f554df4c..a4406cc6 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -15,7 +15,7 @@ use crate::object::Object; use crate::pixman::Region; use crate::rect::Rect; use crate::render::Renderer; -use crate::tree::{Node, NodeId}; +use crate::tree::{ContainerSplit, Node, NodeId}; use crate::utils::buffd::{MsgParser, MsgParserError}; use crate::utils::clonecell::CloneCell; use crate::utils::linkedlist::LinkedList; @@ -31,7 +31,7 @@ use std::mem; use std::ops::{Deref, DerefMut}; use std::rc::Rc; use thiserror::Error; -use i4config::Direction; +use i4config::{ Direction}; use crate::backend::{KeyState, ScrollAxis}; #[allow(dead_code)] @@ -610,6 +610,14 @@ impl Node for WlSurface { self.seat_state.destroy_node(self); } + fn get_parent_split(&self) -> Option { + self.xdg.get().and_then(|x| x.get_split()) + } + + fn set_parent_split(&self, split: ContainerSplit) { + self.xdg.get().map(|x| x.set_split(split)); + } + fn move_focus(&self, seat: &Rc, direction: Direction) { let xdg = match self.xdg.get() { Some(x) => x, diff --git a/src/ifs/wl_surface/xdg_surface.rs b/src/ifs/wl_surface/xdg_surface.rs index 8ea351c8..f67ce90d 100644 --- a/src/ifs/wl_surface/xdg_surface.rs +++ b/src/ifs/wl_surface/xdg_surface.rs @@ -12,7 +12,7 @@ use crate::ifs::xdg_wm_base::XdgWmBase; use crate::leaks::Tracker; use crate::object::Object; use crate::rect::Rect; -use crate::tree::{FindTreeResult, FoundNode, Node, WorkspaceNode}; +use crate::tree::{ContainerSplit, FindTreeResult, FoundNode, Node, WorkspaceNode}; use crate::utils::buffd::MsgParser; use crate::utils::buffd::MsgParserError; use crate::utils::clonecell::CloneCell; @@ -25,7 +25,7 @@ use std::cell::Cell; use std::fmt::Debug; use std::rc::Rc; use thiserror::Error; -use i4config::Direction; +use i4config::{Direction}; #[allow(dead_code)] const NOT_CONSTRUCTED: u32 = 1; @@ -75,6 +75,14 @@ struct PendingXdgSurfaceData { } pub trait XdgSurfaceExt: Debug { + fn get_split(&self) -> Option { + None + } + + fn set_split(&self, split: ContainerSplit) { + let _ = split; + } + fn move_focus(self: Rc, seat: &Rc, direction: Direction) { let _ = seat; let _ = direction; @@ -142,6 +150,14 @@ impl XdgSurface { } } + pub fn get_split(&self) -> Option { + self.ext.get().and_then(|e| e.get_split()) + } + + pub fn set_split(&self, split: ContainerSplit) { + self.ext.get().map(|e| e.set_split(split)); + } + pub fn move_focus(&self, seat: &Rc, direction: Direction) { let ext = match self.ext.get() { None => return, diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs index 54ea951f..42aaeeca 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs @@ -8,7 +8,7 @@ use crate::leaks::Tracker; use crate::object::Object; use crate::rect::Rect; use crate::render::Renderer; -use crate::tree::{ContainerNode, FindTreeResult}; +use crate::tree::{ContainerNode, ContainerSplit, FindTreeResult}; use crate::tree::{FloatNode, FoundNode, Node, NodeId, ToplevelNodeId, WorkspaceNode}; use crate::utils::buffd::MsgParser; use crate::utils::buffd::MsgParserError; @@ -26,7 +26,7 @@ use std::mem; use std::ops::Deref; use std::rc::Rc; use thiserror::Error; -use i4config::Direction; +use i4config::{Direction}; #[derive(Copy, Clone, Debug, FromPrimitive)] pub enum ResizeEdge { @@ -484,6 +484,14 @@ impl Node for XdgToplevel { } impl XdgSurfaceExt for XdgToplevel { + fn get_split(&self) -> Option { + self.parent_node.get().and_then(|p| p.get_split()) + } + + fn set_split(&self, split: ContainerSplit) { + self.parent_node.get().map(|p| p.set_split(split)); + } + fn move_focus(self: Rc, seat: &Rc, direction: Direction) { let pn = match self.parent_node.get() { Some(pn) => pn, diff --git a/src/tree/container.rs b/src/tree/container.rs index f36b6856..452b3826 100644 --- a/src/tree/container.rs +++ b/src/tree/container.rs @@ -14,7 +14,7 @@ use std::fmt::{Debug, Formatter}; use std::mem; use std::ops::DerefMut; use std::rc::Rc; -use i4config::Direction; +use i4config::{Axis, Direction}; #[allow(dead_code)] #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -23,6 +23,24 @@ pub enum ContainerSplit { Vertical, } +impl From for ContainerSplit { + fn from(a: Axis) -> Self { + match a { + Axis::Horizontal => Self::Horizontal, + Axis::Vertical => Self::Vertical, + } + } +} + +impl Into for ContainerSplit { + fn into(self) -> Axis { + match self { + ContainerSplit::Horizontal => Axis::Horizontal, + ContainerSplit::Vertical => Axis::Vertical, + } + } +} + #[allow(dead_code)] #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum ContainerFocus { @@ -422,6 +440,16 @@ impl Node for ContainerNode { self.seat_state.destroy_node(self); } + fn get_split(&self) -> Option { + Some(self.split.get()) + } + + fn set_split(&self, split: ContainerSplit) { + self.split.set(split); + self.update_content_size(); + self.apply_factors(1.0); + } + fn do_focus(self: Rc, seat: &Rc, direction: Direction) { let node = match direction { Direction::Left => self.children.last(), @@ -539,7 +567,6 @@ impl Node for ContainerNode { }; return; }; - log::info!("op = {:?}", kind); seat_data.op = Some(SeatOp { child, kind }) } else if state == KeyState::Released { let op = seat_data.op.take().unwrap(); diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 33a5d16b..96980a3a 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -17,7 +17,7 @@ use std::cell::{Cell, RefCell}; use std::fmt::{Debug, Display, Formatter}; use std::ops::Deref; use std::rc::Rc; -use i4config::Direction; +use i4config::{Direction}; pub use workspace::*; mod container; @@ -67,6 +67,22 @@ pub trait Node { fn seat_state(&self) -> &NodeSeatState; fn destroy_node(&self, detach: bool); + fn get_parent_split(&self) -> Option { + None + } + + fn set_parent_split(&self, split: ContainerSplit) { + let _ = split; + } + + fn get_split(&self) -> Option { + None + } + + fn set_split(&self, split: ContainerSplit) { + let _ = split; + } + fn do_focus(self: Rc, seat: &Rc, direction: Direction) { let _ = seat; let _ = direction;