From 355a9eb2402340b3026a590f5fff55b30678aad7 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Wed, 13 Mar 2024 14:16:26 +0100 Subject: [PATCH] input: add a default seat --- jay-config/src/_private.rs | 2 ++ jay-config/src/_private/client.rs | 4 ++++ jay-config/src/_private/ipc.rs | 1 + jay-config/src/input.rs | 22 ++++++++++++++++++++++ jay-config/src/lib.rs | 10 +++------- src/compositor.rs | 7 ++++++- src/config/handler.rs | 5 ++--- src/it/tests/t0005_create_seat.rs | 6 +++--- src/state.rs | 8 ++++++++ src/tasks/input_device.rs | 7 +++++++ 10 files changed, 58 insertions(+), 14 deletions(-) diff --git a/jay-config/src/_private.rs b/jay-config/src/_private.rs index 04a26cf2..cf4b6064 100644 --- a/jay-config/src/_private.rs +++ b/jay-config/src/_private.rs @@ -62,3 +62,5 @@ impl WireMode { #[derive(Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq, Hash)] pub struct PollableId(pub u64); + +pub const DEFAULT_SEAT_NAME: &str = "default"; diff --git a/jay-config/src/_private/client.rs b/jay-config/src/_private/client.rs index 305690e9..b32085c4 100644 --- a/jay-config/src/_private/client.rs +++ b/jay-config/src/_private/client.rs @@ -576,6 +576,10 @@ impl Client { self.send(&ClientMessage::SetDoubleClickDistance { dist }); } + pub fn disable_default_seat(&self) { + self.send(&ClientMessage::DisableDefaultSeat); + } + pub fn connector_set_position(&self, connector: Connector, x: i32, y: i32) { self.send(&ClientMessage::ConnectorSetPosition { connector, x, y }); } diff --git a/jay-config/src/_private/ipc.rs b/jay-config/src/_private/ipc.rs index f23896cd..cf63c823 100644 --- a/jay-config/src/_private/ipc.rs +++ b/jay-config/src/_private/ipc.rs @@ -381,6 +381,7 @@ pub enum ClientMessage<'a> { env: Vec<(String, String)>, fds: Vec<(i32, i32)>, }, + DisableDefaultSeat, } #[derive(Serialize, Deserialize, Debug)] diff --git a/jay-config/src/input.rs b/jay-config/src/input.rs index a3999ec6..d3c5091f 100644 --- a/jay-config/src/input.rs +++ b/jay-config/src/input.rs @@ -8,6 +8,7 @@ use { input::{acceleration::AccelProfile, capability::Capability}, keyboard::Keymap, Axis, Direction, ModifiedKeySym, Workspace, + _private::DEFAULT_SEAT_NAME, }, serde::{Deserialize, Serialize}, std::time::Duration, @@ -319,10 +320,20 @@ pub fn input_devices() -> Vec { /// Returns or creates a seat. /// /// Seats are identified by their name. If no seat with the name exists, a new seat will be created. +/// +/// NOTE: You should prefer [`get_default_seat`] instead. Most applications cannot handle more than +/// one seat and will only process input from one of the seats. pub fn get_seat(name: &str) -> Seat { get!(Seat(0)).get_seat(name) } +/// Returns or creates the default seat. +/// +/// This is equivalent to `get_seat("default")`. +pub fn get_default_seat() -> Seat { + get_seat(DEFAULT_SEAT_NAME) +} + /// Sets a closure to run when a new seat has been created. pub fn on_new_seat(f: F) { get!().on_new_seat(f) @@ -357,3 +368,14 @@ pub fn set_double_click_time(duration: Duration) { pub fn set_double_click_distance(distance: i32) { get!().set_double_click_distance(distance) } + +/// Disables the creation of a default seat. +/// +/// Unless this function is called at startup of the compositor, a seat called `default` +/// will automatically be created. +/// +/// When a new input device is attached and a seat called `default` exists, the input +/// device is initially attached to this seat. +pub fn disable_default_seat() { + get!().disable_default_seat(); +} diff --git a/jay-config/src/lib.rs b/jay-config/src/lib.rs index 5d618f01..5630744a 100644 --- a/jay-config/src/lib.rs +++ b/jay-config/src/lib.rs @@ -12,23 +12,19 @@ //! config!(configure); //! ``` //! -//! This configuration will not allow you to interact with the compositor at all nor exit it. +//! This configuration will not allow you to exit the compositor. //! To add at least that much functionality, add the following code to `configure`: //! //! ```rust //! use jay_config::{config, quit}; -//! use jay_config::input::{get_seat, input_devices, on_new_input_device}; +//! use jay_config::input::{get_default_seat, input_devices, on_new_input_device}; //! use jay_config::keyboard::mods::ALT; //! use jay_config::keyboard::syms::SYM_q; //! //! fn configure() { -//! // Create a seat. -//! let seat = get_seat("default"); +//! let seat = get_default_seat(); //! // Create a key binding to exit the compositor. //! seat.bind(ALT | SYM_q, || quit()); -//! // Assign all current and future input devices to this seat. -//! input_devices().into_iter().for_each(move |d| d.set_seat(seat)); -//! on_new_input_device(move |d| d.set_seat(seat)); //! } //! //! config!(configure); diff --git a/src/compositor.rs b/src/compositor.rs index dc3681a4..a226d1d7 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -39,7 +39,7 @@ use { }, ahash::AHashSet, forker::ForkerProxy, - jay_config::video::GfxApi, + jay_config::{_private::DEFAULT_SEAT_NAME, video::GfxApi}, std::{cell::Cell, env, future::Future, ops::Deref, rc::Rc, sync::Arc, time::Duration}, thiserror::Error, uapi::c, @@ -207,6 +207,7 @@ fn start_compositor2( output_transforms: Default::default(), double_click_interval_usec: Cell::new(400 * 1000), double_click_distance: Cell::new(5), + create_default_seat: Cell::new(true), }); state.tracker.register(ClientId::from_raw(0)); create_dummy_output(&state); @@ -254,6 +255,10 @@ async fn start_compositor3(state: Rc, test_future: Option) { config.configure(false); state.config.set(Some(Rc::new(config))); + if state.create_default_seat.get() && state.globals.seats.is_empty() { + state.create_seat(DEFAULT_SEAT_NAME); + } + let _geh = start_global_event_handlers(&state, &backend); state.start_xwayland(); diff --git a/src/config/handler.rs b/src/config/handler.rs index b898162d..baeb69f7 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -164,9 +164,7 @@ impl ConfigProxyHandler { return; } } - let global_name = self.state.globals.name(); - let seat = WlSeatGlobal::new(global_name, name, &self.state); - self.state.globals.add_global(&self.state, &seat); + let seat = self.state.create_seat(name); self.respond(Response::GetSeat { seat: Seat(seat.id().raw() as _), }); @@ -1516,6 +1514,7 @@ impl ConfigProxyHandler { env, fds, } => self.handle_run(prog, args, env, fds).wrn("run")?, + ClientMessage::DisableDefaultSeat => self.state.create_default_seat.set(false), } Ok(()) } diff --git a/src/it/tests/t0005_create_seat.rs b/src/it/tests/t0005_create_seat.rs index 90d1e23b..4757d76a 100644 --- a/src/it/tests/t0005_create_seat.rs +++ b/src/it/tests/t0005_create_seat.rs @@ -12,13 +12,13 @@ testcase!(); async fn test(run: Rc) -> Result<(), TestError> { let client = run.create_client().await?; - tassert!(client.registry.seats.is_empty()); + tassert_eq!(client.registry.seats.len(), 1); - let seat = run.get_seat("default")?; + let seat = run.get_seat("new-seat")?; client.sync().await; - tassert_eq!(client.registry.seats.len(), 1); + tassert_eq!(client.registry.seats.len(), 2); let client_seat = client.registry.seats.get(&seat.name()); tassert!(client_seat.is_some()); diff --git a/src/state.rs b/src/state.rs index 31062e8b..277a1918 100644 --- a/src/state.rs +++ b/src/state.rs @@ -156,6 +156,7 @@ pub struct State { pub output_transforms: RefCell, Transform>>, pub double_click_interval_usec: Cell, pub double_click_distance: Cell, + pub create_default_seat: Cell, } // impl Drop for State { @@ -924,4 +925,11 @@ impl State { capture.send_failed(); } } + + pub fn create_seat(self: &Rc, name: &str) -> Rc { + let global_name = self.globals.name(); + let seat = WlSeatGlobal::new(global_name, name, self); + self.globals.add_global(self, &seat); + seat + } } diff --git a/src/tasks/input_device.rs b/src/tasks/input_device.rs index 2d7601d5..7b57f15d 100644 --- a/src/tasks/input_device.rs +++ b/src/tasks/input_device.rs @@ -6,6 +6,7 @@ use { tasks::udev_utils::{udev_props, UdevProps}, utils::asyncevent::AsyncEvent, }, + jay_config::_private::DEFAULT_SEAT_NAME, std::{cell::Cell, rc::Rc}, }; @@ -53,6 +54,12 @@ impl DeviceHandler { let ae = self.ae.clone(); self.dev.on_change(Rc::new(move || ae.trigger())); } + for seat in self.state.globals.seats.lock().values() { + if seat.seat_name() == DEFAULT_SEAT_NAME { + self.data.seat.set(Some(seat.clone())); + break; + } + } if let Some(config) = self.state.config.get() { config.new_input_device(self.dev.id()); }