Restore view offset upon unfullscreening

This commit is contained in:
Ivan Molodetskikh
2024-04-13 18:17:49 +04:00
parent 1336a581a6
commit 2c873044e8
3 changed files with 177 additions and 1 deletions
+101
View File
@@ -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
+4
View File
@@ -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
View File
@@ -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;