Using GtkApplication

GtkApplication is the base class of a Gtk Application. Its primary purpose is to separate your program from main().

main() is an operating system implementation detail that is really uninteresting to applications. The philosophy of GtkApplication is that applications are interested in being told what needs to happen, when it needs to happen, in response to actions from the user. The exact mechanism by which the operating system starts applications is uninteresting.

To this end, GtkApplication exposes a set of signals (or virtual functions) that an application should respond to.

  • startup: sets up the application when it first starts

  • shutdown: performs shutdown tasks

  • activate: shows the default first window of the application (like a new document). This corresponds to the application being launched by the desktop environment.

  • open: opens files and shows them in a new window. This corresponds to someone trying to open a document (or documents) using the application from the file browser, or similar.

When your application starts, the startup signal will be fired. This gives you a chance to perform initialisation tasks that are not directly related to showing a new window. After this, depending on how the application is started, either activate or open will be called next.

GtkApplication defaults to applications being single-instance. If the user attempts to start a second instance of a single-instance application then GtkApplication will signal the first instance and you will receive additional activate or open signals. In this case, the second instance will exit immediately, without calling startup or shutdown.

For this reason, you should do essentially no work at all from main(). All startup initialisation should be done in startup. This avoids wasting work in the second-instance case where the program just exits immediately.

The application will continue to run for as long as it needs to. This is usually for as long as there are any open windows. You can additionally force the application to stay alive using g_application_hold().

On shutdown, you receive a shutdown signal where you can do any necessary cleanup tasks (such as saving files to disk).

GtkApplication does not implement main() for you. You must do so yourself. Your main() function should be as small as possible and do almost nothing except creating your GtkApplication and running it. The "real work" should always be done in response to the signals fired by GtkApplication.

Primary vs. local instance

The "primary instance" of an application is the first instance of it that was run. A "remote instance" is another instance that is started that is not the primary instance. The term "local instance" is used to refer to the current process which may or may not be the primary instance.

GtkApplication only ever emits signals in the primary instance. Calls to GtkApplication API can be made in primary or remote instances (and are made from the vantage of being the "local instance"). In the case that the local instance is the primary instance, function calls on GtkApplication will result in signals being emitted locally, in the primary instance. In the case that the local instance is a remote instance, function calls result in messages being sent to the primary instance and signals being emitted there.

For example, calling g_application_activate() on the primary instance will emit the "activate" signal. Calling it on a remote instance will result in a message being sent to the primary instance and it will emit "activate".

You rarely need to know if the local instance is primary or remote. In almost all cases, you should just call the GtkApplication method you are interested in and either have it be forwarded or handled locally, as appropriate.

Actions

An application can register a set of actions that it supports in addition to the default activate and open. Actions are added to the application with the GActionMap interface and invoked or queried with the GActionGroup interface.

As with activate and open, calling g_action_group_activate_action() on the primary instance will activate the named action in the current process. Calling g_action_group_activate_action() on a remote instance will send a message to the primary instance, causing the action to be activated there.

Dealing with the command line

Normally, GtkApplication will assume that arguments passed on the command line are files to be opened. If no arguments are passed, then it assumes that an application is being launched to show its main window or an empty document. In the case that files were given, you will receive these files (in the form of GFile) from the open signal. Otherwise you will receive an activate signal. It is recommended that new applications make use of this default handling of command line arguments.

If you want to deal with command line arguments in more advanced ways, there are several (complementary) mechanisms by which you can do this.

First, the handle-local-options signal will be emitted and the signal handler gets a dictionary with the parsed options. To make use of this, you need to register your options with g_application_add_main_option_entries(). The signal handler can return a non-negative value to end the process with this exit code, or a negative value to continue with the regular handling of commandline options. A popular use of for this signal is to implement a --version argument that works without communicating with a remote instance.

If handle-local-options is not flexible enough for your needs, you can override the local_command_line virtual function to take over the handling of command line arguments in the local instance entirely. If you do so, you will be responsible for registering the application, and for handling a --help argument (the default local_command_line function does this for you).

It is also possible to invoke actions from handle-local-options or local_command_line in response to command line arguments. For example, a mail client may choose to map the --compose command line argument to an invocation of its "compose" action. This is done by calling g_action_group_activate_action() from the local_command_line implementation. In the case that the command line being processed is in the primary instance then the "compose" action is invoked locally. In the case that it is a remote instance, the action invocation is forwarded to the primary instance.

Note in particular that it is possible to use action activations instead of activate or open. It is perfectly reasonable that an application could start without an activate signal ever being emitted. activate is only supposed to be the default "started with no options" signal. Actions are meant to be used for anything else.

Some applications may wish to perform even more advanced handling of command lines, including controlling the life cycle of the remote instance and its exit status once it quits as well as forwarding the entire contents of the command line arguments, the environment and even forwarding stdin/stdout/stderr. This can be accomplished using G_APPLICATION_HANDLES_COMMAND_LINE and the command-line signal.

For more in-depth information about commandline handling with GApplication, see /CommandLine.

C

   1 #include <gtk/gtk.h>
   2 
   3 static void
   4 activate (GApplication *app,
   5           gpointer      user_data)
   6 {
   7   GtkWidget *widget;
   8 
   9   widget = gtk_application_window_new (GTK_APPLICATION (app));
  10   gtk_widget_show (widget);
  11 }
  12 
  13 int
  14 main (int argc, char **argv)
  15 {
  16   GtkApplication *app;
  17   int status;
  18 
  19   app = gtk_application_new ("org.gnome.example", G_APPLICATION_FLAGS_NONE);
  20   g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  21   status = g_application_run (G_APPLICATION (app), argc, argv);
  22   g_object_unref (app);
  23 
  24   return status;
  25 }

Python

   1 import sys
   2 
   3 from gi.repository import Gio, Gtk
   4 
   5 
   6 class App(Gtk.Application):
   7 
   8     def __init__(self):
   9         Gtk.Application.__init__(self,
  10                                  application_id="org.gnome.example",
  11                                  flags=Gio.ApplicationFlags.FLAGS_NONE)
  12 
  13         self.connect("activate", self.activateCb)
  14 
  15     def activateCb(self, app):
  16         window = Gtk.ApplicationWindow()
  17         app.add_window(window)
  18         window.show()
  19 
  20 
  21 if __name__ == '__main__':
  22     app = App()
  23     app.run(sys.argv)

Vala

   1 class ExampleApp : Gtk.Application {
   2   protected override void activate () {
   3     var window = new Gtk.ApplicationWindow (this);
   4     window.show ();
   5   }
   6 
   7   public ExampleApp () {
   8     Object (application_id: "org.gnome.example");
   9   }
  10 }
  11 
  12 int main (string[] args) {
  13   return new ExampleApp ().run (args);
  14 }

See Also

HowDoI/GtkApplication (last edited 2017-03-06 09:04:21 by TobiasMueller)