editor: Fix pane's tab buttons flicker on right-click (#42549)
Whenever right-click was used on the editor, the pane's tab buttons
would flicker, which was confirmed to happen because of the following
check:
```
self.focus_handle.contains_focused(window, cx)
|| self
.active_item()
.is_some_and(|item| {
item.item_focus_handle(cx).contains_focused(window, cx)
})
```
This check was returning `false` right after right-clicking but
returning `true` right after. When digging into it a little bit more,
this appears to be happening because the editor's `MouseContextMenu`
relies on `ContextMenu` which is rendered in a deferred fashion but
`MouseContextMenu` updates the window's focus to it instantaneously.
Since the `ContextMenu` is rendered in a deferred fashion, its focus
handle is not yet a descendant of the editor (pane's active item) focus
handle, so the `contains_focused(window, cx)` call would return `false`,
with it returning `true` after the menu was rendered.
This commit updates the `MouseContextMenu::new` function to leverage
`cx.on_next_frame` and ensure that the focus is only moved to the
`ContextMenu` 2 frames later, ensuring that by the time the focus is
moved, the `ContextMenu`'s focus handle is a descendant of the editor's.
Closes #41771
Release Notes:
- Fixed pane's tab buttons flickering when using right-click on the
editor
This commit is contained in:
@@ -81,7 +81,19 @@ impl MouseContextMenu {
|
||||
cx: &mut Context<Editor>,
|
||||
) -> Self {
|
||||
let context_menu_focus = context_menu.focus_handle(cx);
|
||||
window.focus(&context_menu_focus);
|
||||
|
||||
// Since `ContextMenu` is rendered in a deferred fashion its focus
|
||||
// handle is not linked to the Editor's until after the deferred draw
|
||||
// callback runs.
|
||||
// We need to wait for that to happen before focusing it, so that
|
||||
// calling `contains_focused` on the editor's focus handle returns
|
||||
// `true` when the `ContextMenu` is focused.
|
||||
let focus_handle = context_menu_focus.clone();
|
||||
cx.on_next_frame(window, move |_, window, cx| {
|
||||
cx.on_next_frame(window, move |_, window, _cx| {
|
||||
window.focus(&focus_handle);
|
||||
});
|
||||
});
|
||||
|
||||
let _dismiss_subscription = cx.subscribe_in(&context_menu, window, {
|
||||
let context_menu_focus = context_menu_focus.clone();
|
||||
@@ -329,8 +341,18 @@ mod tests {
|
||||
}
|
||||
"});
|
||||
cx.editor(|editor, _window, _app| assert!(editor.mouse_context_menu.is_none()));
|
||||
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
deploy_context_menu(editor, Some(Default::default()), point, window, cx)
|
||||
deploy_context_menu(editor, Some(Default::default()), point, window, cx);
|
||||
|
||||
// Assert that, even after deploying the editor's mouse context
|
||||
// menu, the editor's focus handle still contains the focused
|
||||
// element. The pane's tab bar relies on this to determine whether
|
||||
// to show the tab bar buttons and there was a small flicker when
|
||||
// deploying the mouse context menu that would cause this to not be
|
||||
// true, making it so that the buttons would disappear for a couple
|
||||
// of frames.
|
||||
assert!(editor.focus_handle.contains_focused(window, cx));
|
||||
});
|
||||
|
||||
cx.assert_editor_state(indoc! {"
|
||||
|
||||
Reference in New Issue
Block a user