This commit is contained in:
Antonio Scandurra
2023-10-22 12:21:28 +02:00
parent 909fbb9538
commit f4135e6bcf
12 changed files with 860 additions and 637 deletions
+41 -4
View File
@@ -9,10 +9,11 @@ use refineable::Refineable;
use smallvec::SmallVec;
use crate::{
current_platform, image_cache::ImageCache, Action, AssetSource, Context, DisplayId, Executor,
FocusEvent, FocusHandle, FocusId, KeyBinding, Keymap, LayoutId, MainThread, MainThreadOnly,
Platform, SemanticVersion, SharedString, SubscriberSet, SvgRenderer, Task, TextStyle,
TextStyleRefinement, TextSystem, View, Window, WindowContext, WindowHandle, WindowId,
current_platform, image_cache::ImageCache, Action, AssetSource, Context, DispatchPhase,
DisplayId, Executor, FocusEvent, FocusHandle, FocusId, KeyBinding, Keymap, LayoutId,
MainThread, MainThreadOnly, Platform, SemanticVersion, SharedString, SubscriberSet,
SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem, View, Window, WindowContext,
WindowHandle, WindowId,
};
use anyhow::{anyhow, Result};
use collections::{HashMap, HashSet, VecDeque};
@@ -67,6 +68,7 @@ impl App {
entities,
windows: SlotMap::with_key(),
keymap: Arc::new(RwLock::new(Keymap::default())),
global_action_listeners: HashMap::default(),
action_builders: HashMap::default(),
pending_notifications: Default::default(),
pending_effects: Default::default(),
@@ -74,6 +76,7 @@ impl App {
event_handlers: SubscriberSet::new(),
release_handlers: SubscriberSet::new(),
layout_id_buffer: Default::default(),
propagate_event: true,
})
}))
}
@@ -168,6 +171,8 @@ pub struct AppContext {
pub(crate) entities: EntityMap,
pub(crate) windows: SlotMap<WindowId, Option<Window>>,
pub(crate) keymap: Arc<RwLock<Keymap>>,
pub(crate) global_action_listeners:
HashMap<TypeId, Vec<Box<dyn Fn(&dyn Action, DispatchPhase, &mut Self) + Send + Sync>>>,
action_builders: HashMap<SharedString, ActionBuilder>,
pub(crate) pending_notifications: HashSet<EntityId>,
pending_effects: VecDeque<Effect>,
@@ -175,6 +180,7 @@ pub struct AppContext {
pub(crate) event_handlers: SubscriberSet<EntityId, EventHandler>,
pub(crate) release_handlers: SubscriberSet<EntityId, ReleaseHandler>,
pub(crate) layout_id_buffer: Vec<LayoutId>, // We recycle this memory across layout requests.
pub(crate) propagate_event: bool,
}
impl AppContext {
@@ -508,6 +514,21 @@ impl AppContext {
self.push_effect(Effect::Refresh);
}
pub fn on_action<A: Action>(
&mut self,
listener: impl Fn(&A, &mut Self) + Send + Sync + 'static,
) {
self.global_action_listeners
.entry(TypeId::of::<A>())
.or_default()
.push(Box::new(move |action, phase, cx| {
if phase == DispatchPhase::Bubble {
let action = action.as_any().downcast_ref().unwrap();
listener(action, cx)
}
}));
}
pub fn register_action_type<A: Action>(&mut self) {
self.action_builders.insert(A::qualified_name(), A::build);
}
@@ -523,6 +544,10 @@ impl AppContext {
.ok_or_else(|| anyhow!("no action type registered for {}", name))?;
(build)(params)
}
pub fn stop_propagation(&mut self) {
self.propagate_event = false;
}
}
impl Context for AppContext {
@@ -610,6 +635,18 @@ impl MainThread<AppContext> {
self.platform().activate(ignoring_other_apps);
}
pub fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Result<()> {
self.platform().write_credentials(url, username, password)
}
pub fn read_credentials(&self, url: &str) -> Result<Option<(String, Vec<u8>)>> {
self.platform().read_credentials(url)
}
pub fn delete_credentials(&self, url: &str) -> Result<()> {
self.platform().delete_credentials(url)
}
pub fn open_window<S: 'static + Send + Sync>(
&mut self,
options: crate::WindowOptions,
+30 -3
View File
@@ -1,8 +1,9 @@
use crate::{
AnyWindowHandle, AppContext, Context, Handle, ModelContext, Result, Task, ViewContext,
WindowContext,
AnyWindowHandle, AppContext, Context, Executor, Handle, MainThread, ModelContext, Result, Task,
ViewContext, WindowContext,
};
use anyhow::anyhow;
use derive_more::{Deref, DerefMut};
use parking_lot::Mutex;
use std::{future::Future, sync::Weak};
@@ -75,6 +76,15 @@ impl Context for AsyncAppContext {
}
impl AsyncAppContext {
pub fn executor(&self) -> Result<Executor> {
let app = self
.0
.upgrade()
.ok_or_else(|| anyhow!("app was released"))?;
let lock = app.lock(); // Need this to compile
Ok(lock.executor().clone())
}
pub fn read_window<R>(
&self,
handle: AnyWindowHandle,
@@ -116,10 +126,27 @@ impl AsyncAppContext {
let app_context = app.lock();
Ok(app_context.spawn(f))
}
pub fn run_on_main<R>(
&self,
f: impl FnOnce(&mut MainThread<AppContext>) -> R + Send + 'static,
) -> Result<Task<R>>
where
R: Send + 'static,
{
let app = self
.0
.upgrade()
.ok_or_else(|| anyhow!("app was released"))?;
let mut app_context = app.lock();
Ok(app_context.run_on_main(f))
}
}
#[derive(Clone)]
#[derive(Clone, Deref, DerefMut)]
pub struct AsyncWindowContext {
#[deref]
#[deref_mut]
app: AsyncAppContext,
window: AnyWindowHandle,
}
+120 -35
View File
@@ -4,7 +4,7 @@ use derive_more::{Deref, DerefMut};
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
use slotmap::{SecondaryMap, SlotMap};
use std::{
any::Any,
any::{Any, TypeId},
marker::PhantomData,
mem,
sync::{
@@ -70,9 +70,12 @@ impl EntityMap {
pub fn weak_handle<T: 'static + Send + Sync>(&self, id: EntityId) -> WeakHandle<T> {
WeakHandle {
id,
any_handle: AnyWeakHandle {
id,
entity_type: TypeId::of::<T>(),
entity_map: Arc::downgrade(&self.0),
},
entity_type: PhantomData,
entity_map: Arc::downgrade(&self.0),
}
}
@@ -112,44 +115,45 @@ impl<T> Drop for Lease<T> {
#[derive(Deref, DerefMut)]
pub struct Slot<T: Send + Sync + 'static>(Handle<T>);
pub struct Handle<T: Send + Sync> {
pub struct AnyHandle {
pub(crate) id: EntityId,
entity_type: PhantomData<T>,
entity_type: TypeId,
entity_map: Weak<RwLock<EntityMapState>>,
}
impl<T: 'static + Send + Sync> Handle<T> {
fn new(id: EntityId, entity_map: Weak<RwLock<EntityMapState>>) -> Self {
impl AnyHandle {
fn new(id: EntityId, entity_type: TypeId, entity_map: Weak<RwLock<EntityMapState>>) -> Self {
Self {
id,
entity_type: PhantomData,
entity_type,
entity_map,
}
}
pub fn downgrade(&self) -> WeakHandle<T> {
WeakHandle {
pub fn downgrade(&self) -> AnyWeakHandle {
AnyWeakHandle {
id: self.id,
entity_type: self.entity_type,
entity_map: self.entity_map.clone(),
}
}
/// Update the entity referenced by this handle with the given function.
///
/// The update function receives a context appropriate for its environment.
/// When updating in an `AppContext`, it receives a `ModelContext`.
/// When updating an a `WindowContext`, it receives a `ViewContext`.
pub fn update<C: Context, R>(
&self,
cx: &mut C,
update: impl FnOnce(&mut T, &mut C::EntityContext<'_, '_, T>) -> R,
) -> C::Result<R> {
cx.update_entity(self, update)
pub fn downcast<T>(&self) -> Option<Handle<T>>
where
T: 'static + Send + Sync,
{
if TypeId::of::<T>() == self.entity_type {
Some(Handle {
any_handle: self.clone(),
entity_type: PhantomData,
})
} else {
None
}
}
}
impl<T: Send + Sync> Clone for Handle<T> {
impl Clone for AnyHandle {
fn clone(&self) -> Self {
if let Some(entity_map) = self.entity_map.upgrade() {
let entity_map = entity_map.read();
@@ -163,13 +167,13 @@ impl<T: Send + Sync> Clone for Handle<T> {
Self {
id: self.id,
entity_type: PhantomData,
entity_type: self.entity_type,
entity_map: self.entity_map.clone(),
}
}
}
impl<T: Send + Sync> Drop for Handle<T> {
impl Drop for AnyHandle {
fn drop(&mut self) {
if let Some(entity_map) = self.entity_map.upgrade() {
let entity_map = entity_map.upgradable_read();
@@ -193,36 +197,117 @@ impl<T: Send + Sync> Drop for Handle<T> {
}
}
pub struct WeakHandle<T> {
pub(crate) id: EntityId,
entity_type: PhantomData<T>,
entity_map: Weak<RwLock<EntityMapState>>,
impl<T> From<Handle<T>> for AnyHandle
where
T: 'static + Send + Sync,
{
fn from(handle: Handle<T>) -> Self {
handle.any_handle
}
}
impl<T: 'static + Send + Sync> Clone for WeakHandle<T> {
#[derive(Deref, DerefMut)]
pub struct Handle<T: Send + Sync> {
#[deref]
#[deref_mut]
any_handle: AnyHandle,
entity_type: PhantomData<T>,
}
impl<T: 'static + Send + Sync> Handle<T> {
fn new(id: EntityId, entity_map: Weak<RwLock<EntityMapState>>) -> Self {
Self {
any_handle: AnyHandle::new(id, TypeId::of::<T>(), entity_map),
entity_type: PhantomData,
}
}
pub fn downgrade(&self) -> WeakHandle<T> {
WeakHandle {
any_handle: self.any_handle.downgrade(),
entity_type: self.entity_type,
}
}
/// Update the entity referenced by this handle with the given function.
///
/// The update function receives a context appropriate for its environment.
/// When updating in an `AppContext`, it receives a `ModelContext`.
/// When updating an a `WindowContext`, it receives a `ViewContext`.
pub fn update<C: Context, R>(
&self,
cx: &mut C,
update: impl FnOnce(&mut T, &mut C::EntityContext<'_, '_, T>) -> R,
) -> C::Result<R> {
cx.update_entity(self, update)
}
}
impl<T: Send + Sync> Clone for Handle<T> {
fn clone(&self) -> Self {
Self {
id: self.id,
any_handle: self.any_handle.clone(),
entity_type: self.entity_type,
entity_map: self.entity_map.clone(),
}
}
}
impl<T: Send + Sync + 'static> WeakHandle<T> {
pub fn upgrade(&self, _: &impl Context) -> Option<Handle<T>> {
#[derive(Clone)]
pub struct AnyWeakHandle {
pub(crate) id: EntityId,
entity_type: TypeId,
entity_map: Weak<RwLock<EntityMapState>>,
}
impl AnyWeakHandle {
pub fn upgrade(&self) -> Option<AnyHandle> {
let entity_map = &self.entity_map.upgrade()?;
entity_map
.read()
.ref_counts
.get(self.id)?
.fetch_add(1, SeqCst);
Some(Handle {
Some(AnyHandle {
id: self.id,
entity_type: self.entity_type,
entity_map: self.entity_map.clone(),
})
}
}
impl<T> From<WeakHandle<T>> for AnyWeakHandle
where
T: 'static + Send + Sync,
{
fn from(handle: WeakHandle<T>) -> Self {
handle.any_handle
}
}
#[derive(Deref, DerefMut)]
pub struct WeakHandle<T> {
#[deref]
#[deref_mut]
any_handle: AnyWeakHandle,
entity_type: PhantomData<T>,
}
impl<T: 'static + Send + Sync> Clone for WeakHandle<T> {
fn clone(&self) -> Self {
Self {
any_handle: self.any_handle.clone(),
entity_type: self.entity_type,
}
}
}
impl<T: Send + Sync + 'static> WeakHandle<T> {
pub fn upgrade(&self) -> Option<Handle<T>> {
Some(Handle {
any_handle: self.any_handle.upgrade()?,
entity_type: self.entity_type,
})
}
/// Update the entity referenced by this handle with the given function if
/// the referenced entity still exists. Returns an error if the entity has
@@ -240,7 +325,7 @@ impl<T: Send + Sync + 'static> WeakHandle<T> {
Result<C::Result<R>>: crate::Flatten<R>,
{
crate::Flatten::flatten(
self.upgrade(cx)
self.upgrade()
.ok_or_else(|| anyhow!("entity release"))
.map(|this| cx.update_entity(&this, update)),
)
+4 -4
View File
@@ -1,5 +1,5 @@
use crate::{
AppContext, Context, Effect, EntityId, EventEmitter, Handle, Reference, Subscription,
AppContext, Context, Effect, EntityId, EventEmitter, Executor, Handle, Reference, Subscription,
WeakHandle,
};
use std::marker::PhantomData;
@@ -51,7 +51,7 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
self.app.observers.insert(
handle.id,
Box::new(move |cx| {
if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(cx)) {
if let Some((this, handle)) = this.upgrade().zip(handle.upgrade()) {
this.update(cx, |this, cx| on_notify(this, handle, cx));
true
} else {
@@ -75,7 +75,7 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
handle.id,
Box::new(move |event, cx| {
let event = event.downcast_ref().expect("invalid event type");
if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(cx)) {
if let Some((this, handle)) = this.upgrade().zip(handle.upgrade()) {
this.update(cx, |this, cx| on_event(this, handle, event, cx));
true
} else {
@@ -108,7 +108,7 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
handle.id,
Box::new(move |entity, cx| {
let entity = entity.downcast_mut().expect("invalid entity type");
if let Some(this) = this.upgrade(cx) {
if let Some(this) = this.upgrade() {
this.update(cx, |this, cx| on_release(this, entity, cx));
}
}),
+6
View File
@@ -8,6 +8,7 @@ use std::{
pin::Pin,
sync::Arc,
task::{Context, Poll},
time::Duration,
};
use util::TryFutureExt;
@@ -151,6 +152,11 @@ impl Executor {
}
}
pub fn timer(&self, duration: Duration) -> smol::Timer {
// todo!("integrate with deterministic dispatcher")
smol::Timer::after(duration)
}
pub fn is_main_thread(&self) -> bool {
self.dispatcher.is_main_thread()
}
+73 -36
View File
@@ -1,13 +1,13 @@
use crate::{
px, size, Action, AnyBox, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
BorrowAppContext, Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext,
DisplayId, Edges, Effect, Element, EntityId, EventEmitter, FocusEvent, FontId, GlobalElementId,
GlyphId, Handle, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher,
Keystroke, LayoutId, MainThread, MainThreadOnly, MonochromeSprite, MouseMoveEvent, Path,
Pixels, Platform, PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference,
RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow,
SharedString, Size, Style, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle,
WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
DisplayId, Edges, Effect, Element, EntityId, EventEmitter, Executor, FocusEvent, FontId,
GlobalElementId, GlyphId, Handle, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch,
KeyMatcher, Keystroke, LayoutId, MainThread, MainThreadOnly, MonochromeSprite, MouseMoveEvent,
Path, Pixels, Platform, PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad,
Reference, RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder,
Shadow, SharedString, Size, Style, Subscription, TaffyLayoutEngine, Task, Underline,
UnderlineStyle, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
};
use anyhow::Result;
use collections::HashMap;
@@ -167,7 +167,6 @@ pub struct Window {
focus_parents_by_child: HashMap<FocusId, FocusId>,
pub(crate) focus_listeners: Vec<AnyFocusListener>,
pub(crate) focus_handles: Arc<RwLock<SlotMap<FocusId, AtomicUsize>>>,
propagate: bool,
default_prevented: bool,
mouse_position: Point<Pixels>,
scale_factor: f32,
@@ -243,7 +242,6 @@ impl Window {
focus_parents_by_child: HashMap::default(),
focus_listeners: Vec::new(),
focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
propagate: true,
default_prevented: true,
mouse_position,
scale_factor,
@@ -302,6 +300,10 @@ impl<'a, 'w> WindowContext<'a, 'w> {
}
}
pub fn window_handle(&self) -> AnyWindowHandle {
self.window.handle
}
pub fn notify(&mut self) {
self.window.dirty = true;
}
@@ -477,10 +479,6 @@ impl<'a, 'w> WindowContext<'a, 'w> {
.to_pixels(text_style.font_size.into(), rem_size)
}
pub fn stop_propagation(&mut self) {
self.window.propagate = false;
}
pub fn prevent_default(&mut self) {
self.window.default_prevented = true;
}
@@ -878,7 +876,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
}
// Handlers may set this to false by calling `stop_propagation`
self.window.propagate = true;
self.app.propagate_event = true;
self.window.default_prevented = false;
if let Some(mut handlers) = self
@@ -893,16 +891,16 @@ impl<'a, 'w> WindowContext<'a, 'w> {
// special purposes, such as detecting events outside of a given Bounds.
for (_, handler) in &handlers {
handler(any_mouse_event, DispatchPhase::Capture, self);
if !self.window.propagate {
if !self.app.propagate_event {
break;
}
}
// Bubble phase, where most normal handlers do their work.
if self.window.propagate {
if self.app.propagate_event {
for (_, handler) in handlers.iter().rev() {
handler(any_mouse_event, DispatchPhase::Bubble, self);
if !self.window.propagate {
if !self.app.propagate_event {
break;
}
}
@@ -940,7 +938,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
) {
self.dispatch_action(action, &key_dispatch_stack[..ix]);
}
if !self.window.propagate {
if !self.app.propagate_event {
break;
}
}
@@ -951,7 +949,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
}
}
if self.window.propagate {
if self.app.propagate_event {
for (ix, frame) in key_dispatch_stack.iter().enumerate().rev() {
match frame {
KeyDispatchStackFrame::Listener {
@@ -968,7 +966,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
self.dispatch_action(action, &key_dispatch_stack[..ix]);
}
if !self.window.propagate {
if !self.app.propagate_event {
break;
}
}
@@ -1015,22 +1013,41 @@ impl<'a, 'w> WindowContext<'a, 'w> {
dispatch_stack: &[KeyDispatchStackFrame],
) {
let action_type = action.as_any().type_id();
for stack_frame in dispatch_stack {
if let KeyDispatchStackFrame::Listener {
event_type,
listener,
} = stack_frame
{
if action_type == *event_type {
listener(action.as_any(), &[], DispatchPhase::Capture, self);
if !self.window.propagate {
break;
if let Some(mut global_listeners) = self.app.global_action_listeners.remove(&action_type) {
for listener in &global_listeners {
listener(action.as_ref(), DispatchPhase::Capture, self);
if !self.app.propagate_event {
break;
}
}
global_listeners.extend(
self.global_action_listeners
.remove(&action_type)
.unwrap_or_default(),
);
self.global_action_listeners
.insert(action_type, global_listeners);
}
if self.app.propagate_event {
for stack_frame in dispatch_stack {
if let KeyDispatchStackFrame::Listener {
event_type,
listener,
} = stack_frame
{
if action_type == *event_type {
listener(action.as_any(), &[], DispatchPhase::Capture, self);
if !self.app.propagate_event {
break;
}
}
}
}
}
if self.window.propagate {
if self.app.propagate_event {
for stack_frame in dispatch_stack.iter().rev() {
if let KeyDispatchStackFrame::Listener {
event_type,
@@ -1039,13 +1056,33 @@ impl<'a, 'w> WindowContext<'a, 'w> {
{
if action_type == *event_type {
listener(action.as_any(), &[], DispatchPhase::Bubble, self);
if !self.window.propagate {
if !self.app.propagate_event {
break;
}
}
}
}
}
if self.app.propagate_event {
if let Some(mut global_listeners) =
self.app.global_action_listeners.remove(&action_type)
{
for listener in global_listeners.iter().rev() {
listener(action.as_ref(), DispatchPhase::Bubble, self);
if !self.app.propagate_event {
break;
}
}
global_listeners.extend(
self.global_action_listeners
.remove(&action_type)
.unwrap_or_default(),
);
self.global_action_listeners
.insert(action_type, global_listeners);
}
}
}
}
@@ -1313,7 +1350,7 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
handle.id,
Box::new(move |cx| {
cx.update_window(window_handle.id, |cx| {
if let Some(handle) = handle.upgrade(cx) {
if let Some(handle) = handle.upgrade() {
this.update(cx, |this, cx| on_notify(this, handle, cx))
.is_ok()
} else {
@@ -1340,7 +1377,7 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
handle.id,
Box::new(move |event, cx| {
cx.update_window(window_handle.id, |cx| {
if let Some(handle) = handle.upgrade(cx) {
if let Some(handle) = handle.upgrade() {
let event = event.downcast_ref().expect("invalid event type");
this.update(cx, |this, cx| on_event(this, handle, event, cx))
.is_ok()
@@ -1504,7 +1541,7 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
let cx = unsafe { mem::transmute::<&mut Self, &mut MainThread<Self>>(self) };
Task::ready(Ok(f(view, cx)))
} else {
let handle = self.handle().upgrade(self).unwrap();
let handle = self.handle().upgrade().unwrap();
self.window_cx.run_on_main(move |cx| handle.update(cx, f))
}
}
@@ -1528,7 +1565,7 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
&mut self,
handler: impl Fn(&mut V, &Event, DispatchPhase, &mut ViewContext<V>) + Send + Sync + 'static,
) {
let handle = self.handle().upgrade(self).unwrap();
let handle = self.handle().upgrade().unwrap();
self.window_cx.on_mouse_event(move |event, phase, cx| {
handle.update(cx, |view, cx| {
handler(view, event, phase, cx);