Implement single instance support with Unique

This commit is contained in:
Christian Dywan 2008-08-22 03:59:07 +02:00
parent 65cbe4b05a
commit c375f862a0
7 changed files with 229 additions and 7 deletions

View file

@ -38,6 +38,11 @@ if test x"$enable_debug" = x"yes"; then
]) ])
fi 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 # Checks for GIO2
PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.16, have_gio=true, have_gio=false) PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.16, have_gio=true, have_gio=false)
AC_SUBST(GIO_CFLAGS) AC_SUBST(GIO_CFLAGS)

View file

@ -1,4 +1,5 @@
INCLUDES = \ INCLUDES = \
$(UNIQUE_CFLAGS) \
$(GIO_CFLAGS) \ $(GIO_CFLAGS) \
$(GTK_CFLAGS) \ $(GTK_CFLAGS) \
$(GTKSOURCEVIEW_CFLAGS) \ $(GTKSOURCEVIEW_CFLAGS) \
@ -8,6 +9,7 @@ INCLUDES = \
AM_CFLAGS = -DMIDORI_LOCALEDIR=\""$(localedir)"\" AM_CFLAGS = -DMIDORI_LOCALEDIR=\""$(localedir)"\"
LDADD = \ LDADD = \
$(UNIQUE_LIBS) \
$(GIO_LIBS) \ $(GIO_LIBS) \
$(GTK_LIBS) \ $(GTK_LIBS) \
$(GTKSOURCEVIEW_LIBS)\ $(GTKSOURCEVIEW_LIBS)\

View file

@ -384,6 +384,8 @@ main (int argc,
char** argv) char** argv)
{ {
gboolean version; gboolean version;
MidoriApp* app;
gboolean result;
GError* error; GError* error;
GOptionEntry entries[] = GOptionEntry entries[] =
{ {
@ -446,6 +448,23 @@ main (int argc,
return 1; 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 */ /* Load configuration files */
GString* error_messages = g_string_new (NULL); GString* error_messages = g_string_new (NULL);
gchar* config_path = g_build_filename (g_get_user_config_dir (), 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_signal_connect_after (trash, "add-item",
G_CALLBACK (midori_web_list_add_item_cb), NULL); G_CALLBACK (midori_web_list_add_item_cb), NULL);
MidoriApp* app = g_object_new (MIDORI_TYPE_APP, g_object_set (app, "settings", settings,
"settings", settings, "trash", trash,
"trash", trash, "search-engines", search_engines,
"search-engines", search_engines, NULL);
NULL);
MidoriBrowser* browser = g_object_new (MIDORI_TYPE_BROWSER, MidoriBrowser* browser = g_object_new (MIDORI_TYPE_BROWSER,
"settings", settings, "settings", settings,

View file

@ -9,11 +9,20 @@
See the file COPYING for the full license text. See the file COPYING for the full license text.
*/ */
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include "midori-app.h" #include "midori-app.h"
#include <string.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <glib/gi18n.h> #include <glib/gi18n.h>
#ifdef HAVE_UNIQUE
#include <unique/unique.h>
#endif
struct _MidoriApp struct _MidoriApp
{ {
GObject parent_instance; GObject parent_instance;
@ -25,6 +34,8 @@ struct _MidoriApp
MidoriWebSettings* settings; MidoriWebSettings* settings;
MidoriWebList* trash; MidoriWebList* trash;
MidoriWebList* search_engines; MidoriWebList* search_engines;
gpointer instance;
}; };
G_DEFINE_TYPE (MidoriApp, midori_app, G_TYPE_OBJECT) G_DEFINE_TYPE (MidoriApp, midori_app, G_TYPE_OBJECT)
@ -163,9 +174,63 @@ midori_app_constructor (GType type,
type, n_construct_properties, construct_properties); 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 static void
midori_app_init (MidoriApp* app) midori_app_init (MidoriApp* app)
{ {
#ifdef HAVE_UNIQUE
gchar* display_name;
gchar* instance_name;
guint i, n;
#endif
g_assert (!_midori_app_singleton); g_assert (!_midori_app_singleton);
_midori_app_singleton = app; _midori_app_singleton = app;
@ -175,6 +240,22 @@ midori_app_init (MidoriApp* app)
app->settings = midori_web_settings_new (); app->settings = midori_web_settings_new ();
app->trash = midori_web_list_new (); app->trash = midori_web_list_new ();
app->search_engines = 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 static void
@ -188,6 +269,9 @@ midori_app_finalize (GObject* object)
g_object_unref (app->settings); g_object_unref (app->settings);
g_object_unref (app->trash); g_object_unref (app->trash);
if (app->instance)
g_object_unref (app->instance);
G_OBJECT_CLASS (midori_app_parent_class)->finalize (object); G_OBJECT_CLASS (midori_app_parent_class)->finalize (object);
} }
@ -321,8 +405,99 @@ midori_app_new (void)
return app; 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: * midori_app_add_browser:
* @app: a #MidoriApp
* @browser: a #MidoriBrowser
* *
* Adds a #MidoriBrowser to the #MidoriApp singleton. * Adds a #MidoriBrowser to the #MidoriApp singleton.
* *
@ -336,6 +511,9 @@ void
midori_app_add_browser (MidoriApp* app, midori_app_add_browser (MidoriApp* app,
MidoriBrowser* browser) 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); gtk_window_add_accel_group (GTK_WINDOW (browser), app->accel_group);
g_object_connect (browser, g_object_connect (browser,
"signal::focus-in-event", midori_browser_focus_in_event_cb, app, "signal::focus-in-event", midori_browser_focus_in_event_cb, app,
@ -346,6 +524,11 @@ midori_app_add_browser (MidoriApp* app,
NULL); NULL);
app->browsers = g_list_prepend (app->browsers, browser); app->browsers = g_list_prepend (app->browsers, browser);
#ifdef HAVE_UNIQUE
if (app->instance)
unique_app_watch_window (app->instance, GTK_WINDOW (browser));
#endif
} }
/** /**

View file

@ -53,6 +53,16 @@ midori_app_get_type (void);
MidoriApp* MidoriApp*
midori_app_new (void); 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 void
midori_app_add_browser (MidoriApp* app, midori_app_add_browser (MidoriApp* app,
MidoriBrowser* browser); MidoriBrowser* browser);

View file

@ -5,5 +5,5 @@ obj = bld.create_obj ('cc', 'program')
obj.target = 'midori' obj.target = 'midori'
obj.includes = '.. ../katze' obj.includes = '.. ../katze'
obj.find_sources_in_dirs ('.') obj.find_sources_in_dirs ('.')
obj.uselib = 'GIO GTK GTKSOURCEVIEW WEBKIT LIBXML' obj.uselib = 'UNIQUE GIO GTK GTKSOURCEVIEW WEBKIT LIBXML'
obj.uselib_local = 'katze' obj.uselib_local = 'katze'

View file

@ -35,6 +35,10 @@ def configure (conf):
nls = 'no' nls = 'no'
conf.check_message_custom ('localization', 'support', nls) 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 ('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 ('gtk+-2.0', destvar='GTK', vnum='2.6.0', mandatory=True)
conf.check_pkg ('gtksourceview-2.0', destvar='GTKSOURCEVIEW', vnum='2.0', mandatory=False) 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_VERSION', VERSION)
conf.define ('PACKAGE_NAME', APPNAME) 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.define ('GETTEXT_PACKAGE', APPNAME)
conf.write_config_header ('config.h') conf.write_config_header ('config.h')