Replace notify_all with an explicit refresh_windows effect

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2021-08-26 15:00:00 +02:00
parent c865f8ad1a
commit 5fe5685641
3 changed files with 61 additions and 20 deletions

View file

@ -22,6 +22,7 @@ use std::{
fmt::{self, Debug}, fmt::{self, Debug},
hash::{Hash, Hasher}, hash::{Hash, Hasher},
marker::PhantomData, marker::PhantomData,
mem,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
path::{Path, PathBuf}, path::{Path, PathBuf},
rc::{self, Rc}, rc::{self, Rc},
@ -973,16 +974,6 @@ impl MutableAppContext {
.push_back(Effect::ViewNotification { window_id, view_id }); .push_back(Effect::ViewNotification { window_id, view_id });
} }
pub(crate) fn notify_all_views(&mut self) {
let notifications = self
.views
.keys()
.copied()
.map(|(window_id, view_id)| Effect::ViewNotification { window_id, view_id })
.collect::<Vec<_>>();
self.pending_effects.extend(notifications);
}
pub fn dispatch_action<A: Action>( pub fn dispatch_action<A: Action>(
&mut self, &mut self,
window_id: usize, window_id: usize,
@ -1314,6 +1305,7 @@ impl MutableAppContext {
if !self.flushing_effects && self.pending_flushes == 0 { if !self.flushing_effects && self.pending_flushes == 0 {
self.flushing_effects = true; self.flushing_effects = true;
let mut full_refresh = false;
loop { loop {
if let Some(effect) = self.pending_effects.pop_front() { if let Some(effect) = self.pending_effects.pop_front() {
match effect { match effect {
@ -1327,15 +1319,24 @@ impl MutableAppContext {
Effect::Focus { window_id, view_id } => { Effect::Focus { window_id, view_id } => {
self.focus(window_id, view_id); self.focus(window_id, view_id);
} }
Effect::RefreshWindows => {
full_refresh = true;
}
} }
self.remove_dropped_entities(); self.remove_dropped_entities();
} else { } else {
self.remove_dropped_entities(); self.remove_dropped_entities();
self.update_windows(); if full_refresh {
self.perform_window_refresh();
} else {
self.update_windows();
}
if self.pending_effects.is_empty() { if self.pending_effects.is_empty() {
self.flushing_effects = false; self.flushing_effects = false;
break; break;
} else {
full_refresh = false;
} }
} }
} }
@ -1366,6 +1367,28 @@ impl MutableAppContext {
} }
} }
pub fn refresh_windows(&mut self) {
self.pending_effects.push_back(Effect::RefreshWindows);
}
fn perform_window_refresh(&mut self) {
let mut presenters = mem::take(&mut self.presenters_and_platform_windows);
for (window_id, (presenter, window)) in &mut presenters {
let invalidation = self
.cx
.windows
.get_mut(&window_id)
.unwrap()
.invalidation
.take();
let mut presenter = presenter.borrow_mut();
presenter.refresh(invalidation, self.as_ref());
let scene = presenter.build_scene(window.size(), window.scale_factor(), self);
window.present_scene(scene);
}
self.presenters_and_platform_windows = presenters;
}
fn emit_event(&mut self, entity_id: usize, payload: Box<dyn Any>) { fn emit_event(&mut self, entity_id: usize, payload: Box<dyn Any>) {
let callbacks = self.subscriptions.lock().remove(&entity_id); let callbacks = self.subscriptions.lock().remove(&entity_id);
if let Some(callbacks) = callbacks { if let Some(callbacks) = callbacks {
@ -1615,10 +1638,11 @@ impl AppContext {
window_id: usize, window_id: usize,
view_id: usize, view_id: usize,
titlebar_height: f32, titlebar_height: f32,
refresh: bool,
) -> Result<ElementBox> { ) -> Result<ElementBox> {
self.views self.views
.get(&(window_id, view_id)) .get(&(window_id, view_id))
.map(|v| v.render(window_id, view_id, titlebar_height, self)) .map(|v| v.render(window_id, view_id, titlebar_height, refresh, self))
.ok_or(anyhow!("view not found")) .ok_or(anyhow!("view not found"))
} }
@ -1633,7 +1657,7 @@ impl AppContext {
if *win_id == window_id { if *win_id == window_id {
Some(( Some((
*view_id, *view_id,
view.render(*win_id, *view_id, titlebar_height, self), view.render(*win_id, *view_id, titlebar_height, false, self),
)) ))
} else { } else {
None None
@ -1730,6 +1754,7 @@ pub enum Effect {
window_id: usize, window_id: usize,
view_id: usize, view_id: usize,
}, },
RefreshWindows,
} }
impl Debug for Effect { impl Debug for Effect {
@ -1753,6 +1778,7 @@ impl Debug for Effect {
.field("window_id", window_id) .field("window_id", window_id)
.field("view_id", view_id) .field("view_id", view_id)
.finish(), .finish(),
Effect::RefreshWindows => f.debug_struct("Effect::FullViewRefresh").finish(),
} }
} }
} }
@ -1790,6 +1816,7 @@ pub trait AnyView {
window_id: usize, window_id: usize,
view_id: usize, view_id: usize,
titlebar_height: f32, titlebar_height: f32,
refresh: bool,
cx: &AppContext, cx: &AppContext,
) -> ElementBox; ) -> ElementBox;
fn on_focus(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize); fn on_focus(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize);
@ -1822,6 +1849,7 @@ where
window_id: usize, window_id: usize,
view_id: usize, view_id: usize,
titlebar_height: f32, titlebar_height: f32,
refresh: bool,
cx: &AppContext, cx: &AppContext,
) -> ElementBox { ) -> ElementBox {
View::render( View::render(
@ -1832,6 +1860,7 @@ where
app: cx, app: cx,
view_type: PhantomData::<T>, view_type: PhantomData::<T>,
titlebar_height, titlebar_height,
refresh,
}, },
) )
} }
@ -2182,10 +2211,6 @@ impl<'a, T: View> ViewContext<'a, T> {
self.app.notify_view(self.window_id, self.view_id); self.app.notify_view(self.window_id, self.view_id);
} }
pub fn notify_all(&mut self) {
self.app.notify_all_views();
}
pub fn propagate_action(&mut self) { pub fn propagate_action(&mut self) {
self.halt_action_dispatch = false; self.halt_action_dispatch = false;
} }
@ -2204,6 +2229,7 @@ impl<'a, T: View> ViewContext<'a, T> {
pub struct RenderContext<'a, T: View> { pub struct RenderContext<'a, T: View> {
pub app: &'a AppContext, pub app: &'a AppContext,
pub titlebar_height: f32, pub titlebar_height: f32,
pub refresh: bool,
window_id: usize, window_id: usize,
view_id: usize, view_id: usize,
view_type: PhantomData<T>, view_type: PhantomData<T>,

View file

@ -66,12 +66,27 @@ impl Presenter {
for view_id in invalidation.updated { for view_id in invalidation.updated {
self.rendered_views.insert( self.rendered_views.insert(
view_id, view_id,
cx.render_view(self.window_id, view_id, self.titlebar_height) cx.render_view(self.window_id, view_id, self.titlebar_height, false)
.unwrap(), .unwrap(),
); );
} }
} }
pub fn refresh(&mut self, invalidation: Option<WindowInvalidation>, cx: &AppContext) {
if let Some(invalidation) = invalidation {
for view_id in invalidation.removed {
self.rendered_views.remove(&view_id);
self.parents.remove(&view_id);
}
}
for (view_id, view) in &mut self.rendered_views {
*view = cx
.render_view(self.window_id, *view_id, self.titlebar_height, true)
.unwrap();
}
}
pub fn build_scene( pub fn build_scene(
&mut self, &mut self,
window_size: Vector2F, window_size: Vector2F,

View file

@ -97,7 +97,7 @@ impl ThemeSelector {
action.0.themes.clear(); action.0.themes.clear();
match action.0.themes.get(&current_theme_name) { match action.0.themes.get(&current_theme_name) {
Ok(theme) => { Ok(theme) => {
cx.notify_all(); cx.refresh_windows();
action.0.settings_tx.lock().borrow_mut().theme = theme; action.0.settings_tx.lock().borrow_mut().theme = theme;
log::info!("reloaded theme {}", current_theme_name); log::info!("reloaded theme {}", current_theme_name);
} }
@ -112,7 +112,7 @@ impl ThemeSelector {
match self.registry.get(&mat.string) { match self.registry.get(&mat.string) {
Ok(theme) => { Ok(theme) => {
self.settings_tx.lock().borrow_mut().theme = theme; self.settings_tx.lock().borrow_mut().theme = theme;
cx.notify_all(); cx.refresh_windows();
cx.emit(Event::Dismissed); cx.emit(Event::Dismissed);
} }
Err(error) => log::error!("error loading theme {}: {}", mat.string, error), Err(error) => log::error!("error loading theme {}: {}", mat.string, error),