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.

286 lines
8.5KB

  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. // (This file gets included by juce_mac_NativeCode.mm, rather than being
  24. // compiled on its own).
  25. #ifdef JUCE_INCLUDED_FILE
  26. struct CallbackMessagePayload
  27. {
  28. MessageCallbackFunction* function;
  29. void* parameter;
  30. void* volatile result;
  31. bool volatile hasBeenExecuted;
  32. };
  33. END_JUCE_NAMESPACE
  34. using namespace JUCE_NAMESPACE;
  35. @interface JuceAppDelegate : NSObject
  36. {
  37. id oldDelegate;
  38. }
  39. - (JuceAppDelegate*) init;
  40. - (void) dealloc;
  41. - (BOOL) application: (NSApplication*) theApplication openFile: (NSString*) filename;
  42. - (void) application: (NSApplication*) sender openFiles: (NSArray*) filenames;
  43. - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) app;
  44. - (void) applicationDidBecomeActive: (NSNotification*) aNotification;
  45. - (void) applicationDidResignActive: (NSNotification*) aNotification;
  46. - (void) applicationWillUnhide: (NSNotification*) aNotification;
  47. - (void) customEvent: (id) data;
  48. - (void) performCallback: (id) info;
  49. - (void) dummyMethod;
  50. @end
  51. @implementation JuceAppDelegate
  52. - (JuceAppDelegate*) init
  53. {
  54. [super init];
  55. NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
  56. if (JUCEApplication::getInstance() != 0)
  57. {
  58. oldDelegate = [NSApp delegate];
  59. [NSApp setDelegate: self];
  60. }
  61. else
  62. {
  63. oldDelegate = 0;
  64. [center addObserver: self selector: @selector (applicationDidResignActive:)
  65. name: NSApplicationDidResignActiveNotification object: NSApp];
  66. [center addObserver: self selector: @selector (applicationDidBecomeActive:)
  67. name: NSApplicationDidBecomeActiveNotification object: NSApp];
  68. [center addObserver: self selector: @selector (applicationWillUnhide:)
  69. name: NSApplicationWillUnhideNotification object: NSApp];
  70. }
  71. return self;
  72. }
  73. - (void) dealloc
  74. {
  75. if (oldDelegate != 0)
  76. [NSApp setDelegate: oldDelegate];
  77. [super dealloc];
  78. }
  79. - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) app
  80. {
  81. if (JUCEApplication::getInstance() != 0)
  82. {
  83. JUCEApplication::getInstance()->systemRequestedQuit();
  84. if (! MessageManager::getInstance()->hasStopMessageBeenSent())
  85. return NSTerminateCancel;
  86. }
  87. return NSTerminateNow;
  88. }
  89. - (BOOL) application: (NSApplication*) app openFile: (NSString*) filename
  90. {
  91. if (JUCEApplication::getInstance() != 0)
  92. {
  93. JUCEApplication::getInstance()->anotherInstanceStarted (nsStringToJuce (filename));
  94. return YES;
  95. }
  96. return NO;
  97. }
  98. - (void) application: (NSApplication*) sender openFiles: (NSArray*) filenames
  99. {
  100. StringArray files;
  101. for (int i = 0; i < [filenames count]; ++i)
  102. files.add (nsStringToJuce ((NSString*) [filenames objectAtIndex: i]));
  103. if (files.size() > 0 && JUCEApplication::getInstance() != 0)
  104. JUCEApplication::getInstance()->anotherInstanceStarted (files.joinIntoString (T(" ")));
  105. }
  106. - (void) applicationDidBecomeActive: (NSNotification*) aNotification
  107. {
  108. juce_HandleProcessFocusChange();
  109. }
  110. - (void) applicationDidResignActive: (NSNotification*) aNotification
  111. {
  112. juce_HandleProcessFocusChange();
  113. }
  114. - (void) applicationWillUnhide: (NSNotification*) aNotification
  115. {
  116. juce_HandleProcessFocusChange();
  117. }
  118. - (void) customEvent: (id) n
  119. {
  120. NSData* data = (NSData*) n;
  121. void* message = 0;
  122. [data getBytes: &message length: sizeof (message)];
  123. if (message != 0)
  124. MessageManager::getInstance()->deliverMessage (message);
  125. [data release];
  126. }
  127. - (void) performCallback: (id) info
  128. {
  129. CallbackMessagePayload* pl = (CallbackMessagePayload*) info;
  130. if (pl != 0)
  131. {
  132. pl->result = (*pl->function) (pl->parameter);
  133. pl->hasBeenExecuted = true;
  134. }
  135. }
  136. - (void) dummyMethod {} // (used as a way of running a dummy thread)
  137. @end
  138. BEGIN_JUCE_NAMESPACE
  139. static JuceAppDelegate* juceAppDelegate = 0;
  140. void MessageManager::runDispatchLoop()
  141. {
  142. const ScopedAutoReleasePool pool;
  143. MessageManagerLock mml;
  144. // must only be called by the message thread!
  145. jassert (isThisTheMessageThread());
  146. [NSApp run];
  147. }
  148. void MessageManager::stopDispatchLoop()
  149. {
  150. quitMessagePosted = true;
  151. [NSApp stop: nil];
  152. }
  153. bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
  154. {
  155. const ScopedAutoReleasePool pool;
  156. jassert (isThisTheMessageThread()); // must only be called by the message thread
  157. uint32 endTime = Time::getMillisecondCounter() + millisecondsToRunFor;
  158. NSDate* endDate = [NSDate dateWithTimeIntervalSinceNow: millisecondsToRunFor * 0.001];
  159. while (Time::getMillisecondCounter() < endTime)
  160. {
  161. const ScopedAutoReleasePool pool;
  162. [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
  163. beforeDate: endDate];
  164. NSEvent* e = [NSApp nextEventMatchingMask: NSAnyEventMask
  165. untilDate: endDate
  166. inMode: NSDefaultRunLoopMode
  167. dequeue: YES];
  168. [NSApp sendEvent: e];
  169. }
  170. return ! quitMessagePosted;
  171. }
  172. //==============================================================================
  173. void MessageManager::doPlatformSpecificInitialisation()
  174. {
  175. if (juceAppDelegate == 0)
  176. juceAppDelegate = [[JuceAppDelegate alloc] init];
  177. // This launches a dummy thread, which forces Cocoa to initialise NSThreads
  178. // correctly (needed prior to 10.5)
  179. if (! [NSThread isMultiThreaded])
  180. [NSThread detachNewThreadSelector: @selector (dummyMethod)
  181. toTarget: juceAppDelegate
  182. withObject: nil];
  183. initialiseMainMenu();
  184. }
  185. void MessageManager::doPlatformSpecificShutdown()
  186. {
  187. [[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceAppDelegate];
  188. [[NSNotificationCenter defaultCenter] removeObserver: juceAppDelegate];
  189. [juceAppDelegate release];
  190. juceAppDelegate = 0;
  191. }
  192. bool juce_postMessageToSystemQueue (void* message)
  193. {
  194. [juceAppDelegate performSelectorOnMainThread: @selector (customEvent:)
  195. withObject: (id) [[NSData alloc] initWithBytes: &message
  196. length: (int) sizeof (message)]
  197. waitUntilDone: NO];
  198. return true;
  199. }
  200. void MessageManager::broadcastMessage (const String& value) throw()
  201. {
  202. }
  203. void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback,
  204. void* data)
  205. {
  206. if (isThisTheMessageThread())
  207. {
  208. return (*callback) (data);
  209. }
  210. else
  211. {
  212. CallbackMessagePayload cmp;
  213. cmp.function = callback;
  214. cmp.parameter = data;
  215. cmp.result = 0;
  216. cmp.hasBeenExecuted = false;
  217. [juceAppDelegate performSelectorOnMainThread: @selector (performCallback:)
  218. withObject: (id) &cmp
  219. waitUntilDone: YES];
  220. return cmp.result;
  221. }
  222. }
  223. #endif