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.

258 lines
9.1KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. // Your project must contain an AppConfig.h file with your project-specific settings in it,
  19. // and your header search path must make it accessible to the module's files.
  20. #include "AppConfig.h"
  21. #include "../utility/juce_CheckSettingMacros.h"
  22. #if JucePlugin_Build_VST
  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. #include "../utility/juce_PluginHostType.h"
  29. //==============================================================================
  30. namespace juce
  31. {
  32. #if ! JUCE_64BIT
  33. static void updateComponentPos (Component* const 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. updateComponentPos ((Component*) user);
  50. return noErr;
  51. }
  52. #endif
  53. //==============================================================================
  54. void initialiseMac()
  55. {
  56. #if ! JUCE_64BIT
  57. NSApplicationLoad();
  58. #endif
  59. }
  60. void* attachComponentToWindowRef (Component* comp, void* windowRef)
  61. {
  62. JUCE_AUTORELEASEPOOL
  63. #if JUCE_64BIT
  64. NSView* parentView = (NSView*) windowRef;
  65. #if JucePlugin_EditorRequiresKeyboardFocus
  66. comp->addToDesktop (0, parentView);
  67. #else
  68. comp->addToDesktop (ComponentPeer::windowIgnoresKeyPresses, parentView);
  69. #endif
  70. // (this workaround is because Wavelab provides a zero-size parent view..)
  71. if ([parentView frame].size.height == 0)
  72. [((NSView*) comp->getWindowHandle()) setFrameOrigin: NSZeroPoint];
  73. comp->setVisible (true);
  74. comp->toFront (false);
  75. [[parentView window] setAcceptsMouseMovedEvents: YES];
  76. return parentView;
  77. #else
  78. NSWindow* hostWindow = [[NSWindow alloc] initWithWindowRef: windowRef];
  79. [hostWindow retain];
  80. [hostWindow setCanHide: YES];
  81. [hostWindow setReleasedWhenClosed: YES];
  82. HIViewRef parentView = 0;
  83. WindowAttributes attributes;
  84. GetWindowAttributes ((WindowRef) windowRef, &attributes);
  85. if ((attributes & kWindowCompositingAttribute) != 0)
  86. {
  87. HIViewRef root = HIViewGetRoot ((WindowRef) windowRef);
  88. HIViewFindByID (root, kHIViewWindowContentID, &parentView);
  89. if (parentView == 0)
  90. parentView = root;
  91. }
  92. else
  93. {
  94. GetRootControl ((WindowRef) windowRef, (ControlRef*) &parentView);
  95. if (parentView == 0)
  96. CreateRootControl ((WindowRef) windowRef, (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. updateComponentPos (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) windowRef, hostWindow);
  127. return hostWindow;
  128. #endif
  129. }
  130. void detachComponentFromWindowRef (Component* comp, void* nsWindow)
  131. {
  132. #if JUCE_64BIT
  133. comp->removeFromDesktop();
  134. #else
  135. {
  136. JUCE_AUTORELEASEPOOL
  137. EventHandlerRef ref = (EventHandlerRef) (void*) (pointer_sized_int)
  138. comp->getProperties() ["boundsEventRef"].toString().getHexValue64();
  139. RemoveEventHandler (ref);
  140. removeWindowHidingHooks (comp);
  141. HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int)
  142. comp->getProperties() ["dummyViewRef"].toString().getHexValue64();
  143. if (HIViewIsValid (dummyView))
  144. CFRelease (dummyView);
  145. NSWindow* hostWindow = (NSWindow*) nsWindow;
  146. NSView* pluginView = (NSView*) comp->getWindowHandle();
  147. NSWindow* pluginWindow = [pluginView window];
  148. [hostWindow removeChildWindow: pluginWindow];
  149. comp->removeFromDesktop();
  150. [hostWindow release];
  151. }
  152. // The event loop needs to be run between closing the window and deleting the plugin,
  153. // presumably to let the cocoa objects get tidied up. Leaving out this line causes crashes
  154. // in Live and Reaper when you delete the plugin with its window open.
  155. // (Doing it this way rather than using a single longer timout means that we can guarantee
  156. // how many messages will be dispatched, which seems to be vital in Reaper)
  157. for (int i = 20; --i >= 0;)
  158. MessageManager::getInstance()->runDispatchLoopUntil (1);
  159. #endif
  160. }
  161. void setNativeHostWindowSize (void* nsWindow, Component* component, int newWidth, int newHeight, const PluginHostType& host)
  162. {
  163. JUCE_AUTORELEASEPOOL
  164. #if JUCE_64BIT
  165. NSView* hostView = (NSView*) nsWindow;
  166. if (hostView != nil)
  167. {
  168. // xxx is this necessary, or do the hosts detect a change in the child view and do this automatically?
  169. [hostView setFrameSize: NSMakeSize ([hostView frame].size.width + (newWidth - component->getWidth()),
  170. [hostView frame].size.height + (newHeight - component->getHeight()))];
  171. }
  172. #else
  173. HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int)
  174. component->getProperties() ["dummyViewRef"].toString().getHexValue64();
  175. if (dummyView != 0)
  176. {
  177. HIRect frameRect;
  178. HIViewGetFrame (dummyView, &frameRect);
  179. frameRect.size.width = newWidth;
  180. frameRect.size.height = newHeight;
  181. HIViewSetFrame (dummyView, &frameRect);
  182. }
  183. #endif
  184. }
  185. void checkWindowVisibility (void* nsWindow, Component* comp)
  186. {
  187. #if ! JUCE_64BIT
  188. comp->setVisible ([((NSWindow*) nsWindow) isVisible]);
  189. #endif
  190. }
  191. bool forwardCurrentKeyEventToHost (Component* comp)
  192. {
  193. #if JUCE_64BIT
  194. return false;
  195. #else
  196. NSWindow* win = [(NSView*) comp->getWindowHandle() window];
  197. [[win parentWindow] makeKeyWindow];
  198. [NSApp postEvent: [NSApp currentEvent] atStart: YES];
  199. return true;
  200. #endif
  201. }
  202. } // (juce namespace)
  203. #endif