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.

290 lines
9.4KB

  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. #ifndef __JUCE_MAC_CARBONVIEWWRAPPERCOMPONENT_JUCEHEADER__
  19. #define __JUCE_MAC_CARBONVIEWWRAPPERCOMPONENT_JUCEHEADER__
  20. //==============================================================================
  21. /**
  22. Creates a floating carbon window that can be used to hold a carbon UI.
  23. This is a handy class that's designed to be inlined where needed, e.g.
  24. in the audio plugin hosting code.
  25. */
  26. class CarbonViewWrapperComponent : public Component,
  27. public ComponentMovementWatcher,
  28. public Timer
  29. {
  30. public:
  31. CarbonViewWrapperComponent()
  32. : ComponentMovementWatcher (this),
  33. wrapperWindow (0),
  34. carbonWindow (0),
  35. embeddedView (0),
  36. recursiveResize (false)
  37. {
  38. }
  39. virtual ~CarbonViewWrapperComponent()
  40. {
  41. jassert (embeddedView == 0); // must call deleteWindow() in the subclass's destructor!
  42. }
  43. virtual HIViewRef attachView (WindowRef windowRef, HIViewRef rootView) = 0;
  44. virtual void removeView (HIViewRef embeddedView) = 0;
  45. virtual void mouseDown (int, int) {}
  46. virtual void paint() {}
  47. virtual bool getEmbeddedViewSize (int& w, int& h)
  48. {
  49. if (embeddedView == 0)
  50. return false;
  51. HIRect bounds;
  52. HIViewGetBounds (embeddedView, &bounds);
  53. w = jmax (1, roundToInt (bounds.size.width));
  54. h = jmax (1, roundToInt (bounds.size.height));
  55. return true;
  56. }
  57. void createWindow()
  58. {
  59. if (wrapperWindow == 0)
  60. {
  61. Rect r;
  62. r.left = getScreenX();
  63. r.top = getScreenY();
  64. r.right = r.left + getWidth();
  65. r.bottom = r.top + getHeight();
  66. CreateNewWindow (kDocumentWindowClass,
  67. (WindowAttributes) (kWindowStandardHandlerAttribute | kWindowCompositingAttribute
  68. | kWindowNoShadowAttribute | kWindowNoTitleBarAttribute),
  69. &r, &wrapperWindow);
  70. jassert (wrapperWindow != 0);
  71. if (wrapperWindow == 0)
  72. return;
  73. carbonWindow = [[NSWindow alloc] initWithWindowRef: wrapperWindow];
  74. [getOwnerWindow() addChildWindow: carbonWindow
  75. ordered: NSWindowAbove];
  76. embeddedView = attachView (wrapperWindow, HIViewGetRoot (wrapperWindow));
  77. EventTypeSpec windowEventTypes[] =
  78. {
  79. { kEventClassWindow, kEventWindowGetClickActivation },
  80. { kEventClassWindow, kEventWindowHandleDeactivate },
  81. { kEventClassWindow, kEventWindowBoundsChanging },
  82. { kEventClassMouse, kEventMouseDown },
  83. { kEventClassMouse, kEventMouseMoved },
  84. { kEventClassMouse, kEventMouseDragged },
  85. { kEventClassMouse, kEventMouseUp},
  86. { kEventClassWindow, kEventWindowDrawContent },
  87. { kEventClassWindow, kEventWindowShown },
  88. { kEventClassWindow, kEventWindowHidden }
  89. };
  90. EventHandlerUPP upp = NewEventHandlerUPP (carbonEventCallback);
  91. InstallWindowEventHandler (wrapperWindow, upp,
  92. sizeof (windowEventTypes) / sizeof (EventTypeSpec),
  93. windowEventTypes, this, &eventHandlerRef);
  94. setOurSizeToEmbeddedViewSize();
  95. setEmbeddedWindowToOurSize();
  96. creationTime = Time::getCurrentTime();
  97. }
  98. }
  99. void deleteWindow()
  100. {
  101. removeView (embeddedView);
  102. embeddedView = 0;
  103. if (wrapperWindow != 0)
  104. {
  105. NSWindow* ownerWindow = getOwnerWindow();
  106. if ([[ownerWindow childWindows] count] > 0)
  107. {
  108. [ownerWindow removeChildWindow: carbonWindow];
  109. [carbonWindow close];
  110. }
  111. RemoveEventHandler (eventHandlerRef);
  112. DisposeWindow (wrapperWindow);
  113. wrapperWindow = 0;
  114. }
  115. }
  116. //==============================================================================
  117. void setOurSizeToEmbeddedViewSize()
  118. {
  119. int w, h;
  120. if (getEmbeddedViewSize (w, h))
  121. {
  122. if (w != getWidth() || h != getHeight())
  123. {
  124. startTimer (50);
  125. setSize (w, h);
  126. if (getParentComponent() != nullptr)
  127. getParentComponent()->setSize (w, h);
  128. }
  129. else
  130. {
  131. startTimer (jlimit (50, 500, getTimerInterval() + 20));
  132. }
  133. }
  134. else
  135. {
  136. stopTimer();
  137. }
  138. }
  139. void setEmbeddedWindowToOurSize()
  140. {
  141. if (! recursiveResize)
  142. {
  143. recursiveResize = true;
  144. if (embeddedView != 0)
  145. {
  146. HIRect r;
  147. r.origin.x = 0;
  148. r.origin.y = 0;
  149. r.size.width = (float) getWidth();
  150. r.size.height = (float) getHeight();
  151. HIViewSetFrame (embeddedView, &r);
  152. }
  153. if (wrapperWindow != 0)
  154. {
  155. Rect wr;
  156. wr.left = getScreenX();
  157. wr.top = getScreenY();
  158. wr.right = wr.left + getWidth();
  159. wr.bottom = wr.top + getHeight();
  160. SetWindowBounds (wrapperWindow, kWindowContentRgn, &wr);
  161. ShowWindow (wrapperWindow);
  162. }
  163. recursiveResize = false;
  164. }
  165. }
  166. void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/)
  167. {
  168. setEmbeddedWindowToOurSize();
  169. }
  170. void componentPeerChanged()
  171. {
  172. deleteWindow();
  173. createWindow();
  174. }
  175. void componentVisibilityChanged()
  176. {
  177. if (isShowing())
  178. createWindow();
  179. else
  180. deleteWindow();
  181. setEmbeddedWindowToOurSize();
  182. }
  183. static void recursiveHIViewRepaint (HIViewRef view)
  184. {
  185. HIViewSetNeedsDisplay (view, true);
  186. HIViewRef child = HIViewGetFirstSubview (view);
  187. while (child != 0)
  188. {
  189. recursiveHIViewRepaint (child);
  190. child = HIViewGetNextView (child);
  191. }
  192. }
  193. void timerCallback()
  194. {
  195. setOurSizeToEmbeddedViewSize();
  196. // To avoid strange overpainting problems when the UI is first opened, we'll
  197. // repaint it a few times during the first second that it's on-screen..
  198. if ((Time::getCurrentTime() - creationTime).inMilliseconds() < 1000)
  199. recursiveHIViewRepaint (HIViewGetRoot (wrapperWindow));
  200. }
  201. OSStatus carbonEventHandler (EventHandlerCallRef /*nextHandlerRef*/, EventRef event)
  202. {
  203. switch (GetEventKind (event))
  204. {
  205. case kEventWindowHandleDeactivate:
  206. ActivateWindow (wrapperWindow, TRUE);
  207. return noErr;
  208. case kEventWindowGetClickActivation:
  209. {
  210. getTopLevelComponent()->toFront (false);
  211. [carbonWindow makeKeyAndOrderFront: nil];
  212. ClickActivationResult howToHandleClick = kActivateAndHandleClick;
  213. SetEventParameter (event, kEventParamClickActivation, typeClickActivationResult,
  214. sizeof (ClickActivationResult), &howToHandleClick);
  215. HIViewSetNeedsDisplay (embeddedView, true);
  216. return noErr;
  217. }
  218. }
  219. return eventNotHandledErr;
  220. }
  221. static pascal OSStatus carbonEventCallback (EventHandlerCallRef nextHandlerRef, EventRef event, void* userData)
  222. {
  223. return ((CarbonViewWrapperComponent*) userData)->carbonEventHandler (nextHandlerRef, event);
  224. }
  225. protected:
  226. WindowRef wrapperWindow;
  227. NSWindow* carbonWindow;
  228. HIViewRef embeddedView;
  229. bool recursiveResize;
  230. Time creationTime;
  231. EventHandlerRef eventHandlerRef;
  232. NSWindow* getOwnerWindow() const { return [((NSView*) getWindowHandle()) window]; }
  233. };
  234. #endif // __JUCE_MAC_CARBONVIEWWRAPPERCOMPONENT_JUCEHEADER__