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