diff --git a/config.ron b/config.ron index 1fcdea5d..ebc4ac26 100644 --- a/config.ron +++ b/config.ron @@ -27,6 +27,9 @@ (modifiers: [Logo], key: "Right"): Focus(Right), (modifiers: [Logo], key: "Up"): Focus(Up), (modifiers: [Logo], key: "Down"): Focus(Down), + (modifiers: [Logo], key: "v"): Orientation(Vertical), + (modifiers: [Logo], key: "h"): Orientation(Horizontal), (modifiers: [Ctrl], key: "Return"): Spawn("gnome-terminal"), - } + }, + workspace_mode: OutputBound, ) \ No newline at end of file diff --git a/src/config.rs b/src/config.rs index 62005091..c8946584 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,6 +12,7 @@ use xkbcommon::xkb; #[derive(Debug, Deserialize)] pub struct Config { pub key_bindings: HashMap, + pub workspace_mode: crate::shell::Mode, } impl Config { @@ -39,6 +40,7 @@ impl Config { Config { key_bindings: HashMap::new(), + workspace_mode: crate::shell::Mode::global(), } } } @@ -180,6 +182,7 @@ pub enum Action { Workspace(u8), MoveToWorkspace(u8), Focus(FocusAction), + Orientation(crate::shell::layout::Orientation), Spawn(String), } diff --git a/src/input/mod.rs b/src/input/mod.rs index 5dcebd72..95f3c9ed 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -283,6 +283,15 @@ impl Common { Action::Focus(focus) => match focus { _ => { /* TODO */ } }, + Action::Orientation(orientation) => { + let output = active_output(seat, &self); + self.shell.set_orientation( + &seat, + &output, + *orientation, + ); + return FilterResult::Intercept(()); + } Action::Spawn(command) => { if let Err(err) = std::process::Command::new("/bin/sh") diff --git a/src/shell/handler.rs b/src/shell/handler.rs index 16aae0bd..dd4d0729 100644 --- a/src/shell/handler.rs +++ b/src/shell/handler.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only -use crate::{input::active_output, state::State, utils::SurfaceDropNotifier}; +use crate::{config::Config, input::active_output, state::State, utils::SurfaceDropNotifier}; use smithay::{ backend::renderer::utils::on_commit_buffer_handler, desktop::{ @@ -27,7 +27,7 @@ use smithay::{ }; use std::{cell::Cell, rc::Rc, sync::Mutex}; -pub fn init_shell(display: &mut Display) -> super::Shell { +pub fn init_shell(config: &Config, display: &mut Display) -> super::Shell { compositor_init( display, move |surface, mut ddata| { @@ -234,7 +234,7 @@ pub fn init_shell(display: &mut Display) -> super::Shell { None, ); - super::Shell::new(popup_grab) + super::Shell::new(config, popup_grab) } fn check_grab_preconditions( diff --git a/src/shell/layout/mod.rs b/src/shell/layout/mod.rs index b4573719..124093e6 100644 --- a/src/shell/layout/mod.rs +++ b/src/shell/layout/mod.rs @@ -14,6 +14,12 @@ pub mod combined; pub mod floating; pub mod tiling; +#[derive(Debug, serde::Deserialize, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Orientation { + Horizontal, + Vertical, +} + pub trait Layout { fn map_window<'a>( &mut self, @@ -25,6 +31,15 @@ pub trait Layout { fn refresh(&mut self, space: &mut Space); //fn unmap_window(&mut self, space: &mut Space, window: &Window); + fn update_orientation<'a>( + &mut self, + orientation: Orientation, + seat: &Seat, + space: &mut Space, + focus_stack: Box + 'a>, + ) { + let _ = (orientation, seat, space, focus_stack); + } fn maximize_request(&mut self, space: &mut Space, window: &Window, output: &Output) { let _ = (space, window, output); } diff --git a/src/shell/layout/tiling.rs b/src/shell/layout/tiling.rs index aaee5ed1..bb6ab2fb 100644 --- a/src/shell/layout/tiling.rs +++ b/src/shell/layout/tiling.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only -use crate::shell::layout::Layout; +use crate::shell::layout::{Layout, Orientation}; use id_tree::{InsertBehavior, MoveBehavior, Node, NodeId, NodeIdError, RemoveBehavior, Tree}; use smithay::{ desktop::{layer_map_for_output, Kind, Space, Window}, @@ -16,12 +16,6 @@ pub struct TilingLayout { gaps: (i32, i32), } -#[derive(Debug)] -pub enum Orientation { - Horizontal, - Vertical, -} - #[derive(Debug)] pub enum Data { Fork { @@ -143,6 +137,50 @@ impl Layout for TilingLayout { self.refresh(space); } + fn update_orientation<'a>( + &mut self, + new_orientation: Orientation, + seat: &Seat, + space: &mut Space, + mut focus_stack: Box + 'a>, + ) { + { + let output = super::output_from_seat(seat, space); + output + .user_data() + .insert_if_missing(|| RefCell::new(OutputInfo::default())); + let mut output_info = output + .user_data() + .get::>() + .unwrap() + .borrow_mut(); + let tree = &mut output_info.trees.entry(self.idx).or_insert_with(Tree::new); + + let last_active = focus_stack + .find_map(|window| tree.root_node_id() + .and_then(|root| tree.traverse_pre_order_ids(root).unwrap() + .find(|id| matches!(tree.get(id).map(|n| n.data()), Ok(Data::Window(w)) if w == window)) + ) + ); + + if let Some(ref node_id) = last_active { + let mut node_id = node_id.clone(); + while let Some(parent_id) = tree.get(&node_id).unwrap().parent().cloned() { + if let &mut Data::Fork { + ref mut orientation, + .. + } = tree.get_mut(&parent_id).unwrap().data_mut() + { + *orientation = new_orientation; + break; + } + node_id = parent_id; + } + } + } + self.refresh(space); + } + fn refresh(&mut self, space: &mut Space) { while let Some(dead_windows) = Some(update_space_positions(self.idx, space, self.gaps)).filter(|v| !v.is_empty()) diff --git a/src/shell/mod.rs b/src/shell/mod.rs index af9f13dc..1bea84db 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only +use crate::config::Config; pub use smithay::{ desktop::{PopupGrab, PopupManager, PopupUngrabStrategy, Space, Window}, reexports::wayland_server::protocol::wl_surface::WlSurface, @@ -33,10 +34,13 @@ impl ActiveWorkspace { } } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Debug, serde::Deserialize, PartialEq, Eq, Clone, Copy)] pub enum Mode { OutputBound, - Global { active: usize }, + Global { + #[serde(default)] + active: usize, + }, } impl Mode { @@ -60,11 +64,11 @@ pub struct Shell { const UNINIT_SPACE: MaybeUninit = MaybeUninit::uninit(); impl Shell { - fn new(popup_grab: Rc>>) -> Self { + fn new(config: &Config, popup_grab: Rc>>) -> Self { Shell { popups: PopupManager::new(None), popup_grab, - mode: Mode::global(), + mode: config.workspace_mode, outputs: Vec::new(), spaces: unsafe { let mut spaces = [UNINIT_SPACE; MAX_WORKSPACES]; @@ -392,4 +396,14 @@ impl Shell { } } } + + pub fn set_orientation( + &mut self, + seat: &Seat, + output: &Output, + orientation: layout::Orientation, + ) { + self.active_space_mut(output) + .update_orientation(seat, orientation) + } } diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index f7417811..eba08f32 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -63,6 +63,11 @@ impl Workspace { self.space.refresh(); } + pub fn update_orientation(&mut self, seat: &Seat, orientation: layout::Orientation) { + self.layout + .update_orientation(orientation, seat, &mut self.space, self.focus_stack.iter()) + } + pub fn maximize_request(&mut self, window: &Window, output: &Output) { self.layout .maximize_request(&mut self.space, window, output) diff --git a/src/state.rs b/src/state.rs index 4d737300..ab72f4c8 100644 --- a/src/state.rs +++ b/src/state.rs @@ -135,9 +135,10 @@ impl State { handle: LoopHandle<'static, State>, log: LogState, ) -> State { + let config = Config::load(); init_shm_global(&mut display, vec![], None); init_xdg_output_manager(&mut display, None); - let shell = init_shell(&mut display); + let shell = init_shell(&config, &mut display); let initial_seat = crate::input::add_seat(&mut display, "seat-0".into()); init_data_device( &mut display, @@ -170,8 +171,7 @@ impl State { State { common: Common { - config: Config::load(), - + config, display: Rc::new(RefCell::new(display)), socket, event_loop_handle: handle,