Skip to main content

wayland_backend/sys/client_impl/
mod.rs

1//! Client-side implementation of a Wayland protocol backend using `libwayland`
2
3use 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    // scoped_tls does not allow unsafe_op_in_unsafe_fn internally
38    #[allow(unsafe_op_in_unsafe_fn)]
39    static BACKEND: Backend
40}
41
42/// An ID representing a Wayland object
43#[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                // this is an object we manage
59                Arc::ptr_eq(a, b)
60            }
61            (None, None) => {
62                // this is an external (un-managed) object
63                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        // Safety: the provided pointer must be a valid wayland object
104        let ptr_iface_name = unsafe {
105            CStr::from_ptr(ffi_dispatch!(wayland_client_handle(), wl_proxy_get_class, ptr))
106        };
107        // Safety: the code generated by wayland-scanner is valid
108        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        // Test if the proxy is managed by us.
123        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            // SAFETY: the object is rust_managed, so its user-data pointer must be valid
130            // The udata won't be concurrently destroyed because the caller of this function
131            // guarantees the `*mut wl_proxy` is valid until it returns.
132            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        // set the log trampoline
260        #[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        // check if it was actually a protocol error
354        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        // We erase the lifetime of the Handle to be able to store it in the tls,
407        // it's safe as it'll only last until the end of this function call anyway
408        let ret = BACKEND.set(&backend, || unsafe {
409            // SAFETY: The `display` pointer will remain valid until `ConnectionState` is dropped, which
410            // we hold a strong reference to.
411            // Proxy pointers a ref-counted internally in libwayland, so a proxy destroy in another
412            // thread won't free a proxy that is being dispatched here until it is done.
413            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        // The read occured, dispatch pending events.
469        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            // we have done the reading, and there is an error
478            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            // special case the display, because libwayland returns a version of 0 for it
517            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            // SAFTETY: the udata_ptr must be valid as we are in a rust-managed object, and we are done with using udata
539            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        // check that the argument list is valid
589        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        // Prepare the child object data
617        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        // check that all input objects are valid and create the [wl_argument]
670        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            // We are a guest Backend, need to use a wrapper
726            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        // initialize the proxy
753        let child_id = if let Some((child_interface, _)) = child_spec {
754            let data = match data {
755                Some(data) => data,
756                None => {
757                    // we destroy this proxy before panicking to avoid a leak, as it cannot be destroyed by the
758                    // main destructor given it does not yet have a proper user-data
759                    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            // special case the display whose object data is not accessible
789            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        // Cannot touch the user_data of the display
812        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    /// Start managing a Wayland object.
830    ///
831    /// Safety: This will change the event queue the proxy is associated with.
832    /// Changing the event queue of an existing proxy is not thread-safe.
833    /// If another thread is concurrently reading the wayland socket and the
834    /// proxy already received an event it might get enqueued on the old event queue.
835    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    /// Start managing a Wayland object.
849    ///
850    /// Opposed to [`Self::manage_object`], this does not acquire any guards.
851    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        // SAFETY: if our dispatcher func is called, then the associated proxy must be rust_managed and have a valid user_data
897        // If another thread calls `wl_proxy_destroy()`, the proxy will still be valid due to ref
898        // counting in libwayland. But we may get a `NULL` user data.
899        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        // Another thread has destroyed the proxy, so drop the event.
907        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    // Safety (args deference): the args array provided by libwayland is well-formed
927    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                // Safety: the array provided by libwayland must be valid
938                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                // Safety: the c-string provided by libwayland must be valid
945                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                    // retrieve the object relevant info
956                    let obj_id = ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, obj);
957                    // check if this is a local or distant proxy
958                    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                            // SAFETY: the object is rust-managed, its user-data must be valid
965                            // If another thread calls `wl_proxy_destroy()`, the proxy will still be valid due to ref
966                            // counting in libwayland. But we may get a `NULL` user data.
967                            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                            // If arg has object been destroyed in another thread, treat the same
977                            // way as a argument received as `NULL` from libwayland.
978                            // TODO Add a test for this
979                            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                    // libwayland-client.so checks nulls for us
1020                    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                // this is a newid, it needs to be initialized
1033                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            // Safety: child_udata_ptr is valid, we created it earlier
1107            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        // Cleanup the objects we know about, libwayland will discard any future message
1131        // they receive.
1132        for proxy_ptr in self.known_proxies.drain() {
1133            // SAFETY: `InnerBackend::get_data()` cannot be called after this point since we
1134            // are dropping the backend.
1135            // If the proxy is in `known_proxies`, it is managed by us and has not yet been
1136            // destroyed.
1137            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            // we own the connection, close it
1151            unsafe { ffi_dispatch!(wayland_client_handle(), wl_display_disconnect, self.display) }
1152        }
1153    }
1154}