1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Moved most of the functionality from JUCEApplication into JUCEApplicationBase, so that it can be used without needing juce_gui_basics to be present.

This commit is contained in:
jules 2013-09-07 09:43:45 +01:00
parent 207557d996
commit 42aa27900b
31 changed files with 455 additions and 411 deletions

View file

@ -22,104 +22,29 @@
==============================================================================
*/
#if JUCE_MAC
extern void juce_initialiseMacMainMenu();
#endif
#if ! (JUCE_IOS || JUCE_ANDROID)
#define JUCE_HANDLE_MULTIPLE_INSTANCES 1
#endif
JUCEApplication::JUCEApplication() {}
JUCEApplication::~JUCEApplication() {}
//==============================================================================
#if JUCE_HANDLE_MULTIPLE_INSTANCES
struct JUCEApplication::MultipleInstanceHandler : public ActionListener
{
public:
MultipleInstanceHandler (const String& appName)
: appLock ("juceAppLock_" + appName)
{
}
bool sendCommandLineToPreexistingInstance()
{
if (appLock.enter (0))
return false;
JUCEApplication* const app = JUCEApplication::getInstance();
jassert (app != nullptr);
MessageManager::broadcastMessage (app->getApplicationName()
+ "/" + app->getCommandLineParameters());
return true;
}
void actionListenerCallback (const String& message) override
{
if (JUCEApplication* const app = JUCEApplication::getInstance())
{
const String appName (app->getApplicationName());
if (message.startsWith (appName + "/"))
app->anotherInstanceStarted (message.substring (appName.length() + 1));
}
}
private:
InterProcessLock appLock;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultipleInstanceHandler)
};
#else
struct JUCEApplication::MultipleInstanceHandler {};
#endif
//==============================================================================
JUCEApplication::JUCEApplication()
: appReturnValue (0),
stillInitialising (true)
JUCEApplication* JUCE_CALLTYPE JUCEApplication::getInstance() noexcept
{
return dynamic_cast <JUCEApplication*> (JUCEApplicationBase::getInstance());
}
JUCEApplication::~JUCEApplication()
{
}
//==============================================================================
bool JUCEApplication::moreThanOneInstanceAllowed() { return true; }
void JUCEApplication::anotherInstanceStarted (const String&) {}
void JUCEApplication::suspended() {}
void JUCEApplication::resumed() {}
void JUCEApplication::systemRequestedQuit()
{
quit();
}
void JUCEApplication::systemRequestedQuit() { quit(); }
void JUCEApplication::quit()
{
MessageManager::getInstance()->stopDispatchLoop();
}
void JUCEApplication::setApplicationReturnValue (const int newReturnValue) noexcept
{
appReturnValue = newReturnValue;
}
//==============================================================================
void JUCEApplication::unhandledException (const std::exception*, const String&, int)
{
jassertfalse;
}
void JUCEApplication::sendUnhandledException (const std::exception* const e,
const char* const sourceFile,
const int lineNumber)
{
if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance())
app->unhandledException (e, sourceFile, lineNumber);
}
//==============================================================================
ApplicationCommandTarget* JUCEApplication::getNextCommandTarget()
{
@ -137,8 +62,7 @@ void JUCEApplication::getCommandInfo (const CommandID commandID, ApplicationComm
{
result.setInfo (TRANS("Quit"),
TRANS("Quits the application"),
"Application",
0);
"Application", 0);
result.defaultKeypresses.add (KeyPress ('q', ModifierKeys::commandModifier, 0));
}
@ -155,148 +79,21 @@ bool JUCEApplication::perform (const InvocationInfo& info)
return false;
}
#if JUCE_HANDLE_MULTIPLE_INSTANCES
bool JUCEApplication::sendCommandLineToPreexistingInstance()
{
jassert (multipleInstanceHandler == nullptr); // this must only be called once!
multipleInstanceHandler = new MultipleInstanceHandler (getApplicationName());
return multipleInstanceHandler->sendCommandLineToPreexistingInstance();
}
//==============================================================================
#if JUCE_MAC
extern void juce_initialiseMacMainMenu();
#endif
//==============================================================================
bool JUCEApplication::initialiseApp()
{
#if JUCE_HANDLE_MULTIPLE_INSTANCES
if ((! moreThanOneInstanceAllowed()) && sendCommandLineToPreexistingInstance())
{
DBG ("Another instance is running - quitting...");
return false;
}
#endif
// let the app do its setting-up..
initialise (getCommandLineParameters());
stillInitialising = false;
if (! MessageManager::getInstance()->hasStopMessageBeenSent())
if (JUCEApplicationBase::initialiseApp())
{
#if JUCE_MAC
juce_initialiseMacMainMenu(); // (needs to get the app's name)
#endif
#if JUCE_HANDLE_MULTIPLE_INSTANCES
if (multipleInstanceHandler != nullptr)
MessageManager::getInstance()->registerBroadcastListener (multipleInstanceHandler);
#endif
return true;
}
return true;
return false;
}
int JUCEApplication::shutdownApp()
{
jassert (JUCEApplicationBase::getInstance() == this);
#if JUCE_HANDLE_MULTIPLE_INSTANCES
if (multipleInstanceHandler != nullptr)
MessageManager::getInstance()->deregisterBroadcastListener (multipleInstanceHandler);
#endif
JUCE_TRY
{
// give the app a chance to clean up..
shutdown();
}
JUCE_CATCH_EXCEPTION
multipleInstanceHandler = nullptr;
return getApplicationReturnValue();
}
//==============================================================================
#if JUCE_ANDROID
StringArray JUCEApplication::getCommandLineParameterArray() { return StringArray(); }
String JUCEApplication::getCommandLineParameters() { return String::empty; }
#else
int JUCEApplication::main()
{
ScopedJuceInitialiser_GUI libraryInitialiser;
jassert (createInstance != nullptr);
const ScopedPointer<JUCEApplication> app (dynamic_cast <JUCEApplication*> (createInstance()));
jassert (app != nullptr);
if (! app->initialiseApp())
return 0;
JUCE_TRY
{
// loop until a quit message is received..
MessageManager::getInstance()->runDispatchLoop();
}
JUCE_CATCH_EXCEPTION
return app->shutdownApp();
}
#if ! JUCE_WINDOWS
#if JUCE_IOS
extern int juce_iOSMain (int argc, const char* argv[]);
#endif
#if JUCE_MAC
extern void initialiseNSApplication();
#endif
extern const char* const* juce_argv; // declared in juce_core
extern int juce_argc;
StringArray JUCEApplication::getCommandLineParameterArray()
{
return StringArray (juce_argv + 1, juce_argc - 1);
}
String JUCEApplication::getCommandLineParameters()
{
String argString;
for (int i = 1; i < juce_argc; ++i)
{
String arg (juce_argv[i]);
if (arg.containsChar (' ') && ! arg.isQuotedString())
arg = arg.quoted ('"');
argString << arg << ' ';
}
return argString.trim();
}
int JUCEApplication::main (int argc, const char* argv[])
{
JUCE_AUTORELEASEPOOL
{
juce_argc = argc;
juce_argv = argv;
#if JUCE_MAC
initialiseNSApplication();
#endif
#if JUCE_IOS
return juce_iOSMain (argc, argv);
#else
return JUCEApplication::main();
#endif
}
}
#endif
#endif

View file

@ -31,24 +31,27 @@
An instance of this class is used to specify initialisation and shutdown
code for the application.
An application that wants to run in the JUCE framework needs to declare a
subclass of JUCEApplication and implement its various pure virtual methods.
Any application that wants to run an event loop must declare a subclass of
JUCEApplicationBase or JUCEApplication, and implement its various pure virtual
methods.
It then needs to use the START_JUCE_APPLICATION macro somewhere in a cpp file
to declare an instance of this class and generate a suitable platform-specific
main() function.
It then needs to use the START_JUCE_APPLICATION macro somewhere in a CPP file
to declare an instance of this class and generate suitable platform-specific
boilerplate code to launch the app.
Note that this class is derived from JUCEApplicationBase, which contains most
of the useful methods and functionality. This derived class is here simply as
a convenient way to also inherit from an ApplicationCommandTarget, and to implement
default versions of some of the pure virtual base class methods. But you can derive
your app object directly from JUCEApplicationBase if you want to, and by doing so
can avoid having a dependency on the juce_gui_basics module.
e.g. @code
class MyJUCEApp : public JUCEApplication
{
public:
MyJUCEApp()
{
}
~MyJUCEApp()
{
}
MyJUCEApp() {}
~MyJUCEApp() {}
void initialise (const String& commandLine)
{
@ -59,7 +62,7 @@
void shutdown()
{
myMainWindow = 0;
myMainWindow = nullptr;
}
const String getApplicationName()
@ -73,19 +76,19 @@
}
private:
ScopedPointer <MyApplicationWindow> myMainWindow;
ScopedPointer<MyApplicationWindow> myMainWindow;
};
// this creates wrapper code to actually launch the app properly.
// this generates boilerplate code to launch our app class:
START_JUCE_APPLICATION (MyJUCEApp)
@endcode
@see MessageManager
@see JUCEApplicationBase, START_JUCE_APPLICATION
*/
class JUCE_API JUCEApplication : public JUCEApplicationBase,
public ApplicationCommandTarget
{
protected:
public:
//==============================================================================
/** Constructs a JUCE app object.
@ -95,37 +98,23 @@ protected:
*/
JUCEApplication();
public:
/** Destructor.
If subclasses implement a constructor or destructor, they shouldn't call any
JUCE code in there - put your startup/shutdown code in initialise() and
shutdown() instead.
*/
virtual ~JUCEApplication();
~JUCEApplication();
//==============================================================================
/** Returns the global instance of the application object being run. */
static JUCEApplication* getInstance() noexcept { return dynamic_cast <JUCEApplication*> (JUCEApplicationBase::getInstance()); }
static JUCEApplication* JUCE_CALLTYPE getInstance() noexcept;
//==============================================================================
/** Returns true if the application hasn't yet completed its initialise() method
and entered the main event loop.
This is handy for things like splash screens to know when the app's up-and-running
properly.
*/
bool isInitialising() const noexcept { return stillInitialising; }
//==============================================================================
/** Returns the application's name.
An application must implement this to name itself.
*/
/** Returns the application's name. */
virtual const String getApplicationName() = 0;
/** Returns the application's version number.
*/
/** Returns the application's version number. */
virtual const String getApplicationVersion() = 0;
/** Checks whether multiple instances of the app are allowed.
@ -138,13 +127,12 @@ public:
callback to anotherInstanceStarted() to tell you about this - which
gives you a chance to react to what the user was trying to do.
*/
virtual bool moreThanOneInstanceAllowed();
bool moreThanOneInstanceAllowed() override;
/** Indicates that the user has tried to start up another instance of the app.
This will get called even if moreThanOneInstanceAllowed() is false.
*/
virtual void anotherInstanceStarted (const String& commandLine);
void anotherInstanceStarted (const String& commandLine) override;
/** Called when the operating system is trying to close the application.
@ -158,17 +146,17 @@ public:
in the same way as those from your own application code. So e.g. you'd
call this method from a "quit" item on a menu bar.
*/
virtual void systemRequestedQuit();
void systemRequestedQuit() override;
/** This method is called when the application is being put into background mode
by the operating system.
*/
virtual void suspended();
void suspended() override;
/** This method is called when the application is being woken from background mode
by the operating system.
*/
virtual void resumed();
void resumed() override;
/** If any unhandled exceptions make it through to the message dispatch loop, this
callback will be triggered, in case you want to log them or do some other
@ -178,54 +166,9 @@ public:
passed-in will be valid. If the exception is of unknown type, this pointer
will be null.
*/
virtual void unhandledException (const std::exception* e,
const String& sourceFilename,
int lineNumber);
//==============================================================================
/** Signals that the main message loop should stop and the application should terminate.
This isn't synchronous, it just posts a quit message to the main queue, and
when this message arrives, the message loop will stop, the shutdown() method
will be called, and the app will exit.
Note that this will cause an unconditional quit to happen, so if you need an
extra level before this, e.g. to give the user the chance to save their work
and maybe cancel the quit, you'll need to handle this in the systemRequestedQuit()
method - see that method's help for more info.
@see MessageManager
*/
static void quit();
/** Sets the value that should be returned as the application's exit code when the
app quits.
This is the value that's returned by the main() function. Normally you'd leave this
as 0 unless you want to indicate an error code.
@see getApplicationReturnValue
*/
void setApplicationReturnValue (int newReturnValue) noexcept;
/** Returns the value that has been set as the application's exit code.
@see setApplicationReturnValue
*/
int getApplicationReturnValue() const noexcept { return appReturnValue; }
/** Returns the application's command line parameters as a set of strings.
@see getCommandLineParameters
*/
static StringArray JUCE_CALLTYPE getCommandLineParameterArray();
/** Returns the application's command line parameters as a single string.
@see getCommandLineParameterArray
*/
static String JUCE_CALLTYPE getCommandLineParameters();
/** Returns true if this executable is running as an app (as opposed to being a plugin
or other kind of shared library. */
static inline bool isStandaloneApp() noexcept { return createInstance != nullptr; }
void unhandledException (const std::exception* e,
const String& sourceFilename,
int lineNumber) override;
//==============================================================================
/** @internal */
@ -237,28 +180,8 @@ public:
/** @internal */
bool perform (const InvocationInfo&);
//==============================================================================
#ifndef DOXYGEN
// The following methods are internal calls - not for public use.
static int main();
static int main (int argc, const char* argv[]);
static void sendUnhandledException (const std::exception*, const char* sourceFile, int lineNumber);
bool initialiseApp();
int shutdownApp();
protected:
bool sendCommandLineToPreexistingInstance();
#endif
private:
//==============================================================================
struct MultipleInstanceHandler;
friend struct MultipleInstanceHandler;
friend struct ContainerDeletePolicy<MultipleInstanceHandler>;
ScopedPointer<MultipleInstanceHandler> multipleInstanceHandler;
int appReturnValue;
bool stillInitialising;
bool initialiseApp() override;
JUCE_DECLARE_NON_COPYABLE (JUCEApplication)
};

View file

@ -1,113 +0,0 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_INITIALISATION_H_INCLUDED
#define JUCE_INITIALISATION_H_INCLUDED
//==============================================================================
/** Initialises Juce's GUI classes.
If you're embedding Juce into an application that uses its own event-loop rather
than using the START_JUCE_APPLICATION macro, call this function before making any
Juce calls, to make sure things are initialised correctly.
Note that if you're creating a Juce DLL for Windows, you may also need to call the
Process::setCurrentModuleInstanceHandle() method.
@see shutdownJuce_GUI()
*/
JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI();
/** Clears up any static data being used by Juce's GUI classes.
If you're embedding Juce into an application that uses its own event-loop rather
than using the START_JUCE_APPLICATION macro, call this function in your shutdown
code to clean up any juce objects that might be lying around.
@see initialiseJuce_GUI()
*/
JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI();
//==============================================================================
/** A utility object that helps you initialise and shutdown Juce correctly
using an RAII pattern.
When an instance of this class is created, it calls initialiseJuce_GUI(),
and when it's deleted, it calls shutdownJuce_GUI(), which lets you easily
make sure that these functions are matched correctly.
This class is particularly handy to use at the beginning of a console app's
main() function, because it'll take care of shutting down whenever you return
from the main() call.
*/
class ScopedJuceInitialiser_GUI
{
public:
/** The constructor simply calls initialiseJuce_GUI(). */
ScopedJuceInitialiser_GUI() { initialiseJuce_GUI(); }
/** The destructor simply calls shutdownJuce_GUI(). */
~ScopedJuceInitialiser_GUI() { shutdownJuce_GUI(); }
};
//==============================================================================
/*
To start a JUCE app, use this macro: START_JUCE_APPLICATION (AppSubClass) where
AppSubClass is the name of a class derived from JUCEApplication.
See the JUCEApplication class documentation (juce_Application.h) for more details.
*/
#if JUCE_ANDROID
#define START_JUCE_APPLICATION(AppClass) \
juce::JUCEApplication* juce_CreateApplication() { return new AppClass(); }
#else
#if JUCE_WINDOWS
#if defined (WINAPI) || defined (_WINDOWS_)
#define JUCE_MAIN_FUNCTION int __stdcall WinMain (HINSTANCE, HINSTANCE, const LPSTR, int)
#elif defined (_UNICODE)
#define JUCE_MAIN_FUNCTION int __stdcall WinMain (void*, void*, const wchar_t*, int)
#else
#define JUCE_MAIN_FUNCTION int __stdcall WinMain (void*, void*, const char*, int)
#endif
#define JUCE_MAIN_FUNCTION_ARGS
#else
#define JUCE_MAIN_FUNCTION int main (int argc, char* argv[])
#define JUCE_MAIN_FUNCTION_ARGS argc, (const char**) argv
#endif
#define START_JUCE_APPLICATION(AppClass) \
static juce::JUCEApplicationBase* juce_CreateApplication() { return new AppClass(); } \
extern "C" JUCE_MAIN_FUNCTION \
{ \
juce::JUCEApplication::createInstance = &juce_CreateApplication; \
return juce::JUCEApplication::main (JUCE_MAIN_FUNCTION_ARGS); \
}
#endif
#endif // JUCE_INITIALISATION_H_INCLUDED