Introduction to GtkApplication
GtkApplication is the basis for how most GNOME (and generally Gtk+) applications should be written.
GtkApplication is based on GApplication, which contains some features not directly dependent on Gtk+. This document describes both, from the context of creating a Gtk application.
The two most important features of GApplication (and therefore the two most important things to understand about it) are that it:
- abstracts away of the invocation of your program and exposes an event-based model
- manages the life cycle of your program
Before GApplication, most Gtk applications would have a main() function that performed various setup routines for the application and then showed the main window. Since an invocation of main() corresponds directly to a commandline invocation of your program, this tied the startup of the application and showing of windows directly to the starting of a process.
Some time ago, single instance applications became popular. These are applications that can only have one copy running. Attempting to start a second copy would typically result in the second copy detecting the first copy running and sending a message to it asking it to display a new window or raise its current window.
This was implemented in a very direct way: main() would gain a step in the setup procedure that would check if another instance was running and, if so, signal it and exit early.
Similarly, historically, applications would inspect argc and argv to determine which files (if any) they needed to open.
GApplication takes a fundamentally different approach. Very little work is done from main() -- not application setup tasks, and certainly not showing windows or opening files. main() should usually only instantiate a GApplication and call g_application_run() on it. GApplication makes extensive use of virtual functions (or signals) when certain events need to occur (such as application startup tasks, showing a new window, opening a file, etc).
The three most important virtual functions that you need to know about are:
In the usual style, each of these is also available as a signal with the same name.
In the case of a single instance application, most of the startup tasks of an application should only be done once you know that the currently-executing instance is the primary one. It would be wasteful to perform these initialisation steps in the second instance to be executed.
In the event that the currently-executing instance is the primary one, certain startup tasks must be performed. The startup function is the way to handle these tasks.
As an example, the implementation of startup in GtkApplication is where Gtk is initialised and the connection is made to the graphics server. Any startup task in your application that is not related to constructing a window and putting it on the screen should probably also be done at this point.
If you implement this function that you must be sure to 'chain up' from the start.
startup will be called at most once per process and will be called before any of the other functions mentioned here.
activate is executed by GApplication when the application is "activated". This corresponds to the program being run from the command line or when its icon is clicked on in an application launcher. From a semantic standpoint, activate should usually do one of two things, depending on the type of application.
If your application is the type of application that deals with several documents at a time, in separate windows (and/or tabs) then activate should involve showing a window or creating a tab for a new document.
If your application is more like the type of application with one primary main window then activate should usually involve raising this window with gtk_window_present(). It is the choice of the application in this case if the window itself is constructed in startup or on the first execution of activate.
activate is potentially called many times in a process or maybe never. If the process is started without files to open then activate will be run after startup. It may also be run again if a second instance of the process is started.
open is similar to activate, but it is used when some files have been passed to the application to open.
In fact, you could think of activate as a special case of open: the one with zero files.
Similar to activate, open should create a window or tab. It should open the file in this window. If multiple files are given, possibly several windows should be opened.
open will only be invoked in the case that your application declares that it supports opening files with the G_APPLICATION_HANDLES_OPEN GApplicationFlag.
The second major concept of GApplication is lifecycle management. Historically, applications have run the mainloop using gtk_main() and kept track of which windows it has open. Once all windows are closed, the application would called gtk_main_quit() to exit.
GApplication keeps track of reasons that an application would want to run and runs it for as long as there is a reason. An open window is a reason, but there may be other reasons.
When creating a GtkApplicationWindow, there is an application parameter. This associates the window with the application for (among other things) purposes of lifecycle management. Normal GtkWindow also has an application property that you can set manually and it has the same effect.
You can also call g_application_hold() to request that an application stays alive for a reason not related to showing a window (and g_application_release() when done). This could be used if your application is doing a background task and it needs to continue running.