Browse Source

Merge pull request #3660 from atom/tray-custom-menu

Add `menu` parameter for Tray.popUpContextMenu
Cheng Zhao 9 years ago
parent
commit
4252c17db0

+ 3 - 1
atom/browser/api/atom_api_tray.cc

@@ -137,9 +137,11 @@ void Tray::DisplayBalloon(mate::Arguments* args,
 }
 
 void Tray::PopUpContextMenu(mate::Arguments* args) {
+  mate::Handle<Menu> menu;
+  args->GetNext(&menu);
   gfx::Point pos;
   args->GetNext(&pos);
-  tray_icon_->PopUpContextMenu(pos);
+  tray_icon_->PopUpContextMenu(pos, menu.IsEmpty() ? nullptr : menu->model());
 }
 
 void Tray::SetContextMenu(mate::Arguments* args, Menu* menu) {

+ 2 - 1
atom/browser/ui/tray_icon.cc

@@ -26,7 +26,8 @@ void TrayIcon::DisplayBalloon(const gfx::Image& icon,
                               const base::string16& contents) {
 }
 
-void TrayIcon::PopUpContextMenu(const gfx::Point& pos) {
+void TrayIcon::PopUpContextMenu(const gfx::Point& pos,
+                                ui::SimpleMenuModel* menu_model) {
 }
 
 void TrayIcon::NotifyClicked(const gfx::Rect& bounds, int modifiers) {

+ 3 - 1
atom/browser/ui/tray_icon.h

@@ -47,7 +47,9 @@ class TrayIcon {
                               const base::string16& title,
                               const base::string16& contents);
 
-  virtual void PopUpContextMenu(const gfx::Point& pos);
+  // Popups the menu.
+  virtual void PopUpContextMenu(const gfx::Point& pos,
+                                ui::SimpleMenuModel* menu_model);
 
   // Set the context menu for this icon.
   virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) = 0;

+ 2 - 1
atom/browser/ui/tray_icon_cocoa.h

@@ -29,7 +29,8 @@ class TrayIconCocoa : public TrayIcon,
   void SetToolTip(const std::string& tool_tip) override;
   void SetTitle(const std::string& title) override;
   void SetHighlightMode(bool highlight) override;
-  void PopUpContextMenu(const gfx::Point& pos) override;
+  void PopUpContextMenu(const gfx::Point& pos,
+                        ui::SimpleMenuModel* menu_model) override;
   void SetContextMenu(ui::SimpleMenuModel* menu_model) override;
 
  protected:

+ 21 - 3
atom/browser/ui/tray_icon_cocoa.mm

@@ -23,6 +23,7 @@ const CGFloat kVerticalTitleMargin = 2;
   atom::TrayIconCocoa* trayIcon_; // weak
   AtomMenuController* menuController_; // weak
   BOOL isHighlightEnable_;
+  BOOL forceHighlight_;
   BOOL inMouseEventSequence_;
   base::scoped_nsobject<NSImage> image_;
   base::scoped_nsobject<NSImage> alternateImage_;
@@ -39,6 +40,8 @@ const CGFloat kVerticalTitleMargin = 2;
   image_.reset([image copy]);
   trayIcon_ = icon;
   isHighlightEnable_ = YES;
+  forceHighlight_ = NO;
+  inMouseEventSequence_ = NO;
 
   if ((self = [super initWithFrame: CGRectZero])) {
     // Setup the image view.
@@ -238,7 +241,19 @@ const CGFloat kVerticalTitleMargin = 2;
   [self setNeedsDisplay:YES];
 }
 
-- (void)popUpContextMenu {
+- (void)popUpContextMenu:(ui::SimpleMenuModel*)menu_model {
+  // Show a custom menu.
+  if (menu_model) {
+    base::scoped_nsobject<AtomMenuController> menuController(
+        [[AtomMenuController alloc] initWithModel:menu_model]);
+    forceHighlight_ = YES;  // Should highlight when showing menu.
+    [self setNeedsDisplay:YES];
+    [statusItem_ popUpStatusItemMenu:[menuController menu]];
+    forceHighlight_ = NO;
+    [self setNeedsDisplay:YES];
+    return;
+  }
+
   if (menuController_ && ![menuController_ isMenuOpen]) {
     // Redraw the dray icon to show highlight if it is enabled.
     [self setNeedsDisplay:YES];
@@ -288,6 +303,8 @@ const CGFloat kVerticalTitleMargin = 2;
 }
 
 - (BOOL)shouldHighlight {
+  if (isHighlightEnable_ && forceHighlight_)
+    return true;
   BOOL isMenuOpen = menuController_ && [menuController_ isMenuOpen];
   return isHighlightEnable_ && (inMouseEventSequence_ || isMenuOpen);
 }
@@ -338,8 +355,9 @@ void TrayIconCocoa::SetHighlightMode(bool highlight) {
   [status_item_view_ setHighlight:highlight];
 }
 
-void TrayIconCocoa::PopUpContextMenu(const gfx::Point& pos) {
-  [status_item_view_ popUpContextMenu];
+void TrayIconCocoa::PopUpContextMenu(const gfx::Point& pos,
+                                     ui::SimpleMenuModel* menu_model) {
+  [status_item_view_ popUpContextMenu:menu_model];
 }
 
 void TrayIconCocoa::SetContextMenu(ui::SimpleMenuModel* menu_model) {

+ 13 - 11
atom/browser/ui/win/notify_icon.cc

@@ -13,6 +13,7 @@
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/screen.h"
 #include "ui/views/controls/menu/menu_runner.h"
 
 namespace atom {
@@ -45,8 +46,7 @@ NotifyIcon::~NotifyIcon() {
   Shell_NotifyIcon(NIM_DELETE, &icon_data);
 }
 
-void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos,
-                                  int modifiers,
+void NotifyIcon::HandleClickEvent(int modifiers,
                                   bool left_mouse_click,
                                   bool double_button_click) {
   NOTIFYICONIDENTIFIER icon_id;
@@ -66,7 +66,7 @@ void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos,
     return;
   } else if (!double_button_click) {  // single right click
     if (menu_model_)
-      PopUpContextMenu(cursor_pos);
+      PopUpContextMenu(gfx::Point(), menu_model_);
     else
       NotifyRightClicked(gfx::Rect(rect), modifiers);
   }
@@ -142,24 +142,26 @@ void NotifyIcon::DisplayBalloon(const gfx::Image& icon,
     LOG(WARNING) << "Unable to create status tray balloon.";
 }
 
-void NotifyIcon::PopUpContextMenu(const gfx::Point& pos) {
+void NotifyIcon::PopUpContextMenu(const gfx::Point& pos,
+                                  ui::SimpleMenuModel* menu_model) {
   // Returns if context menu isn't set.
-  if (!menu_model_)
+  if (!menu_model)
     return;
   // Set our window as the foreground window, so the context menu closes when
   // we click away from it.
   if (!SetForegroundWindow(window_))
     return;
 
+  // Show menu at mouse's position by default.
+  gfx::Rect rect(pos, gfx::Size());
+  if (pos.IsOrigin())
+    rect.set_origin(gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
+
   views::MenuRunner menu_runner(
-      menu_model_,
+      menu_model,
       views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS);
   ignore_result(menu_runner.RunMenuAt(
-      NULL,
-      NULL,
-      gfx::Rect(pos, gfx::Size()),
-      views::MENU_ANCHOR_TOPLEFT,
-      ui::MENU_SOURCE_MOUSE));
+      NULL, NULL, rect, views::MENU_ANCHOR_TOPLEFT, ui::MENU_SOURCE_MOUSE));
 }
 
 void NotifyIcon::SetContextMenu(ui::SimpleMenuModel* menu_model) {

+ 3 - 3
atom/browser/ui/win/notify_icon.h

@@ -33,8 +33,7 @@ class NotifyIcon : public TrayIcon {
   // Handles a click event from the user - if |left_button_click| is true and
   // there is a registered observer, passes the click event to the observer,
   // otherwise displays the context menu if there is one.
-  void HandleClickEvent(const gfx::Point& cursor_pos,
-                        int modifiers,
+  void HandleClickEvent(int modifiers,
                         bool left_button_click,
                         bool double_button_click);
 
@@ -52,7 +51,8 @@ class NotifyIcon : public TrayIcon {
   void DisplayBalloon(const gfx::Image& icon,
                       const base::string16& title,
                       const base::string16& contents) override;
-  void PopUpContextMenu(const gfx::Point& pos) override;
+  void PopUpContextMenu(const gfx::Point& pos,
+                        ui::SimpleMenuModel* menu_model) override;
   void SetContextMenu(ui::SimpleMenuModel* menu_model) override;
 
  private:

+ 0 - 4
atom/browser/ui/win/notify_icon_host.cc

@@ -15,7 +15,6 @@
 #include "base/win/win_util.h"
 #include "base/win/wrapped_window_proc.h"
 #include "ui/events/event_constants.h"
-#include "ui/gfx/screen.h"
 #include "ui/gfx/win/hwnd_util.h"
 
 namespace atom {
@@ -172,10 +171,7 @@ LRESULT CALLBACK NotifyIconHost::WndProc(HWND hwnd,
       case WM_CONTEXTMENU:
         // Walk our icons, find which one was clicked on, and invoke its
         // HandleClickEvent() method.
-        gfx::Point cursor_pos(
-            gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
         win_icon->HandleClickEvent(
-            cursor_pos,
             GetKeyboardModifers(),
             (lparam == WM_LBUTTONDOWN || lparam == WM_LBUTTONDBLCLK),
             (lparam == WM_LBUTTONDBLCLK || lparam == WM_RBUTTONDBLCLK));

+ 6 - 2
docs/api/tray.md

@@ -187,12 +187,16 @@ when the tray icon is clicked. Defaults to true.
 
 Displays a tray balloon.
 
-### `Tray.popUpContextMenu([position])` _OS X_ _Windows_
+### `Tray.popUpContextMenu([menu, position])` _OS X_ _Windows_
 
-* `position` Object (optional)- The pop up position.
+* `menu` Menu (optional)
+* `position` Object (optional) - The pop up position.
   * `x` Integer
   * `y` Integer
 
+Popups the context menu of tray icon. When `menu` is passed, the `menu` will
+showed instead of the tray's context menu.
+
 The `position` is only available on Windows, and it is (0, 0) by default.
 
 ### `Tray.setContextMenu(menu)`