wl_proxy/client.rs
1//! Wayland clients connected to the proxy.
2
3use {
4 crate::{
5 endpoint::Endpoint, handler::HandlerHolder, object::Object,
6 protocols::wayland::wl_display::WlDisplay, state::State,
7 },
8 std::{cell::Cell, rc::Rc},
9};
10
11#[cfg(test)]
12mod tests;
13
14/// A client connected to the proxy.
15///
16/// Clients are usually created by having them connect to an
17/// [`Acceptor`](crate::acceptor::Acceptor). See [`State::create_acceptor`].
18///
19/// Clients can also be created manually with [`State::connect`] and
20/// [`State::add_client`].
21pub struct Client {
22 pub(crate) state: Rc<State>,
23 pub(crate) endpoint: Rc<Endpoint>,
24 pub(crate) display: Rc<WlDisplay>,
25 pub(crate) destroyed: Cell<bool>,
26 pub(crate) handler: HandlerHolder<dyn ClientHandler>,
27}
28
29/// A handler for events emitted by a [`Client`].
30pub trait ClientHandler: 'static {
31 /// The client disconnected.
32 ///
33 /// This is not emitted if the client is disconnected with [`Client::disconnect`].
34 fn disconnected(self: Box<Self>) {
35 // nothing
36 }
37}
38
39impl Client {
40 /// Sets a new handler.
41 pub fn set_handler(&self, handler: impl ClientHandler) {
42 self.set_boxed_handler(Box::new(handler));
43 }
44
45 /// Sets a new, already boxed handler.
46 pub fn set_boxed_handler(&self, handler: Box<dyn ClientHandler>) {
47 if self.destroyed.get() {
48 return;
49 }
50 self.handler.set(Some(handler));
51 }
52
53 /// Unsets the handler.
54 pub fn unset_handler(&self) {
55 self.handler.set(None);
56 }
57
58 /// Returns all objects associated with this client.
59 ///
60 /// This can be used when a client disconnects to perform cleanup in a multi-client
61 /// proxy.
62 pub fn objects(&self, objects: &mut Vec<Rc<dyn Object>>) {
63 objects.extend(self.endpoint.objects.borrow().values().cloned());
64 }
65
66 /// Returns the wl_display object of this client.
67 pub fn display(&self) -> &Rc<WlDisplay> {
68 &self.display
69 }
70
71 /// Disconnects this client.
72 ///
73 /// The [`ClientHandler::disconnected`] event is not emitted.
74 pub fn disconnect(&self) {
75 if self.destroyed.replace(true) {
76 return;
77 }
78 let proxies = &mut *self.state.object_stash.borrow();
79 for (_, object) in self.endpoint.objects.borrow_mut().drain() {
80 let core = object.core();
81 core.client.take();
82 core.client_id.take();
83 core.client_obj_id.take();
84 proxies.push(object);
85 }
86 self.handler.set(None);
87 self.state.remove_endpoint(&self.endpoint);
88 }
89
90 /// Suspends or unsuspends dispatching messages from the client.
91 ///
92 /// Suspending takes effect immediately. That is, if this is called from within a
93 /// message handler, no further messages from the client will be dispatched until it
94 /// is unsuspended.
95 ///
96 /// This can be useful in situations where one clients needs to synchronize with
97 /// another. For example, when a client sends `wl_surface.commit` and another client
98 /// needs to take some action before the commit is forwarded to the server.
99 pub fn set_suspended(self: &Rc<Self>, suspended: bool) {
100 self.state
101 .set_endpoint_suspended(&self.endpoint, Some(self), suspended);
102 }
103}