fix macOS build (following Projucer changes made in Windows, which removed /Applications/JUCE/modules from its headers). move JUCE headers under source control, so that Windows and macOS can both build against same version of JUCE. remove AUv3 target (I think it's an iOS thing, so it will never work with this macOS fluidsynth dylib).
This commit is contained in:
@ -0,0 +1,347 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2017 - ROLI Ltd.
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
|
||||
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
|
||||
27th April 2017).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-5-licence
|
||||
Privacy Policy: www.juce.com/juce-5-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
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.
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class CarbonViewWrapperComponent : public Component,
|
||||
public ComponentMovementWatcher,
|
||||
public Timer
|
||||
{
|
||||
public:
|
||||
CarbonViewWrapperComponent()
|
||||
: ComponentMovementWatcher (this),
|
||||
carbonWindow (nil),
|
||||
keepPluginWindowWhenHidden (false),
|
||||
wrapperWindow (nil),
|
||||
embeddedView (0),
|
||||
recursiveResize (false),
|
||||
repaintChildOnCreation (true)
|
||||
{
|
||||
}
|
||||
|
||||
~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 handleMouseDown (int, int) {}
|
||||
virtual void handlePaint() {}
|
||||
|
||||
virtual bool getEmbeddedViewSize (int& w, int& h)
|
||||
{
|
||||
if (embeddedView == 0)
|
||||
return false;
|
||||
|
||||
HIRect bounds;
|
||||
HIViewGetBounds (embeddedView, &bounds);
|
||||
w = jmax (1, roundToInt (bounds.size.width));
|
||||
h = jmax (1, roundToInt (bounds.size.height));
|
||||
return true;
|
||||
}
|
||||
|
||||
void createWindow()
|
||||
{
|
||||
if (wrapperWindow == nil)
|
||||
{
|
||||
Rect r;
|
||||
r.left = (short) getScreenX();
|
||||
r.top = (short) getScreenY();
|
||||
r.right = (short) (r.left + getWidth());
|
||||
r.bottom = (short) (r.top + getHeight());
|
||||
|
||||
CreateNewWindow (kDocumentWindowClass,
|
||||
(WindowAttributes) (kWindowStandardHandlerAttribute | kWindowCompositingAttribute
|
||||
| kWindowNoShadowAttribute | kWindowNoTitleBarAttribute),
|
||||
&r, &wrapperWindow);
|
||||
|
||||
jassert (wrapperWindow != 0);
|
||||
if (wrapperWindow == 0)
|
||||
return;
|
||||
|
||||
carbonWindow = [[NSWindow alloc] initWithWindowRef: wrapperWindow];
|
||||
|
||||
[getOwnerWindow() addChildWindow: carbonWindow
|
||||
ordered: NSWindowAbove];
|
||||
|
||||
embeddedView = attachView (wrapperWindow, HIViewGetRoot (wrapperWindow));
|
||||
|
||||
// Check for the plugin creating its own floating window, and if there is one,
|
||||
// we need to reparent it to make it visible..
|
||||
if (carbonWindow.childWindows.count > 0)
|
||||
if (NSWindow* floatingChildWindow = [[carbonWindow childWindows] objectAtIndex: 0])
|
||||
[getOwnerWindow() addChildWindow: floatingChildWindow
|
||||
ordered: NSWindowAbove];
|
||||
|
||||
EventTypeSpec windowEventTypes[] =
|
||||
{
|
||||
{ kEventClassWindow, kEventWindowGetClickActivation },
|
||||
{ kEventClassWindow, kEventWindowHandleDeactivate },
|
||||
{ kEventClassWindow, kEventWindowBoundsChanging },
|
||||
{ kEventClassMouse, kEventMouseDown },
|
||||
{ kEventClassMouse, kEventMouseMoved },
|
||||
{ kEventClassMouse, kEventMouseDragged },
|
||||
{ kEventClassMouse, kEventMouseUp },
|
||||
{ kEventClassWindow, kEventWindowDrawContent },
|
||||
{ kEventClassWindow, kEventWindowShown },
|
||||
{ kEventClassWindow, kEventWindowHidden }
|
||||
};
|
||||
|
||||
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 != nil)
|
||||
{
|
||||
NSWindow* ownerWindow = getOwnerWindow();
|
||||
|
||||
if ([[ownerWindow childWindows] count] > 0)
|
||||
{
|
||||
[ownerWindow removeChildWindow: carbonWindow];
|
||||
[carbonWindow close];
|
||||
}
|
||||
|
||||
RemoveEventHandler (eventHandlerRef);
|
||||
DisposeWindow (wrapperWindow);
|
||||
wrapperWindow = nil;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void setOurSizeToEmbeddedViewSize()
|
||||
{
|
||||
int w, h;
|
||||
if (getEmbeddedViewSize (w, h))
|
||||
{
|
||||
if (w != getWidth() || h != getHeight())
|
||||
{
|
||||
startTimer (50);
|
||||
setSize (w, h);
|
||||
|
||||
if (Component* p = getParentComponent())
|
||||
p->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 != nil)
|
||||
{
|
||||
jassert (getTopLevelComponent()->getDesktopScaleFactor() == 1.0f);
|
||||
Rectangle<int> screenBounds (getScreenBounds() * Desktop::getInstance().getGlobalScaleFactor());
|
||||
|
||||
Rect wr;
|
||||
wr.left = (short) screenBounds.getX();
|
||||
wr.top = (short) screenBounds.getY();
|
||||
wr.right = (short) screenBounds.getRight();
|
||||
wr.bottom = (short) screenBounds.getBottom();
|
||||
|
||||
SetWindowBounds (wrapperWindow, kWindowContentRgn, &wr);
|
||||
|
||||
// This group stuff is mainly a workaround for Mackie plugins like FinalMix..
|
||||
WindowGroupRef group = GetWindowGroup (wrapperWindow);
|
||||
WindowRef attachedWindow;
|
||||
|
||||
if (GetIndexedWindow (group, 2, kWindowGroupContentsReturnWindows, &attachedWindow) == noErr)
|
||||
{
|
||||
SelectWindow (attachedWindow);
|
||||
ActivateWindow (attachedWindow, TRUE);
|
||||
HideWindow (wrapperWindow);
|
||||
}
|
||||
|
||||
ShowWindow (wrapperWindow);
|
||||
}
|
||||
|
||||
recursiveResize = false;
|
||||
}
|
||||
}
|
||||
|
||||
void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override
|
||||
{
|
||||
setEmbeddedWindowToOurSize();
|
||||
}
|
||||
|
||||
// (overridden to intercept movements of the top-level window)
|
||||
void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized) override
|
||||
{
|
||||
ComponentMovementWatcher::componentMovedOrResized (component, wasMoved, wasResized);
|
||||
|
||||
if (&component == getTopLevelComponent())
|
||||
setEmbeddedWindowToOurSize();
|
||||
}
|
||||
|
||||
void componentPeerChanged() override
|
||||
{
|
||||
deleteWindow();
|
||||
createWindow();
|
||||
}
|
||||
|
||||
void componentVisibilityChanged() override
|
||||
{
|
||||
if (isShowing())
|
||||
createWindow();
|
||||
else if (! keepPluginWindowWhenHidden)
|
||||
deleteWindow();
|
||||
|
||||
setEmbeddedWindowToOurSize();
|
||||
}
|
||||
|
||||
static void recursiveHIViewRepaint (HIViewRef view)
|
||||
{
|
||||
HIViewSetNeedsDisplay (view, true);
|
||||
HIViewRef child = HIViewGetFirstSubview (view);
|
||||
|
||||
while (child != 0)
|
||||
{
|
||||
recursiveHIViewRepaint (child);
|
||||
child = HIViewGetNextView (child);
|
||||
}
|
||||
}
|
||||
|
||||
void timerCallback() override
|
||||
{
|
||||
if (isShowing())
|
||||
{
|
||||
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 (repaintChildOnCreation && (Time::getCurrentTime() - creationTime).inMilliseconds() < 1000)
|
||||
recursiveHIViewRepaint (HIViewGetRoot (wrapperWindow));
|
||||
}
|
||||
}
|
||||
|
||||
void setRepaintsChildHIViewWhenCreated (bool b) noexcept
|
||||
{
|
||||
repaintChildOnCreation = b;
|
||||
}
|
||||
|
||||
OSStatus carbonEventHandler (EventHandlerCallRef /*nextHandlerRef*/, EventRef event)
|
||||
{
|
||||
switch (GetEventKind (event))
|
||||
{
|
||||
case kEventWindowHandleDeactivate:
|
||||
ActivateWindow (wrapperWindow, TRUE);
|
||||
return noErr;
|
||||
|
||||
case kEventWindowGetClickActivation:
|
||||
{
|
||||
getTopLevelComponent()->toFront (false);
|
||||
[carbonWindow makeKeyAndOrderFront: nil];
|
||||
|
||||
ClickActivationResult howToHandleClick = kActivateAndHandleClick;
|
||||
|
||||
SetEventParameter (event, kEventParamClickActivation, typeClickActivationResult,
|
||||
sizeof (ClickActivationResult), &howToHandleClick);
|
||||
|
||||
if (embeddedView != 0)
|
||||
HIViewSetNeedsDisplay (embeddedView, true);
|
||||
|
||||
return noErr;
|
||||
}
|
||||
}
|
||||
|
||||
return eventNotHandledErr;
|
||||
}
|
||||
|
||||
static pascal OSStatus carbonEventCallback (EventHandlerCallRef nextHandlerRef, EventRef event, void* userData)
|
||||
{
|
||||
return ((CarbonViewWrapperComponent*) userData)->carbonEventHandler (nextHandlerRef, event);
|
||||
}
|
||||
|
||||
NSWindow* carbonWindow;
|
||||
bool keepPluginWindowWhenHidden;
|
||||
|
||||
protected:
|
||||
WindowRef wrapperWindow;
|
||||
HIViewRef embeddedView;
|
||||
bool recursiveResize, repaintChildOnCreation;
|
||||
Time creationTime;
|
||||
|
||||
EventHandlerRef eventHandlerRef;
|
||||
|
||||
NSWindow* getOwnerWindow() const { return [((NSView*) getWindowHandle()) window]; }
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// Non-public utility function that hosts can use if they need to get hold of the
|
||||
// internals of a carbon wrapper window..
|
||||
void* getCarbonWindow (Component* possibleCarbonComponent)
|
||||
{
|
||||
if (CarbonViewWrapperComponent* cv = dynamic_cast<CarbonViewWrapperComponent*> (possibleCarbonComponent))
|
||||
return cv->carbonWindow;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace juce
|
Reference in New Issue
Block a user