libunique

About

Unique is a library for writing single instance application. If you launch a single instance application twice, the second instance will either just quit or will send a message to the running instance.

Unique makes it easy to write this kind of applications, by providing a base class, taking care of all the IPC machinery needed to send messages to a running instance, and also handling the startup notification side.

Unique aims to replace the BaconMessageConnection code that has been copied by many projects and the code using Bonobo and D-Bus.

Features

Development

Releases

Example

#include <gtk/gtk.h>
#include <unique/unique.h>

enum
{
  COMMAND_0, /* unused: 0 is an invalid command */

  COMMAND_FOO,
  COMMAND_BAR
};

static GtkWidget *main_window = NULL;

static void
message_received_cb (UniqueApp         *app,
                     gint               command,
                     UniqueMessageData *message,
                     guint              time_,
                     gpointer           user_data)
{
  UniqueResponse res;

  switch (command)
    {
    UNIQUE_ACTIVATE:
      /* move the main window to the screen that sent us the command */
      gtk_widget_set_screen (GTK_WINDOW (main_window), unique_message_data_get_screen (screen));
      gtk_window_present (GTK_WINDOW (main_window));
      res = UNIQUE_RESPONSE_OK;
      break;
    COMMAND_FOO:
      /* "foo" is a command that can fail */
      if (do_command_foo ())
        res = UNIQUE_RESPONSE_OK;
      else
        res = UNIQUE_RESPONSE_FAIL;
      break;
    COMMAND_BAR:
      /* "bar" is a command that requires user interaction */
      if (!ask_user_for_bar ())
        res = UNIQUE_RESPONSE_CANCEL;
      else
        {
          do_command_bar ();
          res = UNIQUE_RESPONSE_OK;
        }
      break;
    default:
      res = UNIQUE_RESPONSE_OK;
      break;
    }
  
  return res;
}

int
main (int argc, char *argv[])
{
  UniqueApp *app;

  gtk_init (&argc, &argv);

  /* as soon as we create the UniqueApp instance we either have the name
   * we requested ("org.mydomain.MyApplication", in the example) or we
   * don't because there already is an application using the same name
   */
  app = unique_app_new_with_commands ("org.mydomain.MyApplication", NULL,
                                      "foo", COMMAND_FOO,
                                      "bar", COMMAND_BAR,
                                      NULL);

  /* if there already is an instance running, this will return TRUE; there
   * is no race condition because the check is already performed at
   * construction time
   */
  if (unique_app_is_running (app))
    {
      gint command;            /* the command we want to send */
      UniqueResponse response; /* the response to our command */

      command = parse_command_line (&argc, &argv);
      if (command == UNIQUE_ACTIVATE)
        response = unique_app_send_message (app, command, NULL);
      else
        {
          UniqueMessageData *message; /* the payload for the command */

          /* here, populate_message() will create the message data using
           * the command line arguments. for instance, if we want to send
           * a list of URIs we can use unique_message_data_set_uris() to
           * correctly populate the UniqueMessageData structure with the
           * URI list.
          message = populate_message (&argc, &argv);

          /* send_message() will block until we get our response back */
          response = unique_app_send_message (app, command, message);

          /* the message is copied, so we need to free it before returning */
          unique_message_data_free (message);
        }

      /* we don't need the application instance anymore */
      g_object_unref (app);

      if (response == UNIQUE_RESPONSE_OK)
        return EXIT_SUCCESS;
      else
        handle_fail_or_user_cancel ();
    }
  else
    {
      /* this is the first instance, so we can proceed with the usual application
       * construction sequence
       */
      main_window = create_main_window ();

      /* the UniqueApp instance must "watch" all the top-level windows the application
       * creates, so that it can terminate the startup notification sequence for us
       */
      unique_app_watch_window (app, GTK_WINDOW (main_window));

      /* using this signal we get notifications from the newly launched instances
       * and we can reply to them; the default signal handler will just return
       * UNIQUE_RESPONSE_OK and terminate the startup notification sequence on each
       * watched window, so you can connect to the message-received signal only if
       * you want to handle the commands and responses
       */
      g_signal_connect (app, "message-received", G_CALLBACK (message_received_cb), NULL);

      gtk_main ();

      /* don't forget to unref the object when cleaning up after the application
       * execution
       */
      g_object_unref (app);
    }

  return EXIT_SUCCESS;
}

The example above shows how to correctly set up a UniqueApp instance, send commands and reply to them with the correct response ids.

LibUnique (last edited 2008-04-16 12:56:28 by EmmanueleBassi)