[mutter/wayland] wayland: add TTY and DRM master management



commit e72f81c24f58a3ab5158f503c55f76d60ab7c933
Author: Giovanni Campagna <gcampagn redhat com>
Date:   Mon Aug 19 14:57:16 2013 +0200

    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

 configure.ac                       |    2 +-
 src/Makefile.am                    |    4 +-
 src/core/main.c                    |   70 +-----
 src/wayland/meta-wayland-private.h |    6 +
 src/wayland/meta-wayland.c         |   41 ++++-
 src/wayland/meta-weston-launch.c   |  453 ++++++++++++++++++++++++++++++++++++
 src/wayland/meta-weston-launch.h   |   55 +++++
 src/wayland/weston-launch.c        |   77 ++++---
 src/wayland/weston-launch.h        |   27 ++-
 9 files changed, 630 insertions(+), 105 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 415ca5d..efd8fb8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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],
diff --git a/src/Makefile.am b/src/Makefile.am
index 4fc7c58..462e8a8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -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)
diff --git a/src/core/main.c b/src/core/main.c
index c4620a1..5f1f4da 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -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);
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
index e470dfa..2c51a7d 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -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 */
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 267a536..c4f5e0b 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -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;
 }
diff --git a/src/wayland/meta-weston-launch.c b/src/wayland/meta-weston-launch.c
new file mode 100644
index 0000000..709eacc
--- /dev/null
+++ b/src/wayland/meta-weston-launch.c
@@ -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);
+}
+
diff --git a/src/wayland/meta-weston-launch.h b/src/wayland/meta-weston-launch.h
new file mode 100644
index 0000000..19d3756
--- /dev/null
+++ b/src/wayland/meta-weston-launch.h
@@ -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
diff --git a/src/wayland/weston-launch.c b/src/wayland/weston-launch.c
index 1efff30..71c7530 100644
--- a/src/wayland/weston-launch.c
+++ b/src/wayland/weston-launch.c
@@ -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);
diff --git a/src/wayland/weston-launch.h b/src/wayland/weston-launch.h
index 092a476..74e6c3b 100644
--- a/src/wayland/weston-launch.h
+++ b/src/wayland/weston-launch.h
@@ -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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]