aboutsummaryrefslogtreecommitdiff
path: root/libindicator/indicator-service.c
diff options
context:
space:
mode:
authorMike Gabriel <mike.gabriel@das-netzwerkteam.de>2015-11-06 14:46:09 +0000
committerMike Gabriel <mike.gabriel@das-netzwerkteam.de>2015-11-06 15:17:48 +0000
commit9d1b39fa6a02985a613604826997f0d7b969a40d (patch)
tree7ea1aae3aeb0f3084b082f4cc1ca85b31fc9ff16 /libindicator/indicator-service.c
parentb1f280aa8eb47f039398d604fe8fd126aae86fa4 (diff)
downloadlibayatana-indicator-9d1b39fa6a02985a613604826997f0d7b969a40d.tar.gz
libayatana-indicator-9d1b39fa6a02985a613604826997f0d7b969a40d.tar.bz2
libayatana-indicator-9d1b39fa6a02985a613604826997f0d7b969a40d.zip
Fork libayatana-indicator from Ubuntu's libindicator shared library.
Diffstat (limited to 'libindicator/indicator-service.c')
-rw-r--r--libindicator/indicator-service.c653
1 files changed, 0 insertions, 653 deletions
diff --git a/libindicator/indicator-service.c b/libindicator/indicator-service.c
deleted file mode 100644
index 1cd6964..0000000
--- a/libindicator/indicator-service.c
+++ /dev/null
@@ -1,653 +0,0 @@
-/*
-An object used to provide a simple interface for a service
-to query version and manage whether it's running.
-
-Copyright 2009 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@canonical.com>
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-version 3.0 as published by the Free Software Foundation.
-
-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 General Public License version 3.0 for more details.
-
-You should have received a copy of the GNU General Public
-License along with this library. If not, see
-<http://www.gnu.org/licenses/>.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdlib.h> /* exit() */
-
-#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 watchers_remove (gpointer value);
-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.
- @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;
- GDBusConnection * bus;
- GCancellable * bus_cancel;
- guint timeout;
- guint timeout_length;
- GHashTable * watchers;
- guint this_service_version;
- guint dbus_registration;
- gboolean replace_mode;
-};
-
-/* Signals Stuff */
-enum {
- SHUTDOWN,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-/* Properties */
-/* Enum for the properties so that they can be quickly
- found and looked up. */
-enum {
- PROP_0,
- PROP_NAME,
- PROP_VERSION
-};
-
-/* The strings so that they can be slowly looked up. */
-#define PROP_NAME_S "name"
-#define PROP_VERSION_S "version"
-
-/* GObject Stuff */
-#define INDICATOR_SERVICE_GET_PRIVATE(o) \
- (G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_SERVICE_TYPE, IndicatorServicePrivate))
-
-static void indicator_service_class_init (IndicatorServiceClass *klass);
-static void indicator_service_init (IndicatorService *self);
-static void indicator_service_dispose (GObject *object);
-static void indicator_service_finalize (GObject *object);
-
-/* Other 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 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
-indicator_service_class_init (IndicatorServiceClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (klass, sizeof (IndicatorServicePrivate));
-
- object_class->dispose = indicator_service_dispose;
- object_class->finalize = indicator_service_finalize;
-
- /* Property funcs */
- object_class->set_property = set_property;
- object_class->get_property = get_property;
-
- /* Properties */
- g_object_class_install_property(object_class, PROP_NAME,
- g_param_spec_string(PROP_NAME_S,
- "The DBus name for this service",
- "This is the name that should be used on DBus for this service.",
- NULL,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property(object_class, PROP_VERSION,
- g_param_spec_uint(PROP_VERSION_S,
- "The version of the service that we're implementing.",
- "A number to represent the version of the other APIs the service provides. This should match across the manager and the service",
- 0, G_MAXUINT, 0,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /* Signals */
-
- /**
- IndicatorService::shutdown:
- @arg0: The #IndicatorService object
-
- Signaled when the service should shutdown as no one
- is listening anymore.
- */
- signals[SHUTDOWN] = g_signal_new (INDICATOR_SERVICE_SIGNAL_SHUTDOWN,
- G_TYPE_FROM_CLASS(klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (IndicatorServiceClass, shutdown),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0, G_TYPE_NONE);
-
- /* 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;
-}
-
-/* This function builds the variables, sets up the dbus
- proxy and registers the object on dbus. Importantly,
- it does not request a name as we don't know what name
- we have yet. */
-static void
-indicator_service_init (IndicatorService *self)
-{
- IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(self);
-
- /* Get the private variables in a decent state */
- priv->name = NULL;
- priv->timeout = 0;
- priv->watchers = NULL;
- priv->bus = NULL;
- priv->bus_cancel = NULL;
- priv->this_service_version = 0;
- priv->timeout_length = 500;
- priv->dbus_registration = 0;
- priv->replace_mode = FALSE;
-
- const gchar * timeoutenv = g_getenv("INDICATOR_SERVICE_SHUTDOWN_TIMEOUT");
- if (timeoutenv != NULL) {
- gdouble newtimeout = g_strtod(timeoutenv, NULL);
- if (newtimeout >= 1.0f) {
- priv->timeout_length = newtimeout;
- g_debug("Setting shutdown timeout to: %u", priv->timeout_length);
- }
- }
-
- const gchar * replaceenv = g_getenv("INDICATOR_SERVICE_REPLACE_MODE");
- if (replaceenv != NULL) {
- priv->replace_mode = TRUE;
- g_debug("Putting into replace mode");
- }
-
- /* NOTE: We're using g_free here because that's what needs to
- happen and we're watchers_remove as well to clean up the dbus
- watches we've setup. */
- priv->watchers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, watchers_remove);
-
- priv->bus_cancel = g_cancellable_new();
- g_bus_get(G_BUS_TYPE_SESSION,
- priv->bus_cancel,
- bus_get_cb,
- self);
-
- return;
-}
-
-/* Unrefcounting the proxies and making sure that our
- timeout doesn't come to haunt us. */
-static void
-indicator_service_dispose (GObject *object)
-{
- IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(object);
-
- g_clear_pointer (&priv->watchers, g_hash_table_destroy);
-
- 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;
- }
-
- g_clear_object (&priv->bus);
-
- if (priv->bus_cancel != NULL) {
- g_cancellable_cancel(priv->bus_cancel);
- g_object_unref(priv->bus_cancel);
- priv->bus_cancel = NULL;
- }
-
- G_OBJECT_CLASS (indicator_service_parent_class)->dispose (object);
- return;
-}
-
-/* Freeing the name we're looking for and all of the
- information on the watchers we're tracking. */
-static void
-indicator_service_finalize (GObject *object)
-{
- IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(object);
-
- g_free (priv->name);
- g_clear_pointer (&priv->watchers, g_hash_table_destroy);
-
- G_OBJECT_CLASS (indicator_service_parent_class)->finalize (object);
- return;
-}
-
-/* Either copies a string for the name or it just grabs
- the value of the version. */
-static void
-set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
-{
- IndicatorService * self = INDICATOR_SERVICE(object);
- g_return_if_fail(self != NULL);
-
- IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(self);
- g_return_if_fail(priv != NULL);
-
- switch (prop_id) {
- /* *********************** */
- case PROP_NAME:
- if (G_VALUE_HOLDS_STRING(value)) {
- if (priv->name != NULL) {
- g_error("Name can not be set twice!");
- return;
- }
- priv->name = g_value_dup_string(value);
- try_and_get_name(self);
- } else {
- g_warning("Name property requires a string value.");
- }
- break;
- /* *********************** */
- case PROP_VERSION:
- priv->this_service_version = g_value_get_uint(value);
- break;
- /* *********************** */
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-
- return;
-}
-
-/* Copies out the name into a value or the version number.
- Probably this is the least useful code in this file. */
-static void
-get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
-{
- IndicatorService * self = INDICATOR_SERVICE(object);
- g_return_if_fail(self != NULL);
-
- IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(self);
- g_return_if_fail(priv != NULL);
-
- switch (prop_id) {
- /* *********************** */
- case PROP_NAME:
- if (G_VALUE_HOLDS_STRING(value)) {
- g_value_set_string(value, priv->name);
- } else {
- g_warning("Name property requires a string value.");
- }
- break;
- /* *********************** */
- case PROP_VERSION:
- g_value_set_uint(value, priv->this_service_version);
- break;
- /* *********************** */
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-
- 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_warning("Unable to get a connection to the session DBus: %s", error->message);
- g_error_free(error);
- exit (0);
- return;
- }
-
- IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(user_data);
-
- g_warn_if_fail(priv->bus == NULL);
- priv->bus = connection;
-
- if (priv->bus_cancel != NULL) {
- g_object_unref(priv->bus_cancel);
- priv->bus_cancel = NULL;
- }
-
- /* 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 if (g_strcmp0(method, "Shutdown") == 0) {
- g_signal_emit(G_OBJECT(service), signals[SHUTDOWN], 0, TRUE);
- } 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 void
-watchers_remove (gpointer value)
-{
- g_bus_unwatch_name(GPOINTER_TO_UINT(value));
- return;
-}
-
-/* This is the function that gets executed if we timeout
- because there are no watchers. We sent the shutdown
- signal and hope someone does something sane with it. */
-static gboolean
-timeout_no_watchers (gpointer data)
-{
- g_warning("No watchers, service timing out.");
- if (g_getenv("INDICATOR_ALLOW_NO_WATCHERS") == NULL) {
- g_signal_emit(G_OBJECT(data), signals[SHUTDOWN], 0, TRUE);
- } else {
- g_warning("\tblocked by environment variable.");
- }
- return FALSE;
-}
-
-/* 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_acquired_cb (GDBusConnection * connection, const gchar * name, gpointer user_data)
-{
- g_return_if_fail(connection != NULL);
- g_return_if_fail(INDICATOR_IS_SERVICE(user_data));
-
- IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(user_data);
-
- /* 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;
- }
-
- /* 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, 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));
-
- IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(user_data);
-
- if (!priv->replace_mode) {
- g_warning("Name request failed.");
- g_signal_emit(G_OBJECT(user_data), signals[SHUTDOWN], 0, TRUE);
- } else {
- /* If we're in replace mode we can be a little more trickey
- here. We're going to tell the other guy to shutdown and hope
- that we get the name. */
- GDBusMessage * message = NULL;
- message = g_dbus_message_new_method_call(name,
- INDICATOR_SERVICE_OBJECT,
- INDICATOR_SERVICE_INTERFACE,
- "Shutdown");
-
- g_dbus_connection_send_message(connection, message, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
- g_object_unref(message);
-
- /* Check to see if we need to clean up a timeout */
- if (priv->timeout != 0) {
- g_source_remove(priv->timeout);
- priv->timeout = 0;
- }
-
- /* Set a timeout for no watchers if we can't get the name */
- priv->timeout = g_timeout_add(priv->timeout_length * 4, timeout_no_watchers, user_data);
- }
-
- return;
-}
-
-/* This function sets up the request for the name on dbus. */
-static void
-try_and_get_name (IndicatorService * service)
-{
- IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(service);
- g_return_if_fail(priv->name != NULL);
-
- 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;
-}
-
-/* When the watcher vanishes we don't really care about it
- anymore. */
-static void
-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);
-
- 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;
-}
-
-/* Here is the function that gets called by the dbus
- 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 GVariant *
-bus_watch (IndicatorService * service, const gchar * sender)
-{
- g_return_val_if_fail(INDICATOR_IS_SERVICE(service), NULL);
- IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(service);
-
- 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 watch for '%s'", sender);
- }
- }
-
- if (priv->timeout != 0) {
- g_source_remove(priv->timeout);
- priv->timeout = 0;
- }
-
- return g_variant_new("(uu)", INDICATOR_SERVICE_VERSION, priv->this_service_version);
-}
-
-/* Performs the core of loosing a watcher; it removes them
- from the list of watchers. If there are none left, it then
- starts the timer for the shutdown signal. */
-static void
-unwatch_core (IndicatorService * service, const gchar * name)
-{
- g_return_if_fail(name != NULL);
- g_return_if_fail(INDICATOR_IS_SERVICE(service));
-
- IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(service);
-
- /* Remove us from the watcher list here */
- gpointer watcher_item = g_hash_table_lookup(priv->watchers, name);
- if (watcher_item != NULL) {
- gchar * safe_name = g_strdup(name);
- g_hash_table_remove(priv->watchers, safe_name);
- g_free(safe_name);
- } else {
- /* Odd that we couldn't find the person, but, eh */
- g_warning("Unable to find watcher who is unwatching: %s", name);
- }
-
- /* If we're out of watchers set the timeout for shutdown */
- if (g_hash_table_size(priv->watchers) == 0) {
- if (priv->timeout != 0) {
- /* This should never really happen, but let's ensure that
- bad things don't happen if it does. */
- g_warning("No watchers timeout set twice. Resolving, but odd.");
- g_source_remove(priv->timeout);
- priv->timeout = 0;
- }
- /* If we don't get a new watcher quickly, we'll shutdown. */
- priv->timeout = g_timeout_add(priv->timeout_length, timeout_no_watchers, service);
- }
-
- return;
-}
-
-/* API */
-
-/**
- indicator_service_new:
- @name: The name for the service on dbus
-
- This function creates the service on DBus and tries to
- get a well-known name specified in @name. If the name
- can't be estabilished then the #IndicatorService::shutdown
- signal will be sent.
-
- Return value: A brand new #IndicatorService object or #NULL
- if there is an error.
-*/
-IndicatorService *
-indicator_service_new (gchar * name)
-{
- GObject * obj = g_object_new(INDICATOR_SERVICE_TYPE,
- PROP_NAME_S, name,
- NULL);
-
- return INDICATOR_SERVICE(obj);
-}
-
-/**
- indicator_service_new_version:
- @name: The name for the service on dbus
- @version: The version of the other interfaces provide
- by the service.
-
- This function creates the service on DBus and tries to
- get a well-known name specified in @name. If the name
- can't be estabilished then the #IndicatorService::shutdown
- signal will be sent.
-
- Return value: A brand new #IndicatorService object or #NULL
- if there is an error.
-*/
-IndicatorService *
-indicator_service_new_version (gchar * name, guint version)
-{
- GObject * obj = g_object_new(INDICATOR_SERVICE_TYPE,
- PROP_NAME_S, name,
- PROP_VERSION_S, version,
- NULL);
-
- return INDICATOR_SERVICE(obj);
-}