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.

264 lines
9.6KB

  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
  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. #include "../utility/juce_PluginHostType.h"
  28. //==============================================================================
  29. namespace juce
  30. {
  31. #if ! JUCE_64BIT
  32. void updateEditorCompBounds (Component*);
  33. void updateEditorCompBounds (Component* comp)
  34. {
  35. HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int)
  36. comp->getProperties() ["dummyViewRef"].toString().getHexValue64();
  37. HIRect r;
  38. HIViewGetFrame (dummyView, &r);
  39. HIViewRef root;
  40. HIViewFindByID (HIViewGetRoot (HIViewGetWindow (dummyView)), kHIViewWindowContentID, &root);
  41. HIViewConvertRect (&r, HIViewGetSuperview (dummyView), root);
  42. Rect windowPos;
  43. GetWindowBounds (HIViewGetWindow (dummyView), kWindowContentRgn, &windowPos);
  44. comp->setTopLeftPosition ((int) (windowPos.left + r.origin.x),
  45. (int) (windowPos.top + r.origin.y));
  46. }
  47. static pascal OSStatus viewBoundsChangedEvent (EventHandlerCallRef, EventRef, void* user)
  48. {
  49. updateEditorCompBounds ((Component*) user);
  50. return noErr;
  51. }
  52. #endif
  53. //==============================================================================
  54. void initialiseMac();
  55. void initialiseMac()
  56. {
  57. #if ! JUCE_64BIT
  58. NSApplicationLoad();
  59. #endif
  60. }
  61. void* attachComponentToWindowRef (Component* comp, void* windowRef);
  62. void* attachComponentToWindowRef (Component* comp, void* windowRef)
  63. {
  64. JUCE_AUTORELEASEPOOL
  65. {
  66. #if JUCE_64BIT
  67. NSView* parentView = (NSView*) windowRef;
  68. #if JucePlugin_EditorRequiresKeyboardFocus
  69. comp->addToDesktop (0, parentView);
  70. #else
  71. comp->addToDesktop (ComponentPeer::windowIgnoresKeyPresses, parentView);
  72. #endif
  73. // (this workaround is because Wavelab provides a zero-size parent view..)
  74. if ([parentView frame].size.height == 0)
  75. [((NSView*) comp->getWindowHandle()) setFrameOrigin: NSZeroPoint];
  76. comp->setVisible (true);
  77. comp->toFront (false);
  78. [[parentView window] setAcceptsMouseMovedEvents: YES];
  79. return parentView;
  80. #else
  81. NSWindow* hostWindow = [[NSWindow alloc] initWithWindowRef: windowRef];
  82. [hostWindow retain];
  83. [hostWindow setCanHide: YES];
  84. [hostWindow setReleasedWhenClosed: YES];
  85. HIViewRef parentView = 0;
  86. WindowAttributes attributes;
  87. GetWindowAttributes ((WindowRef) windowRef, &attributes);
  88. if ((attributes & kWindowCompositingAttribute) != 0)
  89. {
  90. HIViewRef root = HIViewGetRoot ((WindowRef) windowRef);
  91. HIViewFindByID (root, kHIViewWindowContentID, &parentView);
  92. if (parentView == 0)
  93. parentView = root;
  94. }
  95. else
  96. {
  97. GetRootControl ((WindowRef) windowRef, (ControlRef*) &parentView);
  98. if (parentView == 0)
  99. CreateRootControl ((WindowRef) windowRef, (ControlRef*) &parentView);
  100. }
  101. // It seems that the only way to successfully position our overlaid window is by putting a dummy
  102. // HIView into the host's carbon window, and then catching events to see when it gets repositioned
  103. HIViewRef dummyView = 0;
  104. HIImageViewCreate (0, &dummyView);
  105. HIRect r = { {0, 0}, { (float) comp->getWidth(), (float) comp->getHeight()} };
  106. HIViewSetFrame (dummyView, &r);
  107. HIViewAddSubview (parentView, dummyView);
  108. comp->getProperties().set ("dummyViewRef", String::toHexString ((pointer_sized_int) (void*) dummyView));
  109. EventHandlerRef ref;
  110. const EventTypeSpec kControlBoundsChangedEvent = { kEventClassControl, kEventControlBoundsChanged };
  111. InstallEventHandler (GetControlEventTarget (dummyView), NewEventHandlerUPP (viewBoundsChangedEvent), 1, &kControlBoundsChangedEvent, (void*) comp, &ref);
  112. comp->getProperties().set ("boundsEventRef", String::toHexString ((pointer_sized_int) (void*) ref));
  113. updateEditorCompBounds (comp);
  114. #if ! JucePlugin_EditorRequiresKeyboardFocus
  115. comp->addToDesktop (ComponentPeer::windowIsTemporary | ComponentPeer::windowIgnoresKeyPresses);
  116. #else
  117. comp->addToDesktop (ComponentPeer::windowIsTemporary);
  118. #endif
  119. comp->setVisible (true);
  120. comp->toFront (false);
  121. NSView* pluginView = (NSView*) comp->getWindowHandle();
  122. NSWindow* pluginWindow = [pluginView window];
  123. [pluginWindow setExcludedFromWindowsMenu: YES];
  124. [pluginWindow setCanHide: YES];
  125. [hostWindow addChildWindow: pluginWindow
  126. ordered: NSWindowAbove];
  127. [hostWindow orderFront: nil];
  128. [pluginWindow orderFront: nil];
  129. attachWindowHidingHooks (comp, (WindowRef) windowRef, hostWindow);
  130. return hostWindow;
  131. #endif
  132. }
  133. }
  134. void detachComponentFromWindowRef (Component* comp, void* nsWindow);
  135. void detachComponentFromWindowRef (Component* comp, void* nsWindow)
  136. {
  137. JUCE_AUTORELEASEPOOL
  138. {
  139. #if JUCE_64BIT
  140. comp->removeFromDesktop();
  141. #else
  142. EventHandlerRef ref = (EventHandlerRef) (void*) (pointer_sized_int)
  143. comp->getProperties() ["boundsEventRef"].toString().getHexValue64();
  144. RemoveEventHandler (ref);
  145. removeWindowHidingHooks (comp);
  146. HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int)
  147. comp->getProperties() ["dummyViewRef"].toString().getHexValue64();
  148. if (HIViewIsValid (dummyView))
  149. CFRelease (dummyView);
  150. NSWindow* hostWindow = (NSWindow*) nsWindow;
  151. NSView* pluginView = (NSView*) comp->getWindowHandle();
  152. NSWindow* pluginWindow = [pluginView window];
  153. [hostWindow removeChildWindow: pluginWindow];
  154. comp->removeFromDesktop();
  155. [hostWindow release];
  156. // The event loop needs to be run between closing the window and deleting the plugin,
  157. // presumably to let the cocoa objects get tidied up. Leaving out this line causes crashes
  158. // in Live and Reaper when you delete the plugin with its window open.
  159. // (Doing it this way rather than using a single longer timout means that we can guarantee
  160. // how many messages will be dispatched, which seems to be vital in Reaper)
  161. for (int i = 20; --i >= 0;)
  162. MessageManager::getInstance()->runDispatchLoopUntil (1);
  163. #endif
  164. }
  165. }
  166. void setNativeHostWindowSize (void* nsWindow, Component* component, int newWidth, int newHeight);
  167. void setNativeHostWindowSize (void* nsWindow, Component* component, int newWidth, int newHeight)
  168. {
  169. JUCE_AUTORELEASEPOOL
  170. {
  171. #if JUCE_64BIT
  172. if (NSView* hostView = (NSView*) nsWindow)
  173. {
  174. // xxx is this necessary, or do the hosts detect a change in the child view and do this automatically?
  175. [hostView setFrameSize: NSMakeSize ([hostView frame].size.width + (newWidth - component->getWidth()),
  176. [hostView frame].size.height + (newHeight - component->getHeight()))];
  177. }
  178. #else
  179. if (HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int)
  180. component->getProperties() ["dummyViewRef"].toString().getHexValue64())
  181. {
  182. HIRect frameRect;
  183. HIViewGetFrame (dummyView, &frameRect);
  184. frameRect.size.width = newWidth;
  185. frameRect.size.height = newHeight;
  186. HIViewSetFrame (dummyView, &frameRect);
  187. }
  188. #endif
  189. }
  190. }
  191. void checkWindowVisibility (void* nsWindow, Component* comp);
  192. void checkWindowVisibility (void* nsWindow, Component* comp)
  193. {
  194. #if ! JUCE_64BIT
  195. comp->setVisible ([((NSWindow*) nsWindow) isVisible]);
  196. #endif
  197. }
  198. bool forwardCurrentKeyEventToHost (Component* comp);
  199. bool forwardCurrentKeyEventToHost (Component* comp)
  200. {
  201. #if JUCE_64BIT
  202. (void) comp;
  203. return false;
  204. #else
  205. NSWindow* win = [(NSView*) comp->getWindowHandle() window];
  206. [[win parentWindow] makeKeyWindow];
  207. [NSApp postEvent: [NSApp currentEvent] atStart: YES];
  208. return true;
  209. #endif
  210. }
  211. } // (juce namespace)
  212. #endif