~elementary-os/elementaryos/os-patch-mutter-bionic

« back to all changes in this revision

Viewing changes to src/compositor/meta-surface-actor.c

  • Committer: RabbitBot
  • Date: 2018-04-11 14:49:36 UTC
  • Revision ID: rabbitbot@elementary.io-20180411144936-hgymqa9d8d1xfpbh
Initial import, version 3.28.0-2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 
2
 
 
3
/**
 
4
 * SECTION:meta-surface-actor
 
5
 * @title: MetaSurfaceActor
 
6
 * @short_description: An actor representing a surface in the scene graph
 
7
 *
 
8
 * A surface can be either a shaped texture, or a group of shaped texture,
 
9
 * used to draw the content of a window.
 
10
 */
 
11
 
 
12
#include <config.h>
 
13
 
 
14
#include "meta-surface-actor.h"
 
15
 
 
16
#include <clutter/clutter.h>
 
17
#include <meta/meta-shaped-texture.h>
 
18
#include "meta-cullable.h"
 
19
#include "meta-shaped-texture-private.h"
 
20
 
 
21
struct _MetaSurfaceActorPrivate
 
22
{
 
23
  MetaShapedTexture *texture;
 
24
 
 
25
  cairo_region_t *input_region;
 
26
 
 
27
  /* Freeze/thaw accounting */
 
28
  cairo_region_t *pending_damage;
 
29
  guint frozen : 1;
 
30
};
 
31
 
 
32
static void cullable_iface_init (MetaCullableInterface *iface);
 
33
 
 
34
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaSurfaceActor, meta_surface_actor, CLUTTER_TYPE_ACTOR,
 
35
                                  G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init));
 
36
 
 
37
enum {
 
38
  REPAINT_SCHEDULED,
 
39
  SIZE_CHANGED,
 
40
 
 
41
  LAST_SIGNAL,
 
42
};
 
43
 
 
44
static guint signals[LAST_SIGNAL];
 
45
 
 
46
static void
 
47
meta_surface_actor_pick (ClutterActor       *actor,
 
48
                         const ClutterColor *color)
 
49
{
 
50
  MetaSurfaceActor *self = META_SURFACE_ACTOR (actor);
 
51
  MetaSurfaceActorPrivate *priv = self->priv;
 
52
  ClutterActorIter iter;
 
53
  ClutterActor *child;
 
54
 
 
55
  if (!clutter_actor_should_pick_paint (actor))
 
56
    return;
 
57
 
 
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);
 
61
  else
 
62
    {
 
63
      int n_rects;
 
64
      float *rectangles;
 
65
      int i;
 
66
      CoglPipeline *pipeline;
 
67
      CoglContext *ctx;
 
68
      CoglFramebuffer *fb;
 
69
      CoglColor cogl_color;
 
70
 
 
71
      n_rects = cairo_region_num_rectangles (priv->input_region);
 
72
      rectangles = g_alloca (sizeof (float) * 4 * n_rects);
 
73
 
 
74
      for (i = 0; i < n_rects; i++)
 
75
        {
 
76
          cairo_rectangle_int_t rect;
 
77
          int pos = i * 4;
 
78
 
 
79
          cairo_region_get_rectangle (priv->input_region, i, &rect);
 
80
 
 
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;
 
85
        }
 
86
 
 
87
      ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
 
88
      fb = cogl_get_draw_framebuffer ();
 
89
 
 
90
      cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha);
 
91
 
 
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);
 
96
    }
 
97
 
 
98
  clutter_actor_iter_init (&iter, actor);
 
99
 
 
100
  while (clutter_actor_iter_next (&iter, &child))
 
101
    clutter_actor_paint (child);
 
102
}
 
103
 
 
104
static void
 
105
meta_surface_actor_dispose (GObject *object)
 
106
{
 
107
  MetaSurfaceActor *self = META_SURFACE_ACTOR (object);
 
108
  MetaSurfaceActorPrivate *priv = self->priv;
 
109
 
 
110
  g_clear_pointer (&priv->input_region, cairo_region_destroy);
 
111
 
 
112
  G_OBJECT_CLASS (meta_surface_actor_parent_class)->dispose (object);
 
113
}
 
114
 
 
115
static void
 
116
meta_surface_actor_class_init (MetaSurfaceActorClass *klass)
 
117
{
 
118
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
119
  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
 
120
 
 
121
  object_class->dispose = meta_surface_actor_dispose;
 
122
  actor_class->pick = meta_surface_actor_pick;
 
123
 
 
124
  signals[REPAINT_SCHEDULED] = g_signal_new ("repaint-scheduled",
 
125
                                             G_TYPE_FROM_CLASS (object_class),
 
126
                                             G_SIGNAL_RUN_LAST,
 
127
                                             0,
 
128
                                             NULL, NULL, NULL,
 
129
                                             G_TYPE_NONE, 0);
 
130
 
 
131
  signals[SIZE_CHANGED] = g_signal_new ("size-changed",
 
132
                                        G_TYPE_FROM_CLASS (object_class),
 
133
                                        G_SIGNAL_RUN_LAST,
 
134
                                        0,
 
135
                                        NULL, NULL, NULL,
 
136
                                        G_TYPE_NONE, 0);
 
137
 
 
138
  g_type_class_add_private (klass, sizeof (MetaSurfaceActorPrivate));
 
139
}
 
140
 
 
141
static void
 
142
meta_surface_actor_cull_out (MetaCullable   *cullable,
 
143
                             cairo_region_t *unobscured_region,
 
144
                             cairo_region_t *clip_region)
 
145
{
 
146
  meta_cullable_cull_out_children (cullable, unobscured_region, clip_region);
 
147
}
 
148
 
 
149
static void
 
150
meta_surface_actor_reset_culling (MetaCullable *cullable)
 
151
{
 
152
  meta_cullable_reset_culling_children (cullable);
 
153
}
 
154
 
 
155
static void
 
156
cullable_iface_init (MetaCullableInterface *iface)
 
157
{
 
158
  iface->cull_out = meta_surface_actor_cull_out;
 
159
  iface->reset_culling = meta_surface_actor_reset_culling;
 
160
}
 
161
 
 
162
static void
 
163
texture_size_changed (MetaShapedTexture *texture,
 
164
                      gpointer           user_data)
 
165
{
 
166
  MetaSurfaceActor *actor = META_SURFACE_ACTOR (user_data);
 
167
  g_signal_emit (actor, signals[SIZE_CHANGED], 0);
 
168
}
 
169
 
 
170
static void
 
171
meta_surface_actor_init (MetaSurfaceActor *self)
 
172
{
 
173
  MetaSurfaceActorPrivate *priv;
 
174
 
 
175
  priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
 
176
                                                   META_TYPE_SURFACE_ACTOR,
 
177
                                                   MetaSurfaceActorPrivate);
 
178
 
 
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));
 
183
}
 
184
 
 
185
cairo_surface_t *
 
186
meta_surface_actor_get_image (MetaSurfaceActor      *self,
 
187
                              cairo_rectangle_int_t *clip)
 
188
{
 
189
  return meta_shaped_texture_get_image (self->priv->texture, clip);
 
190
}
 
191
 
 
192
MetaShapedTexture *
 
193
meta_surface_actor_get_texture (MetaSurfaceActor *self)
 
194
{
 
195
  return self->priv->texture;
 
196
}
 
197
 
 
198
static void
 
199
meta_surface_actor_update_area (MetaSurfaceActor *self,
 
200
                                int x, int y, int width, int height)
 
201
{
 
202
  MetaSurfaceActorPrivate *priv = self->priv;
 
203
 
 
204
  if (meta_shaped_texture_update_area (priv->texture, x, y, width, height))
 
205
    g_signal_emit (self, signals[REPAINT_SCHEDULED], 0);
 
206
}
 
207
 
 
208
gboolean
 
209
meta_surface_actor_is_obscured (MetaSurfaceActor *self)
 
210
{
 
211
  MetaSurfaceActorPrivate *priv = self->priv;
 
212
  return meta_shaped_texture_is_obscured (priv->texture);
 
213
}
 
214
 
 
215
void
 
216
meta_surface_actor_set_input_region (MetaSurfaceActor *self,
 
217
                                     cairo_region_t   *region)
 
218
{
 
219
  MetaSurfaceActorPrivate *priv = self->priv;
 
220
 
 
221
  if (priv->input_region)
 
222
    cairo_region_destroy (priv->input_region);
 
223
 
 
224
  if (region)
 
225
    priv->input_region = cairo_region_reference (region);
 
226
  else
 
227
    priv->input_region = NULL;
 
228
}
 
229
 
 
230
void
 
231
meta_surface_actor_set_opaque_region (MetaSurfaceActor *self,
 
232
                                      cairo_region_t   *region)
 
233
{
 
234
  MetaSurfaceActorPrivate *priv = self->priv;
 
235
  meta_shaped_texture_set_opaque_region (priv->texture, region);
 
236
}
 
237
 
 
238
cairo_region_t *
 
239
meta_surface_actor_get_opaque_region (MetaSurfaceActor *actor)
 
240
{
 
241
  MetaSurfaceActorPrivate *priv = actor->priv;
 
242
  return meta_shaped_texture_get_opaque_region (priv->texture);
 
243
}
 
244
 
 
245
static gboolean
 
246
is_frozen (MetaSurfaceActor *self)
 
247
{
 
248
  MetaSurfaceActorPrivate *priv = self->priv;
 
249
  return priv->frozen;
 
250
}
 
251
 
 
252
void
 
253
meta_surface_actor_process_damage (MetaSurfaceActor *self,
 
254
                                   int x, int y, int width, int height)
 
255
{
 
256
  MetaSurfaceActorPrivate *priv = self->priv;
 
257
 
 
258
  if (is_frozen (self))
 
259
    {
 
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.
 
263
       *
 
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.
 
266
       *
 
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.
 
272
       */
 
273
      cairo_rectangle_int_t rect = { .x = x, .y = y, .width = width, .height = height };
 
274
 
 
275
      if (!priv->pending_damage)
 
276
        priv->pending_damage = cairo_region_create_rectangle (&rect);
 
277
      else
 
278
        cairo_region_union_rectangle (priv->pending_damage, &rect);
 
279
      return;
 
280
    }
 
281
 
 
282
  META_SURFACE_ACTOR_GET_CLASS (self)->process_damage (self, x, y, width, height);
 
283
 
 
284
  if (meta_surface_actor_is_visible (self))
 
285
    meta_surface_actor_update_area (self, x, y, width, height);
 
286
}
 
287
 
 
288
void
 
289
meta_surface_actor_pre_paint (MetaSurfaceActor *self)
 
290
{
 
291
  META_SURFACE_ACTOR_GET_CLASS (self)->pre_paint (self);
 
292
}
 
293
 
 
294
gboolean
 
295
meta_surface_actor_is_argb32 (MetaSurfaceActor *self)
 
296
{
 
297
  MetaShapedTexture *stex = meta_surface_actor_get_texture (self);
 
298
  CoglTexture *texture = meta_shaped_texture_get_texture (stex);
 
299
 
 
300
  /* If we don't have a texture, like during initialization, assume
 
301
   * that we're ARGB32.
 
302
   *
 
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.
 
307
   */
 
308
  if (!texture)
 
309
    return !meta_surface_actor_is_unredirected (self);
 
310
 
 
311
  switch (cogl_texture_get_components (texture))
 
312
    {
 
313
    case COGL_TEXTURE_COMPONENTS_A:
 
314
    case COGL_TEXTURE_COMPONENTS_RGBA:
 
315
      return TRUE;
 
316
    case COGL_TEXTURE_COMPONENTS_RG:
 
317
    case COGL_TEXTURE_COMPONENTS_RGB:
 
318
    case COGL_TEXTURE_COMPONENTS_DEPTH:
 
319
      return FALSE;
 
320
    default:
 
321
      g_assert_not_reached ();
 
322
    }
 
323
}
 
324
 
 
325
gboolean
 
326
meta_surface_actor_is_visible (MetaSurfaceActor *self)
 
327
{
 
328
  return META_SURFACE_ACTOR_GET_CLASS (self)->is_visible (self);
 
329
}
 
330
 
 
331
void
 
332
meta_surface_actor_set_frozen (MetaSurfaceActor *self,
 
333
                               gboolean          frozen)
 
334
{
 
335
  MetaSurfaceActorPrivate *priv = self->priv;
 
336
 
 
337
  priv->frozen = frozen;
 
338
 
 
339
  if (!frozen && priv->pending_damage)
 
340
    {
 
341
      int i, n_rects = cairo_region_num_rectangles (priv->pending_damage);
 
342
      cairo_rectangle_int_t rect;
 
343
 
 
344
      /* Since we ignore damage events while a window is frozen for certain effects
 
345
       * we need to apply the tracked damage now. */
 
346
 
 
347
      for (i = 0; i < n_rects; i++)
 
348
        {
 
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);
 
352
        }
 
353
      g_clear_pointer (&priv->pending_damage, cairo_region_destroy);
 
354
    }
 
355
}
 
356
 
 
357
gboolean
 
358
meta_surface_actor_should_unredirect (MetaSurfaceActor *self)
 
359
{
 
360
  return META_SURFACE_ACTOR_GET_CLASS (self)->should_unredirect (self);
 
361
}
 
362
 
 
363
void
 
364
meta_surface_actor_set_unredirected (MetaSurfaceActor *self,
 
365
                                     gboolean          unredirected)
 
366
{
 
367
  META_SURFACE_ACTOR_GET_CLASS (self)->set_unredirected (self, unredirected);
 
368
}
 
369
 
 
370
gboolean
 
371
meta_surface_actor_is_unredirected (MetaSurfaceActor *self)
 
372
{
 
373
  return META_SURFACE_ACTOR_GET_CLASS (self)->is_unredirected (self);
 
374
}
 
375
 
 
376
MetaWindow *
 
377
meta_surface_actor_get_window (MetaSurfaceActor *self)
 
378
{
 
379
  return META_SURFACE_ACTOR_GET_CLASS (self)->get_window (self);
 
380
}