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
436unsafe impl Send for InnerReadEventsGuard {}
437unsafe impl Sync for InnerReadEventsGuard {}
438
439impl InnerReadEventsGuard {
440 pub fn try_new(backend: InnerBackend) -> Option<Self> {
441 let (display, evq) = {
442 let guard = backend.lock_state();
443 (guard.display, guard.evq)
444 };
445
446 let ret = unsafe {
447 ffi_dispatch!(wayland_client_handle(), wl_display_prepare_read_queue, display, evq)
448 };
449 if ret < 0 {
450 None
451 } else {
452 Some(Self { inner: backend.inner, display, done: false })
453 }
454 }
455
456 pub fn connection_fd(&self) -> BorrowedFd<'_> {
457 unsafe {
458 BorrowedFd::borrow_raw(ffi_dispatch!(
459 wayland_client_handle(),
460 wl_display_get_fd,
461 self.display
462 ))
463 }
464 }
465
466 pub fn read(mut self) -> Result<usize, WaylandError> {
467 self.read_non_dispatch()?;
468 self.inner.dispatch_lock.lock().unwrap().dispatch_pending(self.inner.clone())
470 }
471
472 pub fn read_non_dispatch(&mut self) -> Result<(), WaylandError> {
473 self.done = true;
474 let ret =
475 unsafe { ffi_dispatch!(wayland_client_handle(), wl_display_read_events, self.display) };
476 if ret < 0 {
477 Err(self
479 .inner
480 .state
481 .lock()
482 .unwrap()
483 .store_if_not_wouldblock_and_return_error(std::io::Error::last_os_error()))
484 } else {
485 Ok(())
486 }
487 }
488}
489
490impl Drop for InnerReadEventsGuard {
491 fn drop(&mut self) {
492 if !self.done {
493 unsafe {
494 ffi_dispatch!(wayland_client_handle(), wl_display_cancel_read, self.display);
495 }
496 }
497 }
498}
499
500impl InnerBackend {
501 pub fn display_id(&self) -> ObjectId {
502 ObjectId { id: self.lock_state().display_id.clone() }
503 }
504
505 pub fn last_error(&self) -> Option<WaylandError> {
506 self.lock_state().last_error.clone()
507 }
508
509 pub fn info(&self, ObjectId { id }: ObjectId) -> Result<ObjectInfo, InvalidId> {
510 if !id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(true) || id.ptr.is_null()
511 {
512 return Err(InvalidId);
513 }
514
515 let version = if id.id == 1 {
516 1
518 } else {
519 unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_get_version, id.ptr) }
520 };
521
522 Ok(ObjectInfo { id: id.id, interface: id.interface, version })
523 }
524
525 pub fn null_id() -> ObjectId {
526 ObjectId {
527 id: InnerObjectId {
528 ptr: std::ptr::null_mut(),
529 interface: &ANONYMOUS_INTERFACE,
530 id: 0,
531 alive: None,
532 },
533 }
534 }
535
536 fn destroy_object_inner(&self, mut guard: MutexGuard<ConnectionState>, id: &ObjectId) {
537 if let Some(ref alive) = id.id.alive {
538 let udata = unsafe {
540 ffi_dispatch!(wayland_client_handle(), wl_proxy_get_user_data, id.id.ptr)
541 };
542 if udata.is_null() {
543 panic!("NULL user data on object {id:?}");
544 }
545 unsafe {
546 ffi_dispatch!(
547 wayland_client_handle(),
548 wl_proxy_set_user_data,
549 id.id.ptr,
550 std::ptr::null_mut()
551 );
552 }
553 let udata = unsafe { Box::from_raw(udata as *mut ProxyUserData) };
554 alive.store(false, Ordering::Release);
555 guard.known_proxies.remove(&id.id.ptr);
556 drop(guard);
557 udata.data.destroyed(id.clone());
558 }
559
560 unsafe {
561 ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, id.id.ptr);
562 }
563 }
564
565 pub fn destroy_object(&self, id: &ObjectId) -> Result<(), InvalidId> {
566 let guard = self.lock_state();
567
568 if !id.id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(false) {
569 return Err(InvalidId);
570 }
571
572 self.destroy_object_inner(guard, id);
573 Ok(())
574 }
575
576 pub fn send_request(
577 &self,
578 Message { sender_id: ObjectId { id }, opcode, args }: Message<ObjectId, RawFd>,
579 data: Option<Arc<dyn ObjectData>>,
580 child_spec: Option<(&'static Interface, u32)>,
581 ) -> Result<ObjectId, InvalidId> {
582 let mut guard = self.lock_state();
583
584 if id.is_null() {
585 return Err(InvalidId);
586 }
587
588 let message_desc = match id.interface.requests.get(opcode as usize) {
590 Some(msg) => msg,
591 None => {
592 panic!("Unknown opcode {} for object {}@{}.", opcode, id.interface.name, id.id);
593 }
594 };
595
596 if !id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(true) {
597 if self.inner.debug {
598 debug::print_send_message(id.interface.name, id.id, message_desc.name, &args, true);
599 }
600 return Err(InvalidId);
601 }
602
603 let parent_version = if id.id == 1 {
604 1
605 } else {
606 unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_get_version, id.ptr) }
607 };
608
609 if !check_for_signature(message_desc.signature, &args) {
610 panic!(
611 "Unexpected signature for request {}@{}.{}: expected {:?}, got {:?}.",
612 id.interface.name, id.id, message_desc.name, message_desc.signature, args
613 );
614 }
615
616 let child_spec = if message_desc
618 .signature
619 .iter()
620 .any(|arg| matches!(arg, ArgumentType::NewId))
621 {
622 if let Some((iface, version)) = child_spec {
623 if let Some(child_interface) = message_desc.child_interface {
624 if !same_interface(child_interface, iface) {
625 panic!(
626 "Wrong placeholder used when sending request {}@{}.{}: expected interface {} but got {}",
627 id.interface.name,
628 id.id,
629 message_desc.name,
630 child_interface.name,
631 iface.name
632 );
633 }
634 if version != parent_version {
635 panic!(
636 "Wrong placeholder used when sending request {}@{}.{}: expected version {} but got {}",
637 id.interface.name,
638 id.id,
639 message_desc.name,
640 parent_version,
641 version
642 );
643 }
644 }
645 Some((iface, version))
646 } else if let Some(child_interface) = message_desc.child_interface {
647 Some((child_interface, parent_version))
648 } else {
649 panic!(
650 "Wrong placeholder used when sending request {}@{}.{}: target interface must be specified for a generic constructor.",
651 id.interface.name,
652 id.id,
653 message_desc.name
654 );
655 }
656 } else {
657 None
658 };
659
660 let child_interface_ptr = child_spec
661 .as_ref()
662 .map(|(i, _)| {
663 i.c_ptr.expect("[wayland-backend-sys] Cannot use Interface without c_ptr!")
664 as *const _
665 })
666 .unwrap_or(std::ptr::null());
667 let child_version = child_spec.as_ref().map(|(_, v)| *v).unwrap_or(parent_version);
668
669 let mut argument_list = SmallVec::<[wl_argument; 4]>::with_capacity(args.len());
671 let mut arg_interfaces = message_desc.arg_interfaces.iter();
672 for (i, arg) in args.iter().enumerate() {
673 match *arg {
674 Argument::Uint(u) => argument_list.push(wl_argument { u }),
675 Argument::Int(i) => argument_list.push(wl_argument { i }),
676 Argument::Fixed(f) => argument_list.push(wl_argument { f }),
677 Argument::Fd(h) => argument_list.push(wl_argument { h }),
678 Argument::Array(ref a) => {
679 let a = Box::new(wl_array {
680 size: a.len(),
681 alloc: a.len(),
682 data: a.as_ptr() as *mut _,
683 });
684 argument_list.push(wl_argument { a: Box::into_raw(a) })
685 }
686 Argument::Str(Some(ref s)) => argument_list.push(wl_argument { s: s.as_ptr() }),
687 Argument::Str(None) => argument_list.push(wl_argument { s: std::ptr::null() }),
688 Argument::Object(ref o) => {
689 let next_interface = arg_interfaces.next().unwrap();
690 if !o.id.ptr.is_null() {
691 if !o.id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(true) {
692 unsafe { free_arrays(message_desc.signature, &argument_list) };
693 return Err(InvalidId);
694 }
695 if !same_interface(next_interface, o.id.interface) {
696 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);
697 }
698 } else if !matches!(
699 message_desc.signature[i],
700 ArgumentType::Object(AllowNull::Yes)
701 ) {
702 panic!(
703 "Request {}@{}.{} expects an non-null object argument.",
704 id.interface.name, id.id, message_desc.name
705 );
706 }
707 argument_list.push(wl_argument { o: o.id.ptr as *const _ })
708 }
709 Argument::NewId(_) => argument_list.push(wl_argument { n: 0 }),
710 }
711 }
712
713 let ret = if child_spec.is_none() {
714 unsafe {
715 ffi_dispatch!(
716 wayland_client_handle(),
717 wl_proxy_marshal_array,
718 id.ptr,
719 opcode as u32,
720 argument_list.as_mut_ptr(),
721 )
722 }
723 std::ptr::null_mut()
724 } else {
725 unsafe {
727 let wrapped_ptr =
728 ffi_dispatch!(wayland_client_handle(), wl_proxy_create_wrapper, id.ptr);
729 ffi_dispatch!(wayland_client_handle(), wl_proxy_set_queue, wrapped_ptr, guard.evq);
730 let ret = ffi_dispatch!(
731 wayland_client_handle(),
732 wl_proxy_marshal_array_constructor_versioned,
733 wrapped_ptr,
734 opcode as u32,
735 argument_list.as_mut_ptr(),
736 child_interface_ptr,
737 child_version
738 );
739 ffi_dispatch!(wayland_client_handle(), wl_proxy_wrapper_destroy, wrapped_ptr);
740 ret
741 }
742 };
743
744 unsafe {
745 free_arrays(message_desc.signature, &argument_list);
746 }
747
748 if ret.is_null() && child_spec.is_some() {
749 panic!("[wayland-backend-sys] libwayland reported an allocation failure.");
750 }
751
752 let child_id = if let Some((child_interface, _)) = child_spec {
754 let data = match data {
755 Some(data) => data,
756 None => {
757 unsafe {
760 ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, ret);
761 }
762 panic!(
763 "Sending a request creating an object without providing an object data."
764 );
765 }
766 };
767
768 unsafe { self.manage_object_internal(child_interface, ret, data, &mut guard) }
769 } else {
770 Self::null_id()
771 };
772
773 if message_desc.is_destructor {
774 self.destroy_object_inner(guard, &ObjectId { id })
775 }
776
777 Ok(child_id)
778 }
779
780 pub fn get_data(&self, ObjectId { id }: ObjectId) -> Result<Arc<dyn ObjectData>, InvalidId> {
781 let mut _guard = self.lock_state();
782
783 if !id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(false) {
784 return Err(InvalidId);
785 }
786
787 if id.id == 1 {
788 return Ok(Arc::new(DumbObjectData));
790 }
791
792 let udata =
793 unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_get_user_data, id.ptr) };
794 if udata.is_null() {
795 panic!("NULL user data on object {id:?}");
796 }
797 Ok(unsafe { &*(udata as *mut ProxyUserData) }.data.clone())
798 }
799
800 pub fn set_data(
801 &self,
802 ObjectId { id }: ObjectId,
803 data: Arc<dyn ObjectData>,
804 ) -> Result<(), InvalidId> {
805 let mut _guard = self.lock_state();
806
807 if !id.alive.as_ref().map(|a| a.load(Ordering::Acquire)).unwrap_or(false) {
808 return Err(InvalidId);
809 }
810
811 if id.id == 1 {
813 return Err(InvalidId);
814 }
815
816 let mut _guard = self.lock_state();
817 let udata =
818 unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_get_user_data, id.ptr) };
819 if udata.is_null() {
820 panic!("NULL user data on object {id:?}");
821 }
822 let udata = unsafe { &mut *(udata as *mut ProxyUserData) };
823
824 udata.data = data;
825
826 Ok(())
827 }
828
829 pub unsafe fn manage_object(
836 &self,
837 interface: &'static Interface,
838 proxy: *mut wl_proxy,
839 data: Arc<dyn ObjectData>,
840 ) -> ObjectId {
841 let mut guard = self.lock_state();
842 unsafe {
843 ffi_dispatch!(wayland_client_handle(), wl_proxy_set_queue, proxy, guard.evq);
844 self.manage_object_internal(interface, proxy, data, &mut guard)
845 }
846 }
847
848 unsafe fn manage_object_internal(
852 &self,
853 interface: &'static Interface,
854 proxy: *mut wl_proxy,
855 data: Arc<dyn ObjectData>,
856 guard: &mut MutexGuard<ConnectionState>,
857 ) -> ObjectId {
858 let alive = Arc::new(AtomicBool::new(true));
859 let object_id = ObjectId {
860 id: InnerObjectId {
861 ptr: proxy,
862 alive: Some(alive.clone()),
863 id: unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, proxy) },
864 interface,
865 },
866 };
867
868 guard.known_proxies.insert(proxy);
869
870 let udata = Box::new(ProxyUserData { alive, data, interface });
871 unsafe {
872 ffi_dispatch!(
873 wayland_client_handle(),
874 wl_proxy_add_dispatcher,
875 proxy,
876 dispatcher_func,
877 &RUST_MANAGED as *const u8 as *const c_void,
878 Box::into_raw(udata) as *mut c_void
879 );
880 }
881
882 object_id
883 }
884}
885
886unsafe extern "C" fn dispatcher_func(
887 _: *const c_void,
888 proxy: *mut c_void,
889 opcode: u32,
890 _: *const wl_message,
891 args: *const wl_argument,
892) -> c_int {
893 let proxy = proxy as *mut wl_proxy;
894
895 let Some(udata) = BACKEND.with(|backend| {
896 let _guard = backend.backend.lock_state();
900 let udata = ffi_dispatch!(wayland_client_handle(), wl_proxy_get_user_data, proxy);
901 if udata.is_null() {
902 return None;
903 }
904 Some(unsafe { &*(udata as *mut ProxyUserData) }.clone())
905 }) else {
906 return 0;
908 };
909
910 let message_desc = match udata.interface.events.get(opcode as usize) {
911 Some(desc) => desc,
912 None => {
913 crate::log_error!(
914 "Unknown event opcode {} for interface {}.",
915 opcode,
916 udata.interface.name
917 );
918 return -1;
919 }
920 };
921
922 let mut parsed_args =
923 SmallVec::<[Argument<ObjectId, OwnedFd>; 4]>::with_capacity(message_desc.signature.len());
924 let mut arg_interfaces = message_desc.arg_interfaces.iter().copied();
925 let mut created = None;
926 for (i, typ) in message_desc.signature.iter().enumerate() {
928 match typ {
929 ArgumentType::Uint => parsed_args.push(Argument::Uint(unsafe { (*args.add(i)).u })),
930 ArgumentType::Int => parsed_args.push(Argument::Int(unsafe { (*args.add(i)).i })),
931 ArgumentType::Fixed => parsed_args.push(Argument::Fixed(unsafe { (*args.add(i)).f })),
932 ArgumentType::Fd => {
933 parsed_args.push(Argument::Fd(unsafe { OwnedFd::from_raw_fd((*args.add(i)).h) }))
934 }
935 ArgumentType::Array => {
936 let array = unsafe { &*((*args.add(i)).a) };
937 let content =
939 unsafe { std::slice::from_raw_parts(array.data as *mut u8, array.size) };
940 parsed_args.push(Argument::Array(Box::new(content.into())));
941 }
942 ArgumentType::Str(_) => {
943 let ptr = unsafe { (*args.add(i)).s };
944 if !ptr.is_null() {
946 let cstr = unsafe { std::ffi::CStr::from_ptr(ptr) };
947 parsed_args.push(Argument::Str(Some(Box::new(cstr.into()))));
948 } else {
949 parsed_args.push(Argument::Str(None));
950 }
951 }
952 ArgumentType::Object(_) => {
953 let obj = unsafe { (*args.add(i)).o as *mut wl_proxy };
954 if !obj.is_null() {
955 let obj_id = ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, obj);
957 let next_interface = arg_interfaces.next().unwrap_or(&ANONYMOUS_INTERFACE);
959 let listener =
960 ffi_dispatch!(wayland_client_handle(), wl_proxy_get_listener, obj);
961 if ptr::eq(listener, &RUST_MANAGED as *const u8 as *const c_void) {
962 let Some(obj_udata) = BACKEND.with(|backend| {
963 let _guard = backend.backend.lock_state();
964 let udata = unsafe {
968 ffi_dispatch!(wayland_client_handle(), wl_proxy_get_user_data, obj)
969 };
970 if !udata.is_null() {
971 Some(unsafe { &mut *(udata as *mut ProxyUserData) }.clone())
972 } else {
973 None
974 }
975 }) else {
976 parsed_args.push(Argument::Object(ObjectId {
980 id: InnerObjectId {
981 alive: None,
982 id: 0,
983 ptr: std::ptr::null_mut(),
984 interface: &ANONYMOUS_INTERFACE,
985 },
986 }));
987 continue;
988 };
989 if !same_interface(next_interface, obj_udata.interface) {
990 crate::log_error!(
991 "Received object {}@{} in {}.{} but expected interface {}.",
992 obj_udata.interface.name,
993 obj_id,
994 udata.interface.name,
995 message_desc.name,
996 next_interface.name,
997 );
998 return -1;
999 }
1000 parsed_args.push(Argument::Object(ObjectId {
1001 id: InnerObjectId {
1002 alive: Some(obj_udata.alive.clone()),
1003 ptr: obj,
1004 id: obj_id,
1005 interface: obj_udata.interface,
1006 },
1007 }));
1008 } else {
1009 parsed_args.push(Argument::Object(ObjectId {
1010 id: InnerObjectId {
1011 alive: None,
1012 id: obj_id,
1013 ptr: obj,
1014 interface: next_interface,
1015 },
1016 }));
1017 }
1018 } else {
1019 parsed_args.push(Argument::Object(ObjectId {
1021 id: InnerObjectId {
1022 alive: None,
1023 id: 0,
1024 ptr: std::ptr::null_mut(),
1025 interface: &ANONYMOUS_INTERFACE,
1026 },
1027 }))
1028 }
1029 }
1030 ArgumentType::NewId => {
1031 let obj = unsafe { (*args.add(i)).o as *mut wl_proxy };
1032 if !obj.is_null() {
1034 let child_interface = message_desc.child_interface.unwrap_or_else(|| {
1035 crate::log_warn!(
1036 "Event {}.{} creates an anonymous object.",
1037 udata.interface.name,
1038 opcode
1039 );
1040 &ANONYMOUS_INTERFACE
1041 });
1042 let child_alive = Arc::new(AtomicBool::new(true));
1043 let child_id = InnerObjectId {
1044 ptr: obj,
1045 alive: Some(child_alive.clone()),
1046 id: ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, obj),
1047 interface: child_interface,
1048 };
1049 let child_udata = Box::into_raw(Box::new(ProxyUserData {
1050 alive: child_alive,
1051 data: Arc::new(UninitObjectData),
1052 interface: child_interface,
1053 }));
1054 created = Some((child_id.clone(), child_udata));
1055 ffi_dispatch!(
1056 wayland_client_handle(),
1057 wl_proxy_add_dispatcher,
1058 obj,
1059 dispatcher_func,
1060 &RUST_MANAGED as *const u8 as *const c_void,
1061 child_udata as *mut c_void
1062 );
1063 parsed_args.push(Argument::NewId(ObjectId { id: child_id }));
1064 } else {
1065 parsed_args.push(Argument::NewId(ObjectId {
1066 id: InnerObjectId {
1067 id: 0,
1068 ptr: std::ptr::null_mut(),
1069 alive: None,
1070 interface: &ANONYMOUS_INTERFACE,
1071 },
1072 }))
1073 }
1074 }
1075 }
1076 }
1077
1078 let proxy_id = ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, proxy);
1079 let id = ObjectId {
1080 id: InnerObjectId {
1081 alive: Some(udata.alive.clone()),
1082 ptr: proxy,
1083 id: proxy_id,
1084 interface: udata.interface,
1085 },
1086 };
1087
1088 let ret = BACKEND.with(|backend| {
1089 let mut guard = backend.backend.lock_state();
1090 if let Some((ref new_id, _)) = created {
1091 guard.known_proxies.insert(new_id.ptr);
1092 }
1093 std::mem::drop(guard);
1094 let ret = udata.data.clone().event(
1095 backend,
1096 Message { sender_id: id.clone(), opcode: opcode as u16, args: parsed_args },
1097 );
1098 if message_desc.is_destructor {
1099 backend.backend.destroy_object_inner(backend.backend.lock_state(), &id);
1100 }
1101 ret
1102 });
1103
1104 match (created, ret) {
1105 (Some((_, child_udata_ptr)), Some(child_data)) => {
1106 unsafe {
1108 (*child_udata_ptr).data = child_data;
1109 }
1110 }
1111 (Some((child_id, _)), None) => {
1112 panic!("Callback creating object {child_id} did not provide any object data.");
1113 }
1114 (None, Some(_)) => {
1115 panic!("An object data was returned from a callback not creating any object");
1116 }
1117 (None, None) => {}
1118 }
1119
1120 0
1121}
1122
1123#[cfg(feature = "log")]
1124extern "C" {
1125 fn wl_log_trampoline_to_rust_client(fmt: *const std::os::raw::c_char, list: *const c_void);
1126}
1127
1128impl Drop for ConnectionState {
1129 fn drop(&mut self) {
1130 for proxy_ptr in self.known_proxies.drain() {
1133 let _ = unsafe {
1138 Box::from_raw(ffi_dispatch!(
1139 wayland_client_handle(),
1140 wl_proxy_get_user_data,
1141 proxy_ptr
1142 ) as *mut ProxyUserData)
1143 };
1144 unsafe {
1145 ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, proxy_ptr);
1146 }
1147 }
1148 unsafe { ffi_dispatch!(wayland_client_handle(), wl_event_queue_destroy, self.evq) }
1149 if self.owns_display {
1150 unsafe { ffi_dispatch!(wayland_client_handle(), wl_display_disconnect, self.display) }
1152 }
1153 }
1154}