1
0
Fork 0
forked from wry/wry

tree: make surface visibility tracking more robust

This commit is contained in:
Julian Orth 2024-03-29 20:07:28 +01:00
parent be0935c8dd
commit ba98103233
26 changed files with 313 additions and 144 deletions

View file

@ -196,7 +196,9 @@ impl Backend for MetalBackend {
return; return;
} }
} }
if !idle { if idle {
self.state.set_backend_idle(true);
} else {
for device in devices.values() { for device in devices.values() {
for connector in device.connectors.lock().values() { for connector in device.connectors.lock().values() {
connector.schedule_present(); connector.schedule_present();

View file

@ -389,8 +389,11 @@ impl MetalConnector {
async fn present_loop(self: Rc<Self>) { async fn present_loop(self: Rc<Self>) {
loop { loop {
self.present_trigger.triggered().await; self.present_trigger.triggered().await;
if let Err(e) = self.present(true) { match self.present(true) {
log::error!("Could not present: {}", ErrorFmt(e)); Ok(_) => self.state.set_backend_idle(false),
Err(e) => {
log::error!("Could not present: {}", ErrorFmt(e));
}
} }
} }
} }

View file

@ -772,6 +772,8 @@ impl XBackend {
log::error!("Could not present image: {:?}", e); log::error!("Could not present image: {:?}", e);
return; return;
} }
self.state.set_backend_idle(false);
} }
async fn handle_input_event(self: &Rc<Self>, event: &Event) -> Result<(), XBackendError> { async fn handle_input_event(self: &Rc<Self>, event: &Event) -> Result<(), XBackendError> {

View file

@ -184,6 +184,7 @@ fn start_compositor2(
timeout_changed: Default::default(), timeout_changed: Default::default(),
inhibitors: Default::default(), inhibitors: Default::default(),
inhibitors_changed: Default::default(), inhibitors_changed: Default::default(),
backend_idle: Cell::new(true),
}, },
run_args, run_args,
xwayland: XWaylandState { xwayland: XWaylandState {

View file

@ -69,6 +69,10 @@ pub trait Cursor {
fn time_until_tick(&self) -> Duration { fn time_until_tick(&self) -> Duration {
Duration::new(0, 0) Duration::new(0, 0)
} }
fn set_visible(&self, visible: bool) {
let _ = visible;
}
} }
pub struct ServerCursors { pub struct ServerCursors {

View file

@ -66,7 +66,7 @@ impl ExtSessionLockV1 {
if node.lock_surface.is_some() { if node.lock_surface.is_some() {
return Err(ExtSessionLockV1Error::OutputAlreadyLocked); return Err(ExtSessionLockV1Error::OutputAlreadyLocked);
} }
node.lock_surface.set(Some(new.clone())); node.set_lock_surface(Some(new.clone()));
let pos = output.global.pos.get(); let pos = output.global.pos.get();
new.change_extents(pos); new.change_extents(pos);
self.client.state.tree_changed(); self.client.state.tree_changed();
@ -85,7 +85,7 @@ impl ExtSessionLockV1 {
state.lock.locked.set(false); state.lock.locked.set(false);
state.lock.lock.take(); state.lock.lock.take();
for output in state.outputs.lock().values() { 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(); surface.destroy_node();
} }
} }

View file

@ -190,7 +190,7 @@ impl JayCompositor {
lock.finish(); lock.finish();
} }
for output in state.outputs.lock().values() { 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(); surface.destroy_node();
} }
} }

View file

@ -981,6 +981,20 @@ impl WlSeatGlobal {
pub fn last_input(&self) -> u64 { pub fn last_input(&self) -> u64 {
self.last_input_usec.get() 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); global_base!(WlSeatGlobal, WlSeat, WlSeatError);

View file

@ -368,7 +368,7 @@ impl PointerOwner for GrabPointerOwner {
return Ok(()); return Ok(());
} }
if let Some(icon) = &icon { 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 { if let Some(new) = &src {
ipc::attach_seat::<ClipboardIpc>(new, seat, ipc::Role::Dnd)?; ipc::attach_seat::<ClipboardIpc>(new, seat, ipc::Role::Dnd)?;
@ -460,7 +460,7 @@ impl PointerOwner for DndPointerOwner {
} }
} }
if let Some(icon) = self.icon.get() { 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.pointer_owner.set_default_pointer_owner(seat);
seat.tree_changed.trigger(); seat.tree_changed.trigger();
@ -530,7 +530,7 @@ impl PointerOwner for DndPointerOwner {
ipc::detach_seat::<ClipboardIpc>(src, seat); ipc::detach_seat::<ClipboardIpc>(src, seat);
} }
if let Some(icon) = self.icon.get() { 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.pointer_owner.set_default_pointer_owner(seat);
seat.tree_changed.trigger(); seat.tree_changed.trigger();

View file

@ -234,7 +234,7 @@ pub struct WlSurface {
seat_state: NodeSeatState, seat_state: NodeSeatState,
toplevel: CloneCell<Option<Rc<dyn ToplevelNode>>>, toplevel: CloneCell<Option<Rc<dyn ToplevelNode>>>,
cursors: SmallMap<SeatId, Rc<CursorSurface>, 1>, cursors: SmallMap<SeatId, Rc<CursorSurface>, 1>,
pub dnd_icons: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>, dnd_icons: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
pub tracker: Tracker<Self>, pub tracker: Tracker<Self>,
idle_inhibitors: SmallMap<ZwpIdleInhibitorV1Id, Rc<ZwpIdleInhibitorV1>, 1>, idle_inhibitors: SmallMap<ZwpIdleInhibitorV1Id, Rc<ZwpIdleInhibitorV1>, 1>,
viewporter: CloneCell<Option<Rc<WpViewport>>>, viewporter: CloneCell<Option<Rc<WpViewport>>>,
@ -489,7 +489,7 @@ impl WlSurface {
id, id,
node_id: client.state.node_ids.next(), node_id: client.state.node_ids.next(),
client: client.clone(), client: client.clone(),
visible: Default::default(), visible: Cell::new(false),
role: Cell::new(SurfaceRole::None), role: Cell::new(SurfaceRole::None),
pending: Default::default(), pending: Default::default(),
input_region: Default::default(), input_region: Default::default(),
@ -1184,7 +1184,9 @@ impl WlSurface {
} }
pub fn set_visible(&self, visible: bool) { pub fn set_visible(&self, visible: bool) {
self.visible.set(visible); if self.visible.replace(visible) == visible {
return;
}
for (_, inhibitor) in &self.idle_inhibitors { for (_, inhibitor) in &self.idle_inhibitors {
if visible { if visible {
inhibitor.activate(); inhibitor.activate();
@ -1204,11 +1206,7 @@ impl WlSurface {
self.seat_state.set_visible(self, visible); self.seat_state.set_visible(self, visible);
} }
pub fn detach_node(&self) { pub fn detach_node(&self, set_invisible: bool) {
self.destroy_node();
}
pub fn destroy_node(&self) {
for (_, constraint) in &self.constraints { for (_, constraint) in &self.constraints {
constraint.deactivate(); constraint.deactivate();
} }
@ -1218,7 +1216,7 @@ impl WlSurface {
let children = self.children.borrow(); let children = self.children.borrow();
if let Some(ch) = children.deref() { if let Some(ch) = children.deref() {
for ss in ch.subsurfaces.values() { for ss in ch.subsurfaces.values() {
ss.surface.destroy_node(); ss.surface.detach_node(set_invisible);
} }
} }
if let Some(tl) = self.toplevel.get() { if let Some(tl) = self.toplevel.get() {
@ -1238,6 +1236,13 @@ impl WlSurface {
if self.visible.get() { if self.visible.get() {
self.client.state.damage(); 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<ContentType>) { pub fn set_content_type(&self, content_type: Option<ContentType>) {
@ -1267,6 +1272,18 @@ impl WlSurface {
.get() .get()
.consume_pending_child(self, child, &mut consume) .consume_pending_child(self, child, &mut consume)
} }
pub fn set_dnd_icon_seat(&self, id: SeatId, seat: Option<&Rc<WlSeatGlobal>>) {
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! { object_base! {

View file

@ -125,9 +125,20 @@ impl Cursor for CursorSurface {
fn handle_set(self: Rc<Self>) { fn handle_set(self: Rc<Self>) {
self.surface.cursors.insert(self.seat.id(), self.clone()); 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) { fn handle_unset(&self) {
self.surface.cursors.remove(&self.seat.id()); 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);
} }
} }

View file

@ -74,7 +74,7 @@ impl ExtSessionLockSurfaceV1 {
if let Some(output) = &self.output { if let Some(output) = &self.output {
if let Some(ls) = output.lock_surface.get() { if let Some(ls) = output.lock_surface.get() {
if ls.node_id == self.node_id { if ls.node_id == self.node_id {
output.lock_surface.take(); output.set_lock_surface(None);
self.client.state.tree_changed(); self.client.state.tree_changed();
} }
} }

View file

@ -46,6 +46,7 @@ pub struct WlSubsurface {
latest_node: CloneCell<Option<NodeRef<StackElement>>>, latest_node: CloneCell<Option<NodeRef<StackElement>>>,
depth: NumCell<u32>, depth: NumCell<u32>,
pub tracker: Tracker<Self>, pub tracker: Tracker<Self>,
had_buffer: Cell<bool>,
} }
#[derive(Default)] #[derive(Default)]
@ -102,6 +103,7 @@ impl WlSubsurface {
latest_node: Default::default(), latest_node: Default::default(),
depth: NumCell::new(0), depth: NumCell::new(0),
tracker: Default::default(), tracker: Default::default(),
had_buffer: Cell::new(false),
} }
} }
@ -178,6 +180,7 @@ impl WlSubsurface {
} }
} }
self.surface.client.remove_obj(self)?; self.surface.client.remove_obj(self)?;
self.surface.destroy_node();
Ok(()) Ok(())
} }
@ -344,6 +347,16 @@ impl SurfaceExt for WlSubsurface {
self.parent.need_extents_update.set(true); 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<Rc<WlSurface>> { fn subsurface_parent(&self) -> Option<Rc<WlSurface>> {

View file

@ -436,6 +436,10 @@ impl StackedNode for Xwindow {
fn stacked_set_visible(&self, visible: bool) { fn stacked_set_visible(&self, visible: bool) {
self.tl_set_visible(visible); self.tl_set_visible(visible);
} }
fn stacked_has_workspace_link(&self) -> bool {
false
}
} }
#[derive(Debug, Error)] #[derive(Debug, Error)]

View file

@ -183,7 +183,7 @@ impl XdgSurface {
fn detach_node(&self) { fn detach_node(&self) {
self.workspace.set(None); self.workspace.set(None);
self.surface.detach_node(); self.surface.detach_node(false);
let popups = self.popups.lock(); let popups = self.popups.lock();
for popup in popups.values() { for popup in popups.values() {
popup.detach_node(); popup.detach_node();

View file

@ -47,6 +47,7 @@ pub struct XdgPopup {
pos: RefCell<XdgPositioned>, pos: RefCell<XdgPositioned>,
pub tracker: Tracker<Self>, pub tracker: Tracker<Self>,
seat_state: NodeSeatState, seat_state: NodeSeatState,
set_visible_prepared: Cell<bool>,
} }
impl Debug for XdgPopup { impl Debug for XdgPopup {
@ -77,6 +78,7 @@ impl XdgPopup {
pos: RefCell::new(pos), pos: RefCell::new(pos),
tracker: Default::default(), tracker: Default::default(),
seat_state: 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) { pub fn set_visible(&self, visible: bool) {
// log::info!("set visible = {}", visible); // log::info!("set visible = {}", visible);
self.set_visible_prepared.set(false);
self.xdg.set_visible(visible); self.xdg.set_visible(visible);
self.seat_state.set_visible(self, visible); self.seat_state.set_visible(self, visible);
} }
@ -340,8 +343,20 @@ impl Node for XdgPopup {
impl StackedNode for XdgPopup { impl StackedNode for XdgPopup {
stacked_node_impl!(); 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) { 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 { fn stacked_absolute_position_constrains_input(&self) -> bool {

View file

@ -389,6 +389,7 @@ impl XdgToplevel {
} }
self.toplevel_data.detach_node(self); self.toplevel_data.detach_node(self);
self.xdg.detach_node(); self.xdg.detach_node();
self.tl_set_visible(self.state.root_visible());
} }
pub fn after_toplevel_drag(self: &Rc<Self>, output: &Rc<OutputNode>, x: i32, y: i32) { pub fn after_toplevel_drag(self: &Rc<Self>, output: &Rc<OutputNode>, x: i32, y: i32) {

View file

@ -351,6 +351,7 @@ impl SurfaceExt for ZwlrLayerSurfaceV1 {
fn after_apply_commit(self: Rc<Self>, _pending: &mut PendingState) { fn after_apply_commit(self: Rc<Self>, _pending: &mut PendingState) {
let buffer_is_some = self.surface.buffer.is_some(); let buffer_is_some = self.surface.buffer.is_some();
let was_mapped = self.mapped.get();
if self.mapped.get() { if self.mapped.get() {
if !buffer_is_some { if !buffer_is_some {
self.destroy_node(); self.destroy_node();
@ -367,6 +368,9 @@ impl SurfaceExt for ZwlrLayerSurfaceV1 {
self.mapped.set(true); self.mapped.set(true);
self.compute_position(); self.compute_position();
} }
if self.mapped.get() != was_mapped {
self.output.update_visible();
}
if self.mapped.get() { if self.mapped.get() {
match self.keyboard_interactivity.get() { match self.keyboard_interactivity.get() {
KI_NONE => { KI_NONE => {

View file

@ -47,6 +47,7 @@ pub struct TestBackend {
impl TestBackend { impl TestBackend {
pub fn new(state: &Rc<State>, future: TestFuture) -> Self { pub fn new(state: &Rc<State>, future: TestFuture) -> Self {
state.set_backend_idle(false);
let default_connector = Rc::new(TestConnector { let default_connector = Rc::new(TestConnector {
id: state.connector_ids.next(), id: state.connector_ids.next(),
kernel_id: ConnectorKernelId { kernel_id: ConnectorKernelId {

View file

@ -104,84 +104,84 @@ impl Renderer<'_> {
} }
}; };
} }
let mut fullscreen = None;
if let Some(ws) = output.workspace.get() { if let Some(ws) = output.workspace.get() {
if let Some(fs) = ws.fullscreen.get() { fullscreen = ws.fullscreen.get();
fs.tl_as_node().node_render(self, x, y, None);
render_layer!(output.layers[2]);
render_layer!(output.layers[3]);
return;
}
} }
render_layer!(output.layers[0]); if let Some(fs) = fullscreen {
render_layer!(output.layers[1]); fs.tl_as_node().node_render(self, x, y, None);
let theme = &self.state.theme; } else {
let th = theme.sizes.title_height.get(); render_layer!(output.layers[0]);
{ render_layer!(output.layers[1]);
let c = theme.colors.bar_background.get(); let theme = &self.state.theme;
self.base.fill_boxes2( let th = theme.sizes.title_height.get();
slice::from_ref(&Rect::new_sized(0, 0, opos.width(), th).unwrap()), {
&c, let c = theme.colors.bar_background.get();
x, self.base.fill_boxes2(
y, slice::from_ref(&Rect::new_sized(0, 0, opos.width(), th).unwrap()),
); &c,
let has_captures = x,
!output.screencasts.is_empty() || !output.global.pending_captures.is_empty(); y,
let rd = output.render_data.borrow_mut(); );
if let Some(aw) = &rd.active_workspace { let has_captures =
let c = match has_captures && aw.captured { !output.screencasts.is_empty() || !output.global.pending_captures.is_empty();
true => theme.colors.captured_focused_title_background.get(), let rd = output.render_data.borrow_mut();
false => theme.colors.focused_title_background.get(), 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(slice::from_ref(&aw.rect), &c, x, y); 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,
);
}
} }
let c = theme.colors.separator.get(); if let Some(ws) = output.workspace.get() {
self.base self.render_workspace(&ws, x, y + th + 1);
.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(ws) = output.workspace.get() {
self.render_workspace(&ws, x, y + th + 1);
} }
for stacked in self.state.root.stacked.iter() { for stacked in self.state.root.stacked.iter() {
if stacked.node_visible() { if stacked.node_visible() {

View file

@ -205,6 +205,7 @@ pub struct IdleState {
pub timeout_changed: Cell<bool>, pub timeout_changed: Cell<bool>,
pub inhibitors: CopyHashMap<IdleInhibitorId, Rc<ZwpIdleInhibitorV1>>, pub inhibitors: CopyHashMap<IdleInhibitorId, Rc<ZwpIdleInhibitorV1>>,
pub inhibitors_changed: Cell<bool>, pub inhibitors_changed: Cell<bool>,
pub backend_idle: Cell<bool>,
} }
impl IdleState { impl IdleState {
@ -960,6 +961,16 @@ impl State {
log::error!("Could not signal sync obj: {}", ErrorFmt(e)); 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)] #[derive(Debug, Error)]

View file

@ -5,6 +5,7 @@ use {
ifs::wl_seat::{NodeSeatState, WlSeatGlobal}, ifs::wl_seat::{NodeSeatState, WlSeatGlobal},
rect::Rect, rect::Rect,
renderer::Renderer, renderer::Renderer,
state::State,
tree::{ tree::{
walker::NodeVisitor, FindTreeResult, FoundNode, Node, NodeId, OutputNode, StackedNode, walker::NodeVisitor, FindTreeResult, FoundNode, Node, NodeId, OutputNode, StackedNode,
}, },
@ -60,6 +61,21 @@ impl DisplayNode {
} }
self.extents.set(Rect::new(x1, y1, x2, y2).unwrap()); 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 { impl Node for DisplayNode {

View file

@ -101,7 +101,7 @@ impl FloatNode {
let floater = Rc::new(FloatNode { let floater = Rc::new(FloatNode {
id: state.node_ids.next(), id: state.node_ids.next(),
state: state.clone(), state: state.clone(),
visible: Cell::new(ws.stacked_visible()), visible: Cell::new(ws.container_visible()),
position: Cell::new(position), position: Cell::new(position),
display_link: RefCell::new(None), display_link: RefCell::new(None),
workspace_link: Cell::new(None), workspace_link: Cell::new(None),
@ -346,7 +346,7 @@ impl FloatNode {
self.workspace_link self.workspace_link
.set(Some(ws.stacked.add_last(self.clone()))); .set(Some(ws.stacked.add_last(self.clone())));
self.workspace.set(ws.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<Self>, title: &str) { fn update_child_title(self: &Rc<Self>, title: &str) {
@ -625,4 +625,8 @@ impl StackedNode for FloatNode {
} }
self.seat_state.set_visible(self, visible); self.seat_state.set_visible(self, visible);
} }
fn stacked_has_workspace_link(&self) -> bool {
true
}
} }

View file

@ -317,7 +317,7 @@ impl OutputNode {
old.flush_jay_workspaces(); old.flush_jay_workspaces();
} }
} }
ws.set_visible(true); self.update_visible();
if let Some(fs) = ws.fullscreen.get() { if let Some(fs) = ws.fullscreen.get() {
fs.tl_change_extents(&self.global.pos.get()); fs.tl_change_extents(&self.global.pos.get());
} }
@ -502,6 +502,44 @@ impl OutputNode {
.map(|w| w.fullscreen.is_some()) .map(|w| w.fullscreen.is_some())
.unwrap_or(false) .unwrap_or(false)
} }
pub fn set_lock_surface(
&self,
surface: Option<Rc<ExtSessionLockSurfaceV1>>,
) -> Option<Rc<ExtSessionLockSurfaceV1>> {
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 { pub struct OutputTitle {
@ -607,16 +645,6 @@ impl Node for OutputNode {
return res; 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); let (x_abs, y_abs) = self.global.pos.get().translate_inv(x, y);
for stacked in self.state.root.stacked.rev_iter() { 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; let mut fullscreen = None;
if y >= bar_height { if let Some(ws) = self.workspace.get() {
y -= bar_height; fullscreen = ws.fullscreen.get();
let len = tree.len(); }
if let Some(ws) = self.workspace.get() { if let Some(fs) = fullscreen {
tree.push(FoundNode { tree.push(FoundNode {
node: ws.clone(), node: fs.clone().tl_into_node(),
x, x,
y, y,
}); });
ws.node_find_tree_at(x, y, tree); fs.tl_as_node().node_find_tree_at(x, y, tree)
} } else {
if tree.len() == len { let bar_height = self.state.theme.sizes.title_height.get() + 1;
self.find_layer_surface_at(x, y, &[BOTTOM, BACKGROUND], tree); 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>) { fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, _bounds: Option<&Rect>) {

View file

@ -4,7 +4,14 @@ pub trait StackedNode: Node {
fn stacked_as_node(&self) -> &dyn Node; fn stacked_as_node(&self) -> &dyn Node;
fn stacked_into_node(self: Rc<Self>) -> Rc<dyn Node>; fn stacked_into_node(self: Rc<Self>) -> Rc<dyn Node>;
fn stacked_into_dyn(self: Rc<Self>) -> Rc<dyn StackedNode>; fn stacked_into_dyn(self: Rc<Self>) -> Rc<dyn StackedNode>;
fn stacked_prepare_set_visible(&self) {
// nothing
}
fn stacked_needs_set_visible(&self) -> bool {
true
}
fn stacked_set_visible(&self, visible: bool); fn stacked_set_visible(&self, visible: bool);
fn stacked_has_workspace_link(&self) -> bool;
fn stacked_absolute_position_constrains_input(&self) -> bool { fn stacked_absolute_position_constrains_input(&self) -> bool {
true true

View file

@ -88,7 +88,7 @@ impl WorkspaceNode {
let pos = self.position.get(); let pos = self.position.get();
container.clone().tl_change_extents(&pos); container.clone().tl_change_extents(&pos);
container.tl_set_parent(self.clone()); 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())); self.container.set(Some(container.clone()));
} }
@ -96,7 +96,7 @@ impl WorkspaceNode {
self.stacked.is_empty() && self.fullscreen.is_none() && self.container.is_none() 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() 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) { pub fn set_visible(&self, visible: bool) {
self.visible.set(visible);
for jw in self.jay_workspaces.lock().values() { for jw in self.jay_workspaces.lock().values() {
jw.send_visible(visible); 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() { if let Some(fs) = self.fullscreen.get() {
fs.tl_set_visible(visible); 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); self.seat_state.set_visible(self, visible);
} }
pub fn set_fullscreen_node(&self, node: &Rc<dyn ToplevelNode>) { pub fn set_fullscreen_node(&self, node: &Rc<dyn ToplevelNode>) {
let visible = self.visible.get();
let mut plane_was_visible = visible;
if let Some(prev) = self.fullscreen.set(Some(node.clone())) { if let Some(prev) = self.fullscreen.set(Some(node.clone())) {
plane_was_visible = false;
self.discard_child_properties(&*prev); self.discard_child_properties(&*prev);
} }
self.pull_child_properties(&**node); self.pull_child_properties(&**node);
node.tl_set_visible(visible); if self.visible.get() {
if plane_was_visible { self.output.get().update_visible();
self.plane_set_visible(false); } else {
node.tl_set_visible(false);
} }
if let Some(surface) = node.tl_scanout_surface() { if let Some(surface) = node.tl_scanout_surface() {
if let Some(fb) = self.output.get().global.connector.connector.drm_feedback() { 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() { if let Some(node) = self.fullscreen.take() {
self.discard_child_properties(&*node); self.discard_child_properties(&*node);
if self.visible.get() { 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(surface) = node.tl_scanout_surface() {
if let Some(fb) = surface.client.state.drm_feedback.get() { if let Some(fb) = surface.client.state.drm_feedback.get() {