@@ -569,59 +569,61 @@ impl AppContext {
/// such as notifying observers, emitting events, etc. Effects can themselves
/// cause effects, so we continue looping until all effects are processed.
fn flush_effects(&mut self) {
- loop {
- self.release_dropped_entities();
- self.release_dropped_focus_handles();
- if let Some(effect) = self.pending_effects.pop_front() {
- match effect {
- Effect::Notify { emitter } => {
- self.apply_notify_effect(emitter);
- }
- Effect::Emit {
- emitter,
- event_type,
- event,
- } => self.apply_emit_effect(emitter, event_type, event),
- Effect::FocusChanged {
- window_handle,
- focused,
- } => {
- self.apply_focus_changed_effect(window_handle, focused);
- }
- Effect::Refresh => {
- self.apply_refresh_effect();
- }
- Effect::NotifyGlobalObservers { global_type } => {
- self.apply_notify_global_observers_effect(global_type);
- }
- Effect::Defer { callback } => {
- self.apply_defer_effect(callback);
+ while !self.pending_effects.is_empty() {
+ loop {
+ self.release_dropped_entities();
+ self.release_dropped_focus_handles();
+ if let Some(effect) = self.pending_effects.pop_front() {
+ match effect {
+ Effect::Notify { emitter } => {
+ self.apply_notify_effect(emitter);
+ }
+ Effect::Emit {
+ emitter,
+ event_type,
+ event,
+ } => self.apply_emit_effect(emitter, event_type, event),
+ Effect::FocusChanged {
+ window_handle,
+ focused,
+ } => {
+ self.apply_focus_changed_effect(window_handle, focused);
+ }
+ Effect::Refresh => {
+ self.apply_refresh_effect();
+ }
+ Effect::NotifyGlobalObservers { global_type } => {
+ self.apply_notify_global_observers_effect(global_type);
+ }
+ Effect::Defer { callback } => {
+ self.apply_defer_effect(callback);
+ }
}
+ } else {
+ break;
}
- } else {
- break;
}
- }
- for window in self.windows.values() {
- if let Some(window) = window.as_ref() {
- if window.dirty {
- window.platform_window.invalidate();
+ for window in self.windows.values() {
+ if let Some(window) = window.as_ref() {
+ if window.dirty {
+ window.platform_window.invalidate();
+ }
}
}
- }
- #[cfg(any(test, feature = "test-support"))]
- for window in self
- .windows
- .values()
- .filter_map(|window| {
- let window = window.as_ref()?;
- window.dirty.then_some(window.handle)
- })
- .collect::<Vec<_>>()
- {
- self.update_window(window, |_, cx| cx.draw()).unwrap();
+ #[cfg(any(test, feature = "test-support"))]
+ for window in self
+ .windows
+ .values()
+ .filter_map(|window| {
+ let window = window.as_ref()?;
+ window.dirty.then_some(window.handle)
+ })
+ .collect::<Vec<_>>()
+ {
+ self.update_window(window, |_, cx| cx.draw()).unwrap();
+ }
}
}
@@ -229,6 +229,7 @@ pub struct Window {
pub(crate) next_frame: Frame,
pub(crate) focus_handles: Arc<RwLock<SlotMap<FocusId, AtomicUsize>>>,
pub(crate) focus_listeners: SubscriberSet<(), AnyWindowFocusListener>,
+ pub(crate) blur_listeners: SubscriberSet<(), AnyObserver>,
default_prevented: bool,
mouse_position: Point<Pixels>,
requested_cursor_style: Option<CursorStyle>,
@@ -362,6 +363,7 @@ impl Window {
next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
focus_listeners: SubscriberSet::new(),
+ blur_listeners: SubscriberSet::new(),
default_prevented: true,
mouse_position,
requested_cursor_style: None,
@@ -1235,6 +1237,16 @@ impl<'a> WindowContext<'a> {
/// Draw pixels to the display for this window based on the contents of its scene.
pub(crate) fn draw(&mut self) -> Scene {
+ let window_was_focused = self
+ .window
+ .focus
+ .and_then(|focus_id| {
+ self.window
+ .rendered_frame
+ .dispatch_tree
+ .focusable_node_id(focus_id)
+ })
+ .is_some();
self.text_system().start_frame();
self.window.platform_window.clear_input_handler();
self.window.layout_engine.as_mut().unwrap().clear();
@@ -1273,6 +1285,23 @@ impl<'a> WindowContext<'a> {
});
}
+ let window_is_focused = self
+ .window
+ .focus
+ .and_then(|focus_id| {
+ self.window
+ .next_frame
+ .dispatch_tree
+ .focusable_node_id(focus_id)
+ })
+ .is_some();
+ if window_was_focused && !window_is_focused {
+ self.window
+ .blur_listeners
+ .clone()
+ .retain(&(), |listener| listener(self));
+ }
+
self.window
.next_frame
.dispatch_tree
@@ -2423,23 +2452,16 @@ impl<'a, V: 'static> ViewContext<'a, V> {
/// Register a listener to be called when the window loses focus.
/// Unlike [on_focus_changed], returns a subscription and persists until the subscription
/// is dropped.
- pub fn on_window_focus_lost(
+ pub fn on_blur_window(
&mut self,
mut listener: impl FnMut(&mut V, &mut ViewContext<V>) + 'static,
) -> Subscription {
let view = self.view.downgrade();
- let (subscription, activate) = self.window.focus_listeners.insert(
+ let (subscription, activate) = self.window.blur_listeners.insert(
(),
- Box::new(move |event, cx| {
- view.update(cx, |view, cx| {
- if event.blurred.is_none() && event.focused.is_none() {
- listener(view, cx)
- }
- })
- .is_ok()
- }),
+ Box::new(move |cx| view.update(cx, |view, cx| listener(view, cx)).is_ok()),
);
- self.app.defer(move |_| activate());
+ activate();
subscription
}