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 {
133 &*(ffi_dispatch!(wayland_client_handle(), wl_proxy_get_user_data, ptr)
134 as *mut ProxyUserData)
135 };
136 Some(udata.alive.clone())
137 } else {
138 None
139 };
140
141 Ok(Self { id, ptr, alive, interface })
142 }
143
144 pub fn as_ptr(&self) -> Result<NonNull<wl_proxy>, InvalidId> {
145 if self.alive.as_ref().map(|alive| alive.load(Ordering::Acquire)).unwrap_or(true) {
146 NonNull::new(self.ptr).ok_or(InvalidId)
147 } else {
148 Err(InvalidId)
149 }
150 }
151
152 #[cfg(feature = "libwayland_client_1_23")]
153 pub fn display_ptr(&self) -> Result<NonNull<wl_display>, InvalidId> {
154 if self.alive.as_ref().map(|alive| alive.load(Ordering::Acquire)).unwrap_or(true) {
155 let ptr =
156 unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_get_display, self.ptr) };
157 NonNull::new(ptr).ok_or(InvalidId)
158 } else {
159 Err(InvalidId)
160 }
161 }
162}
163
164impl std::fmt::Display for InnerObjectId {
165 #[cfg_attr(unstable_coverage, coverage(off))]
166 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167 write!(f, "{}@{}", self.interface.name, self.id)
168 }
169}
170
171impl std::fmt::Debug for InnerObjectId {
172 #[cfg_attr(unstable_coverage, coverage(off))]
173 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
174 write!(f, "ObjectId({self})")
175 }
176}
177
178#[derive(Clone)]
179struct ProxyUserData {
180 alive: Arc<AtomicBool>,
181 data: Arc<dyn ObjectData>,
182 interface: &'static Interface,
183}
184
185#[derive(Debug)]
186struct ConnectionState {
187 display: *mut wl_display,
188 owns_display: bool,
189 evq: *mut wl_event_queue,
190 display_id: InnerObjectId,
191 last_error: Option<WaylandError>,
192 known_proxies: HashSet<*mut wl_proxy>,
193}
194
195unsafe impl Send for ConnectionState {}
196
197#[derive(Debug)]
198struct Dispatcher;
199
200#[derive(Debug)]
201struct Inner {
202 state: Mutex<ConnectionState>,
203 dispatch_lock: Mutex<Dispatcher>,
204 debug: bool,
205}
206
207#[derive(Clone, Debug)]
208pub struct InnerBackend {
209 inner: Arc<Inner>,
210}
211
212#[derive(Clone, Debug)]
213pub struct WeakInnerBackend {
214 inner: Weak<Inner>,
215}
216
217impl InnerBackend {
218 fn lock_state(&self) -> MutexGuard<'_, ConnectionState> {
219 self.inner.state.lock().unwrap()
220 }
221
222 pub fn downgrade(&self) -> WeakInnerBackend {
223 WeakInnerBackend { inner: Arc::downgrade(&self.inner) }
224 }
225
226 pub fn display_ptr(&self) -> *mut wl_display {
227 self.inner.state.lock().unwrap().display
228 }
229}
230
231impl WeakInnerBackend {
232 pub fn upgrade(&self) -> Option<InnerBackend> {
233 Weak::upgrade(&self.inner).map(|inner| InnerBackend { inner })
234 }
235}
236
237impl PartialEq for InnerBackend {
238 fn eq(&self, rhs: &Self) -> bool {
239 Arc::ptr_eq(&self.inner, &rhs.inner)
240 }
241}
242
243impl Eq for InnerBackend {}
244
245unsafe impl Send for InnerBackend {}
246unsafe impl Sync for InnerBackend {}
247
248impl InnerBackend {
249 pub fn connect(stream: UnixStream) -> Result<Self, NoWaylandLib> {
250 if !is_lib_available() {
251 return Err(NoWaylandLib);
252 }
253 let display = unsafe {
254 ffi_dispatch!(wayland_client_handle(), wl_display_connect_to_fd, stream.into_raw_fd())
255 };
256 if display.is_null() {
257 panic!("[wayland-backend-sys] libwayland reported an allocation failure.");
258 }
259 #[cfg(feature = "log")]
261 unsafe {
262 ffi_dispatch!(
263 wayland_client_handle(),
264 wl_log_set_handler_client,
265 wl_log_trampoline_to_rust_client
266 );
267 }
268 Ok(Self::from_display(display, true))
269 }
270
271 pub unsafe fn from_foreign_display(display: *mut wl_display) -> Self {
272 Self::from_display(display, false)
273 }
274
275 fn from_display(display: *mut wl_display, owned: bool) -> Self {
276 let evq =
277 unsafe { ffi_dispatch!(wayland_client_handle(), wl_display_create_queue, display) };
278 let display_alive = owned.then(|| Arc::new(AtomicBool::new(true)));
279 Self {
280 inner: Arc::new(Inner {
281 state: Mutex::new(ConnectionState {
282 display,
283 evq,
284 display_id: InnerObjectId {
285 id: 1,
286 ptr: display as *mut wl_proxy,
287 alive: display_alive,
288 interface: &WL_DISPLAY_INTERFACE,
289 },
290 owns_display: owned,
291 last_error: None,
292 known_proxies: HashSet::new(),
293 }),
294 debug: has_debug_client_env(),
295 dispatch_lock: Mutex::new(Dispatcher),
296 }),
297 }
298 }
299
300 pub fn flush(&self) -> Result<(), WaylandError> {
301 let mut guard = self.lock_state();
302 guard.no_last_error()?;
303 let ret =
304 unsafe { ffi_dispatch!(wayland_client_handle(), wl_display_flush, guard.display) };
305 if ret < 0 {
306 Err(guard.store_if_not_wouldblock_and_return_error(std::io::Error::last_os_error()))
307 } else {
308 Ok(())
309 }
310 }
311
312 pub fn poll_fd(&self) -> BorrowedFd<'_> {
313 let guard = self.lock_state();
314 unsafe {
315 BorrowedFd::borrow_raw(ffi_dispatch!(
316 wayland_client_handle(),
317 wl_display_get_fd,
318 guard.display
319 ))
320 }
321 }
322
323 pub fn dispatch_inner_queue(&self) -> Result<usize, WaylandError> {
324 self.inner.dispatch_lock.lock().unwrap().dispatch_pending(self.inner.clone())
325 }
326
327 #[cfg(feature = "libwayland_client_1_23")]
328 pub fn set_max_buffer_size(&self, max_buffer_size: Option<usize>) {
329 let guard = self.lock_state();
330 unsafe {
331 ffi_dispatch!(
332 wayland_client_handle(),
333 wl_display_set_max_buffer_size,
334 guard.display,
335 max_buffer_size.unwrap_or(0)
336 )
337 }
338 }
339}
340
341impl ConnectionState {
342 #[inline]
343 fn no_last_error(&self) -> Result<(), WaylandError> {
344 if let Some(ref err) = self.last_error {
345 Err(err.clone())
346 } else {
347 Ok(())
348 }
349 }
350
351 #[inline]
352 fn store_and_return_error(&mut self, err: std::io::Error) -> WaylandError {
353 let err = if err.raw_os_error() == Some(rustix::io::Errno::PROTO.raw_os_error()) {
355 let mut object_id = 0;
356 let mut interface = std::ptr::null();
357 let code = unsafe {
358 ffi_dispatch!(
359 wayland_client_handle(),
360 wl_display_get_protocol_error,
361 self.display,
362 &mut interface,
363 &mut object_id
364 )
365 };
366 let object_interface = unsafe {
367 if interface.is_null() {
368 String::new()
369 } else {
370 let cstr = std::ffi::CStr::from_ptr((*interface).name);
371 cstr.to_string_lossy().into()
372 }
373 };
374 WaylandError::Protocol(ProtocolError {
375 code,
376 object_id,
377 object_interface,
378 message: String::new(),
379 })
380 } else {
381 WaylandError::Io(err)
382 };
383 crate::log_error!("{err}");
384 self.last_error = Some(err.clone());
385 err
386 }
387
388 #[inline]
389 fn store_if_not_wouldblock_and_return_error(&mut self, e: std::io::Error) -> WaylandError {
390 if e.kind() != std::io::ErrorKind::WouldBlock {
391 self.store_and_return_error(e)
392 } else {
393 e.into()
394 }
395 }
396}
397
398impl Dispatcher {
399 fn dispatch_pending(&self, inner: Arc<Inner>) -> Result<usize, WaylandError> {
400 let (display, evq) = {
401 let guard = inner.state.lock().unwrap();
402 (guard.display, guard.evq)
403 };
404 let backend = Backend { backend: InnerBackend { inner } };
405
406 let ret = BACKEND.set(&backend, || unsafe {
409 ffi_dispatch!(wayland_client_handle(), wl_display_dispatch_queue_pending, display, evq)
414 });
415 if ret < 0 {
416 Err(backend
417 .backend
418 .inner
419 .state
420 .lock()
421 .unwrap()
422 .store_if_not_wouldblock_and_return_error(std::io::Error::last_os_error()))
423 } else {
424 Ok(ret as usize)
425 }
426 }
427}
428
429#[derive(Debug)]
430pub struct InnerReadEventsGuard {
431 inner: Arc<Inner>,
432 display: *mut wl_display,
433 done: bool,
434}
435
436impl InnerReadEventsGuard {
437 pub fn try_new(backend: InnerBackend) -> Option<Self> {
438 let (display, evq) = {
439 let guard = backend.lock_state();
440 (guard.display, guard.evq)
441 };
442
443 let ret = unsafe {
444 ffi_dispatch!(wayland_client_handle(), wl_display_prepare_read_queue, display, evq)
445 };
446 if ret < 0 {
447 None
448 } else {
449 Some(Self { inner: backend.inner, display, done: false })
450 }
451 }
452
453 pub fn connection_fd(&self) -> BorrowedFd<'_> {
454 unsafe {
455 BorrowedFd::borrow_raw(ffi_dispatch!(
456 wayland_client_handle(),
457 wl_display_get_fd,
458 self.display
459 ))
460 }
461 }
462
463 pub fn read(mut self) -> Result<usize, WaylandError> {
464 self.read_non_dispatch()?;
465 self.inner.dispatch_lock.lock().unwrap().dispatch_pending(self.inner.clone())
467 }
468
469 pub fn read_non_dispatch(&mut self) -> Result<(), WaylandError> {
470 self.done = true;
471 let ret =
472 unsafe { ffi_dispatch!(wayland_client_handle(), wl_display_read_events, self.display) };
473 if ret < 0 {
474 Err(self
476 .inner
477 .state
478 .lock()
479 .unwrap()
480 .store_if_not_wouldblock_and_return_error(std::io::Error::last_os_error()))
481 } else {
482 Ok(())
483 }
484 }
485}
486
487impl Drop for InnerReadEventsGuard {
488 fn drop(&mut self) {
489 if !self.done {
490 unsafe {
491 ffi_dispatch!(wayland_client_handle(), wl_display_cancel_read, self.display);
492 }
493 }
494 }
495}
496
497impl InnerBackend {
498 pub fn display_id(&self) -> ObjectId {
499 ObjectId { id: self.lock_state().display_id.clone() }
500 }
501
502 pub fn last_error(&self) -> Option<WaylandError> {
503 self.lock_state().last_error.clone()
504 }
505
506 pub fn info(&self, ObjectId { id }: ObjectId) -> Result<ObjectInfo, InvalidId> {
507 if !id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(true) || id.ptr.is_null()
508 {
509 return Err(InvalidId);
510 }
511
512 let version = if id.id == 1 {
513 1
515 } else {
516 unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_get_version, id.ptr) }
517 };
518
519 Ok(ObjectInfo { id: id.id, interface: id.interface, version })
520 }
521
522 pub fn null_id() -> ObjectId {
523 ObjectId {
524 id: InnerObjectId {
525 ptr: std::ptr::null_mut(),
526 interface: &ANONYMOUS_INTERFACE,
527 id: 0,
528 alive: None,
529 },
530 }
531 }
532
533 fn destroy_object_inner(&self, mut guard: MutexGuard<ConnectionState>, id: &ObjectId) {
534 if let Some(ref alive) = id.id.alive {
535 let udata = unsafe {
537 ffi_dispatch!(wayland_client_handle(), wl_proxy_get_user_data, id.id.ptr)
538 };
539 if udata.is_null() {
540 panic!("NULL user data on object {id:?}");
541 }
542 unsafe {
543 ffi_dispatch!(
544 wayland_client_handle(),
545 wl_proxy_set_user_data,
546 id.id.ptr,
547 std::ptr::null_mut()
548 );
549 }
550 let udata = unsafe { Box::from_raw(udata as *mut ProxyUserData) };
551 alive.store(false, Ordering::Release);
552 guard.known_proxies.remove(&id.id.ptr);
553 drop(guard);
554 udata.data.destroyed(id.clone());
555 }
556
557 unsafe {
558 ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, id.id.ptr);
559 }
560 }
561
562 pub fn destroy_object(&self, id: &ObjectId) -> Result<(), InvalidId> {
563 let guard = self.lock_state();
564
565 if !id.id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(false) {
566 return Err(InvalidId);
567 }
568
569 self.destroy_object_inner(guard, id);
570 Ok(())
571 }
572
573 pub fn send_request(
574 &self,
575 Message { sender_id: ObjectId { id }, opcode, args }: Message<ObjectId, RawFd>,
576 data: Option<Arc<dyn ObjectData>>,
577 child_spec: Option<(&'static Interface, u32)>,
578 ) -> Result<ObjectId, InvalidId> {
579 let mut guard = self.lock_state();
580
581 if id.is_null() {
582 return Err(InvalidId);
583 }
584
585 let message_desc = match id.interface.requests.get(opcode as usize) {
587 Some(msg) => msg,
588 None => {
589 panic!("Unknown opcode {} for object {}@{}.", opcode, id.interface.name, id.id);
590 }
591 };
592
593 if !id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(true) {
594 if self.inner.debug {
595 debug::print_send_message(id.interface.name, id.id, message_desc.name, &args, true);
596 }
597 return Err(InvalidId);
598 }
599
600 let parent_version = if id.id == 1 {
601 1
602 } else {
603 unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_get_version, id.ptr) }
604 };
605
606 if !check_for_signature(message_desc.signature, &args) {
607 panic!(
608 "Unexpected signature for request {}@{}.{}: expected {:?}, got {:?}.",
609 id.interface.name, id.id, message_desc.name, message_desc.signature, args
610 );
611 }
612
613 let child_spec = if message_desc
615 .signature
616 .iter()
617 .any(|arg| matches!(arg, ArgumentType::NewId))
618 {
619 if let Some((iface, version)) = child_spec {
620 if let Some(child_interface) = message_desc.child_interface {
621 if !same_interface(child_interface, iface) {
622 panic!(
623 "Wrong placeholder used when sending request {}@{}.{}: expected interface {} but got {}",
624 id.interface.name,
625 id.id,
626 message_desc.name,
627 child_interface.name,
628 iface.name
629 );
630 }
631 if version != parent_version {
632 panic!(
633 "Wrong placeholder used when sending request {}@{}.{}: expected version {} but got {}",
634 id.interface.name,
635 id.id,
636 message_desc.name,
637 parent_version,
638 version
639 );
640 }
641 }
642 Some((iface, version))
643 } else if let Some(child_interface) = message_desc.child_interface {
644 Some((child_interface, parent_version))
645 } else {
646 panic!(
647 "Wrong placeholder used when sending request {}@{}.{}: target interface must be specified for a generic constructor.",
648 id.interface.name,
649 id.id,
650 message_desc.name
651 );
652 }
653 } else {
654 None
655 };
656
657 let child_interface_ptr = child_spec
658 .as_ref()
659 .map(|(i, _)| {
660 i.c_ptr.expect("[wayland-backend-sys] Cannot use Interface without c_ptr!")
661 as *const _
662 })
663 .unwrap_or(std::ptr::null());
664 let child_version = child_spec.as_ref().map(|(_, v)| *v).unwrap_or(parent_version);
665
666 let mut argument_list = SmallVec::<[wl_argument; 4]>::with_capacity(args.len());
668 let mut arg_interfaces = message_desc.arg_interfaces.iter();
669 for (i, arg) in args.iter().enumerate() {
670 match *arg {
671 Argument::Uint(u) => argument_list.push(wl_argument { u }),
672 Argument::Int(i) => argument_list.push(wl_argument { i }),
673 Argument::Fixed(f) => argument_list.push(wl_argument { f }),
674 Argument::Fd(h) => argument_list.push(wl_argument { h }),
675 Argument::Array(ref a) => {
676 let a = Box::new(wl_array {
677 size: a.len(),
678 alloc: a.len(),
679 data: a.as_ptr() as *mut _,
680 });
681 argument_list.push(wl_argument { a: Box::into_raw(a) })
682 }
683 Argument::Str(Some(ref s)) => argument_list.push(wl_argument { s: s.as_ptr() }),
684 Argument::Str(None) => argument_list.push(wl_argument { s: std::ptr::null() }),
685 Argument::Object(ref o) => {
686 let next_interface = arg_interfaces.next().unwrap();
687 if !o.id.ptr.is_null() {
688 if !o.id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(true) {
689 unsafe { free_arrays(message_desc.signature, &argument_list) };
690 return Err(InvalidId);
691 }
692 if !same_interface(next_interface, o.id.interface) {
693 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);
694 }
695 } else if !matches!(
696 message_desc.signature[i],
697 ArgumentType::Object(AllowNull::Yes)
698 ) {
699 panic!(
700 "Request {}@{}.{} expects an non-null object argument.",
701 id.interface.name, id.id, message_desc.name
702 );
703 }
704 argument_list.push(wl_argument { o: o.id.ptr as *const _ })
705 }
706 Argument::NewId(_) => argument_list.push(wl_argument { n: 0 }),
707 }
708 }
709
710 let ret = if child_spec.is_none() {
711 unsafe {
712 ffi_dispatch!(
713 wayland_client_handle(),
714 wl_proxy_marshal_array,
715 id.ptr,
716 opcode as u32,
717 argument_list.as_mut_ptr(),
718 )
719 }
720 std::ptr::null_mut()
721 } else {
722 unsafe {
724 let wrapped_ptr =
725 ffi_dispatch!(wayland_client_handle(), wl_proxy_create_wrapper, id.ptr);
726 ffi_dispatch!(wayland_client_handle(), wl_proxy_set_queue, wrapped_ptr, guard.evq);
727 let ret = ffi_dispatch!(
728 wayland_client_handle(),
729 wl_proxy_marshal_array_constructor_versioned,
730 wrapped_ptr,
731 opcode as u32,
732 argument_list.as_mut_ptr(),
733 child_interface_ptr,
734 child_version
735 );
736 ffi_dispatch!(wayland_client_handle(), wl_proxy_wrapper_destroy, wrapped_ptr);
737 ret
738 }
739 };
740
741 unsafe {
742 free_arrays(message_desc.signature, &argument_list);
743 }
744
745 if ret.is_null() && child_spec.is_some() {
746 panic!("[wayland-backend-sys] libwayland reported an allocation failure.");
747 }
748
749 let child_id = if let Some((child_interface, _)) = child_spec {
751 let data = match data {
752 Some(data) => data,
753 None => {
754 unsafe {
757 ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, ret);
758 }
759 panic!(
760 "Sending a request creating an object without providing an object data."
761 );
762 }
763 };
764
765 unsafe { self.manage_object_internal(child_interface, ret, data, &mut guard) }
766 } else {
767 Self::null_id()
768 };
769
770 if message_desc.is_destructor {
771 self.destroy_object_inner(guard, &ObjectId { id })
772 }
773
774 Ok(child_id)
775 }
776
777 pub fn get_data(&self, ObjectId { id }: ObjectId) -> Result<Arc<dyn ObjectData>, InvalidId> {
778 let mut _guard = self.lock_state();
779
780 if !id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(false) {
781 return Err(InvalidId);
782 }
783
784 if id.id == 1 {
785 return Ok(Arc::new(DumbObjectData));
787 }
788
789 let udata =
790 unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_get_user_data, id.ptr) };
791 if udata.is_null() {
792 panic!("NULL user data on object {id:?}");
793 }
794 Ok(unsafe { &*(udata as *mut ProxyUserData) }.data.clone())
795 }
796
797 pub fn set_data(
798 &self,
799 ObjectId { id }: ObjectId,
800 data: Arc<dyn ObjectData>,
801 ) -> Result<(), InvalidId> {
802 let mut _guard = self.lock_state();
803
804 if !id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(false) {
805 return Err(InvalidId);
806 }
807
808 if id.id == 1 {
810 return Err(InvalidId);
811 }
812
813 let mut _guard = self.lock_state();
814 let udata =
815 unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_get_user_data, id.ptr) };
816 if udata.is_null() {
817 panic!("NULL user data on object {id:?}");
818 }
819 let udata = unsafe { &mut *(udata as *mut ProxyUserData) };
820
821 udata.data = data;
822
823 Ok(())
824 }
825
826 pub unsafe fn manage_object(
833 &self,
834 interface: &'static Interface,
835 proxy: *mut wl_proxy,
836 data: Arc<dyn ObjectData>,
837 ) -> ObjectId {
838 let mut guard = self.lock_state();
839 unsafe {
840 ffi_dispatch!(wayland_client_handle(), wl_proxy_set_queue, proxy, guard.evq);
841 self.manage_object_internal(interface, proxy, data, &mut guard)
842 }
843 }
844
845 unsafe fn manage_object_internal(
849 &self,
850 interface: &'static Interface,
851 proxy: *mut wl_proxy,
852 data: Arc<dyn ObjectData>,
853 guard: &mut MutexGuard<ConnectionState>,
854 ) -> ObjectId {
855 let alive = Arc::new(AtomicBool::new(true));
856 let object_id = ObjectId {
857 id: InnerObjectId {
858 ptr: proxy,
859 alive: Some(alive.clone()),
860 id: unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, proxy) },
861 interface,
862 },
863 };
864
865 guard.known_proxies.insert(proxy);
866
867 let udata = Box::new(ProxyUserData { alive, data, interface });
868 unsafe {
869 ffi_dispatch!(
870 wayland_client_handle(),
871 wl_proxy_add_dispatcher,
872 proxy,
873 dispatcher_func,
874 &RUST_MANAGED as *const u8 as *const c_void,
875 Box::into_raw(udata) as *mut c_void
876 );
877 }
878
879 object_id
880 }
881}
882
883unsafe extern "C" fn dispatcher_func(
884 _: *const c_void,
885 proxy: *mut c_void,
886 opcode: u32,
887 _: *const wl_message,
888 args: *const wl_argument,
889) -> c_int {
890 let proxy = proxy as *mut wl_proxy;
891
892 let Some(udata) = BACKEND.with(|backend| {
893 let _guard = backend.backend.lock_state();
897 let udata = ffi_dispatch!(wayland_client_handle(), wl_proxy_get_user_data, proxy);
898 if udata.is_null() {
899 return None;
900 }
901 Some(unsafe { &*(udata as *mut ProxyUserData) }.clone())
902 }) else {
903 return 0;
905 };
906
907 let message_desc = match udata.interface.events.get(opcode as usize) {
908 Some(desc) => desc,
909 None => {
910 crate::log_error!(
911 "Unknown event opcode {} for interface {}.",
912 opcode,
913 udata.interface.name
914 );
915 return -1;
916 }
917 };
918
919 let mut parsed_args =
920 SmallVec::<[Argument<ObjectId, OwnedFd>; 4]>::with_capacity(message_desc.signature.len());
921 let mut arg_interfaces = message_desc.arg_interfaces.iter().copied();
922 let mut created = None;
923 for (i, typ) in message_desc.signature.iter().enumerate() {
925 match typ {
926 ArgumentType::Uint => parsed_args.push(Argument::Uint(unsafe { (*args.add(i)).u })),
927 ArgumentType::Int => parsed_args.push(Argument::Int(unsafe { (*args.add(i)).i })),
928 ArgumentType::Fixed => parsed_args.push(Argument::Fixed(unsafe { (*args.add(i)).f })),
929 ArgumentType::Fd => {
930 parsed_args.push(Argument::Fd(unsafe { OwnedFd::from_raw_fd((*args.add(i)).h) }))
931 }
932 ArgumentType::Array => {
933 let array = unsafe { &*((*args.add(i)).a) };
934 let content =
936 unsafe { std::slice::from_raw_parts(array.data as *mut u8, array.size) };
937 parsed_args.push(Argument::Array(Box::new(content.into())));
938 }
939 ArgumentType::Str(_) => {
940 let ptr = unsafe { (*args.add(i)).s };
941 if !ptr.is_null() {
943 let cstr = unsafe { std::ffi::CStr::from_ptr(ptr) };
944 parsed_args.push(Argument::Str(Some(Box::new(cstr.into()))));
945 } else {
946 parsed_args.push(Argument::Str(None));
947 }
948 }
949 ArgumentType::Object(_) => {
950 let obj = unsafe { (*args.add(i)).o as *mut wl_proxy };
951 if !obj.is_null() {
952 let obj_id = ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, obj);
954 let next_interface = arg_interfaces.next().unwrap_or(&ANONYMOUS_INTERFACE);
956 let listener =
957 ffi_dispatch!(wayland_client_handle(), wl_proxy_get_listener, obj);
958 if ptr::eq(listener, &RUST_MANAGED as *const u8 as *const c_void) {
959 let Some(obj_udata) = BACKEND.with(|backend| {
960 let _guard = backend.backend.lock_state();
961 let udata = unsafe {
965 ffi_dispatch!(wayland_client_handle(), wl_proxy_get_user_data, obj)
966 };
967 if !udata.is_null() {
968 Some(unsafe { &mut *(udata as *mut ProxyUserData) }.clone())
969 } else {
970 None
971 }
972 }) else {
973 parsed_args.push(Argument::Object(ObjectId {
977 id: InnerObjectId {
978 alive: None,
979 id: 0,
980 ptr: std::ptr::null_mut(),
981 interface: &ANONYMOUS_INTERFACE,
982 },
983 }));
984 continue;
985 };
986 if !same_interface(next_interface, obj_udata.interface) {
987 crate::log_error!(
988 "Received object {}@{} in {}.{} but expected interface {}.",
989 obj_udata.interface.name,
990 obj_id,
991 udata.interface.name,
992 message_desc.name,
993 next_interface.name,
994 );
995 return -1;
996 }
997 parsed_args.push(Argument::Object(ObjectId {
998 id: InnerObjectId {
999 alive: Some(obj_udata.alive.clone()),
1000 ptr: obj,
1001 id: obj_id,
1002 interface: obj_udata.interface,
1003 },
1004 }));
1005 } else {
1006 parsed_args.push(Argument::Object(ObjectId {
1007 id: InnerObjectId {
1008 alive: None,
1009 id: obj_id,
1010 ptr: obj,
1011 interface: next_interface,
1012 },
1013 }));
1014 }
1015 } else {
1016 parsed_args.push(Argument::Object(ObjectId {
1018 id: InnerObjectId {
1019 alive: None,
1020 id: 0,
1021 ptr: std::ptr::null_mut(),
1022 interface: &ANONYMOUS_INTERFACE,
1023 },
1024 }))
1025 }
1026 }
1027 ArgumentType::NewId => {
1028 let obj = unsafe { (*args.add(i)).o as *mut wl_proxy };
1029 if !obj.is_null() {
1031 let child_interface = message_desc.child_interface.unwrap_or_else(|| {
1032 crate::log_warn!(
1033 "Event {}.{} creates an anonymous object.",
1034 udata.interface.name,
1035 opcode
1036 );
1037 &ANONYMOUS_INTERFACE
1038 });
1039 let child_alive = Arc::new(AtomicBool::new(true));
1040 let child_id = InnerObjectId {
1041 ptr: obj,
1042 alive: Some(child_alive.clone()),
1043 id: ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, obj),
1044 interface: child_interface,
1045 };
1046 let child_udata = Box::into_raw(Box::new(ProxyUserData {
1047 alive: child_alive,
1048 data: Arc::new(UninitObjectData),
1049 interface: child_interface,
1050 }));
1051 created = Some((child_id.clone(), child_udata));
1052 ffi_dispatch!(
1053 wayland_client_handle(),
1054 wl_proxy_add_dispatcher,
1055 obj,
1056 dispatcher_func,
1057 &RUST_MANAGED as *const u8 as *const c_void,
1058 child_udata as *mut c_void
1059 );
1060 parsed_args.push(Argument::NewId(ObjectId { id: child_id }));
1061 } else {
1062 parsed_args.push(Argument::NewId(ObjectId {
1063 id: InnerObjectId {
1064 id: 0,
1065 ptr: std::ptr::null_mut(),
1066 alive: None,
1067 interface: &ANONYMOUS_INTERFACE,
1068 },
1069 }))
1070 }
1071 }
1072 }
1073 }
1074
1075 let proxy_id = ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, proxy);
1076 let id = ObjectId {
1077 id: InnerObjectId {
1078 alive: Some(udata.alive.clone()),
1079 ptr: proxy,
1080 id: proxy_id,
1081 interface: udata.interface,
1082 },
1083 };
1084
1085 let ret = BACKEND.with(|backend| {
1086 let mut guard = backend.backend.lock_state();
1087 if let Some((ref new_id, _)) = created {
1088 guard.known_proxies.insert(new_id.ptr);
1089 }
1090 std::mem::drop(guard);
1091 let ret = udata.data.clone().event(
1092 backend,
1093 Message { sender_id: id.clone(), opcode: opcode as u16, args: parsed_args },
1094 );
1095 if message_desc.is_destructor {
1096 backend.backend.destroy_object_inner(backend.backend.lock_state(), &id);
1097 }
1098 ret
1099 });
1100
1101 match (created, ret) {
1102 (Some((_, child_udata_ptr)), Some(child_data)) => {
1103 unsafe {
1105 (*child_udata_ptr).data = child_data;
1106 }
1107 }
1108 (Some((child_id, _)), None) => {
1109 panic!("Callback creating object {child_id} did not provide any object data.");
1110 }
1111 (None, Some(_)) => {
1112 panic!("An object data was returned from a callback not creating any object");
1113 }
1114 (None, None) => {}
1115 }
1116
1117 0
1118}
1119
1120#[cfg(feature = "log")]
1121extern "C" {
1122 fn wl_log_trampoline_to_rust_client(fmt: *const std::os::raw::c_char, list: *const c_void);
1123}
1124
1125impl Drop for ConnectionState {
1126 fn drop(&mut self) {
1127 for proxy_ptr in self.known_proxies.drain() {
1130 let _ = unsafe {
1135 Box::from_raw(ffi_dispatch!(
1136 wayland_client_handle(),
1137 wl_proxy_get_user_data,
1138 proxy_ptr
1139 ) as *mut ProxyUserData)
1140 };
1141 unsafe {
1142 ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, proxy_ptr);
1143 }
1144 }
1145 unsafe { ffi_dispatch!(wayland_client_handle(), wl_event_queue_destroy, self.evq) }
1146 if self.owns_display {
1147 unsafe { ffi_dispatch!(wayland_client_handle(), wl_display_disconnect, self.display) }
1149 }
1150 }
1151}