PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/modules/juce_events/messages/juce_ApplicationBase.cpp

https://gitlab.com/bill-auger/JUCE
C++ | 308 lines | 246 code | 36 blank | 26 comment | 17 complexity | b7886f2a68dde1a89de9f0787bb21939 MD5 | raw file
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI 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. JUCEApplicationBase::CreateInstanceFunction JUCEApplicationBase::createInstance = 0;
  18. JUCEApplicationBase* JUCEApplicationBase::appInstance = nullptr;
  19. JUCEApplicationBase::JUCEApplicationBase()
  20. : appReturnValue (0),
  21. stillInitialising (true)
  22. {
  23. jassert (isStandaloneApp() && appInstance == nullptr);
  24. appInstance = this;
  25. }
  26. JUCEApplicationBase::~JUCEApplicationBase()
  27. {
  28. jassert (appInstance == this);
  29. appInstance = nullptr;
  30. }
  31. void JUCEApplicationBase::setApplicationReturnValue (const int newReturnValue) noexcept
  32. {
  33. appReturnValue = newReturnValue;
  34. }
  35. // This is called on the Mac and iOS where the OS doesn't allow the stack to unwind on shutdown..
  36. void JUCEApplicationBase::appWillTerminateByForce()
  37. {
  38. JUCE_AUTORELEASEPOOL
  39. {
  40. {
  41. const ScopedPointer<JUCEApplicationBase> app (appInstance);
  42. if (app != nullptr)
  43. app->shutdownApp();
  44. }
  45. DeletedAtShutdown::deleteAll();
  46. MessageManager::deleteInstance();
  47. }
  48. }
  49. void JUCEApplicationBase::quit()
  50. {
  51. MessageManager::getInstance()->stopDispatchLoop();
  52. }
  53. void JUCEApplicationBase::sendUnhandledException (const std::exception* const e,
  54. const char* const sourceFile,
  55. const int lineNumber)
  56. {
  57. if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance())
  58. app->unhandledException (e, sourceFile, lineNumber);
  59. }
  60. //==============================================================================
  61. #if ! (JUCE_IOS || JUCE_ANDROID)
  62. #define JUCE_HANDLE_MULTIPLE_INSTANCES 1
  63. #endif
  64. #if JUCE_HANDLE_MULTIPLE_INSTANCES
  65. struct JUCEApplicationBase::MultipleInstanceHandler : public ActionListener
  66. {
  67. public:
  68. MultipleInstanceHandler (const String& appName)
  69. : appLock ("juceAppLock_" + appName)
  70. {
  71. }
  72. bool sendCommandLineToPreexistingInstance()
  73. {
  74. if (appLock.enter (0))
  75. return false;
  76. JUCEApplicationBase* const app = JUCEApplicationBase::getInstance();
  77. jassert (app != nullptr);
  78. MessageManager::broadcastMessage (app->getApplicationName()
  79. + "/" + app->getCommandLineParameters());
  80. return true;
  81. }
  82. void actionListenerCallback (const String& message) override
  83. {
  84. if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance())
  85. {
  86. const String appName (app->getApplicationName());
  87. if (message.startsWith (appName + "/"))
  88. app->anotherInstanceStarted (message.substring (appName.length() + 1));
  89. }
  90. }
  91. private:
  92. InterProcessLock appLock;
  93. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultipleInstanceHandler)
  94. };
  95. bool JUCEApplicationBase::sendCommandLineToPreexistingInstance()
  96. {
  97. jassert (multipleInstanceHandler == nullptr); // this must only be called once!
  98. multipleInstanceHandler = new MultipleInstanceHandler (getApplicationName());
  99. return multipleInstanceHandler->sendCommandLineToPreexistingInstance();
  100. }
  101. #else
  102. struct JUCEApplicationBase::MultipleInstanceHandler {};
  103. #endif
  104. //==============================================================================
  105. #if JUCE_ANDROID
  106. StringArray JUCEApplicationBase::getCommandLineParameterArray() { return StringArray(); }
  107. String JUCEApplicationBase::getCommandLineParameters() { return String(); }
  108. #else
  109. #if JUCE_WINDOWS && ! defined (_CONSOLE)
  110. String JUCE_CALLTYPE JUCEApplicationBase::getCommandLineParameters()
  111. {
  112. return CharacterFunctions::findEndOfToken (CharPointer_UTF16 (GetCommandLineW()),
  113. CharPointer_UTF16 (L" "),
  114. CharPointer_UTF16 (L"\"")).findEndOfWhitespace();
  115. }
  116. StringArray JUCE_CALLTYPE JUCEApplicationBase::getCommandLineParameterArray()
  117. {
  118. StringArray s;
  119. int argc = 0;
  120. if (LPWSTR* const argv = CommandLineToArgvW (GetCommandLineW(), &argc))
  121. {
  122. s = StringArray (argv + 1, argc - 1);
  123. LocalFree (argv);
  124. }
  125. return s;
  126. }
  127. #else
  128. #if JUCE_IOS
  129. extern int juce_iOSMain (int argc, const char* argv[]);
  130. #endif
  131. #if JUCE_MAC
  132. extern void initialiseNSApplication();
  133. #endif
  134. #if JUCE_WINDOWS
  135. const char* const* juce_argv = nullptr;
  136. int juce_argc = 0;
  137. #else
  138. extern const char* const* juce_argv; // declared in juce_core
  139. extern int juce_argc;
  140. #endif
  141. String JUCEApplicationBase::getCommandLineParameters()
  142. {
  143. String argString;
  144. for (int i = 1; i < juce_argc; ++i)
  145. {
  146. String arg (juce_argv[i]);
  147. if (arg.containsChar (' ') && ! arg.isQuotedString())
  148. arg = arg.quoted ('"');
  149. argString << arg << ' ';
  150. }
  151. return argString.trim();
  152. }
  153. StringArray JUCEApplicationBase::getCommandLineParameterArray()
  154. {
  155. return StringArray (juce_argv + 1, juce_argc - 1);
  156. }
  157. int JUCEApplicationBase::main (int argc, const char* argv[])
  158. {
  159. JUCE_AUTORELEASEPOOL
  160. {
  161. juce_argc = argc;
  162. juce_argv = argv;
  163. #if JUCE_MAC
  164. initialiseNSApplication();
  165. #endif
  166. #if JUCE_IOS
  167. return juce_iOSMain (argc, argv);
  168. #else
  169. return JUCEApplicationBase::main();
  170. #endif
  171. }
  172. }
  173. #endif
  174. //==============================================================================
  175. int JUCEApplicationBase::main()
  176. {
  177. ScopedJuceInitialiser_GUI libraryInitialiser;
  178. jassert (createInstance != nullptr);
  179. const ScopedPointer<JUCEApplicationBase> app (createInstance());
  180. jassert (app != nullptr);
  181. if (! app->initialiseApp())
  182. return app->shutdownApp();
  183. JUCE_TRY
  184. {
  185. // loop until a quit message is received..
  186. MessageManager::getInstance()->runDispatchLoop();
  187. }
  188. JUCE_CATCH_EXCEPTION
  189. return app->shutdownApp();
  190. }
  191. #endif
  192. //==============================================================================
  193. bool JUCEApplicationBase::initialiseApp()
  194. {
  195. #if JUCE_HANDLE_MULTIPLE_INSTANCES
  196. if ((! moreThanOneInstanceAllowed()) && sendCommandLineToPreexistingInstance())
  197. {
  198. DBG ("Another instance is running - quitting...");
  199. return false;
  200. }
  201. #endif
  202. #if JUCE_WINDOWS && JUCE_STANDALONE_APPLICATION && (! defined (_CONSOLE)) && (! JUCE_MINGW)
  203. if (AttachConsole (ATTACH_PARENT_PROCESS) != 0)
  204. {
  205. // if we've launched a GUI app from cmd.exe or PowerShell, we need this to enable printf etc.
  206. // However, only reassign stdout, stderr, stdin if they have not been already opened by
  207. // a redirect or similar.
  208. FILE* ignore;
  209. if (_fileno(stdout) < 0) freopen_s (&ignore, "CONOUT$", "w", stdout);
  210. if (_fileno(stderr) < 0) freopen_s (&ignore, "CONOUT$", "w", stderr);
  211. if (_fileno(stdin) < 0) freopen_s (&ignore, "CONIN$", "r", stdin);
  212. }
  213. #endif
  214. // let the app do its setting-up..
  215. initialise (getCommandLineParameters());
  216. stillInitialising = false;
  217. if (MessageManager::getInstance()->hasStopMessageBeenSent())
  218. return false;
  219. #if JUCE_HANDLE_MULTIPLE_INSTANCES
  220. if (multipleInstanceHandler != nullptr)
  221. MessageManager::getInstance()->registerBroadcastListener (multipleInstanceHandler);
  222. #endif
  223. return true;
  224. }
  225. int JUCEApplicationBase::shutdownApp()
  226. {
  227. jassert (JUCEApplicationBase::getInstance() == this);
  228. #if JUCE_HANDLE_MULTIPLE_INSTANCES
  229. if (multipleInstanceHandler != nullptr)
  230. MessageManager::getInstance()->deregisterBroadcastListener (multipleInstanceHandler);
  231. #endif
  232. JUCE_TRY
  233. {
  234. // give the app a chance to clean up..
  235. shutdown();
  236. }
  237. JUCE_CATCH_EXCEPTION
  238. multipleInstanceHandler = nullptr;
  239. return getApplicationReturnValue();
  240. }