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},
hash::{Hash, Hasher},
marker::PhantomData,
mem,
ops::{Deref, DerefMut},
path::{Path, PathBuf},
rc::{self, Rc},
@ -973,16 +974,6 @@ impl MutableAppContext {
.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>(
&mut self,
window_id: usize,
@ -1314,6 +1305,7 @@ impl MutableAppContext {
if !self.flushing_effects && self.pending_flushes == 0 {
self.flushing_effects = true;
let mut full_refresh = false;
loop {
if let Some(effect) = self.pending_effects.pop_front() {
match effect {
@ -1327,15 +1319,24 @@ impl MutableAppContext {
Effect::Focus { window_id, view_id } => {
self.focus(window_id, view_id);
}
Effect::RefreshWindows => {
full_refresh = true;
}
}
self.remove_dropped_entities();
} else {
self.remove_dropped_entities();
if full_refresh {
self.perform_window_refresh();
} else {
self.update_windows();
}
if self.pending_effects.is_empty() {
self.flushing_effects = false;
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>) {
let callbacks = self.subscriptions.lock().remove(&entity_id);
if let Some(callbacks) = callbacks {
@ -1615,10 +1638,11 @@ impl AppContext {
window_id: usize,
view_id: usize,
titlebar_height: f32,
refresh: bool,
) -> Result<ElementBox> {
self.views
.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"))
}
@ -1633,7 +1657,7 @@ impl AppContext {
if *win_id == window_id {
Some((
*view_id,
view.render(*win_id, *view_id, titlebar_height, self),
view.render(*win_id, *view_id, titlebar_height, false, self),
))
} else {
None
@ -1730,6 +1754,7 @@ pub enum Effect {
window_id: usize,
view_id: usize,
},
RefreshWindows,
}
impl Debug for Effect {
@ -1753,6 +1778,7 @@ impl Debug for Effect {
.field("window_id", window_id)
.field("view_id", view_id)
.finish(),
Effect::RefreshWindows => f.debug_struct("Effect::FullViewRefresh").finish(),
}
}
}
@ -1790,6 +1816,7 @@ pub trait AnyView {
window_id: usize,
view_id: usize,
titlebar_height: f32,
refresh: bool,
cx: &AppContext,
) -> ElementBox;
fn on_focus(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize);
@ -1822,6 +1849,7 @@ where
window_id: usize,
view_id: usize,
titlebar_height: f32,
refresh: bool,
cx: &AppContext,
) -> ElementBox {
View::render(
@ -1832,6 +1860,7 @@ where
app: cx,
view_type: PhantomData::<T>,
titlebar_height,
refresh,
},
)
}
@ -2182,10 +2211,6 @@ impl<'a, T: View> ViewContext<'a, T> {
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) {
self.halt_action_dispatch = false;
}
@ -2204,6 +2229,7 @@ impl<'a, T: View> ViewContext<'a, T> {
pub struct RenderContext<'a, T: View> {
pub app: &'a AppContext,
pub titlebar_height: f32,
pub refresh: bool,
window_id: usize,
view_id: usize,
view_type: PhantomData<T>,

View file

@ -66,12 +66,27 @@ impl Presenter {
for view_id in invalidation.updated {
self.rendered_views.insert(
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(),
);
}
}
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(
&mut self,
window_size: Vector2F,

View file

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