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);