changeset 17709:176d0fc8bc16

Alternative dbus_uniq implementation
author Gabriel Schulhof <nix@go-nix.ca>
date Tue, 15 May 2007 20:41:36 +0000
parents 9f5c9df30287
children 601594a64190
files libpurple/core.c libpurple/core.h libpurple/dbus-server.c libpurple/dbus-server.h pidgin/gtkmain.c
diffstat 5 files changed, 112 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/core.c	Sun May 13 19:52:05 2007 +0000
+++ b/libpurple/core.c	Tue May 15 20:41:36 2007 +0000
@@ -48,7 +48,11 @@
 #include "util.h"
 
 #ifdef HAVE_DBUS
+#  define DBUS_API_SUBJECT_TO_CHANGE
+#  include <dbus/dbus.h>
+#  include "dbus-purple.h"
 #  include "dbus-server.h"
+#  include "dbus-bindings.h"
 #endif
 
 struct PurpleCore
@@ -276,6 +280,85 @@
 	return _ops;
 }
 
+#ifdef HAVE_DBUS
+static char *purple_dbus_owner_user_dir(void)
+{
+	DBusMessage *msg = NULL, *reply = NULL;
+	DBusConnection *dbus_connection = NULL;
+	DBusError dbus_error;
+	char *remote_user_dir = NULL;
+
+	if (NULL == (dbus_connection = purple_dbus_get_connection()))
+		return NULL;
+
+	if (NULL == (msg = dbus_message_new_method_call(DBUS_SERVICE_PURPLE, DBUS_PATH_PURPLE, DBUS_INTERFACE_PURPLE, "PurpleUserDir")))
+		return NULL;
+
+	dbus_error_init(&dbus_error);
+	reply = dbus_connection_send_with_reply_and_block(dbus_connection, msg, 5000, &dbus_error);
+	dbus_message_unref(msg);
+	dbus_error_free(&dbus_error);
+
+	if (NULL != reply)
+		{
+		dbus_error_init(&dbus_error);
+		dbus_message_get_args(reply, &dbus_error, DBUS_TYPE_STRING, &remote_user_dir, DBUS_TYPE_INVALID);
+		if (NULL != remote_user_dir)
+			remote_user_dir = g_strdup(remote_user_dir);
+		dbus_error_free(&dbus_error);
+		dbus_message_unref(reply);
+		}
+
+	return remote_user_dir;
+}
+
+static void purple_dbus_owner_show_buddy_list(void)
+{
+	DBusError dbus_error;
+	DBusMessage *msg = NULL, *reply = NULL;
+	DBusConnection *dbus_connection = purple_dbus_get_connection();
+
+	if (NULL == dbus_connection) return;
+
+	if (NULL == (msg = dbus_message_new_method_call(DBUS_SERVICE_PURPLE, DBUS_PATH_PURPLE, DBUS_INTERFACE_PURPLE, "PurpleBlistShow")))
+		return ;
+
+	dbus_error_init(&dbus_error);
+	if (NULL != (reply = dbus_connection_send_with_reply_and_block(dbus_connection, msg, 5000, &dbus_error)))
+		dbus_message_unref(msg);
+	dbus_error_free(&dbus_error);
+}
+#endif /* HAVE_DBUS */
+
+gboolean purple_core_ensure_single_instance()
+{
+gboolean is_single_instance = TRUE;
+#ifdef HAVE_DBUS
+	if (is_single_instance) /* in the future, other mechanisms might have already set this to FALSE */
+		if (!purple_dbus_is_owner()) {
+			const char *user_dir = purple_user_dir();
+			char *dbus_owner_user_dir = purple_dbus_owner_user_dir();
+
+			if (NULL == user_dir && NULL != dbus_owner_user_dir)
+				is_single_instance = TRUE;
+			else
+			if (NULL != user_dir && NULL == dbus_owner_user_dir)
+				is_single_instance = TRUE;
+			else
+			if (NULL == user_dir && NULL == dbus_owner_user_dir)
+				is_single_instance = FALSE;
+			else
+				is_single_instance = strcmp(dbus_owner_user_dir, user_dir);
+
+			if (!is_single_instance)
+				purple_dbus_owner_show_buddy_list();
+
+			g_free(dbus_owner_user_dir);
+		}
+#endif /* HAVE_DBUS */
+	return is_single_instance;
+}
+
 static gboolean
 move_and_symlink_dir(const char *path, const char *basename, const char *old_base, const char *new_base, const char *relative)
 {
--- a/libpurple/core.h	Sun May 13 19:52:05 2007 +0000
+++ b/libpurple/core.h	Tue May 15 20:41:36 2007 +0000
@@ -121,6 +121,14 @@
  */
 gboolean purple_core_migrate(void);
 
+/**
+ * Ensures that only one instance is running.
+ *
+ * @return A boolean such that success indicates that this is the first instance,
+ *         whereas failure indicates that there is another instance running.
+ */
+gboolean purple_core_ensure_single_instance(void);
+
 #ifdef __cplusplus
 }
 #endif
--- a/libpurple/dbus-server.c	Sun May 13 19:52:05 2007 +0000
+++ b/libpurple/dbus-server.c	Tue May 15 20:41:36 2007 +0000
@@ -65,6 +65,12 @@
 static GHashTable *map_id_type;
 
 static gchar *init_error;
+static int dbus_request_name_reply = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
+
+gboolean purple_dbus_is_owner(void)
+{
+	return(DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER == dbus_request_name_reply);
+}
 
 /**
  * This function initializes the pointer-id traslation system.  It
@@ -592,6 +598,7 @@
 		return;
 	}
 
+	dbus_request_name_reply =
 	result = dbus_bus_request_name(purple_dbus_connection,
 			DBUS_SERVICE_PURPLE, 0, &error);
 
@@ -604,25 +611,6 @@
 		return;
 	}
 
-	if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
-		DBusMessage *msg = dbus_message_new_method_call(DBUS_SERVICE_PURPLE, DBUS_PATH_PURPLE, DBUS_INTERFACE_PURPLE, "PurpleBlistShow") ;
-
-		if (NULL != msg) {
-			DBusMessage *reply = NULL ;
-			DBusError dbus_error ;
-
-			dbus_error_init(&dbus_error) ;
-			reply = dbus_connection_send_with_reply_and_block(purple_dbus_connection, msg, 5000, &dbus_error) ;
-			dbus_message_unref(msg) ;
-			if (NULL != reply)
-				dbus_message_unref(reply) ;
-			dbus_error_free(&dbus_error) ;
-		}
-
-		purple_core_quit() ;
-		_exit(0) ;
-	}
-
 	dbus_connection_setup_with_g_main(purple_dbus_connection, NULL);
 
 	purple_debug_misc("dbus", "okkk\n");
--- a/libpurple/dbus-server.h	Sun May 13 19:52:05 2007 +0000
+++ b/libpurple/dbus-server.h	Tue May 15 20:41:36 2007 +0000
@@ -169,6 +169,11 @@
 void *purple_dbus_get_handle(void);
 
 /**
+ * Determines whether this instance owns the DBus service name
+ */
+gboolean purple_dbus_is_owner();
+
+/**
  * Starts Purple's D-BUS server.  It is responsible for handling DBUS
  * requests from other applications.
  */
--- a/pidgin/gtkmain.c	Sun May 13 19:52:05 2007 +0000
+++ b/pidgin/gtkmain.c	Tue May 15 20:41:36 2007 +0000
@@ -730,6 +730,15 @@
 		abort();
 	}
 
+	if (!purple_core_ensure_single_instance ())
+		{
+#ifdef HAVE_SIGNAL_H
+		g_free(segfault_message);
+#endif
+		return 0 ;
+		}
+		
+
 	/* TODO: Move blist loading into purple_blist_init() */
 	purple_set_blist(purple_blist_new());
 	purple_blist_load();