[mutter/wip/wayland-kms: 13/15] wayland: Adds virtual terminal enter/leave handling



commit 45e35d931401ff28c4f3e120b459fbeb4d2b804b
Author: Robert Bragg <robert linux intel com>
Date:   Fri Jan 20 16:50:19 2012 +0000

    wayland: Adds virtual terminal enter/leave handling
    
    This adds code to open and switch to a free virtual terminal and
    adds code to drop evdev devices when switching away from the virtual
    terminal and set/drop drm master mode.

 src/Makefile.am                    |    4 +-
 src/wayland/meta-tty.c             |  216 ++++++++++++++++++++++++++++++++++++
 src/wayland/meta-tty.h             |   45 ++++++++
 src/wayland/meta-wayland-private.h |    2 +
 src/wayland/meta-wayland.c         |   77 ++++++++++++-
 5 files changed, 336 insertions(+), 8 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index f8733fb..32a0c7d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -172,7 +172,9 @@ libmutter_la_SOURCES +=				\
 	wayland/meta-wayland-input-device.h	\
 	wayland/meta-wayland-input-device.c	\
 	wayland/meta-wayland-stage.h		\
-	wayland/meta-wayland-stage.c
+	wayland/meta-wayland-stage.c		\
+	wayland/meta-tty.h			\
+	wayland/meta-tty.c
 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..2c4360a
--- /dev/null
+++ b/src/wayland/meta-tty.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright  2010 Intel Corporation
+ *
+ * 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 <termios.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <linux/major.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include "meta-wayland-private.h"
+#include "meta-tty.h"
+
+struct tty {
+	MetaWaylandCompositor *compositor;
+	int fd;
+	struct termios terminal_attributes;
+
+	struct wl_event_source *input_source;
+	struct wl_event_source *enter_vt_source;
+	struct wl_event_source *leave_vt_source;
+	MetaTTYVTFunc vt_func;
+};
+
+static int on_enter_vt(int signal_number, void *data)
+{
+	struct tty *tty = data;
+
+	ioctl(tty->fd, VT_RELDISP, VT_ACKACQ);
+
+	tty->vt_func(tty->compositor, META_TTY_VT_EVENT_ENTER);
+
+	return 1;
+}
+
+static int
+on_leave_vt(int signal_number, void *data)
+{
+	struct tty *tty = data;
+
+	tty->vt_func(tty->compositor, META_TTY_VT_EVENT_LEAVE);
+
+	ioctl(tty->fd, VT_RELDISP, 1);
+
+	return 1;
+}
+
+static int
+on_tty_input(int fd, uint32_t mask, void *data)
+{
+	struct tty *tty = data;
+
+	/* Ignore input to tty.  We get keyboard events from evdev
+	 */
+	tcflush(tty->fd, TCIFLUSH);
+
+	return 1;
+}
+
+static int
+try_open_vt(void)
+{
+	int tty0, vt, fd;
+	char filename[16];
+
+	tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
+	if (tty0 < 0) {
+		g_warning ("could not open tty0: %m\n");
+		return -1;
+	}
+
+	if (ioctl(tty0, VT_OPENQRY, &vt) < 0 || vt == -1) {
+		g_warning ("could not open tty0: %m\n");
+		close(tty0);
+		return -1;
+	}
+
+	close(tty0);
+	snprintf(filename, sizeof filename, "/dev/tty%d", vt);
+	g_warning ("compositor: using new vt %s\n", filename);
+	fd = open(filename, O_RDWR | O_NOCTTY | O_CLOEXEC);
+	if (fd < 0)
+		return fd;
+
+	if (ioctl(fd, VT_ACTIVATE, vt) < 0 ||
+	    ioctl(fd, VT_WAITACTIVE, vt) < 0) {
+		g_warning ("failed to swtich to new vt\n");
+		close(fd);
+		return -1;
+	}
+
+	return fd;
+}
+
+struct tty *
+meta_tty_create (MetaWaylandCompositor *compositor,
+                 MetaTTYVTFunc vt_func,
+                 int tty_nr)
+{
+	struct termios raw_attributes;
+	struct vt_mode mode = { 0 };
+	int ret;
+	struct tty *tty;
+	struct wl_event_loop *loop;
+	struct stat buf;
+	char filename[16];
+
+	tty = malloc(sizeof *tty);
+	if (tty == NULL)
+		return NULL;
+
+	memset(tty, 0, sizeof *tty);
+	tty->compositor = compositor;
+	tty->vt_func = vt_func;
+	if (tty_nr > 0) {
+		snprintf(filename, sizeof filename, "/dev/tty%d", tty_nr);
+		g_warning ("compositor: using %s\n", filename);
+		tty->fd = open(filename, O_RDWR | O_NOCTTY | O_CLOEXEC);
+	} else if (fstat(tty->fd, &buf) == 0 &&
+		   major(buf.st_rdev) == TTY_MAJOR &&
+		   minor(buf.st_rdev) > 0) {
+		tty->fd = fcntl(0, F_DUPFD_CLOEXEC, 0);
+	} else {
+		/* Fall back to try opening a new VT.  This typically
+		 * requires root. */
+		tty->fd = try_open_vt();
+	}
+
+	if (tty->fd <= 0) {
+		g_warning ("failed to open tty: %m\n");
+		return NULL;
+	}
+
+	if (tcgetattr(tty->fd, &tty->terminal_attributes) < 0) {
+		g_warning ("could not get terminal attributes: %m\n");
+		return NULL;
+	}
+
+	/* 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: %m\n");
+
+	loop = wl_display_get_event_loop(compositor->wayland_display);
+	tty->input_source =
+		wl_event_loop_add_fd(loop, tty->fd,
+				     WL_EVENT_READABLE, on_tty_input, tty);
+
+	ret = ioctl(tty->fd, KDSETMODE, KD_GRAPHICS);
+	if (ret) {
+		g_warning ("failed to set KD_GRAPHICS mode on tty: %m\n");
+		return NULL;
+	}
+
+	mode.mode = VT_PROCESS;
+	mode.relsig = SIGUSR1;
+	mode.acqsig = SIGUSR2;
+	if (ioctl(tty->fd, VT_SETMODE, &mode) < 0) {
+		g_warning ("failed to take control of vt handling\n");
+		return NULL;
+	}
+
+	tty->leave_vt_source =
+		wl_event_loop_add_signal(loop, SIGUSR1, on_leave_vt, tty);
+	tty->enter_vt_source =
+		wl_event_loop_add_signal(loop, SIGUSR2, on_enter_vt, tty);
+
+	return tty;
+}
+
+void
+meta_tty_destroy(struct tty *tty)
+{
+        if(!tty)
+                return;
+
+	if (ioctl(tty->fd, KDSETMODE, KD_TEXT))
+		g_warning ("failed to set KD_TEXT mode on tty: %m\n");
+
+	if (tcsetattr(tty->fd, TCSANOW, &tty->terminal_attributes) < 0)
+		g_warning ("could not restore terminal to canonical mode\n");
+
+	close(tty->fd);
+
+	free(tty);
+}
diff --git a/src/wayland/meta-tty.h b/src/wayland/meta-tty.h
new file mode 100644
index 0000000..42e24f6
--- /dev/null
+++ b/src/wayland/meta-tty.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * 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 "meta-wayland-private.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+  META_TTY_VT_EVENT_ENTER,
+  META_TTY_VT_EVENT_LEAVE
+} MetaTTYVTEvent;
+
+typedef void (*MetaTTYVTFunc)(MetaWaylandCompositor *compositor,
+                              MetaTTYVTEvent event);
+
+struct tty *
+meta_tty_create (MetaWaylandCompositor *compositor,
+                 MetaTTYVTFunc callback,
+                 int tty_nr);
+
+void
+meta_tty_destroy(struct tty *tty);
+
+G_END_DECLS
+
+#endif /* META_TTY_H */
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
index b0896a6..0a1b980 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -109,6 +109,8 @@ struct _MetaWaylandCompositor
   struct wl_event_loop *wayland_loop;
   GMainLoop *init_loop;
   ClutterActor *stage;
+  int drm_fd;
+  struct tty *tty;
   GList *outputs;
   GSource *wayland_event_source;
   GList *surfaces;
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index e21c407..6abb1c9 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -21,10 +21,12 @@
 
 #include <config.h>
 
+#define CLUTTER_ENABLE_EXPERIMENTAL_API
 #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>
+#include <clutter/evdev/clutter-evdev.h>
 
 #include <glib.h>
 #include <sys/time.h>
@@ -37,12 +39,14 @@
 #include <sys/un.h>
 #include <stdlib.h>
 #include <sys/wait.h>
+#include <xf86drm.h>
 
 #include <wayland-server.h>
 
 #include "xserver-server-protocol.h"
 
 #include "meta-wayland-private.h"
+#include "meta-tty.h"
 #include "meta-wayland-stage.h"
 #include "meta-window-actor-private.h"
 #include "display-private.h"
@@ -1456,6 +1460,26 @@ event_emission_hook_cb (GSignalInvocationHint *ihint,
   return TRUE /* stay connected */;
 }
 
+static void
+vt_func (MetaWaylandCompositor *compositor,
+         MetaTTYVTEvent event)
+{
+  switch (event)
+    {
+    case META_TTY_VT_EVENT_ENTER:
+      if (drmSetMaster (compositor->drm_fd))
+        g_critical ("failed to set master: %m\n");
+      clutter_actor_queue_redraw (compositor->stage);
+      clutter_evdev_reclaim_devices ();
+      break;
+    case META_TTY_VT_EVENT_LEAVE:
+      clutter_evdev_release_devices ();
+      if (drmDropMaster(compositor->drm_fd) < 0)
+        g_warning ("failed to drop master: %m\n");
+      break;
+    };
+}
+
 void
 meta_wayland_init (void)
 {
@@ -1468,18 +1492,28 @@ meta_wayland_init (void)
   if (compositor->wayland_display == NULL)
     g_error ("failed to create wayland display");
 
+  /* XXX: Come up with a more elegant approach... */
+  if (strcmp (getenv ("CLUTTER_BACKEND"), "eglnative") == 0)
+    compositor->tty = meta_tty_create (compositor, vt_func, 0);
+
   g_queue_init (&compositor->frame_callbacks);
 
   if (!wl_display_add_global (compositor->wayland_display,
                               &wl_compositor_interface,
 			      compositor,
                               compositor_bind))
-    g_error ("Failed to register wayland compositor object");
+    {
+      g_printerr ("Failed to register wayland compositor object");
+      goto error;
+    }
 
   compositor->wayland_shm = wl_shm_init (compositor->wayland_display,
                                          &shm_callbacks);
   if (!compositor->wayland_shm)
-    g_error ("Failed to allocate setup wayland shm callbacks");
+    {
+      g_printerr ("Failed to allocate setup wayland shm callbacks");
+      goto error;
+    }
 
   compositor->wayland_loop =
     wl_display_get_event_loop (compositor->wayland_display);
@@ -1502,7 +1536,10 @@ meta_wayland_init (void)
   clutter_wayland_set_compositor_display (compositor->wayland_display);
 
   if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
-    g_error ("Failed to initialize Clutter");
+    {
+      g_printerr ("Failed to initialize Clutter");
+      goto error;
+    }
 
   compositor->stage = meta_wayland_stage_new ();
   clutter_stage_set_user_resizable (CLUTTER_STAGE (compositor->stage), FALSE);
@@ -1523,6 +1560,16 @@ meta_wayland_init (void)
                               compositor, /* hook_data */
                               NULL /* data_destroy */);
 
+  if (compositor->tty)
+    {
+      ClutterBackend *clutter_backend = clutter_get_default_backend ();
+      CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
+      CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
+      CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_display);
+
+      compositor->drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
+    }
+
   wl_data_device_manager_init (compositor->wayland_display);
 
   compositor->input_device =
@@ -1533,12 +1580,18 @@ meta_wayland_init (void)
 
   if (wl_display_add_global (compositor->wayland_display, &wl_shell_interface,
                              compositor, bind_shell) == NULL)
-    g_error ("Failed to register a global shell object");
+    {
+      g_printerr ("Failed to register a global shell object");
+      goto error;
+    }
 
   clutter_actor_show (compositor->stage);
 
   if (wl_display_add_socket (compositor->wayland_display, "wayland-0"))
-    g_error ("Failed to create socket");
+    {
+      g_printerr ("Failed to create socket");
+      goto error;
+    }
 
   wl_display_add_global (compositor->wayland_display,
                          &xserver_interface,
@@ -1559,7 +1612,10 @@ meta_wayland_init (void)
    */
 
   if (!start_xwayland (compositor))
-    g_error ("Failed to start X Wayland");
+    {
+      g_printerr ("Failed to start X Wayland");
+      goto error;
+    }
 
   putenv (g_strdup_printf ("DISPLAY=:%d", compositor->xwayland_display_index));
 
@@ -1569,12 +1625,19 @@ meta_wayland_init (void)
   compositor->init_loop = g_main_loop_new (NULL, FALSE);
 
   g_main_loop_run (compositor->init_loop);
+
+  return;
+error:
+  meta_tty_destroy (compositor->tty);
 }
 
 void
 meta_wayland_finalize (void)
 {
-  stop_xwayland (meta_wayland_compositor_get_default ());
+  MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
+  if (compositor->tty)
+    meta_tty_destroy (compositor->tty);
+  stop_xwayland (compositor);
 }
 
 void



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