Compare commits
	
		
			7 Commits
		
	
	
		
			3.21.1
			...
			wip/waylan
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					7f07b4a0fc | ||
| 
						 | 
					c9a9c5fe79 | ||
| 
						 | 
					04aff06876 | ||
| 
						 | 
					1cb5284113 | ||
| 
						 | 
					b1e758b341 | ||
| 
						 | 
					96753bb703 | ||
| 
						 | 
					33b06f97e3 | 
@@ -139,6 +139,12 @@ AM_GLIB_GNU_GETTEXT
 | 
			
		||||
## here we get the flags we'll actually use
 | 
			
		||||
# GRegex requires Glib-2.14.0
 | 
			
		||||
PKG_CHECK_MODULES(ALL, glib-2.0 >= 2.14.0)
 | 
			
		||||
PKG_CHECK_MODULES(MUTTER_LAUNCH, libdrm libsystemd-login)
 | 
			
		||||
 | 
			
		||||
saved_LIBS="$LIBS"
 | 
			
		||||
LIBS="$LIBS $MUTTER_LAUNCH"
 | 
			
		||||
AC_CHECK_FUNCS([sd_session_get_vt])
 | 
			
		||||
LIBS="$saved_LIBS"
 | 
			
		||||
 | 
			
		||||
# Unconditionally use this dir to avoid a circular dep with gnomecc
 | 
			
		||||
GNOME_KEYBINDINGS_KEYSDIR="${datadir}/gnome-control-center/keybindings"
 | 
			
		||||
@@ -226,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)
 | 
			
		||||
@@ -247,6 +249,17 @@ bin_PROGRAMS=mutter-wayland
 | 
			
		||||
mutter_wayland_SOURCES = core/mutter.c
 | 
			
		||||
mutter_wayland_LDADD = $(MUTTER_LIBS) libmutter-wayland.la
 | 
			
		||||
 | 
			
		||||
bin_PROGRAMS+=mutter-launch
 | 
			
		||||
 | 
			
		||||
mutter_launch_SOURCES = wayland/weston-launch.c wayland/weston-launch.h
 | 
			
		||||
 | 
			
		||||
mutter_launch_CFLAGS = $(MUTTER_LAUNCH_CFLAGS) -DLIBDIR=\"$(libdir)\"
 | 
			
		||||
mutter_launch_LDFLAGS = $(MUTTER_LAUNCH_LIBS) -lpam
 | 
			
		||||
 | 
			
		||||
install-exec-hook:
 | 
			
		||||
	-chown root $(DESTDIR)$(bindir)/mutter-launch
 | 
			
		||||
	-chmod u+s $(DESTDIR)$(bindir)/mutter-launch
 | 
			
		||||
 | 
			
		||||
if HAVE_INTROSPECTION
 | 
			
		||||
include $(INTROSPECTION_MAKEFILE)
 | 
			
		||||
 | 
			
		||||
@@ -306,7 +319,7 @@ xml_DATA     = $(xml_in_files:.xml.in=.xml)
 | 
			
		||||
 | 
			
		||||
dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h
 | 
			
		||||
 | 
			
		||||
gsettings_SCHEMAS = org.gnome.mutter.gschema.xml
 | 
			
		||||
gsettings_SCHEMAS = org.gnome.mutter.gschema.xml org.gnome.mutter.wayland.gschema.xml
 | 
			
		||||
@INTLTOOL_XML_NOMERGE_RULE@
 | 
			
		||||
@GSETTINGS_RULES@
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -53,8 +53,13 @@
 | 
			
		||||
#include <X11/XKBlib.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
#include "meta-wayland-private.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define SCHEMA_COMMON_KEYBINDINGS "org.gnome.desktop.wm.keybindings"
 | 
			
		||||
#define SCHEMA_MUTTER_KEYBINDINGS "org.gnome.mutter.keybindings"
 | 
			
		||||
#define SCHEMA_MUTTER_WAYLAND_KEYBINDINGS "org.gnome.mutter.wayland.keybindings"
 | 
			
		||||
 | 
			
		||||
static gboolean add_builtin_keybinding (MetaDisplay          *display,
 | 
			
		||||
                                        const char           *name,
 | 
			
		||||
@@ -4098,6 +4103,40 @@ handle_set_spew_mark (MetaDisplay    *display,
 | 
			
		||||
  meta_verbose ("-- MARK MARK MARK MARK --\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
static void
 | 
			
		||||
handle_switch_vt (MetaDisplay    *display,
 | 
			
		||||
                  MetaScreen     *screen,
 | 
			
		||||
                  MetaWindow     *window,
 | 
			
		||||
                  XIDeviceEvent  *event,
 | 
			
		||||
                  MetaKeyBinding *binding,
 | 
			
		||||
                  gpointer        dummy)
 | 
			
		||||
{
 | 
			
		||||
    gint vt = binding->handler->data;
 | 
			
		||||
    MetaWaylandCompositor *compositor;
 | 
			
		||||
    MetaLauncher *launcher;
 | 
			
		||||
 | 
			
		||||
    compositor = meta_wayland_compositor_get_default ();
 | 
			
		||||
    launcher = meta_wayland_compositor_get_launcher (compositor);
 | 
			
		||||
 | 
			
		||||
    if (launcher)
 | 
			
		||||
      {
 | 
			
		||||
        GError *error;
 | 
			
		||||
 | 
			
		||||
        error = NULL;
 | 
			
		||||
        if (!meta_launcher_activate_vt (launcher, vt, &error))
 | 
			
		||||
          {
 | 
			
		||||
            g_warning ("Failed to switch VT: %s", error->message);
 | 
			
		||||
            g_error_free (error);
 | 
			
		||||
          }
 | 
			
		||||
      }
 | 
			
		||||
    else
 | 
			
		||||
      {
 | 
			
		||||
        g_debug ("Ignoring VT switch keybinding, not running as VT manager");
 | 
			
		||||
      }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * meta_keybindings_set_custom_handler:
 | 
			
		||||
 * @name: The name of the keybinding to set
 | 
			
		||||
@@ -4161,6 +4200,7 @@ init_builtin_key_bindings (MetaDisplay *display)
 | 
			
		||||
                               META_KEY_BINDING_IS_REVERSED)
 | 
			
		||||
  GSettings *common_keybindings = g_settings_new (SCHEMA_COMMON_KEYBINDINGS);
 | 
			
		||||
  GSettings *mutter_keybindings = g_settings_new (SCHEMA_MUTTER_KEYBINDINGS);
 | 
			
		||||
  GSettings *mutter_wayland_keybindings = g_settings_new (SCHEMA_MUTTER_WAYLAND_KEYBINDINGS);
 | 
			
		||||
 | 
			
		||||
  add_builtin_keybinding (display,
 | 
			
		||||
                          "switch-to-workspace-1",
 | 
			
		||||
@@ -4422,6 +4462,60 @@ init_builtin_key_bindings (MetaDisplay *display)
 | 
			
		||||
                          META_KEYBINDING_ACTION_SET_SPEW_MARK,
 | 
			
		||||
                          handle_set_spew_mark, 0);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_WAYLAND
 | 
			
		||||
  if (meta_is_wayland_compositor ())
 | 
			
		||||
    {
 | 
			
		||||
      add_builtin_keybinding (display,
 | 
			
		||||
                              "switch-to-session-1",
 | 
			
		||||
                              mutter_wayland_keybindings,
 | 
			
		||||
                              META_KEY_BINDING_NONE,
 | 
			
		||||
                              META_KEYBINDING_ACTION_NONE,
 | 
			
		||||
                              handle_switch_vt, 1);
 | 
			
		||||
 | 
			
		||||
      add_builtin_keybinding (display,
 | 
			
		||||
                              "switch-to-session-2",
 | 
			
		||||
                              mutter_wayland_keybindings,
 | 
			
		||||
                              META_KEY_BINDING_NONE,
 | 
			
		||||
                              META_KEYBINDING_ACTION_NONE,
 | 
			
		||||
                              handle_switch_vt, 2);
 | 
			
		||||
 | 
			
		||||
      add_builtin_keybinding (display,
 | 
			
		||||
                              "switch-to-session-3",
 | 
			
		||||
                              mutter_wayland_keybindings,
 | 
			
		||||
                              META_KEY_BINDING_NONE,
 | 
			
		||||
                              META_KEYBINDING_ACTION_NONE,
 | 
			
		||||
                              handle_switch_vt, 3);
 | 
			
		||||
 | 
			
		||||
      add_builtin_keybinding (display,
 | 
			
		||||
                              "switch-to-session-4",
 | 
			
		||||
                              mutter_wayland_keybindings,
 | 
			
		||||
                              META_KEY_BINDING_NONE,
 | 
			
		||||
                              META_KEYBINDING_ACTION_NONE,
 | 
			
		||||
                              handle_switch_vt, 4);
 | 
			
		||||
 | 
			
		||||
      add_builtin_keybinding (display,
 | 
			
		||||
                              "switch-to-session-5",
 | 
			
		||||
                              mutter_wayland_keybindings,
 | 
			
		||||
                              META_KEY_BINDING_NONE,
 | 
			
		||||
                              META_KEYBINDING_ACTION_NONE,
 | 
			
		||||
                              handle_switch_vt, 5);
 | 
			
		||||
 | 
			
		||||
      add_builtin_keybinding (display,
 | 
			
		||||
                              "switch-to-session-6",
 | 
			
		||||
                              mutter_wayland_keybindings,
 | 
			
		||||
                              META_KEY_BINDING_NONE,
 | 
			
		||||
                              META_KEYBINDING_ACTION_NONE,
 | 
			
		||||
                              handle_switch_vt, 6);
 | 
			
		||||
 | 
			
		||||
      add_builtin_keybinding (display,
 | 
			
		||||
                              "switch-to-session-7",
 | 
			
		||||
                              mutter_wayland_keybindings,
 | 
			
		||||
                              META_KEY_BINDING_NONE,
 | 
			
		||||
                              META_KEYBINDING_ACTION_NONE,
 | 
			
		||||
                              handle_switch_vt, 7);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#undef REVERSES_AND_REVERSED
 | 
			
		||||
 | 
			
		||||
  /************************ PER WINDOW BINDINGS ************************/
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										33
									
								
								src/org.gnome.mutter.wayland.gschema.xml.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/org.gnome.mutter.wayland.gschema.xml.in
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
<schemalist>
 | 
			
		||||
  <schema id="org.gnome.mutter.wayland.keybindings" path="/org/gnome/mutter/wayland/keybindings/"
 | 
			
		||||
	  gettext-domain="@GETTEXT_DOMAIN@">
 | 
			
		||||
    <key name="switch-to-session-1" type="as">
 | 
			
		||||
      <default><![CDATA[['<Primary><Alt>F1']]]></default>
 | 
			
		||||
      <_summary>Switch to VT 1</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="switch-to-session-2" type="as">
 | 
			
		||||
      <default><![CDATA[['<Primary><Alt>F2']]]></default>
 | 
			
		||||
      <_summary>Switch to VT 2</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="switch-to-session-3" type="as">
 | 
			
		||||
      <default><![CDATA[['<Primary><Alt>F3']]]></default>
 | 
			
		||||
      <_summary>Switch to VT 3</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="switch-to-session-4" type="as">
 | 
			
		||||
      <default><![CDATA[['<Primary><Alt>F4']]]></default>
 | 
			
		||||
      <_summary>Switch to VT 4</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="switch-to-session-5" type="as">
 | 
			
		||||
      <default><![CDATA[['<Primary><Alt>F5']]]></default>
 | 
			
		||||
      <_summary>Switch to VT 5</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="switch-to-session-6" type="as">
 | 
			
		||||
      <default><![CDATA[['<Primary><Alt>F6']]]></default>
 | 
			
		||||
      <_summary>Switch to VT 6</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="switch-to-session-7" type="as">
 | 
			
		||||
      <default><![CDATA[['<Primary><Alt>F7']]]></default>
 | 
			
		||||
      <_summary>Switch to VT 7</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
  </schema>
 | 
			
		||||
</schemalist>
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -148,6 +149,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
 | 
			
		||||
@@ -338,6 +342,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;
 | 
			
		||||
@@ -1529,6 +1530,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));
 | 
			
		||||
 | 
			
		||||
@@ -1565,9 +1569,35 @@ 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;
 | 
			
		||||
 | 
			
		||||
      meta_launcher_set_drm_fd (compositor->launcher, compositor->drm_fd);
 | 
			
		||||
 | 
			
		||||
      error = NULL;
 | 
			
		||||
      if (!meta_launcher_set_master (compositor->launcher, TRUE, &error))
 | 
			
		||||
	{
 | 
			
		||||
	  g_error ("Failed to 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",
 | 
			
		||||
@@ -1630,5 +1660,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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										432
									
								
								src/wayland/meta-weston-launch.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										432
									
								
								src/wayland/meta-weston-launch.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,432 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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;
 | 
			
		||||
  int drm_fd;
 | 
			
		||||
 | 
			
		||||
  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 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 && 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_master (MetaLauncher  *self,
 | 
			
		||||
			  gboolean       master,
 | 
			
		||||
			  GError       **error)
 | 
			
		||||
{
 | 
			
		||||
  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),
 | 
			
		||||
				   self->drm_fd, error) == FALSE)
 | 
			
		||||
    {
 | 
			
		||||
      g_object_unref (cmsg);
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  ok = send_message_to_wl (self->weston_launch, &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->weston_launch, 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)
 | 
			
		||||
{
 | 
			
		||||
  GError *error;
 | 
			
		||||
 | 
			
		||||
  error = NULL;
 | 
			
		||||
  if (!meta_launcher_set_master (launcher, TRUE, &error))
 | 
			
		||||
    {
 | 
			
		||||
      g_critical ("Failed to become DRM master: %s", error->message);
 | 
			
		||||
      g_error_free (error);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  clutter_evdev_reclaim_devices ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
meta_launcher_leave (MetaLauncher *launcher)
 | 
			
		||||
{
 | 
			
		||||
  GError *error;
 | 
			
		||||
 | 
			
		||||
  error = NULL;
 | 
			
		||||
  if (!meta_launcher_set_master (launcher, FALSE, &error))
 | 
			
		||||
    {
 | 
			
		||||
      g_critical ("Failed to release DRM master: %s", error->message);
 | 
			
		||||
      g_error_free (error);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  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->weston_launch, &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 void
 | 
			
		||||
on_socket_readable (GSocket      *socket,
 | 
			
		||||
		    GIOCondition  condition,
 | 
			
		||||
		    gpointer      user_data)
 | 
			
		||||
{
 | 
			
		||||
  MetaLauncher *launcher = user_data;
 | 
			
		||||
  struct weston_launcher_message header;
 | 
			
		||||
  gssize read;
 | 
			
		||||
  GError *error;
 | 
			
		||||
 | 
			
		||||
  if ((condition & G_IO_IN) == 0)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  error = NULL;
 | 
			
		||||
  read = g_socket_receive (socket, (char*)&header, sizeof(header), NULL, &error);
 | 
			
		||||
  if (read < (gssize)sizeof(header))
 | 
			
		||||
    {
 | 
			
		||||
      g_warning ("Error reading from weston-launcher socket: %s", error->message);
 | 
			
		||||
      g_error_free (error);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  switch (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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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->weston_launch, &message,
 | 
			
		||||
			     sizeof (message), NULL, NULL, error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
meta_launcher_set_drm_fd (MetaLauncher *launcher,
 | 
			
		||||
			  int           drm_fd)
 | 
			
		||||
{
 | 
			
		||||
  launcher->drm_fd = drm_fd;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								src/wayland/meta-weston-launch.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/wayland/meta-weston-launch.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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);
 | 
			
		||||
 | 
			
		||||
void              meta_launcher_set_drm_fd              (MetaLauncher  *self,
 | 
			
		||||
							 int            drm_fd);
 | 
			
		||||
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
 | 
			
		||||
							
								
								
									
										742
									
								
								src/wayland/weston-launch.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										742
									
								
								src/wayland/weston-launch.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,742 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2012 Benjamin Franzke
 | 
			
		||||
 *
 | 
			
		||||
 * 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 <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <poll.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#include <error.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/ioctl.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/signalfd.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
 | 
			
		||||
#include <termios.h>
 | 
			
		||||
#include <linux/vt.h>
 | 
			
		||||
#include <linux/major.h>
 | 
			
		||||
#include <linux/kd.h>
 | 
			
		||||
 | 
			
		||||
#include <pwd.h>
 | 
			
		||||
#include <grp.h>
 | 
			
		||||
#include <security/pam_appl.h>
 | 
			
		||||
 | 
			
		||||
#include <xf86drm.h>
 | 
			
		||||
 | 
			
		||||
#include <systemd/sd-login.h>
 | 
			
		||||
 | 
			
		||||
#include "weston-launch.h"
 | 
			
		||||
 | 
			
		||||
#define MAX_ARGV_SIZE 256
 | 
			
		||||
 | 
			
		||||
enum vt_state {
 | 
			
		||||
	VT_HAS_VT,
 | 
			
		||||
	VT_PENDING_CONFIRM,
 | 
			
		||||
	VT_NOT_HAVE_VT,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct weston_launch {
 | 
			
		||||
	struct pam_conv pc;
 | 
			
		||||
	pam_handle_t *ph;
 | 
			
		||||
	int tty;
 | 
			
		||||
	int ttynr;
 | 
			
		||||
	int sock[2];
 | 
			
		||||
	struct passwd *pw;
 | 
			
		||||
 | 
			
		||||
	int signalfd;
 | 
			
		||||
 | 
			
		||||
	pid_t child;
 | 
			
		||||
	int verbose;
 | 
			
		||||
	char *new_user;
 | 
			
		||||
 | 
			
		||||
	struct termios terminal_attributes;
 | 
			
		||||
	int kb_mode;
 | 
			
		||||
	enum vt_state vt_state;
 | 
			
		||||
	int expect_drop_master;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
union cmsg_data { unsigned char b[4]; int fd; };
 | 
			
		||||
 | 
			
		||||
static void quit (struct weston_launch *wl, int status);
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
weston_launch_allowed(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	char *session, *seat;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (getuid() == 0)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	err = sd_pid_get_session(getpid(), &session);
 | 
			
		||||
	if (err == 0 && session) {
 | 
			
		||||
		if (sd_session_is_active(session) &&
 | 
			
		||||
		    sd_session_get_seat(session, &seat) == 0) {
 | 
			
		||||
			free(seat);
 | 
			
		||||
			free(session);
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
		free(session);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
setup_launcher_socket(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, wl->sock) < 0)
 | 
			
		||||
		error(1, errno, "socketpair failed");
 | 
			
		||||
	
 | 
			
		||||
	fcntl(wl->sock[0], F_SETFD, O_CLOEXEC);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
setup_signals(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	sigset_t mask;
 | 
			
		||||
	struct sigaction sa;
 | 
			
		||||
 | 
			
		||||
	memset(&sa, 0, sizeof sa);
 | 
			
		||||
	sa.sa_handler = SIG_DFL;
 | 
			
		||||
	sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
 | 
			
		||||
	ret = sigaction(SIGCHLD, &sa, NULL);
 | 
			
		||||
	assert(ret == 0);
 | 
			
		||||
 | 
			
		||||
	sa.sa_handler = SIG_IGN;
 | 
			
		||||
	sa.sa_flags = 0;
 | 
			
		||||
	sigaction(SIGHUP, &sa, NULL);
 | 
			
		||||
 | 
			
		||||
	ret = sigemptyset(&mask);
 | 
			
		||||
	assert(ret == 0);
 | 
			
		||||
	sigaddset(&mask, SIGCHLD);
 | 
			
		||||
	sigaddset(&mask, SIGINT);
 | 
			
		||||
	sigaddset(&mask, SIGTERM);
 | 
			
		||||
	sigaddset(&mask, SIGUSR1);
 | 
			
		||||
	ret = sigprocmask(SIG_BLOCK, &mask, NULL);
 | 
			
		||||
	assert(ret == 0);
 | 
			
		||||
 | 
			
		||||
	wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
 | 
			
		||||
	if (wl->signalfd < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
setenv_fd(const char *env, int fd)
 | 
			
		||||
{
 | 
			
		||||
	char buf[32];
 | 
			
		||||
 | 
			
		||||
	snprintf(buf, sizeof buf, "%d", fd);
 | 
			
		||||
	setenv(env, buf, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handle_setmaster(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
 | 
			
		||||
{
 | 
			
		||||
	int ret = -1;
 | 
			
		||||
	struct cmsghdr *cmsg;
 | 
			
		||||
	struct weston_launcher_set_master *message;
 | 
			
		||||
	union cmsg_data *data;
 | 
			
		||||
 | 
			
		||||
	if (len != sizeof(*message)) {
 | 
			
		||||
		error(0, 0, "missing value in setmaster request");
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	message = msg->msg_iov->iov_base;
 | 
			
		||||
 | 
			
		||||
	cmsg = CMSG_FIRSTHDR(msg);
 | 
			
		||||
	if (!cmsg ||
 | 
			
		||||
	    cmsg->cmsg_level != SOL_SOCKET ||
 | 
			
		||||
	    cmsg->cmsg_type != SCM_RIGHTS) {
 | 
			
		||||
		error(0, 0, "invalid control message");
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data = (union cmsg_data *) CMSG_DATA(cmsg);
 | 
			
		||||
	if (data->fd == -1) {
 | 
			
		||||
		error(0, 0, "missing drm fd in socket request");
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (message->set_master)
 | 
			
		||||
		ret = drmSetMaster(data->fd);
 | 
			
		||||
	else
 | 
			
		||||
		ret = drmDropMaster(data->fd);
 | 
			
		||||
	if (ret == -1)
 | 
			
		||||
		ret = -errno;
 | 
			
		||||
 | 
			
		||||
	if (message->set_master == 0)
 | 
			
		||||
		wl->expect_drop_master = 0;
 | 
			
		||||
 | 
			
		||||
	close(data->fd);
 | 
			
		||||
 | 
			
		||||
	if (wl->verbose)
 | 
			
		||||
		fprintf(stderr, "weston-launch: %sMaster, ret: %d, fd: %d\n",
 | 
			
		||||
			message->set_master ? "set" : "drop", ret, data->fd);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	do {
 | 
			
		||||
		len = send(wl->sock[0], &ret, sizeof ret, 0);
 | 
			
		||||
	} while (len < 0 && errno == EINTR);
 | 
			
		||||
	if (len < 0)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handle_confirm_vt_switch(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
 | 
			
		||||
{
 | 
			
		||||
	int ret = -1;
 | 
			
		||||
 | 
			
		||||
	if (wl->vt_state != VT_PENDING_CONFIRM) {
 | 
			
		||||
		error(0, 0, "unexpected CONFIRM_VT_SWITCH");
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (wl->expect_drop_master) {
 | 
			
		||||
		error(0, 0, "drmDropMaster not called for VT switch");
 | 
			
		||||
		quit(wl, 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl->vt_state = VT_NOT_HAVE_VT;
 | 
			
		||||
	ioctl(wl->tty, VT_RELDISP, 1);
 | 
			
		||||
 | 
			
		||||
	if (wl->verbose)
 | 
			
		||||
		fprintf(stderr, "weston-launcher: confirmed VT switch\n");
 | 
			
		||||
 | 
			
		||||
	ret = 0;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	do {
 | 
			
		||||
		len = send(wl->sock[0], &ret, sizeof ret, 0);
 | 
			
		||||
	} while (len < 0 && errno == EINTR);
 | 
			
		||||
	if (len < 0)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handle_activate_vt(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
 | 
			
		||||
{
 | 
			
		||||
	int ret = -1;
 | 
			
		||||
	struct weston_launcher_activate_vt *message;
 | 
			
		||||
 | 
			
		||||
	if (len != sizeof(*message)) {
 | 
			
		||||
		error(0, 0, "missing value in activate_vt request");
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	message = msg->msg_iov->iov_base;
 | 
			
		||||
 | 
			
		||||
	ret = ioctl(wl->tty, VT_ACTIVATE, message->vt);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		ret = -errno;
 | 
			
		||||
 | 
			
		||||
	if (wl->verbose)
 | 
			
		||||
		fprintf(stderr, "weston-launch: activate VT, ret: %d\n", ret);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	do {
 | 
			
		||||
		len = send(wl->sock[0], &ret, sizeof ret, 0);
 | 
			
		||||
	} while (len < 0 && errno == EINTR);
 | 
			
		||||
	if (len < 0)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
 | 
			
		||||
{
 | 
			
		||||
	int fd = -1, ret = -1;
 | 
			
		||||
	char control[CMSG_SPACE(sizeof(fd))];
 | 
			
		||||
	struct cmsghdr *cmsg;
 | 
			
		||||
	struct stat s;
 | 
			
		||||
	struct msghdr nmsg;
 | 
			
		||||
	struct iovec iov;
 | 
			
		||||
	struct weston_launcher_open *message;
 | 
			
		||||
	union cmsg_data *data;
 | 
			
		||||
 | 
			
		||||
	message = msg->msg_iov->iov_base;
 | 
			
		||||
	if ((size_t)len < sizeof(*message))
 | 
			
		||||
		goto err0;
 | 
			
		||||
 | 
			
		||||
	/* Ensure path is null-terminated */
 | 
			
		||||
	((char *) message)[len-1] = '\0';
 | 
			
		||||
 | 
			
		||||
	if (stat(message->path, &s) < 0)
 | 
			
		||||
		goto err0;
 | 
			
		||||
 | 
			
		||||
	fd = open(message->path, message->flags);
 | 
			
		||||
	if (fd < 0) {
 | 
			
		||||
		fprintf(stderr, "Error opening device %s: %m\n",
 | 
			
		||||
			message->path);
 | 
			
		||||
		goto err0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (major(s.st_rdev) != INPUT_MAJOR) {
 | 
			
		||||
		close(fd);
 | 
			
		||||
		fd = -1;
 | 
			
		||||
		fprintf(stderr, "Device %s is not an input device\n",
 | 
			
		||||
			message->path);
 | 
			
		||||
		goto err0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
err0:
 | 
			
		||||
	memset(&nmsg, 0, sizeof nmsg);
 | 
			
		||||
	nmsg.msg_iov = &iov;
 | 
			
		||||
	nmsg.msg_iovlen = 1;
 | 
			
		||||
	if (fd != -1) {
 | 
			
		||||
		nmsg.msg_control = control;
 | 
			
		||||
		nmsg.msg_controllen = sizeof control;
 | 
			
		||||
		cmsg = CMSG_FIRSTHDR(&nmsg);
 | 
			
		||||
		cmsg->cmsg_level = SOL_SOCKET;
 | 
			
		||||
		cmsg->cmsg_type = SCM_RIGHTS;
 | 
			
		||||
		cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
 | 
			
		||||
		data = (union cmsg_data *) CMSG_DATA(cmsg);
 | 
			
		||||
		data->fd = fd;
 | 
			
		||||
		nmsg.msg_controllen = cmsg->cmsg_len;
 | 
			
		||||
		ret = 0;
 | 
			
		||||
	}
 | 
			
		||||
	iov.iov_base = &ret;
 | 
			
		||||
	iov.iov_len = sizeof ret;
 | 
			
		||||
 | 
			
		||||
	if (wl->verbose)
 | 
			
		||||
		fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
 | 
			
		||||
			message->path, ret, fd);
 | 
			
		||||
	do {
 | 
			
		||||
		len = sendmsg(wl->sock[0], &nmsg, 0);
 | 
			
		||||
	} while (len < 0 && errno == EINTR);
 | 
			
		||||
 | 
			
		||||
	close(fd);
 | 
			
		||||
 | 
			
		||||
	if (len < 0)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handle_socket_msg(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	char control[CMSG_SPACE(sizeof(int))];
 | 
			
		||||
	char buf[BUFSIZ];
 | 
			
		||||
	struct msghdr msg;
 | 
			
		||||
	struct iovec iov;
 | 
			
		||||
	int ret = -1;
 | 
			
		||||
	ssize_t len;
 | 
			
		||||
	struct weston_launcher_message *message;
 | 
			
		||||
 | 
			
		||||
	memset(&msg, 0, sizeof(msg));
 | 
			
		||||
	iov.iov_base = buf;
 | 
			
		||||
	iov.iov_len  = sizeof buf;
 | 
			
		||||
	msg.msg_iov = &iov;
 | 
			
		||||
	msg.msg_iovlen = 1;
 | 
			
		||||
	msg.msg_control = control;
 | 
			
		||||
	msg.msg_controllen = sizeof control;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		len = recvmsg(wl->sock[0], &msg, 0);
 | 
			
		||||
	} while (len < 0 && errno == EINTR);
 | 
			
		||||
 | 
			
		||||
	if (len < 1)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	message = (void *) buf;
 | 
			
		||||
	switch (message->opcode) {
 | 
			
		||||
	case WESTON_LAUNCHER_OPEN:
 | 
			
		||||
		ret = handle_open(wl, &msg, len);
 | 
			
		||||
		break;
 | 
			
		||||
	case WESTON_LAUNCHER_DRM_SET_MASTER:
 | 
			
		||||
		ret = handle_setmaster(wl, &msg, len);
 | 
			
		||||
		break;
 | 
			
		||||
	case WESTON_LAUNCHER_CONFIRM_VT_SWITCH:
 | 
			
		||||
		ret = handle_confirm_vt_switch(wl, &msg, len);
 | 
			
		||||
		break;
 | 
			
		||||
	case WESTON_LAUNCHER_ACTIVATE_VT:
 | 
			
		||||
		ret = handle_activate_vt(wl, &msg, len);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
tty_reset(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	struct vt_mode mode = { 0 };
 | 
			
		||||
 | 
			
		||||
	if (ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
 | 
			
		||||
		fprintf(stderr, "failed to restore keyboard mode: %m\n");
 | 
			
		||||
 | 
			
		||||
	if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
 | 
			
		||||
		fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
 | 
			
		||||
 | 
			
		||||
	if (tcsetattr(wl->tty, TCSANOW, &wl->terminal_attributes) < 0)
 | 
			
		||||
		fprintf(stderr, "could not restore terminal to canonical mode\n");
 | 
			
		||||
 | 
			
		||||
	mode.mode = VT_AUTO;
 | 
			
		||||
	if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
 | 
			
		||||
		fprintf(stderr, "could not reset vt handling\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
quit(struct weston_launch *wl, int status)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (wl->child > 0)
 | 
			
		||||
		kill(wl->child, SIGKILL);
 | 
			
		||||
 | 
			
		||||
	close(wl->signalfd);
 | 
			
		||||
	close(wl->sock[0]);
 | 
			
		||||
 | 
			
		||||
	tty_reset(wl);
 | 
			
		||||
 | 
			
		||||
	if (wl->new_user) {
 | 
			
		||||
		err = pam_close_session(wl->ph, 0);
 | 
			
		||||
		if (err)
 | 
			
		||||
			fprintf(stderr, "pam_close_session failed: %d: %s\n",
 | 
			
		||||
				err, pam_strerror(wl->ph, err));
 | 
			
		||||
		pam_end(wl->ph, err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	exit(status);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handle_vt_switch(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	struct weston_launcher_message message;
 | 
			
		||||
	ssize_t len;
 | 
			
		||||
 | 
			
		||||
	if (wl->vt_state == VT_HAS_VT) {
 | 
			
		||||
		wl->vt_state = VT_PENDING_CONFIRM;
 | 
			
		||||
		wl->expect_drop_master = 1;
 | 
			
		||||
		message.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);
 | 
			
		||||
 | 
			
		||||
		message.opcode = WESTON_LAUNCHER_SERVER_VT_ENTER;
 | 
			
		||||
	} else
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		len = send(wl->sock[0], &message, sizeof(message), 0);
 | 
			
		||||
	} while (len < 0 && errno == EINTR);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
handle_signal(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	struct signalfd_siginfo sig;
 | 
			
		||||
	int pid, status, ret;
 | 
			
		||||
 | 
			
		||||
	if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
 | 
			
		||||
		error(0, errno, "reading signalfd failed");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (sig.ssi_signo) {
 | 
			
		||||
	case SIGCHLD:
 | 
			
		||||
		pid = waitpid(-1, &status, 0);
 | 
			
		||||
		if (pid == wl->child) {
 | 
			
		||||
			wl->child = 0;
 | 
			
		||||
			if (WIFEXITED(status))
 | 
			
		||||
				ret = WEXITSTATUS(status);
 | 
			
		||||
			else if (WIFSIGNALED(status))
 | 
			
		||||
				/*
 | 
			
		||||
				 * If weston dies because of signal N, we
 | 
			
		||||
				 * return 10+N. This is distinct from
 | 
			
		||||
				 * weston-launch dying because of a signal
 | 
			
		||||
				 * (128+N).
 | 
			
		||||
				 */
 | 
			
		||||
				ret = 10 + WTERMSIG(status);
 | 
			
		||||
			else
 | 
			
		||||
				ret = 0;
 | 
			
		||||
			quit(wl, ret);
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case SIGTERM:
 | 
			
		||||
	case SIGINT:
 | 
			
		||||
		if (wl->child)
 | 
			
		||||
			kill(wl->child, sig.ssi_signo);
 | 
			
		||||
		break;
 | 
			
		||||
	case SIGUSR1:
 | 
			
		||||
		return handle_vt_switch(wl);
 | 
			
		||||
	default:
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
setup_tty(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	struct stat buf;
 | 
			
		||||
	struct termios raw_attributes;
 | 
			
		||||
	struct vt_mode mode = { 0 };
 | 
			
		||||
	char *session, *tty;
 | 
			
		||||
	char path[PATH_MAX];
 | 
			
		||||
	int ok;
 | 
			
		||||
 | 
			
		||||
	ok = sd_pid_get_session(getpid(), &session);
 | 
			
		||||
	if (ok < 0)
 | 
			
		||||
	  error(1, -ok, "could not determine current session");
 | 
			
		||||
 | 
			
		||||
	ok = sd_session_get_tty(session, &tty);
 | 
			
		||||
	if (ok == 0) {
 | 
			
		||||
		snprintf(path, PATH_MAX, "/dev/%s", tty);
 | 
			
		||||
		wl->tty = open(path, O_RDWR | O_NOCTTY | O_CLOEXEC);
 | 
			
		||||
		free(tty);
 | 
			
		||||
#ifdef HAVE_SD_SESSION_GET_VT
 | 
			
		||||
	} else if (ok == -ENOENT) {
 | 
			
		||||
		/* Negative errnos are cool, right?
 | 
			
		||||
		   So cool that we can't distinguish "session not found"
 | 
			
		||||
		   from "key does not exist in the session file"!
 | 
			
		||||
		   Let's assume the latter, as we got the value
 | 
			
		||||
		   from sd_pid_get_session()...
 | 
			
		||||
		*/
 | 
			
		||||
 | 
			
		||||
		ok = sd_session_get_vt(session, &tty);
 | 
			
		||||
		if (ok < 0)
 | 
			
		||||
			error(1, -ok, "could not determine current TTY");
 | 
			
		||||
 | 
			
		||||
		snprintf(path, PATH_MAX, "/dev/tty%s", tty);
 | 
			
		||||
		wl->tty = open(path, O_RDWR | O_NOCTTY | O_CLOEXEC);
 | 
			
		||||
		free(tty);
 | 
			
		||||
#endif
 | 
			
		||||
	} else
 | 
			
		||||
		error(1, -ok, "could not determine current TTY");
 | 
			
		||||
 | 
			
		||||
	if (wl->tty < 0)
 | 
			
		||||
		error(1, errno, "failed to open tty");
 | 
			
		||||
 | 
			
		||||
	if (fstat(wl->tty, &buf) < 0)
 | 
			
		||||
		error(1, errno, "stat %s failed", path);
 | 
			
		||||
 | 
			
		||||
	if (major(buf.st_rdev) != TTY_MAJOR)
 | 
			
		||||
		error(1, 0, "invalid tty device: %s", path);
 | 
			
		||||
 | 
			
		||||
	wl->ttynr = minor(buf.st_rdev);
 | 
			
		||||
 | 
			
		||||
	if (tcgetattr(wl->tty, &wl->terminal_attributes) < 0)
 | 
			
		||||
		error(1, errno, "could not get terminal attributes");
 | 
			
		||||
 | 
			
		||||
	/* Ignore control characters and disable echo */
 | 
			
		||||
	raw_attributes = wl->terminal_attributes;
 | 
			
		||||
	cfmakeraw(&raw_attributes);
 | 
			
		||||
 | 
			
		||||
	/* Fix up line endings to be normal (cfmakeraw hoses them) */
 | 
			
		||||
	raw_attributes.c_oflag |= OPOST | OCRNL;
 | 
			
		||||
	/* Don't generate ttou signals */
 | 
			
		||||
	raw_attributes.c_oflag &= ~TOSTOP;
 | 
			
		||||
 | 
			
		||||
	if (tcsetattr(wl->tty, TCSANOW, &raw_attributes) < 0)
 | 
			
		||||
	        error(1, errno, "could not put terminal into raw mode");
 | 
			
		||||
 | 
			
		||||
	ioctl(wl->tty, KDGKBMODE, &wl->kb_mode);
 | 
			
		||||
	ok = ioctl(wl->tty, KDSKBMODE, K_OFF);
 | 
			
		||||
	if (ok < 0) {
 | 
			
		||||
		ok = ioctl(wl->tty, KDSKBMODE, K_RAW);
 | 
			
		||||
		if (ok < 0)
 | 
			
		||||
			error(1, errno, "failed to set keyboard mode on tty");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ok = ioctl(wl->tty, KDSETMODE, KD_GRAPHICS);
 | 
			
		||||
	if (ok < 0)
 | 
			
		||||
		error(1, errno, "failed to set KD_GRAPHICS mode on tty");
 | 
			
		||||
 | 
			
		||||
	wl->vt_state = VT_HAS_VT;
 | 
			
		||||
	mode.mode = VT_PROCESS;
 | 
			
		||||
	mode.relsig = SIGUSR1;
 | 
			
		||||
	mode.acqsig = SIGUSR1;
 | 
			
		||||
	ok = ioctl(wl->tty, VT_SETMODE, &mode);
 | 
			
		||||
	if (ok < 0)
 | 
			
		||||
		error(1, errno, "failed to take control of vt handling");
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
drop_privileges(struct weston_launch *wl)
 | 
			
		||||
{
 | 
			
		||||
	if (setgid(wl->pw->pw_gid) < 0 ||
 | 
			
		||||
#ifdef HAVE_INITGROUPS
 | 
			
		||||
	    initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
 | 
			
		||||
#endif
 | 
			
		||||
	    setuid(wl->pw->pw_uid) < 0)
 | 
			
		||||
		error(1, errno, "dropping privileges failed");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
launch_compositor(struct weston_launch *wl, int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
	char command[PATH_MAX];
 | 
			
		||||
	char *child_argv[MAX_ARGV_SIZE];
 | 
			
		||||
	sigset_t mask;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (wl->verbose)
 | 
			
		||||
		printf("weston-launch: spawned weston with pid: %d\n", getpid());
 | 
			
		||||
 | 
			
		||||
	drop_privileges(wl);
 | 
			
		||||
 | 
			
		||||
	setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
 | 
			
		||||
	setenv("LD_LIBRARY_PATH", LIBDIR, 1);
 | 
			
		||||
	unsetenv("DISPLAY");
 | 
			
		||||
 | 
			
		||||
	/* Do not give our signal mask to the new process. */
 | 
			
		||||
	sigemptyset(&mask);
 | 
			
		||||
	sigaddset(&mask, SIGTERM);
 | 
			
		||||
	sigaddset(&mask, SIGCHLD);
 | 
			
		||||
	sigaddset(&mask, SIGINT);
 | 
			
		||||
	sigaddset(&mask, SIGUSR1);
 | 
			
		||||
	sigprocmask(SIG_UNBLOCK, &mask, NULL);
 | 
			
		||||
 | 
			
		||||
	snprintf (command, PATH_MAX, "%s \"$@\"", argv[0]);
 | 
			
		||||
 | 
			
		||||
	child_argv[0] = wl->pw->pw_shell;
 | 
			
		||||
	child_argv[1] = "-l";
 | 
			
		||||
	child_argv[2] = "-c";
 | 
			
		||||
	child_argv[3] = command;
 | 
			
		||||
	for (i = 0; i < argc; ++i)
 | 
			
		||||
		child_argv[4 + i] = argv[i];
 | 
			
		||||
	child_argv[4 + i] = NULL;
 | 
			
		||||
 | 
			
		||||
	execv(child_argv[0], child_argv);
 | 
			
		||||
	error(1, errno, "exec failed");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
help(const char *name)
 | 
			
		||||
{
 | 
			
		||||
	fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
 | 
			
		||||
	fprintf(stderr, "  -u, --user      Start session as specified username\n");
 | 
			
		||||
	fprintf(stderr, "  -v, --verbose   Be verbose\n");
 | 
			
		||||
	fprintf(stderr, "  -h, --help      Display this help message\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main(int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
	struct weston_launch wl;
 | 
			
		||||
	int i, c;
 | 
			
		||||
	struct option opts[] = {
 | 
			
		||||
		{ "verbose", no_argument,       NULL, 'v' },
 | 
			
		||||
		{ "help",    no_argument,       NULL, 'h' },
 | 
			
		||||
		{ 0,         0,                 NULL,  0  }
 | 
			
		||||
	};	
 | 
			
		||||
 | 
			
		||||
	memset(&wl, 0, sizeof wl);
 | 
			
		||||
 | 
			
		||||
	while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
 | 
			
		||||
		switch (c) {
 | 
			
		||||
		case 'v':
 | 
			
		||||
			wl.verbose = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'h':
 | 
			
		||||
			help("weston-launch");
 | 
			
		||||
			exit(EXIT_FAILURE);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((argc - optind) > (MAX_ARGV_SIZE - 6))
 | 
			
		||||
		error(1, E2BIG, "Too many arguments to pass to weston");
 | 
			
		||||
 | 
			
		||||
	if (strcmp (argv[optind], "mutter-wayland") &&
 | 
			
		||||
	    strcmp (argv[optind], "gnome-shell-wayland"))
 | 
			
		||||
	  error(1, 0, "mutter-launch can only be used to launch mutter or gnome-shell");
 | 
			
		||||
 | 
			
		||||
	wl.pw = getpwuid(getuid());
 | 
			
		||||
	if (wl.pw == NULL)
 | 
			
		||||
		error(1, errno, "failed to get username");
 | 
			
		||||
 | 
			
		||||
	if (!weston_launch_allowed(&wl))
 | 
			
		||||
		error(1, 0, "Permission denied. You must run from an active and local (systemd) session.");
 | 
			
		||||
 | 
			
		||||
	if (setup_tty(&wl) < 0)
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
 | 
			
		||||
	if (setup_launcher_socket(&wl) < 0)
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
 | 
			
		||||
	if (setup_signals(&wl) < 0)
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
 | 
			
		||||
	wl.child = fork();
 | 
			
		||||
	if (wl.child == -1) {
 | 
			
		||||
		error(1, errno, "fork failed");
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (wl.child == 0)
 | 
			
		||||
		launch_compositor(&wl, argc - optind, argv + optind);
 | 
			
		||||
 | 
			
		||||
	close(wl.sock[1]);
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
		struct pollfd fds[2];
 | 
			
		||||
		int n;
 | 
			
		||||
 | 
			
		||||
		fds[0].fd = wl.sock[0];
 | 
			
		||||
		fds[0].events = POLLIN;
 | 
			
		||||
		fds[1].fd = wl.signalfd;
 | 
			
		||||
		fds[1].events = POLLIN;
 | 
			
		||||
 | 
			
		||||
		n = poll(fds, 2, -1);
 | 
			
		||||
		if (n < 0)
 | 
			
		||||
			error(0, errno, "poll failed");
 | 
			
		||||
		if (fds[0].revents & POLLIN)
 | 
			
		||||
			handle_socket_msg(&wl);
 | 
			
		||||
		if (fds[1].revents)
 | 
			
		||||
			handle_signal(&wl);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										59
									
								
								src/wayland/weston-launch.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/wayland/weston-launch.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright © 2012 Benjamin Franzke
 | 
			
		||||
 *             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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _WESTON_LAUNCH_H_
 | 
			
		||||
#define _WESTON_LAUNCH_H_
 | 
			
		||||
 | 
			
		||||
enum weston_launcher_opcode {
 | 
			
		||||
	WESTON_LAUNCHER_OPEN,
 | 
			
		||||
	WESTON_LAUNCHER_DRM_SET_MASTER,
 | 
			
		||||
	WESTON_LAUNCHER_ACTIVATE_VT,
 | 
			
		||||
	WESTON_LAUNCHER_CONFIRM_VT_SWITCH, 
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum weston_launcher_server_opcode {
 | 
			
		||||
	WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH,
 | 
			
		||||
	WESTON_LAUNCHER_SERVER_VT_ENTER,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct weston_launcher_activate_vt {
 | 
			
		||||
	struct weston_launcher_message header;
 | 
			
		||||
	int vt;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
		Reference in New Issue
	
	Block a user