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.

217 lines
7.6KB

  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. // (these functions are from juce_win32_Windowing.cpp)
  19. extern void* getUser32Function (const char*);
  20. namespace IconConverters
  21. {
  22. extern HICON createHICONFromImage (const Image&, BOOL isIcon, int hotspotX, int hotspotY);
  23. }
  24. //==============================================================================
  25. class SystemTrayIconComponent::Pimpl
  26. {
  27. public:
  28. Pimpl (SystemTrayIconComponent& owner_, HICON hicon, HWND hwnd)
  29. : owner (owner_),
  30. originalWndProc ((WNDPROC) GetWindowLongPtr (hwnd, GWLP_WNDPROC)),
  31. taskbarCreatedMessage (RegisterWindowMessage (TEXT ("TaskbarCreated")))
  32. {
  33. SetWindowLongPtr (hwnd, GWLP_WNDPROC, (LONG_PTR) hookedWndProc);
  34. zerostruct (iconData);
  35. iconData.cbSize = sizeof (iconData);
  36. iconData.hWnd = hwnd;
  37. iconData.uID = (UINT) (pointer_sized_int) hwnd;
  38. iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  39. iconData.uCallbackMessage = WM_TRAYNOTIFY;
  40. iconData.hIcon = hicon;
  41. Shell_NotifyIcon (NIM_ADD, &iconData);
  42. // In order to receive the "TaskbarCreated" message, we need to request that it's not filtered out.
  43. // (Need to load dynamically, as ChangeWindowMessageFilter is only available in Vista and later)
  44. typedef BOOL (WINAPI* ChangeWindowMessageFilterType) (UINT, DWORD);
  45. ChangeWindowMessageFilterType changeWindowMessageFilter
  46. = (ChangeWindowMessageFilterType) getUser32Function ("ChangeWindowMessageFilter");
  47. if (changeWindowMessageFilter != nullptr)
  48. changeWindowMessageFilter (taskbarCreatedMessage, 1 /* MSGFLT_ADD */);
  49. }
  50. ~Pimpl()
  51. {
  52. SetWindowLongPtr (iconData.hWnd, GWLP_WNDPROC, (LONG_PTR) originalWndProc);
  53. iconData.uFlags = 0;
  54. Shell_NotifyIcon (NIM_DELETE, &iconData);
  55. DestroyIcon (iconData.hIcon);
  56. }
  57. void updateIcon (HICON hicon)
  58. {
  59. HICON oldIcon = iconData.hIcon;
  60. iconData.hIcon = hicon;
  61. iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  62. Shell_NotifyIcon (NIM_MODIFY, &iconData);
  63. DestroyIcon (oldIcon);
  64. }
  65. void setToolTip (const String& toolTip)
  66. {
  67. iconData.uFlags = NIF_TIP;
  68. toolTip.copyToUTF16 (iconData.szTip, sizeof (iconData.szTip) - 1);
  69. Shell_NotifyIcon (NIM_MODIFY, &iconData);
  70. }
  71. void handleTaskBarEvent (const LPARAM lParam)
  72. {
  73. if (owner.isCurrentlyBlockedByAnotherModalComponent())
  74. {
  75. if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN
  76. || lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK)
  77. {
  78. Component* const current = Component::getCurrentlyModalComponent();
  79. if (current != nullptr)
  80. current->inputAttemptWhenModal();
  81. }
  82. }
  83. else
  84. {
  85. ModifierKeys eventMods (ModifierKeys::getCurrentModifiersRealtime());
  86. if (lParam == WM_LBUTTONDOWN || lParam == WM_LBUTTONDBLCLK)
  87. eventMods = eventMods.withFlags (ModifierKeys::leftButtonModifier);
  88. else if (lParam == WM_RBUTTONDOWN || lParam == WM_RBUTTONDBLCLK)
  89. eventMods = eventMods.withFlags (ModifierKeys::rightButtonModifier);
  90. else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP)
  91. eventMods = eventMods.withoutMouseButtons();
  92. const MouseEvent e (Desktop::getInstance().getMainMouseSource(),
  93. Point<int>(), eventMods, &owner, &owner, Time (getMouseEventTime()),
  94. Point<int>(), Time (getMouseEventTime()), 1, false);
  95. if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN)
  96. {
  97. SetFocus (iconData.hWnd);
  98. SetForegroundWindow (iconData.hWnd);
  99. owner.mouseDown (e);
  100. }
  101. else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP)
  102. {
  103. owner.mouseUp (e);
  104. }
  105. else if (lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK)
  106. {
  107. owner.mouseDoubleClick (e);
  108. }
  109. else if (lParam == WM_MOUSEMOVE)
  110. {
  111. owner.mouseMove (e);
  112. }
  113. }
  114. }
  115. static Pimpl* getPimpl (HWND hwnd)
  116. {
  117. if (JuceWindowIdentifier::isJUCEWindow (hwnd))
  118. {
  119. ComponentPeer* peer = (ComponentPeer*) GetWindowLongPtr (hwnd, 8);
  120. if (peer != nullptr)
  121. {
  122. SystemTrayIconComponent* const iconComp = dynamic_cast<SystemTrayIconComponent*> (&(peer->getComponent()));
  123. if (iconComp != nullptr)
  124. return iconComp->pimpl;
  125. }
  126. }
  127. return nullptr;
  128. }
  129. static LRESULT CALLBACK hookedWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  130. {
  131. Pimpl* const p = getPimpl (hwnd);
  132. if (p != nullptr)
  133. return p->windowProc (hwnd, message, wParam, lParam);
  134. else
  135. return DefWindowProcW (hwnd, message, wParam, lParam);
  136. }
  137. LRESULT windowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  138. {
  139. if (message == WM_TRAYNOTIFY)
  140. {
  141. handleTaskBarEvent (lParam);
  142. }
  143. else if (message == taskbarCreatedMessage)
  144. {
  145. iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  146. Shell_NotifyIcon (NIM_ADD, &iconData);
  147. }
  148. return CallWindowProc (originalWndProc, hwnd, message, wParam, lParam);
  149. }
  150. private:
  151. SystemTrayIconComponent& owner;
  152. NOTIFYICONDATA iconData;
  153. WNDPROC originalWndProc;
  154. const DWORD taskbarCreatedMessage;
  155. enum { WM_TRAYNOTIFY = WM_USER + 100 };
  156. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl);
  157. };
  158. //==============================================================================
  159. void SystemTrayIconComponent::setIconImage (const Image& newImage)
  160. {
  161. if (newImage.isValid())
  162. {
  163. HICON hicon = IconConverters::createHICONFromImage (newImage, TRUE, 0, 0);
  164. if (pimpl == nullptr)
  165. pimpl = new Pimpl (*this, hicon, (HWND) getWindowHandle());
  166. else
  167. pimpl->updateIcon (hicon);
  168. }
  169. else
  170. {
  171. pimpl = nullptr;
  172. }
  173. }
  174. void SystemTrayIconComponent::setIconTooltip (const String& tooltip)
  175. {
  176. if (pimpl != nullptr)
  177. pimpl->setToolTip (tooltip);
  178. }