Compare commits

...

9 Commits

Author SHA1 Message Date
Antonio Scandurra
a24b8f2e09 zed 0.127.2 2024-03-18 18:35:25 +01:00
gcp-cherry-pick-bot[bot]
642fd36fdc Fix dispatching global actions from a window (cherry-pick #9502) (#9504)
Cherry-picked Fix dispatching global actions from a window (#9502)

Fixes https://github.com/zed-industries/zed/issues/9313

Release Notes:

- Fixed a regression that caused global actions to stop working when
invoked from a window (preview-only)
([#9313](https://github.com/zed-industries/zed/issues/9313)).

Co-authored-by: Conrad <conrad@zed.dev>

Co-authored-by: Antonio Scandurra <me@as-cii.com>
Co-authored-by: Conrad <conrad@zed.dev>
2024-03-18 18:33:36 +01:00
gcp-cherry-pick-bot[bot]
743760be87 Automatically create a hitbox for focusable elements (cherry-pick #9485) (#9486)
Cherry-picked Automatically create a hitbox for focusable elements
(#9485)

Closes #9462

This fixes the focus story in the storybook.

Release Notes:

- N/A

Co-authored-by: Antonio Scandurra <me@as-cii.com>
2024-03-18 09:59:07 +01:00
gcp-cherry-pick-bot[bot]
2db783ad04 Fix flickering when interacting with the language server logs (cherry-pick #9390) (#9435)
Cherry-picked Fix flickering when interacting with the language server
logs (#9390)

Fixes https://github.com/zed-industries/zed/issues/9340

The flickering was caused by the pane trying to restore focus on a
`FocusHandle` that wasn't being rendered anymore. This commit uses the
new `WeakFocusHandle` to avoid retaining a reference to focus handles
that don't exist anymore.

Release Notes:

- Fixed a bug that caused flickering when interacting with the language
server logs
([#9340](https://github.com/zed-industries/zed/issues/9340)).

Co-authored-by: Antonio Scandurra <me@as-cii.com>
2024-03-16 10:11:49 +01:00
Antonio Scandurra
597858ef99 zed 0.127.1 2024-03-14 09:47:22 +01:00
gcp-cherry-pick-bot[bot]
327879e054 Fix double-clicking titlebar to zoom (cherry-pick #9323) (#9327)
Cherry-picked Fix double-clicking titlebar to zoom (#9323)

Fixes https://github.com/zed-industries/zed/issues/9300

This was a regression caused by not inserting a hitbox when a div only
had click listeners on it.

Release Notes:

- Fixed a regression that disabled double-clicking on the titlebar to
zoom the window.
([#9300](https://github.com/zed-industries/zed/issues/9300))
(preview-only)

Co-authored-by: Antonio Scandurra <me@as-cii.com>
2024-03-14 09:38:05 +01:00
gcp-cherry-pick-bot[bot]
c1b4f3d817 Fix accidental leak of text stack between frames (cherry-pick #9297) (#9324)
Cherry-picked Fix accidental leak of text stack between frames (#9297)

Co-Authored-By: Max <max@zed.dev>
Co-Authored-By: Marshall <marshall@zed.dev>

Release Notes:

- Fixed a bug where text styles could leak between frames (preview only)

Co-authored-by: Max <max@zed.dev>
Co-authored-by: Marshall <marshall@zed.dev>

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: Max <max@zed.dev>
Co-authored-by: Marshall <marshall@zed.dev>
2024-03-14 09:34:20 +01:00
gcp-cherry-pick-bot[bot]
5bc4c4250c Automatically reset cursor style when hit test changes (cherry-pick #9289) (#9322)
Cherry-picked Automatically reset cursor style when hit test changes
(#9289)

Release Notes:

- N/A

Co-authored-by: Nathan Sobo <nathan@zed.dev>

Co-authored-by: Antonio Scandurra <me@as-cii.com>
Co-authored-by: Nathan Sobo <nathan@zed.dev>
2024-03-14 09:31:50 +01:00
Joseph T. Lyons
ced690dc0b v0.127.x preview 2024-03-13 11:57:21 -04:00
9 changed files with 138 additions and 42 deletions

2
Cargo.lock generated
View File

@@ -12748,7 +12748,7 @@ dependencies = [
[[package]]
name = "zed"
version = "0.127.0"
version = "0.127.2"
dependencies = [
"activity_indicator",
"anyhow",

View File

@@ -1144,7 +1144,7 @@ impl AppContext {
}
}
pub(crate) fn dispatch_global_action(&mut self, action: &dyn Action) {
fn dispatch_global_action(&mut self, action: &dyn Action) {
self.propagate_event = true;
if let Some(mut global_listeners) = self

View File

@@ -1307,6 +1307,7 @@ impl Interactivity {
|| self.has_hover_styles()
|| self.has_mouse_listeners()
|| self.scroll_offset.is_some()
|| self.tracked_focus_handle.is_some()
{
Some(cx.insert_hitbox(bounds, self.occlude_mouse))
} else {
@@ -1330,6 +1331,7 @@ impl Interactivity {
!self.mouse_up_listeners.is_empty()
|| !self.mouse_down_listeners.is_empty()
|| !self.mouse_move_listeners.is_empty()
|| !self.click_listeners.is_empty()
|| !self.scroll_wheel_listeners.is_empty()
|| self.drag_listener.is_some()
|| !self.drop_listeners.is_empty()

View File

@@ -29,7 +29,7 @@ use std::{
rc::Rc,
sync::{
atomic::{AtomicUsize, Ordering::SeqCst},
Arc,
Arc, Weak,
},
time::{Duration, Instant},
};
@@ -155,6 +155,14 @@ impl FocusHandle {
}
}
/// Converts this focus handle into a weak variant, which does not prevent it from being released.
pub fn downgrade(&self) -> WeakFocusHandle {
WeakFocusHandle {
id: self.id,
handles: Arc::downgrade(&self.handles),
}
}
/// Moves the focus to the element associated with this handle.
pub fn focus(&self, cx: &mut WindowContext) {
cx.focus(self)
@@ -207,6 +215,41 @@ impl Drop for FocusHandle {
}
}
/// A weak reference to a focus handle.
#[derive(Clone, Debug)]
pub struct WeakFocusHandle {
pub(crate) id: FocusId,
handles: Weak<RwLock<SlotMap<FocusId, AtomicUsize>>>,
}
impl WeakFocusHandle {
/// Attempts to upgrade the [WeakFocusHandle] to a [FocusHandle].
pub fn upgrade(&self) -> Option<FocusHandle> {
let handles = self.handles.upgrade()?;
FocusHandle::for_id(self.id, &handles)
}
}
impl PartialEq for WeakFocusHandle {
fn eq(&self, other: &WeakFocusHandle) -> bool {
self.id == other.id
}
}
impl Eq for WeakFocusHandle {}
impl PartialEq<FocusHandle> for WeakFocusHandle {
fn eq(&self, other: &FocusHandle) -> bool {
self.id == other.id
}
}
impl PartialEq<WeakFocusHandle> for FocusHandle {
fn eq(&self, other: &WeakFocusHandle) -> bool {
self.id == other.id
}
}
/// FocusableView allows users of your view to easily
/// focus it (using cx.focus_view(view))
pub trait FocusableView: 'static + Render {
@@ -653,7 +696,6 @@ impl<'a> WindowContext<'a> {
let window = self.window.handle;
self.app.defer(move |cx| {
cx.propagate_event = true;
window
.update(cx, |_, cx| {
let node_id = focus_handle
@@ -668,9 +710,6 @@ impl<'a> WindowContext<'a> {
cx.dispatch_action_on_node(node_id, action.as_ref());
})
.log_err();
if cx.propagate_event {
cx.dispatch_global_action(action.as_ref());
}
})
}
@@ -956,12 +995,6 @@ impl<'a> WindowContext<'a> {
self.window.next_frame.focus = self.window.focus;
self.window.next_frame.window_active = self.window.active.get();
// Set the cursor only if we're the active window.
if self.is_window_active() {
let cursor_style = self.compute_cursor_style().unwrap_or(CursorStyle::Arrow);
self.platform.set_cursor_style(cursor_style);
}
// Register requested input handler with the platform window.
if let Some(input_handler) = self.window.next_frame.input_handlers.pop() {
self.window
@@ -1017,6 +1050,8 @@ impl<'a> WindowContext<'a> {
.clone()
.retain(&(), |listener| listener(&event, self));
}
self.reset_cursor_style();
self.window.refreshing = false;
self.window.draw_phase = DrawPhase::None;
self.window.needs_present.set(true);
@@ -1031,16 +1066,20 @@ impl<'a> WindowContext<'a> {
profiling::finish_frame!();
}
fn compute_cursor_style(&mut self) -> Option<CursorStyle> {
// TODO: maybe we should have a HashMap keyed by HitboxId.
let request = self
.window
.next_frame
.cursor_styles
.iter()
.rev()
.find(|request| request.hitbox_id.is_hovered(self))?;
Some(request.style)
fn reset_cursor_style(&self) {
// Set the cursor only if we're the active window.
if self.is_window_active() {
let style = self
.window
.rendered_frame
.cursor_styles
.iter()
.rev()
.find(|request| request.hitbox_id.is_hovered(self))
.map(|request| request.style)
.unwrap_or(CursorStyle::Arrow);
self.platform.set_cursor_style(style);
}
}
/// Dispatch a given keystroke as though the user had typed it.
@@ -1175,7 +1214,11 @@ impl<'a> WindowContext<'a> {
}
fn dispatch_mouse_event(&mut self, event: &dyn Any) {
self.window.mouse_hit_test = self.window.rendered_frame.hit_test(self.mouse_position());
let hit_test = self.window.rendered_frame.hit_test(self.mouse_position());
if hit_test != self.window.mouse_hit_test {
self.window.mouse_hit_test = hit_test;
self.reset_cursor_style();
}
let mut mouse_listeners = mem::take(&mut self.window.rendered_frame.mouse_listeners);
self.with_element_context(|cx| {
@@ -1407,7 +1450,34 @@ impl<'a> WindowContext<'a> {
.dispatch_tree
.dispatch_path(node_id);
// Capture phase
// Capture phase for global actions.
self.propagate_event = true;
if let Some(mut global_listeners) = self
.global_action_listeners
.remove(&action.as_any().type_id())
{
for listener in &global_listeners {
listener(action.as_any(), DispatchPhase::Capture, self);
if !self.propagate_event {
break;
}
}
global_listeners.extend(
self.global_action_listeners
.remove(&action.as_any().type_id())
.unwrap_or_default(),
);
self.global_action_listeners
.insert(action.as_any().type_id(), global_listeners);
}
if !self.propagate_event {
return;
}
// Capture phase for window actions.
for node_id in &dispatch_path {
let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
for DispatchActionListener {
@@ -1427,7 +1497,8 @@ impl<'a> WindowContext<'a> {
}
}
}
// Bubble phase
// Bubble phase for window actions.
for node_id in dispatch_path.iter().rev() {
let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
for DispatchActionListener {
@@ -1449,6 +1520,30 @@ impl<'a> WindowContext<'a> {
}
}
}
// Bubble phase for global actions.
if let Some(mut global_listeners) = self
.global_action_listeners
.remove(&action.as_any().type_id())
{
for listener in global_listeners.iter().rev() {
self.propagate_event = false; // Actions stop propagation by default during the bubble phase
listener(action.as_any(), DispatchPhase::Bubble, self);
if !self.propagate_event {
break;
}
}
global_listeners.extend(
self.global_action_listeners
.remove(&action.as_any().type_id())
.unwrap_or_default(),
);
self.global_action_listeners
.insert(action.as_any().type_id(), global_listeners);
}
}
/// Register the given handler to be invoked whenever the global of the given type

View File

@@ -79,7 +79,7 @@ impl Hitbox {
}
}
#[derive(Default)]
#[derive(Default, Eq, PartialEq)]
pub(crate) struct HitTest(SmallVec<[HitboxId; 8]>);
pub(crate) struct DeferredDraw {
@@ -432,6 +432,7 @@ impl<'a> ElementContext<'a> {
);
self.window.next_frame.deferred_draws = deferred_draws;
self.window.element_id_stack.clear();
self.window.text_style_stack.clear();
}
fn paint_deferred_draws(&mut self, deferred_draw_indices: &[usize]) {

View File

@@ -12,7 +12,7 @@ use gpui::{
AsyncWindowContext, ClickEvent, DismissEvent, Div, DragMoveEvent, EntityId, EventEmitter,
ExternalPaths, FocusHandle, FocusableView, Model, MouseButton, NavigationDirection, Pixels,
Point, PromptLevel, Render, ScrollHandle, Subscription, Task, View, ViewContext, VisualContext,
WeakView, WindowContext,
WeakFocusHandle, WeakView, WindowContext,
};
use parking_lot::Mutex;
use project::{Project, ProjectEntryId, ProjectPath};
@@ -166,7 +166,7 @@ pub struct Pane {
zoomed: bool,
was_focused: bool,
active_item_index: usize,
last_focused_view_by_item: HashMap<EntityId, FocusHandle>,
last_focus_handle_by_item: HashMap<EntityId, WeakFocusHandle>,
nav_history: NavHistory,
toolbar: View<Toolbar>,
new_item_menu: Option<View<ContextMenu>>,
@@ -262,7 +262,7 @@ impl Pane {
was_focused: false,
zoomed: false,
active_item_index: 0,
last_focused_view_by_item: Default::default(),
last_focus_handle_by_item: Default::default(),
nav_history: NavHistory(Arc::new(Mutex::new(NavHistoryState {
mode: NavigationMode::Normal,
backward_stack: Default::default(),
@@ -380,18 +380,20 @@ impl Pane {
if self.focus_handle.is_focused(cx) {
// Pane was focused directly. We need to either focus a view inside the active item,
// or focus the active item itself
if let Some(weak_last_focused_view) =
self.last_focused_view_by_item.get(&active_item.item_id())
if let Some(weak_last_focus_handle) =
self.last_focus_handle_by_item.get(&active_item.item_id())
{
weak_last_focused_view.focus(cx);
return;
if let Some(focus_handle) = weak_last_focus_handle.upgrade() {
focus_handle.focus(cx);
return;
}
}
active_item.focus_handle(cx).focus(cx);
} else if let Some(focused) = cx.focused() {
if !self.context_menu_focused(cx) {
self.last_focused_view_by_item
.insert(active_item.item_id(), focused);
self.last_focus_handle_by_item
.insert(active_item.item_id(), focused.downgrade());
}
}
}

View File

@@ -941,8 +941,6 @@ mod element {
let flexes = self.flexes.clone();
let child_bounds = child.bounds;
let axis = self.axis;
let handle_hitbox = handle.hitbox.clone();
let was_hovered = handle_hitbox.is_hovered(cx);
move |e: &MouseMoveEvent, phase, cx| {
let dragged_handle = dragged_handle.borrow();
if phase.bubble() {
@@ -957,8 +955,6 @@ mod element {
workspace.clone(),
cx,
)
} else if was_hovered != handle_hitbox.is_hovered(cx) {
cx.refresh();
}
}
}

View File

@@ -2,7 +2,7 @@
description = "The fast, collaborative code editor."
edition = "2021"
name = "zed"
version = "0.127.0"
version = "0.127.2"
publish = false
license = "GPL-3.0-or-later"
authors = ["Zed Team <hi@zed.dev>"]

View File

@@ -1 +1 @@
dev
preview