AApplication#
Application-wide lifetime and instancing control.
| Header: | #include <AUI/Platform/AApplication.h> |
| CMake: | aui_link(my_target PUBLIC aui::core) |
Detailed Description#
See Application lifetime & instancing for the overview.
AApplication is fully opt-in: if you never call its methods, your application behaves exactly as before (CLI
applications exit after AUI_ENTRY, UI applications exit after the last window is closed, embedded applications run
their own loop).
Lifetime#
After AUI_ENTRY returns, AUI runs the main event loop as long as the application is held. Each shown AWindow
holds the application (unless quitOnLastWindowClosed is false). You can hold the application explicitly with
hold().
Single instance#
See requestSingleInstanceLock().
Data directory#
Application's own persistent data (settings, databases, etc.) should be stored in the per-application folder
returned by dataDir(). Unlike APath::APPDATA, which is shared between all applications of the user, it is derived
from the application id specified in aui_app(ID ...). The folder is created by dataDir() on first call.
APath settings = AApplication::inst().dataDir() / "settings.json";
Public Types#
Hold#
class AApplication::Hold
RAII object that keeps the application alive. While at least one Hold exists, the main event loop keeps running even if there are no open windows.
Empty structure.
Public fields and Signals#
activated#
emits<AActivation> activated
Emitted on the main thread when another instance of the application was launched and redirected to this one.
Not emitted for the first launch: handle it in AUI_ENTRY.
quitOnLastWindowClosed#
std::atomic_bool quitOnLastWindowClosed
Whether a shown AWindow holds the application.
Defaults to true, which means that the application exits when the last window is closed. Set to false to
manage the lifetime by hold() and quit() only.
Public Methods#
dataDir#
APath AApplication::dataDir()
Per-application folder for persistent data (settings, databases, etc.).
- Returns
- absolute path to an existing (created on demand) folder.
The folder name is derived from aui::app_info::app_id (set by aui_app(ID ...)). If the id is not set, the
aui::app_info::name is used instead. Different applications never share the same folder as long as their
ids (or names) differ.
The folder is created by AUI: every call makes sure that it exists (including missing parent folders), so you
don't need to call APath::makeDirs() on it yourself. If the folder is removed while the application is
running (i.e., by the user), the next call to dataDir() creates it again; hence, don't cache the folder's
existence, call dataDir() when you need the path. Files and subfolders inside it are up to you.
Throws AException if the application id (or name) is not set, or if the folder can't be created (i.e., no permissions).
APath settings = AApplication::inst().dataDir() / "settings.json";
hasSingleInstanceLock#
Whether requestSingleInstanceLock() succeeded.
hold#
Creates a new application hold.
Store the result in a long-living object (a controller, a tracker, a tray icon, the application state, etc.).
AUI_ENTRY returns before the main loop starts, so a local variable inside AUI_ENTRY is not enough.
To stop holding (i.e., a window is closed and the user didn't allow background work), reset the pointer: when the last hold is released, the application exits.
state->lifetimeHold = AApplication::inst().hold();
...
state->lifetimeHold.reset(); // allow the application to exit
holdCount#
Number of active holds (explicit ones and implicit ones made by windows).
isHeld#
Whether the main loop should keep running.
isQuitRequested#
Whether quit() was called.
quit#
void AApplication::quit(AOptional<int> exitCode = std::nullopt)
Requests the main event loop to stop regardless of holds.
- Arguments
exitCodeif set, overrides the value returned from `AUI_ENTRY`.
requestSingleInstanceLock#
Makes the current process the only running instance of the application.
- Arguments
- Returns
- true, if the current process is the primary instance; false, if another instance is running. In the latter case, the activation (args, working dir, activation token) of the current process has already been delivered to the primary instance and you should return from `AUI_ENTRY` immediately.
Should be called at the very beginning of AUI_ENTRY, before any window is created. Code that may relaunch the
executable (i.e., an updater) should run before the lock.
When another instance is launched, the primary instance receives activated signal on the main thread. For applications working in background, create the window lazily in the handler and keep the application alive with hold().
AUI_ENTRY {
if (!AApplication::inst().requestSingleInstanceLock()) {
return 0;
}
auto state = _new<State>();
state->lifetimeHold = AApplication::inst().hold();
AObject::connect(AApplication::inst().activated, AObject::GENERIC_OBSERVER, [=](const AActivation& a) {
if (!gMainWindow) {
gMainWindow = _new<MainWindow>(state);
}
gMainWindow->activate(a.activationToken);
});
...
}
See Application lifetime & instancing for the complete example.