diff --git a/crates/gpui3/src/elements/div.rs b/crates/gpui3/src/elements/div.rs index 552c27686ed3e15488f04439c226080a7db17050..3623e44a921bb323fbc4e7f8829f8a0e2917d64c 100644 --- a/crates/gpui3/src/elements/div.rs +++ b/crates/gpui3/src/elements/div.rs @@ -375,10 +375,17 @@ where element_state: Option, cx: &mut ViewContext, ) -> Self::ElementState { - for child in &mut self.children { - child.initialize(view_state, cx); - } - element_state.unwrap_or_default() + cx.with_focus( + self.focusability.focus_handle().cloned(), + self.listeners.key_down.clone(), + self.listeners.key_up.clone(), + |cx| { + for child in &mut self.children { + child.initialize(view_state, cx); + } + element_state.unwrap_or_default() + }, + ) } fn layout( @@ -408,68 +415,57 @@ where cx: &mut ViewContext, ) { self.with_element_id(cx, |this, cx| { - cx.with_key_listeners( - this.focusability.focus_handle().cloned(), - this.listeners.key_down.clone(), - this.listeners.key_up.clone(), - |cx| { - if let Some(group) = this.group.clone() { - cx.default_global::() - .0 - .entry(group) - .or_default() - .push(bounds); - } + if let Some(group) = this.group.clone() { + cx.default_global::() + .0 + .entry(group) + .or_default() + .push(bounds); + } - let hover_group_bounds = this - .group_hover - .as_ref() - .and_then(|group_hover| group_bounds(&group_hover.group, cx)); - let active_group_bounds = this - .group_active - .as_ref() - .and_then(|group_active| group_bounds(&group_active.group, cx)); - let style = this.compute_style(bounds, element_state, cx); - let z_index = style.z_index.unwrap_or(0); - - // Paint background and event handlers. - cx.stack(z_index, |cx| { - cx.stack(0, |cx| { - style.paint(bounds, cx); - this.paint_hover_listeners(bounds, hover_group_bounds, cx); - this.paint_active_listener( - bounds, - active_group_bounds, - element_state.active_state.clone(), - cx, - ); - this.paint_event_listeners( - bounds, - element_state.pending_click.clone(), - cx, - ); - }); - - cx.stack(1, |cx| { - style.apply_text_style(cx, |cx| { - style.apply_overflow(bounds, cx, |cx| { - for child in &mut this.children { - child.paint(view_state, None, cx); - } - }) - }) - }); - }); - - if let Some(group) = this.group.as_ref() { - cx.default_global::() - .0 - .get_mut(group) - .unwrap() - .pop(); - } - }, - ) + let hover_group_bounds = this + .group_hover + .as_ref() + .and_then(|group_hover| group_bounds(&group_hover.group, cx)); + let active_group_bounds = this + .group_active + .as_ref() + .and_then(|group_active| group_bounds(&group_active.group, cx)); + let style = this.compute_style(bounds, element_state, cx); + let z_index = style.z_index.unwrap_or(0); + + // Paint background and event handlers. + cx.stack(z_index, |cx| { + cx.stack(0, |cx| { + style.paint(bounds, cx); + this.paint_hover_listeners(bounds, hover_group_bounds, cx); + this.paint_active_listener( + bounds, + active_group_bounds, + element_state.active_state.clone(), + cx, + ); + this.paint_event_listeners(bounds, element_state.pending_click.clone(), cx); + }); + + cx.stack(1, |cx| { + style.apply_text_style(cx, |cx| { + style.apply_overflow(bounds, cx, |cx| { + for child in &mut this.children { + child.paint(view_state, None, cx); + } + }) + }) + }); + }); + + if let Some(group) = this.group.as_ref() { + cx.default_global::() + .0 + .get_mut(group) + .unwrap() + .pop(); + } }) } } diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index e491913b29bba06a631ec5b353ade39223aa5568..c0744532ee70be4918773e8bb7433e903ccecf19 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -9,7 +9,7 @@ use crate::{ Task, Underline, UnderlineStyle, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS, }; use anyhow::Result; -use collections::HashMap; +use collections::{HashMap, HashSet}; use derive_more::{Deref, DerefMut}; use smallvec::SmallVec; use std::{ @@ -42,7 +42,7 @@ pub enum DispatchPhase { type MouseEventHandler = Arc; -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct FocusId(usize); #[derive(Clone)] @@ -64,10 +64,13 @@ pub struct Window { element_states: HashMap, z_index_stack: StackingOrder, content_mask_stack: Vec>, - mouse_event_handlers: HashMap>, - key_down_listener_stack: + mouse_listeners: HashMap>, + focus_stack: Vec, + focus_parents_by_child: HashMap, + focused_in: HashSet, + key_down_listeners: Vec>, - key_up_listener_stack: + key_up_listeners: Vec>, propagate_event: bool, mouse_position: Point, @@ -76,7 +79,6 @@ pub struct Window { pub(crate) dirty: bool, focus: Option, next_focus_id: FocusId, - painted_focused_element: bool, } impl Window { @@ -135,9 +137,12 @@ impl Window { element_states: HashMap::default(), z_index_stack: StackingOrder(SmallVec::new()), content_mask_stack: Vec::new(), - mouse_event_handlers: HashMap::default(), - key_down_listener_stack: Vec::new(), - key_up_listener_stack: Vec::new(), + focus_stack: Vec::new(), + focus_parents_by_child: HashMap::default(), + focused_in: HashSet::default(), + mouse_listeners: HashMap::default(), + key_down_listeners: Vec::new(), + key_up_listeners: Vec::new(), propagate_event: true, mouse_position, scale_factor, @@ -145,7 +150,6 @@ impl Window { dirty: true, focus: None, next_focus_id: FocusId(0), - painted_focused_element: false, } } } @@ -169,6 +173,16 @@ impl ContentMask { } } +struct FocusStackFrame { + handle: FocusHandle, + key_down_listeners: SmallVec< + [Arc; 2], + >, + key_up_listeners: SmallVec< + [Arc; 2], + >, +} + pub struct WindowContext<'a, 'w> { app: Reference<'a, AppContext>, pub(crate) window: Reference<'w, Window>, @@ -323,7 +337,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { ) { let order = self.window.z_index_stack.clone(); self.window - .mouse_event_handlers + .mouse_listeners .entry(TypeId::of::()) .or_default() .push(( @@ -675,12 +689,14 @@ impl<'a, 'w> WindowContext<'a, 'w> { // Clear mouse event listeners, because elements add new element listeners // when the upcoming frame is painted. - window - .mouse_event_handlers - .values_mut() - .for_each(Vec::clear); + window.mouse_listeners.values_mut().for_each(Vec::clear); - window.painted_focused_element = false; + // Clear focus state, because we determine what is focused when the new elements + // in the upcoming frame are initialized. + window.key_down_listeners.clear(); + window.key_up_listeners.clear(); + window.focused_in.clear(); + window.focus_parents_by_child.clear(); } fn end_frame(&mut self) { @@ -695,7 +711,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { if let Some(mut handlers) = self .window - .mouse_event_handlers + .mouse_listeners .remove(&any_mouse_event.type_id()) { // Because handlers may add other handlers, we sort every time. @@ -726,13 +742,13 @@ impl<'a, 'w> WindowContext<'a, 'w> { // Just in case any handlers added new handlers, which is weird, but possible. handlers.extend( self.window - .mouse_event_handlers + .mouse_listeners .get_mut(&any_mouse_event.type_id()) .into_iter() .flat_map(|handlers| handlers.drain(..)), ); self.window - .mouse_event_handlers + .mouse_listeners .insert(any_mouse_event.type_id(), handlers); } } @@ -1030,7 +1046,7 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> { }); } - pub fn with_key_listeners( + pub fn with_focus( &mut self, focus_handle: Option, key_down: impl IntoIterator>, @@ -1040,20 +1056,25 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> { let Some(focus_handle) = focus_handle else { return f(self); }; - let Some(focused_id) = self.window.focus else { - return f(self); - }; - if self.window.painted_focused_element { - return f(self); + + let handle = self.handle(); + let window = &mut *self.window; + if let Some(parent_frame) = window.focus_stack.last() { + window + .focus_parents_by_child + .insert(focus_handle.id, parent_frame.handle.id); } - let prev_key_down_len = self.window.key_down_listener_stack.len(); - let prev_key_up_len = self.window.key_up_listener_stack.len(); + let mut frame = FocusStackFrame { + handle: focus_handle.clone(), + key_down_listeners: SmallVec::new(), + key_up_listeners: SmallVec::new(), + }; for listener in key_down { - let handle = self.handle(); - self.window - .key_down_listener_stack + let handle = handle.clone(); + frame + .key_down_listeners .push(Arc::new(move |event, phase, cx| { handle .update(cx, |view, cx| listener(view, event, phase, cx)) @@ -1061,9 +1082,9 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> { })); } for listener in key_up { - let handle = self.handle(); - self.window - .key_up_listener_stack + let handle = handle.clone(); + frame + .key_up_listeners .push(Arc::new(move |event, phase, cx| { handle .update(cx, |view, cx| listener(view, event, phase, cx)) @@ -1071,19 +1092,22 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> { })); } - if focus_handle.id == focused_id { - self.window.painted_focused_element = true; + window.focus_stack.push(frame); + + if Some(focus_handle.id) == window.focus { + for frame in &window.focus_stack { + window.focused_in.insert(frame.handle.id); + window + .key_down_listeners + .extend_from_slice(&frame.key_down_listeners); + window + .key_up_listeners + .extend_from_slice(&frame.key_up_listeners); + } } let result = f(self); - - if focus_handle.id != focused_id { - self.window - .key_down_listener_stack - .truncate(prev_key_down_len); - self.window.key_up_listener_stack.truncate(prev_key_up_len); - } - + self.window.focus_stack.pop(); result }