diff --git a/src/shell/mod.rs b/src/shell/mod.rs index ef871567..b15698c2 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -229,12 +229,27 @@ impl From<&CosmicSurface> for ActivationKey { } } +#[derive(Debug)] +pub struct PendingWindow { + pub surface: CosmicSurface, + pub seat: Seat, + pub fullscreen: Option, + pub maximized: bool, +} + +#[derive(Debug)] +pub struct PendingLayer { + pub surface: LayerSurface, + pub seat: Seat, + pub output: Output, +} + #[derive(Debug)] pub struct Shell { pub workspaces: Workspaces, - pub pending_windows: Vec<(CosmicSurface, Seat, Option)>, - pub pending_layers: Vec<(LayerSurface, Output, Seat)>, + pub pending_windows: Vec, + pub pending_layers: Vec, pub pending_activations: HashMap, pub override_redirect_windows: Vec, pub session_lock: Option, @@ -1612,14 +1627,14 @@ impl Shell { }) // pending layer map surface? .or_else(|| { - self.pending_layers.iter().find_map(|(l, output, _)| { + self.pending_layers.iter().find_map(|pending| { let mut found = false; - l.with_surfaces(|s, _| { + pending.surface.with_surfaces(|s, _| { if s == surface { found = true; } }); - found.then_some(output) + found.then_some(&pending.output) }) }) // override redirect window? @@ -1975,8 +1990,10 @@ impl Shell { .iter() .for_each(|or| or.refresh()); - self.pending_layers.retain(|(s, _, _)| s.alive()); - self.pending_windows.retain(|(s, _, _)| s.alive()); + self.pending_layers + .retain(|pending| pending.surface.alive()); + self.pending_windows + .retain(|pending| pending.surface.alive()); } pub fn update_pointer_position(&mut self, location: Point, output: &Output) { @@ -2067,9 +2084,14 @@ impl Shell { let pos = self .pending_windows .iter() - .position(|(w, _, _)| w == window) + .position(|pending| &pending.surface == window) .unwrap(); - let (window, seat, output) = self.pending_windows.remove(pos); + let PendingWindow { + surface: window, + seat, + fullscreen: output, + maximized: should_be_maximized, + } = self.pending_windows.remove(pos); let parent_is_sticky = if let Some(toplevel) = window.0.toplevel() { if let Some(parent) = toplevel.parent() { @@ -2155,7 +2177,7 @@ impl Shell { let maybe_focused = workspace.focus_stack.get(&seat).iter().next().cloned(); if let Some(focused) = maybe_focused { - if (focused.is_stack() && !is_dialog && !should_be_fullscreen) + if (focused.is_stack() && !is_dialog && !should_be_fullscreen && !should_be_maximized) && !(workspace.is_tiled(&focused) && floating_exception) { focused.stack_ref().unwrap().add_window(window, None); @@ -2205,6 +2227,10 @@ impl Shell { self.toggle_sticky(&seat, &mapped); } + if !should_be_fullscreen && should_be_maximized { + self.maximize_request(&mapped, &seat); + } + let new_target = if (workspace_output == seat.active_output() && active_handle == workspace_handle) || parent_is_sticky @@ -2246,12 +2272,12 @@ impl Shell { let pos = self .pending_layers .iter() - .position(|(l, _, _)| l == layer_surface) + .position(|pending| &pending.surface == layer_surface) .unwrap(); - let (layer_surface, output, _seat) = self.pending_layers.remove(pos); + let pending = self.pending_layers.remove(pos); let wants_focus = { - with_states(layer_surface.wl_surface(), |states| { + with_states(pending.surface.wl_surface(), |states| { let mut state = states.cached_state.get::(); matches!(state.current().layer, Layer::Top | Layer::Overlay) && state.current().keyboard_interactivity != KeyboardInteractivity::None @@ -2259,14 +2285,14 @@ impl Shell { }; { - let mut map = layer_map_for_output(&output); - map.map_layer(&layer_surface).unwrap(); + let mut map = layer_map_for_output(&pending.output); + map.map_layer(&pending.surface).unwrap(); } for workspace in self.workspaces.spaces_mut() { workspace.tiling_layer.recalculate(); } - wants_focus.then(|| layer_surface.into()) + wants_focus.then(|| pending.surface.into()) } pub fn unmap_surface( @@ -2323,7 +2349,12 @@ impl Shell { if let Some(surface) = surface { toplevel_info.remove_toplevel(&surface); - self.pending_windows.push((surface, seat.clone(), None)); + self.pending_windows.push(PendingWindow { + surface, + seat: seat.clone(), + fullscreen: None, + maximized: false, + }); return; } } diff --git a/src/wayland/handlers/compositor.rs b/src/wayland/handlers/compositor.rs index 008b46e0..607b5ac3 100644 --- a/src/wayland/handlers/compositor.rs +++ b/src/wayland/handlers/compositor.rs @@ -277,11 +277,11 @@ impl State { fn send_initial_configure_and_map(&mut self, surface: &WlSurface) -> bool { let mut shell = self.common.shell.write().unwrap(); - if let Some((window, _, _)) = shell + if let Some(window) = shell .pending_windows .iter() - .find(|(window, _, _)| window.wl_surface().as_deref() == Some(surface)) - .cloned() + .find(|pending| pending.surface.wl_surface().as_deref() == Some(surface)) + .map(|pending| pending.surface.clone()) { if let Some(toplevel) = window.0.toplevel() { if toplevel_ensure_initial_configure(&toplevel) @@ -305,11 +305,11 @@ impl State { } } - if let Some((layer_surface, _, _)) = shell + if let Some(layer_surface) = shell .pending_layers .iter() - .find(|(layer_surface, _, _)| layer_surface.wl_surface() == surface) - .cloned() + .find(|pending| pending.surface.wl_surface() == surface) + .map(|pending| pending.surface.clone()) { if !layer_surface_check_inital_configure(&layer_surface) { // compute initial dimensions by mapping diff --git a/src/wayland/handlers/layer_shell.rs b/src/wayland/handlers/layer_shell.rs index 876cbdb3..839e8ea5 100644 --- a/src/wayland/handlers/layer_shell.rs +++ b/src/wayland/handlers/layer_shell.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only -use crate::utils::prelude::*; +use crate::{shell::PendingLayer, utils::prelude::*}; use smithay::{ delegate_layer_shell, desktop::{layer_map_for_output, LayerSurface, PopupKind, WindowSurfaceType}, @@ -32,9 +32,11 @@ impl WlrLayerShellHandler for State { .as_ref() .and_then(Output::from_resource) .unwrap_or_else(|| seat.active_output()); - shell - .pending_layers - .push((LayerSurface::new(surface, namespace), output, seat)); + shell.pending_layers.push(PendingLayer { + surface: LayerSurface::new(surface, namespace), + output, + seat, + }); } fn new_popup(&mut self, _parent: WlrLayerSurface, popup: PopupSurface) { diff --git a/src/wayland/handlers/xdg_shell/mod.rs b/src/wayland/handlers/xdg_shell/mod.rs index 7f19913c..6d0c6050 100644 --- a/src/wayland/handlers/xdg_shell/mod.rs +++ b/src/wayland/handlers/xdg_shell/mod.rs @@ -1,7 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::{ - shell::{element::CosmicWindow, grabs::ReleaseMode, CosmicMapped, CosmicSurface, ManagedLayer}, + shell::{ + element::CosmicWindow, grabs::ReleaseMode, CosmicMapped, CosmicSurface, ManagedLayer, + PendingWindow, + }, utils::prelude::*, wayland::protocols::toplevel_info::{toplevel_enter_output, toplevel_enter_workspace}, }; @@ -45,7 +48,12 @@ impl XdgShellHandler for State { let mut shell = self.common.shell.write().unwrap(); let seat = shell.seats.last_active().clone(); let window = CosmicSurface::from(surface); - shell.pending_windows.push((window, seat, None)); + shell.pending_windows.push(PendingWindow { + surface: window, + seat, + fullscreen: None, + maximized: false, + }); // We will position the window after the first commit, when we know its size hints } @@ -219,6 +227,12 @@ impl XdgShellHandler for State { if let Some(mapped) = shell.element_for_surface(surface.wl_surface()).cloned() { let seat = shell.seats.last_active().clone(); shell.maximize_request(&mapped, &seat) + } else if let Some(pending) = shell + .pending_windows + .iter_mut() + .find(|pending| pending.surface.wl_surface().as_deref() == Some(surface.wl_surface())) + { + pending.maximized = true; } } @@ -226,6 +240,12 @@ impl XdgShellHandler for State { let mut shell = self.common.shell.write().unwrap(); if let Some(mapped) = shell.element_for_surface(surface.wl_surface()).cloned() { shell.unmaximize_request(&mapped); + } else if let Some(pending) = shell + .pending_windows + .iter_mut() + .find(|pending| pending.surface.wl_surface().as_deref() == Some(surface.wl_surface())) + { + pending.maximized = false; } } @@ -339,15 +359,12 @@ impl XdgShellHandler for State { workspace.fullscreen_request(&window, None, from, &seat) } } - } else { - if let Some(o) = shell - .pending_windows - .iter_mut() - .find(|(s, _, _)| s.wl_surface().as_deref() == Some(surface.wl_surface())) - .map(|(_, _, o)| o) - { - *o = Some(output); - } + } else if let Some(pending) = shell + .pending_windows + .iter_mut() + .find(|pending| pending.surface.wl_surface().as_deref() == Some(surface.wl_surface())) + { + pending.fullscreen = Some(output); } } @@ -376,6 +393,12 @@ impl XdgShellHandler for State { ); } } + } else if let Some(pending) = shell + .pending_windows + .iter_mut() + .find(|pending| pending.surface.wl_surface().as_deref() == Some(surface.wl_surface())) + { + pending.fullscreen.take(); } } diff --git a/src/xwayland.rs b/src/xwayland.rs index 3847f7b6..2af93b31 100644 --- a/src/xwayland.rs +++ b/src/xwayland.rs @@ -2,7 +2,9 @@ use std::{ffi::OsString, os::unix::io::OwnedFd, process::Stdio}; use crate::{ backend::render::cursor::{load_cursor_theme, Cursor}, - shell::{focus::target::KeyboardFocusTarget, grabs::ReleaseMode, CosmicSurface, Shell}, + shell::{ + focus::target::KeyboardFocusTarget, grabs::ReleaseMode, CosmicSurface, PendingWindow, Shell, + }, state::State, utils::prelude::*, wayland::handlers::{ @@ -349,16 +351,21 @@ impl XwmHandler for State { } let surface = CosmicSurface::from(window); - shell.pending_windows.push((surface, seat, None)); + shell.pending_windows.push(PendingWindow { + surface, + seat, + fullscreen: None, + maximized: false, + }); } fn map_window_notify(&mut self, _xwm: XwmId, surface: X11Surface) { let mut shell = self.common.shell.write().unwrap(); - if let Some((window, _, _)) = shell + if let Some(window) = shell .pending_windows .iter() - .find(|(window, _, _)| window.x11_surface() == Some(&surface)) - .cloned() + .find(|pending| pending.surface.x11_surface() == Some(&surface)) + .map(|pending| pending.surface.clone()) { if !shell .pending_activations @@ -606,6 +613,12 @@ impl XwmHandler for State { if let Some(mapped) = shell.element_for_surface(&window).cloned() { let seat = shell.seats.last_active().clone(); shell.maximize_request(&mapped, &seat); + } else if let Some(pending) = shell + .pending_windows + .iter_mut() + .find(|pending| pending.surface.x11_surface() == Some(&window)) + { + pending.maximized = true; } } @@ -613,6 +626,12 @@ impl XwmHandler for State { let mut shell = self.common.shell.write().unwrap(); if let Some(mapped) = shell.element_for_surface(&window).cloned() { shell.unmaximize_request(&mapped); + } else if let Some(pending) = shell + .pending_windows + .iter_mut() + .find(|pending| pending.surface.x11_surface() == Some(&window)) + { + pending.maximized = false; } } @@ -659,16 +678,13 @@ impl XwmHandler for State { .fullscreen_request(&surface, None, from, &seat); } } - } else { + } else if let Some(pending) = shell + .pending_windows + .iter_mut() + .find(|pending| pending.surface.x11_surface() == Some(&window)) + { let output = seat.active_output(); - if let Some(o) = shell - .pending_windows - .iter_mut() - .find(|(s, _, _)| s.x11_surface() == Some(&window)) - .map(|(_, _, o)| o) - { - *o = Some(output); - } + pending.fullscreen = Some(output); } } @@ -683,6 +699,12 @@ impl XwmHandler for State { let previous = workspace.unfullscreen_request(&window); assert!(previous.is_none()); } + } else if let Some(pending) = shell + .pending_windows + .iter_mut() + .find(|pending| pending.surface.x11_surface() == Some(&window)) + { + pending.fullscreen.take(); } }