1 --- gtk+-2.6.4/gtk/gtkentry.c 2005-02-04 17:36:02.000000000 +0200
2 +++ gtk+-2.6.4/gtk/gtkentry.c 2005-04-06 16:19:36.466994536 +0300
4 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
7 + /* Modified for Nokia Oyj during 2002-2003. See CHANGES file for list
15 #include "gtktreeselection.h"
16 #include "gtkentryprivate.h"
17 #include "gtkcelllayout.h"
18 +#include "gtkscrolledwindow.h"
20 #define GTK_ENTRY_COMPLETION_KEY "gtk-entry-completion-key"
23 #define DRAW_TIMEOUT 20
24 #define INNER_BORDER 2
25 #define COMPLETION_TIMEOUT 300
26 +#define HILDON_EDITED_CHARACTER_MAX 8
27 +#define HILDON_EDITED_CHARACTER_MS 600 /* 0.6 seconds */
29 /* Initial size of buffer, in bytes */
35 + /* Hildon additions:
36 + * following variables are needed
37 + * for Hildon password 'preview'
38 + * functionality; last inputted character
39 + * is showed for defined period, before it is
42 + gchar hildon_edited_character[HILDON_EDITED_CHARACTER_MAX];
43 + gboolean hildon_edited_character_timeout;
44 + gint hildon_edited_character_length;
45 + gboolean keep_focus;
46 + gboolean menu_popped;
60 static guint signals[LAST_SIGNAL] = { 0 };
65 +static void gtk_entry_update_scrolled_window (GtkEntry *entry);
66 +static void gtk_entry_set_autocap (GtkEntry *entry,
68 +static gboolean gtk_entry_get_autocap (GtkEntry *entry);
69 +static void gtk_entry_set_input_mode (GtkEntry *entry,
71 +static gint gtk_entry_get_input_mode (GtkEntry *entry);
74 + *returns an iterator to the character at position x,y of the
76 + *returns NULL if no iterator was found at that position
77 + *Caller must call pango_layout_free_iter on the returned iterator
79 +static PangoLayoutIter *get_char_at_pos( PangoLayout *layout, gint x, gint y );
81 +static gboolean hildon_remove_visible_character( gpointer data );
84 static gint gtk_entry_completion_timeout (gpointer data);
86 P_("FALSE displays the \"invisible char\" instead of the actual text (password mode)"),
88 G_PARAM_READABLE | G_PARAM_WRITABLE));
91 + g_object_class_install_property (gobject_class,
93 + g_param_spec_boolean ("autocap",
94 + P_("auto capitalization"),
95 + P_("Enable autocap support"),
97 + G_PARAM_READABLE | G_PARAM_WRITABLE));
99 + g_object_class_install_property (gobject_class,
101 + g_param_spec_int ("input_mode",
103 + P_("Define widget's input mode"),
105 + 9, /* keep me updated */
107 + G_PARAM_READABLE | G_PARAM_WRITABLE));
109 g_object_class_install_property (gobject_class,
111 g_param_spec_boolean ("has_frame",
114 G_PARAM_READABLE | G_PARAM_WRITABLE));
116 + gtk_widget_class_install_style_property (widget_class,
117 + g_param_spec_int ("horizontal-border",
118 + P_("Horizontal borders for entry"),
119 + P_("Set left/right borders"),
123 + G_PARAM_READWRITE));
125 + gtk_widget_class_install_style_property (widget_class,
126 + g_param_spec_int ("vertical-border",
127 + P_("Vertical borders for entry"),
128 + P_("Set top/bottom borders"),
132 + G_PARAM_READWRITE));
134 + gtk_widget_class_install_style_property (widget_class,
135 + g_param_spec_int ("icon-width",
137 + P_("Size of the purpose icon."),
141 + G_PARAM_READWRITE));
143 + gtk_widget_class_install_style_property (widget_class,
144 + g_param_spec_boolean ("show-last-char",
145 + P_("Show last char in invisible mode for a while"),
146 + P_("Last char is shown before it is rendered to asterisk"),
148 + G_PARAM_READABLE | G_PARAM_WRITABLE));
150 signals[POPULATE_POPUP] =
151 g_signal_new ("populate_popup",
152 G_OBJECT_CLASS_TYPE (gobject_class),
154 iface->start_editing = gtk_entry_start_editing;
157 +/* HILDON: Timed function to hide the most recently inputted character in password mode
160 + hildon_remove_visible_character( gpointer data )
162 + g_return_val_if_fail (GTK_IS_WIDGET (data), FALSE);
164 + GtkEntry * entry = GTK_ENTRY( data );
166 + /* Force the string to redrawn, but now without a visible character */
167 + gtk_entry_recompute( entry );
169 + /* Return false so this timeout is not called again and destroyed */
174 gtk_entry_set_property (GObject *object,
178 gboolean new_value = g_value_get_boolean (value);
180 + gtk_widget_set_sensitive( GTK_WIDGET( entry ), entry->editable );
181 if (new_value != entry->editable)
186 gtk_entry_reset_im_context (entry);
187 if (GTK_WIDGET_HAS_FOCUS (entry))
188 @@ -896,6 +1003,14 @@
189 case PROP_VISIBILITY:
190 gtk_entry_set_visibility (entry, g_value_get_boolean (value));
194 + gtk_entry_set_autocap (entry, g_value_get_boolean (value));
197 + case PROP_INPUT_MODE:
198 + gtk_entry_set_input_mode (entry, g_value_get_int (value));
202 gtk_entry_set_has_frame (entry, g_value_get_boolean (value));
203 @@ -954,6 +1069,12 @@
204 case PROP_VISIBILITY:
205 g_value_set_boolean (value, entry->visible);
208 + g_value_set_boolean (value, gtk_entry_get_autocap (entry));
210 + case PROP_INPUT_MODE:
211 + g_value_set_int (value, gtk_entry_get_input_mode (entry));
214 g_value_set_boolean (value, entry->has_frame);
216 @@ -1000,7 +1121,20 @@
217 entry->width_chars = -1;
218 entry->is_cell_renderer = FALSE;
219 entry->editing_canceled = FALSE;
220 - entry->has_frame = TRUE;
221 +#ifdef HILDON_SINGLE_LINE_EDITOR
222 + entry->has_frame = FALSE;
224 + entry->has_frame = TRUE;
228 + memset( &priv->hildon_edited_character, 0x00, HILDON_EDITED_CHARACTER_MAX );
229 + priv->hildon_edited_character_length = 0;
230 + priv->hildon_edited_character_timeout = FALSE;
232 + priv->keep_focus = FALSE;
233 + priv->menu_popped = FALSE;
237 gtk_drag_dest_set (GTK_WIDGET (entry),
238 @@ -1013,6 +1147,10 @@
239 * to it; so we create it here and destroy it in finalize().
241 entry->im_context = gtk_im_multicontext_new ();
242 + /* Set default stuff. */
243 + gtk_entry_set_autocap (entry, TRUE);
244 + gtk_entry_set_input_mode (entry, 0); /* alpha-numeric-special */
245 + g_object_set (G_OBJECT (entry->im_context), "use-show-hide", TRUE, NULL);
247 g_signal_connect (entry->im_context, "commit",
248 G_CALLBACK (gtk_entry_commit_cb), entry);
249 @@ -1058,7 +1196,8 @@
250 gtk_entry_finalize (GObject *object)
252 GtkEntry *entry = GTK_ENTRY (object);
254 + GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (GTK_WIDGET (entry));
256 gtk_entry_set_completion (entry, NULL);
258 if (entry->cached_layout)
259 @@ -1072,6 +1211,9 @@
260 if (entry->recompute_idle)
261 g_source_remove (entry->recompute_idle);
263 + if (priv->hildon_edited_character_timeout)
264 + g_source_remove (priv->hildon_edited_character_timeout);
266 entry->text_size = 0;
269 @@ -1213,7 +1355,14 @@
270 PangoFontMetrics *metrics;
271 gint xborder, yborder;
272 PangoContext *context;
274 + gint border_x, border_y;
277 + gtk_widget_style_get (widget,
278 + "horizontal-border", &border_x,
279 + "vertical-border", &border_y,
280 + "icon-width", &icon_width, NULL);
282 gtk_widget_ensure_style (widget);
283 context = gtk_widget_get_pango_context (widget);
284 metrics = pango_context_get_metrics (context,
285 @@ -1225,21 +1374,22 @@
287 _gtk_entry_get_borders (entry, &xborder, &yborder);
289 - xborder += INNER_BORDER;
290 - yborder += INNER_BORDER;
291 + xborder += border_x<<1;
292 + yborder += border_y<<1;
294 if (entry->width_chars < 0)
295 - requisition->width = MIN_ENTRY_WIDTH + xborder * 2;
296 + requisition->width = MIN_ENTRY_WIDTH + xborder;
299 gint char_width = pango_font_metrics_get_approximate_char_width (metrics);
300 gint digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
301 gint char_pixels = (MAX (char_width, digit_width) + PANGO_SCALE - 1) / PANGO_SCALE;
303 - requisition->width = char_pixels * entry->width_chars + xborder * 2;
304 + requisition->width = char_pixels * entry->width_chars + xborder;
307 - requisition->height = PANGO_PIXELS (entry->ascent + entry->descent) + yborder * 2;
309 + requisition->width += icon_width;
310 + requisition->height = PANGO_PIXELS (entry->ascent + entry->descent) + yborder;
312 pango_font_metrics_unref (metrics);
314 @@ -1253,23 +1403,39 @@
316 gint xborder, yborder;
317 GtkRequisition requisition;
319 GtkWidget *widget = GTK_WIDGET (entry);
321 + gtk_widget_style_get (widget, "icon-width", &icon_width, NULL);
323 gtk_widget_get_child_requisition (widget, &requisition);
325 _gtk_entry_get_borders (entry, &xborder, &yborder);
329 + *x = xborder + icon_width;
334 + if( widget->allocation.height < requisition.height )
335 + *y += ((widget->allocation.height - requisition.height) / 2);
341 - *width = GTK_WIDGET (entry)->allocation.width - xborder * 2;
342 + *width = GTK_WIDGET (entry)->allocation.width - xborder * 2 - icon_width;
345 - *height = requisition.height - yborder * 2;
347 + if( widget->allocation.height < requisition.height )
348 + *height = widget->allocation.height - yborder * 2;
350 + *height = widget->requisition.height - yborder * 2;
357 @@ -1289,10 +1455,9 @@
361 - if (entry->is_cell_renderer)
362 - *y = widget->allocation.y;
364 - *y = widget->allocation.y + (widget->allocation.height - requisition.height) / 2;
365 + *y = widget->allocation.y;
366 + if( widget->allocation.height > requisition.height )
367 + *y += ((widget->allocation.height - requisition.height) / 2);
371 @@ -1300,10 +1465,10 @@
375 - if (entry->is_cell_renderer)
376 - *height = widget->allocation.height;
378 + if( widget->allocation.height > requisition.height )
379 *height = requisition.height;
381 + *height = widget->allocation.height;
385 @@ -1383,20 +1548,19 @@
386 GdkEventExpose *event)
388 GtkEntry *entry = GTK_ENTRY (widget);
389 + gint area_width, area_height;
391 + get_widget_window_size (entry, NULL, NULL, &area_width, &area_height);
393 if (widget->window == event->window)
394 - gtk_entry_draw_frame (widget);
396 + gtk_paint_box (widget->style, widget->window,
397 + GTK_WIDGET_STATE (widget), GTK_SHADOW_NONE,
398 + NULL, widget, "entry_frame",
399 + 0, 0, area_width, area_height);
401 else if (entry->text_area == event->window)
403 - gint area_width, area_height;
405 - get_text_area_size (entry, NULL, NULL, &area_width, &area_height);
407 - gtk_paint_flat_box (widget->style, entry->text_area,
408 - GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
409 - NULL, widget, "entry_bg",
410 - 0, 0, area_width, area_height);
412 if ((entry->visible || entry->invisible_char != 0) &&
413 GTK_WIDGET_HAS_FOCUS (widget) &&
414 entry->selection_bound == entry->current_pos && entry->cursor_visible)
415 @@ -1490,16 +1654,19 @@
418 entry->button = event->button;
421 if (!GTK_WIDGET_HAS_FOCUS (widget))
423 entry->in_click = TRUE;
424 gtk_widget_grab_focus (widget);
425 entry->in_click = FALSE;
429 + /* Hildon: we need to reset IM context so pre-edit string can be committed */
430 + gtk_entry_reset_im_context (entry);
432 tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
435 if (event->button == 1)
437 gboolean have_selection = gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end);
438 @@ -1509,8 +1676,6 @@
440 if (event->state & GDK_SHIFT_MASK)
442 - gtk_entry_reset_im_context (entry);
444 if (!have_selection) /* select from the current position to the clicked position */
445 sel_start = sel_end = entry->current_pos;
447 @@ -1575,9 +1740,20 @@
448 entry->drag_start_x = event->x + entry->scroll_offset;
449 entry->drag_start_y = event->y + entry->scroll_offset;
452 - gtk_editable_set_position (editable, tmp_pos);
455 + /* HILDON: do not move the cursor inside the textarea if invisible
456 + * as per the specifications */
457 + if (!entry->visible)
458 + if(tmp_pos == strlen(gtk_entry_get_text(entry))){
459 + gtk_editable_set_position( editable, entry->text_length);
461 + gtk_editable_select_region (editable, 0, -1);
464 + gtk_editable_set_position (editable, tmp_pos);
469 case GDK_2BUTTON_PRESS:
470 /* We ALWAYS receive a GDK_BUTTON_PRESS immediately before
471 @@ -1614,8 +1790,16 @@
473 else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
475 + /* Hildon: if we are in password mode selection and Cut & Copy should
477 + if (!entry->visible)
479 + gtk_editable_set_position (GTK_EDITABLE(entry), 0);
482 gtk_entry_do_popup (entry, event);
483 entry->button = 0; /* Don't wait for release, since the menu will gtk_grab_add */
484 + priv->keep_focus = TRUE;
488 @@ -1632,11 +1816,23 @@
489 if (event->window != entry->text_area || entry->button != event->button)
492 + if (entry->editable)
493 + gtk_im_context_show (entry->im_context);
497 gint tmp_pos = gtk_entry_find_position (entry, entry->drag_start_x);
499 - gtk_editable_set_position (GTK_EDITABLE (entry), tmp_pos);
500 + /* HILDON: If not visible, do not allow cursor to be positioned inside the string */
501 + if (!entry->visible){
502 + if(tmp_pos == strlen(gtk_entry_get_text(entry))){
503 + gtk_editable_set_position( GTK_EDITABLE(entry), entry->text_length);
505 + gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
508 + gtk_editable_set_position (GTK_EDITABLE (entry), tmp_pos);
513 @@ -1822,6 +2018,13 @@
517 + if (event->keyval == GDK_Return)
519 + if (event->keyval == GDK_KP_Enter)
520 + g_signal_emit_by_name (G_OBJECT(gtk_widget_get_ancestor (widget,
521 + GTK_TYPE_WINDOW)), "move-focus",
522 + GTK_DIR_TAB_FORWARD);
524 if (GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
525 /* Activate key bindings
527 @@ -1835,6 +2038,8 @@
530 GtkEntry *entry = GTK_ENTRY (widget);
532 + gtk_entry_update_scrolled_window( entry );
536 @@ -1853,7 +2058,35 @@
537 GdkEventFocus *event)
539 GtkEntry *entry = GTK_ENTRY (widget);
541 + GtkEntryPrivate *priv;
543 + priv = GTK_ENTRY_GET_PRIVATE (widget);
544 + /* Hildon : If the text doesn't fit the entry, upon focusing
545 + * to an text field, move the caret to the end of the entry.
546 + * Force the entry to recompute, otherwise it doesn't update
547 + * if the cursor is currently at the end*/
548 + /* hildon : If the text has no selection and focus returned with
549 + other means than pointer click, set cursor before first
550 + character of the text, otherwise behave normally */
552 + if (!entry->in_click)
554 + /*gboolean has_selection;
555 + has_selection = gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), NULL, NULL);
556 + if (!has_selection)
558 + gtk_editable_set_position (GTK_EDITABLE (entry), -1);
559 + }*//*FIXME need a better hack here*/
560 + /* Hildon: If in SecretEditor mode highlight selection if entry got focus
561 + * otherways than mouse/stylus */
562 + if (!entry->visible && priv->keep_focus)
564 + gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
568 + gtk_entry_recompute (GTK_ENTRY (entry));
570 gtk_widget_queue_draw (widget);
573 @@ -1876,6 +2109,8 @@
574 GdkEventFocus *event)
576 GtkEntry *entry = GTK_ENTRY (widget);
577 + GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
579 GtkEntryCompletion *completion;
581 gtk_widget_queue_draw (widget);
582 @@ -1886,6 +2121,20 @@
583 gtk_im_context_focus_out (entry->im_context);
586 + tmp_pos = gtk_editable_get_position (GTK_EDITABLE (widget));
587 + if (priv->keep_focus){
588 + if (!entry->visible)
589 + gtk_editable_set_position (GTK_EDITABLE (widget), tmp_pos);
590 + priv->keep_focus = FALSE;
593 + if (priv->menu_popped)
594 + priv->menu_popped = FALSE;
595 + else gtk_editable_set_position (GTK_EDITABLE (widget), tmp_pos);
598 + gtk_widget_queue_draw(widget);
600 gtk_entry_check_cursor_blink (entry);
602 g_signal_handlers_disconnect_by_func (gdk_keymap_get_for_display (gtk_widget_get_display (widget)),
603 @@ -1902,7 +2151,6 @@
605 gtk_entry_grab_focus (GtkWidget *widget)
607 - GtkEntry *entry = GTK_ENTRY (widget);
608 gboolean select_on_focus;
610 GTK_WIDGET_CLASS (parent_class)->grab_focus (widget);
611 @@ -1912,8 +2160,8 @@
615 - if (select_on_focus && entry->editable && !entry->in_click)
616 - gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
617 +/* Hildon : When focusing to an entry, it shouldn't become
622 @@ -1987,7 +2235,7 @@
624 if (new_text_length > 63)
627 + gtk_entry_update_scrolled_window( entry );
628 g_object_unref (editable);
631 @@ -2074,7 +2322,7 @@
633 end = entry->text_length;
635 - gtk_entry_reset_im_context (entry);
636 + /*gtk_entry_reset_im_context (entry);*//*FIXME tmp kludge, might break something*/
638 gtk_entry_set_positions (entry,
639 MIN (end, entry->text_length),
640 @@ -2168,13 +2416,19 @@
644 + gboolean show_last_char = FALSE;
646 GtkEntry *entry = GTK_ENTRY (editable);
648 + GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (GTK_WIDGET (entry));
649 if (new_text_length < 0)
650 new_text_length = strlen (new_text);
652 n_chars = g_utf8_strlen (new_text, new_text_length);
655 + gtk_widget_style_get (GTK_WIDGET (entry), "show-last-char",
656 + &show_last_char, NULL);
658 if (entry->text_max_length > 0 && n_chars + entry->text_length > entry->text_max_length)
660 gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (entry)));
661 @@ -2238,6 +2492,14 @@
663 if (entry->selection_bound > *position)
664 entry->selection_bound += n_chars;
666 + /* Hildon: store this addition IF it was only 1 char (user inputted) and we are currently in secret mode (invisible) */
668 + if (show_last_char && n_chars == 1 && !entry->visible && (new_text_length < HILDON_EDITED_CHARACTER_MAX)) {
669 + memset( &priv->hildon_edited_character, 0x00, HILDON_EDITED_CHARACTER_MAX );
670 + priv->hildon_edited_character_length = new_text_length;
671 + memcpy( &priv->hildon_edited_character, new_text, new_text_length ); /* Guaranteed to be < total length */
674 *position += n_chars;
676 @@ -2339,6 +2601,11 @@
678 gtk_entry_reset_im_context (entry);
680 + /* Hildon, if not visible set the position to the end */
681 + /* New SecretEditor specs say that with cursor should move
682 + * With left/right arrows
685 if (entry->current_pos != entry->selection_bound && !extend_selection)
687 /* If we have a current selection and aren't extending it, move to the
688 @@ -2445,7 +2712,7 @@
689 gint start_pos = entry->current_pos;
690 gint end_pos = entry->current_pos;
692 - gtk_entry_reset_im_context (entry);
693 + /* Hildon: code removed - backspace should not clear the word completion */
695 if (!entry->editable)
697 @@ -2515,7 +2782,8 @@
698 GtkEditable *editable = GTK_EDITABLE (entry);
701 - gtk_entry_reset_im_context (entry);
702 +/* gtk_entry_reset_im_context (entry); */ /*backspace should not clear
703 + the word completion*/
705 if (!entry->editable || !entry->text)
707 @@ -2883,21 +3151,28 @@
713 +#define HILDON_EDITED_CHARACTER_MS 600 /* 0.6 seconds */
716 gtk_entry_create_layout (GtkEntry *entry,
717 gboolean include_preedit)
719 GtkWidget *widget = GTK_WIDGET (entry);
720 + GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
721 PangoLayout *layout = gtk_widget_create_pango_layout (widget, NULL);
722 PangoAttrList *tmp_attrs = pango_attr_list_new ();
724 gchar *preedit_string = NULL;
725 gint preedit_length = 0;
726 PangoAttrList *preedit_attrs = NULL;
727 + gboolean show_last_char = FALSE;
729 pango_layout_set_single_paragraph_mode (layout, TRUE);
731 + gtk_widget_style_get (widget, "show-last-char",
732 + &show_last_char, NULL);
736 gtk_im_context_get_preedit_string (entry->im_context,
737 @@ -3003,7 +3278,49 @@
739 invisible_char = ' '; /* just pick a char */
741 - append_char (str, invisible_char, entry->text_length);
742 + if (!show_last_char)
743 + append_char (str, invisible_char, entry->text_length);
744 + else if (show_last_char)
747 + if (priv->hildon_edited_character_length > 0)
750 + /* If we have an outstanding timeout, remove it, because the character it is set to hide
751 + * is already hidden now. We do this first to prevent possible race conditions if the timout
752 + * were to trigger while in here
755 + if (priv->hildon_edited_character_timeout)
757 + g_source_remove( priv->hildon_edited_character_timeout );
758 + priv->hildon_edited_character_timeout = FALSE;
761 + /* Draw the secret character length-1 times, because the last char will be visible */
762 + append_char (str, invisible_char, entry->text_length > 1 ? entry->text_length - 1 : 0);
764 + /* Add our visible char, the most recently inputted one */
765 + g_string_append_len (str, (char *)&priv->hildon_edited_character, priv->hildon_edited_character_length);
767 + /* Now remove this last inputted character, don't need it anymore */
769 + memset( priv->hildon_edited_character, 0x00, HILDON_EDITED_CHARACTER_MAX );
770 + priv->hildon_edited_character_length = 0;
772 + priv->hildon_edited_character_timeout = g_timeout_add( HILDON_EDITED_CHARACTER_MS, (GSourceFunc)
773 + hildon_remove_visible_character, entry );
778 + /* No last character known. This could be for example because the application has filled
779 + * in the password already. In that case we of course don't want to view it
781 + append_char (str, invisible_char, entry->text_length);
785 pango_layout_set_text (layout, str->str, str->len);
786 g_string_free (str, TRUE);
788 @@ -3048,12 +3365,17 @@
789 gint area_width, area_height;
791 PangoLayoutLine *line;
793 + gint border_x, border_y;
795 + gtk_widget_style_get (GTK_WIDGET (entry), "horizontal-border", &border_x,
796 + "vertical-border", &border_y,
799 layout = gtk_entry_ensure_layout (entry, TRUE);
801 get_text_area_size (entry, NULL, NULL, &area_width, &area_height);
803 - area_height = PANGO_SCALE * (area_height - 2 * INNER_BORDER);
804 + area_height = PANGO_SCALE * (area_height - 2 * border_y);
806 line = pango_layout_get_lines (layout)->data;
807 pango_layout_line_get_extents (line, NULL, &logical_rect);
808 @@ -3070,10 +3392,10 @@
809 else if (y_pos + logical_rect.height > area_height)
810 y_pos = area_height - logical_rect.height;
812 - y_pos = INNER_BORDER + y_pos / PANGO_SCALE;
813 + y_pos = border_y + y_pos / PANGO_SCALE;
816 - *x = INNER_BORDER - entry->scroll_offset;
817 + *x = border_x - entry->scroll_offset;
821 @@ -3083,6 +3405,10 @@
822 gtk_entry_draw_text (GtkEntry *entry)
825 + gint border_y, border_x;
827 + gtk_widget_style_get (GTK_WIDGET (entry), "horizontal-border", &border_x,
828 + "vertical-border", &border_y, NULL);
830 if (!entry->visible && entry->invisible_char == 0)
832 @@ -3092,14 +3418,76 @@
833 PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
835 gint start_pos, end_pos;
836 + GdkRectangle clip_rect;
838 widget = GTK_WIDGET (entry);
840 get_layout_position (entry, &x, &y);
842 + /* Use a clipping rectangle so that we always get enough empty space around
845 + clip_rect.x = border_x;
848 + gdk_drawable_get_size (entry->text_area, &clip_rect.width, &clip_rect.height);
849 + clip_rect.width -= border_x * 2;
851 + /*changes for Hildon
852 + *Reduce the size of the clip rect, so that only full characters are displayed
855 + /* NOTE: Commented out because it does not work with bidi text where
856 +the indexes are in random
857 + * left-right or right-left order. Code causes Pango assert aborts. Because gtkentry itself
858 + * is broken with regard to bidi anyway (bug #478) we ignore this requirement of the spec
859 + * until gtkentry itself is fixed. (bug #477)
862 + /* Better yet, let's enable this only when not in RTL mode */
864 + /* Note: BUG #857. patched gtkentry crashed when pasting scalable fonts. This is pango problem
865 + * and we tested patched gtkentry with pango version 1.3.2 and it appears to be fixed. Section is commented
866 + out until we upgrade to new version of pango
867 + if (gtk_widget_get_direction( entry ) != GTK_TEXT_DIR_RTL)
869 + PangoRectangle char_rect; // used for getting character's onscreen pos
870 + PangoLayoutIter *iter; // used to iterate over the text
872 + // get the position of the character currently at the clip border
873 + iter = get_char_at_pos( layout, (clip_rect.x + clip_rect.width + entry->scroll_offset), 0 );
876 + // get the position of that character on the screen
877 + pango_layout_iter_get_char_extents( iter, &char_rect );
878 + char_rect.x /= PANGO_SCALE;
879 + char_rect.x -= entry->scroll_offset;
880 + char_rect.width /= PANGO_SCALE;
882 + // if the ending position is > the clip rectangle, then the
883 + // character is only partially visible, and we should
884 + // clip the entire character.
886 + if ( char_rect.x + char_rect.width > clip_rect.x + clip_rect.width )
888 + clip_rect.width = char_rect.x;
891 + pango_layout_iter_free( iter );
896 + /******************************************************************/
898 + gdk_gc_set_clip_rectangle (widget->style->text_gc [widget->state], &clip_rect);
900 gdk_draw_layout (entry->text_area, widget->style->text_gc [widget->state],
904 + gdk_gc_set_clip_rectangle (widget->style->text_gc [widget->state], NULL);
907 if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_pos, &end_pos))
909 @@ -3128,7 +3516,7 @@
913 - rect.x = INNER_BORDER - entry->scroll_offset + ranges[2 * i];
914 + rect.x = border_x - entry->scroll_offset + ranges[2 * i];
916 rect.width = ranges[2 * i + 1];
917 rect.height = logical_rect.height;
918 @@ -3177,14 +3565,18 @@
920 GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (entry)));
921 PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
922 + gint border_x, border_y;
924 + gtk_widget_style_get (GTK_WIDGET (entry), "horizontal-border", &border_x,
925 + "vertical-border", &border_y,
927 if (GTK_WIDGET_DRAWABLE (entry))
929 GtkWidget *widget = GTK_WIDGET (entry);
930 GdkRectangle cursor_location;
931 gboolean split_cursor;
933 - gint xoffset = INNER_BORDER - entry->scroll_offset;
934 + gint xoffset = border_x - entry->scroll_offset;
935 gint strong_x, weak_x;
936 gint text_area_height;
937 PangoDirection dir1 = PANGO_DIRECTION_NEUTRAL;
938 @@ -3221,9 +3613,9 @@
941 cursor_location.x = xoffset + x1;
942 - cursor_location.y = INNER_BORDER;
943 + cursor_location.y = border_y;
944 cursor_location.width = 0;
945 - cursor_location.height = text_area_height - 2 * INNER_BORDER ;
946 + cursor_location.height = text_area_height - 2 * border_y;
948 draw_insertion_cursor (entry,
949 &cursor_location, TRUE, dir1,
950 @@ -3249,11 +3641,8 @@
952 gtk_entry_reset_im_context (GtkEntry *entry)
954 - if (entry->need_im_reset)
956 - entry->need_im_reset = 0;
957 - gtk_im_context_reset (entry->im_context);
959 + /* Hildon: We want reset to be sent more often */
960 + gtk_im_context_reset (entry->im_context);
964 @@ -3266,8 +3655,12 @@
970 + gint border_x, cursor_index;
972 + gtk_widget_style_get (GTK_WIDGET (entry), "horizontal-border", &border_x,
976 layout = gtk_entry_ensure_layout (entry, TRUE);
977 text = pango_layout_get_text (layout);
978 cursor_index = g_utf8_offset_to_pointer (text, entry->current_pos) - text;
979 @@ -3355,12 +3748,17 @@
981 PangoLayoutLine *line;
982 PangoRectangle logical_rect;
983 + gint border_x, border_y;
985 + gtk_widget_style_get (GTK_WIDGET (entry), "horizontal-border", &border_x,
986 + "vertical-border", &border_y,
989 if (!GTK_WIDGET_REALIZED (entry))
992 gdk_drawable_get_size (entry->text_area, &text_area_width, NULL);
993 - text_area_width -= 2 * INNER_BORDER;
994 + text_area_width -= 2 * border_x;
996 layout = gtk_entry_ensure_layout (entry, TRUE);
997 line = pango_layout_get_lines (layout)->data;
998 @@ -3390,13 +3788,13 @@
999 entry->scroll_offset = CLAMP (entry->scroll_offset, min_offset, max_offset);
1001 /* And make sure cursors are on screen. Note that the cursor is
1002 - * actually drawn one pixel into the INNER_BORDER space on
1003 + * actually drawn one pixel into the border_x space on
1004 * the right, when the scroll is at the utmost right. This
1005 * looks better to to me than confining the cursor inside the
1006 * border entirely, though it means that the cursor gets one
1007 * pixel closer to the edge of the widget on the right than
1008 * on the left. This might need changing if one changed
1009 - * INNER_BORDER from 2 to 1, as one would do on a
1010 + * border_x from 2 to 1, as one would do on a
1011 * small-screen-real-estate display.
1013 * We always make sure that the strong cursor is on screen, and
1014 @@ -3430,6 +3828,52 @@
1015 entry->scroll_offset += weak_xoffset - text_area_width;
1018 + /*Changes for Hildon
1019 + * now we make it so that if a character is partially visible,
1020 + * then we also scroll that off the screen.
1023 + /* NOTE: Commented out because it does not work with bidi text where the indexes are in random
1024 + * left-right or right-left order. Code causes Pango assert aborts. Because gtkentry itself
1025 + * is broken with regard to bidi anyway (bug #478) we ignore this requirement of the spec
1026 + * until gtkentry itself is fixed. (bug #477)
1029 + /* Better yet, let's disable this (for now) only when using RTL text */
1031 +/*Note: BUG #857. patched gtkentry crashed when pasting scalable fonts. This is pango problem
1032 + * and we tested patched gtkentry with pango version 1.3.2 and it appears to be fixed. Section is comment ed out until we upgrade to new version of pango
1033 + if (gtk_widget_get_direction( entry ) != GTK_TEXT_DIR_RTL)
1035 + PangoLayoutIter *iter = get_char_at_pos( layout, entry->scroll_offset, 0 );
1036 + // if we found the char we were looking for
1039 + PangoRectangle char_rect; // used for getting character's onscreen pos
1041 + // get the position of that character on the screen
1042 + pango_layout_iter_get_char_extents( iter, &char_rect );
1043 + char_rect.x /= PANGO_SCALE;
1045 + // if the starting position is < the current scroll offset, then the
1046 + // character is only partially visible, and we should scroll to the
1047 + // start of the next character instead
1049 + if ( char_rect.x < entry->scroll_offset )
1051 + if ( pango_layout_iter_next_char( iter ) )
1053 + pango_layout_iter_get_char_extents( iter, &char_rect);
1054 + entry->scroll_offset = char_rect.x / PANGO_SCALE;
1058 + pango_layout_iter_free( iter );
1064 g_object_notify (G_OBJECT (entry), "scroll_offset");
1067 @@ -3552,8 +3996,9 @@
1068 pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
1070 /* Find the next word end */
1071 + /*Hildon: cursor should seek to the start of the next word*/
1073 - while (new_pos < n_attrs && !log_attrs[new_pos].is_word_end)
1074 + while (new_pos < n_attrs && !log_attrs[new_pos].is_word_start)
1078 @@ -3648,14 +4093,9 @@
1081 return gtk_editable_get_chars (GTK_EDITABLE (entry), start, end);
1082 - else if (!entry->invisible_char)
1083 + /*Hildon: when not visible, no chars are public*/
1085 return g_strdup ("");
1088 - GString *str = g_string_new (NULL);
1089 - append_char (str, entry->invisible_char, end - start);
1090 - return g_string_free (str, FALSE);
1095 @@ -3678,9 +4118,12 @@
1099 - gint pos, start, end;
1100 + gint pos, start, end, index;
1101 GtkEntryCompletion *completion = gtk_entry_get_completion (entry);
1103 + /* when pasting multiline text, ignore everything but the first line */
1104 + for (index = 0; text[index] != 0 && text[index] != '\n'; index++);
1108 g_signal_handler_block (entry, completion->priv->changed_id);
1109 @@ -3692,7 +4135,7 @@
1110 gtk_editable_delete_text (editable, start, end);
1112 pos = entry->current_pos;
1113 - gtk_editable_insert_text (editable, text, -1, &pos);
1114 + gtk_editable_insert_text (editable, text, index, &pos);
1115 gtk_editable_set_position (editable, pos);
1118 @@ -3888,6 +4331,7 @@
1120 g_return_if_fail (GTK_IS_ENTRY (entry));
1122 + g_object_set(G_OBJECT(entry->im_context), "visibility", visible, NULL);
1123 entry->visible = visible ? TRUE : FALSE;
1124 g_object_notify (G_OBJECT (entry), "visibility");
1125 gtk_entry_recompute (entry);
1126 @@ -4569,6 +5013,7 @@
1127 GdkEventButton *event)
1129 PopupInfo *info = g_new (PopupInfo, 1);
1130 + GtkEntryPrivate *priv;
1132 /* In order to know what entries we should make sensitive, we
1133 * ask for the current targets of the clipboard, and when
1134 @@ -4576,6 +5021,8 @@
1136 info->entry = g_object_ref (entry);
1138 + priv = GTK_ENTRY_GET_PRIVATE (entry);
1142 info->button = event->button;
1143 @@ -4591,6 +5038,8 @@
1144 gdk_atom_intern ("TARGETS", FALSE),
1145 popup_targets_received,
1148 + priv->menu_popped = TRUE;
1152 @@ -5389,3 +5838,156 @@
1157 +static PangoLayoutIter *get_char_at_pos( PangoLayout *layout, gint x, gint y )
1159 + gint index = 0; /*the index of the first character */
1160 + gint trailing = 0; /*not used*/
1161 + PangoLayoutIter *iter; /*used to iterate over the text*/
1162 + gboolean valid_char = TRUE;
1164 + /*get the position of the character currently at the scroll offset*/
1165 + pango_layout_xy_to_index( layout, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing );
1166 + iter = pango_layout_get_iter( layout );
1168 + /*iterate until we get to the character at the same index*/
1169 + while ( valid_char && pango_layout_iter_get_index( iter ) != index )
1171 + valid_char = pango_layout_iter_next_char( iter );
1174 + if ( valid_char == FALSE )
1180 +static void gtk_entry_update_scrolled_window( GtkEntry *entry)
1182 + GtkWidget *parent;
1183 + GtkWidget *widget;
1184 + GtkWidget *direct_parent = NULL;
1185 + GtkScrolledWindow *sw = NULL;
1186 + gboolean need_update = FALSE;
1187 + GtkAdjustment *vadjustment;
1190 + widget = parent = GTK_WIDGET(entry);
1191 + if(parent->parent != NULL)
1192 + direct_parent = parent->parent;
1193 + while(parent && !GTK_WIDGET_TOPLEVEL(parent))
1195 + if(GTK_IS_SCROLLED_WINDOW(parent))
1197 + need_update = TRUE;
1198 + sw = GTK_SCROLLED_WINDOW(parent);
1201 + parent = parent->parent;
1207 + vadjustment = gtk_scrolled_window_get_vadjustment(sw);
1208 + value = gtk_adjustment_get_value(vadjustment);
1210 + if(direct_parent != NULL)
1211 + gtk_widget_translate_coordinates( direct_parent, parent,
1212 + widget->allocation.x, widget->allocation.y, &x, &y );
1214 + if( (gdouble) y < 0 )
1216 + value = value + (gdouble) y;
1217 + if (value < vadjustment->lower)
1218 + value = vadjustment->lower;
1220 + else if( (gdouble )y + widget->allocation.height > vadjustment->page_size)
1222 + value = value + (gdouble)y + widget->allocation.height
1223 + - vadjustment->page_size;
1224 + if(value > vadjustment->upper - vadjustment->page_size)
1225 + value = vadjustment->upper - vadjustment->page_size;
1227 + gtk_adjustment_set_value(vadjustment, value);
1228 + gtk_scrolled_window_set_vadjustment(sw, GTK_ADJUSTMENT(vadjustment));
1233 + * gtk_entry_set_autocap:
1234 + * @entry: a #GtkEntry
1235 + * @autocap: autocap
1237 + * Sets autocapitalization of the widget.
1240 +gtk_entry_set_autocap (GtkEntry *entry,
1243 + g_return_if_fail (GTK_IS_ENTRY (entry));
1245 + if (gtk_entry_get_autocap (entry) != autocap)
1247 + g_object_set (G_OBJECT (entry->im_context), "autocap", autocap, NULL);
1248 + g_object_notify (G_OBJECT (entry), "autocap");
1253 + * gtk_entry_get_autocap:
1254 + * @entry: a #GtkEntry
1256 + * Gets autocapitalization state of the widget.
1258 + * Return value: a state
1261 +gtk_entry_get_autocap (GtkEntry *entry)
1264 + g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
1266 + g_object_get (G_OBJECT (entry->im_context), "autocap", &autocap, NULL);
1272 + * gtk_entry_set_input_mode:
1273 + * @entry: a #GtkEntry
1274 + * @autocap: input mode
1276 + * Sets autocapitalization of the widget.
1279 +gtk_entry_set_input_mode (GtkEntry *entry,
1282 + g_return_if_fail (GTK_IS_ENTRY (entry));
1284 + if (gtk_entry_get_input_mode (entry) != mode)
1286 + g_object_set (G_OBJECT (entry->im_context), "input_mode", mode, NULL);
1287 + g_object_notify (G_OBJECT (entry), "input_mode");
1292 + * gtk_entry_get_input_mode:
1293 + * @entry: a #GtkEntry
1295 + * Gets input mode of the widget.
1297 + * Return value: input mode
1300 +gtk_entry_get_input_mode (GtkEntry *entry)
1303 + g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
1305 + g_object_get (G_OBJECT (entry->im_context), "input_mode", &mode, NULL);