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