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.

224 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. currentPeer = peer;
  118. if (peer != nullptr)
  119. {
  120. NSView* const peerView = (NSView*) peer->getNativeHandle();
  121. [peerView addSubview: view];
  122. componentMovedOrResized (false, false);
  123. }
  124. else
  125. {
  126. removeFromParent();
  127. }
  128. }
  129. [view setHidden: ! owner.isShowing()];
  130. }
  131. void componentVisibilityChanged() override
  132. {
  133. componentPeerChanged();
  134. }
  135. void viewResized() override
  136. {
  137. owner.childBoundsChanged (nullptr);
  138. }
  139. NSView* const view;
  140. private:
  141. Component& owner;
  142. ComponentPeer* currentPeer;
  143. void removeFromParent()
  144. {
  145. if ([view superview] != nil)
  146. [view removeFromSuperview]; // Must be careful not to call this unless it's required - e.g. some Apple AU views
  147. // override the call and use it as a sign that they're being deleted, which breaks everything..
  148. }
  149. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NSViewAttachment)
  150. };
  151. //==============================================================================
  152. NSViewComponent::NSViewComponent() {}
  153. NSViewComponent::~NSViewComponent() {}
  154. void NSViewComponent::setView (void* const view)
  155. {
  156. if (view != getView())
  157. {
  158. attachment = nullptr;
  159. if (view != nullptr)
  160. attachment = attachViewToComponent (*this, view);
  161. }
  162. }
  163. void* NSViewComponent::getView() const
  164. {
  165. return attachment != nullptr ? static_cast<NSViewAttachment*> (attachment.get())->view
  166. : nullptr;
  167. }
  168. void NSViewComponent::resizeToFitView()
  169. {
  170. if (attachment != nullptr)
  171. {
  172. NSRect r = [static_cast<NSViewAttachment*> (attachment.get())->view frame];
  173. setBounds (Rectangle<int> ((int) r.size.width, (int) r.size.height));
  174. }
  175. }
  176. void NSViewComponent::paint (Graphics&) {}
  177. ReferenceCountedObject* NSViewComponent::attachViewToComponent (Component& comp, void* const view)
  178. {
  179. return new NSViewAttachment ((NSView*) view, comp);
  180. }