[mutter/wip/wayland-display: 3/17] wayland: add TTY and DRM master management through weston-launch



commit 76c2c809640cd2fb1d1c4ba0bed2a9ebaa4df45e
Author: Giovanni Campagna <gcampagn redhat com>
Date:   Mon Jul 15 18:07:01 2013 +0200

    wayland: add TTY and DRM master management through weston-launch
    
    To run mutter as a display server, one needs to acquire and
    release the DRM master, which is only possible for root, so
    we take advantage of weston-launch, a small setuid helper binary
    written for the weston project.

 configure.ac                       |    2 +-
 src/Makefile.am                    |    6 +-
 src/wayland/meta-tty.c             |  397 ++++++++++++++++++++++++++++++++++++
 src/wayland/meta-tty.h             |   43 ++++
 src/wayland/meta-wayland-private.h |    5 +
 src/wayland/meta-wayland.c         |   85 ++++++++-
 src/wayland/meta-weston-launch.c   |  202 ++++++++++++++++++
 src/wayland/meta-weston-launch.h   |   56 +++++
 8 files changed, 792 insertions(+), 4 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index dabe507..06e3bb0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -259,7 +259,7 @@ if test x$enable_wayland = "xyes"; then
 fi
 
 if test x$have_wayland = "xyes"; then
-  MUTTER_PC_MODULES="$MUTTER_PC_MODULES wayland-server clutter-wayland-compositor-1.0"
+  MUTTER_PC_MODULES="$MUTTER_PC_MODULES wayland-server clutter-wayland-compositor-1.0 libdrm"
   AC_DEFINE(HAVE_WAYLAND, , [Building with Wayland support])
   AC_SUBST(XWAYLAND_PATH)
 fi
diff --git a/src/Makefile.am b/src/Makefile.am
index dd45d7e..3a4e629 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -176,6 +176,8 @@ libmutter_la_SOURCES =                              \
 
 if HAVE_WAYLAND
 libmutter_la_SOURCES +=                                \
+       wayland/meta-tty.c                      \
+       wayland/meta-tty.h                      \
        wayland/meta-wayland.c                  \
        wayland/meta-wayland-data-device.c      \
        wayland/meta-wayland-data-device.h      \
@@ -187,7 +189,9 @@ libmutter_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
 endif
 
 libmutter_la_LDFLAGS = -no-undefined
diff --git a/src/wayland/meta-tty.c b/src/wayland/meta-tty.c
new file mode 100644
index 0000000..8b5174e
--- /dev/null
+++ b/src/wayland/meta-tty.c
@@ -0,0 +1,397 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *             2013 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <termios.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <linux/major.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "meta-tty.h"
+#include <gio/gio.h>
+#include <glib-unix.h>
+
+/* Introduced in 2.6.38 */
+#ifndef K_OFF
+#define K_OFF 0x04
+#endif
+
+struct _MetaTTYClass
+{
+  GObjectClass parent_class;
+};
+
+struct _MetaTTY
+{
+  GObject parent;
+
+  int fd;
+  struct termios terminal_attributes;
+
+  int input_source, vt_source;
+  int vt, starting_vt;
+  gboolean has_vt;
+  int kb_mode;
+};
+
+enum {
+  SIGNAL_ENTER,
+  SIGNAL_LEAVE,
+  SIGNAL_LAST
+};
+
+static int signals[SIGNAL_LAST];
+
+static void meta_tty_initable_iface_init (GInitableIface *);
+
+G_DEFINE_TYPE_WITH_CODE (MetaTTY, meta_tty, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                               meta_tty_initable_iface_init));
+
+static int
+vt_handler (gpointer user_data)
+{
+  MetaTTY *tty = user_data;
+
+  if (tty->has_vt)
+    {
+      tty->has_vt = FALSE;
+      g_signal_emit (tty, signals[SIGNAL_LEAVE], 0);
+
+      ioctl (tty->fd, VT_RELDISP, 1);
+    }
+  else
+    {
+      ioctl (tty->fd, VT_RELDISP, VT_ACKACQ);
+
+      tty->has_vt = 1;
+      g_signal_emit (tty, signals[SIGNAL_ENTER], 0);
+    }
+
+  return 1;
+}
+
+static int
+on_tty_input (int          fd, 
+             GIOCondition mask,
+             gpointer     user_data)
+{
+  MetaTTY *tty = user_data;
+
+  /* Ignore input to tty.  We get keyboard events from evdev */
+  tcflush(tty->fd, TCIFLUSH);
+
+  return 1;
+}
+
+static int
+try_open_vt (MetaTTY  *tty,
+            GError  **error)
+{
+  int tty0, fd;
+  char filename[16];
+
+  tty0 = open ("/dev/tty0", O_WRONLY | O_CLOEXEC);
+  if (tty0 < 0)
+    {
+      g_set_error (error, G_IO_ERROR,
+                  g_io_error_from_errno (errno),
+                  "Could not open tty0: %s", strerror (errno));
+      return -1;
+    }
+
+  if (ioctl (tty0, VT_OPENQRY, &tty->vt) < 0 || tty->vt == -1) {
+      g_set_error (error, G_IO_ERROR,
+                  g_io_error_from_errno (errno),
+                  "Could not open tty0: %s", strerror (errno));
+      close (tty0);
+      return -1;
+  }
+
+  close (tty0);
+  snprintf (filename, sizeof filename, "/dev/tty%d", tty->vt);
+  g_debug("compositor: using new vt %s\n", filename);
+  fd = open (filename, O_RDWR | O_NOCTTY | O_CLOEXEC);
+  return fd;
+}
+
+/* FIXME? */
+static int
+tty_activate_vt (MetaTTY *tty,
+                int      vt)
+{
+  return ioctl(tty->fd, VT_ACTIVATE, vt);
+}
+
+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 (env, NULL, 10);
+}
+
+static gboolean
+meta_tty_initable_init(GInitable     *initable,
+                      GCancellable  *cancellable,
+                      GError       **error)
+{
+  MetaTTY *tty = META_TTY (initable);
+  struct termios raw_attributes;
+  struct vt_mode mode = { 0 };
+  int ret;
+       
+  struct stat buf;
+  struct vt_stat vts;
+
+  tty->fd = env_get_fd ("WESTON_TTY_FD");
+  if (tty->fd < 0)
+    tty->fd = STDIN_FILENO;
+
+  if (fstat(tty->fd, &buf) == 0 &&
+      major(buf.st_rdev) == TTY_MAJOR &&
+      minor(buf.st_rdev) > 0)
+    {
+      if (tty->fd == STDIN_FILENO)
+       tty->fd = fcntl(STDIN_FILENO, F_DUPFD_CLOEXEC, 0);
+      tty->vt = minor(buf.st_rdev);
+    }
+  else
+    {
+      /* Fall back to try opening a new VT.  This typically
+       * requires root. */
+      tty->fd = try_open_vt(tty, error);
+    }
+
+  if (tty->fd <= 0 && (!error || !*error))
+    {
+      g_set_error (error, G_IO_ERROR,
+                  g_io_error_from_errno (errno),
+                  "Could not open tty0: %s", strerror (errno));
+      return FALSE;
+    }
+
+  if (ioctl(tty->fd, VT_GETSTATE, &vts) == 0)
+    tty->starting_vt = vts.v_active;
+  else
+    tty->starting_vt = tty->vt;
+  
+  if (tty->starting_vt != tty->vt)
+    {
+      if (ioctl(tty->fd, VT_ACTIVATE, tty->vt) < 0 ||
+         ioctl(tty->fd, VT_WAITACTIVE, tty->vt) < 0)
+       {
+         g_set_error (error, G_IO_ERROR,
+                      g_io_error_from_errno (errno),
+                      "Failed to switch to new vt: %s", strerror (errno));
+         goto err;
+       }
+    }
+
+  if (tcgetattr(tty->fd, &tty->terminal_attributes) < 0)
+    {
+      g_set_error (error, G_IO_ERROR,
+                  g_io_error_from_errno (errno),
+                  "Could not get terminal attributes: %s", strerror (errno));
+      goto err;
+    }
+
+  /* Ignore control characters and disable echo */
+  raw_attributes = tty->terminal_attributes;
+  cfmakeraw(&raw_attributes);
+
+  /* Fix up line endings to be normal (cfmakeraw hoses them) */
+  raw_attributes.c_oflag |= OPOST | OCRNL;
+
+  if (tcsetattr(tty->fd, TCSANOW, &raw_attributes) < 0)
+    g_warning("Could not put terminal into raw mode: %s", strerror (errno));
+
+  ioctl(tty->fd, KDGKBMODE, &tty->kb_mode);
+  ret = ioctl(tty->fd, KDSKBMODE, K_OFF);
+  if (ret)
+    {
+      ret = ioctl(tty->fd, KDSKBMODE, K_RAW);
+      if (ret)
+       {
+         g_set_error (error, G_IO_ERROR,
+                      g_io_error_from_errno (errno),
+                      "Failed to set keyboard mode: %s", strerror (errno));
+         goto err_attr;
+       }
+
+      tty->input_source = g_unix_fd_add (tty->fd,
+                                        G_IO_IN,
+                                        on_tty_input, tty);
+    }
+
+  ret = ioctl(tty->fd, KDSETMODE, KD_GRAPHICS);
+  if (ret)
+    {
+      g_set_error (error, G_IO_ERROR,
+                  g_io_error_from_errno (errno),
+                  "Failed to set KD_GRAPHICS mode: %s", strerror (errno));
+      goto err_kdkbmode;
+    }
+
+  tty->has_vt = 1;
+  mode.mode = VT_PROCESS;
+  mode.relsig = SIGUSR1;
+  mode.acqsig = SIGUSR1;
+  if (ioctl(tty->fd, VT_SETMODE, &mode) < 0)
+    {
+      g_set_error (error, G_IO_ERROR,
+                  g_io_error_from_errno (errno),
+                  "Failed to take control of vt handling: %s", strerror (errno));
+      goto err_kdmode;
+    }
+
+  tty->vt_source = g_unix_signal_add (SIGUSR1, vt_handler, tty);
+
+  return TRUE;
+
+ err_kdmode:
+  ioctl (tty->fd, KDSETMODE, KD_TEXT);
+
+ err_kdkbmode:
+  if (tty->input_source)
+    g_source_remove (tty->input_source);
+  ioctl (tty->fd, KDSKBMODE, tty->kb_mode);
+
+ err_attr:
+  tcsetattr (tty->fd, TCSANOW, &tty->terminal_attributes);
+  
+ err:
+  close (tty->fd);
+  return FALSE;
+}
+
+static void
+tty_reset (MetaTTY *tty)
+{
+  struct vt_mode mode = { 0 };
+
+  if (ioctl (tty->fd, KDSKBMODE, tty->kb_mode))
+    g_warning ("failed to restore keyboard mode: %s", strerror (errno));
+
+  if (ioctl (tty->fd, KDSETMODE, KD_TEXT))
+    g_warning ("failed to set KD_TEXT mode on tty: %s", strerror (errno));
+
+  if (tcsetattr (tty->fd, TCSANOW, &tty->terminal_attributes) < 0)
+    g_warning ("could not restore terminal to canonical mode");
+
+  mode.mode = VT_AUTO;
+  if (ioctl (tty->fd, VT_SETMODE, &mode) < 0)
+    g_warning ("could not reset vt handling\n");
+
+  if (tty->has_vt && tty->vt != tty->starting_vt)
+    {
+      ioctl(tty->fd, VT_ACTIVATE, tty->starting_vt);
+      ioctl(tty->fd, VT_WAITACTIVE, tty->starting_vt);
+    }
+}
+
+static void
+meta_tty_finalize (GObject *object)
+{
+  MetaTTY *tty = META_TTY (object);
+
+  if (tty->input_source)
+    g_source_remove (tty->input_source);
+
+  g_source_remove (tty->vt_source);
+
+  tty_reset (tty);
+
+  close (tty->fd);
+
+  G_OBJECT_CLASS (meta_tty_parent_class)->finalize (object);
+}
+
+static void
+meta_tty_init (MetaTTY *self)
+{
+}
+
+static void
+meta_tty_class_init (MetaTTYClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = meta_tty_finalize;
+
+  signals[SIGNAL_ENTER] = g_signal_new ("enter",
+                                       G_TYPE_FROM_CLASS (klass),
+                                       G_SIGNAL_RUN_FIRST,
+                                       0, /* class offset */
+                                       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,
+                                       0, /* class offset */
+                                       NULL, NULL, /* accumulator */
+                                       g_cclosure_marshal_VOID__VOID,
+                                       G_TYPE_NONE, 0);
+}
+
+static void
+meta_tty_initable_iface_init (GInitableIface *iface)
+{
+  iface->init = meta_tty_initable_init;
+}
+
+MetaTTY *
+meta_tty_new (void)
+{
+  GError *error;
+  MetaTTY *tty;
+
+  error = NULL;
+  tty = g_initable_new (META_TYPE_TTY, NULL, &error, NULL);
+
+  if (tty == NULL)
+    {
+      g_warning ("Failed to initalize TTY handling: %s", error->message);
+      g_error_free (error);
+    }
+
+  return tty;
+}
diff --git a/src/wayland/meta-tty.h b/src/wayland/meta-tty.h
new file mode 100644
index 0000000..2c3bf2a
--- /dev/null
+++ b/src/wayland/meta-tty.h
@@ -0,0 +1,43 @@
+/*
+ * 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_TTY_H
+#define META_TTY_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define META_TYPE_TTY              (meta_tty_get_type())
+#define META_TTY(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_TTY, MetaTTY))
+#define META_TTY_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_TTY, MetaTTYClass))
+#define META_IS_TTY(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_TTY))
+#define META_IS_TTY_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_TTY))
+#define META_TTY_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TTY, MetaTTYClass))
+
+typedef struct _MetaTTY      MetaTTY;
+typedef struct _MetaTTYClass MetaTTYClass;
+
+GType             meta_tty_get_type                (void) G_GNUC_CONST;
+
+MetaTTY          *meta_tty_new                     (void);
+
+G_END_DECLS
+
+#endif /* META_TTY_H */
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
index c33f7f9..9fed560 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-tty.h"
 
 typedef struct _MetaWaylandCompositor MetaWaylandCompositor;
 
@@ -166,6 +167,10 @@ struct _MetaWaylandCompositor
   struct wl_resource *xserver_resource;
   GHashTable *window_surfaces;
 
+  MetaTTY *tty;
+  int drm_fd;
+  GSocket *weston_launch;
+
   MetaWaylandSeat *seat;
 
   /* This surface is only used to keep drag of the implicit grab when
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 2c6c0fb..17c121b 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -21,7 +21,6 @@
 
 #include <config.h>
 
-#define COGL_ENABLE_EXPERIMENTAL_2_0_API
 #include <clutter/clutter.h>
 #include <clutter/wayland/clutter-wayland-compositor.h>
 #include <clutter/wayland/clutter-wayland-surface.h>
@@ -54,6 +53,7 @@
 #include <meta/types.h>
 #include <meta/main.h>
 #include "frame.h"
+#include "meta-weston-launch.h"
 
 static MetaWaylandCompositor _meta_wayland_compositor;
 
@@ -1727,11 +1727,59 @@ event_emission_hook_cb (GSignalInvocationHint *ihint,
   return TRUE /* stay connected */;
 }
 
+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 (env, NULL, 10);
+}
+
+static void
+on_our_vt_enter (MetaTTY               *tty,
+                MetaWaylandCompositor *compositor)
+{
+  GError *error;
+
+  error = NULL;
+  if (!meta_weston_launch_set_master (compositor->weston_launch,
+                                     compositor->drm_fd, TRUE, &error))
+    {
+      g_warning ("Failed to become DRM master: %s", error->message);
+      g_error_free (error);
+    }
+}
+
+static void
+on_our_vt_leave (MetaTTY               *tty,
+                MetaWaylandCompositor *compositor)
+{
+  GError *error;
+
+  error = NULL;
+  if (!meta_weston_launch_set_master (compositor->weston_launch,
+                                     compositor->drm_fd, FALSE, &error))
+    {
+      g_warning ("Failed to release DRM master: %s", error->message);
+      g_error_free (error);
+    }
+
+  /* FIXME: we must release input devices as well! */
+}
+
 void
 meta_wayland_init (void)
 {
   MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
   guint event_signal;
+  ClutterBackend *backend;
+  CoglContext *cogl_context;
+  CoglRenderer *cogl_renderer;
 
   memset (compositor, 0, sizeof (MetaWaylandCompositor));
 
@@ -1771,6 +1819,34 @@ meta_wayland_init (void)
   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)
+    {
+      /* Running on bare metal, let's initalize DRM master and VT handling */
+      int weston_launch_fd;
+
+      weston_launch_fd = env_get_fd ("WESTON_LAUNCHER_SOCK");
+      if (weston_launch_fd >= 0)
+       compositor->weston_launch = g_socket_new_from_fd (weston_launch_fd, NULL);
+
+      compositor->tty = meta_tty_new ();
+      if (compositor->tty)
+       {
+         g_signal_connect (compositor->tty, "enter", G_CALLBACK (on_our_vt_enter), compositor);
+         g_signal_connect (compositor->tty, "leave", G_CALLBACK (on_our_vt_leave), compositor);
+       }
+
+      on_our_vt_enter (compositor->tty, compositor);
+    }
+
   compositor->stage = meta_wayland_stage_new ();
   clutter_stage_set_user_resizable (CLUTTER_STAGE (compositor->stage), FALSE);
   g_signal_connect_after (compositor->stage, "paint",
@@ -1842,5 +1918,10 @@ meta_wayland_init (void)
 void
 meta_wayland_finalize (void)
 {
-  stop_xwayland (meta_wayland_compositor_get_default ());
+  MetaWaylandCompositor *compositor;
+
+  compositor = meta_wayland_compositor_get_default ();
+
+  stop_xwayland (compositor);
+  g_clear_object (&compositor->tty);
 }
diff --git a/src/wayland/meta-weston-launch.c b/src/wayland/meta-weston-launch.c
new file mode 100644
index 0000000..68f14cf
--- /dev/null
+++ b/src/wayland/meta-weston-launch.c
@@ -0,0 +1,202 @@
+/*
+ * 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 <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"
+
+static gboolean
+send_message_to_wl (GSocket                *weston_launch,
+                   void                   *message,
+                   gsize                   size,
+                   GSocketControlMessage  *out_cmsg,
+                   GSocketControlMessage **in_cmsg,
+                   GError                **error)
+{
+  int ok;
+  GInputVector in_iov = { &ok, sizeof (int) };
+  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 (weston_launch, NULL,
+                            &out_iov, 1,
+                            out_all_cmsg, -1,
+                            flags, NULL, error) != (gssize)size)
+    return FALSE;
+
+  if (g_socket_receive_message (weston_launch, NULL,
+                               &in_iov, 1,
+                               &in_all_cmsg, NULL,
+                               &flags, NULL, error) != sizeof (int))
+    return FALSE;
+
+  if (ok != 0)
+    {
+      if (ok == -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 (-ok),
+                    "Got failure from weston-launch: %s", strerror (-ok));
+
+      for (i = 0; in_all_cmsg[i]; i++)
+       g_object_unref (in_all_cmsg[i]);
+      g_free (in_all_cmsg);
+
+      return FALSE;
+    }
+
+  if (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_weston_launch_set_master (GSocket   *weston_launch,
+                              int        drm_fd,
+                              gboolean   master,
+                              GError   **error)
+{
+  if (weston_launch)
+    {
+      struct weston_launcher_set_master message;
+      GSocketControlMessage *cmsg;
+      gboolean ok;
+
+      message.header.opcode = WESTON_LAUNCHER_DRM_SET_MASTER;
+      message.set_master = master;
+
+      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 (weston_launch, &message, sizeof message, cmsg, NULL, error);
+
+      g_object_unref (cmsg);
+      return ok;
+    }
+  else
+    {
+      int ret;
+
+      if (master)
+       ret = drmSetMaster (drm_fd);
+      else
+       ret = drmDropMaster (drm_fd);
+
+      if (ret < 0)
+       {
+         g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret),
+                      "Failed to set DRM master directly: %s", strerror (-ret));
+         return FALSE;
+       }
+      else
+       return TRUE;
+    }
+}
+
+int
+meta_weston_launch_open_input_device (GSocket    *weston_launch,
+                                     const char *name,
+                                     int         flags,
+                                     GError    **error)
+{
+  if (weston_launch)
+    {
+      struct weston_launcher_open *message;
+      GSocketControlMessage *cmsg;
+      gboolean ok;
+      int *fds, n_fd;
+      int ret;
+
+      message = g_malloc (sizeof (struct weston_launcher_open) +
+                         strlen (name));
+      message->header.opcode = WESTON_LAUNCHER_OPEN;
+      message->flags = flags;
+      strcpy (message->path, name);
+
+      ok = send_message_to_wl (weston_launch, message,
+                              sizeof (struct weston_launcher_open) + strlen (name),
+                              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);
+       }
+      else
+       ret = -1;
+
+      g_free (message);
+      g_object_unref (cmsg);
+      return ret;
+    }
+  else
+    {
+      int ret;
+
+      ret = open (name, flags, 0);
+
+      if (ret < 0)
+       g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
+                    "Failed to open input device directly: %s", strerror (errno));
+
+      return ret;
+    }
+}
+
diff --git a/src/wayland/meta-weston-launch.h b/src/wayland/meta-weston-launch.h
new file mode 100644
index 0000000..f642ba9
--- /dev/null
+++ b/src/wayland/meta-weston-launch.h
@@ -0,0 +1,56 @@
+/*
+ * 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>
+
+/* Keep this in sync with weston-launch */
+
+enum weston_launcher_opcode {
+       WESTON_LAUNCHER_OPEN,
+       WESTON_LAUNCHER_DRM_SET_MASTER
+};
+
+struct weston_launcher_message {
+       int opcode;
+};
+
+struct weston_launcher_open {
+       struct weston_launcher_message header;
+       int flags;
+       char path[0];
+};
+
+struct weston_launcher_set_master {
+       struct weston_launcher_message header;
+       int set_master;
+};
+
+gboolean meta_weston_launch_set_master (GSocket   *weston_launch,
+                                       int        drm_fd,
+                                       gboolean   master,
+                                       GError   **error);
+int      meta_weston_launch_open_input_device (GSocket     *weston_launch,
+                                              const char  *name,
+                                              int          flags,
+                                              GError     **error);
+
+#endif


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