mirror of
https://github.com/brl/mutter.git
synced 2024-11-12 17:27:03 -05:00
wayland: add TTY and DRM master management
Now that we have a setuid launcher binary, we can make use of using a private protocol through the socket we're passed at startup. We also use the new hook in clutter-evdev to ask mutter-launch for the FDs of the input devices we need, and we emulate the old X DRM lock with a nested GMainContext without sources. In the future, mutter-launch will be replaced with the new logind API currently in development. https://bugzilla.gnome.org/show_bug.cgi?id=705861
This commit is contained in:
parent
96fa518576
commit
e72f81c24f
@ -232,7 +232,7 @@ AS_IF([test "x$WAYLAND_SCANNER" = "xno"],
|
||||
AC_SUBST([WAYLAND_SCANNER])
|
||||
AC_SUBST(XWAYLAND_PATH)
|
||||
|
||||
MUTTER_PC_MODULES="$MUTTER_PC_MODULES wayland-server"
|
||||
MUTTER_PC_MODULES="$MUTTER_PC_MODULES wayland-server libdrm"
|
||||
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
|
||||
|
||||
PKG_CHECK_EXISTS([xi >= 1.6.99.1],
|
||||
|
@ -195,7 +195,9 @@ libmutter_wayland_la_SOURCES += \
|
||||
wayland/meta-wayland-seat.c \
|
||||
wayland/meta-wayland-seat.h \
|
||||
wayland/meta-wayland-stage.h \
|
||||
wayland/meta-wayland-stage.c
|
||||
wayland/meta-wayland-stage.c \
|
||||
wayland/meta-weston-launch.c \
|
||||
wayland/meta-weston-launch.h
|
||||
|
||||
libmutter_wayland_la_LDFLAGS = -no-undefined
|
||||
libmutter_wayland_la_LIBADD = $(MUTTER_LIBS)
|
||||
|
@ -58,6 +58,7 @@
|
||||
#include "meta-wayland-private.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <glib-unix.h>
|
||||
#include <gdk/gdkx.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
@ -352,59 +353,12 @@ meta_finalize (void)
|
||||
meta_wayland_finalize ();
|
||||
}
|
||||
|
||||
static int signal_pipe_fds[2] = { -1, -1 };
|
||||
|
||||
static void
|
||||
signal_handler (int signum)
|
||||
{
|
||||
if (signal_pipe_fds[1] >= 0)
|
||||
{
|
||||
switch (signum)
|
||||
{
|
||||
case SIGTERM:
|
||||
write (signal_pipe_fds[1], "T", 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_signal (GIOChannel *source,
|
||||
GIOCondition condition,
|
||||
void *data)
|
||||
on_sigterm (gpointer user_data)
|
||||
{
|
||||
char signal;
|
||||
int count;
|
||||
meta_quit (EXIT_SUCCESS);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
count = read (signal_pipe_fds[0], &signal, 1);
|
||||
if (count == EINTR)
|
||||
continue;
|
||||
if (count < 0)
|
||||
{
|
||||
const char *msg = strerror (errno);
|
||||
g_warning ("Error handling signal: %s", msg);
|
||||
}
|
||||
if (count != 1)
|
||||
{
|
||||
g_warning ("Unexpectedly failed to read byte from signal pipe\n");
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch (signal)
|
||||
{
|
||||
case 'T': /* SIGTERM */
|
||||
meta_quit (META_EXIT_SUCCESS);
|
||||
break;
|
||||
default:
|
||||
g_warning ("Spurious character '%c' read from signal pipe", signal);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -418,7 +372,6 @@ meta_init (void)
|
||||
{
|
||||
struct sigaction act;
|
||||
sigset_t empty_mask;
|
||||
GIOChannel *channel;
|
||||
|
||||
sigemptyset (&empty_mask);
|
||||
act.sa_handler = SIG_IGN;
|
||||
@ -433,20 +386,7 @@ meta_init (void)
|
||||
g_strerror (errno));
|
||||
#endif
|
||||
|
||||
if (pipe (signal_pipe_fds) != 0)
|
||||
g_printerr ("Failed to create signal pipe: %s\n",
|
||||
g_strerror (errno));
|
||||
|
||||
channel = g_io_channel_unix_new (signal_pipe_fds[0]);
|
||||
g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL);
|
||||
g_io_add_watch (channel, G_IO_IN, (GIOFunc) on_signal, NULL);
|
||||
g_io_channel_set_close_on_unref (channel, TRUE);
|
||||
g_io_channel_unref (channel);
|
||||
|
||||
act.sa_handler = &signal_handler;
|
||||
if (sigaction (SIGTERM, &act, NULL) < 0)
|
||||
g_printerr ("Failed to register SIGTERM handler: %s\n",
|
||||
g_strerror (errno));
|
||||
g_unix_signal_add (SIGTERM, on_sigterm, NULL);
|
||||
|
||||
if (g_getenv ("MUTTER_VERBOSE"))
|
||||
meta_set_verbose (TRUE);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <cairo.h>
|
||||
|
||||
#include "window-private.h"
|
||||
#include "meta-weston-launch.h"
|
||||
#include <meta/meta-cursor-tracker.h>
|
||||
|
||||
typedef struct _MetaWaylandCompositor MetaWaylandCompositor;
|
||||
@ -140,6 +141,9 @@ struct _MetaWaylandCompositor
|
||||
struct wl_client *xwayland_client;
|
||||
struct wl_resource *xserver_resource;
|
||||
|
||||
MetaLauncher *launcher;
|
||||
int drm_fd;
|
||||
|
||||
MetaWaylandSeat *seat;
|
||||
|
||||
/* This surface is only used to keep drag of the implicit grab when
|
||||
@ -330,6 +334,8 @@ void meta_wayland_compositor_repick (MetaWaylandComp
|
||||
void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
|
||||
MetaWindow *window);
|
||||
|
||||
MetaLauncher *meta_wayland_compositor_get_launcher (MetaWaylandCompositor *compositor);
|
||||
|
||||
void meta_wayland_surface_free (MetaWaylandSurface *surface);
|
||||
|
||||
#endif /* META_WAYLAND_PRIVATE_H */
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include <meta/main.h>
|
||||
#include "frame.h"
|
||||
#include "meta-idle-monitor-private.h"
|
||||
#include "meta-weston-launch.h"
|
||||
#include "monitor-private.h"
|
||||
|
||||
static MetaWaylandCompositor _meta_wayland_compositor;
|
||||
@ -1545,6 +1546,9 @@ meta_wayland_init (void)
|
||||
MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
|
||||
guint event_signal;
|
||||
MetaMonitorManager *monitors;
|
||||
ClutterBackend *backend;
|
||||
CoglContext *cogl_context;
|
||||
CoglRenderer *cogl_renderer;
|
||||
|
||||
memset (compositor, 0, sizeof (MetaWaylandCompositor));
|
||||
|
||||
@ -1581,9 +1585,33 @@ meta_wayland_init (void)
|
||||
|
||||
clutter_wayland_set_compositor_display (compositor->wayland_display);
|
||||
|
||||
if (getenv ("WESTON_LAUNCHER_SOCK"))
|
||||
compositor->launcher = meta_launcher_new ();
|
||||
|
||||
if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
|
||||
g_error ("Failed to initialize Clutter");
|
||||
|
||||
backend = clutter_get_default_backend ();
|
||||
cogl_context = clutter_backend_get_cogl_context (backend);
|
||||
cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (cogl_context));
|
||||
|
||||
if (cogl_renderer_get_winsys_id (cogl_renderer) == COGL_WINSYS_ID_EGL_KMS)
|
||||
compositor->drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
|
||||
else
|
||||
compositor->drm_fd = -1;
|
||||
|
||||
if (compositor->drm_fd >= 0)
|
||||
{
|
||||
GError *error;
|
||||
|
||||
error = NULL;
|
||||
if (!meta_launcher_set_drm_fd (compositor->launcher, compositor->drm_fd, &error))
|
||||
{
|
||||
g_error ("Failed to set DRM fd to weston-launch and become DRM master: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
meta_monitor_manager_initialize ();
|
||||
monitors = meta_monitor_manager_get ();
|
||||
g_signal_connect (monitors, "monitors-changed",
|
||||
@ -1646,5 +1674,16 @@ meta_wayland_init (void)
|
||||
void
|
||||
meta_wayland_finalize (void)
|
||||
{
|
||||
meta_xwayland_stop (meta_wayland_compositor_get_default ());
|
||||
MetaWaylandCompositor *compositor;
|
||||
|
||||
compositor = meta_wayland_compositor_get_default ();
|
||||
|
||||
meta_xwayland_stop (compositor);
|
||||
g_clear_object (&compositor->launcher);
|
||||
}
|
||||
|
||||
MetaLauncher *
|
||||
meta_wayland_compositor_get_launcher (MetaWaylandCompositor *compositor)
|
||||
{
|
||||
return compositor->launcher;
|
||||
}
|
||||
|
453
src/wayland/meta-weston-launch.c
Normal file
453
src/wayland/meta-weston-launch.c
Normal file
@ -0,0 +1,453 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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 <gio/gio.h>
|
||||
#include <gio/gunixfdmessage.h>
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <clutter/evdev/clutter-evdev.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <sys/time.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <drm.h>
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
|
||||
#include "meta-weston-launch.h"
|
||||
|
||||
struct _MetaLauncherClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (*enter) (MetaLauncher *);
|
||||
void (*leave) (MetaLauncher *);
|
||||
};
|
||||
|
||||
struct _MetaLauncher
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
GSocket *weston_launch;
|
||||
|
||||
gboolean vt_switched;
|
||||
|
||||
GMainContext *nested_context;
|
||||
GMainLoop *nested_loop;
|
||||
|
||||
GSource *inner_source;
|
||||
GSource *outer_source;
|
||||
};
|
||||
|
||||
enum {
|
||||
SIGNAL_ENTER,
|
||||
SIGNAL_LEAVE,
|
||||
SIGNAL_LAST
|
||||
};
|
||||
|
||||
static int signals[SIGNAL_LAST];
|
||||
|
||||
G_DEFINE_TYPE (MetaLauncher, meta_launcher, G_TYPE_OBJECT);
|
||||
|
||||
static void handle_request_vt_switch (MetaLauncher *self);
|
||||
|
||||
static gboolean
|
||||
request_vt_switch_idle (gpointer user_data)
|
||||
{
|
||||
handle_request_vt_switch (user_data);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
while (reply.header.opcode != ((struct weston_launcher_message*)message)->opcode)
|
||||
{
|
||||
/* 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:
|
||||
g_idle_add (request_vt_switch_idle, self);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_launcher_set_drm_fd (MetaLauncher *self,
|
||||
int drm_fd,
|
||||
GError **error)
|
||||
{
|
||||
struct weston_launcher_message message;
|
||||
GSocketControlMessage *cmsg;
|
||||
gboolean ok;
|
||||
|
||||
message.opcode = WESTON_LAUNCHER_DRM_SET_FD;
|
||||
|
||||
cmsg = g_unix_fd_message_new ();
|
||||
if (g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (cmsg),
|
||||
drm_fd, error) == FALSE)
|
||||
{
|
||||
g_object_unref (cmsg);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = send_message_to_wl (self, &message, sizeof message, cmsg, NULL, error);
|
||||
|
||||
g_object_unref (cmsg);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int
|
||||
meta_launcher_open_input_device (MetaLauncher *self,
|
||||
const char *name,
|
||||
int flags,
|
||||
GError **error)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_launcher_finalize (GObject *object)
|
||||
{
|
||||
MetaLauncher *launcher = META_LAUNCHER (object);
|
||||
|
||||
g_source_destroy (launcher->outer_source);
|
||||
g_source_destroy (launcher->inner_source);
|
||||
|
||||
g_main_loop_unref (launcher->nested_loop);
|
||||
g_main_context_unref (launcher->nested_context);
|
||||
|
||||
g_object_unref (launcher->weston_launch);
|
||||
|
||||
G_OBJECT_CLASS (meta_launcher_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_launcher_enter (MetaLauncher *launcher)
|
||||
{
|
||||
ClutterBackend *backend;
|
||||
CoglContext *cogl_context;
|
||||
CoglDisplay *cogl_display;
|
||||
|
||||
backend = clutter_get_default_backend ();
|
||||
cogl_context = clutter_backend_get_cogl_context (backend);
|
||||
cogl_display = cogl_context_get_display (cogl_context);
|
||||
cogl_kms_display_queue_modes_reset (cogl_display);
|
||||
|
||||
clutter_evdev_reclaim_devices ();
|
||||
}
|
||||
|
||||
static void
|
||||
meta_launcher_leave (MetaLauncher *launcher)
|
||||
{
|
||||
clutter_evdev_release_devices ();
|
||||
}
|
||||
|
||||
static int
|
||||
on_evdev_device_open (const char *path,
|
||||
int flags,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
MetaLauncher *launcher = user_data;
|
||||
|
||||
return meta_launcher_open_input_device (launcher, path, flags, error);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_vt_enter (MetaLauncher *launcher)
|
||||
{
|
||||
g_assert (launcher->vt_switched);
|
||||
|
||||
g_main_loop_quit (launcher->nested_loop);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_request_vt_switch (MetaLauncher *launcher)
|
||||
{
|
||||
struct weston_launcher_message message;
|
||||
GError *error;
|
||||
gboolean ok;
|
||||
|
||||
g_signal_emit (launcher, signals[SIGNAL_LEAVE], 0);
|
||||
|
||||
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;
|
||||
|
||||
/* We can't do anything at this point, because we don't
|
||||
have input devices and we don't have the DRM master,
|
||||
so let's run a nested busy loop until the VT is reentered */
|
||||
g_main_loop_run (launcher->nested_loop);
|
||||
|
||||
g_assert (launcher->vt_switched);
|
||||
launcher->vt_switched = FALSE;
|
||||
|
||||
g_signal_emit (launcher, signals[SIGNAL_ENTER], 0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_socket_readable (GSocket *socket,
|
||||
GIOCondition condition,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaLauncher *launcher = user_data;
|
||||
struct weston_launcher_event event;
|
||||
gssize read;
|
||||
GError *error;
|
||||
|
||||
if ((condition & G_IO_IN) == 0)
|
||||
return TRUE;
|
||||
|
||||
error = NULL;
|
||||
read = g_socket_receive (socket, (char*)&event, sizeof(event), NULL, &error);
|
||||
if (read < (gssize)sizeof(event))
|
||||
{
|
||||
g_warning ("Error reading from weston-launcher socket: %s", error->message);
|
||||
g_error_free (error);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
switch (event.header.opcode)
|
||||
{
|
||||
case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH:
|
||||
handle_request_vt_switch (launcher);
|
||||
break;
|
||||
|
||||
case WESTON_LAUNCHER_SERVER_VT_ENTER:
|
||||
handle_vt_enter (launcher);
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
env_get_fd (const char *env)
|
||||
{
|
||||
const char *value;
|
||||
|
||||
value = g_getenv (env);
|
||||
|
||||
if (value == NULL)
|
||||
return -1;
|
||||
else
|
||||
return g_ascii_strtoll (value, NULL, 10);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_launcher_init (MetaLauncher *self)
|
||||
{
|
||||
int launch_fd;
|
||||
|
||||
launch_fd = env_get_fd ("WESTON_LAUNCHER_SOCK");
|
||||
if (launch_fd < 0)
|
||||
g_error ("Invalid mutter-launch socket");
|
||||
|
||||
self->weston_launch = g_socket_new_from_fd (launch_fd, NULL);
|
||||
|
||||
clutter_evdev_set_open_callback (on_evdev_device_open, self);
|
||||
|
||||
self->nested_context = g_main_context_new ();
|
||||
self->nested_loop = g_main_loop_new (self->nested_context, FALSE);
|
||||
|
||||
self->outer_source = g_socket_create_source (self->weston_launch, G_IO_IN, NULL);
|
||||
g_source_set_callback (self->outer_source, (GSourceFunc)on_socket_readable, self, NULL);
|
||||
g_source_attach (self->outer_source, NULL);
|
||||
g_source_unref (self->outer_source);
|
||||
|
||||
self->inner_source = g_socket_create_source (self->weston_launch, G_IO_IN, NULL);
|
||||
g_source_set_callback (self->inner_source, (GSourceFunc)on_socket_readable, self, NULL);
|
||||
g_source_attach (self->inner_source, self->nested_context);
|
||||
g_source_unref (self->inner_source);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_launcher_class_init (MetaLauncherClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_launcher_finalize;
|
||||
|
||||
klass->enter = meta_launcher_enter;
|
||||
klass->leave = meta_launcher_leave;
|
||||
|
||||
signals[SIGNAL_ENTER] = g_signal_new ("enter",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (MetaLauncherClass, enter),
|
||||
NULL, NULL, /* accumulator */
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
signals[SIGNAL_LEAVE] = g_signal_new ("leave",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (MetaLauncherClass, leave),
|
||||
NULL, NULL, /* accumulator */
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
MetaLauncher *
|
||||
meta_launcher_new (void)
|
||||
{
|
||||
return g_object_new (META_TYPE_LAUNCHER, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_launcher_activate_vt (MetaLauncher *launcher,
|
||||
int 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);
|
||||
}
|
||||
|
55
src/wayland/meta-weston-launch.h
Normal file
55
src/wayland/meta-weston-launch.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.
|
||||
*/
|
||||
|
||||
#ifndef META_WESTON_LAUNCH_H
|
||||
#define META_WESTON_LAUNCH_H
|
||||
|
||||
#include <glib-object.h>
|
||||
#include "weston-launch.h"
|
||||
|
||||
#define META_TYPE_LAUNCHER (meta_launcher_get_type())
|
||||
#define META_LAUNCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_LAUNCHER, MetaLauncher))
|
||||
#define META_LAUNCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_LAUNCHER, MetaLauncherClass))
|
||||
#define META_IS_LAUNCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_LAUNCHER))
|
||||
#define META_IS_LAUNCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_LAUNCHER))
|
||||
#define META_LAUNCHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_LAUNCHER, MetaLauncherClass))
|
||||
|
||||
typedef struct _MetaLauncher MetaLauncher;
|
||||
typedef struct _MetaLauncherClass MetaLauncherClass;
|
||||
|
||||
GType meta_launcher_get_type (void) G_GNUC_CONST;
|
||||
|
||||
MetaLauncher *meta_launcher_new (void);
|
||||
|
||||
gboolean meta_launcher_activate_vt (MetaLauncher *self,
|
||||
int number,
|
||||
GError **error);
|
||||
|
||||
gboolean meta_launcher_set_drm_fd (MetaLauncher *self,
|
||||
int drm_fd,
|
||||
GError **error);
|
||||
gboolean meta_launcher_set_master (MetaLauncher *self,
|
||||
gboolean master,
|
||||
GError **error);
|
||||
int meta_launcher_open_input_device (MetaLauncher *self,
|
||||
const char *name,
|
||||
int flags,
|
||||
GError **error);
|
||||
|
||||
#endif
|
@ -171,14 +171,17 @@ setenv_fd(const char *env, int fd)
|
||||
static int
|
||||
handle_setdrmfd(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
|
||||
{
|
||||
int ret = -1;
|
||||
struct weston_launcher_reply reply;
|
||||
struct cmsghdr *cmsg;
|
||||
union cmsg_data *data;
|
||||
struct stat s;
|
||||
|
||||
reply.header.opcode = WESTON_LAUNCHER_DRM_SET_FD;
|
||||
reply.ret = -1;
|
||||
|
||||
if (wl->drm_fd != -1) {
|
||||
error(0, 0, "DRM FD already set");
|
||||
ret = -EINVAL;
|
||||
reply.ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -187,40 +190,40 @@ handle_setdrmfd(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
|
||||
cmsg->cmsg_level != SOL_SOCKET ||
|
||||
cmsg->cmsg_type != SCM_RIGHTS) {
|
||||
error(0, 0, "invalid control message");
|
||||
ret = -EINVAL;
|
||||
reply.ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
data = (union cmsg_data *) CMSG_DATA(cmsg);
|
||||
if (data->fd < 0) {
|
||||
error(0, 0, "missing drm fd in socket request");
|
||||
ret = -EINVAL;
|
||||
reply.ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fstat(data->fd, &s) < 0) {
|
||||
ret = -errno;
|
||||
reply.ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (major(s.st_rdev) != DRM_MAJOR) {
|
||||
fprintf(stderr, "FD is not for DRM\n");
|
||||
ret = -EPERM;
|
||||
reply.ret = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl->drm_fd = data->fd;
|
||||
ret = drmSetMaster(data->fd);
|
||||
if (ret < 0)
|
||||
ret = -errno;
|
||||
reply.ret = drmSetMaster(data->fd);
|
||||
if (reply.ret < 0)
|
||||
reply.ret = -errno;
|
||||
|
||||
if (wl->verbose)
|
||||
fprintf(stderr, "weston-launch: set drm FD, ret: %d, fd: %d\n",
|
||||
ret, data->fd);
|
||||
reply.ret, data->fd);
|
||||
|
||||
out:
|
||||
do {
|
||||
len = send(wl->sock[0], &ret, sizeof ret, 0);
|
||||
len = send(wl->sock[0], &reply, sizeof reply, 0);
|
||||
} while (len < 0 && errno == EINTR);
|
||||
if (len < 0)
|
||||
return -1;
|
||||
@ -231,7 +234,10 @@ out:
|
||||
static int
|
||||
handle_confirm_vt_switch(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
|
||||
{
|
||||
int ret = -1;
|
||||
struct weston_launcher_reply reply;
|
||||
|
||||
reply.header.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH;
|
||||
reply.ret = -1;
|
||||
|
||||
if (wl->vt_state != VT_PENDING_CONFIRM) {
|
||||
error(0, 0, "unexpected CONFIRM_VT_SWITCH");
|
||||
@ -255,11 +261,11 @@ handle_confirm_vt_switch(struct weston_launch *wl, struct msghdr *msg, ssize_t l
|
||||
if (wl->verbose)
|
||||
fprintf(stderr, "weston-launcher: confirmed VT switch\n");
|
||||
|
||||
ret = 0;
|
||||
reply.ret = 0;
|
||||
|
||||
out:
|
||||
do {
|
||||
len = send(wl->sock[0], &ret, sizeof ret, 0);
|
||||
len = send(wl->sock[0], &reply, sizeof reply, 0);
|
||||
} while (len < 0 && errno == EINTR);
|
||||
if (len < 0)
|
||||
return -1;
|
||||
@ -270,9 +276,12 @@ out:
|
||||
static int
|
||||
handle_activate_vt(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
|
||||
{
|
||||
int ret = -1;
|
||||
struct weston_launcher_reply reply;
|
||||
struct weston_launcher_activate_vt *message;
|
||||
|
||||
reply.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT;
|
||||
reply.ret = -1;
|
||||
|
||||
if (len != sizeof(*message)) {
|
||||
error(0, 0, "missing value in activate_vt request");
|
||||
goto out;
|
||||
@ -280,16 +289,16 @@ handle_activate_vt(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
|
||||
|
||||
message = msg->msg_iov->iov_base;
|
||||
|
||||
ret = ioctl(wl->tty, VT_ACTIVATE, message->vt);
|
||||
if (ret < 0)
|
||||
ret = -errno;
|
||||
reply.ret = ioctl(wl->tty, VT_ACTIVATE, message->vt);
|
||||
if (reply.ret < 0)
|
||||
reply.ret = -errno;
|
||||
|
||||
if (wl->verbose)
|
||||
fprintf(stderr, "weston-launch: activate VT, ret: %d\n", ret);
|
||||
fprintf(stderr, "weston-launch: activate VT, ret: %d\n", reply.ret);
|
||||
|
||||
out:
|
||||
do {
|
||||
len = send(wl->sock[0], &ret, sizeof ret, 0);
|
||||
len = send(wl->sock[0], &reply, sizeof reply, 0);
|
||||
} while (len < 0 && errno == EINTR);
|
||||
if (len < 0)
|
||||
return -1;
|
||||
@ -301,7 +310,8 @@ out:
|
||||
static int
|
||||
handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
|
||||
{
|
||||
int fd = -1, ret = -1;
|
||||
struct weston_launcher_reply reply;
|
||||
int fd = -1;
|
||||
char control[CMSG_SPACE(sizeof(fd))];
|
||||
struct cmsghdr *cmsg;
|
||||
struct stat s;
|
||||
@ -310,6 +320,9 @@ handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
|
||||
struct weston_launcher_open *message;
|
||||
union cmsg_data *data;
|
||||
|
||||
reply.header.opcode = WESTON_LAUNCHER_OPEN;
|
||||
reply.ret = -1;
|
||||
|
||||
message = msg->msg_iov->iov_base;
|
||||
if ((size_t)len < sizeof(*message))
|
||||
goto err0;
|
||||
@ -318,7 +331,7 @@ handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
|
||||
((char *) message)[len-1] = '\0';
|
||||
|
||||
if (stat(message->path, &s) < 0) {
|
||||
ret = -errno;
|
||||
reply.ret = -errno;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
@ -326,7 +339,7 @@ handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Error opening device %s: %m\n",
|
||||
message->path);
|
||||
ret = -errno;
|
||||
reply.ret = -errno;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
@ -335,7 +348,7 @@ handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
|
||||
fd = -1;
|
||||
fprintf(stderr, "Device %s is not an input device\n",
|
||||
message->path);
|
||||
ret = -EPERM;
|
||||
reply.ret = -EPERM;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
@ -353,14 +366,14 @@ err0:
|
||||
data = (union cmsg_data *) CMSG_DATA(cmsg);
|
||||
data->fd = fd;
|
||||
nmsg.msg_controllen = cmsg->cmsg_len;
|
||||
ret = 0;
|
||||
reply.ret = 0;
|
||||
}
|
||||
iov.iov_base = &ret;
|
||||
iov.iov_len = sizeof ret;
|
||||
iov.iov_base = &reply;
|
||||
iov.iov_len = sizeof reply;
|
||||
|
||||
if (wl->verbose)
|
||||
fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
|
||||
message->path, ret, fd);
|
||||
message->path, reply.ret, fd);
|
||||
do {
|
||||
len = sendmsg(wl->sock[0], &nmsg, 0);
|
||||
} while (len < 0 && errno == EINTR);
|
||||
@ -467,12 +480,12 @@ quit(struct weston_launch *wl, int status)
|
||||
static int
|
||||
handle_vt_switch(struct weston_launch *wl)
|
||||
{
|
||||
struct weston_launcher_message message;
|
||||
struct weston_launcher_event message;
|
||||
ssize_t len;
|
||||
|
||||
if (wl->vt_state == VT_HAS_VT) {
|
||||
wl->vt_state = VT_PENDING_CONFIRM;
|
||||
message.opcode = WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH;
|
||||
message.header.opcode = WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH;
|
||||
} else if (wl->vt_state == VT_NOT_HAVE_VT) {
|
||||
wl->vt_state = VT_HAS_VT;
|
||||
ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
|
||||
@ -490,10 +503,12 @@ handle_vt_switch(struct weston_launch *wl)
|
||||
}
|
||||
}
|
||||
|
||||
message.opcode = WESTON_LAUNCHER_SERVER_VT_ENTER;
|
||||
message.header.opcode = WESTON_LAUNCHER_SERVER_VT_ENTER;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
message.detail = 0;
|
||||
|
||||
do {
|
||||
len = send(wl->sock[0], &message, sizeof(message), 0);
|
||||
} while (len < 0 && errno == EINTR);
|
||||
|
@ -24,16 +24,21 @@
|
||||
#ifndef _WESTON_LAUNCH_H_
|
||||
#define _WESTON_LAUNCH_H_
|
||||
|
||||
enum weston_launcher_message_type {
|
||||
WESTON_LAUNCHER_REQUEST,
|
||||
WESTON_LAUNCHER_EVENT,
|
||||
};
|
||||
|
||||
enum weston_launcher_opcode {
|
||||
WESTON_LAUNCHER_OPEN,
|
||||
WESTON_LAUNCHER_DRM_SET_FD,
|
||||
WESTON_LAUNCHER_ACTIVATE_VT,
|
||||
WESTON_LAUNCHER_CONFIRM_VT_SWITCH,
|
||||
WESTON_LAUNCHER_OPEN = (1 << 1 | WESTON_LAUNCHER_REQUEST),
|
||||
WESTON_LAUNCHER_DRM_SET_FD = (2 << 1 | WESTON_LAUNCHER_REQUEST),
|
||||
WESTON_LAUNCHER_ACTIVATE_VT = (3 << 1 | WESTON_LAUNCHER_REQUEST),
|
||||
WESTON_LAUNCHER_CONFIRM_VT_SWITCH = (4 << 1 | WESTON_LAUNCHER_REQUEST),
|
||||
};
|
||||
|
||||
enum weston_launcher_server_opcode {
|
||||
WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH,
|
||||
WESTON_LAUNCHER_SERVER_VT_ENTER,
|
||||
WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH = (1 << 1 | WESTON_LAUNCHER_EVENT),
|
||||
WESTON_LAUNCHER_SERVER_VT_ENTER = (2 << 1 | WESTON_LAUNCHER_EVENT),
|
||||
};
|
||||
|
||||
struct weston_launcher_message {
|
||||
@ -51,4 +56,14 @@ struct weston_launcher_activate_vt {
|
||||
int vt;
|
||||
};
|
||||
|
||||
struct weston_launcher_reply {
|
||||
struct weston_launcher_message header;
|
||||
int ret;
|
||||
};
|
||||
|
||||
struct weston_launcher_event {
|
||||
struct weston_launcher_message header;
|
||||
int detail; /* unused, but makes sure replies and events are serialized the same */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user