Skip to content

Commit

Permalink
shell: Properly handle fullscreen outputs
Browse files Browse the repository at this point in the history
  • Loading branch information
Drakulix committed Oct 11, 2023
1 parent 0c6b418 commit c573627
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 50 deletions.
8 changes: 4 additions & 4 deletions src/shell/layout/tiling/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,15 +363,15 @@ impl TilingLayout {
pub fn map<'a>(
&mut self,
window: CosmicMapped,
focus_stack: impl Iterator<Item = &'a CosmicMapped> + 'a,
focus_stack: Option<impl Iterator<Item = &'a CosmicMapped> + 'a>,
direction: Option<Direction>,
) {
window.output_enter(&self.output, window.bbox());
window.set_bounds(self.output.geometry().size.as_logical());
self.map_internal(window, Some(focus_stack), direction);
self.map_internal(window, focus_stack, direction);
}

fn map_internal<'a>(
pub fn map_internal<'a>(
&mut self,
window: impl Into<CosmicMapped>,
focus_stack: Option<impl Iterator<Item = &'a CosmicMapped> + 'a>,
Expand Down Expand Up @@ -528,7 +528,7 @@ impl TilingLayout {
}

mapped.set_tiled(true);
other.map(mapped.clone(), focus_stack, None);
other.map(mapped.clone(), Some(focus_stack), None);
return Some(KeyboardFocusTarget::Element(mapped));
}
None => {
Expand Down
93 changes: 79 additions & 14 deletions src/shell/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ pub struct Shell {

pub popups: PopupManager,
pub maximize_mode: MaximizeMode,
pub pending_windows: Vec<(CosmicSurface, Seat<State>)>,
pub pending_windows: Vec<(CosmicSurface, Seat<State>, Option<Output>)>,
pub pending_layers: Vec<(LayerSurface, Output, Seat<State>)>,
pub override_redirect_windows: Vec<X11Surface>,

Expand Down Expand Up @@ -382,7 +382,8 @@ impl WorkspaceSet {

for mut workspace in overflow {
if last_space.fullscreen.is_some() {
workspace.remove_fullscreen();
// Don't handle the returned original workspace, for this nieche case.
let _ = workspace.remove_fullscreen();
}

for element in workspace.mapped() {
Expand Down Expand Up @@ -1250,18 +1251,78 @@ impl Shell {
.refresh(Some(&self.workspace_state));
}

pub fn map_window(state: &mut State, window: &CosmicSurface, output: &Output) {
pub fn remap_unfullscreened_window(
&mut self,
mapped: CosmicMapped,
current_workspace: &WorkspaceHandle,
previous_workspace: &WorkspaceHandle,
target_layer: ManagedLayer,
) {
if self.space_for_handle(previous_workspace).is_none() {
return;
}

{
let Some(workspace) = self.space_for_handle_mut(&current_workspace) else { return };
let _ = workspace.unmap(&mapped);
}

let new_workspace_output = self
.space_for_handle(&previous_workspace)
.unwrap()
.output()
.clone();
for (window, _) in mapped.windows() {
self.toplevel_info_state
.toplevel_enter_output(&window, &new_workspace_output);
self.toplevel_info_state
.toplevel_enter_workspace(&window, &previous_workspace);
}

let new_workspace = self.space_for_handle_mut(&previous_workspace).unwrap();
match target_layer {
ManagedLayer::Floating => new_workspace.floating_layer.map(mapped, None),
ManagedLayer::Tiling => {
new_workspace
.tiling_layer
.map(mapped, Option::<std::iter::Empty<_>>::None, None)
}
};
}

pub fn map_window(state: &mut State, window: &CosmicSurface) {
let pos = state
.common
.shell
.pending_windows
.iter()
.position(|(w, _)| w == window)
.position(|(w, _, _)| w == window)
.unwrap();
let (window, seat) = state.common.shell.pending_windows.remove(pos);
let (window, seat, output) = state.common.shell.pending_windows.remove(pos);

let workspace = state.common.shell.workspaces.active_mut(output);
workspace.remove_fullscreen();
let should_be_fullscreen = output.is_some();
let output = output.unwrap_or_else(|| seat.active_output());

let workspace = state.common.shell.workspaces.active_mut(&output);
if let Some((mapped, layer, previous_workspace)) = workspace.remove_fullscreen() {
let old_handle = workspace.handle.clone();
let new_workspace_handle = state
.common
.shell
.space_for_handle(&previous_workspace)
.is_some()
.then_some(previous_workspace)
.unwrap_or(old_handle);

state.common.shell.remap_unfullscreened_window(
mapped,
&old_handle,
&new_workspace_handle,
layer,
);
};

let workspace = state.common.shell.workspaces.active_mut(&output);
state.common.shell.toplevel_info_state.new_toplevel(&window);
state
.common
Expand Down Expand Up @@ -1297,25 +1358,29 @@ impl Shell {
let focus_stack = workspace.focus_stack.get(&seat);
workspace
.tiling_layer
.map(mapped.clone(), focus_stack.iter(), None);
.map(mapped.clone(), Some(focus_stack.iter()), None);
}

if should_be_fullscreen {
workspace.fullscreen_request(&mapped.active_window(), None);
}

if let CosmicSurface::X11(surface) = window {
if let CosmicSurface::X11(ref surface) = window {
if let Some(xwm) = state
.common
.xwayland_state
.as_mut()
.and_then(|state| state.xwm.as_mut())
{
if let Err(err) = xwm.raise_window(&surface) {
if let Err(err) = xwm.raise_window(surface) {
warn!(?err, "Failed to update Xwayland stacking order.");
}
}
}

Shell::set_focus(state, Some(&KeyboardFocusTarget::from(mapped)), &seat, None);

let active_space = state.common.shell.active_space(output);
let active_space = state.common.shell.active_space(&output);
for mapped in active_space.mapped() {
state.common.shell.update_reactive_popups(mapped);
}
Expand Down Expand Up @@ -1440,10 +1505,10 @@ impl Shell {
} else {
to_workspace
.tiling_layer
.map(mapped.clone(), focus_stack.iter(), direction);
.map(mapped.clone(), Some(focus_stack.iter()), direction);
}
let focus_target = if window_state.was_fullscreen.is_some() {
to_workspace.fullscreen_request(&mapped.active_window());
let focus_target = if let Some(f) = window_state.was_fullscreen {
to_workspace.fullscreen_request(&mapped.active_window(), f.previously);
KeyboardFocusTarget::from(to_workspace.get_fullscreen().unwrap().clone())
} else {
KeyboardFocusTarget::from(mapped.clone())
Expand Down
32 changes: 24 additions & 8 deletions src/shell/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ pub struct Workspace {
#[derive(Debug, Clone)]
pub struct FullscreenSurface {
pub surface: CosmicSurface,
pub previously: Option<(ManagedLayer, WorkspaceHandle)>,
original_geometry: Rectangle<i32, Global>,
start_at: Option<Instant>,
ended_at: Option<Instant>,
Expand Down Expand Up @@ -472,7 +473,11 @@ impl Workspace {
None
}

pub fn fullscreen_request(&mut self, window: &CosmicSurface) {
pub fn fullscreen_request(
&mut self,
window: &CosmicSurface,
previously: Option<(ManagedLayer, WorkspaceHandle)>,
) {
if self.fullscreen.is_some() {
return;
}
Expand All @@ -497,14 +502,19 @@ impl Workspace {

self.fullscreen = Some(FullscreenSurface {
surface: window.clone(),
previously,
original_geometry,
start_at: Some(Instant::now()),
ended_at: None,
animation_signal: signal,
});
}

pub fn unfullscreen_request(&mut self, window: &CosmicSurface) -> Option<Size<i32, Logical>> {
#[must_use]
pub fn unfullscreen_request(
&mut self,
window: &CosmicSurface,
) -> Option<(ManagedLayer, WorkspaceHandle)> {
if let Some(f) = self.fullscreen.as_mut().filter(|f| &f.surface == window) {
window.set_fullscreen(false);
window.set_geometry(f.original_geometry);
Expand Down Expand Up @@ -545,15 +555,19 @@ impl Workspace {
}
}

Some(f.original_geometry.size.as_logical())
f.previously
} else {
None
}
}

pub fn remove_fullscreen(&mut self) {
#[must_use]
pub fn remove_fullscreen(&mut self) -> Option<(CosmicMapped, ManagedLayer, WorkspaceHandle)> {
if let Some(surface) = self.fullscreen.as_ref().map(|f| f.surface.clone()) {
self.unfullscreen_request(&surface);
self.unfullscreen_request(&surface)
.map(|(l, h)| (self.element_for_surface(&surface).unwrap().clone(), l, h))
} else {
None
}
}

Expand Down Expand Up @@ -633,7 +647,7 @@ impl Workspace {
.as_ref()
.is_some_and(|f| &f.surface == window)
{
self.remove_fullscreen();
let _ = self.remove_fullscreen(); // We are moving this window, we don't need to send it back to it's original workspace
}

let mapped = self.element_for_surface(&window)?.clone();
Expand Down Expand Up @@ -692,7 +706,8 @@ impl Workspace {
.into_iter()
{
self.floating_layer.unmap(&window);
self.tiling_layer.map(window, focus_stack.iter(), None)
self.tiling_layer
.map(window, Some(focus_stack.iter()), None)
}
self.tiling_enabled = true;
}
Expand All @@ -707,7 +722,8 @@ impl Workspace {
} else if self.floating_layer.mapped().any(|w| w == &window) {
let focus_stack = self.focus_stack.get(seat);
self.floating_layer.unmap(&window);
self.tiling_layer.map(window, focus_stack.iter(), None)
self.tiling_layer
.map(window, Some(focus_stack.iter()), None)
}
}
}
Expand Down
7 changes: 3 additions & 4 deletions src/wayland/handlers/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,12 +171,12 @@ impl CompositorHandler for State {
on_commit_buffer_handler::<Self>(surface);

// then handle initial configure events and map windows if necessary
if let Some((window, seat)) = self
if let Some((window, _, _)) = self
.common
.shell
.pending_windows
.iter()
.find(|(window, _)| window.wl_surface().as_ref() == Some(surface))
.find(|(window, _, _)| window.wl_surface().as_ref() == Some(surface))
.cloned()
{
match window {
Expand All @@ -185,9 +185,8 @@ impl CompositorHandler for State {
if self.toplevel_ensure_initial_configure(&toplevel)
&& with_renderer_surface_state(&surface, |state| state.buffer().is_some())
{
let output = seat.active_output();
window.on_commit();
Shell::map_window(self, &window, &output);
Shell::map_window(self, &window);
} else {
return;
}
Expand Down
Loading

0 comments on commit c573627

Please sign in to comment.