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.

205 lines
7.2KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. // (these functions are from juce_win32_Windowing.cpp)
  18. extern void* getUser32Function (const char*);
  19. namespace IconConverters
  20. {
  21. extern HICON createHICONFromImage (const Image&, BOOL isIcon, int hotspotX, int hotspotY);
  22. }
  23. //==============================================================================
  24. class SystemTrayIconComponent::Pimpl
  25. {
  26. public:
  27. Pimpl (SystemTrayIconComponent& owner_, HICON hicon, HWND hwnd)
  28. : owner (owner_),
  29. originalWndProc ((WNDPROC) GetWindowLongPtr (hwnd, GWLP_WNDPROC)),
  30. taskbarCreatedMessage (RegisterWindowMessage (TEXT ("TaskbarCreated")))
  31. {
  32. SetWindowLongPtr (hwnd, GWLP_WNDPROC, (LONG_PTR) hookedWndProc);
  33. zerostruct (iconData);
  34. iconData.cbSize = sizeof (iconData);
  35. iconData.hWnd = hwnd;
  36. iconData.uID = (UINT) (pointer_sized_int) hwnd;
  37. iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  38. iconData.uCallbackMessage = WM_TRAYNOTIFY;
  39. iconData.hIcon = hicon;
  40. Shell_NotifyIcon (NIM_ADD, &iconData);
  41. // In order to receive the "TaskbarCreated" message, we need to request that it's not filtered out.
  42. // (Need to load dynamically, as ChangeWindowMessageFilter is only available in Vista and later)
  43. typedef BOOL (WINAPI* ChangeWindowMessageFilterType) (UINT, DWORD);
  44. if (ChangeWindowMessageFilterType changeWindowMessageFilter
  45. = (ChangeWindowMessageFilterType) getUser32Function ("ChangeWindowMessageFilter"))
  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. if (Component* const current = Component::getCurrentlyModalComponent())
  77. current->inputAttemptWhenModal();
  78. }
  79. }
  80. else
  81. {
  82. ModifierKeys eventMods (ModifierKeys::getCurrentModifiersRealtime());
  83. if (lParam == WM_LBUTTONDOWN || lParam == WM_LBUTTONDBLCLK)
  84. eventMods = eventMods.withFlags (ModifierKeys::leftButtonModifier);
  85. else if (lParam == WM_RBUTTONDOWN || lParam == WM_RBUTTONDBLCLK)
  86. eventMods = eventMods.withFlags (ModifierKeys::rightButtonModifier);
  87. else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP)
  88. eventMods = eventMods.withoutMouseButtons();
  89. const Time eventTime (getMouseEventTime());
  90. const MouseEvent e (Desktop::getInstance().getMainMouseSource(),
  91. Point<int>(), eventMods, &owner, &owner, eventTime,
  92. Point<int>(), eventTime, 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. if (ComponentPeer* peer = (ComponentPeer*) GetWindowLongPtr (hwnd, 8))
  117. if (SystemTrayIconComponent* const iconComp = dynamic_cast<SystemTrayIconComponent*> (&(peer->getComponent())))
  118. return iconComp->pimpl;
  119. return nullptr;
  120. }
  121. static LRESULT CALLBACK hookedWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  122. {
  123. if (Pimpl* const p = getPimpl (hwnd))
  124. return p->windowProc (hwnd, message, wParam, lParam);
  125. return DefWindowProcW (hwnd, message, wParam, lParam);
  126. }
  127. LRESULT windowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  128. {
  129. if (message == WM_TRAYNOTIFY)
  130. {
  131. handleTaskBarEvent (lParam);
  132. }
  133. else if (message == taskbarCreatedMessage)
  134. {
  135. iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  136. Shell_NotifyIcon (NIM_ADD, &iconData);
  137. }
  138. return CallWindowProc (originalWndProc, hwnd, message, wParam, lParam);
  139. }
  140. private:
  141. SystemTrayIconComponent& owner;
  142. NOTIFYICONDATA iconData;
  143. WNDPROC originalWndProc;
  144. const DWORD taskbarCreatedMessage;
  145. enum { WM_TRAYNOTIFY = WM_USER + 100 };
  146. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  147. };
  148. //==============================================================================
  149. void SystemTrayIconComponent::setIconImage (const Image& newImage)
  150. {
  151. if (newImage.isValid())
  152. {
  153. HICON hicon = IconConverters::createHICONFromImage (newImage, TRUE, 0, 0);
  154. if (pimpl == nullptr)
  155. pimpl = new Pimpl (*this, hicon, (HWND) getWindowHandle());
  156. else
  157. pimpl->updateIcon (hicon);
  158. }
  159. else
  160. {
  161. pimpl = nullptr;
  162. }
  163. }
  164. void SystemTrayIconComponent::setIconTooltip (const String& tooltip)
  165. {
  166. if (pimpl != nullptr)
  167. pimpl->setToolTip (tooltip);
  168. }