Keep overview open when selecting workspace cards
This commit is contained in:
1 parent
0ab5f2e05b
commit
61870b9b6c
2 files changed
+59
-29
No files matched your search
+59
-27
@@ -104,6 +104,7 @@ type OverviewStateLabel = HashMap<
|
|||||||
pub(crate) struct OverviewState {
|
pub(crate) struct OverviewState {
|
||||||
active: bool,
|
active: bool,
|
||||||
selected: Option<WindowId>,
|
selected: Option<WindowId>,
|
||||||
|
selection_workspace: Option<WorkspaceId>,
|
||||||
presentations: HashMap<WindowId, AnimatedRect>,
|
presentations: HashMap<WindowId, AnimatedRect>,
|
||||||
opacity: AnimatedValue,
|
opacity: AnimatedValue,
|
||||||
exit_transition: Option<(f64, f64)>,
|
exit_transition: Option<(f64, f64)>,
|
||||||
@@ -119,6 +120,7 @@ impl Default for OverviewState {
|
|||||||
Self {
|
Self {
|
||||||
active: false,
|
active: false,
|
||||||
selected: None,
|
selected: None,
|
||||||
|
selection_workspace: None,
|
||||||
presentations: HashMap::new(),
|
presentations: HashMap::new(),
|
||||||
opacity: AnimatedValue::new(0.0),
|
opacity: AnimatedValue::new(0.0),
|
||||||
exit_transition: None,
|
exit_transition: None,
|
||||||
@@ -139,14 +141,6 @@ pub(crate) struct WorkspaceCard {
|
|||||||
pub windows: Vec<(WindowId, Rect)>,
|
pub windows: Vec<(WindowId, Rect)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorkspaceCard {
|
|
||||||
fn window_at(&self, point: Point<f64, Logical>) -> Option<WindowId> {
|
|
||||||
self.windows
|
|
||||||
.iter()
|
|
||||||
.find_map(|(id, rect)| contains(*rect, point).then_some(*id))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn workspace_strip(bounds: Rect) -> Rect {
|
pub(crate) fn workspace_strip(bounds: Rect) -> Rect {
|
||||||
let inset = 24.0_f64.min(bounds.width * 0.05);
|
let inset = 24.0_f64.min(bounds.width * 0.05);
|
||||||
Rect::new(
|
Rect::new(
|
||||||
@@ -291,6 +285,21 @@ impl OverviewState {
|
|||||||
self.opacity.current.clamp(0.0, 1.0) as f32
|
self.opacity.current.clamp(0.0, 1.0) as f32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn select_workspace_windows(&mut self, windows: &[WindowId], preferred: Option<WindowId>) {
|
||||||
|
let visible = |id: &WindowId| windows.contains(id) && self.presentations.contains_key(id);
|
||||||
|
self.selected = self
|
||||||
|
.selected
|
||||||
|
.filter(visible)
|
||||||
|
.or_else(|| preferred.filter(visible))
|
||||||
|
.or_else(|| {
|
||||||
|
windows
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.filter(visible)
|
||||||
|
.min_by_key(|id| id.0)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn selected(&self) -> Option<WindowId> {
|
pub(crate) fn selected(&self) -> Option<WindowId> {
|
||||||
self.selected
|
self.selected
|
||||||
}
|
}
|
||||||
@@ -322,6 +331,7 @@ impl OverviewState {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.selection_workspace = None;
|
||||||
self.selected = Some(next);
|
self.selected = Some(next);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@@ -359,6 +369,7 @@ impl OverviewState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.exit_transition = None;
|
self.exit_transition = None;
|
||||||
|
self.selection_workspace = None;
|
||||||
self.active = true;
|
self.active = true;
|
||||||
self.opacity.retarget_preserving_motion(1.0);
|
self.opacity.retarget_preserving_motion(1.0);
|
||||||
if !animations_enabled {
|
if !animations_enabled {
|
||||||
@@ -484,6 +495,7 @@ impl Ferese {
|
|||||||
.and_then(|w| self.window_ids.get(&w).copied());
|
.and_then(|w| self.window_ids.get(&w).copied());
|
||||||
|
|
||||||
if selected.is_some() && self.overview.selected != selected {
|
if selected.is_some() && self.overview.selected != selected {
|
||||||
|
self.overview.selection_workspace = None;
|
||||||
self.overview.selected = selected;
|
self.overview.selected = selected;
|
||||||
crate::backends::direct::render_all(self);
|
crate::backends::direct::render_all(self);
|
||||||
}
|
}
|
||||||
@@ -595,6 +607,23 @@ impl Ferese {
|
|||||||
|
|
||||||
let targets = self.overview_targets();
|
let targets = self.overview_targets();
|
||||||
self.overview.retarget(targets, self.animations_enabled());
|
self.overview.retarget(targets, self.animations_enabled());
|
||||||
|
if self.overview.selection_workspace.is_some() {
|
||||||
|
let id = self.workspaces.active_id();
|
||||||
|
self.overview.selection_workspace = Some(id);
|
||||||
|
let windows = self
|
||||||
|
.workspaces
|
||||||
|
.workspace(id)
|
||||||
|
.map(|workspace| {
|
||||||
|
workspace
|
||||||
|
.layout
|
||||||
|
.window_ids()
|
||||||
|
.chain(workspace.floating.iter().copied())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
self.overview
|
||||||
|
.select_workspace_windows(&windows, self.focused_window);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn presented_window_rect(&self, id: WindowId) -> Option<Rect> {
|
pub(crate) fn presented_window_rect(&self, id: WindowId) -> Option<Rect> {
|
||||||
@@ -732,12 +761,6 @@ impl Ferese {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.find(|card| contains(card.rect, point));
|
.find(|card| contains(card.rect, point));
|
||||||
if let Some(card) = card {
|
if let Some(card) = card {
|
||||||
if let Some(id) = card.window_at(point) {
|
|
||||||
if self.activate_managed_window(id) {
|
|
||||||
self.set_overview_active(false);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
let Some(output_id) = self.output_id(&output) else {
|
let Some(output_id) = self.output_id(&output) else {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@@ -749,6 +772,7 @@ impl Ferese {
|
|||||||
// Existing monitor ownership wins; never steal another output's workspace.
|
// Existing monitor ownership wins; never steal another output's workspace.
|
||||||
self.restore_output_focus();
|
self.restore_output_focus();
|
||||||
self.overview.strip_offsets.clear();
|
self.overview.strip_offsets.clear();
|
||||||
|
self.overview.selection_workspace = Some(card.workspace);
|
||||||
self.relayout();
|
self.relayout();
|
||||||
self.restore_keyboard_focus();
|
self.restore_keyboard_focus();
|
||||||
}
|
}
|
||||||
@@ -1164,19 +1188,27 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn workspace_thumbnail_hit_selects_the_clicked_window_not_workspace_focus() {
|
fn workspace_selection_replaces_other_output_selection_and_keeps_empty_selection() {
|
||||||
let card = WorkspaceCard {
|
let old = WindowId(1);
|
||||||
workspace: WorkspaceId(1),
|
let new = WindowId(2);
|
||||||
rect: Rect::new(0.0, 0.0, 160.0, 100.0),
|
let rect = Rect::new(0.0, 0.0, 100.0, 100.0);
|
||||||
selected: true,
|
let targets = HashMap::from([(old, (rect, rect)), (new, (rect, rect))]);
|
||||||
windows: vec![
|
let mut overview = OverviewState::default();
|
||||||
(WindowId(1), Rect::new(5.0, 5.0, 70.0, 65.0)),
|
overview.enter(targets.clone(), Some(old), false);
|
||||||
(WindowId(2), Rect::new(85.0, 5.0, 70.0, 65.0)),
|
|
||||||
],
|
overview.retarget(targets.clone(), false);
|
||||||
};
|
overview.select_workspace_windows(&[new], Some(new));
|
||||||
assert_eq!(card.window_at((120.0, 35.0).into()), Some(WindowId(2)));
|
assert!(overview.is_active());
|
||||||
assert_eq!(card.window_at((30.0, 35.0).into()), Some(WindowId(1)));
|
assert_eq!(overview.selected(), Some(new));
|
||||||
assert_eq!(card.window_at((80.0, 85.0).into()), None);
|
|
||||||
|
overview.retarget(targets.clone(), false);
|
||||||
|
overview.select_workspace_windows(&[], None);
|
||||||
|
assert_eq!(overview.selected(), None);
|
||||||
|
assert!(overview.is_active());
|
||||||
|
|
||||||
|
overview.retarget(targets, false);
|
||||||
|
overview.select_workspace_windows(&[new], None);
|
||||||
|
assert_eq!(overview.selected(), Some(new));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# Backlog
|
# Backlog
|
||||||
|
|
||||||
- [ ] Keep overview open when selecting a workspace and show all of that workspace’s windows. Activate a window only after the user selects it.
|
|
||||||
|
|
||||||
- [ ] Add a first-run keybinding guide modal showing important keybindings and their functions. Keep showing it until the user disables the guide in Settings.
|
- [ ] Add a first-run keybinding guide modal showing important keybindings and their functions. Keep showing it until the user disables the guide in Settings.
|
||||||
Reference in new issue
Block a user