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 is_test(&self) -> bool {
166 self.background_executor.is_test()
167 }
168
169 pub fn foreground_executor(&self) -> &ForegroundExecutor {
171 &self.foreground_executor
172 }
173
174 #[inline(always)]
176 pub fn update<R>(&self, f: impl FnOnce(&mut App) -> R) -> R {
177 let app = self.app();
178 let mut lock = app.borrow_mut();
179 lock.update(f)
180 }
181
182 pub fn subscribe<T, Event>(
185 &mut self,
186 entity: &Entity<T>,
187 on_event: impl FnMut(Entity<T>, &Event, &mut App) + 'static,
188 ) -> Subscription
189 where
190 T: 'static + EventEmitter<Event>,
191 Event: 'static,
192 {
193 let app = self.app();
194 let mut lock = app.borrow_mut();
195 lock.subscribe(entity, on_event)
196 }
197
198 pub fn open_window<V>(
200 &self,
201 options: crate::WindowOptions,
202 build_root_view: impl FnOnce(&mut Window, &mut App) -> Entity<V>,
203 ) -> Result<WindowHandle<V>>
204 where
205 V: 'static + Render,
206 {
207 let app = self.app();
208 let mut lock = app.borrow_mut();
209 if lock.quitting {
210 bail!("app is quitting");
211 }
212 lock.open_window(options, build_root_view)
213 }
214
215 #[track_caller]
217 #[inline(always)]
218 pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
219 where
220 AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
221 R: 'static,
222 {
223 let mut cx = self.clone();
224 self.foreground_executor
225 .spawn(async move { f(&mut cx).await }.boxed_local())
226 }
227
228 pub fn has_global<G: Global>(&self) -> bool {
230 let app = self.app();
231 let app = app.borrow_mut();
232 app.has_global::<G>()
233 }
234
235 #[inline(always)]
239 pub fn read_global<G: Global, R>(&self, read: impl FnOnce(&G, &App) -> R) -> R {
240 let app = self.app();
241 let app = app.borrow_mut();
242 read(app.global(), &app)
243 }
244
245 pub fn try_read_global<G: Global, R>(&self, read: impl FnOnce(&G, &App) -> R) -> Option<R> {
249 let app = self.app();
250 let app = app.borrow_mut();
251 if app.quitting {
252 return None;
253 }
254 Some(read(app.try_global()?, &app))
255 }
256
257 pub fn read_default_global<G: Global + Default, R>(
260 &self,
261 read: impl FnOnce(&G, &App) -> R,
262 ) -> R {
263 let app = self.app();
264 let mut app = app.borrow_mut();
265 app.update(|cx| {
266 cx.default_global::<G>();
267 });
268 read(app.global(), &app)
269 }
270
271 pub fn update_global<G: Global, R>(&self, update: impl FnOnce(&mut G, &mut App) -> R) -> R {
274 let app = self.app();
275 let mut app = app.borrow_mut();
276 app.update(|cx| cx.update_global(update))
277 }
278
279 pub fn on_drop<T: 'static, Callback: FnOnce(&mut T, &mut Context<T>) + 'static>(
281 &self,
282 entity: &WeakEntity<T>,
283 f: Callback,
284 ) -> gpui_util::Deferred<impl FnOnce() + use<T, Callback>> {
285 let entity = entity.clone();
286 let mut cx = self.clone();
287 gpui_util::defer(move || {
288 entity.update(&mut cx, f).ok();
289 })
290 }
291}
292
293#[derive(Clone, Deref, DerefMut)]
296pub struct AsyncWindowContext {
297 #[deref]
298 #[deref_mut]
299 app: AsyncApp,
300 window: AnyWindowHandle,
301}
302
303impl AsyncWindowContext {
304 pub(crate) fn new_context(app: AsyncApp, window: AnyWindowHandle) -> Self {
305 Self { app, window }
306 }
307
308 pub fn window_handle(&self) -> AnyWindowHandle {
310 self.window
311 }
312
313 #[inline(always)]
315 pub fn update<R>(&mut self, update: impl FnOnce(&mut Window, &mut App) -> R) -> Result<R> {
316 self.app
317 .update_window(self.window, |_, window, cx| update(window, cx))
318 }
319
320 #[inline(always)]
322 pub fn update_root<R>(
323 &mut self,
324 update: impl FnOnce(AnyView, &mut Window, &mut App) -> R,
325 ) -> Result<R> {
326 self.app.update_window(self.window, update)
327 }
328
329 pub fn on_next_frame(&mut self, f: impl FnOnce(&mut Window, &mut App) + 'static) {
331 self.app
332 .update_window(self.window, |_, window, _| window.on_next_frame(f))
333 .ok();
334 }
335
336 pub fn read_global<G: Global, R>(
338 &mut self,
339 read: impl FnOnce(&G, &Window, &App) -> R,
340 ) -> Result<R> {
341 self.app
342 .update_window(self.window, |_, window, cx| read(cx.global(), window, cx))
343 }
344
345 pub fn update_global<G, R>(
348 &mut self,
349 update: impl FnOnce(&mut G, &mut Window, &mut App) -> R,
350 ) -> Result<R>
351 where
352 G: Global,
353 {
354 self.app.update_window(self.window, |_, window, cx| {
355 cx.update_global(|global, cx| update(global, window, cx))
356 })
357 }
358
359 #[track_caller]
362 #[inline(always)]
363 pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
364 where
365 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
366 R: 'static,
367 {
368 let mut cx = self.clone();
369 self.foreground_executor
370 .spawn(async move { f(&mut cx).await }.boxed_local())
371 }
372
373 pub fn prompt<T>(
377 &mut self,
378 level: PromptLevel,
379 message: &str,
380 detail: Option<&str>,
381 answers: &[T],
382 ) -> oneshot::Receiver<usize>
383 where
384 T: Clone + Into<PromptButton>,
385 {
386 self.app
387 .update_window(self.window, |_, window, cx| {
388 window.prompt(level, message, detail, answers, cx)
389 })
390 .unwrap_or_else(|_| oneshot::channel().1)
391 }
392}
393
394impl AppContext for AsyncWindowContext {
395 fn new<T>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T>
396 where
397 T: 'static,
398 {
399 let mut build_entity = Some(build_entity);
400 match self.app.update_window(self.window, |_, _, cx| {
401 cx.new(
402 build_entity
403 .take()
404 .expect("build_entity is taken exactly once"),
405 )
406 }) {
407 Ok(entity) => entity,
408 Err(_) => self.app.new(
409 build_entity
410 .take()
411 .expect("update_window returned Err without invoking the closure"),
412 ),
413 }
414 }
415
416 fn reserve_entity<T: 'static>(&mut self) -> Reservation<T> {
417 self.app.reserve_entity()
418 }
419
420 fn insert_entity<T: 'static>(
421 &mut self,
422 reservation: Reservation<T>,
423 build_entity: impl FnOnce(&mut Context<T>) -> T,
424 ) -> Entity<T> {
425 let mut args = Some((reservation, build_entity));
426 match self.app.update_window(self.window, |_, _, cx| {
427 let (reservation, build_entity) = args.take().expect("args are taken exactly once");
428 cx.insert_entity(reservation, build_entity)
429 }) {
430 Ok(entity) => entity,
431 Err(_) => {
432 let (reservation, build_entity) = args
433 .take()
434 .expect("update_window returned Err without invoking the closure");
435 self.app.insert_entity(reservation, build_entity)
436 }
437 }
438 }
439
440 #[inline(always)]
441 fn update_entity<T: 'static, R>(
442 &mut self,
443 handle: &Entity<T>,
444 update: impl FnOnce(&mut T, &mut Context<T>) -> R,
445 ) -> R {
446 self.app.update_entity(handle, update)
447 }
448
449 fn as_mut<'a, T>(&'a mut self, _: &Entity<T>) -> GpuiBorrow<'a, T>
450 where
451 T: 'static,
452 {
453 panic!("Cannot use as_mut() from an async context, call `update`")
454 }
455
456 #[inline(always)]
457 fn read_entity<T, R>(&self, handle: &Entity<T>, read: impl FnOnce(&T, &App) -> R) -> R
458 where
459 T: 'static,
460 {
461 self.app.read_entity(handle, read)
462 }
463
464 #[inline(always)]
465 fn update_window<T, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<T>
466 where
467 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
468 {
469 self.app.update_window(window, update)
470 }
471
472 #[inline(always)]
473 fn with_window<R>(
474 &mut self,
475 entity_id: EntityId,
476 f: impl FnOnce(&mut Window, &mut App) -> R,
477 ) -> Option<R> {
478 self.app.with_window(entity_id, f)
479 }
480
481 fn read_window<T, R>(
482 &self,
483 window: &WindowHandle<T>,
484 read: impl FnOnce(Entity<T>, &App) -> R,
485 ) -> Result<R>
486 where
487 T: 'static,
488 {
489 self.app.read_window(window, read)
490 }
491
492 #[track_caller]
493 fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
494 where
495 R: Send + 'static,
496 {
497 self.app.background_executor.spawn(future)
498 }
499
500 fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> R
501 where
502 G: Global,
503 {
504 self.app.read_global(callback)
505 }
506}
507
508impl VisualContext for AsyncWindowContext {
509 type Result<T> = Result<T>;
510
511 fn window_handle(&self) -> AnyWindowHandle {
512 self.window
513 }
514
515 fn new_window_entity<T: 'static>(
516 &mut self,
517 build_entity: impl FnOnce(&mut Window, &mut Context<T>) -> T,
518 ) -> Result<Entity<T>> {
519 self.app.update_window(self.window, |_, window, cx| {
520 cx.new(|cx| build_entity(window, cx))
521 })
522 }
523
524 fn update_window_entity<T: 'static, R>(
525 &mut self,
526 view: &Entity<T>,
527 update: impl FnOnce(&mut T, &mut Window, &mut Context<T>) -> R,
528 ) -> Result<R> {
529 let view = view.clone();
530 self.app
531 .with_window(view.entity_id(), |window, app| {
532 view.update(app, |entity, cx| update(entity, window, cx))
533 })
534 .context("entity has no current window")
535 }
536
537 fn replace_root_view<V>(
538 &mut self,
539 build_view: impl FnOnce(&mut Window, &mut Context<V>) -> V,
540 ) -> Result<Entity<V>>
541 where
542 V: 'static + Render,
543 {
544 self.app.update_window(self.window, |_, window, cx| {
545 window.replace_root(cx, build_view)
546 })
547 }
548
549 fn focus<V>(&mut self, view: &Entity<V>) -> Result<()>
550 where
551 V: Focusable,
552 {
553 self.app.update_window(self.window, |_, window, cx| {
554 view.read(cx).focus_handle(cx).focus(window, cx);
555 })
556 }
557}