1 //! Client-side implementation of a Wayland protocol backend using `libwayland`
2
3 use std::{
4 cell::RefCell,
5 ffi::CStr,
6 os::raw::{c_char, c_int, c_void},
7 os::unix::{io::RawFd, net::UnixStream, prelude::IntoRawFd},
8 sync::{
9 atomic::{AtomicBool, Ordering},
10 Arc, Mutex,
11 },
12 };
13
14 use crate::{
15 core_interfaces::WL_DISPLAY_INTERFACE,
16 protocol::{
17 check_for_signature, same_interface, AllowNull, Argument, ArgumentType, Interface, Message,
18 ObjectInfo, ProtocolError, ANONYMOUS_INTERFACE,
19 },
20 };
21 use scoped_tls::scoped_thread_local;
22 use smallvec::SmallVec;
23
24 use wayland_sys::{client::*, common::*, ffi_dispatch};
25
26 pub use crate::types::client::{InvalidId, NoWaylandLib, WaylandError};
27
28 use super::{free_arrays, RUST_MANAGED};
29
30 scoped_thread_local!(static HANDLE: RefCell<&mut Handle>);
31
32 /// A trait representing your data associated to an object
33 ///
34 /// You will only be given access to it as a `&` reference, so you
35 /// need to handle interior mutability by yourself.
36 ///
37 /// The methods of this trait will be invoked internally every time a
38 /// new object is created to initialize its data.
39 pub trait ObjectData: downcast_rs::DowncastSync {
40 /// Dispatch an event for the associated object
41 ///
42 /// If the event has a NewId argument, the callback must return the object data
43 /// for the newly created object
event( self: Arc<Self>, handle: &mut Handle, msg: Message<ObjectId>, ) -> Option<Arc<dyn ObjectData>>44 fn event(
45 self: Arc<Self>,
46 handle: &mut Handle,
47 msg: Message<ObjectId>,
48 ) -> Option<Arc<dyn ObjectData>>;
49 /// Notification that the object has been destroyed and is no longer active
destroyed(&self, object_id: ObjectId)50 fn destroyed(&self, object_id: ObjectId);
51 /// Helper for forwarding a Debug implementation of your `ObjectData` type
52 ///
53 /// By default will just print `ObjectData { ... }`
debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result54 fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 f.debug_struct("ObjectData").finish_non_exhaustive()
56 }
57 }
58
59 #[cfg(not(tarpaulin_include))]
60 impl std::fmt::Debug for dyn ObjectData {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 self.debug(f)
63 }
64 }
65
66 downcast_rs::impl_downcast!(sync ObjectData);
67
68 /// An ID representing a Wayland object
69 #[derive(Clone)]
70 pub struct ObjectId {
71 id: u32,
72 ptr: *mut wl_proxy,
73 alive: Option<Arc<AtomicBool>>,
74 interface: &'static Interface,
75 }
76
77 unsafe impl Send for ObjectId {}
78 unsafe impl Sync for ObjectId {}
79
80 impl std::cmp::PartialEq for ObjectId {
eq(&self, other: &ObjectId) -> bool81 fn eq(&self, other: &ObjectId) -> bool {
82 match (&self.alive, &other.alive) {
83 (Some(ref a), Some(ref b)) => {
84 // this is an object we manage
85 Arc::ptr_eq(a, b)
86 }
87 (None, None) => {
88 // this is an external (un-managed) object
89 self.ptr == other.ptr
90 && self.id == other.id
91 && same_interface(self.interface, other.interface)
92 }
93 _ => false,
94 }
95 }
96 }
97
98 impl std::cmp::Eq for ObjectId {}
99
100 impl ObjectId {
101 /// Check if this is the null ID
is_null(&self) -> bool102 pub fn is_null(&self) -> bool {
103 self.ptr.is_null()
104 }
105
106 /// Interface of the represented object
interface(&self) -> &'static Interface107 pub fn interface(&self) -> &'static Interface {
108 self.interface
109 }
110
111 /// Return the protocol-level numerical ID of this object
112 ///
113 /// Protocol IDs are reused after object destruction, so this should not be used as a
114 /// unique identifier,
protocol_id(&self) -> u32115 pub fn protocol_id(&self) -> u32 {
116 self.id
117 }
118
119 /// Creates an object id from a libwayland-client pointer.
120 ///
121 /// # Errors
122 ///
123 /// This function returns an [`InvalidId`] error if the interface of the proxy does not match the provided
124 /// interface.
125 ///
126 /// # Safety
127 ///
128 /// The provided pointer must be a valid pointer to a `wl_resource` and remain valid for as
129 /// long as the retrieved `ObjectId` is used.
from_ptr( interface: &'static Interface, ptr: *mut wl_proxy, ) -> Result<ObjectId, InvalidId>130 pub unsafe fn from_ptr(
131 interface: &'static Interface,
132 ptr: *mut wl_proxy,
133 ) -> Result<ObjectId, InvalidId> {
134 let ptr_iface_name =
135 CStr::from_ptr(ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_class, ptr));
136 let provided_iface_name = CStr::from_ptr(
137 interface
138 .c_ptr
139 .expect("[wayland-backend-sys] Cannot use Interface without c_ptr!")
140 .name,
141 );
142 if ptr_iface_name != provided_iface_name {
143 return Err(InvalidId);
144 }
145
146 let id = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_id, ptr);
147
148 // Test if the proxy is managed by us.
149 let is_rust_managed = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_listener, ptr)
150 == &RUST_MANAGED as *const u8 as *const _;
151
152 let alive = if is_rust_managed {
153 let udata = &*(ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_user_data, ptr)
154 as *mut ProxyUserData);
155 Some(udata.alive.clone())
156 } else {
157 None
158 };
159
160 Ok(ObjectId { id, ptr, alive, interface })
161 }
162
163 /// Get the underlying libwayland pointer for this object
as_ptr(&self) -> *mut wl_proxy164 pub fn as_ptr(&self) -> *mut wl_proxy {
165 if self.alive.as_ref().map(|alive| alive.load(Ordering::Acquire)).unwrap_or(true) {
166 self.ptr
167 } else {
168 std::ptr::null_mut()
169 }
170 }
171 }
172
173 #[cfg(not(tarpaulin_include))]
174 impl std::fmt::Display for ObjectId {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 write!(f, "{}@{}", self.interface.name, self.id)
177 }
178 }
179
180 #[cfg(not(tarpaulin_include))]
181 impl std::fmt::Debug for ObjectId {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result182 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183 write!(f, "ObjectId({})", self)
184 }
185 }
186
187 struct ProxyUserData {
188 alive: Arc<AtomicBool>,
189 data: Arc<dyn ObjectData>,
190 interface: &'static Interface,
191 }
192
193 /// Main handle of a backend to the Wayland protocol
194 ///
195 /// This type hosts most of the protocol-related functionality of the backend, and is the
196 /// main entry point for manipulating Wayland objects. It can be retrieved both from
197 /// the backend via [`Backend::handle()`](Backend::handle), and is given to you as argument
198 /// in most event callbacks.
199 #[derive(Debug)]
200 pub struct Handle {
201 display: *mut wl_display,
202 evq: *mut wl_event_queue,
203 display_id: ObjectId,
204 last_error: Option<WaylandError>,
205 pending_placeholder: Option<(&'static Interface, u32)>,
206 }
207
208 /// A pure rust implementation of a Wayland client backend
209 ///
210 /// This type hosts the plumbing functionalities for interacting with the wayland protocol,
211 /// and most of the protocol-level interactions are made through the [`Handle`] type, accessed
212 /// via the [`handle()`](Backend::handle) method.
213 #[derive(Debug)]
214 pub struct Backend {
215 handle: Handle,
216 }
217
218 unsafe impl Send for Backend {}
219 unsafe impl Sync for Backend {}
220
221 impl Backend {
222 /// Try to initialize a Wayland backend on the provided unix stream
223 ///
224 /// The provided stream should correspond to an already established unix connection with
225 /// the Wayland server. This function fails if the system `libwayland` could not be loaded.
connect(stream: UnixStream) -> Result<Self, NoWaylandLib>226 pub fn connect(stream: UnixStream) -> Result<Self, NoWaylandLib> {
227 if !is_lib_available() {
228 return Err(NoWaylandLib);
229 }
230 let display = unsafe {
231 ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_connect_to_fd, stream.into_raw_fd())
232 };
233 if display.is_null() {
234 panic!("[wayland-backend-sys] libwayland reported an allocation failure.");
235 }
236 // set the log trampoline
237 unsafe {
238 ffi_dispatch!(
239 WAYLAND_CLIENT_HANDLE,
240 wl_log_set_handler_client,
241 wl_log_trampoline_to_rust_client
242 );
243 }
244 let display_alive = Arc::new(AtomicBool::new(true));
245 Ok(Self {
246 handle: Handle {
247 display,
248 evq: std::ptr::null_mut(),
249 display_id: ObjectId {
250 id: 1,
251 ptr: display as *mut wl_proxy,
252 alive: Some(display_alive),
253 interface: &WL_DISPLAY_INTERFACE,
254 },
255 last_error: None,
256 pending_placeholder: None,
257 },
258 })
259 }
260
261 /// Flush all pending outgoing requests to the server
flush(&mut self) -> Result<(), WaylandError>262 pub fn flush(&mut self) -> Result<(), WaylandError> {
263 self.handle.no_last_error()?;
264 let ret =
265 unsafe { ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_flush, self.handle.display) };
266 if ret < 0 {
267 Err(self
268 .handle
269 .store_if_not_wouldblock_and_return_error(std::io::Error::last_os_error()))
270 } else {
271 Ok(())
272 }
273 }
274
275 /// Read events from the wayland socket if available, and invoke the associated callbacks
276 ///
277 /// This function will never block, and returns an I/O `WouldBlock` error if no event is available
278 /// to read.
279 ///
280 /// **Note:** this function should only be used if you know that you are the only thread
281 /// reading events from the wayland socket. If this may not be the case, see [`ReadEventsGuard`]
dispatch_events(&mut self) -> Result<usize, WaylandError>282 pub fn dispatch_events(&mut self) -> Result<usize, WaylandError> {
283 self.handle.no_last_error()?;
284 self.handle.try_read()?;
285 self.handle.dispatch_pending()
286 }
287
288 /// Access the [`Handle`] associated with this backend
handle(&mut self) -> &mut Handle289 pub fn handle(&mut self) -> &mut Handle {
290 &mut self.handle
291 }
292 }
293
294 impl Handle {
295 #[inline]
no_last_error(&self) -> Result<(), WaylandError>296 fn no_last_error(&self) -> Result<(), WaylandError> {
297 if let Some(ref err) = self.last_error {
298 Err(err.clone())
299 } else {
300 Ok(())
301 }
302 }
303
304 #[inline]
store_and_return_error(&mut self, err: std::io::Error) -> WaylandError305 fn store_and_return_error(&mut self, err: std::io::Error) -> WaylandError {
306 // check if it was actually a protocol error
307 let err = if err.raw_os_error() == Some(nix::errno::Errno::EPROTO as i32) {
308 let mut object_id = 0;
309 let mut interface = std::ptr::null();
310 let code = unsafe {
311 ffi_dispatch!(
312 WAYLAND_CLIENT_HANDLE,
313 wl_display_get_protocol_error,
314 self.display,
315 &mut interface,
316 &mut object_id
317 )
318 };
319 let object_interface = unsafe {
320 if interface.is_null() {
321 String::new()
322 } else {
323 let cstr = std::ffi::CStr::from_ptr((*interface).name);
324 cstr.to_string_lossy().into()
325 }
326 };
327 WaylandError::Protocol(ProtocolError {
328 code,
329 object_id,
330 object_interface,
331 message: String::new(),
332 })
333 } else {
334 WaylandError::Io(err)
335 };
336 log::error!("{}", err);
337 self.last_error = Some(err.clone());
338 err
339 }
340
341 #[inline]
store_if_not_wouldblock_and_return_error(&mut self, e: std::io::Error) -> WaylandError342 fn store_if_not_wouldblock_and_return_error(&mut self, e: std::io::Error) -> WaylandError {
343 if e.kind() != std::io::ErrorKind::WouldBlock {
344 self.store_and_return_error(e)
345 } else {
346 e.into()
347 }
348 }
349
dispatch_pending(&mut self) -> Result<usize, WaylandError>350 fn dispatch_pending(&mut self) -> Result<usize, WaylandError> {
351 let display = self.display;
352 let evq = self.evq;
353
354 // We erase the lifetime of the Handle to be able to store it in the tls,
355 // it's safe as it'll only last until the end of this function call anyway
356 let ret =
357 HANDLE.set(&RefCell::new(unsafe { std::mem::transmute(&mut *self) }), || unsafe {
358 if evq.is_null() {
359 ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_dispatch_pending, display)
360 } else {
361 ffi_dispatch!(
362 WAYLAND_CLIENT_HANDLE,
363 wl_display_dispatch_queue_pending,
364 display,
365 evq
366 )
367 }
368 });
369 if ret < 0 {
370 Err(self.store_if_not_wouldblock_and_return_error(std::io::Error::last_os_error()))
371 } else {
372 Ok(ret as usize)
373 }
374 }
375
try_read(&mut self) -> Result<(), WaylandError>376 fn try_read(&mut self) -> Result<(), WaylandError> {
377 let ret = unsafe {
378 if self.evq.is_null() {
379 ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_prepare_read, self.display)
380 } else {
381 ffi_dispatch!(
382 WAYLAND_CLIENT_HANDLE,
383 wl_display_prepare_read_queue,
384 self.display,
385 self.evq
386 )
387 }
388 };
389 if ret < 0 {
390 return Ok(());
391 }
392 let ret =
393 unsafe { ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_read_events, self.display) };
394 if ret < 0 {
395 Err(self.store_if_not_wouldblock_and_return_error(std::io::Error::last_os_error()))
396 } else {
397 Ok(())
398 }
399 }
400 }
401
402 /// Guard for synchronizing event reading across multiple threads
403 ///
404 /// If multiple threads need to read events from the Wayland socket concurrently,
405 /// it is necessary to synchronize their access. Failing to do so may cause some of the
406 /// threads to not be notified of new events, and sleep much longer than appropriate.
407 ///
408 /// To correctly synchronize access, this type should be used. The guard is created using
409 /// the [`try_new()`](ReadEventsGuard::try_new) method. And the event reading is triggered by consuming
410 /// the guard using the [`read()`](ReadEventsGuard::read) method.
411 ///
412 /// If you plan to poll the Wayland socket for readiness, the file descriptor can be retrieved via
413 /// the [`connection_fd`](ReadEventsGuard::connection_fd) method. Note that for the synchronization to
414 /// correctly occur, you must *always* create the `ReadEventsGuard` *before* polling the socket.
415 ///
416 /// This synchronization is compatible with the "prepare_read" mechanism of the system libwayland,
417 /// and will correctly synchronize with other C libraries using the same Wayland socket.
418 #[derive(Debug)]
419 pub struct ReadEventsGuard {
420 backend: Arc<Mutex<Backend>>,
421 display: *mut wl_display,
422 done: bool,
423 }
424
425 impl ReadEventsGuard {
426 /// Create a new reading guard
427 ///
428 /// This call will not block, but event callbacks may be invoked in the process
429 /// of preparing the guard.
try_new(backend: Arc<Mutex<Backend>>) -> Result<Self, WaylandError>430 pub fn try_new(backend: Arc<Mutex<Backend>>) -> Result<Self, WaylandError> {
431 let mut backend_guard = backend.lock().unwrap();
432 let display = backend_guard.handle.display;
433 let evq = backend_guard.handle.evq;
434
435 // do the prepare_read() and dispatch as necessary
436 loop {
437 let ret = unsafe {
438 if evq.is_null() {
439 ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_prepare_read, display)
440 } else {
441 ffi_dispatch!(
442 WAYLAND_CLIENT_HANDLE,
443 wl_display_prepare_read_queue,
444 display,
445 evq
446 )
447 }
448 };
449 if ret < 0 {
450 backend_guard.handle.dispatch_pending()?;
451 } else {
452 break;
453 }
454 }
455
456 std::mem::drop(backend_guard);
457
458 // prepare_read is done, we are ready
459 Ok(ReadEventsGuard { backend, display, done: false })
460 }
461
462 /// Access the Wayland socket FD for polling
connection_fd(&self) -> RawFd463 pub fn connection_fd(&self) -> RawFd {
464 unsafe { ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_get_fd, self.display) }
465 }
466
467 /// Attempt to read events from the Wayland socket
468 ///
469 /// If multiple threads have a live reading guard, this method will block until all of them
470 /// are either dropped or have their `read()` method invoked, at which point on of the threads
471 /// will read events from the socket and invoke the callbacks for the received events. All
472 /// threads will then resume their execution.
473 ///
474 /// This returns the number of dispatched events, or `0` if an other thread handled the dispatching.
475 /// If no events are available to read from the socket, this returns a `WouldBlock` IO error.
read(mut self) -> Result<usize, WaylandError>476 pub fn read(mut self) -> Result<usize, WaylandError> {
477 self.done = true;
478 let ret =
479 unsafe { ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_read_events, self.display) };
480 if ret < 0 {
481 // we have done the reading, and there is an error
482 Err(self
483 .backend
484 .lock()
485 .unwrap()
486 .handle
487 .store_if_not_wouldblock_and_return_error(std::io::Error::last_os_error()))
488 } else {
489 // the read occured, dispatch pending events
490 self.backend.lock().unwrap().handle.dispatch_pending()
491 }
492 }
493 }
494
495 impl Drop for ReadEventsGuard {
drop(&mut self)496 fn drop(&mut self) {
497 if !self.done {
498 unsafe {
499 ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_cancel_read, self.display);
500 }
501 }
502 }
503 }
504
505 impl Handle {
506 /// Get the object ID for the `wl_display`
display_id(&self) -> ObjectId507 pub fn display_id(&self) -> ObjectId {
508 self.display_id.clone()
509 }
510
511 /// Get the last error that occurred on this backend
512 ///
513 /// If this returns an error, your Wayland connection is already dead.
last_error(&self) -> Option<WaylandError>514 pub fn last_error(&self) -> Option<WaylandError> {
515 self.last_error.clone()
516 }
517
518 /// Get the detailed information about a wayland object
519 ///
520 /// Returns an error if the provided object ID is no longer valid.
info(&self, id: ObjectId) -> Result<ObjectInfo, InvalidId>521 pub fn info(&self, id: ObjectId) -> Result<ObjectInfo, InvalidId> {
522 if !id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(true) || id.ptr.is_null()
523 {
524 return Err(InvalidId);
525 }
526
527 let version = if id.id == 1 {
528 // special case the display, because libwayland returns a version of 0 for it
529 1
530 } else {
531 unsafe { ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_version, id.ptr) }
532 };
533
534 Ok(ObjectInfo { id: id.id, interface: id.interface, version })
535 }
536
537 /// Create a null object ID
538 ///
539 /// This object ID is always invalid, and can be used as placeholder.
null_id(&mut self) -> ObjectId540 pub fn null_id(&mut self) -> ObjectId {
541 ObjectId { ptr: std::ptr::null_mut(), interface: &ANONYMOUS_INTERFACE, id: 0, alive: None }
542 }
543
544 /// Create a placeholder ID for object creation
545 ///
546 /// This ID needs to be created beforehand and given as argument to a request creating a
547 /// new object ID. A specification must be specified if the interface and version cannot
548 /// be inferred from the protocol (for example object creation from the `wl_registry`).
549 ///
550 /// If a specification is provided it'll be checked against what can be deduced from the
551 /// protocol specification, and [`send_request`](Handle::send_request) will panic if they
552 /// do not match.
placeholder_id(&mut self, spec: Option<(&'static Interface, u32)>) -> ObjectId553 pub fn placeholder_id(&mut self, spec: Option<(&'static Interface, u32)>) -> ObjectId {
554 self.pending_placeholder = spec;
555 ObjectId {
556 ptr: std::ptr::null_mut(),
557 alive: None,
558 id: 0,
559 interface: spec.map(|(iface, _)| iface).unwrap_or(&ANONYMOUS_INTERFACE),
560 }
561 }
562
563 /// Sends a request to the server
564 ///
565 /// Returns an error if the sender ID of the provided message is no longer valid.
566 ///
567 /// **Panic:**
568 ///
569 /// Several checks against the protocol specification are done, and this method will panic if they do
570 /// not pass:
571 ///
572 /// - the message opcode must be valid for the sender interface
573 /// - the argument list must match the prototype for the message associated with this opcode
574 /// - if the method creates a new object, a [`placeholder_id()`](Handle::placeholder_id) must be given
575 /// in the argument list, either without a specification, or with a specification that matches the
576 /// interface and version deduced from the protocol rules
577 ///
578 /// When using the system libwayland backend, the Wayland interfaces must have been generated with the C-ptr
579 /// support.
580 pub fn send_request(
581 &mut self,
582 Message { sender_id: id, opcode, args }: Message<ObjectId>,
583 data: Option<Arc<dyn ObjectData>>,
584 ) -> Result<ObjectId, InvalidId> {
585 if !id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(true) || id.ptr.is_null()
586 {
587 return Err(InvalidId);
588 }
589 let parent_version = if id.id == 1 {
590 1
591 } else {
592 unsafe { ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_version, id.ptr) }
593 };
594 // check that the argument list is valid
595 let message_desc = match id.interface.requests.get(opcode as usize) {
596 Some(msg) => msg,
597 None => {
598 panic!("Unknown opcode {} for object {}@{}.", opcode, id.interface.name, id.id);
599 }
600 };
601 if !check_for_signature(message_desc.signature, &args) {
602 panic!(
603 "Unexpected signature for request {}@{}.{}: expected {:?}, got {:?}.",
604 id.interface.name, id.id, message_desc.name, message_desc.signature, args
605 );
606 }
607
608 // Prepare the child object data
609 let child_spec = if message_desc
610 .signature
611 .iter()
612 .any(|arg| matches!(arg, ArgumentType::NewId(_)))
613 {
614 if let Some((iface, version)) = self.pending_placeholder.take() {
615 if let Some(child_interface) = message_desc.child_interface {
616 if !same_interface(child_interface, iface) {
617 panic!(
618 "Wrong placeholder used when sending request {}@{}.{}: expected interface {} but got {}",
619 id.interface.name,
620 id.id,
621 message_desc.name,
622 child_interface.name,
623 iface.name
624 );
625 }
626 if version != parent_version {
627 panic!(
628 "Wrong placeholder used when sending request {}@{}.{}: expected version {} but got {}",
629 id.interface.name,
630 id.id,
631 message_desc.name,
632 parent_version,
633 version
634 );
635 }
636 }
637 Some((iface, version))
638 } else if let Some(child_interface) = message_desc.child_interface {
639 Some((child_interface, parent_version))
640 } else {
641 panic!(
642 "Wrong placeholder used when sending request {}@{}.{}: target interface must be specified for a generic constructor.",
643 id.interface.name,
644 id.id,
645 message_desc.name
646 );
647 }
648 } else {
649 None
650 };
651
652 let child_interface_ptr = child_spec
653 .as_ref()
654 .map(|(i, _)| {
655 i.c_ptr.expect("[wayland-backend-sys] Cannot use Interface without c_ptr!")
656 as *const _
657 })
658 .unwrap_or(std::ptr::null());
659 let child_version = child_spec.as_ref().map(|(_, v)| *v).unwrap_or(parent_version);
660
661 // check that all input objects are valid and create the [wl_argument]
662 let mut argument_list = SmallVec::<[wl_argument; 4]>::with_capacity(args.len());
663 let mut arg_interfaces = message_desc.arg_interfaces.iter();
664 for (i, arg) in args.iter().enumerate() {
665 match *arg {
666 Argument::Uint(u) => argument_list.push(wl_argument { u }),
667 Argument::Int(i) => argument_list.push(wl_argument { i }),
668 Argument::Fixed(f) => argument_list.push(wl_argument { f }),
669 Argument::Fd(h) => argument_list.push(wl_argument { h }),
670 Argument::Array(ref a) => {
671 let a = Box::new(wl_array {
672 size: a.len(),
673 alloc: a.len(),
674 data: a.as_ptr() as *mut _,
675 });
676 argument_list.push(wl_argument { a: Box::into_raw(a) })
677 }
678 Argument::Str(ref s) => argument_list.push(wl_argument { s: s.as_ptr() }),
679 Argument::Object(ref o) => {
680 if !o.ptr.is_null() {
681 if !id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(true) {
682 unsafe { free_arrays(message_desc.signature, &argument_list) };
683 return Err(InvalidId);
684 }
685 let next_interface = arg_interfaces.next().unwrap();
686 if !same_interface(next_interface, o.interface) {
687 panic!("Request {}@{}.{} expects an argument of interface {} but {} was provided instead.", id.interface.name, id.id, message_desc.name, next_interface.name, o.interface.name);
688 }
689 } else if !matches!(
690 message_desc.signature[i],
691 ArgumentType::Object(AllowNull::Yes)
692 ) {
693 panic!(
694 "Request {}@{}.{} expects an non-null object argument.",
695 id.interface.name, id.id, message_desc.name
696 );
697 }
698 argument_list.push(wl_argument { o: o.ptr as *const _ })
699 }
700 Argument::NewId(_) => argument_list.push(wl_argument { n: 0 }),
701 }
702 }
703
704 let ret = unsafe {
705 ffi_dispatch!(
706 WAYLAND_CLIENT_HANDLE,
707 wl_proxy_marshal_array_constructor_versioned,
708 id.ptr,
709 opcode as u32,
710 argument_list.as_mut_ptr(),
711 child_interface_ptr,
712 child_version
713 )
714 };
715
716 unsafe {
717 free_arrays(message_desc.signature, &argument_list);
718 }
719
720 if ret.is_null() && child_spec.is_some() {
721 panic!("[wayland-backend-sys] libwayland reported an allocation failure.");
722 }
723
724 // initialize the proxy
725 let child_id = if let Some((child_interface, _)) = child_spec {
726 let child_alive = Arc::new(AtomicBool::new(true));
727 let child_id = ObjectId {
728 ptr: ret,
729 alive: Some(child_alive.clone()),
730 id: unsafe { ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_id, ret) },
731 interface: child_interface,
732 };
733 let child_udata = Box::new(ProxyUserData {
734 alive: child_alive,
735 data: data.expect(
736 "Sending a request creating an object without providing an object data.",
737 ),
738 interface: child_interface,
739 });
740 unsafe {
741 ffi_dispatch!(
742 WAYLAND_CLIENT_HANDLE,
743 wl_proxy_add_dispatcher,
744 ret,
745 dispatcher_func,
746 &RUST_MANAGED as *const u8 as *const c_void,
747 Box::into_raw(child_udata) as *mut c_void
748 );
749 }
750 child_id
751 } else {
752 self.null_id()
753 };
754
755 if message_desc.is_destructor {
756 if let Some(ref alive) = id.alive {
757 let udata = unsafe {
758 Box::from_raw(ffi_dispatch!(
759 WAYLAND_CLIENT_HANDLE,
760 wl_proxy_get_user_data,
761 id.ptr
762 ) as *mut ProxyUserData)
763 };
764 unsafe {
765 ffi_dispatch!(
766 WAYLAND_CLIENT_HANDLE,
767 wl_proxy_set_user_data,
768 id.ptr,
769 std::ptr::null_mut()
770 );
771 }
772 alive.store(false, Ordering::Release);
773 udata.data.destroyed(id.clone());
774 }
775 unsafe {
776 ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_destroy, id.ptr);
777 }
778 }
779
780 Ok(child_id)
781 }
782
783 /// Access the object data associated with a given object ID
784 ///
785 /// Returns an error if the object ID is not longer valid or if it corresponds to a Wayland
786 /// object that is not managed by this backend (when multiple libraries share the same Wayland
787 /// socket via `libwayland`).
get_data(&self, id: ObjectId) -> Result<Arc<dyn ObjectData>, InvalidId>788 pub fn get_data(&self, id: ObjectId) -> Result<Arc<dyn ObjectData>, InvalidId> {
789 if !id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(false) {
790 return Err(InvalidId);
791 }
792
793 if id.id == 1 {
794 // special case the display whose object data is not accessible
795 return Ok(Arc::new(DumbObjectData));
796 }
797
798 let udata = unsafe {
799 &*(ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_user_data, id.ptr)
800 as *mut ProxyUserData)
801 };
802 Ok(udata.data.clone())
803 }
804
805 /// Set the object data associated with a given object ID
806 ///
807 /// Returns an error if the object ID is not longer valid or if it corresponds to a Wayland
808 /// object that is not managed by this backend (when multiple libraries share the same Wayland
809 /// socket via `libwayland`).
set_data(&mut self, id: ObjectId, data: Arc<dyn ObjectData>) -> Result<(), InvalidId>810 pub fn set_data(&mut self, id: ObjectId, data: Arc<dyn ObjectData>) -> Result<(), InvalidId> {
811 if !id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(false) {
812 return Err(InvalidId);
813 }
814
815 // Cannot touch the user_data of the display
816 if id.id == 1 {
817 return Err(InvalidId);
818 }
819
820 let udata = unsafe {
821 &mut *(ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_user_data, id.ptr)
822 as *mut ProxyUserData)
823 };
824
825 udata.data = data;
826
827 Ok(())
828 }
829 }
830
dispatcher_func( _: *const c_void, proxy: *mut c_void, opcode: u32, _: *const wl_message, args: *const wl_argument, ) -> c_int831 unsafe extern "C" fn dispatcher_func(
832 _: *const c_void,
833 proxy: *mut c_void,
834 opcode: u32,
835 _: *const wl_message,
836 args: *const wl_argument,
837 ) -> c_int {
838 let proxy = proxy as *mut wl_proxy;
839 let udata_ptr =
840 ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_user_data, proxy) as *mut ProxyUserData;
841 let udata = &mut *udata_ptr;
842 let interface = udata.interface;
843 let message_desc = match interface.events.get(opcode as usize) {
844 Some(desc) => desc,
845 None => {
846 log::error!("Unknown event opcode {} for interface {}.", opcode, interface.name);
847 return -1;
848 }
849 };
850
851 let mut parsed_args =
852 SmallVec::<[Argument<ObjectId>; 4]>::with_capacity(message_desc.signature.len());
853 let mut arg_interfaces = message_desc.arg_interfaces.iter().copied();
854 let mut created = None;
855 for (i, typ) in message_desc.signature.iter().enumerate() {
856 match typ {
857 ArgumentType::Uint => parsed_args.push(Argument::Uint((*args.add(i)).u)),
858 ArgumentType::Int => parsed_args.push(Argument::Int((*args.add(i)).i)),
859 ArgumentType::Fixed => parsed_args.push(Argument::Fixed((*args.add(i)).f)),
860 ArgumentType::Fd => parsed_args.push(Argument::Fd((*args.add(i)).h)),
861 ArgumentType::Array(_) => {
862 let array = &*((*args.add(i)).a);
863 let content = std::slice::from_raw_parts(array.data as *mut u8, array.size);
864 parsed_args.push(Argument::Array(Box::new(content.into())));
865 }
866 ArgumentType::Str(_) => {
867 let ptr = (*args.add(i)).s;
868 let cstr = std::ffi::CStr::from_ptr(ptr);
869 parsed_args.push(Argument::Str(Box::new(cstr.into())));
870 }
871 ArgumentType::Object(_) => {
872 let obj = (*args.add(i)).o as *mut wl_proxy;
873 if !obj.is_null() {
874 // retrieve the object relevant info
875 let obj_id = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_id, obj);
876 // check if this is a local or distant proxy
877 let next_interface = arg_interfaces.next().unwrap_or(&ANONYMOUS_INTERFACE);
878 let listener = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_listener, obj);
879 if listener == &RUST_MANAGED as *const u8 as *const c_void {
880 let obj_udata =
881 &*(ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_user_data, obj)
882 as *mut ProxyUserData);
883 if !same_interface(next_interface, obj_udata.interface) {
884 log::error!(
885 "Received object {}@{} in {}.{} but expected interface {}.",
886 obj_udata.interface.name,
887 obj_id,
888 interface.name,
889 message_desc.name,
890 next_interface.name,
891 );
892 return -1;
893 }
894 parsed_args.push(Argument::Object(ObjectId {
895 alive: Some(obj_udata.alive.clone()),
896 ptr: obj,
897 id: obj_id,
898 interface: obj_udata.interface,
899 }));
900 } else {
901 parsed_args.push(Argument::Object(ObjectId {
902 alive: None,
903 id: obj_id,
904 ptr: obj,
905 interface: next_interface,
906 }));
907 }
908 } else {
909 // libwayland-client.so checks nulls for us
910 parsed_args.push(Argument::Object(ObjectId {
911 alive: None,
912 id: 0,
913 ptr: std::ptr::null_mut(),
914 interface: &ANONYMOUS_INTERFACE,
915 }))
916 }
917 }
918 ArgumentType::NewId(_) => {
919 let obj = (*args.add(i)).o as *mut wl_proxy;
920 // this is a newid, it needs to be initialized
921 if !obj.is_null() {
922 let child_interface = message_desc.child_interface.unwrap_or_else(|| {
923 log::warn!(
924 "Event {}.{} creates an anonymous object.",
925 interface.name,
926 opcode
927 );
928 &ANONYMOUS_INTERFACE
929 });
930 let child_alive = Arc::new(AtomicBool::new(true));
931 let child_id = ObjectId {
932 ptr: obj,
933 alive: Some(child_alive.clone()),
934 id: ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_id, obj),
935 interface: child_interface,
936 };
937 let child_udata = Box::into_raw(Box::new(ProxyUserData {
938 alive: child_alive,
939 data: Arc::new(UninitObjectData),
940 interface: child_interface,
941 }));
942 created = Some((child_id.clone(), child_udata));
943 ffi_dispatch!(
944 WAYLAND_CLIENT_HANDLE,
945 wl_proxy_add_dispatcher,
946 obj,
947 dispatcher_func,
948 &RUST_MANAGED as *const u8 as *const c_void,
949 child_udata as *mut c_void
950 );
951 parsed_args.push(Argument::NewId(child_id));
952 } else {
953 parsed_args.push(Argument::NewId(ObjectId {
954 id: 0,
955 ptr: std::ptr::null_mut(),
956 alive: None,
957 interface: &ANONYMOUS_INTERFACE,
958 }))
959 }
960 }
961 }
962 }
963
964 let proxy_id = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_id, proxy);
965 let id = ObjectId {
966 alive: Some(udata.alive.clone()),
967 ptr: proxy,
968 id: proxy_id,
969 interface: udata.interface,
970 };
971
972 let ret = HANDLE.with(|handle| {
973 udata.data.clone().event(
974 &mut **handle.borrow_mut(),
975 Message { sender_id: id.clone(), opcode: opcode as u16, args: parsed_args },
976 )
977 });
978
979 if message_desc.is_destructor {
980 let udata = Box::from_raw(udata_ptr);
981 ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_set_user_data, proxy, std::ptr::null_mut());
982 udata.alive.store(false, Ordering::Release);
983 udata.data.destroyed(id);
984 ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_destroy, proxy);
985 }
986
987 match (created, ret) {
988 (Some((_, child_udata_ptr)), Some(child_data)) => {
989 (*child_udata_ptr).data = child_data;
990 }
991 (Some((child_id, _)), None) => {
992 panic!("Callback creating object {} did not provide any object data.", child_id);
993 }
994 (None, Some(_)) => {
995 panic!("An object data was returned from a callback not creating any object");
996 }
997 (None, None) => {}
998 }
999
1000 0
1001 }
1002
1003 extern "C" {
wl_log_trampoline_to_rust_client(fmt: *const c_char, list: *const c_void)1004 fn wl_log_trampoline_to_rust_client(fmt: *const c_char, list: *const c_void);
1005 }
1006
1007 impl Drop for Backend {
drop(&mut self)1008 fn drop(&mut self) {
1009 if self.handle.evq.is_null() {
1010 // we are own the connection, clone it
1011 unsafe {
1012 ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_disconnect, self.handle.display)
1013 }
1014 }
1015 }
1016 }
1017
1018 struct DumbObjectData;
1019
1020 impl ObjectData for DumbObjectData {
event( self: Arc<Self>, _handle: &mut Handle, _msg: Message<ObjectId>, ) -> Option<Arc<dyn ObjectData>>1021 fn event(
1022 self: Arc<Self>,
1023 _handle: &mut Handle,
1024 _msg: Message<ObjectId>,
1025 ) -> Option<Arc<dyn ObjectData>> {
1026 unreachable!()
1027 }
1028
destroyed(&self, _object_id: ObjectId)1029 fn destroyed(&self, _object_id: ObjectId) {
1030 unreachable!()
1031 }
1032 }
1033
1034 struct UninitObjectData;
1035
1036 impl ObjectData for UninitObjectData {
event( self: Arc<Self>, _handle: &mut Handle, msg: Message<ObjectId>, ) -> Option<Arc<dyn ObjectData>>1037 fn event(
1038 self: Arc<Self>,
1039 _handle: &mut Handle,
1040 msg: Message<ObjectId>,
1041 ) -> Option<Arc<dyn ObjectData>> {
1042 panic!("Received a message on an uninitialized object: {:?}", msg);
1043 }
1044
destroyed(&self, _object_id: ObjectId)1045 fn destroyed(&self, _object_id: ObjectId) {}
1046
debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result1047 fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1048 f.debug_struct("UninitObjectData").finish()
1049 }
1050 }
1051