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.

352 lines
9.6KB

  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 "../../juce_core/basics/juce_StandardHeader.h"
  24. #if JUCE_MSVC
  25. #pragma warning (push)
  26. #pragma warning (disable: 4245 4514 4100)
  27. #include <crtdbg.h>
  28. #pragma warning (pop)
  29. #endif
  30. BEGIN_JUCE_NAMESPACE
  31. #include "juce_Application.h"
  32. #include "juce_DeletedAtShutdown.h"
  33. #include "../events/juce_MessageManager.h"
  34. #include "../gui/graphics/contexts/juce_Graphics.h"
  35. #include "../gui/components/windows/juce_AlertWindow.h"
  36. #include "../gui/components/buttons/juce_TextButton.h"
  37. #include "../gui/components/lookandfeel/juce_LookAndFeel.h"
  38. #include "../../juce_core/basics/juce_Time.h"
  39. #include "../../juce_core/basics/juce_Initialisation.h"
  40. #include "../../juce_core/threads/juce_Process.h"
  41. #include "../../juce_core/threads/juce_InterProcessLock.h"
  42. void juce_setCurrentExecutableFileName (const String& filename) throw();
  43. void juce_setCurrentThreadName (const String& name) throw();
  44. static JUCEApplication* appInstance = 0;
  45. //==============================================================================
  46. JUCEApplication::JUCEApplication()
  47. : stillInitialising (true)
  48. {
  49. }
  50. JUCEApplication::~JUCEApplication()
  51. {
  52. }
  53. JUCEApplication* JUCEApplication::getInstance()
  54. {
  55. return appInstance;
  56. }
  57. bool JUCEApplication::isInitialising() const
  58. {
  59. return stillInitialising;
  60. }
  61. //==============================================================================
  62. const String JUCEApplication::getApplicationVersion()
  63. {
  64. return String::empty;
  65. }
  66. bool JUCEApplication::moreThanOneInstanceAllowed()
  67. {
  68. return true;
  69. }
  70. void JUCEApplication::anotherInstanceStarted (const String&)
  71. {
  72. }
  73. void JUCEApplication::systemRequestedQuit()
  74. {
  75. quit();
  76. }
  77. void JUCEApplication::quit (const bool useMaximumForce)
  78. {
  79. MessageManager::getInstance()->postQuitMessage (useMaximumForce);
  80. }
  81. //==============================================================================
  82. void JUCEApplication::unhandledException (const std::exception*,
  83. const String&,
  84. const int)
  85. {
  86. jassertfalse
  87. }
  88. void JUCEApplication::sendUnhandledException (const std::exception* const e,
  89. const char* const sourceFile,
  90. const int lineNumber)
  91. {
  92. if (appInstance != 0)
  93. appInstance->unhandledException (e, sourceFile, lineNumber);
  94. }
  95. //==============================================================================
  96. ApplicationCommandTarget* JUCEApplication::getNextCommandTarget()
  97. {
  98. return 0;
  99. }
  100. void JUCEApplication::getAllCommands (Array <CommandID>& commands)
  101. {
  102. commands.add (StandardApplicationCommandIDs::quit);
  103. }
  104. void JUCEApplication::getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result)
  105. {
  106. if (commandID == StandardApplicationCommandIDs::quit)
  107. {
  108. result.setInfo ("Quit",
  109. "Quits the application",
  110. "Application",
  111. 0);
  112. result.defaultKeypresses.add (KeyPress (T('q'), ModifierKeys::commandModifier, 0));
  113. }
  114. }
  115. bool JUCEApplication::perform (const InvocationInfo& info)
  116. {
  117. if (info.commandID == StandardApplicationCommandIDs::quit)
  118. {
  119. systemRequestedQuit();
  120. return true;
  121. }
  122. return false;
  123. }
  124. //==============================================================================
  125. // used as a listener object later on..
  126. class NewAppListener : public ActionListener
  127. {
  128. public:
  129. void actionListenerCallback (const String& message)
  130. {
  131. if (message.startsWith (appInstance->getApplicationName() + T("/")))
  132. {
  133. appInstance->anotherInstanceStarted (message.fromFirstOccurrenceOf (T("/"),
  134. false, false));
  135. }
  136. }
  137. };
  138. int JUCEApplication::main (String& commandLine, JUCEApplication* const app)
  139. {
  140. jassert (appInstance == 0);
  141. appInstance = app;
  142. bool useForce = true;
  143. initialiseJuce_GUI();
  144. InterProcessLock* appLock = 0;
  145. if (! app->moreThanOneInstanceAllowed())
  146. {
  147. appLock = new InterProcessLock ("juceAppLock_" + app->getApplicationName());
  148. if (! appLock->enter(0))
  149. {
  150. MessageManager::broadcastMessage (app->getApplicationName()
  151. + T("/") + commandLine);
  152. delete appInstance;
  153. appInstance = 0;
  154. commandLine = String::empty;
  155. DBG ("Another instance is running - quitting...");
  156. return 0;
  157. }
  158. }
  159. JUCE_TRY
  160. {
  161. juce_setCurrentThreadName ("Juce Message Thread");
  162. // let the app do its setting-up..
  163. app->initialise (commandLine.trim());
  164. commandLine = String::empty;
  165. // register for broadcast new app messages
  166. NewAppListener* const newAppListener = new NewAppListener();
  167. MessageManager::getInstance()->registerBroadcastListener (newAppListener);
  168. app->stillInitialising = false;
  169. // now loop until a quit message is received..
  170. useForce = MessageManager::getInstance()->runDispatchLoop();
  171. delete newAppListener;
  172. if (appLock != 0)
  173. {
  174. appLock->exit();
  175. delete appLock;
  176. }
  177. }
  178. #if JUCE_CATCH_UNHANDLED_EXCEPTIONS
  179. catch (const std::exception& e)
  180. {
  181. app->unhandledException (&e, __FILE__, __LINE__);
  182. }
  183. catch (...)
  184. {
  185. app->unhandledException (0, __FILE__, __LINE__);
  186. }
  187. #endif
  188. shutdownAppAndClearUp (useForce);
  189. return 0;
  190. }
  191. void JUCEApplication::shutdownAppAndClearUp (bool useMaximumForce)
  192. {
  193. jassert (appInstance != 0);
  194. JUCEApplication* const app = appInstance;
  195. static bool reentrancyCheck = false;
  196. if (! reentrancyCheck)
  197. {
  198. reentrancyCheck = true;
  199. JUCE_TRY
  200. {
  201. // give the app a chance to clean up..
  202. app->shutdown();
  203. }
  204. #if JUCE_CATCH_UNHANDLED_EXCEPTIONS
  205. catch (const std::exception& e)
  206. {
  207. app->unhandledException (&e, __FILE__, __LINE__);
  208. }
  209. catch (...)
  210. {
  211. app->unhandledException (0, __FILE__, __LINE__);
  212. }
  213. #endif
  214. JUCE_TRY
  215. {
  216. shutdownJuce_GUI();
  217. appInstance = 0;
  218. delete app;
  219. }
  220. JUCE_CATCH_ALL_ASSERT
  221. if (useMaximumForce)
  222. {
  223. Process::terminate();
  224. }
  225. reentrancyCheck = false;
  226. }
  227. }
  228. int JUCEApplication::main (int argc, char* argv[],
  229. JUCEApplication* const newApp)
  230. {
  231. juce_setCurrentExecutableFileName (argv[0]);
  232. String cmd;
  233. for (int i = 1; i < argc; ++i)
  234. cmd << argv[i] << T(' ');
  235. return JUCEApplication::main (cmd, newApp);
  236. }
  237. //==============================================================================
  238. static bool juceInitialisedGUI = false;
  239. void JUCE_PUBLIC_FUNCTION initialiseJuce_GUI()
  240. {
  241. if (! juceInitialisedGUI)
  242. {
  243. juceInitialisedGUI = true;
  244. initialiseJuce_NonGUI();
  245. MessageManager::getInstance();
  246. Font::initialiseDefaultFontNames();
  247. LookAndFeel::setDefaultLookAndFeel (0);
  248. #if JUCE_WIN32 && JUCE_DEBUG
  249. // This section is just for catching people who mess up their project settings and
  250. // turn RTTI off..
  251. try
  252. {
  253. TextButton tb (String::empty);
  254. Component* c = &tb;
  255. // Got an exception here? Then TURN ON RTTI in your compiler settings!!
  256. c = dynamic_cast <Button*> (c);
  257. }
  258. catch (...)
  259. {
  260. // Ended up here? If so, TURN ON RTTI in your compiler settings!! And if you
  261. // got as far as this catch statement, then why haven't you got exception catching
  262. // turned on in the debugger???
  263. jassertfalse
  264. }
  265. #endif
  266. }
  267. }
  268. void JUCE_PUBLIC_FUNCTION shutdownJuce_GUI()
  269. {
  270. if (juceInitialisedGUI)
  271. {
  272. DeletedAtShutdown::deleteAll();
  273. LookAndFeel::clearDefaultLookAndFeel();
  274. shutdownJuce_NonGUI();
  275. juceInitialisedGUI = false;
  276. }
  277. }
  278. END_JUCE_NAMESPACE