mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-21 02:01:55 +07:00
floating: Don't use fullscreen size as floating size
This commit is contained in:
@@ -375,8 +375,9 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
floating_size.unwrap_or_default()
|
||||
} else {
|
||||
// If the window wasn't fullscreen without a floating size (e.g. it was tiled before),
|
||||
// ask for the current size.
|
||||
floating_size.unwrap_or_else(|| win.expected_size())
|
||||
// ask for the current size. If the current size is unknown (the window was only ever
|
||||
// fullscreen until now), fall back to (0, 0).
|
||||
floating_size.unwrap_or_else(|| win.expected_size().unwrap_or_default())
|
||||
};
|
||||
// Make sure fixed-size through window rules keeps working.
|
||||
let min_size = win.min_size();
|
||||
@@ -482,8 +483,10 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
}
|
||||
}
|
||||
|
||||
// Store the floating size.
|
||||
tile.set_floating_window_size(tile.window().expected_size());
|
||||
// Store the floating size if we have one.
|
||||
if let Some(size) = tile.window().expected_size() {
|
||||
tile.set_floating_window_size(size);
|
||||
}
|
||||
|
||||
let width = ColumnWidth::Fixed(tile.window_size().w);
|
||||
RemovedTile {
|
||||
@@ -600,7 +603,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
win_width = ensure_min_max_size(win_width, min_size.w, max_size.w);
|
||||
win_width = max(1, win_width);
|
||||
|
||||
let win_height = win.expected_size().h;
|
||||
let win_height = win.expected_size().unwrap_or_default().h;
|
||||
let win_height = ensure_min_max_size(win_height, min_size.h, max_size.h);
|
||||
|
||||
let win_size = Size::from((win_width, win_height));
|
||||
@@ -626,7 +629,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
win_height = ensure_min_max_size(win_height, min_size.h, max_size.h);
|
||||
win_height = max(1, win_height);
|
||||
|
||||
let win_width = win.expected_size().w;
|
||||
let win_width = win.expected_size().unwrap_or_default().w;
|
||||
let win_width = ensure_min_max_size(win_width, min_size.w, max_size.w);
|
||||
|
||||
let win_size = Size::from((win_width, win_height));
|
||||
|
||||
+14
-6
@@ -197,7 +197,7 @@ pub trait LayoutElement {
|
||||
/// Size previously requested through [`LayoutElement::request_size()`].
|
||||
fn requested_size(&self) -> Option<Size<i32, Logical>>;
|
||||
|
||||
/// Size that we expect this window has or will shortly have.
|
||||
/// Non-fullscreen size that we expect this window has or will shortly have.
|
||||
///
|
||||
/// This can be different from [`requested_size()`](LayoutElement::requested_size()). For
|
||||
/// example, for floating windows this will generally return the current window size, rather
|
||||
@@ -205,10 +205,15 @@ pub trait LayoutElement {
|
||||
/// size freely. But not always: if we just requested a floating window to resize and it hasn't
|
||||
/// responded to it yet, this will return the newly requested size.
|
||||
///
|
||||
/// This function should never return a 0 size component.
|
||||
/// This function should never return a 0 size component. `None` means there's no known
|
||||
/// expected size (for example, the window is fullscreen).
|
||||
///
|
||||
/// The default impl is for testing only, it will not preserve the window's own size changes.
|
||||
fn expected_size(&self) -> Size<i32, Logical> {
|
||||
fn expected_size(&self) -> Option<Size<i32, Logical>> {
|
||||
if self.is_fullscreen() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut requested = self.requested_size().unwrap_or_default();
|
||||
let current = self.size();
|
||||
if requested.w == 0 {
|
||||
@@ -217,7 +222,7 @@ pub trait LayoutElement {
|
||||
if requested.h == 0 {
|
||||
requested.h = current.h;
|
||||
}
|
||||
requested
|
||||
Some(requested)
|
||||
}
|
||||
|
||||
fn is_child_of(&self, parent: &Self) -> bool;
|
||||
@@ -2722,7 +2727,8 @@ impl<W: LayoutElement> Layout<W> {
|
||||
if move_.is_floating {
|
||||
let floating_size = move_.tile.floating_window_size();
|
||||
let win = move_.tile.window_mut();
|
||||
let mut size = floating_size.unwrap_or_else(|| win.expected_size());
|
||||
let mut size =
|
||||
floating_size.unwrap_or_else(|| win.expected_size().unwrap_or_default());
|
||||
// Make sure fixed-size through window rules keeps working.
|
||||
let min_size = win.min_size();
|
||||
let max_size = win.max_size();
|
||||
@@ -3479,7 +3485,9 @@ impl<W: LayoutElement> Layout<W> {
|
||||
// Set the floating size so it takes into account any window resizing that
|
||||
// took place during the move.
|
||||
let mut tile = move_.tile;
|
||||
tile.set_floating_window_size(tile.window().expected_size());
|
||||
if let Some(size) = tile.window().expected_size() {
|
||||
tile.set_floating_window_size(size);
|
||||
}
|
||||
|
||||
mon.add_floating_tile(ws_idx, tile, Some(pos), true);
|
||||
}
|
||||
|
||||
@@ -725,3 +725,63 @@ fn interactive_move_restores_floating_size_when_set_to_floating() {
|
||||
@""
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn floating_doesnt_store_fullscreen_size() {
|
||||
let mut f = Fixture::new();
|
||||
f.add_output(1, (1920, 1080));
|
||||
f.add_output(2, (1280, 720));
|
||||
|
||||
// Open a window fullscreen.
|
||||
let id = f.add_client();
|
||||
let window = f.client(id).create_window();
|
||||
let surface = window.surface.clone();
|
||||
window.set_fullscreen(None);
|
||||
window.commit();
|
||||
f.roundtrip(id);
|
||||
|
||||
let window = f.client(id).window(&surface);
|
||||
window.attach_new_buffer();
|
||||
window.set_size(1920, 1080);
|
||||
window.ack_last_and_commit();
|
||||
f.double_roundtrip(id);
|
||||
|
||||
let _ = f.client(id).window(&surface).recent_configures();
|
||||
|
||||
// Make it floating.
|
||||
f.niri().layout.toggle_window_floating(None);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// This should request 0 × 0 to unfullscreen.
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 0 × 0, bounds: 1920 × 1080, states: [Activated]"
|
||||
);
|
||||
|
||||
// Without committing, make it tiling again. We never committed while floating, so there's no
|
||||
// floating size to remember.
|
||||
f.niri().layout.toggle_window_floating(None);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// This should request the tiled size.
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 1920 × 1048, bounds: 1888 × 1048, states: [Activated]"
|
||||
);
|
||||
|
||||
// Commit in response.
|
||||
let window = f.client(id).window(&surface);
|
||||
window.set_size(100, 100);
|
||||
window.ack_last_and_commit();
|
||||
f.roundtrip(id);
|
||||
|
||||
// Make the window floating again.
|
||||
f.niri().layout.toggle_window_floating(None);
|
||||
f.double_roundtrip(id);
|
||||
|
||||
// This shouldn't request any size change, particularly not the fullscreen size.
|
||||
assert_snapshot!(
|
||||
f.client(id).window(&surface).format_recent_configures(),
|
||||
@"size: 100 × 100, bounds: 1920 × 1080, states: [Activated]"
|
||||
);
|
||||
}
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1280 × 720, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1280 × 720, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1280 × 720, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1280 × 720, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1280 × 720, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1280 × 720, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1280 × 720, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1248 × 688, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1280 × 720, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ size: 1280 × 720, bounds: 1280 × 720, states: [Fullscreen]
|
||||
|
||||
post-map configures:
|
||||
size: 0 × 0, bounds: 1280 × 720, states: []
|
||||
size: 1 × 1, bounds: 1280 × 720, states: [Activated]
|
||||
size: 0 × 0, bounds: 1280 × 720, states: [Activated]
|
||||
|
||||
+33
-14
@@ -829,8 +829,9 @@ impl LayoutElement for Mapped {
|
||||
self.toplevel().with_pending_state(|state| state.size)
|
||||
}
|
||||
|
||||
fn expected_size(&self) -> Size<i32, Logical> {
|
||||
let current_size = self.window.geometry().size;
|
||||
fn expected_size(&self) -> Option<Size<i32, Logical>> {
|
||||
// We can only use current size if it's not fullscreen.
|
||||
let current_size = (!self.is_fullscreen()).then(|| self.window.geometry().size);
|
||||
|
||||
// Check if we should be using the current window size.
|
||||
//
|
||||
@@ -849,12 +850,17 @@ impl LayoutElement for Mapped {
|
||||
return current_size;
|
||||
}
|
||||
|
||||
let pending_size = with_toplevel_role(self.toplevel(), |role| {
|
||||
let pending = with_toplevel_role(self.toplevel(), |role| {
|
||||
// If we have a server-pending size change that we haven't sent yet, use that size.
|
||||
if let Some(server_pending) = &role.server_pending {
|
||||
let current_server = role.current_server_state();
|
||||
if server_pending.size != current_server.size {
|
||||
return Some(server_pending.size.unwrap_or_default());
|
||||
return Some((
|
||||
server_pending.size.unwrap_or_default(),
|
||||
server_pending
|
||||
.states
|
||||
.contains(xdg_toplevel::State::Fullscreen),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -871,23 +877,36 @@ impl LayoutElement for Mapped {
|
||||
|
||||
if let Some(current_serial) = role.current_serial {
|
||||
if !current_serial.is_no_older_than(&last_serial) {
|
||||
return Some(last_sent.size.unwrap_or_default());
|
||||
return Some((
|
||||
last_sent.size.unwrap_or_default(),
|
||||
last_sent.states.contains(xdg_toplevel::State::Fullscreen),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
});
|
||||
|
||||
// If we have no pending size change (size change that the window hasn't committed to), or
|
||||
// if some component of the pending size change is zero, use the current window size.
|
||||
let mut size = pending_size.unwrap_or_default();
|
||||
if size.w == 0 {
|
||||
size.w = current_size.w;
|
||||
if let Some((mut size, fullscreen)) = pending {
|
||||
// If the pending change is fullscreen, we can't use that size.
|
||||
if fullscreen {
|
||||
return None;
|
||||
}
|
||||
|
||||
// If some component of the pending size is zero, substitute it with the current window
|
||||
// size. But only if the current size is not fullscreen.
|
||||
if size.w == 0 {
|
||||
size.w = current_size?.w;
|
||||
}
|
||||
if size.h == 0 {
|
||||
size.h = current_size?.h;
|
||||
}
|
||||
|
||||
Some(size)
|
||||
} else {
|
||||
// No pending size, return the current size if it's non-fullscreen.
|
||||
current_size
|
||||
}
|
||||
if size.h == 0 {
|
||||
size.h = current_size.h;
|
||||
}
|
||||
size
|
||||
}
|
||||
|
||||
fn is_child_of(&self, parent: &Self) -> bool {
|
||||
|
||||
Reference in New Issue
Block a user