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