[Goodies-commits] r6924 - in gigolo/trunk: . src

Enrico Troeger enrico at xfce.org
Mon Mar 16 22:25:59 CET 2009


Author: enrico
Date: 2009-03-16 21:25:59 +0000 (Mon, 16 Mar 2009)
New Revision: 6924

Added:
   gigolo/trunk/src/singleinstance.c
   gigolo/trunk/src/singleinstance.h
Modified:
   gigolo/trunk/ChangeLog
   gigolo/trunk/gigolo.1.in
   gigolo/trunk/src/Makefile.am
   gigolo/trunk/src/main.c
   gigolo/trunk/wscript
Log:
Detect an already running instance and show its window instead of starting a new instance.
Add command line option "--new-instance" ("-i") to restore the old behaviour.

Modified: gigolo/trunk/ChangeLog
===================================================================
--- gigolo/trunk/ChangeLog	2009-03-16 21:25:27 UTC (rev 6923)
+++ gigolo/trunk/ChangeLog	2009-03-16 21:25:59 UTC (rev 6924)
@@ -1,3 +1,13 @@
+2009-03-17  Enrico Tröger  <enrico(at)xfce(dot)org>
+
+ * gigolo.1.in, src/Makefile.am, src/main.c, src/singleinstance.c,
+   src/singleinstance.h, wscript:
+   Detect an already running instance and show its window instead of
+   starting a new instance.
+   Add command line option "--new-instance" ("-i") to restore the
+   old behaviour.
+
+
 2009-03-05  Enrico Tröger  <enrico(at)xfce(dot)org>
 
  * src/backendgvfs.c, src/backendgvfs.h, src/bookmarkeditdialog.c,

Modified: gigolo/trunk/gigolo.1.in
===================================================================
--- gigolo/trunk/gigolo.1.in	2009-03-16 21:25:27 UTC (rev 6923)
+++ gigolo/trunk/gigolo.1.in	2009-03-16 21:25:59 UTC (rev 6924)
@@ -1,6 +1,6 @@
 .TH "GIGOLO" "1" "" "gigolo @VERSION@" ""
 .SH "NAME"
-Gigolo \(em a simple frontend to easily connect to remote filesystems with GIO/GVFS
+Gigolo \(em a simple frontend to easily connect to remote filesystems with GIO/GVfs
 .SH "SYNOPSIS"
 .PP
 \fBgigolo\fR [\fBoption\fP]
@@ -13,6 +13,9 @@
 Homepage: http://www.uvena.de/gigolo/
 .SH "OPTIONS"
 If called without any arguments, the Gigolo main window is shown.
+.IP "\fB-i\fP, \fB\-\-new-instance\fP         " 10
+Don't find and show an already running instance of Gigolo, instead
+force opening a new instance.
 .IP "\fB-l\fP, \fB\-\-list-schemes\fP         " 10
 Print a list of supported URI schemes and exit.
 .IP "\fB-v\fP, \fB\-\-verbose\fP         " 10

Modified: gigolo/trunk/src/Makefile.am
===================================================================
--- gigolo/trunk/src/Makefile.am	2009-03-16 21:25:27 UTC (rev 6923)
+++ gigolo/trunk/src/Makefile.am	2009-03-16 21:25:59 UTC (rev 6924)
@@ -15,6 +15,7 @@
 	bookmarkdialog.c bookmarkdialog.h			\
 	bookmarkeditdialog.c bookmarkeditdialog.h	\
 	browsenetworkdialog.c browsenetworkdialog.h	\
+	singleinstance.c singleinstance.h			\
 	preferencesdialog.c preferencesdialog.h
 
 

Modified: gigolo/trunk/src/main.c
===================================================================
--- gigolo/trunk/src/main.c	2009-03-16 21:25:27 UTC (rev 6923)
+++ gigolo/trunk/src/main.c	2009-03-16 21:25:59 UTC (rev 6924)
@@ -33,14 +33,17 @@
 #include "bookmark.h"
 #include "window.h"
 #include "backendgvfs.h"
+#include "singleinstance.h"
 
 
 static gboolean show_version = FALSE;
 static gboolean verbose_mode = FALSE;
 static gboolean list_schemes = FALSE;
+static gboolean new_instance = FALSE;
 
 static GOptionEntry cli_options[] =
 {
+	{ "new-instance", 'i', 0, G_OPTION_ARG_NONE, &new_instance, N_("Ignore running instances, enforce opening a new instance"), NULL },
 	{ "list-schemes", 'l', 0, G_OPTION_ARG_NONE, &list_schemes, N_("Print a list of supported URI schemes"), NULL },
 	{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose_mode, N_("Be verbose"), NULL },
 	{ "version", 'V', 0, G_OPTION_ARG_NONE, &show_version, N_("Show version information"), NULL },
@@ -89,6 +92,7 @@
 gint main(gint argc, gchar** argv)
 {
 	GigoloSettings *settings;
+	GigoloSingleInstance *gis = NULL;
 	const gchar *vm_impl;
 	gchar *accel_filename;
 	GOptionContext *context;
@@ -124,6 +128,17 @@
 		return EXIT_SUCCESS;
 	}
 
+	if (! new_instance)
+	{
+		gis = gigolo_single_instance_new();
+		if (gigolo_single_instance_is_running(gis))
+		{
+			gigolo_single_instance_present(gis);
+			g_object_unref(gis);
+			exit(0);
+		}
+	}
+
 	verbose("Gigolo %s (GTK+ %u.%u.%u, GLib %u.%u.%u)",
 		VERSION,
 		gtk_major_version, gtk_minor_version, gtk_micro_version,
@@ -142,6 +157,9 @@
 	window = gigolo_window_new(settings);
     g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
 
+	if (gis != NULL)
+		gigolo_single_instance_set_parent(gis, GTK_WINDOW(window));
+
 	if (gigolo_settings_get_boolean(settings, "start-in-systray"))
 		gdk_notify_startup_complete();
 	else
@@ -150,6 +168,8 @@
 	gtk_main();
 
 	g_object_unref(settings);
+	if (gis != NULL)
+		g_object_unref(gis);
 
 	gtk_accel_map_save(accel_filename);
 	g_free(accel_filename);

Added: gigolo/trunk/src/singleinstance.c
===================================================================
--- gigolo/trunk/src/singleinstance.c	                        (rev 0)
+++ gigolo/trunk/src/singleinstance.c	2009-03-16 21:25:59 UTC (rev 6924)
@@ -0,0 +1,280 @@
+/*
+ *      singleinstance.c
+ *
+ *      Copyright 2009      Enrico Tröger <enrico(at)xfce(dot)org>
+ *      Copyright 2006      Darren Salt
+ *      Copyright 2002-2006 Olivier Fourdan
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *      MA 02110-1301, USA.
+ */
+
+
+/*
+ * This is very simple detection of an already running by using XSelections.
+ */
+
+#include "config.h"
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <X11/Xlib.h>
+
+#include "singleinstance.h"
+#include "common.h"
+#include "compat.h"
+#include "main.h"
+
+
+#define GIGOLO_SI_NAME "GIGOLO_SEL"
+#define GIGOLO_SI_CMD "gigolo_show_window"
+
+
+enum
+{
+	PROP_0,
+
+	PROP_PARENT
+};
+
+
+struct _GigoloSingleInstance
+{
+	GObject parent;
+};
+
+struct _GigoloSingleInstanceClass
+{
+	GObjectClass parent_class;
+};
+
+typedef struct _GigoloSingleInstancePrivate			GigoloSingleInstancePrivate;
+
+#define GIGOLO_SINGLE_INSTANCE_GET_PRIVATE(obj)		(G_TYPE_INSTANCE_GET_PRIVATE((obj),\
+			GIGOLO_SINGLE_INSTANCE_TYPE, GigoloSingleInstancePrivate))
+
+
+struct _GigoloSingleInstancePrivate
+{
+	gboolean	 found_instance;
+	Window		 id;
+	GtkWidget	*window;
+
+	GtkWindow	*parent;
+};
+
+static void gigolo_single_instance_finalize  			(GObject *object);
+
+
+G_DEFINE_TYPE(GigoloSingleInstance, gigolo_single_instance, G_TYPE_OBJECT);
+
+
+void gigolo_single_instance_set_parent(GigoloSingleInstance *gis, GtkWindow *parent)
+{
+	GigoloSingleInstancePrivate *priv;
+
+	g_return_if_fail(gis != NULL);
+	g_return_if_fail(parent != NULL);
+
+	priv = GIGOLO_SINGLE_INSTANCE_GET_PRIVATE(gis);
+	priv->parent = parent;
+}
+
+
+static void gigolo_single_instance_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+	switch (prop_id)
+	{
+	case PROP_PARENT:
+		gigolo_single_instance_set_parent(GIGOLO_SINGLE_INSTANCE(object), g_value_get_object(value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+		break;
+	}
+}
+
+
+static void gigolo_single_instance_class_init(GigoloSingleInstanceClass *klass)
+{
+	GObjectClass *g_object_class;
+
+	g_object_class = G_OBJECT_CLASS(klass);
+	g_object_class->finalize = gigolo_single_instance_finalize;
+	g_object_class->set_property = gigolo_single_instance_set_property;
+
+	g_type_class_add_private(klass, sizeof(GigoloSingleInstancePrivate));
+
+	g_object_class_install_property(g_object_class,
+									PROP_PARENT,
+									g_param_spec_object(
+									"parent",
+									"Parent",
+									"The Gigolo main window which gets popped up by the remote instance.",
+									GTK_TYPE_WINDOW,
+									G_PARAM_WRITABLE));
+}
+
+
+static void gigolo_single_instance_finalize(GObject *object)
+{
+	GigoloSingleInstancePrivate *priv = GIGOLO_SINGLE_INSTANCE_GET_PRIVATE(object);
+
+	if (priv->window != NULL)
+		gtk_widget_destroy(priv->window);
+
+	G_OBJECT_CLASS(gigolo_single_instance_parent_class)->finalize(object);
+}
+
+
+static gboolean message_received(GtkWidget *w, GdkEventClient *ev, GigoloSingleInstance *gis)
+{
+	if (ev->data_format == 8 && gigolo_str_equal(ev->data.b, GIGOLO_SI_CMD))
+	{
+		GigoloSingleInstancePrivate *priv;
+
+		g_return_val_if_fail(gis != NULL, FALSE);
+
+		priv = GIGOLO_SINGLE_INSTANCE_GET_PRIVATE(gis);
+		gtk_window_present(priv->parent);
+
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static void setup_selection(GigoloSingleInstance *gis)
+{
+	GdkScreen *gscreen;
+	gchar      selection_name[32];
+	Atom       selection_atom;
+	GtkWidget *win;
+	Window     xwin;
+
+	win = gtk_invisible_new();
+	gtk_widget_realize(win);
+	xwin = GDK_WINDOW_XID(gigolo_widget_get_window(GTK_WIDGET(win)));
+
+	gscreen = gtk_widget_get_screen(win);
+	g_snprintf(selection_name, sizeof(selection_name),
+		GIGOLO_SI_NAME"%d", gdk_screen_get_number(gscreen));
+	selection_atom = XInternAtom(GDK_DISPLAY(), selection_name, False);
+
+	if (XGetSelectionOwner(GDK_DISPLAY(), selection_atom))
+	{
+		gtk_widget_destroy(win);
+		return;
+	}
+
+	XSelectInput(GDK_DISPLAY(), xwin, PropertyChangeMask);
+	XSetSelectionOwner(GDK_DISPLAY(), selection_atom, xwin, GDK_CURRENT_TIME);
+
+	g_signal_connect(G_OBJECT(win), "client-event", G_CALLBACK(message_received), gis);
+}
+
+
+static void gigolo_single_instance_init(GigoloSingleInstance *self)
+{
+	GigoloSingleInstancePrivate *priv = GIGOLO_SINGLE_INSTANCE_GET_PRIVATE(self);
+
+	priv->found_instance = FALSE;
+	priv->window = NULL;
+}
+
+
+gboolean gigolo_single_instance_is_running(GigoloSingleInstance *gis)
+{
+	GigoloSingleInstancePrivate *priv;
+
+	g_return_val_if_fail(gis != NULL, FALSE);
+
+	priv = GIGOLO_SINGLE_INSTANCE_GET_PRIVATE(gis);
+
+	return priv->found_instance;
+}
+
+
+static gboolean find_running_instance(GigoloSingleInstance *gis)
+{
+	GdkScreen *gscreen;
+	gchar selection_name[32];
+	Atom selection_atom;
+	GigoloSingleInstancePrivate *priv;
+
+	g_return_val_if_fail(gis != NULL, FALSE);
+
+	priv = GIGOLO_SINGLE_INSTANCE_GET_PRIVATE(gis);
+	priv->window = gtk_invisible_new();
+	gtk_widget_realize(priv->window);
+
+	gscreen = gtk_widget_get_screen(priv->window);
+	g_snprintf(selection_name, sizeof(selection_name),
+		GIGOLO_SI_NAME"%d", gdk_screen_get_number(gscreen));
+	selection_atom = XInternAtom(GDK_DISPLAY(), selection_name, False);
+
+	priv->id = XGetSelectionOwner(GDK_DISPLAY(), selection_atom);
+
+	gdk_flush();
+
+	return (priv->id != None);
+}
+
+
+void gigolo_single_instance_present(GigoloSingleInstance *gis)
+{
+	GigoloSingleInstancePrivate *priv;
+
+	g_return_if_fail(gis != NULL);
+
+	priv = GIGOLO_SINGLE_INSTANCE_GET_PRIVATE(gis);
+	if (priv->id != None && priv->found_instance)
+	{
+		GdkEventClient gev;
+
+		gev.type = GDK_CLIENT_EVENT;
+		gev.window = gigolo_widget_get_window(priv->window);
+		gev.send_event = TRUE;
+		gev.message_type = gdk_atom_intern("STRING", FALSE);
+		gev.data_format = 8;
+		g_strlcpy(gev.data.b, GIGOLO_SI_CMD, sizeof(gev.data.b));
+
+		gdk_event_send_client_message((GdkEvent*) &gev, (GdkNativeWindow) priv->id);
+	}
+}
+
+
+/* When creating a new object of this class we search an already running instance of Gigolo
+ * and in case we found one, we set the 'found_instance' member to TRUE.
+ * Otherwise, we register ourselves as new single running instance. */
+GigoloSingleInstance *gigolo_single_instance_new(void)
+{
+	GigoloSingleInstance *gis = g_object_new(GIGOLO_SINGLE_INSTANCE_TYPE, NULL);
+	GigoloSingleInstancePrivate *priv = GIGOLO_SINGLE_INSTANCE_GET_PRIVATE(gis);
+
+	if (find_running_instance(gis))
+	{
+		priv->found_instance = TRUE;
+	}
+	else
+	{
+		setup_selection(gis);
+	}
+
+	return gis;
+}
+

Added: gigolo/trunk/src/singleinstance.h
===================================================================
--- gigolo/trunk/src/singleinstance.h	                        (rev 0)
+++ gigolo/trunk/src/singleinstance.h	2009-03-16 21:25:59 UTC (rev 6924)
@@ -0,0 +1,52 @@
+/*
+ *      singleinstance.h
+ *
+ *      Copyright 2009 Enrico Tröger <enrico(at)xfce(dot)org>
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *      MA 02110-1301, USA.
+ */
+
+
+#ifndef __SINGLEINSTANCE_H__
+#define __SINGLEINSTANCE_H__
+
+G_BEGIN_DECLS
+
+#define GIGOLO_SINGLE_INSTANCE_TYPE				(gigolo_single_instance_get_type())
+#define GIGOLO_SINGLE_INSTANCE(obj)				(G_TYPE_CHECK_INSTANCE_CAST((obj),\
+			GIGOLO_SINGLE_INSTANCE_TYPE, GigoloSingleInstance))
+#define GIGOLO_SINGLE_INSTANCE_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass),\
+			GIGOLO_SINGLE_INSTANCE_TYPE, GigoloSingleInstanceClass))
+#define IS_GIGOLO_SINGLE_INSTANCE(obj)			(G_TYPE_CHECK_INSTANCE_TYPE((obj),\
+			GIGOLO_SINGLE_INSTANCE_TYPE))
+#define IS_GIGOLO_SINGLE_INSTANCE_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((klass),\
+			GIGOLO_SINGLE_INSTANCE_TYPE))
+
+typedef struct _GigoloSingleInstance			GigoloSingleInstance;
+typedef struct _GigoloSingleInstanceClass		GigoloSingleInstanceClass;
+
+GType					gigolo_single_instance_get_type		(void);
+GigoloSingleInstance*	gigolo_single_instance_new			(void);
+
+gboolean				gigolo_single_instance_is_running	(GigoloSingleInstance *gis);
+void					gigolo_single_instance_present		(GigoloSingleInstance *gis);
+
+void					gigolo_single_instance_set_parent	(GigoloSingleInstance *gis,
+															 GtkWindow *parent);
+
+G_END_DECLS
+
+#endif /* __SINGLEINSTANCE_H__ */

Modified: gigolo/trunk/wscript
===================================================================
--- gigolo/trunk/wscript	2009-03-16 21:25:27 UTC (rev 6923)
+++ gigolo/trunk/wscript	2009-03-16 21:25:59 UTC (rev 6924)
@@ -36,7 +36,8 @@
 sources = [ 'src/main.c', 'src/compat.c', 'src/window.c', 'src/bookmark.c', 'src/settings.c',
 			'src/menubuttonaction.c', 'src/mountoperation.c', 'src/bookmarkdialog.c',
 			'src/bookmarkeditdialog.c', 'src/preferencesdialog.c', 'src/backendgvfs.c',
-			'src/common.c', 'src/mountdialog.c', 'src/browsenetworkdialog.c' ]
+			'src/common.c', 'src/mountdialog.c', 'src/browsenetworkdialog.c',
+			'src/singleinstance.c' ]
 
 
 




More information about the Goodies-commits mailing list