Back to index

libindicator  12.10.0
Classes
indicator-service.c File Reference
#include <gio/gio.h>
#include "indicator-service.h"
#include "gen-indicator-service.xml.h"
#include "dbus-shared.h"

Go to the source code of this file.

Classes

struct  _IndicatorServicePrivate

Functions

. 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)
IndicatorService * indicator_service_new_version (gchar *name, guint version)

: The DBus well known name for the service.

IndicatorSevicePrivate:

: The source ID for the timeout event.

: A list of processes on dbus that are watching us. : The version to hand out that we're implementing. May not be set, so we'll send zero (default). : The handle for this object being registered on dbus.

#define PROP_NAME_S   "name"
#define PROP_VERSION_S   "version"
#define INDICATOR_SERVICE_GET_PRIVATE(o)   (G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_SERVICE_TYPE, IndicatorServicePrivate))
enum  { SHUTDOWN, LAST_SIGNAL }
enum  { PROP_0, PROP_NAME, PROP_VERSION }
typedef struct _IndicatorServicePrivate
static guint signals [LAST_SIGNAL] = { 0 }
static GDBusNodeInfo * node_info = NULL
static GDBusInterfaceInfo * interface_info = NULL
static GDBusInterfaceVTable interface_table
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)
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)
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)
 G_DEFINE_TYPE (IndicatorService, indicator_service, G_TYPE_OBJECT)
static gboolean timeout_no_watchers (gpointer data)
static void try_and_get_name_acquired_cb (GDBusConnection *connection, const gchar *name, gpointer user_data)
static void try_and_get_name_lost_cb (GDBusConnection *connection, const gchar *name, gpointer user_data)
static void watcher_vanished_cb (GDBusConnection *connection, const gchar *name, gpointer user_data)

Class Documentation

struct _IndicatorServicePrivate

Definition at line 51 of file indicator-service.c.

Class Members
GDBusConnection * bus
GCancellable * bus_cancel
guint dbus_registration
gchar * name
gboolean replace_mode
guint this_service_version
guint timeout
guint timeout_length
GHashTable * watchers

Define Documentation

#define INDICATOR_SERVICE_GET_PRIVATE (   o)    (G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_SERVICE_TYPE, IndicatorServicePrivate))

Definition at line 85 of file indicator-service.c.

#define PROP_NAME_S   "name"

Definition at line 81 of file indicator-service.c.

#define PROP_VERSION_S   "version"

Definition at line 82 of file indicator-service.c.


Typedef Documentation

typedef struct _IndicatorServicePrivate

Definition at line 50 of file indicator-service.c.


Enumeration Type Documentation

anonymous enum
Enumerator:
SHUTDOWN 
LAST_SIGNAL 

Definition at line 64 of file indicator-service.c.

anonymous enum
Enumerator:
PROP_0 
PROP_NAME 
PROP_VERSION 

Definition at line 74 of file indicator-service.c.


Function Documentation

static void bus_get_cb ( GObject *  object,
GAsyncResult *  res,
gpointer  user_data 
) [static]

Definition at line 358 of file indicator-service.c.

{
       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);

       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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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 
) [static]

Definition at line 399 of file indicator-service.c.

{
       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;
}

Here is the call graph for this function:

static GVariant * bus_watch ( IndicatorService *  service,
const gchar *  sender 
) [static]

Definition at line 548 of file indicator-service.c.

{
       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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

G_DEFINE_TYPE ( IndicatorService  ,
indicator_service  ,
G_TYPE_OBJECT   
)
static void get_property ( GObject *  object,
guint  prop_id,
GValue *  value,
GParamSpec *  pspec 
) [static]

Definition at line 326 of file indicator-service.c.

{
       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;
}

Here is the caller graph for this function:

static void indicator_service_class_init ( IndicatorServiceClass *  klass) [static]

IndicatorService::shutdown: : The #IndicatorService object

Signaled when the service should shutdown as no one is listening anymore.

Definition at line 112 of file indicator-service.c.

{
       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 */

       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;
}

Here is the call graph for this function:

static void indicator_service_dispose ( GObject *  object) [static]

Definition at line 230 of file indicator-service.c.

{
       IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(object);

       if (priv->watchers != NULL) {
              g_hash_table_destroy(priv->watchers);
              priv->watchers = 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;
       }

       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;
}

Here is the caller graph for this function:

static void indicator_service_finalize ( GObject *  object) [static]

Definition at line 268 of file indicator-service.c.

{
       IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(object);

       if (priv->name != NULL) {
              g_free(priv->name);
       }

       if (priv->watchers != NULL) {
              g_hash_table_destroy(priv->watchers);
              priv->watchers = NULL;
       }

       G_OBJECT_CLASS (indicator_service_parent_class)->finalize (object);
       return;
}

Here is the caller graph for this function:

static void indicator_service_init ( IndicatorService *  self) [static]

Definition at line 183 of file indicator-service.c.

{
       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;
}

Here is the call graph for this function:

IndicatorService* indicator_service_new ( gchar *  name)

Definition at line 630 of file indicator-service.c.

{
       GObject * obj = g_object_new(INDICATOR_SERVICE_TYPE,
                                    PROP_NAME_S, name,
                                    NULL);

       return INDICATOR_SERVICE(obj);
}

Here is the caller graph for this function:

IndicatorService* indicator_service_new_version ( gchar *  name,
guint  version 
)

Definition at line 654 of file indicator-service.c.

{
       GObject * obj = g_object_new(INDICATOR_SERVICE_TYPE,
                                    PROP_NAME_S, name,
                                    PROP_VERSION_S, version,
                                    NULL);

       return INDICATOR_SERVICE(obj);
}

Here is the caller graph for this function:

static void set_property ( GObject *  object,
guint  prop_id,
const GValue *  value,
GParamSpec *  pspec 
) [static]

Definition at line 288 of file indicator-service.c.

{
       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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static gboolean timeout_no_watchers ( gpointer  data) [static]

Definition at line 431 of file indicator-service.c.

{
       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;
}

Here is the caller graph for this function:

static void try_and_get_name ( IndicatorService *  service) [static]

Definition at line 508 of file indicator-service.c.

{
       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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void try_and_get_name_acquired_cb ( GDBusConnection *  connection,
const gchar *  name,
gpointer  user_data 
) [static]

Definition at line 446 of file indicator-service.c.

{
       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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void try_and_get_name_lost_cb ( GDBusConnection *  connection,
const gchar *  name,
gpointer  user_data 
) [static]

Definition at line 470 of file indicator-service.c.

{
       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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void unwatch_core ( IndicatorService *  service,
const gchar *  name 
) [static]

Definition at line 581 of file indicator-service.c.

{
       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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void watcher_vanished_cb ( GDBusConnection *  connection,
const gchar *  name,
gpointer  user_data 
) [static]

Definition at line 528 of file indicator-service.c.

{
       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 call graph for this function:

Here is the caller graph for this function:

static void watchers_remove ( gpointer  value) [static]

Definition at line 421 of file indicator-service.c.

{
       g_bus_unwatch_name(GPOINTER_TO_UINT(value));
       return;
}

Here is the caller graph for this function:


Variable Documentation

GDBusInterfaceInfo* interface_info = NULL [static]

Definition at line 101 of file indicator-service.c.

GDBusInterfaceVTable interface_table [static]
Initial value:
 {
       method_call:  bus_method_call,
       get_property: NULL, 
       set_property: NULL  
}

Definition at line 102 of file indicator-service.c.

GDBusNodeInfo* node_info = NULL [static]

Definition at line 100 of file indicator-service.c.

guint signals[LAST_SIGNAL] = { 0 } [static]

Definition at line 69 of file indicator-service.c.