]> spindle.queued.net Git - midori/commitdiff
Implement single instance support with Unique
authorChristian Dywan <christian@twotoasts.de>
Fri, 22 Aug 2008 01:59:07 +0000 (03:59 +0200)
committerChristian Dywan <christian@twotoasts.de>
Fri, 22 Aug 2008 01:59:07 +0000 (03:59 +0200)
configure.in
midori/Makefile.am
midori/main.c
midori/midori-app.c
midori/midori-app.h
midori/wscript_build
wscript

index ed99b8adfebc0ed00b724544dda4fc9207bf19fa..702d8812c8c188094e0095f6d3d7a1c7e83b5586 100644 (file)
@@ -38,6 +38,11 @@ if test x"$enable_debug" = x"yes"; then
   ])
 fi
 
+# Checks for UNIQUE
+PKG_CHECK_MODULES(UNIQUE, unique-1.0 >= 0.9, have_unique=true, have_unique=false)
+AC_SUBST(UNIQUE_CFLAGS)
+AC_SUBST(UNIQUE_LIBS)
+
 # Checks for GIO2
 PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.16, have_gio=true, have_gio=false)
 AC_SUBST(GIO_CFLAGS)
index 99ed5170311cd311f5b35ed1b299660593a5c76f..73229a721f83ae9ab4cba2377cadb4aaf9583487 100644 (file)
@@ -1,4 +1,5 @@
 INCLUDES = \
+    $(UNIQUE_CFLAGS)        \
     $(GIO_CFLAGS)           \
     $(GTK_CFLAGS)           \
     $(GTKSOURCEVIEW_CFLAGS) \
@@ -8,6 +9,7 @@ INCLUDES = \
 AM_CFLAGS = -DMIDORI_LOCALEDIR=\""$(localedir)"\"
 
 LDADD = \
+    $(UNIQUE_LIBS)       \
     $(GIO_LIBS)          \
     $(GTK_LIBS)          \
     $(GTKSOURCEVIEW_LIBS)\
index 863ccee6eefaf99a843958335765573741bbe185..a1651468a7ca6a9867bef3aeabe062e97432ca7c 100644 (file)
@@ -384,6 +384,8 @@ main (int argc,
       char** argv)
 {
     gboolean version;
+    MidoriApp* app;
+    gboolean result;
     GError* error;
     GOptionEntry entries[] =
     {
@@ -446,6 +448,23 @@ main (int argc,
         return 1;
     }
 
+    app = midori_app_new ();
+    if (midori_app_instance_is_running (app))
+    {
+        /* TODO: Open as many tabs as we have uris, seperated by pipes */
+        if (argc > 1)
+            result = midori_app_instance_send_uris (app, argv+1);
+        else
+            result = midori_app_instance_send_activate (app);
+
+        if (result)
+            return 0;
+
+        /* FIXME: Do we want a graphical error message? */
+        g_print (_("An instance of Midori is already running but not responding.\n"));
+        return 1;
+    }
+
     /* Load configuration files */
     GString* error_messages = g_string_new (NULL);
     gchar* config_path = g_build_filename (g_get_user_config_dir (),
@@ -590,11 +609,10 @@ main (int argc,
     g_signal_connect_after (trash, "add-item",
         G_CALLBACK (midori_web_list_add_item_cb), NULL);
 
-    MidoriApp* app = g_object_new (MIDORI_TYPE_APP,
-                                   "settings", settings,
-                                   "trash", trash,
-                                   "search-engines", search_engines,
-                                   NULL);
+    g_object_set (app, "settings", settings,
+                       "trash", trash,
+                       "search-engines", search_engines,
+                       NULL);
 
     MidoriBrowser* browser = g_object_new (MIDORI_TYPE_BROWSER,
                                            "settings", settings,
index 58335a2f7fbc7420dd0826d5183e8fa7f5a5dbe4..660bbe4de7efc8f7b1e4cb29a8addde2eb273029 100644 (file)
@@ -9,11 +9,20 @@
  See the file COPYING for the full license text.
 */
 
+#if HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
 #include "midori-app.h"
 
+#include <string.h>
 #include <gtk/gtk.h>
 #include <glib/gi18n.h>
 
+#ifdef HAVE_UNIQUE
+    #include <unique/unique.h>
+#endif
+
 struct _MidoriApp
 {
     GObject parent_instance;
@@ -25,6 +34,8 @@ struct _MidoriApp
     MidoriWebSettings* settings;
     MidoriWebList* trash;
     MidoriWebList* search_engines;
+
+    gpointer instance;
 };
 
 G_DEFINE_TYPE (MidoriApp, midori_app, G_TYPE_OBJECT)
@@ -163,9 +174,63 @@ midori_app_constructor (GType                  type,
             type, n_construct_properties, construct_properties);
 }
 
+#ifdef HAVE_UNIQUE
+static UniqueResponse
+midori_browser_message_received_cb (UniqueApp*         instance,
+                                    UniqueCommand      command,
+                                    UniqueMessageData* message,
+                                    guint              time,
+                                    MidoriApp*         app)
+{
+  UniqueResponse response;
+  gchar** uris;
+
+  switch (command)
+  {
+  case UNIQUE_ACTIVATE:
+      g_print("activate\n");
+      gtk_window_set_screen (GTK_WINDOW (app->browser),
+                             unique_message_data_get_screen (message));
+      gtk_window_present (GTK_WINDOW (app->browser));
+      response = UNIQUE_RESPONSE_OK;
+      break;
+  case UNIQUE_OPEN:
+      g_print("open\n");
+      uris = unique_message_data_get_uris (message);
+      if (!uris)
+          response = UNIQUE_RESPONSE_FAIL;
+      else
+      {
+          g_print("open uris\n");
+          while (*uris)
+          {
+              midori_browser_add_uri (app->browser, *uris);
+              g_print ("uri: %s\n", *uris);
+              uris++;
+          }
+          /* g_strfreev (uris); */
+          response = UNIQUE_RESPONSE_OK;
+      }
+      break;
+  default:
+      g_print("fail\n");
+      response = UNIQUE_RESPONSE_FAIL;
+      break;
+  }
+
+  return response;
+}
+#endif
+
 static void
 midori_app_init (MidoriApp* app)
 {
+    #ifdef HAVE_UNIQUE
+    gchar* display_name;
+    gchar* instance_name;
+    guint i, n;
+    #endif
+
     g_assert (!_midori_app_singleton);
 
     _midori_app_singleton = app;
@@ -175,6 +240,22 @@ midori_app_init (MidoriApp* app)
     app->settings = midori_web_settings_new ();
     app->trash = midori_web_list_new ();
     app->search_engines = midori_web_list_new ();
+
+    #ifdef HAVE_UNIQUE
+    display_name = g_strdup (gdk_display_get_name (gdk_display_get_default ()));
+    n = strlen (display_name);
+    for (i = 0; i < n; i++)
+        if (display_name[i] == ':' || display_name[i] == '.')
+            display_name[i] = '_';
+    instance_name = g_strdup_printf ("de.twotoasts.midori_%s", display_name);
+    app->instance = unique_app_new (instance_name, NULL);
+    g_free (instance_name);
+    g_free (display_name);
+    g_signal_connect (app->instance, "message-received",
+                      G_CALLBACK (midori_browser_message_received_cb), app);
+    #else
+    app->instance = NULL;
+    #endif
 }
 
 static void
@@ -188,6 +269,9 @@ midori_app_finalize (GObject* object)
     g_object_unref (app->settings);
     g_object_unref (app->trash);
 
+    if (app->instance)
+        g_object_unref (app->instance);
+
     G_OBJECT_CLASS (midori_app_parent_class)->finalize (object);
 }
 
@@ -321,8 +405,99 @@ midori_app_new (void)
     return app;
 }
 
+/**
+ * midori_app_instance_is_running:
+ * @app: a #MidoriApp
+ *
+ * Determines whether an instance of Midori is
+ * already running on the default display.
+ *
+ * If Midori was built without single instance support
+ * this function will always return %FALSE.
+ *
+ * Return value: %TRUE if an instance is already running
+ **/
+gboolean
+midori_app_instance_is_running (MidoriApp* app)
+{
+    g_return_val_if_fail (MIDORI_IS_APP (app), FALSE);
+
+    #ifdef HAVE_UNIQUE
+    return unique_app_is_running (app->instance);
+    #else
+    return FALSE;
+    #endif
+}
+
+/**
+ * midori_app_instance_send_activate:
+ * @app: a #MidoriApp
+ *
+ * Sends a message to an instance of Midori already
+ * running on the default display, asking to activate it.
+ *
+ * Practically the current browser will be focussed.
+ *
+ * Return value: %TRUE if the message was sent successfully
+ **/
+gboolean
+midori_app_instance_send_activate (MidoriApp* app)
+{
+    #ifdef HAVE_UNIQUE
+    UniqueResponse response;
+    #endif
+
+    g_return_val_if_fail (MIDORI_IS_APP (app), FALSE);
+    g_return_val_if_fail (midori_app_instance_is_running (app), FALSE);
+
+    #ifdef HAVE_UNIQUE
+    response = unique_app_send_message (app->instance, UNIQUE_ACTIVATE, NULL);
+    if (response == UNIQUE_RESPONSE_OK)
+        return TRUE;
+    #endif
+    return FALSE;
+}
+
+/**
+ * midori_app_instance_send_uris:
+ * @app: a #MidoriApp
+ * @uris: a string vector of URIs
+ *
+ * Sends a message to an instance of Midori already
+ * running on the default display, asking to open @uris.
+ *
+ * The strings in @uris will each be opened in a new tab.
+ *
+ * Return value: %TRUE if the message was sent successfully
+ **/
+gboolean
+midori_app_instance_send_uris (MidoriApp* app,
+                               gchar**    uris)
+{
+    #ifdef HAVE_UNIQUE
+    UniqueMessageData* message;
+    UniqueResponse response;
+    #endif
+
+    g_return_val_if_fail (MIDORI_IS_APP (app), FALSE);
+    g_return_val_if_fail (midori_app_instance_is_running (app), FALSE);
+    g_return_val_if_fail (uris != NULL, FALSE);
+
+    #ifdef HAVE_UNIQUE
+    message = unique_message_data_new ();
+    unique_message_data_set_uris (message, uris);
+    response = unique_app_send_message (app->instance, UNIQUE_OPEN, message);
+    unique_message_data_free (message);
+    if (response == UNIQUE_RESPONSE_OK)
+        return TRUE;
+    #endif
+    return FALSE;
+}
+
 /**
  * midori_app_add_browser:
+ * @app: a #MidoriApp
+ * @browser: a #MidoriBrowser
  *
  * Adds a #MidoriBrowser to the #MidoriApp singleton.
  *
@@ -336,6 +511,9 @@ void
 midori_app_add_browser (MidoriApp*     app,
                         MidoriBrowser* browser)
 {
+    g_return_if_fail (MIDORI_IS_APP (app));
+    g_return_if_fail (MIDORI_IS_BROWSER (browser));
+
     gtk_window_add_accel_group (GTK_WINDOW (browser), app->accel_group);
     g_object_connect (browser,
         "signal::focus-in-event", midori_browser_focus_in_event_cb, app,
@@ -346,6 +524,11 @@ midori_app_add_browser (MidoriApp*     app,
         NULL);
 
     app->browsers = g_list_prepend (app->browsers, browser);
+
+    #ifdef HAVE_UNIQUE
+    if (app->instance)
+        unique_app_watch_window (app->instance, GTK_WINDOW (browser));
+    #endif
 }
 
 /**
index 6735a98c59b4638bfb469865f698acf3cc433ba7..637cb6ef9fe8b2ed61085ee5fd9a02225d5e5001 100644 (file)
@@ -53,6 +53,16 @@ midori_app_get_type               (void);
 MidoriApp*
 midori_app_new                    (void);
 
+gboolean
+midori_app_instance_is_running    (MidoriApp*         app);
+
+gboolean
+midori_app_instance_send_activate (MidoriApp*         app);
+
+gboolean
+midori_app_instance_send_uris     (MidoriApp*         app,
+                                   gchar**            uris);
+
 void
 midori_app_add_browser            (MidoriApp*         app,
                                    MidoriBrowser*     browser);
index 0963128e840871fadbfc38539b667116fc54c6d2..cc6435cf3eb9f615102bbdced6a0ca3ac8000e92 100644 (file)
@@ -5,5 +5,5 @@ obj = bld.create_obj ('cc', 'program')
 obj.target = 'midori'
 obj.includes = '.. ../katze'
 obj.find_sources_in_dirs ('.')
-obj.uselib = 'GIO GTK GTKSOURCEVIEW WEBKIT LIBXML'
+obj.uselib = 'UNIQUE GIO GTK GTKSOURCEVIEW WEBKIT LIBXML'
 obj.uselib_local = 'katze'
diff --git a/wscript b/wscript
index 52fa64f954248176217b2664adac7f3f5ac020a3..10964a59cd42e800513f345aea7bd2765525b058 100644 (file)
--- a/wscript
+++ b/wscript
@@ -35,6 +35,10 @@ def configure (conf):
         nls = 'no'
     conf.check_message_custom ('localization', 'support', nls)
 
+    conf.check_pkg ('unique-1.0', destvar='UNIQUE', vnum='0.9', mandatory=False)
+    single_instance = ['no','yes'][conf.env['HAVE_UNIQUE'] == 1]
+    conf.check_message_custom ('single instance', 'support', single_instance)
+
     conf.check_pkg ('gio-2.0', destvar='GIO', vnum='2.16.0', mandatory=False)
     conf.check_pkg ('gtk+-2.0', destvar='GTK', vnum='2.6.0', mandatory=True)
     conf.check_pkg ('gtksourceview-2.0', destvar='GTKSOURCEVIEW', vnum='2.0', mandatory=False)
@@ -51,7 +55,7 @@ def configure (conf):
 
     conf.define ('PACKAGE_VERSION', VERSION)
     conf.define ('PACKAGE_NAME', APPNAME)
-    conf.define ('PACKAGE_BUGREPORT', 'http://software.twotoasts.de/bugs')
+    conf.define ('PACKAGE_BUGREPORT', 'http://www.twotoasts.de/bugs')
     conf.define ('GETTEXT_PACKAGE', APPNAME)
 
     conf.write_config_header ('config.h')