summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authoratwilson@google.com <atwilson@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-24 21:29:05 +0000
committeratwilson@google.com <atwilson@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-24 21:29:05 +0000
commita24642a800c1712eeaa791f0fb0ed1527885c6fb (patch)
tree925671bf6414abcc8da68cd48a6085fa0007dd6b /chrome
parent45e9bcaa8bd6ff0eb2bf61d7100b1faacd2ccef4 (diff)
downloadchromium_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')
-rw-r--r--chrome/browser/browser_init.cc6
-rw-r--r--chrome/browser/cocoa/status_icons/status_icon_mac.h18
-rw-r--r--chrome/browser/cocoa/status_icons/status_icon_mac.mm24
-rw-r--r--chrome/browser/cocoa/status_icons/status_icon_mac_unittest.mm31
-rw-r--r--chrome/browser/cocoa/status_icons/status_tray_mac.h23
-rw-r--r--chrome/browser/cocoa/status_icons/status_tray_mac.mm18
-rw-r--r--chrome/browser/status_icons/status_icon.cc30
-rw-r--r--chrome/browser/status_icons/status_icon.h16
-rw-r--r--chrome/browser/status_icons/status_icon_unittest.cc47
-rw-r--r--chrome/browser/status_icons/status_tray.cc10
-rw-r--r--chrome/browser/status_icons/status_tray.h31
-rw-r--r--chrome/browser/status_icons/status_tray_manager.cc19
-rw-r--r--chrome/browser/status_icons/status_tray_unittest.cc19
-rw-r--r--chrome/browser/views/status_icons/status_icon_win.cc58
-rw-r--r--chrome/browser/views/status_icons/status_icon_win.h50
-rw-r--r--chrome/browser/views/status_icons/status_tray_win.cc79
-rw-r--r--chrome/browser/views/status_icons/status_tray_win.h42
-rw-r--r--chrome/browser/views/status_icons/status_tray_win_unittest.cc48
-rwxr-xr-xchrome/chrome_browser.gypi7
-rw-r--r--chrome/chrome_tests.gypi2
-rw-r--r--chrome/common/chrome_constants.cc1
-rw-r--r--chrome/common/chrome_constants.h1
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[];