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.

305 lines
8.4KB

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