/* ============================================================================== 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 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