1use crate::{
2 AnyView, AnyWindowHandle, App, AppCell, AppContext, BackgroundExecutor, BorrowAppContext,
3 Entity, EntityId, EventEmitter, Focusable, ForegroundExecutor, Global, GpuiBorrow,
4 PromptButton, PromptLevel, Render, Reservation, Result, Subscription, Task, VisualContext,
5 Window, WindowHandle,
6};
7use anyhow::{Context as _, bail};
8use derive_more::{Deref, DerefMut};
9use futures::channel::oneshot;
10use futures::future::FutureExt;
11use std::{future::Future, rc::Weak};
12
13use super::{Context, WeakEntity};
14
15#[derive(Clone)]
58pub struct AsyncApp {
59 pub(crate) app: Weak<AppCell>,
60 pub(crate) background_executor: BackgroundExecutor,
61 pub(crate) foreground_executor: ForegroundExecutor,
62}
63
64impl AsyncApp {
65 fn app(&self) -> std::rc::Rc<AppCell> {
66 self.app
67 .upgrade()
68 .expect("app was released before async operation completed")
69 }
70}
71
72impl AppContext for AsyncApp {
73 fn new<T: 'static>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T> {
74 let app = self.app();
75 let mut app = app.borrow_mut();
76 app.new(build_entity)
77 }
78
79 fn reserve_entity<T: 'static>(&mut self) -> Reservation<T> {
80 let app = self.app();
81 let mut app = app.borrow_mut();
82 app.reserve_entity()
83 }
84
85 fn insert_entity<T: 'static>(
86 &mut self,
87 reservation: Reservation<T>,
88 build_entity: impl FnOnce(&mut Context<T>) -> T,
89 ) -> Entity<T> {
90 let app = self.app();
91 let mut app = app.borrow_mut();
92 app.insert_entity(reservation, build_entity)
93 }
94
95 #[inline(always)]
96 fn update_entity<T: 'static, R>(
97 &mut self,
98 handle: &Entity<T>,
99 update: impl FnOnce(&mut T, &mut Context<T>) -> R,
100 ) -> R {
101 let app = self.app();
102 let mut app = app.borrow_mut();
103 app.update_entity(handle, update)
104 }
105
106 fn as_mut<'a, T>(&'a mut self, _handle: &Entity<T>) -> GpuiBorrow<'a, T>
107 where
108 T: 'static,
109 {
110 panic!("Cannot as_mut with an async context. Try calling update() first")
111 }
112
113 #[inline(always)]
114 fn read_entity<T, R>(&self, handle: &Entity<T>, callback: impl FnOnce(&T, &App) -> R) -> R
115 where
116 T: 'static,
117 {
118 let app = self.app();
119 let lock = app.borrow();
120 lock.read_entity(handle, callback)
121 }
122
123 fn notify(&mut self, entity_id: EntityId) {
124 let app = self.app();
125 let mut lock = app.borrow_mut();
126 lock.notify(entity_id);
127 }
128
129 fn emit<EntityType, EventType>(&mut self, entity: &Entity<EntityType>, event: EventType)
130 where
131 EntityType: EventEmitter<EventType>,
132 EventType: 'static,
133 {
134 let app = self.app();
135 let mut lock = app.borrow_mut();
136 lock.emit(entity, event)
137 }
138
139 #[inline(always)]
140 fn update_window<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Result<T>
141 where
142 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
143 {
144 let app = self.app.upgrade().context("app was released")?;
145 let mut lock = app.try_borrow_mut()?;
146 if lock.quitting {
147 bail!("app is quitting");
148 }
149 lock.update_window(window, f)
150 }
151
152 #[inline(always)]
153 fn with_window<R>(
154 &mut self,
155 entity_id: EntityId,
156 f: impl FnOnce(&mut Window, &mut App) -> R,
157 ) -> Option<R> {
158 let app = self.app.upgrade()?;
159 let mut lock = app.try_borrow_mut().ok()?;
160 if lock.quitting {
161 return None;
162 }
163 lock.with_window(entity_id, f)
164 }
165
166 fn read_window<T, R>(
167 &self,
168 window: &WindowHandle<T>,
169 read: impl FnOnce(Entity<T>, &App) -> R,
170 ) -> Result<R>
171 where
172 T: 'static,
173 {
174 let app = self.app.upgrade().context("app was released")?;
175 let lock = app.borrow();
176 if lock.quitting {
177 bail!("app is quitting");
178 }
179 lock.read_window(window, read)
180 }
181
182 #[track_caller]
183 fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
184 where
185 R: Send + 'static,
186 {
187 self.background_executor.spawn(future)
188 }
189
190 fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> R
191 where
192 G: Global,
193 {
194 let app = self.app();
195 let mut lock = app.borrow_mut();
196 lock.update(|this| this.read_global(callback))
197 }
198
199 fn insert_global_entity<T: 'static>(&mut self, entity: Entity<T>) {
200 let app = self.app();
201 let mut lock = app.borrow_mut();
202 lock.insert_global_entity(entity)
203 }
204
205 fn remove_global_entity<T: 'static>(&mut self, entity: &Entity<T>) {
206 let app = self.app();
207 let mut lock = app.borrow_mut();
208 lock.remove_global_entity(entity)
209 }
210
211 fn global_entities<T: 'static>(&self) -> impl Iterator<Item = Entity<T>> {
212 let app = self.app();
213 let mut lock = app.borrow_mut();
214 let iter = lock.global_entities();
215 iter.collect::<Vec<_>>().into_iter()
217 }
218}
219
220impl AsyncApp {
221 pub fn refresh(&self) {
225 let app = self.app();
226 let mut lock = app.borrow_mut();
227 lock.update(|cx| cx.refresh_windows());
230 }
231
232 pub fn background_executor(&self) -> &BackgroundExecutor {
234 &self.background_executor
235 }
236
237 pub fn is_test(&self) -> bool {
240 self.background_executor.is_test()
241 }
242
243 pub fn foreground_executor(&self) -> &ForegroundExecutor {
245 &self.foreground_executor
246 }
247
248 #[inline(always)]
257 pub fn update<R>(&self, f: impl FnOnce(&mut App) -> R) -> R {
258 let app = self.app();
259 let mut lock = app.borrow_mut();
260 lock.update(f)
261 }
262
263 pub fn subscribe<T, Event>(
270 &mut self,
271 entity: &Entity<T>,
272 on_event: impl FnMut(Entity<T>, &Event, &mut App) + 'static,
273 ) -> Subscription
274 where
275 T: 'static + EventEmitter<Event>,
276 Event: 'static,
277 {
278 let app = self.app();
279 let mut lock = app.borrow_mut();
280 lock.subscribe(entity, on_event)
281 }
282
283 pub fn open_window<V>(
292 &self,
293 options: crate::WindowOptions,
294 build_root_view: impl FnOnce(&mut Window, &mut App) -> Entity<V>,
295 ) -> Result<WindowHandle<V>>
296 where
297 V: 'static + Render,
298 {
299 let app = self.app();
300 let mut lock = app.borrow_mut();
301 if lock.quitting {
302 bail!("app is quitting");
303 }
304 lock.open_window(options, build_root_view)
305 }
306
307 #[track_caller]
313 #[inline(always)]
314 pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
315 where
316 AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
317 R: 'static,
318 {
319 let mut cx = self.clone();
320 self.foreground_executor
321 .spawn(async move { f(&mut cx).await }.boxed_local())
322 }
323
324 pub fn has_global<G: Global>(&self) -> bool {
326 let app = self.app();
327 let app = app.borrow_mut();
328 app.has_global::<G>()
329 }
330
331 #[inline(always)]
339 pub fn read_global<G: Global, R>(&self, read: impl FnOnce(&G, &App) -> R) -> R {
340 let app = self.app();
341 let app = app.borrow_mut();
342 read(app.global(), &app)
343 }
344
345 pub fn try_read_global<G: Global, R>(&self, read: impl FnOnce(&G, &App) -> R) -> Option<R> {
348 let app = self.app();
349 let app = app.borrow_mut();
350 if app.quitting {
351 return None;
352 }
353 Some(read(app.try_global()?, &app))
354 }
355
356 pub fn read_default_global<G: Global + Default, R>(
359 &self,
360 read: impl FnOnce(&G, &App) -> R,
361 ) -> R {
362 let app = self.app();
363 let mut app = app.borrow_mut();
364 app.update(|cx| {
365 cx.default_global::<G>();
366 });
367 read(app.global(), &app)
368 }
369
370 pub fn update_global<G: Global, R>(&self, update: impl FnOnce(&mut G, &mut App) -> R) -> R {
380 let app = self.app();
381 let mut app = app.borrow_mut();
382 app.update(|cx| cx.update_global(update))
383 }
384
385 pub fn on_drop<T: 'static, Callback: FnOnce(&mut T, &mut Context<T>) + 'static>(
407 &self,
408 entity: &WeakEntity<T>,
409 f: Callback,
410 ) -> gpui_util::Deferred<impl FnOnce() + use<T, Callback>> {
411 let entity = entity.clone();
412 let mut cx = self.clone();
413 gpui_util::defer(move || {
414 entity.update(&mut cx, f).ok();
415 })
416 }
417}
418
419#[derive(Clone, Deref, DerefMut)]
462pub struct AsyncWindowContext {
463 #[deref]
464 #[deref_mut]
465 app: AsyncApp,
466 window: AnyWindowHandle,
467}
468
469impl AsyncWindowContext {
470 pub(crate) fn new_context(app: AsyncApp, window: AnyWindowHandle) -> Self {
471 Self { app, window }
472 }
473
474 pub fn window_handle(&self) -> AnyWindowHandle {
476 self.window
477 }
478
479 #[inline(always)]
488 pub fn update<R>(&mut self, update: impl FnOnce(&mut Window, &mut App) -> R) -> Result<R> {
489 self.app
490 .update_window(self.window, |_, window, cx| update(window, cx))
491 }
492
493 #[inline(always)]
499 pub fn update_root<R>(
500 &mut self,
501 update: impl FnOnce(AnyView, &mut Window, &mut App) -> R,
502 ) -> Result<R> {
503 self.app.update_window(self.window, update)
504 }
505
506 pub fn on_next_frame(&mut self, f: impl FnOnce(&mut Window, &mut App) + 'static) {
512 self.app
513 .update_window(self.window, |_, window, _| window.on_next_frame(f))
514 .ok();
515 }
516
517 pub fn read_global<G: Global, R>(
528 &mut self,
529 read: impl FnOnce(&G, &Window, &App) -> R,
530 ) -> Result<R> {
531 self.app
532 .update_window(self.window, |_, window, cx| read(cx.global(), window, cx))
533 }
534
535 pub fn update_global<G, R>(
548 &mut self,
549 update: impl FnOnce(&mut G, &mut Window, &mut App) -> R,
550 ) -> Result<R>
551 where
552 G: Global,
553 {
554 self.app.update_window(self.window, |_, window, cx| {
555 cx.update_global(|global, cx| update(global, window, cx))
556 })
557 }
558
559 #[track_caller]
565 #[inline(always)]
566 pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
567 where
568 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
569 R: 'static,
570 {
571 let mut cx = self.clone();
572 self.foreground_executor
573 .spawn(async move { f(&mut cx).await }.boxed_local())
574 }
575
576 pub fn prompt<T>(
582 &mut self,
583 level: PromptLevel,
584 message: &str,
585 detail: Option<&str>,
586 answers: &[T],
587 ) -> oneshot::Receiver<usize>
588 where
589 T: Clone + Into<PromptButton>,
590 {
591 self.app
592 .update_window(self.window, |_, window, cx| {
593 window.prompt(level, message, detail, answers, cx)
594 })
595 .unwrap_or_else(|_| oneshot::channel().1)
596 }
597}
598
599impl AppContext for AsyncWindowContext {
600 fn new<T>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T>
601 where
602 T: 'static,
603 {
604 let mut build_entity = Some(build_entity);
605 match self.app.update_window(self.window, |_, _, cx| {
606 cx.new(
607 build_entity
608 .take()
609 .expect("build_entity is taken exactly once"),
610 )
611 }) {
612 Ok(entity) => entity,
613 Err(_) => self.app.new(
614 build_entity
615 .take()
616 .expect("update_window returned Err without invoking the closure"),
617 ),
618 }
619 }
620
621 fn reserve_entity<T: 'static>(&mut self) -> Reservation<T> {
622 self.app.reserve_entity()
623 }
624
625 fn insert_entity<T: 'static>(
626 &mut self,
627 reservation: Reservation<T>,
628 build_entity: impl FnOnce(&mut Context<T>) -> T,
629 ) -> Entity<T> {
630 let mut args = Some((reservation, build_entity));
631 match self.app.update_window(self.window, |_, _, cx| {
632 let (reservation, build_entity) = args.take().expect("args are taken exactly once");
633 cx.insert_entity(reservation, build_entity)
634 }) {
635 Ok(entity) => entity,
636 Err(_) => {
637 let (reservation, build_entity) = args
638 .take()
639 .expect("update_window returned Err without invoking the closure");
640 self.app.insert_entity(reservation, build_entity)
641 }
642 }
643 }
644
645 #[inline(always)]
646 fn update_entity<T: 'static, R>(
647 &mut self,
648 handle: &Entity<T>,
649 update: impl FnOnce(&mut T, &mut Context<T>) -> R,
650 ) -> R {
651 self.app.update_entity(handle, update)
652 }
653
654 fn as_mut<'a, T>(&'a mut self, _: &Entity<T>) -> GpuiBorrow<'a, T>
655 where
656 T: 'static,
657 {
658 panic!("Cannot use as_mut() from an async context, call `update`")
659 }
660
661 #[inline(always)]
662 fn read_entity<T, R>(&self, handle: &Entity<T>, read: impl FnOnce(&T, &App) -> R) -> R
663 where
664 T: 'static,
665 {
666 self.app.read_entity(handle, read)
667 }
668
669 fn notify(&mut self, entity_id: EntityId) {
670 self.app.notify(entity_id);
671 }
672
673 fn emit<EntityType, EventType>(&mut self, entity: &Entity<EntityType>, event: EventType)
674 where
675 EntityType: EventEmitter<EventType>,
676 EventType: 'static,
677 {
678 self.app.emit(entity, event)
679 }
680
681 #[inline(always)]
682 fn update_window<T, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<T>
683 where
684 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
685 {
686 self.app.update_window(window, update)
687 }
688
689 #[inline(always)]
690 fn with_window<R>(
691 &mut self,
692 entity_id: EntityId,
693 f: impl FnOnce(&mut Window, &mut App) -> R,
694 ) -> Option<R> {
695 self.app.with_window(entity_id, f)
696 }
697
698 fn read_window<T, R>(
699 &self,
700 window: &WindowHandle<T>,
701 read: impl FnOnce(Entity<T>, &App) -> R,
702 ) -> Result<R>
703 where
704 T: 'static,
705 {
706 self.app.read_window(window, read)
707 }
708
709 #[track_caller]
710 fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
711 where
712 R: Send + 'static,
713 {
714 self.app.background_executor.spawn(future)
715 }
716
717 fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> R
718 where
719 G: Global,
720 {
721 self.app.read_global(callback)
722 }
723
724 fn insert_global_entity<T: 'static>(&mut self, entity: Entity<T>) {
725 self.app.insert_global_entity(entity)
726 }
727
728 fn remove_global_entity<T: 'static>(&mut self, entity: &Entity<T>) {
729 self.app.remove_global_entity(entity)
730 }
731
732 fn global_entities<T: 'static>(&self) -> impl Iterator<Item = Entity<T>> {
733 self.app.global_entities()
734 }
735}
736
737impl VisualContext for AsyncWindowContext {
738 type Result<T> = Result<T>;
739
740 fn window_handle(&self) -> AnyWindowHandle {
741 self.window
742 }
743
744 fn new_window_entity<T: 'static>(
745 &mut self,
746 build_entity: impl FnOnce(&mut Window, &mut Context<T>) -> T,
747 ) -> Result<Entity<T>> {
748 self.app.update_window(self.window, |_, window, cx| {
749 cx.new(|cx| build_entity(window, cx))
750 })
751 }
752
753 fn update_window_entity<T: 'static, R>(
754 &mut self,
755 view: &Entity<T>,
756 update: impl FnOnce(&mut T, &mut Window, &mut Context<T>) -> R,
757 ) -> Result<R> {
758 let view = view.clone();
759 self.app
760 .with_window(view.entity_id(), |window, app| {
761 view.update(app, |entity, cx| update(entity, window, cx))
762 })
763 .context("entity has no current window")
764 }
765
766 fn replace_root_view<V>(
767 &mut self,
768 build_view: impl FnOnce(&mut Window, &mut Context<V>) -> V,
769 ) -> Result<Entity<V>>
770 where
771 V: 'static + Render,
772 {
773 self.app.update_window(self.window, |_, window, cx| {
774 window.replace_root(cx, build_view)
775 })
776 }
777
778 fn focus<V>(&mut self, view: &Entity<V>) -> Result<()>
779 where
780 V: Focusable,
781 {
782 self.app.update_window(self.window, |_, window, cx| {
783 view.read(cx).focus_handle(cx).focus(window, cx);
784 })
785 }
786}