diff options
author | atwilson@google.com <atwilson@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-24 21:29:05 +0000 |
---|---|---|
committer | atwilson@google.com <atwilson@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-24 21:29:05 +0000 |
commit | a24642a800c1712eeaa791f0fb0ed1527885c6fb (patch) | |
tree | 925671bf6414abcc8da68cd48a6085fa0007dd6b /chrome | |
parent | 45e9bcaa8bd6ff0eb2bf61d7100b1faacd2ccef4 (diff) | |
download | chromium_src-a24642a800c1712eeaa791f0fb0ed1527885c6fb.zip chromium_src-a24642a800c1712eeaa791f0fb0ed1527885c6fb.tar.gz chromium_src-a24642a800c1712eeaa791f0fb0ed1527885c6fb.tar.bz2 |
Implement status icons on windows.
Refactor existing status icon code to allow platform-specific StatusTray implementation to
track common state for all status icons.
BUG=37375
TEST=new unit tests
Review URL: http://codereview.chromium.org/1136005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42538 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
22 files changed, 461 insertions, 119 deletions
diff --git a/chrome/browser/browser_init.cc b/chrome/browser/browser_init.cc index 34e61b3a..4d45cdd 100644 --- a/chrome/browser/browser_init.cc +++ b/chrome/browser/browser_init.cc @@ -421,17 +421,13 @@ bool BrowserInit::LaunchBrowser( chromeos::CrosLibrary::Get()->GetPowerLibrary()->AddObserver(observer); } #endif -#if defined(OS_MACOSX) - // TODO(atwilson): Status tray UI is currently only supported on the mac - // (http://crbug.com/37375). + if (command_line.HasSwitch(switches::kLongLivedExtensions)) { // Create status icons StatusTrayManager* tray = g_browser_process->status_tray_manager(); if (tray) tray->Init(profile); } -#endif - return true; } diff --git a/chrome/browser/cocoa/status_icons/status_icon_mac.h b/chrome/browser/cocoa/status_icons/status_icon_mac.h index e032476..0f99539 100644 --- a/chrome/browser/cocoa/status_icons/status_icon_mac.h +++ b/chrome/browser/cocoa/status_icons/status_icon_mac.h @@ -5,8 +5,6 @@ #ifndef CHROME_BROWSER_COCOA_STATUS_ICONS_STATUS_ICON_MAC_H_ #define CHROME_BROWSER_COCOA_STATUS_ICONS_STATUS_ICON_MAC_H_ -#include <vector> - #import <Cocoa/Cocoa.h> #include "base/scoped_nsobject.h" @@ -22,29 +20,19 @@ class StatusIconMac : public StatusIcon { StatusIconMac(); virtual ~StatusIconMac(); - // Sets the image associated with this status icon. + // Overridden from StatusIcon virtual void SetImage(const SkBitmap& image); - - // Sets the pressed image associated with this status icon. virtual void SetPressedImage(const SkBitmap& image); - - // Sets the hover text for this status icon. virtual void SetToolTip(const string16& tool_tip); - // Adds/removes a observer for status bar events. - virtual void AddObserver(StatusIcon::StatusIconObserver* observer); - virtual void RemoveObserver(StatusIcon::StatusIconObserver* observer); - - // Called back if the user clicks on the status bar icon. - void HandleClick(); - private: // Getter for item_ that allows lazy initialization. NSStatusItem* item(); scoped_nsobject<NSStatusItem> item_; scoped_nsobject<StatusItemController> controller_; - std::vector<StatusIcon::StatusIconObserver*> observers_; + + DISALLOW_COPY_AND_ASSIGN(StatusIconMac); }; diff --git a/chrome/browser/cocoa/status_icons/status_icon_mac.mm b/chrome/browser/cocoa/status_icons/status_icon_mac.mm index 0711184..239b8b6 100644 --- a/chrome/browser/cocoa/status_icons/status_icon_mac.mm +++ b/chrome/browser/cocoa/status_icons/status_icon_mac.mm @@ -27,7 +27,7 @@ - (void)handleClick:(id)sender { // Pass along the click notification to our owner. DCHECK(statusIcon_); - statusIcon_->HandleClick(); + statusIcon_->DispatchClickEvent(); } @end @@ -76,28 +76,6 @@ void StatusIconMac::SetToolTip(const string16& tool_tip) { [item() setToolTip:base::SysUTF16ToNSString(tool_tip)]; } -void StatusIconMac::AddObserver(StatusIconObserver* observer) { - observers_.push_back(observer); -} - -void StatusIconMac::RemoveObserver(StatusIconObserver* observer) { - std::vector<StatusIconObserver*>::iterator iter = - std::find(observers_.begin(), observers_.end(), observer); - if (iter != observers_.end()) - observers_.erase(iter); -} - -void StatusIconMac::HandleClick() { - // Walk observers, call callback for each one. - for (std::vector<StatusIconObserver*>::const_iterator iter = - observers_.begin(); - iter != observers_.end(); - ++iter) { - StatusIconObserver* observer = *iter; - observer->OnClicked(); - } -} - // static factory method StatusIcon* StatusIcon::Create() { return new StatusIconMac(); diff --git a/chrome/browser/cocoa/status_icons/status_icon_mac_unittest.mm b/chrome/browser/cocoa/status_icons/status_icon_mac_unittest.mm index 8051320..fe15bca 100644 --- a/chrome/browser/cocoa/status_icons/status_icon_mac_unittest.mm +++ b/chrome/browser/cocoa/status_icons/status_icon_mac_unittest.mm @@ -13,11 +13,6 @@ class SkBitmap; -class MockStatusIconObserver : public StatusIcon::StatusIconObserver { - public: - MOCK_METHOD0(OnClicked, void()); -}; - class StatusIconMacTest : public CocoaTest { }; @@ -32,29 +27,3 @@ TEST_F(StatusIconMacTest, Create) { icon->SetPressedImage(*pressed); icon->SetToolTip(ASCIIToUTF16("tool tip")); } - -TEST_F(StatusIconMacTest, ObserverAdd) { - // Make sure that observers are invoked when we click items. - StatusIconMac icon; - MockStatusIconObserver observer, observer2; - EXPECT_CALL(observer, OnClicked()).Times(2); - EXPECT_CALL(observer2, OnClicked()); - icon.AddObserver(&observer); - icon.HandleClick(); - icon.AddObserver(&observer2); - icon.HandleClick(); - icon.RemoveObserver(&observer); - icon.RemoveObserver(&observer2); -} - -TEST_F(StatusIconMacTest, ObserverRemove) { - // Make sure that observers are no longer invoked after they are removed. - StatusIconMac icon; - MockStatusIconObserver observer; - EXPECT_CALL(observer, OnClicked()); - icon.AddObserver(&observer); - icon.HandleClick(); - icon.RemoveObserver(&observer); - icon.HandleClick(); -} - diff --git a/chrome/browser/cocoa/status_icons/status_tray_mac.h b/chrome/browser/cocoa/status_icons/status_tray_mac.h new file mode 100644 index 0000000..9b4df80 --- /dev/null +++ b/chrome/browser/cocoa/status_icons/status_tray_mac.h @@ -0,0 +1,23 @@ +// Copyright (c) 2010 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_COCOA_STATUS_ICONS_STATUS_TRAY_MAC_H_ +#define CHROME_BROWSER_COCOA_STATUS_ICONS_STATUS_TRAY_MAC_H_ + +#include "chrome/browser/status_icons/status_tray.h" + +class StatusTrayMac : public StatusTray { + public: + StatusTrayMac(); + + protected: + // Factory method for creating a status icon. + virtual StatusIcon* CreateStatusIcon(); + + private: + DISALLOW_COPY_AND_ASSIGN(StatusTrayMac); +}; + +#endif // CHROME_BROWSER_COCOA_STATUS_ICONS_STATUS_TRAY_MAC_H_ + diff --git a/chrome/browser/cocoa/status_icons/status_tray_mac.mm b/chrome/browser/cocoa/status_icons/status_tray_mac.mm new file mode 100644 index 0000000..8c9449b --- /dev/null +++ b/chrome/browser/cocoa/status_icons/status_tray_mac.mm @@ -0,0 +1,18 @@ +// Copyright (c) 2010 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. + +#include "chrome/browser/cocoa/status_icons/status_tray_mac.h" + +#include "chrome/browser/cocoa/status_icons/status_icon_mac.h" + +StatusTray* StatusTray::Create() { + return new StatusTrayMac(); +} + +StatusTrayMac::StatusTrayMac() { +} + +StatusIcon* StatusTrayMac::CreateStatusIcon() { + return new StatusIconMac(); +} diff --git a/chrome/browser/status_icons/status_icon.cc b/chrome/browser/status_icons/status_icon.cc new file mode 100644 index 0000000..85fd175 --- /dev/null +++ b/chrome/browser/status_icons/status_icon.cc @@ -0,0 +1,30 @@ +// Copyright (c) 2010 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. + +#include <algorithm> + +#include "chrome/browser/status_icons/status_icon.h" + +void StatusIcon::AddObserver(StatusIconObserver* observer) { + observers_.push_back(observer); +} + +void StatusIcon::RemoveObserver(StatusIconObserver* observer) { + std::vector<StatusIconObserver*>::iterator iter = + std::find(observers_.begin(), observers_.end(), observer); + if (iter != observers_.end()) + observers_.erase(iter); +} + +void StatusIcon::DispatchClickEvent() { + // Walk observers, call callback for each one. + for (std::vector<StatusIconObserver*>::const_iterator iter = + observers_.begin(); + iter != observers_.end(); + ++iter) { + StatusIconObserver* observer = *iter; + observer->OnClicked(); + } +} + diff --git a/chrome/browser/status_icons/status_icon.h b/chrome/browser/status_icons/status_icon.h index a2bc089..3050026 100644 --- a/chrome/browser/status_icons/status_icon.h +++ b/chrome/browser/status_icons/status_icon.h @@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_STATUS_ICONS_STATUS_ICON_H_ #define CHROME_BROWSER_STATUS_ICONS_STATUS_ICON_H_ +#include <vector> + #include "base/string16.h" class SkBitmap; @@ -14,6 +16,7 @@ class StatusIcon { // Creates a new StatusIcon. static StatusIcon* Create(); + StatusIcon() {} virtual ~StatusIcon() {} // Sets the image associated with this status icon. @@ -33,9 +36,16 @@ class StatusIcon { virtual void OnClicked() = 0; }; - // Adds/removes a observer for status bar events. - virtual void AddObserver(StatusIcon::StatusIconObserver* observer) = 0; - virtual void RemoveObserver(StatusIcon::StatusIconObserver* observer) = 0; + // Adds/removes an observer for status bar events. + void AddObserver(StatusIconObserver* observer); + void RemoveObserver(StatusIconObserver* observer); + + // Dispatches a click event to the observers. + void DispatchClickEvent(); + + private: + std::vector<StatusIconObserver*> observers_; + 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 new file mode 100644 index 0000000..de791c9c0 --- /dev/null +++ b/chrome/browser/status_icons/status_icon_unittest.cc @@ -0,0 +1,47 @@ +// Copyright (c) 2010 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. + +#include "chrome/browser/status_icons/status_icon.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +class MockStatusIconObserver : public StatusIcon::StatusIconObserver { + public: + MOCK_METHOD0(OnClicked, void()); +}; + +// Define pure virtual functions so we can test base class functionality. +class TestStatusIcon : public StatusIcon { + public: + TestStatusIcon() {} + virtual void SetImage(const SkBitmap& image) {} + virtual void SetPressedImage(const SkBitmap& image) {} + virtual void SetToolTip(const string16& tool_tip) {} +}; + +TEST(StatusIconTest, ObserverAdd) { + // Make sure that observers are invoked when we click items. + TestStatusIcon icon; + MockStatusIconObserver observer, observer2; + EXPECT_CALL(observer, OnClicked()).Times(2); + EXPECT_CALL(observer2, OnClicked()); + icon.AddObserver(&observer); + icon.DispatchClickEvent(); + icon.AddObserver(&observer2); + icon.DispatchClickEvent(); + icon.RemoveObserver(&observer); + icon.RemoveObserver(&observer2); +} + +TEST(StatusIconTest, ObserverRemove) { + // Make sure that observers are no longer invoked after they are removed. + TestStatusIcon icon; + MockStatusIconObserver observer; + EXPECT_CALL(observer, OnClicked()); + icon.AddObserver(&observer); + icon.DispatchClickEvent(); + icon.RemoveObserver(&observer); + icon.DispatchClickEvent(); +} + diff --git a/chrome/browser/status_icons/status_tray.cc b/chrome/browser/status_icons/status_tray.cc index 1415babe..b7ae49c 100644 --- a/chrome/browser/status_icons/status_tray.cc +++ b/chrome/browser/status_icons/status_tray.cc @@ -7,14 +7,18 @@ #include "base/stl_util-inl.h" #include "chrome/browser/status_icons/status_icon.h" -StatusTray::StatusTray(StatusIconFactory* factory) - : factory_(factory) { +StatusTray::StatusTray() { } StatusTray::~StatusTray() { + RemoveAllIcons(); +} + +void StatusTray::RemoveAllIcons() { // Walk any active status icons and delete them. STLDeleteContainerPairSecondPointers(status_icons_.begin(), status_icons_.end()); + status_icons_.clear(); } StatusIcon* StatusTray::GetStatusIcon(const string16& identifier) { @@ -23,7 +27,7 @@ StatusIcon* StatusTray::GetStatusIcon(const string16& identifier) { return iter->second; // No existing StatusIcon, create a new one. - StatusIcon* icon = factory_->CreateIcon(); + StatusIcon* icon = CreateStatusIcon(); if (icon) status_icons_[identifier] = icon; return icon; diff --git a/chrome/browser/status_icons/status_tray.h b/chrome/browser/status_icons/status_tray.h index 663bfa8..30a60aa 100644 --- a/chrome/browser/status_icons/status_tray.h +++ b/chrome/browser/status_icons/status_tray.h @@ -10,20 +10,15 @@ class StatusIcon; -// Factory interface for creating icons to improve testability. -class StatusIconFactory { - public: - virtual StatusIcon* CreateIcon() = 0; - virtual ~StatusIconFactory() { } -}; - // Provides a cross-platform interface to the system's status tray, and exposes // APIs to add/remove icons to the tray and attach context menus. class StatusTray { public: - // Takes ownership of |factory|. - explicit StatusTray(StatusIconFactory* factory); - ~StatusTray(); + // Static factory method that is implemented separately for each platform to + // produce the appropriate platform-specific instance. + static StatusTray* Create(); + + virtual ~StatusTray(); // Gets the current status icon associated with this identifier, or creates // a new one if none exists. The StatusTray retains ownership of the @@ -33,15 +28,27 @@ class StatusTray { // Removes the current status icon associated with this identifier, if any. void RemoveStatusIcon(const string16& identifier); - private: + protected: + StatusTray(); + // Factory method for creating a status icon. + virtual StatusIcon* CreateStatusIcon() = 0; + + // Removes all StatusIcons (used by derived classes to clean up in case they + // track external state used by the StatusIcons). + void RemoveAllIcons(); + typedef base::hash_map<string16, StatusIcon*> StatusIconMap; + // Returns the list of active status icons so subclasses can operate on them. + const StatusIconMap& status_icons() { return status_icons_; } + + private: // Map containing all active StatusIcons. // Key: String identifiers (passed in to GetStatusIcon) // Value: The StatusIcon associated with that identifier (strong pointer - // StatusIcons are freed when the StatusTray destructor is called). StatusIconMap status_icons_; - scoped_ptr<StatusIconFactory> factory_; + DISALLOW_COPY_AND_ASSIGN(StatusTray); }; #endif // CHROME_BROWSER_STATUS_ICONS_STATUS_TRAY_H_ diff --git a/chrome/browser/status_icons/status_tray_manager.cc b/chrome/browser/status_icons/status_tray_manager.cc index f0ef268..39b6c85 100644 --- a/chrome/browser/status_icons/status_tray_manager.cc +++ b/chrome/browser/status_icons/status_tray_manager.cc @@ -14,21 +14,6 @@ #include "grit/browser_resources.h" #include "grit/theme_resources.h" -class StatusIconFactoryImpl : public StatusIconFactory { - public: - virtual StatusIcon* CreateIcon(); -}; - -StatusIcon* StatusIconFactoryImpl::CreateIcon() { -#ifdef OS_MACOSX - return StatusIcon::Create(); -#else - // TODO(atwilson): Add support for non-Mac platforms. - return 0; -#endif -} - - StatusTrayManager::StatusTrayManager() { } @@ -36,9 +21,10 @@ StatusTrayManager::~StatusTrayManager() { } void StatusTrayManager::Init(Profile* profile) { +#if !defined(OS_LINUX) DCHECK(profile); profile_ = profile; - status_tray_.reset(new StatusTray(new StatusIconFactoryImpl())); + status_tray_.reset(StatusTray::Create()); StatusIcon* icon = status_tray_->GetStatusIcon(ASCIIToUTF16("chrome_main")); if (icon) { // Create an icon and add ourselves as a click observer on it @@ -50,6 +36,7 @@ void StatusTrayManager::Init(Profile* profile) { icon->SetPressedImage(*pressed); icon->AddObserver(this); } +#endif } void StatusTrayManager::OnClicked() { diff --git a/chrome/browser/status_icons/status_tray_unittest.cc b/chrome/browser/status_icons/status_tray_unittest.cc index e224fac..538a132 100644 --- a/chrome/browser/status_icons/status_tray_unittest.cc +++ b/chrome/browser/status_icons/status_tray_unittest.cc @@ -18,34 +18,31 @@ class MockStatusIcon : public StatusIcon { virtual void RemoveObserver(StatusIcon::StatusIconObserver* observer) {} }; -class TestStatusIconFactory : public StatusIconFactory { +class TestStatusTray : public StatusTray { public: - MOCK_METHOD0(CreateIcon, StatusIcon*()); + MOCK_METHOD0(CreateStatusIcon, StatusIcon*()); }; TEST(StatusTrayTest, Create) { // Check for creation and leaks. - TestStatusIconFactory* factory = new TestStatusIconFactory(); - StatusTray tray(factory); - EXPECT_CALL(*factory, CreateIcon()).WillOnce(Return(new MockStatusIcon())); + TestStatusTray tray; + EXPECT_CALL(tray, CreateStatusIcon()).WillOnce(Return(new MockStatusIcon())); tray.GetStatusIcon(ASCIIToUTF16("test")); } TEST(StatusTrayTest, GetIconTwice) { - TestStatusIconFactory* factory = new TestStatusIconFactory(); - StatusTray tray(factory); + TestStatusTray tray; string16 id = ASCIIToUTF16("test"); // We should not try to create a new icon if we get the same ID twice. - EXPECT_CALL(*factory, CreateIcon()).WillOnce(Return(new MockStatusIcon())); + EXPECT_CALL(tray, CreateStatusIcon()).WillOnce(Return(new MockStatusIcon())); StatusIcon* icon = tray.GetStatusIcon(id); EXPECT_EQ(icon, tray.GetStatusIcon(id)); } TEST(StatusTrayTest, GetIconAfterRemove) { - TestStatusIconFactory* factory = new TestStatusIconFactory(); - StatusTray tray(factory); + TestStatusTray tray; string16 id = ASCIIToUTF16("test"); - EXPECT_CALL(*factory, CreateIcon()).Times(2) + EXPECT_CALL(tray, CreateStatusIcon()).Times(2) .WillOnce(Return(new MockStatusIcon())) .WillOnce(Return(new MockStatusIcon())); StatusIcon* icon = tray.GetStatusIcon(id); diff --git a/chrome/browser/views/status_icons/status_icon_win.cc b/chrome/browser/views/status_icons/status_icon_win.cc new file mode 100644 index 0000000..4ba6603 --- /dev/null +++ b/chrome/browser/views/status_icons/status_icon_win.cc @@ -0,0 +1,58 @@ +// Copyright (c) 2010 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. + +#include "chrome/browser/views/status_icons/status_icon_win.h" + +#include <windows.h> +#include <shellapi.h> + +#include "gfx/icon_util.h" +#include "base/logging.h" +#include "base/sys_string_conversions.h" +#include "third_party/skia/include/core/SkBitmap.h" + +StatusIconWin::StatusIconWin(UINT id, HWND window, UINT message) + : icon_id_(id), + window_(window), + message_id_(message) { + NOTIFYICONDATA icon_data; + InitIconData(&icon_data); + icon_data.uFlags = NIF_MESSAGE; + icon_data.uCallbackMessage = message_id_; + BOOL result = Shell_NotifyIcon(NIM_ADD, &icon_data); + DCHECK(result); +} + +StatusIconWin::~StatusIconWin() { + // Remove our icon. + NOTIFYICONDATA icon_data; + InitIconData(&icon_data); + Shell_NotifyIcon(NIM_DELETE, &icon_data); +} + +void StatusIconWin::SetImage(const SkBitmap& image) { + // Create the icon. + NOTIFYICONDATA icon_data; + InitIconData(&icon_data); + icon_data.uFlags = NIF_ICON; + icon_.Set(IconUtil::CreateHICONFromSkBitmap(image)); + icon_data.hIcon = icon_.Get(); + BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data); + DCHECK(result); +} + +void StatusIconWin::SetPressedImage(const SkBitmap& image) { + // Ignore pressed images, since the standard on Windows is to not highlight + // pressed status icons. +} + +void StatusIconWin::SetToolTip(const string16& tool_tip) { + // TODO(atwilson): Implement this (http://crbug.com/38993). +} + +void StatusIconWin::InitIconData(NOTIFYICONDATA* icon_data) { + icon_data->cbSize = sizeof(icon_data); + icon_data->hWnd = window_; + icon_data->uID = icon_id_; +} diff --git a/chrome/browser/views/status_icons/status_icon_win.h b/chrome/browser/views/status_icons/status_icon_win.h new file mode 100644 index 0000000..be3c9b0 --- /dev/null +++ b/chrome/browser/views/status_icons/status_icon_win.h @@ -0,0 +1,50 @@ +// Copyright (c) 2010 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_VIEWS_STATUS_ICONS_STATUS_ICON_WIN_H_ +#define CHROME_BROWSER_VIEWS_STATUS_ICONS_STATUS_ICON_WIN_H_ + +#include <windows.h> +#include <shellapi.h> + +#include "base/scoped_handle_win.h" +#include "base/string16.h" +#include "chrome/browser/status_icons/status_icon.h" + +class SkBitmap; + +class StatusIconWin : public StatusIcon { + public: + // Constructor which provides this icon's unique ID and messaging window. + StatusIconWin(UINT id, HWND window, UINT message); + virtual ~StatusIconWin(); + + // Overridden from StatusIcon + virtual void SetImage(const SkBitmap& image); + virtual void SetPressedImage(const SkBitmap& image); + virtual void SetToolTip(const string16& tool_tip); + + UINT icon_id() const { return icon_id_; } + + UINT message_id() const { return message_id_; } + + private: + void InitIconData(NOTIFYICONDATA* icon_data); + + // The unique ID corresponding to this icon. + UINT icon_id_; + + // Window used for processing messages from this icon. + HWND window_; + + // The message identifier used for status icon messages. + UINT message_id_; + + // The currently-displayed icon for the window. + ScopedHICON icon_; + + DISALLOW_COPY_AND_ASSIGN(StatusIconWin); +}; + +#endif // CHROME_BROWSER_VIEWS_STATUS_ICONS_STATUS_ICON_WIN_H_ diff --git a/chrome/browser/views/status_icons/status_tray_win.cc b/chrome/browser/views/status_icons/status_tray_win.cc new file mode 100644 index 0000000..8c1a998 --- /dev/null +++ b/chrome/browser/views/status_icons/status_tray_win.cc @@ -0,0 +1,79 @@ +// Copyright (c) 2010 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. + +#include "chrome/browser/views/status_icons/status_tray_win.h" + +#include "base/win_util.h" +#include "chrome/browser/views/status_icons/status_icon_win.h" +#include "chrome/common/chrome_constants.h" + +static const UINT kStatusIconMessage = WM_APP + 1; + +StatusTrayWin::StatusTrayWin() + : next_icon_id_(1) { + // Register our window class + HINSTANCE hinst = GetModuleHandle(NULL); + WNDCLASSEX wc = {0}; + wc.cbSize = sizeof(wc); + wc.lpfnWndProc = StatusTrayWin::WndProcStatic; + wc.hInstance = hinst; + wc.lpszClassName = chrome::kStatusTrayWindowClass; + ATOM clazz = RegisterClassEx(&wc); + DCHECK(clazz); + + // Create an offscreen window for handling messages for the status icons. + window_ = CreateWindow(chrome::kStatusTrayWindowClass, + 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hinst, 0); + win_util::SetWindowUserData(window_, this); +} + +LRESULT CALLBACK StatusTrayWin::WndProcStatic(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam) { + StatusTrayWin* msg_wnd = reinterpret_cast<StatusTrayWin*>( + GetWindowLongPtr(hwnd, GWLP_USERDATA)); + return msg_wnd->WndProc(hwnd, message, wparam, lparam); +} + +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: + // Walk our icons, find which one was clicked on, and invoke its + // DispatchClickEvent() method. + for (StatusIconMap::const_iterator iter = status_icons().begin(); + iter != status_icons().end(); + ++iter) { + StatusIconWin* win_icon = + static_cast<StatusIconWin*>(iter->second); + if (win_icon->icon_id() == wparam) + win_icon->DispatchClickEvent(); + } + return TRUE; + } + break; + } + return ::DefWindowProc(hwnd, message, wparam, lparam); +} + +StatusTrayWin::~StatusTrayWin() { + if (window_) + DestroyWindow(window_); + UnregisterClass(chrome::kStatusTrayWindowClass, GetModuleHandle(NULL)); +} + +StatusIcon* StatusTrayWin::CreateStatusIcon() { + return new StatusIconWin(next_icon_id_++, window_, kStatusIconMessage); +} + +StatusTray* StatusTray::Create() { + return new StatusTrayWin(); +} diff --git a/chrome/browser/views/status_icons/status_tray_win.h b/chrome/browser/views/status_icons/status_tray_win.h new file mode 100644 index 0000000..0dbc5cd --- /dev/null +++ b/chrome/browser/views/status_icons/status_tray_win.h @@ -0,0 +1,42 @@ +// Copyright (c) 2010 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_VIEWS_STATUS_ICONS_STATUS_TRAY_WIN_H_ +#define CHROME_BROWSER_VIEWS_STATUS_ICONS_STATUS_TRAY_WIN_H_ + +#include <windows.h> + +#include "chrome/browser/status_icons/status_tray.h" + +class StatusTrayWin : public StatusTray { + public: + StatusTrayWin(); + ~StatusTrayWin(); + + // Exposed for testing. + LRESULT CALLBACK WndProc(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam); + protected: + // Factory method for creating a status icon. + virtual StatusIcon* CreateStatusIcon(); + + private: + // Static callback invoked when a message comes in to our messaging window. + static LRESULT CALLBACK WndProcStatic(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam); + + // The unique icon ID we will assign to the next icon. + UINT next_icon_id_; + // The window used for processing events. + HWND window_; + + DISALLOW_COPY_AND_ASSIGN(StatusTrayWin); +}; + +#endif // CHROME_BROWSER_VIEWS_STATUS_ICONS_STATUS_TRAY_WIN_H_ + diff --git a/chrome/browser/views/status_icons/status_tray_win_unittest.cc b/chrome/browser/views/status_icons/status_tray_win_unittest.cc new file mode 100644 index 0000000..67449bf --- /dev/null +++ b/chrome/browser/views/status_icons/status_tray_win_unittest.cc @@ -0,0 +1,48 @@ +// Copyright (c) 2010 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. + +#include "app/resource_bundle.h" +#include "base/string_util.h" +#include "chrome/browser/views/status_icons/status_icon_win.h" +#include "chrome/browser/views/status_icons/status_tray_win.h" +#include "grit/browser_resources.h" +#include "grit/theme_resources.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +class SkBitmap; + +class MockStatusIconObserver : public StatusIcon::StatusIconObserver { + public: + MOCK_METHOD0(OnClicked, void()); +}; + +TEST(StatusTrayWinTest, CreateTray) { + // Just tests creation/destruction. + StatusTrayWin tray; +} + +TEST(StatusTrayWinTest, CreateIcon) { + // Create an icon, set the images and tooltip, then shut it down. + StatusTrayWin tray; + StatusIcon* icon = tray.GetStatusIcon(ASCIIToUTF16("test")); + SkBitmap* bitmap = ResourceBundle::GetSharedInstance().GetBitmapNamed( + IDR_STATUS_TRAY_ICON); + icon->SetImage(*bitmap); + icon->SetPressedImage(*bitmap); + icon->SetToolTip(ASCIIToUTF16("tool tip")); +} + +TEST(StatusTrayWinTest, ClickOnIcon) { + // Create an icon, send a fake click event, make sure observer is called. + StatusTrayWin tray; + StatusIconWin* icon = static_cast<StatusIconWin*>( + tray.GetStatusIcon(ASCIIToUTF16("test"))); + MockStatusIconObserver observer; + icon->AddObserver(&observer); + EXPECT_CALL(observer, OnClicked()); + // Mimic a click. + tray.WndProc(NULL, icon->message_id(), icon->icon_id(), WM_LBUTTONDOWN); + icon->RemoveObserver(&observer); +} diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 8c13b7f..4a51880 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -737,6 +737,8 @@ 'browser/cocoa/status_bubble_mac.mm', 'browser/cocoa/status_icons/status_icon_mac.h', 'browser/cocoa/status_icons/status_icon_mac.mm', + 'browser/cocoa/status_icons/status_tray_mac.h', + 'browser/cocoa/status_icons/status_tray_mac.mm', 'browser/cocoa/styled_text_field.h', 'browser/cocoa/styled_text_field.mm', 'browser/cocoa/styled_text_field_cell.h', @@ -1903,6 +1905,7 @@ 'browser/status_icons/status_tray.h', 'browser/status_icons/status_tray_manager.cc', 'browser/status_icons/status_tray_manager.h', + 'browser/status_icons/status_icon.cc', 'browser/status_icons/status_icon.h', 'browser/transport_security_persister.cc', 'browser/transport_security_persister.h', @@ -2283,6 +2286,10 @@ 'browser/views/shell_dialogs_win.cc', 'browser/views/status_bubble_views.cc', 'browser/views/status_bubble_views.h', + 'browser/views/status_icons/status_icon_win.cc', + 'browser/views/status_icons/status_icon_win.h', + 'browser/views/status_icons/status_tray_win.cc', + 'browser/views/status_icons/status_tray_win.h', 'browser/views/tab_icon_view.cc', 'browser/views/tab_icon_view.h', 'browser/views/tab_contents/tab_contents_container.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 6878c5e..3fcc607 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -867,6 +867,7 @@ 'browser/shell_integration_unittest.cc', 'browser/spellchecker_platform_engine_unittest.cc', 'browser/ssl/ssl_host_state_unittest.cc', + 'browser/status_icons/status_icon_unittest.cc', 'browser/status_icons/status_tray_unittest.cc', 'browser/sync/glue/autofill_model_associator_unittest.cc', 'browser/sync/glue/bookmark_data_type_controller_unittest.cc', @@ -909,6 +910,7 @@ 'browser/views/bookmark_editor_view_unittest.cc', 'browser/views/extensions/browser_action_drag_data_unittest.cc', 'browser/views/generic_info_view_unittest.cc', + 'browser/views/status_icons/status_tray_win_unittest.cc', 'browser/visitedlink_unittest.cc', 'browser/webdata/web_data_service_unittest.cc', 'browser/webdata/web_database_unittest.cc', diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc index e88c835..38cf59e 100644 --- a/chrome/common/chrome_constants.cc +++ b/chrome/common/chrome_constants.cc @@ -67,6 +67,7 @@ const wchar_t kBrowserAppID[] = L"Chrome"; #else const wchar_t kBrowserAppID[] = L"Chromium"; #endif +const wchar_t kStatusTrayWindowClass[] = L"Chrome_StatusTrayWindow"; #endif // defined(OS_WIN) const wchar_t kMessageWindowClass[] = L"Chrome_MessageWindow"; diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h index abe0283..554a48b 100644 --- a/chrome/common/chrome_constants.h +++ b/chrome/common/chrome_constants.h @@ -23,6 +23,7 @@ extern const FilePath::CharType kFrameworkName[]; extern const wchar_t kBrowserAppName[]; #if defined(OS_WIN) extern const wchar_t kBrowserAppID[]; +extern const wchar_t kStatusTrayWindowClass[]; #endif // defined(OS_WIN) extern const wchar_t kMessageWindowClass[]; extern const wchar_t kCrashReportLog[]; |