notify_icon.cc 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. // Copyright (c) 2014 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "atom/browser/ui/win/notify_icon.h"
  5. #include "atom/browser/ui/win/notify_icon_host.h"
  6. #include "base/strings/string_number_conversions.h"
  7. #include "base/strings/utf_string_conversions.h"
  8. #include "base/win/windows_version.h"
  9. #include "third_party/skia/include/core/SkBitmap.h"
  10. #include "ui/display/screen.h"
  11. #include "ui/display/win/screen_win.h"
  12. #include "ui/gfx/geometry/point.h"
  13. #include "ui/gfx/geometry/rect.h"
  14. #include "ui/gfx/image/image.h"
  15. #include "ui/views/controls/menu/menu_runner.h"
  16. namespace atom {
  17. NotifyIcon::NotifyIcon(NotifyIconHost* host, UINT id, HWND window, UINT message)
  18. : host_(host), icon_id_(id), window_(window), message_id_(message) {
  19. NOTIFYICONDATA icon_data;
  20. InitIconData(&icon_data);
  21. icon_data.uFlags |= NIF_MESSAGE;
  22. icon_data.uCallbackMessage = message_id_;
  23. BOOL result = Shell_NotifyIcon(NIM_ADD, &icon_data);
  24. // This can happen if the explorer process isn't running when we try to
  25. // create the icon for some reason (for example, at startup).
  26. if (!result)
  27. LOG(WARNING) << "Unable to create status tray icon.";
  28. }
  29. NotifyIcon::~NotifyIcon() {
  30. // Remove our icon.
  31. host_->Remove(this);
  32. NOTIFYICONDATA icon_data;
  33. InitIconData(&icon_data);
  34. Shell_NotifyIcon(NIM_DELETE, &icon_data);
  35. }
  36. void NotifyIcon::HandleClickEvent(int modifiers,
  37. bool left_mouse_click,
  38. bool double_button_click) {
  39. gfx::Rect bounds = GetBounds();
  40. if (left_mouse_click) {
  41. if (double_button_click) // double left click
  42. NotifyDoubleClicked(bounds, modifiers);
  43. else // single left click
  44. NotifyClicked(bounds,
  45. display::Screen::GetScreen()->GetCursorScreenPoint(),
  46. modifiers);
  47. return;
  48. } else if (!double_button_click) { // single right click
  49. if (menu_model_)
  50. PopUpContextMenu(gfx::Point(), menu_model_);
  51. else
  52. NotifyRightClicked(bounds, modifiers);
  53. }
  54. }
  55. void NotifyIcon::ResetIcon() {
  56. NOTIFYICONDATA icon_data;
  57. InitIconData(&icon_data);
  58. // Delete any previously existing icon.
  59. Shell_NotifyIcon(NIM_DELETE, &icon_data);
  60. InitIconData(&icon_data);
  61. icon_data.uFlags |= NIF_MESSAGE;
  62. icon_data.uCallbackMessage = message_id_;
  63. icon_data.hIcon = icon_.get();
  64. // If we have an image, then set the NIF_ICON flag, which tells
  65. // Shell_NotifyIcon() to set the image for the status icon it creates.
  66. if (icon_data.hIcon)
  67. icon_data.uFlags |= NIF_ICON;
  68. // Re-add our icon.
  69. BOOL result = Shell_NotifyIcon(NIM_ADD, &icon_data);
  70. if (!result)
  71. LOG(WARNING) << "Unable to re-create status tray icon.";
  72. }
  73. void NotifyIcon::SetImage(HICON image) {
  74. icon_ = base::win::ScopedHICON(CopyIcon(image));
  75. // Create the icon.
  76. NOTIFYICONDATA icon_data;
  77. InitIconData(&icon_data);
  78. icon_data.uFlags |= NIF_ICON;
  79. icon_data.hIcon = image;
  80. BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data);
  81. if (!result)
  82. LOG(WARNING) << "Error setting status tray icon image";
  83. }
  84. void NotifyIcon::SetPressedImage(HICON image) {
  85. // Ignore pressed images, since the standard on Windows is to not highlight
  86. // pressed status icons.
  87. }
  88. void NotifyIcon::SetToolTip(const std::string& tool_tip) {
  89. // Create the icon.
  90. NOTIFYICONDATA icon_data;
  91. InitIconData(&icon_data);
  92. icon_data.uFlags |= NIF_TIP;
  93. wcsncpy_s(icon_data.szTip, base::UTF8ToUTF16(tool_tip).c_str(), _TRUNCATE);
  94. BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data);
  95. if (!result)
  96. LOG(WARNING) << "Unable to set tooltip for status tray icon";
  97. }
  98. void NotifyIcon::DisplayBalloon(HICON icon,
  99. const base::string16& title,
  100. const base::string16& contents) {
  101. NOTIFYICONDATA icon_data;
  102. InitIconData(&icon_data);
  103. icon_data.uFlags |= NIF_INFO;
  104. icon_data.dwInfoFlags = NIIF_INFO;
  105. wcsncpy_s(icon_data.szInfoTitle, title.c_str(), _TRUNCATE);
  106. wcsncpy_s(icon_data.szInfo, contents.c_str(), _TRUNCATE);
  107. icon_data.uTimeout = 0;
  108. icon_data.hBalloonIcon = icon;
  109. icon_data.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON;
  110. BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data);
  111. if (!result)
  112. LOG(WARNING) << "Unable to create status tray balloon.";
  113. }
  114. void NotifyIcon::PopUpContextMenu(const gfx::Point& pos,
  115. AtomMenuModel* menu_model) {
  116. // Returns if context menu isn't set.
  117. if (menu_model == nullptr && menu_model_ == nullptr)
  118. return;
  119. // Set our window as the foreground window, so the context menu closes when
  120. // we click away from it.
  121. if (!SetForegroundWindow(window_))
  122. return;
  123. // Show menu at mouse's position by default.
  124. gfx::Rect rect(pos, gfx::Size());
  125. if (pos.IsOrigin())
  126. rect.set_origin(display::Screen::GetScreen()->GetCursorScreenPoint());
  127. menu_runner_.reset(new views::MenuRunner(
  128. menu_model != nullptr ? menu_model : menu_model_,
  129. views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS));
  130. menu_runner_->RunMenuAt(NULL, NULL, rect, views::MENU_ANCHOR_TOPLEFT,
  131. ui::MENU_SOURCE_MOUSE);
  132. }
  133. void NotifyIcon::SetContextMenu(AtomMenuModel* menu_model) {
  134. menu_model_ = menu_model;
  135. }
  136. gfx::Rect NotifyIcon::GetBounds() {
  137. NOTIFYICONIDENTIFIER icon_id;
  138. memset(&icon_id, 0, sizeof(NOTIFYICONIDENTIFIER));
  139. icon_id.uID = icon_id_;
  140. icon_id.hWnd = window_;
  141. icon_id.cbSize = sizeof(NOTIFYICONIDENTIFIER);
  142. RECT rect = {0};
  143. Shell_NotifyIconGetRect(&icon_id, &rect);
  144. return display::win::ScreenWin::ScreenToDIPRect(window_, gfx::Rect(rect));
  145. }
  146. void NotifyIcon::InitIconData(NOTIFYICONDATA* icon_data) {
  147. memset(icon_data, 0, sizeof(NOTIFYICONDATA));
  148. icon_data->cbSize = sizeof(NOTIFYICONDATA);
  149. icon_data->hWnd = window_;
  150. icon_data->uID = icon_id_;
  151. }
  152. } // namespace atom