Add Menu.closePopup API on macOS
authorKevin Sawicki <kevinsawicki@gmail.com>
Thu, 16 Feb 2017 18:58:02 +0000 (10:58 -0800)
committerKevin Sawicki <kevinsawicki@gmail.com>
Wed, 22 Feb 2017 18:30:28 +0000 (10:30 -0800)
atom/browser/api/atom_api_menu.cc
atom/browser/api/atom_api_menu.h
atom/browser/api/atom_api_menu_mac.h
atom/browser/api/atom_api_menu_mac.mm
atom/browser/api/atom_api_window.h
atom/browser/ui/cocoa/atom_menu_controller.h
atom/browser/ui/cocoa/atom_menu_controller.mm
lib/browser/api/menu.js

index 627ce60..da208b3 100644 (file)
@@ -176,7 +176,8 @@ void Menu::BuildPrototype(v8::Isolate* isolate,
       .SetMethod("isItemCheckedAt", &Menu::IsItemCheckedAt)
       .SetMethod("isEnabledAt", &Menu::IsEnabledAt)
       .SetMethod("isVisibleAt", &Menu::IsVisibleAt)
-      .SetMethod("popupAt", &Menu::PopupAt);
+      .SetMethod("popupAt", &Menu::PopupAt)
+      .SetMethod("closePopupAt", &Menu::ClosePopupAt);
 }
 
 }  // namespace api
index 772b2f3..59312e1 100644 (file)
@@ -55,6 +55,7 @@ class Menu : public mate::TrackableObject<Menu>,
 
   virtual void PopupAt(Window* window, int x, int y, int positioning_item,
                       bool async) = 0;
+  virtual void ClosePopupAt(int32_t window_id) = 0;
 
   std::unique_ptr<AtomMenuModel> model_;
   Menu* parent_;
index 0c5c7f7..7c41cd7 100644 (file)
@@ -7,10 +7,13 @@
 
 #include "atom/browser/api/atom_api_menu.h"
 
+#include <map>
 #include <string>
 
 #import "atom/browser/ui/cocoa/atom_menu_controller.h"
 
+using base::scoped_nsobject;
+
 namespace atom {
 
 namespace api {
@@ -22,9 +25,12 @@ class MenuMac : public Menu {
   void PopupAt(
       Window* window, int x, int y, int positioning_item, bool async) override;
   void PopupOnUI(const base::WeakPtr<NativeWindow>& native_window,
-                 int x, int y, int positioning_item, bool async);
+                 int32_t window_id, int x, int y, int positioning_item,
+                 bool async);
+  void ClosePopupAt(int32_t window_id) override;
 
-  base::scoped_nsobject<AtomMenuController> menu_controller_;
+  scoped_nsobject<AtomMenuController> menu_controller_;
+  std::map<int32_t, scoped_nsobject<AtomMenuController>> popup_controllers_;
 
  private:
   friend class Menu;
index 84a6b8d..9741202 100644 (file)
@@ -34,8 +34,8 @@ void MenuMac::PopupAt(
     return;
 
   auto popup = base::Bind(&MenuMac::PopupOnUI, weak_factory_.GetWeakPtr(),
-                          native_window->GetWeakPtr(), x, y, positioning_item,
-                          async);
+                          native_window->GetWeakPtr(), window->ID(), x, y,
+                          positioning_item, async);
   if (async)
     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, popup);
   else
@@ -43,7 +43,8 @@ void MenuMac::PopupAt(
 }
 
 void MenuMac::PopupOnUI(const base::WeakPtr<NativeWindow>& native_window,
-                        int x, int y, int positioning_item, bool async) {
+                        int32_t window_id, int x, int y, int positioning_item,
+                        bool async) {
   if (!native_window)
     return;
   brightray::InspectableWebContents* web_contents =
@@ -51,10 +52,12 @@ void MenuMac::PopupOnUI(const base::WeakPtr<NativeWindow>& native_window,
   if (!web_contents)
     return;
 
-  base::scoped_nsobject<AtomMenuController> menu_controller(
-      [[AtomMenuController alloc] initWithModel:model_.get()
+  auto close_callback = base::Bind(&MenuMac::ClosePopupAt,
+                                   weak_factory_.GetWeakPtr(), window_id);
+  popup_controllers_[window_id] = base::scoped_nsobject<AtomMenuController>(
+      [[AtomMenuController alloc] initWithModel:model()
                           useDefaultAccelerator:NO]);
-  NSMenu* menu = [menu_controller menu];
+  NSMenu* menu = [popup_controllers_[window_id] menu];
   NSView* view = web_contents->GetView()->GetNativeView();
 
   // Which menu item to show.
@@ -91,6 +94,7 @@ void MenuMac::PopupOnUI(const base::WeakPtr<NativeWindow>& native_window,
 
 
   if (async) {
+    [popup_controllers_[window_id] setCloseCallback:close_callback];
     // Make sure events can be pumped while the menu is up.
     base::MessageLoop::ScopedNestableTaskAllower allow(
         base::MessageLoop::current());
@@ -109,9 +113,14 @@ void MenuMac::PopupOnUI(const base::WeakPtr<NativeWindow>& native_window,
     // Don't emit unresponsive event when showing menu.
     atom::UnresponsiveSuppressor suppressor;
     [menu popUpMenuPositioningItem:item atLocation:position inView:view];
+    close_callback.Run();
   }
 }
 
+void MenuMac::ClosePopupAt(int32_t window_id) {
+  popup_controllers_.erase(window_id);
+}
+
 // static
 void Menu::SetApplicationMenu(Menu* base_menu) {
   MenuMac* menu = static_cast<MenuMac*>(base_menu);
index 9908fee..80af78a 100644 (file)
@@ -51,6 +51,8 @@ class Window : public mate::TrackableObject<Window>,
 
   NativeWindow* window() const { return window_.get(); }
 
+  int32_t ID() const;
+
  protected:
   Window(v8::Isolate* isolate, v8::Local<v8::Object> wrapper,
          const mate::Dictionary& options);
@@ -202,7 +204,6 @@ class Window : public mate::TrackableObject<Window>,
 
   void SetVibrancy(mate::Arguments* args);
 
-  int32_t ID() const;
   v8::Local<v8::Value> WebContents(v8::Isolate* isolate);
 
   // Remove this window from parent window's |child_windows_|.
index af0b276..a230437 100644 (file)
@@ -8,6 +8,7 @@
 
 #import <Cocoa/Cocoa.h>
 
+#include "base/callback.h"
 #include "base/mac/scoped_nsobject.h"
 #include "base/strings/string16.h"
 
@@ -27,6 +28,7 @@ class AtomMenuModel;
   base::scoped_nsobject<NSMenu> menu_;
   BOOL isMenuOpen_;
   BOOL useDefaultAccelerator_;
+  base::Callback<void()> closeCallback;
 }
 
 @property(nonatomic, assign) atom::AtomMenuModel* model;
@@ -35,6 +37,8 @@ class AtomMenuModel;
 // to the contents of the model after calling this will not be noticed.
 - (id)initWithModel:(atom::AtomMenuModel*)model useDefaultAccelerator:(BOOL)use;
 
+- (void)setCloseCallback:(const base::Callback<void()>&)callback;
+
 // Populate current NSMenu with |model|.
 - (void)populateWithModel:(atom::AtomMenuModel*)model;
 
index 6bdaa4c..2286b6b 100644 (file)
@@ -71,6 +71,10 @@ Role kRolesMap[] = {
   [super dealloc];
 }
 
+- (void)setCloseCallback:(const base::Callback<void()>&)callback {
+  closeCallback = callback;
+}
+
 - (void)populateWithModel:(atom::AtomMenuModel*)model {
   if (!menu_)
     return;
@@ -265,8 +269,10 @@ Role kRolesMap[] = {
 
 - (void)menuDidClose:(NSMenu*)menu {
   if (isMenuOpen_) {
-    model_->MenuWillClose();
     isMenuOpen_ = NO;
+    model_->MenuWillClose();
+    if (!closeCallback.is_null())
+      closeCallback.Run();
   }
 }
 
index e4fda6d..30f3df7 100644 (file)
@@ -174,6 +174,15 @@ Menu.prototype.popup = function (window, x, y, positioningItem) {
   this.popupAt(window, x, y, positioningItem, asyncPopup)
 }
 
+Menu.prototype.closePopup = function (window) {
+  if (window == null || window.constructor !== BrowserWindow) {
+    window = BrowserWindow.getFocusedWindow()
+  }
+  if (window != null) {
+    this.closePopupAt(window.id)
+  }
+}
+
 Menu.prototype.append = function (item) {
   return this.insert(this.getItemCount(), item)
 }