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.2KB

9 years ago
9 years ago
9 years ago
10 years ago
9 years ago
9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI 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. updateAlpha();
  84. if (owner.isShowing())
  85. componentPeerChanged();
  86. attachViewWatcher (view);
  87. }
  88. ~NSViewAttachment()
  89. {
  90. detachViewWatcher();
  91. removeFromParent();
  92. [view release];
  93. }
  94. void componentMovedOrResized (Component& comp, bool wasMoved, bool wasResized) override
  95. {
  96. ComponentMovementWatcher::componentMovedOrResized (comp, wasMoved, wasResized);
  97. // The ComponentMovementWatcher version of this method avoids calling
  98. // us when the top-level comp is resized, but for an NSView we need to know this
  99. // because with inverted coordinates, we need to update the position even if the
  100. // top-left pos hasn't changed
  101. if (comp.isOnDesktop() && wasResized)
  102. componentMovedOrResized (wasMoved, wasResized);
  103. }
  104. void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override
  105. {
  106. if (ComponentPeer* const peer = owner.getTopLevelComponent()->getPeer())
  107. {
  108. NSRect r = makeNSRect (peer->getAreaCoveredBy (owner));
  109. r.origin.y = [[view superview] frame].size.height - (r.origin.y + r.size.height);
  110. [view setFrame: r];
  111. }
  112. }
  113. void componentPeerChanged() override
  114. {
  115. ComponentPeer* const peer = owner.getPeer();
  116. if (currentPeer != peer)
  117. {
  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. else
  126. {
  127. removeFromParent();
  128. }
  129. }
  130. [view setHidden: ! owner.isShowing()];
  131. }
  132. void componentVisibilityChanged() override
  133. {
  134. componentPeerChanged();
  135. }
  136. void viewResized() override
  137. {
  138. owner.childBoundsChanged (nullptr);
  139. }
  140. void updateAlpha()
  141. {
  142. [view setAlphaValue: (CGFloat) owner.getAlpha()];
  143. }
  144. NSView* const view;
  145. private:
  146. Component& owner;
  147. ComponentPeer* currentPeer;
  148. void removeFromParent()
  149. {
  150. if ([view superview] != nil)
  151. [view removeFromSuperview]; // Must be careful not to call this unless it's required - e.g. some Apple AU views
  152. // override the call and use it as a sign that they're being deleted, which breaks everything..
  153. }
  154. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NSViewAttachment)
  155. };
  156. //==============================================================================
  157. NSViewComponent::NSViewComponent() {}
  158. NSViewComponent::~NSViewComponent() {}
  159. void NSViewComponent::setView (void* const view)
  160. {
  161. if (view != getView())
  162. {
  163. attachment = nullptr;
  164. if (view != nullptr)
  165. attachment = attachViewToComponent (*this, view);
  166. }
  167. }
  168. void* NSViewComponent::getView() const
  169. {
  170. return attachment != nullptr ? static_cast<NSViewAttachment*> (attachment.get())->view
  171. : nullptr;
  172. }
  173. void NSViewComponent::resizeToFitView()
  174. {
  175. if (attachment != nullptr)
  176. {
  177. NSRect r = [static_cast<NSViewAttachment*> (attachment.get())->view frame];
  178. setBounds (Rectangle<int> ((int) r.size.width, (int) r.size.height));
  179. }
  180. }
  181. void NSViewComponent::paint (Graphics&) {}
  182. void NSViewComponent::alphaChanged()
  183. {
  184. if (attachment != nullptr)
  185. (static_cast<NSViewAttachment*> (attachment.get()))->updateAlpha();
  186. }
  187. ReferenceCountedObject* NSViewComponent::attachViewToComponent (Component& comp, void* const view)
  188. {
  189. return new NSViewAttachment ((NSView*) view, comp);
  190. }