Commit 668fd294147a
tarball2 files changed+70-13
@@ -7,7 +7,9 @@ use smithay::backend::renderer::Renderer;
77
use smithay::backend::renderer::utils::{import_surface_tree, with_renderer_surface_state};88
use smithay::desktop::Window;99
use smithay::reexports::calloop::timer::{TimeoutAction, Timer};10
+use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::State as XdgState;1011
use smithay::reexports::wayland_server::Resource;12
+use smithay::reexports::wayland_server::protocol::wl_output::WlOutput;1113
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;1214
use smithay::utils::{Logical, Point, Rectangle, Serial};1315
use smithay::wayland::compositor::with_states;@@ -29,6 +31,7 @@ impl State {
2931
.map(|c| c.pid as u32),3032
};3133
let launch = pid.and_then(|pid| self.services.launches.find(pid));34
+ let (fullscreen, fullscreen_output) = requested_fullscreen(&window);3235
let output = rule3336
.output3437
.as_deref()@@ -39,6 +42,7 @@ impl State {
3942
.find(|(_, o)| o.name == name)4043
.map(|(id, _)| id)4144
})45
+ .or(fullscreen_output.and_then(|o| self.layout_output(&o)))4246
.or(launch.and_then(|l| l.0));4347
let tag = match rule.tag.as_deref() {4448
Some(t) => Some(self.wm.layout.tag(t)),@@ -61,6 +65,9 @@ impl State {
6165
if floating != self.wm.layout.window(id).is_some_and(|w| w.floating) {6266
self.wm.layout.toggle_floating(id);6367
}68
+ if fullscreen {69
+ self.wm.layout.toggle_fullscreen(id);70
+ }6471
if rule.sticky == Some(true) {6572
self.wm.layout.toggle_sticky(id);6673
}@@ -69,7 +76,7 @@ impl State {
6976
}7077
self.view_if_first(id);7178
let by_rule = rule.tag.is_some() || rule.output.is_some();72
- let natural_size = floating && window.toplevel().is_some();79
+ let natural_size = floating && !fullscreen && window.toplevel().is_some();7380
let reclassify = !floating && rule.floating.is_none() && window.toplevel().is_some();7481
self.wm.insert(id, window, by_rule, app_id, title);7582
if let Some(s) = self.wm.get_mut(id) {@@ -432,3 +439,19 @@ fn acked(window: &Window, serial: Serial) -> bool {
432439
})433440
.unwrap_or(false)434441
}442
+443
+/// What a window asked for before it mapped. X11 windows carry it in their444
+/// state, xdg toplevels in the pending state `set_fullscreen` left.445
+fn requested_fullscreen(window: &Window) -> (bool, Option<WlOutput>) {446
+ if let Some(x) = window.x11_surface() {447
+ return (x.is_fullscreen(), None);448
+ }449
+ window.toplevel().map_or((false, None), |t| {450
+ t.with_pending_state(|s| {451
+ (452
+ s.states.contains(XdgState::Fullscreen),453
+ s.fullscreen_output.clone(),454
+ )455
+ })456
+ })457
+}@@ -1,9 +1,10 @@
11
use crate::state::State;2
+use monolith_layout::OutputId;23
use smithay::desktop::{PopupKind, Window};34
use smithay::reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode as DecorationMode;5
+use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::State as XdgState;46
use smithay::reexports::wayland_server::protocol::wl_output::WlOutput;57
use smithay::reexports::wayland_server::protocol::wl_seat::WlSeat;6
-use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;78
use smithay::utils::{Logical, Serial, Size};89
use smithay::wayland::shell::xdg::decoration::XdgDecorationHandler;910
use smithay::wayland::compositor::with_states;@@ -45,12 +46,12 @@ impl XdgShellHandler for State {
4546
self.unmap_window(surface.wl_surface());4647
}4748
48
- fn fullscreen_request(&mut self, surface: ToplevelSurface, _output: Option<WlOutput>) {49
- self.set_fullscreen(surface.wl_surface(), true);49
+ fn fullscreen_request(&mut self, surface: ToplevelSurface, output: Option<WlOutput>) {50
+ self.set_fullscreen(&surface, true, output);5051
}5152
5253
fn unfullscreen_request(&mut self, surface: ToplevelSurface) {53
- self.set_fullscreen(surface.wl_surface(), false);54
+ self.set_fullscreen(&surface, false, None);5455
}5556
5657
fn new_popup(&mut self, surface: PopupSurface, positioner: PositionerState) {@@ -97,16 +98,49 @@ fn server_side(toplevel: &ToplevelSurface) {
9798
}9899
99100
impl State {100
- fn set_fullscreen(&mut self, surface: &WlSurface, on: bool) {101
- if let Some(id) = self.window_id(surface)102
- && self103
- .wm104
- .layout105
- .window(id)106
- .is_some_and(|w| w.fullscreen != on)107
- {101
+ /// A toplevel that has not mapped has no window to change, so its wish is102
+ /// kept in its pending state for `map_window` to find.103
+ fn set_fullscreen(&mut self, toplevel: &ToplevelSurface, on: bool, output: Option<WlOutput>) {104
+ let Some(id) = self.window_id(toplevel.wl_surface()) else {105
+ toplevel.with_pending_state(|s| {106
+ if on {107
+ s.states.set(XdgState::Fullscreen);108
+ } else {109
+ s.states.unset(XdgState::Fullscreen);110
+ }111
+ s.fullscreen_output = output.filter(|_| on);112
+ });113
+ return;114
+ };115
+ let target = output116
+ .as_ref()117
+ .and_then(|o| self.layout_output(o))118
+ .filter(|&o| {119
+ self.wm120
+ .layout121
+ .window(id)122
+ .is_some_and(|w| w.output != Some(o))123
+ });124
+ if let Some(o) = target {125
+ self.wm.layout.send_to_output(id, o);126
+ }127
+ let toggled = self128
+ .wm129
+ .layout130
+ .window(id)131
+ .is_some_and(|w| w.fullscreen != on);132
+ if toggled {108133
self.wm.layout.toggle_fullscreen(id);134
+ }135
+ if target.is_some() || toggled {109136
self.apply_layout();110137
}111138
}139
+140
+ /// The layout output a client's `wl_output` names.141
+ pub fn layout_output(&self, output: &WlOutput) -> Option<OutputId> {142
+ let ids = self.wm.layout.outputs().map(|(id, _)| id);143
+ ids.into_iter()144
+ .find(|&id| self.backend.output(id).is_some_and(|o| o.owns(output)))145
+ }112146
}