From d3de9f7fadb68217c1a85a3e709bf24a4fd94cda Mon Sep 17 00:00:00 2001 From: "Brian J. Tarricone" Date: Wed, 8 Jun 2022 00:30:11 -0700 Subject: [PATCH] Be more aggressive about handling user activity Previously we only trigger unblanking or showing the unlock dialog if core key or motion events come through. Now we also do this when xinput events come in. We also now reset the last-user-activity time for core events. This also changes xcb-xembed to explicitly only handle core events. --- locker/src/screensaver.rs | 58 ++++++++++++++++++++++---------------- xcb-xembed/src/embedder.rs | 22 +++++++-------- 2 files changed, 44 insertions(+), 36 deletions(-) diff --git a/locker/src/screensaver.rs b/locker/src/screensaver.rs index 3250b76..7213aaa 100644 --- a/locker/src/screensaver.rs +++ b/locker/src/screensaver.rs @@ -26,7 +26,7 @@ struct UnlockDialog<'a> { monitor_geom: x::Rectangle, blanker_window: x::Window, embedder: Embedder<'a>, - event_to_forward: Option, + event_to_forward: Option, child: Child, child_pidfd: PidFd, } @@ -109,16 +109,21 @@ impl<'a> Screensaver<'a> { loop { if let Some(event) = self.conn.poll_for_event()? { let embedder_handled = if let Some(mut unlock_dialog) = self.unlock_dialog.take() { - match unlock_dialog.embedder.event(&event) { - Err(err) => { - // XXX: should we assume unlock dialog is dead here? - warn!("Error sending event to unlock dialog: {}", err); - false - }, - Ok(handled) => { - self.unlock_dialog = Some(unlock_dialog); - handled - }, + if let xcb::Event::X(xev) = &event { + match unlock_dialog.embedder.event(xev) { + Err(err) => { + // XXX: should we assume unlock dialog is dead here? + warn!("Error sending event to unlock dialog: {}", err); + false + }, + Ok(handled) => { + self.unlock_dialog = Some(unlock_dialog); + handled + }, + } + } else { + self.unlock_dialog = Some(unlock_dialog); + false } } else { false @@ -148,10 +153,7 @@ impl<'a> Screensaver<'a> { }, } }, - xcb::Event::Input(_) => { - // TODO: implement some sort of hysteresis/debouncing for mouse motion - self.last_user_activity = Instant::now(); - }, + ev @ xcb::Event::Input(_) => self.handle_user_activity(ev)?, xcb::Event::X(x::Event::ClientMessage(ev)) => { let res = match ev.r#type() { b if b == self.command_atoms.blank => Some(self.blank_screen()), @@ -259,18 +261,24 @@ impl<'a> Screensaver<'a> { } fn handle_user_activity(&mut self, ev: xcb::Event) -> anyhow::Result<()> { + // TODO: implement some sort of hysteresis/debouncing for mouse motion + self.last_user_activity = Instant::now(); + match self.blanker_state { BlankerState::Idle => Ok(()), BlankerState::Blanked => self.unblank_screen(), BlankerState::Locked => match &self.unlock_dialog { None => { - self.unlock_dialog = match self.start_unlock_dialog(Some(ev)) { - Err(err) => { - error!("Unable to start unlock dialog: {}", err); - None + match ev { + xcb::Event::X(xev) => self.unlock_dialog = match self.start_unlock_dialog(Some(xev)) { + Err(err) => { + error!("Unable to start unlock dialog: {}", err); + None + }, + Ok(unlock_dialog) => Some(unlock_dialog), }, - Ok(unlock_dialog) => Some(unlock_dialog), - }; + _ => (), + } Ok(()) }, Some(unlock_dialog) => { @@ -331,7 +339,7 @@ impl<'a> Screensaver<'a> { Ok(()) } - fn start_unlock_dialog(&self, trigger_event: Option) -> anyhow::Result> { + fn start_unlock_dialog(&self, trigger_event: Option) -> anyhow::Result> { let mut monitor_data = None; for monitor in &self.monitors { let cookie = self.conn.send_request(&x::QueryPointer { @@ -359,15 +367,15 @@ impl<'a> Screensaver<'a> { } let trigger_event = match trigger_event { - Some(xcb::Event::X(x::Event::KeyPress(ev))) => match keysym_for_keypress(self.conn, &ev) { + Some(x::Event::KeyPress(ev)) => match keysym_for_keypress(self.conn, &ev) { Err(err) => { warn!("Failed to get keysym for key press event: {}", err); - Some(xcb::Event::X(x::Event::KeyPress(ev))) + Some(x::Event::KeyPress(ev)) }, Ok(Some(keysym)) if keysym == xkb::key::KP_Enter || keysym == xkb::key::ISO_Enter || keysym == xkb::key::Return || keysym == xkb::key::Escape => // don't forward an or to the dialog, as that will make it activate/close immediately None, - _ => Some(xcb::Event::X(x::Event::KeyPress(ev))), + _ => Some(x::Event::KeyPress(ev)), }, te => te, }; diff --git a/xcb-xembed/src/embedder.rs b/xcb-xembed/src/embedder.rs index 1114cca..9ded397 100644 --- a/xcb-xembed/src/embedder.rs +++ b/xcb-xembed/src/embedder.rs @@ -122,13 +122,13 @@ impl<'a> Embedder<'a> { Ok(()) } - pub fn event(&mut self, event: &xcb::Event) -> Result { + pub fn event(&mut self, event: &x::Event) -> Result { if self.client == x::WINDOW_NONE { return Err(Error::ClientDestroyed); } match event { - xcb::Event::X(x::Event::PropertyNotify(ev)) if ev.window() == self.client && ev.atom() == intern_atom(self.conn, XEMBED_INFO_ATOM_NAME)? => { + x::Event::PropertyNotify(ev) if ev.window() == self.client && ev.atom() == intern_atom(self.conn, XEMBED_INFO_ATOM_NAME)? => { let info = fetch_xembed_info(self.conn, self.client)?; if (self.flags & XEmbedFlags::MAPPED) != (info.flags & XEmbedFlags::MAPPED) { if info.flags.contains(XEmbedFlags::MAPPED) { @@ -146,7 +146,7 @@ impl<'a> Embedder<'a> { } Ok(true) }, - xcb::Event::X(x::Event::ConfigureNotify(ev)) if ev.window() == self.client => { + x::Event::ConfigureNotify(ev) if ev.window() == self.client => { let mut cookies = Vec::new(); if ev.x() != 0 || ev.y() != 0 { cookies.push(self.conn.send_request_checked(&x::ConfigureWindow { @@ -169,7 +169,7 @@ impl<'a> Embedder<'a> { } Ok(true) }, - xcb::Event::X(x::Event::ClientMessage(ev)) if ev.window() == self.embedder && ev.r#type() == intern_atom(self.conn, XEMBED_MESSAGE_ATOM_NAME)? => { + x::Event::ClientMessage(ev) if ev.window() == self.embedder && ev.r#type() == intern_atom(self.conn, XEMBED_MESSAGE_ATOM_NAME)? => { match ev.data() { x::ClientMessageData::Data32(data) if data[1] == XEmbedMessage::RequestFocus as u32 => { debug!("Client requests focus"); @@ -188,7 +188,7 @@ impl<'a> Embedder<'a> { _ => Ok(false), } }, - xcb::Event::X(x::Event::KeyPress(ev)) if ev.event() == self.embedder && self.flags.contains(XEmbedFlags::MAPPED) => { + x::Event::KeyPress(ev) if ev.event() == self.embedder && self.flags.contains(XEmbedFlags::MAPPED) => { trace!("Forwarding key press to client ({:?} + {})", ev.state(), ev.detail()); self.conn.send_and_check_request(&x::SendEvent { propagate: false, @@ -199,7 +199,7 @@ impl<'a> Embedder<'a> { Ok(true) }, /* - xcb::Event::X(x::Event::KeyRelease(ev)) if ev.event() == self.embedder && self.flags.contains(XEmbedFlags::MAPPED) => { + x::Event::KeyRelease(ev) if ev.event() == self.embedder && self.flags.contains(XEmbedFlags::MAPPED) => { trace!("Forwarding key release to client ({:?} + {})", ev.state(), ev.detail()); self.conn.send_and_check_request(&x::SendEvent { propagate: false, @@ -210,7 +210,7 @@ impl<'a> Embedder<'a> { Ok(true) }, */ - xcb::Event::X(x::Event::MotionNotify(ev)) if ev.event() == self.embedder && self.flags.contains(XEmbedFlags::MAPPED) => { + x::Event::MotionNotify(ev) if ev.event() == self.embedder && self.flags.contains(XEmbedFlags::MAPPED) => { trace!("Forwarding pointer motion to client ({}, {})", ev.event_x(), ev.event_y()); self.conn.send_and_check_request(&x::SendEvent { propagate: false, @@ -220,7 +220,7 @@ impl<'a> Embedder<'a> { })?; Ok(true) }, - xcb::Event::X(x::Event::ButtonPress(ev)) if ev.event() == self.embedder && self.flags.contains(XEmbedFlags::MAPPED) => { + x::Event::ButtonPress(ev) if ev.event() == self.embedder && self.flags.contains(XEmbedFlags::MAPPED) => { trace!("Forwarding button press to client ({:?} + {}: {}, {})", ev.state(), ev.detail(), ev.event_x(), ev.event_y()); self.conn.send_and_check_request(&x::SendEvent { propagate: false, @@ -230,7 +230,7 @@ impl<'a> Embedder<'a> { })?; Ok(true) }, - xcb::Event::X(x::Event::ButtonRelease(ev)) if ev.event() == self.embedder && self.flags.contains(XEmbedFlags::MAPPED) => { + x::Event::ButtonRelease(ev) if ev.event() == self.embedder && self.flags.contains(XEmbedFlags::MAPPED) => { trace!("Forwarding button release to client ({:?} + {}: {}, {})", ev.state(), ev.detail(), ev.event_x(), ev.event_y()); self.conn.send_and_check_request(&x::SendEvent { propagate: false, @@ -240,12 +240,12 @@ impl<'a> Embedder<'a> { })?; Ok(true) }, - xcb::Event::X(x::Event::UnmapNotify(ev)) if ev.window() == self.client => { + x::Event::UnmapNotify(ev) if ev.window() == self.client => { debug!("Client was unmapped"); self.flags -= XEmbedFlags::MAPPED; Ok(true) }, - xcb::Event::X(x::Event::DestroyNotify(ev)) if ev.window() == self.client => { + x::Event::DestroyNotify(ev) if ev.window() == self.client => { debug!("Client was destroyed"); self.flags -= XEmbedFlags::MAPPED; self.client = x::WINDOW_NONE;