The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

345 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #include "../../../src/juce_core/basics/juce_StandardHeader.h"
  24. #include <Carbon/Carbon.h>
  25. BEGIN_JUCE_NAMESPACE
  26. #include "../../../src/juce_appframework/events/juce_MessageManager.h"
  27. #include "../../../src/juce_appframework/application/juce_Application.h"
  28. #include "../../../src/juce_appframework/gui/components/juce_Desktop.h"
  29. #include "../../../src/juce_core/text/juce_StringArray.h"
  30. #include "../../../src/juce_core/threads/juce_Thread.h"
  31. #include "../../../src/juce_core/misc/juce_PlatformUtilities.h"
  32. #undef Point
  33. static int kJUCEClass = FOUR_CHAR_CODE ('JUCE');
  34. const int kJUCEKind = 1;
  35. const int kCallbackKind = 2;
  36. extern void juce_HandleProcessFocusChange();
  37. extern void juce_maximiseAllMinimisedWindows();
  38. extern void juce_InvokeMainMenuCommand (const HICommand& command);
  39. extern void juce_MainMenuAboutToBeUsed();
  40. static pascal OSStatus EventHandlerProc (EventHandlerCallRef, EventRef theEvent, void* userData)
  41. {
  42. void* event = 0;
  43. GetEventParameter (theEvent, 'mess', typeVoidPtr, 0, sizeof (void*), 0, &event);
  44. if (event != 0)
  45. MessageManager::getInstance()->deliverMessage (event);
  46. return noErr;
  47. }
  48. struct CallbackMessagePayload
  49. {
  50. MessageCallbackFunction* function;
  51. void* parameter;
  52. void* volatile result;
  53. bool volatile hasBeenExecuted;
  54. };
  55. static pascal OSStatus CallbackHandlerProc (EventHandlerCallRef, EventRef theEvent, void* userData)
  56. {
  57. CallbackMessagePayload* pl = 0;
  58. GetEventParameter (theEvent, 'mess', typeVoidPtr, 0, sizeof(pl), 0, &pl);
  59. if (pl != 0)
  60. {
  61. pl->result = (*pl->function) (pl->parameter);
  62. pl->hasBeenExecuted = true;
  63. }
  64. return noErr;
  65. }
  66. static pascal OSStatus MouseClickHandlerProc (EventHandlerCallRef, EventRef theEvent, void* userData)
  67. {
  68. ::Point where;
  69. GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, 0, sizeof(::Point), 0, &where);
  70. WindowRef window;
  71. if (FindWindow (where, &window) == inMenuBar)
  72. {
  73. // turn off the wait cursor before going in here..
  74. const int oldTimeBeforeWaitCursor = MessageManager::getInstance()->getTimeBeforeShowingWaitCursor();
  75. MessageManager::getInstance()->setTimeBeforeShowingWaitCursor (0);
  76. if (Component::getCurrentlyModalComponent() != 0)
  77. Component::getCurrentlyModalComponent()->inputAttemptWhenModal();
  78. juce_MainMenuAboutToBeUsed();
  79. MenuSelect (where);
  80. HiliteMenu (0);
  81. MessageManager::getInstance()->setTimeBeforeShowingWaitCursor (oldTimeBeforeWaitCursor);
  82. return noErr;
  83. }
  84. return eventNotHandledErr;
  85. }
  86. static pascal OSErr QuitAppleEventHandler (const AppleEvent *appleEvt, AppleEvent* reply, long refcon)
  87. {
  88. if (JUCEApplication::getInstance() != 0)
  89. JUCEApplication::getInstance()->systemRequestedQuit();
  90. return noErr;
  91. }
  92. static pascal OSErr OpenDocEventHandler (const AppleEvent *appleEvt, AppleEvent* reply, long refcon)
  93. {
  94. AEDescList docs;
  95. StringArray files;
  96. if (AEGetParamDesc (appleEvt, keyDirectObject, typeAEList, &docs) == noErr)
  97. {
  98. long num;
  99. if (AECountItems (&docs, &num) == noErr)
  100. {
  101. for (int i = 1; i <= num; ++i)
  102. {
  103. FSRef file;
  104. AEKeyword keyword;
  105. DescType type;
  106. Size size;
  107. if (AEGetNthPtr (&docs, i, typeFSRef, &keyword, &type,
  108. &file, sizeof (file), &size) == noErr)
  109. {
  110. const String path (PlatformUtilities::makePathFromFSRef (&file));
  111. if (path.isNotEmpty())
  112. files.add (path.quoted());
  113. }
  114. }
  115. if (files.size() > 0
  116. && JUCEApplication::getInstance() != 0)
  117. {
  118. JUCE_TRY
  119. {
  120. JUCEApplication::getInstance()
  121. ->anotherInstanceStarted (files.joinIntoString (T(" ")));
  122. }
  123. JUCE_CATCH_ALL
  124. }
  125. }
  126. AEDisposeDesc (&docs);
  127. };
  128. return noErr;
  129. }
  130. static pascal OSStatus AppEventHandlerProc (EventHandlerCallRef, EventRef theEvent, void* userData)
  131. {
  132. const UInt32 eventClass = GetEventClass (theEvent);
  133. if (eventClass == kEventClassCommand)
  134. {
  135. HICommand command;
  136. if (GetEventParameter (theEvent, kEventParamHICommand, typeHICommand, 0, sizeof (command), 0, &command) == noErr
  137. || GetEventParameter (theEvent, kEventParamDirectObject, typeHICommand, 0, sizeof (command), 0, &command) == noErr)
  138. {
  139. if (command.commandID == kHICommandQuit)
  140. {
  141. if (JUCEApplication::getInstance() != 0)
  142. JUCEApplication::getInstance()->systemRequestedQuit();
  143. return noErr;
  144. }
  145. else if (command.commandID == kHICommandMaximizeAll
  146. || command.commandID == kHICommandMaximizeWindow
  147. || command.commandID == kHICommandBringAllToFront)
  148. {
  149. juce_maximiseAllMinimisedWindows();
  150. return noErr;
  151. }
  152. else
  153. {
  154. juce_InvokeMainMenuCommand (command);
  155. }
  156. }
  157. }
  158. else if (eventClass == kEventClassApplication)
  159. {
  160. if (GetEventKind (theEvent) == kEventAppFrontSwitched)
  161. {
  162. juce_HandleProcessFocusChange();
  163. }
  164. else if (GetEventKind (theEvent) == kEventAppShown)
  165. {
  166. // this seems to blank the windows, so we need to do a repaint..
  167. for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;)
  168. {
  169. Component* const c = Desktop::getInstance().getComponent (i);
  170. if (c != 0)
  171. c->repaint();
  172. }
  173. }
  174. }
  175. return eventNotHandledErr;
  176. }
  177. static EventQueueRef mainQueue;
  178. static EventHandlerRef juceEventHandler = 0;
  179. static EventHandlerRef callbackEventHandler = 0;
  180. //==============================================================================
  181. void MessageManager::doPlatformSpecificInitialisation()
  182. {
  183. static bool initialised = false;
  184. if (! initialised)
  185. {
  186. initialised = true;
  187. #if MACOS_10_3_OR_EARLIER
  188. // work-around for a bug in MacOS 10.2..
  189. ProcessSerialNumber junkPSN;
  190. (void) GetCurrentProcess (&junkPSN);
  191. #endif
  192. mainQueue = GetMainEventQueue();
  193. // if we're linking a Juce app to one or more dynamic libraries, we'll need different values
  194. // for this so each module doesn't interfere with the others.
  195. UnsignedWide t;
  196. Microseconds (&t);
  197. kJUCEClass ^= t.lo;
  198. }
  199. const EventTypeSpec type1 = { kJUCEClass, kJUCEKind };
  200. InstallApplicationEventHandler (NewEventHandlerUPP (EventHandlerProc), 1, &type1, 0, &juceEventHandler);
  201. const EventTypeSpec type2 = { kJUCEClass, kCallbackKind };
  202. InstallApplicationEventHandler (NewEventHandlerUPP (CallbackHandlerProc), 1, &type2, 0, &callbackEventHandler);
  203. // only do this stuff if we're running as an application rather than a library..
  204. if (JUCEApplication::getInstance() != 0)
  205. {
  206. const EventTypeSpec type3 = { kEventClassMouse, kEventMouseDown };
  207. InstallApplicationEventHandler (NewEventHandlerUPP (MouseClickHandlerProc), 1, &type3, 0, 0);
  208. const EventTypeSpec type4[] = { { kEventClassApplication, kEventAppShown },
  209. { kEventClassApplication, kEventAppFrontSwitched },
  210. { kEventClassCommand, kEventProcessCommand } };
  211. InstallApplicationEventHandler (NewEventHandlerUPP (AppEventHandlerProc), 3, type4, 0, 0);
  212. AEInstallEventHandler (kCoreEventClass, kAEQuitApplication,
  213. NewAEEventHandlerUPP (QuitAppleEventHandler), 0, false);
  214. AEInstallEventHandler (kCoreEventClass, kAEOpenDocuments,
  215. NewAEEventHandlerUPP (OpenDocEventHandler), 0, false);
  216. }
  217. }
  218. void MessageManager::doPlatformSpecificShutdown()
  219. {
  220. if (juceEventHandler != 0)
  221. {
  222. RemoveEventHandler (juceEventHandler);
  223. juceEventHandler = 0;
  224. }
  225. if (callbackEventHandler != 0)
  226. {
  227. RemoveEventHandler (callbackEventHandler);
  228. callbackEventHandler = 0;
  229. }
  230. }
  231. bool juce_postMessageToSystemQueue (void* message)
  232. {
  233. jassert (mainQueue == GetMainEventQueue());
  234. EventRef event;
  235. if (CreateEvent (0, kJUCEClass, kJUCEKind, 0, kEventAttributeUserEvent, &event) == noErr)
  236. {
  237. SetEventParameter (event, 'mess', typeVoidPtr, sizeof (void*), &message);
  238. const bool ok = PostEventToQueue (mainQueue, event, kEventPriorityStandard) == noErr;
  239. ReleaseEvent (event);
  240. return ok;
  241. }
  242. return false;
  243. }
  244. void MessageManager::broadcastMessage (const String& value) throw()
  245. {
  246. }
  247. void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback,
  248. void* data)
  249. {
  250. if (isThisTheMessageThread())
  251. {
  252. return (*callback) (data);
  253. }
  254. else
  255. {
  256. jassert (mainQueue == GetMainEventQueue());
  257. CallbackMessagePayload cmp;
  258. cmp.function = callback;
  259. cmp.parameter = data;
  260. cmp.result = 0;
  261. cmp.hasBeenExecuted = false;
  262. EventRef event;
  263. if (CreateEvent (0, kJUCEClass, kCallbackKind, 0, kEventAttributeUserEvent, &event) == noErr)
  264. {
  265. void* v = &cmp;
  266. SetEventParameter (event, 'mess', typeVoidPtr, sizeof (void*), &v);
  267. if (PostEventToQueue (mainQueue, event, kEventPriorityStandard) == noErr)
  268. {
  269. while (! cmp.hasBeenExecuted)
  270. Thread::yield();
  271. return cmp.result;
  272. }
  273. }
  274. return 0;
  275. }
  276. }
  277. END_JUCE_NAMESPACE