@@ -1470,6 +1470,7 @@ impl AppContext {
.push_back(Effect::Focus(FocusEffect::View {
window_id,
view_id: Some(view_id),
+ is_forced: false,
}));
}
@@ -1492,7 +1493,7 @@ impl AppContext {
let mut refreshing = false;
let mut updated_windows = HashSet::default();
- let mut focus_changes = HashMap::default();
+ let mut focus_effects = HashMap::<usize, FocusEffect>::default();
loop {
self.remove_dropped_entities();
if let Some(effect) = self.pending_effects.pop_front() {
@@ -1567,8 +1568,15 @@ impl AppContext {
self.handle_entity_release_effect(view_id, view.as_any())
}
- Effect::Focus(effect) => {
- focus_changes.insert(effect.window_id(), effect);
+ Effect::Focus(mut effect) => {
+ if focus_effects
+ .get(&effect.window_id())
+ .map_or(false, |prev_effect| prev_effect.is_forced())
+ {
+ effect.force();
+ }
+
+ focus_effects.insert(effect.window_id(), effect);
}
Effect::FocusObservation {
@@ -1609,7 +1617,22 @@ impl AppContext {
Effect::ActivateWindow {
window_id,
is_active,
- } => self.handle_window_activation_effect(window_id, is_active),
+ } => {
+ if self.handle_window_activation_effect(window_id, is_active)
+ && is_active
+ {
+ focus_effects
+ .entry(window_id)
+ .or_insert_with(|| FocusEffect::View {
+ window_id,
+ view_id: self
+ .read_window(window_id, |cx| cx.focused_view_id())
+ .flatten(),
+ is_forced: true,
+ })
+ .force();
+ }
+ }
Effect::WindowFullscreenObservation {
window_id,
@@ -1692,7 +1715,7 @@ impl AppContext {
});
}
- for (_, effect) in focus_changes.drain() {
+ for (_, effect) in focus_effects.drain() {
self.handle_focus_effect(effect);
}
@@ -1846,28 +1869,18 @@ impl AppContext {
});
}
- fn handle_window_activation_effect(&mut self, window_id: usize, active: bool) {
+ fn handle_window_activation_effect(&mut self, window_id: usize, active: bool) -> bool {
self.update_window(window_id, |cx| {
if cx.window.is_active == active {
- return;
+ return false;
}
cx.window.is_active = active;
- if let Some(focused_id) = cx.window.focused_view_id {
- for view_id in cx.ancestors(focused_id).collect::<Vec<_>>() {
- cx.update_any_view(view_id, |view, cx| {
- if active {
- view.focus_in(focused_id, cx, view_id);
- } else {
- view.focus_out(focused_id, cx, view_id);
- }
- });
- }
- }
-
let mut observations = cx.window_activation_observations.clone();
observations.emit(window_id, |callback| callback(active, cx));
- });
+ true
+ })
+ .unwrap_or(false)
}
fn handle_focus_effect(&mut self, effect: FocusEffect) {
@@ -1877,41 +1890,37 @@ impl AppContext {
FocusEffect::View { view_id, .. } => view_id,
FocusEffect::ViewParent { view_id, .. } => cx.ancestors(view_id).skip(1).next(),
};
- if cx.window.focused_view_id == focused_id {
- return;
- }
+
+ let focus_changed = cx.window.focused_view_id != focused_id;
let blurred_id = cx.window.focused_view_id;
cx.window.focused_view_id = focused_id;
- let blurred_parents = blurred_id
- .map(|blurred_id| cx.ancestors(blurred_id).collect::<Vec<_>>())
- .unwrap_or_default();
- let focused_parents = focused_id
- .map(|focused_id| cx.ancestors(focused_id).collect::<Vec<_>>())
- .unwrap_or_default();
-
- if let Some(blurred_id) = blurred_id {
- for view_id in blurred_parents.iter().copied() {
- if let Some(mut view) = cx.views.remove(&(window_id, view_id)) {
- view.focus_out(blurred_id, cx, view_id);
- cx.views.insert((window_id, view_id), view);
+ if focus_changed {
+ if let Some(blurred_id) = blurred_id {
+ for view_id in cx.ancestors(blurred_id).collect::<Vec<_>>() {
+ if let Some(mut view) = cx.views.remove(&(window_id, view_id)) {
+ view.focus_out(blurred_id, cx, view_id);
+ cx.views.insert((window_id, view_id), view);
+ }
}
- }
- let mut subscriptions = cx.focus_observations.clone();
- subscriptions.emit(blurred_id, |callback| callback(false, cx));
+ let mut subscriptions = cx.focus_observations.clone();
+ subscriptions.emit(blurred_id, |callback| callback(false, cx));
+ }
}
- if let Some(focused_id) = focused_id {
- for view_id in focused_parents {
- if let Some(mut view) = cx.views.remove(&(window_id, view_id)) {
- view.focus_in(focused_id, cx, view_id);
- cx.views.insert((window_id, view_id), view);
+ if focus_changed || effect.is_forced() {
+ if let Some(focused_id) = focused_id {
+ for view_id in cx.ancestors(focused_id).collect::<Vec<_>>() {
+ if let Some(mut view) = cx.views.remove(&(window_id, view_id)) {
+ view.focus_in(focused_id, cx, view_id);
+ cx.views.insert((window_id, view_id), view);
+ }
}
- }
- let mut subscriptions = cx.focus_observations.clone();
- subscriptions.emit(focused_id, |callback| callback(true, cx));
+ let mut subscriptions = cx.focus_observations.clone();
+ subscriptions.emit(focused_id, |callback| callback(true, cx));
+ }
}
});
}
@@ -1963,7 +1972,11 @@ impl AppContext {
pub fn focus(&mut self, window_id: usize, view_id: Option<usize>) {
self.pending_effects
- .push_back(Effect::Focus(FocusEffect::View { window_id, view_id }));
+ .push_back(Effect::Focus(FocusEffect::View {
+ window_id,
+ view_id,
+ is_forced: false,
+ }));
}
fn spawn_internal<F, Fut, T>(&mut self, task_name: Option<&'static str>, f: F) -> Task<T>
@@ -2064,10 +2077,12 @@ pub enum FocusEffect {
View {
window_id: usize,
view_id: Option<usize>,
+ is_forced: bool,
},
ViewParent {
window_id: usize,
view_id: usize,
+ is_forced: bool,
},
}
@@ -2078,6 +2093,20 @@ impl FocusEffect {
FocusEffect::ViewParent { window_id, .. } => *window_id,
}
}
+
+ fn is_forced(&self) -> bool {
+ match self {
+ FocusEffect::View { is_forced, .. } => *is_forced,
+ FocusEffect::ViewParent { is_forced, .. } => *is_forced,
+ }
+ }
+
+ fn force(&mut self) {
+ match self {
+ FocusEffect::View { is_forced, .. } => *is_forced = true,
+ FocusEffect::ViewParent { is_forced, .. } => *is_forced = true,
+ }
+ }
}
pub enum Effect {
@@ -2866,6 +2895,7 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
.push_back(Effect::Focus(FocusEffect::ViewParent {
window_id,
view_id,
+ is_forced: false,
}));
}