Merge pull request #140 from mahkoh/jorth/surface-visibility
tree: make surface visibility tracking more robust
This commit is contained in:
commit
00efe7b51b
28 changed files with 345 additions and 152 deletions
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -389,8 +389,11 @@ impl MetalConnector {
|
|||
async fn present_loop(self: Rc<Self>) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Self>, event: &Event) -> Result<(), XBackendError> {
|
||||
|
|
|
|||
12
src/bugs.rs
12
src/bugs.rs
|
|
@ -6,6 +6,14 @@ static BUGS: Lazy<AHashMap<&'static str, Bugs>> = Lazy::new(|| {
|
|||
"chromium",
|
||||
Bugs {
|
||||
respect_min_max_size: true,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
map.insert(
|
||||
"Alacritty",
|
||||
Bugs {
|
||||
min_size: Some((100, 100)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
map
|
||||
|
|
@ -17,9 +25,11 @@ pub fn get(app_id: &str) -> &'static Bugs {
|
|||
|
||||
pub static NONE: Bugs = Bugs {
|
||||
respect_min_max_size: false,
|
||||
min_size: None,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Bugs {
|
||||
pub respect_min_max_size: bool,
|
||||
pub min_size: Option<(i32, i32)>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ pub trait Cursor {
|
|||
fn set_output(&self, output: &Rc<OutputNode>) {
|
||||
let _ = output;
|
||||
}
|
||||
fn handle_set(self: Rc<Self>) {}
|
||||
fn handle_unset(&self) {}
|
||||
fn tick(&self) {}
|
||||
fn needs_tick(&self) -> bool {
|
||||
|
|
@ -68,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 {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -879,6 +879,7 @@ impl WlSeatGlobal {
|
|||
old.handle_unset();
|
||||
}
|
||||
if let Some(cursor) = cursor.as_ref() {
|
||||
cursor.clone().handle_set();
|
||||
cursor.set_output(&self.output.get());
|
||||
}
|
||||
self.cursor.set(cursor.clone());
|
||||
|
|
@ -980,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);
|
||||
|
|
|
|||
|
|
@ -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::<ClipboardIpc>(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::<ClipboardIpc>(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();
|
||||
|
|
|
|||
|
|
@ -234,9 +234,9 @@ pub struct WlSurface {
|
|||
seat_state: NodeSeatState,
|
||||
toplevel: CloneCell<Option<Rc<dyn ToplevelNode>>>,
|
||||
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>,
|
||||
idle_inhibitors: CopyHashMap<ZwpIdleInhibitorV1Id, Rc<ZwpIdleInhibitorV1>>,
|
||||
idle_inhibitors: SmallMap<ZwpIdleInhibitorV1Id, Rc<ZwpIdleInhibitorV1>, 1>,
|
||||
viewporter: CloneCell<Option<Rc<WpViewport>>>,
|
||||
output: CloneCell<Rc<OutputNode>>,
|
||||
fractional_scale: CloneCell<Option<Rc<WpFractionalScaleV1>>>,
|
||||
|
|
@ -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(),
|
||||
|
|
@ -620,7 +620,6 @@ impl WlSurface {
|
|||
let cursor = Rc::new(CursorSurface::new(seat, self));
|
||||
track!(self.client, cursor);
|
||||
cursor.handle_buffer_change();
|
||||
self.cursors.insert(seat.id(), cursor.clone());
|
||||
Ok(cursor)
|
||||
}
|
||||
|
||||
|
|
@ -1185,8 +1184,10 @@ impl WlSurface {
|
|||
}
|
||||
|
||||
pub fn set_visible(&self, visible: bool) {
|
||||
self.visible.set(visible);
|
||||
for inhibitor in self.idle_inhibitors.lock().values() {
|
||||
if self.visible.replace(visible) == visible {
|
||||
return;
|
||||
}
|
||||
for (_, inhibitor) in &self.idle_inhibitors {
|
||||
if visible {
|
||||
inhibitor.activate();
|
||||
} else {
|
||||
|
|
@ -1205,21 +1206,17 @@ 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();
|
||||
}
|
||||
for (_, inhibitor) in self.idle_inhibitors.lock().drain() {
|
||||
for (_, inhibitor) in &self.idle_inhibitors {
|
||||
inhibitor.deactivate();
|
||||
}
|
||||
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() {
|
||||
|
|
@ -1239,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<ContentType>) {
|
||||
|
|
@ -1268,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<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! {
|
||||
|
|
|
|||
|
|
@ -123,7 +123,22 @@ impl Cursor for CursorSurface {
|
|||
self.surface.set_output(output);
|
||||
}
|
||||
|
||||
fn handle_set(self: Rc<Self>) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ pub struct WlSubsurface {
|
|||
latest_node: CloneCell<Option<NodeRef<StackElement>>>,
|
||||
depth: NumCell<u32>,
|
||||
pub tracker: Tracker<Self>,
|
||||
had_buffer: Cell<bool>,
|
||||
}
|
||||
|
||||
#[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<Rc<WlSurface>> {
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ pub struct XdgPopup {
|
|||
pos: RefCell<XdgPositioned>,
|
||||
pub tracker: Tracker<Self>,
|
||||
seat_state: NodeSeatState,
|
||||
set_visible_prepared: Cell<bool>,
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -156,7 +156,12 @@ impl XdgToplevel {
|
|||
fn send_configure_checked(&self, mut width: i32, mut height: i32) {
|
||||
width = width.max(1);
|
||||
height = height.max(1);
|
||||
if self.bugs.get().respect_min_max_size {
|
||||
let bugs = self.bugs.get();
|
||||
if let Some((mw, mh)) = bugs.min_size {
|
||||
width = width.max(mw);
|
||||
height = height.max(mh);
|
||||
}
|
||||
if bugs.respect_min_max_size {
|
||||
if let Some(min) = self.min_width.get() {
|
||||
width = width.max(min);
|
||||
}
|
||||
|
|
@ -384,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<Self>, output: &Rc<OutputNode>, x: i32, y: i32) {
|
||||
|
|
@ -647,7 +653,11 @@ impl ToplevelNodeBase for XdgToplevel {
|
|||
impl XdgSurfaceExt for XdgToplevel {
|
||||
fn initial_configure(self: Rc<Self>) -> Result<(), XdgSurfaceError> {
|
||||
let rect = self.xdg.absolute_desired_extents.get();
|
||||
self.send_configure(rect.width(), rect.height());
|
||||
if rect.is_empty() {
|
||||
self.send_configure(0, 0);
|
||||
} else {
|
||||
self.send_configure_checked(rect.width(), rect.height());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -351,6 +351,7 @@ impl SurfaceExt for ZwlrLayerSurfaceV1 {
|
|||
|
||||
fn after_apply_commit(self: Rc<Self>, _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 => {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ impl ZwpIdleInhibitorV1 {
|
|||
}
|
||||
|
||||
pub fn install(self: &Rc<Self>) -> Result<(), ZwpIdleInhibitorV1Error> {
|
||||
self.surface.idle_inhibitors.set(self.id, self.clone());
|
||||
self.surface.idle_inhibitors.insert(self.id, self.clone());
|
||||
if self.surface.visible.get() {
|
||||
self.activate();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ pub struct TestBackend {
|
|||
|
||||
impl TestBackend {
|
||||
pub fn new(state: &Rc<State>, future: TestFuture) -> Self {
|
||||
state.set_backend_idle(false);
|
||||
let default_connector = Rc::new(TestConnector {
|
||||
id: state.connector_ids.next(),
|
||||
kernel_id: ConnectorKernelId {
|
||||
|
|
|
|||
146
src/renderer.rs
146
src/renderer.rs
|
|
@ -104,84 +104,84 @@ 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(),
|
||||
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,
|
||||
);
|
||||
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(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();
|
||||
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(ws) = output.workspace.get() {
|
||||
self.render_workspace(&ws, x, y + th + 1);
|
||||
}
|
||||
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() {
|
||||
if stacked.node_visible() {
|
||||
|
|
|
|||
11
src/state.rs
11
src/state.rs
|
|
@ -205,6 +205,7 @@ pub struct IdleState {
|
|||
pub timeout_changed: Cell<bool>,
|
||||
pub inhibitors: CopyHashMap<IdleInhibitorId, Rc<ZwpIdleInhibitorV1>>,
|
||||
pub inhibitors_changed: Cell<bool>,
|
||||
pub backend_idle: Cell<bool>,
|
||||
}
|
||||
|
||||
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)]
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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<Self>, 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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<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 {
|
||||
|
|
@ -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>) {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,14 @@ pub trait StackedNode: Node {
|
|||
fn stacked_as_node(&self) -> &dyn Node;
|
||||
fn stacked_into_node(self: Rc<Self>) -> Rc<dyn Node>;
|
||||
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_has_workspace_link(&self) -> bool;
|
||||
|
||||
fn stacked_absolute_position_constrains_input(&self) -> bool {
|
||||
true
|
||||
|
|
|
|||
|
|
@ -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<dyn ToplevelNode>) {
|
||||
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() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue