cosmic-comp/src/shell/workspace.rs

272 lines
9.1 KiB
Rust
Raw Normal View History

2022-03-24 20:32:31 +01:00
use super::{layout, Layout};
2022-05-02 17:43:58 +02:00
#[cfg(feature = "experimental")]
use crate::wayland::workspace as ext_work;
2022-03-24 20:32:31 +01:00
use indexmap::IndexSet;
use smithay::{
2022-05-03 13:37:51 +02:00
desktop::{Kind, LayerSurface, Space, Window},
2022-04-22 15:18:28 +02:00
reexports::wayland_protocols::xdg_shell::server::xdg_toplevel::{self, ResizeEdge},
2022-03-24 20:32:31 +01:00
wayland::{
output::Output,
seat::{PointerGrabStartData, Seat},
Serial,
},
};
2022-03-30 22:00:44 +02:00
use std::{
cell::{Ref, RefCell, RefMut},
collections::HashMap,
};
pub struct FocusStack<'a>(Ref<'a, IndexSet<Window>>);
pub struct FocusStackMut<'a>(RefMut<'a, IndexSet<Window>>);
2022-03-24 20:32:31 +01:00
2022-03-30 22:00:44 +02:00
impl<'a> FocusStack<'a> {
pub fn last(&self) -> Option<Window> {
self.0.iter().rev().find(|w| w.toplevel().alive()).cloned()
}
pub fn iter<'b>(&'b self) -> Box<dyn Iterator<Item = &'b Window> + 'b> {
//working around object-safety constraints for trait Layout
Box::new(self.0.iter().rev().filter(|w| w.toplevel().alive()))
2022-03-24 20:32:31 +01:00
}
2022-03-30 22:00:44 +02:00
}
2022-03-24 20:32:31 +01:00
2022-03-30 22:00:44 +02:00
impl<'a> FocusStackMut<'a> {
2022-03-24 20:32:31 +01:00
pub fn append(&mut self, window: &Window) {
self.0.retain(|w| w.toplevel().alive());
self.0.shift_remove(window);
self.0.insert(window.clone());
}
pub fn last(&self) -> Option<Window> {
self.0.iter().rev().find(|w| w.toplevel().alive()).cloned()
}
2022-03-30 22:00:44 +02:00
pub fn iter<'b>(&'b self) -> Box<dyn Iterator<Item = &'b Window> + 'b> {
2022-03-24 20:32:31 +01:00
//working around object-safety constraints for trait Layout
Box::new(self.0.iter().rev().filter(|w| w.toplevel().alive()))
}
}
2022-03-30 22:00:44 +02:00
type FocusStackData = RefCell<(HashMap<u8, IndexSet<Window>>, IndexSet<Window>)>;
2022-03-24 20:32:31 +01:00
pub struct Workspace {
2022-03-30 22:11:29 +02:00
pub(super) idx: u8,
2022-03-24 20:32:31 +01:00
pub space: Space,
pub(super) layout: Box<dyn Layout>,
pub(super) pending_windows: Vec<(Window, Seat)>,
pub(super) pending_layers: Vec<(LayerSurface, Output, Seat)>,
2022-04-22 15:18:28 +02:00
pub fullscreen: HashMap<String, Window>,
2022-05-02 17:43:58 +02:00
#[cfg(feature = "experimental")]
pub(super) ext_workspace: Option<ext_work::Workspace>,
2022-03-24 20:32:31 +01:00
}
impl Workspace {
2022-05-03 13:37:51 +02:00
pub fn new(idx: u8) -> Workspace {
2022-03-24 20:32:31 +01:00
Workspace {
2022-03-30 22:00:44 +02:00
idx,
2022-03-24 20:32:31 +01:00
space: Space::new(None),
layout: layout::new_default_layout(),
2022-03-24 20:32:31 +01:00
pending_windows: Vec::new(),
pending_layers: Vec::new(),
2022-04-22 15:18:28 +02:00
fullscreen: HashMap::new(),
2022-05-02 17:43:58 +02:00
#[cfg(feature = "experimental")]
ext_workspace: None,
2022-03-24 20:32:31 +01:00
}
}
2022-03-30 22:00:44 +02:00
pub fn focus_stack<'a>(&'a self, seat: &'a Seat) -> FocusStack<'a> {
seat.user_data()
.insert_if_missing(|| FocusStackData::new((HashMap::new(), IndexSet::new())));
FocusStack(Ref::map(
seat.user_data().get::<FocusStackData>().unwrap().borrow(),
|map| map.0.get(&self.idx).unwrap_or(&map.1), //TODO: workaround until Ref::filter_map goes stable
))
}
pub fn focus_stack_mut<'a>(&'a self, seat: &'a Seat) -> FocusStackMut<'a> {
seat.user_data()
.insert_if_missing(|| FocusStackData::new((HashMap::new(), IndexSet::new())));
FocusStackMut(RefMut::map(
seat.user_data()
.get::<FocusStackData>()
.unwrap()
.borrow_mut(),
|map| map.0.entry(self.idx).or_insert_with(|| IndexSet::new()),
))
}
2022-03-24 20:32:31 +01:00
pub fn pending_window(&mut self, window: Window, seat: &Seat) {
self.pending_windows.push((window, seat.clone()));
}
2022-04-22 15:18:28 +02:00
pub fn pending_layer(&mut self, layer: LayerSurface, output: &Output, seat: &Seat) {
2022-04-22 15:18:28 +02:00
self.pending_layers
.push((layer, output.clone(), seat.clone()));
}
2022-03-24 20:32:31 +01:00
2022-03-30 22:11:29 +02:00
pub(super) fn map_window(&mut self, window: &Window, seat: &Seat) {
2022-03-30 22:00:44 +02:00
seat.user_data()
.insert_if_missing(|| FocusStackData::new((HashMap::new(), IndexSet::new())));
let focus_stack = FocusStackMut(RefMut::map(
seat.user_data()
.get::<FocusStackData>()
.unwrap()
.borrow_mut(),
|map| map.0.entry(self.idx).or_insert_with(|| IndexSet::new()),
));
2022-03-24 20:32:31 +01:00
self.layout
2022-03-30 22:00:44 +02:00
.map_window(&mut self.space, window, seat, focus_stack.iter())
2022-03-24 20:32:31 +01:00
}
2022-03-30 22:11:29 +02:00
pub(super) fn unmap_window(&mut self, window: &Window) {
self.layout.unmap_window(&mut self.space, window)
}
2022-03-24 20:32:31 +01:00
pub fn refresh(&mut self) {
2022-04-22 15:18:28 +02:00
let outputs = self.space.outputs().collect::<Vec<_>>();
2022-05-03 13:37:51 +02:00
let dead_output_windows = self
.fullscreen
2022-04-22 15:18:28 +02:00
.iter()
2022-05-03 13:37:51 +02:00
.filter(|(name, _)| !outputs.iter().any(|o| o.name() == **name))
2022-04-22 15:18:28 +02:00
.map(|(_, w)| w)
.cloned()
.collect::<Vec<_>>();
for window in dead_output_windows {
self.unfullscreen_request(&window);
}
self.fullscreen.retain(|_, w| w.toplevel().alive());
2022-03-24 20:32:31 +01:00
self.layout.refresh(&mut self.space);
self.space.refresh();
}
pub fn update_orientation(&mut self, seat: &Seat, orientation: layout::Orientation) {
2022-03-30 22:00:44 +02:00
seat.user_data()
.insert_if_missing(|| FocusStackData::new((HashMap::new(), IndexSet::new())));
let focus_stack = FocusStackMut(RefMut::map(
seat.user_data()
.get::<FocusStackData>()
.unwrap()
.borrow_mut(),
|map| map.0.entry(self.idx).or_insert_with(|| IndexSet::new()),
));
self.layout
2022-03-30 22:00:44 +02:00
.update_orientation(orientation, seat, &mut self.space, focus_stack.iter())
}
pub fn move_focus(&mut self, seat: &Seat, focus: layout::FocusDirection) -> Option<Window> {
seat.user_data()
.insert_if_missing(|| FocusStackData::new((HashMap::new(), IndexSet::new())));
let focus_stack = FocusStackMut(RefMut::map(
seat.user_data()
.get::<FocusStackData>()
.unwrap()
.borrow_mut(),
|map| map.0.entry(self.idx).or_insert_with(|| IndexSet::new()),
));
self.layout
.move_focus(focus, seat, &mut self.space, focus_stack.iter())
}
2022-03-24 20:32:31 +01:00
pub fn maximize_request(&mut self, window: &Window, output: &Output) {
2022-04-22 15:18:28 +02:00
if self.fullscreen.values().any(|w| w == window) {
return;
}
2022-03-24 20:32:31 +01:00
self.layout
.maximize_request(&mut self.space, window, output)
}
pub fn move_request(
&mut self,
window: &Window,
seat: &Seat,
serial: Serial,
start_data: PointerGrabStartData,
) {
2022-04-22 15:18:28 +02:00
if self.fullscreen.values().any(|w| w == window) {
return;
}
2022-03-24 20:32:31 +01:00
self.layout
.move_request(&mut self.space, window, seat, serial, start_data)
}
pub fn resize_request(
&mut self,
window: &Window,
seat: &Seat,
serial: Serial,
start_data: PointerGrabStartData,
edges: ResizeEdge,
) {
2022-04-22 15:18:28 +02:00
if self.fullscreen.values().any(|w| w == window) {
return;
}
2022-03-24 20:32:31 +01:00
self.layout
.resize_request(&mut self.space, window, seat, serial, start_data, edges)
}
2022-04-22 15:18:28 +02:00
pub fn fullscreen_request(&mut self, window: &Window, output: &Output) {
if self.fullscreen.contains_key(&output.name()) {
return;
}
#[allow(irrefutable_let_patterns)]
if let Kind::Xdg(xdg) = &window.toplevel() {
if xdg.get_surface().is_some() {
let ret = xdg.with_pending_state(|state| {
state.states.set(xdg_toplevel::State::Fullscreen);
state.size = Some(
output
.current_mode()
.map(|m| m.size)
.unwrap_or((0, 0).into())
.to_f64()
.to_logical(output.current_scale().fractional_scale())
.to_i32_round(),
2022-04-22 15:18:28 +02:00
);
});
if ret.is_ok() {
xdg.send_configure();
self.fullscreen.insert(output.name(), window.clone());
}
}
}
}
2022-05-03 13:37:51 +02:00
2022-04-22 15:18:28 +02:00
pub fn unfullscreen_request(&mut self, window: &Window) {
if self.fullscreen.values().any(|w| w == window) {
#[allow(irrefutable_let_patterns)]
if let Kind::Xdg(xdg) = &window.toplevel() {
if xdg.get_surface().is_some() {
let ret = xdg.with_pending_state(|state| {
state.states.unset(xdg_toplevel::State::Fullscreen);
state.size = None;
});
if ret.is_ok() {
self.layout.refresh(&mut self.space);
xdg.send_configure();
2022-05-03 13:37:51 +02:00
}
2022-04-22 15:18:28 +02:00
}
}
self.fullscreen.retain(|_, w| w != window);
}
}
pub fn fullscreen_toggle(&mut self, window: &Window, output: &Output) {
if self.fullscreen.contains_key(&output.name()) {
self.unfullscreen_request(window)
} else {
self.fullscreen_request(window, output)
}
}
pub fn get_fullscreen(&self, output: &Output) -> Option<&Window> {
if !self.space.outputs().any(|o| o == output) {
return None;
}
2022-05-03 13:37:51 +02:00
self.fullscreen
.get(&output.name())
.filter(|w| w.toplevel().get_surface().is_some())
2022-04-22 15:18:28 +02:00
}
2022-03-24 20:32:31 +01:00
}