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.

209 lines
7.7KB

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