Rename MainThreadPlatform to ForegroundPlatform and fix crash on quit

Nathan Sobo and Max Brunsfeld created

Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>

Change summary

gpui/src/app.rs                   | 45 ++++++++++++++++----------------
gpui/src/platform.rs              | 36 +++++++++++++-------------
gpui/src/platform/mac.rs          | 10 +++---
gpui/src/platform/mac/platform.rs | 30 +++++++++++----------
gpui/src/platform/test.rs         | 14 +++++-----
5 files changed, 68 insertions(+), 67 deletions(-)

Detailed changes

gpui/src/app.rs 🔗

@@ -107,7 +107,7 @@ pub struct AsyncAppContext(Rc<RefCell<MutableAppContext>>);
 #[derive(Clone)]
 pub struct TestAppContext {
     cx: Rc<RefCell<MutableAppContext>>,
-    main_thread_platform: Rc<platform::test::MainThreadPlatform>,
+    foreground_platform: Rc<platform::test::ForegroundPlatform>,
 }
 
 impl App {
@@ -115,13 +115,13 @@ impl App {
         asset_source: A,
         f: F,
     ) -> T {
-        let main_thread_platform = platform::test::main_thread_platform();
+        let foreground_platform = platform::test::foreground_platform();
         let platform = platform::test::platform();
         let foreground = Rc::new(executor::Foreground::test());
         let cx = Rc::new(RefCell::new(MutableAppContext::new(
             foreground,
             Arc::new(platform),
-            Rc::new(main_thread_platform),
+            Rc::new(foreground_platform),
             asset_source,
         )));
         cx.borrow_mut().weak_self = Some(Rc::downgrade(&cx));
@@ -135,16 +135,16 @@ impl App {
         F: Future<Output = T>,
     {
         let platform = Arc::new(platform::test::platform());
-        let main_thread_platform = Rc::new(platform::test::main_thread_platform());
+        let foreground_platform = Rc::new(platform::test::foreground_platform());
         let foreground = Rc::new(executor::Foreground::test());
         let cx = TestAppContext {
             cx: Rc::new(RefCell::new(MutableAppContext::new(
                 foreground.clone(),
                 platform,
-                main_thread_platform.clone(),
+                foreground_platform.clone(),
                 asset_source,
             ))),
-            main_thread_platform,
+            foreground_platform,
         };
         cx.cx.borrow_mut().weak_self = Some(Rc::downgrade(&cx.cx));
 
@@ -154,17 +154,17 @@ impl App {
 
     pub fn new(asset_source: impl AssetSource) -> Result<Self> {
         let platform = platform::current::platform();
-        let main_thread_platform = platform::current::main_thread_platform();
+        let foreground_platform = platform::current::foreground_platform();
         let foreground = Rc::new(executor::Foreground::platform(platform.dispatcher())?);
         let app = Self(Rc::new(RefCell::new(MutableAppContext::new(
             foreground,
             platform.clone(),
-            main_thread_platform.clone(),
+            foreground_platform.clone(),
             asset_source,
         ))));
 
         let cx = app.0.clone();
-        main_thread_platform.on_menu_command(Box::new(move |command, arg| {
+        foreground_platform.on_menu_command(Box::new(move |command, arg| {
             let mut cx = cx.borrow_mut();
             if let Some(key_window_id) = cx.platform.key_window_id() {
                 if let Some((presenter, _)) = cx.presenters_and_platform_windows.get(&key_window_id)
@@ -191,7 +191,7 @@ impl App {
         let cx = self.0.clone();
         self.0
             .borrow_mut()
-            .main_thread_platform
+            .foreground_platform
             .on_become_active(Box::new(move || callback(&mut *cx.borrow_mut())));
         self
     }
@@ -203,7 +203,7 @@ impl App {
         let cx = self.0.clone();
         self.0
             .borrow_mut()
-            .main_thread_platform
+            .foreground_platform
             .on_resign_active(Box::new(move || callback(&mut *cx.borrow_mut())));
         self
     }
@@ -215,7 +215,7 @@ impl App {
         let cx = self.0.clone();
         self.0
             .borrow_mut()
-            .main_thread_platform
+            .foreground_platform
             .on_event(Box::new(move |event| {
                 callback(event, &mut *cx.borrow_mut())
             }));
@@ -229,7 +229,7 @@ impl App {
         let cx = self.0.clone();
         self.0
             .borrow_mut()
-            .main_thread_platform
+            .foreground_platform
             .on_open_files(Box::new(move |paths| {
                 callback(paths, &mut *cx.borrow_mut())
             }));
@@ -240,7 +240,7 @@ impl App {
     where
         F: 'static + FnOnce(&mut MutableAppContext),
     {
-        let platform = self.0.borrow().main_thread_platform.clone();
+        let platform = self.0.borrow().foreground_platform.clone();
         platform.run(Box::new(move || {
             let mut cx = self.0.borrow_mut();
             on_finish_launching(&mut *cx);
@@ -366,12 +366,11 @@ impl TestAppContext {
     }
 
     pub fn simulate_new_path_selection(&self, result: impl FnOnce(PathBuf) -> Option<PathBuf>) {
-        self.main_thread_platform
-            .simulate_new_path_selection(result);
+        self.foreground_platform.simulate_new_path_selection(result);
     }
 
     pub fn did_prompt_for_new_path(&self) -> bool {
-        self.main_thread_platform.as_ref().did_prompt_for_new_path()
+        self.foreground_platform.as_ref().did_prompt_for_new_path()
     }
 
     pub fn simulate_prompt_answer(&self, window_id: usize, answer: usize) {
@@ -529,7 +528,7 @@ type GlobalActionCallback = dyn FnMut(&dyn Any, &mut MutableAppContext);
 
 pub struct MutableAppContext {
     weak_self: Option<rc::Weak<RefCell<Self>>>,
-    main_thread_platform: Rc<dyn platform::MainThreadPlatform>,
+    foreground_platform: Rc<dyn platform::ForegroundPlatform>,
     platform: Arc<dyn platform::Platform>,
     assets: Arc<AssetCache>,
     cx: AppContext,
@@ -554,13 +553,13 @@ impl MutableAppContext {
     fn new(
         foreground: Rc<executor::Foreground>,
         platform: Arc<dyn platform::Platform>,
-        main_thread_platform: Rc<dyn platform::MainThreadPlatform>,
+        foreground_platform: Rc<dyn platform::ForegroundPlatform>,
         asset_source: impl AssetSource,
     ) -> Self {
         let fonts = platform.fonts();
         Self {
             weak_self: None,
-            main_thread_platform,
+            foreground_platform,
             platform,
             assets: Arc::new(AssetCache::new(asset_source)),
             cx: AppContext {
@@ -721,7 +720,7 @@ impl MutableAppContext {
     }
 
     pub fn set_menus(&mut self, menus: Vec<Menu>) {
-        self.main_thread_platform.set_menus(menus);
+        self.foreground_platform.set_menus(menus);
     }
 
     fn prompt<F>(
@@ -755,7 +754,7 @@ impl MutableAppContext {
     {
         let app = self.weak_self.as_ref().unwrap().upgrade().unwrap();
         let foreground = self.foreground.clone();
-        self.main_thread_platform.prompt_for_paths(
+        self.foreground_platform.prompt_for_paths(
             options,
             Box::new(move |paths| {
                 foreground
@@ -771,7 +770,7 @@ impl MutableAppContext {
     {
         let app = self.weak_self.as_ref().unwrap().upgrade().unwrap();
         let foreground = self.foreground.clone();
-        self.main_thread_platform.prompt_for_new_path(
+        self.foreground_platform.prompt_for_new_path(
             directory,
             Box::new(move |path| {
                 foreground

gpui/src/platform.rs 🔗

@@ -27,7 +27,24 @@ use std::{
     sync::Arc,
 };
 
-pub(crate) trait MainThreadPlatform {
+pub trait Platform: Send + Sync {
+    fn dispatcher(&self) -> Arc<dyn Dispatcher>;
+    fn fonts(&self) -> Arc<dyn FontSystem>;
+
+    fn activate(&self, ignoring_other_apps: bool);
+    fn open_window(
+        &self,
+        id: usize,
+        options: WindowOptions,
+        executor: Rc<executor::Foreground>,
+    ) -> Box<dyn Window>;
+    fn key_window_id(&self) -> Option<usize>;
+    fn quit(&self);
+    fn write_to_clipboard(&self, item: ClipboardItem);
+    fn read_from_clipboard(&self) -> Option<ClipboardItem>;
+}
+
+pub(crate) trait ForegroundPlatform {
     fn on_become_active(&self, callback: Box<dyn FnMut()>);
     fn on_resign_active(&self, callback: Box<dyn FnMut()>);
     fn on_event(&self, callback: Box<dyn FnMut(Event) -> bool>);
@@ -48,23 +65,6 @@ pub(crate) trait MainThreadPlatform {
     );
 }
 
-pub trait Platform: Send + Sync {
-    fn dispatcher(&self) -> Arc<dyn Dispatcher>;
-    fn fonts(&self) -> Arc<dyn FontSystem>;
-
-    fn activate(&self, ignoring_other_apps: bool);
-    fn open_window(
-        &self,
-        id: usize,
-        options: WindowOptions,
-        executor: Rc<executor::Foreground>,
-    ) -> Box<dyn Window>;
-    fn key_window_id(&self) -> Option<usize>;
-    fn quit(&self);
-    fn write_to_clipboard(&self, item: ClipboardItem);
-    fn read_from_clipboard(&self) -> Option<ClipboardItem>;
-}
-
 pub trait Dispatcher: Send + Sync {
     fn is_main_thread(&self) -> bool;
     fn run_on_main_thread(&self, task: Runnable);

gpui/src/platform/mac.rs 🔗

@@ -11,18 +11,18 @@ mod window;
 use cocoa::base::{BOOL, NO, YES};
 pub use dispatcher::Dispatcher;
 pub use fonts::FontSystem;
-use platform::{MacMainThreadPlatform, MacPlatform};
+use platform::{MacForegroundPlatform, MacPlatform};
 use std::{rc::Rc, sync::Arc};
 use window::Window;
 
-pub(crate) fn main_thread_platform() -> Rc<dyn super::MainThreadPlatform> {
-    Rc::new(MacMainThreadPlatform::default())
-}
-
 pub(crate) fn platform() -> Arc<dyn super::Platform> {
     Arc::new(MacPlatform::new())
 }
 
+pub(crate) fn foreground_platform() -> Rc<dyn super::ForegroundPlatform> {
+    Rc::new(MacForegroundPlatform::default())
+}
+
 trait BoolExt {
     fn to_objc(self) -> BOOL;
 }

gpui/src/platform/mac/platform.rs 🔗

@@ -76,10 +76,10 @@ unsafe fn build_classes() {
 }
 
 #[derive(Default)]
-pub struct MacMainThreadPlatform(RefCell<MacMainThreadPlatformState>);
+pub struct MacForegroundPlatform(RefCell<MacForegroundPlatformState>);
 
 #[derive(Default)]
-pub struct MacMainThreadPlatformState {
+pub struct MacForegroundPlatformState {
     become_active: Option<Box<dyn FnMut()>>,
     resign_active: Option<Box<dyn FnMut()>>,
     event: Option<Box<dyn FnMut(crate::Event) -> bool>>,
@@ -89,7 +89,7 @@ pub struct MacMainThreadPlatformState {
     menu_actions: Vec<(String, Option<Box<dyn Any>>)>,
 }
 
-impl MacMainThreadPlatform {
+impl MacForegroundPlatform {
     unsafe fn create_menu_bar(&self, menus: Vec<Menu>) -> id {
         let menu_bar = NSMenu::new(nil).autorelease();
         let mut state = self.0.borrow_mut();
@@ -170,7 +170,7 @@ impl MacMainThreadPlatform {
     }
 }
 
-impl platform::MainThreadPlatform for MacMainThreadPlatform {
+impl platform::ForegroundPlatform for MacForegroundPlatform {
     fn on_become_active(&self, callback: Box<dyn FnMut()>) {
         self.0.borrow_mut().become_active = Some(callback);
     }
@@ -451,16 +451,16 @@ impl platform::Platform for MacPlatform {
     }
 }
 
-unsafe fn get_main_thread_platform(object: &mut Object) -> &MacMainThreadPlatform {
+unsafe fn get_foreground_platform(object: &mut Object) -> &MacForegroundPlatform {
     let platform_ptr: *mut c_void = *object.get_ivar(MAC_PLATFORM_IVAR);
     assert!(!platform_ptr.is_null());
-    &*(platform_ptr as *const MacMainThreadPlatform)
+    &*(platform_ptr as *const MacForegroundPlatform)
 }
 
 extern "C" fn send_event(this: &mut Object, _sel: Sel, native_event: id) {
     unsafe {
         if let Some(event) = Event::from_native(native_event, None) {
-            let platform = get_main_thread_platform(this);
+            let platform = get_foreground_platform(this);
             if let Some(callback) = platform.0.borrow_mut().event.as_mut() {
                 if callback(event) {
                     return;
@@ -477,7 +477,7 @@ extern "C" fn did_finish_launching(this: &mut Object, _: Sel, _: id) {
         let app: id = msg_send![APP_CLASS, sharedApplication];
         app.setActivationPolicy_(NSApplicationActivationPolicyRegular);
 
-        let platform = get_main_thread_platform(this);
+        let platform = get_foreground_platform(this);
         let callback = platform.0.borrow_mut().finish_launching.take();
         if let Some(callback) = callback {
             callback();
@@ -486,14 +486,14 @@ extern "C" fn did_finish_launching(this: &mut Object, _: Sel, _: id) {
 }
 
 extern "C" fn did_become_active(this: &mut Object, _: Sel, _: id) {
-    let platform = unsafe { get_main_thread_platform(this) };
+    let platform = unsafe { get_foreground_platform(this) };
     if let Some(callback) = platform.0.borrow_mut().become_active.as_mut() {
         callback();
     }
 }
 
 extern "C" fn did_resign_active(this: &mut Object, _: Sel, _: id) {
-    let platform = unsafe { get_main_thread_platform(this) };
+    let platform = unsafe { get_foreground_platform(this) };
     if let Some(callback) = platform.0.borrow_mut().resign_active.as_mut() {
         callback();
     }
@@ -515,7 +515,7 @@ extern "C" fn open_files(this: &mut Object, _: Sel, _: id, paths: id) {
             })
             .collect::<Vec<_>>()
     };
-    let platform = unsafe { get_main_thread_platform(this) };
+    let platform = unsafe { get_foreground_platform(this) };
     if let Some(callback) = platform.0.borrow_mut().open_files.as_mut() {
         callback(paths);
     }
@@ -523,13 +523,15 @@ extern "C" fn open_files(this: &mut Object, _: Sel, _: id, paths: id) {
 
 extern "C" fn handle_menu_item(this: &mut Object, _: Sel, item: id) {
     unsafe {
-        let platform = get_main_thread_platform(this);
-        if let Some(callback) = platform.0.borrow_mut().menu_command.as_mut() {
+        let platform = get_foreground_platform(this);
+        let mut platform = platform.0.borrow_mut();
+        if let Some(mut callback) = platform.menu_command.take() {
             let tag: NSInteger = msg_send![item, tag];
             let index = tag as usize;
-            if let Some((action, arg)) = platform.0.borrow_mut().menu_actions.get(index) {
+            if let Some((action, arg)) = platform.menu_actions.get(index) {
                 callback(action, arg.as_ref().map(Box::as_ref));
             }
+            platform.menu_command = Some(callback);
         }
     }
 }

gpui/src/platform/test.rs 🔗

@@ -16,7 +16,7 @@ pub(crate) struct Platform {
 }
 
 #[derive(Default)]
-pub(crate) struct MainThreadPlatform {
+pub(crate) struct ForegroundPlatform {
     last_prompt_for_new_path_args: RefCell<Option<(PathBuf, Box<dyn FnOnce(Option<PathBuf>)>)>>,
 }
 
@@ -32,7 +32,7 @@ pub struct Window {
     pub(crate) last_prompt: RefCell<Option<Box<dyn FnOnce(usize)>>>,
 }
 
-impl MainThreadPlatform {
+impl ForegroundPlatform {
     pub(crate) fn simulate_new_path_selection(
         &self,
         result: impl FnOnce(PathBuf) -> Option<PathBuf>,
@@ -49,7 +49,7 @@ impl MainThreadPlatform {
     }
 }
 
-impl super::MainThreadPlatform for MainThreadPlatform {
+impl super::ForegroundPlatform for ForegroundPlatform {
     fn on_become_active(&self, _: Box<dyn FnMut()>) {}
 
     fn on_resign_active(&self, _: Box<dyn FnMut()>) {}
@@ -183,10 +183,10 @@ impl super::Window for Window {
     }
 }
 
-pub(crate) fn main_thread_platform() -> MainThreadPlatform {
-    MainThreadPlatform::default()
-}
-
 pub(crate) fn platform() -> Platform {
     Platform::new()
 }
+
+pub(crate) fn foreground_platform() -> ForegroundPlatform {
+    ForegroundPlatform::default()
+}