1mod async_context;
2mod entity_map;
3mod model_context;
4
5pub use async_context::*;
6pub use entity_map::*;
7pub use model_context::*;
8use refineable::Refineable;
9use smallvec::SmallVec;
10
11use crate::{
12 current_platform, image_cache::ImageCache, Action, AssetSource, Context, DispatchPhase,
13 DisplayId, Executor, FocusEvent, FocusHandle, FocusId, KeyBinding, Keymap, LayoutId,
14 MainThread, MainThreadOnly, Platform, SemanticVersion, SharedString, SubscriberSet,
15 SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem, View, Window, WindowContext,
16 WindowHandle, WindowId,
17};
18use anyhow::{anyhow, Result};
19use collections::{HashMap, HashSet, VecDeque};
20use futures::Future;
21use parking_lot::{Mutex, RwLock};
22use slotmap::SlotMap;
23use std::{
24 any::{type_name, Any, TypeId},
25 mem,
26 sync::{atomic::Ordering::SeqCst, Arc, Weak},
27};
28use util::http::{self, HttpClient};
29
30pub struct App(Arc<Mutex<AppContext>>);
31
32impl App {
33 pub fn production(asset_source: Arc<dyn AssetSource>) -> Self {
34 let http_client = http::client();
35 Self::new(current_platform(), asset_source, http_client)
36 }
37
38 #[cfg(any(test, feature = "test"))]
39 pub fn test() -> Self {
40 let platform = Arc::new(super::TestPlatform::new());
41 let asset_source = Arc::new(());
42 let http_client = util::http::FakeHttpClient::with_404_response();
43 Self::new(platform, asset_source, http_client)
44 }
45
46 fn new(
47 platform: Arc<dyn Platform>,
48 asset_source: Arc<dyn AssetSource>,
49 http_client: Arc<dyn HttpClient>,
50 ) -> Self {
51 let executor = platform.executor();
52 let entities = EntityMap::new();
53 let unit_entity = entities.insert(entities.reserve(), ());
54 Self(Arc::new_cyclic(|this| {
55 Mutex::new(AppContext {
56 this: this.clone(),
57 text_system: Arc::new(TextSystem::new(platform.text_system())),
58 platform: MainThreadOnly::new(platform, executor.clone()),
59 flushing_effects: false,
60 pending_updates: 0,
61 next_frame_callbacks: Default::default(),
62 executor,
63 svg_renderer: SvgRenderer::new(asset_source),
64 image_cache: ImageCache::new(http_client),
65 text_style_stack: Vec::new(),
66 global_stacks_by_type: HashMap::default(),
67 unit_entity,
68 entities,
69 windows: SlotMap::with_key(),
70 keymap: Arc::new(RwLock::new(Keymap::default())),
71 global_action_listeners: HashMap::default(),
72 action_builders: HashMap::default(),
73 pending_notifications: Default::default(),
74 pending_effects: Default::default(),
75 observers: SubscriberSet::new(),
76 event_handlers: SubscriberSet::new(),
77 release_handlers: SubscriberSet::new(),
78 layout_id_buffer: Default::default(),
79 propagate_event: true,
80 })
81 }))
82 }
83
84 pub fn run<F>(self, on_finish_launching: F)
85 where
86 F: 'static + FnOnce(&mut MainThread<AppContext>),
87 {
88 let this = self.0.clone();
89 let platform = self.0.lock().platform.clone();
90 platform.borrow_on_main_thread().run(Box::new(move || {
91 let cx = &mut *this.lock();
92 let cx = unsafe { mem::transmute::<&mut AppContext, &mut MainThread<AppContext>>(cx) };
93 on_finish_launching(cx);
94 }));
95 }
96
97 pub fn on_open_urls<F>(&self, mut callback: F) -> &Self
98 where
99 F: 'static + FnMut(Vec<String>, &mut AppContext),
100 {
101 let this = Arc::downgrade(&self.0);
102 self.0
103 .lock()
104 .platform
105 .borrow_on_main_thread()
106 .on_open_urls(Box::new(move |urls| {
107 if let Some(app) = this.upgrade() {
108 callback(urls, &mut app.lock());
109 }
110 }));
111 self
112 }
113
114 pub fn on_reopen<F>(&self, mut callback: F) -> &Self
115 where
116 F: 'static + FnMut(&mut AppContext),
117 {
118 let this = Arc::downgrade(&self.0);
119 self.0
120 .lock()
121 .platform
122 .borrow_on_main_thread()
123 .on_reopen(Box::new(move || {
124 if let Some(app) = this.upgrade() {
125 callback(&mut app.lock());
126 }
127 }));
128 self
129 }
130
131 pub fn app_version(&self) -> Result<SemanticVersion> {
132 self.0.lock().platform.borrow_on_main_thread().app_version()
133 }
134
135 pub fn os_name(&self) -> &'static str {
136 self.0.lock().platform.borrow_on_main_thread().os_name()
137 }
138
139 pub fn os_version(&self) -> Result<SemanticVersion> {
140 self.0.lock().platform.borrow_on_main_thread().os_version()
141 }
142
143 pub fn executor(&self) -> Executor {
144 self.0.lock().executor.clone()
145 }
146
147 pub fn text_system(&self) -> Arc<TextSystem> {
148 self.0.lock().text_system.clone()
149 }
150}
151
152type Handler = Box<dyn Fn(&mut AppContext) -> bool + Send + Sync + 'static>;
153type EventHandler = Box<dyn Fn(&dyn Any, &mut AppContext) -> bool + Send + Sync + 'static>;
154type ReleaseHandler = Box<dyn Fn(&mut dyn Any, &mut AppContext) + Send + Sync + 'static>;
155type FrameCallback = Box<dyn FnOnce(&mut WindowContext) + Send>;
156type ActionBuilder = fn(json: Option<serde_json::Value>) -> anyhow::Result<Box<dyn Action>>;
157
158pub struct AppContext {
159 this: Weak<Mutex<AppContext>>,
160 pub(crate) platform: MainThreadOnly<dyn Platform>,
161 text_system: Arc<TextSystem>,
162 flushing_effects: bool,
163 pending_updates: usize,
164 pub(crate) next_frame_callbacks: HashMap<DisplayId, Vec<FrameCallback>>,
165 pub(crate) executor: Executor,
166 pub(crate) svg_renderer: SvgRenderer,
167 pub(crate) image_cache: ImageCache,
168 pub(crate) text_style_stack: Vec<TextStyleRefinement>,
169 pub(crate) global_stacks_by_type: HashMap<TypeId, Vec<Box<dyn Any + Send + Sync>>>,
170 pub(crate) unit_entity: Handle<()>,
171 pub(crate) entities: EntityMap,
172 pub(crate) windows: SlotMap<WindowId, Option<Window>>,
173 pub(crate) keymap: Arc<RwLock<Keymap>>,
174 pub(crate) global_action_listeners:
175 HashMap<TypeId, Vec<Box<dyn Fn(&dyn Action, DispatchPhase, &mut Self) + Send + Sync>>>,
176 action_builders: HashMap<SharedString, ActionBuilder>,
177 pub(crate) pending_notifications: HashSet<EntityId>,
178 pending_effects: VecDeque<Effect>,
179 pub(crate) observers: SubscriberSet<EntityId, Handler>,
180 pub(crate) event_handlers: SubscriberSet<EntityId, EventHandler>,
181 pub(crate) release_handlers: SubscriberSet<EntityId, ReleaseHandler>,
182 pub(crate) layout_id_buffer: Vec<LayoutId>, // We recycle this memory across layout requests.
183 pub(crate) propagate_event: bool,
184}
185
186impl AppContext {
187 pub(crate) fn update<R>(&mut self, update: impl FnOnce(&mut Self) -> R) -> R {
188 self.pending_updates += 1;
189 let result = update(self);
190 if !self.flushing_effects && self.pending_updates == 1 {
191 self.flushing_effects = true;
192 self.flush_effects();
193 self.flushing_effects = false;
194 }
195 self.pending_updates -= 1;
196 result
197 }
198
199 pub(crate) fn read_window<R>(
200 &mut self,
201 id: WindowId,
202 read: impl FnOnce(&WindowContext) -> R,
203 ) -> Result<R> {
204 let window = self
205 .windows
206 .get(id)
207 .ok_or_else(|| anyhow!("window not found"))?
208 .as_ref()
209 .unwrap();
210 Ok(read(&WindowContext::immutable(self, &window)))
211 }
212
213 pub(crate) fn update_window<R>(
214 &mut self,
215 id: WindowId,
216 update: impl FnOnce(&mut WindowContext) -> R,
217 ) -> Result<R> {
218 self.update(|cx| {
219 let mut window = cx
220 .windows
221 .get_mut(id)
222 .ok_or_else(|| anyhow!("window not found"))?
223 .take()
224 .unwrap();
225
226 let result = update(&mut WindowContext::mutable(cx, &mut window));
227
228 cx.windows
229 .get_mut(id)
230 .ok_or_else(|| anyhow!("window not found"))?
231 .replace(window);
232
233 Ok(result)
234 })
235 }
236
237 pub(crate) fn push_effect(&mut self, effect: Effect) {
238 match &effect {
239 Effect::Notify { emitter } => {
240 if self.pending_notifications.insert(*emitter) {
241 self.pending_effects.push_back(effect);
242 }
243 }
244 Effect::Emit { .. } => self.pending_effects.push_back(effect),
245 Effect::FocusChanged { .. } => self.pending_effects.push_back(effect),
246 Effect::Refresh => self.pending_effects.push_back(effect),
247 }
248 }
249
250 fn flush_effects(&mut self) {
251 loop {
252 self.release_dropped_entities();
253 self.release_dropped_focus_handles();
254 if let Some(effect) = self.pending_effects.pop_front() {
255 match effect {
256 Effect::Notify { emitter } => self.apply_notify_effect(emitter),
257 Effect::Emit { emitter, event } => self.apply_emit_effect(emitter, event),
258 Effect::FocusChanged { window_id, focused } => {
259 self.apply_focus_changed(window_id, focused)
260 }
261 Effect::Refresh => {
262 self.apply_refresh();
263 }
264 }
265 } else {
266 break;
267 }
268 }
269
270 let dirty_window_ids = self
271 .windows
272 .iter()
273 .filter_map(|(window_id, window)| {
274 let window = window.as_ref().unwrap();
275 if window.dirty {
276 Some(window_id)
277 } else {
278 None
279 }
280 })
281 .collect::<SmallVec<[_; 8]>>();
282
283 for dirty_window_id in dirty_window_ids {
284 self.update_window(dirty_window_id, |cx| cx.draw()).unwrap();
285 }
286 }
287
288 fn release_dropped_entities(&mut self) {
289 loop {
290 let dropped = self.entities.take_dropped();
291 if dropped.is_empty() {
292 break;
293 }
294
295 for (entity_id, mut entity) in dropped {
296 self.observers.remove(&entity_id);
297 self.event_handlers.remove(&entity_id);
298 for release_callback in self.release_handlers.remove(&entity_id) {
299 release_callback(&mut entity, self);
300 }
301 }
302 }
303 }
304
305 fn release_dropped_focus_handles(&mut self) {
306 let window_ids = self.windows.keys().collect::<SmallVec<[_; 8]>>();
307 for window_id in window_ids {
308 self.update_window(window_id, |cx| {
309 let mut blur_window = false;
310 let focus = cx.window.focus;
311 cx.window.focus_handles.write().retain(|handle_id, count| {
312 if count.load(SeqCst) == 0 {
313 if focus == Some(handle_id) {
314 blur_window = true;
315 }
316 false
317 } else {
318 true
319 }
320 });
321
322 if blur_window {
323 cx.blur();
324 }
325 })
326 .unwrap();
327 }
328 }
329
330 fn apply_notify_effect(&mut self, emitter: EntityId) {
331 self.pending_notifications.remove(&emitter);
332 self.observers
333 .clone()
334 .retain(&emitter, |handler| handler(self));
335 }
336
337 fn apply_emit_effect(&mut self, emitter: EntityId, event: Box<dyn Any>) {
338 self.event_handlers
339 .clone()
340 .retain(&emitter, |handler| handler(&event, self));
341 }
342
343 fn apply_focus_changed(&mut self, window_id: WindowId, focused: Option<FocusId>) {
344 self.update_window(window_id, |cx| {
345 if cx.window.focus == focused {
346 let mut listeners = mem::take(&mut cx.window.focus_listeners);
347 let focused =
348 focused.map(|id| FocusHandle::for_id(id, &cx.window.focus_handles).unwrap());
349 let blurred = cx
350 .window
351 .last_blur
352 .take()
353 .unwrap()
354 .and_then(|id| FocusHandle::for_id(id, &cx.window.focus_handles));
355 if focused.is_some() || blurred.is_some() {
356 let event = FocusEvent { focused, blurred };
357 for listener in &listeners {
358 listener(&event, cx);
359 }
360 }
361
362 listeners.extend(cx.window.focus_listeners.drain(..));
363 cx.window.focus_listeners = listeners;
364 }
365 })
366 .ok();
367 }
368
369 fn apply_refresh(&mut self) {
370 for window in self.windows.values_mut() {
371 if let Some(window) = window.as_mut() {
372 window.dirty = true;
373 }
374 }
375 }
376
377 pub fn to_async(&self) -> AsyncAppContext {
378 AsyncAppContext(unsafe { mem::transmute(self.this.clone()) })
379 }
380
381 pub fn executor(&self) -> &Executor {
382 &self.executor
383 }
384
385 pub fn run_on_main<R>(
386 &mut self,
387 f: impl FnOnce(&mut MainThread<AppContext>) -> R + Send + 'static,
388 ) -> Task<R>
389 where
390 R: Send + 'static,
391 {
392 if self.executor.is_main_thread() {
393 Task::ready(f(unsafe {
394 mem::transmute::<&mut AppContext, &mut MainThread<AppContext>>(self)
395 }))
396 } else {
397 let this = self.this.upgrade().unwrap();
398 self.executor.run_on_main(move || {
399 let cx = &mut *this.lock();
400 cx.update(|cx| f(unsafe { mem::transmute::<&mut Self, &mut MainThread<Self>>(cx) }))
401 })
402 }
403 }
404
405 pub fn spawn_on_main<F, R>(
406 &self,
407 f: impl FnOnce(&mut MainThread<AppContext>) -> F + Send + 'static,
408 ) -> Task<R>
409 where
410 F: Future<Output = R> + 'static,
411 R: Send + 'static,
412 {
413 let this = self.this.upgrade().unwrap();
414 self.executor.spawn_on_main(move || {
415 let cx = &mut *this.lock();
416 cx.update(|cx| {
417 f(unsafe { mem::transmute::<&mut AppContext, &mut MainThread<AppContext>>(cx) })
418 })
419 })
420 }
421
422 pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task<R>
423 where
424 Fut: Future<Output = R> + Send + 'static,
425 R: Send + 'static,
426 {
427 let cx = self.to_async();
428 self.executor.spawn(async move {
429 let future = f(cx);
430 future.await
431 })
432 }
433
434 pub fn text_system(&self) -> &Arc<TextSystem> {
435 &self.text_system
436 }
437
438 pub fn text_style(&self) -> TextStyle {
439 let mut style = TextStyle::default();
440 for refinement in &self.text_style_stack {
441 style.refine(refinement);
442 }
443 style
444 }
445
446 pub fn global<G: 'static>(&self) -> &G {
447 self.global_stacks_by_type
448 .get(&TypeId::of::<G>())
449 .and_then(|stack| stack.last())
450 .and_then(|any_state| any_state.downcast_ref::<G>())
451 .ok_or_else(|| anyhow!("no state of type {} exists", type_name::<G>()))
452 .unwrap()
453 }
454
455 pub fn global_mut<G: 'static>(&mut self) -> &mut G {
456 self.global_stacks_by_type
457 .get_mut(&TypeId::of::<G>())
458 .and_then(|stack| stack.last_mut())
459 .and_then(|any_state| any_state.downcast_mut::<G>())
460 .ok_or_else(|| anyhow!("no state of type {} exists", type_name::<G>()))
461 .unwrap()
462 }
463
464 pub fn default_global<G: 'static + Default + Sync + Send>(&mut self) -> &mut G {
465 let stack = self
466 .global_stacks_by_type
467 .entry(TypeId::of::<G>())
468 .or_default();
469 if stack.is_empty() {
470 stack.push(Box::new(G::default()));
471 }
472 stack.last_mut().unwrap().downcast_mut::<G>().unwrap()
473 }
474
475 pub fn set_global<T: Send + Sync + 'static>(&mut self, global: T) {
476 let global = Box::new(global);
477 let stack = self
478 .global_stacks_by_type
479 .entry(TypeId::of::<T>())
480 .or_default();
481 if let Some(last) = stack.last_mut() {
482 *last = global;
483 } else {
484 stack.push(global)
485 }
486 }
487
488 pub(crate) fn push_global<T: Send + Sync + 'static>(&mut self, global: T) {
489 self.global_stacks_by_type
490 .entry(TypeId::of::<T>())
491 .or_default()
492 .push(Box::new(global));
493 }
494
495 pub(crate) fn pop_global<T: 'static>(&mut self) -> Box<T> {
496 self.global_stacks_by_type
497 .get_mut(&TypeId::of::<T>())
498 .and_then(|stack| stack.pop())
499 .expect("state stack underflow")
500 .downcast()
501 .unwrap()
502 }
503
504 pub(crate) fn push_text_style(&mut self, text_style: TextStyleRefinement) {
505 self.text_style_stack.push(text_style);
506 }
507
508 pub(crate) fn pop_text_style(&mut self) {
509 self.text_style_stack.pop();
510 }
511
512 pub fn bind_keys(&mut self, bindings: impl IntoIterator<Item = KeyBinding>) {
513 self.keymap.write().add_bindings(bindings);
514 self.push_effect(Effect::Refresh);
515 }
516
517 pub fn on_action<A: Action>(
518 &mut self,
519 listener: impl Fn(&A, &mut Self) + Send + Sync + 'static,
520 ) {
521 self.global_action_listeners
522 .entry(TypeId::of::<A>())
523 .or_default()
524 .push(Box::new(move |action, phase, cx| {
525 if phase == DispatchPhase::Bubble {
526 let action = action.as_any().downcast_ref().unwrap();
527 listener(action, cx)
528 }
529 }));
530 }
531
532 pub fn register_action_type<A: Action>(&mut self) {
533 self.action_builders.insert(A::qualified_name(), A::build);
534 }
535
536 pub fn build_action(
537 &mut self,
538 name: &str,
539 params: Option<serde_json::Value>,
540 ) -> Result<Box<dyn Action>> {
541 let build = self
542 .action_builders
543 .get(name)
544 .ok_or_else(|| anyhow!("no action type registered for {}", name))?;
545 (build)(params)
546 }
547
548 pub fn stop_propagation(&mut self) {
549 self.propagate_event = false;
550 }
551}
552
553impl Context for AppContext {
554 type BorrowedContext<'a, 'w> = Self;
555 type EntityContext<'a, 'w, T: Send + Sync + 'static> = ModelContext<'a, T>;
556 type Result<T> = T;
557
558 fn refresh(&mut self) {
559 self.push_effect(Effect::Refresh);
560 }
561
562 fn entity<T: Send + Sync + 'static>(
563 &mut self,
564 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
565 ) -> Handle<T> {
566 self.update(|cx| {
567 let slot = cx.entities.reserve();
568 let entity = build_entity(&mut ModelContext::mutable(cx, slot.id));
569 cx.entities.insert(slot, entity)
570 })
571 }
572
573 fn update_entity<T: Send + Sync + 'static, R>(
574 &mut self,
575 handle: &Handle<T>,
576 update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
577 ) -> R {
578 self.update(|cx| {
579 let mut entity = cx.entities.lease(handle);
580 let result = update(&mut entity, &mut ModelContext::mutable(cx, handle.id));
581 cx.entities.end_lease(entity);
582 result
583 })
584 }
585
586 fn read_global<G: 'static + Send + Sync, R>(&self, read: impl FnOnce(&G, &Self) -> R) -> R {
587 read(self.global(), self)
588 }
589
590 fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
591 where
592 G: 'static + Send + Sync,
593 {
594 let mut global = self
595 .global_stacks_by_type
596 .get_mut(&TypeId::of::<G>())
597 .and_then(|stack| stack.pop())
598 .ok_or_else(|| anyhow!("no state of type {} exists", type_name::<G>()))
599 .unwrap();
600 let result = f(global.downcast_mut().unwrap(), self);
601 self.global_stacks_by_type
602 .get_mut(&TypeId::of::<G>())
603 .unwrap()
604 .push(global);
605 result
606 }
607}
608
609impl MainThread<AppContext> {
610 fn update<R>(&mut self, update: impl FnOnce(&mut Self) -> R) -> R {
611 self.0.update(|cx| {
612 update(unsafe {
613 std::mem::transmute::<&mut AppContext, &mut MainThread<AppContext>>(cx)
614 })
615 })
616 }
617
618 pub(crate) fn update_window<R>(
619 &mut self,
620 id: WindowId,
621 update: impl FnOnce(&mut MainThread<WindowContext>) -> R,
622 ) -> Result<R> {
623 self.0.update_window(id, |cx| {
624 update(unsafe {
625 std::mem::transmute::<&mut WindowContext, &mut MainThread<WindowContext>>(cx)
626 })
627 })
628 }
629
630 pub(crate) fn platform(&self) -> &dyn Platform {
631 self.platform.borrow_on_main_thread()
632 }
633
634 pub fn activate(&mut self, ignoring_other_apps: bool) {
635 self.platform().activate(ignoring_other_apps);
636 }
637
638 pub fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Result<()> {
639 self.platform().write_credentials(url, username, password)
640 }
641
642 pub fn read_credentials(&self, url: &str) -> Result<Option<(String, Vec<u8>)>> {
643 self.platform().read_credentials(url)
644 }
645
646 pub fn delete_credentials(&self, url: &str) -> Result<()> {
647 self.platform().delete_credentials(url)
648 }
649
650 pub fn open_window<S: 'static + Send + Sync>(
651 &mut self,
652 options: crate::WindowOptions,
653 build_root_view: impl FnOnce(&mut WindowContext) -> View<S> + Send + 'static,
654 ) -> WindowHandle<S> {
655 self.update(|cx| {
656 let id = cx.windows.insert(None);
657 let handle = WindowHandle::new(id);
658 let mut window = Window::new(handle.into(), options, cx);
659 let root_view = build_root_view(&mut WindowContext::mutable(cx, &mut window));
660 window.root_view.replace(root_view.into_any());
661 cx.windows.get_mut(id).unwrap().replace(window);
662 handle
663 })
664 }
665}
666
667pub(crate) enum Effect {
668 Notify {
669 emitter: EntityId,
670 },
671 Emit {
672 emitter: EntityId,
673 event: Box<dyn Any + Send + Sync + 'static>,
674 },
675 FocusChanged {
676 window_id: WindowId,
677 focused: Option<FocusId>,
678 },
679 Refresh,
680}
681
682#[cfg(test)]
683mod tests {
684 use super::AppContext;
685
686 #[test]
687 fn test_app_context_send_sync() {
688 // This will not compile if `AppContext` does not implement `Send`
689 fn assert_send<T: Send>() {}
690 assert_send::<AppContext>();
691 }
692}