|  | /*
  ==============================================================================
   This file is part of the JUCE library.
   Copyright (c) 2015 - ROLI Ltd.
   Permission is granted to use this software under the terms of either:
   a) the GPL v2 (or any later version)
   b) the Affero GPL v3
   Details of these licenses can be found 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.juce.com for more information.
  ==============================================================================
*/
// Your project must contain an AppConfig.h file with your project-specific settings in it,
// and your header search path must make it accessible to the module's files.
#include "AppConfig.h"
#include "../utility/juce_CheckSettingMacros.h"
#if JucePlugin_Build_VST3
#define JUCE_MAC_WINDOW_VISIBITY_BODGE 1
#include "../utility/juce_IncludeSystemHeaders.h"
#include "../utility/juce_IncludeModuleHeaders.h"
#include "../utility/juce_FakeMouseMoveGenerator.h"
#include "../utility/juce_CarbonVisibility.h"
#undef Component
#undef Point
//==============================================================================
namespace juce
{
    static void initialiseMac()
    {
       #if ! JUCE_64BIT
        NSApplicationLoad();
       #endif
    }
   #if ! JUCE_64BIT
    static void updateComponentPos (Component* const comp)
    {
        DBG ("updateComponentPos()");
        HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int)
        comp->getProperties() ["dummyViewRef"].toString().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;
    }
   #endif
    static void* attachComponentToWindowRef (Component* comp, void* windowRef, bool isHIView)
    {
        DBG ("attachComponentToWindowRef()");
        JUCE_AUTORELEASEPOOL
        {
           #if JUCE_64BIT
            (void) isHIView;
            NSView* parentView = (NSView*) windowRef;
           #if JucePlugin_EditorRequiresKeyboardFocus
            comp->addToDesktop (0, parentView);
           #else
            comp->addToDesktop (ComponentPeer::windowIgnoresKeyPresses, parentView);
           #endif
            // (this workaround is because Wavelab provides a zero-size parent view..)
            if ([parentView frame].size.height == 0)
                [((NSView*) comp->getWindowHandle()) setFrameOrigin: NSZeroPoint];
            comp->setVisible (true);
            comp->toFront (false);
            [[parentView window] setAcceptsMouseMovedEvents: YES];
            return parentView;
           #else
            //treat NSView like 64bit
            if (! isHIView)
            {
                NSView* parentView = (NSView*) windowRef;
               #if JucePlugin_EditorRequiresKeyboardFocus
                comp->addToDesktop (0, parentView);
               #else
                comp->addToDesktop (ComponentPeer::windowIgnoresKeyPresses, parentView);
               #endif
                // (this workaround is because Wavelab provides a zero-size parent view..)
                if ([parentView frame].size.height == 0)
                    [((NSView*) comp->getWindowHandle()) setFrameOrigin: NSZeroPoint];
                comp->setVisible (true);
                comp->toFront (false);
                [[parentView window] setAcceptsMouseMovedEvents: YES];
                return parentView;
            }
            NSWindow* hostWindow = [[NSWindow alloc] initWithWindowRef: windowRef];
            [hostWindow retain];
            [hostWindow setCanHide: YES];
            [hostWindow setReleasedWhenClosed: YES];
            HIViewRef parentView = nullptr;
            WindowAttributes attributes;
            GetWindowAttributes ((WindowRef) windowRef, &attributes);
            if ((attributes & kWindowCompositingAttribute) != 0)
            {
                HIViewRef root = HIViewGetRoot ((WindowRef) windowRef);
                HIViewFindByID (root, kHIViewWindowContentID, &parentView);
                if (parentView == nullptr)
                    parentView = root;
            }
            else
            {
                GetRootControl ((WindowRef) windowRef, (ControlRef*) &parentView);
                if (parentView == nullptr)
                    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}, { (float) comp->getWidth(), (float) comp->getHeight()} };
            HIViewSetFrame (dummyView, &r);
            HIViewAddSubview (parentView, dummyView);
            comp->getProperties().set ("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->getProperties().set ("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];
            attachWindowHidingHooks (comp, (WindowRef) windowRef, hostWindow);
            return hostWindow;
           #endif
        }
    }
    static void detachComponentFromWindowRef (Component* comp, void* nsWindow, bool isHIView)
    {
        JUCE_AUTORELEASEPOOL
        {
           #if ! JUCE_64BIT
            if (isHIView)
            {
                JUCE_AUTORELEASEPOOL
                {
                    EventHandlerRef ref = (EventHandlerRef) (void*) (pointer_sized_int)
                    comp->getProperties() ["boundsEventRef"].toString().getHexValue64();
                    RemoveEventHandler (ref);
                    removeWindowHidingHooks (comp);
                    HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int)
                    comp->getProperties() ["dummyViewRef"].toString().getHexValue64();
                    if (HIViewIsValid (dummyView))
                        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);
                return;
            }
           #endif
            (void) nsWindow; (void) isHIView;
            comp->removeFromDesktop();
        }
    }
    static void setNativeHostWindowSize (void* nsWindow, Component* component, int newWidth, int newHeight, bool isHIView)
    {
        JUCE_AUTORELEASEPOOL
        {
           #if ! JUCE_64BIT
            if (isHIView)
            {
                if (HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int)
                                            component->getProperties() ["dummyViewRef"].toString().getHexValue64())
                {
                    HIRect frameRect;
                    HIViewGetFrame (dummyView, &frameRect);
                    frameRect.size.width = newWidth;
                    frameRect.size.height = newHeight;
                    HIViewSetFrame (dummyView, &frameRect);
                }
                return;
            }
           #endif
            (void) nsWindow; (void) isHIView;
            component->setSize (newWidth, newHeight);
        }
    }
} // (juce namespace)
#endif
 |