1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/views/status_icons/status_icon_win.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "base/win/metro.h"
9 #include "base/win/windows_version.h"
10 #include "third_party/skia/include/core/SkBitmap.h"
11 #include "ui/gfx/icon_util.h"
12 #include "ui/gfx/point.h"
13 #include "ui/views/controls/menu/menu_item_view.h"
14 #include "ui/views/controls/menu/menu_runner.h"
15 #include "win8/util/win8_util.h"
17 ////////////////////////////////////////////////////////////////////////////////
18 // StatusIconWin, public:
20 StatusIconWin::StatusIconWin(UINT id
, HWND window
, UINT message
)
25 NOTIFYICONDATA icon_data
;
26 InitIconData(&icon_data
);
27 icon_data
.uFlags
= NIF_MESSAGE
;
28 icon_data
.uCallbackMessage
= message_id_
;
29 BOOL result
= Shell_NotifyIcon(NIM_ADD
, &icon_data
);
30 // This can happen if the explorer process isn't running when we try to
31 // create the icon for some reason (for example, at startup).
33 LOG(WARNING
) << "Unable to create status tray icon.";
36 StatusIconWin::~StatusIconWin() {
38 NOTIFYICONDATA icon_data
;
39 InitIconData(&icon_data
);
40 Shell_NotifyIcon(NIM_DELETE
, &icon_data
);
43 void StatusIconWin::HandleClickEvent(const gfx::Point
& cursor_pos
,
44 bool left_mouse_click
) {
45 // Pass to the observer if appropriate.
46 if (left_mouse_click
&& HasObservers()) {
54 // Set our window as the foreground window, so the context menu closes when
55 // we click away from it.
56 if (!SetForegroundWindow(window_
))
59 menu_runner_
.reset(new views::MenuRunner(menu_model_
));
61 ignore_result(menu_runner_
->RunMenuAt(NULL
, NULL
,
62 gfx::Rect(cursor_pos
, gfx::Size()), views::MenuItemView::TOPLEFT
,
63 ui::MENU_SOURCE_MOUSE
, views::MenuRunner::HAS_MNEMONICS
));
66 void StatusIconWin::HandleBalloonClickEvent() {
68 DispatchBalloonClickEvent();
71 void StatusIconWin::ResetIcon() {
72 NOTIFYICONDATA icon_data
;
73 InitIconData(&icon_data
);
74 // Delete any previously existing icon.
75 Shell_NotifyIcon(NIM_DELETE
, &icon_data
);
76 InitIconData(&icon_data
);
77 icon_data
.uFlags
= NIF_MESSAGE
;
78 icon_data
.uCallbackMessage
= message_id_
;
79 icon_data
.hIcon
= icon_
.Get();
80 // If we have an image, then set the NIF_ICON flag, which tells
81 // Shell_NotifyIcon() to set the image for the status icon it creates.
83 icon_data
.uFlags
|= NIF_ICON
;
85 BOOL result
= Shell_NotifyIcon(NIM_ADD
, &icon_data
);
87 LOG(WARNING
) << "Unable to re-create status tray icon.";
90 void StatusIconWin::SetImage(const gfx::ImageSkia
& image
) {
92 NOTIFYICONDATA icon_data
;
93 InitIconData(&icon_data
);
94 icon_data
.uFlags
= NIF_ICON
;
95 icon_
.Set(IconUtil::CreateHICONFromSkBitmap(*image
.bitmap()));
96 icon_data
.hIcon
= icon_
.Get();
97 BOOL result
= Shell_NotifyIcon(NIM_MODIFY
, &icon_data
);
99 LOG(WARNING
) << "Error setting status tray icon image";
102 void StatusIconWin::SetPressedImage(const gfx::ImageSkia
& image
) {
103 // Ignore pressed images, since the standard on Windows is to not highlight
104 // pressed status icons.
107 void StatusIconWin::SetToolTip(const string16
& tool_tip
) {
109 NOTIFYICONDATA icon_data
;
110 InitIconData(&icon_data
);
111 icon_data
.uFlags
= NIF_TIP
;
112 wcscpy_s(icon_data
.szTip
, tool_tip
.c_str());
113 BOOL result
= Shell_NotifyIcon(NIM_MODIFY
, &icon_data
);
115 LOG(WARNING
) << "Unable to set tooltip for status tray icon";
118 void StatusIconWin::DisplayBalloon(const gfx::ImageSkia
& icon
,
119 const string16
& title
,
120 const string16
& contents
) {
121 NOTIFYICONDATA icon_data
;
122 InitIconData(&icon_data
);
123 icon_data
.uFlags
= NIF_INFO
;
124 icon_data
.dwInfoFlags
= NIIF_INFO
;
125 wcscpy_s(icon_data
.szInfoTitle
, title
.c_str());
126 wcscpy_s(icon_data
.szInfo
, contents
.c_str());
127 icon_data
.uTimeout
= 0;
129 base::win::Version win_version
= base::win::GetVersion();
130 if (!icon
.isNull() && win_version
!= base::win::VERSION_PRE_XP
) {
131 balloon_icon_
.Set(IconUtil::CreateHICONFromSkBitmap(*icon
.bitmap()));
132 if (win_version
>= base::win::VERSION_VISTA
) {
133 icon_data
.hBalloonIcon
= balloon_icon_
.Get();
134 icon_data
.dwInfoFlags
= NIIF_USER
| NIIF_LARGE_ICON
;
136 icon_data
.hIcon
= balloon_icon_
.Get();
137 icon_data
.uFlags
|= NIF_ICON
;
138 icon_data
.dwInfoFlags
= NIIF_USER
;
142 BOOL result
= Shell_NotifyIcon(NIM_MODIFY
, &icon_data
);
144 LOG(WARNING
) << "Unable to create status tray balloon.";
147 ////////////////////////////////////////////////////////////////////////////////
148 // StatusIconWin, private:
150 void StatusIconWin::UpdatePlatformContextMenu(StatusIconMenuModel
* menu
) {
151 // |menu_model_| is about to be destroyed. Destroy the menu (which closes it)
152 // so that it doesn't attempt to continue using |menu_model_|.
153 menu_runner_
.reset();
158 void StatusIconWin::InitIconData(NOTIFYICONDATA
* icon_data
) {
159 if (base::win::GetVersion() >= base::win::VERSION_VISTA
) {
160 memset(icon_data
, 0, sizeof(NOTIFYICONDATA
));
161 icon_data
->cbSize
= sizeof(NOTIFYICONDATA
);
163 memset(icon_data
, 0, NOTIFYICONDATA_V3_SIZE
);
164 icon_data
->cbSize
= NOTIFYICONDATA_V3_SIZE
;
167 icon_data
->hWnd
= window_
;
168 icon_data
->uID
= icon_id_
;
171 ////////////////////////////////////////////////////////////////////////////////
174 StatusIconMetro::StatusIconMetro(UINT id
)
176 DCHECK(win8::IsSingleWindowMetroMode());
179 StatusIconMetro::~StatusIconMetro() {
182 void StatusIconMetro::SetImage(const gfx::ImageSkia
& image
) {
183 DVLOG(1) << __FUNCTION__
;
186 void StatusIconMetro::SetPressedImage(const gfx::ImageSkia
& image
) {
187 DVLOG(1) << __FUNCTION__
;
190 void StatusIconMetro::SetToolTip(const string16
& tool_tip
) {
191 DVLOG(1) << __FUNCTION__
;
192 tool_tip_
= tool_tip
;
195 void StatusIconMetro::DisplayBalloon(const gfx::ImageSkia
& icon
,
196 const string16
& title
,
197 const string16
& contents
) {
198 DVLOG(1) << __FUNCTION__
;
200 HMODULE metro_module
= base::win::GetMetroModule();
201 DCHECK(metro_module
);
204 base::win::MetroNotification notification
=
205 reinterpret_cast<base::win::MetroNotification
>(
206 ::GetProcAddress(metro_module
, "DisplayNotification"));
207 DCHECK(notification
);
208 notification("", "", title
.c_str(), contents
.c_str(), L
"",
209 base::IntToString(id_
).c_str(), NULL
, NULL
);
213 void StatusIconMetro::UpdatePlatformContextMenu(StatusIconMenuModel
* menu
) {
214 DVLOG(1) << __FUNCTION__
215 << " This functionality is not supported in Windows 8 metro";