This commit is contained in:
Antonio Scandurra 2023-10-18 17:27:59 +02:00
parent 24086191af
commit 03937a9f89
2 changed files with 87 additions and 16 deletions

View File

@ -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);

View File

@ -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) {