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.

304 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 7 technical preview.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For the technical preview this file cannot be licensed commercially.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. #include <juce_core/system/juce_TargetPlatform.h>
  14. #if JUCE_MAC
  15. #include "../utility/juce_CheckSettingMacros.h"
  16. #if JucePlugin_Build_VST || JucePlugin_Build_VST3
  17. #include "../utility/juce_IncludeSystemHeaders.h"
  18. #include "../utility/juce_IncludeModuleHeaders.h"
  19. //==============================================================================
  20. namespace juce
  21. {
  22. #if ! JUCE_64BIT
  23. JUCE_API void updateEditorCompBoundsVST (Component*);
  24. void updateEditorCompBoundsVST (Component* comp)
  25. {
  26. HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int)
  27. comp->getProperties() ["dummyViewRef"].toString().getHexValue64();
  28. HIRect r;
  29. HIViewGetFrame (dummyView, &r);
  30. HIViewRef root;
  31. HIViewFindByID (HIViewGetRoot (HIViewGetWindow (dummyView)), kHIViewWindowContentID, &root);
  32. HIViewConvertRect (&r, HIViewGetSuperview (dummyView), root);
  33. Rect windowPos;
  34. GetWindowBounds (HIViewGetWindow (dummyView), kWindowContentRgn, &windowPos);
  35. comp->setTopLeftPosition ((int) (windowPos.left + r.origin.x),
  36. (int) (windowPos.top + r.origin.y));
  37. }
  38. static pascal OSStatus viewBoundsChangedEvent (EventHandlerCallRef, EventRef, void* user)
  39. {
  40. updateEditorCompBoundsVST ((Component*) user);
  41. return noErr;
  42. }
  43. static bool shouldManuallyCloseHostWindow()
  44. {
  45. return getHostType().isCubase7orLater() || getHostType().isRenoise() || ((SystemStats::getOperatingSystemType() & 0xff) >= 12);
  46. }
  47. #endif
  48. //==============================================================================
  49. JUCE_API void initialiseMacVST();
  50. void initialiseMacVST()
  51. {
  52. #if ! JUCE_64BIT
  53. NSApplicationLoad();
  54. #endif
  55. }
  56. JUCE_API void* attachComponentToWindowRefVST (Component* comp, void* parentWindowOrView, bool isNSView);
  57. void* attachComponentToWindowRefVST (Component* comp, void* parentWindowOrView, bool isNSView)
  58. {
  59. JUCE_AUTORELEASEPOOL
  60. {
  61. #if ! JUCE_64BIT
  62. if (! isNSView)
  63. {
  64. NSWindow* hostWindow = [[NSWindow alloc] initWithWindowRef: parentWindowOrView];
  65. if (shouldManuallyCloseHostWindow())
  66. {
  67. [hostWindow setReleasedWhenClosed: NO];
  68. }
  69. else
  70. {
  71. [hostWindow retain];
  72. [hostWindow setReleasedWhenClosed: YES];
  73. }
  74. [hostWindow setCanHide: YES];
  75. HIViewRef parentView = 0;
  76. WindowAttributes attributes;
  77. GetWindowAttributes ((WindowRef) parentWindowOrView, &attributes);
  78. if ((attributes & kWindowCompositingAttribute) != 0)
  79. {
  80. HIViewRef root = HIViewGetRoot ((WindowRef) parentWindowOrView);
  81. HIViewFindByID (root, kHIViewWindowContentID, &parentView);
  82. if (parentView == 0)
  83. parentView = root;
  84. }
  85. else
  86. {
  87. GetRootControl ((WindowRef) parentWindowOrView, (ControlRef*) &parentView);
  88. if (parentView == 0)
  89. CreateRootControl ((WindowRef) parentWindowOrView, (ControlRef*) &parentView);
  90. }
  91. // It seems that the only way to successfully position our overlaid window is by putting a dummy
  92. // HIView into the host's carbon window, and then catching events to see when it gets repositioned
  93. HIViewRef dummyView = 0;
  94. HIImageViewCreate (0, &dummyView);
  95. HIRect r = { {0, 0}, { (float) comp->getWidth(), (float) comp->getHeight()} };
  96. HIViewSetFrame (dummyView, &r);
  97. HIViewAddSubview (parentView, dummyView);
  98. comp->getProperties().set ("dummyViewRef", String::toHexString ((pointer_sized_int) (void*) dummyView));
  99. EventHandlerRef ref;
  100. const EventTypeSpec kControlBoundsChangedEvent = { kEventClassControl, kEventControlBoundsChanged };
  101. InstallEventHandler (GetControlEventTarget (dummyView), NewEventHandlerUPP (viewBoundsChangedEvent), 1, &kControlBoundsChangedEvent, (void*) comp, &ref);
  102. comp->getProperties().set ("boundsEventRef", String::toHexString ((pointer_sized_int) (void*) ref));
  103. updateEditorCompBoundsVST (comp);
  104. #if ! JucePlugin_EditorRequiresKeyboardFocus
  105. comp->addToDesktop (ComponentPeer::windowIsTemporary | ComponentPeer::windowIgnoresKeyPresses);
  106. #else
  107. comp->addToDesktop (ComponentPeer::windowIsTemporary);
  108. #endif
  109. comp->setVisible (true);
  110. comp->toFront (false);
  111. NSView* pluginView = (NSView*) comp->getWindowHandle();
  112. NSWindow* pluginWindow = [pluginView window];
  113. [pluginWindow setExcludedFromWindowsMenu: YES];
  114. [pluginWindow setCanHide: YES];
  115. [hostWindow addChildWindow: pluginWindow
  116. ordered: NSWindowAbove];
  117. [hostWindow orderFront: nil];
  118. [pluginWindow orderFront: nil];
  119. return hostWindow;
  120. }
  121. #endif
  122. ignoreUnused (isNSView);
  123. NSView* parentView = [(NSView*) parentWindowOrView retain];
  124. #if JucePlugin_EditorRequiresKeyboardFocus
  125. comp->addToDesktop (0, parentView);
  126. #else
  127. comp->addToDesktop (ComponentPeer::windowIgnoresKeyPresses, parentView);
  128. #endif
  129. // (this workaround is because Wavelab provides a zero-size parent view..)
  130. if ([parentView frame].size.height == 0)
  131. [((NSView*) comp->getWindowHandle()) setFrameOrigin: NSZeroPoint];
  132. comp->setVisible (true);
  133. comp->toFront (false);
  134. [[parentView window] setAcceptsMouseMovedEvents: YES];
  135. return parentView;
  136. }
  137. }
  138. JUCE_API void detachComponentFromWindowRefVST (Component* comp, void* window, bool isNSView);
  139. void detachComponentFromWindowRefVST (Component* comp, void* window, bool isNSView)
  140. {
  141. JUCE_AUTORELEASEPOOL
  142. {
  143. #if ! JUCE_64BIT
  144. if (! isNSView)
  145. {
  146. EventHandlerRef ref = (EventHandlerRef) (void*) (pointer_sized_int)
  147. comp->getProperties() ["boundsEventRef"].toString().getHexValue64();
  148. RemoveEventHandler (ref);
  149. CFUniquePtr<HIViewRef> dummyView ((HIViewRef) (void*) (pointer_sized_int)
  150. comp->getProperties() ["dummyViewRef"].toString().getHexValue64());
  151. if (HIViewIsValid (dummyView.get()))
  152. dummyView = nullptr;
  153. NSWindow* hostWindow = (NSWindow*) window;
  154. NSView* pluginView = (NSView*) comp->getWindowHandle();
  155. NSWindow* pluginWindow = [pluginView window];
  156. [pluginView retain];
  157. [hostWindow removeChildWindow: pluginWindow];
  158. [pluginWindow close];
  159. comp->removeFromDesktop();
  160. [pluginView release];
  161. if (shouldManuallyCloseHostWindow())
  162. [hostWindow close];
  163. else
  164. [hostWindow release];
  165. #if JUCE_MODAL_LOOPS_PERMITTED
  166. static bool needToRunMessageLoop = ! getHostType().isReaper();
  167. // The event loop needs to be run between closing the window and deleting the plugin,
  168. // presumably to let the cocoa objects get tidied up. Leaving out this line causes crashes
  169. // in Live when you delete the plugin with its window open.
  170. // (Doing it this way rather than using a single longer timeout means that we can guarantee
  171. // how many messages will be dispatched, which seems to be vital in Reaper)
  172. if (needToRunMessageLoop)
  173. for (int i = 20; --i >= 0;)
  174. MessageManager::getInstance()->runDispatchLoopUntil (1);
  175. #endif
  176. return;
  177. }
  178. #endif
  179. ignoreUnused (isNSView);
  180. comp->removeFromDesktop();
  181. [(id) window release];
  182. }
  183. }
  184. JUCE_API void setNativeHostWindowSizeVST (void* window, Component* component, int newWidth, int newHeight, bool isNSView);
  185. void setNativeHostWindowSizeVST (void* window, Component* component, int newWidth, int newHeight, bool isNSView)
  186. {
  187. JUCE_AUTORELEASEPOOL
  188. {
  189. #if ! JUCE_64BIT
  190. if (! isNSView)
  191. {
  192. if (HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int)
  193. component->getProperties() ["dummyViewRef"].toString().getHexValue64())
  194. {
  195. HIRect frameRect;
  196. HIViewGetFrame (dummyView, &frameRect);
  197. frameRect.size.width = newWidth;
  198. frameRect.size.height = newHeight;
  199. HIViewSetFrame (dummyView, &frameRect);
  200. }
  201. return;
  202. }
  203. #endif
  204. ignoreUnused (isNSView);
  205. if (NSView* hostView = (NSView*) window)
  206. {
  207. const int dx = newWidth - component->getWidth();
  208. const int dy = newHeight - component->getHeight();
  209. NSRect r = [hostView frame];
  210. r.size.width += dx;
  211. r.size.height += dy;
  212. r.origin.y -= dy;
  213. [hostView setFrame: r];
  214. }
  215. }
  216. }
  217. JUCE_API void checkWindowVisibilityVST (void* window, Component* comp, bool isNSView);
  218. void checkWindowVisibilityVST (void* window, Component* comp, bool isNSView)
  219. {
  220. ignoreUnused (window, comp, isNSView);
  221. #if ! JUCE_64BIT
  222. if (! isNSView)
  223. comp->setVisible ([((NSWindow*) window) isVisible]);
  224. #endif
  225. }
  226. JUCE_API bool forwardCurrentKeyEventToHostVST (Component* comp, bool isNSView);
  227. bool forwardCurrentKeyEventToHostVST (Component* comp, bool isNSView)
  228. {
  229. #if ! JUCE_64BIT
  230. if (! isNSView)
  231. {
  232. NSWindow* win = [(NSView*) comp->getWindowHandle() window];
  233. [[win parentWindow] makeKeyWindow];
  234. repostCurrentNSEvent();
  235. return true;
  236. }
  237. #endif
  238. ignoreUnused (comp, isNSView);
  239. return false;
  240. }
  241. } // (juce namespace)
  242. #endif
  243. #endif