@@ -5,7 +5,10 @@ use std::{
ops::{Deref, DerefMut},
path::{Path, PathBuf},
rc::{Rc, Weak},
- sync::{atomic::Ordering::SeqCst, Arc},
+ sync::{
+ atomic::{AtomicUsize, Ordering::SeqCst},
+ Arc,
+ },
time::Duration,
};
@@ -16,6 +19,7 @@ use futures::{
future::{LocalBoxFuture, Shared},
Future, FutureExt,
};
+use parking_lot::RwLock;
use slotmap::SlotMap;
pub use async_context::*;
@@ -30,11 +34,12 @@ use util::ResultExt;
use crate::{
current_platform, hash, init_app_menus, Action, ActionRegistry, Any, AnyView, AnyWindowHandle,
Asset, AssetSource, BackgroundExecutor, ClipboardItem, Context, DispatchPhase, DisplayId,
- Entity, EventEmitter, ForegroundExecutor, Global, KeyBinding, Keymap, Keystroke, LayoutId,
- Menu, MenuItem, OwnedMenu, PathPromptOptions, Pixels, Platform, PlatformDisplay, Point,
- PromptBuilder, PromptHandle, PromptLevel, Render, RenderablePromptHandle, Reservation,
- ScreenCaptureSource, SharedString, SubscriberSet, Subscription, SvgRenderer, Task, TextSystem,
- View, ViewContext, Window, WindowAppearance, WindowContext, WindowHandle, WindowId,
+ Entity, EventEmitter, FocusHandle, FocusId, ForegroundExecutor, Global, KeyBinding, Keymap,
+ Keystroke, LayoutId, Menu, MenuItem, OwnedMenu, PathPromptOptions, Pixels, Platform,
+ PlatformDisplay, Point, PromptBuilder, PromptHandle, PromptLevel, Render,
+ RenderablePromptHandle, Reservation, ScreenCaptureSource, SharedString, SubscriberSet,
+ Subscription, SvgRenderer, Task, TextSystem, View, ViewContext, Window, WindowAppearance,
+ WindowContext, WindowHandle, WindowId,
};
mod async_context;
@@ -242,6 +247,7 @@ pub struct AppContext {
pub(crate) new_view_observers: SubscriberSet<TypeId, NewViewListener>,
pub(crate) windows: SlotMap<WindowId, Option<Window>>,
pub(crate) window_handles: FxHashMap<WindowId, AnyWindowHandle>,
+ pub(crate) focus_handles: Arc<RwLock<SlotMap<FocusId, AtomicUsize>>>,
pub(crate) keymap: Rc<RefCell<Keymap>>,
pub(crate) keyboard_layout: SharedString,
pub(crate) global_action_listeners:
@@ -302,8 +308,9 @@ impl AppContext {
entities,
new_view_observers: SubscriberSet::new(),
new_model_observers: SubscriberSet::new(),
- window_handles: FxHashMap::default(),
windows: SlotMap::with_key(),
+ window_handles: FxHashMap::default(),
+ focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
keymap: Rc::new(RefCell::new(Keymap::default())),
keyboard_layout,
global_action_listeners: FxHashMap::default(),
@@ -439,6 +446,7 @@ impl AppContext {
self.defer(move |_| activate());
subscription
}
+
pub(crate) fn observe_internal<W, E>(
&mut self,
entity: &E,
@@ -569,6 +577,12 @@ impl AppContext {
})
}
+ /// Obtain a new [`FocusHandle`], which allows you to track and manipulate the keyboard focus
+ /// for elements rendered within this window.
+ pub fn focus_handle(&self) -> FocusHandle {
+ FocusHandle::new(&self.focus_handles)
+ }
+
/// Instructs the platform to activate the application by bringing it to the foreground.
pub fn activate(&self, ignoring_other_apps: bool) {
self.platform.activate(ignoring_other_apps);
@@ -844,28 +858,25 @@ impl AppContext {
/// Repeatedly called during `flush_effects` to handle a focused handle being dropped.
fn release_dropped_focus_handles(&mut self) {
- for window_handle in self.windows() {
- window_handle
- .update(self, |_, cx| {
- let mut blur_window = false;
- let focus = cx.window.focus;
- cx.window.focus_handles.write().retain(|handle_id, count| {
- if count.load(SeqCst) == 0 {
- if focus == Some(handle_id) {
- blur_window = true;
- }
- false
- } else {
- true
- }
- });
-
- if blur_window {
- cx.blur();
+ self.focus_handles
+ .clone()
+ .write()
+ .retain(|handle_id, count| {
+ if count.load(SeqCst) == 0 {
+ for window_handle in self.windows() {
+ window_handle
+ .update(self, |_, cx| {
+ if cx.window.focus == Some(handle_id) {
+ cx.blur();
+ }
+ })
+ .unwrap();
}
- })
- .unwrap();
- }
+ false
+ } else {
+ true
+ }
+ });
}
fn apply_notify_effect(&mut self, emitter: EntityId) {
@@ -531,7 +531,6 @@ pub struct Window {
pub(crate) tooltip_bounds: Option<TooltipBounds>,
next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>>,
pub(crate) dirty_views: FxHashSet<EntityId>,
- pub(crate) focus_handles: Arc<RwLock<SlotMap<FocusId, AtomicUsize>>>,
focus_listeners: SubscriberSet<(), AnyWindowFocusListener>,
focus_lost_listeners: SubscriberSet<(), AnyObserver>,
default_prevented: bool,
@@ -809,7 +808,6 @@ impl Window {
next_tooltip_id: TooltipId::default(),
tooltip_bounds: None,
dirty_views: FxHashSet::default(),
- focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
focus_listeners: SubscriberSet::new(),
focus_lost_listeners: SubscriberSet::new(),
default_prevented: true,
@@ -931,17 +929,11 @@ impl<'a> WindowContext<'a> {
self.window.removed = true;
}
- /// Obtain a new [`FocusHandle`], which allows you to track and manipulate the keyboard focus
- /// for elements rendered within this window.
- pub fn focus_handle(&self) -> FocusHandle {
- FocusHandle::new(&self.window.focus_handles)
- }
-
/// Obtain the currently focused [`FocusHandle`]. If no elements are focused, returns `None`.
pub fn focused(&self) -> Option<FocusHandle> {
self.window
.focus
- .and_then(|id| FocusHandle::for_id(id, &self.window.focus_handles))
+ .and_then(|id| FocusHandle::for_id(id, &self.app.focus_handles))
}
/// Move focus to the element associated with the given [`FocusHandle`].
@@ -3021,7 +3013,7 @@ impl<'a> WindowContext<'a> {
let event = FocusOutEvent {
blurred: WeakFocusHandle {
id: blurred_id,
- handles: Arc::downgrade(&cx.window.focus_handles),
+ handles: Arc::downgrade(&cx.app.focus_handles),
},
};
listener(event, cx)
@@ -4439,7 +4431,7 @@ impl<'a, V: 'static> ViewContext<'a, V> {
let event = FocusOutEvent {
blurred: WeakFocusHandle {
id: blurred_id,
- handles: Arc::downgrade(&cx.window.focus_handles),
+ handles: Arc::downgrade(&cx.app.focus_handles),
},
};
listener(view, event, cx)