diff options
author | Jasper St. Pierre <jstpierre@mecheye.net> | 2013-12-31 17:44:45 -0500 |
---|---|---|
committer | Jasper St. Pierre <jstpierre@mecheye.net> | 2014-05-19 15:09:23 -0400 |
commit | dcf64ca1678a2950842708bee146f09a063ed828 (patch) | |
tree | d3608b5b3f5ebbc58f47d73a13d9f14708260756 /src/backends/native/meta-launcher.c | |
parent | f93fc1506b1ca2cf6e65521a22a8d27c96d363cf (diff) | |
download | mutter-dcf64ca1678a2950842708bee146f09a063ed828.tar.gz |
launcher: Replace mutter-launch with logind integration
This uses David Herrmann's new logind sessions interface to retrieve
fds for input devices, rather than using a custom setuid helper to do
the management. This vastly simplifies the interface.
This requires systemd v210, at least.
https://bugzilla.gnome.org/show_bug.cgi?id=724604
Diffstat (limited to 'src/backends/native/meta-launcher.c')
-rw-r--r-- | src/backends/native/meta-launcher.c | 433 |
1 files changed, 208 insertions, 225 deletions
diff --git a/src/backends/native/meta-launcher.c b/src/backends/native/meta-launcher.c index 66755088e..751919464 100644 --- a/src/backends/native/meta-launcher.c +++ b/src/backends/native/meta-launcher.c @@ -20,9 +20,8 @@ #include "config.h" #include "meta-launcher.h" -#include "weston-launch.h" -#include <gio/gunixfdmessage.h> +#include <gio/gunixfdlist.h> #include <clutter/clutter.h> #include <clutter/egl/clutter-egl.h> @@ -30,10 +29,17 @@ #include <sys/types.h> #include <sys/stat.h> +#include <malloc.h> #include <fcntl.h> #include <errno.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> + +#include <systemd/sd-login.h> + +#include "dbus-utils.h" +#include "meta-dbus-login1.h" #include "wayland/meta-wayland-private.h" #include "backends/meta-backend.h" @@ -41,153 +47,44 @@ struct _MetaLauncher { - GSocket *weston_launch; - GSource *weston_launch_source; + Login1Session *session_proxy; + Login1Seat *seat_proxy; - gboolean vt_switched; + gboolean session_active; }; /* AAA BBB CCC */ -static void handle_request_vt_switch (MetaLauncher *self); - -static gboolean -request_vt_switch_idle (gpointer user_data) +static Login1Session * +get_session_proxy (GCancellable *cancellable) { - handle_request_vt_switch (user_data); + char *proxy_path; + char *session_id; + Login1Session *session_proxy; - return FALSE; -} + if (sd_pid_get_session (getpid (), &session_id) < 0) + return NULL; -static gboolean -send_message_to_wl (MetaLauncher *self, - void *message, - gsize size, - GSocketControlMessage *out_cmsg, - GSocketControlMessage **in_cmsg, - GError **error) -{ - struct weston_launcher_reply reply; - GInputVector in_iov = { &reply, sizeof (reply) }; - GOutputVector out_iov = { message, size }; - GSocketControlMessage *out_all_cmsg[2]; - GSocketControlMessage **in_all_cmsg; - int flags = 0; - int i; - - out_all_cmsg[0] = out_cmsg; - out_all_cmsg[1] = NULL; - if (g_socket_send_message (self->weston_launch, NULL, - &out_iov, 1, - out_all_cmsg, -1, - flags, NULL, error) != (gssize)size) - return FALSE; - - if (g_socket_receive_message (self->weston_launch, NULL, - &in_iov, 1, - &in_all_cmsg, NULL, - &flags, NULL, error) != sizeof (reply)) - return FALSE; + proxy_path = get_escaped_dbus_path ("/org/freedesktop/login1/session", session_id); - while (reply.header.opcode != ((struct weston_launcher_message*)message)->opcode) - { - guint id; - - /* There were events queued */ - g_assert ((reply.header.opcode & WESTON_LAUNCHER_EVENT) == WESTON_LAUNCHER_EVENT); - - /* This can never happen, because the only time mutter-launch can queue - this event is after confirming a VT switch, and we don't make requests - during that time. - - Note that getting this event would be really bad, because we would be - in the wrong loop/context. - */ - g_assert (reply.header.opcode != WESTON_LAUNCHER_SERVER_VT_ENTER); - - switch (reply.header.opcode) - { - case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH: - id = g_idle_add (request_vt_switch_idle, self); - g_source_set_name_by_id (id, "[mutter] request_vt_switch_idle"); - break; - - default: - g_assert_not_reached (); - } - - if (g_socket_receive_message (self->weston_launch, NULL, - &in_iov, 1, - NULL, NULL, - &flags, NULL, error) != sizeof (reply)) - return FALSE; - } + session_proxy = login1_session_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + "org.freedesktop.login1", + proxy_path, + cancellable, NULL); + free (proxy_path); - if (reply.ret != 0) - { - if (reply.ret == -1) - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Got failure from weston-launch"); - else - g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-reply.ret), - "Got failure from weston-launch: %s", strerror (-reply.ret)); - - for (i = 0; in_all_cmsg && in_all_cmsg[i]; i++) - g_object_unref (in_all_cmsg[i]); - g_free (in_all_cmsg); - - return FALSE; - } - - if (in_all_cmsg && in_all_cmsg[0]) - { - for (i = 1; in_all_cmsg[i]; i++) - g_object_unref (in_all_cmsg[i]); - *in_cmsg = in_all_cmsg[0]; - } - - g_free (in_all_cmsg); - return TRUE; + return session_proxy; } -static int -meta_launcher_open_device (MetaLauncher *self, - const char *name, - int flags, - GError **error) +static Login1Seat * +get_seat_proxy (GCancellable *cancellable) { - struct weston_launcher_open *message; - GSocketControlMessage *cmsg; - gboolean ok; - gsize size; - int *fds, n_fd; - int ret; - - size = sizeof (struct weston_launcher_open) + strlen (name) + 1; - message = g_malloc (size); - message->header.opcode = WESTON_LAUNCHER_OPEN; - message->flags = flags; - strcpy (message->path, name); - message->path[strlen(name)] = 0; - - ok = send_message_to_wl (self, message, size, NULL, &cmsg, error); - - if (ok) - { - g_assert (G_IS_UNIX_FD_MESSAGE (cmsg)); - - fds = g_unix_fd_message_steal_fds (G_UNIX_FD_MESSAGE (cmsg), &n_fd); - g_assert (n_fd == 1); - - ret = fds[0]; - g_free (fds); - g_object_unref (cmsg); - } - else - ret = -1; - - g_free (message); - return ret; + return login1_seat_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + "org.freedesktop.login1", + "/org/freedesktop/login1/seat/self", + cancellable, NULL); } /* QQQ RRR SSS */ @@ -228,107 +125,190 @@ session_pause (void) clutter_egl_freeze_master_clock (); } +static gboolean +take_device (Login1Session *session_proxy, + int dev_major, + int dev_minor, + int *out_fd, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + GVariant *fd_variant = NULL; + int fd = -1; + GUnixFDList *fd_list; + + if (!login1_session_call_take_device_sync (session_proxy, + dev_major, + dev_minor, + NULL, + &fd_variant, + NULL, /* paused */ + &fd_list, + cancellable, + error)) + goto out; + + fd = g_unix_fd_list_get (fd_list, g_variant_get_handle (fd_variant), error); + if (fd == -1) + goto out; + + *out_fd = fd; + ret = TRUE; + + out: + if (fd_variant) + g_variant_unref (fd_variant); + if (fd_list) + g_object_unref (fd_list); + return ret; +} + +static gboolean +get_device_info_from_path (const char *path, + int *out_major, + int *out_minor) +{ + gboolean ret = FALSE; + int r; + struct stat st; + + r = stat (path, &st); + if (r < 0) + goto out; + if (!S_ISCHR (st.st_mode)) + goto out; + + *out_major = major (st.st_rdev); + *out_minor = minor (st.st_rdev); + ret = TRUE; + + out: + return ret; +} + +static gboolean +get_device_info_from_fd (int fd, + int *out_major, + int *out_minor) +{ + gboolean ret = FALSE; + int r; + struct stat st; + + r = fstat (fd, &st); + if (r < 0) + goto out; + if (!S_ISCHR (st.st_mode)) + goto out; + + *out_major = major (st.st_rdev); + *out_minor = minor (st.st_rdev); + ret = TRUE; + + out: + return ret; +} + static int on_evdev_device_open (const char *path, int flags, gpointer user_data, GError **error) { - MetaLauncher *launcher = user_data; + MetaLauncher *self = user_data; + int fd; + int major, minor; + + if (!get_device_info_from_path (path, &major, &minor)) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "Could not get device info for path %s: %m", path); + return -1; + } + + if (!take_device (self->session_proxy, major, minor, &fd, NULL, error)) + return -1; - return meta_launcher_open_device (launcher, path, flags, error); + return fd; } static void on_evdev_device_close (int fd, gpointer user_data) { - close (fd); + MetaLauncher *self = user_data; + int major, minor; + GError *error = NULL; + + if (!get_device_info_from_fd (fd, &major, &minor)) + { + g_warning ("Could not get device info for fd %d: %m", fd); + return; + } + + if (!login1_session_call_release_device_sync (self->session_proxy, + major, minor, + NULL, &error)) + { + g_warning ("Could not release device %d,%d: %s", major, minor, error->message); + } } /* TTT UUU VVV */ static void -handle_vt_enter (MetaLauncher *launcher) +sync_active (MetaLauncher *self) { - g_assert (launcher->vt_switched); - launcher->vt_switched = FALSE; + gboolean active = login1_session_get_active (LOGIN1_SESSION (self->session_proxy)); + + if (active == self->session_active) + return; - session_unpause (); + self->session_active = active; + + if (active) + session_unpause (); + else + session_pause (); } static void -handle_request_vt_switch (MetaLauncher *launcher) +on_active_changed (Login1Session *session, + GParamSpec *pspec, + gpointer user_data) { - struct weston_launcher_message message; - GError *error; - gboolean ok; - - session_pause (); - - message.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH; - - error = NULL; - ok = send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, &error); - if (!ok) { - g_warning ("Failed to acknowledge VT switch: %s", error->message); - g_error_free (error); - return; - } - - g_assert (!launcher->vt_switched); - launcher->vt_switched = TRUE; - - session_unpause (); + MetaLauncher *self = user_data; + sync_active (self); } static gboolean -on_socket_readable (GSocket *socket, - GIOCondition condition, - gpointer user_data) +get_kms_fd (Login1Session *session_proxy, + int *fd_out) { - MetaLauncher *launcher = user_data; - struct weston_launcher_event event; - gssize read; - GError *error; - - if ((condition & G_IO_IN) == 0) - return TRUE; + int major, minor; + int fd; + GError *error = NULL; - error = NULL; - read = g_socket_receive (socket, (char*)&event, sizeof(event), NULL, &error); - if (read < (gssize)sizeof(event)) + /* XXX -- use udev to find the DRM master device */ + if (!get_device_info_from_path ("/dev/dri/card0", &major, &minor)) { - g_warning ("Error reading from weston-launcher socket: %s", error->message); - g_error_free (error); - return TRUE; + g_warning ("Could not stat /dev/dri/card0: %m"); + return FALSE; } - switch (event.header.opcode) + if (!take_device (session_proxy, major, minor, &fd, NULL, &error)) { - case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH: - handle_request_vt_switch (launcher); - break; - - case WESTON_LAUNCHER_SERVER_VT_ENTER: - handle_vt_enter (launcher); - break; + g_warning ("Could not open DRM device: %s\n", error->message); + g_error_free (error); + return FALSE; } - return TRUE; -} - -static int -env_get_fd (const char *env) -{ - const char *value; - - value = g_getenv (env); + *fd_out = fd; - if (value == NULL) - return -1; - else - return g_ascii_strtoll (value, NULL, 10); + return TRUE; } /* XXX YYY ZZZ */ @@ -336,47 +316,55 @@ env_get_fd (const char *env) MetaLauncher * meta_launcher_new (void) { - MetaLauncher *self = g_slice_new0 (MetaLauncher); + MetaLauncher *self; + Login1Session *session_proxy; GError *error = NULL; - int launch_fd; int kms_fd; - launch_fd = env_get_fd ("WESTON_LAUNCHER_SOCK"); - if (launch_fd < 0) - g_error ("Invalid mutter-launch socket"); + session_proxy = get_session_proxy (NULL); + if (!login1_session_call_take_control_sync (session_proxy, FALSE, NULL, &error)) + { + g_warning ("Could not take control: %s", error->message); + g_error_free (error); + return NULL; + } - self->weston_launch = g_socket_new_from_fd (launch_fd, NULL); + if (!get_kms_fd (session_proxy, &kms_fd)) + return NULL; - self->weston_launch_source = g_socket_create_source (self->weston_launch, G_IO_IN, NULL); - g_source_set_callback (self->weston_launch_source, (GSourceFunc)on_socket_readable, self, NULL); - g_source_attach (self->weston_launch_source, NULL); - g_source_unref (self->weston_launch_source); + self = g_slice_new0 (MetaLauncher); + self->session_proxy = session_proxy; + self->seat_proxy = get_seat_proxy (NULL); - kms_fd = meta_launcher_open_device (self, "/dev/dri/card0", O_RDWR, &error); - if (error) - g_error ("Failed to open /dev/dri/card0: %s", error->message); + self->session_active = TRUE; clutter_egl_set_kms_fd (kms_fd); clutter_evdev_set_device_callbacks (on_evdev_device_open, on_evdev_device_close, self); + g_signal_connect (self->session_proxy, "notify::active", G_CALLBACK (on_active_changed), self); + return self; } void -meta_launcher_free (MetaLauncher *launcher) +meta_launcher_free (MetaLauncher *self) { - g_source_destroy (launcher->weston_launch_source); - g_object_unref (launcher->weston_launch); - g_slice_free (MetaLauncher, launcher); + g_object_unref (self->seat_proxy); + g_object_unref (self->session_proxy); + g_slice_free (MetaLauncher, self); } gboolean meta_launcher_activate_session (MetaLauncher *launcher, GError **error) { - return meta_launcher_activate_vt (launcher, -1, error); + if (!login1_session_call_activate_sync (launcher->session_proxy, NULL, error)) + return FALSE; + + sync_active (launcher); + return TRUE; } gboolean @@ -384,10 +372,5 @@ meta_launcher_activate_vt (MetaLauncher *launcher, signed char vt, GError **error) { - struct weston_launcher_activate_vt message; - - message.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT; - message.vt = vt; - - return send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, error); + return login1_seat_call_switch_to_sync (launcher->seat_proxy, vt, NULL, error); } |