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.

245 lines
7.8KB

  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. /** Creates a floating carbon window that can be used to hold a carbon UI.
  24. This is a handy class that's designed to be inlined where needed, e.g.
  25. in the audio plugin hosting code.
  26. */
  27. class CarbonViewWrapperComponent : public Component,
  28. public ComponentMovementWatcher,
  29. public Timer
  30. {
  31. public:
  32. CarbonViewWrapperComponent()
  33. : ComponentMovementWatcher (this),
  34. wrapperWindow (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 x, int y) {}
  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, roundFloatToInt (bounds.size.width));
  54. h = jmax (1, roundFloatToInt (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. NSWindow* carbonWindow = [[NSWindow alloc] initWithWindowRef: wrapperWindow];
  74. NSWindow* ownerWindow = [((NSView*) getWindowHandle()) window];
  75. [ownerWindow addChildWindow: carbonWindow
  76. ordered: NSWindowAbove];
  77. embeddedView = attachView (wrapperWindow, HIViewGetRoot (wrapperWindow));
  78. EventTypeSpec windowEventTypes[] = { { kEventClassWindow, kEventWindowGetClickActivation },
  79. { kEventClassWindow, kEventWindowHandleDeactivate } };
  80. EventHandlerUPP upp = NewEventHandlerUPP (carbonEventCallback);
  81. InstallWindowEventHandler (wrapperWindow, upp,
  82. sizeof (windowEventTypes) / sizeof (EventTypeSpec),
  83. windowEventTypes, this, &eventHandlerRef);
  84. setOurSizeToEmbeddedViewSize();
  85. setEmbeddedWindowToOurSize();
  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. }
  170. OSStatus carbonEventHandler (EventHandlerCallRef nextHandlerRef,
  171. EventRef event)
  172. {
  173. switch (GetEventKind (event))
  174. {
  175. case kEventWindowHandleDeactivate:
  176. ActivateWindow (wrapperWindow, TRUE);
  177. break;
  178. case kEventWindowGetClickActivation:
  179. {
  180. getTopLevelComponent()->toFront (false);
  181. ClickActivationResult howToHandleClick = kActivateAndHandleClick;
  182. SetEventParameter (event, kEventParamClickActivation, typeClickActivationResult,
  183. sizeof (ClickActivationResult), &howToHandleClick);
  184. }
  185. break;
  186. }
  187. return noErr;
  188. }
  189. static pascal OSStatus carbonEventCallback (EventHandlerCallRef nextHandlerRef,
  190. EventRef event, void* userData)
  191. {
  192. return ((CarbonViewWrapperComponent*) userData)->carbonEventHandler (nextHandlerRef, event);
  193. }
  194. protected:
  195. WindowRef wrapperWindow;
  196. HIViewRef embeddedView;
  197. bool recursiveResize;
  198. EventHandlerRef eventHandlerRef;
  199. };