mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-21 02:01:55 +07:00
Restore view offset upon unfullscreening
This commit is contained in:
@@ -3037,6 +3037,107 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unfullscreen_view_offset_not_reset_on_removal() {
|
||||
let ops = [
|
||||
Op::AddOutput(1),
|
||||
Op::AddWindow {
|
||||
id: 0,
|
||||
bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)),
|
||||
min_max_size: Default::default(),
|
||||
},
|
||||
Op::FullscreenWindow(0),
|
||||
Op::AddWindow {
|
||||
id: 1,
|
||||
bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)),
|
||||
min_max_size: Default::default(),
|
||||
},
|
||||
Op::ConsumeOrExpelWindowRight,
|
||||
];
|
||||
|
||||
check_ops(&ops);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unfullscreen_view_offset_not_reset_on_consume() {
|
||||
let ops = [
|
||||
Op::AddOutput(1),
|
||||
Op::AddWindow {
|
||||
id: 0,
|
||||
bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)),
|
||||
min_max_size: Default::default(),
|
||||
},
|
||||
Op::FullscreenWindow(0),
|
||||
Op::AddWindow {
|
||||
id: 1,
|
||||
bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)),
|
||||
min_max_size: Default::default(),
|
||||
},
|
||||
Op::ConsumeWindowIntoColumn,
|
||||
];
|
||||
|
||||
check_ops(&ops);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unfullscreen_view_offset_not_reset_on_quick_double_toggle() {
|
||||
let ops = [
|
||||
Op::AddOutput(1),
|
||||
Op::AddWindow {
|
||||
id: 0,
|
||||
bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)),
|
||||
min_max_size: Default::default(),
|
||||
},
|
||||
Op::FullscreenWindow(0),
|
||||
Op::FullscreenWindow(0),
|
||||
];
|
||||
|
||||
check_ops(&ops);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unfullscreen_view_offset_set_on_fullscreening_inactive_tile_in_column() {
|
||||
let ops = [
|
||||
Op::AddOutput(1),
|
||||
Op::AddWindow {
|
||||
id: 0,
|
||||
bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)),
|
||||
min_max_size: Default::default(),
|
||||
},
|
||||
Op::AddWindow {
|
||||
id: 1,
|
||||
bbox: Rectangle::from_loc_and_size((0, 0), (100, 200)),
|
||||
min_max_size: Default::default(),
|
||||
},
|
||||
Op::ConsumeOrExpelWindowLeft,
|
||||
Op::FullscreenWindow(0),
|
||||
];
|
||||
|
||||
check_ops(&ops);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unfullscreen_view_offset_not_reset_on_gesture() {
|
||||
let ops = [
|
||||
Op::AddOutput(1),
|
||||
Op::AddWindow {
|
||||
id: 0,
|
||||
bbox: Rectangle::from_loc_and_size((0, 0), (200, 200)),
|
||||
min_max_size: Default::default(),
|
||||
},
|
||||
Op::AddWindow {
|
||||
id: 1,
|
||||
bbox: Rectangle::from_loc_and_size((0, 0), (1280, 200)),
|
||||
min_max_size: Default::default(),
|
||||
},
|
||||
Op::FullscreenWindow(1),
|
||||
Op::ViewOffsetGestureBegin { output_idx: 1 },
|
||||
Op::ViewOffsetGestureEnd,
|
||||
];
|
||||
|
||||
check_ops(&ops);
|
||||
}
|
||||
|
||||
fn arbitrary_spacing() -> impl Strategy<Value = u16> {
|
||||
// Give equal weight to:
|
||||
// - 0: the element is disabled
|
||||
|
||||
@@ -269,6 +269,10 @@ impl<W: LayoutElement> Tile<W> {
|
||||
self.window
|
||||
}
|
||||
|
||||
pub fn is_fullscreen(&self) -> bool {
|
||||
self.is_fullscreen
|
||||
}
|
||||
|
||||
/// Returns `None` if the border is hidden and `Some(width)` if it should be shown.
|
||||
fn effective_border_width(&self) -> Option<i32> {
|
||||
if self.is_fullscreen {
|
||||
|
||||
+72
-1
@@ -78,6 +78,9 @@ pub struct Workspace<W: LayoutElement> {
|
||||
/// The value is the view offset that the previous column had before, to restore it.
|
||||
activate_prev_column_on_removal: Option<i32>,
|
||||
|
||||
/// View offset to restore after unfullscreening.
|
||||
view_offset_before_fullscreen: Option<i32>,
|
||||
|
||||
/// Windows in the closing animation.
|
||||
closing_windows: Vec<ClosingWindow>,
|
||||
|
||||
@@ -252,6 +255,7 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
view_offset: 0,
|
||||
view_offset_adj: None,
|
||||
activate_prev_column_on_removal: None,
|
||||
view_offset_before_fullscreen: None,
|
||||
closing_windows: vec![],
|
||||
options,
|
||||
id: WorkspaceId::next(),
|
||||
@@ -269,6 +273,7 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
view_offset: 0,
|
||||
view_offset_adj: None,
|
||||
activate_prev_column_on_removal: None,
|
||||
view_offset_before_fullscreen: None,
|
||||
closing_windows: vec![],
|
||||
options,
|
||||
id: WorkspaceId::next(),
|
||||
@@ -604,6 +609,7 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
|
||||
// A different column was activated; reset the flag.
|
||||
self.activate_prev_column_on_removal = None;
|
||||
self.view_offset_before_fullscreen = None;
|
||||
}
|
||||
|
||||
pub fn has_windows(&self) -> bool {
|
||||
@@ -785,6 +791,10 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
self.activate_prev_column_on_removal = None;
|
||||
}
|
||||
|
||||
if column_idx == self.active_column_idx {
|
||||
self.view_offset_before_fullscreen = None;
|
||||
}
|
||||
|
||||
self.columns.remove(column_idx);
|
||||
if self.columns.is_empty() {
|
||||
return window;
|
||||
@@ -838,6 +848,10 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
self.activate_prev_column_on_removal = None;
|
||||
}
|
||||
|
||||
if column_idx == self.active_column_idx {
|
||||
self.view_offset_before_fullscreen = None;
|
||||
}
|
||||
|
||||
if self.columns.is_empty() {
|
||||
return column;
|
||||
}
|
||||
@@ -899,6 +913,8 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
.take()
|
||||
.map_or(0, |prev| prev - column.width());
|
||||
|
||||
let was_fullscreen = column.tiles[tile_idx].is_fullscreen();
|
||||
|
||||
column.update_window(window);
|
||||
column.update_tile_sizes(false);
|
||||
|
||||
@@ -930,6 +946,14 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
// We might need to move the view to ensure the resized window is still visible.
|
||||
let current_x = self.view_pos();
|
||||
|
||||
// Upon unfullscreening, restore the view offset.
|
||||
let is_fullscreen = self.columns[col_idx].tiles[tile_idx].is_fullscreen();
|
||||
if was_fullscreen && !is_fullscreen {
|
||||
if let Some(prev_offset) = self.view_offset_before_fullscreen.take() {
|
||||
self.animate_view_offset(current_x, col_idx, prev_offset);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: we will want to skip the animation in some cases here to make continuously
|
||||
// resizing windows not look janky.
|
||||
self.animate_view_offset_to_column(current_x, col_idx, None);
|
||||
@@ -1077,6 +1101,18 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
for column in &self.columns {
|
||||
column.verify_invariants();
|
||||
}
|
||||
|
||||
// When we have an unfullscreen view offset stored, the active column should have a
|
||||
// fullscreen tile.
|
||||
if self.view_offset_before_fullscreen.is_some() {
|
||||
let col = &self.columns[self.active_column_idx];
|
||||
assert!(
|
||||
col.is_fullscreen
|
||||
|| col.tiles.iter().any(|tile| {
|
||||
tile.is_fullscreen() || tile.window().is_pending_fullscreen()
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1278,7 +1314,13 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
self.enter_output_for_window(&window);
|
||||
|
||||
let target_column = &mut self.columns[self.active_column_idx];
|
||||
let was_fullscreen = target_column.tiles[target_column.active_tile_idx].is_fullscreen();
|
||||
|
||||
target_column.add_window(window);
|
||||
|
||||
if !was_fullscreen {
|
||||
self.view_offset_before_fullscreen = None;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expel_from_column(&mut self) {
|
||||
@@ -1464,6 +1506,13 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
.find_map(|(col_idx, col)| col.position(window).map(|tile_idx| (col_idx, tile_idx)))
|
||||
.unwrap();
|
||||
|
||||
if is_fullscreen
|
||||
&& col_idx == self.active_column_idx
|
||||
&& self.columns[col_idx].tiles.len() == 1
|
||||
{
|
||||
self.view_offset_before_fullscreen = Some(self.static_view_offset());
|
||||
}
|
||||
|
||||
let mut col = &mut self.columns[col_idx];
|
||||
|
||||
if is_fullscreen && col.tiles.len() > 1 {
|
||||
@@ -1489,13 +1538,30 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
is_full_width,
|
||||
),
|
||||
);
|
||||
if self.active_column_idx >= col_idx || target_window_was_focused {
|
||||
|
||||
if target_window_was_focused {
|
||||
self.activate_column(col_idx);
|
||||
self.view_offset_before_fullscreen = Some(self.static_view_offset());
|
||||
} else if self.active_column_idx >= col_idx {
|
||||
self.active_column_idx += 1;
|
||||
}
|
||||
|
||||
col = &mut self.columns[col_idx];
|
||||
}
|
||||
|
||||
col.set_fullscreen(is_fullscreen);
|
||||
|
||||
// If we quickly fullscreen and unfullscreen before any window has a chance to receive the
|
||||
// request, we need to reset the offset.
|
||||
if col_idx == self.active_column_idx
|
||||
&& !is_fullscreen
|
||||
&& !col
|
||||
.tiles
|
||||
.iter()
|
||||
.any(|tile| tile.is_fullscreen() || tile.window().is_pending_fullscreen())
|
||||
{
|
||||
self.view_offset_before_fullscreen = None;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_fullscreen(&mut self, window: &W::Id) {
|
||||
@@ -1754,6 +1820,11 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
let new_col_x = self.column_x(new_col_idx);
|
||||
let delta = (active_col_x - new_col_x) as f64;
|
||||
self.view_offset = (current_view_offset + delta).round() as i32;
|
||||
|
||||
if self.active_column_idx != new_col_idx {
|
||||
self.view_offset_before_fullscreen = None;
|
||||
}
|
||||
|
||||
self.active_column_idx = new_col_idx;
|
||||
|
||||
let target_view_offset = target_snap.view_pos - new_col_x;
|
||||
|
||||
Reference in New Issue
Block a user