Commit 7fbc70e4 authored by Avi Drissman's avatar Avi Drissman Committed by Commit Bot

Mac: close Views menus when windows take focus.

This matches Aura behavior. In addition, native Mac menus take key focus
so this matches platform behavior better, too.

BUG=986247
TEST=as in bug

Change-Id: I92dc11c73d390f348b087aaaa8dd3b15e62b86b2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1718453Reviewed-by: default avatarLeonard Grey <lgrey@chromium.org>
Commit-Queue: Avi Drissman <avi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#682299}
parent 51e04c22
...@@ -193,6 +193,18 @@ void EditableComboboxTest::InitWidget() { ...@@ -193,6 +193,18 @@ void EditableComboboxTest::InitWidget() {
container->AddChildView(dummy_focusable_view_); container->AddChildView(dummy_focusable_view_);
widget_->Show(); widget_->Show();
#if defined(OS_MACOSX)
// The event loop needs to be flushed here, otherwise in various tests:
// 1. The actual showing of the native window backing the widget gets delayed
// until a spin of the event loop.
// 2. The combobox menu object is triggered, and it starts listening for the
// "window did become key" notification as a sign that it lost focus and
// should close.
// 3. The event loop is spun, and the actual showing of the native window
// triggers the close of the menu opened from within the window.
base::RunLoop().RunUntilIdle();
#endif
event_generator_ = event_generator_ =
std::make_unique<ui::test::EventGenerator>(GetRootWindow(widget_)); std::make_unique<ui::test::EventGenerator>(GetRootWindow(widget_));
event_generator_->set_target(ui::test::EventGenerator::Target::WINDOW); event_generator_->set_target(ui::test::EventGenerator::Target::WINDOW);
......
...@@ -13,20 +13,25 @@ ...@@ -13,20 +13,25 @@
namespace views { namespace views {
// This class executes a callback when a native menu begins tracking. With // This class executes a callback when a native menu begins tracking, or when a
// native menus, each one automatically closes when a new one begins tracking. // new window takes focus. With native menus, each one automatically closes when
// This allows Views menus to tie into this behavior. // a new one begins tracking, and MenuPreTargetHandlerAura::OnWindowActivated()
// closes menus when new windows take focus. This allows Views menus to have the
// correct behavior.
class VIEWS_EXPORT MenuCocoaWatcherMac { class VIEWS_EXPORT MenuCocoaWatcherMac {
public: public:
explicit MenuCocoaWatcherMac(base::OnceClosure callback); explicit MenuCocoaWatcherMac(base::OnceClosure callback);
~MenuCocoaWatcherMac(); ~MenuCocoaWatcherMac();
private: private:
void ExecuteCallback();
// The closure to call when the notification comes in. // The closure to call when the notification comes in.
base::OnceClosure callback_; base::OnceClosure callback_;
// The token representing the notification observer. // Tokens representing the notification observers.
id observer_token_; id observer_token_other_menu_;
id observer_token_new_window_focus_;
DISALLOW_COPY_AND_ASSIGN(MenuCocoaWatcherMac); DISALLOW_COPY_AND_ASSIGN(MenuCocoaWatcherMac);
}; };
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "ui/views/controls/menu/menu_cocoa_watcher_mac.h" #include "ui/views/controls/menu/menu_cocoa_watcher_mac.h"
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#include <dispatch/dispatch.h>
#import <utility> #import <utility>
...@@ -12,17 +13,36 @@ namespace views { ...@@ -12,17 +13,36 @@ namespace views {
MenuCocoaWatcherMac::MenuCocoaWatcherMac(base::OnceClosure callback) MenuCocoaWatcherMac::MenuCocoaWatcherMac(base::OnceClosure callback)
: callback_(std::move(callback)) { : callback_(std::move(callback)) {
observer_token_ = [[NSNotificationCenter defaultCenter] observer_token_other_menu_ = [[NSNotificationCenter defaultCenter]
addObserverForName:NSMenuDidBeginTrackingNotification addObserverForName:NSMenuDidBeginTrackingNotification
object:[NSApp mainMenu] object:[NSApp mainMenu]
queue:nil queue:nil
usingBlock:^(NSNotification* notification) { usingBlock:^(NSNotification* notification) {
std::move(this->callback_).Run(); ExecuteCallback();
}];
observer_token_new_window_focus_ = [[NSNotificationCenter defaultCenter]
addObserverForName:NSWindowDidBecomeKeyNotification
object:nil
queue:nil
usingBlock:^(NSNotification* notification) {
ExecuteCallback();
}]; }];
} }
MenuCocoaWatcherMac::~MenuCocoaWatcherMac() { MenuCocoaWatcherMac::~MenuCocoaWatcherMac() {
[[NSNotificationCenter defaultCenter] removeObserver:observer_token_]; [[NSNotificationCenter defaultCenter]
removeObserver:observer_token_other_menu_];
[[NSNotificationCenter defaultCenter]
removeObserver:observer_token_new_window_focus_];
}
void MenuCocoaWatcherMac::ExecuteCallback() {
__block base::OnceClosure callback = std::move(callback_);
dispatch_async(dispatch_get_main_queue(), ^{
if (callback) {
std::move(callback).Run();
}
});
} }
} // namespace views } // namespace views
...@@ -475,7 +475,7 @@ void MenuController::Run(Widget* parent, ...@@ -475,7 +475,7 @@ void MenuController::Run(Widget* parent,
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
menu_cocoa_watcher_ = std::make_unique<MenuCocoaWatcherMac>(base::BindOnce( menu_cocoa_watcher_ = std::make_unique<MenuCocoaWatcherMac>(base::BindOnce(
&MenuController::Cancel, base::Unretained(this), ExitType::kAll)); &MenuController::Cancel, this->AsWeakPtr(), ExitType::kAll));
#endif #endif
// Reset current state. // Reset current state.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment