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.

311 lines
11KB

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