aboutsummaryrefslogtreecommitdiff
path: root/libindicator/indicator-service-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'libindicator/indicator-service-manager.c')
-rw-r--r--libindicator/indicator-service-manager.c334
1 files changed, 334 insertions, 0 deletions
diff --git a/libindicator/indicator-service-manager.c b/libindicator/indicator-service-manager.c
new file mode 100644
index 0000000..4eaed23
--- /dev/null
+++ b/libindicator/indicator-service-manager.c
@@ -0,0 +1,334 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <dbus/dbus-glib-bindings.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "indicator-service-manager.h"
+#include "indicator-service-client.h"
+#include "dbus-shared.h"
+
+/* Private Stuff */
+typedef struct _IndicatorServiceManagerPrivate IndicatorServiceManagerPrivate;
+struct _IndicatorServiceManagerPrivate {
+ gchar * name;
+ DBusGProxy * dbus_proxy;
+ DBusGProxy * service_proxy;
+ gboolean connected;
+};
+
+/* Signals Stuff */
+enum {
+ CONNECTION_CHANGE,
+ 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,
+};
+
+/* The strings so that they can be slowly looked up. */
+#define PROP_NAME_S "name"
+
+/* GObject Stuff */
+#define INDICATOR_SERVICE_MANAGER_GET_PRIVATE(o) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_SERVICE_MANAGER_TYPE, IndicatorServiceManagerPrivate))
+
+static void indicator_service_manager_class_init (IndicatorServiceManagerClass *klass);
+static void indicator_service_manager_init (IndicatorServiceManager *self);
+static void indicator_service_manager_dispose (GObject *object);
+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 start_service (IndicatorServiceManager * service);
+
+G_DEFINE_TYPE (IndicatorServiceManager, indicator_service_manager, G_TYPE_OBJECT);
+
+static void
+indicator_service_manager_class_init (IndicatorServiceManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (IndicatorServiceManagerPrivate));
+
+ object_class->dispose = indicator_service_manager_dispose;
+ object_class->finalize = indicator_service_manager_finalize;
+
+ /* Property funcs */
+ object_class->set_property = set_property;
+ object_class->get_property = get_property;
+
+ /**
+ IndicatorServiceManager::connecton-change:
+ @arg0: The #IndicatorServiceManager object
+ @arg1: The state of the connection, TRUE is connected.
+
+ Signaled when the service is connected or disconnected
+ depending on it's previous state.
+ */
+ signals[CONNECTION_CHANGE] = g_signal_new (INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE,
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (IndicatorServiceManagerClass, connection_change),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE, 1, G_TYPE_BOOLEAN, G_TYPE_NONE);
+
+ /* Properties */
+ g_object_class_install_property(object_class, PROP_NAME,
+ g_param_spec_string(PROP_NAME_S,
+ "The DBus name for the service to monitor",
+ "This is the name that should be used to start a service.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ return;
+}
+
+static void
+indicator_service_manager_init (IndicatorServiceManager *self)
+{
+ IndicatorServiceManagerPrivate * priv = INDICATOR_SERVICE_MANAGER_GET_PRIVATE(self);
+
+ /* Get the private variables in a decent state */
+ priv->name = NULL;
+ priv->dbus_proxy = NULL;
+ priv->service_proxy = NULL;
+ priv->connected = FALSE;
+
+ /* Start talkin' dbus */
+ GError * error = NULL;
+ DBusGConnection * session_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(session_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;
+}
+
+static void
+indicator_service_manager_dispose (GObject *object)
+{
+ IndicatorServiceManagerPrivate * priv = INDICATOR_SERVICE_MANAGER_GET_PRIVATE(object);
+
+ /* If we were connected we need to make sure to
+ tell people that it's no longer the case. */
+ if (priv->connected) {
+ priv->connected = FALSE;
+ 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;
+ }
+
+ /* Destory our service proxy, we won't need it. */
+ if (priv->service_proxy != NULL) {
+ g_object_unref(G_OBJECT(priv->service_proxy));
+ priv->service_proxy = NULL;
+ }
+
+ /* Let's see if our parents want to do anything. */
+ G_OBJECT_CLASS (indicator_service_manager_parent_class)->dispose (object);
+ return;
+}
+
+static void
+indicator_service_manager_finalize (GObject *object)
+{
+ IndicatorServiceManagerPrivate * priv = INDICATOR_SERVICE_MANAGER_GET_PRIVATE(object);
+
+ if (priv->name != NULL) {
+ g_free(priv->name);
+ priv->name = NULL;
+ }
+
+ G_OBJECT_CLASS (indicator_service_manager_parent_class)->finalize (object);
+ return;
+}
+
+static void
+set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ IndicatorServiceManager * self = INDICATOR_SERVICE_MANAGER(object);
+ g_return_if_fail(self != NULL);
+
+ IndicatorServiceManagerPrivate * priv = INDICATOR_SERVICE_MANAGER_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);
+ start_service(self);
+ } else {
+ g_warning("Name is a string bud.");
+ }
+ break;
+ /* *********************** */
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+ return;
+}
+
+static void
+get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ IndicatorServiceManager * self = INDICATOR_SERVICE_MANAGER(object);
+ g_return_if_fail(self != NULL);
+
+ IndicatorServiceManagerPrivate * priv = INDICATOR_SERVICE_MANAGER_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 is a string bud.");
+ }
+ break;
+ /* *********************** */
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+ return;
+}
+
+static void
+watch_cb (DBusGProxy * proxy, gint service_version, GError * error, gpointer user_data)
+{
+ IndicatorServiceManagerPrivate * priv = INDICATOR_SERVICE_MANAGER_GET_PRIVATE(user_data);
+
+ if (error != NULL) {
+ g_warning("Unable to set watch on '%s': '%s'", priv->name, error->message);
+ g_error_free(error);
+ return;
+ }
+
+ if (service_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_version);
+ return;
+ }
+
+ if (!priv->connected) {
+ priv->connected = TRUE;
+ g_signal_emit(G_OBJECT(user_data), signals[CONNECTION_CHANGE], 0, TRUE, TRUE);
+ }
+
+ return;
+}
+
+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);
+ 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);
+ return;
+ }
+
+ /* Woot! it's running. Let's do it some more. */
+ DBusGConnection * session_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->service_proxy = dbus_g_proxy_new_for_name_owner(session_bus,
+ priv->name,
+ INDICATOR_SERVICE_OBJECT,
+ INDICATOR_SERVICE_INTERFACE,
+ &error);
+
+ org_ayatana_indicator_service_watch_async(priv->service_proxy,
+ watch_cb,
+ user_data);
+
+ return;
+}
+
+static void
+start_service (IndicatorServiceManager * service)
+{
+ IndicatorServiceManagerPrivate * priv = INDICATOR_SERVICE_MANAGER_GET_PRIVATE(service);
+
+ g_return_if_fail(priv->dbus_proxy != NULL);
+ g_return_if_fail(priv->name != NULL);
+
+ org_freedesktop_DBus_start_service_by_name_async (priv->dbus_proxy,
+ priv->name,
+ 0,
+ start_service_cb,
+ service);
+
+ return;
+}
+
+/* API */
+IndicatorServiceManager *
+indicator_service_manager_new (gchar * dbus_name)
+{
+ GObject * obj = g_object_new(INDICATOR_SERVICE_MANAGER_TYPE,
+ PROP_NAME_S, dbus_name,
+ NULL);
+
+ return INDICATOR_SERVICE_MANAGER(obj);
+}
+
+gboolean
+indicator_service_manager_connected (IndicatorServiceManager * sm)
+{
+
+ return FALSE;
+}
+
+void
+indicator_service_manager_set_refresh (IndicatorServiceManager * sm, guint time_in_ms)
+{
+
+ return;
+}