1
0
Fork 0
forked from wry/wry

config: add Client

This commit is contained in:
Julian Orth 2025-05-02 19:24:43 +02:00
parent 52994c085a
commit ab095b89cf
6 changed files with 133 additions and 11 deletions

View file

@ -10,6 +10,7 @@ use {
logging,
},
Axis, Direction, ModifiedKeySym, PciId, Workspace,
client::Client,
exec::Command,
input::{
FocusFollowsMouseMode, InputDevice, Seat, SwitchEvent, acceleration::AccelProfile,
@ -81,7 +82,7 @@ struct KeyHandler {
latched: Vec<Box<dyn FnOnce()>>,
}
pub(crate) struct Client {
pub(crate) struct ConfigClient {
configure: extern "C" fn(),
srv_data: *const u8,
srv_unref: unsafe extern "C" fn(data: *const u8),
@ -145,7 +146,7 @@ struct Task {
waker: Waker,
}
impl Drop for Client {
impl Drop for ConfigClient {
fn drop(&mut self) {
unsafe {
(self.srv_unref)(self.srv_data);
@ -154,13 +155,13 @@ impl Drop for Client {
}
thread_local! {
pub(crate) static CLIENT: Cell<*const Client> = const { Cell::new(ptr::null()) };
pub(crate) static CLIENT: Cell<*const ConfigClient> = const { Cell::new(ptr::null()) };
}
unsafe fn with_client<T, F: FnOnce(&Client) -> T>(data: *const u8, f: F) -> T {
unsafe fn with_client<T, F: FnOnce(&ConfigClient) -> T>(data: *const u8, f: F) -> T {
struct Reset<'a> {
cell: &'a Cell<*const Client>,
val: *const Client,
cell: &'a Cell<*const ConfigClient>,
val: *const ConfigClient,
}
impl Drop for Reset<'_> {
fn drop(&mut self) {
@ -168,7 +169,7 @@ unsafe fn with_client<T, F: FnOnce(&Client) -> T>(data: *const u8, f: F) -> T {
}
}
CLIENT.with(|cell| unsafe {
let client = data as *const Client;
let client = data as *const ConfigClient;
Rc::increment_strong_count(client);
let client = Rc::from_raw(client);
let old = cell.replace(client.deref());
@ -214,7 +215,7 @@ pub unsafe extern "C" fn init(
size: usize,
f: extern "C" fn(),
) -> *const u8 {
let client = Rc::new(Client {
let client = Rc::new(ConfigClient {
configure: f,
srv_data,
srv_unref,
@ -251,7 +252,7 @@ pub unsafe extern "C" fn init(
}
pub unsafe extern "C" fn unref(data: *const u8) {
let client = data as *const Client;
let client = data as *const ConfigClient;
unsafe {
drop(Rc::from_raw(client));
}
@ -278,7 +279,7 @@ macro_rules! get_response {
}
}
impl Client {
impl ConfigClient {
fn send(&self, msg: &ClientMessage) {
let mut buf = self.bufs.borrow_mut().pop().unwrap_or_default();
buf.clear();
@ -1259,6 +1260,28 @@ impl Client {
}
}
pub fn clients(&self) -> Vec<Client> {
let res = self.send_with_response(&ClientMessage::GetClients);
get_response!(res, vec!(), GetClients { clients });
clients
}
pub fn client_exists(&self, client: Client) -> bool {
let res = self.send_with_response(&ClientMessage::ClientExists { client });
get_response!(res, false, ClientExists { exists });
exists
}
pub fn client_is_xwayland(&self, client: Client) -> bool {
let res = self.send_with_response(&ClientMessage::ClientIsXwayland { client });
get_response!(res, false, ClientIsXwayland { is_xwayland });
is_xwayland
}
pub fn client_kill(&self, client: Client) {
self.send(&ClientMessage::ClientKill { client });
}
fn handle_msg(&self, msg: &[u8]) {
self.handle_msg2(msg);
self.dispatch_futures();

View file

@ -2,6 +2,7 @@ use {
crate::{
_private::{PollableId, WireMode},
Axis, Direction, PciId, Workspace,
client::Client,
input::{
FocusFollowsMouseMode, InputDevice, Seat, SwitchEvent, acceleration::AccelProfile,
capability::Capability,
@ -565,6 +566,16 @@ pub enum ClientMessage<'a> {
GetConnectorWorkspaces {
connector: Connector,
},
GetClients,
ClientExists {
client: Client,
},
ClientKill {
client: Client,
},
ClientIsXwayland {
client: Client,
},
}
#[derive(Serialize, Deserialize, Debug)]
@ -728,6 +739,15 @@ pub enum Response {
GetConnectorWorkspaces {
workspaces: Vec<Workspace>,
},
GetClients {
clients: Vec<Client>,
},
ClientExists {
exists: bool,
},
ClientIsXwayland {
is_xwayland: bool,
},
}
#[derive(Serialize, Deserialize, Debug)]

36
jay-config/src/client.rs Normal file
View file

@ -0,0 +1,36 @@
//! Tools for inspecting and manipulating clients.
use serde::{Deserialize, Serialize};
/// A client connected to the compositor.
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct Client(pub u64);
impl Client {
/// Returns whether the client exists.
pub fn exists(self) -> bool {
self.0 != 0 && get!(false).client_exists(self)
}
/// Returns whether the client does not exist.
///
/// This is a shorthand for `!self.exists()`.
pub fn does_not_exist(self) -> bool {
!self.exists()
}
/// Returns whether this client is XWayland.
pub fn is_xwayland(self) -> bool {
get!(false).client_is_xwayland(self)
}
/// Disconnects the client.
pub fn kill(self) {
get!().client_kill(self)
}
}
/// Returns all current clients.
pub fn clients() -> Vec<Client> {
get!().clients()
}

View file

@ -58,6 +58,7 @@ use {
mod macros;
#[doc(hidden)]
pub mod _private;
pub mod client;
pub mod embedded;
pub mod exec;
pub mod input;

View file

@ -106,7 +106,6 @@ impl Clients {
ClientId(self.next_client_id.fetch_add(1))
}
#[cfg_attr(not(feature = "it"), expect(dead_code))]
pub fn get(&self, id: ClientId) -> Result<Rc<Client>, ClientError> {
let clients = self.clients.borrow();
match clients.get(&id) {

View file

@ -5,6 +5,7 @@ use {
self, BackendColorSpace, BackendTransferFunction, ConnectorId, DrmDeviceId,
InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId,
},
client::{Client, ClientId},
cmm::cmm_transfer_function::TransferFunction,
compositor::MAX_EXTENTS,
config::ConfigProxy,
@ -38,6 +39,7 @@ use {
ipc::{ClientMessage, Response, ServerMessage, WorkspaceSource},
},
Axis, Direction, Workspace,
client::Client as ConfigClient,
input::{
FocusFollowsMouseMode, InputDevice, Seat,
acceleration::{ACCEL_PROFILE_ADAPTIVE, ACCEL_PROFILE_FLAT, AccelProfile},
@ -1717,6 +1719,39 @@ impl ConfigProxyHandler {
self.keymaps.remove(&keymap);
}
fn get_client(&self, client: ConfigClient) -> Result<Rc<Client>, CphError> {
self.state
.clients
.get(ClientId::from_raw(client.0))
.ok()
.ok_or(CphError::ClientDoesNotExist(client))
}
fn handle_get_clients(&self) {
let mut clients = vec![];
for client in self.state.clients.clients.borrow().values() {
clients.push(ConfigClient(client.data.id.raw()));
}
self.respond(Response::GetClients { clients });
}
fn handle_client_exists(&self, client: ConfigClient) {
self.respond(Response::ClientExists {
exists: self.get_client(client).is_ok(),
});
}
fn handle_client_is_xwayland(&self, client: ConfigClient) -> Result<(), CphError> {
self.respond(Response::ClientIsXwayland {
is_xwayland: self.get_client(client)?.is_xwayland,
});
Ok(())
}
fn handle_client_kill(&self, client: ConfigClient) {
self.state.clients.kill(ClientId::from_raw(client.0));
}
pub fn handle_request(self: &Rc<Self>, msg: &[u8]) {
if let Err(e) = self.handle_request_(msg) {
log::error!("Could not handle client request: {}", ErrorFmt(e));
@ -2130,6 +2165,12 @@ impl ConfigProxyHandler {
ClientMessage::GetConnectorWorkspaces { connector } => self
.handle_get_connector_workspaces(connector)
.wrn("get_connector_workspaces")?,
ClientMessage::GetClients => self.handle_get_clients(),
ClientMessage::ClientExists { client } => self.handle_client_exists(client),
ClientMessage::ClientIsXwayland { client } => self
.handle_client_is_xwayland(client)
.wrn("client_is_xwayland")?,
ClientMessage::ClientKill { client } => self.handle_client_kill(client),
}
Ok(())
}
@ -2205,6 +2246,8 @@ enum CphError {
UnknownColorSpace(ColorSpace),
#[error("Unknown transfer function {0:?}")]
UnknownTransferFunction(ConfigTransferFunction),
#[error("Client {0:?} does not exist")]
ClientDoesNotExist(ConfigClient),
}
trait WithRequestName {