Browse Source

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

tags/2021-05-28
jules 12 years ago
parent
commit
42aa27900b
31 changed files with 456 additions and 412 deletions
  1. +1
    -1
      extras/Introjucer/Source/Application/jucer_Application.h
  2. +1
    -1
      extras/Introjucer/Source/Application/jucer_MainWindow.cpp
  3. +1
    -1
      extras/Introjucer/Source/ComponentEditor/jucer_GeneratedCode.cpp
  4. +1
    -1
      extras/audio plugin host/Source/HostStartup.cpp
  5. +3
    -3
      modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h
  6. +1
    -1
      modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp
  7. +1
    -1
      modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp
  8. +1
    -1
      modules/juce_core/juce_core.h
  9. +3
    -3
      modules/juce_core/system/juce_PlatformDefs.h
  10. +2
    -2
      modules/juce_core/threads/juce_Process.h
  11. +1
    -0
      modules/juce_events/juce_events.h
  12. +234
    -0
      modules/juce_events/messages/juce_ApplicationBase.cpp
  13. +122
    -13
      modules/juce_events/messages/juce_ApplicationBase.h
  14. +2
    -2
      modules/juce_events/messages/juce_DeletedAtShutdown.h
  15. +12
    -11
      modules/juce_events/messages/juce_Initialisation.h
  16. +3
    -0
      modules/juce_events/messages/juce_MessageManager.cpp
  17. +1
    -1
      modules/juce_events/messages/juce_MessageManager.h
  18. +12
    -215
      modules/juce_gui_basics/application/juce_Application.cpp
  19. +33
    -110
      modules/juce_gui_basics/application/juce_Application.h
  20. +1
    -1
      modules/juce_gui_basics/commands/juce_ApplicationCommandID.h
  21. +0
    -1
      modules/juce_gui_basics/juce_gui_basics.h
  22. +1
    -1
      modules/juce_gui_basics/native/juce_android_Windowing.cpp
  23. +4
    -5
      modules/juce_gui_basics/native/juce_ios_Windowing.mm
  24. +1
    -1
      modules/juce_gui_basics/native/juce_mac_FileChooser.mm
  25. +2
    -2
      modules/juce_gui_basics/native/juce_mac_MainMenu.mm
  26. +2
    -2
      modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm
  27. +2
    -24
      modules/juce_gui_basics/native/juce_win32_Windowing.cpp
  28. +1
    -1
      modules/juce_gui_basics/properties/juce_PropertyPanel.h
  29. +2
    -2
      modules/juce_gui_basics/windows/juce_DocumentWindow.cpp
  30. +2
    -2
      modules/juce_gui_basics/windows/juce_DocumentWindow.h
  31. +3
    -3
      modules/juce_gui_extra/misc/juce_SplashScreen.h

+ 1
- 1
extras/Introjucer/Source/Application/jucer_Application.h View File

@@ -608,7 +608,7 @@ private:
stopTimer();
delete this;
if (JUCEApplication::getInstance() != nullptr)
if (JUCEApplicationBase::getInstance() != nullptr)
getApp().closeModalCompsAndQuit();
}


+ 1
- 1
extras/Introjucer/Source/Application/jucer_MainWindow.cpp View File

@@ -369,7 +369,7 @@ void MainWindowList::closeWindow (MainWindow* w)
#if ! JUCE_MAC
if (windows.size() == 1)
{
JUCEApplication::getInstance()->systemRequestedQuit();
JUCEApplicationBase::getInstance()->systemRequestedQuit();
}
else
#endif


+ 1
- 1
extras/Introjucer/Source/ComponentEditor/jucer_GeneratedCode.cpp View File

@@ -331,7 +331,7 @@ void GeneratedCode::applyToCode (String& code,
headerGuard << String::toHexString ((className + "xx" + fileNameRoot).hashCode64()).toUpperCase() << "__";
replaceTemplate (code, "headerGuard", headerGuard);
replaceTemplate (code, "version", JUCEApplication::getInstance()->getApplicationVersion());
replaceTemplate (code, "version", JUCEApplicationBase::getInstance()->getApplicationVersion());
replaceTemplate (code, "creationTime", Time::getCurrentTime().toString (true, true, true));
replaceTemplate (code, "className", className);


+ 1
- 1
extras/audio plugin host/Source/HostStartup.cpp View File

@@ -75,7 +75,7 @@ public:
if (mainWindow != nullptr)
mainWindow->tryToQuitApplication();
else
JUCEApplication::quit();
JUCEApplicationBase::quit();
}
const String getApplicationName() { return "Juce Plug-In Host"; }


+ 3
- 3
modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h View File

@@ -31,7 +31,7 @@ extern AudioProcessor* JUCE_CALLTYPE createPluginFilter();
/**
A class that can be used to run a simple standalone application containing your filter.
Just create one of these objects in your JUCEApplication::initialise() method, and
Just create one of these objects in your JUCEApplicationBase::initialise() method, and
let it do its work. It will create your filter object using the same createFilter() function
that the other plugin wrappers use.
*/
@@ -63,7 +63,7 @@ public:
if (filter == nullptr)
{
jassertfalse // Your filter didn't create correctly! In a standalone app that's not too great.
JUCEApplication::quit();
JUCEApplicationBase::quit();
}
filter->setPlayConfigDetails (JucePlugin_MaxNumInputChannels,
@@ -243,7 +243,7 @@ public:
/** @internal */
void closeButtonPressed() override
{
JUCEApplication::quit();
JUCEApplicationBase::quit();
}
/** @internal */


+ 1
- 1
modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp View File

@@ -232,7 +232,7 @@ public:
~SharedMessageThread()
{
signalThreadShouldExit();
JUCEApplication::quit();
JUCEApplicationBase::quit();
waitForThreadToExit (5000);
clearSingletonInstance();
}


+ 1
- 1
modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp View File

@@ -1375,7 +1375,7 @@ public:
{
String hostName ("Juce VST Host");
if (JUCEApplication* app = JUCEApplication::getInstance())
if (JUCEApplicationBase* app = JUCEApplicationBase::getInstance())
hostName = app->getApplicationName();
hostName.copyToUTF8 ((char*) ptr, (size_t) jmin (kVstMaxVendorStrLen, kVstMaxProductStrLen) - 1);


+ 1
- 1
modules/juce_core/juce_core.h View File

@@ -119,7 +119,7 @@
/* Config: JUCE_CATCH_UNHANDLED_EXCEPTIONS
If enabled, this will add some exception-catching code to forward unhandled exceptions
to your JUCEApplication::unhandledException() callback.
to your JUCEApplicationBase::unhandledException() callback.
*/
#ifndef JUCE_CATCH_UNHANDLED_EXCEPTIONS
//#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1


+ 3
- 3
modules/juce_core/system/juce_PlatformDefs.h View File

@@ -222,17 +222,17 @@ namespace juce
#if ! JUCE_MODULE_AVAILABLE_juce_gui_basics
#define JUCE_CATCH_EXCEPTION JUCE_CATCH_ALL
#else
/** Used in try-catch blocks, this macro will send exceptions to the JUCEApplication
/** Used in try-catch blocks, this macro will send exceptions to the JUCEApplicationBase
object so they can be logged by the application if it wants to.
*/
#define JUCE_CATCH_EXCEPTION \
catch (const std::exception& e) \
{ \
juce::JUCEApplication::sendUnhandledException (&e, __FILE__, __LINE__); \
juce::JUCEApplicationBase::sendUnhandledException (&e, __FILE__, __LINE__); \
} \
catch (...) \
{ \
juce::JUCEApplication::sendUnhandledException (nullptr, __FILE__, __LINE__); \
juce::JUCEApplicationBase::sendUnhandledException (nullptr, __FILE__, __LINE__); \
}
#endif


+ 2
- 2
modules/juce_core/threads/juce_Process.h View File

@@ -36,7 +36,7 @@
This contains methods for controlling the current application at the
process-level.
@see Thread, JUCEApplication
@see Thread, JUCEApplicationBase
*/
class JUCE_API Process
{
@@ -63,7 +63,7 @@ public:
immediately - it's intended only for use only when something goes
horribly wrong.
@see JUCEApplication::quit
@see JUCEApplicationBase::quit
*/
static void JUCE_CALLTYPE terminate();


+ 1
- 0
modules/juce_events/juce_events.h View File

@@ -38,6 +38,7 @@ namespace juce
#include "messages/juce_DeletedAtShutdown.h"
#include "messages/juce_NotificationType.h"
#include "messages/juce_ApplicationBase.h"
#include "messages/juce_Initialisation.h"
#include "broadcasters/juce_ListenerList.h"
#include "broadcasters/juce_ActionBroadcaster.h"
#include "broadcasters/juce_ActionListener.h"


+ 234
- 0
modules/juce_events/messages/juce_ApplicationBase.cpp View File

@@ -26,6 +26,8 @@ JUCEApplicationBase::CreateInstanceFunction JUCEApplicationBase::createInstance
JUCEApplicationBase* JUCEApplicationBase::appInstance = nullptr;
JUCEApplicationBase::JUCEApplicationBase()
: appReturnValue (0),
stillInitialising (true)
{
jassert (isStandaloneApp() && appInstance == nullptr);
appInstance = this;
@@ -37,6 +39,11 @@ JUCEApplicationBase::~JUCEApplicationBase()
appInstance = nullptr;
}
void JUCEApplicationBase::setApplicationReturnValue (const int newReturnValue) noexcept
{
appReturnValue = newReturnValue;
}
// This is called on the Mac and iOS where the OS doesn't allow the stack to unwind on shutdown..
void JUCEApplicationBase::appWillTerminateByForce()
{
@@ -53,3 +60,230 @@ void JUCEApplicationBase::appWillTerminateByForce()
MessageManager::deleteInstance();
}
}
void JUCEApplicationBase::quit()
{
MessageManager::getInstance()->stopDispatchLoop();
}
void JUCEApplicationBase::sendUnhandledException (const std::exception* const e,
const char* const sourceFile,
const int lineNumber)
{
if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance())
app->unhandledException (e, sourceFile, lineNumber);
}
//==============================================================================
#if ! (JUCE_IOS || JUCE_ANDROID)
#define JUCE_HANDLE_MULTIPLE_INSTANCES 1
#endif
#if JUCE_HANDLE_MULTIPLE_INSTANCES
struct JUCEApplicationBase::MultipleInstanceHandler : public ActionListener
{
public:
MultipleInstanceHandler (const String& appName)
: appLock ("juceAppLock_" + appName)
{
}
bool sendCommandLineToPreexistingInstance()
{
if (appLock.enter (0))
return false;
JUCEApplicationBase* const app = JUCEApplicationBase::getInstance();
jassert (app != nullptr);
MessageManager::broadcastMessage (app->getApplicationName()
+ "/" + app->getCommandLineParameters());
return true;
}
void actionListenerCallback (const String& message) override
{
if (JUCEApplicationBase* const app = JUCEApplicationBase::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)
};
bool JUCEApplicationBase::sendCommandLineToPreexistingInstance()
{
jassert (multipleInstanceHandler == nullptr); // this must only be called once!
multipleInstanceHandler = new MultipleInstanceHandler (getApplicationName());
return multipleInstanceHandler->sendCommandLineToPreexistingInstance();
}
#else
struct JUCEApplicationBase::MultipleInstanceHandler {};
#endif
//==============================================================================
#if JUCE_ANDROID
StringArray JUCEApplicationBase::getCommandLineParameterArray() { return StringArray(); }
String JUCEApplicationBase::getCommandLineParameters() { return String::empty; }
#else
#if JUCE_WINDOWS
String JUCE_CALLTYPE JUCEApplicationBase::getCommandLineParameters()
{
return CharacterFunctions::findEndOfToken (CharPointer_UTF16 (GetCommandLineW()),
CharPointer_UTF16 (L" "),
CharPointer_UTF16 (L"\"")).findEndOfWhitespace();
}
StringArray JUCE_CALLTYPE JUCEApplicationBase::getCommandLineParameterArray()
{
StringArray s;
int argc = 0;
if (LPWSTR* const argv = CommandLineToArgvW (GetCommandLineW(), &argc))
{
s = StringArray (argv + 1, argc - 1);
LocalFree (argv);
}
return s;
}
#else
#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;
String JUCEApplicationBase::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();
}
StringArray JUCEApplicationBase::getCommandLineParameterArray()
{
return StringArray (juce_argv + 1, juce_argc - 1);
}
int JUCEApplicationBase::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 JUCEApplicationBase::main();
#endif
}
}
#endif
//==============================================================================
int JUCEApplicationBase::main()
{
ScopedJuceInitialiser_GUI libraryInitialiser;
jassert (createInstance != nullptr);
const ScopedPointer<JUCEApplicationBase> app (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();
}
#endif
//==============================================================================
bool JUCEApplicationBase::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())
return false;
#if JUCE_HANDLE_MULTIPLE_INSTANCES
if (multipleInstanceHandler != nullptr)
MessageManager::getInstance()->registerBroadcastListener (multipleInstanceHandler);
#endif
return true;
}
int JUCEApplicationBase::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();
}

+ 122
- 13
modules/juce_events/messages/juce_ApplicationBase.h View File

@@ -30,11 +30,57 @@
/**
Abstract base class for application classes.
This class shouldn't be used directly - you'll normally use JUCEApplication as
the base for your app, and that inherits from this, adding some more functionality
to it.
@see JUCEApplication
Note that in the juce_gui_basics module, there's a utility class JUCEApplication
which derives from JUCEApplicationBase, and takes care of a few chores. Most
of the time you'll want to derive your class from JUCEApplication rather than
using JUCEApplicationBase directly, but if you're not using the juce_gui_basics
module then you might need to go straight to this base class.
Any application that wants to run an event loop must declare a subclass of
JUCEApplicationBase, 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 suitable platform-specific
boilerplate code to launch the app.
e.g. @code
class MyJUCEApp : public JUCEApplication
{
public:
MyJUCEApp() {}
~MyJUCEApp() {}
void initialise (const String& commandLine)
{
myMainWindow = new MyApplicationWindow();
myMainWindow->setBounds (100, 100, 400, 500);
myMainWindow->setVisible (true);
}
void shutdown()
{
myMainWindow = nullptr;
}
const String getApplicationName()
{
return "Super JUCE-o-matic";
}
const String getApplicationVersion()
{
return "1.0";
}
private:
ScopedPointer<MyApplicationWindow> myMainWindow;
};
// this generates boilerplate code to launch our app class:
START_JUCE_APPLICATION (MyJUCEApp)
@endcode
@see JUCEApplication, START_JUCE_APPLICATION
*/
class JUCE_API JUCEApplicationBase
{
@@ -51,13 +97,10 @@ public:
static JUCEApplicationBase* getInstance() noexcept { return appInstance; }
//==============================================================================
/** 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.
@@ -148,24 +191,90 @@ public:
const String& sourceFilename,
int lineNumber) = 0;
//==============================================================================
/** 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();
//==============================================================================
/** 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();
//==============================================================================
/** 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 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; }
static bool isStandaloneApp() noexcept { return createInstance != nullptr; }
/** 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; }
//==============================================================================
#ifndef DOXYGEN
// The following methods are for internal use only...
static int main();
static int main (int argc, const char* argv[]);
static void appWillTerminateByForce();
typedef JUCEApplicationBase* (*CreateInstanceFunction)();
static CreateInstanceFunction createInstance;
protected:
virtual int shutdownApp() = 0;
virtual bool initialiseApp();
static void JUCE_CALLTYPE sendUnhandledException (const std::exception*, const char* sourceFile, int lineNumber);
bool sendCommandLineToPreexistingInstance();
#endif
private:
//==============================================================================
static JUCEApplicationBase* appInstance;
int appReturnValue;
bool stillInitialising;
struct MultipleInstanceHandler;
friend struct MultipleInstanceHandler;
friend struct ContainerDeletePolicy<MultipleInstanceHandler>;
ScopedPointer<MultipleInstanceHandler> multipleInstanceHandler;
int shutdownApp();
JUCE_DECLARE_NON_COPYABLE (JUCEApplicationBase)
};


+ 2
- 2
modules/juce_events/messages/juce_DeletedAtShutdown.h View File

@@ -30,7 +30,7 @@
/**
Classes derived from this will be automatically deleted when the application exits.
After JUCEApplication::shutdown() has been called, any objects derived from
After JUCEApplicationBase::shutdown() has been called, any objects derived from
DeletedAtShutdown which are still in existence will be deleted in the reverse
order to that in which they were created.
@@ -55,7 +55,7 @@ public:
/** Deletes all extant objects.
This shouldn't be used by applications, as it's called automatically
in the shutdown code of the JUCEApplication class.
in the shutdown code of the JUCEApplicationBase class.
*/
static void deleteAll();


modules/juce_gui_basics/application/juce_Initialisation.h → modules/juce_events/messages/juce_Initialisation.h View File

@@ -63,28 +63,29 @@ JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI();
main() function, because it'll take care of shutting down whenever you return
from the main() call.
*/
class ScopedJuceInitialiser_GUI
class JUCE_API ScopedJuceInitialiser_GUI
{
public:
/** The constructor simply calls initialiseJuce_GUI(). */
ScopedJuceInitialiser_GUI() { initialiseJuce_GUI(); }
ScopedJuceInitialiser_GUI();
/** The destructor simply calls shutdownJuce_GUI(). */
~ScopedJuceInitialiser_GUI() { shutdownJuce_GUI(); }
~ScopedJuceInitialiser_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.
AppSubClass is the name of a class derived from JUCEApplication or JUCEApplicationBase.
See the JUCEApplication and JUCEApplicationBase class documentation for more details.
*/
#if JUCE_ANDROID
#ifdef DOXYGEN
#define START_JUCE_APPLICATION(AppClass)
#elif JUCE_ANDROID
#define START_JUCE_APPLICATION(AppClass) \
juce::JUCEApplication* juce_CreateApplication() { return new AppClass(); }
juce::JUCEApplicationBase* juce_CreateApplication() { return new AppClass(); }
#else
#if JUCE_WINDOWS
@@ -105,8 +106,8 @@ public:
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); \
juce::JUCEApplicationBase::createInstance = &juce_CreateApplication; \
return juce::JUCEApplicationBase::main (JUCE_MAIN_FUNCTION_ARGS); \
}
#endif

+ 3
- 0
modules/juce_events/messages/juce_MessageManager.cpp View File

@@ -334,3 +334,6 @@ JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI()
MessageManager::deleteInstance();
}
}
ScopedJuceInitialiser_GUI::ScopedJuceInitialiser_GUI() { initialiseJuce_GUI(); }
ScopedJuceInitialiser_GUI::~ScopedJuceInitialiser_GUI() { shutdownJuce_GUI(); }

+ 1
- 1
modules/juce_events/messages/juce_MessageManager.h View File

@@ -41,7 +41,7 @@ typedef void* (MessageCallbackFunction) (void* userData);
/**
This class is in charge of the application's event-dispatch loop.
@see Message, CallbackMessage, MessageManagerLock, JUCEApplication
@see Message, CallbackMessage, MessageManagerLock, JUCEApplication, JUCEApplicationBase
*/
class JUCE_API MessageManager
{


+ 12
- 215
modules/juce_gui_basics/application/juce_Application.cpp 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::~JUCEApplication()
JUCEApplication* JUCE_CALLTYPE JUCEApplication::getInstance() noexcept
{
return dynamic_cast <JUCEApplication*> (JUCEApplicationBase::getInstance());
}
//==============================================================================
bool JUCEApplication::moreThanOneInstanceAllowed() { return true; }
void JUCEApplication::anotherInstanceStarted (const String&) {}
void JUCEApplication::suspended() {}
void JUCEApplication::resumed() {}
void JUCEApplication::systemRequestedQuit()
{
quit();
}
void JUCEApplication::quit()
{
MessageManager::getInstance()->stopDispatchLoop();
}
void JUCEApplication::setApplicationReturnValue (const int newReturnValue) noexcept
{
appReturnValue = newReturnValue;
}
void JUCEApplication::systemRequestedQuit() { quit(); }
//==============================================================================
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;
}
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 true;
}
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
}
return false;
}
#endif
#endif

+ 33
- 110
modules/juce_gui_basics/application/juce_Application.h 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)
};


+ 1
- 1
modules/juce_gui_basics/commands/juce_ApplicationCommandID.h View File

@@ -55,7 +55,7 @@ namespace StandardApplicationCommandIDs
This command is recognised by the JUCEApplication class, so if it is invoked
and no other ApplicationCommandTarget handles the event first, the JUCEApplication
object will catch it and call JUCEApplication::systemRequestedQuit().
object will catch it and call JUCEApplicationBase::systemRequestedQuit().
*/
static const CommandID quit = 0x1001;


+ 0
- 1
modules/juce_gui_basics/juce_gui_basics.h View File

@@ -238,7 +238,6 @@ class ApplicationCommandManagerListener;
#include "properties/juce_SliderPropertyComponent.h"
#include "properties/juce_TextPropertyComponent.h"
#include "application/juce_Application.h"
#include "application/juce_Initialisation.h"
#include "misc/juce_BubbleComponent.h"
}


+ 1
- 1
modules/juce_gui_basics/native/juce_android_Windowing.cpp View File

@@ -41,7 +41,7 @@ JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, launchApp, void, (JNIEnv* en
initialiseJuce_GUI();
JUCEApplication* app = dynamic_cast <JUCEApplication*> (JUCEApplicationBase::createInstance());
JUCEApplicationBase* app = JUCEApplicationBase::createInstance();
if (! app->initialiseApp())
exit (0);


+ 4
- 5
modules/juce_gui_basics/native/juce_ios_Windowing.mm View File

@@ -41,7 +41,8 @@
{
initialiseJuce_GUI();
JUCEApplication* app = dynamic_cast <JUCEApplication*> (JUCEApplicationBase::createInstance());
JUCEApplicationBase* app = JUCEApplicationBase::createInstance();
if (! app->initialiseApp())
exit (0);
}
@@ -53,15 +54,13 @@
- (void) applicationDidEnterBackground: (UIApplication*) application
{
JUCEApplicationBase* const app = JUCEApplicationBase::getInstance();
if (app != nullptr)
if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance())
app->suspended();
}
- (void) applicationWillEnterForeground: (UIApplication*) application
{
JUCEApplicationBase* const app = JUCEApplicationBase::getInstance();
if (app != nullptr)
if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance())
app->resumed();
}


+ 1
- 1
modules/juce_gui_basics/native/juce_mac_FileChooser.mm View File

@@ -118,7 +118,7 @@ void FileChooser::showPlatformDialog (Array<File>& results,
JUCE_AUTORELEASEPOOL
{
ScopedPointer<TemporaryMainMenuWithStandardCommands> tempMenu;
if (JUCEApplication::isStandaloneApp())
if (JUCEApplicationBase::isStandaloneApp())
tempMenu = new TemporaryMainMenuWithStandardCommands();
StringArray* filters = new StringArray();


+ 2
- 2
modules/juce_gui_basics/native/juce_mac_MainMenu.mm View File

@@ -662,9 +662,9 @@ namespace MainMenuHelpers
static void rebuildMainMenu (const PopupMenu* extraItems)
{
// this can't be used in a plugin!
jassert (JUCEApplication::isStandaloneApp());
jassert (JUCEApplicationBase::isStandaloneApp());
if (JUCEApplication* app = JUCEApplication::getInstance())
if (JUCEApplicationBase* app = JUCEApplicationBase::getInstance())
{
JUCE_AUTORELEASEPOOL
{


+ 2
- 2
modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm View File

@@ -1388,7 +1388,7 @@ private:
static void mouseDown (id self, SEL s, NSEvent* ev)
{
if (JUCEApplication::isStandaloneApp())
if (JUCEApplicationBase::isStandaloneApp())
asyncMouseDown (self, s, ev);
else
// In some host situations, the host will stop modal loops from working
@@ -1401,7 +1401,7 @@ private:
static void mouseUp (id self, SEL s, NSEvent* ev)
{
if (JUCEApplication::isStandaloneApp())
if (JUCEApplicationBase::isStandaloneApp())
asyncMouseUp (self, s, ev);
else
// In some host situations, the host will stop modal loops from working


+ 2
- 24
modules/juce_gui_basics/native/juce_win32_Windowing.cpp View File

@@ -162,7 +162,7 @@ static void setWindowZOrder (HWND hwnd, HWND insertAfter)
//==============================================================================
static void setDPIAwareness()
{
if (JUCEApplication::isStandaloneApp())
if (JUCEApplicationBase::isStandaloneApp())
{
if (setProcessDPIAware == nullptr)
{
@@ -2457,7 +2457,7 @@ private:
return 0;
case WM_QUERYENDSESSION:
if (JUCEApplication* const app = JUCEApplication::getInstance())
if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance())
{
app->systemRequestedQuit();
return MessageManager::getInstance()->hasStopMessageBeenSent();
@@ -3158,28 +3158,6 @@ String SystemClipboard::getTextFromClipboard()
return result;
}
//==============================================================================
String JUCE_CALLTYPE JUCEApplication::getCommandLineParameters()
{
return CharacterFunctions::findEndOfToken (CharPointer_UTF16 (GetCommandLineW()),
CharPointer_UTF16 (L" "),
CharPointer_UTF16 (L"\"")).findEndOfWhitespace();
}
StringArray JUCE_CALLTYPE JUCEApplication::getCommandLineParameterArray()
{
StringArray s;
int argc = 0;
if (LPWSTR* const argv = CommandLineToArgvW (GetCommandLineW(), &argc))
{
s = StringArray (argv + 1, argc - 1);
LocalFree (argv);
}
return s;
}
//==============================================================================
void Desktop::setKioskComponent (Component* kioskModeComponent, bool enableOrDisable, bool /*allowMenusAndBars*/)
{


+ 1
- 1
modules/juce_gui_basics/properties/juce_PropertyPanel.h View File

@@ -79,7 +79,7 @@ public:
/** Calls the refresh() method of all PropertyComponents in the panel */
void refreshAll() const;
/** Returns true if there no properties have been added. */
/** Returns true if the panel contains no properties. */
bool isEmpty() const;
/** Returns the height that the panel needs in order to display all of its content


+ 2
- 2
modules/juce_gui_basics/windows/juce_DocumentWindow.cpp View File

@@ -165,8 +165,8 @@ void DocumentWindow::closeButtonPressed()
If your app is centred around this window such that the whole app should quit when
the window is closed, then you will probably want to use this method as an opportunity
to call JUCEApplication::quit(), and leave the window to be deleted later by your
JUCEApplication::shutdown() method. (Doing it this way means that your window will
to call JUCEApplicationBase::quit(), and leave the window to be deleted later by your
JUCEApplicationBase::shutdown() method. (Doing it this way means that your window will
still get cleaned-up if the app is quit by some other means (e.g. a cmd-Q on the mac
or closing it via the taskbar icon on Windows).
*/


+ 2
- 2
modules/juce_gui_basics/windows/juce_DocumentWindow.h View File

@@ -173,8 +173,8 @@ public:
If your app is centred around this window such that the whole app should quit when
the window is closed, then you will probably want to use this method as an opportunity
to call JUCEApplication::quit(), and leave the window to be deleted later by your
JUCEApplication::shutdown() method. (Doing it this way means that your window will
to call JUCEApplicationBase::quit(), and leave the window to be deleted later by your
JUCEApplicationBase::shutdown() method. (Doing it this way means that your window will
still get cleaned-up if the app is quit by some other means (e.g. a cmd-Q on the mac
or closing it via the taskbar icon on Windows).


+ 3
- 3
modules/juce_gui_extra/misc/juce_SplashScreen.h View File

@@ -32,7 +32,7 @@
This will automatically position itself, and can be told to delete itself after
being on-screen for a minimum length of time.
To use it, just create one of these in your JUCEApplication::initialise() method,
To use it, just create one of these in your JUCEApplicationBase::initialise() method,
and when your initialisation tasks have finished running, call its deleteAfterDelay()
method to make it automatically get rid of itself.
@@ -78,9 +78,9 @@ public:
When called, the constructor will position the SplashScreen in the centre of the
display, and after the time specified, it will automatically delete itself.
Bear in mind that if you call this during your JUCEApplication::initialise()
Bear in mind that if you call this during your JUCEApplicationBase::initialise()
method and then block the message thread by performing some kind of task, then
obviously neither your splash screen or any other GUI won't appear until you
obviously neither your splash screen nor any other GUI will appear until you
allow the message thread to resume and do its work. So if you have time-consuming
tasks to do during startup, use a background thread for them.


Loading…
Cancel
Save