diff options
Diffstat (limited to 'plugins/common/daemon-skeleton-gtk.h')
-rw-r--r-- | plugins/common/daemon-skeleton-gtk.h | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/plugins/common/daemon-skeleton-gtk.h b/plugins/common/daemon-skeleton-gtk.h new file mode 100644 index 0000000..596281d --- /dev/null +++ b/plugins/common/daemon-skeleton-gtk.h @@ -0,0 +1,292 @@ +/** + * Create a gnome-settings-daemon helper easily + * + * #define NEW gsd_media_keys_manager_new + * #define START gsd_media_keys_manager_start + * #define MANAGER GsdMediaKeysManager + * #include "gsd-media-keys-manager.h" + * + * #include "daemon-skeleton-gtk.h" + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <locale.h> + +#include <glib-unix.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> + +#include "gnome-settings-bus.h" + +#ifndef PLUGIN_NAME +#error Include PLUGIN_CFLAGS in the daemon s CFLAGS +#endif /* !PLUGIN_NAME */ + +#define GNOME_SESSION_DBUS_NAME "org.gnome.SessionManager" +#define GNOME_SESSION_CLIENT_PRIVATE_DBUS_INTERFACE "org.gnome.SessionManager.ClientPrivate" + +static MANAGER *manager = NULL; +static int timeout = -1; +static char *dummy_name = NULL; +static gboolean verbose = FALSE; + +static GOptionEntry entries[] = { + { "exit-time", 0, 0, G_OPTION_ARG_INT, &timeout, "Exit after n seconds time", NULL }, + { "dummy-name", 0, 0, G_OPTION_ARG_STRING, &dummy_name, "Name when using the dummy daemon", NULL }, + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose", NULL }, + {NULL} +}; + +static void +respond_to_end_session (GDBusProxy *proxy) +{ + /* we must answer with "EndSessionResponse" */ + g_dbus_proxy_call (proxy, "EndSessionResponse", + g_variant_new ("(bs)", TRUE, ""), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, NULL, NULL); +} + +static void +do_stop (void) +{ + gtk_main_quit (); +} + +static void +client_proxy_signal_cb (GDBusProxy *proxy, + gchar *sender_name, + gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + if (g_strcmp0 (signal_name, "QueryEndSession") == 0) { + g_debug ("Got QueryEndSession signal"); + respond_to_end_session (proxy); + } else if (g_strcmp0 (signal_name, "EndSession") == 0) { + g_debug ("Got EndSession signal"); + respond_to_end_session (proxy); + } else if (g_strcmp0 (signal_name, "Stop") == 0) { + g_debug ("Got Stop signal"); + do_stop (); + } +} + +static void +on_client_registered (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GVariant *variant; + GDBusProxy *client_proxy; + GError *error = NULL; + gchar *object_path = NULL; + + variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if (!variant) { + g_warning ("Unable to register client: %s", error->message); + g_error_free (error); + return; + } + + g_variant_get (variant, "(o)", &object_path); + + g_debug ("Registered client at path %s", object_path); + + client_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, 0, NULL, + GNOME_SESSION_DBUS_NAME, + object_path, + GNOME_SESSION_CLIENT_PRIVATE_DBUS_INTERFACE, + NULL, + &error); + if (!client_proxy) { + g_warning ("Unable to get the session client proxy: %s", error->message); + g_error_free (error); + return; + } + + g_signal_connect (client_proxy, "g-signal", + G_CALLBACK (client_proxy_signal_cb), NULL); + + g_free (object_path); + g_variant_unref (variant); +} + +static void +register_with_gnome_session (void) +{ + GDBusProxy *proxy; + const char *startup_id; + + proxy = G_DBUS_PROXY (gnome_settings_bus_get_session_proxy ()); + startup_id = g_getenv ("DESKTOP_AUTOSTART_ID"); + g_dbus_proxy_call (proxy, + "RegisterClient", + g_variant_new ("(ss)", dummy_name ? dummy_name : PLUGIN_NAME, startup_id ? startup_id : ""), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback) on_client_registered, + NULL); + + /* DESKTOP_AUTOSTART_ID must not leak into child processes, because + * it can't be reused. Child processes will not know whether this is + * a genuine value or erroneous already-used value. */ + g_unsetenv ("DESKTOP_AUTOSTART_ID"); +} + +static void +set_empty_gtk_theme (gboolean set) +{ + static char *old_gtk_theme = NULL; + + if (set) { + /* Override GTK_THEME to reduce overhead of CSS engine. By using + * GTK_THEME environment variable, GtkSettings is not allowed to + * initially parse the Adwaita theme. + * + * https://bugzilla.gnome.org/show_bug.cgi?id=780555 */ + old_gtk_theme = g_strdup (g_getenv ("GTK_THEME")); + g_setenv ("GTK_THEME", "Disabled", TRUE); + } else { + /* GtkSettings has loaded, so we can drop GTK_THEME used to initialize + * our internal theme. Only the main thread accesses the GTK_THEME + * environment variable, so this is safe to release. */ + if (old_gtk_theme != NULL) + g_setenv ("GTK_THEME", old_gtk_theme, TRUE); + else + g_unsetenv ("GTK_THEME"); + } +} + +static gboolean +handle_sigterm (gpointer user_data) +{ + g_debug ("Got SIGTERM; shutting down ..."); + + if (gtk_main_level () > 0) + gtk_main_quit (); + + return G_SOURCE_REMOVE; +} + +static void +install_signal_handler (void) +{ + g_autoptr(GSource) source = NULL; + + source = g_unix_signal_source_new (SIGTERM); + + g_source_set_callback (source, handle_sigterm, NULL, NULL); + g_source_attach (source, NULL); +} + +static void +bus_acquired_cb (GDBusConnection *connection, + const gchar *name, + gpointer user_data G_GNUC_UNUSED) +{ + g_debug ("%s: acquired bus %p for name %s", G_STRFUNC, connection, name); +} + +static void +name_acquired_cb (GDBusConnection *connection, + const gchar *name, + gpointer user_data G_GNUC_UNUSED) +{ + g_debug ("%s: acquired name %s on bus %p", G_STRFUNC, name, connection); +} + +static void +name_lost_cb (GDBusConnection *connection, + const gchar *name, + gpointer user_data G_GNUC_UNUSED) +{ + g_debug ("%s: lost name %s on bus %p", G_STRFUNC, name, connection); +} + +int +main (int argc, char **argv) +{ + GError *error = NULL; + guint name_own_id; + + bindtextdomain (GETTEXT_PACKAGE, GNOME_SETTINGS_LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + setlocale (LC_ALL, ""); + + set_empty_gtk_theme (TRUE); + +#ifdef GDK_BACKEND + { + const gchar *setup_display = getenv ("GNOME_SETUP_DISPLAY"); + if (setup_display && *setup_display != '\0') + g_setenv ("DISPLAY", setup_display, TRUE); + } + + gdk_set_allowed_backends (GDK_BACKEND); +#endif + + error = NULL; + if (! gtk_init_with_args (&argc, &argv, PLUGIN_NAME, entries, NULL, &error)) { + if (error != NULL) { + fprintf (stderr, "%s\n", error->message); + g_error_free (error); + } + exit (1); + } + + set_empty_gtk_theme (FALSE); + + if (verbose) { + g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); + /* Work around GLib not flushing the output for us by explicitly + * setting buffering to a sane behaviour. This is important + * during testing when the output is not going to a TTY and + * we are reading messages from g_debug on stdout. + * + * See also + * https://bugzilla.gnome.org/show_bug.cgi?id=792432 + */ + setlinebuf (stdout); + } + + if (timeout > 0) { + guint id; + id = g_timeout_add_seconds (timeout, (GSourceFunc) gtk_main_quit, NULL); + g_source_set_name_by_id (id, "[gnome-settings-daemon] gtk_main_quit"); + } + + install_signal_handler (); + + manager = NEW (); + register_with_gnome_session (); + + if (!START (manager, &error)) { + fprintf (stderr, "Failed to start: %s\n", error->message); + g_error_free (error); + exit (1); + } + + name_own_id = g_bus_own_name (G_BUS_TYPE_SESSION, + PLUGIN_DBUS_NAME, + G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE, + bus_acquired_cb, + name_acquired_cb, + name_lost_cb, + NULL, /* user_data */ + NULL /* user_data_free_func */); + + gtk_main (); + + STOP (manager); + + g_object_unref (manager); + g_bus_unown_name (name_own_id); + + return 0; +} |