state/lid-inhibit: Take current lid state into account

This commit is contained in:
Victoria Brekenfeld 2025-08-11 16:51:57 +02:00 • committed by Victoria Brekenfeld
parent de43fb1f0e
commit 74e90f793f
4 changed files with 83 additions and 37 deletions

View file

@ -68,7 +68,7 @@ pub struct KmsState {
pub software_renderer: Option<GlowRenderer>, pub software_renderer: Option<GlowRenderer>,
pub api: GpuManager<GbmGlowBackend<DrmDeviceFd>>, pub api: GpuManager<GbmGlowBackend<DrmDeviceFd>>,
session: LibSeatSession, pub session: LibSeatSession,
libinput: Libinput, libinput: Libinput,
pub syncobj_state: Option<DrmSyncobjState>, pub syncobj_state: Option<DrmSyncobjState>,

View file

@ -1,9 +1,10 @@
use std::os::fd::OwnedFd; use std::os::fd::OwnedFd;
use anyhow::{Context, Result};
use logind_zbus::manager::{InhibitType::HandleLidSwitch, ManagerProxyBlocking}; use logind_zbus::manager::{InhibitType::HandleLidSwitch, ManagerProxyBlocking};
use zbus::blocking::Connection; use zbus::blocking::Connection;
pub fn inhibit_lid() -> anyhow::Result<OwnedFd> { pub fn inhibit_lid() -> Result<OwnedFd> {
let conn = Connection::system()?; let conn = Connection::system()?;
let proxy = ManagerProxyBlocking::new(&conn)?; let proxy = ManagerProxyBlocking::new(&conn)?;
let fd = proxy.inhibit( let fd = proxy.inhibit(
@ -15,3 +16,9 @@ pub fn inhibit_lid() -> anyhow::Result<OwnedFd> {
Ok(fd.into()) Ok(fd.into())
} }
pub fn lid_closed() -> Result<bool> {
let conn = Connection::system()?;
let proxy = ManagerProxyBlocking::new(&conn)?;
proxy.lid_closed().context("Failed to talk to logind")
}

View file

@ -7,7 +7,7 @@ use crate::{
cosmic_keystate_from_smithay, cosmic_modifiers_eq_smithay, cosmic_keystate_from_smithay, cosmic_modifiers_eq_smithay,
cosmic_modifiers_from_smithay, cosmic_modifiers_from_smithay,
}, },
Action, Config, OutputConfig, OutputState, PrivateAction, Action, Config, PrivateAction,
}, },
input::gestures::{GestureState, SwipeAction}, input::gestures::{GestureState, SwipeAction},
shell::{ shell::{
@ -1508,37 +1508,19 @@ impl State {
} }
InputEvent::Special(_) => {} InputEvent::Special(_) => {}
InputEvent::SwitchToggle { event } => { InputEvent::SwitchToggle { event } => {
if event.switch() == Some(Switch::Lid) { #[cfg(feature = "systemd")]
let outputs = self.backend.lock().all_outputs(); if event.switch() == Some(Switch::Lid) && self.common.inhibit_lid_fd.is_some() {
if let Some(internal) = outputs.into_iter().find(|o| o.is_internal()) { if event.state() == SwitchState::On {
let config = internal.user_data().get::<RefCell<OutputConfig>>().unwrap(); self.backend
let enabled = config.borrow().enabled.clone(); .lock()
if enabled != OutputState::Disabled && event.state() == SwitchState::On { .disable_internal_output(&mut self.common.output_configuration_state);
config.borrow_mut().enabled = OutputState::Disabled; } else {
self.common self.backend
.output_configuration_state .lock()
.remove_heads(std::iter::once(&internal)); .enable_internal_output(&mut self.common.output_configuration_state);
} else if enabled == OutputState::Disabled
&& event.state() == SwitchState::Off
{
self.common
.output_configuration_state
.add_heads(std::iter::once(&internal));
} else {
return;
}
self.common.config.read_outputs(
&mut self.common.output_configuration_state,
&mut self.backend,
&self.common.shell,
&self.common.event_loop_handle,
&mut self.common.workspace_state.update(),
&self.common.xdg_activation_state,
self.common.startup_done.clone(),
&self.common.clock,
);
} }
self.refresh_output_config();
} }
} }
} }

View file

@ -254,7 +254,7 @@ pub struct Common {
pub atspi_ei: crate::wayland::handlers::atspi::AtspiEiState, pub atspi_ei: crate::wayland::handlers::atspi::AtspiEiState,
#[cfg(feature = "systemd")] #[cfg(feature = "systemd")]
inhibit_lid_fd: Option<OwnedFd>, pub inhibit_lid_fd: Option<OwnedFd>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -408,6 +408,37 @@ impl<'a> LockedBackend<'a> {
} }
} }
pub fn enable_internal_output(
&self,
output_configuration_state: &mut OutputConfigurationState<State>,
) {
let outputs = self.all_outputs();
if let Some(internal) = outputs.iter().find(|o| o.is_internal()) {
let mut config = internal.config_mut();
if config.enabled == OutputState::Disabled {
// If it was previously mirrored, `read_outputs` will restore that correctly.
// But if we don't have a config for *some* reason or reading it fails,
// we don't want to write out `Disabled` accidentally.
config.enabled = OutputState::Enabled;
output_configuration_state.add_heads(std::iter::once(internal));
}
}
}
pub fn disable_internal_output(
&self,
output_configuration_state: &mut OutputConfigurationState<State>,
) {
let outputs = self.all_outputs();
if let Some(internal) = outputs.iter().find(|o| o.is_internal()) {
let mut config = internal.config_mut();
if config.enabled != OutputState::Disabled {
config.enabled = OutputState::Disabled;
output_configuration_state.remove_heads(std::iter::once(internal));
}
}
}
pub fn apply_config_for_outputs( pub fn apply_config_for_outputs(
&mut self, &mut self,
test_only: bool, test_only: bool,
@ -740,10 +771,17 @@ impl State {
fn update_inhibitor_locks(&mut self) { fn update_inhibitor_locks(&mut self) {
#[cfg(feature = "systemd")] #[cfg(feature = "systemd")]
{ {
use smithay::backend::session::Session;
use tracing::{debug, error}; use tracing::{debug, error};
let outputs = self.backend.lock().all_outputs(); let outputs = self.backend.lock().all_outputs();
let should_handle_lid = outputs.iter().any(|o| o.is_internal()) && outputs.len() >= 2; let is_active = match &self.backend {
BackendData::Kms(kms) => kms.session.is_active(),
_ => true,
};
let should_handle_lid =
is_active && outputs.iter().any(|o| o.is_internal()) && outputs.len() >= 2;
if should_handle_lid { if should_handle_lid {
if self.common.inhibit_lid_fd.is_none() { if self.common.inhibit_lid_fd.is_none() {
@ -751,6 +789,18 @@ impl State {
Ok(fd) => { Ok(fd) => {
debug!("Inhibiting lid switch"); debug!("Inhibiting lid switch");
self.common.inhibit_lid_fd = Some(fd); self.common.inhibit_lid_fd = Some(fd);
if crate::dbus::logind::lid_closed().unwrap_or(false) {
self.backend.lock().disable_internal_output(
&mut self.common.output_configuration_state,
);
} else {
self.backend.lock().enable_internal_output(
&mut self.common.output_configuration_state,
);
}
self.refresh_output_config();
} }
Err(err) => { Err(err) => {
error!("Failed to inhibit lid switch: {}", err); error!("Failed to inhibit lid switch: {}", err);
@ -758,8 +808,15 @@ impl State {
} }
} }
} else { } else {
if self.common.inhibit_lid_fd.take().is_some() { if let Some(_fd) = self.common.inhibit_lid_fd.take() {
debug!("Removing inhibitor-lock on lid switch") debug!("Removing inhibitor-lock on lid switch");
self.backend
.lock()
.enable_internal_output(&mut self.common.output_configuration_state);
self.refresh_output_config();
// drop _fd
} }
} }
} }