mod handler; #[cfg(feature = "it")] use crate::it::test_config::TEST_CONFIG_ENTRY; use { crate::{ backend::{ConnectorId, DrmDeviceId, InputDeviceId}, config::handler::ConfigProxyHandler, ifs::wl_seat::SeatId, state::State, tree::{TileState, ToplevelData, ToplevelIdentifier}, utils::{ clonecell::CloneCell, numcell::NumCell, ptr_ext::PtrExt, }, }, jay_config::{ protocol::{ ClientMessage, ConfigEntry, InitMessage, ServerFeature, ServerHandler, ServerMessage, Unref, V1InitMessage, VERSION, handle_client_message, init_client, unref_client, }, input::{InputDevice, Seat, SwitchEvent}, keyboard::{mods::Modifiers, syms::KeySym}, video::{Connector, DrmDevice}, window::{self}, }, std::{cell::Cell, mem, ptr, rc::Rc}, }; pub struct ConfigProxy { handler: CloneCell>>, } impl ConfigProxy { fn send(&self, msg: &ServerMessage) { if let Some(handler) = self.handler.get() { handler.send(msg); } } pub fn destroy(&self) { if let Some(handler) = self.handler.take() { unsafe { handler.do_drop(); (handler.unref)(handler.client_data.get()); } } } pub fn invoke_shortcut(&self, seat: SeatId, shortcut: &InvokedShortcut) { let msg = if shortcut.unmasked_mods == shortcut.effective_mods { ServerMessage::InvokeShortcut { seat: Seat(seat.raw() as _), mods: shortcut.effective_mods, sym: shortcut.sym, } } else { ServerMessage::InvokeShortcut2 { seat: Seat(seat.raw() as _), unmasked_mods: shortcut.unmasked_mods, effective_mods: shortcut.effective_mods, sym: shortcut.sym, } }; self.send(&msg); } pub fn new_drm_dev(&self, dev: DrmDeviceId) { self.send(&ServerMessage::NewDrmDev { device: DrmDevice(dev.raw() as _), }); } pub fn del_drm_dev(&self, dev: DrmDeviceId) { self.send(&ServerMessage::DelDrmDev { device: DrmDevice(dev.raw() as _), }); } pub fn new_connector(&self, connector: ConnectorId) { self.send(&ServerMessage::NewConnector { device: Connector(connector.raw() as _), }); } pub fn del_connector(&self, connector: ConnectorId) { self.send(&ServerMessage::DelConnector { device: Connector(connector.raw() as _), }); } pub fn connector_connected(&self, connector: ConnectorId) { self.send(&ServerMessage::ConnectorConnect { device: Connector(connector.raw() as _), }); } pub fn connector_disconnected(&self, connector: ConnectorId) { self.send(&ServerMessage::ConnectorDisconnect { device: Connector(connector.raw() as _), }); } pub fn new_input_device(&self, dev: InputDeviceId) { self.send(&ServerMessage::NewInputDevice { device: InputDevice(dev.raw() as _), }); } pub fn del_input_device(&self, dev: InputDeviceId) { self.send(&ServerMessage::DelInputDevice { device: InputDevice(dev.raw() as _), }); } pub fn graphics_initialized(&self) { self.send(&ServerMessage::GraphicsInitialized); } pub fn devices_enumerated(&self) { self.send(&ServerMessage::DevicesEnumerated); } pub fn clear(&self) { self.send(&ServerMessage::Clear); } pub fn idle(&self) { self.send(&ServerMessage::Idle); } pub fn switch_event(&self, seat: SeatId, input_device: InputDeviceId, event: SwitchEvent) { self.send(&ServerMessage::SwitchEvent { seat: Seat(seat.raw() as _), input_device: InputDevice(input_device.raw() as _), event, }); } pub fn toplevel_removed(&self, id: ToplevelIdentifier) { let Some(handler) = self.handler.get() else { return; }; if let Some(win) = handler.windows_from_tl_id.remove(&id) { handler.windows_to_tl_id.remove(&win); } } pub fn auto_focus(&self, data: &ToplevelData) -> bool { let Some(handler) = self.handler.get() else { return true; }; handler.auto_focus(data) } pub fn initial_tile_state(&self, data: &ToplevelData) -> Option { self.handler.get()?.initial_tile_state(data) } } impl Drop for ConfigProxy { fn drop(&mut self) { self.destroy(); } } unsafe fn default_client_init( srv_data: *const u8, srv_unref: Unref, srv_handler: ServerHandler, msg: InitMessage, ) -> *const u8 { fn configure() { jay_toml_config::configure(); } unsafe { init_client(srv_data, srv_unref, srv_handler, msg, configure) } } impl ConfigProxy { fn new(entry: &ConfigEntry, state: &Rc) -> Self { let version = entry.version.min(VERSION); let data = Rc::new(ConfigProxyHandler { client_data: Cell::new(ptr::null()), dropped: Cell::new(false), _version: version, unref: entry.unref, handle_msg: entry.handle_msg, state: state.clone(), next_id: NumCell::new(1), keymaps: Default::default(), workspace_ids: NumCell::new(1), workspaces_by_name: Default::default(), workspaces_by_id: Default::default(), timer_ids: NumCell::new(1), timers_by_name: Default::default(), timers_by_id: Default::default(), pollable_id: Default::default(), pollables: Default::default(), window_ids: NumCell::new(1), windows_from_tl_id: Default::default(), windows_to_tl_id: Default::default(), client_matcher_ids: NumCell::new(1), client_matchers: Default::default(), client_matcher_cache: Default::default(), client_matcher_leafs: Default::default(), window_matcher_ids: NumCell::new(1), window_matchers: Default::default(), window_matcher_cache: Default::default(), window_matcher_leafs: Default::default(), window_matcher_std_kinds: state.tl_matcher_manager.kind(window::CLIENT_WINDOW), window_matcher_no_auto_focus: Default::default(), window_matcher_initial_tile_state: Default::default(), }); let init_msg = InitMessage::V1(V1InitMessage {}); unsafe { let client_data = (entry.init)( Rc::into_raw(data.clone()) as _, unref, handle_msg, init_msg, ); data.client_data.set(client_data); } Self { handler: CloneCell::new(Some(data)), } } pub fn configure(&self, reload: bool) { self.send(&ServerMessage::Features { features: vec![ServerFeature::MOD_MASK, ServerFeature::SHOW_WORKSPACE_ON], }); self.send(&ServerMessage::Configure { reload }); } pub fn default(state: &Rc) -> Self { let entry = ConfigEntry { version: VERSION, init: default_client_init, unref: unref_client, handle_msg: handle_client_message, }; Self::new(&entry, state) } #[cfg(feature = "it")] pub fn for_test(state: &Rc) -> Self { Self::new(&TEST_CONFIG_ENTRY, state) } } unsafe fn unref(data: *const u8) { let server = data as *const ConfigProxyHandler; unsafe { drop(Rc::from_raw(server)); } } unsafe fn handle_msg(data: *const u8, msg: &ClientMessage<'_>) { unsafe { let server = (data as *const ConfigProxyHandler).deref(); if server.dropped.get() { return; } let rc = Rc::from_raw(server); rc.handle_request(msg); mem::forget(rc); } } pub struct InvokedShortcut { pub unmasked_mods: Modifiers, pub effective_mods: Modifiers, pub sym: KeySym, }