X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkentry.c;h=de85158482632cb1e3b12c762a50bcbe808ac724;hb=51be6b88dbff3ff6ed83d1247508ad58c0278df6;hp=c3a50f1aa5f83fa84a1053ed79808e79275d37d2;hpb=1ac2982265c87a6164a986b6df161b1af011c944;p=~andy%2Fgtk diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index c3a50f1aa..de8515848 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -65,6 +65,7 @@ #include "gtkicontheme.h" #include "gtkwidgetprivate.h" #include "gtkstylecontextprivate.h" +#include "gtktexthandleprivate.h" #include "a11y/gtkentryaccessible.h" @@ -157,6 +158,8 @@ struct _GtkEntryPrivate gchar *placeholder_text; + GtkTextHandle *text_handle; + gfloat xalign; gint ascent; /* font ascent in pango units */ @@ -213,6 +216,8 @@ struct _GtkEntryPrivate guint select_words : 1; guint select_lines : 1; guint truncate_multiline : 1; + guint cursor_handle_dragged : 1; + guint selection_handle_dragged : 1; }; struct _EntryIconInfo @@ -313,6 +318,7 @@ enum { }; static guint signals[LAST_SIGNAL] = { 0 }; +static gboolean test_touchscreen = FALSE; typedef enum { CURSOR_STANDARD, @@ -558,6 +564,11 @@ static void gtk_entry_get_text_area_size (GtkEntry *entry, gint *y, gint *width, gint *height); +static void gtk_entry_get_frame_size (GtkEntry *entry, + gint *x, + gint *y, + gint *width, + gint *height); static void get_text_area_size (GtkEntry *entry, gint *x, gint *y, @@ -575,6 +586,12 @@ static GdkPixbuf * gtk_entry_ensure_pixbuf (GtkEntry *en static void gtk_entry_update_cached_style_values(GtkEntry *entry); static gboolean get_middle_click_paste (GtkEntry *entry); +/* GtkTextHandle handlers */ +static void gtk_entry_handle_dragged (GtkTextHandle *handle, + GtkTextHandlePosition pos, + gint x, + gint y, + GtkEntry *entry); static void begin_change (GtkEntry *entry); static void end_change (GtkEntry *entry); @@ -693,6 +710,7 @@ gtk_entry_class_init (GtkEntryClass *class) class->toggle_overwrite = gtk_entry_toggle_overwrite; class->activate = gtk_entry_real_activate; class->get_text_area_size = gtk_entry_get_text_area_size; + class->get_frame_size = gtk_entry_get_frame_size; quark_inner_border = g_quark_from_static_string ("gtk-entry-inner-border"); quark_password_hint = g_quark_from_static_string ("gtk-entry-password-hint"); @@ -1927,6 +1945,7 @@ gtk_entry_class_init (GtkEntryClass *class) G_PARAM_DEPRECATED)); g_type_class_add_private (gobject_class, sizeof (GtkEntryPrivate)); + test_touchscreen = g_getenv ("GTK_TEST_TOUCHSCREEN") != NULL; gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_ENTRY_ACCESSIBLE); } @@ -2552,6 +2571,10 @@ gtk_entry_init (GtkEntry *entry) gtk_style_context_add_class (context, GTK_STYLE_CLASS_ENTRY); gtk_entry_update_cached_style_values (entry); + + priv->text_handle = _gtk_text_handle_new (GTK_WIDGET (entry)); + g_signal_connect (priv->text_handle, "handle-dragged", + G_CALLBACK (gtk_entry_handle_dragged), entry); } static void @@ -2788,6 +2811,7 @@ gtk_entry_finalize (GObject *object) if (priv->recompute_idle) g_source_remove (priv->recompute_idle); + g_object_unref (priv->text_handle); g_free (priv->placeholder_text); g_free (priv->im_module); @@ -2949,7 +2973,7 @@ realize_icon_info (GtkWidget *widget, icon_info->window = gdk_window_new (gtk_widget_get_window (widget), &attributes, attributes_mask); - gdk_window_set_user_data (icon_info->window, widget); + gtk_widget_register_window (widget, icon_info->window); gtk_widget_queue_resize (widget); } @@ -3009,6 +3033,9 @@ gtk_entry_unmap (GtkWidget *widget) EntryIconInfo *icon_info = NULL; gint i; + _gtk_text_handle_set_mode (priv->text_handle, + GTK_TEXT_HANDLE_MODE_NONE); + for (i = 0; i < MAX_ICONS; i++) { if ((icon_info = priv->icons[i]) != NULL) @@ -3073,7 +3100,7 @@ gtk_entry_realize (GtkWidget *widget) &attributes, attributes_mask); - gdk_window_set_user_data (priv->text_area, entry); + gtk_widget_register_window (widget, priv->text_area); if (attributes_mask & GDK_WA_CURSOR) g_object_unref (attributes.cursor); @@ -3082,7 +3109,7 @@ gtk_entry_realize (GtkWidget *widget) gtk_entry_adjust_scroll (entry); gtk_entry_update_primary_selection (entry); - + _gtk_text_handle_set_relative_to (priv->text_handle, priv->text_area); /* If the icon positions are already setup, create their windows. * Otherwise if they don't exist yet, then construct_icon_info() @@ -3110,6 +3137,7 @@ gtk_entry_unrealize (GtkWidget *widget) gtk_entry_reset_layout (entry); gtk_im_context_set_client_window (priv->im_context, NULL); + _gtk_text_handle_set_relative_to (priv->text_handle, NULL); clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_PRIMARY); if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (entry)) @@ -3117,7 +3145,7 @@ gtk_entry_unrealize (GtkWidget *widget) if (priv->text_area) { - gdk_window_set_user_data (priv->text_area, NULL); + gtk_widget_unregister_window (widget, priv->text_area); gdk_window_destroy (priv->text_area); priv->text_area = NULL; } @@ -3136,6 +3164,7 @@ gtk_entry_unrealize (GtkWidget *widget) { if (icon_info->window != NULL) { + gtk_widget_unregister_window (widget, icon_info->window); gdk_window_destroy (icon_info->window); icon_info->window = NULL; } @@ -3188,19 +3217,14 @@ gtk_entry_get_preferred_width (GtkWidget *widget, PangoFontMetrics *metrics; GtkBorder borders; PangoContext *context; - GtkStyleContext *style_context; - GtkStateFlags state; gint icon_widths = 0; gint icon_width, i; gint width; context = gtk_widget_get_pango_context (widget); - style_context = gtk_widget_get_style_context (widget); - state = gtk_widget_get_state_flags (widget); - metrics = pango_context_get_metrics (context, - gtk_style_context_get_font (style_context, state), + pango_context_get_font_description (context), pango_context_get_language (context)); _gtk_entry_get_borders (entry, &borders); @@ -3241,28 +3265,25 @@ gtk_entry_get_preferred_height (GtkWidget *widget, GtkEntryPrivate *priv = entry->priv; PangoFontMetrics *metrics; GtkBorder borders; - GtkStyleContext *style_context; - GtkStateFlags state; PangoContext *context; gint height; + PangoLayout *layout; + layout = gtk_entry_ensure_layout (entry, TRUE); context = gtk_widget_get_pango_context (widget); - style_context = gtk_widget_get_style_context (widget); - state = gtk_widget_get_state_flags (widget); - metrics = pango_context_get_metrics (context, - gtk_style_context_get_font (style_context, state), + pango_context_get_font_description (context), pango_context_get_language (context)); priv->ascent = pango_font_metrics_get_ascent (metrics); priv->descent = pango_font_metrics_get_descent (metrics); + pango_font_metrics_unref (metrics); _gtk_entry_get_borders (entry, &borders); + pango_layout_get_pixel_size (layout, NULL, &height); - height = PANGO_PIXELS (priv->ascent + priv->descent) + borders.top + borders.bottom; - - pango_font_metrics_unref (metrics); + height += borders.top + borders.bottom; *minimum = height; *natural = height; @@ -3373,12 +3394,11 @@ get_text_area_size (GtkEntry *entry, static void -get_frame_size (GtkEntry *entry, - gboolean relative_to_window, - gint *x, - gint *y, - gint *width, - gint *height) +gtk_entry_get_frame_size (GtkEntry *entry, + gint *x, + gint *y, + gint *width, + gint *height) { GtkEntryPrivate *priv = entry->priv; GtkAllocation allocation; @@ -3393,7 +3413,7 @@ get_frame_size (GtkEntry *entry, gtk_widget_get_allocation (widget, &allocation); if (x) - *x = relative_to_window ? allocation.x : 0; + *x = allocation.x; if (y) { @@ -3402,8 +3422,7 @@ get_frame_size (GtkEntry *entry, else *y = (allocation.height - req_height) / 2; - if (relative_to_window) - *y += allocation.y; + *y += allocation.y; } if (width) @@ -3418,6 +3437,36 @@ get_frame_size (GtkEntry *entry, } } +static void +get_frame_size (GtkEntry *entry, + gboolean relative_to_window, + gint *x, + gint *y, + gint *width, + gint *height) +{ + GtkEntryClass *class; + GtkWidget *widget = GTK_WIDGET (entry); + + g_return_if_fail (GTK_IS_ENTRY (entry)); + + class = GTK_ENTRY_GET_CLASS (entry); + + if (class->get_frame_size) + class->get_frame_size (entry, x, y, width, height); + + if (!relative_to_window) + { + GtkAllocation allocation; + gtk_widget_get_allocation (widget, &allocation); + + if (x) + *x -= allocation.x; + if (y) + *y -= allocation.y; + } +} + static void gtk_entry_size_allocate (GtkWidget *widget, GtkAllocation *allocation) @@ -3695,36 +3744,40 @@ gtk_entry_draw (GtkWidget *widget, GtkEntryPrivate *priv = entry->priv; int i; - context = gtk_widget_get_style_context (widget); + if (gtk_cairo_should_draw_window (cr, + gtk_widget_get_window (widget))) + { + context = gtk_widget_get_style_context (widget); - /* Draw entry_bg, shadow, progress and focus */ - gtk_entry_draw_frame (widget, context, cr); + /* Draw entry_bg, shadow, progress and focus */ + gtk_entry_draw_frame (widget, context, cr); - /* Draw text and cursor */ - cairo_save (cr); + /* Draw text and cursor */ + cairo_save (cr); - gtk_cairo_transform_to_window (cr, widget, priv->text_area); + gtk_cairo_transform_to_window (cr, widget, priv->text_area); - if (priv->dnd_position != -1) - gtk_entry_draw_cursor (GTK_ENTRY (widget), cr, CURSOR_DND); - - gtk_entry_draw_text (GTK_ENTRY (widget), cr); + if (priv->dnd_position != -1) + gtk_entry_draw_cursor (GTK_ENTRY (widget), cr, CURSOR_DND); - /* When no text is being displayed at all, don't show the cursor */ - if (gtk_entry_get_display_mode (entry) != DISPLAY_BLANK && - gtk_widget_has_focus (widget) && - priv->selection_bound == priv->current_pos && priv->cursor_visible) - gtk_entry_draw_cursor (GTK_ENTRY (widget), cr, CURSOR_STANDARD); + gtk_entry_draw_text (GTK_ENTRY (widget), cr); - cairo_restore (cr); + /* When no text is being displayed at all, don't show the cursor */ + if (gtk_entry_get_display_mode (entry) != DISPLAY_BLANK && + gtk_widget_has_focus (widget) && + priv->selection_bound == priv->current_pos && priv->cursor_visible) + gtk_entry_draw_cursor (GTK_ENTRY (widget), cr, CURSOR_STANDARD); - /* Draw icons */ - for (i = 0; i < MAX_ICONS; i++) - { - EntryIconInfo *icon_info = priv->icons[i]; + cairo_restore (cr); - if (icon_info != NULL) - draw_icon (widget, cr, i); + /* Draw icons */ + for (i = 0; i < MAX_ICONS; i++) + { + EntryIconInfo *icon_info = priv->icons[i]; + + if (icon_info != NULL) + draw_icon (widget, cr, i); + } } return FALSE; @@ -3851,7 +3904,108 @@ in_selection (GtkEntry *entry, g_free (ranges); return retval; } - + +static void +gtk_entry_move_handle (GtkEntry *entry, + GtkTextHandlePosition pos, + gint x, + gint y, + gint height) +{ + GtkEntryPrivate *priv = entry->priv; + + if (!_gtk_text_handle_get_is_dragged (priv->text_handle, pos) && + (x < 0 || x > gdk_window_get_width (priv->text_area))) + { + /* Hide the handle if it's not being manipulated + * and fell outside of the visible text area. + */ + _gtk_text_handle_set_visible (priv->text_handle, pos, FALSE); + } + else + { + GdkRectangle rect; + + rect.x = CLAMP (x, 0, gdk_window_get_width (priv->text_area)); + rect.y = y; + rect.width = 1; + rect.height = height; + + _gtk_text_handle_set_visible (priv->text_handle, pos, TRUE); + _gtk_text_handle_set_position (priv->text_handle, pos, &rect); + } +} + +static gint +gtk_entry_get_selection_bound_location (GtkEntry *entry) +{ + GtkEntryPrivate *priv = entry->priv; + PangoLayout *layout; + PangoRectangle pos; + gint x; + const gchar *text; + gint index; + + layout = gtk_entry_ensure_layout (entry, FALSE); + text = pango_layout_get_text (layout); + index = g_utf8_offset_to_pointer (text, priv->selection_bound) - text; + pango_layout_index_to_pos (layout, index, &pos); + + if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL) + x = (pos.x + pos.width) / PANGO_SCALE; + else + x = pos.x / PANGO_SCALE; + + return x; +} + +static void +gtk_entry_update_handles (GtkEntry *entry, + GtkTextHandleMode mode) +{ + GtkEntryPrivate *priv = entry->priv; + gint strong_x, height; + gint cursor, bound; + + _gtk_text_handle_set_mode (priv->text_handle, mode); + + /* Wait for recomputation before repositioning */ + if (priv->recompute_idle != 0) + return; + + height = gdk_window_get_height (priv->text_area); + + gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, NULL); + cursor = strong_x - priv->scroll_offset; + + if (mode == GTK_TEXT_HANDLE_MODE_SELECTION) + { + gint start, end; + + bound = gtk_entry_get_selection_bound_location (entry) - priv->scroll_offset; + + if (priv->selection_bound > priv->current_pos) + { + start = cursor; + end = bound; + } + else + { + start = bound; + end = cursor; + } + + /* Update start selection bound */ + gtk_entry_move_handle (entry, GTK_TEXT_HANDLE_POSITION_SELECTION_START, + start, 0, height); + gtk_entry_move_handle (entry, GTK_TEXT_HANDLE_POSITION_SELECTION_END, + end, 0, height); + } + else + gtk_entry_move_handle (entry, GTK_TEXT_HANDLE_POSITION_CURSOR, + cursor, 0, height); +} + static gint gtk_entry_button_press (GtkWidget *widget, GdkEventButton *event) @@ -3919,6 +4073,12 @@ gtk_entry_button_press (GtkWidget *widget, else if (event->button == GDK_BUTTON_PRIMARY) { gboolean have_selection = gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end); + gboolean is_touchscreen; + GdkDevice *source; + + source = gdk_event_get_source_device ((GdkEvent *) event); + is_touchscreen = test_touchscreen || + gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN; priv->select_words = FALSE; priv->select_lines = FALSE; @@ -3997,7 +4157,12 @@ gtk_entry_button_press (GtkWidget *widget, priv->drag_start_y = event->y; } else - gtk_editable_set_position (editable, tmp_pos); + { + gtk_editable_set_position (editable, tmp_pos); + + if (is_touchscreen) + gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_CURSOR); + } break; case GDK_2BUTTON_PRESS: @@ -4008,6 +4173,9 @@ gtk_entry_button_press (GtkWidget *widget, priv->in_drag = FALSE; priv->select_words = TRUE; gtk_entry_select_word (entry); + + if (is_touchscreen) + gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_SELECTION); break; case GDK_3BUTTON_PRESS: @@ -4018,6 +4186,8 @@ gtk_entry_button_press (GtkWidget *widget, priv->in_drag = FALSE; priv->select_lines = TRUE; gtk_entry_select_line (entry); + if (is_touchscreen) + gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_SELECTION); break; default: @@ -4087,9 +4257,16 @@ gtk_entry_button_release (GtkWidget *widget, if (priv->in_drag) { gint tmp_pos = gtk_entry_find_position (entry, priv->drag_start_x); + GdkDevice *source; gtk_editable_set_position (GTK_EDITABLE (entry), tmp_pos); + source = gdk_event_get_source_device ((GdkEvent *) event); + + if (test_touchscreen || + gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN) + gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_CURSOR); + priv->in_drag = 0; } @@ -4211,13 +4388,22 @@ gtk_entry_motion_notify (GtkWidget *widget, } else { + GdkInputSource input_source; + GdkDevice *source; + guint length; + + length = gtk_entry_buffer_get_length (get_buffer (entry)); + if (event->y < 0) tmp_pos = 0; else if (event->y >= gdk_window_get_height (priv->text_area)) - tmp_pos = gtk_entry_buffer_get_length (get_buffer (entry)); + tmp_pos = length; else tmp_pos = gtk_entry_find_position (entry, event->x + priv->scroll_offset); + source = gdk_event_get_source_device ((GdkEvent *) event); + input_source = gdk_device_get_source (source); + if (priv->select_words) { gint min, max; @@ -4253,13 +4439,20 @@ gtk_entry_motion_notify (GtkWidget *widget, if (priv->current_pos != max) pos = min; } - + gtk_entry_set_positions (entry, pos, bound); } else gtk_entry_set_positions (entry, tmp_pos, -1); + + /* Update touch handles' position */ + if (test_touchscreen || input_source == GDK_SOURCE_TOUCHSCREEN) + gtk_entry_update_handles (entry, + (priv->current_pos == priv->selection_bound) ? + GTK_TEXT_HANDLE_MODE_CURSOR : + GTK_TEXT_HANDLE_MODE_SELECTION); } - + return TRUE; } @@ -4300,6 +4493,10 @@ gtk_entry_key_press (GtkWidget *widget, gtk_entry_reset_blink_time (entry); gtk_entry_pend_cursor_blink (entry); + if (!event->send_event) + _gtk_text_handle_set_mode (priv->text_handle, + GTK_TEXT_HANDLE_MODE_NONE); + if (priv->editable) { if (gtk_im_context_filter_keypress (priv->im_context, event)) @@ -4393,6 +4590,9 @@ gtk_entry_focus_out (GtkWidget *widget, GtkEntryCompletion *completion; GdkKeymap *keymap; + _gtk_text_handle_set_mode (priv->text_handle, + GTK_TEXT_HANDLE_MODE_NONE); + gtk_widget_queue_draw (widget); keymap = gdk_keymap_get_for_display (gtk_widget_get_display (widget)); @@ -4672,8 +4872,6 @@ gtk_entry_style_updated (GtkWidget *widget) gtk_entry_update_cached_style_values (entry); - gtk_entry_recompute (entry); - icon_theme_changed (entry); } @@ -5573,10 +5771,17 @@ recompute_idle_func (gpointer data) if (gtk_widget_has_screen (GTK_WIDGET (entry))) { + GtkTextHandleMode handle_mode; + gtk_entry_adjust_scroll (entry); gtk_widget_queue_draw (GTK_WIDGET (entry)); update_im_cursor_location (entry); + + handle_mode = _gtk_text_handle_get_mode (priv->text_handle); + + if (handle_mode != GTK_TEXT_HANDLE_MODE_NONE) + gtk_entry_update_handles (entry, handle_mode); } return FALSE; @@ -5765,7 +5970,7 @@ get_layout_position (GtkEntry *entry, layout = gtk_entry_ensure_layout (entry, TRUE); - gtk_entry_get_text_area_size (entry, NULL, NULL, &area_width, &area_height); + get_text_area_size (entry, NULL, NULL, &area_width, &area_height); area_height = PANGO_SCALE * area_height; line = pango_layout_get_lines_readonly (layout)->data; @@ -6010,6 +6215,70 @@ gtk_entry_draw_cursor (GtkEntry *entry, } } +static void +gtk_entry_handle_dragged (GtkTextHandle *handle, + GtkTextHandlePosition pos, + gint x, + gint y, + GtkEntry *entry) +{ + gint cursor_pos, selection_bound_pos, tmp_pos; + GtkEntryPrivate *priv = entry->priv; + GtkTextHandleMode mode; + gint *min, *max; + + cursor_pos = priv->current_pos; + selection_bound_pos = priv->selection_bound; + mode = _gtk_text_handle_get_mode (handle); + tmp_pos = gtk_entry_find_position (entry, x + priv->scroll_offset); + + if (mode == GTK_TEXT_HANDLE_MODE_CURSOR || + cursor_pos >= selection_bound_pos) + { + max = &cursor_pos; + min = &selection_bound_pos; + } + else + { + max = &selection_bound_pos; + min = &cursor_pos; + } + + if (pos == GTK_TEXT_HANDLE_POSITION_SELECTION_END) + { + if (mode == GTK_TEXT_HANDLE_MODE_SELECTION) + { + gint min_pos; + + min_pos = MAX (*min + 1, 0); + tmp_pos = MAX (tmp_pos, min_pos); + } + + *max = tmp_pos; + } + else + { + if (mode == GTK_TEXT_HANDLE_MODE_SELECTION) + { + gint max_pos; + + max_pos = *max - 1; + *min = MIN (tmp_pos, max_pos); + } + } + + if (cursor_pos != priv->current_pos || + selection_bound_pos != priv->selection_bound) + { + if (mode == GTK_TEXT_HANDLE_MODE_CURSOR) + gtk_entry_set_positions (entry, cursor_pos, cursor_pos); + else + gtk_entry_set_positions (entry, cursor_pos, selection_bound_pos); + + gtk_entry_update_handles (entry, mode); + } +} + /** * gtk_entry_reset_im_context: * @entry: a #GtkEntry @@ -6166,6 +6435,23 @@ gtk_entry_get_cursor_locations (GtkEntry *entry, } } +static gboolean +gtk_entry_get_is_selection_handle_dragged (GtkEntry *entry) +{ + GtkEntryPrivate *priv = entry->priv; + GtkTextHandlePosition pos; + + if (_gtk_text_handle_get_mode (priv->text_handle) != GTK_TEXT_HANDLE_MODE_SELECTION) + return FALSE; + + if (priv->current_pos >= priv->selection_bound) + pos = GTK_TEXT_HANDLE_POSITION_SELECTION_START; + else + pos = GTK_TEXT_HANDLE_POSITION_SELECTION_END; + + return _gtk_text_handle_get_is_dragged (priv->text_handle, pos); +} + static void gtk_entry_adjust_scroll (GtkEntry *entry) { @@ -6178,6 +6464,7 @@ gtk_entry_adjust_scroll (GtkEntry *entry) PangoLayout *layout; PangoLayoutLine *line; PangoRectangle logical_rect; + GtkTextHandleMode handle_mode; if (!gtk_widget_get_realized (GTK_WIDGET (entry))) return; @@ -6214,22 +6501,33 @@ gtk_entry_adjust_scroll (GtkEntry *entry) priv->scroll_offset = CLAMP (priv->scroll_offset, min_offset, max_offset); - /* And make sure cursors are on screen. Note that the cursor is - * actually drawn one pixel into the INNER_BORDER space on - * the right, when the scroll is at the utmost right. This - * looks better to to me than confining the cursor inside the - * border entirely, though it means that the cursor gets one - * pixel closer to the edge of the widget on the right than - * on the left. This might need changing if one changed - * INNER_BORDER from 2 to 1, as one would do on a - * small-screen-real-estate display. - * - * We always make sure that the strong cursor is on screen, and - * put the weak cursor on screen if possible. - */ + if (gtk_entry_get_is_selection_handle_dragged (entry)) + { + /* The text handle corresponding to the selection bound is + * being dragged, ensure it stays onscreen even if we scroll + * cursors away, this is so both handles can cause content + * to scroll. + */ + strong_x = weak_x = gtk_entry_get_selection_bound_location (entry); + } + else + { + /* And make sure cursors are on screen. Note that the cursor is + * actually drawn one pixel into the INNER_BORDER space on + * the right, when the scroll is at the utmost right. This + * looks better to to me than confining the cursor inside the + * border entirely, though it means that the cursor gets one + * pixel closer to the edge of the widget on the right than + * on the left. This might need changing if one changed + * INNER_BORDER from 2 to 1, as one would do on a + * small-screen-real-estate display. + * + * We always make sure that the strong cursor is on screen, and + * put the weak cursor on screen if possible. + */ + gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, &weak_x); + } - gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, &weak_x); - strong_xoffset = strong_x - priv->scroll_offset; if (strong_xoffset < 0) @@ -6256,6 +6554,11 @@ gtk_entry_adjust_scroll (GtkEntry *entry) } g_object_notify (G_OBJECT (entry), "scroll-offset"); + + handle_mode = _gtk_text_handle_get_mode (priv->text_handle); + + if (handle_mode != GTK_TEXT_HANDLE_MODE_NONE) + gtk_entry_update_handles (entry, handle_mode); } static void @@ -6266,8 +6569,6 @@ gtk_entry_move_adjustments (GtkEntry *entry) GtkAdjustment *adjustment; PangoContext *context; PangoFontMetrics *metrics; - GtkStyleContext *style_context; - GtkStateFlags state; GtkBorder borders; gint x, layout_x; gint char_width; @@ -6278,7 +6579,7 @@ gtk_entry_move_adjustments (GtkEntry *entry) gtk_widget_get_allocation (widget, &allocation); - /* Cursor position, layout offset, border width, and widget allocation */ + /* Cursor/char position, layout offset, border width, and widget allocation */ gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &x, NULL); get_layout_position (entry, &layout_x, NULL); _gtk_entry_get_borders (entry, &borders); @@ -6286,11 +6587,9 @@ gtk_entry_move_adjustments (GtkEntry *entry) /* Approximate width of a char, so user can see what is ahead/behind */ context = gtk_widget_get_pango_context (widget); - style_context = gtk_widget_get_style_context (widget); - state = gtk_widget_get_state_flags (widget); metrics = pango_context_get_metrics (context, - gtk_style_context_get_font (style_context, state), + pango_context_get_font_description (context), pango_context_get_language (context)); char_width = pango_font_metrics_get_approximate_char_width (metrics) / PANGO_SCALE; @@ -8499,6 +8798,9 @@ gtk_entry_set_icon_tooltip_text (GtkEntry *entry, icon_info->tooltip = tooltip ? g_markup_escape_text (tooltip, -1) : NULL; ensure_has_tooltip (entry); + + g_object_notify (G_OBJECT (entry), + icon_pos == GTK_ENTRY_ICON_PRIMARY ? "primary-icon-tooltip-text" : "secondary-icon-tooltip-text"); } /**