summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/ui')
-rw-r--r--chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm11
-rw-r--r--chrome/browser/ui/cocoa/profiles/avatar_button.h23
-rw-r--r--chrome/browser/ui/cocoa/profiles/avatar_button.mm48
-rw-r--r--chrome/browser/ui/cocoa/profiles/avatar_button_controller.mm33
-rw-r--r--chrome/browser/ui/cocoa/profiles/avatar_button_unittest.mm93
5 files changed, 190 insertions, 18 deletions
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm b/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm
index 66a424a..00cb1b3 100644
--- a/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm
+++ b/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm
@@ -33,6 +33,7 @@ const CGFloat kMenuXOffsetAdjust = 2.0;
@interface AvatarBaseController (Private)
// Shows the avatar bubble.
- (IBAction)buttonClicked:(id)sender;
+- (IBAction)buttonRightClicked:(id)sender;
- (void)bubbleWillClose:(NSNotification*)notif;
@@ -213,8 +214,14 @@ class ProfileInfoUpdateObserver : public ProfileInfoCacheObserver,
BrowserWindow::AvatarBubbleMode mode =
BrowserWindow::AVATAR_BUBBLE_MODE_DEFAULT;
- if ([NSEvent modifierFlags] & NSCommandKeyMask)
- mode = BrowserWindow::AVATAR_BUBBLE_MODE_FAST_USER_SWITCH;
+ [self showAvatarBubbleAnchoredAt:button_
+ withMode:mode
+ withServiceType:signin::GAIA_SERVICE_TYPE_NONE];
+}
+
+- (IBAction)buttonRightClicked:(id)sender {
+ BrowserWindow::AvatarBubbleMode mode =
+ BrowserWindow::AVATAR_BUBBLE_MODE_FAST_USER_SWITCH;
[self showAvatarBubbleAnchoredAt:button_
withMode:mode
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_button.h b/chrome/browser/ui/cocoa/profiles/avatar_button.h
new file mode 100644
index 0000000..444110d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/profiles/avatar_button.h
@@ -0,0 +1,23 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_COCOA_PROFILES_AVATAR_BUTTON_H_
+#define CHROME_BROWSER_UI_COCOA_PROFILES_AVATAR_BUTTON_H_
+
+#import <Cocoa/Cocoa.h>
+
+#import "ui/base/cocoa/hover_image_button.h"
+
+// A subclass of HoverImageButton that sends a target-action on right click.
+@interface AvatarButton : HoverImageButton {
+ @private
+ SEL rightAction_;
+}
+
+// Sets the action that will be called when this button is right clicked.
+- (void)setRightAction:(SEL)selector;
+
+@end
+
+#endif //CHROME_BROWSER_UI_COCOA_PROFILES_AVATAR_BUTTON_H_
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_button.mm b/chrome/browser/ui/cocoa/profiles/avatar_button.mm
new file mode 100644
index 0000000..a1d5c12
--- /dev/null
+++ b/chrome/browser/ui/cocoa/profiles/avatar_button.mm
@@ -0,0 +1,48 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "chrome/browser/ui/cocoa/profiles/avatar_button.h"
+
+@interface AvatarButton (Private)
+
+- (void)rightMouseDown:(NSEvent*)event;
+- (void)performRightClick;
+
+@end
+
+@implementation AvatarButton
+
+// Overrides -rightMouseDown and implements a custom mouse tracking loop.
+- (void)rightMouseDown:(NSEvent*)event {
+ NSEvent* nextEvent = event;
+ BOOL mouseInBounds = NO;
+ hoverState_ = kHoverStateMouseDown;
+
+ do {
+ nextEvent = [[self window]
+ nextEventMatchingMask:NSRightMouseDraggedMask |
+ NSRightMouseUpMask];
+
+ mouseInBounds = NSPointInRect(
+ [self convertPoint:[nextEvent locationInWindow] fromView:nil],
+ [self convertRect:[self frame] fromView:nil]);
+ } while (NSRightMouseUp != [nextEvent type]);
+
+ hoverState_ = kHoverStateNone;
+
+ if (mouseInBounds) {
+ hoverState_ = kHoverStateMouseOver;
+ [self performRightClick];
+ }
+}
+
+- (void)performRightClick {
+ [[super target] performSelector:rightAction_ withObject:self];
+}
+
+- (void)setRightAction:(SEL)selector {
+ rightAction_ = selector;
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_button_controller.mm b/chrome/browser/ui/cocoa/profiles/avatar_button_controller.mm
index 0ed4d4b..b5df7c7 100644
--- a/chrome/browser/ui/cocoa/profiles/avatar_button_controller.mm
+++ b/chrome/browser/ui/cocoa/profiles/avatar_button_controller.mm
@@ -14,11 +14,11 @@
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/profiles/avatar_button.h"
#include "chrome/grit/generated_resources.h"
#include "components/signin/core/browser/signin_error_controller.h"
#include "grit/theme_resources.h"
#import "ui/base/cocoa/appkit_utils.h"
-#import "ui/base/cocoa/hover_image_button.h"
#include "ui/base/l10n/l10n_util_mac.h"
#include "ui/base/nine_image_painter_factory.h"
#include "ui/base/resource/resource_bundle.h"
@@ -102,7 +102,7 @@ NSImage* GetImageFromResourceID(int resourceId) {
- (void)drawBezelWithFrame:(NSRect)frame
inView:(NSView*)controlView {
HoverState hoverState =
- [base::mac::ObjCCastStrict<HoverImageButton>(controlView) hoverState];
+ [base::mac::ObjCCastStrict<AvatarButton>(controlView) hoverState];
ui::NinePartImageIds imageIds = kNormalBorderImageIds;
if (isThemedWindow_)
imageIds = kThemedBorderImageIds;
@@ -146,28 +146,29 @@ NSImage* GetImageFromResourceID(int resourceId) {
ThemeServiceFactory::GetForProfile(browser->profile());
isThemedWindow_ = !themeService->UsingSystemTheme();
- HoverImageButton* hoverButton =
- [[HoverImageButton alloc] initWithFrame:NSZeroRect];
- button_.reset(hoverButton);
+ AvatarButton* avatarButton =
+ [[AvatarButton alloc] initWithFrame:NSZeroRect];
+ button_.reset(avatarButton);
base::scoped_nsobject<CustomThemeButtonCell> cell(
[[CustomThemeButtonCell alloc] initWithThemedWindow:isThemedWindow_]);
- [button_ setCell:cell.get()];
+ [avatarButton setCell:cell.get()];
// Check if the account already has an authentication error.
SigninErrorController* errorController =
profiles::GetSigninErrorController(browser->profile());
hasError_ = errorController && errorController->HasError();
- [button_ setWantsLayer:YES];
- [self setView:button_];
+ [avatarButton setWantsLayer:YES];
+ [self setView:avatarButton];
- [button_ setBezelStyle:NSShadowlessSquareBezelStyle];
- [button_ setButtonType:NSMomentaryChangeButton];
- [button_ setBordered:YES];
+ [avatarButton setBezelStyle:NSShadowlessSquareBezelStyle];
+ [avatarButton setButtonType:NSMomentaryChangeButton];
+ [avatarButton setBordered:YES];
- [button_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
- [button_ setTarget:self];
- [button_ setAction:@selector(buttonClicked:)];
+ [avatarButton setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
+ [avatarButton setTarget:self];
+ [avatarButton setAction:@selector(buttonClicked:)];
+ [avatarButton setRightAction:@selector(buttonRightClicked:)];
[self updateAvatarButtonAndLayoutParent:NO];
@@ -232,8 +233,8 @@ NSImage* GetImageFromResourceID(int resourceId) {
profiles::GetAvatarButtonTextForProfile(browser_->profile()));
[[button_ cell] setHasError:hasError_ withTitle:buttonTitle];
- HoverImageButton* button =
- base::mac::ObjCCastStrict<HoverImageButton>(button_);
+ AvatarButton* button =
+ base::mac::ObjCCastStrict<AvatarButton>(button_);
if (useGenericButton) {
[button setDefaultImage:GetImageFromResourceID(
IDR_AVATAR_MAC_BUTTON_AVATAR)];
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_button_unittest.mm b/chrome/browser/ui/cocoa/profiles/avatar_button_unittest.mm
new file mode 100644
index 0000000..cca632f
--- /dev/null
+++ b/chrome/browser/ui/cocoa/profiles/avatar_button_unittest.mm
@@ -0,0 +1,93 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "chrome/browser/ui/cocoa/profiles/avatar_button.h"
+
+#import "base/mac/scoped_nsobject.h"
+#import "ui/events/test/cocoa_test_event_utils.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
+
+@interface AvatarButton (ExposedForTesting)
+- (void)performRightClick;
+@end
+
+@interface AvatarButtonTestObserver : NSObject
+@property BOOL clicked;
+
+- (void)buttonRightClicked;
+@end
+
+@implementation AvatarButtonTestObserver
+@synthesize clicked = clicked_;
+
+- (void)buttonRightClicked {
+ self.clicked = YES;
+}
+@end
+
+class AvatarButtonTest : public ui::CocoaTest {
+ public:
+ AvatarButtonTest() {
+ NSRect content_frame = [[test_window() contentView] frame];
+ base::scoped_nsobject<AvatarButton> button(
+ [[AvatarButton alloc] initWithFrame:content_frame]);
+ button_ = button.get();
+ [[test_window() contentView] addSubview:button_];
+ }
+
+ AvatarButton* button_;
+};
+
+TEST_F(AvatarButtonTest, RightClick) {
+ base::scoped_nsobject<AvatarButtonTestObserver> observer(
+ [[AvatarButtonTestObserver alloc] init]);
+ [button_ setTarget:observer.get()];
+ [button_ setRightAction:@selector(buttonRightClicked)];
+
+ ASSERT_FALSE(observer.get().clicked);
+
+ [button_ performRightClick];
+ ASSERT_TRUE(observer.get().clicked);
+}
+
+TEST_F(AvatarButtonTest, RightClickInView) {
+ base::scoped_nsobject<AvatarButtonTestObserver> observer(
+ [[AvatarButtonTestObserver alloc] init]);
+ [button_ setTarget:observer.get()];
+ [button_ setRightAction:@selector(buttonRightClicked)];
+
+ ASSERT_FALSE(observer.get().clicked);
+
+ std::pair<NSEvent*, NSEvent*> events =
+ cocoa_test_event_utils::RightMouseClickInView(button_, 1);
+
+ [NSApp postEvent:events.second atStart:YES];
+ [NSApp sendEvent:events.first];
+
+ ASSERT_TRUE(observer.get().clicked);
+}
+
+TEST_F(AvatarButtonTest, RightMouseUpOutOfView) {
+ base::scoped_nsobject<AvatarButtonTestObserver> observer(
+ [[AvatarButtonTestObserver alloc] init]);
+ [button_ setTarget:observer.get()];
+ [button_ setRightAction:@selector(buttonRightClicked)];
+
+ ASSERT_FALSE(observer.get().clicked);
+
+ const NSRect bounds = [button_ convertRect:[button_ bounds] toView:nil];
+ const NSPoint downLocation = NSMakePoint(NSMidX(bounds), NSMidY(bounds));
+ NSEvent* down = cocoa_test_event_utils::MouseEventAtPointInWindow(
+ downLocation, NSRightMouseDown, [button_ window], 1);
+
+ const NSPoint upLocation = NSMakePoint(downLocation.x + bounds.size.width,
+ downLocation.y + bounds.size.height);
+ NSEvent* up = cocoa_test_event_utils::MouseEventAtPointInWindow(
+ upLocation, NSRightMouseUp, [button_ window], 1);
+
+ [NSApp postEvent:up atStart:YES];
+ [NSApp sendEvent:down];
+
+ ASSERT_FALSE(observer.get().clicked);
+}