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.

206 lines
7.4KB

  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. if (ChangeWindowMessageFilterType changeWindowMessageFilter
  46. = (ChangeWindowMessageFilterType) getUser32Function ("ChangeWindowMessageFilter"))
  47. changeWindowMessageFilter (taskbarCreatedMessage, 1 /* MSGFLT_ADD */);
  48. }
  49. ~Pimpl()
  50. {
  51. SetWindowLongPtr (iconData.hWnd, GWLP_WNDPROC, (LONG_PTR) originalWndProc);
  52. iconData.uFlags = 0;
  53. Shell_NotifyIcon (NIM_DELETE, &iconData);
  54. DestroyIcon (iconData.hIcon);
  55. }
  56. void updateIcon (HICON hicon)
  57. {
  58. HICON oldIcon = iconData.hIcon;
  59. iconData.hIcon = hicon;
  60. iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  61. Shell_NotifyIcon (NIM_MODIFY, &iconData);
  62. DestroyIcon (oldIcon);
  63. }
  64. void setToolTip (const String& toolTip)
  65. {
  66. iconData.uFlags = NIF_TIP;
  67. toolTip.copyToUTF16 (iconData.szTip, sizeof (iconData.szTip) - 1);
  68. Shell_NotifyIcon (NIM_MODIFY, &iconData);
  69. }
  70. void handleTaskBarEvent (const LPARAM lParam)
  71. {
  72. if (owner.isCurrentlyBlockedByAnotherModalComponent())
  73. {
  74. if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN
  75. || lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK)
  76. {
  77. if (Component* const current = Component::getCurrentlyModalComponent())
  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 Time eventTime (getMouseEventTime());
  91. const MouseEvent e (Desktop::getInstance().getMainMouseSource(),
  92. Point<int>(), eventMods, &owner, &owner, eventTime,
  93. Point<int>(), eventTime, 1, false);
  94. if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN)
  95. {
  96. SetFocus (iconData.hWnd);
  97. SetForegroundWindow (iconData.hWnd);
  98. owner.mouseDown (e);
  99. }
  100. else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP)
  101. {
  102. owner.mouseUp (e);
  103. }
  104. else if (lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK)
  105. {
  106. owner.mouseDoubleClick (e);
  107. }
  108. else if (lParam == WM_MOUSEMOVE)
  109. {
  110. owner.mouseMove (e);
  111. }
  112. }
  113. }
  114. static Pimpl* getPimpl (HWND hwnd)
  115. {
  116. if (JuceWindowIdentifier::isJUCEWindow (hwnd))
  117. if (ComponentPeer* peer = (ComponentPeer*) GetWindowLongPtr (hwnd, 8))
  118. if (SystemTrayIconComponent* const iconComp = dynamic_cast<SystemTrayIconComponent*> (&(peer->getComponent())))
  119. return iconComp->pimpl;
  120. return nullptr;
  121. }
  122. static LRESULT CALLBACK hookedWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  123. {
  124. if (Pimpl* const p = getPimpl (hwnd))
  125. return p->windowProc (hwnd, message, wParam, lParam);
  126. return DefWindowProcW (hwnd, message, wParam, lParam);
  127. }
  128. LRESULT windowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  129. {
  130. if (message == WM_TRAYNOTIFY)
  131. {
  132. handleTaskBarEvent (lParam);
  133. }
  134. else if (message == taskbarCreatedMessage)
  135. {
  136. iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  137. Shell_NotifyIcon (NIM_ADD, &iconData);
  138. }
  139. return CallWindowProc (originalWndProc, hwnd, message, wParam, lParam);
  140. }
  141. private:
  142. SystemTrayIconComponent& owner;
  143. NOTIFYICONDATA iconData;
  144. WNDPROC originalWndProc;
  145. const DWORD taskbarCreatedMessage;
  146. enum { WM_TRAYNOTIFY = WM_USER + 100 };
  147. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  148. };
  149. //==============================================================================
  150. void SystemTrayIconComponent::setIconImage (const Image& newImage)
  151. {
  152. if (newImage.isValid())
  153. {
  154. HICON hicon = IconConverters::createHICONFromImage (newImage, TRUE, 0, 0);
  155. if (pimpl == nullptr)
  156. pimpl = new Pimpl (*this, hicon, (HWND) getWindowHandle());
  157. else
  158. pimpl->updateIcon (hicon);
  159. }
  160. else
  161. {
  162. pimpl = nullptr;
  163. }
  164. }
  165. void SystemTrayIconComponent::setIconTooltip (const String& tooltip)
  166. {
  167. if (pimpl != nullptr)
  168. pimpl->setToolTip (tooltip);
  169. }