wayland: Refactor serial usage (#11388)

Adds a `SerialTracker` type which helps simplify serial handling.

Release Notes:

- N/A
This commit is contained in:
apricotbucket28 2024-05-06 17:15:42 -03:00 committed by GitHub
parent 3018a64a1b
commit 5486c3dc93
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 108 additions and 26 deletions

View file

@ -1,6 +1,7 @@
mod client; mod client;
mod cursor; mod cursor;
mod display; mod display;
mod serial;
mod window; mod window;
pub(crate) use client::*; pub(crate) use client::*;

View file

@ -55,6 +55,7 @@ use super::super::{open_uri_internal, read_fd, DOUBLE_CLICK_INTERVAL};
use super::window::{WaylandWindowState, WaylandWindowStatePtr}; use super::window::{WaylandWindowState, WaylandWindowStatePtr};
use crate::platform::linux::is_within_click_distance; use crate::platform::linux::is_within_click_distance;
use crate::platform::linux::wayland::cursor::Cursor; use crate::platform::linux::wayland::cursor::Cursor;
use crate::platform::linux::wayland::serial::{SerialKind, SerialTracker};
use crate::platform::linux::wayland::window::WaylandWindow; use crate::platform::linux::wayland::window::WaylandWindow;
use crate::platform::linux::LinuxClient; use crate::platform::linux::LinuxClient;
use crate::platform::PlatformWindow; use crate::platform::PlatformWindow;
@ -124,8 +125,7 @@ impl Globals {
} }
pub(crate) struct WaylandClientState { pub(crate) struct WaylandClientState {
serial: u32, // todo(linux): storing a general serial is wrong serial_tracker: SerialTracker,
pointer_serial: u32,
globals: Globals, globals: Globals,
wl_seat: wl_seat::WlSeat, // todo(linux): multi-seat support wl_seat: wl_seat::WlSeat, // todo(linux): multi-seat support
wl_pointer: Option<wl_pointer::WlPointer>, wl_pointer: Option<wl_pointer::WlPointer>,
@ -315,8 +315,7 @@ impl WaylandClient {
let cursor = Cursor::new(&conn, &globals, 24); let cursor = Cursor::new(&conn, &globals, 24);
let mut state = Rc::new(RefCell::new(WaylandClientState { let mut state = Rc::new(RefCell::new(WaylandClientState {
serial: 0, serial_tracker: SerialTracker::new(),
pointer_serial: 0,
globals, globals,
wl_seat: seat, wl_seat: seat,
wl_pointer: None, wl_pointer: None,
@ -414,7 +413,7 @@ impl LinuxClient for WaylandClient {
.map_or(true, |current_style| current_style != style); .map_or(true, |current_style| current_style != style);
if need_update { if need_update {
let serial = state.pointer_serial; let serial = state.serial_tracker.get(SerialKind::MouseEnter);
state.cursor_style = Some(style); state.cursor_style = Some(style);
if let Some(cursor_shape_device) = &state.cursor_shape_device { if let Some(cursor_shape_device) = &state.cursor_shape_device {
@ -440,7 +439,8 @@ impl LinuxClient for WaylandClient {
) { ) {
state.pending_open_uri = Some(uri.to_owned()); state.pending_open_uri = Some(uri.to_owned());
let token = activation.get_activation_token(&state.globals.qh, ()); let token = activation.get_activation_token(&state.globals.qh, ());
token.set_serial(state.serial, &state.wl_seat); let serial = state.serial_tracker.get(SerialKind::MousePress);
token.set_serial(serial, &state.wl_seat);
token.set_surface(&window.surface()); token.set_surface(&window.surface());
token.commit(); token.commit();
} else { } else {
@ -692,7 +692,7 @@ impl Dispatch<xdg_toplevel::XdgToplevel, ObjectId> for WaylandClientStatePtr {
impl Dispatch<xdg_wm_base::XdgWmBase, ()> for WaylandClientStatePtr { impl Dispatch<xdg_wm_base::XdgWmBase, ()> for WaylandClientStatePtr {
fn event( fn event(
this: &mut Self, _: &mut Self,
wm_base: &xdg_wm_base::XdgWmBase, wm_base: &xdg_wm_base::XdgWmBase,
event: <xdg_wm_base::XdgWmBase as Proxy>::Event, event: <xdg_wm_base::XdgWmBase as Proxy>::Event,
_: &(), _: &(),
@ -700,9 +700,6 @@ impl Dispatch<xdg_wm_base::XdgWmBase, ()> for WaylandClientStatePtr {
_: &QueueHandle<Self>, _: &QueueHandle<Self>,
) { ) {
if let xdg_wm_base::Event::Ping { serial } = event { if let xdg_wm_base::Event::Ping { serial } = event {
let client = this.get_client();
let mut state = client.borrow_mut();
state.serial = serial;
wm_base.pong(serial); wm_base.pong(serial);
} }
} }
@ -802,10 +799,7 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientStatePtr {
}; };
state.keymap_state = Some(xkb::State::new(&keymap)); state.keymap_state = Some(xkb::State::new(&keymap));
} }
wl_keyboard::Event::Enter { wl_keyboard::Event::Enter { surface, .. } => {
serial, surface, ..
} => {
state.serial = serial;
state.keyboard_focused_window = get_window(&mut state, &surface.id()); state.keyboard_focused_window = get_window(&mut state, &surface.id());
state.enter_token = Some(()); state.enter_token = Some(());
@ -814,10 +808,7 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientStatePtr {
window.set_focused(true); window.set_focused(true);
} }
} }
wl_keyboard::Event::Leave { wl_keyboard::Event::Leave { surface, .. } => {
serial, surface, ..
} => {
state.serial = serial;
let keyboard_focused_window = get_window(&mut state, &surface.id()); let keyboard_focused_window = get_window(&mut state, &surface.id());
state.keyboard_focused_window = None; state.keyboard_focused_window = None;
state.enter_token.take(); state.enter_token.take();
@ -828,14 +819,12 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientStatePtr {
} }
} }
wl_keyboard::Event::Modifiers { wl_keyboard::Event::Modifiers {
serial,
mods_depressed, mods_depressed,
mods_latched, mods_latched,
mods_locked, mods_locked,
group, group,
.. ..
} => { } => {
state.serial = serial;
let focused_window = state.keyboard_focused_window.clone(); let focused_window = state.keyboard_focused_window.clone();
let Some(focused_window) = focused_window else { let Some(focused_window) = focused_window else {
return; return;
@ -853,12 +842,12 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientStatePtr {
focused_window.handle_input(input); focused_window.handle_input(input);
} }
wl_keyboard::Event::Key { wl_keyboard::Event::Key {
serial,
key, key,
state: WEnum::Value(key_state), state: WEnum::Value(key_state),
serial,
.. ..
} => { } => {
state.serial = serial; state.serial_tracker.update(SerialKind::KeyPress, serial);
let focused_window = state.keyboard_focused_window.clone(); let focused_window = state.keyboard_focused_window.clone();
let Some(focused_window) = focused_window else { let Some(focused_window) = focused_window else {
@ -971,7 +960,7 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
surface_y, surface_y,
.. ..
} => { } => {
state.pointer_serial = serial; state.serial_tracker.update(SerialKind::MouseEnter, serial);
state.mouse_location = Some(point(px(surface_x as f32), px(surface_y as f32))); state.mouse_location = Some(point(px(surface_x as f32), px(surface_y as f32)));
if let Some(window) = get_window(&mut state, &surface.id()) { if let Some(window) = get_window(&mut state, &surface.id()) {
@ -1041,7 +1030,7 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
state: WEnum::Value(button_state), state: WEnum::Value(button_state),
.. ..
} => { } => {
state.serial = serial; state.serial_tracker.update(SerialKind::MousePress, serial);
let button = linux_button_to_gpui(button); let button = linux_button_to_gpui(button);
let Some(button) = button else { return }; let Some(button) = button else { return };
if state.mouse_focused_window.is_none() { if state.mouse_focused_window.is_none() {
@ -1299,7 +1288,7 @@ impl Dispatch<wl_data_device::WlDataDevice, ()> for WaylandClientStatePtr {
y, y,
id: data_offer, id: data_offer,
} => { } => {
state.serial = serial; state.serial_tracker.update(SerialKind::DataDevice, serial);
if let Some(data_offer) = data_offer { if let Some(data_offer) = data_offer {
let Some(drag_window) = get_window(&mut state, &surface.id()) else { let Some(drag_window) = get_window(&mut state, &surface.id()) else {
return; return;
@ -1429,7 +1418,8 @@ impl Dispatch<wl_data_offer::WlDataOffer, ()> for WaylandClientStatePtr {
match event { match event {
wl_data_offer::Event::Offer { mime_type } => { wl_data_offer::Event::Offer { mime_type } => {
if mime_type == FILE_LIST_MIME_TYPE { if mime_type == FILE_LIST_MIME_TYPE {
data_offer.accept(state.serial, Some(mime_type)); let serial = state.serial_tracker.get(SerialKind::DataDevice);
data_offer.accept(serial, Some(mime_type));
} }
} }
_ => {} _ => {}

View file

@ -0,0 +1,91 @@
use std::time::Instant;
use collections::HashMap;
#[derive(Debug, Hash, PartialEq, Eq)]
pub(crate) enum SerialKind {
DataDevice,
MouseEnter,
MousePress,
KeyPress,
}
#[derive(Debug)]
struct SerialData {
serial: u32,
time: Instant,
}
impl SerialData {
fn new(value: u32) -> Self {
Self {
serial: value,
time: Instant::now(),
}
}
}
#[derive(Debug)]
/// Helper for tracking of different serial kinds.
pub(crate) struct SerialTracker {
serials: HashMap<SerialKind, SerialData>,
}
impl SerialTracker {
pub fn new() -> Self {
Self {
serials: HashMap::default(),
}
}
pub fn update(&mut self, kind: SerialKind, value: u32) {
self.serials.insert(kind, SerialData::new(value));
}
/// Returns the latest tracked serial of the provided [`SerialKind`]
///
/// Will return 0 if not tracked.
pub fn get(&self, kind: SerialKind) -> u32 {
self.serials
.get(&kind)
.map(|serial_data| serial_data.serial)
.unwrap_or(0)
}
/// Returns the newest serial of any of the provided [`SerialKind`]
pub fn get_newest_of(&self, kinds: &[SerialKind]) -> u32 {
kinds
.iter()
.filter_map(|kind| self.serials.get(&kind))
.max_by_key(|serial_data| serial_data.time)
.map(|serial_data| serial_data.serial)
.unwrap_or(0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_serial_tracker() {
let mut tracker = SerialTracker::new();
tracker.update(SerialKind::KeyPress, 100);
tracker.update(SerialKind::MousePress, 50);
tracker.update(SerialKind::MouseEnter, 300);
assert_eq!(
tracker.get_newest_of(&[SerialKind::KeyPress, SerialKind::MousePress]),
50
);
assert_eq!(tracker.get(SerialKind::DataDevice), 0);
tracker.update(SerialKind::KeyPress, 2000);
assert_eq!(tracker.get(SerialKind::KeyPress), 2000);
assert_eq!(
tracker.get_newest_of(&[SerialKind::KeyPress, SerialKind::MousePress]),
2000
);
}
}