The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

222 lines
7.7KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. namespace IconConverters
  19. {
  20. extern HICON createHICONFromImage (const Image& image, const BOOL isIcon, int hotspotX, int hotspotY);
  21. }
  22. //==============================================================================
  23. class SystemTrayIconComponent::Pimpl
  24. {
  25. public:
  26. Pimpl (SystemTrayIconComponent& owner_, HICON hicon, HWND hwnd)
  27. : owner (owner_),
  28. originalWndProc ((WNDPROC) GetWindowLongPtr (hwnd, GWLP_WNDPROC)),
  29. taskbarCreatedMessage (RegisterWindowMessage (TEXT ("TaskbarCreated")))
  30. {
  31. SetWindowLongPtr (hwnd, GWLP_WNDPROC, (LONG_PTR) hookedWndProc);
  32. zerostruct (iconData);
  33. iconData.cbSize = sizeof (iconData);
  34. iconData.hWnd = hwnd;
  35. iconData.uID = (UINT) (pointer_sized_int) hwnd;
  36. iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  37. iconData.uCallbackMessage = WM_TRAYNOTIFY;
  38. iconData.hIcon = hicon;
  39. Shell_NotifyIcon (NIM_ADD, &iconData);
  40. // In order to receive the "TaskbarCreated" message, we need to request that it's not filtered out.
  41. // (Need to load dynamically, as ChangeWindowMessageFilter is only available in Vista and later)
  42. typedef BOOL (WINAPI* ChangeWindowMessageFilterType) (UINT, DWORD);
  43. ChangeWindowMessageFilterType changeWindowMessageFilter
  44. = (ChangeWindowMessageFilterType) getUser32Function ("ChangeWindowMessageFilter");
  45. if (changeWindowMessageFilter != nullptr)
  46. changeWindowMessageFilter (taskbarCreatedMessage, 1 /* MSGFLT_ADD */);
  47. }
  48. ~Pimpl()
  49. {
  50. SetWindowLongPtr (iconData.hWnd, GWLP_WNDPROC, (LONG_PTR) originalWndProc);
  51. iconData.uFlags = 0;
  52. Shell_NotifyIcon (NIM_DELETE, &iconData);
  53. DestroyIcon (iconData.hIcon);
  54. }
  55. void updateIcon (HICON hicon)
  56. {
  57. HICON oldIcon = iconData.hIcon;
  58. iconData.hIcon = hicon;
  59. iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  60. Shell_NotifyIcon (NIM_MODIFY, &iconData);
  61. DestroyIcon (oldIcon);
  62. }
  63. void setToolTip (const String& toolTip)
  64. {
  65. iconData.uFlags = NIF_TIP;
  66. toolTip.copyToUTF16 (iconData.szTip, sizeof (iconData.szTip) - 1);
  67. Shell_NotifyIcon (NIM_MODIFY, &iconData);
  68. }
  69. void handleTaskBarEvent (const LPARAM lParam)
  70. {
  71. if (owner.isCurrentlyBlockedByAnotherModalComponent())
  72. {
  73. if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN
  74. || lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK)
  75. {
  76. Component* const current = Component::getCurrentlyModalComponent();
  77. if (current != nullptr)
  78. current->inputAttemptWhenModal();
  79. }
  80. }
  81. else
  82. {
  83. ModifierKeys eventMods (ModifierKeys::getCurrentModifiersRealtime());
  84. if (lParam == WM_LBUTTONDOWN || lParam == WM_LBUTTONDBLCLK)
  85. eventMods = eventMods.withFlags (ModifierKeys::leftButtonModifier);
  86. else if (lParam == WM_RBUTTONDOWN || lParam == WM_RBUTTONDBLCLK)
  87. eventMods = eventMods.withFlags (ModifierKeys::rightButtonModifier);
  88. else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP)
  89. eventMods = eventMods.withoutMouseButtons();
  90. const MouseEvent e (Desktop::getInstance().getMainMouseSource(),
  91. Point<int>(), eventMods, &owner, &owner, Time (getMouseEventTime()),
  92. Point<int>(), Time (getMouseEventTime()), 1, false);
  93. if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN)
  94. {
  95. SetFocus (iconData.hWnd);
  96. SetForegroundWindow (iconData.hWnd);
  97. owner.mouseDown (e);
  98. }
  99. else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP)
  100. {
  101. owner.mouseUp (e);
  102. }
  103. else if (lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK)
  104. {
  105. owner.mouseDoubleClick (e);
  106. }
  107. else if (lParam == WM_MOUSEMOVE)
  108. {
  109. owner.mouseMove (e);
  110. }
  111. }
  112. }
  113. static Pimpl* getPimpl (HWND hwnd)
  114. {
  115. if (JuceWindowIdentifier::isJUCEWindow (hwnd))
  116. {
  117. ComponentPeer* peer = (ComponentPeer*) GetWindowLongPtr (hwnd, 8);
  118. if (peer != nullptr)
  119. {
  120. SystemTrayIconComponent* const iconComp = dynamic_cast<SystemTrayIconComponent*> (peer->getComponent());
  121. if (iconComp != nullptr)
  122. return iconComp->pimpl;
  123. }
  124. }
  125. return nullptr;
  126. }
  127. static LRESULT CALLBACK hookedWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  128. {
  129. Pimpl* const p = getPimpl (hwnd);
  130. if (p != nullptr)
  131. return p->windowProc (hwnd, message, wParam, lParam);
  132. else
  133. return DefWindowProcW (hwnd, message, wParam, lParam);
  134. }
  135. LRESULT windowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  136. {
  137. if (message == WM_TRAYNOTIFY)
  138. {
  139. handleTaskBarEvent (lParam);
  140. }
  141. else if (message == taskbarCreatedMessage)
  142. {
  143. iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  144. Shell_NotifyIcon (NIM_ADD, &iconData);
  145. }
  146. return CallWindowProc (originalWndProc, hwnd, message, wParam, lParam);
  147. }
  148. private:
  149. SystemTrayIconComponent& owner;
  150. NOTIFYICONDATA iconData;
  151. WNDPROC originalWndProc;
  152. const DWORD taskbarCreatedMessage;
  153. enum { WM_TRAYNOTIFY = WM_USER + 100 };
  154. static void* getUser32Function (const char* functionName)
  155. {
  156. HMODULE user32Mod = GetModuleHandle (_T("user32.dll"));
  157. jassert (user32Mod != 0);
  158. return GetProcAddress (user32Mod, functionName);
  159. }
  160. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl);
  161. };
  162. //==============================================================================
  163. void SystemTrayIconComponent::setIconImage (const Image& newImage)
  164. {
  165. if (newImage.isValid())
  166. {
  167. HICON hicon = IconConverters::createHICONFromImage (newImage, TRUE, 0, 0);
  168. if (pimpl == nullptr)
  169. pimpl = new Pimpl (*this, hicon, (HWND) getWindowHandle());
  170. else
  171. pimpl->updateIcon (hicon);
  172. }
  173. else
  174. {
  175. pimpl = nullptr;
  176. }
  177. }
  178. void SystemTrayIconComponent::setIconTooltip (const String& tooltip)
  179. {
  180. if (pimpl != nullptr)
  181. pimpl->setToolTip (tooltip);
  182. }