mirror of
https://github.com/brl/mutter.git
synced 2024-11-13 09:46:08 -05:00
47af6a0bbf
Add MutterTextureTower, an abstraction for getting a image with the right level of detail for rendering at a particular scale, by manually scaling down by powers of two. This results in much better looking scaled window images when mipmaps can't be used with texture_from_pixmap (which is the typical case for current GL drivers.) When framebuffer objects are available, they are used to do the scaledown using the GPU without having to pull the data back from video memory. A software codepath is also available for the case when FBO's are not present, though performance will suffer https://bugzilla.gnome.org/show_bug.cgi?id=601032
598 lines
19 KiB
C
Executable File
598 lines
19 KiB
C
Executable File
/*
|
|
* shaped texture
|
|
*
|
|
* An actor to draw a texture clipped to a list of rectangles
|
|
*
|
|
* Authored By Neil Roberts <neil@linux.intel.com>
|
|
*
|
|
* Copyright (C) 2008 Intel Corporation
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
* 02111-1307, USA.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include "mutter-shaped-texture.h"
|
|
#include "mutter-texture-tower.h"
|
|
|
|
#include <clutter/clutter.h>
|
|
#include <cogl/cogl.h>
|
|
#include <string.h>
|
|
|
|
static void mutter_shaped_texture_dispose (GObject *object);
|
|
static void mutter_shaped_texture_finalize (GObject *object);
|
|
static void mutter_shaped_texture_notify (GObject *object,
|
|
GParamSpec *pspec);
|
|
|
|
static void mutter_shaped_texture_paint (ClutterActor *actor);
|
|
static void mutter_shaped_texture_pick (ClutterActor *actor,
|
|
const ClutterColor *color);
|
|
|
|
static void mutter_shaped_texture_update_area (ClutterX11TexturePixmap *texture,
|
|
int x,
|
|
int y,
|
|
int width,
|
|
int height);
|
|
|
|
static void mutter_shaped_texture_dirty_mask (MutterShapedTexture *stex);
|
|
|
|
#ifdef HAVE_GLX_TEXTURE_PIXMAP
|
|
G_DEFINE_TYPE (MutterShapedTexture, mutter_shaped_texture,
|
|
CLUTTER_GLX_TYPE_TEXTURE_PIXMAP);
|
|
#else /* HAVE_GLX_TEXTURE_PIXMAP */
|
|
G_DEFINE_TYPE (MutterShapedTexture, mutter_shaped_texture,
|
|
CLUTTER_X11_TYPE_TEXTURE_PIXMAP);
|
|
#endif /* HAVE_GLX_TEXTURE_PIXMAP */
|
|
|
|
#define MUTTER_SHAPED_TEXTURE_GET_PRIVATE(obj) \
|
|
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUTTER_TYPE_SHAPED_TEXTURE, \
|
|
MutterShapedTexturePrivate))
|
|
|
|
struct _MutterShapedTexturePrivate
|
|
{
|
|
MutterTextureTower *paint_tower;
|
|
CoglHandle mask_texture;
|
|
CoglHandle material;
|
|
CoglHandle material_unshaped;
|
|
#if 1 /* see workaround comment in mutter_shaped_texture_paint */
|
|
CoglHandle material_workaround;
|
|
#endif
|
|
|
|
GdkRegion *clip_region;
|
|
|
|
guint mask_width, mask_height;
|
|
|
|
GArray *rectangles;
|
|
};
|
|
|
|
static void
|
|
mutter_shaped_texture_class_init (MutterShapedTextureClass *klass)
|
|
{
|
|
GObjectClass *gobject_class = (GObjectClass *) klass;
|
|
ClutterActorClass *actor_class = (ClutterActorClass *) klass;
|
|
ClutterX11TexturePixmapClass *x11_texture_class = (ClutterX11TexturePixmapClass *) klass;
|
|
|
|
gobject_class->dispose = mutter_shaped_texture_dispose;
|
|
gobject_class->finalize = mutter_shaped_texture_finalize;
|
|
gobject_class->notify = mutter_shaped_texture_notify;
|
|
|
|
actor_class->paint = mutter_shaped_texture_paint;
|
|
actor_class->pick = mutter_shaped_texture_pick;
|
|
|
|
x11_texture_class->update_area = mutter_shaped_texture_update_area;
|
|
|
|
g_type_class_add_private (klass, sizeof (MutterShapedTexturePrivate));
|
|
}
|
|
|
|
static void
|
|
mutter_shaped_texture_init (MutterShapedTexture *self)
|
|
{
|
|
MutterShapedTexturePrivate *priv;
|
|
|
|
priv = self->priv = MUTTER_SHAPED_TEXTURE_GET_PRIVATE (self);
|
|
|
|
priv->rectangles = g_array_new (FALSE, FALSE, sizeof (XRectangle));
|
|
|
|
priv->paint_tower = mutter_texture_tower_new ();
|
|
priv->mask_texture = COGL_INVALID_HANDLE;
|
|
}
|
|
|
|
static void
|
|
mutter_shaped_texture_dispose (GObject *object)
|
|
{
|
|
MutterShapedTexture *self = (MutterShapedTexture *) object;
|
|
MutterShapedTexturePrivate *priv = self->priv;
|
|
|
|
if (priv->paint_tower)
|
|
mutter_texture_tower_free (priv->paint_tower);
|
|
priv->paint_tower = NULL;
|
|
|
|
mutter_shaped_texture_dirty_mask (self);
|
|
|
|
if (priv->material != COGL_INVALID_HANDLE)
|
|
{
|
|
cogl_material_unref (priv->material);
|
|
priv->material = COGL_INVALID_HANDLE;
|
|
}
|
|
if (priv->material_unshaped != COGL_INVALID_HANDLE)
|
|
{
|
|
cogl_material_unref (priv->material_unshaped);
|
|
priv->material_unshaped = COGL_INVALID_HANDLE;
|
|
}
|
|
#if 1 /* see comment in mutter_shaped_texture_paint */
|
|
if (priv->material_workaround != COGL_INVALID_HANDLE)
|
|
{
|
|
cogl_material_unref (priv->material_workaround);
|
|
priv->material_workaround = COGL_INVALID_HANDLE;
|
|
}
|
|
#endif
|
|
|
|
mutter_shaped_texture_set_clip_region (self, NULL);
|
|
|
|
G_OBJECT_CLASS (mutter_shaped_texture_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
mutter_shaped_texture_finalize (GObject *object)
|
|
{
|
|
MutterShapedTexture *self = (MutterShapedTexture *) object;
|
|
MutterShapedTexturePrivate *priv = self->priv;
|
|
|
|
g_array_free (priv->rectangles, TRUE);
|
|
|
|
G_OBJECT_CLASS (mutter_shaped_texture_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
mutter_shaped_texture_notify (GObject *object,
|
|
GParamSpec *pspec)
|
|
{
|
|
if (G_OBJECT_CLASS (mutter_shaped_texture_parent_class)->notify)
|
|
G_OBJECT_CLASS (mutter_shaped_texture_parent_class)->notify (object, pspec);
|
|
|
|
/* It seems like we could just do this out of update_area(), but unfortunately,
|
|
* clutter_glx_texture_pixmap() doesn't call through the vtable on the
|
|
* initial update_area, so we need to look for changes to the texture
|
|
* explicitly.
|
|
*/
|
|
if (strcmp (pspec->name, "cogl-texture") == 0)
|
|
{
|
|
MutterShapedTexture *stex = (MutterShapedTexture *) object;
|
|
MutterShapedTexturePrivate *priv = stex->priv;
|
|
|
|
mutter_texture_tower_set_base_texture (priv->paint_tower,
|
|
clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex)));
|
|
}
|
|
}
|
|
|
|
static void
|
|
mutter_shaped_texture_dirty_mask (MutterShapedTexture *stex)
|
|
{
|
|
MutterShapedTexturePrivate *priv = stex->priv;
|
|
|
|
if (priv->mask_texture != COGL_INVALID_HANDLE)
|
|
{
|
|
GLuint mask_gl_tex;
|
|
GLenum mask_gl_target;
|
|
|
|
cogl_texture_get_gl_texture (priv->mask_texture,
|
|
&mask_gl_tex, &mask_gl_target);
|
|
|
|
if (mask_gl_target == CGL_TEXTURE_RECTANGLE_ARB)
|
|
glDeleteTextures (1, &mask_gl_tex);
|
|
|
|
cogl_texture_unref (priv->mask_texture);
|
|
priv->mask_texture = COGL_INVALID_HANDLE;
|
|
}
|
|
}
|
|
|
|
static void
|
|
mutter_shaped_texture_ensure_mask (MutterShapedTexture *stex)
|
|
{
|
|
MutterShapedTexturePrivate *priv = stex->priv;
|
|
CoglHandle paint_tex;
|
|
guint tex_width, tex_height;
|
|
|
|
paint_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex));
|
|
|
|
if (paint_tex == COGL_INVALID_HANDLE)
|
|
return;
|
|
|
|
tex_width = cogl_texture_get_width (paint_tex);
|
|
tex_height = cogl_texture_get_height (paint_tex);
|
|
|
|
/* If the mask texture we have was created for a different size then
|
|
recreate it */
|
|
if (priv->mask_texture != COGL_INVALID_HANDLE
|
|
&& (priv->mask_width != tex_width || priv->mask_height != tex_height))
|
|
mutter_shaped_texture_dirty_mask (stex);
|
|
|
|
/* If we don't have a mask texture yet then create one */
|
|
if (priv->mask_texture == COGL_INVALID_HANDLE)
|
|
{
|
|
guchar *mask_data;
|
|
const XRectangle *rect;
|
|
GLenum paint_gl_target;
|
|
|
|
/* Create data for an empty image */
|
|
mask_data = g_malloc0 (tex_width * tex_height);
|
|
|
|
/* Cut out a hole for each rectangle */
|
|
for (rect = (XRectangle *) priv->rectangles->data
|
|
+ priv->rectangles->len;
|
|
rect-- > (XRectangle *) priv->rectangles->data;)
|
|
{
|
|
gint x1 = rect->x, x2 = x1 + rect->width;
|
|
gint y1 = rect->y, y2 = y1 + rect->height;
|
|
guchar *p;
|
|
|
|
/* Clip the rectangle to the size of the texture */
|
|
x1 = CLAMP (x1, 0, (gint) tex_width - 1);
|
|
x2 = CLAMP (x2, x1, (gint) tex_width);
|
|
y1 = CLAMP (y1, 0, (gint) tex_height - 1);
|
|
y2 = CLAMP (y2, y1, (gint) tex_height);
|
|
|
|
/* Fill the rectangle */
|
|
for (p = mask_data + y1 * tex_width + x1;
|
|
y1 < y2;
|
|
y1++, p += tex_width)
|
|
memset (p, 255, x2 - x1);
|
|
}
|
|
|
|
cogl_texture_get_gl_texture (paint_tex, NULL, &paint_gl_target);
|
|
|
|
if (paint_gl_target == CGL_TEXTURE_RECTANGLE_ARB)
|
|
{
|
|
GLuint tex;
|
|
|
|
glGenTextures (1, &tex);
|
|
glBindTexture (CGL_TEXTURE_RECTANGLE_ARB, tex);
|
|
glPixelStorei (GL_UNPACK_ROW_LENGTH, tex_width);
|
|
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
|
|
glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
|
|
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
|
|
glTexImage2D (CGL_TEXTURE_RECTANGLE_ARB, 0,
|
|
GL_ALPHA, tex_width, tex_height,
|
|
0, GL_ALPHA, GL_UNSIGNED_BYTE, mask_data);
|
|
|
|
priv->mask_texture
|
|
= cogl_texture_new_from_foreign (tex,
|
|
CGL_TEXTURE_RECTANGLE_ARB,
|
|
tex_width, tex_height,
|
|
0, 0,
|
|
COGL_PIXEL_FORMAT_A_8);
|
|
}
|
|
else
|
|
priv->mask_texture = cogl_texture_new_from_data (tex_width, tex_height,
|
|
COGL_TEXTURE_NONE,
|
|
COGL_PIXEL_FORMAT_A_8,
|
|
COGL_PIXEL_FORMAT_ANY,
|
|
tex_width,
|
|
mask_data);
|
|
|
|
g_free (mask_data);
|
|
|
|
priv->mask_width = tex_width;
|
|
priv->mask_height = tex_height;
|
|
}
|
|
}
|
|
|
|
static void
|
|
mutter_shaped_texture_paint (ClutterActor *actor)
|
|
{
|
|
MutterShapedTexture *stex = (MutterShapedTexture *) actor;
|
|
MutterShapedTexturePrivate *priv = stex->priv;
|
|
CoglHandle paint_tex;
|
|
guint tex_width, tex_height;
|
|
ClutterActorBox alloc;
|
|
CoglHandle material;
|
|
#if 1 /* please see comment below about workaround */
|
|
guint depth;
|
|
#endif
|
|
|
|
if (priv->clip_region && gdk_region_empty (priv->clip_region))
|
|
return;
|
|
|
|
if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
|
|
clutter_actor_realize (CLUTTER_ACTOR (stex));
|
|
|
|
/* If mipmaps are supported, then the texture filter quality will
|
|
* still be HIGH here. In that case we just want to use the base
|
|
* texture. If mipmaps are not support then
|
|
* on_glx_texture_pixmap_pre_paint() will have reset the texture
|
|
* filter quality to MEDIUM, and we should use the MutterTextureTower
|
|
* mipmap emulation.
|
|
*
|
|
* http://bugzilla.openedhand.com/show_bug.cgi?id=1877 is an RFE
|
|
* for a better way of handling this.
|
|
*
|
|
* While it would be nice to have direct access to the 'can_mipmap'
|
|
* boolean in ClutterGLXTexturePixmap, since since MutterTextureTower
|
|
* creates the scaled down images on demand there is no substantial
|
|
* overhead from doing the work to create and update the tower and
|
|
* not using it, other than the memory allocated for the MutterTextureTower
|
|
* structure itself.
|
|
*/
|
|
if (clutter_texture_get_filter_quality (CLUTTER_TEXTURE (stex)) == CLUTTER_TEXTURE_QUALITY_HIGH)
|
|
paint_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex));
|
|
else
|
|
paint_tex = mutter_texture_tower_get_paint_texture (priv->paint_tower);
|
|
|
|
if (paint_tex == COGL_INVALID_HANDLE)
|
|
return;
|
|
|
|
tex_width = cogl_texture_get_width (paint_tex);
|
|
tex_height = cogl_texture_get_height (paint_tex);
|
|
|
|
if (tex_width == 0 || tex_height == 0) /* no contents yet */
|
|
return;
|
|
|
|
if (priv->rectangles->len < 1)
|
|
{
|
|
/* If there are no rectangles use a single-layer texture */
|
|
|
|
if (priv->material_unshaped == COGL_INVALID_HANDLE)
|
|
priv->material_unshaped = cogl_material_new ();
|
|
|
|
material = priv->material_unshaped;
|
|
}
|
|
else
|
|
{
|
|
mutter_shaped_texture_ensure_mask (stex);
|
|
|
|
if (priv->material == COGL_INVALID_HANDLE)
|
|
{
|
|
priv->material = cogl_material_new ();
|
|
|
|
cogl_material_set_layer_combine (priv->material, 1,
|
|
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
|
|
NULL);
|
|
}
|
|
material = priv->material;
|
|
|
|
#if 1
|
|
/* This was added as a workaround. It seems that with the intel
|
|
* drivers when multi-texturing using an RGB TFP texture, the
|
|
* texture is actually setup internally as an RGBA texture, where
|
|
* the alpha channel is mostly 0.0 so you only see a shimmer of the
|
|
* window. This workaround forcibly defines the alpha channel as
|
|
* 1.0. Maybe there is some clutter/cogl state that is interacting
|
|
* with this that is being overlooked, but for now this seems to
|
|
* work. */
|
|
g_object_get (stex, "pixmap-depth", &depth, NULL);
|
|
if (depth == 24)
|
|
{
|
|
if (priv->material_workaround == COGL_INVALID_HANDLE)
|
|
{
|
|
material = priv->material_workaround = cogl_material_new ();
|
|
|
|
cogl_material_set_layer_combine (material, 0,
|
|
"RGB = MODULATE (TEXTURE, PREVIOUS)"
|
|
"A = REPLACE (PREVIOUS)",
|
|
NULL);
|
|
cogl_material_set_layer_combine (material, 1,
|
|
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
|
|
NULL);
|
|
}
|
|
|
|
material = priv->material_workaround;
|
|
}
|
|
#endif
|
|
|
|
cogl_material_set_layer (material, 1, priv->mask_texture);
|
|
}
|
|
|
|
cogl_material_set_layer (material, 0, paint_tex);
|
|
|
|
{
|
|
CoglColor color;
|
|
guchar opacity = clutter_actor_get_paint_opacity (actor);
|
|
cogl_color_set_from_4ub (&color, opacity, opacity, opacity, opacity);
|
|
cogl_material_set_color (material, &color);
|
|
}
|
|
|
|
cogl_set_source (material);
|
|
|
|
clutter_actor_get_allocation_box (actor, &alloc);
|
|
|
|
if (priv->clip_region)
|
|
{
|
|
GdkRectangle *rects;
|
|
int n_rects;
|
|
int i;
|
|
|
|
/* Limit to how many separate rectangles we'll draw; beyond this just
|
|
* fall back and draw the whole thing */
|
|
# define MAX_RECTS 16
|
|
|
|
/* Would be nice to be able to check the number of rects first */
|
|
gdk_region_get_rectangles (priv->clip_region, &rects, &n_rects);
|
|
if (n_rects > MAX_RECTS)
|
|
{
|
|
g_free (rects);
|
|
/* Fall through to following code */
|
|
}
|
|
else
|
|
{
|
|
float coords[MAX_RECTS * 8];
|
|
for (i = 0; i < n_rects; i++)
|
|
{
|
|
GdkRectangle *rect = &rects[i];
|
|
|
|
coords[i * 8 + 0] = rect->x;
|
|
coords[i * 8 + 1] = rect->y;
|
|
coords[i * 8 + 2] = rect->x + rect->width;
|
|
coords[i * 8 + 3] = rect->y + rect->height;
|
|
coords[i * 8 + 4] = rect->x / (alloc.x2 - alloc.x1);
|
|
coords[i * 8 + 5] = rect->y / (alloc.y2 - alloc.y1);
|
|
coords[i * 8 + 6] = (rect->x + rect->width) / (alloc.x2 - alloc.x1);
|
|
coords[i * 8 + 7] = (rect->y + rect->height) / (alloc.y2 - alloc.y1);
|
|
}
|
|
|
|
g_free (rects);
|
|
|
|
cogl_rectangles_with_texture_coords (coords, n_rects);
|
|
return;
|
|
}
|
|
}
|
|
|
|
cogl_rectangle (0, 0,
|
|
alloc.x2 - alloc.x1,
|
|
alloc.y2 - alloc.y1);
|
|
}
|
|
|
|
static void
|
|
mutter_shaped_texture_pick (ClutterActor *actor,
|
|
const ClutterColor *color)
|
|
{
|
|
MutterShapedTexture *stex = (MutterShapedTexture *) actor;
|
|
MutterShapedTexturePrivate *priv = stex->priv;
|
|
|
|
/* If there are no rectangles then use the regular pick */
|
|
if (priv->rectangles->len < 1)
|
|
CLUTTER_ACTOR_CLASS (mutter_shaped_texture_parent_class)
|
|
->pick (actor, color);
|
|
else if (clutter_actor_should_pick_paint (actor))
|
|
{
|
|
CoglHandle paint_tex;
|
|
ClutterActorBox alloc;
|
|
guint tex_width, tex_height;
|
|
|
|
paint_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex));
|
|
|
|
if (paint_tex == COGL_INVALID_HANDLE)
|
|
return;
|
|
|
|
tex_width = cogl_texture_get_width (paint_tex);
|
|
tex_height = cogl_texture_get_height (paint_tex);
|
|
|
|
if (tex_width == 0 || tex_height == 0) /* no contents yet */
|
|
return;
|
|
|
|
mutter_shaped_texture_ensure_mask (stex);
|
|
|
|
cogl_set_source_color4ub (color->red, color->green, color->blue,
|
|
color->alpha);
|
|
|
|
clutter_actor_get_allocation_box (actor, &alloc);
|
|
|
|
/* Paint the mask rectangle in the given color */
|
|
cogl_set_source_texture (priv->mask_texture);
|
|
cogl_rectangle_with_texture_coords (0, 0,
|
|
alloc.x2 - alloc.x1,
|
|
alloc.y2 - alloc.y1,
|
|
0, 0, 1, 1);
|
|
}
|
|
}
|
|
|
|
static void
|
|
mutter_shaped_texture_update_area (ClutterX11TexturePixmap *texture,
|
|
int x,
|
|
int y,
|
|
int width,
|
|
int height)
|
|
{
|
|
MutterShapedTexture *stex = (MutterShapedTexture *) texture;
|
|
MutterShapedTexturePrivate *priv = stex->priv;
|
|
|
|
CLUTTER_X11_TEXTURE_PIXMAP_CLASS (mutter_shaped_texture_parent_class)->update_area (texture,
|
|
x, y, width, height);
|
|
|
|
mutter_texture_tower_update_area (priv->paint_tower, x, y, width, height);
|
|
}
|
|
|
|
ClutterActor *
|
|
mutter_shaped_texture_new (void)
|
|
{
|
|
ClutterActor *self = g_object_new (MUTTER_TYPE_SHAPED_TEXTURE, NULL);
|
|
|
|
return self;
|
|
}
|
|
|
|
void
|
|
mutter_shaped_texture_clear_rectangles (MutterShapedTexture *stex)
|
|
{
|
|
MutterShapedTexturePrivate *priv;
|
|
|
|
g_return_if_fail (MUTTER_IS_SHAPED_TEXTURE (stex));
|
|
|
|
priv = stex->priv;
|
|
|
|
g_array_set_size (priv->rectangles, 0);
|
|
mutter_shaped_texture_dirty_mask (stex);
|
|
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
|
|
}
|
|
|
|
void
|
|
mutter_shaped_texture_add_rectangle (MutterShapedTexture *stex,
|
|
const XRectangle *rect)
|
|
{
|
|
g_return_if_fail (MUTTER_IS_SHAPED_TEXTURE (stex));
|
|
|
|
mutter_shaped_texture_add_rectangles (stex, 1, rect);
|
|
}
|
|
|
|
void
|
|
mutter_shaped_texture_add_rectangles (MutterShapedTexture *stex,
|
|
size_t num_rects,
|
|
const XRectangle *rects)
|
|
{
|
|
MutterShapedTexturePrivate *priv;
|
|
|
|
g_return_if_fail (MUTTER_IS_SHAPED_TEXTURE (stex));
|
|
|
|
priv = stex->priv;
|
|
|
|
g_array_append_vals (priv->rectangles, rects, num_rects);
|
|
|
|
mutter_shaped_texture_dirty_mask (stex);
|
|
clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
|
|
}
|
|
|
|
/**
|
|
* mutter_shaped_texture_set_clip_region:
|
|
* @frame: a #TidyTextureframe
|
|
* @clip_region: (transfer full): the region of the texture that
|
|
* is visible and should be painted. OWNERSHIP IS ASSUMED BY
|
|
* THE FUNCTION (for efficiency to avoid a copy.)
|
|
*
|
|
* Provides a hint to the texture about what areas of the texture
|
|
* are not completely obscured and thus need to be painted. This
|
|
* is an optimization and is not supposed to have any effect on
|
|
* the output.
|
|
*
|
|
* Typically a parent container will set the clip region before
|
|
* painting its children, and then unset it afterwards.
|
|
*/
|
|
void
|
|
mutter_shaped_texture_set_clip_region (MutterShapedTexture *stex,
|
|
GdkRegion *clip_region)
|
|
{
|
|
MutterShapedTexturePrivate *priv;
|
|
|
|
g_return_if_fail (MUTTER_IS_SHAPED_TEXTURE (stex));
|
|
|
|
priv = stex->priv;
|
|
|
|
if (priv->clip_region)
|
|
{
|
|
gdk_region_destroy (priv->clip_region);
|
|
priv->clip_region = NULL;
|
|
}
|
|
|
|
priv->clip_region = clip_region;
|
|
}
|