This commit is contained in:
Nathan Sobo 2023-08-07 13:54:47 -06:00
parent d4d32611fe
commit 3e0d0e5c01
5 changed files with 221 additions and 78 deletions

View File

@ -133,12 +133,18 @@ pub trait BorrowAppContext {
pub trait BorrowWindowContext {
type Result<T>;
fn read_window_with<T, F>(&self, window_id: usize, f: F) -> Self::Result<T>
fn read_window<T, F>(&self, window_id: usize, f: F) -> Self::Result<T>
where
F: FnOnce(&WindowContext) -> T;
fn read_window_optional<T, F>(&self, window_id: usize, f: F) -> Option<T>
where
F: FnOnce(&WindowContext) -> Option<T>;
fn update_window<T, F>(&mut self, window_id: usize, f: F) -> Self::Result<T>
where
F: FnOnce(&mut WindowContext) -> T;
fn update_window_optional<T, F>(&mut self, window_id: usize, f: F) -> Option<T>
where
F: FnOnce(&mut WindowContext) -> Option<T>;
}
#[derive(Clone)]
@ -449,13 +455,22 @@ impl BorrowAppContext for AsyncAppContext {
impl BorrowWindowContext for AsyncAppContext {
type Result<T> = Option<T>;
fn read_window_with<T, F>(&self, window_id: usize, f: F) -> Self::Result<T>
fn read_window<T, F>(&self, window_id: usize, f: F) -> Self::Result<T>
where
F: FnOnce(&WindowContext) -> T,
{
self.0.borrow().read_with(|cx| cx.read_window(window_id, f))
}
fn read_window_optional<T, F>(&self, window_id: usize, f: F) -> Option<T>
where
F: FnOnce(&WindowContext) -> Option<T>,
{
self.0
.borrow_mut()
.update(|cx| cx.read_window_optional(window_id, f))
}
fn update_window<T, F>(&mut self, window_id: usize, f: F) -> Self::Result<T>
where
F: FnOnce(&mut WindowContext) -> T,
@ -464,6 +479,15 @@ impl BorrowWindowContext for AsyncAppContext {
.borrow_mut()
.update(|cx| cx.update_window(window_id, f))
}
fn update_window_optional<T, F>(&mut self, window_id: usize, f: F) -> Option<T>
where
F: FnOnce(&mut WindowContext) -> Option<T>,
{
self.0
.borrow_mut()
.update(|cx| cx.update_window_optional(window_id, f))
}
}
type ActionCallback = dyn FnMut(&mut dyn AnyView, &dyn Action, &mut WindowContext, usize);
@ -1303,13 +1327,14 @@ impl AppContext {
F: FnOnce(&mut ViewContext<V>) -> V,
{
self.update(|this| {
let window = WindowHandle::<V>::new(post_inc(&mut this.next_id));
let window_id = post_inc(&mut this.next_id);
let platform_window =
this.platform
.open_window(window, window_options, this.foreground.clone());
let window = this.build_window(window, platform_window, build_root_view);
this.windows.insert(window.into(), window);
window
.open_window(window_id, window_options, this.foreground.clone());
let handle = WindowHandle::<V>::new(window_id);
let window = this.build_window(handle, platform_window, build_root_view);
this.windows.insert(window_id, window);
handle
})
}
@ -1319,11 +1344,11 @@ impl AppContext {
F: FnOnce(&mut ViewContext<V>) -> V,
{
self.update(|this| {
let handle = WindowHandle::<V>::new(post_inc(&mut this.next_id));
let platform_window = this.platform.add_status_item(handle.id());
let window_id = post_inc(&mut this.next_id);
let platform_window = this.platform.add_status_item(window_id);
let handle = WindowHandle::<V>::new(window_id);
let window = this.build_window(handle, platform_window, build_root_view);
this.windows.insert(handle.into(), window);
this.windows.insert(window_id, window);
handle.update_root(this, |view, cx| view.focus_in(cx.handle().into_any(), cx));
handle
})
@ -1340,11 +1365,14 @@ impl AppContext {
V: View,
F: FnOnce(&mut ViewContext<V>) -> V,
{
let handle: AnyWindowHandle = handle.into();
let window_id = handle.id();
{
let mut app = self.upgrade();
platform_window.on_event(Box::new(move |event| {
app.update_window(handle, |cx| {
app.update_window(window_id, |cx| {
if let Event::KeyDown(KeyDownEvent { keystroke, .. }) = &event {
if cx.dispatch_keystroke(keystroke) {
return true;
@ -1360,35 +1388,35 @@ impl AppContext {
{
let mut app = self.upgrade();
platform_window.on_active_status_change(Box::new(move |is_active| {
app.update(|cx| cx.window_changed_active_status(handle, is_active))
app.update(|cx| cx.window_changed_active_status(window_id, is_active))
}));
}
{
let mut app = self.upgrade();
platform_window.on_resize(Box::new(move || {
app.update(|cx| cx.window_was_resized(handle))
app.update(|cx| cx.window_was_resized(window_id))
}));
}
{
let mut app = self.upgrade();
platform_window.on_moved(Box::new(move || {
app.update(|cx| cx.window_was_moved(handle))
app.update(|cx| cx.window_was_moved(window_id))
}));
}
{
let mut app = self.upgrade();
platform_window.on_fullscreen(Box::new(move |is_fullscreen| {
app.update(|cx| cx.window_was_fullscreen_changed(handle, is_fullscreen))
app.update(|cx| cx.window_was_fullscreen_changed(window_id, is_fullscreen))
}));
}
{
let mut app = self.upgrade();
platform_window.on_close(Box::new(move || {
app.update(|cx| cx.update_window(handle, |cx| cx.remove_window()));
app.update(|cx| cx.update_window(window_id, |cx| cx.remove_window()));
}));
}
@ -1400,11 +1428,11 @@ impl AppContext {
platform_window.set_input_handler(Box::new(WindowInputHandler {
app: self.upgrade().0,
window_id: handle,
window: handle,
}));
let mut window = Window::new(handle, platform_window, self, build_root_view);
let mut cx = WindowContext::mutable(self, &mut window, handle);
let mut window = Window::new(window_id, platform_window, self, build_root_view);
let mut cx = WindowContext::mutable(self, &mut window, window_id);
cx.layout(false).expect("initial layout should not error");
let scene = cx.paint().expect("initial paint should not error");
window.platform_window.present_scene(scene);
@ -2156,13 +2184,20 @@ impl BorrowAppContext for AppContext {
impl BorrowWindowContext for AppContext {
type Result<T> = Option<T>;
fn read_window_with<T, F>(&self, window_id: usize, f: F) -> Self::Result<T>
fn read_window<T, F>(&self, window_id: usize, f: F) -> Self::Result<T>
where
F: FnOnce(&WindowContext) -> T,
{
AppContext::read_window(self, window_id, f)
}
fn read_window_optional<T, F>(&self, window_id: usize, f: F) -> Option<T>
where
F: FnOnce(&WindowContext) -> Option<T>,
{
AppContext::read_window(self, window_id, f).flatten()
}
fn update_window<T, F>(&mut self, window_id: usize, f: F) -> Self::Result<T>
where
F: FnOnce(&mut WindowContext) -> T,
@ -2177,6 +2212,13 @@ impl BorrowWindowContext for AppContext {
Some(result)
})
}
fn update_window_optional<T, F>(&mut self, window_id: usize, f: F) -> Option<T>
where
F: FnOnce(&mut WindowContext) -> Option<T>,
{
AppContext::update_window(self, window_id, f).flatten()
}
}
#[derive(Debug)]
@ -3379,8 +3421,15 @@ impl<V> BorrowAppContext for ViewContext<'_, '_, V> {
impl<V> BorrowWindowContext for ViewContext<'_, '_, V> {
type Result<T> = T;
fn read_window_with<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
BorrowWindowContext::read_window_with(&*self.window_context, window_id, f)
fn read_window<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
BorrowWindowContext::read_window(&*self.window_context, window_id, f)
}
fn read_window_optional<T, F>(&self, window_id: usize, f: F) -> Option<T>
where
F: FnOnce(&WindowContext) -> Option<T>,
{
BorrowWindowContext::read_window_optional(&*self.window_context, window_id, f)
}
fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
@ -3390,6 +3439,13 @@ impl<V> BorrowWindowContext for ViewContext<'_, '_, V> {
) -> T {
BorrowWindowContext::update_window(&mut *self.window_context, window_id, f)
}
fn update_window_optional<T, F>(&mut self, window_id: usize, f: F) -> Option<T>
where
F: FnOnce(&mut WindowContext) -> Option<T>,
{
BorrowWindowContext::update_window_optional(&mut *self.window_context, window_id, f)
}
}
pub struct LayoutContext<'a, 'b, 'c, V: View> {
@ -3490,8 +3546,15 @@ impl<V: View> BorrowAppContext for LayoutContext<'_, '_, '_, V> {
impl<V: View> BorrowWindowContext for LayoutContext<'_, '_, '_, V> {
type Result<T> = T;
fn read_window_with<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
BorrowWindowContext::read_window_with(&*self.view_context, window_id, f)
fn read_window<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
BorrowWindowContext::read_window(&*self.view_context, window_id, f)
}
fn read_window_optional<T, F>(&self, window_id: usize, f: F) -> Option<T>
where
F: FnOnce(&WindowContext) -> Option<T>,
{
BorrowWindowContext::read_window_optional(&*self.view_context, window_id, f)
}
fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
@ -3501,6 +3564,13 @@ impl<V: View> BorrowWindowContext for LayoutContext<'_, '_, '_, V> {
) -> T {
BorrowWindowContext::update_window(&mut *self.view_context, window_id, f)
}
fn update_window_optional<T, F>(&mut self, window_id: usize, f: F) -> Option<T>
where
F: FnOnce(&mut WindowContext) -> Option<T>,
{
BorrowWindowContext::update_window_optional(&mut *self.view_context, window_id, f)
}
}
pub struct EventContext<'a, 'b, 'c, V: View> {
@ -3548,8 +3618,15 @@ impl<V: View> BorrowAppContext for EventContext<'_, '_, '_, V> {
impl<V: View> BorrowWindowContext for EventContext<'_, '_, '_, V> {
type Result<T> = T;
fn read_window_with<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
BorrowWindowContext::read_window_with(&*self.view_context, window_id, f)
fn read_window<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
BorrowWindowContext::read_window(&*self.view_context, window_id, f)
}
fn read_window_optional<T, F>(&self, window_id: usize, f: F) -> Option<T>
where
F: FnOnce(&WindowContext) -> Option<T>,
{
BorrowWindowContext::read_window_optional(&*self.view_context, window_id, f)
}
fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
@ -3559,6 +3636,13 @@ impl<V: View> BorrowWindowContext for EventContext<'_, '_, '_, V> {
) -> T {
BorrowWindowContext::update_window(&mut *self.view_context, window_id, f)
}
fn update_window_optional<T, F>(&mut self, window_id: usize, f: F) -> Option<T>
where
F: FnOnce(&mut WindowContext) -> Option<T>,
{
BorrowWindowContext::update_window_optional(&mut *self.view_context, window_id, f)
}
}
pub(crate) enum Reference<'a, T> {
@ -3841,13 +3925,24 @@ impl<T> Clone for WeakModelHandle<T> {
impl<T> Copy for WeakModelHandle<T> {}
#[derive(Deref, Copy, Clone)]
pub struct WindowHandle<T> {
#[derive(Deref)]
pub struct WindowHandle<V> {
#[deref]
any_handle: AnyWindowHandle,
root_view_type: PhantomData<T>,
root_view_type: PhantomData<V>,
}
impl<V> Clone for WindowHandle<V> {
fn clone(&self) -> Self {
Self {
any_handle: self.any_handle.clone(),
root_view_type: PhantomData,
}
}
}
impl<V> Copy for WindowHandle<V> {}
impl<V: View> WindowHandle<V> {
fn new(window_id: usize) -> Self {
WindowHandle {
@ -3933,7 +4028,15 @@ impl AnyWindowHandle {
C: BorrowWindowContext,
F: FnOnce(&WindowContext) -> R,
{
cx.read_window_with(self.window_id, |cx| read(cx))
cx.read_window(self.window_id, |cx| read(cx))
}
pub fn read_optional_with<C, F, R>(&self, cx: &C, read: F) -> Option<R>
where
C: BorrowWindowContext,
F: FnOnce(&WindowContext) -> Option<R>,
{
cx.read_window_optional(self.window_id, |cx| read(cx))
}
pub fn update<C, F, R>(&self, cx: &mut C, update: F) -> C::Result<R>
@ -3944,6 +4047,14 @@ impl AnyWindowHandle {
cx.update_window(self.window_id, update)
}
pub fn update_optional<C, F, R>(&self, cx: &mut C, update: F) -> Option<R>
where
C: BorrowWindowContext,
F: FnOnce(&mut WindowContext) -> Option<R>,
{
cx.update_window_optional(self.window_id, update)
}
pub fn add_view<C, U, F>(&self, cx: &mut C, build_view: F) -> C::Result<ViewHandle<U>>
where
C: BorrowWindowContext,
@ -3953,6 +4064,17 @@ impl AnyWindowHandle {
self.update(cx, |cx| cx.add_view(build_view))
}
pub fn downcast<V: View>(self) -> Option<WindowHandle<V>> {
if self.root_view_type == TypeId::of::<V>() {
Some(WindowHandle {
any_handle: self,
root_view_type: PhantomData,
})
} else {
None
}
}
pub fn root_is<V: View>(&self) -> bool {
self.root_view_type == TypeId::of::<V>()
}
@ -4018,7 +4140,7 @@ impl<T: View> ViewHandle<T> {
C: BorrowWindowContext,
F: FnOnce(&T, &ViewContext<T>) -> S,
{
cx.read_window_with(self.window_id, |cx| {
cx.read_window(self.window_id, |cx| {
let cx = ViewContext::immutable(cx, self.view_id);
read(cx.read_view(self), &cx)
})

View File

@ -92,33 +92,34 @@ impl TestAppContext {
self.update(|cx| cx.dispatch_global_action_any(&action));
}
pub fn dispatch_keystroke(&mut self, window_id: usize, keystroke: Keystroke, is_held: bool) {
let handled = self
.cx
.borrow_mut()
.update_window(window_id, |cx| {
if cx.dispatch_keystroke(&keystroke) {
return true;
}
pub fn dispatch_keystroke(
&mut self,
window: AnyWindowHandle,
keystroke: Keystroke,
is_held: bool,
) {
let handled = window.update(self, |cx| {
if cx.dispatch_keystroke(&keystroke) {
return true;
}
if cx.dispatch_event(
Event::KeyDown(KeyDownEvent {
keystroke: keystroke.clone(),
is_held,
}),
false,
) {
return true;
}
if cx.dispatch_event(
Event::KeyDown(KeyDownEvent {
keystroke: keystroke.clone(),
is_held,
}),
false,
) {
return true;
}
false
})
.unwrap_or(false);
false
});
if !handled && !keystroke.cmd && !keystroke.ctrl {
WindowInputHandler {
app: self.cx.clone(),
window_id,
window,
}
.replace_text_in_range(None, &keystroke.key)
}
@ -419,13 +420,20 @@ impl BorrowAppContext for TestAppContext {
impl BorrowWindowContext for TestAppContext {
type Result<T> = T;
fn read_window_with<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
fn read_window<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
self.cx
.borrow()
.read_window(window_id, f)
.expect("window was closed")
}
fn read_window_optional<T, F>(&self, window_id: usize, f: F) -> Option<T>
where
F: FnOnce(&WindowContext) -> Option<T>,
{
BorrowWindowContext::read_window(self, window_id, f)
}
fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
&mut self,
window_id: usize,
@ -436,6 +444,13 @@ impl BorrowWindowContext for TestAppContext {
.update_window(window_id, f)
.expect("window was closed")
}
fn update_window_optional<T, F>(&mut self, window_id: usize, f: F) -> Option<T>
where
F: FnOnce(&mut WindowContext) -> Option<T>,
{
BorrowWindowContext::update_window(self, window_id, f)
}
}
impl<T: Entity> ModelHandle<T> {

View File

@ -144,7 +144,7 @@ impl BorrowAppContext for WindowContext<'_> {
impl BorrowWindowContext for WindowContext<'_> {
type Result<T> = T;
fn read_window_with<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
fn read_window<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
if self.window_id == window_id {
f(self)
} else {
@ -152,6 +152,13 @@ impl BorrowWindowContext for WindowContext<'_> {
}
}
fn read_window_optional<T, F>(&self, window_id: usize, f: F) -> Option<T>
where
F: FnOnce(&WindowContext) -> Option<T>,
{
BorrowWindowContext::read_window(self, window_id, f)
}
fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
&mut self,
window_id: usize,
@ -163,6 +170,13 @@ impl BorrowWindowContext for WindowContext<'_> {
panic!("update called with id of window that does not belong to this context")
}
}
fn update_window_optional<T, F>(&mut self, window_id: usize, f: F) -> Option<T>
where
F: FnOnce(&mut WindowContext) -> Option<T>,
{
BorrowWindowContext::update_window_optional(self, window_id, f)
}
}
impl<'a> WindowContext<'a> {

View File

@ -2,11 +2,11 @@ use std::{cell::RefCell, ops::Range, rc::Rc};
use pathfinder_geometry::rect::RectF;
use crate::{platform::InputHandler, window::WindowContext, AnyView, AppContext};
use crate::{platform::InputHandler, window::WindowContext, AnyView, AnyWindowHandle, AppContext};
pub struct WindowInputHandler {
pub app: Rc<RefCell<AppContext>>,
pub window_id: usize,
pub window: AnyWindowHandle,
}
impl WindowInputHandler {
@ -21,13 +21,12 @@ impl WindowInputHandler {
//
// See https://github.com/zed-industries/community/issues/444
let mut app = self.app.try_borrow_mut().ok()?;
app.update_window(self.window_id, |cx| {
self.window.update_optional(&mut *app, |cx| {
let view_id = cx.window.focused_view_id?;
let view = cx.views.get(&(self.window_id, view_id))?;
let view = cx.views.get(&(self.window.id(), view_id))?;
let result = f(view.as_ref(), &cx);
Some(result)
})
.flatten()
}
fn update_focused_view<T, F>(&mut self, f: F) -> Option<T>
@ -35,11 +34,12 @@ impl WindowInputHandler {
F: FnOnce(&mut dyn AnyView, &mut WindowContext, usize) -> T,
{
let mut app = self.app.try_borrow_mut().ok()?;
app.update_window(self.window_id, |cx| {
let view_id = cx.window.focused_view_id?;
cx.update_any_view(view_id, |view, cx| f(view, cx, view_id))
})
.flatten()
self.window
.update(&mut *app, |cx| {
let view_id = cx.window.focused_view_id?;
cx.update_any_view(view_id, |view, cx| f(view, cx, view_id))
})
.flatten()
}
}
@ -83,9 +83,8 @@ impl InputHandler for WindowInputHandler {
}
fn rect_for_range(&self, range_utf16: Range<usize>) -> Option<RectF> {
self.app
.borrow()
.read_window(self.window_id, |cx| cx.rect_for_text_range(range_utf16))
.flatten()
self.window.read_optional_with(&*self.app.borrow(), |cx| {
cx.rect_for_text_range(range_utf16)
})
}
}

View File

@ -4035,16 +4035,9 @@ pub fn restart(_: &Restart, cx: &mut AppContext) {
let should_confirm = settings::get::<WorkspaceSettings>(cx).confirm_quit;
cx.spawn(|mut cx| async move {
let mut workspaces = cx
.window_ids()
.windows()
.into_iter()
.filter_map(|window_id| {
Some(
cx.root_view(window_id)?
.clone()
.downcast::<Workspace>()?
.downgrade(),
)
})
.filter_map(|window| Some(window.downcast::<Workspace>()?.root(&cx)?.downgrade()))
.collect::<Vec<_>>();
// If multiple windows have unsaved changes, and need a save prompt,