[mutter] MetaWindowGroup: Handle painting inside a ClutterClone
- From: Owen Taylor <otaylor src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] MetaWindowGroup: Handle painting inside a ClutterClone
- Date: Thu, 16 Aug 2012 00:44:27 +0000 (UTC)
commit c27b4b7cfc23ccfd83ddc83a989f807428c7d612
Author: Owen W. Taylor <otaylor fishsoup net>
Date: Wed Aug 15 19:03:39 2012 -0400
MetaWindowGroup: Handle painting inside a ClutterClone
Look at the current COGL model-view matrix and use that to find
out any offset we are painting at as a result of being inside
a ClutterClone.
https://bugzilla.gnome.org/show_bug.cgi?id=681953
src/compositor/meta-window-group.c | 171 ++++++++++++++++++++++++++++++------
1 files changed, 142 insertions(+), 29 deletions(-)
---
diff --git a/src/compositor/meta-window-group.c b/src/compositor/meta-window-group.c
index 4ba2118..c47cfaf 100644
--- a/src/compositor/meta-window-group.c
+++ b/src/compositor/meta-window-group.c
@@ -26,9 +26,28 @@ struct _MetaWindowGroup
G_DEFINE_TYPE (MetaWindowGroup, meta_window_group, CLUTTER_TYPE_GROUP);
-/* We want to find out if the window is "close enough" to
- * 1:1 transform. We do that by converting the transformed coordinates
- * to 24.8 fixed-point before checking if they look right.
+/* This file uses pixel-aligned region computation to determine what
+ * can be clipped out. This only really works if everything is aligned
+ * to the pixel grid - not scaled or rotated and at integer offsets.
+ *
+ * (This could be relaxed - if we turned off filtering for unscaled
+ * windows then windows would be, by definition aligned to the pixel
+ * grid. And for rectangular windows without a shape, the outline that
+ * we draw for an unrotated window is always a rectangle because we
+ * don't use antialasing for the window boundary - with or without
+ * filtering, with or without a scale. But figuring out exactly
+ * what pixels will be drawn by the graphics system in these cases
+ * gets tricky, so we just go for the easiest part - no scale,
+ * and at integer offsets.)
+ *
+ * The way we check for pixel-aligned is by looking at the
+ * transformation into screen space of the allocation box of an actor
+ * and and checking if the corners are "close enough" to integral
+ * pixel values.
+ */
+
+/* The definition of "close enough" to integral pixel values is
+ * equality when we convert to 24.8 fixed-point.
*/
static inline int
round_to_fixed (float x)
@@ -36,41 +55,24 @@ round_to_fixed (float x)
return roundf (x * 256);
}
-/* We can only (easily) apply our logic for figuring out what a window
- * obscures if is not transformed. This function does that check and
- * as a side effect gets the position of the upper-left corner of the
- * actors.
- *
- * (We actually could handle scaled and non-integrally positioned actors
- * too as long as they weren't shaped - no filtering is done at the
- * edges so a rectangle stays a rectangle. But the gain from that is
- * small, especally since most of our windows are shaped. The simple
- * case we handle here is the case that matters when the user is just
- * using the desktop normally.)
- *
- * If we assume that the window group is untransformed (it better not
- * be!) then we could also make this determination by checking directly
- * if the actor itself is rotated, scaled, or at a non-integral position.
- * However, the criterion for "close enough" in that case get trickier,
- * since, for example, the allowed rotation depends on the size of
- * actor. The approach we take here is to just require everything
- * to be within 1/256th of a pixel.
+/* This helper function checks if (according to our fixed point precision)
+ * the vertices @verts form a box of width @widthf and height @heightf
+ * located at integral coordinates. These coordinates are returned
+ * in @x_origin and @y_origin.
*/
static gboolean
-actor_is_untransformed (ClutterActor *actor,
- int *x_origin,
- int *y_origin)
+vertices_are_untransformed (ClutterVertex *verts,
+ float widthf,
+ float heightf,
+ int *x_origin,
+ int *y_origin)
{
- gfloat widthf, heightf;
int width, height;
- ClutterVertex verts[4];
int v0x, v0y, v1x, v1y, v2x, v2y, v3x, v3y;
int x, y;
- clutter_actor_get_size (actor, &widthf, &heightf);
width = round_to_fixed (widthf); height = round_to_fixed (heightf);
- clutter_actor_get_abs_allocation_vertices (actor, verts);
v0x = round_to_fixed (verts[0].x); v0y = round_to_fixed (verts[0].y);
v1x = round_to_fixed (verts[1].x); v1y = round_to_fixed (verts[1].y);
v2x = round_to_fixed (verts[2].x); v2y = round_to_fixed (verts[2].y);
@@ -101,6 +103,81 @@ actor_is_untransformed (ClutterActor *actor,
return TRUE;
}
+/* Check if an actor is "untransformed" - which actually means transformed by
+ * at most a integer-translation. The integer translation, if any, is returned.
+ */
+static gboolean
+actor_is_untransformed (ClutterActor *actor,
+ int *x_origin,
+ int *y_origin)
+{
+ gfloat widthf, heightf;
+ ClutterVertex verts[4];
+
+ clutter_actor_get_size (actor, &widthf, &heightf);
+ clutter_actor_get_abs_allocation_vertices (actor, verts);
+
+ return vertices_are_untransformed (verts, widthf, heightf, x_origin, y_origin);
+}
+
+/* Help macros to scale from OpenGL <-1,1> coordinates system to
+ * window coordinates ranging [0,window-size]. Borrowed from clutter-utils.c
+ */
+#define MTX_GL_SCALE_X(x,w,v1,v2) ((((((x) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2))
+#define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - (((((y) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2))
+
+/* Check if we're painting the MetaWindowGroup "untransformed". This can
+ * differ from the result of actor_is_untransformed(window_group) if we're
+ * inside a clone paint. The integer translation, if any, is returned.
+ */
+static gboolean
+painting_untransformed (MetaWindowGroup *window_group,
+ int *x_origin,
+ int *y_origin)
+{
+ CoglMatrix modelview, projection, modelview_projection;
+ ClutterVertex vertices[4];
+ int width, height;
+ float viewport[4];
+ int i;
+
+ cogl_get_modelview_matrix (&modelview);
+ cogl_get_projection_matrix (&projection);
+
+ cogl_matrix_multiply (&modelview_projection,
+ &projection,
+ &modelview);
+
+ meta_screen_get_size (window_group->screen, &width, &height);
+
+ vertices[0].x = 0;
+ vertices[0].y = 0;
+ vertices[0].z = 0;
+ vertices[1].x = width;
+ vertices[1].y = 0;
+ vertices[1].z = 0;
+ vertices[2].x = 0;
+ vertices[2].y = height;
+ vertices[2].z = 0;
+ vertices[3].x = width;
+ vertices[3].y = height;
+ vertices[3].z = 0;
+
+ cogl_get_viewport (viewport);
+
+ for (i = 0; i < 4; i++)
+ {
+ float w = 1;
+ cogl_matrix_transform_point (&modelview_projection, &vertices[i].x, &vertices[i].y, &vertices[i].z, &w);
+ vertices[i].x = MTX_GL_SCALE_X (vertices[i].x, w,
+ viewport[2], viewport[0]);
+ vertices[i].y = MTX_GL_SCALE_Y (vertices[i].y, w,
+ viewport[3], viewport[1]);
+ }
+
+ return vertices_are_untransformed (vertices, width, height, x_origin, y_origin);
+}
+
static void
meta_window_group_paint (ClutterActor *actor)
{
@@ -109,10 +186,40 @@ meta_window_group_paint (ClutterActor *actor)
ClutterActor *stage;
cairo_rectangle_int_t visible_rect, unredirected_rect;
GList *children, *l;
+<<<<<<< HEAD
gfloat group_x, group_y;
+=======
+ int paint_x_origin, paint_y_origin;
+ int actor_x_origin, actor_y_origin;
+ int paint_x_offset, paint_y_offset;
+>>>>>>> MetaWindowGroup: Handle painting inside a ClutterClone
MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen);
+
+ /* Normally we expect an actor to be drawn at it's position on the screen.
+ * However, if we're inside the paint of a ClutterClone, that won't be the
+ * case and we need to compensate. We look at the position of the window
+ * group under the current model-view matrix and the position of the actor.
+ * If they are both simply integer translations, then we can compensate
+ * easily, otherwise we give up.
+ *
+ * Possible cleanup: work entirely in paint space - we can compute the
+ * combination of the model-view matrix with the local matrix for each child
+ * actor and get a total transformation for that actor for how we are
+ * painting currently, and never worry about how actors are positioned
+ * on the stage.
+ */
+ if (!painting_untransformed (window_group, &paint_x_origin, &paint_y_origin) ||
+ !actor_is_untransformed (actor, &actor_x_origin, &actor_y_origin))
+ {
+ CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);
+ return;
+ }
+
+ paint_x_offset = paint_x_origin - actor_x_origin;
+ paint_y_offset = paint_y_origin - actor_y_origin;
+
if (info->unredirected_window != NULL)
{
meta_window_actor_get_shape_bounds (META_WINDOW_ACTOR (info->unredirected_window), &unredirected_rect);
@@ -175,6 +282,9 @@ meta_window_group_paint (ClutterActor *actor)
if (!actor_is_untransformed (CLUTTER_ACTOR (window_actor), &x, &y))
continue;
+ x += paint_x_offset;
+ y += paint_y_offset;
+
/* Temporarily move to the coordinate system of the actor */
cairo_region_translate (visible_region, - x, - y);
@@ -198,6 +308,9 @@ meta_window_group_paint (ClutterActor *actor)
if (!actor_is_untransformed (CLUTTER_ACTOR (background_actor), &x, &y))
continue;
+ x += paint_x_offset;
+ y += paint_y_offset;
+
cairo_region_translate (visible_region, - x, - y);
meta_background_actor_set_visible_region (background_actor, visible_region);
cairo_region_translate (visible_region, x, y);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]