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.

243 lines
7.3KB

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