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.

251 lines
8.8KB

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