diff --git a/src/main.rs b/src/main.rs index 7837f4a3..5bc8f3d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ use smithay::reexports::{ use anyhow::{Context, Result}; use slog::Drain; +use std::sync::atomic::Ordering; pub mod backend; pub mod input; @@ -42,12 +43,18 @@ fn main() -> Result<()> { return; } - // trigger routines - state.common.spaces.refresh(); + // do we need to trigger another render + if state.common.dirty_flag.swap(false, Ordering::SeqCst) { + for output in state.common.spaces.outputs() { + state.backend.schedule_render(output) + } + } // send out events let display = state.common.display.clone(); display.borrow_mut().flush_clients(state); + // trigger routines + state.common.spaces.refresh(); })?; Ok(()) diff --git a/src/shell/mod.rs b/src/shell/mod.rs index cb7d242f..e6213b03 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only -use crate::{input::active_output, state::State}; +use crate::{input::active_output, state::State, utils::SurfaceDropNotifier}; use smithay::{ backend::renderer::utils::on_commit_buffer_handler, desktop::{ @@ -342,6 +342,11 @@ fn commit(surface: &WlSurface, state: &mut State) { } let state = &mut state.common; + let _ = with_states(surface, |states| { + states + .data_map + .insert_if_missing(|| SurfaceDropNotifier::from(&*state)); + }); if let Some(toplevel) = state.pending_toplevels.iter().find(|toplevel| { toplevel diff --git a/src/state.rs b/src/state.rs index d7860cdb..3e61435d 100644 --- a/src/state.rs +++ b/src/state.rs @@ -18,7 +18,12 @@ use smithay::{ }, }; -use std::{cell::RefCell, rc::Rc, time::Instant}; +use std::{ + cell::RefCell, + rc::Rc, + sync::{atomic::AtomicBool, Arc}, + time::Instant, +}; #[cfg(feature = "debug")] use std::{collections::VecDeque, time::Duration}; @@ -34,6 +39,7 @@ pub struct Common { pub spaces: Workspaces, pub shell: ShellStates, pub pending_toplevels: Vec, + pub dirty_flag: Arc, pub seats: Vec, pub last_active_seat: Seat, @@ -125,6 +131,7 @@ impl State { spaces: Workspaces::new(), shell: shell_handles, pending_toplevels: Vec::new(), + dirty_flag: Arc::new(AtomicBool::new(false)), seats: vec![initial_seat.clone()], last_active_seat: initial_seat, diff --git a/src/utils.rs b/src/utils.rs index 95541a1b..eeab09b1 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,13 @@ // SPDX-License-Identifier: GPL-3.0-only use smithay::reexports::wayland_server::{Global, Interface, Resource}; -use std::convert::{AsRef, From}; +use std::{ + convert::{AsRef, From}, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, +}; pub struct GlobalDrop> + From>>(Option>); @@ -18,3 +24,20 @@ impl> + From>> Drop for GlobalDrop< } } } + +// This hack will hopefully will be superseeded by a better solution, when smithay transitions to wayland-rs 0.30. +// But until then there is not really a better way to schedule a repaint on surface destruction +#[derive(Debug)] +pub struct SurfaceDropNotifier(Arc); + +impl From<&crate::state::Common> for SurfaceDropNotifier { + fn from(state: &crate::state::Common) -> Self { + SurfaceDropNotifier(state.dirty_flag.clone()) + } +} + +impl Drop for SurfaceDropNotifier { + fn drop(&mut self) { + self.0.store(true, Ordering::SeqCst); + } +}