git.lucas.co / cce-display-manager
login greeter
git clone https://git.lucas.co/cce-display-manager.git

commitb1cdc2e985d6267b8d7904d6c0663f326bdf8e4d
parent542cd87e69
authorLucas Galante <[email protected]>
date2026-05-29 22:18
Support Ctrl+P and Ctrl+N session cycling in greeter

 src/main.rs | 24 +++++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index 6f9c671..db07204 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1165,13 +1165,16 @@ impl AppState {
             shift: self.shift_pressed,
         };
 
+        let is_ctrl_p = self.ctrl_pressed && (keysym == xkeysym::Keysym::p || keysym == xkeysym::Keysym::P);
+        let is_ctrl_n = self.ctrl_pressed && (keysym == xkeysym::Keysym::n || keysym == xkeysym::Keysym::N);
+
         if state == ElementState::Pressed {
             if let Some(st) = &mut self.state {
                 // If we are currently in fingerprint authentication and the user starts typing a password,
                 // cancel the fingerprint auth and let them type.
                 if st.is_authenticating {
                     if st.password_box.text.is_empty() {
-                        let is_typing = match &logical_key {
+                        let is_typing = !self.ctrl_pressed && match &logical_key {
                             Key::Character(_) | Key::Named(NamedKey::Backspace) | Key::Named(NamedKey::Delete) | Key::Named(NamedKey::Space) => true,
                             _ => false,
                         };
@@ -1184,7 +1187,7 @@ impl AppState {
                         } else {
                             let is_nav = match &logical_key {
                                 Key::Named(NamedKey::ArrowUp) | Key::Named(NamedKey::ArrowDown) | Key::Named(NamedKey::Tab) => true,
-                                _ => false,
+                                _ => is_ctrl_p || is_ctrl_n,
                             };
                             if !is_nav {
                                 return;
@@ -1197,13 +1200,16 @@ impl AppState {
 
                 let mut changed = false;
 
-                // Handle Up/Down navigation to cycle sessions
-                if logical_key == Key::Named(NamedKey::ArrowUp) && !st.session_list.sessions.is_empty() {
+                // Handle Up/Down or Ctrl+P/N navigation to cycle sessions
+                let cycle_up = (logical_key == Key::Named(NamedKey::ArrowUp) || is_ctrl_p) && !st.session_list.sessions.is_empty();
+                let cycle_down = (logical_key == Key::Named(NamedKey::ArrowDown) || is_ctrl_n) && !st.session_list.sessions.is_empty();
+
+                if cycle_up {
                     let len = st.session_list.sessions.len();
                     st.session_list.selected_idx = (st.session_list.selected_idx + len - 1) % len;
                     st.session_list.hovered_idx = None;
                     changed = true;
-                } else if logical_key == Key::Named(NamedKey::ArrowDown) && !st.session_list.sessions.is_empty() {
+                } else if cycle_down {
                     let len = st.session_list.sessions.len();
                     st.session_list.selected_idx = (st.session_list.selected_idx + 1) % len;
                     st.session_list.hovered_idx = None;
@@ -1887,6 +1893,14 @@ fn run_daemon() {
             let pam_env = auth.get_env();
             println!("[clear-display-manager] PAM Environment variables: {:?}", pam_env);
 
+            if let Some((_, session_id)) = pam_env.iter().find(|(k, _)| k == "XDG_SESSION_ID") {
+                println!("[clear-display-manager] Explicitly activating logind session {} via loginctl...", session_id);
+                let _ = std::process::Command::new("loginctl")
+                    .arg("activate")
+                    .arg(session_id)
+                    .status();
+            }
+
             let user = match users::get_user_by_name(&username) {
                 Some(u) => u,
                 None => {