mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-02-05 03:50:07 +00:00
243 lines
8.9 KiB
Text
243 lines
8.9 KiB
Text
/*
|
|
==============================================================================
|
|
|
|
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
|
Copyright 2004-9 by Raw Material Software Ltd.
|
|
|
|
------------------------------------------------------------------------------
|
|
|
|
JUCE can be redistributed and/or modified under the terms of the GNU General
|
|
Public License (Version 2), as published by the Free Software Foundation.
|
|
A copy of the license is included in the JUCE distribution, or can be found
|
|
online at www.gnu.org/licenses.
|
|
|
|
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.
|
|
|
|
------------------------------------------------------------------------------
|
|
|
|
To release a closed-source product which uses JUCE, commercial licenses are
|
|
available: visit www.rawmaterialsoftware.com/juce for more information.
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
//==============================================================================
|
|
#include "../juce_IncludeCharacteristics.h"
|
|
|
|
#if JucePlugin_Build_VST
|
|
|
|
#include <Cocoa/Cocoa.h>
|
|
#include <Carbon/Carbon.h>
|
|
|
|
#include "../juce_PluginHeaders.h"
|
|
|
|
#define ADD_CARBON_BODGE 1 // see note below..
|
|
|
|
//==============================================================================
|
|
BEGIN_JUCE_NAMESPACE
|
|
|
|
#if ADD_CARBON_BODGE
|
|
/* When you wrap a WindowRef as an NSWindow, it seems to bugger up the HideWindow
|
|
function, so when the host tries (and fails) to hide the window, this catches
|
|
the event and does the job properly.
|
|
*/
|
|
|
|
static pascal OSStatus windowVisibilityBodge (EventHandlerCallRef, EventRef e, void* user)
|
|
{
|
|
NSWindow* hostWindow = (NSWindow*) user;
|
|
|
|
switch (GetEventKind (e))
|
|
{
|
|
case kEventWindowShown:
|
|
[hostWindow orderFront: nil];
|
|
break;
|
|
case kEventWindowHidden:
|
|
[hostWindow orderOut: nil];
|
|
break;
|
|
}
|
|
|
|
return eventNotHandledErr;
|
|
}
|
|
#endif
|
|
|
|
static void updateComponentPos (Component* const comp)
|
|
{
|
|
HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int)
|
|
comp->getComponentProperty ("dummyViewRef", false, String::empty).getHexValue64();
|
|
|
|
HIRect r;
|
|
HIViewGetFrame (dummyView, &r);
|
|
HIViewRef root;
|
|
HIViewFindByID (HIViewGetRoot (HIViewGetWindow (dummyView)), kHIViewWindowContentID, &root);
|
|
HIViewConvertRect (&r, HIViewGetSuperview (dummyView), root);
|
|
|
|
Rect windowPos;
|
|
GetWindowBounds (HIViewGetWindow (dummyView), kWindowContentRgn, &windowPos);
|
|
|
|
comp->setTopLeftPosition ((int) (windowPos.left + r.origin.x),
|
|
(int) (windowPos.top + r.origin.y));
|
|
}
|
|
|
|
static pascal OSStatus viewBoundsChangedEvent (EventHandlerCallRef, EventRef, void* user)
|
|
{
|
|
updateComponentPos ((Component*) user);
|
|
return noErr;
|
|
}
|
|
|
|
//==============================================================================
|
|
void initialiseMac()
|
|
{
|
|
NSApplicationLoad();
|
|
}
|
|
|
|
void* attachComponentToWindowRef (Component* comp, void* windowRef)
|
|
{
|
|
const ScopedAutoReleasePool pool;
|
|
|
|
NSWindow* hostWindow = [[NSWindow alloc] initWithWindowRef: windowRef];
|
|
[hostWindow retain];
|
|
[hostWindow setCanHide: YES];
|
|
[hostWindow setReleasedWhenClosed: YES];
|
|
|
|
HIViewRef parentView = 0;
|
|
|
|
WindowAttributes attributes;
|
|
GetWindowAttributes ((WindowRef) windowRef, &attributes);
|
|
if ((attributes & kWindowCompositingAttribute) != 0)
|
|
{
|
|
HIViewRef root = HIViewGetRoot ((WindowRef) windowRef);
|
|
HIViewFindByID (root, kHIViewWindowContentID, &parentView);
|
|
|
|
if (parentView == 0)
|
|
parentView = root;
|
|
}
|
|
else
|
|
{
|
|
GetRootControl ((WindowRef) windowRef, (ControlRef*) &parentView);
|
|
|
|
if (parentView == 0)
|
|
CreateRootControl ((WindowRef) windowRef, (ControlRef*) &parentView);
|
|
}
|
|
|
|
// It seems that the only way to successfully position our overlaid window is by putting a dummy
|
|
// HIView into the host's carbon window, and then catching events to see when it gets repositioned
|
|
HIViewRef dummyView = 0;
|
|
HIImageViewCreate (0, &dummyView);
|
|
HIRect r = { {0, 0}, {comp->getWidth(), comp->getHeight()} };
|
|
HIViewSetFrame (dummyView, &r);
|
|
HIViewAddSubview (parentView, dummyView);
|
|
comp->setComponentProperty ("dummyViewRef", String::toHexString ((pointer_sized_int) (void*) dummyView));
|
|
|
|
EventHandlerRef ref;
|
|
const EventTypeSpec kControlBoundsChangedEvent = { kEventClassControl, kEventControlBoundsChanged };
|
|
InstallEventHandler (GetControlEventTarget (dummyView), NewEventHandlerUPP (viewBoundsChangedEvent), 1, &kControlBoundsChangedEvent, (void*) comp, &ref);
|
|
comp->setComponentProperty ("boundsEventRef", String::toHexString ((pointer_sized_int) (void*) ref));
|
|
|
|
updateComponentPos (comp);
|
|
|
|
#if ! JucePlugin_EditorRequiresKeyboardFocus
|
|
comp->addToDesktop (ComponentPeer::windowIsTemporary | ComponentPeer::windowIgnoresKeyPresses);
|
|
#else
|
|
comp->addToDesktop (ComponentPeer::windowIsTemporary);
|
|
#endif
|
|
|
|
comp->setVisible (true);
|
|
comp->toFront (false);
|
|
|
|
NSView* pluginView = (NSView*) comp->getWindowHandle();
|
|
NSWindow* pluginWindow = [pluginView window];
|
|
[pluginWindow setExcludedFromWindowsMenu: YES];
|
|
[pluginWindow setCanHide: YES];
|
|
|
|
[hostWindow addChildWindow: pluginWindow
|
|
ordered: NSWindowAbove];
|
|
[hostWindow orderFront: nil];
|
|
[pluginWindow orderFront: nil];
|
|
|
|
#if ADD_CARBON_BODGE
|
|
// Adds a callback bodge to work around some problems with wrapped
|
|
// carbon windows..
|
|
const EventTypeSpec eventsToCatch[] = {
|
|
{ kEventClassWindow, kEventWindowShown },
|
|
{ kEventClassWindow, kEventWindowHidden }
|
|
};
|
|
|
|
InstallWindowEventHandler ((WindowRef) windowRef,
|
|
NewEventHandlerUPP (windowVisibilityBodge),
|
|
GetEventTypeCount (eventsToCatch), eventsToCatch,
|
|
(void*) hostWindow, &ref);
|
|
comp->setComponentProperty ("carbonEventRef", String::toHexString ((pointer_sized_int) (void*) ref));
|
|
#endif
|
|
|
|
return hostWindow;
|
|
}
|
|
|
|
void detachComponentFromWindowRef (Component* comp, void* nsWindow)
|
|
{
|
|
{
|
|
const ScopedAutoReleasePool pool;
|
|
|
|
EventHandlerRef ref = (EventHandlerRef) (void*) (pointer_sized_int)
|
|
comp->getComponentProperty ("boundsEventRef", false, String::empty).getHexValue64();
|
|
RemoveEventHandler (ref);
|
|
|
|
#if ADD_CARBON_BODGE
|
|
ref = (EventHandlerRef) (void*) (pointer_sized_int)
|
|
comp->getComponentProperty ("carbonEventRef", false, String::empty).getHexValue64();
|
|
RemoveEventHandler (ref);
|
|
#endif
|
|
|
|
HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int)
|
|
comp->getComponentProperty ("dummyViewRef", false, String::empty).getHexValue64();
|
|
CFRelease (dummyView);
|
|
|
|
NSWindow* hostWindow = (NSWindow*) nsWindow;
|
|
NSView* pluginView = (NSView*) comp->getWindowHandle();
|
|
NSWindow* pluginWindow = [pluginView window];
|
|
|
|
[hostWindow removeChildWindow: pluginWindow];
|
|
comp->removeFromDesktop();
|
|
|
|
[hostWindow release];
|
|
}
|
|
|
|
// The event loop needs to be run between closing the window and deleting the plugin,
|
|
// presumably to let the cocoa objects get tidied up. Leaving out this line causes crashes
|
|
// in Live and Reaper when you delete the plugin with its window open.
|
|
// (Doing it this way rather than using a single longer timout means that we can guarantee
|
|
// how many messages will be dispatched, which seems to be vital in Reaper)
|
|
for (int i = 20; --i >= 0;)
|
|
MessageManager::getInstance()->runDispatchLoopUntil (1);
|
|
}
|
|
|
|
void setNativeHostWindowSize (void* nsWindow, Component* component, int newWidth, int newHeight)
|
|
{
|
|
NSWindow* hostWindow = (NSWindow*) nsWindow;
|
|
if (hostWindow != 0)
|
|
{
|
|
ScopedAutoReleasePool pool;
|
|
|
|
// Can't use the cocoa NSWindow resizing code, or it messes up in Live.
|
|
Rect r;
|
|
GetWindowBounds ((WindowRef) [hostWindow windowRef], kWindowContentRgn, &r);
|
|
r.right += newWidth - component->getWidth();
|
|
r.bottom += newHeight - component->getHeight();
|
|
SetWindowBounds ((WindowRef) [hostWindow windowRef], kWindowContentRgn, &r);
|
|
|
|
r.left = r.top = 0;
|
|
InvalWindowRect ((WindowRef) [hostWindow windowRef], &r);
|
|
//[[hostWindow contentView] setNeedsDisplay: YES];
|
|
}
|
|
}
|
|
|
|
void checkWindowVisibility (void* nsWindow, Component* comp)
|
|
{
|
|
NSWindow* hostWindow = (NSWindow*) nsWindow;
|
|
comp->setVisible ([hostWindow isVisible]);
|
|
}
|
|
|
|
END_JUCE_NAMESPACE
|
|
|
|
#endif
|