@@ -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 {
@@ -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());
}
}
}