tiling: Allow orientation of active container to be swapped

This commit is contained in:
Victoria Brekenfeld 2022-03-29 14:41:09 +02:00
parent 2c311c67d1
commit b3ff2a7ca3
9 changed files with 105 additions and 18 deletions

View file

@ -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,
)

View file

@ -12,6 +12,7 @@ use xkbcommon::xkb;
#[derive(Debug, Deserialize)]
pub struct Config {
pub key_bindings: HashMap<KeyPattern, Action>,
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),
}

View file

@ -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")

View file

@ -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(

View file

@ -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<dyn Iterator<Item = &'a Window> + 'a>,
) {
let _ = (orientation, seat, space, focus_stack);
}
fn maximize_request(&mut self, space: &mut Space, window: &Window, output: &Output) {
let _ = (space, window, output);
}

View file

@ -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<dyn Iterator<Item = &'a Window> + '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::<RefCell<OutputInfo>>()
.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())

View file

@ -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<Workspace> = MaybeUninit::uninit();
impl Shell {
fn new(popup_grab: Rc<Cell<Option<PopupGrab>>>) -> Self {
fn new(config: &Config, popup_grab: Rc<Cell<Option<PopupGrab>>>) -> 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)
}
}

View file

@ -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)

View file

@ -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,