1use std::{
4 collections::HashSet,
5 ffi::CStr,
6 os::raw::{c_int, c_void},
7 os::unix::{
8 io::{BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd},
9 net::UnixStream,
10 },
11 ptr::{self, NonNull},
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
32use super::{free_arrays, RUST_MANAGED};
33
34use super::client::*;
35
36scoped_thread_local! {
37 #[allow(unsafe_op_in_unsafe_fn)]
39 static BACKEND: Backend
40}
41
42#[derive(Clone)]
44pub struct InnerObjectId {
45 id: u32,
46 ptr: *mut wl_proxy,
47 alive: Option<Arc<AtomicBool>>,
48 interface: &'static Interface,
49}
50
51unsafe impl Send for InnerObjectId {}
52unsafe impl Sync for InnerObjectId {}
53
54impl std::cmp::PartialEq for InnerObjectId {
55 fn eq(&self, other: &Self) -> bool {
56 match (&self.alive, &other.alive) {
57 (Some(ref a), Some(ref b)) => {
58 Arc::ptr_eq(a, b)
60 }
61 (None, None) => {
62 ptr::eq(self.ptr, other.ptr)
64 && self.id == other.id
65 && same_interface(self.interface, other.interface)
66 }
67 _ => false,
68 }
69 }
70}
71
72impl std::cmp::Eq for InnerObjectId {}
73
74impl std::hash::Hash for InnerObjectId {
75 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
76 self.id.hash(state);
77 self.ptr.hash(state);
78 self.alive
79 .as_ref()
80 .map(|arc| &**arc as *const AtomicBool)
81 .unwrap_or(std::ptr::null())
82 .hash(state);
83 }
84}
85
86impl InnerObjectId {
87 pub fn is_null(&self) -> bool {
88 self.ptr.is_null()
89 }
90
91 pub fn interface(&self) -> &'static Interface {
92 self.interface
93 }
94
95 pub fn protocol_id(&self) -> u32 {
96 self.id
97 }
98
99 pub unsafe fn from_ptr(
100 interface: &'static Interface,
101 ptr: *mut wl_proxy,
102 ) -> Result<Self, InvalidId> {
103 let ptr_iface_name = unsafe {
105 CStr::from_ptr(ffi_dispatch!(wayland_client_handle(), wl_proxy_get_class, ptr))
106 };
107 let provided_iface_name = unsafe {
109 CStr::from_ptr(
110 interface
111 .c_ptr
112 .expect("[wayland-backend-sys] Cannot use Interface without c_ptr!")
113 .name,
114 )
115 };
116 if ptr_iface_name != provided_iface_name {
117 return Err(InvalidId);
118 }
119
120 let id = ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, ptr);
121
122 let is_rust_managed = ptr::eq(
124 ffi_dispatch!(wayland_client_handle(), wl_proxy_get_listener, ptr),
125 &RUST_MANAGED as *const u8 as *const _,
126 );
127
128 let alive = if is_rust_managed {
129 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) -> Result<NonNull<wl_proxy>, InvalidId> {
143 if self.alive.as_ref().map(|alive| alive.load(Ordering::Acquire)).unwrap_or(true) {
144 NonNull::new(self.ptr).ok_or(InvalidId)
145 } else {
146 Err(InvalidId)
147 }
148 }
149
150 #[cfg(feature = "libwayland_client_1_23")]
151 pub fn display_ptr(&self) -> Result<NonNull<wl_display>, InvalidId> {
152 if self.alive.as_ref().map(|alive| alive.load(Ordering::Acquire)).unwrap_or(true) {
153 let ptr =
154 unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_get_display, self.ptr) };
155 NonNull::new(ptr).ok_or(InvalidId)
156 } else {
157 Err(InvalidId)
158 }
159 }
160}
161
162impl std::fmt::Display for InnerObjectId {
163 #[cfg_attr(unstable_coverage, coverage(off))]
164 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165 write!(f, "{}@{}", self.interface.name, self.id)
166 }
167}
168
169impl std::fmt::Debug for InnerObjectId {
170 #[cfg_attr(unstable_coverage, coverage(off))]
171 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172 write!(f, "ObjectId({self})")
173 }
174}
175
176struct ProxyUserData {
177 alive: Arc<AtomicBool>,
178 data: Arc<dyn ObjectData>,
179 interface: &'static Interface,
180}
181
182#[derive(Debug)]
183struct ConnectionState {
184 display: *mut wl_display,
185 owns_display: bool,
186 evq: *mut wl_event_queue,
187 display_id: InnerObjectId,
188 last_error: Option<WaylandError>,
189 known_proxies: HashSet<*mut wl_proxy>,
190}
191
192unsafe impl Send for ConnectionState {}
193
194#[derive(Debug)]
195struct Dispatcher;
196
197#[derive(Debug)]
198struct Inner {
199 state: Mutex<ConnectionState>,
200 dispatch_lock: Mutex<Dispatcher>,
201 debug: bool,
202}
203
204#[derive(Clone, Debug)]
205pub struct InnerBackend {
206 inner: Arc<Inner>,
207}
208
209#[derive(Clone, Debug)]
210pub struct WeakInnerBackend {
211 inner: Weak<Inner>,
212}
213
214impl InnerBackend {
215 fn lock_state(&self) -> MutexGuard<'_, ConnectionState> {
216 self.inner.state.lock().unwrap()
217 }
218
219 pub fn downgrade(&self) -> WeakInnerBackend {
220 WeakInnerBackend { inner: Arc::downgrade(&self.inner) }
221 }
222
223 pub fn display_ptr(&self) -> *mut wl_display {
224 self.inner.state.lock().unwrap().display
225 }
226}
227
228impl WeakInnerBackend {
229 pub fn upgrade(&self) -> Option<InnerBackend> {
230 Weak::upgrade(&self.inner).map(|inner| InnerBackend { inner })
231 }
232}
233
234impl PartialEq for InnerBackend {
235 fn eq(&self, rhs: &Self) -> bool {
236 Arc::ptr_eq(&self.inner, &rhs.inner)
237 }
238}
239
240impl Eq for InnerBackend {}
241
242unsafe impl Send for InnerBackend {}
243unsafe impl Sync for InnerBackend {}
244
245impl InnerBackend {
246 pub fn connect(stream: UnixStream) -> Result<Self, NoWaylandLib> {
247 if !is_lib_available() {
248 return Err(NoWaylandLib);
249 }
250 let display = unsafe {
251 ffi_dispatch!(wayland_client_handle(), wl_display_connect_to_fd, stream.into_raw_fd())
252 };
253 if display.is_null() {
254 panic!("[wayland-backend-sys] libwayland reported an allocation failure.");
255 }
256 #[cfg(feature = "log")]
258 unsafe {
259 ffi_dispatch!(
260 wayland_client_handle(),
261 wl_log_set_handler_client,
262 wl_log_trampoline_to_rust_client
263 );
264 }
265 Ok(Self::from_display(display, true))
266 }
267
268 pub unsafe fn from_foreign_display(display: *mut wl_display) -> Self {
269 Self::from_display(display, false)
270 }
271
272 fn from_display(display: *mut wl_display, owned: bool) -> Self {
273 let evq =
274 unsafe { ffi_dispatch!(wayland_client_handle(), wl_display_create_queue, display) };
275 let display_alive = owned.then(|| Arc::new(AtomicBool::new(true)));
276 Self {
277 inner: Arc::new(Inner {
278 state: Mutex::new(ConnectionState {
279 display,
280 evq,
281 display_id: InnerObjectId {
282 id: 1,
283 ptr: display as *mut wl_proxy,
284 alive: display_alive,
285 interface: &WL_DISPLAY_INTERFACE,
286 },
287 owns_display: owned,
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 #[cfg(feature = "libwayland_client_1_23")]
325 pub fn set_max_buffer_size(&self, max_buffer_size: Option<usize>) {
326 let guard = self.lock_state();
327 unsafe {
328 ffi_dispatch!(
329 wayland_client_handle(),
330 wl_display_set_max_buffer_size,
331 guard.display,
332 max_buffer_size.unwrap_or(0)
333 )
334 }
335 }
336}
337
338impl ConnectionState {
339 #[inline]
340 fn no_last_error(&self) -> Result<(), WaylandError> {
341 if let Some(ref err) = self.last_error {
342 Err(err.clone())
343 } else {
344 Ok(())
345 }
346 }
347
348 #[inline]
349 fn store_and_return_error(&mut self, err: std::io::Error) -> WaylandError {
350 let err = if err.raw_os_error() == Some(rustix::io::Errno::PROTO.raw_os_error()) {
352 let mut object_id = 0;
353 let mut interface = std::ptr::null();
354 let code = unsafe {
355 ffi_dispatch!(
356 wayland_client_handle(),
357 wl_display_get_protocol_error,
358 self.display,
359 &mut interface,
360 &mut object_id
361 )
362 };
363 let object_interface = unsafe {
364 if interface.is_null() {
365 String::new()
366 } else {
367 let cstr = std::ffi::CStr::from_ptr((*interface).name);
368 cstr.to_string_lossy().into()
369 }
370 };
371 WaylandError::Protocol(ProtocolError {
372 code,
373 object_id,
374 object_interface,
375 message: String::new(),
376 })
377 } else {
378 WaylandError::Io(err)
379 };
380 crate::log_error!("{err}");
381 self.last_error = Some(err.clone());
382 err
383 }
384
385 #[inline]
386 fn store_if_not_wouldblock_and_return_error(&mut self, e: std::io::Error) -> WaylandError {
387 if e.kind() != std::io::ErrorKind::WouldBlock {
388 self.store_and_return_error(e)
389 } else {
390 e.into()
391 }
392 }
393}
394
395impl Dispatcher {
396 fn dispatch_pending(&self, inner: Arc<Inner>) -> Result<usize, WaylandError> {
397 let (display, evq) = {
398 let guard = inner.state.lock().unwrap();
399 (guard.display, guard.evq)
400 };
401 let backend = Backend { backend: InnerBackend { inner } };
402
403 let ret = BACKEND.set(&backend, || unsafe {
406 ffi_dispatch!(wayland_client_handle(), wl_display_dispatch_queue_pending, display, evq)
407 });
408 if ret < 0 {
409 Err(backend
410 .backend
411 .inner
412 .state
413 .lock()
414 .unwrap()
415 .store_if_not_wouldblock_and_return_error(std::io::Error::last_os_error()))
416 } else {
417 Ok(ret as usize)
418 }
419 }
420}
421
422#[derive(Debug)]
423pub struct InnerReadEventsGuard {
424 inner: Arc<Inner>,
425 display: *mut wl_display,
426 done: bool,
427}
428
429impl InnerReadEventsGuard {
430 pub fn try_new(backend: InnerBackend) -> Option<Self> {
431 let (display, evq) = {
432 let guard = backend.lock_state();
433 (guard.display, guard.evq)
434 };
435
436 let ret = unsafe {
437 ffi_dispatch!(wayland_client_handle(), wl_display_prepare_read_queue, display, evq)
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.read_non_dispatch()?;
458 self.inner.dispatch_lock.lock().unwrap().dispatch_pending(self.inner.clone())
460 }
461
462 pub fn read_non_dispatch(&mut self) -> Result<(), WaylandError> {
463 self.done = true;
464 let ret =
465 unsafe { ffi_dispatch!(wayland_client_handle(), wl_display_read_events, self.display) };
466 if ret < 0 {
467 Err(self
469 .inner
470 .state
471 .lock()
472 .unwrap()
473 .store_if_not_wouldblock_and_return_error(std::io::Error::last_os_error()))
474 } else {
475 Ok(())
476 }
477 }
478}
479
480impl Drop for InnerReadEventsGuard {
481 fn drop(&mut self) {
482 if !self.done {
483 unsafe {
484 ffi_dispatch!(wayland_client_handle(), wl_display_cancel_read, self.display);
485 }
486 }
487 }
488}
489
490impl InnerBackend {
491 pub fn display_id(&self) -> ObjectId {
492 ObjectId { id: self.lock_state().display_id.clone() }
493 }
494
495 pub fn last_error(&self) -> Option<WaylandError> {
496 self.lock_state().last_error.clone()
497 }
498
499 pub fn info(&self, ObjectId { id }: ObjectId) -> Result<ObjectInfo, InvalidId> {
500 if !id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(true) || id.ptr.is_null()
501 {
502 return Err(InvalidId);
503 }
504
505 let version = if id.id == 1 {
506 1
508 } else {
509 unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_get_version, id.ptr) }
510 };
511
512 Ok(ObjectInfo { id: id.id, interface: id.interface, version })
513 }
514
515 pub fn null_id() -> ObjectId {
516 ObjectId {
517 id: InnerObjectId {
518 ptr: std::ptr::null_mut(),
519 interface: &ANONYMOUS_INTERFACE,
520 id: 0,
521 alive: None,
522 },
523 }
524 }
525
526 fn destroy_object_inner(&self, guard: &mut MutexGuard<ConnectionState>, id: &ObjectId) {
527 if let Some(ref alive) = id.id.alive {
528 let udata = unsafe {
529 Box::from_raw(ffi_dispatch!(
530 wayland_client_handle(),
531 wl_proxy_get_user_data,
532 id.id.ptr
533 ) as *mut ProxyUserData)
534 };
535 unsafe {
536 ffi_dispatch!(
537 wayland_client_handle(),
538 wl_proxy_set_user_data,
539 id.id.ptr,
540 std::ptr::null_mut()
541 );
542 }
543 alive.store(false, Ordering::Release);
544 udata.data.destroyed(id.clone());
545 }
546
547 guard.known_proxies.remove(&id.id.ptr);
548
549 unsafe {
550 ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, id.id.ptr);
551 }
552 }
553
554 pub fn destroy_object(&self, id: &ObjectId) -> Result<(), InvalidId> {
555 if !id.id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(false) {
556 return Err(InvalidId);
557 }
558
559 self.destroy_object_inner(&mut self.lock_state(), id);
560 Ok(())
561 }
562
563 pub fn send_request(
564 &self,
565 Message { sender_id: ObjectId { id }, opcode, args }: Message<ObjectId, RawFd>,
566 data: Option<Arc<dyn ObjectData>>,
567 child_spec: Option<(&'static Interface, u32)>,
568 ) -> Result<ObjectId, InvalidId> {
569 let mut guard = self.lock_state();
570
571 if id.is_null() {
572 return Err(InvalidId);
573 }
574
575 let message_desc = match id.interface.requests.get(opcode as usize) {
577 Some(msg) => msg,
578 None => {
579 panic!("Unknown opcode {} for object {}@{}.", opcode, id.interface.name, id.id);
580 }
581 };
582
583 if !id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(true) {
584 if self.inner.debug {
585 debug::print_send_message(id.interface.name, id.id, message_desc.name, &args, true);
586 }
587 return Err(InvalidId);
588 }
589
590 let parent_version = if id.id == 1 {
591 1
592 } else {
593 unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_get_version, id.ptr) }
594 };
595
596 if !check_for_signature(message_desc.signature, &args) {
597 panic!(
598 "Unexpected signature for request {}@{}.{}: expected {:?}, got {:?}.",
599 id.interface.name, id.id, message_desc.name, message_desc.signature, args
600 );
601 }
602
603 let child_spec = if message_desc
605 .signature
606 .iter()
607 .any(|arg| matches!(arg, ArgumentType::NewId))
608 {
609 if let Some((iface, version)) = child_spec {
610 if let Some(child_interface) = message_desc.child_interface {
611 if !same_interface(child_interface, iface) {
612 panic!(
613 "Wrong placeholder used when sending request {}@{}.{}: expected interface {} but got {}",
614 id.interface.name,
615 id.id,
616 message_desc.name,
617 child_interface.name,
618 iface.name
619 );
620 }
621 if version != parent_version {
622 panic!(
623 "Wrong placeholder used when sending request {}@{}.{}: expected version {} but got {}",
624 id.interface.name,
625 id.id,
626 message_desc.name,
627 parent_version,
628 version
629 );
630 }
631 }
632 Some((iface, version))
633 } else if let Some(child_interface) = message_desc.child_interface {
634 Some((child_interface, parent_version))
635 } else {
636 panic!(
637 "Wrong placeholder used when sending request {}@{}.{}: target interface must be specified for a generic constructor.",
638 id.interface.name,
639 id.id,
640 message_desc.name
641 );
642 }
643 } else {
644 None
645 };
646
647 let child_interface_ptr = child_spec
648 .as_ref()
649 .map(|(i, _)| {
650 i.c_ptr.expect("[wayland-backend-sys] Cannot use Interface without c_ptr!")
651 as *const _
652 })
653 .unwrap_or(std::ptr::null());
654 let child_version = child_spec.as_ref().map(|(_, v)| *v).unwrap_or(parent_version);
655
656 let mut argument_list = SmallVec::<[wl_argument; 4]>::with_capacity(args.len());
658 let mut arg_interfaces = message_desc.arg_interfaces.iter();
659 for (i, arg) in args.iter().enumerate() {
660 match *arg {
661 Argument::Uint(u) => argument_list.push(wl_argument { u }),
662 Argument::Int(i) => argument_list.push(wl_argument { i }),
663 Argument::Fixed(f) => argument_list.push(wl_argument { f }),
664 Argument::Fd(h) => argument_list.push(wl_argument { h }),
665 Argument::Array(ref a) => {
666 let a = Box::new(wl_array {
667 size: a.len(),
668 alloc: a.len(),
669 data: a.as_ptr() as *mut _,
670 });
671 argument_list.push(wl_argument { a: Box::into_raw(a) })
672 }
673 Argument::Str(Some(ref s)) => argument_list.push(wl_argument { s: s.as_ptr() }),
674 Argument::Str(None) => argument_list.push(wl_argument { s: std::ptr::null() }),
675 Argument::Object(ref o) => {
676 let next_interface = arg_interfaces.next().unwrap();
677 if !o.id.ptr.is_null() {
678 if !o.id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(true) {
679 unsafe { free_arrays(message_desc.signature, &argument_list) };
680 return Err(InvalidId);
681 }
682 if !same_interface(next_interface, o.id.interface) {
683 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);
684 }
685 } else if !matches!(
686 message_desc.signature[i],
687 ArgumentType::Object(AllowNull::Yes)
688 ) {
689 panic!(
690 "Request {}@{}.{} expects an non-null object argument.",
691 id.interface.name, id.id, message_desc.name
692 );
693 }
694 argument_list.push(wl_argument { o: o.id.ptr as *const _ })
695 }
696 Argument::NewId(_) => argument_list.push(wl_argument { n: 0 }),
697 }
698 }
699
700 let ret = if child_spec.is_none() {
701 unsafe {
702 ffi_dispatch!(
703 wayland_client_handle(),
704 wl_proxy_marshal_array,
705 id.ptr,
706 opcode as u32,
707 argument_list.as_mut_ptr(),
708 )
709 }
710 std::ptr::null_mut()
711 } else {
712 unsafe {
714 let wrapped_ptr =
715 ffi_dispatch!(wayland_client_handle(), wl_proxy_create_wrapper, id.ptr);
716 ffi_dispatch!(wayland_client_handle(), wl_proxy_set_queue, wrapped_ptr, guard.evq);
717 let ret = ffi_dispatch!(
718 wayland_client_handle(),
719 wl_proxy_marshal_array_constructor_versioned,
720 wrapped_ptr,
721 opcode as u32,
722 argument_list.as_mut_ptr(),
723 child_interface_ptr,
724 child_version
725 );
726 ffi_dispatch!(wayland_client_handle(), wl_proxy_wrapper_destroy, wrapped_ptr);
727 ret
728 }
729 };
730
731 unsafe {
732 free_arrays(message_desc.signature, &argument_list);
733 }
734
735 if ret.is_null() && child_spec.is_some() {
736 panic!("[wayland-backend-sys] libwayland reported an allocation failure.");
737 }
738
739 let child_id = if let Some((child_interface, _)) = child_spec {
741 let data = match data {
742 Some(data) => data,
743 None => {
744 unsafe {
747 ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, ret);
748 }
749 panic!(
750 "Sending a request creating an object without providing an object data."
751 );
752 }
753 };
754
755 unsafe { self.manage_object_internal(child_interface, ret, data, &mut guard) }
756 } else {
757 Self::null_id()
758 };
759
760 if message_desc.is_destructor {
761 self.destroy_object_inner(&mut guard, &ObjectId { id })
762 }
763
764 Ok(child_id)
765 }
766
767 pub fn get_data(&self, ObjectId { id }: ObjectId) -> Result<Arc<dyn ObjectData>, InvalidId> {
768 if !id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(false) {
769 return Err(InvalidId);
770 }
771
772 if id.id == 1 {
773 return Ok(Arc::new(DumbObjectData));
775 }
776
777 let udata = unsafe {
778 &*(ffi_dispatch!(wayland_client_handle(), wl_proxy_get_user_data, id.ptr)
779 as *mut ProxyUserData)
780 };
781 Ok(udata.data.clone())
782 }
783
784 pub fn set_data(
785 &self,
786 ObjectId { id }: ObjectId,
787 data: Arc<dyn ObjectData>,
788 ) -> Result<(), 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 {
795 return Err(InvalidId);
796 }
797
798 let udata = unsafe {
799 &mut *(ffi_dispatch!(wayland_client_handle(), wl_proxy_get_user_data, id.ptr)
800 as *mut ProxyUserData)
801 };
802
803 udata.data = data;
804
805 Ok(())
806 }
807
808 pub unsafe fn manage_object(
815 &self,
816 interface: &'static Interface,
817 proxy: *mut wl_proxy,
818 data: Arc<dyn ObjectData>,
819 ) -> ObjectId {
820 let mut guard = self.lock_state();
821 unsafe {
822 ffi_dispatch!(wayland_client_handle(), wl_proxy_set_queue, proxy, guard.evq);
823 self.manage_object_internal(interface, proxy, data, &mut guard)
824 }
825 }
826
827 unsafe fn manage_object_internal(
831 &self,
832 interface: &'static Interface,
833 proxy: *mut wl_proxy,
834 data: Arc<dyn ObjectData>,
835 guard: &mut MutexGuard<ConnectionState>,
836 ) -> ObjectId {
837 let alive = Arc::new(AtomicBool::new(true));
838 let object_id = ObjectId {
839 id: InnerObjectId {
840 ptr: proxy,
841 alive: Some(alive.clone()),
842 id: unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, proxy) },
843 interface,
844 },
845 };
846
847 guard.known_proxies.insert(proxy);
848
849 let udata = Box::new(ProxyUserData { alive, data, interface });
850 unsafe {
851 ffi_dispatch!(
852 wayland_client_handle(),
853 wl_proxy_add_dispatcher,
854 proxy,
855 dispatcher_func,
856 &RUST_MANAGED as *const u8 as *const c_void,
857 Box::into_raw(udata) as *mut c_void
858 );
859 }
860
861 object_id
862 }
863}
864
865unsafe extern "C" fn dispatcher_func(
866 _: *const c_void,
867 proxy: *mut c_void,
868 opcode: u32,
869 _: *const wl_message,
870 args: *const wl_argument,
871) -> c_int {
872 let proxy = proxy as *mut wl_proxy;
873
874 let udata_ptr = unsafe {
876 ffi_dispatch!(wayland_client_handle(), wl_proxy_get_user_data, proxy) as *mut ProxyUserData
877 };
878 let udata = unsafe { &mut *udata_ptr };
879
880 let interface = udata.interface;
881 let message_desc = match interface.events.get(opcode as usize) {
882 Some(desc) => desc,
883 None => {
884 crate::log_error!("Unknown event opcode {} for interface {}.", opcode, interface.name);
885 return -1;
886 }
887 };
888
889 let mut parsed_args =
890 SmallVec::<[Argument<ObjectId, OwnedFd>; 4]>::with_capacity(message_desc.signature.len());
891 let mut arg_interfaces = message_desc.arg_interfaces.iter().copied();
892 let mut created = None;
893 for (i, typ) in message_desc.signature.iter().enumerate() {
895 match typ {
896 ArgumentType::Uint => parsed_args.push(Argument::Uint(unsafe { (*args.add(i)).u })),
897 ArgumentType::Int => parsed_args.push(Argument::Int(unsafe { (*args.add(i)).i })),
898 ArgumentType::Fixed => parsed_args.push(Argument::Fixed(unsafe { (*args.add(i)).f })),
899 ArgumentType::Fd => {
900 parsed_args.push(Argument::Fd(unsafe { OwnedFd::from_raw_fd((*args.add(i)).h) }))
901 }
902 ArgumentType::Array => {
903 let array = unsafe { &*((*args.add(i)).a) };
904 let content =
906 unsafe { std::slice::from_raw_parts(array.data as *mut u8, array.size) };
907 parsed_args.push(Argument::Array(Box::new(content.into())));
908 }
909 ArgumentType::Str(_) => {
910 let ptr = unsafe { (*args.add(i)).s };
911 if !ptr.is_null() {
913 let cstr = unsafe { std::ffi::CStr::from_ptr(ptr) };
914 parsed_args.push(Argument::Str(Some(Box::new(cstr.into()))));
915 } else {
916 parsed_args.push(Argument::Str(None));
917 }
918 }
919 ArgumentType::Object(_) => {
920 let obj = unsafe { (*args.add(i)).o as *mut wl_proxy };
921 if !obj.is_null() {
922 let obj_id = ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, obj);
924 let next_interface = arg_interfaces.next().unwrap_or(&ANONYMOUS_INTERFACE);
926 let listener =
927 ffi_dispatch!(wayland_client_handle(), wl_proxy_get_listener, obj);
928 if ptr::eq(listener, &RUST_MANAGED as *const u8 as *const c_void) {
929 let obj_udata = unsafe {
931 &*(ffi_dispatch!(wayland_client_handle(), wl_proxy_get_user_data, obj)
932 as *mut ProxyUserData)
933 };
934 if !same_interface(next_interface, obj_udata.interface) {
935 crate::log_error!(
936 "Received object {}@{} in {}.{} but expected interface {}.",
937 obj_udata.interface.name,
938 obj_id,
939 interface.name,
940 message_desc.name,
941 next_interface.name,
942 );
943 return -1;
944 }
945 parsed_args.push(Argument::Object(ObjectId {
946 id: InnerObjectId {
947 alive: Some(obj_udata.alive.clone()),
948 ptr: obj,
949 id: obj_id,
950 interface: obj_udata.interface,
951 },
952 }));
953 } else {
954 parsed_args.push(Argument::Object(ObjectId {
955 id: InnerObjectId {
956 alive: None,
957 id: obj_id,
958 ptr: obj,
959 interface: next_interface,
960 },
961 }));
962 }
963 } else {
964 parsed_args.push(Argument::Object(ObjectId {
966 id: InnerObjectId {
967 alive: None,
968 id: 0,
969 ptr: std::ptr::null_mut(),
970 interface: &ANONYMOUS_INTERFACE,
971 },
972 }))
973 }
974 }
975 ArgumentType::NewId => {
976 let obj = unsafe { (*args.add(i)).o as *mut wl_proxy };
977 if !obj.is_null() {
979 let child_interface = message_desc.child_interface.unwrap_or_else(|| {
980 crate::log_warn!(
981 "Event {}.{} creates an anonymous object.",
982 interface.name,
983 opcode
984 );
985 &ANONYMOUS_INTERFACE
986 });
987 let child_alive = Arc::new(AtomicBool::new(true));
988 let child_id = InnerObjectId {
989 ptr: obj,
990 alive: Some(child_alive.clone()),
991 id: ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, obj),
992 interface: child_interface,
993 };
994 let child_udata = Box::into_raw(Box::new(ProxyUserData {
995 alive: child_alive,
996 data: Arc::new(UninitObjectData),
997 interface: child_interface,
998 }));
999 created = Some((child_id.clone(), child_udata));
1000 ffi_dispatch!(
1001 wayland_client_handle(),
1002 wl_proxy_add_dispatcher,
1003 obj,
1004 dispatcher_func,
1005 &RUST_MANAGED as *const u8 as *const c_void,
1006 child_udata as *mut c_void
1007 );
1008 parsed_args.push(Argument::NewId(ObjectId { id: child_id }));
1009 } else {
1010 parsed_args.push(Argument::NewId(ObjectId {
1011 id: InnerObjectId {
1012 id: 0,
1013 ptr: std::ptr::null_mut(),
1014 alive: None,
1015 interface: &ANONYMOUS_INTERFACE,
1016 },
1017 }))
1018 }
1019 }
1020 }
1021 }
1022
1023 let proxy_id = ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, proxy);
1024 let id = ObjectId {
1025 id: InnerObjectId {
1026 alive: Some(udata.alive.clone()),
1027 ptr: proxy,
1028 id: proxy_id,
1029 interface: udata.interface,
1030 },
1031 };
1032
1033 let ret = BACKEND.with(|backend| {
1034 let mut guard = backend.backend.lock_state();
1035 if let Some((ref new_id, _)) = created {
1036 guard.known_proxies.insert(new_id.ptr);
1037 }
1038 if message_desc.is_destructor {
1039 guard.known_proxies.remove(&proxy);
1040 }
1041 std::mem::drop(guard);
1042 udata.data.clone().event(
1043 backend,
1044 Message { sender_id: id.clone(), opcode: opcode as u16, args: parsed_args },
1045 )
1046 });
1047
1048 if message_desc.is_destructor {
1049 let udata = unsafe { Box::from_raw(udata_ptr) };
1051 ffi_dispatch!(wayland_client_handle(), wl_proxy_set_user_data, proxy, std::ptr::null_mut());
1052 udata.alive.store(false, Ordering::Release);
1053 udata.data.destroyed(id);
1054 ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, proxy);
1055 }
1056
1057 match (created, ret) {
1058 (Some((_, child_udata_ptr)), Some(child_data)) => {
1059 unsafe {
1061 (*child_udata_ptr).data = child_data;
1062 }
1063 }
1064 (Some((child_id, _)), None) => {
1065 panic!("Callback creating object {child_id} did not provide any object data.");
1066 }
1067 (None, Some(_)) => {
1068 panic!("An object data was returned from a callback not creating any object");
1069 }
1070 (None, None) => {}
1071 }
1072
1073 0
1074}
1075
1076#[cfg(feature = "log")]
1077extern "C" {
1078 fn wl_log_trampoline_to_rust_client(fmt: *const std::os::raw::c_char, list: *const c_void);
1079}
1080
1081impl Drop for ConnectionState {
1082 fn drop(&mut self) {
1083 for proxy_ptr in self.known_proxies.drain() {
1086 let _ = unsafe {
1087 Box::from_raw(ffi_dispatch!(
1088 wayland_client_handle(),
1089 wl_proxy_get_user_data,
1090 proxy_ptr
1091 ) as *mut ProxyUserData)
1092 };
1093 unsafe {
1094 ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, proxy_ptr);
1095 }
1096 }
1097 unsafe { ffi_dispatch!(wayland_client_handle(), wl_event_queue_destroy, self.evq) }
1098 if self.owns_display {
1099 unsafe { ffi_dispatch!(wayland_client_handle(), wl_display_disconnect, self.display) }
1101 }
1102 }
1103}