summaryrefslogtreecommitdiff
path: root/mate-session/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'mate-session/main.c')
-rw-r--r--mate-session/main.c543
1 files changed, 543 insertions, 0 deletions
diff --git a/mate-session/main.c b/mate-session/main.c
new file mode 100644
index 0000000..2d7dd64
--- /dev/null
+++ b/mate-session/main.c
@@ -0,0 +1,543 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2006 Novell, Inc.
+ * Copyright (C) 2008 Red Hat, 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.
+ */
+
+#include <config.h>
+
+#include <libintl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib/gi18n.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-bindings.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "mdm-signal-handler.h"
+#include "mdm-log.h"
+
+#include "gsm-consolekit.h"
+#include "gsm-mateconf.h"
+#include "gsm-util.h"
+#include "gsm-manager.h"
+#include "gsm-xsmp-server.h"
+#include "gsm-store.h"
+
+#define GSM_MATECONF_DEFAULT_SESSION_KEY "/desktop/mate/session/default_session"
+#define GSM_MATECONF_REQUIRED_COMPONENTS_DIRECTORY "/desktop/mate/session/required_components"
+#define GSM_MATECONF_REQUIRED_COMPONENTS_LIST_KEY "/desktop/mate/session/required_components_list"
+
+#define GSM_DBUS_NAME "org.mate.SessionManager"
+
+#define IS_STRING_EMPTY(x) \
+ ((x) == NULL || (x)[0] == '\0')
+
+static gboolean failsafe = FALSE;
+static gboolean show_version = FALSE;
+static gboolean debug = FALSE;
+
+static void on_bus_name_lost(DBusGProxy* bus_proxy, const char* name, gpointer data)
+{
+ g_warning("Lost name on bus: %s, exiting", name);
+ exit(1);
+}
+
+static gboolean acquire_name_on_proxy(DBusGProxy* bus_proxy, const char* name)
+{
+ GError* error;
+ guint result;
+ gboolean res;
+ gboolean ret;
+
+ ret = FALSE;
+
+ if (bus_proxy == NULL)
+ {
+ goto out;
+ }
+
+ error = NULL;
+ res = dbus_g_proxy_call(bus_proxy, "RequestName", &error, G_TYPE_STRING, name, G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &result, G_TYPE_INVALID);
+
+ if (! res)
+ {
+ if (error != NULL)
+ {
+ g_warning("Failed to acquire %s: %s", name, error->message);
+ g_error_free(error);
+ }
+ else
+ {
+ g_warning ("Failed to acquire %s", name);
+ }
+
+ goto out;
+ }
+
+ if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+ {
+ if (error != NULL)
+ {
+ g_warning("Failed to acquire %s: %s", name, error->message);
+ g_error_free(error);
+ }
+ else
+ {
+ g_warning("Failed to acquire %s", name);
+ }
+
+ goto out;
+ }
+
+ /* register for name lost */
+ dbus_g_proxy_add_signal(bus_proxy, "NameLost", G_TYPE_STRING, G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal(bus_proxy, "NameLost", G_CALLBACK(on_bus_name_lost), NULL, NULL);
+
+ ret = TRUE;
+
+ out:
+
+ return ret;
+}
+
+static gboolean acquire_name(void)
+{
+ DBusGProxy* bus_proxy;
+ GError* error;
+ DBusGConnection* connection;
+
+ error = NULL;
+ connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
+
+ if (connection == NULL)
+ {
+ gsm_util_init_error(TRUE, "Could not connect to session bus: %s", error->message);
+ /* not reached */
+ }
+
+ bus_proxy = dbus_g_proxy_new_for_name(connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
+
+ if (!acquire_name_on_proxy(bus_proxy, GSM_DBUS_NAME))
+ {
+ gsm_util_init_error(TRUE, "%s", "Could not acquire name on session bus");
+ /* not reached */
+ }
+
+ g_object_unref(bus_proxy);
+
+ return TRUE;
+}
+
+/* This doesn't contain the required components, so we need to always
+ * call append_required_apps() after a call to append_default_apps(). */
+static void append_default_apps(GsmManager* manager, const char* default_session_key, char** autostart_dirs)
+{
+ GSList* default_apps;
+ GSList* a;
+ MateConfClient* client;
+
+ g_debug("main: *** Adding default apps");
+
+ g_assert(default_session_key != NULL);
+ g_assert(autostart_dirs != NULL);
+
+ client = mateconf_client_get_default();
+ default_apps = mateconf_client_get_list(client, default_session_key, MATECONF_VALUE_STRING, NULL);
+ g_object_unref(client);
+
+ for (a = default_apps; a; a = a->next)
+ {
+ char* app_path;
+
+ if (IS_STRING_EMPTY((char*) a->data))
+ {
+ continue;
+ }
+
+ app_path = gsm_util_find_desktop_file_for_app_name(a->data, autostart_dirs);
+
+ if (app_path != NULL)
+ {
+ gsm_manager_add_autostart_app(manager, app_path, NULL);
+ g_free(app_path);
+ }
+ }
+
+ g_slist_foreach(default_apps, (GFunc) g_free, NULL);
+ g_slist_free(default_apps);
+}
+
+static void append_required_apps(GsmManager* manager)
+{
+ GSList* required_components;
+ GSList* r;
+ MateConfClient* client;
+
+ g_debug("main: *** Adding required apps");
+
+ client = mateconf_client_get_default();
+ required_components = mateconf_client_get_list(client, GSM_MATECONF_REQUIRED_COMPONENTS_LIST_KEY, MATECONF_VALUE_STRING, NULL);
+
+ if (required_components == NULL)
+ {
+ g_warning("No required applications specified");
+ }
+
+ for (r = required_components; r != NULL; r = r->next)
+ {
+ char* path;
+ char* default_provider;
+ const char* component;
+
+ if (IS_STRING_EMPTY((char*) r->data))
+ {
+ continue;
+ }
+
+ component = r->data;
+
+ path = g_strdup_printf("%s/%s", GSM_MATECONF_REQUIRED_COMPONENTS_DIRECTORY, component);
+
+ default_provider = mateconf_client_get_string(client, path, NULL);
+
+ g_debug ("main: %s looking for component: '%s'", path, default_provider);
+
+ if (default_provider != NULL)
+ {
+ char* app_path;
+
+ app_path = gsm_util_find_desktop_file_for_app_name(default_provider, NULL);
+
+ if (app_path != NULL)
+ {
+ gsm_manager_add_autostart_app(manager, app_path, component);
+ }
+ else
+ {
+ g_warning("Unable to find provider '%s' of required component '%s'", default_provider, component);
+ }
+
+ g_free(app_path);
+ }
+
+ g_free(default_provider);
+ g_free(path);
+ }
+
+ g_debug("main: *** Done adding required apps");
+
+ g_slist_foreach(required_components, (GFunc) g_free, NULL);
+ g_slist_free(required_components);
+
+ g_object_unref(client);
+}
+
+static void maybe_load_saved_session_apps(GsmManager* manager)
+{
+ GsmConsolekit* consolekit;
+ char* session_type;
+
+ consolekit = gsm_get_consolekit();
+ session_type = gsm_consolekit_get_current_session_type(consolekit);
+
+ if (g_strcmp0 (session_type, GSM_CONSOLEKIT_SESSION_TYPE_LOGIN_WINDOW) != 0)
+ {
+ gsm_manager_add_autostart_apps_from_dir(manager, gsm_util_get_saved_session_dir());
+ }
+
+ g_object_unref(consolekit);
+ g_free(session_type);
+}
+
+static void load_standard_apps (GsmManager* manager, const char* default_session_key)
+{
+ char** autostart_dirs;
+ int i;
+
+ autostart_dirs = gsm_util_get_autostart_dirs();
+
+ if (!failsafe)
+ {
+ maybe_load_saved_session_apps(manager);
+
+ for (i = 0; autostart_dirs[i]; i++)
+ {
+ gsm_manager_add_autostart_apps_from_dir(manager, autostart_dirs[i]);
+ }
+ }
+
+ /* We do this at the end in case a saved session contains an
+ * application that already provides one of the components. */
+ append_default_apps(manager, default_session_key, autostart_dirs);
+ append_required_apps(manager);
+
+ g_strfreev(autostart_dirs);
+}
+
+static void load_override_apps(GsmManager* manager, char** override_autostart_dirs)
+{
+ int i;
+
+ for (i = 0; override_autostart_dirs[i]; i++)
+ {
+ gsm_manager_add_autostart_apps_from_dir(manager, override_autostart_dirs[i]);
+ }
+}
+
+static gboolean signal_cb(int signo, gpointer data)
+{
+ int ret;
+ GsmManager* manager;
+
+ g_debug("Got callback for signal %d", signo);
+
+ ret = TRUE;
+
+ switch (signo)
+ {
+ case SIGFPE:
+ case SIGPIPE:
+ /* let the fatal signals interrupt us */
+ g_debug ("Caught signal %d, shutting down abnormally.", signo);
+ ret = FALSE;
+ break;
+ case SIGINT:
+ case SIGTERM:
+ manager = (GsmManager*) data;
+ gsm_manager_logout(manager, GSM_MANAGER_LOGOUT_MODE_FORCE, NULL);
+
+ /* let the fatal signals interrupt us */
+ g_debug("Caught signal %d, shutting down normally.", signo);
+ ret = TRUE;
+ break;
+ case SIGHUP:
+ g_debug("Got HUP signal");
+ ret = TRUE;
+ break;
+ case SIGUSR1:
+ g_debug("Got USR1 signal");
+ ret = TRUE;
+ mdm_log_toggle_debug();
+ break;
+ default:
+ g_debug("Caught unhandled signal %d", signo);
+ ret = TRUE;
+
+ break;
+ }
+
+ return ret;
+}
+
+static void shutdown_cb(gpointer data)
+{
+ GsmManager* manager = (GsmManager*) data;
+ g_debug("Calling shutdown callback function");
+
+ /*
+ * When the signal handler gets a shutdown signal, it calls
+ * this function to inform GsmManager to not restart
+ * applications in the off chance a handler is already queued
+ * to dispatch following the below call to gtk_main_quit.
+ */
+ gsm_manager_set_phase(manager, GSM_MANAGER_PHASE_EXIT);
+
+ gtk_main_quit();
+}
+
+static gboolean require_dbus_session(int argc, char** argv, GError** error)
+{
+ char** new_argv;
+ int i;
+
+ if (g_getenv("DBUS_SESSION_BUS_ADDRESS"))
+ {
+ return TRUE;
+ }
+
+ /* Just a sanity check to prevent infinite recursion if
+ * dbus-launch fails to set DBUS_SESSION_BUS_ADDRESS
+ */
+ g_return_val_if_fail(!g_str_has_prefix(argv[0], "dbus-launch"), TRUE);
+
+ /* +2 for our new arguments, +1 for NULL */
+ new_argv = g_malloc(argc + 3 * sizeof (*argv));
+
+ new_argv[0] = "dbus-launch";
+ new_argv[1] = "--exit-with-session";
+
+ for (i = 0; i < argc; i++)
+ {
+ new_argv[i + 2] = argv[i];
+ }
+
+ new_argv[i + 2] = NULL;
+
+ if (!execvp("dbus-launch", new_argv))
+ {
+ g_set_error(error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, "No session bus and could not exec dbus-launch: %s", g_strerror(errno));
+ return FALSE;
+ }
+
+ /* Should not be reached */
+ return TRUE;
+}
+
+int main(int argc, char** argv)
+{
+ struct sigaction sa;
+ GError* error;
+ char* display_str;
+ GsmManager* manager;
+ GsmStore* client_store;
+ GsmXsmpServer* xsmp_server;
+ MdmSignalHandler* signal_handler;
+ static char** override_autostart_dirs = NULL;
+ static char* default_session_key = NULL;
+
+ static GOptionEntry entries[] = {
+ {"autostart", 'a', 0, G_OPTION_ARG_STRING_ARRAY, &override_autostart_dirs, N_("Override standard autostart directories"), NULL},
+ {"default-session-key", 0, 0, G_OPTION_ARG_STRING, &default_session_key, N_("MateConf key used to look up default session"), NULL},
+ {"debug", 0, 0, G_OPTION_ARG_NONE, &debug, N_("Enable debugging code"), NULL},
+ {"failsafe", 'f', 0, G_OPTION_ARG_NONE, &failsafe, N_("Do not load user-specified applications"), NULL},
+ {"version", 0, 0, G_OPTION_ARG_NONE, &show_version, N_("Version of this application"), NULL},
+ {NULL, 0, 0, 0, NULL, NULL, NULL }
+ };
+
+ /* Make sure that we have a session bus */
+ if (!require_dbus_session(argc, argv, &error))
+ {
+ gsm_util_init_error(TRUE, "%s", error->message);
+ }
+
+ bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR);
+ bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
+ textdomain(GETTEXT_PACKAGE);
+
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGPIPE, &sa, 0);
+
+ error = NULL;
+ gtk_init_with_args(&argc, &argv, (char*) _(" - the MATE session manager"), entries, GETTEXT_PACKAGE, &error);
+
+ if (error != NULL)
+ {
+ g_warning("%s", error->message);
+ exit(1);
+ }
+
+ if (show_version)
+ {
+ g_print("%s %s\n", argv [0], VERSION);
+ exit(1);
+ }
+
+ mdm_log_init();
+ mdm_log_set_debug(debug);
+
+ /* Set DISPLAY explicitly for all our children, in case --display
+ * was specified on the command line.
+ */
+ display_str = gdk_get_display();
+ gsm_util_setenv("DISPLAY", display_str);
+ g_free(display_str);
+
+ /* Some third-party programs rely on MATE_DESKTOP_SESSION_ID to
+ * detect if MATE is running. We keep this for compatibility reasons.
+ */
+ gsm_util_setenv("MATE_DESKTOP_SESSION_ID", "this-is-deprecated");
+
+ client_store = gsm_store_new();
+
+
+ /* Start up mateconfd if not already running. */
+ gsm_mateconf_init();
+
+ xsmp_server = gsm_xsmp_server_new(client_store);
+
+ /* Now make sure they succeeded. (They'll call
+ * gsm_util_init_error() if they failed.)
+ */
+ gsm_mateconf_check();
+ acquire_name();
+
+ manager = gsm_manager_new(client_store, failsafe);
+
+ signal_handler = mdm_signal_handler_new();
+ mdm_signal_handler_add_fatal(signal_handler);
+ mdm_signal_handler_add(signal_handler, SIGFPE, signal_cb, NULL);
+ mdm_signal_handler_add(signal_handler, SIGHUP, signal_cb, NULL);
+ mdm_signal_handler_add(signal_handler, SIGUSR1, signal_cb, NULL);
+ mdm_signal_handler_add(signal_handler, SIGTERM, signal_cb, manager);
+ mdm_signal_handler_add(signal_handler, SIGINT, signal_cb, manager);
+ mdm_signal_handler_set_fatal_func(signal_handler, shutdown_cb, manager);
+
+ if (override_autostart_dirs != NULL)
+ {
+ load_override_apps(manager, override_autostart_dirs);
+ }
+ else
+ {
+ if (!IS_STRING_EMPTY(default_session_key))
+ {
+ load_standard_apps(manager, default_session_key);
+ }
+ else
+ {
+ load_standard_apps(manager, GSM_MATECONF_DEFAULT_SESSION_KEY);
+ }
+ }
+
+ gsm_xsmp_server_start(xsmp_server);
+ gsm_manager_start(manager);
+
+ gtk_main();
+
+ if (xsmp_server != NULL)
+ {
+ g_object_unref(xsmp_server);
+ }
+
+ if (manager != NULL)
+ {
+ g_debug("Unreffing manager");
+ g_object_unref(manager);
+ }
+
+ if (client_store != NULL)
+ {
+ g_object_unref(client_store);
+ }
+
+ gsm_mateconf_shutdown();
+
+ mdm_log_shutdown();
+
+ return 0;
+}