From 8130a8a227f891d0d3aab433c7b19ccaf51e5fa7 Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Mon, 1 Mar 2004 16:07:45 +0000 Subject: [PATCH] Patch from Dov Grobgeld to implement auto-bidi-direction for GtkTextView Mon Mar 1 10:41:27 2004 Owen Taylor Patch from Dov Grobgeld to implement auto-bidi-direction for GtkTextView (#118543) * gtk/gtktextbtree.[ch]: Resolve bidi base direction for each line by propagating backwards/forwards as necessary. * gtk/gtktextlayout.[ch] gtk/gtktextview.c: Set the bidi base direction for the ;ine with the cursor from the keyboard direction. Add gtk_text_layout_set_keyboard_direction(). Mon Mar 1 10:31:11 2004 Owen Taylor * gtk/gtkentry.[ch]: Implement auto-bidi-direction, based on a patch from Dov Grobgeld. (#118540) --- ChangeLog | 15 +++- ChangeLog.pre-2-10 | 15 +++- ChangeLog.pre-2-4 | 15 +++- ChangeLog.pre-2-6 | 15 +++- ChangeLog.pre-2-8 | 15 +++- gtk/gtkentry.h | 1 + gtk/gtktextbtree.c | 175 ++++++++++++++++++++++++++++++++++++++++++ gtk/gtktextbtree.h | 3 + gtk/gtktextlayout.c | 182 +++++++++++++++++++++++++++++++++++++++----- gtk/gtktextlayout.h | 9 ++- gtk/gtktextview.c | 32 ++++---- 11 files changed, 439 insertions(+), 38 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7372e4ea3c..b167cde200 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,19 @@ +Mon Mar 1 10:41:27 2004 Owen Taylor + + Patch from Dov Grobgeld to implement auto-bidi-direction + for GtkTextView (#118543) + + * gtk/gtktextbtree.[ch]: Resolve bidi base direction + for each line by propagating backwards/forwards as + necessary. + + * gtk/gtktextlayout.[ch] gtk/gtktextview.c: Set the + bidi base direction for the ;ine with the cursor from + the keyboard direction. Add gtk_text_layout_set_keyboard_direction(). + Mon Mar 1 10:31:11 2004 Owen Taylor - * gtk/gtkentry.c: Implement auto-bidi-direction, + * gtk/gtkentry.[ch]: Implement auto-bidi-direction, based on a patch from Dov Grobgeld. (#118540) Sun Feb 29 22:01:49 2004 Owen Taylor diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 7372e4ea3c..b167cde200 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,6 +1,19 @@ +Mon Mar 1 10:41:27 2004 Owen Taylor + + Patch from Dov Grobgeld to implement auto-bidi-direction + for GtkTextView (#118543) + + * gtk/gtktextbtree.[ch]: Resolve bidi base direction + for each line by propagating backwards/forwards as + necessary. + + * gtk/gtktextlayout.[ch] gtk/gtktextview.c: Set the + bidi base direction for the ;ine with the cursor from + the keyboard direction. Add gtk_text_layout_set_keyboard_direction(). + Mon Mar 1 10:31:11 2004 Owen Taylor - * gtk/gtkentry.c: Implement auto-bidi-direction, + * gtk/gtkentry.[ch]: Implement auto-bidi-direction, based on a patch from Dov Grobgeld. (#118540) Sun Feb 29 22:01:49 2004 Owen Taylor diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 7372e4ea3c..b167cde200 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,6 +1,19 @@ +Mon Mar 1 10:41:27 2004 Owen Taylor + + Patch from Dov Grobgeld to implement auto-bidi-direction + for GtkTextView (#118543) + + * gtk/gtktextbtree.[ch]: Resolve bidi base direction + for each line by propagating backwards/forwards as + necessary. + + * gtk/gtktextlayout.[ch] gtk/gtktextview.c: Set the + bidi base direction for the ;ine with the cursor from + the keyboard direction. Add gtk_text_layout_set_keyboard_direction(). + Mon Mar 1 10:31:11 2004 Owen Taylor - * gtk/gtkentry.c: Implement auto-bidi-direction, + * gtk/gtkentry.[ch]: Implement auto-bidi-direction, based on a patch from Dov Grobgeld. (#118540) Sun Feb 29 22:01:49 2004 Owen Taylor diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 7372e4ea3c..b167cde200 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,6 +1,19 @@ +Mon Mar 1 10:41:27 2004 Owen Taylor + + Patch from Dov Grobgeld to implement auto-bidi-direction + for GtkTextView (#118543) + + * gtk/gtktextbtree.[ch]: Resolve bidi base direction + for each line by propagating backwards/forwards as + necessary. + + * gtk/gtktextlayout.[ch] gtk/gtktextview.c: Set the + bidi base direction for the ;ine with the cursor from + the keyboard direction. Add gtk_text_layout_set_keyboard_direction(). + Mon Mar 1 10:31:11 2004 Owen Taylor - * gtk/gtkentry.c: Implement auto-bidi-direction, + * gtk/gtkentry.[ch]: Implement auto-bidi-direction, based on a patch from Dov Grobgeld. (#118540) Sun Feb 29 22:01:49 2004 Owen Taylor diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 7372e4ea3c..b167cde200 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,6 +1,19 @@ +Mon Mar 1 10:41:27 2004 Owen Taylor + + Patch from Dov Grobgeld to implement auto-bidi-direction + for GtkTextView (#118543) + + * gtk/gtktextbtree.[ch]: Resolve bidi base direction + for each line by propagating backwards/forwards as + necessary. + + * gtk/gtktextlayout.[ch] gtk/gtktextview.c: Set the + bidi base direction for the ;ine with the cursor from + the keyboard direction. Add gtk_text_layout_set_keyboard_direction(). + Mon Mar 1 10:31:11 2004 Owen Taylor - * gtk/gtkentry.c: Implement auto-bidi-direction, + * gtk/gtkentry.[ch]: Implement auto-bidi-direction, based on a patch from Dov Grobgeld. (#118540) Sun Feb 29 22:01:49 2004 Owen Taylor diff --git a/gtk/gtkentry.h b/gtk/gtkentry.h index 3c06f472dc..be8b4a6446 100644 --- a/gtk/gtkentry.h +++ b/gtk/gtkentry.h @@ -93,6 +93,7 @@ struct _GtkEntry guint select_words : 1; guint select_lines : 1; + guint resolved_dir : 4; /* PangoDirection */ guint button; guint blink_timeout; guint recompute_idle; diff --git a/gtk/gtktextbtree.c b/gtk/gtktextbtree.c index 6d340a74ae..c62d55855d 100644 --- a/gtk/gtktextbtree.c +++ b/gtk/gtktextbtree.c @@ -554,6 +554,174 @@ _gtk_text_btree_segments_changed (GtkTextBTree *tree) * Indexable segment mutation */ +/* + * The following function is responsible for resolving the bidi direction + * for the lines between start and end. But it also calculates any + * dependent bidi direction for surrounding lines that change as a result + * of the bidi direction decisions within the range. The function is + * trying to do as little propagation as is needed. + */ +static void +gtk_text_btree_resolve_bidi (GtkTextIter *start, + GtkTextIter *end) +{ + GtkTextBTree *tree = _gtk_text_iter_get_btree (start); + GtkTextLine *start_line, *end_line, *start_line_prev, *end_line_next, *line; + PangoDirection last_strong, dir_above_propagated, dir_below_propagated; + + /* Resolve the strong bidi direction for all lines between + * start and end. + */ + start_line = _gtk_text_iter_get_text_line (start); + start_line_prev = _gtk_text_line_previous (start_line); + end_line = _gtk_text_iter_get_text_line (end); + end_line_next = _gtk_text_line_next (end_line); + + line = start_line; + while (line && line != end_line_next) + { + /* Loop through the segments and search for a strong character + */ + GtkTextLineSegment *seg = line->segments; + line->dir_strong = PANGO_DIRECTION_NEUTRAL; + + while (seg) + { + if (seg->byte_count > 0) + { + PangoDirection pango_dir; + + pango_dir = pango_find_base_dir (seg->body.chars, + seg->byte_count); + + if (pango_dir != PANGO_DIRECTION_NEUTRAL) + { + line->dir_strong = pango_dir; + break; + } + } + seg = seg->next; + } + + line = _gtk_text_line_next (line); + } + + /* Sweep forward */ + + /* The variable dir_above_propagated contains the forward propagated + * direction before start. It is neutral if start is in the beginning + * of the buffer. + */ + dir_above_propagated = PANGO_DIRECTION_NEUTRAL; + if (start_line_prev) + dir_above_propagated = start_line_prev->dir_propagated_forward; + + /* Loop forward and propagate the direction of each paragraph + * to all neutral lines. + */ + line = start_line; + last_strong = dir_above_propagated; + while (line != end_line_next) + { + if (line->dir_strong != PANGO_DIRECTION_NEUTRAL) + last_strong = line->dir_strong; + + line->dir_propagated_forward = last_strong; + + line = _gtk_text_line_next (line); + } + + /* Continue propagating as long as the previous resolved forward + * is different from last_strong. + */ + { + GtkTextIter end_propagate; + + while (line && + line->dir_strong == PANGO_DIRECTION_NEUTRAL && + line->dir_propagated_forward != last_strong) + { + GtkTextLine *prev = line; + line->dir_propagated_forward = last_strong; + + line = _gtk_text_line_next(line); + if (!line) + { + line = prev; + break; + } + } + + /* The last line to invalidate is the last line before the + * line with the strong character. Or in case of the end of the + * buffer, the last line of the buffer. (There seems to be an + * extra "virtual" last line in the buffer that must not be used + * calling _gtk_text_btree_get_iter_at_line (causes crash). Thus the + * _gtk_text_line_previous is ok in that case as well.) + */ + line = _gtk_text_line_previous (line); + _gtk_text_btree_get_iter_at_line (tree, &end_propagate, line, 0); + _gtk_text_btree_invalidate_region (tree, end, &end_propagate); + } + + /* Sweep backward */ + + /* The variable dir_below_propagated contains the backward propagated + * direction after end. It is neutral if end is at the end of + * the buffer. + */ + dir_below_propagated = PANGO_DIRECTION_NEUTRAL; + if (end_line_next) + dir_below_propagated = end_line_next->dir_propagated_back; + + /* Loop backward and propagate the direction of each paragraph + * to all neutral lines. + */ + line = end_line; + last_strong = dir_below_propagated; + while (line != start_line_prev) + { + if (line->dir_strong != PANGO_DIRECTION_NEUTRAL) + last_strong = line->dir_strong; + + line->dir_propagated_back = last_strong; + + line = _gtk_text_line_previous (line); + } + + /* Continue propagating as long as the resolved backward dir + * is different from last_strong. + */ + { + GtkTextIter start_propagate; + + while (line && + line->dir_strong == PANGO_DIRECTION_NEUTRAL && + line->dir_propagated_back != last_strong) + { + GtkTextLine *prev = line; + line->dir_propagated_back = last_strong; + + line = _gtk_text_line_previous (line); + if (!line) + { + line = prev; + break; + } + } + + /* We only need to invalidate for backwards propagation if the + * line we ended up on didn't get a direction from forwards + * propagation. + */ + if (line && line->dir_propagated_forward == PANGO_DIRECTION_NEUTRAL) + { + _gtk_text_btree_get_iter_at_line (tree, &start_propagate, line, 0); + _gtk_text_btree_invalidate_region(tree, &start_propagate, start); + } + } +} + void _gtk_text_btree_delete (GtkTextIter *start, GtkTextIter *end) @@ -884,6 +1052,8 @@ _gtk_text_btree_delete (GtkTextIter *start, /* Re-initialize our iterators */ _gtk_text_btree_get_iter_at_line (tree, start, start_line, start_byte_offset); *end = *start; + + _gtk_text_btree_resolve_bidi (start, end); } void @@ -1050,6 +1220,8 @@ _gtk_text_btree_insert (GtkTextIter *iter, /* Convenience for the user */ *iter = end; + + _gtk_text_btree_resolve_bidi (&start, &end); } } @@ -4498,6 +4670,9 @@ gtk_text_line_new (void) GtkTextLine *line; line = g_new0(GtkTextLine, 1); + line->dir_strong = PANGO_DIRECTION_NEUTRAL; + line->dir_propagated_forward = PANGO_DIRECTION_NEUTRAL; + line->dir_propagated_back = PANGO_DIRECTION_NEUTRAL; return line; } diff --git a/gtk/gtktextbtree.h b/gtk/gtktextbtree.h index 28fe390f0c..59ef11408a 100644 --- a/gtk/gtktextbtree.h +++ b/gtk/gtktextbtree.h @@ -216,6 +216,9 @@ struct _GtkTextLine { GtkTextLineSegment *segments; /* First in ordered list of segments * that make up the line. */ GtkTextLineData *views; /* data stored here by views */ + guchar dir_strong; /* BiDi algo dir of line */ + guchar dir_propagated_back; /* BiDi algo dir of next line */ + guchar dir_propagated_forward; /* BiDi algo dir of prev line */ }; diff --git a/gtk/gtktextlayout.c b/gtk/gtktextlayout.c index 157435a8b8..9c98dd7899 100644 --- a/gtk/gtktextlayout.c +++ b/gtk/gtktextlayout.c @@ -85,6 +85,18 @@ #include #include +#define GTK_TEXT_LAYOUT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_TEXT_LAYOUT, GtkTextLayoutPrivate)) + +typedef struct _GtkTextLayoutPrivate GtkTextLayoutPrivate; + +struct _GtkTextLayoutPrivate +{ + /* Cache the line that the cursor is positioned on, as the keyboard + direction only influences the direction of the cursor line. + */ + GtkTextLine *cursor_line; +}; + static GtkTextLineData *gtk_text_layout_real_wrap (GtkTextLayout *layout, GtkTextLine *line, /* may be NULL */ @@ -110,6 +122,22 @@ static void gtk_text_layout_invalidate_all (GtkTextLayout *layout); static PangoAttribute *gtk_text_attr_appearance_new (const GtkTextAppearance *appearance); +static void gtk_text_layout_mark_set_handler (GtkTextBuffer *buffer, + const GtkTextIter *location, + GtkTextMark *mark, + gpointer data); +static void gtk_text_layout_buffer_insert_text (GtkTextBuffer *textbuffer, + GtkTextIter *iter, + gchar *str, + gint len, + gpointer data); +static void gtk_text_layout_buffer_delete_range (GtkTextBuffer *textbuffer, + GtkTextIter *start, + GtkTextIter *end, + gpointer data); + +static void gtk_text_layout_update_cursor_line (GtkTextLayout *layout); + enum { INVALIDATED, CHANGED, @@ -209,6 +237,8 @@ gtk_text_layout_class_init (GtkTextLayoutClass *klass) GTK_TYPE_OBJECT, G_TYPE_INT, G_TYPE_INT); + + g_type_class_add_private (object_class, sizeof (GtkTextLayoutPrivate)); } static void @@ -284,6 +314,16 @@ gtk_text_layout_set_buffer (GtkTextLayout *layout, _gtk_text_btree_remove_view (_gtk_text_buffer_get_btree (layout->buffer), layout); + g_signal_handlers_disconnect_by_func (layout->buffer, + G_CALLBACK (gtk_text_layout_mark_set_handler), + layout); + g_signal_handlers_disconnect_by_func (layout->buffer, + G_CALLBACK (gtk_text_layout_buffer_insert_text), + layout); + g_signal_handlers_disconnect_by_func (layout->buffer, + G_CALLBACK (gtk_text_layout_buffer_delete_range), + layout); + g_object_unref (layout->buffer); layout->buffer = NULL; } @@ -295,6 +335,14 @@ gtk_text_layout_set_buffer (GtkTextLayout *layout, g_object_ref (buffer); _gtk_text_btree_add_view (_gtk_text_buffer_get_btree (buffer), layout); + + /* Bind to all signals that move the insert mark. */ + g_signal_connect_after (layout->buffer, "mark_set", + G_CALLBACK (gtk_text_layout_mark_set_handler), layout); + g_signal_connect_after (layout->buffer, "insert_text", + G_CALLBACK (gtk_text_layout_buffer_insert_text), layout); + g_signal_connect_after (layout->buffer, "delete_range", + G_CALLBACK (gtk_text_layout_buffer_delete_range), layout); } } @@ -374,6 +422,25 @@ gtk_text_layout_set_cursor_direction (GtkTextLayout *layout, } } +/** + * gtk_text_layout_set_keyboard_direction: + * @keyboard_dir: the current direction of the keyboard. + * + * Sets the keyboard direction; this is used as for the bidirectional + * base direction for the line with the cursor if the line contains + * only neutral characters. + **/ +void +gtk_text_layout_set_keyboard_direction (GtkTextLayout *layout, + GtkTextDirection keyboard_dir) +{ + if (keyboard_dir != layout->keyboard_direction) + { + layout->keyboard_direction = keyboard_dir; + gtk_text_layout_invalidate_cursor_line (layout); + } +} + /** * gtk_text_layout_get_buffer: * @layout: a #GtkTextLayout @@ -704,23 +771,33 @@ gtk_text_layout_invalidate_cache (GtkTextLayout *layout, static void gtk_text_layout_invalidate_cursor_line (GtkTextLayout *layout) { - GtkTextIter iter; - GtkTextLine *line; + GtkTextLayoutPrivate *priv = GTK_TEXT_LAYOUT_GET_PRIVATE (layout); GtkTextLineData *line_data; - gtk_text_buffer_get_iter_at_mark (layout->buffer, &iter, - gtk_text_buffer_get_mark (layout->buffer, "insert")); + if (priv->cursor_line == NULL) + return; - line = _gtk_text_iter_get_text_line (&iter); - line_data = _gtk_text_line_get_data (line, layout); + line_data = _gtk_text_line_get_data (priv->cursor_line, layout); if (line_data) { - gtk_text_layout_invalidate_cache (layout, line); - _gtk_text_line_invalidate_wrap (line, line_data); + gtk_text_layout_invalidate_cache (layout, priv->cursor_line); + _gtk_text_line_invalidate_wrap (priv->cursor_line, line_data); gtk_text_layout_invalidated (layout); } } +static void +gtk_text_layout_update_cursor_line(GtkTextLayout *layout) +{ + GtkTextLayoutPrivate *priv = GTK_TEXT_LAYOUT_GET_PRIVATE (layout); + GtkTextIter iter; + + gtk_text_buffer_get_iter_at_mark (layout->buffer, &iter, + gtk_text_buffer_get_mark (layout->buffer, "insert")); + + priv->cursor_line = _gtk_text_iter_get_text_line (&iter); +} + static void gtk_text_layout_real_invalidate (GtkTextLayout *layout, const GtkTextIter *start, @@ -1121,26 +1198,46 @@ totally_invisible_line (GtkTextLayout *layout, static void set_para_values (GtkTextLayout *layout, - GtkTextAttributes *style, + PangoDirection base_dir, + GtkTextAttributes *style, GtkTextLineDisplay *display) { PangoAlignment pango_align = PANGO_ALIGN_LEFT; int layout_width; - display->direction = style->direction; + switch (base_dir) + { + /* If no base direction was found, then use the style direction */ + case PANGO_DIRECTION_NEUTRAL : + display->direction = style->direction; - if (display->direction == GTK_TEXT_DIR_LTR) - display->layout = pango_layout_new (layout->ltr_context); - else + /* Override the base direction */ + if (display->direction == GTK_TEXT_DIR_RTL) + base_dir = PANGO_DIRECTION_RTL; + else + base_dir = PANGO_DIRECTION_LTR; + + break; + case PANGO_DIRECTION_RTL : + display->direction = GTK_TEXT_DIR_RTL; + break; + default: + display->direction = GTK_TEXT_DIR_LTR; + break; + } + + if (display->direction == GTK_TEXT_DIR_RTL) display->layout = pango_layout_new (layout->rtl_context); + else + display->layout = pango_layout_new (layout->ltr_context); switch (style->justification) { case GTK_JUSTIFY_LEFT: - pango_align = (style->direction == GTK_TEXT_DIR_LTR) ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT; + pango_align = (base_dir == PANGO_DIRECTION_LTR) ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT; break; case GTK_JUSTIFY_RIGHT: - pango_align = (style->direction == GTK_TEXT_DIR_LTR) ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT; + pango_align = (base_dir == PANGO_DIRECTION_LTR) ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT; break; case GTK_JUSTIFY_CENTER: pango_align = PANGO_ALIGN_CENTER; @@ -1683,6 +1780,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, GtkTextLine *line, gboolean size_only) { + GtkTextLayoutPrivate *priv = GTK_TEXT_LAYOUT_GET_PRIVATE (layout); GtkTextLineDisplay *display; GtkTextLineSegment *seg; GtkTextIter iter; @@ -1696,6 +1794,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, GSList *cursor_segs = NULL; GSList *tmp_list1, *tmp_list2; gboolean saw_widget = FALSE; + PangoDirection base_dir; g_return_val_if_fail (line != NULL, NULL); @@ -1728,6 +1827,18 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, if (totally_invisible_line (layout, line, &iter)) return display; + /* Find the bidi base direction */ + base_dir = line->dir_propagated_forward; + if (base_dir == PANGO_DIRECTION_NEUTRAL) + base_dir = line->dir_propagated_back; + + if (line == priv->cursor_line && + line->dir_strong == PANGO_DIRECTION_NEUTRAL) + { + base_dir = (layout->keyboard_direction == GTK_TEXT_DIR_LTR) ? + PANGO_DIRECTION_LTR : PANGO_DIRECTION_RTL; + } + /* Allocate space for flat text for buffer */ text_allocated = _gtk_text_line_byte_count (line); @@ -1758,7 +1869,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, */ if (!para_values_set) { - set_para_values (layout, style, display); + set_para_values (layout, base_dir, style, display); para_values_set = TRUE; } @@ -1927,7 +2038,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout, if (!para_values_set) { style = get_style (layout, &iter); - set_para_values (layout, style, display); + set_para_values (layout, base_dir, style, display); release_style (layout, style); } @@ -3070,3 +3181,40 @@ gtk_text_layout_spew (GtkTextLayout *layout) layout->height, layout->screen_width); #endif } + +/* Catch all situations that move the insertion point. + */ +static void +gtk_text_layout_mark_set_handler (GtkTextBuffer *buffer, + const GtkTextIter *location, + GtkTextMark *mark, + gpointer data) +{ + GtkTextLayout *layout = GTK_TEXT_LAYOUT (data); + + if (mark == gtk_text_buffer_get_insert (buffer)) + gtk_text_layout_update_cursor_line (layout); +} + +static void +gtk_text_layout_buffer_insert_text (GtkTextBuffer *textbuffer, + GtkTextIter *iter, + gchar *str, + gint len, + gpointer data) +{ + GtkTextLayout *layout = GTK_TEXT_LAYOUT (data); + + gtk_text_layout_update_cursor_line (layout); +} + +static void +gtk_text_layout_buffer_delete_range (GtkTextBuffer *textbuffer, + GtkTextIter *start, + GtkTextIter *end, + gpointer data) +{ + GtkTextLayout *layout = GTK_TEXT_LAYOUT (data); + + gtk_text_layout_update_cursor_line (layout); +} diff --git a/gtk/gtktextlayout.h b/gtk/gtktextlayout.h index 58e8e97c45..fa6802ebb0 100644 --- a/gtk/gtktextlayout.h +++ b/gtk/gtktextlayout.h @@ -165,6 +165,11 @@ struct _GtkTextLayout */ guint cursor_direction : 2; + /* The keyboard direction is used to default the alignment when + there are no strong characters. + */ + guint keyboard_direction : 2; + /* The preedit string and attributes, if any */ gchar *preedit_string; @@ -265,7 +270,9 @@ void gtk_text_layout_set_contexts (GtkTextLayout *lay PangoContext *ltr_context, PangoContext *rtl_context); void gtk_text_layout_set_cursor_direction (GtkTextLayout *layout, - GtkTextDirection direction); + GtkTextDirection direction); +void gtk_text_layout_set_keyboard_direction (GtkTextLayout *layout, + GtkTextDirection keyboard_dir); void gtk_text_layout_default_style_changed (GtkTextLayout *layout); void gtk_text_layout_set_screen_width (GtkTextLayout *layout, diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index 5238aa71f5..dbb4e2ffcb 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -5620,26 +5620,28 @@ gtk_text_view_check_keymap_direction (GtkTextView *text_view) { if (text_view->layout) { - gboolean split_cursor; - GtkTextDirection new_dir; GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (text_view)); - + GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (text_view))); + GtkTextDirection new_cursor_dir; + GtkTextDirection new_keyboard_dir; + gboolean split_cursor; + g_object_get (settings, "gtk-split-cursor", &split_cursor, NULL); - if (split_cursor) - { - new_dir = GTK_TEXT_DIR_NONE; - } - else - { - GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (text_view))); - new_dir = (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_LTR) ? - GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL; - } - if (text_view->layout->cursor_direction != new_dir) - gtk_text_layout_set_cursor_direction (text_view->layout, new_dir); + if (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_LTR) + new_keyboard_dir = GTK_TEXT_DIR_LTR; + else + new_keyboard_dir = GTK_TEXT_DIR_RTL; + + if (split_cursor) + new_cursor_dir = GTK_TEXT_DIR_NONE; + else + new_cursor_dir = new_keyboard_dir; + + gtk_text_layout_set_cursor_direction (text_view->layout, new_cursor_dir); + gtk_text_layout_set_keyboard_direction (text_view->layout, new_keyboard_dir); } }