From 9163374cdb8de9a0fd46b810ae4090719e9b1997 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Tue, 13 Oct 2026 13:10:53 +0100 Subject: [PATCH] unblock brightness shortcut on lock screen --- compositor/src/input.rs | 55 ++++++++++++++++++++++++++++++++++++++--- compositor/src/main.rs | 1 - docs/locking.md | 4 +++ 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/compositor/src/input.rs b/compositor/src/input.rs index 638fb8d..cbfec6c 100644 --- a/compositor/src/input.rs +++ b/compositor/src/input.rs @@ -51,22 +51,27 @@ impl Ferese { let presented = self.presented_window_rect(*id)?; let (scale_x, scale_y) = self.visual_scale_for_window(window)?; let point = local.to_f64() + hint - geometry.loc.to_f64(); + return Some(Point::from(( presented.x + point.x * scale_x, presented.y + point.y * scale_y, ))); } + for output in self.space.outputs() { let output_geometry = self.space.output_geometry(output)?; let layers = smithay::desktop::layer_map_for_output(output); + for layer in layers.layers() { let Some(local) = surface_tree_position(layer.wl_surface(), surface, (0, 0).into()) else { continue; }; let geometry = layers.layer_geometry(layer)?; + return Some((output_geometry.loc + geometry.loc + local).to_f64() + hint); } } + None } @@ -77,6 +82,7 @@ impl Ferese { if !hint.surface.is_alive() || self.session_lock.active() || self.input_capture.active() { return; } + let Some(pointer) = self.seat.get_pointer() else { return; }; @@ -85,10 +91,12 @@ impl Ferese { constraint.is_active() && matches!(&*constraint, PointerConstraint::Locked(_)) }) }); + if locked { self.locked_pointer_hint = Some(hint); return; } + if pointer.current_focus().is_some_and(|surface| { with_pointer_constraint(&surface, &pointer, |constraint| { constraint.is_some_and(|constraint| constraint.is_active()) @@ -96,11 +104,13 @@ impl Ferese { }) { return; } + let Some(global) = self.pointer_hint_position(&hint.surface, hint.local) else { return; }; let location = self.clamp_pointer_position(global); let focus = self.surface_under(location); + pointer.motion( self, focus, @@ -111,6 +121,7 @@ impl Ferese { }, ); pointer.frame(self); + self.cursor_redraw_pending = true; } @@ -118,8 +129,10 @@ impl Ferese { if self.input_capture.active() { self.set_binding_mode("default"); } + let seat = self.seat.clone(); self.idle_notifier_state.notify_activity(&seat); + if !matches!( &event, InputEvent::DeviceAdded { .. } | InputEvent::DeviceRemoved { .. } | InputEvent::SwitchToggle { .. } @@ -166,7 +179,9 @@ impl Ferese { .any(|binding| binding.swipe_fingers(event.fingers())), self.input_settings.touchpad.swipe_threshold, ); + self.swipe.start_time(std::time::Duration::from_micros(event.time())); + if self.swipe.active() { self.focus_output_at(pointer.current_location()); } else { @@ -187,6 +202,7 @@ impl Ferese { event.delta_y(), std::time::Duration::from_micros(event.time()), ); + if self.swipe_navigation_blocked() { self.finish_workspace_swipe(None); self.finish_focus_swipe(None); @@ -274,6 +290,7 @@ impl Ferese { keyboard.set_focus(self, None, SERIAL_COUNTER.next_serial()); } } + let serial = SERIAL_COUNTER.next_serial(); let interaction_focus = keyboard.current_focus(); let client_grab = keyboard @@ -293,6 +310,7 @@ impl Ferese { data.finish_focus_cycle(); } } + if state == KeyState::Released { data.binding_mode_pressed.remove(&keycode); data.binding_mode_repeats.remove(&keycode); @@ -308,7 +326,31 @@ impl Ferese { return FilterResult::Forward; } let raw_symbols = keysym.raw_syms().into_iter().map(|symbol| symbol.raw()).collect::>(); - if !data.binding_mode_pressed.insert(keycode) { + let first_press = data.binding_mode_pressed.insert(keycode); + if data.session_lock.active() { + // Preserve ownership of keys held across the lock transition. + if !first_press && !data.intercepted_keys.contains(&keycode) { + return FilterResult::Forward; + } + if let Some(step) = locked_brightness_step(keysym.modified_sym().raw()) { + data.intercepted_keys.insert(keycode); + // Never execute configurable commands while locked. + if let Some(child) = spawn_client( + data, + ["brightnessctl", "set", step], + crate::private_client::ClientCapabilities::default(), + ) { + crate::process::watch_client_exit(&data.loop_handle, child); + } + return FilterResult::Intercept(()); + } + return if data.intercepted_keys.contains(&keycode) { + FilterResult::Intercept(()) + } else { + FilterResult::Forward + }; + } + if !first_press { // A held key belongs to the recipient of its first // press, even when a mode or configuration changes. return if data.intercepted_keys.contains(&keycode) { @@ -331,9 +373,6 @@ impl Ferese { FilterResult::Forward }; } - if data.session_lock.active() { - return FilterResult::Forward; - } let symbol = keysym.modified_sym().raw(); if data.binding_modes.active().is_some() && symbol == keysyms::KEY_Escape { if state == KeyState::Pressed { @@ -1298,6 +1337,14 @@ fn surface_tree_offset(root: &WlSurface, target: &WlSurface) -> Option Option<&'static str> { + match symbol { + keysyms::KEY_XF86MonBrightnessUp => Some("2%+"), + keysyms::KEY_XF86MonBrightnessDown => Some("2%-"), + _ => None, + } +} + fn virtual_terminal(symbol: u32, ctrl: bool, alt: bool, direct: bool) -> Option { if !direct { return None; diff --git a/compositor/src/main.rs b/compositor/src/main.rs index a730079..8cff647 100644 --- a/compositor/src/main.rs +++ b/compositor/src/main.rs @@ -57,7 +57,6 @@ use calloop::signals::{Signal, Signals}; use process::{spawn_client, terminate_child, watch_client_exit}; use smithay::reexports::calloop::EventLoop; use smithay::reexports::wayland_server::Display; -pub use state::{Ferese, RuntimeConfig}; use tracing::{info, warn}; use crate::backends::LaunchConfig; diff --git a/docs/locking.md b/docs/locking.md index 2ad8cda..39ff5bf 100644 --- a/docs/locking.md +++ b/docs/locking.md @@ -19,6 +19,10 @@ Press Escape to clear the password. The authentication status also shows whether Caps Lock is on. A failed attempt displays an error and delays the next retry. Authentication uses the system's PAM policy; both password and account validation must succeed. +The screen brightness keys work while locked, including when brightness is zero. +They require `brightnessctl` and adjust brightness in 2% steps. While locked, +these keys use the compositor's brightness control instead of custom bindings. + ## Automatic locking Install `swayidle`, then add this to `~/.config/ferese/config.kdl` to lock after