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.

222 lines
6.9KB

  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. struct NSViewResizeWatcher
  18. {
  19. NSViewResizeWatcher() : callback (nil) {}
  20. virtual ~NSViewResizeWatcher()
  21. {
  22. // must call detachViewWatcher() first
  23. jassert (callback == nil);
  24. }
  25. void attachViewWatcher (NSView* view)
  26. {
  27. static ViewFrameChangeCallbackClass cls;
  28. callback = [cls.createInstance() init];
  29. ViewFrameChangeCallbackClass::setTarget (callback, this);
  30. [[NSNotificationCenter defaultCenter] addObserver: callback
  31. selector: @selector (frameChanged:)
  32. name: NSViewFrameDidChangeNotification
  33. object: view];
  34. }
  35. void detachViewWatcher()
  36. {
  37. if (callback != nil)
  38. {
  39. [[NSNotificationCenter defaultCenter] removeObserver: callback];
  40. [callback release];
  41. callback = nil;
  42. }
  43. }
  44. virtual void viewResized() = 0;
  45. private:
  46. id callback;
  47. //==============================================================================
  48. struct ViewFrameChangeCallbackClass : public ObjCClass<NSObject>
  49. {
  50. ViewFrameChangeCallbackClass() : ObjCClass<NSObject> ("JUCE_NSViewCallback_")
  51. {
  52. addIvar<NSViewResizeWatcher*> ("target");
  53. addMethod (@selector (frameChanged:), frameChanged, "v@:@");
  54. registerClass();
  55. }
  56. static void setTarget (id self, NSViewResizeWatcher* c)
  57. {
  58. object_setInstanceVariable (self, "target", c);
  59. }
  60. private:
  61. static void frameChanged (id self, SEL, NSNotification*)
  62. {
  63. if (NSViewResizeWatcher* const target = getIvar<NSViewResizeWatcher*> (self, "target"))
  64. target->viewResized();
  65. }
  66. JUCE_DECLARE_NON_COPYABLE (ViewFrameChangeCallbackClass);
  67. };
  68. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NSViewResizeWatcher)
  69. };
  70. //==============================================================================
  71. class NSViewAttachment : public ReferenceCountedObject,
  72. public ComponentMovementWatcher,
  73. private NSViewResizeWatcher
  74. {
  75. public:
  76. NSViewAttachment (NSView* const v, Component& comp)
  77. : ComponentMovementWatcher (&comp),
  78. view (v), owner (comp),
  79. currentPeer (nullptr)
  80. {
  81. [view retain];
  82. [view setPostsFrameChangedNotifications: YES];
  83. if (owner.isShowing())
  84. componentPeerChanged();
  85. attachViewWatcher (view);
  86. }
  87. ~NSViewAttachment()
  88. {
  89. detachViewWatcher();
  90. removeFromParent();
  91. [view release];
  92. }
  93. void componentMovedOrResized (Component& comp, bool wasMoved, bool wasResized) override
  94. {
  95. ComponentMovementWatcher::componentMovedOrResized (comp, wasMoved, wasResized);
  96. // The ComponentMovementWatcher version of this method avoids calling
  97. // us when the top-level comp is resized, but for an NSView we need to know this
  98. // because with inverted coordinates, we need to update the position even if the
  99. // top-left pos hasn't changed
  100. if (comp.isOnDesktop() && wasResized)
  101. componentMovedOrResized (wasMoved, wasResized);
  102. }
  103. void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override
  104. {
  105. if (ComponentPeer* const peer = owner.getTopLevelComponent()->getPeer())
  106. {
  107. NSRect r = makeNSRect (peer->getAreaCoveredBy (owner));
  108. r.origin.y = [[view superview] frame].size.height - (r.origin.y + r.size.height);
  109. [view setFrame: r];
  110. }
  111. }
  112. void componentPeerChanged() override
  113. {
  114. ComponentPeer* const peer = owner.getPeer();
  115. if (currentPeer != peer)
  116. {
  117. removeFromParent();
  118. currentPeer = peer;
  119. if (peer != nullptr)
  120. {
  121. NSView* const peerView = (NSView*) peer->getNativeHandle();
  122. [peerView addSubview: view];
  123. componentMovedOrResized (false, false);
  124. }
  125. }
  126. [view setHidden: ! owner.isShowing()];
  127. }
  128. void componentVisibilityChanged() override
  129. {
  130. componentPeerChanged();
  131. }
  132. void viewResized() override
  133. {
  134. owner.childBoundsChanged (nullptr);
  135. }
  136. NSView* const view;
  137. private:
  138. Component& owner;
  139. ComponentPeer* currentPeer;
  140. void removeFromParent()
  141. {
  142. if ([view superview] != nil)
  143. [view removeFromSuperview]; // Must be careful not to call this unless it's required - e.g. some Apple AU views
  144. // override the call and use it as a sign that they're being deleted, which breaks everything..
  145. }
  146. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NSViewAttachment)
  147. };
  148. //==============================================================================
  149. NSViewComponent::NSViewComponent() {}
  150. NSViewComponent::~NSViewComponent() {}
  151. void NSViewComponent::setView (void* const view)
  152. {
  153. if (view != getView())
  154. {
  155. attachment = nullptr;
  156. if (view != nullptr)
  157. attachment = attachViewToComponent (*this, view);
  158. }
  159. }
  160. void* NSViewComponent::getView() const
  161. {
  162. return attachment != nullptr ? static_cast<NSViewAttachment*> (attachment.get())->view
  163. : nullptr;
  164. }
  165. void NSViewComponent::resizeToFitView()
  166. {
  167. if (attachment != nullptr)
  168. {
  169. NSRect r = [static_cast<NSViewAttachment*> (attachment.get())->view frame];
  170. setBounds (Rectangle<int> ((int) r.size.width, (int) r.size.height));
  171. }
  172. }
  173. void NSViewComponent::paint (Graphics&) {}
  174. ReferenceCountedObject* NSViewComponent::attachViewToComponent (Component& comp, void* const view)
  175. {
  176. return new NSViewAttachment ((NSView*) view, comp);
  177. }