application.h
An application built on the SDK: the object that owns the process, and the main() that runs it.
#include <sonore/application.h>- 1type
- 1other declaration
- Guides: Testing your plugin
On this page
Design notes
Not for plugins, and not the plugin standalone
A plugin has no application: the host owns the process, its loop and its lifetime, and a plugin that made an application singleton would be a second one inside somebody else's. standalone.h's main() is the PLUGIN standalone and stays what it is. This is for programs that are applications in their own right -- an editor, a librarian, a tool -- in the reference's shape: subclass Application, answer initialise() and shutdown(), and SONORE_START_APPLICATION(MyApp) writes main (and WinMain) for you.
What run() does, in order
- The command line, as UTF-8 (on Windows from GetCommandLineW, because main's argv is in the ANSI code page and loses every name outside it).
- MessageManager::getInstance() on this thread, which makes it the message thread, and the unhandled-exception hook pointed at the app.
- If moreThanOneInstanceAllowed() is false: the single-instance lock. The second instance hands its command line to the first, whose anotherInstanceStarted() receives it, and exits without initialising.
- The platform's quit requests wired to systemRequestedQuit(): Windows' end-of-session query and console Ctrl+C/close, AppKit's applicationShouldTerminate: (Cmd-Q, the Dock, log-out), and SIGINT / SIGTERM on Linux through a self-pipe the loop polls.
- initialise(), the dispatch loop until quit(), shutdown(), and the return value.
The single-instance lock and its message
Windows: a named mutex in the session's namespace -- the kernel drops it with the last handle, so an instance that crashed cannot leave the lock held. macOS and Linux: flock on a file in the temporary directory, which the kernel likewise releases with the process. The first instance takes the lock only AFTER its message thread can hear (its message window or socket exists), so a second instance started a moment later cannot find the lock held and nobody listening.
The command line travels tagged with the application's name, so every other Sonore program ignores it. On Windows it is WM_COPYDATA sent to the first instance's own session window, waiting for as long as its initialise() keeps it from answering (detail::app::forwardToFirstInstance); on macOS MessageManager::broadcastMessage (a distributed notification); on Linux, where broadcastMessage has no transport, an abstract-namespace Unix socket the first instance listens on.
Unhandled exceptions
An exception thrown by a queued callback, by a window procedure in document_window.h, by initialise() or shutdown() reaches unhandledException() and the program carries on (the loop is re-entered); the default prints it to stderr. Nothing unwinds into the OS's loop.
RUN on Windows: the whole lifecycle in a child process, the lock and the forwarded command line between two processes, the end-of-session query, the exception hook. macOS and Linux are compiled only.
Types 1
The application: one per process, made by SONORE_START_APPLICATION (or handed to Application::run) and destroyed after shutdown().
Everything here runs on the message thread -- the main thread.
Macros 1
- macro
#define SONORE_START_APPLICATION(AppClass) …main (and, on Windows, WinMain) for an application class:application.h:973More
class MyApp : public sonore::Application { ... }; SONORE_START_APPLICATION(MyApp)Both entry points are defined on Windows; the linker's subsystem picks one (/SUBSYSTEM:WINDOWS for a GUI program with no console, WinMain), and either reads the command line as UTF-16.