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.

174 lines
6.2KB

  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. {
  29. static SystemTrayCallbackClass cls;
  30. callback = [cls.createInstance() init];
  31. SystemTrayCallbackClass::setOwner (callback, this);
  32. statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength: NSSquareStatusItemLength] retain];
  33. [statusItem setHighlightMode: YES];
  34. setIconSize();
  35. [statusItem setImage: statusIcon];
  36. [statusItem setTarget: callback];
  37. [statusItem setAction: @selector (statusItemAction:)];
  38. }
  39. ~Pimpl()
  40. {
  41. [statusItem release];
  42. [statusIcon release];
  43. [callback release];
  44. }
  45. void updateIcon (const Image& newImage)
  46. {
  47. [statusIcon release];
  48. statusIcon = MouseCursorHelpers::createNSImage (newImage);
  49. setIconSize();
  50. }
  51. void handleStatusItemAction (NSEvent* e)
  52. {
  53. NSEventType type = [e type];
  54. const bool isLeft = (type == NSLeftMouseDown || type == NSLeftMouseUp);
  55. const bool isRight = (type == NSRightMouseDown || type == NSRightMouseUp);
  56. if (owner.isCurrentlyBlockedByAnotherModalComponent())
  57. {
  58. if (isLeft || isRight)
  59. if (Component* const current = Component::getCurrentlyModalComponent())
  60. current->inputAttemptWhenModal();
  61. }
  62. else
  63. {
  64. ModifierKeys eventMods (ModifierKeys::getCurrentModifiersRealtime());
  65. if (([e modifierFlags] & NSCommandKeyMask) != 0)
  66. eventMods = eventMods.withFlags (ModifierKeys::commandModifier);
  67. NSRect r = [[e window] frame];
  68. r.origin.y = [[[NSScreen screens] objectAtIndex: 0] frame].size.height - r.origin.y - r.size.height;
  69. owner.setBounds (convertToRectInt (r));
  70. const Time now (Time::getCurrentTime());
  71. if (isLeft || isRight) // Only mouse up is sent by the OS, so simulate a down/up
  72. {
  73. owner.mouseDown (MouseEvent (Desktop::getInstance().getMainMouseSource(),
  74. Point<int>(),
  75. eventMods.withFlags (isLeft ? ModifierKeys::leftButtonModifier
  76. : ModifierKeys::rightButtonModifier),
  77. &owner, &owner, now,
  78. Point<int>(), now, 1, false));
  79. owner.mouseUp (MouseEvent (Desktop::getInstance().getMainMouseSource(),
  80. Point<int>(), eventMods.withoutMouseButtons(),
  81. &owner, &owner, now,
  82. Point<int>(), now, 1, false));
  83. }
  84. else if (type == NSMouseMoved)
  85. {
  86. owner.mouseMove (MouseEvent (Desktop::getInstance().getMainMouseSource(),
  87. Point<int>(), eventMods,
  88. &owner, &owner, now,
  89. Point<int>(), now, 1, false));
  90. }
  91. }
  92. }
  93. private:
  94. SystemTrayIconComponent& owner;
  95. NSStatusItem* statusItem;
  96. NSImage* statusIcon;
  97. NSObject* callback;
  98. void setIconSize()
  99. {
  100. [statusIcon setSize: NSMakeSize (20.0f, 20.0f)];
  101. }
  102. struct SystemTrayCallbackClass : public ObjCClass <NSObject>
  103. {
  104. SystemTrayCallbackClass() : ObjCClass <NSObject> ("JUCESystemTray_")
  105. {
  106. addIvar<SystemTrayIconComponent::Pimpl*> ("owner");
  107. addMethod (@selector (statusItemAction:), statusItemAction, "v@:@");
  108. registerClass();
  109. }
  110. static void setOwner (id self, SystemTrayIconComponent::Pimpl* owner)
  111. {
  112. object_setInstanceVariable (self, "owner", owner);
  113. }
  114. private:
  115. static void statusItemAction (id self, SEL, id /*sender*/)
  116. {
  117. if (SystemTrayIconComponent::Pimpl* const owner = getIvar<SystemTrayIconComponent::Pimpl*> (self, "owner"))
  118. owner->handleStatusItemAction ([NSApp currentEvent]);
  119. }
  120. };
  121. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
  122. };
  123. //==============================================================================
  124. void SystemTrayIconComponent::setIconImage (const Image& newImage)
  125. {
  126. if (newImage.isValid())
  127. {
  128. if (pimpl == nullptr)
  129. pimpl = new Pimpl (*this, newImage);
  130. else
  131. pimpl->updateIcon (newImage);
  132. }
  133. else
  134. {
  135. pimpl = nullptr;
  136. }
  137. }
  138. void SystemTrayIconComponent::setIconTooltip (const String& /* tooltip */)
  139. {
  140. // xxx not yet implemented!
  141. }