wl_proxy/
lib.rs

1#![expect(
2    clippy::single_char_add_str,
3    clippy::manual_is_multiple_of,
4    clippy::manual_div_ceil
5)]
6
7//! This crate can be used to proxy wayland connections and manipulate wayland messages.
8//!
9//! # Example
10//!
11//! This example spawns mpv and hides the wp_fifo_manager_v1 global from it.
12//!
13//! ```no_run
14//! use std::process::Command;
15//! use std::rc::Rc;
16//! use wl_proxy::baseline::Baseline;
17//! use wl_proxy::global_mapper::GlobalMapper;
18//! use wl_proxy::object::Object;
19//! use wl_proxy::protocols::ObjectInterface;
20//! use wl_proxy::protocols::wayland::wl_display::{WlDisplay, WlDisplayHandler};
21//! use wl_proxy::protocols::wayland::wl_region::WlRegionHandler;
22//! use wl_proxy::protocols::wayland::wl_registry::{WlRegistry, WlRegistryHandler};
23//! use wl_proxy::simple::{SimpleProxy, SimpleCommandExt};
24//!
25//! // SimpleProxy is a helper type that creates one proxy per client and runs the proxy
26//! // in a thread.
27//! // Baselines are used to limit the protocols exposed by the proxy. This allows
28//! // semver-compatible updates of this crate to add new protocols and protocol versions
29//! // without causing protocol errors in existing proxies. Since this proxy is very
30//! // simple, we just expose all protocols supported by the crate.
31//! let proxy = SimpleProxy::new(Baseline::ALL_OF_THEM).unwrap();
32//! // This starts mpv and spawns a thread that waits for mpv to exit. When mpv exits,
33//! // the thread also calls exit to forward the exit code.
34//! Command::new("mpv")
35//!     .with_wayland_display(proxy.display())
36//!     .spawn_and_forward_exit_code()
37//!     .unwrap();
38//! // The closure is invoked once for each client that connects and must return a
39//! // WlDisplayHandler.
40//! // This function does not return unless there is a fatal error.
41//! proxy.run(|| Display);
42//!
43//! struct Display;
44//!
45//! impl WlDisplayHandler for Display {
46//!     // This function is invoked when the client sends a get_registry request.
47//!     fn handle_get_registry(&mut self, slf: &Rc<WlDisplay>, registry: &Rc<WlRegistry>) {
48//!         // Forward the request to the compositor.
49//!         slf.send_get_registry(registry);
50//!         // Install a message handler for the registry.
51//!         registry.set_handler(Registry::default());
52//!     }
53//! }
54//!
55//! #[derive(Default)]
56//! struct Registry {
57//!     // This helper allows the proxy to easily filter compositor globals and to
58//!     // announce its own globals.
59//!     filter: GlobalMapper,
60//! }
61//!
62//! impl WlRegistryHandler for Registry {
63//!     // This function is invoked when the client sends a bind request.
64//!     fn handle_bind(&mut self, slf: &Rc<WlRegistry>, name: u32, id: Rc<dyn Object>) {
65//!         // This function forwards the bind request to the compositor.
66//!         self.filter.forward_bind(slf, name, &id);
67//!     }
68//!
69//!     // This function is invoked when the compositor sends a global event.
70//!     fn handle_global(&mut self, slf: &Rc<WlRegistry>, name: u32, interface: ObjectInterface, version: u32) {
71//!         if interface == ObjectInterface::WpFifoManagerV1 {
72//!             // This function does not forward the global to the client and marks it
73//!             // as ignored so that the corresponding global_remove event can be
74//!             // filtered as well.
75//!             self.filter.ignore_global(name);
76//!         } else {
77//!             // This function forwards the global to the client.
78//!             self.filter.forward_global(slf, name, interface, version);
79//!         }
80//!     }
81//!
82//!     fn handle_global_remove(&mut self, slf: &Rc<WlRegistry>, name: u32) {
83//!         self.filter.forward_global_remove(slf, name);
84//!     }
85//! }
86//! ```
87//!
88//! A more complex proxy might not use [`SimpleProxy`](simple::SimpleProxy) and could
89//! instead construct [`State`](state::State) objects manually. These objects can be
90//! polled with an external mechanism such as epoll and therefore integrate into existing
91//! event loops. They allow multiple client connections to be proxied over the same
92//! compositor connection, so that they can share wayland objects. This can be used, for
93//! example, to embed one client into another.
94//!
95//! The crate repository contains several more complex examples.
96//!
97//! # Objects
98//!
99//! The [`Object`](object::Object) trait represents wayland objects such as wl_display or
100//! wl_registry.
101//!
102//! Objects are created in one of three ways:
103//!
104//! - The client sends a request with a new_id parameter.
105//! - The compositor sends an event with a new_id parameter.
106//! - The proxy itself creates the object.
107//!
108//! The case where the client creates an object with a request can be seen above in the
109//! wl_display.get_registry and wl_registry.bind handlers.
110//!
111//! Each object
112//!
113//! - can be associated with 0 or 1 objects in the compositor and
114//! - can be associated with 0 or 1 objects in a client.
115//!
116//! Objects created by the client start out as associated with the client but not with
117//! the compositor. Objects created by the compositor start out as associated with the
118//! compositor but not with any client. Objects created by the proxy start out
119//! unassociated.
120//!
121//! Associations are created implicitly. For example,
122//!
123//! ```no_run
124//! # use std::rc::Rc;
125//! # use wl_proxy::protocols::wayland::wl_display::{WlDisplay, WlDisplayHandler};
126//! # use wl_proxy::protocols::wayland::wl_registry::WlRegistry;
127//! #
128//! struct Display;
129//!
130//! impl WlDisplayHandler for Display {
131//!     fn handle_get_registry(&mut self, slf: &Rc<WlDisplay>, registry: &Rc<WlRegistry>) {
132//!         // At this point the WlRegistry is associated with a client-side wl_registry
133//!         // but not yet with a compositor object.
134//!
135//!         // By forwarding the wl_display.get_registry request to the compositor, we
136//!         // create a new wl_registry object in the compositor and associate the
137//!         // WlRegistry with it.
138//!         slf.send_get_registry(registry);
139//!     }
140//! }
141//! ```
142//!
143//! An object becomes unassociated through destructor messages or through delete_id
144//! messages, if delete_id messages are used for the object. Once an object is
145//! unassociated, it can once again become associated if it is used in a subsequent
146//! constructor request or event.
147//!
148//! It is valid for an object to never be associated with a compositor or client object.
149//! For example, this can happen if a client-created object is handled internally by the
150//! proxy without ever forwarding it to the compositor.
151//!
152//! Each object can only be associated with one client at a time. Multiplexing must be
153//! implemented manually.
154//!
155//! # Handlers
156//!
157//! Each object can have a handler that implements the corresponding trait. For example,
158//! [`WlRegistryHandler`](protocols::wayland::wl_registry::WlRegistryHandler).
159//!
160//! All functions in a handler have default implementations that try to forward the
161//! message to the peer. This behavior can be adjusted by using
162//! [`ObjectCoreApi::set_forward_to_client`](object::ObjectCoreApi::set_forward_to_client)
163//! and
164//! [`ObjectCoreApi::set_forward_to_server`](object::ObjectCoreApi::set_forward_to_server).
165//!
166//! If an object does not have a handler, this default behavior is used for all messages.
167//!
168//! All handler functions use a `&mut self` receiver. The handlers of other objects can
169//! be accessed with [`ObjectUtils::get_handler_ref`](object::ObjectUtils::get_handler_ref)
170//! and [`ObjectUtils::get_handler_mut`](object::ObjectUtils::get_handler_mut). These
171//! functions panic if the handler already has an incompatible borrow or if an invalid
172//! type is used.
173//!
174//! ```no_run
175//! # use std::rc::Rc;
176//! # use wl_proxy::object::ObjectUtils;
177//! # use wl_proxy::protocols::wayland::wl_compositor::{WlCompositor, WlCompositorHandler};
178//! # use wl_proxy::protocols::wayland::wl_surface::{WlSurface, WlSurfaceHandler};
179//! # use wl_proxy::protocols::xdg_shell::xdg_surface::XdgSurface;
180//! # use wl_proxy::protocols::xdg_shell::xdg_wm_base::{XdgWmBase, XdgWmBaseHandler};
181//! #
182//! struct Compositor;
183//!
184//! impl WlCompositorHandler for Compositor {
185//!     fn handle_create_surface(&mut self, slf: &Rc<WlCompositor>, id: &Rc<WlSurface>) {
186//!         slf.send_create_surface(id);
187//!         // set this handler for all wl_surface objects created by the client
188//!         id.set_handler(Surface);
189//!     }
190//! }
191//!
192//! struct Surface;
193//!
194//! impl WlSurfaceHandler for Surface { }
195//!
196//! struct WmBase;
197//!
198//! impl XdgWmBaseHandler for WmBase {
199//!     fn handle_get_xdg_surface(&mut self, _slf: &Rc<XdgWmBase>, id: &Rc<XdgSurface>, surface: &Rc<WlSurface>) {
200//!         // ok:
201//!         // - we always set this handler type
202//!         // - since we're in an XdgWmBaseHandler, only the handler of the XdgWmBase is
203//!         //   currently borrowed
204//!         let surface_handler = &mut *surface.get_handler_mut::<Surface>();
205//!     }
206//! }
207//! ```
208//!
209//! The `try_get_handler_ref` and `try_get_handler_mut` functions can be used to handle
210//! such errors gracefully.
211//!
212//! Handlers can be unset by calling [`Object::unset_handler`](object::Object::unset_handler).
213//! Both `set_handler` and `unset_handler` can be called at any time, even if the object
214//! is currently borrowed. If the handler is borrowed, the change will happen at the next
215//! possible moment.
216//!
217//! Handlers are unset implicitly if the [`State`](state::State) is destroyed. If a
218//! handler forms a reference cycle that would prevent the containing object from reaching
219//! a reference count of 0, the handler must be unset manually if it is supposed to be
220//! dropped before the state is destroyed. Most commonly, the handler should be unset
221//! when the object is logically destroyed.
222//!
223//! # Sending Messages
224//!
225//! Objects define functions that can be used to send messages. Whether the message is
226//! sent to the compositor or the client depends implicitly on the type of the message.
227//!
228//! For each message there are usually two functions: `send_*` and `try_send_*`. For
229//! example,
230//! [`WlDisplay::send_get_registry`](protocols::wayland::wl_display::WlDisplay::send_get_registry)
231//! and
232//! [`WlDisplay::try_send_get_registry`](protocols::wayland::wl_display::WlDisplay::try_send_get_registry).
233//! The difference is that `send_*` logs errors instead of returning them. Errors in these
234//! functions usually occur because the object is not associated with the compositor or
235//! a client or if one of the object arguments is not associated with the compositor or
236//! the client.
237//!
238//! For messages with new_id parameters, there are two additional functions: `new_send_*`,
239//! and `new_try_send_*`. For example,
240//! [`WlDisplay::new_send_get_registry`](protocols::wayland::wl_display::WlDisplay::new_send_get_registry)
241//! and
242//! [`WlDisplay::new_try_send_get_registry`](protocols::wayland::wl_display::WlDisplay::new_try_send_get_registry).
243//! Instead of taking the new_id parameter as an argument, they create a new object and
244//! return it.
245//!
246//! # delete_id message
247//!
248//! If an object is associated with the compositor, the association was created by the
249//! proxy (i.e. not via a new_id _event_), and the association is subsequently removed, the
250//! compositor will send a wl_display.delete_id message with the object ID. The proxy can
251//! intercept this message by overriding the delete_id function in the object handler. By
252//! default, the delete_id message is forwarded to the client.
253//!
254//! In an object is associated with a client, the association was created by the client
255//! with a request containing a new_id parameter, and the association is subsequently
256//! removed, the proxy _must_ send a wl_display.delete_id message with the object ID. If
257//! the object is also associated with the compositor, then this might happen
258//! automatically as described in the previous paragraph. Otherwise, the proxy has to
259//! manually invoke the [`ObjectCoreApi::delete_id`](object::ObjectCoreApi::delete_id)
260//! function on the object. For example, if the object is handled inside the proxy without
261//! involving the compositor, the proxy might invoke this function at the end of a
262//! destructor request.
263//!
264//! ```
265//! # use std::rc::Rc;
266//! # use wl_proxy::object::ObjectCoreApi;
267//! # use wl_proxy::protocols::wayland::wl_surface::{WlSurface, WlSurfaceHandler};
268//! #
269//! struct Surface;
270//!
271//! impl WlSurfaceHandler for Surface {
272//!     fn handle_destroy(&mut self, slf: &Rc<WlSurface>) {
273//!         slf.delete_id();
274//!     }
275//! }
276//! ```
277//!
278//! # Protocol Support
279//!
280//! This crate supports most of the protocols from [wayland-db](https://github.com/mahkoh/wayland-db).
281//!
282//! Protocol XML files are generated from the database by running the update-protocols
283//! application in the wl-proxy repository. Rust code is generated from these XML files by
284//! running the generator application. If an application needs to support a protocol that
285//! is not currently supported by wl-proxy, the application can vendor the wl-proxy
286//! repository, add the protocol XML file, and re-run the generator.
287//!
288//! Some protocols had to be excluded because they don't use proper namespacing. This
289//! mostly affects protocols from the plasma-wayland-protocols suite.
290//!
291//! Protocols that use the same message name multiple times in the same interface are
292//! currently not supported. This currently only affects the `cosmic_workspace_unstable_v1`
293//! protocol and its dependents. If there is demand, this can be worked around by
294//! renaming these conflicting messages within update-protocols.
295//!
296//! The core wayland protocol is always available. All other protocols must be enabled via
297//! cargo features. If a protocol depends on another protocol, the dependency is enabled
298//! automatically. There are also cargo features named `suite-*` that can be used to
299//! enable all protocols from specific suites.
300//!
301//! # Synchronizing With Clients
302//!
303//! In some situations it might be desirable for a client to synchronize messages with
304//! the proxy. For example, consider the following three actors:
305//!
306//! - The proxy
307//! - An embedding client A
308//! - An embedded client B
309//!
310//! Both A and B are proxied over the same compositor connection, allowing A to embed
311//! surfaces from B into its own application. The proxy runs in the same process as
312//! client A.
313//!
314//! It might be necessary for the process to match objects created by the wayland client
315//! of A with proxy objects. This can be accomplished by having A or the proxy send
316//! synchronization messages.
317//!
318//! This [wlproxy_sync_v1](https://github.com/mahkoh/wl-proxy/blob/master/protocols/wlproxy/wlproxy-sync-v1.xml)
319//! protocol can be used for this.
320//!
321//! # Logging
322//!
323//! Messages sent in all directions can be logged. The logged messages look like this:
324//!
325//! ```text
326//! [1679788.330] {socket-1} client#2    -> wl_display#1.get_registry(registry: wl_registry#2)
327//! ^~~~~~~~~~~~~
328//!  timestamp of the message
329//!               ^~~~~~~~~~
330//!                the logging prefix of the State
331//!                          ^~~~~~~~
332//!                           the sender or receiver
333//!                                      ^~
334//!                                       the direction of the message
335//!                                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
336//!                                          the message
337//! ```
338//!
339//! By default, logging is controlled by the `WL_PROXY_DEBUG` environment variable. If it
340//! is set to 1, messages are logged, otherwise messages are not logged. Messages are
341//! always written to STDERR.
342//!
343//! Applications can disable or enable logging programmatically via
344//! [`StateBuilder::with_logging`](state::StateBuilder::with_logging).
345//!
346//! Messages can have a prefix that is taken from the `WL_PROXY_PREFIX` environment
347//! variable. Applications can augment this prefix via
348//! [`StateBuilder::with_log_prefix`](state::StateBuilder::with_log_prefix). This can be
349//! used to easily distinguish these log messages from WAYLAND_DEBUG messages. The
350//! [`SimpleProxy`](simple::SimpleProxy) always sets the prefix to a unique identifier
351//! of the connection to allow distinguishing messages from different clients.
352//!
353//! Each message indicates the sender or receiver of the message. For messages sent by/to
354//! clients, the client is identified as `client#N`. Note that `N` does not start at 1 nor
355//! are the number contiguous. For messages sent by/to the compositor, the identifier is
356//! `server`.
357//!
358//! The symbols `->` and `<=` indicate the direction of the message.
359//!
360//! Logging can be disabled at compile time by disabling the default-enabled `logging`
361//! feature. This can significantly improve compile times and reduce binary size. For
362//! example, the wl-veil application has a program size of 6.7 MB by default but only
363//! 4.4 MB with logging disabled at compile time. Most programs should leave logging
364//! enabled to aid debuggability.
365
366pub mod acceptor;
367pub mod client;
368mod endpoint;
369pub mod fixed;
370mod protocol_helpers;
371/// Auto-generated wayland protocols.
372#[rustfmt::skip]
373pub mod protocols;
374pub mod baseline;
375pub mod global_mapper;
376pub mod handler;
377pub mod object;
378mod poll;
379pub mod simple;
380pub mod state;
381#[cfg(test)]
382mod test_framework;
383mod trans;
384mod utils;
385mod wire;