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