shell: ext_workspace implementation
This commit is contained in:
parent
6096b8114e
commit
64b9295ddb
3 changed files with 215 additions and 21 deletions
|
|
@ -266,7 +266,7 @@ pub fn init_shell(config: &Config, display: &mut Display) -> super::Shell {
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
super::Shell::new(config)
|
super::Shell::new(config, display)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_grab_preconditions(
|
fn check_grab_preconditions(
|
||||||
|
|
|
||||||
224
src/shell/mod.rs
224
src/shell/mod.rs
|
|
@ -1,25 +1,28 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
#[cfg(feature = "experimental")]
|
||||||
|
use crate::wayland::workspace as ext_work;
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{Config, OutputConfig},
|
config::{Config, OutputConfig},
|
||||||
input::active_output,
|
input::active_output,
|
||||||
state::Common,
|
state::Common,
|
||||||
};
|
};
|
||||||
pub use smithay::{
|
pub use smithay::{
|
||||||
desktop::{PopupGrab, PopupManager, PopupUngrabStrategy, Space, Window, layer_map_for_output},
|
desktop::{layer_map_for_output, PopupGrab, PopupManager, PopupUngrabStrategy, Space, Window},
|
||||||
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
reexports::wayland_server::{protocol::wl_surface::WlSurface, Display},
|
||||||
utils::{Logical, Point, Rectangle, Size},
|
utils::{Logical, Point, Rectangle, Size},
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor::with_states,
|
compositor::with_states,
|
||||||
output::{Mode as OutputMode, Output, Scale},
|
output::{Mode as OutputMode, Output, Scale},
|
||||||
seat::Seat,
|
seat::Seat,
|
||||||
shell::{
|
shell::{
|
||||||
|
wlr_layer::{KeyboardInteractivity, Layer, LayerSurfaceCachedState},
|
||||||
xdg::XdgToplevelSurfaceRoleAttributes,
|
xdg::XdgToplevelSurfaceRoleAttributes,
|
||||||
wlr_layer::{Layer, KeyboardInteractivity, LayerSurfaceCachedState},
|
|
||||||
},
|
},
|
||||||
Serial, SERIAL_COUNTER,
|
Serial, SERIAL_COUNTER,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
mem::MaybeUninit,
|
mem::MaybeUninit,
|
||||||
|
|
@ -75,12 +78,16 @@ pub struct Shell {
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
outputs: Vec<Output>,
|
outputs: Vec<Output>,
|
||||||
pub spaces: [Workspace; MAX_WORKSPACES],
|
pub spaces: [Workspace; MAX_WORKSPACES],
|
||||||
|
#[cfg(feature = "experimental")]
|
||||||
|
manager: ext_work::WorkspaceManager,
|
||||||
|
#[cfg(feature = "experimental")]
|
||||||
|
global_group: Option<ext_work::WorkspaceGroup>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const UNINIT_SPACE: MaybeUninit<Workspace> = MaybeUninit::uninit();
|
const UNINIT_SPACE: MaybeUninit<Workspace> = MaybeUninit::uninit();
|
||||||
|
|
||||||
impl Shell {
|
impl Shell {
|
||||||
fn new(config: &Config) -> Self {
|
fn new(config: &Config, _display: &mut Display) -> Self {
|
||||||
Shell {
|
Shell {
|
||||||
popups: PopupManager::new(None),
|
popups: PopupManager::new(None),
|
||||||
mode: config.static_conf.workspace_mode,
|
mode: config.static_conf.workspace_mode,
|
||||||
|
|
@ -92,6 +99,37 @@ impl Shell {
|
||||||
}
|
}
|
||||||
std::mem::transmute(spaces)
|
std::mem::transmute(spaces)
|
||||||
},
|
},
|
||||||
|
#[cfg(feature = "experimental")]
|
||||||
|
manager: ext_work::init_ext_workspace(
|
||||||
|
_display,
|
||||||
|
|_, changes, mut ddata| {
|
||||||
|
let state = ddata.get::<crate::state::State>().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::<RefCell<OutputConfig>>()
|
.get::<RefCell<OutputConfig>>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.borrow();
|
.borrow();
|
||||||
workspace
|
workspace.space.map_output(output, config.position);
|
||||||
.space
|
|
||||||
.map_output(output, config.position);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for output in self.outputs.iter() {
|
for output in self.outputs.iter() {
|
||||||
|
|
@ -125,7 +161,7 @@ impl Shell {
|
||||||
fn assign_next_free_output<'a>(
|
fn assign_next_free_output<'a>(
|
||||||
spaces: &'a mut [Workspace],
|
spaces: &'a mut [Workspace],
|
||||||
output: &Output,
|
output: &Output,
|
||||||
) -> &'a mut Workspace {
|
) -> (usize, &'a mut Workspace) {
|
||||||
output
|
output
|
||||||
.user_data()
|
.user_data()
|
||||||
.insert_if_missing(|| ActiveWorkspace::new());
|
.insert_if_missing(|| ActiveWorkspace::new());
|
||||||
|
|
@ -140,7 +176,7 @@ impl Shell {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set(idx);
|
.set(idx);
|
||||||
|
|
||||||
workspace
|
(idx, workspace)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_output(&mut self, output: &Output) {
|
pub fn add_output(&mut self, output: &Output) {
|
||||||
|
|
@ -153,14 +189,76 @@ impl Shell {
|
||||||
|
|
||||||
match self.mode {
|
match self.mode {
|
||||||
Mode::OutputBound => {
|
Mode::OutputBound => {
|
||||||
let workspace = Self::assign_next_free_output(&mut self.spaces, output);
|
let _idx = {
|
||||||
workspace.space.map_output(output, (0, 0));
|
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::<ext_work::WorkspaceGroup>::None)
|
||||||
|
});
|
||||||
|
*output
|
||||||
|
.user_data()
|
||||||
|
.get::<RefCell<Option<ext_work::WorkspaceGroup>>>()
|
||||||
|
.unwrap()
|
||||||
|
.borrow_mut() = Some(group);
|
||||||
|
self.manager.done();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Mode::Global { active } => {
|
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];
|
let workspace = &mut self.spaces[active];
|
||||||
workspace
|
workspace.space.map_output(output, config.position);
|
||||||
.space
|
|
||||||
.map_output(output, config.position);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
output.change_current_state(None, None, Some(Scale::Fractional(config.scale)), None);
|
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.spaces[idx].space.unmap_output(output);
|
||||||
self.outputs.retain(|o| o != output);
|
self.outputs.retain(|o| o != output);
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "experimental")]
|
||||||
|
{
|
||||||
|
let group = output
|
||||||
|
.user_data()
|
||||||
|
.get::<RefCell<Option<ext_work::WorkspaceGroup>>>()
|
||||||
|
.unwrap()
|
||||||
|
.borrow_mut()
|
||||||
|
.take()
|
||||||
|
.unwrap();
|
||||||
|
let mut alternative_group = self.outputs.last_mut().map(|o| {
|
||||||
|
o.user_data()
|
||||||
|
.get::<RefCell<Option<ext_work::WorkspaceGroup>>>()
|
||||||
|
.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 } => {
|
Mode::Global { active } => {
|
||||||
|
#[cfg(feature = "experimental")]
|
||||||
|
self.manager.update_outputs(|_, outputs| {
|
||||||
|
outputs.remove(output);
|
||||||
|
});
|
||||||
self.spaces[active].space.unmap_output(output);
|
self.spaces[active].space.unmap_output(output);
|
||||||
self.outputs.retain(|o| o != output);
|
self.outputs.retain(|o| o != output);
|
||||||
// TODO move windows and outputs farther on the right / or load save config for remaining monitors
|
// 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::<ActiveWorkspace>() {
|
if let Some(active) = output.user_data().get::<ActiveWorkspace>() {
|
||||||
if let Some(old_idx) = active.set(idx) {
|
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[old_idx].space.unmap_output(output);
|
||||||
}
|
}
|
||||||
self.spaces[idx]
|
self.spaces[idx].space.map_output(output, (0, 0));
|
||||||
.space
|
#[cfg(feature = "experimental")]
|
||||||
.map_output(output, (0, 0));
|
{
|
||||||
|
let mut group_borrow = output
|
||||||
|
.user_data()
|
||||||
|
.get::<RefCell<Option<ext_work::WorkspaceGroup>>>()
|
||||||
|
.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();
|
self.spaces[idx].refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -289,6 +456,25 @@ impl Shell {
|
||||||
.space
|
.space
|
||||||
.map_output(output, config.position);
|
.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::<ActiveWorkspace>().unwrap().set(a);
|
output.user_data().get::<ActiveWorkspace>().unwrap().set(a);
|
||||||
&mut self.spaces[a]
|
&mut self.spaces[a]
|
||||||
} else {
|
} 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.space.map_output(output, (0, 0));
|
||||||
workspace.refresh();
|
workspace.refresh();
|
||||||
|
|
@ -472,7 +658,7 @@ impl Shell {
|
||||||
} {
|
} {
|
||||||
new_focus = Some(seat);
|
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
|
if let Some((layer, output, seat)) = workspace
|
||||||
.pending_layers
|
.pending_layers
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
use super::{layout, Layout};
|
use super::{layout, Layout};
|
||||||
|
#[cfg(feature = "experimental")]
|
||||||
|
use crate::wayland::workspace as ext_work;
|
||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::{LayerSurface, Space, Window, Kind},
|
desktop::{LayerSurface, Space, Window, Kind},
|
||||||
|
|
@ -54,10 +56,14 @@ pub struct Workspace {
|
||||||
pub(super) pending_windows: Vec<(Window, Seat)>,
|
pub(super) pending_windows: Vec<(Window, Seat)>,
|
||||||
pub(super) pending_layers: Vec<(LayerSurface, Output, Seat)>,
|
pub(super) pending_layers: Vec<(LayerSurface, Output, Seat)>,
|
||||||
pub fullscreen: HashMap<String, Window>,
|
pub fullscreen: HashMap<String, Window>,
|
||||||
|
#[cfg(feature = "experimental")]
|
||||||
|
pub(super) ext_workspace: Option<ext_work::Workspace>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Workspace {
|
impl Workspace {
|
||||||
pub fn new(idx: u8) -> Workspace {
|
pub fn new(
|
||||||
|
idx: u8,
|
||||||
|
) -> Workspace {
|
||||||
Workspace {
|
Workspace {
|
||||||
idx,
|
idx,
|
||||||
space: Space::new(None),
|
space: Space::new(None),
|
||||||
|
|
@ -65,6 +71,8 @@ impl Workspace {
|
||||||
pending_windows: Vec::new(),
|
pending_windows: Vec::new(),
|
||||||
pending_layers: Vec::new(),
|
pending_layers: Vec::new(),
|
||||||
fullscreen: HashMap::new(),
|
fullscreen: HashMap::new(),
|
||||||
|
#[cfg(feature = "experimental")]
|
||||||
|
ext_workspace: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue