766 lines · 26.0 KB · Rust
RawDownload
use crate::{    AnyView, AnyWindowHandle, AppContext, AsyncApp, DispatchPhase, Effect, EntityId, EventEmitter,    FocusHandle, FocusOutEvent, Focusable, Global, KeystrokeObserver, Reservation, SubscriberSet,    Subscription, Task, WeakEntity, WeakFocusHandle, Window, WindowHandle,};use anyhow::Result;use derive_more::{Deref, DerefMut};use futures::FutureExt;use std::{    any::{Any, TypeId},    borrow::{Borrow, BorrowMut},    future::Future,    sync::Arc,}; use super::{App, AsyncWindowContext, Entity, KeystrokeEvent}; /// The app context, with specialized behavior for the given entity.#[derive(Deref, DerefMut)]pub struct Context<'a, T> {    #[deref]    #[deref_mut]    app: &'a mut App,    entity_state: WeakEntity<T>,} impl<'a, T: 'static> Context<'a, T> {    pub(crate) fn new_context(app: &'a mut App, entity_state: WeakEntity<T>) -> Self {        Self { app, entity_state }    }     /// The entity id of the entity backing this context.    pub fn entity_id(&self) -> EntityId {        self.entity_state.entity_id    }     /// Returns a handle to the entity belonging to this context.    pub fn entity(&self) -> Entity<T> {        self.weak_entity()            .upgrade()            .expect("The entity must be alive if we have a entity context")    }     /// Returns a weak handle to the entity belonging to this context.    pub fn weak_entity(&self) -> WeakEntity<T> {        self.entity_state.clone()    }     /// Arranges for the given function to be called whenever [`Context::notify`] is    /// called with the given entity.    pub fn observe<W>(        &mut self,        entity: &Entity<W>,        mut on_notify: impl FnMut(&mut T, Entity<W>, &mut Context<'_, T>) + 'static,    ) -> Subscription    where        T: 'static,        W: 'static,    {        let this = self.weak_entity();        self.app.observe_internal(entity, move |e, cx| {            if let Some(this) = this.upgrade() {                this.update(cx, |this, cx| on_notify(this, e, cx));                true            } else {                false            }        })    }     /// Subscribe to an event type from another entity    pub fn subscribe<T2, Evt>(        &mut self,        entity: &Entity<T2>,        mut on_event: impl FnMut(&mut T, Entity<T2>, &Evt, &mut Context<'_, T>) + 'static,    ) -> Subscription    where        T: 'static,        T2: 'static + EventEmitter<Evt>,        Evt: 'static,    {        let this = self.weak_entity();        self.app.subscribe_internal(entity, move |e, event, cx| {            if let Some(this) = this.upgrade() {                this.update(cx, |this, cx| on_event(this, e, event, cx));                true            } else {                false            }        })    }     /// Subscribe to an event type from ourself    pub fn subscribe_self<Evt>(        &mut self,        mut on_event: impl FnMut(&mut T, &Evt, &mut Context<'_, T>) + 'static,    ) -> Subscription    where        T: 'static + EventEmitter<Evt>,        Evt: 'static,    {        let this = self.entity();        self.app.subscribe(&this, move |this, evt, cx| {            this.update(cx, |this, cx| on_event(this, evt, cx))        })    }     /// Register a callback to be invoked when GPUI releases this entity.    pub fn on_release(&self, on_release: impl FnOnce(&mut T, &mut App) + 'static) -> Subscription    where        T: 'static,    {        let (subscription, activate) = self.app.release_listeners.insert(            self.entity_state.entity_id,            Box::new(move |this, cx| {                let this = this.downcast_mut().expect("invalid entity type");                on_release(this, cx);            }),        );        activate();        subscription    }     /// Register a callback to be run on the release of another entity    pub fn observe_release<T2>(        &self,        entity: &Entity<T2>,        on_release: impl FnOnce(&mut T, &mut T2, &mut Context<'_, T>) + 'static,    ) -> Subscription    where        T: Any,        T2: 'static,    {        let entity_id = entity.entity_id();        let this = self.weak_entity();        let (subscription, activate) = self.app.release_listeners.insert(            entity_id,            Box::new(move |entity, cx| {                let entity = entity.downcast_mut().expect("invalid entity type");                if let Some(this) = this.upgrade() {                    this.update(cx, |this, cx| on_release(this, entity, cx));                }            }),        );        activate();        subscription    }     /// Register a callback to for updates to the given global    pub fn observe_global<G: 'static>(        &mut self,        mut f: impl FnMut(&mut T, &mut Context<'_, T>) + 'static,    ) -> Subscription    where        T: 'static,    {        let handle = self.weak_entity();        let (subscription, activate) = self.global_observers.insert(            TypeId::of::<G>(),            Box::new(move |cx| handle.update(cx, |view, cx| f(view, cx)).is_ok()),        );        self.defer(move |_| activate());        subscription    }     /// Arrange for the given function to be invoked whenever the application is quit.    /// The future returned from this callback will be polled for up to [crate::SHUTDOWN_TIMEOUT] until the app fully quits.    pub fn on_app_quit<Fut>(        &self,        mut on_quit: impl FnMut(&mut T, &mut Context<T>) -> Fut + 'static,    ) -> Subscription    where        Fut: 'static + Future<Output = ()>,        T: 'static,    {        let handle = self.weak_entity();        let (subscription, activate) = self.app.quit_observers.insert(            (),            Box::new(move |cx| {                let future = handle.update(cx, |entity, cx| on_quit(entity, cx)).ok();                async move {                    if let Some(future) = future {                        future.await;                    }                }                .boxed_local()            }),        );        activate();        subscription    }     /// Tell GPUI that this entity has changed and observers of it should be notified.    pub fn notify(&mut self) {        self.app.notify(self.entity_state.entity_id);    }     /// Spawn the future returned by the given function.    /// The function is provided a weak handle to the entity owned by this context and a context that can be held across await points.    /// The returned task must be held or detached.    #[track_caller]    pub fn spawn<Fut, R>(&self, f: impl FnOnce(WeakEntity<T>, AsyncApp) -> Fut) -> Task<R>    where        T: 'static,        Fut: Future<Output = R> + 'static,        R: 'static,    {        let this = self.weak_entity();        self.app.spawn(|cx| f(this, cx))    }     /// Convenience method for accessing view state in an event callback.    ///    /// Many GPUI callbacks take the form of `Fn(&E, &mut Window, &mut AppContext)`,    /// but it's often useful to be able to access view state in these    /// callbacks. This method provides a convenient way to do so.    pub fn listener<E: ?Sized>(        &self,        f: impl Fn(&mut T, &E, &mut Window, &mut Context<T>) + 'static,    ) -> impl Fn(&E, &mut Window, &mut App) + 'static {        let view = self.entity().downgrade();        move |e: &E, window: &mut Window, cx: &mut App| {            view.update(cx, |view, cx| f(view, e, window, cx)).ok();        }    }     /// Focus the given view in the given window. View type is required to implement Focusable.    pub fn focus_view<W: Focusable>(&mut self, view: &Entity<W>, window: &mut Window) {        window.focus(&view.focus_handle(self));    }     /// Sets a given callback to be run on the next frame.    pub fn on_next_frame(        &self,        window: &mut Window,        f: impl FnOnce(&mut T, &mut Window, &mut Context<T>) + 'static,    ) where        T: 'static,    {        let view = self.entity();        window.on_next_frame(move |window, cx| view.update(cx, |view, cx| f(view, window, cx)));    }     /// Schedules the given function to be run at the end of the current effect cycle, allowing entities    /// that are currently on the stack to be returned to the app.    pub fn defer_in(        &mut self,        window: &Window,        f: impl FnOnce(&mut T, &mut Window, &mut Context<T>) + 'static,    ) {        let view = self.entity();        window.defer(self, move |window, cx| {            view.update(cx, |view, cx| f(view, window, cx))        });    }     /// Observe another entity for changes to its state, as tracked by [`Context::notify`].    pub fn observe_in<V2>(        &mut self,        observed: &Entity<V2>,        window: &mut Window,        mut on_notify: impl FnMut(&mut T, Entity<V2>, &mut Window, &mut Context<'_, T>) + 'static,    ) -> Subscription    where        V2: 'static,        T: 'static,    {        let observed_id = observed.entity_id();        let observed = observed.downgrade();        let window_handle = window.handle;        let observer = self.weak_entity();        self.new_observer(            observed_id,            Box::new(move |cx| {                window_handle                    .update(cx, |_, window, cx| {                        if let Some((observer, observed)) =                            observer.upgrade().zip(observed.upgrade())                        {                            observer.update(cx, |observer, cx| {                                on_notify(observer, observed, window, cx);                            });                            true                        } else {                            false                        }                    })                    .unwrap_or(false)            }),        )    }     /// Subscribe to events emitted by another entity.    /// The entity to which you're subscribing must implement the [`EventEmitter`] trait.    /// The callback will be invoked with a reference to the current view, a handle to the emitting `Entity`, the event, a mutable reference to the `Window`, and the context for the entity.    pub fn subscribe_in<Emitter, Evt>(        &mut self,        emitter: &Entity<Emitter>,        window: &Window,        mut on_event: impl FnMut(&mut T, &Entity<Emitter>, &Evt, &mut Window, &mut Context<'_, T>)            + 'static,    ) -> Subscription    where        Emitter: EventEmitter<Evt>,        Evt: 'static,    {        let emitter = emitter.downgrade();        let window_handle = window.handle;        let subscriber = self.weak_entity();        self.new_subscription(            emitter.entity_id(),            (                TypeId::of::<Evt>(),                Box::new(move |event, cx| {                    window_handle                        .update(cx, |_, window, cx| {                            if let Some((subscriber, emitter)) =                                subscriber.upgrade().zip(emitter.upgrade())                            {                                let event = event.downcast_ref().expect("invalid event type");                                subscriber.update(cx, |subscriber, cx| {                                    on_event(subscriber, &emitter, event, window, cx);                                });                                true                            } else {                                false                            }                        })                        .unwrap_or(false)                }),            ),        )    }     /// Register a callback to be invoked when the view is released.    ///    /// The callback receives a handle to the view's window. This handle may be    /// invalid, if the window was closed before the view was released.    pub fn on_release_in(        &mut self,        window: &Window,        on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,    ) -> Subscription {        let entity = self.entity();        self.app.observe_release_in(&entity, window, on_release)    }     /// Register a callback to be invoked when the given Entity is released.    pub fn observe_release_in<T2>(        &self,        observed: &Entity<T2>,        window: &Window,        mut on_release: impl FnMut(&mut T, &mut T2, &mut Window, &mut Context<'_, T>) + 'static,    ) -> Subscription    where        T: 'static,        T2: 'static,    {        let observer = self.weak_entity();        self.app            .observe_release_in(observed, window, move |observed, window, cx| {                observer                    .update(cx, |observer, cx| {                        on_release(observer, observed, window, cx)                    })                    .ok();            })    }     /// Register a callback to be invoked when the window is resized.    pub fn observe_window_bounds(        &self,        window: &mut Window,        mut callback: impl FnMut(&mut T, &mut Window, &mut Context<T>) + 'static,    ) -> Subscription {        let view = self.weak_entity();        let (subscription, activate) = window.bounds_observers.insert(            (),            Box::new(move |window, cx| {                view.update(cx, |view, cx| callback(view, window, cx))                    .is_ok()            }),        );        activate();        subscription    }     /// Register a callback to be invoked when the window is activated or deactivated.    pub fn observe_window_activation(        &self,        window: &mut Window,        mut callback: impl FnMut(&mut T, &mut Window, &mut Context<T>) + 'static,    ) -> Subscription {        let view = self.weak_entity();        let (subscription, activate) = window.activation_observers.insert(            (),            Box::new(move |window, cx| {                view.update(cx, |view, cx| callback(view, window, cx))                    .is_ok()            }),        );        activate();        subscription    }     /// Registers a callback to be invoked when the window appearance changes.    pub fn observe_window_appearance(        &self,        window: &mut Window,        mut callback: impl FnMut(&mut T, &mut Window, &mut Context<T>) + 'static,    ) -> Subscription {        let view = self.weak_entity();        let (subscription, activate) = window.appearance_observers.insert(            (),            Box::new(move |window, cx| {                view.update(cx, |view, cx| callback(view, window, cx))                    .is_ok()            }),        );        activate();        subscription    }     /// Register a callback to be invoked when a keystroke is received by the application    /// in any window. Note that this fires after all other action and event mechanisms have resolved    /// and that this API will not be invoked if the event's propagation is stopped.    pub fn observe_keystrokes(        &mut self,        mut f: impl FnMut(&mut T, &KeystrokeEvent, &mut Window, &mut Context<T>) + 'static,    ) -> Subscription {        fn inner(            keystroke_observers: &SubscriberSet<(), KeystrokeObserver>,            handler: KeystrokeObserver,        ) -> Subscription {            let (subscription, activate) = keystroke_observers.insert((), handler);            activate();            subscription        }         let view = self.weak_entity();        inner(            &mut self.keystroke_observers,            Box::new(move |event, window, cx| {                if let Some(view) = view.upgrade() {                    view.update(cx, |view, cx| f(view, event, window, cx));                    true                } else {                    false                }            }),        )    }     /// Register a callback to be invoked when the window's pending input changes.    pub fn observe_pending_input(        &self,        window: &mut Window,        mut callback: impl FnMut(&mut T, &mut Window, &mut Context<T>) + 'static,    ) -> Subscription {        let view = self.weak_entity();        let (subscription, activate) = window.pending_input_observers.insert(            (),            Box::new(move |window, cx| {                view.update(cx, |view, cx| callback(view, window, cx))                    .is_ok()            }),        );        activate();        subscription    }     /// Register a listener to be called when the given focus handle receives focus.    /// Returns a subscription and persists until the subscription is dropped.    pub fn on_focus(        &mut self,        handle: &FocusHandle,        window: &mut Window,        mut listener: impl FnMut(&mut T, &mut Window, &mut Context<T>) + 'static,    ) -> Subscription {        let view = self.weak_entity();        let focus_id = handle.id;        let (subscription, activate) =            window.new_focus_listener(Box::new(move |event, window, cx| {                view.update(cx, |view, cx| {                    if event.previous_focus_path.last() != Some(&focus_id)                        && event.current_focus_path.last() == Some(&focus_id)                    {                        listener(view, window, cx)                    }                })                .is_ok()            }));        self.defer(|_| activate());        subscription    }     /// Register a listener to be called when the given focus handle or one of its descendants receives focus.    /// This does not fire if the given focus handle - or one of its descendants - was previously focused.    /// Returns a subscription and persists until the subscription is dropped.    pub fn on_focus_in(

Lines 1–500 of 766.