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)]
22pub struct AsyncApp {
23 pub(crate) app: Weak<AppCell>,
24 pub(crate) background_executor: BackgroundExecutor,
25 pub(crate) foreground_executor: ForegroundExecutor,
26}
27
28impl AsyncApp {
29 fn app(&self) -> std::rc::Rc<AppCell> {
30 self.app
31 .upgrade()
32 .expect("app was released before async operation completed")
33 }
34}
35
36impl AppContext for AsyncApp {
37 fn new<T: 'static>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T> {
38 let app = self.app();
39 let mut app = app.borrow_mut();
40 app.new(build_entity)
41 }
42
43 fn reserve_entity<T: 'static>(&mut self) -> Reservation<T> {
44 let app = self.app();
45 let mut app = app.borrow_mut();
46 app.reserve_entity()
47 }
48
49 fn insert_entity<T: 'static>(
50 &mut self,
51 reservation: Reservation<T>,
52 build_entity: impl FnOnce(&mut Context<T>) -> T,
53 ) -> Entity<T> {
54 let app = self.app();
55 let mut app = app.borrow_mut();
56 app.insert_entity(reservation, build_entity)
57 }
58
59 #[inline(always)]
60 fn update_entity<T: 'static, R>(
61 &mut self,
62 handle: &Entity<T>,
63 update: impl FnOnce(&mut T, &mut Context<T>) -> R,
64 ) -> R {
65 let app = self.app();
66 let mut app = app.borrow_mut();
67 app.update_entity(handle, update)
68 }
69
70 fn as_mut<'a, T>(&'a mut self, _handle: &Entity<T>) -> GpuiBorrow<'a, T>
71 where
72 T: 'static,
73 {
74 panic!("Cannot as_mut with an async context. Try calling update() first")
75 }
76
77 #[inline(always)]
78 fn read_entity<T, R>(&self, handle: &Entity<T>, callback: impl FnOnce(&T, &App) -> R) -> R
79 where
80 T: 'static,
81 {
82 let app = self.app();
83 let lock = app.borrow();
84 lock.read_entity(handle, callback)
85 }
86
87 #[inline(always)]
88 fn update_window<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Result<T>
89 where
90 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
91 {
92 let app = self.app.upgrade().context("app was released")?;
93 let mut lock = app.try_borrow_mut()?;
94 if lock.quitting {
95 bail!("app is quitting");
96 }
97 lock.update_window(window, f)
98 }
99
100 #[inline(always)]
101 fn with_window<R>(
102 &mut self,
103 entity_id: EntityId,
104 f: impl FnOnce(&mut Window, &mut App) -> R,
105 ) -> Option<R> {
106 let app = self.app.upgrade()?;
107 let mut lock = app.try_borrow_mut().ok()?;
108 if lock.quitting {
109 return None;
110 }
111 lock.with_window(entity_id, f)
112 }
113
114 fn read_window<T, R>(
115 &self,
116 window: &WindowHandle<T>,
117 read: impl FnOnce(Entity<T>, &App) -> R,
118 ) -> Result<R>
119 where
120 T: 'static,
121 {
122 let app = self.app.upgrade().context("app was released")?;
123 let lock = app.borrow();
124 if lock.quitting {
125 bail!("app is quitting");
126 }
127 lock.read_window(window, read)
128 }
129
130 #[track_caller]
131 fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
132 where
133 R: Send + 'static,
134 {
135 self.background_executor.spawn(future)
136 }
137
138 fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> R
139 where
140 G: Global,
141 {
142 let app = self.app();
143 let mut lock = app.borrow_mut();
144 lock.update(|this| this.read_global(callback))
145 }
146}
147
148impl AsyncApp {
149 pub fn refresh(&self) {
151 let app = self.app();
152 let mut lock = app.borrow_mut();
153 lock.update(|cx| cx.refresh_windows());
156 }
157
158 pub fn background_executor(&self) -> &BackgroundExecutor {
160 &self.background_executor
161 }
162
163 pub fn foreground_executor(&self) -> &ForegroundExecutor {
165 &self.foreground_executor
166 }
167
168 #[inline(always)]
170 pub fn update<R>(&self, f: impl FnOnce(&mut App) -> R) -> R {
171 let app = self.app();
172 let mut lock = app.borrow_mut();
173 lock.update(f)
174 }
175
176 pub fn subscribe<T, Event>(
179 &mut self,
180 entity: &Entity<T>,
181 on_event: impl FnMut(Entity<T>, &Event, &mut App) + 'static,
182 ) -> Subscription
183 where
184 T: 'static + EventEmitter<Event>,
185 Event: 'static,
186 {
187 let app = self.app();
188 let mut lock = app.borrow_mut();
189 lock.subscribe(entity, on_event)
190 }
191
192 pub fn open_window<V>(
194 &self,
195 options: crate::WindowOptions,
196 build_root_view: impl FnOnce(&mut Window, &mut App) -> Entity<V>,
197 ) -> Result<WindowHandle<V>>
198 where
199 V: 'static + Render,
200 {
201 let app = self.app();
202 let mut lock = app.borrow_mut();
203 if lock.quitting {
204 bail!("app is quitting");
205 }
206 lock.open_window(options, build_root_view)
207 }
208
209 #[track_caller]
211 #[inline(always)]
212 pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
213 where
214 AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
215 R: 'static,
216 {
217 let mut cx = self.clone();
218 self.foreground_executor
219 .spawn(async move { f(&mut cx).await }.boxed_local())
220 }
221
222 pub fn has_global<G: Global>(&self) -> bool {
224 let app = self.app();
225 let app = app.borrow_mut();
226 app.has_global::<G>()
227 }
228
229 #[inline(always)]
233 pub fn read_global<G: Global, R>(&self, read: impl FnOnce(&G, &App) -> R) -> R {
234 let app = self.app();
235 let app = app.borrow_mut();
236 read(app.global(), &app)
237 }
238
239 pub fn try_read_global<G: Global, R>(&self, read: impl FnOnce(&G, &App) -> R) -> Option<R> {
243 let app = self.app();
244 let app = app.borrow_mut();
245 if app.quitting {
246 return None;
247 }
248 Some(read(app.try_global()?, &app))
249 }
250
251 pub fn read_default_global<G: Global + Default, R>(
254 &self,
255 read: impl FnOnce(&G, &App) -> R,
256 ) -> R {
257 let app = self.app();
258 let mut app = app.borrow_mut();
259 app.update(|cx| {
260 cx.default_global::<G>();
261 });
262 read(app.global(), &app)
263 }
264
265 pub fn update_global<G: Global, R>(&self, update: impl FnOnce(&mut G, &mut App) -> R) -> R {
268 let app = self.app();
269 let mut app = app.borrow_mut();
270 app.update(|cx| cx.update_global(update))
271 }
272
273 pub fn on_drop<T: 'static, Callback: FnOnce(&mut T, &mut Context<T>) + 'static>(
275 &self,
276 entity: &WeakEntity<T>,
277 f: Callback,
278 ) -> gpui_util::Deferred<impl FnOnce() + use<T, Callback>> {
279 let entity = entity.clone();
280 let mut cx = self.clone();
281 gpui_util::defer(move || {
282 entity.update(&mut cx, f).ok();
283 })
284 }
285}
286
287#[derive(Clone, Deref, DerefMut)]
290pub struct AsyncWindowContext {
291 #[deref]
292 #[deref_mut]
293 app: AsyncApp,
294 window: AnyWindowHandle,
295}
296
297impl AsyncWindowContext {
298 pub(crate) fn new_context(app: AsyncApp, window: AnyWindowHandle) -> Self {
299 Self { app, window }
300 }
301
302 pub fn window_handle(&self) -> AnyWindowHandle {
304 self.window
305 }
306
307 #[inline(always)]
309 pub fn update<R>(&mut self, update: impl FnOnce(&mut Window, &mut App) -> R) -> Result<R> {
310 self.app
311 .update_window(self.window, |_, window, cx| update(window, cx))
312 }
313
314 #[inline(always)]
316 pub fn update_root<R>(
317 &mut self,
318 update: impl FnOnce(AnyView, &mut Window, &mut App) -> R,
319 ) -> Result<R> {
320 self.app.update_window(self.window, update)
321 }
322
323 pub fn on_next_frame(&mut self, f: impl FnOnce(&mut Window, &mut App) + 'static) {
325 self.app
326 .update_window(self.window, |_, window, _| window.on_next_frame(f))
327 .ok();
328 }
329
330 pub fn read_global<G: Global, R>(
332 &mut self,
333 read: impl FnOnce(&G, &Window, &App) -> R,
334 ) -> Result<R> {
335 self.app
336 .update_window(self.window, |_, window, cx| read(cx.global(), window, cx))
337 }
338
339 pub fn update_global<G, R>(
342 &mut self,
343 update: impl FnOnce(&mut G, &mut Window, &mut App) -> R,
344 ) -> Result<R>
345 where
346 G: Global,
347 {
348 self.app.update_window(self.window, |_, window, cx| {
349 cx.update_global(|global, cx| update(global, window, cx))
350 })
351 }
352
353 #[track_caller]
356 #[inline(always)]
357 pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
358 where
359 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
360 R: 'static,
361 {
362 let mut cx = self.clone();
363 self.foreground_executor
364 .spawn(async move { f(&mut cx).await }.boxed_local())
365 }
366
367 pub fn prompt<T>(
371 &mut self,
372 level: PromptLevel,
373 message: &str,
374 detail: Option<&str>,
375 answers: &[T],
376 ) -> oneshot::Receiver<usize>
377 where
378 T: Clone + Into<PromptButton>,
379 {
380 self.app
381 .update_window(self.window, |_, window, cx| {
382 window.prompt(level, message, detail, answers, cx)
383 })
384 .unwrap_or_else(|_| oneshot::channel().1)
385 }
386}
387
388impl AppContext for AsyncWindowContext {
389 fn new<T>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T>
390 where
391 T: 'static,
392 {
393 let mut build_entity = Some(build_entity);
394 match self.app.update_window(self.window, |_, _, cx| {
395 cx.new(
396 build_entity
397 .take()
398 .expect("build_entity is taken exactly once"),
399 )
400 }) {
401 Ok(entity) => entity,
402 Err(_) => self.app.new(
403 build_entity
404 .take()
405 .expect("update_window returned Err without invoking the closure"),
406 ),
407 }
408 }
409
410 fn reserve_entity<T: 'static>(&mut self) -> Reservation<T> {
411 self.app.reserve_entity()
412 }
413
414 fn insert_entity<T: 'static>(
415 &mut self,
416 reservation: Reservation<T>,
417 build_entity: impl FnOnce(&mut Context<T>) -> T,
418 ) -> Entity<T> {
419 let mut args = Some((reservation, build_entity));
420 match self.app.update_window(self.window, |_, _, cx| {
421 let (reservation, build_entity) = args.take().expect("args are taken exactly once");
422 cx.insert_entity(reservation, build_entity)
423 }) {
424 Ok(entity) => entity,
425 Err(_) => {
426 let (reservation, build_entity) = args
427 .take()
428 .expect("update_window returned Err without invoking the closure");
429 self.app.insert_entity(reservation, build_entity)
430 }
431 }
432 }
433
434 #[inline(always)]
435 fn update_entity<T: 'static, R>(
436 &mut self,
437 handle: &Entity<T>,
438 update: impl FnOnce(&mut T, &mut Context<T>) -> R,
439 ) -> R {
440 self.app.update_entity(handle, update)
441 }
442
443 fn as_mut<'a, T>(&'a mut self, _: &Entity<T>) -> GpuiBorrow<'a, T>
444 where
445 T: 'static,
446 {
447 panic!("Cannot use as_mut() from an async context, call `update`")
448 }
449
450 #[inline(always)]
451 fn read_entity<T, R>(&self, handle: &Entity<T>, read: impl FnOnce(&T, &App) -> R) -> R
452 where
453 T: 'static,
454 {
455 self.app.read_entity(handle, read)
456 }
457
458 #[inline(always)]
459 fn update_window<T, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<T>
460 where
461 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
462 {
463 self.app.update_window(window, update)
464 }
465
466 #[inline(always)]
467 fn with_window<R>(
468 &mut self,
469 entity_id: EntityId,
470 f: impl FnOnce(&mut Window, &mut App) -> R,
471 ) -> Option<R> {
472 self.app.with_window(entity_id, f)
473 }
474
475 fn read_window<T, R>(
476 &self,
477 window: &WindowHandle<T>,
478 read: impl FnOnce(Entity<T>, &App) -> R,
479 ) -> Result<R>
480 where
481 T: 'static,
482 {
483 self.app.read_window(window, read)
484 }
485
486 #[track_caller]
487 fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
488 where
489 R: Send + 'static,
490 {
491 self.app.background_executor.spawn(future)
492 }
493
494 fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> R
495 where
496 G: Global,
497 {
498 self.app.read_global(callback)
499 }
500}
501
502impl VisualContext for AsyncWindowContext {
503 type Result<T> = Result<T>;
504
505 fn window_handle(&self) -> AnyWindowHandle {
506 self.window
507 }
508
509 fn new_window_entity<T: 'static>(
510 &mut self,
511 build_entity: impl FnOnce(&mut Window, &mut Context<T>) -> T,
512 ) -> Result<Entity<T>> {
513 self.app.update_window(self.window, |_, window, cx| {
514 cx.new(|cx| build_entity(window, cx))
515 })
516 }
517
518 fn update_window_entity<T: 'static, R>(
519 &mut self,
520 view: &Entity<T>,
521 update: impl FnOnce(&mut T, &mut Window, &mut Context<T>) -> R,
522 ) -> Result<R> {
523 let view = view.clone();
524 self.app
525 .with_window(view.entity_id(), |window, app| {
526 view.update(app, |entity, cx| update(entity, window, cx))
527 })
528 .context("entity has no current window")
529 }
530
531 fn replace_root_view<V>(
532 &mut self,
533 build_view: impl FnOnce(&mut Window, &mut Context<V>) -> V,
534 ) -> Result<Entity<V>>
535 where
536 V: 'static + Render,
537 {
538 self.app.update_window(self.window, |_, window, cx| {
539 window.replace_root(cx, build_view)
540 })
541 }
542
543 fn focus<V>(&mut self, view: &Entity<V>) -> Result<()>
544 where
545 V: Focusable,
546 {
547 self.app.update_window(self.window, |_, window, cx| {
548 view.read(cx).focus_handle(cx).focus(window, cx);
549 })
550 }
551}