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