| 
									
										
										
										
											2014-10-31 11:17:05 -07:00
										 |  |  | // Copyright (c) 2014 GitHub, Inc.
 | 
					
						
							| 
									
										
										
										
											2014-06-03 11:25:09 +08:00
										 |  |  | // Use of this source code is governed by the MIT license that can be
 | 
					
						
							|  |  |  | // found in the LICENSE file.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "atom/browser/ui/win/notify_icon.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "atom/browser/ui/win/notify_icon_host.h"
 | 
					
						
							|  |  |  | #include "base/strings/string_number_conversions.h"
 | 
					
						
							|  |  |  | #include "base/strings/utf_string_conversions.h"
 | 
					
						
							|  |  |  | #include "base/win/windows_version.h"
 | 
					
						
							|  |  |  | #include "third_party/skia/include/core/SkBitmap.h"
 | 
					
						
							|  |  |  | #include "ui/gfx/icon_util.h"
 | 
					
						
							| 
									
										
										
										
											2015-01-02 19:30:48 -08:00
										 |  |  | #include "ui/gfx/image/image.h"
 | 
					
						
							| 
									
										
										
										
											2015-03-10 15:35:53 -07:00
										 |  |  | #include "ui/gfx/geometry/point.h"
 | 
					
						
							|  |  |  | #include "ui/gfx/geometry/rect.h"
 | 
					
						
							| 
									
										
										
										
											2014-07-11 19:42:53 +08:00
										 |  |  | #include "ui/views/controls/menu/menu_runner.h"
 | 
					
						
							| 
									
										
										
										
											2014-06-03 11:25:09 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace atom { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | NotifyIcon::NotifyIcon(NotifyIconHost* host, | 
					
						
							|  |  |  |                        UINT id, | 
					
						
							|  |  |  |                        HWND window, | 
					
						
							|  |  |  |                        UINT message) | 
					
						
							|  |  |  |     : host_(host), | 
					
						
							|  |  |  |       icon_id_(id), | 
					
						
							|  |  |  |       window_(window), | 
					
						
							| 
									
										
										
										
											2014-06-03 11:52:57 +08:00
										 |  |  |       message_id_(message), | 
					
						
							|  |  |  |       menu_model_(NULL) { | 
					
						
							| 
									
										
										
										
											2014-06-03 11:25:09 +08:00
										 |  |  |   NOTIFYICONDATA icon_data; | 
					
						
							|  |  |  |   InitIconData(&icon_data); | 
					
						
							|  |  |  |   icon_data.uFlags = NIF_MESSAGE; | 
					
						
							|  |  |  |   icon_data.uCallbackMessage = message_id_; | 
					
						
							|  |  |  |   BOOL result = Shell_NotifyIcon(NIM_ADD, &icon_data); | 
					
						
							|  |  |  |   // This can happen if the explorer process isn't running when we try to
 | 
					
						
							|  |  |  |   // create the icon for some reason (for example, at startup).
 | 
					
						
							|  |  |  |   if (!result) | 
					
						
							|  |  |  |     LOG(WARNING) << "Unable to create status tray icon."; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | NotifyIcon::~NotifyIcon() { | 
					
						
							|  |  |  |   // Remove our icon.
 | 
					
						
							|  |  |  |   host_->Remove(this); | 
					
						
							|  |  |  |   NOTIFYICONDATA icon_data; | 
					
						
							|  |  |  |   InitIconData(&icon_data); | 
					
						
							|  |  |  |   Shell_NotifyIcon(NIM_DELETE, &icon_data); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos, | 
					
						
							|  |  |  |                                   bool left_mouse_click) { | 
					
						
							|  |  |  |   // Pass to the observer if appropriate.
 | 
					
						
							|  |  |  |   if (left_mouse_click) { | 
					
						
							| 
									
										
										
										
											2015-05-01 15:24:22 +05:30
										 |  |  |     NotifyClicked(cursor_pos); | 
					
						
							| 
									
										
										
										
											2014-06-03 11:25:09 +08:00
										 |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!menu_model_) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Set our window as the foreground window, so the context menu closes when
 | 
					
						
							|  |  |  |   // we click away from it.
 | 
					
						
							|  |  |  |   if (!SetForegroundWindow(window_)) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-16 21:22:22 +08:00
										 |  |  |   views::MenuRunner menu_runner( | 
					
						
							|  |  |  |       menu_model_, | 
					
						
							|  |  |  |       views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS); | 
					
						
							| 
									
										
										
										
											2014-07-28 20:44:11 +08:00
										 |  |  |   ignore_result(menu_runner.RunMenuAt( | 
					
						
							| 
									
										
										
										
											2014-07-11 19:42:53 +08:00
										 |  |  |       NULL, | 
					
						
							|  |  |  |       NULL, | 
					
						
							| 
									
										
										
										
											2014-07-28 20:44:11 +08:00
										 |  |  |       gfx::Rect(cursor_pos, gfx::Size()), | 
					
						
							| 
									
										
										
										
											2014-07-28 20:32:10 +08:00
										 |  |  |       views::MENU_ANCHOR_TOPLEFT, | 
					
						
							| 
									
										
										
										
											2014-10-13 22:47:13 +08:00
										 |  |  |       ui::MENU_SOURCE_MOUSE)); | 
					
						
							| 
									
										
										
										
											2014-06-03 11:25:09 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void NotifyIcon::ResetIcon() { | 
					
						
							|  |  |  |   NOTIFYICONDATA icon_data; | 
					
						
							|  |  |  |   InitIconData(&icon_data); | 
					
						
							|  |  |  |   // Delete any previously existing icon.
 | 
					
						
							|  |  |  |   Shell_NotifyIcon(NIM_DELETE, &icon_data); | 
					
						
							|  |  |  |   InitIconData(&icon_data); | 
					
						
							|  |  |  |   icon_data.uFlags = NIF_MESSAGE; | 
					
						
							|  |  |  |   icon_data.uCallbackMessage = message_id_; | 
					
						
							|  |  |  |   icon_data.hIcon = icon_.Get(); | 
					
						
							|  |  |  |   // If we have an image, then set the NIF_ICON flag, which tells
 | 
					
						
							|  |  |  |   // Shell_NotifyIcon() to set the image for the status icon it creates.
 | 
					
						
							|  |  |  |   if (icon_data.hIcon) | 
					
						
							|  |  |  |     icon_data.uFlags |= NIF_ICON; | 
					
						
							|  |  |  |   // Re-add our icon.
 | 
					
						
							|  |  |  |   BOOL result = Shell_NotifyIcon(NIM_ADD, &icon_data); | 
					
						
							|  |  |  |   if (!result) | 
					
						
							|  |  |  |     LOG(WARNING) << "Unable to re-create status tray icon."; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-02 18:43:56 -08:00
										 |  |  | void NotifyIcon::SetImage(const gfx::Image& image) { | 
					
						
							| 
									
										
										
										
											2014-06-03 11:25:09 +08:00
										 |  |  |   // Create the icon.
 | 
					
						
							|  |  |  |   NOTIFYICONDATA icon_data; | 
					
						
							|  |  |  |   InitIconData(&icon_data); | 
					
						
							|  |  |  |   icon_data.uFlags = NIF_ICON; | 
					
						
							| 
									
										
										
										
											2015-01-02 18:43:56 -08:00
										 |  |  |   icon_.Set(IconUtil::CreateHICONFromSkBitmap(image.AsBitmap())); | 
					
						
							| 
									
										
										
										
											2014-06-03 11:25:09 +08:00
										 |  |  |   icon_data.hIcon = icon_.Get(); | 
					
						
							|  |  |  |   BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data); | 
					
						
							|  |  |  |   if (!result) | 
					
						
							|  |  |  |     LOG(WARNING) << "Error setting status tray icon image"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-02 18:43:56 -08:00
										 |  |  | void NotifyIcon::SetPressedImage(const gfx::Image& image) { | 
					
						
							| 
									
										
										
										
											2014-06-03 11:25:09 +08:00
										 |  |  |   // Ignore pressed images, since the standard on Windows is to not highlight
 | 
					
						
							|  |  |  |   // pressed status icons.
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void NotifyIcon::SetToolTip(const std::string& tool_tip) { | 
					
						
							|  |  |  |   // Create the icon.
 | 
					
						
							|  |  |  |   NOTIFYICONDATA icon_data; | 
					
						
							|  |  |  |   InitIconData(&icon_data); | 
					
						
							|  |  |  |   icon_data.uFlags = NIF_TIP; | 
					
						
							| 
									
										
										
										
											2014-07-11 12:19:01 +08:00
										 |  |  |   wcscpy_s(icon_data.szTip, base::UTF8ToUTF16(tool_tip).c_str()); | 
					
						
							| 
									
										
										
										
											2014-06-03 11:25:09 +08:00
										 |  |  |   BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data); | 
					
						
							|  |  |  |   if (!result) | 
					
						
							|  |  |  |     LOG(WARNING) << "Unable to set tooltip for status tray icon"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-02 18:43:56 -08:00
										 |  |  | void NotifyIcon::DisplayBalloon(const gfx::Image& icon, | 
					
						
							| 
									
										
										
										
											2014-11-28 18:30:43 +08:00
										 |  |  |                                 const base::string16& title, | 
					
						
							|  |  |  |                                 const base::string16& contents) { | 
					
						
							|  |  |  |   NOTIFYICONDATA icon_data; | 
					
						
							|  |  |  |   InitIconData(&icon_data); | 
					
						
							|  |  |  |   icon_data.uFlags = NIF_INFO; | 
					
						
							|  |  |  |   icon_data.dwInfoFlags = NIIF_INFO; | 
					
						
							|  |  |  |   wcscpy_s(icon_data.szInfoTitle, title.c_str()); | 
					
						
							|  |  |  |   wcscpy_s(icon_data.szInfo, contents.c_str()); | 
					
						
							|  |  |  |   icon_data.uTimeout = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   base::win::Version win_version = base::win::GetVersion(); | 
					
						
							| 
									
										
										
										
											2015-01-02 19:30:48 -08:00
										 |  |  |   if (!icon.IsEmpty() && win_version != base::win::VERSION_PRE_XP) { | 
					
						
							| 
									
										
										
										
											2015-01-02 18:43:56 -08:00
										 |  |  |     balloon_icon_.Set(IconUtil::CreateHICONFromSkBitmap(icon.AsBitmap())); | 
					
						
							| 
									
										
										
										
											2014-11-28 18:59:51 +08:00
										 |  |  |     icon_data.hBalloonIcon = balloon_icon_.Get(); | 
					
						
							|  |  |  |     icon_data.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON; | 
					
						
							| 
									
										
										
										
											2014-11-28 18:30:43 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data); | 
					
						
							|  |  |  |   if (!result) | 
					
						
							|  |  |  |     LOG(WARNING) << "Unable to create status tray balloon."; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-03 11:25:09 +08:00
										 |  |  | void NotifyIcon::SetContextMenu(ui::SimpleMenuModel* menu_model) { | 
					
						
							| 
									
										
										
										
											2014-06-03 11:52:57 +08:00
										 |  |  |   menu_model_ = menu_model; | 
					
						
							| 
									
										
										
										
											2014-06-03 11:25:09 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void NotifyIcon::InitIconData(NOTIFYICONDATA* icon_data) { | 
					
						
							| 
									
										
										
										
											2014-11-28 18:59:51 +08:00
										 |  |  |   memset(icon_data, 0, sizeof(NOTIFYICONDATA)); | 
					
						
							|  |  |  |   icon_data->cbSize = sizeof(NOTIFYICONDATA); | 
					
						
							| 
									
										
										
										
											2014-06-03 11:25:09 +08:00
										 |  |  |   icon_data->hWnd = window_; | 
					
						
							|  |  |  |   icon_data->uID = icon_id_; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }  // namespace atom
 |