|
|
@@ -1,344 +1,503 @@ |
|
|
|
/*
|
|
|
|
==============================================================================
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
==============================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "../../../src/juce_core/basics/juce_StandardHeader.h"
|
|
|
|
#include <Carbon/Carbon.h>
|
|
|
|
|
|
|
|
BEGIN_JUCE_NAMESPACE
|
|
|
|
|
|
|
|
#include "../../../src/juce_appframework/events/juce_MessageManager.h"
|
|
|
|
#include "../../../src/juce_appframework/application/juce_Application.h"
|
|
|
|
#include "../../../src/juce_appframework/gui/components/juce_Desktop.h"
|
|
|
|
#include "../../../src/juce_core/text/juce_StringArray.h"
|
|
|
|
#include "../../../src/juce_core/threads/juce_Thread.h"
|
|
|
|
#include "../../../src/juce_core/misc/juce_PlatformUtilities.h"
|
|
|
|
|
|
|
|
#undef Point
|
|
|
|
|
|
|
|
static int kJUCEClass = FOUR_CHAR_CODE ('JUCE');
|
|
|
|
const int kJUCEKind = 1;
|
|
|
|
const int kCallbackKind = 2;
|
|
|
|
|
|
|
|
extern void juce_HandleProcessFocusChange();
|
|
|
|
extern void juce_maximiseAllMinimisedWindows();
|
|
|
|
extern void juce_InvokeMainMenuCommand (const HICommand& command);
|
|
|
|
extern void juce_MainMenuAboutToBeUsed();
|
|
|
|
|
|
|
|
static pascal OSStatus EventHandlerProc (EventHandlerCallRef, EventRef theEvent, void* userData)
|
|
|
|
{
|
|
|
|
void* event = 0;
|
|
|
|
GetEventParameter (theEvent, 'mess', typeVoidPtr, 0, sizeof (void*), 0, &event);
|
|
|
|
|
|
|
|
if (event != 0)
|
|
|
|
MessageManager::getInstance()->deliverMessage (event);
|
|
|
|
|
|
|
|
return noErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct CallbackMessagePayload
|
|
|
|
{
|
|
|
|
MessageCallbackFunction* function;
|
|
|
|
void* parameter;
|
|
|
|
void* volatile result;
|
|
|
|
bool volatile hasBeenExecuted;
|
|
|
|
};
|
|
|
|
|
|
|
|
static pascal OSStatus CallbackHandlerProc (EventHandlerCallRef, EventRef theEvent, void* userData)
|
|
|
|
{
|
|
|
|
CallbackMessagePayload* pl = 0;
|
|
|
|
GetEventParameter (theEvent, 'mess', typeVoidPtr, 0, sizeof(pl), 0, &pl);
|
|
|
|
|
|
|
|
if (pl != 0)
|
|
|
|
{
|
|
|
|
pl->result = (*pl->function) (pl->parameter);
|
|
|
|
pl->hasBeenExecuted = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return noErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static pascal OSStatus MouseClickHandlerProc (EventHandlerCallRef, EventRef theEvent, void* userData)
|
|
|
|
{
|
|
|
|
::Point where;
|
|
|
|
GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, 0, sizeof(::Point), 0, &where);
|
|
|
|
WindowRef window;
|
|
|
|
if (FindWindow (where, &window) == inMenuBar)
|
|
|
|
{
|
|
|
|
// turn off the wait cursor before going in here..
|
|
|
|
const int oldTimeBeforeWaitCursor = MessageManager::getInstance()->getTimeBeforeShowingWaitCursor();
|
|
|
|
MessageManager::getInstance()->setTimeBeforeShowingWaitCursor (0);
|
|
|
|
|
|
|
|
if (Component::getCurrentlyModalComponent() != 0)
|
|
|
|
Component::getCurrentlyModalComponent()->inputAttemptWhenModal();
|
|
|
|
|
|
|
|
juce_MainMenuAboutToBeUsed();
|
|
|
|
MenuSelect (where);
|
|
|
|
HiliteMenu (0);
|
|
|
|
|
|
|
|
MessageManager::getInstance()->setTimeBeforeShowingWaitCursor (oldTimeBeforeWaitCursor);
|
|
|
|
return noErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return eventNotHandledErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static pascal OSErr QuitAppleEventHandler (const AppleEvent *appleEvt, AppleEvent* reply, long refcon)
|
|
|
|
{
|
|
|
|
if (JUCEApplication::getInstance() != 0)
|
|
|
|
JUCEApplication::getInstance()->systemRequestedQuit();
|
|
|
|
|
|
|
|
return noErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static pascal OSErr OpenDocEventHandler (const AppleEvent *appleEvt, AppleEvent* reply, long refcon)
|
|
|
|
{
|
|
|
|
AEDescList docs;
|
|
|
|
StringArray files;
|
|
|
|
|
|
|
|
if (AEGetParamDesc (appleEvt, keyDirectObject, typeAEList, &docs) == noErr)
|
|
|
|
{
|
|
|
|
long num;
|
|
|
|
if (AECountItems (&docs, &num) == noErr)
|
|
|
|
{
|
|
|
|
for (int i = 1; i <= num; ++i)
|
|
|
|
{
|
|
|
|
FSRef file;
|
|
|
|
AEKeyword keyword;
|
|
|
|
DescType type;
|
|
|
|
Size size;
|
|
|
|
|
|
|
|
if (AEGetNthPtr (&docs, i, typeFSRef, &keyword, &type,
|
|
|
|
&file, sizeof (file), &size) == noErr)
|
|
|
|
{
|
|
|
|
const String path (PlatformUtilities::makePathFromFSRef (&file));
|
|
|
|
|
|
|
|
if (path.isNotEmpty())
|
|
|
|
files.add (path.quoted());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (files.size() > 0
|
|
|
|
&& JUCEApplication::getInstance() != 0)
|
|
|
|
{
|
|
|
|
JUCE_TRY
|
|
|
|
{
|
|
|
|
JUCEApplication::getInstance()
|
|
|
|
->anotherInstanceStarted (files.joinIntoString (T(" ")));
|
|
|
|
}
|
|
|
|
JUCE_CATCH_ALL
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AEDisposeDesc (&docs);
|
|
|
|
};
|
|
|
|
|
|
|
|
return noErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static pascal OSStatus AppEventHandlerProc (EventHandlerCallRef, EventRef theEvent, void* userData)
|
|
|
|
{
|
|
|
|
const UInt32 eventClass = GetEventClass (theEvent);
|
|
|
|
|
|
|
|
if (eventClass == kEventClassCommand)
|
|
|
|
{
|
|
|
|
HICommand command;
|
|
|
|
|
|
|
|
if (GetEventParameter (theEvent, kEventParamHICommand, typeHICommand, 0, sizeof (command), 0, &command) == noErr
|
|
|
|
|| GetEventParameter (theEvent, kEventParamDirectObject, typeHICommand, 0, sizeof (command), 0, &command) == noErr)
|
|
|
|
{
|
|
|
|
if (command.commandID == kHICommandQuit)
|
|
|
|
{
|
|
|
|
if (JUCEApplication::getInstance() != 0)
|
|
|
|
JUCEApplication::getInstance()->systemRequestedQuit();
|
|
|
|
|
|
|
|
return noErr;
|
|
|
|
}
|
|
|
|
else if (command.commandID == kHICommandMaximizeAll
|
|
|
|
|| command.commandID == kHICommandMaximizeWindow
|
|
|
|
|| command.commandID == kHICommandBringAllToFront)
|
|
|
|
{
|
|
|
|
juce_maximiseAllMinimisedWindows();
|
|
|
|
return noErr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
juce_InvokeMainMenuCommand (command);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (eventClass == kEventClassApplication)
|
|
|
|
{
|
|
|
|
if (GetEventKind (theEvent) == kEventAppFrontSwitched)
|
|
|
|
{
|
|
|
|
juce_HandleProcessFocusChange();
|
|
|
|
}
|
|
|
|
else if (GetEventKind (theEvent) == kEventAppShown)
|
|
|
|
{
|
|
|
|
// this seems to blank the windows, so we need to do a repaint..
|
|
|
|
for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;)
|
|
|
|
{
|
|
|
|
Component* const c = Desktop::getInstance().getComponent (i);
|
|
|
|
|
|
|
|
if (c != 0)
|
|
|
|
c->repaint();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return eventNotHandledErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static EventQueueRef mainQueue;
|
|
|
|
static EventHandlerRef juceEventHandler = 0;
|
|
|
|
static EventHandlerRef callbackEventHandler = 0;
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
void MessageManager::doPlatformSpecificInitialisation()
|
|
|
|
{
|
|
|
|
static bool initialised = false;
|
|
|
|
|
|
|
|
if (! initialised)
|
|
|
|
{
|
|
|
|
initialised = true;
|
|
|
|
|
|
|
|
#if MACOS_10_3_OR_EARLIER
|
|
|
|
// work-around for a bug in MacOS 10.2..
|
|
|
|
ProcessSerialNumber junkPSN;
|
|
|
|
(void) GetCurrentProcess (&junkPSN);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
mainQueue = GetMainEventQueue();
|
|
|
|
|
|
|
|
// if we're linking a Juce app to one or more dynamic libraries, we'll need different values
|
|
|
|
// for this so each module doesn't interfere with the others.
|
|
|
|
UnsignedWide t;
|
|
|
|
Microseconds (&t);
|
|
|
|
kJUCEClass ^= t.lo;
|
|
|
|
}
|
|
|
|
|
|
|
|
const EventTypeSpec type1 = { kJUCEClass, kJUCEKind };
|
|
|
|
InstallApplicationEventHandler (NewEventHandlerUPP (EventHandlerProc), 1, &type1, 0, &juceEventHandler);
|
|
|
|
|
|
|
|
const EventTypeSpec type2 = { kJUCEClass, kCallbackKind };
|
|
|
|
InstallApplicationEventHandler (NewEventHandlerUPP (CallbackHandlerProc), 1, &type2, 0, &callbackEventHandler);
|
|
|
|
|
|
|
|
// only do this stuff if we're running as an application rather than a library..
|
|
|
|
if (JUCEApplication::getInstance() != 0)
|
|
|
|
{
|
|
|
|
const EventTypeSpec type3 = { kEventClassMouse, kEventMouseDown };
|
|
|
|
InstallApplicationEventHandler (NewEventHandlerUPP (MouseClickHandlerProc), 1, &type3, 0, 0);
|
|
|
|
|
|
|
|
const EventTypeSpec type4[] = { { kEventClassApplication, kEventAppShown },
|
|
|
|
{ kEventClassApplication, kEventAppFrontSwitched },
|
|
|
|
{ kEventClassCommand, kEventProcessCommand } };
|
|
|
|
|
|
|
|
InstallApplicationEventHandler (NewEventHandlerUPP (AppEventHandlerProc), 3, type4, 0, 0);
|
|
|
|
|
|
|
|
AEInstallEventHandler (kCoreEventClass, kAEQuitApplication,
|
|
|
|
NewAEEventHandlerUPP (QuitAppleEventHandler), 0, false);
|
|
|
|
|
|
|
|
AEInstallEventHandler (kCoreEventClass, kAEOpenDocuments,
|
|
|
|
NewAEEventHandlerUPP (OpenDocEventHandler), 0, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MessageManager::doPlatformSpecificShutdown()
|
|
|
|
{
|
|
|
|
if (juceEventHandler != 0)
|
|
|
|
{
|
|
|
|
RemoveEventHandler (juceEventHandler);
|
|
|
|
juceEventHandler = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (callbackEventHandler != 0)
|
|
|
|
{
|
|
|
|
RemoveEventHandler (callbackEventHandler);
|
|
|
|
callbackEventHandler = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool juce_postMessageToSystemQueue (void* message)
|
|
|
|
{
|
|
|
|
jassert (mainQueue == GetMainEventQueue());
|
|
|
|
|
|
|
|
EventRef event;
|
|
|
|
if (CreateEvent (0, kJUCEClass, kJUCEKind, 0, kEventAttributeUserEvent, &event) == noErr)
|
|
|
|
{
|
|
|
|
SetEventParameter (event, 'mess', typeVoidPtr, sizeof (void*), &message);
|
|
|
|
const bool ok = PostEventToQueue (mainQueue, event, kEventPriorityStandard) == noErr;
|
|
|
|
ReleaseEvent (event);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MessageManager::broadcastMessage (const String& value) throw()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback,
|
|
|
|
void* data)
|
|
|
|
{
|
|
|
|
if (isThisTheMessageThread())
|
|
|
|
{
|
|
|
|
return (*callback) (data);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
jassert (mainQueue == GetMainEventQueue());
|
|
|
|
|
|
|
|
CallbackMessagePayload cmp;
|
|
|
|
cmp.function = callback;
|
|
|
|
cmp.parameter = data;
|
|
|
|
cmp.result = 0;
|
|
|
|
cmp.hasBeenExecuted = false;
|
|
|
|
|
|
|
|
EventRef event;
|
|
|
|
if (CreateEvent (0, kJUCEClass, kCallbackKind, 0, kEventAttributeUserEvent, &event) == noErr)
|
|
|
|
{
|
|
|
|
void* v = &cmp;
|
|
|
|
SetEventParameter (event, 'mess', typeVoidPtr, sizeof (void*), &v);
|
|
|
|
|
|
|
|
if (PostEventToQueue (mainQueue, event, kEventPriorityStandard) == noErr)
|
|
|
|
{
|
|
|
|
while (! cmp.hasBeenExecuted)
|
|
|
|
Thread::yield();
|
|
|
|
|
|
|
|
return cmp.result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
END_JUCE_NAMESPACE
|
|
|
|
/* |
|
|
|
============================================================================== |
|
|
|
|
|
|
|
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. |
|
|
|
|
|
|
|
============================================================================== |
|
|
|
*/ |
|
|
|
|
|
|
|
#include "juce_mac_NativeHeaders.h" |
|
|
|
#include <Carbon/Carbon.h> |
|
|
|
|
|
|
|
BEGIN_JUCE_NAMESPACE |
|
|
|
|
|
|
|
#include "../../../src/juce_appframework/events/juce_MessageManager.h" |
|
|
|
#include "../../../src/juce_appframework/application/juce_Application.h" |
|
|
|
#include "../../../src/juce_appframework/gui/components/juce_Desktop.h" |
|
|
|
#include "../../../src/juce_core/text/juce_StringArray.h" |
|
|
|
#include "../../../src/juce_core/threads/juce_Thread.h" |
|
|
|
#include "../../../src/juce_core/misc/juce_PlatformUtilities.h" |
|
|
|
|
|
|
|
#undef Point |
|
|
|
|
|
|
|
extern void juce_HandleProcessFocusChange(); |
|
|
|
extern void juce_maximiseAllMinimisedWindows(); |
|
|
|
extern void juce_InvokeMainMenuCommand (const HICommand& command); |
|
|
|
extern void juce_MainMenuAboutToBeUsed(); |
|
|
|
|
|
|
|
struct CallbackMessagePayload |
|
|
|
{ |
|
|
|
MessageCallbackFunction* function; |
|
|
|
void* parameter; |
|
|
|
void* volatile result; |
|
|
|
bool volatile hasBeenExecuted; |
|
|
|
}; |
|
|
|
|
|
|
|
END_JUCE_NAMESPACE |
|
|
|
|
|
|
|
#if JUCE_COCOA |
|
|
|
|
|
|
|
NSString* juceMessageName = 0; |
|
|
|
|
|
|
|
@interface JuceAppDelegate : NSObject |
|
|
|
id oldDelegate; |
|
|
|
- (JuceAppDelegate*) init; |
|
|
|
- (void) dealloc; |
|
|
|
- (BOOL) application: (NSApplication*) theApplication openFile: (NSString*) filename; |
|
|
|
- (void) application: (NSApplication*) sender openFiles: (NSArray*) filenames; |
|
|
|
- (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) app; |
|
|
|
- (void) applicationDidBecomeActive: (NSNotification*) aNotification; |
|
|
|
- (void) applicationDidResignActive: (NSNotification*) aNotification; |
|
|
|
- (void) applicationWillUnhide: (NSNotification*) aNotification; |
|
|
|
- (void) customEvent: (NSNotification*) aNotification; |
|
|
|
- (void) performCallback: (id) info; |
|
|
|
@end |
|
|
|
|
|
|
|
@implementation JuceAppDelegate |
|
|
|
|
|
|
|
- (JuceAppDelegate*) init |
|
|
|
{ |
|
|
|
[super init]; |
|
|
|
|
|
|
|
NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; |
|
|
|
|
|
|
|
if (JUCE_NAMESPACE::JUCEApplication::getInstance() != 0) |
|
|
|
{ |
|
|
|
oldDelegate = [NSApp delegate]; |
|
|
|
[NSApp setDelegate: self]; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
oldDelegate = 0; |
|
|
|
[center addObserver: self selector: @selector (applicationDidResignActive:) |
|
|
|
name: NSApplicationDidResignActiveNotification object: NSApp]; |
|
|
|
|
|
|
|
[center addObserver: self selector: @selector (applicationDidBecomeActive:) |
|
|
|
name: NSApplicationDidBecomeActiveNotification object: NSApp]; |
|
|
|
|
|
|
|
[center addObserver: self selector: @selector (applicationWillUnhide:) |
|
|
|
name: NSApplicationWillUnhideNotification object: NSApp]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
[center addObserver: self selector: @selector (customEvent:) |
|
|
|
name: juceMessageName object: nil]; |
|
|
|
|
|
|
|
return self; |
|
|
|
} |
|
|
|
|
|
|
|
- (void) dealloc |
|
|
|
{ |
|
|
|
if (oldDelegate != 0) |
|
|
|
[NSApp setDelegate: oldDelegate]; |
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver: self]; |
|
|
|
[super dealloc]; |
|
|
|
} |
|
|
|
|
|
|
|
- (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) app |
|
|
|
{ |
|
|
|
if (JUCE_NAMESPACE::JUCEApplication::getInstance() != 0) |
|
|
|
JUCE_NAMESPACE::JUCEApplication::getInstance()->systemRequestedQuit(); |
|
|
|
|
|
|
|
return NSTerminateLater; |
|
|
|
} |
|
|
|
|
|
|
|
- (BOOL) application: (NSApplication*) app openFile: (NSString*) filename |
|
|
|
{ |
|
|
|
if (JUCE_NAMESPACE::JUCEApplication::getInstance() != 0) |
|
|
|
{ |
|
|
|
JUCE_NAMESPACE::JUCEApplication::getInstance()->anotherInstanceStarted (nsStringToJuce (filename)); |
|
|
|
return YES; |
|
|
|
} |
|
|
|
|
|
|
|
return NO; |
|
|
|
} |
|
|
|
|
|
|
|
- (void) application: (NSApplication*) sender openFiles: (NSArray*) filenames |
|
|
|
{ |
|
|
|
JUCE_NAMESPACE::StringArray files; |
|
|
|
for (int i = 0; i < [filenames count]; ++i) |
|
|
|
files.add (nsStringToJuce ((NSString*) [filenames objectAtIndex: i])); |
|
|
|
|
|
|
|
if (files.size() > 0 && JUCE_NAMESPACE::JUCEApplication::getInstance() != 0) |
|
|
|
JUCE_NAMESPACE::JUCEApplication::getInstance()->anotherInstanceStarted (files.joinIntoString (T(" "))); |
|
|
|
} |
|
|
|
|
|
|
|
- (void) applicationDidBecomeActive: (NSNotification*) aNotification |
|
|
|
{ |
|
|
|
JUCE_NAMESPACE::juce_HandleProcessFocusChange(); |
|
|
|
} |
|
|
|
|
|
|
|
- (void) applicationDidResignActive: (NSNotification*) aNotification |
|
|
|
{ |
|
|
|
JUCE_NAMESPACE::juce_HandleProcessFocusChange(); |
|
|
|
} |
|
|
|
|
|
|
|
- (void) applicationWillUnhide: (NSNotification*) aNotification |
|
|
|
{ |
|
|
|
JUCE_NAMESPACE::juce_maximiseAllMinimisedWindows(); |
|
|
|
} |
|
|
|
|
|
|
|
- (void) customEvent: (NSNotification*) n |
|
|
|
{ |
|
|
|
void* message = 0; |
|
|
|
[((NSData*) [n object]) getBytes: &message length: sizeof (message)]; |
|
|
|
|
|
|
|
if (message != 0) |
|
|
|
JUCE_NAMESPACE::MessageManager::getInstance()->deliverMessage (message); |
|
|
|
} |
|
|
|
|
|
|
|
- (void) performCallback: (id) info |
|
|
|
{ |
|
|
|
JUCE_NAMESPACE::CallbackMessagePayload* pl = (JUCE_NAMESPACE::CallbackMessagePayload*) info; |
|
|
|
|
|
|
|
if (pl != 0) |
|
|
|
{ |
|
|
|
pl->result = (*pl->function) (pl->parameter); |
|
|
|
pl->hasBeenExecuted = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@end |
|
|
|
#endif |
|
|
|
|
|
|
|
BEGIN_JUCE_NAMESPACE |
|
|
|
|
|
|
|
|
|
|
|
#if JUCE_COCOA |
|
|
|
static JuceAppDelegate* juceAppDelegate = 0; |
|
|
|
|
|
|
|
#else |
|
|
|
static int kJUCEClass = FOUR_CHAR_CODE ('JUCE'); |
|
|
|
const int kJUCEKind = 1; |
|
|
|
const int kCallbackKind = 2; |
|
|
|
|
|
|
|
|
|
|
|
static pascal OSStatus EventHandlerProc (EventHandlerCallRef, EventRef theEvent, void* userData) |
|
|
|
{ |
|
|
|
void* event = 0; |
|
|
|
GetEventParameter (theEvent, 'mess', typeVoidPtr, 0, sizeof (void*), 0, &event); |
|
|
|
|
|
|
|
if (event != 0) |
|
|
|
MessageManager::getInstance()->deliverMessage (event); |
|
|
|
|
|
|
|
return noErr; |
|
|
|
} |
|
|
|
|
|
|
|
static pascal OSStatus CallbackHandlerProc (EventHandlerCallRef, EventRef theEvent, void* userData) |
|
|
|
{ |
|
|
|
CallbackMessagePayload* pl = 0; |
|
|
|
GetEventParameter (theEvent, 'mess', typeVoidPtr, 0, sizeof(pl), 0, &pl); |
|
|
|
|
|
|
|
if (pl != 0) |
|
|
|
{ |
|
|
|
pl->result = (*pl->function) (pl->parameter); |
|
|
|
pl->hasBeenExecuted = true; |
|
|
|
} |
|
|
|
|
|
|
|
return noErr; |
|
|
|
} |
|
|
|
|
|
|
|
static pascal OSStatus MouseClickHandlerProc (EventHandlerCallRef, EventRef theEvent, void* userData) |
|
|
|
{ |
|
|
|
::Point where; |
|
|
|
GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, 0, sizeof(::Point), 0, &where); |
|
|
|
WindowRef window; |
|
|
|
if (FindWindow (where, &window) == inMenuBar) |
|
|
|
{ |
|
|
|
// turn off the wait cursor before going in here.. |
|
|
|
const int oldTimeBeforeWaitCursor = MessageManager::getInstance()->getTimeBeforeShowingWaitCursor(); |
|
|
|
MessageManager::getInstance()->setTimeBeforeShowingWaitCursor (0); |
|
|
|
|
|
|
|
if (Component::getCurrentlyModalComponent() != 0) |
|
|
|
Component::getCurrentlyModalComponent()->inputAttemptWhenModal(); |
|
|
|
|
|
|
|
juce_MainMenuAboutToBeUsed(); |
|
|
|
MenuSelect (where); |
|
|
|
HiliteMenu (0); |
|
|
|
|
|
|
|
MessageManager::getInstance()->setTimeBeforeShowingWaitCursor (oldTimeBeforeWaitCursor); |
|
|
|
return noErr; |
|
|
|
} |
|
|
|
|
|
|
|
return eventNotHandledErr; |
|
|
|
} |
|
|
|
|
|
|
|
static pascal OSErr QuitAppleEventHandler (const AppleEvent *appleEvt, AppleEvent* reply, long refcon) |
|
|
|
{ |
|
|
|
if (JUCEApplication::getInstance() != 0) |
|
|
|
JUCEApplication::getInstance()->systemRequestedQuit(); |
|
|
|
|
|
|
|
return noErr; |
|
|
|
} |
|
|
|
|
|
|
|
static pascal OSErr OpenDocEventHandler (const AppleEvent *appleEvt, AppleEvent* reply, long refcon) |
|
|
|
{ |
|
|
|
AEDescList docs; |
|
|
|
StringArray files; |
|
|
|
|
|
|
|
if (AEGetParamDesc (appleEvt, keyDirectObject, typeAEList, &docs) == noErr) |
|
|
|
{ |
|
|
|
long num; |
|
|
|
if (AECountItems (&docs, &num) == noErr) |
|
|
|
{ |
|
|
|
for (int i = 1; i <= num; ++i) |
|
|
|
{ |
|
|
|
FSRef file; |
|
|
|
AEKeyword keyword; |
|
|
|
DescType type; |
|
|
|
Size size; |
|
|
|
|
|
|
|
if (AEGetNthPtr (&docs, i, typeFSRef, &keyword, &type, |
|
|
|
&file, sizeof (file), &size) == noErr) |
|
|
|
{ |
|
|
|
const String path (PlatformUtilities::makePathFromFSRef (&file)); |
|
|
|
|
|
|
|
if (path.isNotEmpty()) |
|
|
|
files.add (path.quoted()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (files.size() > 0 |
|
|
|
&& JUCEApplication::getInstance() != 0) |
|
|
|
{ |
|
|
|
JUCE_TRY |
|
|
|
{ |
|
|
|
JUCEApplication::getInstance() |
|
|
|
->anotherInstanceStarted (files.joinIntoString (T(" "))); |
|
|
|
} |
|
|
|
JUCE_CATCH_ALL |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
AEDisposeDesc (&docs); |
|
|
|
}; |
|
|
|
|
|
|
|
return noErr; |
|
|
|
} |
|
|
|
|
|
|
|
static pascal OSStatus AppEventHandlerProc (EventHandlerCallRef, EventRef theEvent, void* userData) |
|
|
|
{ |
|
|
|
const UInt32 eventClass = GetEventClass (theEvent); |
|
|
|
|
|
|
|
if (eventClass == kEventClassCommand) |
|
|
|
{ |
|
|
|
HICommand command; |
|
|
|
|
|
|
|
if (GetEventParameter (theEvent, kEventParamHICommand, typeHICommand, 0, sizeof (command), 0, &command) == noErr |
|
|
|
|| GetEventParameter (theEvent, kEventParamDirectObject, typeHICommand, 0, sizeof (command), 0, &command) == noErr) |
|
|
|
{ |
|
|
|
if (command.commandID == kHICommandQuit) |
|
|
|
{ |
|
|
|
if (JUCEApplication::getInstance() != 0) |
|
|
|
JUCEApplication::getInstance()->systemRequestedQuit(); |
|
|
|
|
|
|
|
return noErr; |
|
|
|
} |
|
|
|
else if (command.commandID == kHICommandMaximizeAll |
|
|
|
|| command.commandID == kHICommandMaximizeWindow |
|
|
|
|| command.commandID == kHICommandBringAllToFront) |
|
|
|
{ |
|
|
|
juce_maximiseAllMinimisedWindows(); |
|
|
|
return noErr; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
juce_InvokeMainMenuCommand (command); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else if (eventClass == kEventClassApplication) |
|
|
|
{ |
|
|
|
if (GetEventKind (theEvent) == kEventAppFrontSwitched) |
|
|
|
{ |
|
|
|
juce_HandleProcessFocusChange(); |
|
|
|
} |
|
|
|
else if (GetEventKind (theEvent) == kEventAppShown) |
|
|
|
{ |
|
|
|
// this seems to blank the windows, so we need to do a repaint.. |
|
|
|
for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;) |
|
|
|
{ |
|
|
|
Component* const c = Desktop::getInstance().getComponent (i); |
|
|
|
|
|
|
|
if (c != 0) |
|
|
|
c->repaint(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return eventNotHandledErr; |
|
|
|
} |
|
|
|
|
|
|
|
static EventQueueRef mainQueue; |
|
|
|
static EventHandlerRef juceEventHandler = 0; |
|
|
|
static EventHandlerRef callbackEventHandler = 0; |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
//============================================================================== |
|
|
|
void MessageManager::doPlatformSpecificInitialisation() |
|
|
|
{ |
|
|
|
static bool initialised = false; |
|
|
|
|
|
|
|
if (! initialised) |
|
|
|
{ |
|
|
|
initialised = true; |
|
|
|
|
|
|
|
#if JUCE_COCOA |
|
|
|
// if we're linking a Juce app to one or more dynamic libraries, we'll need different values |
|
|
|
// for this so each module doesn't interfere with the others. |
|
|
|
UnsignedWide t; |
|
|
|
Microseconds (&t); |
|
|
|
kJUCEClass ^= t.lo; |
|
|
|
|
|
|
|
juceMessageName = juceStringToNS ("juce_" + String::toHexString ((int) t.lo)); |
|
|
|
|
|
|
|
juceAppDelegate = [[JuceAppDelegate alloc] init]; |
|
|
|
#else |
|
|
|
mainQueue = GetMainEventQueue(); |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
#if ! JUCE_COCOA |
|
|
|
const EventTypeSpec type1 = { kJUCEClass, kJUCEKind }; |
|
|
|
InstallApplicationEventHandler (NewEventHandlerUPP (EventHandlerProc), 1, &type1, 0, &juceEventHandler); |
|
|
|
|
|
|
|
const EventTypeSpec type2 = { kJUCEClass, kCallbackKind }; |
|
|
|
InstallApplicationEventHandler (NewEventHandlerUPP (CallbackHandlerProc), 1, &type2, 0, &callbackEventHandler); |
|
|
|
|
|
|
|
// only do this stuff if we're running as an application rather than a library.. |
|
|
|
if (JUCEApplication::getInstance() != 0) |
|
|
|
{ |
|
|
|
const EventTypeSpec type3 = { kEventClassMouse, kEventMouseDown }; |
|
|
|
InstallApplicationEventHandler (NewEventHandlerUPP (MouseClickHandlerProc), 1, &type3, 0, 0); |
|
|
|
|
|
|
|
const EventTypeSpec type4[] = { { kEventClassApplication, kEventAppShown }, |
|
|
|
{ kEventClassApplication, kEventAppFrontSwitched }, |
|
|
|
{ kEventClassCommand, kEventProcessCommand } }; |
|
|
|
|
|
|
|
InstallApplicationEventHandler (NewEventHandlerUPP (AppEventHandlerProc), 3, type4, 0, 0); |
|
|
|
|
|
|
|
AEInstallEventHandler (kCoreEventClass, kAEQuitApplication, |
|
|
|
NewAEEventHandlerUPP (QuitAppleEventHandler), 0, false); |
|
|
|
|
|
|
|
AEInstallEventHandler (kCoreEventClass, kAEOpenDocuments, |
|
|
|
NewAEEventHandlerUPP (OpenDocEventHandler), 0, false); |
|
|
|
} |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
void MessageManager::doPlatformSpecificShutdown() |
|
|
|
{ |
|
|
|
if (juceEventHandler != 0) |
|
|
|
{ |
|
|
|
RemoveEventHandler (juceEventHandler); |
|
|
|
juceEventHandler = 0; |
|
|
|
} |
|
|
|
|
|
|
|
if (callbackEventHandler != 0) |
|
|
|
{ |
|
|
|
RemoveEventHandler (callbackEventHandler); |
|
|
|
callbackEventHandler = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
bool juce_postMessageToSystemQueue (void* message) |
|
|
|
{ |
|
|
|
#if JUCE_COCOA |
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName: juceMessageName |
|
|
|
object: [NSData dataWithBytes: &message |
|
|
|
length: (int) sizeof (message)]]; |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
#else |
|
|
|
jassert (mainQueue == GetMainEventQueue()); |
|
|
|
|
|
|
|
EventRef event; |
|
|
|
if (CreateEvent (0, kJUCEClass, kJUCEKind, 0, kEventAttributeUserEvent, &event) == noErr) |
|
|
|
{ |
|
|
|
SetEventParameter (event, 'mess', typeVoidPtr, sizeof (void*), &message); |
|
|
|
const bool ok = PostEventToQueue (mainQueue, event, kEventPriorityStandard) == noErr; |
|
|
|
ReleaseEvent (event); |
|
|
|
return ok; |
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
void MessageManager::broadcastMessage (const String& value) throw() |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, |
|
|
|
void* data) |
|
|
|
{ |
|
|
|
if (isThisTheMessageThread()) |
|
|
|
{ |
|
|
|
return (*callback) (data); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
CallbackMessagePayload cmp; |
|
|
|
cmp.function = callback; |
|
|
|
cmp.parameter = data; |
|
|
|
cmp.result = 0; |
|
|
|
cmp.hasBeenExecuted = false; |
|
|
|
|
|
|
|
#if JUCE_COCOA |
|
|
|
[juceAppDelegate performSelectorOnMainThread: @selector (performCallback:) |
|
|
|
withObject: (id) &cmp |
|
|
|
waitUntilDone: YES]; |
|
|
|
|
|
|
|
return cmp.result; |
|
|
|
|
|
|
|
#else |
|
|
|
jassert (mainQueue == GetMainEventQueue()); |
|
|
|
|
|
|
|
EventRef event; |
|
|
|
if (CreateEvent (0, kJUCEClass, kCallbackKind, 0, kEventAttributeUserEvent, &event) == noErr) |
|
|
|
{ |
|
|
|
void* v = &cmp; |
|
|
|
SetEventParameter (event, 'mess', typeVoidPtr, sizeof (void*), &v); |
|
|
|
|
|
|
|
if (PostEventToQueue (mainQueue, event, kEventPriorityStandard) == noErr) |
|
|
|
{ |
|
|
|
while (! cmp.hasBeenExecuted) |
|
|
|
Thread::yield(); |
|
|
|
|
|
|
|
return cmp.result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
#endif |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
END_JUCE_NAMESPACE |