Checkpoint
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
343c426307
commit
e4e9da7673
12 changed files with 280 additions and 210 deletions
|
@ -1,21 +1,19 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
current_platform, Context, LayoutId, Platform, Reference, RootView, TextSystem, Window,
|
current_platform, Context, LayoutId, MainThreadOnly, Platform, Reference, RootView, TextSystem,
|
||||||
WindowContext, WindowHandle, WindowId,
|
Window, WindowContext, WindowHandle, WindowId,
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use parking_lot::RwLock;
|
use futures::Future;
|
||||||
|
use parking_lot::Mutex;
|
||||||
use slotmap::SlotMap;
|
use slotmap::SlotMap;
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
mem,
|
|
||||||
sync::{Arc, Weak},
|
sync::{Arc, Weak},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct App(Arc<RwLock<AppContext<()>>>);
|
pub struct App(Arc<Mutex<AppContext>>);
|
||||||
|
|
||||||
pub struct MainThread;
|
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn production() -> Self {
|
pub fn production() -> Self {
|
||||||
|
@ -28,14 +26,14 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(platform: Arc<dyn Platform>) -> Self {
|
fn new(platform: Arc<dyn Platform>) -> Self {
|
||||||
|
let dispatcher = platform.dispatcher();
|
||||||
let text_system = Arc::new(TextSystem::new(platform.text_system()));
|
let text_system = Arc::new(TextSystem::new(platform.text_system()));
|
||||||
let mut entities = SlotMap::with_key();
|
let mut entities = SlotMap::with_key();
|
||||||
let unit_entity_id = entities.insert(Some(Box::new(()) as Box<dyn Any>));
|
let unit_entity_id = entities.insert(Some(Box::new(()) as Box<dyn Any + Send>));
|
||||||
Self(Arc::new_cyclic(|this| {
|
Self(Arc::new_cyclic(|this| {
|
||||||
RwLock::new(AppContext {
|
Mutex::new(AppContext {
|
||||||
this: this.clone(),
|
this: this.clone(),
|
||||||
thread: PhantomData,
|
platform: MainThreadOnly::new(platform, dispatcher),
|
||||||
platform,
|
|
||||||
text_system,
|
text_system,
|
||||||
unit_entity_id,
|
unit_entity_id,
|
||||||
entities,
|
entities,
|
||||||
|
@ -47,83 +45,65 @@ impl App {
|
||||||
|
|
||||||
pub fn run<F>(self, on_finish_launching: F)
|
pub fn run<F>(self, on_finish_launching: F)
|
||||||
where
|
where
|
||||||
F: 'static + FnOnce(&mut AppContext<MainThread>),
|
F: 'static + FnOnce(&mut AppContext),
|
||||||
{
|
{
|
||||||
let platform = self.0.read().platform.clone();
|
let platform = self.0.lock().platform.clone();
|
||||||
platform.run(Box::new(move || {
|
platform.borrow_on_main_thread().run(Box::new(move || {
|
||||||
let mut cx = self.0.write();
|
let cx = &mut *self.0.lock();
|
||||||
let cx: &mut AppContext<()> = &mut cx;
|
|
||||||
let cx: &mut AppContext<MainThread> = unsafe { mem::transmute(cx) };
|
|
||||||
on_finish_launching(cx);
|
on_finish_launching(cx);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AppContext<Thread = ()> {
|
pub struct AppContext {
|
||||||
this: Weak<RwLock<AppContext>>,
|
this: Weak<Mutex<AppContext>>,
|
||||||
thread: PhantomData<Thread>,
|
platform: MainThreadOnly<dyn Platform>,
|
||||||
platform: Arc<dyn Platform>,
|
|
||||||
text_system: Arc<TextSystem>,
|
text_system: Arc<TextSystem>,
|
||||||
pub(crate) unit_entity_id: EntityId,
|
pub(crate) unit_entity_id: EntityId,
|
||||||
pub(crate) entities: SlotMap<EntityId, Option<Box<dyn Any>>>,
|
pub(crate) entities: SlotMap<EntityId, Option<Box<dyn Any + Send>>>,
|
||||||
pub(crate) windows: SlotMap<WindowId, Option<Window>>,
|
pub(crate) windows: SlotMap<WindowId, Option<Window>>,
|
||||||
// We recycle this memory across layout requests.
|
// We recycle this memory across layout requests.
|
||||||
pub(crate) layout_id_buffer: Vec<LayoutId>,
|
pub(crate) layout_id_buffer: Vec<LayoutId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppContext<()> {
|
impl AppContext {
|
||||||
// pub fn run_on_main<F: 'static, T: 'static>(
|
|
||||||
// &self,
|
|
||||||
// to_call: F,
|
|
||||||
// ) -> Result<T, impl Future<Output = T>>
|
|
||||||
// where
|
|
||||||
// F: Fn(&mut AppContext<MainThread>) -> T + Send + Sync,
|
|
||||||
// {
|
|
||||||
// todo!();
|
|
||||||
|
|
||||||
// // let dispatcher = self.platform().dispatcher();
|
|
||||||
// // if dispatcher.is_main_thread() {
|
|
||||||
// // } else {
|
|
||||||
// // let future = async move {
|
|
||||||
// // // let cx = unsafe { };
|
|
||||||
// // };
|
|
||||||
// // let schedule = move |runnable: Runnable| dispatcher.run_on_main_thread(runnable);
|
|
||||||
// // // let (runnable, task) = async_task::spawn_local();
|
|
||||||
// // // runnable.schedule();
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // let (runnable, task) = async_task::spawn_local(future, schedule);
|
|
||||||
// // runnable.schedule();
|
|
||||||
// // task
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Thread> AppContext<Thread> {
|
|
||||||
pub fn text_system(&self) -> &Arc<TextSystem> {
|
pub fn text_system(&self) -> &Arc<TextSystem> {
|
||||||
&self.text_system
|
&self.text_system
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_window<S: 'static>(
|
pub fn with_platform<R: Send + 'static>(
|
||||||
|
&mut self,
|
||||||
|
f: impl FnOnce(&dyn Platform, &mut Self) -> R + Send + 'static,
|
||||||
|
) -> impl Future<Output = R> {
|
||||||
|
let this = self.this.upgrade().unwrap();
|
||||||
|
self.platform.read(move |platform| {
|
||||||
|
let cx = &mut *this.lock();
|
||||||
|
f(platform, cx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_window<S: 'static + Send>(
|
||||||
&mut self,
|
&mut self,
|
||||||
options: crate::WindowOptions,
|
options: crate::WindowOptions,
|
||||||
build_root_view: impl FnOnce(&mut WindowContext<Thread>) -> RootView<S>,
|
build_root_view: impl FnOnce(&mut WindowContext) -> RootView<S> + Send + 'static,
|
||||||
) -> WindowHandle<S> {
|
) -> impl Future<Output = WindowHandle<S>> {
|
||||||
let id = self.windows.insert(None);
|
self.with_platform(move |platform, cx| {
|
||||||
|
let id = cx.windows.insert(None);
|
||||||
let handle = WindowHandle::new(id);
|
let handle = WindowHandle::new(id);
|
||||||
let platform_window = self.platform.open_window(handle.into(), options);
|
|
||||||
|
|
||||||
let mut window = Window::new(id, platform_window);
|
let mut window = Window::new(handle.into(), options, platform);
|
||||||
let root_view = build_root_view(&mut WindowContext::mutable(self, &mut window));
|
let root_view = build_root_view(&mut WindowContext::mutable(cx, &mut window));
|
||||||
window.root_view.replace(Box::new(root_view));
|
window.root_view.replace(Box::new(root_view));
|
||||||
|
|
||||||
self.windows.get_mut(id).unwrap().replace(window);
|
cx.windows.get_mut(id).unwrap().replace(window);
|
||||||
handle
|
handle
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn update_window<R>(
|
pub(crate) fn update_window<R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
window_id: WindowId,
|
window_id: WindowId,
|
||||||
update: impl FnOnce(&mut WindowContext<Thread>) -> R,
|
update: impl FnOnce(&mut WindowContext) -> R,
|
||||||
) -> Result<R> {
|
) -> Result<R> {
|
||||||
let mut window = self
|
let mut window = self
|
||||||
.windows
|
.windows
|
||||||
|
@ -143,16 +123,10 @@ impl<Thread> AppContext<Thread> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppContext<MainThread> {
|
impl Context for AppContext {
|
||||||
pub fn platform(&self) -> &dyn Platform {
|
type EntityContext<'a, 'w, T: Send + 'static> = ModelContext<'a, T>;
|
||||||
self.platform.as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Thread: 'static> Context for AppContext<Thread> {
|
fn entity<T: Send + 'static>(
|
||||||
type EntityContext<'a, 'w, T: 'static> = ModelContext<'a, Thread, T>;
|
|
||||||
|
|
||||||
fn entity<T: 'static>(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
|
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
|
||||||
) -> Handle<T> {
|
) -> Handle<T> {
|
||||||
|
@ -163,7 +137,7 @@ impl<Thread: 'static> Context for AppContext<Thread> {
|
||||||
Handle::new(id)
|
Handle::new(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_entity<T: 'static, R>(
|
fn update_entity<T: Send + 'static, R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
handle: &Handle<T>,
|
handle: &Handle<T>,
|
||||||
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
|
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
|
||||||
|
@ -183,14 +157,14 @@ impl<Thread: 'static> Context for AppContext<Thread> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ModelContext<'a, Thread: 'static, T> {
|
pub struct ModelContext<'a, T> {
|
||||||
app: Reference<'a, AppContext<Thread>>,
|
app: Reference<'a, AppContext>,
|
||||||
entity_type: PhantomData<T>,
|
entity_type: PhantomData<T>,
|
||||||
entity_id: EntityId,
|
entity_id: EntityId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Thread, T: 'static> ModelContext<'a, Thread, T> {
|
impl<'a, T: 'static> ModelContext<'a, T> {
|
||||||
pub(crate) fn mutable(app: &'a mut AppContext<Thread>, entity_id: EntityId) -> Self {
|
pub(crate) fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self {
|
||||||
Self {
|
Self {
|
||||||
app: Reference::Mutable(app),
|
app: Reference::Mutable(app),
|
||||||
entity_type: PhantomData,
|
entity_type: PhantomData,
|
||||||
|
@ -198,7 +172,7 @@ impl<'a, Thread, T: 'static> ModelContext<'a, Thread, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn immutable(app: &'a AppContext<Thread>, entity_id: EntityId) -> Self {
|
fn immutable(app: &'a AppContext, entity_id: EntityId) -> Self {
|
||||||
Self {
|
Self {
|
||||||
app: Reference::Immutable(app),
|
app: Reference::Immutable(app),
|
||||||
entity_type: PhantomData,
|
entity_type: PhantomData,
|
||||||
|
@ -224,16 +198,17 @@ impl<'a, Thread, T: 'static> ModelContext<'a, Thread, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Thread, T: 'static> Context for ModelContext<'a, Thread, T> {
|
impl<'a, T: 'static> Context for ModelContext<'a, T> {
|
||||||
type EntityContext<'b, 'c, U: 'static> = ModelContext<'b, Thread, U>;
|
type EntityContext<'b, 'c, U: Send + 'static> = ModelContext<'b, U>;
|
||||||
fn entity<U: 'static>(
|
|
||||||
|
fn entity<U: Send + 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
|
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
|
||||||
) -> Handle<U> {
|
) -> Handle<U> {
|
||||||
self.app.entity(build_entity)
|
self.app.entity(build_entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_entity<U: 'static, R>(
|
fn update_entity<U: Send + 'static, R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
handle: &Handle<U>,
|
handle: &Handle<U>,
|
||||||
update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
|
update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
|
||||||
|
@ -249,7 +224,7 @@ pub struct Handle<T> {
|
||||||
|
|
||||||
slotmap::new_key_type! { pub struct EntityId; }
|
slotmap::new_key_type! { pub struct EntityId; }
|
||||||
|
|
||||||
impl<T: 'static> Handle<T> {
|
impl<T: Send + 'static> Handle<T> {
|
||||||
fn new(id: EntityId) -> Self {
|
fn new(id: EntityId) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
|
@ -279,3 +254,15 @@ impl<T> Clone for Handle<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::AppContext;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_app_context_send_sync() {
|
||||||
|
// This will not compile if `AppContext` does not implement `Send`
|
||||||
|
fn assert_send<T: Send>() {}
|
||||||
|
assert_send::<AppContext>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,8 +2,9 @@ use crate::{
|
||||||
AnyElement, Bounds, Element, Layout, LayoutId, Overflow, ParentElement, Pixels, Point,
|
AnyElement, Bounds, Element, Layout, LayoutId, Overflow, ParentElement, Pixels, Point,
|
||||||
Refineable, RefinementCascade, Result, Style, StyleHelpers, Styled, ViewContext,
|
Refineable, RefinementCascade, Result, Style, StyleHelpers, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
|
use parking_lot::Mutex;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{cell::Cell, rc::Rc};
|
use std::sync::Arc;
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
|
||||||
pub struct Div<S: 'static> {
|
pub struct Div<S: 'static> {
|
||||||
|
@ -271,26 +272,22 @@ impl<V: 'static> ParentElement<V> for Div<V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct ScrollState(Rc<Cell<Point<Pixels>>>);
|
pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
|
||||||
|
|
||||||
impl ScrollState {
|
impl ScrollState {
|
||||||
pub fn x(&self) -> Pixels {
|
pub fn x(&self) -> Pixels {
|
||||||
self.0.get().x
|
self.0.lock().x
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_x(&self, value: Pixels) {
|
pub fn set_x(&self, value: Pixels) {
|
||||||
let mut current_value = self.0.get();
|
self.0.lock().x = value;
|
||||||
current_value.x = value;
|
|
||||||
self.0.set(current_value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn y(&self) -> Pixels {
|
pub fn y(&self) -> Pixels {
|
||||||
self.0.get().y
|
self.0.lock().y
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_y(&self, value: Pixels) {
|
pub fn set_y(&self, value: Pixels) {
|
||||||
let mut current_value = self.0.get();
|
self.0.lock().y = value;
|
||||||
current_value.y = value;
|
|
||||||
self.0.set(current_value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ pub use color::*;
|
||||||
pub use element::*;
|
pub use element::*;
|
||||||
pub use elements::*;
|
pub use elements::*;
|
||||||
pub use executor::*;
|
pub use executor::*;
|
||||||
|
use futures::channel::oneshot;
|
||||||
pub use geometry::*;
|
pub use geometry::*;
|
||||||
pub use gpui3_macros::*;
|
pub use gpui3_macros::*;
|
||||||
pub use platform::*;
|
pub use platform::*;
|
||||||
|
@ -31,7 +32,11 @@ pub use serde;
|
||||||
pub use serde_json;
|
pub use serde_json;
|
||||||
pub use smallvec;
|
pub use smallvec;
|
||||||
pub use smol::Timer;
|
pub use smol::Timer;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::{
|
||||||
|
future::Future,
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
pub use style::*;
|
pub use style::*;
|
||||||
pub use style_helpers::*;
|
pub use style_helpers::*;
|
||||||
pub use styled::*;
|
pub use styled::*;
|
||||||
|
@ -43,14 +48,14 @@ pub use view::*;
|
||||||
pub use window::*;
|
pub use window::*;
|
||||||
|
|
||||||
pub trait Context {
|
pub trait Context {
|
||||||
type EntityContext<'a, 'w, T: 'static>;
|
type EntityContext<'a, 'w, T: Send + 'static>;
|
||||||
|
|
||||||
fn entity<T: 'static>(
|
fn entity<T: 'static + Send>(
|
||||||
&mut self,
|
&mut self,
|
||||||
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
|
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
|
||||||
) -> Handle<T>;
|
) -> Handle<T>;
|
||||||
|
|
||||||
fn update_entity<T: 'static, R>(
|
fn update_entity<T: 'static + Send, R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
handle: &Handle<T>,
|
handle: &Handle<T>,
|
||||||
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
|
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
|
||||||
|
@ -110,3 +115,54 @@ impl<'a, T> DerefMut for Reference<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct MainThreadOnly<T: ?Sized> {
|
||||||
|
dispatcher: Arc<dyn PlatformDispatcher>,
|
||||||
|
value: Arc<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> Clone for MainThreadOnly<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
dispatcher: self.dispatcher.clone(),
|
||||||
|
value: self.value.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allows a value to be accessed only on the main thread, allowing a non-`Send` type
|
||||||
|
/// to become `Send`.
|
||||||
|
impl<T: 'static + ?Sized> MainThreadOnly<T> {
|
||||||
|
pub(crate) fn new(value: Arc<T>, dispatcher: Arc<dyn PlatformDispatcher>) -> Self {
|
||||||
|
Self { dispatcher, value }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn borrow_on_main_thread(&self) -> &T {
|
||||||
|
assert!(self.dispatcher.is_main_thread());
|
||||||
|
&self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read<R>(
|
||||||
|
&self,
|
||||||
|
f: impl FnOnce(&T) -> R + Send + 'static,
|
||||||
|
) -> impl Future<Output = R>
|
||||||
|
where
|
||||||
|
R: Send + 'static,
|
||||||
|
{
|
||||||
|
let (tx, rx) = oneshot::channel();
|
||||||
|
if self.dispatcher.is_main_thread() {
|
||||||
|
let _ = tx.send(f(&self.value));
|
||||||
|
} else {
|
||||||
|
let this = self.clone();
|
||||||
|
let _ = crate::spawn_on_main(self.dispatcher.clone(), async move {
|
||||||
|
// Required so we move `this` instead of this.value. Only `this` is `Send`.
|
||||||
|
let this = this;
|
||||||
|
let _ = tx.send(f(&this.value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async move { rx.await.unwrap() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: ?Sized> Send for MainThreadOnly<T> {}
|
||||||
|
|
|
@ -15,6 +15,7 @@ use futures::channel::oneshot;
|
||||||
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
|
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
|
||||||
use seahash::SeaHasher;
|
use seahash::SeaHasher;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::ffi::c_void;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
|
@ -40,7 +41,7 @@ pub(crate) fn current_platform() -> Arc<dyn Platform> {
|
||||||
Arc::new(MacPlatform::new())
|
Arc::new(MacPlatform::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Platform {
|
pub trait Platform: 'static {
|
||||||
fn dispatcher(&self) -> Arc<dyn PlatformDispatcher>;
|
fn dispatcher(&self) -> Arc<dyn PlatformDispatcher>;
|
||||||
fn text_system(&self) -> Arc<dyn PlatformTextSystem>;
|
fn text_system(&self) -> Arc<dyn PlatformTextSystem>;
|
||||||
|
|
||||||
|
@ -53,7 +54,7 @@ pub trait Platform {
|
||||||
fn unhide_other_apps(&self);
|
fn unhide_other_apps(&self);
|
||||||
|
|
||||||
fn screens(&self) -> Vec<Rc<dyn PlatformScreen>>;
|
fn screens(&self) -> Vec<Rc<dyn PlatformScreen>>;
|
||||||
fn screen_by_id(&self, id: uuid::Uuid) -> Option<Rc<dyn PlatformScreen>>;
|
fn screen_by_id(&self, id: ScreenId) -> Option<Rc<dyn PlatformScreen>>;
|
||||||
fn main_window(&self) -> Option<AnyWindowHandle>;
|
fn main_window(&self) -> Option<AnyWindowHandle>;
|
||||||
fn open_window(
|
fn open_window(
|
||||||
&self,
|
&self,
|
||||||
|
@ -96,12 +97,23 @@ pub trait Platform {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PlatformScreen: Debug {
|
pub trait PlatformScreen: Debug {
|
||||||
|
fn id(&self) -> Option<ScreenId>;
|
||||||
|
fn handle(&self) -> PlatformScreenHandle;
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
fn bounds(&self) -> Bounds<Pixels>;
|
fn bounds(&self) -> Bounds<Pixels>;
|
||||||
fn content_bounds(&self) -> Bounds<Pixels>;
|
fn content_bounds(&self) -> Bounds<Pixels>;
|
||||||
fn display_uuid(&self) -> Option<Uuid>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PlatformScreenHandle(pub *mut c_void);
|
||||||
|
|
||||||
|
impl Debug for PlatformScreenHandle {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "PlatformScreenHandle({:p})", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for PlatformScreenHandle {}
|
||||||
|
|
||||||
pub trait PlatformWindow: HasRawWindowHandle + HasRawDisplayHandle {
|
pub trait PlatformWindow: HasRawWindowHandle + HasRawDisplayHandle {
|
||||||
fn bounds(&self) -> WindowBounds;
|
fn bounds(&self) -> WindowBounds;
|
||||||
fn content_size(&self) -> Size<Pixels>;
|
fn content_size(&self) -> Size<Pixels>;
|
||||||
|
@ -190,6 +202,9 @@ pub trait InputHandler {
|
||||||
fn bounds_for_range(&self, range_utf16: Range<usize>) -> Option<Bounds<f32>>;
|
fn bounds_for_range(&self, range_utf16: Range<usize>) -> Option<Bounds<f32>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
|
pub struct ScreenId(pub(crate) Uuid);
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum RasterizationOptions {
|
pub enum RasterizationOptions {
|
||||||
Alpha,
|
Alpha,
|
||||||
|
@ -205,7 +220,7 @@ pub struct WindowOptions {
|
||||||
pub show: bool,
|
pub show: bool,
|
||||||
pub kind: WindowKind,
|
pub kind: WindowKind,
|
||||||
pub is_movable: bool,
|
pub is_movable: bool,
|
||||||
pub screen: Option<Rc<dyn PlatformScreen>>,
|
pub screen: Option<PlatformScreenHandle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for WindowOptions {
|
impl Default for WindowOptions {
|
||||||
|
|
|
@ -2,7 +2,7 @@ use super::BoolExt;
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyWindowHandle, ClipboardItem, CursorStyle, Event, MacDispatcher, MacScreen, MacTextSystem,
|
AnyWindowHandle, ClipboardItem, CursorStyle, Event, MacDispatcher, MacScreen, MacTextSystem,
|
||||||
MacWindow, PathPromptOptions, Platform, PlatformScreen, PlatformTextSystem, PlatformWindow,
|
MacWindow, PathPromptOptions, Platform, PlatformScreen, PlatformTextSystem, PlatformWindow,
|
||||||
Result, SemanticVersion, WindowOptions,
|
Result, ScreenId, SemanticVersion, WindowOptions,
|
||||||
};
|
};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use block::ConcreteBlock;
|
use block::ConcreteBlock;
|
||||||
|
@ -462,7 +462,7 @@ impl Platform for MacPlatform {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn screen_by_id(&self, id: uuid::Uuid) -> Option<Rc<dyn PlatformScreen>> {
|
fn screen_by_id(&self, id: ScreenId) -> Option<Rc<dyn PlatformScreen>> {
|
||||||
MacScreen::find_by_id(id).map(|screen| Rc::new(screen) as Rc<_>)
|
MacScreen::find_by_id(id).map(|screen| Rc::new(screen) as Rc<_>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,8 +479,7 @@ impl Platform for MacPlatform {
|
||||||
handle: AnyWindowHandle,
|
handle: AnyWindowHandle,
|
||||||
options: WindowOptions,
|
options: WindowOptions,
|
||||||
) -> Box<dyn PlatformWindow> {
|
) -> Box<dyn PlatformWindow> {
|
||||||
let dispatcher = self.0.lock().dispatcher.clone();
|
Box::new(MacWindow::open(handle, options, self))
|
||||||
Box::new(MacWindow::open(handle, options, dispatcher))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_url(&self, url: &str) {
|
fn open_url(&self, url: &str) {
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
use super::ns_string;
|
use super::ns_string;
|
||||||
use crate::{platform, point, px, size, Bounds, Pixels, PlatformScreen};
|
use crate::{
|
||||||
|
platform, point, px, size, Bounds, MainThreadOnly, Pixels, PlatformScreen,
|
||||||
|
PlatformScreenHandle, ScreenId,
|
||||||
|
};
|
||||||
use cocoa::{
|
use cocoa::{
|
||||||
appkit::NSScreen,
|
appkit::NSScreen,
|
||||||
base::{id, nil},
|
base::{id, nil},
|
||||||
|
@ -10,6 +13,7 @@ use core_foundation::{
|
||||||
uuid::{CFUUIDGetUUIDBytes, CFUUIDRef},
|
uuid::{CFUUIDGetUUIDBytes, CFUUIDRef},
|
||||||
};
|
};
|
||||||
use core_graphics::display::CGDirectDisplayID;
|
use core_graphics::display::CGDirectDisplayID;
|
||||||
|
use objc::runtime::Object;
|
||||||
use std::{any::Any, ffi::c_void};
|
use std::{any::Any, ffi::c_void};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
@ -23,10 +27,18 @@ pub struct MacScreen {
|
||||||
pub(crate) native_screen: id,
|
pub(crate) native_screen: id,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for MacScreen {}
|
||||||
|
|
||||||
impl MacScreen {
|
impl MacScreen {
|
||||||
|
pub(crate) fn from_handle(handle: PlatformScreenHandle) -> Self {
|
||||||
|
Self {
|
||||||
|
native_screen: handle.0 as *mut Object,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the screen with the given UUID.
|
/// Get the screen with the given UUID.
|
||||||
pub fn find_by_id(uuid: Uuid) -> Option<Self> {
|
pub fn find_by_id(id: ScreenId) -> Option<Self> {
|
||||||
Self::all().find(|screen| platform::MacScreen::display_uuid(screen) == Some(uuid))
|
Self::all().find(|screen| screen.id() == Some(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the primary screen - the one with the menu bar, and whose bottom left
|
/// Get the primary screen - the one with the menu bar, and whose bottom left
|
||||||
|
@ -82,14 +94,8 @@ impl MacScreen {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlatformScreen for MacScreen {
|
impl PlatformScreen for MacScreen {
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn id(&self) -> Option<ScreenId> {
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn display_uuid(&self) -> Option<uuid::Uuid> {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// Screen ids are not stable. Further, the default device id is also unstable across restarts.
|
|
||||||
// CGDisplayCreateUUIDFromDisplayID is stable but not exposed in the bindings we use.
|
|
||||||
// This approach is similar to that which winit takes
|
// This approach is similar to that which winit takes
|
||||||
// https://github.com/rust-windowing/winit/blob/402cbd55f932e95dbfb4e8b5e8551c49e56ff9ac/src/platform_impl/macos/monitor.rs#L99
|
// https://github.com/rust-windowing/winit/blob/402cbd55f932e95dbfb4e8b5e8551c49e56ff9ac/src/platform_impl/macos/monitor.rs#L99
|
||||||
let device_description = self.native_screen.deviceDescription();
|
let device_description = self.native_screen.deviceDescription();
|
||||||
|
@ -114,7 +120,7 @@ impl PlatformScreen for MacScreen {
|
||||||
}
|
}
|
||||||
|
|
||||||
let bytes = CFUUIDGetUUIDBytes(cfuuid);
|
let bytes = CFUUIDGetUUIDBytes(cfuuid);
|
||||||
Some(Uuid::from_bytes([
|
Some(ScreenId(Uuid::from_bytes([
|
||||||
bytes.byte0,
|
bytes.byte0,
|
||||||
bytes.byte1,
|
bytes.byte1,
|
||||||
bytes.byte2,
|
bytes.byte2,
|
||||||
|
@ -131,10 +137,18 @@ impl PlatformScreen for MacScreen {
|
||||||
bytes.byte13,
|
bytes.byte13,
|
||||||
bytes.byte14,
|
bytes.byte14,
|
||||||
bytes.byte15,
|
bytes.byte15,
|
||||||
]))
|
])))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle(&self) -> PlatformScreenHandle {
|
||||||
|
PlatformScreenHandle(self.native_screen as *mut c_void)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn bounds(&self) -> Bounds<Pixels> {
|
fn bounds(&self) -> Bounds<Pixels> {
|
||||||
unsafe { Self::screen_bounds_from_native(self.native_screen.frame()) }
|
unsafe { Self::screen_bounds_from_native(self.native_screen.frame()) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
point, px, size, AnyWindowHandle, Bounds, Event, InputHandler, KeyDownEvent, Keystroke,
|
point, px, size, AnyWindowHandle, Bounds, Event, InputHandler, KeyDownEvent, Keystroke,
|
||||||
MacDispatcher, MacScreen, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent,
|
MacScreen, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMovedEvent,
|
||||||
MouseMovedEvent, MouseUpEvent, NSRectExt, Pixels, PlatformDispatcher, PlatformScreen,
|
MouseUpEvent, NSRectExt, Pixels, Platform, PlatformDispatcher, PlatformScreen, PlatformWindow,
|
||||||
PlatformWindow, Point, Size, Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions,
|
Point, Size, Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions,
|
||||||
WindowPromptLevel,
|
WindowPromptLevel,
|
||||||
};
|
};
|
||||||
use block::ConcreteBlock;
|
use block::ConcreteBlock;
|
||||||
|
@ -38,8 +38,8 @@ use std::{
|
||||||
ops::Range,
|
ops::Range,
|
||||||
os::raw::c_char,
|
os::raw::c_char,
|
||||||
ptr,
|
ptr,
|
||||||
rc::{Rc, Weak},
|
rc::Rc,
|
||||||
sync::Arc,
|
sync::{Arc, Weak},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -417,11 +417,7 @@ unsafe impl Send for WindowState {}
|
||||||
pub struct MacWindow(Arc<Mutex<WindowState>>);
|
pub struct MacWindow(Arc<Mutex<WindowState>>);
|
||||||
|
|
||||||
impl MacWindow {
|
impl MacWindow {
|
||||||
pub fn open(
|
pub fn open(handle: AnyWindowHandle, options: WindowOptions, platform: &dyn Platform) -> Self {
|
||||||
handle: AnyWindowHandle,
|
|
||||||
options: WindowOptions,
|
|
||||||
dispatcher: Arc<MacDispatcher>,
|
|
||||||
) -> Self {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let pool = NSAutoreleasePool::new(nil);
|
let pool = NSAutoreleasePool::new(nil);
|
||||||
|
|
||||||
|
@ -454,9 +450,7 @@ impl MacWindow {
|
||||||
NO,
|
NO,
|
||||||
options
|
options
|
||||||
.screen
|
.screen
|
||||||
.and_then(|screen| {
|
.map(|screen| MacScreen::from_handle(screen).native_screen)
|
||||||
Some(screen.as_any().downcast_ref::<MacScreen>()?.native_screen)
|
|
||||||
})
|
|
||||||
.unwrap_or(nil),
|
.unwrap_or(nil),
|
||||||
);
|
);
|
||||||
assert!(!native_window.is_null());
|
assert!(!native_window.is_null());
|
||||||
|
@ -487,7 +481,7 @@ impl MacWindow {
|
||||||
|
|
||||||
let window = Self(Arc::new(Mutex::new(WindowState {
|
let window = Self(Arc::new(Mutex::new(WindowState {
|
||||||
handle,
|
handle,
|
||||||
dispatcher,
|
dispatcher: platform.dispatcher(),
|
||||||
native_window,
|
native_window,
|
||||||
kind: options.kind,
|
kind: options.kind,
|
||||||
event_callback: None,
|
event_callback: None,
|
||||||
|
@ -610,7 +604,7 @@ impl MacWindow {
|
||||||
let app = NSApplication::sharedApplication(nil);
|
let app = NSApplication::sharedApplication(nil);
|
||||||
let main_window: id = msg_send![app, mainWindow];
|
let main_window: id = msg_send![app, mainWindow];
|
||||||
if msg_send![main_window, isKindOfClass: WINDOW_CLASS] {
|
if msg_send![main_window, isKindOfClass: WINDOW_CLASS] {
|
||||||
let handle = get_window_state(&*main_window).borrow().handle;
|
let handle = get_window_state(&*main_window).lock().handle;
|
||||||
Some(handle)
|
Some(handle)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -892,7 +886,7 @@ impl PlatformWindow for MacWindow {
|
||||||
let is_panel: BOOL = msg_send![top_most_window, isKindOfClass: PANEL_CLASS];
|
let is_panel: BOOL = msg_send![top_most_window, isKindOfClass: PANEL_CLASS];
|
||||||
let is_window: BOOL = msg_send![top_most_window, isKindOfClass: WINDOW_CLASS];
|
let is_window: BOOL = msg_send![top_most_window, isKindOfClass: WINDOW_CLASS];
|
||||||
if is_panel == YES || is_window == YES {
|
if is_panel == YES || is_window == YES {
|
||||||
let topmost_window = get_window_state(&*top_most_window).borrow().handle;
|
let topmost_window = get_window_state(&*top_most_window).lock().handle;
|
||||||
topmost_window == self_handle
|
topmost_window == self_handle
|
||||||
} else {
|
} else {
|
||||||
// Someone else's window is on top
|
// Someone else's window is on top
|
||||||
|
@ -909,9 +903,9 @@ fn get_scale_factor(native_window: id) -> f32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn get_window_state(object: &Object) -> Rc<RefCell<WindowState>> {
|
unsafe fn get_window_state(object: &Object) -> Arc<Mutex<WindowState>> {
|
||||||
let raw: *mut c_void = *object.get_ivar(WINDOW_STATE_IVAR);
|
let raw: *mut c_void = *object.get_ivar(WINDOW_STATE_IVAR);
|
||||||
let rc1 = Rc::from_raw(raw as *mut RefCell<WindowState>);
|
let rc1 = Arc::from_raw(raw as *mut Mutex<WindowState>);
|
||||||
let rc2 = rc1.clone();
|
let rc2 = rc1.clone();
|
||||||
mem::forget(rc1);
|
mem::forget(rc1);
|
||||||
rc2
|
rc2
|
||||||
|
@ -950,7 +944,7 @@ extern "C" fn handle_key_down(this: &Object, _: Sel, native_event: id) {
|
||||||
|
|
||||||
extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: bool) -> BOOL {
|
extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: bool) -> BOOL {
|
||||||
let window_state = unsafe { get_window_state(this) };
|
let window_state = unsafe { get_window_state(this) };
|
||||||
let mut window_state_borrow = window_state.as_ref().borrow_mut();
|
let mut window_state_borrow = window_state.as_ref().lock();
|
||||||
|
|
||||||
let window_height = window_state_borrow.content_size().height;
|
let window_height = window_state_borrow.content_size().height;
|
||||||
let event = unsafe { Event::from_native(native_event, Some(window_height)) };
|
let event = unsafe { Event::from_native(native_event, Some(window_height)) };
|
||||||
|
@ -990,7 +984,7 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent:
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut handled = false;
|
let mut handled = false;
|
||||||
let mut window_state_borrow = window_state.borrow_mut();
|
let mut window_state_borrow = window_state.lock();
|
||||||
let ime_text = window_state_borrow.ime_text.clone();
|
let ime_text = window_state_borrow.ime_text.clone();
|
||||||
if let Some((event, insert_text)) = window_state_borrow.pending_key_down.take() {
|
if let Some((event, insert_text)) = window_state_borrow.pending_key_down.take() {
|
||||||
let is_held = event.is_held;
|
let is_held = event.is_held;
|
||||||
|
@ -1056,7 +1050,7 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window_state.borrow_mut().event_callback = Some(callback);
|
window_state.lock().event_callback = Some(callback);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
handled = true;
|
handled = true;
|
||||||
|
@ -1070,8 +1064,8 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent:
|
||||||
|
|
||||||
extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
|
extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
|
||||||
let window_state = unsafe { get_window_state(this) };
|
let window_state = unsafe { get_window_state(this) };
|
||||||
let weak_window_state = Rc::downgrade(&window_state);
|
let weak_window_state = Arc::downgrade(&window_state);
|
||||||
let mut window_state_borrow = window_state.as_ref().borrow_mut();
|
let mut window_state_borrow = window_state.as_ref().lock();
|
||||||
let is_active = unsafe { window_state_borrow.native_window.isKeyWindow() == YES };
|
let is_active = unsafe { window_state_borrow.native_window.isKeyWindow() == YES };
|
||||||
|
|
||||||
let window_height = window_state_borrow.content_size().height;
|
let window_height = window_state_borrow.content_size().height;
|
||||||
|
@ -1172,7 +1166,7 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
|
||||||
if let Some(event) = synthesized_second_event {
|
if let Some(event) = synthesized_second_event {
|
||||||
callback(event);
|
callback(event);
|
||||||
}
|
}
|
||||||
window_state.borrow_mut().event_callback = Some(callback);
|
window_state.lock().event_callback = Some(callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1181,7 +1175,7 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
|
||||||
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=300620#c6
|
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=300620#c6
|
||||||
extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) {
|
extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) {
|
||||||
let window_state = unsafe { get_window_state(this) };
|
let window_state = unsafe { get_window_state(this) };
|
||||||
let mut window_state_borrow = window_state.as_ref().borrow_mut();
|
let mut window_state_borrow = window_state.as_ref().lock();
|
||||||
|
|
||||||
let keystroke = Keystroke {
|
let keystroke = Keystroke {
|
||||||
modifiers: Default::default(),
|
modifiers: Default::default(),
|
||||||
|
@ -1196,13 +1190,13 @@ extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) {
|
||||||
if let Some(mut callback) = window_state_borrow.event_callback.take() {
|
if let Some(mut callback) = window_state_borrow.event_callback.take() {
|
||||||
drop(window_state_borrow);
|
drop(window_state_borrow);
|
||||||
callback(event);
|
callback(event);
|
||||||
window_state.borrow_mut().event_callback = Some(callback);
|
window_state.lock().event_callback = Some(callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) {
|
extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) {
|
||||||
let window_state = unsafe { get_window_state(this) };
|
let window_state = unsafe { get_window_state(this) };
|
||||||
window_state.as_ref().borrow().move_traffic_light();
|
window_state.as_ref().lock().move_traffic_light();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) {
|
extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) {
|
||||||
|
@ -1215,27 +1209,27 @@ extern "C" fn window_will_exit_fullscreen(this: &Object, _: Sel, _: id) {
|
||||||
|
|
||||||
fn window_fullscreen_changed(this: &Object, is_fullscreen: bool) {
|
fn window_fullscreen_changed(this: &Object, is_fullscreen: bool) {
|
||||||
let window_state = unsafe { get_window_state(this) };
|
let window_state = unsafe { get_window_state(this) };
|
||||||
let mut window_state_borrow = window_state.as_ref().borrow_mut();
|
let mut window_state_borrow = window_state.as_ref().lock();
|
||||||
if let Some(mut callback) = window_state_borrow.fullscreen_callback.take() {
|
if let Some(mut callback) = window_state_borrow.fullscreen_callback.take() {
|
||||||
drop(window_state_borrow);
|
drop(window_state_borrow);
|
||||||
callback(is_fullscreen);
|
callback(is_fullscreen);
|
||||||
window_state.borrow_mut().fullscreen_callback = Some(callback);
|
window_state.lock().fullscreen_callback = Some(callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn window_did_move(this: &Object, _: Sel, _: id) {
|
extern "C" fn window_did_move(this: &Object, _: Sel, _: id) {
|
||||||
let window_state = unsafe { get_window_state(this) };
|
let window_state = unsafe { get_window_state(this) };
|
||||||
let mut window_state_borrow = window_state.as_ref().borrow_mut();
|
let mut window_state_borrow = window_state.as_ref().lock();
|
||||||
if let Some(mut callback) = window_state_borrow.moved_callback.take() {
|
if let Some(mut callback) = window_state_borrow.moved_callback.take() {
|
||||||
drop(window_state_borrow);
|
drop(window_state_borrow);
|
||||||
callback();
|
callback();
|
||||||
window_state.borrow_mut().moved_callback = Some(callback);
|
window_state.lock().moved_callback = Some(callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) {
|
extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) {
|
||||||
let window_state = unsafe { get_window_state(this) };
|
let window_state = unsafe { get_window_state(this) };
|
||||||
let window_state_borrow = window_state.borrow();
|
let window_state_borrow = window_state.lock();
|
||||||
let is_active = unsafe { window_state_borrow.native_window.isKeyWindow() == YES };
|
let is_active = unsafe { window_state_borrow.native_window.isKeyWindow() == YES };
|
||||||
|
|
||||||
// When opening a pop-up while the application isn't active, Cocoa sends a spurious
|
// When opening a pop-up while the application isn't active, Cocoa sends a spurious
|
||||||
|
@ -1259,22 +1253,22 @@ extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id)
|
||||||
let dispatcher = window_state_borrow.dispatcher.clone();
|
let dispatcher = window_state_borrow.dispatcher.clone();
|
||||||
drop(window_state_borrow);
|
drop(window_state_borrow);
|
||||||
let _ = crate::spawn_on_main_local(dispatcher, async move {
|
let _ = crate::spawn_on_main_local(dispatcher, async move {
|
||||||
let mut window_state_borrow = window_state.as_ref().borrow_mut();
|
let mut window_state_borrow = window_state.as_ref().lock();
|
||||||
if let Some(mut callback) = window_state_borrow.activate_callback.take() {
|
if let Some(mut callback) = window_state_borrow.activate_callback.take() {
|
||||||
drop(window_state_borrow);
|
drop(window_state_borrow);
|
||||||
callback(is_active);
|
callback(is_active);
|
||||||
window_state.borrow_mut().activate_callback = Some(callback);
|
window_state.lock().activate_callback = Some(callback);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn window_should_close(this: &Object, _: Sel, _: id) -> BOOL {
|
extern "C" fn window_should_close(this: &Object, _: Sel, _: id) -> BOOL {
|
||||||
let window_state = unsafe { get_window_state(this) };
|
let window_state = unsafe { get_window_state(this) };
|
||||||
let mut window_state_borrow = window_state.as_ref().borrow_mut();
|
let mut window_state_borrow = window_state.as_ref().lock();
|
||||||
if let Some(mut callback) = window_state_borrow.should_close_callback.take() {
|
if let Some(mut callback) = window_state_borrow.should_close_callback.take() {
|
||||||
drop(window_state_borrow);
|
drop(window_state_borrow);
|
||||||
let should_close = callback();
|
let should_close = callback();
|
||||||
window_state.borrow_mut().should_close_callback = Some(callback);
|
window_state.lock().should_close_callback = Some(callback);
|
||||||
should_close as BOOL
|
should_close as BOOL
|
||||||
} else {
|
} else {
|
||||||
YES
|
YES
|
||||||
|
@ -1287,8 +1281,7 @@ extern "C" fn close_window(this: &Object, _: Sel) {
|
||||||
let window_state = get_window_state(this);
|
let window_state = get_window_state(this);
|
||||||
window_state
|
window_state
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.try_borrow_mut()
|
.try_lock()
|
||||||
.ok()
|
|
||||||
.and_then(|mut window_state| window_state.close_callback.take())
|
.and_then(|mut window_state| window_state.close_callback.take())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1302,13 +1295,13 @@ extern "C" fn close_window(this: &Object, _: Sel) {
|
||||||
|
|
||||||
// extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id {
|
// extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id {
|
||||||
// let window_state = unsafe { get_window_state(this) };
|
// let window_state = unsafe { get_window_state(this) };
|
||||||
// let window_state = window_state.as_ref().borrow();
|
// let window_state = window_state.as_ref().lock();
|
||||||
// window_state.renderer.layer().as_ptr() as id
|
// window_state.renderer.layer().as_ptr() as id
|
||||||
// }
|
// }
|
||||||
|
|
||||||
extern "C" fn view_did_change_backing_properties(this: &Object, _: Sel) {
|
extern "C" fn view_did_change_backing_properties(this: &Object, _: Sel) {
|
||||||
let window_state = unsafe { get_window_state(this) };
|
let window_state = unsafe { get_window_state(this) };
|
||||||
let mut window_state_borrow = window_state.as_ref().borrow_mut();
|
let mut window_state_borrow = window_state.as_ref().lock();
|
||||||
|
|
||||||
// unsafe {
|
// unsafe {
|
||||||
// let scale_factor = window_state_borrow.scale_factor() as f64;
|
// let scale_factor = window_state_borrow.scale_factor() as f64;
|
||||||
|
@ -1331,13 +1324,13 @@ extern "C" fn view_did_change_backing_properties(this: &Object, _: Sel) {
|
||||||
if let Some(mut callback) = window_state_borrow.resize_callback.take() {
|
if let Some(mut callback) = window_state_borrow.resize_callback.take() {
|
||||||
drop(window_state_borrow);
|
drop(window_state_borrow);
|
||||||
callback();
|
callback();
|
||||||
window_state.as_ref().borrow_mut().resize_callback = Some(callback);
|
window_state.as_ref().lock().resize_callback = Some(callback);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) {
|
extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) {
|
||||||
let window_state = unsafe { get_window_state(this) };
|
let window_state = unsafe { get_window_state(this) };
|
||||||
let window_state_borrow = window_state.as_ref().borrow();
|
let window_state_borrow = window_state.as_ref().lock();
|
||||||
|
|
||||||
if window_state_borrow.content_size() == size.into() {
|
if window_state_borrow.content_size() == size.into() {
|
||||||
return;
|
return;
|
||||||
|
@ -1361,18 +1354,18 @@ extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
drop(window_state_borrow);
|
drop(window_state_borrow);
|
||||||
let mut window_state_borrow = window_state.borrow_mut();
|
let mut window_state_borrow = window_state.lock();
|
||||||
if let Some(mut callback) = window_state_borrow.resize_callback.take() {
|
if let Some(mut callback) = window_state_borrow.resize_callback.take() {
|
||||||
drop(window_state_borrow);
|
drop(window_state_borrow);
|
||||||
callback();
|
callback();
|
||||||
window_state.borrow_mut().resize_callback = Some(callback);
|
window_state.lock().resize_callback = Some(callback);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn display_layer(_this: &Object, _: Sel, _: id) {
|
extern "C" fn display_layer(_this: &Object, _: Sel, _: id) {
|
||||||
// unsafe {
|
// unsafe {
|
||||||
// let window_state = get_window_state(this);
|
// let window_state = get_window_state(this);
|
||||||
// let mut window_state = window_state.as_ref().borrow_mut();
|
// let mut window_state = window_state.as_ref().lock();
|
||||||
// if let Some(scene) = window_state.scene_to_render.take() {
|
// if let Some(scene) = window_state.scene_to_render.take() {
|
||||||
// window_state.renderer.render(&scene);
|
// window_state.renderer.render(&scene);
|
||||||
// };
|
// };
|
||||||
|
@ -1408,7 +1401,7 @@ extern "C" fn first_rect_for_character_range(
|
||||||
_: id,
|
_: id,
|
||||||
) -> NSRect {
|
) -> NSRect {
|
||||||
let frame = unsafe {
|
let frame = unsafe {
|
||||||
let window = get_window_state(this).borrow().native_window;
|
let window = get_window_state(this).lock().native_window;
|
||||||
NSView::frame(window)
|
NSView::frame(window)
|
||||||
};
|
};
|
||||||
with_input_handler(this, |input_handler| {
|
with_input_handler(this, |input_handler| {
|
||||||
|
@ -1432,7 +1425,7 @@ extern "C" fn first_rect_for_character_range(
|
||||||
extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NSRange) {
|
extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NSRange) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let window_state = get_window_state(this);
|
let window_state = get_window_state(this);
|
||||||
let mut window_state_borrow = window_state.borrow_mut();
|
let mut window_state_borrow = window_state.lock();
|
||||||
let pending_key_down = window_state_borrow.pending_key_down.take();
|
let pending_key_down = window_state_borrow.pending_key_down.take();
|
||||||
drop(window_state_borrow);
|
drop(window_state_borrow);
|
||||||
|
|
||||||
|
@ -1448,8 +1441,8 @@ extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NS
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let replacement_range = replacement_range.to_range();
|
let replacement_range = replacement_range.to_range();
|
||||||
|
|
||||||
window_state.borrow_mut().ime_text = Some(text.to_string());
|
window_state.lock().ime_text = Some(text.to_string());
|
||||||
window_state.borrow_mut().ime_state = ImeState::Acted;
|
window_state.lock().ime_state = ImeState::Acted;
|
||||||
|
|
||||||
let is_composing =
|
let is_composing =
|
||||||
with_input_handler(this, |input_handler| input_handler.marked_text_range())
|
with_input_handler(this, |input_handler| input_handler.marked_text_range())
|
||||||
|
@ -1466,7 +1459,7 @@ extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NS
|
||||||
replacement_range,
|
replacement_range,
|
||||||
text: text.to_string(),
|
text: text.to_string(),
|
||||||
});
|
});
|
||||||
window_state.borrow_mut().pending_key_down = Some(pending_key_down);
|
window_state.lock().pending_key_down = Some(pending_key_down);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1480,7 +1473,7 @@ extern "C" fn set_marked_text(
|
||||||
) {
|
) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let window_state = get_window_state(this);
|
let window_state = get_window_state(this);
|
||||||
window_state.borrow_mut().pending_key_down.take();
|
window_state.lock().pending_key_down.take();
|
||||||
|
|
||||||
let is_attributed_string: BOOL =
|
let is_attributed_string: BOOL =
|
||||||
msg_send![text, isKindOfClass: [class!(NSAttributedString)]];
|
msg_send![text, isKindOfClass: [class!(NSAttributedString)]];
|
||||||
|
@ -1495,8 +1488,8 @@ extern "C" fn set_marked_text(
|
||||||
.to_str()
|
.to_str()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
window_state.borrow_mut().ime_state = ImeState::Acted;
|
window_state.lock().ime_state = ImeState::Acted;
|
||||||
window_state.borrow_mut().ime_text = Some(text.to_string());
|
window_state.lock().ime_text = Some(text.to_string());
|
||||||
|
|
||||||
with_input_handler(this, |input_handler| {
|
with_input_handler(this, |input_handler| {
|
||||||
input_handler.replace_and_mark_text_in_range(replacement_range, text, selected_range);
|
input_handler.replace_and_mark_text_in_range(replacement_range, text, selected_range);
|
||||||
|
@ -1507,7 +1500,7 @@ extern "C" fn set_marked_text(
|
||||||
extern "C" fn unmark_text(this: &Object, _: Sel) {
|
extern "C" fn unmark_text(this: &Object, _: Sel) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let state = get_window_state(this);
|
let state = get_window_state(this);
|
||||||
let mut borrow = state.borrow_mut();
|
let mut borrow = state.lock();
|
||||||
borrow.ime_state = ImeState::Acted;
|
borrow.ime_state = ImeState::Acted;
|
||||||
borrow.ime_text.take();
|
borrow.ime_text.take();
|
||||||
}
|
}
|
||||||
|
@ -1541,7 +1534,7 @@ extern "C" fn attributed_substring_for_proposed_range(
|
||||||
extern "C" fn do_command_by_selector(this: &Object, _: Sel, _: Sel) {
|
extern "C" fn do_command_by_selector(this: &Object, _: Sel, _: Sel) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let state = get_window_state(this);
|
let state = get_window_state(this);
|
||||||
let mut borrow = state.borrow_mut();
|
let mut borrow = state.lock();
|
||||||
borrow.ime_state = ImeState::Continue;
|
borrow.ime_state = ImeState::Continue;
|
||||||
borrow.ime_text.take();
|
borrow.ime_text.take();
|
||||||
}
|
}
|
||||||
|
@ -1550,11 +1543,11 @@ extern "C" fn do_command_by_selector(this: &Object, _: Sel, _: Sel) {
|
||||||
extern "C" fn view_did_change_effective_appearance(this: &Object, _: Sel) {
|
extern "C" fn view_did_change_effective_appearance(this: &Object, _: Sel) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let state = get_window_state(this);
|
let state = get_window_state(this);
|
||||||
let mut state_borrow = state.as_ref().borrow_mut();
|
let mut state_borrow = state.as_ref().lock();
|
||||||
if let Some(mut callback) = state_borrow.appearance_changed_callback.take() {
|
if let Some(mut callback) = state_borrow.appearance_changed_callback.take() {
|
||||||
drop(state_borrow);
|
drop(state_borrow);
|
||||||
callback();
|
callback();
|
||||||
state.borrow_mut().appearance_changed_callback = Some(callback);
|
state.lock().appearance_changed_callback = Some(callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1562,7 +1555,7 @@ extern "C" fn view_did_change_effective_appearance(this: &Object, _: Sel) {
|
||||||
extern "C" fn accepts_first_mouse(this: &Object, _: Sel, _: id) -> BOOL {
|
extern "C" fn accepts_first_mouse(this: &Object, _: Sel, _: id) -> BOOL {
|
||||||
unsafe {
|
unsafe {
|
||||||
let state = get_window_state(this);
|
let state = get_window_state(this);
|
||||||
let state_borrow = state.as_ref().borrow();
|
let state_borrow = state.as_ref().lock();
|
||||||
return if state_borrow.kind == WindowKind::PopUp {
|
return if state_borrow.kind == WindowKind::PopUp {
|
||||||
YES
|
YES
|
||||||
} else {
|
} else {
|
||||||
|
@ -1572,19 +1565,19 @@ extern "C" fn accepts_first_mouse(this: &Object, _: Sel, _: id) -> BOOL {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn synthetic_drag(
|
async fn synthetic_drag(
|
||||||
window_state: Weak<RefCell<WindowState>>,
|
window_state: Weak<Mutex<WindowState>>,
|
||||||
drag_id: usize,
|
drag_id: usize,
|
||||||
event: MouseMovedEvent,
|
event: MouseMovedEvent,
|
||||||
) {
|
) {
|
||||||
loop {
|
loop {
|
||||||
Timer::after(Duration::from_millis(16)).await;
|
Timer::after(Duration::from_millis(16)).await;
|
||||||
if let Some(window_state) = window_state.upgrade() {
|
if let Some(window_state) = window_state.upgrade() {
|
||||||
let mut window_state_borrow = window_state.borrow_mut();
|
let mut window_state_borrow = window_state.lock();
|
||||||
if window_state_borrow.synthetic_drag_counter == drag_id {
|
if window_state_borrow.synthetic_drag_counter == drag_id {
|
||||||
if let Some(mut callback) = window_state_borrow.event_callback.take() {
|
if let Some(mut callback) = window_state_borrow.event_callback.take() {
|
||||||
drop(window_state_borrow);
|
drop(window_state_borrow);
|
||||||
callback(Event::MouseMoved(event.clone()));
|
callback(Event::MouseMoved(event.clone()));
|
||||||
window_state.borrow_mut().event_callback = Some(callback);
|
window_state.lock().event_callback = Some(callback);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
@ -1598,11 +1591,11 @@ where
|
||||||
F: FnOnce(&mut dyn InputHandler) -> R,
|
F: FnOnce(&mut dyn InputHandler) -> R,
|
||||||
{
|
{
|
||||||
let window_state = unsafe { get_window_state(window) };
|
let window_state = unsafe { get_window_state(window) };
|
||||||
let mut window_state_borrow = window_state.as_ref().borrow_mut();
|
let mut window_state_borrow = window_state.as_ref().lock();
|
||||||
if let Some(mut input_handler) = window_state_borrow.input_handler.take() {
|
if let Some(mut input_handler) = window_state_borrow.input_handler.take() {
|
||||||
drop(window_state_borrow);
|
drop(window_state_borrow);
|
||||||
let result = f(input_handler.as_mut());
|
let result = f(input_handler.as_mut());
|
||||||
window_state.borrow_mut().input_handler = Some(input_handler);
|
window_state.lock().input_handler = Some(input_handler);
|
||||||
Some(result)
|
Some(result)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use super::Platform;
|
use super::Platform;
|
||||||
|
use crate::ScreenId;
|
||||||
|
|
||||||
pub struct TestPlatform;
|
pub struct TestPlatform;
|
||||||
|
|
||||||
|
@ -49,7 +50,7 @@ impl Platform for TestPlatform {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn screen_by_id(&self, _id: uuid::Uuid) -> Option<std::rc::Rc<dyn crate::PlatformScreen>> {
|
fn screen_by_id(&self, _id: ScreenId) -> Option<std::rc::Rc<dyn crate::PlatformScreen>> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -215,7 +215,7 @@ impl Boundary {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{App, AppContext, FontWeight};
|
use crate::{App, FontWeight};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_wrap_line() {
|
fn test_wrap_line() {
|
||||||
|
|
|
@ -2,11 +2,11 @@ use crate::{
|
||||||
AnyElement, Element, Handle, IntoAnyElement, Layout, LayoutId, Result, ViewContext,
|
AnyElement, Element, Handle, IntoAnyElement, Layout, LayoutId, Result, ViewContext,
|
||||||
WindowContext,
|
WindowContext,
|
||||||
};
|
};
|
||||||
use std::{any::Any, cell::RefCell, marker::PhantomData, rc::Rc};
|
use std::{any::Any, cell::RefCell, marker::PhantomData, rc::Rc, sync::Arc};
|
||||||
|
|
||||||
pub struct View<S, P> {
|
pub struct View<S, P> {
|
||||||
state: Handle<S>,
|
state: Handle<S>,
|
||||||
render: Rc<dyn Fn(&mut S, &mut ViewContext<S>) -> AnyElement<S>>,
|
render: Arc<dyn Fn(&mut S, &mut ViewContext<S>) -> AnyElement<S> + Send + Sync + 'static>,
|
||||||
parent_state_type: PhantomData<P>,
|
parent_state_type: PhantomData<P>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,16 +24,16 @@ pub type RootView<S> = View<S, ()>;
|
||||||
|
|
||||||
pub fn view<S: 'static, P: 'static, E: Element<State = S>>(
|
pub fn view<S: 'static, P: 'static, E: Element<State = S>>(
|
||||||
state: Handle<S>,
|
state: Handle<S>,
|
||||||
render: impl 'static + Fn(&mut S, &mut ViewContext<S>) -> E,
|
render: impl Fn(&mut S, &mut ViewContext<S>) -> E + Send + Sync + 'static,
|
||||||
) -> View<S, P> {
|
) -> View<S, P> {
|
||||||
View {
|
View {
|
||||||
state,
|
state,
|
||||||
render: Rc::new(move |state, cx| render(state, cx).into_any()),
|
render: Arc::new(move |state, cx| render(state, cx).into_any()),
|
||||||
parent_state_type: PhantomData,
|
parent_state_type: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static, P: 'static> View<S, P> {
|
impl<S: Send + 'static, P: 'static> View<S, P> {
|
||||||
pub fn into_any<ParentState>(self) -> AnyView<ParentState> {
|
pub fn into_any<ParentState>(self) -> AnyView<ParentState> {
|
||||||
AnyView {
|
AnyView {
|
||||||
view: Rc::new(RefCell::new(self)),
|
view: Rc::new(RefCell::new(self)),
|
||||||
|
@ -42,7 +42,7 @@ impl<S: 'static, P: 'static> View<S, P> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static, P: 'static> Element for View<S, P> {
|
impl<S: Send + 'static, P: Send + 'static> Element for View<S, P> {
|
||||||
type State = P;
|
type State = P;
|
||||||
type FrameState = AnyElement<S>;
|
type FrameState = AnyElement<S>;
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ trait ViewObject {
|
||||||
) -> Result<()>;
|
) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static, P> ViewObject for View<S, P> {
|
impl<S: Send + 'static, P> ViewObject for View<S, P> {
|
||||||
fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)> {
|
fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)> {
|
||||||
self.state.update(cx, |state, cx| {
|
self.state.update(cx, |state, cx| {
|
||||||
let mut element = (self.render)(state, cx);
|
let mut element = (self.render)(state, cx);
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use crate::{AvailableSpace, PlatformWindow, Point, Size, Style, TextStyle, TextStyleRefinement};
|
use crate::{
|
||||||
|
AvailableSpace, MainThreadOnly, Platform, PlatformWindow, Point, Size, Style, TextStyle,
|
||||||
|
TextStyleRefinement, WindowOptions,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
px, taffy::LayoutId, AppContext, Bounds, Context, EntityId, Handle, Pixels, Reference,
|
px, taffy::LayoutId, AppContext, Bounds, Context, EntityId, Handle, Pixels, Reference,
|
||||||
|
@ -10,49 +13,54 @@ use refineable::Refineable;
|
||||||
use std::{
|
use std::{
|
||||||
any::{Any, TypeId},
|
any::{Any, TypeId},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct AnyWindow {}
|
pub struct AnyWindow {}
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
id: WindowId,
|
handle: AnyWindowHandle,
|
||||||
platform_window: Box<dyn PlatformWindow>,
|
platform_window: MainThreadOnly<Box<dyn PlatformWindow>>,
|
||||||
rem_size: Pixels,
|
rem_size: Pixels,
|
||||||
layout_engine: TaffyLayoutEngine,
|
layout_engine: TaffyLayoutEngine,
|
||||||
text_style_stack: Vec<TextStyleRefinement>,
|
text_style_stack: Vec<TextStyleRefinement>,
|
||||||
pub(crate) root_view: Option<Box<dyn Any>>,
|
pub(crate) root_view: Option<Box<dyn Any + Send>>,
|
||||||
|
mouse_position: Point<Pixels>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(id: WindowId, platform_window: Box<dyn PlatformWindow>) -> Window {
|
pub fn new(handle: AnyWindowHandle, options: WindowOptions, platform: &dyn Platform) -> Window {
|
||||||
|
let platform_window = Arc::new(platform.open_window(handle, options));
|
||||||
|
let mouse_position = platform_window.mouse_position();
|
||||||
Window {
|
Window {
|
||||||
id,
|
handle,
|
||||||
platform_window,
|
platform_window: MainThreadOnly::new(platform_window, platform.dispatcher()),
|
||||||
rem_size: px(16.),
|
rem_size: px(16.),
|
||||||
layout_engine: TaffyLayoutEngine::new(),
|
layout_engine: TaffyLayoutEngine::new(),
|
||||||
text_style_stack: Vec::new(),
|
text_style_stack: Vec::new(),
|
||||||
root_view: None,
|
root_view: None,
|
||||||
|
mouse_position,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deref, DerefMut)]
|
#[derive(Deref, DerefMut)]
|
||||||
pub struct WindowContext<'a, 'b, Thread = ()> {
|
pub struct WindowContext<'a, 'b> {
|
||||||
#[deref]
|
#[deref]
|
||||||
#[deref_mut]
|
#[deref_mut]
|
||||||
app: Reference<'a, AppContext<Thread>>,
|
app: Reference<'a, AppContext>,
|
||||||
window: Reference<'b, Window>,
|
window: Reference<'b, Window>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'w, Thread> WindowContext<'a, 'w, Thread> {
|
impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
pub(crate) fn mutable(app: &'a mut AppContext<Thread>, window: &'w mut Window) -> Self {
|
pub(crate) fn mutable(app: &'a mut AppContext, window: &'w mut Window) -> Self {
|
||||||
Self {
|
Self {
|
||||||
app: Reference::Mutable(app),
|
app: Reference::Mutable(app),
|
||||||
window: Reference::Mutable(window),
|
window: Reference::Mutable(window),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn immutable(app: &'a AppContext<Thread>, window: &'w Window) -> Self {
|
pub(crate) fn immutable(app: &'a AppContext, window: &'w Window) -> Self {
|
||||||
Self {
|
Self {
|
||||||
app: Reference::Immutable(app),
|
app: Reference::Immutable(app),
|
||||||
window: Reference::Immutable(window),
|
window: Reference::Immutable(window),
|
||||||
|
@ -115,15 +123,15 @@ impl<'a, 'w, Thread> WindowContext<'a, 'w, Thread> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mouse_position(&self) -> Point<Pixels> {
|
pub fn mouse_position(&self) -> Point<Pixels> {
|
||||||
self.window.platform_window.mouse_position()
|
self.window.mouse_position
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_window<R>(
|
fn update_window<R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
window_id: WindowId,
|
window_id: WindowId,
|
||||||
update: impl FnOnce(&mut WindowContext<Thread>) -> R,
|
update: impl FnOnce(&mut WindowContext) -> R,
|
||||||
) -> Result<R> {
|
) -> Result<R> {
|
||||||
if window_id == self.window.id {
|
if window_id == self.window.handle.id {
|
||||||
Ok(update(self))
|
Ok(update(self))
|
||||||
} else {
|
} else {
|
||||||
self.app.update_window(window_id, update)
|
self.app.update_window(window_id, update)
|
||||||
|
@ -132,9 +140,9 @@ impl<'a, 'w, Thread> WindowContext<'a, 'w, Thread> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context for WindowContext<'_, '_> {
|
impl Context for WindowContext<'_, '_> {
|
||||||
type EntityContext<'a, 'w, T: 'static> = ViewContext<'a, 'w, T>;
|
type EntityContext<'a, 'w, T: Send + 'static> = ViewContext<'a, 'w, T>;
|
||||||
|
|
||||||
fn entity<T: 'static>(
|
fn entity<T: Send + 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
|
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
|
||||||
) -> Handle<T> {
|
) -> Handle<T> {
|
||||||
|
@ -152,7 +160,7 @@ impl Context for WindowContext<'_, '_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_entity<T: 'static, R>(
|
fn update_entity<T: Send + 'static, R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
handle: &Handle<T>,
|
handle: &Handle<T>,
|
||||||
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
|
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
|
||||||
|
@ -233,16 +241,16 @@ impl<'a, 'w, T: 'static> ViewContext<'a, 'w, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'w, T: 'static> Context for ViewContext<'a, 'w, T> {
|
impl<'a, 'w, T: 'static> Context for ViewContext<'a, 'w, T> {
|
||||||
type EntityContext<'b, 'c, U: 'static> = ViewContext<'b, 'c, U>;
|
type EntityContext<'b, 'c, U: Send + 'static> = ViewContext<'b, 'c, U>;
|
||||||
|
|
||||||
fn entity<T2: 'static>(
|
fn entity<T2: Send + 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T2>) -> T2,
|
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T2>) -> T2,
|
||||||
) -> Handle<T2> {
|
) -> Handle<T2> {
|
||||||
self.window_cx.entity(build_entity)
|
self.window_cx.entity(build_entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_entity<U: 'static, R>(
|
fn update_entity<U: Send + 'static, R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
handle: &Handle<U>,
|
handle: &Handle<U>,
|
||||||
update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
|
update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
|
||||||
|
|
|
@ -22,7 +22,7 @@ fn main() {
|
||||||
SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
|
SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
|
||||||
|
|
||||||
gpui3::App::production().run(|cx| {
|
gpui3::App::production().run(|cx| {
|
||||||
let window: gpui3::WindowHandle<()> = cx.open_window(Default::default(), |cx| todo!());
|
let window = cx.open_window(Default::default(), |cx| workspace(cx));
|
||||||
});
|
});
|
||||||
|
|
||||||
// gpui3::App::new(Assets).unwrap().run(|cx| {
|
// gpui3::App::new(Assets).unwrap().run(|cx| {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue