From 64b9295ddb3d1ba9190ac2cafb7d676468a7ca20 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Mon, 2 May 2022 17:43:58 +0200 Subject: [PATCH] shell: ext_workspace implementation --- src/shell/handler.rs | 2 +- src/shell/mod.rs | 224 +++++++++++++++++++++++++++++++++++++---- src/shell/workspace.rs | 10 +- 3 files changed, 215 insertions(+), 21 deletions(-) diff --git a/src/shell/handler.rs b/src/shell/handler.rs index 33007c9d..ea0a486b 100644 --- a/src/shell/handler.rs +++ b/src/shell/handler.rs @@ -266,7 +266,7 @@ pub fn init_shell(config: &Config, display: &mut Display) -> super::Shell { None, ); - super::Shell::new(config) + super::Shell::new(config, display) } fn check_grab_preconditions( diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 1e647e38..da742624 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -1,25 +1,28 @@ // SPDX-License-Identifier: GPL-3.0-only +#[cfg(feature = "experimental")] +use crate::wayland::workspace as ext_work; use crate::{ config::{Config, OutputConfig}, input::active_output, state::Common, }; pub use smithay::{ - desktop::{PopupGrab, PopupManager, PopupUngrabStrategy, Space, Window, layer_map_for_output}, - reexports::wayland_server::protocol::wl_surface::WlSurface, + desktop::{layer_map_for_output, PopupGrab, PopupManager, PopupUngrabStrategy, Space, Window}, + reexports::wayland_server::{protocol::wl_surface::WlSurface, Display}, utils::{Logical, Point, Rectangle, Size}, wayland::{ compositor::with_states, output::{Mode as OutputMode, Output, Scale}, seat::Seat, shell::{ + wlr_layer::{KeyboardInteractivity, Layer, LayerSurfaceCachedState}, xdg::XdgToplevelSurfaceRoleAttributes, - wlr_layer::{Layer, KeyboardInteractivity, LayerSurfaceCachedState}, }, Serial, SERIAL_COUNTER, }, }; + use std::{ cell::{Cell, RefCell}, mem::MaybeUninit, @@ -75,12 +78,16 @@ pub struct Shell { mode: Mode, outputs: Vec, pub spaces: [Workspace; MAX_WORKSPACES], + #[cfg(feature = "experimental")] + manager: ext_work::WorkspaceManager, + #[cfg(feature = "experimental")] + global_group: Option, } const UNINIT_SPACE: MaybeUninit = MaybeUninit::uninit(); impl Shell { - fn new(config: &Config) -> Self { + fn new(config: &Config, _display: &mut Display) -> Self { Shell { popups: PopupManager::new(None), mode: config.static_conf.workspace_mode, @@ -92,6 +99,37 @@ impl Shell { } std::mem::transmute(spaces) }, + #[cfg(feature = "experimental")] + manager: ext_work::init_ext_workspace( + _display, + |_, changes, mut ddata| { + let state = ddata.get::().unwrap(); + if let Some((w, _)) = changes.into_iter().rev().find(|(_, p)| { + p.into_iter() + .rev() + .find(|o| { + **o == ext_work::PendingOperation::Activate + || **o == ext_work::PendingOperation::Deactivate + }) + .map(|o| *o == ext_work::PendingOperation::Activate) + .unwrap_or(false) + }) { + if let Some(idx) = state.common.shell.spaces.iter().position(|work| { + work.ext_workspace.as_ref().map(|e| e == w).unwrap_or(false) + }) { + state.common.event_loop_handle.insert_idle(move |state| { + let seat = &state.common.last_active_seat; + let output = active_output(&seat, &state.common); + state.common.shell.activate(seat, &output, idx); + }); + } + } + }, + |_| true, + ) + .0, + #[cfg(feature = "experimental")] + global_group: None, } } @@ -104,9 +142,7 @@ impl Shell { .get::>() .unwrap() .borrow(); - workspace - .space - .map_output(output, config.position); + workspace.space.map_output(output, config.position); } } else { for output in self.outputs.iter() { @@ -125,7 +161,7 @@ impl Shell { fn assign_next_free_output<'a>( spaces: &'a mut [Workspace], output: &Output, - ) -> &'a mut Workspace { + ) -> (usize, &'a mut Workspace) { output .user_data() .insert_if_missing(|| ActiveWorkspace::new()); @@ -140,7 +176,7 @@ impl Shell { .unwrap() .set(idx); - workspace + (idx, workspace) } pub fn add_output(&mut self, output: &Output) { @@ -153,14 +189,76 @@ impl Shell { match self.mode { Mode::OutputBound => { - let workspace = Self::assign_next_free_output(&mut self.spaces, output); - workspace.space.map_output(output, (0, 0)); + let _idx = { + let (idx, workspace) = Self::assign_next_free_output(&mut self.spaces, output); + workspace.space.map_output(output, (0, 0)); + idx + }; + #[cfg(feature = "experimental")] + { + let group = self + .manager + .new_group(|_, _, _| {}, std::iter::once(output.clone())); + if self.spaces.iter().all(|w| w.ext_workspace.is_none()) { + for (idx, workspace) in self.spaces.iter_mut().enumerate() { + let ext_workspace = group.create_workspace(format!("{}", idx + 1)); + ext_workspace.set_coordinates(std::iter::once(idx as u32 + 1)); + workspace.ext_workspace = Some(ext_workspace); + } + self.spaces[_idx] + .ext_workspace + .as_mut() + .unwrap() + .add_state(ext_work::State::Active); + } else { + let ext_workspace = group.create_workspace(format!("{}", _idx + 1)); + ext_workspace.set_coordinates(std::iter::once(_idx as u32 + 1)); + ext_workspace.add_state(ext_work::State::Active); + if let Some(old) = self.spaces[_idx].ext_workspace.replace(ext_workspace) { + old.remove(); + } + } + output.user_data().insert_if_missing(|| { + RefCell::new(Option::::None) + }); + *output + .user_data() + .get::>>() + .unwrap() + .borrow_mut() = Some(group); + self.manager.done(); + } } Mode::Global { active } => { + #[cfg(feature = "experimental")] + { + if self.global_group.is_none() { + self.global_group = Some( + self.manager + .new_group(|_, _, _| {}, std::iter::once(output.clone())), + ); + for (idx, workspace) in self.spaces.iter_mut().enumerate() { + let ext_workspace = self + .global_group + .as_mut() + .unwrap() + .create_workspace(format!("{}", idx + 1)); + ext_workspace.set_coordinates(std::iter::once(idx as u32 + 1)); + if idx == active { + ext_workspace.add_state(ext_work::State::Active); + } + workspace.ext_workspace = Some(ext_workspace); + } + } else { + self.manager.update_outputs(|_, outputs| { + outputs.insert(output.clone()); + }); + } + self.manager.done(); + } + let workspace = &mut self.spaces[active]; - workspace - .space - .map_output(output, config.position); + workspace.space.map_output(output, config.position); } } output.change_current_state(None, None, Some(Scale::Fractional(config.scale)), None); @@ -177,8 +275,47 @@ impl Shell { self.spaces[idx].space.unmap_output(output); self.outputs.retain(|o| o != output); } + #[cfg(feature = "experimental")] + { + let group = output + .user_data() + .get::>>() + .unwrap() + .borrow_mut() + .take() + .unwrap(); + let mut alternative_group = self.outputs.last_mut().map(|o| { + o.user_data() + .get::>>() + .unwrap() + }); + for (idx, workspace) in self.spaces.iter_mut().enumerate() { + if workspace + .ext_workspace + .as_ref() + .map(|w| group.belongs(w)) + .unwrap_or(false) + { + workspace.ext_workspace.take().unwrap().remove(); + if let Some(alternative) = alternative_group.as_mut() { + let ext_workspace = alternative + .borrow_mut() + .as_mut() + .unwrap() + .create_workspace(format!("{}", idx + 1)); + ext_workspace.set_coordinates(std::iter::once(idx as u32 + 1)); + workspace.ext_workspace = Some(ext_workspace); + } + } + } + self.manager.remove_group(&group); + } } Mode::Global { active } => { + #[cfg(feature = "experimental")] + self.manager.update_outputs(|_, outputs| { + outputs.remove(output); + }); self.spaces[active].space.unmap_output(output); self.outputs.retain(|o| o != output); // TODO move windows and outputs farther on the right / or load save config for remaining monitors @@ -267,11 +404,41 @@ impl Shell { if let Some(active) = output.user_data().get::() { if let Some(old_idx) = active.set(idx) { + #[cfg(feature = "experimental")] + if let Some(ext_workspace) = self.spaces[old_idx].ext_workspace.as_mut() { + ext_workspace.remove_state(ext_work::State::Active); + } self.spaces[old_idx].space.unmap_output(output); } - self.spaces[idx] - .space - .map_output(output, (0, 0)); + self.spaces[idx].space.map_output(output, (0, 0)); + #[cfg(feature = "experimental")] + { + let mut group_borrow = output + .user_data() + .get::>>() + .unwrap() + .borrow_mut(); + let group = group_borrow.as_mut().unwrap(); + if self.spaces[idx] + .ext_workspace + .as_ref() + .map(|x| !group.belongs(x)) + .unwrap_or(true) + { + let ext_workspace = group.create_workspace(format!("{}", idx + 1)); + ext_workspace.set_coordinates(std::iter::once(idx as u32 + 1)); + if let Some(old) = self.spaces[idx].ext_workspace.replace(ext_workspace) + { + old.remove(); + } + } + self.spaces[idx] + .ext_workspace + .as_mut() + .unwrap() + .add_state(ext_work::State::Active); + self.manager.done(); + } self.spaces[idx].refresh(); } } @@ -289,6 +456,25 @@ impl Shell { .space .map_output(output, config.position); } + #[cfg(feature = "experimental")] + { + for (idx, workspace) in self.spaces.iter_mut().enumerate() { + if idx == *active { + workspace + .ext_workspace + .as_mut() + .unwrap() + .add_state(ext_work::State::Active); + } else { + workspace + .ext_workspace + .as_mut() + .unwrap() + .remove_state(ext_work::State::Active); + } + } + self.manager.done(); + } } }; } @@ -367,7 +553,7 @@ impl Shell { output.user_data().get::().unwrap().set(a); &mut self.spaces[a] } else { - Self::assign_next_free_output(&mut self.spaces, output) + Self::assign_next_free_output(&mut self.spaces, output).1 }; workspace.space.map_output(output, (0, 0)); workspace.refresh(); @@ -472,7 +658,7 @@ impl Shell { } { new_focus = Some(seat); } - workspace.pending_windows.retain(|(w, _)| w != &window); + workspace.pending_windows.retain(|(w, _)| w != &window); } if let Some((layer, output, seat)) = workspace .pending_layers diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index e5317c2c..c314f069 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -1,4 +1,6 @@ use super::{layout, Layout}; +#[cfg(feature = "experimental")] +use crate::wayland::workspace as ext_work; use indexmap::IndexSet; use smithay::{ desktop::{LayerSurface, Space, Window, Kind}, @@ -54,10 +56,14 @@ pub struct Workspace { pub(super) pending_windows: Vec<(Window, Seat)>, pub(super) pending_layers: Vec<(LayerSurface, Output, Seat)>, pub fullscreen: HashMap, + #[cfg(feature = "experimental")] + pub(super) ext_workspace: Option, } impl Workspace { - pub fn new(idx: u8) -> Workspace { + pub fn new( + idx: u8, + ) -> Workspace { Workspace { idx, space: Space::new(None), @@ -65,6 +71,8 @@ impl Workspace { pending_windows: Vec::new(), pending_layers: Vec::new(), fullscreen: HashMap::new(), + #[cfg(feature = "experimental")] + ext_workspace: None, } }