mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-11 05:00:16 +00:00
wayland: Refactor serial usage (#11388)
Adds a `SerialTracker` type which helps simplify serial handling. Release Notes: - N/A
This commit is contained in:
parent
3018a64a1b
commit
5486c3dc93
3 changed files with 108 additions and 26 deletions
|
@ -1,6 +1,7 @@
|
|||
mod client;
|
||||
mod cursor;
|
||||
mod display;
|
||||
mod serial;
|
||||
mod window;
|
||||
|
||||
pub(crate) use client::*;
|
||||
|
|
|
@ -55,6 +55,7 @@ use super::super::{open_uri_internal, read_fd, DOUBLE_CLICK_INTERVAL};
|
|||
use super::window::{WaylandWindowState, WaylandWindowStatePtr};
|
||||
use crate::platform::linux::is_within_click_distance;
|
||||
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::LinuxClient;
|
||||
use crate::platform::PlatformWindow;
|
||||
|
@ -124,8 +125,7 @@ impl Globals {
|
|||
}
|
||||
|
||||
pub(crate) struct WaylandClientState {
|
||||
serial: u32, // todo(linux): storing a general serial is wrong
|
||||
pointer_serial: u32,
|
||||
serial_tracker: SerialTracker,
|
||||
globals: Globals,
|
||||
wl_seat: wl_seat::WlSeat, // todo(linux): multi-seat support
|
||||
wl_pointer: Option<wl_pointer::WlPointer>,
|
||||
|
@ -315,8 +315,7 @@ impl WaylandClient {
|
|||
let cursor = Cursor::new(&conn, &globals, 24);
|
||||
|
||||
let mut state = Rc::new(RefCell::new(WaylandClientState {
|
||||
serial: 0,
|
||||
pointer_serial: 0,
|
||||
serial_tracker: SerialTracker::new(),
|
||||
globals,
|
||||
wl_seat: seat,
|
||||
wl_pointer: None,
|
||||
|
@ -414,7 +413,7 @@ impl LinuxClient for WaylandClient {
|
|||
.map_or(true, |current_style| current_style != style);
|
||||
|
||||
if need_update {
|
||||
let serial = state.pointer_serial;
|
||||
let serial = state.serial_tracker.get(SerialKind::MouseEnter);
|
||||
state.cursor_style = Some(style);
|
||||
|
||||
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());
|
||||
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.commit();
|
||||
} else {
|
||||
|
@ -692,7 +692,7 @@ impl Dispatch<xdg_toplevel::XdgToplevel, ObjectId> for WaylandClientStatePtr {
|
|||
|
||||
impl Dispatch<xdg_wm_base::XdgWmBase, ()> for WaylandClientStatePtr {
|
||||
fn event(
|
||||
this: &mut Self,
|
||||
_: &mut Self,
|
||||
wm_base: &xdg_wm_base::XdgWmBase,
|
||||
event: <xdg_wm_base::XdgWmBase as Proxy>::Event,
|
||||
_: &(),
|
||||
|
@ -700,9 +700,6 @@ impl Dispatch<xdg_wm_base::XdgWmBase, ()> for WaylandClientStatePtr {
|
|||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -802,10 +799,7 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientStatePtr {
|
|||
};
|
||||
state.keymap_state = Some(xkb::State::new(&keymap));
|
||||
}
|
||||
wl_keyboard::Event::Enter {
|
||||
serial, surface, ..
|
||||
} => {
|
||||
state.serial = serial;
|
||||
wl_keyboard::Event::Enter { surface, .. } => {
|
||||
state.keyboard_focused_window = get_window(&mut state, &surface.id());
|
||||
state.enter_token = Some(());
|
||||
|
||||
|
@ -814,10 +808,7 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientStatePtr {
|
|||
window.set_focused(true);
|
||||
}
|
||||
}
|
||||
wl_keyboard::Event::Leave {
|
||||
serial, surface, ..
|
||||
} => {
|
||||
state.serial = serial;
|
||||
wl_keyboard::Event::Leave { surface, .. } => {
|
||||
let keyboard_focused_window = get_window(&mut state, &surface.id());
|
||||
state.keyboard_focused_window = None;
|
||||
state.enter_token.take();
|
||||
|
@ -828,14 +819,12 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientStatePtr {
|
|||
}
|
||||
}
|
||||
wl_keyboard::Event::Modifiers {
|
||||
serial,
|
||||
mods_depressed,
|
||||
mods_latched,
|
||||
mods_locked,
|
||||
group,
|
||||
..
|
||||
} => {
|
||||
state.serial = serial;
|
||||
let focused_window = state.keyboard_focused_window.clone();
|
||||
let Some(focused_window) = focused_window else {
|
||||
return;
|
||||
|
@ -853,12 +842,12 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientStatePtr {
|
|||
focused_window.handle_input(input);
|
||||
}
|
||||
wl_keyboard::Event::Key {
|
||||
serial,
|
||||
key,
|
||||
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 Some(focused_window) = focused_window else {
|
||||
|
@ -971,7 +960,7 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
|
|||
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)));
|
||||
|
||||
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.serial = serial;
|
||||
state.serial_tracker.update(SerialKind::MousePress, serial);
|
||||
let button = linux_button_to_gpui(button);
|
||||
let Some(button) = button else { return };
|
||||
if state.mouse_focused_window.is_none() {
|
||||
|
@ -1299,7 +1288,7 @@ impl Dispatch<wl_data_device::WlDataDevice, ()> for WaylandClientStatePtr {
|
|||
y,
|
||||
id: data_offer,
|
||||
} => {
|
||||
state.serial = serial;
|
||||
state.serial_tracker.update(SerialKind::DataDevice, serial);
|
||||
if let Some(data_offer) = data_offer {
|
||||
let Some(drag_window) = get_window(&mut state, &surface.id()) else {
|
||||
return;
|
||||
|
@ -1429,7 +1418,8 @@ impl Dispatch<wl_data_offer::WlDataOffer, ()> for WaylandClientStatePtr {
|
|||
match event {
|
||||
wl_data_offer::Event::Offer { 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));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
91
crates/gpui/src/platform/linux/wayland/serial.rs
Normal file
91
crates/gpui/src/platform/linux/wayland/serial.rs
Normal 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
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue