shell: Properly handle fullscreen outputs

This commit is contained in:
Victoria Brekenfeld 2023-10-11 22:00:20 +02:00
parent aec8263e1b
commit 64143e75e7
6 changed files with 211 additions and 50 deletions

View file

@ -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 {
@ -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;
}

View file

@ -1,6 +1,10 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::{shell::CosmicSurface, utils::prelude::*, wayland::protocols::screencopy::SessionType};
use crate::{
shell::{element::CosmicWindow, CosmicMapped, CosmicSurface, ManagedLayer},
utils::prelude::*,
wayland::protocols::screencopy::SessionType,
};
use smithay::{
delegate_xdg_shell,
desktop::{
@ -38,7 +42,7 @@ impl XdgShellHandler for State {
fn new_toplevel(&mut self, surface: ToplevelSurface) {
let seat = self.common.last_active_seat().clone();
let window = CosmicSurface::Wayland(Window::new(surface));
self.common.shell.pending_windows.push((window, seat));
self.common.shell.pending_windows.push((window, seat, None));
// We will position the window after the first commit, when we know its size hints
}
@ -184,14 +188,14 @@ impl XdgShellHandler for State {
}
fn fullscreen_request(&mut self, surface: ToplevelSurface, output: Option<WlOutput>) {
let active_output = {
let seat = self.common.last_active_seat();
seat.active_output()
};
let output = output
.as_ref()
.and_then(Output::from_resource)
.unwrap_or_else(|| {
let seat = self.common.last_active_seat();
seat.active_output()
});
// TODO: If this is not the output? Do we move it?
.unwrap_or_else(|| active_output.clone());
if let Some(mapped) = self
.common
@ -200,11 +204,69 @@ impl XdgShellHandler for State {
.cloned()
{
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
let (window, _) = mapped
.windows()
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface.wl_surface()))
.unwrap();
workspace.fullscreen_request(&window)
if workspace.output != output {
let (mapped, layer) = if mapped
.stack_ref()
.map(|stack| stack.len() > 1)
.unwrap_or(false)
{
let stack = mapped.stack_ref().unwrap();
let surface = stack
.surfaces()
.find(|s| s.wl_surface().as_ref() == Some(surface.wl_surface()))
.unwrap();
stack.remove_window(&surface);
(
CosmicMapped::from(CosmicWindow::new(
surface,
self.common.event_loop_handle.clone(),
)),
if workspace.is_tiled(&mapped) {
ManagedLayer::Tiling
} else {
ManagedLayer::Floating
},
)
} else {
let layer = workspace.unmap(&mapped).unwrap().layer;
(mapped, layer)
};
let handle = workspace.handle.clone();
std::mem::drop(workspace);
let workspace_handle = self.common.shell.active_space(&output).handle.clone();
for (window, _) in mapped.windows() {
self.common
.shell
.toplevel_info_state
.toplevel_enter_output(&window, &output);
self.common
.shell
.toplevel_info_state
.toplevel_enter_workspace(&window, &workspace_handle);
}
let workspace = self.common.shell.active_space_mut(&output);
workspace.floating_layer.map(mapped.clone(), None);
workspace.fullscreen_request(&mapped.active_window(), Some((layer, handle)));
} else {
let (window, _) = mapped
.windows()
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface.wl_surface()))
.unwrap();
workspace.fullscreen_request(&window, None)
}
}
} else {
if let Some(o) = self
.common
.shell
.pending_windows
.iter_mut()
.find(|(s, _, _)| s.wl_surface().as_ref() == Some(surface.wl_surface()))
.map(|(_, _, o)| o)
{
*o = Some(output);
}
}
}
@ -221,7 +283,23 @@ impl XdgShellHandler for State {
.windows()
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface.wl_surface()))
.unwrap();
workspace.unfullscreen_request(&window);
if let Some((layer, previous_workspace)) = workspace.unfullscreen_request(&window) {
let old_handle = workspace.handle.clone();
let new_workspace_handle = self
.common
.shell
.space_for_handle(&previous_workspace)
.is_some()
.then_some(previous_workspace)
.unwrap_or(old_handle); // if the workspace doesn't exist anymore, we can still remap on the right layer
self.common.shell.remap_unfullscreened_window(
mapped,
&old_handle,
&new_workspace_handle,
layer,
);
}
}
}
}