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.

257 lines
8.3KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 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. embeddedView (0),
  35. recursiveResize (false)
  36. {
  37. }
  38. virtual ~CarbonViewWrapperComponent()
  39. {
  40. jassert (embeddedView == 0); // must call deleteWindow() in the subclass's destructor!
  41. }
  42. virtual HIViewRef attachView (WindowRef windowRef, HIViewRef rootView) = 0;
  43. virtual void removeView (HIViewRef embeddedView) = 0;
  44. virtual void mouseDown (int x, int y) {}
  45. virtual void paint() {}
  46. virtual bool getEmbeddedViewSize (int& w, int& h)
  47. {
  48. if (embeddedView == 0)
  49. return false;
  50. HIRect bounds;
  51. HIViewGetBounds (embeddedView, &bounds);
  52. w = jmax (1, roundFloatToInt (bounds.size.width));
  53. h = jmax (1, roundFloatToInt (bounds.size.height));
  54. return true;
  55. }
  56. void createWindow()
  57. {
  58. if (wrapperWindow == 0)
  59. {
  60. Rect r;
  61. r.left = getScreenX();
  62. r.top = getScreenY();
  63. r.right = r.left + getWidth();
  64. r.bottom = r.top + getHeight();
  65. CreateNewWindow (kDocumentWindowClass,
  66. (WindowAttributes) (kWindowStandardHandlerAttribute | kWindowCompositingAttribute
  67. | kWindowNoShadowAttribute | kWindowNoTitleBarAttribute),
  68. &r, &wrapperWindow);
  69. jassert (wrapperWindow != 0);
  70. if (wrapperWindow == 0)
  71. return;
  72. NSWindow* carbonWindow = [[NSWindow alloc] initWithWindowRef: wrapperWindow];
  73. NSWindow* ownerWindow = [((NSView*) getWindowHandle()) window];
  74. [ownerWindow addChildWindow: carbonWindow
  75. ordered: NSWindowAbove];
  76. embeddedView = attachView (wrapperWindow, HIViewGetRoot (wrapperWindow));
  77. EventTypeSpec windowEventTypes[] = { { kEventClassWindow, kEventWindowGetClickActivation },
  78. { kEventClassWindow, kEventWindowHandleDeactivate } };
  79. EventHandlerUPP upp = NewEventHandlerUPP (carbonEventCallback);
  80. InstallWindowEventHandler (wrapperWindow, upp,
  81. sizeof (windowEventTypes) / sizeof (EventTypeSpec),
  82. windowEventTypes, this, &eventHandlerRef);
  83. setOurSizeToEmbeddedViewSize();
  84. setEmbeddedWindowToOurSize();
  85. creationTime = Time::getCurrentTime();
  86. }
  87. }
  88. void deleteWindow()
  89. {
  90. removeView (embeddedView);
  91. embeddedView = 0;
  92. if (wrapperWindow != 0)
  93. {
  94. RemoveEventHandler (eventHandlerRef);
  95. DisposeWindow (wrapperWindow);
  96. wrapperWindow = 0;
  97. }
  98. }
  99. //==============================================================================
  100. void setOurSizeToEmbeddedViewSize()
  101. {
  102. int w, h;
  103. if (getEmbeddedViewSize (w, h))
  104. {
  105. if (w != getWidth() || h != getHeight())
  106. {
  107. startTimer (50);
  108. setSize (w, h);
  109. if (getParentComponent() != 0)
  110. getParentComponent()->setSize (w, h);
  111. }
  112. else
  113. {
  114. startTimer (jlimit (50, 500, getTimerInterval() + 20));
  115. }
  116. }
  117. else
  118. {
  119. stopTimer();
  120. }
  121. }
  122. void setEmbeddedWindowToOurSize()
  123. {
  124. if (! recursiveResize)
  125. {
  126. recursiveResize = true;
  127. if (embeddedView != 0)
  128. {
  129. HIRect r;
  130. r.origin.x = 0;
  131. r.origin.y = 0;
  132. r.size.width = (float) getWidth();
  133. r.size.height = (float) getHeight();
  134. HIViewSetFrame (embeddedView, &r);
  135. }
  136. if (wrapperWindow != 0)
  137. {
  138. Rect wr;
  139. wr.left = getScreenX();
  140. wr.top = getScreenY();
  141. wr.right = wr.left + getWidth();
  142. wr.bottom = wr.top + getHeight();
  143. SetWindowBounds (wrapperWindow, kWindowContentRgn, &wr);
  144. ShowWindow (wrapperWindow);
  145. }
  146. recursiveResize = false;
  147. }
  148. }
  149. void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/)
  150. {
  151. setEmbeddedWindowToOurSize();
  152. }
  153. void componentPeerChanged()
  154. {
  155. deleteWindow();
  156. createWindow();
  157. }
  158. void componentVisibilityChanged (Component&)
  159. {
  160. if (isShowing())
  161. createWindow();
  162. else
  163. deleteWindow();
  164. setEmbeddedWindowToOurSize();
  165. }
  166. void timerCallback()
  167. {
  168. setOurSizeToEmbeddedViewSize();
  169. // To avoid strange overpainting problems when the UI is first opened, we'll
  170. // repaint it a few times during the first second that it's on-screen..
  171. if ((Time::getCurrentTime() - creationTime).inMilliseconds() < 1000)
  172. HIViewSetNeedsDisplay (embeddedView, true);
  173. }
  174. OSStatus carbonEventHandler (EventHandlerCallRef nextHandlerRef,
  175. EventRef event)
  176. {
  177. switch (GetEventKind (event))
  178. {
  179. case kEventWindowHandleDeactivate:
  180. ActivateWindow (wrapperWindow, TRUE);
  181. break;
  182. case kEventWindowGetClickActivation:
  183. {
  184. getTopLevelComponent()->toFront (false);
  185. ClickActivationResult howToHandleClick = kActivateAndHandleClick;
  186. SetEventParameter (event, kEventParamClickActivation, typeClickActivationResult,
  187. sizeof (ClickActivationResult), &howToHandleClick);
  188. HIViewSetNeedsDisplay (embeddedView, true);
  189. }
  190. break;
  191. }
  192. return noErr;
  193. }
  194. static pascal OSStatus carbonEventCallback (EventHandlerCallRef nextHandlerRef,
  195. EventRef event, void* userData)
  196. {
  197. return ((CarbonViewWrapperComponent*) userData)->carbonEventHandler (nextHandlerRef, event);
  198. }
  199. protected:
  200. WindowRef wrapperWindow;
  201. HIViewRef embeddedView;
  202. bool recursiveResize;
  203. Time creationTime;
  204. EventHandlerRef eventHandlerRef;
  205. };
  206. #endif // __JUCE_MAC_CARBONVIEWWRAPPERCOMPONENT_JUCEHEADER__