notify_icon_host.cc 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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_host.h"
  5. #include <commctrl.h>
  6. #include <winuser.h>
  7. #include "atom/browser/ui/win/notify_icon.h"
  8. #include "base/bind.h"
  9. #include "base/stl_util.h"
  10. #include "base/win/win_util.h"
  11. #include "base/win/wrapped_window_proc.h"
  12. #include "ui/events/event_constants.h"
  13. #include "ui/events/win/system_event_state_lookup.h"
  14. #include "ui/gfx/win/hwnd_util.h"
  15. namespace atom {
  16. namespace {
  17. const UINT kNotifyIconMessage = WM_APP + 1;
  18. // |kBaseIconId| is 2 to avoid conflicts with plugins that hard-code id 1.
  19. const UINT kBaseIconId = 2;
  20. const wchar_t kNotifyIconHostWindowClass[] = L"Electron_NotifyIconHostWindow";
  21. bool IsWinPressed() {
  22. return ((::GetKeyState(VK_LWIN) & 0x8000) == 0x8000) ||
  23. ((::GetKeyState(VK_RWIN) & 0x8000) == 0x8000);
  24. }
  25. int GetKeyboardModifers() {
  26. int modifiers = ui::EF_NONE;
  27. if (ui::win::IsShiftPressed())
  28. modifiers |= ui::EF_SHIFT_DOWN;
  29. if (ui::win::IsCtrlPressed())
  30. modifiers |= ui::EF_CONTROL_DOWN;
  31. if (ui::win::IsAltPressed())
  32. modifiers |= ui::EF_ALT_DOWN;
  33. if (IsWinPressed())
  34. modifiers |= ui::EF_COMMAND_DOWN;
  35. return modifiers;
  36. }
  37. } // namespace
  38. NotifyIconHost::NotifyIconHost() {
  39. // Register our window class
  40. WNDCLASSEX window_class;
  41. base::win::InitializeWindowClass(
  42. kNotifyIconHostWindowClass,
  43. &base::win::WrappedWindowProc<NotifyIconHost::WndProcStatic>, 0, 0, 0,
  44. NULL, NULL, NULL, NULL, NULL, &window_class);
  45. instance_ = window_class.hInstance;
  46. atom_ = RegisterClassEx(&window_class);
  47. CHECK(atom_);
  48. // If the taskbar is re-created after we start up, we have to rebuild all of
  49. // our icons.
  50. taskbar_created_message_ = RegisterWindowMessage(TEXT("TaskbarCreated"));
  51. // Create an offscreen window for handling messages for the status icons. We
  52. // create a hidden WS_POPUP window instead of an HWND_MESSAGE window, because
  53. // only top-level windows such as popups can receive broadcast messages like
  54. // "TaskbarCreated".
  55. window_ = CreateWindow(MAKEINTATOM(atom_), 0, WS_POPUP, 0, 0, 0, 0, 0, 0,
  56. instance_, 0);
  57. gfx::CheckWindowCreated(window_);
  58. gfx::SetWindowUserData(window_, this);
  59. }
  60. NotifyIconHost::~NotifyIconHost() {
  61. if (window_)
  62. DestroyWindow(window_);
  63. if (atom_)
  64. UnregisterClass(MAKEINTATOM(atom_), instance_);
  65. for (NotifyIcon* ptr : notify_icons_)
  66. delete ptr;
  67. }
  68. NotifyIcon* NotifyIconHost::CreateNotifyIcon() {
  69. NotifyIcon* notify_icon =
  70. new NotifyIcon(this, NextIconId(), window_, kNotifyIconMessage);
  71. notify_icons_.push_back(notify_icon);
  72. return notify_icon;
  73. }
  74. void NotifyIconHost::Remove(NotifyIcon* icon) {
  75. NotifyIcons::iterator i(
  76. std::find(notify_icons_.begin(), notify_icons_.end(), icon));
  77. if (i == notify_icons_.end()) {
  78. NOTREACHED();
  79. return;
  80. }
  81. notify_icons_.erase(i);
  82. }
  83. LRESULT CALLBACK NotifyIconHost::WndProcStatic(HWND hwnd,
  84. UINT message,
  85. WPARAM wparam,
  86. LPARAM lparam) {
  87. NotifyIconHost* msg_wnd =
  88. reinterpret_cast<NotifyIconHost*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
  89. if (msg_wnd)
  90. return msg_wnd->WndProc(hwnd, message, wparam, lparam);
  91. else
  92. return ::DefWindowProc(hwnd, message, wparam, lparam);
  93. }
  94. LRESULT CALLBACK NotifyIconHost::WndProc(HWND hwnd,
  95. UINT message,
  96. WPARAM wparam,
  97. LPARAM lparam) {
  98. if (message == taskbar_created_message_) {
  99. // We need to reset all of our icons because the taskbar went away.
  100. for (NotifyIcons::const_iterator i(notify_icons_.begin());
  101. i != notify_icons_.end(); ++i) {
  102. NotifyIcon* win_icon = static_cast<NotifyIcon*>(*i);
  103. win_icon->ResetIcon();
  104. }
  105. return TRUE;
  106. } else if (message == kNotifyIconMessage) {
  107. NotifyIcon* win_icon = NULL;
  108. // Find the selected status icon.
  109. for (NotifyIcons::const_iterator i(notify_icons_.begin());
  110. i != notify_icons_.end(); ++i) {
  111. NotifyIcon* current_win_icon = static_cast<NotifyIcon*>(*i);
  112. if (current_win_icon->icon_id() == wparam) {
  113. win_icon = current_win_icon;
  114. break;
  115. }
  116. }
  117. // It is possible for this procedure to be called with an obsolete icon
  118. // id. In that case we should just return early before handling any
  119. // actions.
  120. if (!win_icon)
  121. return TRUE;
  122. switch (lparam) {
  123. case TB_CHECKBUTTON:
  124. win_icon->NotifyBalloonShow();
  125. return TRUE;
  126. case TB_INDETERMINATE:
  127. win_icon->NotifyBalloonClicked();
  128. return TRUE;
  129. case TB_HIDEBUTTON:
  130. win_icon->NotifyBalloonClosed();
  131. return TRUE;
  132. case WM_LBUTTONDOWN:
  133. case WM_RBUTTONDOWN:
  134. case WM_LBUTTONDBLCLK:
  135. case WM_RBUTTONDBLCLK:
  136. case WM_CONTEXTMENU:
  137. // Walk our icons, find which one was clicked on, and invoke its
  138. // HandleClickEvent() method.
  139. win_icon->HandleClickEvent(
  140. GetKeyboardModifers(),
  141. (lparam == WM_LBUTTONDOWN || lparam == WM_LBUTTONDBLCLK),
  142. (lparam == WM_LBUTTONDBLCLK || lparam == WM_RBUTTONDBLCLK));
  143. return TRUE;
  144. }
  145. }
  146. return ::DefWindowProc(hwnd, message, wparam, lparam);
  147. }
  148. UINT NotifyIconHost::NextIconId() {
  149. UINT icon_id = next_icon_id_++;
  150. return kBaseIconId + icon_id;
  151. }
  152. } // namespace atom