Audio plugin host https://kx.studio/carla
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.

juce_mac_SystemTrayIcon.cpp 8.7KB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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. namespace MouseCursorHelpers
  18. {
  19. extern NSImage* createNSImage (const Image&);
  20. }
  21. class SystemTrayIconComponent::Pimpl
  22. {
  23. public:
  24. Pimpl (SystemTrayIconComponent& iconComp, const Image& im)
  25. : owner (iconComp), statusItem (nil),
  26. statusIcon (MouseCursorHelpers::createNSImage (im)),
  27. isHighlighted (false)
  28. {
  29. static SystemTrayViewClass cls;
  30. view = [cls.createInstance() init];
  31. SystemTrayViewClass::setOwner (view, this);
  32. SystemTrayViewClass::setImage (view, statusIcon);
  33. setIconSize();
  34. statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength: NSSquareStatusItemLength] retain];
  35. [statusItem setView: view];
  36. SystemTrayViewClass::frameChanged (view, SEL(), nullptr);
  37. [[NSNotificationCenter defaultCenter] addObserver: view
  38. selector: @selector (frameChanged:)
  39. name: NSWindowDidMoveNotification
  40. object: nil];
  41. }
  42. ~Pimpl()
  43. {
  44. [[NSNotificationCenter defaultCenter] removeObserver: view];
  45. [[NSStatusBar systemStatusBar] removeStatusItem: statusItem];
  46. SystemTrayViewClass::setOwner (view, nullptr);
  47. SystemTrayViewClass::setImage (view, nil);
  48. [statusItem release];
  49. [view release];
  50. [statusIcon release];
  51. }
  52. void updateIcon (const Image& newImage)
  53. {
  54. [statusIcon release];
  55. statusIcon = MouseCursorHelpers::createNSImage (newImage);
  56. setIconSize();
  57. SystemTrayViewClass::setImage (view, statusIcon);
  58. }
  59. void setHighlighted (bool shouldHighlight)
  60. {
  61. isHighlighted = shouldHighlight;
  62. [view setNeedsDisplay: true];
  63. }
  64. void handleStatusItemAction (NSEvent* e)
  65. {
  66. NSEventType type = [e type];
  67. const bool isLeft = (type == NSLeftMouseDown || type == NSLeftMouseUp);
  68. const bool isRight = (type == NSRightMouseDown || type == NSRightMouseUp);
  69. if (owner.isCurrentlyBlockedByAnotherModalComponent())
  70. {
  71. if (isLeft || isRight)
  72. if (Component* const current = Component::getCurrentlyModalComponent())
  73. current->inputAttemptWhenModal();
  74. }
  75. else
  76. {
  77. ModifierKeys eventMods (ModifierKeys::getCurrentModifiersRealtime());
  78. if (([e modifierFlags] & NSCommandKeyMask) != 0)
  79. eventMods = eventMods.withFlags (ModifierKeys::commandModifier);
  80. const Time now (Time::getCurrentTime());
  81. MouseInputSource mouseSource = Desktop::getInstance().getMainMouseSource();
  82. if (isLeft || isRight) // Only mouse up is sent by the OS, so simulate a down/up
  83. {
  84. owner.mouseDown (MouseEvent (mouseSource, Point<float>(),
  85. eventMods.withFlags (isLeft ? ModifierKeys::leftButtonModifier
  86. : ModifierKeys::rightButtonModifier),
  87. &owner, &owner, now,
  88. Point<float>(), now, 1, false));
  89. owner.mouseUp (MouseEvent (mouseSource, Point<float>(), eventMods.withoutMouseButtons(),
  90. &owner, &owner, now,
  91. Point<float>(), now, 1, false));
  92. }
  93. else if (type == NSMouseMoved)
  94. {
  95. owner.mouseMove (MouseEvent (mouseSource, Point<float>(), eventMods,
  96. &owner, &owner, now,
  97. Point<float>(), now, 1, false));
  98. }
  99. }
  100. }
  101. SystemTrayIconComponent& owner;
  102. NSStatusItem* statusItem;
  103. private:
  104. NSImage* statusIcon;
  105. NSControl* view;
  106. bool isHighlighted;
  107. void setIconSize()
  108. {
  109. [statusIcon setSize: NSMakeSize (20.0f, 20.0f)];
  110. }
  111. struct SystemTrayViewClass : public ObjCClass<NSControl>
  112. {
  113. SystemTrayViewClass() : ObjCClass<NSControl> ("JUCESystemTrayView_")
  114. {
  115. addIvar<Pimpl*> ("owner");
  116. addIvar<NSImage*> ("image");
  117. addMethod (@selector (mouseDown:), handleEventDown, "v@:@");
  118. addMethod (@selector (rightMouseDown:), handleEventDown, "v@:@");
  119. addMethod (@selector (drawRect:), drawRect, "v@:@");
  120. addMethod (@selector (frameChanged:), frameChanged, "v@:@");
  121. registerClass();
  122. }
  123. static Pimpl* getOwner (id self) { return getIvar<Pimpl*> (self, "owner"); }
  124. static NSImage* getImage (id self) { return getIvar<NSImage*> (self, "image"); }
  125. static void setOwner (id self, Pimpl* owner) { object_setInstanceVariable (self, "owner", owner); }
  126. static void setImage (id self, NSImage* image) { object_setInstanceVariable (self, "image", image); }
  127. static void frameChanged (id self, SEL, NSNotification*)
  128. {
  129. if (Pimpl* const owner = getOwner (self))
  130. {
  131. NSRect r = [[[owner->statusItem view] window] frame];
  132. NSRect sr = [[[NSScreen screens] objectAtIndex: 0] frame];
  133. r.origin.y = sr.size.height - r.origin.y - r.size.height;
  134. owner->owner.setBounds (convertToRectInt (r));
  135. }
  136. }
  137. private:
  138. static void handleEventDown (id self, SEL, NSEvent* e)
  139. {
  140. if (Pimpl* const owner = getOwner (self))
  141. {
  142. owner->setHighlighted (! owner->isHighlighted);
  143. owner->handleStatusItemAction (e);
  144. }
  145. }
  146. static void drawRect (id self, SEL, NSRect)
  147. {
  148. NSRect bounds = [self bounds];
  149. if (Pimpl* const owner = getOwner (self))
  150. [owner->statusItem drawStatusBarBackgroundInRect: bounds
  151. withHighlight: owner->isHighlighted];
  152. if (NSImage* const im = getImage (self))
  153. {
  154. NSSize imageSize = [im size];
  155. [im drawInRect: NSMakeRect (bounds.origin.x + ((bounds.size.width - imageSize.width) / 2.0f),
  156. bounds.origin.y + ((bounds.size.height - imageSize.height) / 2.0f),
  157. imageSize.width, imageSize.height)
  158. fromRect: NSZeroRect
  159. operation: NSCompositeSourceOver
  160. fraction: 1.0f];
  161. }
  162. }
  163. };
  164. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  165. };
  166. //==============================================================================
  167. void SystemTrayIconComponent::setIconImage (const Image& newImage)
  168. {
  169. if (newImage.isValid())
  170. {
  171. if (pimpl == nullptr)
  172. pimpl = new Pimpl (*this, newImage);
  173. else
  174. pimpl->updateIcon (newImage);
  175. }
  176. else
  177. {
  178. pimpl = nullptr;
  179. }
  180. }
  181. void SystemTrayIconComponent::setIconTooltip (const String&)
  182. {
  183. // xxx not yet implemented!
  184. }
  185. void SystemTrayIconComponent::setHighlighted (bool highlight)
  186. {
  187. if (pimpl != nullptr)
  188. pimpl->setHighlighted (highlight);
  189. }
  190. void SystemTrayIconComponent::showInfoBubble (const String& /*title*/, const String& /*content*/)
  191. {
  192. // xxx Not implemented!
  193. }
  194. void SystemTrayIconComponent::hideInfoBubble()
  195. {
  196. // xxx Not implemented!
  197. }
  198. void* SystemTrayIconComponent::getNativeHandle() const
  199. {
  200. return pimpl != nullptr ? pimpl->statusItem : nullptr;
  201. }