~oem-solutions-group/unity-2d/clutter-1.0

« back to all changes in this revision

Viewing changes to clutter/clutter-actor.c

  • Committer: Bazaar Package Importer
  • Author(s): Emilio Pozuelo Monfort
  • Date: 2010-03-21 13:27:56 UTC
  • mto: (2.1.3 experimental)
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: james.westby@ubuntu.com-20100321132756-nf8yd30yxo3zzwcm
Tags: upstream-1.2.2
ImportĀ upstreamĀ versionĀ 1.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
 *
6
6
 * Authored By Matthew Allum  <mallum@openedhand.com>
7
7
 *
8
 
 * Copyright (C) 2006 OpenedHand
 
8
 * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
 
9
 * Copyright (C) 2009, 2010 Intel Corp
9
10
 *
10
11
 * This library is free software; you can redistribute it and/or
11
12
 * modify it under the terms of the GNU Lesser General Public
18
19
 * Lesser General Public License for more details.
19
20
 *
20
21
 * You should have received a copy of the GNU Lesser General Public
21
 
 * License along with this library; if not, write to the
22
 
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23
 
 * Boston, MA 02111-1307, USA.
 
22
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
24
23
 */
25
24
 
26
25
/**
74
73
 * clutter_actor_set_width(); or it can have a preferred width and
75
74
 * height, which then allows a layout manager to implicitly size and
76
75
 * position it by "allocating" an area for an actor. This allows for
77
 
 * actors to be manipulate in both a fixed or static parent container
78
 
 * (i.e. children of #ClutterGroup) and a more automatic or dynamic
 
76
 * actors to be manipulated in both a fixed (or static) parent container
 
77
 * (i.e. children of #ClutterGroup) and a more automatic (or dynamic)
79
78
 * layout based parent container.
80
79
 *
81
80
 * When accessing the position and size of an actor, the simple accessors
204
203
#include "clutter-private.h"
205
204
#include "clutter-debug.h"
206
205
#include "clutter-units.h"
 
206
#include "clutter-profile.h"
 
207
#include "clutter-stage.h"
207
208
#include "cogl/cogl.h"
208
209
 
209
210
typedef struct _ShaderData ShaderData;
234
235
  } v;
235
236
};
236
237
 
 
238
/* 3 entries should be a good compromise, few layout managers
 
239
 * will ask for 3 different preferred size in each allocation cycle */
 
240
#define N_CACHED_SIZE_REQUESTS 3
 
241
typedef struct _SizeRequest SizeRequest;
 
242
struct _SizeRequest
 
243
{
 
244
  guint  age;
 
245
  gfloat for_size;
 
246
  gfloat min_size;
 
247
  gfloat natural_size;
 
248
};
 
249
 
237
250
/* Internal enum used to control mapped state update.  This is a hint
238
251
 * which indicates when to do something other than just enforce
239
252
 * invariants.
262
275
  /* request mode */
263
276
  ClutterRequestMode request_mode;
264
277
 
265
 
  /* our cached request width is for this height */
266
 
  gfloat request_width_for_height;
 
278
  /* our cached size requests for different width / height */
 
279
  SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
 
280
  SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
 
281
 
 
282
  /* An age of 0 means the entry is not set */
 
283
  guint cached_height_age;
 
284
  guint cached_width_age;
 
285
 
267
286
  gfloat request_min_width;
 
287
  gfloat request_min_height;
268
288
  gfloat request_natural_width;
269
 
 
270
 
  /* our cached request height is for this width */
271
 
  gfloat request_height_for_width;
272
 
  gfloat request_min_height;
273
289
  gfloat request_natural_height;
274
290
 
275
291
  ClutterActorBox allocation;
286
302
  guint needs_height_request        : 1;
287
303
  /* cached allocation is invalid (request has changed, probably) */
288
304
  guint needs_allocation            : 1;
289
 
  guint queued_redraw               : 1;
290
305
  guint show_on_set_parent          : 1;
291
306
  guint has_clip                    : 1;
292
307
  guint clip_to_allocation          : 1;
293
308
  guint enable_model_view_transform : 1;
294
309
  guint enable_paint_unmapped       : 1;
 
310
  guint has_pointer                 : 1;
 
311
  guint propagated_one_redraw       : 1;
295
312
 
296
313
  gfloat clip[4];
297
314
 
332
349
  PangoContext   *pango_context;
333
350
 
334
351
  ClutterActor   *opacity_parent;
 
352
 
 
353
  ClutterTextDirection text_direction;
 
354
 
 
355
  gint internal_child;
 
356
 
 
357
  /* XXX: This is a workaround for not being able to break the ABI
 
358
   * of the QUEUE_REDRAW signal. It's an out-of-band argument.
 
359
   * See clutter_actor_queue_clipped_redraw() for details.
 
360
   */
 
361
  const ClutterActorBox *oob_queue_redraw_clip;
335
362
};
336
363
 
337
364
enum
409
436
  PROP_ANCHOR_Y,
410
437
  PROP_ANCHOR_GRAVITY,
411
438
 
412
 
  PROP_SHOW_ON_SET_PARENT
 
439
  PROP_SHOW_ON_SET_PARENT,
 
440
 
 
441
  PROP_TEXT_DIRECTION,
 
442
  PROP_HAS_POINTER
413
443
};
414
444
 
415
445
enum
425
455
  REALIZE,
426
456
  UNREALIZE,
427
457
  QUEUE_REDRAW,
 
458
  QUEUE_RELAYOUT,
428
459
  EVENT,
429
460
  CAPTURED_EVENT,
430
461
  BUTTON_PRESS_EVENT,
472
503
                                                  gboolean  use_natural_width);
473
504
static void clutter_actor_set_natural_height_set (ClutterActor *self,
474
505
                                                  gboolean  use_natural_height);
475
 
static void clutter_actor_set_request_mode       (ClutterActor *self,
476
 
                                                  ClutterRequestMode mode);
477
506
static void clutter_actor_update_map_state       (ClutterActor  *self,
478
507
                                                  MapStateChange change);
479
508
static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
534
563
                {
535
564
                }
536
565
              else
537
 
                g_warning ("Realized non-toplevel actor should have a parent");
 
566
                g_warning ("Realized non-toplevel actor '%s' should "
 
567
                           "have a parent",
 
568
                           priv->name ? priv->name
 
569
                                      : G_OBJECT_TYPE_NAME (self));
538
570
            }
539
571
          else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent_actor))
540
572
            {
541
 
              g_warning ("Realized actor %s[%p] has an unrealized parent %s[%p]",
542
 
                         G_OBJECT_TYPE_NAME (self), self,
543
 
                         G_OBJECT_TYPE_NAME (priv->parent_actor),
544
 
                         priv->parent_actor);
 
573
              g_warning ("Realized actor %s has an unrealized parent %s",
 
574
                         priv->name ? priv->name
 
575
                                    : G_OBJECT_TYPE_NAME (self),
 
576
                         clutter_actor_get_name (priv->parent_actor)
 
577
                           ? clutter_actor_get_name (priv->parent_actor)
 
578
                           : G_OBJECT_TYPE_NAME (priv->parent_actor));
545
579
            }
546
580
        }
547
581
    }
549
583
  if (CLUTTER_ACTOR_IS_MAPPED (self))
550
584
    {
551
585
      if (!CLUTTER_ACTOR_IS_REALIZED (self))
552
 
        g_warning ("Actor is mapped but not realized");
 
586
        g_warning ("Actor '%s' is mapped but not realized",
 
587
                   priv->name ? priv->name
 
588
                              : G_OBJECT_TYPE_NAME (self));
553
589
 
554
590
      /* remaining bets are off during reparent when we're potentially
555
591
       * mapped, but should not be according to invariants
563
599
                  if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
564
600
                      !(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_DESTRUCTION))
565
601
                    {
566
 
                      g_warning ("Toplevel actor is mapped but not visible");
 
602
                      g_warning ("Toplevel actor '%s' is mapped "
 
603
                                 "but not visible",
 
604
                                 priv->name ? priv->name
 
605
                                            : G_OBJECT_TYPE_NAME (self));
567
606
                    }
568
607
                }
569
608
              else
570
609
                {
571
 
                  g_warning ("Mapped actor %s %p should have a parent",
572
 
                             G_OBJECT_TYPE_NAME (self), self);
 
610
                  g_warning ("Mapped actor '%s' should have a parent",
 
611
                             priv->name ? priv->name
 
612
                                        :G_OBJECT_TYPE_NAME (self));
573
613
                }
574
614
            }
575
615
          else
591
631
 
592
632
              if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent_actor))
593
633
                {
594
 
                  g_warning ("Actor should not be mapped if parent "
595
 
                             "is not visible");
 
634
                  g_warning ("Actor '%s' should not be mapped if parent "
 
635
                             "is not visible",
 
636
                             priv->name ? priv->name
 
637
                                        : G_OBJECT_TYPE_NAME (self));
596
638
                }
597
639
 
598
640
              if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent_actor))
599
641
                {
600
 
                  g_warning ("Actor should not be mapped if parent "
601
 
                             "is not realized");
 
642
                  g_warning ("Actor '%s' should not be mapped if parent "
 
643
                             "is not realized",
 
644
                             priv->name ? priv->name
 
645
                                        : G_OBJECT_TYPE_NAME (self));
602
646
                }
603
647
 
604
648
              if (!(CLUTTER_PRIVATE_FLAGS (priv->parent_actor) &
605
649
                    CLUTTER_ACTOR_IS_TOPLEVEL))
606
650
                {
607
651
                  if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent_actor))
608
 
                    g_warning ("Actor is mapped but its non-toplevel "
609
 
                               "parent is not mapped");
 
652
                    g_warning ("Actor '%s' is mapped but its non-toplevel "
 
653
                               "parent is not mapped",
 
654
                               priv->name ? priv->name
 
655
                                          : G_OBJECT_TYPE_NAME (self));
610
656
                }
611
657
            }
612
658
        }
642
688
                                MapStateChange change)
643
689
{
644
690
  gboolean was_mapped;
645
 
  gboolean was_realized;
646
691
 
647
692
  was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
648
 
  was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
649
693
 
650
694
  if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL)
651
695
    {
777
821
          if (priv->enable_paint_unmapped)
778
822
            {
779
823
              if (priv->parent_actor == NULL)
780
 
                g_warning ("Attempting to map an unparented actor");
 
824
                g_warning ("Attempting to map an unparented actor '%s'",
 
825
                           priv->name ? priv->name
 
826
                                      : G_OBJECT_TYPE_NAME (self));
781
827
 
782
828
              should_be_mapped = TRUE;
783
829
              must_be_realized = TRUE;
791
837
        {
792
838
          if (parent == NULL)
793
839
            g_warning ("Attempting to map a child that does not "
794
 
                       "meet the necessary invariants: the actor "
795
 
                       "has no parent");
 
840
                       "meet the necessary invariants: the actor '%s' "
 
841
                       "has no parent",
 
842
                       priv->name ? priv->name
 
843
                                  : G_OBJECT_TYPE_NAME (self));
796
844
          else
797
845
            g_warning ("Attempting to map a child that does not "
798
 
                       "meet the necessary invariants: the actor "
799
 
                       "is parented to an unmapped actor");
 
846
                       "meet the necessary invariants: the actor '%s' "
 
847
                       "is parented to an unmapped actor",
 
848
                       priv->name ? priv->name
 
849
                                  : G_OBJECT_TYPE_NAME (self));
800
850
        }
801
851
 
802
852
      /* If in reparent, we temporarily suspend unmap and unrealize.
827
877
      if (should_be_mapped)
828
878
        {
829
879
          if (!must_be_realized)
830
 
            g_warning ("Somehow we think an actor should be mapped but "
831
 
                       "not realized, which isn't allowed");
 
880
            g_warning ("Somehow we think actor '%s' should be mapped but "
 
881
                       "not realized, which isn't allowed",
 
882
                       priv->name ? priv->name
 
883
                                  : G_OBJECT_TYPE_NAME (self));
832
884
 
833
885
          /* realization is allowed to fail (though I don't know what
834
886
           * an app is supposed to do about that - shouldn't it just
852
904
  g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
853
905
 
854
906
  CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
 
907
 
855
908
  /* notify on parent mapped before potentially mapping
856
909
   * children, so apps see a top-down notification.
857
910
   */
867
920
 * clutter_actor_map:
868
921
 * @self: A #ClutterActor
869
922
 *
870
 
 * Sets the #CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
 
923
 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
871
924
 * and realizes its children if they are visible. Does nothing if the
872
925
 * actor is not visible.
873
926
 *
932
985
 * clutter_actor_unmap:
933
986
 * @self: A #ClutterActor
934
987
 *
935
 
 * Unsets the #CLUTTER_ACTOR_MAPPED flag on the actor and possibly
 
988
 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
936
989
 * unmaps its children if they were mapped.
937
990
 *
938
991
 * Calling this is allowed in only one case: you are implementing the
962
1015
{
963
1016
  if (!CLUTTER_ACTOR_IS_VISIBLE (self))
964
1017
    {
 
1018
      ClutterActorPrivate *priv = self->priv;
 
1019
 
965
1020
      CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
 
1021
 
966
1022
      /* we notify on the "visible" flag in the clutter_actor_show()
967
1023
       * wrapper so the entire show signal emission completes first
968
1024
       * (?)
969
1025
       */
970
1026
      clutter_actor_update_map_state (self, MAP_STATE_CHECK);
971
1027
 
972
 
      clutter_actor_queue_relayout (self);
 
1028
      /* we queue a relayout unless the actor is inside a
 
1029
       * container that explicitly told us not to
 
1030
       */
 
1031
      if (priv->parent_actor &&
 
1032
          (!(priv->parent_actor->flags & CLUTTER_ACTOR_NO_LAYOUT)))
 
1033
        {
 
1034
          /* While an actor is hidden the parent may not have
 
1035
           * allocated/requested so we need to start from scratch
 
1036
           * and avoid the short-circuiting in
 
1037
           * clutter_actor_queue_relayout().
 
1038
           */
 
1039
          priv->needs_width_request  = FALSE;
 
1040
          priv->needs_height_request = FALSE;
 
1041
          priv->needs_allocation     = FALSE;
 
1042
          clutter_actor_queue_relayout (self);
 
1043
        }
973
1044
    }
974
1045
}
975
1046
 
1044
1115
{
1045
1116
  if (CLUTTER_ACTOR_IS_VISIBLE (self))
1046
1117
    {
 
1118
      ClutterActorPrivate *priv = self->priv;
 
1119
 
1047
1120
      CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1048
1121
 
1049
1122
      /* we notify on the "visible" flag in the clutter_actor_hide()
1052
1125
       */
1053
1126
      clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1054
1127
 
1055
 
      clutter_actor_queue_relayout (self);
 
1128
      /* we queue a relayout unless the actor is inside a
 
1129
       * container that explicitly told us not to
 
1130
       */
 
1131
      if (priv->parent_actor &&
 
1132
          (!(priv->parent_actor->flags & CLUTTER_ACTOR_NO_LAYOUT)))
 
1133
        clutter_actor_queue_relayout (priv->parent_actor);
1056
1134
    }
1057
1135
}
1058
1136
 
1144
1222
void
1145
1223
clutter_actor_realize (ClutterActor *self)
1146
1224
{
 
1225
  ClutterActorPrivate *priv;
 
1226
 
1147
1227
  g_return_if_fail (CLUTTER_IS_ACTOR (self));
1148
1228
 
 
1229
  priv = self->priv;
 
1230
 
1149
1231
#ifdef CLUTTER_ENABLE_DEBUG
1150
1232
  clutter_actor_verify_map_state (self);
1151
1233
#endif
1156
1238
  /* To be realized, our parent actors must be realized first.
1157
1239
   * This will only succeed if we're inside a toplevel.
1158
1240
   */
1159
 
  if (self->priv->parent_actor != NULL)
1160
 
    clutter_actor_realize (self->priv->parent_actor);
 
1241
  if (priv->parent_actor != NULL)
 
1242
    clutter_actor_realize (priv->parent_actor);
1161
1243
 
1162
1244
  if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL)
1163
1245
    {
1172
1254
       * someone can fix it. But for now it's too hard to fix this
1173
1255
       * because e.g. ClutterTexture needs reworking.
1174
1256
       */
1175
 
      if (self->priv->parent_actor == NULL ||
1176
 
          !CLUTTER_ACTOR_IS_REALIZED (self->priv->parent_actor))
 
1257
      if (priv->parent_actor == NULL ||
 
1258
          !CLUTTER_ACTOR_IS_REALIZED (priv->parent_actor))
1177
1259
        return;
1178
1260
    }
1179
1261
 
1180
1262
  CLUTTER_NOTE (ACTOR, "Realizing actor '%s' [%p]",
1181
 
                self->priv->name ? self->priv->name
 
1263
                priv->name ? priv->name
1182
1264
                                 : G_OBJECT_TYPE_NAME (self),
1183
1265
                self);
1184
1266
 
1254
1336
  clutter_actor_unrealize_not_hiding (self);
1255
1337
}
1256
1338
 
1257
 
/**
 
1339
/*
1258
1340
 * clutter_actor_unrealize_not_hiding:
1259
1341
 * @self: A #ClutterActor
1260
1342
 *
1301
1383
  g_object_notify (G_OBJECT (self), "realized");
1302
1384
}
1303
1385
 
1304
 
/**
 
1386
/*
1305
1387
 * _clutter_actor_rerealize:
1306
1388
 * @self: A #ClutterActor
1307
1389
 * @callback: Function to call while unrealized
1547
1629
 
1548
1630
  g_object_freeze_notify (G_OBJECT (self));
1549
1631
 
1550
 
  if (x1_changed || y1_changed || x2_changed || y2_changed)
 
1632
  if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
1551
1633
    {
1552
1634
      g_object_notify (G_OBJECT (self), "allocation");
1553
1635
 
1568
1650
clutter_actor_queue_redraw_with_origin (ClutterActor *self,
1569
1651
                                        ClutterActor *origin)
1570
1652
{
1571
 
  /* already queued since last paint() */
1572
 
  if (self->priv->queued_redraw)
 
1653
  /* no point in queuing a redraw on a destroyed actor */
 
1654
  if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_DESTRUCTION)
1573
1655
    return;
1574
1656
 
 
1657
  /* NB: We can't bail out early here if the actor is hidden in case
 
1658
   * the actor bas been cloned. In this case the clone will need to
 
1659
   * receive the signal so it can queue its own redraw.
 
1660
   */
 
1661
 
1575
1662
  /* calls klass->queue_redraw in default handler */
1576
1663
  g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
1577
1664
}
1582
1669
{
1583
1670
  ClutterActor *parent;
1584
1671
 
1585
 
  /* already queued since last paint() */
1586
 
  if (self->priv->queued_redraw)
1587
 
    return;
1588
 
 
1589
1672
  CLUTTER_NOTE (PAINT, "Redraw queued on '%s'",
1590
1673
                clutter_actor_get_name (self) ? clutter_actor_get_name (self)
1591
1674
                                              : G_OBJECT_TYPE_NAME (self));
1592
 
  self->priv->queued_redraw = TRUE;
 
1675
 
 
1676
  /* no point in queuing a redraw on a destroyed actor */
 
1677
  if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_DESTRUCTION)
 
1678
    return;
1593
1679
 
1594
1680
  /* If the actor isn't visible, we still had to emit the signal
1595
1681
   * to allow for a ClutterClone, but the appearance of the parent
1598
1684
  if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1599
1685
    return;
1600
1686
 
 
1687
  /* Although we could determine here that a full stage redraw
 
1688
   * has already been queued and immediately bail out, we actually
 
1689
   * guarantee that we will propagate a queue-redraw signal to our
 
1690
   * parent at least once so that it's possible to implement a
 
1691
   * container that tracks which of its children have queued a
 
1692
   * redraw.
 
1693
   */
 
1694
  if (self->priv->propagated_one_redraw)
 
1695
    {
 
1696
      ClutterActor *stage = clutter_actor_get_stage (self);
 
1697
      if (stage &&
 
1698
          _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
 
1699
        return;
 
1700
    }
 
1701
  self->priv->propagated_one_redraw = TRUE;
 
1702
 
1601
1703
  /* notify parents, if they are all visible eventually we'll
1602
1704
   * queue redraw on the stage, which queues the redraw idle.
1603
1705
   */
1609
1711
    }
1610
1712
}
1611
1713
 
 
1714
void
 
1715
clutter_actor_real_queue_relayout (ClutterActor *self)
 
1716
{
 
1717
  ClutterActorPrivate *priv = self->priv;
 
1718
 
 
1719
  /* no point in queueing a redraw on a destroyed actor */
 
1720
  if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_DESTRUCTION)
 
1721
    return;
 
1722
 
 
1723
  priv->needs_width_request  = TRUE;
 
1724
  priv->needs_height_request = TRUE;
 
1725
  priv->needs_allocation     = TRUE;
 
1726
 
 
1727
  /* reset the cached size requests */
 
1728
  memset (priv->width_requests, 0,
 
1729
          N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
 
1730
  memset (priv->height_requests, 0,
 
1731
          N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
 
1732
 
 
1733
  /* always repaint also (no-op if not mapped) */
 
1734
  clutter_actor_queue_redraw (self);
 
1735
 
 
1736
  /* We need to go all the way up the hierarchy */
 
1737
  if (priv->parent_actor)
 
1738
    clutter_actor_queue_relayout (priv->parent_actor);
 
1739
}
 
1740
 
1612
1741
/* like ClutterVertex, but with a w component */
1613
1742
typedef struct {
1614
1743
  gfloat x;
1627
1756
  u->z = f->z;
1628
1757
}
1629
1758
 
1630
 
/* Transforms a vertex using the passed matrix; vertex is
1631
 
 * an in-out parameter
1632
 
 */
1633
 
static void
1634
 
mtx_transform (const CoglMatrix *matrix,
1635
 
               full_vertex_t    *vertex)
1636
 
{
1637
 
  cogl_matrix_transform_point (matrix,
1638
 
                               &vertex->x,
1639
 
                               &vertex->y,
1640
 
                               &vertex->z,
1641
 
                               &vertex->w);
1642
 
}
1643
 
 
1644
 
/* Help macros to scale from OpenGL <-1,1> coordinates system to our
1645
 
 * X-window based <0,window-size> coordinates
1646
 
 */
1647
 
#define MTX_GL_SCALE_X(x,w,v1,v2)       ((((((x) / (w)) + 1.0) / 2) * (v1)) + (v2))
1648
 
#define MTX_GL_SCALE_Y(y,w,v1,v2)       ((v1) - (((((y) / (w)) + 1.0) / 2) * (v1)) + (v2))
1649
 
#define MTX_GL_SCALE_Z(z,w,v1,v2)       (MTX_GL_SCALE_X ((z), (w), (v1), (v2)))
1650
 
 
1651
1759
/* transforms a 4-tuple of coordinates using @matrix and
1652
 
 * places the result into a fixed @vertex
 
1760
 * places the result into a @vertex
1653
1761
 */
1654
1762
static inline void
1655
1763
full_vertex_transform (const CoglMatrix *matrix,
1659
1767
                       gfloat            w,
1660
1768
                       full_vertex_t    *vertex)
1661
1769
{
1662
 
  full_vertex_t tmp = { 0, };
1663
 
 
1664
 
  tmp.x = x;
1665
 
  tmp.y = y;
1666
 
  tmp.z = z;
1667
 
  tmp.w = w;
1668
 
 
1669
 
  mtx_transform (matrix, &tmp);
1670
 
 
1671
 
  *vertex = tmp;
 
1770
  cogl_matrix_transform_point (matrix, &x, &y, &z, &w);
 
1771
 
 
1772
  vertex->x = x;
 
1773
  vertex->y = y;
 
1774
  vertex->z = z;
 
1775
  vertex->w = w;
1672
1776
}
1673
1777
 
 
1778
/* Help macros to scale from OpenGL <-1,1> coordinates system to our
 
1779
 * X-window based <0,window-size> coordinates
 
1780
 */
 
1781
#define MTX_GL_SCALE_X(x,w,v1,v2)       ((((((x) / (w)) + 1.0) / 2) * (v1)) + (v2))
 
1782
#define MTX_GL_SCALE_Y(y,w,v1,v2)       ((v1) - (((((y) / (w)) + 1.0) / 2) * (v1)) + (v2))
 
1783
#define MTX_GL_SCALE_Z(z,w,v1,v2)       (MTX_GL_SCALE_X ((z), (w), (v1), (v2)))
 
1784
 
1674
1785
/* scales a fixed @vertex using @matrix and @viewport, and
1675
1786
 * transforms the result into a ClutterVertex, filling @vertex_p
1676
1787
 */
1681
1792
                   ClutterVertex       *vertex_p)
1682
1793
{
1683
1794
  gfloat v_x, v_y, v_width, v_height;
1684
 
  full_vertex_t tmp = { 0, };
 
1795
  full_vertex_t tmp;
1685
1796
 
1686
1797
  tmp = *vertex;
1687
1798
 
1688
 
  mtx_transform (matrix, &tmp);
 
1799
  cogl_matrix_transform_point (matrix,
 
1800
                               &tmp.x,
 
1801
                               &tmp.y,
 
1802
                               &tmp.z,
 
1803
                               &tmp.w);
1689
1804
 
1690
1805
  v_x      = viewport[0];
1691
1806
  v_y      = viewport[1];
1714
1829
                                        gfloat       *z,
1715
1830
                                        gfloat       *w)
1716
1831
{
1717
 
  full_vertex_t vertex = { 0, };
 
1832
  full_vertex_t vertex;
1718
1833
  CoglMatrix matrix;
1719
1834
 
1720
1835
  vertex.x = (x != NULL) ? *x : 0;
1727
1842
  _clutter_actor_apply_modelview_transform_recursive (actor, ancestor);
1728
1843
 
1729
1844
  cogl_get_modelview_matrix (&matrix);
1730
 
  mtx_transform (&matrix, &vertex);
 
1845
  cogl_matrix_transform_point (&matrix,
 
1846
                               &vertex.x,
 
1847
                               &vertex.y,
 
1848
                               &vertex.z,
 
1849
                               &vertex.w);
 
1850
 
1731
1851
 
1732
1852
  cogl_pop_matrix();
1733
1853
 
1755
1875
                               gfloat       *z,
1756
1876
                               gfloat       *w)
1757
1877
{
1758
 
  full_vertex_t vertex = { 0, };
 
1878
  full_vertex_t vertex;
1759
1879
  CoglMatrix matrix;
1760
1880
 
1761
1881
  vertex.x = (x != NULL) ? *x : 0;
1768
1888
  _clutter_actor_apply_modelview_transform_recursive (actor, NULL);
1769
1889
 
1770
1890
  cogl_get_modelview_matrix (&matrix);
1771
 
  mtx_transform (&matrix, &vertex);
 
1891
  cogl_matrix_transform_point (&matrix,
 
1892
                               &vertex.x,
 
1893
                               &vertex.y,
 
1894
                               &vertex.z,
 
1895
                               &vertex.w);
 
1896
 
1772
1897
 
1773
1898
  cogl_pop_matrix();
1774
1899
 
1883
2008
  cogl_get_viewport (v);
1884
2009
 
1885
2010
  /* Now, transform it again with the projection matrix */
1886
 
  mtx_transform (&matrix_p, &tmp);
 
2011
  cogl_matrix_transform_point (&matrix_p,
 
2012
                               &tmp.x,
 
2013
                               &tmp.y,
 
2014
                               &tmp.z,
 
2015
                               &tmp.w);
 
2016
 
1887
2017
 
1888
2018
  /* Finaly translate from OpenGL coords to window coords */
1889
2019
  vertex->x = MTX_GL_SCALE_X (tmp.x, tmp.w, v[2], v[0]);
1921
2051
  cogl_pop_matrix();
1922
2052
}
1923
2053
 
1924
 
/* Recursively tranform supplied box with the tranform for the current
 
2054
/* _clutter_actor_ensure_stage_current
 
2055
 *
 
2056
 * Ensures that the actors corresponding stage is made current so we
 
2057
 * have a valid viewport, projection matrix and modelview matrix stack.
 
2058
 */
 
2059
static void
 
2060
_clutter_actor_ensure_stage_current (ClutterActor *self)
 
2061
{
 
2062
  ClutterActor *stage;
 
2063
 
 
2064
  /* We essentially have to dupe some code from clutter_redraw() here
 
2065
   * to make sure GL Matrices etc are initialised if we're called and we
 
2066
   * haven't yet rendered anything.
 
2067
   *
 
2068
   * Simply duping code for now in wait for Cogl cleanup that can hopefully
 
2069
   * address this in a nicer way.
 
2070
  */
 
2071
  stage = clutter_actor_get_stage (self);
 
2072
 
 
2073
  /* FIXME: if were not yet added to a stage, its probably unsafe to
 
2074
   * return default - ideally the func should fail
 
2075
  */
 
2076
  if (stage == NULL)
 
2077
    stage = clutter_stage_get_default ();
 
2078
 
 
2079
  clutter_stage_ensure_current (CLUTTER_STAGE (stage));
 
2080
  _clutter_stage_maybe_setup_viewport (CLUTTER_STAGE (stage));
 
2081
}
 
2082
 
 
2083
/* _clutter_actor_get_relative_modelview:
 
2084
 *
 
2085
 * Retrives the modelview transformation relative to some ancestor actor, or
 
2086
 * the stage if NULL is given for the ancestor.
 
2087
 *
 
2088
 * It assumes you currently have an empty matrix stack.
 
2089
 */
 
2090
/* FIXME: We should be caching the stage relative modelview along with the
 
2091
 * actor itself */
 
2092
/* TODO: Replace all other occurrences of this code pattern in clutter-actor.c:
 
2093
 *   cogl_push_matrix();
 
2094
 *   _clutter_actor_apply_modelview_transform_recursive (self, ancestor)
 
2095
 *   cogl_get_modelview_matrix()
 
2096
 *   cogl_pop_matrix();
 
2097
 * with a call to this function:
 
2098
 */
 
2099
void
 
2100
_clutter_actor_get_relative_modelview (ClutterActor *self,
 
2101
                                       ClutterActor *ancestor,
 
2102
                                       CoglMatrix *matrix)
 
2103
{
 
2104
  _clutter_actor_ensure_stage_current (self);
 
2105
 
 
2106
  /* FIXME: init_identity instead of assuming we have an empty stack! */
 
2107
 
 
2108
  cogl_push_matrix ();
 
2109
 
 
2110
  _clutter_actor_apply_modelview_transform_recursive (self, ancestor);
 
2111
 
 
2112
  cogl_get_modelview_matrix (matrix);
 
2113
 
 
2114
  cogl_pop_matrix ();
 
2115
}
 
2116
 
 
2117
/* _clutter_actor_get_projection_and_viewport
 
2118
 *
 
2119
 * Retrieves the projection matrix and viewport for the actors corresponding
 
2120
 * stage.
 
2121
 */
 
2122
void
 
2123
_clutter_actor_get_projection_and_viewport (ClutterActor *self,
 
2124
                                            CoglMatrix *matrix,
 
2125
                                            float *viewport)
 
2126
{
 
2127
  _clutter_actor_ensure_stage_current (self);
 
2128
 
 
2129
  cogl_get_projection_matrix (matrix);
 
2130
  cogl_get_viewport (viewport);
 
2131
}
 
2132
 
 
2133
/* Recursively transform supplied box with the transform for the current
1925
2134
 * actor and all its ancestors (like clutter_actor_transform_point()
1926
2135
 * but for all the vertices in one go) and project it into screen
1927
2136
 * coordinates
1928
2137
 */
1929
 
static void
1930
 
clutter_actor_transform_and_project_box (ClutterActor          *self,
1931
 
                                         const ClutterActorBox *box,
1932
 
                                         ClutterVertex          verts[])
 
2138
void
 
2139
_clutter_actor_transform_and_project_box (ClutterActor          *self,
 
2140
                                          const ClutterActorBox *box,
 
2141
                                          ClutterVertex          verts[])
1933
2142
{
1934
 
  ClutterActor *stage;
1935
2143
  CoglMatrix mtx;
1936
2144
  CoglMatrix mtx_p;
1937
 
  gfloat v[4];
1938
 
  gfloat width, height;
 
2145
  float v[4];
1939
2146
  full_vertex_t vertices[4];
1940
2147
 
1941
 
  width  = box->x2 - box->x1;
1942
 
  height = box->y2 - box->y1;
1943
 
 
1944
 
  /* We essentially have to dupe some code from clutter_redraw() here
1945
 
   * to make sure GL Matrices etc are initialised if we're called and we
1946
 
   * havn't yet rendered anything.
1947
 
   *
1948
 
   * Simply duping code for now in wait for Cogl cleanup that can hopefully
1949
 
   * address this in a nicer way.
1950
 
  */
1951
 
  stage = clutter_actor_get_stage (self);
1952
 
 
1953
 
  /* FIXME: if were not yet added to a stage, its probably unsafe to
1954
 
   * return default - ideally the func should fail
1955
 
  */
1956
 
  if (stage == NULL)
1957
 
    stage = clutter_stage_get_default ();
1958
 
 
1959
 
  clutter_stage_ensure_current (CLUTTER_STAGE (stage));
1960
 
  _clutter_stage_maybe_setup_viewport (CLUTTER_STAGE (stage));
1961
 
 
1962
 
  cogl_push_matrix();
1963
 
 
1964
 
  _clutter_actor_apply_modelview_transform_recursive (self, NULL);
1965
 
 
1966
 
  cogl_get_modelview_matrix (&mtx);
1967
 
 
1968
 
  full_vertex_transform (&mtx, 0,     0,      0, 1.0, &vertices[0]);
1969
 
  full_vertex_transform (&mtx, width, 0,      0, 1.0, &vertices[1]);
1970
 
  full_vertex_transform (&mtx, 0,     height, 0, 1.0, &vertices[2]);
1971
 
  full_vertex_transform (&mtx, width, height, 0, 1.0, &vertices[3]);
1972
 
 
1973
 
  cogl_pop_matrix();
1974
 
 
1975
 
  cogl_get_projection_matrix (&mtx_p);
1976
 
  cogl_get_viewport (v);
 
2148
  _clutter_actor_get_relative_modelview (self, NULL, &mtx);
 
2149
 
 
2150
  full_vertex_transform (&mtx, box->x1, box->y1, 0, 1.0, &vertices[0]);
 
2151
  full_vertex_transform (&mtx, box->x2, box->y1, 0, 1.0, &vertices[1]);
 
2152
  full_vertex_transform (&mtx, box->x1, box->y2, 0, 1.0, &vertices[2]);
 
2153
  full_vertex_transform (&mtx, box->x2, box->y2, 0, 1.0, &vertices[3]);
 
2154
 
 
2155
  _clutter_actor_get_projection_and_viewport (self, &mtx_p, v);
1977
2156
 
1978
2157
  full_vertex_scale (&mtx_p, &vertices[0], v, &verts[0]);
1979
2158
  full_vertex_scale (&mtx_p, &vertices[1], v, &verts[1]);
2098
2277
                                           ClutterVertex  verts[])
2099
2278
{
2100
2279
  ClutterActorPrivate   *priv;
 
2280
  ClutterActorBox        actor_space_allocation;
2101
2281
 
2102
2282
  g_return_if_fail (CLUTTER_IS_ACTOR (self));
2103
2283
 
2105
2285
 
2106
2286
  /* if the actor needs to be allocated we force a relayout, so that
2107
2287
   * the actor allocation box will be valid for
2108
 
   * clutter_actor_transform_and_project_box()
 
2288
   * _clutter_actor_transform_and_project_box()
2109
2289
   */
2110
2290
  if (priv->needs_allocation)
2111
2291
    {
2120
2300
      _clutter_stage_maybe_relayout (stage);
2121
2301
    }
2122
2302
 
2123
 
  clutter_actor_transform_and_project_box (self,
2124
 
                                           &self->priv->allocation,
2125
 
                                           verts);
 
2303
  /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
 
2304
   * own coordinate space... */
 
2305
  actor_space_allocation.x1 = 0;
 
2306
  actor_space_allocation.y1 = 0;
 
2307
  actor_space_allocation.x2 =
 
2308
    self->priv->allocation.x2 - self->priv->allocation.x1;
 
2309
  actor_space_allocation.y2 =
 
2310
    self->priv->allocation.y2 - self->priv->allocation.y1;
 
2311
  _clutter_actor_transform_and_project_box (self,
 
2312
                                            &actor_space_allocation,
 
2313
                                            verts);
2126
2314
}
2127
2315
 
2128
2316
static void
2242
2430
  if (stage == NULL)
2243
2431
    stage = clutter_stage_get_default ();
2244
2432
 
2245
 
  if (parent)
 
2433
  if (parent != NULL)
2246
2434
    _clutter_actor_apply_modelview_transform_recursive (parent, ancestor);
2247
2435
  else if (self != stage)
2248
2436
    _clutter_actor_apply_modelview_transform (stage);
2267
2455
  ClutterActorPrivate *priv;
2268
2456
  ClutterMainContext *context;
2269
2457
  gboolean clip_set = FALSE;
 
2458
  CLUTTER_STATIC_COUNTER (actor_paint_counter,
 
2459
                          "Actor real-paint counter",
 
2460
                          "Increments each time any actor is painted",
 
2461
                          0 /* no application private data */);
 
2462
  CLUTTER_STATIC_COUNTER (actor_pick_counter,
 
2463
                          "Actor pick-paint counter",
 
2464
                          "Increments each time any actor is painted "
 
2465
                          "for picking",
 
2466
                          0 /* no application private data */);
2270
2467
 
2271
2468
  g_return_if_fail (CLUTTER_IS_ACTOR (self));
2272
2469
 
2281
2478
         clone's opacity instead */
2282
2479
      (priv->opacity_parent ? priv->opacity_parent->priv : priv)->opacity == 0)
2283
2480
    {
2284
 
      priv->queued_redraw = FALSE;
 
2481
      priv->propagated_one_redraw = FALSE;
2285
2482
      return;
2286
2483
    }
2287
2484
 
2301
2498
 
2302
2499
  if (priv->has_clip)
2303
2500
    {
2304
 
      cogl_clip_push (priv->clip[0],
2305
 
                      priv->clip[1],
2306
 
                      priv->clip[2],
2307
 
                      priv->clip[3]);
 
2501
      cogl_clip_push_rectangle (priv->clip[0],
 
2502
                                priv->clip[1],
 
2503
                                priv->clip[0] + priv->clip[2],
 
2504
                                priv->clip[1] + priv->clip[3]);
2308
2505
      clip_set = TRUE;
2309
2506
    }
2310
2507
  else if (priv->clip_to_allocation)
2314
2511
      width  = priv->allocation.x2 - priv->allocation.x1;
2315
2512
      height = priv->allocation.y2 - priv->allocation.y1;
2316
2513
 
2317
 
      cogl_clip_push (0, 0, width, height);
 
2514
      cogl_clip_push_rectangle (0, 0, width, height);
2318
2515
      clip_set = TRUE;
2319
2516
    }
2320
2517
 
2322
2519
    {
2323
2520
      ClutterColor col = { 0, };
2324
2521
 
 
2522
      CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
 
2523
 
2325
2524
      _clutter_id_to_color (clutter_actor_get_gid (self), &col);
2326
2525
 
2327
2526
      /* Actor will then paint silhouette of itself in supplied
2332
2531
    }
2333
2532
  else
2334
2533
    {
 
2534
      CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
 
2535
 
2335
2536
      clutter_actor_shader_pre_paint (self, FALSE);
2336
2537
 
2337
 
      self->priv->queued_redraw = FALSE;
 
2538
      self->priv->propagated_one_redraw = FALSE;
2338
2539
      g_signal_emit (self, actor_signals[PAINT], 0);
2339
2540
 
2340
2541
      clutter_actor_shader_post_paint (self);
2383
2584
  g_object_thaw_notify (G_OBJECT (self));
2384
2585
  g_object_unref (self);
2385
2586
 
2386
 
  if (CLUTTER_ACTOR_IS_VISIBLE (self))
2387
 
    clutter_actor_queue_redraw (self);
 
2587
  clutter_actor_queue_redraw (self);
2388
2588
}
2389
2589
 
2390
2590
static void
2467
2667
      break;
2468
2668
 
2469
2669
    case PROP_OPACITY:
2470
 
      clutter_actor_set_opacity (actor, g_value_get_uchar (value));
 
2670
      clutter_actor_set_opacity (actor, g_value_get_uint (value));
2471
2671
      break;
2472
2672
 
2473
2673
    case PROP_NAME:
2656
2856
      priv->show_on_set_parent = g_value_get_boolean (value);
2657
2857
      break;
2658
2858
 
 
2859
    case PROP_TEXT_DIRECTION:
 
2860
      clutter_actor_set_text_direction (actor, g_value_get_enum (value));
 
2861
      break;
 
2862
 
2659
2863
    default:
2660
2864
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2661
2865
      break;
2746
2950
      break;
2747
2951
 
2748
2952
    case PROP_OPACITY:
2749
 
      g_value_set_uchar (value, priv->opacity);
 
2953
      g_value_set_uint (value, priv->opacity);
2750
2954
      break;
2751
2955
 
2752
2956
    case PROP_NAME:
2909
3113
      g_value_set_boolean (value, priv->show_on_set_parent);
2910
3114
      break;
2911
3115
 
 
3116
    case PROP_TEXT_DIRECTION:
 
3117
      g_value_set_enum (value, priv->text_direction);
 
3118
      break;
 
3119
 
 
3120
    case PROP_HAS_POINTER:
 
3121
      g_value_set_boolean (value, priv->has_pointer);
 
3122
      break;
 
3123
 
2912
3124
    default:
2913
3125
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2914
3126
      break;
2931
3143
    {
2932
3144
      ClutterActor *parent = priv->parent_actor;
2933
3145
 
2934
 
      if (CLUTTER_IS_CONTAINER (parent))
2935
 
        clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
 
3146
      /* go through the Container implementation unless this
 
3147
       * is an internal child and has been marked as such
 
3148
       */
 
3149
      if (CLUTTER_IS_CONTAINER (parent) &&
 
3150
          !(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_INTERNAL_CHILD))
 
3151
        {
 
3152
          clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
 
3153
        }
2936
3154
      else
2937
 
        priv->parent_actor = NULL;
 
3155
        clutter_actor_unparent (self);
2938
3156
    }
2939
3157
 
2940
3158
  /* parent should be gone */
3279
3497
   *   gfloat natural_width, min_width;
3280
3498
   *   gfloat natural_height, min_height;
3281
3499
   *
3282
 
   *   g_object_get (G_OBJECT (child), "request-mode", &amp;mode, NULL);
 
3500
   *   mode = clutter_actor_get_request_mode (child);
3283
3501
   *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
3284
3502
   *     {
3285
3503
   *       clutter_actor_get_preferred_width (child, -1,
3334
3552
  /**
3335
3553
   * ClutterActor:opacity:
3336
3554
   *
3337
 
   * Opacity of the actor, between 0 (fully transparent) and
 
3555
   * Opacity of an actor, between 0 (fully transparent) and
3338
3556
   * 255 (fully opaque)
3339
3557
   */
3340
 
  pspec = g_param_spec_uchar ("opacity",
3341
 
                              "Opacity",
3342
 
                              "Opacity of actor",
3343
 
                              0, 255,
3344
 
                              255,
3345
 
                              CLUTTER_PARAM_READWRITE);
 
3558
  pspec = g_param_spec_uint ("opacity",
 
3559
                             "Opacity",
 
3560
                             "Opacity of an actor",
 
3561
                             0, 255,
 
3562
                             255,
 
3563
                             CLUTTER_PARAM_READWRITE);
3346
3564
  g_object_class_install_property (object_class, PROP_OPACITY, pspec);
3347
3565
 
3348
3566
  /**
3720
3938
                                   PROP_CLIP_TO_ALLOCATION,
3721
3939
                                   pspec);
3722
3940
 
 
3941
  pspec = g_param_spec_enum ("text-direction",
 
3942
                             "Text Direction",
 
3943
                             "Direction of the text",
 
3944
                             CLUTTER_TYPE_TEXT_DIRECTION,
 
3945
                             CLUTTER_TEXT_DIRECTION_LTR,
 
3946
                             CLUTTER_PARAM_READWRITE);
 
3947
  g_object_class_install_property (object_class,
 
3948
                                   PROP_TEXT_DIRECTION,
 
3949
                                   pspec);
 
3950
 
 
3951
  /**
 
3952
   * ClutterActor:has-pointer:
 
3953
   *
 
3954
   * Whether the actor contains the pointer of a #ClutterInputDevice
 
3955
   * or not.
 
3956
   *
 
3957
   * Since: 1.2
 
3958
   */
 
3959
  pspec = g_param_spec_boolean ("has-pointer",
 
3960
                                "Has Pointer",
 
3961
                                "Whether the actor contains the pointer "
 
3962
                                "of an input device",
 
3963
                                FALSE,
 
3964
                                CLUTTER_PARAM_READABLE);
 
3965
  g_object_class_install_property (object_class,
 
3966
                                   PROP_HAS_POINTER,
 
3967
                                   pspec);
 
3968
 
3723
3969
  /**
3724
3970
   * ClutterActor::destroy:
3725
3971
   * @actor: the object which received the signal
3852
4098
                  CLUTTER_TYPE_ACTOR);
3853
4099
 
3854
4100
  /**
 
4101
   * ClutterActor::queue-relayout
 
4102
   * @actor: the actor being queued for relayout
 
4103
   *
 
4104
   * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
 
4105
   * is called on an actor.
 
4106
   *
 
4107
   * The default implementation for #ClutterActor chains up to the
 
4108
   * parent actor and queues a relayout on the parent, thus "bubbling"
 
4109
   * the relayout queue up through the actor graph.
 
4110
   *
 
4111
   * The main purpose of this signal is to allow relayout to be propagated
 
4112
   * properly in the procense of #ClutterClone actors. Applications will
 
4113
   * not normally need to connect to this signal.
 
4114
   *
 
4115
   * Since: 1.2
 
4116
   */
 
4117
  actor_signals[QUEUE_RELAYOUT] =
 
4118
    g_signal_new (I_("queue-relayout"),
 
4119
                  G_TYPE_FROM_CLASS (object_class),
 
4120
                  G_SIGNAL_RUN_LAST,
 
4121
                  G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
 
4122
                  NULL, NULL,
 
4123
                  clutter_marshal_VOID__VOID,
 
4124
                  G_TYPE_NONE, 0);
 
4125
 
 
4126
  /**
3855
4127
   * ClutterActor::event:
3856
4128
   * @actor: the actor which received the event
3857
4129
   * @event: a #ClutterEvent
4262
4534
  klass->get_preferred_height = clutter_actor_real_get_preferred_height;
4263
4535
  klass->allocate = clutter_actor_real_allocate;
4264
4536
  klass->queue_redraw = clutter_actor_real_queue_redraw;
 
4537
  klass->queue_relayout = clutter_actor_real_queue_relayout;
4265
4538
  klass->apply_transform = clutter_actor_real_apply_transform;
4266
4539
}
4267
4540
 
4285
4558
  priv->needs_height_request = TRUE;
4286
4559
  priv->needs_allocation     = TRUE;
4287
4560
 
 
4561
  priv->cached_width_age = 1;
 
4562
  priv->cached_height_age = 1;
 
4563
 
4288
4564
  priv->opacity_parent = NULL;
4289
4565
  priv->enable_model_view_transform = TRUE;
4290
4566
 
4307
4583
void
4308
4584
clutter_actor_destroy (ClutterActor *self)
4309
4585
{
4310
 
  ClutterActorPrivate *priv;
4311
 
 
4312
4586
  g_return_if_fail (CLUTTER_IS_ACTOR (self));
4313
4587
 
4314
 
  priv = self->priv;
4315
 
 
4316
4588
  g_object_ref (self);
4317
4589
 
4318
4590
  /* avoid recursion while destroying */
4359
4631
  clutter_actor_queue_redraw_with_origin (self, self);
4360
4632
}
4361
4633
 
 
4634
static void
 
4635
_clutter_actor_get_allocation_clip (ClutterActor *self,
 
4636
                                    ClutterActorBox *clip)
 
4637
{
 
4638
  ClutterActorBox allocation;
 
4639
 
 
4640
  /* XXX: we don't care if we get an out of date allocation here
 
4641
   * because clutter_actor_queue_redraw_with_origin knows to ignore
 
4642
   * the clip if the actor's allocation is invalid.
 
4643
   *
 
4644
   * This is noted because clutter_actor_get_allocation_box does some
 
4645
   * unnecessary work to support buggy code with a comment suggesting
 
4646
   * that it could be changed later which would be good for this use
 
4647
   * case!
 
4648
   */
 
4649
  clutter_actor_get_allocation_box (self, &allocation);
 
4650
 
 
4651
  /* NB: clutter_actor_queue_clipped_redraw expects a box in the
 
4652
   * actor's own coordinate space but the allocation is in parent
 
4653
   * coordinates */
 
4654
  clip->x1 = 0;
 
4655
  clip->y1 = 0;
 
4656
  clip->x2 = allocation.x2 - allocation.x1;
 
4657
  clip->y2 = allocation.y2 - allocation.y1;
 
4658
}
 
4659
 
 
4660
/*
 
4661
 * clutter_actor_queue_redraw_with_clip:
 
4662
 * @self: A #ClutterActor
 
4663
 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
 
4664
 *   this queue redraw.
 
4665
 * @clip: A #ClutterActorBox describing the bounds of what needs to be
 
4666
 *   redrawn or %NULL if you are just using a @flag to state your
 
4667
 *   desired clipping.
 
4668
 *
 
4669
 * Queues up a clipped redraw of an actor and any children. The redraw
 
4670
 * occurs once the main loop becomes idle (after the current batch of
 
4671
 * events has been processed, roughly).
 
4672
 *
 
4673
 * If the %CLUTTER_REDRAW_CLIPPED_TO_BOX @flag is used, the clip box is
 
4674
 * specified in actor coordinates and tells Clutter that only content
 
4675
 * within this box has been changed so Clutter can optionally optimize
 
4676
 * the redraw.
 
4677
 *
 
4678
 * If you are queuing a clipped redraw it is assumed that the actor is
 
4679
 * flat, and once the clip rectangle is projected into stage
 
4680
 * coordinates it will cover the area of the stage that needs to be
 
4681
 * redrawn. This is not possible to determine for 3D actors since the
 
4682
 * projection of such actors may escape the clip rectangle.
 
4683
 *
 
4684
 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @clip
 
4685
 * should be NULL and this tells Clutter to use the actors current
 
4686
 * allocation as a clip box. As above this flag can only be used for
 
4687
 * 2D actors.
 
4688
 *
 
4689
 * Applications rarely need to call this, as redraws are handled
 
4690
 * automatically by modification functions.
 
4691
 *
 
4692
 * This function will not do anything if @self is not visible, or if
 
4693
 * the actor is inside an invisible part of the scenegraph.
 
4694
 *
 
4695
 * Also be aware that painting is a NOP for actors with an opacity of
 
4696
 * 0
 
4697
 */
 
4698
void
 
4699
_clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
 
4700
                                       ClutterRedrawFlags  flags,
 
4701
                                       ClutterActorBox    *clip)
 
4702
{
 
4703
  ClutterActorBox allocation_clip;
 
4704
 
 
4705
  /* If the actor doesn't have a valid allocation then we will queue a
 
4706
   * full stage redraw */
 
4707
  if (self->priv->needs_allocation)
 
4708
    {
 
4709
      clutter_actor_queue_redraw (self);
 
4710
      return;
 
4711
    }
 
4712
 
 
4713
  /* SYNC_MATRICES is a flag for the stage, which means that we just
 
4714
   * got resized and we need to re-setup the viewport.
 
4715
   * IN_RESIZE is used on X11 where the resize is asynchronous, so we
 
4716
   * don't ask for a viewport change before we have the final size.
 
4717
   *
 
4718
   * If either of these flags are set then we won't be able to
 
4719
   * transform the given clip rectangle into valid stage coordinates,
 
4720
   * so we instead queue a full stage redraw.
 
4721
   *
 
4722
   * (Note: to some extent this is redundant because these flags
 
4723
   *  should imply a full stage redraw will be queued, but we at least
 
4724
   *  avoid needlessly traversing the actors ancestors to derive an
 
4725
   *  incorrect modelview matrix.)
 
4726
   */
 
4727
  if ((CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_SYNC_MATRICES) &&
 
4728
      !(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_STAGE_IN_RESIZE))
 
4729
    {
 
4730
      clutter_actor_queue_redraw (self);
 
4731
      return;
 
4732
    }
 
4733
 
 
4734
  if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
 
4735
    {
 
4736
      _clutter_actor_get_allocation_clip (self, &allocation_clip);
 
4737
      clip = &allocation_clip;
 
4738
    }
 
4739
 
 
4740
  /* XXX: Ideally the redraw signal would take a clip rectangle
 
4741
   * argument, but that would be an ABI break. Until we can break the
 
4742
   * ABI we pass the argument out-of-band via an actor->priv member...
 
4743
   */
 
4744
 
 
4745
  _clutter_actor_set_queue_redraw_clip (self, clip);
 
4746
 
 
4747
  clutter_actor_queue_redraw_with_origin (self, self);
 
4748
 
 
4749
  /* Just in case anyone is manually firing redraw signals without
 
4750
   * using the public queue_redraw() API we are careful to ensure that
 
4751
   * our out-of-band clip member is cleared before returning...
 
4752
   *
 
4753
   * Note: A NULL clip denotes a full-stage, un-clipped redraw
 
4754
   */
 
4755
  _clutter_actor_set_queue_redraw_clip (self, NULL);
 
4756
}
 
4757
 
4362
4758
/**
4363
4759
 * clutter_actor_queue_relayout:
4364
4760
 * @self: A #ClutterActor
4385
4781
      priv->needs_allocation)
4386
4782
    return; /* save some cpu cycles */
4387
4783
 
4388
 
  priv->needs_width_request  = TRUE;
4389
 
  priv->needs_height_request = TRUE;
4390
 
  priv->needs_allocation     = TRUE;
4391
 
 
4392
 
  /* always repaint also (no-op if not mapped) */
4393
 
  clutter_actor_queue_redraw (self);
4394
 
 
4395
 
  /* We need to go all the way up the hierarchy */
4396
 
  if (priv->parent_actor)
4397
 
    clutter_actor_queue_relayout (priv->parent_actor);
 
4784
  if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL) &&
 
4785
      (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_RELAYOUT))
 
4786
    {
 
4787
      g_warning ("The actor '%s' is currently inside an allocation "
 
4788
                 "cycle; calling clutter_actor_queue_relayout() is "
 
4789
                 "not recommended",
 
4790
                 priv->name ? priv->name
 
4791
                            : G_OBJECT_TYPE_NAME (self));
 
4792
    }
 
4793
 
 
4794
  g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
4398
4795
}
4399
4796
 
4400
4797
/**
4431
4828
                                  gfloat       *natural_height_p)
4432
4829
{
4433
4830
  ClutterActorPrivate *priv;
4434
 
  gfloat for_width, for_height;
4435
4831
  gfloat min_width, min_height;
4436
4832
  gfloat natural_width, natural_height;
4437
4833
 
4439
4835
 
4440
4836
  priv = self->priv;
4441
4837
 
4442
 
  for_width = for_height = 0;
4443
4838
  min_width = min_height = 0;
4444
4839
  natural_width = natural_height = 0;
4445
4840
 
4477
4872
    *natural_height_p = natural_height;
4478
4873
}
4479
4874
 
 
4875
/* looks for a cached size request for this for_size. If not
 
4876
 * found, returns the oldest entry so it can be overwritten */
 
4877
static gboolean
 
4878
_clutter_actor_get_cached_size_request (gfloat         for_size,
 
4879
                                        SizeRequest   *cached_size_requests,
 
4880
                                        SizeRequest  **result)
 
4881
{
 
4882
  guint i;
 
4883
 
 
4884
  *result = &cached_size_requests[0];
 
4885
 
 
4886
  for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
 
4887
    {
 
4888
      SizeRequest *sr;
 
4889
 
 
4890
      sr = &cached_size_requests[i];
 
4891
 
 
4892
      if (sr->age > 0 &&
 
4893
          sr->for_size == for_size)
 
4894
        {
 
4895
          CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
 
4896
          *result = sr;
 
4897
          return TRUE;
 
4898
        }
 
4899
      else if (sr->age < (*result)->age)
 
4900
        {
 
4901
          *result = sr;
 
4902
        }
 
4903
    }
 
4904
 
 
4905
  CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
 
4906
 
 
4907
  return FALSE;
 
4908
}
 
4909
 
4480
4910
/**
4481
4911
 * clutter_actor_get_preferred_width:
4482
4912
 * @self: A #ClutterActor
4507
4937
{
4508
4938
  ClutterActorClass *klass;
4509
4939
  ClutterActorPrivate *priv;
 
4940
  gboolean found_in_cache;
 
4941
  SizeRequest *cached_size_request;
4510
4942
 
4511
4943
  g_return_if_fail (CLUTTER_IS_ACTOR (self));
4512
4944
 
4513
4945
  klass = CLUTTER_ACTOR_GET_CLASS (self);
4514
4946
  priv = self->priv;
4515
4947
 
4516
 
  if (priv->needs_width_request ||
4517
 
      priv->request_width_for_height != for_height)
 
4948
  found_in_cache = FALSE;
 
4949
  cached_size_request = &priv->width_requests[0];
 
4950
 
 
4951
  if (!priv->needs_width_request)
 
4952
    found_in_cache = _clutter_actor_get_cached_size_request (for_height,
 
4953
                                                             priv->width_requests,
 
4954
                                                             &cached_size_request);
 
4955
 
 
4956
  if (!found_in_cache)
4518
4957
    {
4519
4958
      gfloat min_width, natural_width;
4520
4959
 
4532
4971
      if (natural_width < min_width)
4533
4972
        natural_width = min_width;
4534
4973
 
4535
 
      if (!priv->min_width_set)
4536
 
        priv->request_min_width = min_width;
4537
 
 
4538
 
      if (!priv->natural_width_set)
4539
 
        priv->request_natural_width = natural_width;
4540
 
 
4541
 
      priv->request_width_for_height = for_height;
 
4974
      cached_size_request->min_size = min_width;
 
4975
      cached_size_request->natural_size = natural_width;
 
4976
      cached_size_request->for_size = for_height;
 
4977
      cached_size_request->age = priv->cached_width_age;
 
4978
 
 
4979
      priv->cached_width_age ++;
4542
4980
      priv->needs_width_request = FALSE;
4543
4981
    }
4544
4982
 
 
4983
  if (!priv->min_width_set)
 
4984
    priv->request_min_width = cached_size_request->min_size;
 
4985
 
 
4986
  if (!priv->natural_width_set)
 
4987
    priv->request_natural_width = cached_size_request->natural_size;
 
4988
 
4545
4989
  if (min_width_p)
4546
4990
    *min_width_p = priv->request_min_width;
4547
4991
 
4578
5022
{
4579
5023
  ClutterActorClass *klass;
4580
5024
  ClutterActorPrivate *priv;
 
5025
  gboolean found_in_cache;
 
5026
  SizeRequest *cached_size_request;
4581
5027
 
4582
5028
  g_return_if_fail (CLUTTER_IS_ACTOR (self));
4583
5029
 
4584
5030
  klass = CLUTTER_ACTOR_GET_CLASS (self);
4585
5031
  priv = self->priv;
4586
5032
 
4587
 
  if (priv->needs_height_request ||
4588
 
      priv->request_height_for_width != for_width)
 
5033
  found_in_cache = FALSE;
 
5034
  cached_size_request = &priv->height_requests[0];
 
5035
 
 
5036
  if (!priv->needs_height_request)
 
5037
    found_in_cache = _clutter_actor_get_cached_size_request (for_width,
 
5038
                                                             priv->height_requests,
 
5039
                                                             &cached_size_request);
 
5040
 
 
5041
  if (!found_in_cache)
4589
5042
    {
4590
5043
      gfloat min_height, natural_height;
4591
5044
 
4592
5045
      min_height = natural_height = 0;
4593
5046
 
4594
 
      CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_width);
 
5047
      CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
4595
5048
 
4596
5049
      klass->get_preferred_height (self, for_width,
4597
5050
                                   &min_height,
4604
5057
        natural_height = min_height;
4605
5058
 
4606
5059
      if (!priv->min_height_set)
4607
 
        priv->request_min_height = min_height;
 
5060
        {
 
5061
          priv->request_min_height = min_height;
 
5062
        }
4608
5063
 
4609
5064
      if (!priv->natural_height_set)
4610
 
        priv->request_natural_height = natural_height;
4611
 
 
4612
 
      priv->request_height_for_width = for_width;
 
5065
        {
 
5066
          priv->request_natural_height = natural_height;
 
5067
        }
 
5068
 
 
5069
      cached_size_request->min_size = min_height;
 
5070
      cached_size_request->natural_size = natural_height;
 
5071
      cached_size_request->for_size = for_width;
 
5072
      cached_size_request->age = priv->cached_height_age;
 
5073
 
 
5074
      priv->cached_height_age ++;
 
5075
 
4613
5076
      priv->needs_height_request = FALSE;
4614
5077
    }
4615
5078
 
 
5079
  if (!priv->min_height_set)
 
5080
    priv->request_min_height = cached_size_request->min_size;
 
5081
 
 
5082
  if (!priv->natural_height_set)
 
5083
    priv->request_natural_height = cached_size_request->natural_size;
 
5084
 
4616
5085
  if (min_height_p)
4617
5086
    *min_height_p = priv->request_min_height;
4618
5087
 
4771
5240
  if (child_moved)
4772
5241
    flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
4773
5242
 
 
5243
  CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_IN_RELAYOUT);
 
5244
 
4774
5245
  klass = CLUTTER_ACTOR_GET_CLASS (self);
4775
5246
  klass->allocate (self, box, flags);
 
5247
 
 
5248
  CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_IN_RELAYOUT);
4776
5249
}
4777
5250
 
4778
5251
/**
5148
5621
  clutter_actor_queue_relayout (self);
5149
5622
}
5150
5623
 
5151
 
static void
5152
 
clutter_actor_set_request_mode (ClutterActor *self,
5153
 
                                ClutterRequestMode mode)
 
5624
/**
 
5625
 * clutter_actor_set_request_mode:
 
5626
 * @self: a #ClutterActor
 
5627
 * @mode: the request mode
 
5628
 *
 
5629
 * Sets the geometry request mode of @self.
 
5630
 *
 
5631
 * The @mode determines the order for invoking
 
5632
 * clutter_actor_get_preferred_width() and
 
5633
 * clutter_actor_get_preferred_height()
 
5634
 *
 
5635
 * Since: 1.2
 
5636
 */
 
5637
void
 
5638
clutter_actor_set_request_mode (ClutterActor       *self,
 
5639
                                ClutterRequestMode  mode)
5154
5640
{
5155
 
  ClutterActorPrivate *priv = self->priv;
 
5641
  ClutterActorPrivate *priv;
 
5642
 
 
5643
  g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
5644
 
 
5645
  priv = self->priv;
5156
5646
 
5157
5647
  if (priv->request_mode == mode)
5158
5648
    return;
5168
5658
}
5169
5659
 
5170
5660
/**
 
5661
 * clutter_actor_get_request_mode:
 
5662
 * @self: a #ClutterActor
 
5663
 *
 
5664
 * Retrieves the geometry request mode of @self
 
5665
 *
 
5666
 * Return value: the request mode for the actor
 
5667
 *
 
5668
 * Since: 1.2
 
5669
 */
 
5670
ClutterRequestMode
 
5671
clutter_actor_get_request_mode (ClutterActor *self)
 
5672
{
 
5673
  g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
 
5674
                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
 
5675
 
 
5676
  return self->priv->request_mode;
 
5677
}
 
5678
 
 
5679
/* variant of set_width() without checks and without notification
 
5680
 * freeze+thaw, for internal usage only
 
5681
 */
 
5682
static inline void
 
5683
clutter_actor_set_width_internal (ClutterActor *self,
 
5684
                                  gfloat        width)
 
5685
{
 
5686
  if (width >= 0)
 
5687
    {
 
5688
      /* the Stage will use the :min-width to control the minimum
 
5689
       * width to be resized to, so we should not be setting it
 
5690
       * along with the :natural-width
 
5691
       */
 
5692
      if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL))
 
5693
        clutter_actor_set_min_width (self, width);
 
5694
 
 
5695
      clutter_actor_set_natural_width (self, width);
 
5696
    }
 
5697
  else
 
5698
    {
 
5699
      /* we only unset the :natural-width for the Stage */
 
5700
      if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL))
 
5701
        clutter_actor_set_min_width_set (self, FALSE);
 
5702
 
 
5703
      clutter_actor_set_natural_width_set (self, FALSE);
 
5704
    }
 
5705
}
 
5706
 
 
5707
/* variant of set_height() without checks and without notification
 
5708
 * freeze+thaw, for internal usage only
 
5709
 */
 
5710
static inline void
 
5711
clutter_actor_set_height_internal (ClutterActor *self,
 
5712
                                   gfloat        height)
 
5713
{
 
5714
  if (height >= 0)
 
5715
    {
 
5716
      /* see the comment above in set_width_internal() */
 
5717
      if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL))
 
5718
        clutter_actor_set_min_height (self, height);
 
5719
 
 
5720
      clutter_actor_set_natural_height (self, height);
 
5721
    }
 
5722
  else
 
5723
    {
 
5724
      /* see the comment above in set_width_internal() */
 
5725
      if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL))
 
5726
        clutter_actor_set_min_height_set (self, FALSE);
 
5727
 
 
5728
      clutter_actor_set_natural_height_set (self, FALSE);
 
5729
    }
 
5730
}
 
5731
 
 
5732
/**
5171
5733
 * clutter_actor_set_size
5172
5734
 * @self: A #ClutterActor
5173
5735
 * @width: New width of actor in pixels, or -1
5193
5755
 
5194
5756
  g_object_freeze_notify (G_OBJECT (self));
5195
5757
 
5196
 
  if (width >= 0)
5197
 
    {
5198
 
      clutter_actor_set_min_width (self, width);
5199
 
      clutter_actor_set_natural_width (self, width);
5200
 
    }
5201
 
  else
5202
 
    {
5203
 
      clutter_actor_set_min_width_set (self, FALSE);
5204
 
      clutter_actor_set_natural_width_set (self, FALSE);
5205
 
    }
5206
 
 
5207
 
  if (height >= 0)
5208
 
    {
5209
 
      clutter_actor_set_min_height (self, height);
5210
 
      clutter_actor_set_natural_height (self, height);
5211
 
    }
5212
 
  else
5213
 
    {
5214
 
      clutter_actor_set_min_height_set (self, FALSE);
5215
 
      clutter_actor_set_natural_height_set (self, FALSE);
5216
 
    }
 
5758
  clutter_actor_set_width_internal (self, width);
 
5759
  clutter_actor_set_height_internal (self, height);
5217
5760
 
5218
5761
  g_object_thaw_notify (G_OBJECT (self));
5219
5762
}
5358
5901
      gfloat natural_width, natural_height;
5359
5902
      ClutterActorBox box;
5360
5903
 
5361
 
      /* make a fake allocation to transform */
5362
 
      clutter_actor_get_position (self, &box.x1, &box.y1);
 
5904
      /* Make a fake allocation to transform.
 
5905
       *
 
5906
       * NB: _clutter_actor_transform_and_project_box expects a box in
 
5907
       * the actor's coordinate space... */
 
5908
 
 
5909
      box.x1 = 0;
 
5910
      box.y1 = 0;
5363
5911
 
5364
5912
      natural_width = natural_height = 0;
5365
5913
      clutter_actor_get_preferred_size (self, NULL, NULL,
5366
5914
                                        &natural_width,
5367
5915
                                        &natural_height);
5368
5916
 
5369
 
      box.x2 = box.x1 + natural_width;
5370
 
      box.y2 = box.y1 + natural_height;
 
5917
      box.x2 = natural_width;
 
5918
      box.y2 = natural_height;
5371
5919
 
5372
 
      clutter_actor_transform_and_project_box (self, &box, v);
 
5920
      _clutter_actor_transform_and_project_box (self, &box, v);
5373
5921
    }
5374
5922
  else
5375
5923
    clutter_actor_get_abs_allocation_vertices (self, v);
5513
6061
/**
5514
6062
 * clutter_actor_set_width
5515
6063
 * @self: A #ClutterActor
5516
 
 * @width: Requested new width for the actor, in pixels
 
6064
 * @width: Requested new width for the actor, in pixels, or -1
5517
6065
 *
5518
6066
 * Forces a width on an actor, causing the actor's preferred width
5519
6067
 * and height (if any) to be ignored.
5520
6068
 *
 
6069
 * If @width is -1 the actor will use its preferred width request
 
6070
 * instead of overriding it, i.e. you can "unset" the width with -1.
 
6071
 *
5521
6072
 * This function sets both the minimum and natural size of the actor.
5522
6073
 *
5523
6074
 * since: 0.2
5524
 
 **/
 
6075
 */
5525
6076
void
5526
6077
clutter_actor_set_width (ClutterActor *self,
5527
6078
                         gfloat        width)
5530
6081
 
5531
6082
  g_object_freeze_notify (G_OBJECT (self));
5532
6083
 
5533
 
  clutter_actor_set_min_width (self, width);
5534
 
  clutter_actor_set_natural_width (self, width);
 
6084
  clutter_actor_set_width_internal (self, width);
5535
6085
 
5536
6086
  g_object_thaw_notify (G_OBJECT (self));
5537
6087
}
5539
6089
/**
5540
6090
 * clutter_actor_set_height
5541
6091
 * @self: A #ClutterActor
5542
 
 * @height: Requested new height for the actor, in pixels
 
6092
 * @height: Requested new height for the actor, in pixels, or -1
5543
6093
 *
5544
6094
 * Forces a height on an actor, causing the actor's preferred width
5545
6095
 * and height (if any) to be ignored.
5546
6096
 *
 
6097
 * If @height is -1 the actor will use its preferred height instead of
 
6098
 * overriding it, i.e. you can "unset" the height with -1.
 
6099
 *
5547
6100
 * This function sets both the minimum and natural size of the actor.
5548
6101
 *
5549
6102
 * since: 0.2
5550
 
 **/
 
6103
 */
5551
6104
void
5552
6105
clutter_actor_set_height (ClutterActor *self,
5553
6106
                          gfloat        height)
5556
6109
 
5557
6110
  g_object_freeze_notify (G_OBJECT (self));
5558
6111
 
5559
 
  clutter_actor_set_min_height (self, height);
5560
 
  clutter_actor_set_natural_height (self, height);
 
6112
  clutter_actor_set_height_internal (self, height);
5561
6113
 
5562
6114
  g_object_thaw_notify (G_OBJECT (self));
5563
6115
}
5701
6253
gfloat
5702
6254
clutter_actor_get_y (ClutterActor *self)
5703
6255
{
 
6256
  ClutterActorPrivate *priv;
 
6257
 
5704
6258
  g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
5705
6259
 
5706
 
  if (self->priv->needs_allocation)
 
6260
  priv = self->priv;
 
6261
 
 
6262
  if (priv->needs_allocation)
5707
6263
    {
5708
 
      if (self->priv->position_set)
5709
 
        return self->priv->fixed_y;
 
6264
      if (priv->position_set)
 
6265
        return priv->fixed_y;
5710
6266
      else
5711
6267
        return 0;
5712
6268
    }
5713
6269
  else
5714
 
    return self->priv->allocation.y1;
 
6270
    return priv->allocation.y1;
5715
6271
}
5716
6272
 
5717
6273
/**
5745
6301
  priv->scale_y = scale_y;
5746
6302
  g_object_notify (G_OBJECT (self), "scale-y");
5747
6303
 
5748
 
  if (CLUTTER_ACTOR_IS_VISIBLE (self))
5749
 
    clutter_actor_queue_redraw (self);
 
6304
  clutter_actor_queue_redraw (self);
5750
6305
 
5751
6306
  g_object_thaw_notify (G_OBJECT (self));
5752
6307
}
5941
6496
    }
5942
6497
}
5943
6498
 
 
6499
/*
 
6500
 * clutter_actor_get_paint_opacity_internal:
 
6501
 * @self: a #ClutterActor
 
6502
 *
 
6503
 * Retrieves the absolute opacity of the actor, as it appears on the stage
 
6504
 *
 
6505
 * This function does not do type checks
 
6506
 *
 
6507
 * Return value: the absolute opacity of the actor
 
6508
 */
 
6509
static guint8
 
6510
clutter_actor_get_paint_opacity_internal (ClutterActor *self)
 
6511
{
 
6512
  ClutterActorPrivate *priv = self->priv;
 
6513
  ClutterActor *parent;
 
6514
 
 
6515
  if (priv->opacity_parent != NULL)
 
6516
    return clutter_actor_get_paint_opacity_internal (priv->opacity_parent);
 
6517
 
 
6518
  parent = priv->parent_actor;
 
6519
 
 
6520
  /* Factor in the actual actors opacity with parents */
 
6521
  if (parent != NULL)
 
6522
    {
 
6523
      guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
 
6524
 
 
6525
      if (opacity != 0xff)
 
6526
        return (opacity * priv->opacity) / 0xff;
 
6527
    }
 
6528
 
 
6529
  return priv->opacity;
 
6530
 
 
6531
}
 
6532
 
5944
6533
/**
5945
6534
 * clutter_actor_get_paint_opacity:
5946
6535
 * @self: A #ClutterActor
5960
6549
guint8
5961
6550
clutter_actor_get_paint_opacity (ClutterActor *self)
5962
6551
{
5963
 
  ClutterActorPrivate *priv;
5964
 
  ClutterActor *parent;
5965
 
 
5966
6552
  g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
5967
6553
 
5968
 
  priv = self->priv;
5969
 
 
5970
 
  if (priv->opacity_parent)
5971
 
    return clutter_actor_get_paint_opacity (priv->opacity_parent);
5972
 
 
5973
 
  parent = priv->parent_actor;
5974
 
 
5975
 
  /* Factor in the actual actors opacity with parents */
5976
 
  if (G_LIKELY (parent))
5977
 
    {
5978
 
      guint8 opacity = clutter_actor_get_paint_opacity (parent);
5979
 
 
5980
 
      if (opacity != 0xff)
5981
 
        return (opacity * priv->opacity) / 0xff;
5982
 
    }
5983
 
 
5984
 
  return clutter_actor_get_opacity (self);
 
6554
  return clutter_actor_get_paint_opacity_internal (self);
5985
6555
}
5986
6556
 
5987
6557
/**
6446
7016
                          ClutterActor *parent)
6447
7017
{
6448
7018
  ClutterActorPrivate *priv;
 
7019
  ClutterTextDirection text_dir;
6449
7020
 
6450
7021
  g_return_if_fail (CLUTTER_IS_ACTOR (self));
6451
7022
  g_return_if_fail (CLUTTER_IS_ACTOR (parent));
6466
7037
      return;
6467
7038
    }
6468
7039
 
 
7040
  if (CLUTTER_PRIVATE_FLAGS (parent) & CLUTTER_ACTOR_IN_DESTRUCTION)
 
7041
    {
 
7042
      g_warning ("Cannot set a parent currently being destroyed");
 
7043
      return;
 
7044
    }
 
7045
 
6469
7046
  g_object_ref_sink (self);
6470
7047
  priv->parent_actor = parent;
6471
7048
 
 
7049
  /* if push_internal() has been called then we automatically set
 
7050
   * the flag on the actor
 
7051
   */
 
7052
  if (parent->priv->internal_child)
 
7053
    CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_INTERNAL_CHILD);
 
7054
 
6472
7055
  /* clutter_actor_reparent() will emit ::parent-set for us */
6473
7056
  if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_REPARENT))
6474
7057
    g_signal_emit (self, actor_signals[PARENT_SET], 0, NULL);
6478
7061
   */
6479
7062
  clutter_actor_update_map_state (self, MAP_STATE_CHECK);
6480
7063
 
 
7064
  /* propagate the parent's text direction to the child */
 
7065
  text_dir = clutter_actor_get_text_direction (parent);
 
7066
  clutter_actor_set_text_direction (self, text_dir);
 
7067
 
6481
7068
  if (priv->show_on_set_parent)
6482
7069
    clutter_actor_show (self);
6483
7070
 
6484
7071
  if (CLUTTER_ACTOR_IS_MAPPED (self))
6485
 
    {
6486
 
      clutter_actor_queue_redraw (self);
6487
 
    }
 
7072
    clutter_actor_queue_redraw (self);
6488
7073
 
6489
7074
  /* maintain the invariant that if an actor needs layout,
6490
7075
   * its parents do as well
6622
7207
 
6623
7208
  if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL)
6624
7209
    {
6625
 
      g_warning ("Cannot set a parent on a toplevel actor\n");
 
7210
      g_warning ("Cannot set a parent on a toplevel actor");
 
7211
      return;
 
7212
    }
 
7213
 
 
7214
  if (CLUTTER_PRIVATE_FLAGS (new_parent) & CLUTTER_ACTOR_IN_DESTRUCTION)
 
7215
    {
 
7216
      g_warning ("Cannot set a parent currently being destroyed");
6626
7217
      return;
6627
7218
    }
6628
7219
 
6638
7229
 
6639
7230
      g_object_ref (self);
6640
7231
 
6641
 
      if (CLUTTER_IS_CONTAINER (priv->parent_actor))
 
7232
      /* go through the Container implementation if this is a regular
 
7233
       * child and not an internal one
 
7234
       */
 
7235
      if (CLUTTER_IS_CONTAINER (priv->parent_actor) &&
 
7236
          !(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_INTERNAL_CHILD))
6642
7237
        {
6643
7238
          ClutterContainer *parent = CLUTTER_CONTAINER (priv->parent_actor);
6644
 
          /* Note, will call unparent() */
 
7239
 
 
7240
          /* this will have to call unparent() */
6645
7241
          clutter_container_remove_actor (parent, self);
6646
7242
        }
6647
7243
      else
6648
7244
        clutter_actor_unparent (self);
6649
7245
 
 
7246
      /* Note, will call parent() */
6650
7247
      if (CLUTTER_IS_CONTAINER (new_parent))
6651
 
          /* Note, will call parent() */
6652
7248
        clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
6653
7249
      else
6654
7250
        clutter_actor_set_parent (self, new_parent);
6671
7267
 *
6672
7268
 * Puts @self above @below.
6673
7269
 *
6674
 
 * Both actors must have the same parent.
 
7270
 * Both actors must have the same parent, and the parent must implement
 
7271
 * the #ClutterContainer interface
6675
7272
 *
6676
7273
 * This function is the equivalent of clutter_container_raise_child().
6677
7274
 */
6684
7281
  g_return_if_fail (CLUTTER_IS_ACTOR (self));
6685
7282
 
6686
7283
  parent = clutter_actor_get_parent (self);
6687
 
  if (!parent)
 
7284
  if (parent == NULL || !CLUTTER_IS_CONTAINER (parent))
6688
7285
    {
6689
 
      g_warning ("Actor of type %s is not inside a container",
6690
 
                 g_type_name (G_OBJECT_TYPE (self)));
 
7286
      g_warning ("%s: Actor '%s' is not inside a container",
 
7287
                 G_STRFUNC,
 
7288
                 self->priv->name != NULL ? self->priv->name
 
7289
                                          : G_OBJECT_TYPE_NAME (self));
6691
7290
      return;
6692
7291
    }
6693
7292
 
6694
 
  if (below)
 
7293
  if (below != NULL)
6695
7294
    {
6696
7295
      if (parent != clutter_actor_get_parent (below))
6697
7296
        {
6698
 
          g_warning ("Actor of type %s is not in the same "
6699
 
                     "container of actor of type %s",
6700
 
                     g_type_name (G_OBJECT_TYPE (self)),
6701
 
                     g_type_name (G_OBJECT_TYPE (below)));
 
7297
          g_warning ("%s Actor '%s' is not in the same container as "
 
7298
                     "actor '%s'",
 
7299
                     G_STRFUNC,
 
7300
                     self->priv->name != NULL ? self->priv->name
 
7301
                                              : G_OBJECT_TYPE_NAME (self),
 
7302
                     below->priv->name != NULL ? below->priv->name
 
7303
                                               : G_OBJECT_TYPE_NAME (below));
6702
7304
          return;
6703
7305
        }
6704
7306
    }
6713
7315
 *
6714
7316
 * Puts @self below @above.
6715
7317
 *
6716
 
 * Both actors must have the same parent.
 
7318
 * Both actors must have the same parent, and the parent must implement
 
7319
 * the #ClutterContainer interface.
6717
7320
 *
6718
7321
 * This function is the equivalent of clutter_container_lower_child().
6719
7322
 */
6726
7329
  g_return_if_fail (CLUTTER_IS_ACTOR(self));
6727
7330
 
6728
7331
  parent = clutter_actor_get_parent (self);
6729
 
  if (!parent)
 
7332
  if (parent == NULL || !CLUTTER_IS_CONTAINER (parent))
6730
7333
    {
6731
 
      g_warning ("Actor of type %s is not inside a container",
6732
 
                 g_type_name (G_OBJECT_TYPE (self)));
 
7334
      g_warning ("%s: Actor of type %s is not inside a container",
 
7335
                 G_STRFUNC,
 
7336
                 self->priv->name != NULL ? self->priv->name
 
7337
                                          : G_OBJECT_TYPE_NAME (self));
6733
7338
      return;
6734
7339
    }
6735
7340
 
6737
7342
    {
6738
7343
      if (parent != clutter_actor_get_parent (above))
6739
7344
        {
6740
 
          g_warning ("Actor of type %s is not in the same "
6741
 
                     "container of actor of type %s",
6742
 
                     g_type_name (G_OBJECT_TYPE (self)),
6743
 
                     g_type_name (G_OBJECT_TYPE (above)));
 
7345
          g_warning ("%s: Actor '%s' is not in the same container as "
 
7346
                     "actor '%s'",
 
7347
                     G_STRFUNC,
 
7348
                     self->priv->name != NULL ? self->priv->name
 
7349
                                              : G_OBJECT_TYPE_NAME (self),
 
7350
                     above->priv->name != NULL ? above->priv->name
 
7351
                                               : G_OBJECT_TYPE_NAME (above));
6744
7352
          return;
6745
7353
        }
6746
7354
    }
6989
7597
 
6990
7598
  clutter_anchor_coord_set_units (&priv->anchor, anchor_x, anchor_y, 0);
6991
7599
 
6992
 
  if (changed && CLUTTER_ACTOR_IS_VISIBLE (self))
 
7600
  if (changed)
6993
7601
    clutter_actor_queue_redraw (self);
6994
7602
 
6995
7603
  g_object_thaw_notify (G_OBJECT (self));
7164
7772
 
7165
7773
  json_node_get_value (node, &value);
7166
7774
 
7167
 
  if (G_VALUE_HOLDS (&value, G_TYPE_INT))
 
7775
  if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
7168
7776
    {
7169
 
      retval = (gfloat) g_value_get_int (&value);
 
7777
      retval = (gfloat) g_value_get_int64 (&value);
7170
7778
    }
7171
7779
  else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
7172
7780
    {
7398
8006
      units = parse_units (actor, dimension, node);
7399
8007
 
7400
8008
      /* convert back to pixels: all properties are pixel-based */
7401
 
      g_value_init (value, G_TYPE_INT);
7402
 
      g_value_set_int (value, units);
 
8009
      g_value_init (value, G_TYPE_FLOAT);
 
8010
      g_value_set_float (value, units);
7403
8011
 
7404
8012
      retval = TRUE;
7405
8013
    }
8130
8738
  box->y2 = y_2;
8131
8739
}
8132
8740
 
 
8741
/**
 
8742
 * clutter_actor_box_interpolate:
 
8743
 * @initial: the initial #ClutterActorBox
 
8744
 * @final: the final #ClutterActorBox
 
8745
 * @progress: the interpolation progress
 
8746
 * @result: (out): return location for the interpolation
 
8747
 *
 
8748
 * Interpolates between @initial and @final #ClutterActorBox<!-- -->es
 
8749
 * using @progress
 
8750
 *
 
8751
 * Since: 1.2
 
8752
 */
 
8753
void
 
8754
clutter_actor_box_interpolate (const ClutterActorBox *initial,
 
8755
                               const ClutterActorBox *final,
 
8756
                               gdouble                progress,
 
8757
                               ClutterActorBox       *result)
 
8758
{
 
8759
  g_return_if_fail (initial != NULL);
 
8760
  g_return_if_fail (final != NULL);
 
8761
  g_return_if_fail (result != NULL);
 
8762
 
 
8763
  result->x1 = initial->x1 + (final->x1 - initial->x1) * progress;
 
8764
  result->y1 = initial->y1 + (final->y1 - initial->y1) * progress;
 
8765
  result->x2 = initial->x2 + (final->x2 - initial->x2) * progress;
 
8766
  result->y2 = initial->y2 + (final->y2 - initial->y2) * progress;
 
8767
}
 
8768
 
 
8769
/**
 
8770
 * clutter_actor_box_clamp_to_pixel:
 
8771
 * @box: (inout): the #ClutterActorBox to clamp
 
8772
 *
 
8773
 * Clamps the components of @box to the nearest integer
 
8774
 *
 
8775
 * Since: 1.2
 
8776
 */
 
8777
void
 
8778
clutter_actor_box_clamp_to_pixel (ClutterActorBox *box)
 
8779
{
 
8780
  g_return_if_fail (box != NULL);
 
8781
 
 
8782
  box->x1 = floorf (box->x1 + 0.5);
 
8783
  box->y1 = floorf (box->y1 + 0.5);
 
8784
  box->x2 = floorf (box->x2 + 0.5);
 
8785
  box->y2 = floorf (box->y2 + 0.5);
 
8786
}
 
8787
 
8133
8788
/******************************************************************************/
8134
8789
 
8135
8790
struct _ShaderData
8372
9027
  g_value_copy (value, var);
8373
9028
  g_hash_table_insert (shader_data->value_hash, g_strdup (param), var);
8374
9029
 
8375
 
  if (CLUTTER_ACTOR_IS_VISIBLE (self))
8376
 
    clutter_actor_queue_redraw (self);
 
9030
  clutter_actor_queue_redraw (self);
8377
9031
}
8378
9032
 
8379
9033
/**
9156
9810
{
9157
9811
  g_return_if_fail (CLUTTER_IS_ACTOR (self));
9158
9812
 
 
9813
  cogl_matrix_init_identity (matrix);
 
9814
 
9159
9815
  CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
9160
9816
}
9161
9817
 
9179
9835
gboolean
9180
9836
clutter_actor_is_in_clone_paint (ClutterActor *self)
9181
9837
{
 
9838
  ClutterActorPrivate *priv;
 
9839
 
9182
9840
  g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9183
9841
 
9184
9842
  /* XXX - keep in sync with the overrides set by ClutterClone:
9187
9845
   *  - enable_model_view_transform == FALSE
9188
9846
   */
9189
9847
 
9190
 
  return self->priv->opacity_parent != NULL &&
9191
 
         !self->priv->enable_model_view_transform;
9192
 
}
 
9848
  priv = self->priv;
 
9849
 
 
9850
  return priv->opacity_parent != NULL &&
 
9851
         !priv->enable_model_view_transform;
 
9852
}
 
9853
 
 
9854
static void
 
9855
set_direction_recursive (ClutterActor *actor,
 
9856
                         gpointer      user_data)
 
9857
{
 
9858
  ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
 
9859
 
 
9860
  clutter_actor_set_text_direction (actor, text_dir);
 
9861
}
 
9862
 
 
9863
/**
 
9864
 * clutter_actor_set_text_direction:
 
9865
 * @self: a #ClutterActor
 
9866
 * @text_dir: the text direction for @self
 
9867
 *
 
9868
 * Sets the #ClutterTextDirection for an actor
 
9869
 *
 
9870
 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
 
9871
 *
 
9872
 * If @self implements #ClutterContainer then this function will recurse
 
9873
 * inside all the children of @self (including the internal ones).
 
9874
 *
 
9875
 * Composite actors not implementing #ClutterContainer, or actors requiring
 
9876
 * special handling when the text direction changes, should connect to
 
9877
 * the #GObject::notify signal for the #ClutterActor:text-direction property
 
9878
 *
 
9879
 * Since: 1.2
 
9880
 */
 
9881
void
 
9882
clutter_actor_set_text_direction (ClutterActor         *self,
 
9883
                                  ClutterTextDirection  text_dir)
 
9884
{
 
9885
  ClutterActorPrivate *priv;
 
9886
 
 
9887
  g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
9888
  g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
 
9889
 
 
9890
  priv = self->priv;
 
9891
 
 
9892
  if (priv->text_direction != text_dir)
 
9893
    {
 
9894
      priv->text_direction = text_dir;
 
9895
 
 
9896
      /* we need to emit the notify::text-direction first, so that
 
9897
       * the sub-classes can catch that and do specific handling of
 
9898
       * the text direction; see clutter_text_direction_changed_cb()
 
9899
       * inside clutter-text.c
 
9900
       */
 
9901
      g_object_notify (G_OBJECT (self), "text-direction");
 
9902
 
 
9903
      /* if this is a container we need to recurse */
 
9904
      if (CLUTTER_IS_CONTAINER (self))
 
9905
        {
 
9906
          ClutterContainer *container = CLUTTER_CONTAINER (self);
 
9907
 
 
9908
          clutter_container_foreach_with_internals (container,
 
9909
                                                    set_direction_recursive,
 
9910
                                                    GINT_TO_POINTER (text_dir));
 
9911
        }
 
9912
 
 
9913
      clutter_actor_queue_relayout (self);
 
9914
    }
 
9915
}
 
9916
 
 
9917
void
 
9918
_clutter_actor_set_has_pointer (ClutterActor *self,
 
9919
                                gboolean      has_pointer)
 
9920
{
 
9921
  ClutterActorPrivate *priv = self->priv;
 
9922
 
 
9923
  if (priv->has_pointer != has_pointer)
 
9924
    {
 
9925
      priv->has_pointer = has_pointer;
 
9926
 
 
9927
      g_object_notify (G_OBJECT (self), "has-pointer");
 
9928
    }
 
9929
}
 
9930
 
 
9931
/**
 
9932
 * clutter_actor_get_text_direction:
 
9933
 * @self: a #ClutterActor
 
9934
 *
 
9935
 * Retrieves the value set using clutter_actor_set_text_direction()
 
9936
 *
 
9937
 * If no text direction has been previously set, the default text
 
9938
 * direction, as returned by clutter_get_default_text_direction(), will
 
9939
 * be returned instead
 
9940
 *
 
9941
 * Return value: the #ClutterTextDirection for the actor
 
9942
 *
 
9943
 * Since: 1.2
 
9944
 */
 
9945
ClutterTextDirection
 
9946
clutter_actor_get_text_direction (ClutterActor *self)
 
9947
{
 
9948
  ClutterActorPrivate *priv;
 
9949
 
 
9950
  g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
 
9951
                        CLUTTER_TEXT_DIRECTION_LTR);
 
9952
 
 
9953
  priv = self->priv;
 
9954
 
 
9955
  /* if no direction has been set yet use the default */
 
9956
  if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
 
9957
    priv->text_direction = clutter_get_default_text_direction ();
 
9958
 
 
9959
  return priv->text_direction;
 
9960
}
 
9961
 
 
9962
/**
 
9963
 * clutter_actor_push_internal:
 
9964
 * @self: a #ClutterActor
 
9965
 *
 
9966
 * Should be used by actors implementing the #ClutterContainer and with
 
9967
 * internal children added through clutter_actor_set_parent(), for instance:
 
9968
 *
 
9969
 * |[
 
9970
 *   static void
 
9971
 *   my_actor_init (MyActor *self)
 
9972
 *   {
 
9973
 *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
 
9974
 *
 
9975
 *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
 
9976
 *
 
9977
 *     /&ast; calling clutter_actor_set_parent() now will result in
 
9978
 *      &ast; the internal flag being set on a child of MyActor
 
9979
 *      &ast;/
 
9980
 *
 
9981
 *     /&ast; internal child: a background texture &ast;/
 
9982
 *     self->priv->background_tex = clutter_texture_new ();
 
9983
 *     clutter_actor_set_parent (self->priv->background_tex,
 
9984
 *                               CLUTTER_ACTOR (self));
 
9985
 *
 
9986
 *     /&ast; internal child: a label &ast;/
 
9987
 *     self->priv->label = clutter_text_new ();
 
9988
 *     clutter_actor_set_parent (self->priv->label,
 
9989
 *                               CLUTTER_ACTOR (self));
 
9990
 *
 
9991
 *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
 
9992
 *
 
9993
 *     /&ast; calling clutter_actor_set_parent() now will not result in
 
9994
 *      &ast; the internal flag being set on a child of MyActor
 
9995
 *      &ast;/
 
9996
 *   }
 
9997
 * ]|
 
9998
 *
 
9999
 * This function will be used by Clutter to toggle an "internal child"
 
10000
 * flag whenever clutter_actor_set_parent() is called; internal children
 
10001
 * are handled differently by Clutter, specifically when destroying their
 
10002
 * parent.
 
10003
 *
 
10004
 * Call clutter_actor_pop_internal() when you finished adding internal
 
10005
 * children.
 
10006
 *
 
10007
 * Nested calls to clutter_actor_push_internal() are allowed, but each
 
10008
 * one must by followed by a clutter_actor_pop_internal() call.
 
10009
 *
 
10010
 * Since: 1.2
 
10011
 */
 
10012
void
 
10013
clutter_actor_push_internal (ClutterActor *self)
 
10014
{
 
10015
  g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
10016
 
 
10017
  self->priv->internal_child += 1;
 
10018
}
 
10019
 
 
10020
/**
 
10021
 * clutter_actor_pop_internal:
 
10022
 * @self: a #ClutterActor
 
10023
 *
 
10024
 * Disables the effects of clutter_actor_pop_internal()
 
10025
 *
 
10026
 * Since: 1.2
 
10027
 */
 
10028
void
 
10029
clutter_actor_pop_internal (ClutterActor *self)
 
10030
{
 
10031
  ClutterActorPrivate *priv;
 
10032
 
 
10033
  g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
10034
 
 
10035
  priv = self->priv;
 
10036
 
 
10037
  if (priv->internal_child == 0)
 
10038
    {
 
10039
      g_warning ("Mismatched %s: you need to call "
 
10040
                 "clutter_actor_push_composite() at least once before "
 
10041
                 "calling this function", G_STRFUNC);
 
10042
      return;
 
10043
    }
 
10044
 
 
10045
  priv->internal_child -= 1;
 
10046
}
 
10047
 
 
10048
/**
 
10049
 * clutter_actor_has_pointer:
 
10050
 * @self: a #ClutterActor
 
10051
 *
 
10052
 * Checks whether an actor contains the the pointer of a
 
10053
 * #ClutterInputDevice
 
10054
 *
 
10055
 * Return value: %TRUE if the actor contains the pointer, and
 
10056
 *   %FALSE otherwise
 
10057
 *
 
10058
 * Since: 1.2
 
10059
 */
 
10060
gboolean
 
10061
clutter_actor_has_pointer (ClutterActor *self)
 
10062
{
 
10063
  g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
 
10064
 
 
10065
  return self->priv->has_pointer;
 
10066
}
 
10067
 
 
10068
/* XXX: This is a workaround for not being able to break the ABI of
 
10069
 * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
 
10070
 * clutter_actor_queue_clipped_redraw() for details.
 
10071
 */
 
10072
const ClutterActorBox *
 
10073
_clutter_actor_get_queue_redraw_clip (ClutterActor *self)
 
10074
{
 
10075
  return self->priv->oob_queue_redraw_clip;
 
10076
}
 
10077
 
 
10078
void
 
10079
_clutter_actor_set_queue_redraw_clip (ClutterActor *self,
 
10080
                                      const ClutterActorBox *clip)
 
10081
{
 
10082
  self->priv->oob_queue_redraw_clip = clip;
 
10083
}
 
10084