Compare commits
7 Commits
wip/waylan
...
wip/waylan
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10fbaf7695 | ||
|
|
ef73402654 | ||
|
|
22cdf2d650 | ||
|
|
284b497b4c | ||
|
|
7d9141c56f | ||
|
|
519a06b93d | ||
|
|
0cceddab75 |
@@ -139,12 +139,6 @@ AM_GLIB_GNU_GETTEXT
|
|||||||
## here we get the flags we'll actually use
|
## here we get the flags we'll actually use
|
||||||
# GRegex requires Glib-2.14.0
|
# GRegex requires Glib-2.14.0
|
||||||
PKG_CHECK_MODULES(ALL, glib-2.0 >= 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
|
# Unconditionally use this dir to avoid a circular dep with gnomecc
|
||||||
GNOME_KEYBINDINGS_KEYSDIR="${datadir}/gnome-control-center/keybindings"
|
GNOME_KEYBINDINGS_KEYSDIR="${datadir}/gnome-control-center/keybindings"
|
||||||
@@ -232,7 +226,7 @@ AS_IF([test "x$WAYLAND_SCANNER" = "xno"],
|
|||||||
AC_SUBST([WAYLAND_SCANNER])
|
AC_SUBST([WAYLAND_SCANNER])
|
||||||
AC_SUBST(XWAYLAND_PATH)
|
AC_SUBST(XWAYLAND_PATH)
|
||||||
|
|
||||||
MUTTER_PC_MODULES="$MUTTER_PC_MODULES wayland-server libdrm"
|
MUTTER_PC_MODULES="$MUTTER_PC_MODULES wayland-server"
|
||||||
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
|
PKG_CHECK_MODULES(MUTTER, $MUTTER_PC_MODULES)
|
||||||
|
|
||||||
PKG_CHECK_EXISTS([xi >= 1.6.99.1],
|
PKG_CHECK_EXISTS([xi >= 1.6.99.1],
|
||||||
|
|||||||
@@ -195,9 +195,7 @@ libmutter_wayland_la_SOURCES += \
|
|||||||
wayland/meta-wayland-seat.c \
|
wayland/meta-wayland-seat.c \
|
||||||
wayland/meta-wayland-seat.h \
|
wayland/meta-wayland-seat.h \
|
||||||
wayland/meta-wayland-stage.h \
|
wayland/meta-wayland-stage.h \
|
||||||
wayland/meta-wayland-stage.c \
|
wayland/meta-wayland-stage.c
|
||||||
wayland/meta-weston-launch.c \
|
|
||||||
wayland/meta-weston-launch.h
|
|
||||||
|
|
||||||
libmutter_wayland_la_LDFLAGS = -no-undefined
|
libmutter_wayland_la_LDFLAGS = -no-undefined
|
||||||
libmutter_wayland_la_LIBADD = $(MUTTER_LIBS)
|
libmutter_wayland_la_LIBADD = $(MUTTER_LIBS)
|
||||||
@@ -249,17 +247,6 @@ bin_PROGRAMS=mutter-wayland
|
|||||||
mutter_wayland_SOURCES = core/mutter.c
|
mutter_wayland_SOURCES = core/mutter.c
|
||||||
mutter_wayland_LDADD = $(MUTTER_LIBS) libmutter-wayland.la
|
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
|
if HAVE_INTROSPECTION
|
||||||
include $(INTROSPECTION_MAKEFILE)
|
include $(INTROSPECTION_MAKEFILE)
|
||||||
|
|
||||||
@@ -319,7 +306,7 @@ xml_DATA = $(xml_in_files:.xml.in=.xml)
|
|||||||
|
|
||||||
dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h
|
dbus_idle_built_sources = meta-dbus-idle-monitor.c meta-dbus-idle-monitor.h
|
||||||
|
|
||||||
gsettings_SCHEMAS = org.gnome.mutter.gschema.xml org.gnome.mutter.wayland.gschema.xml
|
gsettings_SCHEMAS = org.gnome.mutter.gschema.xml
|
||||||
@INTLTOOL_XML_NOMERGE_RULE@
|
@INTLTOOL_XML_NOMERGE_RULE@
|
||||||
@GSETTINGS_RULES@
|
@GSETTINGS_RULES@
|
||||||
|
|
||||||
|
|||||||
@@ -930,8 +930,8 @@ is_grabbed_event (MetaDisplay *display,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_compositor_window_x11_shape_changed (MetaCompositor *compositor,
|
meta_compositor_window_shape_changed (MetaCompositor *compositor,
|
||||||
MetaWindow *window)
|
MetaWindow *window)
|
||||||
{
|
{
|
||||||
MetaWindowActor *window_actor;
|
MetaWindowActor *window_actor;
|
||||||
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
||||||
|
|||||||
@@ -91,11 +91,10 @@ struct _MetaShapedTexturePrivate
|
|||||||
CoglTexture *texture;
|
CoglTexture *texture;
|
||||||
|
|
||||||
CoglTexture *mask_texture;
|
CoglTexture *mask_texture;
|
||||||
CoglPipeline *pipeline;
|
|
||||||
CoglPipeline *pipeline_unshaped;
|
|
||||||
|
|
||||||
cairo_region_t *clip_region;
|
cairo_region_t *clip_region;
|
||||||
cairo_region_t *input_shape_region;
|
cairo_region_t *input_shape_region;
|
||||||
|
cairo_region_t *opaque_region;
|
||||||
|
|
||||||
guint tex_width, tex_height;
|
guint tex_width, tex_height;
|
||||||
|
|
||||||
@@ -145,8 +144,6 @@ meta_shaped_texture_dispose (GObject *object)
|
|||||||
meta_texture_tower_free (priv->paint_tower);
|
meta_texture_tower_free (priv->paint_tower);
|
||||||
priv->paint_tower = NULL;
|
priv->paint_tower = NULL;
|
||||||
|
|
||||||
g_clear_pointer (&priv->pipeline, cogl_object_unref);
|
|
||||||
g_clear_pointer (&priv->pipeline_unshaped, cogl_object_unref);
|
|
||||||
g_clear_pointer (&priv->texture, cogl_object_unref);
|
g_clear_pointer (&priv->texture, cogl_object_unref);
|
||||||
|
|
||||||
meta_shaped_texture_set_mask_texture (self, NULL);
|
meta_shaped_texture_set_mask_texture (self, NULL);
|
||||||
@@ -155,6 +152,76 @@ meta_shaped_texture_dispose (GObject *object)
|
|||||||
G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object);
|
G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CoglPipeline *
|
||||||
|
get_unmasked_pipeline (CoglContext *ctx)
|
||||||
|
{
|
||||||
|
return cogl_pipeline_new (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CoglPipeline *
|
||||||
|
get_masked_pipeline (CoglContext *ctx)
|
||||||
|
{
|
||||||
|
static CoglPipeline *template = NULL;
|
||||||
|
if (G_UNLIKELY (template == NULL))
|
||||||
|
{
|
||||||
|
template = cogl_pipeline_new (ctx);
|
||||||
|
cogl_pipeline_set_layer_combine (template, 1,
|
||||||
|
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cogl_pipeline_copy (template);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CoglPipeline *
|
||||||
|
get_unblended_pipeline (CoglContext *ctx)
|
||||||
|
{
|
||||||
|
static CoglPipeline *template = NULL;
|
||||||
|
if (G_UNLIKELY (template == NULL))
|
||||||
|
{
|
||||||
|
CoglColor color;
|
||||||
|
template = cogl_pipeline_new (ctx);
|
||||||
|
cogl_color_init_from_4ub (&color, 255, 255, 255, 255);
|
||||||
|
cogl_pipeline_set_blend (template,
|
||||||
|
"RGBA = ADD (SRC_COLOR, 0)",
|
||||||
|
NULL);
|
||||||
|
cogl_pipeline_set_color (template, &color);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cogl_pipeline_copy (template);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
paint_clipped_rectangle (CoglFramebuffer *fb,
|
||||||
|
CoglPipeline *pipeline,
|
||||||
|
cairo_rectangle_int_t *rect,
|
||||||
|
ClutterActorBox *alloc)
|
||||||
|
{
|
||||||
|
float coords[8];
|
||||||
|
float x1, y1, x2, y2;
|
||||||
|
|
||||||
|
x1 = rect->x;
|
||||||
|
y1 = rect->y;
|
||||||
|
x2 = rect->x + rect->width;
|
||||||
|
y2 = rect->y + rect->height;
|
||||||
|
|
||||||
|
coords[0] = rect->x / (alloc->x2 - alloc->x1);
|
||||||
|
coords[1] = rect->y / (alloc->y2 - alloc->y1);
|
||||||
|
coords[2] = (rect->x + rect->width) / (alloc->x2 - alloc->x1);
|
||||||
|
coords[3] = (rect->y + rect->height) / (alloc->y2 - alloc->y1);
|
||||||
|
|
||||||
|
coords[4] = coords[0];
|
||||||
|
coords[5] = coords[1];
|
||||||
|
coords[6] = coords[2];
|
||||||
|
coords[7] = coords[3];
|
||||||
|
|
||||||
|
cogl_framebuffer_draw_multitextured_rectangle (fb, pipeline,
|
||||||
|
x1, y1, x2, y2,
|
||||||
|
&coords[0], 8);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_cogl_texture (MetaShapedTexture *stex,
|
set_cogl_texture (MetaShapedTexture *stex,
|
||||||
CoglTexture *cogl_tex)
|
CoglTexture *cogl_tex)
|
||||||
@@ -171,12 +238,6 @@ set_cogl_texture (MetaShapedTexture *stex,
|
|||||||
|
|
||||||
priv->texture = cogl_tex;
|
priv->texture = cogl_tex;
|
||||||
|
|
||||||
if (priv->pipeline != NULL)
|
|
||||||
cogl_pipeline_set_layer_texture (priv->pipeline, 0, COGL_TEXTURE (cogl_tex));
|
|
||||||
|
|
||||||
if (priv->pipeline_unshaped != NULL)
|
|
||||||
cogl_pipeline_set_layer_texture (priv->pipeline_unshaped, 0, COGL_TEXTURE (cogl_tex));
|
|
||||||
|
|
||||||
if (cogl_tex != NULL)
|
if (cogl_tex != NULL)
|
||||||
{
|
{
|
||||||
width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex));
|
width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex));
|
||||||
@@ -210,14 +271,14 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
|||||||
{
|
{
|
||||||
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
|
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
|
||||||
MetaShapedTexturePrivate *priv = stex->priv;
|
MetaShapedTexturePrivate *priv = stex->priv;
|
||||||
CoglTexture *paint_tex;
|
|
||||||
guint tex_width, tex_height;
|
guint tex_width, tex_height;
|
||||||
|
guchar opacity;
|
||||||
|
CoglContext *ctx;
|
||||||
|
CoglFramebuffer *fb;
|
||||||
|
CoglPipeline *pipeline = NULL;
|
||||||
|
CoglTexture *paint_tex;
|
||||||
ClutterActorBox alloc;
|
ClutterActorBox alloc;
|
||||||
|
cairo_region_t *blended_region = NULL;
|
||||||
static CoglPipeline *pipeline_template = NULL;
|
|
||||||
static CoglPipeline *pipeline_unshaped_template = NULL;
|
|
||||||
|
|
||||||
CoglPipeline *pipeline;
|
|
||||||
|
|
||||||
if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
|
if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
|
||||||
return;
|
return;
|
||||||
@@ -254,38 +315,67 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
|||||||
if (tex_width == 0 || tex_height == 0) /* no contents yet */
|
if (tex_width == 0 || tex_height == 0) /* no contents yet */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||||
|
fb = cogl_get_draw_framebuffer ();
|
||||||
|
|
||||||
|
opacity = clutter_actor_get_paint_opacity (actor);
|
||||||
|
clutter_actor_get_allocation_box (actor, &alloc);
|
||||||
|
|
||||||
|
if (priv->opaque_region != NULL && opacity == 255)
|
||||||
|
{
|
||||||
|
CoglPipeline *opaque_pipeline;
|
||||||
|
cairo_region_t *region;
|
||||||
|
int n_rects;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
region = cairo_region_copy (priv->clip_region);
|
||||||
|
cairo_region_intersect (region, priv->opaque_region);
|
||||||
|
|
||||||
|
if (cairo_region_is_empty (region))
|
||||||
|
goto paint_blended;
|
||||||
|
|
||||||
|
opaque_pipeline = get_unblended_pipeline (ctx);
|
||||||
|
cogl_pipeline_set_layer_texture (opaque_pipeline, 0, paint_tex);
|
||||||
|
|
||||||
|
n_rects = cairo_region_num_rectangles (region);
|
||||||
|
for (i = 0; i < n_rects; i++)
|
||||||
|
{
|
||||||
|
cairo_rectangle_int_t rect;
|
||||||
|
cairo_region_get_rectangle (region, i, &rect);
|
||||||
|
paint_clipped_rectangle (fb, opaque_pipeline, &rect, &alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
cogl_object_unref (opaque_pipeline);
|
||||||
|
|
||||||
|
if (priv->clip_region != NULL)
|
||||||
|
{
|
||||||
|
blended_region = cairo_region_copy (priv->clip_region);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cairo_rectangle_int_t rect = { 0, 0, tex_width, tex_height };
|
||||||
|
blended_region = cairo_region_create_rectangle (&rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
cairo_region_subtract (blended_region, priv->opaque_region);
|
||||||
|
|
||||||
|
paint_blended:
|
||||||
|
cairo_region_destroy (region);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blended_region == NULL && priv->clip_region != NULL)
|
||||||
|
blended_region = cairo_region_reference (priv->clip_region);
|
||||||
|
|
||||||
|
if (blended_region != NULL && cairo_region_is_empty (blended_region))
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (priv->mask_texture == NULL)
|
if (priv->mask_texture == NULL)
|
||||||
{
|
{
|
||||||
/* Use a single-layer texture if we don't have a mask. */
|
pipeline = get_unmasked_pipeline (ctx);
|
||||||
|
|
||||||
if (priv->pipeline_unshaped == NULL)
|
|
||||||
{
|
|
||||||
if (G_UNLIKELY (pipeline_unshaped_template == NULL))
|
|
||||||
{
|
|
||||||
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
|
||||||
pipeline_unshaped_template = cogl_pipeline_new (ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->pipeline_unshaped = cogl_pipeline_copy (pipeline_unshaped_template);
|
|
||||||
}
|
|
||||||
pipeline = priv->pipeline_unshaped;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (priv->pipeline == NULL)
|
pipeline = get_masked_pipeline (ctx);
|
||||||
{
|
|
||||||
if (G_UNLIKELY (pipeline_template == NULL))
|
|
||||||
{
|
|
||||||
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
|
||||||
pipeline_template = cogl_pipeline_new (ctx);
|
|
||||||
cogl_pipeline_set_layer_combine (pipeline_template, 1,
|
|
||||||
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
priv->pipeline = cogl_pipeline_copy (pipeline_template);
|
|
||||||
}
|
|
||||||
pipeline = priv->pipeline;
|
|
||||||
|
|
||||||
cogl_pipeline_set_layer_texture (pipeline, 1, priv->mask_texture);
|
cogl_pipeline_set_layer_texture (pipeline, 1, priv->mask_texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,20 +383,13 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
|||||||
|
|
||||||
{
|
{
|
||||||
CoglColor color;
|
CoglColor color;
|
||||||
guchar opacity = clutter_actor_get_paint_opacity (actor);
|
cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity);
|
||||||
cogl_color_set_from_4ub (&color, opacity, opacity, opacity, opacity);
|
|
||||||
cogl_pipeline_set_color (pipeline, &color);
|
cogl_pipeline_set_color (pipeline, &color);
|
||||||
}
|
}
|
||||||
|
|
||||||
cogl_set_source (pipeline);
|
if (blended_region != NULL)
|
||||||
|
|
||||||
clutter_actor_get_allocation_box (actor, &alloc);
|
|
||||||
|
|
||||||
if (priv->clip_region)
|
|
||||||
{
|
{
|
||||||
int n_rects;
|
int n_rects;
|
||||||
int i;
|
|
||||||
cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height };
|
|
||||||
|
|
||||||
/* Limit to how many separate rectangles we'll draw; beyond this just
|
/* Limit to how many separate rectangles we'll draw; beyond this just
|
||||||
* fall back and draw the whole thing */
|
* fall back and draw the whole thing */
|
||||||
@@ -315,8 +398,8 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
|||||||
n_rects = cairo_region_num_rectangles (priv->clip_region);
|
n_rects = cairo_region_num_rectangles (priv->clip_region);
|
||||||
if (n_rects <= MAX_RECTS)
|
if (n_rects <= MAX_RECTS)
|
||||||
{
|
{
|
||||||
float coords[8];
|
int i;
|
||||||
float x1, y1, x2, y2;
|
cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height };
|
||||||
|
|
||||||
for (i = 0; i < n_rects; i++)
|
for (i = 0; i < n_rects; i++)
|
||||||
{
|
{
|
||||||
@@ -327,32 +410,23 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
|||||||
if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect))
|
if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
x1 = rect.x;
|
paint_clipped_rectangle (fb, pipeline, &rect, &alloc);
|
||||||
y1 = rect.y;
|
|
||||||
x2 = rect.x + rect.width;
|
|
||||||
y2 = rect.y + rect.height;
|
|
||||||
|
|
||||||
coords[0] = rect.x / (alloc.x2 - alloc.x1);
|
|
||||||
coords[1] = rect.y / (alloc.y2 - alloc.y1);
|
|
||||||
coords[2] = (rect.x + rect.width) / (alloc.x2 - alloc.x1);
|
|
||||||
coords[3] = (rect.y + rect.height) / (alloc.y2 - alloc.y1);
|
|
||||||
|
|
||||||
coords[4] = coords[0];
|
|
||||||
coords[5] = coords[1];
|
|
||||||
coords[6] = coords[2];
|
|
||||||
coords[7] = coords[3];
|
|
||||||
|
|
||||||
cogl_rectangle_with_multitexture_coords (x1, y1, x2, y2,
|
|
||||||
&coords[0], 8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cogl_rectangle (0, 0,
|
cogl_framebuffer_draw_rectangle (fb, pipeline,
|
||||||
alloc.x2 - alloc.x1,
|
0, 0,
|
||||||
alloc.y2 - alloc.y1);
|
alloc.x2 - alloc.x1,
|
||||||
|
alloc.y2 - alloc.y1);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (pipeline != NULL)
|
||||||
|
cogl_object_unref (pipeline);
|
||||||
|
if (blended_region != NULL)
|
||||||
|
cairo_region_destroy (blended_region);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -368,13 +442,17 @@ meta_shaped_texture_pick (ClutterActor *actor,
|
|||||||
|
|
||||||
/* If there is no region then use the regular pick */
|
/* If there is no region then use the regular pick */
|
||||||
if (priv->input_shape_region == NULL)
|
if (priv->input_shape_region == NULL)
|
||||||
CLUTTER_ACTOR_CLASS (meta_shaped_texture_parent_class)
|
CLUTTER_ACTOR_CLASS (meta_shaped_texture_parent_class)->pick (actor, color);
|
||||||
->pick (actor, color);
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int n_rects;
|
int n_rects;
|
||||||
float *rectangles;
|
float *rectangles;
|
||||||
int i;
|
int i;
|
||||||
|
ClutterActorBox alloc;
|
||||||
|
CoglPipeline *pipeline;
|
||||||
|
CoglContext *ctx;
|
||||||
|
CoglFramebuffer *fb;
|
||||||
|
CoglColor cogl_color;
|
||||||
|
|
||||||
/* Note: We don't bother trying to intersect the pick and clip regions
|
/* Note: We don't bother trying to intersect the pick and clip regions
|
||||||
* since needing to copy the region, do the intersection, and probably
|
* since needing to copy the region, do the intersection, and probably
|
||||||
@@ -403,12 +481,17 @@ meta_shaped_texture_pick (ClutterActor *actor,
|
|||||||
rectangles[pos + 3] = rect.y + rect.height;
|
rectangles[pos + 3] = rect.y + rect.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
cogl_set_source_color4ub (color->red,
|
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||||
color->green,
|
fb = cogl_get_draw_framebuffer ();
|
||||||
color->blue,
|
|
||||||
color->alpha);
|
|
||||||
|
|
||||||
cogl_rectangles (rectangles, n_rects);
|
cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha);
|
||||||
|
|
||||||
|
pipeline = cogl_pipeline_new (ctx);
|
||||||
|
cogl_pipeline_set_color (pipeline, &cogl_color);
|
||||||
|
|
||||||
|
cogl_framebuffer_draw_rectangles (fb, pipeline,
|
||||||
|
rectangles, n_rects);
|
||||||
|
cogl_object_unref (pipeline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -845,6 +928,36 @@ meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
|
|||||||
priv->clip_region = NULL;
|
priv->clip_region = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* meta_shaped_texture_set_opaque_region:
|
||||||
|
* @stex: a #MetaShapedTexture
|
||||||
|
* @opaque_region: (transfer full): the region of the texture that
|
||||||
|
* can have blending turned off.
|
||||||
|
*
|
||||||
|
* As most windows have a large portion that does not require blending,
|
||||||
|
* we can easily turn off blending if we know the areas that do not
|
||||||
|
* require blending. This sets the region where we will not blend for
|
||||||
|
* optimization purposes.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex,
|
||||||
|
cairo_region_t *opaque_region)
|
||||||
|
{
|
||||||
|
MetaShapedTexturePrivate *priv;
|
||||||
|
|
||||||
|
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
||||||
|
|
||||||
|
priv = stex->priv;
|
||||||
|
|
||||||
|
if (priv->opaque_region)
|
||||||
|
cairo_region_destroy (priv->opaque_region);
|
||||||
|
|
||||||
|
if (opaque_region)
|
||||||
|
priv->opaque_region = cairo_region_reference (opaque_region);
|
||||||
|
else
|
||||||
|
priv->opaque_region = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* meta_shaped_texture_get_image:
|
* meta_shaped_texture_get_image:
|
||||||
* @stex: A #MetaShapedTexture
|
* @stex: A #MetaShapedTexture
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include <X11/extensions/shape.h>
|
|
||||||
#include <X11/extensions/Xcomposite.h>
|
#include <X11/extensions/Xcomposite.h>
|
||||||
#include <X11/extensions/Xdamage.h>
|
#include <X11/extensions/Xdamage.h>
|
||||||
#include <X11/extensions/Xrender.h>
|
#include <X11/extensions/Xrender.h>
|
||||||
@@ -71,7 +70,7 @@ struct _MetaWindowActorPrivate
|
|||||||
/* A region that matches the shape of the window, including frame bounds */
|
/* A region that matches the shape of the window, including frame bounds */
|
||||||
cairo_region_t *shape_region;
|
cairo_region_t *shape_region;
|
||||||
/* If the window has an input shape, a region that matches the shape */
|
/* If the window has an input shape, a region that matches the shape */
|
||||||
cairo_region_t *input_shape_region;
|
cairo_region_t *input_region;
|
||||||
/* The opaque region, from _NET_WM_OPAQUE_REGION, intersected with
|
/* The opaque region, from _NET_WM_OPAQUE_REGION, intersected with
|
||||||
* the shape region. */
|
* the shape region. */
|
||||||
cairo_region_t *opaque_region;
|
cairo_region_t *opaque_region;
|
||||||
@@ -407,8 +406,8 @@ meta_window_actor_constructed (GObject *object)
|
|||||||
|
|
||||||
/* Start off with empty regions to maintain the invariant that
|
/* Start off with empty regions to maintain the invariant that
|
||||||
these regions are always set */
|
these regions are always set */
|
||||||
priv->shape_region = cairo_region_create();
|
priv->shape_region = cairo_region_create ();
|
||||||
priv->input_shape_region = cairo_region_create();
|
priv->input_region = cairo_region_create ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -438,7 +437,7 @@ meta_window_actor_dispose (GObject *object)
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_clear_pointer (&priv->shape_region, cairo_region_destroy);
|
g_clear_pointer (&priv->shape_region, cairo_region_destroy);
|
||||||
g_clear_pointer (&priv->input_shape_region, cairo_region_destroy);
|
g_clear_pointer (&priv->input_region, cairo_region_destroy);
|
||||||
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
|
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
|
||||||
g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
|
g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
|
||||||
|
|
||||||
@@ -1260,7 +1259,7 @@ meta_window_actor_should_unredirect (MetaWindowActor *self)
|
|||||||
if (priv->opacity != 0xff)
|
if (priv->opacity != 0xff)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (metaWindow->has_shape)
|
if (metaWindow->shape_region != NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (priv->argb32 && !meta_window_requested_bypass_compositor (metaWindow))
|
if (priv->argb32 && !meta_window_requested_bypass_compositor (metaWindow))
|
||||||
@@ -2171,85 +2170,21 @@ build_and_scan_frame_mask (MetaWindowActor *self,
|
|||||||
g_free (mask_data);
|
g_free (mask_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static cairo_region_t *
|
|
||||||
region_create_from_x_rectangles (const XRectangle *rects,
|
|
||||||
int n_rects,
|
|
||||||
int dx,
|
|
||||||
int dy)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
cairo_rectangle_int_t *cairo_rects = g_newa (cairo_rectangle_int_t, n_rects);
|
|
||||||
|
|
||||||
for (i = 0; i < n_rects; i ++)
|
|
||||||
{
|
|
||||||
cairo_rects[i].x = rects[i].x + dx;
|
|
||||||
cairo_rects[i].y = rects[i].y + dy;
|
|
||||||
cairo_rects[i].width = rects[i].width;
|
|
||||||
cairo_rects[i].height = rects[i].height;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cairo_region_create_rectangles (cairo_rects, n_rects);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
meta_window_actor_update_x11_shape_region (MetaWindowActor *self,
|
meta_window_actor_update_shape_region (MetaWindowActor *self,
|
||||||
cairo_rectangle_int_t *client_area)
|
cairo_rectangle_int_t *client_area)
|
||||||
{
|
{
|
||||||
MetaWindowActorPrivate *priv = self->priv;
|
MetaWindowActorPrivate *priv = self->priv;
|
||||||
cairo_region_t *region = NULL;
|
cairo_region_t *region = NULL;
|
||||||
gboolean needs_mask;
|
|
||||||
|
|
||||||
if (priv->shadow_shape != NULL)
|
if (priv->window->frame != NULL && priv->window->shape_region != NULL)
|
||||||
{
|
{
|
||||||
meta_window_shape_unref (priv->shadow_shape);
|
region = cairo_region_copy (priv->window->shape_region);
|
||||||
priv->shadow_shape = NULL;
|
cairo_region_translate (region, client_area->x, client_area->y);
|
||||||
}
|
}
|
||||||
|
else if (priv->window->shape_region != NULL)
|
||||||
meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), NULL);
|
|
||||||
g_clear_pointer (&priv->shape_region, cairo_region_destroy);
|
|
||||||
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
|
|
||||||
|
|
||||||
#ifdef HAVE_SHAPE
|
|
||||||
if (priv->window->has_shape)
|
|
||||||
{
|
{
|
||||||
/* Translate the set of XShape rectangles that we
|
region = cairo_region_reference (priv->window->shape_region);
|
||||||
* get from the X server to a cairo_region. */
|
|
||||||
MetaScreen *screen = priv->screen;
|
|
||||||
MetaDisplay *display = meta_screen_get_display (screen);
|
|
||||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
|
||||||
XRectangle *rects;
|
|
||||||
int n_rects, ordering;
|
|
||||||
|
|
||||||
meta_error_trap_push (display);
|
|
||||||
rects = XShapeGetRectangles (xdisplay,
|
|
||||||
priv->window->xwindow,
|
|
||||||
ShapeBounding,
|
|
||||||
&n_rects,
|
|
||||||
&ordering);
|
|
||||||
meta_error_trap_pop (display);
|
|
||||||
|
|
||||||
if (rects)
|
|
||||||
{
|
|
||||||
region = region_create_from_x_rectangles (rects, n_rects,
|
|
||||||
client_area->x,
|
|
||||||
client_area->y);
|
|
||||||
XFree (rects);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
needs_mask = (region != NULL) || (priv->window->frame != NULL);
|
|
||||||
|
|
||||||
if (region != NULL)
|
|
||||||
{
|
|
||||||
/* The shape we get back from the client may have coordinates
|
|
||||||
* outside of the frame. The X SHAPE Extension requires that
|
|
||||||
* the overall shape the client provides never exceeds the
|
|
||||||
* "bounding rectangle" of the window -- the shape that the
|
|
||||||
* window would have gotten if it was unshaped. In our case,
|
|
||||||
* this is simply the client area.
|
|
||||||
*/
|
|
||||||
cairo_region_intersect_rectangle (region, client_area);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2259,11 +2194,70 @@ meta_window_actor_update_x11_shape_region (MetaWindowActor *self,
|
|||||||
region = cairo_region_create_rectangle (client_area);
|
region = cairo_region_create_rectangle (client_area);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The region at this point should be constrained to the
|
meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), NULL);
|
||||||
* bounds of the client rectangle. */
|
if ((priv->window->shape_region != NULL) || (priv->window->frame != NULL))
|
||||||
|
build_and_scan_frame_mask (self, client_area, region);
|
||||||
|
|
||||||
|
g_clear_pointer (&priv->shape_region, cairo_region_destroy);
|
||||||
|
priv->shape_region = region;
|
||||||
|
|
||||||
|
if (priv->shadow_shape != NULL)
|
||||||
|
{
|
||||||
|
meta_window_shape_unref (priv->shadow_shape);
|
||||||
|
priv->shadow_shape = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
meta_window_actor_invalidate_shadow (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_window_actor_update_input_region (MetaWindowActor *self,
|
||||||
|
cairo_rectangle_int_t *client_area)
|
||||||
|
{
|
||||||
|
MetaWindowActorPrivate *priv = self->priv;
|
||||||
|
MetaShapedTexture *stex = META_SHAPED_TEXTURE (priv->actor);
|
||||||
|
cairo_region_t *region = NULL;
|
||||||
|
|
||||||
|
if (priv->window->frame != NULL && priv->window->shape_region != NULL)
|
||||||
|
{
|
||||||
|
cairo_region_t *client_region = cairo_region_copy (priv->window->input_region);
|
||||||
|
|
||||||
|
region = meta_frame_get_frame_bounds (priv->window->frame);
|
||||||
|
|
||||||
|
cairo_region_subtract_rectangle (region, client_area);
|
||||||
|
cairo_region_translate (client_region, client_area->x, client_area->y);
|
||||||
|
cairo_region_union (region, client_region);
|
||||||
|
cairo_region_destroy (client_region);
|
||||||
|
}
|
||||||
|
else if (priv->window->shape_region != NULL)
|
||||||
|
{
|
||||||
|
region = cairo_region_reference (priv->window->input_region);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* If we don't have a shape on the server, that means that
|
||||||
|
* we have an implicit shape of one rectangle covering the
|
||||||
|
* entire window. */
|
||||||
|
region = cairo_region_create_rectangle (client_area);
|
||||||
|
}
|
||||||
|
|
||||||
|
meta_shaped_texture_set_input_shape_region (stex, region);
|
||||||
|
cairo_region_destroy (region);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_window_actor_update_opaque_region (MetaWindowActor *self)
|
||||||
|
{
|
||||||
|
MetaWindowActorPrivate *priv = self->priv;
|
||||||
|
|
||||||
|
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
|
||||||
|
|
||||||
if (priv->argb32 && priv->window->opaque_region != NULL)
|
if (priv->argb32 && priv->window->opaque_region != NULL)
|
||||||
{
|
{
|
||||||
|
MetaFrameBorders borders;
|
||||||
|
|
||||||
|
meta_frame_calc_borders (priv->window->frame, &borders);
|
||||||
|
|
||||||
/* The opaque region is defined to be a part of the
|
/* The opaque region is defined to be a part of the
|
||||||
* window which ARGB32 will always paint with opaque
|
* window which ARGB32 will always paint with opaque
|
||||||
* pixels. For these regions, we want to avoid painting
|
* pixels. For these regions, we want to avoid painting
|
||||||
@@ -2275,91 +2269,16 @@ meta_window_actor_update_x11_shape_region (MetaWindowActor *self,
|
|||||||
* case, graphical glitches will occur.
|
* case, graphical glitches will occur.
|
||||||
*/
|
*/
|
||||||
priv->opaque_region = cairo_region_copy (priv->window->opaque_region);
|
priv->opaque_region = cairo_region_copy (priv->window->opaque_region);
|
||||||
cairo_region_translate (priv->opaque_region, client_area->x, client_area->y);
|
cairo_region_translate (priv->opaque_region, borders.total.left, borders.total.top);
|
||||||
cairo_region_intersect (priv->opaque_region, region);
|
cairo_region_intersect (priv->opaque_region, priv->shape_region);
|
||||||
}
|
}
|
||||||
else if (priv->argb32)
|
else if (priv->argb32)
|
||||||
priv->opaque_region = NULL;
|
priv->opaque_region = NULL;
|
||||||
else
|
else
|
||||||
priv->opaque_region = cairo_region_reference (region);
|
priv->opaque_region = cairo_region_reference (priv->shape_region);
|
||||||
|
|
||||||
if (needs_mask)
|
meta_shaped_texture_set_opaque_region (META_SHAPED_TEXTURE (priv->actor),
|
||||||
{
|
priv->opaque_region);
|
||||||
/* This takes the region, generates a mask using GTK+
|
|
||||||
* and scans the mask looking for all opaque pixels,
|
|
||||||
* adding it to region.
|
|
||||||
*/
|
|
||||||
build_and_scan_frame_mask (self, client_area, region);
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->shape_region = region;
|
|
||||||
|
|
||||||
meta_window_actor_invalidate_shadow (self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
meta_window_actor_update_x11_input_shape_region (MetaWindowActor *self,
|
|
||||||
cairo_rectangle_int_t *client_area)
|
|
||||||
{
|
|
||||||
MetaWindowActorPrivate *priv = self->priv;
|
|
||||||
cairo_region_t *region = NULL;
|
|
||||||
|
|
||||||
g_clear_pointer (&priv->input_shape_region, cairo_region_destroy);
|
|
||||||
|
|
||||||
#ifdef HAVE_SHAPE
|
|
||||||
/* Note: we currently assume that mutter never sets an input region
|
|
||||||
* when there is a frame. */
|
|
||||||
if (priv->window->frame == NULL && priv->window->has_input_shape)
|
|
||||||
{
|
|
||||||
MetaScreen *screen = priv->screen;
|
|
||||||
MetaDisplay *display = meta_screen_get_display (screen);
|
|
||||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
|
||||||
XRectangle *rects;
|
|
||||||
int n_rects, ordering;
|
|
||||||
|
|
||||||
/* Note we only actually query the ShapeInput shape of a window
|
|
||||||
* when we don't have a frame because we assume currently that
|
|
||||||
* mutter never sets an ShapeInput shape on a frame. */
|
|
||||||
meta_error_trap_push (display);
|
|
||||||
rects = XShapeGetRectangles (xdisplay,
|
|
||||||
priv->window->xwindow,
|
|
||||||
ShapeInput,
|
|
||||||
&n_rects,
|
|
||||||
&ordering);
|
|
||||||
meta_error_trap_pop (display);
|
|
||||||
if (rects)
|
|
||||||
{
|
|
||||||
region = region_create_from_x_rectangles (rects, n_rects,
|
|
||||||
client_area->x,
|
|
||||||
client_area->y);
|
|
||||||
XFree (rects);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* HAVE_SHAPE */
|
|
||||||
|
|
||||||
if (region != NULL)
|
|
||||||
{
|
|
||||||
/* The X shape extension requires us to intersect the input
|
|
||||||
* region with the effective bounding shape to determine the
|
|
||||||
* effective input region.
|
|
||||||
*/
|
|
||||||
if (priv->shape_region)
|
|
||||||
cairo_region_intersect (region, priv->shape_region);
|
|
||||||
else
|
|
||||||
cairo_region_intersect_rectangle (region, client_area);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* If we don't have a shape on the server, that means that we
|
|
||||||
* have an implicit shape of one rectangle covering the entire
|
|
||||||
* window. */
|
|
||||||
region = cairo_region_create_rectangle (client_area);
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->input_shape_region = region;
|
|
||||||
|
|
||||||
meta_shaped_texture_set_input_shape_region (META_SHAPED_TEXTURE (priv->actor),
|
|
||||||
priv->input_shape_region);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -2385,24 +2304,9 @@ check_needs_reshape (MetaWindowActor *self)
|
|||||||
else
|
else
|
||||||
client_area.height = priv->window->rect.height;
|
client_area.height = priv->window->rect.height;
|
||||||
|
|
||||||
if (priv->window->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
meta_window_actor_update_shape_region (self, &client_area);
|
||||||
{
|
meta_window_actor_update_input_region (self, &client_area);
|
||||||
meta_window_actor_update_x11_shape_region (self, &client_area);
|
meta_window_actor_update_opaque_region (self);
|
||||||
meta_window_actor_update_x11_input_shape_region (self, &client_area);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* TODO: properly support setting an input region as specified
|
|
||||||
* via the wayland protocol */
|
|
||||||
|
|
||||||
g_clear_pointer (&priv->shape_region, cairo_region_destroy);
|
|
||||||
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
|
|
||||||
g_clear_pointer (&priv->input_shape_region, cairo_region_destroy);
|
|
||||||
|
|
||||||
priv->shape_region = cairo_region_create_rectangle (&client_area);
|
|
||||||
priv->opaque_region = cairo_region_reference (priv->shape_region);
|
|
||||||
priv->input_shape_region = cairo_region_reference (priv->shape_region);
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->needs_reshape = FALSE;
|
priv->needs_reshape = FALSE;
|
||||||
}
|
}
|
||||||
@@ -2463,6 +2367,8 @@ meta_window_actor_set_wayland_surface (MetaWindowActor *self,
|
|||||||
surface);
|
surface);
|
||||||
if (surface && surface->buffer_ref.buffer)
|
if (surface && surface->buffer_ref.buffer)
|
||||||
maybe_emit_size_changed (self, surface->buffer_ref.buffer);
|
maybe_emit_size_changed (self, surface->buffer_ref.buffer);
|
||||||
|
|
||||||
|
meta_window_actor_invalidate_shadow (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -186,7 +186,6 @@ meta_window_group_paint (ClutterActor *actor)
|
|||||||
|
|
||||||
if (META_IS_WINDOW_ACTOR (child))
|
if (META_IS_WINDOW_ACTOR (child))
|
||||||
{
|
{
|
||||||
MetaWindow *meta_window;
|
|
||||||
MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
|
MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
|
||||||
int x, y;
|
int x, y;
|
||||||
|
|
||||||
@@ -201,14 +200,7 @@ meta_window_group_paint (ClutterActor *actor)
|
|||||||
|
|
||||||
meta_window_actor_set_visible_region (window_actor, visible_region);
|
meta_window_actor_set_visible_region (window_actor, visible_region);
|
||||||
|
|
||||||
/* TODO: Track the opaque regions of wayland clients.
|
if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
|
||||||
* Although wayland clients can report opaque window
|
|
||||||
* regions, for now we assume that all wayland clients are
|
|
||||||
* transparent... */
|
|
||||||
meta_window = meta_window_actor_get_meta_window (window_actor);
|
|
||||||
|
|
||||||
if (meta_window->client_type != META_WINDOW_CLIENT_TYPE_WAYLAND &&
|
|
||||||
clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
|
|
||||||
{
|
{
|
||||||
cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
|
cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
|
||||||
if (obscured_region)
|
if (obscured_region)
|
||||||
|
|||||||
@@ -75,6 +75,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "meta-xwayland-private.h"
|
||||||
|
|
||||||
#define GRAB_OP_IS_WINDOW_SWITCH(g) \
|
#define GRAB_OP_IS_WINDOW_SWITCH(g) \
|
||||||
(g == META_GRAB_OP_KEYBOARD_TABBING_NORMAL || \
|
(g == META_GRAB_OP_KEYBOARD_TABBING_NORMAL || \
|
||||||
g == META_GRAB_OP_KEYBOARD_TABBING_DOCK || \
|
g == META_GRAB_OP_KEYBOARD_TABBING_DOCK || \
|
||||||
@@ -516,6 +518,9 @@ meta_display_open (void)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (meta_is_wayland_compositor ())
|
||||||
|
meta_xwayland_complete_init ();
|
||||||
|
|
||||||
if (meta_is_syncing ())
|
if (meta_is_syncing ())
|
||||||
XSynchronize (xdisplay, True);
|
XSynchronize (xdisplay, True);
|
||||||
|
|
||||||
@@ -2331,59 +2336,9 @@ meta_display_handle_event (MetaDisplay *display,
|
|||||||
XShapeEvent *sev = (XShapeEvent*) event;
|
XShapeEvent *sev = (XShapeEvent*) event;
|
||||||
|
|
||||||
if (sev->kind == ShapeBounding)
|
if (sev->kind == ShapeBounding)
|
||||||
{
|
meta_window_update_shape_region_x11 (window);
|
||||||
if (sev->shaped && !window->has_shape)
|
|
||||||
{
|
|
||||||
window->has_shape = TRUE;
|
|
||||||
meta_topic (META_DEBUG_SHAPES,
|
|
||||||
"Window %s now has a shape\n",
|
|
||||||
window->desc);
|
|
||||||
}
|
|
||||||
else if (!sev->shaped && window->has_shape)
|
|
||||||
{
|
|
||||||
window->has_shape = FALSE;
|
|
||||||
meta_topic (META_DEBUG_SHAPES,
|
|
||||||
"Window %s no longer has a shape\n",
|
|
||||||
window->desc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
meta_topic (META_DEBUG_SHAPES,
|
|
||||||
"Window %s shape changed\n",
|
|
||||||
window->desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (display->compositor)
|
|
||||||
meta_compositor_window_x11_shape_changed (display->compositor,
|
|
||||||
window);
|
|
||||||
}
|
|
||||||
else if (sev->kind == ShapeInput)
|
else if (sev->kind == ShapeInput)
|
||||||
{
|
meta_window_update_input_region_x11 (window);
|
||||||
if (sev->shaped && !window->has_input_shape)
|
|
||||||
{
|
|
||||||
window->has_input_shape = TRUE;
|
|
||||||
meta_topic (META_DEBUG_SHAPES,
|
|
||||||
"Window %s now has an input shape\n",
|
|
||||||
window->desc);
|
|
||||||
}
|
|
||||||
else if (!sev->shaped && window->has_input_shape)
|
|
||||||
{
|
|
||||||
window->has_input_shape = FALSE;
|
|
||||||
meta_topic (META_DEBUG_SHAPES,
|
|
||||||
"Window %s no longer has an input shape\n",
|
|
||||||
window->desc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
meta_topic (META_DEBUG_SHAPES,
|
|
||||||
"Window %s input shape changed\n",
|
|
||||||
window->desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (display->compositor)
|
|
||||||
meta_compositor_window_x11_shape_changed (display->compositor,
|
|
||||||
window);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -53,13 +53,8 @@
|
|||||||
#include <X11/XKBlib.h>
|
#include <X11/XKBlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_WAYLAND
|
|
||||||
#include "meta-wayland-private.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SCHEMA_COMMON_KEYBINDINGS "org.gnome.desktop.wm.keybindings"
|
#define SCHEMA_COMMON_KEYBINDINGS "org.gnome.desktop.wm.keybindings"
|
||||||
#define SCHEMA_MUTTER_KEYBINDINGS "org.gnome.mutter.keybindings"
|
#define SCHEMA_MUTTER_KEYBINDINGS "org.gnome.mutter.keybindings"
|
||||||
#define SCHEMA_MUTTER_WAYLAND_KEYBINDINGS "org.gnome.mutter.wayland.keybindings"
|
|
||||||
|
|
||||||
static gboolean add_builtin_keybinding (MetaDisplay *display,
|
static gboolean add_builtin_keybinding (MetaDisplay *display,
|
||||||
const char *name,
|
const char *name,
|
||||||
@@ -4103,40 +4098,6 @@ handle_set_spew_mark (MetaDisplay *display,
|
|||||||
meta_verbose ("-- MARK MARK MARK MARK --\n");
|
meta_verbose ("-- MARK MARK MARK MARK --\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_WAYLAND
|
|
||||||
static void
|
|
||||||
handle_switch_vt (MetaDisplay *display,
|
|
||||||
MetaScreen *screen,
|
|
||||||
MetaWindow *window,
|
|
||||||
XIDeviceEvent *event,
|
|
||||||
MetaKeyBinding *binding,
|
|
||||||
gpointer dummy)
|
|
||||||
{
|
|
||||||
gint vt = binding->handler->data;
|
|
||||||
MetaWaylandCompositor *compositor;
|
|
||||||
MetaLauncher *launcher;
|
|
||||||
|
|
||||||
compositor = meta_wayland_compositor_get_default ();
|
|
||||||
launcher = meta_wayland_compositor_get_launcher (compositor);
|
|
||||||
|
|
||||||
if (launcher)
|
|
||||||
{
|
|
||||||
GError *error;
|
|
||||||
|
|
||||||
error = NULL;
|
|
||||||
if (!meta_launcher_activate_vt (launcher, vt, &error))
|
|
||||||
{
|
|
||||||
g_warning ("Failed to switch VT: %s", error->message);
|
|
||||||
g_error_free (error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_debug ("Ignoring VT switch keybinding, not running as VT manager");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* meta_keybindings_set_custom_handler:
|
* meta_keybindings_set_custom_handler:
|
||||||
* @name: The name of the keybinding to set
|
* @name: The name of the keybinding to set
|
||||||
@@ -4200,7 +4161,6 @@ init_builtin_key_bindings (MetaDisplay *display)
|
|||||||
META_KEY_BINDING_IS_REVERSED)
|
META_KEY_BINDING_IS_REVERSED)
|
||||||
GSettings *common_keybindings = g_settings_new (SCHEMA_COMMON_KEYBINDINGS);
|
GSettings *common_keybindings = g_settings_new (SCHEMA_COMMON_KEYBINDINGS);
|
||||||
GSettings *mutter_keybindings = g_settings_new (SCHEMA_MUTTER_KEYBINDINGS);
|
GSettings *mutter_keybindings = g_settings_new (SCHEMA_MUTTER_KEYBINDINGS);
|
||||||
GSettings *mutter_wayland_keybindings = g_settings_new (SCHEMA_MUTTER_WAYLAND_KEYBINDINGS);
|
|
||||||
|
|
||||||
add_builtin_keybinding (display,
|
add_builtin_keybinding (display,
|
||||||
"switch-to-workspace-1",
|
"switch-to-workspace-1",
|
||||||
@@ -4462,60 +4422,6 @@ init_builtin_key_bindings (MetaDisplay *display)
|
|||||||
META_KEYBINDING_ACTION_SET_SPEW_MARK,
|
META_KEYBINDING_ACTION_SET_SPEW_MARK,
|
||||||
handle_set_spew_mark, 0);
|
handle_set_spew_mark, 0);
|
||||||
|
|
||||||
#ifdef HAVE_WAYLAND
|
|
||||||
if (meta_is_wayland_compositor ())
|
|
||||||
{
|
|
||||||
add_builtin_keybinding (display,
|
|
||||||
"switch-to-session-1",
|
|
||||||
mutter_wayland_keybindings,
|
|
||||||
META_KEY_BINDING_NONE,
|
|
||||||
META_KEYBINDING_ACTION_NONE,
|
|
||||||
handle_switch_vt, 1);
|
|
||||||
|
|
||||||
add_builtin_keybinding (display,
|
|
||||||
"switch-to-session-2",
|
|
||||||
mutter_wayland_keybindings,
|
|
||||||
META_KEY_BINDING_NONE,
|
|
||||||
META_KEYBINDING_ACTION_NONE,
|
|
||||||
handle_switch_vt, 2);
|
|
||||||
|
|
||||||
add_builtin_keybinding (display,
|
|
||||||
"switch-to-session-3",
|
|
||||||
mutter_wayland_keybindings,
|
|
||||||
META_KEY_BINDING_NONE,
|
|
||||||
META_KEYBINDING_ACTION_NONE,
|
|
||||||
handle_switch_vt, 3);
|
|
||||||
|
|
||||||
add_builtin_keybinding (display,
|
|
||||||
"switch-to-session-4",
|
|
||||||
mutter_wayland_keybindings,
|
|
||||||
META_KEY_BINDING_NONE,
|
|
||||||
META_KEYBINDING_ACTION_NONE,
|
|
||||||
handle_switch_vt, 4);
|
|
||||||
|
|
||||||
add_builtin_keybinding (display,
|
|
||||||
"switch-to-session-5",
|
|
||||||
mutter_wayland_keybindings,
|
|
||||||
META_KEY_BINDING_NONE,
|
|
||||||
META_KEYBINDING_ACTION_NONE,
|
|
||||||
handle_switch_vt, 5);
|
|
||||||
|
|
||||||
add_builtin_keybinding (display,
|
|
||||||
"switch-to-session-6",
|
|
||||||
mutter_wayland_keybindings,
|
|
||||||
META_KEY_BINDING_NONE,
|
|
||||||
META_KEYBINDING_ACTION_NONE,
|
|
||||||
handle_switch_vt, 6);
|
|
||||||
|
|
||||||
add_builtin_keybinding (display,
|
|
||||||
"switch-to-session-7",
|
|
||||||
mutter_wayland_keybindings,
|
|
||||||
META_KEY_BINDING_NONE,
|
|
||||||
META_KEYBINDING_ACTION_NONE,
|
|
||||||
handle_switch_vt, 7);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#undef REVERSES_AND_REVERSED
|
#undef REVERSES_AND_REVERSED
|
||||||
|
|
||||||
/************************ PER WINDOW BINDINGS ************************/
|
/************************ PER WINDOW BINDINGS ************************/
|
||||||
|
|||||||
@@ -58,7 +58,6 @@
|
|||||||
#include "meta-wayland-private.h"
|
#include "meta-wayland-private.h"
|
||||||
|
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
#include <glib-unix.h>
|
|
||||||
#include <gdk/gdkx.h>
|
#include <gdk/gdkx.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -353,12 +352,59 @@ meta_finalize (void)
|
|||||||
meta_wayland_finalize ();
|
meta_wayland_finalize ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static int signal_pipe_fds[2] = { -1, -1 };
|
||||||
on_sigterm (gpointer user_data)
|
|
||||||
{
|
|
||||||
meta_quit (EXIT_SUCCESS);
|
|
||||||
|
|
||||||
return G_SOURCE_REMOVE;
|
static void
|
||||||
|
signal_handler (int signum)
|
||||||
|
{
|
||||||
|
if (signal_pipe_fds[1] >= 0)
|
||||||
|
{
|
||||||
|
switch (signum)
|
||||||
|
{
|
||||||
|
case SIGTERM:
|
||||||
|
write (signal_pipe_fds[1], "T", 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
on_signal (GIOChannel *source,
|
||||||
|
GIOCondition condition,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
char signal;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
count = read (signal_pipe_fds[0], &signal, 1);
|
||||||
|
if (count == EINTR)
|
||||||
|
continue;
|
||||||
|
if (count < 0)
|
||||||
|
{
|
||||||
|
const char *msg = strerror (errno);
|
||||||
|
g_warning ("Error handling signal: %s", msg);
|
||||||
|
}
|
||||||
|
if (count != 1)
|
||||||
|
{
|
||||||
|
g_warning ("Unexpectedly failed to read byte from signal pipe\n");
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (signal)
|
||||||
|
{
|
||||||
|
case 'T': /* SIGTERM */
|
||||||
|
meta_quit (META_EXIT_SUCCESS);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_warning ("Spurious character '%c' read from signal pipe", signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -372,6 +418,7 @@ meta_init (void)
|
|||||||
{
|
{
|
||||||
struct sigaction act;
|
struct sigaction act;
|
||||||
sigset_t empty_mask;
|
sigset_t empty_mask;
|
||||||
|
GIOChannel *channel;
|
||||||
|
|
||||||
sigemptyset (&empty_mask);
|
sigemptyset (&empty_mask);
|
||||||
act.sa_handler = SIG_IGN;
|
act.sa_handler = SIG_IGN;
|
||||||
@@ -386,7 +433,20 @@ meta_init (void)
|
|||||||
g_strerror (errno));
|
g_strerror (errno));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
g_unix_signal_add (SIGTERM, on_sigterm, NULL);
|
if (pipe (signal_pipe_fds) != 0)
|
||||||
|
g_printerr ("Failed to create signal pipe: %s\n",
|
||||||
|
g_strerror (errno));
|
||||||
|
|
||||||
|
channel = g_io_channel_unix_new (signal_pipe_fds[0]);
|
||||||
|
g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL);
|
||||||
|
g_io_add_watch (channel, G_IO_IN, (GIOFunc) on_signal, NULL);
|
||||||
|
g_io_channel_set_close_on_unref (channel, TRUE);
|
||||||
|
g_io_channel_unref (channel);
|
||||||
|
|
||||||
|
act.sa_handler = &signal_handler;
|
||||||
|
if (sigaction (SIGTERM, &act, NULL) < 0)
|
||||||
|
g_printerr ("Failed to register SIGTERM handler: %s\n",
|
||||||
|
g_strerror (errno));
|
||||||
|
|
||||||
if (g_getenv ("MUTTER_VERBOSE"))
|
if (g_getenv ("MUTTER_VERBOSE"))
|
||||||
meta_set_verbose (TRUE);
|
meta_set_verbose (TRUE);
|
||||||
|
|||||||
@@ -339,11 +339,6 @@ struct _MetaWindow
|
|||||||
guint using_net_wm_icon_name : 1; /* vs. plain wm_icon_name */
|
guint using_net_wm_icon_name : 1; /* vs. plain wm_icon_name */
|
||||||
guint using_net_wm_visible_icon_name : 1; /* tracked so we can clear it */
|
guint using_net_wm_visible_icon_name : 1; /* tracked so we can clear it */
|
||||||
|
|
||||||
/* has a bounding shape mask */
|
|
||||||
guint has_shape : 1;
|
|
||||||
/* has an input shape mask */
|
|
||||||
guint has_input_shape : 1;
|
|
||||||
|
|
||||||
/* icon props have changed */
|
/* icon props have changed */
|
||||||
guint need_reread_icon : 1;
|
guint need_reread_icon : 1;
|
||||||
|
|
||||||
@@ -365,9 +360,15 @@ struct _MetaWindow
|
|||||||
/* if non-NULL, the bounds of the window frame */
|
/* if non-NULL, the bounds of the window frame */
|
||||||
cairo_region_t *frame_bounds;
|
cairo_region_t *frame_bounds;
|
||||||
|
|
||||||
|
/* if non-NULL, the bounding shape region of the window */
|
||||||
|
cairo_region_t *shape_region;
|
||||||
|
|
||||||
/* if non-NULL, the opaque region _NET_WM_OPAQUE_REGION */
|
/* if non-NULL, the opaque region _NET_WM_OPAQUE_REGION */
|
||||||
cairo_region_t *opaque_region;
|
cairo_region_t *opaque_region;
|
||||||
|
|
||||||
|
/* the input shape region for picking */
|
||||||
|
cairo_region_t *input_region;
|
||||||
|
|
||||||
/* if TRUE, the we have the new form of sync request counter which
|
/* if TRUE, the we have the new form of sync request counter which
|
||||||
* also handles application frames */
|
* also handles application frames */
|
||||||
guint extended_sync_request_counter : 1;
|
guint extended_sync_request_counter : 1;
|
||||||
@@ -685,7 +686,6 @@ void meta_window_update_icon_now (MetaWindow *window);
|
|||||||
|
|
||||||
void meta_window_update_role (MetaWindow *window);
|
void meta_window_update_role (MetaWindow *window);
|
||||||
void meta_window_update_net_wm_type (MetaWindow *window);
|
void meta_window_update_net_wm_type (MetaWindow *window);
|
||||||
void meta_window_update_opaque_region (MetaWindow *window);
|
|
||||||
void meta_window_update_for_monitors_changed (MetaWindow *window);
|
void meta_window_update_for_monitors_changed (MetaWindow *window);
|
||||||
void meta_window_update_on_all_workspaces (MetaWindow *window);
|
void meta_window_update_on_all_workspaces (MetaWindow *window);
|
||||||
|
|
||||||
@@ -699,4 +699,16 @@ void meta_window_compute_tile_match (MetaWindow *window);
|
|||||||
|
|
||||||
gboolean meta_window_updates_are_frozen (MetaWindow *window);
|
gboolean meta_window_updates_are_frozen (MetaWindow *window);
|
||||||
|
|
||||||
|
void meta_window_set_opaque_region (MetaWindow *window,
|
||||||
|
cairo_region_t *region);
|
||||||
|
void meta_window_update_opaque_region_x11 (MetaWindow *window);
|
||||||
|
|
||||||
|
void meta_window_set_input_region (MetaWindow *window,
|
||||||
|
cairo_region_t *region);
|
||||||
|
void meta_window_update_input_region_x11 (MetaWindow *window);
|
||||||
|
|
||||||
|
void meta_window_set_shape_region (MetaWindow *window,
|
||||||
|
cairo_region_t *region);
|
||||||
|
void meta_window_update_shape_region_x11 (MetaWindow *window);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -565,7 +565,7 @@ reload_opaque_region (MetaWindow *window,
|
|||||||
MetaPropValue *value,
|
MetaPropValue *value,
|
||||||
gboolean initial)
|
gboolean initial)
|
||||||
{
|
{
|
||||||
meta_window_update_opaque_region (window);
|
meta_window_update_opaque_region_x11 (window);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
@@ -822,8 +822,6 @@ meta_window_new_shared (MetaDisplay *display,
|
|||||||
Window xwindow,
|
Window xwindow,
|
||||||
gboolean must_be_viewable,
|
gboolean must_be_viewable,
|
||||||
gulong existing_wm_state,
|
gulong existing_wm_state,
|
||||||
gboolean has_shape,
|
|
||||||
gboolean has_input_shape,
|
|
||||||
MetaCompEffect effect,
|
MetaCompEffect effect,
|
||||||
XWindowAttributes *attrs)
|
XWindowAttributes *attrs)
|
||||||
{
|
{
|
||||||
@@ -876,9 +874,6 @@ meta_window_new_shared (MetaDisplay *display,
|
|||||||
/* avoid tons of stack updates */
|
/* avoid tons of stack updates */
|
||||||
meta_stack_freeze (window->screen->stack);
|
meta_stack_freeze (window->screen->stack);
|
||||||
|
|
||||||
window->has_shape = has_shape;
|
|
||||||
window->has_input_shape = has_input_shape;
|
|
||||||
|
|
||||||
window->rect.x = attrs->x;
|
window->rect.x = attrs->x;
|
||||||
window->rect.y = attrs->y;
|
window->rect.y = attrs->y;
|
||||||
window->rect.width = attrs->width;
|
window->rect.width = attrs->width;
|
||||||
@@ -1059,6 +1054,8 @@ meta_window_new_shared (MetaDisplay *display,
|
|||||||
}
|
}
|
||||||
|
|
||||||
meta_display_register_x_window (display, &window->xwindow, window);
|
meta_display_register_x_window (display, &window->xwindow, window);
|
||||||
|
meta_window_update_shape_region_x11 (window);
|
||||||
|
meta_window_update_input_region_x11 (window);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* assign the window to its group, or create a new group if needed
|
/* assign the window to its group, or create a new group if needed
|
||||||
@@ -1425,8 +1422,6 @@ meta_window_new_for_wayland (MetaDisplay *display,
|
|||||||
None,
|
None,
|
||||||
TRUE,
|
TRUE,
|
||||||
WithdrawnState,
|
WithdrawnState,
|
||||||
FALSE, /* has shape */
|
|
||||||
FALSE, /* has input shape */
|
|
||||||
META_COMP_EFFECT_NONE,
|
META_COMP_EFFECT_NONE,
|
||||||
&attrs);
|
&attrs);
|
||||||
|
|
||||||
@@ -1455,8 +1450,6 @@ meta_window_new_with_attrs (MetaDisplay *display,
|
|||||||
gulong existing_wm_state;
|
gulong existing_wm_state;
|
||||||
MetaWindow *window;
|
MetaWindow *window;
|
||||||
gulong event_mask;
|
gulong event_mask;
|
||||||
gboolean has_shape = FALSE;
|
|
||||||
gboolean has_input_shape = FALSE;
|
|
||||||
|
|
||||||
meta_verbose ("Attempting to manage 0x%lx\n", xwindow);
|
meta_verbose ("Attempting to manage 0x%lx\n", xwindow);
|
||||||
|
|
||||||
@@ -1576,53 +1569,6 @@ meta_window_new_with_attrs (MetaDisplay *display,
|
|||||||
XISelectEvents (display->xdisplay, xwindow, &mask, 1);
|
XISelectEvents (display->xdisplay, xwindow, &mask, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SHAPE
|
|
||||||
if (META_DISPLAY_HAS_SHAPE (display))
|
|
||||||
{
|
|
||||||
int x_bounding, y_bounding, x_clip, y_clip;
|
|
||||||
unsigned w_bounding, h_bounding, w_clip, h_clip;
|
|
||||||
int bounding_shaped, clip_shaped;
|
|
||||||
XRectangle *input_rectangles;
|
|
||||||
int n_rects, ordering;
|
|
||||||
|
|
||||||
XShapeSelectInput (display->xdisplay, xwindow, ShapeNotifyMask);
|
|
||||||
|
|
||||||
XShapeQueryExtents (display->xdisplay, xwindow,
|
|
||||||
&bounding_shaped, &x_bounding, &y_bounding,
|
|
||||||
&w_bounding, &h_bounding,
|
|
||||||
&clip_shaped, &x_clip, &y_clip,
|
|
||||||
&w_clip, &h_clip);
|
|
||||||
|
|
||||||
has_shape = bounding_shaped != FALSE;
|
|
||||||
|
|
||||||
/* XXX: The x shape extension doesn't provide a way to only test if an
|
|
||||||
* input shape has been specified, so we have to query and throw away the
|
|
||||||
* rectangles. */
|
|
||||||
meta_error_trap_push (display);
|
|
||||||
input_rectangles = XShapeGetRectangles (display->xdisplay, xwindow,
|
|
||||||
ShapeInput, &n_rects, &ordering);
|
|
||||||
meta_error_trap_pop (display);
|
|
||||||
if (input_rectangles)
|
|
||||||
{
|
|
||||||
if (n_rects > 1 ||
|
|
||||||
(n_rects == 1 &&
|
|
||||||
(input_rectangles[0].x != x_bounding ||
|
|
||||||
input_rectangles[1].y != y_bounding ||
|
|
||||||
input_rectangles[2].width != w_bounding ||
|
|
||||||
input_rectangles[3].height != h_bounding)))
|
|
||||||
{
|
|
||||||
has_input_shape = TRUE;
|
|
||||||
}
|
|
||||||
XFree (input_rectangles);
|
|
||||||
}
|
|
||||||
|
|
||||||
meta_topic (META_DEBUG_SHAPES,
|
|
||||||
"Window has_shape = %d extents %d,%d %u x %u\n",
|
|
||||||
has_shape, x_bounding, y_bounding,
|
|
||||||
w_bounding, h_bounding);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Get rid of any borders */
|
/* Get rid of any borders */
|
||||||
if (attrs->border_width != 0)
|
if (attrs->border_width != 0)
|
||||||
XSetWindowBorderWidth (display->xdisplay, xwindow, 0);
|
XSetWindowBorderWidth (display->xdisplay, xwindow, 0);
|
||||||
@@ -1656,8 +1602,6 @@ meta_window_new_with_attrs (MetaDisplay *display,
|
|||||||
xwindow,
|
xwindow,
|
||||||
must_be_viewable,
|
must_be_viewable,
|
||||||
existing_wm_state,
|
existing_wm_state,
|
||||||
has_shape,
|
|
||||||
has_input_shape,
|
|
||||||
effect,
|
effect,
|
||||||
attrs);
|
attrs);
|
||||||
|
|
||||||
@@ -7810,14 +7754,25 @@ meta_window_update_net_wm_type (MetaWindow *window)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_window_update_opaque_region (MetaWindow *window)
|
meta_window_set_opaque_region (MetaWindow *window,
|
||||||
|
cairo_region_t *region)
|
||||||
|
{
|
||||||
|
g_clear_pointer (&window->opaque_region, cairo_region_destroy);
|
||||||
|
|
||||||
|
if (region != NULL)
|
||||||
|
window->opaque_region = cairo_region_reference (region);
|
||||||
|
|
||||||
|
if (window->display->compositor)
|
||||||
|
meta_compositor_window_shape_changed (window->display->compositor, window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_window_update_opaque_region_x11 (MetaWindow *window)
|
||||||
{
|
{
|
||||||
cairo_region_t *opaque_region = NULL;
|
cairo_region_t *opaque_region = NULL;
|
||||||
gulong *region = NULL;
|
gulong *region = NULL;
|
||||||
int nitems;
|
int nitems;
|
||||||
|
|
||||||
g_clear_pointer (&window->opaque_region, cairo_region_destroy);
|
|
||||||
|
|
||||||
if (meta_prop_get_cardinal_list (window->display,
|
if (meta_prop_get_cardinal_list (window->display,
|
||||||
window->xwindow,
|
window->xwindow,
|
||||||
window->display->atom__NET_WM_OPAQUE_REGION,
|
window->display->atom__NET_WM_OPAQUE_REGION,
|
||||||
@@ -7860,11 +7815,191 @@ meta_window_update_opaque_region (MetaWindow *window)
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
window->opaque_region = opaque_region;
|
|
||||||
meta_XFree (region);
|
meta_XFree (region);
|
||||||
|
|
||||||
|
meta_window_set_opaque_region (window, opaque_region);
|
||||||
|
cairo_region_destroy (opaque_region);
|
||||||
|
}
|
||||||
|
|
||||||
|
static cairo_region_t *
|
||||||
|
region_create_from_x_rectangles (const XRectangle *rects,
|
||||||
|
int n_rects)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
cairo_rectangle_int_t *cairo_rects = g_newa (cairo_rectangle_int_t, n_rects);
|
||||||
|
|
||||||
|
for (i = 0; i < n_rects; i ++)
|
||||||
|
{
|
||||||
|
cairo_rects[i].x = rects[i].x;
|
||||||
|
cairo_rects[i].y = rects[i].y;
|
||||||
|
cairo_rects[i].width = rects[i].width;
|
||||||
|
cairo_rects[i].height = rects[i].height;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cairo_region_create_rectangles (cairo_rects, n_rects);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_window_set_input_region (MetaWindow *window,
|
||||||
|
cairo_region_t *region)
|
||||||
|
{
|
||||||
|
g_clear_pointer (&window->input_region, cairo_region_destroy);
|
||||||
|
|
||||||
|
if (region != NULL)
|
||||||
|
window->input_region = cairo_region_reference (region);
|
||||||
|
|
||||||
if (window->display->compositor)
|
if (window->display->compositor)
|
||||||
meta_compositor_window_x11_shape_changed (window->display->compositor, window);
|
meta_compositor_window_shape_changed (window->display->compositor, window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_window_update_input_region_x11 (MetaWindow *window)
|
||||||
|
{
|
||||||
|
cairo_region_t *region = NULL;
|
||||||
|
|
||||||
|
#ifdef HAVE_SHAPE
|
||||||
|
if (META_DISPLAY_HAS_SHAPE (window->display))
|
||||||
|
{
|
||||||
|
/* Translate the set of XShape rectangles that we
|
||||||
|
* get from the X server to a cairo_region. */
|
||||||
|
XRectangle *rects = NULL;
|
||||||
|
int n_rects, ordering;
|
||||||
|
|
||||||
|
int x_bounding, y_bounding, x_clip, y_clip;
|
||||||
|
unsigned w_bounding, h_bounding, w_clip, h_clip;
|
||||||
|
int bounding_shaped, clip_shaped;
|
||||||
|
|
||||||
|
meta_error_trap_push (window->display);
|
||||||
|
XShapeQueryExtents (window->display->xdisplay, window->xwindow,
|
||||||
|
&bounding_shaped, &x_bounding, &y_bounding,
|
||||||
|
&w_bounding, &h_bounding,
|
||||||
|
&clip_shaped, &x_clip, &y_clip,
|
||||||
|
&w_clip, &h_clip);
|
||||||
|
|
||||||
|
rects = XShapeGetRectangles (window->display->xdisplay,
|
||||||
|
window->xwindow,
|
||||||
|
ShapeInput,
|
||||||
|
&n_rects,
|
||||||
|
&ordering);
|
||||||
|
meta_error_trap_pop (window->display);
|
||||||
|
|
||||||
|
/* XXX: The x shape extension doesn't provide a way to only test if an
|
||||||
|
* input shape has been specified, so we have to query and throw away the
|
||||||
|
* rectangles. */
|
||||||
|
if (rects)
|
||||||
|
{
|
||||||
|
if (n_rects > 1 ||
|
||||||
|
(n_rects == 1 &&
|
||||||
|
(rects[0].x != x_bounding ||
|
||||||
|
rects[1].y != y_bounding ||
|
||||||
|
rects[2].width != w_bounding ||
|
||||||
|
rects[3].height != h_bounding)))
|
||||||
|
region = region_create_from_x_rectangles (rects, n_rects);
|
||||||
|
|
||||||
|
XFree (rects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* HAVE_SHAPE */
|
||||||
|
|
||||||
|
if (region != NULL)
|
||||||
|
{
|
||||||
|
cairo_rectangle_int_t client_area;
|
||||||
|
|
||||||
|
client_area.x = 0;
|
||||||
|
client_area.y = 0;
|
||||||
|
client_area.width = window->rect.width;
|
||||||
|
client_area.height = window->rect.height;
|
||||||
|
|
||||||
|
/* The shape we get back from the client may have coordinates
|
||||||
|
* outside of the frame. The X SHAPE Extension requires that
|
||||||
|
* the overall shape the client provides never exceeds the
|
||||||
|
* "bounding rectangle" of the window -- the shape that the
|
||||||
|
* window would have gotten if it was unshaped. In our case,
|
||||||
|
* this is simply the client area.
|
||||||
|
*/
|
||||||
|
cairo_region_intersect_rectangle (region, &client_area);
|
||||||
|
}
|
||||||
|
|
||||||
|
meta_window_set_input_region (window, region);
|
||||||
|
cairo_region_destroy (region);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_window_set_shape_region (MetaWindow *window,
|
||||||
|
cairo_region_t *region)
|
||||||
|
{
|
||||||
|
g_clear_pointer (&window->shape_region, cairo_region_destroy);
|
||||||
|
|
||||||
|
if (region != NULL)
|
||||||
|
window->shape_region = cairo_region_reference (region);
|
||||||
|
|
||||||
|
if (window->display->compositor)
|
||||||
|
meta_compositor_window_shape_changed (window->display->compositor, window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_window_update_shape_region_x11 (MetaWindow *window)
|
||||||
|
{
|
||||||
|
cairo_region_t *region = NULL;
|
||||||
|
|
||||||
|
#ifdef HAVE_SHAPE
|
||||||
|
if (META_DISPLAY_HAS_SHAPE (window->display))
|
||||||
|
{
|
||||||
|
/* Translate the set of XShape rectangles that we
|
||||||
|
* get from the X server to a cairo_region. */
|
||||||
|
XRectangle *rects = NULL;
|
||||||
|
int n_rects, ordering;
|
||||||
|
|
||||||
|
int x_bounding, y_bounding, x_clip, y_clip;
|
||||||
|
unsigned w_bounding, h_bounding, w_clip, h_clip;
|
||||||
|
int bounding_shaped, clip_shaped;
|
||||||
|
|
||||||
|
meta_error_trap_push (window->display);
|
||||||
|
XShapeQueryExtents (window->display->xdisplay, window->xwindow,
|
||||||
|
&bounding_shaped, &x_bounding, &y_bounding,
|
||||||
|
&w_bounding, &h_bounding,
|
||||||
|
&clip_shaped, &x_clip, &y_clip,
|
||||||
|
&w_clip, &h_clip);
|
||||||
|
|
||||||
|
if (bounding_shaped)
|
||||||
|
{
|
||||||
|
rects = XShapeGetRectangles (window->display->xdisplay,
|
||||||
|
window->xwindow,
|
||||||
|
ShapeBounding,
|
||||||
|
&n_rects,
|
||||||
|
&ordering);
|
||||||
|
}
|
||||||
|
meta_error_trap_pop (window->display);
|
||||||
|
|
||||||
|
if (rects)
|
||||||
|
{
|
||||||
|
region = region_create_from_x_rectangles (rects, n_rects);
|
||||||
|
XFree (rects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* HAVE_SHAPE */
|
||||||
|
|
||||||
|
if (region != NULL)
|
||||||
|
{
|
||||||
|
cairo_rectangle_int_t client_area;
|
||||||
|
|
||||||
|
client_area.x = 0;
|
||||||
|
client_area.y = 0;
|
||||||
|
client_area.width = window->rect.width;
|
||||||
|
client_area.height = window->rect.height;
|
||||||
|
|
||||||
|
/* The shape we get back from the client may have coordinates
|
||||||
|
* outside of the frame. The X SHAPE Extension requires that
|
||||||
|
* the overall shape the client provides never exceeds the
|
||||||
|
* "bounding rectangle" of the window -- the shape that the
|
||||||
|
* window would have gotten if it was unshaped. In our case,
|
||||||
|
* this is simply the client area.
|
||||||
|
*/
|
||||||
|
cairo_region_intersect_rectangle (region, &client_area);
|
||||||
|
}
|
||||||
|
|
||||||
|
meta_window_set_shape_region (window, region);
|
||||||
|
cairo_region_destroy (region);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
@@ -64,8 +64,8 @@ void meta_compositor_manage_screen (MetaCompositor *compositor,
|
|||||||
void meta_compositor_unmanage_screen (MetaCompositor *compositor,
|
void meta_compositor_unmanage_screen (MetaCompositor *compositor,
|
||||||
MetaScreen *screen);
|
MetaScreen *screen);
|
||||||
|
|
||||||
void meta_compositor_window_x11_shape_changed (MetaCompositor *compositor,
|
void meta_compositor_window_shape_changed (MetaCompositor *compositor,
|
||||||
MetaWindow *window);
|
MetaWindow *window);
|
||||||
|
|
||||||
gboolean meta_compositor_process_event (MetaCompositor *compositor,
|
gboolean meta_compositor_process_event (MetaCompositor *compositor,
|
||||||
XEvent *event,
|
XEvent *event,
|
||||||
|
|||||||
@@ -84,6 +84,9 @@ void meta_shaped_texture_set_input_shape_region (MetaShapedTexture *stex,
|
|||||||
void meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
|
void meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
|
||||||
cairo_region_t *clip_region);
|
cairo_region_t *clip_region);
|
||||||
|
|
||||||
|
void meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex,
|
||||||
|
cairo_region_t *opaque_region);
|
||||||
|
|
||||||
cairo_surface_t * meta_shaped_texture_get_image (MetaShapedTexture *stex,
|
cairo_surface_t * meta_shaped_texture_get_image (MetaShapedTexture *stex,
|
||||||
cairo_rectangle_int_t *clip);
|
cairo_rectangle_int_t *clip);
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
<schemalist>
|
|
||||||
<schema id="org.gnome.mutter.wayland.keybindings" path="/org/gnome/mutter/wayland/keybindings/"
|
|
||||||
gettext-domain="@GETTEXT_DOMAIN@">
|
|
||||||
<key name="switch-to-session-1" type="as">
|
|
||||||
<default><![CDATA[['<Primary><Alt>F1']]]></default>
|
|
||||||
<_summary>Switch to VT 1</_summary>
|
|
||||||
</key>
|
|
||||||
<key name="switch-to-session-2" type="as">
|
|
||||||
<default><![CDATA[['<Primary><Alt>F2']]]></default>
|
|
||||||
<_summary>Switch to VT 2</_summary>
|
|
||||||
</key>
|
|
||||||
<key name="switch-to-session-3" type="as">
|
|
||||||
<default><![CDATA[['<Primary><Alt>F3']]]></default>
|
|
||||||
<_summary>Switch to VT 3</_summary>
|
|
||||||
</key>
|
|
||||||
<key name="switch-to-session-4" type="as">
|
|
||||||
<default><![CDATA[['<Primary><Alt>F4']]]></default>
|
|
||||||
<_summary>Switch to VT 4</_summary>
|
|
||||||
</key>
|
|
||||||
<key name="switch-to-session-5" type="as">
|
|
||||||
<default><![CDATA[['<Primary><Alt>F5']]]></default>
|
|
||||||
<_summary>Switch to VT 5</_summary>
|
|
||||||
</key>
|
|
||||||
<key name="switch-to-session-6" type="as">
|
|
||||||
<default><![CDATA[['<Primary><Alt>F6']]]></default>
|
|
||||||
<_summary>Switch to VT 6</_summary>
|
|
||||||
</key>
|
|
||||||
<key name="switch-to-session-7" type="as">
|
|
||||||
<default><![CDATA[['<Primary><Alt>F7']]]></default>
|
|
||||||
<_summary>Switch to VT 7</_summary>
|
|
||||||
</key>
|
|
||||||
</schema>
|
|
||||||
</schemalist>
|
|
||||||
@@ -28,7 +28,6 @@
|
|||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
|
|
||||||
#include "window-private.h"
|
#include "window-private.h"
|
||||||
#include "meta-weston-launch.h"
|
|
||||||
#include <meta/meta-cursor-tracker.h>
|
#include <meta/meta-cursor-tracker.h>
|
||||||
|
|
||||||
typedef struct _MetaWaylandCompositor MetaWaylandCompositor;
|
typedef struct _MetaWaylandCompositor MetaWaylandCompositor;
|
||||||
@@ -149,9 +148,6 @@ struct _MetaWaylandCompositor
|
|||||||
struct wl_client *xwayland_client;
|
struct wl_client *xwayland_client;
|
||||||
struct wl_resource *xserver_resource;
|
struct wl_resource *xserver_resource;
|
||||||
|
|
||||||
MetaLauncher *launcher;
|
|
||||||
int drm_fd;
|
|
||||||
|
|
||||||
MetaWaylandSeat *seat;
|
MetaWaylandSeat *seat;
|
||||||
|
|
||||||
/* This surface is only used to keep drag of the implicit grab when
|
/* This surface is only used to keep drag of the implicit grab when
|
||||||
@@ -342,8 +338,6 @@ void meta_wayland_compositor_repick (MetaWaylandComp
|
|||||||
void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
|
void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
|
||||||
MetaWindow *window);
|
MetaWindow *window);
|
||||||
|
|
||||||
MetaLauncher *meta_wayland_compositor_get_launcher (MetaWaylandCompositor *compositor);
|
|
||||||
|
|
||||||
void meta_wayland_surface_free (MetaWaylandSurface *surface);
|
void meta_wayland_surface_free (MetaWaylandSurface *surface);
|
||||||
|
|
||||||
#endif /* META_WAYLAND_PRIVATE_H */
|
#endif /* META_WAYLAND_PRIVATE_H */
|
||||||
|
|||||||
@@ -50,7 +50,6 @@
|
|||||||
#include <meta/main.h>
|
#include <meta/main.h>
|
||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
#include "meta-idle-monitor-private.h"
|
#include "meta-idle-monitor-private.h"
|
||||||
#include "meta-weston-launch.h"
|
|
||||||
#include "monitor-private.h"
|
#include "monitor-private.h"
|
||||||
|
|
||||||
static MetaWaylandCompositor _meta_wayland_compositor;
|
static MetaWaylandCompositor _meta_wayland_compositor;
|
||||||
@@ -325,18 +324,34 @@ meta_wayland_surface_frame (struct wl_client *client,
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
meta_wayland_surface_set_opaque_region (struct wl_client *client,
|
meta_wayland_surface_set_opaque_region (struct wl_client *client,
|
||||||
struct wl_resource *resource,
|
struct wl_resource *surface_resource,
|
||||||
struct wl_resource *region)
|
struct wl_resource *region_resource)
|
||||||
{
|
{
|
||||||
g_warning ("TODO: support set_opaque_region request");
|
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
||||||
|
MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
|
||||||
|
|
||||||
|
/* X11 unmanaged window */
|
||||||
|
if (!surface)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (surface->window)
|
||||||
|
meta_window_set_opaque_region (surface->window, cairo_region_copy (region->region));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
meta_wayland_surface_set_input_region (struct wl_client *client,
|
meta_wayland_surface_set_input_region (struct wl_client *client,
|
||||||
struct wl_resource *resource,
|
struct wl_resource *surface_resource,
|
||||||
struct wl_resource *region)
|
struct wl_resource *region_resource)
|
||||||
{
|
{
|
||||||
g_warning ("TODO: support set_input_region request");
|
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
||||||
|
MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
|
||||||
|
|
||||||
|
/* X11 unmanaged window */
|
||||||
|
if (!surface)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (surface->window)
|
||||||
|
meta_window_set_input_region (surface->window, cairo_region_copy (region->region));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1530,9 +1545,6 @@ meta_wayland_init (void)
|
|||||||
MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
|
MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
|
||||||
guint event_signal;
|
guint event_signal;
|
||||||
MetaMonitorManager *monitors;
|
MetaMonitorManager *monitors;
|
||||||
ClutterBackend *backend;
|
|
||||||
CoglContext *cogl_context;
|
|
||||||
CoglRenderer *cogl_renderer;
|
|
||||||
|
|
||||||
memset (compositor, 0, sizeof (MetaWaylandCompositor));
|
memset (compositor, 0, sizeof (MetaWaylandCompositor));
|
||||||
|
|
||||||
@@ -1569,35 +1581,9 @@ meta_wayland_init (void)
|
|||||||
|
|
||||||
clutter_wayland_set_compositor_display (compositor->wayland_display);
|
clutter_wayland_set_compositor_display (compositor->wayland_display);
|
||||||
|
|
||||||
if (getenv ("WESTON_LAUNCHER_SOCK"))
|
|
||||||
compositor->launcher = meta_launcher_new ();
|
|
||||||
|
|
||||||
if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
|
if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
|
||||||
g_error ("Failed to initialize Clutter");
|
g_error ("Failed to initialize Clutter");
|
||||||
|
|
||||||
backend = clutter_get_default_backend ();
|
|
||||||
cogl_context = clutter_backend_get_cogl_context (backend);
|
|
||||||
cogl_renderer = cogl_display_get_renderer (cogl_context_get_display (cogl_context));
|
|
||||||
|
|
||||||
if (cogl_renderer_get_winsys_id (cogl_renderer) == COGL_WINSYS_ID_EGL_KMS)
|
|
||||||
compositor->drm_fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
|
|
||||||
else
|
|
||||||
compositor->drm_fd = -1;
|
|
||||||
|
|
||||||
if (compositor->drm_fd >= 0)
|
|
||||||
{
|
|
||||||
GError *error;
|
|
||||||
|
|
||||||
meta_launcher_set_drm_fd (compositor->launcher, compositor->drm_fd);
|
|
||||||
|
|
||||||
error = NULL;
|
|
||||||
if (!meta_launcher_set_master (compositor->launcher, TRUE, &error))
|
|
||||||
{
|
|
||||||
g_error ("Failed to become DRM master: %s", error->message);
|
|
||||||
g_error_free (error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
meta_monitor_manager_initialize ();
|
meta_monitor_manager_initialize ();
|
||||||
monitors = meta_monitor_manager_get ();
|
monitors = meta_monitor_manager_get ();
|
||||||
g_signal_connect (monitors, "monitors-changed",
|
g_signal_connect (monitors, "monitors-changed",
|
||||||
@@ -1660,16 +1646,5 @@ meta_wayland_init (void)
|
|||||||
void
|
void
|
||||||
meta_wayland_finalize (void)
|
meta_wayland_finalize (void)
|
||||||
{
|
{
|
||||||
MetaWaylandCompositor *compositor;
|
meta_xwayland_stop (meta_wayland_compositor_get_default ());
|
||||||
|
|
||||||
compositor = meta_wayland_compositor_get_default ();
|
|
||||||
|
|
||||||
meta_xwayland_stop (compositor);
|
|
||||||
g_clear_object (&compositor->launcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
MetaLauncher *
|
|
||||||
meta_wayland_compositor_get_launcher (MetaWaylandCompositor *compositor)
|
|
||||||
{
|
|
||||||
return compositor->launcher;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,432 +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 _MetaLauncherClass
|
|
||||||
{
|
|
||||||
GObjectClass parent_class;
|
|
||||||
|
|
||||||
void (*enter) (MetaLauncher *);
|
|
||||||
void (*leave) (MetaLauncher *);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _MetaLauncher
|
|
||||||
{
|
|
||||||
GObject parent;
|
|
||||||
|
|
||||||
GSocket *weston_launch;
|
|
||||||
int drm_fd;
|
|
||||||
|
|
||||||
gboolean vt_switched;
|
|
||||||
|
|
||||||
GMainContext *nested_context;
|
|
||||||
GMainLoop *nested_loop;
|
|
||||||
|
|
||||||
GSource *inner_source;
|
|
||||||
GSource *outer_source;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
SIGNAL_ENTER,
|
|
||||||
SIGNAL_LEAVE,
|
|
||||||
SIGNAL_LAST
|
|
||||||
};
|
|
||||||
|
|
||||||
static int signals[SIGNAL_LAST];
|
|
||||||
|
|
||||||
G_DEFINE_TYPE (MetaLauncher, meta_launcher, G_TYPE_OBJECT);
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
send_message_to_wl (GSocket *weston_launch,
|
|
||||||
void *message,
|
|
||||||
gsize size,
|
|
||||||
GSocketControlMessage *out_cmsg,
|
|
||||||
GSocketControlMessage **in_cmsg,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
int ok;
|
|
||||||
GInputVector in_iov = { &ok, sizeof (int) };
|
|
||||||
GOutputVector out_iov = { message, size };
|
|
||||||
GSocketControlMessage *out_all_cmsg[2];
|
|
||||||
GSocketControlMessage **in_all_cmsg;
|
|
||||||
int flags = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
out_all_cmsg[0] = out_cmsg;
|
|
||||||
out_all_cmsg[1] = NULL;
|
|
||||||
if (g_socket_send_message (weston_launch, NULL,
|
|
||||||
&out_iov, 1,
|
|
||||||
out_all_cmsg, -1,
|
|
||||||
flags, NULL, error) != (gssize)size)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (g_socket_receive_message (weston_launch, NULL,
|
|
||||||
&in_iov, 1,
|
|
||||||
&in_all_cmsg, NULL,
|
|
||||||
&flags, NULL, error) != sizeof (int))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (ok != 0)
|
|
||||||
{
|
|
||||||
if (ok == -1)
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Got failure from weston-launch");
|
|
||||||
else
|
|
||||||
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ok),
|
|
||||||
"Got failure from weston-launch: %s", strerror (-ok));
|
|
||||||
|
|
||||||
for (i = 0; in_all_cmsg && in_all_cmsg[i]; i++)
|
|
||||||
g_object_unref (in_all_cmsg[i]);
|
|
||||||
g_free (in_all_cmsg);
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_all_cmsg && in_all_cmsg[0])
|
|
||||||
{
|
|
||||||
for (i = 1; in_all_cmsg[i]; i++)
|
|
||||||
g_object_unref (in_all_cmsg[i]);
|
|
||||||
*in_cmsg = in_all_cmsg[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free (in_all_cmsg);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
meta_launcher_set_master (MetaLauncher *self,
|
|
||||||
gboolean master,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
struct weston_launcher_set_master message;
|
|
||||||
GSocketControlMessage *cmsg;
|
|
||||||
gboolean ok;
|
|
||||||
|
|
||||||
message.header.opcode = WESTON_LAUNCHER_DRM_SET_MASTER;
|
|
||||||
message.set_master = master;
|
|
||||||
|
|
||||||
cmsg = g_unix_fd_message_new ();
|
|
||||||
if (g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (cmsg),
|
|
||||||
self->drm_fd, error) == FALSE)
|
|
||||||
{
|
|
||||||
g_object_unref (cmsg);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ok = send_message_to_wl (self->weston_launch, &message,
|
|
||||||
sizeof message, cmsg, NULL, error);
|
|
||||||
|
|
||||||
g_object_unref (cmsg);
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
meta_launcher_open_input_device (MetaLauncher *self,
|
|
||||||
const char *name,
|
|
||||||
int flags,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
struct weston_launcher_open *message;
|
|
||||||
GSocketControlMessage *cmsg;
|
|
||||||
gboolean ok;
|
|
||||||
gsize size;
|
|
||||||
int *fds, n_fd;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
size = sizeof (struct weston_launcher_open) + strlen (name) + 1;
|
|
||||||
message = g_malloc (size);
|
|
||||||
message->header.opcode = WESTON_LAUNCHER_OPEN;
|
|
||||||
message->flags = flags;
|
|
||||||
strcpy (message->path, name);
|
|
||||||
message->path[strlen(name)] = 0;
|
|
||||||
|
|
||||||
ok = send_message_to_wl (self->weston_launch, message, size,
|
|
||||||
NULL, &cmsg, error);
|
|
||||||
|
|
||||||
if (ok)
|
|
||||||
{
|
|
||||||
g_assert (G_IS_UNIX_FD_MESSAGE (cmsg));
|
|
||||||
|
|
||||||
fds = g_unix_fd_message_steal_fds (G_UNIX_FD_MESSAGE (cmsg), &n_fd);
|
|
||||||
g_assert (n_fd == 1);
|
|
||||||
|
|
||||||
ret = fds[0];
|
|
||||||
g_free (fds);
|
|
||||||
g_object_unref (cmsg);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
g_free (message);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
meta_launcher_finalize (GObject *object)
|
|
||||||
{
|
|
||||||
MetaLauncher *launcher = META_LAUNCHER (object);
|
|
||||||
|
|
||||||
g_source_destroy (launcher->outer_source);
|
|
||||||
g_source_destroy (launcher->inner_source);
|
|
||||||
|
|
||||||
g_main_loop_unref (launcher->nested_loop);
|
|
||||||
g_main_context_unref (launcher->nested_context);
|
|
||||||
|
|
||||||
g_object_unref (launcher->weston_launch);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (meta_launcher_parent_class)->finalize (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
meta_launcher_enter (MetaLauncher *launcher)
|
|
||||||
{
|
|
||||||
GError *error;
|
|
||||||
|
|
||||||
error = NULL;
|
|
||||||
if (!meta_launcher_set_master (launcher, TRUE, &error))
|
|
||||||
{
|
|
||||||
g_critical ("Failed to become DRM master: %s", error->message);
|
|
||||||
g_error_free (error);
|
|
||||||
}
|
|
||||||
|
|
||||||
clutter_evdev_reclaim_devices ();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
meta_launcher_leave (MetaLauncher *launcher)
|
|
||||||
{
|
|
||||||
GError *error;
|
|
||||||
|
|
||||||
error = NULL;
|
|
||||||
if (!meta_launcher_set_master (launcher, FALSE, &error))
|
|
||||||
{
|
|
||||||
g_critical ("Failed to release DRM master: %s", error->message);
|
|
||||||
g_error_free (error);
|
|
||||||
}
|
|
||||||
|
|
||||||
clutter_evdev_release_devices ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
on_evdev_device_open (const char *path,
|
|
||||||
int flags,
|
|
||||||
gpointer user_data,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
MetaLauncher *launcher = user_data;
|
|
||||||
|
|
||||||
return meta_launcher_open_input_device (launcher, path, flags, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
handle_vt_enter (MetaLauncher *launcher)
|
|
||||||
{
|
|
||||||
g_assert (launcher->vt_switched);
|
|
||||||
|
|
||||||
g_main_loop_quit (launcher->nested_loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
handle_request_vt_switch (MetaLauncher *launcher)
|
|
||||||
{
|
|
||||||
struct weston_launcher_message message;
|
|
||||||
GError *error;
|
|
||||||
gboolean ok;
|
|
||||||
|
|
||||||
g_signal_emit (launcher, signals[SIGNAL_LEAVE], 0);
|
|
||||||
|
|
||||||
message.opcode = WESTON_LAUNCHER_CONFIRM_VT_SWITCH;
|
|
||||||
|
|
||||||
error = NULL;
|
|
||||||
ok = send_message_to_wl (launcher->weston_launch, &message,
|
|
||||||
sizeof (message), NULL, NULL, &error);
|
|
||||||
if (!ok) {
|
|
||||||
g_warning ("Failed to acknowledge VT switch: %s", error->message);
|
|
||||||
g_error_free (error);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_assert (!launcher->vt_switched);
|
|
||||||
launcher->vt_switched = TRUE;
|
|
||||||
|
|
||||||
/* We can't do anything at this point, because we don't
|
|
||||||
have input devices and we don't have the DRM master,
|
|
||||||
so let's run a nested busy loop until the VT is reentered */
|
|
||||||
g_main_loop_run (launcher->nested_loop);
|
|
||||||
|
|
||||||
g_assert (launcher->vt_switched);
|
|
||||||
launcher->vt_switched = FALSE;
|
|
||||||
|
|
||||||
g_signal_emit (launcher, signals[SIGNAL_ENTER], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_socket_readable (GSocket *socket,
|
|
||||||
GIOCondition condition,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
MetaLauncher *launcher = user_data;
|
|
||||||
struct weston_launcher_message header;
|
|
||||||
gssize read;
|
|
||||||
GError *error;
|
|
||||||
|
|
||||||
if ((condition & G_IO_IN) == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
error = NULL;
|
|
||||||
read = g_socket_receive (socket, (char*)&header, sizeof(header), NULL, &error);
|
|
||||||
if (read < (gssize)sizeof(header))
|
|
||||||
{
|
|
||||||
g_warning ("Error reading from weston-launcher socket: %s", error->message);
|
|
||||||
g_error_free (error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (header.opcode)
|
|
||||||
{
|
|
||||||
case WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH:
|
|
||||||
handle_request_vt_switch (launcher);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WESTON_LAUNCHER_SERVER_VT_ENTER:
|
|
||||||
handle_vt_enter (launcher);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
env_get_fd (const char *env)
|
|
||||||
{
|
|
||||||
const char *value;
|
|
||||||
|
|
||||||
value = g_getenv (env);
|
|
||||||
|
|
||||||
if (value == NULL)
|
|
||||||
return -1;
|
|
||||||
else
|
|
||||||
return g_ascii_strtoll (value, NULL, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
meta_launcher_init (MetaLauncher *self)
|
|
||||||
{
|
|
||||||
int launch_fd;
|
|
||||||
|
|
||||||
launch_fd = env_get_fd ("WESTON_LAUNCHER_SOCK");
|
|
||||||
if (launch_fd < 0)
|
|
||||||
g_error ("Invalid mutter-launch socket");
|
|
||||||
|
|
||||||
self->weston_launch = g_socket_new_from_fd (launch_fd, NULL);
|
|
||||||
|
|
||||||
clutter_evdev_set_open_callback (on_evdev_device_open, self);
|
|
||||||
|
|
||||||
self->nested_context = g_main_context_new ();
|
|
||||||
self->nested_loop = g_main_loop_new (self->nested_context, FALSE);
|
|
||||||
|
|
||||||
self->outer_source = g_socket_create_source (self->weston_launch, G_IO_IN, NULL);
|
|
||||||
g_source_set_callback (self->outer_source, (GSourceFunc)on_socket_readable, self, NULL);
|
|
||||||
g_source_attach (self->outer_source, NULL);
|
|
||||||
g_source_unref (self->outer_source);
|
|
||||||
|
|
||||||
self->inner_source = g_socket_create_source (self->weston_launch, G_IO_IN, NULL);
|
|
||||||
g_source_set_callback (self->inner_source, (GSourceFunc)on_socket_readable, self, NULL);
|
|
||||||
g_source_attach (self->inner_source, self->nested_context);
|
|
||||||
g_source_unref (self->inner_source);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
meta_launcher_class_init (MetaLauncherClass *klass)
|
|
||||||
{
|
|
||||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
||||||
|
|
||||||
object_class->finalize = meta_launcher_finalize;
|
|
||||||
|
|
||||||
klass->enter = meta_launcher_enter;
|
|
||||||
klass->leave = meta_launcher_leave;
|
|
||||||
|
|
||||||
signals[SIGNAL_ENTER] = g_signal_new ("enter",
|
|
||||||
G_TYPE_FROM_CLASS (klass),
|
|
||||||
G_SIGNAL_RUN_FIRST,
|
|
||||||
G_STRUCT_OFFSET (MetaLauncherClass, enter),
|
|
||||||
NULL, NULL, /* accumulator */
|
|
||||||
g_cclosure_marshal_VOID__VOID,
|
|
||||||
G_TYPE_NONE, 0);
|
|
||||||
|
|
||||||
signals[SIGNAL_LEAVE] = g_signal_new ("leave",
|
|
||||||
G_TYPE_FROM_CLASS (klass),
|
|
||||||
G_SIGNAL_RUN_FIRST,
|
|
||||||
G_STRUCT_OFFSET (MetaLauncherClass, leave),
|
|
||||||
NULL, NULL, /* accumulator */
|
|
||||||
g_cclosure_marshal_VOID__VOID,
|
|
||||||
G_TYPE_NONE, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
MetaLauncher *
|
|
||||||
meta_launcher_new (void)
|
|
||||||
{
|
|
||||||
return g_object_new (META_TYPE_LAUNCHER, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
meta_launcher_activate_vt (MetaLauncher *launcher,
|
|
||||||
int vt,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
struct weston_launcher_activate_vt message;
|
|
||||||
|
|
||||||
message.header.opcode = WESTON_LAUNCHER_ACTIVATE_VT;
|
|
||||||
message.vt = vt;
|
|
||||||
|
|
||||||
return send_message_to_wl (launcher->weston_launch, &message,
|
|
||||||
sizeof (message), NULL, NULL, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
meta_launcher_set_drm_fd (MetaLauncher *launcher,
|
|
||||||
int drm_fd)
|
|
||||||
{
|
|
||||||
launcher->drm_fd = drm_fd;
|
|
||||||
}
|
|
||||||
@@ -1,54 +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"
|
|
||||||
|
|
||||||
#define META_TYPE_LAUNCHER (meta_launcher_get_type())
|
|
||||||
#define META_LAUNCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_LAUNCHER, MetaLauncher))
|
|
||||||
#define META_LAUNCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_LAUNCHER, MetaLauncherClass))
|
|
||||||
#define META_IS_LAUNCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_LAUNCHER))
|
|
||||||
#define META_IS_LAUNCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_LAUNCHER))
|
|
||||||
#define META_LAUNCHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_LAUNCHER, MetaLauncherClass))
|
|
||||||
|
|
||||||
typedef struct _MetaLauncher MetaLauncher;
|
|
||||||
typedef struct _MetaLauncherClass MetaLauncherClass;
|
|
||||||
|
|
||||||
GType meta_launcher_get_type (void) G_GNUC_CONST;
|
|
||||||
|
|
||||||
MetaLauncher *meta_launcher_new (void);
|
|
||||||
|
|
||||||
gboolean meta_launcher_activate_vt (MetaLauncher *self,
|
|
||||||
int number,
|
|
||||||
GError **error);
|
|
||||||
|
|
||||||
void meta_launcher_set_drm_fd (MetaLauncher *self,
|
|
||||||
int drm_fd);
|
|
||||||
gboolean meta_launcher_set_master (MetaLauncher *self,
|
|
||||||
gboolean master,
|
|
||||||
GError **error);
|
|
||||||
int meta_launcher_open_input_device (MetaLauncher *self,
|
|
||||||
const char *name,
|
|
||||||
int flags,
|
|
||||||
GError **error);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -27,6 +27,9 @@
|
|||||||
gboolean
|
gboolean
|
||||||
meta_xwayland_start (MetaWaylandCompositor *compositor);
|
meta_xwayland_start (MetaWaylandCompositor *compositor);
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_xwayland_complete_init (void);
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_xwayland_stop (MetaWaylandCompositor *compositor);
|
meta_xwayland_stop (MetaWaylandCompositor *compositor);
|
||||||
|
|
||||||
|
|||||||
@@ -301,6 +301,14 @@ xserver_died (GPid pid,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
x_io_error (Display *display)
|
||||||
|
{
|
||||||
|
g_error ("Connection to xwayland lost");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
meta_xwayland_start (MetaWaylandCompositor *compositor)
|
meta_xwayland_start (MetaWaylandCompositor *compositor)
|
||||||
{
|
{
|
||||||
@@ -425,6 +433,18 @@ meta_xwayland_start (MetaWaylandCompositor *compositor)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* To be called right after connecting */
|
||||||
|
void
|
||||||
|
meta_xwayland_complete_init (void)
|
||||||
|
{
|
||||||
|
/* We install an X IO error handler in addition to the child watch,
|
||||||
|
because after Xlib connects our child watch may not be called soon
|
||||||
|
enough, and therefore we won't crash when X exits (and most important
|
||||||
|
we won't reset the tty).
|
||||||
|
*/
|
||||||
|
XSetIOErrorHandler (x_io_error);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_xwayland_stop (MetaWaylandCompositor *compositor)
|
meta_xwayland_stop (MetaWaylandCompositor *compositor)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,742 +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 <security/pam_appl.h>
|
|
||||||
|
|
||||||
#include <xf86drm.h>
|
|
||||||
|
|
||||||
#include <systemd/sd-login.h>
|
|
||||||
|
|
||||||
#include "weston-launch.h"
|
|
||||||
|
|
||||||
#define MAX_ARGV_SIZE 256
|
|
||||||
|
|
||||||
enum vt_state {
|
|
||||||
VT_HAS_VT,
|
|
||||||
VT_PENDING_CONFIRM,
|
|
||||||
VT_NOT_HAVE_VT,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct weston_launch {
|
|
||||||
struct pam_conv pc;
|
|
||||||
pam_handle_t *ph;
|
|
||||||
int tty;
|
|
||||||
int ttynr;
|
|
||||||
int sock[2];
|
|
||||||
struct passwd *pw;
|
|
||||||
|
|
||||||
int signalfd;
|
|
||||||
|
|
||||||
pid_t child;
|
|
||||||
int verbose;
|
|
||||||
char *new_user;
|
|
||||||
|
|
||||||
struct termios terminal_attributes;
|
|
||||||
int kb_mode;
|
|
||||||
enum vt_state vt_state;
|
|
||||||
int expect_drop_master;
|
|
||||||
};
|
|
||||||
|
|
||||||
union cmsg_data { unsigned char b[4]; int fd; };
|
|
||||||
|
|
||||||
static void quit (struct weston_launch *wl, int status);
|
|
||||||
|
|
||||||
static int
|
|
||||||
weston_launch_allowed(struct weston_launch *wl)
|
|
||||||
{
|
|
||||||
char *session, *seat;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (getuid() == 0)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
err = sd_pid_get_session(getpid(), &session);
|
|
||||||
if (err == 0 && session) {
|
|
||||||
if (sd_session_is_active(session) &&
|
|
||||||
sd_session_get_seat(session, &seat) == 0) {
|
|
||||||
free(seat);
|
|
||||||
free(session);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
free(session);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
setup_launcher_socket(struct weston_launch *wl)
|
|
||||||
{
|
|
||||||
if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, wl->sock) < 0)
|
|
||||||
error(1, errno, "socketpair failed");
|
|
||||||
|
|
||||||
fcntl(wl->sock[0], F_SETFD, O_CLOEXEC);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
setup_signals(struct weston_launch *wl)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
sigset_t mask;
|
|
||||||
struct sigaction sa;
|
|
||||||
|
|
||||||
memset(&sa, 0, sizeof sa);
|
|
||||||
sa.sa_handler = SIG_DFL;
|
|
||||||
sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
|
|
||||||
ret = sigaction(SIGCHLD, &sa, NULL);
|
|
||||||
assert(ret == 0);
|
|
||||||
|
|
||||||
sa.sa_handler = SIG_IGN;
|
|
||||||
sa.sa_flags = 0;
|
|
||||||
sigaction(SIGHUP, &sa, NULL);
|
|
||||||
|
|
||||||
ret = sigemptyset(&mask);
|
|
||||||
assert(ret == 0);
|
|
||||||
sigaddset(&mask, SIGCHLD);
|
|
||||||
sigaddset(&mask, SIGINT);
|
|
||||||
sigaddset(&mask, SIGTERM);
|
|
||||||
sigaddset(&mask, SIGUSR1);
|
|
||||||
ret = sigprocmask(SIG_BLOCK, &mask, NULL);
|
|
||||||
assert(ret == 0);
|
|
||||||
|
|
||||||
wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
|
|
||||||
if (wl->signalfd < 0)
|
|
||||||
return -errno;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
setenv_fd(const char *env, int fd)
|
|
||||||
{
|
|
||||||
char buf[32];
|
|
||||||
|
|
||||||
snprintf(buf, sizeof buf, "%d", fd);
|
|
||||||
setenv(env, buf, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
handle_setmaster(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
|
|
||||||
{
|
|
||||||
int ret = -1;
|
|
||||||
struct cmsghdr *cmsg;
|
|
||||||
struct weston_launcher_set_master *message;
|
|
||||||
union cmsg_data *data;
|
|
||||||
|
|
||||||
if (len != sizeof(*message)) {
|
|
||||||
error(0, 0, "missing value in setmaster request");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
message = msg->msg_iov->iov_base;
|
|
||||||
|
|
||||||
cmsg = CMSG_FIRSTHDR(msg);
|
|
||||||
if (!cmsg ||
|
|
||||||
cmsg->cmsg_level != SOL_SOCKET ||
|
|
||||||
cmsg->cmsg_type != SCM_RIGHTS) {
|
|
||||||
error(0, 0, "invalid control message");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = (union cmsg_data *) CMSG_DATA(cmsg);
|
|
||||||
if (data->fd == -1) {
|
|
||||||
error(0, 0, "missing drm fd in socket request");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message->set_master)
|
|
||||||
ret = drmSetMaster(data->fd);
|
|
||||||
else
|
|
||||||
ret = drmDropMaster(data->fd);
|
|
||||||
if (ret == -1)
|
|
||||||
ret = -errno;
|
|
||||||
|
|
||||||
if (message->set_master == 0)
|
|
||||||
wl->expect_drop_master = 0;
|
|
||||||
|
|
||||||
close(data->fd);
|
|
||||||
|
|
||||||
if (wl->verbose)
|
|
||||||
fprintf(stderr, "weston-launch: %sMaster, ret: %d, fd: %d\n",
|
|
||||||
message->set_master ? "set" : "drop", ret, data->fd);
|
|
||||||
|
|
||||||
out:
|
|
||||||
do {
|
|
||||||
len = send(wl->sock[0], &ret, sizeof ret, 0);
|
|
||||||
} while (len < 0 && errno == EINTR);
|
|
||||||
if (len < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
handle_confirm_vt_switch(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
|
|
||||||
{
|
|
||||||
int ret = -1;
|
|
||||||
|
|
||||||
if (wl->vt_state != VT_PENDING_CONFIRM) {
|
|
||||||
error(0, 0, "unexpected CONFIRM_VT_SWITCH");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wl->expect_drop_master) {
|
|
||||||
error(0, 0, "drmDropMaster not called for VT switch");
|
|
||||||
quit(wl, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
wl->vt_state = VT_NOT_HAVE_VT;
|
|
||||||
ioctl(wl->tty, VT_RELDISP, 1);
|
|
||||||
|
|
||||||
if (wl->verbose)
|
|
||||||
fprintf(stderr, "weston-launcher: confirmed VT switch\n");
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
out:
|
|
||||||
do {
|
|
||||||
len = send(wl->sock[0], &ret, sizeof ret, 0);
|
|
||||||
} while (len < 0 && errno == EINTR);
|
|
||||||
if (len < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
handle_activate_vt(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
|
|
||||||
{
|
|
||||||
int ret = -1;
|
|
||||||
struct weston_launcher_activate_vt *message;
|
|
||||||
|
|
||||||
if (len != sizeof(*message)) {
|
|
||||||
error(0, 0, "missing value in activate_vt request");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
message = msg->msg_iov->iov_base;
|
|
||||||
|
|
||||||
ret = ioctl(wl->tty, VT_ACTIVATE, message->vt);
|
|
||||||
if (ret < 0)
|
|
||||||
ret = -errno;
|
|
||||||
|
|
||||||
if (wl->verbose)
|
|
||||||
fprintf(stderr, "weston-launch: activate VT, ret: %d\n", ret);
|
|
||||||
|
|
||||||
out:
|
|
||||||
do {
|
|
||||||
len = send(wl->sock[0], &ret, sizeof ret, 0);
|
|
||||||
} while (len < 0 && errno == EINTR);
|
|
||||||
if (len < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
|
|
||||||
{
|
|
||||||
int fd = -1, ret = -1;
|
|
||||||
char control[CMSG_SPACE(sizeof(fd))];
|
|
||||||
struct cmsghdr *cmsg;
|
|
||||||
struct stat s;
|
|
||||||
struct msghdr nmsg;
|
|
||||||
struct iovec iov;
|
|
||||||
struct weston_launcher_open *message;
|
|
||||||
union cmsg_data *data;
|
|
||||||
|
|
||||||
message = msg->msg_iov->iov_base;
|
|
||||||
if ((size_t)len < sizeof(*message))
|
|
||||||
goto err0;
|
|
||||||
|
|
||||||
/* Ensure path is null-terminated */
|
|
||||||
((char *) message)[len-1] = '\0';
|
|
||||||
|
|
||||||
if (stat(message->path, &s) < 0)
|
|
||||||
goto err0;
|
|
||||||
|
|
||||||
fd = open(message->path, message->flags);
|
|
||||||
if (fd < 0) {
|
|
||||||
fprintf(stderr, "Error opening device %s: %m\n",
|
|
||||||
message->path);
|
|
||||||
goto err0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (major(s.st_rdev) != INPUT_MAJOR) {
|
|
||||||
close(fd);
|
|
||||||
fd = -1;
|
|
||||||
fprintf(stderr, "Device %s is not an input device\n",
|
|
||||||
message->path);
|
|
||||||
goto err0;
|
|
||||||
}
|
|
||||||
|
|
||||||
err0:
|
|
||||||
memset(&nmsg, 0, sizeof nmsg);
|
|
||||||
nmsg.msg_iov = &iov;
|
|
||||||
nmsg.msg_iovlen = 1;
|
|
||||||
if (fd != -1) {
|
|
||||||
nmsg.msg_control = control;
|
|
||||||
nmsg.msg_controllen = sizeof control;
|
|
||||||
cmsg = CMSG_FIRSTHDR(&nmsg);
|
|
||||||
cmsg->cmsg_level = SOL_SOCKET;
|
|
||||||
cmsg->cmsg_type = SCM_RIGHTS;
|
|
||||||
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
|
|
||||||
data = (union cmsg_data *) CMSG_DATA(cmsg);
|
|
||||||
data->fd = fd;
|
|
||||||
nmsg.msg_controllen = cmsg->cmsg_len;
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
iov.iov_base = &ret;
|
|
||||||
iov.iov_len = sizeof ret;
|
|
||||||
|
|
||||||
if (wl->verbose)
|
|
||||||
fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
|
|
||||||
message->path, ret, fd);
|
|
||||||
do {
|
|
||||||
len = sendmsg(wl->sock[0], &nmsg, 0);
|
|
||||||
} while (len < 0 && errno == EINTR);
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
if (len < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
handle_socket_msg(struct weston_launch *wl)
|
|
||||||
{
|
|
||||||
char control[CMSG_SPACE(sizeof(int))];
|
|
||||||
char buf[BUFSIZ];
|
|
||||||
struct msghdr msg;
|
|
||||||
struct iovec iov;
|
|
||||||
int ret = -1;
|
|
||||||
ssize_t len;
|
|
||||||
struct weston_launcher_message *message;
|
|
||||||
|
|
||||||
memset(&msg, 0, sizeof(msg));
|
|
||||||
iov.iov_base = buf;
|
|
||||||
iov.iov_len = sizeof buf;
|
|
||||||
msg.msg_iov = &iov;
|
|
||||||
msg.msg_iovlen = 1;
|
|
||||||
msg.msg_control = control;
|
|
||||||
msg.msg_controllen = sizeof control;
|
|
||||||
|
|
||||||
do {
|
|
||||||
len = recvmsg(wl->sock[0], &msg, 0);
|
|
||||||
} while (len < 0 && errno == EINTR);
|
|
||||||
|
|
||||||
if (len < 1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
message = (void *) buf;
|
|
||||||
switch (message->opcode) {
|
|
||||||
case WESTON_LAUNCHER_OPEN:
|
|
||||||
ret = handle_open(wl, &msg, len);
|
|
||||||
break;
|
|
||||||
case WESTON_LAUNCHER_DRM_SET_MASTER:
|
|
||||||
ret = handle_setmaster(wl, &msg, len);
|
|
||||||
break;
|
|
||||||
case WESTON_LAUNCHER_CONFIRM_VT_SWITCH:
|
|
||||||
ret = handle_confirm_vt_switch(wl, &msg, len);
|
|
||||||
break;
|
|
||||||
case WESTON_LAUNCHER_ACTIVATE_VT:
|
|
||||||
ret = handle_activate_vt(wl, &msg, len);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
tty_reset(struct weston_launch *wl)
|
|
||||||
{
|
|
||||||
struct vt_mode mode = { 0 };
|
|
||||||
|
|
||||||
if (ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
|
|
||||||
fprintf(stderr, "failed to restore keyboard mode: %m\n");
|
|
||||||
|
|
||||||
if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
|
|
||||||
fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
|
|
||||||
|
|
||||||
if (tcsetattr(wl->tty, TCSANOW, &wl->terminal_attributes) < 0)
|
|
||||||
fprintf(stderr, "could not restore terminal to canonical mode\n");
|
|
||||||
|
|
||||||
mode.mode = VT_AUTO;
|
|
||||||
if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
|
|
||||||
fprintf(stderr, "could not reset vt handling\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
quit(struct weston_launch *wl, int status)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (wl->child > 0)
|
|
||||||
kill(wl->child, SIGKILL);
|
|
||||||
|
|
||||||
close(wl->signalfd);
|
|
||||||
close(wl->sock[0]);
|
|
||||||
|
|
||||||
tty_reset(wl);
|
|
||||||
|
|
||||||
if (wl->new_user) {
|
|
||||||
err = pam_close_session(wl->ph, 0);
|
|
||||||
if (err)
|
|
||||||
fprintf(stderr, "pam_close_session failed: %d: %s\n",
|
|
||||||
err, pam_strerror(wl->ph, err));
|
|
||||||
pam_end(wl->ph, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
handle_vt_switch(struct weston_launch *wl)
|
|
||||||
{
|
|
||||||
struct weston_launcher_message message;
|
|
||||||
ssize_t len;
|
|
||||||
|
|
||||||
if (wl->vt_state == VT_HAS_VT) {
|
|
||||||
wl->vt_state = VT_PENDING_CONFIRM;
|
|
||||||
wl->expect_drop_master = 1;
|
|
||||||
message.opcode = WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH;
|
|
||||||
} else if (wl->vt_state == VT_NOT_HAVE_VT) {
|
|
||||||
wl->vt_state = VT_HAS_VT;
|
|
||||||
ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
|
|
||||||
|
|
||||||
message.opcode = WESTON_LAUNCHER_SERVER_VT_ENTER;
|
|
||||||
} else
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
do {
|
|
||||||
len = send(wl->sock[0], &message, sizeof(message), 0);
|
|
||||||
} while (len < 0 && errno == EINTR);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
handle_signal(struct weston_launch *wl)
|
|
||||||
{
|
|
||||||
struct signalfd_siginfo sig;
|
|
||||||
int pid, status, ret;
|
|
||||||
|
|
||||||
if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
|
|
||||||
error(0, errno, "reading signalfd failed");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (sig.ssi_signo) {
|
|
||||||
case SIGCHLD:
|
|
||||||
pid = waitpid(-1, &status, 0);
|
|
||||||
if (pid == wl->child) {
|
|
||||||
wl->child = 0;
|
|
||||||
if (WIFEXITED(status))
|
|
||||||
ret = WEXITSTATUS(status);
|
|
||||||
else if (WIFSIGNALED(status))
|
|
||||||
/*
|
|
||||||
* If weston dies because of signal N, we
|
|
||||||
* return 10+N. This is distinct from
|
|
||||||
* weston-launch dying because of a signal
|
|
||||||
* (128+N).
|
|
||||||
*/
|
|
||||||
ret = 10 + WTERMSIG(status);
|
|
||||||
else
|
|
||||||
ret = 0;
|
|
||||||
quit(wl, ret);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SIGTERM:
|
|
||||||
case SIGINT:
|
|
||||||
if (wl->child)
|
|
||||||
kill(wl->child, sig.ssi_signo);
|
|
||||||
break;
|
|
||||||
case SIGUSR1:
|
|
||||||
return handle_vt_switch(wl);
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
setup_tty(struct weston_launch *wl)
|
|
||||||
{
|
|
||||||
struct stat buf;
|
|
||||||
struct termios raw_attributes;
|
|
||||||
struct vt_mode mode = { 0 };
|
|
||||||
char *session, *tty;
|
|
||||||
char path[PATH_MAX];
|
|
||||||
int ok;
|
|
||||||
|
|
||||||
ok = sd_pid_get_session(getpid(), &session);
|
|
||||||
if (ok < 0)
|
|
||||||
error(1, -ok, "could not determine current session");
|
|
||||||
|
|
||||||
ok = sd_session_get_tty(session, &tty);
|
|
||||||
if (ok == 0) {
|
|
||||||
snprintf(path, PATH_MAX, "/dev/%s", tty);
|
|
||||||
wl->tty = open(path, O_RDWR | O_NOCTTY | O_CLOEXEC);
|
|
||||||
free(tty);
|
|
||||||
#ifdef HAVE_SD_SESSION_GET_VT
|
|
||||||
} else if (ok == -ENOENT) {
|
|
||||||
/* Negative errnos are cool, right?
|
|
||||||
So cool that we can't distinguish "session not found"
|
|
||||||
from "key does not exist in the session file"!
|
|
||||||
Let's assume the latter, as we got the value
|
|
||||||
from sd_pid_get_session()...
|
|
||||||
*/
|
|
||||||
|
|
||||||
ok = sd_session_get_vt(session, &tty);
|
|
||||||
if (ok < 0)
|
|
||||||
error(1, -ok, "could not determine current TTY");
|
|
||||||
|
|
||||||
snprintf(path, PATH_MAX, "/dev/tty%s", tty);
|
|
||||||
wl->tty = open(path, O_RDWR | O_NOCTTY | O_CLOEXEC);
|
|
||||||
free(tty);
|
|
||||||
#endif
|
|
||||||
} else
|
|
||||||
error(1, -ok, "could not determine current TTY");
|
|
||||||
|
|
||||||
if (wl->tty < 0)
|
|
||||||
error(1, errno, "failed to open tty");
|
|
||||||
|
|
||||||
if (fstat(wl->tty, &buf) < 0)
|
|
||||||
error(1, errno, "stat %s failed", path);
|
|
||||||
|
|
||||||
if (major(buf.st_rdev) != TTY_MAJOR)
|
|
||||||
error(1, 0, "invalid tty device: %s", path);
|
|
||||||
|
|
||||||
wl->ttynr = minor(buf.st_rdev);
|
|
||||||
|
|
||||||
if (tcgetattr(wl->tty, &wl->terminal_attributes) < 0)
|
|
||||||
error(1, errno, "could not get terminal attributes");
|
|
||||||
|
|
||||||
/* Ignore control characters and disable echo */
|
|
||||||
raw_attributes = wl->terminal_attributes;
|
|
||||||
cfmakeraw(&raw_attributes);
|
|
||||||
|
|
||||||
/* Fix up line endings to be normal (cfmakeraw hoses them) */
|
|
||||||
raw_attributes.c_oflag |= OPOST | OCRNL;
|
|
||||||
/* Don't generate ttou signals */
|
|
||||||
raw_attributes.c_oflag &= ~TOSTOP;
|
|
||||||
|
|
||||||
if (tcsetattr(wl->tty, TCSANOW, &raw_attributes) < 0)
|
|
||||||
error(1, errno, "could not put terminal into raw mode");
|
|
||||||
|
|
||||||
ioctl(wl->tty, KDGKBMODE, &wl->kb_mode);
|
|
||||||
ok = ioctl(wl->tty, KDSKBMODE, K_OFF);
|
|
||||||
if (ok < 0) {
|
|
||||||
ok = ioctl(wl->tty, KDSKBMODE, K_RAW);
|
|
||||||
if (ok < 0)
|
|
||||||
error(1, errno, "failed to set keyboard mode on tty");
|
|
||||||
}
|
|
||||||
|
|
||||||
ok = ioctl(wl->tty, KDSETMODE, KD_GRAPHICS);
|
|
||||||
if (ok < 0)
|
|
||||||
error(1, errno, "failed to set KD_GRAPHICS mode on tty");
|
|
||||||
|
|
||||||
wl->vt_state = VT_HAS_VT;
|
|
||||||
mode.mode = VT_PROCESS;
|
|
||||||
mode.relsig = SIGUSR1;
|
|
||||||
mode.acqsig = SIGUSR1;
|
|
||||||
ok = ioctl(wl->tty, VT_SETMODE, &mode);
|
|
||||||
if (ok < 0)
|
|
||||||
error(1, errno, "failed to take control of vt handling");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
drop_privileges(struct weston_launch *wl)
|
|
||||||
{
|
|
||||||
if (setgid(wl->pw->pw_gid) < 0 ||
|
|
||||||
#ifdef HAVE_INITGROUPS
|
|
||||||
initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
|
|
||||||
#endif
|
|
||||||
setuid(wl->pw->pw_uid) < 0)
|
|
||||||
error(1, errno, "dropping privileges failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
launch_compositor(struct weston_launch *wl, int argc, char *argv[])
|
|
||||||
{
|
|
||||||
char command[PATH_MAX];
|
|
||||||
char *child_argv[MAX_ARGV_SIZE];
|
|
||||||
sigset_t mask;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (wl->verbose)
|
|
||||||
printf("weston-launch: spawned weston with pid: %d\n", getpid());
|
|
||||||
|
|
||||||
drop_privileges(wl);
|
|
||||||
|
|
||||||
setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
|
|
||||||
setenv("LD_LIBRARY_PATH", LIBDIR, 1);
|
|
||||||
unsetenv("DISPLAY");
|
|
||||||
|
|
||||||
/* Do not give our signal mask to the new process. */
|
|
||||||
sigemptyset(&mask);
|
|
||||||
sigaddset(&mask, SIGTERM);
|
|
||||||
sigaddset(&mask, SIGCHLD);
|
|
||||||
sigaddset(&mask, SIGINT);
|
|
||||||
sigaddset(&mask, SIGUSR1);
|
|
||||||
sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
|
||||||
|
|
||||||
snprintf (command, PATH_MAX, "%s \"$@\"", argv[0]);
|
|
||||||
|
|
||||||
child_argv[0] = wl->pw->pw_shell;
|
|
||||||
child_argv[1] = "-l";
|
|
||||||
child_argv[2] = "-c";
|
|
||||||
child_argv[3] = command;
|
|
||||||
for (i = 0; i < argc; ++i)
|
|
||||||
child_argv[4 + i] = argv[i];
|
|
||||||
child_argv[4 + i] = NULL;
|
|
||||||
|
|
||||||
execv(child_argv[0], child_argv);
|
|
||||||
error(1, errno, "exec failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
help(const char *name)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
|
|
||||||
fprintf(stderr, " -u, --user Start session as specified username\n");
|
|
||||||
fprintf(stderr, " -v, --verbose Be verbose\n");
|
|
||||||
fprintf(stderr, " -h, --help Display this help message\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
struct weston_launch wl;
|
|
||||||
int i, c;
|
|
||||||
struct option opts[] = {
|
|
||||||
{ "verbose", no_argument, NULL, 'v' },
|
|
||||||
{ "help", no_argument, NULL, 'h' },
|
|
||||||
{ 0, 0, NULL, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
memset(&wl, 0, sizeof wl);
|
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
|
|
||||||
switch (c) {
|
|
||||||
case 'v':
|
|
||||||
wl.verbose = 1;
|
|
||||||
break;
|
|
||||||
case 'h':
|
|
||||||
help("weston-launch");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((argc - optind) > (MAX_ARGV_SIZE - 6))
|
|
||||||
error(1, E2BIG, "Too many arguments to pass to weston");
|
|
||||||
|
|
||||||
if (strcmp (argv[optind], "mutter-wayland") &&
|
|
||||||
strcmp (argv[optind], "gnome-shell-wayland"))
|
|
||||||
error(1, 0, "mutter-launch can only be used to launch mutter or gnome-shell");
|
|
||||||
|
|
||||||
wl.pw = getpwuid(getuid());
|
|
||||||
if (wl.pw == NULL)
|
|
||||||
error(1, errno, "failed to get username");
|
|
||||||
|
|
||||||
if (!weston_launch_allowed(&wl))
|
|
||||||
error(1, 0, "Permission denied. You must run from an active and local (systemd) session.");
|
|
||||||
|
|
||||||
if (setup_tty(&wl) < 0)
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
|
|
||||||
if (setup_launcher_socket(&wl) < 0)
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
|
|
||||||
if (setup_signals(&wl) < 0)
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
|
|
||||||
wl.child = fork();
|
|
||||||
if (wl.child == -1) {
|
|
||||||
error(1, errno, "fork failed");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wl.child == 0)
|
|
||||||
launch_compositor(&wl, argc - optind, argv + optind);
|
|
||||||
|
|
||||||
close(wl.sock[1]);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
struct pollfd fds[2];
|
|
||||||
int n;
|
|
||||||
|
|
||||||
fds[0].fd = wl.sock[0];
|
|
||||||
fds[0].events = POLLIN;
|
|
||||||
fds[1].fd = wl.signalfd;
|
|
||||||
fds[1].events = POLLIN;
|
|
||||||
|
|
||||||
n = poll(fds, 2, -1);
|
|
||||||
if (n < 0)
|
|
||||||
error(0, errno, "poll failed");
|
|
||||||
if (fds[0].revents & POLLIN)
|
|
||||||
handle_socket_msg(&wl);
|
|
||||||
if (fds[1].revents)
|
|
||||||
handle_signal(&wl);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,59 +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_opcode {
|
|
||||||
WESTON_LAUNCHER_OPEN,
|
|
||||||
WESTON_LAUNCHER_DRM_SET_MASTER,
|
|
||||||
WESTON_LAUNCHER_ACTIVATE_VT,
|
|
||||||
WESTON_LAUNCHER_CONFIRM_VT_SWITCH,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum weston_launcher_server_opcode {
|
|
||||||
WESTON_LAUNCHER_SERVER_REQUEST_VT_SWITCH,
|
|
||||||
WESTON_LAUNCHER_SERVER_VT_ENTER,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct weston_launcher_message {
|
|
||||||
int opcode;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct weston_launcher_open {
|
|
||||||
struct weston_launcher_message header;
|
|
||||||
int flags;
|
|
||||||
char path[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct weston_launcher_set_master {
|
|
||||||
struct weston_launcher_message header;
|
|
||||||
int set_master;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct weston_launcher_activate_vt {
|
|
||||||
struct weston_launcher_message header;
|
|
||||||
int vt;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
Reference in New Issue
Block a user