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,
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            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        // set the log trampoline
246        #[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        // check if it was actually a protocol error
327        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        // We erase the lifetime of the Handle to be able to store it in the tls,
380        // it's safe as it'll only last until the end of this function call anyway
381        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        // The read occured, dispatch pending events.
435        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            // we have done the reading, and there is an error
444            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            // special case the display, because libwayland returns a version of 0 for it
483            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        // check that the argument list is valid
547        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        // Prepare the child object data
576        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        // check that all input objects are valid and create the [wl_argument]
629        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            // We are a guest Backend, need to use a wrapper
685            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        // initialize the proxy
712        let child_id = if let Some((child_interface, _)) = child_spec {
713            let data = match data {
714                Some(data) => data,
715                None => {
716                    // we destroy this proxy before panicking to avoid a leak, as it cannot be destroyed by the
717                    // main destructor given it does not yet have a proper user-data
718                    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            // special case the display whose object data is not accessible
746            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        // Cannot touch the user_data of the display
766        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    /// Start managing a Wayland object.
781    ///
782    /// Safety: This will change the event queue the proxy is associated with.
783    /// Changing the event queue of an existing proxy is not thread-safe.
784    /// If another thread is concurrently reading the wayland socket and the
785    /// proxy already received an event it might get enqueued on the old event queue.
786    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    /// Start managing a Wayland object.
800    ///
801    /// Opposed to [`Self::manage_object`], this does not acquire any guards.
802    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    // Safety: if our dispatcher fun is called, then the associated proxy must be rust_managed and have a valid user_data
847    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    // Safety (args deference): the args array provided by libwayland is well-formed
866    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                // Safety: the array provided by libwayland must be valid
877                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                // Safety: the c-string provided by libwayland must be valid
884                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                    // retrieve the object relevant info
895                    let obj_id = ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, obj);
896                    // check if this is a local or distant proxy
897                    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                        // Safety: the object is rust-managed, its user-data must be valid
902                        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                    // libwayland-client.so checks nulls for us
937                    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                // this is a newid, it needs to be initialized
950                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        // Safety: the udata_ptr must be valid as we are in a rust-managed object, and we are done with using udata
1022        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            // Safety: child_udata_ptr is valid, we created it earlier
1032            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        // Cleanup the objects we know about, libwayland will discard any future message
1056        // they receive.
1057        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            // we own the connection, close it
1072            unsafe { ffi_dispatch!(wayland_client_handle(), wl_display_disconnect, self.display) }
1073        }
1074    }
1075}