feat: support multiple fullscreen windows per workspace
This commit is contained in:
parent
9f28a764a7
commit
28ef6bdbc8
12 changed files with 381 additions and 308 deletions
128
src/shell/mod.rs
128
src/shell/mod.rs
|
|
@ -763,21 +763,19 @@ impl WorkspaceSet {
|
|||
.any(|(w, _)| w.wl_surface().as_deref() == Some(&root))
|
||||
})
|
||||
.and_then(|w| {
|
||||
w.surface_offset(surface).and_then(|offset| {
|
||||
self.sticky_layer
|
||||
.element_geometry(w)
|
||||
.map(|geom| (geom, offset))
|
||||
})
|
||||
self.sticky_layer
|
||||
.element_geometry(w)
|
||||
.zip(w.surface_offset(surface))
|
||||
})
|
||||
.or_else(|| {
|
||||
self.workspaces.iter().find_map(|workspace| {
|
||||
workspace
|
||||
.get_fullscreen()
|
||||
.and_then(|fullscreen| {
|
||||
(fullscreen.wl_surface().as_deref() == Some(&root))
|
||||
.get_fullscreen_surfaces()
|
||||
.find_map(|fs| {
|
||||
(fs.surface.wl_surface().as_deref() == Some(&root))
|
||||
.then(|| {
|
||||
fullscreen.surface_offset(surface).and_then(|offset| {
|
||||
workspace.fullscreen_geometry().map(|geom| (geom, offset))
|
||||
fs.surface.surface_offset(surface).map(|offset| {
|
||||
(workspace.fullscreen_geometry_for(fs), offset)
|
||||
})
|
||||
})
|
||||
.flatten()
|
||||
|
|
@ -787,9 +785,7 @@ impl WorkspaceSet {
|
|||
w.windows()
|
||||
.any(|(w, _)| w.wl_surface().as_deref() == Some(&root))
|
||||
.then(|| {
|
||||
w.surface_offset(surface).and_then(|offset| {
|
||||
workspace.element_geometry(w).map(|geom| (geom, offset))
|
||||
})
|
||||
workspace.element_geometry(w).zip(w.surface_offset(surface))
|
||||
})
|
||||
.flatten()
|
||||
})
|
||||
|
|
@ -1641,12 +1637,13 @@ impl Common {
|
|||
if let Some(mapped) = shell.element_for_surface(surface) {
|
||||
mapped.on_commit(surface);
|
||||
}
|
||||
if let Some(surface) = shell
|
||||
if let Some(fs) = shell
|
||||
.workspaces
|
||||
.spaces()
|
||||
.find_map(|w| w.get_fullscreen().filter(|s| *s == surface))
|
||||
.flat_map(|w| w.get_fullscreen_surfaces())
|
||||
.find(|f| f.surface == *surface)
|
||||
{
|
||||
surface.on_commit()
|
||||
fs.surface.on_commit()
|
||||
};
|
||||
}
|
||||
self.popups.commit(surface);
|
||||
|
|
@ -1907,7 +1904,9 @@ impl Shell {
|
|||
.outputs()
|
||||
.find(|output| {
|
||||
let workspace = self.active_space(output).unwrap();
|
||||
workspace.get_fullscreen() == Some(&elem)
|
||||
workspace
|
||||
.get_fullscreen_surfaces()
|
||||
.any(|f| f.surface == elem)
|
||||
})
|
||||
.cloned(),
|
||||
KeyboardFocusTarget::Group(WindowGroup { node, .. }) => self
|
||||
|
|
@ -2040,8 +2039,8 @@ impl Shell {
|
|||
let workspace = self.active_space(o).unwrap();
|
||||
|
||||
workspace
|
||||
.get_fullscreen()
|
||||
.is_some_and(|s| s.has_surface(surface, WindowSurfaceType::ALL))
|
||||
.get_fullscreen_surfaces()
|
||||
.any(|f| f.surface.has_surface(surface, WindowSurfaceType::ALL))
|
||||
|| workspace
|
||||
.mapped()
|
||||
.any(|e| e.has_surface(surface, WindowSurfaceType::ALL))
|
||||
|
|
@ -2096,8 +2095,8 @@ impl Shell {
|
|||
.workspaces
|
||||
.spaces()
|
||||
.find(|w| {
|
||||
w.get_fullscreen()
|
||||
.is_some_and(|s| s.has_surface(surface, WindowSurfaceType::ALL))
|
||||
w.get_fullscreen_surfaces()
|
||||
.any(|f| f.surface.has_surface(surface, WindowSurfaceType::ALL))
|
||||
|| w.mapped()
|
||||
.any(|e| e.has_surface(surface, WindowSurfaceType::ALL))
|
||||
|| w.minimized_windows.iter().any(|m| {
|
||||
|
|
@ -2144,7 +2143,7 @@ impl Shell {
|
|||
.mapped()
|
||||
.any(|m| m.windows().any(|(s, _)| &s == surface))
|
||||
|| set.workspaces.iter().any(|w| {
|
||||
w.get_fullscreen().is_some_and(|s| s == surface)
|
||||
w.get_fullscreen_surfaces().any(|f| &f.surface == surface)
|
||||
|| w.minimized_windows
|
||||
.iter()
|
||||
.any(|m| m.windows().any(|s| &s == surface))
|
||||
|
|
@ -2833,12 +2832,7 @@ impl Shell {
|
|||
let floating_exception = layout::has_floating_exception(&self.tiling_exceptions, &window);
|
||||
|
||||
if should_be_fullscreen {
|
||||
if let Some((surface, state, _)) = workspace.map_fullscreen(&window, &seat, None, None)
|
||||
{
|
||||
toplevel_leave_output(&surface, &workspace.output);
|
||||
toplevel_leave_workspace(&surface, &workspace.handle);
|
||||
self.remap_unfullscreened_window(surface, state, loop_handle);
|
||||
}
|
||||
workspace.map_fullscreen(&window, &seat, None, None);
|
||||
if was_activated {
|
||||
workspace_state.add_workspace_state(&workspace_handle, WState::Urgent);
|
||||
}
|
||||
|
|
@ -3209,9 +3203,12 @@ impl Shell {
|
|||
let from_workspace = self.workspaces.space_for_handle_mut(from).unwrap(); // checked above
|
||||
|
||||
let is_minimized = window.is_minimized();
|
||||
let is_fullscreen = from_workspace.get_fullscreen().is_some_and(|f| f == window);
|
||||
let is_fullscreen = from_workspace
|
||||
.get_fullscreen_surfaces()
|
||||
.any(|f| &f.surface == window);
|
||||
let mut window_state = if is_fullscreen {
|
||||
let (_, previous_state, previous_geometry) = from_workspace.take_fullscreen().unwrap();
|
||||
let (_, previous_state, previous_geometry) =
|
||||
from_workspace.take_fullscreen(window).unwrap();
|
||||
WorkspaceRestoreData::Fullscreen(previous_state.zip(previous_geometry).map(
|
||||
|(previous_state, previous_geometry)| FullscreenRestoreData {
|
||||
previous_state,
|
||||
|
|
@ -3367,14 +3364,12 @@ impl Shell {
|
|||
);
|
||||
mapped.into()
|
||||
} else if let WorkspaceRestoreData::Fullscreen(previous) = window_state {
|
||||
if let Some((old_surface, previous_state, _)) = to_workspace.map_fullscreen(
|
||||
to_workspace.map_fullscreen(
|
||||
window,
|
||||
None,
|
||||
previous.clone().map(|p| p.previous_state),
|
||||
previous.map(|p| p.previous_geometry),
|
||||
) {
|
||||
self.remap_unfullscreened_window(old_surface, previous_state, evlh);
|
||||
}
|
||||
);
|
||||
window.clone().into()
|
||||
} else {
|
||||
unreachable!() // TODO: sticky
|
||||
|
|
@ -3592,8 +3587,12 @@ impl Shell {
|
|||
} else if let Some((workspace, output)) = self.workspace_for_surface(surface) {
|
||||
let workspace = self.workspaces.space_for_handle(&workspace).unwrap();
|
||||
|
||||
if let Some(window) = workspace.get_fullscreen().filter(|s| *s == surface) {
|
||||
let global_position = (workspace.fullscreen_geometry().unwrap().loc
|
||||
if let Some(fs) = workspace
|
||||
.get_fullscreen_surfaces()
|
||||
.find(|f| &f.surface == surface)
|
||||
{
|
||||
let window = &fs.surface;
|
||||
let global_position = (workspace.fullscreen_geometry_for(fs).loc
|
||||
+ location.as_local())
|
||||
.to_global(&output);
|
||||
|
||||
|
|
@ -3686,10 +3685,14 @@ impl Shell {
|
|||
let maybe_fullscreen_workspace = self
|
||||
.workspaces
|
||||
.spaces_mut()
|
||||
.find(|w| w.get_fullscreen().is_some_and(|s| s == surface));
|
||||
.find(|w| w.get_fullscreen_surfaces().any(|f| &f.surface == surface));
|
||||
if let Some(workspace) = maybe_fullscreen_workspace {
|
||||
element_geo = Some(workspace.fullscreen_geometry().unwrap());
|
||||
let (surface, state, _) = workspace.remove_fullscreen().unwrap();
|
||||
let fs = workspace
|
||||
.get_fullscreen_surfaces()
|
||||
.find(|f| &f.surface == surface)
|
||||
.unwrap();
|
||||
element_geo = Some(workspace.fullscreen_geometry_for(fs));
|
||||
let (surface, state, _) = workspace.remove_fullscreen_surface(surface).unwrap();
|
||||
self.remap_unfullscreened_window(surface, state, evlh);
|
||||
};
|
||||
|
||||
|
|
@ -3902,19 +3905,15 @@ impl Shell {
|
|||
/// Get the window geometry of a keyboard focus target
|
||||
pub fn focused_geometry(&self, target: &KeyboardFocusTarget) -> Option<Rectangle<i32, Global>> {
|
||||
match target {
|
||||
KeyboardFocusTarget::Fullscreen(surface) => {
|
||||
if let Some(workspace) = surface
|
||||
.wl_surface()
|
||||
.and_then(|s| self.workspace_for_surface(&s))
|
||||
.and_then(|(handle, _)| self.workspaces.space_for_handle(&handle))
|
||||
{
|
||||
KeyboardFocusTarget::Fullscreen(surface) => surface
|
||||
.wl_surface()
|
||||
.and_then(|s| self.workspace_for_surface(&s))
|
||||
.and_then(|(handle, _)| self.workspaces.space_for_handle(&handle))
|
||||
.map(|workspace| {
|
||||
workspace
|
||||
.fullscreen_geometry()
|
||||
.map(|f| f.to_global(workspace.output()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
.fullscreen_geometry_for_surface(surface)
|
||||
.to_global(workspace.output())
|
||||
}),
|
||||
_ => {
|
||||
if let Some(element) = self.focused_element(target) {
|
||||
self.element_geometry(&element)
|
||||
|
|
@ -4266,9 +4265,8 @@ impl Shell {
|
|||
self.workspaces.sets.values_mut().find_map(|set| {
|
||||
set.workspaces.iter_mut().find_map(|workspace| {
|
||||
let window = workspace
|
||||
.get_fullscreen()
|
||||
.cloned()
|
||||
.into_iter()
|
||||
.get_fullscreen_surfaces()
|
||||
.map(|f| f.surface.clone())
|
||||
.chain(workspace.mapped().map(|m| m.active_window()))
|
||||
.find(|s| s == surface);
|
||||
window.map(|s| (workspace, s))
|
||||
|
|
@ -4768,15 +4766,16 @@ impl Shell {
|
|||
&mut self,
|
||||
surface: &S,
|
||||
output: Output,
|
||||
loop_handle: &LoopHandle<'static, State>,
|
||||
_loop_handle: &LoopHandle<'static, State>,
|
||||
) -> Option<KeyboardFocusTarget>
|
||||
where
|
||||
CosmicSurface: PartialEq<S>,
|
||||
{
|
||||
let mapped = self.element_for_surface(surface).cloned()?;
|
||||
let seat = self.seats.last_active().clone();
|
||||
let window;
|
||||
|
||||
let old_fullscreen = if let Some((old_output, set)) = self
|
||||
if let Some((old_output, set)) = self
|
||||
.workspaces
|
||||
.sets
|
||||
.iter_mut()
|
||||
|
|
@ -4823,7 +4822,7 @@ impl Shell {
|
|||
let workspace = self.active_space_mut(&output).unwrap();
|
||||
workspace.map_fullscreen(
|
||||
&window,
|
||||
None,
|
||||
&seat,
|
||||
Some(FullscreenRestoreState::Sticky {
|
||||
output: old_output,
|
||||
state: FloatingRestoreData {
|
||||
|
|
@ -4834,7 +4833,7 @@ impl Shell {
|
|||
},
|
||||
}),
|
||||
Some(from),
|
||||
)
|
||||
);
|
||||
} else if let Some(workspace) = self.space_for_mut(&mapped) {
|
||||
if mapped.is_minimized() {
|
||||
// TODO: Rewrite the `MinimizedWindow` to restore to fullscreen
|
||||
|
|
@ -4860,7 +4859,7 @@ impl Shell {
|
|||
|
||||
workspace.map_fullscreen(
|
||||
&window,
|
||||
None,
|
||||
&seat,
|
||||
match state {
|
||||
WorkspaceRestoreData::Floating(floating_state) => {
|
||||
floating_state.map(|state| FullscreenRestoreState::Floating {
|
||||
|
|
@ -4877,15 +4876,11 @@ impl Shell {
|
|||
WorkspaceRestoreData::Fullscreen(_) => unreachable!(),
|
||||
},
|
||||
Some(from),
|
||||
)
|
||||
);
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
if let Some((old_fullscreen, restore, _)) = old_fullscreen {
|
||||
self.remap_unfullscreened_window(old_fullscreen, restore, loop_handle);
|
||||
}
|
||||
|
||||
Some(KeyboardFocusTarget::Fullscreen(window))
|
||||
}
|
||||
|
||||
|
|
@ -4900,11 +4895,12 @@ impl Shell {
|
|||
let maybe_workspace = self.workspaces.iter_mut().find_map(|(_, s)| {
|
||||
s.workspaces
|
||||
.iter_mut()
|
||||
.find(|w| w.get_fullscreen().is_some_and(|f| f == surface))
|
||||
.find(|w| w.get_fullscreen_surfaces().any(|f| &f.surface == surface))
|
||||
});
|
||||
|
||||
if let Some(workspace) = maybe_workspace {
|
||||
let (old_fullscreen, restore, _) = workspace.remove_fullscreen().unwrap();
|
||||
let (old_fullscreen, restore, _) =
|
||||
workspace.remove_fullscreen_surface(surface).unwrap();
|
||||
toplevel_leave_output(&old_fullscreen, &workspace.output);
|
||||
toplevel_leave_workspace(&old_fullscreen, &workspace.handle);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue