diff options
-rw-r--r-- | ChangeLog | 38 | ||||
-rw-r--r-- | ChangeLog.pre-2-0 | 38 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 38 | ||||
-rw-r--r-- | ChangeLog.pre-2-2 | 38 | ||||
-rw-r--r-- | ChangeLog.pre-2-4 | 38 | ||||
-rw-r--r-- | ChangeLog.pre-2-6 | 38 | ||||
-rw-r--r-- | ChangeLog.pre-2-8 | 38 | ||||
-rw-r--r-- | gdk/gdkdraw.c | 7 | ||||
-rw-r--r-- | gtk/gtkentry.c | 14 | ||||
-rw-r--r-- | gtk/gtktextbuffer.c | 60 | ||||
-rw-r--r-- | gtk/gtktextdisplay.c | 4 | ||||
-rw-r--r-- | gtk/gtktextiter.c | 110 | ||||
-rw-r--r-- | gtk/gtktextiter.h | 3 | ||||
-rw-r--r-- | gtk/gtktextlayout.c | 178 | ||||
-rw-r--r-- | gtk/gtktextlayout.h | 30 | ||||
-rw-r--r-- | gtk/gtktextmark.c | 26 | ||||
-rw-r--r-- | gtk/gtktextmark.h | 12 | ||||
-rw-r--r-- | gtk/gtktextview.c | 144 | ||||
-rw-r--r-- | gtk/gtktextview.h | 17 |
19 files changed, 740 insertions, 131 deletions
@@ -1,4 +1,40 @@ -2000-12-01 <alexl@redhat.com> +2000-11-30 Havoc Pennington <hp@pobox.com> + + * gtk/gtktextdisplay.c (gtk_text_layout_draw): don't create + dangling pointers to the appearance attributes from the + line display + + * gdk/gdkdraw.c (gdk_drawable_get_image): allow negative + width/height to mean "full width/height of drawable" + + * gtk/gtktextview.h, gtk/gtktextview.c: Implement double/triple + click to select word/line + + * gtk/gtktextiter.c (test_log_attrs): include paragraph delimiters + when getting log attrs. Get a slice, so that pixmaps and stuff + are properly handled. + + * gtk/gtktextbuffer.c (paste): Fix pasting to work properly if you + paste into the selection (replaces selection now, previously + crashed or added to selection). Reveals longstanding btree bug - + select multiple lines, middle-click on the selection, boom. This + isn't related to my changes though. + + * gtk/gtkentry.c (gtk_entry_move_forward_word): Update to reflect + PangoLogAttrs changes + (gtk_entry_move_backward_word): ditto + + * gtk/gtktextlayout.h, gtk/gtktextlayout.c: Make the iter motion + functions return bool whether the iter moved onto a + dereferenceable position. + + * gtk/gtktextview.h, gtk/gtktextview.c: Add a bunch of public + functions for motion in terms of display lines. + + * gtk/gtktextmark.c (gtk_text_mark_get_buffer): Add function to + get the buffer a mark is inside + +2000-12-01 Alexander Larsson <alexl@redhat.com> * gdk/linux-fb/Makefile.am: * modules/linux-fb/Makefile.am: diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 6f525e6152..49b9f5c17a 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,4 +1,40 @@ -2000-12-01 <alexl@redhat.com> +2000-11-30 Havoc Pennington <hp@pobox.com> + + * gtk/gtktextdisplay.c (gtk_text_layout_draw): don't create + dangling pointers to the appearance attributes from the + line display + + * gdk/gdkdraw.c (gdk_drawable_get_image): allow negative + width/height to mean "full width/height of drawable" + + * gtk/gtktextview.h, gtk/gtktextview.c: Implement double/triple + click to select word/line + + * gtk/gtktextiter.c (test_log_attrs): include paragraph delimiters + when getting log attrs. Get a slice, so that pixmaps and stuff + are properly handled. + + * gtk/gtktextbuffer.c (paste): Fix pasting to work properly if you + paste into the selection (replaces selection now, previously + crashed or added to selection). Reveals longstanding btree bug - + select multiple lines, middle-click on the selection, boom. This + isn't related to my changes though. + + * gtk/gtkentry.c (gtk_entry_move_forward_word): Update to reflect + PangoLogAttrs changes + (gtk_entry_move_backward_word): ditto + + * gtk/gtktextlayout.h, gtk/gtktextlayout.c: Make the iter motion + functions return bool whether the iter moved onto a + dereferenceable position. + + * gtk/gtktextview.h, gtk/gtktextview.c: Add a bunch of public + functions for motion in terms of display lines. + + * gtk/gtktextmark.c (gtk_text_mark_get_buffer): Add function to + get the buffer a mark is inside + +2000-12-01 Alexander Larsson <alexl@redhat.com> * gdk/linux-fb/Makefile.am: * modules/linux-fb/Makefile.am: diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 6f525e6152..49b9f5c17a 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,4 +1,40 @@ -2000-12-01 <alexl@redhat.com> +2000-11-30 Havoc Pennington <hp@pobox.com> + + * gtk/gtktextdisplay.c (gtk_text_layout_draw): don't create + dangling pointers to the appearance attributes from the + line display + + * gdk/gdkdraw.c (gdk_drawable_get_image): allow negative + width/height to mean "full width/height of drawable" + + * gtk/gtktextview.h, gtk/gtktextview.c: Implement double/triple + click to select word/line + + * gtk/gtktextiter.c (test_log_attrs): include paragraph delimiters + when getting log attrs. Get a slice, so that pixmaps and stuff + are properly handled. + + * gtk/gtktextbuffer.c (paste): Fix pasting to work properly if you + paste into the selection (replaces selection now, previously + crashed or added to selection). Reveals longstanding btree bug - + select multiple lines, middle-click on the selection, boom. This + isn't related to my changes though. + + * gtk/gtkentry.c (gtk_entry_move_forward_word): Update to reflect + PangoLogAttrs changes + (gtk_entry_move_backward_word): ditto + + * gtk/gtktextlayout.h, gtk/gtktextlayout.c: Make the iter motion + functions return bool whether the iter moved onto a + dereferenceable position. + + * gtk/gtktextview.h, gtk/gtktextview.c: Add a bunch of public + functions for motion in terms of display lines. + + * gtk/gtktextmark.c (gtk_text_mark_get_buffer): Add function to + get the buffer a mark is inside + +2000-12-01 Alexander Larsson <alexl@redhat.com> * gdk/linux-fb/Makefile.am: * modules/linux-fb/Makefile.am: diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 6f525e6152..49b9f5c17a 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,4 +1,40 @@ -2000-12-01 <alexl@redhat.com> +2000-11-30 Havoc Pennington <hp@pobox.com> + + * gtk/gtktextdisplay.c (gtk_text_layout_draw): don't create + dangling pointers to the appearance attributes from the + line display + + * gdk/gdkdraw.c (gdk_drawable_get_image): allow negative + width/height to mean "full width/height of drawable" + + * gtk/gtktextview.h, gtk/gtktextview.c: Implement double/triple + click to select word/line + + * gtk/gtktextiter.c (test_log_attrs): include paragraph delimiters + when getting log attrs. Get a slice, so that pixmaps and stuff + are properly handled. + + * gtk/gtktextbuffer.c (paste): Fix pasting to work properly if you + paste into the selection (replaces selection now, previously + crashed or added to selection). Reveals longstanding btree bug - + select multiple lines, middle-click on the selection, boom. This + isn't related to my changes though. + + * gtk/gtkentry.c (gtk_entry_move_forward_word): Update to reflect + PangoLogAttrs changes + (gtk_entry_move_backward_word): ditto + + * gtk/gtktextlayout.h, gtk/gtktextlayout.c: Make the iter motion + functions return bool whether the iter moved onto a + dereferenceable position. + + * gtk/gtktextview.h, gtk/gtktextview.c: Add a bunch of public + functions for motion in terms of display lines. + + * gtk/gtktextmark.c (gtk_text_mark_get_buffer): Add function to + get the buffer a mark is inside + +2000-12-01 Alexander Larsson <alexl@redhat.com> * gdk/linux-fb/Makefile.am: * modules/linux-fb/Makefile.am: diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 6f525e6152..49b9f5c17a 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,4 +1,40 @@ -2000-12-01 <alexl@redhat.com> +2000-11-30 Havoc Pennington <hp@pobox.com> + + * gtk/gtktextdisplay.c (gtk_text_layout_draw): don't create + dangling pointers to the appearance attributes from the + line display + + * gdk/gdkdraw.c (gdk_drawable_get_image): allow negative + width/height to mean "full width/height of drawable" + + * gtk/gtktextview.h, gtk/gtktextview.c: Implement double/triple + click to select word/line + + * gtk/gtktextiter.c (test_log_attrs): include paragraph delimiters + when getting log attrs. Get a slice, so that pixmaps and stuff + are properly handled. + + * gtk/gtktextbuffer.c (paste): Fix pasting to work properly if you + paste into the selection (replaces selection now, previously + crashed or added to selection). Reveals longstanding btree bug - + select multiple lines, middle-click on the selection, boom. This + isn't related to my changes though. + + * gtk/gtkentry.c (gtk_entry_move_forward_word): Update to reflect + PangoLogAttrs changes + (gtk_entry_move_backward_word): ditto + + * gtk/gtktextlayout.h, gtk/gtktextlayout.c: Make the iter motion + functions return bool whether the iter moved onto a + dereferenceable position. + + * gtk/gtktextview.h, gtk/gtktextview.c: Add a bunch of public + functions for motion in terms of display lines. + + * gtk/gtktextmark.c (gtk_text_mark_get_buffer): Add function to + get the buffer a mark is inside + +2000-12-01 Alexander Larsson <alexl@redhat.com> * gdk/linux-fb/Makefile.am: * modules/linux-fb/Makefile.am: diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 6f525e6152..49b9f5c17a 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,4 +1,40 @@ -2000-12-01 <alexl@redhat.com> +2000-11-30 Havoc Pennington <hp@pobox.com> + + * gtk/gtktextdisplay.c (gtk_text_layout_draw): don't create + dangling pointers to the appearance attributes from the + line display + + * gdk/gdkdraw.c (gdk_drawable_get_image): allow negative + width/height to mean "full width/height of drawable" + + * gtk/gtktextview.h, gtk/gtktextview.c: Implement double/triple + click to select word/line + + * gtk/gtktextiter.c (test_log_attrs): include paragraph delimiters + when getting log attrs. Get a slice, so that pixmaps and stuff + are properly handled. + + * gtk/gtktextbuffer.c (paste): Fix pasting to work properly if you + paste into the selection (replaces selection now, previously + crashed or added to selection). Reveals longstanding btree bug - + select multiple lines, middle-click on the selection, boom. This + isn't related to my changes though. + + * gtk/gtkentry.c (gtk_entry_move_forward_word): Update to reflect + PangoLogAttrs changes + (gtk_entry_move_backward_word): ditto + + * gtk/gtktextlayout.h, gtk/gtktextlayout.c: Make the iter motion + functions return bool whether the iter moved onto a + dereferenceable position. + + * gtk/gtktextview.h, gtk/gtktextview.c: Add a bunch of public + functions for motion in terms of display lines. + + * gtk/gtktextmark.c (gtk_text_mark_get_buffer): Add function to + get the buffer a mark is inside + +2000-12-01 Alexander Larsson <alexl@redhat.com> * gdk/linux-fb/Makefile.am: * modules/linux-fb/Makefile.am: diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 6f525e6152..49b9f5c17a 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,4 +1,40 @@ -2000-12-01 <alexl@redhat.com> +2000-11-30 Havoc Pennington <hp@pobox.com> + + * gtk/gtktextdisplay.c (gtk_text_layout_draw): don't create + dangling pointers to the appearance attributes from the + line display + + * gdk/gdkdraw.c (gdk_drawable_get_image): allow negative + width/height to mean "full width/height of drawable" + + * gtk/gtktextview.h, gtk/gtktextview.c: Implement double/triple + click to select word/line + + * gtk/gtktextiter.c (test_log_attrs): include paragraph delimiters + when getting log attrs. Get a slice, so that pixmaps and stuff + are properly handled. + + * gtk/gtktextbuffer.c (paste): Fix pasting to work properly if you + paste into the selection (replaces selection now, previously + crashed or added to selection). Reveals longstanding btree bug - + select multiple lines, middle-click on the selection, boom. This + isn't related to my changes though. + + * gtk/gtkentry.c (gtk_entry_move_forward_word): Update to reflect + PangoLogAttrs changes + (gtk_entry_move_backward_word): ditto + + * gtk/gtktextlayout.h, gtk/gtktextlayout.c: Make the iter motion + functions return bool whether the iter moved onto a + dereferenceable position. + + * gtk/gtktextview.h, gtk/gtktextview.c: Add a bunch of public + functions for motion in terms of display lines. + + * gtk/gtktextmark.c (gtk_text_mark_get_buffer): Add function to + get the buffer a mark is inside + +2000-12-01 Alexander Larsson <alexl@redhat.com> * gdk/linux-fb/Makefile.am: * modules/linux-fb/Makefile.am: diff --git a/gdk/gdkdraw.c b/gdk/gdkdraw.c index facc185e9c..fcab539e58 100644 --- a/gdk/gdkdraw.c +++ b/gdk/gdkdraw.c @@ -486,9 +486,12 @@ gdk_drawable_get_image (GdkDrawable *drawable, g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (x >= 0, NULL); g_return_val_if_fail (y >= 0, NULL); - g_return_val_if_fail (width >= 0, NULL); - g_return_val_if_fail (height >= 0, NULL); + if (width < 0 || height < 0) + gdk_drawable_get_size (drawable, + width < 0 ? &width : NULL, + height < 0 ? &height : NULL); + composite = GDK_DRAWABLE_GET_CLASS (drawable)->get_composite_drawable (drawable, x, y, diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index 865f261b9a..45c7f05927 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -2111,20 +2111,12 @@ gtk_entry_move_forward_word (GtkEntry *entry, gint n_attrs; pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs); - - /* Advance over white space */ - while (new_pos < n_attrs && log_attrs[new_pos].is_white) - new_pos++; - /* Find the next word beginning */ + /* Find the next word end */ new_pos++; - while (new_pos < n_attrs && !log_attrs[new_pos].is_word_stop) + while (new_pos < n_attrs && !log_attrs[new_pos].is_word_end) new_pos++; - /* Back up over white space */ - while (new_pos > 0 && log_attrs[new_pos - 1].is_white) - new_pos--; - g_free (log_attrs); g_object_unref (G_OBJECT (layout)); } @@ -2155,7 +2147,7 @@ gtk_entry_move_backward_word (GtkEntry *entry, new_pos = start - 1; /* Find the previous word beginning */ - while (new_pos > 0 && !log_attrs[new_pos].is_word_stop) + while (new_pos > 0 && !log_attrs[new_pos].is_word_start) new_pos--; g_free (log_attrs); diff --git a/gtk/gtktextbuffer.c b/gtk/gtktextbuffer.c index 9cd8dbba9f..db770bab66 100644 --- a/gtk/gtktextbuffer.c +++ b/gtk/gtktextbuffer.c @@ -2172,24 +2172,40 @@ pre_paste_prep (ClipboardRequest *request_data, GtkTextIter *insert_point) { GtkTextBuffer *buffer = request_data->buffer; + + get_paste_point (buffer, insert_point, TRUE); + /* If we're going to replace the selection, we insert before it to + * avoid messing it up, then we delete the selection after inserting. + */ if (request_data->replace_selection) { GtkTextIter start, end; if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end)) + *insert_point = start; + } +} + +static void +post_paste_cleanup (ClipboardRequest *request_data) +{ + if (request_data->replace_selection) + { + GtkTextIter start, end; + + if (gtk_text_buffer_get_selection_bounds (request_data->buffer, + &start, &end)) { if (request_data->interactive) - gtk_text_buffer_delete_interactive (buffer, + gtk_text_buffer_delete_interactive (request_data->buffer, &start, &end, request_data->default_editable); else - gtk_text_buffer_delete (buffer, &start, &end); + gtk_text_buffer_delete (request_data->buffer, &start, &end); } } - - get_paste_point (buffer, insert_point, TRUE); } /* Called when we request a paste and receive the text data @@ -2214,6 +2230,8 @@ clipboard_text_received (GtkClipboard *clipboard, else gtk_text_buffer_insert (buffer, &insert_point, str, -1); + + post_paste_cleanup (request_data); } g_object_unref (G_OBJECT (buffer)); @@ -2253,6 +2271,33 @@ selection_data_get_buffer (GtkSelectionData *selection_data, return src_buffer; } +#if 0 +/* These are pretty handy functions; maybe something like them + * should be in the public API. Also, there are other places in this + * file where they could be used. + */ +static gpointer +save_iter (const GtkTextIter *iter, + gboolean left_gravity) +{ + return gtk_text_buffer_create_mark (gtk_text_iter_get_buffer (iter), + NULL, + iter, + TRUE); +} + +static void +restore_iter (const GtkTextIter *iter, + gpointer save_id) +{ + gtk_text_buffer_get_iter_at_mark (gtk_text_mark_get_buffer (save_id), + (GtkTextIter*) iter, + save_id); + gtk_text_buffer_delete_mark (gtk_text_mark_get_buffer (save_id), + save_id); +} +#endif + static void paste_from_buffer (ClipboardRequest *request_data, GtkTextBuffer *src_buffer, @@ -2274,6 +2319,8 @@ paste_from_buffer (ClipboardRequest *request_data, end, request_data->interactive); } + + post_paste_cleanup (request_data); g_object_unref (G_OBJECT (src_buffer)); } @@ -2392,13 +2439,14 @@ paste (GtkTextBuffer *buffer, * replace the selection with the new text, otherwise, you * simply insert the new text at the point where the click * occured, unselecting any selected text. The replace_selection - * flag toggles this behavior. FIXME set the flag based on something. + * flag toggles this behavior. */ data->replace_selection = FALSE; get_paste_point (buffer, &paste_point, FALSE); if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end) && - gtk_text_iter_in_range (&paste_point, &start, &end)) + (gtk_text_iter_in_range (&paste_point, &start, &end) || + gtk_text_iter_equal (&paste_point, &end))) data->replace_selection = TRUE; if (is_clipboard) diff --git a/gtk/gtktextdisplay.c b/gtk/gtktextdisplay.c index e5a6d3b721..b02ade89f4 100644 --- a/gtk/gtktextdisplay.c +++ b/gtk/gtktextdisplay.c @@ -796,7 +796,9 @@ gtk_text_layout_draw (GtkTextLayout *layout, current_y += line_display->height; gtk_text_layout_free_line_display (layout, line_display); - + render_state->last_appearance = NULL; + render_state->last_bg_appearance = NULL; + tmp_list = g_slist_next (tmp_list); } diff --git a/gtk/gtktextiter.c b/gtk/gtktextiter.c index 1d90ceb433..d73e0a8589 100644 --- a/gtk/gtktextiter.c +++ b/gtk/gtktextiter.c @@ -2368,14 +2368,9 @@ find_word_end_func (PangoLogAttr *attrs, { ++offset; /* We always go to the NEXT word end */ - /* Find start of next word */ + /* Find end of next word */ while (offset < min_offset + len && - !attrs[offset].is_word_stop) - ++offset; - - /* Find end */ - while (offset < min_offset + len && - !attrs[offset].is_white) + !attrs[offset].is_word_end) ++offset; *found_offset = offset; @@ -2384,6 +2379,16 @@ find_word_end_func (PangoLogAttr *attrs, } static gboolean +is_word_end_func (PangoLogAttr *attrs, + gint offset, + gint min_offset, + gint len, + gint *found_offset) +{ + return attrs[offset].is_word_end; +} + +static gboolean find_word_start_func (PangoLogAttr *attrs, gint offset, gint min_offset, @@ -2392,14 +2397,9 @@ find_word_start_func (PangoLogAttr *attrs, { --offset; /* We always go to the NEXT word start */ - /* Find end of prev word */ + /* Find start of prev word */ while (offset >= min_offset && - attrs[offset].is_white) - --offset; - - /* Find start */ - while (offset >= min_offset && - !attrs[offset].is_word_stop) + !attrs[offset].is_word_start) --offset; *found_offset = offset; @@ -2407,31 +2407,53 @@ find_word_start_func (PangoLogAttr *attrs, return offset >= min_offset; } -/* FIXME this function is very, very gratuitously slow */ static gboolean -find_by_log_attrs (GtkTextIter *iter, - FindLogAttrFunc func, - gboolean forward) +is_word_start_func (PangoLogAttr *attrs, + gint offset, + gint min_offset, + gint len, + gint *found_offset) +{ + return attrs[offset].is_word_start; +} + +static gboolean +inside_word_func (PangoLogAttr *attrs, + gint offset, + gint min_offset, + gint len, + gint *found_offset) +{ + /* Find next word start or end */ + while (offset >= min_offset && + !(attrs[offset].is_word_start || attrs[offset].is_word_end)) + --offset; + + return attrs[offset].is_word_start; +} + +static gboolean +test_log_attrs (GtkTextIter *iter, + FindLogAttrFunc func, + gint *found_offset) { - GtkTextIter orig; GtkTextIter start; GtkTextIter end; gchar *paragraph; gint char_len, byte_len; PangoLogAttr *attrs; int offset; - gboolean found = FALSE; + gboolean result = FALSE; g_return_val_if_fail (iter != NULL, FALSE); - orig = *iter; start = *iter; end = *iter; gtk_text_iter_set_line_offset (&start, 0); - gtk_text_iter_forward_to_newline (&end); + gtk_text_iter_forward_line (&end); - paragraph = gtk_text_iter_get_text (&start, &end); + paragraph = gtk_text_iter_get_slice (&start, &end); char_len = g_utf8_strlen (paragraph, -1); byte_len = strlen (paragraph); @@ -2451,13 +2473,32 @@ find_by_log_attrs (GtkTextIter *iter, g_free (lang); - found = (* func) (attrs, offset, 0, char_len, &offset); + result = (* func) (attrs, offset, 0, char_len, found_offset); g_free (attrs); } g_free (paragraph); + return result; +} + +/* FIXME this function is very, very gratuitously slow */ +static gboolean +find_by_log_attrs (GtkTextIter *iter, + FindLogAttrFunc func, + gboolean forward) +{ + GtkTextIter orig; + gint offset = 0; + gboolean found = FALSE; + + g_return_val_if_fail (iter != NULL, FALSE); + + orig = *iter; + + found = test_log_attrs (iter, func, &offset); + if (!found) { if (forward) @@ -2502,7 +2543,7 @@ gtk_text_iter_backward_word_start (GtkTextIter *iter) */ gboolean gtk_text_iter_forward_word_ends (GtkTextIter *iter, - gint count) + gint count) { g_return_val_if_fail (iter != NULL, FALSE); g_return_val_if_fail (count > 0, FALSE); @@ -2540,6 +2581,25 @@ gtk_text_iter_backward_word_starts (GtkTextIter *iter, return TRUE; } + +gboolean +gtk_text_iter_starts_word (const GtkTextIter *iter) +{ + return test_log_attrs (iter, is_word_start_func, NULL); +} + +gboolean +gtk_text_iter_ends_word (const GtkTextIter *iter) +{ + return test_log_attrs (iter, is_word_end_func, NULL); +} + +gboolean +gtk_text_iter_inside_word (const GtkTextIter *iter) +{ + return test_log_attrs (iter, inside_word_func, NULL); +} + void gtk_text_iter_set_line_offset (GtkTextIter *iter, gint char_on_line) diff --git a/gtk/gtktextiter.h b/gtk/gtktextiter.h index caadecb2a2..1c32fdaeb0 100644 --- a/gtk/gtktextiter.h +++ b/gtk/gtktextiter.h @@ -124,6 +124,9 @@ GSList *gtk_text_iter_get_tags (const GtkTextIter *iter); gboolean gtk_text_iter_editable (const GtkTextIter *iter, gboolean default_setting); +gboolean gtk_text_iter_starts_word (const GtkTextIter *iter); +gboolean gtk_text_iter_ends_word (const GtkTextIter *iter); +gboolean gtk_text_iter_inside_word (const GtkTextIter *iter); gboolean gtk_text_iter_starts_line (const GtkTextIter *iter); gboolean gtk_text_iter_ends_line (const GtkTextIter *iter); diff --git a/gtk/gtktextlayout.c b/gtk/gtktextlayout.c index c43320e505..877eadc3e9 100644 --- a/gtk/gtktextlayout.c +++ b/gtk/gtktextlayout.c @@ -2209,7 +2209,6 @@ find_display_line_below (GtkTextLayout *layout, while (line && !found_line) { GtkTextLineDisplay *display = gtk_text_layout_get_line_display (layout, line, FALSE); - gint byte_index = 0; PangoLayoutIter *layout_iter; layout_iter = pango_layout_get_iter (display->layout); @@ -2221,7 +2220,7 @@ find_display_line_below (GtkTextLayout *layout, gint first_y, last_y; PangoLayoutLine *layout_line = pango_layout_iter_get_line (layout_iter); - found_byte = byte_index; + found_byte = layout_line->start_index; if (line_top >= y) { @@ -2231,8 +2230,6 @@ find_display_line_below (GtkTextLayout *layout, pango_layout_iter_get_line_yrange (layout_iter, &first_y, &last_y); line_top += (last_y - first_y) / PANGO_SCALE; - - byte_index += layout_line->length; } while (pango_layout_iter_next_line (layout_iter)); @@ -2278,8 +2275,6 @@ find_display_line_above (GtkTextLayout *layout, { GtkTextLineDisplay *display = gtk_text_layout_get_line_display (layout, line, FALSE); PangoRectangle logical_rect; - - gint byte_index = 0; PangoLayoutIter *layout_iter; gint tmp_top; @@ -2296,7 +2291,7 @@ find_display_line_above (GtkTextLayout *layout, gint first_y, last_y; PangoLayoutLine *layout_line = pango_layout_iter_get_line (layout_iter); - found_byte = byte_index; + found_byte = layout_line->start_index; pango_layout_iter_get_line_yrange (layout_iter, &first_y, &last_y); @@ -2305,11 +2300,8 @@ find_display_line_above (GtkTextLayout *layout, if (tmp_top < y) { found_line = line; - found_byte = byte_index; goto done; } - - byte_index += layout_line->length; } while (pango_layout_iter_next_line (layout_iter)); @@ -2383,7 +2375,7 @@ gtk_text_layout_clamp_iter_to_vrange (GtkTextLayout *layout, * Move the iterator to the beginning of the previous line. The lines * of a wrapped paragraph are treated as distinct for this operation. **/ -void +gboolean gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout, GtkTextIter *iter) { @@ -2392,11 +2384,14 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout, gint line_byte; GSList *tmp_list; PangoLayoutLine *layout_line; + GtkTextIter orig; + + g_return_val_if_fail (layout != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); - g_return_if_fail (layout != NULL); - g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout)); - g_return_if_fail (iter != NULL); - + orig = *iter; + line = gtk_text_iter_get_text_line (iter); display = gtk_text_layout_get_line_display (layout, line, FALSE); line_byte = line_display_iter_to_index (layout, display, iter); @@ -2410,49 +2405,49 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout, if (prev_line) { - gint byte_offset = 0; - gtk_text_layout_free_line_display (layout, display); display = gtk_text_layout_get_line_display (layout, prev_line, FALSE); - tmp_list = pango_layout_get_lines (display->layout); - + tmp_list = pango_layout_get_lines (display->layout); + while (tmp_list->next) { layout_line = tmp_list->data; tmp_list = tmp_list->next; - - byte_offset += layout_line->length; } - line_display_index_to_iter (layout, display, iter, byte_offset, 0); + line_display_index_to_iter (layout, display, iter, + layout_line->start_index + layout_line->length, 0); } else line_display_index_to_iter (layout, display, iter, 0, 0); } else { - gint prev_offset = 0; - gint byte_offset = layout_line->length; + gint prev_offset = layout_line->start_index; tmp_list = tmp_list->next; while (tmp_list) { layout_line = tmp_list->data; - if (line_byte < byte_offset + layout_line->length || !tmp_list->next) + if (line_byte < layout_line->start_index + layout_line->length || + !tmp_list->next) { line_display_index_to_iter (layout, display, iter, prev_offset, 0); break; } - prev_offset = byte_offset; - byte_offset += layout_line->length; + prev_offset = layout_line->start_index; tmp_list = tmp_list->next; } } gtk_text_layout_free_line_display (layout, display); + + return + !gtk_text_iter_equal (iter, &orig) && + !gtk_text_iter_is_last (iter); } /** @@ -2464,27 +2459,28 @@ gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout, * lines of a wrapped paragraph are treated as distinct for * this operation. **/ -void +gboolean gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout, GtkTextIter *iter) { GtkTextLine *line; GtkTextLineDisplay *display; gint line_byte; - + GtkTextIter orig; gboolean found = FALSE; gboolean found_after = FALSE; gboolean first = TRUE; - g_return_if_fail (layout != NULL); - g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout)); - g_return_if_fail (iter != NULL); + g_return_val_if_fail (layout != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + orig = *iter; + line = gtk_text_iter_get_text_line (iter); while (line && !found_after) { - gint byte_offset = 0; GSList *tmp_list; display = gtk_text_layout_get_line_display (layout, line, FALSE); @@ -2504,13 +2500,13 @@ gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout, if (found) { - line_display_index_to_iter (layout, display, iter, byte_offset, 0); + line_display_index_to_iter (layout, display, iter, + layout_line->start_index, 0); found_after = TRUE; } - else if (line_byte < byte_offset + layout_line->length || !tmp_list->next) + else if (line_byte < layout_line->start_index + layout_line->length || !tmp_list->next) found = TRUE; - - byte_offset += layout_line->length; + tmp_list = tmp_list->next; } @@ -2518,6 +2514,10 @@ gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout, line = gtk_text_line_next (line); } + + return + !gtk_text_iter_equal (iter, &orig) && + !gtk_text_iter_is_last (iter); } /** @@ -2528,7 +2528,7 @@ gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout, * * Move to the beginning or end of a display line. **/ -void +gboolean gtk_text_layout_move_iter_to_line_end (GtkTextLayout *layout, GtkTextIter *iter, gint direction) @@ -2536,13 +2536,15 @@ gtk_text_layout_move_iter_to_line_end (GtkTextLayout *layout, GtkTextLine *line; GtkTextLineDisplay *display; gint line_byte; - gint byte_offset = 0; GSList *tmp_list; + GtkTextIter orig; + + g_return_val_if_fail (layout != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); - g_return_if_fail (layout != NULL); - g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout)); - g_return_if_fail (iter != NULL); - + orig = *iter; + line = gtk_text_iter_get_text_line (iter); display = gtk_text_layout_get_line_display (layout, line, FALSE); line_byte = line_display_iter_to_index (layout, display, iter); @@ -2552,10 +2554,10 @@ gtk_text_layout_move_iter_to_line_end (GtkTextLayout *layout, { PangoLayoutLine *layout_line = tmp_list->data; - if (line_byte < byte_offset + layout_line->length || !tmp_list->next) + if (line_byte < layout_line->start_index + layout_line->length || !tmp_list->next) { line_display_index_to_iter (layout, display, iter, - direction < 0 ? byte_offset : byte_offset + layout_line->length, + direction < 0 ? layout_line->start_index : layout_line->start_index + layout_line->length, 0); /* FIXME: As a bad hack, we move back one position when we @@ -2567,12 +2569,66 @@ gtk_text_layout_move_iter_to_line_end (GtkTextLayout *layout, break; } - - byte_offset += layout_line->length; + tmp_list = tmp_list->next; } gtk_text_layout_free_line_display (layout, display); + + return + !gtk_text_iter_equal (iter, &orig) && + !gtk_text_iter_is_last (iter); +} + + +/** + * gtk_text_layout_iter_starts_line: + * @layout: a #GtkTextLayout + * @iter: iterator to test + * + * Tests whether an iterator is at the start of a display line. + **/ +gboolean +gtk_text_layout_iter_starts_line (GtkTextLayout *layout, + const GtkTextIter *iter) +{ + GtkTextLine *line; + GtkTextLineDisplay *display; + gint line_byte; + GSList *tmp_list; + + g_return_val_if_fail (layout != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT_LAYOUT (layout), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + + line = gtk_text_iter_get_text_line (iter); + display = gtk_text_layout_get_line_display (layout, line, FALSE); + line_byte = line_display_iter_to_index (layout, display, iter); + + tmp_list = pango_layout_get_lines (display->layout); + while (tmp_list) + { + PangoLayoutLine *layout_line = tmp_list->data; + + if (line_byte < layout_line->start_index + layout_line->length || + !tmp_list->next) + { + /* We're located on this line of the para delimiters before + * it + */ + gtk_text_layout_free_line_display (layout, display); + + if (line_byte == layout_line->start_index) + return TRUE; + else + return FALSE; + } + + tmp_list = tmp_list->next; + } + + g_assert_not_reached (); + return FALSE; } /** @@ -2593,7 +2649,6 @@ gtk_text_layout_move_iter_to_x (GtkTextLayout *layout, GtkTextLine *line; GtkTextLineDisplay *display; gint line_byte; - gint byte_offset = 0; PangoLayoutIter *layout_iter; g_return_if_fail (layout != NULL); @@ -2611,7 +2666,7 @@ gtk_text_layout_move_iter_to_x (GtkTextLayout *layout, { PangoLayoutLine *layout_line = pango_layout_iter_get_line (layout_iter); - if (line_byte < byte_offset + layout_line->length || + if (line_byte < layout_line->start_index + layout_line->length || pango_layout_iter_at_last_line (layout_iter)) { PangoRectangle logical_rect; @@ -2628,8 +2683,6 @@ gtk_text_layout_move_iter_to_x (GtkTextLayout *layout, break; } - - byte_offset += layout_line->length; } while (pango_layout_iter_next_line (layout_iter)); @@ -2657,16 +2710,19 @@ gtk_text_layout_move_iter_to_x (GtkTextLayout *layout, * is moved off of the end of a run. **/ -void +gboolean gtk_text_layout_move_iter_visually (GtkTextLayout *layout, GtkTextIter *iter, gint count) { GtkTextLineDisplay *display = NULL; + GtkTextIter orig; + + g_return_val_if_fail (layout != NULL, FALSE); + g_return_val_if_fail (iter != NULL, FALSE); - g_return_if_fail (layout != NULL); - g_return_if_fail (iter != NULL); - + orig = *iter; + while (count != 0) { GtkTextLine *line = gtk_text_iter_get_text_line (iter); @@ -2715,8 +2771,8 @@ gtk_text_layout_move_iter_visually (GtkTextLayout *layout, line = gtk_text_line_previous (line); if (!line) - return; - + goto done; + gtk_text_layout_free_line_display (layout, display); display = gtk_text_layout_get_line_display (layout, line, FALSE); new_index = gtk_text_line_byte_count (line); @@ -2725,7 +2781,7 @@ gtk_text_layout_move_iter_visually (GtkTextLayout *layout, { line = gtk_text_line_next (line); if (!line) - return; + goto done; gtk_text_layout_free_line_display (layout, display); display = gtk_text_layout_get_line_display (layout, line, FALSE); @@ -2738,6 +2794,12 @@ gtk_text_layout_move_iter_visually (GtkTextLayout *layout, } gtk_text_layout_free_line_display (layout, display); + + done: + + return + !gtk_text_iter_equal (iter, &orig) && + !gtk_text_iter_is_last (iter); } void diff --git a/gtk/gtktextlayout.h b/gtk/gtktextlayout.h index 81e8824f01..8977a97eb7 100644 --- a/gtk/gtktextlayout.h +++ b/gtk/gtktextlayout.h @@ -339,20 +339,22 @@ gboolean gtk_text_layout_clamp_iter_to_vrange (GtkTextLayout *layout, gint top, gint bottom); -void gtk_text_layout_move_iter_to_line_end (GtkTextLayout *layout, - GtkTextIter *iter, - gint direction); -void gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout, - GtkTextIter *iter); -void gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout, - GtkTextIter *iter); -void gtk_text_layout_move_iter_to_x (GtkTextLayout *layout, - GtkTextIter *iter, - gint x); -void gtk_text_layout_move_iter_visually (GtkTextLayout *layout, - GtkTextIter *iter, - gint count); - +gboolean gtk_text_layout_move_iter_to_line_end (GtkTextLayout *layout, + GtkTextIter *iter, + gint direction); +gboolean gtk_text_layout_move_iter_to_previous_line (GtkTextLayout *layout, + GtkTextIter *iter); +gboolean gtk_text_layout_move_iter_to_next_line (GtkTextLayout *layout, + GtkTextIter *iter); +void gtk_text_layout_move_iter_to_x (GtkTextLayout *layout, + GtkTextIter *iter, + gint x); +gboolean gtk_text_layout_move_iter_visually (GtkTextLayout *layout, + GtkTextIter *iter, + gint count); + +gboolean gtk_text_layout_iter_starts_line (GtkTextLayout *layout, + const GtkTextIter *iter); /* Don't use these. Use gtk_text_view_add_child_at_anchor(). * These functions are defined in gtktextchild.c, but here diff --git a/gtk/gtktextmark.c b/gtk/gtktextmark.c index 4e20eb300c..e18ea3295e 100644 --- a/gtk/gtktextmark.c +++ b/gtk/gtktextmark.c @@ -179,7 +179,7 @@ gtk_text_mark_get_deleted (GtkTextMark *mark) { GtkTextLineSegment *seg; - g_return_val_if_fail (mark != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT_MARK (mark), FALSE); seg = mark->segment; @@ -189,6 +189,30 @@ gtk_text_mark_get_deleted (GtkTextMark *mark) return seg->body.mark.tree == NULL; } +/** + * gtk_text_mark_get_buffer: + * @mark: a #GtkTextMark + * + * Gets the buffer this mark is located inside, + * or NULL if the mark is deleted. + * + * Return value: the mark's #GtkTextBuffer + **/ +GtkTextBuffer* +gtk_text_mark_get_buffer (GtkTextMark *mark) +{ + GtkTextLineSegment *seg; + + g_return_val_if_fail (GTK_IS_TEXT_MARK (mark), FALSE); + + seg = mark->segment; + + if (seg->body.mark.tree == NULL) + return NULL; + else + return gtk_text_btree_get_buffer (seg->body.mark.tree); +} + /* * Macro that determines the size of a mark segment: */ diff --git a/gtk/gtktextmark.h b/gtk/gtktextmark.h index e2130c5acd..3b2d0fc9aa 100644 --- a/gtk/gtktextmark.h +++ b/gtk/gtktextmark.h @@ -81,12 +81,14 @@ struct _GtkTextMarkClass GType gtk_text_mark_get_type (void) G_GNUC_CONST; -void gtk_text_mark_set_visible (GtkTextMark *mark, - gboolean setting); -gboolean gtk_text_mark_get_visible (GtkTextMark *mark); +void gtk_text_mark_set_visible (GtkTextMark *mark, + gboolean setting); +gboolean gtk_text_mark_get_visible (GtkTextMark *mark); + /* FIXME gconst */ -const char *gtk_text_mark_get_name (GtkTextMark *mark); -gboolean gtk_text_mark_get_deleted (GtkTextMark *mark); +const char * gtk_text_mark_get_name (GtkTextMark *mark); +gboolean gtk_text_mark_get_deleted (GtkTextMark *mark); +GtkTextBuffer* gtk_text_mark_get_buffer (GtkTextMark *mark); #ifdef __cplusplus diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index 489a04e037..78ac46a6aa 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -2637,7 +2637,69 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event) gtk_text_view_popup_menu (text_view, event); } } + else if ((event->type == GDK_2BUTTON_PRESS || + event->type == GDK_3BUTTON_PRESS) && + event->button == 1) + { + GtkTextIter start, end; + + /* End the selection drag, otherwise we'd clear the new + * word/line selection on button release + */ + gtk_text_view_end_selection_drag (text_view, event); + + gtk_text_layout_get_iter_at_pixel (text_view->layout, + &start, + event->x + text_view->xoffset, + event->y + text_view->yoffset); + end = start; + + if (event->type == GDK_2BUTTON_PRESS) + { + if (gtk_text_iter_inside_word (&start)) + { + if (!gtk_text_iter_starts_word (&start)) + gtk_text_iter_backward_word_start (&start); + + if (!gtk_text_iter_ends_word (&end)) + gtk_text_iter_forward_word_end (&end); + } + } + else if (event->type == GDK_3BUTTON_PRESS) + { + if (gtk_text_view_starts_display_line (text_view, &start)) + { + /* If on a display line boundary, we assume the user + * clicked off the end of a line and we therefore select + * the line before the boundary. + */ + gtk_text_view_backward_display_line_start (text_view, &start); + } + else + { + /* start isn't on the start of a line, so we move it to the + * start, and move end to the end unless it's already there. + */ + gtk_text_view_backward_display_line_start (text_view, &start); + + if (!gtk_text_view_starts_display_line (text_view, &end)) + gtk_text_view_forward_display_line_end (text_view, &end); + } + } + + gtk_text_buffer_move_mark (get_buffer (text_view), + gtk_text_buffer_get_selection_bound (get_buffer (text_view)), + &start); + gtk_text_buffer_move_mark (get_buffer (text_view), + gtk_text_buffer_get_insert (get_buffer (text_view)), + &end); + + text_view->just_selected_element = TRUE; + + return TRUE; + } + return FALSE; } @@ -2661,6 +2723,11 @@ gtk_text_view_button_release_event (GtkWidget *widget, GdkEventButton *event) if (gtk_text_view_end_selection_drag (GTK_TEXT_VIEW (widget), event)) return TRUE; + else if (text_view->just_selected_element) + { + text_view->just_selected_element = FALSE; + return FALSE; + } else { /* Unselect everything; probably we were dragging, or clicked @@ -5457,3 +5524,80 @@ gtk_text_view_move_child (GtkTextView *text_view, } + +/* Iterator operations */ + +gboolean +gtk_text_view_forward_display_line (GtkTextView *text_view, + GtkTextIter *iter) +{ + g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + + gtk_text_view_ensure_layout (text_view); + + return gtk_text_layout_move_iter_to_next_line (text_view->layout, iter); +} + +gboolean +gtk_text_view_backward_display_line (GtkTextView *text_view, + GtkTextIter *iter) +{ + g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + + gtk_text_view_ensure_layout (text_view); + + return gtk_text_layout_move_iter_to_previous_line (text_view->layout, iter); +} + +gboolean +gtk_text_view_forward_display_line_end (GtkTextView *text_view, + GtkTextIter *iter) +{ + g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + + gtk_text_view_ensure_layout (text_view); + + return gtk_text_layout_move_iter_to_line_end (text_view->layout, iter, 1); +} + +gboolean +gtk_text_view_backward_display_line_start (GtkTextView *text_view, + GtkTextIter *iter) +{ + g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + + gtk_text_view_ensure_layout (text_view); + + return gtk_text_layout_move_iter_to_line_end (text_view->layout, iter, -1); +} + +gboolean +gtk_text_view_starts_display_line (GtkTextView *text_view, + const GtkTextIter *iter) +{ + g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + + gtk_text_view_ensure_layout (text_view); + + return gtk_text_layout_iter_starts_line (text_view->layout, iter); +} + +gboolean +gtk_text_view_move_visually (GtkTextView *text_view, + GtkTextIter *iter, + gint count) +{ + g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE); + g_return_val_if_fail (iter != NULL, FALSE); + + gtk_text_view_ensure_layout (text_view); + + return gtk_text_layout_move_iter_visually (text_view->layout, iter, count); +} + + diff --git a/gtk/gtktextview.h b/gtk/gtktextview.h index 880cff302e..edcc8f2870 100644 --- a/gtk/gtktextview.h +++ b/gtk/gtktextview.h @@ -87,7 +87,9 @@ struct _GtkTextView guint overwrite_mode : 1; guint cursor_visible : 1; guint need_im_reset : 1; /* If we have reset the IM since the last character entered */ - + /* just selected a word or line via double/triple click */ + guint just_selected_element : 1; + GtkTextWindow *text_window; GtkTextWindow *left_window; GtkTextWindow *right_window; @@ -226,6 +228,19 @@ void gtk_text_view_set_text_window_size (GtkTextView *text_view, gint width, gint height); +gboolean gtk_text_view_forward_display_line (GtkTextView *text_view, + GtkTextIter *iter); +gboolean gtk_text_view_backward_display_line (GtkTextView *text_view, + GtkTextIter *iter); +gboolean gtk_text_view_forward_display_line_end (GtkTextView *text_view, + GtkTextIter *iter); +gboolean gtk_text_view_backward_display_line_start (GtkTextView *text_view, + GtkTextIter *iter); +gboolean gtk_text_view_starts_display_line (GtkTextView *text_view, + const GtkTextIter *iter); +gboolean gtk_text_view_move_visually (GtkTextView *text_view, + GtkTextIter *iter, + gint count); /* Adding child widgets */ void gtk_text_view_add_child_at_anchor (GtkTextView *text_view, |