diff options
29 files changed, 1872 insertions, 3 deletions
@@ -103,3 +103,31 @@ src-sus/indicator-applet-sus data/GNOME_IndicatorAppletSUS.server data/GNOME_IndicatorAppletSUS.server.in src-sus/indicator-applet-no-sus +libindicator/libindicator.la +libindicator/libindicator_la-indicator-object. +libindicator/libindicator_la-indicator-object.lo +tests/loader-check-results.xml +tests/loader-check-results.html +tests/test-loader +tests/libdummy-indicator-null.la +tests/libdummy_indicator_null_la-dummy-indicator-null.lo +tests/libdummy-indicator-simple.la +tests/libdummy_indicator_simple_la-dummy-indicator-simple.lo +tests/libdummy-indicator-blank.la +tests/libdummy_indicator_blank_la-dummy-indicator-blank.lo +libindicator-[0-9].[0-9].[0-9].tar.gz +libindicator-[0-9].[0-9].[0-9].tar.gz.asc +libindicator/indicator-service-client.h +libindicator/indicator-service-server.h +libindicator/libindicator_la-indicator-service.lo +libindicator/libindicator_la-indicator-service-manager.lo +tests/service-shutdown-timeout +tests/loader-tester +tests/service-shutdown-timeout-tester +tests/service-manager-no-connect +tests/service-manager-no-connect-tester +tests/service-manager-connect +tests/service-manager-connect-service +tests/service-manager-connect-tester +tests/session.conf +tests/service-manager-connect.service diff --git a/Makefile.am b/Makefile.am index ae85ded..8894e24 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,8 @@ SUBDIRS = \ - libindicator + libindicator \ + tests \ + tools DISTCLEANFILES = \ libindicator-*.tar.gz diff --git a/configure.ac b/configure.ac index 090e281..d2e18fc 100644 --- a/configure.ac +++ b/configure.ac @@ -21,6 +21,19 @@ AC_CONFIG_MACRO_DIR([m4]) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) ############################## +# Dependencies +############################## + +GTK_REQUIRED_VERSION=2.18 +DBUS_REQUIRED_VERSION=0.76 + +PKG_CHECK_MODULES(LIBINDICATOR, gtk+-2.0 >= $GTK_REQUIRED_VERSION + dbus-glib-1 >= $DBUS_REQUIRED_VERSION) + +AC_SUBST(LIBINDICATOR_CFLAGS) +AC_SUBST(LIBINDICATOR_LIBS) + +############################## # Custom Junk ############################## @@ -73,6 +86,8 @@ AC_OUTPUT([ Makefile libindicator/Makefile libindicator/indicator.pc +tests/Makefile +tools/Makefile ]) ########################### diff --git a/debian/changelog b/debian/changelog index d3ca348..a908ebc 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +libindicator (0.2.1-0ubuntu2~ppa1) UNRELEASED; urgency=low + + * Adding in service management code. + * debian/control: Adding a target for libindicator0 + * Adding libindicator0.install and libindicator-dev.install + + -- Ted Gould <ted@ubuntu.com> Wed, 04 Nov 2009 08:14:34 -0600 + libindicator (0.2.1-0ubuntu1) karmic; urgency=low * Upstream release 0.2.1 (LP: #446619) diff --git a/debian/control b/debian/control index 9f0f009..6d14ad9 100644 --- a/debian/control +++ b/debian/control @@ -10,6 +10,17 @@ Homepage: https://launchpad.net/libindicator Vcs-Bzr: https://code.launchpad.net/~ubuntu-desktop/libindicator/ubuntu Vcs-Browser: http://bazaar.launchpad.net/~ubuntu-desktop/libindicator/ubuntu +Package: libindicator0 +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, + ${misc:Depends} +Description: GNOME panel indicator applet - shared library + This library contains information to build indicators to go into + the indicator applet. + . + This package contains files that are needed to build applications. + Package: libindicator-dev Section: libdevel Architecture: any diff --git a/debian/libindicator-dev.install b/debian/libindicator-dev.install new file mode 100644 index 0000000..33d0de9 --- /dev/null +++ b/debian/libindicator-dev.install @@ -0,0 +1,4 @@ +debian/tmp/usr/include/libindicator-0.1/libindicator/* +debian/tmp/usr/lib/pkgconfig/indicator.pc +debian/tmp/usr/lib/libindicator.a +debian/tmp/usr/lib/libindicator.so diff --git a/debian/libindicator0.install b/debian/libindicator0.install new file mode 100644 index 0000000..85dbd3e --- /dev/null +++ b/debian/libindicator0.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libindicator.so.* diff --git a/libindicator/Makefile.am b/libindicator/Makefile.am index be68721..5c512cd 100644 --- a/libindicator/Makefile.am +++ b/libindicator/Makefile.am @@ -1,14 +1,64 @@ +BUILT_SOURCES = +CLEANFILES = EXTRA_DIST = \ indicator.pc.in libindicatorincludedir=$(includedir)/libindicator-0.1/libindicator indicator_headers = \ - indicator.h + indicator.h \ + indicator-object.h \ + indicator-service.h \ + indicator-service-manager.h libindicatorinclude_HEADERS = \ $(indicator_headers) +lib_LTLIBRARIES = \ + libindicator.la + +libindicator_la_SOURCES = \ + $(indicator_headers) \ + dbus-shared.h \ + indicator-object.c \ + indicator-service.c \ + indicator-service-manager.c + +libindicator_la_CFLAGS = \ + $(LIBINDICATOR_CFLAGS) \ + -Wall -Werror + +libindicator_la_LIBADD = \ + $(LIBINDICATOR_LIBS) + pkgconfig_DATA = indicator.pc pkgconfigdir = $(libdir)/pkgconfig +################################## +# DBus Specs +################################## + +DBUS_SPECS = \ + indicator-service.xml + +%-client.h: %.xml + dbus-binding-tool \ + --prefix=_$(subst -,_,$(basename $(notdir $<)))_client \ + --mode=glib-client \ + --output=$@ \ + $< + +%-server.h: %.xml + dbus-binding-tool \ + --prefix=_$(subst -,_,$(basename $(notdir $<)))_server \ + --mode=glib-server \ + --output=$@ \ + $< + +BUILT_SOURCES += \ + $(DBUS_SPECS:.xml=-client.h) \ + $(DBUS_SPECS:.xml=-server.h) + +CLEANFILES += $(BUILT_SOURCES) + +EXTRA_DIST += $(DBUS_SPECS) diff --git a/libindicator/dbus-shared.h b/libindicator/dbus-shared.h new file mode 100644 index 0000000..f3dbd83 --- /dev/null +++ b/libindicator/dbus-shared.h @@ -0,0 +1,6 @@ + +#define INDICATOR_SERVICE_INTERFACE "org.ayatana.indicator.service" +#define INDICATOR_SERVICE_OBJECT "/org/ayatana/indicator/service" + +#define INDICATOR_SERVICE_VERSION 1 + diff --git a/libindicator/indicator-object.c b/libindicator/indicator-object.c new file mode 100644 index 0000000..0554b48 --- /dev/null +++ b/libindicator/indicator-object.c @@ -0,0 +1,290 @@ +/* +An object to represent loadable indicator modules to make loading +them easy and objectified. + +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 "indicator.h" +#include "indicator-object.h" + +/** + IndicatorObjectPrivate: + @label: The label representing this indicator or #NULL if none. + @icon: The icon representing this indicator or #NULL if none. + @menu: The menu representing this indicator or #NULL if none. + + Structure to define the memory for the private area + of the object instance. +*/ +typedef struct _IndicatorObjectPrivate IndicatorObjectPrivate; +struct _IndicatorObjectPrivate { + GtkLabel * label; + GtkImage * icon; + GtkMenu * menu; +}; + +#define INDICATOR_OBJECT_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_OBJECT_TYPE, IndicatorObjectPrivate)) + +static void indicator_object_class_init (IndicatorObjectClass *klass); +static void indicator_object_init (IndicatorObject *self); +static void indicator_object_dispose (GObject *object); +static void indicator_object_finalize (GObject *object); + +G_DEFINE_TYPE (IndicatorObject, indicator_object, G_TYPE_OBJECT); + +/* Setup the class and put the functions into the + class structure */ +static void +indicator_object_class_init (IndicatorObjectClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (IndicatorObjectPrivate)); + + object_class->dispose = indicator_object_dispose; + object_class->finalize = indicator_object_finalize; + + return; +} + +/* Initialize an instance */ +static void +indicator_object_init (IndicatorObject *self) +{ + IndicatorObjectPrivate * priv = INDICATOR_OBJECT_GET_PRIVATE(self); + + priv->label = NULL; + priv->icon = NULL; + priv->menu = NULL; + + return; +} + +/* Unref the objects that we're holding on to. */ +static void +indicator_object_dispose (GObject *object) +{ + IndicatorObjectPrivate * priv = INDICATOR_OBJECT_GET_PRIVATE(object); + + if (priv->label != NULL) { + g_object_unref(priv->label); + priv->label = NULL; + } + + if (priv->icon != NULL) { + g_object_unref(priv->icon); + priv->icon = NULL; + } + + if (priv->menu != NULL) { + g_object_unref(priv->menu); + priv->menu = NULL; + } + + G_OBJECT_CLASS (indicator_object_parent_class)->dispose (object); + return; +} + +/* Free memory */ +static void +indicator_object_finalize (GObject *object) +{ + + G_OBJECT_CLASS (indicator_object_parent_class)->finalize (object); + return; +} + +/** + indicator_object_new_from_file: + @file: Filename containing a loadable module + + This function builds an #IndicatorObject using the symbols + that are found in @file. The module is loaded and the + references are all kept by the object. To unload the + module the object must be destroyed. + + Return value: A valid #IndicatorObject or #NULL if error. +*/ +IndicatorObject * +indicator_object_new_from_file (const gchar * file) +{ + /* Check to make sure the name exists and that the + file itself exists */ + if (file == NULL) { + g_warning("Invalid filename."); + return NULL; + } + + if (!g_file_test(file, G_FILE_TEST_EXISTS)) { + g_warning("File '%s' does not exist.", file); + return NULL; + } + + /* Grab the g_module reference, pull it in but let's + keep the symbols local to avoid conflicts. */ + GModule * module = g_module_open(file, + G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); + if(module == NULL) { + g_warning("Unable to load module: %s", file); + return NULL; + } + + /* Look for the version function, error if not found. */ + get_version_t lget_version = NULL; + if (!g_module_symbol(module, INDICATOR_GET_VERSION_S, (gpointer *)(&lget_version))) { + g_warning("Unable to get the symbol for getting the version."); + return NULL; + } + + /* Check the version with the macro and make sure we're + all talking the same language. */ + if (!INDICATOR_VERSION_CHECK(lget_version())) { + g_warning("Indicator using API version '%s' we're expecting '%s'", lget_version(), INDICATOR_VERSION); + return NULL; + } + + /* A this point we allocate the object, any code beyond + here needs to deallocate it if we're returning in an + error'd state. */ + GObject * object = g_object_new(INDICATOR_OBJECT_TYPE, NULL); + IndicatorObjectPrivate * priv = INDICATOR_OBJECT_GET_PRIVATE(object); + + /* The function for grabbing a label from the module + execute it, and make sure everything is a-okay */ + get_label_t lget_label = NULL; + if (!g_module_symbol(module, INDICATOR_GET_LABEL_S, (gpointer *)(&lget_label))) { + g_warning("Unable to get '" INDICATOR_GET_LABEL_S "' symbol from module: %s", file); + goto unrefandout; + } + if (lget_label == NULL) { + g_warning("Symbol '" INDICATOR_GET_LABEL_S "' is (null) in module: %s", file); + goto unrefandout; + } + priv->label = lget_label(); + if (priv->label) { + g_object_ref(G_OBJECT(priv->label)); + } + + /* The function for grabbing an icon from the module + execute it, and make sure everything is a-okay */ + get_icon_t lget_icon = NULL; + if (!g_module_symbol(module, INDICATOR_GET_ICON_S, (gpointer *)(&lget_icon))) { + g_warning("Unable to get '" INDICATOR_GET_ICON_S "' symbol from module: %s", file); + goto unrefandout; + } + if (lget_icon == NULL) { + g_warning("Symbol '" INDICATOR_GET_ICON_S "' is (null) in module: %s", file); + goto unrefandout; + } + priv->icon = lget_icon(); + if (priv->icon) { + g_object_ref(G_OBJECT(priv->icon)); + } + + /* The function for grabbing a menu from the module + execute it, and make sure everything is a-okay */ + get_menu_t lget_menu = NULL; + if (!g_module_symbol(module, INDICATOR_GET_MENU_S, (gpointer *)(&lget_menu))) { + g_warning("Unable to get '" INDICATOR_GET_MENU_S "' symbol from module: %s", file); + goto unrefandout; + } + if (lget_menu == NULL) { + g_warning("Symbol '" INDICATOR_GET_MENU_S "' is (null) in module: %s", file); + goto unrefandout; + } + priv->menu = lget_menu(); + if (priv->menu) { + g_object_ref(G_OBJECT(priv->menu)); + } + + if (priv->label == NULL && priv->icon == NULL) { + /* This is the case where there is nothing to display, + kinda odd that we'd have a module with nothing. */ + g_warning("No label or icon. Odd."); + goto unrefandout; + } + + return INDICATOR_OBJECT(object); + + /* Error, let's drop the object and return NULL. Sad when + this happens. */ +unrefandout: + g_object_unref(object); + return NULL; +} + +/** + indicator_object_get_label: + @io: An #IndicatorObject. + + A function to get the label for a particular object. This + function does not increase the refcount. That's your job + if you want to do it. + + Return value: A #GtkLabel or #NULL if unavailable. +*/ +GtkLabel * +indicator_object_get_label (IndicatorObject * io) +{ + g_return_val_if_fail(INDICATOR_IS_OBJECT(io), NULL); + IndicatorObjectPrivate * priv = INDICATOR_OBJECT_GET_PRIVATE(io); + return priv->label; +} + +/** + indicator_object_get_icon: + @io: An #IndicatorObject. + + A function to get the icon for a particular object. This + function does not increase the refcount. That's your job + if you want to do it. + + Return value: A #GtkImage or #NULL if unavailable. +*/ +GtkImage * +indicator_object_get_icon (IndicatorObject * io) +{ + g_return_val_if_fail(INDICATOR_IS_OBJECT(io), NULL); + IndicatorObjectPrivate * priv = INDICATOR_OBJECT_GET_PRIVATE(io); + return priv->icon; +} + +/** + indicator_object_get_menu: + @io: An #IndicatorObject. + + A function to get the menu for a particular object. This + function does not increase the refcount. That's your job + if you want to do it. + + Return value: A #GtkMenu or #NULL if unavailable. +*/ +GtkMenu * +indicator_object_get_menu (IndicatorObject * io) +{ + g_return_val_if_fail(INDICATOR_IS_OBJECT(io), NULL); + IndicatorObjectPrivate * priv = INDICATOR_OBJECT_GET_PRIVATE(io); + return priv->menu; +} diff --git a/libindicator/indicator-object.h b/libindicator/indicator-object.h new file mode 100644 index 0000000..1d2a065 --- /dev/null +++ b/libindicator/indicator-object.h @@ -0,0 +1,61 @@ +/* +An object to represent loadable indicator modules to make loading +them easy and objectified. + +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/>. +*/ + +#ifndef __INDICATOR_OBJECT_H__ +#define __INDICATOR_OBJECT_H__ + +#include <glib.h> +#include <glib-object.h> + +G_BEGIN_DECLS + +#define INDICATOR_OBJECT_TYPE (indicator_object_get_type ()) +#define INDICATOR_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_OBJECT_TYPE, IndicatorObject)) +#define INDICATOR_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_OBJECT_TYPE, IndicatorObjectClass)) +#define INDICATOR_IS_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_OBJECT_TYPE)) +#define INDICATOR_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_OBJECT_TYPE)) +#define INDICATOR_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_OBJECT_TYPE, IndicatorObjectClass)) + +typedef struct _IndicatorObject IndicatorObject; +typedef struct _IndicatorObjectClass IndicatorObjectClass; + +struct _IndicatorObjectClass { + GObjectClass parent_class; + +}; + +struct _IndicatorObject { + GObject parent; + +}; + +GType indicator_object_get_type (void); +IndicatorObject * indicator_object_new_from_file (const gchar * file); + +GtkLabel * indicator_object_get_label (IndicatorObject * io); +GtkImage * indicator_object_get_icon (IndicatorObject * io); +GtkMenu * indicator_object_get_menu (IndicatorObject * io); + +G_END_DECLS + +#endif 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; +} diff --git a/libindicator/indicator-service-manager.h b/libindicator/indicator-service-manager.h new file mode 100644 index 0000000..127d56b --- /dev/null +++ b/libindicator/indicator-service-manager.h @@ -0,0 +1,63 @@ +#ifndef __INDICATOR_SERVICE_MANAGER_H__ +#define __INDICATOR_SERVICE_MANAGER_H__ + +#include <glib.h> +#include <glib-object.h> + +G_BEGIN_DECLS + +#define INDICATOR_SERVICE_MANAGER_TYPE (indicator_service_manager_get_type ()) +#define INDICATOR_SERVICE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_SERVICE_MANAGER_TYPE, IndicatorServiceManager)) +#define INDICATOR_SERVICE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_SERVICE_MANAGER_TYPE, IndicatorServiceManagerClass)) +#define INDICATOR_IS_SERVICE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_SERVICE_MANAGER_TYPE)) +#define INDICATOR_IS_SERVICE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_SERVICE_MANAGER_TYPE)) +#define INDICATOR_SERVICE_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_SERVICE_MANAGER_TYPE, IndicatorServiceManagerClass)) + +#define INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE "connection-change" + +typedef struct _IndicatorServiceManager IndicatorServiceManager; +typedef struct _IndicatorServiceManagerClass IndicatorServiceManagerClass; + +/** + IndicatorServiceManagerClass: + @parent: #GObjectClass + @connection_changed: Slot for #IndicatorServiceManager::connection-changed. + @indicator_service_manager_reserved1: Reserved for future use. + @indicator_service_manager_reserved2: Reserved for future use. + @indicator_service_manager_reserved3: Reserved for future use. + @indicator_service_manager_reserved4: Reserved for future use. + +*/ +struct _IndicatorServiceManagerClass { + GObjectClass parent_class; + + /* Signals */ + void (*connection_change) (IndicatorServiceManager * sm, gboolean connected, gpointer user_data); + + /* Buffer */ + void (*indicator_service_manager_reserved1) (void); + void (*indicator_service_manager_reserved2) (void); + void (*indicator_service_manager_reserved3) (void); + void (*indicator_service_manager_reserved4) (void); +}; + +/** + IndicatorServiceManager: + @parent: #GObject + +*/ +struct _IndicatorServiceManager { + GObject parent; + +}; + +GType indicator_service_manager_get_type (void); + +IndicatorServiceManager * indicator_service_manager_new (gchar * dbus_name); +gboolean indicator_service_manager_connected (IndicatorServiceManager * sm); +void indicator_service_manager_set_refresh (IndicatorServiceManager * sm, + guint time_in_ms); + +G_END_DECLS + +#endif diff --git a/libindicator/indicator-service.c b/libindicator/indicator-service.c new file mode 100644 index 0000000..69422c5 --- /dev/null +++ b/libindicator/indicator-service.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.h" + +/* DBus Prototypes */ +static gboolean _indicator_service_server_watch (IndicatorService * service, DBusGMethodInvocation * method); + +#include "indicator-service-server.h" +#include "dbus-shared.h" + +/* Private Stuff */ +typedef struct _IndicatorServicePrivate IndicatorServicePrivate; + +struct _IndicatorServicePrivate { + gchar * name; + DBusGProxy * dbus_proxy; + guint timeout; + GList * watchers; +}; + +/* 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, +}; + +/* The strings so that they can be slowly looked up. */ +#define PROP_NAME_S "name" + +/* 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); + +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)); + + /* 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); + + /* Initialize the object as a DBus type */ + dbus_g_object_type_install_info(INDICATOR_SERVICE_TYPE, + &dbus_glib__indicator_service_server_object_info); + + return; +} + +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->dbus_proxy = NULL; + priv->timeout = 0; + priv->watchers = NULL; + + /* Start talkin' dbus */ + GError * error = NULL; + DBusGConnection * 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; + 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(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; + } + + dbus_g_connection_register_g_object(bus, + INDICATOR_SERVICE_OBJECT, + G_OBJECT(self)); + + return; +} + +static void +indicator_service_dispose (GObject *object) +{ + IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(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; + } + + G_OBJECT_CLASS (indicator_service_parent_class)->dispose (object); + return; +} + +static void +indicator_service_finalize (GObject *object) +{ + IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(object); + + if (priv->name != NULL) { + g_free(priv->name); + } + + if (priv->watchers != NULL) { + g_list_foreach(priv->watchers, (GFunc)g_free, NULL); + g_list_free(priv->watchers); + priv->watchers = NULL; + } + + G_OBJECT_CLASS (indicator_service_parent_class)->finalize (object); + return; +} + +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; + /* *********************** */ + 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) +{ + 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; + /* *********************** */ + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + + return; +} + +static gboolean +timeout_no_watchers (gpointer data) +{ + g_signal_emit(G_OBJECT(data), signals[SHUTDOWN], 0, TRUE); + return FALSE; +} + +static void +try_and_get_name_cb (DBusGProxy * proxy, guint status, GError * error, gpointer data) +{ + IndicatorService * service = INDICATOR_SERVICE(data); + g_return_if_fail(service != NULL); + + 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_signal_emit(G_OBJECT(data), signals[SHUTDOWN], 0, TRUE); + return; + } + + IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(service); + priv->timeout = g_timeout_add(500, timeout_no_watchers, service); + + return; +} + +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); + + return; +} + +static gboolean +_indicator_service_server_watch (IndicatorService * service, DBusGMethodInvocation * method) +{ + g_return_val_if_fail(INDICATOR_IS_SERVICE(service), FALSE); + IndicatorServicePrivate * priv = INDICATOR_SERVICE_GET_PRIVATE(service); + + priv->watchers = g_list_append(priv->watchers, + g_strdup(dbus_g_method_get_sender(method))); + + if (priv->timeout != 0) { + g_source_remove(priv->timeout); + priv->timeout = 0; + } + + dbus_g_method_return(method, 1); + return TRUE; +} + +/* 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); +} diff --git a/libindicator/indicator-service.h b/libindicator/indicator-service.h new file mode 100644 index 0000000..b47a91a --- /dev/null +++ b/libindicator/indicator-service.h @@ -0,0 +1,60 @@ +#ifndef __INDICATOR_SERVICE_H__ +#define __INDICATOR_SERVICE_H__ + +#include <glib.h> +#include <glib-object.h> + +G_BEGIN_DECLS + +#define INDICATOR_SERVICE_TYPE (indicator_service_get_type ()) +#define INDICATOR_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_SERVICE_TYPE, IndicatorService)) +#define INDICATOR_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_SERVICE_TYPE, IndicatorServiceClass)) +#define INDICATOR_IS_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_SERVICE_TYPE)) +#define INDICATOR_IS_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_SERVICE_TYPE)) +#define INDICATOR_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_SERVICE_TYPE, IndicatorServiceClass)) + +#define INDICATOR_SERVICE_SIGNAL_SHUTDOWN "shutdown" + +typedef struct _IndicatorService IndicatorService; +typedef struct _IndicatorServiceClass IndicatorServiceClass; + +/** + IndicatorServiceClass: + @parent_class: #GObjectClass + @shutdown: Slot for IndicatorServiceClass::shutdown + @indicator_service_reserved1: Reserved for future use + @indicator_service_reserved2: Reserved for future use + @indicator_service_reserved3: Reserved for future use + @indicator_service_reserved4: Reserved for future use + +*/ +struct _IndicatorServiceClass { + GObjectClass parent_class; + + /* Signals */ + void (*shutdown) (IndicatorService * service, gpointer user_data); + + /* Reserved */ + void (*indicator_service_reserved1) (void); + void (*indicator_service_reserved2) (void); + void (*indicator_service_reserved3) (void); + void (*indicator_service_reserved4) (void); +}; + +/** + IndicatorService: + @parent: #GObject + +*/ +struct _IndicatorService { + GObject parent; + +}; + +GType indicator_service_get_type (void); + +IndicatorService * indicator_service_new (gchar * name); + +G_END_DECLS + +#endif diff --git a/libindicator/indicator-service.xml b/libindicator/indicator-service.xml new file mode 100644 index 0000000..d876ea8 --- /dev/null +++ b/libindicator/indicator-service.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<node name="/"> + <interface name="org.ayatana.indicator.service"> +<!-- Properties --> + <!-- None currently --> + +<!-- Methods --> + <method name="Watch"> + <annotation name="org.freedesktop.DBus.GLib.Async" value="true" /> + <arg type="i" name="version" direction="out" /> + </method> + +<!-- Signals --> + <!-- None currently --> + + </interface> +</node> diff --git a/libindicator/indicator.pc.in b/libindicator/indicator.pc.in index 2835115..9a8169e 100644 --- a/libindicator/indicator.pc.in +++ b/libindicator/indicator.pc.in @@ -9,7 +9,7 @@ iconsdir=@datarootdir@/@PACKAGE@/icons/ Cflags: -I${includedir}/libindicator-0.1 Requires: gtk+-2.0 -Libs: +Libs: -lindicator Name: libindicator Description: libindicator. diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 0000000..7c306bc --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,189 @@ +TESTS = +DISTCLEANFILES = + +check_PROGRAMS = \ + test-loader \ + service-manager-no-connect \ + service-manager-connect \ + service-manager-connect-service \ + service-shutdown-timeout + +lib_LTLIBRARIES = \ + libdummy-indicator-blank.la \ + libdummy-indicator-null.la \ + libdummy-indicator-simple.la + +DBUS_RUNNER=dbus-test-runner --dbus-config /usr/share/dbus-test-runner/session.conf + +############################# +# Test Loader +############################# + +test_loader_SOURCES = \ + test-loader.c + +test_loader_CFLAGS = \ + -Wall -Werror \ + $(LIBINDICATOR_CFLAGS) -I$(top_srcdir) \ + -DBUILD_DIR="\"$(builddir)\"" + +test_loader_LDADD = \ + $(LIBINDICATOR_LIBS) $(top_builddir)/libindicator/.libs/libindicator.a + +############################# +# Dummy Indicator Blank +############################# + +libdummy_indicator_blank_la_SOURCES = \ + dummy-indicator-blank.c + +libdummy_indicator_blank_la_CFLAGS = \ + -Wall -Werror \ + $(LIBINDICATOR_CFLAGS) -I$(top_srcdir) + +libdummy_indicator_blank_la_LIBADD = \ + $(LIBINDICATOR_LIBS) + +libdummy_indicator_blank_la_LDFLAGS = \ + -module \ + -avoid-version + +############################# +# Dummy Indicator NULL +############################# + +libdummy_indicator_null_la_SOURCES = \ + dummy-indicator-null.c + +libdummy_indicator_null_la_CFLAGS = \ + -Wall -Werror \ + $(LIBINDICATOR_CFLAGS) -I$(top_srcdir) + +libdummy_indicator_null_la_LIBADD = \ + $(LIBINDICATOR_LIBS) + +libdummy_indicator_null_la_LDFLAGS = \ + -module \ + -avoid-version + +############################# +# Dummy Indicator Simple +############################# + +libdummy_indicator_simple_la_SOURCES = \ + dummy-indicator-simple.c + +libdummy_indicator_simple_la_CFLAGS = \ + -Wall -Werror \ + $(LIBINDICATOR_CFLAGS) -I$(top_srcdir) + +libdummy_indicator_simple_la_LIBADD = \ + $(LIBINDICATOR_LIBS) + +libdummy_indicator_simple_la_LDFLAGS = \ + -module \ + -avoid-version + +############################# +# Service Shutdown Timeout +############################# + +service_shutdown_timeout_SOURCES = \ + service-shutdown-timeout.c + +service_shutdown_timeout_CFLAGS = \ + -Wall -Werror \ + $(LIBINDICATOR_CFLAGS) -I$(top_srcdir) + +service_shutdown_timeout_LDADD = \ + $(LIBINDICATOR_LIBS) \ + $(top_builddir)/libindicator/.libs/libindicator.a + +service-shutdown-timeout-tester: service-shutdown-timeout Makefile + @echo "#!/bin/sh" > service-shutdown-timeout-tester + @echo $(DBUS_RUNNER) --task ./service-shutdown-timeout >> service-shutdown-timeout-tester + @chmod +x service-shutdown-timeout-tester + +TESTS += service-shutdown-timeout-tester +DISTCLEANFILES += service-shutdown-timeout-tester + +############################# +# Service Manager No Connect +############################# + +service_manager_no_connect_SOURCES = \ + service-manager-no-connect.c + +service_manager_no_connect_CFLAGS = \ + -Wall -Werror \ + $(LIBINDICATOR_CFLAGS) -I$(top_srcdir) + +service_manager_no_connect_LDADD = \ + $(LIBINDICATOR_LIBS) \ + $(top_builddir)/libindicator/.libs/libindicator.a + +service-manager-no-connect-tester: service-manager-no-connect Makefile.am + @echo "#!/bin/sh" > service-manager-no-connect-tester + @echo $(DBUS_RUNNER) --task ./service-manager-no-connect >> service-manager-no-connect-tester + @chmod +x service-manager-no-connect-tester + +TESTS += service-manager-no-connect-tester +DISTCLEANFILES += service-manager-no-connect-tester + +############################# +# Service Manager Connect +############################# + +session.conf: $(srcdir)/session.conf.in Makefile.am + sed -e "s|\@servicedir\@|$(abspath $(builddir))|" $< > $@ + +service-manager-connect.service: $(srcdir)/service-manager-connect.service.in Makefile.am + sed -e "s|\@builddir\@|$(abspath $(builddir))|" $< > $@ + +service_manager_connect_SOURCES = \ + service-manager-connect.c + +service_manager_connect_CFLAGS = \ + -Wall -Werror \ + $(LIBINDICATOR_CFLAGS) -I$(top_srcdir) + +service_manager_connect_LDADD = \ + $(LIBINDICATOR_LIBS) \ + $(top_builddir)/libindicator/.libs/libindicator.a + +service_manager_connect_service_SOURCES = \ + service-manager-connect-service.c + +service_manager_connect_service_CFLAGS = \ + -Wall -Werror \ + $(LIBINDICATOR_CFLAGS) -I$(top_srcdir) + +service_manager_connect_service_LDADD = \ + $(LIBINDICATOR_LIBS) \ + $(top_builddir)/libindicator/.libs/libindicator.a + +service-manager-connect-tester: service-manager-connect service-manager-connect-service session.conf service-manager-connect.service Makefile.am + @echo "#!/bin/sh" > service-manager-connect-tester + @echo dbus-test-runner --dbus-config $(builddir)/session.conf --task ./service-manager-connect >> service-manager-connect-tester + @chmod +x service-manager-connect-tester + +TESTS += service-manager-connect-tester +DISTCLEANFILES += service-manager-connect-tester session.conf service-manager-connect.service + +############################# +# Test stuff +############################# + +XML_REPORT = loader-check-results.xml +HTML_REPORT = loader-check-results.html + +loader-tester: test-loader libdummy-indicator-null.la libdummy-indicator-simple.la Makefile + @echo "#!/bin/sh" > loader-tester + @echo gtester -k --verbose -o=$(XML_REPORT) ./test-loader >> loader-tester + @chmod +x loader-tester + +TESTS += loader-tester +DISTCLEANFILES += loader-tester + +DISTCLEANFILES += $(XML_REPORT) $(HTML_REPORT) + diff --git a/tests/dummy-indicator-blank.c b/tests/dummy-indicator-blank.c new file mode 100644 index 0000000..41249f2 --- /dev/null +++ b/tests/dummy-indicator-blank.c @@ -0,0 +1,6 @@ + +#include "libindicator/indicator.h" + +INDICATOR_SET_VERSION +INDICATOR_SET_NAME("dummy-indicator-null") + diff --git a/tests/dummy-indicator-null.c b/tests/dummy-indicator-null.c new file mode 100644 index 0000000..ff99d71 --- /dev/null +++ b/tests/dummy-indicator-null.c @@ -0,0 +1,23 @@ + +#include "libindicator/indicator.h" + +INDICATOR_SET_VERSION +INDICATOR_SET_NAME("dummy-indicator-null") + +GtkLabel * +get_label (void) +{ + return NULL; +} + +GtkImage * +get_icon (void) +{ + return NULL; +} + +GtkMenu * +get_menu (void) +{ + return NULL; +} diff --git a/tests/dummy-indicator-simple.c b/tests/dummy-indicator-simple.c new file mode 100644 index 0000000..cee4eac --- /dev/null +++ b/tests/dummy-indicator-simple.c @@ -0,0 +1,28 @@ + +#include "libindicator/indicator.h" + +INDICATOR_SET_VERSION +INDICATOR_SET_NAME("dummy-indicator-simple") + +GtkLabel * +get_label (void) +{ + return GTK_LABEL(gtk_label_new("Simple Item")); +} + +GtkImage * +get_icon (void) +{ + return GTK_IMAGE(gtk_image_new()); +} + +GtkMenu * +get_menu (void) +{ + GtkMenu * main_menu = GTK_MENU(gtk_menu_new()); + GtkWidget * loading_item = gtk_menu_item_new_with_label("Loading..."); + gtk_menu_shell_append(GTK_MENU_SHELL(main_menu), loading_item); + gtk_widget_show(GTK_WIDGET(loading_item)); + + return main_menu; +} diff --git a/tests/service-manager-connect-service.c b/tests/service-manager-connect-service.c new file mode 100644 index 0000000..297f3ba --- /dev/null +++ b/tests/service-manager-connect-service.c @@ -0,0 +1,46 @@ + +#include <glib.h> +#include "libindicator/indicator-service.h" + +static GMainLoop * mainloop = NULL; +static gboolean passed = FALSE; + +gboolean +timeout (gpointer data) +{ + passed = TRUE; + g_debug("Timeout with no shutdown."); + g_main_loop_quit(mainloop); + return FALSE; +} + +void +shutdown (void) +{ + g_error("Shutdown"); + passed = FALSE; + g_main_loop_quit(mainloop); + return; +} + +int +main (int argc, char ** argv) +{ + g_type_init(); + + IndicatorService * is = indicator_service_new("org.ayatana.test"); + g_signal_connect(G_OBJECT(is), INDICATOR_SERVICE_SIGNAL_SHUTDOWN, shutdown, NULL); + + g_timeout_add_seconds(1, timeout, NULL); + + mainloop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(mainloop); + + g_debug("Quiting"); + if (passed) { + g_debug("Passed"); + return 0; + } + g_debug("Failed"); + return 1; +} diff --git a/tests/service-manager-connect.c b/tests/service-manager-connect.c new file mode 100644 index 0000000..c252542 --- /dev/null +++ b/tests/service-manager-connect.c @@ -0,0 +1,47 @@ + +#include <glib.h> +#include "libindicator/indicator-service-manager.h" + +static GMainLoop * mainloop = NULL; +static gboolean passed = FALSE; + +gboolean +timeout (gpointer data) +{ + passed = FALSE; + g_error("Timeout with no connection."); + g_main_loop_quit(mainloop); + return FALSE; +} + +void +connection (void) +{ + g_debug("Connection"); + passed = TRUE; + g_main_loop_quit(mainloop); + return; +} + +int +main (int argc, char ** argv) +{ + g_type_init(); + g_log_set_always_fatal(G_LOG_LEVEL_CRITICAL); + + IndicatorServiceManager * is = indicator_service_manager_new("org.ayatana.test"); + g_signal_connect(G_OBJECT(is), INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, connection, NULL); + + g_timeout_add_seconds(1, timeout, NULL); + + mainloop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(mainloop); + + g_debug("Quiting"); + if (passed) { + g_debug("Passed"); + return 0; + } + g_debug("Failed"); + return 1; +} diff --git a/tests/service-manager-connect.service.in b/tests/service-manager-connect.service.in new file mode 100644 index 0000000..7d3da6b --- /dev/null +++ b/tests/service-manager-connect.service.in @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.ayatana.test +Exec=@builddir@/service-manager-connect-service diff --git a/tests/service-manager-no-connect.c b/tests/service-manager-no-connect.c new file mode 100644 index 0000000..1c32eb2 --- /dev/null +++ b/tests/service-manager-no-connect.c @@ -0,0 +1,47 @@ + +#include <glib.h> +#include "libindicator/indicator-service-manager.h" + +static GMainLoop * mainloop = NULL; +static gboolean passed = FALSE; + +gboolean +timeout (gpointer data) +{ + passed = TRUE; + g_debug("Timeout with no connection."); + g_main_loop_quit(mainloop); + return FALSE; +} + +void +connection (void) +{ + g_debug("Connection"); + passed = FALSE; + g_main_loop_quit(mainloop); + return; +} + +int +main (int argc, char ** argv) +{ + g_type_init(); + g_log_set_always_fatal(G_LOG_LEVEL_CRITICAL); + + IndicatorServiceManager * is = indicator_service_manager_new("my.test.name"); + g_signal_connect(G_OBJECT(is), INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, connection, NULL); + + g_timeout_add_seconds(1, timeout, NULL); + + mainloop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(mainloop); + + g_debug("Quiting"); + if (passed) { + g_debug("Passed"); + return 0; + } + g_debug("Failed"); + return 1; +} diff --git a/tests/service-shutdown-timeout.c b/tests/service-shutdown-timeout.c new file mode 100644 index 0000000..666739a --- /dev/null +++ b/tests/service-shutdown-timeout.c @@ -0,0 +1,46 @@ + +#include <glib.h> +#include "libindicator/indicator-service.h" + +static GMainLoop * mainloop = NULL; +static gboolean passed = FALSE; + +gboolean +timeout (gpointer data) +{ + passed = FALSE; + g_error("Timeout with no shutdown."); + g_main_loop_quit(mainloop); + return FALSE; +} + +void +shutdown (void) +{ + g_debug("Shutdown"); + passed = TRUE; + g_main_loop_quit(mainloop); + return; +} + +int +main (int argc, char ** argv) +{ + g_type_init(); + + IndicatorService * is = indicator_service_new("my.test.name"); + g_signal_connect(G_OBJECT(is), INDICATOR_SERVICE_SIGNAL_SHUTDOWN, shutdown, NULL); + + g_timeout_add_seconds(1, timeout, NULL); + + mainloop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(mainloop); + + g_debug("Quiting"); + if (passed) { + g_debug("Passed"); + return 0; + } + g_debug("Failed"); + return 1; +} diff --git a/tests/session.conf.in b/tests/session.conf.in new file mode 100644 index 0000000..d1e2805 --- /dev/null +++ b/tests/session.conf.in @@ -0,0 +1,40 @@ +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> +<busconfig> + <!-- If we fork, keep the user's original umask to avoid affecting + the behavior of child processes. --> + <keep_umask/> + + <listen>unix:tmpdir=/tmp</listen> + + <servicedir>@servicedir@</servicedir> + + <policy context="default"> + <!-- Allow everything to be sent --> + <allow send_destination="*" eavesdrop="true"/> + <!-- Allow everything to be received --> + <allow eavesdrop="true"/> + <!-- Allow anyone to own anything --> + <allow own="*"/> + </policy> + + <!-- raise the service start timeout to 40 seconds as it can timeout + on the live cd on slow machines --> + <limit name="service_start_timeout">60000</limit> + + <!-- the memory limits are 1G instead of say 4G because they can't exceed 32-bit signed int max --> + <limit name="max_incoming_bytes">1000000000</limit> + <limit name="max_outgoing_bytes">1000000000</limit> + <limit name="max_message_size">1000000000</limit> + <limit name="service_start_timeout">120000</limit> + <limit name="auth_timeout">240000</limit> + <limit name="max_completed_connections">100000</limit> + <limit name="max_incomplete_connections">10000</limit> + <limit name="max_connections_per_user">100000</limit> + <limit name="max_pending_service_starts">10000</limit> + <limit name="max_names_per_connection">50000</limit> + <limit name="max_match_rules_per_connection">50000</limit> + <limit name="max_replies_per_connection">50000</limit> + <limit name="reply_timeout">300000</limit> + +</busconfig> diff --git a/tests/test-loader.c b/tests/test-loader.c new file mode 100644 index 0000000..4b2b096 --- /dev/null +++ b/tests/test-loader.c @@ -0,0 +1,109 @@ +#include <gtk/gtk.h> +#include "libindicator/indicator-object.h" + +void destroy_cb (gpointer data, GObject * object); + +void +test_loader_filename_dummy_simple_accessors (void) +{ + IndicatorObject * object = indicator_object_new_from_file(BUILD_DIR "/.libs/libdummy-indicator-simple.so"); + g_assert(object != NULL); + + g_assert(indicator_object_get_label(object) != NULL); + g_assert(indicator_object_get_menu(object) != NULL); + g_assert(indicator_object_get_icon(object) != NULL); + + g_object_unref(object); + + return; +} + +void +test_loader_filename_dummy_simple (void) +{ + IndicatorObject * object = indicator_object_new_from_file(BUILD_DIR "/.libs/libdummy-indicator-simple.so"); + g_assert(object != NULL); + + gboolean unreffed = FALSE; + g_object_weak_ref(G_OBJECT(object), destroy_cb, &unreffed); + + g_object_unref(object); + g_assert(unreffed == TRUE); + + return; +} + +void +test_loader_filename_dummy_blank (void) +{ + IndicatorObject * object = indicator_object_new_from_file(BUILD_DIR "/.libs/libdummy-indicator-blank.so"); + g_assert(object == NULL); + return; +} + +void +test_loader_filename_dummy_null (void) +{ + IndicatorObject * object = indicator_object_new_from_file(BUILD_DIR "/.libs/libdummy-indicator-null.so"); + g_assert(object == NULL); + return; +} + +void +test_loader_filename_bad (void) +{ + IndicatorObject * object = indicator_object_new_from_file("/this/file/should/not/exist.so"); + g_assert(object == NULL); + return; +} + +void +destroy_cb (gpointer data, GObject * object) +{ + gboolean * bob = (gboolean *)data; + *bob = TRUE; + return; +} + +void +test_loader_refunref (void) +{ + GObject * object = g_object_new(INDICATOR_OBJECT_TYPE, NULL); + + gboolean unreffed = FALSE; + g_object_weak_ref(object, destroy_cb, &unreffed); + + g_object_unref(object); + + g_assert(unreffed == TRUE); + + return; +} + +void +test_loader_creation_deletion_suite (void) +{ + g_test_add_func ("/libindicator/loader/ref_and_unref", test_loader_refunref); + g_test_add_func ("/libindicator/loader/filename_bad", test_loader_filename_bad); + g_test_add_func ("/libindicator/loader/dummy/null_load", test_loader_filename_dummy_null); + g_test_add_func ("/libindicator/loader/dummy/blank_load", test_loader_filename_dummy_null); + g_test_add_func ("/libindicator/loader/dummy/simple_load", test_loader_filename_dummy_simple); + g_test_add_func ("/libindicator/loader/dummy/simple_accessors", test_loader_filename_dummy_simple_accessors); + + return; +} + + +int +main (int argc, char ** argv) +{ + g_type_init (); + g_test_init (&argc, &argv, NULL); + gtk_init(&argc, &argv); + + test_loader_creation_deletion_suite(); + + g_log_set_always_fatal(G_LOG_LEVEL_CRITICAL); + + return g_test_run(); +} diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 0000000..9de44fc --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1 @@ +#Something |