[gtk+/rgba-texttags] Added GdkRGBA properties to GtkTextTag.



commit 29b5dcaf9c5e9c89e3e4d2c02c4c8e57b909890c
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Wed Feb 9 23:41:39 2011 +0900

    Added GdkRGBA properties to GtkTextTag.
    
    This now allows text view to render text with alpha values in
    the text foreground and backgrounds, the work is almost complete,
    currently the error-underline-color is still a GdkColor style property
    and since we use only GdkRGBA for rendering it needs to be converted
    and applied, probably a new rgba version of the style property should
    also be introduced.
    
    This commit adds tests/testtextview that must be run from the tests/
    directory to show translucent text in action.

 gtk/gtktextattributes.c |   68 +++++++++++++++--
 gtk/gtktextattributes.h |    8 ++-
 gtk/gtktextdisplay.c    |  100 ++++++++++---------------
 gtk/gtktextlayout.c     |   28 +++++++-
 gtk/gtktextlayout.h     |    1 +
 gtk/gtktexttag.c        |  192 ++++++++++++++++++++++++++++++++++++++++-------
 tests/Makefile.am       |    8 ++-
 tests/testtextview.c    |  151 +++++++++++++++++++++++++++++++++++++
 8 files changed, 458 insertions(+), 98 deletions(-)
---
diff --git a/gtk/gtktextattributes.c b/gtk/gtktextattributes.c
index d2a9c6c..98048fb 100644
--- a/gtk/gtktextattributes.c
+++ b/gtk/gtktextattributes.c
@@ -68,10 +68,9 @@ gtk_text_attributes_new (void)
 {
   GtkTextAttributes *values;
 
-  values = g_new0 (GtkTextAttributes, 1);
+  values = g_slice_new0 (GtkTextAttributes);
 
   /* 0 is a valid value for most of the struct */
-
   values->refcount = 1;
 
   values->language = gtk_get_default_language ();
@@ -124,10 +123,24 @@ gtk_text_attributes_copy_values (GtkTextAttributes *src,
     return;
 
   /* Remove refs */
+  if (dest->tabs)
+    pango_tab_array_free (dest->tabs);
 
   if (dest->font)
     pango_font_description_free (dest->font);
+
+  if (dest->pg_bg_color)
+    gdk_color_free (dest->pg_bg_color);
+
+  if (dest->pg_bg_rgba)
+    gdk_rgba_free (dest->pg_bg_rgba);
+
+  if (dest->appearance.rgba[0])
+    gdk_rgba_free (dest->appearance.rgba[0]);
   
+  if (dest->appearance.rgba[1])
+    gdk_rgba_free (dest->appearance.rgba[1]);
+
   /* Copy */
   orig_refcount = dest->refcount;
 
@@ -144,6 +157,15 @@ gtk_text_attributes_copy_values (GtkTextAttributes *src,
   if (src->pg_bg_color)
     dest->pg_bg_color = gdk_color_copy (src->pg_bg_color);
 
+  if (src->pg_bg_rgba)
+    dest->pg_bg_rgba = gdk_rgba_copy (src->pg_bg_rgba);
+
+  if (src->appearance.rgba[0])
+    dest->appearance.rgba[0] = gdk_rgba_copy (src->appearance.rgba[0]);
+
+  if (src->appearance.rgba[1])
+    dest->appearance.rgba[1] = gdk_rgba_copy (src->appearance.rgba[1]);
+
   dest->refcount = orig_refcount;
 }
 
@@ -191,7 +213,16 @@ gtk_text_attributes_unref (GtkTextAttributes *values)
       if (values->pg_bg_color)
 	gdk_color_free (values->pg_bg_color);
 
-      g_free (values);
+      if (values->pg_bg_rgba)
+	gdk_rgba_free (values->pg_bg_rgba);
+
+      if (values->appearance.rgba[0])
+	gdk_rgba_free (values->appearance.rgba[0]);
+
+      if (values->appearance.rgba[1])
+	gdk_rgba_free (values->appearance.rgba[1]);
+
+      g_slice_free (GtkTextAttributes, values);
     }
 }
 
@@ -216,16 +247,41 @@ _gtk_text_attributes_fill_from_tags (GtkTextAttributes *dest,
 
       if (tag->priv->bg_color_set)
         {
-          dest->appearance.bg_color = vals->appearance.bg_color;
+	  if (dest->appearance.rgba[0])
+	    {
+	      gdk_rgba_free (dest->appearance.rgba[0]);
+	      dest->appearance.rgba[0] = NULL;
+	    }
+
+	  if (vals->appearance.rgba[0])
+	    dest->appearance.rgba[0] = gdk_rgba_copy (vals->appearance.rgba[0]);
 
           dest->appearance.draw_bg = TRUE;
         }
+
       if (tag->priv->fg_color_set)
-        dest->appearance.fg_color = vals->appearance.fg_color;
+	{
+	  if (dest->appearance.rgba[1])
+	    {
+	      gdk_rgba_free (dest->appearance.rgba[1]);
+	      dest->appearance.rgba[1] = NULL;
+	    }
+
+	  if (vals->appearance.rgba[1])
+	    dest->appearance.rgba[1] = gdk_rgba_copy (vals->appearance.rgba[1]);
+	}
 
       if (tag->priv->pg_bg_color_set)
         {
-          dest->pg_bg_color = gdk_color_copy (vals->pg_bg_color);
+	  if (dest->pg_bg_rgba)
+	    {
+	      gdk_rgba_free (dest->pg_bg_rgba);
+	      dest->pg_bg_rgba = NULL;
+
+	    }
+
+	  if (vals->pg_bg_rgba)
+	    dest->pg_bg_rgba = gdk_rgba_copy (vals->pg_bg_rgba);
         }
 
       if (vals->font)
diff --git a/gtk/gtktextattributes.h b/gtk/gtktextattributes.h
index aa7d6f8..87b0b8a 100644
--- a/gtk/gtktextattributes.h
+++ b/gtk/gtktextattributes.h
@@ -102,8 +102,10 @@ struct _GtkTextAppearance
   guint inside_selection : 1;
   guint is_text : 1;
 
+  GdkRGBA *rgba[2];
+
   /*< private >*/
-  guint padding[4];
+  guint padding[2];
 };
 
 struct _GtkTextAttributes
@@ -155,7 +157,9 @@ struct _GtkTextAttributes
   guint editable : 1;
 
   /*< private >*/
-  guint padding[4];
+  GdkRGBA *pg_bg_rgba;
+
+  guint padding[3];
 };
 
 GtkTextAttributes* gtk_text_attributes_new         (void);
diff --git a/gtk/gtktextdisplay.c b/gtk/gtktextdisplay.c
index 383f52d..04a0c57 100644
--- a/gtk/gtktextdisplay.c
+++ b/gtk/gtktextdisplay.c
@@ -110,8 +110,11 @@ struct _GtkTextRenderer
   
   GdkColor *error_color;	/* Error underline color for this widget */
   GList *widgets;		/* widgets encountered when drawing */
-  
-  int state;
+
+  GdkRGBA rgba[4];
+  guint8  rgba_set[4];
+
+  guint state : 2;
 };
 
 struct _GtkTextRendererClass
@@ -122,45 +125,34 @@ struct _GtkTextRendererClass
 G_DEFINE_TYPE (GtkTextRenderer, _gtk_text_renderer, PANGO_TYPE_RENDERER)
 
 static void
-text_renderer_set_gdk_color (GtkTextRenderer *text_renderer,
-			     PangoRenderPart  part,
-			     GdkColor        *gdk_color)
-{
-  PangoRenderer *renderer = PANGO_RENDERER (text_renderer);
-
-  if (gdk_color)
-    {
-      PangoColor color;
-
-      color.red = gdk_color->red;
-      color.green = gdk_color->green;
-      color.blue = gdk_color->blue;
-      
-      pango_renderer_set_color (renderer, part, &color);
-    }
-  else
-    pango_renderer_set_color (renderer, part, NULL);
-}
-
-static void
 text_renderer_set_rgba (GtkTextRenderer *text_renderer,
 			PangoRenderPart  part,
-			GdkRGBA         *rgba)
+			const GdkRGBA   *rgba)
 {
   PangoRenderer *renderer = PANGO_RENDERER (text_renderer);
+  PangoColor     dummy = { 0, };
+
+  if ((!rgba && !text_renderer->rgba_set[part]) ||
+      (rgba && text_renderer->rgba_set[part] &&
+       text_renderer->rgba[part].red == rgba->red &&
+       text_renderer->rgba[part].green == rgba->green &&
+       text_renderer->rgba[part].blue == rgba->blue &&
+       text_renderer->rgba[part].alpha == rgba->alpha))
+    return;
 
   if (rgba)
     {
-      PangoColor color;
+      text_renderer->rgba_set[part] = TRUE;
+      text_renderer->rgba[part] = *rgba;
 
-      color.red = CLAMP (rgba->red * 65535. + 0.5, 0, 65535);
-      color.green = CLAMP (rgba->green * 65535. + 0.5, 0, 65535);
-      color.blue = CLAMP (rgba->blue * 65535. + 0.5, 0, 65535);
-
-      pango_renderer_set_color (renderer, part, &color);
+      pango_renderer_set_color (renderer, part, &dummy);
     }
   else
-    pango_renderer_set_color (renderer, part, NULL);
+    {
+      text_renderer->rgba_set[part] = FALSE;
+
+      pango_renderer_set_color (renderer, part, NULL);
+    }
 }
 
 static GtkTextAppearance *
@@ -188,9 +180,8 @@ gtk_text_renderer_prepare_run (PangoRenderer  *renderer,
   GtkStyleContext *context;
   GtkStateFlags state;
   GtkTextRenderer *text_renderer = GTK_TEXT_RENDERER (renderer);
-  GdkColor *bg_color = NULL;
+  GdkRGBA *bg_rgba = NULL;
   GdkRGBA *fg_rgba = NULL;
-  GdkColor *fg_color = NULL;
   GtkTextAppearance *appearance;
 
   PANGO_RENDERER_CLASS (_gtk_text_renderer_parent_class)->prepare_run (renderer, run);
@@ -199,15 +190,14 @@ gtk_text_renderer_prepare_run (PangoRenderer  *renderer,
   g_assert (appearance != NULL);
 
   context = gtk_widget_get_style_context (text_renderer->widget);
-
-  state = gtk_widget_get_state_flags (text_renderer->widget);
+  state   = gtk_widget_get_state_flags (text_renderer->widget);
 
   if (appearance->draw_bg && text_renderer->state == NORMAL)
-    bg_color = &appearance->bg_color;
+    bg_rgba = appearance->rgba[0];
   else
-    bg_color = NULL;
+    bg_rgba = NULL;
   
-  text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_BACKGROUND, bg_color);
+  text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_BACKGROUND, bg_rgba);
 
   if (text_renderer->state == SELECTED)
     {
@@ -224,18 +214,10 @@ gtk_text_renderer_prepare_run (PangoRenderer  *renderer,
                               NULL);
     }
   else
-    fg_color = &appearance->fg_color;
+    fg_rgba = appearance->rgba[1];
 
-  if (fg_rgba)
-    {
-      text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_FOREGROUND, fg_rgba);
-      text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_STRIKETHROUGH,fg_rgba);
-    }
-  else
-    {
-      text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_FOREGROUND, fg_color);
-      text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_STRIKETHROUGH, fg_color);
-    }
+  text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_FOREGROUND, fg_rgba);
+  text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_STRIKETHROUGH,fg_rgba);
 
   if (appearance->underline == PANGO_UNDERLINE_ERROR)
     {
@@ -252,28 +234,24 @@ gtk_text_renderer_prepare_run (PangoRenderer  *renderer,
             }
         }
 
-      text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_UNDERLINE, text_renderer->error_color);
+      // XXX Transform the gdk color to an gdk rgba here 
+      //text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_UNDERLINE, text_renderer->error_color);
     }
-  else if (fg_rgba)
-    text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_UNDERLINE, fg_rgba);
   else
-    text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_UNDERLINE, fg_color);
+    text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_UNDERLINE, fg_rgba);
+
+  if (fg_rgba != appearance->rgba[1])
+    gdk_rgba_free (fg_rgba);
 }
 
 static void
 set_color (GtkTextRenderer *text_renderer,
            PangoRenderPart  part)
 {
-  PangoColor *color;
-
   cairo_save (text_renderer->cr);
 
-  color = pango_renderer_get_color (PANGO_RENDERER (text_renderer), part);
-  if (color)
-    cairo_set_source_rgb (text_renderer->cr,
-                          color->red / 65535.,
-                          color->green / 65535.,
-                          color->blue / 65535.);
+  if (text_renderer->rgba_set[part])
+    gdk_cairo_set_source_rgba (text_renderer->cr, &text_renderer->rgba[part]);
 }
 
 static void
diff --git a/gtk/gtktextlayout.c b/gtk/gtktextlayout.c
index 3580987..f19ab61 100644
--- a/gtk/gtktextlayout.c
+++ b/gtk/gtktextlayout.c
@@ -1424,9 +1424,27 @@ gtk_text_attr_appearance_destroy (PangoAttribute *attr)
 {
   GtkTextAttrAppearance *appearance_attr = (GtkTextAttrAppearance *)attr;
 
+  if (appearance_attr->appearance.rgba[0])
+    gdk_rgba_free (appearance_attr->appearance.rgba[0]);
+
+  if (appearance_attr->appearance.rgba[1])
+    gdk_rgba_free (appearance_attr->appearance.rgba[1]);
+
   g_slice_free (GtkTextAttrAppearance, appearance_attr);
 }
 
+static gboolean 
+rgba_equal (const GdkRGBA *rgba1, const GdkRGBA *rgba2)
+{
+  if (rgba1 && rgba2)
+    return gdk_rgba_equal (rgba1, rgba2);
+  
+  if (rgba1 || rgba2)
+    return FALSE;
+
+  return TRUE;
+}
+
 static gboolean
 gtk_text_attr_appearance_compare (const PangoAttribute *attr1,
                                   const PangoAttribute *attr2)
@@ -1434,8 +1452,8 @@ gtk_text_attr_appearance_compare (const PangoAttribute *attr1,
   const GtkTextAppearance *appearance1 = &((const GtkTextAttrAppearance *)attr1)->appearance;
   const GtkTextAppearance *appearance2 = &((const GtkTextAttrAppearance *)attr2)->appearance;
 
-  return (gdk_color_equal (&appearance1->fg_color, &appearance2->fg_color) &&
-          gdk_color_equal (&appearance1->bg_color, &appearance2->bg_color) &&
+  return (rgba_equal (appearance1->rgba[0], appearance2->rgba[0]) &&
+          rgba_equal (appearance1->rgba[1], appearance2->rgba[1]) &&
           appearance1->underline == appearance2->underline &&
           appearance1->strikethrough == appearance2->strikethrough &&
           appearance1->draw_bg == appearance2->draw_bg);
@@ -1472,6 +1490,12 @@ gtk_text_attr_appearance_new (const GtkTextAppearance *appearance)
 
   result->appearance = *appearance;
 
+  if (appearance->rgba[0])
+    result->appearance.rgba[0] = gdk_rgba_copy (appearance->rgba[0]);
+
+  if (appearance->rgba[1])
+    result->appearance.rgba[1] = gdk_rgba_copy (appearance->rgba[1]);
+
   return (PangoAttribute *)result;
 }
 
diff --git a/gtk/gtktextlayout.h b/gtk/gtktextlayout.h
index 4d83532..f2cc859 100644
--- a/gtk/gtktextlayout.h
+++ b/gtk/gtktextlayout.h
@@ -233,6 +233,7 @@ struct _GtkTextCursorDisplay
   guint is_strong : 1;
   guint is_weak : 1;
 };
+
 struct _GtkTextLineDisplay
 {
   PangoLayout *layout;
diff --git a/gtk/gtktexttag.c b/gtk/gtktexttag.c
index 1a653b3..dbfb5ae 100644
--- a/gtk/gtktexttag.c
+++ b/gtk/gtktexttag.c
@@ -92,6 +92,8 @@ enum {
   PROP_FOREGROUND,
   PROP_BACKGROUND_GDK,
   PROP_FOREGROUND_GDK,
+  PROP_BACKGROUND_RGBA,
+  PROP_FOREGROUND_RGBA,
   PROP_FONT,
   PROP_FONT_DESC,
   PROP_FAMILY,
@@ -121,6 +123,7 @@ enum {
   PROP_INVISIBLE,
   PROP_PARAGRAPH_BACKGROUND,
   PROP_PARAGRAPH_BACKGROUND_GDK,
+  PROP_PARAGRAPH_BACKGROUND_RGBA,
 
   /* Behavior args */
   PROP_ACCUMULATIVE_MARGIN,
@@ -206,6 +209,15 @@ gtk_text_tag_class_init (GtkTextTagClass *klass)
                                                        GDK_TYPE_COLOR,
                                                        GTK_PARAM_READWRITE));
 
+
+  g_object_class_install_property (object_class,
+                                   PROP_BACKGROUND_RGBA,
+                                   g_param_spec_boxed ("background-rgba",
+                                                       P_("Background rgba"),
+                                                       P_("Background rgba as a (possibly unallocated) GdkRGBA"),
+                                                       GDK_TYPE_RGBA,
+                                                       GTK_PARAM_READWRITE));
+
   g_object_class_install_property (object_class,
                                    PROP_BACKGROUND_FULL_HEIGHT,
                                    g_param_spec_boolean ("background-full-height",
@@ -231,6 +243,14 @@ gtk_text_tag_class_init (GtkTextTagClass *klass)
                                                        GTK_PARAM_READWRITE));
 
   g_object_class_install_property (object_class,
+                                   PROP_FOREGROUND_RGBA,
+                                   g_param_spec_boxed ("foreground-rgba",
+                                                       P_("Foreground rgba"),
+                                                       P_("Foreground rgba as a (possibly unallocated) GdkRGBA"),
+                                                       GDK_TYPE_RGBA,
+                                                       GTK_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
                                    PROP_DIRECTION,
                                    g_param_spec_enum ("direction",
                                                       P_("Text direction"),
@@ -532,6 +552,22 @@ gtk_text_tag_class_init (GtkTextTagClass *klass)
                                                        GTK_PARAM_READWRITE));
 
   /**
+   * GtkTextTag:paragraph-background-rgba:
+   *
+   * The paragraph background color as a as a (possibly unallocated) 
+   * #GdkRGBA.
+   *
+   * Since: 3.2
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_PARAGRAPH_BACKGROUND_RGBA,
+                                   g_param_spec_boxed ("paragraph-background-rgba",
+                                                       P_("Paragraph background rgba"),
+                                                       P_("Paragraph background rgba as a (possibly unallocated) GdkRGBA"),
+                                                       GDK_TYPE_RGBA,
+                                                       GTK_PARAM_READWRITE));
+
+  /**
    * GtkTextTag:accumulative-margin:
    *
    * Whether the margins accumulate or override each other.
@@ -740,11 +776,16 @@ gtk_text_tag_finalize (GObject *object)
 }
 
 static void
-set_bg_color (GtkTextTag *tag, GdkColor *color)
+set_bg_rgba (GtkTextTag *tag, GdkRGBA *rgba)
 {
   GtkTextTagPrivate *priv = tag->priv;
 
-  if (color)
+  if (priv->values->appearance.rgba[0])
+    gdk_rgba_free (priv->values->appearance.rgba[0]);
+
+  priv->values->appearance.rgba[0] = NULL;
+
+  if (rgba)
     {
       if (!priv->bg_color_set)
         {
@@ -752,7 +793,7 @@ set_bg_color (GtkTextTag *tag, GdkColor *color)
           g_object_notify (G_OBJECT (tag), "background-set");
         }
 
-      priv->values->appearance.bg_color = *color;
+      priv->values->appearance.rgba[0] = gdk_rgba_copy (rgba);
     }
   else
     {
@@ -765,18 +806,24 @@ set_bg_color (GtkTextTag *tag, GdkColor *color)
 }
 
 static void
-set_fg_color (GtkTextTag *tag, GdkColor *color)
+set_fg_rgba (GtkTextTag *tag, GdkRGBA *rgba)
 {
   GtkTextTagPrivate *priv = tag->priv;
 
-  if (color)
+  if (priv->values->appearance.rgba[1])
+    gdk_rgba_free (priv->values->appearance.rgba[1]);
+
+  priv->values->appearance.rgba[1] = NULL;
+
+  if (rgba)
     {
       if (!priv->fg_color_set)
         {
           priv->fg_color_set = TRUE;
           g_object_notify (G_OBJECT (tag), "foreground-set");
         }
-      priv->values->appearance.fg_color = *color;
+
+      priv->values->appearance.rgba[1] = gdk_rgba_copy (rgba);
     }
   else
     {
@@ -789,21 +836,24 @@ set_fg_color (GtkTextTag *tag, GdkColor *color)
 }
 
 static void
-set_pg_bg_color (GtkTextTag *tag, GdkColor *color)
+set_pg_bg_rgba (GtkTextTag *tag, GdkRGBA *rgba)
 {
   GtkTextTagPrivate *priv = tag->priv;
 
-  if (color)
+  if (priv->values->pg_bg_rgba)
+    gdk_rgba_free (priv->values->pg_bg_rgba);
+
+  priv->values->pg_bg_rgba = NULL;
+
+  if (rgba)
     {
       if (!priv->pg_bg_color_set)
         {
           priv->pg_bg_color_set = TRUE;
           g_object_notify (G_OBJECT (tag), "paragraph-background-set");
         }
-      else
-	gdk_color_free (priv->values->pg_bg_color);
 
-      priv->values->pg_bg_color = gdk_color_copy (color);
+      priv->values->pg_bg_rgba = gdk_rgba_copy (rgba);
     }
   else
     {
@@ -811,11 +861,63 @@ set_pg_bg_color (GtkTextTag *tag, GdkColor *color)
         {
           priv->pg_bg_color_set = FALSE;
           g_object_notify (G_OBJECT (tag), "paragraph-background-set");
-	  gdk_color_free (priv->values->pg_bg_color);
         }
+    }
+}
 
-      priv->values->pg_bg_color = NULL;
+
+static void
+set_bg_color (GtkTextTag *tag, GdkColor *color)
+{
+  if (color)
+    {
+      gchar  *str;
+      GdkRGBA rgba;
+
+      str = gdk_color_to_string (color);
+      gdk_rgba_parse (&rgba, str);
+      g_free (str);
+
+      set_bg_rgba (tag, &rgba);
     }
+  else
+    set_bg_rgba (tag, NULL);
+}
+
+static void
+set_fg_color (GtkTextTag *tag, GdkColor *color)
+{
+  if (color)
+    {
+      gchar  *str;
+      GdkRGBA rgba;
+
+      str = gdk_color_to_string (color);
+      gdk_rgba_parse (&rgba, str);
+      g_free (str);
+
+      set_fg_rgba (tag, &rgba);
+    }
+  else
+    set_fg_rgba (tag, NULL);
+}
+
+static void
+set_pg_bg_color (GtkTextTag *tag, GdkColor *color)
+{
+  if (color)
+    {
+      gchar  *str;
+      GdkRGBA rgba;
+
+      str = gdk_color_to_string (color);
+      gdk_rgba_parse (&rgba, str);
+      g_free (str);
+
+      set_pg_bg_rgba (tag, &rgba);
+    }
+  else
+    set_pg_bg_rgba (tag, NULL);
 }
 
 static PangoFontMask
@@ -998,12 +1100,12 @@ gtk_text_tag_set_property (GObject      *object,
 
     case PROP_BACKGROUND:
       {
-        GdkColor color;
+        GdkRGBA rgba;
 
         if (!g_value_get_string (value))
-          set_bg_color (text_tag, NULL);       /* reset to background_set to FALSE */
-        else if (gdk_color_parse (g_value_get_string (value), &color))
-          set_bg_color (text_tag, &color);
+          set_bg_rgba (text_tag, NULL);       /* reset background_set to FALSE */
+        else if (gdk_rgba_parse (&rgba, g_value_get_string (value)))
+          set_bg_rgba (text_tag, &rgba);
         else
           g_warning ("Don't know color `%s'", g_value_get_string (value));
 
@@ -1013,12 +1115,12 @@ gtk_text_tag_set_property (GObject      *object,
 
     case PROP_FOREGROUND:
       {
-        GdkColor color;
+        GdkRGBA rgba;
 
         if (!g_value_get_string (value))
-          set_fg_color (text_tag, NULL);       /* reset to foreground_set to FALSE */
-        else if (gdk_color_parse (g_value_get_string (value), &color))
-          set_fg_color (text_tag, &color);
+          set_fg_rgba (text_tag, NULL);       /* reset to foreground_set to FALSE */
+        else if (gdk_rgba_parse (&rgba, g_value_get_string (value)))
+          set_fg_rgba (text_tag, &rgba);
         else
           g_warning ("Don't know color `%s'", g_value_get_string (value));
 
@@ -1042,6 +1144,22 @@ gtk_text_tag_set_property (GObject      *object,
       }
       break;
 
+    case PROP_BACKGROUND_RGBA:
+      {
+        GdkRGBA *color = g_value_get_boxed (value);
+
+        set_bg_rgba (text_tag, color);
+      }
+      break;
+
+    case PROP_FOREGROUND_RGBA:
+      {
+        GdkRGBA *color = g_value_get_boxed (value);
+
+        set_fg_rgba (text_tag, color);
+      }
+      break;
+
     case PROP_FONT:
       {
         PangoFontDescription *font_desc = NULL;
@@ -1255,12 +1373,12 @@ gtk_text_tag_set_property (GObject      *object,
       
     case PROP_PARAGRAPH_BACKGROUND:
       {
-        GdkColor color;
+        GdkRGBA rgba;
 
         if (!g_value_get_string (value))
-          set_pg_bg_color (text_tag, NULL);       /* reset to paragraph_background_set to FALSE */
-        else if (gdk_color_parse (g_value_get_string (value), &color))
-          set_pg_bg_color (text_tag, &color);
+          set_pg_bg_rgba (text_tag, NULL);       /* reset paragraph_background_set to FALSE */
+        else if (gdk_rgba_parse (&rgba, g_value_get_string (value)))
+          set_pg_bg_rgba (text_tag, &rgba);
         else
           g_warning ("Don't know color `%s'", g_value_get_string (value));
 
@@ -1276,6 +1394,14 @@ gtk_text_tag_set_property (GObject      *object,
       }
       break;
 
+    case PROP_PARAGRAPH_BACKGROUND_RGBA:
+      {
+        GdkRGBA *color = g_value_get_boxed (value);
+
+        set_pg_bg_rgba (text_tag, color);
+      }
+      break;
+
     case PROP_ACCUMULATIVE_MARGIN:
       priv->accumulative_margin = g_value_get_boolean (value);
       g_object_notify (object, "accumulative-margin");
@@ -1429,6 +1555,7 @@ gtk_text_tag_get_property (GObject      *object,
 {
   GtkTextTag *tag = GTK_TEXT_TAG (object);
   GtkTextTagPrivate *priv = tag->priv;
+  GdkColor color = { 0, };
 
   switch (prop_id)
     {
@@ -1437,10 +1564,22 @@ gtk_text_tag_get_property (GObject      *object,
       break;
 
     case PROP_BACKGROUND_GDK:
-      g_value_set_boxed (value, &priv->values->appearance.bg_color);
+      if (priv->values->appearance.rgba[0])
+	{
+	  color.red   = CLAMP (priv->values->appearance.rgba[0]->red,   0.0, 1.0) * 65535.0;
+	  color.green = CLAMP (priv->values->appearance.rgba[0]->green, 0.0, 1.0) * 65535.0;
+	  color.blue  = CLAMP (priv->values->appearance.rgba[0]->blue,  0.0, 1.0) * 65535.0;
+	}
+      g_value_set_boxed (value, &color);
       break;
 
     case PROP_FOREGROUND_GDK:
+      if (priv->values->appearance.rgba[1])
+	{
+	  color.red   = CLAMP (priv->values->appearance.rgba[1]->red,   0.0, 1.0) * 65535.0;
+	  color.green = CLAMP (priv->values->appearance.rgba[1]->green, 0.0, 1.0) * 65535.0;
+	  color.blue  = CLAMP (priv->values->appearance.rgba[1]->blue,  0.0, 1.0) * 65535.0;
+	}
       g_value_set_boxed (value, &priv->values->appearance.fg_color);
       break;
 
@@ -1574,6 +1713,7 @@ gtk_text_tag_get_property (GObject      *object,
       break;
       
     case PROP_PARAGRAPH_BACKGROUND_GDK:
+      /* XXX Transform the GdkRGBA here */
       g_value_set_boxed (value, priv->values->pg_bg_color);
       break;
 
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 8aaabf7..d99b023 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -106,7 +106,8 @@ noinst_PROGRAMS =  $(TEST_PROGS)	\
 	testtoplevelembed		\
 	testnoscreen			\
 	testtreepos			\
-	testsensitive
+	testsensitive			\
+	testtextview
 
 if USE_X11
 noinst_PROGRAMS += testerrors
@@ -205,6 +206,7 @@ testtoplevelembed_DEPENDENCIES = $(TEST_DEPS)
 testnoscreen_DEPENDENCIES = $(TEST_DEPS)
 testtreepos_DEPENDENCIES = $(TEST_DEPS)
 testsensitive_DEPENDENCIES = $(TEST_DEPS)
+testtextview_DEPENDENCIES = $(TEST_DEPS)
 
 flicker_LDADD = $(LDADDS)
 simple_LDADD = $(LDADDS)
@@ -289,6 +291,7 @@ testtoplevelembed_LDADD = $(LDADDS)
 testnoscreen_LDADD = $(LDADDS)
 testtreepos_LDADD = $(LDADDS)
 testsensitive_LDADD = $(LDADDS)
+testtextview_LDADD = $(LDADDS)
 
 
 testentrycompletion_SOURCES = 	\
@@ -434,6 +437,9 @@ styleexamples_SOURCES = styleexamples.c
 
 testtoplevelembed_SOURCES = testtoplevelembed.c
 
+testtextview_SOURCES = testtextview.c
+
+
 EXTRA_DIST += 			\
 	gradient1.png		\
 	prop-editor.h		\
diff --git a/tests/testtextview.c b/tests/testtextview.c
new file mode 100644
index 0000000..2a7701f
--- /dev/null
+++ b/tests/testtextview.c
@@ -0,0 +1,151 @@
+
+
+#include "config.h"
+#include <gtk/gtk.h>
+
+
+static void
+create_tags (GtkTextBuffer *buffer)
+{
+
+  gtk_text_buffer_create_tag (buffer, "italic",
+                              "style", PANGO_STYLE_ITALIC, NULL);
+
+  gtk_text_buffer_create_tag (buffer, "bold",
+                              "weight", PANGO_WEIGHT_BOLD, NULL);
+
+  gtk_text_buffer_create_tag (buffer, "x-large",
+                              "scale", PANGO_SCALE_X_LARGE, NULL);
+
+  gtk_text_buffer_create_tag (buffer, "semi_blue_foreground",
+                              "foreground", "rgba(0,0,255,0.5)", NULL);
+
+  gtk_text_buffer_create_tag (buffer, "semi_red_background",
+                              "background", "rgba(255,0,0,0.5)", NULL);
+
+  gtk_text_buffer_create_tag (buffer, "word_wrap",
+                              "wrap_mode", GTK_WRAP_WORD, NULL);
+}
+
+
+static void
+insert_text (GtkTextBuffer *buffer)
+{
+  GtkTextIter iter;
+  GtkTextIter start, end;
+
+  /* get start of buffer; each insertion will revalidate the
+   * iterator to point to just after the inserted text.
+   */
+  gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
+
+  gtk_text_buffer_insert (buffer, &iter,
+      "This test shows text view rendering some text with rgba colors.\n\n", -1);
+
+  gtk_text_buffer_insert (buffer, &iter, "For example, you can have ", -1);
+  gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
+                                            "italic translucent blue text", -1,
+                                            "italic", 
+					    "semi_blue_foreground",
+					    "x-large",
+					    NULL);
+
+  gtk_text_buffer_insert (buffer, &iter, ", or ", -1);
+
+  gtk_text_buffer_insert (buffer, &iter, ", ", -1);
+  gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
+                                            "bold text with translucent red background", -1,
+                                            "bold", 
+					    "semi_red_background",
+					    "x-large",
+					    NULL);
+  gtk_text_buffer_insert (buffer, &iter, ".", -1);
+
+  /* Apply word_wrap tag to whole buffer */
+  gtk_text_buffer_get_bounds (buffer, &start, &end);
+  gtk_text_buffer_apply_tag_by_name (buffer, "word_wrap", &start, &end);
+}
+
+
+static cairo_pattern_t *
+get_pattern (void)
+{
+  static cairo_pattern_t *static_pattern = NULL;
+
+  if (!static_pattern)
+    {
+      cairo_surface_t *surface = 
+	cairo_image_surface_create_from_png ("gradient1.png");
+
+      if (surface)
+	{
+	  static_pattern = cairo_pattern_create_for_surface (surface);
+	  cairo_pattern_set_extend (static_pattern, CAIRO_EXTEND_REFLECT);
+	}
+      else 
+	g_warning ("Failed to create surface for gradient1.png\n");
+    }
+  return static_pattern;
+}
+
+static void
+draw_background (GtkWidget *widget, cairo_t *cr)
+{
+  GtkAllocation allocation;
+  cairo_pattern_t *pat;
+  
+  gtk_widget_get_allocation (widget, &allocation);
+
+  cairo_save (cr);
+
+#if 0
+  pat = cairo_pattern_create_linear (0.0, 0.0,  30.0, 30.0);
+  cairo_pattern_add_color_stop_rgba (pat, 1, 0, 0, 0, 1);
+  cairo_pattern_add_color_stop_rgba (pat, 0, 1, 1, 1, 1);
+  cairo_pattern_set_extend (pat, CAIRO_EXTEND_REPEAT);
+  cairo_rectangle (cr, 0, 0, allocation.width, allocation.height);
+  cairo_set_source (cr, pat);
+  cairo_fill (cr);
+  cairo_pattern_destroy (pat);
+
+#else
+
+  if (get_pattern ())
+    {
+      cairo_rectangle (cr, 0, 0, allocation.width, allocation.height);
+      cairo_set_source (cr, get_pattern ());
+      cairo_fill (cr);
+    }
+#endif
+
+  cairo_restore (cr);
+}
+
+int
+main (int argc, char **argv)
+{
+  GtkWidget *window, *textview;
+  GtkTextBuffer *buffer;
+
+  gtk_init (&argc, &argv);
+
+  window   = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  textview = gtk_text_view_new ();
+  buffer   = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
+
+  create_tags (buffer);
+  insert_text (buffer);
+  
+  gtk_widget_show (textview);
+  gtk_container_add (GTK_CONTAINER (window), textview);
+
+  g_signal_connect (textview, "draw",
+		    G_CALLBACK (draw_background), NULL);
+
+
+  gtk_widget_show (window);
+
+  gtk_main ();
+
+  return 0;
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]