]> Pileus Git - ~andy/gtk/blob - gtk/gtkentry.c
Unify the handling of various "Enter" keysyms all over the place.
[~andy/gtk] / gtk / gtkentry.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* GTK - The GIMP Toolkit
3  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
26  */
27
28 #include <config.h>
29 #include <string.h>
30
31 #include <pango/pango.h>
32
33 #include "gdk/gdkkeysyms.h"
34 #include "gtkbindings.h"
35 #include "gtkcelleditable.h"
36 #include "gtkclipboard.h"
37 #include "gtkdnd.h"
38 #include "gtkentry.h"
39 #include "gtkimagemenuitem.h"
40 #include "gtkimcontextsimple.h"
41 #include "gtkimmulticontext.h"
42 #include "gtkintl.h"
43 #include "gtkmain.h"
44 #include "gtkmarshalers.h"
45 #include "gtkmenu.h"
46 #include "gtkmenuitem.h"
47 #include "gtkseparatormenuitem.h"
48 #include "gtkselection.h"
49 #include "gtksettings.h"
50 #include "gtkstock.h"
51 #include "gtktextutil.h"
52 #include "gtkwindow.h"
53 #include "gtktreeview.h"
54 #include "gtktreeselection.h"
55 #include "gtkprivate.h"
56 #include "gtkentryprivate.h"
57 #include "gtkcelllayout.h"
58 #include "gtkalias.h"
59
60 #define GTK_ENTRY_COMPLETION_KEY "gtk-entry-completion-key"
61
62 #define MIN_ENTRY_WIDTH  150
63 #define DRAW_TIMEOUT     20
64 #define COMPLETION_TIMEOUT 300
65 #define PASSWORD_HINT_MAX 8
66
67 /* Initial size of buffer, in bytes */
68 #define MIN_SIZE 16
69
70 /* Maximum size of text buffer, in bytes */
71 #define MAX_SIZE G_MAXUSHORT
72
73 static const GtkBorder default_inner_border = { 2, 2, 2, 2 };
74 static GQuark          quark_inner_border   = 0;
75 static GQuark          quark_password_hint  = 0;
76 static GQuark          quark_cursor_hadjustment = 0;
77
78 typedef struct _GtkEntryPrivate GtkEntryPrivate;
79
80 #define GTK_ENTRY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ENTRY, GtkEntryPrivate))
81
82 struct _GtkEntryPrivate 
83 {
84   gfloat xalign;
85   gint insert_pos;
86   guint blink_time;  /* time in msec the cursor has blinked since last user event */
87   guint interior_focus : 1;
88   guint real_changed   : 1;
89   guint change_count   : 8;
90
91   gint focus_width;
92   GtkShadowType shadow_type;
93 };
94
95 typedef struct _GtkEntryPasswordHint GtkEntryPasswordHint;
96
97 struct _GtkEntryPasswordHint
98 {
99   gchar password_hint[PASSWORD_HINT_MAX];
100   guint password_hint_timeout_id;
101   gint  password_hint_length;
102   gint  password_hint_position;
103 };
104
105 enum {
106   ACTIVATE,
107   POPULATE_POPUP,
108   MOVE_CURSOR,
109   INSERT_AT_CURSOR,
110   DELETE_FROM_CURSOR,
111   BACKSPACE,
112   CUT_CLIPBOARD,
113   COPY_CLIPBOARD,
114   PASTE_CLIPBOARD,
115   TOGGLE_OVERWRITE,
116   LAST_SIGNAL
117 };
118
119 enum {
120   PROP_0,
121   PROP_CURSOR_POSITION,
122   PROP_SELECTION_BOUND,
123   PROP_EDITABLE,
124   PROP_MAX_LENGTH,
125   PROP_VISIBILITY,
126   PROP_HAS_FRAME,
127   PROP_INNER_BORDER,
128   PROP_INVISIBLE_CHAR,
129   PROP_ACTIVATES_DEFAULT,
130   PROP_WIDTH_CHARS,
131   PROP_SCROLL_OFFSET,
132   PROP_TEXT,
133   PROP_XALIGN,
134   PROP_TRUNCATE_MULTILINE,
135   PROP_SHADOW_TYPE
136 };
137
138 static guint signals[LAST_SIGNAL] = { 0 };
139
140 typedef enum {
141   CURSOR_STANDARD,
142   CURSOR_DND
143 } CursorType;
144
145 /* GObject, GtkObject methods
146  */
147 static void   gtk_entry_editable_init        (GtkEditableClass     *iface);
148 static void   gtk_entry_cell_editable_init   (GtkCellEditableIface *iface);
149 static void   gtk_entry_set_property         (GObject          *object,
150                                               guint             prop_id,
151                                               const GValue     *value,
152                                               GParamSpec       *pspec);
153 static void   gtk_entry_get_property         (GObject          *object,
154                                               guint             prop_id,
155                                               GValue           *value,
156                                               GParamSpec       *pspec);
157 static void   gtk_entry_finalize             (GObject          *object);
158 static void   gtk_entry_destroy              (GtkObject        *object);
159
160 /* GtkWidget methods
161  */
162 static void   gtk_entry_realize              (GtkWidget        *widget);
163 static void   gtk_entry_unrealize            (GtkWidget        *widget);
164 static void   gtk_entry_size_request         (GtkWidget        *widget,
165                                               GtkRequisition   *requisition);
166 static void   gtk_entry_size_allocate        (GtkWidget        *widget,
167                                               GtkAllocation    *allocation);
168 static void   gtk_entry_draw_frame           (GtkWidget        *widget,
169                                               GdkRectangle     *area);
170 static gint   gtk_entry_expose               (GtkWidget        *widget,
171                                               GdkEventExpose   *event);
172 static gint   gtk_entry_button_press         (GtkWidget        *widget,
173                                               GdkEventButton   *event);
174 static gint   gtk_entry_button_release       (GtkWidget        *widget,
175                                               GdkEventButton   *event);
176 static gint   gtk_entry_motion_notify        (GtkWidget        *widget,
177                                               GdkEventMotion   *event);
178 static gint   gtk_entry_key_press            (GtkWidget        *widget,
179                                               GdkEventKey      *event);
180 static gint   gtk_entry_key_release          (GtkWidget        *widget,
181                                               GdkEventKey      *event);
182 static gint   gtk_entry_focus_in             (GtkWidget        *widget,
183                                               GdkEventFocus    *event);
184 static gint   gtk_entry_focus_out            (GtkWidget        *widget,
185                                               GdkEventFocus    *event);
186 static void   gtk_entry_grab_focus           (GtkWidget        *widget);
187 static void   gtk_entry_style_set            (GtkWidget        *widget,
188                                               GtkStyle         *previous_style);
189 static void   gtk_entry_direction_changed    (GtkWidget        *widget,
190                                               GtkTextDirection  previous_dir);
191 static void   gtk_entry_state_changed        (GtkWidget        *widget,
192                                               GtkStateType      previous_state);
193 static void   gtk_entry_screen_changed       (GtkWidget        *widget,
194                                               GdkScreen        *old_screen);
195
196 static gboolean gtk_entry_drag_drop          (GtkWidget        *widget,
197                                               GdkDragContext   *context,
198                                               gint              x,
199                                               gint              y,
200                                               guint             time);
201 static gboolean gtk_entry_drag_motion        (GtkWidget        *widget,
202                                               GdkDragContext   *context,
203                                               gint              x,
204                                               gint              y,
205                                               guint             time);
206 static void     gtk_entry_drag_leave         (GtkWidget        *widget,
207                                               GdkDragContext   *context,
208                                               guint             time);
209 static void     gtk_entry_drag_data_received (GtkWidget        *widget,
210                                               GdkDragContext   *context,
211                                               gint              x,
212                                               gint              y,
213                                               GtkSelectionData *selection_data,
214                                               guint             info,
215                                               guint             time);
216 static void     gtk_entry_drag_data_get      (GtkWidget        *widget,
217                                               GdkDragContext   *context,
218                                               GtkSelectionData *selection_data,
219                                               guint             info,
220                                               guint             time);
221 static void     gtk_entry_drag_data_delete   (GtkWidget        *widget,
222                                               GdkDragContext   *context);
223
224 /* GtkEditable method implementations
225  */
226 static void     gtk_entry_insert_text          (GtkEditable *editable,
227                                                 const gchar *new_text,
228                                                 gint         new_text_length,
229                                                 gint        *position);
230 static void     gtk_entry_delete_text          (GtkEditable *editable,
231                                                 gint         start_pos,
232                                                 gint         end_pos);
233 static gchar *  gtk_entry_get_chars            (GtkEditable *editable,
234                                                 gint         start_pos,
235                                                 gint         end_pos);
236 static void     gtk_entry_real_set_position    (GtkEditable *editable,
237                                                 gint         position);
238 static gint     gtk_entry_get_position         (GtkEditable *editable);
239 static void     gtk_entry_set_selection_bounds (GtkEditable *editable,
240                                                 gint         start,
241                                                 gint         end);
242 static gboolean gtk_entry_get_selection_bounds (GtkEditable *editable,
243                                                 gint        *start,
244                                                 gint        *end);
245
246 /* GtkCellEditable method implementations
247  */
248 static void gtk_entry_start_editing (GtkCellEditable *cell_editable,
249                                      GdkEvent        *event);
250
251 /* Default signal handlers
252  */
253 static void gtk_entry_real_insert_text   (GtkEditable     *editable,
254                                           const gchar     *new_text,
255                                           gint             new_text_length,
256                                           gint            *position);
257 static void gtk_entry_real_delete_text   (GtkEditable     *editable,
258                                           gint             start_pos,
259                                           gint             end_pos);
260 static void gtk_entry_move_cursor        (GtkEntry        *entry,
261                                           GtkMovementStep  step,
262                                           gint             count,
263                                           gboolean         extend_selection);
264 static void gtk_entry_insert_at_cursor   (GtkEntry        *entry,
265                                           const gchar     *str);
266 static void gtk_entry_delete_from_cursor (GtkEntry        *entry,
267                                           GtkDeleteType    type,
268                                           gint             count);
269 static void gtk_entry_backspace          (GtkEntry        *entry);
270 static void gtk_entry_cut_clipboard      (GtkEntry        *entry);
271 static void gtk_entry_copy_clipboard     (GtkEntry        *entry);
272 static void gtk_entry_paste_clipboard    (GtkEntry        *entry);
273 static void gtk_entry_toggle_overwrite   (GtkEntry        *entry);
274 static void gtk_entry_select_all         (GtkEntry        *entry);
275 static void gtk_entry_real_activate      (GtkEntry        *entry);
276 static gboolean gtk_entry_popup_menu     (GtkWidget      *widget);
277
278 static void gtk_entry_keymap_direction_changed (GdkKeymap *keymap,
279                                                 GtkEntry  *entry);
280 /* IM Context Callbacks
281  */
282 static void     gtk_entry_commit_cb               (GtkIMContext *context,
283                                                    const gchar  *str,
284                                                    GtkEntry     *entry);
285 static void     gtk_entry_preedit_changed_cb      (GtkIMContext *context,
286                                                    GtkEntry     *entry);
287 static gboolean gtk_entry_retrieve_surrounding_cb (GtkIMContext *context,
288                                                    GtkEntry     *entry);
289 static gboolean gtk_entry_delete_surrounding_cb   (GtkIMContext *context,
290                                                    gint          offset,
291                                                    gint          n_chars,
292                                                    GtkEntry     *entry);
293
294 /* Internal routines
295  */
296 static void         gtk_entry_enter_text               (GtkEntry       *entry,
297                                                         const gchar    *str);
298 static void         gtk_entry_set_positions            (GtkEntry       *entry,
299                                                         gint            current_pos,
300                                                         gint            selection_bound);
301 static void         gtk_entry_draw_text                (GtkEntry       *entry);
302 static void         gtk_entry_draw_cursor              (GtkEntry       *entry,
303                                                         CursorType      type);
304 static PangoLayout *gtk_entry_ensure_layout            (GtkEntry       *entry,
305                                                         gboolean        include_preedit);
306 static void         gtk_entry_reset_layout             (GtkEntry       *entry);
307 static void         gtk_entry_queue_draw               (GtkEntry       *entry);
308 static void         gtk_entry_recompute                (GtkEntry       *entry);
309 static gint         gtk_entry_find_position            (GtkEntry       *entry,
310                                                         gint            x);
311 static void         gtk_entry_get_cursor_locations     (GtkEntry       *entry,
312                                                         CursorType      type,
313                                                         gint           *strong_x,
314                                                         gint           *weak_x);
315 static void         gtk_entry_adjust_scroll            (GtkEntry       *entry);
316 static gint         gtk_entry_move_visually            (GtkEntry       *editable,
317                                                         gint            start,
318                                                         gint            count);
319 static gint         gtk_entry_move_logically           (GtkEntry       *entry,
320                                                         gint            start,
321                                                         gint            count);
322 static gint         gtk_entry_move_forward_word        (GtkEntry       *entry,
323                                                         gint            start,
324                                                         gboolean        allow_whitespace);
325 static gint         gtk_entry_move_backward_word       (GtkEntry       *entry,
326                                                         gint            start,
327                                                         gboolean        allow_whitespace);
328 static void         gtk_entry_delete_whitespace        (GtkEntry       *entry);
329 static void         gtk_entry_select_word              (GtkEntry       *entry);
330 static void         gtk_entry_select_line              (GtkEntry       *entry);
331 static char *       gtk_entry_get_public_chars         (GtkEntry       *entry,
332                                                         gint            start,
333                                                         gint            end);
334 static void         gtk_entry_paste                    (GtkEntry       *entry,
335                                                         GdkAtom         selection);
336 static void         gtk_entry_update_primary_selection (GtkEntry       *entry);
337 static void         gtk_entry_do_popup                 (GtkEntry       *entry,
338                                                         GdkEventButton *event);
339 static gboolean     gtk_entry_mnemonic_activate        (GtkWidget      *widget,
340                                                         gboolean        group_cycling);
341 static void         gtk_entry_state_changed            (GtkWidget      *widget,
342                                                         GtkStateType    previous_state);
343 static void         gtk_entry_check_cursor_blink       (GtkEntry       *entry);
344 static void         gtk_entry_pend_cursor_blink        (GtkEntry       *entry);
345 static void         gtk_entry_reset_blink_time         (GtkEntry       *entry);
346 static void         get_text_area_size                 (GtkEntry       *entry,
347                                                         gint           *x,
348                                                         gint           *y,
349                                                         gint           *width,
350                                                         gint           *height);
351 static void         get_widget_window_size             (GtkEntry       *entry,
352                                                         gint           *x,
353                                                         gint           *y,
354                                                         gint           *width,
355                                                         gint           *height);
356 static void         gtk_entry_move_adjustments         (GtkEntry       *entry);
357
358 /* Completion */
359 static gint         gtk_entry_completion_timeout       (gpointer            data);
360 static gboolean     gtk_entry_completion_key_press     (GtkWidget          *widget,
361                                                         GdkEventKey        *event,
362                                                         gpointer            user_data);
363 static void         gtk_entry_completion_changed       (GtkWidget          *entry,
364                                                         gpointer            user_data);
365 static gboolean     check_completion_callback          (GtkEntryCompletion *completion);
366 static void         clear_completion_callback          (GtkEntry           *entry,
367                                                         GParamSpec         *pspec);
368 static gboolean     accept_completion_callback         (GtkEntry           *entry);
369 static void         completion_insert_text_callback    (GtkEntry           *entry,
370                                                         const gchar        *text,
371                                                         gint                length,
372                                                         gint                position,
373                                                         GtkEntryCompletion *completion);
374 static void         completion_changed                 (GtkEntryCompletion *completion,
375                                                         GParamSpec         *pspec,
376                                                         gpointer            data);
377 static void         disconnect_completion_signals      (GtkEntry           *entry,
378                                                         GtkEntryCompletion *completion);
379 static void         connect_completion_signals         (GtkEntry           *entry,
380                                                         GtkEntryCompletion *completion);
381
382 static void         begin_change                       (GtkEntry *entry);
383 static void         end_change                         (GtkEntry *entry);
384 static void         emit_changed                       (GtkEntry *entry);
385
386 G_DEFINE_TYPE_WITH_CODE (GtkEntry, gtk_entry, GTK_TYPE_WIDGET,
387                          G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
388                                                 gtk_entry_editable_init)
389                          G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_EDITABLE,
390                                                 gtk_entry_cell_editable_init))
391
392 static void
393 add_move_binding (GtkBindingSet  *binding_set,
394                   guint           keyval,
395                   guint           modmask,
396                   GtkMovementStep step,
397                   gint            count)
398 {
399   g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
400   
401   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
402                                 "move_cursor", 3,
403                                 G_TYPE_ENUM, step,
404                                 G_TYPE_INT, count,
405                                 G_TYPE_BOOLEAN, FALSE);
406
407   /* Selection-extending version */
408   gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
409                                 "move_cursor", 3,
410                                 G_TYPE_ENUM, step,
411                                 G_TYPE_INT, count,
412                                 G_TYPE_BOOLEAN, TRUE);
413 }
414
415 static void
416 gtk_entry_class_init (GtkEntryClass *class)
417 {
418   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
419   GtkWidgetClass *widget_class;
420   GtkObjectClass *gtk_object_class;
421   GtkBindingSet *binding_set;
422
423   widget_class = (GtkWidgetClass*) class;
424   gtk_object_class = (GtkObjectClass *)class;
425
426   gobject_class->finalize = gtk_entry_finalize;
427   gobject_class->set_property = gtk_entry_set_property;
428   gobject_class->get_property = gtk_entry_get_property;
429
430   widget_class->realize = gtk_entry_realize;
431   widget_class->unrealize = gtk_entry_unrealize;
432   widget_class->size_request = gtk_entry_size_request;
433   widget_class->size_allocate = gtk_entry_size_allocate;
434   widget_class->expose_event = gtk_entry_expose;
435   widget_class->button_press_event = gtk_entry_button_press;
436   widget_class->button_release_event = gtk_entry_button_release;
437   widget_class->motion_notify_event = gtk_entry_motion_notify;
438   widget_class->key_press_event = gtk_entry_key_press;
439   widget_class->key_release_event = gtk_entry_key_release;
440   widget_class->focus_in_event = gtk_entry_focus_in;
441   widget_class->focus_out_event = gtk_entry_focus_out;
442   widget_class->grab_focus = gtk_entry_grab_focus;
443   widget_class->style_set = gtk_entry_style_set;
444   widget_class->direction_changed = gtk_entry_direction_changed;
445   widget_class->state_changed = gtk_entry_state_changed;
446   widget_class->screen_changed = gtk_entry_screen_changed;
447   widget_class->mnemonic_activate = gtk_entry_mnemonic_activate;
448
449   widget_class->drag_drop = gtk_entry_drag_drop;
450   widget_class->drag_motion = gtk_entry_drag_motion;
451   widget_class->drag_leave = gtk_entry_drag_leave;
452   widget_class->drag_data_received = gtk_entry_drag_data_received;
453   widget_class->drag_data_get = gtk_entry_drag_data_get;
454   widget_class->drag_data_delete = gtk_entry_drag_data_delete;
455
456   widget_class->popup_menu = gtk_entry_popup_menu;
457
458   gtk_object_class->destroy = gtk_entry_destroy;
459
460   class->move_cursor = gtk_entry_move_cursor;
461   class->insert_at_cursor = gtk_entry_insert_at_cursor;
462   class->delete_from_cursor = gtk_entry_delete_from_cursor;
463   class->backspace = gtk_entry_backspace;
464   class->cut_clipboard = gtk_entry_cut_clipboard;
465   class->copy_clipboard = gtk_entry_copy_clipboard;
466   class->paste_clipboard = gtk_entry_paste_clipboard;
467   class->toggle_overwrite = gtk_entry_toggle_overwrite;
468   class->activate = gtk_entry_real_activate;
469   
470   quark_inner_border = g_quark_from_static_string ("gtk-entry-inner-border");
471   quark_password_hint = g_quark_from_static_string ("gtk-entry-password-hint");
472   quark_cursor_hadjustment = g_quark_from_static_string ("gtk-hadjustment");
473
474   g_object_class_install_property (gobject_class,
475                                    PROP_CURSOR_POSITION,
476                                    g_param_spec_int ("cursor-position",
477                                                      P_("Cursor Position"),
478                                                      P_("The current position of the insertion cursor in chars"),
479                                                      0,
480                                                      MAX_SIZE,
481                                                      0,
482                                                      GTK_PARAM_READABLE));
483   
484   g_object_class_install_property (gobject_class,
485                                    PROP_SELECTION_BOUND,
486                                    g_param_spec_int ("selection-bound",
487                                                      P_("Selection Bound"),
488                                                      P_("The position of the opposite end of the selection from the cursor in chars"),
489                                                      0,
490                                                      MAX_SIZE,
491                                                      0,
492                                                      GTK_PARAM_READABLE));
493   
494   g_object_class_install_property (gobject_class,
495                                    PROP_EDITABLE,
496                                    g_param_spec_boolean ("editable",
497                                                          P_("Editable"),
498                                                          P_("Whether the entry contents can be edited"),
499                                                          TRUE,
500                                                          GTK_PARAM_READWRITE));
501   
502   g_object_class_install_property (gobject_class,
503                                    PROP_MAX_LENGTH,
504                                    g_param_spec_int ("max-length",
505                                                      P_("Maximum length"),
506                                                      P_("Maximum number of characters for this entry. Zero if no maximum"),
507                                                      0,
508                                                      MAX_SIZE,
509                                                      0,
510                                                      GTK_PARAM_READWRITE));
511   g_object_class_install_property (gobject_class,
512                                    PROP_VISIBILITY,
513                                    g_param_spec_boolean ("visibility",
514                                                          P_("Visibility"),
515                                                          P_("FALSE displays the \"invisible char\" instead of the actual text (password mode)"),
516                                                          TRUE,
517                                                          GTK_PARAM_READWRITE));
518
519   g_object_class_install_property (gobject_class,
520                                    PROP_HAS_FRAME,
521                                    g_param_spec_boolean ("has-frame",
522                                                          P_("Has Frame"),
523                                                          P_("FALSE removes outside bevel from entry"),
524                                                          TRUE,
525                                                          GTK_PARAM_READWRITE));
526
527   g_object_class_install_property (gobject_class,
528                                    PROP_INNER_BORDER,
529                                    g_param_spec_boxed ("inner-border",
530                                                        P_("Inner Border"),
531                                                        P_("Border between text and frame. Overrides the inner-border style property"),
532                                                        GTK_TYPE_BORDER,
533                                                        GTK_PARAM_READWRITE));
534
535   g_object_class_install_property (gobject_class,
536                                    PROP_INVISIBLE_CHAR,
537                                    g_param_spec_unichar ("invisible-char",
538                                                          P_("Invisible character"),
539                                                          P_("The character to use when masking entry contents (in \"password mode\")"),
540                                                          '*',
541                                                          GTK_PARAM_READWRITE));
542
543   g_object_class_install_property (gobject_class,
544                                    PROP_ACTIVATES_DEFAULT,
545                                    g_param_spec_boolean ("activates-default",
546                                                          P_("Activates default"),
547                                                          P_("Whether to activate the default widget (such as the default button in a dialog) when Enter is pressed"),
548                                                          FALSE,
549                                                          GTK_PARAM_READWRITE));
550   g_object_class_install_property (gobject_class,
551                                    PROP_WIDTH_CHARS,
552                                    g_param_spec_int ("width-chars",
553                                                      P_("Width in chars"),
554                                                      P_("Number of characters to leave space for in the entry"),
555                                                      -1,
556                                                      G_MAXINT,
557                                                      -1,
558                                                      GTK_PARAM_READWRITE));
559
560   g_object_class_install_property (gobject_class,
561                                    PROP_SCROLL_OFFSET,
562                                    g_param_spec_int ("scroll-offset",
563                                                      P_("Scroll offset"),
564                                                      P_("Number of pixels of the entry scrolled off the screen to the left"),
565                                                      0,
566                                                      G_MAXINT,
567                                                      0,
568                                                      GTK_PARAM_READABLE));
569
570   g_object_class_install_property (gobject_class,
571                                    PROP_TEXT,
572                                    g_param_spec_string ("text",
573                                                         P_("Text"),
574                                                         P_("The contents of the entry"),
575                                                         "",
576                                                         GTK_PARAM_READWRITE));
577
578   /**
579    * GtkEntry:xalign:
580    *
581    * The horizontal alignment, from 0 (left) to 1 (right). 
582    * Reversed for RTL layouts.
583    * 
584    * Since: 2.4
585    */
586   g_object_class_install_property (gobject_class,
587                                    PROP_XALIGN,
588                                    g_param_spec_float ("xalign",
589                                                        P_("X align"),
590                                                        P_("The horizontal alignment, from 0 (left) to 1 (right). Reversed for RTL layouts."),
591                                                        0.0,
592                                                        1.0,
593                                                        0.0,
594                                                        GTK_PARAM_READWRITE));
595
596   /**
597    * GtkEntry:truncate-multiline:
598    *
599    * When %TRUE, pasted multi-line text is truncated to the first line.
600    *
601    * Since: 2.10
602    */
603   g_object_class_install_property (gobject_class,
604                                    PROP_TRUNCATE_MULTILINE,
605                                    g_param_spec_boolean ("truncate-multiline",
606                                                          P_("Truncate multiline"),
607                                                          P_("Whether to truncate multiline pastes to one line."),
608                                                          FALSE,
609                                                          GTK_PARAM_READWRITE));
610
611   /**
612    * GtkEntry:shadow-type:
613    *
614    * Which kind of shadow to draw around the entry when 
615    * #GtkEntry:has-frame is set to %TRUE.
616    *
617    * Since: 2.12
618    */
619   g_object_class_install_property (gobject_class,
620                                    PROP_SHADOW_TYPE,
621                                    g_param_spec_enum ("shadow-type",
622                                                       P_("Shadow type"),
623                                                       P_("Which kind of shadow to draw around the entry when has-frame is set"),
624                                                       GTK_TYPE_SHADOW_TYPE,
625                                                       GTK_SHADOW_IN,
626                                                       GTK_PARAM_READWRITE));
627
628   signals[POPULATE_POPUP] =
629     g_signal_new (I_("populate_popup"),
630                   G_OBJECT_CLASS_TYPE (gobject_class),
631                   G_SIGNAL_RUN_LAST,
632                   G_STRUCT_OFFSET (GtkEntryClass, populate_popup),
633                   NULL, NULL,
634                   _gtk_marshal_VOID__OBJECT,
635                   G_TYPE_NONE, 1,
636                   GTK_TYPE_MENU);
637   
638  /* Action signals */
639   
640   signals[ACTIVATE] =
641     g_signal_new (I_("activate"),
642                   G_OBJECT_CLASS_TYPE (gobject_class),
643                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
644                   G_STRUCT_OFFSET (GtkEntryClass, activate),
645                   NULL, NULL,
646                   _gtk_marshal_VOID__VOID,
647                   G_TYPE_NONE, 0);
648   widget_class->activate_signal = signals[ACTIVATE];
649
650   signals[MOVE_CURSOR] = 
651     g_signal_new (I_("move_cursor"),
652                   G_OBJECT_CLASS_TYPE (gobject_class),
653                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
654                   G_STRUCT_OFFSET (GtkEntryClass, move_cursor),
655                   NULL, NULL,
656                   _gtk_marshal_VOID__ENUM_INT_BOOLEAN,
657                   G_TYPE_NONE, 3,
658                   GTK_TYPE_MOVEMENT_STEP,
659                   G_TYPE_INT,
660                   G_TYPE_BOOLEAN);
661
662   signals[INSERT_AT_CURSOR] = 
663     g_signal_new (I_("insert_at_cursor"),
664                   G_OBJECT_CLASS_TYPE (gobject_class),
665                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
666                   G_STRUCT_OFFSET (GtkEntryClass, insert_at_cursor),
667                   NULL, NULL,
668                   _gtk_marshal_VOID__STRING,
669                   G_TYPE_NONE, 1,
670                   G_TYPE_STRING);
671
672   signals[DELETE_FROM_CURSOR] = 
673     g_signal_new (I_("delete_from_cursor"),
674                   G_OBJECT_CLASS_TYPE (gobject_class),
675                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
676                   G_STRUCT_OFFSET (GtkEntryClass, delete_from_cursor),
677                   NULL, NULL,
678                   _gtk_marshal_VOID__ENUM_INT,
679                   G_TYPE_NONE, 2,
680                   GTK_TYPE_DELETE_TYPE,
681                   G_TYPE_INT);
682
683   signals[BACKSPACE] =
684     g_signal_new (I_("backspace"),
685                   G_OBJECT_CLASS_TYPE (gobject_class),
686                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
687                   G_STRUCT_OFFSET (GtkEntryClass, backspace),
688                   NULL, NULL,
689                   _gtk_marshal_VOID__VOID,
690                   G_TYPE_NONE, 0);
691
692   signals[CUT_CLIPBOARD] =
693     g_signal_new (I_("cut_clipboard"),
694                   G_OBJECT_CLASS_TYPE (gobject_class),
695                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
696                   G_STRUCT_OFFSET (GtkEntryClass, cut_clipboard),
697                   NULL, NULL,
698                   _gtk_marshal_VOID__VOID,
699                   G_TYPE_NONE, 0);
700
701   signals[COPY_CLIPBOARD] =
702     g_signal_new (I_("copy_clipboard"),
703                   G_OBJECT_CLASS_TYPE (gobject_class),
704                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
705                   G_STRUCT_OFFSET (GtkEntryClass, copy_clipboard),
706                   NULL, NULL,
707                   _gtk_marshal_VOID__VOID,
708                   G_TYPE_NONE, 0);
709
710   signals[PASTE_CLIPBOARD] =
711     g_signal_new (I_("paste_clipboard"),
712                   G_OBJECT_CLASS_TYPE (gobject_class),
713                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
714                   G_STRUCT_OFFSET (GtkEntryClass, paste_clipboard),
715                   NULL, NULL,
716                   _gtk_marshal_VOID__VOID,
717                   G_TYPE_NONE, 0);
718
719   signals[TOGGLE_OVERWRITE] =
720     g_signal_new (I_("toggle_overwrite"),
721                   G_OBJECT_CLASS_TYPE (gobject_class),
722                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
723                   G_STRUCT_OFFSET (GtkEntryClass, toggle_overwrite),
724                   NULL, NULL,
725                   _gtk_marshal_VOID__VOID,
726                   G_TYPE_NONE, 0);
727
728   /*
729    * Key bindings
730    */
731
732   binding_set = gtk_binding_set_by_class (class);
733
734   /* Moving the insertion point */
735   add_move_binding (binding_set, GDK_Right, 0,
736                     GTK_MOVEMENT_VISUAL_POSITIONS, 1);
737   
738   add_move_binding (binding_set, GDK_Left, 0,
739                     GTK_MOVEMENT_VISUAL_POSITIONS, -1);
740
741   add_move_binding (binding_set, GDK_KP_Right, 0,
742                     GTK_MOVEMENT_VISUAL_POSITIONS, 1);
743   
744   add_move_binding (binding_set, GDK_KP_Left, 0,
745                     GTK_MOVEMENT_VISUAL_POSITIONS, -1);
746   
747   add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
748                     GTK_MOVEMENT_WORDS, 1);
749
750   add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
751                     GTK_MOVEMENT_WORDS, -1);
752
753   add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
754                     GTK_MOVEMENT_WORDS, 1);
755
756   add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
757                     GTK_MOVEMENT_WORDS, -1);
758   
759   add_move_binding (binding_set, GDK_Home, 0,
760                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
761
762   add_move_binding (binding_set, GDK_End, 0,
763                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
764
765   add_move_binding (binding_set, GDK_KP_Home, 0,
766                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
767
768   add_move_binding (binding_set, GDK_KP_End, 0,
769                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
770   
771   add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
772                     GTK_MOVEMENT_BUFFER_ENDS, -1);
773
774   add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
775                     GTK_MOVEMENT_BUFFER_ENDS, 1);
776
777   add_move_binding (binding_set, GDK_KP_Home, GDK_CONTROL_MASK,
778                     GTK_MOVEMENT_BUFFER_ENDS, -1);
779
780   add_move_binding (binding_set, GDK_KP_End, GDK_CONTROL_MASK,
781                     GTK_MOVEMENT_BUFFER_ENDS, 1);
782
783   /* Select all
784    */
785   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK,
786                                 "move_cursor", 3,
787                                 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
788                                 G_TYPE_INT, -1,
789                                 G_TYPE_BOOLEAN, FALSE);
790   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK,
791                                 "move_cursor", 3,
792                                 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
793                                 G_TYPE_INT, 1,
794                                 G_TYPE_BOOLEAN, TRUE);  
795
796   gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK,
797                                 "move_cursor", 3,
798                                 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
799                                 G_TYPE_INT, -1,
800                                 G_TYPE_BOOLEAN, FALSE);
801   gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK,
802                                 "move_cursor", 3,
803                                 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
804                                 G_TYPE_INT, 1,
805                                 G_TYPE_BOOLEAN, TRUE);  
806   /* Unselect all 
807    */
808   gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK,
809                                 "move_cursor", 3,
810                                 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_VISUAL_POSITIONS,
811                                 G_TYPE_INT, 0,
812                                 G_TYPE_BOOLEAN, FALSE);
813   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
814                                 "move_cursor", 3,
815                                 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_VISUAL_POSITIONS,
816                                 G_TYPE_INT, 0,
817                                 G_TYPE_BOOLEAN, FALSE);
818
819   /* Activate
820    */
821   gtk_binding_entry_add_signal (binding_set, GDK_Return, 0,
822                                 "activate", 0);
823   gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0,
824                                 "activate", 0);
825   gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0,
826                                 "activate", 0);
827   
828   /* Deleting text */
829   gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0,
830                                 "delete_from_cursor", 2,
831                                 G_TYPE_ENUM, GTK_DELETE_CHARS,
832                                 G_TYPE_INT, 1);
833
834   gtk_binding_entry_add_signal (binding_set, GDK_KP_Delete, 0,
835                                 "delete_from_cursor", 2,
836                                 G_TYPE_ENUM, GTK_DELETE_CHARS,
837                                 G_TYPE_INT, 1);
838   
839   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0,
840                                 "backspace", 0);
841
842   /* Make this do the same as Backspace, to help with mis-typing */
843   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_SHIFT_MASK,
844                                 "backspace", 0);
845
846   gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_CONTROL_MASK,
847                                 "delete_from_cursor", 2,
848                                 G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
849                                 G_TYPE_INT, 1);
850
851   gtk_binding_entry_add_signal (binding_set, GDK_KP_Delete, GDK_CONTROL_MASK,
852                                 "delete_from_cursor", 2,
853                                 G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
854                                 G_TYPE_INT, 1);
855   
856   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK,
857                                 "delete_from_cursor", 2,
858                                 G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
859                                 G_TYPE_INT, -1);
860
861   /* Cut/copy/paste */
862
863   gtk_binding_entry_add_signal (binding_set, GDK_x, GDK_CONTROL_MASK,
864                                 "cut_clipboard", 0);
865   gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
866                                 "copy_clipboard", 0);
867   gtk_binding_entry_add_signal (binding_set, GDK_v, GDK_CONTROL_MASK,
868                                 "paste_clipboard", 0);
869
870   gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_SHIFT_MASK,
871                                 "cut_clipboard", 0);
872   gtk_binding_entry_add_signal (binding_set, GDK_Insert, GDK_CONTROL_MASK,
873                                 "copy_clipboard", 0);
874   gtk_binding_entry_add_signal (binding_set, GDK_Insert, GDK_SHIFT_MASK,
875                                 "paste_clipboard", 0);
876
877   /* Overwrite */
878   gtk_binding_entry_add_signal (binding_set, GDK_Insert, 0,
879                                 "toggle_overwrite", 0);
880   gtk_binding_entry_add_signal (binding_set, GDK_KP_Insert, 0,
881                                 "toggle_overwrite", 0);
882
883   /**
884    * GtkEntry:inner-border:
885    *
886    * Sets the text area's border between the text and the frame.
887    *
888    * Since: 2.10
889    */
890   gtk_widget_class_install_style_property (widget_class,
891                                            g_param_spec_boxed ("inner-border",
892                                                                P_("Inner Border"),
893                                                                P_("Border between text and frame."),
894                                                                GTK_TYPE_BORDER,
895                                                                GTK_PARAM_READABLE));
896
897    gtk_settings_install_property (g_param_spec_boolean ("gtk-entry-select-on-focus",
898                                                        P_("Select on focus"),
899                                                        P_("Whether to select the contents of an entry when it is focused"),
900                                                        TRUE,
901                                                        GTK_PARAM_READWRITE));
902
903   /**
904    * GtkSettings:gtk-entry-password-hint-timeout:
905    *
906    * How long to show the last input character in hidden
907    * entries. This value is in milliseconds. 0 disables showing the
908    * last char. 600 is a good value for enabling it.
909    *
910    * Since: 2.10
911    */
912   gtk_settings_install_property (g_param_spec_uint ("gtk-entry-password-hint-timeout",
913                                                     P_("Password Hint Timeout"),
914                                                     P_("How long to show the last input character in hidden entries"),
915                                                     0, G_MAXUINT, 0,
916                                                     GTK_PARAM_READWRITE));
917
918   g_type_class_add_private (gobject_class, sizeof (GtkEntryPrivate));
919 }
920
921 static void
922 gtk_entry_editable_init (GtkEditableClass *iface)
923 {
924   iface->do_insert_text = gtk_entry_insert_text;
925   iface->do_delete_text = gtk_entry_delete_text;
926   iface->insert_text = gtk_entry_real_insert_text;
927   iface->delete_text = gtk_entry_real_delete_text;
928   iface->get_chars = gtk_entry_get_chars;
929   iface->set_selection_bounds = gtk_entry_set_selection_bounds;
930   iface->get_selection_bounds = gtk_entry_get_selection_bounds;
931   iface->set_position = gtk_entry_real_set_position;
932   iface->get_position = gtk_entry_get_position;
933 }
934
935 static void
936 gtk_entry_cell_editable_init (GtkCellEditableIface *iface)
937 {
938   iface->start_editing = gtk_entry_start_editing;
939 }
940
941 static void
942 gtk_entry_set_property (GObject         *object,
943                         guint            prop_id,
944                         const GValue    *value,
945                         GParamSpec      *pspec)
946 {
947   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (object);
948   GtkEntry *entry = GTK_ENTRY (object);
949
950   switch (prop_id)
951     {
952     case PROP_EDITABLE:
953       {
954         gboolean new_value = g_value_get_boolean (value);
955
956         if (new_value != entry->editable)
957           {
958             if (!new_value)
959               {
960                 _gtk_entry_reset_im_context (entry);
961                 if (GTK_WIDGET_HAS_FOCUS (entry))
962                   gtk_im_context_focus_out (entry->im_context);
963
964                 entry->preedit_length = 0;
965                 entry->preedit_cursor = 0;
966               }
967
968             entry->editable = new_value;
969
970             if (new_value && GTK_WIDGET_HAS_FOCUS (entry))
971               gtk_im_context_focus_in (entry->im_context);
972             
973             gtk_entry_queue_draw (entry);
974           }
975       }
976       break;
977
978     case PROP_MAX_LENGTH:
979       gtk_entry_set_max_length (entry, g_value_get_int (value));
980       break;
981       
982     case PROP_VISIBILITY:
983       gtk_entry_set_visibility (entry, g_value_get_boolean (value));
984       break;
985
986     case PROP_HAS_FRAME:
987       gtk_entry_set_has_frame (entry, g_value_get_boolean (value));
988       break;
989
990     case PROP_INNER_BORDER:
991       gtk_entry_set_inner_border (entry, g_value_get_boxed (value));
992       break;
993
994     case PROP_INVISIBLE_CHAR:
995       gtk_entry_set_invisible_char (entry, g_value_get_uint (value));
996       break;
997
998     case PROP_ACTIVATES_DEFAULT:
999       gtk_entry_set_activates_default (entry, g_value_get_boolean (value));
1000       break;
1001
1002     case PROP_WIDTH_CHARS:
1003       gtk_entry_set_width_chars (entry, g_value_get_int (value));
1004       break;
1005
1006     case PROP_TEXT:
1007       gtk_entry_set_text (entry, g_value_get_string (value));
1008       break;
1009
1010     case PROP_XALIGN:
1011       gtk_entry_set_alignment (entry, g_value_get_float (value));
1012       break;
1013
1014     case PROP_TRUNCATE_MULTILINE:
1015       entry->truncate_multiline = g_value_get_boolean (value);
1016       break;
1017
1018     case PROP_SHADOW_TYPE:
1019       priv->shadow_type = g_value_get_enum (value);
1020       break;
1021
1022     case PROP_SCROLL_OFFSET:
1023     case PROP_CURSOR_POSITION:
1024     default:
1025       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1026       break;
1027     }
1028 }
1029
1030 static void
1031 gtk_entry_get_property (GObject         *object,
1032                         guint            prop_id,
1033                         GValue          *value,
1034                         GParamSpec      *pspec)
1035 {
1036   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (object);
1037   GtkEntry *entry = GTK_ENTRY (object);
1038
1039   switch (prop_id)
1040     {
1041     case PROP_CURSOR_POSITION:
1042       g_value_set_int (value, entry->current_pos);
1043       break;
1044     case PROP_SELECTION_BOUND:
1045       g_value_set_int (value, entry->selection_bound);
1046       break;
1047     case PROP_EDITABLE:
1048       g_value_set_boolean (value, entry->editable);
1049       break;
1050     case PROP_MAX_LENGTH:
1051       g_value_set_int (value, entry->text_max_length); 
1052       break;
1053     case PROP_VISIBILITY:
1054       g_value_set_boolean (value, entry->visible);
1055       break;
1056     case PROP_HAS_FRAME:
1057       g_value_set_boolean (value, entry->has_frame);
1058       break;
1059     case PROP_INNER_BORDER:
1060       g_value_set_boxed (value, gtk_entry_get_inner_border (entry));
1061       break;
1062     case PROP_INVISIBLE_CHAR:
1063       g_value_set_uint (value, entry->invisible_char);
1064       break;
1065     case PROP_ACTIVATES_DEFAULT:
1066       g_value_set_boolean (value, entry->activates_default);
1067       break;
1068     case PROP_WIDTH_CHARS:
1069       g_value_set_int (value, entry->width_chars);
1070       break;
1071     case PROP_SCROLL_OFFSET:
1072       g_value_set_int (value, entry->scroll_offset);
1073       break;
1074     case PROP_TEXT:
1075       g_value_set_string (value, gtk_entry_get_text (entry));
1076       break;
1077     case PROP_XALIGN:
1078       g_value_set_float (value, gtk_entry_get_alignment (entry));
1079       break;
1080     case PROP_TRUNCATE_MULTILINE:
1081       g_value_set_boolean (value, entry->truncate_multiline);
1082       break;
1083     case PROP_SHADOW_TYPE:
1084       g_value_set_enum (value, priv->shadow_type);
1085       break;
1086
1087     default:
1088       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1089       break;
1090     }
1091 }
1092
1093 static void
1094 gtk_entry_init (GtkEntry *entry)
1095 {
1096   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
1097   
1098   GTK_WIDGET_SET_FLAGS (entry, GTK_CAN_FOCUS);
1099
1100   entry->text_size = MIN_SIZE;
1101   entry->text = g_malloc (entry->text_size);
1102   entry->text[0] = '\0';
1103
1104   entry->editable = TRUE;
1105   entry->visible = TRUE;
1106   entry->invisible_char = '*';
1107   entry->dnd_position = -1;
1108   entry->width_chars = -1;
1109   entry->is_cell_renderer = FALSE;
1110   entry->editing_canceled = FALSE;
1111   entry->has_frame = TRUE;
1112   entry->truncate_multiline = FALSE;
1113   priv->shadow_type = GTK_SHADOW_IN;
1114   priv->xalign = 0.0;
1115
1116   gtk_drag_dest_set (GTK_WIDGET (entry),
1117                      GTK_DEST_DEFAULT_HIGHLIGHT,
1118                      NULL, 0,
1119                      GDK_ACTION_COPY | GDK_ACTION_MOVE);
1120   gtk_drag_dest_add_text_targets (GTK_WIDGET (entry));
1121
1122   /* This object is completely private. No external entity can gain a reference
1123    * to it; so we create it here and destroy it in finalize().
1124    */
1125   entry->im_context = gtk_im_multicontext_new ();
1126   
1127   g_signal_connect (entry->im_context, "commit",
1128                     G_CALLBACK (gtk_entry_commit_cb), entry);
1129   g_signal_connect (entry->im_context, "preedit_changed",
1130                     G_CALLBACK (gtk_entry_preedit_changed_cb), entry);
1131   g_signal_connect (entry->im_context, "retrieve_surrounding",
1132                     G_CALLBACK (gtk_entry_retrieve_surrounding_cb), entry);
1133   g_signal_connect (entry->im_context, "delete_surrounding",
1134                     G_CALLBACK (gtk_entry_delete_surrounding_cb), entry);
1135 }
1136
1137 static void
1138 begin_change (GtkEntry *entry)
1139 {
1140   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
1141
1142   priv->change_count++;
1143 }
1144
1145 static void
1146 end_change (GtkEntry *entry)
1147 {
1148   GtkEditable *editable = GTK_EDITABLE (entry);
1149   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
1150  
1151   g_return_if_fail (priv->change_count > 0);
1152
1153   priv->change_count--;
1154
1155   if (priv->change_count == 0)
1156     {
1157        if (priv->real_changed) 
1158          {
1159            g_signal_emit_by_name (editable, "changed");
1160            priv->real_changed = FALSE;
1161          }
1162     } 
1163 }
1164
1165 static void
1166 emit_changed (GtkEntry *entry)
1167 {
1168   GtkEditable *editable = GTK_EDITABLE (entry);
1169   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
1170
1171   if (priv->change_count == 0)
1172     g_signal_emit_by_name (editable, "changed");
1173   else 
1174     priv->real_changed = TRUE;
1175 }
1176
1177 /*
1178  * Overwrite a memory that might contain sensitive information.
1179  */
1180 static void
1181 trash_area (gchar *area, gsize len)
1182 {
1183   volatile gchar *varea = (volatile gchar *)area;
1184   while (len-- > 0)
1185     *varea++ = 0;
1186 }
1187
1188 static void
1189 gtk_entry_destroy (GtkObject *object)
1190 {
1191   GtkEntry *entry = GTK_ENTRY (object);
1192
1193   entry->n_bytes = 0;
1194   entry->current_pos = entry->selection_bound = entry->text_length = 0;
1195   _gtk_entry_reset_im_context (entry);
1196   gtk_entry_reset_layout (entry);
1197
1198   if (entry->blink_timeout)
1199     {
1200       g_source_remove (entry->blink_timeout);
1201       entry->blink_timeout = 0;
1202     }
1203
1204   if (entry->recompute_idle)
1205     {
1206       g_source_remove (entry->recompute_idle);
1207       entry->recompute_idle = 0;
1208     }
1209
1210   if (!entry->visible)
1211     {
1212       /* We want to trash the text here because the entry might be leaked.  */
1213       trash_area (entry->text, strlen (entry->text));
1214     }
1215
1216   GTK_OBJECT_CLASS (gtk_entry_parent_class)->destroy (object);
1217 }
1218
1219 static void
1220 gtk_entry_finalize (GObject *object)
1221 {
1222   GtkEntry *entry = GTK_ENTRY (object);
1223
1224   gtk_entry_set_completion (entry, NULL);
1225
1226   if (entry->cached_layout)
1227     g_object_unref (entry->cached_layout);
1228
1229   g_object_unref (entry->im_context);
1230
1231   if (entry->blink_timeout)
1232     g_source_remove (entry->blink_timeout);
1233
1234   if (entry->recompute_idle)
1235     g_source_remove (entry->recompute_idle);
1236
1237   entry->text_size = 0;
1238
1239   if (entry->text)
1240     {
1241       if (!entry->visible)
1242         trash_area (entry->text, strlen (entry->text));
1243       g_free (entry->text);
1244       entry->text = NULL;
1245     }
1246
1247   G_OBJECT_CLASS (gtk_entry_parent_class)->finalize (object);
1248 }
1249
1250 static void
1251 gtk_entry_realize (GtkWidget *widget)
1252 {
1253   GtkEntry *entry;
1254   GdkWindowAttr attributes;
1255   gint attributes_mask;
1256
1257   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1258   entry = GTK_ENTRY (widget);
1259
1260   attributes.window_type = GDK_WINDOW_CHILD;
1261   
1262   get_widget_window_size (entry, &attributes.x, &attributes.y, &attributes.width, &attributes.height);
1263
1264   attributes.wclass = GDK_INPUT_OUTPUT;
1265   attributes.visual = gtk_widget_get_visual (widget);
1266   attributes.colormap = gtk_widget_get_colormap (widget);
1267   attributes.event_mask = gtk_widget_get_events (widget);
1268   attributes.event_mask |= (GDK_EXPOSURE_MASK |
1269                             GDK_BUTTON_PRESS_MASK |
1270                             GDK_BUTTON_RELEASE_MASK |
1271                             GDK_BUTTON1_MOTION_MASK |
1272                             GDK_BUTTON3_MOTION_MASK |
1273                             GDK_POINTER_MOTION_HINT_MASK |
1274                             GDK_POINTER_MOTION_MASK |
1275                             GDK_ENTER_NOTIFY_MASK |
1276                             GDK_LEAVE_NOTIFY_MASK);
1277   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1278
1279   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
1280   gdk_window_set_user_data (widget->window, entry);
1281
1282   get_text_area_size (entry, &attributes.x, &attributes.y, &attributes.width, &attributes.height);
1283  
1284   if (GTK_WIDGET_IS_SENSITIVE (widget))
1285     {
1286       attributes.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM);
1287       attributes_mask |= GDK_WA_CURSOR;
1288     }
1289
1290   entry->text_area = gdk_window_new (widget->window, &attributes, attributes_mask);
1291
1292   gdk_window_set_user_data (entry->text_area, entry);
1293
1294   if (attributes_mask & GDK_WA_CURSOR)
1295     gdk_cursor_unref (attributes.cursor);
1296
1297   widget->style = gtk_style_attach (widget->style, widget->window);
1298
1299   gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
1300   gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
1301
1302   gdk_window_show (entry->text_area);
1303
1304   gtk_im_context_set_client_window (entry->im_context, entry->text_area);
1305
1306   gtk_entry_adjust_scroll (entry);
1307   gtk_entry_update_primary_selection (entry);
1308 }
1309
1310 static void
1311 gtk_entry_unrealize (GtkWidget *widget)
1312 {
1313   GtkEntry *entry = GTK_ENTRY (widget);
1314   GtkClipboard *clipboard;
1315
1316   gtk_entry_reset_layout (entry);
1317   
1318   gtk_im_context_set_client_window (entry->im_context, NULL);
1319
1320   clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_PRIMARY);
1321   if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (entry))
1322     gtk_clipboard_clear (clipboard);
1323   
1324   if (entry->text_area)
1325     {
1326       gdk_window_set_user_data (entry->text_area, NULL);
1327       gdk_window_destroy (entry->text_area);
1328       entry->text_area = NULL;
1329     }
1330
1331   if (entry->popup_menu)
1332     {
1333       gtk_widget_destroy (entry->popup_menu);
1334       entry->popup_menu = NULL;
1335     }
1336
1337   if (GTK_WIDGET_CLASS (gtk_entry_parent_class)->unrealize)
1338     (* GTK_WIDGET_CLASS (gtk_entry_parent_class)->unrealize) (widget);
1339 }
1340
1341 void
1342 _gtk_entry_get_borders (GtkEntry *entry,
1343                         gint     *xborder,
1344                         gint     *yborder)
1345 {
1346   GtkWidget *widget = GTK_WIDGET (entry);
1347   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
1348
1349   if (entry->has_frame)
1350     {
1351       *xborder = widget->style->xthickness;
1352       *yborder = widget->style->ythickness;
1353     }
1354   else
1355     {
1356       *xborder = 0;
1357       *yborder = 0;
1358     }
1359
1360   if (!priv->interior_focus)
1361     {
1362       *xborder += priv->focus_width;
1363       *yborder += priv->focus_width;
1364     }
1365 }
1366
1367 static void
1368 gtk_entry_size_request (GtkWidget      *widget,
1369                         GtkRequisition *requisition)
1370 {
1371   GtkEntry *entry = GTK_ENTRY (widget);
1372   PangoFontMetrics *metrics;
1373   gint xborder, yborder;
1374   GtkBorder inner_border;
1375   PangoContext *context;
1376   
1377   gtk_widget_ensure_style (widget);
1378   context = gtk_widget_get_pango_context (widget);
1379   metrics = pango_context_get_metrics (context,
1380                                        widget->style->font_desc,
1381                                        pango_context_get_language (context));
1382
1383   entry->ascent = pango_font_metrics_get_ascent (metrics);
1384   entry->descent = pango_font_metrics_get_descent (metrics);
1385   
1386   _gtk_entry_get_borders (entry, &xborder, &yborder);
1387   _gtk_entry_effective_inner_border (entry, &inner_border);
1388
1389   if (entry->width_chars < 0)
1390     requisition->width = MIN_ENTRY_WIDTH + xborder * 2 + inner_border.left + inner_border.right;
1391   else
1392     {
1393       gint char_width = pango_font_metrics_get_approximate_char_width (metrics);
1394       gint digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
1395       gint char_pixels = (MAX (char_width, digit_width) + PANGO_SCALE - 1) / PANGO_SCALE;
1396       
1397       requisition->width = char_pixels * entry->width_chars + xborder * 2 + inner_border.left + inner_border.right;
1398     }
1399     
1400   requisition->height = PANGO_PIXELS (entry->ascent + entry->descent) + yborder * 2 + inner_border.top + inner_border.bottom;
1401
1402   pango_font_metrics_unref (metrics);
1403 }
1404
1405 static void
1406 get_text_area_size (GtkEntry *entry,
1407                     gint     *x,
1408                     gint     *y,
1409                     gint     *width,
1410                     gint     *height)
1411 {
1412   gint frame_height;
1413   gint xborder, yborder;
1414   GtkRequisition requisition;
1415   GtkWidget *widget = GTK_WIDGET (entry);
1416   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
1417
1418   gtk_widget_get_child_requisition (widget, &requisition);
1419   _gtk_entry_get_borders (entry, &xborder, &yborder);
1420
1421   if (GTK_WIDGET_REALIZED (widget))
1422     gdk_drawable_get_size (widget->window, NULL, &frame_height);
1423   else
1424     frame_height = requisition.height;
1425
1426   if (GTK_WIDGET_HAS_FOCUS (widget) && !priv->interior_focus)
1427       frame_height -= 2 * priv->focus_width;
1428
1429   if (x)
1430     *x = xborder;
1431
1432   if (y)
1433     *y = frame_height / 2 - (requisition.height - yborder * 2) / 2;
1434
1435   if (width)
1436     *width = GTK_WIDGET (entry)->allocation.width - xborder * 2;
1437
1438   if (height)
1439     *height = requisition.height - yborder * 2;
1440 }
1441
1442 static void
1443 get_widget_window_size (GtkEntry *entry,
1444                         gint     *x,
1445                         gint     *y,
1446                         gint     *width,
1447                         gint     *height)
1448 {
1449   GtkRequisition requisition;
1450   GtkWidget *widget = GTK_WIDGET (entry);
1451       
1452   gtk_widget_get_child_requisition (widget, &requisition);
1453
1454   if (x)
1455     *x = widget->allocation.x;
1456
1457   if (y)
1458     {
1459       if (entry->is_cell_renderer)
1460         *y = widget->allocation.y;
1461       else
1462         *y = widget->allocation.y + (widget->allocation.height - requisition.height) / 2;
1463     }
1464
1465   if (width)
1466     *width = widget->allocation.width;
1467
1468   if (height)
1469     {
1470       if (entry->is_cell_renderer)
1471         *height = widget->allocation.height;
1472       else
1473         *height = requisition.height;
1474     }
1475 }
1476
1477 void
1478 _gtk_entry_effective_inner_border (GtkEntry  *entry,
1479                                    GtkBorder *border)
1480 {
1481   GtkBorder *tmp_border;
1482
1483   tmp_border = g_object_get_qdata (G_OBJECT (entry), quark_inner_border);
1484
1485   if (tmp_border)
1486     {
1487       *border = *tmp_border;
1488       return;
1489     }
1490
1491   gtk_widget_style_get (GTK_WIDGET (entry), "inner-border", &tmp_border, NULL);
1492
1493   if (tmp_border)
1494     {
1495       *border = *tmp_border;
1496       gtk_border_free (tmp_border);
1497       return;
1498     }
1499
1500   *border = default_inner_border;
1501 }
1502
1503 static void
1504 gtk_entry_size_allocate (GtkWidget     *widget,
1505                          GtkAllocation *allocation)
1506 {
1507   GtkEntry *entry = GTK_ENTRY (widget);
1508   
1509   widget->allocation = *allocation;
1510   
1511   if (GTK_WIDGET_REALIZED (widget))
1512     {
1513       /* We call gtk_widget_get_child_requisition, since we want (for
1514        * backwards compatibility reasons) the realization here to
1515        * be affected by the usize of the entry, if set
1516        */
1517       gint x, y, width, height;
1518
1519       get_widget_window_size (entry, &x, &y, &width, &height);
1520       
1521       gdk_window_move_resize (widget->window,
1522                               x, y, width, height);   
1523
1524       get_text_area_size (entry, &x, &y, &width, &height);
1525       
1526       gdk_window_move_resize (entry->text_area,
1527                               x, y, width, height);
1528
1529       gtk_entry_recompute (entry);
1530     }
1531 }
1532
1533 static void
1534 gtk_entry_draw_frame (GtkWidget    *widget,
1535                       GdkRectangle *area)
1536 {
1537   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
1538   gint x = 0, y = 0, width, height;
1539   
1540   gdk_drawable_get_size (widget->window, &width, &height);
1541   
1542   if (GTK_WIDGET_HAS_FOCUS (widget) && !priv->interior_focus)
1543     {
1544       x += priv->focus_width;
1545       y += priv->focus_width;
1546       width -= 2 * priv->focus_width;
1547       height -= 2 * priv->focus_width;
1548     }
1549
1550   gtk_paint_shadow (widget->style, widget->window,
1551                     GTK_STATE_NORMAL, priv->shadow_type,
1552                     area, widget, "entry", x, y, width, height);
1553
1554   if (GTK_WIDGET_HAS_FOCUS (widget) && !priv->interior_focus)
1555     {
1556       x -= priv->focus_width;
1557       y -= priv->focus_width;
1558       width += 2 * priv->focus_width;
1559       height += 2 * priv->focus_width;
1560       
1561       gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget), 
1562                        area, widget, "entry",
1563                        0, 0, width, height);
1564     }
1565 }
1566
1567 static gint
1568 gtk_entry_expose (GtkWidget      *widget,
1569                   GdkEventExpose *event)
1570 {
1571   GtkEntry *entry = GTK_ENTRY (widget);
1572
1573   if (widget->window == event->window)
1574     gtk_entry_draw_frame (widget, &event->area);
1575   else if (entry->text_area == event->window)
1576     {
1577       gint area_width, area_height;
1578
1579       get_text_area_size (entry, NULL, NULL, &area_width, &area_height);
1580
1581       gtk_paint_flat_box (widget->style, entry->text_area, 
1582                           GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
1583                           &event->area, widget, "entry_bg",
1584                           0, 0, area_width, area_height);
1585
1586       if (entry->dnd_position != -1)
1587         gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_DND);
1588       
1589       gtk_entry_draw_text (GTK_ENTRY (widget));
1590
1591       if ((entry->visible || entry->invisible_char != 0) &&
1592           GTK_WIDGET_HAS_FOCUS (widget) &&
1593           entry->selection_bound == entry->current_pos && entry->cursor_visible)
1594         gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_STANDARD);
1595     }
1596
1597   return FALSE;
1598 }
1599
1600 static void
1601 gtk_entry_get_pixel_ranges (GtkEntry  *entry,
1602                             gint     **ranges,
1603                             gint      *n_ranges)
1604 {
1605   gint start_char, end_char;
1606
1607   if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_char, &end_char))
1608     {
1609       PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
1610       PangoLayoutLine *line = pango_layout_get_lines_readonly (layout)->data;
1611       const char *text = pango_layout_get_text (layout);
1612       gint start_index = g_utf8_offset_to_pointer (text, start_char) - text;
1613       gint end_index = g_utf8_offset_to_pointer (text, end_char) - text;
1614       gint real_n_ranges, i;
1615
1616       pango_layout_line_get_x_ranges (line, start_index, end_index, ranges, &real_n_ranges);
1617
1618       if (ranges)
1619         {
1620           gint *r = *ranges;
1621           
1622           for (i = 0; i < real_n_ranges; ++i)
1623             {
1624               r[2 * i + 1] = (r[2 * i + 1] - r[2 * i]) / PANGO_SCALE;
1625               r[2 * i] = r[2 * i] / PANGO_SCALE;
1626             }
1627         }
1628       
1629       if (n_ranges)
1630         *n_ranges = real_n_ranges;
1631     }
1632   else
1633     {
1634       if (n_ranges)
1635         *n_ranges = 0;
1636       if (ranges)
1637         *ranges = NULL;
1638     }
1639 }
1640
1641 static gboolean
1642 in_selection (GtkEntry *entry,
1643               gint      x)
1644 {
1645   gint *ranges;
1646   gint n_ranges, i;
1647   gint retval = FALSE;
1648
1649   gtk_entry_get_pixel_ranges (entry, &ranges, &n_ranges);
1650
1651   for (i = 0; i < n_ranges; ++i)
1652     {
1653       if (x >= ranges[2 * i] && x < ranges[2 * i] + ranges[2 * i + 1])
1654         {
1655           retval = TRUE;
1656           break;
1657         }
1658     }
1659
1660   g_free (ranges);
1661   return retval;
1662 }
1663               
1664 static gint
1665 gtk_entry_button_press (GtkWidget      *widget,
1666                         GdkEventButton *event)
1667 {
1668   GtkEntry *entry = GTK_ENTRY (widget);
1669   GtkEditable *editable = GTK_EDITABLE (widget);
1670   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
1671   gint tmp_pos;
1672   gint sel_start, sel_end;
1673
1674   if (event->window != entry->text_area ||
1675       (entry->button && event->button != entry->button))
1676     return FALSE;
1677
1678   gtk_entry_reset_blink_time (entry);
1679
1680   entry->button = event->button;
1681   
1682   if (!GTK_WIDGET_HAS_FOCUS (widget))
1683     {
1684       entry->in_click = TRUE;
1685       gtk_widget_grab_focus (widget);
1686       entry->in_click = FALSE;
1687     }
1688   
1689   tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
1690     
1691   if (event->button == 1)
1692     {
1693       gboolean have_selection = gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end);
1694       
1695       entry->select_words = FALSE;
1696       entry->select_lines = FALSE;
1697
1698       if (event->state & GDK_SHIFT_MASK)
1699         {
1700           _gtk_entry_reset_im_context (entry);
1701           
1702           if (!have_selection) /* select from the current position to the clicked position */
1703             sel_start = sel_end = entry->current_pos;
1704           
1705           if (tmp_pos > sel_start && tmp_pos < sel_end)
1706             {
1707               /* Truncate current selection, but keep it as big as possible */
1708               if (tmp_pos - sel_start > sel_end - tmp_pos)
1709                 gtk_entry_set_positions (entry, sel_start, tmp_pos);
1710               else
1711                 gtk_entry_set_positions (entry, tmp_pos, sel_end);
1712             }
1713           else
1714             {
1715               gboolean extend_to_left;
1716               gint start, end;
1717
1718               /* Figure out what click selects and extend current selection */
1719               switch (event->type)
1720                 {
1721                 case GDK_BUTTON_PRESS:
1722                   gtk_entry_set_positions (entry, tmp_pos, tmp_pos);
1723                   break;
1724                   
1725                 case GDK_2BUTTON_PRESS:
1726                   entry->select_words = TRUE;
1727                   gtk_entry_select_word (entry);
1728                   break;
1729                   
1730                 case GDK_3BUTTON_PRESS:
1731                   entry->select_lines = TRUE;
1732                   gtk_entry_select_line (entry);
1733                   break;
1734
1735                 default:
1736                   break;
1737                 }
1738
1739               start = MIN (entry->current_pos, entry->selection_bound);
1740               start = MIN (sel_start, start);
1741               
1742               end = MAX (entry->current_pos, entry->selection_bound);
1743               end = MAX (sel_end, end);
1744
1745               if (tmp_pos == sel_start || tmp_pos == sel_end)
1746                 extend_to_left = (tmp_pos == start);
1747               else
1748                 extend_to_left = (end == sel_end);
1749               
1750               if (extend_to_left)
1751                 gtk_entry_set_positions (entry, start, end);
1752               else
1753                 gtk_entry_set_positions (entry, end, start);
1754             }
1755         }
1756       else /* no shift key */
1757         switch (event->type)
1758         {
1759         case GDK_BUTTON_PRESS:
1760           if (in_selection (entry, event->x + entry->scroll_offset))
1761             {
1762               /* Click inside the selection - we'll either start a drag, or
1763                * clear the selection
1764                */
1765               entry->in_drag = TRUE;
1766               entry->drag_start_x = event->x + entry->scroll_offset;
1767               entry->drag_start_y = event->y;
1768             }
1769           else
1770             gtk_editable_set_position (editable, tmp_pos);
1771           break;
1772  
1773         case GDK_2BUTTON_PRESS:
1774           /* We ALWAYS receive a GDK_BUTTON_PRESS immediately before 
1775            * receiving a GDK_2BUTTON_PRESS so we need to reset
1776            * entry->in_drag which may have been set above
1777            */
1778           entry->in_drag = FALSE;
1779           entry->select_words = TRUE;
1780           gtk_entry_select_word (entry);
1781           break;
1782         
1783         case GDK_3BUTTON_PRESS:
1784           /* We ALWAYS receive a GDK_BUTTON_PRESS immediately before
1785            * receiving a GDK_3BUTTON_PRESS so we need to reset
1786            * entry->in_drag which may have been set above
1787            */
1788           entry->in_drag = FALSE;
1789           entry->select_lines = TRUE;
1790           gtk_entry_select_line (entry);
1791           break;
1792
1793         default:
1794           break;
1795         }
1796
1797       return TRUE;
1798     }
1799   else if (event->button == 2 && event->type == GDK_BUTTON_PRESS)
1800     {
1801       if (entry->editable)
1802         {
1803           priv->insert_pos = tmp_pos;
1804           gtk_entry_paste (entry, GDK_SELECTION_PRIMARY);
1805           return TRUE;
1806         }
1807       else
1808         {
1809           gtk_widget_error_bell (widget);
1810         }
1811     }
1812   else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
1813     {
1814       gtk_entry_do_popup (entry, event);
1815       entry->button = 0;        /* Don't wait for release, since the menu will gtk_grab_add */
1816
1817       return TRUE;
1818     }
1819
1820   return FALSE;
1821 }
1822
1823 static gint
1824 gtk_entry_button_release (GtkWidget      *widget,
1825                           GdkEventButton *event)
1826 {
1827   GtkEntry *entry = GTK_ENTRY (widget);
1828
1829   if (event->window != entry->text_area || entry->button != event->button)
1830     return FALSE;
1831
1832   if (entry->in_drag)
1833     {
1834       gint tmp_pos = gtk_entry_find_position (entry, entry->drag_start_x);
1835
1836       gtk_editable_set_position (GTK_EDITABLE (entry), tmp_pos);
1837
1838       entry->in_drag = 0;
1839     }
1840   
1841   entry->button = 0;
1842   
1843   gtk_entry_update_primary_selection (entry);
1844               
1845   return TRUE;
1846 }
1847
1848 static gchar *
1849 _gtk_entry_get_selected_text (GtkEntry *entry)
1850 {
1851   GtkEditable *editable = GTK_EDITABLE (entry);
1852   gint         start_text, end_text;
1853   gchar       *text = NULL;
1854
1855   if (gtk_editable_get_selection_bounds (editable, &start_text, &end_text))
1856     text = gtk_editable_get_chars (editable, start_text, end_text);
1857
1858   return text;
1859 }
1860
1861 static void
1862 drag_begin_cb (GtkWidget      *widget,
1863                GdkDragContext *context,
1864                gpointer        data)
1865 {
1866   g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
1867 }
1868
1869 static gint
1870 gtk_entry_motion_notify (GtkWidget      *widget,
1871                          GdkEventMotion *event)
1872 {
1873   GtkEntry *entry = GTK_ENTRY (widget);
1874   gint tmp_pos;
1875
1876   if (entry->mouse_cursor_obscured)
1877     {
1878       GdkCursor *cursor;
1879       
1880       cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM);
1881       gdk_window_set_cursor (entry->text_area, cursor);
1882       gdk_cursor_unref (cursor);
1883       entry->mouse_cursor_obscured = FALSE;
1884     }
1885
1886   if (event->window != entry->text_area || entry->button != 1)
1887     return FALSE;
1888
1889   if (entry->select_lines)
1890     return TRUE;
1891
1892   gdk_event_request_motions (event);
1893
1894   if (entry->in_drag)
1895     {
1896       if (gtk_drag_check_threshold (widget,
1897                                     entry->drag_start_x, entry->drag_start_y,
1898                                     event->x + entry->scroll_offset, event->y))
1899         {
1900           GdkDragContext *context;
1901           GtkTargetList  *target_list = gtk_target_list_new (NULL, 0);
1902           guint actions = entry->editable ? GDK_ACTION_COPY | GDK_ACTION_MOVE : GDK_ACTION_COPY;
1903           gchar *text = NULL;
1904           GdkPixmap *pixmap = NULL;
1905
1906           gtk_target_list_add_text_targets (target_list, 0);
1907
1908           if (entry->visible)
1909             {
1910               text = _gtk_entry_get_selected_text (entry);
1911               pixmap = _gtk_text_util_create_drag_icon (widget, text, -1);
1912             }
1913
1914           context = gtk_drag_begin (widget, target_list, actions,
1915                                     entry->button, (GdkEvent *)event);
1916           
1917           if (pixmap)
1918             gtk_drag_set_icon_pixmap (context,
1919                                       gdk_drawable_get_colormap (pixmap),
1920                                       pixmap,
1921                                       NULL,
1922                                       -2, -2);
1923           else
1924             gtk_drag_set_icon_default (context);
1925           
1926           if (pixmap)
1927             g_object_unref (pixmap);
1928           g_free (text);
1929
1930           entry->in_drag = FALSE;
1931           entry->button = 0;
1932           
1933           gtk_target_list_unref (target_list);
1934         }
1935     }
1936   else
1937     {
1938       gint height;
1939       gdk_drawable_get_size (entry->text_area, NULL, &height);
1940
1941       if (event->y < 0)
1942         tmp_pos = 0;
1943       else if (event->y >= height)
1944         tmp_pos = entry->text_length;
1945       else
1946         tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
1947       
1948       if (entry->select_words) 
1949         {
1950           gint min, max;
1951           gint old_min, old_max;
1952           gint pos, bound;
1953           
1954           min = gtk_entry_move_backward_word (entry, tmp_pos, TRUE);
1955           max = gtk_entry_move_forward_word (entry, tmp_pos, TRUE);
1956           
1957           pos = entry->current_pos;
1958           bound = entry->selection_bound;
1959
1960           old_min = MIN(entry->current_pos, entry->selection_bound);
1961           old_max = MAX(entry->current_pos, entry->selection_bound);
1962           
1963           if (min < old_min)
1964             {
1965               pos = min;
1966               bound = old_max;
1967             }
1968           else if (old_max < max) 
1969             {
1970               pos = max;
1971               bound = old_min;
1972             }
1973           else if (pos == old_min) 
1974             {
1975               if (entry->current_pos != min)
1976                 pos = max;
1977             }
1978           else 
1979             {
1980               if (entry->current_pos != max)
1981                 pos = min;
1982             }
1983         
1984           gtk_entry_set_positions (entry, pos, bound);
1985         }
1986       else
1987       gtk_entry_set_positions (entry, tmp_pos, -1);
1988     }
1989       
1990   return TRUE;
1991 }
1992
1993 static void
1994 set_invisible_cursor (GdkWindow *window)
1995 {
1996   GdkBitmap *empty_bitmap;
1997   GdkCursor *cursor;
1998   GdkColor useless;
1999   char invisible_cursor_bits[] = { 0x0 };       
2000         
2001   useless.red = useless.green = useless.blue = 0;
2002   useless.pixel = 0;
2003   
2004   empty_bitmap = gdk_bitmap_create_from_data (window,
2005                                               invisible_cursor_bits,
2006                                               1, 1);
2007   
2008   cursor = gdk_cursor_new_from_pixmap (empty_bitmap,
2009                                        empty_bitmap,
2010                                        &useless,
2011                                        &useless, 0, 0);
2012   
2013   gdk_window_set_cursor (window, cursor);
2014   
2015   gdk_cursor_unref (cursor);
2016   
2017   g_object_unref (empty_bitmap);
2018 }
2019
2020 static void
2021 gtk_entry_obscure_mouse_cursor (GtkEntry *entry)
2022 {
2023   if (entry->mouse_cursor_obscured)
2024     return;
2025
2026   set_invisible_cursor (entry->text_area);
2027   
2028   entry->mouse_cursor_obscured = TRUE;  
2029 }
2030
2031 static gint
2032 gtk_entry_key_press (GtkWidget   *widget,
2033                      GdkEventKey *event)
2034 {
2035   GtkEntry *entry = GTK_ENTRY (widget);
2036
2037   gtk_entry_reset_blink_time (entry);
2038   gtk_entry_pend_cursor_blink (entry);
2039
2040   if (entry->editable)
2041     {
2042       if (gtk_im_context_filter_keypress (entry->im_context, event))
2043         {
2044           gtk_entry_obscure_mouse_cursor (entry);
2045           entry->need_im_reset = TRUE;
2046           return TRUE;
2047         }
2048     }
2049
2050   if (event->keyval == GDK_Return || 
2051       event->keyval == GDK_KP_Enter || 
2052       event->keyval == GDK_ISO_Enter || 
2053       event->keyval == GDK_Escape)
2054     {
2055       GtkEntryCompletion *completion = gtk_entry_get_completion (entry);
2056       
2057       if (completion && completion->priv->completion_timeout)
2058         {
2059           g_source_remove (completion->priv->completion_timeout);
2060           completion->priv->completion_timeout = 0;
2061         }
2062
2063       _gtk_entry_reset_im_context (entry);
2064     }
2065
2066   if (GTK_WIDGET_CLASS (gtk_entry_parent_class)->key_press_event (widget, event))
2067     /* Activate key bindings
2068      */
2069     return TRUE;
2070
2071   if (!entry->editable && event->length)
2072     gtk_widget_error_bell (widget);
2073
2074   return FALSE;
2075 }
2076
2077 static gint
2078 gtk_entry_key_release (GtkWidget   *widget,
2079                        GdkEventKey *event)
2080 {
2081   GtkEntry *entry = GTK_ENTRY (widget);
2082
2083   if (entry->editable)
2084     {
2085       if (gtk_im_context_filter_keypress (entry->im_context, event))
2086         {
2087           entry->need_im_reset = TRUE;
2088           return TRUE;
2089         }
2090     }
2091
2092   return GTK_WIDGET_CLASS (gtk_entry_parent_class)->key_release_event (widget, event);
2093 }
2094
2095 static gint
2096 gtk_entry_focus_in (GtkWidget     *widget,
2097                     GdkEventFocus *event)
2098 {
2099   GtkEntry *entry = GTK_ENTRY (widget);
2100   
2101   gtk_widget_queue_draw (widget);
2102   
2103   if (entry->editable)
2104     {
2105       entry->need_im_reset = TRUE;
2106       gtk_im_context_focus_in (entry->im_context);
2107     }
2108
2109   g_signal_connect (gdk_keymap_get_for_display (gtk_widget_get_display (widget)),
2110                     "direction_changed",
2111                     G_CALLBACK (gtk_entry_keymap_direction_changed), entry);
2112
2113   gtk_entry_reset_blink_time (entry);
2114   gtk_entry_check_cursor_blink (entry);
2115
2116   return FALSE;
2117 }
2118
2119 static gint
2120 gtk_entry_focus_out (GtkWidget     *widget,
2121                      GdkEventFocus *event)
2122 {
2123   GtkEntry *entry = GTK_ENTRY (widget);
2124   GtkEntryCompletion *completion;
2125   
2126   gtk_widget_queue_draw (widget);
2127
2128   if (entry->editable)
2129     {
2130       entry->need_im_reset = TRUE;
2131       gtk_im_context_focus_out (entry->im_context);
2132     }
2133
2134   gtk_entry_check_cursor_blink (entry);
2135   
2136   g_signal_handlers_disconnect_by_func (gdk_keymap_get_for_display (gtk_widget_get_display (widget)),
2137                                         gtk_entry_keymap_direction_changed,
2138                                         entry);
2139
2140   completion = gtk_entry_get_completion (entry);
2141   if (completion)
2142     _gtk_entry_completion_popdown (completion);
2143   
2144   return FALSE;
2145 }
2146
2147 static void
2148 gtk_entry_grab_focus (GtkWidget        *widget)
2149 {
2150   GtkEntry *entry = GTK_ENTRY (widget);
2151   gboolean select_on_focus;
2152   
2153   GTK_WIDGET_CLASS (gtk_entry_parent_class)->grab_focus (widget);
2154
2155   if (entry->editable && !entry->in_click)
2156     {
2157       g_object_get (gtk_widget_get_settings (widget),
2158                     "gtk-entry-select-on-focus",
2159                     &select_on_focus,
2160                     NULL);
2161   
2162       if (select_on_focus)
2163         gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
2164     }
2165 }
2166
2167 static void 
2168 gtk_entry_direction_changed (GtkWidget        *widget,
2169                              GtkTextDirection  previous_dir)
2170 {
2171   GtkEntry *entry = GTK_ENTRY (widget);
2172
2173   gtk_entry_recompute (entry);
2174       
2175   GTK_WIDGET_CLASS (gtk_entry_parent_class)->direction_changed (widget, previous_dir);
2176 }
2177
2178 static void
2179 gtk_entry_state_changed (GtkWidget      *widget,
2180                          GtkStateType    previous_state)
2181 {
2182   GtkEntry *entry = GTK_ENTRY (widget);
2183   GdkCursor *cursor;
2184   
2185   if (GTK_WIDGET_REALIZED (widget))
2186     {
2187       gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2188       gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2189
2190       if (GTK_WIDGET_IS_SENSITIVE (widget))
2191         cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM);
2192       else 
2193         cursor = NULL;
2194       
2195       gdk_window_set_cursor (entry->text_area, cursor);
2196
2197       if (cursor)
2198         gdk_cursor_unref (cursor);
2199
2200       entry->mouse_cursor_obscured = FALSE;
2201     }
2202
2203   if (!GTK_WIDGET_IS_SENSITIVE (widget))
2204     {
2205       /* Clear any selection */
2206       gtk_editable_select_region (GTK_EDITABLE (entry), entry->current_pos, entry->current_pos);      
2207     }
2208   
2209   gtk_widget_queue_draw (widget);
2210 }
2211
2212 static void
2213 gtk_entry_screen_changed (GtkWidget *widget,
2214                           GdkScreen *old_screen)
2215 {
2216   gtk_entry_recompute (GTK_ENTRY (widget));
2217 }
2218
2219 /* GtkEditable method implementations
2220  */
2221 static void
2222 gtk_entry_insert_text (GtkEditable *editable,
2223                        const gchar *new_text,
2224                        gint         new_text_length,
2225                        gint        *position)
2226 {
2227   GtkEntry *entry = GTK_ENTRY (editable);
2228   gchar buf[64];
2229   gchar *text;
2230
2231   if (*position < 0 || *position > entry->text_length)
2232     *position = entry->text_length;
2233   
2234   g_object_ref (editable);
2235   
2236   if (new_text_length <= 63)
2237     text = buf;
2238   else
2239     text = g_new (gchar, new_text_length + 1);
2240
2241   text[new_text_length] = '\0';
2242   strncpy (text, new_text, new_text_length);
2243
2244   g_signal_emit_by_name (editable, "insert_text", text, new_text_length, position);
2245
2246   if (!entry->visible)
2247     trash_area (text, new_text_length);
2248
2249   if (new_text_length > 63)
2250     g_free (text);
2251
2252   g_object_unref (editable);
2253 }
2254
2255 static void
2256 gtk_entry_delete_text (GtkEditable *editable,
2257                        gint         start_pos,
2258                        gint         end_pos)
2259 {
2260   GtkEntry *entry = GTK_ENTRY (editable);
2261
2262   if (end_pos < 0 || end_pos > entry->text_length)
2263     end_pos = entry->text_length;
2264   if (start_pos < 0)
2265     start_pos = 0;
2266   if (start_pos > end_pos)
2267     start_pos = end_pos;
2268   
2269   g_object_ref (editable);
2270
2271   g_signal_emit_by_name (editable, "delete_text", start_pos, end_pos);
2272
2273   g_object_unref (editable);
2274 }
2275
2276 static gchar *    
2277 gtk_entry_get_chars      (GtkEditable   *editable,
2278                           gint           start_pos,
2279                           gint           end_pos)
2280 {
2281   GtkEntry *entry = GTK_ENTRY (editable);
2282   gint start_index, end_index;
2283   
2284   if (end_pos < 0)
2285     end_pos = entry->text_length;
2286
2287   start_pos = MIN (entry->text_length, start_pos);
2288   end_pos = MIN (entry->text_length, end_pos);
2289
2290   start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text;
2291   end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text;
2292
2293   return g_strndup (entry->text + start_index, end_index - start_index);
2294 }
2295
2296 static void
2297 gtk_entry_real_set_position (GtkEditable *editable,
2298                              gint         position)
2299 {
2300   GtkEntry *entry = GTK_ENTRY (editable);
2301
2302   if (position < 0 || position > entry->text_length)
2303     position = entry->text_length;
2304
2305   if (position != entry->current_pos ||
2306       position != entry->selection_bound)
2307     {
2308       _gtk_entry_reset_im_context (entry);
2309       gtk_entry_set_positions (entry, position, position);
2310     }
2311 }
2312
2313 static gint
2314 gtk_entry_get_position (GtkEditable *editable)
2315 {
2316   return GTK_ENTRY (editable)->current_pos;
2317 }
2318
2319 static void
2320 gtk_entry_set_selection_bounds (GtkEditable *editable,
2321                                 gint         start,
2322                                 gint         end)
2323 {
2324   GtkEntry *entry = GTK_ENTRY (editable);
2325
2326   if (start < 0)
2327     start = entry->text_length;
2328   if (end < 0)
2329     end = entry->text_length;
2330   
2331   _gtk_entry_reset_im_context (entry);
2332
2333   gtk_entry_set_positions (entry,
2334                            MIN (end, entry->text_length),
2335                            MIN (start, entry->text_length));
2336
2337   gtk_entry_update_primary_selection (entry);
2338 }
2339
2340 static gboolean
2341 gtk_entry_get_selection_bounds (GtkEditable *editable,
2342                                 gint        *start,
2343                                 gint        *end)
2344 {
2345   GtkEntry *entry = GTK_ENTRY (editable);
2346
2347   *start = entry->selection_bound;
2348   *end = entry->current_pos;
2349
2350   return (entry->selection_bound != entry->current_pos);
2351 }
2352
2353 static void 
2354 gtk_entry_style_set     (GtkWidget      *widget,
2355                          GtkStyle       *previous_style)
2356 {
2357   GtkEntry *entry = GTK_ENTRY (widget);
2358   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2359   gint focus_width;
2360   gboolean interior_focus;
2361
2362   gtk_widget_style_get (widget,
2363                         "focus-line-width", &focus_width,
2364                         "interior-focus", &interior_focus,
2365                         NULL);
2366
2367   priv->focus_width = focus_width;
2368   priv->interior_focus = interior_focus;
2369   
2370   gtk_entry_recompute (entry);
2371
2372   if (previous_style && GTK_WIDGET_REALIZED (widget))
2373     {
2374       gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2375       gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2376     }
2377 }
2378
2379 /* GtkCellEditable method implementations
2380  */
2381 static void
2382 gtk_cell_editable_entry_activated (GtkEntry *entry, gpointer data)
2383 {
2384   gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry));
2385   gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry));
2386 }
2387
2388 static gboolean
2389 gtk_cell_editable_key_press_event (GtkEntry    *entry,
2390                                    GdkEventKey *key_event,
2391                                    gpointer     data)
2392 {
2393   if (key_event->keyval == GDK_Escape)
2394     {
2395       entry->editing_canceled = TRUE;
2396       gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry));
2397       gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry));
2398
2399       return TRUE;
2400     }
2401
2402   /* override focus */
2403   if (key_event->keyval == GDK_Up || key_event->keyval == GDK_Down)
2404     {
2405       gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry));
2406       gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry));
2407
2408       return TRUE;
2409     }
2410
2411   return FALSE;
2412 }
2413
2414 static void
2415 gtk_entry_start_editing (GtkCellEditable *cell_editable,
2416                          GdkEvent        *event)
2417 {
2418   GTK_ENTRY (cell_editable)->is_cell_renderer = TRUE;
2419
2420   g_signal_connect (cell_editable, "activate",
2421                     G_CALLBACK (gtk_cell_editable_entry_activated), NULL);
2422   g_signal_connect (cell_editable, "key_press_event",
2423                     G_CALLBACK (gtk_cell_editable_key_press_event), NULL);
2424 }
2425
2426 static void
2427 gtk_entry_password_hint_free (GtkEntryPasswordHint *password_hint)
2428 {
2429   if (password_hint->password_hint_timeout_id)
2430     g_source_remove (password_hint->password_hint_timeout_id);
2431
2432   g_free (password_hint);
2433 }
2434
2435 /* Default signal handlers
2436  */
2437 static void
2438 gtk_entry_real_insert_text (GtkEditable *editable,
2439                             const gchar *new_text,
2440                             gint         new_text_length,
2441                             gint        *position)
2442 {
2443   GtkEntry *entry = GTK_ENTRY (editable);
2444   gint index;
2445   gint n_chars;
2446
2447   if (new_text_length < 0)
2448     new_text_length = strlen (new_text);
2449
2450   n_chars = g_utf8_strlen (new_text, new_text_length);
2451   if (entry->text_max_length > 0 && n_chars + entry->text_length > entry->text_max_length)
2452     {
2453       gtk_widget_error_bell (GTK_WIDGET (entry));
2454       n_chars = entry->text_max_length - entry->text_length;
2455       new_text_length = g_utf8_offset_to_pointer (new_text, n_chars) - new_text;
2456     }
2457
2458   if (new_text_length + entry->n_bytes + 1 > entry->text_size)
2459     {
2460       gsize prev_size = entry->text_size;
2461
2462       while (new_text_length + entry->n_bytes + 1 > entry->text_size)
2463         {
2464           if (entry->text_size == 0)
2465             entry->text_size = MIN_SIZE;
2466           else
2467             {
2468               if (2 * (guint)entry->text_size < MAX_SIZE &&
2469                   2 * (guint)entry->text_size > entry->text_size)
2470                 entry->text_size *= 2;
2471               else
2472                 {
2473                   entry->text_size = MAX_SIZE;
2474                   if (new_text_length > (gint)entry->text_size - (gint)entry->n_bytes - 1)
2475                     {
2476                       new_text_length = (gint)entry->text_size - (gint)entry->n_bytes - 1;
2477                       new_text_length = g_utf8_find_prev_char (new_text, new_text + new_text_length + 1) - new_text;
2478                       n_chars = g_utf8_strlen (new_text, new_text_length);
2479                     }
2480                   break;
2481                 }
2482             }
2483         }
2484
2485       if (entry->visible)
2486         entry->text = g_realloc (entry->text, entry->text_size);
2487       else
2488         {
2489           /* Same thing, just slower and without leaving stuff in memory.  */
2490           gchar *et_new = g_malloc (entry->text_size);
2491           memcpy (et_new, entry->text, MIN (prev_size, entry->text_size));
2492           trash_area (entry->text, prev_size);
2493           g_free (entry->text);
2494           entry->text = et_new;
2495         }
2496     }
2497
2498   index = g_utf8_offset_to_pointer (entry->text, *position) - entry->text;
2499
2500   g_memmove (entry->text + index + new_text_length, entry->text + index, entry->n_bytes - index);
2501   memcpy (entry->text + index, new_text, new_text_length);
2502
2503   entry->n_bytes += new_text_length;
2504   entry->text_length += n_chars;
2505
2506   /* NUL terminate for safety and convenience */
2507   entry->text[entry->n_bytes] = '\0';
2508   
2509   if (entry->current_pos > *position)
2510     entry->current_pos += n_chars;
2511   
2512   if (entry->selection_bound > *position)
2513     entry->selection_bound += n_chars;
2514
2515   if (n_chars == 1 && !entry->visible && (new_text_length < PASSWORD_HINT_MAX))
2516     {
2517       guint password_hint_timeout;
2518
2519       g_object_get (gtk_widget_get_settings (GTK_WIDGET (entry)),
2520                     "gtk-entry-password-hint-timeout", &password_hint_timeout,
2521                     NULL);
2522
2523       if (password_hint_timeout > 0)
2524         {
2525           GtkEntryPasswordHint *password_hint = g_object_get_qdata (G_OBJECT (entry),
2526                                                                     quark_password_hint);
2527
2528           if (!password_hint)
2529             {
2530               password_hint = g_new0 (GtkEntryPasswordHint, 1);
2531               g_object_set_qdata_full (G_OBJECT (entry), quark_password_hint,
2532                                        password_hint,
2533                                        (GDestroyNotify) gtk_entry_password_hint_free);
2534             }
2535
2536           memset (&password_hint->password_hint, 0x0, PASSWORD_HINT_MAX);
2537           password_hint->password_hint_length = new_text_length;
2538           memcpy (&password_hint->password_hint, new_text, new_text_length);
2539           password_hint->password_hint_position = *position + n_chars;
2540        }
2541     }
2542   else
2543     {
2544       g_object_set_qdata (G_OBJECT (entry), quark_password_hint, NULL);
2545     }
2546
2547   *position += n_chars;
2548
2549   gtk_entry_recompute (entry);
2550
2551   emit_changed (entry);
2552   g_object_notify (G_OBJECT (editable), "text");
2553 }
2554
2555 static void
2556 gtk_entry_real_delete_text (GtkEditable *editable,
2557                             gint         start_pos,
2558                             gint         end_pos)
2559 {
2560   GtkEntry *entry = GTK_ENTRY (editable);
2561
2562   if (start_pos < 0)
2563     start_pos = 0;
2564   if (end_pos < 0 || end_pos > entry->text_length)
2565     end_pos = entry->text_length;
2566   
2567   if (start_pos < end_pos)
2568     {
2569       gint start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text;
2570       gint end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text;
2571       gint current_pos;
2572       gint selection_bound;
2573
2574       g_memmove (entry->text + start_index, entry->text + end_index, entry->n_bytes + 1 - end_index);
2575       entry->text_length -= (end_pos - start_pos);
2576       entry->n_bytes -= (end_index - start_index);
2577
2578       /* In password-mode, make sure we don't leave anything sensitive after
2579        * the terminating zero.  Note, that the terminating zero already trashed
2580        * one byte.
2581        */
2582       if (!entry->visible)
2583         trash_area (entry->text + entry->n_bytes + 1, end_index - start_index - 1);
2584       
2585       current_pos = entry->current_pos;
2586       if (current_pos > start_pos)
2587         current_pos -= MIN (current_pos, end_pos) - start_pos;
2588
2589       selection_bound = entry->selection_bound;
2590       if (selection_bound > start_pos)
2591         selection_bound -= MIN (selection_bound, end_pos) - start_pos;
2592
2593       gtk_entry_set_positions (entry, current_pos, selection_bound);
2594
2595       /* We might have deleted the selection
2596        */
2597       gtk_entry_update_primary_selection (entry);
2598       
2599       gtk_entry_recompute (entry);
2600
2601       emit_changed (entry);
2602       g_object_notify (G_OBJECT (editable), "text");
2603     }
2604 }
2605
2606 /* Compute the X position for an offset that corresponds to the "more important
2607  * cursor position for that offset. We use this when trying to guess to which
2608  * end of the selection we should go to when the user hits the left or
2609  * right arrow key.
2610  */
2611 static gint
2612 get_better_cursor_x (GtkEntry *entry,
2613                      gint      offset)
2614 {
2615   GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (entry)));
2616   PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
2617   gboolean split_cursor;
2618   
2619   PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
2620   const gchar *text = pango_layout_get_text (layout);
2621   gint index = g_utf8_offset_to_pointer (text, offset) - text;
2622   
2623   PangoRectangle strong_pos, weak_pos;
2624   
2625   g_object_get (gtk_widget_get_settings (GTK_WIDGET (entry)),
2626                 "gtk-split-cursor", &split_cursor,
2627                 NULL);
2628
2629   pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos);
2630
2631   if (split_cursor)
2632     return strong_pos.x / PANGO_SCALE;
2633   else
2634     return (keymap_direction == entry->resolved_dir) ? strong_pos.x / PANGO_SCALE : weak_pos.x / PANGO_SCALE;
2635 }
2636
2637 static void
2638 gtk_entry_move_cursor (GtkEntry       *entry,
2639                        GtkMovementStep step,
2640                        gint            count,
2641                        gboolean        extend_selection)
2642 {
2643   gint new_pos = entry->current_pos;
2644
2645   _gtk_entry_reset_im_context (entry);
2646
2647   if (entry->current_pos != entry->selection_bound && !extend_selection)
2648     {
2649       /* If we have a current selection and aren't extending it, move to the
2650        * start/or end of the selection as appropriate
2651        */
2652       switch (step)
2653         {
2654         case GTK_MOVEMENT_VISUAL_POSITIONS:
2655           {
2656             gint current_x = get_better_cursor_x (entry, entry->current_pos);
2657             gint bound_x = get_better_cursor_x (entry, entry->selection_bound);
2658
2659             if (count <= 0)
2660               new_pos = current_x < bound_x ? entry->current_pos : entry->selection_bound;
2661             else 
2662               new_pos = current_x > bound_x ? entry->current_pos : entry->selection_bound;
2663             break;
2664           }
2665         case GTK_MOVEMENT_LOGICAL_POSITIONS:
2666         case GTK_MOVEMENT_WORDS:
2667           if (count < 0)
2668             new_pos = MIN (entry->current_pos, entry->selection_bound);
2669           else
2670             new_pos = MAX (entry->current_pos, entry->selection_bound);
2671           break;
2672         case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
2673         case GTK_MOVEMENT_PARAGRAPH_ENDS:
2674         case GTK_MOVEMENT_BUFFER_ENDS:
2675           new_pos = count < 0 ? 0 : entry->text_length;
2676           break;
2677         case GTK_MOVEMENT_DISPLAY_LINES:
2678         case GTK_MOVEMENT_PARAGRAPHS:
2679         case GTK_MOVEMENT_PAGES:
2680         case GTK_MOVEMENT_HORIZONTAL_PAGES:
2681           break;
2682         }
2683     }
2684   else
2685     {
2686       switch (step)
2687         {
2688         case GTK_MOVEMENT_LOGICAL_POSITIONS:
2689           new_pos = gtk_entry_move_logically (entry, new_pos, count);
2690           break;
2691         case GTK_MOVEMENT_VISUAL_POSITIONS:
2692           new_pos = gtk_entry_move_visually (entry, new_pos, count);
2693           if (entry->current_pos == new_pos)
2694             {
2695               if (!extend_selection)
2696                 {
2697                   if (!gtk_widget_keynav_failed (GTK_WIDGET (entry),
2698                                                  count > 0 ?
2699                                                  GTK_DIR_RIGHT : GTK_DIR_LEFT))
2700                     {
2701                       GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (entry));
2702
2703                       if (toplevel)
2704                         gtk_widget_child_focus (toplevel,
2705                                                 count > 0 ?
2706                                                 GTK_DIR_RIGHT : GTK_DIR_LEFT);
2707                     }
2708                 }
2709               else
2710                 {
2711                   gtk_widget_error_bell (GTK_WIDGET (entry));
2712                 }
2713             }
2714           break;
2715         case GTK_MOVEMENT_WORDS:
2716           while (count > 0)
2717             {
2718               new_pos = gtk_entry_move_forward_word (entry, new_pos, FALSE);
2719               count--;
2720             }
2721           while (count < 0)
2722             {
2723               new_pos = gtk_entry_move_backward_word (entry, new_pos, FALSE);
2724               count++;
2725             }
2726           if (entry->current_pos == new_pos)
2727             gtk_widget_error_bell (GTK_WIDGET (entry));
2728           break;
2729         case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
2730         case GTK_MOVEMENT_PARAGRAPH_ENDS:
2731         case GTK_MOVEMENT_BUFFER_ENDS:
2732           new_pos = count < 0 ? 0 : entry->text_length;
2733           if (entry->current_pos == new_pos)
2734             gtk_widget_error_bell (GTK_WIDGET (entry));
2735           break;
2736         case GTK_MOVEMENT_DISPLAY_LINES:
2737         case GTK_MOVEMENT_PARAGRAPHS:
2738         case GTK_MOVEMENT_PAGES:
2739         case GTK_MOVEMENT_HORIZONTAL_PAGES:
2740           break;
2741         }
2742     }
2743
2744   if (extend_selection)
2745     gtk_editable_select_region (GTK_EDITABLE (entry), entry->selection_bound, new_pos);
2746   else
2747     gtk_editable_set_position (GTK_EDITABLE (entry), new_pos);
2748   
2749   gtk_entry_pend_cursor_blink (entry);
2750 }
2751
2752 static void
2753 gtk_entry_insert_at_cursor (GtkEntry    *entry,
2754                             const gchar *str)
2755 {
2756   GtkEditable *editable = GTK_EDITABLE (entry);
2757   gint pos = entry->current_pos;
2758
2759   if (entry->editable)
2760     {
2761       _gtk_entry_reset_im_context (entry);
2762
2763       gtk_editable_insert_text (editable, str, -1, &pos);
2764       gtk_editable_set_position (editable, pos);
2765     }
2766 }
2767
2768 static void
2769 gtk_entry_delete_from_cursor (GtkEntry       *entry,
2770                               GtkDeleteType   type,
2771                               gint            count)
2772 {
2773   GtkEditable *editable = GTK_EDITABLE (entry);
2774   gint start_pos = entry->current_pos;
2775   gint end_pos = entry->current_pos;
2776   gint old_n_bytes = entry->n_bytes;
2777   
2778   _gtk_entry_reset_im_context (entry);
2779
2780   if (!entry->editable)
2781     {
2782       gtk_widget_error_bell (GTK_WIDGET (entry));
2783       return;
2784     }
2785
2786   if (entry->selection_bound != entry->current_pos)
2787     {
2788       gtk_editable_delete_selection (editable);
2789       return;
2790     }
2791   
2792   switch (type)
2793     {
2794     case GTK_DELETE_CHARS:
2795       end_pos = gtk_entry_move_logically (entry, entry->current_pos, count);
2796       gtk_editable_delete_text (editable, MIN (start_pos, end_pos), MAX (start_pos, end_pos));
2797       break;
2798     case GTK_DELETE_WORDS:
2799       if (count < 0)
2800         {
2801           /* Move to end of current word, or if not on a word, end of previous word */
2802           end_pos = gtk_entry_move_backward_word (entry, end_pos, FALSE);
2803           end_pos = gtk_entry_move_forward_word (entry, end_pos, FALSE);
2804         }
2805       else if (count > 0)
2806         {
2807           /* Move to beginning of current word, or if not on a word, begining of next word */
2808           start_pos = gtk_entry_move_forward_word (entry, start_pos, FALSE);
2809           start_pos = gtk_entry_move_backward_word (entry, start_pos, FALSE);
2810         }
2811         
2812       /* Fall through */
2813     case GTK_DELETE_WORD_ENDS:
2814       while (count < 0)
2815         {
2816           start_pos = gtk_entry_move_backward_word (entry, start_pos, FALSE);
2817           count++;
2818         }
2819       while (count > 0)
2820         {
2821           end_pos = gtk_entry_move_forward_word (entry, end_pos, FALSE);
2822           count--;
2823         }
2824       gtk_editable_delete_text (editable, start_pos, end_pos);
2825       break;
2826     case GTK_DELETE_DISPLAY_LINE_ENDS:
2827     case GTK_DELETE_PARAGRAPH_ENDS:
2828       if (count < 0)
2829         gtk_editable_delete_text (editable, 0, entry->current_pos);
2830       else
2831         gtk_editable_delete_text (editable, entry->current_pos, -1);
2832       break;
2833     case GTK_DELETE_DISPLAY_LINES:
2834     case GTK_DELETE_PARAGRAPHS:
2835       gtk_editable_delete_text (editable, 0, -1);  
2836       break;
2837     case GTK_DELETE_WHITESPACE:
2838       gtk_entry_delete_whitespace (entry);
2839       break;
2840     }
2841
2842   if (entry->n_bytes == old_n_bytes)
2843     gtk_widget_error_bell (GTK_WIDGET (entry));
2844
2845   gtk_entry_pend_cursor_blink (entry);
2846 }
2847
2848 static void
2849 gtk_entry_backspace (GtkEntry *entry)
2850 {
2851   GtkEditable *editable = GTK_EDITABLE (entry);
2852   gint prev_pos;
2853
2854   _gtk_entry_reset_im_context (entry);
2855
2856   if (!entry->editable || !entry->text)
2857     {
2858       gtk_widget_error_bell (GTK_WIDGET (entry));
2859       return;
2860     }
2861
2862   if (entry->selection_bound != entry->current_pos)
2863     {
2864       gtk_editable_delete_selection (editable);
2865       return;
2866     }
2867
2868   prev_pos = gtk_entry_move_logically(entry, entry->current_pos, -1);
2869
2870   if (prev_pos < entry->current_pos)
2871     {
2872       PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE);
2873       PangoLogAttr *log_attrs;
2874       gint n_attrs;
2875
2876       pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
2877
2878       if (log_attrs[entry->current_pos].backspace_deletes_character)
2879         {
2880           gchar *cluster_text;
2881           gchar *normalized_text;
2882           glong  len;
2883
2884           cluster_text = gtk_editable_get_chars (editable,
2885                                                  prev_pos,
2886                                                  entry->current_pos);
2887           normalized_text = g_utf8_normalize (cluster_text,
2888                                               strlen (cluster_text),
2889                                               G_NORMALIZE_NFD);
2890           len = g_utf8_strlen (normalized_text, -1);
2891
2892           gtk_editable_delete_text (editable, prev_pos, entry->current_pos);
2893           if (len > 1)
2894             {
2895               gint pos = entry->current_pos;
2896
2897               gtk_editable_insert_text (editable, normalized_text,
2898                                         g_utf8_offset_to_pointer (normalized_text, len - 1) - normalized_text,
2899                                         &pos);
2900               gtk_editable_set_position (editable, pos);
2901             }
2902
2903           g_free (normalized_text);
2904           g_free (cluster_text);
2905         }
2906       else
2907         {
2908           gtk_editable_delete_text (editable, prev_pos, entry->current_pos);
2909         }
2910       
2911       g_free (log_attrs);
2912     }
2913   else
2914     {
2915       gtk_widget_error_bell (GTK_WIDGET (entry));
2916     }
2917
2918   gtk_entry_pend_cursor_blink (entry);
2919 }
2920
2921 static void
2922 gtk_entry_copy_clipboard (GtkEntry *entry)
2923 {
2924   GtkEditable *editable = GTK_EDITABLE (entry);
2925   gint start, end;
2926
2927   if (gtk_editable_get_selection_bounds (editable, &start, &end))
2928     {
2929       gchar *str = gtk_entry_get_public_chars (entry, start, end);
2930       gtk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (entry),
2931                                                         GDK_SELECTION_CLIPBOARD),
2932                               str, -1);
2933       g_free (str);
2934     }
2935 }
2936
2937 static void
2938 gtk_entry_cut_clipboard (GtkEntry *entry)
2939 {
2940   GtkEditable *editable = GTK_EDITABLE (entry);
2941   gint start, end;
2942
2943   gtk_entry_copy_clipboard (entry);
2944
2945   if (entry->editable)
2946     {
2947       if (gtk_editable_get_selection_bounds (editable, &start, &end))
2948         gtk_editable_delete_text (editable, start, end);
2949     }
2950   else
2951     {
2952       gtk_widget_error_bell (GTK_WIDGET (entry));
2953     }
2954 }
2955
2956 static void
2957 gtk_entry_paste_clipboard (GtkEntry *entry)
2958 {
2959   if (entry->editable)
2960     gtk_entry_paste (entry, GDK_NONE);
2961   else
2962     gtk_widget_error_bell (GTK_WIDGET (entry));
2963 }
2964
2965 static void
2966 gtk_entry_delete_cb (GtkEntry *entry)
2967 {
2968   GtkEditable *editable = GTK_EDITABLE (entry);
2969   gint start, end;
2970
2971   if (entry->editable)
2972     {
2973       if (gtk_editable_get_selection_bounds (editable, &start, &end))
2974         gtk_editable_delete_text (editable, start, end);
2975     }
2976 }
2977
2978 static void
2979 gtk_entry_toggle_overwrite (GtkEntry *entry)
2980 {
2981   entry->overwrite_mode = !entry->overwrite_mode;
2982   gtk_entry_pend_cursor_blink (entry);
2983   gtk_widget_queue_draw (GTK_WIDGET (entry));
2984 }
2985
2986 static void
2987 gtk_entry_select_all (GtkEntry *entry)
2988 {
2989   gtk_entry_select_line (entry);
2990 }
2991
2992 static void
2993 gtk_entry_real_activate (GtkEntry *entry)
2994 {
2995   GtkWindow *window;
2996   GtkWidget *toplevel;
2997   GtkWidget *widget;
2998
2999   widget = GTK_WIDGET (entry);
3000
3001   if (entry->activates_default)
3002     {
3003       toplevel = gtk_widget_get_toplevel (widget);
3004       if (GTK_IS_WINDOW (toplevel))
3005         {
3006           window = GTK_WINDOW (toplevel);
3007       
3008           if (window &&
3009               widget != window->default_widget &&
3010               !(widget == window->focus_widget &&
3011                 (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget))))
3012             gtk_window_activate_default (window);
3013         }
3014     }
3015 }
3016
3017 static void
3018 gtk_entry_keymap_direction_changed (GdkKeymap *keymap,
3019                                     GtkEntry  *entry)
3020 {
3021   gtk_entry_recompute (entry);
3022 }
3023
3024 /* IM Context Callbacks
3025  */
3026
3027 static void
3028 gtk_entry_commit_cb (GtkIMContext *context,
3029                      const gchar  *str,
3030                      GtkEntry     *entry)
3031 {
3032   if (entry->editable)
3033     gtk_entry_enter_text (entry, str);
3034 }
3035
3036 static void 
3037 gtk_entry_preedit_changed_cb (GtkIMContext *context,
3038                               GtkEntry     *entry)
3039 {
3040   if (entry->editable)
3041     {
3042       gchar *preedit_string;
3043       gint cursor_pos;
3044       
3045       gtk_im_context_get_preedit_string (entry->im_context,
3046                                          &preedit_string, NULL,
3047                                          &cursor_pos);
3048       entry->preedit_length = strlen (preedit_string);
3049       cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (preedit_string, -1));
3050       entry->preedit_cursor = cursor_pos;
3051       g_free (preedit_string);
3052     
3053       gtk_entry_recompute (entry);
3054     }
3055 }
3056
3057 static gboolean
3058 gtk_entry_retrieve_surrounding_cb (GtkIMContext *context,
3059                                GtkEntry     *entry)
3060 {
3061   gtk_im_context_set_surrounding (context,
3062                                   entry->text,
3063                                   entry->n_bytes,
3064                                   g_utf8_offset_to_pointer (entry->text, entry->current_pos) - entry->text);
3065
3066   return TRUE;
3067 }
3068
3069 static gboolean
3070 gtk_entry_delete_surrounding_cb (GtkIMContext *slave,
3071                                  gint          offset,
3072                                  gint          n_chars,
3073                                  GtkEntry     *entry)
3074 {
3075   if (entry->editable)
3076     gtk_editable_delete_text (GTK_EDITABLE (entry),
3077                               entry->current_pos + offset,
3078                               entry->current_pos + offset + n_chars);
3079
3080   return TRUE;
3081 }
3082
3083 /* Internal functions
3084  */
3085
3086 /* Used for im_commit_cb and inserting Unicode chars */
3087 static void
3088 gtk_entry_enter_text (GtkEntry       *entry,
3089                       const gchar    *str)
3090 {
3091   GtkEditable *editable = GTK_EDITABLE (entry);
3092   gint tmp_pos;
3093   gboolean old_need_im_reset;
3094
3095   old_need_im_reset = entry->need_im_reset;
3096   entry->need_im_reset = FALSE;
3097
3098   if (gtk_editable_get_selection_bounds (editable, NULL, NULL))
3099     gtk_editable_delete_selection (editable);
3100   else
3101     {
3102       if (entry->overwrite_mode)
3103         gtk_entry_delete_from_cursor (entry, GTK_DELETE_CHARS, 1);
3104     }
3105
3106   tmp_pos = entry->current_pos;
3107   gtk_editable_insert_text (editable, str, strlen (str), &tmp_pos);
3108   gtk_editable_set_position (editable, tmp_pos);
3109
3110   entry->need_im_reset = old_need_im_reset;
3111 }
3112
3113 /* All changes to entry->current_pos and entry->selection_bound
3114  * should go through this function.
3115  */
3116 static void
3117 gtk_entry_set_positions (GtkEntry *entry,
3118                          gint      current_pos,
3119                          gint      selection_bound)
3120 {
3121   gboolean changed = FALSE;
3122
3123   g_object_freeze_notify (G_OBJECT (entry));
3124   
3125   if (current_pos != -1 &&
3126       entry->current_pos != current_pos)
3127     {
3128       entry->current_pos = current_pos;
3129       changed = TRUE;
3130
3131       g_object_notify (G_OBJECT (entry), "cursor-position");
3132     }
3133
3134   if (selection_bound != -1 &&
3135       entry->selection_bound != selection_bound)
3136     {
3137       entry->selection_bound = selection_bound;
3138       changed = TRUE;
3139       
3140       g_object_notify (G_OBJECT (entry), "selection-bound");
3141     }
3142
3143   g_object_thaw_notify (G_OBJECT (entry));
3144
3145   if (changed) 
3146     {
3147       gtk_entry_move_adjustments (entry);
3148       gtk_entry_recompute (entry);
3149     }
3150 }
3151
3152 static void
3153 gtk_entry_reset_layout (GtkEntry *entry)
3154 {
3155   if (entry->cached_layout)
3156     {
3157       g_object_unref (entry->cached_layout);
3158       entry->cached_layout = NULL;
3159     }
3160 }
3161
3162 static void
3163 update_im_cursor_location (GtkEntry *entry)
3164 {
3165   GdkRectangle area;
3166   gint strong_x;
3167   gint strong_xoffset;
3168   gint area_width, area_height;
3169
3170   gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, NULL)
3171 ;
3172   get_text_area_size (entry, NULL, NULL, &area_width, &area_height);
3173
3174   strong_xoffset = strong_x - entry->scroll_offset;
3175   if (strong_xoffset < 0)
3176     {
3177       strong_xoffset = 0;
3178     }
3179   else if (strong_xoffset > area_width)
3180     {
3181       strong_xoffset = area_width;
3182     }
3183   area.x = strong_xoffset;
3184   area.y = 0;
3185   area.width = 0;
3186   area.height = area_height;
3187
3188   gtk_im_context_set_cursor_location (entry->im_context, &area);
3189 }
3190
3191 static gboolean
3192 recompute_idle_func (gpointer data)
3193 {
3194   GtkEntry *entry;
3195
3196   entry = GTK_ENTRY (data);
3197
3198   entry->recompute_idle = 0;
3199   
3200   if (gtk_widget_has_screen (GTK_WIDGET (entry)))
3201     {
3202       gtk_entry_adjust_scroll (entry);
3203       gtk_entry_queue_draw (entry);
3204       
3205       update_im_cursor_location (entry);
3206     }
3207
3208   return FALSE;
3209 }
3210
3211 static void
3212 gtk_entry_recompute (GtkEntry *entry)
3213 {
3214   gtk_entry_reset_layout (entry);
3215   gtk_entry_check_cursor_blink (entry);
3216   
3217   if (!entry->recompute_idle)
3218     {
3219       entry->recompute_idle = gdk_threads_add_idle_full (G_PRIORITY_HIGH_IDLE + 15, /* between resize and redraw */
3220                                                recompute_idle_func, entry, NULL); 
3221     }
3222 }
3223
3224 static void
3225 append_char (GString *str,
3226              gunichar ch,
3227              gint     count)
3228 {
3229   gint i;
3230   gint char_len;
3231   gchar buf[7];
3232   
3233   char_len = g_unichar_to_utf8 (ch, buf);
3234   
3235   i = 0;
3236   while (i < count)
3237     {
3238       g_string_append_len (str, buf, char_len);
3239       ++i;
3240     }
3241 }
3242
3243 static gboolean
3244 gtk_entry_remove_password_hint (gpointer data)
3245 {
3246   /* Force the string to be redrawn, but now without a visible character */
3247   gtk_entry_recompute (GTK_ENTRY (data));
3248
3249   return FALSE;
3250 }
3251
3252 static PangoLayout *
3253 gtk_entry_create_layout (GtkEntry *entry,
3254                          gboolean  include_preedit)
3255 {
3256   GtkWidget *widget = GTK_WIDGET (entry);
3257   PangoLayout *layout = gtk_widget_create_pango_layout (widget, NULL);
3258   PangoAttrList *tmp_attrs = pango_attr_list_new ();
3259   
3260   gchar *preedit_string = NULL;
3261   gint preedit_length = 0;
3262   PangoAttrList *preedit_attrs = NULL;
3263
3264   pango_layout_set_single_paragraph_mode (layout, TRUE);
3265
3266   if (include_preedit)
3267     {
3268       gtk_im_context_get_preedit_string (entry->im_context,
3269                                          &preedit_string, &preedit_attrs, NULL);
3270       preedit_length = entry->preedit_length;
3271     }
3272
3273   if (preedit_length)
3274     {
3275       GString *tmp_string = g_string_new (NULL);
3276       
3277       gint cursor_index = g_utf8_offset_to_pointer (entry->text, entry->current_pos) - entry->text;
3278       
3279       if (entry->visible)
3280         {
3281           g_string_prepend_len (tmp_string, entry->text, entry->n_bytes);
3282           g_string_insert (tmp_string, cursor_index, preedit_string);
3283         }
3284       else
3285         {
3286           gint ch_len;
3287           gint preedit_len_chars;
3288           gunichar invisible_char;
3289
3290           ch_len = g_utf8_strlen (entry->text, entry->n_bytes);
3291           preedit_len_chars = g_utf8_strlen (preedit_string, -1);
3292           ch_len += preedit_len_chars;
3293
3294           if (entry->invisible_char != 0)
3295             invisible_char = entry->invisible_char;
3296           else
3297             invisible_char = ' '; /* just pick a char */
3298           
3299           append_char (tmp_string, invisible_char, ch_len);
3300           
3301           /* Fix cursor index to point to invisible char corresponding
3302            * to the preedit, fix preedit_length to be the length of
3303            * the invisible chars representing the preedit
3304            */
3305           cursor_index =
3306             g_utf8_offset_to_pointer (tmp_string->str, entry->current_pos) -
3307             tmp_string->str;
3308           preedit_length =
3309             preedit_len_chars *
3310             g_unichar_to_utf8 (invisible_char, NULL);
3311         }
3312       
3313       pango_layout_set_text (layout, tmp_string->str, tmp_string->len);
3314       
3315       pango_attr_list_splice (tmp_attrs, preedit_attrs,
3316                               cursor_index, preedit_length);
3317       
3318       g_string_free (tmp_string, TRUE);
3319     }
3320   else
3321     {
3322       PangoDirection pango_dir;
3323       
3324       if (entry->visible)
3325         pango_dir = pango_find_base_dir (entry->text, entry->n_bytes);
3326
3327       else
3328         pango_dir = PANGO_DIRECTION_NEUTRAL;
3329
3330       if (pango_dir == PANGO_DIRECTION_NEUTRAL)
3331         {
3332           if (GTK_WIDGET_HAS_FOCUS (widget))
3333             {
3334               GdkDisplay *display = gtk_widget_get_display (widget);
3335               GdkKeymap *keymap = gdk_keymap_get_for_display (display);
3336               if (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_RTL)
3337                 pango_dir = PANGO_DIRECTION_RTL;
3338               else
3339                 pango_dir = PANGO_DIRECTION_LTR;
3340             }
3341           else
3342             {
3343               if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
3344                 pango_dir = PANGO_DIRECTION_RTL;
3345               else
3346                 pango_dir = PANGO_DIRECTION_LTR;
3347             }
3348         }
3349
3350       pango_context_set_base_dir (gtk_widget_get_pango_context (widget),
3351                                   pango_dir);
3352
3353       pango_layout_set_alignment (layout, pango_dir);
3354
3355       entry->resolved_dir = pango_dir;
3356       
3357       if (entry->visible)
3358         {
3359           pango_layout_set_text (layout, entry->text, entry->n_bytes);
3360         }
3361       else
3362         {
3363           GString *str = g_string_new (NULL);
3364           gunichar invisible_char;
3365           guint password_hint_timeout;
3366           GtkEntryPasswordHint *password_hint;
3367
3368           g_object_get (gtk_widget_get_settings (widget),
3369                         "gtk-entry-password-hint-timeout", &password_hint_timeout,
3370                         NULL);
3371
3372           if (entry->invisible_char != 0)
3373             invisible_char = entry->invisible_char;
3374           else
3375             invisible_char = ' '; /* just pick a char */
3376
3377           password_hint = g_object_get_qdata (G_OBJECT (entry),
3378                                               quark_password_hint);
3379
3380           if (password_hint && password_hint->password_hint_timeout_id)
3381             {
3382               g_source_remove (password_hint->password_hint_timeout_id);
3383               password_hint->password_hint_timeout_id = 0;
3384             }
3385
3386           if (password_hint_timeout == 0 || password_hint == NULL ||
3387               (password_hint && password_hint->password_hint_length == 0))
3388             {
3389               append_char (str, invisible_char, entry->text_length);
3390             }
3391           else if (password_hint)
3392             {
3393               /* Draw hidden characters upto the inserted position,
3394                * then the real thing, pad up to full length
3395                */
3396               if (password_hint->password_hint_position > 1)
3397                 append_char (str, invisible_char,
3398                              password_hint->password_hint_position - 1);
3399
3400               g_string_append_len (str, password_hint->password_hint,
3401                                    password_hint->password_hint_length);
3402
3403               if (password_hint->password_hint_position < entry->text_length)
3404                 append_char (str, invisible_char,
3405                              entry->text_length -
3406                              password_hint->password_hint_position);
3407
3408               /* Now remove this last input character, don't need
3409                * it anymore
3410                */
3411               memset (password_hint->password_hint, 0, PASSWORD_HINT_MAX);
3412               password_hint->password_hint_length = 0;
3413
3414               password_hint->password_hint_timeout_id =
3415                 gdk_threads_add_timeout (password_hint_timeout,
3416                                (GSourceFunc) gtk_entry_remove_password_hint,
3417                                entry);
3418             }
3419
3420           pango_layout_set_text (layout, str->str, str->len);
3421           g_string_free (str, TRUE);
3422         }
3423     }
3424       
3425   pango_layout_set_attributes (layout, tmp_attrs);
3426
3427   g_free (preedit_string);
3428   if (preedit_attrs)
3429     pango_attr_list_unref (preedit_attrs);
3430       
3431   pango_attr_list_unref (tmp_attrs);
3432
3433   return layout;
3434 }
3435
3436 static PangoLayout *
3437 gtk_entry_ensure_layout (GtkEntry *entry,
3438                          gboolean  include_preedit)
3439 {
3440   if (entry->preedit_length > 0 &&
3441       !include_preedit != !entry->cache_includes_preedit)
3442     gtk_entry_reset_layout (entry);
3443
3444   if (!entry->cached_layout)
3445     {
3446       entry->cached_layout = gtk_entry_create_layout (entry, include_preedit);
3447       entry->cache_includes_preedit = include_preedit;
3448     }
3449   
3450   return entry->cached_layout;
3451 }
3452
3453 static void
3454 get_layout_position (GtkEntry *entry,
3455                      gint     *x,
3456                      gint     *y)
3457 {
3458   PangoLayout *layout;
3459   PangoRectangle logical_rect;
3460   gint area_width, area_height;
3461   GtkBorder inner_border;
3462   gint y_pos;
3463   PangoLayoutLine *line;
3464   
3465   layout = gtk_entry_ensure_layout (entry, TRUE);
3466
3467   get_text_area_size (entry, NULL, NULL, &area_width, &area_height);
3468   _gtk_entry_effective_inner_border (entry, &inner_border);
3469
3470   area_height = PANGO_SCALE * (area_height - inner_border.top - inner_border.bottom);
3471
3472   line = pango_layout_get_lines_readonly (layout)->data;
3473   pango_layout_line_get_extents (line, NULL, &logical_rect);
3474   
3475   /* Align primarily for locale's ascent/descent */
3476   y_pos = ((area_height - entry->ascent - entry->descent) / 2 + 
3477            entry->ascent + logical_rect.y);
3478   
3479   /* Now see if we need to adjust to fit in actual drawn string */
3480   if (logical_rect.height > area_height)
3481     y_pos = (area_height - logical_rect.height) / 2;
3482   else if (y_pos < 0)
3483     y_pos = 0;
3484   else if (y_pos + logical_rect.height > area_height)
3485     y_pos = area_height - logical_rect.height;
3486   
3487   y_pos = inner_border.top + y_pos / PANGO_SCALE;
3488
3489   if (x)
3490     *x = inner_border.left - entry->scroll_offset;
3491
3492   if (y)
3493     *y = y_pos;
3494 }
3495
3496 static void
3497 gtk_entry_draw_text (GtkEntry *entry)
3498 {
3499   GtkWidget *widget;
3500   
3501   if (!entry->visible && entry->invisible_char == 0)
3502     return;
3503   
3504   if (GTK_WIDGET_DRAWABLE (entry))
3505     {
3506       PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
3507       cairo_t *cr;
3508       gint x, y;
3509       gint start_pos, end_pos;
3510       
3511       widget = GTK_WIDGET (entry);
3512       
3513       get_layout_position (entry, &x, &y);
3514
3515       cr = gdk_cairo_create (entry->text_area);
3516
3517       cairo_move_to (cr, x, y);
3518       gdk_cairo_set_source_color (cr, &widget->style->text [widget->state]);
3519       pango_cairo_show_layout (cr, layout);
3520
3521       if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_pos, &end_pos))
3522         {
3523           gint *ranges;
3524           gint n_ranges, i;
3525           PangoRectangle logical_rect;
3526           GdkColor *selection_color, *text_color;
3527           GtkBorder inner_border;
3528
3529           pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
3530           gtk_entry_get_pixel_ranges (entry, &ranges, &n_ranges);
3531
3532           if (GTK_WIDGET_HAS_FOCUS (entry))
3533             {
3534               selection_color = &widget->style->base [GTK_STATE_SELECTED];
3535               text_color = &widget->style->text [GTK_STATE_SELECTED];
3536             }
3537           else
3538             {
3539               selection_color = &widget->style->base [GTK_STATE_ACTIVE];
3540               text_color = &widget->style->text [GTK_STATE_ACTIVE];
3541             }
3542
3543           _gtk_entry_effective_inner_border (entry, &inner_border);
3544
3545           for (i = 0; i < n_ranges; ++i)
3546             cairo_rectangle (cr,
3547                              inner_border.left - entry->scroll_offset + ranges[2 * i],
3548                              y,
3549                              ranges[2 * i + 1],
3550                              logical_rect.height);
3551
3552           cairo_clip (cr);
3553           
3554           gdk_cairo_set_source_color (cr, selection_color);
3555           cairo_paint (cr);
3556
3557           cairo_move_to (cr, x, y);
3558           gdk_cairo_set_source_color (cr, text_color);
3559           pango_cairo_show_layout (cr, layout);
3560           
3561           g_free (ranges);
3562         }
3563
3564       cairo_destroy (cr);
3565     }
3566 }
3567
3568 static void
3569 draw_insertion_cursor (GtkEntry      *entry,
3570                        GdkRectangle  *cursor_location,
3571                        gboolean       is_primary,
3572                        PangoDirection direction,
3573                        gboolean       draw_arrow)
3574 {
3575   GtkWidget *widget = GTK_WIDGET (entry);
3576   GtkTextDirection text_dir;
3577
3578   if (direction == PANGO_DIRECTION_LTR)
3579     text_dir = GTK_TEXT_DIR_LTR;
3580   else
3581     text_dir = GTK_TEXT_DIR_RTL;
3582
3583   gtk_draw_insertion_cursor (widget, entry->text_area, NULL,
3584                              cursor_location,
3585                              is_primary, text_dir, draw_arrow);
3586 }
3587
3588 static void
3589 gtk_entry_draw_cursor (GtkEntry  *entry,
3590                        CursorType type)
3591 {
3592   GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (entry)));
3593   PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
3594   
3595   if (GTK_WIDGET_DRAWABLE (entry))
3596     {
3597       GtkWidget *widget = GTK_WIDGET (entry);
3598       GdkRectangle cursor_location;
3599       gboolean split_cursor;
3600       PangoRectangle cursor_rect;
3601       GtkBorder inner_border;
3602       gint xoffset;
3603       gint text_area_height;
3604       gint cursor_index;
3605       gboolean block;
3606       gboolean block_at_line_end;
3607
3608       _gtk_entry_effective_inner_border (entry, &inner_border);
3609
3610       xoffset = inner_border.left - entry->scroll_offset;
3611
3612       gdk_drawable_get_size (entry->text_area, NULL, &text_area_height);
3613
3614       cursor_index = g_utf8_offset_to_pointer (entry->text, entry->current_pos + entry->preedit_cursor) - entry->text;
3615       if (!entry->overwrite_mode)
3616         block = FALSE;
3617       else
3618         block = _gtk_text_util_get_block_cursor_location (gtk_entry_ensure_layout (entry, TRUE),
3619                                                           cursor_index, &cursor_rect, &block_at_line_end);
3620
3621       if (!block)
3622         {
3623           gint strong_x, weak_x;
3624           PangoDirection dir1 = PANGO_DIRECTION_NEUTRAL;
3625           PangoDirection dir2 = PANGO_DIRECTION_NEUTRAL;
3626           gint x1 = 0;
3627           gint x2 = 0;
3628
3629           gtk_entry_get_cursor_locations (entry, type, &strong_x, &weak_x);
3630
3631           g_object_get (gtk_widget_get_settings (widget),
3632                         "gtk-split-cursor", &split_cursor,
3633                         NULL);
3634
3635           dir1 = entry->resolved_dir;
3636       
3637           if (split_cursor)
3638             {
3639               x1 = strong_x;
3640
3641               if (weak_x != strong_x)
3642                 {
3643                   dir2 = (entry->resolved_dir == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
3644                   x2 = weak_x;
3645                 }
3646             }
3647           else
3648             {
3649               if (keymap_direction == entry->resolved_dir)
3650                 x1 = strong_x;
3651               else
3652                 x1 = weak_x;
3653             }
3654
3655           cursor_location.x = xoffset + x1;
3656           cursor_location.y = inner_border.top;
3657           cursor_location.width = 0;
3658           cursor_location.height = text_area_height - inner_border.top - inner_border.bottom;
3659
3660           draw_insertion_cursor (entry,
3661                                  &cursor_location, TRUE, dir1,
3662                                  dir2 != PANGO_DIRECTION_NEUTRAL);
3663       
3664           if (dir2 != PANGO_DIRECTION_NEUTRAL)
3665             {
3666               cursor_location.x = xoffset + x2;
3667               draw_insertion_cursor (entry,
3668                                      &cursor_location, FALSE, dir2,
3669                                      TRUE);
3670             }
3671         }
3672       else /* overwrite_mode */
3673         {
3674           PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
3675           GdkColor cursor_color;
3676           GdkRectangle rect;
3677           cairo_t *cr;
3678           gint x, y;
3679
3680           get_layout_position (entry, &x, &y);
3681
3682           rect.x = PANGO_PIXELS (cursor_rect.x) + x;
3683           rect.y = PANGO_PIXELS (cursor_rect.y) + y;
3684           rect.width = PANGO_PIXELS (cursor_rect.width);
3685           rect.height = PANGO_PIXELS (cursor_rect.height);
3686
3687           cr = gdk_cairo_create (entry->text_area);
3688
3689           _gtk_widget_get_cursor_color (widget, &cursor_color);
3690           gdk_cairo_set_source_color (cr, &cursor_color);
3691           gdk_cairo_rectangle (cr, &rect);
3692           cairo_fill (cr);
3693
3694           if (!block_at_line_end)
3695             {
3696               gdk_cairo_rectangle (cr, &rect);
3697               cairo_clip (cr);
3698               cairo_move_to (cr, x, y);
3699               gdk_cairo_set_source_color (cr, &widget->style->base[widget->state]);
3700               pango_cairo_show_layout (cr, layout);
3701             }
3702
3703           cairo_destroy (cr);
3704         }
3705     }
3706 }
3707
3708 static void
3709 gtk_entry_queue_draw (GtkEntry *entry)
3710 {
3711   if (GTK_WIDGET_DRAWABLE (entry))
3712     gdk_window_invalidate_rect (entry->text_area, NULL, FALSE);
3713 }
3714
3715 void
3716 _gtk_entry_reset_im_context (GtkEntry *entry)
3717 {
3718   if (entry->need_im_reset)
3719     {
3720       entry->need_im_reset = 0;
3721       gtk_im_context_reset (entry->im_context);
3722     }
3723 }
3724
3725 static gint
3726 gtk_entry_find_position (GtkEntry *entry,
3727                          gint      x)
3728 {
3729   PangoLayout *layout;
3730   PangoLayoutLine *line;
3731   gint index;
3732   gint pos;
3733   gint trailing;
3734   const gchar *text;
3735   gint cursor_index;
3736   
3737   layout = gtk_entry_ensure_layout (entry, TRUE);
3738   text = pango_layout_get_text (layout);
3739   cursor_index = g_utf8_offset_to_pointer (text, entry->current_pos) - text;
3740   
3741   line = pango_layout_get_lines_readonly (layout)->data;
3742   pango_layout_line_x_to_index (line, x * PANGO_SCALE, &index, &trailing);
3743
3744   if (index >= cursor_index && entry->preedit_length)
3745     {
3746       if (index >= cursor_index + entry->preedit_length)
3747         index -= entry->preedit_length;
3748       else
3749         {
3750           index = cursor_index;
3751           trailing = 0;
3752         }
3753     }
3754
3755   pos = g_utf8_pointer_to_offset (text, text + index);
3756   pos += trailing;
3757
3758   return pos;
3759 }
3760
3761 static void
3762 gtk_entry_get_cursor_locations (GtkEntry   *entry,
3763                                 CursorType  type,
3764                                 gint       *strong_x,
3765                                 gint       *weak_x)
3766 {
3767   if (!entry->visible && !entry->invisible_char)
3768     {
3769       if (strong_x)
3770         *strong_x = 0;
3771       
3772       if (weak_x)
3773         *weak_x = 0;
3774     }
3775   else
3776     {
3777       PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
3778       const gchar *text = pango_layout_get_text (layout);
3779       PangoRectangle strong_pos, weak_pos;
3780       gint index;
3781   
3782       if (type == CURSOR_STANDARD)
3783         {
3784           index = g_utf8_offset_to_pointer (text, entry->current_pos + entry->preedit_cursor) - text;
3785         }
3786       else /* type == CURSOR_DND */
3787         {
3788           index = g_utf8_offset_to_pointer (text, entry->dnd_position) - text;
3789
3790           if (entry->dnd_position > entry->current_pos)
3791             {
3792               if (entry->visible)
3793                 index += entry->preedit_length;
3794               else
3795                 {
3796                   gint preedit_len_chars = g_utf8_strlen (text, -1) - entry->text_length;
3797                   index += preedit_len_chars * g_unichar_to_utf8 (entry->invisible_char, NULL);
3798                 }
3799             }
3800         }
3801       
3802       pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos);
3803       
3804       if (strong_x)
3805         *strong_x = strong_pos.x / PANGO_SCALE;
3806       
3807       if (weak_x)
3808         *weak_x = weak_pos.x / PANGO_SCALE;
3809     }
3810 }
3811
3812 static void
3813 gtk_entry_adjust_scroll (GtkEntry *entry)
3814 {
3815   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
3816   gint min_offset, max_offset;
3817   gint text_area_width, text_width;
3818   GtkBorder inner_border;
3819   gint strong_x, weak_x;
3820   gint strong_xoffset, weak_xoffset;
3821   gfloat xalign;
3822   PangoLayout *layout;
3823   PangoLayoutLine *line;
3824   PangoRectangle logical_rect;
3825
3826   if (!GTK_WIDGET_REALIZED (entry))
3827     return;
3828
3829   _gtk_entry_effective_inner_border (entry, &inner_border);
3830
3831   gdk_drawable_get_size (entry->text_area, &text_area_width, NULL);
3832   text_area_width -= inner_border.left + inner_border.right;
3833   if (text_area_width < 0)
3834     text_area_width = 0;
3835
3836   layout = gtk_entry_ensure_layout (entry, TRUE);
3837   line = pango_layout_get_lines_readonly (layout)->data;
3838
3839   pango_layout_line_get_extents (line, NULL, &logical_rect);
3840
3841   /* Display as much text as we can */
3842
3843   if (entry->resolved_dir == PANGO_DIRECTION_LTR)
3844       xalign = priv->xalign;
3845   else
3846       xalign = 1.0 - priv->xalign;
3847
3848   text_width = PANGO_PIXELS(logical_rect.width);
3849
3850   if (text_width > text_area_width)
3851     {
3852       min_offset = 0;
3853       max_offset = text_width - text_area_width;
3854     }
3855   else
3856     {
3857       min_offset = (text_width - text_area_width) * xalign;
3858       max_offset = min_offset;
3859     }
3860
3861   entry->scroll_offset = CLAMP (entry->scroll_offset, min_offset, max_offset);
3862
3863   /* And make sure cursors are on screen. Note that the cursor is
3864    * actually drawn one pixel into the INNER_BORDER space on
3865    * the right, when the scroll is at the utmost right. This
3866    * looks better to to me than confining the cursor inside the
3867    * border entirely, though it means that the cursor gets one
3868    * pixel closer to the edge of the widget on the right than
3869    * on the left. This might need changing if one changed
3870    * INNER_BORDER from 2 to 1, as one would do on a
3871    * small-screen-real-estate display.
3872    *
3873    * We always make sure that the strong cursor is on screen, and
3874    * put the weak cursor on screen if possible.
3875    */
3876
3877   gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, &weak_x);
3878   
3879   strong_xoffset = strong_x - entry->scroll_offset;
3880
3881   if (strong_xoffset < 0)
3882     {
3883       entry->scroll_offset += strong_xoffset;
3884       strong_xoffset = 0;
3885     }
3886   else if (strong_xoffset > text_area_width)
3887     {
3888       entry->scroll_offset += strong_xoffset - text_area_width;
3889       strong_xoffset = text_area_width;
3890     }
3891
3892   weak_xoffset = weak_x - entry->scroll_offset;
3893
3894   if (weak_xoffset < 0 && strong_xoffset - weak_xoffset <= text_area_width)
3895     {
3896       entry->scroll_offset += weak_xoffset;
3897     }
3898   else if (weak_xoffset > text_area_width &&
3899            strong_xoffset - (weak_xoffset - text_area_width) >= 0)
3900     {
3901       entry->scroll_offset += weak_xoffset - text_area_width;
3902     }
3903
3904   g_object_notify (G_OBJECT (entry), "scroll-offset");
3905 }
3906
3907 static void
3908 gtk_entry_move_adjustments (GtkEntry *entry)
3909 {
3910   PangoContext *context;
3911   PangoFontMetrics *metrics;
3912   gint x, layout_x, border_x, border_y;
3913   gint char_width;
3914   GtkAdjustment *adjustment;
3915
3916   adjustment = g_object_get_qdata (G_OBJECT (entry), quark_cursor_hadjustment);
3917   if (!adjustment)
3918     return;
3919
3920   /* Cursor position, layout offset, border width, and widget allocation */
3921   gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &x, NULL);
3922   get_layout_position (entry, &layout_x, NULL);
3923   _gtk_entry_get_borders (entry, &border_x, &border_y);
3924   x += entry->widget.allocation.x + layout_x + border_x;
3925
3926   /* Approximate width of a char, so user can see what is ahead/behind */
3927   context = gtk_widget_get_pango_context (GTK_WIDGET (entry));
3928   metrics = pango_context_get_metrics (context, 
3929                                        entry->widget.style->font_desc,
3930                                        pango_context_get_language (context));
3931   char_width = pango_font_metrics_get_approximate_char_width (metrics) / PANGO_SCALE;
3932
3933   /* Scroll it */
3934   gtk_adjustment_clamp_page (adjustment, 
3935                              x - (char_width + 1),   /* one char + one pixel before */
3936                              x + (char_width + 2));  /* one char + cursor + one pixel after */
3937 }
3938
3939 static gint
3940 gtk_entry_move_visually (GtkEntry *entry,
3941                          gint      start,
3942                          gint      count)
3943 {
3944   gint index;
3945   PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE);
3946   const gchar *text;
3947
3948   text = pango_layout_get_text (layout);
3949   
3950   index = g_utf8_offset_to_pointer (text, start) - text;
3951
3952   while (count != 0)
3953     {
3954       int new_index, new_trailing;
3955       gboolean split_cursor;
3956       gboolean strong;
3957
3958       g_object_get (gtk_widget_get_settings (GTK_WIDGET (entry)),
3959                     "gtk-split-cursor", &split_cursor,
3960                     NULL);
3961
3962       if (split_cursor)
3963         strong = TRUE;
3964       else
3965         {
3966           GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (entry)));
3967           PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
3968
3969           strong = keymap_direction == entry->resolved_dir;
3970         }
3971       
3972       if (count > 0)
3973         {
3974           pango_layout_move_cursor_visually (layout, strong, index, 0, 1, &new_index, &new_trailing);
3975           count--;
3976         }
3977       else
3978         {
3979           pango_layout_move_cursor_visually (layout, strong, index, 0, -1, &new_index, &new_trailing);
3980           count++;
3981         }
3982
3983       if (new_index < 0)
3984         index = 0;
3985       else if (new_index != G_MAXINT)
3986         index = new_index;
3987       
3988       while (new_trailing--)
3989         index = g_utf8_next_char (text + index) - text;
3990     }
3991   
3992   return g_utf8_pointer_to_offset (text, text + index);
3993 }
3994
3995 static gint
3996 gtk_entry_move_logically (GtkEntry *entry,
3997                           gint      start,
3998                           gint      count)
3999 {
4000   gint new_pos = start;
4001
4002   /* Prevent any leak of information */
4003   if (!entry->visible)
4004     {
4005       new_pos = CLAMP (start + count, 0, entry->text_length);
4006     }
4007   else if (entry->text)
4008     {
4009       PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE);
4010       PangoLogAttr *log_attrs;
4011       gint n_attrs;
4012
4013       pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
4014
4015       while (count > 0 && new_pos < entry->text_length)
4016         {
4017           do
4018             new_pos++;
4019           while (new_pos < entry->text_length && !log_attrs[new_pos].is_cursor_position);
4020           
4021           count--;
4022         }
4023       while (count < 0 && new_pos > 0)
4024         {
4025           do
4026             new_pos--;
4027           while (new_pos > 0 && !log_attrs[new_pos].is_cursor_position);
4028           
4029           count++;
4030         }
4031       
4032       g_free (log_attrs);
4033     }
4034
4035   return new_pos;
4036 }
4037
4038 static gint
4039 gtk_entry_move_forward_word (GtkEntry *entry,
4040                              gint      start,
4041                              gboolean  allow_whitespace)
4042 {
4043   gint new_pos = start;
4044
4045   /* Prevent any leak of information */
4046   if (!entry->visible)
4047     {
4048       new_pos = entry->text_length;
4049     }
4050   else if (entry->text && (new_pos < entry->text_length))
4051     {
4052       PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE);
4053       PangoLogAttr *log_attrs;
4054       gint n_attrs;
4055
4056       pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
4057       
4058       /* Find the next word boundary */
4059       new_pos++;
4060       while (new_pos < n_attrs - 1 && !(log_attrs[new_pos].is_word_end ||
4061                                         (log_attrs[new_pos].is_word_start && allow_whitespace)))
4062         new_pos++;
4063
4064       g_free (log_attrs);
4065     }
4066
4067   return new_pos;
4068 }
4069
4070
4071 static gint
4072 gtk_entry_move_backward_word (GtkEntry *entry,
4073                               gint      start,
4074                               gboolean  allow_whitespace)
4075 {
4076   gint new_pos = start;
4077
4078   /* Prevent any leak of information */
4079   if (!entry->visible)
4080     {
4081       new_pos = 0;
4082     }
4083   else if (entry->text && start > 0)
4084     {
4085       PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE);
4086       PangoLogAttr *log_attrs;
4087       gint n_attrs;
4088
4089       pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
4090
4091       new_pos = start - 1;
4092
4093       /* Find the previous word boundary */
4094       while (new_pos > 0 && !(log_attrs[new_pos].is_word_start || 
4095                               (log_attrs[new_pos].is_word_end && allow_whitespace)))
4096         new_pos--;
4097
4098       g_free (log_attrs);
4099     }
4100
4101   return new_pos;
4102 }
4103
4104 static void
4105 gtk_entry_delete_whitespace (GtkEntry *entry)
4106 {
4107   PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE);
4108   PangoLogAttr *log_attrs;
4109   gint n_attrs;
4110   gint start, end;
4111
4112   pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
4113
4114   start = end = entry->current_pos;
4115   
4116   while (start > 0 && log_attrs[start-1].is_white)
4117     start--;
4118
4119   while (end < n_attrs && log_attrs[end].is_white)
4120     end++;
4121
4122   g_free (log_attrs);
4123
4124   if (start != end)
4125     gtk_editable_delete_text (GTK_EDITABLE (entry), start, end);
4126 }
4127
4128
4129 static void
4130 gtk_entry_select_word (GtkEntry *entry)
4131 {
4132   gint start_pos = gtk_entry_move_backward_word (entry, entry->current_pos, TRUE);
4133   gint end_pos = gtk_entry_move_forward_word (entry, entry->current_pos, TRUE);
4134
4135   gtk_editable_select_region (GTK_EDITABLE (entry), start_pos, end_pos);
4136 }
4137
4138 static void
4139 gtk_entry_select_line (GtkEntry *entry)
4140 {
4141   gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
4142 }
4143
4144 /*
4145  * Like gtk_editable_get_chars, but handle not-visible entries
4146  * correctly.
4147  */
4148 static char *    
4149 gtk_entry_get_public_chars (GtkEntry *entry,
4150                             gint      start,
4151                             gint      end)
4152 {
4153   if (end < 0)
4154     end = entry->text_length;
4155   
4156   if (entry->visible)
4157     return gtk_editable_get_chars (GTK_EDITABLE (entry), start, end);
4158   else if (!entry->invisible_char)
4159     return g_strdup ("");
4160   else
4161     {
4162       GString *str = g_string_new (NULL);
4163       append_char (str, entry->invisible_char, end - start);
4164       return g_string_free (str, FALSE);
4165     }
4166 }
4167
4168 static gint
4169 truncate_multiline (const gchar *text)
4170 {
4171   gint length;
4172
4173   for (length = 0;
4174        text[length] && text[length] != '\n' && text[length] != '\r';
4175        length++);
4176
4177   return length;
4178 }
4179
4180 static void
4181 paste_received (GtkClipboard *clipboard,
4182                 const gchar  *text,
4183                 gpointer      data)
4184 {
4185   GtkEntry *entry = GTK_ENTRY (data);
4186   GtkEditable *editable = GTK_EDITABLE (entry);
4187   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
4188       
4189   if (entry->button == 2)
4190     {
4191       gint pos, start, end;
4192       pos = priv->insert_pos;
4193       gtk_editable_get_selection_bounds (editable, &start, &end);
4194       if (!((start <= pos && pos <= end) || (end <= pos && pos <= start)))
4195         gtk_editable_select_region (editable, pos, pos);
4196     }
4197       
4198   if (text)
4199     {
4200       gint pos, start, end;
4201       gint length = -1;
4202       gboolean popup_completion;
4203       GtkEntryCompletion *completion;
4204
4205       completion = gtk_entry_get_completion (entry);
4206
4207       if (entry->truncate_multiline)
4208         length = truncate_multiline (text);
4209
4210       /* only complete if the selection is at the end */
4211       popup_completion = (entry->text_length == MAX (entry->current_pos, entry->selection_bound));
4212
4213       if (completion)
4214         {
4215           if (GTK_WIDGET_MAPPED (completion->priv->popup_window))
4216             _gtk_entry_completion_popdown (completion);
4217
4218           if (!popup_completion && completion->priv->changed_id > 0)
4219             g_signal_handler_block (entry, completion->priv->changed_id);
4220         }
4221
4222       begin_change (entry);
4223       g_object_freeze_notify (G_OBJECT (entry));
4224       if (gtk_editable_get_selection_bounds (editable, &start, &end))
4225         gtk_editable_delete_text (editable, start, end);
4226
4227       pos = entry->current_pos;
4228       gtk_editable_insert_text (editable, text, length, &pos);
4229       gtk_editable_set_position (editable, pos);
4230       g_object_thaw_notify (G_OBJECT (entry));
4231       end_change (entry);
4232
4233       if (completion &&
4234           !popup_completion && completion->priv->changed_id > 0)
4235         g_signal_handler_unblock (entry, completion->priv->changed_id);
4236     }
4237
4238   g_object_unref (entry);
4239 }
4240
4241 static void
4242 gtk_entry_paste (GtkEntry *entry,
4243                  GdkAtom   selection)
4244 {
4245   g_object_ref (entry);
4246   gtk_clipboard_request_text (gtk_widget_get_clipboard (GTK_WIDGET (entry), selection),
4247                               paste_received, entry);
4248 }
4249
4250 static void
4251 primary_get_cb (GtkClipboard     *clipboard,
4252                 GtkSelectionData *selection_data,
4253                 guint             info,
4254                 gpointer          data)
4255 {
4256   GtkEntry *entry = GTK_ENTRY (data);
4257   gint start, end;
4258   
4259   if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end))
4260     {
4261       gchar *str = gtk_entry_get_public_chars (entry, start, end);
4262       gtk_selection_data_set_text (selection_data, str, -1);
4263       g_free (str);
4264     }
4265 }
4266
4267 static void
4268 primary_clear_cb (GtkClipboard *clipboard,
4269                   gpointer      data)
4270 {
4271   GtkEntry *entry = GTK_ENTRY (data);
4272
4273   gtk_editable_select_region (GTK_EDITABLE (entry), entry->current_pos, entry->current_pos);
4274 }
4275
4276 static void
4277 gtk_entry_update_primary_selection (GtkEntry *entry)
4278 {
4279   static GtkTargetEntry targets[] = {
4280     { "UTF8_STRING", 0, 0 },
4281     { "STRING", 0, 0 },
4282     { "TEXT",   0, 0 }, 
4283     { "COMPOUND_TEXT", 0, 0 },
4284     { "text/plain;charset=utf-8",   0, 0 }, 
4285     { NULL,   0, 0 },
4286     { "text/plain", 0, 0 }
4287   };
4288   
4289   GtkClipboard *clipboard;
4290   gint start, end;
4291
4292   if (targets[5].target == NULL)
4293     {
4294       const gchar *charset;
4295
4296       g_get_charset (&charset);
4297       targets[5].target = g_strdup_printf ("text/plain;charset=%s", charset);
4298     }
4299
4300   if (!GTK_WIDGET_REALIZED (entry))
4301     return;
4302
4303   clipboard = gtk_widget_get_clipboard (GTK_WIDGET (entry), GDK_SELECTION_PRIMARY);
4304   
4305   if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end))
4306     {
4307       if (!gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
4308                                          primary_get_cb, primary_clear_cb, G_OBJECT (entry)))
4309         primary_clear_cb (clipboard, entry);
4310     }
4311   else
4312     {
4313       if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (entry))
4314         gtk_clipboard_clear (clipboard);
4315     }
4316 }
4317
4318 /* Public API
4319  */
4320
4321 /**
4322  * gtk_entry_new:
4323  *
4324  * Creates a new entry.
4325  *
4326  * Return value: a new #GtkEntry.
4327  */
4328 GtkWidget*
4329 gtk_entry_new (void)
4330 {
4331   return g_object_new (GTK_TYPE_ENTRY, NULL);
4332 }
4333
4334 /**
4335  * gtk_entry_new_with_max_length:
4336  * @max: the maximum length of the entry, or 0 for no maximum.
4337  *   (other than the maximum length of entries.) The value passed in will
4338  *   be clamped to the range 0-65536.
4339  *
4340  * Creates a new #GtkEntry widget with the given maximum length.
4341  * 
4342  * Note: the existence of this function is inconsistent
4343  * with the rest of the GTK+ API. The normal setup would
4344  * be to just require the user to make an extra call
4345  * to gtk_entry_set_max_length() instead. It is not
4346  * expected that this function will be removed, but
4347  * it would be better practice not to use it.
4348  * 
4349  * Return value: a new #GtkEntry.
4350  **/
4351 GtkWidget*
4352 gtk_entry_new_with_max_length (gint max)
4353 {
4354   GtkEntry *entry;
4355
4356   max = CLAMP (max, 0, MAX_SIZE);
4357
4358   entry = g_object_new (GTK_TYPE_ENTRY, NULL);
4359   entry->text_max_length = max;
4360
4361   return GTK_WIDGET (entry);
4362 }
4363
4364 /**
4365  * gtk_entry_set_text:
4366  * @entry: a #GtkEntry
4367  * @text: the new text
4368  *
4369  * Sets the text in the widget to the given
4370  * value, replacing the current contents.
4371  */
4372 void
4373 gtk_entry_set_text (GtkEntry    *entry,
4374                     const gchar *text)
4375 {
4376   gint tmp_pos;
4377   GtkEntryCompletion *completion;
4378
4379   g_return_if_fail (GTK_IS_ENTRY (entry));
4380   g_return_if_fail (text != NULL);
4381
4382   /* Actually setting the text will affect the cursor and selection;
4383    * if the contents don't actually change, this will look odd to the user.
4384    */
4385   if (strcmp (entry->text, text) == 0)
4386     return;
4387
4388   completion = gtk_entry_get_completion (entry);
4389   if (completion && completion->priv->changed_id > 0)
4390     g_signal_handler_block (entry, completion->priv->changed_id);
4391
4392   begin_change (entry);
4393   g_object_freeze_notify (G_OBJECT (entry));
4394   gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1);
4395
4396   tmp_pos = 0;
4397   gtk_editable_insert_text (GTK_EDITABLE (entry), text, strlen (text), &tmp_pos);
4398   g_object_thaw_notify (G_OBJECT (entry));
4399   end_change (entry);
4400
4401   if (completion && completion->priv->changed_id > 0)
4402     g_signal_handler_unblock (entry, completion->priv->changed_id);
4403 }
4404
4405 /**
4406  * gtk_entry_append_text:
4407  * @entry: a #GtkEntry
4408  * @text: the text to append
4409  *
4410  * Appends the given text to the contents of the widget.
4411  *
4412  * Deprecated: gtk_entry_append_text() is deprecated and should not
4413  *   be used in newly-written code. Use gtk_editable_insert_text()
4414  *   instead.
4415  */
4416 void
4417 gtk_entry_append_text (GtkEntry *entry,
4418                        const gchar *text)
4419 {
4420   gint tmp_pos;
4421
4422   g_return_if_fail (GTK_IS_ENTRY (entry));
4423   g_return_if_fail (text != NULL);
4424
4425   tmp_pos = entry->text_length;
4426   gtk_editable_insert_text (GTK_EDITABLE (entry), text, -1, &tmp_pos);
4427 }
4428
4429 /**
4430  * gtk_entry_prepend_text:
4431  * @entry: a #GtkEntry
4432  * @text: the text to prepend
4433  *
4434  * Prepends the given text to the contents of the widget.
4435  *
4436  * Deprecated: gtk_entry_prepend_text() is deprecated and should not
4437  *    be used in newly-written code. Use gtk_editable_insert_text()
4438  *    instead.
4439  */
4440 void
4441 gtk_entry_prepend_text (GtkEntry *entry,
4442                         const gchar *text)
4443 {
4444   gint tmp_pos;
4445
4446   g_return_if_fail (GTK_IS_ENTRY (entry));
4447   g_return_if_fail (text != NULL);
4448
4449   tmp_pos = 0;
4450   gtk_editable_insert_text (GTK_EDITABLE (entry), text, -1, &tmp_pos);
4451 }
4452
4453 /**
4454  * gtk_entry_set_position:
4455  * @entry: a #GtkEntry
4456  * @position:  the position of the cursor. The cursor is displayed
4457  *    before the character with the given (base 0) index in the widget. 
4458  *    The value must be less than or equal to the number of characters 
4459  *    in the widget. A value of -1 indicates that the position should
4460  *    be set after the last character in the entry. Note that this 
4461  *    position is in characters, not in bytes.
4462  *
4463  * Sets the cursor position in an entry to the given value. 
4464  *
4465  * Deprecated: Use gtk_editable_set_position() instead.
4466  */
4467 void
4468 gtk_entry_set_position (GtkEntry *entry,
4469                         gint       position)
4470 {
4471   g_return_if_fail (GTK_IS_ENTRY (entry));
4472
4473   gtk_editable_set_position (GTK_EDITABLE (entry), position);
4474 }
4475
4476 /**
4477  * gtk_entry_set_visibility:
4478  * @entry: a #GtkEntry
4479  * @visible: %TRUE if the contents of the entry are displayed
4480  *           as plaintext
4481  *
4482  * Sets whether the contents of the entry are visible or not. 
4483  * When visibility is set to %FALSE, characters are displayed 
4484  * as the invisible char, and will also appear that way when 
4485  * the text in the entry widget is copied elsewhere.
4486  *
4487  * The default invisible char is the asterisk '*', but it can
4488  * be changed with gtk_entry_set_invisible_char().
4489  */
4490 void
4491 gtk_entry_set_visibility (GtkEntry *entry,
4492                           gboolean visible)
4493 {
4494   g_return_if_fail (GTK_IS_ENTRY (entry));
4495
4496   visible = visible != FALSE;
4497
4498   if (entry->visible != visible)
4499     {
4500       if (GTK_WIDGET_HAS_FOCUS (entry) && !visible)
4501         gtk_im_context_focus_out (entry->im_context);
4502
4503       g_object_unref (entry->im_context);
4504
4505       if (visible)
4506         entry->im_context = gtk_im_multicontext_new ();
4507       else
4508         entry->im_context = gtk_im_context_simple_new ();
4509       
4510       g_signal_connect (entry->im_context, "commit",
4511                         G_CALLBACK (gtk_entry_commit_cb), entry);
4512       g_signal_connect (entry->im_context, "preedit_changed",
4513                         G_CALLBACK (gtk_entry_preedit_changed_cb), entry);
4514       g_signal_connect (entry->im_context, "retrieve_surrounding",
4515                         G_CALLBACK (gtk_entry_retrieve_surrounding_cb), entry);
4516       g_signal_connect (entry->im_context, "delete_surrounding",
4517                         G_CALLBACK (gtk_entry_delete_surrounding_cb), entry);
4518
4519       if (GTK_WIDGET_HAS_FOCUS (entry) && visible)
4520         gtk_im_context_focus_in (entry->im_context); 
4521
4522       entry->visible = visible;
4523
4524       g_object_notify (G_OBJECT (entry), "visibility");
4525       gtk_entry_recompute (entry);
4526     }
4527 }
4528
4529 /**
4530  * gtk_entry_get_visibility:
4531  * @entry: a #GtkEntry
4532  *
4533  * Retrieves whether the text in @entry is visible. See
4534  * gtk_entry_set_visibility().
4535  *
4536  * Return value: %TRUE if the text is currently visible
4537  **/
4538 gboolean
4539 gtk_entry_get_visibility (GtkEntry *entry)
4540 {
4541   g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
4542
4543   return entry->visible;
4544 }
4545
4546 /**
4547  * gtk_entry_set_invisible_char:
4548  * @entry: a #GtkEntry
4549  * @ch: a Unicode character
4550  * 
4551  * Sets the character to use in place of the actual text when
4552  * gtk_entry_set_visibility() has been called to set text visibility
4553  * to %FALSE. i.e. this is the character used in "password mode" to
4554  * show the user how many characters have been typed. The default
4555  * invisible char is an asterisk ('*').  If you set the invisible char
4556  * to 0, then the user will get no feedback at all; there will be
4557  * no text on the screen as they type.
4558  **/
4559 void
4560 gtk_entry_set_invisible_char (GtkEntry *entry,
4561                               gunichar  ch)
4562 {
4563   g_return_if_fail (GTK_IS_ENTRY (entry));
4564
4565   if (ch == entry->invisible_char)
4566     return;
4567
4568   entry->invisible_char = ch;
4569   g_object_notify (G_OBJECT (entry), "invisible-char");
4570   gtk_entry_recompute (entry);  
4571 }
4572
4573 /**
4574  * gtk_entry_get_invisible_char:
4575  * @entry: a #GtkEntry
4576  *
4577  * Retrieves the character displayed in place of the real characters
4578  * for entries with visibility set to false. See gtk_entry_set_invisible_char().
4579  *
4580  * Return value: the current invisible char, or 0, if the entry does not
4581  *               show invisible text at all. 
4582  **/
4583 gunichar
4584 gtk_entry_get_invisible_char (GtkEntry *entry)
4585 {
4586   g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
4587
4588   return entry->invisible_char;
4589 }
4590
4591 /**
4592  * gtk_entry_set_editable:
4593  * @entry: a #GtkEntry
4594  * @editable: %TRUE if the user is allowed to edit the text
4595  *   in the widget
4596  *
4597  * Determines if the user can edit the text in the editable
4598  * widget or not. 
4599  *
4600  * Deprecated: Use gtk_editable_set_editable() instead.
4601  */
4602 void
4603 gtk_entry_set_editable (GtkEntry *entry,
4604                         gboolean  editable)
4605 {
4606   g_return_if_fail (GTK_IS_ENTRY (entry));
4607
4608   gtk_editable_set_editable (GTK_EDITABLE (entry), editable);
4609 }
4610
4611 /**
4612  * gtk_entry_get_text:
4613  * @entry: a #GtkEntry
4614  *
4615  * Retrieves the contents of the entry widget.
4616  * See also gtk_editable_get_chars().
4617  *
4618  * Return value: a pointer to the contents of the widget as a
4619  *      string. This string points to internally allocated
4620  *      storage in the widget and must not be freed, modified or
4621  *      stored.
4622  **/
4623 G_CONST_RETURN gchar*
4624 gtk_entry_get_text (GtkEntry *entry)
4625 {
4626   g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
4627
4628   return entry->text;
4629 }
4630
4631 /**
4632  * gtk_entry_select_region:
4633  * @entry: a #GtkEntry
4634  * @start: the starting position
4635  * @end: the end position
4636  *
4637  * Selects a region of text. The characters that are selected are 
4638  * those characters at positions from @start_pos up to, but not 
4639  * including @end_pos. If @end_pos is negative, then the the characters 
4640  * selected will be those characters from @start_pos to the end of 
4641  * the text. 
4642  *
4643  * Deprecated: Use gtk_editable_select_region() instead.
4644  */
4645 void       
4646 gtk_entry_select_region  (GtkEntry       *entry,
4647                           gint            start,
4648                           gint            end)
4649 {
4650   gtk_editable_select_region (GTK_EDITABLE (entry), start, end);
4651 }
4652
4653 /**
4654  * gtk_entry_set_max_length:
4655  * @entry: a #GtkEntry
4656  * @max: the maximum length of the entry, or 0 for no maximum.
4657  *   (other than the maximum length of entries.) The value passed in will
4658  *   be clamped to the range 0-65536.
4659  * 
4660  * Sets the maximum allowed length of the contents of the widget. If
4661  * the current contents are longer than the given length, then they
4662  * will be truncated to fit.
4663  **/
4664 void
4665 gtk_entry_set_max_length (GtkEntry     *entry,
4666                           gint          max)
4667 {
4668   g_return_if_fail (GTK_IS_ENTRY (entry));
4669
4670   max = CLAMP (max, 0, MAX_SIZE);
4671
4672   if (max > 0 && entry->text_length > max)
4673     gtk_editable_delete_text (GTK_EDITABLE (entry), max, -1);
4674   
4675   entry->text_max_length = max;
4676   g_object_notify (G_OBJECT (entry), "max-length");
4677 }
4678
4679 /**
4680  * gtk_entry_get_max_length:
4681  * @entry: a #GtkEntry
4682  *
4683  * Retrieves the maximum allowed length of the text in
4684  * @entry. See gtk_entry_set_max_length().
4685  *
4686  * Return value: the maximum allowed number of characters
4687  *               in #GtkEntry, or 0 if there is no maximum.
4688  **/
4689 gint
4690 gtk_entry_get_max_length (GtkEntry *entry)
4691 {
4692   g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
4693
4694   return entry->text_max_length;
4695 }
4696
4697 /**
4698  * gtk_entry_set_activates_default:
4699  * @entry: a #GtkEntry
4700  * @setting: %TRUE to activate window's default widget on Enter keypress
4701  *
4702  * If @setting is %TRUE, pressing Enter in the @entry will activate the default
4703  * widget for the window containing the entry. This usually means that
4704  * the dialog box containing the entry will be closed, since the default
4705  * widget is usually one of the dialog buttons.
4706  *
4707  * (For experts: if @setting is %TRUE, the entry calls
4708  * gtk_window_activate_default() on the window containing the entry, in
4709  * the default handler for the #GtkWidget::activate signal.)
4710  **/
4711 void
4712 gtk_entry_set_activates_default (GtkEntry *entry,
4713                                  gboolean  setting)
4714 {
4715   g_return_if_fail (GTK_IS_ENTRY (entry));
4716   setting = setting != FALSE;
4717
4718   if (setting != entry->activates_default)
4719     {
4720       entry->activates_default = setting;
4721       g_object_notify (G_OBJECT (entry), "activates-default");
4722     }
4723 }
4724
4725 /**
4726  * gtk_entry_get_activates_default:
4727  * @entry: a #GtkEntry
4728  * 
4729  * Retrieves the value set by gtk_entry_set_activates_default().
4730  * 
4731  * Return value: %TRUE if the entry will activate the default widget
4732  **/
4733 gboolean
4734 gtk_entry_get_activates_default (GtkEntry *entry)
4735 {
4736   g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
4737
4738   return entry->activates_default;
4739 }
4740
4741 /**
4742  * gtk_entry_set_width_chars:
4743  * @entry: a #GtkEntry
4744  * @n_chars: width in chars
4745  *
4746  * Changes the size request of the entry to be about the right size
4747  * for @n_chars characters. Note that it changes the size
4748  * <emphasis>request</emphasis>, the size can still be affected by
4749  * how you pack the widget into containers. If @n_chars is -1, the
4750  * size reverts to the default entry size.
4751  **/
4752 void
4753 gtk_entry_set_width_chars (GtkEntry *entry,
4754                            gint      n_chars)
4755 {
4756   g_return_if_fail (GTK_IS_ENTRY (entry));
4757
4758   if (entry->width_chars != n_chars)
4759     {
4760       entry->width_chars = n_chars;
4761       g_object_notify (G_OBJECT (entry), "width-chars");
4762       gtk_widget_queue_resize (GTK_WIDGET (entry));
4763     }
4764 }
4765
4766 /**
4767  * gtk_entry_get_width_chars:
4768  * @entry: a #GtkEntry
4769  * 
4770  * Gets the value set by gtk_entry_set_width_chars().
4771  * 
4772  * Return value: number of chars to request space for, or negative if unset
4773  **/
4774 gint
4775 gtk_entry_get_width_chars (GtkEntry *entry)
4776 {
4777   g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
4778
4779   return entry->width_chars;
4780 }
4781
4782 /**
4783  * gtk_entry_set_has_frame:
4784  * @entry: a #GtkEntry
4785  * @setting: new value
4786  * 
4787  * Sets whether the entry has a beveled frame around it.
4788  **/
4789 void
4790 gtk_entry_set_has_frame (GtkEntry *entry,
4791                          gboolean  setting)
4792 {
4793   g_return_if_fail (GTK_IS_ENTRY (entry));
4794
4795   setting = (setting != FALSE);
4796
4797   if (entry->has_frame == setting)
4798     return;
4799
4800   gtk_widget_queue_resize (GTK_WIDGET (entry));
4801   entry->has_frame = setting;
4802   g_object_notify (G_OBJECT (entry), "has-frame");
4803 }
4804
4805 /**
4806  * gtk_entry_get_has_frame:
4807  * @entry: a #GtkEntry
4808  * 
4809  * Gets the value set by gtk_entry_set_has_frame().
4810  * 
4811  * Return value: whether the entry has a beveled frame
4812  **/
4813 gboolean
4814 gtk_entry_get_has_frame (GtkEntry *entry)
4815 {
4816   g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
4817
4818   return entry->has_frame;
4819 }
4820
4821 /**
4822  * gtk_entry_set_inner_border:
4823  * @entry: a #GtkEntry
4824  * @border: a #GtkBorder, or %NULL
4825  *
4826  * Sets %entry's inner-border property to %border, or clears it if %NULL
4827  * is passed. The inner-border is the area around the entry's text, but
4828  * inside its frame.
4829  *
4830  * If set, this property overrides the inner-border style property.
4831  * Overriding the style-provided border is useful when you want to do
4832  * in-place editing of some text in a canvas or list widget, where
4833  * pixel-exact positioning of the entry is important.
4834  *
4835  * Since: 2.10
4836  **/
4837 void
4838 gtk_entry_set_inner_border (GtkEntry        *entry,
4839                             const GtkBorder *border)
4840 {
4841   g_return_if_fail (GTK_IS_ENTRY (entry));
4842
4843   gtk_widget_queue_resize (GTK_WIDGET (entry));
4844
4845   if (border)
4846     g_object_set_qdata_full (G_OBJECT (entry), quark_inner_border,
4847                              gtk_border_copy (border),
4848                              (GDestroyNotify) gtk_border_free);
4849   else
4850     g_object_set_qdata (G_OBJECT (entry), quark_inner_border, NULL);
4851
4852   g_object_notify (G_OBJECT (entry), "inner-border");
4853 }
4854
4855 /**
4856  * gtk_entry_get_inner_border:
4857  * @entry: a #GtkEntry
4858  *
4859  * This function returns the entry's #GtkEntry:inner-border property. See
4860  * gtk_entry_set_inner_border() for more information.
4861  *
4862  * Return value: the entry's #GtkBorder, or %NULL if none was set.
4863  *
4864  * Since: 2.10
4865  **/
4866 G_CONST_RETURN GtkBorder *
4867 gtk_entry_get_inner_border (GtkEntry *entry)
4868 {
4869   g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
4870
4871   return g_object_get_qdata (G_OBJECT (entry), quark_inner_border);
4872 }
4873
4874 /**
4875  * gtk_entry_get_layout:
4876  * @entry: a #GtkEntry
4877  * 
4878  * Gets the #PangoLayout used to display the entry.
4879  * The layout is useful to e.g. convert text positions to
4880  * pixel positions, in combination with gtk_entry_get_layout_offsets().
4881  * The returned layout is owned by the entry and must not be 
4882  * modified or freed by the caller.
4883  *
4884  * Keep in mind that the layout text may contain a preedit string, so
4885  * gtk_entry_layout_index_to_text_index() and
4886  * gtk_entry_text_index_to_layout_index() are needed to convert byte
4887  * indices in the layout to byte indices in the entry contents.
4888  * 
4889  * Return value: the #PangoLayout for this entry
4890  **/
4891 PangoLayout*
4892 gtk_entry_get_layout (GtkEntry *entry)
4893 {
4894   PangoLayout *layout;
4895   
4896   g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
4897
4898   layout = gtk_entry_ensure_layout (entry, TRUE);
4899
4900   return layout;
4901 }
4902
4903
4904 /**
4905  * gtk_entry_layout_index_to_text_index:
4906  * @entry: a #GtkEntry
4907  * @layout_index: byte index into the entry layout text
4908  * 
4909  * Converts from a position in the entry contents (returned
4910  * by gtk_entry_get_text()) to a position in the
4911  * entry's #PangoLayout (returned by gtk_entry_get_layout(),
4912  * with text retrieved via pango_layout_get_text()).
4913  * 
4914  * Return value: byte index into the entry contents
4915  **/
4916 gint
4917 gtk_entry_layout_index_to_text_index (GtkEntry *entry,
4918                                       gint      layout_index)
4919 {
4920   PangoLayout *layout;
4921   const gchar *text;
4922   gint cursor_index;
4923   
4924   g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
4925
4926   layout = gtk_entry_ensure_layout (entry, TRUE);
4927   text = pango_layout_get_text (layout);
4928   cursor_index = g_utf8_offset_to_pointer (text, entry->current_pos) - text;
4929   
4930   if (layout_index >= cursor_index && entry->preedit_length)
4931     {
4932       if (layout_index >= cursor_index + entry->preedit_length)
4933         layout_index -= entry->preedit_length;
4934       else
4935         layout_index = cursor_index;
4936     }
4937
4938   return layout_index;
4939 }
4940
4941 /**
4942  * gtk_entry_text_index_to_layout_index:
4943  * @entry: a #GtkEntry
4944  * @text_index: byte index into the entry contents
4945  * 
4946  * Converts from a position in the entry's #PangoLayout (returned by
4947  * gtk_entry_get_layout()) to a position in the entry contents
4948  * (returned by gtk_entry_get_text()).
4949  * 
4950  * Return value: byte index into the entry layout text
4951  **/
4952 gint
4953 gtk_entry_text_index_to_layout_index (GtkEntry *entry,
4954                                       gint      text_index)
4955 {
4956   PangoLayout *layout;
4957   const gchar *text;
4958   gint cursor_index;
4959   g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
4960
4961   layout = gtk_entry_ensure_layout (entry, TRUE);
4962   text = pango_layout_get_text (layout);
4963   cursor_index = g_utf8_offset_to_pointer (text, entry->current_pos) - text;
4964   
4965   if (text_index > cursor_index)
4966     text_index += entry->preedit_length;
4967
4968   return text_index;
4969 }
4970
4971 /**
4972  * gtk_entry_get_layout_offsets:
4973  * @entry: a #GtkEntry
4974  * @x: location to store X offset of layout, or %NULL
4975  * @y: location to store Y offset of layout, or %NULL
4976  *
4977  *
4978  * Obtains the position of the #PangoLayout used to render text
4979  * in the entry, in widget coordinates. Useful if you want to line
4980  * up the text in an entry with some other text, e.g. when using the
4981  * entry to implement editable cells in a sheet widget.
4982  *
4983  * Also useful to convert mouse events into coordinates inside the
4984  * #PangoLayout, e.g. to take some action if some part of the entry text
4985  * is clicked.
4986  * 
4987  * Note that as the user scrolls around in the entry the offsets will
4988  * change; you'll need to connect to the "notify::scroll-offset"
4989  * signal to track this. Remember when using the #PangoLayout
4990  * functions you need to convert to and from pixels using
4991  * PANGO_PIXELS() or #PANGO_SCALE.
4992  *
4993  * Keep in mind that the layout text may contain a preedit string, so
4994  * gtk_entry_layout_index_to_text_index() and
4995  * gtk_entry_text_index_to_layout_index() are needed to convert byte
4996  * indices in the layout to byte indices in the entry contents.
4997  **/
4998 void
4999 gtk_entry_get_layout_offsets (GtkEntry *entry,
5000                               gint     *x,
5001                               gint     *y)
5002 {
5003   gint text_area_x, text_area_y;
5004   
5005   g_return_if_fail (GTK_IS_ENTRY (entry));
5006
5007   /* this gets coords relative to text area */
5008   get_layout_position (entry, x, y);
5009
5010   /* convert to widget coords */
5011   get_text_area_size (entry, &text_area_x, &text_area_y, NULL, NULL);
5012   
5013   if (x)
5014     *x += text_area_x;
5015
5016   if (y)
5017     *y += text_area_y;
5018 }
5019
5020
5021 /**
5022  * gtk_entry_set_alignment:
5023  * @entry: a #GtkEntry
5024  * @xalign: The horizontal alignment, from 0 (left) to 1 (right).
5025  *          Reversed for RTL layouts
5026  * 
5027  * Sets the alignment for the contents of the entry. This controls
5028  * the horizontal positioning of the contents when the displayed
5029  * text is shorter than the width of the entry.
5030  *
5031  * Since: 2.4
5032  **/
5033 void
5034 gtk_entry_set_alignment (GtkEntry *entry, gfloat xalign)
5035 {
5036   GtkEntryPrivate *priv;
5037   
5038   g_return_if_fail (GTK_IS_ENTRY (entry));
5039
5040   priv = GTK_ENTRY_GET_PRIVATE (entry);
5041
5042   if (xalign < 0.0)
5043     xalign = 0.0;
5044   else if (xalign > 1.0)
5045     xalign = 1.0;
5046
5047   if (xalign != priv->xalign)
5048     {
5049       priv->xalign = xalign;
5050
5051       gtk_entry_recompute (entry);
5052
5053       g_object_notify (G_OBJECT (entry), "xalign");
5054     }
5055 }
5056
5057 /**
5058  * gtk_entry_get_alignment:
5059  * @entry: a #GtkEntry
5060  * 
5061  * Gets the value set by gtk_entry_set_alignment().
5062  * 
5063  * Return value: the alignment
5064  *
5065  * Since: 2.4
5066  **/
5067 gfloat
5068 gtk_entry_get_alignment (GtkEntry *entry)
5069 {
5070   GtkEntryPrivate *priv;
5071   
5072   g_return_val_if_fail (GTK_IS_ENTRY (entry), 0.0);
5073
5074   priv = GTK_ENTRY_GET_PRIVATE (entry);
5075
5076   return priv->xalign;
5077 }
5078
5079 /* Quick hack of a popup menu
5080  */
5081 static void
5082 activate_cb (GtkWidget *menuitem,
5083              GtkEntry  *entry)
5084 {
5085   const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
5086   g_signal_emit_by_name (entry, signal);
5087 }
5088
5089
5090 static gboolean
5091 gtk_entry_mnemonic_activate (GtkWidget *widget,
5092                              gboolean   group_cycling)
5093 {
5094   gtk_widget_grab_focus (widget);
5095   return TRUE;
5096 }
5097
5098 static void
5099 append_action_signal (GtkEntry     *entry,
5100                       GtkWidget    *menu,
5101                       const gchar  *stock_id,
5102                       const gchar  *signal,
5103                       gboolean      sensitive)
5104 {
5105   GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
5106
5107   g_object_set_data (G_OBJECT (menuitem), I_("gtk-signal"), (char *)signal);
5108   g_signal_connect (menuitem, "activate",
5109                     G_CALLBACK (activate_cb), entry);
5110
5111   gtk_widget_set_sensitive (menuitem, sensitive);
5112   
5113   gtk_widget_show (menuitem);
5114   gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
5115 }
5116         
5117 static void
5118 popup_menu_detach (GtkWidget *attach_widget,
5119                    GtkMenu   *menu)
5120 {
5121   GTK_ENTRY (attach_widget)->popup_menu = NULL;
5122 }
5123
5124 static void
5125 popup_position_func (GtkMenu   *menu,
5126                      gint      *x,
5127                      gint      *y,
5128                      gboolean  *push_in,
5129                      gpointer   user_data)
5130 {
5131   GtkEntry *entry = GTK_ENTRY (user_data);
5132   GtkWidget *widget = GTK_WIDGET (entry);
5133   GdkScreen *screen;
5134   GtkRequisition menu_req;
5135   GdkRectangle monitor;
5136   GtkBorder inner_border;
5137   gint monitor_num, strong_x, height;
5138  
5139   g_return_if_fail (GTK_WIDGET_REALIZED (entry));
5140
5141   gdk_window_get_origin (entry->text_area, x, y);
5142
5143   screen = gtk_widget_get_screen (widget);
5144   monitor_num = gdk_screen_get_monitor_at_window (screen, entry->text_area);
5145   if (monitor_num < 0)
5146     monitor_num = 0;
5147   gtk_menu_set_monitor (menu, monitor_num);
5148
5149   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
5150   gtk_widget_size_request (entry->popup_menu, &menu_req);
5151   gdk_drawable_get_size (entry->text_area, NULL, &height);
5152   gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, NULL);
5153   _gtk_entry_effective_inner_border (entry, &inner_border);
5154
5155   *x += inner_border.left + strong_x - entry->scroll_offset;
5156   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
5157     *x -= menu_req.width;
5158
5159   if ((*y + height + menu_req.height) <= monitor.y + monitor.height)
5160     *y += height;
5161   else if ((*y - menu_req.height) >= monitor.y)
5162     *y -= menu_req.height;
5163   else if (monitor.y + monitor.height - (*y + height) > *y)
5164     *y += height;
5165   else
5166     *y -= menu_req.height;
5167
5168   *push_in = FALSE;
5169 }
5170
5171 static void
5172 unichar_chosen_func (const char *text,
5173                      gpointer    data)
5174 {
5175   GtkEntry *entry = GTK_ENTRY (data);
5176
5177   if (entry->editable)
5178     gtk_entry_enter_text (entry, text);
5179 }
5180
5181 typedef struct
5182 {
5183   GtkEntry *entry;
5184   gint button;
5185   guint time;
5186 } PopupInfo;
5187
5188 static void
5189 popup_targets_received (GtkClipboard     *clipboard,
5190                         GtkSelectionData *data,
5191                         gpointer          user_data)
5192 {
5193   PopupInfo *info = user_data;
5194   GtkEntry *entry = info->entry;
5195   
5196   if (GTK_WIDGET_REALIZED (entry))
5197     {
5198       gboolean clipboard_contains_text;
5199       GtkWidget *menuitem;
5200       GtkWidget *submenu;
5201       gboolean show_input_method_menu;
5202       gboolean show_unicode_menu;
5203       
5204         clipboard_contains_text = gtk_selection_data_targets_include_text (data);
5205       if (entry->popup_menu)
5206         gtk_widget_destroy (entry->popup_menu);
5207       
5208       entry->popup_menu = gtk_menu_new ();
5209       
5210       gtk_menu_attach_to_widget (GTK_MENU (entry->popup_menu),
5211                                  GTK_WIDGET (entry),
5212                                  popup_menu_detach);
5213       
5214       append_action_signal (entry, entry->popup_menu, GTK_STOCK_CUT, "cut_clipboard",
5215                             entry->editable && entry->current_pos != entry->selection_bound);
5216       append_action_signal (entry, entry->popup_menu, GTK_STOCK_COPY, "copy_clipboard",
5217                             entry->current_pos != entry->selection_bound);
5218       append_action_signal (entry, entry->popup_menu, GTK_STOCK_PASTE, "paste_clipboard",
5219                             entry->editable && clipboard_contains_text);
5220       
5221       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_DELETE, NULL);
5222       gtk_widget_set_sensitive (menuitem, entry->editable && entry->current_pos != entry->selection_bound);
5223       g_signal_connect_swapped (menuitem, "activate",
5224                                 G_CALLBACK (gtk_entry_delete_cb), entry);
5225       gtk_widget_show (menuitem);
5226       gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);
5227
5228       menuitem = gtk_separator_menu_item_new ();
5229       gtk_widget_show (menuitem);
5230       gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);
5231       
5232       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SELECT_ALL, NULL);
5233       g_signal_connect_swapped (menuitem, "activate",
5234                                 G_CALLBACK (gtk_entry_select_all), entry);
5235       gtk_widget_show (menuitem);
5236       gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);
5237       
5238       g_object_get (gtk_widget_get_settings (GTK_WIDGET (entry)),
5239                     "gtk-show-input-method-menu", &show_input_method_menu,
5240                     "gtk-show-unicode-menu", &show_unicode_menu,
5241                     NULL);
5242
5243       if (!entry->visible)
5244         show_input_method_menu = FALSE;
5245
5246       if (show_input_method_menu || show_unicode_menu)
5247         {
5248           menuitem = gtk_separator_menu_item_new ();
5249           gtk_widget_show (menuitem);
5250           gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);
5251         }
5252       
5253       if (show_input_method_menu)
5254         {
5255           menuitem = gtk_menu_item_new_with_mnemonic (_("Input _Methods"));
5256           gtk_widget_set_sensitive (menuitem, entry->editable);      
5257           gtk_widget_show (menuitem);
5258           submenu = gtk_menu_new ();
5259           gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
5260           
5261           gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);
5262       
5263           gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (entry->im_context),
5264                                                 GTK_MENU_SHELL (submenu));
5265         }
5266       
5267       if (show_unicode_menu)
5268         {
5269           menuitem = gtk_menu_item_new_with_mnemonic (_("_Insert Unicode Control Character"));
5270           gtk_widget_set_sensitive (menuitem, entry->editable);      
5271           gtk_widget_show (menuitem);
5272           
5273           submenu = gtk_menu_new ();
5274           gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
5275           gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);      
5276           
5277           _gtk_text_util_append_special_char_menuitems (GTK_MENU_SHELL (submenu),
5278                                                         unichar_chosen_func,
5279                                                         entry);
5280         }
5281       
5282       g_signal_emit (entry,
5283                      signals[POPULATE_POPUP],
5284                      0,
5285                      entry->popup_menu);
5286   
5287
5288       if (info->button)
5289         gtk_menu_popup (GTK_MENU (entry->popup_menu), NULL, NULL,
5290                         NULL, NULL,
5291                         info->button, info->time);
5292       else
5293         {
5294           gtk_menu_popup (GTK_MENU (entry->popup_menu), NULL, NULL,
5295                           popup_position_func, entry,
5296                           info->button, info->time);
5297           gtk_menu_shell_select_first (GTK_MENU_SHELL (entry->popup_menu), FALSE);
5298         }
5299     }
5300
5301   g_object_unref (entry);
5302   g_free (info);
5303 }
5304                         
5305 static void
5306 gtk_entry_do_popup (GtkEntry       *entry,
5307                     GdkEventButton *event)
5308 {
5309   PopupInfo *info = g_new (PopupInfo, 1);
5310
5311   /* In order to know what entries we should make sensitive, we
5312    * ask for the current targets of the clipboard, and when
5313    * we get them, then we actually pop up the menu.
5314    */
5315   info->entry = g_object_ref (entry);
5316   
5317   if (event)
5318     {
5319       info->button = event->button;
5320       info->time = event->time;
5321     }
5322   else
5323     {
5324       info->button = 0;
5325       info->time = gtk_get_current_event_time ();
5326     }
5327
5328   gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (entry), GDK_SELECTION_CLIPBOARD),
5329                                   gdk_atom_intern_static_string ("TARGETS"),
5330                                   popup_targets_received,
5331                                   info);
5332 }
5333
5334 static gboolean
5335 gtk_entry_popup_menu (GtkWidget *widget)
5336 {
5337   gtk_entry_do_popup (GTK_ENTRY (widget), NULL);
5338   return TRUE;
5339 }
5340
5341 static void
5342 gtk_entry_drag_leave (GtkWidget        *widget,
5343                       GdkDragContext   *context,
5344                       guint             time)
5345 {
5346   GtkEntry *entry = GTK_ENTRY (widget);
5347
5348   entry->dnd_position = -1;
5349   gtk_widget_queue_draw (widget);
5350 }
5351
5352 static gboolean
5353 gtk_entry_drag_drop  (GtkWidget        *widget,
5354                       GdkDragContext   *context,
5355                       gint              x,
5356                       gint              y,
5357                       guint             time)
5358 {
5359   GtkEntry *entry = GTK_ENTRY (widget);
5360   GdkAtom target = GDK_NONE;
5361   
5362   if (entry->editable)
5363     target = gtk_drag_dest_find_target (widget, context, NULL);
5364
5365   if (target != GDK_NONE)
5366     gtk_drag_get_data (widget, context, target, time);
5367   else
5368     gtk_drag_finish (context, FALSE, FALSE, time);
5369   
5370   return TRUE;
5371 }
5372
5373 static gboolean
5374 gtk_entry_drag_motion (GtkWidget        *widget,
5375                        GdkDragContext   *context,
5376                        gint              x,
5377                        gint              y,
5378                        guint             time)
5379 {
5380   GtkEntry *entry = GTK_ENTRY (widget);
5381   GtkWidget *source_widget;
5382   GdkDragAction suggested_action;
5383   gint new_position, old_position;
5384   gint sel1, sel2;
5385   
5386   x -= widget->style->xthickness;
5387   y -= widget->style->ythickness;
5388   
5389   old_position = entry->dnd_position;
5390   new_position = gtk_entry_find_position (entry, x + entry->scroll_offset);
5391
5392   if (entry->editable &&
5393       gtk_drag_dest_find_target (widget, context, NULL) != GDK_NONE)
5394     {
5395       source_widget = gtk_drag_get_source_widget (context);
5396       suggested_action = context->suggested_action;
5397
5398       if (!gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &sel1, &sel2) ||
5399           new_position < sel1 || new_position > sel2)
5400         {
5401           if (source_widget == widget)
5402             {
5403               /* Default to MOVE, unless the user has
5404                * pressed ctrl or alt to affect available actions
5405                */
5406               if ((context->actions & GDK_ACTION_MOVE) != 0)
5407                 suggested_action = GDK_ACTION_MOVE;
5408             }
5409               
5410           entry->dnd_position = new_position;
5411         }
5412       else
5413         {
5414           if (source_widget == widget)
5415             suggested_action = 0;       /* Can't drop in selection where drag started */
5416           
5417           entry->dnd_position = -1;
5418         }
5419     }
5420   else
5421     {
5422       /* Entry not editable, or no text */
5423       suggested_action = 0;
5424       entry->dnd_position = -1;
5425     }
5426   
5427   gdk_drag_status (context, suggested_action, time);
5428   
5429   if (entry->dnd_position != old_position)
5430     gtk_widget_queue_draw (widget);
5431
5432   return TRUE;
5433 }
5434
5435 static void
5436 gtk_entry_drag_data_received (GtkWidget        *widget,
5437                               GdkDragContext   *context,
5438                               gint              x,
5439                               gint              y,
5440                               GtkSelectionData *selection_data,
5441                               guint             info,
5442                               guint             time)
5443 {
5444   GtkEntry *entry = GTK_ENTRY (widget);
5445   GtkEditable *editable = GTK_EDITABLE (widget);
5446   gchar *str;
5447
5448   str = (gchar *) gtk_selection_data_get_text (selection_data);
5449
5450   x -= widget->style->xthickness;
5451   y -= widget->style->ythickness;
5452
5453   if (str && entry->editable)
5454     {
5455       gint new_position;
5456       gint sel1, sel2;
5457       gint length = -1;
5458
5459       if (entry->truncate_multiline)
5460         length = truncate_multiline (str);
5461
5462       new_position = gtk_entry_find_position (entry, x + entry->scroll_offset);
5463
5464       if (!gtk_editable_get_selection_bounds (editable, &sel1, &sel2) ||
5465           new_position < sel1 || new_position > sel2)
5466         {
5467           gtk_editable_insert_text (editable, str, length, &new_position);
5468         }
5469       else
5470         {
5471           /* Replacing selection */
5472           begin_change (entry);
5473           g_object_freeze_notify (G_OBJECT (entry));
5474           gtk_editable_delete_text (editable, sel1, sel2);
5475           gtk_editable_insert_text (editable, str, length, &sel1);
5476           g_object_thaw_notify (G_OBJECT (entry));
5477           end_change (entry);
5478         }
5479       
5480       gtk_drag_finish (context, TRUE, context->action == GDK_ACTION_MOVE, time);
5481     }
5482   else
5483     {
5484       /* Drag and drop didn't happen! */
5485       gtk_drag_finish (context, FALSE, FALSE, time);
5486     }
5487
5488   g_free (str);
5489 }
5490
5491 static void
5492 gtk_entry_drag_data_get (GtkWidget        *widget,
5493                          GdkDragContext   *context,
5494                          GtkSelectionData *selection_data,
5495                          guint             info,
5496                          guint             time)
5497 {
5498   gint sel_start, sel_end;
5499
5500   GtkEditable *editable = GTK_EDITABLE (widget);
5501   
5502   if (gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end))
5503     {
5504       gchar *str = gtk_entry_get_public_chars (GTK_ENTRY (widget), sel_start, sel_end);
5505
5506       gtk_selection_data_set_text (selection_data, str, -1);
5507       
5508       g_free (str);
5509     }
5510
5511 }
5512
5513 static void
5514 gtk_entry_drag_data_delete (GtkWidget      *widget,
5515                             GdkDragContext *context)
5516 {
5517   gint sel_start, sel_end;
5518
5519   GtkEditable *editable = GTK_EDITABLE (widget);
5520   
5521   if (GTK_ENTRY (widget)->editable &&
5522       gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end))
5523     gtk_editable_delete_text (editable, sel_start, sel_end);
5524 }
5525
5526 /* We display the cursor when
5527  *
5528  *  - the selection is empty, AND
5529  *  - the widget has focus
5530  */
5531
5532 #define CURSOR_ON_MULTIPLIER 2
5533 #define CURSOR_OFF_MULTIPLIER 1
5534 #define CURSOR_PEND_MULTIPLIER 3
5535 #define CURSOR_DIVIDER 3
5536
5537 static gboolean
5538 cursor_blinks (GtkEntry *entry)
5539 {
5540   if (GTK_WIDGET_HAS_FOCUS (entry) &&
5541       entry->editable &&
5542       entry->selection_bound == entry->current_pos)
5543     {
5544       GtkSettings *settings;
5545       gboolean blink;
5546
5547       settings = gtk_widget_get_settings (GTK_WIDGET (entry));
5548       g_object_get (settings, "gtk-cursor-blink", &blink, NULL);
5549
5550       return blink;
5551     }
5552   else
5553     return FALSE;
5554 }
5555
5556 static gint
5557 get_cursor_time (GtkEntry *entry)
5558 {
5559   GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (entry));
5560   gint time;
5561
5562   g_object_get (settings, "gtk-cursor-blink-time", &time, NULL);
5563
5564   return time;
5565 }
5566
5567 static gint
5568 get_cursor_blink_timeout (GtkEntry *entry)
5569 {
5570   GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (entry));
5571   gint timeout;
5572
5573   g_object_get (settings, "gtk-cursor-blink-timeout", &timeout, NULL);
5574
5575   return timeout;
5576 }
5577
5578 static void
5579 show_cursor (GtkEntry *entry)
5580 {
5581   if (!entry->cursor_visible)
5582     {
5583       entry->cursor_visible = TRUE;
5584
5585       if (GTK_WIDGET_HAS_FOCUS (entry) && entry->selection_bound == entry->current_pos)
5586         gtk_widget_queue_draw (GTK_WIDGET (entry));
5587     }
5588 }
5589
5590 static void
5591 hide_cursor (GtkEntry *entry)
5592 {
5593   if (entry->cursor_visible)
5594     {
5595       entry->cursor_visible = FALSE;
5596
5597       if (GTK_WIDGET_HAS_FOCUS (entry) && entry->selection_bound == entry->current_pos)
5598         gtk_widget_queue_draw (GTK_WIDGET (entry));
5599     }
5600 }
5601
5602 /*
5603  * Blink!
5604  */
5605 static gint
5606 blink_cb (gpointer data)
5607 {
5608   GtkEntry *entry;
5609   GtkEntryPrivate *priv; 
5610   gint blink_timeout;
5611
5612   entry = GTK_ENTRY (data);
5613   priv = GTK_ENTRY_GET_PRIVATE (entry);
5614  
5615   if (!GTK_WIDGET_HAS_FOCUS (entry))
5616     {
5617       g_warning ("GtkEntry - did not receive focus-out-event. If you\n"
5618                  "connect a handler to this signal, it must return\n"
5619                  "FALSE so the entry gets the event as well");
5620
5621       gtk_entry_check_cursor_blink (entry);
5622
5623       return FALSE;
5624     }
5625   
5626   g_assert (entry->selection_bound == entry->current_pos);
5627   
5628   blink_timeout = get_cursor_blink_timeout (entry);
5629   if (priv->blink_time > 1000 * blink_timeout && 
5630       blink_timeout < G_MAXINT/1000) 
5631     {
5632       /* we've blinked enough without the user doing anything, stop blinking */
5633       show_cursor (entry);
5634       entry->blink_timeout = 0;
5635     } 
5636   else if (entry->cursor_visible)
5637     {
5638       hide_cursor (entry);
5639       entry->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_OFF_MULTIPLIER / CURSOR_DIVIDER,
5640                                             blink_cb,
5641                                             entry);
5642     }
5643   else
5644     {
5645       show_cursor (entry);
5646       priv->blink_time += get_cursor_time (entry);
5647       entry->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER,
5648                                             blink_cb,
5649                                             entry);
5650     }
5651
5652   /* Remove ourselves */
5653   return FALSE;
5654 }
5655
5656 static void
5657 gtk_entry_check_cursor_blink (GtkEntry *entry)
5658 {
5659   GtkEntryPrivate *priv; 
5660   
5661   priv = GTK_ENTRY_GET_PRIVATE (entry);
5662
5663   if (cursor_blinks (entry))
5664     {
5665       if (!entry->blink_timeout)
5666         {
5667           show_cursor (entry);
5668           entry->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER,
5669                                                 blink_cb,
5670                                                 entry);
5671         }
5672     }
5673   else
5674     {
5675       if (entry->blink_timeout)  
5676         { 
5677           g_source_remove (entry->blink_timeout);
5678           entry->blink_timeout = 0;
5679         }
5680       
5681       entry->cursor_visible = TRUE;
5682     }
5683   
5684 }
5685
5686 static void
5687 gtk_entry_pend_cursor_blink (GtkEntry *entry)
5688 {
5689   if (cursor_blinks (entry))
5690     {
5691       if (entry->blink_timeout != 0)
5692         g_source_remove (entry->blink_timeout);
5693       
5694       entry->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_PEND_MULTIPLIER / CURSOR_DIVIDER,
5695                                             blink_cb,
5696                                             entry);
5697       show_cursor (entry);
5698     }
5699 }
5700
5701 static void
5702 gtk_entry_reset_blink_time (GtkEntry *entry)
5703 {
5704   GtkEntryPrivate *priv; 
5705   
5706   priv = GTK_ENTRY_GET_PRIVATE (entry);
5707   
5708   priv->blink_time = 0;
5709 }
5710
5711
5712 /* completion */
5713 static gint
5714 gtk_entry_completion_timeout (gpointer data)
5715 {
5716   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
5717
5718   completion->priv->completion_timeout = 0;
5719
5720   if (completion->priv->filter_model &&
5721       g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (completion->priv->entry)), -1)
5722       >= completion->priv->minimum_key_length)
5723     {
5724       gint matches;
5725       gint actions;
5726       GtkTreeSelection *s;
5727       gboolean popup_single;
5728
5729       gtk_entry_completion_complete (completion);
5730       matches = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
5731
5732       gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
5733
5734       s = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view));
5735
5736       gtk_tree_selection_unselect_all (s);
5737
5738       actions = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->actions), NULL);
5739
5740       g_object_get (completion, "popup-single-match", &popup_single, NULL);
5741       if ((matches > (popup_single ? 0: 1)) || actions > 0)
5742         { 
5743           if (GTK_WIDGET_VISIBLE (completion->priv->popup_window))
5744             _gtk_entry_completion_resize_popup (completion);
5745           else
5746             _gtk_entry_completion_popup (completion);
5747         }
5748       else 
5749         _gtk_entry_completion_popdown (completion);
5750     }
5751   else if (GTK_WIDGET_VISIBLE (completion->priv->popup_window))
5752     _gtk_entry_completion_popdown (completion);
5753
5754   return FALSE;
5755 }
5756
5757 static inline gboolean
5758 keyval_is_cursor_move (guint keyval)
5759 {
5760   if (keyval == GDK_Up || keyval == GDK_KP_Up)
5761     return TRUE;
5762
5763   if (keyval == GDK_Down || keyval == GDK_KP_Down)
5764     return TRUE;
5765
5766   if (keyval == GDK_Page_Up)
5767     return TRUE;
5768
5769   if (keyval == GDK_Page_Down)
5770     return TRUE;
5771
5772   return FALSE;
5773 }
5774
5775 static gboolean
5776 gtk_entry_completion_key_press (GtkWidget   *widget,
5777                                 GdkEventKey *event,
5778                                 gpointer     user_data)
5779 {
5780   gint matches, actions = 0;
5781   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
5782
5783   if (!GTK_WIDGET_MAPPED (completion->priv->popup_window))
5784     return FALSE;
5785
5786   matches = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
5787
5788   if (completion->priv->actions)
5789     actions = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->actions), NULL);
5790
5791   if (keyval_is_cursor_move (event->keyval))
5792     {
5793       GtkTreePath *path = NULL;
5794       
5795       if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
5796         {
5797           if (completion->priv->current_selected < 0)
5798             completion->priv->current_selected = matches + actions - 1;
5799           else
5800             completion->priv->current_selected--;
5801         }
5802       else if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
5803         {
5804           if (completion->priv->current_selected < matches + actions - 1)
5805             completion->priv->current_selected++;
5806           else
5807             completion->priv->current_selected = -1;
5808         }
5809       else if (event->keyval == GDK_Page_Up)
5810         {
5811           if (completion->priv->current_selected < 0)
5812             completion->priv->current_selected = matches + actions - 1;
5813           else if (completion->priv->current_selected == 0)
5814             completion->priv->current_selected = -1;
5815           else if (completion->priv->current_selected < matches) 
5816             {
5817               completion->priv->current_selected -= 14;
5818               if (completion->priv->current_selected < 0)
5819                 completion->priv->current_selected = 0;
5820             }
5821           else 
5822             {
5823               completion->priv->current_selected -= 14;
5824               if (completion->priv->current_selected < matches - 1)
5825                 completion->priv->current_selected = matches - 1;
5826             }
5827         }
5828       else if (event->keyval == GDK_Page_Down)
5829         {
5830           if (completion->priv->current_selected < 0)
5831             completion->priv->current_selected = 0;
5832           else if (completion->priv->current_selected < matches - 1)
5833             {
5834               completion->priv->current_selected += 14;
5835               if (completion->priv->current_selected > matches - 1)
5836                 completion->priv->current_selected = matches - 1;
5837             }
5838           else if (completion->priv->current_selected == matches + actions - 1)
5839             {
5840               completion->priv->current_selected = -1;
5841             }
5842           else
5843             {
5844               completion->priv->current_selected += 14;
5845               if (completion->priv->current_selected > matches + actions - 1)
5846                 completion->priv->current_selected = matches + actions - 1;
5847             }
5848         }
5849
5850       if (completion->priv->current_selected < 0)
5851         {
5852           gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
5853           gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view)));
5854
5855           if (completion->priv->inline_selection &&
5856               completion->priv->completion_prefix)
5857             {
5858               gtk_entry_set_text (GTK_ENTRY (completion->priv->entry), 
5859                                   completion->priv->completion_prefix);
5860               gtk_editable_set_position (GTK_EDITABLE (widget), -1);
5861             }
5862         }
5863       else if (completion->priv->current_selected < matches)
5864         {
5865           gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view)));
5866
5867           path = gtk_tree_path_new_from_indices (completion->priv->current_selected, -1);
5868           gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->tree_view),
5869                                     path, NULL, FALSE);
5870
5871           if (completion->priv->inline_selection)
5872             {
5873
5874               GtkTreeIter iter;
5875               GtkTreeModel *model = NULL;
5876               GtkTreeSelection *sel;
5877               gboolean entry_set;
5878
5879               sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view));
5880               if (!gtk_tree_selection_get_selected (sel, &model, &iter))
5881                 return FALSE;
5882               
5883               if (completion->priv->completion_prefix == NULL)
5884                 completion->priv->completion_prefix = g_strdup (gtk_entry_get_text (GTK_ENTRY (completion->priv->entry)));
5885
5886               g_signal_emit_by_name (completion, "cursor_on_match", model,
5887                                      &iter, &entry_set);
5888             }
5889         }
5890       else if (completion->priv->current_selected - matches >= 0)
5891         {
5892           gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
5893
5894           path = gtk_tree_path_new_from_indices (completion->priv->current_selected - matches, -1);
5895           gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->action_view),
5896                                     path, NULL, FALSE);
5897
5898           if (completion->priv->inline_selection &&
5899               completion->priv->completion_prefix)
5900             {
5901               gtk_entry_set_text (GTK_ENTRY (completion->priv->entry), 
5902                                   completion->priv->completion_prefix);
5903               gtk_editable_set_position (GTK_EDITABLE (widget), -1);
5904             }
5905         }
5906
5907       gtk_tree_path_free (path);
5908
5909       return TRUE;
5910     }
5911   else if (event->keyval == GDK_Escape ||
5912            event->keyval == GDK_Left ||
5913            event->keyval == GDK_KP_Left ||
5914            event->keyval == GDK_Right ||
5915            event->keyval == GDK_KP_Right) 
5916     {
5917       gboolean retval = TRUE;
5918
5919       _gtk_entry_reset_im_context (GTK_ENTRY (widget));
5920       _gtk_entry_completion_popdown (completion);
5921
5922       if (completion->priv->current_selected < 0)
5923         {
5924           retval = FALSE;
5925           goto keypress_completion_out;
5926         }
5927       else if (completion->priv->inline_selection)
5928         {
5929           /* Escape rejects the tentative completion */
5930           if (event->keyval == GDK_Escape)
5931             {
5932               if (completion->priv->completion_prefix)
5933                 gtk_entry_set_text (GTK_ENTRY (completion->priv->entry), 
5934                                     completion->priv->completion_prefix);
5935               else 
5936                 gtk_entry_set_text (GTK_ENTRY (completion->priv->entry), "");
5937             }
5938
5939           /* Move the cursor to the end for Right/Esc, to the
5940              beginning for Left */
5941           if (event->keyval == GDK_Right ||
5942               event->keyval == GDK_KP_Right ||
5943               event->keyval == GDK_Escape)
5944             gtk_editable_set_position (GTK_EDITABLE (widget), -1);
5945           else
5946             gtk_editable_set_position (GTK_EDITABLE (widget), 0);
5947         }
5948
5949 keypress_completion_out:
5950       if (completion->priv->inline_selection)
5951         {
5952           g_free (completion->priv->completion_prefix);
5953           completion->priv->completion_prefix = NULL;
5954         }
5955
5956       return retval;
5957     }
5958   else if (event->keyval == GDK_Tab || 
5959            event->keyval == GDK_KP_Tab ||
5960            event->keyval == GDK_ISO_Left_Tab) 
5961     {
5962       GtkDirectionType dir = event->keyval == GDK_ISO_Left_Tab ? 
5963         GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD;
5964       
5965       _gtk_entry_reset_im_context (GTK_ENTRY (widget));
5966       _gtk_entry_completion_popdown (completion);
5967
5968       g_free (completion->priv->completion_prefix);
5969       completion->priv->completion_prefix = NULL;
5970
5971       gtk_widget_child_focus (gtk_widget_get_toplevel (widget), dir);
5972
5973       return TRUE;
5974     }
5975   else if (event->keyval == GDK_ISO_Enter ||
5976            event->keyval == GDK_KP_Enter ||
5977            event->keyval == GDK_Return)
5978     {
5979       gboolean retval = TRUE;
5980
5981       _gtk_entry_reset_im_context (GTK_ENTRY (widget));
5982       _gtk_entry_completion_popdown (completion);
5983
5984       if (completion->priv->current_selected < matches)
5985         {
5986           GtkTreeIter iter;
5987           GtkTreeModel *model = NULL;
5988           GtkTreeSelection *sel;
5989           gboolean entry_set;
5990
5991           sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view));
5992           if (gtk_tree_selection_get_selected (sel, &model, &iter))
5993             {
5994               g_signal_handler_block (widget, completion->priv->changed_id);
5995               g_signal_emit_by_name (completion, "match_selected",
5996                                      model, &iter, &entry_set);
5997               g_signal_handler_unblock (widget, completion->priv->changed_id);
5998
5999               if (!entry_set)
6000                 {
6001                   gchar *str = NULL;
6002
6003                   gtk_tree_model_get (model, &iter,
6004                                       completion->priv->text_column, &str,
6005                                       -1);
6006
6007                   gtk_entry_set_text (GTK_ENTRY (widget), str);
6008
6009                   /* move the cursor to the end */
6010                   gtk_editable_set_position (GTK_EDITABLE (widget), -1);
6011
6012                   g_free (str);
6013                 }
6014             }
6015           else
6016             retval = FALSE;
6017         }
6018       else if (completion->priv->current_selected - matches >= 0)
6019         {
6020           GtkTreePath *path;
6021
6022           _gtk_entry_reset_im_context (GTK_ENTRY (widget));
6023
6024           path = gtk_tree_path_new_from_indices (completion->priv->current_selected - matches, -1);
6025
6026           g_signal_emit_by_name (completion, "action_activated",
6027                                  gtk_tree_path_get_indices (path)[0]);
6028           gtk_tree_path_free (path);
6029         }
6030
6031       g_free (completion->priv->completion_prefix);
6032       completion->priv->completion_prefix = NULL;
6033
6034       return retval;
6035     }
6036
6037   return FALSE;
6038 }
6039
6040 static void
6041 gtk_entry_completion_changed (GtkWidget *entry,
6042                               gpointer   user_data)
6043 {
6044   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
6045
6046   /* (re)install completion timeout */
6047   if (completion->priv->completion_timeout)
6048     g_source_remove (completion->priv->completion_timeout);
6049
6050   if (!gtk_entry_get_text (GTK_ENTRY (entry)))
6051     return;
6052
6053   /* no need to normalize for this test */
6054   if (completion->priv->minimum_key_length > 0 &&
6055       strcmp ("", gtk_entry_get_text (GTK_ENTRY (entry))) == 0)
6056     {
6057       if (GTK_WIDGET_VISIBLE (completion->priv->popup_window))
6058         _gtk_entry_completion_popdown (completion);
6059       return;
6060     }
6061
6062   completion->priv->completion_timeout =
6063     gdk_threads_add_timeout (COMPLETION_TIMEOUT,
6064                    gtk_entry_completion_timeout,
6065                    completion);
6066 }
6067
6068 static gboolean
6069 check_completion_callback (GtkEntryCompletion *completion)
6070 {
6071   completion->priv->check_completion_idle = NULL;
6072   
6073   gtk_entry_completion_complete (completion);
6074   gtk_entry_completion_insert_prefix (completion);
6075
6076   return FALSE;
6077 }
6078
6079 static void
6080 clear_completion_callback (GtkEntry   *entry,
6081                            GParamSpec *pspec)
6082 {
6083   if (pspec->name == I_("cursor-position") ||
6084       pspec->name == I_("selection-bound"))
6085     {
6086       GtkEntryCompletion *completion = gtk_entry_get_completion (entry);
6087       
6088       completion->priv->has_completion = FALSE;
6089     }
6090 }
6091
6092 static gboolean
6093 accept_completion_callback (GtkEntry *entry)
6094 {
6095   GtkEntryCompletion *completion = gtk_entry_get_completion (entry);
6096
6097   if (completion->priv->has_completion)
6098     gtk_editable_set_position (GTK_EDITABLE (entry),
6099                                entry->text_length);
6100
6101   return FALSE;
6102 }
6103
6104 static void
6105 completion_insert_text_callback (GtkEntry           *entry,
6106                                  const gchar        *text,
6107                                  gint                length,
6108                                  gint                position,
6109                                  GtkEntryCompletion *completion)
6110 {
6111   /* idle to update the selection based on the file list */
6112   if (completion->priv->check_completion_idle == NULL)
6113     {
6114       completion->priv->check_completion_idle = g_idle_source_new ();
6115       g_source_set_priority (completion->priv->check_completion_idle, G_PRIORITY_HIGH);
6116       g_source_set_closure (completion->priv->check_completion_idle,
6117                             g_cclosure_new_object (G_CALLBACK (check_completion_callback),
6118                                                    G_OBJECT (completion)));
6119       g_source_attach (completion->priv->check_completion_idle, NULL);
6120     }
6121 }
6122
6123 static void
6124 completion_changed (GtkEntryCompletion *completion,
6125                     GParamSpec         *pspec,
6126                     gpointer            data)
6127 {
6128   GtkEntry *entry = GTK_ENTRY (data);
6129
6130   if (pspec->name == I_("popup-completion") ||
6131       pspec->name == I_("inline-completion"))
6132     {
6133       disconnect_completion_signals (entry, completion);
6134       connect_completion_signals (entry, completion);
6135     }
6136 }
6137
6138 static void
6139 disconnect_completion_signals (GtkEntry           *entry,
6140                                GtkEntryCompletion *completion)
6141 {
6142   g_signal_handlers_disconnect_by_func (completion, 
6143                                        G_CALLBACK (completion_changed), entry);
6144   if (completion->priv->changed_id > 0 &&
6145       g_signal_handler_is_connected (entry, completion->priv->changed_id))
6146     {
6147       g_signal_handler_disconnect (entry, completion->priv->changed_id);
6148       completion->priv->changed_id = 0;
6149     }
6150   g_signal_handlers_disconnect_by_func (entry, 
6151                                         G_CALLBACK (gtk_entry_completion_key_press), completion);
6152   if (completion->priv->insert_text_id > 0 &&
6153       g_signal_handler_is_connected (entry, completion->priv->insert_text_id))
6154     {
6155       g_signal_handler_disconnect (entry, completion->priv->insert_text_id);
6156       completion->priv->insert_text_id = 0;
6157     }
6158   g_signal_handlers_disconnect_by_func (entry, 
6159                                         G_CALLBACK (completion_insert_text_callback), completion);
6160   g_signal_handlers_disconnect_by_func (entry, 
6161                                         G_CALLBACK (clear_completion_callback), completion);
6162   g_signal_handlers_disconnect_by_func (entry, 
6163                                         G_CALLBACK (accept_completion_callback), completion);
6164 }
6165
6166 static void
6167 connect_completion_signals (GtkEntry           *entry,
6168                             GtkEntryCompletion *completion)
6169 {
6170   if (completion->priv->popup_completion)
6171     {
6172       completion->priv->changed_id =
6173         g_signal_connect (entry, "changed",
6174                           G_CALLBACK (gtk_entry_completion_changed), completion);
6175       g_signal_connect (entry, "key_press_event",
6176                         G_CALLBACK (gtk_entry_completion_key_press), completion);
6177     }
6178  
6179   if (completion->priv->inline_completion)
6180     {
6181       completion->priv->insert_text_id =
6182         g_signal_connect (entry, "insert_text",
6183                           G_CALLBACK (completion_insert_text_callback), completion);
6184       g_signal_connect (entry, "notify",
6185                         G_CALLBACK (clear_completion_callback), completion);
6186       g_signal_connect (entry, "activate",
6187                         G_CALLBACK (accept_completion_callback), completion);
6188       g_signal_connect (entry, "focus_out_event",
6189                         G_CALLBACK (accept_completion_callback), completion);
6190     }
6191
6192   g_signal_connect (completion, "notify",
6193                     G_CALLBACK (completion_changed), entry);
6194 }
6195
6196 /**
6197  * gtk_entry_set_completion:
6198  * @entry: A #GtkEntry
6199  * @completion: The #GtkEntryCompletion or %NULL
6200  *
6201  * Sets @completion to be the auxiliary completion object to use with @entry.
6202  * All further configuration of the completion mechanism is done on
6203  * @completion using the #GtkEntryCompletion API. Completion is disabled if
6204  * @completion is set to %NULL.
6205  *
6206  * Since: 2.4
6207  */
6208 void
6209 gtk_entry_set_completion (GtkEntry           *entry,
6210                           GtkEntryCompletion *completion)
6211 {
6212   GtkEntryCompletion *old;
6213
6214   g_return_if_fail (GTK_IS_ENTRY (entry));
6215   g_return_if_fail (!completion || GTK_IS_ENTRY_COMPLETION (completion));
6216
6217   old = gtk_entry_get_completion (entry);
6218
6219   if (old == completion)
6220     return;
6221   
6222   if (old)
6223     {
6224       if (old->priv->completion_timeout)
6225         {
6226           g_source_remove (old->priv->completion_timeout);
6227           old->priv->completion_timeout = 0;
6228         }
6229
6230       if (GTK_WIDGET_MAPPED (old->priv->popup_window))
6231         _gtk_entry_completion_popdown (old);
6232
6233       disconnect_completion_signals (entry, old);
6234       old->priv->entry = NULL;
6235
6236       g_object_unref (old);
6237     }
6238
6239   if (!completion)
6240     {
6241       g_object_set_data (G_OBJECT (entry), I_(GTK_ENTRY_COMPLETION_KEY), NULL);
6242       return;
6243     }
6244
6245   /* hook into the entry */
6246   g_object_ref (completion);
6247
6248   connect_completion_signals (entry, completion);    
6249   completion->priv->entry = GTK_WIDGET (entry);
6250   g_object_set_data (G_OBJECT (entry), I_(GTK_ENTRY_COMPLETION_KEY), completion);
6251 }
6252
6253 /**
6254  * gtk_entry_get_completion:
6255  * @entry: A #GtkEntry
6256  *
6257  * Returns the auxiliary completion object currently in use by @entry.
6258  *
6259  * Return value: The auxiliary completion object currently in use by @entry.
6260  *
6261  * Since: 2.4
6262  */
6263 GtkEntryCompletion *
6264 gtk_entry_get_completion (GtkEntry *entry)
6265 {
6266   GtkEntryCompletion *completion;
6267
6268   g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
6269
6270   completion = GTK_ENTRY_COMPLETION (g_object_get_data (G_OBJECT (entry),
6271                                      GTK_ENTRY_COMPLETION_KEY));
6272
6273   return completion;
6274 }
6275
6276 /**
6277  * gtk_entry_set_cursor_hadjustment:
6278  * @entry: a #GtkEntry
6279  * @adjustment: an adjustment which should be adjusted when the cursor 
6280  *              is moved, or %NULL
6281  *
6282  * Hooks up an adjustment to the cursor position in an entry, so that when 
6283  * the cursor is moved, the adjustment is scrolled to show that position. 
6284  * See gtk_scrolled_window_get_hadjustment() for a typical way of obtaining 
6285  * the adjustment.
6286  *
6287  * The adjustment has to be in pixel units and in the same coordinate system 
6288  * as the entry. 
6289  * 
6290  * Since: 2.12
6291  */
6292 void
6293 gtk_entry_set_cursor_hadjustment (GtkEntry      *entry,
6294                                   GtkAdjustment *adjustment)
6295 {
6296   g_return_if_fail (GTK_IS_ENTRY (entry));
6297   if (adjustment)
6298     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
6299
6300   if (adjustment)
6301     g_object_ref (adjustment);
6302
6303   g_object_set_qdata_full (G_OBJECT (entry), 
6304                            quark_cursor_hadjustment,
6305                            adjustment, 
6306                            g_object_unref);
6307 }
6308
6309 /**
6310  * gtk_entry_get_cursor_hadjustment:
6311  * @entry: a #GtkEntry
6312  *
6313  * Retrieves the horizontal cursor adjustment for the entry. 
6314  * See gtk_entry_set_cursor_hadjustment().
6315  *
6316  * Return value: the horizontal cursor adjustment, or %NULL 
6317  *   if none has been set.
6318  * 
6319  * Since: 2.12
6320  */
6321 GtkAdjustment*
6322 gtk_entry_get_cursor_hadjustment (GtkEntry *entry)
6323 {
6324   g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
6325
6326   return g_object_get_qdata (G_OBJECT (entry), quark_cursor_hadjustment);
6327 }
6328
6329 #define __GTK_ENTRY_C__
6330 #include "gtkaliasdef.c"