1use crate::{
2 elements::ElementBox,
3 executor::{self, Task},
4 keymap::{self, Keystroke},
5 platform::{self, CursorStyle, Platform, PromptLevel, WindowOptions},
6 presenter::Presenter,
7 util::{post_inc, timeout},
8 AssetCache, AssetSource, ClipboardItem, FontCache, PathPromptOptions, TextLayoutCache,
9};
10use anyhow::{anyhow, Result};
11use keymap::MatchResult;
12use parking_lot::Mutex;
13use platform::Event;
14use postage::{mpsc, oneshot, sink::Sink as _, stream::Stream as _};
15use smol::prelude::*;
16use std::{
17 any::{type_name, Any, TypeId},
18 cell::RefCell,
19 collections::{hash_map::Entry, BTreeMap, HashMap, HashSet, VecDeque},
20 fmt::{self, Debug},
21 hash::{Hash, Hasher},
22 marker::PhantomData,
23 mem,
24 ops::{Deref, DerefMut},
25 path::{Path, PathBuf},
26 pin::Pin,
27 rc::{self, Rc},
28 sync::{
29 atomic::{AtomicUsize, Ordering::SeqCst},
30 Arc, Weak,
31 },
32 time::Duration,
33};
34
35pub trait Entity: 'static {
36 type Event;
37
38 fn release(&mut self, _: &mut MutableAppContext) {}
39 fn app_will_quit(
40 &mut self,
41 _: &mut MutableAppContext,
42 ) -> Option<Pin<Box<dyn 'static + Future<Output = ()>>>> {
43 None
44 }
45}
46
47pub trait View: Entity + Sized {
48 fn ui_name() -> &'static str;
49 fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox;
50 fn on_focus(&mut self, _: &mut ViewContext<Self>) {}
51 fn on_blur(&mut self, _: &mut ViewContext<Self>) {}
52 fn keymap_context(&self, _: &AppContext) -> keymap::Context {
53 Self::default_keymap_context()
54 }
55 fn default_keymap_context() -> keymap::Context {
56 let mut cx = keymap::Context::default();
57 cx.set.insert(Self::ui_name().into());
58 cx
59 }
60}
61
62pub trait ReadModel {
63 fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T;
64}
65
66pub trait ReadModelWith {
67 fn read_model_with<E: Entity, T>(
68 &self,
69 handle: &ModelHandle<E>,
70 read: &mut dyn FnMut(&E, &AppContext) -> T,
71 ) -> T;
72}
73
74pub trait UpdateModel {
75 fn update_model<T: Entity, O>(
76 &mut self,
77 handle: &ModelHandle<T>,
78 update: &mut dyn FnMut(&mut T, &mut ModelContext<T>) -> O,
79 ) -> O;
80}
81
82pub trait UpgradeModelHandle {
83 fn upgrade_model_handle<T: Entity>(
84 &self,
85 handle: &WeakModelHandle<T>,
86 ) -> Option<ModelHandle<T>>;
87
88 fn upgrade_any_model_handle(&self, handle: &AnyWeakModelHandle) -> Option<AnyModelHandle>;
89}
90
91pub trait UpgradeViewHandle {
92 fn upgrade_view_handle<T: View>(&self, handle: &WeakViewHandle<T>) -> Option<ViewHandle<T>>;
93}
94
95pub trait ReadView {
96 fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T;
97}
98
99pub trait ReadViewWith {
100 fn read_view_with<V, T>(
101 &self,
102 handle: &ViewHandle<V>,
103 read: &mut dyn FnMut(&V, &AppContext) -> T,
104 ) -> T
105 where
106 V: View;
107}
108
109pub trait UpdateView {
110 fn update_view<T, S>(
111 &mut self,
112 handle: &ViewHandle<T>,
113 update: &mut dyn FnMut(&mut T, &mut ViewContext<T>) -> S,
114 ) -> S
115 where
116 T: View;
117}
118
119pub trait ElementStateContext: DerefMut<Target = MutableAppContext> {
120 fn current_view_id(&self) -> usize;
121
122 fn element_state<Tag: 'static, T: 'static + Default>(
123 &mut self,
124 element_id: usize,
125 ) -> ElementStateHandle<T> {
126 let id = ElementStateId {
127 view_id: self.current_view_id(),
128 element_id,
129 tag: TypeId::of::<Tag>(),
130 };
131 self.cx
132 .element_states
133 .entry(id)
134 .or_insert_with(|| Box::new(T::default()));
135 ElementStateHandle::new(id, self.frame_count, &self.cx.ref_counts)
136 }
137}
138
139pub trait Action: 'static + AnyAction {
140 type Argument: 'static + Clone;
141}
142
143pub trait AnyAction {
144 fn id(&self) -> TypeId;
145 fn name(&self) -> &'static str;
146 fn as_any(&self) -> &dyn Any;
147 fn boxed_clone(&self) -> Box<dyn AnyAction>;
148 fn boxed_clone_as_any(&self) -> Box<dyn Any>;
149}
150
151#[macro_export]
152macro_rules! action {
153 ($name:ident, $arg:ty) => {
154 #[derive(Clone)]
155 pub struct $name(pub $arg);
156
157 impl $crate::Action for $name {
158 type Argument = $arg;
159 }
160
161 impl $crate::AnyAction for $name {
162 fn id(&self) -> std::any::TypeId {
163 std::any::TypeId::of::<$name>()
164 }
165
166 fn name(&self) -> &'static str {
167 stringify!($name)
168 }
169
170 fn as_any(&self) -> &dyn std::any::Any {
171 self
172 }
173
174 fn boxed_clone(&self) -> Box<dyn $crate::AnyAction> {
175 Box::new(self.clone())
176 }
177
178 fn boxed_clone_as_any(&self) -> Box<dyn std::any::Any> {
179 Box::new(self.clone())
180 }
181 }
182 };
183
184 ($name:ident) => {
185 #[derive(Clone, Debug, Eq, PartialEq)]
186 pub struct $name;
187
188 impl $crate::Action for $name {
189 type Argument = ();
190 }
191
192 impl $crate::AnyAction for $name {
193 fn id(&self) -> std::any::TypeId {
194 std::any::TypeId::of::<$name>()
195 }
196
197 fn name(&self) -> &'static str {
198 stringify!($name)
199 }
200
201 fn as_any(&self) -> &dyn std::any::Any {
202 self
203 }
204
205 fn boxed_clone(&self) -> Box<dyn $crate::AnyAction> {
206 Box::new(self.clone())
207 }
208
209 fn boxed_clone_as_any(&self) -> Box<dyn std::any::Any> {
210 Box::new(self.clone())
211 }
212 }
213 };
214}
215
216pub struct Menu<'a> {
217 pub name: &'a str,
218 pub items: Vec<MenuItem<'a>>,
219}
220
221pub enum MenuItem<'a> {
222 Action {
223 name: &'a str,
224 keystroke: Option<&'a str>,
225 action: Box<dyn AnyAction>,
226 },
227 Separator,
228}
229
230#[derive(Clone)]
231pub struct App(Rc<RefCell<MutableAppContext>>);
232
233#[derive(Clone)]
234pub struct AsyncAppContext(Rc<RefCell<MutableAppContext>>);
235
236#[derive(Clone)]
237pub struct TestAppContext {
238 cx: Rc<RefCell<MutableAppContext>>,
239 foreground_platform: Rc<platform::test::ForegroundPlatform>,
240}
241
242impl App {
243 pub fn new(asset_source: impl AssetSource) -> Result<Self> {
244 let platform = platform::current::platform();
245 let foreground_platform = platform::current::foreground_platform();
246 let foreground = Rc::new(executor::Foreground::platform(platform.dispatcher())?);
247 let app = Self(Rc::new(RefCell::new(MutableAppContext::new(
248 foreground,
249 Arc::new(executor::Background::new()),
250 platform.clone(),
251 foreground_platform.clone(),
252 Arc::new(FontCache::new(platform.fonts())),
253 asset_source,
254 ))));
255
256 foreground_platform.on_quit(Box::new({
257 let cx = app.0.clone();
258 move || {
259 cx.borrow_mut().quit();
260 }
261 }));
262 foreground_platform.on_menu_command(Box::new({
263 let cx = app.0.clone();
264 move |action| {
265 let mut cx = cx.borrow_mut();
266 if let Some(key_window_id) = cx.cx.platform.key_window_id() {
267 if let Some((presenter, _)) =
268 cx.presenters_and_platform_windows.get(&key_window_id)
269 {
270 let presenter = presenter.clone();
271 let path = presenter.borrow().dispatch_path(cx.as_ref());
272 cx.dispatch_action_any(key_window_id, &path, action);
273 } else {
274 cx.dispatch_global_action_any(action);
275 }
276 } else {
277 cx.dispatch_global_action_any(action);
278 }
279 }
280 }));
281
282 app.0.borrow_mut().weak_self = Some(Rc::downgrade(&app.0));
283 Ok(app)
284 }
285
286 pub fn on_become_active<F>(self, mut callback: F) -> Self
287 where
288 F: 'static + FnMut(&mut MutableAppContext),
289 {
290 let cx = self.0.clone();
291 self.0
292 .borrow_mut()
293 .foreground_platform
294 .on_become_active(Box::new(move || callback(&mut *cx.borrow_mut())));
295 self
296 }
297
298 pub fn on_resign_active<F>(self, mut callback: F) -> Self
299 where
300 F: 'static + FnMut(&mut MutableAppContext),
301 {
302 let cx = self.0.clone();
303 self.0
304 .borrow_mut()
305 .foreground_platform
306 .on_resign_active(Box::new(move || callback(&mut *cx.borrow_mut())));
307 self
308 }
309
310 pub fn on_quit<F>(self, mut callback: F) -> Self
311 where
312 F: 'static + FnMut(&mut MutableAppContext),
313 {
314 let cx = self.0.clone();
315 self.0
316 .borrow_mut()
317 .foreground_platform
318 .on_quit(Box::new(move || callback(&mut *cx.borrow_mut())));
319 self
320 }
321
322 pub fn on_event<F>(self, mut callback: F) -> Self
323 where
324 F: 'static + FnMut(Event, &mut MutableAppContext) -> bool,
325 {
326 let cx = self.0.clone();
327 self.0
328 .borrow_mut()
329 .foreground_platform
330 .on_event(Box::new(move |event| {
331 callback(event, &mut *cx.borrow_mut())
332 }));
333 self
334 }
335
336 pub fn on_open_files<F>(self, mut callback: F) -> Self
337 where
338 F: 'static + FnMut(Vec<PathBuf>, &mut MutableAppContext),
339 {
340 let cx = self.0.clone();
341 self.0
342 .borrow_mut()
343 .foreground_platform
344 .on_open_files(Box::new(move |paths| {
345 callback(paths, &mut *cx.borrow_mut())
346 }));
347 self
348 }
349
350 pub fn run<F>(self, on_finish_launching: F)
351 where
352 F: 'static + FnOnce(&mut MutableAppContext),
353 {
354 let platform = self.0.borrow().foreground_platform.clone();
355 platform.run(Box::new(move || {
356 let mut cx = self.0.borrow_mut();
357 let cx = &mut *cx;
358 crate::views::init(cx);
359 on_finish_launching(cx);
360 }))
361 }
362
363 pub fn platform(&self) -> Arc<dyn Platform> {
364 self.0.borrow().platform()
365 }
366
367 pub fn font_cache(&self) -> Arc<FontCache> {
368 self.0.borrow().cx.font_cache.clone()
369 }
370
371 fn update<T, F: FnOnce(&mut MutableAppContext) -> T>(&mut self, callback: F) -> T {
372 let mut state = self.0.borrow_mut();
373 let result = state.update(callback);
374 state.pending_notifications.clear();
375 result
376 }
377}
378
379impl TestAppContext {
380 pub fn new(
381 foreground_platform: Rc<platform::test::ForegroundPlatform>,
382 platform: Arc<dyn Platform>,
383 foreground: Rc<executor::Foreground>,
384 background: Arc<executor::Background>,
385 font_cache: Arc<FontCache>,
386 first_entity_id: usize,
387 ) -> Self {
388 let mut cx = MutableAppContext::new(
389 foreground.clone(),
390 background,
391 platform,
392 foreground_platform.clone(),
393 font_cache,
394 (),
395 );
396 cx.next_entity_id = first_entity_id;
397 let cx = TestAppContext {
398 cx: Rc::new(RefCell::new(cx)),
399 foreground_platform,
400 };
401 cx.cx.borrow_mut().weak_self = Some(Rc::downgrade(&cx.cx));
402 cx
403 }
404
405 pub fn dispatch_action<A: Action>(
406 &self,
407 window_id: usize,
408 responder_chain: Vec<usize>,
409 action: A,
410 ) {
411 self.cx
412 .borrow_mut()
413 .dispatch_action_any(window_id, &responder_chain, &action);
414 }
415
416 pub fn dispatch_global_action<A: Action>(&self, action: A) {
417 self.cx.borrow_mut().dispatch_global_action(action);
418 }
419
420 pub fn dispatch_keystroke(
421 &self,
422 window_id: usize,
423 responder_chain: Vec<usize>,
424 keystroke: &Keystroke,
425 ) -> Result<bool> {
426 let mut state = self.cx.borrow_mut();
427 state.dispatch_keystroke(window_id, responder_chain, keystroke)
428 }
429
430 pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
431 where
432 T: Entity,
433 F: FnOnce(&mut ModelContext<T>) -> T,
434 {
435 self.cx.borrow_mut().add_model(build_model)
436 }
437
438 pub fn add_window<T, F>(&mut self, build_root_view: F) -> (usize, ViewHandle<T>)
439 where
440 T: View,
441 F: FnOnce(&mut ViewContext<T>) -> T,
442 {
443 self.cx
444 .borrow_mut()
445 .add_window(Default::default(), build_root_view)
446 }
447
448 pub fn window_ids(&self) -> Vec<usize> {
449 self.cx.borrow().window_ids().collect()
450 }
451
452 pub fn root_view<T: View>(&self, window_id: usize) -> Option<ViewHandle<T>> {
453 self.cx.borrow().root_view(window_id)
454 }
455
456 pub fn add_view<T, F>(&mut self, window_id: usize, build_view: F) -> ViewHandle<T>
457 where
458 T: View,
459 F: FnOnce(&mut ViewContext<T>) -> T,
460 {
461 self.cx.borrow_mut().add_view(window_id, build_view)
462 }
463
464 pub fn add_option_view<T, F>(
465 &mut self,
466 window_id: usize,
467 build_view: F,
468 ) -> Option<ViewHandle<T>>
469 where
470 T: View,
471 F: FnOnce(&mut ViewContext<T>) -> Option<T>,
472 {
473 self.cx.borrow_mut().add_option_view(window_id, build_view)
474 }
475
476 pub fn read<T, F: FnOnce(&AppContext) -> T>(&self, callback: F) -> T {
477 callback(self.cx.borrow().as_ref())
478 }
479
480 pub fn update<T, F: FnOnce(&mut MutableAppContext) -> T>(&mut self, callback: F) -> T {
481 let mut state = self.cx.borrow_mut();
482 // Don't increment pending flushes in order to effects to be flushed before the callback
483 // completes, which is helpful in tests.
484 let result = callback(&mut *state);
485 // Flush effects after the callback just in case there are any. This can happen in edge
486 // cases such as the closure dropping handles.
487 state.flush_effects();
488 result
489 }
490
491 pub fn to_async(&self) -> AsyncAppContext {
492 AsyncAppContext(self.cx.clone())
493 }
494
495 pub fn font_cache(&self) -> Arc<FontCache> {
496 self.cx.borrow().cx.font_cache.clone()
497 }
498
499 pub fn foreground_platform(&self) -> Rc<platform::test::ForegroundPlatform> {
500 self.foreground_platform.clone()
501 }
502
503 pub fn platform(&self) -> Arc<dyn platform::Platform> {
504 self.cx.borrow().cx.platform.clone()
505 }
506
507 pub fn foreground(&self) -> Rc<executor::Foreground> {
508 self.cx.borrow().foreground().clone()
509 }
510
511 pub fn background(&self) -> Arc<executor::Background> {
512 self.cx.borrow().background().clone()
513 }
514
515 pub fn spawn<F, Fut, T>(&self, f: F) -> Task<T>
516 where
517 F: FnOnce(AsyncAppContext) -> Fut,
518 Fut: 'static + Future<Output = T>,
519 T: 'static,
520 {
521 self.cx.borrow_mut().spawn(f)
522 }
523
524 pub fn simulate_new_path_selection(&self, result: impl FnOnce(PathBuf) -> Option<PathBuf>) {
525 self.foreground_platform.simulate_new_path_selection(result);
526 }
527
528 pub fn did_prompt_for_new_path(&self) -> bool {
529 self.foreground_platform.as_ref().did_prompt_for_new_path()
530 }
531
532 pub fn simulate_prompt_answer(&self, window_id: usize, answer: usize) {
533 let mut state = self.cx.borrow_mut();
534 let (_, window) = state
535 .presenters_and_platform_windows
536 .get_mut(&window_id)
537 .unwrap();
538 let test_window = window
539 .as_any_mut()
540 .downcast_mut::<platform::test::Window>()
541 .unwrap();
542 let mut done_tx = test_window
543 .last_prompt
544 .take()
545 .expect("prompt was not called");
546 let _ = done_tx.try_send(answer);
547 }
548}
549
550impl AsyncAppContext {
551 pub fn spawn<F, Fut, T>(&self, f: F) -> Task<T>
552 where
553 F: FnOnce(AsyncAppContext) -> Fut,
554 Fut: 'static + Future<Output = T>,
555 T: 'static,
556 {
557 self.0.borrow().foreground.spawn(f(self.clone()))
558 }
559
560 pub fn read<T, F: FnOnce(&AppContext) -> T>(&mut self, callback: F) -> T {
561 callback(self.0.borrow().as_ref())
562 }
563
564 pub fn update<T, F: FnOnce(&mut MutableAppContext) -> T>(&mut self, callback: F) -> T {
565 self.0.borrow_mut().update(callback)
566 }
567
568 pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
569 where
570 T: Entity,
571 F: FnOnce(&mut ModelContext<T>) -> T,
572 {
573 self.update(|cx| cx.add_model(build_model))
574 }
575
576 pub fn platform(&self) -> Arc<dyn Platform> {
577 self.0.borrow().platform()
578 }
579
580 pub fn foreground(&self) -> Rc<executor::Foreground> {
581 self.0.borrow().foreground.clone()
582 }
583
584 pub fn background(&self) -> Arc<executor::Background> {
585 self.0.borrow().cx.background.clone()
586 }
587}
588
589impl UpdateModel for AsyncAppContext {
590 fn update_model<E: Entity, O>(
591 &mut self,
592 handle: &ModelHandle<E>,
593 update: &mut dyn FnMut(&mut E, &mut ModelContext<E>) -> O,
594 ) -> O {
595 self.0.borrow_mut().update_model(handle, update)
596 }
597}
598
599impl UpgradeModelHandle for AsyncAppContext {
600 fn upgrade_model_handle<T: Entity>(
601 &self,
602 handle: &WeakModelHandle<T>,
603 ) -> Option<ModelHandle<T>> {
604 self.0.borrow().upgrade_model_handle(handle)
605 }
606
607 fn upgrade_any_model_handle(&self, handle: &AnyWeakModelHandle) -> Option<AnyModelHandle> {
608 self.0.borrow().upgrade_any_model_handle(handle)
609 }
610}
611
612impl UpgradeViewHandle for AsyncAppContext {
613 fn upgrade_view_handle<T: View>(&self, handle: &WeakViewHandle<T>) -> Option<ViewHandle<T>> {
614 self.0.borrow_mut().upgrade_view_handle(handle)
615 }
616}
617
618impl ReadModelWith for AsyncAppContext {
619 fn read_model_with<E: Entity, T>(
620 &self,
621 handle: &ModelHandle<E>,
622 read: &mut dyn FnMut(&E, &AppContext) -> T,
623 ) -> T {
624 let cx = self.0.borrow();
625 let cx = cx.as_ref();
626 read(handle.read(cx), cx)
627 }
628}
629
630impl UpdateView for AsyncAppContext {
631 fn update_view<T, S>(
632 &mut self,
633 handle: &ViewHandle<T>,
634 update: &mut dyn FnMut(&mut T, &mut ViewContext<T>) -> S,
635 ) -> S
636 where
637 T: View,
638 {
639 self.0.borrow_mut().update_view(handle, update)
640 }
641}
642
643impl ReadViewWith for AsyncAppContext {
644 fn read_view_with<V, T>(
645 &self,
646 handle: &ViewHandle<V>,
647 read: &mut dyn FnMut(&V, &AppContext) -> T,
648 ) -> T
649 where
650 V: View,
651 {
652 let cx = self.0.borrow();
653 let cx = cx.as_ref();
654 read(handle.read(cx), cx)
655 }
656}
657
658impl UpdateModel for TestAppContext {
659 fn update_model<T: Entity, O>(
660 &mut self,
661 handle: &ModelHandle<T>,
662 update: &mut dyn FnMut(&mut T, &mut ModelContext<T>) -> O,
663 ) -> O {
664 self.cx.borrow_mut().update_model(handle, update)
665 }
666}
667
668impl ReadModelWith for TestAppContext {
669 fn read_model_with<E: Entity, T>(
670 &self,
671 handle: &ModelHandle<E>,
672 read: &mut dyn FnMut(&E, &AppContext) -> T,
673 ) -> T {
674 let cx = self.cx.borrow();
675 let cx = cx.as_ref();
676 read(handle.read(cx), cx)
677 }
678}
679
680impl UpdateView for TestAppContext {
681 fn update_view<T, S>(
682 &mut self,
683 handle: &ViewHandle<T>,
684 update: &mut dyn FnMut(&mut T, &mut ViewContext<T>) -> S,
685 ) -> S
686 where
687 T: View,
688 {
689 self.cx.borrow_mut().update_view(handle, update)
690 }
691}
692
693impl ReadViewWith for TestAppContext {
694 fn read_view_with<V, T>(
695 &self,
696 handle: &ViewHandle<V>,
697 read: &mut dyn FnMut(&V, &AppContext) -> T,
698 ) -> T
699 where
700 V: View,
701 {
702 let cx = self.cx.borrow();
703 let cx = cx.as_ref();
704 read(handle.read(cx), cx)
705 }
706}
707
708type ActionCallback =
709 dyn FnMut(&mut dyn AnyView, &dyn AnyAction, &mut MutableAppContext, usize, usize) -> bool;
710type GlobalActionCallback = dyn FnMut(&dyn AnyAction, &mut MutableAppContext);
711
712type SubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext) -> bool>;
713type ObservationCallback = Box<dyn FnMut(&mut MutableAppContext) -> bool>;
714type ReleaseObservationCallback = Box<dyn FnMut(&mut MutableAppContext)>;
715
716pub struct MutableAppContext {
717 weak_self: Option<rc::Weak<RefCell<Self>>>,
718 foreground_platform: Rc<dyn platform::ForegroundPlatform>,
719 assets: Arc<AssetCache>,
720 cx: AppContext,
721 actions: HashMap<TypeId, HashMap<TypeId, Vec<Box<ActionCallback>>>>,
722 global_actions: HashMap<TypeId, Box<GlobalActionCallback>>,
723 keystroke_matcher: keymap::Matcher,
724 next_entity_id: usize,
725 next_window_id: usize,
726 next_subscription_id: usize,
727 frame_count: usize,
728 subscriptions: Arc<Mutex<HashMap<usize, BTreeMap<usize, SubscriptionCallback>>>>,
729 observations: Arc<Mutex<HashMap<usize, BTreeMap<usize, ObservationCallback>>>>,
730 release_observations: Arc<Mutex<HashMap<usize, BTreeMap<usize, ReleaseObservationCallback>>>>,
731 presenters_and_platform_windows:
732 HashMap<usize, (Rc<RefCell<Presenter>>, Box<dyn platform::Window>)>,
733 debug_elements_callbacks: HashMap<usize, Box<dyn Fn(&AppContext) -> crate::json::Value>>,
734 foreground: Rc<executor::Foreground>,
735 pending_effects: VecDeque<Effect>,
736 pending_notifications: HashSet<usize>,
737 pending_flushes: usize,
738 flushing_effects: bool,
739 next_cursor_style_handle_id: Arc<AtomicUsize>,
740}
741
742impl MutableAppContext {
743 fn new(
744 foreground: Rc<executor::Foreground>,
745 background: Arc<executor::Background>,
746 platform: Arc<dyn platform::Platform>,
747 foreground_platform: Rc<dyn platform::ForegroundPlatform>,
748 font_cache: Arc<FontCache>,
749 asset_source: impl AssetSource,
750 // entity_drop_tx:
751 ) -> Self {
752 Self {
753 weak_self: None,
754 foreground_platform,
755 assets: Arc::new(AssetCache::new(asset_source)),
756 cx: AppContext {
757 models: Default::default(),
758 views: Default::default(),
759 windows: Default::default(),
760 element_states: Default::default(),
761 ref_counts: Arc::new(Mutex::new(RefCounts::default())),
762 background,
763 font_cache,
764 platform,
765 },
766 actions: HashMap::new(),
767 global_actions: HashMap::new(),
768 keystroke_matcher: keymap::Matcher::default(),
769 next_entity_id: 0,
770 next_window_id: 0,
771 next_subscription_id: 0,
772 frame_count: 0,
773 subscriptions: Default::default(),
774 observations: Default::default(),
775 release_observations: Default::default(),
776 presenters_and_platform_windows: HashMap::new(),
777 debug_elements_callbacks: HashMap::new(),
778 foreground,
779 pending_effects: VecDeque::new(),
780 pending_notifications: HashSet::new(),
781 pending_flushes: 0,
782 flushing_effects: false,
783 next_cursor_style_handle_id: Default::default(),
784 }
785 }
786
787 pub fn upgrade(&self) -> App {
788 App(self.weak_self.as_ref().unwrap().upgrade().unwrap())
789 }
790
791 pub fn quit(&mut self) {
792 let mut futures = Vec::new();
793 for model_id in self.cx.models.keys().copied().collect::<Vec<_>>() {
794 let mut model = self.cx.models.remove(&model_id).unwrap();
795 futures.extend(model.app_will_quit(self));
796 self.cx.models.insert(model_id, model);
797 }
798
799 for view_id in self.cx.views.keys().copied().collect::<Vec<_>>() {
800 let mut view = self.cx.views.remove(&view_id).unwrap();
801 futures.extend(view.app_will_quit(self));
802 self.cx.views.insert(view_id, view);
803 }
804
805 self.remove_all_windows();
806
807 let futures = futures::future::join_all(futures);
808 if self
809 .background
810 .block_with_timeout(Duration::from_millis(100), futures)
811 .is_err()
812 {
813 log::error!("timed out waiting on app_will_quit");
814 }
815 }
816
817 fn remove_all_windows(&mut self) {
818 for (window_id, _) in self.cx.windows.drain() {
819 self.presenters_and_platform_windows.remove(&window_id);
820 }
821 self.remove_dropped_entities();
822 }
823
824 pub fn platform(&self) -> Arc<dyn platform::Platform> {
825 self.cx.platform.clone()
826 }
827
828 pub fn font_cache(&self) -> &Arc<FontCache> {
829 &self.cx.font_cache
830 }
831
832 pub fn foreground(&self) -> &Rc<executor::Foreground> {
833 &self.foreground
834 }
835
836 pub fn background(&self) -> &Arc<executor::Background> {
837 &self.cx.background
838 }
839
840 pub fn on_debug_elements<F>(&mut self, window_id: usize, callback: F)
841 where
842 F: 'static + Fn(&AppContext) -> crate::json::Value,
843 {
844 self.debug_elements_callbacks
845 .insert(window_id, Box::new(callback));
846 }
847
848 pub fn debug_elements(&self, window_id: usize) -> Option<crate::json::Value> {
849 self.debug_elements_callbacks
850 .get(&window_id)
851 .map(|debug_elements| debug_elements(&self.cx))
852 }
853
854 pub fn add_action<A, V, F>(&mut self, mut handler: F)
855 where
856 A: Action,
857 V: View,
858 F: 'static + FnMut(&mut V, &A, &mut ViewContext<V>),
859 {
860 let handler = Box::new(
861 move |view: &mut dyn AnyView,
862 action: &dyn AnyAction,
863 cx: &mut MutableAppContext,
864 window_id: usize,
865 view_id: usize| {
866 let action = action.as_any().downcast_ref().unwrap();
867 let mut cx = ViewContext::new(cx, window_id, view_id);
868 handler(
869 view.as_any_mut()
870 .downcast_mut()
871 .expect("downcast is type safe"),
872 action,
873 &mut cx,
874 );
875 cx.halt_action_dispatch
876 },
877 );
878
879 self.actions
880 .entry(TypeId::of::<V>())
881 .or_default()
882 .entry(TypeId::of::<A>())
883 .or_default()
884 .push(handler);
885 }
886
887 pub fn add_async_action<A, V, F>(&mut self, mut handler: F)
888 where
889 A: Action,
890 V: View,
891 F: 'static + FnMut(&mut V, &A, &mut ViewContext<V>) -> Option<Task<Result<()>>>,
892 {
893 self.add_action(move |view, action, cx| {
894 handler(view, action, cx).map(|task| task.detach_and_log_err(cx));
895 })
896 }
897
898 pub fn add_global_action<A, F>(&mut self, mut handler: F)
899 where
900 A: Action,
901 F: 'static + FnMut(&A, &mut MutableAppContext),
902 {
903 let handler = Box::new(move |action: &dyn AnyAction, cx: &mut MutableAppContext| {
904 let action = action.as_any().downcast_ref().unwrap();
905 handler(action, cx);
906 });
907
908 if self
909 .global_actions
910 .insert(TypeId::of::<A>(), handler)
911 .is_some()
912 {
913 panic!("registered multiple global handlers for the same action type");
914 }
915 }
916
917 pub fn window_ids(&self) -> impl Iterator<Item = usize> + '_ {
918 self.cx.windows.keys().cloned()
919 }
920
921 pub fn activate_window(&self, window_id: usize) {
922 if let Some((_, window)) = self.presenters_and_platform_windows.get(&window_id) {
923 window.activate()
924 }
925 }
926
927 pub fn root_view<T: View>(&self, window_id: usize) -> Option<ViewHandle<T>> {
928 self.cx
929 .windows
930 .get(&window_id)
931 .and_then(|window| window.root_view.clone().downcast::<T>())
932 }
933
934 pub fn root_view_id(&self, window_id: usize) -> Option<usize> {
935 self.cx.root_view_id(window_id)
936 }
937
938 pub fn focused_view_id(&self, window_id: usize) -> Option<usize> {
939 self.cx.focused_view_id(window_id)
940 }
941
942 pub fn render_view(
943 &mut self,
944 window_id: usize,
945 view_id: usize,
946 titlebar_height: f32,
947 refreshing: bool,
948 ) -> Result<ElementBox> {
949 let mut view = self
950 .cx
951 .views
952 .remove(&(window_id, view_id))
953 .ok_or(anyhow!("view not found"))?;
954 let element = view.render(window_id, view_id, titlebar_height, refreshing, self);
955 self.cx.views.insert((window_id, view_id), view);
956 Ok(element)
957 }
958
959 pub fn render_views(
960 &mut self,
961 window_id: usize,
962 titlebar_height: f32,
963 ) -> HashMap<usize, ElementBox> {
964 self.start_frame();
965 let view_ids = self
966 .views
967 .keys()
968 .filter_map(|(win_id, view_id)| {
969 if *win_id == window_id {
970 Some(*view_id)
971 } else {
972 None
973 }
974 })
975 .collect::<Vec<_>>();
976 view_ids
977 .into_iter()
978 .map(|view_id| {
979 (
980 view_id,
981 self.render_view(window_id, view_id, titlebar_height, false)
982 .unwrap(),
983 )
984 })
985 .collect()
986 }
987
988 pub(crate) fn start_frame(&mut self) {
989 self.frame_count += 1;
990 }
991
992 pub fn update<T, F: FnOnce(&mut Self) -> T>(&mut self, callback: F) -> T {
993 self.pending_flushes += 1;
994 let result = callback(self);
995 self.flush_effects();
996 result
997 }
998
999 pub fn set_menus(&mut self, menus: Vec<Menu>) {
1000 self.foreground_platform.set_menus(menus);
1001 }
1002
1003 fn prompt(
1004 &self,
1005 window_id: usize,
1006 level: PromptLevel,
1007 msg: &str,
1008 answers: &[&str],
1009 ) -> oneshot::Receiver<usize> {
1010 let (_, window) = &self.presenters_and_platform_windows[&window_id];
1011 window.prompt(level, msg, answers)
1012 }
1013
1014 pub fn prompt_for_paths(
1015 &self,
1016 options: PathPromptOptions,
1017 ) -> oneshot::Receiver<Option<Vec<PathBuf>>> {
1018 self.foreground_platform.prompt_for_paths(options)
1019 }
1020
1021 pub fn prompt_for_new_path(&self, directory: &Path) -> oneshot::Receiver<Option<PathBuf>> {
1022 self.foreground_platform.prompt_for_new_path(directory)
1023 }
1024
1025 pub fn subscribe<E, H, F>(&mut self, handle: &H, mut callback: F) -> Subscription
1026 where
1027 E: Entity,
1028 E::Event: 'static,
1029 H: Handle<E>,
1030 F: 'static + FnMut(H, &E::Event, &mut Self),
1031 {
1032 self.subscribe_internal(handle, move |handle, event, cx| {
1033 callback(handle, event, cx);
1034 true
1035 })
1036 }
1037
1038 pub fn observe<E, H, F>(&mut self, handle: &H, mut callback: F) -> Subscription
1039 where
1040 E: Entity,
1041 E::Event: 'static,
1042 H: Handle<E>,
1043 F: 'static + FnMut(H, &mut Self),
1044 {
1045 self.observe_internal(handle, move |handle, cx| {
1046 callback(handle, cx);
1047 true
1048 })
1049 }
1050
1051 pub fn subscribe_internal<E, H, F>(&mut self, handle: &H, mut callback: F) -> Subscription
1052 where
1053 E: Entity,
1054 E::Event: 'static,
1055 H: Handle<E>,
1056 F: 'static + FnMut(H, &E::Event, &mut Self) -> bool,
1057 {
1058 let id = post_inc(&mut self.next_subscription_id);
1059 let emitter = handle.downgrade();
1060 self.subscriptions
1061 .lock()
1062 .entry(handle.id())
1063 .or_default()
1064 .insert(
1065 id,
1066 Box::new(move |payload, cx| {
1067 if let Some(emitter) = H::upgrade_from(&emitter, cx.as_ref()) {
1068 let payload = payload.downcast_ref().expect("downcast is type safe");
1069 callback(emitter, payload, cx)
1070 } else {
1071 false
1072 }
1073 }),
1074 );
1075 Subscription::Subscription {
1076 id,
1077 entity_id: handle.id(),
1078 subscriptions: Some(Arc::downgrade(&self.subscriptions)),
1079 }
1080 }
1081
1082 fn observe_internal<E, H, F>(&mut self, handle: &H, mut callback: F) -> Subscription
1083 where
1084 E: Entity,
1085 E::Event: 'static,
1086 H: Handle<E>,
1087 F: 'static + FnMut(H, &mut Self) -> bool,
1088 {
1089 let id = post_inc(&mut self.next_subscription_id);
1090 let observed = handle.downgrade();
1091 self.observations
1092 .lock()
1093 .entry(handle.id())
1094 .or_default()
1095 .insert(
1096 id,
1097 Box::new(move |cx| {
1098 if let Some(observed) = H::upgrade_from(&observed, cx) {
1099 callback(observed, cx)
1100 } else {
1101 false
1102 }
1103 }),
1104 );
1105 Subscription::Observation {
1106 id,
1107 entity_id: handle.id(),
1108 observations: Some(Arc::downgrade(&self.observations)),
1109 }
1110 }
1111
1112 pub fn observe_release<E, H, F>(&mut self, handle: &H, mut callback: F) -> Subscription
1113 where
1114 E: Entity,
1115 E::Event: 'static,
1116 H: Handle<E>,
1117 F: 'static + FnMut(&mut Self),
1118 {
1119 let id = post_inc(&mut self.next_subscription_id);
1120 self.release_observations
1121 .lock()
1122 .entry(handle.id())
1123 .or_default()
1124 .insert(id, Box::new(move |cx| callback(cx)));
1125 Subscription::ReleaseObservation {
1126 id,
1127 entity_id: handle.id(),
1128 observations: Some(Arc::downgrade(&self.release_observations)),
1129 }
1130 }
1131
1132 fn defer(&mut self, callback: Box<dyn FnOnce(&mut MutableAppContext)>) {
1133 self.pending_effects.push_back(Effect::Deferred(callback))
1134 }
1135
1136 pub(crate) fn notify_model(&mut self, model_id: usize) {
1137 if self.pending_notifications.insert(model_id) {
1138 self.pending_effects
1139 .push_back(Effect::ModelNotification { model_id });
1140 }
1141 }
1142
1143 pub(crate) fn notify_view(&mut self, window_id: usize, view_id: usize) {
1144 if self.pending_notifications.insert(view_id) {
1145 self.pending_effects
1146 .push_back(Effect::ViewNotification { window_id, view_id });
1147 }
1148 }
1149
1150 pub fn dispatch_action<A: Action>(
1151 &mut self,
1152 window_id: usize,
1153 responder_chain: Vec<usize>,
1154 action: &A,
1155 ) {
1156 self.dispatch_action_any(window_id, &responder_chain, action);
1157 }
1158
1159 pub(crate) fn dispatch_action_any(
1160 &mut self,
1161 window_id: usize,
1162 path: &[usize],
1163 action: &dyn AnyAction,
1164 ) -> bool {
1165 self.update(|this| {
1166 let mut halted_dispatch = false;
1167 for view_id in path.iter().rev() {
1168 if let Some(mut view) = this.cx.views.remove(&(window_id, *view_id)) {
1169 let type_id = view.as_any().type_id();
1170
1171 if let Some((name, mut handlers)) = this
1172 .actions
1173 .get_mut(&type_id)
1174 .and_then(|h| h.remove_entry(&action.id()))
1175 {
1176 for handler in handlers.iter_mut().rev() {
1177 let halt_dispatch =
1178 handler(view.as_mut(), action, this, window_id, *view_id);
1179 if halt_dispatch {
1180 halted_dispatch = true;
1181 break;
1182 }
1183 }
1184 this.actions
1185 .get_mut(&type_id)
1186 .unwrap()
1187 .insert(name, handlers);
1188 }
1189
1190 this.cx.views.insert((window_id, *view_id), view);
1191
1192 if halted_dispatch {
1193 break;
1194 }
1195 }
1196 }
1197
1198 if !halted_dispatch {
1199 halted_dispatch = this.dispatch_global_action_any(action);
1200 }
1201 halted_dispatch
1202 })
1203 }
1204
1205 pub fn dispatch_global_action<A: Action>(&mut self, action: A) {
1206 self.dispatch_global_action_any(&action);
1207 }
1208
1209 fn dispatch_global_action_any(&mut self, action: &dyn AnyAction) -> bool {
1210 self.update(|this| {
1211 if let Some((name, mut handler)) = this.global_actions.remove_entry(&action.id()) {
1212 handler(action, this);
1213 this.global_actions.insert(name, handler);
1214 true
1215 } else {
1216 false
1217 }
1218 })
1219 }
1220
1221 pub fn add_bindings<T: IntoIterator<Item = keymap::Binding>>(&mut self, bindings: T) {
1222 self.keystroke_matcher.add_bindings(bindings);
1223 }
1224
1225 pub fn dispatch_keystroke(
1226 &mut self,
1227 window_id: usize,
1228 responder_chain: Vec<usize>,
1229 keystroke: &Keystroke,
1230 ) -> Result<bool> {
1231 let mut context_chain = Vec::new();
1232 for view_id in &responder_chain {
1233 if let Some(view) = self.cx.views.get(&(window_id, *view_id)) {
1234 context_chain.push(view.keymap_context(self.as_ref()));
1235 } else {
1236 return Err(anyhow!(
1237 "View {} in responder chain does not exist",
1238 view_id
1239 ));
1240 }
1241 }
1242
1243 let mut pending = false;
1244 for (i, cx) in context_chain.iter().enumerate().rev() {
1245 match self
1246 .keystroke_matcher
1247 .push_keystroke(keystroke.clone(), responder_chain[i], cx)
1248 {
1249 MatchResult::None => {}
1250 MatchResult::Pending => pending = true,
1251 MatchResult::Action(action) => {
1252 if self.dispatch_action_any(window_id, &responder_chain[0..=i], action.as_ref())
1253 {
1254 self.keystroke_matcher.clear_pending();
1255 return Ok(true);
1256 }
1257 }
1258 }
1259 }
1260
1261 Ok(pending)
1262 }
1263
1264 pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
1265 where
1266 T: Entity,
1267 F: FnOnce(&mut ModelContext<T>) -> T,
1268 {
1269 self.update(|this| {
1270 let model_id = post_inc(&mut this.next_entity_id);
1271 let handle = ModelHandle::new(model_id, &this.cx.ref_counts);
1272 let mut cx = ModelContext::new(this, model_id);
1273 let model = build_model(&mut cx);
1274 this.cx.models.insert(model_id, Box::new(model));
1275 handle
1276 })
1277 }
1278
1279 pub fn add_window<T, F>(
1280 &mut self,
1281 window_options: WindowOptions,
1282 build_root_view: F,
1283 ) -> (usize, ViewHandle<T>)
1284 where
1285 T: View,
1286 F: FnOnce(&mut ViewContext<T>) -> T,
1287 {
1288 self.update(|this| {
1289 let window_id = post_inc(&mut this.next_window_id);
1290 let root_view = this.add_view(window_id, build_root_view);
1291
1292 this.cx.windows.insert(
1293 window_id,
1294 Window {
1295 root_view: root_view.clone().into(),
1296 focused_view_id: root_view.id(),
1297 invalidation: None,
1298 },
1299 );
1300 this.open_platform_window(window_id, window_options);
1301 root_view.update(this, |view, cx| {
1302 view.on_focus(cx);
1303 cx.notify();
1304 });
1305
1306 (window_id, root_view)
1307 })
1308 }
1309
1310 pub fn remove_window(&mut self, window_id: usize) {
1311 self.cx.windows.remove(&window_id);
1312 self.presenters_and_platform_windows.remove(&window_id);
1313 self.remove_dropped_entities();
1314 self.flush_effects();
1315 }
1316
1317 fn open_platform_window(&mut self, window_id: usize, window_options: WindowOptions) {
1318 let mut window =
1319 self.cx
1320 .platform
1321 .open_window(window_id, window_options, self.foreground.clone());
1322 let presenter = Rc::new(RefCell::new(
1323 self.build_presenter(window_id, window.titlebar_height()),
1324 ));
1325
1326 {
1327 let mut app = self.upgrade();
1328 let presenter = presenter.clone();
1329 window.on_event(Box::new(move |event| {
1330 app.update(|cx| {
1331 if let Event::KeyDown { keystroke, .. } = &event {
1332 if cx
1333 .dispatch_keystroke(
1334 window_id,
1335 presenter.borrow().dispatch_path(cx.as_ref()),
1336 keystroke,
1337 )
1338 .unwrap()
1339 {
1340 return;
1341 }
1342 }
1343
1344 presenter.borrow_mut().dispatch_event(event, cx);
1345 })
1346 }));
1347 }
1348
1349 {
1350 let mut app = self.upgrade();
1351 window.on_resize(Box::new(move || {
1352 app.update(|cx| cx.resize_window(window_id))
1353 }));
1354 }
1355
1356 {
1357 let mut app = self.upgrade();
1358 window.on_close(Box::new(move || {
1359 app.update(|cx| cx.remove_window(window_id));
1360 }));
1361 }
1362
1363 self.presenters_and_platform_windows
1364 .insert(window_id, (presenter.clone(), window));
1365
1366 self.on_debug_elements(window_id, move |cx| {
1367 presenter.borrow().debug_elements(cx).unwrap()
1368 });
1369 }
1370
1371 pub fn build_presenter(&mut self, window_id: usize, titlebar_height: f32) -> Presenter {
1372 Presenter::new(
1373 window_id,
1374 titlebar_height,
1375 self.cx.font_cache.clone(),
1376 TextLayoutCache::new(self.cx.platform.fonts()),
1377 self.assets.clone(),
1378 self,
1379 )
1380 }
1381
1382 pub fn build_render_context<V: View>(
1383 &mut self,
1384 window_id: usize,
1385 view_id: usize,
1386 titlebar_height: f32,
1387 refreshing: bool,
1388 ) -> RenderContext<V> {
1389 RenderContext {
1390 app: self,
1391 titlebar_height,
1392 refreshing,
1393 window_id,
1394 view_id,
1395 view_type: PhantomData,
1396 }
1397 }
1398
1399 pub fn add_view<T, F>(&mut self, window_id: usize, build_view: F) -> ViewHandle<T>
1400 where
1401 T: View,
1402 F: FnOnce(&mut ViewContext<T>) -> T,
1403 {
1404 self.add_option_view(window_id, |cx| Some(build_view(cx)))
1405 .unwrap()
1406 }
1407
1408 pub fn add_option_view<T, F>(
1409 &mut self,
1410 window_id: usize,
1411 build_view: F,
1412 ) -> Option<ViewHandle<T>>
1413 where
1414 T: View,
1415 F: FnOnce(&mut ViewContext<T>) -> Option<T>,
1416 {
1417 self.update(|this| {
1418 let view_id = post_inc(&mut this.next_entity_id);
1419 let mut cx = ViewContext::new(this, window_id, view_id);
1420 let handle = if let Some(view) = build_view(&mut cx) {
1421 this.cx.views.insert((window_id, view_id), Box::new(view));
1422 if let Some(window) = this.cx.windows.get_mut(&window_id) {
1423 window
1424 .invalidation
1425 .get_or_insert_with(Default::default)
1426 .updated
1427 .insert(view_id);
1428 }
1429 Some(ViewHandle::new(window_id, view_id, &this.cx.ref_counts))
1430 } else {
1431 None
1432 };
1433 handle
1434 })
1435 }
1436
1437 fn remove_dropped_entities(&mut self) {
1438 loop {
1439 let (dropped_models, dropped_views, dropped_element_states) =
1440 self.cx.ref_counts.lock().take_dropped();
1441 if dropped_models.is_empty()
1442 && dropped_views.is_empty()
1443 && dropped_element_states.is_empty()
1444 {
1445 break;
1446 }
1447
1448 for model_id in dropped_models {
1449 self.subscriptions.lock().remove(&model_id);
1450 self.observations.lock().remove(&model_id);
1451 let mut model = self.cx.models.remove(&model_id).unwrap();
1452 model.release(self);
1453 self.pending_effects.push_back(Effect::Release {
1454 entity_id: model_id,
1455 });
1456 }
1457
1458 for (window_id, view_id) in dropped_views {
1459 self.subscriptions.lock().remove(&view_id);
1460 self.observations.lock().remove(&view_id);
1461 let mut view = self.cx.views.remove(&(window_id, view_id)).unwrap();
1462 view.release(self);
1463 let change_focus_to = self.cx.windows.get_mut(&window_id).and_then(|window| {
1464 window
1465 .invalidation
1466 .get_or_insert_with(Default::default)
1467 .removed
1468 .push(view_id);
1469 if window.focused_view_id == view_id {
1470 Some(window.root_view.id())
1471 } else {
1472 None
1473 }
1474 });
1475
1476 if let Some(view_id) = change_focus_to {
1477 self.focus(window_id, view_id);
1478 }
1479
1480 self.pending_effects
1481 .push_back(Effect::Release { entity_id: view_id });
1482 }
1483
1484 for key in dropped_element_states {
1485 self.cx.element_states.remove(&key);
1486 }
1487 }
1488 }
1489
1490 fn flush_effects(&mut self) {
1491 self.pending_flushes = self.pending_flushes.saturating_sub(1);
1492
1493 if !self.flushing_effects && self.pending_flushes == 0 {
1494 self.flushing_effects = true;
1495
1496 let mut refreshing = false;
1497 loop {
1498 if let Some(effect) = self.pending_effects.pop_front() {
1499 match effect {
1500 Effect::Event { entity_id, payload } => self.emit_event(entity_id, payload),
1501 Effect::ModelNotification { model_id } => {
1502 self.notify_model_observers(model_id)
1503 }
1504 Effect::ViewNotification { window_id, view_id } => {
1505 self.notify_view_observers(window_id, view_id)
1506 }
1507 Effect::Deferred(callback) => callback(self),
1508 Effect::Release { entity_id } => self.notify_release_observers(entity_id),
1509 Effect::Focus { window_id, view_id } => {
1510 self.focus(window_id, view_id);
1511 }
1512 Effect::ResizeWindow { window_id } => {
1513 if let Some(window) = self.cx.windows.get_mut(&window_id) {
1514 window
1515 .invalidation
1516 .get_or_insert(WindowInvalidation::default());
1517 }
1518 }
1519 Effect::RefreshWindows => {
1520 refreshing = true;
1521 }
1522 }
1523 self.pending_notifications.clear();
1524 self.remove_dropped_entities();
1525 } else {
1526 self.remove_dropped_entities();
1527 if refreshing {
1528 self.perform_window_refresh();
1529 } else {
1530 self.update_windows();
1531 }
1532
1533 if self.pending_effects.is_empty() {
1534 self.flushing_effects = false;
1535 self.pending_notifications.clear();
1536 break;
1537 } else {
1538 refreshing = false;
1539 }
1540 }
1541 }
1542 }
1543 }
1544
1545 fn update_windows(&mut self) {
1546 let mut invalidations = HashMap::new();
1547 for (window_id, window) in &mut self.cx.windows {
1548 if let Some(invalidation) = window.invalidation.take() {
1549 invalidations.insert(*window_id, invalidation);
1550 }
1551 }
1552
1553 for (window_id, invalidation) in invalidations {
1554 if let Some((presenter, mut window)) =
1555 self.presenters_and_platform_windows.remove(&window_id)
1556 {
1557 {
1558 let mut presenter = presenter.borrow_mut();
1559 presenter.invalidate(invalidation, self);
1560 let scene =
1561 presenter.build_scene(window.size(), window.scale_factor(), false, self);
1562 window.present_scene(scene);
1563 }
1564 self.presenters_and_platform_windows
1565 .insert(window_id, (presenter, window));
1566 }
1567 }
1568 }
1569
1570 fn resize_window(&mut self, window_id: usize) {
1571 self.pending_effects
1572 .push_back(Effect::ResizeWindow { window_id });
1573 }
1574
1575 pub fn refresh_windows(&mut self) {
1576 self.pending_effects.push_back(Effect::RefreshWindows);
1577 }
1578
1579 fn perform_window_refresh(&mut self) {
1580 let mut presenters = mem::take(&mut self.presenters_and_platform_windows);
1581 for (window_id, (presenter, window)) in &mut presenters {
1582 let invalidation = self
1583 .cx
1584 .windows
1585 .get_mut(&window_id)
1586 .unwrap()
1587 .invalidation
1588 .take();
1589 let mut presenter = presenter.borrow_mut();
1590 presenter.refresh(invalidation, self);
1591 let scene = presenter.build_scene(window.size(), window.scale_factor(), true, self);
1592 window.present_scene(scene);
1593 }
1594 self.presenters_and_platform_windows = presenters;
1595 }
1596
1597 pub fn set_cursor_style(&mut self, style: CursorStyle) -> CursorStyleHandle {
1598 self.platform.set_cursor_style(style);
1599 let id = self.next_cursor_style_handle_id.fetch_add(1, SeqCst);
1600 CursorStyleHandle {
1601 id,
1602 next_cursor_style_handle_id: self.next_cursor_style_handle_id.clone(),
1603 platform: self.platform(),
1604 }
1605 }
1606
1607 fn emit_event(&mut self, entity_id: usize, payload: Box<dyn Any>) {
1608 let callbacks = self.subscriptions.lock().remove(&entity_id);
1609 if let Some(callbacks) = callbacks {
1610 for (id, mut callback) in callbacks {
1611 let alive = callback(payload.as_ref(), self);
1612 if alive {
1613 self.subscriptions
1614 .lock()
1615 .entry(entity_id)
1616 .or_default()
1617 .insert(id, callback);
1618 }
1619 }
1620 }
1621 }
1622
1623 fn notify_model_observers(&mut self, observed_id: usize) {
1624 let callbacks = self.observations.lock().remove(&observed_id);
1625 if let Some(callbacks) = callbacks {
1626 if self.cx.models.contains_key(&observed_id) {
1627 for (id, mut callback) in callbacks {
1628 let alive = callback(self);
1629 if alive {
1630 self.observations
1631 .lock()
1632 .entry(observed_id)
1633 .or_default()
1634 .insert(id, callback);
1635 }
1636 }
1637 }
1638 }
1639 }
1640
1641 fn notify_view_observers(&mut self, observed_window_id: usize, observed_view_id: usize) {
1642 if let Some(window) = self.cx.windows.get_mut(&observed_window_id) {
1643 window
1644 .invalidation
1645 .get_or_insert_with(Default::default)
1646 .updated
1647 .insert(observed_view_id);
1648 }
1649
1650 let callbacks = self.observations.lock().remove(&observed_view_id);
1651 if let Some(callbacks) = callbacks {
1652 if self
1653 .cx
1654 .views
1655 .contains_key(&(observed_window_id, observed_view_id))
1656 {
1657 for (id, mut callback) in callbacks {
1658 let alive = callback(self);
1659 if alive {
1660 self.observations
1661 .lock()
1662 .entry(observed_view_id)
1663 .or_default()
1664 .insert(id, callback);
1665 }
1666 }
1667 }
1668 }
1669 }
1670
1671 fn notify_release_observers(&mut self, entity_id: usize) {
1672 let callbacks = self.release_observations.lock().remove(&entity_id);
1673 if let Some(callbacks) = callbacks {
1674 for (_, mut callback) in callbacks {
1675 callback(self);
1676 }
1677 }
1678 }
1679
1680 fn focus(&mut self, window_id: usize, focused_id: usize) {
1681 if self
1682 .cx
1683 .windows
1684 .get(&window_id)
1685 .map(|w| w.focused_view_id)
1686 .map_or(false, |cur_focused| cur_focused == focused_id)
1687 {
1688 return;
1689 }
1690
1691 self.update(|this| {
1692 let blurred_id = this.cx.windows.get_mut(&window_id).map(|window| {
1693 let blurred_id = window.focused_view_id;
1694 window.focused_view_id = focused_id;
1695 blurred_id
1696 });
1697
1698 if let Some(blurred_id) = blurred_id {
1699 if let Some(mut blurred_view) = this.cx.views.remove(&(window_id, blurred_id)) {
1700 blurred_view.on_blur(this, window_id, blurred_id);
1701 this.cx.views.insert((window_id, blurred_id), blurred_view);
1702 }
1703 }
1704
1705 if let Some(mut focused_view) = this.cx.views.remove(&(window_id, focused_id)) {
1706 focused_view.on_focus(this, window_id, focused_id);
1707 this.cx.views.insert((window_id, focused_id), focused_view);
1708 }
1709 })
1710 }
1711
1712 pub fn spawn<F, Fut, T>(&self, f: F) -> Task<T>
1713 where
1714 F: FnOnce(AsyncAppContext) -> Fut,
1715 Fut: 'static + Future<Output = T>,
1716 T: 'static,
1717 {
1718 let future = f(self.to_async());
1719 let cx = self.to_async();
1720 self.foreground.spawn(async move {
1721 let result = future.await;
1722 cx.0.borrow_mut().flush_effects();
1723 result
1724 })
1725 }
1726
1727 pub fn to_async(&self) -> AsyncAppContext {
1728 AsyncAppContext(self.weak_self.as_ref().unwrap().upgrade().unwrap())
1729 }
1730
1731 pub fn write_to_clipboard(&self, item: ClipboardItem) {
1732 self.cx.platform.write_to_clipboard(item);
1733 }
1734
1735 pub fn read_from_clipboard(&self) -> Option<ClipboardItem> {
1736 self.cx.platform.read_from_clipboard()
1737 }
1738}
1739
1740impl ReadModel for MutableAppContext {
1741 fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
1742 if let Some(model) = self.cx.models.get(&handle.model_id) {
1743 model
1744 .as_any()
1745 .downcast_ref()
1746 .expect("downcast is type safe")
1747 } else {
1748 panic!("circular model reference");
1749 }
1750 }
1751}
1752
1753impl UpdateModel for MutableAppContext {
1754 fn update_model<T: Entity, V>(
1755 &mut self,
1756 handle: &ModelHandle<T>,
1757 update: &mut dyn FnMut(&mut T, &mut ModelContext<T>) -> V,
1758 ) -> V {
1759 if let Some(mut model) = self.cx.models.remove(&handle.model_id) {
1760 self.update(|this| {
1761 let mut cx = ModelContext::new(this, handle.model_id);
1762 let result = update(
1763 model
1764 .as_any_mut()
1765 .downcast_mut()
1766 .expect("downcast is type safe"),
1767 &mut cx,
1768 );
1769 this.cx.models.insert(handle.model_id, model);
1770 result
1771 })
1772 } else {
1773 panic!("circular model update");
1774 }
1775 }
1776}
1777
1778impl UpgradeModelHandle for MutableAppContext {
1779 fn upgrade_model_handle<T: Entity>(
1780 &self,
1781 handle: &WeakModelHandle<T>,
1782 ) -> Option<ModelHandle<T>> {
1783 self.cx.upgrade_model_handle(handle)
1784 }
1785
1786 fn upgrade_any_model_handle(&self, handle: &AnyWeakModelHandle) -> Option<AnyModelHandle> {
1787 self.cx.upgrade_any_model_handle(handle)
1788 }
1789}
1790
1791impl UpgradeViewHandle for MutableAppContext {
1792 fn upgrade_view_handle<T: View>(&self, handle: &WeakViewHandle<T>) -> Option<ViewHandle<T>> {
1793 self.cx.upgrade_view_handle(handle)
1794 }
1795}
1796
1797impl ReadView for MutableAppContext {
1798 fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
1799 if let Some(view) = self.cx.views.get(&(handle.window_id, handle.view_id)) {
1800 view.as_any().downcast_ref().expect("downcast is type safe")
1801 } else {
1802 panic!("circular view reference");
1803 }
1804 }
1805}
1806
1807impl UpdateView for MutableAppContext {
1808 fn update_view<T, S>(
1809 &mut self,
1810 handle: &ViewHandle<T>,
1811 update: &mut dyn FnMut(&mut T, &mut ViewContext<T>) -> S,
1812 ) -> S
1813 where
1814 T: View,
1815 {
1816 self.update(|this| {
1817 let mut view = this
1818 .cx
1819 .views
1820 .remove(&(handle.window_id, handle.view_id))
1821 .expect("circular view update");
1822
1823 let mut cx = ViewContext::new(this, handle.window_id, handle.view_id);
1824 let result = update(
1825 view.as_any_mut()
1826 .downcast_mut()
1827 .expect("downcast is type safe"),
1828 &mut cx,
1829 );
1830 this.cx
1831 .views
1832 .insert((handle.window_id, handle.view_id), view);
1833 result
1834 })
1835 }
1836}
1837
1838impl AsRef<AppContext> for MutableAppContext {
1839 fn as_ref(&self) -> &AppContext {
1840 &self.cx
1841 }
1842}
1843
1844impl Deref for MutableAppContext {
1845 type Target = AppContext;
1846
1847 fn deref(&self) -> &Self::Target {
1848 &self.cx
1849 }
1850}
1851
1852pub struct AppContext {
1853 models: HashMap<usize, Box<dyn AnyModel>>,
1854 views: HashMap<(usize, usize), Box<dyn AnyView>>,
1855 windows: HashMap<usize, Window>,
1856 element_states: HashMap<ElementStateId, Box<dyn Any>>,
1857 background: Arc<executor::Background>,
1858 ref_counts: Arc<Mutex<RefCounts>>,
1859 font_cache: Arc<FontCache>,
1860 platform: Arc<dyn Platform>,
1861}
1862
1863impl AppContext {
1864 pub fn root_view_id(&self, window_id: usize) -> Option<usize> {
1865 self.windows
1866 .get(&window_id)
1867 .map(|window| window.root_view.id())
1868 }
1869
1870 pub fn focused_view_id(&self, window_id: usize) -> Option<usize> {
1871 self.windows
1872 .get(&window_id)
1873 .map(|window| window.focused_view_id)
1874 }
1875
1876 pub fn background(&self) -> &Arc<executor::Background> {
1877 &self.background
1878 }
1879
1880 pub fn font_cache(&self) -> &Arc<FontCache> {
1881 &self.font_cache
1882 }
1883
1884 pub fn platform(&self) -> &Arc<dyn Platform> {
1885 &self.platform
1886 }
1887}
1888
1889impl ReadModel for AppContext {
1890 fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
1891 if let Some(model) = self.models.get(&handle.model_id) {
1892 model
1893 .as_any()
1894 .downcast_ref()
1895 .expect("downcast should be type safe")
1896 } else {
1897 panic!("circular model reference");
1898 }
1899 }
1900}
1901
1902impl UpgradeModelHandle for AppContext {
1903 fn upgrade_model_handle<T: Entity>(
1904 &self,
1905 handle: &WeakModelHandle<T>,
1906 ) -> Option<ModelHandle<T>> {
1907 if self.models.contains_key(&handle.model_id) {
1908 Some(ModelHandle::new(handle.model_id, &self.ref_counts))
1909 } else {
1910 None
1911 }
1912 }
1913
1914 fn upgrade_any_model_handle(&self, handle: &AnyWeakModelHandle) -> Option<AnyModelHandle> {
1915 if self.models.contains_key(&handle.model_id) {
1916 self.ref_counts.lock().inc_model(handle.model_id);
1917 Some(AnyModelHandle {
1918 model_id: handle.model_id,
1919 model_type: handle.model_type,
1920 ref_counts: self.ref_counts.clone(),
1921 })
1922 } else {
1923 None
1924 }
1925 }
1926}
1927
1928impl UpgradeViewHandle for AppContext {
1929 fn upgrade_view_handle<T: View>(&self, handle: &WeakViewHandle<T>) -> Option<ViewHandle<T>> {
1930 if self.ref_counts.lock().is_entity_alive(handle.view_id) {
1931 Some(ViewHandle::new(
1932 handle.window_id,
1933 handle.view_id,
1934 &self.ref_counts,
1935 ))
1936 } else {
1937 None
1938 }
1939 }
1940}
1941
1942impl ReadView for AppContext {
1943 fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
1944 if let Some(view) = self.views.get(&(handle.window_id, handle.view_id)) {
1945 view.as_any()
1946 .downcast_ref()
1947 .expect("downcast should be type safe")
1948 } else {
1949 panic!("circular view reference");
1950 }
1951 }
1952}
1953
1954struct Window {
1955 root_view: AnyViewHandle,
1956 focused_view_id: usize,
1957 invalidation: Option<WindowInvalidation>,
1958}
1959
1960#[derive(Default, Clone)]
1961pub struct WindowInvalidation {
1962 pub updated: HashSet<usize>,
1963 pub removed: Vec<usize>,
1964}
1965
1966pub enum Effect {
1967 Event {
1968 entity_id: usize,
1969 payload: Box<dyn Any>,
1970 },
1971 ModelNotification {
1972 model_id: usize,
1973 },
1974 ViewNotification {
1975 window_id: usize,
1976 view_id: usize,
1977 },
1978 Deferred(Box<dyn FnOnce(&mut MutableAppContext)>),
1979 Release {
1980 entity_id: usize,
1981 },
1982 Focus {
1983 window_id: usize,
1984 view_id: usize,
1985 },
1986 ResizeWindow {
1987 window_id: usize,
1988 },
1989 RefreshWindows,
1990}
1991
1992impl Debug for Effect {
1993 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1994 match self {
1995 Effect::Event { entity_id, .. } => f
1996 .debug_struct("Effect::Event")
1997 .field("entity_id", entity_id)
1998 .finish(),
1999 Effect::ModelNotification { model_id } => f
2000 .debug_struct("Effect::ModelNotification")
2001 .field("model_id", model_id)
2002 .finish(),
2003 Effect::ViewNotification { window_id, view_id } => f
2004 .debug_struct("Effect::ViewNotification")
2005 .field("window_id", window_id)
2006 .field("view_id", view_id)
2007 .finish(),
2008 Effect::Deferred(_) => f.debug_struct("Effect::Deferred").finish(),
2009 Effect::Release { entity_id } => f
2010 .debug_struct("Effect::Release")
2011 .field("entity_id", entity_id)
2012 .finish(),
2013 Effect::Focus { window_id, view_id } => f
2014 .debug_struct("Effect::Focus")
2015 .field("window_id", window_id)
2016 .field("view_id", view_id)
2017 .finish(),
2018 Effect::ResizeWindow { window_id } => f
2019 .debug_struct("Effect::RefreshWindow")
2020 .field("window_id", window_id)
2021 .finish(),
2022 Effect::RefreshWindows => f.debug_struct("Effect::FullViewRefresh").finish(),
2023 }
2024 }
2025}
2026
2027pub trait AnyModel {
2028 fn as_any(&self) -> &dyn Any;
2029 fn as_any_mut(&mut self) -> &mut dyn Any;
2030 fn release(&mut self, cx: &mut MutableAppContext);
2031 fn app_will_quit(
2032 &mut self,
2033 cx: &mut MutableAppContext,
2034 ) -> Option<Pin<Box<dyn 'static + Future<Output = ()>>>>;
2035}
2036
2037impl<T> AnyModel for T
2038where
2039 T: Entity,
2040{
2041 fn as_any(&self) -> &dyn Any {
2042 self
2043 }
2044
2045 fn as_any_mut(&mut self) -> &mut dyn Any {
2046 self
2047 }
2048
2049 fn release(&mut self, cx: &mut MutableAppContext) {
2050 self.release(cx);
2051 }
2052
2053 fn app_will_quit(
2054 &mut self,
2055 cx: &mut MutableAppContext,
2056 ) -> Option<Pin<Box<dyn 'static + Future<Output = ()>>>> {
2057 self.app_will_quit(cx)
2058 }
2059}
2060
2061pub trait AnyView {
2062 fn as_any(&self) -> &dyn Any;
2063 fn as_any_mut(&mut self) -> &mut dyn Any;
2064 fn release(&mut self, cx: &mut MutableAppContext);
2065 fn app_will_quit(
2066 &mut self,
2067 cx: &mut MutableAppContext,
2068 ) -> Option<Pin<Box<dyn 'static + Future<Output = ()>>>>;
2069 fn ui_name(&self) -> &'static str;
2070 fn render<'a>(
2071 &mut self,
2072 window_id: usize,
2073 view_id: usize,
2074 titlebar_height: f32,
2075 refreshing: bool,
2076 cx: &mut MutableAppContext,
2077 ) -> ElementBox;
2078 fn on_focus(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize);
2079 fn on_blur(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize);
2080 fn keymap_context(&self, cx: &AppContext) -> keymap::Context;
2081}
2082
2083impl<T> AnyView for T
2084where
2085 T: View,
2086{
2087 fn as_any(&self) -> &dyn Any {
2088 self
2089 }
2090
2091 fn as_any_mut(&mut self) -> &mut dyn Any {
2092 self
2093 }
2094
2095 fn release(&mut self, cx: &mut MutableAppContext) {
2096 self.release(cx);
2097 }
2098
2099 fn app_will_quit(
2100 &mut self,
2101 cx: &mut MutableAppContext,
2102 ) -> Option<Pin<Box<dyn 'static + Future<Output = ()>>>> {
2103 self.app_will_quit(cx)
2104 }
2105
2106 fn ui_name(&self) -> &'static str {
2107 T::ui_name()
2108 }
2109
2110 fn render<'a>(
2111 &mut self,
2112 window_id: usize,
2113 view_id: usize,
2114 titlebar_height: f32,
2115 refreshing: bool,
2116 cx: &mut MutableAppContext,
2117 ) -> ElementBox {
2118 View::render(
2119 self,
2120 &mut RenderContext {
2121 window_id,
2122 view_id,
2123 app: cx,
2124 view_type: PhantomData::<T>,
2125 titlebar_height,
2126 refreshing,
2127 },
2128 )
2129 }
2130
2131 fn on_focus(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize) {
2132 let mut cx = ViewContext::new(cx, window_id, view_id);
2133 View::on_focus(self, &mut cx);
2134 }
2135
2136 fn on_blur(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize) {
2137 let mut cx = ViewContext::new(cx, window_id, view_id);
2138 View::on_blur(self, &mut cx);
2139 }
2140
2141 fn keymap_context(&self, cx: &AppContext) -> keymap::Context {
2142 View::keymap_context(self, cx)
2143 }
2144}
2145
2146pub struct ModelContext<'a, T: ?Sized> {
2147 app: &'a mut MutableAppContext,
2148 model_id: usize,
2149 model_type: PhantomData<T>,
2150 halt_stream: bool,
2151}
2152
2153impl<'a, T: Entity> ModelContext<'a, T> {
2154 fn new(app: &'a mut MutableAppContext, model_id: usize) -> Self {
2155 Self {
2156 app,
2157 model_id,
2158 model_type: PhantomData,
2159 halt_stream: false,
2160 }
2161 }
2162
2163 pub fn background(&self) -> &Arc<executor::Background> {
2164 &self.app.cx.background
2165 }
2166
2167 pub fn halt_stream(&mut self) {
2168 self.halt_stream = true;
2169 }
2170
2171 pub fn model_id(&self) -> usize {
2172 self.model_id
2173 }
2174
2175 pub fn add_model<S, F>(&mut self, build_model: F) -> ModelHandle<S>
2176 where
2177 S: Entity,
2178 F: FnOnce(&mut ModelContext<S>) -> S,
2179 {
2180 self.app.add_model(build_model)
2181 }
2182
2183 pub fn emit(&mut self, payload: T::Event) {
2184 self.app.pending_effects.push_back(Effect::Event {
2185 entity_id: self.model_id,
2186 payload: Box::new(payload),
2187 });
2188 }
2189
2190 pub fn notify(&mut self) {
2191 self.app.notify_model(self.model_id);
2192 }
2193
2194 pub fn subscribe<S: Entity, F>(
2195 &mut self,
2196 handle: &ModelHandle<S>,
2197 mut callback: F,
2198 ) -> Subscription
2199 where
2200 S::Event: 'static,
2201 F: 'static + FnMut(&mut T, ModelHandle<S>, &S::Event, &mut ModelContext<T>),
2202 {
2203 let subscriber = self.weak_handle();
2204 self.app
2205 .subscribe_internal(handle, move |emitter, event, cx| {
2206 if let Some(subscriber) = subscriber.upgrade(cx) {
2207 subscriber.update(cx, |subscriber, cx| {
2208 callback(subscriber, emitter, event, cx);
2209 });
2210 true
2211 } else {
2212 false
2213 }
2214 })
2215 }
2216
2217 pub fn observe<S, F>(&mut self, handle: &ModelHandle<S>, mut callback: F) -> Subscription
2218 where
2219 S: Entity,
2220 F: 'static + FnMut(&mut T, ModelHandle<S>, &mut ModelContext<T>),
2221 {
2222 let observer = self.weak_handle();
2223 self.app.observe_internal(handle, move |observed, cx| {
2224 if let Some(observer) = observer.upgrade(cx) {
2225 observer.update(cx, |observer, cx| {
2226 callback(observer, observed, cx);
2227 });
2228 true
2229 } else {
2230 false
2231 }
2232 })
2233 }
2234
2235 pub fn observe_release<S, F>(
2236 &mut self,
2237 handle: &ModelHandle<S>,
2238 mut callback: F,
2239 ) -> Subscription
2240 where
2241 S: Entity,
2242 F: 'static + FnMut(&mut T, &mut ModelContext<T>),
2243 {
2244 let observer = self.weak_handle();
2245 self.app.observe_release(handle, move |cx| {
2246 if let Some(observer) = observer.upgrade(cx) {
2247 observer.update(cx, |observer, cx| {
2248 callback(observer, cx);
2249 });
2250 }
2251 })
2252 }
2253
2254 pub fn handle(&self) -> ModelHandle<T> {
2255 ModelHandle::new(self.model_id, &self.app.cx.ref_counts)
2256 }
2257
2258 pub fn weak_handle(&self) -> WeakModelHandle<T> {
2259 WeakModelHandle::new(self.model_id)
2260 }
2261
2262 pub fn spawn<F, Fut, S>(&self, f: F) -> Task<S>
2263 where
2264 F: FnOnce(ModelHandle<T>, AsyncAppContext) -> Fut,
2265 Fut: 'static + Future<Output = S>,
2266 S: 'static,
2267 {
2268 let handle = self.handle();
2269 self.app.spawn(|cx| f(handle, cx))
2270 }
2271
2272 pub fn spawn_weak<F, Fut, S>(&self, f: F) -> Task<S>
2273 where
2274 F: FnOnce(WeakModelHandle<T>, AsyncAppContext) -> Fut,
2275 Fut: 'static + Future<Output = S>,
2276 S: 'static,
2277 {
2278 let handle = self.weak_handle();
2279 self.app.spawn(|cx| f(handle, cx))
2280 }
2281}
2282
2283impl<M> AsRef<AppContext> for ModelContext<'_, M> {
2284 fn as_ref(&self) -> &AppContext {
2285 &self.app.cx
2286 }
2287}
2288
2289impl<M> AsMut<MutableAppContext> for ModelContext<'_, M> {
2290 fn as_mut(&mut self) -> &mut MutableAppContext {
2291 self.app
2292 }
2293}
2294
2295impl<M> ReadModel for ModelContext<'_, M> {
2296 fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
2297 self.app.read_model(handle)
2298 }
2299}
2300
2301impl<M> UpdateModel for ModelContext<'_, M> {
2302 fn update_model<T: Entity, V>(
2303 &mut self,
2304 handle: &ModelHandle<T>,
2305 update: &mut dyn FnMut(&mut T, &mut ModelContext<T>) -> V,
2306 ) -> V {
2307 self.app.update_model(handle, update)
2308 }
2309}
2310
2311impl<M> UpgradeModelHandle for ModelContext<'_, M> {
2312 fn upgrade_model_handle<T: Entity>(
2313 &self,
2314 handle: &WeakModelHandle<T>,
2315 ) -> Option<ModelHandle<T>> {
2316 self.cx.upgrade_model_handle(handle)
2317 }
2318
2319 fn upgrade_any_model_handle(&self, handle: &AnyWeakModelHandle) -> Option<AnyModelHandle> {
2320 self.cx.upgrade_any_model_handle(handle)
2321 }
2322}
2323
2324impl<M> Deref for ModelContext<'_, M> {
2325 type Target = MutableAppContext;
2326
2327 fn deref(&self) -> &Self::Target {
2328 &self.app
2329 }
2330}
2331
2332impl<M> DerefMut for ModelContext<'_, M> {
2333 fn deref_mut(&mut self) -> &mut Self::Target {
2334 &mut self.app
2335 }
2336}
2337
2338pub struct ViewContext<'a, T: ?Sized> {
2339 app: &'a mut MutableAppContext,
2340 window_id: usize,
2341 view_id: usize,
2342 view_type: PhantomData<T>,
2343 halt_action_dispatch: bool,
2344}
2345
2346impl<'a, T: View> ViewContext<'a, T> {
2347 fn new(app: &'a mut MutableAppContext, window_id: usize, view_id: usize) -> Self {
2348 Self {
2349 app,
2350 window_id,
2351 view_id,
2352 view_type: PhantomData,
2353 halt_action_dispatch: true,
2354 }
2355 }
2356
2357 pub fn handle(&self) -> ViewHandle<T> {
2358 ViewHandle::new(self.window_id, self.view_id, &self.app.cx.ref_counts)
2359 }
2360
2361 pub fn weak_handle(&self) -> WeakViewHandle<T> {
2362 WeakViewHandle::new(self.window_id, self.view_id)
2363 }
2364
2365 pub fn window_id(&self) -> usize {
2366 self.window_id
2367 }
2368
2369 pub fn view_id(&self) -> usize {
2370 self.view_id
2371 }
2372
2373 pub fn foreground(&self) -> &Rc<executor::Foreground> {
2374 self.app.foreground()
2375 }
2376
2377 pub fn background_executor(&self) -> &Arc<executor::Background> {
2378 &self.app.cx.background
2379 }
2380
2381 pub fn platform(&self) -> Arc<dyn Platform> {
2382 self.app.platform()
2383 }
2384
2385 pub fn prompt(
2386 &self,
2387 level: PromptLevel,
2388 msg: &str,
2389 answers: &[&str],
2390 ) -> oneshot::Receiver<usize> {
2391 self.app.prompt(self.window_id, level, msg, answers)
2392 }
2393
2394 pub fn prompt_for_paths(
2395 &self,
2396 options: PathPromptOptions,
2397 ) -> oneshot::Receiver<Option<Vec<PathBuf>>> {
2398 self.app.prompt_for_paths(options)
2399 }
2400
2401 pub fn prompt_for_new_path(&self, directory: &Path) -> oneshot::Receiver<Option<PathBuf>> {
2402 self.app.prompt_for_new_path(directory)
2403 }
2404
2405 pub fn debug_elements(&self) -> crate::json::Value {
2406 self.app.debug_elements(self.window_id).unwrap()
2407 }
2408
2409 pub fn focus<S>(&mut self, handle: S)
2410 where
2411 S: Into<AnyViewHandle>,
2412 {
2413 let handle = handle.into();
2414 self.app.pending_effects.push_back(Effect::Focus {
2415 window_id: handle.window_id,
2416 view_id: handle.view_id,
2417 });
2418 }
2419
2420 pub fn focus_self(&mut self) {
2421 self.app.pending_effects.push_back(Effect::Focus {
2422 window_id: self.window_id,
2423 view_id: self.view_id,
2424 });
2425 }
2426
2427 pub fn add_model<S, F>(&mut self, build_model: F) -> ModelHandle<S>
2428 where
2429 S: Entity,
2430 F: FnOnce(&mut ModelContext<S>) -> S,
2431 {
2432 self.app.add_model(build_model)
2433 }
2434
2435 pub fn add_view<S, F>(&mut self, build_view: F) -> ViewHandle<S>
2436 where
2437 S: View,
2438 F: FnOnce(&mut ViewContext<S>) -> S,
2439 {
2440 self.app.add_view(self.window_id, build_view)
2441 }
2442
2443 pub fn add_option_view<S, F>(&mut self, build_view: F) -> Option<ViewHandle<S>>
2444 where
2445 S: View,
2446 F: FnOnce(&mut ViewContext<S>) -> Option<S>,
2447 {
2448 self.app.add_option_view(self.window_id, build_view)
2449 }
2450
2451 pub fn subscribe<E, H, F>(&mut self, handle: &H, mut callback: F) -> Subscription
2452 where
2453 E: Entity,
2454 E::Event: 'static,
2455 H: Handle<E>,
2456 F: 'static + FnMut(&mut T, H, &E::Event, &mut ViewContext<T>),
2457 {
2458 let subscriber = self.weak_handle();
2459 self.app
2460 .subscribe_internal(handle, move |emitter, event, cx| {
2461 if let Some(subscriber) = subscriber.upgrade(cx) {
2462 subscriber.update(cx, |subscriber, cx| {
2463 callback(subscriber, emitter, event, cx);
2464 });
2465 true
2466 } else {
2467 false
2468 }
2469 })
2470 }
2471
2472 pub fn observe<E, F, H>(&mut self, handle: &H, mut callback: F) -> Subscription
2473 where
2474 E: Entity,
2475 H: Handle<E>,
2476 F: 'static + FnMut(&mut T, H, &mut ViewContext<T>),
2477 {
2478 let observer = self.weak_handle();
2479 self.app.observe_internal(handle, move |observed, cx| {
2480 if let Some(observer) = observer.upgrade(cx) {
2481 observer.update(cx, |observer, cx| {
2482 callback(observer, observed, cx);
2483 });
2484 true
2485 } else {
2486 false
2487 }
2488 })
2489 }
2490
2491 pub fn observe_release<E, F, H>(&mut self, handle: &H, mut callback: F) -> Subscription
2492 where
2493 E: Entity,
2494 H: Handle<E>,
2495 F: 'static + FnMut(&mut T, &mut ViewContext<T>),
2496 {
2497 let observer = self.weak_handle();
2498 self.app.observe_release(handle, move |cx| {
2499 if let Some(observer) = observer.upgrade(cx) {
2500 observer.update(cx, |observer, cx| {
2501 callback(observer, cx);
2502 });
2503 }
2504 })
2505 }
2506
2507 pub fn emit(&mut self, payload: T::Event) {
2508 self.app.pending_effects.push_back(Effect::Event {
2509 entity_id: self.view_id,
2510 payload: Box::new(payload),
2511 });
2512 }
2513
2514 pub fn notify(&mut self) {
2515 self.app.notify_view(self.window_id, self.view_id);
2516 }
2517
2518 pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut T, &mut ViewContext<T>)) {
2519 let handle = self.handle();
2520 self.app.defer(Box::new(move |cx| {
2521 handle.update(cx, |view, cx| {
2522 callback(view, cx);
2523 })
2524 }))
2525 }
2526
2527 pub fn propagate_action(&mut self) {
2528 self.halt_action_dispatch = false;
2529 }
2530
2531 pub fn spawn<F, Fut, S>(&self, f: F) -> Task<S>
2532 where
2533 F: FnOnce(ViewHandle<T>, AsyncAppContext) -> Fut,
2534 Fut: 'static + Future<Output = S>,
2535 S: 'static,
2536 {
2537 let handle = self.handle();
2538 self.app.spawn(|cx| f(handle, cx))
2539 }
2540
2541 pub fn spawn_weak<F, Fut, S>(&self, f: F) -> Task<S>
2542 where
2543 F: FnOnce(WeakViewHandle<T>, AsyncAppContext) -> Fut,
2544 Fut: 'static + Future<Output = S>,
2545 S: 'static,
2546 {
2547 let handle = self.weak_handle();
2548 self.app.spawn(|cx| f(handle, cx))
2549 }
2550}
2551
2552pub struct RenderContext<'a, T: View> {
2553 pub app: &'a mut MutableAppContext,
2554 pub titlebar_height: f32,
2555 pub refreshing: bool,
2556 window_id: usize,
2557 view_id: usize,
2558 view_type: PhantomData<T>,
2559}
2560
2561impl<'a, T: View> RenderContext<'a, T> {
2562 pub fn handle(&self) -> WeakViewHandle<T> {
2563 WeakViewHandle::new(self.window_id, self.view_id)
2564 }
2565
2566 pub fn view_id(&self) -> usize {
2567 self.view_id
2568 }
2569}
2570
2571impl AsRef<AppContext> for &AppContext {
2572 fn as_ref(&self) -> &AppContext {
2573 self
2574 }
2575}
2576
2577impl<V: View> Deref for RenderContext<'_, V> {
2578 type Target = MutableAppContext;
2579
2580 fn deref(&self) -> &Self::Target {
2581 self.app
2582 }
2583}
2584
2585impl<V: View> DerefMut for RenderContext<'_, V> {
2586 fn deref_mut(&mut self) -> &mut Self::Target {
2587 self.app
2588 }
2589}
2590
2591impl<V: View> ReadModel for RenderContext<'_, V> {
2592 fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
2593 self.app.read_model(handle)
2594 }
2595}
2596
2597impl<V: View> UpdateModel for RenderContext<'_, V> {
2598 fn update_model<T: Entity, O>(
2599 &mut self,
2600 handle: &ModelHandle<T>,
2601 update: &mut dyn FnMut(&mut T, &mut ModelContext<T>) -> O,
2602 ) -> O {
2603 self.app.update_model(handle, update)
2604 }
2605}
2606
2607impl<V: View> ReadView for RenderContext<'_, V> {
2608 fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
2609 self.app.read_view(handle)
2610 }
2611}
2612
2613impl<V: View> ElementStateContext for RenderContext<'_, V> {
2614 fn current_view_id(&self) -> usize {
2615 self.view_id
2616 }
2617}
2618
2619impl<M> AsRef<AppContext> for ViewContext<'_, M> {
2620 fn as_ref(&self) -> &AppContext {
2621 &self.app.cx
2622 }
2623}
2624
2625impl<M> Deref for ViewContext<'_, M> {
2626 type Target = MutableAppContext;
2627
2628 fn deref(&self) -> &Self::Target {
2629 &self.app
2630 }
2631}
2632
2633impl<M> DerefMut for ViewContext<'_, M> {
2634 fn deref_mut(&mut self) -> &mut Self::Target {
2635 &mut self.app
2636 }
2637}
2638
2639impl<M> AsMut<MutableAppContext> for ViewContext<'_, M> {
2640 fn as_mut(&mut self) -> &mut MutableAppContext {
2641 self.app
2642 }
2643}
2644
2645impl<V> ReadModel for ViewContext<'_, V> {
2646 fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
2647 self.app.read_model(handle)
2648 }
2649}
2650
2651impl<V> UpgradeModelHandle for ViewContext<'_, V> {
2652 fn upgrade_model_handle<T: Entity>(
2653 &self,
2654 handle: &WeakModelHandle<T>,
2655 ) -> Option<ModelHandle<T>> {
2656 self.cx.upgrade_model_handle(handle)
2657 }
2658
2659 fn upgrade_any_model_handle(&self, handle: &AnyWeakModelHandle) -> Option<AnyModelHandle> {
2660 self.cx.upgrade_any_model_handle(handle)
2661 }
2662}
2663
2664impl<V> UpgradeViewHandle for ViewContext<'_, V> {
2665 fn upgrade_view_handle<T: View>(&self, handle: &WeakViewHandle<T>) -> Option<ViewHandle<T>> {
2666 self.cx.upgrade_view_handle(handle)
2667 }
2668}
2669
2670impl<V: View> UpdateModel for ViewContext<'_, V> {
2671 fn update_model<T: Entity, O>(
2672 &mut self,
2673 handle: &ModelHandle<T>,
2674 update: &mut dyn FnMut(&mut T, &mut ModelContext<T>) -> O,
2675 ) -> O {
2676 self.app.update_model(handle, update)
2677 }
2678}
2679
2680impl<V: View> ReadView for ViewContext<'_, V> {
2681 fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
2682 self.app.read_view(handle)
2683 }
2684}
2685
2686impl<V: View> UpdateView for ViewContext<'_, V> {
2687 fn update_view<T, S>(
2688 &mut self,
2689 handle: &ViewHandle<T>,
2690 update: &mut dyn FnMut(&mut T, &mut ViewContext<T>) -> S,
2691 ) -> S
2692 where
2693 T: View,
2694 {
2695 self.app.update_view(handle, update)
2696 }
2697}
2698
2699impl<V: View> ElementStateContext for ViewContext<'_, V> {
2700 fn current_view_id(&self) -> usize {
2701 self.view_id
2702 }
2703}
2704
2705pub trait Handle<T> {
2706 type Weak: 'static;
2707 fn id(&self) -> usize;
2708 fn location(&self) -> EntityLocation;
2709 fn downgrade(&self) -> Self::Weak;
2710 fn upgrade_from(weak: &Self::Weak, cx: &AppContext) -> Option<Self>
2711 where
2712 Self: Sized;
2713}
2714
2715#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
2716pub enum EntityLocation {
2717 Model(usize),
2718 View(usize, usize),
2719}
2720
2721pub struct ModelHandle<T> {
2722 model_id: usize,
2723 model_type: PhantomData<T>,
2724 ref_counts: Arc<Mutex<RefCounts>>,
2725}
2726
2727impl<T: Entity> ModelHandle<T> {
2728 fn new(model_id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
2729 ref_counts.lock().inc_model(model_id);
2730 Self {
2731 model_id,
2732 model_type: PhantomData,
2733 ref_counts: ref_counts.clone(),
2734 }
2735 }
2736
2737 pub fn downgrade(&self) -> WeakModelHandle<T> {
2738 WeakModelHandle::new(self.model_id)
2739 }
2740
2741 pub fn id(&self) -> usize {
2742 self.model_id
2743 }
2744
2745 pub fn read<'a, C: ReadModel>(&self, cx: &'a C) -> &'a T {
2746 cx.read_model(self)
2747 }
2748
2749 pub fn read_with<'a, C, F, S>(&self, cx: &C, read: F) -> S
2750 where
2751 C: ReadModelWith,
2752 F: FnOnce(&T, &AppContext) -> S,
2753 {
2754 let mut read = Some(read);
2755 cx.read_model_with(self, &mut |model, cx| {
2756 let read = read.take().unwrap();
2757 read(model, cx)
2758 })
2759 }
2760
2761 pub fn update<C, F, S>(&self, cx: &mut C, update: F) -> S
2762 where
2763 C: UpdateModel,
2764 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
2765 {
2766 let mut update = Some(update);
2767 cx.update_model(self, &mut |model, cx| {
2768 let update = update.take().unwrap();
2769 update(model, cx)
2770 })
2771 }
2772
2773 pub fn next_notification(&self, cx: &TestAppContext) -> impl Future<Output = ()> {
2774 let (mut tx, mut rx) = mpsc::channel(1);
2775 let mut cx = cx.cx.borrow_mut();
2776 let subscription = cx.observe(self, move |_, _| {
2777 tx.try_send(()).ok();
2778 });
2779
2780 let duration = if std::env::var("CI").is_ok() {
2781 Duration::from_secs(5)
2782 } else {
2783 Duration::from_secs(1)
2784 };
2785
2786 async move {
2787 let notification = timeout(duration, rx.recv())
2788 .await
2789 .expect("next notification timed out");
2790 drop(subscription);
2791 notification.expect("model dropped while test was waiting for its next notification")
2792 }
2793 }
2794
2795 pub fn next_event(&self, cx: &TestAppContext) -> impl Future<Output = T::Event>
2796 where
2797 T::Event: Clone,
2798 {
2799 let (mut tx, mut rx) = mpsc::channel(1);
2800 let mut cx = cx.cx.borrow_mut();
2801 let subscription = cx.subscribe(self, move |_, event, _| {
2802 tx.blocking_send(event.clone()).ok();
2803 });
2804
2805 let duration = if std::env::var("CI").is_ok() {
2806 Duration::from_secs(5)
2807 } else {
2808 Duration::from_secs(1)
2809 };
2810
2811 async move {
2812 let event = timeout(duration, rx.recv())
2813 .await
2814 .expect("next event timed out");
2815 drop(subscription);
2816 event.expect("model dropped while test was waiting for its next event")
2817 }
2818 }
2819
2820 pub fn condition(
2821 &self,
2822 cx: &TestAppContext,
2823 mut predicate: impl FnMut(&T, &AppContext) -> bool,
2824 ) -> impl Future<Output = ()> {
2825 let (tx, mut rx) = mpsc::channel(1024);
2826
2827 let mut cx = cx.cx.borrow_mut();
2828 let subscriptions = (
2829 cx.observe(self, {
2830 let mut tx = tx.clone();
2831 move |_, _| {
2832 tx.blocking_send(()).ok();
2833 }
2834 }),
2835 cx.subscribe(self, {
2836 let mut tx = tx.clone();
2837 move |_, _, _| {
2838 tx.blocking_send(()).ok();
2839 }
2840 }),
2841 );
2842
2843 let cx = cx.weak_self.as_ref().unwrap().upgrade().unwrap();
2844 let handle = self.downgrade();
2845 let duration = if std::env::var("CI").is_ok() {
2846 Duration::from_secs(5)
2847 } else {
2848 Duration::from_secs(1)
2849 };
2850
2851 async move {
2852 timeout(duration, async move {
2853 loop {
2854 {
2855 let cx = cx.borrow();
2856 let cx = cx.as_ref();
2857 if predicate(
2858 handle
2859 .upgrade(cx)
2860 .expect("model dropped with pending condition")
2861 .read(cx),
2862 cx,
2863 ) {
2864 break;
2865 }
2866 }
2867
2868 cx.borrow().foreground().start_waiting();
2869 rx.recv()
2870 .await
2871 .expect("model dropped with pending condition");
2872 cx.borrow().foreground().finish_waiting();
2873 }
2874 })
2875 .await
2876 .expect("condition timed out");
2877 drop(subscriptions);
2878 }
2879 }
2880}
2881
2882impl<T> Clone for ModelHandle<T> {
2883 fn clone(&self) -> Self {
2884 self.ref_counts.lock().inc_model(self.model_id);
2885 Self {
2886 model_id: self.model_id,
2887 model_type: PhantomData,
2888 ref_counts: self.ref_counts.clone(),
2889 }
2890 }
2891}
2892
2893impl<T> PartialEq for ModelHandle<T> {
2894 fn eq(&self, other: &Self) -> bool {
2895 self.model_id == other.model_id
2896 }
2897}
2898
2899impl<T> Eq for ModelHandle<T> {}
2900
2901impl<T> Hash for ModelHandle<T> {
2902 fn hash<H: Hasher>(&self, state: &mut H) {
2903 self.model_id.hash(state);
2904 }
2905}
2906
2907impl<T> std::borrow::Borrow<usize> for ModelHandle<T> {
2908 fn borrow(&self) -> &usize {
2909 &self.model_id
2910 }
2911}
2912
2913impl<T> Debug for ModelHandle<T> {
2914 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2915 f.debug_tuple(&format!("ModelHandle<{}>", type_name::<T>()))
2916 .field(&self.model_id)
2917 .finish()
2918 }
2919}
2920
2921unsafe impl<T> Send for ModelHandle<T> {}
2922unsafe impl<T> Sync for ModelHandle<T> {}
2923
2924impl<T> Drop for ModelHandle<T> {
2925 fn drop(&mut self) {
2926 self.ref_counts.lock().dec_model(self.model_id);
2927 }
2928}
2929
2930impl<T: Entity> Handle<T> for ModelHandle<T> {
2931 type Weak = WeakModelHandle<T>;
2932
2933 fn id(&self) -> usize {
2934 self.model_id
2935 }
2936
2937 fn location(&self) -> EntityLocation {
2938 EntityLocation::Model(self.model_id)
2939 }
2940
2941 fn downgrade(&self) -> Self::Weak {
2942 self.downgrade()
2943 }
2944
2945 fn upgrade_from(weak: &Self::Weak, cx: &AppContext) -> Option<Self>
2946 where
2947 Self: Sized,
2948 {
2949 weak.upgrade(cx)
2950 }
2951}
2952
2953pub struct WeakModelHandle<T> {
2954 model_id: usize,
2955 model_type: PhantomData<T>,
2956}
2957
2958unsafe impl<T> Send for WeakModelHandle<T> {}
2959unsafe impl<T> Sync for WeakModelHandle<T> {}
2960
2961impl<T: Entity> WeakModelHandle<T> {
2962 fn new(model_id: usize) -> Self {
2963 Self {
2964 model_id,
2965 model_type: PhantomData,
2966 }
2967 }
2968
2969 pub fn id(&self) -> usize {
2970 self.model_id
2971 }
2972
2973 pub fn upgrade(&self, cx: &impl UpgradeModelHandle) -> Option<ModelHandle<T>> {
2974 cx.upgrade_model_handle(self)
2975 }
2976}
2977
2978impl<T> Hash for WeakModelHandle<T> {
2979 fn hash<H: Hasher>(&self, state: &mut H) {
2980 self.model_id.hash(state)
2981 }
2982}
2983
2984impl<T> PartialEq for WeakModelHandle<T> {
2985 fn eq(&self, other: &Self) -> bool {
2986 self.model_id == other.model_id
2987 }
2988}
2989
2990impl<T> Eq for WeakModelHandle<T> {}
2991
2992impl<T> Clone for WeakModelHandle<T> {
2993 fn clone(&self) -> Self {
2994 Self {
2995 model_id: self.model_id,
2996 model_type: PhantomData,
2997 }
2998 }
2999}
3000
3001impl<T> Copy for WeakModelHandle<T> {}
3002
3003pub struct ViewHandle<T> {
3004 window_id: usize,
3005 view_id: usize,
3006 view_type: PhantomData<T>,
3007 ref_counts: Arc<Mutex<RefCounts>>,
3008}
3009
3010impl<T: View> ViewHandle<T> {
3011 fn new(window_id: usize, view_id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
3012 ref_counts.lock().inc_view(window_id, view_id);
3013 Self {
3014 window_id,
3015 view_id,
3016 view_type: PhantomData,
3017 ref_counts: ref_counts.clone(),
3018 }
3019 }
3020
3021 pub fn downgrade(&self) -> WeakViewHandle<T> {
3022 WeakViewHandle::new(self.window_id, self.view_id)
3023 }
3024
3025 pub fn window_id(&self) -> usize {
3026 self.window_id
3027 }
3028
3029 pub fn id(&self) -> usize {
3030 self.view_id
3031 }
3032
3033 pub fn read<'a, C: ReadView>(&self, cx: &'a C) -> &'a T {
3034 cx.read_view(self)
3035 }
3036
3037 pub fn read_with<C, F, S>(&self, cx: &C, read: F) -> S
3038 where
3039 C: ReadViewWith,
3040 F: FnOnce(&T, &AppContext) -> S,
3041 {
3042 let mut read = Some(read);
3043 cx.read_view_with(self, &mut |view, cx| {
3044 let read = read.take().unwrap();
3045 read(view, cx)
3046 })
3047 }
3048
3049 pub fn update<C, F, S>(&self, cx: &mut C, update: F) -> S
3050 where
3051 C: UpdateView,
3052 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
3053 {
3054 let mut update = Some(update);
3055 cx.update_view(self, &mut |view, cx| {
3056 let update = update.take().unwrap();
3057 update(view, cx)
3058 })
3059 }
3060
3061 pub fn defer<C, F>(&self, cx: &mut C, update: F)
3062 where
3063 C: AsMut<MutableAppContext>,
3064 F: 'static + FnOnce(&mut T, &mut ViewContext<T>),
3065 {
3066 let this = self.clone();
3067 cx.as_mut().defer(Box::new(move |cx| {
3068 this.update(cx, |view, cx| update(view, cx));
3069 }));
3070 }
3071
3072 pub fn is_focused(&self, cx: &AppContext) -> bool {
3073 cx.focused_view_id(self.window_id)
3074 .map_or(false, |focused_id| focused_id == self.view_id)
3075 }
3076
3077 pub fn next_notification(&self, cx: &TestAppContext) -> impl Future<Output = ()> {
3078 let (mut tx, mut rx) = mpsc::channel(1);
3079 let mut cx = cx.cx.borrow_mut();
3080 let subscription = cx.observe(self, move |_, _| {
3081 tx.try_send(()).ok();
3082 });
3083
3084 let duration = if std::env::var("CI").is_ok() {
3085 Duration::from_secs(5)
3086 } else {
3087 Duration::from_secs(1)
3088 };
3089
3090 async move {
3091 let notification = timeout(duration, rx.recv())
3092 .await
3093 .expect("next notification timed out");
3094 drop(subscription);
3095 notification.expect("model dropped while test was waiting for its next notification")
3096 }
3097 }
3098
3099 pub fn condition(
3100 &self,
3101 cx: &TestAppContext,
3102 mut predicate: impl FnMut(&T, &AppContext) -> bool,
3103 ) -> impl Future<Output = ()> {
3104 let (tx, mut rx) = mpsc::channel(1024);
3105
3106 let mut cx = cx.cx.borrow_mut();
3107 let subscriptions = self.update(&mut *cx, |_, cx| {
3108 (
3109 cx.observe(self, {
3110 let mut tx = tx.clone();
3111 move |_, _, _| {
3112 tx.blocking_send(()).ok();
3113 }
3114 }),
3115 cx.subscribe(self, {
3116 let mut tx = tx.clone();
3117 move |_, _, _, _| {
3118 tx.blocking_send(()).ok();
3119 }
3120 }),
3121 )
3122 });
3123
3124 let cx = cx.weak_self.as_ref().unwrap().upgrade().unwrap();
3125 let handle = self.downgrade();
3126 let duration = if std::env::var("CI").is_ok() {
3127 Duration::from_secs(2)
3128 } else {
3129 Duration::from_millis(500)
3130 };
3131
3132 async move {
3133 timeout(duration, async move {
3134 loop {
3135 {
3136 let cx = cx.borrow();
3137 let cx = cx.as_ref();
3138 if predicate(
3139 handle
3140 .upgrade(cx)
3141 .expect("view dropped with pending condition")
3142 .read(cx),
3143 cx,
3144 ) {
3145 break;
3146 }
3147 }
3148
3149 cx.borrow().foreground().start_waiting();
3150 rx.recv()
3151 .await
3152 .expect("view dropped with pending condition");
3153 cx.borrow().foreground().finish_waiting();
3154 }
3155 })
3156 .await
3157 .expect("condition timed out");
3158 drop(subscriptions);
3159 }
3160 }
3161}
3162
3163impl<T> Clone for ViewHandle<T> {
3164 fn clone(&self) -> Self {
3165 self.ref_counts
3166 .lock()
3167 .inc_view(self.window_id, self.view_id);
3168 Self {
3169 window_id: self.window_id,
3170 view_id: self.view_id,
3171 view_type: PhantomData,
3172 ref_counts: self.ref_counts.clone(),
3173 }
3174 }
3175}
3176
3177impl<T> PartialEq for ViewHandle<T> {
3178 fn eq(&self, other: &Self) -> bool {
3179 self.window_id == other.window_id && self.view_id == other.view_id
3180 }
3181}
3182
3183impl<T> Eq for ViewHandle<T> {}
3184
3185impl<T> Debug for ViewHandle<T> {
3186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3187 f.debug_struct(&format!("ViewHandle<{}>", type_name::<T>()))
3188 .field("window_id", &self.window_id)
3189 .field("view_id", &self.view_id)
3190 .finish()
3191 }
3192}
3193
3194impl<T> Drop for ViewHandle<T> {
3195 fn drop(&mut self) {
3196 self.ref_counts
3197 .lock()
3198 .dec_view(self.window_id, self.view_id);
3199 }
3200}
3201
3202impl<T: View> Handle<T> for ViewHandle<T> {
3203 type Weak = WeakViewHandle<T>;
3204
3205 fn id(&self) -> usize {
3206 self.view_id
3207 }
3208
3209 fn location(&self) -> EntityLocation {
3210 EntityLocation::View(self.window_id, self.view_id)
3211 }
3212
3213 fn downgrade(&self) -> Self::Weak {
3214 self.downgrade()
3215 }
3216
3217 fn upgrade_from(weak: &Self::Weak, cx: &AppContext) -> Option<Self>
3218 where
3219 Self: Sized,
3220 {
3221 weak.upgrade(cx)
3222 }
3223}
3224
3225pub struct AnyViewHandle {
3226 window_id: usize,
3227 view_id: usize,
3228 view_type: TypeId,
3229 ref_counts: Arc<Mutex<RefCounts>>,
3230}
3231
3232impl AnyViewHandle {
3233 pub fn id(&self) -> usize {
3234 self.view_id
3235 }
3236
3237 pub fn is<T: 'static>(&self) -> bool {
3238 TypeId::of::<T>() == self.view_type
3239 }
3240
3241 pub fn is_focused(&self, cx: &AppContext) -> bool {
3242 cx.focused_view_id(self.window_id)
3243 .map_or(false, |focused_id| focused_id == self.view_id)
3244 }
3245
3246 pub fn downcast<T: View>(self) -> Option<ViewHandle<T>> {
3247 if self.is::<T>() {
3248 let result = Some(ViewHandle {
3249 window_id: self.window_id,
3250 view_id: self.view_id,
3251 ref_counts: self.ref_counts.clone(),
3252 view_type: PhantomData,
3253 });
3254 unsafe {
3255 Arc::decrement_strong_count(&self.ref_counts);
3256 }
3257 std::mem::forget(self);
3258 result
3259 } else {
3260 None
3261 }
3262 }
3263}
3264
3265impl Clone for AnyViewHandle {
3266 fn clone(&self) -> Self {
3267 self.ref_counts
3268 .lock()
3269 .inc_view(self.window_id, self.view_id);
3270 Self {
3271 window_id: self.window_id,
3272 view_id: self.view_id,
3273 view_type: self.view_type,
3274 ref_counts: self.ref_counts.clone(),
3275 }
3276 }
3277}
3278
3279impl From<&AnyViewHandle> for AnyViewHandle {
3280 fn from(handle: &AnyViewHandle) -> Self {
3281 handle.clone()
3282 }
3283}
3284
3285impl<T: View> From<&ViewHandle<T>> for AnyViewHandle {
3286 fn from(handle: &ViewHandle<T>) -> Self {
3287 handle
3288 .ref_counts
3289 .lock()
3290 .inc_view(handle.window_id, handle.view_id);
3291 AnyViewHandle {
3292 window_id: handle.window_id,
3293 view_id: handle.view_id,
3294 view_type: TypeId::of::<T>(),
3295 ref_counts: handle.ref_counts.clone(),
3296 }
3297 }
3298}
3299
3300impl<T: View> From<ViewHandle<T>> for AnyViewHandle {
3301 fn from(handle: ViewHandle<T>) -> Self {
3302 let any_handle = AnyViewHandle {
3303 window_id: handle.window_id,
3304 view_id: handle.view_id,
3305 view_type: TypeId::of::<T>(),
3306 ref_counts: handle.ref_counts.clone(),
3307 };
3308 unsafe {
3309 Arc::decrement_strong_count(&handle.ref_counts);
3310 }
3311 std::mem::forget(handle);
3312 any_handle
3313 }
3314}
3315
3316impl Drop for AnyViewHandle {
3317 fn drop(&mut self) {
3318 self.ref_counts
3319 .lock()
3320 .dec_view(self.window_id, self.view_id);
3321 }
3322}
3323
3324pub struct AnyModelHandle {
3325 model_id: usize,
3326 model_type: TypeId,
3327 ref_counts: Arc<Mutex<RefCounts>>,
3328}
3329
3330impl AnyModelHandle {
3331 pub fn downcast<T: Entity>(self) -> Option<ModelHandle<T>> {
3332 if self.is::<T>() {
3333 let result = Some(ModelHandle {
3334 model_id: self.model_id,
3335 model_type: PhantomData,
3336 ref_counts: self.ref_counts.clone(),
3337 });
3338 unsafe {
3339 Arc::decrement_strong_count(&self.ref_counts);
3340 }
3341 std::mem::forget(self);
3342 result
3343 } else {
3344 None
3345 }
3346 }
3347
3348 pub fn downgrade(&self) -> AnyWeakModelHandle {
3349 AnyWeakModelHandle {
3350 model_id: self.model_id,
3351 model_type: self.model_type,
3352 }
3353 }
3354
3355 pub fn is<T: Entity>(&self) -> bool {
3356 self.model_type == TypeId::of::<T>()
3357 }
3358}
3359
3360impl<T: Entity> From<ModelHandle<T>> for AnyModelHandle {
3361 fn from(handle: ModelHandle<T>) -> Self {
3362 handle.ref_counts.lock().inc_model(handle.model_id);
3363 Self {
3364 model_id: handle.model_id,
3365 model_type: TypeId::of::<T>(),
3366 ref_counts: handle.ref_counts.clone(),
3367 }
3368 }
3369}
3370
3371impl Clone for AnyModelHandle {
3372 fn clone(&self) -> Self {
3373 self.ref_counts.lock().inc_model(self.model_id);
3374 Self {
3375 model_id: self.model_id,
3376 model_type: self.model_type,
3377 ref_counts: self.ref_counts.clone(),
3378 }
3379 }
3380}
3381
3382impl Drop for AnyModelHandle {
3383 fn drop(&mut self) {
3384 self.ref_counts.lock().dec_model(self.model_id);
3385 }
3386}
3387
3388pub struct AnyWeakModelHandle {
3389 model_id: usize,
3390 model_type: TypeId,
3391}
3392
3393impl AnyWeakModelHandle {
3394 pub fn upgrade(&self, cx: &impl UpgradeModelHandle) -> Option<AnyModelHandle> {
3395 cx.upgrade_any_model_handle(self)
3396 }
3397}
3398
3399pub struct WeakViewHandle<T> {
3400 window_id: usize,
3401 view_id: usize,
3402 view_type: PhantomData<T>,
3403}
3404
3405impl<T: View> WeakViewHandle<T> {
3406 fn new(window_id: usize, view_id: usize) -> Self {
3407 Self {
3408 window_id,
3409 view_id,
3410 view_type: PhantomData,
3411 }
3412 }
3413
3414 pub fn id(&self) -> usize {
3415 self.view_id
3416 }
3417
3418 pub fn upgrade(&self, cx: &impl UpgradeViewHandle) -> Option<ViewHandle<T>> {
3419 cx.upgrade_view_handle(self)
3420 }
3421}
3422
3423impl<T> Clone for WeakViewHandle<T> {
3424 fn clone(&self) -> Self {
3425 Self {
3426 window_id: self.window_id,
3427 view_id: self.view_id,
3428 view_type: PhantomData,
3429 }
3430 }
3431}
3432
3433impl<T> PartialEq for WeakViewHandle<T> {
3434 fn eq(&self, other: &Self) -> bool {
3435 self.window_id == other.window_id && self.view_id == other.view_id
3436 }
3437}
3438
3439impl<T> Eq for WeakViewHandle<T> {}
3440
3441impl<T> Hash for WeakViewHandle<T> {
3442 fn hash<H: Hasher>(&self, state: &mut H) {
3443 self.window_id.hash(state);
3444 self.view_id.hash(state);
3445 }
3446}
3447
3448#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
3449pub struct ElementStateId {
3450 view_id: usize,
3451 element_id: usize,
3452 tag: TypeId,
3453}
3454
3455pub struct ElementStateHandle<T> {
3456 value_type: PhantomData<T>,
3457 id: ElementStateId,
3458 ref_counts: Weak<Mutex<RefCounts>>,
3459}
3460
3461impl<T: 'static> ElementStateHandle<T> {
3462 fn new(id: ElementStateId, frame_id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
3463 ref_counts.lock().inc_element_state(id, frame_id);
3464 Self {
3465 value_type: PhantomData,
3466 id,
3467 ref_counts: Arc::downgrade(ref_counts),
3468 }
3469 }
3470
3471 pub fn read<'a>(&self, cx: &'a AppContext) -> &'a T {
3472 cx.element_states
3473 .get(&self.id)
3474 .unwrap()
3475 .downcast_ref()
3476 .unwrap()
3477 }
3478
3479 pub fn update<C, R>(&self, cx: &mut C, f: impl FnOnce(&mut T, &mut C) -> R) -> R
3480 where
3481 C: DerefMut<Target = MutableAppContext>,
3482 {
3483 let mut element_state = cx.deref_mut().cx.element_states.remove(&self.id).unwrap();
3484 let result = f(element_state.downcast_mut().unwrap(), cx);
3485 cx.deref_mut()
3486 .cx
3487 .element_states
3488 .insert(self.id, element_state);
3489 result
3490 }
3491}
3492
3493impl<T> Drop for ElementStateHandle<T> {
3494 fn drop(&mut self) {
3495 if let Some(ref_counts) = self.ref_counts.upgrade() {
3496 ref_counts.lock().dec_element_state(self.id);
3497 }
3498 }
3499}
3500
3501pub struct CursorStyleHandle {
3502 id: usize,
3503 next_cursor_style_handle_id: Arc<AtomicUsize>,
3504 platform: Arc<dyn Platform>,
3505}
3506
3507impl Drop for CursorStyleHandle {
3508 fn drop(&mut self) {
3509 if self.id + 1 == self.next_cursor_style_handle_id.load(SeqCst) {
3510 self.platform.set_cursor_style(CursorStyle::Arrow);
3511 }
3512 }
3513}
3514
3515#[must_use]
3516pub enum Subscription {
3517 Subscription {
3518 id: usize,
3519 entity_id: usize,
3520 subscriptions: Option<Weak<Mutex<HashMap<usize, BTreeMap<usize, SubscriptionCallback>>>>>,
3521 },
3522 Observation {
3523 id: usize,
3524 entity_id: usize,
3525 observations: Option<Weak<Mutex<HashMap<usize, BTreeMap<usize, ObservationCallback>>>>>,
3526 },
3527 ReleaseObservation {
3528 id: usize,
3529 entity_id: usize,
3530 observations:
3531 Option<Weak<Mutex<HashMap<usize, BTreeMap<usize, ReleaseObservationCallback>>>>>,
3532 },
3533}
3534
3535impl Subscription {
3536 pub fn detach(&mut self) {
3537 match self {
3538 Subscription::Subscription { subscriptions, .. } => {
3539 subscriptions.take();
3540 }
3541 Subscription::Observation { observations, .. } => {
3542 observations.take();
3543 }
3544 Subscription::ReleaseObservation { observations, .. } => {
3545 observations.take();
3546 }
3547 }
3548 }
3549}
3550
3551impl Drop for Subscription {
3552 fn drop(&mut self) {
3553 match self {
3554 Subscription::Observation {
3555 id,
3556 entity_id,
3557 observations,
3558 } => {
3559 if let Some(observations) = observations.as_ref().and_then(Weak::upgrade) {
3560 if let Some(observations) = observations.lock().get_mut(entity_id) {
3561 observations.remove(id);
3562 }
3563 }
3564 }
3565 Subscription::ReleaseObservation {
3566 id,
3567 entity_id,
3568 observations,
3569 } => {
3570 if let Some(observations) = observations.as_ref().and_then(Weak::upgrade) {
3571 if let Some(observations) = observations.lock().get_mut(entity_id) {
3572 observations.remove(id);
3573 }
3574 }
3575 }
3576 Subscription::Subscription {
3577 id,
3578 entity_id,
3579 subscriptions,
3580 } => {
3581 if let Some(subscriptions) = subscriptions.as_ref().and_then(Weak::upgrade) {
3582 if let Some(subscriptions) = subscriptions.lock().get_mut(entity_id) {
3583 subscriptions.remove(id);
3584 }
3585 }
3586 }
3587 }
3588 }
3589}
3590
3591#[derive(Default)]
3592struct RefCounts {
3593 entity_counts: HashMap<usize, usize>,
3594 element_state_counts: HashMap<ElementStateId, ElementStateRefCount>,
3595 dropped_models: HashSet<usize>,
3596 dropped_views: HashSet<(usize, usize)>,
3597 dropped_element_states: HashSet<ElementStateId>,
3598}
3599
3600struct ElementStateRefCount {
3601 ref_count: usize,
3602 frame_id: usize,
3603}
3604
3605impl RefCounts {
3606 fn inc_model(&mut self, model_id: usize) {
3607 match self.entity_counts.entry(model_id) {
3608 Entry::Occupied(mut entry) => {
3609 *entry.get_mut() += 1;
3610 }
3611 Entry::Vacant(entry) => {
3612 entry.insert(1);
3613 self.dropped_models.remove(&model_id);
3614 }
3615 }
3616 }
3617
3618 fn inc_view(&mut self, window_id: usize, view_id: usize) {
3619 match self.entity_counts.entry(view_id) {
3620 Entry::Occupied(mut entry) => *entry.get_mut() += 1,
3621 Entry::Vacant(entry) => {
3622 entry.insert(1);
3623 self.dropped_views.remove(&(window_id, view_id));
3624 }
3625 }
3626 }
3627
3628 fn inc_element_state(&mut self, id: ElementStateId, frame_id: usize) {
3629 match self.element_state_counts.entry(id) {
3630 Entry::Occupied(mut entry) => {
3631 let entry = entry.get_mut();
3632 if entry.frame_id == frame_id || entry.ref_count >= 2 {
3633 panic!("used the same element state more than once in the same frame");
3634 }
3635 entry.ref_count += 1;
3636 entry.frame_id = frame_id;
3637 }
3638 Entry::Vacant(entry) => {
3639 entry.insert(ElementStateRefCount {
3640 ref_count: 1,
3641 frame_id,
3642 });
3643 self.dropped_element_states.remove(&id);
3644 }
3645 }
3646 }
3647
3648 fn dec_model(&mut self, model_id: usize) {
3649 let count = self.entity_counts.get_mut(&model_id).unwrap();
3650 *count -= 1;
3651 if *count == 0 {
3652 self.entity_counts.remove(&model_id);
3653 self.dropped_models.insert(model_id);
3654 }
3655 }
3656
3657 fn dec_view(&mut self, window_id: usize, view_id: usize) {
3658 let count = self.entity_counts.get_mut(&view_id).unwrap();
3659 *count -= 1;
3660 if *count == 0 {
3661 self.entity_counts.remove(&view_id);
3662 self.dropped_views.insert((window_id, view_id));
3663 }
3664 }
3665
3666 fn dec_element_state(&mut self, id: ElementStateId) {
3667 let entry = self.element_state_counts.get_mut(&id).unwrap();
3668 entry.ref_count -= 1;
3669 if entry.ref_count == 0 {
3670 self.element_state_counts.remove(&id);
3671 self.dropped_element_states.insert(id);
3672 }
3673 }
3674
3675 fn is_entity_alive(&self, entity_id: usize) -> bool {
3676 self.entity_counts.contains_key(&entity_id)
3677 }
3678
3679 fn take_dropped(
3680 &mut self,
3681 ) -> (
3682 HashSet<usize>,
3683 HashSet<(usize, usize)>,
3684 HashSet<ElementStateId>,
3685 ) {
3686 (
3687 std::mem::take(&mut self.dropped_models),
3688 std::mem::take(&mut self.dropped_views),
3689 std::mem::take(&mut self.dropped_element_states),
3690 )
3691 }
3692}
3693
3694#[cfg(test)]
3695mod tests {
3696 use super::*;
3697 use crate::elements::*;
3698 use smol::future::poll_once;
3699 use std::{
3700 cell::Cell,
3701 sync::atomic::{AtomicUsize, Ordering::SeqCst},
3702 };
3703
3704 #[crate::test(self)]
3705 fn test_model_handles(cx: &mut MutableAppContext) {
3706 struct Model {
3707 other: Option<ModelHandle<Model>>,
3708 events: Vec<String>,
3709 }
3710
3711 impl Entity for Model {
3712 type Event = usize;
3713 }
3714
3715 impl Model {
3716 fn new(other: Option<ModelHandle<Self>>, cx: &mut ModelContext<Self>) -> Self {
3717 if let Some(other) = other.as_ref() {
3718 cx.observe(other, |me, _, _| {
3719 me.events.push("notified".into());
3720 })
3721 .detach();
3722 cx.subscribe(other, |me, _, event, _| {
3723 me.events.push(format!("observed event {}", event));
3724 })
3725 .detach();
3726 }
3727
3728 Self {
3729 other,
3730 events: Vec::new(),
3731 }
3732 }
3733 }
3734
3735 let handle_1 = cx.add_model(|cx| Model::new(None, cx));
3736 let handle_2 = cx.add_model(|cx| Model::new(Some(handle_1.clone()), cx));
3737 assert_eq!(cx.cx.models.len(), 2);
3738
3739 handle_1.update(cx, |model, cx| {
3740 model.events.push("updated".into());
3741 cx.emit(1);
3742 cx.notify();
3743 cx.emit(2);
3744 });
3745 assert_eq!(handle_1.read(cx).events, vec!["updated".to_string()]);
3746 assert_eq!(
3747 handle_2.read(cx).events,
3748 vec![
3749 "observed event 1".to_string(),
3750 "notified".to_string(),
3751 "observed event 2".to_string(),
3752 ]
3753 );
3754
3755 handle_2.update(cx, |model, _| {
3756 drop(handle_1);
3757 model.other.take();
3758 });
3759
3760 assert_eq!(cx.cx.models.len(), 1);
3761 assert!(cx.subscriptions.lock().is_empty());
3762 assert!(cx.observations.lock().is_empty());
3763 }
3764
3765 #[crate::test(self)]
3766 fn test_subscribe_and_emit_from_model(cx: &mut MutableAppContext) {
3767 #[derive(Default)]
3768 struct Model {
3769 events: Vec<usize>,
3770 }
3771
3772 impl Entity for Model {
3773 type Event = usize;
3774 }
3775
3776 let handle_1 = cx.add_model(|_| Model::default());
3777 let handle_2 = cx.add_model(|_| Model::default());
3778 let handle_2b = handle_2.clone();
3779
3780 handle_1.update(cx, |_, c| {
3781 c.subscribe(&handle_2, move |model: &mut Model, _, event, c| {
3782 model.events.push(*event);
3783
3784 c.subscribe(&handle_2b, |model, _, event, _| {
3785 model.events.push(*event * 2);
3786 })
3787 .detach();
3788 })
3789 .detach();
3790 });
3791
3792 handle_2.update(cx, |_, c| c.emit(7));
3793 assert_eq!(handle_1.read(cx).events, vec![7]);
3794
3795 handle_2.update(cx, |_, c| c.emit(5));
3796 assert_eq!(handle_1.read(cx).events, vec![7, 5, 10]);
3797 }
3798
3799 #[crate::test(self)]
3800 fn test_observe_and_notify_from_model(cx: &mut MutableAppContext) {
3801 #[derive(Default)]
3802 struct Model {
3803 count: usize,
3804 events: Vec<usize>,
3805 }
3806
3807 impl Entity for Model {
3808 type Event = ();
3809 }
3810
3811 let handle_1 = cx.add_model(|_| Model::default());
3812 let handle_2 = cx.add_model(|_| Model::default());
3813 let handle_2b = handle_2.clone();
3814
3815 handle_1.update(cx, |_, c| {
3816 c.observe(&handle_2, move |model, observed, c| {
3817 model.events.push(observed.read(c).count);
3818 c.observe(&handle_2b, |model, observed, c| {
3819 model.events.push(observed.read(c).count * 2);
3820 })
3821 .detach();
3822 })
3823 .detach();
3824 });
3825
3826 handle_2.update(cx, |model, c| {
3827 model.count = 7;
3828 c.notify()
3829 });
3830 assert_eq!(handle_1.read(cx).events, vec![7]);
3831
3832 handle_2.update(cx, |model, c| {
3833 model.count = 5;
3834 c.notify()
3835 });
3836 assert_eq!(handle_1.read(cx).events, vec![7, 5, 10])
3837 }
3838
3839 #[crate::test(self)]
3840 fn test_view_handles(cx: &mut MutableAppContext) {
3841 struct View {
3842 other: Option<ViewHandle<View>>,
3843 events: Vec<String>,
3844 }
3845
3846 impl Entity for View {
3847 type Event = usize;
3848 }
3849
3850 impl super::View for View {
3851 fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
3852 Empty::new().boxed()
3853 }
3854
3855 fn ui_name() -> &'static str {
3856 "View"
3857 }
3858 }
3859
3860 impl View {
3861 fn new(other: Option<ViewHandle<View>>, cx: &mut ViewContext<Self>) -> Self {
3862 if let Some(other) = other.as_ref() {
3863 cx.subscribe(other, |me, _, event, _| {
3864 me.events.push(format!("observed event {}", event));
3865 })
3866 .detach();
3867 }
3868 Self {
3869 other,
3870 events: Vec::new(),
3871 }
3872 }
3873 }
3874
3875 let (window_id, _) = cx.add_window(Default::default(), |cx| View::new(None, cx));
3876 let handle_1 = cx.add_view(window_id, |cx| View::new(None, cx));
3877 let handle_2 = cx.add_view(window_id, |cx| View::new(Some(handle_1.clone()), cx));
3878 assert_eq!(cx.cx.views.len(), 3);
3879
3880 handle_1.update(cx, |view, cx| {
3881 view.events.push("updated".into());
3882 cx.emit(1);
3883 cx.emit(2);
3884 });
3885 assert_eq!(handle_1.read(cx).events, vec!["updated".to_string()]);
3886 assert_eq!(
3887 handle_2.read(cx).events,
3888 vec![
3889 "observed event 1".to_string(),
3890 "observed event 2".to_string(),
3891 ]
3892 );
3893
3894 handle_2.update(cx, |view, _| {
3895 drop(handle_1);
3896 view.other.take();
3897 });
3898
3899 assert_eq!(cx.cx.views.len(), 2);
3900 assert!(cx.subscriptions.lock().is_empty());
3901 assert!(cx.observations.lock().is_empty());
3902 }
3903
3904 #[crate::test(self)]
3905 fn test_add_window(cx: &mut MutableAppContext) {
3906 struct View {
3907 mouse_down_count: Arc<AtomicUsize>,
3908 }
3909
3910 impl Entity for View {
3911 type Event = ();
3912 }
3913
3914 impl super::View for View {
3915 fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
3916 let mouse_down_count = self.mouse_down_count.clone();
3917 EventHandler::new(Empty::new().boxed())
3918 .on_mouse_down(move |_| {
3919 mouse_down_count.fetch_add(1, SeqCst);
3920 true
3921 })
3922 .boxed()
3923 }
3924
3925 fn ui_name() -> &'static str {
3926 "View"
3927 }
3928 }
3929
3930 let mouse_down_count = Arc::new(AtomicUsize::new(0));
3931 let (window_id, _) = cx.add_window(Default::default(), |_| View {
3932 mouse_down_count: mouse_down_count.clone(),
3933 });
3934 let presenter = cx.presenters_and_platform_windows[&window_id].0.clone();
3935 // Ensure window's root element is in a valid lifecycle state.
3936 presenter.borrow_mut().dispatch_event(
3937 Event::LeftMouseDown {
3938 position: Default::default(),
3939 ctrl: false,
3940 alt: false,
3941 shift: false,
3942 cmd: false,
3943 click_count: 1,
3944 },
3945 cx,
3946 );
3947 assert_eq!(mouse_down_count.load(SeqCst), 1);
3948 }
3949
3950 #[crate::test(self)]
3951 fn test_entity_release_hooks(cx: &mut MutableAppContext) {
3952 struct Model {
3953 released: Rc<Cell<bool>>,
3954 }
3955
3956 struct View {
3957 released: Rc<Cell<bool>>,
3958 }
3959
3960 impl Entity for Model {
3961 type Event = ();
3962
3963 fn release(&mut self, _: &mut MutableAppContext) {
3964 self.released.set(true);
3965 }
3966 }
3967
3968 impl Entity for View {
3969 type Event = ();
3970
3971 fn release(&mut self, _: &mut MutableAppContext) {
3972 self.released.set(true);
3973 }
3974 }
3975
3976 impl super::View for View {
3977 fn ui_name() -> &'static str {
3978 "View"
3979 }
3980
3981 fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
3982 Empty::new().boxed()
3983 }
3984 }
3985
3986 let model_released = Rc::new(Cell::new(false));
3987 let model_release_observed = Rc::new(Cell::new(false));
3988 let view_released = Rc::new(Cell::new(false));
3989 let view_release_observed = Rc::new(Cell::new(false));
3990
3991 let model = cx.add_model(|_| Model {
3992 released: model_released.clone(),
3993 });
3994 let (window_id, view) = cx.add_window(Default::default(), |_| View {
3995 released: view_released.clone(),
3996 });
3997 assert!(!model_released.get());
3998 assert!(!view_released.get());
3999
4000 cx.observe_release(&model, {
4001 let model_release_observed = model_release_observed.clone();
4002 move |_| model_release_observed.set(true)
4003 })
4004 .detach();
4005 cx.observe_release(&view, {
4006 let view_release_observed = view_release_observed.clone();
4007 move |_| view_release_observed.set(true)
4008 })
4009 .detach();
4010
4011 cx.update(move |_| {
4012 drop(model);
4013 });
4014 assert!(model_released.get());
4015 assert!(model_release_observed.get());
4016
4017 drop(view);
4018 cx.remove_window(window_id);
4019 assert!(view_released.get());
4020 assert!(view_release_observed.get());
4021 }
4022
4023 #[crate::test(self)]
4024 fn test_subscribe_and_emit_from_view(cx: &mut MutableAppContext) {
4025 #[derive(Default)]
4026 struct View {
4027 events: Vec<usize>,
4028 }
4029
4030 impl Entity for View {
4031 type Event = usize;
4032 }
4033
4034 impl super::View for View {
4035 fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
4036 Empty::new().boxed()
4037 }
4038
4039 fn ui_name() -> &'static str {
4040 "View"
4041 }
4042 }
4043
4044 struct Model;
4045
4046 impl Entity for Model {
4047 type Event = usize;
4048 }
4049
4050 let (window_id, handle_1) = cx.add_window(Default::default(), |_| View::default());
4051 let handle_2 = cx.add_view(window_id, |_| View::default());
4052 let handle_2b = handle_2.clone();
4053 let handle_3 = cx.add_model(|_| Model);
4054
4055 handle_1.update(cx, |_, c| {
4056 c.subscribe(&handle_2, move |me, _, event, c| {
4057 me.events.push(*event);
4058
4059 c.subscribe(&handle_2b, |me, _, event, _| {
4060 me.events.push(*event * 2);
4061 })
4062 .detach();
4063 })
4064 .detach();
4065
4066 c.subscribe(&handle_3, |me, _, event, _| {
4067 me.events.push(*event);
4068 })
4069 .detach();
4070 });
4071
4072 handle_2.update(cx, |_, c| c.emit(7));
4073 assert_eq!(handle_1.read(cx).events, vec![7]);
4074
4075 handle_2.update(cx, |_, c| c.emit(5));
4076 assert_eq!(handle_1.read(cx).events, vec![7, 5, 10]);
4077
4078 handle_3.update(cx, |_, c| c.emit(9));
4079 assert_eq!(handle_1.read(cx).events, vec![7, 5, 10, 9]);
4080 }
4081
4082 #[crate::test(self)]
4083 fn test_dropping_subscribers(cx: &mut MutableAppContext) {
4084 struct View;
4085
4086 impl Entity for View {
4087 type Event = ();
4088 }
4089
4090 impl super::View for View {
4091 fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
4092 Empty::new().boxed()
4093 }
4094
4095 fn ui_name() -> &'static str {
4096 "View"
4097 }
4098 }
4099
4100 struct Model;
4101
4102 impl Entity for Model {
4103 type Event = ();
4104 }
4105
4106 let (window_id, _) = cx.add_window(Default::default(), |_| View);
4107 let observing_view = cx.add_view(window_id, |_| View);
4108 let emitting_view = cx.add_view(window_id, |_| View);
4109 let observing_model = cx.add_model(|_| Model);
4110 let observed_model = cx.add_model(|_| Model);
4111
4112 observing_view.update(cx, |_, cx| {
4113 cx.subscribe(&emitting_view, |_, _, _, _| {}).detach();
4114 cx.subscribe(&observed_model, |_, _, _, _| {}).detach();
4115 });
4116 observing_model.update(cx, |_, cx| {
4117 cx.subscribe(&observed_model, |_, _, _, _| {}).detach();
4118 });
4119
4120 cx.update(|_| {
4121 drop(observing_view);
4122 drop(observing_model);
4123 });
4124
4125 emitting_view.update(cx, |_, cx| cx.emit(()));
4126 observed_model.update(cx, |_, cx| cx.emit(()));
4127 }
4128
4129 #[crate::test(self)]
4130 fn test_observe_and_notify_from_view(cx: &mut MutableAppContext) {
4131 #[derive(Default)]
4132 struct View {
4133 events: Vec<usize>,
4134 }
4135
4136 impl Entity for View {
4137 type Event = usize;
4138 }
4139
4140 impl super::View for View {
4141 fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
4142 Empty::new().boxed()
4143 }
4144
4145 fn ui_name() -> &'static str {
4146 "View"
4147 }
4148 }
4149
4150 #[derive(Default)]
4151 struct Model {
4152 count: usize,
4153 }
4154
4155 impl Entity for Model {
4156 type Event = ();
4157 }
4158
4159 let (_, view) = cx.add_window(Default::default(), |_| View::default());
4160 let model = cx.add_model(|_| Model::default());
4161
4162 view.update(cx, |_, c| {
4163 c.observe(&model, |me, observed, c| {
4164 me.events.push(observed.read(c).count)
4165 })
4166 .detach();
4167 });
4168
4169 model.update(cx, |model, c| {
4170 model.count = 11;
4171 c.notify();
4172 });
4173 assert_eq!(view.read(cx).events, vec![11]);
4174 }
4175
4176 #[crate::test(self)]
4177 fn test_dropping_observers(cx: &mut MutableAppContext) {
4178 struct View;
4179
4180 impl Entity for View {
4181 type Event = ();
4182 }
4183
4184 impl super::View for View {
4185 fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
4186 Empty::new().boxed()
4187 }
4188
4189 fn ui_name() -> &'static str {
4190 "View"
4191 }
4192 }
4193
4194 struct Model;
4195
4196 impl Entity for Model {
4197 type Event = ();
4198 }
4199
4200 let (window_id, _) = cx.add_window(Default::default(), |_| View);
4201 let observing_view = cx.add_view(window_id, |_| View);
4202 let observing_model = cx.add_model(|_| Model);
4203 let observed_model = cx.add_model(|_| Model);
4204
4205 observing_view.update(cx, |_, cx| {
4206 cx.observe(&observed_model, |_, _, _| {}).detach();
4207 });
4208 observing_model.update(cx, |_, cx| {
4209 cx.observe(&observed_model, |_, _, _| {}).detach();
4210 });
4211
4212 cx.update(|_| {
4213 drop(observing_view);
4214 drop(observing_model);
4215 });
4216
4217 observed_model.update(cx, |_, cx| cx.notify());
4218 }
4219
4220 #[crate::test(self)]
4221 fn test_focus(cx: &mut MutableAppContext) {
4222 struct View {
4223 name: String,
4224 events: Arc<Mutex<Vec<String>>>,
4225 }
4226
4227 impl Entity for View {
4228 type Event = ();
4229 }
4230
4231 impl super::View for View {
4232 fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
4233 Empty::new().boxed()
4234 }
4235
4236 fn ui_name() -> &'static str {
4237 "View"
4238 }
4239
4240 fn on_focus(&mut self, _: &mut ViewContext<Self>) {
4241 self.events.lock().push(format!("{} focused", &self.name));
4242 }
4243
4244 fn on_blur(&mut self, _: &mut ViewContext<Self>) {
4245 self.events.lock().push(format!("{} blurred", &self.name));
4246 }
4247 }
4248
4249 let events: Arc<Mutex<Vec<String>>> = Default::default();
4250 let (window_id, view_1) = cx.add_window(Default::default(), |_| View {
4251 events: events.clone(),
4252 name: "view 1".to_string(),
4253 });
4254 let view_2 = cx.add_view(window_id, |_| View {
4255 events: events.clone(),
4256 name: "view 2".to_string(),
4257 });
4258
4259 view_1.update(cx, |_, cx| cx.focus(&view_2));
4260 view_1.update(cx, |_, cx| cx.focus(&view_1));
4261 view_1.update(cx, |_, cx| cx.focus(&view_2));
4262 view_1.update(cx, |_, _| drop(view_2));
4263
4264 assert_eq!(
4265 *events.lock(),
4266 [
4267 "view 1 focused".to_string(),
4268 "view 1 blurred".to_string(),
4269 "view 2 focused".to_string(),
4270 "view 2 blurred".to_string(),
4271 "view 1 focused".to_string(),
4272 "view 1 blurred".to_string(),
4273 "view 2 focused".to_string(),
4274 "view 1 focused".to_string(),
4275 ],
4276 );
4277 }
4278
4279 #[crate::test(self)]
4280 fn test_dispatch_action(cx: &mut MutableAppContext) {
4281 struct ViewA {
4282 id: usize,
4283 }
4284
4285 impl Entity for ViewA {
4286 type Event = ();
4287 }
4288
4289 impl View for ViewA {
4290 fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
4291 Empty::new().boxed()
4292 }
4293
4294 fn ui_name() -> &'static str {
4295 "View"
4296 }
4297 }
4298
4299 struct ViewB {
4300 id: usize,
4301 }
4302
4303 impl Entity for ViewB {
4304 type Event = ();
4305 }
4306
4307 impl View for ViewB {
4308 fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
4309 Empty::new().boxed()
4310 }
4311
4312 fn ui_name() -> &'static str {
4313 "View"
4314 }
4315 }
4316
4317 action!(Action, &'static str);
4318
4319 let actions = Rc::new(RefCell::new(Vec::new()));
4320
4321 let actions_clone = actions.clone();
4322 cx.add_global_action(move |_: &Action, _: &mut MutableAppContext| {
4323 actions_clone.borrow_mut().push("global".to_string());
4324 });
4325
4326 let actions_clone = actions.clone();
4327 cx.add_action(move |view: &mut ViewA, action: &Action, cx| {
4328 assert_eq!(action.0, "bar");
4329 cx.propagate_action();
4330 actions_clone.borrow_mut().push(format!("{} a", view.id));
4331 });
4332
4333 let actions_clone = actions.clone();
4334 cx.add_action(move |view: &mut ViewA, _: &Action, cx| {
4335 if view.id != 1 {
4336 cx.propagate_action();
4337 }
4338 actions_clone.borrow_mut().push(format!("{} b", view.id));
4339 });
4340
4341 let actions_clone = actions.clone();
4342 cx.add_action(move |view: &mut ViewB, _: &Action, cx| {
4343 cx.propagate_action();
4344 actions_clone.borrow_mut().push(format!("{} c", view.id));
4345 });
4346
4347 let actions_clone = actions.clone();
4348 cx.add_action(move |view: &mut ViewB, _: &Action, cx| {
4349 cx.propagate_action();
4350 actions_clone.borrow_mut().push(format!("{} d", view.id));
4351 });
4352
4353 let (window_id, view_1) = cx.add_window(Default::default(), |_| ViewA { id: 1 });
4354 let view_2 = cx.add_view(window_id, |_| ViewB { id: 2 });
4355 let view_3 = cx.add_view(window_id, |_| ViewA { id: 3 });
4356 let view_4 = cx.add_view(window_id, |_| ViewB { id: 4 });
4357
4358 cx.dispatch_action(
4359 window_id,
4360 vec![view_1.id(), view_2.id(), view_3.id(), view_4.id()],
4361 &Action("bar"),
4362 );
4363
4364 assert_eq!(
4365 *actions.borrow(),
4366 vec!["4 d", "4 c", "3 b", "3 a", "2 d", "2 c", "1 b"]
4367 );
4368
4369 // Remove view_1, which doesn't propagate the action
4370 actions.borrow_mut().clear();
4371 cx.dispatch_action(
4372 window_id,
4373 vec![view_2.id(), view_3.id(), view_4.id()],
4374 &Action("bar"),
4375 );
4376
4377 assert_eq!(
4378 *actions.borrow(),
4379 vec!["4 d", "4 c", "3 b", "3 a", "2 d", "2 c", "global"]
4380 );
4381 }
4382
4383 #[crate::test(self)]
4384 fn test_dispatch_keystroke(cx: &mut MutableAppContext) {
4385 use std::cell::Cell;
4386
4387 action!(Action, &'static str);
4388
4389 struct View {
4390 id: usize,
4391 keymap_context: keymap::Context,
4392 }
4393
4394 impl Entity for View {
4395 type Event = ();
4396 }
4397
4398 impl super::View for View {
4399 fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
4400 Empty::new().boxed()
4401 }
4402
4403 fn ui_name() -> &'static str {
4404 "View"
4405 }
4406
4407 fn keymap_context(&self, _: &AppContext) -> keymap::Context {
4408 self.keymap_context.clone()
4409 }
4410 }
4411
4412 impl View {
4413 fn new(id: usize) -> Self {
4414 View {
4415 id,
4416 keymap_context: keymap::Context::default(),
4417 }
4418 }
4419 }
4420
4421 let mut view_1 = View::new(1);
4422 let mut view_2 = View::new(2);
4423 let mut view_3 = View::new(3);
4424 view_1.keymap_context.set.insert("a".into());
4425 view_2.keymap_context.set.insert("a".into());
4426 view_2.keymap_context.set.insert("b".into());
4427 view_3.keymap_context.set.insert("a".into());
4428 view_3.keymap_context.set.insert("b".into());
4429 view_3.keymap_context.set.insert("c".into());
4430
4431 let (window_id, view_1) = cx.add_window(Default::default(), |_| view_1);
4432 let view_2 = cx.add_view(window_id, |_| view_2);
4433 let view_3 = cx.add_view(window_id, |_| view_3);
4434
4435 // This keymap's only binding dispatches an action on view 2 because that view will have
4436 // "a" and "b" in its context, but not "c".
4437 cx.add_bindings(vec![keymap::Binding::new(
4438 "a",
4439 Action("a"),
4440 Some("a && b && !c"),
4441 )]);
4442
4443 let handled_action = Rc::new(Cell::new(false));
4444 let handled_action_clone = handled_action.clone();
4445 cx.add_action(move |view: &mut View, action: &Action, _| {
4446 handled_action_clone.set(true);
4447 assert_eq!(view.id, 2);
4448 assert_eq!(action.0, "a");
4449 });
4450
4451 cx.dispatch_keystroke(
4452 window_id,
4453 vec![view_1.id(), view_2.id(), view_3.id()],
4454 &Keystroke::parse("a").unwrap(),
4455 )
4456 .unwrap();
4457
4458 assert!(handled_action.get());
4459 }
4460
4461 #[crate::test(self)]
4462 async fn test_model_condition(mut cx: TestAppContext) {
4463 struct Counter(usize);
4464
4465 impl super::Entity for Counter {
4466 type Event = ();
4467 }
4468
4469 impl Counter {
4470 fn inc(&mut self, cx: &mut ModelContext<Self>) {
4471 self.0 += 1;
4472 cx.notify();
4473 }
4474 }
4475
4476 let model = cx.add_model(|_| Counter(0));
4477
4478 let condition1 = model.condition(&cx, |model, _| model.0 == 2);
4479 let condition2 = model.condition(&cx, |model, _| model.0 == 3);
4480 smol::pin!(condition1, condition2);
4481
4482 model.update(&mut cx, |model, cx| model.inc(cx));
4483 assert_eq!(poll_once(&mut condition1).await, None);
4484 assert_eq!(poll_once(&mut condition2).await, None);
4485
4486 model.update(&mut cx, |model, cx| model.inc(cx));
4487 assert_eq!(poll_once(&mut condition1).await, Some(()));
4488 assert_eq!(poll_once(&mut condition2).await, None);
4489
4490 model.update(&mut cx, |model, cx| model.inc(cx));
4491 assert_eq!(poll_once(&mut condition2).await, Some(()));
4492
4493 model.update(&mut cx, |_, cx| cx.notify());
4494 }
4495
4496 #[crate::test(self)]
4497 #[should_panic]
4498 async fn test_model_condition_timeout(mut cx: TestAppContext) {
4499 struct Model;
4500
4501 impl super::Entity for Model {
4502 type Event = ();
4503 }
4504
4505 let model = cx.add_model(|_| Model);
4506 model.condition(&cx, |_, _| false).await;
4507 }
4508
4509 #[crate::test(self)]
4510 #[should_panic(expected = "model dropped with pending condition")]
4511 async fn test_model_condition_panic_on_drop(mut cx: TestAppContext) {
4512 struct Model;
4513
4514 impl super::Entity for Model {
4515 type Event = ();
4516 }
4517
4518 let model = cx.add_model(|_| Model);
4519 let condition = model.condition(&cx, |_, _| false);
4520 cx.update(|_| drop(model));
4521 condition.await;
4522 }
4523
4524 #[crate::test(self)]
4525 async fn test_view_condition(mut cx: TestAppContext) {
4526 struct Counter(usize);
4527
4528 impl super::Entity for Counter {
4529 type Event = ();
4530 }
4531
4532 impl super::View for Counter {
4533 fn ui_name() -> &'static str {
4534 "test view"
4535 }
4536
4537 fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
4538 Empty::new().boxed()
4539 }
4540 }
4541
4542 impl Counter {
4543 fn inc(&mut self, cx: &mut ViewContext<Self>) {
4544 self.0 += 1;
4545 cx.notify();
4546 }
4547 }
4548
4549 let (_, view) = cx.add_window(|_| Counter(0));
4550
4551 let condition1 = view.condition(&cx, |view, _| view.0 == 2);
4552 let condition2 = view.condition(&cx, |view, _| view.0 == 3);
4553 smol::pin!(condition1, condition2);
4554
4555 view.update(&mut cx, |view, cx| view.inc(cx));
4556 assert_eq!(poll_once(&mut condition1).await, None);
4557 assert_eq!(poll_once(&mut condition2).await, None);
4558
4559 view.update(&mut cx, |view, cx| view.inc(cx));
4560 assert_eq!(poll_once(&mut condition1).await, Some(()));
4561 assert_eq!(poll_once(&mut condition2).await, None);
4562
4563 view.update(&mut cx, |view, cx| view.inc(cx));
4564 assert_eq!(poll_once(&mut condition2).await, Some(()));
4565 view.update(&mut cx, |_, cx| cx.notify());
4566 }
4567
4568 #[crate::test(self)]
4569 #[should_panic]
4570 async fn test_view_condition_timeout(mut cx: TestAppContext) {
4571 struct View;
4572
4573 impl super::Entity for View {
4574 type Event = ();
4575 }
4576
4577 impl super::View for View {
4578 fn ui_name() -> &'static str {
4579 "test view"
4580 }
4581
4582 fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
4583 Empty::new().boxed()
4584 }
4585 }
4586
4587 let (_, view) = cx.add_window(|_| View);
4588 view.condition(&cx, |_, _| false).await;
4589 }
4590
4591 #[crate::test(self)]
4592 #[should_panic(expected = "view dropped with pending condition")]
4593 async fn test_view_condition_panic_on_drop(mut cx: TestAppContext) {
4594 struct View;
4595
4596 impl super::Entity for View {
4597 type Event = ();
4598 }
4599
4600 impl super::View for View {
4601 fn ui_name() -> &'static str {
4602 "test view"
4603 }
4604
4605 fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
4606 Empty::new().boxed()
4607 }
4608 }
4609
4610 let window_id = cx.add_window(|_| View).0;
4611 let view = cx.add_view(window_id, |_| View);
4612
4613 let condition = view.condition(&cx, |_, _| false);
4614 cx.update(|_| drop(view));
4615 condition.await;
4616 }
4617}