login greeter
git clone https://git.lucas.co/cce-display-manager.git
refactor: cce-display-manager on routed events (6bd shrink)
The background joins the session list and login card on the router (dm was
already mostly routed since 6ao); the keyboard chain is now fully
short-circuited — every propagate call delivers KeyInput to the ctx-focused
widget first, so the old non-short-circuited bg-then-roots chain would
insert a typed key once per root (the 6ac rule). The two targeted Enter
deliveries (commit the box, then auth / focus-hop) route the same way,
gated on the box being ctx-focused as before. login_btn.take_click stays.
VERIFY NOTE recorded the hard way: with a username prepopulated and
pam_fprintd configured, the greeter starts a ~30s background fingerprint
auth at launch and handle_mouse_input DISCARDS every click until it
resolves (is_authenticating) — a first A/B round read as a deterministic
routed-press regression. Wait ~40s after launch before probing.
Verified live A/B (identical sequences, post-auth-window): username-box
focus click, session-row select, background unfocus — all empty 8% masks
(AE=67 caret-blink class), session switch confirmed within-build. Typing /
Tab / Enter-auth flow: user spot-check.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018u7qTwzX95dd5ysAkaSCLk
src/main.rs | 36 ++++++++++++++++++++++++------------
1 file changed, 24 insertions(+), 12 deletions(-)
diff --git a/src/main.rs b/src/main.rs
index 58e7e14..0e6ac2a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -388,15 +388,17 @@ impl State {
pub fn widgets_cursor_moved(&mut self, cx: f32, cy: f32) -> bool {
let mut changed = false;
- if self.bg.cursor_moved(cx, cy, &mut self.ui_context) {
- changed = true;
- }
let event = cce_ui::widget::Event::PointerMove {
x: cx,
y: cy,
local_x: cx,
local_y: cy,
};
+ // Routed (6bd shrink): the background rides the same router as the other roots.
+ let bg_ptr = self.bg.as_ptr_mut();
+ if self.ui_context.propagate_event(&event, bg_ptr) {
+ changed = true;
+ }
let sl_ptr = self.session_list.as_ptr_mut();
let card_ptr = self.card.as_ptr_mut();
if self.ui_context.propagate_event(&event, sl_ptr) {
@@ -410,9 +412,6 @@ impl State {
pub fn widgets_mouse_input(&mut self, button: MouseButton, state: ElementState, cx: f32, cy: f32) -> bool {
let mut changed = false;
- if self.bg.mouse_input(button, state, cx, cy, &mut self.ui_context) {
- changed = true;
- }
let event = cce_ui::widget::Event::MouseButton {
button,
state,
@@ -421,6 +420,12 @@ impl State {
local_x: cx,
local_y: cy,
};
+ // Routed (6bd shrink); the bg result stays outside `handled` so the
+ // unfocus-on-missed-press rule below keys on the session list + card only.
+ let bg_ptr = self.bg.as_ptr_mut();
+ if self.ui_context.propagate_event(&event, bg_ptr) {
+ changed = true;
+ }
let sl_ptr = self.session_list.as_ptr_mut();
let card_ptr = self.card.as_ptr_mut();
let handled = self.ui_context.propagate_event(&event, sl_ptr)
@@ -441,13 +446,16 @@ impl State {
pub fn widgets_keyboard_input(&mut self, event: &KeyEvent) -> bool {
let mut changed = false;
- if self.bg.keyboard_input(event, &mut self.ui_context) {
- changed = true;
- }
let ui_event = cce_ui::widget::Event::KeyInput(event.clone());
+ // Fully short-circuited (the 6ac rule): every propagate call delivers KeyInput
+ // to the ctx-focused widget first, so a non-short-circuited chain would insert
+ // a typed key once per root.
+ let bg_ptr = self.bg.as_ptr_mut();
let sl_ptr = self.session_list.as_ptr_mut();
let card_ptr = self.card.as_ptr_mut();
- if self.ui_context.propagate_event(&ui_event, sl_ptr) {
+ if self.ui_context.propagate_event(&ui_event, bg_ptr) {
+ changed = true;
+ } else if self.ui_context.propagate_event(&ui_event, sl_ptr) {
changed = true;
} else if self.ui_context.propagate_event(&ui_event, card_ptr) {
changed = true;
@@ -863,11 +871,15 @@ impl cce_ui::engine::Application for State {
}
changed = true;
} else if logical_key == &Key::Named(NamedKey::Enter) && self.password_box.focused(&self.ui_context) {
- self.password_box.keyboard_input(event, &mut self.ui_context);
+ let kev = cce_ui::widget::Event::KeyInput(event.clone());
+ let ptr = self.password_box.as_ptr_mut();
+ let _ = self.ui_context.propagate_event(&kev, ptr);
self.trigger_auth();
changed = true;
} else if logical_key == &Key::Named(NamedKey::Enter) && self.username_box.focused(&self.ui_context) {
- self.username_box.keyboard_input(event, &mut self.ui_context);
+ let kev = cce_ui::widget::Event::KeyInput(event.clone());
+ let ptr = self.username_box.as_ptr_mut();
+ let _ = self.ui_context.propagate_event(&kev, ptr);
self.ui_context.set_focused(&mut self.password_box);
self.username_box.unfocus();
self.password_box.focus();