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.

263 lines
8.5KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #ifndef __JUCE_MAC_CARBONVIEWWRAPPERCOMPONENT_JUCEHEADER__
  24. #define __JUCE_MAC_CARBONVIEWWRAPPERCOMPONENT_JUCEHEADER__
  25. //==============================================================================
  26. /**
  27. Creates a floating carbon window that can be used to hold a carbon UI.
  28. This is a handy class that's designed to be inlined where needed, e.g.
  29. in the audio plugin hosting code.
  30. */
  31. class CarbonViewWrapperComponent : public Component,
  32. public ComponentMovementWatcher,
  33. public Timer
  34. {
  35. public:
  36. CarbonViewWrapperComponent()
  37. : ComponentMovementWatcher (this),
  38. wrapperWindow (0),
  39. embeddedView (0),
  40. recursiveResize (false)
  41. {
  42. }
  43. virtual ~CarbonViewWrapperComponent()
  44. {
  45. jassert (embeddedView == 0); // must call deleteWindow() in the subclass's destructor!
  46. }
  47. virtual HIViewRef attachView (WindowRef windowRef, HIViewRef rootView) = 0;
  48. virtual void removeView (HIViewRef embeddedView) = 0;
  49. virtual void mouseDown (int x, int y) {}
  50. virtual void paint() {}
  51. virtual bool getEmbeddedViewSize (int& w, int& h)
  52. {
  53. if (embeddedView == 0)
  54. return false;
  55. HIRect bounds;
  56. HIViewGetBounds (embeddedView, &bounds);
  57. w = jmax (1, roundFloatToInt (bounds.size.width));
  58. h = jmax (1, roundFloatToInt (bounds.size.height));
  59. return true;
  60. }
  61. void createWindow()
  62. {
  63. if (wrapperWindow == 0)
  64. {
  65. Rect r;
  66. r.left = getScreenX();
  67. r.top = getScreenY();
  68. r.right = r.left + getWidth();
  69. r.bottom = r.top + getHeight();
  70. CreateNewWindow (kDocumentWindowClass,
  71. (WindowAttributes) (kWindowStandardHandlerAttribute | kWindowCompositingAttribute
  72. | kWindowNoShadowAttribute | kWindowNoTitleBarAttribute),
  73. &r, &wrapperWindow);
  74. jassert (wrapperWindow != 0);
  75. if (wrapperWindow == 0)
  76. return;
  77. NSWindow* carbonWindow = [[NSWindow alloc] initWithWindowRef: wrapperWindow];
  78. NSWindow* ownerWindow = [((NSView*) getWindowHandle()) window];
  79. [ownerWindow addChildWindow: carbonWindow
  80. ordered: NSWindowAbove];
  81. embeddedView = attachView (wrapperWindow, HIViewGetRoot (wrapperWindow));
  82. EventTypeSpec windowEventTypes[] = { { kEventClassWindow, kEventWindowGetClickActivation },
  83. { kEventClassWindow, kEventWindowHandleDeactivate } };
  84. EventHandlerUPP upp = NewEventHandlerUPP (carbonEventCallback);
  85. InstallWindowEventHandler (wrapperWindow, upp,
  86. sizeof (windowEventTypes) / sizeof (EventTypeSpec),
  87. windowEventTypes, this, &eventHandlerRef);
  88. setOurSizeToEmbeddedViewSize();
  89. setEmbeddedWindowToOurSize();
  90. creationTime = Time::getCurrentTime();
  91. }
  92. }
  93. void deleteWindow()
  94. {
  95. removeView (embeddedView);
  96. embeddedView = 0;
  97. if (wrapperWindow != 0)
  98. {
  99. RemoveEventHandler (eventHandlerRef);
  100. DisposeWindow (wrapperWindow);
  101. wrapperWindow = 0;
  102. }
  103. }
  104. //==============================================================================
  105. void setOurSizeToEmbeddedViewSize()
  106. {
  107. int w, h;
  108. if (getEmbeddedViewSize (w, h))
  109. {
  110. if (w != getWidth() || h != getHeight())
  111. {
  112. startTimer (50);
  113. setSize (w, h);
  114. if (getParentComponent() != 0)
  115. getParentComponent()->setSize (w, h);
  116. }
  117. else
  118. {
  119. startTimer (jlimit (50, 500, getTimerInterval() + 20));
  120. }
  121. }
  122. else
  123. {
  124. stopTimer();
  125. }
  126. }
  127. void setEmbeddedWindowToOurSize()
  128. {
  129. if (! recursiveResize)
  130. {
  131. recursiveResize = true;
  132. if (embeddedView != 0)
  133. {
  134. HIRect r;
  135. r.origin.x = 0;
  136. r.origin.y = 0;
  137. r.size.width = (float) getWidth();
  138. r.size.height = (float) getHeight();
  139. HIViewSetFrame (embeddedView, &r);
  140. }
  141. if (wrapperWindow != 0)
  142. {
  143. Rect wr;
  144. wr.left = getScreenX();
  145. wr.top = getScreenY();
  146. wr.right = wr.left + getWidth();
  147. wr.bottom = wr.top + getHeight();
  148. SetWindowBounds (wrapperWindow, kWindowContentRgn, &wr);
  149. ShowWindow (wrapperWindow);
  150. }
  151. recursiveResize = false;
  152. }
  153. }
  154. void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/)
  155. {
  156. setEmbeddedWindowToOurSize();
  157. }
  158. void componentPeerChanged()
  159. {
  160. deleteWindow();
  161. createWindow();
  162. }
  163. void componentVisibilityChanged (Component&)
  164. {
  165. if (isShowing())
  166. createWindow();
  167. else
  168. deleteWindow();
  169. setEmbeddedWindowToOurSize();
  170. }
  171. void timerCallback()
  172. {
  173. setOurSizeToEmbeddedViewSize();
  174. // To avoid strange overpainting problems when the UI is first opened, we'll
  175. // repaint it a few times during the first second that it's on-screen..
  176. if ((Time::getCurrentTime() - creationTime).inMilliseconds() < 1000)
  177. HIViewSetNeedsDisplay (embeddedView, true);
  178. }
  179. OSStatus carbonEventHandler (EventHandlerCallRef nextHandlerRef,
  180. EventRef event)
  181. {
  182. switch (GetEventKind (event))
  183. {
  184. case kEventWindowHandleDeactivate:
  185. ActivateWindow (wrapperWindow, TRUE);
  186. break;
  187. case kEventWindowGetClickActivation:
  188. {
  189. getTopLevelComponent()->toFront (false);
  190. ClickActivationResult howToHandleClick = kActivateAndHandleClick;
  191. SetEventParameter (event, kEventParamClickActivation, typeClickActivationResult,
  192. sizeof (ClickActivationResult), &howToHandleClick);
  193. HIViewSetNeedsDisplay (embeddedView, true);
  194. }
  195. break;
  196. }
  197. return noErr;
  198. }
  199. static pascal OSStatus carbonEventCallback (EventHandlerCallRef nextHandlerRef,
  200. EventRef event, void* userData)
  201. {
  202. return ((CarbonViewWrapperComponent*) userData)->carbonEventHandler (nextHandlerRef, event);
  203. }
  204. protected:
  205. WindowRef wrapperWindow;
  206. HIViewRef embeddedView;
  207. bool recursiveResize;
  208. Time creationTime;
  209. EventHandlerRef eventHandlerRef;
  210. };
  211. #endif // __JUCE_MAC_CARBONVIEWWRAPPERCOMPONENT_JUCEHEADER__