diff options
Diffstat (limited to 'libindicator')
-rw-r--r-- | libindicator/Makefile.am | 26 | ||||
-rw-r--r-- | libindicator/indicator-service-manager.c | 250 | ||||
-rw-r--r-- | libindicator/indicator-service.c | 315 |
3 files changed, 313 insertions, 278 deletions
diff --git a/libindicator/Makefile.am b/libindicator/Makefile.am index a799d8c..5c70345 100644 --- a/libindicator/Makefile.am +++ b/libindicator/Makefile.am @@ -31,6 +31,8 @@ libindicatorinclude_HEADERS = \ libindicator_la_SOURCES = \ $(indicator_headers) \ dbus-shared.h \ + gen-indicator-service.xml.h \ + gen-indicator-service.xml.c \ indicator-object.c \ indicator-object-enum-types.c \ indicator-desktop-shortcuts.c \ @@ -100,23 +102,19 @@ CLEANFILES += \ DBUS_SPECS = \ indicator-service.xml -%-client.h: %.xml - dbus-binding-tool \ - --prefix=_$(subst -,_,$(basename $(notdir $<)))_client \ - --mode=glib-client \ - --output=$@ \ - $< +gen-%.xml.h: %.xml + @echo "Building $@ from $<" + @echo "extern const char * _$(subst -,_,$(subst .,_,$(basename $<)));" > $@ -%-server.h: %.xml - dbus-binding-tool \ - --prefix=_$(subst -,_,$(basename $(notdir $<)))_server \ - --mode=glib-server \ - --output=$@ \ - $< +gen-%.xml.c: %.xml + @echo "Building $@ from $<" + @echo "const char * _$(subst -,_,$(subst .,_,$(basename $<))) = " > $@ + @sed -e "s:\":\\\\\":g" -e s:^:\": -e s:\$$:\\\\n\": $< >> $@ + @echo ";" >> $@ BUILT_SOURCES += \ - $(DBUS_SPECS:.xml=-client.h) \ - $(DBUS_SPECS:.xml=-server.h) + gen-indicator-service.xml.h \ + gen-indicator-service.xml.c CLEANFILES += $(BUILT_SOURCES) diff --git a/libindicator/indicator-service-manager.c b/libindicator/indicator-service-manager.c index 20eddec..7b2cae9 100644 --- a/libindicator/indicator-service-manager.c +++ b/libindicator/indicator-service-manager.c @@ -26,33 +26,27 @@ License along with this library. If not, see #endif #include <stdlib.h> - -#include <dbus/dbus-glib-bindings.h> -#include <dbus/dbus-glib-lowlevel.h> +#include <gio/gio.h> #include "indicator-service-manager.h" -#include "indicator-service-client.h" +#include "gen-indicator-service.xml.h" #include "dbus-shared.h" /* Private Stuff */ /** IndicatorServiceManagerPrivate: @name: The well known dbus name the service should be on. - @dbus_proxy: A proxy to talk to the dbus daemon. @service_proxy: The proxy to the service itself. @connected: Whether we're connected to the service or not. @this_service_version: The version of the service that we're looking for. - @bus: A reference to the bus so we don't have to keep getting it. @restart_count: The number of times we've restarted this service. */ typedef struct _IndicatorServiceManagerPrivate IndicatorServiceManagerPrivate; struct _IndicatorServiceManagerPrivate { gchar * name; - DBusGProxy * dbus_proxy; - DBusGProxy * service_proxy; + GDBusProxy * service_proxy; gboolean connected; guint this_service_version; - DBusGConnection * bus; guint restart_count; gint restart_source; }; @@ -86,6 +80,10 @@ enum { #define PROP_NAME_S "name" #define PROP_VERSION_S "version" +/* GDBus Stuff */ +static GDBusNodeInfo * node_info = NULL; +static GDBusInterfaceInfo * interface_info = NULL; + /* GObject Stuff */ #define INDICATOR_SERVICE_MANAGER_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_SERVICE_MANAGER_TYPE, IndicatorServiceManagerPrivate)) @@ -98,9 +96,11 @@ static void indicator_service_manager_finalize (GObject *object); /* Prototypes */ static void set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static void service_proxy_destroyed (DBusGProxy * proxy, gpointer user_data); static void start_service (IndicatorServiceManager * service); static void start_service_again (IndicatorServiceManager * manager); +static void unwatch (GDBusProxy * proxy); +static void service_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data); +static void service_proxy_name_change (GObject * object, GParamSpec * pspec, gpointer user_data); G_DEFINE_TYPE (IndicatorServiceManager, indicator_service_manager, G_TYPE_OBJECT); @@ -150,6 +150,25 @@ indicator_service_manager_class_init (IndicatorServiceManagerClass *klass) 0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /* Setting up the DBus interfaces */ + if (node_info == NULL) { + GError * error = NULL; + + node_info = g_dbus_node_info_new_for_xml(_indicator_service, &error); + if (error != NULL) { + g_error("Unable to parse Indicator Service Interface description: %s", error->message); + g_error_free(error); + } + } + + if (interface_info == NULL) { + interface_info = g_dbus_node_info_lookup_interface(node_info, INDICATOR_SERVICE_INTERFACE); + + if (interface_info == NULL) { + g_error("Unable to find interface '" INDICATOR_SERVICE_INTERFACE "'"); + } + } + return; } @@ -163,34 +182,12 @@ indicator_service_manager_init (IndicatorServiceManager *self) /* Get the private variables in a decent state */ priv->name = NULL; - priv->dbus_proxy = NULL; priv->service_proxy = NULL; priv->connected = FALSE; priv->this_service_version = 0; - priv->bus = NULL; priv->restart_count = 0; priv->restart_source = 0; - /* Start talkin' dbus */ - GError * error = NULL; - priv->bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error); - if (error != NULL) { - g_error("Unable to get session bus for manager: %s", error->message); - g_error_free(error); - return; - } - - priv->dbus_proxy = dbus_g_proxy_new_for_name_owner(priv->bus, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - &error); - if (error != NULL) { - g_error("Unable to get the proxy to DBus: %s", error->message); - g_error_free(error); - return; - } - return; } @@ -217,16 +214,10 @@ indicator_service_manager_dispose (GObject *object) g_signal_emit(object, signals[CONNECTION_CHANGE], 0, FALSE, TRUE); } - /* Destory our DBus proxy, we won't need it. */ - if (priv->dbus_proxy != NULL) { - g_object_unref(G_OBJECT(priv->dbus_proxy)); - priv->dbus_proxy = NULL; - } - /* If we have a proxy, tell it we're shutting down. Just to be polite about it. */ if (priv->service_proxy != NULL) { - dbus_g_proxy_call_no_reply(priv->service_proxy, "UnWatch", G_TYPE_INVALID); + unwatch(priv->service_proxy); } /* Destory our service proxy, we won't need it. */ @@ -318,6 +309,22 @@ get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspe return; } +/* Small little function to make a long function call a little + bit cleaner. */ +static void +unwatch (GDBusProxy * proxy) +{ + g_dbus_proxy_call(proxy, + "UnWatch", + NULL, /* parameters */ + G_DBUS_CALL_FLAGS_NONE, + -1, /* timeout */ + NULL, /* cancelable */ + NULL, /* callback */ + NULL); /* user data */ + return; +} + /* A callback from telling a service that we want to watch it. It gives us the service API version and the version of the other APIs it supports. We check both of those. @@ -325,10 +332,13 @@ get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspe signal a connection change to tell the rest of the world that we have a service now. */ static void -watch_cb (DBusGProxy * proxy, guint service_api_version, guint this_service_version, GError * error, gpointer user_data) +watch_cb (GObject * object, GAsyncResult * res, gpointer user_data) { + GError * error = NULL; IndicatorServiceManagerPrivate * priv = INDICATOR_SERVICE_MANAGER_GET_PRIVATE(user_data); + GVariant * params = g_dbus_proxy_call_finish(G_DBUS_PROXY(object), res, &error); + if (error != NULL) { g_warning("Unable to set watch on '%s': '%s'", priv->name, error->message); g_error_free(error); @@ -336,6 +346,12 @@ watch_cb (DBusGProxy * proxy, guint service_api_version, guint this_service_vers return; } + guint service_api_version; + guint this_service_version; + + g_variant_get(params, "(uu)", &service_api_version, &this_service_version); + g_object_unref(params); + /* We've done it, now let's stop counting. */ /* Note: we're not checking versions. Because, the hope is that the guy holding the name we want with the wrong version will @@ -344,7 +360,7 @@ watch_cb (DBusGProxy * proxy, guint service_api_version, guint this_service_vers if (service_api_version != INDICATOR_SERVICE_VERSION) { g_warning("Service is using a different version of the service interface. Expecting %d and got %d.", INDICATOR_SERVICE_VERSION, service_api_version); - dbus_g_proxy_call_no_reply(priv->service_proxy, "UnWatch", G_TYPE_INVALID); + unwatch(priv->service_proxy); /* Let's make us wait a little while, then try again */ priv->restart_count = TIMEOUT_A_LITTLE_WHILE; @@ -354,7 +370,7 @@ watch_cb (DBusGProxy * proxy, guint service_api_version, guint this_service_vers if (this_service_version != priv->this_service_version) { g_warning("Service is using a different API version than the manager. Expecting %d and got %d.", priv->this_service_version, this_service_version); - dbus_g_proxy_call_no_reply(priv->service_proxy, "UnWatch", G_TYPE_INVALID); + unwatch(priv->service_proxy); /* Let's make us wait a little while, then try again */ priv->restart_count = TIMEOUT_A_LITTLE_WHILE; @@ -370,52 +386,6 @@ watch_cb (DBusGProxy * proxy, guint service_api_version, guint this_service_vers return; } -/* The callback after asking the dbus-daemon to start a - service for us. It can return success or failure, on - failure we can't do much. But, with sucess, we start - to build a proxy and tell the service that we're watching. */ -static void -start_service_cb (DBusGProxy * proxy, guint status, GError * error, gpointer user_data) -{ - IndicatorServiceManagerPrivate * priv = INDICATOR_SERVICE_MANAGER_GET_PRIVATE(user_data); - - if (error != NULL) { - g_warning("Unable to start service '%s': %s", priv->name, error->message); - start_service_again(INDICATOR_SERVICE_MANAGER(user_data)); - return; - } - - if (status != DBUS_START_REPLY_SUCCESS && status != DBUS_START_REPLY_ALREADY_RUNNING) { - g_warning("Status of starting the process '%s' was an error: %d", priv->name, status); - start_service_again(INDICATOR_SERVICE_MANAGER(user_data)); - return; - } - - /* Woot! it's running. Let's do it some more. */ - priv->service_proxy = dbus_g_proxy_new_for_name_owner(priv->bus, - priv->name, - INDICATOR_SERVICE_OBJECT, - INDICATOR_SERVICE_INTERFACE, - &error); - - if (error != NULL || priv->service_proxy == NULL) { - g_warning("Unable to create service proxy on '%s': %s", priv->name, error == NULL ? "(null)" : error->message); - priv->service_proxy = NULL; /* Should be already, but we want to be *really* sure. */ - g_error_free(error); - start_service_again(INDICATOR_SERVICE_MANAGER(user_data)); - return; - } - - g_object_add_weak_pointer(G_OBJECT(priv->service_proxy), (gpointer *)&(priv->service_proxy)); - g_signal_connect(G_OBJECT(priv->service_proxy), "destroy", G_CALLBACK(service_proxy_destroyed), user_data); - - org_ayatana_indicator_service_watch_async(priv->service_proxy, - watch_cb, - user_data); - - return; -} - /* The function that handles getting us connected to the service. In many cases it will start the service, but if the service is already there it just allocates the service proxy and acts @@ -423,10 +393,8 @@ start_service_cb (DBusGProxy * proxy, guint status, GError * error, gpointer use static void start_service (IndicatorServiceManager * service) { - GError * error = NULL; IndicatorServiceManagerPrivate * priv = INDICATOR_SERVICE_MANAGER_GET_PRIVATE(service); - g_return_if_fail(priv->dbus_proxy != NULL); g_return_if_fail(priv->name != NULL); if (priv->service_proxy != NULL) { @@ -434,47 +402,89 @@ start_service (IndicatorServiceManager * service) priv->service_proxy = NULL; } - /* Check to see if we can get a proxy to it first. */ - priv->service_proxy = dbus_g_proxy_new_for_name_owner(priv->bus, - priv->name, - INDICATOR_SERVICE_OBJECT, - INDICATOR_SERVICE_INTERFACE, - &error); + g_dbus_proxy_new_for_bus(G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + interface_info, + priv->name, + INDICATOR_SERVICE_OBJECT, + INDICATOR_SERVICE_INTERFACE, + NULL, /* cancelable */ + service_proxy_cb, + service); + + return; +} + +/* Callback from trying to create the proxy for the serivce, this + could include starting the service. Sometime it'll fail and + we'll try to start that dang service again! */ +static void +service_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data) +{ + GError * error = NULL; + GDBusProxy * proxy = g_dbus_proxy_new_for_bus_finish(res, &error); - if (error != NULL || priv->service_proxy == NULL) { - /* We don't care about the error, just start the service anyway. */ + if (error != NULL) { + /* Unable to create the proxy, eh, let's try again + in a bit */ g_error_free(error); - org_freedesktop_DBus_start_service_by_name_async (priv->dbus_proxy, - priv->name, - 0, - start_service_cb, - service); - } else { - g_object_add_weak_pointer(G_OBJECT(priv->service_proxy), (gpointer *)&(priv->service_proxy)); - g_signal_connect(G_OBJECT(priv->service_proxy), "destroy", G_CALLBACK(service_proxy_destroyed), service); - - /* If we got a proxy just because we're good people then - we need to call watch on it just like 'start_service_cb' - does. */ - org_ayatana_indicator_service_watch_async(priv->service_proxy, - watch_cb, - service); + start_service_again(INDICATOR_SERVICE_MANAGER(user_data)); + return; } + gchar * name = g_dbus_proxy_get_name_owner(proxy); + if (name == NULL) { + /* Hmm, since creating the proxy should start it, it seems very + odd that it wouldn't have an owner at this point. But, all + we can do is try again. */ + g_object_unref(proxy); + start_service_again(INDICATOR_SERVICE_MANAGER(user_data)); + return; + } + g_free(name); + + IndicatorServiceManagerPrivate * priv = INDICATOR_SERVICE_MANAGER_GET_PRIVATE(user_data); + priv->service_proxy = proxy; + + /* Signal for drop */ + g_signal_connect(G_OBJECT(priv->service_proxy), "notify::g-name-owner", G_CALLBACK(service_proxy_name_change), user_data); + + /* Send watch */ + g_dbus_proxy_call(priv->service_proxy, + "Watch", + NULL, /* params */ + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, /* cancel */ + watch_cb, + user_data); + return; } -/* Responds to the destory event of the proxy and starts - setting up to restart the service. */ +/* Responds to the name owner changing of the proxy, this + usually means the service died. We're dropping the proxy + and recreating it so that it'll restart the service. */ static void -service_proxy_destroyed (DBusGProxy * proxy, gpointer user_data) +service_proxy_name_change (GObject * object, GParamSpec * pspec, gpointer user_data) { IndicatorServiceManagerPrivate * priv = INDICATOR_SERVICE_MANAGER_GET_PRIVATE(user_data); - if (priv->connected) { - priv->connected = FALSE; - g_signal_emit(G_OBJECT(user_data), signals[CONNECTION_CHANGE], 0, FALSE, TRUE); + gchar * name = g_dbus_proxy_get_name_owner(priv->service_proxy); + + if (name == NULL) { + if (priv->connected) { + priv->connected = FALSE; + g_signal_emit(G_OBJECT(user_data), signals[CONNECTION_CHANGE], 0, FALSE, TRUE); + } + + start_service_again(INDICATOR_SERVICE_MANAGER(user_data)); + } else { + /* This case is an oddity, and really can only be a weird race + condition. So we're going to ignore it for now. */ + g_free(name); } - return start_service_again(INDICATOR_SERVICE_MANAGER(user_data)); + + return; } /* The callback that starts the service for real after diff --git a/libindicator/indicator-service.c b/libindicator/indicator-service.c index e9005db..e22ed66 100644 --- a/libindicator/indicator-service.c +++ b/libindicator/indicator-service.c @@ -24,40 +24,38 @@ License along with this library. If not, see #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include <dbus/dbus-glib-bindings.h> -#include <dbus/dbus-glib-lowlevel.h> + +#include <gio/gio.h> #include "indicator-service.h" +#include "gen-indicator-service.xml.h" +#include "dbus-shared.h" static void unwatch_core (IndicatorService * service, const gchar * name); -static void proxy_destroyed (GObject * proxy, gpointer user_data); static gboolean watchers_remove (gpointer key, gpointer value, gpointer user_data); -/* DBus Prototypes */ -static gboolean _indicator_service_server_watch (IndicatorService * service, DBusGMethodInvocation * method); -static gboolean _indicator_service_server_un_watch (IndicatorService * service, DBusGMethodInvocation * method); - -#include "indicator-service-server.h" -#include "dbus-shared.h" +static void bus_get_cb (GObject * object, GAsyncResult * res, gpointer user_data); +static GVariant * bus_watch (IndicatorService * service, const gchar * sender); /* Private Stuff */ /** IndicatorSevicePrivate: @name: The DBus well known name for the service. - @dbus_proxy: A proxy for talking to the dbus bus manager. @timeout: The source ID for the timeout event. @watcher: A list of processes on dbus that are watching us. @this_service_version: The version to hand out that we're implementing. May not be set, so we'll send zero (default). + @dbus_registration: The handle for this object being registered + on dbus. */ typedef struct _IndicatorServicePrivate IndicatorServicePrivate; struct _IndicatorServicePrivate { gchar * name; - DBusGProxy * dbus_proxy; - DBusGConnection * bus; + GDBusConnection * bus; guint timeout; guint timeout_length; GHashTable * watchers; guint this_service_version; + guint dbus_registration; }; /* Signals Stuff */ @@ -94,7 +92,18 @@ static void indicator_service_finalize (GObject *object); static void set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static void try_and_get_name (IndicatorService * service); +static void bus_method_call (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * method, GVariant * params, GDBusMethodInvocation * invocation, gpointer user_data); + +/* GDBus Stuff */ +static GDBusNodeInfo * node_info = NULL; +static GDBusInterfaceInfo * interface_info = NULL; +static GDBusInterfaceVTable interface_table = { + method_call: bus_method_call, + get_property: NULL, /* No properties */ + set_property: NULL /* No properties */ +}; +/* THE define */ G_DEFINE_TYPE (IndicatorService, indicator_service, G_TYPE_OBJECT); static void @@ -142,9 +151,24 @@ indicator_service_class_init (IndicatorServiceClass *klass) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); - /* Initialize the object as a DBus type */ - dbus_g_object_type_install_info(INDICATOR_SERVICE_TYPE, - &dbus_glib__indicator_service_server_object_info); + /* Setting up the DBus interfaces */ + if (node_info == NULL) { + GError * error = NULL; + + node_info = g_dbus_node_info_new_for_xml(_indicator_service, &error); + if (error != NULL) { + g_error("Unable to parse Indicator Service Interface description: %s", error->message); + g_error_free(error); + } + } + + if (interface_info == NULL) { + interface_info = g_dbus_node_info_lookup_interface(node_info, INDICATOR_SERVICE_INTERFACE); + + if (interface_info == NULL) { + g_error("Unable to find interface '" INDICATOR_SERVICE_INTERFACE "'"); + } + } return; } @@ -160,12 +184,12 @@ indicator_service_init (IndicatorService *self) /* Get the private variables in a decent state */ priv->name = NULL; - priv->dbus_proxy = NULL; priv->timeout = 0; priv->watchers = NULL; priv->bus = NULL; priv->this_service_version = 0; priv->timeout_length = 500; + priv->dbus_registration = 0; const gchar * timeoutenv = g_getenv("INDICATOR_SERVICE_SHUTDOWN_TIMEOUT"); if (timeoutenv != NULL) { @@ -176,45 +200,16 @@ indicator_service_init (IndicatorService *self) } } - /* NOTE: We're using g_object_unref here because that's what needs to + /* NOTE: We're using g_free here because that's what needs to happen, but you really should call watchers_remove first as well since that disconnects the signals. We can't do that with a callback here because there is no user data to pass the object as well. */ - priv->watchers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref); - - /* Start talkin' dbus */ - GError * error = NULL; - priv->bus = dbus_g_bus_get(DBUS_BUS_STARTER, &error); - if (error != NULL) { - g_error("Unable to get starter bus: %s", error->message); - g_error_free(error); - - /* Okay, fine let's try the session bus then. */ - /* I think this should automatically, but I can't find confirmation - of that, so we're putting the extra little code in here. */ - error = NULL; - priv->bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error); - if (error != NULL) { - g_error("Unable to get session bus: %s", error->message); - g_error_free(error); - return; - } - } - - priv->dbus_proxy = dbus_g_proxy_new_for_name_owner(priv->bus, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - &error); - if (error != NULL) { - g_error("Unable to get the proxy to DBus: %s", error->message); - g_error_free(error); - return; - } + priv->watchers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); - dbus_g_connection_register_g_object(priv->bus, - INDICATOR_SERVICE_OBJECT, - G_OBJECT(self)); + g_bus_get(G_BUS_TYPE_SESSION, + NULL, /* TODO: Cancellable */ + bus_get_cb, + self); return; } @@ -230,16 +225,22 @@ indicator_service_dispose (GObject *object) g_hash_table_foreach_remove(priv->watchers, watchers_remove, object); } - if (priv->dbus_proxy != NULL) { - g_object_unref(G_OBJECT(priv->dbus_proxy)); - priv->dbus_proxy = NULL; - } - if (priv->timeout != 0) { g_source_remove(priv->timeout); priv->timeout = 0; } + if (priv->dbus_registration != 0) { + g_dbus_connection_unregister_object(priv->bus, priv->dbus_registration); + /* Don't care if it fails, there's nothing we can do */ + priv->dbus_registration = 0; + } + + if (priv->bus != NULL) { + g_object_unref(priv->bus); + priv->bus = NULL; + } + G_OBJECT_CLASS (indicator_service_parent_class)->dispose (object); return; } @@ -335,12 +336,65 @@ get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspe return; } +/* Callback for getting our connection to DBus */ +static void +bus_get_cb (GObject * object, GAsyncResult * res, gpointer user_data) +{ + GError * error = NULL; + GDBusConnection * connection = g_bus_get_finish(res, &error); + + if (error != NULL) { + g_error("OMG! Unable to get a connection to DBus: %s", error->message); + g_error_free(error); + return; + } + + IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(user_data); + priv->bus = connection; + + /* Now register our object on our new connection */ + priv->dbus_registration = g_dbus_connection_register_object(priv->bus, + INDICATOR_SERVICE_OBJECT, + interface_info, + &interface_table, + user_data, + NULL, + &error); + if (error != NULL) { + g_error("Unable to register the object to DBus: %s", error->message); + g_error_free(error); + return; + } + + return; +} + +/* A method has been called from our dbus inteface. Figure out what it + is and dispatch it. */ +static void +bus_method_call (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * method, GVariant * params, GDBusMethodInvocation * invocation, gpointer user_data) +{ + IndicatorService * service = INDICATOR_SERVICE(user_data); + GVariant * retval = NULL; + + if (g_strcmp0(method, "Watch") == 0) { + retval = bus_watch(service, sender); + } else if (g_strcmp0(method, "UnWatch") == 0) { + unwatch_core(service, sender); + } else { + g_warning("Calling method '%s' on the indicator service and it's unknown", method); + } + + g_dbus_method_invocation_return_value(invocation, retval); + return; +} + /* A function to remove the signals on a proxy before we destroy it because in this case we've stopped caring. */ static gboolean watchers_remove (gpointer key, gpointer value, gpointer user_data) { - g_signal_handlers_disconnect_by_func(G_OBJECT(value), G_CALLBACK(proxy_destroyed), user_data); + g_bus_unwatch_name(GPOINTER_TO_UINT(value)); return TRUE; } @@ -359,34 +413,41 @@ timeout_no_watchers (gpointer data) return FALSE; } -/* The callback from our request to get a well known name - on dbus. If we can't get it we send the shutdown signal. - Else we start the timer to see if anyone cares about us. */ +/* Callback saying that the name we were looking for has been + found and we've got it. Now start the timer to see if anyone + cares about us. */ static void -try_and_get_name_cb (DBusGProxy * proxy, guint status, GError * error, gpointer data) +try_and_get_name_acquired_cb (GDBusConnection * connection, const gchar * name, gpointer user_data) { - IndicatorService * service = INDICATOR_SERVICE(data); - g_return_if_fail(service != NULL); + g_return_if_fail(connection != NULL); + g_return_if_fail(INDICATOR_IS_SERVICE(user_data)); - if (error != NULL) { - g_warning("Unable to send message to request name: %s", error->message); - g_signal_emit(G_OBJECT(data), signals[SHUTDOWN], 0, TRUE); - return; - } + IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(user_data); - if (status != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER && status != DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER) { - /* The already owner seems like it shouldn't ever - happen, but I have a hard time throwing an error - on it as we did achieve our goals. */ - g_warning("Name request failed. Status returned: %d", status); - g_signal_emit(G_OBJECT(data), signals[SHUTDOWN], 0, TRUE); - return; + /* Check to see if we already had a timer, if so we want to + extend it a bit. */ + if (priv->timeout != 0) { + g_source_remove(priv->timeout); + priv->timeout = 0; } - IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(service); /* Allow some extra time at start up as things can be in high contention then. */ - priv->timeout = g_timeout_add(priv->timeout_length * 2, timeout_no_watchers, service); + priv->timeout = g_timeout_add(priv->timeout_length * 2, timeout_no_watchers, user_data); + + return; +} + +/* Callback saying that we didn't get the name, so we need to + shutdown this service. */ +static void +try_and_get_name_lost_cb (GDBusConnection * connection, const gchar * name, gpointer user_data) +{ + g_return_if_fail(connection != NULL); + g_return_if_fail(INDICATOR_IS_SERVICE(user_data)); + + g_warning("Name request failed."); + g_signal_emit(G_OBJECT(user_data), signals[SHUTDOWN], 0, TRUE); return; } @@ -396,50 +457,34 @@ static void try_and_get_name (IndicatorService * service) { IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(service); - g_return_if_fail(priv->dbus_proxy != NULL); g_return_if_fail(priv->name != NULL); - org_freedesktop_DBus_request_name_async(priv->dbus_proxy, - priv->name, - DBUS_NAME_FLAG_DO_NOT_QUEUE, - try_and_get_name_cb, - service); + g_bus_own_name(G_BUS_TYPE_SESSION, + priv->name, + G_BUS_NAME_OWNER_FLAGS_NONE, + NULL, /* bus acquired */ + try_and_get_name_acquired_cb, /* name acquired */ + try_and_get_name_lost_cb, /* name lost */ + service, + NULL); /* user data destroy */ return; } -typedef struct _hash_table_find_t hash_table_find_t; -struct _hash_table_find_t { - GObject * proxy; - gchar * name; -}; - -/* Look in the hash table for the proxy, as it won't give us - its name. */ -static gboolean -hash_table_find (gpointer key, gpointer value, gpointer user_data) -{ - hash_table_find_t * finddata = (hash_table_find_t *)user_data; - if (value == finddata->proxy) { - finddata->name = key; - return TRUE; - } - return FALSE; -} - -/* If the proxy gets destroyed that's the same as getting an - unwatch signal. Make it so. */ +/* When the watcher vanishes we don't really care about it + anymore. */ static void -proxy_destroyed (GObject * proxy, gpointer user_data) +watcher_vanished_cb (GDBusConnection * connection, const gchar * name, gpointer user_data) { g_return_if_fail(INDICATOR_IS_SERVICE(user_data)); IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(user_data); - hash_table_find_t finddata = {0}; - finddata.proxy = proxy; - - g_hash_table_find(priv->watchers, hash_table_find, &finddata); - unwatch_core(INDICATOR_SERVICE(user_data), finddata.name); + gpointer finddata = g_hash_table_lookup(priv->watchers, name); + if (finddata != NULL) { + unwatch_core(INDICATOR_SERVICE(user_data), name); + } else { + g_warning("Odd, we were watching for '%s' and it disappeard, but then it wasn't in the hashtable.", name); + } return; } @@ -448,28 +493,25 @@ proxy_destroyed (GObject * proxy, gpointer user_data) interface "Watch" function. It is an async function so that we can get the sender and store that information. We put them in a list and reset the timeout. */ -static gboolean -_indicator_service_server_watch (IndicatorService * service, DBusGMethodInvocation * method) +static GVariant * +bus_watch (IndicatorService * service, const gchar * sender) { - g_return_val_if_fail(INDICATOR_IS_SERVICE(service), FALSE); + g_return_val_if_fail(INDICATOR_IS_SERVICE(service), NULL); IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(service); - const gchar * sender = dbus_g_method_get_sender(method); - if (g_hash_table_lookup(priv->watchers, sender) == NULL) { - GError * error = NULL; - DBusGProxy * senderproxy = dbus_g_proxy_new_for_name_owner(priv->bus, - sender, - "/", - DBUS_INTERFACE_INTROSPECTABLE, - &error); - - g_signal_connect(G_OBJECT(senderproxy), "destroy", G_CALLBACK(proxy_destroyed), service); - - if (error == NULL) { - g_hash_table_insert(priv->watchers, g_strdup(sender), senderproxy); + if (GPOINTER_TO_UINT(g_hash_table_lookup(priv->watchers, sender)) == 0) { + guint watch = g_bus_watch_name_on_connection(priv->bus, + sender, + G_BUS_NAME_WATCHER_FLAGS_NONE, + NULL, /* appeared, we dont' care, should have already happened. */ + watcher_vanished_cb, + service, + NULL); + + if (watch != 0) { + g_hash_table_insert(priv->watchers, g_strdup(sender), GUINT_TO_POINTER(watch)); } else { - g_warning("Unable to create proxy for watcher '%s': %s", sender, error->message); - g_error_free(error); + g_warning("Unable watch for '%s'", sender); } } @@ -478,22 +520,7 @@ _indicator_service_server_watch (IndicatorService * service, DBusGMethodInvocati priv->timeout = 0; } - dbus_g_method_return(method, INDICATOR_SERVICE_VERSION, priv->this_service_version); - return TRUE; -} - -/* A function connecting into the dbus interface for the - "UnWatch" function. It is also an async function to get - the sender and passes everything to unwatch_core to remove it. */ -static gboolean -_indicator_service_server_un_watch (IndicatorService * service, DBusGMethodInvocation * method) -{ - g_return_val_if_fail(INDICATOR_IS_SERVICE(service), FALSE); - - unwatch_core(service, dbus_g_method_get_sender(method)); - - dbus_g_method_return(method); - return TRUE; + return g_variant_new("(uu)", INDICATOR_SERVICE_VERSION, priv->this_service_version); } /* Performs the core of loosing a watcher; it removes them |