mutter/src/backends/meta-dbus-session-manager.c
Bilal Elmoussaoui b852bbba47 cleanup: Stop translating nick/blurb for pspecs
As those strings are intended to be used by some UI but nothing uses
that in reality except GStreamer.
So drop them similar to what GTK did at
https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/4717

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3101>
2023-07-19 11:33:59 +00:00

498 lines
15 KiB
C

/*
* Copyright (C) 2015-2017, 2022 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
* 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 "backends/meta-dbus-session-manager.h"
#include <gobject/gvaluecollector.h>
#include "backends/meta-backend-private.h"
#include "backends/meta-dbus-session-watcher.h"
enum
{
PROP_0,
PROP_BACKEND,
PROP_SERVICE_NAME,
PROP_SERVICE_PATH,
PROP_SESSION_GTYPE,
PROP_INTERFACE_SKELETON,
N_PROPS
};
static GParamSpec *obj_props[N_PROPS];
typedef struct _MetaDbusSessionManagerPrivate
{
GObject parent;
MetaBackend *backend;
char *service_name;
char *service_path;
GType session_gtype;
guint dbus_name_id;
GDBusInterfaceSkeleton *interface_skeleton;
int inhibit_count;
GHashTable *sessions;
} MetaDbusSessionManagerPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (MetaDbusSessionManager,
meta_dbus_session_manager,
G_TYPE_OBJECT)
static void
on_prepare_shutdown (MetaBackend *backend,
MetaDbusSessionManager *session_manager)
{
MetaDbusSessionManagerPrivate *priv =
meta_dbus_session_manager_get_instance_private (session_manager);
GHashTableIter iter;
gpointer value;
g_hash_table_iter_init (&iter, priv->sessions);
while (g_hash_table_iter_next (&iter, NULL, &value))
{
MetaDbusSession *session = META_DBUS_SESSION (value);
g_hash_table_iter_steal (&iter);
meta_dbus_session_close (session);
}
}
static void
meta_dbus_session_manager_finalize (GObject *object)
{
MetaDbusSessionManager *session_manager = META_DBUS_SESSION_MANAGER (object);
MetaDbusSessionManagerPrivate *priv =
meta_dbus_session_manager_get_instance_private (session_manager);
g_clear_handle_id (&priv->dbus_name_id, g_bus_unown_name);
g_assert (g_hash_table_size (priv->sessions) == 0);
g_hash_table_destroy (priv->sessions);
g_clear_pointer (&priv->service_name, g_free);
g_clear_pointer (&priv->service_path, g_free);
g_clear_object (&priv->interface_skeleton);
G_OBJECT_CLASS (meta_dbus_session_manager_parent_class)->finalize (object);
}
static void
on_bus_acquired (GDBusConnection *connection,
const char *name,
gpointer user_data)
{
MetaDbusSessionManager *session_manager =
META_DBUS_SESSION_MANAGER (user_data);
MetaDbusSessionManagerPrivate *priv =
meta_dbus_session_manager_get_instance_private (session_manager);
g_autoptr (GError) error = NULL;
meta_topic (META_DEBUG_BACKEND,
"Acquired D-Bus name '%s', exporting service on '%s'",
priv->service_name, priv->service_path);
if (!g_dbus_interface_skeleton_export (priv->interface_skeleton,
connection,
priv->service_path,
&error))
{
g_warning ("Failed to export '%s' object on '%s': %s",
priv->service_name,
priv->service_path,
error->message);
}
}
static void
meta_dbus_session_manager_constructed (GObject *object)
{
MetaDbusSessionManager *session_manager = META_DBUS_SESSION_MANAGER (object);
MetaDbusSessionManagerPrivate *priv =
meta_dbus_session_manager_get_instance_private (session_manager);
priv->dbus_name_id =
g_bus_own_name (G_BUS_TYPE_SESSION,
priv->service_name,
G_BUS_NAME_OWNER_FLAGS_NONE,
on_bus_acquired,
NULL,
NULL,
session_manager,
NULL);
g_signal_connect (priv->backend, "prepare-shutdown",
G_CALLBACK (on_prepare_shutdown),
session_manager);
G_OBJECT_CLASS (meta_dbus_session_manager_parent_class)->constructed (object);
}
static void
meta_dbus_session_manager_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaDbusSessionManager *session_manager = META_DBUS_SESSION_MANAGER (object);
MetaDbusSessionManagerPrivate *priv =
meta_dbus_session_manager_get_instance_private (session_manager);
switch (prop_id)
{
case PROP_BACKEND:
priv->backend = g_value_get_object (value);
break;
case PROP_SERVICE_NAME:
priv->service_name = g_value_dup_string (value);
break;
case PROP_SERVICE_PATH:
priv->service_path = g_value_dup_string (value);
break;
case PROP_SESSION_GTYPE:
priv->session_gtype = g_value_get_gtype (value);
break;
case PROP_INTERFACE_SKELETON:
priv->interface_skeleton = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_dbus_session_manager_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaDbusSessionManager *session_manager = META_DBUS_SESSION_MANAGER (object);
MetaDbusSessionManagerPrivate *priv =
meta_dbus_session_manager_get_instance_private (session_manager);
switch (prop_id)
{
case PROP_BACKEND:
g_value_set_object (value, priv->backend);
break;
case PROP_SERVICE_NAME:
g_value_set_string (value, priv->service_name);
break;
case PROP_SERVICE_PATH:
g_value_set_string (value, priv->service_path);
break;
case PROP_SESSION_GTYPE:
g_value_set_gtype (value, priv->session_gtype);
break;
case PROP_INTERFACE_SKELETON:
g_value_set_object (value, priv->interface_skeleton);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_dbus_session_manager_class_init (MetaDbusSessionManagerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_dbus_session_manager_finalize;
object_class->constructed = meta_dbus_session_manager_constructed;
object_class->set_property = meta_dbus_session_manager_set_property;
object_class->get_property = meta_dbus_session_manager_get_property;
obj_props[PROP_BACKEND] =
g_param_spec_object ("backend", NULL, NULL,
META_TYPE_BACKEND,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_props[PROP_SERVICE_NAME] =
g_param_spec_string ("service-name", NULL, NULL,
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_props[PROP_SERVICE_PATH] =
g_param_spec_string ("service-path", NULL, NULL,
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_props[PROP_SESSION_GTYPE] =
g_param_spec_gtype ("session-gtype", NULL, NULL,
G_TYPE_NONE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_props[PROP_INTERFACE_SKELETON] =
g_param_spec_object ("interface-skeleton", NULL, NULL,
G_TYPE_DBUS_INTERFACE_SKELETON,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, obj_props);
}
static void
meta_dbus_session_manager_init (MetaDbusSessionManager *session_manager)
{
MetaDbusSessionManagerPrivate *priv =
meta_dbus_session_manager_get_instance_private (session_manager);
priv->sessions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
}
static void
on_session_closed (MetaDbusSession *session,
MetaDbusSessionManager *session_manager)
{
MetaDbusSessionManagerPrivate *priv =
meta_dbus_session_manager_get_instance_private (session_manager);
g_autofree char *session_id = NULL;
session_id = meta_dbus_session_get_id (session);
g_hash_table_remove (priv->sessions, session_id);
}
static char *
generate_session_id (MetaDbusSessionManager *session_manager)
{
MetaDbusSessionManagerPrivate *priv =
meta_dbus_session_manager_get_instance_private (session_manager);
g_autoptr (GRand) rand = NULL;
char *session_id;
rand = g_rand_new ();
while (TRUE)
{
session_id = meta_generate_random_id (rand, 32);
if (g_hash_table_lookup (priv->sessions, session_id))
g_free (session_id);
else
return session_id;
}
}
static void
append_property (GObjectClass *object_class,
GArray *names,
GArray *values,
const char *name,
...)
{
va_list var_args;
GValue value = G_VALUE_INIT;
GParamSpec *pspec;
GType ptype;
char *error = NULL;
va_start (var_args, name);
pspec = g_object_class_find_property (object_class, name);
g_assert (pspec);
ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
G_VALUE_COLLECT_INIT (&value, ptype, var_args, 0, &error);
g_assert (!error);
g_array_append_val (names, name);
g_array_append_val (values, value);
va_end (var_args);
}
MetaDbusSession *
meta_dbus_session_manager_create_session (MetaDbusSessionManager *session_manager,
GDBusMethodInvocation *invocation,
GError **error,
...)
{
MetaDbusSessionManagerPrivate *priv =
meta_dbus_session_manager_get_instance_private (session_manager);
MetaDbusSessionWatcher *session_watcher =
meta_backend_get_dbus_session_watcher (priv->backend);
GObject *session;
va_list var_args;
GObjectClass *object_class;
g_autoptr (GArray) names = NULL;
g_autoptr (GArray) values = NULL;
const char *property_name;
const char *peer_name;
g_autofree char *session_id = NULL;
const char *client_dbus_name;
if (priv->inhibit_count > 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Session creation inhibited");
return NULL;
}
peer_name = g_dbus_method_invocation_get_sender (invocation);
object_class = g_type_class_ref (priv->session_gtype);
va_start (var_args, error);
names = g_array_new (FALSE, FALSE, sizeof (const char *));
values = g_array_new (FALSE, FALSE, sizeof (GValue));
g_array_set_clear_func (values, (GDestroyNotify) g_value_unset);
property_name = va_arg (var_args, const char *);
while (property_name)
{
GValue value = G_VALUE_INIT;
GParamSpec *pspec;
GType ptype;
gchar *error = NULL;
pspec = g_object_class_find_property (object_class,
property_name);
g_assert (pspec);
ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
G_VALUE_COLLECT_INIT (&value, ptype, var_args, 0, &error);
g_assert (!error);
g_array_append_val (names, property_name);
g_array_append_val (values, value);
property_name = va_arg (var_args, const char *);
}
va_end (var_args);
append_property (object_class, names, values, "session-manager",
session_manager);
append_property (object_class, names, values, "peer-name", peer_name);
session_id = generate_session_id (session_manager);
append_property (object_class, names, values, "id", session_id);
g_type_class_unref (object_class);
session = g_object_new_with_properties (priv->session_gtype,
values->len,
(const char **) names->data,
(const GValue *) values->data);
if (!g_initable_init (G_INITABLE (session), NULL, error))
{
g_object_unref (session);
return NULL;
}
g_hash_table_insert (priv->sessions,
g_strdup (session_id),
session);
client_dbus_name = g_dbus_method_invocation_get_sender (invocation);
meta_dbus_session_watcher_watch_session (session_watcher,
client_dbus_name,
META_DBUS_SESSION (session));
g_signal_connect (session, "session-closed",
G_CALLBACK (on_session_closed),
session_manager);
return META_DBUS_SESSION (session);
}
MetaDbusSession *
meta_dbus_session_manager_get_session (MetaDbusSessionManager *session_manager,
const char *session_id)
{
MetaDbusSessionManagerPrivate *priv =
meta_dbus_session_manager_get_instance_private (session_manager);
return g_hash_table_lookup (priv->sessions, session_id);
}
void
meta_dbus_session_manager_inhibit (MetaDbusSessionManager *session_manager)
{
MetaDbusSessionManagerPrivate *priv =
meta_dbus_session_manager_get_instance_private (session_manager);
priv->inhibit_count++;
if (priv->inhibit_count == 1)
{
GHashTableIter iter;
gpointer key, value;
g_hash_table_iter_init (&iter, priv->sessions);
while (g_hash_table_iter_next (&iter, &key, &value))
{
MetaDbusSession *session = META_DBUS_SESSION (value);
g_hash_table_iter_steal (&iter);
meta_dbus_session_close (session);
}
}
}
void
meta_dbus_session_manager_uninhibit (MetaDbusSessionManager *session_manager)
{
MetaDbusSessionManagerPrivate *priv =
meta_dbus_session_manager_get_instance_private (session_manager);
g_return_if_fail (priv->inhibit_count > 0);
priv->inhibit_count--;
}
MetaBackend *
meta_dbus_session_manager_get_backend (MetaDbusSessionManager *session_manager)
{
MetaDbusSessionManagerPrivate *priv =
meta_dbus_session_manager_get_instance_private (session_manager);
return priv->backend;
}
GDBusConnection *
meta_dbus_session_manager_get_connection (MetaDbusSessionManager *session_manager)
{
MetaDbusSessionManagerPrivate *priv =
meta_dbus_session_manager_get_instance_private (session_manager);
return g_dbus_interface_skeleton_get_connection (priv->interface_skeleton);
}
GDBusInterfaceSkeleton *
meta_dbus_session_manager_get_interface_skeleton (MetaDbusSessionManager *session_manager)
{
MetaDbusSessionManagerPrivate *priv =
meta_dbus_session_manager_get_instance_private (session_manager);
return priv->interface_skeleton;
}