]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtktextdisplay.c
texthandles: Keep state internally to avoid X overhead
[~andy/gtk] / gtk / gtktextdisplay.c
index 5f79ce4ce21a4bea95ef8a98038315c4c7df9585..24cc0ec6b4850970c08c3b46f341184232b7b328 100644 (file)
@@ -21,8 +21,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.Free
  *
  * Original Tk license:
  *
 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
 #include "config.h"
 #include "gtktextdisplay.h"
+#include "gtkwidgetprivate.h"
+#include "gtkstylecontextprivate.h"
 #include "gtkintl.h"
+
 /* DO NOT go putting private headers in here. This file should only
  * use the semi-public headers, as with gtktextview.c.
  */
@@ -105,10 +107,13 @@ struct _GtkTextRenderer
   GtkWidget *widget;
   cairo_t *cr;
   
-  GdkColor *error_color;       /* Error underline color for this widget */
-  GList *widgets;              /* widgets encountered when drawing */
-  
-  int state;
+  GdkRGBA *error_color;        /* Error underline color for this widget */
+  GList *widgets;              /* widgets encountered when drawing */
+
+  GdkRGBA rgba[4];
+  guint8  rgba_set[4];
+
+  guint state : 2;
 };
 
 struct _GtkTextRendererClass
@@ -116,44 +121,27 @@ struct _GtkTextRendererClass
   PangoRendererClass parent_class;
 };
 
-G_DEFINE_TYPE (GtkTextRenderer, _gtk_text_renderer, PANGO_TYPE_RENDERER)
-
-static GdkColor *
-text_renderer_get_error_color (GtkTextRenderer *text_renderer)
-{
-  static const GdkColor red = { 0, 0xffff, 0, 0 };
-
-  if (!text_renderer->error_color)
-    gtk_widget_style_get (text_renderer->widget,
-                         "error-underline-color", &text_renderer->error_color,
-                         NULL);
-  
-  if (!text_renderer->error_color)
-    text_renderer->error_color = gdk_color_copy (&red);
+GType _gtk_text_renderer_get_type (void);
 
-  return text_renderer->error_color;
-}
+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)
+text_renderer_set_rgba (GtkTextRenderer *text_renderer,
+                       PangoRenderPart  part,
+                       const GdkRGBA   *rgba)
 {
   PangoRenderer *renderer = PANGO_RENDERER (text_renderer);
+  PangoColor     dummy = { 0, };
 
-  if (gdk_color)
+  if (rgba)
     {
-      PangoColor color;
-
-      color.red = gdk_color->red;
-      color.green = gdk_color->green;
-      color.blue = gdk_color->blue;
-      
-      pango_renderer_set_color (renderer, part, &color);
+      text_renderer->rgba[part] = *rgba;
+      pango_renderer_set_color (renderer, part, &dummy);
     }
   else
     pango_renderer_set_color (renderer, part, NULL);
-          
+
+  text_renderer->rgba_set[part] = (rgba != NULL);
 }
 
 static GtkTextAppearance *
@@ -178,8 +166,11 @@ static void
 gtk_text_renderer_prepare_run (PangoRenderer  *renderer,
                               PangoLayoutRun *run)
 {
+  GtkStyleContext *context;
+  GtkStateFlags state;
   GtkTextRenderer *text_renderer = GTK_TEXT_RENDERER (renderer);
-  GdkColor *bg_color, *fg_color, *underline_color;
+  GdkRGBA *bg_rgba = NULL;
+  GdkRGBA *fg_rgba = NULL;
   GtkTextAppearance *appearance;
 
   PANGO_RENDERER_CLASS (_gtk_text_renderer_parent_class)->prepare_run (renderer, run);
@@ -187,50 +178,80 @@ gtk_text_renderer_prepare_run (PangoRenderer  *renderer,
   appearance = get_item_appearance (run->item);
   g_assert (appearance != NULL);
 
+  context = gtk_widget_get_style_context (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)
     {
-      if (gtk_widget_has_focus (text_renderer->widget))
-       fg_color = &text_renderer->widget->style->text[GTK_STATE_SELECTED];
-      else
-       fg_color = &text_renderer->widget->style->text[GTK_STATE_ACTIVE];
+      state |= GTK_STATE_FLAG_SELECTED;
+
+      gtk_style_context_get (context, state, "color", &fg_rgba, NULL);
     }
   else if (text_renderer->state == CURSOR && gtk_widget_has_focus (text_renderer->widget))
-    fg_color = &text_renderer->widget->style->base[GTK_STATE_NORMAL];
+    {
+      gtk_style_context_get (context, state,
+                             "background-color", &fg_rgba,
+                              NULL);
+    }
   else
-    fg_color = &appearance->fg_color;
+    fg_rgba = appearance->rgba[1];
 
-  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)
-    underline_color = text_renderer_get_error_color (text_renderer);
+    {
+      if (!text_renderer->error_color)
+        {
+         GdkColor *color = NULL;
+
+          gtk_style_context_get_style (context,
+                                       "error-underline-color", &color,
+                                       NULL);
+
+         if (color)
+           {
+             GdkRGBA   rgba;
+
+             rgba.red = color->red / 65535.;
+             rgba.green = color->green / 65535.;
+             rgba.blue = color->blue / 65535.;
+             rgba.alpha = 1;
+             gdk_color_free (color);
+
+             text_renderer->error_color = gdk_rgba_copy (&rgba);
+           }
+         else
+           {
+             static const GdkRGBA red = { 1, 0, 0, 1 };
+             text_renderer->error_color = gdk_rgba_copy (&red);
+           }
+        }
+
+      text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_UNDERLINE, text_renderer->error_color);
+    }
   else
-    underline_color = fg_color;
+    text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_UNDERLINE, fg_rgba);
 
-  text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_UNDERLINE, underline_color);
+  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
@@ -352,20 +373,7 @@ gtk_text_renderer_draw_shape (PangoRenderer   *renderer,
                              int              y)
 {
   GtkTextRenderer *text_renderer = GTK_TEXT_RENDERER (renderer);
-  GdkColor *fg;
 
-  if (text_renderer->state == SELECTED)
-    {
-      if (gtk_widget_has_focus (text_renderer->widget))
-       fg = &text_renderer->widget->style->text[GTK_STATE_SELECTED];
-      else
-       fg = &text_renderer->widget->style->text[GTK_STATE_SELECTED];
-    }
-  else if (text_renderer->state == CURSOR && gtk_widget_has_focus (text_renderer->widget))
-    fg = &text_renderer->widget->style->base[GTK_STATE_NORMAL];
-  else
-    fg = &text_renderer->widget->style->text[GTK_STATE_NORMAL];
-  
   if (attr->data == NULL)
     {
       /* This happens if we have an empty widget anchor. Draw
@@ -373,18 +381,17 @@ gtk_text_renderer_draw_shape (PangoRenderer   *renderer,
        */
       GdkRectangle shape_rect;
       cairo_t *cr;
-      
+
       shape_rect.x = PANGO_PIXELS (x);
       shape_rect.y = PANGO_PIXELS (y + attr->logical_rect.y);
       shape_rect.width = PANGO_PIXELS (x + attr->logical_rect.width) - shape_rect.x;
       shape_rect.height = PANGO_PIXELS (y + attr->logical_rect.y + attr->logical_rect.height) - shape_rect.y;
-      
-      cr = text_renderer->cr;
 
-      cairo_save (cr);
+      set_color (text_renderer, PANGO_RENDER_PART_FOREGROUND);
+
+      cr = text_renderer->cr;
 
       cairo_set_line_width (cr, 1.0);
-      gdk_cairo_set_source_color (cr, fg);
 
       cairo_rectangle (cr,
                        shape_rect.x + 0.5, shape_rect.y + 0.5,
@@ -399,8 +406,8 @@ gtk_text_renderer_draw_shape (PangoRenderer   *renderer,
                      shape_rect.y + 0.5);
 
       cairo_stroke (cr);
-      
-      cairo_restore (cr);
+
+      unset_color (text_renderer);
     }
   else if (GDK_IS_PIXBUF (attr->data))
     {
@@ -470,8 +477,24 @@ text_renderer_begin (GtkTextRenderer *text_renderer,
                      GtkWidget       *widget,
                      cairo_t         *cr)
 {
+  GtkStyleContext *context;
+  GtkStateFlags state;
+  GdkRGBA color;
+
   text_renderer->widget = widget;
   text_renderer->cr = cr;
+
+  context = gtk_widget_get_style_context (widget);
+
+  gtk_style_context_save (context);
+  gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
+
+  state = gtk_widget_get_state_flags (widget);
+  gtk_style_context_get_color (context, state, &color);
+
+  cairo_save (cr);
+
+  gdk_cairo_set_source_rgba (cr, &color);
 }
 
 /* Returns a GSList of (referenced) widgets encountered while drawing.
@@ -479,8 +502,15 @@ text_renderer_begin (GtkTextRenderer *text_renderer,
 static GList *
 text_renderer_end (GtkTextRenderer *text_renderer)
 {
+  GtkStyleContext *context;
   GList *widgets = text_renderer->widgets;
 
+  cairo_restore (text_renderer->cr);
+
+  context = gtk_widget_get_style_context (text_renderer->widget);
+
+  gtk_style_context_restore (context);
+
   text_renderer->widget = NULL;
   text_renderer->cr = NULL;
 
@@ -488,14 +518,13 @@ text_renderer_end (GtkTextRenderer *text_renderer)
 
   if (text_renderer->error_color)
     {
-      gdk_color_free (text_renderer->error_color);
+      gdk_rgba_free (text_renderer->error_color);
       text_renderer->error_color = NULL;
     }
 
   return widgets;
 }
 
-
 static cairo_region_t *
 get_selected_clip (GtkTextRenderer    *text_renderer,
                    PangoLayout        *layout,
@@ -531,20 +560,17 @@ get_selected_clip (GtkTextRenderer    *text_renderer,
 static void
 render_para (GtkTextRenderer    *text_renderer,
              GtkTextLineDisplay *line_display,
-             /* Top-left corner of paragraph including all margins */
-             int                 x,
-             int                 y,
              int                 selection_start_index,
              int                 selection_end_index)
 {
+  GtkStyleContext *context;
+  GtkStateFlags state;
   PangoLayout *layout = line_display->layout;
   int byte_offset = 0;
   PangoLayoutIter *iter;
   PangoRectangle layout_logical;
   int screen_width;
-  GdkColor *selection;
-  gint state;
-  
+  GdkRGBA selection;
   gboolean first = TRUE;
 
   iter = pango_layout_get_iter (layout);
@@ -557,13 +583,13 @@ render_para (GtkTextRenderer    *text_renderer,
   layout_logical.y += line_display->top_margin * PANGO_SCALE;
 
   screen_width = line_display->total_width;
-  
-  if (gtk_widget_has_focus (text_renderer->widget))
-    state = GTK_STATE_SELECTED;
-  else
-    state = GTK_STATE_ACTIVE;
 
-  selection = &text_renderer->widget->style->base [state];
+  context = gtk_widget_get_style_context (text_renderer->widget);
+  state = gtk_widget_get_state_flags (text_renderer->widget);
+
+  state |= GTK_STATE_FLAG_SELECTED;
+
+  gtk_style_context_get_background_color (context, state, &selection);
 
   do
     {
@@ -587,7 +613,7 @@ render_para (GtkTextRenderer    *text_renderer,
       /* Selection is the height of the line, plus top/bottom
        * margin if we're the first/last line
        */
-      selection_y = y + PANGO_PIXELS (first_y) + line_display->top_margin;
+      selection_y = PANGO_PIXELS (first_y) + line_display->top_margin;
       selection_height = PANGO_PIXELS (last_y) - PANGO_PIXELS (first_y);
 
       if (first)
@@ -608,9 +634,9 @@ render_para (GtkTextRenderer    *text_renderer,
           cairo_t *cr = text_renderer->cr;
 
           cairo_save (cr);
-          gdk_cairo_set_source_color (cr, selection);
+          gdk_cairo_set_source_rgba (cr, &selection);
           cairo_rectangle (cr, 
-                           x + line_display->left_margin, selection_y,
+                           line_display->left_margin, selection_y,
                            screen_width, selection_height);
           cairo_fill (cr);
           cairo_restore(cr);
@@ -618,20 +644,20 @@ render_para (GtkTextRenderer    *text_renderer,
          text_renderer_set_state (text_renderer, SELECTED);
          pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer),
                                           line, 
-                                          PANGO_SCALE * x + line_rect.x,
-                                          PANGO_SCALE * y + baseline);
+                                          line_rect.x,
+                                          baseline);
         }
       else
         {
-          if (line_display->pg_bg_color)
+          if (line_display->pg_bg_rgba)
             {
               cairo_t *cr = text_renderer->cr;
 
               cairo_save (cr);
-
-              gdk_cairo_set_source_color (cr, line_display->pg_bg_color);
+             gdk_cairo_set_source_rgba (text_renderer->cr, line_display->pg_bg_rgba);
               cairo_rectangle (cr, 
-                               x + line_display->left_margin, selection_y,
+                               line_display->left_margin, selection_y,
                                screen_width, selection_height);
               cairo_fill (cr);
 
@@ -641,8 +667,8 @@ render_para (GtkTextRenderer    *text_renderer,
          text_renderer_set_state (text_renderer, NORMAL);
          pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer),
                                           line, 
-                                          PANGO_SCALE * x + line_rect.x,
-                                          PANGO_SCALE * y + baseline);
+                                          line_rect.x,
+                                          baseline);
 
          /* Check if some part of the line is selected; the newline
           * that is after line->length for the last line of the
@@ -654,7 +680,7 @@ render_para (GtkTextRenderer    *text_renderer,
             {
               cairo_t *cr = text_renderer->cr;
               cairo_region_t *clip_region = get_selected_clip (text_renderer, layout, line,
-                                                          x + line_display->x_offset,
+                                                          line_display->x_offset,
                                                           selection_y,
                                                           selection_height,
                                                           selection_start_index, selection_end_index);
@@ -664,9 +690,9 @@ render_para (GtkTextRenderer    *text_renderer,
               cairo_clip (cr);
               cairo_region_destroy (clip_region);
 
-              gdk_cairo_set_source_color (cr, selection);
+              gdk_cairo_set_source_rgba (cr, &selection);
               cairo_rectangle (cr,
-                               x + PANGO_PIXELS (line_rect.x),
+                               PANGO_PIXELS (line_rect.x),
                                selection_y,
                                PANGO_PIXELS (line_rect.width),
                                selection_height);
@@ -675,8 +701,8 @@ render_para (GtkTextRenderer    *text_renderer,
              text_renderer_set_state (text_renderer, SELECTED);
              pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer),
                                               line, 
-                                              PANGO_SCALE * x + line_rect.x,
-                                              PANGO_SCALE * y + baseline);
+                                              line_rect.x,
+                                              baseline);
 
               cairo_restore (cr);
 
@@ -687,9 +713,9 @@ render_para (GtkTextRenderer    *text_renderer,
                 {
                   cairo_save (cr);
 
-                  gdk_cairo_set_source_color (cr, selection);
+                  gdk_cairo_set_source_rgba (cr, &selection);
                   cairo_rectangle (cr,
-                                   x + line_display->left_margin,
+                                   line_display->left_margin,
                                    selection_y,
                                    PANGO_PIXELS (line_rect.x) - line_display->left_margin,
                                    selection_height);
@@ -711,9 +737,9 @@ render_para (GtkTextRenderer    *text_renderer,
 
                   cairo_save (cr);
 
-                  gdk_cairo_set_source_color (cr, selection);
+                  gdk_cairo_set_source_rgba (cr, &selection);
                   cairo_rectangle (cr,
-                                   x + PANGO_PIXELS (line_rect.x) + PANGO_PIXELS (line_rect.width),
+                                   PANGO_PIXELS (line_rect.x) + PANGO_PIXELS (line_rect.width),
                                    selection_y,
                                    nonlayout_width,
                                    selection_height);
@@ -729,15 +755,15 @@ render_para (GtkTextRenderer    *text_renderer,
                    (at_last_line && line_display->insert_index == byte_offset + line->length)))
            {
              GdkRectangle cursor_rect;
-              GdkColor cursor_color;
+              GdkRGBA cursor_color;
               cairo_t *cr = text_renderer->cr;
 
-             /* we draw text using base color on filled cursor rectangle of cursor color
-              * (normally white on black) */
-             _gtk_widget_get_cursor_color (text_renderer->widget, &cursor_color);
+              /* we draw text using base color on filled cursor rectangle of cursor color
+               * (normally white on black) */
+              _gtk_style_context_get_cursor_color (context, &cursor_color, NULL);
 
-             cursor_rect.x = x + line_display->x_offset + line_display->block_cursor.x;
-             cursor_rect.y = y + line_display->block_cursor.y + line_display->top_margin;
+             cursor_rect.x = line_display->x_offset + line_display->block_cursor.x;
+             cursor_rect.y = line_display->block_cursor.y + line_display->top_margin;
              cursor_rect.width = line_display->block_cursor.width;
              cursor_rect.height = line_display->block_cursor.height;
 
@@ -746,23 +772,26 @@ render_para (GtkTextRenderer    *text_renderer,
               gdk_cairo_rectangle (cr, &cursor_rect);
               cairo_clip (cr);
 
-              gdk_cairo_set_source_color (cr, &cursor_color);
+              gdk_cairo_set_source_rgba (cr, &cursor_color);
               cairo_paint (cr);
 
-             /* draw text under the cursor if any */
-             if (!line_display->cursor_at_line_end)
-               {
-                  gdk_cairo_set_source_color (cr,
-                                              &text_renderer->widget->style->base[text_renderer->widget->state]);
+              /* draw text under the cursor if any */
+              if (!line_display->cursor_at_line_end)
+                {
+                  GdkRGBA color;
+
+                  state = gtk_widget_get_state_flags (text_renderer->widget);
+                  gtk_style_context_get_background_color (context, state, &color);
+
+                  gdk_cairo_set_source_rgba (cr, &color);
 
                  text_renderer_set_state (text_renderer, CURSOR);
 
                  pango_renderer_draw_layout_line (PANGO_RENDERER (text_renderer),
                                                   line,
-                                                  PANGO_SCALE * x + line_rect.x,
-                                                  PANGO_SCALE * y + baseline);
-
-               }
+                                                  line_rect.x,
+                                                  baseline);
+                }
 
               cairo_restore (cr);
            }
@@ -789,63 +818,45 @@ get_text_renderer (void)
 void
 gtk_text_layout_draw (GtkTextLayout *layout,
                       GtkWidget *widget,
-                      GdkDrawable *drawable,
-                     gpointer     cursor_gc,
-                      /* Location of the drawable
-                         in layout coordinates */
-                      gint x_offset,
-                      gint y_offset,
-                      /* Region of the layout to
-                         render */
-                      gint x,
-                      gint y,
-                      gint width,
-                      gint height,
-                      /* widgets to expose */
+                      cairo_t *cr,
                       GList **widgets)
 {
-  GdkRectangle clip;
-  gint current_y;
-  GSList *cursor_list;
+  GtkStyleContext *context;
+  gint offset_y;
   GtkTextRenderer *text_renderer;
   GtkTextIter selection_start, selection_end;
-  gboolean have_selection = FALSE;
+  gboolean have_selection;
   GSList *line_list;
   GSList *tmp_list;
   GList *tmp_widgets;
-  cairo_t *cr;
-  
+  GdkRectangle clip;
+
   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
   g_return_if_fail (layout->default_style != NULL);
   g_return_if_fail (layout->buffer != NULL);
-  g_return_if_fail (drawable != NULL);
-  g_return_if_fail (width >= 0);
-  g_return_if_fail (height >= 0);
+  g_return_if_fail (cr != NULL);
 
-  if (width == 0 || height == 0)
+  if (!gdk_cairo_get_clip_rectangle (cr, &clip))
     return;
 
-  line_list =  gtk_text_layout_get_lines (layout, y + y_offset, y + y_offset + height, &current_y);
-  current_y -= y_offset;
+  context = gtk_widget_get_style_context (widget);
+
+  line_list = gtk_text_layout_get_lines (layout, clip.y, clip.y + clip.height, &offset_y);
 
   if (line_list == NULL)
     return; /* nothing on the screen */
 
-  cr = gdk_cairo_create (drawable);
-  cairo_rectangle (cr, x, y, width, height);
-  cairo_clip (cr);
-
-  gdk_cairo_set_source_color (cr, &widget->style->text[widget->state]);
-
   text_renderer = get_text_renderer ();
   text_renderer_begin (text_renderer, widget, cr);
 
+  /* text_renderer_begin/end does cairo_save/restore */
+  cairo_translate (cr, 0, offset_y);
+
   gtk_text_layout_wrap_loop_start (layout);
 
-  if (gtk_text_buffer_get_selection_bounds (layout->buffer,
-                                            &selection_start,
-                                            &selection_end))
-    have_selection = TRUE;
+  have_selection = gtk_text_buffer_get_selection_bounds (layout->buffer,
+                                                         &selection_start,
+                                                         &selection_end);
 
   tmp_list = line_list;
   while (tmp_list != NULL)
@@ -853,8 +864,6 @@ gtk_text_layout_draw (GtkTextLayout *layout,
       GtkTextLineDisplay *line_display;
       gint selection_start_index = -1;
       gint selection_end_index = -1;
-      gboolean have_strong;
-      gboolean have_weak;
 
       GtkTextLine *line = tmp_list->data;
 
@@ -893,56 +902,30 @@ gtk_text_layout_draw (GtkTextLayout *layout,
             }
 
           render_para (text_renderer, line_display,
-                       - x_offset,
-                       current_y,
                        selection_start_index, selection_end_index);
 
           /* We paint the cursors last, because they overlap another chunk
-         and need to appear on top. */
-
-         have_strong = FALSE;
-         have_weak = FALSE;
-         
-         cursor_list = line_display->cursors;
-         while (cursor_list)
-           {
-             GtkTextCursorDisplay *cursor = cursor_list->data;
-             if (cursor->is_strong)
-               have_strong = TRUE;
-             else
-               have_weak = TRUE;
-             
-             cursor_list = cursor_list->next;
-           }
-         
-          cursor_list = line_display->cursors;
-          while (cursor_list)
+           * and need to appear on top.
+           */
+          if (line_display->cursors != NULL)
             {
-              GtkTextCursorDisplay *cursor = cursor_list->data;
-             GtkTextDirection dir;
-             GdkRectangle cursor_location;
-
-              dir = line_display->direction;
-             if (have_strong && have_weak)
-               {
-                 if (!cursor->is_strong)
-                   dir = (dir == GTK_TEXT_DIR_RTL) ? GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
-               }
-             cursor_location.x = line_display->x_offset + cursor->x - x_offset;
-             cursor_location.y = current_y + line_display->top_margin + cursor->y;
-             cursor_location.width = 0;
-             cursor_location.height = cursor->height;
+              int i;
 
-             gtk_draw_insertion_cursor (widget, drawable, &clip, &cursor_location,
-                                        cursor->is_strong,
-                                        dir, have_strong && have_weak);
-
-              cursor_list = cursor_list->next;
+              for (i = 0; i < line_display->cursors->len; i++)
+                {
+                  int index;
+                  PangoDirection dir;
+
+                  index = g_array_index(line_display->cursors, int, i);
+                  dir = (line_display->direction == GTK_TEXT_DIR_RTL) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
+                  gtk_render_insertion_cursor (context, cr,
+                                               line_display->x_offset, line_display->top_margin,
+                                               line_display->layout, index, dir);
+                }
             }
         } /* line_display->height > 0 */
-          
-      current_y += line_display->height;
+
+      cairo_translate (cr, 0, line_display->height);
       gtk_text_layout_free_line_display (layout, line_display);
       
       tmp_list = g_slist_next (tmp_list);
@@ -954,12 +937,7 @@ gtk_text_layout_draw (GtkTextLayout *layout,
   if (widgets)
     *widgets = tmp_widgets;
   else
-    {
-      g_list_foreach (tmp_widgets, (GFunc)g_object_unref, NULL);
-      g_list_free (tmp_widgets);
-    }
-
-  cairo_destroy (cr);
+    g_list_free_full (tmp_widgets, g_object_unref);
 
   g_slist_free (line_list);
 }