diff options
author | Bastien Nocera <hadess@hadess.net> | 2016-06-23 18:45:18 +0200 |
---|---|---|
committer | Bastien Nocera <hadess@hadess.net> | 2019-05-11 22:27:56 +0200 |
commit | 91ca2fdbfcb75ca889e460e5dbc4ef247bf9e7d5 (patch) | |
tree | 146b0b74e4b0cd46a68a8c872295a77e70af2c31 | |
parent | 745b858716b10b407012375c05b6a803f871a380 (diff) | |
download | gnome-settings-daemon-wip/hadess/better-sdl-metadata.tar.gz |
screensaver-proxy: Better metadata for SDL gameswip/hadess/better-sdl-metadata
SDL applications (usually games) don't have any API to provide an
application ID and a reason for inhibition, so if those are Flatpak'ed
get the application ID from the Flatpak, and use the gathered name as
the reason for inhibition.
https://bugzilla.gnome.org/show_bug.cgi?id=767982
-rw-r--r-- | plugins/screensaver-proxy/gsd-screensaver-proxy-manager.c | 176 | ||||
-rw-r--r-- | plugins/screensaver-proxy/meson.build | 2 |
2 files changed, 173 insertions, 5 deletions
diff --git a/plugins/screensaver-proxy/gsd-screensaver-proxy-manager.c b/plugins/screensaver-proxy/gsd-screensaver-proxy-manager.c index e434eb90..e6c22512 100644 --- a/plugins/screensaver-proxy/gsd-screensaver-proxy-manager.c +++ b/plugins/screensaver-proxy/gsd-screensaver-proxy-manager.c @@ -20,17 +20,20 @@ #include "config.h" #include <sys/types.h> +#include <sys/stat.h> #include <sys/wait.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> +#include <fcntl.h> #include <errno.h> #include <locale.h> #include <glib/gi18n.h> #include <gio/gio.h> +#include <gio/gdesktopappinfo.h> #include "gnome-settings-bus.h" #include "gnome-settings-profile.h" @@ -181,6 +184,164 @@ name_vanished_cb (GDBusConnection *connection, g_hash_table_remove (manager->watch_ht, name); } +/* Based on xdp_get_app_id_from_pid() from xdg-desktop-portal + * Returns NULL on failure, keyfile with name "" if not sandboxed, and full app-info otherwise */ +static GKeyFile * +parse_app_info_from_fileinfo (int pid) +{ + g_autofree char *root_path = NULL; + g_autofree char *path = NULL; + g_autofree char *content = NULL; + g_autofree char *app_id = NULL; + int root_fd = -1; + int info_fd = -1; + struct stat stat_buf; + g_autoptr(GError) local_error = NULL; + g_autoptr(GMappedFile) mapped = NULL; + g_autoptr(GKeyFile) metadata = NULL; + + root_path = g_strdup_printf ("/proc/%u/root", pid); + root_fd = openat (AT_FDCWD, root_path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY); + if (root_fd == -1) + { + /* Not able to open the root dir shouldn't happen. Probably the app died and + we're failing due to /proc/$pid not existing. In that case fail instead + of treating this as privileged. */ + return NULL; + } + + metadata = g_key_file_new (); + + info_fd = openat (root_fd, ".flatpak-info", O_RDONLY | O_CLOEXEC | O_NOCTTY); + close (root_fd); + if (info_fd == -1) + { + if (errno == ENOENT) + { + /* No file => on the host */ + g_key_file_set_string (metadata, "Application", "name", ""); + return g_steal_pointer (&metadata); + } + + /* Some weird error => failure */ + return NULL; + } + + if (fstat (info_fd, &stat_buf) != 0 || !S_ISREG (stat_buf.st_mode)) + { + /* Some weird fd => failure */ + close (info_fd); + return NULL; + } + + mapped = g_mapped_file_new_from_fd (info_fd, FALSE, &local_error); + if (mapped == NULL) + { + close (info_fd); + return NULL; + } + + if (!g_key_file_load_from_data (metadata, + g_mapped_file_get_contents (mapped), + g_mapped_file_get_length (mapped), + G_KEY_FILE_NONE, &local_error)) + { + close (info_fd); + return NULL; + } + + return g_steal_pointer (&metadata); +} + +static char * +get_xdg_id (guint32 pid) +{ + g_autoptr(GKeyFile) app_info = NULL; + + app_info = parse_app_info_from_fileinfo (pid); + if (app_info == NULL) + return NULL; + + return g_key_file_get_string (app_info, "Application", "name", NULL); +} + +static char * +get_app_id_from_flatpak (GDBusConnection *connection, + GCancellable *cancellable, + const char *sender) +{ + GVariant *ret; + guint32 pid; + GError *error = NULL; + + ret = g_dbus_connection_call_sync (connection, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "GetConnectionUnixProcessID", + g_variant_new ("(s)", sender), + G_VARIANT_TYPE ("(u)"), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, + cancellable, + NULL); + if (ret == NULL) { + g_debug ("Could not get PID for sender '%s': %s", sender, error->message); + g_error_free (error); + return NULL; + } + + g_assert (g_variant_n_children (ret) > 0); + g_variant_get_child (ret, 0, "u", &pid); + g_variant_unref (ret); + + return get_xdg_id (pid); +} + +static void +get_inhibit_args (GDBusConnection *connection, + GCancellable *cancellable, + GVariant *parameters, + const char *sender, + char **app_id, + char **reason) +{ + const char *p_app_id; + const char *p_reason; + + g_variant_get (parameters, + "(ss)", &p_app_id, &p_reason); + + /* Try to get useful app id and reason for SDL games: + * http://hg.libsdl.org/SDL/file/bc2aba33ae1f/src/core/linux/SDL_dbus.c#l315 */ + + if (g_strcmp0 (p_app_id, "My SDL application") != 0) { + *app_id = g_strdup (p_app_id); + } else { + *app_id = get_app_id_from_flatpak (connection, cancellable, sender); + if (*app_id == NULL) + *app_id = g_strdup (p_app_id); + } + + if (g_strcmp0 (p_reason, "Playing a game") != 0 || + g_strcmp0 (*app_id, "My SDL application") == 0) { + *reason = g_strdup (p_reason); + } else { + GDesktopAppInfo *app_info; + + app_info = g_desktop_app_info_new (*app_id); + if (app_info == NULL) { + *reason = g_strdup (p_reason); + } else { + /* Translators: This is the reason to disable the screensaver, for example: + * Playing “Another World: 20th anniversary Edition” */ + *reason = g_strdup_printf (_("Playing “%s”"), + g_app_info_get_name (G_APP_INFO (app_info))); + g_object_unref (app_info); + } + } +} + static void handle_method_call (GDBusConnection *connection, const gchar *sender, @@ -208,12 +369,16 @@ handle_method_call (GDBusConnection *connection, if (g_strcmp0 (method_name, "Inhibit") == 0) { GVariant *ret; - const char *app_id; - const char *reason; + char *app_id; + char *reason; guint cookie; - g_variant_get (parameters, - "(ss)", &app_id, &reason); + get_inhibit_args (connection, + manager->bus_cancellable, + parameters, + sender, + &app_id, + &reason); ret = g_dbus_proxy_call_sync (G_DBUS_PROXY (G_DBUS_PROXY (manager->session)), "Inhibit", @@ -222,6 +387,9 @@ handle_method_call (GDBusConnection *connection, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + g_free (reason); + g_free (app_id); + if (!ret) goto error; diff --git a/plugins/screensaver-proxy/meson.build b/plugins/screensaver-proxy/meson.build index 5430eb8c..d5aad80d 100644 --- a/plugins/screensaver-proxy/meson.build +++ b/plugins/screensaver-proxy/meson.build @@ -3,7 +3,7 @@ sources = files( 'main.c' ) -deps = plugins_deps + [gio_dep] +deps = plugins_deps + [gio_dep, gio_unix_dep] executable( 'gsd-' + plugin_name, |