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.

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