Port screen cast and remote desktop to MetaDbusSessionManager
This eliminates some code duplication related to managing D-Bus session objects. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2713>
This commit is contained in:
parent
122fea2dc4
commit
5731268087
@ -206,9 +206,9 @@ meta_backend_dispose (GObject *object)
|
||||
#ifdef HAVE_REMOTE_DESKTOP
|
||||
g_clear_object (&priv->remote_desktop);
|
||||
g_clear_object (&priv->screen_cast);
|
||||
#endif
|
||||
g_clear_object (&priv->dbus_session_watcher);
|
||||
g_clear_object (&priv->remote_access_controller);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBWACOM
|
||||
g_clear_pointer (&priv->wacom_db, libwacom_database_destroy);
|
||||
@ -557,14 +557,20 @@ meta_backend_real_post_init (MetaBackend *backend)
|
||||
input_settings);
|
||||
}
|
||||
|
||||
#ifdef HAVE_REMOTE_DESKTOP
|
||||
priv->dbus_session_watcher = g_object_new (META_TYPE_DBUS_SESSION_WATCHER, NULL);
|
||||
priv->screen_cast = meta_screen_cast_new (backend,
|
||||
priv->dbus_session_watcher);
|
||||
priv->remote_desktop = meta_remote_desktop_new (backend,
|
||||
priv->dbus_session_watcher);
|
||||
priv->remote_access_controller =
|
||||
meta_remote_access_controller_new (priv->remote_desktop, priv->screen_cast);
|
||||
meta_remote_access_controller_new ();
|
||||
priv->dbus_session_watcher =
|
||||
g_object_new (META_TYPE_DBUS_SESSION_WATCHER, NULL);
|
||||
|
||||
#ifdef HAVE_REMOTE_DESKTOP
|
||||
priv->screen_cast = meta_screen_cast_new (backend);
|
||||
meta_remote_access_controller_add (
|
||||
priv->remote_access_controller,
|
||||
META_DBUS_SESSION_MANAGER (priv->screen_cast));
|
||||
priv->remote_desktop = meta_remote_desktop_new (backend);
|
||||
meta_remote_access_controller_add (
|
||||
priv->remote_access_controller,
|
||||
META_DBUS_SESSION_MANAGER (priv->remote_desktop));
|
||||
#endif /* HAVE_REMOTE_DESKTOP */
|
||||
|
||||
if (!meta_monitor_manager_is_headless (priv->monitor_manager))
|
||||
|
@ -24,8 +24,10 @@
|
||||
#include "backends/meta-backend-types.h"
|
||||
#include "meta/meta-remote-access-controller.h"
|
||||
|
||||
MetaRemoteAccessController * meta_remote_access_controller_new (MetaRemoteDesktop *remote_desktop,
|
||||
MetaScreenCast *screen_cast);
|
||||
MetaRemoteAccessController * meta_remote_access_controller_new (void);
|
||||
|
||||
void meta_remote_access_controller_add (MetaRemoteAccessController *controller,
|
||||
MetaDbusSessionManager *session_manager);
|
||||
|
||||
void meta_remote_access_controller_notify_new_handle (MetaRemoteAccessController *controller,
|
||||
MetaRemoteAccessHandle *handle);
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
#include "backends/meta-remote-access-controller-private.h"
|
||||
|
||||
#include "backends/meta-dbus-session-manager.h"
|
||||
|
||||
#ifdef HAVE_REMOTE_DESKTOP
|
||||
#include "backends/meta-remote-desktop.h"
|
||||
#include "backends/meta-screen-cast.h"
|
||||
@ -73,8 +75,7 @@ struct _MetaRemoteAccessController
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
MetaRemoteDesktop *remote_desktop;
|
||||
MetaScreenCast *screen_cast;
|
||||
GList *session_managers;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaRemoteAccessController,
|
||||
@ -153,10 +154,14 @@ meta_remote_access_controller_notify_new_handle (MetaRemoteAccessController *con
|
||||
void
|
||||
meta_remote_access_controller_inhibit_remote_access (MetaRemoteAccessController *controller)
|
||||
{
|
||||
#ifdef HAVE_REMOTE_DESKTOP
|
||||
meta_remote_desktop_inhibit (controller->remote_desktop);
|
||||
meta_screen_cast_inhibit (controller->screen_cast);
|
||||
#endif
|
||||
GList *l;
|
||||
|
||||
for (l = controller->session_managers; l; l = l->next)
|
||||
{
|
||||
MetaDbusSessionManager *session_manager = l->data;
|
||||
|
||||
meta_dbus_session_manager_inhibit (session_manager);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -170,24 +175,28 @@ meta_remote_access_controller_inhibit_remote_access (MetaRemoteAccessController
|
||||
void
|
||||
meta_remote_access_controller_uninhibit_remote_access (MetaRemoteAccessController *controller)
|
||||
{
|
||||
#ifdef HAVE_REMOTE_DESKTOP
|
||||
meta_screen_cast_uninhibit (controller->screen_cast);
|
||||
meta_remote_desktop_uninhibit (controller->remote_desktop);
|
||||
#endif
|
||||
GList *l;
|
||||
|
||||
for (l = controller->session_managers; l; l = l->next)
|
||||
{
|
||||
MetaDbusSessionManager *session_manager = l->data;
|
||||
|
||||
meta_dbus_session_manager_uninhibit (session_manager);
|
||||
}
|
||||
}
|
||||
|
||||
MetaRemoteAccessController *
|
||||
meta_remote_access_controller_new (MetaRemoteDesktop *remote_desktop,
|
||||
MetaScreenCast *screen_cast)
|
||||
meta_remote_access_controller_new (void)
|
||||
{
|
||||
MetaRemoteAccessController *remote_access_controller;
|
||||
return g_object_new (META_TYPE_REMOTE_ACCESS_CONTROLLER, NULL);
|
||||
}
|
||||
|
||||
remote_access_controller = g_object_new (META_TYPE_REMOTE_ACCESS_CONTROLLER,
|
||||
NULL);
|
||||
remote_access_controller->remote_desktop = remote_desktop;
|
||||
remote_access_controller->screen_cast = screen_cast;
|
||||
|
||||
return remote_access_controller;
|
||||
void
|
||||
meta_remote_access_controller_add (MetaRemoteAccessController *controller,
|
||||
MetaDbusSessionManager *session_manager)
|
||||
{
|
||||
controller->session_managers = g_list_append (controller->session_managers,
|
||||
session_manager);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include "backends/meta-dbus-session-watcher.h"
|
||||
#include "backends/meta-dbus-session-manager.h"
|
||||
#include "backends/meta-screen-cast-session.h"
|
||||
#include "backends/meta-remote-access-controller-private.h"
|
||||
#include "backends/x11/meta-backend-x11.h"
|
||||
@ -49,6 +50,19 @@
|
||||
|
||||
#define TRANSFER_REQUEST_CLEANUP_TIMEOUT_MS (s2ms (15))
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_SESSION_MANAGER,
|
||||
PROP_PEER_NAME,
|
||||
PROP_ID,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *obj_props[N_PROPS];
|
||||
|
||||
typedef enum _MetaRemoteDesktopNotifyAxisFlags
|
||||
{
|
||||
META_REMOTE_DESKTOP_NOTIFY_AXIS_FLAGS_NONE = 0,
|
||||
@ -69,7 +83,7 @@ struct _MetaRemoteDesktopSession
|
||||
{
|
||||
MetaDBusRemoteDesktopSessionSkeleton parent;
|
||||
|
||||
MetaRemoteDesktop *remote_desktop;
|
||||
MetaDbusSessionManager *session_manager;
|
||||
|
||||
GDBusConnection *connection;
|
||||
char *peer_name;
|
||||
@ -96,6 +110,8 @@ struct _MetaRemoteDesktopSession
|
||||
guint transfer_request_timeout_id;
|
||||
};
|
||||
|
||||
static void initable_init_iface (GInitableIface *iface);
|
||||
|
||||
static void
|
||||
meta_remote_desktop_session_init_iface (MetaDBusRemoteDesktopSessionIface *iface);
|
||||
|
||||
@ -105,6 +121,8 @@ meta_dbus_session_init_iface (MetaDbusSessionInterface *iface);
|
||||
G_DEFINE_TYPE_WITH_CODE (MetaRemoteDesktopSession,
|
||||
meta_remote_desktop_session,
|
||||
META_DBUS_TYPE_REMOTE_DESKTOP_SESSION_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
|
||||
initable_init_iface)
|
||||
G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_REMOTE_DESKTOP_SESSION,
|
||||
meta_remote_desktop_session_init_iface)
|
||||
G_IMPLEMENT_INTERFACE (META_TYPE_DBUS_SESSION,
|
||||
@ -127,8 +145,8 @@ meta_remote_desktop_session_handle_new (MetaRemoteDesktopSession *session);
|
||||
static MetaDisplay *
|
||||
display_from_session (MetaRemoteDesktopSession *session)
|
||||
{
|
||||
MetaRemoteDesktop *remote_desktop = session->remote_desktop;
|
||||
MetaBackend *backend = meta_remote_desktop_get_backend (remote_desktop);
|
||||
MetaBackend *backend =
|
||||
meta_dbus_session_manager_get_backend (session->session_manager);
|
||||
MetaContext *context = meta_backend_get_context (backend);
|
||||
|
||||
return meta_context_get_display (context);
|
||||
@ -143,8 +161,8 @@ meta_remote_desktop_session_is_running (MetaRemoteDesktopSession *session)
|
||||
static void
|
||||
init_remote_access_handle (MetaRemoteDesktopSession *session)
|
||||
{
|
||||
MetaRemoteDesktop *remote_desktop = session->remote_desktop;
|
||||
MetaBackend *backend = meta_remote_desktop_get_backend (remote_desktop);
|
||||
MetaBackend *backend =
|
||||
meta_dbus_session_manager_get_backend (session->session_manager);
|
||||
MetaRemoteAccessController *remote_access_controller;
|
||||
MetaRemoteAccessHandle *remote_access_handle;
|
||||
|
||||
@ -160,8 +178,8 @@ static void
|
||||
ensure_virtual_device (MetaRemoteDesktopSession *session,
|
||||
ClutterInputDeviceType device_type)
|
||||
{
|
||||
MetaRemoteDesktop *remote_desktop = session->remote_desktop;
|
||||
MetaBackend *backend = meta_remote_desktop_get_backend (remote_desktop);
|
||||
MetaBackend *backend =
|
||||
meta_dbus_session_manager_get_backend (session->session_manager);
|
||||
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
|
||||
ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend);
|
||||
ClutterVirtualInputDevice **virtual_device_ptr = NULL;
|
||||
@ -247,18 +265,20 @@ meta_remote_desktop_session_close (MetaDbusSession *dbus_session)
|
||||
g_object_unref (session);
|
||||
}
|
||||
|
||||
static const char *
|
||||
meta_remote_desktop_session_get_id (MetaDbusSession *dbus_session)
|
||||
{
|
||||
MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (dbus_session);
|
||||
|
||||
return session->session_id;
|
||||
}
|
||||
|
||||
char *
|
||||
meta_remote_desktop_session_get_object_path (MetaRemoteDesktopSession *session)
|
||||
{
|
||||
return session->object_path;
|
||||
}
|
||||
|
||||
char *
|
||||
meta_remote_desktop_session_get_session_id (MetaRemoteDesktopSession *session)
|
||||
{
|
||||
return session->session_id;
|
||||
}
|
||||
|
||||
static void
|
||||
on_screen_cast_session_closed (MetaScreenCastSession *screen_cast_session,
|
||||
MetaRemoteDesktopSession *session)
|
||||
@ -289,44 +309,6 @@ meta_remote_desktop_session_register_screen_cast (MetaRemoteDesktopSession *ses
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
MetaRemoteDesktopSession *
|
||||
meta_remote_desktop_session_new (MetaRemoteDesktop *remote_desktop,
|
||||
const char *peer_name,
|
||||
GError **error)
|
||||
{
|
||||
MetaBackend *backend = meta_remote_desktop_get_backend (remote_desktop);
|
||||
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
|
||||
ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend);
|
||||
ClutterKeymap *keymap = clutter_seat_get_keymap (seat);
|
||||
GDBusInterfaceSkeleton *interface_skeleton;
|
||||
MetaRemoteDesktopSession *session;
|
||||
|
||||
session = g_object_new (META_TYPE_REMOTE_DESKTOP_SESSION, NULL);
|
||||
|
||||
session->remote_desktop = remote_desktop;
|
||||
session->peer_name = g_strdup (peer_name);
|
||||
|
||||
interface_skeleton = G_DBUS_INTERFACE_SKELETON (session);
|
||||
session->connection = meta_remote_desktop_get_connection (remote_desktop);
|
||||
if (!g_dbus_interface_skeleton_export (interface_skeleton,
|
||||
session->connection,
|
||||
session->object_path,
|
||||
error))
|
||||
{
|
||||
g_object_unref (session);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_object_bind_property (keymap, "caps-lock-state",
|
||||
session, "caps-lock-state",
|
||||
G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (keymap, "num-lock-state",
|
||||
session, "num-lock-state",
|
||||
G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_permission (MetaRemoteDesktopSession *session,
|
||||
GDBusMethodInvocation *invocation)
|
||||
@ -1657,6 +1639,46 @@ handle_selection_read (MetaDBusRemoteDesktopSession *skeleton,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_remote_desktop_session_initable_init (GInitable *initable,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (initable);
|
||||
MetaBackend *backend =
|
||||
meta_dbus_session_manager_get_backend (session->session_manager);
|
||||
ClutterSeat *seat = meta_backend_get_default_seat (backend);
|
||||
ClutterKeymap *keymap = clutter_seat_get_keymap (seat);
|
||||
GDBusInterfaceSkeleton *interface_skeleton = G_DBUS_INTERFACE_SKELETON (session);
|
||||
MetaDBusRemoteDesktopSession *skeleton =
|
||||
META_DBUS_REMOTE_DESKTOP_SESSION (interface_skeleton);
|
||||
|
||||
meta_dbus_remote_desktop_session_set_session_id (skeleton, session->session_id);
|
||||
|
||||
session->connection =
|
||||
meta_dbus_session_manager_get_connection (session->session_manager);
|
||||
if (!g_dbus_interface_skeleton_export (interface_skeleton,
|
||||
session->connection,
|
||||
session->object_path,
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
g_object_bind_property (keymap, "caps-lock-state",
|
||||
session, "caps-lock-state",
|
||||
G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
|
||||
g_object_bind_property (keymap, "num-lock-state",
|
||||
session, "num-lock-state",
|
||||
G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
initable_init_iface (GInitableIface *iface)
|
||||
{
|
||||
iface->init = meta_remote_desktop_session_initable_init;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_remote_desktop_session_init_iface (MetaDBusRemoteDesktopSessionIface *iface)
|
||||
{
|
||||
@ -1684,6 +1706,7 @@ static void
|
||||
meta_dbus_session_init_iface (MetaDbusSessionInterface *iface)
|
||||
{
|
||||
iface->close = meta_remote_desktop_session_close;
|
||||
iface->get_id = meta_remote_desktop_session_get_id;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1708,20 +1731,61 @@ meta_remote_desktop_session_finalize (GObject *object)
|
||||
G_OBJECT_CLASS (meta_remote_desktop_session_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_remote_desktop_session_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SESSION_MANAGER:
|
||||
session->session_manager = g_value_get_object (value);
|
||||
break;
|
||||
case PROP_PEER_NAME:
|
||||
session->peer_name = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_ID:
|
||||
session->session_id = g_value_dup_string (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_remote_desktop_session_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SESSION_MANAGER:
|
||||
g_value_set_object (value, session->session_manager);
|
||||
break;
|
||||
case PROP_PEER_NAME:
|
||||
g_value_set_string (value, session->peer_name);
|
||||
break;
|
||||
case PROP_ID:
|
||||
g_value_set_string (value, session->session_id);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_remote_desktop_session_init (MetaRemoteDesktopSession *session)
|
||||
{
|
||||
MetaDBusRemoteDesktopSession *skeleton =
|
||||
META_DBUS_REMOTE_DESKTOP_SESSION (session);
|
||||
GRand *rand;
|
||||
static unsigned int global_session_number = 0;
|
||||
|
||||
rand = g_rand_new ();
|
||||
session->session_id = meta_generate_random_id (rand, 32);
|
||||
g_rand_free (rand);
|
||||
|
||||
meta_dbus_remote_desktop_session_set_session_id (skeleton, session->session_id);
|
||||
|
||||
session->object_path =
|
||||
g_strdup_printf (META_REMOTE_DESKTOP_SESSION_DBUS_PATH "/u%u",
|
||||
++global_session_number);
|
||||
@ -1736,6 +1800,34 @@ meta_remote_desktop_session_class_init (MetaRemoteDesktopSessionClass *klass)
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_remote_desktop_session_finalize;
|
||||
object_class->set_property = meta_remote_desktop_session_set_property;
|
||||
object_class->get_property = meta_remote_desktop_session_get_property;
|
||||
|
||||
obj_props[PROP_SESSION_MANAGER] =
|
||||
g_param_spec_object ("session-manager",
|
||||
"session manager",
|
||||
"D-Bus session manager",
|
||||
META_TYPE_DBUS_SESSION_MANAGER,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
obj_props[PROP_PEER_NAME] =
|
||||
g_param_spec_string ("peer-name",
|
||||
"peer name",
|
||||
"D-Bus peer name",
|
||||
NULL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
obj_props[PROP_ID] =
|
||||
g_param_spec_string ("id",
|
||||
"session id",
|
||||
"Unique ID of the session",
|
||||
NULL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
g_object_class_install_properties (object_class, N_PROPS, obj_props);
|
||||
}
|
||||
|
||||
static MetaRemoteDesktopSessionHandle *
|
||||
|
@ -41,8 +41,6 @@ G_DECLARE_FINAL_TYPE (MetaRemoteDesktopSessionHandle,
|
||||
|
||||
char * meta_remote_desktop_session_get_object_path (MetaRemoteDesktopSession *session);
|
||||
|
||||
char * meta_remote_desktop_session_get_session_id (MetaRemoteDesktopSession *session);
|
||||
|
||||
gboolean meta_remote_desktop_session_register_screen_cast (MetaRemoteDesktopSession *session,
|
||||
MetaScreenCastSession *screen_cast_session,
|
||||
GError **error);
|
||||
@ -51,8 +49,4 @@ void meta_remote_desktop_session_request_transfer (MetaRemoteDesktopSession *se
|
||||
const char *mime_type,
|
||||
GTask *task);
|
||||
|
||||
MetaRemoteDesktopSession * meta_remote_desktop_session_new (MetaRemoteDesktop *remote_desktop,
|
||||
const char *peer_name,
|
||||
GError **error);
|
||||
|
||||
#endif /* META_REMOTE_DESKTOP_SESSION_H */
|
||||
|
@ -52,256 +52,49 @@ typedef enum _MetaRemoteDesktopDeviceTypes
|
||||
|
||||
struct _MetaRemoteDesktop
|
||||
{
|
||||
MetaDBusRemoteDesktopSkeleton parent;
|
||||
|
||||
MetaBackend *backend;
|
||||
int dbus_name_id;
|
||||
|
||||
int inhibit_count;
|
||||
|
||||
GHashTable *sessions;
|
||||
|
||||
MetaDbusSessionWatcher *session_watcher;
|
||||
MetaDbusSessionManager parent;
|
||||
};
|
||||
|
||||
static void
|
||||
meta_remote_desktop_init_iface (MetaDBusRemoteDesktopIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (MetaRemoteDesktop,
|
||||
meta_remote_desktop,
|
||||
META_DBUS_TYPE_REMOTE_DESKTOP_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_REMOTE_DESKTOP,
|
||||
meta_remote_desktop_init_iface));
|
||||
|
||||
void
|
||||
meta_remote_desktop_inhibit (MetaRemoteDesktop *remote_desktop)
|
||||
{
|
||||
remote_desktop->inhibit_count++;
|
||||
if (remote_desktop->inhibit_count == 1)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
g_hash_table_iter_init (&iter, remote_desktop->sessions);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
MetaRemoteDesktopSession *session = value;
|
||||
|
||||
g_hash_table_iter_steal (&iter);
|
||||
meta_dbus_session_close (META_DBUS_SESSION (session));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_remote_desktop_uninhibit (MetaRemoteDesktop *remote_desktop)
|
||||
{
|
||||
g_return_if_fail (remote_desktop->inhibit_count > 0);
|
||||
|
||||
remote_desktop->inhibit_count--;
|
||||
}
|
||||
|
||||
MetaBackend *
|
||||
meta_remote_desktop_get_backend (MetaRemoteDesktop *remote_desktop)
|
||||
{
|
||||
return remote_desktop->backend;
|
||||
}
|
||||
|
||||
GDBusConnection *
|
||||
meta_remote_desktop_get_connection (MetaRemoteDesktop *remote_desktop)
|
||||
{
|
||||
GDBusInterfaceSkeleton *interface_skeleton =
|
||||
G_DBUS_INTERFACE_SKELETON (remote_desktop);
|
||||
|
||||
return g_dbus_interface_skeleton_get_connection (interface_skeleton);
|
||||
}
|
||||
|
||||
MetaRemoteDesktopSession *
|
||||
meta_remote_desktop_get_session (MetaRemoteDesktop *remote_desktop,
|
||||
const char *session_id)
|
||||
{
|
||||
return g_hash_table_lookup (remote_desktop->sessions, session_id);
|
||||
}
|
||||
|
||||
static void
|
||||
on_session_closed (MetaRemoteDesktopSession *session,
|
||||
MetaRemoteDesktop *remote_desktop)
|
||||
{
|
||||
char *session_id;
|
||||
|
||||
session_id = meta_remote_desktop_session_get_session_id (session);
|
||||
g_hash_table_remove (remote_desktop->sessions, session_id);
|
||||
}
|
||||
G_DEFINE_TYPE (MetaRemoteDesktop, meta_remote_desktop,
|
||||
META_TYPE_DBUS_SESSION_MANAGER)
|
||||
|
||||
static gboolean
|
||||
handle_create_session (MetaDBusRemoteDesktop *skeleton,
|
||||
GDBusMethodInvocation *invocation)
|
||||
GDBusMethodInvocation *invocation,
|
||||
MetaRemoteDesktop *remote_desktop)
|
||||
{
|
||||
MetaRemoteDesktop *remote_desktop = META_REMOTE_DESKTOP (skeleton);
|
||||
const char *peer_name;
|
||||
MetaDbusSessionManager *session_manager =
|
||||
META_DBUS_SESSION_MANAGER (remote_desktop);
|
||||
MetaDbusSession *dbus_session;
|
||||
MetaRemoteDesktopSession *session;
|
||||
GError *error = NULL;
|
||||
char *session_id;
|
||||
g_autoptr (GError) error = NULL;
|
||||
char *session_path;
|
||||
const char *client_dbus_name;
|
||||
|
||||
if (remote_desktop->inhibit_count > 0)
|
||||
dbus_session =
|
||||
meta_dbus_session_manager_create_session (session_manager,
|
||||
invocation,
|
||||
&error,
|
||||
NULL);
|
||||
if (!dbus_session)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_ACCESS_DENIED,
|
||||
"Session creation inhibited");
|
||||
|
||||
return TRUE;
|
||||
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_FAILED,
|
||||
error->message);
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
peer_name = g_dbus_method_invocation_get_sender (invocation);
|
||||
session = meta_remote_desktop_session_new (remote_desktop,
|
||||
peer_name,
|
||||
&error);
|
||||
if (!session)
|
||||
{
|
||||
g_warning ("Failed to create remote desktop session: %s",
|
||||
error->message);
|
||||
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_FAILED,
|
||||
"Failed to create session: %s",
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
session_id = meta_remote_desktop_session_get_session_id (session);
|
||||
g_hash_table_insert (remote_desktop->sessions,
|
||||
session_id,
|
||||
session);
|
||||
|
||||
client_dbus_name = g_dbus_method_invocation_get_sender (invocation);
|
||||
meta_dbus_session_watcher_watch_session (remote_desktop->session_watcher,
|
||||
client_dbus_name,
|
||||
META_DBUS_SESSION (session));
|
||||
|
||||
session = META_REMOTE_DESKTOP_SESSION (dbus_session);
|
||||
session_path = meta_remote_desktop_session_get_object_path (session);
|
||||
meta_dbus_remote_desktop_complete_create_session (skeleton,
|
||||
invocation,
|
||||
session_path);
|
||||
|
||||
g_signal_connect (session, "session-closed",
|
||||
G_CALLBACK (on_session_closed),
|
||||
remote_desktop);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_remote_desktop_init_iface (MetaDBusRemoteDesktopIface *iface)
|
||||
{
|
||||
iface->handle_create_session = handle_create_session;
|
||||
}
|
||||
|
||||
static void
|
||||
on_bus_acquired (GDBusConnection *connection,
|
||||
const char *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaRemoteDesktop *remote_desktop = user_data;
|
||||
GDBusInterfaceSkeleton *interface_skeleton =
|
||||
G_DBUS_INTERFACE_SKELETON (remote_desktop);
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
if (!g_dbus_interface_skeleton_export (interface_skeleton,
|
||||
connection,
|
||||
META_REMOTE_DESKTOP_DBUS_PATH,
|
||||
&error))
|
||||
g_warning ("Failed to export remote desktop object: %s", error->message);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_acquired (GDBusConnection *connection,
|
||||
const char *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_info ("Acquired name %s", name);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_lost (GDBusConnection *connection,
|
||||
const char *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_warning ("Lost or failed to acquire name %s", name);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_remote_desktop_constructed (GObject *object)
|
||||
{
|
||||
MetaRemoteDesktop *remote_desktop = META_REMOTE_DESKTOP (object);
|
||||
|
||||
remote_desktop->dbus_name_id =
|
||||
g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
META_REMOTE_DESKTOP_DBUS_SERVICE,
|
||||
G_BUS_NAME_OWNER_FLAGS_NONE,
|
||||
on_bus_acquired,
|
||||
on_name_acquired,
|
||||
on_name_lost,
|
||||
remote_desktop,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
on_prepare_shutdown (MetaBackend *backend,
|
||||
MetaRemoteDesktop *remote_desktop)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer value;
|
||||
|
||||
g_hash_table_iter_init (&iter, remote_desktop->sessions);
|
||||
while (g_hash_table_iter_next (&iter, NULL, &value))
|
||||
{
|
||||
MetaRemoteDesktopSession *session = value;
|
||||
|
||||
g_hash_table_iter_steal (&iter);
|
||||
meta_dbus_session_close (META_DBUS_SESSION (session));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_remote_desktop_finalize (GObject *object)
|
||||
{
|
||||
MetaRemoteDesktop *remote_desktop = META_REMOTE_DESKTOP (object);
|
||||
|
||||
if (remote_desktop->dbus_name_id != 0)
|
||||
g_bus_unown_name (remote_desktop->dbus_name_id);
|
||||
|
||||
g_assert (g_hash_table_size (remote_desktop->sessions) == 0);
|
||||
g_hash_table_destroy (remote_desktop->sessions);
|
||||
|
||||
G_OBJECT_CLASS (meta_remote_desktop_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
MetaRemoteDesktop *
|
||||
meta_remote_desktop_new (MetaBackend *backend,
|
||||
MetaDbusSessionWatcher *session_watcher)
|
||||
{
|
||||
MetaRemoteDesktop *remote_desktop;
|
||||
|
||||
remote_desktop = g_object_new (META_TYPE_REMOTE_DESKTOP, NULL);
|
||||
remote_desktop->backend = backend;
|
||||
remote_desktop->session_watcher = session_watcher;
|
||||
|
||||
g_signal_connect (backend, "prepare-shutdown",
|
||||
G_CALLBACK (on_prepare_shutdown),
|
||||
remote_desktop);
|
||||
|
||||
return remote_desktop;
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
static MetaRemoteDesktopDeviceTypes
|
||||
calculate_supported_device_types (void)
|
||||
calculate_supported_device_types (MetaBackend *backend)
|
||||
{
|
||||
ClutterBackend *backend = clutter_get_default_backend ();
|
||||
ClutterSeat *seat = clutter_backend_get_default_seat (backend);
|
||||
ClutterSeat *seat = meta_backend_get_default_seat (backend);
|
||||
ClutterVirtualDeviceType device_types;
|
||||
MetaRemoteDesktopDeviceTypes supported_devices =
|
||||
META_REMOTE_DESKTOP_DEVICE_TYPE_NONE;
|
||||
@ -320,16 +113,52 @@ calculate_supported_device_types (void)
|
||||
}
|
||||
|
||||
static void
|
||||
meta_remote_desktop_init (MetaRemoteDesktop *remote_desktop)
|
||||
meta_remote_desktop_constructed (GObject *object)
|
||||
{
|
||||
remote_desktop->sessions = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
MetaRemoteDesktop *remote_desktop = META_REMOTE_DESKTOP (object);
|
||||
MetaDbusSessionManager *session_manager =
|
||||
META_DBUS_SESSION_MANAGER (remote_desktop);
|
||||
GDBusInterfaceSkeleton *interface_skeleton =
|
||||
meta_dbus_session_manager_get_interface_skeleton (session_manager);
|
||||
MetaDBusRemoteDesktop *interface =
|
||||
META_DBUS_REMOTE_DESKTOP (interface_skeleton);
|
||||
MetaBackend *backend = meta_dbus_session_manager_get_backend (session_manager);
|
||||
|
||||
g_signal_connect (interface, "handle-create-session",
|
||||
G_CALLBACK (handle_create_session), remote_desktop);
|
||||
|
||||
meta_dbus_remote_desktop_set_supported_device_types (
|
||||
META_DBUS_REMOTE_DESKTOP (remote_desktop),
|
||||
calculate_supported_device_types ());
|
||||
interface,
|
||||
calculate_supported_device_types (backend));
|
||||
meta_dbus_remote_desktop_set_version (
|
||||
META_DBUS_REMOTE_DESKTOP (remote_desktop),
|
||||
interface,
|
||||
META_REMOTE_DESKTOP_API_VERSION);
|
||||
|
||||
G_OBJECT_CLASS (meta_remote_desktop_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
MetaRemoteDesktop *
|
||||
meta_remote_desktop_new (MetaBackend *backend)
|
||||
{
|
||||
MetaRemoteDesktop *remote_desktop;
|
||||
g_autoptr (MetaDBusRemoteDesktop) skeleton = NULL;
|
||||
|
||||
skeleton = meta_dbus_remote_desktop_skeleton_new ();
|
||||
remote_desktop =
|
||||
g_object_new (META_TYPE_REMOTE_DESKTOP,
|
||||
"backend", backend,
|
||||
"service-name", META_REMOTE_DESKTOP_DBUS_SERVICE,
|
||||
"service-path", META_REMOTE_DESKTOP_DBUS_PATH,
|
||||
"session-gtype", META_TYPE_REMOTE_DESKTOP_SESSION,
|
||||
"interface-skeleton", skeleton,
|
||||
NULL);
|
||||
|
||||
return remote_desktop;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_remote_desktop_init (MetaRemoteDesktop *remote_desktop)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
@ -338,5 +167,4 @@ meta_remote_desktop_class_init (MetaRemoteDesktopClass *klass)
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->constructed = meta_remote_desktop_constructed;
|
||||
object_class->finalize = meta_remote_desktop_finalize;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "backends/meta-backend-types.h"
|
||||
#include "backends/meta-dbus-session-manager.h"
|
||||
#include "backends/meta-dbus-session-watcher.h"
|
||||
|
||||
#include "meta-dbus-remote-desktop.h"
|
||||
@ -35,20 +36,8 @@ typedef struct _MetaRemoteDesktopSession MetaRemoteDesktopSession;
|
||||
#define META_TYPE_REMOTE_DESKTOP (meta_remote_desktop_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaRemoteDesktop, meta_remote_desktop,
|
||||
META, REMOTE_DESKTOP,
|
||||
MetaDBusRemoteDesktopSkeleton)
|
||||
MetaDbusSessionManager)
|
||||
|
||||
void meta_remote_desktop_inhibit (MetaRemoteDesktop *remote_desktop);
|
||||
|
||||
void meta_remote_desktop_uninhibit (MetaRemoteDesktop *remote_desktop);
|
||||
|
||||
MetaBackend * meta_remote_desktop_get_backend (MetaRemoteDesktop *remote_desktop);
|
||||
|
||||
MetaRemoteDesktopSession * meta_remote_desktop_get_session (MetaRemoteDesktop *remote_desktop,
|
||||
const char *session_id);
|
||||
|
||||
GDBusConnection * meta_remote_desktop_get_connection (MetaRemoteDesktop *remote_desktop);
|
||||
|
||||
MetaRemoteDesktop * meta_remote_desktop_new (MetaBackend *backend,
|
||||
MetaDbusSessionWatcher *session_watcher);
|
||||
MetaRemoteDesktop * meta_remote_desktop_new (MetaBackend *backend);
|
||||
|
||||
#endif /* META_REMOTE_DESKTOP_H */
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include "backends/meta-cursor-tracker-private.h"
|
||||
#include "backends/meta-dbus-session-manager.h"
|
||||
#include "backends/meta-screen-cast-area-stream.h"
|
||||
#include "backends/meta-screen-cast-session.h"
|
||||
#include "backends/meta-stage-private.h"
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "backends/meta-screen-cast-session.h"
|
||||
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include "backends/meta-dbus-session-manager.h"
|
||||
#include "backends/meta-dbus-session-watcher.h"
|
||||
#include "backends/meta-remote-access-controller-private.h"
|
||||
#include "backends/meta-screen-cast-area-stream.h"
|
||||
@ -34,18 +35,35 @@
|
||||
#include "backends/meta-screen-cast-window-stream.h"
|
||||
#include "core/display-private.h"
|
||||
|
||||
#include "meta-private-enum-types.h"
|
||||
|
||||
#define META_SCREEN_CAST_SESSION_DBUS_PATH "/org/gnome/Mutter/ScreenCast/Session"
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_SESSION_MANAGER,
|
||||
PROP_PEER_NAME,
|
||||
PROP_ID,
|
||||
PROP_SESSION_TYPE,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *obj_props[N_PROPS];
|
||||
|
||||
struct _MetaScreenCastSession
|
||||
{
|
||||
MetaDBusScreenCastSessionSkeleton parent;
|
||||
|
||||
MetaScreenCast *screen_cast;
|
||||
MetaDbusSessionManager *session_manager;
|
||||
|
||||
char *peer_name;
|
||||
|
||||
MetaScreenCastSessionType session_type;
|
||||
char *object_path;
|
||||
char *session_id;
|
||||
|
||||
GList *streams;
|
||||
|
||||
@ -55,6 +73,8 @@ struct _MetaScreenCastSession
|
||||
gboolean disable_animations;
|
||||
};
|
||||
|
||||
static void initable_init_iface (GInitableIface *iface);
|
||||
|
||||
static void
|
||||
meta_screen_cast_session_init_iface (MetaDBusScreenCastSessionIface *iface);
|
||||
|
||||
@ -64,6 +84,8 @@ meta_dbus_session_init_iface (MetaDbusSessionInterface *iface);
|
||||
G_DEFINE_TYPE_WITH_CODE (MetaScreenCastSession,
|
||||
meta_screen_cast_session,
|
||||
META_DBUS_TYPE_SCREEN_CAST_SESSION_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
|
||||
initable_init_iface)
|
||||
G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_SCREEN_CAST_SESSION,
|
||||
meta_screen_cast_session_init_iface)
|
||||
G_IMPLEMENT_INTERFACE (META_TYPE_DBUS_SESSION,
|
||||
@ -87,7 +109,7 @@ static void
|
||||
init_remote_access_handle (MetaScreenCastSession *session)
|
||||
{
|
||||
MetaBackend *backend =
|
||||
meta_screen_cast_get_backend (session->screen_cast);
|
||||
meta_dbus_session_manager_get_backend (session->session_manager);
|
||||
MetaRemoteAccessController *remote_access_controller;
|
||||
MetaRemoteAccessHandle *remote_access_handle;
|
||||
|
||||
@ -164,6 +186,14 @@ meta_screen_cast_session_close (MetaDbusSession *dbus_session)
|
||||
g_object_unref (session);
|
||||
}
|
||||
|
||||
static const char *
|
||||
meta_screen_cast_session_get_id (MetaDbusSession *dbus_session)
|
||||
{
|
||||
MetaScreenCastSession *session = META_SCREEN_CAST_SESSION (dbus_session);
|
||||
|
||||
return session->session_id;
|
||||
}
|
||||
|
||||
MetaScreenCastStream *
|
||||
meta_screen_cast_session_get_stream (MetaScreenCastSession *session,
|
||||
const char *path)
|
||||
@ -185,7 +215,7 @@ meta_screen_cast_session_get_stream (MetaScreenCastSession *session,
|
||||
MetaScreenCast *
|
||||
meta_screen_cast_session_get_screen_cast (MetaScreenCastSession *session)
|
||||
{
|
||||
return session->screen_cast;
|
||||
return META_SCREEN_CAST (session->session_manager);
|
||||
}
|
||||
|
||||
void
|
||||
@ -221,6 +251,38 @@ check_permission (MetaScreenCastSession *session,
|
||||
g_dbus_method_invocation_get_sender (invocation)) == 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_screen_cast_session_initable_init (GInitable *initable,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
MetaScreenCastSession *session = META_SCREEN_CAST_SESSION (initable);
|
||||
GDBusInterfaceSkeleton *interface_skeleton;
|
||||
GDBusConnection *connection;
|
||||
static unsigned int global_session_number = 0;
|
||||
|
||||
session->object_path =
|
||||
g_strdup_printf (META_SCREEN_CAST_SESSION_DBUS_PATH "/u%u",
|
||||
++global_session_number);
|
||||
|
||||
interface_skeleton = G_DBUS_INTERFACE_SKELETON (session);
|
||||
connection =
|
||||
meta_dbus_session_manager_get_connection (session->session_manager);
|
||||
if (!g_dbus_interface_skeleton_export (interface_skeleton,
|
||||
connection,
|
||||
session->object_path,
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
initable_init_iface (GInitableIface *iface)
|
||||
{
|
||||
iface->init = meta_screen_cast_session_initable_init;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_start (MetaDBusScreenCastSession *skeleton,
|
||||
GDBusMethodInvocation *invocation)
|
||||
@ -326,7 +388,7 @@ handle_record_monitor (MetaDBusScreenCastSession *skeleton,
|
||||
GDBusInterfaceSkeleton *interface_skeleton;
|
||||
GDBusConnection *connection;
|
||||
MetaBackend *backend =
|
||||
meta_screen_cast_get_backend (session->screen_cast);
|
||||
meta_dbus_session_manager_get_backend (session->session_manager);
|
||||
MetaMonitorManager *monitor_manager =
|
||||
meta_backend_get_monitor_manager (backend);
|
||||
MetaMonitor *monitor;
|
||||
@ -426,7 +488,7 @@ handle_record_window (MetaDBusScreenCastSession *skeleton,
|
||||
{
|
||||
MetaScreenCastSession *session = META_SCREEN_CAST_SESSION (skeleton);
|
||||
MetaBackend *backend =
|
||||
meta_screen_cast_get_backend (session->screen_cast);
|
||||
meta_dbus_session_manager_get_backend (session->session_manager);
|
||||
MetaContext *context = meta_backend_get_context (backend);
|
||||
MetaDisplay *display = meta_context_get_display (context);
|
||||
GDBusInterfaceSkeleton *interface_skeleton;
|
||||
@ -580,7 +642,7 @@ handle_record_area (MetaDBusScreenCastSession *skeleton,
|
||||
|
||||
interface_skeleton = G_DBUS_INTERFACE_SKELETON (skeleton);
|
||||
connection = g_dbus_interface_skeleton_get_connection (interface_skeleton);
|
||||
backend = meta_screen_cast_get_backend (session->screen_cast);
|
||||
backend = meta_dbus_session_manager_get_backend (session->session_manager);
|
||||
stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
|
||||
|
||||
flags = META_SCREEN_CAST_FLAG_NONE;
|
||||
@ -715,36 +777,7 @@ static void
|
||||
meta_dbus_session_init_iface (MetaDbusSessionInterface *iface)
|
||||
{
|
||||
iface->close = meta_screen_cast_session_close;
|
||||
}
|
||||
|
||||
MetaScreenCastSession *
|
||||
meta_screen_cast_session_new (MetaScreenCast *screen_cast,
|
||||
MetaScreenCastSessionType session_type,
|
||||
const char *peer_name,
|
||||
GError **error)
|
||||
{
|
||||
GDBusInterfaceSkeleton *interface_skeleton;
|
||||
MetaScreenCastSession *session;
|
||||
GDBusConnection *connection;
|
||||
static unsigned int global_session_number = 0;
|
||||
|
||||
session = g_object_new (META_TYPE_SCREEN_CAST_SESSION, NULL);
|
||||
session->screen_cast = screen_cast;
|
||||
session->session_type = session_type;
|
||||
session->peer_name = g_strdup (peer_name);
|
||||
session->object_path =
|
||||
g_strdup_printf (META_SCREEN_CAST_SESSION_DBUS_PATH "/u%u",
|
||||
++global_session_number);
|
||||
|
||||
interface_skeleton = G_DBUS_INTERFACE_SKELETON (session);
|
||||
connection = meta_screen_cast_get_connection (screen_cast);
|
||||
if (!g_dbus_interface_skeleton_export (interface_skeleton,
|
||||
connection,
|
||||
session->object_path,
|
||||
error))
|
||||
return NULL;
|
||||
|
||||
return session;
|
||||
iface->get_id = meta_screen_cast_session_get_id;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -755,10 +788,67 @@ meta_screen_cast_session_finalize (GObject *object)
|
||||
g_clear_object (&session->handle);
|
||||
g_free (session->peer_name);
|
||||
g_free (session->object_path);
|
||||
g_free (session->session_id);
|
||||
|
||||
G_OBJECT_CLASS (meta_screen_cast_session_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_session_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaScreenCastSession *session = META_SCREEN_CAST_SESSION (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SESSION_MANAGER:
|
||||
session->session_manager = g_value_get_object (value);
|
||||
break;
|
||||
case PROP_PEER_NAME:
|
||||
session->peer_name = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_ID:
|
||||
session->session_id = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_SESSION_TYPE:
|
||||
session->session_type = g_value_get_enum (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_session_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaScreenCastSession *session = META_SCREEN_CAST_SESSION (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SESSION_MANAGER:
|
||||
g_value_set_object (value, session->session_manager);
|
||||
break;
|
||||
case PROP_PEER_NAME:
|
||||
g_value_set_string (value, session->peer_name);
|
||||
break;
|
||||
case PROP_ID:
|
||||
g_value_set_string (value, session->session_id);
|
||||
break;
|
||||
case PROP_SESSION_TYPE:
|
||||
g_value_set_enum (value, session->session_type);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_session_init (MetaScreenCastSession *session)
|
||||
{
|
||||
@ -770,6 +860,43 @@ meta_screen_cast_session_class_init (MetaScreenCastSessionClass *klass)
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_screen_cast_session_finalize;
|
||||
object_class->set_property = meta_screen_cast_session_set_property;
|
||||
object_class->get_property = meta_screen_cast_session_get_property;
|
||||
|
||||
obj_props[PROP_SESSION_MANAGER] =
|
||||
g_param_spec_object ("session-manager",
|
||||
"session manager",
|
||||
"D-Bus session manager",
|
||||
META_TYPE_DBUS_SESSION_MANAGER,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
obj_props[PROP_PEER_NAME] =
|
||||
g_param_spec_string ("peer-name",
|
||||
"peer name",
|
||||
"D-Bus peer name",
|
||||
NULL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
obj_props[PROP_ID] =
|
||||
g_param_spec_string ("id",
|
||||
"session id",
|
||||
"Unique ID of the session",
|
||||
NULL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
obj_props[PROP_SESSION_TYPE] =
|
||||
g_param_spec_enum ("session-type",
|
||||
"session type",
|
||||
"The type of screen cast session",
|
||||
META_TYPE_SCREEN_CAST_SESSION_TYPE,
|
||||
META_SCREEN_CAST_SESSION_TYPE_NORMAL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
g_object_class_install_properties (object_class, N_PROPS, obj_props);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -51,11 +51,6 @@ char * meta_screen_cast_session_get_peer_name (MetaScreenCastSession *session);
|
||||
|
||||
MetaScreenCastSessionType meta_screen_cast_session_get_session_type (MetaScreenCastSession *session);
|
||||
|
||||
MetaScreenCastSession * meta_screen_cast_session_new (MetaScreenCast *screen_cast,
|
||||
MetaScreenCastSessionType session_type,
|
||||
const char *peer_name,
|
||||
GError **error);
|
||||
|
||||
gboolean meta_screen_cast_session_start (MetaScreenCastSession *session,
|
||||
GError **error);
|
||||
|
||||
|
@ -36,64 +36,20 @@
|
||||
|
||||
struct _MetaScreenCast
|
||||
{
|
||||
MetaDBusScreenCastSkeleton parent;
|
||||
|
||||
int dbus_name_id;
|
||||
|
||||
int inhibit_count;
|
||||
|
||||
GList *sessions;
|
||||
|
||||
MetaDbusSessionWatcher *session_watcher;
|
||||
MetaBackend *backend;
|
||||
MetaDbusSessionManager parent;
|
||||
|
||||
gboolean disable_dma_bufs;
|
||||
};
|
||||
|
||||
static void
|
||||
meta_screen_cast_init_iface (MetaDBusScreenCastIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (MetaScreenCast, meta_screen_cast,
|
||||
META_DBUS_TYPE_SCREEN_CAST_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (META_DBUS_TYPE_SCREEN_CAST,
|
||||
meta_screen_cast_init_iface))
|
||||
|
||||
void
|
||||
meta_screen_cast_inhibit (MetaScreenCast *screen_cast)
|
||||
{
|
||||
screen_cast->inhibit_count++;
|
||||
if (screen_cast->inhibit_count == 1)
|
||||
{
|
||||
while (screen_cast->sessions)
|
||||
{
|
||||
MetaScreenCastSession *session = screen_cast->sessions->data;
|
||||
|
||||
meta_dbus_session_close (META_DBUS_SESSION (session));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_screen_cast_uninhibit (MetaScreenCast *screen_cast)
|
||||
{
|
||||
g_return_if_fail (screen_cast->inhibit_count > 0);
|
||||
|
||||
screen_cast->inhibit_count--;
|
||||
}
|
||||
|
||||
GDBusConnection *
|
||||
meta_screen_cast_get_connection (MetaScreenCast *screen_cast)
|
||||
{
|
||||
GDBusInterfaceSkeleton *interface_skeleton =
|
||||
G_DBUS_INTERFACE_SKELETON (screen_cast);
|
||||
|
||||
return g_dbus_interface_skeleton_get_connection (interface_skeleton);
|
||||
}
|
||||
G_DEFINE_TYPE (MetaScreenCast, meta_screen_cast,
|
||||
META_TYPE_DBUS_SESSION_MANAGER)
|
||||
|
||||
MetaBackend *
|
||||
meta_screen_cast_get_backend (MetaScreenCast *screen_cast)
|
||||
{
|
||||
return screen_cast->backend;
|
||||
MetaDbusSessionManager *session_manager = META_DBUS_SESSION_MANAGER (screen_cast);
|
||||
|
||||
return meta_dbus_session_manager_get_backend (session_manager);
|
||||
}
|
||||
|
||||
void
|
||||
@ -107,8 +63,12 @@ meta_screen_cast_create_dma_buf_handle (MetaScreenCast *screen_cast,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
MetaDbusSessionManager *session_manager =
|
||||
META_DBUS_SESSION_MANAGER (screen_cast);
|
||||
MetaBackend *backend =
|
||||
meta_dbus_session_manager_get_backend (session_manager);
|
||||
ClutterBackend *clutter_backend =
|
||||
meta_backend_get_clutter_backend (screen_cast->backend);
|
||||
meta_backend_get_clutter_backend (backend);
|
||||
CoglContext *cogl_context =
|
||||
clutter_backend_get_cogl_context (clutter_backend);
|
||||
CoglRenderer *cogl_renderer = cogl_context_get_renderer (cogl_context);
|
||||
@ -140,19 +100,28 @@ register_remote_desktop_screen_cast_session (MetaScreenCastSession *session,
|
||||
{
|
||||
MetaScreenCast *screen_cast =
|
||||
meta_screen_cast_session_get_screen_cast (session);
|
||||
MetaBackend *backend = meta_screen_cast_get_backend (screen_cast);
|
||||
MetaDbusSessionManager *session_manager =
|
||||
META_DBUS_SESSION_MANAGER (screen_cast);
|
||||
MetaBackend *backend =
|
||||
meta_dbus_session_manager_get_backend (session_manager);
|
||||
MetaRemoteDesktop *remote_desktop = meta_backend_get_remote_desktop (backend);
|
||||
MetaDbusSessionManager *remote_desktop_session_manager =
|
||||
META_DBUS_SESSION_MANAGER (remote_desktop);
|
||||
MetaDbusSession *remote_desktop_dbus_session;
|
||||
MetaRemoteDesktopSession *remote_desktop_session;
|
||||
|
||||
remote_desktop_session =
|
||||
meta_remote_desktop_get_session (remote_desktop, remote_desktop_session_id);
|
||||
if (!remote_desktop_session)
|
||||
remote_desktop_dbus_session =
|
||||
meta_dbus_session_manager_get_session (remote_desktop_session_manager,
|
||||
remote_desktop_session_id);
|
||||
if (!remote_desktop_dbus_session)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"No remote desktop session found");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
remote_desktop_session =
|
||||
META_REMOTE_DESKTOP_SESSION (remote_desktop_dbus_session);
|
||||
if (!meta_remote_desktop_session_register_screen_cast (remote_desktop_session,
|
||||
session,
|
||||
error))
|
||||
@ -161,36 +130,21 @@ register_remote_desktop_screen_cast_session (MetaScreenCastSession *session,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
on_session_closed (MetaScreenCastSession *session,
|
||||
MetaScreenCast *screen_cast)
|
||||
{
|
||||
screen_cast->sessions = g_list_remove (screen_cast->sessions, session);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_create_session (MetaDBusScreenCast *skeleton,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GVariant *properties)
|
||||
GVariant *properties,
|
||||
MetaScreenCast *screen_cast)
|
||||
{
|
||||
MetaScreenCast *screen_cast = META_SCREEN_CAST (skeleton);
|
||||
const char *peer_name;
|
||||
MetaScreenCastSession *session;
|
||||
GError *error = NULL;
|
||||
const char *session_path;
|
||||
const char *client_dbus_name;
|
||||
MetaDbusSessionManager *session_manager =
|
||||
META_DBUS_SESSION_MANAGER (screen_cast);
|
||||
char *remote_desktop_session_id = NULL;
|
||||
gboolean disable_animations;
|
||||
MetaScreenCastSessionType session_type;
|
||||
|
||||
if (screen_cast->inhibit_count > 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_ACCESS_DENIED,
|
||||
"Session creation inhibited");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
MetaDbusSession *dbus_session;
|
||||
MetaScreenCastSession *session;
|
||||
g_autoptr (GError) error = NULL;
|
||||
gboolean disable_animations;
|
||||
const char *session_path;
|
||||
|
||||
g_variant_lookup (properties, "remote-desktop-session-id", "s",
|
||||
&remote_desktop_session_id);
|
||||
@ -200,24 +154,20 @@ handle_create_session (MetaDBusScreenCast *skeleton,
|
||||
else
|
||||
session_type = META_SCREEN_CAST_SESSION_TYPE_NORMAL;
|
||||
|
||||
peer_name = g_dbus_method_invocation_get_sender (invocation);
|
||||
session = meta_screen_cast_session_new (screen_cast,
|
||||
session_type,
|
||||
peer_name,
|
||||
&error);
|
||||
if (!session)
|
||||
dbus_session =
|
||||
meta_dbus_session_manager_create_session (session_manager,
|
||||
invocation,
|
||||
&error,
|
||||
"session-type", session_type,
|
||||
NULL);
|
||||
if (!dbus_session)
|
||||
{
|
||||
g_warning ("Failed to create screen cast session: %s",
|
||||
error->message);
|
||||
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_FAILED,
|
||||
"Failed to create session: %s",
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
|
||||
return TRUE;
|
||||
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_FAILED,
|
||||
error->message);
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
session = META_SCREEN_CAST_SESSION (dbus_session);
|
||||
|
||||
if (remote_desktop_session_id)
|
||||
{
|
||||
@ -228,9 +178,8 @@ handle_create_session (MetaDBusScreenCast *skeleton,
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||
G_DBUS_ERROR_FAILED,
|
||||
"%s", error->message);
|
||||
g_error_free (error);
|
||||
g_object_unref (session);
|
||||
return TRUE;
|
||||
meta_dbus_session_close (dbus_session);
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,121 +189,46 @@ handle_create_session (MetaDBusScreenCast *skeleton,
|
||||
meta_screen_cast_session_set_disable_animations (session,
|
||||
disable_animations);
|
||||
}
|
||||
|
||||
client_dbus_name = g_dbus_method_invocation_get_sender (invocation);
|
||||
meta_dbus_session_watcher_watch_session (screen_cast->session_watcher,
|
||||
client_dbus_name,
|
||||
META_DBUS_SESSION (session));
|
||||
|
||||
session_path = meta_screen_cast_session_get_object_path (session);
|
||||
meta_dbus_screen_cast_complete_create_session (skeleton,
|
||||
invocation,
|
||||
session_path);
|
||||
|
||||
screen_cast->sessions = g_list_append (screen_cast->sessions, session);
|
||||
|
||||
g_signal_connect (session, "session-closed",
|
||||
G_CALLBACK (on_session_closed),
|
||||
screen_cast);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_init_iface (MetaDBusScreenCastIface *iface)
|
||||
{
|
||||
iface->handle_create_session = handle_create_session;
|
||||
}
|
||||
|
||||
static void
|
||||
on_bus_acquired (GDBusConnection *connection,
|
||||
const char *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaScreenCast *screen_cast = user_data;
|
||||
GDBusInterfaceSkeleton *interface_skeleton =
|
||||
G_DBUS_INTERFACE_SKELETON (screen_cast);
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
if (!g_dbus_interface_skeleton_export (interface_skeleton,
|
||||
connection,
|
||||
META_SCREEN_CAST_DBUS_PATH,
|
||||
&error))
|
||||
g_warning ("Failed to export screen cast object: %s", error->message);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_acquired (GDBusConnection *connection,
|
||||
const char *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_info ("Acquired name %s", name);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_lost (GDBusConnection *connection,
|
||||
const char *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_warning ("Lost or failed to acquire name %s", name);
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_screen_cast_constructed (GObject *object)
|
||||
{
|
||||
MetaScreenCast *screen_cast = META_SCREEN_CAST (object);
|
||||
MetaDbusSessionManager *session_manager =
|
||||
META_DBUS_SESSION_MANAGER (screen_cast);
|
||||
GDBusInterfaceSkeleton *interface_skeleton =
|
||||
meta_dbus_session_manager_get_interface_skeleton (session_manager);
|
||||
MetaDBusScreenCast *skeleton = META_DBUS_SCREEN_CAST (interface_skeleton);
|
||||
|
||||
screen_cast->dbus_name_id =
|
||||
g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
META_SCREEN_CAST_DBUS_SERVICE,
|
||||
G_BUS_NAME_OWNER_FLAGS_NONE,
|
||||
on_bus_acquired,
|
||||
on_name_acquired,
|
||||
on_name_lost,
|
||||
screen_cast,
|
||||
NULL);
|
||||
}
|
||||
g_signal_connect (interface_skeleton, "handle-create-session",
|
||||
G_CALLBACK (handle_create_session), screen_cast);
|
||||
|
||||
static void
|
||||
meta_screen_cast_finalize (GObject *object)
|
||||
{
|
||||
MetaScreenCast *screen_cast = META_SCREEN_CAST (object);
|
||||
meta_dbus_screen_cast_set_version (skeleton, META_SCREEN_CAST_API_VERSION);
|
||||
|
||||
if (screen_cast->dbus_name_id)
|
||||
g_bus_unown_name (screen_cast->dbus_name_id);
|
||||
|
||||
g_assert (!screen_cast->sessions);
|
||||
|
||||
G_OBJECT_CLASS (meta_screen_cast_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
on_prepare_shutdown (MetaBackend *backend,
|
||||
MetaScreenCast *screen_cast)
|
||||
{
|
||||
while (screen_cast->sessions)
|
||||
{
|
||||
MetaScreenCastSession *session = screen_cast->sessions->data;
|
||||
|
||||
if (meta_screen_cast_session_get_session_type (session) !=
|
||||
META_SCREEN_CAST_SESSION_TYPE_REMOTE_DESKTOP)
|
||||
meta_dbus_session_close (META_DBUS_SESSION (session));
|
||||
}
|
||||
G_OBJECT_CLASS (meta_screen_cast_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
MetaScreenCast *
|
||||
meta_screen_cast_new (MetaBackend *backend,
|
||||
MetaDbusSessionWatcher *session_watcher)
|
||||
meta_screen_cast_new (MetaBackend *backend)
|
||||
{
|
||||
MetaScreenCast *screen_cast;
|
||||
g_autoptr (MetaDBusScreenCast) skeleton = NULL;
|
||||
|
||||
screen_cast = g_object_new (META_TYPE_SCREEN_CAST, NULL);
|
||||
screen_cast->backend = backend;
|
||||
screen_cast->session_watcher = session_watcher;
|
||||
|
||||
g_signal_connect (backend, "prepare-shutdown",
|
||||
G_CALLBACK (on_prepare_shutdown),
|
||||
screen_cast);
|
||||
skeleton = meta_dbus_screen_cast_skeleton_new ();
|
||||
screen_cast =
|
||||
g_object_new (META_TYPE_SCREEN_CAST,
|
||||
"backend", backend,
|
||||
"service-name", META_SCREEN_CAST_DBUS_SERVICE,
|
||||
"service-path", META_SCREEN_CAST_DBUS_PATH,
|
||||
"session-gtype", META_TYPE_SCREEN_CAST_SESSION,
|
||||
"interface-skeleton", skeleton,
|
||||
NULL);
|
||||
|
||||
return screen_cast;
|
||||
}
|
||||
@ -369,9 +243,6 @@ meta_screen_cast_init (MetaScreenCast *screen_cast)
|
||||
pw_init (NULL, NULL);
|
||||
is_pipewire_initialized = TRUE;
|
||||
}
|
||||
|
||||
meta_dbus_screen_cast_set_version (META_DBUS_SCREEN_CAST (screen_cast),
|
||||
META_SCREEN_CAST_API_VERSION);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -380,5 +251,4 @@ meta_screen_cast_class_init (MetaScreenCastClass *klass)
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->constructed = meta_screen_cast_constructed;
|
||||
object_class->finalize = meta_screen_cast_finalize;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include "backends/meta-dbus-session-manager.h"
|
||||
#include "backends/meta-dbus-session-watcher.h"
|
||||
|
||||
#include "meta-dbus-screen-cast.h"
|
||||
@ -47,13 +48,7 @@ typedef enum _MetaScreenCastFlag
|
||||
#define META_TYPE_SCREEN_CAST (meta_screen_cast_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaScreenCast, meta_screen_cast,
|
||||
META, SCREEN_CAST,
|
||||
MetaDBusScreenCastSkeleton)
|
||||
|
||||
void meta_screen_cast_inhibit (MetaScreenCast *screen_cast);
|
||||
|
||||
void meta_screen_cast_uninhibit (MetaScreenCast *screen_cast);
|
||||
|
||||
GDBusConnection * meta_screen_cast_get_connection (MetaScreenCast *screen_cast);
|
||||
MetaDbusSessionManager)
|
||||
|
||||
MetaBackend * meta_screen_cast_get_backend (MetaScreenCast *screen_cast);
|
||||
|
||||
@ -63,7 +58,6 @@ CoglDmaBufHandle * meta_screen_cast_create_dma_buf_handle (MetaScreenCast *scree
|
||||
int width,
|
||||
int height);
|
||||
|
||||
MetaScreenCast * meta_screen_cast_new (MetaBackend *backend,
|
||||
MetaDbusSessionWatcher *session_watcher);
|
||||
MetaScreenCast * meta_screen_cast_new (MetaBackend *backend);
|
||||
|
||||
#endif /* META_SCREEN_CAST_H */
|
||||
|
@ -845,6 +845,7 @@ mutter_private_enum_sources = []
|
||||
if have_remote_desktop
|
||||
mutter_private_enum_sources += [
|
||||
'backends/meta-screen-cast.h',
|
||||
'backends/meta-screen-cast-session.h',
|
||||
]
|
||||
endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user