@@ -8,9 +8,9 @@ pub use model_context::*;
use refineable::Refineable;
use crate::{
- current_platform, image_cache::ImageCache, AssetSource, Context, DisplayLinker, Executor,
- LayoutId, MainThread, MainThreadOnly, Platform, RootView, SvgRenderer, Task, TextStyle,
- TextStyleRefinement, TextSystem, Window, WindowContext, WindowHandle, WindowId,
+ current_platform, image_cache::ImageCache, AssetSource, Context, DisplayId, Executor, LayoutId,
+ MainThread, MainThreadOnly, Platform, PlatformDisplayLinker, RootView, SvgRenderer, Task,
+ TextStyle, TextStyleRefinement, TextSystem, Window, WindowContext, WindowHandle, WindowId,
};
use anyhow::{anyhow, Result};
use collections::{HashMap, VecDeque};
@@ -56,13 +56,14 @@ impl App {
Self(Arc::new_cyclic(|this| {
Mutex::new(AppContext {
this: this.clone(),
- display_linker: Arc::new(DisplayLinker::new(platform.display_linker())),
text_system: Arc::new(TextSystem::new(platform.text_system())),
+ pending_updates: 0,
+ display_linker: platform.display_linker(),
+ next_frame_callbacks: Default::default(),
platform: MainThreadOnly::new(platform, executor.clone()),
executor,
svg_renderer: SvgRenderer::new(asset_source),
image_cache: ImageCache::new(http_client),
- pending_updates: 0,
text_style_stack: Vec::new(),
state_stacks_by_type: HashMap::default(),
unit_entity,
@@ -90,14 +91,16 @@ impl App {
}
type Handlers = SmallVec<[Arc<dyn Fn(&mut AppContext) -> bool + Send + Sync + 'static>; 2]>;
+type FrameCallback = Box<dyn FnOnce(&mut WindowContext) + Send>;
pub struct AppContext {
this: Weak<Mutex<AppContext>>,
platform: MainThreadOnly<dyn Platform>,
text_system: Arc<TextSystem>,
pending_updates: usize,
+ pub(crate) display_linker: Arc<dyn PlatformDisplayLinker>,
+ pub(crate) next_frame_callbacks: HashMap<DisplayId, Vec<FrameCallback>>,
pub(crate) executor: Executor,
- pub(crate) display_linker: Arc<DisplayLinker>,
pub(crate) svg_renderer: SvgRenderer,
pub(crate) image_cache: ImageCache,
pub(crate) text_style_stack: Vec<TextStyleRefinement>,
@@ -146,7 +149,6 @@ impl AppContext {
}
fn flush_effects(&mut self) {
- dbg!("flush effects");
while let Some(effect) = self.pending_effects.pop_front() {
match effect {
Effect::Notify(entity_id) => self.apply_notify_effect(entity_id),
@@ -1,56 +0,0 @@
-use crate::{DisplayId, PlatformDisplayLinker, VideoTimestamp};
-use collections::HashMap;
-use parking_lot::Mutex;
-use std::sync::Arc;
-
-type FrameCallback = Box<dyn FnOnce(&VideoTimestamp, &VideoTimestamp) + Send>;
-
-pub struct DisplayLinker {
- platform_linker: Arc<dyn PlatformDisplayLinker>,
- next_frame_callbacks: Arc<Mutex<HashMap<DisplayId, Vec<FrameCallback>>>>,
-}
-
-impl DisplayLinker {
- pub(crate) fn new(platform_linker: Arc<dyn PlatformDisplayLinker>) -> Self {
- Self {
- platform_linker,
- next_frame_callbacks: Default::default(),
- }
- }
-
- pub(crate) fn on_next_frame(
- &self,
- display_id: DisplayId,
- callback: impl FnOnce(&VideoTimestamp, &VideoTimestamp) + Send + 'static,
- ) {
- let next_frame_callbacks = self.next_frame_callbacks.clone();
- let callback = Box::new(callback);
- match self.next_frame_callbacks.lock().entry(display_id) {
- collections::hash_map::Entry::Occupied(mut entry) => {
- if entry.get().is_empty() {
- self.platform_linker.start(display_id);
- }
- entry.get_mut().push(callback)
- }
- collections::hash_map::Entry::Vacant(entry) => {
- // let platform_linker = self.platform_linker.clone();
- self.platform_linker.set_output_callback(
- display_id,
- Box::new(move |current_time, output_time| {
- for callback in next_frame_callbacks
- .lock()
- .get_mut(&display_id)
- .unwrap()
- .drain(..)
- {
- callback(current_time, output_time);
- }
- // platform_linker.stop(display_id);
- }),
- );
- self.platform_linker.start(display_id);
- entry.insert(vec![callback]);
- }
- }
- }
-}
@@ -144,11 +144,42 @@ impl<'a, 'w> WindowContext<'a, 'w> {
}
pub fn on_next_frame(&mut self, f: impl FnOnce(&mut WindowContext) + Send + 'static) {
- let cx = self.to_async();
+ let f = Box::new(f);
let display_id = self.window.display_id;
- self.display_linker.on_next_frame(display_id, move |_, _| {
- cx.update(f).ok();
- });
+ let async_cx = self.to_async();
+ let app_cx = self.app_mut();
+ match app_cx.next_frame_callbacks.entry(display_id) {
+ collections::hash_map::Entry::Occupied(mut entry) => {
+ if entry.get().is_empty() {
+ app_cx.display_linker.start(display_id);
+ }
+ entry.get_mut().push(f);
+ }
+ collections::hash_map::Entry::Vacant(entry) => {
+ app_cx.display_linker.set_output_callback(
+ display_id,
+ Box::new(move |_current_time, _output_time| {
+ let _ = async_cx.update(|cx| {
+ let callbacks = cx
+ .next_frame_callbacks
+ .get_mut(&display_id)
+ .unwrap()
+ .drain(..)
+ .collect::<Vec<_>>();
+ for callback in callbacks {
+ callback(cx);
+ }
+
+ if cx.next_frame_callbacks.get(&display_id).unwrap().is_empty() {
+ cx.display_linker.stop(display_id);
+ }
+ });
+ }),
+ );
+ app_cx.display_linker.start(display_id);
+ entry.insert(vec![f]);
+ }
+ }
}
pub fn spawn<Fut, R>(
@@ -590,11 +621,9 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
}
pub fn on_next_frame(&mut self, f: impl FnOnce(&mut S, &mut ViewContext<S>) + Send + 'static) {
- let mut cx = self.to_async();
let entity = self.handle();
- let display_id = self.window.display_id;
- self.display_linker.on_next_frame(display_id, move |_, _| {
- entity.update(&mut cx, f).ok();
+ self.window_cx.on_next_frame(move |cx| {
+ entity.update(cx, f).ok();
});
}