[gtk+/rendering-cleanup: 49/75] label: Draw all text using gtk_paint_layout()



commit d9652763f48fcd3449dcd9edacaa2233cfaaa775
Author: Benjamin Otte <otte redhat com>
Date:   Wed Jul 21 14:23:22 2010 +0200

    label: Draw all text using gtk_paint_layout()
    
    Previously, selected areas were overdrawn gdk_draw_layout(). Now we
    insert the proper Pango markup to modify foreground and background
    colors of the selection or active anchors. This way, we can use
    gtk_paint_layout() unconditionally.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=624917

 gtk/gtklabel.c |  223 +++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 139 insertions(+), 84 deletions(-)
---
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index 07a1f4e..21d8518 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -223,6 +223,8 @@ static gboolean gtk_label_motion            (GtkWidget        *widget,
 					     GdkEventMotion   *event);
 static gboolean gtk_label_leave_notify      (GtkWidget        *widget,
                                              GdkEventCrossing *event);
+static gboolean gtk_label_focus_out         (GtkWidget        *widget,
+                                             GdkEventFocus    *event);
 
 static void     gtk_label_grab_focus        (GtkWidget        *widget);
 
@@ -408,6 +410,7 @@ gtk_label_class_init (GtkLabelClass *class)
   widget_class->button_release_event = gtk_label_button_release;
   widget_class->motion_notify_event = gtk_label_motion;
   widget_class->leave_notify_event = gtk_label_leave_notify;
+  widget_class->focus_out_event = gtk_label_focus_out;
   widget_class->hierarchy_changed = gtk_label_hierarchy_changed;
   widget_class->screen_changed = gtk_label_screen_changed;
   widget_class->mnemonic_activate = gtk_label_mnemonic_activate;
@@ -3164,6 +3167,120 @@ get_label_wrap_width (GtkLabel *label)
 }
 
 static void
+gtk_label_update_color (PangoAttrList *attrs,
+                        guint          start,
+                        guint          end,
+                        GdkColor      *foreground,
+                        GdkColor      *background)
+{
+  PangoAttribute *attr;
+
+  attr = pango_attr_background_new (background->red,
+                                    background->green,
+                                    background->blue);
+  attr->start_index = start;
+  attr->end_index = end;
+  pango_attr_list_change (attrs, attr);
+
+  attr = pango_attr_foreground_new (foreground->red,
+                                    foreground->green,
+                                    foreground->blue);
+  attr->start_index = start;
+  attr->end_index = end;
+  pango_attr_list_change (attrs, attr);
+
+}
+
+static void
+gtk_label_update_layout_attributes (GtkLabel *label)
+{
+  GtkWidget *widget = GTK_WIDGET (label);
+  GtkLabelPriv *priv = label->priv;
+  GtkLabelSelectionInfo *info;
+  PangoAttrList *attrs;
+  GtkStateType state;
+  guint start, end;
+
+  if (priv->layout == NULL)
+    return;
+
+  if (priv->select_info == NULL)
+    {
+      if (priv->effective_attrs)
+        pango_layout_set_attributes (priv->layout, priv->effective_attrs);
+
+      return;
+    }
+
+  info = priv->select_info;
+
+  if (priv->effective_attrs)
+    attrs = pango_attr_list_copy (priv->effective_attrs);
+  else
+    attrs = pango_attr_list_new ();
+
+  if (info->selection_anchor != info->selection_end)
+    {
+
+      start = info->selection_anchor;
+      end = info->selection_end;
+
+      if (start > end)
+        {
+          guint tmp = start;
+          start = end;
+          end = tmp;
+        }
+
+      state = GTK_STATE_SELECTED;
+      if (!gtk_widget_has_focus (widget))
+        state = GTK_STATE_ACTIVE;
+
+      gtk_label_update_color (attrs,
+                              start, end, 
+                              &widget->style->text[state],
+                              &widget->style->base[state]);
+    }
+  else
+    {
+      GtkLabelLink *active_link;
+      GdkColor *text_color;
+      GdkColor *base_color;
+      GdkColor *link_color;
+      GdkColor *visited_link_color;
+
+      active_link = info->active_link;
+
+      if (active_link)
+        {
+          start = active_link->start;
+          end = active_link->end;
+
+          gtk_label_get_link_colors (widget, &link_color, &visited_link_color);
+          if (active_link->visited)
+            text_color = visited_link_color;
+          else
+            text_color = link_color;
+          if (info->link_clicked)
+            base_color = &widget->style->base[GTK_STATE_ACTIVE];
+          else
+            base_color = &widget->style->base[GTK_STATE_PRELIGHT];
+
+          gtk_label_update_color (attrs,
+                                  start, end, 
+                                  text_color,
+                                  base_color);
+
+          gdk_color_free (link_color);
+          gdk_color_free (visited_link_color);
+        }
+    }
+
+  pango_layout_set_attributes (priv->layout, attrs);
+  pango_attr_list_unref (attrs);
+}
+
+static void
 gtk_label_ensure_layout (GtkLabel *label, gboolean guess_wrap_width)
 {
   GtkLabelPriv *priv = label->priv;
@@ -3204,8 +3321,7 @@ gtk_label_ensure_layout (GtkLabel *label, gboolean guess_wrap_width)
 
       priv->layout = gtk_widget_create_pango_layout (widget, priv->text);
 
-      if (priv->effective_attrs)
-	pango_layout_set_attributes (priv->layout, priv->effective_attrs);
+      gtk_label_update_layout_attributes (label);
 
       gtk_label_rescan_links (label);
 
@@ -4098,99 +4214,18 @@ gtk_label_expose (GtkWidget      *widget,
                         priv->layout);
 
       if (info &&
-          (info->selection_anchor != info->selection_end))
-        {
-          gint range[2];
-          cairo_region_t *clip;
-	  GtkStateType state;
-
-          range[0] = info->selection_anchor;
-          range[1] = info->selection_end;
-
-          if (range[0] > range[1])
-            {
-              gint tmp = range[0];
-              range[0] = range[1];
-              range[1] = tmp;
-            }
-
-          clip = gdk_pango_layout_get_clip_region (priv->layout,
-                                                   x, y,
-                                                   range,
-                                                   1);
-	  cairo_region_intersect (clip, event->region);
-
-         /* FIXME should use gtk_paint, but it can't use a clip
-           * region
-           */
-
-          gdk_gc_set_clip_region (widget->style->black_gc, clip);
-
-
-	  state = GTK_STATE_SELECTED;
-	  if (!gtk_widget_has_focus (widget))
-	    state = GTK_STATE_ACTIVE;
-
-          gdk_draw_layout_with_colors (widget->window,
-                                       widget->style->black_gc,
-                                       x, y,
-                                       priv->layout,
-                                       &widget->style->text[state],
-                                       &widget->style->base[state]);
-
-          gdk_gc_set_clip_region (widget->style->black_gc, NULL);
-          cairo_region_destroy (clip);
-        }
-      else if (info)
+          (info->selection_anchor == info->selection_end))
         {
           GtkLabelLink *focus_link;
           GtkLabelLink *active_link;
           gint range[2];
           cairo_region_t *clip;
           GdkRectangle rect;
-          GdkColor *text_color;
-          GdkColor *base_color;
-          GdkColor *link_color;
-          GdkColor *visited_link_color;
 
           if (info->selectable && gtk_widget_has_focus (widget))
 	    gtk_label_draw_cursor (label, x, y);
 
           focus_link = gtk_label_get_focus_link (label);
-          active_link = info->active_link;
-
-          if (active_link)
-            {
-              range[0] = active_link->start;
-              range[1] = active_link->end;
-
-              clip = gdk_pango_layout_get_clip_region (priv->layout,
-                                                       x, y,
-                                                       range,
-                                                       1);
-              gdk_gc_set_clip_region (widget->style->black_gc, clip);
-
-              gtk_label_get_link_colors (widget, &link_color, &visited_link_color);
-              if (active_link->visited)
-                text_color = visited_link_color;
-              else
-                text_color = link_color;
-              if (info->link_clicked)
-                base_color = &widget->style->base[GTK_STATE_ACTIVE];
-              else
-                base_color = &widget->style->base[GTK_STATE_PRELIGHT];
-              gdk_draw_layout_with_colors (widget->window,
-                                           widget->style->black_gc,
-                                           x, y,
-                                           priv->layout,
-                                           text_color,
-                                           base_color);
-              gdk_color_free (link_color);
-              gdk_color_free (visited_link_color);
-
-              gdk_gc_set_clip_region (widget->style->black_gc, NULL);
-              cairo_region_destroy (clip);
-            }
 
           if (focus_link && gtk_widget_has_focus (widget))
             {
@@ -4535,6 +4570,7 @@ gtk_label_grab_focus (GtkWidget *widget)
           link = priv->select_info->links->data;
           priv->select_info->selection_anchor = link->start;
           priv->select_info->selection_end = link->start;
+          gtk_label_update_layout_attributes (label);
         }
     }
 }
@@ -4561,6 +4597,7 @@ gtk_label_focus (GtkWidget        *widget,
               focus_link = l->data;
               info->selection_anchor = focus_link->start;
               info->selection_end = focus_link->start;
+              gtk_label_update_layout_attributes (label);
             }
         }
 
@@ -4638,6 +4675,7 @@ gtk_label_focus (GtkWidget        *widget,
           focus_link = l->data;
           info->selection_anchor = focus_link->start;
           info->selection_end = focus_link->start;
+          gtk_label_update_layout_attributes (label);
           gtk_widget_queue_draw (widget);
 
           return TRUE;
@@ -4756,6 +4794,20 @@ gtk_label_button_press (GtkWidget      *widget,
 }
 
 static gboolean
+gtk_label_focus_out (GtkWidget      *widget,
+		     GdkEventFocus *event)
+{
+  GtkLabel *label = GTK_LABEL (widget);
+
+  gtk_label_update_layout_attributes (label);
+
+  if (GTK_WIDGET_CLASS (gtk_label_parent_class)->focus_out_event)
+    return GTK_WIDGET_CLASS (gtk_label_parent_class)->focus_out_event (widget, event);
+  else
+    return FALSE;
+}
+
+static gboolean
 gtk_label_button_release (GtkWidget      *widget,
                           GdkEventButton *event)
 
@@ -5350,6 +5402,7 @@ clear_text_callback (GtkClipboard     *clipboard,
     {
       priv->select_info->selection_anchor = priv->select_info->selection_end;
 
+      gtk_label_update_layout_attributes (label);
       gtk_widget_queue_draw (GTK_WIDGET (label));
     }
 }
@@ -5404,6 +5457,8 @@ gtk_label_select_region_index (GtkLabel *label,
             gtk_clipboard_clear (clipboard);
         }
 
+      gtk_label_update_layout_attributes (label);
+
       gtk_widget_queue_draw (GTK_WIDGET (label));
 
       g_object_freeze_notify (G_OBJECT (label));



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