Re: Gnome Session Services Framework
- From: Rodrigo Moya <rodrigo gnome-db org>
- To: Ray Strode <halfline gmail com>
- Cc: "John \(J5\) Palmieri" <johnp redhat com>, desktop-devel-list gnome org
- Subject: Re: Gnome Session Services Framework
- Date: Tue, 12 Jul 2005 13:47:40 +0200
On Mon, 2005-07-11 at 13:05 -0400, Ray Strode wrote:
> Hi,
> > Updated patch attached
>
> So a few comments...
> You shoulnd't start the session until all the services are done loading.
>
> You shouldn't need the is_done function. Instead connect to the
> "startup-complete" signal of the service manager object.
>
right, updated patch attached which starts the session on the
startup-complete signal when using services, and a little addition to
gsm_service_manager_start_services_and_dependencies, to emit the
startup-complete signal, which was not being emitted.
Attaching the whole patch again, sorry list admins :)
--
Rodrigo Moya <rodrigo gnome-db org>
? compile
? depcomp
? stamp-h1
? gnome-session/gsm-dbus-utils.c
? gnome-session/gsm-dbus-utils.h
? gnome-session/gsm-service-manager.c
? gnome-session/gsm-service-manager.h
? gnome-session/gsm-service.c
? gnome-session/gsm-service.h
? gnome-session/service-manager-test
? gnome-session/session-properties.desktop.in
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gnome-session/ChangeLog,v
retrieving revision 1.591
diff -u -p -r1.591 ChangeLog
--- ChangeLog 3 Jul 2005 18:50:14 -0000 1.591
+++ ChangeLog 12 Jul 2005 11:51:11 -0000
@@ -1,3 +1,10 @@
+2005-07-11 Rodrigo Moya <rodrigo novell com>
+
+ Original patch by Ray Strode <rstrode redhat com>
+
+ * configure.in: added --enable-services flag to compile services code
+ conditionally.
+
2005-07-03 Aivars Kalvans <aivars kalvans inbox lv>
* configure.in: smproxy requires glib-2.0, does not require libgnome
Index: configure.in
===================================================================
RCS file: /cvs/gnome/gnome-session/configure.in,v
retrieving revision 1.511
diff -u -p -r1.511 configure.in
--- configure.in 3 Jul 2005 18:50:14 -0000 1.511
+++ configure.in 12 Jul 2005 11:51:11 -0000
@@ -61,6 +61,22 @@ PKG_CHECK_MODULES(GNOME_SESSION, gtk+-2.
PKG_CHECK_MODULES(SMPROXY, glib-2.0)
+dnl See if we build the services code
+enable_services=no
+build_services=no
+AC_ARG_ENABLE(services, [ --enable-services=[no/yes] enable services code], enable_services=yes, enable_services=no)
+if test "x$enable_services" = "xyes"; then
+ PKG_CHECK_MODULES(DBUS, dbus-1 dbus-glib-1, have_dbus=yes, have_dbus=no)
+ if test "x$have_dbus" = "xyes"; then
+ build_services=yes
+ AC_SUBST(DBUS_CFLAGS)
+ AC_SUBST(DBUS_LIBS)
+ AC_DEFINE(BUILD_SERVICES, 1, [Whether to build services code or not])
+ fi
+fi
+
+AM_CONDITIONAL(BUILD_SERVICES, test "x$build_services" = "xyes")
+
dnl gconf checks
AC_PATH_PROG(GCONFTOOL, gconftool-2, no)
Index: gnome-session/ChangeLog
===================================================================
RCS file: /cvs/gnome/gnome-session/gnome-session/ChangeLog,v
retrieving revision 1.448
diff -u -p -r1.448 ChangeLog
--- gnome-session/ChangeLog 21 Jun 2005 01:24:27 -0000 1.448
+++ gnome-session/ChangeLog 12 Jul 2005 11:51:12 -0000
@@ -1,3 +1,17 @@
+2005-07-11 Rodrigo Moya <rodrigo novell com>
+
+ Original patch by Ray Strode <rstrode redhat com>
+
+ * gnome-session/Makefile.am: added DBUS_CFLAGS/LIBS and conditionally
+ compile the services-related source files.
+
+ * gnome-session/main.c: added #ifdef'ed code for new service activation
+ framework, to be compiled conditionally.
+
+ * gnome-session/gsm-dbus-utils.[ch]:
+ * gnome-session/gsm-service.[ch]:
+ * gnome-session/gsm-service-manager.[ch]: new files.
+
2005-06-20 Federico Mena Quintero <federico ximian com>
* main.c (main): Free the result of gdk_get_display(). Fixes
Index: gnome-session/Makefile.am
===================================================================
RCS file: /cvs/gnome/gnome-session/gnome-session/Makefile.am,v
retrieving revision 1.108
diff -u -p -r1.108 Makefile.am
--- gnome-session/Makefile.am 10 Jan 2005 16:36:40 -0000 1.108
+++ gnome-session/Makefile.am 12 Jul 2005 11:51:12 -0000
@@ -16,7 +16,9 @@ INCLUDES = \
-DRSH_COMMAND=\""$(RSH_COMMAND)\"" \
-DGCONFTOOL_CMD=\""$(GCONFTOOL)\"" \
-DDEFAULTDIR="\"$(defaultdir)\"" \
- -DESD_SERVER="\"$(ESD_SERVER)\""
+ -DESD_SERVER="\"$(ESD_SERVER)\"" \
+ -DDBUS_API_SUBJECT_TO_CHANGE \
+ $(DBUS_CFLAGS)
# Used by the GNOME_PROGRAM_STANDARD_PROPERTIES macros
STANDARD_PROPERTIES_CFLAGS = \
@@ -26,7 +28,8 @@ STANDARD_PROPERTIES_CFLAGS =
-DDATADIR=\""$(datadir)"\" \
$(NULL)
-gnome_session_LDADD = $(X_LIBS) $(GNOME_SESSION_LIBS) $(LIBWRAP_LIBS)
+gnome_session_CFLAGS = -DDEBUG
+gnome_session_LDADD = $(X_LIBS) $(GNOME_SESSION_LIBS) $(LIBWRAP_LIBS) $(DBUS_LIBS)
gnome_session_save_LDADD = $(GNOME_SESSION_LIBS)
gnome_session_remove_LDADD = $(GNOME_SESSION_LIBS)
gnome_session_properties_LDADD = $(GNOME_SESSION_LIBS)
@@ -70,6 +73,18 @@ logout_test_SOURCES = \
gdm-logout-action.h \
$(EGGFILES)
+if BUILD_SERVICES
+services_source_files = \
+ gsm-dbus-utils.c \
+ gsm-dbus-utils.h \
+ gsm-service.c \
+ gsm-service.h \
+ gsm-service-manager.c \
+ gsm-service-manager.h
+else
+services_source_files =
+endif
+
gnome_session_SOURCES = \
manager.c \
manager.h \
@@ -89,6 +104,7 @@ gnome_session_SOURCES = \
logout.h \
splash-widget.c \
splash-widget.h \
+ $(services_source_files)\
gsm-xrandr.c \
gsm-xrandr.h \
gsm-keyring.c \
Index: gnome-session/gsm-marshal.list
===================================================================
RCS file: /cvs/gnome/gnome-session/gnome-session/gsm-marshal.list,v
retrieving revision 1.1
diff -u -p -r1.1 gsm-marshal.list
--- gnome-session/gsm-marshal.list 27 Sep 2001 14:55:01 -0000 1.1
+++ gnome-session/gsm-marshal.list 12 Jul 2005 11:51:12 -0000
@@ -1 +1,2 @@
NONE:INT,POINTER
+
Index: gnome-session/main.c
===================================================================
RCS file: /cvs/gnome/gnome-session/gnome-session/main.c,v
retrieving revision 1.66
diff -u -p -r1.66 main.c
--- gnome-session/main.c 21 Jun 2005 01:24:27 -0000 1.66
+++ gnome-session/main.c 12 Jul 2005 11:51:12 -0000
@@ -48,6 +48,10 @@
#include "gsm-xrandr.h"
#include "gsm-at-startup.h"
#include "gsm-remote-desktop.h"
+#ifdef BUILD_SERVICES
+#include "gsm-service-manager.h"
+#include "gsm-service.h"
+#endif
/* Flag indicating autosave - user won't be prompted on logout to
* save the session */
@@ -313,15 +317,50 @@ gsm_shutdown_gconfd (void)
g_free (command);
}
+static gboolean splashing;
+static gboolean a_t_support;
+
+static void
+try_start_session (void)
+{
+ char *session_name_env;
+ Session *the_session;
+
+ session_name_env = g_strconcat ("GNOME_DESKTOP_SESSION_ID=", session_name, NULL);
+ putenv (session_name_env);
+ the_session = read_session (session_name);
+
+ gsm_sound_login ();
+
+ gsm_gsd_start ();
+
+ gsm_remote_desktop_start ();
+
+ if (splashing)
+ splash_start ();
+
+ start_session (the_session);
+
+ if (a_t_support) /* the ATs are happier if the session has started */
+ gsm_assistive_technologies_start ();
+}
+
+#ifdef BUILD_SERVICES
+static void
+service_startup_complete_cb (GsmServiceManager *service_manager)
+{
+ try_start_session ();
+}
+#endif
+
int
main (int argc, char *argv[])
{
char *ep;
- char *session_name_env;
- Session *the_session;
+#ifdef BUILD_SERVICES
+ GsmServiceManager *service_manager;
+#endif
GConfClient *gconf_client;
- gboolean splashing;
- gboolean a_t_support;
GError *err;
int status;
char *display_str;
@@ -377,8 +416,8 @@ main (int argc, char *argv[])
GNOME_PARAM_POPT_TABLE, options,
NULL);
- /* FIXME: it would be nice to skip this check if we're debugging the
- session manager. */
+ /* FIXME: it would be nice to skip this check if we're debugging the
+ session manager. */
if (GNOME_CLIENT_CONNECTED (gnome_master_client ()))
{
@@ -400,9 +439,11 @@ main (int argc, char *argv[])
ignore (SIGPIPE);
+#ifndef BUILD_SERVICES
/* Need DISPLAY set */
gsm_keyring_daemon_start ();
-
+#endif
+
/* Read in config options */
gconf_client = gconf_client_get_default ();
@@ -450,32 +491,36 @@ main (int argc, char *argv[])
if(failsafe)
session_name = FAILSAFE_SESSION;
- session_name_env = g_strconcat ("GNOME_DESKTOP_SESSION_ID=", session_name, NULL);
- putenv (session_name_env);
- the_session = read_session (session_name);
-
- gsm_sound_login ();
-
- gsm_gsd_start ();
-
- gsm_remote_desktop_start ();
-
- if (splashing)
- splash_start ();
+#ifdef BUILD_SERVICES
+ /* Start services that are registered with D-BUS
+ */
+ service_manager = gsm_service_manager_new ();
+ g_signal_connect (G_OBJECT (service_manager), "startup-complete", G_CALLBACK (service_startup_complete_cb), NULL);
- start_session (the_session);
+ if (!gsm_service_manager_connect_to_bus (service_manager))
+ return 1;
- if (a_t_support) /* the ATs are happier if the session has started */
- gsm_assistive_technologies_start ();
+ gsm_service_manager_start (service_manager);
+#else
+ try_start_session ();
+#endif
gtk_main ();
+#ifdef BUILD_SERVICES
+ gsm_service_manager_stop (service_manager);
+ g_object_unref (service_manager);
+
+#else
gsm_remote_desktop_cleanup ();
+#endif
gsm_sound_logout ();
+#ifndef BUILD_SERVICES
gsm_keyring_daemon_stop ();
-
+#endif
+
gsm_shutdown_gconfd ();
clean_ice ();
/* gsm-dbus-utils.c - D-Bus related convenience functions
*
* Copyright (C) 2005 Ray Strode
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include "gsm-dbus-utils.h"
#include <glib.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
struct _GsmDBusMethodCall
{
DBusConnection *connection;
DBusPendingCall *pending_call;
GsmDBusMethodCallReplyFunc reply_func;
gpointer reply_func_data;
GDestroyNotify free_func;
};
static void
gsm_dbus_method_call_free (GsmDBusMethodCall *method_call)
{
if (method_call->free_func != NULL)
method_call->free_func (method_call->reply_func_data);
g_free (method_call);
}
static void
gsm_dbus_method_call_returned_handler (DBusPendingCall *pending_call,
GsmDBusMethodCall *method_call)
{
DBusMessage *reply;
g_assert (dbus_pending_call_get_completed (pending_call));
reply = dbus_pending_call_steal_reply (pending_call);
g_assert (reply != NULL);
if (method_call->reply_func != NULL)
method_call->reply_func (method_call->reply_func_data, reply);
dbus_message_unref (reply);
dbus_pending_call_unref (pending_call);
}
GsmDBusMethodCall *
gsm_dbus_call_method (DBusConnection *connection,
const gchar *service_name,
const gchar *object_path,
const gchar *interface,
const gchar *method_name,
GsmDBusMethodCallReplyFunc reply_func,
gpointer reply_func_data,
GDestroyNotify free_func,
gint timeout,
gint param_type,
...)
{
GsmDBusMethodCall *method_call;
DBusMessage *message;
va_list param_list;
message = dbus_message_new_method_call (service_name, object_path, interface,
method_name);
dbus_message_set_auto_start (message, TRUE);
va_start (param_list, param_type);
if (param_type != DBUS_TYPE_ARRAY)
dbus_message_append_args_valist (message, param_type, param_list);
/* FIXME: kludge until dbus supports string arrays again
*/
else
{
gint array_type;
gint i, length;
DBusMessageIter iter, array_iter;
const gchar **array;
array_type = va_arg (param_list, gint);
/* FIXME: support other types
*/
g_assert (array_type == DBUS_TYPE_STRING);
array = va_arg (param_list, const gchar **);
length = va_arg (param_list, gint);
dbus_message_iter_init_append (message, &iter);
dbus_message_iter_open_container (&iter,
DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING,
&array_iter);
for (i = 0; i < length; i++)
dbus_message_iter_append_basic (&array_iter, array_type,
(gconstpointer) &array[i]);
dbus_message_iter_close_container (&iter, &array_iter);
}
va_end (param_list);
method_call = g_new (GsmDBusMethodCall, 1);
method_call->reply_func = reply_func;
method_call->reply_func_data = reply_func_data;
method_call->free_func = free_func;
dbus_connection_send_with_reply (connection, message, &method_call->pending_call,
timeout);
dbus_pending_call_set_notify (method_call->pending_call,
(DBusPendingCallNotifyFunction)
gsm_dbus_method_call_returned_handler, method_call,
(DBusFreeFunction) gsm_dbus_method_call_free);
return method_call;
}
void
gsm_dbus_cancel_method_call (GsmDBusMethodCall *method_call)
{
dbus_pending_call_cancel (method_call->pending_call);
}
void
gsm_dbus_emit_signal (DBusConnection *connection,
const gchar *object_path,
const gchar *interface,
const gchar *signal_name,
gint param_type,
...)
{
DBusMessage *message;
va_list param_pair_list;
message = dbus_message_new_signal (object_path, interface,
signal_name);
va_start (param_pair_list, param_type);
dbus_message_append_args_valist (message, param_type, param_pair_list);
va_end (param_pair_list);
dbus_message_set_no_reply (message, TRUE);
dbus_connection_send (connection, message, NULL);
}
/* gsm-dbus-utils.h - D-Bus related convenience functions
*
* Copyright (C) 2005 Ray Strode
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef GSM_DBUS_UTILS_H
#define GSM_DBUS_UTILS_H
#include <glib.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
G_BEGIN_DECLS
typedef struct _GsmDBusMethodCall GsmDBusMethodCall;
typedef void (* GsmDBusMethodCallReplyFunc) (gpointer user_data,
DBusMessage *reply);
GsmDBusMethodCall *gsm_dbus_call_method (DBusConnection *connection,
const gchar *service_name,
const gchar *object_path,
const gchar *interface,
const gchar *method_name,
GsmDBusMethodCallReplyFunc reply_func,
gpointer reply_func_data,
GDestroyNotify destroy_notify_func,
gint timeout,
gint param_type,
...);
void gsm_dbus_cancel_method_call (GsmDBusMethodCall *method_call);
void gsm_dbus_emit_signal (DBusConnection *connection,
const gchar *object_path,
const gchar *interface,
const gchar *signal_name,
gint param_type,
...);
G_END_DECLS
#endif /* GSM_DBUS_UTILS_H */
/* gsm-service.c - Services
*
* Copyright (C) 2005 Ray Strode, Matthias Clasen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifdef DEBUG
#define gsm_warning(format, args...) \
G_STMT_START \
{ \
static const char *_function_prefix = "", *_function_suffix = ""; \
const char *_function_name = ""; \
if (G_STRFUNC && G_STRFUNC[0] != '\0') \
{ \
_function_prefix = "\t"; \
_function_name = G_STRFUNC; \
_function_suffix = ": "; \
} \
g_printerr ("%.4f%s%45s%s" format, \
gsm_service_get_timestamp (), \
_function_prefix, _function_name, _function_suffix, ##args); \
} \
G_STMT_END
#define gsm_verbose(format, args...) \
G_STMT_START \
{ \
static const char *_function_prefix = "", *_function_suffix = ""; \
const char *_function_name = ""; \
if (G_STRFUNC && G_STRFUNC[0] != '\0') \
{ \
_function_prefix = "\t"; \
_function_name = G_STRFUNC; \
_function_suffix = ": "; \
} \
g_print ("%.4f%s%45s%s" format, \
gsm_service_get_timestamp (), \
_function_prefix, _function_name, _function_suffix, ##args); \
} \
G_STMT_END
#else
#include <config.h>
#include "util.h"
#endif
#include "gsm-service.h"
#include "gsm-dbus-utils.h"
#include <string.h>
#include <glib/gi18n.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include <sys/time.h>
#include <unistd.h>
struct _GsmServicePrivate
{
gchar *name; /* Human-readable name */
gchar *description; /* Human-readable description */
gchar *dbus_name; /* D-BUS service name (e.g. org.gnome.Panel) */
gchar **dependencies; /* Dependency list of D-BUS service names */
GsmServiceStatus status; /* STOPPED, ACTIVATING, STARTING, RUNNING, STOPPING*/
gboolean is_disabled; /* Is this service startable? */
};
static void gsm_service_finalize (GObject *object);
static void gsm_service_get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec);
static void gsm_service_set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec);
static void
gsm_service_class_install_properties (GsmServiceClass *service_class);
static void
gsm_service_class_install_signals (GsmServiceClass *service_class);
static void
gsm_service_started_handler (GsmService *service);
static void
gsm_service_startup_complete_handler (GsmService *service);
static void
gsm_service_error_starting_handler (GsmService *service,
GError *error);
enum
{
PROP_NAME = 1,
PROP_DESCRIPTION,
PROP_DBUS_NAME,
PROP_STATUS,
PROP_DISABLED,
};
enum
{
STARTED = 0,
STARTUP_COMPLETE,
ERROR_STARTING,
NUMBER_OF_SIGNALS
};
static const GEnumValue gsm_service_status_values[] =
{
{ GSM_SERVICE_STATUS_STOPPED, "GSM_SERVICE_STATUS_STOPPED",
"stopped" },
{ GSM_SERVICE_STATUS_ACTIVATING, "GSM_SERVICE_STATUS_ACTIVATING",
"activating" },
{ GSM_SERVICE_STATUS_STARTING, "GSM_SERVICE_STATUS_STARTING",
"starting" },
{ GSM_SERVICE_STATUS_RUNNING, "GSM_SERVICE_STATUS_RUNNING",
"running" },
{ GSM_SERVICE_STATUS_STOPPING, "GSM_SERVICE_STATUS_STOPPING",
"stopping" },
{ 0, NULL, NULL }
};
static guint gsm_service_signals[NUMBER_OF_SIGNALS];
G_DEFINE_TYPE (GsmService, gsm_service, G_TYPE_OBJECT);
static inline gdouble
gsm_service_get_timestamp (void)
{
gdouble timestamp;
GTimeVal tv = { 0, /* zero-filled */ };
g_get_current_time (&tv);
timestamp = (1.0 * G_USEC_PER_SEC * tv.tv_sec + tv.tv_usec) /
(1.0 * G_USEC_PER_SEC);
return timestamp;
}
GQuark
gsm_service_error_quark (void)
{
static GQuark error_quark = 0;
if (error_quark == 0)
error_quark =
g_quark_from_static_string ("gsm-service-error-quark");
return error_quark;
}
static void
gsm_service_class_init (GsmServiceClass *service_class)
{
GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS (service_class);
gobject_class->get_property = gsm_service_get_property;
gobject_class->set_property = gsm_service_set_property;
gobject_class->finalize = gsm_service_finalize;
gsm_service_class_install_properties (service_class);
gsm_service_class_install_signals (service_class);
g_type_class_add_private (gobject_class, sizeof (GsmServicePrivate));
}
GType
gsm_service_status_get_type (void)
{
static GType type = 0;
if (type == 0)
type = g_enum_register_static ("GsmServiceStatus",
gsm_service_status_values);
return type;
}
static void
gsm_service_class_install_properties (GsmServiceClass *service_class)
{
GObjectClass *object_class;
GParamSpec *param_spec;
object_class = G_OBJECT_CLASS (service_class);
param_spec = g_param_spec_string ("name", _("Name"),
_("Name of Service"),
NULL, G_PARAM_READABLE);
g_object_class_install_property (object_class, PROP_NAME, param_spec);
param_spec = g_param_spec_string ("description", _("Description"),
_("Description of Service"),
NULL, G_PARAM_READABLE);
g_object_class_install_property (object_class, PROP_DESCRIPTION, param_spec);
param_spec = g_param_spec_string ("dbus-name", _("D-BUS Name"),
_("Name of D-BUS Service"),
NULL, G_PARAM_READABLE);
g_object_class_install_property (object_class, PROP_DBUS_NAME, param_spec);
param_spec = g_param_spec_enum ("status", _("Status"), _("Current Status"),
GSM_SERVICE_TYPE_STATUS,
GSM_SERVICE_STATUS_STOPPED,
G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_STATUS, param_spec);
param_spec = g_param_spec_boolean ("disabled", _("disabled"), _("Whether"
"service is"
"disabled or"
"not"),
FALSE,
G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_DISABLED, param_spec);
}
static void
gsm_service_class_install_signals (GsmServiceClass *service_class)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (service_class);
gsm_service_signals[STARTED] =
g_signal_new ("started",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GsmServiceClass, started),
NULL, NULL, g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
service_class->started = gsm_service_started_handler;
gsm_service_signals[STARTUP_COMPLETE] =
g_signal_new ("startup-complete",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GsmServiceClass, startup_complete),
NULL, NULL, g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
service_class->startup_complete = gsm_service_startup_complete_handler;
gsm_service_signals[ERROR_STARTING] =
g_signal_new ("error-starting",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GsmServiceClass, error_starting),
NULL, NULL, g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE, 1, G_TYPE_POINTER);
service_class->error_starting = gsm_service_error_starting_handler;
}
static void
gsm_service_init (GsmService *service)
{
service->priv = G_TYPE_INSTANCE_GET_PRIVATE (service,
GSM_TYPE_SERVICE,
GsmServicePrivate);
service->priv->name = NULL;
service->priv->description = NULL;
service->priv->dbus_name = NULL;
service->priv->dependencies = NULL;
service->priv->status = GSM_SERVICE_STATUS_STOPPED;
service->priv->is_disabled = FALSE;
}
static void
gsm_service_clear (GsmService *service)
{
if (service->priv == NULL)
return;
gsm_verbose ("Freeing all resources associated with service '%s'\n",
service->priv->dbus_name);
g_free (service->priv->dbus_name);
service->priv->dbus_name = NULL;
g_free (service->priv->name);
service->priv->name = NULL;
g_free (service->priv->description);
service->priv->description = NULL;
if (service->priv->dependencies != NULL)
g_strfreev (service->priv->dependencies);
service->priv->dependencies = NULL;
service->priv->status = GSM_SERVICE_STATUS_STOPPED;
service->priv->is_disabled = FALSE;
}
static void
gsm_service_finalize (GObject *object)
{
gsm_service_clear (GSM_SERVICE (object));
(* G_OBJECT_CLASS (gsm_service_parent_class)->finalize) (object);
}
static void
gsm_service_get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec)
{
GsmService *service;
service = GSM_SERVICE (object);
switch (param_id)
{
case PROP_NAME:
g_value_set_string (value, service->priv->name);
break;
case PROP_DESCRIPTION:
g_value_set_string (value, service->priv->description);
break;
case PROP_DBUS_NAME:
g_value_set_string (value, service->priv->dbus_name);
break;
case PROP_STATUS:
g_value_set_enum (value, (gint) service->priv->status);
break;
case PROP_DISABLED:
g_value_set_boolean (value, service->priv->is_disabled);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
gsm_service_set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec)
{
GsmService *service;
service = GSM_SERVICE (object);
switch (param_id)
{
case PROP_STATUS:
gsm_service_set_status (service,
(GsmServiceStatus) g_value_get_enum (value));
break;
case PROP_DISABLED:
gsm_service_set_disabled (service, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
/**
* gsm_service_new:
*
* Creates a new desktop service object.
*
* Returns: A new service
*/
GsmService *
gsm_service_new (void)
{
GsmService *service;
service = g_object_new (GSM_TYPE_SERVICE, NULL);
return service;
}
static gboolean
gsm_service_is_initialized (GsmService *service)
{
return service->priv->name != NULL;
}
gboolean
gsm_service_load_from_file (GsmService *service,
const gchar *filename,
GError **error)
{
GKeyFile *key_file;
GError *key_file_error;
gchar *value;
if (gsm_service_is_initialized (service))
gsm_service_clear (service);
key_file = g_key_file_new ();
key_file_error = NULL;
if (!g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE,
&key_file_error))
{
g_propagate_error (error, key_file_error);
return FALSE;
}
value = g_key_file_get_string (key_file, "Desktop Service",
"D-BUS-Name", &key_file_error);
if (key_file_error != NULL)
{
g_free (value);
g_propagate_error (error, key_file_error);
return FALSE;
}
service->priv->dbus_name = value;
value = g_key_file_get_locale_string (key_file, "Desktop Service",
"Name", NULL, &key_file_error);
if (key_file_error != NULL)
{
g_free (value);
g_propagate_error (error, key_file_error);
return FALSE;
}
service->priv->name = value;
value = g_key_file_get_locale_string (key_file, "Desktop Service",
"Description", NULL, &key_file_error);
if (key_file_error != NULL)
{
g_free (value);
g_propagate_error (error, key_file_error);
return FALSE;
}
service->priv->description = value;
if (g_key_file_has_key (key_file, "Desktop Service", "Dependencies", NULL))
{
gchar **dependencies;
dependencies = g_key_file_get_string_list (key_file, "Desktop Service",
"Dependencies", NULL, &key_file_error);
if (key_file_error != NULL)
{
g_strfreev (dependencies);
g_propagate_error (error, key_file_error);
return FALSE;
}
service->priv->dependencies = dependencies;
}
else
service->priv->dependencies = NULL;
if (g_key_file_has_key (key_file, "Desktop Service", "Enabled", NULL))
{
gboolean is_disabled;
is_disabled = g_key_file_get_boolean (key_file, "Desktop Service",
"Disabled", &key_file_error);
if (key_file_error != NULL)
{
g_propagate_error (error, key_file_error);
service->priv->is_disabled = is_disabled;
}
}
return TRUE;
}
/**
* gsm_service_get_name:
* @service: a #GsmService struct
*
* Returns a human-readable name for @service,
* suitable for displaying a list of services
* to the user. The string is taken from the
* "Name" field of the .desktop-service file.
*
* Returns: a string that shouldn't be freed
*/
G_CONST_RETURN gchar *
gsm_service_get_name (GsmService *service)
{
return service->priv->name;
}
/**
* gsm_service_get_description:
* @service: a #GsmService struct
*
* Returns a description for @service.
* suitable for displaying a list of services
* to the user. The string is taken from the
* "Description" field of the .desktop-service file.
*
* Returns: a string that shouldn't be freed
*/
G_CONST_RETURN gchar *
gsm_service_get_description (GsmService *service)
{
return g_strdup (service->priv->description);
}
/**
* gsm_service_get_dbus_name:
* @service: a #GsmService struct
*
* Returns a D-BUS service name
*
* Returns: a string that shouldn't be freed
*/
G_CONST_RETURN gchar *
gsm_service_get_dbus_name (GsmService *service)
{
return service->priv->dbus_name;
}
/**
* gsm_service_get_status:
* @service: a #GsmService struct
*
* Returns the current status of @service.
* The status will typically be %STATUS_RUNNING
* or %STATUS_STOPPED, the intermediate states
* %STATUS_STARTING and %STATUS_STOPPING should
* only occur for short periods of time when
* services are started or stopped.
*
* Returns: the current status of @service.
*/
GsmServiceStatus
gsm_service_get_status (GsmService *service)
{
return service->priv->status;
}
void
gsm_service_set_status (GsmService *service,
GsmServiceStatus status)
{
if (service->priv->status != status)
{
gsm_verbose ("Status set to '%s' for service '%s'\n",
gsm_service_status_as_string (gsm_service_get_status
(service)),
service->priv->dbus_name);
service->priv->status = status;
if (status == GSM_SERVICE_STATUS_RUNNING)
g_signal_emit (G_OBJECT (service), gsm_service_signals[STARTUP_COMPLETE], 0);
g_object_notify (G_OBJECT (service), "status");
}
}
G_CONST_RETURN gchar *
gsm_service_status_as_string (GsmServiceStatus status)
{
return gsm_service_status_values[(guint) status].value_nick;
}
/**
* gsm_service_is_disabled:
* @service: a #GsmService struct
*
* Returns %TRUE if the service is currently
* disabled. If a service is disabled, the
* service service will not start it, and if
* it is already running, it will be stopped.
*
* Returns: whether @service is disabled
*/
gboolean
gsm_service_is_disabled (GsmService *service)
{
return service->priv->is_disabled;
}
void
gsm_service_set_disabled (GsmService *service,
gboolean disable)
{
/* The !! stuff is to cannonicalize input to 1 or 0 for equality check
*/
if ((!!disable) != service->priv->is_disabled)
{
service->priv->is_disabled = disable;
g_object_notify (G_OBJECT (service), "disabled");
}
}
gchar **
gsm_service_get_dependencies (GsmService *service)
{
guint length, i;
gchar **dependencies;
if (service->priv->dependencies == NULL)
return NULL;
length = g_strv_length (service->priv->dependencies);
dependencies = g_new0 (char *, length + 1);
for (i = 0; i < length; i++)
{
dependencies[i] = g_strdup (service->priv->dependencies[i]);
}
dependencies[i] = NULL;
return dependencies;
}
static void
gsm_service_started_handler (GsmService *service)
{
/* FIXME: Maybe track process id of service here,
* so that service manager can watch/kill services independent
* of d-bus
*/
gsm_verbose ("service '%s' is started\n",
service->priv->dbus_name);
gsm_service_set_status (service, GSM_SERVICE_STATUS_STARTING);
}
static void
gsm_service_startup_complete_handler (GsmService *service)
{
gsm_verbose ("service '%s' is done starting up\n",
service->priv->dbus_name);
}
static void
gsm_service_error_starting_handler (GsmService *service,
GError *error)
{
if (g_error_matches (error, GSM_SERVICE_ERROR,
GSM_SERVICE_ERROR_CRASH_ON_STARTUP))
{
gsm_service_set_status (service, GSM_SERVICE_STATUS_STOPPED);
gsm_warning ("service '%s' could not start up: it crashed\n",
service->priv->dbus_name);
}
else
{
/* FIXME: Not sure why this code is here. It's probably wrong.
*/
gsm_service_set_status (service, GSM_SERVICE_STATUS_STOPPED);
gsm_warning ("service '%s' could not start up: %s\n",
service->priv->dbus_name, error->message);
}
}
static void
gsm_service_start_by_name_handler (GsmService *service,
DBusMessage *reply)
{
if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR)
{
gchar *message;
GError *error;
dbus_message_get_args (reply, NULL, DBUS_TYPE_STRING, &message,
DBUS_TYPE_INVALID);
gsm_warning ("could not start service '%s': %s'\n",
service->priv->dbus_name, message);
if (g_str_equal (dbus_message_get_error_name (reply),
"org.freedesktop.DBus.Error.Spawn.ChildExited"))
{
error = g_error_new (GSM_SERVICE_ERROR,
GSM_SERVICE_ERROR_CRASH_ON_STARTUP,
"%s", message);
}
else
{
error = g_error_new (GSM_SERVICE_ERROR,
GSM_SERVICE_ERROR_STARTING_UP,
"%s", message);
}
g_signal_emit (G_OBJECT (service), gsm_service_signals[ERROR_STARTING], 0,
error);
g_error_free (error);
}
else
{
gsm_verbose ("started service '%s'\n",
service->priv->dbus_name);
g_signal_emit (G_OBJECT (service), gsm_service_signals[STARTED], 0);
}
}
void
gsm_service_start (GsmService *service,
DBusConnection *connection)
{
dbus_uint32_t flags;
gsm_verbose ("starting service '%s'\n", service->priv->dbus_name);
g_return_if_fail (connection != NULL);
gsm_service_set_status (service, GSM_SERVICE_STATUS_ACTIVATING);
flags = 0;
/* dbus can't handle the barrage of async calls that occurs
* FIXME: https://bugs.freedesktop.org/show_bug.cgi?id=2813
*/
#if 1
gsm_dbus_call_method (connection,
DBUS_SERVICE_DBUS,
DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS,
"StartServiceByName",
(GsmDBusMethodCallReplyFunc)
gsm_service_start_by_name_handler,
service, NULL, -1,
DBUS_TYPE_STRING, &service->priv->dbus_name,
DBUS_TYPE_UINT32, &flags,
DBUS_TYPE_INVALID);
#else
dbus_bus_start_service_by_name (connection, service->priv->dbus_name, flags, NULL, NULL);
g_signal_emit (G_OBJECT (service), gsm_service_signals[STARTED], 0);
#endif
}
void
gsm_service_stop (GsmService *service,
DBusConnection *connection)
{
gsm_verbose ("stopping service '%s'\n", service->priv->dbus_name);
g_return_if_fail (connection != NULL);
gsm_service_set_status (service, GSM_SERVICE_STATUS_STOPPING);
gsm_dbus_call_method (connection,
service->priv->dbus_name,
GSM_SERVICE_OBJECT_PATH,
GSM_SERVICE_INTERFACE,
"Stop", NULL, NULL, NULL, 300, DBUS_TYPE_INVALID);
}
/* gsm-service.h - Desktop Service Object
*
* Copyright (C) 2005 Matthias Clasen, Ray Strode
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef GSM_SERVICE_H
#define GSM_SERVICE_H
#include <glib.h>
#include <glib-object.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
G_BEGIN_DECLS
#define GSM_TYPE_SERVICE (gsm_service_get_type ())
#define GSM_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSM_TYPE_SERVICE, GsmService))
#define GSM_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSM_TYPE_SERVICE, GsmServiceClass))
#define GSM_IS_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSM_TYPE_SERVICE))
#define GSM_IS_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSM_TYPE_SERVICE))
#define GSM_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GSM_TYPE_SERVICE, GsmServiceClass))
#define GSM_SERVICE_ERROR (gsm_service_error_quark ())
#define GSM_SERVICE_TYPE_STATUS (gsm_service_status_get_type ())
#define GSM_SERVICE_OBJECT_PATH "/org/gnome/ServiceManager/Service"
#define GSM_SERVICE_INTERFACE "org.gnome.ServiceManager.Service"
typedef struct _GsmService GsmService;
typedef struct _GsmServiceClass GsmServiceClass;
typedef struct _GsmServicePrivate GsmServicePrivate;
struct _GsmService
{
GObject parent;
/*< private >*/
GsmServicePrivate *priv;
};
struct _GsmServiceClass
{
GObjectClass parent_class;
/* Signals */
void (* started) (GsmService *service);
void (* startup_complete) (GsmService *service);
void (* error_starting) (GsmService *service,
GError *error);
};
typedef enum
{
GSM_SERVICE_STATUS_STOPPED = 0,
GSM_SERVICE_STATUS_ACTIVATING,
GSM_SERVICE_STATUS_STARTING,
GSM_SERVICE_STATUS_RUNNING,
GSM_SERVICE_STATUS_STOPPING
} GsmServiceStatus;
typedef enum
{
GSM_SERVICE_ERROR_STARTING_UP = 0,
GSM_SERVICE_ERROR_CRASH_ON_STARTUP
} GsmServiceError;
GType gsm_service_get_type (void) G_GNUC_CONST;
GQuark gsm_service_error_quark (void) G_GNUC_CONST;
GType gsm_service_status_get_type (void) G_GNUC_CONST;
GsmService *gsm_service_new (void);
gboolean gsm_service_load_from_file (GsmService *service,
const gchar *filename,
GError **error);
G_CONST_RETURN gchar *gsm_service_get_name (GsmService *service);
G_CONST_RETURN gchar *gsm_service_get_description (GsmService *service);
G_CONST_RETURN gchar *gsm_service_get_dbus_name (GsmService *service);
GsmServiceStatus gsm_service_get_status (GsmService *service);
void gsm_service_set_status (GsmService *service,
GsmServiceStatus status);
G_CONST_RETURN gchar *gsm_service_status_as_string (GsmServiceStatus status);
gboolean gsm_service_is_disabled (GsmService *service);
void gsm_service_set_disabled (GsmService *service,
gboolean disable);
gchar **gsm_service_get_dependencies (GsmService *service);
void gsm_service_start (GsmService *service,
DBusConnection *connection);
void gsm_service_stop (GsmService *service,
DBusConnection *connection);
G_END_DECLS
#endif /* GSM_SERVICE_H */
/* gsm-service-manager.c - Manage services
*
* Copyright (C) 2005 Ray Strode, Matthias Clasen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#define DEBUG
#ifdef DEBUG
#define gsm_warning(format, args...) \
G_STMT_START \
{ \
static const char *_function_prefix = "", *_function_suffix = ""; \
const char *_function_name = ""; \
if (G_STRFUNC && G_STRFUNC[0] != '\0') \
{ \
_function_prefix = "\t"; \
_function_name = G_STRFUNC; \
_function_suffix = ": "; \
} \
g_printerr ("%.4f%s%45s%s" format, \
gsm_service_manager_get_timestamp (), \
_function_prefix, _function_name, _function_suffix, ##args); \
} \
G_STMT_END
#define gsm_verbose(format, args...) \
G_STMT_START \
{ \
static const char *_function_prefix = "", *_function_suffix = ""; \
const char *_function_name = ""; \
if (G_STRFUNC && G_STRFUNC[0] != '\0') \
{ \
_function_prefix = "\t"; \
_function_name = G_STRFUNC; \
_function_suffix = ": "; \
} \
g_print ("%.4f%s%45s%s" format, \
gsm_service_manager_get_timestamp (), \
_function_prefix, _function_name, _function_suffix, ##args); \
} \
G_STMT_END
#else
#include <config.h>
#include "util.h"
#endif
#include "gsm-service-manager.h"
#include "gsm-service.h"
#include "gsm-dbus-utils.h"
#include <string.h>
#include <glib/gi18n.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include <sys/time.h>
#define GSM_SERVICE_MANAGER_OBJECT_PATH "/org/gnome/ServiceManager"
#define GSM_MANAGED_SERVICE_OBJECT_PATH_PREFIX \
"/org/gnome/ServiceManager/Services"
#define GSM_SERVICE_MANAGER_INTERFACE "org.gnome.ServiceManager"
#define GSM_MANAGED_SERVICE_INTERFACE "org.gnome.ServiceManager.ManagedService"
#define GSM_SERVICE_OBJECT_PATH \
"/org/gnome/ServiceManager/Service"
#define GSM_SERVICE_INTERFACE \
"org.gnome.ServiceManager.Service"
struct _GsmServiceManagerPrivate
{
GQueue *services,
*failed_services;
GHashTable *service_dbus_name_map;
GHashTable *service_object_map;
DBusConnection *dbus_connection;
gboolean dbus_message_handlers_are_registered;
};
extern char **environ;
static void gsm_service_manager_dispose (GObject *object);
static void gsm_service_manager_finalize (GObject *object);
static void gsm_service_manager_class_install_signals (GsmServiceManagerClass *service_class);
enum
{
STARTUP_COMPLETE = 0,
NUMBER_OF_SIGNALS
};
static guint gsm_service_manager_signals[NUMBER_OF_SIGNALS];
G_DEFINE_TYPE (GsmServiceManager, gsm_service_manager, G_TYPE_OBJECT);
static void
gsm_service_manager_load_service_files (GsmServiceManager *manager);
static void
gsm_service_manager_service_status_changed_handler (GsmServiceManager *manager,
gpointer useless_param,
GsmService *service);
static DBusHandlerResult
gsm_service_manager_name_owner_changed_handler (GsmServiceManager *manager,
DBusMessage *message);
static gboolean
gsm_service_manager_start_service_and_dependencies (GsmServiceManager *manager,
GsmService *service,
GError **error);
static void
gsm_service_manager_stop_service_and_dependents (GsmServiceManager *manager,
GsmService *service);
static inline gdouble
gsm_service_manager_get_timestamp (void)
{
gdouble timestamp;
GTimeVal tv = { 0, /* zero-filled */ };
g_get_current_time (&tv);
timestamp = (1.0 * G_USEC_PER_SEC * tv.tv_sec + tv.tv_usec) /
(1.0 * G_USEC_PER_SEC);
return timestamp;
}
static void
gsm_service_manager_class_init (GsmServiceManagerClass *manager_class)
{
GObjectClass *gobject_class;
gsm_verbose ("Initializing GsmServiceManagerClass\n");
gobject_class = G_OBJECT_CLASS (manager_class);
gobject_class->dispose = gsm_service_manager_dispose;
gobject_class->finalize = gsm_service_manager_finalize;
gsm_service_manager_class_install_signals (manager_class);
g_type_class_add_private (manager_class, sizeof (GsmServiceManagerPrivate));
}
static void
gsm_service_manager_startup_complete_handler (GsmServiceManager *manager)
{
gdouble timestamp;
timestamp = gsm_service_manager_get_timestamp ();
gsm_dbus_emit_signal (manager->priv->dbus_connection,
GSM_SERVICE_MANAGER_OBJECT_PATH,
GSM_SERVICE_MANAGER_INTERFACE,
"StartupComplete",
DBUS_TYPE_DOUBLE, ×tamp,
DBUS_TYPE_INVALID);
}
static void
gsm_service_manager_class_install_signals (GsmServiceManagerClass *manager_class)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (manager_class);
gsm_service_manager_signals[STARTUP_COMPLETE] =
g_signal_new ("startup-complete",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GsmServiceManagerClass, startup_complete),
NULL, NULL, g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
manager_class->startup_complete = gsm_service_manager_startup_complete_handler;
}
static void
gsm_service_manager_init (GsmServiceManager *manager)
{
gsm_verbose ("Initializing GsmServiceManager object\n");
manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
GSM_TYPE_SERVICE_MANAGER,
GsmServiceManagerPrivate);
manager->priv->services = g_queue_new ();
manager->priv->service_dbus_name_map =
g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) g_object_unref);
manager->priv->service_object_map =
g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) g_object_unref);
manager->priv->failed_services = NULL;
gsm_service_manager_load_service_files (manager);
}
static void
gsm_service_manager_remove_service (GsmServiceManager *manager,
GsmService *service);
static void
gsm_service_manager_dispose (GObject *object)
{
static gboolean ran_before = FALSE;
GsmServiceManager *manager;
GsmService *service;
GObjectClass *gobject_class;
if (ran_before)
return;
manager = GSM_SERVICE_MANAGER (object);
gobject_class = G_OBJECT_CLASS (gsm_service_manager_parent_class);
/* FIXME: need to refactor this code. The removal is O(n) when it could
* be O(1) because remove_service calls g_queue_remove
*/
while ((service = g_queue_peek_head (manager->priv->services)) != NULL)
gsm_service_manager_remove_service (manager, service);
g_queue_free (manager->priv->services);
manager->priv->services = NULL;
gsm_service_manager_disconnect_from_bus (manager);
ran_before = TRUE;
gobject_class->dispose (object);
}
static void
gsm_service_manager_finalize (GObject *object)
{
GsmServiceManager *manager;
GObjectClass *gobject_class;
manager = GSM_SERVICE_MANAGER (object);
gobject_class = G_OBJECT_CLASS (gsm_service_manager_parent_class);
g_hash_table_destroy (manager->priv->service_object_map);
g_hash_table_destroy (manager->priv->service_dbus_name_map);
gobject_class->finalize (object);
}
GQuark
gsm_service_manager_error_quark (void)
{
static GQuark error_quark = 0;
if (error_quark == 0)
error_quark = g_quark_from_static_string ("gsm-service-manager-error-quark");
return error_quark;
}
/**
* gsm_service_manager_new:
*
* Creates a new service manager object. The service manager
* manages all the services listed in the .desktop-service
* files in $HOME/gnome2/.desktop-services and
* /usr/share/gnome/desktop-services, taking dependencies
* declared in the .desktop-service files into account.
*
* Returns: A new service manager
*/
GsmServiceManager *
gsm_service_manager_new (void)
{
GObject *instance;
instance = g_object_new (GSM_TYPE_SERVICE_MANAGER, NULL);
return GSM_SERVICE_MANAGER (instance);
}
static gboolean
gsm_service_manager_has_service (GsmServiceManager *manager,
GsmService *service)
{
const gchar *dbus_name;
gboolean has_service;
dbus_name = gsm_service_get_dbus_name (service);
has_service = (g_hash_table_lookup (manager->priv->service_dbus_name_map,
dbus_name) != NULL);
return has_service;
}
static void
gsm_service_manager_service_started_handler (GsmServiceManager *manager,
GsmService *service);
static void
gsm_service_manager_error_starting_service_handler (GsmServiceManager *manager,
GError *error,
GsmService *service);
static void
gsm_service_manager_add_service (GsmServiceManager *manager,
GsmService *service)
{
static guint last_object_id = 0;
gchar *object_path;
g_hash_table_insert (manager->priv->service_dbus_name_map,
g_strdup (gsm_service_get_dbus_name (service)),
g_object_ref (service));
object_path = g_strdup_printf (GSM_MANAGED_SERVICE_OBJECT_PATH_PREFIX "/%u",
last_object_id);
g_object_set_data_full (G_OBJECT (service),
"gsm-service-manager-object-path", object_path,
(GDestroyNotify) g_free);
gsm_verbose ("Adding object path '%s' service object hash table\n",
object_path);
g_hash_table_insert (manager->priv->service_object_map,
g_strdup (object_path), g_object_ref (service));
g_queue_push_tail (manager->priv->services,
g_object_ref (G_OBJECT (service)));
g_signal_connect_swapped (G_OBJECT (service), "startup-complete",
G_CALLBACK (gsm_service_manager_service_started_handler),
manager);
g_signal_connect_swapped (G_OBJECT (service), "error-starting",
G_CALLBACK (gsm_service_manager_error_starting_service_handler),
manager);
g_signal_connect_swapped (G_OBJECT (service), "notify::status",
G_CALLBACK (gsm_service_manager_service_status_changed_handler),
manager);
last_object_id++;
}
static void
gsm_service_manager_remove_service (GsmServiceManager *manager,
GsmService *service)
{
const gchar *object_path, *dbus_name;;
dbus_name = gsm_service_get_dbus_name (service);
object_path = g_object_get_data (G_OBJECT (service),
"gsm-service-manager-object-path");
g_hash_table_remove (manager->priv->service_object_map, object_path);
g_hash_table_remove (manager->priv->service_dbus_name_map, dbus_name);
g_queue_remove (manager->priv->services, service);
g_signal_handlers_disconnect_by_func (G_OBJECT (service),
G_CALLBACK (gsm_service_manager_service_status_changed_handler),
manager);
g_signal_handlers_disconnect_by_func (G_OBJECT (service),
G_CALLBACK (gsm_service_manager_error_starting_service_handler),
manager);
g_signal_handlers_disconnect_by_func (G_OBJECT (service),
G_CALLBACK (gsm_service_manager_service_started_handler),
manager);
g_object_unref (G_OBJECT (service));
}
static gboolean
gsm_service_manager_load_service_directory (GsmServiceManager *manager,
const gchar *directory,
GError **error)
{
GDir *dir;
const gchar *name;
gchar *path;
GError *open_error;
gsm_verbose ("Loading desktop service files in directory '%s'\n", directory);
open_error = NULL;
dir = g_dir_open (directory, 0, &open_error);
if (dir == NULL)
{
g_propagate_error (error, open_error);
return FALSE;
}
while ((name = g_dir_read_name (dir)) != NULL)
{
GsmService *service;
if (g_str_has_prefix (name, "."))
continue;
if (!g_str_has_suffix (name, ".desktop-service"))
continue;
path = g_build_filename (directory, name, NULL);
service = gsm_service_new ();
g_object_set_data (G_OBJECT (service), "gsm-service-manager", manager);
open_error = NULL;
if (!gsm_service_load_from_file (service, path, &open_error))
{
g_object_unref (service);
service = NULL;
gsm_warning ("could not load service '%s': %s\n", path,
open_error->message);
g_error_free (open_error);
open_error = NULL;
}
g_free (path);
if (service == NULL)
continue;
if (!gsm_service_manager_has_service (manager, service))
gsm_service_manager_add_service (manager, service);
else
{
const gchar *dbus_name;
dbus_name = gsm_service_get_dbus_name (service);
gsm_warning ("D-BUS name '%s' found in multiple desktop service "
"files\n", dbus_name);
}
g_object_unref (service);
}
g_dir_close (dir);
return TRUE;
}
static void
gsm_service_manager_load_service_files (GsmServiceManager *manager)
{
GError *load_error;
gchar *path;
gboolean files_loaded;
gsm_verbose ("Loading desktop service files...\n");
files_loaded = FALSE;
path = g_build_filename (g_get_home_dir (), ".gnome2", "desktop-services",
NULL);
load_error = NULL;
gsm_service_manager_load_service_directory (manager, path, &load_error);
if (load_error != NULL)
{
gsm_warning ("could not load service directory '%s': %s\n", path,
load_error->message);
g_error_free (load_error);
load_error = NULL;
}
else
files_loaded = TRUE;
g_free (path);
gsm_service_manager_load_service_directory (manager,
DEFAULTDIR "/desktop-services",
&load_error);
if (load_error != NULL)
{
gsm_warning ("could not load service directory "
"'"DEFAULTDIR"/desktop-services': %s\n",
load_error->message);
g_error_free (load_error);
load_error = NULL;
}
else
files_loaded = TRUE;
if (!files_loaded)
gsm_warning ("no loadable services could be found\n");
}
static DBusMessage *
get_managed_service (GsmServiceManager *manager,
DBusMessage *message)
{
gchar *dbus_service_name;
const gchar *object_path;
DBusMessage *reply;
DBusError error;
GsmService *service;
gsm_verbose ("\n");
dbus_error_init (&error);
dbus_message_get_args (message,
&error,
DBUS_TYPE_STRING, &dbus_service_name,
DBUS_TYPE_INVALID);
if (dbus_error_is_set (&error))
{
reply = dbus_message_new_error (message, error.name,
error.message);
dbus_error_free (&error);
return reply;
}
service = g_hash_table_lookup (manager->priv->service_dbus_name_map,
dbus_service_name);
if (service == NULL)
{
reply = dbus_message_new_error_printf (message,
"org.gnome.ServiceManager.Error.ServiceNotFound",
_("the service '%s' requested could"
"not be found"),
dbus_service_name);
return reply;
}
object_path = (const gchar *) g_object_get_data (G_OBJECT (service),
"gsm-service-manager-object-path");
reply = dbus_message_new_method_return (message);
dbus_message_append_args (reply,
DBUS_TYPE_OBJECT_PATH, &object_path,
DBUS_TYPE_INVALID);
return reply;
}
static void
collect_object_paths (gpointer key, gpointer value, gpointer data)
{
DBusMessageIter *array_iter;
GsmService *service;
const gchar *object_path;
array_iter = (DBusMessageIter *) data;
service = (GsmService *) value;
object_path = (const gchar *) g_object_get_data (G_OBJECT (service),
"gsm-service-manager-object-path");
dbus_message_iter_append_basic (array_iter, DBUS_TYPE_OBJECT_PATH, &object_path);
}
static DBusMessage *
list_managed_services (GsmServiceManager *manager,
DBusMessage *message)
{
DBusMessage *reply;
DBusMessageIter iter, array_iter;
gsm_verbose ("\n");
reply = dbus_message_new_method_return (message);
dbus_message_iter_init (reply, &iter);
dbus_message_iter_open_container (&iter,
DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING,
&array_iter);
g_hash_table_foreach (manager->priv->service_object_map, collect_object_paths,
&array_iter);
dbus_message_iter_close_container (&iter, &array_iter);
return reply;
}
static DBusHandlerResult
handle_service_message (GsmServiceManager *manager,
GsmService *service,
DBusMessage *message)
{
DBusMessage *reply;
DBusHandlerResult result;
reply = NULL;
result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
if (dbus_message_is_method_call (message, GSM_MANAGED_SERVICE_INTERFACE,
"GetEnvironment"))
{
gint i, length;
DBusMessageIter iter, array_iter;
reply = dbus_message_new_method_return (message);
dbus_message_iter_init_append (reply, &iter);
dbus_message_iter_open_container (&iter,
DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING,
&array_iter);
for (length = 0; environ[length] != NULL; length++);
for (i = 0; i < length; i++)
dbus_message_iter_append_basic (&array_iter, DBUS_TYPE_STRING,
(gconstpointer) &environ[i]);
dbus_message_iter_close_container (&iter, &array_iter);
{
const gchar *dbus_name;
dbus_name = gsm_service_get_dbus_name (service);
gsm_verbose ("Replying to GetEnvironment request for service '%s' "
"(%d elements in environment)\n", dbus_name, i);
}
result = DBUS_HANDLER_RESULT_HANDLED;
}
else if (dbus_message_is_method_call (message, GSM_MANAGED_SERVICE_INTERFACE,
"Start"))
{
/* If a service is stopped and it is asked to be started, then start it
* and its dependencies.
*
* FIXME: What should we do if it's in the STOPPING state?
*/
if ((gsm_service_get_status (service) == GSM_SERVICE_STATUS_STOPPED) &&
!gsm_service_is_disabled (service))
{
GError *error;
error = NULL;
/* FIXME: Send a dbus error message
*/
if (!gsm_service_manager_start_service_and_dependencies (manager, service,
&error))
{
g_assert (error != NULL);
gsm_warning ("could not start service '%s': %s\n",
gsm_service_get_dbus_name (service), error->message);
g_error_free (error);
}
}
reply = dbus_message_new_method_return (message);
result = DBUS_HANDLER_RESULT_HANDLED;
}
else if (dbus_message_is_method_call (message, GSM_MANAGED_SERVICE_INTERFACE,
"Stop"))
{
if (gsm_service_get_status (service) != GSM_SERVICE_STATUS_STOPPED)
{
gsm_service_manager_stop_service_and_dependents (manager, service);
}
reply = dbus_message_new_method_return (message);
result = DBUS_HANDLER_RESULT_HANDLED;
}
else if (dbus_message_is_method_call (message, GSM_MANAGED_SERVICE_INTERFACE,
"GetDBusName"))
{
const gchar *dbus_name;
reply = dbus_message_new_method_return (message);
dbus_name = gsm_service_get_dbus_name (service);
dbus_message_append_args (reply,
DBUS_TYPE_STRING, &dbus_name,
DBUS_TYPE_INVALID);
gsm_verbose ("Replying to GetDBusName request for service '%s'\n",
dbus_name);
result = DBUS_HANDLER_RESULT_HANDLED;
}
else if (dbus_message_is_method_call (message, GSM_MANAGED_SERVICE_INTERFACE,
"GetName"))
{
const gchar *name;
reply = dbus_message_new_method_return (message);
name = gsm_service_get_name (service);
dbus_message_append_args (reply,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID);
gsm_verbose ("Replying to GetName request for service '%s'\n",
name);
result = DBUS_HANDLER_RESULT_HANDLED;
}
else if (dbus_message_is_method_call (message, GSM_MANAGED_SERVICE_INTERFACE,
"GetDescription"))
{
const gchar *description;
reply = dbus_message_new_method_return (message);
description = gsm_service_get_description (service);
dbus_message_append_args (reply,
DBUS_TYPE_STRING, &description,
DBUS_TYPE_INVALID);
gsm_verbose ("Replying to GetDescription request for service '%s'\n",
description);
result = DBUS_HANDLER_RESULT_HANDLED;
}
else if (dbus_message_is_method_call (message, GSM_MANAGED_SERVICE_INTERFACE,
"SetStatus"))
{
const gchar *status;
dbus_message_get_args (message, NULL,
DBUS_TYPE_STRING, &status,
DBUS_TYPE_INVALID);
if (g_str_equal (status, "starting"))
gsm_service_set_status (service, GSM_SERVICE_STATUS_STARTING);
else if (g_str_equal (status, "running"))
gsm_service_set_status (service, GSM_SERVICE_STATUS_RUNNING);
else if (g_str_equal (status, "stopping"))
gsm_service_set_status (service, GSM_SERVICE_STATUS_STOPPING);
else if (g_str_equal (status, "stopped"))
gsm_service_set_status (service, GSM_SERVICE_STATUS_STOPPED);
else
{
gsm_warning ("unknown service status '%s'\n", status);
}
reply = dbus_message_new_method_return (message);
result = DBUS_HANDLER_RESULT_HANDLED;
}
else if (dbus_message_is_method_call (message, GSM_MANAGED_SERVICE_INTERFACE,
"GetStatus"))
{
const gchar *status;
status = gsm_service_status_as_string (gsm_service_get_status
(service));
if (status == NULL)
{
gsm_warning ("unknown service status type %u\n",
gsm_service_get_status (service));
}
else
{
reply = dbus_message_new_method_return (message);
dbus_message_append_args (reply,
DBUS_TYPE_STRING, &status,
DBUS_TYPE_INVALID);
gsm_verbose ("Replying to GetStatus request for service '%s'\n",
gsm_service_get_dbus_name (service));
result = DBUS_HANDLER_RESULT_HANDLED;
}
}
if (reply != NULL)
dbus_connection_send (manager->priv->dbus_connection, reply, NULL);
return result;
}
static DBusHandlerResult
gsm_service_manager_dbus_message_handler (DBusConnection *connection,
DBusMessage *message,
GsmServiceManager *manager)
{
DBusMessage *reply;
const gchar *member;
reply = NULL;
gsm_verbose ("Service Manager method handler invoked\n");
if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
member = dbus_message_get_member (message);
g_assert (member != NULL);
if (g_str_equal (member, "GetManagedService"))
reply = get_managed_service (manager, message);
else if (g_str_equal (member, "ListManagedServices"))
reply = list_managed_services (manager, message);
if (reply != NULL)
{
dbus_connection_send (manager->priv->dbus_connection, reply, NULL);
return DBUS_HANDLER_RESULT_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static DBusHandlerResult
gsm_service_manager_managed_object_dbus_message_handler (DBusConnection *connection,
DBusMessage *message,
GsmServiceManager *manager)
{
DBusMessage *reply;
GsmService *service;
const gchar *object_path;
reply = NULL;
if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
object_path = dbus_message_get_path (message);
g_assert (g_str_has_prefix (object_path, GSM_MANAGED_SERVICE_OBJECT_PATH_PREFIX));
gsm_verbose ("Calling method on object '%s'\n", object_path);
service = g_hash_table_lookup (manager->priv->service_object_map,
object_path);
if (service != NULL)
return handle_service_message (manager, service, message);
gsm_warning ("Client attempted to call method on non-existant "
"managed service '%s'\n", object_path);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static void
gsm_service_manager_service_lost_name_handler (GsmServiceManager *manager,
GsmService *service)
{
const gchar *dbus_name;
dbus_name = gsm_service_get_dbus_name (service);
gsm_verbose ("Service '%s' was disconnected from bus\n",
dbus_name);
/* Service was lost--restart it if it's not disabled
* or stopped.
*
* FIXME: Make sure we don't get stuck in restart/lost/restart
* cycles.
*/
switch (gsm_service_get_status (service))
{
case GSM_SERVICE_STATUS_ACTIVATING:
case GSM_SERVICE_STATUS_STARTING:
case GSM_SERVICE_STATUS_RUNNING:
gsm_service_set_status (service, GSM_SERVICE_STATUS_STOPPED);
if (!gsm_service_is_disabled (service))
{
GError *error;
gsm_verbose ("Service '%s' was %s when released, "
"restarting\n", dbus_name,
(gsm_service_get_status (service) ==
GSM_SERVICE_STATUS_STARTING)? "starting" : "running");
/* FIXME: Report this problem to the user
*/
error = NULL;
if (!gsm_service_manager_start_service_and_dependencies (manager,
service,
&error))
{
g_assert (error != NULL);
gsm_warning ("could not start service '%s': %s\n",
gsm_service_get_dbus_name (service), error->message);
g_error_free (error);
}
}
else
gsm_verbose ("Service '%s' was already disabled when lost,"
"not restarting\n", dbus_name);
break;
case GSM_SERVICE_STATUS_STOPPING:
gsm_verbose ("Service '%s' was stopping when released. "
"Making note it has stopped.\n", dbus_name);
gsm_service_set_status (service, GSM_SERVICE_STATUS_STOPPED);
break;
case GSM_SERVICE_STATUS_STOPPED:
gsm_verbose ("Service '%s' was already stopped when released.\n",
dbus_name);
break;
default:
gsm_warning ("Service '%s' was in unknown state %u when "
"released\n", dbus_name,
gsm_service_get_status (service));
break;
}
}
static void
gsm_service_manager_service_gained_name_handler (GsmServiceManager *manager,
GsmService *service)
{
const gchar *dbus_name;
dbus_name = gsm_service_get_dbus_name (service);
gsm_verbose ("Service '%s' has been acquired on session bus\n",
dbus_name);
/* Service was gained--make note that the service is starting now
* if it wasn't already noted.
*/
switch (gsm_service_get_status (service))
{
case GSM_SERVICE_STATUS_ACTIVATING:
gsm_verbose ("Service '%s' was in activating state, noting it has "
"been activated and is now starting\n", dbus_name);
gsm_service_set_status (service, GSM_SERVICE_STATUS_STARTING);
break;
case GSM_SERVICE_STATUS_STARTING:
gsm_verbose ("Service '%s' is already in 'starting' state\n",
dbus_name);
break;
case GSM_SERVICE_STATUS_RUNNING:
gsm_warning ("Service manager thought service '%s' was already "
"running, but it claims to be just starting\n",
dbus_name);
case GSM_SERVICE_STATUS_STOPPING:
case GSM_SERVICE_STATUS_STOPPED:
{
gsm_service_set_status (service, GSM_SERVICE_STATUS_STARTING);
}
break;
default:
gsm_warning ("Service '%s' was in unknown state %u when "
"acquired\n", dbus_name,
gsm_service_get_status (service));
gsm_service_set_status (service, GSM_SERVICE_STATUS_STARTING);
break;
}
}
static DBusHandlerResult
gsm_service_manager_name_owner_changed_handler (GsmServiceManager *manager,
DBusMessage *message)
{
DBusError error;
GsmService *service;
const gchar *dbus_name, *previous_unique_name, *new_unique_name;
dbus_error_init (&error);
dbus_message_get_args (message, &error,
DBUS_TYPE_STRING, &dbus_name,
DBUS_TYPE_STRING, &previous_unique_name,
DBUS_TYPE_STRING, &new_unique_name,
DBUS_TYPE_INVALID);
if (dbus_error_is_set (&error))
{
gsm_warning ("could not get args from 'NameOwnerChanged' signal: %s",
error.message);
dbus_error_free (&error);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
g_assert (dbus_name != NULL);
/* Short-cuts to save needless hash table lookups
*/
if (dbus_name[0] == ':')
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
if (g_str_equal (dbus_name, "org.gnome.ServiceManager"))
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
service = g_hash_table_lookup (manager->priv->service_dbus_name_map,
dbus_name);
if (service == NULL)
{
gsm_verbose ("'%s' is not managed by service manager\n",
dbus_name);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
if ((new_unique_name == NULL) ||
(new_unique_name[0] == '\0'))
gsm_service_manager_service_lost_name_handler (manager, service);
else
gsm_service_manager_service_gained_name_handler (manager, service);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult
gsm_service_manager_filtering_message_handler (DBusConnection *connection,
DBusMessage *message,
GsmServiceManager *manager)
{
if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
"NameOwnerChanged"))
{
if (dbus_message_has_signature (message, "sss"))
{
gsm_service_manager_name_owner_changed_handler (manager, message);
return DBUS_HANDLER_RESULT_HANDLED;
}
else
gsm_warning ("NameOwnerChanged method has the wrong signature");
}
else if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL)
{
/* FIXME: Shouldn't be necessary, but filter function seems to get
* called sometimes when the registered objects don't
*/
const gchar *interface, *object_path;
interface = dbus_message_get_interface (message);
object_path = dbus_message_get_path (message);
if (interface != NULL)
{
if (g_str_equal (interface, GSM_MANAGED_SERVICE_INTERFACE))
{
return gsm_service_manager_dbus_message_handler (connection,
message,
manager);
}
else if ((object_path != NULL) &&
g_str_equal (interface, GSM_MANAGED_SERVICE_INTERFACE) &&
g_str_has_prefix (object_path,
GSM_MANAGED_SERVICE_OBJECT_PATH_PREFIX))
{
return gsm_service_manager_managed_object_dbus_message_handler
(connection, message, manager);
}
}
}
else if (dbus_message_get_member (message) != NULL)
gsm_verbose ("message '%s' received and ignored by filter\n",
dbus_message_get_member (message));
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static void
gsm_service_manager_register_dbus_message_handlers (GsmServiceManager *manager)
{
DBusError error;
static const DBusObjectPathVTable manager_vtable =
{
unregister_function: (DBusObjectPathUnregisterFunction) NULL,
message_function: (DBusObjectPathMessageFunction)
gsm_service_manager_dbus_message_handler
};
static const DBusObjectPathVTable managed_object_vtable =
{
unregister_function: (DBusObjectPathUnregisterFunction) NULL,
message_function: (DBusObjectPathMessageFunction)
gsm_service_manager_managed_object_dbus_message_handler
};
g_return_if_fail (!manager->priv->dbus_message_handlers_are_registered);
dbus_error_init (&error);
/* for NameOwnerChanged */
dbus_bus_add_match (manager->priv->dbus_connection,
"sender='"DBUS_SERVICE_DBUS"',"
"interface='"DBUS_INTERFACE_DBUS"',"
"type='signal',"
"member='NameOwnerChanged'", &error);
if (dbus_error_is_set (&error))
{
gsm_warning ("Could not add NameOwnerChange match filter: %s\n",
error.message);
dbus_error_free (&error);
}
dbus_bus_add_match (manager->priv->dbus_connection, "type='signal'", &error);
/* for replies from client library (maybe not needed?) */
dbus_bus_add_match (manager->priv->dbus_connection,
"interface='"GSM_SERVICE_INTERFACE"'", &error);
if (dbus_error_is_set (&error))
{
gsm_warning ("Could not add NameOwnerChange match filter: %s\n",
error.message);
dbus_error_free (&error);
}
/* for service manager methods */
/*
dbus_bus_add_match (manager->priv->dbus_connection,
"interface='"GSM_SERVICE_MANAGER_INTERFACE"',"
"type='method_call'", &error);
if (dbus_error_is_set (&error))
{
gsm_warning ("Could not add NameOwnerChange match filter: %s\n",
error.message);
dbus_error_free (&error);
}
*/
/* for managed object methods */
/*
dbus_bus_add_match (manager->priv->dbus_connection,
"interface='"GSM_MANAGED_SERVICE_INTERFACE"'", &error);
if (dbus_error_is_set (&error))
{
gsm_warning ("Could not add Managed Service match filter: %s\n",
error.message);
dbus_error_free (&error);
}
*/
dbus_connection_register_object_path (manager->priv->dbus_connection,
GSM_SERVICE_MANAGER_OBJECT_PATH,
&manager_vtable, manager);
dbus_connection_register_fallback (manager->priv->dbus_connection,
GSM_MANAGED_SERVICE_OBJECT_PATH_PREFIX,
&managed_object_vtable, manager);
dbus_connection_add_filter (manager->priv->dbus_connection,
(DBusHandleMessageFunction)
gsm_service_manager_filtering_message_handler,
manager, NULL);
manager->priv->dbus_message_handlers_are_registered = TRUE;
}
static void
gsm_service_manager_unregister_dbus_message_handlers (GsmServiceManager *manager)
{
if (!manager->priv->dbus_message_handlers_are_registered)
return;
dbus_connection_remove_filter (manager->priv->dbus_connection,
(DBusHandleMessageFunction)
gsm_service_manager_filtering_message_handler,
manager);
dbus_connection_unregister_object_path (manager->priv->dbus_connection,
GSM_SERVICE_MANAGER_OBJECT_PATH);
dbus_connection_unregister_object_path (manager->priv->dbus_connection,
GSM_MANAGED_SERVICE_OBJECT_PATH_PREFIX);
manager->priv->dbus_message_handlers_are_registered = FALSE;
}
gboolean
gsm_service_manager_connect_to_bus (GsmServiceManager *manager)
{
DBusError error;
DBusConnection *dbus_connection;
dbus_error_init (&error);
dbus_connection = dbus_bus_get (DBUS_BUS_SESSION, &error);
if (dbus_connection == NULL)
{
g_assert (dbus_error_is_set (&error));
gsm_warning ("Could not get connection to the session bus: %s\n",
error.message);
dbus_error_free (&error);
return FALSE;
}
dbus_connection_set_exit_on_disconnect (dbus_connection, TRUE);
dbus_connection_setup_with_g_main (dbus_connection, NULL);
manager->priv->dbus_connection = dbus_connection;
gsm_service_manager_register_dbus_message_handlers (manager);
dbus_bus_request_name (dbus_connection, "org.gnome.ServiceManager",
DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT, &error);
if (dbus_error_is_set (&error))
{
gsm_warning ("Could not request name: %s\n", error.message);
dbus_error_free (&error);
return FALSE;
}
return TRUE;
}
void
gsm_service_manager_disconnect_from_bus (GsmServiceManager *manager)
{
gsm_service_manager_unregister_dbus_message_handlers (manager);
manager->priv->dbus_connection = NULL;
}
/*** Querying services ***/
/*** Starting of services ***/
static gboolean
gsm_service_manager_service_is_startable (GsmService *service)
{
GList *dependency_list, *tmp;
gsm_verbose ("checking if service '%s' is startable\n",
gsm_service_get_dbus_name (service));
if (gsm_service_is_disabled (service))
{
gsm_verbose ("service '%s' is not startable: service is disabled\n",
gsm_service_get_dbus_name (service));
return FALSE;
}
dependency_list =
g_object_get_data (G_OBJECT (service),
"gsm-service-manager-service-dependency-list");
tmp = dependency_list;
while (tmp != NULL)
{
GsmService *other_dependency;
other_dependency = GSM_SERVICE (tmp->data);
if (gsm_service_get_status (other_dependency) !=
GSM_SERVICE_STATUS_RUNNING)
{
gsm_verbose ("service '%s' is not startable: waiting on service '%s'"
"\n",
gsm_service_get_dbus_name (service),
gsm_service_get_dbus_name (other_dependency));
return FALSE;
}
tmp = tmp->next;
}
gsm_verbose ("service '%s' is not startable!\n",
gsm_service_get_dbus_name (service));
return TRUE;
}
static gboolean
print_failed_services (GsmServiceManager *manager)
{
GList *services, *tmp;
services = g_queue_peek_head_link (manager->priv->failed_services);
g_print ("Services that have failed: [\n ");
tmp = services;
while (tmp != NULL)
{
GsmService *service;
const gchar *name;
service = GSM_SERVICE (tmp->data);
name = gsm_service_get_name (service);
g_print ("'%s' : \"%s\"\n ", name,
(gchar *) g_object_get_data (G_OBJECT (service),
"gsm-service-reason-failed"));
tmp = tmp->next;
}
g_print ("]\n");
return TRUE;
}
static void
gsm_service_manager_service_started_handler (GsmServiceManager *manager,
GsmService *service)
{
const gchar *name;
name = gsm_service_get_name (service);
gsm_verbose ("service '%s' is now running\n", name);
}
static void
gsm_service_manager_error_starting_service_handler (GsmServiceManager *manager,
GError *error,
GsmService *service)
{
const gchar *name;
name = gsm_service_get_name (service);
g_assert (error != NULL);
gsm_warning ("service '%s' was not started: %s\n", name,
error->message);
if (manager->priv->failed_services == NULL)
{
manager->priv->failed_services = g_queue_new ();
g_timeout_add (1000, (GSourceFunc) print_failed_services, manager);
}
g_queue_push_tail (manager->priv->failed_services,
g_object_ref (G_OBJECT (service)));
g_object_set_data (G_OBJECT (service), "gsm-service-reason-failed",
g_strdup (error->message));
}
static GsmService *
gsm_service_manager_lookup_service (GsmServiceManager *manager,
const gchar *dbus_name)
{
GsmService *service;
service = g_hash_table_lookup (manager->priv->service_dbus_name_map,
dbus_name);
return service;
}
static void
gsm_service_manager_service_dependency_startup_complete_handler (GsmService *service,
GsmService *dependency)
{
gsm_verbose ("service '%s' is done starting up\n",
gsm_service_get_dbus_name (dependency));
if ((gsm_service_get_status (service) != GSM_SERVICE_STATUS_RUNNING) &&
(gsm_service_get_status (service) != GSM_SERVICE_STATUS_ACTIVATING) &&
(gsm_service_get_status (service) != GSM_SERVICE_STATUS_STARTING) &&
gsm_service_manager_service_is_startable (service))
{
GsmServiceManager *manager;
gsm_verbose ("service '%s' can now be started\n",
gsm_service_get_dbus_name (service));
manager = g_object_get_data (G_OBJECT (service), "gsm-service-manager");
gsm_service_start (service, manager->priv->dbus_connection);
}
else
gsm_verbose ("cannot startup service '%s' yet\n",
gsm_service_get_dbus_name (service));
}
static void
gsm_service_manager_disconnect_service_from_dependencies (GsmServiceManager *manager,
GsmService *service)
{
GList *dependency_list, *tmp;
dependency_list =
g_object_get_data (G_OBJECT (service),
"gsm-service-manager-service-dependency-list");
tmp = dependency_list;
while (tmp != NULL)
{
GList *next;
GsmService *dependency;
dependency = GSM_SERVICE (tmp->data);
gsm_service_manager_disconnect_service_from_dependencies (manager,
dependency);
g_signal_handlers_disconnect_by_func (G_OBJECT (dependency),
G_CALLBACK (gsm_service_manager_service_dependency_startup_complete_handler),
service);
next = tmp->next;
dependency_list = g_list_remove_link (dependency_list, tmp);
g_list_free_1 (tmp);
g_object_unref (dependency);
tmp = next;
}
g_object_set_data (G_OBJECT (service),
"gsm-service-manager-service-dependency-list", NULL);
}
static gboolean
gsm_service_manager_start_service_and_dependencies (GsmServiceManager *manager,
GsmService *service,
GError **error)
{
gchar **dependencies;
const gchar *name;
guint i;
gboolean dependencies_started;
if ((gsm_service_get_status (service) == GSM_SERVICE_STATUS_STARTING) ||
(gsm_service_get_status (service) == GSM_SERVICE_STATUS_ACTIVATING) ||
(gsm_service_get_status (service) == GSM_SERVICE_STATUS_RUNNING))
return TRUE;
dependencies_started = TRUE;
name = gsm_service_get_name (service);
gsm_verbose ("starting service '%s' and its dependencies\n", name);
dependencies = gsm_service_get_dependencies (service);
if (dependencies != NULL)
{
#ifdef DEBUG
gchar *services_to_wait_for;
services_to_wait_for = g_strjoinv (", ", dependencies);
gsm_verbose ("service '%s' is waiting to start on services: %s\n",
name, services_to_wait_for);
g_free (services_to_wait_for);
#endif
for (i = 0; dependencies[i] != NULL; i++)
{
GsmService *dependency;
dependency = gsm_service_manager_lookup_service (manager,
dependencies[i]);
if (dependency == NULL)
{
gsm_service_manager_disconnect_service_from_dependencies (manager,
service);
gsm_warning ("couldn't find service '%s' to startup service '%s'\n",
name, dependencies[i]);
g_set_error (error, GSM_SERVICE_MANAGER_ERROR,
GSM_SERVICE_MANAGER_SERVICE_NOT_FOUND,
_("service '%s' needs service '%s' but it "
"cannot be found"), name, dependencies[i]);
g_strfreev (dependencies);
return FALSE;
}
else
{
GList *dependency_list, *dependents_list;
GError *dependency_error;
GsmServiceStatus status;
dependency_error = NULL;
status = gsm_service_get_status (dependency);
if ((status == GSM_SERVICE_STATUS_STOPPING) ||
(status == GSM_SERVICE_STATUS_STOPPED))
{
if (!gsm_service_manager_start_service_and_dependencies (manager,
dependency,
&dependency_error))
{
gsm_service_manager_disconnect_service_from_dependencies (manager,
service);
g_propagate_error (error, dependency_error);
g_strfreev (dependencies);
return FALSE;
}
}
dependency_list =
g_object_get_data (G_OBJECT (service),
"gsm-service-manager-service-dependency-list");
if (!g_list_find (dependency_list, dependency))
{
dependency_list = g_list_prepend (dependency_list,
g_object_ref (dependency));
g_object_set_data (G_OBJECT (service),
"gsm-service-manager-service-dependency-list",
dependency_list);
}
dependents_list =
g_object_get_data (G_OBJECT (dependency),
"gsm-service-manager-service-dependents-list");
if (!g_list_find (dependents_list, service))
{
dependents_list = g_list_prepend (dependents_list,
g_object_ref (service));
g_object_set_data (G_OBJECT (dependency),
"gsm-service-manager-service-dependents-list",
dependents_list);
}
if (status != GSM_SERVICE_STATUS_RUNNING)
{
g_signal_connect_swapped (G_OBJECT (dependency),
"startup-complete",
G_CALLBACK (gsm_service_manager_service_dependency_startup_complete_handler),
service);
dependencies_started = FALSE;
}
}
}
}
if (dependencies_started)
{
gsm_verbose ("service '%s' has no unstarted dependencies, "
"starting immediately\n",
name);
gsm_service_start (service,
manager->priv->dbus_connection);
}
g_strfreev (dependencies);
return TRUE;
}
static void
gsm_service_manager_stop_service_and_dependents (GsmServiceManager *manager,
GsmService *service)
{
GList *dependent_list, *tmp;
gsm_verbose ("stopping service '%s' and other services that depend on it\n",
gsm_service_get_name (service));
gsm_service_manager_disconnect_service_from_dependencies (manager,
service);
dependent_list =
g_object_get_data (G_OBJECT (service),
"gsm-service-manager-service-dependents-list");
tmp = dependent_list;
while (tmp != NULL)
{
GsmService *dependent;
dependent = GSM_SERVICE (tmp->data);
gsm_service_manager_stop_service_and_dependents (manager, dependent);
g_object_unref (G_OBJECT (dependent));
tmp = tmp->next;
}
g_list_free (dependent_list);
g_object_set_data (G_OBJECT (service),
"gsm-service-manager-service-dependents-list",
NULL);
gsm_service_stop (service, manager->priv->dbus_connection);
}
static void
gsm_service_manager_start_services_and_dependencies (GsmServiceManager *manager)
{
GList *tmp;
gsm_verbose ("starting services and dependencies\n");
tmp = g_queue_peek_head_link (manager->priv->services);
while (tmp)
{
GError *error;
GsmService *service;
service = GSM_SERVICE (tmp->data);
error = NULL;
if (!gsm_service_manager_start_service_and_dependencies (manager, service,
&error))
{
gsm_warning ("could not start all the dependencies of service '%s'%s%s\n",
gsm_service_get_name (service),
error != NULL? ": " : "", error->message);
if (error != NULL)
g_error_free (error);
}
tmp = tmp->next;
}
g_signal_emit (manager, gsm_service_manager_signals[STARTUP_COMPLETE], NULL);
}
static void
gsm_service_manager_stop_services_and_dependents (GsmServiceManager *manager)
{
GList *tmp;
gsm_verbose ("stopping services and dependendents\n");
tmp = g_queue_peek_head_link (manager->priv->services);
while (tmp)
{
GsmService *service;
service = GSM_SERVICE (tmp->data);
gsm_service_manager_stop_service_and_dependents (manager, service);
tmp = tmp->next;
}
}
/**
* gsm_service_manager_start:
* @manager: a #GsmServiceManager
*
* Starts all the services managed by @manager, taking
* dependencies between services into account. Services
* are not started if they have been disabled. The
* starting is done asynchronously, so this function
* will return immediately.
*/
void
gsm_service_manager_start (GsmServiceManager *manager)
{
if (g_queue_is_empty (manager->priv->services))
{
gsm_verbose ("No services to start\n");
return;
}
gsm_service_manager_start_services_and_dependencies (manager);
}
/**
* gsm_service_manager_stop:
* @manager: a #GsmServiceManager
*
* Stops all the services managed by @manager, taking
* dependencies declared in the .desktop-service files into account.
* The stopping is done asynchronously, so this function
* will return immediately.
*/
void
gsm_service_manager_stop (GsmServiceManager *manager)
{
gsm_service_manager_stop_services_and_dependents (manager);
}
static void
gsm_service_manager_service_status_changed_handler (GsmServiceManager *manager,
gpointer useless_param,
GsmService *service)
{
gdouble timestamp;
const gchar *signal;
const gchar *name, *dbus_name;
name = gsm_service_get_name (service);
timestamp = gsm_service_manager_get_timestamp ();
switch (gsm_service_get_status (service))
{
case GSM_SERVICE_STATUS_ACTIVATING:
gsm_verbose ("Service '%s' changed status to 'starting'\n",
name);
signal = "ServiceActivating";
break;
case GSM_SERVICE_STATUS_STARTING:
gsm_verbose ("Service '%s' changed status to 'starting'\n",
name);
signal = "ServiceStarting";
break;
case GSM_SERVICE_STATUS_RUNNING:
gsm_verbose ("Service '%s' changed status to 'running'\n",
name);
signal = "ServiceStarted";
break;
case GSM_SERVICE_STATUS_STOPPING:
gsm_verbose ("Service '%s' changed status to 'stopping'\n",
name);
signal = "ServiceStopping";
break;
case GSM_SERVICE_STATUS_STOPPED:
gsm_verbose ("Service '%s' changed status to 'stopped'\n",
name);
signal = "ServiceStopped";
break;
default:
gsm_warning ("Status '%u' is unknown!",
gsm_service_get_status (service));
signal = NULL;
break;
}
dbus_name = gsm_service_get_dbus_name (service);
if (signal != NULL)
{
gsm_verbose ("emitting signal '"GSM_SERVICE_MANAGER_INTERFACE".%s' "
"from object '"GSM_SERVICE_MANAGER_OBJECT_PATH"'\n", signal);
gsm_dbus_emit_signal (manager->priv->dbus_connection,
GSM_SERVICE_MANAGER_OBJECT_PATH,
GSM_SERVICE_MANAGER_INTERFACE,
signal,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &dbus_name,
DBUS_TYPE_DOUBLE, ×tamp,
DBUS_TYPE_INVALID);
}
}
/*** Debugging and testing ***/
#if 0 && defined (DEBUG)
static void
dump_cb (gpointer key,
gpointer value,
gpointer data)
{
GsmService *service = value;
const gchar *name, *dbus_name;
gchar **dependencies;
name = gsm_service_get_name (service);
dbus_name = gsm_service_get_dbus_name (service);
g_print ("service %s (%s), status '%s' %s\n", name, dbus_name,
gsm_service_status_as_string (gsm_service_get_status (service)),
gsm_service_is_disabled (service) ? ", disabled" : "");
dependencies = gsm_service_get_dependencies (service);
if (dependencies)
{
gsize i;
g_print ("\tdepends on");
for (i = 0; dependencies[i]; i++)
g_print ("%s %s", i > 0 ? "," : "", dependencies[i]);
g_print ("\n");
}
g_strfreev (dependencies);
}
static void
dump_services (GsmServiceManager *manager,
gint step,
const gchar *title)
{
g_print ("\nStep %d (%s)^\n================================\n\n", step, title);
g_hash_table_foreach (manager->priv->service_dbus_name_map, dump_cb, NULL);
}
static gboolean is_started_up = FALSE;
static void
startup_complete (void)
{
gsm_verbose ("Startup is now complete\n");
is_started_up = TRUE;
}
static gboolean
test_timeout (gpointer data)
{
static gint step = 0;
static gboolean run_again;
GMainLoop *loop = data;
static GsmServiceManager *manager = NULL;
run_again = TRUE;
switch (step)
{
case 0:
manager = gsm_service_manager_new ();
g_signal_connect (G_OBJECT (manager), "startup-complete",
startup_complete, NULL);
break;
case 1:
dump_services (manager, step / 2, "new");
break;
case 2:
run_again = gsm_service_manager_connect_to_bus (manager);
break;
case 3:
dump_services (manager, step / 2, "connect to bus");
break;
case 4:
gsm_service_manager_start (manager);
break;
case 5:
dump_services (manager, step / 2, "start");
if (!is_started_up)
step--;
break;
#if 0
case 6:
gsm_service_manager_stop (manager);
break;
case 7:
dump_services (manager, step / 2, "stop");
break;
case 8:
{
GsmServiceBatch *batch;
GsmService *service;
service = g_hash_table_lookup (manager->priv->service_dbus_name_map, "org.gnome.Panel");
if (service == NULL)
{
gsm_warning ("service 'org.gnome.Panel' is not loaded");
run_again = FALSE;
}
else
{
batch = gsm_service_batch_new_from_service (manager, service);
gsm_service_batch_set_operation (batch,
GSM_SERVICE_BATCH_OPERATION_START);
gsm_service_manager_add_batch (manager, batch);
gsm_service_manager_queue_batch (manager);
}
}
break;
case 9:
dump_services (manager, step / 2, "start org.gnome.Panel");
break;
case 10:
{
GsmServiceBatch *batch;
GsmService *service;
service = g_hash_table_lookup (manager->priv->service_dbus_name_map, "org.gnome.Nautilus");
if (service == NULL)
{
gsm_warning ("service 'org.gnome.Nautilus' is not loaded");
run_again = FALSE;
}
else
{
batch = gsm_service_batch_new_from_service (manager, service);
gsm_service_batch_set_operation (batch,
GSM_SERVICE_BATCH_OPERATION_STOP);
gsm_service_manager_add_batch (manager, batch);
gsm_service_manager_queue_batch (manager);
}
}
break;
case 11:
dump_services (manager, step / 2, "stop org.gnome.Nautilus");
break;
case 12:
{
GsmServiceBatch *batch;
GsmService *service;
service = g_hash_table_lookup (manager->priv->service_dbus_name_map, "org.gnome.Keyring");
if (service == NULL)
{
gsm_warning ("service 'org.gnome.Keyring' is not loaded");
run_again = FALSE;
}
else
{
gsm_service_set_disabled (service, TRUE);
batch = gsm_service_batch_new_from_service (manager, service);
gsm_service_batch_set_operation (batch,
GSM_SERVICE_BATCH_OPERATION_STOP);
gsm_service_manager_add_batch (manager, batch);
gsm_service_manager_queue_batch (manager);
}
}
break;
case 13:
dump_services (manager, step / 2, "disable org.gnome.Keyring");
break;
case 14:
gsm_service_manager_start (manager);
break;
case 15:
dump_services (manager, step / 2, "start");
break;
case 16:
{
GsmServiceBatch *batch;
GsmService *service;
service = g_hash_table_lookup (manager->priv->service_dbus_name_map, "org.gnome.Keyring");
if (service == NULL)
{
gsm_warning ("service 'org.gnome.Keyring' is not loaded");
run_again = FALSE;
}
else
{
gsm_service_set_disabled (service, FALSE);
batch = gsm_service_batch_new_from_service (manager, service);
gsm_service_batch_set_operation (batch,
GSM_SERVICE_BATCH_OPERATION_START);
gsm_service_manager_add_batch (manager, batch);
gsm_service_manager_queue_batch (manager);
}
}
break;
case 17:
dump_services (manager, step / 2, "enable org.gnome.Keyring");
break;
#endif
default:
g_object_unref (manager);
g_main_loop_quit (loop);
break;
}
step++;
return run_again;
}
int
main (int argc, char *argv[])
{
GMainLoop *loop;
g_type_init ();
loop = g_main_loop_new (NULL, FALSE);
g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 1000, test_timeout, loop,
(GDestroyNotify) g_main_loop_quit);
g_main_loop_run (loop);
return 0;
}
#endif
/* gsm-service-manager.h - Manage services
*
* Copyright (C) 2005 Matthias Clasen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef GSM_SERVICE_MANAGER_H
#define GSM_SERVICE_MANAGER_H
#include <glib.h>
#include <glib-object.h>
G_BEGIN_DECLS
#define GSM_TYPE_SERVICE_MANAGER (gsm_service_manager_get_type ())
#define GSM_SERVICE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSM_TYPE_SERVICE_MANAGER, GsmServiceManager))
#define GSM_SERVICE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSM_TYPE_SERVICE_MANAGER, GsmServiceManagerClass))
#define GSM_IS_SERVICE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSM_TYPE_SERVICE_MANAGER))
#define GSM_IS_SERVICE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSM_TYPE_SERVICE_MANAGER))
#define GSM_SERVICE_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GSM_TYPE_SERVICE_MANAGER, GsmServiceManagerClass))
#define GSM_SERVICE_MANAGER_ERROR (gsm_service_manager_error_quark ())
typedef struct _GsmServiceManager GsmServiceManager;
typedef struct _GsmServiceManagerClass GsmServiceManagerClass;
typedef struct _GsmServiceManagerPrivate GsmServiceManagerPrivate;
typedef enum _GsmServiceManagerError GsmServiceManagerError;
struct _GsmServiceManager {
GObject parent;
/*< private >*/
GsmServiceManagerPrivate *priv;
};
struct _GsmServiceManagerClass {
GObjectClass parent_class;
/* Signals */
/* Virtual functions */
void (* startup_complete) (GsmServiceManager *manager);
};
enum _GsmServiceManagerError {
GSM_SERVICE_MANAGER_ERROR_GENERIC = 0,
GSM_SERVICE_MANAGER_SERVICE_NOT_FOUND
};
GType gsm_service_manager_get_type (void) G_GNUC_CONST;
GQuark gsm_service_manager_error_quark (void) G_GNUC_CONST;
GsmServiceManager *gsm_service_manager_new (void);
gboolean gsm_service_manager_connect_to_bus (GsmServiceManager *manager);
void gsm_service_manager_disconnect_from_bus (GsmServiceManager *manager);
void gsm_service_manager_start (GsmServiceManager *manager);
void gsm_service_manager_stop (GsmServiceManager *manager);
G_END_DECLS
#endif /* GSM_SERVICES_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]