Restore floating window size before the first buffer

This commit is contained in:
Samuel Onoja committed 2026-10-01 11:36:53 +01:00
1 parent a14f222119
commit 53bad8c672
5 files changed
+162 -11

No files matched your search

+6
View File
@@ -77,6 +77,12 @@ impl CompositorHandler for Ferese {
self.space.map_element(window.clone(), (0, 0), false);
self.restore_keyboard_focus();
}
if window
.toplevel()
.is_some_and(|toplevel| !xdg_shell::initial_configure_sent(toplevel))
{
self.restore_initial_floating_size(&window);
}
}
self.record_client_commit(&window);
}
+22 -6
View File
@@ -285,11 +285,13 @@ impl XdgDecorationHandler for Ferese {
let mode = self.decoration_mode_for(&toplevel);
toplevel.with_pending_state(|state| state.decoration_mode = Some(mode));
// This must be unconditional: the initial xdg-toplevel configure may
// already contain the same mode before the decoration object exists.
// `send_pending_configure` would then see no state change and omit the
// decoration configure, leaving clients to fall back to CSD.
toplevel.send_configure();
// Wait for the initial surface commit so app-id and saved floating
// size can be included in the first configure. If already configured,
// send unconditionally: the existing toplevel state may have the same
// mode, but the new decoration object still needs its configure event.
if initial_configure_sent(&toplevel) {
toplevel.send_configure();
}
}
fn request_mode(&mut self, toplevel: ToplevelSurface, _mode: Mode) {
@@ -319,7 +321,21 @@ impl Ferese {
fn set_decoration_mode(toplevel: &ToplevelSurface, mode: Mode) {
toplevel.with_pending_state(|state| state.decoration_mode = Some(mode));
toplevel.send_pending_configure();
if initial_configure_sent(toplevel) {
toplevel.send_pending_configure();
}
}
pub(crate) fn initial_configure_sent(toplevel: &ToplevelSurface) -> bool {
with_states(toplevel.wl_surface(), |states| {
states
.data_map
.get::<XdgToplevelSurfaceData>()
.unwrap()
.lock()
.unwrap()
.initial_configure_sent
})
}
pub fn handle_commit(popups: &mut PopupManager, space: &mut Space<Window>, surface: &WlSurface) {
+48
View File
@@ -1257,6 +1257,54 @@ impl Ferese {
.is_some_and(|geometry| geometry.client.committed_size.is_some())
}
pub(crate) fn restore_initial_floating_size(&mut self, window: &Window) {
let Some(toplevel) = window.toplevel() else { return };
let (app_id, title, transient) = with_states(toplevel.wl_surface(), |states| {
let attributes = states.data_map.get::<XdgToplevelSurfaceData>().unwrap().lock().unwrap();
(
attributes.app_id.clone(),
attributes.title.clone(),
attributes.parent.is_some(),
)
});
let special_mode = toplevel.with_pending_state(|pending| {
pending.states.contains(xdg_toplevel::State::Fullscreen)
|| pending.states.contains(xdg_toplevel::State::Maximized)
});
let rule = resolve_window_rules(&self.window_rules, app_id.as_deref(), title.as_deref(), transient);
if transient
|| special_mode
|| rule.fullscreen == Some(true)
|| !rule.floating.unwrap_or(rule.width.is_some() || rule.height.is_some())
{
return;
}
let outputs = self.floating_outputs();
let Some((remembered, work)) = app_id
.as_deref()
.and_then(|app| self.floating_memory.get(app))
.and_then(|entry| {
let rect = entry.restore(&outputs)?;
let work = outputs.iter().find(|(name, _)| *name == entry.output)?.1;
Some((rect, work))
})
else {
return;
};
// Metadata is available on the initial bufferless commit. Restore the
// size before the client creates its first buffer, without mapping or
// focusing the window. Use the same rule/constraint precedence as map.
let rect = self.place_floating(
window,
None,
work,
(remembered.width, remembered.height),
Some((rule.width, rule.height)),
);
let size = ClientSize::from_rect(rect);
toplevel.with_pending_state(|pending| pending.size = Some((size.width, size.height).into()));
}
pub(crate) fn add_rule_placed_window(
&mut self,
window: Window,