]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtktextlayout.c
When in split cursor mode, always add the cursor as both strong and weak
[~andy/gtk] / gtk / gtktextlayout.c
index bcb10912e31b0ad9bfeda0b13d0c82b58b535cd7..b92e85cc8f16abdd9cd88ccb7e09bdf7be8706fd 100644 (file)
@@ -76,7 +76,9 @@
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
  */
 
+#define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
 #include "gtksignal.h"
+#include "gtkmarshalers.h"
 #include "gtktextlayout.h"
 #include "gtktextbtree.h"
 #include "gtktextiterprivate.h"
@@ -84,9 +86,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-static GtkTextLineData    *gtk_text_line_data_new                 (GtkTextLayout     *layout,
-                                                                   GtkTextLine       *line);
-
 static GtkTextLineData *gtk_text_layout_real_wrap (GtkTextLayout *layout,
                                                    GtkTextLine *line,
                                                    /* may be NULL */
@@ -178,7 +177,7 @@ gtk_text_layout_class_init (GtkTextLayoutClass *klass)
                   G_SIGNAL_RUN_LAST,
                   G_STRUCT_OFFSET (GtkTextLayoutClass, invalidated),
                   NULL, NULL,
-                  gtk_marshal_VOID__VOID,
+                  _gtk_marshal_VOID__VOID,
                   GTK_TYPE_NONE,
                   0);
 
@@ -188,7 +187,7 @@ gtk_text_layout_class_init (GtkTextLayoutClass *klass)
                   G_SIGNAL_RUN_LAST,
                   G_STRUCT_OFFSET (GtkTextLayoutClass, changed),
                   NULL, NULL,
-                  gtk_marshal_VOID__INT_INT_INT,
+                  _gtk_marshal_VOID__INT_INT_INT,
                   GTK_TYPE_NONE,
                   3,
                   GTK_TYPE_INT,
@@ -201,7 +200,7 @@ gtk_text_layout_class_init (GtkTextLayoutClass *klass)
                   G_SIGNAL_RUN_LAST,
                   G_STRUCT_OFFSET (GtkTextLayoutClass, allocate_child),
                   NULL, NULL,
-                  gtk_marshal_VOID__OBJECT_INT_INT,
+                  _gtk_marshal_VOID__OBJECT_INT_INT,
                   GTK_TYPE_NONE,
                   3,
                   GTK_TYPE_OBJECT,
@@ -209,7 +208,7 @@ gtk_text_layout_class_init (GtkTextLayoutClass *klass)
                   GTK_TYPE_INT);
 }
 
-void
+static void
 gtk_text_layout_init (GtkTextLayout *text_layout)
 {
   text_layout->cursor_visible = TRUE;
@@ -294,6 +293,7 @@ gtk_text_layout_default_style_changed (GtkTextLayout *layout)
 {
   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
 
+  DV (g_print ("invalidating all due to default style change (%s)\n", G_STRLOC));
   gtk_text_layout_invalidate_all (layout);
 }
 
@@ -336,6 +336,7 @@ gtk_text_layout_set_contexts (GtkTextLayout *layout,
   layout->rtl_context = rtl_context;
   g_object_ref (G_OBJECT (rtl_context));
 
+  DV (g_print ("invalidating all due to new pango contexts (%s)\n", G_STRLOC));
   gtk_text_layout_invalidate_all (layout);
 }
 
@@ -392,6 +393,7 @@ gtk_text_layout_set_screen_width (GtkTextLayout *layout, gint width)
 
   layout->screen_width = width;
 
+  DV (g_print ("invalidating all due to new screen width (%s)\n", G_STRLOC));
   gtk_text_layout_invalidate_all (layout);
 }
 
@@ -578,13 +580,11 @@ gtk_text_layout_get_lines (GtkTextLayout *layout,
   /* -1 since bottom_y is one past */
   last_btree_line =
     _gtk_text_btree_find_line_by_y (_gtk_text_buffer_get_btree (layout->buffer),
-                                   layout, bottom_y - 1, NULL);
+                                    layout, bottom_y - 1, NULL);
 
   if (!last_btree_line)
     last_btree_line =
-      _gtk_text_btree_get_line (_gtk_text_buffer_get_btree (layout->buffer),
-                               _gtk_text_btree_line_count (_gtk_text_buffer_get_btree (layout->buffer)) - 1,
-                               NULL);
+      _gtk_text_btree_get_end_iter_line (_gtk_text_buffer_get_btree (layout->buffer));
 
   g_assert (last_btree_line != NULL);
 
@@ -596,7 +596,7 @@ gtk_text_layout_get_lines (GtkTextLayout *layout,
       if (line == last_btree_line)
         break;
 
-      line = _gtk_text_line_next (line);
+      line = _gtk_text_line_next_excluding_last (line);
     }
 
   retval = g_slist_reverse (retval);
@@ -722,7 +722,7 @@ gtk_text_layout_real_invalidate (GtkTextLayout *layout,
       if (line == last_line)
         break;
 
-      line = _gtk_text_line_next (line);
+      line = _gtk_text_line_next_excluding_last (line);
     }
 
   gtk_text_layout_invalidated (layout);
@@ -751,7 +751,7 @@ gtk_text_layout_real_free_line_data (GtkTextLayout     *layout,
  *
  * Check if there are any invalid regions in a #GtkTextLayout's buffer
  *
- * Return value: #TRUE if any invalid regions were found
+ * Return value: %TRUE if any invalid regions were found
  **/
 gboolean
 gtk_text_layout_is_valid (GtkTextLayout *layout)
@@ -862,7 +862,7 @@ gtk_text_layout_validate_yrange (GtkTextLayout *layout,
         }
 
       seen += line_data->height;
-      line = _gtk_text_line_next (line);
+      line = _gtk_text_line_next_excluding_last (line);
     }
 
   /* If we found and validated any invalid lines, update size and
@@ -922,10 +922,11 @@ gtk_text_layout_real_wrap (GtkTextLayout   *layout,
   GtkTextLineDisplay *display;
 
   g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), NULL);
-
+  g_return_val_if_fail (line != NULL, NULL);
+  
   if (line_data == NULL)
     {
-      line_data = gtk_text_line_data_new (layout, line);
+      line_data = _gtk_text_line_data_new (layout, line);
       _gtk_text_line_add_data (line, line_data);
     }
 
@@ -1097,8 +1098,7 @@ totally_invisible_line (GtkTextLayout *layout,
 static void
 set_para_values (GtkTextLayout      *layout,
                  GtkTextAttributes *style,
-                 GtkTextLineDisplay *display,
-                 gdouble            *align)
+                 GtkTextLineDisplay *display)
 {
   PangoAlignment pango_align = PANGO_ALIGN_LEFT;
   int layout_width;
@@ -1129,19 +1129,6 @@ set_para_values (GtkTextLayout      *layout,
       break;
     }
 
-  switch (pango_align)
-    {
-    case PANGO_ALIGN_LEFT:
-      *align = 0.0;
-      break;
-    case PANGO_ALIGN_RIGHT:
-      *align = 1.0;
-      break;
-    case PANGO_ALIGN_CENTER:
-      *align = 0.5;
-      break;
-    }
-
   pango_layout_set_alignment (display->layout, pango_align);
   pango_layout_set_spacing (display->layout,
                             style->pixels_inside_wrap * PANGO_SCALE);
@@ -1313,7 +1300,7 @@ add_text_attrs (GtkTextLayout      *layout,
 {
   PangoAttribute *attr;
 
-  attr = pango_attr_font_desc_new (&style->font);
+  attr = pango_attr_font_desc_new (style->font);
   attr->start_index = start;
   attr->end_index = start + byte_count;
 
@@ -1471,7 +1458,7 @@ add_cursor (GtkTextLayout      *layout,
       cursor->y = PANGO_PIXELS (strong_pos.y);
       cursor->height = PANGO_PIXELS (strong_pos.height);
       cursor->is_strong = TRUE;
-      cursor->is_weak = FALSE;
+      cursor->is_weak = (layout->cursor_direction == GTK_TEXT_DIR_NONE) ? FALSE : TRUE;
       display->cursors = g_slist_prepend (display->cursors, cursor);
     }
   
@@ -1486,7 +1473,7 @@ add_cursor (GtkTextLayout      *layout,
          cursor->x = PANGO_PIXELS (weak_pos.x);
          cursor->y = PANGO_PIXELS (weak_pos.y);
          cursor->height = PANGO_PIXELS (weak_pos.height);
-         cursor->is_strong = FALSE;
+         cursor->is_strong = (layout->cursor_direction == GTK_TEXT_DIR_NONE) ? FALSE : TRUE;
          cursor->is_weak = TRUE;
          display->cursors = g_slist_prepend (display->cursors, cursor);
        }
@@ -1585,7 +1572,7 @@ add_preedit_attrs (GtkTextLayout     *layout,
   do
     {
       GtkTextAppearance appearance = style->appearance;
-      PangoFontDescription font_desc;
+      PangoFontDescription *font_desc = pango_font_description_copy_static (style->font);
       PangoAttribute *insert_attr;
       GSList *extra_attrs = NULL;
       GSList *tmp_list;
@@ -1597,8 +1584,7 @@ add_preedit_attrs (GtkTextLayout     *layout,
       if (end == G_MAXINT)
        end = layout->preedit_len;
       
-      pango_attr_iterator_get_font (iter, &style->font,
-                                   &font_desc, &language, &extra_attrs);
+      pango_attr_iterator_get_font (iter, font_desc, &language, &extra_attrs);
       
       tmp_list = extra_attrs;
       while (tmp_list)
@@ -1633,7 +1619,7 @@ add_preedit_attrs (GtkTextLayout     *layout,
       
       g_slist_free (extra_attrs);
       
-      insert_attr = pango_attr_font_desc_new (&font_desc);
+      insert_attr = pango_attr_font_desc_new (font_desc);
       insert_attr->start_index = start + offset;
       insert_attr->end_index = end + offset;
       
@@ -1651,6 +1637,8 @@ add_preedit_attrs (GtkTextLayout     *layout,
       add_generic_attrs (layout, &appearance, end - start,
                          attrs, start + offset,
                          size_only, TRUE);
+      
+      pango_font_description_free (font_desc);
     }
   while (pango_attr_iterator_next (iter));
 
@@ -1669,7 +1657,6 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
   gchar *text;
   PangoAttrList *attrs;
   gint text_allocated, layout_byte_offset, buffer_byte_offset;
-  gdouble align;
   PangoRectangle extents;
   gboolean para_values_set = FALSE;
   GSList *cursor_byte_offsets = NULL;
@@ -1738,7 +1725,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
            */
           if (!para_values_set)
             {
-              set_para_values (layout, style, display, &align);
+              set_para_values (layout, style, display);
               para_values_set = TRUE;
             }
 
@@ -1907,7 +1894,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
   if (!para_values_set)
     {
       style = get_style (layout, &iter);
-      set_para_values (layout, style, display, &align);
+      set_para_values (layout, style, display);
       release_style (layout, style);
     }
   
@@ -1954,8 +1941,6 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
 
   pango_layout_get_extents (display->layout, NULL, &extents);
 
-  display->x_offset += (display->total_width - PANGO_PIXELS (extents.x + extents.width)) * align;
-
   display->width = PANGO_PIXELS (extents.width) + display->left_margin + display->right_margin;
   display->height += PANGO_PIXELS (extents.height);
   
@@ -2021,6 +2006,9 @@ line_display_index_to_iter (GtkTextLayout      *layout,
                            gint                index,
                            gint                trailing)
 {
+  g_return_if_fail (!_gtk_text_line_is_last (display->line,
+                                             _gtk_text_buffer_get_btree (layout->buffer)));
+  
   if (index >= display->insert_index + layout->preedit_len)
     index -= layout->preedit_len;
   else if (index > display->insert_index)
@@ -2049,24 +2037,6 @@ line_display_index_to_iter (GtkTextLayout      *layout,
   gtk_text_iter_forward_chars (iter, trailing);
 }
 
-/* FIXME: This really doesn't belong in this file ... */
-static GtkTextLineData*
-gtk_text_line_data_new (GtkTextLayout *layout,
-                        GtkTextLine   *line)
-{
-  GtkTextLineData *line_data;
-
-  line_data = g_new (GtkTextLineData, 1);
-
-  line_data->view_id = layout;
-  line_data->next = NULL;
-  line_data->width = 0;
-  line_data->height = 0;
-  line_data->valid = FALSE;
-
-  return line_data;
-}
-
 static void
 get_line_at_y (GtkTextLayout *layout,
                gint           y,
@@ -2082,8 +2052,8 @@ get_line_at_y (GtkTextLayout *layout,
                                          layout, y, line_top);
   if (*line == NULL)
     {
-      *line = _gtk_text_btree_get_line (_gtk_text_buffer_get_btree (layout->buffer),
-                                       _gtk_text_btree_line_count (_gtk_text_buffer_get_btree (layout->buffer)) - 1, NULL);
+      *line = _gtk_text_btree_get_end_iter_line (_gtk_text_buffer_get_btree (layout->buffer));
+      
       if (line_top)
         *line_top =
           _gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer),
@@ -2131,14 +2101,6 @@ gtk_text_layout_get_iter_at_pixel (GtkTextLayout *layout,
   g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
   g_return_if_fail (target_iter != NULL);
 
-  /* Adjust pixels to be on-screen. This gives nice
-     behavior if the user is dragging with a pointer grab.
-  */
-  if (x < 0)
-    x = 0;
-  if (x > layout->width)
-    x = layout->width;
-
   get_line_at_y (layout, y, &line, &line_top);
 
   display = gtk_text_layout_get_line_display (layout, line, FALSE);
@@ -2146,17 +2108,23 @@ gtk_text_layout_get_iter_at_pixel (GtkTextLayout *layout,
   x -= display->x_offset;
   y -= line_top + display->top_margin;
 
-  /* We clamp y to the area of the actual layout so that the layouts
-   * hit testing works OK on the space above and below the layout
+  /* If we are below the layout, position the cursor at the last character
+   * of the line.
    */
-  y = CLAMP (y, 0, display->height - display->top_margin - display->bottom_margin - 1);
-
-  if (!pango_layout_xy_to_index (display->layout, x * PANGO_SCALE, y * PANGO_SCALE,
-                                 &byte_index, &trailing))
+  if (y > display->height - display->top_margin - display->bottom_margin)
     {
       byte_index = _gtk_text_line_byte_count (line);
       trailing = 0;
     }
+  else
+    {
+       /* Ignore the "outside" return value from pango. Pango is doing
+        * the right thing even if we are outside the layout in the
+        * x-direction.
+        */
+      pango_layout_xy_to_index (display->layout, x * PANGO_SCALE, y * PANGO_SCALE,
+                                &byte_index, &trailing);
+    }
 
   line_display_index_to_iter (layout, display, target_iter, byte_index, trailing);
 
@@ -2264,6 +2232,45 @@ gtk_text_layout_get_line_yrange (GtkTextLayout     *layout,
     }
 }
 
+/**
+ * _gtk_text_layout_get_line_xrange:
+ * @layout: a #GtkTextLayout
+ * @iter:   a #GtkTextIter
+ * @x:      location to store the top of the paragraph in pixels,
+ *          or %NULL.
+ * @width  location to store the height of the paragraph in pixels,
+ *          or %NULL.
+ *
+ * Find the range of X coordinates for the paragraph containing
+ * the given iter. Private for 2.0 due to API freeze, could
+ * be made public for 2.2.
+ **/
+void
+_gtk_text_layout_get_line_xrange (GtkTextLayout     *layout,
+                                  const GtkTextIter *iter,
+                                  gint              *x,
+                                  gint              *width)
+{
+  GtkTextLine *line;
+
+  g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
+  g_return_if_fail (_gtk_text_iter_get_btree (iter) == _gtk_text_buffer_get_btree (layout->buffer));
+
+  line = _gtk_text_iter_get_text_line (iter);
+
+  if (x)
+    *x = 0; /* FIXME This is wrong; should represent the first available cursor position */
+  
+  if (width)
+    {
+      GtkTextLineData *line_data = _gtk_text_line_get_data (line, layout);
+      if (line_data)
+        *width = line_data->width;
+      else
+        *width = 0;
+    }
+}
+
 void
 gtk_text_layout_get_iter_location (GtkTextLayout     *layout,
                                    const GtkTextIter *iter,
@@ -2322,9 +2329,8 @@ find_display_line_below (GtkTextLayout *layout,
   if (!line)
     {
       line =
-        _gtk_text_btree_get_line (_gtk_text_buffer_get_btree (layout->buffer),
-                                 _gtk_text_btree_line_count (_gtk_text_buffer_get_btree (layout->buffer)) - 1,
-                                 NULL);
+        _gtk_text_btree_get_end_iter_line (_gtk_text_buffer_get_btree (layout->buffer));
+
       line_top =
         _gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer),
                                       line, layout);
@@ -2362,7 +2368,7 @@ find_display_line_below (GtkTextLayout *layout,
       line_top += display->bottom_margin;
       gtk_text_layout_free_line_display (layout, display);
 
-      next = _gtk_text_line_next (line);
+      next = _gtk_text_line_next_excluding_last (line);
       if (!next)
         found_line = line;
 
@@ -2390,8 +2396,8 @@ find_display_line_above (GtkTextLayout *layout,
   line = _gtk_text_btree_find_line_by_y (_gtk_text_buffer_get_btree (layout->buffer), layout, y, &line_top);
   if (!line)
     {
-      line = _gtk_text_btree_get_line (_gtk_text_buffer_get_btree (layout->buffer),
-                                      _gtk_text_btree_line_count (_gtk_text_buffer_get_btree (layout->buffer)) - 1, NULL);
+      line = _gtk_text_btree_get_end_iter_line (_gtk_text_buffer_get_btree (layout->buffer));
+      
       line_top = _gtk_text_btree_find_line_top (_gtk_text_buffer_get_btree (layout->buffer), line, layout);
     }
 
@@ -2424,6 +2430,7 @@ find_display_line_above (GtkTextLayout *layout,
           if (tmp_top < y)
             {
               found_line = line;
+             pango_layout_iter_free (layout_iter);
               goto done;
             }
         }
@@ -2674,7 +2681,7 @@ gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout,
       
       gtk_text_layout_free_line_display (layout, display);
 
-      line = _gtk_text_line_next (line);
+      line = _gtk_text_line_next_excluding_last (line);
     }
 
   return
@@ -2955,7 +2962,7 @@ gtk_text_layout_move_iter_visually (GtkTextLayout *layout,
         }
       else if (new_index > byte_count)
         {
-          line = _gtk_text_line_next (line);
+          line = _gtk_text_line_next_excluding_last (line);
           if (!line)
             goto done;