Implement single instance support with Unique
This commit is contained in:
parent
65cbe4b05a
commit
c375f862a0
7 changed files with 229 additions and 7 deletions
|
@ -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)
|
||||||
|
|
|
@ -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)\
|
||||||
|
|
|
@ -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,8 +609,7 @@ 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);
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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'
|
||||||
|
|
6
wscript
6
wscript
|
@ -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')
|
||||||
|
|
Loading…
Reference in a new issue