WIP

Marshall Bowers created

Change summary

crates/gpui2/src/app.rs    | 16 ++++++++++++----
crates/gpui2/src/window.rs | 30 +++++++++++++++++++++++++++++-
2 files changed, 41 insertions(+), 5 deletions(-)

Detailed changes

crates/gpui2/src/app.rs 🔗

@@ -139,12 +139,18 @@ impl App {
 }
 
 type ActionBuilder = fn(json: Option<serde_json::Value>) -> anyhow::Result<Box<dyn Action>>;
-type FrameCallback = Box<dyn FnOnce(&mut WindowContext)>;
+type FrameCallback = Box<dyn FnOnce(&mut AppContext)>;
 type Handler = Box<dyn FnMut(&mut AppContext) -> bool + 'static>;
 type Listener = Box<dyn FnMut(&dyn Any, &mut AppContext) -> bool + 'static>;
 type QuitHandler = Box<dyn FnOnce(&mut AppContext) -> LocalBoxFuture<'static, ()> + 'static>;
 type ReleaseListener = Box<dyn FnOnce(&mut dyn Any, &mut AppContext) + 'static>;
 
+// struct FrameConsumer {
+//     next_frame_callbacks: Vec<FrameCallback>,
+//     task: Task<()>,
+//     display_linker
+// }
+
 pub struct AppContext {
     this: Weak<AppCell>,
     pub(crate) platform: Rc<dyn Platform>,
@@ -154,6 +160,7 @@ pub struct AppContext {
     pending_updates: usize,
     pub(crate) active_drag: Option<AnyDrag>,
     pub(crate) next_frame_callbacks: HashMap<DisplayId, Vec<FrameCallback>>,
+    pub(crate) frame_consumers: HashMap<DisplayId, Task<()>>,
     pub(crate) background_executor: BackgroundExecutor,
     pub(crate) foreground_executor: ForegroundExecutor,
     pub(crate) svg_renderer: SvgRenderer,
@@ -204,12 +211,14 @@ impl AppContext {
         Rc::new_cyclic(|this| AppCell {
             app: RefCell::new(AppContext {
                 this: this.clone(),
-                text_system,
                 platform,
                 app_metadata,
+                text_system,
                 flushing_effects: false,
                 pending_updates: 0,
-                next_frame_callbacks: Default::default(),
+                active_drag: None,
+                next_frame_callbacks: HashMap::default(),
+                frame_consumers: HashMap::default(),
                 background_executor: executor,
                 foreground_executor,
                 svg_renderer: SvgRenderer::new(asset_source.clone()),
@@ -232,7 +241,6 @@ impl AppContext {
                 quit_observers: SubscriberSet::new(),
                 layout_id_buffer: Default::default(),
                 propagate_event: true,
-                active_drag: None,
             }),
         })
     }

crates/gpui2/src/window.rs 🔗

@@ -12,7 +12,10 @@ use crate::{
 use anyhow::{anyhow, Result};
 use collections::HashMap;
 use derive_more::{Deref, DerefMut};
-use futures::channel::oneshot;
+use futures::{
+    channel::{mpsc, oneshot},
+    StreamExt,
+};
 use parking_lot::RwLock;
 use slotmap::SlotMap;
 use smallvec::SmallVec;
@@ -411,6 +414,31 @@ impl<'a> WindowContext<'a> {
         let f = Box::new(f);
         let display_id = self.window.display_id;
 
+        self.next_frame_callbacks
+            .entry(display_id)
+            .or_default()
+            .push(f);
+
+        self.frame_consumers.entry(display_id).or_insert_with(|| {
+            let (tx, rx) = mpsc::unbounded::<()>();
+
+            self.spawn(|cx| async move {
+                while rx.next().await.is_some() {
+                    let _ = cx.update(|_, cx| {
+                        for callback in cx
+                            .app
+                            .next_frame_callbacks
+                            .get_mut(&display_id)
+                            .unwrap()
+                            .drain(..)
+                        {
+                            callback(cx);
+                        }
+                    });
+                }
+            })
+        });
+
         if let Some(callbacks) = self.next_frame_callbacks.get_mut(&display_id) {
             callbacks.push(f);
             // If there was already a callback, it means that we already scheduled a frame.