Compare commits
38 Commits
wip/resize
...
wip/login1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
283dec74c1 | ||
|
|
4fec9e4eba | ||
|
|
68626eb9cd | ||
|
|
1436017344 | ||
|
|
8fdeb17e60 | ||
|
|
857561baed | ||
|
|
a44cc9ef47 | ||
|
|
d47b7ba038 | ||
|
|
f21312e2fd | ||
|
|
394af33607 | ||
|
|
7314cdac94 | ||
|
|
81025e37ea | ||
|
|
1bb9f1e333 | ||
|
|
b11c75c1c9 | ||
|
|
757b626aee | ||
|
|
fb3df5243f | ||
|
|
e34792d9f0 | ||
|
|
f397c32192 | ||
|
|
f79314d7b5 | ||
|
|
55c61259d8 | ||
|
|
5298cf0a3a | ||
|
|
f1dc1a0cbc | ||
|
|
2cf80bc647 | ||
|
|
40c15f6e2a | ||
|
|
a8849621c9 | ||
|
|
49c0be11d6 | ||
|
|
9df8e831be | ||
|
|
84c6b2a3fa | ||
|
|
06cd669ccb | ||
|
|
81eb7d9537 | ||
|
|
dd8d8e436d | ||
|
|
d6b6b363ad | ||
|
|
254e2e993c | ||
|
|
c595a9c29f | ||
|
|
dfc7f7222b | ||
|
|
ef278eb547 | ||
|
|
38e26e5cc3 | ||
|
|
9773a879c3 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -48,7 +48,6 @@ po/*.pot
|
||||
50-metacity-key.xml
|
||||
libmutter-wayland.pc
|
||||
mutter-wayland
|
||||
mutter-launch
|
||||
org.gnome.mutter.gschema.valid
|
||||
org.gnome.mutter.gschema.xml
|
||||
org.gnome.mutter.wayland.gschema.valid
|
||||
@@ -77,6 +76,7 @@ src/mutter-marshal.[ch]
|
||||
src/stamp-mutter-marshal.h
|
||||
src/meta-dbus-xrandr.[ch]
|
||||
src/meta-dbus-idle-monitor.[ch]
|
||||
src/meta-dbus-login1.[ch]
|
||||
src/mutter-plugins.pc
|
||||
src/wayland/gtk-shell-protocol.c
|
||||
src/wayland/gtk-shell-server-protocol.h
|
||||
|
||||
@@ -140,12 +140,6 @@ 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"
|
||||
@@ -218,7 +212,7 @@ AS_IF([test "x$WAYLAND_SCANNER" = "xno"],
|
||||
AC_SUBST([WAYLAND_SCANNER])
|
||||
AC_SUBST(XWAYLAND_PATH)
|
||||
|
||||
MUTTER_PC_MODULES="$MUTTER_PC_MODULES clutter-wayland-1.0 clutter-wayland-compositor-1.0 clutter-egl-1.0 wayland-server libdrm"
|
||||
MUTTER_PC_MODULES="$MUTTER_PC_MODULES clutter-wayland-1.0 clutter-wayland-compositor-1.0 clutter-egl-1.0 wayland-server libdrm libsystemd"
|
||||
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
|
||||
|
||||
PKG_CHECK_EXISTS([xi >= 1.6.99.1],
|
||||
|
||||
@@ -39,6 +39,7 @@ INCLUDES += \
|
||||
mutter_built_sources = \
|
||||
$(dbus_idle_built_sources) \
|
||||
$(dbus_xrandr_built_sources) \
|
||||
$(dbus_login1_built_sources) \
|
||||
mutter-enum-types.h \
|
||||
mutter-enum-types.c \
|
||||
wayland/gtk-shell-protocol.c \
|
||||
@@ -207,8 +208,8 @@ libmutter_wayland_la_SOURCES = \
|
||||
wayland/meta-wayland-surface.h \
|
||||
wayland/meta-wayland-types.h \
|
||||
wayland/meta-wayland-versions.h \
|
||||
wayland/meta-weston-launch.c \
|
||||
wayland/meta-weston-launch.h
|
||||
wayland/meta-login1.c \
|
||||
wayland/meta-login1.h
|
||||
|
||||
nodist_libmutter_wayland_la_SOURCES = \
|
||||
$(mutter_built_sources)
|
||||
@@ -263,17 +264,6 @@ 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)
|
||||
|
||||
@@ -409,6 +399,15 @@ $(dbus_idle_built_sources) : Makefile.am idle-monitor.xml
|
||||
--c-generate-object-manager \
|
||||
$(srcdir)/idle-monitor.xml
|
||||
|
||||
dbus_login1_built_sources = meta-dbus-login1.c meta-dbus-login1.h
|
||||
|
||||
$(dbus_login1_built_sources) : Makefile.am org.freedesktop.login1.xml
|
||||
$(AM_V_GEN)gdbus-codegen \
|
||||
--interface-prefix org.freedesktop.login1 \
|
||||
--c-namespace Login1 \
|
||||
--generate-c-code meta-dbus-login1 \
|
||||
$(srcdir)/org.freedesktop.login1.xml
|
||||
|
||||
wayland/%-protocol.c : $(top_builddir)/protocol/%.xml
|
||||
mkdir -p wayland
|
||||
$(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@
|
||||
|
||||
@@ -436,45 +436,6 @@ begin_modal_x11 (MetaScreen *screen,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
begin_modal_wayland (MetaScreen *screen,
|
||||
MetaPlugin *plugin,
|
||||
MetaModalOptions options,
|
||||
guint32 timestamp)
|
||||
{
|
||||
MetaWaylandCompositor *compositor;
|
||||
gboolean pointer_grabbed = FALSE;
|
||||
gboolean keyboard_grabbed = FALSE;
|
||||
|
||||
compositor = meta_wayland_compositor_get_default ();
|
||||
|
||||
if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0)
|
||||
{
|
||||
if (!meta_wayland_pointer_begin_modal (&compositor->seat->pointer))
|
||||
goto fail;
|
||||
|
||||
pointer_grabbed = TRUE;
|
||||
}
|
||||
if ((options & META_MODAL_KEYBOARD_ALREADY_GRABBED) == 0)
|
||||
{
|
||||
if (!meta_wayland_keyboard_begin_modal (&compositor->seat->keyboard,
|
||||
timestamp))
|
||||
goto fail;
|
||||
|
||||
keyboard_grabbed = TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
if (pointer_grabbed)
|
||||
meta_wayland_pointer_end_modal (&compositor->seat->pointer);
|
||||
if (keyboard_grabbed)
|
||||
meta_wayland_keyboard_end_modal (&compositor->seat->keyboard, timestamp);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_begin_modal_for_plugin (MetaScreen *screen,
|
||||
MetaPlugin *plugin,
|
||||
@@ -493,7 +454,7 @@ meta_begin_modal_for_plugin (MetaScreen *screen,
|
||||
return FALSE;
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
ok = begin_modal_wayland (screen, plugin, options, timestamp);
|
||||
ok = TRUE;
|
||||
else
|
||||
ok = begin_modal_x11 (screen, plugin, options, timestamp);
|
||||
if (!ok)
|
||||
@@ -521,15 +482,7 @@ meta_end_modal_for_plugin (MetaScreen *screen,
|
||||
|
||||
g_return_if_fail (compositor->modal_plugin == plugin);
|
||||
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
||||
|
||||
meta_wayland_pointer_end_modal (&compositor->seat->pointer);
|
||||
meta_wayland_keyboard_end_modal (&compositor->seat->keyboard,
|
||||
timestamp);
|
||||
}
|
||||
else
|
||||
if (!meta_is_wayland_compositor ())
|
||||
{
|
||||
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
|
||||
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
|
||||
|
||||
@@ -425,8 +425,9 @@ setup_constraint_info (ConstraintInfo *info,
|
||||
* the monitor.
|
||||
*/
|
||||
if (meta_prefs_get_force_fullscreen() &&
|
||||
window->client_type != META_WINDOW_CLIENT_TYPE_WAYLAND &&
|
||||
!window->hide_titlebar_when_maximized &&
|
||||
window->decorated &&
|
||||
(window->decorated || !meta_window_is_client_decorated (window)) &&
|
||||
meta_rectangle_equal (new, &monitor_info->rect) &&
|
||||
window->has_fullscreen_func &&
|
||||
!window->fullscreen)
|
||||
|
||||
@@ -1295,10 +1295,6 @@ meta_get_display (void)
|
||||
return the_display;
|
||||
}
|
||||
|
||||
#ifdef WITH_VERBOSE_MODE
|
||||
static gboolean dump_events = TRUE;
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
grab_op_is_mouse_only (MetaGrabOp op)
|
||||
{
|
||||
@@ -1418,6 +1414,20 @@ meta_grab_op_is_moving (MetaGrabOp op)
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
grab_op_should_block_mouse_events (MetaGrabOp op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case META_GRAB_OP_WAYLAND_CLIENT:
|
||||
case META_GRAB_OP_COMPOSITOR:
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_display_xserver_time_is_before:
|
||||
* @display: a #MetaDisplay
|
||||
@@ -2054,7 +2064,7 @@ meta_display_handle_event (MetaDisplay *display,
|
||||
switch (event->type)
|
||||
{
|
||||
case CLUTTER_BUTTON_PRESS:
|
||||
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
|
||||
if (grab_op_should_block_mouse_events (display->grab_op))
|
||||
break;
|
||||
|
||||
display->overlay_key_only_pressed = FALSE;
|
||||
@@ -2226,7 +2236,7 @@ meta_display_handle_event (MetaDisplay *display,
|
||||
}
|
||||
break;
|
||||
case CLUTTER_BUTTON_RELEASE:
|
||||
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
|
||||
if (grab_op_should_block_mouse_events (display->grab_op))
|
||||
break;
|
||||
|
||||
display->overlay_key_only_pressed = FALSE;
|
||||
@@ -2240,7 +2250,7 @@ meta_display_handle_event (MetaDisplay *display,
|
||||
}
|
||||
break;
|
||||
case CLUTTER_MOTION:
|
||||
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
|
||||
if (grab_op_should_block_mouse_events (display->grab_op))
|
||||
break;
|
||||
|
||||
if (display->grab_window == window &&
|
||||
@@ -2274,6 +2284,10 @@ meta_display_handle_event (MetaDisplay *display,
|
||||
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
|
||||
bypass_wayland = TRUE;
|
||||
|
||||
/* If a Wayland client has a grab, don't pass that through to Clutter */
|
||||
if (display->grab_op == META_GRAB_OP_WAYLAND_CLIENT)
|
||||
bypass_clutter = TRUE;
|
||||
|
||||
if (compositor && !bypass_wayland)
|
||||
{
|
||||
if (meta_wayland_compositor_handle_event (compositor, event))
|
||||
@@ -2974,9 +2988,8 @@ meta_display_handle_xevent (MetaDisplay *display,
|
||||
MetaMonitorManager *monitor;
|
||||
MetaScreen *screen;
|
||||
|
||||
#ifdef WITH_VERBOSE_MODE
|
||||
if (dump_events)
|
||||
meta_spew_event (display, event);
|
||||
#if 0
|
||||
meta_spew_event (display, event);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STARTUP_NOTIFICATION
|
||||
@@ -3252,8 +3265,7 @@ event_get_time (MetaDisplay *display,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_VERBOSE_MODE
|
||||
const char*
|
||||
G_GNUC_UNUSED const char*
|
||||
meta_event_detail_to_string (int d)
|
||||
{
|
||||
const char *detail = "???";
|
||||
@@ -3289,10 +3301,8 @@ meta_event_detail_to_string (int d)
|
||||
|
||||
return detail;
|
||||
}
|
||||
#endif /* WITH_VERBOSE_MODE */
|
||||
|
||||
#ifdef WITH_VERBOSE_MODE
|
||||
const char*
|
||||
G_GNUC_UNUSED const char*
|
||||
meta_event_mode_to_string (int m)
|
||||
{
|
||||
const char *mode = "???";
|
||||
@@ -3314,10 +3324,8 @@ meta_event_mode_to_string (int m)
|
||||
|
||||
return mode;
|
||||
}
|
||||
#endif /* WITH_VERBOSE_MODE */
|
||||
|
||||
#ifdef WITH_VERBOSE_MODE
|
||||
static const char*
|
||||
G_GNUC_UNUSED static const char*
|
||||
stack_mode_to_string (int mode)
|
||||
{
|
||||
switch (mode)
|
||||
@@ -3336,11 +3344,9 @@ stack_mode_to_string (int mode)
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
#endif /* WITH_VERBOSE_MODE */
|
||||
|
||||
#ifdef HAVE_XSYNC
|
||||
#ifdef WITH_VERBOSE_MODE
|
||||
static gint64
|
||||
G_GNUC_UNUSED static gint64
|
||||
sync_value_to_64 (const XSyncValue *value)
|
||||
{
|
||||
gint64 v;
|
||||
@@ -3350,10 +3356,8 @@ sync_value_to_64 (const XSyncValue *value)
|
||||
|
||||
return v;
|
||||
}
|
||||
#endif /* WITH_VERBOSE_MODE */
|
||||
|
||||
#ifdef WITH_VERBOSE_MODE
|
||||
static const char*
|
||||
G_GNUC_UNUSED static const char*
|
||||
alarm_state_to_string (XSyncAlarmState state)
|
||||
{
|
||||
switch (state)
|
||||
@@ -3368,12 +3372,9 @@ alarm_state_to_string (XSyncAlarmState state)
|
||||
return "(unknown)";
|
||||
}
|
||||
}
|
||||
#endif /* WITH_VERBOSE_MODE */
|
||||
|
||||
#endif /* HAVE_XSYNC */
|
||||
|
||||
#ifdef WITH_VERBOSE_MODE
|
||||
static void
|
||||
G_GNUC_UNUSED static void
|
||||
meta_spew_xi2_event (MetaDisplay *display,
|
||||
XIEvent *input_event,
|
||||
const char **name_p,
|
||||
@@ -3433,7 +3434,7 @@ meta_spew_xi2_event (MetaDisplay *display,
|
||||
*extra_p = extra;
|
||||
}
|
||||
|
||||
static void
|
||||
G_GNUC_UNUSED static void
|
||||
meta_spew_core_event (MetaDisplay *display,
|
||||
XEvent *event,
|
||||
const char **name_p,
|
||||
@@ -3657,7 +3658,7 @@ meta_spew_core_event (MetaDisplay *display,
|
||||
*extra_p = extra;
|
||||
}
|
||||
|
||||
static void
|
||||
G_GNUC_UNUSED static void
|
||||
meta_spew_event (MetaDisplay *display,
|
||||
XEvent *event)
|
||||
{
|
||||
@@ -3666,9 +3667,6 @@ meta_spew_event (MetaDisplay *display,
|
||||
char *winname;
|
||||
MetaScreen *screen;
|
||||
XIEvent *input_event;
|
||||
|
||||
if (!meta_is_verbose())
|
||||
return;
|
||||
|
||||
/* filter overnumerous events */
|
||||
if (event->type == Expose || event->type == MotionNotify ||
|
||||
@@ -3698,18 +3696,16 @@ meta_spew_event (MetaDisplay *display,
|
||||
else
|
||||
winname = g_strdup_printf ("0x%lx", event->xany.window);
|
||||
|
||||
meta_topic (META_DEBUG_EVENTS,
|
||||
"%s on %s%s %s %sserial %lu\n", name, winname,
|
||||
extra ? ":" : "", extra ? extra : "",
|
||||
event->xany.send_event ? "SEND " : "",
|
||||
event->xany.serial);
|
||||
g_print ("%s on %s%s %s %sserial %lu\n", name, winname,
|
||||
extra ? ":" : "", extra ? extra : "",
|
||||
event->xany.send_event ? "SEND " : "",
|
||||
event->xany.serial);
|
||||
|
||||
g_free (winname);
|
||||
|
||||
if (extra)
|
||||
g_free (extra);
|
||||
}
|
||||
#endif /* WITH_VERBOSE_MODE */
|
||||
|
||||
MetaWindow*
|
||||
meta_display_lookup_x_window (MetaDisplay *display,
|
||||
|
||||
@@ -3916,6 +3916,7 @@ init_builtin_key_bindings (MetaDisplay *display)
|
||||
|
||||
g_object_unref (common_keybindings);
|
||||
g_object_unref (mutter_keybindings);
|
||||
g_object_unref (mutter_wayland_keybindings);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -190,6 +190,7 @@ static gboolean opt_replace_wm;
|
||||
static gboolean opt_disable_sm;
|
||||
static gboolean opt_sync;
|
||||
static gboolean opt_wayland;
|
||||
static gboolean opt_display_server;
|
||||
|
||||
static GOptionEntry meta_options[] = {
|
||||
{
|
||||
@@ -233,6 +234,11 @@ static GOptionEntry meta_options[] = {
|
||||
N_("Run as a wayland compositor"),
|
||||
NULL
|
||||
},
|
||||
{
|
||||
"display-server", 0, 0, G_OPTION_ARG_NONE,
|
||||
&opt_display_server,
|
||||
N_("Run as a full display server, rather than nested")
|
||||
},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
@@ -401,8 +407,7 @@ meta_init (void)
|
||||
if (g_getenv ("MUTTER_DEBUG"))
|
||||
meta_set_debugging (TRUE);
|
||||
|
||||
/* We consider running from mutter-launch equivalent to running from bare metal. */
|
||||
if (getenv ("WESTON_LAUNCHER_SOCK"))
|
||||
if (opt_display_server)
|
||||
clutter_set_windowing_backend (CLUTTER_WINDOWING_EGL);
|
||||
|
||||
meta_set_is_wayland_compositor (opt_wayland);
|
||||
@@ -497,6 +502,32 @@ meta_register_with_session (void)
|
||||
g_free (opt_client_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_activate_session:
|
||||
*
|
||||
* Tells mutter to activate the session. When mutter is a
|
||||
* Wayland compositor, this tells logind to switch over to
|
||||
* the new session.
|
||||
*/
|
||||
gboolean
|
||||
meta_activate_session (void)
|
||||
{
|
||||
if (meta_is_wayland_compositor ())
|
||||
{
|
||||
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
||||
GError *error = NULL;
|
||||
|
||||
if (!meta_wayland_compositor_activate_session (compositor, &error))
|
||||
{
|
||||
g_warning ("Could not activate session: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_run: (skip)
|
||||
*
|
||||
|
||||
@@ -43,4 +43,7 @@ void meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
|
||||
int new_x,
|
||||
int new_y);
|
||||
void meta_cursor_tracker_paint (MetaCursorTracker *tracker);
|
||||
|
||||
void meta_cursor_tracker_force_update (MetaCursorTracker *tracker);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <gbm.h>
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
|
||||
#include <X11/cursorfont.h>
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
@@ -569,6 +570,9 @@ make_wayland_cursor_tracker (MetaScreen *screen)
|
||||
|
||||
compositor = meta_wayland_compositor_get_default ();
|
||||
compositor->seat->cursor_tracker = self;
|
||||
meta_cursor_tracker_update_position (self,
|
||||
wl_fixed_to_int (compositor->seat->pointer.x),
|
||||
wl_fixed_to_int (compositor->seat->pointer.y));
|
||||
|
||||
#if defined(CLUTTER_WINDOWING_EGL)
|
||||
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
|
||||
@@ -1143,3 +1147,12 @@ meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker,
|
||||
tracker->screen->xroot);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_cursor_tracker_force_update (MetaCursorTracker *tracker)
|
||||
{
|
||||
g_assert (meta_is_wayland_compositor ());
|
||||
|
||||
update_hw_cursor (tracker);
|
||||
sync_cursor (tracker);
|
||||
}
|
||||
|
||||
@@ -751,4 +751,6 @@ void meta_window_activate_full (MetaWindow *window,
|
||||
MetaClientType source_indication,
|
||||
MetaWorkspace *workspace);
|
||||
|
||||
gboolean meta_window_is_client_decorated (MetaWindow *window);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5082,6 +5082,7 @@ meta_window_move_resize_wayland (MetaWindow *window,
|
||||
|
||||
meta_window_move_resize_internal (window, flags, NorthWestGravity,
|
||||
x, y, width, height);
|
||||
save_user_window_placement (window);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7840,7 +7841,7 @@ meta_window_titlebar_is_onscreen (MetaWindow *window)
|
||||
|
||||
/* Titlebar can't be offscreen if there is no titlebar... */
|
||||
if (!window->frame)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
|
||||
/* Get the rectangle corresponding to the titlebar */
|
||||
meta_window_get_frame_rect (window, &titlebar_rect);
|
||||
@@ -8855,6 +8856,34 @@ meta_window_same_application (MetaWindow *window,
|
||||
group==other_group;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_window_is_client_decorated:
|
||||
*
|
||||
* Check if if the window has decorations drawn by the client.
|
||||
* (window->decorated refers only to whether we should add decorations)
|
||||
*/
|
||||
gboolean
|
||||
meta_window_is_client_decorated (MetaWindow *window)
|
||||
{
|
||||
if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
|
||||
{
|
||||
/* Assume all Wayland clients draw decorations - not strictly
|
||||
* true but good enough for current purposes.
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Currently the implementation here is hackish -
|
||||
* has_custom_frame_extents() is set if _GTK_FRAME_EXTENTS is set
|
||||
* to any value even 0. GTK+ always sets _GTK_FRAME_EXTENTS for
|
||||
* client-side-decorated window, even if the value is 0 because
|
||||
* the window is maxized and has no invisible borders or shadows.
|
||||
*/
|
||||
return window->has_custom_frame_extents;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_refresh_resize_popup (MetaWindow *window)
|
||||
{
|
||||
|
||||
@@ -228,7 +228,10 @@ typedef enum
|
||||
META_GRAB_OP_CLICKING_UNSTICK,
|
||||
|
||||
/* Special grab op when the compositor asked for a grab */
|
||||
META_GRAB_OP_COMPOSITOR
|
||||
META_GRAB_OP_COMPOSITOR,
|
||||
|
||||
/* For when a client takes a popup grab */
|
||||
META_GRAB_OP_WAYLAND_CLIENT,
|
||||
} MetaGrabOp;
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,6 +28,7 @@ GOptionContext *meta_get_option_context (void);
|
||||
void meta_init (void);
|
||||
int meta_run (void);
|
||||
void meta_register_with_session (void);
|
||||
gboolean meta_activate_session (void);
|
||||
gboolean meta_get_replace_current_wm (void); /* Actually defined in util.c */
|
||||
|
||||
void meta_set_wm_name (const char *wm_name);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
_Name=Mutter (wayland compositor)
|
||||
Exec=mutter-launch -- mutter --wayland
|
||||
Exec=mutter --wayland --display-server
|
||||
NoDisplay=true
|
||||
# name of loadable control center module
|
||||
X-GNOME-WMSettingsModule=metacity
|
||||
|
||||
44
src/org.freedesktop.login1.xml
Normal file
44
src/org.freedesktop.login1.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.freedesktop.login1.Session">
|
||||
<property name="Active" type="b" access="read" />
|
||||
|
||||
<method name="Activate">
|
||||
</method>
|
||||
<method name="TakeControl">
|
||||
<arg name="force" type="b"/>
|
||||
</method>
|
||||
<method name="TakeDevice">
|
||||
<annotation name="org.gtk.GDBus.C.UnixFD" value="true"/>
|
||||
<arg name="major" type="u" direction="in"/>
|
||||
<arg name="minor" type="u" direction="in"/>
|
||||
<arg name="fd" type="h" direction="out"/>
|
||||
<arg name="paused" type="b" direction="out"/>
|
||||
</method>
|
||||
<method name="ReleaseDevice">
|
||||
<arg name="major" type="u"/>
|
||||
<arg name="minor" type="u"/>
|
||||
</method>
|
||||
<method name="PauseDeviceComplete">
|
||||
<arg name="major" type="u"/>
|
||||
<arg name="minor" type="u"/>
|
||||
</method>
|
||||
<signal name="PauseDevice">
|
||||
<arg name="major" type="u"/>
|
||||
<arg name="minor" type="u"/>
|
||||
<arg name="type" type="s"/>
|
||||
</signal>
|
||||
<signal name="ResumeDevice">
|
||||
<arg name="major" type="u"/>
|
||||
<arg name="minor" type="u"/>
|
||||
<arg name="fd" type="h"/>
|
||||
</signal>
|
||||
</interface>
|
||||
|
||||
<interface name="org.freedesktop.login1.Seat">
|
||||
<method name="SwitchTo">
|
||||
<arg name="vt" type="u"/>
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
||||
441
src/wayland/meta-login1.c
Normal file
441
src/wayland/meta-login1.c
Normal file
@@ -0,0 +1,441 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 "meta-login1.h"
|
||||
|
||||
#include "meta-dbus-login1.h"
|
||||
|
||||
#include "meta-wayland-private.h"
|
||||
#include "meta-cursor-tracker-private.h"
|
||||
|
||||
#include <gio/gunixfdlist.h>
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <clutter/evdev/clutter-evdev.h>
|
||||
#include <clutter/egl/clutter-egl.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <malloc.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <systemd/sd-login.h>
|
||||
|
||||
struct _MetaLogin1
|
||||
{
|
||||
Login1Session *session_proxy;
|
||||
Login1Seat *seat_proxy;
|
||||
|
||||
gboolean session_active;
|
||||
};
|
||||
|
||||
/* Stolen from tp_escape_as_identifier, from tp-glib,
|
||||
* which follows the same escaping convention as systemd.
|
||||
*/
|
||||
static inline gboolean
|
||||
_esc_ident_bad (gchar c, gboolean is_first)
|
||||
{
|
||||
return ((c < 'a' || c > 'z') &&
|
||||
(c < 'A' || c > 'Z') &&
|
||||
(c < '0' || c > '9' || is_first));
|
||||
}
|
||||
|
||||
static gchar *
|
||||
escape_dbus_component (const gchar *name)
|
||||
{
|
||||
gboolean bad = FALSE;
|
||||
size_t len = 0;
|
||||
GString *op;
|
||||
const gchar *ptr, *first_ok;
|
||||
|
||||
g_return_val_if_fail (name != NULL, NULL);
|
||||
|
||||
/* fast path for empty name */
|
||||
if (name[0] == '\0')
|
||||
return g_strdup ("_");
|
||||
|
||||
for (ptr = name; *ptr; ptr++)
|
||||
{
|
||||
if (_esc_ident_bad (*ptr, ptr == name))
|
||||
{
|
||||
bad = TRUE;
|
||||
len += 3;
|
||||
}
|
||||
else
|
||||
len++;
|
||||
}
|
||||
|
||||
/* fast path if it's clean */
|
||||
if (!bad)
|
||||
return g_strdup (name);
|
||||
|
||||
/* If strictly less than ptr, first_ok is the first uncopied safe character.
|
||||
*/
|
||||
first_ok = name;
|
||||
op = g_string_sized_new (len);
|
||||
for (ptr = name; *ptr; ptr++)
|
||||
{
|
||||
if (_esc_ident_bad (*ptr, ptr == name))
|
||||
{
|
||||
/* copy preceding safe characters if any */
|
||||
if (first_ok < ptr)
|
||||
{
|
||||
g_string_append_len (op, first_ok, ptr - first_ok);
|
||||
}
|
||||
/* escape the unsafe character */
|
||||
g_string_append_printf (op, "_%02x", (unsigned char)(*ptr));
|
||||
/* restart after it */
|
||||
first_ok = ptr + 1;
|
||||
}
|
||||
}
|
||||
/* copy trailing safe characters if any */
|
||||
if (first_ok < ptr)
|
||||
{
|
||||
g_string_append_len (op, first_ok, ptr - first_ok);
|
||||
}
|
||||
return g_string_free (op, FALSE);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_escaped_dbus_path (const char *prefix,
|
||||
const char *component)
|
||||
{
|
||||
char *escaped_component = escape_dbus_component (component);
|
||||
char *path = g_strconcat (prefix, "/", component, NULL);
|
||||
|
||||
g_free (escaped_component);
|
||||
return path;
|
||||
}
|
||||
|
||||
static Login1Session *
|
||||
get_session_proxy (GCancellable *cancellable)
|
||||
{
|
||||
char *proxy_path;
|
||||
char *session_id;
|
||||
Login1Session *session_proxy;
|
||||
|
||||
if (sd_pid_get_session (getpid (), &session_id) < 0)
|
||||
return NULL;
|
||||
|
||||
proxy_path = get_escaped_dbus_path ("/org/freedesktop/login1/session", session_id);
|
||||
|
||||
session_proxy = login1_session_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||
"org.freedesktop.login1",
|
||||
proxy_path,
|
||||
cancellable, NULL);
|
||||
free (proxy_path);
|
||||
|
||||
return session_proxy;
|
||||
}
|
||||
|
||||
static Login1Seat *
|
||||
get_seat_proxy (GCancellable *cancellable)
|
||||
{
|
||||
return login1_seat_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||
"org.freedesktop.login1",
|
||||
"/org/freedesktop/login1/seat/self",
|
||||
cancellable, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
session_unpause (void)
|
||||
{
|
||||
ClutterBackend *backend;
|
||||
CoglContext *cogl_context;
|
||||
CoglDisplay *cogl_display;
|
||||
|
||||
backend = clutter_get_default_backend ();
|
||||
cogl_context = clutter_backend_get_cogl_context (backend);
|
||||
cogl_display = cogl_context_get_display (cogl_context);
|
||||
cogl_kms_display_queue_modes_reset (cogl_display);
|
||||
|
||||
clutter_set_paused (FALSE);
|
||||
/* clutter_evdev_reclaim_devices (); */
|
||||
|
||||
{
|
||||
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
||||
|
||||
/* When we mode-switch back, we need to immediately queue a redraw
|
||||
* in case nothing else quueed one for us, and force the cursor to
|
||||
* update. */
|
||||
|
||||
clutter_actor_queue_redraw (compositor->stage);
|
||||
meta_cursor_tracker_force_update (compositor->seat->cursor_tracker);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
session_pause (void)
|
||||
{
|
||||
clutter_set_paused (TRUE);
|
||||
/* clutter_evdev_release_devices (); */
|
||||
}
|
||||
|
||||
static void
|
||||
sync_active (MetaLogin1 *self)
|
||||
{
|
||||
gboolean active = login1_session_get_active (LOGIN1_SESSION (self->session_proxy));
|
||||
|
||||
if (active == self->session_active)
|
||||
return;
|
||||
|
||||
self->session_active = active;
|
||||
|
||||
if (active)
|
||||
session_unpause ();
|
||||
else
|
||||
session_pause ();
|
||||
}
|
||||
|
||||
static void
|
||||
on_active_changed (Login1Session *session,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaLogin1 *self = user_data;
|
||||
sync_active (self);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
take_device (Login1Session *session_proxy,
|
||||
int dev_major,
|
||||
int dev_minor,
|
||||
int *out_fd,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GVariant *fd_variant = NULL;
|
||||
int fd = -1;
|
||||
GUnixFDList *fd_list;
|
||||
|
||||
if (!login1_session_call_take_device_sync (session_proxy,
|
||||
dev_major,
|
||||
dev_minor,
|
||||
NULL,
|
||||
&fd_variant,
|
||||
NULL, /* paused */
|
||||
&fd_list,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
fd = g_unix_fd_list_get (fd_list, g_variant_get_handle (fd_variant), error);
|
||||
if (fd == -1)
|
||||
goto out;
|
||||
|
||||
*out_fd = fd;
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
if (fd_variant)
|
||||
g_variant_unref (fd_variant);
|
||||
if (fd_list)
|
||||
g_object_unref (fd_list);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_device_info_from_path (const char *path,
|
||||
int *out_major,
|
||||
int *out_minor)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int r;
|
||||
struct stat st;
|
||||
|
||||
r = stat (path, &st);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
if (!S_ISCHR (st.st_mode))
|
||||
goto out;
|
||||
|
||||
*out_major = major (st.st_rdev);
|
||||
*out_minor = minor (st.st_rdev);
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_device_info_from_fd (int fd,
|
||||
int *out_major,
|
||||
int *out_minor)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int r;
|
||||
struct stat st;
|
||||
|
||||
r = fstat (fd, &st);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
if (!S_ISCHR (st.st_mode))
|
||||
goto out;
|
||||
|
||||
*out_major = major (st.st_rdev);
|
||||
*out_minor = minor (st.st_rdev);
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
open_evdev_device (const char *path,
|
||||
int flags,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
MetaLogin1 *self = user_data;
|
||||
int fd;
|
||||
int major, minor;
|
||||
|
||||
if (!get_device_info_from_path (path, &major, &minor))
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_FOUND,
|
||||
"Could not get device info for path %s: %m", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!take_device (self->session_proxy, major, minor, &fd, NULL, error))
|
||||
return -1;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void
|
||||
close_evdev_device (int fd,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaLogin1 *self = user_data;
|
||||
int major, minor;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!get_device_info_from_fd (fd, &major, &minor))
|
||||
{
|
||||
g_warning ("Could not get device info for fd %d: %m", fd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!login1_session_call_release_device_sync (self->session_proxy,
|
||||
major, minor,
|
||||
NULL, &error))
|
||||
{
|
||||
g_warning ("Could not release device %d,%d: %s", major, minor, error->message);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_kms_fd (Login1Session *session_proxy,
|
||||
int *fd_out)
|
||||
{
|
||||
int major, minor;
|
||||
int fd;
|
||||
GError *error = NULL;
|
||||
|
||||
/* XXX -- use udev to find the DRM master device */
|
||||
if (!get_device_info_from_path ("/dev/dri/card0", &major, &minor))
|
||||
{
|
||||
g_warning ("Could not stat /dev/dri/card0: %m");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!take_device (session_proxy, major, minor, &fd, NULL, &error))
|
||||
{
|
||||
g_warning ("Could not open DRM device: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*fd_out = fd;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
MetaLogin1 *
|
||||
meta_login1_new (void)
|
||||
{
|
||||
MetaLogin1 *self;
|
||||
Login1Session *session_proxy;
|
||||
GError *error = NULL;
|
||||
int kms_fd;
|
||||
|
||||
session_proxy = get_session_proxy (NULL);
|
||||
if (!login1_session_call_take_control_sync (session_proxy, FALSE, NULL, &error))
|
||||
{
|
||||
g_warning ("Could not take control: %s", error->message);
|
||||
g_error_free (error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!get_kms_fd (session_proxy, &kms_fd))
|
||||
return NULL;
|
||||
|
||||
self = g_slice_new0 (MetaLogin1);
|
||||
self->session_proxy = session_proxy;
|
||||
self->seat_proxy = get_seat_proxy (NULL);
|
||||
|
||||
/* Clutter/Cogl start out in a state that assumes the session is active */
|
||||
self->session_active = TRUE;
|
||||
|
||||
clutter_egl_native_set_kms_fd (kms_fd);
|
||||
clutter_evdev_set_open_callback (open_evdev_device,
|
||||
close_evdev_device,
|
||||
self);
|
||||
|
||||
g_signal_connect (self->session_proxy, "notify::active", G_CALLBACK (on_active_changed), self);
|
||||
sync_active (self);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
meta_login1_free (MetaLogin1 *self)
|
||||
{
|
||||
g_object_unref (self->seat_proxy);
|
||||
g_object_unref (self->session_proxy);
|
||||
g_slice_free (MetaLogin1, self);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_login1_activate_session (MetaLogin1 *self,
|
||||
GError **error)
|
||||
{
|
||||
if (!login1_session_call_activate_sync (self->session_proxy, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
sync_active (self);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_login1_activate_vt (MetaLogin1 *self,
|
||||
int vt,
|
||||
GError **error)
|
||||
{
|
||||
return login1_seat_call_switch_to_sync (self->seat_proxy, vt, NULL, error);
|
||||
}
|
||||
35
src/wayland/meta-login1.h
Normal file
35
src/wayland/meta-login1.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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_LOGIN1_H
|
||||
#define META_LOGIN1_H
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
typedef struct _MetaLogin1 MetaLogin1;
|
||||
|
||||
MetaLogin1 *meta_login1_new (void);
|
||||
void meta_login1_free (MetaLogin1 *self);
|
||||
gboolean meta_login1_activate_session (MetaLogin1 *self,
|
||||
GError **error);
|
||||
gboolean meta_login1_activate_vt (MetaLogin1 *self,
|
||||
int vt,
|
||||
GError **error);
|
||||
|
||||
#endif
|
||||
@@ -48,7 +48,7 @@ data_offer_accept (struct wl_client *client,
|
||||
* this be a wl_data_device request? */
|
||||
|
||||
if (offer->source)
|
||||
offer->source->accept (offer->source, serial, mime_type);
|
||||
wl_data_source_send_target (offer->source->resource, mime_type);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -58,9 +58,9 @@ data_offer_receive (struct wl_client *client, struct wl_resource *resource,
|
||||
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
|
||||
|
||||
if (offer->source)
|
||||
offer->source->send (offer->source, mime_type, fd);
|
||||
else
|
||||
close (fd);
|
||||
wl_data_source_send_send (offer->source->resource, mime_type, fd);
|
||||
|
||||
close (fd);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -82,7 +82,8 @@ destroy_data_offer (struct wl_resource *resource)
|
||||
|
||||
if (offer->source)
|
||||
wl_list_remove (&offer->source_destroy_listener.link);
|
||||
free (offer);
|
||||
|
||||
g_slice_free (MetaWaylandDataOffer, offer);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -99,13 +100,9 @@ static struct wl_resource *
|
||||
meta_wayland_data_source_send_offer (MetaWaylandDataSource *source,
|
||||
struct wl_resource *target)
|
||||
{
|
||||
MetaWaylandDataOffer *offer;
|
||||
MetaWaylandDataOffer *offer = g_slice_new0 (MetaWaylandDataOffer);
|
||||
char **p;
|
||||
|
||||
offer = malloc (sizeof *offer);
|
||||
if (offer == NULL)
|
||||
return NULL;
|
||||
|
||||
offer->source = source;
|
||||
offer->source_destroy_listener.notify = destroy_offer_data_source;
|
||||
|
||||
@@ -318,8 +315,12 @@ data_device_start_drag (struct wl_client *client,
|
||||
{
|
||||
MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
|
||||
MetaWaylandDragGrab *drag_grab;
|
||||
/* FIXME: Check that client has implicit grab on the origin
|
||||
* surface that matches the given time. */
|
||||
|
||||
if ((seat->pointer.button_count == 0 ||
|
||||
seat->pointer.grab_serial != serial ||
|
||||
!seat->pointer.focus_surface ||
|
||||
seat->pointer.focus_surface != wl_resource_get_user_data (origin_resource)))
|
||||
return;
|
||||
|
||||
/* FIXME: Check that the data source type array isn't empty. */
|
||||
|
||||
@@ -332,6 +333,7 @@ data_device_start_drag (struct wl_client *client,
|
||||
drag_grab->generic.pointer = &seat->pointer;
|
||||
|
||||
drag_grab->drag_client = client;
|
||||
drag_grab->seat = seat;
|
||||
|
||||
if (source_resource)
|
||||
{
|
||||
@@ -375,7 +377,7 @@ destroy_selection_data_source (struct wl_listener *listener, void *data)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
meta_wayland_seat_set_selection (MetaWaylandSeat *seat,
|
||||
MetaWaylandDataSource *source,
|
||||
guint32 serial)
|
||||
@@ -389,7 +391,7 @@ meta_wayland_seat_set_selection (MetaWaylandSeat *seat,
|
||||
|
||||
if (seat->selection_data_source)
|
||||
{
|
||||
seat->selection_data_source->cancel (seat->selection_data_source);
|
||||
wl_data_source_send_cancelled (seat->selection_data_source->resource);
|
||||
wl_list_remove (&seat->selection_data_source_listener.link);
|
||||
seat->selection_data_source = NULL;
|
||||
}
|
||||
@@ -449,47 +451,21 @@ static const struct wl_data_device_interface data_device_interface = {
|
||||
static void
|
||||
destroy_data_source (struct wl_resource *resource)
|
||||
{
|
||||
MetaWaylandDataSource *source = wl_container_of (resource, source, resource);
|
||||
MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
|
||||
char **p;
|
||||
|
||||
wl_array_for_each (p, &source->mime_types) free (*p);
|
||||
|
||||
wl_array_release (&source->mime_types);
|
||||
}
|
||||
|
||||
static void
|
||||
client_source_accept (MetaWaylandDataSource *source,
|
||||
guint32 time, const char *mime_type)
|
||||
{
|
||||
wl_data_source_send_target (source->resource, mime_type);
|
||||
}
|
||||
|
||||
static void
|
||||
client_source_send (MetaWaylandDataSource *source,
|
||||
const char *mime_type, int32_t fd)
|
||||
{
|
||||
wl_data_source_send_send (source->resource, mime_type, fd);
|
||||
close (fd);
|
||||
}
|
||||
|
||||
static void
|
||||
client_source_cancel (MetaWaylandDataSource *source)
|
||||
{
|
||||
wl_data_source_send_cancelled (source->resource);
|
||||
g_slice_free (MetaWaylandDataSource, source);
|
||||
}
|
||||
|
||||
static void
|
||||
create_data_source (struct wl_client *client,
|
||||
struct wl_resource *resource, guint32 id)
|
||||
{
|
||||
MetaWaylandDataSource *source;
|
||||
|
||||
source = malloc (sizeof *source);
|
||||
if (source == NULL)
|
||||
{
|
||||
wl_resource_post_no_memory (resource);
|
||||
return;
|
||||
}
|
||||
MetaWaylandDataSource *source = g_slice_new0 (MetaWaylandDataSource);
|
||||
|
||||
source->resource = wl_resource_create (client, &wl_data_source_interface,
|
||||
MIN (META_WL_DATA_SOURCE_VERSION,
|
||||
@@ -497,10 +473,6 @@ create_data_source (struct wl_client *client,
|
||||
wl_resource_set_implementation (source->resource, &data_source_interface,
|
||||
source, destroy_data_source);
|
||||
|
||||
source->accept = client_source_accept;
|
||||
source->send = client_source_send;
|
||||
source->cancel = client_source_cancel;
|
||||
|
||||
wl_array_init (&source->mime_types);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,10 +33,4 @@ meta_wayland_data_device_set_keyboard_focus (MetaWaylandSeat *seat);
|
||||
int
|
||||
meta_wayland_data_device_manager_init (struct wl_display *display);
|
||||
|
||||
void
|
||||
meta_wayland_seat_set_selection (MetaWaylandSeat *seat,
|
||||
MetaWaylandDataSource *source,
|
||||
uint32_t serial);
|
||||
|
||||
|
||||
#endif /* __META_WAYLAND_DATA_DEVICE_H__ */
|
||||
|
||||
@@ -142,20 +142,6 @@ meta_wayland_keyboard_take_keymap (MetaWaylandKeyboard *keyboard,
|
||||
xkb_keymap_unref (xkb_info->keymap);
|
||||
xkb_info->keymap = keymap;
|
||||
|
||||
xkb_info->shift_mod =
|
||||
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_SHIFT);
|
||||
xkb_info->caps_mod =
|
||||
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_CAPS);
|
||||
xkb_info->ctrl_mod =
|
||||
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_CTRL);
|
||||
xkb_info->alt_mod =
|
||||
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_ALT);
|
||||
xkb_info->mod2_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod2");
|
||||
xkb_info->mod3_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod3");
|
||||
xkb_info->super_mod =
|
||||
xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_LOGO);
|
||||
xkb_info->mod5_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod5");
|
||||
|
||||
keymap_str = xkb_map_get_as_string (xkb_info->keymap);
|
||||
if (keymap_str == NULL)
|
||||
{
|
||||
@@ -295,31 +281,6 @@ static const MetaWaylandKeyboardGrabInterface
|
||||
default_grab_modifiers,
|
||||
};
|
||||
|
||||
static gboolean
|
||||
modal_key (MetaWaylandKeyboardGrab *grab,
|
||||
uint32_t time,
|
||||
uint32_t key,
|
||||
uint32_t state)
|
||||
{
|
||||
/* FALSE means: let the event through to clutter */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
modal_modifiers (MetaWaylandKeyboardGrab *grab,
|
||||
uint32_t serial,
|
||||
uint32_t mods_depressed,
|
||||
uint32_t mods_latched,
|
||||
uint32_t mods_locked,
|
||||
uint32_t group)
|
||||
{
|
||||
}
|
||||
|
||||
static MetaWaylandKeyboardGrabInterface modal_grab = {
|
||||
modal_key,
|
||||
modal_modifiers,
|
||||
};
|
||||
|
||||
gboolean
|
||||
meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
|
||||
struct wl_display *display)
|
||||
@@ -535,26 +496,13 @@ meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
|
||||
struct wl_display *display = wl_client_get_display (client);
|
||||
uint32_t serial = wl_display_next_serial (display);
|
||||
|
||||
/* If we're in a modal grab, the client is focused but doesn't see
|
||||
modifiers or pressed keys (and fix that up when we exit the modal) */
|
||||
if (keyboard->grab->interface == &modal_grab)
|
||||
{
|
||||
struct wl_array empty;
|
||||
wl_array_init (&empty);
|
||||
|
||||
wl_keyboard_send_modifiers (keyboard->focus_resource, serial, 0, 0, 0, 0);
|
||||
wl_keyboard_send_enter (keyboard->focus_resource, serial, keyboard->focus_surface->resource, &empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
wl_keyboard_send_modifiers (keyboard->focus_resource, serial,
|
||||
keyboard->modifier_state.mods_depressed,
|
||||
keyboard->modifier_state.mods_latched,
|
||||
keyboard->modifier_state.mods_locked,
|
||||
keyboard->modifier_state.group);
|
||||
wl_keyboard_send_enter (keyboard->focus_resource, serial, keyboard->focus_surface->resource,
|
||||
&keyboard->keys);
|
||||
}
|
||||
wl_keyboard_send_modifiers (keyboard->focus_resource, serial,
|
||||
keyboard->modifier_state.mods_depressed,
|
||||
keyboard->modifier_state.mods_latched,
|
||||
keyboard->modifier_state.mods_locked,
|
||||
keyboard->modifier_state.group);
|
||||
wl_keyboard_send_enter (keyboard->focus_resource, serial, keyboard->focus_surface->resource,
|
||||
&keyboard->keys);
|
||||
|
||||
wl_resource_add_destroy_listener (keyboard->focus_resource, &keyboard->focus_resource_listener);
|
||||
keyboard->focus_serial = serial;
|
||||
@@ -588,85 +536,6 @@ meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard)
|
||||
wl_array_release (&keyboard->keys);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard,
|
||||
guint32 timestamp)
|
||||
{
|
||||
MetaWaylandKeyboardGrab *grab;
|
||||
uint32_t *end = (void *) ((char *) keyboard->keys.data +
|
||||
keyboard->keys.size);
|
||||
uint32_t *k;
|
||||
uint32_t serial;
|
||||
|
||||
meta_verbose ("Asked to acquire modal keyboard grab, timestamp %d\n", timestamp);
|
||||
|
||||
if (keyboard->grab != &keyboard->default_grab)
|
||||
return FALSE;
|
||||
|
||||
if (keyboard->focus_surface)
|
||||
{
|
||||
/* Fake key release events for the focused app */
|
||||
serial = wl_display_next_serial (keyboard->display);
|
||||
keyboard->grab->interface->modifiers (keyboard->grab,
|
||||
serial,
|
||||
0, 0, 0, 0);
|
||||
|
||||
for (k = keyboard->keys.data; k < end; k++)
|
||||
{
|
||||
keyboard->grab->interface->key (keyboard->grab,
|
||||
timestamp,
|
||||
*k, 0);
|
||||
}
|
||||
}
|
||||
|
||||
grab = g_slice_new0 (MetaWaylandKeyboardGrab);
|
||||
grab->interface = &modal_grab;
|
||||
meta_wayland_keyboard_start_grab (keyboard, grab);
|
||||
|
||||
meta_verbose ("Acquired modal keyboard grab, timestamp %d\n", timestamp);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard,
|
||||
guint32 timestamp)
|
||||
{
|
||||
MetaWaylandKeyboardGrab *grab;
|
||||
uint32_t *end = (void *) ((char *) keyboard->keys.data +
|
||||
keyboard->keys.size);
|
||||
uint32_t *k;
|
||||
uint32_t serial;
|
||||
|
||||
grab = keyboard->grab;
|
||||
|
||||
g_assert (grab->interface == &modal_grab);
|
||||
|
||||
meta_wayland_keyboard_end_grab (keyboard);
|
||||
g_slice_free (MetaWaylandKeyboardGrab, grab);
|
||||
|
||||
if (keyboard->focus_surface)
|
||||
{
|
||||
/* Fake key press events for the focused app */
|
||||
serial = wl_display_next_serial (keyboard->display);
|
||||
keyboard->grab->interface->modifiers (keyboard->grab,
|
||||
serial,
|
||||
keyboard->modifier_state.mods_depressed,
|
||||
keyboard->modifier_state.mods_latched,
|
||||
keyboard->modifier_state.mods_locked,
|
||||
keyboard->modifier_state.group);
|
||||
|
||||
for (k = keyboard->keys.data; k < end; k++)
|
||||
{
|
||||
keyboard->grab->interface->key (keyboard->grab,
|
||||
timestamp,
|
||||
*k, 1);
|
||||
}
|
||||
}
|
||||
|
||||
meta_verbose ("Released modal keyboard grab, timestamp %d\n", timestamp);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_keyboard_set_keymap_names (MetaWaylandKeyboard *keyboard,
|
||||
const char *rules,
|
||||
|
||||
@@ -72,14 +72,6 @@ typedef struct
|
||||
int keymap_fd;
|
||||
size_t keymap_size;
|
||||
char *keymap_area;
|
||||
xkb_mod_index_t shift_mod;
|
||||
xkb_mod_index_t caps_mod;
|
||||
xkb_mod_index_t ctrl_mod;
|
||||
xkb_mod_index_t alt_mod;
|
||||
xkb_mod_index_t mod2_mod;
|
||||
xkb_mod_index_t mod3_mod;
|
||||
xkb_mod_index_t super_mod;
|
||||
xkb_mod_index_t mod5_mod;
|
||||
} MetaWaylandXkbInfo;
|
||||
|
||||
typedef struct
|
||||
@@ -150,13 +142,6 @@ meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *device,
|
||||
void
|
||||
meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard);
|
||||
|
||||
gboolean
|
||||
meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard,
|
||||
guint32 timestamp);
|
||||
void
|
||||
meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard,
|
||||
guint32 timestamp);
|
||||
|
||||
void
|
||||
meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard);
|
||||
|
||||
|
||||
@@ -398,61 +398,6 @@ meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer)
|
||||
interface->focus (pointer->grab, pointer->current, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
modal_focus (MetaWaylandPointerGrab *grab,
|
||||
MetaWaylandSurface *surface,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
modal_motion (MetaWaylandPointerGrab *grab,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
modal_button (MetaWaylandPointerGrab *grab,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
}
|
||||
|
||||
static MetaWaylandPointerGrabInterface modal_grab = {
|
||||
modal_focus,
|
||||
modal_motion,
|
||||
modal_button
|
||||
};
|
||||
|
||||
gboolean
|
||||
meta_wayland_pointer_begin_modal (MetaWaylandPointer *pointer)
|
||||
{
|
||||
MetaWaylandPointerGrab *grab;
|
||||
|
||||
if (pointer->grab != &pointer->default_grab)
|
||||
return FALSE;
|
||||
|
||||
meta_wayland_pointer_set_focus (pointer, NULL);
|
||||
|
||||
grab = g_slice_new0 (MetaWaylandPointerGrab);
|
||||
grab->interface = &modal_grab;
|
||||
meta_wayland_pointer_start_grab (pointer, grab);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_pointer_end_modal (MetaWaylandPointer *pointer)
|
||||
{
|
||||
MetaWaylandPointerGrab *grab;
|
||||
|
||||
grab = pointer->grab;
|
||||
|
||||
g_assert (grab->interface == &modal_grab);
|
||||
|
||||
meta_wayland_pointer_end_grab (pointer);
|
||||
g_slice_free (MetaWaylandPointerGrab, grab);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
MetaWaylandPointerGrab generic;
|
||||
|
||||
@@ -533,6 +478,12 @@ meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer)
|
||||
g_slice_free (MetaWaylandPopup, popup);
|
||||
}
|
||||
|
||||
{
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
meta_display_end_grab_op (display,
|
||||
meta_display_get_current_time_roundtrip (display));
|
||||
}
|
||||
|
||||
meta_wayland_pointer_end_grab (pointer);
|
||||
g_slice_free (MetaWaylandPopupGrab, popup_grab);
|
||||
}
|
||||
@@ -572,6 +523,8 @@ meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
|
||||
|
||||
if (pointer->grab == &pointer->default_grab)
|
||||
{
|
||||
MetaWindow *window = surface->window;
|
||||
|
||||
grab = g_slice_new0 (MetaWaylandPopupGrab);
|
||||
grab->generic.interface = &popup_grab_interface;
|
||||
grab->generic.pointer = pointer;
|
||||
@@ -579,6 +532,19 @@ meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
|
||||
wl_list_init (&grab->all_popups);
|
||||
|
||||
meta_wayland_pointer_start_grab (pointer, (MetaWaylandPointerGrab*)grab);
|
||||
|
||||
meta_display_begin_grab_op (window->display,
|
||||
window->screen,
|
||||
window,
|
||||
META_GRAB_OP_WAYLAND_CLIENT,
|
||||
FALSE, /* pointer_already_grabbed */
|
||||
FALSE, /* frame_action */
|
||||
1, /* button. XXX? */
|
||||
0, /* modmask */
|
||||
meta_display_get_current_time_roundtrip (window->display),
|
||||
wl_fixed_to_int (pointer->grab_x),
|
||||
wl_fixed_to_int (pointer->grab_y));
|
||||
|
||||
}
|
||||
else
|
||||
grab = (MetaWaylandPopupGrab*)pointer->grab;
|
||||
@@ -593,7 +559,6 @@ meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
|
||||
wl_resource_add_destroy_listener (surface->wl_shell_surface.resource, &popup->surface_destroy_listener);
|
||||
|
||||
wl_list_insert (&grab->all_popups, &popup->link);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -85,11 +85,6 @@ meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer,
|
||||
void
|
||||
meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer);
|
||||
|
||||
gboolean
|
||||
meta_wayland_pointer_begin_modal (MetaWaylandPointer *pointer);
|
||||
void
|
||||
meta_wayland_pointer_end_modal (MetaWaylandPointer *pointer);
|
||||
|
||||
gboolean
|
||||
meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
|
||||
MetaWaylandSurface *popup);
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <cairo.h>
|
||||
|
||||
#include "window-private.h"
|
||||
#include "meta-weston-launch.h"
|
||||
#include "meta-login1.h"
|
||||
#include <meta/meta-cursor-tracker.h>
|
||||
|
||||
#include "meta-wayland.h"
|
||||
@@ -85,7 +85,7 @@ struct _MetaWaylandCompositor
|
||||
|
||||
MetaXWaylandManager xwayland_manager;
|
||||
|
||||
MetaLauncher *launcher;
|
||||
MetaLogin1 *login1;
|
||||
|
||||
MetaWaylandSeat *seat;
|
||||
};
|
||||
|
||||
@@ -276,42 +276,53 @@ static void
|
||||
handle_scroll_event (MetaWaylandSeat *seat,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
enum wl_pointer_axis axis;
|
||||
wl_fixed_t value;
|
||||
wl_fixed_t x_value = 0, y_value = 0;
|
||||
|
||||
notify_motion (seat, event);
|
||||
|
||||
if (!seat->pointer.focus_resource)
|
||||
return;
|
||||
|
||||
if (clutter_event_is_pointer_emulated (event))
|
||||
return;
|
||||
|
||||
switch (clutter_event_get_scroll_direction (event))
|
||||
{
|
||||
case CLUTTER_SCROLL_UP:
|
||||
axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
|
||||
value = -DEFAULT_AXIS_STEP_DISTANCE;
|
||||
y_value = -DEFAULT_AXIS_STEP_DISTANCE;
|
||||
break;
|
||||
|
||||
case CLUTTER_SCROLL_DOWN:
|
||||
axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
|
||||
value = DEFAULT_AXIS_STEP_DISTANCE;
|
||||
y_value = DEFAULT_AXIS_STEP_DISTANCE;
|
||||
break;
|
||||
|
||||
case CLUTTER_SCROLL_LEFT:
|
||||
axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
|
||||
value = -DEFAULT_AXIS_STEP_DISTANCE;
|
||||
x_value = -DEFAULT_AXIS_STEP_DISTANCE;
|
||||
break;
|
||||
|
||||
case CLUTTER_SCROLL_RIGHT:
|
||||
axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
|
||||
value = DEFAULT_AXIS_STEP_DISTANCE;
|
||||
x_value = DEFAULT_AXIS_STEP_DISTANCE;
|
||||
break;
|
||||
|
||||
case CLUTTER_SCROLL_SMOOTH:
|
||||
{
|
||||
double dx, dy;
|
||||
clutter_event_get_scroll_delta (event, &dx, &dy);
|
||||
x_value = wl_fixed_from_double (dx);
|
||||
y_value = wl_fixed_from_double (dy);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (seat->pointer.focus_resource)
|
||||
wl_pointer_send_axis (seat->pointer.focus_resource,
|
||||
clutter_event_get_time (event),
|
||||
axis,
|
||||
value);
|
||||
if (x_value)
|
||||
wl_pointer_send_axis (seat->pointer.focus_resource, clutter_event_get_time (event),
|
||||
WL_POINTER_AXIS_HORIZONTAL_SCROLL, x_value);
|
||||
if (y_value)
|
||||
wl_pointer_send_axis (seat->pointer.focus_resource, clutter_event_get_time (event),
|
||||
WL_POINTER_AXIS_VERTICAL_SCROLL, y_value);
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
@@ -43,12 +43,6 @@ struct _MetaWaylandDataSource
|
||||
{
|
||||
struct wl_resource *resource;
|
||||
struct wl_array mime_types;
|
||||
|
||||
void (*accept) (MetaWaylandDataSource * source,
|
||||
uint32_t serial, const char *mime_type);
|
||||
void (*send) (MetaWaylandDataSource * source,
|
||||
const char *mime_type, int32_t fd);
|
||||
void (*cancel) (MetaWaylandDataSource * source);
|
||||
};
|
||||
|
||||
struct _MetaWaylandSeat
|
||||
|
||||
@@ -874,8 +874,7 @@ static void
|
||||
xdg_surface_unset_fullscreen (struct wl_client *client,
|
||||
struct wl_resource *resource)
|
||||
{
|
||||
MetaWaylandSurfaceExtension *xdg_surface = wl_resource_get_user_data (resource);
|
||||
MetaWaylandSurface *surface = wl_container_of (xdg_surface, surface, xdg_surface);
|
||||
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
||||
|
||||
surface->pending.fullscreen.changed = TRUE;
|
||||
surface->pending.fullscreen.value = FALSE;
|
||||
@@ -1465,8 +1464,6 @@ subsurface_parent_surface_committed (MetaWaylandSurface *surface)
|
||||
|
||||
if (surface->sub.synchronous)
|
||||
commit_double_buffered_state (surface, pending_surface_state);
|
||||
|
||||
double_buffered_state_reset (pending_surface_state);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
#include <meta/main.h>
|
||||
#include "frame.h"
|
||||
#include "meta-idle-monitor-private.h"
|
||||
#include "meta-weston-launch.h"
|
||||
#include "meta-login1.h"
|
||||
#include "monitor-private.h"
|
||||
|
||||
static MetaWaylandCompositor _meta_wayland_compositor;
|
||||
@@ -643,25 +643,16 @@ meta_wayland_init (void)
|
||||
|
||||
clutter_wayland_set_compositor_display (compositor->wayland_display);
|
||||
|
||||
/* If we're running on bare metal, we're a display server,
|
||||
* so start talking to logind. */
|
||||
#if defined(CLUTTER_WINDOWING_EGL)
|
||||
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
|
||||
compositor->launcher = meta_launcher_new ();
|
||||
compositor->login1 = meta_login1_new ();
|
||||
#endif
|
||||
|
||||
if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
|
||||
g_error ("Failed to initialize Clutter");
|
||||
|
||||
#if defined(CLUTTER_WINDOWING_EGL)
|
||||
if (clutter_check_windowing_backend (CLUTTER_WINDOWING_EGL))
|
||||
{
|
||||
ClutterBackend *backend = clutter_get_default_backend ();
|
||||
CoglContext *cogl_context = clutter_backend_get_cogl_context (backend);
|
||||
CoglRenderer *cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (cogl_context));
|
||||
int drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
|
||||
meta_launcher_set_drm_fd (compositor->launcher, drm_fd, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
meta_monitor_manager_initialize ();
|
||||
monitors = meta_monitor_manager_get ();
|
||||
g_signal_connect (monitors, "monitors-changed",
|
||||
@@ -713,8 +704,8 @@ meta_wayland_finalize (void)
|
||||
|
||||
meta_xwayland_stop (&compositor->xwayland_manager);
|
||||
|
||||
if (compositor->launcher)
|
||||
meta_launcher_free (compositor->launcher);
|
||||
if (compositor->login1)
|
||||
meta_login1_free (compositor->login1);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -722,13 +713,28 @@ meta_wayland_compositor_activate_vt (MetaWaylandCompositor *compositor,
|
||||
int vt,
|
||||
GError **error)
|
||||
{
|
||||
if (compositor->launcher)
|
||||
if (compositor->login1)
|
||||
{
|
||||
return meta_launcher_activate_vt (compositor->launcher, vt, error);
|
||||
return meta_login1_activate_vt (compositor->login1, vt, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_debug ("Ignoring VT switch keybinding, not running as VT manager");
|
||||
g_debug ("Ignoring VT switch keybinding, not running as display server");
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_wayland_compositor_activate_session (MetaWaylandCompositor *compositor,
|
||||
GError **error)
|
||||
{
|
||||
if (compositor->login1)
|
||||
{
|
||||
return meta_login1_activate_session (compositor->login1, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_debug ("Ignoring activate_session, not running as display server");
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ void meta_wayland_compositor_paint_finished (MetaWaylandComp
|
||||
gboolean meta_wayland_compositor_activate_vt (MetaWaylandCompositor *compositor,
|
||||
int vt,
|
||||
GError **error);
|
||||
gboolean meta_wayland_compositor_activate_session (MetaWaylandCompositor *compositor,
|
||||
GError **error);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,401 +0,0 @@
|
||||
/*
|
||||
* 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 _MetaLauncher
|
||||
{
|
||||
GSocket *weston_launch;
|
||||
|
||||
gboolean vt_switched;
|
||||
|
||||
GMainContext *nested_context;
|
||||
GMainLoop *nested_loop;
|
||||
|
||||
GSource *inner_source;
|
||||
GSource *outer_source;
|
||||
};
|
||||
|
||||
static void handle_request_vt_switch (MetaLauncher *self);
|
||||
|
||||
static gboolean
|
||||
request_vt_switch_idle (gpointer user_data)
|
||||
{
|
||||
handle_request_vt_switch (user_data);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
send_message_to_wl (MetaLauncher *self,
|
||||
void *message,
|
||||
gsize size,
|
||||
GSocketControlMessage *out_cmsg,
|
||||
GSocketControlMessage **in_cmsg,
|
||||
GError **error)
|
||||
{
|
||||
struct weston_launcher_reply reply;
|
||||
GInputVector in_iov = { &reply, sizeof (reply) };
|
||||
GOutputVector out_iov = { message, size };
|
||||
GSocketControlMessage *out_all_cmsg[2];
|
||||
GSocketControlMessage **in_all_cmsg;
|
||||
int flags = 0;
|
||||
int i;
|
||||
|
||||
out_all_cmsg[0] = out_cmsg;
|
||||
out_all_cmsg[1] = NULL;
|
||||
if (g_socket_send_message (self->weston_launch, NULL,
|
||||
&out_iov, 1,
|
||||
out_all_cmsg, -1,
|
||||
flags, NULL, error) != (gssize)size)
|
||||
return FALSE;
|
||||
|
||||
if (g_socket_receive_message (self->weston_launch, NULL,
|
||||
&in_iov, 1,
|
||||
&in_all_cmsg, NULL,
|
||||
&flags, NULL, error) != sizeof (reply))
|
||||
return FALSE;
|
||||
|
||||
while (reply.header.opcode != ((struct weston_launcher_message*)message)->opcode)
|
||||
{
|
||||
/* There were events queued */
|
||||
g_assert ((reply.header.opcode & WESTON_LAUNCHER_EVENT) == WESTON_LAUNCHER_EVENT);
|
||||
|
||||
/* This can never happen, because the only time mutter-launch can queue
|
||||
this event is after confirming a VT switch, and we don't make requests
|
||||
during that time.
|
||||
|
||||
Note that getting this event would be really bad, because we would be
|
||||
in the wrong loop/context.
|
||||
*/
|
||||
g_assert (reply.header.opcode != WESTON_LAUNCHER_SERVER_VT_ENTER);
|
||||
|
||||
switch (reply.header.opcode)
|
||||
{
|
||||
case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH:
|
||||
g_idle_add (request_vt_switch_idle, self);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
if (g_socket_receive_message (self->weston_launch, NULL,
|
||||
&in_iov, 1,
|
||||
NULL, NULL,
|
||||
&flags, NULL, error) != sizeof (reply))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (reply.ret != 0)
|
||||
{
|
||||
if (reply.ret == -1)
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Got failure from weston-launch");
|
||||
else
|
||||
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-reply.ret),
|
||||
"Got failure from weston-launch: %s", strerror (-reply.ret));
|
||||
|
||||
for (i = 0; in_all_cmsg && in_all_cmsg[i]; i++)
|
||||
g_object_unref (in_all_cmsg[i]);
|
||||
g_free (in_all_cmsg);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (in_all_cmsg && in_all_cmsg[0])
|
||||
{
|
||||
for (i = 1; in_all_cmsg[i]; i++)
|
||||
g_object_unref (in_all_cmsg[i]);
|
||||
*in_cmsg = in_all_cmsg[0];
|
||||
}
|
||||
|
||||
g_free (in_all_cmsg);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_launcher_set_drm_fd (MetaLauncher *self,
|
||||
int drm_fd,
|
||||
GError **error)
|
||||
{
|
||||
struct weston_launcher_message message;
|
||||
GSocketControlMessage *cmsg;
|
||||
gboolean ok;
|
||||
|
||||
message.opcode = WESTON_LAUNCHER_DRM_SET_FD;
|
||||
|
||||
cmsg = g_unix_fd_message_new ();
|
||||
if (g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (cmsg),
|
||||
drm_fd, error) == FALSE)
|
||||
{
|
||||
g_object_unref (cmsg);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = send_message_to_wl (self, &message, sizeof message, cmsg, NULL, error);
|
||||
|
||||
g_object_unref (cmsg);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int
|
||||
meta_launcher_open_input_device (MetaLauncher *self,
|
||||
const char *name,
|
||||
int flags,
|
||||
GError **error)
|
||||
{
|
||||
struct weston_launcher_open *message;
|
||||
GSocketControlMessage *cmsg;
|
||||
gboolean ok;
|
||||
gsize size;
|
||||
int *fds, n_fd;
|
||||
int ret;
|
||||
|
||||
size = sizeof (struct weston_launcher_open) + strlen (name) + 1;
|
||||
message = g_malloc (size);
|
||||
message->header.opcode = WESTON_LAUNCHER_OPEN;
|
||||
message->flags = flags;
|
||||
strcpy (message->path, name);
|
||||
message->path[strlen(name)] = 0;
|
||||
|
||||
ok = send_message_to_wl (self, message, size, NULL, &cmsg, error);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
g_assert (G_IS_UNIX_FD_MESSAGE (cmsg));
|
||||
|
||||
fds = g_unix_fd_message_steal_fds (G_UNIX_FD_MESSAGE (cmsg), &n_fd);
|
||||
g_assert (n_fd == 1);
|
||||
|
||||
ret = fds[0];
|
||||
g_free (fds);
|
||||
g_object_unref (cmsg);
|
||||
}
|
||||
else
|
||||
ret = -1;
|
||||
|
||||
g_free (message);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_launcher_enter (MetaLauncher *launcher)
|
||||
{
|
||||
ClutterBackend *backend;
|
||||
CoglContext *cogl_context;
|
||||
CoglDisplay *cogl_display;
|
||||
|
||||
backend = clutter_get_default_backend ();
|
||||
cogl_context = clutter_backend_get_cogl_context (backend);
|
||||
cogl_display = cogl_context_get_display (cogl_context);
|
||||
cogl_kms_display_queue_modes_reset (cogl_display);
|
||||
|
||||
clutter_evdev_reclaim_devices ();
|
||||
}
|
||||
|
||||
static void
|
||||
meta_launcher_leave (MetaLauncher *launcher)
|
||||
{
|
||||
clutter_evdev_release_devices ();
|
||||
}
|
||||
|
||||
static int
|
||||
on_evdev_device_open (const char *path,
|
||||
int flags,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
MetaLauncher *launcher = user_data;
|
||||
|
||||
return meta_launcher_open_input_device (launcher, path, flags, error);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_vt_enter (MetaLauncher *launcher)
|
||||
{
|
||||
g_assert (launcher->vt_switched);
|
||||
|
||||
g_main_loop_quit (launcher->nested_loop);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_request_vt_switch (MetaLauncher *launcher)
|
||||
{
|
||||
struct weston_launcher_message message;
|
||||
GError *error;
|
||||
gboolean ok;
|
||||
|
||||
meta_launcher_leave (launcher);
|
||||
|
||||
message.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH;
|
||||
|
||||
error = NULL;
|
||||
ok = send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, &error);
|
||||
if (!ok) {
|
||||
g_warning ("Failed to acknowledge VT switch: %s", error->message);
|
||||
g_error_free (error);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert (!launcher->vt_switched);
|
||||
launcher->vt_switched = TRUE;
|
||||
|
||||
/* We can't do anything at this point, because we don't
|
||||
have input devices and we don't have the DRM master,
|
||||
so let's run a nested busy loop until the VT is reentered */
|
||||
g_main_loop_run (launcher->nested_loop);
|
||||
|
||||
g_assert (launcher->vt_switched);
|
||||
launcher->vt_switched = FALSE;
|
||||
|
||||
meta_launcher_enter (launcher);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_socket_readable (GSocket *socket,
|
||||
GIOCondition condition,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaLauncher *launcher = user_data;
|
||||
struct weston_launcher_event event;
|
||||
gssize read;
|
||||
GError *error;
|
||||
|
||||
if ((condition & G_IO_IN) == 0)
|
||||
return TRUE;
|
||||
|
||||
error = NULL;
|
||||
read = g_socket_receive (socket, (char*)&event, sizeof(event), NULL, &error);
|
||||
if (read < (gssize)sizeof(event))
|
||||
{
|
||||
g_warning ("Error reading from weston-launcher socket: %s", error->message);
|
||||
g_error_free (error);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
switch (event.header.opcode)
|
||||
{
|
||||
case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH:
|
||||
handle_request_vt_switch (launcher);
|
||||
break;
|
||||
|
||||
case WESTON_LAUNCHER_SERVER_VT_ENTER:
|
||||
handle_vt_enter (launcher);
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
env_get_fd (const char *env)
|
||||
{
|
||||
const char *value;
|
||||
|
||||
value = g_getenv (env);
|
||||
|
||||
if (value == NULL)
|
||||
return -1;
|
||||
else
|
||||
return g_ascii_strtoll (value, NULL, 10);
|
||||
}
|
||||
|
||||
MetaLauncher *
|
||||
meta_launcher_new (void)
|
||||
{
|
||||
MetaLauncher *self = g_slice_new0 (MetaLauncher);
|
||||
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);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
meta_launcher_free (MetaLauncher *launcher)
|
||||
{
|
||||
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_slice_free (MetaLauncher, launcher);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_launcher_activate_vt (MetaLauncher *launcher,
|
||||
int vt,
|
||||
GError **error)
|
||||
{
|
||||
struct weston_launcher_activate_vt message;
|
||||
|
||||
message.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT;
|
||||
message.vt = vt;
|
||||
|
||||
return send_message_to_wl (launcher, &message, sizeof (message), NULL, NULL, error);
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
typedef struct _MetaLauncher MetaLauncher;
|
||||
|
||||
MetaLauncher *meta_launcher_new (void);
|
||||
void meta_launcher_free (MetaLauncher *self);
|
||||
|
||||
gboolean meta_launcher_activate_vt (MetaLauncher *self,
|
||||
int number,
|
||||
GError **error);
|
||||
|
||||
gboolean meta_launcher_set_drm_fd (MetaLauncher *self,
|
||||
int drm_fd,
|
||||
GError **error);
|
||||
gboolean meta_launcher_set_master (MetaLauncher *self,
|
||||
gboolean master,
|
||||
GError **error);
|
||||
int meta_launcher_open_input_device (MetaLauncher *self,
|
||||
const char *name,
|
||||
int flags,
|
||||
GError **error);
|
||||
|
||||
#endif
|
||||
@@ -47,6 +47,13 @@ xserver_set_window_id (struct wl_client *client,
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
/* If the window has an existing surface, like if we're
|
||||
* undecorating or decorating the window, then we need
|
||||
* to detach the window from its old surface.
|
||||
*/
|
||||
if (window->surface)
|
||||
window->surface->window = NULL;
|
||||
|
||||
meta_wayland_surface_make_toplevel (surface);
|
||||
|
||||
surface->window = window;
|
||||
|
||||
@@ -1,788 +0,0 @@
|
||||
/*
|
||||
* 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 <xf86drm.h>
|
||||
|
||||
#include <systemd/sd-login.h>
|
||||
|
||||
#include "weston-launch.h"
|
||||
|
||||
#define MAX_ARGV_SIZE 256
|
||||
#define DRM_MAJOR 226
|
||||
|
||||
enum vt_state {
|
||||
VT_HAS_VT,
|
||||
VT_PENDING_CONFIRM,
|
||||
VT_NOT_HAVE_VT,
|
||||
};
|
||||
|
||||
struct weston_launch {
|
||||
int tty;
|
||||
int ttynr;
|
||||
int sock[2];
|
||||
struct passwd *pw;
|
||||
|
||||
int signalfd;
|
||||
|
||||
pid_t child;
|
||||
int verbose;
|
||||
|
||||
struct termios terminal_attributes;
|
||||
int kb_mode;
|
||||
enum vt_state vt_state;
|
||||
|
||||
int drm_fd;
|
||||
};
|
||||
|
||||
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_setdrmfd(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
|
||||
{
|
||||
struct weston_launcher_reply reply;
|
||||
struct cmsghdr *cmsg;
|
||||
union cmsg_data *data;
|
||||
struct stat s;
|
||||
|
||||
reply.header.opcode = WESTON_LAUNCHER_DRM_SET_FD;
|
||||
reply.ret = -1;
|
||||
|
||||
if (wl->drm_fd != -1) {
|
||||
error(0, 0, "DRM FD already set");
|
||||
reply.ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(msg);
|
||||
if (!cmsg ||
|
||||
cmsg->cmsg_level != SOL_SOCKET ||
|
||||
cmsg->cmsg_type != SCM_RIGHTS) {
|
||||
error(0, 0, "invalid control message");
|
||||
reply.ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
data = (union cmsg_data *) CMSG_DATA(cmsg);
|
||||
if (data->fd < 0) {
|
||||
error(0, 0, "missing drm fd in socket request");
|
||||
reply.ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fstat(data->fd, &s) < 0) {
|
||||
reply.ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (major(s.st_rdev) != DRM_MAJOR) {
|
||||
fprintf(stderr, "FD is not for DRM\n");
|
||||
reply.ret = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl->drm_fd = data->fd;
|
||||
reply.ret = drmSetMaster(data->fd);
|
||||
if (reply.ret < 0)
|
||||
reply.ret = -errno;
|
||||
|
||||
if (wl->verbose)
|
||||
fprintf(stderr, "mutter-launch: set drm FD, ret: %d, fd: %d\n",
|
||||
reply.ret, data->fd);
|
||||
|
||||
out:
|
||||
do {
|
||||
len = send(wl->sock[0], &reply, sizeof reply, 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)
|
||||
{
|
||||
struct weston_launcher_reply reply;
|
||||
|
||||
reply.header.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH;
|
||||
reply.ret = -1;
|
||||
|
||||
if (wl->vt_state != VT_PENDING_CONFIRM) {
|
||||
error(0, 0, "unexpected CONFIRM_VT_SWITCH");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (wl->drm_fd != -1) {
|
||||
int ret;
|
||||
|
||||
ret = drmDropMaster(wl->drm_fd);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "failed to drop DRM master: %m\n");
|
||||
} else if (wl->verbose) {
|
||||
fprintf(stderr, "dropped DRM master for VT switch\n");
|
||||
}
|
||||
}
|
||||
|
||||
wl->vt_state = VT_NOT_HAVE_VT;
|
||||
ioctl(wl->tty, VT_RELDISP, 1);
|
||||
|
||||
if (wl->verbose)
|
||||
fprintf(stderr, "mutter-launcher: confirmed VT switch\n");
|
||||
|
||||
reply.ret = 0;
|
||||
|
||||
out:
|
||||
do {
|
||||
len = send(wl->sock[0], &reply, sizeof reply, 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)
|
||||
{
|
||||
struct weston_launcher_reply reply;
|
||||
struct weston_launcher_activate_vt *message;
|
||||
|
||||
reply.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT;
|
||||
reply.ret = -1;
|
||||
|
||||
if (len != sizeof(*message)) {
|
||||
error(0, 0, "missing value in activate_vt request");
|
||||
goto out;
|
||||
}
|
||||
|
||||
message = msg->msg_iov->iov_base;
|
||||
|
||||
reply.ret = ioctl(wl->tty, VT_ACTIVATE, message->vt);
|
||||
if (reply.ret < 0)
|
||||
reply.ret = -errno;
|
||||
|
||||
if (wl->verbose)
|
||||
fprintf(stderr, "mutter-launch: activate VT, ret: %d\n", reply.ret);
|
||||
|
||||
out:
|
||||
do {
|
||||
len = send(wl->sock[0], &reply, sizeof reply, 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)
|
||||
{
|
||||
struct weston_launcher_reply reply;
|
||||
int fd = -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;
|
||||
|
||||
reply.header.opcode = WESTON_LAUNCHER_OPEN;
|
||||
reply.ret = -1;
|
||||
|
||||
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) {
|
||||
reply.ret = -errno;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
fd = open(message->path, message->flags);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Error opening device %s: %m\n",
|
||||
message->path);
|
||||
reply.ret = -errno;
|
||||
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);
|
||||
reply.ret = -EPERM;
|
||||
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;
|
||||
reply.ret = 0;
|
||||
}
|
||||
iov.iov_base = &reply;
|
||||
iov.iov_len = sizeof reply;
|
||||
|
||||
if (wl->verbose)
|
||||
fprintf(stderr, "mutter-launch: opened %s: ret: %d, fd: %d\n",
|
||||
message->path, reply.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_FD:
|
||||
ret = handle_setdrmfd(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)
|
||||
{
|
||||
if (wl->child > 0)
|
||||
kill(wl->child, SIGKILL);
|
||||
|
||||
close(wl->signalfd);
|
||||
close(wl->sock[0]);
|
||||
|
||||
if (wl->drm_fd > 0)
|
||||
close(wl->drm_fd);
|
||||
|
||||
tty_reset(wl);
|
||||
|
||||
exit(status);
|
||||
}
|
||||
|
||||
static int
|
||||
handle_vt_switch(struct weston_launch *wl)
|
||||
{
|
||||
struct weston_launcher_event message;
|
||||
ssize_t len;
|
||||
|
||||
if (wl->vt_state == VT_HAS_VT) {
|
||||
wl->vt_state = VT_PENDING_CONFIRM;
|
||||
message.header.opcode = WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH;
|
||||
} else if (wl->vt_state == VT_NOT_HAVE_VT) {
|
||||
wl->vt_state = VT_HAS_VT;
|
||||
ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
|
||||
|
||||
if (wl->drm_fd != -1) {
|
||||
int ret;
|
||||
|
||||
ret = drmSetMaster(wl->drm_fd);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "failed to become DRM master: %m\n");
|
||||
/* This is very, very bad, and the compositor will crash soon,
|
||||
but oh well... */
|
||||
} else if (wl->verbose) {
|
||||
fprintf(stderr, "became DRM master after VT switch\n");
|
||||
}
|
||||
}
|
||||
|
||||
message.header.opcode = WESTON_LAUNCHER_SERVER_VT_ENTER;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
message.detail = 0;
|
||||
|
||||
do {
|
||||
len = send(wl->sock[0], &message, sizeof(message), 0);
|
||||
} while (len < 0 && errno == EINTR);
|
||||
|
||||
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) {
|
||||
/* Old systemd only has the tty name in the TTY
|
||||
field, new one has the full char device path.
|
||||
|
||||
Check what we have and fix it properly.
|
||||
*/
|
||||
if (strncmp(tty, "/dev", strlen("/dev")) == 0) {
|
||||
strncpy(path, tty, PATH_MAX);
|
||||
path[PATH_MAX-1] = 0;
|
||||
} else {
|
||||
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) {
|
||||
unsigned vt;
|
||||
|
||||
/* 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, &vt);
|
||||
if (ok < 0)
|
||||
error(1, -ok, "could not determine current TTY");
|
||||
|
||||
snprintf(path, PATH_MAX, "/dev/tty%u", vt);
|
||||
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);
|
||||
wl.drm_fd = -1;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
|
||||
switch (c) {
|
||||
case 'v':
|
||||
wl.verbose = 1;
|
||||
break;
|
||||
case 'h':
|
||||
help("mutter-launch");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if ((argc - optind) > (MAX_ARGV_SIZE - 6))
|
||||
error(1, E2BIG, "Too many arguments to pass to weston");
|
||||
|
||||
if (optind >= argc)
|
||||
error(1, 0, "Expected program argument");
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* 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_message_type {
|
||||
WESTON_LAUNCHER_REQUEST,
|
||||
WESTON_LAUNCHER_EVENT,
|
||||
};
|
||||
|
||||
enum weston_launcher_opcode {
|
||||
WESTON_LAUNCHER_OPEN = (1 << 1 | WESTON_LAUNCHER_REQUEST),
|
||||
WESTON_LAUNCHER_DRM_SET_FD = (2 << 1 | WESTON_LAUNCHER_REQUEST),
|
||||
WESTON_LAUNCHER_ACTIVATE_VT = (3 << 1 | WESTON_LAUNCHER_REQUEST),
|
||||
WESTON_LAUNCHER_CONFIRM_VT_SWITCH = (4 << 1 | WESTON_LAUNCHER_REQUEST),
|
||||
};
|
||||
|
||||
enum weston_launcher_server_opcode {
|
||||
WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH = (1 << 1 | WESTON_LAUNCHER_EVENT),
|
||||
WESTON_LAUNCHER_SERVER_VT_ENTER = (2 << 1 | WESTON_LAUNCHER_EVENT),
|
||||
};
|
||||
|
||||
struct weston_launcher_message {
|
||||
int opcode;
|
||||
};
|
||||
|
||||
struct weston_launcher_open {
|
||||
struct weston_launcher_message header;
|
||||
int flags;
|
||||
char path[0];
|
||||
};
|
||||
|
||||
struct weston_launcher_activate_vt {
|
||||
struct weston_launcher_message header;
|
||||
int vt;
|
||||
};
|
||||
|
||||
struct weston_launcher_reply {
|
||||
struct weston_launcher_message header;
|
||||
int ret;
|
||||
};
|
||||
|
||||
struct weston_launcher_event {
|
||||
struct weston_launcher_message header;
|
||||
int detail; /* unused, but makes sure replies and events are serialized the same */
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user