diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index fce6088f..946f19aa 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -68,7 +68,7 @@ pub struct KmsState { pub software_renderer: Option, pub api: GpuManager>, - session: LibSeatSession, + pub session: LibSeatSession, libinput: Libinput, pub syncobj_state: Option, diff --git a/src/dbus/logind.rs b/src/dbus/logind.rs index 75ee9d8d..b0c59170 100644 --- a/src/dbus/logind.rs +++ b/src/dbus/logind.rs @@ -1,9 +1,10 @@ use std::os::fd::OwnedFd; +use anyhow::{Context, Result}; use logind_zbus::manager::{InhibitType::HandleLidSwitch, ManagerProxyBlocking}; use zbus::blocking::Connection; -pub fn inhibit_lid() -> anyhow::Result { +pub fn inhibit_lid() -> Result { let conn = Connection::system()?; let proxy = ManagerProxyBlocking::new(&conn)?; let fd = proxy.inhibit( @@ -15,3 +16,9 @@ pub fn inhibit_lid() -> anyhow::Result { Ok(fd.into()) } + +pub fn lid_closed() -> Result { + let conn = Connection::system()?; + let proxy = ManagerProxyBlocking::new(&conn)?; + proxy.lid_closed().context("Failed to talk to logind") +} diff --git a/src/input/mod.rs b/src/input/mod.rs index 9e252569..9f2bac9d 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -7,7 +7,7 @@ use crate::{ cosmic_keystate_from_smithay, cosmic_modifiers_eq_smithay, cosmic_modifiers_from_smithay, }, - Action, Config, OutputConfig, OutputState, PrivateAction, + Action, Config, PrivateAction, }, input::gestures::{GestureState, SwipeAction}, shell::{ @@ -1508,37 +1508,19 @@ impl State { } InputEvent::Special(_) => {} InputEvent::SwitchToggle { event } => { - if event.switch() == Some(Switch::Lid) { - let outputs = self.backend.lock().all_outputs(); - if let Some(internal) = outputs.into_iter().find(|o| o.is_internal()) { - let config = internal.user_data().get::>().unwrap(); - let enabled = config.borrow().enabled.clone(); - if enabled != OutputState::Disabled && event.state() == SwitchState::On { - config.borrow_mut().enabled = OutputState::Disabled; - self.common - .output_configuration_state - .remove_heads(std::iter::once(&internal)); - } 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, - ); + #[cfg(feature = "systemd")] + if event.switch() == Some(Switch::Lid) && self.common.inhibit_lid_fd.is_some() { + if event.state() == SwitchState::On { + 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(); } } } diff --git a/src/state.rs b/src/state.rs index 4b46a90f..6cfe4e1f 100644 --- a/src/state.rs +++ b/src/state.rs @@ -254,7 +254,7 @@ pub struct Common { pub atspi_ei: crate::wayland::handlers::atspi::AtspiEiState, #[cfg(feature = "systemd")] - inhibit_lid_fd: Option, + pub inhibit_lid_fd: Option, } #[derive(Debug)] @@ -408,6 +408,37 @@ impl<'a> LockedBackend<'a> { } } + pub fn enable_internal_output( + &self, + output_configuration_state: &mut OutputConfigurationState, + ) { + 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, + ) { + 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( &mut self, test_only: bool, @@ -740,10 +771,17 @@ impl State { fn update_inhibitor_locks(&mut self) { #[cfg(feature = "systemd")] { + use smithay::backend::session::Session; use tracing::{debug, error}; 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 self.common.inhibit_lid_fd.is_none() { @@ -751,6 +789,18 @@ impl State { Ok(fd) => { debug!("Inhibiting lid switch"); 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) => { error!("Failed to inhibit lid switch: {}", err); @@ -758,8 +808,15 @@ impl State { } } } else { - if self.common.inhibit_lid_fd.take().is_some() { - debug!("Removing inhibitor-lock on lid switch") + if let Some(_fd) = self.common.inhibit_lid_fd.take() { + 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 } } }