[mutter/wip/wayland-kms: 13/15] wayland: Adds virtual terminal enter/leave handling
- From: Neil Roberts <nroberts src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wip/wayland-kms: 13/15] wayland: Adds virtual terminal enter/leave handling
- Date: Wed, 18 Jul 2012 16:06:04 +0000 (UTC)
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]