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.

343 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. // work-around for a bug in MacOS 10.2..
  188. ProcessSerialNumber junkPSN;
  189. (void) GetCurrentProcess (&junkPSN);
  190. mainQueue = GetMainEventQueue();
  191. // if we're linking a Juce app to one or more dynamic libraries, we'll need different values
  192. // for this so each module doesn't interfere with the others.
  193. UnsignedWide t;
  194. Microseconds (&t);
  195. kJUCEClass ^= t.lo;
  196. }
  197. const EventTypeSpec type1 = { kJUCEClass, kJUCEKind };
  198. InstallApplicationEventHandler (NewEventHandlerUPP (EventHandlerProc), 1, &type1, 0, &juceEventHandler);
  199. const EventTypeSpec type2 = { kJUCEClass, kCallbackKind };
  200. InstallApplicationEventHandler (NewEventHandlerUPP (CallbackHandlerProc), 1, &type2, 0, &callbackEventHandler);
  201. // only do this stuff if we're running as an application rather than a library..
  202. if (JUCEApplication::getInstance() != 0)
  203. {
  204. const EventTypeSpec type3 = { kEventClassMouse, kEventMouseDown };
  205. InstallApplicationEventHandler (NewEventHandlerUPP (MouseClickHandlerProc), 1, &type3, 0, 0);
  206. const EventTypeSpec type4[] = { { kEventClassApplication, kEventAppShown },
  207. { kEventClassApplication, kEventAppFrontSwitched },
  208. { kEventClassCommand, kEventProcessCommand } };
  209. InstallApplicationEventHandler (NewEventHandlerUPP (AppEventHandlerProc), 3, type4, 0, 0);
  210. AEInstallEventHandler (kCoreEventClass, kAEQuitApplication,
  211. NewAEEventHandlerUPP (QuitAppleEventHandler), 0, false);
  212. AEInstallEventHandler (kCoreEventClass, kAEOpenDocuments,
  213. NewAEEventHandlerUPP (OpenDocEventHandler), 0, false);
  214. }
  215. }
  216. void MessageManager::doPlatformSpecificShutdown()
  217. {
  218. if (juceEventHandler != 0)
  219. {
  220. RemoveEventHandler (juceEventHandler);
  221. juceEventHandler = 0;
  222. }
  223. if (callbackEventHandler != 0)
  224. {
  225. RemoveEventHandler (callbackEventHandler);
  226. callbackEventHandler = 0;
  227. }
  228. }
  229. bool juce_postMessageToSystemQueue (void* message)
  230. {
  231. jassert (mainQueue == GetMainEventQueue());
  232. EventRef event;
  233. if (CreateEvent (0, kJUCEClass, kJUCEKind, 0, kEventAttributeUserEvent, &event) == noErr)
  234. {
  235. SetEventParameter (event, 'mess', typeVoidPtr, sizeof (void*), &message);
  236. const bool ok = PostEventToQueue (mainQueue, event, kEventPriorityStandard) == noErr;
  237. ReleaseEvent (event);
  238. return ok;
  239. }
  240. return false;
  241. }
  242. void MessageManager::broadcastMessage (const String& value) throw()
  243. {
  244. }
  245. void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback,
  246. void* data)
  247. {
  248. if (isThisTheMessageThread())
  249. {
  250. return (*callback) (data);
  251. }
  252. else
  253. {
  254. jassert (mainQueue == GetMainEventQueue());
  255. CallbackMessagePayload cmp;
  256. cmp.function = callback;
  257. cmp.parameter = data;
  258. cmp.result = 0;
  259. cmp.hasBeenExecuted = false;
  260. EventRef event;
  261. if (CreateEvent (0, kJUCEClass, kCallbackKind, 0, kEventAttributeUserEvent, &event) == noErr)
  262. {
  263. void* v = &cmp;
  264. SetEventParameter (event, 'mess', typeVoidPtr, sizeof (void*), &v);
  265. if (PostEventToQueue (mainQueue, event, kEventPriorityStandard) == noErr)
  266. {
  267. while (! cmp.hasBeenExecuted)
  268. Thread::yield();
  269. return cmp.result;
  270. }
  271. }
  272. return 0;
  273. }
  274. }
  275. END_JUCE_NAMESPACE