Commit 621fc9d239f8
tarball4 files changed+62-3
@@ -359,6 +359,7 @@ impl State {
359359
let mut mapped = Vec::new();360360
for (id, rect, kind, _) in shown {361361
if let Some(window) = self.wm.window(id).cloned()362
+ && !self.wm.get(id).is_some_and(|s| s.natural_size)362363
&& configure(&window, rect, kind, self.wm.layout.maximized(id))363364
{364365
let loc = (rect.x.round() as i32, rect.y.round() as i32);@@ -50,8 +50,13 @@ impl State {
5050
f64::from(r.size.h),5151
)5252
});53
- let id = self.wm.layout.add_window(output, tag, float);54
- if rule.floating == Some(true) {53
+ let auto = float.is_some() || window.toplevel().is_some_and(crate::xdg::floats);54
+ let floating = rule.floating.unwrap_or(auto);55
+ let id = self56
+ .wm57
+ .layout58
+ .add_window(output, tag, float.filter(|_| floating));59
+ if floating != self.wm.layout.window(id).is_some_and(|w| w.floating) {5560
self.wm.layout.toggle_floating(id);5661
}5762
if rule.sticky == Some(true) {@@ -62,7 +67,11 @@ impl State {
6267
}6368
self.view_if_first(id);6469
let by_rule = rule.tag.is_some() || rule.output.is_some();70
+ let natural_size = floating && window.toplevel().is_some();6571
self.wm.insert(id, window, by_rule, app_id, title);72
+ if let Some(s) = self.wm.get_mut(id) {73
+ s.natural_size = natural_size;74
+ }6675
self.await_first_buffer(id);6776
if self.wm.layout.visible(id) {6877
self.wm.layout.focus(id);@@ -98,12 +107,44 @@ impl State {
98107
return;99108
};100109
w.placed_by_rule = false;110
+ if std::mem::take(&mut w.natural_size) {111
+ let size = w.window.geometry().size;112
+ if size.w > 0 && size.h > 0 {113
+ self.float_at_natural_size(id, f64::from(size.w), f64::from(size.h));114
+ }115
+ }116
+ let Some(w) = self.wm.get_mut(id) else {117
+ return;118
+ };101119
if std::mem::take(&mut w.awaiting_buffer) {102120
self.wm.anim.spawned(id, now_ns());103121
self.apply_layout();104122
}105123
}106124
125
+ /// Centres a window over its parent, or else its output.126
+ fn float_at_natural_size(&mut self, id: WindowId, w: f64, h: f64) {127
+ let parent = self128
+ .wm129
+ .window(id)130
+ .and_then(|win| win.toplevel()?.parent())131
+ .and_then(|p| self.window_id(&p))132
+ .and_then(|p| self.wm.get(p)?.placed)133
+ .map(|(_, r, _)| r);134
+ let output = self135
+ .wm136
+ .layout137
+ .window(id)138
+ .and_then(|win| win.output)139
+ .and_then(|o| self.wm.layout.output(o))140
+ .map(|o| o.area);141
+ if let Some(around) = parent.or(output) {142
+ let x = around.x + (around.w - w) / 2.0;143
+ let y = around.y + (around.h - h) / 2.0;144
+ self.wm.layout.set_float_rect(id, Rect::new(x, y, w, h));145
+ }146
+ }147
+107148
pub fn unmap_window(&mut self, surface: &WlSurface) {108149
self.wm109150
.unmapped@@ -55,6 +55,9 @@ pub struct WindowState {
5555
pub placed: Option<(Kind, Rect, OutputId)>,5656
/// Held on its seed until its first buffer lands.5757
pub awaiting_buffer: bool,58
+ /// Configured without a size until its first buffer shows the one it59
+ /// picked.60
+ pub natural_size: bool,5861
/// A rule sent it somewhere, so activation tokens leave it alone.5962
pub placed_by_rule: bool,6063
pub list_handle: Option<ForeignToplevelHandle>,@@ -110,6 +113,7 @@ impl Wm {
110113
window,111114
placed: None,112115
awaiting_buffer: true,116
+ natural_size: false,113117
placed_by_rule,114118
list_handle: None,115119
borders: None,@@ -6,10 +6,23 @@ use smithay::reexports::wayland_server::protocol::wl_seat::WlSeat;
66
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;77
use smithay::utils::Serial;88
use smithay::wayland::shell::xdg::decoration::XdgDecorationHandler;9
+use smithay::wayland::compositor::with_states;910
use smithay::wayland::shell::xdg::{10
- PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState,11
+ PopupSurface, PositionerState, SurfaceCachedState, ToplevelSurface, XdgShellHandler,12
+ XdgShellState,1113
};1214
15
+/// Dialogs, and windows that cap their size and so could never fill a tile.16
+pub fn floats(toplevel: &ToplevelSurface) -> bool {17
+ let max = with_states(toplevel.wl_surface(), |s| {18
+ s.cached_state19
+ .get::<SurfaceCachedState>()20
+ .current()21
+ .max_size22
+ });23
+ toplevel.parent().is_some() || (max.w > 0 && max.h > 0)24
+}25
+1326
impl XdgShellHandler for State {1427
fn xdg_shell_state(&mut self) -> &mut XdgShellState {1528
&mut self.protocols.xdg_shell_state