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.

316 lines
11KB

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