Porting application to use GUniqueApp single-instance library

The basics

To use guniqueapp in your application, add this code to your applications' source, usually somewhere in main(...) (please note that Glib type system must be initialized before, because GUniqueApp is a GObject):

   1 int main (int argc, char** argv)
   2 {
   3         GUniqueApp *app;
   4         
   5         /* Your stuff & gtk init here */
   6         
   7         app = g_unique_app_get ("my-cool-application");
   8         
   9         /* If we have another instance running, send it a message */
  10         if (g_unique_app_is_running (app))
  11         {
  12                 /* There are 4 predefined message functions, 
  13                  * g_unique_app_activate (GUniqueApp *app) - tells another instance to activate its window;
  14                  * g_unique_app_activate (GUniqueApp *app) - tells another instance to create a new document/window;
  15                  * g_unique_app_open_uri (GUniqueApp *app, gchar* uri) - opens URI;
  16                  * g_unique_app_custom_message (GUniqueApp *app, gchar* data) - sends a custom message.
  17                  */
  18                  
  19                  /* Lets suppose we have a simple application of one window here,
  20                   * which only needs to raise the existing window */
  21                   
  22                  g_unique_app_activate (app);
  23 
  24                 /* Clean up & exit */
  25                 g_object_unref (app);
  26                 exit(1);
  27         }
  28         
  29         /* Listen for messages from another instances */
  30         else g_signal_connect (G_OBJECT (app), "message", (GCallback) user_callback, user_data);
  31         
  32         /* Somewhere in the end of the program */
  33         
  34         /* Unref GUniqueApp object, may be not necessarily needed, but still, can't hurt */
  35         g_object_unref (app);
  36 }

We connected our callback to the "message" signal, callback looks something like:

   1 static void user_callback (GUniqueApp *app, GUniqueAppCommand command, gchar* data, gchar* startup_id, guint workspace, gpointer user_data)
   2 {
   3         /* Just set the startup_id on the window, everything is handled automatically */
   4         if (command == G_UNIQUE_APP_ACTIVATE)
   5                 gtk_window_set_startup_id (GTK_WINDOW (our_window), startup_id);
   6         
   7         /* If you construct a new window, everything is pretty the same, just set the startup-id before showing it, i.e.:
   8          * new_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   9          * ...
  10          * gtk_window_set_startup_id (GTK_WINDOW (new_window), startup_id);
  11          * gtk_widget_show_all (new_window);
  12          */
  13 }

Unpatched GTK versions

To be fully functional, libguniqueapp requires GTK version with specific patches in, see: http://bugzilla.gnome.org/show_bug.cgi?id=347375.

However, some fallbacks are provided to compile on older GTK versions as well. Define AC_DEFINE(OLDER_GTK_VERSION, , [Building with GTK+ older than 2.12]), if you are using such.

Also, add the following ammendments to your code:

   1 int main (int argc, char** argv)
   2 {
   3         GUniqueApp *app;
   4         gchar* startup_id = NULL;
   5         
   6         /* Obtain startup ID from env-variable */
   7         
   8 #ifdef OLDER_GTK_VERSION
   9         /* We must get the startup ID *BEFORE* gtk_init() is called
  10          * because gtk_init() will clear it.
  11          */
  12         startup_id = g_getenv ("DESKTOP_STARTUP_ID");
  13 #endif
  14         
  15         /* Your stuff & gtk init here */
  16         
  17         /* Pass the obtained startup-id */
  18         app = g_unique_app_get_with_startup_id ("my-cool-application", startup_id);
  19         
  20         /* If we have another instance running, send it a message */
  21         if (g_unique_app_is_running (app))
  22         {
  23                 /* There are 4 predefined message functions, 
  24                  * g_unique_app_activate (GUniqueApp *app) - tells another instance to activate its window;
  25                  * g_unique_app_activate (GUniqueApp *app) - tells another instance to create a new document/window;
  26                  * g_unique_app_open_uri (GUniqueApp *app, gchar* uri) - opens URI,
  27                  * g_unique_app_custom_message (GUniqueApp *app, gchar* data) - sends a custom message.
  28                  */
  29                  
  30                  /* Lets suppose we have a simple application of one window here,
  31                   * which only needs to raise the existing window */
  32                   
  33                  g_unique_app_activate (app);
  34                  
  35 #ifdef OLDER_GTK_VERSION
  36                 /* This will cause the busy cursor and temporary task in the
  37                  * tasklist to go away too soon.  However, the alternative
  38                  * without newer gtk+ is having both be stuck until the
  39                  * 30-second-or-so timeout ends, which would be worse.
  40                  */
  41                 gdk_notify_startup_complete ();
  42 #endif
  43 
  44                 /* Clean up & exit */
  45                 g_object_unref (app);
  46                 exit(1);
  47         }
  48         
  49         /* Listen for messages from another instances */
  50         else g_signal_connect (G_OBJECT (app), "message", (GCallback) user_callback, user_data);
  51         
  52         /* Somewhere in the end of the program */
  53         
  54         /* Unref GUniqueApp object, may be not necessarily needed, but still, can't hurt */
  55         g_object_unref (app);
  56 }

Passing complex arguments

Applications often pass entire command line to another instance. This can be easily achieved using Glib's string functions, join the string and send a custom message:

   1 gchar* data = g_strjoinv ("\v", argv);
   2 g_unique_app_custom_message (app, data);
   3 g_free (data);
   4 
   5 /* Later, in the callback code, split it back if needed: */
   6 
   7 gchar** argv = g_strsplit (data, "\v", 0);
   8 /* Do something here. You can find out argc = g_strv_length (argv) */
   9 g_strfreev (argv);

Attic/GuniqueappUsageGuide (last edited 2013-11-22 21:19:36 by WilliamJonMcCann)