Use lock idle deadlines and stop polling after display sleep
This commit is contained in:
1 parent
96b0a9d097
commit
79a968b0a6
3 files changed
+98
-33
No files matched your search
@@ -57,6 +57,7 @@ pub struct DirectBackendState {
|
|||||||
input_devices: Vec<LibinputDevice>,
|
input_devices: Vec<LibinputDevice>,
|
||||||
presentation: HashMap<(DrmNode, crtc::Handle), PresentationClock>,
|
presentation: HashMap<(DrmNode, crtc::Handle), PresentationClock>,
|
||||||
pub(crate) connected_outputs: Vec<ConnectedOutputInfo>,
|
pub(crate) connected_outputs: Vec<ConnectedOutputInfo>,
|
||||||
|
power_retry: Option<RegistrationToken>,
|
||||||
animation_timer: Option<RegistrationToken>,
|
animation_timer: Option<RegistrationToken>,
|
||||||
animation_deadline: Option<Instant>,
|
animation_deadline: Option<Instant>,
|
||||||
scheduling_metrics: SchedulingMetrics,
|
scheduling_metrics: SchedulingMetrics,
|
||||||
@@ -236,6 +237,7 @@ pub fn init(event_loop: &mut EventLoop<Ferese>, state: &mut Ferese) -> Result<()
|
|||||||
input_devices: Vec::new(),
|
input_devices: Vec::new(),
|
||||||
presentation: HashMap::new(),
|
presentation: HashMap::new(),
|
||||||
connected_outputs: Vec::new(),
|
connected_outputs: Vec::new(),
|
||||||
|
power_retry: None,
|
||||||
animation_timer: None,
|
animation_timer: None,
|
||||||
animation_deadline: None,
|
animation_deadline: None,
|
||||||
scheduling_metrics: SchedulingMetrics::new(),
|
scheduling_metrics: SchedulingMetrics::new(),
|
||||||
@@ -274,6 +276,9 @@ pub fn init(event_loop: &mut EventLoop<Ferese>, state: &mut Ferese) -> Result<()
|
|||||||
let handle = state.loop_handle.clone();
|
let handle = state.loop_handle.clone();
|
||||||
if let Some(backend) = state.direct_backend.as_mut() {
|
if let Some(backend) = state.direct_backend.as_mut() {
|
||||||
backend.active = false;
|
backend.active = false;
|
||||||
|
if let Some(token) = backend.power_retry.take() {
|
||||||
|
handle.remove(token);
|
||||||
|
}
|
||||||
backend
|
backend
|
||||||
.presentation
|
.presentation
|
||||||
.values_mut()
|
.values_mut()
|
||||||
@@ -702,6 +707,35 @@ fn apply_output_power(state: &mut Ferese) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let retry = backend.active
|
||||||
|
&& backend
|
||||||
|
.devices
|
||||||
|
.values()
|
||||||
|
.filter(|device| device.drm.is_active())
|
||||||
|
.any(|device| {
|
||||||
|
device
|
||||||
|
.outputs
|
||||||
|
.values()
|
||||||
|
.any(|output| output.power.needs_power_off() && !output.frame_pending)
|
||||||
|
});
|
||||||
|
if !retry {
|
||||||
|
if let Some(token) = backend.power_retry.take() {
|
||||||
|
state.loop_handle.remove(token);
|
||||||
|
}
|
||||||
|
} else if backend.power_retry.is_none() {
|
||||||
|
match state
|
||||||
|
.loop_handle
|
||||||
|
.insert_source(Timer::from_duration(Duration::from_secs(1)), |_, _, state| {
|
||||||
|
if let Some(backend) = state.direct_backend.as_mut() {
|
||||||
|
backend.power_retry = None;
|
||||||
|
}
|
||||||
|
apply_output_power(state);
|
||||||
|
TimeoutAction::Drop
|
||||||
|
}) {
|
||||||
|
Ok(token) => backend.power_retry = Some(token),
|
||||||
|
Err(error) => tracing::warn!(%error, "could not arm failed power-off retry"),
|
||||||
|
}
|
||||||
|
}
|
||||||
state.refresh_idle_inhibition();
|
state.refresh_idle_inhibition();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -717,6 +751,7 @@ pub(crate) fn wake_locked_outputs(state: &mut Ferese) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
apply_output_power(state);
|
||||||
render_all(state);
|
render_all(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,14 +44,17 @@ impl IdleSettings {
|
|||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_poll(self, elapsed: Duration, fade_duration: Duration) -> Duration {
|
fn next_deadline(self, elapsed: Duration, fade_duration: Duration) -> Option<Duration> {
|
||||||
|
if self.sleep_after_seconds != 0 && elapsed >= Duration::from_secs(self.sleep_after_seconds) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
let dim_at = Duration::from_secs(self.dim_after_seconds);
|
let dim_at = Duration::from_secs(self.dim_after_seconds);
|
||||||
if !fade_duration.is_zero()
|
if !fade_duration.is_zero()
|
||||||
&& self.dim_after_seconds != 0
|
&& self.dim_after_seconds != 0
|
||||||
&& elapsed >= dim_at
|
&& elapsed >= dim_at
|
||||||
&& elapsed < dim_at + fade_duration
|
&& elapsed < dim_at + fade_duration
|
||||||
{
|
{
|
||||||
return Duration::from_millis(16);
|
return Some(Duration::from_millis(16));
|
||||||
}
|
}
|
||||||
[self.dim_after_seconds, self.sleep_after_seconds]
|
[self.dim_after_seconds, self.sleep_after_seconds]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -59,8 +62,6 @@ impl IdleSettings {
|
|||||||
.filter_map(|delay| Duration::from_secs(delay).checked_sub(elapsed))
|
.filter_map(|delay| Duration::from_secs(delay).checked_sub(elapsed))
|
||||||
.filter(|delay| !delay.is_zero())
|
.filter(|delay| !delay.is_zero())
|
||||||
.min()
|
.min()
|
||||||
.unwrap_or(Duration::from_secs(1))
|
|
||||||
.min(Duration::from_secs(1))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn appearance(self, elapsed: Duration, fade_duration: Duration) -> (f32, bool) {
|
fn appearance(self, elapsed: Duration, fade_duration: Duration) -> (f32, bool) {
|
||||||
@@ -125,6 +126,42 @@ impl Ferese {
|
|||||||
crate::backends::direct::wake_locked_outputs(self);
|
crate::backends::direct::wake_locked_outputs(self);
|
||||||
self.cursor_redraw_pending = true;
|
self.cursor_redraw_pending = true;
|
||||||
}
|
}
|
||||||
|
self.rearm_lock_idle();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn refresh_lock_idle_policy(&mut self) {
|
||||||
|
self.update_lock_idle(Instant::now());
|
||||||
|
self.rearm_lock_idle();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rearm_lock_idle(&mut self) {
|
||||||
|
if let Some(token) = self.session_lock.idle_timer.take() {
|
||||||
|
self.loop_handle.remove(token);
|
||||||
|
}
|
||||||
|
if !self.session_lock.ready_for_idle(self.space.outputs()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let elapsed = self
|
||||||
|
.session_lock
|
||||||
|
.idle_since
|
||||||
|
.map_or(Duration::ZERO, |since| since.elapsed());
|
||||||
|
let Some(delay) = self
|
||||||
|
.lock_idle
|
||||||
|
.next_deadline(elapsed, self.animation_duration(Duration::from_millis(500)))
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
match self
|
||||||
|
.loop_handle
|
||||||
|
.insert_source(Timer::from_duration(delay), |_, _, state| {
|
||||||
|
state.session_lock.idle_timer = None;
|
||||||
|
state.refresh_lock_idle_policy();
|
||||||
|
TimeoutAction::Drop
|
||||||
|
}) {
|
||||||
|
Ok(token) => self.session_lock.idle_timer = Some(token),
|
||||||
|
Err(error) => tracing::warn!(%error, "could not arm lock idle deadline"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_lock_idle(&mut self, now: Instant) {
|
fn update_lock_idle(&mut self, now: Instant) {
|
||||||
@@ -186,7 +223,7 @@ impl Ferese {
|
|||||||
if !self.session_lock.active {
|
if !self.session_lock.active {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.session_lock.presented.insert(output.clone());
|
let newly_presented = self.session_lock.presented.insert(output.clone());
|
||||||
if self
|
if self
|
||||||
.space
|
.space
|
||||||
.outputs()
|
.outputs()
|
||||||
@@ -198,6 +235,9 @@ impl Ferese {
|
|||||||
self.session_lock.confirmed = true;
|
self.session_lock.confirmed = true;
|
||||||
tracing::info!("session lock confirmed after safe output frames");
|
tracing::info!("session lock confirmed after safe output frames");
|
||||||
}
|
}
|
||||||
|
if newly_presented {
|
||||||
|
self.refresh_lock_idle_policy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn configure_lock_surfaces(&mut self) {
|
pub(crate) fn configure_lock_surfaces(&mut self) {
|
||||||
@@ -239,26 +279,6 @@ impl SessionLockHandler for Ferese {
|
|||||||
self.session_lock.active = true;
|
self.session_lock.active = true;
|
||||||
self.refresh_idle_inhibition();
|
self.refresh_idle_inhibition();
|
||||||
self.session_lock.idle_since = Some(Instant::now());
|
self.session_lock.idle_since = Some(Instant::now());
|
||||||
match self
|
|
||||||
.loop_handle
|
|
||||||
.insert_source(Timer::from_duration(Duration::from_secs(1)), |_, _, state| {
|
|
||||||
if !state.session_lock.active {
|
|
||||||
return TimeoutAction::Drop;
|
|
||||||
}
|
|
||||||
state.update_lock_idle(Instant::now());
|
|
||||||
let elapsed = state
|
|
||||||
.session_lock
|
|
||||||
.idle_since
|
|
||||||
.map_or(Duration::ZERO, |since| since.elapsed());
|
|
||||||
TimeoutAction::ToDuration(
|
|
||||||
state
|
|
||||||
.lock_idle
|
|
||||||
.next_poll(elapsed, state.animation_duration(Duration::from_millis(500))),
|
|
||||||
)
|
|
||||||
}) {
|
|
||||||
Ok(token) => self.session_lock.idle_timer = Some(token),
|
|
||||||
Err(error) => tracing::warn!(%error, "could not schedule lock screen inactivity"),
|
|
||||||
}
|
|
||||||
self.input_capture.disable_all();
|
self.input_capture.disable_all();
|
||||||
self.portal_session.set_locked(true);
|
self.portal_session.set_locked(true);
|
||||||
self.session_lock.owner = Some(confirmation.ext_session_lock().clone());
|
self.session_lock.owner = Some(confirmation.ext_session_lock().clone());
|
||||||
@@ -375,8 +395,8 @@ mod tests {
|
|||||||
let halfway = policy.appearance(Duration::from_millis(half_at), fade);
|
let halfway = policy.appearance(Duration::from_millis(half_at), fade);
|
||||||
assert!((halfway.0 - 0.325).abs() < 0.001 && !halfway.1);
|
assert!((halfway.0 - 0.325).abs() < 0.001 && !halfway.1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
policy.next_poll(Duration::from_millis(half_at), fade),
|
policy.next_deadline(Duration::from_millis(half_at), fade),
|
||||||
Duration::from_millis(16)
|
Some(Duration::from_millis(16))
|
||||||
);
|
);
|
||||||
assert_eq!(policy.appearance(Duration::from_secs(120), fade), (1.0, true));
|
assert_eq!(policy.appearance(Duration::from_secs(120), fade), (1.0, true));
|
||||||
}
|
}
|
||||||
@@ -409,16 +429,25 @@ mod tests {
|
|||||||
(0.0, false)
|
(0.0, false)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
policy.next_poll(Duration::from_millis(29_998), Duration::from_millis(500)),
|
policy.next_deadline(Duration::from_millis(29_998), Duration::from_millis(500)),
|
||||||
Duration::from_millis(2)
|
Some(Duration::from_millis(2))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
policy.next_poll(Duration::from_secs(30), Duration::from_millis(500)),
|
policy.next_deadline(Duration::from_secs(30), Duration::from_millis(500)),
|
||||||
Duration::from_millis(16)
|
Some(Duration::from_millis(16))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
policy.next_poll(Duration::from_secs(30), Duration::ZERO),
|
policy.next_deadline(Duration::from_secs(30), Duration::ZERO),
|
||||||
Duration::from_secs(1)
|
Some(Duration::from_secs(90))
|
||||||
|
);
|
||||||
|
assert_eq!(policy.next_deadline(Duration::from_secs(120), Duration::ZERO), None);
|
||||||
|
assert_eq!(
|
||||||
|
IdleSettings {
|
||||||
|
dim_after_seconds: 0,
|
||||||
|
sleep_after_seconds: 0
|
||||||
|
}
|
||||||
|
.next_deadline(Duration::ZERO, Duration::ZERO),
|
||||||
|
None
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -699,6 +699,7 @@ impl Ferese {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.lock_idle = config.lock_idle;
|
self.lock_idle = config.lock_idle;
|
||||||
|
self.refresh_lock_idle_policy();
|
||||||
self.advance_animations(Instant::now());
|
self.advance_animations(Instant::now());
|
||||||
|
|
||||||
let touchpad_changed = self.input_settings.touchpad != config.input_settings.touchpad;
|
let touchpad_changed = self.input_settings.touchpad != config.input_settings.touchpad;
|
||||||
|
|||||||
Reference in new issue
Block a user