From 8c451b8a6733d0193089760b67d61e6056c39675 Mon Sep 17 00:00:00 2001
From: Emmanuele Bassi <ebassi@openedhand.com>
Date: Wed, 20 Feb 2008 10:59:47 +0000
Subject: [PATCH] 2008-02-20  Emmanuele Bassi  <ebassi@openedhand.com>

	* clutter/clutter-actor.h:
	* clutter/clutter-actor.c:
	(clutter_actor_get_abs_opacity): Add function that does what
	get_opacity() does now...

	(clutter_actor_get_opacity): ... and make get_opacity() do what
	it's supposed to be doing. The original get_opacity() returned
	a composited value, and there's no way to actually extract the
	real opacity value set with set_opacity().

	* clutter/clutter-clone-texture.c:
	* clutter/clutter-rectangle.c:
	* clutter/clutter-texture.c: Update to use get_abs_opacity().

	* clutter/clutter-entry.c:
	* clutter/clutter-label.c: Ditto. Also, never change the stored
	alpha value. (#804)

	* tests/Makefile.am:
	* tests/test-opacity.c: Test suite for the get_opacity() and
	get_abs_opacity() API, and correct opacity handling.

	* README: Add note about the change in get_opacity().
---
 ChangeLog                       |  26 ++++++++
 README                          |  13 +++-
 clutter/clutter-actor.c         |  48 +++++++++++--
 clutter/clutter-actor.h         |   1 +
 clutter/clutter-clone-texture.c |   2 +-
 clutter/clutter-entry.c         |   7 +-
 clutter/clutter-label.c         |   6 +-
 clutter/clutter-rectangle.c     |   9 ++-
 clutter/clutter-texture.c       |   3 +-
 tests/Makefile.am               |   6 +-
 tests/test-opacity.c            | 115 ++++++++++++++++++++++++++++++++
 11 files changed, 215 insertions(+), 21 deletions(-)
 create mode 100644 tests/test-opacity.c

diff --git a/ChangeLog b/ChangeLog
index e7b437367..e2d13a809 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2008-02-20  Emmanuele Bassi  <ebassi@openedhand.com>
+
+	* clutter/clutter-actor.h:
+	* clutter/clutter-actor.c:
+	(clutter_actor_get_abs_opacity): Add function that does what
+	get_opacity() does now...
+
+	(clutter_actor_get_opacity): ... and make get_opacity() do what
+	it's supposed to be doing. The original get_opacity() returned
+	a composited value, and there's no way to actually extract the
+	real opacity value set with set_opacity().
+
+	* clutter/clutter-clone-texture.c:
+	* clutter/clutter-rectangle.c:
+	* clutter/clutter-texture.c: Update to use get_abs_opacity().
+
+	* clutter/clutter-entry.c:
+	* clutter/clutter-label.c: Ditto. Also, never change the stored
+	alpha value. (#804)
+
+	* tests/Makefile.am:
+	* tests/test-opacity.c: Test suite for the get_opacity() and
+	get_abs_opacity() API, and correct opacity handling.
+
+	* README: Add note about the change in get_opacity().
+
 2008-02-19  Chris Lord  <chris@openedhand.com>
 
 	* clutter/clutter-model.c: (clutter_model_resort):
diff --git a/README b/README
index 9303e473f..70e92575f 100644
--- a/README
+++ b/README
@@ -140,7 +140,7 @@ RELEASE NOTES
 Relevant information for developers with existing Clutter applications
 wanting to port to newer releases (See NEWS for general new feature info).
 
-Release Notes for Clutter 0.6.0
+Release Notes for Clutter 0.6
 -------------------------------
 
 * Now that every actor has events, the class signal handlers have been
@@ -229,6 +229,17 @@ Release Notes for Clutter 0.6.0
   clutter_entry_set_cursor_position() and clutter_entry_get_cursor_position()
   respectively.
 
+* The behaviour of clutter_actor_get_opacity() has been slightly changed;
+  instead of returning the composited opacity of the entire parents chain
+  of an actor, clutter_actor_get_opacity() does what you mean, and returns
+  the opacity set with clutter_actor_set_opacity(). The composited
+  opacity value is now returned by clutter_actor_get_abs_opacity().
+
+* Until 0.6.0, clutter_label_get_color() would have returned a ClutterColor
+  with the alpha component equal to the composited opacity of the label.
+  Now, clutter_label_get_color() returns a copy of the exact color set
+  with clutter_label_set_color().
+
 Release Notes for Clutter 0.4.0
 -------------------------------
 
diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c
index fe4e837e5..95e2b9885 100644
--- a/clutter/clutter-actor.c
+++ b/clutter/clutter-actor.c
@@ -3345,25 +3345,61 @@ clutter_actor_set_opacity (ClutterActor *self,
 }
 
 /**
- * clutter_actor_get_opacity:
+ * clutter_actor_get_abs_opacity:
  * @self: A #ClutterActor
  *
- * Retrieves the actor's opacity.
+ * Retrieves the absolute opacity of the actor, as it appears on the stage.
+ *
+ * This function traverses the hierarchy chain and composites the opacity of
+ * the actor with that of its parents.
+ *
+ * This function is intended for subclasses to use in the paint virtual
+ * function, to paint themselves with the correct opacity.
  *
  * Return value: The actor opacity value.
+ *
+ * Since: 0.6
  */
 guint8
-clutter_actor_get_opacity (ClutterActor *self)
+clutter_actor_get_abs_opacity (ClutterActor *self)
 {
+  ClutterActorPrivate *priv;
   ClutterActor *parent;
 
   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
 
-  parent = self->priv->parent_actor;
+  priv = self->priv;
+
+  parent = priv->parent_actor;
 
   /* Factor in the actual actors opacity with parents */
-  if (parent && clutter_actor_get_opacity (parent) != 0xff)
-      return (clutter_actor_get_opacity(parent) * self->priv->opacity) / 0xff;
+  if (G_LIKELY (parent))
+    {
+      guint8 opacity = clutter_actor_get_abs_opacity (parent);
+
+      if (opacity != 0xff)
+        return (opacity * priv->opacity) / 0xff;
+    }
+
+  return clutter_actor_get_opacity (self);
+}
+
+/**
+ * clutter_actor_get_opacity:
+ * @self: a #ClutterActor
+ *
+ * Retrieves the opacity value of an actor, as set by
+ * clutter_actor_set_opacity().
+ *
+ * For retrieving the absolute opacity of the actor inside a paint
+ * virtual function, see clutter_actor_get_abs_opacity().
+ *
+ * Return value: the opacity of the actor
+ */
+guint8
+clutter_actor_get_opacity (ClutterActor *self)
+{
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
 
   return self->priv->opacity;
 }
diff --git a/clutter/clutter-actor.h b/clutter/clutter-actor.h
index f71ddc3cf..1ad5b541e 100644
--- a/clutter/clutter-actor.h
+++ b/clutter/clutter-actor.h
@@ -360,6 +360,7 @@ ClutterFixed          clutter_actor_get_rotationx            (ClutterActor
 void                  clutter_actor_set_opacity              (ClutterActor          *self,
                                                               guint8                 opacity);
 guint8                clutter_actor_get_opacity              (ClutterActor          *self);
+guint8                clutter_actor_get_abs_opacity          (ClutterActor          *self);
 void                  clutter_actor_set_name                 (ClutterActor          *self,
                                                               const gchar           *name);
 G_CONST_RETURN gchar *clutter_actor_get_name                 (ClutterActor          *self);
diff --git a/clutter/clutter-clone-texture.c b/clutter/clutter-clone-texture.c
index 6643dcac1..7a1de598a 100644
--- a/clutter/clutter-clone-texture.c
+++ b/clutter/clutter-clone-texture.c
@@ -213,7 +213,7 @@ clutter_clone_texture_paint (ClutterActor *self)
       cogl_enable (CGL_ENABLE_TEXTURE_2D|CGL_ENABLE_BLEND);
     }
 
-  col.alpha = clutter_actor_get_opacity (self);
+  col.alpha = clutter_actor_get_abs_opacity (self);
   cogl_color (&col);
 
   clutter_actor_get_coords (self, &x_1, &y_1, &x_2, &y_2);
diff --git a/clutter/clutter-entry.c b/clutter/clutter-entry.c
index a9671265f..f73fa7268 100644
--- a/clutter/clutter-entry.c
+++ b/clutter/clutter-entry.c
@@ -396,6 +396,7 @@ clutter_entry_paint (ClutterActor *self)
   gint                  width, actor_width;
   gint                  text_width;
   gint                  cursor_x;
+  ClutterColor          color = { 0, };
 
   entry  = CLUTTER_ENTRY(self);
   priv   = entry->priv;
@@ -465,10 +466,12 @@ clutter_entry_paint (ClutterActor *self)
       priv->cursor_pos.x += priv->entry_padding;
     }
 
-  priv->fgcol.alpha = clutter_actor_get_opacity (self);
+  memcpy (&color, &priv->fgcol, sizeof (ClutterColor));
+  color.alpha = clutter_actor_get_abs_opacity (self);
+
   pango_clutter_render_layout (priv->layout,
                                priv->text_x + priv->entry_padding, 0,
-                               &priv->fgcol, 0);
+                               &color, 0);
 
   if (CLUTTER_ENTRY_GET_CLASS (entry)->paint_cursor)
     CLUTTER_ENTRY_GET_CLASS (entry)->paint_cursor (entry);
diff --git a/clutter/clutter-label.c b/clutter/clutter-label.c
index 11de65aed..15c492923 100644
--- a/clutter/clutter-label.c
+++ b/clutter/clutter-label.c
@@ -288,6 +288,7 @@ clutter_label_paint (ClutterActor *self)
 {
   ClutterLabel        *label = CLUTTER_LABEL (self);
   ClutterLabelPrivate *priv = label->priv;
+  ClutterColor color = { 0, };
 
   if (priv->font_desc == NULL || priv->text == NULL)
     {
@@ -302,9 +303,10 @@ clutter_label_paint (ClutterActor *self)
 
   clutter_label_ensure_layout (label);
 
-  priv->fgcol.alpha = clutter_actor_get_opacity (self);
+  memcpy (&color, &priv->fgcol, sizeof (ClutterColor));
+  color.alpha = clutter_actor_get_abs_opacity (self);
 
-  pango_clutter_render_layout (priv->layout, 0, 0, &priv->fgcol, 0);
+  pango_clutter_render_layout (priv->layout, 0, 0, &color, 0);
 }
 
 static void
diff --git a/clutter/clutter-rectangle.c b/clutter/clutter-rectangle.c
index 950dc1700..e7d9833ad 100644
--- a/clutter/clutter-rectangle.c
+++ b/clutter/clutter-rectangle.c
@@ -96,7 +96,7 @@ clutter_rectangle_paint (ClutterActor *self)
       tmp_col.red   = priv->border_color.red;
       tmp_col.green = priv->border_color.green;
       tmp_col.blue  = priv->border_color.blue;
-      tmp_col.alpha = clutter_actor_get_opacity (self);
+      tmp_col.alpha = clutter_actor_get_abs_opacity (self);
 
       cogl_color (&tmp_col);
 
@@ -134,7 +134,7 @@ clutter_rectangle_paint (ClutterActor *self)
       tmp_col.red   = priv->color.red;
       tmp_col.green = priv->color.green;
       tmp_col.blue  = priv->color.blue;
-      tmp_col.alpha = clutter_actor_get_opacity (self);
+      tmp_col.alpha = clutter_actor_get_abs_opacity (self);
 
       cogl_color (&tmp_col);
 
@@ -392,8 +392,7 @@ clutter_rectangle_set_color (ClutterRectangle   *rectangle,
   priv->color.blue = color->blue;
   priv->color.alpha = color->alpha;
 
-  clutter_actor_set_opacity (CLUTTER_ACTOR (rectangle),
-		  	       priv->color.alpha);
+  clutter_actor_set_opacity (CLUTTER_ACTOR (rectangle), priv->color.alpha);
 
 #if 0
   /* FIXME - appears to be causing border to always get drawn */
@@ -403,7 +402,7 @@ clutter_rectangle_set_color (ClutterRectangle   *rectangle,
     priv->has_border = TRUE;
 #endif
 
-  if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (rectangle)))
+  if (CLUTTER_ACTOR_IS_VISIBLE (rectangle))
     clutter_actor_queue_redraw (CLUTTER_ACTOR (rectangle));
 
   g_object_notify (G_OBJECT (rectangle), "color");
diff --git a/clutter/clutter-texture.c b/clutter/clutter-texture.c
index f1c35d09e..fc28e9607 100644
--- a/clutter/clutter-texture.c
+++ b/clutter/clutter-texture.c
@@ -847,8 +847,7 @@ clutter_texture_paint (ClutterActor *self)
       break;
     }
 
-  col.alpha = clutter_actor_get_opacity (self);
-
+  col.alpha = clutter_actor_get_abs_opacity (self);
   cogl_color (&col);
 
   clutter_actor_get_coords (self, &x_1, &y_1, &x_2, &y_2);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index e6f869841..d529f3e6f 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -3,7 +3,8 @@ noinst_PROGRAMS = test-textures test-events test-offscreen test-scale \
 		  test-perspective test-rotate test-depth \
 		  test-threads test-timeline test-score test-script \
 		  test-model test-grab test-effects test-fullscreen \
-		  test-shader test-unproject test-viewport test-fbo
+		  test-shader test-unproject test-viewport test-fbo \
+		  test-opacity
 
 INCLUDES = -I$(top_srcdir)/
 LDADD = $(top_builddir)/clutter/libclutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR@.la
@@ -33,6 +34,7 @@ test_model_SOURCES       = test-model.c
 test_effects_SOURCES     = test-effects.c
 test_fullscreen_SOURCES  = test-fullscreen.c
 test_viewport_SOURCES    = test-viewport.c
-test_fbo_SOURCES    = test-fbo.c
+test_fbo_SOURCES         = test-fbo.c
+test_opacity_SOURCES     = test-opacity.c
 
 EXTRA_DIST = redhand.png test-script.json
diff --git a/tests/test-opacity.c b/tests/test-opacity.c
new file mode 100644
index 000000000..6fac2ffaf
--- /dev/null
+++ b/tests/test-opacity.c
@@ -0,0 +1,115 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <glib.h>
+
+#include <clutter/clutter.h>
+
+int
+main (int argc, char *argv[])
+{
+  ClutterActor *stage, *group1, *group2, *label, *rect;
+  ClutterColor label_color = { 255, 0, 0, 128 };
+  ClutterColor rect_color = { 0, 0, 255, 255 };
+  ClutterColor color_check = { 0, };
+
+  clutter_init (&argc, &argv);
+
+  stage = clutter_stage_get_default ();
+
+  label = clutter_label_new_with_text ("Sans 18px", "Label, 50% opacity");
+  clutter_label_set_color (CLUTTER_LABEL (label), &label_color);
+
+  g_print ("label 50%%.get_color()/1\n");
+  clutter_label_get_color (CLUTTER_LABEL (label), &color_check);
+  g_assert (color_check.alpha == label_color.alpha);
+
+  clutter_container_add (CLUTTER_CONTAINER (stage), label, NULL);
+  clutter_actor_set_position (label, 10, 10);
+
+  g_print ("label 50%%.get_color()/2\n");
+  clutter_label_get_color (CLUTTER_LABEL (label), &color_check);
+  g_assert (color_check.alpha == label_color.alpha);
+
+  g_print ("label 50%%.get_abs_opacity() = %d\n",
+           clutter_actor_get_abs_opacity (label));
+  g_assert (clutter_actor_get_abs_opacity (label) == 128);
+
+  clutter_actor_show (label);
+
+  group1 = clutter_group_new ();
+  clutter_actor_set_opacity (group1, 128);
+  clutter_container_add (CLUTTER_CONTAINER (stage), group1, NULL);
+  clutter_actor_set_position (group1, 10, 30);
+  clutter_actor_show (group1);
+
+  label = clutter_label_new_with_text ("Sans 18px", "Label+Group, 25% opacity");
+
+  clutter_label_set_color (CLUTTER_LABEL (label), &label_color);
+
+  g_print ("label 50%% + group 50%%.get_color()/1\n");
+  clutter_label_get_color (CLUTTER_LABEL (label), &color_check);
+  g_assert (color_check.alpha == label_color.alpha);
+
+  clutter_container_add (CLUTTER_CONTAINER (group1), label, NULL);
+
+  g_print ("label 50%% + group 50%%.get_color()/2\n");
+  clutter_label_get_color (CLUTTER_LABEL (label), &color_check);
+  g_assert (color_check.alpha == label_color.alpha);
+
+  g_print ("label 50%% + group 50%%.get_abs_opacity() = %d\n",
+           clutter_actor_get_abs_opacity (label));
+  g_assert (clutter_actor_get_abs_opacity (label) == 64);
+
+  clutter_actor_show (label);
+
+  group2 = clutter_group_new ();
+  clutter_container_add (CLUTTER_CONTAINER (group1), group2, NULL);
+  clutter_actor_set_position (group2, 10, 60);
+  clutter_actor_show (group2);
+
+  rect = clutter_rectangle_new_with_color (&rect_color);
+  clutter_actor_set_size (rect, 128, 128);
+
+  g_print ("rect 100%% + group 100%% + group 50%%.get_color()/1\n");
+  clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
+  g_assert (color_check.alpha == rect_color.alpha);
+
+  clutter_container_add (CLUTTER_CONTAINER (group2), rect, NULL);
+
+  g_print ("rect 100%% + group 100%% + group 50%%.get_color()/2\n");
+  clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
+  g_assert (color_check.alpha == rect_color.alpha);
+
+  g_print ("rect 100%%.get_abs_opacity() = %d\n",
+           clutter_actor_get_abs_opacity (rect));
+  g_assert (clutter_actor_get_abs_opacity (rect) == 128);
+
+  clutter_actor_show (rect);
+
+  rect = clutter_rectangle_new_with_color (&rect_color);
+  clutter_actor_set_size (rect, 128, 128);
+  clutter_actor_set_position (rect, 150, 90);
+
+  g_print ("rect 100%%.get_color()/1\n");
+  clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
+  g_assert (color_check.alpha == rect_color.alpha);
+
+  clutter_container_add (CLUTTER_CONTAINER (stage), rect, NULL);
+
+  g_print ("rect 100%%.get_color()/2\n");
+  clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
+  g_assert (color_check.alpha == rect_color.alpha);
+
+  g_print ("rect 100%%.get_abs_opacity() = %d\n",
+           clutter_actor_get_abs_opacity (rect));
+  g_assert (clutter_actor_get_abs_opacity (rect) == 255);
+
+  clutter_actor_show (rect);
+
+  clutter_actor_show_all (stage);
+
+  clutter_main ();
+
+  return EXIT_SUCCESS;
+}