From 38d8df809ec949953373133918ddfdb0710866a1 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Thu, 7 Jul 2022 22:41:02 +0200 Subject: [PATCH 1/3] floating: Remember window sizes and locations --- src/shell/layout/floating/mod.rs | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/shell/layout/floating/mod.rs b/src/shell/layout/floating/mod.rs index 17be1f2e..2091b6a8 100644 --- a/src/shell/layout/floating/mod.rs +++ b/src/shell/layout/floating/mod.rs @@ -5,7 +5,7 @@ use smithay::{ reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::{ ResizeEdge, State as XdgState, }, - utils::IsAlive, + utils::{IsAlive, Rectangle, Logical}, wayland::{ compositor::with_states, output::Output, @@ -29,6 +29,12 @@ pub struct FloatingLayout { pub windows: HashSet, } +#[derive(Default)] +pub struct WindowUserDataInner { + last_geometry: Rectangle, +} +pub type WindowUserData = Mutex; + impl FloatingLayout { pub fn new() -> FloatingLayout { Default::default() @@ -53,11 +59,17 @@ impl FloatingLayout { } fn map_window_internal(&mut self, space: &mut Space, window: Window, output: &Output) { + let last_geometry = window.user_data().get::().map(|u| u.lock().unwrap().last_geometry); let mut win_geo = window.geometry(); + let layers = layer_map_for_output(&output); let geometry = layers.non_exclusive_zone(); let mut geo_updated = false; + if let Some(size) = last_geometry.clone().map(|g| g.size) { + geo_updated = win_geo.size == size; + win_geo.size = size; + } { let (min_size, max_size) = with_states(window.toplevel().wl_surface(), |states| { let attrs = states @@ -100,10 +112,10 @@ impl FloatingLayout { } } - let position = ( + let position = last_geometry.map(|g| g.loc).unwrap_or_else(|| ( geometry.loc.x + (geometry.size.w / 2) - (win_geo.size.w / 2) + win_geo.loc.x, geometry.loc.y + (geometry.size.h / 2) - (win_geo.size.h / 2) + win_geo.loc.y, - ); + ).into()); #[allow(irrefutable_let_patterns)] if let Kind::Xdg(xdg) = &window.toplevel() { @@ -124,6 +136,15 @@ impl FloatingLayout { } pub fn unmap_window(&mut self, space: &mut Space, window: &Window) { + if let Some(location) = space.window_location(window) { + let user_data = window.user_data(); + user_data.insert_if_missing(|| WindowUserData::default()); + user_data.get::().unwrap().lock().unwrap().last_geometry = Rectangle::from_loc_and_size( + location, + window.geometry().size, + ); + } + space.unmap_window(window); self.pending_windows.retain(|w| w != window); self.windows.remove(window); From 06da5cc9b61d2265e66f5ab40a49ba92d0a772ec Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Thu, 7 Jul 2022 22:41:17 +0200 Subject: [PATCH 2/3] workspace: Allow tiling to be toggled --- src/shell/workspace.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index 56e7406b..5a7617ea 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -24,6 +24,7 @@ pub struct Workspace { pub space: Space, pub tiling_layer: TilingLayout, pub floating_layer: FloatingLayout, + tiling_enabled: bool, pub fullscreen: HashMap, pub handle: WorkspaceHandle, } @@ -35,6 +36,7 @@ impl Workspace { space: Space::new(None), tiling_layer: TilingLayout::new(), floating_layer: FloatingLayout::new(), + tiling_enabled: true, fullscreen: HashMap::new(), handle, } @@ -172,4 +174,36 @@ impl Workspace { } self.fullscreen.get(&output.name()).filter(|w| w.alive()) } + + pub fn toggle_tiling(&mut self, seat: &Seat) { + if self.tiling_enabled { + for window in self.tiling_layer.windows.clone().into_iter() { + self.tiling_layer.unmap_window(&mut self.space, &window); + self.floating_layer.map_window(&mut self.space, window, seat); + } + self.tiling_enabled = false; + } else { + let focus_stack = self.focus_stack(seat); + for window in self.floating_layer.windows.clone().into_iter() { + self.floating_layer.unmap_window(&mut self.space, &window); + self.tiling_layer.map_window(&mut self.space, window, seat, focus_stack.iter()) + } + self.tiling_enabled = true; + } + } + + pub fn toggle_floating_window(&mut self, seat: &Seat) { + if self.tiling_enabled { + if let Some(window) = self.focus_stack(seat).iter().next().cloned() { + if self.tiling_layer.windows.contains(&window) { + self.tiling_layer.unmap_window(&mut self.space, &window); + self.floating_layer.map_window(&mut self.space, window, seat); + } else if self.floating_layer.windows.contains(&window) { + let focus_stack = self.focus_stack(seat); + self.floating_layer.unmap_window(&mut self.space, &window); + self.tiling_layer.map_window(&mut self.space, window, seat, focus_stack.iter()) + } + } + } + } } From 022267c6f6edf44fc1534639e78f3ec8daebf6ee Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Thu, 7 Jul 2022 22:45:04 +0200 Subject: [PATCH 3/3] input: Add keybindings for toggling tiling --- config.ron | 8 +++++--- src/config/mod.rs | 2 ++ src/input/mod.rs | 10 ++++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/config.ron b/config.ron index 81b93635..6ba1550f 100644 --- a/config.ron +++ b/config.ron @@ -2,7 +2,7 @@ key_bindings: { (modifiers: [Logo, Shift], key: "Escape"): Terminate, (modifiers: [Logo], key: "Escape"): Debug, - (modifiers: [Logo], key: "Q"): Close, + (modifiers: [Logo], key: "q"): Close, (modifiers: [Logo], key: "1"): Workspace(1), (modifiers: [Logo], key: "2"): Workspace(2), (modifiers: [Logo], key: "3"): Workspace(3), @@ -31,9 +31,11 @@ (modifiers: [Logo], key: "j"): Focus(Down), (modifiers: [Logo], key: "k"): Focus(Up), (modifiers: [Logo], key: "l"): Focus(Right), - //TODO: automatic orientation with Logo+o toggling + //TODO: automatic orientation with Logo+o toggling (modifiers: [Logo], key: "v"): Orientation(Vertical), (modifiers: [Logo], key: "o"): Orientation(Horizontal), + (modifiers: [Logo], key: "y"): ToggleTiling, + (modifiers: [Logo], key: "g"): ToggleWindowFloating, (modifiers: [Logo, Shift], key: "f"): Fullscreen, //TODO: ability to select default web browser (modifiers: [Logo], key: "b"): Spawn("firefox"), @@ -42,7 +44,7 @@ //TODO: ability to select default terminal (modifiers: [Logo], key: "t"): Spawn("gnome-terminal"), (modifiers: [Logo], key: "a"): Spawn("xdg-shell-wrapper cosmic-app-library"), - (modifiers: [Logo], key: "Slash"): Spawn("xdg-shell-wrapper cosmic-launcher"), + (modifiers: [Logo], key: "slash"): Spawn("xdg-shell-wrapper cosmic-launcher"), }, workspace_mode: OutputBound, ) diff --git a/src/config/mod.rs b/src/config/mod.rs index ae244a64..7bbeed5d 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -749,6 +749,8 @@ pub enum Action { MoveToWorkspace(u8), Focus(FocusDirection), Orientation(crate::shell::layout::Orientation), + ToggleTiling, + ToggleWindowFloating, Fullscreen, Spawn(String), } diff --git a/src/input/mod.rs b/src/input/mod.rs index 4c5cd27e..44366427 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -344,6 +344,16 @@ impl State { focus_stack.iter(), ); } + Action::ToggleTiling => { + let output = active_output(seat, &self.common); + let workspace = self.common.shell.active_space_mut(&output); + workspace.toggle_tiling(seat); + } + Action::ToggleWindowFloating => { + let output = active_output(seat, &self.common); + let workspace = self.common.shell.active_space_mut(&output); + workspace.toggle_floating_window(seat); + } Action::Spawn(command) => { if let Err(err) = std::process::Command::new("/bin/sh") .arg("-c")