diff --git a/protocols.md b/protocols.md new file mode 100644 index 00000000..e9366ddb --- /dev/null +++ b/protocols.md @@ -0,0 +1,16 @@ +- wayland + - wl_compositor + - todo: version 5 + - wl_shm + - support for more formats + - wl_surface + - set_input_region + - damage + - transform + - scale + - offset + - wl_touch + - todo + +- xdg-shell + - oeuo.e diff --git a/src/client.rs b/src/client.rs index 5967aca7..385a3021 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,3 +1,4 @@ +use std::collections::VecDeque; use bstr::ByteSlice; pub use error::{ClientError, MethodError, ObjectError}; use { @@ -134,9 +135,9 @@ impl Clients { tracker: Default::default(), is_xwayland, secure, - last_serial: Cell::new(0), last_enter_serial: Cell::new(0), pid_info: get_pid_info(uid, pid), + serials: Default::default(), }); track!(data, data); let display = Rc::new(WlDisplay::new(&data)); @@ -241,9 +242,16 @@ pub struct Client { pub tracker: Tracker, pub is_xwayland: bool, pub secure: bool, - pub last_serial: Cell, pub last_enter_serial: Cell, pub pid_info: PidInfo, + pub serials: RefCell>, +} + +pub const NUM_CACHED_SERIAL_RANGES: usize = 64; + +pub struct SerialRange { + pub lo: u32, + pub hi: u32, } impl Client { @@ -271,12 +279,17 @@ impl Client { } } - pub fn validate_serial(&self, serial: u32) -> Result<(), ClientError> { - if serial > self.last_serial.get() { - Err(ClientError::InvalidSerial) - } else { - Ok(()) + pub fn valid_serial(&self, serial: u32) -> bool { + let serials = self.serials.borrow_mut(); + for range in serials.iter().rev() { + if serial.wrapping_sub(range.hi) as i32 > 0 { + return false; + } + if serial.wrapping_sub(range.lo) as i32 >= 0 { + return true; + } } + serials.len() == NUM_CACHED_SERIAL_RANGES } pub fn next_serial(&self) -> u32 { diff --git a/src/client/error.rs b/src/client/error.rs index 8affc77c..54b4b9de 100644 --- a/src/client/error.rs +++ b/src/client/error.rs @@ -12,8 +12,6 @@ use { #[derive(Debug, Error)] pub enum ClientError { - #[error("Client sent an invalid serial")] - InvalidSerial, #[error("An error occurred in the async engine")] Async(#[from] AsyncError), #[error("An error occurred reading from/writing to the client")] diff --git a/src/ifs/ipc/wl_data_device.rs b/src/ifs/ipc/wl_data_device.rs index b3d3d61c..c1eb6cf0 100644 --- a/src/ifs/ipc/wl_data_device.rs +++ b/src/ifs/ipc/wl_data_device.rs @@ -94,7 +94,10 @@ impl WlDataDevice { fn start_drag(&self, parser: MsgParser<'_, '_>) -> Result<(), StartDragError> { let req: StartDrag = self.manager.client.parse(self, parser)?; - self.manager.client.validate_serial(req.serial)?; + if !self.manager.client.valid_serial(req.serial) { + log::warn!("Client tried to start_drag with an invalid serial"); + return Ok(()); + } let origin = self.manager.client.lookup(req.origin)?; let source = if req.source.is_some() { Some(self.manager.client.lookup(req.source)?) @@ -116,7 +119,10 @@ impl WlDataDevice { fn set_selection(&self, parser: MsgParser<'_, '_>) -> Result<(), SetSelectionError> { let req: SetSelection = self.manager.client.parse(self, parser)?; - self.manager.client.validate_serial(req.serial)?; + if !self.manager.client.valid_serial(req.serial) { + log::warn!("Client tried to set_selection with an invalid serial"); + return Ok(()); + } if !self .seat .global diff --git a/src/ifs/ipc/zwp_primary_selection_device_v1.rs b/src/ifs/ipc/zwp_primary_selection_device_v1.rs index 9d5766cd..fa4d2025 100644 --- a/src/ifs/ipc/zwp_primary_selection_device_v1.rs +++ b/src/ifs/ipc/zwp_primary_selection_device_v1.rs @@ -63,7 +63,10 @@ impl ZwpPrimarySelectionDeviceV1 { fn set_selection(&self, parser: MsgParser<'_, '_>) -> Result<(), SetSelectionError> { let req: SetSelection = self.manager.client.parse(self, parser)?; - self.seat.client.validate_serial(req.serial)?; + if !self.manager.client.valid_serial(req.serial) { + log::warn!("Client tried to set_selection with an invalid serial"); + return Ok(()); + } if !self .seat .global diff --git a/src/ifs/wl_seat/kb_owner.rs b/src/ifs/wl_seat/kb_owner.rs index 258ad579..8dea3e1a 100644 --- a/src/ifs/wl_seat/kb_owner.rs +++ b/src/ifs/wl_seat/kb_owner.rs @@ -60,7 +60,7 @@ impl KbOwner for DefaultKbOwner { if old.node_id() == node.node_id() { return; } - log::info!("unfocus {}", old.node_id()); + // log::info!("unfocus {}", old.node_id()); if old.node_is_xwayland_surface() && !node.node_is_xwayland_surface() { seat.state.xwayland.queue.push(XWaylandEvent::ActivateRoot); } @@ -72,7 +72,7 @@ impl KbOwner for DefaultKbOwner { if node.node_seat_state().focus(seat) { node.node_active_changed(true); } - log::info!("focus {}", node.node_id()); + // log::info!("focus {}", node.node_id()); node.clone().node_focus(seat); seat.keyboard_node.set(node.clone()); } diff --git a/src/ifs/wl_seat/wl_pointer.rs b/src/ifs/wl_seat/wl_pointer.rs index b380b7ea..b642ee27 100644 --- a/src/ifs/wl_seat/wl_pointer.rs +++ b/src/ifs/wl_seat/wl_pointer.rs @@ -156,7 +156,10 @@ impl WlPointer { fn set_cursor(&self, parser: MsgParser<'_, '_>) -> Result<(), SetCursorError> { let req: SetCursor = self.seat.client.parse(self, parser)?; - self.seat.client.validate_serial(req.serial)?; + if !self.seat.client.valid_serial(req.serial) { + log::warn!("Client tried to set_cursor with an invalid serial"); + return Ok(()); + } let mut cursor_opt = None; if req.surface.is_some() { let surface = self.seat.client.lookup(req.surface)?; diff --git a/src/ifs/wl_surface/zwp_idle_inhibitor_v1.rs b/src/ifs/wl_surface/zwp_idle_inhibitor_v1.rs index 45c177cb..c5caae93 100644 --- a/src/ifs/wl_surface/zwp_idle_inhibitor_v1.rs +++ b/src/ifs/wl_surface/zwp_idle_inhibitor_v1.rs @@ -5,7 +5,7 @@ use { leaks::Tracker, object::Object, utils::buffd::{MsgParser, MsgParserError}, - wire::{zwp_idle_inhibitor_v1::*, WlSurfaceId, ZwpIdleInhibitorV1Id}, + wire::{zwp_idle_inhibitor_v1::*, ZwpIdleInhibitorV1Id}, }, std::rc::Rc, thiserror::Error, @@ -23,6 +23,7 @@ pub struct ZwpIdleInhibitorV1 { impl ZwpIdleInhibitorV1 { fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), ZwpIdleInhibitorV1Error> { + log::info!("destroy {}", self.id); let _req: Destroy = self.client.parse(self, parser)?; self.client.remove_obj(self)?; if self.surface.idle_inhibitors.remove(&self.id).is_some() { diff --git a/src/ifs/zwp_idle_inhibit_manager_v1.rs b/src/ifs/zwp_idle_inhibit_manager_v1.rs index ee7dd835..333d52de 100644 --- a/src/ifs/zwp_idle_inhibit_manager_v1.rs +++ b/src/ifs/zwp_idle_inhibit_manager_v1.rs @@ -80,6 +80,7 @@ impl ZwpIdleInhibitManagerV1 { ) -> Result<(), ZwpIdleInhibitManagerV1Error> { let req: CreateInhibitor = self.client.parse(self, parser)?; let surface = self.client.lookup(req.surface)?; + log::info!("create {}", req.id); let inhibit = Rc::new(ZwpIdleInhibitorV1 { id: req.id, inhibit_id: self.client.state.idle_inhibitor_ids.next(), diff --git a/src/state.rs b/src/state.rs index b7d55326..9ef0af70 100644 --- a/src/state.rs +++ b/src/state.rs @@ -47,6 +47,7 @@ use { time::Duration, }, }; +use crate::client::{NUM_CACHED_SERIAL_RANGES, SerialRange}; pub struct State { pub xkb_ctx: XkbContext, @@ -359,8 +360,23 @@ impl State { pub fn next_serial(&self, client: Option<&Client>) -> u32 { let serial = self.serial.fetch_add(Wrapping(1)).0; if let Some(client) = client { - client.last_serial.set(serial); + 'update_range: { + let mut serials = client.serials.borrow_mut(); + if let Some(last) = serials.back_mut() { + if last.hi.wrapping_add(1) == serial { + last.hi = serial; + break 'update_range; + } + } + if serials.len() >= NUM_CACHED_SERIAL_RANGES { + serials.pop_front(); + } + serials.push_back(SerialRange { + lo: serial, + hi: serial, + }); + } } - serial + serial as _ } } diff --git a/src/xwayland/xwm.rs b/src/xwayland/xwm.rs index 543b4196..452f2789 100644 --- a/src/xwayland/xwm.rs +++ b/src/xwayland/xwm.rs @@ -435,9 +435,9 @@ impl Wm { } async fn focus_window(&mut self, window: Option<&Rc>) { - log::info!("xwm focus_window {:?}", window.map(|w| w.window_id)); + // log::info!("xwm focus_window {:?}", window.map(|w| w.window_id)); if let Some(old) = mem::replace(&mut self.focus_window, window.cloned()) { - log::info!("xwm unfocus {:?}", old.window_id); + // log::info!("xwm unfocus {:?}", old.window_id); self.set_net_wm_state(&old).await; } let window = match window { @@ -458,7 +458,7 @@ impl Wm { } }; if window.info.override_redirect.get() { - log::info!("xwm or => return"); + // log::info!("xwm or => return"); return; } if let Some(window) = window.window.get() { @@ -558,7 +558,7 @@ impl Wm { return; } } - log::info!("{} role {}", data.window_id, buf.as_bstr()); + // log::info!("{} role {}", data.window_id, buf.as_bstr()); *data.info.role.borrow_mut() = Some(buf.into()); } @@ -995,13 +995,13 @@ impl Wm { async fn handle_focus_in(&mut self, revent: &Event) -> Result<(), XWaylandError> { let event: FocusIn = revent.parse()?; - log::info!("xwm focus_in {}", event.event); + // log::info!("xwm focus_in {}", event.event); if matches!(event.mode, NOTIFY_MODE_GRAB | NOTIFY_MODE_UNGRAB) { - log::info!("xwm GRAB/UNGRAB"); + // log::info!("xwm GRAB/UNGRAB"); return Ok(()); } if matches!(event.detail, NOTIFY_DETAIL_POINTER) { - log::info!("xwm POINTER"); + // log::info!("xwm POINTER"); return Ok(()); } let new_window = self.windows.get(&event.event); @@ -1014,7 +1014,7 @@ impl Wm { && prev_pid == new_pid && revent.serial() >= self.last_input_serial { - log::info!("xwm ACCEPT"); + // log::info!("xwm ACCEPT"); focus_window = new_window; } } @@ -1036,7 +1036,7 @@ impl Wm { } async fn activate_window(&mut self, window: Option<&Rc>) { - log::info!("xwm activate_window {:?}", window.map(|w| w.window_id)); + // log::info!("xwm activate_window {:?}", window.map(|w| w.window_id)); if self.focus_window.as_ref().map(|w| w.window_id) == window.map(|w| w.window_id) { return; } @@ -1126,7 +1126,7 @@ impl Wm { Some(w) => w, _ => return Ok(()), }; - log::info!("xwm destroy_notify {}", event.window); + // log::info!("xwm destroy_notify {}", event.window); data.destroyed.set(true); if let Some(sid) = data.surface_id.take() { self.windows_by_surface_id.remove(&sid); diff --git a/todo.md b/todo.md index 45acb43e..da9a8a72 100644 --- a/todo.md +++ b/todo.md @@ -7,6 +7,7 @@ # done +- idle inhibit - layer shell - Float moving - Float toggle