From 01066039529c0181f231325476bb4823c16a2aea Mon Sep 17 00:00:00 2001 From: Christian Persch Date: Sat, 15 May 2010 17:47:45 +0000 Subject: Add GDBus backend Add backend using GDBus, the new D-BUS binding in GIO 2.25. Bug #618723. --- diff --git a/configure.ac b/configure.ac index bc3163a..b6a4221 100644 --- a/configure.ac +++ b/configure.ac @@ -116,6 +116,19 @@ AS_IF([test "x$have_dbus" = "xyes"], AM_CONDITIONAL([HAVE_DBUS], [test "x$have_dbus" = "xyes"]) +dnl GDBus backend +dnl This is the default backend if GIO is recent enough +m4_define([gdbus_gio_required],[2.25.7]) +PKG_CHECK_MODULES([GDBUS],[gio-2.0 >= gdbus_gio_required],[have_gdbus=yes],[have_gdbus=no]) + +AS_IF([test "x$have_gdbus" = "xyes"], + [ + AC_DEFINE([HAVE_GDBUS],[1],[Define if GDBus backend is enabled]) + ] + ) + +AM_CONDITIONAL([HAVE_GDBUS],[test "$have_gdbus" = "yes"]) + dnl Bacon backend dnl This is the fallback backend, so we *need* these headers and functions dnl even if we end up using D-Bus @@ -146,7 +159,13 @@ AM_CONDITIONAL([HAVE_BACON], [test "x$have_bacon" = "xyes"]) dnl Choose the default backend AC_MSG_CHECKING([for default IPC mechanism]) -AS_IF([test "x$have_dbus" = "xyes"], +AS_IF([test "x$have_gdbus" = "xyes"], + [ + UNIQUE_DEFAULT_BACKEND=gdbus + AC_MSG_RESULT([GDBus]) + ], + + [test "x$have_dbus" = "xyes"], [ UNIQUE_DEFAULT_BACKEND=dbus AC_MSG_RESULT([D-Bus]) @@ -243,6 +262,7 @@ AC_CONFIG_FILES([ unique/uniqueversion.h unique/bacon/Makefile unique/dbus/Makefile + unique/gdbus/Makefile tests/Makefile po/Makefile.in ]) @@ -261,6 +281,7 @@ Configuration: Backends: Unix Domain Socket: $have_bacon D-BUS: $have_dbus + GDBus: $have_gdbus Default backend: $UNIQUE_DEFAULT_BACKEND " diff --git a/doc/reference/Makefile.am b/doc/reference/Makefile.am index 3172588..2c1dbf4 100644 --- a/doc/reference/Makefile.am +++ b/doc/reference/Makefile.am @@ -50,7 +50,8 @@ IGNORE_HFILES = \ uniquemarshal.h \ stamp-uniquemarshal.h \ bacon \ - dbus + dbus \ + gdbus EXTRA_HFILES = diff --git a/unique/Makefile.am b/unique/Makefile.am index 6475a87..8f0b7ba 100644 --- a/unique/Makefile.am +++ b/unique/Makefile.am @@ -12,7 +12,11 @@ if HAVE_DBUS SUBDIRS += dbus endif -DIST_SUBDIRS = bacon dbus +if HAVE_GDBUS +SUBDIRS += gdbus +endif + +DIST_SUBDIRS = bacon dbus gdbus INCLUDES = -I$(top_srcdir) @@ -72,6 +76,10 @@ if HAVE_DBUS unique_backend_libs += $(top_builddir)/unique/dbus/libunique-dbus.la endif +if HAVE_GDBUS +unique_backend_libs += $(top_builddir)/unique/gdbus/libunique-gdbus.la +endif + uniquedir = $(includedir)/unique-1.0/unique unique_HEADERS = \ $(unique_sources_h) \ diff --git a/unique/gdbus/.gitignore b/unique/gdbus/.gitignore new file mode 100644 index 0000000..c7e22c3 --- /dev/null +++ b/unique/gdbus/.gitignore @@ -0,0 +1,2 @@ +libunique_gdbus_la-uniquebackend-gdbus.lo +libunique-gdbus.la diff --git a/unique/gdbus/Makefile.am b/unique/gdbus/Makefile.am new file mode 100644 index 0000000..e10637d --- /dev/null +++ b/unique/gdbus/Makefile.am @@ -0,0 +1,24 @@ +include $(top_srcdir)/build/autotools/Makefile.am.silent + +noinst_LTLIBRARIES = libunique-gdbus.la + +libunique_gdbus_la_SOURCES = \ + uniquebackend-gdbus.h \ + uniquebackend-gdbus.c + +libunique_gdbus_la_PPCFLAGS = \ + -DG_LOG_DOMAIN=\"Unique-GDBus\" \ + -DG_DISABLE_SINGLE_INCLUDES \ + -I$(top_srcdir) \ + $(AM_CPPFLAGS) + +libunique_gdbus_la_CFLAGS = \ + $(UNIQUE_CFLAGS) \ + $(UNIQUE_DEBUG_CFLAGS) \ + $(MAINTAINER_CFLAGS) \ + $(GDBUS_CFLAGS) \ + $(AM_CFLAGS) + +libunique_gdbus_la_LIBADD = \ + $(UNIQUE_LIBS) \ + $(GDBUS_LIBS) diff --git a/unique/gdbus/uniquebackend-gdbus.c b/unique/gdbus/uniquebackend-gdbus.c new file mode 100644 index 0000000..14d54a9 --- /dev/null +++ b/unique/gdbus/uniquebackend-gdbus.c @@ -0,0 +1,303 @@ +/* Unique - Single Instance application library + * uniquebackend-gdbus.c: GDBus implementation of UniqueBackend + * + * Copyright (C) 2007 Emmanuele Bassi + * Copyright © 2010 Christian Persch + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "../uniqueinternals.h" +#include "uniquebackend-gdbus.h" + +struct _UniqueBackendGDBus +{ + UniqueBackend parent_instance; + + GDBusConnection *connection; + guint registration_id; + guint owner_id; + gboolean owns_name; + GMainLoop *loop; +}; + +struct _UniqueBackendGDBusClass +{ + UniqueBackendClass parent_class; + GDBusNodeInfo *introspection_data; +}; + +G_DEFINE_TYPE (UniqueBackendGDBus, unique_backend_gdbus, UNIQUE_TYPE_BACKEND); + +static const char introspection_xml[] = + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + +static void +method_call_cb (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + if (g_strcmp0 (interface_name, "org.gtk.UniqueApp") != 0 || + g_strcmp0 (object_path, "/Factory") != 0) + return; + + if (g_strcmp0 (method_name, "SendMessage") == 0) + { + UniqueBackend *backend = UNIQUE_BACKEND (user_data); + const gchar *command_str, *data, *startup_id; + guint len, screen_num, workspace, time_; + UniqueMessageData message_data; + gint command; + UniqueResponse response; + GdkDisplay *display; + + g_variant_get (parameters, + "(&s(&suuu&s)u)", + &command_str, + &data, &len, &screen_num, &workspace, &startup_id, + &time_); + + command = unique_command_from_string (backend->parent, command_str); + if (command == 0) + { + g_dbus_method_invocation_return_error (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Invalid command `%s' received", + command_str); + return; + } + + display = gdk_display_get_default (); + + message_data.data = len > 0 ? (guchar *) data : NULL; + message_data.length = (gint) len; + message_data.workspace = workspace; + message_data.startup_id = (char *) startup_id; + if (screen_num >= 0 && screen_num < gdk_display_get_n_screens (display)) + message_data.screen = gdk_display_get_screen (display, screen_num); + else + message_data.screen = gdk_screen_get_default (); + + response = unique_app_emit_message_received (backend->parent, command, &message_data, time_); + + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("(s)", unique_response_to_string (response))); + return; + } +} + +static void +name_acquired_cb (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + UniqueBackendGDBus *backend_gdbus = UNIQUE_BACKEND_GDBUS (user_data); + + backend_gdbus->owns_name = TRUE; + if (backend_gdbus->loop && g_main_loop_is_running (backend_gdbus->loop)) + g_main_loop_quit (backend_gdbus->loop); +} + +static void +name_lost_cb (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + UniqueBackendGDBus *backend_gdbus = UNIQUE_BACKEND_GDBUS (user_data); + + backend_gdbus->owns_name = FALSE; + if (backend_gdbus->loop && g_main_loop_is_running (backend_gdbus->loop)) + g_main_loop_quit (backend_gdbus->loop); +} + +static const GDBusInterfaceVTable interface_vtable = { + method_call_cb, + NULL, + NULL +}; + +static gboolean +unique_backend_gdbus_request_name (UniqueBackend *backend) +{ + UniqueBackendGDBus *backend_gdbus = UNIQUE_BACKEND_GDBUS (backend); + UniqueBackendGDBusClass *klass = UNIQUE_BACKEND_GDBUS_GET_CLASS (backend); + GError *error; + + error = NULL; + backend_gdbus->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); + if (!backend_gdbus->connection) + { + g_warning ("Unable to open a connection to the session bus: %s", + error->message); + g_error_free (error); + + return FALSE; + } + + backend_gdbus->registration_id = + g_dbus_connection_register_object (backend_gdbus->connection, + "/Factory", + klass->introspection_data->interfaces[0], + &interface_vtable, + backend, NULL, + &error); + if (backend_gdbus->registration_id == 0) + { + g_warning ("Unable to register object with the session bus: %s", + error->message); + g_error_free (error); + + return FALSE; + } + + backend_gdbus->owns_name = FALSE; + + backend_gdbus->owner_id = + g_bus_own_name_on_connection (backend_gdbus->connection, + unique_backend_get_name (backend), + G_BUS_NAME_OWNER_FLAGS_NONE, + name_acquired_cb, + name_lost_cb, + backend, NULL); + + backend_gdbus->loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (backend_gdbus->loop); + g_main_loop_unref (backend_gdbus->loop); + backend_gdbus->loop = NULL; + + return backend_gdbus->owns_name; +} + +static UniqueResponse +unique_backend_gdbus_send_message (UniqueBackend *backend, + gint command, + UniqueMessageData *message_data, + guint time_) +{ + UniqueBackendGDBus *backend_gdbus = UNIQUE_BACKEND_GDBUS (backend); + GVariantBuilder builder; + GVariant *result; + const gchar *command_str, *resp; + UniqueResponse response; + GError *error; + + command_str = unique_command_to_string (backend->parent, command); + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("(s(suuus)u)")); + g_variant_builder_add (&builder, "s", command_str ? command_str : ""); + g_variant_builder_open (&builder, G_VARIANT_TYPE ("(suuus)")); + g_variant_builder_add (&builder, "s", message_data->data ? (char *) message_data->data : ""); + g_variant_builder_add (&builder, "u", (guint) message_data->length); + g_variant_builder_add (&builder, "u", (guint) gdk_screen_get_number (message_data->screen)); + g_variant_builder_add (&builder, "u", (guint) message_data->workspace); + g_variant_builder_add (&builder, "s", message_data->startup_id ? message_data->startup_id : ""); + g_variant_builder_close (&builder); + g_variant_builder_add (&builder, "u", time_); + + error = NULL; + result = g_dbus_connection_call_sync (backend_gdbus->connection, + unique_backend_get_name (backend), + "/Factory", + "org.gtk.UniqueApp", + "SendMessage", + g_variant_builder_end (&builder), + G_VARIANT_TYPE ("(s)"), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, + NULL, + &error); + if (error) + { + g_warning ("Error while sending message: %s", error->message); + g_error_free (error); + + return UNIQUE_RESPONSE_INVALID; + } + + g_variant_get (result, "(&s)", &resp); + response = unique_response_from_string (resp); + g_variant_unref (result); + + return response; +} + +static void +unique_backend_gdbus_dispose (GObject *gobject) +{ + UniqueBackendGDBus *backend_gdbus = UNIQUE_BACKEND_GDBUS (gobject); + + if (backend_gdbus->owner_id != 0) + { + g_bus_unown_name (backend_gdbus->owner_id); + backend_gdbus->owner_id = 0; + } + if (backend_gdbus->registration_id != 0) + { + g_assert (backend_gdbus->connection != NULL); + g_dbus_connection_unregister_object (backend_gdbus->connection, + backend_gdbus->registration_id); + backend_gdbus->registration_id = 0; + } + if (backend_gdbus->connection) + { + g_object_unref (backend_gdbus->connection); + backend_gdbus->connection = NULL; + } + + G_OBJECT_CLASS (unique_backend_gdbus_parent_class)->dispose (gobject); +} + +static void +unique_backend_gdbus_class_init (UniqueBackendGDBusClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + UniqueBackendClass *backend_class = UNIQUE_BACKEND_CLASS (klass); + + gobject_class->dispose = unique_backend_gdbus_dispose; + + backend_class->request_name = unique_backend_gdbus_request_name; + backend_class->send_message = unique_backend_gdbus_send_message; + + klass->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); + g_assert (klass->introspection_data != NULL); +} + +static void +unique_backend_gdbus_init (UniqueBackendGDBus *backend) +{ +} diff --git a/unique/gdbus/uniquebackend-gdbus.h b/unique/gdbus/uniquebackend-gdbus.h new file mode 100644 index 0000000..41eb6e5 --- /dev/null +++ b/unique/gdbus/uniquebackend-gdbus.h @@ -0,0 +1,43 @@ +/* Unique - Single Instance application library + * uniquebackend-gdbus.c: GDBus implementation of UniqueBackend + * + * Copyright (C) 2007 Emmanuele Bassi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef __UNIQUE_BACKEND_GDBUS_H__ +#define __UNIQUE_BACKEND_GDBUS_H__ + +#include + +G_BEGIN_DECLS + +#define UNIQUE_TYPE_BACKEND_GDBUS (unique_backend_gdbus_get_type ()) +#define UNIQUE_BACKEND_GDBUS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNIQUE_TYPE_BACKEND_GDBUS, UniqueBackendGDBus)) +#define UNIQUE_IS_BACKEND_GDBUS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNIQUE_TYPE_BACKEND_GDBUS)) +#define UNIQUE_BACKEND_GDBUS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNIQUE_TYPE_BACKEND_GDBUS, UniqueBackendGDBusClass)) +#define UNIQUE_IS_BACKEND_GDBUS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNIQUE_TYPE_BACKEND_GDBUS)) +#define UNIQUE_BACKEND_GDBUS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNIQUE_TYPE_BACKEND_GDBUS, UniqueBackendGDBusClass)) + +typedef struct _UniqueBackendGDBus UniqueBackendGDBus; +typedef struct _UniqueBackendGDBusClass UniqueBackendGDBusClass; + +GType unique_backend_gdbus_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* __UNIQUE_BACKEND_GDBUS_H__ */ diff --git a/unique/uniquebackend.c b/unique/uniquebackend.c index 18a0c45..a76e42e 100644 --- a/unique/uniquebackend.c +++ b/unique/uniquebackend.c @@ -298,6 +298,9 @@ unique_backend_send_message (UniqueBackend *backend, #ifdef HAVE_DBUS #include "dbus/uniquebackend-dbus.h" #endif +#ifdef HAVE_GDBUS +#include "gdbus/uniquebackend-gdbus.h" +#endif /** * unique_backend_create: @@ -329,6 +332,10 @@ unique_backend_create (void) if (strcmp (backend_name, "dbus") == 0) backend_gtype = unique_backend_dbus_get_type (); #endif /* HAVE_DBUS */ +#ifdef HAVE_GDBUS + if (strcmp (backend_name, "gdbus") == 0) + backend_gtype = unique_backend_gdbus_get_type (); +#endif /* HAVE_GDBUS */ #if !defined(HAVE_BACON) && !defined(HAVE_DBUS) #error Need either bacon or dbus #endif -- cgit v0.8.3.1