From eaef567cabc5c0dda9706faa0e17e20909131ade Mon Sep 17 00:00:00 2001 From: simpoir Date: Fri, 30 Jan 2009 04:14:48 +0000 Subject: ajout initial du tree jhbuild [jhbuild base] --- (limited to 'src/sugar/gsm-app.c') diff --git a/src/sugar/gsm-app.c b/src/sugar/gsm-app.c new file mode 100644 index 0000000..3a63bac --- /dev/null +++ b/src/sugar/gsm-app.c @@ -0,0 +1,396 @@ +/* app.c + * Copyright (C) 2007 Novell, Inc. + * + * 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 of the + * License, 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 + * Lesser 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 HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "gsm-app.h" + +enum { + EXITED, + REGISTERED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +enum { + PROP_0, + + PROP_DESKTOP_FILE, + PROP_CLIENT_ID, + + LAST_PROP +}; + +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 dispose (GObject *object); + +static const char *get_basename (GsmApp *app); +static pid_t launch (GsmApp *app, GError **err); + +G_DEFINE_TYPE (GsmApp, gsm_app, G_TYPE_OBJECT) + +static void +gsm_app_init (GsmApp *app) +{ + app->pid = -1; +} + +static void +gsm_app_class_init (GsmAppClass *app_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (app_class); + + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->dispose = dispose; + + app_class->get_basename = get_basename; + app_class->launch = launch; + + g_object_class_install_property (object_class, + PROP_DESKTOP_FILE, + g_param_spec_string ("desktop-file", + "Desktop file", + "Freedesktop .desktop file", + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_CLIENT_ID, + g_param_spec_string ("client-id", + "Client ID", + "Session management client ID", + NULL, + G_PARAM_READWRITE)); + + signals[EXITED] = + g_signal_new ("exited", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GsmAppClass, exited), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + signals[REGISTERED] = + g_signal_new ("registered", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GsmAppClass, registered), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + GsmApp *app = GSM_APP (object); + const char *desktop_file; + char *phase; + GError *error = NULL; + + switch (prop_id) + { + case PROP_DESKTOP_FILE: + if (app->desktop_file) + egg_desktop_file_free (app->desktop_file); + desktop_file = g_value_get_string (value); + if (!desktop_file) + { + app->desktop_file = NULL; + break; + } + + app->desktop_file = egg_desktop_file_new (desktop_file, &error); + if (!app->desktop_file) + { + g_warning ("Could not parse desktop file %s: %s", + desktop_file, error->message); + g_error_free (error); + break; + } + + phase = egg_desktop_file_get_string (app->desktop_file, + "X-GNOME-Autostart-Phase", NULL); + if (phase) + { + if (!strcmp (phase, "Initialization")) + app->phase = GSM_SESSION_PHASE_INITIALIZATION; + else if (!strcmp (phase, "WindowManager")) + app->phase = GSM_SESSION_PHASE_WINDOW_MANAGER; + else if (!strcmp (phase, "Panel")) + app->phase = GSM_SESSION_PHASE_PANEL; + else if (!strcmp (phase, "Desktop")) + app->phase = GSM_SESSION_PHASE_DESKTOP; + else + app->phase = GSM_SESSION_PHASE_APPLICATION; + + g_free (phase); + } + else + app->phase = GSM_SESSION_PHASE_APPLICATION; + break; + + case PROP_CLIENT_ID: + g_free (app->client_id); + app->client_id = g_value_dup_string (value); + break; + + default: + break; + } +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + GsmApp *app = GSM_APP (object); + + switch (prop_id) + { + case PROP_DESKTOP_FILE: + if (app->desktop_file) + g_value_set_string (value, egg_desktop_file_get_source (app->desktop_file)); + else + g_value_set_string (value, NULL); + break; + + case PROP_CLIENT_ID: + g_value_set_string (value, app->client_id); + break; + + default: + break; + } +} + +static void +dispose(GObject *object) +{ + GsmApp *app = GSM_APP (object); + + if (app->desktop_file) + { + egg_desktop_file_free (app->desktop_file); + app->desktop_file = NULL; + } + + if (app->startup_id) + { + g_free (app->startup_id); + app->startup_id = NULL; + } + + if (app->client_id) + { + g_free (app->client_id); + app->client_id = NULL; + } +} + +/** + * gsm_app_get_basename: + * @app: a %GsmApp + * + * Returns an identifying name for @app, e.g. the basename of the path to + * @app's desktop file (if any). + * + * Return value: an identifying name for @app, or %NULL. + **/ +const char * +gsm_app_get_basename (GsmApp *app) +{ + return GSM_APP_GET_CLASS (app)->get_basename (app); +} + +static const char * +get_basename (GsmApp *app) +{ + const char *location, *slash; + + if (!app->desktop_file) + return NULL; + + location = egg_desktop_file_get_source (app->desktop_file); + + slash = strrchr (location, '/'); + if (slash) + return slash + 1; + else + return location; +} + +/** + * gsm_app_get_phase: + * @app: a %GsmApp + * + * Returns @app's startup phase. + * + * Return value: @app's startup phase + **/ +GsmSessionPhase +gsm_app_get_phase (GsmApp *app) +{ + g_return_val_if_fail (GSM_IS_APP (app), GSM_SESSION_PHASE_APPLICATION); + + return app->phase; +} + +/** + * gsm_app_is_disabled: + * @app: a %GsmApp + * + * Tests if @app is disabled + * + * Return value: whether or not @app is disabled + **/ +gboolean +gsm_app_is_disabled (GsmApp *app) +{ + g_return_val_if_fail (GSM_IS_APP (app), FALSE); + + if (GSM_APP_GET_CLASS (app)->is_disabled) + return GSM_APP_GET_CLASS (app)->is_disabled (app); + else + return FALSE; +} + +gboolean +gsm_app_provides (GsmApp *app, const char *service) +{ + char **provides; + gsize len, i; + + g_return_val_if_fail (GSM_IS_APP (app), FALSE); + + if (!app->desktop_file) + return FALSE; + + provides = egg_desktop_file_get_string_list (app->desktop_file, + "X-GNOME-Provides", + &len, NULL); + if (!provides) + return FALSE; + + for (i = 0; i < len; i++) + { + if (!strcmp (provides[i], service)) + { + g_strfreev (provides); + return TRUE; + } + } + + g_strfreev (provides); + return FALSE; +} + +static void +app_exited (GPid pid, gint status, gpointer data) +{ + if (WIFEXITED (status)) + g_signal_emit (GSM_APP (data), signals[EXITED], 0); +} + +static pid_t +launch (GsmApp *app, + GError **err) +{ + char *env[2] = { NULL, NULL }; + gboolean success; + + g_return_val_if_fail (app->desktop_file != NULL, (pid_t)-1); + + if (egg_desktop_file_get_boolean (app->desktop_file, + "X-GNOME-Autostart-Notify", NULL) || + egg_desktop_file_get_boolean (app->desktop_file, + "AutostartNotify", NULL)) + env[0] = g_strdup_printf ("DESKTOP_AUTOSTART_ID=%s", app->client_id); + +#if 0 + g_debug ("launching %s with client_id %s\n", + gsm_app_get_basename (app), app->client_id); +#endif + + success = + egg_desktop_file_launch (app->desktop_file, NULL, err, + EGG_DESKTOP_FILE_LAUNCH_PUTENV, env, + EGG_DESKTOP_FILE_LAUNCH_FLAGS, G_SPAWN_DO_NOT_REAP_CHILD, + EGG_DESKTOP_FILE_LAUNCH_RETURN_PID, &app->pid, + EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID, &app->startup_id, + NULL); + + g_free (env[0]); + + if (success) + { + /* In case the app belongs to Initialization phase, we monitor + * if it exits to emit proper "exited" signal to session. */ + if (app->phase == GSM_SESSION_PHASE_INITIALIZATION) + g_child_watch_add ((GPid) app->pid, app_exited, app); + + return app->pid; + } + else + return (pid_t) -1; +} + +/** + * gsm_app_launch: + * @app: a %GsmApp + * @err: an error pointer + * + * Launches @app + * + * Return value: the pid of the new process, or -1 on error + **/ +pid_t +gsm_app_launch (GsmApp *app, GError **err) +{ + return GSM_APP_GET_CLASS (app)->launch (app, err); +} + +/** + * gsm_app_registered: + * @app: a %GsmApp + * + * Emits "registered" signal in @app + **/ +void +gsm_app_registered (GsmApp *app) +{ + g_return_if_fail (GSM_IS_APP (app)); + + g_signal_emit (app, signals[REGISTERED], 0); +} + -- cgit v0.9.1