From ba98103233edec09a692d3d7979bc9e5a0d065df Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Fri, 29 Mar 2024 20:07:28 +0100 Subject: [PATCH] tree: make surface visibility tracking more robust --- src/backends/metal.rs | 4 +- src/backends/metal/video.rs | 7 +- src/backends/x.rs | 2 + src/compositor.rs | 1 + src/cursor.rs | 4 + src/ifs/ext_session_lock_v1.rs | 4 +- src/ifs/jay_compositor.rs | 2 +- src/ifs/wl_seat.rs | 14 ++ src/ifs/wl_seat/pointer_owner.rs | 6 +- src/ifs/wl_surface.rs | 35 +++-- src/ifs/wl_surface/cursor.rs | 11 ++ .../wl_surface/ext_session_lock_surface_v1.rs | 2 +- src/ifs/wl_surface/wl_subsurface.rs | 13 ++ src/ifs/wl_surface/x_surface/xwindow.rs | 4 + src/ifs/wl_surface/xdg_surface.rs | 2 +- src/ifs/wl_surface/xdg_surface/xdg_popup.rs | 17 ++- .../wl_surface/xdg_surface/xdg_toplevel.rs | 1 + src/ifs/wl_surface/zwlr_layer_surface_v1.rs | 4 + src/it/test_backend.rs | 1 + src/renderer.rs | 142 +++++++++--------- src/state.rs | 11 ++ src/tree/display.rs | 16 ++ src/tree/float.rs | 8 +- src/tree/output.rs | 93 ++++++++---- src/tree/stacked.rs | 7 + src/tree/workspace.rs | 40 +++-- 26 files changed, 310 insertions(+), 141 deletions(-) diff --git a/src/backends/metal.rs b/src/backends/metal.rs index 78a01341..fb76db20 100644 --- a/src/backends/metal.rs +++ b/src/backends/metal.rs @@ -196,7 +196,9 @@ impl Backend for MetalBackend { return; } } - if !idle { + if idle { + self.state.set_backend_idle(true); + } else { for device in devices.values() { for connector in device.connectors.lock().values() { connector.schedule_present(); diff --git a/src/backends/metal/video.rs b/src/backends/metal/video.rs index 072ea5cd..c5300ded 100644 --- a/src/backends/metal/video.rs +++ b/src/backends/metal/video.rs @@ -389,8 +389,11 @@ impl MetalConnector { async fn present_loop(self: Rc) { loop { self.present_trigger.triggered().await; - if let Err(e) = self.present(true) { - log::error!("Could not present: {}", ErrorFmt(e)); + match self.present(true) { + Ok(_) => self.state.set_backend_idle(false), + Err(e) => { + log::error!("Could not present: {}", ErrorFmt(e)); + } } } } diff --git a/src/backends/x.rs b/src/backends/x.rs index 1130e32c..88f2c8ac 100644 --- a/src/backends/x.rs +++ b/src/backends/x.rs @@ -772,6 +772,8 @@ impl XBackend { log::error!("Could not present image: {:?}", e); return; } + + self.state.set_backend_idle(false); } async fn handle_input_event(self: &Rc, event: &Event) -> Result<(), XBackendError> { diff --git a/src/compositor.rs b/src/compositor.rs index c435c5b8..4f30dc91 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -184,6 +184,7 @@ fn start_compositor2( timeout_changed: Default::default(), inhibitors: Default::default(), inhibitors_changed: Default::default(), + backend_idle: Cell::new(true), }, run_args, xwayland: XWaylandState { diff --git a/src/cursor.rs b/src/cursor.rs index 04c245ab..098b6e76 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -69,6 +69,10 @@ pub trait Cursor { fn time_until_tick(&self) -> Duration { Duration::new(0, 0) } + + fn set_visible(&self, visible: bool) { + let _ = visible; + } } pub struct ServerCursors { diff --git a/src/ifs/ext_session_lock_v1.rs b/src/ifs/ext_session_lock_v1.rs index 057b1f99..dd518d8a 100644 --- a/src/ifs/ext_session_lock_v1.rs +++ b/src/ifs/ext_session_lock_v1.rs @@ -66,7 +66,7 @@ impl ExtSessionLockV1 { if node.lock_surface.is_some() { return Err(ExtSessionLockV1Error::OutputAlreadyLocked); } - node.lock_surface.set(Some(new.clone())); + node.set_lock_surface(Some(new.clone())); let pos = output.global.pos.get(); new.change_extents(pos); self.client.state.tree_changed(); @@ -85,7 +85,7 @@ impl ExtSessionLockV1 { state.lock.locked.set(false); state.lock.lock.take(); for output in state.outputs.lock().values() { - if let Some(surface) = output.node.lock_surface.take() { + if let Some(surface) = output.node.set_lock_surface(None) { surface.destroy_node(); } } diff --git a/src/ifs/jay_compositor.rs b/src/ifs/jay_compositor.rs index 696ae7fa..9acf0035 100644 --- a/src/ifs/jay_compositor.rs +++ b/src/ifs/jay_compositor.rs @@ -190,7 +190,7 @@ impl JayCompositor { lock.finish(); } for output in state.outputs.lock().values() { - if let Some(surface) = output.node.lock_surface.take() { + if let Some(surface) = output.node.set_lock_surface(None) { surface.destroy_node(); } } diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index 1da67a81..e9c225ca 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -981,6 +981,20 @@ impl WlSeatGlobal { pub fn last_input(&self) -> u64 { self.last_input_usec.get() } + + pub fn set_visible(&self, visible: bool) { + if let Some(cursor) = self.cursor.get() { + cursor.set_visible(visible); + } + if let Some(icon) = self.dnd_icon() { + icon.set_visible(visible); + } + if let Some(tl_drag) = self.toplevel_drag() { + if let Some(tl) = tl_drag.toplevel.get() { + tl.tl_set_visible(visible); + } + } + } } global_base!(WlSeatGlobal, WlSeat, WlSeatError); diff --git a/src/ifs/wl_seat/pointer_owner.rs b/src/ifs/wl_seat/pointer_owner.rs index d89c0668..ddd9ecf0 100644 --- a/src/ifs/wl_seat/pointer_owner.rs +++ b/src/ifs/wl_seat/pointer_owner.rs @@ -368,7 +368,7 @@ impl PointerOwner for GrabPointerOwner { return Ok(()); } if let Some(icon) = &icon { - icon.dnd_icons.insert(seat.id(), seat.clone()); + icon.set_dnd_icon_seat(seat.id, Some(seat)); } if let Some(new) = &src { ipc::attach_seat::(new, seat, ipc::Role::Dnd)?; @@ -460,7 +460,7 @@ impl PointerOwner for DndPointerOwner { } } if let Some(icon) = self.icon.get() { - icon.dnd_icons.remove(&seat.id()); + icon.set_dnd_icon_seat(seat.id(), None); } seat.pointer_owner.set_default_pointer_owner(seat); seat.tree_changed.trigger(); @@ -530,7 +530,7 @@ impl PointerOwner for DndPointerOwner { ipc::detach_seat::(src, seat); } if let Some(icon) = self.icon.get() { - icon.dnd_icons.remove(&seat.id()); + icon.set_dnd_icon_seat(seat.id(), None); } seat.pointer_owner.set_default_pointer_owner(seat); seat.tree_changed.trigger(); diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index ef1e76af..884afcf9 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -234,7 +234,7 @@ pub struct WlSurface { seat_state: NodeSeatState, toplevel: CloneCell>>, cursors: SmallMap, 1>, - pub dnd_icons: SmallMap, 1>, + dnd_icons: SmallMap, 1>, pub tracker: Tracker, idle_inhibitors: SmallMap, 1>, viewporter: CloneCell>>, @@ -489,7 +489,7 @@ impl WlSurface { id, node_id: client.state.node_ids.next(), client: client.clone(), - visible: Default::default(), + visible: Cell::new(false), role: Cell::new(SurfaceRole::None), pending: Default::default(), input_region: Default::default(), @@ -1184,7 +1184,9 @@ impl WlSurface { } pub fn set_visible(&self, visible: bool) { - self.visible.set(visible); + if self.visible.replace(visible) == visible { + return; + } for (_, inhibitor) in &self.idle_inhibitors { if visible { inhibitor.activate(); @@ -1204,11 +1206,7 @@ impl WlSurface { self.seat_state.set_visible(self, visible); } - pub fn detach_node(&self) { - self.destroy_node(); - } - - pub fn destroy_node(&self) { + pub fn detach_node(&self, set_invisible: bool) { for (_, constraint) in &self.constraints { constraint.deactivate(); } @@ -1218,7 +1216,7 @@ impl WlSurface { let children = self.children.borrow(); if let Some(ch) = children.deref() { for ss in ch.subsurfaces.values() { - ss.surface.destroy_node(); + ss.surface.detach_node(set_invisible); } } if let Some(tl) = self.toplevel.get() { @@ -1238,6 +1236,13 @@ impl WlSurface { if self.visible.get() { self.client.state.damage(); } + if set_invisible { + self.visible.set(false); + } + } + + pub fn destroy_node(&self) { + self.detach_node(true); } pub fn set_content_type(&self, content_type: Option) { @@ -1267,6 +1272,18 @@ impl WlSurface { .get() .consume_pending_child(self, child, &mut consume) } + + pub fn set_dnd_icon_seat(&self, id: SeatId, seat: Option<&Rc>) { + match seat { + None => { + self.dnd_icons.remove(&id); + } + Some(seat) => { + self.dnd_icons.insert(id, seat.clone()); + } + } + self.set_visible(self.dnd_icons.is_not_empty() && self.client.state.root_visible()); + } } object_base! { diff --git a/src/ifs/wl_surface/cursor.rs b/src/ifs/wl_surface/cursor.rs index 79efa74e..9de08603 100644 --- a/src/ifs/wl_surface/cursor.rs +++ b/src/ifs/wl_surface/cursor.rs @@ -125,9 +125,20 @@ impl Cursor for CursorSurface { fn handle_set(self: Rc) { self.surface.cursors.insert(self.seat.id(), self.clone()); + if self.surface.cursors.is_not_empty() { + self.surface + .set_visible(self.surface.client.state.root_visible()); + } } fn handle_unset(&self) { self.surface.cursors.remove(&self.seat.id()); + if self.surface.cursors.is_empty() { + self.surface.set_visible(false); + } + } + + fn set_visible(&self, visible: bool) { + self.surface.set_visible(visible); } } diff --git a/src/ifs/wl_surface/ext_session_lock_surface_v1.rs b/src/ifs/wl_surface/ext_session_lock_surface_v1.rs index 08b0b14f..cc713ea8 100644 --- a/src/ifs/wl_surface/ext_session_lock_surface_v1.rs +++ b/src/ifs/wl_surface/ext_session_lock_surface_v1.rs @@ -74,7 +74,7 @@ impl ExtSessionLockSurfaceV1 { if let Some(output) = &self.output { if let Some(ls) = output.lock_surface.get() { if ls.node_id == self.node_id { - output.lock_surface.take(); + output.set_lock_surface(None); self.client.state.tree_changed(); } } diff --git a/src/ifs/wl_surface/wl_subsurface.rs b/src/ifs/wl_surface/wl_subsurface.rs index 6c4146e1..aedb7609 100644 --- a/src/ifs/wl_surface/wl_subsurface.rs +++ b/src/ifs/wl_surface/wl_subsurface.rs @@ -46,6 +46,7 @@ pub struct WlSubsurface { latest_node: CloneCell>>, depth: NumCell, pub tracker: Tracker, + had_buffer: Cell, } #[derive(Default)] @@ -102,6 +103,7 @@ impl WlSubsurface { latest_node: Default::default(), depth: NumCell::new(0), tracker: Default::default(), + had_buffer: Cell::new(false), } } @@ -178,6 +180,7 @@ impl WlSubsurface { } } self.surface.client.remove_obj(self)?; + self.surface.destroy_node(); Ok(()) } @@ -344,6 +347,16 @@ impl SurfaceExt for WlSubsurface { self.parent.need_extents_update.set(true); } } + let has_buffer = self.surface.buffer.is_some(); + if self.had_buffer.replace(has_buffer) != has_buffer { + if has_buffer { + if self.parent.visible.get() { + self.surface.set_visible(true); + } + } else { + self.surface.destroy_node(); + } + } } fn subsurface_parent(&self) -> Option> { diff --git a/src/ifs/wl_surface/x_surface/xwindow.rs b/src/ifs/wl_surface/x_surface/xwindow.rs index b6685335..cb06db52 100644 --- a/src/ifs/wl_surface/x_surface/xwindow.rs +++ b/src/ifs/wl_surface/x_surface/xwindow.rs @@ -436,6 +436,10 @@ impl StackedNode for Xwindow { fn stacked_set_visible(&self, visible: bool) { self.tl_set_visible(visible); } + + fn stacked_has_workspace_link(&self) -> bool { + false + } } #[derive(Debug, Error)] diff --git a/src/ifs/wl_surface/xdg_surface.rs b/src/ifs/wl_surface/xdg_surface.rs index 8974381c..4bdf2965 100644 --- a/src/ifs/wl_surface/xdg_surface.rs +++ b/src/ifs/wl_surface/xdg_surface.rs @@ -183,7 +183,7 @@ impl XdgSurface { fn detach_node(&self) { self.workspace.set(None); - self.surface.detach_node(); + self.surface.detach_node(false); let popups = self.popups.lock(); for popup in popups.values() { popup.detach_node(); diff --git a/src/ifs/wl_surface/xdg_surface/xdg_popup.rs b/src/ifs/wl_surface/xdg_surface/xdg_popup.rs index 078cc31e..a6df1ff8 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_popup.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup.rs @@ -47,6 +47,7 @@ pub struct XdgPopup { pos: RefCell, pub tracker: Tracker, seat_state: NodeSeatState, + set_visible_prepared: Cell, } impl Debug for XdgPopup { @@ -77,6 +78,7 @@ impl XdgPopup { pos: RefCell::new(pos), tracker: Default::default(), seat_state: Default::default(), + set_visible_prepared: Cell::new(false), }) } @@ -243,6 +245,7 @@ impl XdgPopup { pub fn set_visible(&self, visible: bool) { // log::info!("set visible = {}", visible); + self.set_visible_prepared.set(false); self.xdg.set_visible(visible); self.seat_state.set_visible(self, visible); } @@ -340,8 +343,20 @@ impl Node for XdgPopup { impl StackedNode for XdgPopup { stacked_node_impl!(); + fn stacked_prepare_set_visible(&self) { + self.set_visible_prepared.set(true); + } + + fn stacked_needs_set_visible(&self) -> bool { + self.set_visible_prepared.get() + } + fn stacked_set_visible(&self, visible: bool) { - self.xdg.set_visible(visible); + self.set_visible(visible); + } + + fn stacked_has_workspace_link(&self) -> bool { + self.workspace_link.borrow().is_some() } fn stacked_absolute_position_constrains_input(&self) -> bool { diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs index 2fd3cabf..f77943ba 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs @@ -389,6 +389,7 @@ impl XdgToplevel { } self.toplevel_data.detach_node(self); self.xdg.detach_node(); + self.tl_set_visible(self.state.root_visible()); } pub fn after_toplevel_drag(self: &Rc, output: &Rc, x: i32, y: i32) { diff --git a/src/ifs/wl_surface/zwlr_layer_surface_v1.rs b/src/ifs/wl_surface/zwlr_layer_surface_v1.rs index 9e6c87e9..c5817af1 100644 --- a/src/ifs/wl_surface/zwlr_layer_surface_v1.rs +++ b/src/ifs/wl_surface/zwlr_layer_surface_v1.rs @@ -351,6 +351,7 @@ impl SurfaceExt for ZwlrLayerSurfaceV1 { fn after_apply_commit(self: Rc, _pending: &mut PendingState) { let buffer_is_some = self.surface.buffer.is_some(); + let was_mapped = self.mapped.get(); if self.mapped.get() { if !buffer_is_some { self.destroy_node(); @@ -367,6 +368,9 @@ impl SurfaceExt for ZwlrLayerSurfaceV1 { self.mapped.set(true); self.compute_position(); } + if self.mapped.get() != was_mapped { + self.output.update_visible(); + } if self.mapped.get() { match self.keyboard_interactivity.get() { KI_NONE => { diff --git a/src/it/test_backend.rs b/src/it/test_backend.rs index 00a2d219..17ff055f 100644 --- a/src/it/test_backend.rs +++ b/src/it/test_backend.rs @@ -47,6 +47,7 @@ pub struct TestBackend { impl TestBackend { pub fn new(state: &Rc, future: TestFuture) -> Self { + state.set_backend_idle(false); let default_connector = Rc::new(TestConnector { id: state.connector_ids.next(), kernel_id: ConnectorKernelId { diff --git a/src/renderer.rs b/src/renderer.rs index 0bb25b1f..93922a9d 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -104,85 +104,85 @@ impl Renderer<'_> { } }; } + let mut fullscreen = None; if let Some(ws) = output.workspace.get() { - if let Some(fs) = ws.fullscreen.get() { - fs.tl_as_node().node_render(self, x, y, None); - render_layer!(output.layers[2]); - render_layer!(output.layers[3]); - return; - } + fullscreen = ws.fullscreen.get(); } - render_layer!(output.layers[0]); - render_layer!(output.layers[1]); - let theme = &self.state.theme; - let th = theme.sizes.title_height.get(); - { - let c = theme.colors.bar_background.get(); - self.base.fill_boxes2( - slice::from_ref(&Rect::new_sized(0, 0, opos.width(), th).unwrap()), - &c, - x, - y, - ); - let has_captures = - !output.screencasts.is_empty() || !output.global.pending_captures.is_empty(); - let rd = output.render_data.borrow_mut(); - if let Some(aw) = &rd.active_workspace { - let c = match has_captures && aw.captured { - true => theme.colors.captured_focused_title_background.get(), - false => theme.colors.focused_title_background.get(), - }; - self.base.fill_boxes2(slice::from_ref(&aw.rect), &c, x, y); - } - let c = theme.colors.separator.get(); - self.base - .fill_boxes2(slice::from_ref(&rd.underline), &c, x, y); - let c = theme.colors.unfocused_title_background.get(); - self.base.fill_boxes2(&rd.inactive_workspaces, &c, x, y); - let c = match has_captures { - true => theme.colors.captured_unfocused_title_background.get(), - false => theme.colors.unfocused_title_background.get(), - }; - self.base - .fill_boxes2(&rd.captured_inactive_workspaces, &c, x, y); - let c = theme.colors.attention_requested_background.get(); - self.base - .fill_boxes2(&rd.attention_requested_workspaces, &c, x, y); - let scale = output.global.persistent.scale.get(); - for title in &rd.titles { - let (x, y) = self.base.scale_point(x + title.tex_x, y + title.tex_y); - self.base.render_texture( - &title.tex, + if let Some(fs) = fullscreen { + fs.tl_as_node().node_render(self, x, y, None); + } else { + render_layer!(output.layers[0]); + render_layer!(output.layers[1]); + let theme = &self.state.theme; + let th = theme.sizes.title_height.get(); + { + let c = theme.colors.bar_background.get(); + self.base.fill_boxes2( + slice::from_ref(&Rect::new_sized(0, 0, opos.width(), th).unwrap()), + &c, x, y, - None, - None, - scale, - None, - None, - AcquireSync::None, - ReleaseSync::None, ); + let has_captures = + !output.screencasts.is_empty() || !output.global.pending_captures.is_empty(); + let rd = output.render_data.borrow_mut(); + if let Some(aw) = &rd.active_workspace { + let c = match has_captures && aw.captured { + true => theme.colors.captured_focused_title_background.get(), + false => theme.colors.focused_title_background.get(), + }; + self.base.fill_boxes2(slice::from_ref(&aw.rect), &c, x, y); + } + let c = theme.colors.separator.get(); + self.base + .fill_boxes2(slice::from_ref(&rd.underline), &c, x, y); + let c = theme.colors.unfocused_title_background.get(); + self.base.fill_boxes2(&rd.inactive_workspaces, &c, x, y); + let c = match has_captures { + true => theme.colors.captured_unfocused_title_background.get(), + false => theme.colors.unfocused_title_background.get(), + }; + self.base + .fill_boxes2(&rd.captured_inactive_workspaces, &c, x, y); + let c = theme.colors.attention_requested_background.get(); + self.base + .fill_boxes2(&rd.attention_requested_workspaces, &c, x, y); + let scale = output.global.persistent.scale.get(); + for title in &rd.titles { + let (x, y) = self.base.scale_point(x + title.tex_x, y + title.tex_y); + self.base.render_texture( + &title.tex, + x, + y, + None, + None, + scale, + None, + None, + AcquireSync::None, + ReleaseSync::None, + ); + } + if let Some(status) = &rd.status { + let (x, y) = self.base.scale_point(x + status.tex_x, y + status.tex_y); + self.base.render_texture( + &status.tex.texture, + x, + y, + None, + None, + scale, + None, + None, + AcquireSync::None, + ReleaseSync::None, + ); + } } - if let Some(status) = &rd.status { - let (x, y) = self.base.scale_point(x + status.tex_x, y + status.tex_y); - self.base.render_texture( - &status.tex.texture, - x, - y, - None, - None, - scale, - None, - None, - AcquireSync::None, - ReleaseSync::None, - ); + if let Some(ws) = output.workspace.get() { + self.render_workspace(&ws, x, y + th + 1); } } - if let Some(ws) = output.workspace.get() { - self.render_workspace(&ws, x, y + th + 1); - } for stacked in self.state.root.stacked.iter() { if stacked.node_visible() { self.base.ops.push(GfxApiOpt::Sync); diff --git a/src/state.rs b/src/state.rs index ff1ad5c9..a6047fe4 100644 --- a/src/state.rs +++ b/src/state.rs @@ -205,6 +205,7 @@ pub struct IdleState { pub timeout_changed: Cell, pub inhibitors: CopyHashMap>, pub inhibitors_changed: Cell, + pub backend_idle: Cell, } impl IdleState { @@ -960,6 +961,16 @@ impl State { log::error!("Could not signal sync obj: {}", ErrorFmt(e)); } } + + pub fn set_backend_idle(&self, idle: bool) { + if self.idle.backend_idle.replace(idle) != idle { + self.root.update_visible(self); + } + } + + pub fn root_visible(&self) -> bool { + !self.idle.backend_idle.get() + } } #[derive(Debug, Error)] diff --git a/src/tree/display.rs b/src/tree/display.rs index caad562f..e10333fd 100644 --- a/src/tree/display.rs +++ b/src/tree/display.rs @@ -5,6 +5,7 @@ use { ifs::wl_seat::{NodeSeatState, WlSeatGlobal}, rect::Rect, renderer::Renderer, + state::State, tree::{ walker::NodeVisitor, FindTreeResult, FoundNode, Node, NodeId, OutputNode, StackedNode, }, @@ -60,6 +61,21 @@ impl DisplayNode { } self.extents.set(Rect::new(x1, y1, x2, y2).unwrap()); } + + pub fn update_visible(&self, state: &State) { + let visible = state.root_visible(); + for output in self.outputs.lock().values() { + output.update_visible(); + } + for stacked in self.stacked.iter() { + if !stacked.stacked_has_workspace_link() { + stacked.stacked_set_visible(visible); + } + } + for seat in state.globals.seats.lock().values() { + seat.set_visible(visible); + } + } } impl Node for DisplayNode { diff --git a/src/tree/float.rs b/src/tree/float.rs index 7f191216..6cc692ca 100644 --- a/src/tree/float.rs +++ b/src/tree/float.rs @@ -101,7 +101,7 @@ impl FloatNode { let floater = Rc::new(FloatNode { id: state.node_ids.next(), state: state.clone(), - visible: Cell::new(ws.stacked_visible()), + visible: Cell::new(ws.container_visible()), position: Cell::new(position), display_link: RefCell::new(None), workspace_link: Cell::new(None), @@ -346,7 +346,7 @@ impl FloatNode { self.workspace_link .set(Some(ws.stacked.add_last(self.clone()))); self.workspace.set(ws.clone()); - self.stacked_set_visible(ws.stacked_visible()); + self.stacked_set_visible(ws.container_visible()); } fn update_child_title(self: &Rc, title: &str) { @@ -625,4 +625,8 @@ impl StackedNode for FloatNode { } self.seat_state.set_visible(self, visible); } + + fn stacked_has_workspace_link(&self) -> bool { + true + } } diff --git a/src/tree/output.rs b/src/tree/output.rs index 165abe34..7f4bf2c0 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -317,7 +317,7 @@ impl OutputNode { old.flush_jay_workspaces(); } } - ws.set_visible(true); + self.update_visible(); if let Some(fs) = ws.fullscreen.get() { fs.tl_change_extents(&self.global.pos.get()); } @@ -502,6 +502,44 @@ impl OutputNode { .map(|w| w.fullscreen.is_some()) .unwrap_or(false) } + + pub fn set_lock_surface( + &self, + surface: Option>, + ) -> Option> { + let prev = self.lock_surface.set(surface); + self.update_visible(); + prev + } + + pub fn update_visible(&self) { + let mut visible = self.state.root_visible(); + if self.state.lock.locked.get() { + if let Some(surface) = self.lock_surface.get() { + surface.surface.set_visible(visible); + } + visible = false; + } + macro_rules! set_layer_visible { + ($layer:expr, $visible:expr) => { + for ls in $layer.iter() { + ls.surface.set_visible($visible); + } + }; + } + let mut have_fullscreen = false; + if let Some(ws) = self.workspace.get() { + have_fullscreen = ws.fullscreen.is_some(); + } + let lower_visible = visible && have_fullscreen; + set_layer_visible!(self.layers[0], lower_visible); + set_layer_visible!(self.layers[1], lower_visible); + if let Some(ws) = self.workspace.get() { + ws.set_visible(visible); + } + set_layer_visible!(self.layers[2], visible); + set_layer_visible!(self.layers[3], visible); + } } pub struct OutputTitle { @@ -607,16 +645,6 @@ impl Node for OutputNode { return res; } } - if let Some(ws) = self.workspace.get() { - if let Some(fs) = ws.fullscreen.get() { - tree.push(FoundNode { - node: fs.clone().tl_into_node(), - x, - y, - }); - return fs.tl_as_node().node_find_tree_at(x, y, tree); - } - } { let (x_abs, y_abs) = self.global.pos.get().translate_inv(x, y); for stacked in self.state.root.stacked.rev_iter() { @@ -647,23 +675,36 @@ impl Node for OutputNode { } } } - let bar_height = self.state.theme.sizes.title_height.get() + 1; - if y >= bar_height { - y -= bar_height; - let len = tree.len(); - if let Some(ws) = self.workspace.get() { - tree.push(FoundNode { - node: ws.clone(), - x, - y, - }); - ws.node_find_tree_at(x, y, tree); - } - if tree.len() == len { - self.find_layer_surface_at(x, y, &[BOTTOM, BACKGROUND], tree); + let mut fullscreen = None; + if let Some(ws) = self.workspace.get() { + fullscreen = ws.fullscreen.get(); + } + if let Some(fs) = fullscreen { + tree.push(FoundNode { + node: fs.clone().tl_into_node(), + x, + y, + }); + fs.tl_as_node().node_find_tree_at(x, y, tree) + } else { + let bar_height = self.state.theme.sizes.title_height.get() + 1; + if y >= bar_height { + y -= bar_height; + let len = tree.len(); + if let Some(ws) = self.workspace.get() { + tree.push(FoundNode { + node: ws.clone(), + x, + y, + }); + ws.node_find_tree_at(x, y, tree); + } + if tree.len() == len { + self.find_layer_surface_at(x, y, &[BOTTOM, BACKGROUND], tree); + } } + FindTreeResult::AcceptsInput } - FindTreeResult::AcceptsInput } fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, _bounds: Option<&Rect>) { diff --git a/src/tree/stacked.rs b/src/tree/stacked.rs index 8dd7528b..f0f03e52 100644 --- a/src/tree/stacked.rs +++ b/src/tree/stacked.rs @@ -4,7 +4,14 @@ pub trait StackedNode: Node { fn stacked_as_node(&self) -> &dyn Node; fn stacked_into_node(self: Rc) -> Rc; fn stacked_into_dyn(self: Rc) -> Rc; + fn stacked_prepare_set_visible(&self) { + // nothing + } + fn stacked_needs_set_visible(&self) -> bool { + true + } fn stacked_set_visible(&self, visible: bool); + fn stacked_has_workspace_link(&self) -> bool; fn stacked_absolute_position_constrains_input(&self) -> bool { true diff --git a/src/tree/workspace.rs b/src/tree/workspace.rs index 9471576a..472db74c 100644 --- a/src/tree/workspace.rs +++ b/src/tree/workspace.rs @@ -88,7 +88,7 @@ impl WorkspaceNode { let pos = self.position.get(); container.clone().tl_change_extents(&pos); container.tl_set_parent(self.clone()); - container.tl_set_visible(self.stacked_visible()); + container.tl_set_visible(self.container_visible()); self.container.set(Some(container.clone())); } @@ -96,7 +96,7 @@ impl WorkspaceNode { self.stacked.is_empty() && self.fullscreen.is_none() && self.container.is_none() } - pub fn stacked_visible(&self) -> bool { + pub fn container_visible(&self) -> bool { self.visible.get() && self.fullscreen.is_none() } @@ -113,39 +113,37 @@ impl WorkspaceNode { } } - fn plane_set_visible(&self, visible: bool) { - if let Some(container) = self.container.get() { - container.tl_set_visible(visible); - } - for stacked in self.stacked.iter() { - stacked.stacked_set_visible(visible); - } - } - pub fn set_visible(&self, visible: bool) { + self.visible.set(visible); for jw in self.jay_workspaces.lock().values() { jw.send_visible(visible); } - self.visible.set(visible); + for stacked in self.stacked.iter() { + stacked.stacked_prepare_set_visible(); + } if let Some(fs) = self.fullscreen.get() { fs.tl_set_visible(visible); - } else { - self.plane_set_visible(visible); + } + if let Some(container) = self.container.get() { + container.tl_set_visible(self.container_visible()); + } + for stacked in self.stacked.iter() { + if stacked.stacked_needs_set_visible() { + stacked.stacked_set_visible(self.container_visible()); + } } self.seat_state.set_visible(self, visible); } pub fn set_fullscreen_node(&self, node: &Rc) { - let visible = self.visible.get(); - let mut plane_was_visible = visible; if let Some(prev) = self.fullscreen.set(Some(node.clone())) { - plane_was_visible = false; self.discard_child_properties(&*prev); } self.pull_child_properties(&**node); - node.tl_set_visible(visible); - if plane_was_visible { - self.plane_set_visible(false); + if self.visible.get() { + self.output.get().update_visible(); + } else { + node.tl_set_visible(false); } if let Some(surface) = node.tl_scanout_surface() { if let Some(fb) = self.output.get().global.connector.connector.drm_feedback() { @@ -158,7 +156,7 @@ impl WorkspaceNode { if let Some(node) = self.fullscreen.take() { self.discard_child_properties(&*node); if self.visible.get() { - self.plane_set_visible(true); + self.output.get().update_visible(); } if let Some(surface) = node.tl_scanout_surface() { if let Some(fb) = surface.client.state.drm_feedback.get() {