1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
4
* SECTION:meta-surface-actor
5
* @title: MetaSurfaceActor
6
* @short_description: An actor representing a surface in the scene graph
8
* A surface can be either a shaped texture, or a group of shaped texture,
9
* used to draw the content of a window.
14
#include "meta-surface-actor.h"
16
#include <clutter/clutter.h>
17
#include <meta/meta-shaped-texture.h>
18
#include "meta-cullable.h"
19
#include "meta-shaped-texture-private.h"
21
struct _MetaSurfaceActorPrivate
23
MetaShapedTexture *texture;
25
cairo_region_t *input_region;
27
/* Freeze/thaw accounting */
28
cairo_region_t *pending_damage;
32
static void cullable_iface_init (MetaCullableInterface *iface);
34
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaSurfaceActor, meta_surface_actor, CLUTTER_TYPE_ACTOR,
35
G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init));
44
static guint signals[LAST_SIGNAL];
47
meta_surface_actor_pick (ClutterActor *actor,
48
const ClutterColor *color)
50
MetaSurfaceActor *self = META_SURFACE_ACTOR (actor);
51
MetaSurfaceActorPrivate *priv = self->priv;
52
ClutterActorIter iter;
55
if (!clutter_actor_should_pick_paint (actor))
58
/* If there is no region then use the regular pick */
59
if (priv->input_region == NULL)
60
CLUTTER_ACTOR_CLASS (meta_surface_actor_parent_class)->pick (actor, color);
66
CoglPipeline *pipeline;
71
n_rects = cairo_region_num_rectangles (priv->input_region);
72
rectangles = g_alloca (sizeof (float) * 4 * n_rects);
74
for (i = 0; i < n_rects; i++)
76
cairo_rectangle_int_t rect;
79
cairo_region_get_rectangle (priv->input_region, i, &rect);
81
rectangles[pos + 0] = rect.x;
82
rectangles[pos + 1] = rect.y;
83
rectangles[pos + 2] = rect.x + rect.width;
84
rectangles[pos + 3] = rect.y + rect.height;
87
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
88
fb = cogl_get_draw_framebuffer ();
90
cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha);
92
pipeline = cogl_pipeline_new (ctx);
93
cogl_pipeline_set_color (pipeline, &cogl_color);
94
cogl_framebuffer_draw_rectangles (fb, pipeline, rectangles, n_rects);
95
cogl_object_unref (pipeline);
98
clutter_actor_iter_init (&iter, actor);
100
while (clutter_actor_iter_next (&iter, &child))
101
clutter_actor_paint (child);
105
meta_surface_actor_dispose (GObject *object)
107
MetaSurfaceActor *self = META_SURFACE_ACTOR (object);
108
MetaSurfaceActorPrivate *priv = self->priv;
110
g_clear_pointer (&priv->input_region, cairo_region_destroy);
112
G_OBJECT_CLASS (meta_surface_actor_parent_class)->dispose (object);
116
meta_surface_actor_class_init (MetaSurfaceActorClass *klass)
118
GObjectClass *object_class = G_OBJECT_CLASS (klass);
119
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
121
object_class->dispose = meta_surface_actor_dispose;
122
actor_class->pick = meta_surface_actor_pick;
124
signals[REPAINT_SCHEDULED] = g_signal_new ("repaint-scheduled",
125
G_TYPE_FROM_CLASS (object_class),
131
signals[SIZE_CHANGED] = g_signal_new ("size-changed",
132
G_TYPE_FROM_CLASS (object_class),
138
g_type_class_add_private (klass, sizeof (MetaSurfaceActorPrivate));
142
meta_surface_actor_cull_out (MetaCullable *cullable,
143
cairo_region_t *unobscured_region,
144
cairo_region_t *clip_region)
146
meta_cullable_cull_out_children (cullable, unobscured_region, clip_region);
150
meta_surface_actor_reset_culling (MetaCullable *cullable)
152
meta_cullable_reset_culling_children (cullable);
156
cullable_iface_init (MetaCullableInterface *iface)
158
iface->cull_out = meta_surface_actor_cull_out;
159
iface->reset_culling = meta_surface_actor_reset_culling;
163
texture_size_changed (MetaShapedTexture *texture,
166
MetaSurfaceActor *actor = META_SURFACE_ACTOR (user_data);
167
g_signal_emit (actor, signals[SIZE_CHANGED], 0);
171
meta_surface_actor_init (MetaSurfaceActor *self)
173
MetaSurfaceActorPrivate *priv;
175
priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
176
META_TYPE_SURFACE_ACTOR,
177
MetaSurfaceActorPrivate);
179
priv->texture = META_SHAPED_TEXTURE (meta_shaped_texture_new ());
180
g_signal_connect_object (priv->texture, "size-changed",
181
G_CALLBACK (texture_size_changed), self, 0);
182
clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (priv->texture));
186
meta_surface_actor_get_image (MetaSurfaceActor *self,
187
cairo_rectangle_int_t *clip)
189
return meta_shaped_texture_get_image (self->priv->texture, clip);
193
meta_surface_actor_get_texture (MetaSurfaceActor *self)
195
return self->priv->texture;
199
meta_surface_actor_update_area (MetaSurfaceActor *self,
200
int x, int y, int width, int height)
202
MetaSurfaceActorPrivate *priv = self->priv;
204
if (meta_shaped_texture_update_area (priv->texture, x, y, width, height))
205
g_signal_emit (self, signals[REPAINT_SCHEDULED], 0);
209
meta_surface_actor_is_obscured (MetaSurfaceActor *self)
211
MetaSurfaceActorPrivate *priv = self->priv;
212
return meta_shaped_texture_is_obscured (priv->texture);
216
meta_surface_actor_set_input_region (MetaSurfaceActor *self,
217
cairo_region_t *region)
219
MetaSurfaceActorPrivate *priv = self->priv;
221
if (priv->input_region)
222
cairo_region_destroy (priv->input_region);
225
priv->input_region = cairo_region_reference (region);
227
priv->input_region = NULL;
231
meta_surface_actor_set_opaque_region (MetaSurfaceActor *self,
232
cairo_region_t *region)
234
MetaSurfaceActorPrivate *priv = self->priv;
235
meta_shaped_texture_set_opaque_region (priv->texture, region);
239
meta_surface_actor_get_opaque_region (MetaSurfaceActor *actor)
241
MetaSurfaceActorPrivate *priv = actor->priv;
242
return meta_shaped_texture_get_opaque_region (priv->texture);
246
is_frozen (MetaSurfaceActor *self)
248
MetaSurfaceActorPrivate *priv = self->priv;
253
meta_surface_actor_process_damage (MetaSurfaceActor *self,
254
int x, int y, int width, int height)
256
MetaSurfaceActorPrivate *priv = self->priv;
258
if (is_frozen (self))
260
/* The window is frozen due to an effect in progress: we ignore damage
261
* here on the off chance that this will stop the corresponding
262
* texture_from_pixmap from being update.
264
* pending_damage tracks any damage that happened while the window was
265
* frozen so that when can apply it when the window becomes unfrozen.
267
* It should be noted that this is an unreliable mechanism since it's
268
* quite likely that drivers will aim to provide a zero-copy
269
* implementation of the texture_from_pixmap extension and in those cases
270
* any drawing done to the window is always immediately reflected in the
271
* texture regardless of damage event handling.
273
cairo_rectangle_int_t rect = { .x = x, .y = y, .width = width, .height = height };
275
if (!priv->pending_damage)
276
priv->pending_damage = cairo_region_create_rectangle (&rect);
278
cairo_region_union_rectangle (priv->pending_damage, &rect);
282
META_SURFACE_ACTOR_GET_CLASS (self)->process_damage (self, x, y, width, height);
284
if (meta_surface_actor_is_visible (self))
285
meta_surface_actor_update_area (self, x, y, width, height);
289
meta_surface_actor_pre_paint (MetaSurfaceActor *self)
291
META_SURFACE_ACTOR_GET_CLASS (self)->pre_paint (self);
295
meta_surface_actor_is_argb32 (MetaSurfaceActor *self)
297
MetaShapedTexture *stex = meta_surface_actor_get_texture (self);
298
CoglTexture *texture = meta_shaped_texture_get_texture (stex);
300
/* If we don't have a texture, like during initialization, assume
303
* If we are unredirected and we have no texture assume that we are
304
* not ARGB32 otherwise we wouldn't be unredirected in the first
305
* place. This prevents us from continually redirecting and
306
* unredirecting on every paint.
309
return !meta_surface_actor_is_unredirected (self);
311
switch (cogl_texture_get_components (texture))
313
case COGL_TEXTURE_COMPONENTS_A:
314
case COGL_TEXTURE_COMPONENTS_RGBA:
316
case COGL_TEXTURE_COMPONENTS_RG:
317
case COGL_TEXTURE_COMPONENTS_RGB:
318
case COGL_TEXTURE_COMPONENTS_DEPTH:
321
g_assert_not_reached ();
326
meta_surface_actor_is_visible (MetaSurfaceActor *self)
328
return META_SURFACE_ACTOR_GET_CLASS (self)->is_visible (self);
332
meta_surface_actor_set_frozen (MetaSurfaceActor *self,
335
MetaSurfaceActorPrivate *priv = self->priv;
337
priv->frozen = frozen;
339
if (!frozen && priv->pending_damage)
341
int i, n_rects = cairo_region_num_rectangles (priv->pending_damage);
342
cairo_rectangle_int_t rect;
344
/* Since we ignore damage events while a window is frozen for certain effects
345
* we need to apply the tracked damage now. */
347
for (i = 0; i < n_rects; i++)
349
cairo_region_get_rectangle (priv->pending_damage, i, &rect);
350
meta_surface_actor_process_damage (self, rect.x, rect.y,
351
rect.width, rect.height);
353
g_clear_pointer (&priv->pending_damage, cairo_region_destroy);
358
meta_surface_actor_should_unredirect (MetaSurfaceActor *self)
360
return META_SURFACE_ACTOR_GET_CLASS (self)->should_unredirect (self);
364
meta_surface_actor_set_unredirected (MetaSurfaceActor *self,
365
gboolean unredirected)
367
META_SURFACE_ACTOR_GET_CLASS (self)->set_unredirected (self, unredirected);
371
meta_surface_actor_is_unredirected (MetaSurfaceActor *self)
373
return META_SURFACE_ACTOR_GET_CLASS (self)->is_unredirected (self);
377
meta_surface_actor_get_window (MetaSurfaceActor *self)
379
return META_SURFACE_ACTOR_GET_CLASS (self)->get_window (self);