Commit 751df8e3 authored by xrenishere@gmail.com's avatar xrenishere@gmail.com

Fix BaseBubbleController close issue.

  A bubble should disappear when we right mouse click on a blank
  space. Add event monitor for NSRightMouseDownMask, and change
  not to use performSelector, for sometimes when  rightmouse  down
  happens, a menu comes out. This menu  might be a Modal Dialogue Box.
  So we can't perform the windowDidResignKey until the menu is  closed.

  BUG=378186
  TEST="--gtest_filter=BaseBubbleControllerTest.*"
  R=rsesek@chromium.org

Review URL: https://codereview.chromium.org/300113009

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@276875 0039d316-1c4b-4281-b951-d872f2087c98
parent 448b17f5
...@@ -241,14 +241,16 @@ ...@@ -241,14 +241,16 @@
// The eventTap_ catches clicks within the application that are outside the // The eventTap_ catches clicks within the application that are outside the
// window. // window.
eventTap_ = [NSEvent eventTap_ = [NSEvent
addLocalMonitorForEventsMatchingMask:NSLeftMouseDownMask addLocalMonitorForEventsMatchingMask:NSLeftMouseDownMask |
NSRightMouseDownMask
handler:^NSEvent* (NSEvent* event) { handler:^NSEvent* (NSEvent* event) {
if (event.window != window) { if (event.window != window) {
// Call via the runloop because this block is called in the // Do it right now, because if this event is right mouse event,
// middle of event dispatch. // it may pop up a menu. windowDidResignKey: will not run until
[self performSelector:@selector(windowDidResignKey:) // the menu is closed.
withObject:note if ([self respondsToSelector:@selector(windowDidResignKey:)]) {
afterDelay:0]; [self windowDidResignKey:note];
}
} }
return event; return event;
}]; }];
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#import "base/mac/scoped_nsobject.h" #import "base/mac/scoped_nsobject.h"
#import "chrome/browser/ui/cocoa/cocoa_test_helper.h" #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
#import "chrome/browser/ui/cocoa/info_bubble_view.h" #import "chrome/browser/ui/cocoa/info_bubble_view.h"
#import "chrome/browser/ui/cocoa/run_loop_testing.h"
#import "ui/events/test/cocoa_test_event_utils.h" #import "ui/events/test/cocoa_test_event_utils.h"
namespace { namespace {
...@@ -18,6 +17,72 @@ const CGFloat kAnchorPointX = 400; ...@@ -18,6 +17,72 @@ const CGFloat kAnchorPointX = 400;
const CGFloat kAnchorPointY = 300; const CGFloat kAnchorPointY = 300;
} // namespace } // namespace
@interface ContextMenuController : NSObject<NSMenuDelegate> {
@private
NSMenu* menu_;
NSWindow* window_;
BOOL isMenuOpen_;
BOOL didOpen_;
}
- (id)initWithMenu:(NSMenu*)menu andWindow:(NSWindow*)window;
- (BOOL)isMenuOpen;
- (BOOL)didOpen;
- (BOOL)isWindowVisible;
// NSMenuDelegate methods
- (void)menuWillOpen:(NSMenu*)menu;
- (void)menuDidClose:(NSMenu*)menu;
@end
@implementation ContextMenuController
- (id)initWithMenu:(NSMenu*)menu andWindow:(NSWindow*)window {
if (self = [super init]) {
menu_ = menu;
window_ = window;
isMenuOpen_ = NO;
didOpen_ = NO;
[menu_ setDelegate:self];
}
return self;
}
- (BOOL)isMenuOpen {
return isMenuOpen_;
}
- (BOOL)didOpen {
return didOpen_;
}
- (BOOL)isWindowVisible {
if (window_) {
return [window_ isVisible];
}
return NO;
}
- (void)menuWillOpen:(NSMenu*)menu {
isMenuOpen_ = YES;
didOpen_ = NO;
NSArray* modes = @[NSEventTrackingRunLoopMode, NSDefaultRunLoopMode];
[menu_ performSelector:@selector(cancelTracking)
withObject:nil
afterDelay:0.1
inModes:modes];
}
- (void)menuDidClose:(NSMenu*)menu {
isMenuOpen_ = NO;
didOpen_ = YES;
}
@end
class BaseBubbleControllerTest : public CocoaTest { class BaseBubbleControllerTest : public CocoaTest {
public: public:
virtual void SetUp() OVERRIDE { virtual void SetUp() OVERRIDE {
...@@ -174,7 +239,7 @@ TEST_F(BaseBubbleControllerTest, ResignKeyCloses) { ...@@ -174,7 +239,7 @@ TEST_F(BaseBubbleControllerTest, ResignKeyCloses) {
// Test that clicking outside the window causes the bubble to close if // Test that clicking outside the window causes the bubble to close if
// shouldCloseOnResignKey is YES. // shouldCloseOnResignKey is YES.
TEST_F(BaseBubbleControllerTest, LionClickOutsideCloses) { TEST_F(BaseBubbleControllerTest, LionClickOutsideClosesWithoutContextMenu) {
// The event tap is only installed on 10.7+. // The event tap is only installed on 10.7+.
if (!base::mac::IsOSLionOrLater()) if (!base::mac::IsOSLionOrLater())
return; return;
...@@ -194,7 +259,12 @@ TEST_F(BaseBubbleControllerTest, LionClickOutsideCloses) { ...@@ -194,7 +259,12 @@ TEST_F(BaseBubbleControllerTest, LionClickOutsideCloses) {
NSEvent* event = cocoa_test_event_utils::LeftMouseDownAtPointInWindow( NSEvent* event = cocoa_test_event_utils::LeftMouseDownAtPointInWindow(
NSMakePoint(10, 10), test_window()); NSMakePoint(10, 10), test_window());
[NSApp sendEvent:event]; [NSApp sendEvent:event];
chrome::testing::NSRunLoopRunAllPending();
EXPECT_TRUE([window isVisible]);
event = cocoa_test_event_utils::RightMouseDownAtPointInWindow(
NSMakePoint(10, 10), test_window());
[NSApp sendEvent:event];
EXPECT_TRUE([window isVisible]); EXPECT_TRUE([window isVisible]);
...@@ -202,7 +272,70 @@ TEST_F(BaseBubbleControllerTest, LionClickOutsideCloses) { ...@@ -202,7 +272,70 @@ TEST_F(BaseBubbleControllerTest, LionClickOutsideCloses) {
event = cocoa_test_event_utils::LeftMouseDownAtPointInWindow( event = cocoa_test_event_utils::LeftMouseDownAtPointInWindow(
NSMakePoint(10, 10), test_window()); NSMakePoint(10, 10), test_window());
[NSApp sendEvent:event]; [NSApp sendEvent:event];
chrome::testing::NSRunLoopRunAllPending();
EXPECT_FALSE([window isVisible]); EXPECT_FALSE([window isVisible]);
[controller_ showWindow:nil]; // Show it again
EXPECT_TRUE([window isVisible]);
EXPECT_TRUE([controller_ shouldCloseOnResignKey]); // Verify.
event = cocoa_test_event_utils::RightMouseDownAtPointInWindow(
NSMakePoint(10, 10), test_window());
[NSApp sendEvent:event];
EXPECT_FALSE([window isVisible]);
}
// Test that right-clicking the window with displaying a context menu causes
// the bubble to close.
TEST_F(BaseBubbleControllerTest, LionRightClickOutsideClosesWithContextMenu) {
// The event tap is only installed on 10.7+.
if (!base::mac::IsOSLionOrLater())
return;
// Closing the bubble will autorelease the controller.
base::scoped_nsobject<BaseBubbleController> keep_alive([controller_ retain]);
NSWindow* window = [controller_ window];
EXPECT_TRUE([controller_ shouldCloseOnResignKey]); // Verify default value.
EXPECT_FALSE([window isVisible]);
[controller_ showWindow:nil];
EXPECT_TRUE([window isVisible]);
base::scoped_nsobject<NSMenu> context_menu(
[[NSMenu alloc] initWithTitle:@""]);
[context_menu addItemWithTitle:@"ContextMenuTest"
action:nil
keyEquivalent:@""];
base::scoped_nsobject<ContextMenuController> menu_controller(
[[ContextMenuController alloc] initWithMenu:context_menu
andWindow:window]);
// Set the menu as the contextual menu of contentView of test_window().
[[test_window() contentView] setMenu:context_menu];
// RightMouseDown in test_window() would close the bubble window and then
// dispaly the contextual menu.
NSEvent* event = cocoa_test_event_utils::RightMouseDownAtPointInWindow(
NSMakePoint(10, 10), test_window());
// Verify bubble's window is closed when contextual menu is open.
CFRunLoopPerformBlock(CFRunLoopGetCurrent(), NSEventTrackingRunLoopMode, ^{
EXPECT_TRUE([menu_controller isMenuOpen]);
EXPECT_FALSE([menu_controller isWindowVisible]);
});
EXPECT_FALSE([menu_controller isMenuOpen]);
EXPECT_FALSE([menu_controller didOpen]);
[NSApp sendEvent:event];
// When we got here, menu has already run its RunLoop.
// See -[ContextualMenuController menuWillOpen:].
EXPECT_FALSE([window isVisible]);
EXPECT_FALSE([menu_controller isMenuOpen]);
EXPECT_TRUE([menu_controller didOpen]);
} }
...@@ -36,6 +36,8 @@ NSEvent* MouseEventAtPoint(NSPoint point, NSEventType type, ...@@ -36,6 +36,8 @@ NSEvent* MouseEventAtPoint(NSPoint point, NSEventType type,
NSUInteger modifiers); NSUInteger modifiers);
NSEvent* LeftMouseDownAtPoint(NSPoint point); NSEvent* LeftMouseDownAtPoint(NSPoint point);
NSEvent* LeftMouseDownAtPointInWindow(NSPoint point, NSWindow* window); NSEvent* LeftMouseDownAtPointInWindow(NSPoint point, NSWindow* window);
NSEvent* RightMouseDownAtPoint(NSPoint point);
NSEvent* RightMouseDownAtPointInWindow(NSPoint point, NSWindow* window);
// Return a mouse down and an up event with the given |clickCount| at // Return a mouse down and an up event with the given |clickCount| at
// |view|'s midpoint. // |view|'s midpoint.
......
...@@ -67,6 +67,14 @@ static NSEvent* MouseEventAtPointInWindow(NSPoint point, ...@@ -67,6 +67,14 @@ static NSEvent* MouseEventAtPointInWindow(NSPoint point,
pressure:1.0]; pressure:1.0];
} }
NSEvent* RightMouseDownAtPointInWindow(NSPoint point, NSWindow* window) {
return MouseEventAtPointInWindow(point, NSRightMouseDown, window, 1);
}
NSEvent* RightMouseDownAtPoint(NSPoint point) {
return RightMouseDownAtPointInWindow(point, nil);
}
NSEvent* LeftMouseDownAtPointInWindow(NSPoint point, NSWindow* window) { NSEvent* LeftMouseDownAtPointInWindow(NSPoint point, NSWindow* window) {
return MouseEventAtPointInWindow(point, NSLeftMouseDown, window, 1); return MouseEventAtPointInWindow(point, NSLeftMouseDown, window, 1);
} }
......
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