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.
This commit is contained in:
parent
b0c2ffc74a
commit
d3de9f7fad
@ -26,7 +26,7 @@ struct UnlockDialog<'a> {
|
|||||||
monitor_geom: x::Rectangle,
|
monitor_geom: x::Rectangle,
|
||||||
blanker_window: x::Window,
|
blanker_window: x::Window,
|
||||||
embedder: Embedder<'a>,
|
embedder: Embedder<'a>,
|
||||||
event_to_forward: Option<xcb::Event>,
|
event_to_forward: Option<x::Event>,
|
||||||
child: Child,
|
child: Child,
|
||||||
child_pidfd: PidFd,
|
child_pidfd: PidFd,
|
||||||
}
|
}
|
||||||
@ -109,16 +109,21 @@ impl<'a> Screensaver<'a> {
|
|||||||
loop {
|
loop {
|
||||||
if let Some(event) = self.conn.poll_for_event()? {
|
if let Some(event) = self.conn.poll_for_event()? {
|
||||||
let embedder_handled = if let Some(mut unlock_dialog) = self.unlock_dialog.take() {
|
let embedder_handled = if let Some(mut unlock_dialog) = self.unlock_dialog.take() {
|
||||||
match unlock_dialog.embedder.event(&event) {
|
if let xcb::Event::X(xev) = &event {
|
||||||
Err(err) => {
|
match unlock_dialog.embedder.event(xev) {
|
||||||
// XXX: should we assume unlock dialog is dead here?
|
Err(err) => {
|
||||||
warn!("Error sending event to unlock dialog: {}", err);
|
// XXX: should we assume unlock dialog is dead here?
|
||||||
false
|
warn!("Error sending event to unlock dialog: {}", err);
|
||||||
},
|
false
|
||||||
Ok(handled) => {
|
},
|
||||||
self.unlock_dialog = Some(unlock_dialog);
|
Ok(handled) => {
|
||||||
handled
|
self.unlock_dialog = Some(unlock_dialog);
|
||||||
},
|
handled
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.unlock_dialog = Some(unlock_dialog);
|
||||||
|
false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@ -148,10 +153,7 @@ impl<'a> Screensaver<'a> {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
xcb::Event::Input(_) => {
|
ev @ xcb::Event::Input(_) => self.handle_user_activity(ev)?,
|
||||||
// TODO: implement some sort of hysteresis/debouncing for mouse motion
|
|
||||||
self.last_user_activity = Instant::now();
|
|
||||||
},
|
|
||||||
xcb::Event::X(x::Event::ClientMessage(ev)) => {
|
xcb::Event::X(x::Event::ClientMessage(ev)) => {
|
||||||
let res = match ev.r#type() {
|
let res = match ev.r#type() {
|
||||||
b if b == self.command_atoms.blank => Some(self.blank_screen()),
|
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<()> {
|
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 {
|
match self.blanker_state {
|
||||||
BlankerState::Idle => Ok(()),
|
BlankerState::Idle => Ok(()),
|
||||||
BlankerState::Blanked => self.unblank_screen(),
|
BlankerState::Blanked => self.unblank_screen(),
|
||||||
BlankerState::Locked => match &self.unlock_dialog {
|
BlankerState::Locked => match &self.unlock_dialog {
|
||||||
None => {
|
None => {
|
||||||
self.unlock_dialog = match self.start_unlock_dialog(Some(ev)) {
|
match ev {
|
||||||
Err(err) => {
|
xcb::Event::X(xev) => self.unlock_dialog = match self.start_unlock_dialog(Some(xev)) {
|
||||||
error!("Unable to start unlock dialog: {}", err);
|
Err(err) => {
|
||||||
None
|
error!("Unable to start unlock dialog: {}", err);
|
||||||
|
None
|
||||||
|
},
|
||||||
|
Ok(unlock_dialog) => Some(unlock_dialog),
|
||||||
},
|
},
|
||||||
Ok(unlock_dialog) => Some(unlock_dialog),
|
_ => (),
|
||||||
};
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
Some(unlock_dialog) => {
|
Some(unlock_dialog) => {
|
||||||
@ -331,7 +339,7 @@ impl<'a> Screensaver<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_unlock_dialog(&self, trigger_event: Option<xcb::Event>) -> anyhow::Result<UnlockDialog<'a>> {
|
fn start_unlock_dialog(&self, trigger_event: Option<x::Event>) -> anyhow::Result<UnlockDialog<'a>> {
|
||||||
let mut monitor_data = None;
|
let mut monitor_data = None;
|
||||||
for monitor in &self.monitors {
|
for monitor in &self.monitors {
|
||||||
let cookie = self.conn.send_request(&x::QueryPointer {
|
let cookie = self.conn.send_request(&x::QueryPointer {
|
||||||
@ -359,15 +367,15 @@ impl<'a> Screensaver<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let trigger_event = match trigger_event {
|
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) => {
|
Err(err) => {
|
||||||
warn!("Failed to get keysym for key press event: {}", 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 =>
|
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 <enter> or <esc> to the dialog, as that will make it activate/close immediately
|
// don't forward an <enter> or <esc> to the dialog, as that will make it activate/close immediately
|
||||||
None,
|
None,
|
||||||
_ => Some(xcb::Event::X(x::Event::KeyPress(ev))),
|
_ => Some(x::Event::KeyPress(ev)),
|
||||||
},
|
},
|
||||||
te => te,
|
te => te,
|
||||||
};
|
};
|
||||||
|
@ -122,13 +122,13 @@ impl<'a> Embedder<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn event(&mut self, event: &xcb::Event) -> Result<bool, Error> {
|
pub fn event(&mut self, event: &x::Event) -> Result<bool, Error> {
|
||||||
if self.client == x::WINDOW_NONE {
|
if self.client == x::WINDOW_NONE {
|
||||||
return Err(Error::ClientDestroyed);
|
return Err(Error::ClientDestroyed);
|
||||||
}
|
}
|
||||||
|
|
||||||
match event {
|
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)?;
|
let info = fetch_xembed_info(self.conn, self.client)?;
|
||||||
if (self.flags & XEmbedFlags::MAPPED) != (info.flags & XEmbedFlags::MAPPED) {
|
if (self.flags & XEmbedFlags::MAPPED) != (info.flags & XEmbedFlags::MAPPED) {
|
||||||
if info.flags.contains(XEmbedFlags::MAPPED) {
|
if info.flags.contains(XEmbedFlags::MAPPED) {
|
||||||
@ -146,7 +146,7 @@ impl<'a> Embedder<'a> {
|
|||||||
}
|
}
|
||||||
Ok(true)
|
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();
|
let mut cookies = Vec::new();
|
||||||
if ev.x() != 0 || ev.y() != 0 {
|
if ev.x() != 0 || ev.y() != 0 {
|
||||||
cookies.push(self.conn.send_request_checked(&x::ConfigureWindow {
|
cookies.push(self.conn.send_request_checked(&x::ConfigureWindow {
|
||||||
@ -169,7 +169,7 @@ impl<'a> Embedder<'a> {
|
|||||||
}
|
}
|
||||||
Ok(true)
|
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() {
|
match ev.data() {
|
||||||
x::ClientMessageData::Data32(data) if data[1] == XEmbedMessage::RequestFocus as u32 => {
|
x::ClientMessageData::Data32(data) if data[1] == XEmbedMessage::RequestFocus as u32 => {
|
||||||
debug!("Client requests focus");
|
debug!("Client requests focus");
|
||||||
@ -188,7 +188,7 @@ impl<'a> Embedder<'a> {
|
|||||||
_ => Ok(false),
|
_ => 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());
|
trace!("Forwarding key press to client ({:?} + {})", ev.state(), ev.detail());
|
||||||
self.conn.send_and_check_request(&x::SendEvent {
|
self.conn.send_and_check_request(&x::SendEvent {
|
||||||
propagate: false,
|
propagate: false,
|
||||||
@ -199,7 +199,7 @@ impl<'a> Embedder<'a> {
|
|||||||
Ok(true)
|
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());
|
trace!("Forwarding key release to client ({:?} + {})", ev.state(), ev.detail());
|
||||||
self.conn.send_and_check_request(&x::SendEvent {
|
self.conn.send_and_check_request(&x::SendEvent {
|
||||||
propagate: false,
|
propagate: false,
|
||||||
@ -210,7 +210,7 @@ impl<'a> Embedder<'a> {
|
|||||||
Ok(true)
|
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());
|
trace!("Forwarding pointer motion to client ({}, {})", ev.event_x(), ev.event_y());
|
||||||
self.conn.send_and_check_request(&x::SendEvent {
|
self.conn.send_and_check_request(&x::SendEvent {
|
||||||
propagate: false,
|
propagate: false,
|
||||||
@ -220,7 +220,7 @@ impl<'a> Embedder<'a> {
|
|||||||
})?;
|
})?;
|
||||||
Ok(true)
|
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());
|
trace!("Forwarding button press to client ({:?} + {}: {}, {})", ev.state(), ev.detail(), ev.event_x(), ev.event_y());
|
||||||
self.conn.send_and_check_request(&x::SendEvent {
|
self.conn.send_and_check_request(&x::SendEvent {
|
||||||
propagate: false,
|
propagate: false,
|
||||||
@ -230,7 +230,7 @@ impl<'a> Embedder<'a> {
|
|||||||
})?;
|
})?;
|
||||||
Ok(true)
|
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());
|
trace!("Forwarding button release to client ({:?} + {}: {}, {})", ev.state(), ev.detail(), ev.event_x(), ev.event_y());
|
||||||
self.conn.send_and_check_request(&x::SendEvent {
|
self.conn.send_and_check_request(&x::SendEvent {
|
||||||
propagate: false,
|
propagate: false,
|
||||||
@ -240,12 +240,12 @@ impl<'a> Embedder<'a> {
|
|||||||
})?;
|
})?;
|
||||||
Ok(true)
|
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");
|
debug!("Client was unmapped");
|
||||||
self.flags -= XEmbedFlags::MAPPED;
|
self.flags -= XEmbedFlags::MAPPED;
|
||||||
Ok(true)
|
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");
|
debug!("Client was destroyed");
|
||||||
self.flags -= XEmbedFlags::MAPPED;
|
self.flags -= XEmbedFlags::MAPPED;
|
||||||
self.client = x::WINDOW_NONE;
|
self.client = x::WINDOW_NONE;
|
||||||
|
Loading…
Reference in New Issue
Block a user