853 lines · 28.6 KB · Rust
RawDownload
use crate::{    AnyView, AnyWindowHandle, AppContext, AsyncApp, DispatchPhase, Effect, EntityId, EventEmitter,    FocusHandle, FocusOutEvent, Focusable, Global, KeystrokeObserver, Priority, Reservation,    SubscriberSet, Subscription, Task, WeakEntity, WeakFocusHandle, Window, WindowHandle,};use anyhow::Result;use futures::FutureExt;use std::{    any::{Any, TypeId},    borrow::{Borrow, BorrowMut},    future::Future,    ops,    sync::Arc,};use util::Deferred; use super::{App, AsyncWindowContext, Entity, KeystrokeEvent}; /// The app context, with specialized behavior for the given entity.pub struct Context<'a, T> {    app: &'a mut App,    entity_state: WeakEntity<T>,} impl<'a, T> ops::Deref for Context<'a, T> {    type Target = App;     fn deref(&self) -> &Self::Target {        self.app    }} impl<'a, T> ops::DerefMut for Context<'a, T> {    fn deref_mut(&mut self) -> &mut Self::Target {        self.app    }} 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            }        })    }     /// Observe changes to ourselves    pub fn observe_self(        &mut self,        mut on_event: impl FnMut(&mut T, &mut Context<T>) + 'static,    ) -> Subscription    where        T: 'static,    {        let this = self.entity();        self.app.observe(&this, move |this, cx| {            this.update(cx, |this, cx| on_event(this, cx))        })    }     /// 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    }     /// Register a callback to be invoked when the application is about to restart.    pub fn on_app_restart(        &self,        mut on_restart: impl FnMut(&mut T, &mut App) + 'static,    ) -> Subscription    where        T: 'static,    {        let handle = self.weak_entity();        self.app.on_app_restart(move |cx| {            handle.update(cx, |entity, cx| on_restart(entity, cx)).ok();        })    }     /// 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();        self.app.on_app_quit(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()        })    }     /// 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<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>    where        T: 'static,        AsyncFn: AsyncFnOnce(WeakEntity<T>, &mut AsyncApp) -> R + 'static,        R: 'static,    {        let this = self.weak_entity();        self.app.spawn(async move |cx| f(this, cx).await)    }     /// Convenience method for accessing view state in an event callback.    ///    /// Many GPUI callbacks take the form of `Fn(&E, &mut Window, &mut App)`,    /// 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();        }    }     /// Convenience method for producing view state in a closure.    /// See `listener` for more details.    pub fn processor<E, R>(        &self,        f: impl Fn(&mut T, E, &mut Window, &mut Context<T>) -> R + 'static,    ) -> impl Fn(E, &mut Window, &mut App) -> R + 'static {        let view = self.entity();        move |e: E, window: &mut Window, cx: &mut App| {            view.update(cx, |view, cx| f(view, e, window, cx))        }    }     /// Run something using this entity and cx, when the returned struct is dropped    pub fn on_drop(        &self,        f: impl FnOnce(&mut T, &mut Context<T>) + 'static,    ) -> Deferred<impl FnOnce()> {        let this = self.weak_entity();        let mut cx = self.to_async();        util::defer(move || {            this.update(&mut cx, f).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), 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(            &self.keystroke_observers,

Lines 1–500 of 853.