summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authoratwilson@chromium.org <atwilson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-20 04:52:44 +0000
committeratwilson@chromium.org <atwilson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-20 04:52:44 +0000
commit9979f5d4a25cab18fa10885c5c7b64ea9f8d8eeb (patch)
tree0204e3328959fb902f7fb613d0c99103a0e858c7 /chrome/browser
parentc78b1e1619d7e700fce78f29533eba5ee78b0c70 (diff)
downloadchromium_src-9979f5d4a25cab18fa10885c5c7b64ea9f8d8eeb.zip
chromium_src-9979f5d4a25cab18fa10885c5c7b64ea9f8d8eeb.tar.gz
chromium_src-9979f5d4a25cab18fa10885c5c7b64ea9f8d8eeb.tar.bz2
Added support for context menus to status icons.
BUG=37375 TEST=updated StatusIcon unit tests Review URL: http://codereview.chromium.org/3189003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@56812 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/background_mode_manager.cc54
-rw-r--r--chrome/browser/background_mode_manager.h11
-rw-r--r--chrome/browser/cocoa/status_icons/status_icon_mac.h3
-rw-r--r--chrome/browser/cocoa/status_icons/status_icon_mac.mm5
-rw-r--r--chrome/browser/gtk/status_icons/status_icon_gtk.cc5
-rw-r--r--chrome/browser/gtk/status_icons/status_icon_gtk.h3
-rw-r--r--chrome/browser/status_icons/status_icon.cc18
-rw-r--r--chrome/browser/status_icons/status_icon.h35
-rw-r--r--chrome/browser/status_icons/status_icon_unittest.cc1
-rw-r--r--chrome/browser/status_icons/status_tray_unittest.cc2
-rw-r--r--chrome/browser/views/status_icons/status_icon_win.cc31
-rw-r--r--chrome/browser/views/status_icons/status_icon_win.h16
-rw-r--r--chrome/browser/views/status_icons/status_tray_win.cc13
-rw-r--r--chrome/browser/views/status_icons/status_tray_win_unittest.cc11
14 files changed, 189 insertions, 19 deletions
diff --git a/chrome/browser/background_mode_manager.cc b/chrome/browser/background_mode_manager.cc
index 814e2a2..f67a34b 100644
--- a/chrome/browser/background_mode_manager.cc
+++ b/chrome/browser/background_mode_manager.cc
@@ -5,6 +5,7 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/command_line.h"
+#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/background_mode_manager.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/metrics/user_metrics.h"
@@ -19,6 +20,7 @@
#include "chrome/common/pref_names.h"
#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
BackgroundModeManager::BackgroundModeManager(Profile* profile)
@@ -64,6 +66,9 @@ BackgroundModeManager::BackgroundModeManager(Profile* profile)
}
BackgroundModeManager::~BackgroundModeManager() {
+ // If we're going away, remove our status tray icon so we don't get any events
+ // from it.
+ RemoveStatusTrayIcon();
}
bool BackgroundModeManager::IsBackgroundModeEnabled() {
@@ -183,7 +188,30 @@ void BackgroundModeManager::CreateStatusTrayIcon() {
IDR_STATUS_TRAY_ICON);
status_icon_->SetImage(*bitmap);
status_icon_->SetToolTip(l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
- status_icon_->AddObserver(this);
+
+ // Create a context menu item for Chrome.
+ menus::SimpleMenuModel* menu = new menus::SimpleMenuModel(this);
+ menu->AddItem(IDC_ABOUT, l10n_util::GetStringFUTF16(IDS_ABOUT,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
+ menu->AddSeparator();
+ menu->AddItemWithStringId(IDC_EXIT, IDS_EXIT);
+ status_icon_->SetContextMenu(menu);
+}
+
+bool BackgroundModeManager::IsCommandIdChecked(int command_id) const {
+ return false;
+}
+
+bool BackgroundModeManager::IsCommandIdEnabled(int command_id) const {
+ // For now, we do not support disabled items.
+ return true;
+}
+
+bool BackgroundModeManager::GetAcceleratorForCommandId(
+ int command_id,
+ menus::Accelerator* accelerator) {
+ // No accelerators for status icon context menus.
+ return false;
}
void BackgroundModeManager::RemoveStatusTrayIcon() {
@@ -192,9 +220,27 @@ void BackgroundModeManager::RemoveStatusTrayIcon() {
status_icon_ = NULL;
}
-void BackgroundModeManager::OnClicked() {
- UserMetrics::RecordAction(UserMetricsAction("Exit"), profile_);
- BrowserList::CloseAllBrowsersAndExit();
+
+void BackgroundModeManager::ExecuteCommand(int item) {
+ switch (item) {
+ case IDC_EXIT:
+ UserMetrics::RecordAction(UserMetricsAction("Exit"), profile_);
+ BrowserList::CloseAllBrowsersAndExit();
+ break;
+ case IDC_ABOUT: {
+ // Need to display a browser window to put up the about dialog.
+ Browser* browser = BrowserList::GetLastActive();
+ if (!browser) {
+ Browser::OpenEmptyWindow(profile_);
+ browser = BrowserList::GetLastActive();
+ }
+ browser->OpenAboutChromeDialog();
+ break;
+ }
+ default:
+ NOTREACHED();
+ break;
+ }
}
// static
diff --git a/chrome/browser/background_mode_manager.h b/chrome/browser/background_mode_manager.h
index fa5296b..4ae4959 100644
--- a/chrome/browser/background_mode_manager.h
+++ b/chrome/browser/background_mode_manager.h
@@ -6,6 +6,7 @@
#define CHROME_BROWSER_BACKGROUND_MODE_MANAGER_H_
#pragma once
+#include "app/menus/simple_menu_model.h"
#include "base/gtest_prod_util.h"
#include "chrome/browser/status_icons/status_icon.h"
#include "chrome/common/notification_observer.h"
@@ -34,7 +35,7 @@ class StatusTray;
// background.
class BackgroundModeManager
: private NotificationObserver,
- private StatusIcon::Observer {
+ private menus::SimpleMenuModel::Delegate {
public:
explicit BackgroundModeManager(Profile* profile);
virtual ~BackgroundModeManager();
@@ -53,8 +54,12 @@ class BackgroundModeManager
const NotificationSource& source,
const NotificationDetails& details);
- // StatusIcon::Observer implementation.
- virtual void OnClicked();
+ // SimpleMenuModel::Delegate implementation.
+ virtual bool IsCommandIdChecked(int command_id) const;
+ virtual bool IsCommandIdEnabled(int command_id) const;
+ virtual bool GetAcceleratorForCommandId(int command_id,
+ menus::Accelerator* accelerator);
+ virtual void ExecuteCommand(int command_id);
// Called when an extension is loaded to manage count of background apps.
void OnBackgroundAppLoaded();
diff --git a/chrome/browser/cocoa/status_icons/status_icon_mac.h b/chrome/browser/cocoa/status_icons/status_icon_mac.h
index 3008607..3f4fbe2 100644
--- a/chrome/browser/cocoa/status_icons/status_icon_mac.h
+++ b/chrome/browser/cocoa/status_icons/status_icon_mac.h
@@ -26,6 +26,9 @@ class StatusIconMac : public StatusIcon {
virtual void SetPressedImage(const SkBitmap& image);
virtual void SetToolTip(const string16& tool_tip);
+ protected:
+ virtual void ResetContextMenu(menus::MenuModel* menu);
+
private:
// Getter for item_ that allows lazy initialization.
NSStatusItem* item();
diff --git a/chrome/browser/cocoa/status_icons/status_icon_mac.mm b/chrome/browser/cocoa/status_icons/status_icon_mac.mm
index 5e824b8..0d50c76 100644
--- a/chrome/browser/cocoa/status_icons/status_icon_mac.mm
+++ b/chrome/browser/cocoa/status_icons/status_icon_mac.mm
@@ -75,3 +75,8 @@ void StatusIconMac::SetPressedImage(const SkBitmap& bitmap) {
void StatusIconMac::SetToolTip(const string16& tool_tip) {
[item() setToolTip:base::SysUTF16ToNSString(tool_tip)];
}
+
+void StatusIconMac::ResetContextMenu(menus::MenuModel* menu) {
+ // TODO(atwilson): Add support for context menus for Mac when actually needed
+ // (not yet used by anything) - http://crbug.com/37375.
+}
diff --git a/chrome/browser/gtk/status_icons/status_icon_gtk.cc b/chrome/browser/gtk/status_icons/status_icon_gtk.cc
index 3dacfbc..d6af0a7 100644
--- a/chrome/browser/gtk/status_icons/status_icon_gtk.cc
+++ b/chrome/browser/gtk/status_icons/status_icon_gtk.cc
@@ -40,6 +40,11 @@ void StatusIconGtk::SetToolTip(const string16& tool_tip) {
gtk_status_icon_set_tooltip(icon_, UTF16ToUTF8(tool_tip).c_str());
}
+void StatusIconGtk::ResetContextMenu(menus::MenuModel* menu) {
+ // TODO(atwilson): Add support for context menus for GTK
+ // (http://crbug.com.37375).
+}
+
void StatusIconGtk::OnClick(GtkWidget* widget) {
DispatchClickEvent();
}
diff --git a/chrome/browser/gtk/status_icons/status_icon_gtk.h b/chrome/browser/gtk/status_icons/status_icon_gtk.h
index adb139b..4aa6c93 100644
--- a/chrome/browser/gtk/status_icons/status_icon_gtk.h
+++ b/chrome/browser/gtk/status_icons/status_icon_gtk.h
@@ -26,6 +26,9 @@ class StatusIconGtk : public StatusIcon {
// Exposed for testing.
CHROMEGTK_CALLBACK_0(StatusIconGtk, void, OnClick);
+ protected:
+ virtual void ResetContextMenu(menus::MenuModel* menu);
+
private:
// The currently-displayed icon for the window.
GtkStatusIcon* icon_;
diff --git a/chrome/browser/status_icons/status_icon.cc b/chrome/browser/status_icons/status_icon.cc
index 9fed83d..066419f 100644
--- a/chrome/browser/status_icons/status_icon.cc
+++ b/chrome/browser/status_icons/status_icon.cc
@@ -4,6 +4,15 @@
#include "chrome/browser/status_icons/status_icon.h"
+#include "app/menus/menu_model.h"
+
+StatusIcon::StatusIcon()
+{
+}
+
+StatusIcon::~StatusIcon() {
+}
+
void StatusIcon::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
@@ -12,6 +21,15 @@ void StatusIcon::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
+bool StatusIcon::HasObservers() {
+ return observers_.size() > 0;
+}
+
void StatusIcon::DispatchClickEvent() {
FOR_EACH_OBSERVER(Observer, observers_, OnClicked());
}
+
+void StatusIcon::SetContextMenu(menus::MenuModel* menu) {
+ context_menu_contents_.reset(menu);
+ ResetContextMenu(menu);
+}
diff --git a/chrome/browser/status_icons/status_icon.h b/chrome/browser/status_icons/status_icon.h
index 8245e12..8f868b5 100644
--- a/chrome/browser/status_icons/status_icon.h
+++ b/chrome/browser/status_icons/status_icon.h
@@ -7,14 +7,19 @@
#pragma once
#include "base/observer_list.h"
+#include "base/scoped_ptr.h"
#include "base/string16.h"
class SkBitmap;
+namespace menus {
+class MenuModel;
+}
+
class StatusIcon {
public:
- StatusIcon() {}
- virtual ~StatusIcon() {}
+ StatusIcon();
+ virtual ~StatusIcon();
// Sets the image associated with this status icon.
virtual void SetImage(const SkBitmap& image) = 0;
@@ -25,23 +30,45 @@ class StatusIcon {
// Sets the hover text for this status icon.
virtual void SetToolTip(const string16& tool_tip) = 0;
+ // Set the context menu for this icon. The icon takes ownership of the passed
+ // context menu. Passing NULL results in no menu at all.
+ void SetContextMenu(menus::MenuModel* menu);
+
class Observer {
public:
virtual ~Observer() {}
- // Called when the user clicks on the system tray icon.
+ // Called when the user clicks on the system tray icon. Clicks that result
+ // in the context menu being displayed will not be passed to this observer
+ // (i.e. if there's a context menu set on this status icon, and the user
+ // right clicks on the icon to display the context menu, OnClicked will not
+ // be called).
virtual void OnClicked() = 0;
};
- // Adds/Removes an observer for status bar events.
+ // Adds/Removes an observer for clicks on the status icon. If an observer is
+ // registered, then left clicks on the status icon will result in the observer
+ // being called, otherwise, both left and right clicks will display the
+ // context menu (if any).
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
+ // Returns true if there are registered click observers.
+ bool HasObservers();
+
// Dispatches a click event to the observers.
void DispatchClickEvent();
+ protected:
+ // Invoked after a call to SetContextMenu() to let the platform-specific
+ // subclass update the native context menu based on the new model. If NULL is
+ // passed, subclass should destroy the native context menu.
+ virtual void ResetContextMenu(menus::MenuModel* model) = 0;
+
private:
ObserverList<Observer> observers_;
+ // Context menu, if any.
+ scoped_ptr<menus::MenuModel> context_menu_contents_;
DISALLOW_COPY_AND_ASSIGN(StatusIcon);
};
diff --git a/chrome/browser/status_icons/status_icon_unittest.cc b/chrome/browser/status_icons/status_icon_unittest.cc
index db8c529..1738ff7 100644
--- a/chrome/browser/status_icons/status_icon_unittest.cc
+++ b/chrome/browser/status_icons/status_icon_unittest.cc
@@ -18,6 +18,7 @@ class TestStatusIcon : public StatusIcon {
virtual void SetImage(const SkBitmap& image) {}
virtual void SetPressedImage(const SkBitmap& image) {}
virtual void SetToolTip(const string16& tool_tip) {}
+ virtual void ResetContextMenu(menus::MenuModel* menu) {}
};
TEST(StatusIconTest, ObserverAdd) {
diff --git a/chrome/browser/status_icons/status_tray_unittest.cc b/chrome/browser/status_icons/status_tray_unittest.cc
index 26219bd..1d43cdc 100644
--- a/chrome/browser/status_icons/status_tray_unittest.cc
+++ b/chrome/browser/status_icons/status_tray_unittest.cc
@@ -15,6 +15,7 @@ class MockStatusIcon : public StatusIcon {
virtual void SetImage(const SkBitmap& image) {}
virtual void SetPressedImage(const SkBitmap& image) {}
virtual void SetToolTip(const string16& tool_tip) {}
+ virtual void ResetContextMenu(menus::MenuModel* menu) {}
virtual void AddObserver(StatusIcon::Observer* observer) {}
virtual void RemoveObserver(StatusIcon::Observer* observer) {}
};
@@ -22,6 +23,7 @@ class MockStatusIcon : public StatusIcon {
class TestStatusTray : public StatusTray {
public:
MOCK_METHOD0(CreatePlatformStatusIcon, StatusIcon*());
+ MOCK_METHOD1(ResetContextMenu, void(menus::MenuModel*));
};
TEST(StatusTrayTest, Create) {
diff --git a/chrome/browser/views/status_icons/status_icon_win.cc b/chrome/browser/views/status_icons/status_icon_win.cc
index 53cfcad..524829e 100644
--- a/chrome/browser/views/status_icons/status_icon_win.cc
+++ b/chrome/browser/views/status_icons/status_icon_win.cc
@@ -4,9 +4,11 @@
#include "chrome/browser/views/status_icons/status_icon_win.h"
-#include "gfx/icon_util.h"
#include "base/sys_string_conversions.h"
+#include "gfx/icon_util.h"
+#include "gfx/point.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "views/controls/menu/menu_2.h"
StatusIconWin::StatusIconWin(UINT id, HWND window, UINT message)
: icon_id_(id),
@@ -58,3 +60,30 @@ void StatusIconWin::InitIconData(NOTIFYICONDATA* icon_data) {
icon_data->hWnd = window_;
icon_data->uID = icon_id_;
}
+
+void StatusIconWin::ResetContextMenu(menus::MenuModel* menu) {
+ // If no items are passed, blow away our context menu.
+ if (!menu) {
+ context_menu_.reset();
+ return;
+ }
+
+ // Create context menu with the new contents.
+ context_menu_.reset(new views::Menu2(menu));
+}
+
+void StatusIconWin::HandleClickEvent(int x, int y, bool left_mouse_click) {
+ // Pass to the observer if appropriate.
+ if (left_mouse_click && HasObservers()) {
+ DispatchClickEvent();
+ return;
+ }
+
+ // Event not sent to the observer, so display the context menu if one exists.
+ if (context_menu_.get()) {
+ // Set our window as the foreground window, so the context menu closes when
+ // we click away from it.
+ SetForegroundWindow(window_);
+ context_menu_->RunContextMenuAt(gfx::Point(x, y));
+ }
+}
diff --git a/chrome/browser/views/status_icons/status_icon_win.h b/chrome/browser/views/status_icons/status_icon_win.h
index e3f88f4..f698fc4 100644
--- a/chrome/browser/views/status_icons/status_icon_win.h
+++ b/chrome/browser/views/status_icons/status_icon_win.h
@@ -10,8 +10,13 @@
#include <shellapi.h>
#include "base/scoped_handle_win.h"
+#include "base/scoped_ptr.h"
#include "chrome/browser/status_icons/status_icon.h"
+namespace views {
+class Menu2;
+}
+
class StatusIconWin : public StatusIcon {
public:
// Constructor which provides this icon's unique ID and messaging window.
@@ -27,6 +32,14 @@ class StatusIconWin : public StatusIcon {
UINT message_id() const { return message_id_; }
+ // Handles a click event from the user - if |left_button_click| is true and
+ // there is a registered observer, passes the click event to the observer,
+ // otherwise displays the context menu if there is one.
+ void HandleClickEvent(int x, int y, bool left_button_click);
+
+ protected:
+ virtual void ResetContextMenu(menus::MenuModel* menu);
+
private:
void InitIconData(NOTIFYICONDATA* icon_data);
@@ -42,6 +55,9 @@ class StatusIconWin : public StatusIcon {
// The currently-displayed icon for the window.
ScopedHICON icon_;
+ // Context menu associated with this icon (if any).
+ scoped_ptr<views::Menu2> context_menu_;
+
DISALLOW_COPY_AND_ASSIGN(StatusIconWin);
};
diff --git a/chrome/browser/views/status_icons/status_tray_win.cc b/chrome/browser/views/status_icons/status_tray_win.cc
index 5a4587f..29ed025 100644
--- a/chrome/browser/views/status_icons/status_tray_win.cc
+++ b/chrome/browser/views/status_icons/status_tray_win.cc
@@ -41,20 +41,23 @@ LRESULT CALLBACK StatusTrayWin::WndProc(HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam) {
- // TODO(atwilson): Add support for right clicks and context menu messages
- // (tracked in http://crbug.com/37375).
switch (message) {
case kStatusIconMessage:
switch (lparam) {
case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_CONTEXTMENU:
// Walk our icons, find which one was clicked on, and invoke its
- // DispatchClickEvent() method.
+ // HandleClickEvent() method.
for (StatusIconList::const_iterator iter = status_icons().begin();
iter != status_icons().end();
++iter) {
StatusIconWin* win_icon = static_cast<StatusIconWin*>(*iter);
- if (win_icon->icon_id() == wparam)
- win_icon->DispatchClickEvent();
+ if (win_icon->icon_id() == wparam) {
+ POINT p;
+ GetCursorPos(&p);
+ win_icon->HandleClickEvent(p.x, p.y, lparam == WM_LBUTTONDOWN);
+ }
}
return TRUE;
}
diff --git a/chrome/browser/views/status_icons/status_tray_win_unittest.cc b/chrome/browser/views/status_icons/status_tray_win_unittest.cc
index e5499b9e..c824755 100644
--- a/chrome/browser/views/status_icons/status_tray_win_unittest.cc
+++ b/chrome/browser/views/status_icons/status_tray_win_unittest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "app/menus/simple_menu_model.h"
#include "app/resource_bundle.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -24,8 +25,9 @@ TEST(StatusTrayWinTest, CreateTray) {
StatusTrayWin tray;
}
-TEST(StatusTrayWinTest, CreateIcon) {
- // Create an icon, set the images and tooltip, then shut it down.
+TEST(StatusTrayWinTest, CreateIconAndMenu) {
+ // Create an icon, set the images, tooltip, and context menu, then shut it
+ // down.
StatusTrayWin tray;
StatusIcon* icon = tray.CreateStatusIcon();
SkBitmap* bitmap = ResourceBundle::GetSharedInstance().GetBitmapNamed(
@@ -33,6 +35,9 @@ TEST(StatusTrayWinTest, CreateIcon) {
icon->SetImage(*bitmap);
icon->SetPressedImage(*bitmap);
icon->SetToolTip(ASCIIToUTF16("tool tip"));
+ menus::SimpleMenuModel* menu = new menus::SimpleMenuModel(NULL);
+ menu->AddItem(0, L"foo");
+ icon->SetContextMenu(menu);
}
TEST(StatusTrayWinTest, ClickOnIcon) {
@@ -44,5 +49,7 @@ TEST(StatusTrayWinTest, ClickOnIcon) {
EXPECT_CALL(observer, OnClicked());
// Mimic a click.
tray.WndProc(NULL, icon->message_id(), icon->icon_id(), WM_LBUTTONDOWN);
+ // Mimic a right-click - observer should not be called.
+ tray.WndProc(NULL, icon->message_id(), icon->icon_id(), WM_RBUTTONDOWN);
icon->RemoveObserver(&observer);
}