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