Browse Source

Revert "fix: do not use CONTEXT_MENU flag for tray menu (#23880)" (#24078)

This reverts commit 26c6c8154030f053a38de9b367f16c742b6472ad.
Samuel Attard 4 years ago
parent
commit
3d6125894b
2 changed files with 40 additions and 6 deletions
  1. 30 5
      shell/browser/ui/win/notify_icon.cc
  2. 10 1
      shell/browser/ui/win/notify_icon.h

+ 30 - 5
shell/browser/ui/win/notify_icon.cc

@@ -18,6 +18,7 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/image/image.h"
 #include "ui/views/controls/menu/menu_runner.h"
+#include "ui/views/widget/widget.h"
 
 namespace {
 
@@ -48,7 +49,11 @@ NotifyIcon::NotifyIcon(NotifyIconHost* host,
                        HWND window,
                        UINT message,
                        GUID guid)
-    : host_(host), icon_id_(id), window_(window), message_id_(message) {
+    : host_(host),
+      icon_id_(id),
+      window_(window),
+      message_id_(message),
+      weak_factory_(this) {
   guid_ = guid;
   is_using_guid_ = guid != GUID_DEFAULT;
   NOTIFYICONDATA icon_data;
@@ -208,10 +213,26 @@ void NotifyIcon::PopUpContextMenu(const gfx::Point& pos,
   if (pos.IsOrigin())
     rect.set_origin(display::Screen::GetScreen()->GetCursorScreenPoint());
 
-  menu_runner_.reset(
-      new views::MenuRunner(menu_model != nullptr ? menu_model : menu_model_,
-                            views::MenuRunner::HAS_MNEMONICS));
-  menu_runner_->RunMenuAt(nullptr, nullptr, rect,
+  // Create a widget for the menu, otherwise we get no keyboard events, which
+  // is required for accessibility.
+  widget_.reset(new views::Widget());
+  views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
+  params.ownership =
+      views::Widget::InitParams::Ownership::WIDGET_OWNS_NATIVE_WIDGET;
+  params.bounds = gfx::Rect(0, 0, 0, 0);
+  params.force_software_compositing = true;
+  params.z_order = ui::ZOrderLevel::kFloatingUIElement;
+
+  widget_->Init(std::move(params));
+
+  widget_->Show();
+  widget_->Activate();
+  menu_runner_.reset(new views::MenuRunner(
+      menu_model != nullptr ? menu_model : menu_model_,
+      views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS,
+      base::BindRepeating(&NotifyIcon::OnContextMenuClosed,
+                          weak_factory_.GetWeakPtr())));
+  menu_runner_->RunMenuAt(widget_.get(), NULL, rect,
                           views::MenuAnchorPosition::kTopLeft,
                           ui::MENU_SOURCE_MOUSE);
 }
@@ -252,4 +273,8 @@ void NotifyIcon::InitIconData(NOTIFYICONDATA* icon_data) {
   }
 }
 
+void NotifyIcon::OnContextMenuClosed() {
+  widget_->Close();
+}
+
 }  // namespace electron

+ 10 - 1
shell/browser/ui/win/notify_icon.h

@@ -14,6 +14,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "base/win/scoped_gdi_object.h"
 #include "shell/browser/ui/tray_icon.h"
 #include "shell/browser/ui/win/notify_icon_host.h"
@@ -24,7 +25,8 @@ class Point;
 
 namespace views {
 class MenuRunner;
-}
+class Widget;
+}  // namespace views
 
 namespace electron {
 
@@ -73,6 +75,7 @@ class NotifyIcon : public TrayIcon {
 
  private:
   void InitIconData(NOTIFYICONDATA* icon_data);
+  void OnContextMenuClosed();
 
   // The tray that owns us.  Weak.
   NotifyIconHost* host_;
@@ -101,6 +104,12 @@ class NotifyIcon : public TrayIcon {
   // Context menu associated with this icon (if any).
   std::unique_ptr<views::MenuRunner> menu_runner_;
 
+  // Temporary widget for the context menu, needed for keyboard event capture.
+  std::unique_ptr<views::Widget> widget_;
+
+  // WeakPtrFactory for CloseClosure safety.
+  base::WeakPtrFactory<NotifyIcon> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(NotifyIcon);
 };