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    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    // scoped_tls does not allow unsafe_op_in_unsafe_fn internally
37    #[allow(unsafe_op_in_unsafe_fn)]
38    static BACKEND: Backend
39}
40
41/// An ID representing a Wayland object
42#[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                // this is an object we manage
58                Arc::ptr_eq(a, b)
59            }
60            (None, None) => {
61                // this is an external (un-managed) object
62                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        // Safety: the provided pointer must be a valid wayland object
103        let ptr_iface_name = unsafe {
104            CStr::from_ptr(ffi_dispatch!(wayland_client_handle(), wl_proxy_get_class, ptr))
105        };
106        // Safety: the code generated by wayland-scanner is valid
107        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        // Test if the proxy is managed by us.
122        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            // Safety: the object is rust_managed, so its user-data pointer must be valid
127            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        // set the log trampoline
243        #[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        // check if it was actually a protocol error
324        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        // We erase the lifetime of the Handle to be able to store it in the tls,
377        // it's safe as it'll only last until the end of this function call anyway
378        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            // we have done the reading, and there is an error
435            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            // the read occured, dispatch pending events
443            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            // special case the display, because libwayland returns a version of 0 for it
475            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        // check that the argument list is valid
502        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        // Prepare the child object data
531        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        // check that all input objects are valid and create the [wl_argument]
584        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            // We are a guest Backend, need to use a wrapper
640            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        // initialize the proxy
667        let child_id = if let Some((child_interface, _)) = child_spec {
668            let data = match data {
669                Some(data) => data,
670                None => {
671                    // we destroy this proxy before panicking to avoid a leak, as it cannot be destroyed by the
672                    // main destructor given it does not yet have a proper user-data
673                    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            // special case the display whose object data is not accessible
725            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        // Cannot touch the user_data of the display
745        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    /// Start managing a Wayland object.
760    ///
761    /// Safety: This will change the event queue the proxy is associated with.
762    /// Changing the event queue of an existing proxy is not thread-safe.
763    /// If another thread is concurrently reading the wayland socket and the
764    /// proxy already received an event it might get enqueued on the old event queue.
765    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    /// Start managing a Wayland object.
779    ///
780    /// Opposed to [`Self::manage_object`], this does not acquire any guards.
781    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    // Safety: if our dispatcher fun is called, then the associated proxy must be rust_managed and have a valid user_data
826    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    // Safety (args deference): the args array provided by libwayland is well-formed
845    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                // Safety: the array provided by libwayland must be valid
856                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                // Safety: the c-string provided by libwayland must be valid
863                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                    // retrieve the object relevant info
874                    let obj_id = ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, obj);
875                    // check if this is a local or distant proxy
876                    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                        // Safety: the object is rust-managed, its user-data must be valid
881                        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                    // libwayland-client.so checks nulls for us
916                    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                // this is a newid, it needs to be initialized
929                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        // Safety: the udata_ptr must be valid as we are in a rust-managed object, and we are done with using udata
1001        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            // Safety: child_udata_ptr is valid, we created it earlier
1011            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        // Cleanup the objects we know about, libwayland will discard any future message
1035        // they receive.
1036        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            // we own the connection, close it
1051            unsafe { ffi_dispatch!(wayland_client_handle(), wl_display_disconnect, self.display) }
1052        }
1053    }
1054}