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.

303 lines
8.2KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #if JUCE_MAC
  18. extern void juce_initialiseMacMainMenu();
  19. #endif
  20. #if ! (JUCE_IOS || JUCE_ANDROID)
  21. #define JUCE_HANDLE_MULTIPLE_INSTANCES 1
  22. #endif
  23. //==============================================================================
  24. #if JUCE_HANDLE_MULTIPLE_INSTANCES
  25. struct JUCEApplication::MultipleInstanceHandler : public ActionListener
  26. {
  27. public:
  28. MultipleInstanceHandler (const String& appName)
  29. : appLock ("juceAppLock_" + appName)
  30. {
  31. }
  32. bool sendCommandLineToPreexistingInstance()
  33. {
  34. if (appLock.enter (0))
  35. return false;
  36. JUCEApplication* const app = JUCEApplication::getInstance();
  37. jassert (app != nullptr);
  38. MessageManager::broadcastMessage (app->getApplicationName()
  39. + "/" + app->getCommandLineParameters());
  40. return true;
  41. }
  42. void actionListenerCallback (const String& message)
  43. {
  44. if (JUCEApplication* const app = JUCEApplication::getInstance())
  45. {
  46. const String appName (app->getApplicationName());
  47. if (message.startsWith (appName + "/"))
  48. app->anotherInstanceStarted (message.substring (appName.length() + 1));
  49. }
  50. }
  51. private:
  52. InterProcessLock appLock;
  53. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultipleInstanceHandler)
  54. };
  55. #else
  56. struct JUCEApplication::MultipleInstanceHandler {};
  57. #endif
  58. //==============================================================================
  59. JUCEApplication::JUCEApplication()
  60. : appReturnValue (0),
  61. stillInitialising (true)
  62. {
  63. }
  64. JUCEApplication::~JUCEApplication()
  65. {
  66. }
  67. //==============================================================================
  68. bool JUCEApplication::moreThanOneInstanceAllowed() { return true; }
  69. void JUCEApplication::anotherInstanceStarted (const String&) {}
  70. void JUCEApplication::suspended() {}
  71. void JUCEApplication::resumed() {}
  72. void JUCEApplication::systemRequestedQuit()
  73. {
  74. quit();
  75. }
  76. void JUCEApplication::quit()
  77. {
  78. MessageManager::getInstance()->stopDispatchLoop();
  79. }
  80. void JUCEApplication::setApplicationReturnValue (const int newReturnValue) noexcept
  81. {
  82. appReturnValue = newReturnValue;
  83. }
  84. //==============================================================================
  85. void JUCEApplication::unhandledException (const std::exception*, const String&, int)
  86. {
  87. jassertfalse;
  88. }
  89. void JUCEApplication::sendUnhandledException (const std::exception* const e,
  90. const char* const sourceFile,
  91. const int lineNumber)
  92. {
  93. if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance())
  94. app->unhandledException (e, sourceFile, lineNumber);
  95. }
  96. //==============================================================================
  97. ApplicationCommandTarget* JUCEApplication::getNextCommandTarget()
  98. {
  99. return nullptr;
  100. }
  101. void JUCEApplication::getAllCommands (Array <CommandID>& commands)
  102. {
  103. commands.add (StandardApplicationCommandIDs::quit);
  104. }
  105. void JUCEApplication::getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result)
  106. {
  107. if (commandID == StandardApplicationCommandIDs::quit)
  108. {
  109. result.setInfo (TRANS("Quit"),
  110. TRANS("Quits the application"),
  111. "Application",
  112. 0);
  113. result.defaultKeypresses.add (KeyPress ('q', ModifierKeys::commandModifier, 0));
  114. }
  115. }
  116. bool JUCEApplication::perform (const InvocationInfo& info)
  117. {
  118. if (info.commandID == StandardApplicationCommandIDs::quit)
  119. {
  120. systemRequestedQuit();
  121. return true;
  122. }
  123. return false;
  124. }
  125. #if JUCE_HANDLE_MULTIPLE_INSTANCES
  126. bool JUCEApplication::sendCommandLineToPreexistingInstance()
  127. {
  128. jassert (multipleInstanceHandler == nullptr); // this must only be called once!
  129. multipleInstanceHandler = new MultipleInstanceHandler (getApplicationName());
  130. return multipleInstanceHandler->sendCommandLineToPreexistingInstance();
  131. }
  132. #endif
  133. //==============================================================================
  134. bool JUCEApplication::initialiseApp()
  135. {
  136. #if JUCE_HANDLE_MULTIPLE_INSTANCES
  137. if ((! moreThanOneInstanceAllowed()) && sendCommandLineToPreexistingInstance())
  138. {
  139. DBG ("Another instance is running - quitting...");
  140. return false;
  141. }
  142. #endif
  143. // let the app do its setting-up..
  144. initialise (getCommandLineParameters());
  145. stillInitialising = false;
  146. if (! MessageManager::getInstance()->hasStopMessageBeenSent())
  147. {
  148. #if JUCE_MAC
  149. juce_initialiseMacMainMenu(); // (needs to get the app's name)
  150. #endif
  151. #if JUCE_HANDLE_MULTIPLE_INSTANCES
  152. if (multipleInstanceHandler != nullptr)
  153. MessageManager::getInstance()->registerBroadcastListener (multipleInstanceHandler);
  154. #endif
  155. }
  156. return true;
  157. }
  158. int JUCEApplication::shutdownApp()
  159. {
  160. jassert (JUCEApplicationBase::getInstance() == this);
  161. #if JUCE_HANDLE_MULTIPLE_INSTANCES
  162. if (multipleInstanceHandler != nullptr)
  163. MessageManager::getInstance()->deregisterBroadcastListener (multipleInstanceHandler);
  164. #endif
  165. JUCE_TRY
  166. {
  167. // give the app a chance to clean up..
  168. shutdown();
  169. }
  170. JUCE_CATCH_EXCEPTION
  171. multipleInstanceHandler = nullptr;
  172. return getApplicationReturnValue();
  173. }
  174. //==============================================================================
  175. #if JUCE_ANDROID
  176. StringArray JUCEApplication::getCommandLineParameterArray() { return StringArray(); }
  177. String JUCEApplication::getCommandLineParameters() { return String::empty; }
  178. #else
  179. int JUCEApplication::main()
  180. {
  181. ScopedJuceInitialiser_GUI libraryInitialiser;
  182. jassert (createInstance != nullptr);
  183. const ScopedPointer<JUCEApplication> app (dynamic_cast <JUCEApplication*> (createInstance()));
  184. jassert (app != nullptr);
  185. if (! app->initialiseApp())
  186. return 0;
  187. JUCE_TRY
  188. {
  189. // loop until a quit message is received..
  190. MessageManager::getInstance()->runDispatchLoop();
  191. }
  192. JUCE_CATCH_EXCEPTION
  193. return app->shutdownApp();
  194. }
  195. #if ! JUCE_WINDOWS
  196. #if JUCE_IOS
  197. extern int juce_iOSMain (int argc, const char* argv[]);
  198. #endif
  199. #if JUCE_MAC
  200. extern void initialiseNSApplication();
  201. #endif
  202. extern const char* const* juce_argv; // declared in juce_core
  203. extern int juce_argc;
  204. StringArray JUCEApplication::getCommandLineParameterArray()
  205. {
  206. return StringArray (juce_argv + 1, juce_argc - 1);
  207. }
  208. String JUCEApplication::getCommandLineParameters()
  209. {
  210. String argString;
  211. for (int i = 1; i < juce_argc; ++i)
  212. {
  213. String arg (juce_argv[i]);
  214. if (arg.containsChar (' ') && ! arg.isQuotedString())
  215. arg = arg.quoted ('"');
  216. argString << arg << ' ';
  217. }
  218. return argString.trim();
  219. }
  220. int JUCEApplication::main (int argc, const char* argv[])
  221. {
  222. JUCE_AUTORELEASEPOOL
  223. {
  224. juce_argc = argc;
  225. juce_argv = argv;
  226. #if JUCE_MAC
  227. initialiseNSApplication();
  228. #endif
  229. #if JUCE_IOS
  230. return juce_iOSMain (argc, argv);
  231. #else
  232. return JUCEApplication::main();
  233. #endif
  234. }
  235. }
  236. #endif
  237. #endif