cosmic-comp/src/shell/mod.rs

1387 lines
51 KiB
Rust
Raw Normal View History

2022-09-28 12:01:29 +02:00
use serde::{Deserialize, Serialize};
use std::{cell::RefCell, collections::HashMap};
2022-09-28 12:01:29 +02:00
use cosmic_protocols::workspace::v1::server::zcosmic_workspace_handle_v1::State as WState;
use smithay::{
2023-01-23 18:25:01 +01:00
backend::renderer::element::Id,
desktop::{
layer_map_for_output, space::SpaceElement, LayerSurface, PopupManager, WindowSurfaceType,
},
2023-01-18 20:23:41 +01:00
input::{
pointer::{Focus, GrabStartData as PointerGrabStartData},
Seat,
},
output::Output,
2023-01-23 18:25:01 +01:00
reexports::wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle},
2023-01-18 20:23:41 +01:00
utils::{Logical, Point, Rectangle, Serial, SERIAL_COUNTER},
2022-03-30 22:00:44 +02:00
wayland::{
compositor::with_states,
2023-01-18 20:23:41 +01:00
seat::WaylandFocus,
shell::{
2022-07-04 16:00:29 +02:00
wlr_layer::{
KeyboardInteractivity, Layer, LayerSurfaceCachedState, WlrLayerShellState,
},
xdg::XdgShellState,
},
2022-03-30 22:00:44 +02:00
},
2023-01-18 20:23:41 +01:00
xwayland::X11Surface,
2022-03-30 22:00:44 +02:00
};
2022-05-02 17:43:58 +02:00
use crate::{
config::{Config, OutputConfig, WorkspaceMode as ConfigMode},
2022-07-04 16:00:29 +02:00
utils::prelude::*,
wayland::protocols::{
toplevel_info::ToplevelInfoState,
2022-08-30 13:28:36 +02:00
toplevel_management::{ManagementCapabilities, ToplevelManagementState},
workspace::{
2022-07-04 16:00:29 +02:00
WorkspaceCapabilities, WorkspaceGroupHandle, WorkspaceHandle, WorkspaceState,
WorkspaceUpdateGuard,
},
},
};
2022-03-24 20:32:31 +01:00
2022-09-28 12:01:29 +02:00
mod element;
2022-07-04 16:00:29 +02:00
pub mod focus;
pub mod grabs;
2022-08-30 13:28:36 +02:00
pub mod layout;
2022-03-24 20:32:31 +01:00
mod workspace;
pub use self::element::{CosmicMapped, CosmicMappedRenderElement, CosmicSurface};
2022-03-24 20:32:31 +01:00
pub use self::workspace::*;
2022-09-28 12:01:29 +02:00
use self::{
element::CosmicWindow,
2022-09-28 12:01:29 +02:00
focus::target::KeyboardFocusTarget,
2023-01-18 20:23:41 +01:00
grabs::ResizeEdge,
2022-09-28 12:01:29 +02:00
layout::{floating::FloatingLayout, tiling::TilingLayout},
};
2022-03-24 20:32:31 +01:00
pub struct Shell {
pub popups: PopupManager,
pub outputs: Vec<Output>,
2022-09-28 12:01:29 +02:00
pub workspaces: WorkspaceMode,
2023-01-27 13:26:28 +01:00
pub tiling_enabled: bool,
pub pending_windows: Vec<(CosmicSurface, Seat<State>)>,
pub pending_layers: Vec<(LayerSurface, Output, Seat<State>)>,
2023-01-18 20:23:41 +01:00
pub override_redirect_windows: Vec<OverrideRedirectWindow>,
// wayland_state
pub layer_shell_state: WlrLayerShellState,
pub toplevel_info_state: ToplevelInfoState<State, CosmicSurface>,
2022-07-18 21:26:02 +02:00
pub toplevel_management_state: ToplevelManagementState,
pub xdg_shell_state: XdgShellState,
pub workspace_state: WorkspaceState<State>,
2022-03-24 20:32:31 +01:00
}
2023-01-23 18:25:01 +01:00
#[derive(Debug)]
2023-01-18 20:23:41 +01:00
pub struct OverrideRedirectWindow {
pub surface: X11Surface,
2023-01-23 18:25:01 +01:00
pub above: Ordering,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Ordering {
Above,
AboveWindow(Id),
Below,
2023-01-18 20:23:41 +01:00
}
2022-09-28 12:01:29 +02:00
#[derive(Debug)]
pub struct WorkspaceSet {
active: usize,
2022-11-10 17:22:16 +01:00
amount: WorkspaceAmount,
2022-09-28 12:01:29 +02:00
group: WorkspaceGroupHandle,
idx: usize,
2023-01-27 13:26:28 +01:00
tiling_enabled: bool,
pub(crate) workspaces: Vec<Workspace>,
2022-09-28 12:01:29 +02:00
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum WorkspaceAmount {
Dynamic,
Static(u8),
2022-03-24 20:32:31 +01:00
}
2022-09-28 12:01:29 +02:00
fn create_workspace(
state: &mut WorkspaceUpdateGuard<'_, State>,
group_handle: &WorkspaceGroupHandle,
active: bool,
2023-01-27 13:26:28 +01:00
tiling: bool,
2022-09-28 12:01:29 +02:00
) -> Workspace {
let workspace_handle = state.create_workspace(&group_handle).unwrap();
if active {
state.add_workspace_state(&workspace_handle, WState::Active);
}
2022-11-08 09:38:43 +01:00
state.set_workspace_capabilities(
&workspace_handle,
[WorkspaceCapabilities::Activate].into_iter(),
);
2023-01-27 13:26:28 +01:00
Workspace::new(workspace_handle, tiling)
2022-09-28 12:01:29 +02:00
}
impl WorkspaceSet {
fn new(
state: &mut WorkspaceUpdateGuard<'_, State>,
amount: WorkspaceAmount,
idx: usize,
2023-01-27 13:26:28 +01:00
tiling_enabled: bool,
) -> WorkspaceSet {
2022-09-28 12:01:29 +02:00
let group_handle = state.create_workspace_group();
let workspaces = match amount {
WorkspaceAmount::Dynamic => {
2023-01-27 13:26:28 +01:00
let workspace = create_workspace(state, &group_handle, true, tiling_enabled);
workspace_set_idx(state, 1, idx, &workspace.handle);
2022-11-08 09:38:43 +01:00
state.set_workspace_capabilities(
&workspace.handle,
[WorkspaceCapabilities::Activate].into_iter(),
);
vec![workspace]
2022-09-28 12:01:29 +02:00
}
WorkspaceAmount::Static(len) => (0..len)
2022-11-08 09:38:43 +01:00
.map(|i| {
2023-01-27 13:26:28 +01:00
let workspace = create_workspace(state, &group_handle, i == 0, tiling_enabled);
workspace_set_idx(state, i + 1, idx, &workspace.handle);
2022-11-08 09:38:43 +01:00
state.set_workspace_capabilities(
&workspace.handle,
[WorkspaceCapabilities::Activate].into_iter(),
);
workspace
})
2022-09-28 12:01:29 +02:00
.collect(),
};
WorkspaceSet {
active: 0,
2022-11-10 17:22:16 +01:00
amount,
2022-09-28 12:01:29 +02:00
group: group_handle,
idx,
2023-01-27 13:26:28 +01:00
tiling_enabled,
2022-09-28 12:01:29 +02:00
workspaces,
}
}
fn activate(&mut self, idx: usize, state: &mut WorkspaceUpdateGuard<'_, State>) {
if idx < self.workspaces.len() && self.active != idx {
let old_active = self.active;
state.remove_workspace_state(&self.workspaces[old_active].handle, WState::Active);
state.add_workspace_state(&self.workspaces[idx].handle, WState::Active);
self.active = idx;
}
}
fn refresh<'a>(
2022-09-28 12:01:29 +02:00
&mut self,
state: &mut WorkspaceState<State>,
toplevel_info: &mut ToplevelInfoState<State, CosmicSurface>,
outputs: impl Iterator<Item = (&'a Output, Point<i32, Logical>)>,
2022-09-28 12:01:29 +02:00
) {
2022-11-10 17:22:16 +01:00
match self.amount {
WorkspaceAmount::Dynamic => self.ensure_last_empty(state, outputs),
WorkspaceAmount::Static(len) => {
self.ensure_static(len as usize, state, toplevel_info, outputs)
}
2022-09-28 12:01:29 +02:00
}
self.workspaces[self.active].refresh();
}
fn ensure_last_empty<'a>(
&mut self,
state: &mut WorkspaceState<State>,
outputs: impl Iterator<Item = (&'a Output, Point<i32, Logical>)>,
) {
2022-11-08 09:38:43 +01:00
let mut state = state.update();
2022-09-28 12:01:29 +02:00
// add empty at the end, if necessary
if self.workspaces.last().unwrap().windows().next().is_some() {
2023-01-27 13:26:28 +01:00
let mut workspace =
create_workspace(&mut state, &self.group, false, self.tiling_enabled);
2022-11-29 18:40:53 +01:00
workspace_set_idx(
&mut state,
self.workspaces.len() as u8 + 1,
2022-11-29 18:40:53 +01:00
self.idx,
&workspace.handle,
);
2022-11-08 09:38:43 +01:00
state.set_workspace_capabilities(
&workspace.handle,
[WorkspaceCapabilities::Activate].into_iter(),
);
for (output, location) in outputs {
workspace.map_output(output, location);
}
self.workspaces.push(workspace);
2022-09-28 12:01:29 +02:00
}
let len = self.workspaces.len();
let mut keep = vec![true; len];
// remove empty workspaces in between, if they are not active
for (i, workspace) in self.workspaces.iter().enumerate() {
let has_windows = workspace.windows().next().is_some();
if !has_windows && i != self.active && i != len - 1 {
2022-11-08 09:38:43 +01:00
state.remove_workspace(workspace.handle);
2022-09-28 12:01:29 +02:00
keep[i] = false;
}
}
let mut iter = keep.iter();
self.workspaces.retain(|_| *iter.next().unwrap());
self.active -= keep
.iter()
.take(self.active + 1)
.filter(|keep| !**keep)
.count();
2022-11-08 09:38:43 +01:00
if keep.iter().any(|val| *val == false) {
for (i, workspace) in self.workspaces.iter().enumerate() {
workspace_set_idx(&mut state, i as u8 + 1, self.idx, &workspace.handle);
2022-11-08 09:38:43 +01:00
}
}
2022-09-28 12:01:29 +02:00
}
fn ensure_static<'a>(
2022-09-28 12:01:29 +02:00
&mut self,
amount: usize,
state: &mut WorkspaceState<State>,
toplevel_info: &mut ToplevelInfoState<State, CosmicSurface>,
outputs: impl Iterator<Item = (&'a Output, Point<i32, Logical>)>,
2022-09-28 12:01:29 +02:00
) {
if amount < self.workspaces.len() {
let mut state = state.update();
// merge last ones
let overflow = self.workspaces.split_off(amount);
if self.active >= self.workspaces.len() {
self.active = self.workspaces.len() - 1;
state.add_workspace_state(&self.workspaces[self.active].handle, WState::Active);
}
let last_space = self.workspaces.last_mut().unwrap();
for workspace in overflow {
for element in workspace.mapped() {
// fixup toplevel state
for (toplevel, _) in element.windows() {
toplevel_info.toplevel_leave_workspace(&toplevel, &workspace.handle);
toplevel_info.toplevel_enter_workspace(&toplevel, &last_space.handle);
}
}
last_space.tiling_layer.merge(workspace.tiling_layer);
last_space.floating_layer.merge(workspace.floating_layer);
last_space
.fullscreen
.extend(workspace.fullscreen.into_iter());
state.remove_workspace(workspace.handle);
}
last_space.refresh();
} else if amount > self.workspaces.len() {
let mut state = state.update();
// add empty ones
let outputs = outputs.collect::<Vec<_>>();
2022-09-28 12:01:29 +02:00
while amount > self.workspaces.len() {
2023-01-27 13:26:28 +01:00
let mut workspace =
create_workspace(&mut state, &self.group, false, self.tiling_enabled);
2022-11-08 09:38:43 +01:00
workspace_set_idx(
&mut state,
self.workspaces.len() as u8 + 1,
self.idx,
2022-11-08 09:38:43 +01:00
&workspace.handle,
);
state.set_workspace_capabilities(
&workspace.handle,
[WorkspaceCapabilities::Activate].into_iter(),
);
for &(output, location) in outputs.iter() {
workspace.map_output(output, location);
}
self.workspaces.push(workspace);
2022-09-28 12:01:29 +02:00
}
}
}
fn update_idx(&mut self, state: &mut WorkspaceUpdateGuard<'_, State>, idx: usize) {
self.idx = idx;
for (i, workspace) in self.workspaces.iter().enumerate() {
workspace_set_idx(state, i as u8 + 1, idx, &workspace.handle);
}
}
2023-01-27 13:26:28 +01:00
fn update_tiling_status(&mut self, seat: &Seat<State>, tiling_enabled: bool) {
self.tiling_enabled = tiling_enabled;
for workspace in &mut self.workspaces {
if workspace.tiling_enabled != tiling_enabled {
workspace.toggle_tiling(seat);
}
}
}
2022-03-24 20:32:31 +01:00
}
2021-12-21 18:57:09 +01:00
2022-09-28 12:01:29 +02:00
#[derive(Debug)]
pub enum WorkspaceMode {
2022-11-10 17:22:16 +01:00
OutputBound(HashMap<Output, WorkspaceSet>, WorkspaceAmount),
2022-09-28 12:01:29 +02:00
Global(WorkspaceSet),
2021-12-21 18:57:09 +01:00
}
2022-09-28 12:01:29 +02:00
impl WorkspaceMode {
pub fn new(
config: crate::config::WorkspaceMode,
amount: WorkspaceAmount,
state: &mut WorkspaceUpdateGuard<'_, State>,
2023-01-27 13:26:28 +01:00
tiling_enabled: bool,
2022-09-28 12:01:29 +02:00
) -> WorkspaceMode {
match config {
crate::config::WorkspaceMode::Global => {
2023-01-27 13:26:28 +01:00
WorkspaceMode::Global(WorkspaceSet::new(state, amount, 0, tiling_enabled))
2022-09-28 12:01:29 +02:00
}
2022-11-10 17:22:16 +01:00
crate::config::WorkspaceMode::OutputBound => {
WorkspaceMode::OutputBound(HashMap::new(), amount)
}
2022-09-28 12:01:29 +02:00
}
}
pub fn get(&self, num: usize, output: &Output) -> Option<&Workspace> {
match self {
WorkspaceMode::Global(set) => set.workspaces.get(num),
2022-11-10 17:22:16 +01:00
WorkspaceMode::OutputBound(sets, _) => {
2022-09-28 12:01:29 +02:00
sets.get(output).and_then(|set| set.workspaces.get(num))
}
}
}
pub fn get_mut(&mut self, num: usize, output: &Output) -> Option<&mut Workspace> {
match self {
WorkspaceMode::Global(set) => set.workspaces.get_mut(num),
2022-11-10 17:22:16 +01:00
WorkspaceMode::OutputBound(sets, _) => sets
2022-09-28 12:01:29 +02:00
.get_mut(output)
.and_then(|set| set.workspaces.get_mut(num)),
}
}
pub fn active(&self, output: &Output) -> &Workspace {
match self {
WorkspaceMode::Global(set) => &set.workspaces[set.active],
2022-11-10 17:22:16 +01:00
WorkspaceMode::OutputBound(sets, _) => {
2022-09-28 12:01:29 +02:00
let set = sets.get(output).unwrap();
&set.workspaces[set.active]
}
}
}
pub fn active_mut(&mut self, output: &Output) -> &mut Workspace {
match self {
WorkspaceMode::Global(set) => &mut set.workspaces[set.active],
2022-11-10 17:22:16 +01:00
WorkspaceMode::OutputBound(sets, _) => {
2022-09-28 12:01:29 +02:00
let set = sets.get_mut(output).unwrap();
&mut set.workspaces[set.active]
}
}
}
2022-11-10 17:22:16 +01:00
pub fn active_num(&self, output: &Output) -> usize {
2022-09-28 12:01:29 +02:00
match self {
WorkspaceMode::Global(set) => set.active,
2022-11-10 17:22:16 +01:00
WorkspaceMode::OutputBound(sets, _) => {
2022-09-28 12:01:29 +02:00
let set = sets.get(output).unwrap();
set.active
}
}
}
2022-11-10 18:42:11 +01:00
pub fn len(&self, output: &Output) -> usize {
match self {
WorkspaceMode::Global(set) => set.workspaces.len(),
WorkspaceMode::OutputBound(sets, _) => {
let set = sets.get(output).unwrap();
set.workspaces.len()
}
}
}
2022-09-28 12:01:29 +02:00
pub fn spaces(&self) -> impl Iterator<Item = &Workspace> {
match self {
WorkspaceMode::Global(set) => {
Box::new(set.workspaces.iter()) as Box<dyn Iterator<Item = &Workspace>>
}
2022-11-10 17:22:16 +01:00
WorkspaceMode::OutputBound(sets, _) => {
2022-09-28 12:01:29 +02:00
Box::new(sets.values().flat_map(|set| set.workspaces.iter()))
}
}
}
pub fn spaces_for_output(&self, output: &Output) -> impl Iterator<Item = &Workspace> {
match self {
WorkspaceMode::Global(set) => {
Box::new(set.workspaces.iter()) as Box<dyn Iterator<Item = &Workspace>>
}
2022-11-10 17:22:16 +01:00
WorkspaceMode::OutputBound(sets, _) => Box::new(
2022-09-28 12:01:29 +02:00
sets.get(output)
.into_iter()
.flat_map(|set| set.workspaces.iter()),
),
}
}
pub fn spaces_mut(&mut self) -> impl Iterator<Item = &mut Workspace> {
match self {
WorkspaceMode::Global(set) => {
Box::new(set.workspaces.iter_mut()) as Box<dyn Iterator<Item = &mut Workspace>>
}
2022-11-10 17:22:16 +01:00
WorkspaceMode::OutputBound(sets, _) => {
2022-09-28 12:01:29 +02:00
Box::new(sets.values_mut().flat_map(|set| set.workspaces.iter_mut()))
}
}
}
2023-01-27 13:26:28 +01:00
pub fn update_tiling_status(&mut self, seat: &Seat<State>, tiling: bool) {
match self {
WorkspaceMode::Global(set) => set.update_tiling_status(seat, tiling),
WorkspaceMode::OutputBound(sets, _) => {
for set in sets.values_mut() {
set.update_tiling_status(seat, tiling)
}
}
}
}
2022-09-28 12:01:29 +02:00
}
2022-03-24 20:32:31 +01:00
impl Shell {
pub fn new(config: &Config, dh: &DisplayHandle) -> Self {
2022-07-18 21:26:02 +02:00
// TODO: Privileged protocols
let layer_shell_state = WlrLayerShellState::new::<State, _>(dh, None);
let xdg_shell_state = XdgShellState::new::<State, _>(dh, None);
2022-07-18 21:26:02 +02:00
let toplevel_info_state = ToplevelInfoState::new(
dh,
2023-01-24 19:32:57 +01:00
//|client| client.get_data::<ClientState>().map_or(false, |s| s.privileged),
2022-08-30 13:28:36 +02:00
|_| true,
);
2022-07-18 21:26:02 +02:00
let toplevel_management_state = ToplevelManagementState::new::<State, _>(
dh,
2022-08-30 13:28:36 +02:00
vec![
ManagementCapabilities::Close,
ManagementCapabilities::Activate,
],
2023-01-24 19:32:57 +01:00
//|client| client.get_data::<ClientState>().map_or(false, |s| s.privileged),
2022-07-18 21:26:02 +02:00
|_| true,
);
let mut workspace_state = WorkspaceState::new(
dh,
2023-01-24 19:32:57 +01:00
//|client| client.get_data::<ClientState>().map_or(false, |s| s.privileged),
2022-07-18 21:26:02 +02:00
|_| true,
);
2023-01-27 13:26:28 +01:00
let tiling_enabled = config.static_conf.tiling_enabled;
2022-09-28 12:01:29 +02:00
let mode = WorkspaceMode::new(
config.static_conf.workspace_mode,
config.static_conf.workspace_amount,
&mut workspace_state.update(),
2023-01-27 13:26:28 +01:00
tiling_enabled,
2022-07-04 16:00:29 +02:00
);
2022-03-24 20:32:31 +01:00
Shell {
popups: PopupManager::new(None),
outputs: Vec::new(),
2022-09-28 12:01:29 +02:00
workspaces: mode,
2023-01-27 13:26:28 +01:00
tiling_enabled,
2021-12-28 16:23:12 +01:00
pending_windows: Vec::new(),
pending_layers: Vec::new(),
2023-01-18 20:23:41 +01:00
override_redirect_windows: Vec::new(),
layer_shell_state,
toplevel_info_state,
2022-07-18 21:26:02 +02:00
toplevel_management_state,
xdg_shell_state,
workspace_state,
}
}
2022-04-14 22:16:37 +02:00
pub fn add_output(&mut self, output: &Output) {
2022-11-11 21:36:42 +01:00
if self.outputs.contains(output) {
return;
}
2022-04-14 22:16:37 +02:00
self.outputs.push(output.clone());
let mut state = self.workspace_state.update();
2022-09-28 12:01:29 +02:00
match &mut self.workspaces {
2022-11-10 17:22:16 +01:00
WorkspaceMode::OutputBound(sets, amount) => {
2022-09-28 12:01:29 +02:00
// TODO: Restore previously assigned workspaces, if possible!
if !sets.contains_key(output) {
2023-01-27 13:26:28 +01:00
let set =
WorkspaceSet::new(&mut state, *amount, sets.len(), self.tiling_enabled);
2022-11-29 18:40:53 +01:00
state.add_group_output(&set.group, &output);
sets.insert(output.clone(), set);
2022-05-02 17:43:58 +02:00
}
2022-09-28 12:01:29 +02:00
for workspace in &mut sets.get_mut(output).unwrap().workspaces {
workspace.map_output(output, (0, 0).into());
}
2022-07-04 16:00:29 +02:00
}
2022-09-28 12:01:29 +02:00
WorkspaceMode::Global(set) => {
// TODO: Restore any window positions from previous outputs ???
state.add_group_output(&set.group, output);
for workspace in &mut set.workspaces {
workspace.map_output(
output,
output
.user_data()
.get::<RefCell<OutputConfig>>()
.unwrap()
.borrow()
.position
.into(),
);
2022-09-28 12:01:29 +02:00
}
}
}
}
pub fn remove_output(&mut self, output: &Output, seats: impl Iterator<Item = Seat<State>>) {
if let Some(first_output) = self.outputs.get(0) {
for seat in seats {
if &seat.active_output() == output {
seat.set_active_output(first_output);
}
}
}
2022-11-11 21:36:42 +01:00
if !self.outputs.contains(output) {
return;
}
let mut state = self.workspace_state.update();
self.outputs.retain(|o| o != output);
2022-07-04 16:00:29 +02:00
2022-09-28 12:01:29 +02:00
match &mut self.workspaces {
2022-11-10 17:22:16 +01:00
WorkspaceMode::OutputBound(sets, _) => {
2023-01-27 13:26:28 +01:00
// TODO:
// If amount::static merge them instead of appending
2022-09-28 12:01:29 +02:00
if let Some(set) = sets.remove(output) {
// TODO: Heuristic which output to move to.
// It is supposed to be the *most* internal, we just pick the first one for now
// and hope enumeration order works in our favor.
if let Some(new_output) = self.outputs.get(0) {
let new_set = sets.get_mut(new_output).unwrap();
let workspace_group = new_set.group;
for mut workspace in set.workspaces {
// update workspace protocol state
state.remove_workspace(workspace.handle);
let workspace_handle =
state.create_workspace(&workspace_group).unwrap();
2022-11-08 09:38:43 +01:00
state.set_workspace_capabilities(
&workspace_handle,
[WorkspaceCapabilities::Activate].into_iter(),
);
2022-09-28 12:01:29 +02:00
workspace.handle = workspace_handle;
// update mapping
workspace.map_output(new_output, (0, 0).into());
workspace.unmap_output(output, &mut self.toplevel_info_state);
2022-09-28 12:01:29 +02:00
workspace.refresh();
new_set.workspaces.push(workspace);
2022-05-02 17:43:58 +02:00
}
2022-09-28 12:01:29 +02:00
state.remove_workspace_group(set.group);
2022-05-02 17:43:58 +02:00
}
2022-09-28 12:01:29 +02:00
// if there is no output, we are going to quit anyway, just drop the workspace set
2022-05-02 17:43:58 +02:00
}
for (i, set) in sets.values_mut().enumerate() {
set.update_idx(&mut state, i);
}
std::mem::drop(state);
self.refresh(); // cleans up excess of workspaces and empty workspaces
2022-07-04 16:00:29 +02:00
}
2022-09-28 12:01:29 +02:00
WorkspaceMode::Global(set) => {
state.remove_group_output(&set.group, output);
for workspace in &mut set.workspaces {
workspace.unmap_output(output, &mut self.toplevel_info_state);
2022-09-28 12:01:29 +02:00
workspace.refresh();
}
2022-07-04 16:00:29 +02:00
}
};
2022-03-24 20:32:31 +01:00
}
2021-12-28 16:23:12 +01:00
pub fn refresh_outputs(&mut self) {
2022-09-28 12:01:29 +02:00
if let WorkspaceMode::Global(set) = &mut self.workspaces {
for workspace in &mut set.workspaces {
for output in self.outputs.iter() {
workspace.map_output(
output,
output
.user_data()
.get::<RefCell<OutputConfig>>()
.unwrap()
.borrow()
.position
.into(),
);
2022-09-28 12:01:29 +02:00
}
}
2022-03-24 20:32:31 +01:00
}
}
pub fn set_mode(&mut self, mode: ConfigMode) {
2022-09-28 12:01:29 +02:00
let mut state = self.workspace_state.update();
match (&mut self.workspaces, mode) {
2022-11-10 17:22:16 +01:00
(dst @ WorkspaceMode::OutputBound(_, _), ConfigMode::Global) => {
2022-09-28 12:01:29 +02:00
// rustc should really be able to infer that this doesn't need an if.
2022-11-10 17:22:16 +01:00
let (sets, amount) =
if let &mut WorkspaceMode::OutputBound(ref mut sets, ref amount) = dst {
(sets, *amount)
} else {
unreachable!()
};
2022-09-28 12:01:29 +02:00
// in this case we have to merge our sets, preserving placing of windows as nicely as possible
2023-01-27 13:26:28 +01:00
let mut new_set = WorkspaceSet::new(
&mut state,
WorkspaceAmount::Static(0),
0,
self.tiling_enabled,
);
2022-11-29 18:40:53 +01:00
for output in &self.outputs {
state.add_group_output(&new_set.group, output);
}
2022-09-28 12:01:29 +02:00
// lets construct an iterator of all the pairs of workspaces we have to merge
// we first split of the part of the workspaces that contain the currently active one
let mut second_half = sets
.iter_mut()
.map(|(output, set)| (output.clone(), set.workspaces.split_off(set.active)))
.collect::<Vec<_>>();
let mut first_half = std::iter::repeat(())
// we continuously pop the last elements from the first half and group them together.
.map(|_| {
sets.iter_mut()
.flat_map(|(o, w)| w.workspaces.pop().map(|w| (o.clone(), w)))
.collect::<Vec<_>>()
})
// we stop once there is no workspace anymore in the entire set
.filter(|vec| !vec.is_empty())
.fuse()
.collect::<Vec<_>>();
// we reverse those then to get the proper order
first_half.reverse();
let mergers = first_half
.into_iter()
// we need to know, which is supposed to be active and we loose that info by chaining, so lets add a bool
.map(|w| (w, false))
.chain(
(0..)
// here we continuously remove the first element
.map(|i| {
(
second_half
.iter_mut()
.flat_map(|&mut (ref o, ref mut w)| {
if !w.is_empty() {
Some((o.clone(), w.remove(0)))
} else {
None
}
})
.collect::<Vec<_>>(),
i == 0,
)
})
.filter(|(vec, _)| !vec.is_empty())
.fuse(),
2022-07-04 16:00:29 +02:00
);
2022-09-28 12:01:29 +02:00
for (i, (workspaces, active)) in mergers.into_iter().enumerate() {
// and then we can merge each vector into one and put that into our new set.
let workspace_handle = state.create_workspace(&new_set.group).unwrap();
2022-11-08 09:38:43 +01:00
state.set_workspace_capabilities(
&workspace_handle,
[WorkspaceCapabilities::Activate].into_iter(),
);
workspace_set_idx(&mut state, i as u8 + 1, 0, &workspace_handle);
2022-09-28 12:01:29 +02:00
2023-01-27 13:26:28 +01:00
let mut new_workspace = Workspace::new(workspace_handle, self.tiling_enabled);
2022-09-28 12:01:29 +02:00
for output in self.outputs.iter() {
new_workspace.map_output(output, output.current_location());
}
new_workspace.tiling_enabled = workspaces.iter().any(|(_, w)| w.tiling_enabled);
for (_output, workspace) in workspaces.into_iter() {
for toplevel in workspace.windows() {
self.toplevel_info_state
.toplevel_leave_workspace(&toplevel, &workspace.handle);
self.toplevel_info_state
.toplevel_enter_workspace(&toplevel, &new_workspace.handle);
}
new_workspace.tiling_layer.merge(workspace.tiling_layer);
new_workspace.floating_layer.merge(workspace.floating_layer);
new_workspace
.fullscreen
.extend(workspace.fullscreen.into_iter());
state.remove_workspace(workspace.handle);
2022-05-02 17:43:58 +02:00
}
2022-03-24 20:32:31 +01:00
2022-09-28 12:01:29 +02:00
if active {
new_set.active = new_set.workspaces.len();
}
2022-09-28 12:01:29 +02:00
new_set.workspaces.push(new_workspace);
}
2022-03-24 20:32:31 +01:00
2022-09-28 12:01:29 +02:00
for group in sets.values().map(|set| set.group) {
state.remove_workspace_group(group);
}
2022-07-04 16:00:29 +02:00
2022-11-10 17:22:16 +01:00
new_set.amount = amount;
2022-09-28 12:01:29 +02:00
*dst = WorkspaceMode::Global(new_set);
}
(dst @ WorkspaceMode::Global(_), ConfigMode::OutputBound) => {
// rustc should really be able to infer that this doesn't need an if.
let set = if let &mut WorkspaceMode::Global(ref mut set) = dst {
set
} else {
unreachable!()
};
2022-03-24 20:32:31 +01:00
2022-09-28 12:01:29 +02:00
// split workspaces apart, preserving window positions relative to their outputs
let mut sets = HashMap::new();
for (i, output) in self.outputs.iter().enumerate() {
2023-01-27 13:26:28 +01:00
let set = WorkspaceSet::new(
&mut state,
WorkspaceAmount::Static(0),
i,
self.tiling_enabled,
);
2022-11-29 18:40:53 +01:00
state.add_group_output(&set.group, output);
sets.insert(output.clone(), set);
2021-12-21 18:57:09 +01:00
}
2022-09-28 12:01:29 +02:00
for (i, workspace) in set.workspaces.drain(..).enumerate() {
for (idx, output) in self.outputs.iter().enumerate() {
2022-09-28 12:01:29 +02:00
// copy over everything and then remove other outputs to preserve state
let new_set = sets.get_mut(output).unwrap();
let new_workspace_handle = state.create_workspace(&new_set.group).unwrap();
2022-11-08 09:38:43 +01:00
state.set_workspace_capabilities(
&new_workspace_handle,
[WorkspaceCapabilities::Activate].into_iter(),
);
workspace_set_idx(&mut state, i as u8 + 1, idx, &new_workspace_handle);
2022-09-28 12:01:29 +02:00
let mut old_tiling_layer = workspace.tiling_layer.clone();
let mut new_floating_layer = FloatingLayout::new();
let mut new_tiling_layer = TilingLayout::new();
for element in workspace.mapped() {
for (toplevel, _) in element.windows() {
self.toplevel_info_state
.toplevel_leave_workspace(&toplevel, &workspace.handle);
}
if workspace
.floating_layer
.most_overlapped_output_for_element(element)
.as_ref()
== Some(output)
{
if let Some(mut old_mapped_loc) =
workspace.floating_layer.space.element_location(element)
{
let old_output_geo = workspace
.floating_layer
.space
.output_geometry(output)
.unwrap();
old_mapped_loc -= old_output_geo.loc;
new_floating_layer.map_internal(
element.clone(),
output,
Some(old_mapped_loc),
);
}
} else {
old_tiling_layer.unmap(element);
}
}
new_floating_layer.map_output(output, (0, 0).into());
new_tiling_layer.map_output(output, (0, 0).into());
new_tiling_layer.merge(old_tiling_layer);
let mut new_workspace = Workspace {
tiling_layer: new_tiling_layer,
floating_layer: new_floating_layer,
tiling_enabled: workspace.tiling_enabled,
fullscreen: workspace
.fullscreen
.iter()
.filter(|(key, _)| *key == output)
.map(|(o, w)| (o.clone(), w.clone()))
.collect(),
2023-01-27 13:26:28 +01:00
..Workspace::new(new_workspace_handle, true)
2022-09-28 12:01:29 +02:00
};
for toplevel in new_workspace.windows() {
self.toplevel_info_state
.toplevel_enter_workspace(&toplevel, &new_workspace_handle);
}
new_workspace.refresh();
new_set.workspaces.push(new_workspace);
new_set.active = set.active;
}
state.remove_workspace(workspace.handle);
}
state.remove_workspace_group(set.group);
2022-11-10 17:22:16 +01:00
for new_set in sets.values_mut() {
new_set.amount = set.amount;
}
*dst = WorkspaceMode::OutputBound(sets, set.amount);
2022-07-04 16:00:29 +02:00
}
2022-09-28 12:01:29 +02:00
_ => {}
}
2022-01-25 16:31:58 +01:00
2022-09-28 12:01:29 +02:00
std::mem::drop(state);
self.refresh(); // get rid of empty workspaces and enforce potential maximum
}
2022-11-22 10:10:08 +01:00
pub fn activate(&mut self, output: &Output, idx: usize) -> Option<Point<i32, Logical>> {
2022-09-28 12:01:29 +02:00
match &mut self.workspaces {
2022-11-10 17:22:16 +01:00
WorkspaceMode::OutputBound(sets, _) => {
2022-09-28 12:01:29 +02:00
if let Some(set) = sets.get_mut(output) {
set.activate(idx, &mut self.workspace_state.update());
2022-01-25 16:31:58 +01:00
}
2022-09-28 12:01:29 +02:00
}
WorkspaceMode::Global(set) => {
set.activate(idx, &mut self.workspace_state.update());
2021-12-21 18:57:09 +01:00
}
}
2021-12-21 18:57:09 +01:00
2022-11-22 10:10:08 +01:00
let output_geo = output.geometry();
Some(output_geo.loc + Point::from((output_geo.size.w / 2, output_geo.size.h / 2)))
2021-12-28 16:23:12 +01:00
}
2022-03-24 20:32:31 +01:00
pub fn active_space(&self, output: &Output) -> &Workspace {
2022-09-28 12:01:29 +02:00
match &self.workspaces {
2022-11-10 17:22:16 +01:00
WorkspaceMode::OutputBound(sets, _) => {
2022-09-28 12:01:29 +02:00
let set = sets.get(output).unwrap();
&set.workspaces[set.active]
2022-03-24 20:32:31 +01:00
}
2022-09-28 12:01:29 +02:00
WorkspaceMode::Global(set) => &set.workspaces[set.active],
2021-12-21 18:57:09 +01:00
}
2022-03-24 20:32:31 +01:00
}
2021-12-21 18:57:09 +01:00
2022-03-24 20:32:31 +01:00
pub fn active_space_mut(&mut self, output: &Output) -> &mut Workspace {
2022-09-28 12:01:29 +02:00
match &mut self.workspaces {
2022-11-10 17:22:16 +01:00
WorkspaceMode::OutputBound(sets, _) => {
2022-09-28 12:01:29 +02:00
let set = sets.get_mut(output).unwrap();
&mut set.workspaces[set.active]
2021-12-21 18:57:09 +01:00
}
2022-09-28 12:01:29 +02:00
WorkspaceMode::Global(set) => &mut set.workspaces[set.active],
2021-12-21 18:57:09 +01:00
}
}
2022-11-03 18:51:27 +01:00
pub fn visible_outputs_for_surface<'a>(
2022-08-30 13:28:36 +02:00
&'a self,
surface: &'a WlSurface,
) -> impl Iterator<Item = Output> + 'a {
match self.outputs.iter().find(|o| {
let map = layer_map_for_output(o);
2022-08-30 13:28:36 +02:00
map.layer_for_surface(surface, WindowSurfaceType::ALL)
.is_some()
}) {
2022-08-30 13:28:36 +02:00
Some(output) => {
Box::new(std::iter::once(output.clone())) as Box<dyn Iterator<Item = Output>>
}
2023-01-23 18:25:01 +01:00
None => Box::new(
self.outputs()
.filter(|o| {
self.override_redirect_windows.iter().any(|or| {
if or.surface.wl_surface().as_ref() == Some(surface) {
or.surface.geometry().intersection(o.geometry()).is_some()
} else {
false
}
})
})
.cloned()
.chain(self.outputs().map(|o| self.active_space(o)).flat_map(|w| {
w.mapped()
.find(|e| e.has_surface(surface, WindowSurfaceType::ALL))
.into_iter()
.flat_map(|e| w.outputs_for_element(e))
})),
),
}
}
2022-11-03 18:51:27 +01:00
pub fn workspaces_for_surface(
&self,
surface: &WlSurface,
) -> impl Iterator<Item = (WorkspaceHandle, Output)> {
match self.outputs.iter().find(|o| {
let map = layer_map_for_output(o);
map.layer_for_surface(surface, WindowSurfaceType::ALL)
.is_some()
}) {
Some(output) => self
.workspaces
.spaces()
.filter(move |workspace| {
workspace
.floating_layer
.space
.outputs()
.any(|o| o == output)
})
.map(|w| (w.handle.clone(), output.clone()))
.collect::<Vec<_>>(),
None => self
.workspaces
.spaces()
.filter_map(|w| {
if let Some(mapped) = w
.mapped()
.find(|e| e.has_surface(surface, WindowSurfaceType::ALL))
{
let outputs = w.outputs_for_element(mapped);
Some(std::iter::repeat(w.handle.clone()).zip(outputs).fuse())
} else {
None
}
})
.flatten()
.collect::<Vec<_>>(),
}
.into_iter()
}
2023-01-18 20:23:41 +01:00
pub fn element_for_surface(&self, surface: &CosmicSurface) -> Option<&CosmicMapped> {
2022-09-28 12:01:29 +02:00
self.workspaces
.spaces()
.find_map(|w| w.element_for_surface(surface))
2022-03-24 20:32:31 +01:00
}
2021-12-28 16:23:12 +01:00
2023-01-18 20:23:41 +01:00
pub fn element_for_wl_surface(&self, surface: &WlSurface) -> Option<&CosmicMapped> {
self.workspaces
.spaces()
.find_map(|w| w.element_for_wl_surface(surface))
}
2022-09-28 12:01:29 +02:00
pub fn space_for(&self, mapped: &CosmicMapped) -> Option<&Workspace> {
self.workspaces
.spaces()
.find(|workspace| workspace.mapped().any(|m| m == mapped))
}
pub fn space_for_mut(&mut self, mapped: &CosmicMapped) -> Option<&mut Workspace> {
self.workspaces
.spaces_mut()
.find(|workspace| workspace.mapped().any(|m| m == mapped))
2021-12-28 16:23:12 +01:00
}
2022-07-04 16:00:29 +02:00
2022-11-03 18:51:27 +01:00
pub fn space_for_handle(&self, handle: &WorkspaceHandle) -> Option<&Workspace> {
self.workspaces.spaces().find(|w| &w.handle == handle)
}
pub fn space_for_handle_mut(&mut self, handle: &WorkspaceHandle) -> Option<&mut Workspace> {
self.workspaces.spaces_mut().find(|w| &w.handle == handle)
}
2022-07-04 16:00:29 +02:00
pub fn outputs(&self) -> impl Iterator<Item = &Output> {
self.outputs.iter()
}
2021-12-28 16:23:12 +01:00
pub fn global_space(&self) -> Rectangle<i32, Logical> {
self.outputs
.iter()
.fold(
Option::<Rectangle<i32, Logical>>::None,
|maybe_geo, output| match maybe_geo {
Some(rect) => Some(rect.merge(output.geometry())),
None => Some(output.geometry()),
},
)
.unwrap_or_else(|| Rectangle::from_loc_and_size((0, 0), (0, 0)))
}
2022-09-28 12:01:29 +02:00
pub fn map_global_to_space<C: smithay::utils::Coordinate>(
&self,
global_loc: impl Into<Point<C, Logical>>,
output: &Output,
) -> Point<C, Logical> {
2022-09-28 12:01:29 +02:00
match self.workspaces {
WorkspaceMode::Global(_) => global_loc.into(),
2022-11-10 17:22:16 +01:00
WorkspaceMode::OutputBound(_, _) => {
let p = global_loc.into().to_f64() - output.current_location().to_f64();
(C::from_f64(p.x), C::from_f64(p.y)).into()
}
}
}
2022-09-28 12:01:29 +02:00
pub fn refresh(&mut self) {
self.popups.cleanup();
match &mut self.workspaces {
2022-11-10 17:22:16 +01:00
WorkspaceMode::OutputBound(sets, _) => {
for (output, set) in sets.iter_mut() {
2022-09-28 12:01:29 +02:00
set.refresh(
&mut self.workspace_state,
&mut self.toplevel_info_state,
std::iter::once((output, (0, 0).into())),
2022-09-28 12:01:29 +02:00
);
}
}
2022-09-28 12:01:29 +02:00
WorkspaceMode::Global(set) => set.refresh(
&mut self.workspace_state,
&mut self.toplevel_info_state,
self.outputs.iter().map(|o| (o, o.current_location())),
2022-09-28 12:01:29 +02:00
),
}
for output in &self.outputs {
2022-04-26 18:55:04 +02:00
let mut map = layer_map_for_output(output);
2022-09-28 12:01:29 +02:00
map.cleanup();
}
2022-09-28 12:01:29 +02:00
2023-01-23 18:25:01 +01:00
self.override_redirect_windows
.retain(|or| or.surface.alive());
self.override_redirect_windows
.iter()
.for_each(|or| or.surface.refresh());
2023-01-23 18:25:01 +01:00
2022-07-04 16:00:29 +02:00
self.toplevel_info_state
.refresh(Some(&self.workspace_state));
2022-03-24 20:32:31 +01:00
}
2022-07-04 16:00:29 +02:00
pub fn map_window(state: &mut State, window: &CosmicSurface, output: &Output) {
2022-08-31 13:01:23 +02:00
let pos = state
.common
.shell
2022-07-04 16:00:29 +02:00
.pending_windows
.iter()
.position(|(w, _)| w == window)
.unwrap();
2022-08-31 13:01:23 +02:00
let (window, seat) = state.common.shell.pending_windows.remove(pos);
2022-09-28 12:01:29 +02:00
let workspace = state.common.shell.workspaces.active_mut(output);
state.common.shell.toplevel_info_state.new_toplevel(&window);
2022-08-31 13:01:23 +02:00
state
.common
.shell
.toplevel_info_state
2022-09-28 12:01:29 +02:00
.toplevel_enter_output(&window, &output);
2022-08-31 13:01:23 +02:00
state
.common
.shell
.toplevel_info_state
2022-09-28 12:01:29 +02:00
.toplevel_enter_workspace(&window, &workspace.handle);
let mapped = CosmicMapped::from(CosmicWindow::new(
window.clone(),
state.common.event_loop_handle.clone(),
));
#[cfg(feature = "debug")]
{
mapped.set_debug(state.common.egui.active);
}
2023-01-27 13:26:28 +01:00
if layout::should_be_floating(&window) || !workspace.tiling_enabled {
2022-09-28 12:01:29 +02:00
workspace.floating_layer.map(mapped.clone(), &seat, None);
} else {
2022-09-28 12:01:29 +02:00
let focus_stack = workspace.focus_stack.get(&seat);
workspace
.tiling_layer
.map(mapped.clone(), &seat, focus_stack.iter());
2022-03-24 20:32:31 +01:00
}
2022-07-05 18:46:38 +02:00
2023-01-18 20:23:41 +01:00
if let CosmicSurface::X11(surface) = window {
if let Some(xwm) = state
.common
.xwayland_state
.values_mut()
.flat_map(|state| state.xwm.as_mut())
.find(|xwm| Some(xwm.id()) == surface.xwm_id())
{
if let Err(err) = xwm.update_stacking_order_downwards(workspace.mapped()) {
slog_scope::warn!("Failed to update Xwayland stacking order: {}", err);
}
}
}
2022-09-28 12:01:29 +02:00
Shell::set_focus(state, Some(&KeyboardFocusTarget::from(mapped)), &seat, None);
2022-07-06 23:35:17 +02:00
2022-09-28 12:01:29 +02:00
let active_space = state.common.shell.active_space(output);
for mapped in active_space.mapped() {
state.common.shell.update_reactive_popups(mapped);
2022-07-05 18:46:38 +02:00
}
}
2023-01-18 20:23:41 +01:00
pub fn map_override_redirect(state: &mut State, window: X11Surface) {
let geo = window.geometry();
for (output, overlap) in state
2023-01-18 20:23:41 +01:00
.common
.shell
.outputs()
.cloned()
.filter_map(|o| o.geometry().intersection(geo).map(|overlap| (o, overlap)))
{
window.output_enter(&output, overlap);
}
2023-01-18 20:23:41 +01:00
state
.common
.shell
.override_redirect_windows
.push(OverrideRedirectWindow {
surface: window,
2023-01-23 18:25:01 +01:00
above: Ordering::Above,
2023-01-18 20:23:41 +01:00
});
}
2022-08-31 13:01:23 +02:00
pub fn map_layer(state: &mut State, layer_surface: &LayerSurface) {
let pos = state
.common
.shell
2022-07-04 16:00:29 +02:00
.pending_layers
.iter()
.position(|(l, _, _)| l == layer_surface)
.unwrap();
2022-08-31 13:01:23 +02:00
let (layer_surface, output, seat) = state.common.shell.pending_layers.remove(pos);
2022-07-04 16:00:29 +02:00
let wants_focus = {
2022-09-28 12:01:29 +02:00
with_states(layer_surface.wl_surface(), |states| {
let state = states.cached_state.current::<LayerSurfaceCachedState>();
matches!(state.layer, Layer::Top | Layer::Overlay)
2022-07-15 14:22:25 +02:00
&& state.keyboard_interactivity != KeyboardInteractivity::None
})
};
2022-03-30 22:00:44 +02:00
let mut map = layer_map_for_output(&output);
2022-09-28 12:01:29 +02:00
map.map_layer(&layer_surface).unwrap();
if wants_focus {
2022-09-28 12:01:29 +02:00
Shell::set_focus(state, Some(&layer_surface.into()), &seat, None)
}
}
2022-11-10 18:42:11 +01:00
pub fn move_current_window(
state: &mut State,
seat: &Seat<State>,
from_output: &Output,
to: (&Output, Option<usize>),
2023-01-24 19:22:00 +01:00
follow: bool,
2022-11-22 10:10:08 +01:00
) -> Option<Point<i32, Logical>> {
2022-11-10 18:42:11 +01:00
let (to_output, to_idx) = to;
let to_idx = to_idx.unwrap_or(state.common.shell.workspaces.active_num(to_output));
if state
.common
.shell
.workspaces
.get(to_idx, to_output)
.is_none()
{
return None;
}
2022-11-10 18:42:11 +01:00
if from_output == to_output
&& to_idx == state.common.shell.workspaces.active_num(from_output)
{
2022-11-22 10:10:08 +01:00
return None;
}
2022-11-10 18:42:11 +01:00
let from_workspace = state.common.shell.workspaces.active_mut(from_output);
let maybe_window = from_workspace.focus_stack.get(seat).last().cloned();
2022-11-22 10:10:08 +01:00
let Some(mapped) = maybe_window else { return None; };
let Some(window_state) = from_workspace.unmap(&mapped) else { return None; };
2022-07-04 16:00:29 +02:00
for (toplevel, _) in mapped.windows() {
state
2022-11-10 18:42:11 +01:00
.common
.shell
.toplevel_info_state
.toplevel_leave_workspace(&toplevel, &from_workspace.handle);
if from_output != to_output {
state
.common
.shell
.toplevel_info_state
.toplevel_leave_output(&toplevel, from_output);
}
}
let elements = from_workspace.mapped().cloned().collect::<Vec<_>>();
std::mem::drop(from_workspace);
for mapped in elements.into_iter() {
state.common.shell.update_reactive_popups(&mapped);
}
2023-01-24 19:22:00 +01:00
let new_pos = if follow {
seat.set_active_output(&to_output);
state.common.shell.activate(to_output, to_idx)
} else {
None
};
2022-11-22 10:10:08 +01:00
let to_workspace = state
.common
.shell
.workspaces
.get_mut(to_idx, to_output)
.unwrap(); // checked above
let focus_stack = to_workspace.focus_stack.get(&seat);
if window_state == ManagedState::Floating {
to_workspace.floating_layer.map(mapped.clone(), &seat, None);
} else {
to_workspace
.tiling_layer
.map(mapped.clone(), &seat, focus_stack.iter());
}
for (toplevel, _) in mapped.windows() {
if from_output != to_output {
state
.common
.shell
.toplevel_info_state
.toplevel_enter_output(&toplevel, to_output);
}
state
.common
.shell
.toplevel_info_state
.toplevel_enter_workspace(&toplevel, &to_workspace.handle);
}
for mapped in to_workspace
.mapped()
.cloned()
.collect::<Vec<_>>()
.into_iter()
{
state.common.shell.update_reactive_popups(&mapped);
2022-07-04 16:00:29 +02:00
}
2023-01-24 19:22:00 +01:00
if follow {
Common::set_focus(state, Some(&KeyboardFocusTarget::from(mapped)), &seat, None);
}
2022-11-22 10:10:08 +01:00
new_pos
2022-09-28 12:01:29 +02:00
}
2022-09-28 12:01:29 +02:00
pub fn update_reactive_popups(&self, mapped: &CosmicMapped) {
if let Some(workspace) = self.space_for(mapped) {
let element_loc = workspace.element_geometry(mapped).unwrap().loc;
for (toplevel, offset) in mapped.windows() {
if let CosmicSurface::Wayland(toplevel) = toplevel {
let window_geo_offset = toplevel.geometry().loc;
update_reactive_popups(
&toplevel,
element_loc + offset + window_geo_offset,
self.outputs.iter(),
);
}
2022-03-24 20:32:31 +01:00
}
}
}
2023-01-18 20:23:41 +01:00
pub fn move_request(
state: &mut State,
surface: &WlSurface,
seat: &Seat<State>,
serial: impl Into<Option<Serial>>,
) {
let serial = serial.into();
if let Some(start_data) = check_grab_preconditions(&seat, surface, serial) {
if let Some(mapped) = state.common.shell.element_for_wl_surface(surface).cloned() {
if let Some(workspace) = state.common.shell.space_for_mut(&mapped) {
let output = seat.active_output();
let (window, _) = mapped
.windows()
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface))
.unwrap();
if let Some(grab) = workspace.move_request(&window, &seat, &output, start_data)
{
let handle = workspace.handle;
state
.common
.shell
.toplevel_info_state
.toplevel_leave_workspace(&window, &handle);
state
.common
.shell
.toplevel_info_state
.toplevel_leave_output(&window, &output);
seat.get_pointer().unwrap().set_grab(
state,
grab,
serial.unwrap_or_else(|| SERIAL_COUNTER.next_serial()),
Focus::Clear,
);
}
}
}
}
}
pub fn resize_request(
state: &mut State,
surface: &WlSurface,
seat: &Seat<State>,
serial: impl Into<Option<Serial>>,
edges: ResizeEdge,
) {
let serial = serial.into();
if let Some(start_data) = check_grab_preconditions(&seat, surface, serial) {
if let Some(mapped) = state.common.shell.element_for_wl_surface(surface).cloned() {
if let Some(workspace) = state.common.shell.space_for_mut(&mapped) {
if let Some(grab) = workspace.resize_request(&mapped, &seat, start_data, edges)
{
seat.get_pointer().unwrap().set_grab(
state,
grab,
serial.unwrap_or_else(|| SERIAL_COUNTER.next_serial()),
Focus::Clear,
);
}
}
}
}
}
2022-03-30 22:00:44 +02:00
}
2022-11-08 09:38:43 +01:00
fn workspace_set_idx<'a>(
2022-07-04 16:00:29 +02:00
state: &mut WorkspaceUpdateGuard<'a, State>,
2022-09-28 12:01:29 +02:00
idx: u8,
output_pos: usize,
2022-09-28 12:01:29 +02:00
handle: &WorkspaceHandle,
) {
state.set_workspace_name(&handle, format!("{}", idx));
state.set_workspace_coordinates(&handle, [Some(idx as u32), Some(output_pos as u32), None]);
2022-07-04 16:00:29 +02:00
}
2023-01-18 20:23:41 +01:00
pub fn check_grab_preconditions(
seat: &Seat<State>,
surface: &WlSurface,
serial: Option<Serial>,
) -> Option<PointerGrabStartData<State>> {
use smithay::reexports::wayland_server::Resource;
// TODO: touch resize.
let pointer = seat.get_pointer().unwrap();
// Check that this surface has a click grab.
if !match serial {
Some(serial) => pointer.has_grab(serial),
None => pointer.is_grabbed(),
} {
return None;
}
let start_data = pointer.grab_start_data().unwrap();
// If the focus was for a different surface, ignore the request.
if start_data.focus.is_none()
|| !start_data
.focus
.as_ref()
.unwrap()
.0
.same_client_as(&surface.id())
{
return None;
}
Some(start_data)
}