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.

juce_mac_NSViewComponent.mm 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  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 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace juce
  20. {
  21. struct NSViewResizeWatcher
  22. {
  23. NSViewResizeWatcher() : callback (nil) {}
  24. virtual ~NSViewResizeWatcher()
  25. {
  26. // must call detachViewWatcher() first
  27. jassert (callback == nil);
  28. }
  29. void attachViewWatcher (NSView* view)
  30. {
  31. static ViewFrameChangeCallbackClass cls;
  32. callback = [cls.createInstance() init];
  33. ViewFrameChangeCallbackClass::setTarget (callback, this);
  34. [[NSNotificationCenter defaultCenter] addObserver: callback
  35. selector: @selector (frameChanged:)
  36. name: NSViewFrameDidChangeNotification
  37. object: view];
  38. }
  39. void detachViewWatcher()
  40. {
  41. if (callback != nil)
  42. {
  43. [[NSNotificationCenter defaultCenter] removeObserver: callback];
  44. [callback release];
  45. callback = nil;
  46. }
  47. }
  48. virtual void viewResized() = 0;
  49. private:
  50. id callback;
  51. //==============================================================================
  52. struct ViewFrameChangeCallbackClass : public ObjCClass<NSObject>
  53. {
  54. ViewFrameChangeCallbackClass() : ObjCClass<NSObject> ("JUCE_NSViewCallback_")
  55. {
  56. addIvar<NSViewResizeWatcher*> ("target");
  57. addMethod (@selector (frameChanged:), frameChanged, "v@:@");
  58. registerClass();
  59. }
  60. static void setTarget (id self, NSViewResizeWatcher* c)
  61. {
  62. object_setInstanceVariable (self, "target", c);
  63. }
  64. private:
  65. static void frameChanged (id self, SEL, NSNotification*)
  66. {
  67. if (NSViewResizeWatcher* const target = getIvar<NSViewResizeWatcher*> (self, "target"))
  68. target->viewResized();
  69. }
  70. JUCE_DECLARE_NON_COPYABLE (ViewFrameChangeCallbackClass)
  71. };
  72. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NSViewResizeWatcher)
  73. };
  74. //==============================================================================
  75. class NSViewAttachment : public ReferenceCountedObject,
  76. public ComponentMovementWatcher,
  77. private NSViewResizeWatcher
  78. {
  79. public:
  80. NSViewAttachment (NSView* const v, Component& comp)
  81. : ComponentMovementWatcher (&comp),
  82. view (v), owner (comp),
  83. currentPeer (nullptr)
  84. {
  85. [view retain];
  86. [view setPostsFrameChangedNotifications: YES];
  87. updateAlpha();
  88. if (owner.isShowing())
  89. componentPeerChanged();
  90. attachViewWatcher (view);
  91. }
  92. ~NSViewAttachment()
  93. {
  94. detachViewWatcher();
  95. removeFromParent();
  96. [view release];
  97. }
  98. void componentMovedOrResized (Component& comp, bool wasMoved, bool wasResized) override
  99. {
  100. ComponentMovementWatcher::componentMovedOrResized (comp, wasMoved, wasResized);
  101. // The ComponentMovementWatcher version of this method avoids calling
  102. // us when the top-level comp is resized, but for an NSView we need to know this
  103. // because with inverted coordinates, we need to update the position even if the
  104. // top-left pos hasn't changed
  105. if (comp.isOnDesktop() && wasResized)
  106. componentMovedOrResized (wasMoved, wasResized);
  107. }
  108. void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override
  109. {
  110. if (ComponentPeer* const peer = owner.getTopLevelComponent()->getPeer())
  111. {
  112. NSRect r = makeNSRect (peer->getAreaCoveredBy (owner));
  113. r.origin.y = [[view superview] frame].size.height - (r.origin.y + r.size.height);
  114. [view setFrame: r];
  115. }
  116. }
  117. void componentPeerChanged() override
  118. {
  119. ComponentPeer* const peer = owner.getPeer();
  120. if (currentPeer != peer)
  121. {
  122. currentPeer = peer;
  123. if (peer != nullptr)
  124. {
  125. NSView* const peerView = (NSView*) peer->getNativeHandle();
  126. [peerView addSubview: view];
  127. componentMovedOrResized (false, false);
  128. }
  129. else
  130. {
  131. removeFromParent();
  132. }
  133. }
  134. [view setHidden: ! owner.isShowing()];
  135. }
  136. void componentVisibilityChanged() override
  137. {
  138. componentPeerChanged();
  139. }
  140. void viewResized() override
  141. {
  142. owner.childBoundsChanged (nullptr);
  143. }
  144. void updateAlpha()
  145. {
  146. [view setAlphaValue: (CGFloat) owner.getAlpha()];
  147. }
  148. NSView* const view;
  149. typedef ReferenceCountedObjectPtr<NSViewAttachment> Ptr;
  150. private:
  151. Component& owner;
  152. ComponentPeer* currentPeer;
  153. void removeFromParent()
  154. {
  155. if ([view superview] != nil)
  156. [view removeFromSuperview]; // Must be careful not to call this unless it's required - e.g. some Apple AU views
  157. // override the call and use it as a sign that they're being deleted, which breaks everything..
  158. }
  159. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NSViewAttachment)
  160. };
  161. //==============================================================================
  162. NSViewComponent::NSViewComponent() {}
  163. NSViewComponent::~NSViewComponent() {}
  164. void NSViewComponent::setView (void* const view)
  165. {
  166. if (view != getView())
  167. {
  168. NSViewAttachment::Ptr old = attachment;
  169. attachment = nullptr;
  170. if (view != nullptr)
  171. attachment = attachViewToComponent (*this, view);
  172. old = nullptr;
  173. }
  174. }
  175. void* NSViewComponent::getView() const
  176. {
  177. return attachment != nullptr ? static_cast<NSViewAttachment*> (attachment.get())->view
  178. : nullptr;
  179. }
  180. void NSViewComponent::resizeToFitView()
  181. {
  182. if (attachment != nullptr)
  183. {
  184. NSRect r = [static_cast<NSViewAttachment*> (attachment.get())->view frame];
  185. setBounds (Rectangle<int> ((int) r.size.width, (int) r.size.height));
  186. }
  187. }
  188. void NSViewComponent::paint (Graphics&) {}
  189. void NSViewComponent::alphaChanged()
  190. {
  191. if (attachment != nullptr)
  192. (static_cast<NSViewAttachment*> (attachment.get()))->updateAlpha();
  193. }
  194. ReferenceCountedObject* NSViewComponent::attachViewToComponent (Component& comp, void* const view)
  195. {
  196. return new NSViewAttachment ((NSView*) view, comp);
  197. }
  198. } // namespace juce