Merge pull request #105 from pinnacle-comp/overlay_plane

Clear drm overlay planes on tty switch
This commit is contained in:
Ottatop 2023-10-17 23:39:59 -05:00 committed by GitHub
commit 5b026b63f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 88 additions and 9 deletions

View file

@ -66,6 +66,14 @@ impl Backend {
pub fn is_winit(&self) -> bool {
matches!(self, Self::Winit(..))
}
/// Returns `true` if the backend is [`Udev`].
///
/// [`Udev`]: Backend::Udev
#[must_use]
pub fn is_udev(&self) -> bool {
matches!(self, Self::Udev(..))
}
}
/// A trait defining common methods for each available backend: winit and tty-udev

View file

@ -161,6 +161,61 @@ impl Udev {
}
}
impl State {
/// Switch the tty.
///
/// This will first clear the overlay plane to prevent any lingering artifacts,
/// then switch the vt.
///
/// Yells at you when called on the winit backend. Bad developer. Very bad.
pub fn switch_vt(&mut self, vt: i32) {
match &mut self.backend {
Backend::Winit(_) => tracing::error!("Called `switch_vt` on winit"),
Backend::Udev(udev) => {
for backend in udev.backends.values_mut() {
for surface in backend.surfaces.values_mut() {
// Clear the overlay planes on tty switch.
//
// On my machine, switching a tty would leave the topmost window on the
// screen. Smithay will render the topmost window on the overlay plane,
// so we clear it here.
let planes = surface.compositor.surface().planes().clone();
tracing::debug!("Clearing overlay planes");
for overlay_plane in planes.overlay {
if let Err(err) = surface
.compositor
.surface()
.clear_plane(overlay_plane.handle)
{
tracing::warn!("Failed to clear overlay planes: {err}");
}
}
}
}
// Wait for the clear to commit before switching
self.schedule(
|data| {
let udev = data.state.backend.udev();
!udev
.backends
.values()
.flat_map(|backend| backend.surfaces.values())
.map(|surface| surface.compositor.surface())
.any(|drm_surf| drm_surf.commit_pending())
},
move |data| {
let udev = data.state.backend.udev_mut();
if let Err(err) = udev.session.change_vt(vt) {
tracing::error!("Failed to switch to vt {vt}: {err}");
}
},
);
}
}
}
}
impl BackendData for Udev {
fn seat_name(&self) -> String {
self.session.seat()
@ -334,12 +389,29 @@ pub fn run_udev() -> anyhow::Result<()> {
}
}
for output in data.state.space.outputs().cloned().collect::<Vec<_>>() {
data.state.schedule_render(&output);
// data.state
// .loop_handle
// .insert_idle(move |data| data.state.render_surface(&output));
let connectors = udev
.backends
.iter()
.map(|(node, backend)| {
let connectors = backend
.drm_scanner
.crtcs()
.map(|(info, crtc)| (info.clone(), crtc))
.collect::<Vec<_>>();
(*node, connectors)
})
.collect::<Vec<_>>();
for (node, connectors) in connectors {
for (connector, crtc) in connectors {
data.state
.connector_disconnected(node, connector.clone(), crtc);
data.state.connector_connected(node, connector, crtc);
}
}
// for output in data.state.space.outputs().cloned().collect::<Vec<_>>() {
// data.state.schedule_render(&output);
// }
}
}
})
@ -562,6 +634,7 @@ struct DrmSurfaceDmabufFeedback {
enum RenderState {
/// No render is scheduled.
Idle,
// TODO: remove the token on tty switch or output unplug
/// A render has been queued.
Scheduled(
/// The idle token from a render being scheduled.

View file

@ -375,10 +375,8 @@ impl State {
}
}
Some(KeyAction::SwitchVt(vt)) => {
if let Backend::Udev(udev) = &mut self.backend {
if let Err(err) = udev.session.change_vt(vt) {
tracing::error!("Failed to switch to vt {vt}: {err}");
}
if self.backend.is_udev() {
self.switch_vt(vt);
}
}
Some(KeyAction::Quit) => {