2013-03-14

Moving from Unique to GtkApplication

A new class has been introduced in GTK+3 that is GtkApplication, and GApplication with GIO 2.28. A common use case is to have a single window present every time the same application or command line is run, that is also known as process uniqueness. This is already possible with Unique that was especially developed for single instance applications. This very basic post will show an example in C with Unique, and also how to do it with GtkApplication, where you will see that GtkApplication makes things even easier.

First of all, the documentation available from the GIO source code doesn't give a concrete example for process uniqueness with GApplication. There are mainly examples about using GApplication with GSimpleAction, that is pretty cool since it lets you easily define actions to run on the primary instance outside of the process, either with the same program or a different one.

Single window with Unique

In the following example, a UniqueApp class is instantiated, then it's checked against another running instance. If not, a window is created and a handle is connected to the UniqueApp object to react on received messages. Otherwise a message is sent, and the existing instance will execute the connected handle and put the window in front.
#include <unique/unique.h>
#include <gtk/gtk.h>

static UniqueResponse
cb_unique_app (UniqueApp *app,
               gint command,
               UniqueMessageData *message_data,
               guint time_,
               gpointer user_data)
{
  GtkWidget *window = user_data;
  if (command != UNIQUE_ACTIVATE)
    {
      return UNIQUE_RESPONSE_PASSTHROUGH;
    }
  gtk_window_present (GTK_WINDOW (window));
  return UNIQUE_RESPONSE_OK;
}

gint main (gint argc, gchar *argv[])
{
  GtkWidget *window;
  UniqueApp *app;

  gtk_init (&argc, &argv);

  app = unique_app_new ("info.mmassonnet.UniqueExample", NULL);
  if (unique_app_is_running (app))
    {
      if (unique_app_send_message (app, UNIQUE_ACTIVATE, NULL) == UNIQUE_RESPONSE_OK)
        {
          g_object_unref (app);
          return 0;
        }
    }

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_widget_show (window);

  gtk_main ();
  return 0;
}

Single window with GtkApplication

In this example, a GtkApplication class is instantiated. This one is then registered, and a check is done to know if the running process is the primary one or a remote one. Just like in the previous example, either the process is the main one and a window is created and shown, otherwise a signal is sent and the connected handle will put the window in front. The handle used here is directly a GTK function that presents the window which spares the need to write a custom handler.
#include <gtk/gtk.h>

gint main (gint argc, gchar *argv[])
{
  GtkWidget *window;
  GtkApplication *app;
  GError *error = NULL;

  gtk_init (&argc, &argv);

  app = gtk_application_new ("info.mmassonnet.GtkExample", 0);

  g_application_register (G_APPLICATION (app), NULL, &error);
  if (error != NULL)
    {
      g_warning ("Unable to register GApplication: %s", error->message);
      g_error_free (error);
      error = NULL;
    }

  if (g_application_get_is_remote (G_APPLICATION (app)))
    {
      g_application_activate (G_APPLICATION (app));
      g_object_unref (app);
      return 0;
    }

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_widget_show (window);

  g_signal_connect_swapped (app, "activate", G_CALLBACK (gtk_window_present), dialog);

  gtk_main ();
  return 0;
}
In both examples there is just one difference, it is how the primary process is seen. With Unique there is a function to know if another instance is running, while with GtkApplication there is a function to know if the current process is not the primary one e.g. a remote instance. I prefer the second approach, since with Unique if there is only one instance running, the is_running property will tell you false but the primary instance is running, isn't it? But anyhow, as you can see, it is possible to implement painlessly what is done by Unique with GtkApplication.