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.

319 lines
11KB

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