Add platform::startup_notify for Wayland/X11

The utils in this module should help the users to activate the windows
they create, as well as manage activation tokens environment variables.

The API is essential for Wayland in the first place, since some
compositors may decide initial focus of the window based on whether
the activation token was during the window creation.

Fixes #2279.

Co-authored-by: John Nunley <jtnunley01@gmail.com>
This commit is contained in:
Kirill Chibisov 2023-07-20 13:16:51 +00:00 committed by GitHub
parent 89aa7cc06e
commit f7a84a5b50
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 771 additions and 35 deletions

View file

@ -57,7 +57,7 @@ impl<T: 'static> EventProcessor<T> {
}
}
fn with_window<F, Ret>(&self, window_id: xproto::Window, callback: F) -> Option<Ret>
pub(crate) fn with_window<F, Ret>(&self, window_id: xproto::Window, callback: F) -> Option<Ret>
where
F: Fn(&Arc<UnownedWindow>) -> Ret,
{
@ -237,6 +237,10 @@ impl<T: 'static> EventProcessor<T> {
// In version 0, time isn't specified
x11rb::CURRENT_TIME
};
// Log this timestamp.
wt.xconn.set_timestamp(time);
// This results in the `SelectionNotify` event below
self.dnd.convert_selection(window, time);
}
@ -291,6 +295,9 @@ impl<T: 'static> EventProcessor<T> {
let window = xsel.requestor as xproto::Window;
let window_id = mkwid(window);
// Set the timestamp.
wt.xconn.set_timestamp(xsel.time as xproto::Timestamp);
if xsel.property == atoms[XdndSelection] as c_ulong {
let mut result = None;
@ -562,6 +569,10 @@ impl<T: 'static> EventProcessor<T> {
// Note that in compose/pre-edit sequences, we'll always receive KeyRelease events
ty @ ffi::KeyPress | ty @ ffi::KeyRelease => {
let xkev: &mut ffi::XKeyEvent = xev.as_mut();
// Set the timestamp.
wt.xconn.set_timestamp(xkev.time as xproto::Timestamp);
let window = match self.active_window {
Some(window) => window,
None => return,
@ -664,6 +675,10 @@ impl<T: 'static> EventProcessor<T> {
let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
let window_id = mkwid(xev.event as xproto::Window);
let device_id = mkdid(xev.deviceid);
// Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
if (xev.flags & ffi::XIPointerEmulated) != 0 {
// Deliver multi-touch events instead of emulated mouse events.
return;
@ -751,6 +766,10 @@ impl<T: 'static> EventProcessor<T> {
}
ffi::XI_Motion => {
let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
// Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
let device_id = mkdid(xev.deviceid);
let window = xev.event as xproto::Window;
let window_id = mkwid(window);
@ -838,6 +857,9 @@ impl<T: 'static> EventProcessor<T> {
ffi::XI_Enter => {
let xev: &ffi::XIEnterEvent = unsafe { &*(xev.data as *const _) };
// Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
let window = xev.event as xproto::Window;
let window_id = mkwid(window);
let device_id = mkdid(xev.deviceid);
@ -881,6 +903,9 @@ impl<T: 'static> EventProcessor<T> {
let xev: &ffi::XILeaveEvent = unsafe { &*(xev.data as *const _) };
let window = xev.event as xproto::Window;
// Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
// Leave, FocusIn, and FocusOut can be received by a window that's already
// been destroyed, which the user presumably doesn't want to deal with.
let window_closed = !self.window_exists(window);
@ -897,6 +922,9 @@ impl<T: 'static> EventProcessor<T> {
let xev: &ffi::XIFocusInEvent = unsafe { &*(xev.data as *const _) };
let window = xev.event as xproto::Window;
// Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
wt.ime
.borrow_mut()
.focus(xev.event)
@ -958,6 +986,10 @@ impl<T: 'static> EventProcessor<T> {
ffi::XI_FocusOut => {
let xev: &ffi::XIFocusOutEvent = unsafe { &*(xev.data as *const _) };
let window = xev.event as xproto::Window;
// Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
if !self.window_exists(window) {
return;
}
@ -1004,6 +1036,10 @@ impl<T: 'static> EventProcessor<T> {
ffi::XI_TouchBegin | ffi::XI_TouchUpdate | ffi::XI_TouchEnd => {
let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
// Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
let window = xev.event as xproto::Window;
let window_id = mkwid(window);
let phase = match xev.evtype {
@ -1044,6 +1080,10 @@ impl<T: 'static> EventProcessor<T> {
ffi::XI_RawButtonPress | ffi::XI_RawButtonRelease => {
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
// Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
if xev.flags & ffi::XIPointerEmulated == 0 {
callback(Event::DeviceEvent {
device_id: mkdid(xev.deviceid),
@ -1061,6 +1101,10 @@ impl<T: 'static> EventProcessor<T> {
ffi::XI_RawMotion => {
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
// Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
let did = mkdid(xev.deviceid);
let mask = unsafe {
@ -1112,6 +1156,9 @@ impl<T: 'static> EventProcessor<T> {
ffi::XI_RawKeyPress | ffi::XI_RawKeyRelease => {
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
// Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
let state = match xev.evtype {
ffi::XI_RawKeyPress => Pressed,
ffi::XI_RawKeyRelease => Released,
@ -1136,6 +1183,10 @@ impl<T: 'static> EventProcessor<T> {
ffi::XI_HierarchyChanged => {
let xev: &ffi::XIHierarchyEvent = unsafe { &*(xev.data as *const _) };
// Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
for info in
unsafe { slice::from_raw_parts(xev.info, xev.num_info as usize) }
{
@ -1168,6 +1219,10 @@ impl<T: 'static> EventProcessor<T> {
let xev = unsafe {
&*(xev as *const _ as *const ffi::XkbNewKeyboardNotifyEvent)
};
// Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
let keycodes_changed_flag = 0x1;
let geometry_changed_flag = 0x1 << 1;
@ -1186,6 +1241,9 @@ impl<T: 'static> EventProcessor<T> {
let xev =
unsafe { &*(xev as *const _ as *const ffi::XkbStateNotifyEvent) };
// Set the timestamp.
wt.xconn.set_timestamp(xev.time as xproto::Timestamp);
let prev_mods = self.kb_state.mods_state();
self.kb_state.update_modifiers(
xev.base_mods,