wl_client/proxy/low_level/owned/
scope.rs

1#[expect(unused_imports)]
2use crate::Connection;
3#[expect(unused_imports)]
4use crate::proxy;
5use {
6    crate::{
7        DispatchLock, Queue,
8        builder::prelude::{CreateEventHandler, EventHandler, UntypedBorrowedProxy},
9        ffi::{wl_argument, wl_interface, wl_message},
10        proxy::{
11            OwnedProxy, get_owned,
12            low_level::{
13                OwnedProxyRegistry, ProxyDataDestruction,
14                owned::{UntypedOwnedProxyData, box_event_handler, event_handler_func},
15            },
16        },
17        utils::{
18            on_drop::{abort_on_panic, on_drop},
19            sync_cell::{SyncCell, SyncUnsafeCell},
20        },
21    },
22    parking_lot::{Condvar, Mutex},
23    std::{
24        ffi::{c_int, c_void},
25        future::poll_fn,
26        marker::PhantomData,
27        mem,
28        pin::pin,
29        ptr::NonNull,
30        sync::{Arc, atomic::Ordering::Relaxed},
31    },
32};
33
34#[cfg(test)]
35mod tests;
36
37/// A scope for event handlers with shorter than `'static` lifetime.
38///
39/// Scopes are created by calling [`Queue::dispatch_scope_blocking`] and
40/// [`Queue::dispatch_scope_async`].
41///
42/// Event handlers attached via a scope have the following, additional restriction: they
43/// will be dropped and therefore not be invoked after the lifetime of the scope has
44/// ended. The proxies can still be used to send requests or as arguments, but no event
45/// callbacks will be invoked. Instead, the [`OwnedProxy::NO_OP_EVENT_HANDLER`] will be
46/// invoked to prevent any memory leaks.
47///
48/// Async scopes created via [`Queue::dispatch_scope_async`] have one more restriction:
49/// event handlers will only be invoked while the returned future is being polled. Until
50/// the future completes, the queue should therefore only be dispatched from inside the
51/// future.
52///
53/// # Example
54///
55/// ```
56/// # use std::cell::Cell;
57/// # use wl_client::Libwayland;
58/// # use wl_client::test_protocols::core::wl_callback::WlCallback;
59/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
60/// #
61/// let lib = Libwayland::open().unwrap();
62/// let con = lib.connect_to_default_display().unwrap();
63/// let queue = con.create_local_queue(c"queue name");
64///
65/// let sync = queue.display::<WlDisplay>().sync();
66/// let done = Cell::new(false);
67/// queue.dispatch_scope_blocking(|scope| {
68///     scope.set_event_handler_local(&sync, WlCallback::on_done(|_, _| done.set(true)));
69///     queue.dispatch_roundtrip_blocking().unwrap();
70/// });
71/// assert!(done.get());
72/// ```
73pub struct Scope<'scope, 'env: 'scope> {
74    /// Shared data of the scope. This data is kept alive even after the scope has ended
75    /// so that proxies can continue to refer to it and check the may_dispatch field.
76    pub(super) data: Arc<ScopeData>,
77    /// Ensure that 'scope and 'env are invariant. If 'scope were covariant, applications
78    /// could use this to attach an event handler with a lifetime shorter than the
79    /// original 'scope. Non-contravariance and non-any-variance of 'env is not required
80    /// but keeps things in line with [`std::thread::Scope`].
81    _inv_scope: PhantomData<&'scope mut &'scope mut ()>,
82    _inv_env: PhantomData<&'env mut &'env mut ()>,
83}
84
85pub(super) struct ScopeData {
86    /// The queue that this scope belongs to.
87    queue: Queue,
88    /// This field is protected by the queue lock. We define the following terms:
89    ///
90    /// - A system stack frame is any stack frame defined by the functions
91    ///
92    ///   - `dispatch_scope_blocking`
93    ///   - `dispatch_scope_async`
94    ///
95    ///   including any closures therein and the stack frame invoking the closures.
96    ///
97    /// - A user stack frame is any other stack frame.
98    ///
99    /// To simplify the invariants below, we coalesce all adjacent system stack frames.
100    /// That is, if we have system stack frames S1, S2, S3 where S1 calls S2 and S3, then
101    /// we treat S1, S2, and S3 as a single system stack frame. Here, S2 and S3 are the
102    /// closures defined in the functions above.
103    ///
104    /// This field has the following invariants:
105    ///
106    /// - It is only modified by system stack frames.
107    /// - If it is set to true by a system stack frame, then it is set back to false by
108    ///   the same stack frame.
109    /// - If it is set to true, then it is not modified again before being set to false as
110    ///   described in the previous bullet point.
111    ///
112    /// It follows that
113    ///
114    /// - For any user stack frame, the value of this field is constant during the
115    ///   execution of the frame. (A child stack frame might modify the value but it will
116    ///   be reset before returning.)
117    /// - If the value of the field is `false`, then it has always been false during the
118    ///   execution of any user parent stack frame.
119    may_dispatch: SyncCell<bool>,
120    /// This field is protected by the queue lock. This field has the following invariant:
121    /// It is false if and only if
122    ///
123    /// - none of the event handlers attached via the scope are currently being referenced
124    ///   by a dispatcher
125    /// - none of the event handlers attached via the scope will ever again be referenced
126    ///   by a dispatcher
127    /// - we're still within 'scope or all of the event handlers attached via the scope
128    ///   have already been dropped
129    defer_destruction: SyncCell<bool>,
130    /// This field is protected by the queue lock. This field contains the number of event
131    /// handlers attached through this scope that a) have a drop impl and b) have not yet
132    /// had their drop impl run. We use this to ensure the following invariant:
133    ///
134    /// - before the end of 'scope, all event handlers have been dropped or the remaining
135    ///   event handlers are leaked.
136    live_event_handlers: SyncCell<u64>,
137    /// This field is protected by the queue lock. If, after the scope has performed
138    /// cleanup in [`Scope::drop`], live_event_handlers is still not 0, then other
139    /// threads must currently be destroying the remaining event handlers. In this case we
140    /// set this field to true to let those destructors know that they must set
141    /// last_event_handler_destroyed to true once live_event_handlers reaches 0.
142    awaiting_last_destruction: SyncCell<bool>,
143    /// See the destruction of awaiting_last_destruction for how the following two fields
144    /// are used.
145    last_event_handler_destroyed: Mutex<bool>,
146    last_event_handler_condvar: Condvar,
147    /// The registry that registers all `Drop`-able proxies that had an event handler
148    /// attached via this scope.
149    pub(super) registry: OwnedProxyRegistry,
150    /// This field is protected by the queue lock. No long-lived references must be
151    /// created to the vector to avoid conflicting access.
152    ///
153    /// The contained destructions have the following property: It must be safe to run the
154    /// destruction once there are no ongoing dispatches of the event handler.
155    destructions: SyncUnsafeCell<Vec<ProxyDataDestruction>>,
156}
157
158impl Queue {
159    /// Creates a blocking scope for event handlers with shorter than `'static` lifetime.
160    ///
161    /// The scope can be used to attach event handlers to proxies. The following
162    /// restriction applies: Such event handlers will only be invoked while inside this
163    /// function. Once this function returns, the [`OwnedProxy::NO_OP_EVENT_HANDLER`] of
164    /// the proxy is invoked instead.
165    ///
166    /// # Panic
167    ///
168    /// Panics if this is a [local queue](Connection::create_local_queue) and the current
169    /// thread is not the thread that this queue was created in.
170    ///
171    /// # Example
172    ///
173    /// ```
174    /// # use std::cell::Cell;
175    /// # use wl_client::Libwayland;
176    /// # use wl_client::test_protocols::core::wl_callback::WlCallback;
177    /// # use wl_client::test_protocols::core::wl_display::WlDisplay;
178    /// #
179    /// let lib = Libwayland::open().unwrap();
180    /// let con = lib.connect_to_default_display().unwrap();
181    /// let queue = con.create_local_queue(c"queue name");
182    ///
183    /// let sync = queue.display::<WlDisplay>().sync();
184    /// let done = Cell::new(false);
185    /// queue.dispatch_scope_blocking(|scope| {
186    ///     scope.set_event_handler_local(&sync, WlCallback::on_done(|_, _| done.set(true)));
187    ///     queue.dispatch_roundtrip_blocking().unwrap();
188    /// });
189    /// assert!(done.get());
190    /// ```
191    pub fn dispatch_scope_blocking<'env, T, F>(&self, f: F) -> T
192    where
193        F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T,
194    {
195        let scope = Scope::new(self);
196        {
197            let _lock = self.lock_dispatch();
198            // SAFETY: - We're holding the queue lock.
199            //         - _cleanup will set may_dispatch to false, or abort, before
200            //           returning to the parent.
201            //         - No other code modifies may_dispatch before this function call
202            //           returns.
203            unsafe {
204                scope.data.may_dispatch.set(true);
205            }
206        }
207        let _cleanup = on_drop(|| {
208            let lock = abort_on_panic(|| self.lock_dispatch());
209            // SAFETY: - We're holding the queue lock.
210            unsafe {
211                scope.data.may_dispatch.set(false);
212            }
213            // SAFETY:  - This function runs when dispatch_scope_blocking returns,
214            //           therefore may_dispatch can never again become true.
215            unsafe {
216                scope.drop(Some(lock));
217            }
218        });
219        f(&scope)
220    }
221
222    /// Creates an async scope for event handlers with shorter than `'static` lifetime.
223    ///
224    /// The scope can be used to attach event handlers to proxies. The following
225    /// restriction applies: Such event handlers will only be invoked while the future is
226    /// being polled. If an event needs to be dispatched in any other situation, the
227    /// [`OwnedProxy::NO_OP_EVENT_HANDLER`] of the proxy is invoked instead.
228    ///
229    /// In particular, dispatching the queue from a outside this future while this future
230    /// exists is unlikely to have the desired effect.
231    ///
232    /// # Panic
233    ///
234    /// Panics if this is a [local queue](Connection::create_local_queue) and the thread
235    /// polling the future is not the thread that this queue was created in.
236    ///
237    /// # Example
238    ///
239    /// ```
240    /// # use std::cell::Cell;
241    /// # use wl_client::Libwayland;
242    /// # use wl_client::test_protocols::core::wl_callback::WlCallback;
243    /// # use wl_client::test_protocols::core::wl_display::WlDisplay;
244    /// #
245    /// # tokio_test::block_on(async {
246    /// let lib = Libwayland::open().unwrap();
247    /// let con = lib.connect_to_default_display().unwrap();
248    /// let queue = con.create_local_queue(c"queue name");
249    ///
250    /// let sync = queue.display::<WlDisplay>().sync();
251    /// let done = Cell::new(false);
252    /// queue.dispatch_scope_async(async |scope| {
253    ///     scope.set_event_handler_local(&sync, WlCallback::on_done(|_, _| done.set(true)));
254    ///     queue.dispatch_roundtrip_async().await.unwrap();
255    /// }).await;
256    /// assert!(done.get());
257    /// # });
258    /// ```
259    pub async fn dispatch_scope_async<'env, T, F>(&self, f: F) -> T
260    where
261        F: for<'scope> AsyncFnOnce(&'scope Scope<'scope, 'env>) -> T,
262    {
263        let scope = Scope::new(self);
264        let _cleanup = on_drop(|| {
265            // SAFETY: - This function runs when the future created by
266            //           dispatch_scope_async is dropped or completes, therefore
267            //           may_dispatch can never again become true.
268            unsafe {
269                scope.drop(None);
270            }
271        });
272        let mut fut = pin!(f(&scope));
273        poll_fn(|ctx| {
274            {
275                let _lock = self.lock_dispatch();
276                // SAFETY: - We're holding the queue lock.
277                //         - _cleanup will set may_dispatch to false, or abort, before the
278                //           poll function returns.
279                //         - The execution of this function implies `&mut` access to the
280                //           future. Therefore may_dispatch is not modified again until
281                //           this function returns.
282                unsafe {
283                    scope.data.may_dispatch.set(true);
284                }
285            }
286            let _cleanup = on_drop(|| {
287                let _lock = abort_on_panic(|| self.lock_dispatch());
288                // SAFETY: - We're holding the queue lock.
289                unsafe {
290                    scope.data.may_dispatch.set(false);
291                }
292                // SAFETY: - We're holding the queue lock.
293                //         - We just set may_dispatch to false.
294                unsafe {
295                    scope.run_destructions(true);
296                }
297            });
298            fut.as_mut().poll(ctx)
299        })
300        .await
301    }
302}
303
304impl<'scope> Scope<'scope, '_> {
305    fn new(queue: &Queue) -> Self {
306        Scope {
307            data: Arc::new(ScopeData {
308                queue: queue.clone(),
309                may_dispatch: SyncCell::new(false),
310                defer_destruction: SyncCell::new(true),
311                live_event_handlers: SyncCell::new(0),
312                awaiting_last_destruction: SyncCell::new(false),
313                last_event_handler_destroyed: Default::default(),
314                last_event_handler_condvar: Default::default(),
315                registry: Default::default(),
316                destructions: SyncUnsafeCell::new(Vec::new()),
317            }),
318            _inv_scope: Default::default(),
319            _inv_env: Default::default(),
320        }
321    }
322
323    /// # Safety
324    ///
325    /// - may_dispatch must be false and must always stay false.
326    unsafe fn drop(&'scope self, lock: Option<DispatchLock<'_>>) {
327        let lock = lock.unwrap_or_else(|| self.data.queue.lock_dispatch());
328        // SAFETY: - We are holding the queue lock.
329        //         - Since we are holding the queue lock and may_dispatch is and stays
330        //           false, event_handler_func_scoped prevents any future access to any
331        //           of the event handlers attached via this scope.
332        //         - Since may_dispatch is false, by the invariants of may_dispatch,
333        //           may_dispatch has always been false in any parent user stack frame.
334        //           Therefore, if any parent stack frame is an execution of
335        //           event_handler_func_scoped, that execution is calling the no-op event
336        //           handler. Therefore, there is currently no execution of any event
337        //           handler attached via this scope.
338        //         - This function will block until all event handlers have been dropped.
339        //           Should this function panic, the following on_drop handler will set
340        //           defer_destruction back to true before the end of 'scope.
341        unsafe {
342            self.data.defer_destruction.set(false);
343        }
344        // If this function panics, then we must reset defer_destruction before the end
345        // of 'scope. This ensures that event handler drop impls that have not yet run
346        // will be leaked.
347        let reset_defer_destruction = on_drop(|| {
348            self.data.queue.run_locked(|| {
349                // SAFETY: run_locked holds the queue lock.
350                unsafe {
351                    self.data.defer_destruction.set(true);
352                }
353            });
354        });
355        // SAFETY: - All proxies in the registry belong to this scope.
356        //         - We're holding a reference to &'scope self.
357        //         - We're holding the queue lock.
358        //         - By the same logic as in the previous safety comment, there are no
359        //           ongoing dispatches and there won't be any in the future.
360        unsafe {
361            self.data.registry.destroy_event_handlers();
362        }
363        // SAFETY: - We're holding the queue lock.
364        //         - By the safety requirements of this function, may_dispatch is false.
365        unsafe {
366            self.run_destructions(false);
367        }
368        // SAFETY: - We're holding the queue lock.
369        let live_event_handlers = unsafe { self.data.live_event_handlers.get() };
370        // This can only happen if a proxy was removed from the registry in another thread
371        // before destroy_event_handlers collected them but whose destruction has not yet
372        // run. Since defer_destruction is false, the destruction should run very soon.
373        // We have to block here until that has happened so that the drop impl completes
374        // before the end of 'scope.
375        if live_event_handlers > 0 {
376            // SAFETY: - We're holding the queue lock.
377            unsafe {
378                self.data.awaiting_last_destruction.set(true);
379            }
380            drop(lock);
381            let mut done = self.data.last_event_handler_destroyed.lock();
382            while !*done {
383                self.data.last_event_handler_condvar.wait(&mut done);
384            }
385        }
386        reset_defer_destruction.forget();
387    }
388
389    /// # Safety
390    ///
391    /// - The queue lock must be held.
392    /// - may_dispatch must be false
393    unsafe fn run_destructions(&self, re_use_memory: bool) {
394        let mut stash = vec![];
395        // SAFETY: - destructions is only ever accessed with the queue lock held
396        //         - no long-lived references to destructions are ever created
397        mem::swap(&mut stash, unsafe { &mut *self.data.destructions.get() });
398        for destruction in stash.drain(..) {
399            // SAFETY: - destructions only contains destructions such that it is safe to
400            //           run the destruction once there are no ongoing dispatches of the
401            //           event handler.
402            //         - Since may_dispatch is false, by the invariants of may_dispatch,
403            //           it has always been false in any parent stack frame.
404            //           Therefore, if any parent stack frame is an execution of
405            //           event_handler_func_scoped, that execution is calling the no-op
406            //           event handler. Therefore, there can be no dispatch referencing
407            //           the event handler going on.
408            unsafe {
409                destruction.run();
410            }
411        }
412        if re_use_memory {
413            // SAFETY: - destructions is only ever accessed with the queue lock held
414            //         - no long-lived references to destructions are ever created
415            mem::swap(&mut stash, unsafe { &mut *self.data.destructions.get() });
416            assert!(stash.is_empty());
417        }
418    }
419
420    /// Sets the event handler of the proxy.
421    ///
422    /// This function is the same as [`proxy::set_event_handler`] except that the event
423    /// handler does not have to implement `'static` and that the event handler will not
424    /// be invoked after `'scope`.
425    ///
426    /// The proxy must belong to the queue that was used to create this scope.
427    ///
428    /// # Panic
429    ///
430    /// This function panics whenever [`proxy::set_event_handler`] panics and also if the
431    /// proxy does not belong to the queue that was used to create this scope.
432    ///
433    /// # Example
434    ///
435    /// ```
436    /// # use std::sync::Arc;
437    /// # use std::sync::atomic::AtomicBool;
438    /// # use std::sync::atomic::Ordering::Relaxed;
439    /// # use wl_client::{proxy, Libwayland};
440    /// # use wl_client::test_protocols::core::wl_callback::{WlCallback, WlCallbackEventHandler, WlCallbackRef};
441    /// # use wl_client::test_protocols::core::wl_display::WlDisplay;
442    /// #
443    /// let lib = Libwayland::open().unwrap();
444    /// let con = lib.connect_to_default_display().unwrap();
445    /// let queue = con.create_queue(c"queue name");
446    /// let display: WlDisplay = queue.display();
447    /// let sync = display.sync();
448    /// let done = AtomicBool::new(false);
449    ///
450    /// queue.dispatch_scope_blocking(|scope| {
451    ///     // Attach the event handler.
452    ///     scope.set_event_handler(&sync, WlCallback::on_done(|_, _| done.store(true, Relaxed)));
453    ///
454    ///     // Wait for the compositor to send the `done` message.
455    ///     queue.dispatch_roundtrip_blocking().unwrap();
456    /// });
457    ///
458    /// // The event handler sets the value to `true`.
459    /// assert!(done.load(Relaxed));
460    /// ```
461    #[inline]
462    pub fn set_event_handler<P, H>(&'scope self, proxy: &P, handler: H)
463    where
464        P: OwnedProxy,
465        P::Api: CreateEventHandler<H>,
466        <P::Api as CreateEventHandler<H>>::EventHandler: Send + 'scope,
467    {
468        // SAFETY: - The event handler is Send
469        unsafe {
470            set_event_handler(self, proxy, P::Api::create_event_handler(handler));
471        }
472    }
473
474    /// Sets the `!Send` event handler of the proxy.
475    ///
476    /// This function is the same as [`proxy::set_event_handler_local`] except that the
477    /// event handler does not have to implement `'static` and that the event handler will
478    /// not be invoked after `'scope`.
479    ///
480    /// The proxy must belong to the queue that was used to create this scope.
481    ///
482    /// # Panic
483    ///
484    /// This function panics whenever [`proxy::set_event_handler_local`] panics and also
485    /// if the proxy does not belong to the queue that was used to create this scope.
486    ///
487    /// # Example
488    ///
489    /// ```
490    /// # use std::cell::Cell;
491    /// # use std::rc::Rc;
492    /// # use std::sync::atomic::Ordering::Relaxed;
493    /// # use wl_client::{proxy, Libwayland};
494    /// # use wl_client::test_protocols::core::wl_callback::{WlCallback, WlCallbackEventHandler, WlCallbackRef};
495    /// # use wl_client::test_protocols::core::wl_display::WlDisplay;
496    /// #
497    /// let lib = Libwayland::open().unwrap();
498    /// let con = lib.connect_to_default_display().unwrap();
499    /// let queue = con.create_local_queue(c"queue name");
500    /// let display: WlDisplay = queue.display();
501    /// let sync = display.sync();
502    /// let done = Cell::new(false);
503    ///
504    /// queue.dispatch_scope_blocking(|scope| {
505    ///     // Attach the event handler.
506    ///     scope.set_event_handler_local(&sync, WlCallback::on_done(|_, _| done.set(true)));
507    ///
508    ///     // Wait for the compositor to send the `done` message.
509    ///     queue.dispatch_roundtrip_blocking().unwrap();
510    /// });
511    ///
512    /// // The event handler sets the value to `true`.
513    /// assert!(done.get());
514    /// ```
515    #[inline]
516    pub fn set_event_handler_local<P, H>(&'scope self, proxy: &P, handler: H)
517    where
518        P: OwnedProxy,
519        P::Api: CreateEventHandler<H>,
520        <P::Api as CreateEventHandler<H>>::EventHandler: 'scope,
521    {
522        if self.data.queue.is_non_local() {
523            panic!("Queue is not a local queue");
524        }
525        // SAFETY: - We've checked that the queue is a local queue.
526        unsafe {
527            set_event_handler(self, proxy, P::Api::create_event_handler(handler));
528        }
529    }
530}
531
532struct ScopeEventHandler<H, D> {
533    event_handler: H,
534    _on_drop: D,
535}
536
537unsafe impl<H, D> EventHandler for ScopeEventHandler<H, D>
538where
539    H: EventHandler,
540{
541    const WL_INTERFACE: &'static wl_interface = H::WL_INTERFACE;
542
543    #[inline]
544    unsafe fn handle_event(
545        &self,
546        queue: &Queue,
547        slf: &UntypedBorrowedProxy,
548        opcode: u32,
549        args: *mut wl_argument,
550    ) {
551        unsafe {
552            self.event_handler.handle_event(queue, slf, opcode, args);
553        }
554    }
555}
556
557/// # Safety
558///
559/// - if T does not implement Send, then the queue must be a local queue
560unsafe fn set_event_handler<'scope, P, H>(
561    scope: &'scope Scope<'scope, '_>,
562    proxy: &P,
563    event_handler: H,
564) where
565    P: OwnedProxy,
566    H: EventHandler + 'scope,
567{
568    if mem::needs_drop::<H>() {
569        let data = scope.data.clone();
570        let event_handler = ScopeEventHandler {
571            event_handler,
572            _on_drop: on_drop(move || {
573                let d = &*data;
574                let leh = &d.live_event_handlers;
575                // SAFETY: the scope lock is held while dropping event handlers.
576                let live = unsafe { leh.get() };
577                // SAFETY: the scope lock is held while dropping event handlers.
578                unsafe {
579                    leh.set(live - 1);
580                }
581                // SAFETY: the scope lock is held while dropping event handlers.
582                let awaiting_last_destruction = unsafe { d.awaiting_last_destruction.get() };
583                if live == 1 && awaiting_last_destruction {
584                    *d.last_event_handler_destroyed.lock() = true;
585                    d.last_event_handler_condvar.notify_all();
586                }
587            }),
588        };
589        scope.data.queue.run_locked(|| {
590            let leh = &scope.data.live_event_handlers;
591            // SAFETY: We're holding the queue lock.
592            unsafe {
593                leh.set(leh.get() + 1);
594            }
595        });
596        // SAFETY: The requirements are forwarded to the caller.
597        unsafe {
598            set_event_handler2(scope, proxy, event_handler);
599        }
600    } else {
601        // SAFETY: The requirements are forwarded to the caller.
602        unsafe {
603            set_event_handler2(scope, proxy, event_handler);
604        }
605    }
606}
607
608/// # Safety
609///
610/// - if T does not implement Send, then the queue must be a local queue
611unsafe fn set_event_handler2<'scope, P, H>(
612    scope: &'scope Scope<'scope, '_>,
613    proxy: &P,
614    event_handler: H,
615) where
616    P: OwnedProxy,
617    H: EventHandler + 'scope,
618{
619    let proxy = get_owned(proxy);
620    assert_eq!(proxy.queue(), &scope.data.queue);
621    let (event_handler, drop_event_handler) = box_event_handler(event_handler);
622    // SAFETY: - libwayland only ever calls event handlers while preserving a
623    //           valid pointer to the proxy and all pointers in args
624    //         - set_event_handler3 checks that the interface of the proxy is
625    //           P::WL_INTERFACE
626    //         - libwayland ensures that opcode and args conform to the
627    //           interface before calling the event handler
628    //         - set_event_handler3 sets event_handler to a pointer to H
629    //         - if T is not Send, then this function requires that this is a
630    //           local queue which will panic when trying to call this function
631    //           or any dispatching function on a thread other than the thread
632    //           on which the queue was created
633    //         - we always hold the queue lock while dispatching
634    //         - set_event_handler3 sets the scope_data to a pointer to the scope data
635    //           and stores a clone of the Arc so that the pointer will always remain
636    //           valid
637    //         - we only ever invalidate the self.event_handler or self.data
638    //           pointers via handle_destruction which requires that it is safe to run
639    //           the destruction.
640    //         - handle_destruction does not run destructions unless defer_destruction is
641    //           false or run_destructions is called.
642    //           - run_destructions is only ever called within 'scope and
643    //           - defer_destruction is only set to true in drop which blocks until all
644    //             event handlers have been destroyed.
645    unsafe {
646        proxy.set_event_handler3(
647            P::WL_INTERFACE,
648            event_handler,
649            drop_event_handler,
650            mem::needs_drop::<H>(),
651            event_handler_func_scoped::<P, H>,
652            Some(scope),
653        );
654    }
655}
656
657impl ScopeData {
658    /// Handles the destruction of proxies attached to this scope.
659    ///
660    /// If this is called within `'scope`, the destruction is either never runs or runs
661    /// also within `'scope`.
662    ///
663    /// # Safety
664    ///
665    /// - The proxy must be attached to this scope.
666    /// - It must be safe to run the destruction once there are no ongoing dispatches
667    ///   of the event handler of the proxy.
668    pub(super) unsafe fn handle_destruction(&self, destruction: ProxyDataDestruction) {
669        let _lock = self.queue.lock_dispatch();
670        // SAFETY: - we're holding the queue lock
671        match unsafe { self.defer_destruction.get() } {
672            true => {
673                // SAFETY: - destructions is only ever accessed with the queue lock held
674                //         - no long-lived references to destructions are ever created
675                let destructions = unsafe { &mut *self.destructions.get() };
676                // SAFETY: - the destructions in destructions are only run within
677                //           'scope, if ever.
678                destructions.push(destruction);
679            }
680            false => {
681                // SAFETY: - by the invariants, defer_destruction being false implies
682                //           that all dispatcher uses of the event handler have
683                //           ceased and if destruction contains an event handlers then we
684                //           are still within 'scope
685                unsafe { destruction.run() }
686            }
687        }
688    }
689}
690
691/// The event handler function for scoped event handlers.
692///
693/// This function is the same as [`event_handler_func`] except that it additionally checks
694/// that [`ScopeData::may_dispatch`] is true. If it is not, then, instead of calling the
695/// normal event handler, [`P::NO_OP_EVENT_HANDLER`] is called.
696///
697/// This allows the event handler to be destroyed long before the proxy itself is
698/// destroyed as long as `may_dispatch` remains false afterwards.
699///
700/// # Safety
701///
702/// - event_handler_data must be a pointer to UntypedOwnedProxyData
703/// - the scope_data field in the UntypedOwnedProxy must contain a pointer to ScopeData
704/// - the queue lock of the proxy must be held
705/// - if scope_data.may_dispatch, then all safety requirements of event_handler_func::<T>
706///   must be satisfied
707/// - the interface of the proxy must be P::WL_INTERFACE
708unsafe extern "C" fn event_handler_func_scoped<P, T>(
709    event_handler_data: *const c_void,
710    target: *mut c_void,
711    opcode: u32,
712    msg: *const wl_message,
713    args: *mut wl_argument,
714) -> c_int
715where
716    P: OwnedProxy,
717    T: EventHandler,
718{
719    // SAFETY: By the safety requirements of this function, event_handler is a valid pointer
720    //         to UntypedOwnedProxyData.
721    let proxy_data = unsafe { &*(event_handler_data as *const UntypedOwnedProxyData) };
722    // SAFETY: Dito, scope_data is a valid pointer.
723    let scope_data = unsafe { &*proxy_data.scope_data.load(Relaxed) };
724    // SAFETY: Dito, the queue lock is being held.
725    if unsafe { scope_data.may_dispatch.get() } {
726        // SAFETY: Dito, since may_dispatch is true, all safety requirements of
727        //         event_handler_func are satisfied.
728        return unsafe { event_handler_func::<T>(event_handler_data, target, opcode, msg, args) };
729    }
730    // SAFETY: Dito, target is and stays valid.
731    let target = unsafe { NonNull::new_unchecked(target.cast()) };
732    // SAFETY: Dito, target is and stays valid.
733    let target =
734        unsafe { UntypedBorrowedProxy::new_immutable(proxy_data.proxy.libwayland, target) };
735    // SAFETY: Dito, the interface of the proxy is P::WL_INTERFACE
736    //         Dito, target is a valid pointer and stays valid
737    //         Dito, opcode and args conform to P::WL_INTERFACE
738    unsafe {
739        P::NO_OP_EVENT_HANDLER.handle_event(&proxy_data.queue, &target, opcode, args);
740    }
741    0
742}