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
6.9KB

  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. }
  41. ~Pimpl()
  42. {
  43. SetWindowLongPtr (iconData.hWnd, GWLP_WNDPROC, (LONG_PTR) originalWndProc);
  44. iconData.uFlags = 0;
  45. Shell_NotifyIcon (NIM_DELETE, &iconData);
  46. DestroyIcon (iconData.hIcon);
  47. }
  48. void updateIcon (HICON hicon)
  49. {
  50. HICON oldIcon = iconData.hIcon;
  51. iconData.hIcon = hicon;
  52. iconData.uFlags = NIF_ICON;
  53. Shell_NotifyIcon (NIM_MODIFY, &iconData);
  54. DestroyIcon (oldIcon);
  55. }
  56. void setToolTip (const String& toolTip)
  57. {
  58. iconData.uFlags = NIF_TIP;
  59. toolTip.copyToUTF16 (iconData.szTip, sizeof (iconData.szTip) - 1);
  60. Shell_NotifyIcon (NIM_MODIFY, &iconData);
  61. }
  62. void handleTaskBarEvent (const LPARAM lParam)
  63. {
  64. if (owner.isCurrentlyBlockedByAnotherModalComponent())
  65. {
  66. if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN
  67. || lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK)
  68. {
  69. Component* const current = Component::getCurrentlyModalComponent();
  70. if (current != nullptr)
  71. current->inputAttemptWhenModal();
  72. }
  73. }
  74. else
  75. {
  76. ModifierKeys eventMods (ModifierKeys::getCurrentModifiersRealtime());
  77. if (lParam == WM_LBUTTONDOWN || lParam == WM_LBUTTONDBLCLK)
  78. eventMods = eventMods.withFlags (ModifierKeys::leftButtonModifier);
  79. else if (lParam == WM_RBUTTONDOWN || lParam == WM_RBUTTONDBLCLK)
  80. eventMods = eventMods.withFlags (ModifierKeys::rightButtonModifier);
  81. else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP)
  82. eventMods = eventMods.withoutMouseButtons();
  83. const MouseEvent e (Desktop::getInstance().getMainMouseSource(),
  84. Point<int>(), eventMods, &owner, &owner, Time (getMouseEventTime()),
  85. Point<int>(), Time (getMouseEventTime()), 1, false);
  86. if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN)
  87. {
  88. SetFocus (iconData.hWnd);
  89. SetForegroundWindow (iconData.hWnd);
  90. owner.mouseDown (e);
  91. }
  92. else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP)
  93. {
  94. owner.mouseUp (e);
  95. }
  96. else if (lParam == WM_LBUTTONDBLCLK || lParam == WM_LBUTTONDBLCLK)
  97. {
  98. owner.mouseDoubleClick (e);
  99. }
  100. else if (lParam == WM_MOUSEMOVE)
  101. {
  102. owner.mouseMove (e);
  103. }
  104. }
  105. }
  106. static Pimpl* getPimpl (HWND hwnd)
  107. {
  108. if (JuceWindowIdentifier::isJUCEWindow (hwnd))
  109. {
  110. ComponentPeer* peer = (ComponentPeer*) GetWindowLongPtr (hwnd, 8);
  111. if (peer != nullptr)
  112. {
  113. SystemTrayIconComponent* const iconComp = dynamic_cast<SystemTrayIconComponent*> (peer->getComponent());
  114. if (iconComp != nullptr)
  115. return iconComp->pimpl;
  116. }
  117. }
  118. return nullptr;
  119. }
  120. static LRESULT CALLBACK hookedWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  121. {
  122. Pimpl* const p = getPimpl (hwnd);
  123. if (p != nullptr)
  124. return p->windowProc (hwnd, message, wParam, lParam);
  125. else
  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. }