Add AppContext::dispatch_action and use it for app menu actions

Co-Authored-By: Marshall <marshall@zed.dev>
Co-Authored-By: Julia <julia@zed.dev>
This commit is contained in:
Nathan Sobo 2023-12-05 15:49:06 -07:00
parent 631e264e3c
commit 79567d1c87
5 changed files with 73 additions and 33 deletions

View file

@ -39,7 +39,10 @@ use std::{
sync::{atomic::Ordering::SeqCst, Arc}, sync::{atomic::Ordering::SeqCst, Arc},
time::Duration, time::Duration,
}; };
use util::http::{self, HttpClient}; use util::{
http::{self, HttpClient},
ResultExt,
};
/// Temporary(?) wrapper around RefCell<AppContext> to help us debug any double borrows. /// Temporary(?) wrapper around RefCell<AppContext> to help us debug any double borrows.
/// Strongly consider removing after stabilization. /// Strongly consider removing after stabilization.
@ -1055,6 +1058,62 @@ impl AppContext {
self.global_action_listeners self.global_action_listeners
.contains_key(&action.as_any().type_id()) .contains_key(&action.as_any().type_id())
} }
pub fn dispatch_action(&mut self, action: &dyn Action) {
self.propagate_event = true;
if let Some(mut global_listeners) = self
.global_action_listeners
.remove(&action.as_any().type_id())
{
for listener in &global_listeners {
listener(action, DispatchPhase::Capture, self);
if !self.propagate_event {
break;
}
}
global_listeners.extend(
self.global_action_listeners
.remove(&action.as_any().type_id())
.unwrap_or_default(),
);
self.global_action_listeners
.insert(action.as_any().type_id(), global_listeners);
}
if self.propagate_event {
if let Some(active_window) = self.active_window() {
active_window
.update(self, |_, cx| cx.dispatch_action(action.boxed_clone()))
.log_err();
}
}
if self.propagate_event {
if let Some(mut global_listeners) = self
.global_action_listeners
.remove(&action.as_any().type_id())
{
for listener in global_listeners.iter().rev() {
listener(action, DispatchPhase::Bubble, self);
if !self.propagate_event {
break;
}
}
global_listeners.extend(
self.global_action_listeners
.remove(&action.as_any().type_id())
.unwrap_or_default(),
);
self.global_action_listeners
.insert(action.as_any().type_id(), global_listeners);
}
}
}
} }
impl Context for AppContext { impl Context for AppContext {

View file

@ -92,9 +92,9 @@ pub trait Platform: 'static {
fn on_reopen(&self, callback: Box<dyn FnMut()>); fn on_reopen(&self, callback: Box<dyn FnMut()>);
fn on_event(&self, callback: Box<dyn FnMut(InputEvent) -> bool>); fn on_event(&self, callback: Box<dyn FnMut(InputEvent) -> bool>);
fn on_menu_command(&self, callback: Box<dyn FnMut(&dyn Action)>); fn on_app_menu_action(&self, callback: Box<dyn FnMut(&dyn Action)>);
fn on_will_open_menu(&self, callback: Box<dyn FnMut()>); fn on_will_open_app_menu(&self, callback: Box<dyn FnMut()>);
fn on_validate_menu_command(&self, callback: Box<dyn FnMut(&dyn Action) -> bool>); fn on_validate_app_menu_command(&self, callback: Box<dyn FnMut(&dyn Action) -> bool>);
fn os_name(&self) -> &'static str; fn os_name(&self) -> &'static str;
fn os_version(&self) -> Result<SemanticVersion>; fn os_version(&self) -> Result<SemanticVersion>;

View file

@ -53,14 +53,14 @@ pub enum OsAction {
} }
pub(crate) fn init(platform: &dyn Platform, cx: &mut AppContext) { pub(crate) fn init(platform: &dyn Platform, cx: &mut AppContext) {
platform.on_will_open_menu(Box::new({ platform.on_will_open_app_menu(Box::new({
let cx = cx.to_async(); let cx = cx.to_async();
move || { move || {
cx.update(|cx| cx.clear_pending_keystrokes()).ok(); cx.update(|cx| cx.clear_pending_keystrokes()).ok();
} }
})); }));
platform.on_validate_menu_command(Box::new({ platform.on_validate_app_menu_command(Box::new({
let cx = cx.to_async(); let cx = cx.to_async();
move |action| { move |action| {
cx.update(|cx| cx.is_action_available(action)) cx.update(|cx| cx.is_action_available(action))
@ -68,29 +68,10 @@ pub(crate) fn init(platform: &dyn Platform, cx: &mut AppContext) {
} }
})); }));
platform.on_menu_command(Box::new({ platform.on_app_menu_action(Box::new({
let cx = cx.to_async(); let cx = cx.to_async();
move |action| { move |action| {
cx.update(|cx| { cx.update(|cx| cx.dispatch_action(action)).log_err();
// if let Some(main_window) = cx.active_window() {
// let dispatched = main_window
// .update(&mut *cx, |cx| {
// if let Some(view_id) = cx.focused_view_id() {
// cx.dispatch_action(Some(view_id), action);
// true
// } else {
// false
// }
// })
// .unwrap_or(false);
// if dispatched {
// return;
// }
// }
// cx.dispatch_global_action_any(action);
})
.log_err();
} }
})); }));
} }

View file

@ -683,15 +683,15 @@ impl Platform for MacPlatform {
} }
} }
fn on_menu_command(&self, callback: Box<dyn FnMut(&dyn Action)>) { fn on_app_menu_action(&self, callback: Box<dyn FnMut(&dyn Action)>) {
self.0.lock().menu_command = Some(callback); self.0.lock().menu_command = Some(callback);
} }
fn on_will_open_menu(&self, callback: Box<dyn FnMut()>) { fn on_will_open_app_menu(&self, callback: Box<dyn FnMut()>) {
self.0.lock().will_open_menu = Some(callback); self.0.lock().will_open_menu = Some(callback);
} }
fn on_validate_menu_command(&self, callback: Box<dyn FnMut(&dyn Action) -> bool>) { fn on_validate_app_menu_command(&self, callback: Box<dyn FnMut(&dyn Action) -> bool>) {
self.0.lock().validate_menu_command = Some(callback); self.0.lock().validate_menu_command = Some(callback);
} }

View file

@ -205,15 +205,15 @@ impl Platform for TestPlatform {
unimplemented!() unimplemented!()
} }
fn on_menu_command(&self, _callback: Box<dyn FnMut(&dyn crate::Action)>) { fn on_app_menu_action(&self, _callback: Box<dyn FnMut(&dyn crate::Action)>) {
unimplemented!() unimplemented!()
} }
fn on_will_open_menu(&self, _callback: Box<dyn FnMut()>) { fn on_will_open_app_menu(&self, _callback: Box<dyn FnMut()>) {
unimplemented!() unimplemented!()
} }
fn on_validate_menu_command(&self, _callback: Box<dyn FnMut(&dyn crate::Action) -> bool>) { fn on_validate_app_menu_command(&self, _callback: Box<dyn FnMut(&dyn crate::Action) -> bool>) {
unimplemented!() unimplemented!()
} }