/* ============================================================================== This file is part of the JUCE library - "Jules' Utility Class Extensions" Copyright 2004-7 by Raw Material Software ltd. ------------------------------------------------------------------------------ JUCE can be redistributed and/or modified under the terms of the GNU General Public License, as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with JUCE; if not, visit www.gnu.org/licenses or write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ------------------------------------------------------------------------------ If you'd like to release a closed-source product which uses JUCE, commercial licenses are also available: visit www.rawmaterialsoftware.com/juce for more information. ============================================================================== */ #ifndef __JUCE_MAC_CARBONVIEWWRAPPERCOMPONENT_JUCEHEADER__ #define __JUCE_MAC_CARBONVIEWWRAPPERCOMPONENT_JUCEHEADER__ //============================================================================== /** Creates a floating carbon window that can be used to hold a carbon UI. This is a handy class that's designed to be inlined where needed, e.g. in the audio plugin hosting code. */ class CarbonViewWrapperComponent : public Component, public ComponentMovementWatcher, public Timer { public: CarbonViewWrapperComponent() : ComponentMovementWatcher (this), wrapperWindow (0), embeddedView (0), recursiveResize (false) { } virtual ~CarbonViewWrapperComponent() { jassert (embeddedView == 0); // must call deleteWindow() in the subclass's destructor! } virtual HIViewRef attachView (WindowRef windowRef, HIViewRef rootView) = 0; virtual void removeView (HIViewRef embeddedView) = 0; virtual void mouseDown (int x, int y) {} virtual void paint() {} virtual bool getEmbeddedViewSize (int& w, int& h) { if (embeddedView == 0) return false; HIRect bounds; HIViewGetBounds (embeddedView, &bounds); w = jmax (1, roundFloatToInt (bounds.size.width)); h = jmax (1, roundFloatToInt (bounds.size.height)); return true; } void createWindow() { if (wrapperWindow == 0) { Rect r; r.left = getScreenX(); r.top = getScreenY(); r.right = r.left + getWidth(); r.bottom = r.top + getHeight(); CreateNewWindow (kDocumentWindowClass, (WindowAttributes) (kWindowStandardHandlerAttribute | kWindowCompositingAttribute | kWindowNoShadowAttribute | kWindowNoTitleBarAttribute), &r, &wrapperWindow); jassert (wrapperWindow != 0); if (wrapperWindow == 0) return; NSWindow* carbonWindow = [[NSWindow alloc] initWithWindowRef: wrapperWindow]; NSWindow* ownerWindow = [((NSView*) getWindowHandle()) window]; [ownerWindow addChildWindow: carbonWindow ordered: NSWindowAbove]; embeddedView = attachView (wrapperWindow, HIViewGetRoot (wrapperWindow)); EventTypeSpec windowEventTypes[] = { { kEventClassWindow, kEventWindowGetClickActivation }, { kEventClassWindow, kEventWindowHandleDeactivate } }; EventHandlerUPP upp = NewEventHandlerUPP (carbonEventCallback); InstallWindowEventHandler (wrapperWindow, upp, sizeof (windowEventTypes) / sizeof (EventTypeSpec), windowEventTypes, this, &eventHandlerRef); setOurSizeToEmbeddedViewSize(); setEmbeddedWindowToOurSize(); creationTime = Time::getCurrentTime(); } } void deleteWindow() { removeView (embeddedView); embeddedView = 0; if (wrapperWindow != 0) { RemoveEventHandler (eventHandlerRef); DisposeWindow (wrapperWindow); wrapperWindow = 0; } } //============================================================================== void setOurSizeToEmbeddedViewSize() { int w, h; if (getEmbeddedViewSize (w, h)) { if (w != getWidth() || h != getHeight()) { startTimer (50); setSize (w, h); if (getParentComponent() != 0) getParentComponent()->setSize (w, h); } else { startTimer (jlimit (50, 500, getTimerInterval() + 20)); } } else { stopTimer(); } } void setEmbeddedWindowToOurSize() { if (! recursiveResize) { recursiveResize = true; if (embeddedView != 0) { HIRect r; r.origin.x = 0; r.origin.y = 0; r.size.width = (float) getWidth(); r.size.height = (float) getHeight(); HIViewSetFrame (embeddedView, &r); } if (wrapperWindow != 0) { Rect wr; wr.left = getScreenX(); wr.top = getScreenY(); wr.right = wr.left + getWidth(); wr.bottom = wr.top + getHeight(); SetWindowBounds (wrapperWindow, kWindowContentRgn, &wr); ShowWindow (wrapperWindow); } recursiveResize = false; } } void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) { setEmbeddedWindowToOurSize(); } void componentPeerChanged() { deleteWindow(); createWindow(); } void componentVisibilityChanged (Component&) { if (isShowing()) createWindow(); else deleteWindow(); setEmbeddedWindowToOurSize(); } void timerCallback() { setOurSizeToEmbeddedViewSize(); // To avoid strange overpainting problems when the UI is first opened, we'll // repaint it a few times during the first second that it's on-screen.. if ((Time::getCurrentTime() - creationTime).inMilliseconds() < 1000) HIViewSetNeedsDisplay (embeddedView, true); } OSStatus carbonEventHandler (EventHandlerCallRef nextHandlerRef, EventRef event) { switch (GetEventKind (event)) { case kEventWindowHandleDeactivate: ActivateWindow (wrapperWindow, TRUE); break; case kEventWindowGetClickActivation: { getTopLevelComponent()->toFront (false); ClickActivationResult howToHandleClick = kActivateAndHandleClick; SetEventParameter (event, kEventParamClickActivation, typeClickActivationResult, sizeof (ClickActivationResult), &howToHandleClick); HIViewSetNeedsDisplay (embeddedView, true); } break; } return noErr; } static pascal OSStatus carbonEventCallback (EventHandlerCallRef nextHandlerRef, EventRef event, void* userData) { return ((CarbonViewWrapperComponent*) userData)->carbonEventHandler (nextHandlerRef, event); } protected: WindowRef wrapperWindow; HIViewRef embeddedView; bool recursiveResize; Time creationTime; EventHandlerRef eventHandlerRef; }; #endif // __JUCE_MAC_CARBONVIEWWRAPPERCOMPONENT_JUCEHEADER__