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() {
container->AddChildView(dummy_focusable_view_);
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_ =
std::make_unique<ui::test::EventGenerator>(GetRootWindow(widget_));
event_generator_->set_target(ui::test::EventGenerator::Target::WINDOW);
......
......@@ -13,20 +13,25 @@
namespace views {
// This class executes a callback when a native menu begins tracking. With
// native menus, each one automatically closes when a new one begins tracking.
// This allows Views menus to tie into this behavior.
// This class executes a callback when a native menu begins tracking, or when a
// new window takes focus. With native menus, each one automatically closes when
// 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 {
public:
explicit MenuCocoaWatcherMac(base::OnceClosure callback);
~MenuCocoaWatcherMac();
private:
void ExecuteCallback();
// The closure to call when the notification comes in.
base::OnceClosure callback_;
// The token representing the notification observer.
id observer_token_;
// Tokens representing the notification observers.
id observer_token_other_menu_;
id observer_token_new_window_focus_;
DISALLOW_COPY_AND_ASSIGN(MenuCocoaWatcherMac);
};
......
......@@ -5,6 +5,7 @@
#include "ui/views/controls/menu/menu_cocoa_watcher_mac.h"
#import <Cocoa/Cocoa.h>
#include <dispatch/dispatch.h>
#import <utility>
......@@ -12,17 +13,36 @@ namespace views {
MenuCocoaWatcherMac::MenuCocoaWatcherMac(base::OnceClosure callback)
: callback_(std::move(callback)) {
observer_token_ = [[NSNotificationCenter defaultCenter]
observer_token_other_menu_ = [[NSNotificationCenter defaultCenter]
addObserverForName:NSMenuDidBeginTrackingNotification
object:[NSApp mainMenu]
queue:nil
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() {
[[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
......@@ -475,7 +475,7 @@ void MenuController::Run(Widget* parent,
#if defined(OS_MACOSX)
menu_cocoa_watcher_ = std::make_unique<MenuCocoaWatcherMac>(base::BindOnce(
&MenuController::Cancel, base::Unretained(this), ExitType::kAll));
&MenuController::Cancel, this->AsWeakPtr(), ExitType::kAll));
#endif
// 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