@@ -6,6 +6,7 @@ pub use async_context::*;
pub use entity_map::*;
pub use model_context::*;
use refineable::Refineable;
+use smallvec::SmallVec;
use crate::{
current_platform, image_cache::ImageCache, AssetSource, Context, DisplayId, Executor,
@@ -21,7 +22,7 @@ use slotmap::SlotMap;
use std::{
any::{type_name, Any, TypeId},
mem,
- sync::{Arc, Weak},
+ sync::{atomic::Ordering::SeqCst, Arc, Weak},
};
use util::http::{self, HttpClient};
@@ -170,6 +171,7 @@ impl AppContext {
fn flush_effects(&mut self) {
loop {
self.release_dropped_entities();
+ self.release_dropped_focus_handles();
if let Some(effect) = self.pending_effects.pop_front() {
match effect {
Effect::Notify { emitter } => self.apply_notify_effect(emitter),
@@ -194,7 +196,7 @@ impl AppContext {
None
}
})
- .collect::<Vec<_>>();
+ .collect::<SmallVec<[_; 8]>>();
for dirty_window_id in dirty_window_ids {
self.update_window(dirty_window_id, |cx| cx.draw()).unwrap();
@@ -218,6 +220,32 @@ impl AppContext {
}
}
+ fn release_dropped_focus_handles(&mut self) {
+ let window_ids = self.windows.keys().collect::<SmallVec<[_; 8]>>();
+ for window_id in window_ids {
+ self.update_window(window_id, |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.window.focus = None;
+ cx.blur();
+ }
+ })
+ .unwrap();
+ }
+ }
+
fn apply_notify_effect(&mut self, emitter: EntityId) {
self.pending_notifications.remove(&emitter);
self.observers
@@ -235,8 +263,12 @@ impl AppContext {
self.update_window(window_id, |cx| {
if cx.window.focus == focused {
let mut listeners = mem::take(&mut cx.window.focus_listeners);
- let focused = focused.map(FocusHandle::new);
- let blurred = cx.window.last_blur.unwrap().map(FocusHandle::new);
+ let focused = focused.map(|id| FocusHandle::for_id(id, &cx.window.focus_handles));
+ let blurred = cx
+ .window
+ .last_blur
+ .unwrap()
+ .map(|id| FocusHandle::for_id(id, &cx.window.focus_handles));
let event = FocusEvent { focused, blurred };
for listener in &listeners {
listener(&event, cx);
@@ -12,6 +12,8 @@ use crate::{
use anyhow::Result;
use collections::HashMap;
use derive_more::{Deref, DerefMut};
+use parking_lot::{RwLock, RwLockUpgradableReadGuard};
+use slotmap::SlotMap;
use smallvec::SmallVec;
use std::{
any::{Any, TypeId},
@@ -20,9 +22,12 @@ use std::{
future::Future,
marker::PhantomData,
mem,
- sync::Arc,
+ sync::{
+ atomic::{AtomicUsize, Ordering::SeqCst},
+ Arc, Weak,
+ },
};
-use util::{post_inc, ResultExt};
+use util::ResultExt;
#[derive(Deref, DerefMut, Ord, PartialOrd, Eq, PartialEq, Clone, Default)]
pub struct StackingOrder(pub(crate) SmallVec<[u32; 16]>);
@@ -50,17 +55,34 @@ type AnyKeyDownListener =
type AnyKeyUpListener =
Box<dyn Fn(&KeyUpEvent, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
-pub struct FocusId(usize);
+slotmap::new_key_type! { pub struct FocusId; }
-#[derive(Clone, PartialEq, Eq)]
+#[derive(Clone)]
pub struct FocusHandle {
pub(crate) id: FocusId,
+ handles: Weak<RwLock<SlotMap<FocusId, AtomicUsize>>>,
}
impl FocusHandle {
- pub(crate) fn new(id: FocusId) -> Self {
- Self { id }
+ pub(crate) fn new(handles: &Arc<RwLock<SlotMap<FocusId, AtomicUsize>>>) -> Self {
+ let id = handles.write().insert(AtomicUsize::new(1));
+ Self {
+ id,
+ handles: Arc::downgrade(handles),
+ }
+ }
+
+ pub(crate) fn for_id(
+ id: FocusId,
+ handles: &Arc<RwLock<SlotMap<FocusId, AtomicUsize>>>,
+ ) -> Self {
+ let lock = handles.upgradable_read();
+ let ref_count = lock.get(id).expect("all focus handles dropped for id");
+ ref_count.fetch_add(1, SeqCst);
+ Self {
+ id,
+ handles: Arc::downgrade(handles),
+ }
}
pub fn is_focused(&self, cx: &WindowContext) -> bool {
@@ -90,6 +112,22 @@ impl FocusHandle {
}
}
+impl PartialEq for FocusHandle {
+ fn eq(&self, other: &Self) -> bool {
+ self.id == other.id
+ }
+}
+
+impl Eq for FocusHandle {}
+
+impl Drop for FocusHandle {
+ fn drop(&mut self) {
+ if let Some(handles) = self.handles.upgrade() {
+ handles.read().get(self.id).unwrap().fetch_sub(1, SeqCst);
+ }
+ }
+}
+
pub struct Window {
handle: AnyWindowHandle,
platform_window: MainThreadOnly<Box<dyn PlatformWindow>>,
@@ -109,6 +147,7 @@ pub struct Window {
focus_stack: Vec<FocusStackFrame>,
focus_parents_by_child: HashMap<FocusId, FocusId>,
pub(crate) focus_listeners: Vec<AnyFocusListener>,
+ pub(crate) focus_handles: Arc<RwLock<SlotMap<FocusId, AtomicUsize>>>,
propagate_event: bool,
mouse_position: Point<Pixels>,
scale_factor: f32,
@@ -116,7 +155,6 @@ pub struct Window {
pub(crate) dirty: bool,
pub(crate) last_blur: Option<Option<FocusId>>,
pub(crate) focus: Option<FocusId>,
- next_focus_id: FocusId,
}
impl Window {
@@ -185,9 +223,9 @@ impl Window {
scale_factor,
scene_builder: SceneBuilder::new(),
dirty: true,
+ focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
last_blur: None,
focus: None,
- next_focus_id: FocusId(0),
}
}
}
@@ -235,12 +273,13 @@ impl<'a, 'w> WindowContext<'a, 'w> {
}
pub fn focus_handle(&mut self) -> FocusHandle {
- let id = FocusId(post_inc(&mut self.window.next_focus_id.0));
- FocusHandle { id }
+ FocusHandle::new(&self.window.focus_handles)
}
pub fn focused(&self) -> Option<FocusHandle> {
- self.window.focus.map(|id| FocusHandle::new(id))
+ self.window
+ .focus
+ .map(|id| FocusHandle::for_id(id, &self.window.focus_handles))
}
pub fn focus(&mut self, handle: &FocusHandle) {