clutter-stage.c 140 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * Clutter.
 *
 * An OpenGL based 'interactive canvas' library.
 *
 * Authored By Matthew Allum  <mallum@openedhand.com>
 *
 * Copyright (C) 2006 OpenedHand
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
21
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
22 23
 */

24 25 26
/**
 * SECTION:clutter-stage
 * @short_description: Top level visual element to which actors are placed.
27
 *
28 29
 * #ClutterStage is a top level 'window' on which child actors are placed
 * and manipulated.
30 31 32 33 34 35 36 37 38 39 40 41 42
 *
 * Backends might provide support for multiple stages. The support for this
 * feature can be checked at run-time using the clutter_feature_available()
 * function and the %CLUTTER_FEATURE_STAGE_MULTIPLE flag. If the backend used
 * supports multiple stages, new #ClutterStage instances can be created
 * using clutter_stage_new(). These stages must be managed by the developer
 * using clutter_actor_destroy(), which will take care of destroying all the
 * actors contained inside them.
 *
 * #ClutterStage is a proxy actor, wrapping the backend-specific
 * implementation of the windowing system. It is possible to subclass
 * #ClutterStage, as long as every overridden virtual function chains up to
 * the parent class corresponding function.
43 44
 */

45
#ifdef HAVE_CONFIG_H
46
#include "clutter-build-config.h"
47
#endif
48

49
#include <math.h>
50
#include <cairo.h>
51

52
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
53
#define CLUTTER_ENABLE_EXPERIMENTAL_API
54

55
#include "clutter-stage.h"
56
#include "deprecated/clutter-stage.h"
57
#include "deprecated/clutter-container.h"
58

59
#include "clutter-actor-private.h"
60
#include "clutter-backend-private.h"
61
#include "clutter-cairo.h"
62
#include "clutter-color.h"
63 64 65 66
#include "clutter-container.h"
#include "clutter-debug.h"
#include "clutter-device-manager-private.h"
#include "clutter-enum-types.h"
67
#include "clutter-event-private.h"
68
#include "clutter-id-pool.h"
69
#include "clutter-main.h"
70
#include "clutter-marshal.h"
71
#include "clutter-master-clock.h"
72
#include "clutter-mutter.h"
73
#include "clutter-paint-volume-private.h"
74
#include "clutter-private.h"
75
#include "clutter-stage-manager-private.h"
76
#include "clutter-stage-private.h"
77
#include "clutter-version.h" 	/* For flavour */
78
#include "clutter-private.h"
79

80
#include "cogl/cogl.h"
81

82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
/* <private>
 * ClutterStageHint:
 * @CLUTTER_STAGE_NONE: No hint set
 * @CLUTTER_STAGE_NO_CLEAR_ON_PAINT: When this hint is set, the stage
 *   should not clear the viewport; this flag is useful when painting
 *   fully opaque actors covering the whole visible area of the stage,
 *   i.e. when no blending with the stage color happens over the whole
 *   stage viewport
 *
 * A series of hints that enable or disable behaviours on the stage
 */
typedef enum { /*< prefix=CLUTTER_STAGE >*/
  CLUTTER_STAGE_HINT_NONE = 0,

  CLUTTER_STAGE_NO_CLEAR_ON_PAINT = 1 << 0
} ClutterStageHint;

#define STAGE_NO_CLEAR_ON_PAINT(s)      ((((ClutterStage *) (s))->priv->stage_hints & CLUTTER_STAGE_NO_CLEAR_ON_PAINT) != 0)

101 102 103 104 105 106 107
struct _ClutterStageQueueRedrawEntry
{
  ClutterActor *actor;
  gboolean has_clip;
  ClutterPaintVolume clip;
};

108
struct _ClutterStagePrivate
109
{
110
  /* the stage implementation */
111
  ClutterStageWindow *impl;
112

113 114 115 116 117
  ClutterPerspective perspective;
  CoglMatrix projection;
  CoglMatrix inverse_projection;
  CoglMatrix view;
  float viewport[4];
118

119
  ClutterFog fog;
120

121 122
  gchar *title;
  ClutterActor *key_focused_actor;
123

124
  GQueue *event_queue;
125

126
  ClutterStageHint stage_hints;
127

128
  GArray *paint_volume_stack;
129

130
  ClutterPlane current_clip_planes[4];
131

132
  GList *pending_queue_redraws;
133

134
  CoglFramebuffer *active_framebuffer;
135

136 137
  gint sync_delay;

138 139 140
  GTimer *fps_timer;
  gint32 timer_n_frames;

141 142
  ClutterIDPool *pick_id_pool;

143 144 145 146
#ifdef CLUTTER_ENABLE_DEBUG
  gulong redraw_count;
#endif /* CLUTTER_ENABLE_DEBUG */

147 148
  ClutterStageState current_state;

149 150 151
  gpointer paint_data;
  GDestroyNotify paint_notify;

152
  guint relayout_pending       : 1;
153 154 155 156 157 158
  guint redraw_pending         : 1;
  guint is_fullscreen          : 1;
  guint is_cursor_visible      : 1;
  guint is_user_resizable      : 1;
  guint use_fog                : 1;
  guint throttle_motion_events : 1;
159
  guint use_alpha              : 1;
160
  guint min_size_changed       : 1;
161
  guint accept_focus           : 1;
162
  guint motion_events_enabled  : 1;
163
  guint has_custom_perspective : 1;
164 165 166 167 168
};

enum
{
  PROP_0,
169

170
  PROP_COLOR,
171
  PROP_FULLSCREEN_SET,
172
  PROP_OFFSCREEN,
173 174
  PROP_CURSOR_VISIBLE,
  PROP_PERSPECTIVE,
175
  PROP_TITLE,
176
  PROP_USER_RESIZABLE,
177
  PROP_USE_FOG,
178
  PROP_FOG,
179
  PROP_USE_ALPHA,
180
  PROP_KEY_FOCUS,
181 182
  PROP_NO_CLEAR_HINT,
  PROP_ACCEPT_FOCUS
183 184 185 186
};

enum
{
187 188 189 190
  FULLSCREEN,
  UNFULLSCREEN,
  ACTIVATE,
  DEACTIVATE,
191
  DELETE_EVENT,
192
  AFTER_PAINT,
193
  PRESENTED,
194

195 196 197
  LAST_SIGNAL
};

198
static guint stage_signals[LAST_SIGNAL] = { 0, };
199

200 201
static const ClutterColor default_stage_color = { 255, 255, 255, 255 };

202
static void clutter_stage_maybe_finish_queue_redraws (ClutterStage *stage);
203
static void free_queue_redraw_entry (ClutterStageQueueRedrawEntry *entry);
204

205 206 207 208 209 210 211
static void clutter_container_iface_init (ClutterContainerIface *iface);

G_DEFINE_TYPE_WITH_CODE (ClutterStage, clutter_stage, CLUTTER_TYPE_GROUP,
                         G_ADD_PRIVATE (ClutterStage)
                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
                                                clutter_container_iface_init))

212
static void
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
clutter_stage_real_add (ClutterContainer *container,
                        ClutterActor     *child)
{
  clutter_actor_add_child (CLUTTER_ACTOR (container), child);
}

static void
clutter_stage_real_remove (ClutterContainer *container,
                           ClutterActor     *child)
{
  clutter_actor_remove_child (CLUTTER_ACTOR (container), child);
}

static void
clutter_stage_real_foreach (ClutterContainer *container,
                            ClutterCallback   callback,
                            gpointer          user_data)
{
231 232
  ClutterActorIter iter;
  ClutterActor *child;
233

234
  clutter_actor_iter_init (&iter, CLUTTER_ACTOR (container));
235

236 237
  while (clutter_actor_iter_next (&iter, &child))
    callback (child, user_data);
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
}

static void
clutter_stage_real_raise (ClutterContainer *container,
                          ClutterActor     *child,
                          ClutterActor     *sibling)
{
  clutter_actor_set_child_above_sibling (CLUTTER_ACTOR (container),
                                         child,
                                         sibling);
}

static void
clutter_stage_real_lower (ClutterContainer *container,
                          ClutterActor     *child,
                          ClutterActor     *sibling)
{
  clutter_actor_set_child_below_sibling (CLUTTER_ACTOR (container),
                                         child,
                                         sibling);
}

static void
clutter_stage_real_sort_depth_order (ClutterContainer *container)
{
}

static void
clutter_container_iface_init (ClutterContainerIface *iface)
{
  iface->add = clutter_stage_real_add;
  iface->remove = clutter_stage_real_remove;
  iface->foreach = clutter_stage_real_foreach;
  iface->raise = clutter_stage_real_raise;
  iface->lower = clutter_stage_real_lower;
  iface->sort_depth_order = clutter_stage_real_sort_depth_order;
}
275

276
static void
277
clutter_stage_get_preferred_width (ClutterActor *self,
278 279 280
                                   gfloat        for_height,
                                   gfloat       *min_width_p,
                                   gfloat       *natural_width_p)
281 282
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
283
  cairo_rectangle_int_t geom;
284

285 286
  if (priv->impl == NULL)
    return;
287

288 289 290 291 292 293 294
  _clutter_stage_window_get_geometry (priv->impl, &geom);

  if (min_width_p)
    *min_width_p = geom.width;

  if (natural_width_p)
    *natural_width_p = geom.width;
295 296 297
}

static void
298
clutter_stage_get_preferred_height (ClutterActor *self,
299 300 301
                                    gfloat        for_width,
                                    gfloat       *min_height_p,
                                    gfloat       *natural_height_p)
302 303
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
304
  cairo_rectangle_int_t geom;
305

306 307
  if (priv->impl == NULL)
    return;
308

309 310 311 312 313 314 315
  _clutter_stage_window_get_geometry (priv->impl, &geom);

  if (min_height_p)
    *min_height_p = geom.height;

  if (natural_height_p)
    *natural_height_p = geom.height;
316
}
317

318
static inline void
319 320 321 322
queue_full_redraw (ClutterStage *stage)
{
  ClutterStageWindow *stage_window;

323 324 325
  if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
    return;

326 327 328 329 330 331 332
  clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));

  /* Just calling clutter_actor_queue_redraw will typically only
   * redraw the bounding box of the children parented on the stage but
   * in this case we really need to ensure that the full stage is
   * redrawn so we add a NULL redraw clip to the stage window. */
  stage_window = _clutter_stage_get_window (stage);
333 334 335
  if (stage_window == NULL)
    return;

336 337 338
  _clutter_stage_window_add_redraw_clip (stage_window, NULL);
}

339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
static gboolean
stage_is_default (ClutterStage *stage)
{
  ClutterStageManager *stage_manager;
  ClutterStageWindow *impl;

  stage_manager = clutter_stage_manager_get_default ();
  if (stage != clutter_stage_manager_get_default_stage (stage_manager))
    return FALSE;

  impl = _clutter_stage_get_window (stage);
  if (impl != _clutter_stage_get_default_window ())
    return FALSE;

  return TRUE;
}

356
static void
357 358 359
clutter_stage_allocate (ClutterActor           *self,
                        const ClutterActorBox  *box,
                        ClutterAllocationFlags  flags)
360 361
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
362 363 364 365
  ClutterActorBox alloc = CLUTTER_ACTOR_BOX_INIT_ZERO;
  float old_width, old_height;
  float new_width, new_height;
  float width, height;
366
  cairo_rectangle_int_t window_size;
367
  int scale_factor;
368

369 370
  if (priv->impl == NULL)
    return;
371

372
  /* our old allocation */
373 374
  clutter_actor_get_allocation_box (self, &alloc);
  clutter_actor_box_get_size (&alloc, &old_width, &old_height);
375

376
  /* the current allocation */
377
  clutter_actor_box_get_size (box, &width, &height);
378

379 380 381 382
  /* the current Stage implementation size */
  _clutter_stage_window_get_geometry (priv->impl, &window_size);

  /* if the stage is fixed size (for instance, it's using a EGL framebuffer)
383
   * then we simply ignore any allocation request and override the
384 385
   * allocation chain - because we cannot forcibly change the size of the
   * stage window.
386
   */
387
  if (!clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
388
    {
389
      CLUTTER_NOTE (LAYOUT,
390
                    "Following allocation to %.2fx%.2f (absolute origin %s)",
391
                    width, height,
392 393 394
                    (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED)
                      ? "changed"
                      : "not changed");
395

396 397
      clutter_actor_set_allocation (self, box,
                                    flags | CLUTTER_DELEGATE_LAYOUT);
398

399
      /* Ensure the window is sized correctly */
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
      if (!priv->is_fullscreen)
        {
          if (priv->min_size_changed)
            {
              gfloat min_width, min_height;
              gboolean min_width_set, min_height_set;

              g_object_get (G_OBJECT (self),
                            "min-width", &min_width,
                            "min-width-set", &min_width_set,
                            "min-height", &min_height,
                            "min-height-set", &min_height_set,
                            NULL);

              if (!min_width_set)
                min_width = 1;
              if (!min_height_set)
                min_height = 1;

              if (width < min_width)
                width = min_width;
              if (height < min_height)
                height = min_height;

              priv->min_size_changed = FALSE;
            }

427 428
          if (window_size.width != CLUTTER_NEARBYINT (width) ||
              window_size.height != CLUTTER_NEARBYINT (height))
429
            {
430 431 432
              _clutter_stage_window_resize (priv->impl,
                                            CLUTTER_NEARBYINT (width),
                                            CLUTTER_NEARBYINT (height));
433
            }
434
        }
435
    }
436 437 438
  else
    {
      ClutterActorBox override = { 0, };
439

440
      /* override the passed allocation */
441 442
      override.x1 = 0;
      override.y1 = 0;
443 444
      override.x2 = window_size.width;
      override.y2 = window_size.height;
445

446
      CLUTTER_NOTE (LAYOUT,
447
                    "Overriding original allocation of %.2fx%.2f "
448
                    "with %.2fx%.2f (absolute origin %s)",
449
                    width, height,
450
                    override.x2, override.y2,
451 452 453
                    (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED)
                      ? "changed"
                      : "not changed");
454

455
      /* and store the overridden allocation */
456 457
      clutter_actor_set_allocation (self, &override,
                                    flags | CLUTTER_DELEGATE_LAYOUT);
458
    }
459

460 461 462 463
  /* XXX: Until Cogl becomes fully responsible for backend windows
   * Clutter need to manually keep it informed of the current window
   * size. We do this after the allocation above so that the stage
   * window has a chance to update the window size based on the
464 465 466
   * allocation.
   */
  _clutter_stage_window_get_geometry (priv->impl, &window_size);
467 468 469 470 471 472

  scale_factor = _clutter_stage_window_get_scale_factor (priv->impl);

  window_size.width *= scale_factor;
  window_size.height *= scale_factor;

473 474
  cogl_onscreen_clutter_backend_set_size (window_size.width,
                                          window_size.height);
475

476
  /* reset the viewport if the allocation effectively changed */
477 478 479 480 481
  clutter_actor_get_allocation_box (self, &alloc);
  clutter_actor_box_get_size (&alloc, &new_width, &new_height);

  if (CLUTTER_NEARBYINT (old_width) != CLUTTER_NEARBYINT (new_width) ||
      CLUTTER_NEARBYINT (old_height) != CLUTTER_NEARBYINT (new_height))
482
    {
483 484 485
      int real_width = CLUTTER_NEARBYINT (new_width);
      int real_height = CLUTTER_NEARBYINT (new_height);

486
      _clutter_stage_set_viewport (CLUTTER_STAGE (self),
487
                                   0, 0,
488 489
                                   real_width,
                                   real_height);
490

491 492
      /* Note: we don't assume that set_viewport will queue a full redraw
       * since it may bail-out early if something preemptively set the
493 494
       * viewport before the stage was really allocated its new size.
       */
495 496
      queue_full_redraw (CLUTTER_STAGE (self));
    }
497 498
}

499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
typedef struct _Vector4
{
  float x, y, z, w;
} Vector4;

static void
_cogl_util_get_eye_planes_for_screen_poly (float *polygon,
                                           int n_vertices,
                                           float *viewport,
                                           const CoglMatrix *projection,
                                           const CoglMatrix *inverse_project,
                                           ClutterPlane *planes)
{
  float Wc;
  Vector4 *tmp_poly;
  ClutterPlane *plane;
  int i;
Neil Roberts's avatar
Neil Roberts committed
516 517
  float b[3];
  float c[3];
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
  int count;

  tmp_poly = g_alloca (sizeof (Vector4) * n_vertices * 2);

#define DEPTH -50

  /* Determine W in clip-space (Wc) for a point (0, 0, DEPTH, 1)
   *
   * Note: the depth could be anything except 0.
   *
   * We will transform the polygon into clip coordinates using this
   * depth and then into eye coordinates. Our clip planes will be
   * defined by triangles that extend between points of the polygon at
   * DEPTH and corresponding points of the same polygon at DEPTH * 2.
   *
   * NB: Wc defines the position of the clip planes in clip
   * coordinates. Given a screen aligned cross section through the
   * frustum; coordinates range from [-Wc,Wc] left to right on the
   * x-axis and [Wc,-Wc] top to bottom on the y-axis.
   */
  Wc = DEPTH * projection->wz + projection->ww;

#define CLIP_X(X) ((((float)X - viewport[0]) * (2.0 / viewport[2])) - 1) * Wc
#define CLIP_Y(Y) ((((float)Y - viewport[1]) * (2.0 / viewport[3])) - 1) * -Wc

  for (i = 0; i < n_vertices; i++)
    {
      tmp_poly[i].x = CLIP_X (polygon[i * 2]);
      tmp_poly[i].y = CLIP_Y (polygon[i * 2 + 1]);
      tmp_poly[i].z = DEPTH;
      tmp_poly[i].w = Wc;
    }

  Wc = DEPTH * 2 * projection->wz + projection->ww;

  /* FIXME: technically we don't need to project all of the points
   * twice, it would be enough project every other point since
   * we can share points in this set to define the plane vectors. */
  for (i = 0; i < n_vertices; i++)
    {
      tmp_poly[n_vertices + i].x = CLIP_X (polygon[i * 2]);
      tmp_poly[n_vertices + i].y = CLIP_Y (polygon[i * 2 + 1]);
      tmp_poly[n_vertices + i].z = DEPTH * 2;
      tmp_poly[n_vertices + i].w = Wc;
    }

#undef CLIP_X
#undef CLIP_Y

  cogl_matrix_project_points (inverse_project,
                              4,
                              sizeof (Vector4),
                              tmp_poly,
                              sizeof (Vector4),
                              tmp_poly,
                              n_vertices * 2);

  /* XXX: It's quite ugly that we end up with these casts between
   * Vector4 types and CoglVector3s, it might be better if the
   * cogl_vector APIs just took pointers to floats.
   */

  count = n_vertices - 1;
  for (i = 0; i < count; i++)
    {
      plane = &planes[i];
Neil Roberts's avatar
Neil Roberts committed
584 585 586 587 588 589 590
      memcpy (plane->v0, tmp_poly + i, sizeof (float) * 3);
      memcpy (b, tmp_poly + n_vertices + i, sizeof (float) * 3);
      memcpy (c, tmp_poly + n_vertices + i + 1, sizeof (float) * 3);
      cogl_vector3_subtract (b, b, plane->v0);
      cogl_vector3_subtract (c, c, plane->v0);
      cogl_vector3_cross_product (plane->n, b, c);
      cogl_vector3_normalize (plane->n);
591 592 593
    }

  plane = &planes[n_vertices - 1];
Neil Roberts's avatar
Neil Roberts committed
594 595 596 597 598 599 600
  memcpy (plane->v0, tmp_poly + 0, sizeof (float) * 3);
  memcpy (b, tmp_poly + (2 * n_vertices - 1), sizeof (float) * 3);
  memcpy (c, tmp_poly + n_vertices, sizeof (float) * 3);
  cogl_vector3_subtract (b, b, plane->v0);
  cogl_vector3_subtract (c, c, plane->v0);
  cogl_vector3_cross_product (plane->n, b, c);
  cogl_vector3_normalize (plane->n);
601 602
}

603
static void
604 605
_clutter_stage_update_active_framebuffer (ClutterStage    *stage,
                                          CoglFramebuffer *framebuffer)
606 607 608 609 610 611 612 613
{
  ClutterStagePrivate *priv = stage->priv;

  /* We track the CoglFramebuffer that corresponds to the stage itself
   * so, for example, we can disable culling when rendering to an
   * offscreen framebuffer.
   */

614
  priv->active_framebuffer = framebuffer;
615 616
}

617
/* XXX: Instead of having a toplevel 2D clip region, it might be
618 619 620
 * better to have a clip volume within the view frustum. This could
 * allow us to avoid projecting actors into window coordinates to
 * be able to cull them.
621
 */
622 623 624 625
static void
clutter_stage_do_paint_view (ClutterStage                *stage,
                             ClutterStageView            *view,
                             const cairo_rectangle_int_t *clip)
626
{
627
  ClutterStagePrivate *priv = stage->priv;
628 629
  CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
  cairo_rectangle_int_t view_layout;
630
  float clip_poly[8];
631
  float viewport[4];
632
  cairo_rectangle_int_t geom;
633
  int window_scale;
634 635

  _clutter_stage_window_get_geometry (priv->impl, &geom);
636 637 638 639 640 641
  window_scale = _clutter_stage_window_get_scale_factor (priv->impl);

  viewport[0] = priv->viewport[0] * window_scale;
  viewport[1] = priv->viewport[1] * window_scale;
  viewport[2] = priv->viewport[2] * window_scale;
  viewport[3] = priv->viewport[3] * window_scale;
642

643
  if (!clip)
644
    {
645 646
      clutter_stage_view_get_layout (view, &view_layout);
      clip = &view_layout;
647 648
    }

649 650 651 652 653 654 655 656 657 658 659 660 661 662
  clip_poly[0] = MAX (clip->x * window_scale, 0);
  clip_poly[1] = MAX (clip->y * window_scale, 0);

  clip_poly[2] = MIN ((clip->x + clip->width) * window_scale,
                      geom.width * window_scale);
  clip_poly[3] = clip_poly[1];

  clip_poly[4] = clip_poly[2];
  clip_poly[5] = MIN ((clip->y + clip->height) * window_scale,
                      geom.height * window_scale);

  clip_poly[6] = clip_poly[0];
  clip_poly[7] = clip_poly[5];

663 664 665 666 667 668
  CLUTTER_NOTE (CLIPPING, "Setting stage clip too: "
                "x=%f, y=%f, width=%f, height=%f",
                clip_poly[0], clip_poly[1],
                clip_poly[2] - clip_poly[0],
                clip_poly[5] - clip_poly[1]);

669 670
  _cogl_util_get_eye_planes_for_screen_poly (clip_poly,
                                             4,
671
                                             viewport,
672 673 674 675
                                             &priv->projection,
                                             &priv->inverse_projection,
                                             priv->current_clip_planes);

676
  _clutter_stage_paint_volume_stack_free_all (stage);
677
  _clutter_stage_update_active_framebuffer (stage, framebuffer);
678
  clutter_actor_paint (CLUTTER_ACTOR (stage));
679
}
680

681 682 683 684 685 686 687 688 689 690 691 692 693 694
/* This provides a common point of entry for painting the scenegraph
 * for picking or painting...
 */
void
_clutter_stage_paint_view (ClutterStage                *stage,
                           ClutterStageView            *view,
                           const cairo_rectangle_int_t *clip)
{
  ClutterStagePrivate *priv = stage->priv;

  if (!priv->impl)
    return;

  clutter_stage_do_paint_view (stage, view, clip);
695
  g_signal_emit (stage, stage_signals[AFTER_PAINT], 0);
696 697
}

698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
/* If we don't implement this here, we get the paint function
 * from the deprecated clutter-group class, which doesn't
 * respect the Z order as it uses our empty sort_depth_order.
 */
static void
clutter_stage_paint (ClutterActor *self)
{
  ClutterActorIter iter;
  ClutterActor *child;

  clutter_actor_iter_init (&iter, self);
  while (clutter_actor_iter_next (&iter, &child))
    clutter_actor_paint (child);
}

713 714 715 716
static void
clutter_stage_pick (ClutterActor       *self,
		    const ClutterColor *color)
{
717
  ClutterActorIter iter;
718 719
  ClutterActor *child;

720 721 722
  /* Note: we don't chain up to our parent as we don't want any geometry
   * emitted for the stage itself. The stage's pick id is effectively handled
   * by the call to cogl_clear done in clutter-main.c:_clutter_do_pick_async()
723
   */
724 725 726
  clutter_actor_iter_init (&iter, self);
  while (clutter_actor_iter_next (&iter, &child))
    clutter_actor_paint (child);
727 728
}

729 730 731 732 733 734 735 736 737
static gboolean
clutter_stage_get_paint_volume (ClutterActor *self,
                                ClutterPaintVolume *volume)
{
  /* Returning False effectively means Clutter has to assume it covers
   * everything... */
  return FALSE;
}

738 739 740 741
static void
clutter_stage_realize (ClutterActor *self)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
742
  gboolean is_realized;
743

744
  g_assert (priv->impl != NULL);
745
  is_realized = _clutter_stage_window_realize (priv->impl);
746

747
  if (!is_realized)
748
    CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
749 750 751 752 753 754 755 756
}

static void
clutter_stage_unrealize (ClutterActor *self)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;

  /* and then unrealize the implementation */
757
  g_assert (priv->impl != NULL);
758 759 760
  _clutter_stage_window_unrealize (priv->impl);

  CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
761 762 763
}

static void
764
clutter_stage_show_all (ClutterActor *self)
765
{
766
  ClutterActorIter iter;
767 768
  ClutterActor *child;

769 770 771
  /* we don't do a recursive show_all(), to maintain the old
   * invariants from ClutterGroup
   */
772 773 774
  clutter_actor_iter_init (&iter, self);
  while (clutter_actor_iter_next (&iter, &child))
    clutter_actor_show (child);
775

776 777 778 779 780 781 782 783
  clutter_actor_show (self);
}

static void
clutter_stage_show (ClutterActor *self)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;

784 785
  CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->show (self);

786 787 788 789
  /* Possibly do an allocation run so that the stage will have the
     right size before we map it */
  _clutter_stage_maybe_relayout (self);

790
  g_assert (priv->impl != NULL);
791
  _clutter_stage_window_show (priv->impl, TRUE);
792 793 794
}

static void
795
clutter_stage_hide_all (ClutterActor *self)
796
{
797
  ClutterActorIter iter;
798
  ClutterActor *child;
799

800
  clutter_actor_hide (self);
801

802 803 804
  /* we don't do a recursive hide_all(), to maintain the old invariants
   * from ClutterGroup
   */
805 806
  clutter_actor_iter_init (&iter, self);
  while (clutter_actor_iter_next (&iter, &child))
807 808 809 810 811 812 813 814 815 816
    clutter_actor_hide (child);
}

static void
clutter_stage_hide (ClutterActor *self)
{
  ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;

  g_assert (priv->impl != NULL);
  _clutter_stage_window_hide (priv->impl);
817

818
  CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->hide (self);
819 820
}

821 822 823 824 825 826 827 828 829 830 831 832 833
static void
clutter_stage_emit_key_focus_event (ClutterStage *stage,
                                    gboolean      focus_in)
{
  ClutterStagePrivate *priv = stage->priv;

  if (priv->key_focused_actor == NULL)
    return;

  if (focus_in)
    g_signal_emit_by_name (priv->key_focused_actor, "key-focus-in");
  else
    g_signal_emit_by_name (priv->key_focused_actor, "key-focus-out");
834 835

  g_object_notify (G_OBJECT (stage), "key-focus");
836 837 838 839 840 841 842 843 844 845 846 847 848 849
}

static void
clutter_stage_real_activate (ClutterStage *stage)
{
  clutter_stage_emit_key_focus_event (stage, TRUE);
}

static void
clutter_stage_real_deactivate (ClutterStage *stage)
{
  clutter_stage_emit_key_focus_event (stage, FALSE);
}

850 851 852 853
static void
clutter_stage_real_fullscreen (ClutterStage *stage)
{
  ClutterStagePrivate *priv = stage->priv;
854
  cairo_rectangle_int_t geom;
855 856 857 858 859 860 861 862 863
  ClutterActorBox box;

  /* we need to force an allocation here because the size
   * of the stage might have been changed by the backend
   *
   * this is a really bad solution to the issues caused by
   * the fact that fullscreening the stage on the X11 backends
   * is really an asynchronous operation
   */
864
  _clutter_stage_window_get_geometry (priv->impl, &geom);
865 866 867

  box.x1 = 0;
  box.y1 = 0;
868 869
  box.x2 = geom.width;
  box.y2 = geom.height;
870

871 872 873 874 875 876 877 878
  /* we need to blow the caching on the Stage size, given that
   * we're about to force an allocation, because if anything
   * ends up querying the size of the stage during the allocate()
   * call, like constraints or signal handlers, we'll get into an
   * inconsistent state: the stage will report the old cached size,
   * but the allocation will be updated anyway.
   */
  clutter_actor_set_size (CLUTTER_ACTOR (stage), -1.0, -1.0);
879 880 881
  clutter_actor_allocate (CLUTTER_ACTOR (stage),
                          &box,
                          CLUTTER_ALLOCATION_NONE);
882 883
}

884 885
void
_clutter_stage_queue_event (ClutterStage *stage,
886 887
                            ClutterEvent *event,
                            gboolean      copy_event)
888
{
889
  ClutterStagePrivate *priv;
890
  gboolean first_event;
891
  ClutterInputDevice *device;
892

893
  g_return_if_fail (CLUTTER_IS_STAGE (stage));
894

895 896
  priv = stage->priv;

897 898
  first_event = priv->event_queue->length == 0;

899 900 901 902
  if (copy_event)
    event = clutter_event_copy (event);

  g_queue_push_tail (priv->event_queue, event);
903 904 905 906 907

  if (first_event)
    {
      ClutterMasterClock *master_clock = _clutter_master_clock_get_default ();
      _clutter_master_clock_start_running (master_clock);
908
      _clutter_stage_schedule_update (stage);
909
    }
910 911 912 913 914 915

  /* if needed, update the state of the input device of the event.
   * we do it here to avoid calling the same code from every backend
   * event processing function
   */
  device = clutter_event_get_device (event);
916 917 918
  if (device != NULL &&
      event->type != CLUTTER_PROXIMITY_IN &&
      event->type != CLUTTER_PROXIMITY_OUT)
919 920
    {
      ClutterModifierType event_state = clutter_event_get_state (event);
921
      ClutterEventSequence *sequence = clutter_event_get_event_sequence (event);
922 923 924 925 926
      guint32 event_time = clutter_event_get_time (event);
      gfloat event_x, event_y;

      clutter_event_get_coords (event, &event_x, &event_y);

927
      _clutter_input_device_set_coords (device, sequence, event_x, event_y, stage);
928 929 930
      _clutter_input_device_set_state (device, event_state);
      _clutter_input_device_set_time (device, event_time);
    }
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948
}

gboolean
_clutter_stage_has_queued_events (ClutterStage *stage)
{
  ClutterStagePrivate *priv;

  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);

  priv = stage->priv;

  return priv->event_queue->length > 0;
}

void
_clutter_stage_process_queued_events (ClutterStage *stage)
{
  ClutterStagePrivate *priv;
949
  GList *events, *l;
950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967

  g_return_if_fail (CLUTTER_IS_STAGE (stage));

  priv = stage->priv;

  if (priv->event_queue->length == 0)
    return;

  /* In case the stage gets destroyed during event processing */
  g_object_ref (stage);

  /* Steal events before starting processing to avoid reentrancy
   * issues */
  events = priv->event_queue->head;
  priv->event_queue->head =  NULL;
  priv->event_queue->tail = NULL;
  priv->event_queue->length = 0;

968
  for (l = events; l != NULL; l = l->next)
969 970 971
    {
      ClutterEvent *event;
      ClutterEvent *next_event;
972 973 974
      ClutterInputDevice *device;
      ClutterInputDevice *next_device;
      gboolean check_device = FALSE;
975 976 977 978

      event = l->data;
      next_event = l->next ? l->next->data : NULL;

979 980 981 982 983 984 985 986 987 988 989
      device = clutter_event_get_device (event);

      if (next_event != NULL)
        next_device = clutter_event_get_device (next_event);
      else
        next_device = NULL;

      if (device != NULL && next_device != NULL)
        check_device = TRUE;

      /* Skip consecutive motion events coming from the same device */
990 991 992 993 994 995 996 997 998 999 1000
      if (priv->throttle_motion_events && next_event != NULL)
        {
          if (event->type == CLUTTER_MOTION &&
              (next_event->type == CLUTTER_MOTION ||
               next_event->type == CLUTTER_LEAVE) &&
              (!check_device || (device == next_device)))
            {
              CLUTTER_NOTE (EVENT,
                            "Omitting motion event at %d, %d",
                            (int) event->motion.x,
                            (int) event->motion.y);
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010

              if (next_event->type == CLUTTER_MOTION)
                {
                  ClutterDeviceManager *device_manager =
                    clutter_device_manager_get_default ();

                  _clutter_device_manager_compress_motion (device_manager,
                                                           next_event, event);
                }

1011 1012 1013
              goto next_event;
            }
          else if (event->type == CLUTTER_TOUCH_UPDATE &&
1014 1015
                   next_event->type == CLUTTER_TOUCH_UPDATE &&
                   event->touch.sequence == next_event->touch.sequence &&
1016 1017 1018 1019 1020 1021 1022 1023 1024
                   (!check_device || (device == next_device)))
            {
              CLUTTER_NOTE (EVENT,
                            "Omitting touch update event at %d, %d",
                            (int) event->touch.x,
                            (int) event->touch.y);
              goto next_event;
            }
        }
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036

      _clutter_process_event (event);

    next_event:
      clutter_event_free (event);
    }

  g_list_free (events);

  g_object_unref (stage);
}

1037 1038 1039 1040 1041 1042
/**
 * _clutter_stage_needs_update:
 * @stage: A #ClutterStage
 *
 * Determines if _clutter_stage_do_update() needs to be called.
 *
1043
 * Return value: %TRUE if the stage need layout or painting
1044 1045 1046
 */
gboolean
_clutter_stage_needs_update (ClutterStage *stage)
1047
{
1048
  ClutterStagePrivate *priv;
1049

1050 1051 1052 1053
  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);

  priv = stage->priv;

1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
  return priv->relayout_pending || priv->redraw_pending;
}

void
_clutter_stage_maybe_relayout (ClutterActor *actor)
{
  ClutterStage *stage = CLUTTER_STAGE (actor);
  ClutterStagePrivate *priv = stage->priv;
  gfloat natural_width, natural_height;
  ClutterActorBox box = { 0, };

  if (!priv->relayout_pending)
    return;

  /* avoid reentrancy */
  if (!CLUTTER_ACTOR_IN_RELAYOUT (stage))
    {
1071 1072
      priv->relayout_pending = FALSE;

1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
      CLUTTER_NOTE (ACTOR, "Recomputing layout");

      CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_IN_RELAYOUT);

      natural_width = natural_height = 0;
      clutter_actor_get_preferred_size (CLUTTER_ACTOR (stage),
                                        NULL, NULL,
                                        &natural_width, &natural_height);

      box.x1 = 0;
      box.y1 = 0;
      box.x2 = natural_width;
      box.y2 = natural_height;

      CLUTTER_NOTE (ACTOR, "Allocating (0, 0 - %d, %d) for the stage",
                    (int) natural_width,
                    (int) natural_height);

      clutter_actor_allocate (CLUTTER_ACTOR (stage),
                              &box, CLUTTER_ALLOCATION_NONE);

      CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_IN_RELAYOUT);
    }
1096 1097
}

1098 1099 1100 1101 1102 1103
static void
clutter_stage_do_redraw (ClutterStage *stage)
{
  ClutterActor *actor = CLUTTER_ACTOR (stage);
  ClutterStagePrivate *priv = stage->priv;

1104 1105 1106 1107 1108 1109
  if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
    return;

  if (priv->impl == NULL)
    return;

1110 1111 1112
  CLUTTER_NOTE (PAINT, "Redraw started for stage '%s'[%p]",
                _clutter_actor_get_debug_name (actor),
                stage);
1113

1114
  if (_clutter_context_get_show_fps ())
1115 1116 1117 1118 1119
    {
      if (priv->fps_timer == NULL)
        priv->fps_timer = g_timer_new ();
    }

1120 1121
  _clutter_stage_window_redraw (priv->impl);

1122
  if (_clutter_context_get_show_fps ())
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136
    {
      priv->timer_n_frames += 1;

      if (g_timer_elapsed (priv->fps_timer, NULL) >= 1.0)
        {
          g_print ("*** FPS for %s: %i ***\n",
                   _clutter_actor_get_debug_name (actor),
                   priv->timer_n_frames);

          priv->timer_n_frames = 0;
          g_timer_start (priv->fps_timer);
        }
    }

1137 1138 1139
  CLUTTER_NOTE (PAINT, "Redraw finished for stage '%s'[%p]",
                _clutter_actor_get_debug_name (actor),
                stage);
1140 1141
}

1142 1143 1144 1145 1146
/**
 * _clutter_stage_do_update:
 * @stage: A #ClutterStage
 *
 * Handles per-frame layout and repaint for the stage.
1147 1148
 *
 * Return value: %TRUE if the stage was updated
1149
 */
1150
gboolean
1151 1152
_clutter_stage_do_update (ClutterStage *stage)
{
1153
  ClutterStagePrivate *priv = stage->priv;
1154

1155 1156 1157 1158 1159
  /* if the stage is being destroyed, or if the destruction already
   * happened and we don't have an StageWindow any more, then we
   * should bail out
   */
  if (CLUTTER_ACTOR_IN_DESTRUCTION (stage) || priv->impl == NULL)
1160 1161
    return FALSE;

1162 1163 1164
  if (!CLUTTER_ACTOR_IS_REALIZED (stage))
    return FALSE;

1165 1166 1167
  /* NB: We need to ensure we have an up to date layout *before* we
   * check or clear the pending redraws flag since a relayout may
   * queue a redraw.
1168 1169 1170
   */
  _clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage));

1171 1172 1173
  if (!priv->redraw_pending)
    return FALSE;

1174
  clutter_stage_maybe_finish_queue_redraws (stage);
1175

1176
  clutter_stage_do_redraw (stage);
1177

1178
  /* reset the guard, so that new redraws are possible */
1179
  priv->redraw_pending = FALSE;
1180

1181 1182
#ifdef CLUTTER_ENABLE_DEBUG
  if (priv->redraw_count > 0)
1183
    {
1184
      CLUTTER_NOTE (SCHEDULER, "Queued %lu redraws during the last cycle",
1185
                    priv->redraw_count);
1186

1187
      priv->redraw_count = 0;
1188
    }
1189
#endif /* CLUTTER_ENABLE_DEBUG */
1190

1191
  return TRUE;
1192 1193
}

1194 1195 1196 1197 1198 1199 1200
static void
clutter_stage_real_queue_relayout (ClutterActor *self)
{
  ClutterStage *stage = CLUTTER_STAGE (self);
  ClutterStagePrivate *priv = stage->priv;
  ClutterActorClass *parent_class;

1201 1202 1203 1204 1205
  if (!priv->relayout_pending)
    {
      _clutter_stage_schedule_update (stage);
      priv->relayout_pending = TRUE;
    }
1206 1207 1208 1209 1210 1211

  /* chain up */
  parent_class = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class);
  parent_class->queue_relayout (self);
}

1212
static void
1213 1214
clutter_stage_real_queue_redraw (ClutterActor *actor,
                                 ClutterActor *leaf)
1215
{
1216
  ClutterStage *stage = CLUTTER_STAGE (actor);
1217
  ClutterStageWindow *stage_window;
1218
  ClutterPaintVolume *redraw_clip;
1219
  ClutterActorBox bounding_box;
1220
  ClutterActorBox intersection_box;
1221
  cairo_rectangle_int_t geom, stage_clip;
1222

1223 1224 1225
  if (CLUTTER_ACTOR_IN_DESTRUCTION (actor))
    return;

1226 1227
  /* If the backend can't do anything with redraw clips (e.g. it already knows
   * it needs to redraw everything anyway) then don't spend time transforming
1228
   * any clip volume into stage coordinates... */
1229
  stage_window = _clutter_stage_get_window (stage);
1230 1231 1232
  if (stage_window == NULL)
    return;

1233
  if (_clutter_stage_window_ignoring_redraw_clips (stage_window))
1234 1235 1236 1237
    {
      _clutter_stage_window_add_redraw_clip (stage_window, NULL);
      return;
    }
1238

1239 1240
  /* Convert the clip volume into stage coordinates and then into an
   * axis aligned stage coordinates bounding box...
1241
   */
1242 1243
  redraw_clip = _clutter_actor_get_queue_redraw_clip (leaf);
  if (redraw_clip == NULL)
1244 1245 1246 1247 1248
    {
      _clutter_stage_window_add_redraw_clip (stage_window, NULL);
      return;
    }

1249 1250 1251
  if (redraw_clip->is_empty)
    return;

1252 1253 1254
  _clutter_paint_volume_get_stage_paint_box (redraw_clip,
                                             stage,
                                             &bounding_box);
1255

1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267
  _clutter_stage_window_get_geometry (stage_window, &geom);

  intersection_box.x1 = MAX (bounding_box.x1, 0);
  intersection_box.y1 = MAX (bounding_box.y1, 0);
  intersection_box.x2 = MIN (bounding_box.x2, geom.width);
  intersection_box.y2 = MIN (bounding_box.y2, geom.height);

  /* There is no need to track degenerate/empty redraw clips */
  if (intersection_box.x2 <= intersection_box.x1 ||
      intersection_box.y2 <= intersection_box.y1)
    return;

1268 1269
  /* when converting to integer coordinates make sure we round the edges of the
   * clip rectangle outwards... */
1270 1271 1272 1273
  stage_clip.x = intersection_box.x1;
  stage_clip.y = intersection_box.y1;
  stage_clip.width = intersection_box.x2 - stage_clip.x;
  stage_clip.height = intersection_box.y2 - stage_clip.y;
1274 1275 1276 1277 1278 1279 1280 1281

  _clutter_stage_window_add_redraw_clip (stage_window, &stage_clip);
}

gboolean
_clutter_stage_has_full_redraw_queued (ClutterStage *stage)
{
  ClutterStageWindow *stage_window = _clutter_stage_get_window (stage);
1282

1283
  if (CLUTTER_ACTOR_IN_DESTRUCTION (stage) || stage_window == NULL)
1284
    return FALSE;
1285 1286 1287 1288 1289 1290

  if (stage->priv->redraw_pending &&
      !_clutter_stage_window_has_redraw_clips (stage_window))
    return TRUE;
  else
    return FALSE;
1291 1292
}

1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323
/**
 * clutter_stage_get_redraw_clip_bounds:
 * @stage: A #ClutterStage
 * @clip: (out caller-allocates): Return location for the clip bounds
 *
 * Gets the bounds of the current redraw for @stage in stage pixel
 * coordinates. E.g., if only a single actor has queued a redraw then
 * Clutter may redraw the stage with a clip so that it doesn't have to
 * paint every pixel in the stage. This function would then return the
 * bounds of that clip. An application can use this information to
 * avoid some extra work if it knows that some regions of the stage
 * aren't going to be painted. This should only be called while the
 * stage is being painted. If there is no current redraw clip then
 * this function will set @clip to the full extents of the stage.
 *
 * Since: 1.8
 */
void
clutter_stage_get_redraw_clip_bounds (ClutterStage          *stage,
                                      cairo_rectangle_int_t *clip)
{
  ClutterStagePrivate *priv;

  g_return_if_fail (CLUTTER_IS_STAGE (stage));
  g_return_if_fail (clip != NULL);

  priv = stage->priv;

  if (!_clutter_stage_window_get_redraw_clip_bounds (priv->impl, clip))
    {
      /* Set clip to the full extents of the stage */
1324
      _clutter_stage_window_get_geometry (priv->impl, clip);
1325 1326 1327
    }
}

1328 1329 1330 1331 1332 1333 1334
static void
read_pixels_to_file (char *filename_stem,
                     int   x,
                     int   y,
                     int   width,
                     int   height)
{
1335
  guint8 *data;
1336
  cairo_surface_t *surface;
1337
  static int read_count = 0;
1338 1339 1340
  char *filename = g_strdup_printf ("%s-%05d.png",
                                    filename_stem,
                                    read_count);
1341 1342 1343 1344

  data = g_malloc (4 * width * height);
  cogl_read_pixels (x, y, width, height,
                    COGL_READ_PIXELS_COLOR_BUFFER,
1345
                    CLUTTER_CAIRO_FORMAT_ARGB32,
1346 1347
                    data);

1348 1349 1350
  surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_RGB24,
                                                 width, height,
                                                 width * 4);
1351

1352 1353 1354 1355 1356 1357 1358
  cairo_surface_write_to_png (surface, filename);
  cairo_surface_destroy (surface);

  g_free (data);
  g_free (filename);

  read_count++;
1359 1360
}

1361 1362 1363 1364 1365 1366
static ClutterActor *
_clutter_stage_do_pick_on_view (ClutterStage     *stage,
                                gint              x,
                                gint              y,
                                ClutterPickMode   mode,
                                ClutterStageView *view)
1367
{
1368 1369
  ClutterActor *actor = CLUTTER_ACTOR (stage);
  ClutterStagePrivate *priv = stage->priv;
1370 1371
  CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view);
  cairo_rectangle_int_t view_layout;
1372 1373 1374
  ClutterMainContext *context;
  guchar pixel[4] = { 0xff, 0xff, 0xff, 0xff };
  CoglColor stage_pick_id;
1375
  gboolean dither_enabled_save;
1376
  ClutterActor *retval;
1377 1378
  gint dirty_x;
  gint dirty_y;
1379 1380
  gint read_x;
  gint read_y;
1381
  int window_scale;
1382 1383 1384
  float fb_width, fb_height;
  int viewport_offset_x;
  int viewport_offset_y;
1385

1386 1387 1388
  priv = stage->priv;

  context = _clutter_context_get_default ();
1389
  window_scale = _clutter_stage_window_get_scale_factor (priv->impl);
1390
  clutter_stage_view_get_layout (view, &view_layout);
1391

1392 1393 1394
  fb_width = view_layout.width;
  fb_height = view_layout.height;
  cogl_push_framebuffer (fb);
1395 1396

  /* needed for when a context switch happens */
1397 1398 1399 1400 1401 1402 1403 1404
  _clutter_stage_maybe_setup_viewport (stage, view);

  /* FIXME: For some reason leaving the cogl clip stack empty causes the
   * picking to not work at all, so setting it the whole framebuffer content
   * for now. */
  cogl_framebuffer_push_scissor_clip (fb, 0, 0,
                                      view_layout.width,
                                      view_layout.height);
1405

1406
  _clutter_stage_window_get_dirty_pixel (priv->impl, view, &dirty_x, &dirty_y);
1407

1408
  if (G_LIKELY (!(clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS)))
1409 1410 1411 1412 1413 1414
    {
      CLUTTER_NOTE (PICK, "Pushing pick scissor clip x: %d, y: %d, 1x1",
                    dirty_x * window_scale,
                    dirty_y * window_scale);
      cogl_framebuffer_push_scissor_clip (fb, dirty_x * window_scale, dirty_y * window_scale, 1, 1);
    }
1415

1416 1417 1418 1419 1420 1421 1422 1423 1424
  viewport_offset_x = x * window_scale - dirty_x * window_scale;
  viewport_offset_y = y * window_scale - dirty_y * window_scale;
  CLUTTER_NOTE (PICK, "Setting viewport to %f, %f, %f, %f",
                priv->viewport[0] * window_scale - viewport_offset_x,
                priv->viewport[1] * window_scale - viewport_offset_y,
                priv->viewport[2] * window_scale,
                priv->viewport[3] * window_scale);
  cogl_set_viewport (priv->viewport[0] * window_scale - viewport_offset_x,
                     priv->viewport[1] * window_scale - viewport_offset_y,
1425 1426
                     priv->viewport[2] * window_scale,
                     priv->viewport[3] * window_scale);
1427

1428 1429
  read_x = dirty_x * window_scale;
  read_y = dirty_y * window_scale;
1430

1431 1432 1433 1434
  CLUTTER_NOTE (PICK, "Performing pick at %i,%i on view %dx%d+%d+%d",
                x, y,
                view_layout.width, view_layout.height,
                view_layout.x, view_layout.y);
1435

1436 1437
  cogl_color_init_from_4ub (&stage_pick_id, 255, 255, 255, 255);
  cogl_clear (&stage_pick_id, COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH);
1438 1439

  /* Disable dithering (if any) when doing the painting in pick mode */
1440 1441
  dither_enabled_save = cogl_framebuffer_get_dither_enabled (fb);
  cogl_framebuffer_set_dither_enabled (fb, FALSE);
1442 1443 1444 1445 1446

  /* Render the entire scence in pick mode - just single colored silhouette's
   * are drawn offscreen (as we never swap buffers)
  */
  context->pick_mode = mode;
1447
  _clutter_stage_paint_view (stage, view, NULL);
1448 1449 1450 1451 1452 1453 1454 1455 1456
  context->pick_mode = CLUTTER_PICK_NONE;

  /* Read the color of the screen co-ords pixel. RGBA_8888_PRE is used
     even though we don't care about the alpha component because under
     GLES this is the only format that is guaranteed to work so Cogl
     will end up having to do a conversion if any other format is
     used. The format is requested as pre-multiplied because Cogl
     assumes that all pixels in the framebuffer are premultiplied so
     it avoids a conversion. */
1457 1458 1459 1460
  cogl_framebuffer_read_pixels (fb,
                                read_x, read_y, 1, 1,
                                COGL_PIXEL_FORMAT_RGBA_8888_PRE,
                                pixel);
1461 1462 1463

  if (G_UNLIKELY (clutter_pick_debug_flags & CLUTTER_DEBUG_DUMP_PICK_BUFFERS))
    {
1464
      char *file_name =
1465 1466 1467
        g_strdup_printf ("pick-buffer-%s-view-x-%d",
                         _clutter_actor_get_debug_name (actor),
                         view_layout.x);
Emmanuele Bassi's avatar