diff options
author | shinyak@google.com <shinyak@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-23 07:45:11 +0000 |
---|---|---|
committer | shinyak@google.com <shinyak@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-23 07:45:11 +0000 |
commit | f55962f2f0cf52a6a878d0bc574c5975d646d265 (patch) | |
tree | 4ab23c675e5d71bf59acf74624f09880f66fc0d6 | |
parent | 334749a11083fc523b9abab456ecca2072cd2055 (diff) | |
download | chromium_src-f55962f2f0cf52a6a878d0bc574c5975d646d265.zip chromium_src-f55962f2f0cf52a6a878d0bc574c5975d646d265.tar.gz chromium_src-f55962f2f0cf52a6a878d0bc574c5975d646d265.tar.bz2 |
Added right click handler to back/forward button on Mac Chromium.
BUG=62620
TEST=Right click on the back/forward button in the toolbar and investigate that a menu is shown.
Review URL: http://codereview.chromium.org/7104020
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@93793 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/ui/cocoa/menu_button.h | 4 | ||||
-rw-r--r-- | chrome/browser/ui/cocoa/menu_button.mm | 16 | ||||
-rw-r--r-- | chrome/browser/ui/cocoa/menu_button_unittest.mm | 71 | ||||
-rw-r--r-- | chrome/browser/ui/cocoa/toolbar/toolbar_button.h | 5 | ||||
-rw-r--r-- | chrome/browser/ui/cocoa/toolbar/toolbar_button.mm | 77 | ||||
-rw-r--r-- | chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm | 54 | ||||
-rw-r--r-- | chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm | 3 |
7 files changed, 143 insertions, 87 deletions
diff --git a/chrome/browser/ui/cocoa/menu_button.h b/chrome/browser/ui/cocoa/menu_button.h index cca74ab..bc12be8 100644 --- a/chrome/browser/ui/cocoa/menu_button.h +++ b/chrome/browser/ui/cocoa/menu_button.h @@ -28,6 +28,7 @@ scoped_nsobject<NSMenu> attachedMenu_; BOOL attachedMenuEnabled_; BOOL openMenuOnClick_; + BOOL openMenuOnRightClick_; scoped_nsobject<NSPopUpButtonCell> popUpCell_; } @@ -43,6 +44,9 @@ // menu will only be opened when clicked and held. @property(assign, nonatomic) BOOL openMenuOnClick; +// Whether or not to open the menu when the right button is clicked. +@property(assign, nonatomic) BOOL openMenuOnRightClick; + // Returns the rectangle that menus are anchored at. Can be overridden by // subclasses, returns -bounds by default. - (NSRect)menuRect; diff --git a/chrome/browser/ui/cocoa/menu_button.mm b/chrome/browser/ui/cocoa/menu_button.mm index 92b4c49..8cc0812 100644 --- a/chrome/browser/ui/cocoa/menu_button.mm +++ b/chrome/browser/ui/cocoa/menu_button.mm @@ -18,6 +18,7 @@ @implementation MenuButton @synthesize openMenuOnClick = openMenuOnClick_; +@synthesize openMenuOnRightClick = openMenuOnRightClick_; // Overrides: @@ -57,6 +58,15 @@ [self configureCell]; } +- (void)rightMouseDown:(NSEvent*)theEvent { + if (!openMenuOnRightClick_) { + [super rightMouseDown:theEvent]; + return; + } + + [self clickShowMenu:self]; +} + // Accessors and mutators: - (NSMenu*)attachedMenu { @@ -79,6 +89,10 @@ } } +- (void)setOpenMenuOnRightClick:(BOOL)enabled { + openMenuOnRightClick_ = enabled; +} + - (NSRect)menuRect { return [self bounds]; } @@ -155,7 +169,7 @@ - (void)clickShowMenu:(id)sender { // This should only be called if openMenuOnClick has been set (which hooks // up this target-action). - DCHECK(openMenuOnClick_); + DCHECK(openMenuOnClick_ || openMenuOnRightClick_); [self showMenu:NO]; } diff --git a/chrome/browser/ui/cocoa/menu_button_unittest.mm b/chrome/browser/ui/cocoa/menu_button_unittest.mm index 98a03e9..be8a3e4 100644 --- a/chrome/browser/ui/cocoa/menu_button_unittest.mm +++ b/chrome/browser/ui/cocoa/menu_button_unittest.mm @@ -79,6 +79,23 @@ class MenuButtonTest : public CocoaTest { return menu; } + NSEvent* MouseDownEvent(NSEventType eventType) { + NSPoint location; + location.x = location.y = 0; + NSGraphicsContext* context = [NSGraphicsContext currentContext]; + NSEvent* event = [NSEvent mouseEventWithType:eventType + location:location + modifierFlags:0 + timestamp:0 + windowNumber:0 + context:context + eventNumber:0 + clickCount:1 + pressure:0.0F]; + + return event; + } + MenuButton* button_; }; @@ -115,4 +132,58 @@ TEST_F(MenuButtonTest, OpenOnClick) { EXPECT_FALSE([delegate isOpen]); } +TEST_F(MenuButtonTest, OpenOnRightClick) { + scoped_nsobject<NSMenu> menu(CreateMenu()); + ASSERT_TRUE(menu.get()); + + scoped_nsobject<MenuButtonTestDelegate> delegate( + [[MenuButtonTestDelegate alloc] initWithMenu:menu.get()]); + ASSERT_TRUE(delegate.get()); + + [menu setDelegate:delegate.get()]; + [button_ setAttachedMenu:menu]; + [button_ setOpenMenuOnClick:YES]; + // Right click is enabled. + [button_ setOpenMenuOnRightClick:YES]; + + EXPECT_FALSE([delegate isOpen]); + EXPECT_FALSE([delegate didOpen]); + + // Should open the menu. + NSEvent* event = MouseDownEvent(NSRightMouseDown); + [button_ rightMouseDown:event]; + + EXPECT_TRUE([delegate didOpen]); + EXPECT_FALSE([delegate isOpen]); +} + +TEST_F(MenuButtonTest, DontOpenOnRightClickWithoutSetRightClick) { + scoped_nsobject<NSMenu> menu(CreateMenu()); + ASSERT_TRUE(menu.get()); + + scoped_nsobject<MenuButtonTestDelegate> delegate( + [[MenuButtonTestDelegate alloc] initWithMenu:menu.get()]); + ASSERT_TRUE(delegate.get()); + + [menu setDelegate:delegate.get()]; + [button_ setAttachedMenu:menu]; + [button_ setOpenMenuOnClick:YES]; + + EXPECT_FALSE([delegate isOpen]); + EXPECT_FALSE([delegate didOpen]); + + // Should not open the menu. + NSEvent* event = MouseDownEvent(NSRightMouseDown); + [button_ rightMouseDown:event]; + + EXPECT_FALSE([delegate didOpen]); + EXPECT_FALSE([delegate isOpen]); + + // Should open the menu in this case. + [button_ performClick:nil]; + + EXPECT_TRUE([delegate didOpen]); + EXPECT_FALSE([delegate isOpen]); +} + } // namespace diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_button.h b/chrome/browser/ui/cocoa/toolbar/toolbar_button.h index c35d1e5..3a7f1b6 100644 --- a/chrome/browser/ui/cocoa/toolbar/toolbar_button.h +++ b/chrome/browser/ui/cocoa/toolbar/toolbar_button.h @@ -14,11 +14,6 @@ @protected // YES when middle mouse clicks should be handled. BOOL handleMiddleClick_; - - // YES when a middle mouse click is being handled. This is set to YES by an - // NSOtherMouseDown event, and NO by an NSOtherMouseUp event. While this is - // YES, other mouse button events should be ignored. - BOOL handlingMiddleClick_; } // Whether or not to handle the mouse middle click events. diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_button.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_button.mm index 517e6e5..afc3483 100644 --- a/chrome/browser/ui/cocoa/toolbar/toolbar_button.mm +++ b/chrome/browser/ui/cocoa/toolbar/toolbar_button.mm @@ -4,63 +4,42 @@ #import "chrome/browser/ui/cocoa/toolbar/toolbar_button.h" -@interface ToolbarButton (Private) -- (BOOL)updateStatus:(NSEvent*)theEvent; -@end - @implementation ToolbarButton @synthesize handleMiddleClick = handleMiddleClick_; -- (void)mouseDown:(NSEvent*)theEvent { - if (!handlingMiddleClick_) - [super mouseDown:theEvent]; -} - -- (void)mouseDragged:(NSEvent*)theEvent { - if (!handlingMiddleClick_) - [super mouseDragged:theEvent]; -} - -- (void)mouseUp:(NSEvent*)theEvent { - if (!handlingMiddleClick_) - [super mouseUp:theEvent]; -} - - (void)otherMouseDown:(NSEvent*)theEvent { - if (![self shouldHandleEvent:theEvent]) + if (![self shouldHandleEvent:theEvent]) { [super otherMouseDown:theEvent]; - else - handlingMiddleClick_ = [self updateStatus:theEvent]; -} - -- (void)otherMouseDragged:(NSEvent*)theEvent { - if (!handlingMiddleClick_ || ![self shouldHandleEvent:theEvent]) - [super otherMouseDragged:theEvent]; - else - [self updateStatus:theEvent]; -} - -- (void)otherMouseUp:(NSEvent*)theEvent { - if (!handlingMiddleClick_ || ![self shouldHandleEvent:theEvent]) { - [super otherMouseUp:theEvent]; - } else { - if ([self state] == NSOnState) - [self sendAction:[self action] to:[self target]]; - - [self setState:NSOffState]; - [self highlight:NO]; - handlingMiddleClick_ = NO; + return; } -} -- (BOOL)updateStatus:(NSEvent*)theEvent { - NSPoint mouseLoc = [self convertPoint:[theEvent locationInWindow] - fromView:nil]; - BOOL isInside = [self mouse:mouseLoc inRect:[self bounds]]; - [self setState:isInside ? NSOnState : NSOffState]; - [self highlight:isInside]; - return isInside; + NSEvent* nextEvent = theEvent; + BOOL isInside; + + // Loop until middle button is released. Also, the mouse cursor is outside of + // the button, the button should not be highlighted. + do { + NSPoint mouseLoc = [self convertPoint:[nextEvent locationInWindow] + fromView:nil]; + isInside = [self mouse:mouseLoc inRect:[self bounds]]; + [self highlight:isInside]; + [self setState:isInside ? NSOnState : NSOffState]; + + NSUInteger mask = NSOtherMouseDraggedMask | NSOtherMouseUpMask; + nextEvent = [[self window] nextEventMatchingMask:mask]; + } while (!([nextEvent buttonNumber] == 2 && + [nextEvent type] == NSOtherMouseUp)); + + // Discard the events before the middle button up event. + // If we don't discard it, the events will be re-processed later. + [[self window] discardEventsMatchingMask:NSAnyEventMask + beforeEvent:nextEvent]; + + [self highlight:NO]; + [self setState:NSOffState]; + if (isInside) + [self sendAction:[self action] to:[self target]]; } - (BOOL)shouldHandleEvent:(NSEvent*)theEvent { diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm index 3322267..b7907a3 100644 --- a/chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm +++ b/chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm @@ -213,9 +213,9 @@ TEST_F(ToolbarButtonTest, MouseClickInsideOnYES) { [button_ setHandleMiddleClick:YES]; // Middle button clicking in the view. + [NSApp postEvent:other_up_in_view atStart:YES]; [button_ otherMouseDown:other_down_in_view]; - EXPECT_EQ(NSOnState, [button_ state]); - [button_ otherMouseUp:other_up_in_view]; + EXPECT_EQ(NSOffState, [button_ state]); EXPECT_EQ(1, [button_ numOfClick]); EXPECT_EQ(IDC_HOME, [button_ lastCommand]); @@ -226,9 +226,9 @@ TEST_F(ToolbarButtonTest, MouseClickOutsideOnYES) { [button_ setHandleMiddleClick:YES]; // Middle button clicking outside of the view. + [NSApp postEvent:other_up_out_view atStart:YES]; [button_ otherMouseDown:other_down_out_view]; - EXPECT_EQ(NSOffState, [button_ state]); - [button_ otherMouseUp:other_up_out_view]; + EXPECT_EQ(NSOffState, [button_ state]); EXPECT_EQ(0, [button_ numOfClick]); EXPECT_EQ(IDC_STOP, [button_ lastCommand]); @@ -239,45 +239,36 @@ TEST_F(ToolbarButtonTest, MouseDraggingOnYES) { [button_ setHandleMiddleClick:YES]; // Middle button being down in the view and up outside of the view. + [NSApp postEvent:other_up_out_view atStart:YES]; + [NSApp postEvent:other_dragged_out_view atStart:YES]; [button_ otherMouseDown:other_down_in_view]; - EXPECT_EQ(NSOnState, [button_ state]); - [button_ otherMouseDragged:other_dragged_out_view]; - EXPECT_EQ(NSOffState, [button_ state]); - [button_ otherMouseUp:other_up_out_view]; + EXPECT_EQ(NSOffState, [button_ state]); EXPECT_EQ(0, [button_ numOfClick]); EXPECT_EQ(IDC_STOP, [button_ lastCommand]); // Middle button being down on the button, move to outside and move on it // again, then up on the button. + [NSApp postEvent:other_up_in_view atStart:YES]; + [NSApp postEvent:other_dragged_in_view atStart:YES]; + [NSApp postEvent:other_dragged_out_view atStart:YES]; [button_ otherMouseDown:other_down_in_view]; - EXPECT_EQ(NSOnState, [button_ state]); - [button_ otherMouseDragged:other_dragged_out_view]; - EXPECT_EQ(NSOffState, [button_ state]); - [button_ otherMouseDragged:other_dragged_in_view]; - EXPECT_EQ(NSOnState, [button_ state]); - [button_ otherMouseUp:other_up_in_view]; + EXPECT_EQ(NSOffState, [button_ state]); EXPECT_EQ(1, [button_ numOfClick]); EXPECT_EQ(IDC_HOME, [button_ lastCommand]); } -TEST_F(ToolbarButtonTest, DoesNotSwallowRightClickOnYES) { +TEST_F(ToolbarButtonTest, DoesSwallowRightClickOnYES) { // Enable middle button handling. [button_ setHandleMiddleClick:YES]; - // Middle button being down should swallow right button clicks, but - // ToolbarButton doesn't swallow it because it doesn't handle right button - // events. + // Middle button being down should swallow right button clicks. + [NSApp postEvent:other_up_in_view atStart:YES]; + [NSApp postEvent:right_up_in_view atStart:YES]; + [NSApp postEvent:right_down_in_view atStart:YES]; [button_ otherMouseDown:other_down_in_view]; - EXPECT_EQ(NSOnState, [button_ state]); - [button_ rightMouseDown:right_down_in_view]; - EXPECT_EQ(NSOnState, [button_ state]); - [button_ rightMouseUp:right_up_in_view]; - EXPECT_EQ(NSOnState, [button_ state]); - EXPECT_EQ(0, [button_ numOfClick]); - EXPECT_EQ(IDC_STOP, [button_ lastCommand]); - [button_ otherMouseUp:other_up_in_view]; + EXPECT_EQ(NSOffState, [button_ state]); EXPECT_EQ(1, [button_ numOfClick]); EXPECT_EQ(IDC_HOME, [button_ lastCommand]); @@ -288,13 +279,12 @@ TEST_F(ToolbarButtonTest, DoesSwallowLeftClickOnYES) { [button_ setHandleMiddleClick:YES]; // Middle button being down swallows left button clicks. - [button_ otherMouseDown:other_down_in_view]; - EXPECT_EQ(NSOnState, [button_ state]); + [NSApp postEvent:other_up_in_view atStart:YES]; [NSApp postEvent:left_up_in_view atStart:YES]; - [button_ mouseDown:left_down_in_view]; - EXPECT_EQ(0, [button_ numOfClick]); - EXPECT_EQ(IDC_STOP, [button_ lastCommand]); - [button_ otherMouseUp:other_up_in_view]; + [NSApp postEvent:left_down_in_view atStart:YES]; + [button_ otherMouseDown:other_down_in_view]; + + EXPECT_EQ(NSOffState, [button_ state]); EXPECT_EQ(1, [button_ numOfClick]); EXPECT_EQ(IDC_HOME, [button_ lastCommand]); } diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm index 7044bcc..4d3ee82 100644 --- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm +++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm @@ -265,6 +265,9 @@ class NotificationBridge : public NotificationObserver { [wrenchButton_ setOpenMenuOnClick:YES]; + [backButton_ setOpenMenuOnRightClick:YES]; + [forwardButton_ setOpenMenuOnRightClick:YES]; + [backButton_ setHandleMiddleClick:YES]; [forwardButton_ setHandleMiddleClick:YES]; [reloadButton_ setHandleMiddleClick:YES]; |