server/decoration: remove decorations when fullscreen

This commit is contained in:
Shawn Wallace 2025-11-06 23:01:40 -05:00
parent c51c0759a2
commit 3cd3edffe1
4 changed files with 78 additions and 11 deletions

View file

@ -41,6 +41,8 @@ pub struct DecorationsDataSatellite {
x_data: DecorationsBox, x_data: DecorationsBox,
title: Option<String>, title: Option<String>,
title_rect: Rect, title_rect: Rect,
should_draw: bool,
remove_buffer: bool,
} }
impl Drop for DecorationsDataSatellite { impl Drop for DecorationsDataSatellite {
@ -100,6 +102,8 @@ impl DecorationsDataSatellite {
scale: 1.0, scale: 1.0,
title: title.map(str::to_string), title: title.map(str::to_string),
title_rect: Rect::from_ltrb(0.0, 0.0, 0.0, 0.0).unwrap(), title_rect: Rect::from_ltrb(0.0, 0.0, 0.0, 0.0).unwrap(),
should_draw: true,
remove_buffer: false,
} }
.into(), .into(),
new_pool.map(|p| { new_pool.map(|p| {
@ -134,9 +138,21 @@ impl DecorationsDataSatellite {
self.surface.commit(); self.surface.commit();
} }
pub fn draw_decorations(&mut self, world: &World, width: i32, parent_scale_factor: f32) { /// Returns true if decorations were actually drawn
if width <= 0 { #[must_use]
return; pub fn draw_decorations(
&mut self,
world: &World,
width: i32,
parent_scale_factor: f32,
) -> bool {
if width <= 0 || !self.should_draw {
if self.remove_buffer {
self.surface.attach(None, 0, 0);
self.surface.commit();
self.remove_buffer = false;
}
return false;
} }
self.scale = parent_scale_factor; self.scale = parent_scale_factor;
@ -196,6 +212,7 @@ impl DecorationsDataSatellite {
self.pixmap = bar; self.pixmap = bar;
self.viewport.set_destination(width, Self::TITLEBAR_HEIGHT); self.viewport.set_destination(width, Self::TITLEBAR_HEIGHT);
self.update_buffer(world); self.update_buffer(world);
true
} }
fn redraw_x_pixmap(&mut self, world: &World) { fn redraw_x_pixmap(&mut self, world: &World) {
@ -263,6 +280,13 @@ impl DecorationsDataSatellite {
self.update_buffer(world); self.update_buffer(world);
} }
pub fn handle_fullscreen(&mut self, fullscreen: bool) {
if self.should_draw == fullscreen {
self.should_draw = !fullscreen;
self.remove_buffer = fullscreen;
}
}
fn handle_motion(&mut self, world: &World, x: f64, y: f64) { fn handle_motion(&mut self, world: &World, x: f64, y: f64) {
if self.x_data.check_hovered(x as f32, y as f32) { if self.x_data.check_hovered(x as f32, y as f32) {
self.redraw_x_pixmap(world); self.redraw_x_pixmap(world);

View file

@ -313,13 +313,14 @@ impl SurfaceEvents {
if let SurfaceRole::Toplevel(Some(toplevel)) = &mut *role { if let SurfaceRole::Toplevel(Some(toplevel)) = &mut *role {
if let Some(d) = &mut toplevel.decoration.satellite { if let Some(d) = &mut toplevel.decoration.satellite {
let surface_width = (width as f64 / scale_factor.0) as i32; let surface_width = (width as f64 / scale_factor.0) as i32;
d.draw_decorations(&state.world, surface_width, scale_factor.0 as f32); if d.draw_decorations(&state.world, surface_width, scale_factor.0 as f32) {
height = height height = height
.saturating_sub( .saturating_sub(
(DecorationsDataSatellite::TITLEBAR_HEIGHT as f64 * scale_factor.0) (DecorationsDataSatellite::TITLEBAR_HEIGHT as f64 * scale_factor.0)
as u16, as u16,
) )
.max(DecorationsDataSatellite::TITLEBAR_HEIGHT as u16); .max(DecorationsDataSatellite::TITLEBAR_HEIGHT as u16);
}
} }
} }
@ -393,6 +394,9 @@ impl SurfaceEvents {
*data.get::<&x::Window>().unwrap(), *data.get::<&x::Window>().unwrap(),
toplevel.fullscreen, toplevel.fullscreen,
); );
if let Some(decorations) = toplevel.decoration.satellite.as_mut() {
decorations.handle_fullscreen(toplevel.fullscreen);
}
} }
}; };

View file

@ -2608,23 +2608,61 @@ fn client_side_decorations() {
let (_, id) = f.create_toplevel(&compositor, window); let (_, id) = f.create_toplevel(&compositor, window);
f.testwl f.testwl
.force_decoration_mode(id, zxdg_toplevel_decoration_v1::Mode::ClientSide); .force_decoration_mode(id, zxdg_toplevel_decoration_v1::Mode::ClientSide);
f.testwl.configure_toplevel(id, 100, 100, vec![]);
f.run(); f.run();
let data = f.connection().window(window);
assert_eq!(
data.dims,
WindowDims {
x: 0,
y: 0,
width: 100,
height: 75
}
);
let subsurface_id = f.testwl.last_created_surface_id().unwrap(); let subsurface_id = f.testwl.last_created_surface_id().unwrap();
assert_ne!(subsurface_id, id); assert_ne!(subsurface_id, id);
let data = f.testwl.get_surface_data(subsurface_id).unwrap(); let data = f.testwl.get_surface_data(subsurface_id).unwrap();
assert!(data.buffer.is_some());
let Some(SurfaceRole::Subsurface(subsurface)) = &data.role else { let Some(SurfaceRole::Subsurface(subsurface)) = &data.role else {
panic!("surface was not a subsurface: {:?}", data.role); panic!("surface was not a subsurface: {:?}", data.role);
}; };
assert_eq!(subsurface.position, testwl::Vec2 { x: 0, y: -25 }); assert_eq!(subsurface.position, testwl::Vec2 { x: 0, y: -25 });
assert_eq!(subsurface.parent, id); assert_eq!(subsurface.parent, id);
let subsurface = subsurface.subsurface.clone(); let subsurface = subsurface.subsurface.clone();
f.testwl
.configure_toplevel(id, 100, 100, vec![xdg_toplevel::State::Fullscreen]);
f.run();
let data = f.connection().window(window);
assert_eq!(
data.dims,
WindowDims {
x: 0,
y: 0,
width: 100,
height: 100
}
);
let data = f.testwl.get_surface_data(subsurface_id).unwrap();
assert!(data.buffer.is_none());
f.testwl f.testwl
.force_decoration_mode(id, zxdg_toplevel_decoration_v1::Mode::ServerSide); .force_decoration_mode(id, zxdg_toplevel_decoration_v1::Mode::ServerSide);
f.testwl.configure_toplevel(id, 100, 100, vec![]);
f.run(); f.run();
let data = f.connection().window(window);
assert_eq!(
data.dims,
WindowDims {
x: 0,
y: 0,
width: 100,
height: 100
}
);
assert!(f.testwl.get_surface_data(subsurface_id).is_none()); assert!(f.testwl.get_surface_data(subsurface_id).is_none());
assert!(!subsurface.is_alive()); assert!(!subsurface.is_alive());
} }

View file

@ -1865,6 +1865,7 @@ impl Dispatch<WlShmPool, ()> for State {
let buf = data_init.init(id, ()); let buf = data_init.init(id, ());
state.buffers.insert(buf); state.buffers.insert(buf);
} }
Resize { .. } => {}
Destroy => {} Destroy => {}
other => todo!("unhandled request {other:?}"), other => todo!("unhandled request {other:?}"),
} }