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.

198 lines
5.9KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. class NSViewAttachment final : public ReferenceCountedObject,
  21. public ComponentMovementWatcher
  22. {
  23. public:
  24. NSViewAttachment (NSView* v, Component& comp)
  25. : ComponentMovementWatcher (&comp),
  26. view (v), owner (comp)
  27. {
  28. [view retain];
  29. [view setPostsFrameChangedNotifications: YES];
  30. updateAlpha();
  31. if (owner.isShowing())
  32. componentPeerChanged();
  33. }
  34. ~NSViewAttachment() override
  35. {
  36. removeFromParent();
  37. [view release];
  38. }
  39. void componentMovedOrResized (Component& comp, bool wasMoved, bool wasResized) override
  40. {
  41. ComponentMovementWatcher::componentMovedOrResized (comp, wasMoved, wasResized);
  42. // The ComponentMovementWatcher version of this method avoids calling
  43. // us when the top-level comp is resized, but if we're listening to the
  44. // top-level comp we still want the NSView to track its size.
  45. if (comp.isOnDesktop() && wasResized)
  46. componentMovedOrResized (wasMoved, wasResized);
  47. }
  48. void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override
  49. {
  50. if (auto* peer = owner.getTopLevelComponent()->getPeer())
  51. {
  52. const auto newArea = peer->getAreaCoveredBy (owner);
  53. if (convertToRectInt ([view frame]) != newArea)
  54. [view setFrame: makeNSRect (newArea)];
  55. }
  56. }
  57. void componentPeerChanged() override
  58. {
  59. auto* peer = owner.getPeer();
  60. if (std::exchange (currentPeer, peer) != peer)
  61. {
  62. if (peer != nullptr)
  63. {
  64. auto peerView = (NSView*) peer->getNativeHandle();
  65. [peerView addSubview: view];
  66. if (@available (macOS 10.10, *))
  67. [view setAccessibilityParent:static_cast<id> (owner.getAccessibilityHandler()->getNativeImplementation())];
  68. componentMovedOrResized (false, false);
  69. }
  70. else
  71. {
  72. removeFromParent();
  73. }
  74. }
  75. [view setHidden: ! owner.isShowing()];
  76. }
  77. void componentVisibilityChanged() override
  78. {
  79. componentPeerChanged();
  80. }
  81. void updateAlpha()
  82. {
  83. [view setAlphaValue: (CGFloat) owner.getAlpha()];
  84. }
  85. NSView* const view;
  86. using Ptr = ReferenceCountedObjectPtr<NSViewAttachment>;
  87. private:
  88. Component& owner;
  89. ComponentPeer* currentPeer = nullptr;
  90. NSViewFrameWatcher frameWatcher { view, [this] { owner.childBoundsChanged (nullptr); } };
  91. void removeFromParent()
  92. {
  93. if ([view superview] != nil)
  94. [view removeFromSuperview]; // Must be careful not to call this unless it's required - e.g. some Apple AU views
  95. // override the call and use it as a sign that they're being deleted, which breaks everything..
  96. }
  97. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NSViewAttachment)
  98. };
  99. //==============================================================================
  100. NSViewComponent::NSViewComponent() = default;
  101. NSViewComponent::~NSViewComponent()
  102. {
  103. AccessibilityHandler::setNativeChildForComponent (*this, nullptr);
  104. }
  105. void NSViewComponent::setView (void* view)
  106. {
  107. if (view != getView())
  108. {
  109. auto old = attachment;
  110. attachment = nullptr;
  111. if (view != nullptr)
  112. attachment = attachViewToComponent (*this, view);
  113. old = nullptr;
  114. AccessibilityHandler::setNativeChildForComponent (*this, getView());
  115. }
  116. }
  117. void* NSViewComponent::getView() const
  118. {
  119. return attachment != nullptr ? static_cast<NSViewAttachment*> (attachment.get())->view
  120. : nullptr;
  121. }
  122. void NSViewComponent::resizeToFitView()
  123. {
  124. if (attachment != nullptr)
  125. {
  126. auto* view = static_cast<NSViewAttachment*> (attachment.get())->view;
  127. auto r = [view frame];
  128. setBounds (Rectangle<int> ((int) r.size.width, (int) r.size.height));
  129. if (auto* peer = getTopLevelComponent()->getPeer())
  130. {
  131. const auto position = peer->getAreaCoveredBy (*this).getPosition();
  132. [view setFrameOrigin: convertToCGPoint (position)];
  133. }
  134. }
  135. }
  136. void NSViewComponent::resizeViewToFit()
  137. {
  138. if (attachment != nullptr)
  139. static_cast<NSViewAttachment*> (attachment.get())->componentMovedOrResized (true, true);
  140. }
  141. void NSViewComponent::paint (Graphics&) {}
  142. void NSViewComponent::alphaChanged()
  143. {
  144. if (attachment != nullptr)
  145. (static_cast<NSViewAttachment*> (attachment.get()))->updateAlpha();
  146. }
  147. ReferenceCountedObject* NSViewComponent::attachViewToComponent (Component& comp, void* view)
  148. {
  149. return new NSViewAttachment ((NSView*) view, comp);
  150. }
  151. std::unique_ptr<AccessibilityHandler> NSViewComponent::createAccessibilityHandler()
  152. {
  153. return std::make_unique<AccessibilityHandler> (*this, AccessibilityRole::group);
  154. }
  155. } // namespace juce