]> Pileus Git - ~andy/gtk/blob - gtk/gtkentry.c
Documentation fixes
[~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  * Copyright (C) 2004-2006 Christian Hammond
5  * Copyright (C) 2008 Cody Russell
6  * Copyright (C) 2008 Red Hat, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /*
25  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
26  * file for a list of people on the GTK+ Team.  See the ChangeLog
27  * files for a list of changes.  These files are distributed with
28  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
29  */
30
31 #include "config.h"
32
33 #include <math.h>
34 #include <string.h>
35
36 #include "gdk/gdkkeysyms.h"
37 #include "gtkalignment.h"
38 #include "gtkbindings.h"
39 #include "gtkcelleditable.h"
40 #include "gtkclipboard.h"
41 #include "gtkdnd.h"
42 #include "gtkentry.h"
43 #include "gtkimagemenuitem.h"
44 #include "gtkimcontextsimple.h"
45 #include "gtkimmulticontext.h"
46 #include "gtkintl.h"
47 #include "gtklabel.h"
48 #include "gtkmain.h"
49 #include "gtkmarshalers.h"
50 #include "gtkmenu.h"
51 #include "gtkmenuitem.h"
52 #include "gtkseparatormenuitem.h"
53 #include "gtkselection.h"
54 #include "gtksettings.h"
55 #include "gtkspinbutton.h"
56 #include "gtkstock.h"
57 #include "gtktextutil.h"
58 #include "gtkwindow.h"
59 #include "gtktreeview.h"
60 #include "gtktreeselection.h"
61 #include "gtkprivate.h"
62 #include "gtkentryprivate.h"
63 #include "gtkcelllayout.h"
64 #include "gtktooltip.h"
65 #include "gtkiconfactory.h"
66 #include "gtkicontheme.h"
67 #include "gtkalias.h"
68
69 #define GTK_ENTRY_COMPLETION_KEY "gtk-entry-completion-key"
70
71 #define MIN_ENTRY_WIDTH  150
72 #define DRAW_TIMEOUT     20
73 #define COMPLETION_TIMEOUT 300
74 #define PASSWORD_HINT_MAX 8
75
76 /* Initial size of buffer, in bytes */
77 #define MIN_SIZE 16
78
79 /* Maximum size of text buffer, in bytes */
80 #define MAX_SIZE G_MAXUSHORT
81
82 #define MAX_ICONS 2
83
84 #define IS_VALID_ICON_POSITION(pos)               \
85   ((pos) == GTK_ENTRY_ICON_PRIMARY ||                   \
86    (pos) == GTK_ENTRY_ICON_SECONDARY)
87
88 static const GtkBorder default_inner_border = { 2, 2, 2, 2 };
89 static GQuark          quark_inner_border   = 0;
90 static GQuark          quark_password_hint  = 0;
91 static GQuark          quark_cursor_hadjustment = 0;
92 static GQuark          quark_capslock_feedback = 0;
93
94 typedef struct _GtkEntryPrivate GtkEntryPrivate;
95
96 #define GTK_ENTRY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ENTRY, GtkEntryPrivate))
97
98 typedef struct
99 {
100   GdkWindow *window;
101   gchar *tooltip;
102   guint insensitive    : 1;
103   guint nonactivatable : 1;
104   guint prelight       : 1;
105   guint in_drag        : 1;
106   guint pressed        : 1;
107
108   GtkImageType  storage_type;
109   GdkPixbuf    *pixbuf;
110   gchar        *stock_id;
111   gchar        *icon_name;
112   GIcon        *gicon;
113
114   GtkTargetList *target_list;
115   GdkDragAction actions;
116 } EntryIconInfo;
117
118 struct _GtkEntryPrivate 
119 {
120   gfloat xalign;
121   gint insert_pos;
122   guint blink_time;  /* time in msec the cursor has blinked since last user event */
123   guint interior_focus          : 1;
124   guint real_changed            : 1;
125   guint invisible_char_set      : 1;
126   guint caps_lock_warning       : 1;
127   guint change_count            : 8;
128   guint progress_pulse_mode     : 1;
129   guint progress_pulse_way_back : 1;
130
131   gint focus_width;
132   GtkShadowType shadow_type;
133
134   gdouble progress_fraction;
135   gdouble progress_pulse_fraction;
136   gdouble progress_pulse_current;
137
138   EntryIconInfo *icons[MAX_ICONS];
139   gint icon_margin;
140   gint start_x;
141   gint start_y;
142 };
143
144 typedef struct _GtkEntryPasswordHint GtkEntryPasswordHint;
145
146 struct _GtkEntryPasswordHint
147 {
148   gchar password_hint[PASSWORD_HINT_MAX];
149   guint password_hint_timeout_id;
150   gint  password_hint_length;
151   gint  password_hint_position;
152 };
153
154 typedef struct _GtkEntryCapslockFeedback GtkEntryCapslockFeedback;
155
156 struct _GtkEntryCapslockFeedback
157 {
158   GtkWidget *entry;
159   GtkWidget *window;
160   GtkWidget *label;
161 };
162
163 enum {
164   ACTIVATE,
165   POPULATE_POPUP,
166   MOVE_CURSOR,
167   INSERT_AT_CURSOR,
168   DELETE_FROM_CURSOR,
169   BACKSPACE,
170   CUT_CLIPBOARD,
171   COPY_CLIPBOARD,
172   PASTE_CLIPBOARD,
173   TOGGLE_OVERWRITE,
174   ICON_PRESSED,
175   ICON_RELEASED,
176   LAST_SIGNAL
177 };
178
179 enum {
180   PROP_0,
181   PROP_CURSOR_POSITION,
182   PROP_SELECTION_BOUND,
183   PROP_EDITABLE,
184   PROP_MAX_LENGTH,
185   PROP_VISIBILITY,
186   PROP_HAS_FRAME,
187   PROP_INNER_BORDER,
188   PROP_INVISIBLE_CHAR,
189   PROP_ACTIVATES_DEFAULT,
190   PROP_WIDTH_CHARS,
191   PROP_SCROLL_OFFSET,
192   PROP_TEXT,
193   PROP_XALIGN,
194   PROP_TRUNCATE_MULTILINE,
195   PROP_SHADOW_TYPE,
196   PROP_OVERWRITE_MODE,
197   PROP_TEXT_LENGTH,
198   PROP_INVISIBLE_CHAR_SET,
199   PROP_CAPS_LOCK_WARNING,
200   PROP_PROGRESS_FRACTION,
201   PROP_PROGRESS_PULSE_STEP,
202   PROP_PIXBUF_PRIMARY,
203   PROP_PIXBUF_SECONDARY,
204   PROP_STOCK_PRIMARY,
205   PROP_STOCK_SECONDARY,
206   PROP_ICON_NAME_PRIMARY,
207   PROP_ICON_NAME_SECONDARY,
208   PROP_GICON_PRIMARY,
209   PROP_GICON_SECONDARY,
210   PROP_STORAGE_TYPE_PRIMARY,
211   PROP_STORAGE_TYPE_SECONDARY,
212   PROP_ACTIVATABLE_PRIMARY,
213   PROP_ACTIVATABLE_SECONDARY,
214   PROP_SENSITIVE_PRIMARY,
215   PROP_SENSITIVE_SECONDARY
216 };
217
218 static guint signals[LAST_SIGNAL] = { 0 };
219
220 typedef enum {
221   CURSOR_STANDARD,
222   CURSOR_DND
223 } CursorType;
224
225 /* GObject, GtkObject methods
226  */
227 static void   gtk_entry_editable_init        (GtkEditableClass     *iface);
228 static void   gtk_entry_cell_editable_init   (GtkCellEditableIface *iface);
229 static void   gtk_entry_set_property         (GObject          *object,
230                                               guint             prop_id,
231                                               const GValue     *value,
232                                               GParamSpec       *pspec);
233 static void   gtk_entry_get_property         (GObject          *object,
234                                               guint             prop_id,
235                                               GValue           *value,
236                                               GParamSpec       *pspec);
237 static void   gtk_entry_finalize             (GObject          *object);
238 static void   gtk_entry_destroy              (GtkObject        *object);
239 static void   gtk_entry_dispose              (GObject          *object);
240
241 /* GtkWidget methods
242  */
243 static void   gtk_entry_realize              (GtkWidget        *widget);
244 static void   gtk_entry_unrealize            (GtkWidget        *widget);
245 static void   gtk_entry_map                  (GtkWidget        *widget);
246 static void   gtk_entry_unmap                (GtkWidget        *widget);
247 static void   gtk_entry_size_request         (GtkWidget        *widget,
248                                               GtkRequisition   *requisition);
249 static void   gtk_entry_size_allocate        (GtkWidget        *widget,
250                                               GtkAllocation    *allocation);
251 static void   gtk_entry_draw_frame           (GtkWidget        *widget,
252                                               GdkRectangle     *area);
253 static void   gtk_entry_draw_progress        (GtkWidget        *widget,
254                                               GdkEventExpose   *event);
255 static gint   gtk_entry_expose               (GtkWidget        *widget,
256                                               GdkEventExpose   *event);
257 static gint   gtk_entry_button_press         (GtkWidget        *widget,
258                                               GdkEventButton   *event);
259 static gint   gtk_entry_button_release       (GtkWidget        *widget,
260                                               GdkEventButton   *event);
261 static gint   gtk_entry_enter_notify         (GtkWidget        *widget,
262                                               GdkEventCrossing *event);
263 static gint   gtk_entry_leave_notify         (GtkWidget        *widget,
264                                               GdkEventCrossing *event);
265 static gint   gtk_entry_motion_notify        (GtkWidget        *widget,
266                                               GdkEventMotion   *event);
267 static gint   gtk_entry_key_press            (GtkWidget        *widget,
268                                               GdkEventKey      *event);
269 static gint   gtk_entry_key_release          (GtkWidget        *widget,
270                                               GdkEventKey      *event);
271 static gint   gtk_entry_focus_in             (GtkWidget        *widget,
272                                               GdkEventFocus    *event);
273 static gint   gtk_entry_focus_out            (GtkWidget        *widget,
274                                               GdkEventFocus    *event);
275 static void   gtk_entry_grab_focus           (GtkWidget        *widget);
276 static void   gtk_entry_style_set            (GtkWidget        *widget,
277                                               GtkStyle         *previous_style);
278 static gboolean gtk_entry_query_tooltip      (GtkWidget        *widget,
279                                               gint              x,
280                                               gint              y,
281                                               gboolean          keyboard_tip,
282                                               GtkTooltip       *tooltip);
283 static void   gtk_entry_direction_changed    (GtkWidget        *widget,
284                                               GtkTextDirection  previous_dir);
285 static void   gtk_entry_state_changed        (GtkWidget        *widget,
286                                               GtkStateType      previous_state);
287 static void   gtk_entry_screen_changed       (GtkWidget        *widget,
288                                               GdkScreen        *old_screen);
289
290 static gboolean gtk_entry_drag_drop          (GtkWidget        *widget,
291                                               GdkDragContext   *context,
292                                               gint              x,
293                                               gint              y,
294                                               guint             time);
295 static gboolean gtk_entry_drag_motion        (GtkWidget        *widget,
296                                               GdkDragContext   *context,
297                                               gint              x,
298                                               gint              y,
299                                               guint             time);
300 static void     gtk_entry_drag_leave         (GtkWidget        *widget,
301                                               GdkDragContext   *context,
302                                               guint             time);
303 static void     gtk_entry_drag_data_received (GtkWidget        *widget,
304                                               GdkDragContext   *context,
305                                               gint              x,
306                                               gint              y,
307                                               GtkSelectionData *selection_data,
308                                               guint             info,
309                                               guint             time);
310 static void     gtk_entry_drag_data_get      (GtkWidget        *widget,
311                                               GdkDragContext   *context,
312                                               GtkSelectionData *selection_data,
313                                               guint             info,
314                                               guint             time);
315 static void     gtk_entry_drag_data_delete   (GtkWidget        *widget,
316                                               GdkDragContext   *context);
317 static void     gtk_entry_drag_begin         (GtkWidget        *widget,
318                                               GdkDragContext   *context);
319 static void     gtk_entry_drag_end           (GtkWidget        *widget,
320                                               GdkDragContext   *context);
321
322
323 /* GtkEditable method implementations
324  */
325 static void     gtk_entry_insert_text          (GtkEditable *editable,
326                                                 const gchar *new_text,
327                                                 gint         new_text_length,
328                                                 gint        *position);
329 static void     gtk_entry_delete_text          (GtkEditable *editable,
330                                                 gint         start_pos,
331                                                 gint         end_pos);
332 static gchar *  gtk_entry_get_chars            (GtkEditable *editable,
333                                                 gint         start_pos,
334                                                 gint         end_pos);
335 static void     gtk_entry_real_set_position    (GtkEditable *editable,
336                                                 gint         position);
337 static gint     gtk_entry_get_position         (GtkEditable *editable);
338 static void     gtk_entry_set_selection_bounds (GtkEditable *editable,
339                                                 gint         start,
340                                                 gint         end);
341 static gboolean gtk_entry_get_selection_bounds (GtkEditable *editable,
342                                                 gint        *start,
343                                                 gint        *end);
344
345 /* GtkCellEditable method implementations
346  */
347 static void gtk_entry_start_editing (GtkCellEditable *cell_editable,
348                                      GdkEvent        *event);
349
350 /* Default signal handlers
351  */
352 static void gtk_entry_real_insert_text   (GtkEditable     *editable,
353                                           const gchar     *new_text,
354                                           gint             new_text_length,
355                                           gint            *position);
356 static void gtk_entry_real_delete_text   (GtkEditable     *editable,
357                                           gint             start_pos,
358                                           gint             end_pos);
359 static void gtk_entry_move_cursor        (GtkEntry        *entry,
360                                           GtkMovementStep  step,
361                                           gint             count,
362                                           gboolean         extend_selection);
363 static void gtk_entry_insert_at_cursor   (GtkEntry        *entry,
364                                           const gchar     *str);
365 static void gtk_entry_delete_from_cursor (GtkEntry        *entry,
366                                           GtkDeleteType    type,
367                                           gint             count);
368 static void gtk_entry_backspace          (GtkEntry        *entry);
369 static void gtk_entry_cut_clipboard      (GtkEntry        *entry);
370 static void gtk_entry_copy_clipboard     (GtkEntry        *entry);
371 static void gtk_entry_paste_clipboard    (GtkEntry        *entry);
372 static void gtk_entry_toggle_overwrite   (GtkEntry        *entry);
373 static void gtk_entry_select_all         (GtkEntry        *entry);
374 static void gtk_entry_real_activate      (GtkEntry        *entry);
375 static gboolean gtk_entry_popup_menu     (GtkWidget       *widget);
376
377 static void keymap_direction_changed     (GdkKeymap       *keymap,
378                                           GtkEntry        *entry);
379 static void keymap_state_changed         (GdkKeymap       *keymap,
380                                           GtkEntry        *entry);
381 static void remove_capslock_feedback     (GtkEntry        *entry);
382
383 /* IM Context Callbacks
384  */
385 static void     gtk_entry_commit_cb               (GtkIMContext *context,
386                                                    const gchar  *str,
387                                                    GtkEntry     *entry);
388 static void     gtk_entry_preedit_changed_cb      (GtkIMContext *context,
389                                                    GtkEntry     *entry);
390 static gboolean gtk_entry_retrieve_surrounding_cb (GtkIMContext *context,
391                                                    GtkEntry     *entry);
392 static gboolean gtk_entry_delete_surrounding_cb   (GtkIMContext *context,
393                                                    gint          offset,
394                                                    gint          n_chars,
395                                                    GtkEntry     *entry);
396
397 /* Internal routines
398  */
399 static void         gtk_entry_enter_text               (GtkEntry       *entry,
400                                                         const gchar    *str);
401 static void         gtk_entry_set_positions            (GtkEntry       *entry,
402                                                         gint            current_pos,
403                                                         gint            selection_bound);
404 static void         gtk_entry_draw_text                (GtkEntry       *entry);
405 static void         gtk_entry_draw_cursor              (GtkEntry       *entry,
406                                                         CursorType      type);
407 static PangoLayout *gtk_entry_ensure_layout            (GtkEntry       *entry,
408                                                         gboolean        include_preedit);
409 static void         gtk_entry_reset_layout             (GtkEntry       *entry);
410 static void         gtk_entry_queue_draw               (GtkEntry       *entry);
411 static void         gtk_entry_recompute                (GtkEntry       *entry);
412 static gint         gtk_entry_find_position            (GtkEntry       *entry,
413                                                         gint            x);
414 static void         gtk_entry_get_cursor_locations     (GtkEntry       *entry,
415                                                         CursorType      type,
416                                                         gint           *strong_x,
417                                                         gint           *weak_x);
418 static void         gtk_entry_adjust_scroll            (GtkEntry       *entry);
419 static gint         gtk_entry_move_visually            (GtkEntry       *editable,
420                                                         gint            start,
421                                                         gint            count);
422 static gint         gtk_entry_move_logically           (GtkEntry       *entry,
423                                                         gint            start,
424                                                         gint            count);
425 static gint         gtk_entry_move_forward_word        (GtkEntry       *entry,
426                                                         gint            start,
427                                                         gboolean        allow_whitespace);
428 static gint         gtk_entry_move_backward_word       (GtkEntry       *entry,
429                                                         gint            start,
430                                                         gboolean        allow_whitespace);
431 static void         gtk_entry_delete_whitespace        (GtkEntry       *entry);
432 static void         gtk_entry_select_word              (GtkEntry       *entry);
433 static void         gtk_entry_select_line              (GtkEntry       *entry);
434 static char *       gtk_entry_get_public_chars         (GtkEntry       *entry,
435                                                         gint            start,
436                                                         gint            end);
437 static void         gtk_entry_paste                    (GtkEntry       *entry,
438                                                         GdkAtom         selection);
439 static void         gtk_entry_update_primary_selection (GtkEntry       *entry);
440 static void         gtk_entry_do_popup                 (GtkEntry       *entry,
441                                                         GdkEventButton *event);
442 static gboolean     gtk_entry_mnemonic_activate        (GtkWidget      *widget,
443                                                         gboolean        group_cycling);
444 static void         gtk_entry_state_changed            (GtkWidget      *widget,
445                                                         GtkStateType    previous_state);
446 static void         gtk_entry_check_cursor_blink       (GtkEntry       *entry);
447 static void         gtk_entry_pend_cursor_blink        (GtkEntry       *entry);
448 static void         gtk_entry_reset_blink_time         (GtkEntry       *entry);
449 static void         get_text_area_size                 (GtkEntry       *entry,
450                                                         GtkAllocation  *alloc);
451 static void         gtk_entry_get_text_area_size       (GtkEntry       *entry,
452                                                         gint           *x,
453                                                         gint           *y,
454                                                         gint           *width,
455                                                         gint           *height);
456 static void         get_widget_window_size             (GtkEntry       *entry,
457                                                         gint           *x,
458                                                         gint           *y,
459                                                         gint           *width,
460                                                         gint           *height);
461 static void         gtk_entry_move_adjustments         (GtkEntry             *entry);
462 static void         gtk_entry_ensure_pixbuf            (GtkEntry             *entry,
463                                                         GtkEntryIconPosition  icon_pos);
464
465
466 /* Completion */
467 static gint         gtk_entry_completion_timeout       (gpointer            data);
468 static gboolean     gtk_entry_completion_key_press     (GtkWidget          *widget,
469                                                         GdkEventKey        *event,
470                                                         gpointer            user_data);
471 static void         gtk_entry_completion_changed       (GtkWidget          *entry,
472                                                         gpointer            user_data);
473 static gboolean     check_completion_callback          (GtkEntryCompletion *completion);
474 static void         clear_completion_callback          (GtkEntry           *entry,
475                                                         GParamSpec         *pspec);
476 static gboolean     accept_completion_callback         (GtkEntry           *entry);
477 static void         completion_insert_text_callback    (GtkEntry           *entry,
478                                                         const gchar        *text,
479                                                         gint                length,
480                                                         gint                position,
481                                                         GtkEntryCompletion *completion);
482 static void         completion_changed                 (GtkEntryCompletion *completion,
483                                                         GParamSpec         *pspec,
484                                                         gpointer            data);
485 static void         disconnect_completion_signals      (GtkEntry           *entry,
486                                                         GtkEntryCompletion *completion);
487 static void         connect_completion_signals         (GtkEntry           *entry,
488                                                         GtkEntryCompletion *completion);
489
490 static void         begin_change                       (GtkEntry *entry);
491 static void         end_change                         (GtkEntry *entry);
492 static void         emit_changed                       (GtkEntry *entry);
493
494
495 G_DEFINE_TYPE_WITH_CODE (GtkEntry, gtk_entry, GTK_TYPE_WIDGET,
496                          G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
497                                                 gtk_entry_editable_init)
498                          G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_EDITABLE,
499                                                 gtk_entry_cell_editable_init))
500
501 static void
502 add_move_binding (GtkBindingSet  *binding_set,
503                   guint           keyval,
504                   guint           modmask,
505                   GtkMovementStep step,
506                   gint            count)
507 {
508   g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
509   
510   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
511                                 "move-cursor", 3,
512                                 G_TYPE_ENUM, step,
513                                 G_TYPE_INT, count,
514                                 G_TYPE_BOOLEAN, FALSE);
515
516   /* Selection-extending version */
517   gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
518                                 "move-cursor", 3,
519                                 G_TYPE_ENUM, step,
520                                 G_TYPE_INT, count,
521                                 G_TYPE_BOOLEAN, TRUE);
522 }
523
524 static void
525 gtk_entry_class_init (GtkEntryClass *class)
526 {
527   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
528   GtkWidgetClass *widget_class;
529   GtkObjectClass *gtk_object_class;
530   GtkBindingSet *binding_set;
531
532   widget_class = (GtkWidgetClass*) class;
533   gtk_object_class = (GtkObjectClass *)class;
534
535   gobject_class->dispose = gtk_entry_dispose;
536   gobject_class->finalize = gtk_entry_finalize;
537   gobject_class->set_property = gtk_entry_set_property;
538   gobject_class->get_property = gtk_entry_get_property;
539
540   widget_class->map = gtk_entry_map;
541   widget_class->unmap = gtk_entry_unmap;
542   widget_class->realize = gtk_entry_realize;
543   widget_class->unrealize = gtk_entry_unrealize;
544   widget_class->size_request = gtk_entry_size_request;
545   widget_class->size_allocate = gtk_entry_size_allocate;
546   widget_class->expose_event = gtk_entry_expose;
547   widget_class->enter_notify_event = gtk_entry_enter_notify;
548   widget_class->leave_notify_event = gtk_entry_leave_notify;
549   widget_class->button_press_event = gtk_entry_button_press;
550   widget_class->button_release_event = gtk_entry_button_release;
551   widget_class->motion_notify_event = gtk_entry_motion_notify;
552   widget_class->key_press_event = gtk_entry_key_press;
553   widget_class->key_release_event = gtk_entry_key_release;
554   widget_class->focus_in_event = gtk_entry_focus_in;
555   widget_class->focus_out_event = gtk_entry_focus_out;
556   widget_class->grab_focus = gtk_entry_grab_focus;
557   widget_class->style_set = gtk_entry_style_set;
558   widget_class->query_tooltip = gtk_entry_query_tooltip;
559   widget_class->drag_begin = gtk_entry_drag_begin;
560   widget_class->drag_end = gtk_entry_drag_end;
561   widget_class->direction_changed = gtk_entry_direction_changed;
562   widget_class->state_changed = gtk_entry_state_changed;
563   widget_class->screen_changed = gtk_entry_screen_changed;
564   widget_class->mnemonic_activate = gtk_entry_mnemonic_activate;
565
566   widget_class->drag_drop = gtk_entry_drag_drop;
567   widget_class->drag_motion = gtk_entry_drag_motion;
568   widget_class->drag_leave = gtk_entry_drag_leave;
569   widget_class->drag_data_received = gtk_entry_drag_data_received;
570   widget_class->drag_data_get = gtk_entry_drag_data_get;
571   widget_class->drag_data_delete = gtk_entry_drag_data_delete;
572
573   widget_class->popup_menu = gtk_entry_popup_menu;
574
575   gtk_object_class->destroy = gtk_entry_destroy;
576
577   class->move_cursor = gtk_entry_move_cursor;
578   class->insert_at_cursor = gtk_entry_insert_at_cursor;
579   class->delete_from_cursor = gtk_entry_delete_from_cursor;
580   class->backspace = gtk_entry_backspace;
581   class->cut_clipboard = gtk_entry_cut_clipboard;
582   class->copy_clipboard = gtk_entry_copy_clipboard;
583   class->paste_clipboard = gtk_entry_paste_clipboard;
584   class->toggle_overwrite = gtk_entry_toggle_overwrite;
585   class->activate = gtk_entry_real_activate;
586   class->get_text_area_size = gtk_entry_get_text_area_size;
587   
588   quark_inner_border = g_quark_from_static_string ("gtk-entry-inner-border");
589   quark_password_hint = g_quark_from_static_string ("gtk-entry-password-hint");
590   quark_cursor_hadjustment = g_quark_from_static_string ("gtk-hadjustment");
591   quark_capslock_feedback = g_quark_from_static_string ("gtk-entry-capslock-feedback");
592
593   g_object_class_install_property (gobject_class,
594                                    PROP_CURSOR_POSITION,
595                                    g_param_spec_int ("cursor-position",
596                                                      P_("Cursor Position"),
597                                                      P_("The current position of the insertion cursor in chars"),
598                                                      0,
599                                                      MAX_SIZE,
600                                                      0,
601                                                      GTK_PARAM_READABLE));
602   
603   g_object_class_install_property (gobject_class,
604                                    PROP_SELECTION_BOUND,
605                                    g_param_spec_int ("selection-bound",
606                                                      P_("Selection Bound"),
607                                                      P_("The position of the opposite end of the selection from the cursor in chars"),
608                                                      0,
609                                                      MAX_SIZE,
610                                                      0,
611                                                      GTK_PARAM_READABLE));
612   
613   g_object_class_install_property (gobject_class,
614                                    PROP_EDITABLE,
615                                    g_param_spec_boolean ("editable",
616                                                          P_("Editable"),
617                                                          P_("Whether the entry contents can be edited"),
618                                                          TRUE,
619                                                          GTK_PARAM_READWRITE));
620   
621   g_object_class_install_property (gobject_class,
622                                    PROP_MAX_LENGTH,
623                                    g_param_spec_int ("max-length",
624                                                      P_("Maximum length"),
625                                                      P_("Maximum number of characters for this entry. Zero if no maximum"),
626                                                      0,
627                                                      MAX_SIZE,
628                                                      0,
629                                                      GTK_PARAM_READWRITE));
630   g_object_class_install_property (gobject_class,
631                                    PROP_VISIBILITY,
632                                    g_param_spec_boolean ("visibility",
633                                                          P_("Visibility"),
634                                                          P_("FALSE displays the \"invisible char\" instead of the actual text (password mode)"),
635                                                          TRUE,
636                                                          GTK_PARAM_READWRITE));
637
638   g_object_class_install_property (gobject_class,
639                                    PROP_HAS_FRAME,
640                                    g_param_spec_boolean ("has-frame",
641                                                          P_("Has Frame"),
642                                                          P_("FALSE removes outside bevel from entry"),
643                                                          TRUE,
644                                                          GTK_PARAM_READWRITE));
645
646   g_object_class_install_property (gobject_class,
647                                    PROP_INNER_BORDER,
648                                    g_param_spec_boxed ("inner-border",
649                                                        P_("Inner Border"),
650                                                        P_("Border between text and frame. Overrides the inner-border style property"),
651                                                        GTK_TYPE_BORDER,
652                                                        GTK_PARAM_READWRITE));
653
654   g_object_class_install_property (gobject_class,
655                                    PROP_INVISIBLE_CHAR,
656                                    g_param_spec_unichar ("invisible-char",
657                                                          P_("Invisible character"),
658                                                          P_("The character to use when masking entry contents (in \"password mode\")"),
659                                                          '*',
660                                                          GTK_PARAM_READWRITE));
661
662   g_object_class_install_property (gobject_class,
663                                    PROP_ACTIVATES_DEFAULT,
664                                    g_param_spec_boolean ("activates-default",
665                                                          P_("Activates default"),
666                                                          P_("Whether to activate the default widget (such as the default button in a dialog) when Enter is pressed"),
667                                                          FALSE,
668                                                          GTK_PARAM_READWRITE));
669   g_object_class_install_property (gobject_class,
670                                    PROP_WIDTH_CHARS,
671                                    g_param_spec_int ("width-chars",
672                                                      P_("Width in chars"),
673                                                      P_("Number of characters to leave space for in the entry"),
674                                                      -1,
675                                                      G_MAXINT,
676                                                      -1,
677                                                      GTK_PARAM_READWRITE));
678
679   g_object_class_install_property (gobject_class,
680                                    PROP_SCROLL_OFFSET,
681                                    g_param_spec_int ("scroll-offset",
682                                                      P_("Scroll offset"),
683                                                      P_("Number of pixels of the entry scrolled off the screen to the left"),
684                                                      0,
685                                                      G_MAXINT,
686                                                      0,
687                                                      GTK_PARAM_READABLE));
688
689   g_object_class_install_property (gobject_class,
690                                    PROP_TEXT,
691                                    g_param_spec_string ("text",
692                                                         P_("Text"),
693                                                         P_("The contents of the entry"),
694                                                         "",
695                                                         GTK_PARAM_READWRITE));
696
697   /**
698    * GtkEntry:xalign:
699    *
700    * The horizontal alignment, from 0 (left) to 1 (right). 
701    * Reversed for RTL layouts.
702    * 
703    * Since: 2.4
704    */
705   g_object_class_install_property (gobject_class,
706                                    PROP_XALIGN,
707                                    g_param_spec_float ("xalign",
708                                                        P_("X align"),
709                                                        P_("The horizontal alignment, from 0 (left) to 1 (right). Reversed for RTL layouts."),
710                                                        0.0,
711                                                        1.0,
712                                                        0.0,
713                                                        GTK_PARAM_READWRITE));
714
715   /**
716    * GtkEntry:truncate-multiline:
717    *
718    * When %TRUE, pasted multi-line text is truncated to the first line.
719    *
720    * Since: 2.10
721    */
722   g_object_class_install_property (gobject_class,
723                                    PROP_TRUNCATE_MULTILINE,
724                                    g_param_spec_boolean ("truncate-multiline",
725                                                          P_("Truncate multiline"),
726                                                          P_("Whether to truncate multiline pastes to one line."),
727                                                          FALSE,
728                                                          GTK_PARAM_READWRITE));
729
730   /**
731    * GtkEntry:shadow-type:
732    *
733    * Which kind of shadow to draw around the entry when 
734    * #GtkEntry:has-frame is set to %TRUE.
735    *
736    * Since: 2.12
737    */
738   g_object_class_install_property (gobject_class,
739                                    PROP_SHADOW_TYPE,
740                                    g_param_spec_enum ("shadow-type",
741                                                       P_("Shadow type"),
742                                                       P_("Which kind of shadow to draw around the entry when has-frame is set"),
743                                                       GTK_TYPE_SHADOW_TYPE,
744                                                       GTK_SHADOW_IN,
745                                                       GTK_PARAM_READWRITE));
746
747   /**
748    * GtkEntry:overwrite-mode:
749    *
750    * If text is overwritten when typing in the #GtkEntry.
751    *
752    * Since: 2.14
753    */
754   g_object_class_install_property (gobject_class,
755                                    PROP_OVERWRITE_MODE,
756                                    g_param_spec_boolean ("overwrite-mode",
757                                                          P_("Overwrite mode"),
758                                                          P_("Whether new text overwrites existing text"),
759                                                          FALSE,
760                                                          GTK_PARAM_READWRITE));
761
762   /**
763    * GtkEntry:text-length:
764    *
765    * The length of the text in the #GtkEntry.
766    *
767    * Since: 2.14
768    */
769   g_object_class_install_property (gobject_class,
770                                    PROP_TEXT_LENGTH,
771                                    g_param_spec_uint ("text-length",
772                                                       P_("Text length"),
773                                                       P_("Length of the text currently in the entry"),
774                                                       0, 
775                                                       G_MAXUINT16,
776                                                       0,
777                                                       GTK_PARAM_READABLE));
778   /**
779    * GtkEntry:invisible-char-set:
780    *
781    * Whether the invisible char has been set for the #GtkEntry.
782    *
783    * Since: 2.16
784    */
785   g_object_class_install_property (gobject_class,
786                                    PROP_INVISIBLE_CHAR_SET,
787                                    g_param_spec_boolean ("invisible-char-set",
788                                                          P_("Invisible char set"),
789                                                          P_("Whether the invisible char has been set"),
790                                                          FALSE,
791                                                          GTK_PARAM_READWRITE));
792
793   /**
794    * GtkEntry:caps-lock-warning
795    *
796    * Whether password entries will show a warning when Caps Lock is on
797    * or an input method is active.
798    *
799    * Since: 2.16
800    */
801   g_object_class_install_property (gobject_class,
802                                    PROP_CAPS_LOCK_WARNING,
803                                    g_param_spec_boolean ("caps-lock-warning",
804                                                          P_("Caps Lock warning"),
805                                                          P_("Whether password entries will show a warning when Caps Lock is on or an input method is active"),
806                                                          TRUE,
807                                                          GTK_PARAM_READWRITE));
808
809   /**
810    * GtkEntry:progress-fraction:
811    *
812    * The current fraction of the task that's been completed.
813    *
814    * Since: 2.16
815    */
816   g_object_class_install_property (gobject_class,
817                                    PROP_PROGRESS_FRACTION,
818                                    g_param_spec_double ("progress-fraction",
819                                                         P_("Progress Fraction"),
820                                                         P_("The current fraction of the task that's been completed"),
821                                                         0.0,
822                                                         1.0,
823                                                         0.0,
824                                                         GTK_PARAM_READWRITE));
825
826   /**
827    * GtkEntry:progress-pulse-step:
828    *
829    * The fraction of total entry width to move the progress
830    * bouncing block for each call to gtk_entry_progress_pulse().
831    *
832    * Since: 2.16
833    */
834   g_object_class_install_property (gobject_class,
835                                    PROP_PROGRESS_PULSE_STEP,
836                                    g_param_spec_double ("progress-pulse-step",
837                                                         P_("Progress Pulse Step"),
838                                                         P_("The fraction of total entry width to move the progress bouncing block for each call to gtk_entry_progress_pulse()"),
839                                                         0.0,
840                                                         1.0,
841                                                         0.1,
842                                                         GTK_PARAM_READWRITE));
843
844   /**
845    * GtkEntry:pixbuf-primary:
846    *
847    * A pixbuf to use as the primary icon for the entry.
848    *
849    * Since: 2.16
850    */
851   g_object_class_install_property (gobject_class,
852                                    PROP_PIXBUF_PRIMARY,
853                                    g_param_spec_object ("pixbuf-primary",
854                                                         P_("Primary pixbuf"),
855                                                         P_("Primary pixbuf for the entry"),
856                                                         GDK_TYPE_PIXBUF,
857                                                         GTK_PARAM_READWRITE));
858   
859   /**
860    * GtkEntry:pixbuf-secondary:
861    *
862    * An pixbuf to use as the secondary icon for the entry.
863    *
864    * Since: 2.16
865    */
866   g_object_class_install_property (gobject_class,
867                                    PROP_PIXBUF_SECONDARY,
868                                    g_param_spec_object ("pixbuf-secondary",
869                                                         P_("Secondary pixbuf"),
870                                                         P_("Secondary pixbuf for the entry"),
871                                                         GDK_TYPE_PIXBUF,
872                                                         GTK_PARAM_READWRITE));
873
874   /**
875    * GtkEntry:stock-primary:
876    *
877    * The stock id to use for the primary icon for the entry.
878    *
879    * Since: 2.16
880    */
881   g_object_class_install_property (gobject_class,
882                                    PROP_STOCK_PRIMARY,
883                                    g_param_spec_string ("stock-primary",
884                                                         P_("Primary stock ID"),
885                                                         P_("Stock ID for primary icon"),
886                                                         NULL,
887                                                         GTK_PARAM_WRITABLE));
888
889   /**
890    * GtkEntry:stock-secondary:
891    *
892    * The stock id to use for the secondary icon for the entry.
893    *
894    * Since: 2.16
895    */
896   g_object_class_install_property (gobject_class,
897                                    PROP_STOCK_SECONDARY,
898                                    g_param_spec_string ("stock-secondary",
899                                                         P_("Secondary stock ID"),
900                                                         P_("Stock ID for secondary icon"),
901                                                         NULL,
902                                                         GTK_PARAM_WRITABLE));
903   
904   /**
905    * GtkEntry:icon-name-primary:
906    *
907    * The icon name to use for the primary icon for the entry.
908    *
909    * Since: 2.16
910    */
911   g_object_class_install_property (gobject_class,
912                                    PROP_ICON_NAME_PRIMARY,
913                                    g_param_spec_string ("icon-name-primary",
914                                                         P_("Primary icon name"),
915                                                         P_("Icon name for primary icon"),
916                                                         NULL,
917                                                         GTK_PARAM_WRITABLE));
918   
919   /**
920    * GtkEntry:icon-name-secondary:
921    *
922    * The icon name to use for the secondary icon for the entry.
923    *
924    * Since: 2.16
925    */
926   g_object_class_install_property (gobject_class,
927                                    PROP_ICON_NAME_SECONDARY,
928                                    g_param_spec_string ("icon-name-secondary",
929                                                         P_("Secondary icon name"),
930                                                         P_("Icon name for secondary icon"),
931                                                         NULL,
932                                                         GTK_PARAM_WRITABLE));
933   
934   /**
935    * GtkEntry:gicon-primary:
936    *
937    * The #GIcon to use for the primary icon for the entry.
938    *
939    * Since: 2.16
940    */
941   g_object_class_install_property (gobject_class,
942                                    PROP_GICON_PRIMARY,
943                                    g_param_spec_object ("gicon-primary",
944                                                         P_("Primary GIcon"),
945                                                         P_("GIcon for primary icon"),
946                                                         G_TYPE_ICON,
947                                                         GTK_PARAM_READWRITE));
948   
949   /**
950    * GtkEntry:gicon-secondary:
951    *
952    * The #GIcon to use for the secondary icon for the entry.
953    *
954    * Since: 2.16
955    */
956   g_object_class_install_property (gobject_class,
957                                    PROP_GICON_SECONDARY,
958                                    g_param_spec_object ("gicon-secondary",
959                                                         P_("Secondary GIcon"),
960                                                         P_("GIcon for secondary icon"),
961                                                         G_TYPE_ICON,
962                                                         GTK_PARAM_READWRITE));
963   
964   /**
965    * GtkEntry:storage-type-primary:
966    *
967    * The representation which is used for the primary icon of the entry.
968    *
969    * Since: 2.16
970    */
971   g_object_class_install_property (gobject_class,
972                                    PROP_STORAGE_TYPE_PRIMARY,
973                                    g_param_spec_enum ("storage-type-primary",
974                                                       P_("Primary storage type"),
975                                                       P_("The representation being used for primary icon"),
976                                                       GTK_TYPE_IMAGE_TYPE,
977                                                       GTK_IMAGE_EMPTY,
978                                                       GTK_PARAM_READABLE));
979   
980   /**
981    * GtkEntry:storage-type-secondary:
982    *
983    * The representation which is used for the secondary icon of the entry.
984    *
985    * Since: 2.16
986    */
987   g_object_class_install_property (gobject_class,
988                                    PROP_STORAGE_TYPE_SECONDARY,
989                                    g_param_spec_enum ("storage-type-secondary",
990                                                       P_("Secondary storage type"),
991                                                       P_("The representation being used for secondary icon"),
992                                                       GTK_TYPE_IMAGE_TYPE,
993                                                       GTK_IMAGE_EMPTY,
994                                                       GTK_PARAM_READABLE));
995   
996   /**
997    * GtkEntry:activatable-primary:
998    *
999    * Whether the primary icon is activatable.
1000    *
1001    * GTK+ emits the #GtkEntry::icon-pressed and #GtkEntry::icon-released 
1002    * signals only on sensitive, activatable icons. 
1003    *
1004    * Sensitive, but non-activatable icons can be used for purely 
1005    * informational purposes.
1006    *
1007    * Since: 2.16
1008    */
1009   g_object_class_install_property (gobject_class,
1010                                    PROP_ACTIVATABLE_PRIMARY,
1011                                    g_param_spec_boolean ("activatable-primary",
1012                                                          P_("Primary icon activatable"),
1013                                                          P_("Whether the primary icon is activatable"),
1014                                                          FALSE,
1015                                                          GTK_PARAM_READWRITE));
1016   
1017   /**
1018    * GtkEntry:activatable-secondary:
1019    *
1020    * Whether the secondary icon is activatable.
1021    *
1022    * GTK+ emits the #GtkEntry::icon-pressed and #GtkEntry::icon-released 
1023    * signals only on sensitive, activatable icons.
1024    *
1025    * Sensitive, but non-activatable icons can be used for purely 
1026    * informational purposes.
1027    *
1028    * Since: 2.16
1029    */
1030   g_object_class_install_property (gobject_class,
1031                                    PROP_ACTIVATABLE_SECONDARY,
1032                                    g_param_spec_boolean ("activatable-secondary",
1033                                                          P_("Secondary icon activatable"),
1034                                                          P_("Whether the secondary icon is activatable"),
1035                                                          FALSE,
1036                                                          GTK_PARAM_READWRITE));
1037   
1038   
1039   /**
1040    * GtkEntry:sensitive-primary:
1041    *
1042    * Whether the primary icon is sensitive.
1043    *
1044    * An insensitive icon appears grayed out. GTK+ does not emit the 
1045    * #GtkEntry::icon-pressed and #GtkEntry::icon-released signals and 
1046    * does not allow DND from insensitive icons.
1047    *
1048    * An icon should be set insensitive if the action that would trigger
1049    * when clicked is currently not available.
1050    * 
1051    * Since: 2.16
1052    */
1053   g_object_class_install_property (gobject_class,
1054                                    PROP_SENSITIVE_PRIMARY,
1055                                    g_param_spec_boolean ("sensitive-primary",
1056                                                          P_("Primary icon sensitive"),
1057                                                          P_("Whether the primary icon is sensitive"),
1058                                                          TRUE,
1059                                                          GTK_PARAM_READWRITE));
1060   
1061   /**
1062    * GtkEntry:sensitive-secondary:
1063    *
1064    * Whether the secondary icon is sensitive.
1065    *
1066    * An insensitive icon appears grayed out. GTK+ does not emit the 
1067    * #GtkEntry::icon-pressed and #GtkEntry::icon-released signals and 
1068    * does not allow DND from insensitive icons.
1069    *
1070    * An icon should be set insensitive if the action that would trigger
1071    * when clicked is currently not available.
1072    *
1073    * Since: 2.16
1074    */
1075   g_object_class_install_property (gobject_class,
1076                                    PROP_SENSITIVE_SECONDARY,
1077                                    g_param_spec_boolean ("sensitive-secondary",
1078                                                          P_("Secondary icon sensitive"),
1079                                                          P_("Whether the secondary icon is sensitive"),
1080                                                          TRUE,
1081                                                          GTK_PARAM_READWRITE));
1082   
1083   /**
1084    * GtkEntry:prelight:
1085    *
1086    * The prelight style property determines whether activatable
1087    * icons prelight on mouseover.
1088    *
1089    * Since: 2.16
1090    */
1091   gtk_widget_class_install_style_property (widget_class,
1092                                            g_param_spec_boolean ("prelight",
1093                                                                  P_("Prelight"),
1094                                                                  P_("Whether activatable icons should prelight when hovered"),
1095                                                                  TRUE,
1096                                                                  GTK_PARAM_READABLE));
1097   
1098   signals[POPULATE_POPUP] =
1099     g_signal_new (I_("populate-popup"),
1100                   G_OBJECT_CLASS_TYPE (gobject_class),
1101                   G_SIGNAL_RUN_LAST,
1102                   G_STRUCT_OFFSET (GtkEntryClass, populate_popup),
1103                   NULL, NULL,
1104                   _gtk_marshal_VOID__OBJECT,
1105                   G_TYPE_NONE, 1,
1106                   GTK_TYPE_MENU);
1107   
1108  /* Action signals */
1109   
1110   signals[ACTIVATE] =
1111     g_signal_new (I_("activate"),
1112                   G_OBJECT_CLASS_TYPE (gobject_class),
1113                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1114                   G_STRUCT_OFFSET (GtkEntryClass, activate),
1115                   NULL, NULL,
1116                   _gtk_marshal_VOID__VOID,
1117                   G_TYPE_NONE, 0);
1118   widget_class->activate_signal = signals[ACTIVATE];
1119
1120   signals[MOVE_CURSOR] = 
1121     g_signal_new (I_("move-cursor"),
1122                   G_OBJECT_CLASS_TYPE (gobject_class),
1123                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1124                   G_STRUCT_OFFSET (GtkEntryClass, move_cursor),
1125                   NULL, NULL,
1126                   _gtk_marshal_VOID__ENUM_INT_BOOLEAN,
1127                   G_TYPE_NONE, 3,
1128                   GTK_TYPE_MOVEMENT_STEP,
1129                   G_TYPE_INT,
1130                   G_TYPE_BOOLEAN);
1131
1132   signals[INSERT_AT_CURSOR] = 
1133     g_signal_new (I_("insert-at-cursor"),
1134                   G_OBJECT_CLASS_TYPE (gobject_class),
1135                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1136                   G_STRUCT_OFFSET (GtkEntryClass, insert_at_cursor),
1137                   NULL, NULL,
1138                   _gtk_marshal_VOID__STRING,
1139                   G_TYPE_NONE, 1,
1140                   G_TYPE_STRING);
1141
1142   signals[DELETE_FROM_CURSOR] = 
1143     g_signal_new (I_("delete-from-cursor"),
1144                   G_OBJECT_CLASS_TYPE (gobject_class),
1145                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1146                   G_STRUCT_OFFSET (GtkEntryClass, delete_from_cursor),
1147                   NULL, NULL,
1148                   _gtk_marshal_VOID__ENUM_INT,
1149                   G_TYPE_NONE, 2,
1150                   GTK_TYPE_DELETE_TYPE,
1151                   G_TYPE_INT);
1152
1153   signals[BACKSPACE] =
1154     g_signal_new (I_("backspace"),
1155                   G_OBJECT_CLASS_TYPE (gobject_class),
1156                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1157                   G_STRUCT_OFFSET (GtkEntryClass, backspace),
1158                   NULL, NULL,
1159                   _gtk_marshal_VOID__VOID,
1160                   G_TYPE_NONE, 0);
1161
1162   signals[CUT_CLIPBOARD] =
1163     g_signal_new (I_("cut-clipboard"),
1164                   G_OBJECT_CLASS_TYPE (gobject_class),
1165                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1166                   G_STRUCT_OFFSET (GtkEntryClass, cut_clipboard),
1167                   NULL, NULL,
1168                   _gtk_marshal_VOID__VOID,
1169                   G_TYPE_NONE, 0);
1170
1171   signals[COPY_CLIPBOARD] =
1172     g_signal_new (I_("copy-clipboard"),
1173                   G_OBJECT_CLASS_TYPE (gobject_class),
1174                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1175                   G_STRUCT_OFFSET (GtkEntryClass, copy_clipboard),
1176                   NULL, NULL,
1177                   _gtk_marshal_VOID__VOID,
1178                   G_TYPE_NONE, 0);
1179
1180   signals[PASTE_CLIPBOARD] =
1181     g_signal_new (I_("paste-clipboard"),
1182                   G_OBJECT_CLASS_TYPE (gobject_class),
1183                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1184                   G_STRUCT_OFFSET (GtkEntryClass, paste_clipboard),
1185                   NULL, NULL,
1186                   _gtk_marshal_VOID__VOID,
1187                   G_TYPE_NONE, 0);
1188
1189   signals[TOGGLE_OVERWRITE] =
1190     g_signal_new (I_("toggle-overwrite"),
1191                   G_OBJECT_CLASS_TYPE (gobject_class),
1192                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1193                   G_STRUCT_OFFSET (GtkEntryClass, toggle_overwrite),
1194                   NULL, NULL,
1195                   _gtk_marshal_VOID__VOID,
1196                   G_TYPE_NONE, 0);
1197
1198   /**
1199    * GtkEntry::icon-pressed:
1200    * @entry: The entry on which the signal is emitted
1201    * @icon_pos: The position of the clicked icon
1202    * @event: the button press event
1203    *
1204    * The ::icon-pressed signal is emitted when an activatable icon 
1205    * is clicked.
1206    *
1207    * Since: 2.16
1208    */
1209   signals[ICON_PRESSED] =
1210     g_signal_new (I_("icon-pressed"),
1211                   G_TYPE_FROM_CLASS (gobject_class),
1212                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1213                   0,
1214                   NULL, NULL,
1215                   _gtk_marshal_VOID__ENUM_BOXED,
1216                   G_TYPE_NONE, 2,
1217                   GTK_TYPE_ENTRY_ICON_POSITION,
1218                   GDK_TYPE_EVENT);
1219   
1220   /**
1221    * GtkEntry::icon-released:
1222    * @entry: The entry on which the signal is emitted
1223    * @icon_pos: The position of the clicked icon
1224    * @event: the button release event
1225    *
1226    * The ::icon-released signal is emitted on the button release from a
1227    * mouse click over an activatable icon.
1228    *
1229    * Since: 2.16
1230    */
1231   signals[ICON_RELEASED] =
1232     g_signal_new (I_("icon-released"),
1233                   G_TYPE_FROM_CLASS (gobject_class),
1234                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1235                   0,
1236                   NULL, NULL,
1237                   _gtk_marshal_VOID__ENUM_BOXED,
1238                   G_TYPE_NONE, 2,
1239                   GTK_TYPE_ENTRY_ICON_POSITION,
1240                   GDK_TYPE_EVENT);
1241
1242
1243   /*
1244    * Key bindings
1245    */
1246
1247   binding_set = gtk_binding_set_by_class (class);
1248
1249   /* Moving the insertion point */
1250   add_move_binding (binding_set, GDK_Right, 0,
1251                     GTK_MOVEMENT_VISUAL_POSITIONS, 1);
1252   
1253   add_move_binding (binding_set, GDK_Left, 0,
1254                     GTK_MOVEMENT_VISUAL_POSITIONS, -1);
1255
1256   add_move_binding (binding_set, GDK_KP_Right, 0,
1257                     GTK_MOVEMENT_VISUAL_POSITIONS, 1);
1258   
1259   add_move_binding (binding_set, GDK_KP_Left, 0,
1260                     GTK_MOVEMENT_VISUAL_POSITIONS, -1);
1261   
1262   add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
1263                     GTK_MOVEMENT_WORDS, 1);
1264
1265   add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
1266                     GTK_MOVEMENT_WORDS, -1);
1267
1268   add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
1269                     GTK_MOVEMENT_WORDS, 1);
1270
1271   add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
1272                     GTK_MOVEMENT_WORDS, -1);
1273   
1274   add_move_binding (binding_set, GDK_Home, 0,
1275                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
1276
1277   add_move_binding (binding_set, GDK_End, 0,
1278                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
1279
1280   add_move_binding (binding_set, GDK_KP_Home, 0,
1281                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
1282
1283   add_move_binding (binding_set, GDK_KP_End, 0,
1284                     GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
1285   
1286   add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
1287                     GTK_MOVEMENT_BUFFER_ENDS, -1);
1288
1289   add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
1290                     GTK_MOVEMENT_BUFFER_ENDS, 1);
1291
1292   add_move_binding (binding_set, GDK_KP_Home, GDK_CONTROL_MASK,
1293                     GTK_MOVEMENT_BUFFER_ENDS, -1);
1294
1295   add_move_binding (binding_set, GDK_KP_End, GDK_CONTROL_MASK,
1296                     GTK_MOVEMENT_BUFFER_ENDS, 1);
1297
1298   /* Select all
1299    */
1300   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK,
1301                                 "move-cursor", 3,
1302                                 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
1303                                 G_TYPE_INT, -1,
1304                                 G_TYPE_BOOLEAN, FALSE);
1305   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK,
1306                                 "move-cursor", 3,
1307                                 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
1308                                 G_TYPE_INT, 1,
1309                                 G_TYPE_BOOLEAN, TRUE);  
1310
1311   gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK,
1312                                 "move-cursor", 3,
1313                                 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
1314                                 G_TYPE_INT, -1,
1315                                 G_TYPE_BOOLEAN, FALSE);
1316   gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK,
1317                                 "move-cursor", 3,
1318                                 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
1319                                 G_TYPE_INT, 1,
1320                                 G_TYPE_BOOLEAN, TRUE);  
1321   /* Unselect all 
1322    */
1323   gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK,
1324                                 "move-cursor", 3,
1325                                 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_VISUAL_POSITIONS,
1326                                 G_TYPE_INT, 0,
1327                                 G_TYPE_BOOLEAN, FALSE);
1328   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_SHIFT_MASK | GDK_CONTROL_MASK,
1329                                 "move-cursor", 3,
1330                                 GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_VISUAL_POSITIONS,
1331                                 G_TYPE_INT, 0,
1332                                 G_TYPE_BOOLEAN, FALSE);
1333
1334   /* Activate
1335    */
1336   gtk_binding_entry_add_signal (binding_set, GDK_Return, 0,
1337                                 "activate", 0);
1338   gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0,
1339                                 "activate", 0);
1340   gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0,
1341                                 "activate", 0);
1342   
1343   /* Deleting text */
1344   gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0,
1345                                 "delete-from-cursor", 2,
1346                                 G_TYPE_ENUM, GTK_DELETE_CHARS,
1347                                 G_TYPE_INT, 1);
1348
1349   gtk_binding_entry_add_signal (binding_set, GDK_KP_Delete, 0,
1350                                 "delete-from-cursor", 2,
1351                                 G_TYPE_ENUM, GTK_DELETE_CHARS,
1352                                 G_TYPE_INT, 1);
1353   
1354   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0,
1355                                 "backspace", 0);
1356
1357   /* Make this do the same as Backspace, to help with mis-typing */
1358   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_SHIFT_MASK,
1359                                 "backspace", 0);
1360
1361   gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_CONTROL_MASK,
1362                                 "delete-from-cursor", 2,
1363                                 G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
1364                                 G_TYPE_INT, 1);
1365
1366   gtk_binding_entry_add_signal (binding_set, GDK_KP_Delete, GDK_CONTROL_MASK,
1367                                 "delete-from-cursor", 2,
1368                                 G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
1369                                 G_TYPE_INT, 1);
1370   
1371   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK,
1372                                 "delete-from-cursor", 2,
1373                                 G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
1374                                 G_TYPE_INT, -1);
1375
1376   /* Cut/copy/paste */
1377
1378   gtk_binding_entry_add_signal (binding_set, GDK_x, GDK_CONTROL_MASK,
1379                                 "cut-clipboard", 0);
1380   gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
1381                                 "copy-clipboard", 0);
1382   gtk_binding_entry_add_signal (binding_set, GDK_v, GDK_CONTROL_MASK,
1383                                 "paste-clipboard", 0);
1384
1385   gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_SHIFT_MASK,
1386                                 "cut-clipboard", 0);
1387   gtk_binding_entry_add_signal (binding_set, GDK_Insert, GDK_CONTROL_MASK,
1388                                 "copy-clipboard", 0);
1389   gtk_binding_entry_add_signal (binding_set, GDK_Insert, GDK_SHIFT_MASK,
1390                                 "paste-clipboard", 0);
1391
1392   /* Overwrite */
1393   gtk_binding_entry_add_signal (binding_set, GDK_Insert, 0,
1394                                 "toggle-overwrite", 0);
1395   gtk_binding_entry_add_signal (binding_set, GDK_KP_Insert, 0,
1396                                 "toggle-overwrite", 0);
1397
1398   /**
1399    * GtkEntry:inner-border:
1400    *
1401    * Sets the text area's border between the text and the frame.
1402    *
1403    * Since: 2.10
1404    */
1405   gtk_widget_class_install_style_property (widget_class,
1406                                            g_param_spec_boxed ("inner-border",
1407                                                                P_("Inner Border"),
1408                                                                P_("Border between text and frame."),
1409                                                                GTK_TYPE_BORDER,
1410                                                                GTK_PARAM_READABLE));
1411
1412    /**
1413     * GtkEntry:state-hint:
1414     *
1415     * Indicates whether to pass a proper widget state when
1416     * drawing the shadow and the widget background.
1417     *
1418     * Since: 2.16
1419     */
1420    gtk_widget_class_install_style_property (widget_class,
1421                                             g_param_spec_boolean ("state-hint",
1422                                                                   P_("State Hint"),
1423                                                                   P_("Whether to pass a proper state when drawing shadow or background"),
1424                                                                   FALSE,
1425                                                                   GTK_PARAM_READABLE));
1426
1427    gtk_settings_install_property (g_param_spec_boolean ("gtk-entry-select-on-focus",
1428                                                        P_("Select on focus"),
1429                                                        P_("Whether to select the contents of an entry when it is focused"),
1430                                                        TRUE,
1431                                                        GTK_PARAM_READWRITE));
1432
1433   /**
1434    * GtkSettings:gtk-entry-password-hint-timeout:
1435    *
1436    * How long to show the last input character in hidden
1437    * entries. This value is in milliseconds. 0 disables showing the
1438    * last char. 600 is a good value for enabling it.
1439    *
1440    * Since: 2.10
1441    */
1442   gtk_settings_install_property (g_param_spec_uint ("gtk-entry-password-hint-timeout",
1443                                                     P_("Password Hint Timeout"),
1444                                                     P_("How long to show the last input character in hidden entries"),
1445                                                     0, G_MAXUINT, 0,
1446                                                     GTK_PARAM_READWRITE));
1447
1448   g_type_class_add_private (gobject_class, sizeof (GtkEntryPrivate));
1449 }
1450
1451 static void
1452 gtk_entry_editable_init (GtkEditableClass *iface)
1453 {
1454   iface->do_insert_text = gtk_entry_insert_text;
1455   iface->do_delete_text = gtk_entry_delete_text;
1456   iface->insert_text = gtk_entry_real_insert_text;
1457   iface->delete_text = gtk_entry_real_delete_text;
1458   iface->get_chars = gtk_entry_get_chars;
1459   iface->set_selection_bounds = gtk_entry_set_selection_bounds;
1460   iface->get_selection_bounds = gtk_entry_get_selection_bounds;
1461   iface->set_position = gtk_entry_real_set_position;
1462   iface->get_position = gtk_entry_get_position;
1463 }
1464
1465 static void
1466 gtk_entry_cell_editable_init (GtkCellEditableIface *iface)
1467 {
1468   iface->start_editing = gtk_entry_start_editing;
1469 }
1470
1471 static void
1472 gtk_entry_set_property (GObject         *object,
1473                         guint            prop_id,
1474                         const GValue    *value,
1475                         GParamSpec      *pspec)
1476 {
1477   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (object);
1478   GtkEntry *entry = GTK_ENTRY (object);
1479
1480   switch (prop_id)
1481     {
1482     case PROP_EDITABLE:
1483       {
1484         gboolean new_value = g_value_get_boolean (value);
1485
1486         if (new_value != entry->editable)
1487           {
1488             if (!new_value)
1489               {
1490                 _gtk_entry_reset_im_context (entry);
1491                 if (GTK_WIDGET_HAS_FOCUS (entry))
1492                   gtk_im_context_focus_out (entry->im_context);
1493
1494                 entry->preedit_length = 0;
1495                 entry->preedit_cursor = 0;
1496               }
1497
1498             entry->editable = new_value;
1499
1500             if (new_value && GTK_WIDGET_HAS_FOCUS (entry))
1501               gtk_im_context_focus_in (entry->im_context);
1502             
1503             gtk_entry_queue_draw (entry);
1504           }
1505       }
1506       break;
1507
1508     case PROP_MAX_LENGTH:
1509       gtk_entry_set_max_length (entry, g_value_get_int (value));
1510       break;
1511       
1512     case PROP_VISIBILITY:
1513       gtk_entry_set_visibility (entry, g_value_get_boolean (value));
1514       break;
1515
1516     case PROP_HAS_FRAME:
1517       gtk_entry_set_has_frame (entry, g_value_get_boolean (value));
1518       break;
1519
1520     case PROP_INNER_BORDER:
1521       gtk_entry_set_inner_border (entry, g_value_get_boxed (value));
1522       break;
1523
1524     case PROP_INVISIBLE_CHAR:
1525       gtk_entry_set_invisible_char (entry, g_value_get_uint (value));
1526       break;
1527
1528     case PROP_ACTIVATES_DEFAULT:
1529       gtk_entry_set_activates_default (entry, g_value_get_boolean (value));
1530       break;
1531
1532     case PROP_WIDTH_CHARS:
1533       gtk_entry_set_width_chars (entry, g_value_get_int (value));
1534       break;
1535
1536     case PROP_TEXT:
1537       gtk_entry_set_text (entry, g_value_get_string (value));
1538       break;
1539
1540     case PROP_XALIGN:
1541       gtk_entry_set_alignment (entry, g_value_get_float (value));
1542       break;
1543
1544     case PROP_TRUNCATE_MULTILINE:
1545       entry->truncate_multiline = g_value_get_boolean (value);
1546       break;
1547
1548     case PROP_SHADOW_TYPE:
1549       priv->shadow_type = g_value_get_enum (value);
1550       break;
1551
1552     case PROP_OVERWRITE_MODE:
1553       gtk_entry_set_overwrite_mode (entry, g_value_get_boolean (value));
1554       break;
1555
1556     case PROP_INVISIBLE_CHAR_SET:
1557       if (g_value_get_boolean (value))
1558         priv->invisible_char_set = TRUE;
1559       else
1560         gtk_entry_unset_invisible_char (entry);
1561       break;
1562
1563     case PROP_CAPS_LOCK_WARNING:
1564       priv->caps_lock_warning = g_value_get_boolean (value);
1565       break;
1566
1567     case PROP_PROGRESS_FRACTION:
1568       gtk_entry_set_progress_fraction (entry, g_value_get_double (value));
1569       break;
1570
1571     case PROP_PROGRESS_PULSE_STEP:
1572       gtk_entry_set_progress_pulse_step (entry, g_value_get_double (value));
1573
1574     case PROP_PIXBUF_PRIMARY:
1575       gtk_entry_set_icon_from_pixbuf (entry,
1576                                       GTK_ENTRY_ICON_PRIMARY,
1577                                       g_value_get_object (value));
1578       break;
1579
1580     case PROP_PIXBUF_SECONDARY:
1581       gtk_entry_set_icon_from_pixbuf (entry,
1582                                       GTK_ENTRY_ICON_SECONDARY,
1583                                       g_value_get_object (value));
1584       break;
1585
1586     case PROP_STOCK_PRIMARY:
1587       gtk_entry_set_icon_from_stock (entry,
1588                                      GTK_ENTRY_ICON_PRIMARY,
1589                                      g_value_get_string (value));
1590       break;
1591
1592     case PROP_STOCK_SECONDARY:
1593       gtk_entry_set_icon_from_stock (entry,
1594                                      GTK_ENTRY_ICON_SECONDARY,
1595                                      g_value_get_string (value));
1596       break;
1597
1598     case PROP_ICON_NAME_PRIMARY:
1599       gtk_entry_set_icon_from_icon_name (entry,
1600                                          GTK_ENTRY_ICON_PRIMARY,
1601                                          g_value_get_string (value));
1602       break;
1603
1604     case PROP_ICON_NAME_SECONDARY:
1605       gtk_entry_set_icon_from_icon_name (entry,
1606                                          GTK_ENTRY_ICON_SECONDARY,
1607                                          g_value_get_string (value));
1608       break;
1609
1610     case PROP_GICON_PRIMARY:
1611       gtk_entry_set_icon_from_gicon (entry,
1612                                      GTK_ENTRY_ICON_PRIMARY,
1613                                      g_value_get_object (value));
1614       break;
1615
1616     case PROP_GICON_SECONDARY:
1617       gtk_entry_set_icon_from_gicon (entry,
1618                                      GTK_ENTRY_ICON_SECONDARY,
1619                                      g_value_get_object (value));
1620       break;
1621
1622     case PROP_ACTIVATABLE_PRIMARY:
1623       gtk_entry_set_icon_activatable (entry,
1624                                       GTK_ENTRY_ICON_PRIMARY,
1625                                       g_value_get_boolean (value));
1626       break;
1627
1628     case PROP_ACTIVATABLE_SECONDARY:
1629       gtk_entry_set_icon_activatable (entry,
1630                                       GTK_ENTRY_ICON_SECONDARY,
1631                                       g_value_get_boolean (value));
1632       break;
1633
1634     case PROP_SENSITIVE_PRIMARY:
1635       gtk_entry_set_icon_sensitive (entry,
1636                                     GTK_ENTRY_ICON_PRIMARY,
1637                                     g_value_get_boolean (value));
1638       break;
1639
1640     case PROP_SENSITIVE_SECONDARY:
1641       gtk_entry_set_icon_sensitive (entry,
1642                                     GTK_ENTRY_ICON_SECONDARY,
1643                                     g_value_get_boolean (value));
1644       break;
1645
1646     case PROP_SCROLL_OFFSET:
1647     case PROP_CURSOR_POSITION:
1648     default:
1649       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1650       break;
1651     }
1652 }
1653
1654 static void
1655 gtk_entry_get_property (GObject         *object,
1656                         guint            prop_id,
1657                         GValue          *value,
1658                         GParamSpec      *pspec)
1659 {
1660   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (object);
1661   GtkEntry *entry = GTK_ENTRY (object);
1662
1663   switch (prop_id)
1664     {
1665     case PROP_CURSOR_POSITION:
1666       g_value_set_int (value, entry->current_pos);
1667       break;
1668
1669     case PROP_SELECTION_BOUND:
1670       g_value_set_int (value, entry->selection_bound);
1671       break;
1672
1673     case PROP_EDITABLE:
1674       g_value_set_boolean (value, entry->editable);
1675       break;
1676
1677     case PROP_MAX_LENGTH:
1678       g_value_set_int (value, entry->text_max_length); 
1679       break;
1680
1681     case PROP_VISIBILITY:
1682       g_value_set_boolean (value, entry->visible);
1683       break;
1684
1685     case PROP_HAS_FRAME:
1686       g_value_set_boolean (value, entry->has_frame);
1687       break;
1688
1689     case PROP_INNER_BORDER:
1690       g_value_set_boxed (value, gtk_entry_get_inner_border (entry));
1691       break;
1692
1693     case PROP_INVISIBLE_CHAR:
1694       g_value_set_uint (value, entry->invisible_char);
1695       break;
1696
1697     case PROP_ACTIVATES_DEFAULT:
1698       g_value_set_boolean (value, entry->activates_default);
1699       break;
1700
1701     case PROP_WIDTH_CHARS:
1702       g_value_set_int (value, entry->width_chars);
1703       break;
1704
1705     case PROP_SCROLL_OFFSET:
1706       g_value_set_int (value, entry->scroll_offset);
1707       break;
1708
1709     case PROP_TEXT:
1710       g_value_set_string (value, gtk_entry_get_text (entry));
1711       break;
1712
1713     case PROP_XALIGN:
1714       g_value_set_float (value, gtk_entry_get_alignment (entry));
1715       break;
1716
1717     case PROP_TRUNCATE_MULTILINE:
1718       g_value_set_boolean (value, entry->truncate_multiline);
1719       break;
1720
1721     case PROP_SHADOW_TYPE:
1722       g_value_set_enum (value, priv->shadow_type);
1723       break;
1724
1725     case PROP_OVERWRITE_MODE:
1726       g_value_set_boolean (value, entry->overwrite_mode);
1727       break;
1728
1729     case PROP_TEXT_LENGTH:
1730       g_value_set_uint (value, entry->text_length);
1731       break;
1732
1733     case PROP_INVISIBLE_CHAR_SET:
1734       g_value_set_boolean (value, priv->invisible_char_set);
1735       break;
1736
1737     case PROP_CAPS_LOCK_WARNING:
1738       g_value_set_boolean (value, priv->caps_lock_warning);
1739       break;
1740
1741     case PROP_PROGRESS_FRACTION:
1742       g_value_set_double (value, priv->progress_fraction);
1743       break;
1744
1745     case PROP_PROGRESS_PULSE_STEP:
1746       g_value_set_double (value, priv->progress_pulse_fraction);
1747
1748     case PROP_PIXBUF_PRIMARY:
1749       g_value_set_object (value,
1750                           gtk_entry_get_pixbuf (entry,
1751                                                 GTK_ENTRY_ICON_PRIMARY));
1752       break;
1753
1754     case PROP_PIXBUF_SECONDARY:
1755       g_value_set_object (value,
1756                           gtk_entry_get_pixbuf (entry,
1757                                                 GTK_ENTRY_ICON_SECONDARY));
1758       break;
1759
1760     case PROP_STOCK_PRIMARY:
1761       g_value_set_string (value,
1762                           gtk_entry_get_stock (entry,
1763                                                GTK_ENTRY_ICON_PRIMARY));
1764       break;
1765
1766     case PROP_STOCK_SECONDARY:
1767       g_value_set_string (value,
1768                           gtk_entry_get_stock (entry,
1769                                                GTK_ENTRY_ICON_SECONDARY));
1770       break;
1771
1772     case PROP_ICON_NAME_PRIMARY:
1773       g_value_set_string (value,
1774                           gtk_entry_get_icon_name (entry,
1775                                                    GTK_ENTRY_ICON_PRIMARY));
1776       break;
1777
1778     case PROP_ICON_NAME_SECONDARY:
1779       g_value_set_string (value,
1780                           gtk_entry_get_icon_name (entry,
1781                                                    GTK_ENTRY_ICON_SECONDARY));
1782       break;
1783
1784     case PROP_GICON_PRIMARY:
1785       g_value_set_object (value,
1786                           gtk_entry_get_gicon (entry,
1787                                                GTK_ENTRY_ICON_PRIMARY));
1788       break;
1789
1790     case PROP_GICON_SECONDARY:
1791       g_value_set_object (value,
1792                           gtk_entry_get_gicon (entry,
1793                                                GTK_ENTRY_ICON_SECONDARY));
1794
1795     case PROP_STORAGE_TYPE_PRIMARY:
1796       g_value_set_enum (value,
1797                         gtk_entry_get_storage_type (entry, GTK_ENTRY_ICON_PRIMARY));
1798       break;
1799
1800     case PROP_STORAGE_TYPE_SECONDARY:
1801       g_value_set_enum (value,
1802                         gtk_entry_get_storage_type (entry, GTK_ENTRY_ICON_SECONDARY));
1803       break;
1804
1805     case PROP_ACTIVATABLE_PRIMARY:
1806       g_value_set_boolean (value,
1807                            gtk_entry_get_icon_activatable (entry, GTK_ENTRY_ICON_PRIMARY));
1808       break;
1809
1810     case PROP_ACTIVATABLE_SECONDARY:
1811       g_value_set_boolean (value,
1812                            gtk_entry_get_icon_activatable (entry, GTK_ENTRY_ICON_SECONDARY));
1813       break;
1814
1815     case PROP_SENSITIVE_PRIMARY:
1816       g_value_set_boolean (value,
1817                            gtk_entry_get_icon_sensitive (entry, GTK_ENTRY_ICON_PRIMARY));
1818       break;
1819
1820     case PROP_SENSITIVE_SECONDARY:
1821       g_value_set_boolean (value,
1822                            gtk_entry_get_icon_sensitive (entry, GTK_ENTRY_ICON_SECONDARY));
1823       break;
1824
1825     default:
1826       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1827       break;
1828     }
1829 }
1830
1831 static gunichar
1832 find_invisible_char (GtkWidget *widget)
1833 {
1834   PangoLayout *layout;
1835   PangoAttrList *attr_list;
1836   gint i;
1837   gunichar invisible_chars [] = {
1838     0x25cf, /* BLACK CIRCLE */
1839     0x2022, /* BULLET */
1840     0x2731, /* HEAVY ASTERISK */
1841     0x273a  /* SIXTEEN POINTED ASTERISK */
1842   };
1843
1844   layout = gtk_widget_create_pango_layout (widget, NULL);
1845
1846   attr_list = pango_attr_list_new ();
1847   pango_attr_list_insert (attr_list, pango_attr_fallback_new (FALSE));
1848
1849   pango_layout_set_attributes (layout, attr_list);
1850   pango_attr_list_unref (attr_list);
1851
1852   for (i = 0; i < G_N_ELEMENTS (invisible_chars); i++)
1853     {
1854       gchar text[7] = { 0, };
1855       gint len, count;
1856
1857       len = g_unichar_to_utf8 (invisible_chars[i], text);
1858       pango_layout_set_text (layout, text, len);
1859
1860       count = pango_layout_get_unknown_glyphs_count (layout);
1861
1862       if (count == 0)
1863         {
1864           g_object_unref (layout);
1865           return invisible_chars[i];
1866         }
1867     }
1868
1869   g_object_unref (layout);
1870   return '*';
1871 }
1872
1873 static void
1874 gtk_entry_init (GtkEntry *entry)
1875 {
1876   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
1877   
1878   GTK_WIDGET_SET_FLAGS (entry, GTK_CAN_FOCUS);
1879
1880   entry->text_size = MIN_SIZE;
1881   entry->text = g_malloc (entry->text_size);
1882   entry->text[0] = '\0';
1883
1884   entry->editable = TRUE;
1885   entry->visible = TRUE;
1886   entry->invisible_char = find_invisible_char (GTK_WIDGET (entry));
1887   entry->dnd_position = -1;
1888   entry->width_chars = -1;
1889   entry->is_cell_renderer = FALSE;
1890   entry->editing_canceled = FALSE;
1891   entry->has_frame = TRUE;
1892   entry->truncate_multiline = FALSE;
1893   priv->shadow_type = GTK_SHADOW_IN;
1894   priv->xalign = 0.0;
1895   priv->caps_lock_warning = TRUE;
1896   priv->progress_fraction = 0.0;
1897   priv->progress_pulse_fraction = 0.1;
1898
1899   gtk_drag_dest_set (GTK_WIDGET (entry),
1900                      GTK_DEST_DEFAULT_HIGHLIGHT,
1901                      NULL, 0,
1902                      GDK_ACTION_COPY | GDK_ACTION_MOVE);
1903   gtk_drag_dest_add_text_targets (GTK_WIDGET (entry));
1904
1905   /* This object is completely private. No external entity can gain a reference
1906    * to it; so we create it here and destroy it in finalize().
1907    */
1908   entry->im_context = gtk_im_multicontext_new ();
1909   
1910   g_signal_connect (entry->im_context, "commit",
1911                     G_CALLBACK (gtk_entry_commit_cb), entry);
1912   g_signal_connect (entry->im_context, "preedit-changed",
1913                     G_CALLBACK (gtk_entry_preedit_changed_cb), entry);
1914   g_signal_connect (entry->im_context, "retrieve-surrounding",
1915                     G_CALLBACK (gtk_entry_retrieve_surrounding_cb), entry);
1916   g_signal_connect (entry->im_context, "delete-surrounding",
1917                     G_CALLBACK (gtk_entry_delete_surrounding_cb), entry);
1918 }
1919
1920 static gint
1921 get_icon_width (GtkEntry             *entry,
1922                 GtkEntryIconPosition  icon_pos)
1923 {
1924   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
1925   EntryIconInfo *icon_info;
1926   GdkScreen *screen;
1927   GtkSettings *settings;
1928   gint menu_icon_width;
1929
1930   if (!(icon_info = priv->icons[icon_pos]))
1931     return 0;
1932
1933   if (icon_info->pixbuf == NULL)
1934     return 0;
1935
1936   if (priv->icons[icon_pos] == NULL)
1937     return 0;
1938
1939   screen = gtk_widget_get_screen (GTK_WIDGET (entry));
1940   settings = gtk_settings_get_for_screen (screen);
1941
1942   gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
1943                                      &menu_icon_width, NULL);
1944
1945   return MAX (gdk_pixbuf_get_width (icon_info->pixbuf), menu_icon_width);
1946 }
1947
1948 static void
1949 get_icon_allocation (GtkEntry             *entry,
1950                      gboolean              left,
1951                      GtkAllocation        *widget_alloc,
1952                      GtkAllocation        *text_area_alloc,
1953                      GtkAllocation        *allocation,
1954                      GtkEntryIconPosition *icon_pos)
1955 {
1956   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
1957   gboolean rtl;
1958
1959   rtl = (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL);
1960
1961   if (left)
1962     *icon_pos = (rtl ? GTK_ENTRY_ICON_SECONDARY : GTK_ENTRY_ICON_PRIMARY);
1963   else
1964     *icon_pos = (rtl ? GTK_ENTRY_ICON_PRIMARY : GTK_ENTRY_ICON_SECONDARY);
1965
1966   allocation->y = text_area_alloc->y;
1967   allocation->width = get_icon_width (entry, *icon_pos);
1968   allocation->height = text_area_alloc->height;
1969
1970   if (allocation->width > 0)
1971     allocation->width += 2 * priv->icon_margin;
1972
1973   if (left)
1974     allocation->x = text_area_alloc->x;
1975   else
1976     allocation->x = text_area_alloc->x + text_area_alloc->width - allocation->width;
1977 }
1978
1979
1980 static void
1981 begin_change (GtkEntry *entry)
1982 {
1983   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
1984
1985   priv->change_count++;
1986 }
1987
1988 static void
1989 end_change (GtkEntry *entry)
1990 {
1991   GtkEditable *editable = GTK_EDITABLE (entry);
1992   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
1993  
1994   g_return_if_fail (priv->change_count > 0);
1995
1996   priv->change_count--;
1997
1998   if (priv->change_count == 0)
1999     {
2000        if (priv->real_changed) 
2001          {
2002            g_signal_emit_by_name (editable, "changed");
2003            priv->real_changed = FALSE;
2004          }
2005     } 
2006 }
2007
2008 static void
2009 emit_changed (GtkEntry *entry)
2010 {
2011   GtkEditable *editable = GTK_EDITABLE (entry);
2012   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2013
2014   if (priv->change_count == 0)
2015     g_signal_emit_by_name (editable, "changed");
2016   else 
2017     priv->real_changed = TRUE;
2018 }
2019
2020 /*
2021  * Overwrite a memory that might contain sensitive information.
2022  */
2023 static void
2024 trash_area (gchar *area, gsize len)
2025 {
2026   volatile gchar *varea = (volatile gchar *)area;
2027   while (len-- > 0)
2028     *varea++ = 0;
2029 }
2030
2031 static void
2032 gtk_entry_destroy (GtkObject *object)
2033 {
2034   GtkEntry *entry = GTK_ENTRY (object);
2035
2036   entry->n_bytes = 0;
2037   entry->current_pos = entry->selection_bound = entry->text_length = 0;
2038   _gtk_entry_reset_im_context (entry);
2039   gtk_entry_reset_layout (entry);
2040
2041   if (entry->blink_timeout)
2042     {
2043       g_source_remove (entry->blink_timeout);
2044       entry->blink_timeout = 0;
2045     }
2046
2047   if (entry->recompute_idle)
2048     {
2049       g_source_remove (entry->recompute_idle);
2050       entry->recompute_idle = 0;
2051     }
2052
2053   if (!entry->visible)
2054     {
2055       /* We want to trash the text here because the entry might be leaked.  */
2056       trash_area (entry->text, strlen (entry->text));
2057     }
2058
2059   GTK_OBJECT_CLASS (gtk_entry_parent_class)->destroy (object);
2060 }
2061
2062 static void
2063 gtk_entry_dispose (GObject *object)
2064 {
2065   GtkEntry *entry = GTK_ENTRY (object);
2066
2067   gtk_entry_set_icon_from_pixbuf (entry, GTK_ENTRY_ICON_PRIMARY, NULL);
2068   gtk_entry_set_icon_tooltip_markup (entry, GTK_ENTRY_ICON_PRIMARY, NULL);
2069   gtk_entry_set_icon_from_pixbuf (entry, GTK_ENTRY_ICON_SECONDARY, NULL);
2070   gtk_entry_set_icon_tooltip_markup (entry, GTK_ENTRY_ICON_SECONDARY, NULL);
2071
2072   G_OBJECT_CLASS (gtk_entry_parent_class)->dispose (object);
2073 }
2074
2075 static void
2076 gtk_entry_finalize (GObject *object)
2077 {
2078   GtkEntry *entry = GTK_ENTRY (object);
2079   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2080   EntryIconInfo *icon_info = NULL;
2081   gint i;
2082
2083   for (i = 0; i < MAX_ICONS; i++)
2084     {
2085       if ((icon_info = priv->icons[i]) != NULL)
2086         {
2087           if (icon_info->target_list != NULL)
2088             {
2089               gtk_target_list_unref (icon_info->target_list);
2090               icon_info->target_list = NULL;
2091             }
2092
2093           g_slice_free (EntryIconInfo, icon_info);
2094           priv->icons[i] = NULL;
2095         }
2096     }
2097
2098   gtk_entry_set_completion (entry, NULL);
2099
2100   if (entry->cached_layout)
2101     g_object_unref (entry->cached_layout);
2102
2103   g_object_unref (entry->im_context);
2104
2105   if (entry->blink_timeout)
2106     g_source_remove (entry->blink_timeout);
2107
2108   if (entry->recompute_idle)
2109     g_source_remove (entry->recompute_idle);
2110
2111   entry->text_size = 0;
2112
2113   if (entry->text)
2114     {
2115       if (!entry->visible)
2116         trash_area (entry->text, strlen (entry->text));
2117       g_free (entry->text);
2118       entry->text = NULL;
2119     }
2120
2121   G_OBJECT_CLASS (gtk_entry_parent_class)->finalize (object);
2122 }
2123
2124 static void
2125 update_cursors (GtkWidget *widget)
2126 {
2127   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
2128   EntryIconInfo *icon_info = NULL;
2129   GdkDisplay *display;
2130   GdkCursor *cursor;
2131   gint i;
2132
2133   for (i = 0; i < MAX_ICONS; i++)
2134     {
2135       if ((icon_info = priv->icons[i]) != NULL)
2136         {
2137           if (icon_info->pixbuf != NULL)
2138             gdk_window_show (icon_info->window);
2139
2140           /* The icon windows are not children of the visible entry window,
2141            * thus we can't just inherit the xterm cursor. Slight complication 
2142            * here is that for the entry, insensitive => arrow cursor, but for 
2143            * an icon in a sensitive entry, insensitive => xterm cursor.
2144            */
2145           if (GTK_WIDGET_IS_SENSITIVE (widget) && 
2146               (icon_info->insensitive || 
2147                (icon_info->nonactivatable && icon_info->target_list == NULL)))
2148             {
2149               display = gtk_widget_get_display (widget);
2150               cursor = gdk_cursor_new_for_display (display, GDK_XTERM);
2151               gdk_window_set_cursor (icon_info->window, cursor);
2152               gdk_cursor_unref (cursor);
2153             }
2154           else
2155             {
2156               gdk_window_set_cursor (icon_info->window, NULL);
2157             }
2158         }
2159     }
2160 }
2161
2162 static void
2163 realize_icon_info (GtkWidget *widget, GtkEntryIconPosition icon_pos)
2164 {
2165   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
2166   EntryIconInfo *icon_info = priv->icons[icon_pos];
2167   GdkWindowAttr attributes;
2168   gint attributes_mask;
2169
2170   g_return_if_fail (icon_info != NULL);
2171
2172   attributes.x = 0;
2173   attributes.y = 0;
2174   attributes.width = 1;
2175   attributes.height = 1;
2176   attributes.window_type = GDK_WINDOW_CHILD;
2177   attributes.wclass = GDK_INPUT_OUTPUT;
2178   attributes.visual = gtk_widget_get_visual (widget);
2179   attributes.colormap = gtk_widget_get_colormap (widget);
2180   attributes.event_mask = gtk_widget_get_events (widget);
2181   attributes.event_mask |= (GDK_EXPOSURE_MASK |
2182                                 GDK_BUTTON_PRESS_MASK |
2183                                 GDK_BUTTON_RELEASE_MASK |
2184                                 GDK_BUTTON1_MOTION_MASK |
2185                                 GDK_BUTTON3_MOTION_MASK |
2186                                 GDK_POINTER_MOTION_HINT_MASK |
2187                                 GDK_POINTER_MOTION_MASK |
2188                                 GDK_ENTER_NOTIFY_MASK |
2189                             GDK_LEAVE_NOTIFY_MASK);
2190   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2191
2192   icon_info->window = gdk_window_new (widget->window,
2193                                       &attributes,
2194                                       attributes_mask);
2195   gdk_window_set_user_data (icon_info->window, widget);
2196   gdk_window_set_background (icon_info->window,
2197                              &widget->style->base[GTK_WIDGET_STATE (widget)]);
2198
2199   gtk_widget_queue_resize (widget);
2200 }
2201
2202 static EntryIconInfo*
2203 construct_icon_info (GtkWidget *widget, GtkEntryIconPosition icon_pos)
2204 {
2205   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
2206   EntryIconInfo *icon_info;
2207
2208   g_return_val_if_fail (priv->icons[icon_pos] == NULL, NULL);
2209
2210   icon_info = g_slice_new0 (EntryIconInfo);
2211   priv->icons[icon_pos] = icon_info;
2212
2213   if (GTK_WIDGET_REALIZED (widget))
2214     {
2215       realize_icon_info (widget, icon_pos);
2216     }
2217
2218   if (GTK_WIDGET_MAPPED (widget))
2219     gdk_window_show (icon_info->window);
2220
2221   return icon_info;
2222 }
2223
2224 static void
2225 gtk_entry_map (GtkWidget *widget)
2226 {
2227   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
2228   EntryIconInfo *icon_info = NULL;
2229   gint i;
2230
2231   if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_MAPPED (widget))
2232     {
2233       GTK_WIDGET_CLASS (gtk_entry_parent_class)->map (widget);
2234
2235       for (i = 0; i < MAX_ICONS; i++)
2236         {
2237           if ((icon_info = priv->icons[i]) != NULL)
2238             {
2239               if (icon_info->pixbuf != NULL && icon_info->window != NULL)
2240                 gdk_window_show (icon_info->window);
2241             }
2242         }
2243
2244       update_cursors (widget);
2245     }
2246 }
2247
2248 static void
2249 gtk_entry_unmap (GtkWidget *widget)
2250 {
2251   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
2252   EntryIconInfo *icon_info = NULL;
2253   gint i;
2254
2255   if (GTK_WIDGET_MAPPED (widget))
2256     {
2257       for (i = 0; i < MAX_ICONS; i++)
2258         {
2259           if ((icon_info = priv->icons[i]) != NULL)
2260             {
2261               if (icon_info->pixbuf != NULL && icon_info->window != NULL)
2262                 gdk_window_hide (icon_info->window);
2263             }
2264         }
2265
2266       GTK_WIDGET_CLASS (gtk_entry_parent_class)->unmap (widget);
2267     }
2268 }
2269
2270 static void
2271 gtk_entry_realize (GtkWidget *widget)
2272 {
2273   GtkEntry *entry;
2274   GtkEntryPrivate *priv;
2275   EntryIconInfo *icon_info;
2276   GdkWindowAttr attributes;
2277   gint attributes_mask;
2278   int i;
2279
2280   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
2281   entry = GTK_ENTRY (widget);
2282   priv = GTK_ENTRY_GET_PRIVATE (entry);
2283
2284   attributes.window_type = GDK_WINDOW_CHILD;
2285   
2286   get_widget_window_size (entry, &attributes.x, &attributes.y, &attributes.width, &attributes.height);
2287
2288   attributes.wclass = GDK_INPUT_OUTPUT;
2289   attributes.visual = gtk_widget_get_visual (widget);
2290   attributes.colormap = gtk_widget_get_colormap (widget);
2291   attributes.event_mask = gtk_widget_get_events (widget);
2292   attributes.event_mask |= (GDK_EXPOSURE_MASK |
2293                             GDK_BUTTON_PRESS_MASK |
2294                             GDK_BUTTON_RELEASE_MASK |
2295                             GDK_BUTTON1_MOTION_MASK |
2296                             GDK_BUTTON3_MOTION_MASK |
2297                             GDK_POINTER_MOTION_HINT_MASK |
2298                             GDK_POINTER_MOTION_MASK |
2299                             GDK_ENTER_NOTIFY_MASK |
2300                             GDK_LEAVE_NOTIFY_MASK);
2301   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
2302
2303   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
2304   gdk_window_set_user_data (widget->window, entry);
2305
2306   gtk_entry_get_text_area_size (entry, &attributes.x, &attributes.y, &attributes.width, &attributes.height);
2307  
2308   if (GTK_WIDGET_IS_SENSITIVE (widget))
2309     {
2310       attributes.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM);
2311       attributes_mask |= GDK_WA_CURSOR;
2312     }
2313
2314   entry->text_area = gdk_window_new (widget->window, &attributes, attributes_mask);
2315
2316   gdk_window_set_user_data (entry->text_area, entry);
2317
2318   if (attributes_mask & GDK_WA_CURSOR)
2319     gdk_cursor_unref (attributes.cursor);
2320
2321   widget->style = gtk_style_attach (widget->style, widget->window);
2322
2323   gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2324   gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2325
2326   gdk_window_show (entry->text_area);
2327
2328   gtk_im_context_set_client_window (entry->im_context, entry->text_area);
2329
2330   gtk_entry_adjust_scroll (entry);
2331   gtk_entry_update_primary_selection (entry);
2332
2333
2334   /* If the icon positions are already setup, create their windows.
2335    * Otherwise if they don't exist yet, then construct_icon_info()
2336    * will create the windows once the widget is already realized.
2337    */
2338   for (i = 0; i < MAX_ICONS; i++)
2339     {
2340       if ((icon_info = priv->icons[i]) != NULL)
2341         {
2342           if (icon_info->window == NULL)
2343             realize_icon_info (widget, i);
2344         }
2345     }
2346
2347   gtk_widget_queue_resize (widget);
2348 }
2349
2350 static void
2351 gtk_entry_unrealize (GtkWidget *widget)
2352 {
2353   GtkEntry *entry = GTK_ENTRY (widget);
2354   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2355   GtkClipboard *clipboard;
2356   EntryIconInfo *icon_info;
2357   gint i;
2358
2359   gtk_entry_reset_layout (entry);
2360   
2361   gtk_im_context_set_client_window (entry->im_context, NULL);
2362
2363   clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_PRIMARY);
2364   if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (entry))
2365     gtk_clipboard_clear (clipboard);
2366   
2367   if (entry->text_area)
2368     {
2369       gdk_window_set_user_data (entry->text_area, NULL);
2370       gdk_window_destroy (entry->text_area);
2371       entry->text_area = NULL;
2372     }
2373
2374   if (entry->popup_menu)
2375     {
2376       gtk_widget_destroy (entry->popup_menu);
2377       entry->popup_menu = NULL;
2378     }
2379
2380   GTK_WIDGET_CLASS (gtk_entry_parent_class)->unrealize (widget);
2381
2382   for (i = 0; i < MAX_ICONS; i++)
2383     {
2384       if ((icon_info = priv->icons[i]) != NULL)
2385         {
2386           if (icon_info->window != NULL)
2387             {
2388               gdk_window_destroy (icon_info->window);
2389               icon_info->window = NULL;
2390             }
2391         }
2392     }
2393 }
2394
2395 void
2396 _gtk_entry_get_borders (GtkEntry *entry,
2397                         gint     *xborder,
2398                         gint     *yborder)
2399 {
2400   GtkWidget *widget = GTK_WIDGET (entry);
2401   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
2402
2403   if (entry->has_frame)
2404     {
2405       *xborder = widget->style->xthickness;
2406       *yborder = widget->style->ythickness;
2407     }
2408   else
2409     {
2410       *xborder = 0;
2411       *yborder = 0;
2412     }
2413
2414   if (!priv->interior_focus)
2415     {
2416       *xborder += priv->focus_width;
2417       *yborder += priv->focus_width;
2418     }
2419 }
2420
2421 static void
2422 gtk_entry_size_request (GtkWidget      *widget,
2423                         GtkRequisition *requisition)
2424 {
2425   GtkEntry *entry = GTK_ENTRY (widget);
2426   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2427   PangoFontMetrics *metrics;
2428   gint xborder, yborder;
2429   GtkBorder inner_border;
2430   PangoContext *context;
2431   int icon_widths = 0;
2432   int icon_width, i;
2433   
2434   gtk_widget_ensure_style (widget);
2435   context = gtk_widget_get_pango_context (widget);
2436   metrics = pango_context_get_metrics (context,
2437                                        widget->style->font_desc,
2438                                        pango_context_get_language (context));
2439
2440   entry->ascent = pango_font_metrics_get_ascent (metrics);
2441   entry->descent = pango_font_metrics_get_descent (metrics);
2442   
2443   _gtk_entry_get_borders (entry, &xborder, &yborder);
2444   _gtk_entry_effective_inner_border (entry, &inner_border);
2445
2446   if (entry->width_chars < 0)
2447     requisition->width = MIN_ENTRY_WIDTH + xborder * 2 + inner_border.left + inner_border.right;
2448   else
2449     {
2450       gint char_width = pango_font_metrics_get_approximate_char_width (metrics);
2451       gint digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
2452       gint char_pixels = (MAX (char_width, digit_width) + PANGO_SCALE - 1) / PANGO_SCALE;
2453       
2454       requisition->width = char_pixels * entry->width_chars + xborder * 2 + inner_border.left + inner_border.right;
2455     }
2456     
2457   requisition->height = PANGO_PIXELS (entry->ascent + entry->descent) + yborder * 2 + inner_border.top + inner_border.bottom;
2458
2459   for (i = 0; i < MAX_ICONS; i++)
2460     {
2461       icon_width = get_icon_width (entry, i);
2462       if (icon_width > 0)
2463         icon_widths += icon_width + 2 * priv->icon_margin;
2464     }
2465
2466   if (icon_widths > requisition->width)
2467     requisition->width += icon_widths;
2468
2469   pango_font_metrics_unref (metrics);
2470 }
2471
2472 static void
2473 place_windows (GtkEntry  *entry,
2474                GtkAllocation *widget_alloc)
2475 {
2476   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2477   GtkEntryIconPosition left_icon_pos;
2478   GtkEntryIconPosition right_icon_pos;
2479   GtkAllocation left_icon_alloc;
2480   GtkAllocation right_icon_alloc;
2481   GtkAllocation text_area_alloc;
2482   EntryIconInfo *icon_info = NULL;
2483
2484   get_text_area_size (entry, &text_area_alloc);
2485   get_icon_allocation (entry, TRUE, widget_alloc, &text_area_alloc,
2486                        &left_icon_alloc, &left_icon_pos);
2487   get_icon_allocation (entry, FALSE, widget_alloc, &text_area_alloc,
2488                        &right_icon_alloc, &right_icon_pos);
2489
2490   if (left_icon_alloc.width > 0)
2491     {
2492       text_area_alloc.x = left_icon_alloc.x + left_icon_alloc.width;
2493       text_area_alloc.width -= left_icon_alloc.width;
2494     }
2495
2496   if (right_icon_alloc.width > 0)
2497     text_area_alloc.width -= right_icon_alloc.width;
2498
2499   if ((icon_info = priv->icons[left_icon_pos]) != NULL)
2500     gdk_window_move_resize (icon_info->window,
2501                             left_icon_alloc.x, left_icon_alloc.y,
2502                             left_icon_alloc.width, left_icon_alloc.height);
2503
2504   if ((icon_info = priv->icons[right_icon_pos]) != NULL)
2505     gdk_window_move_resize (icon_info->window,
2506                             right_icon_alloc.x, right_icon_alloc.y,
2507                             right_icon_alloc.width, right_icon_alloc.height);
2508
2509   gdk_window_move_resize (GTK_ENTRY (entry)->text_area,
2510                           text_area_alloc.x, text_area_alloc.y,
2511                           text_area_alloc.width, text_area_alloc.height);
2512
2513   gtk_entry_adjust_scroll (GTK_ENTRY (entry));
2514 }
2515
2516 static void
2517 get_text_area_size (GtkEntry      *entry,
2518                     GtkAllocation *alloc)
2519 {
2520   gtk_entry_get_text_area_size (entry,
2521                                 &alloc->x,
2522                                 &alloc->y,
2523                                 &alloc->width,
2524                                 &alloc->height);
2525 }
2526
2527 static void
2528 gtk_entry_get_text_area_size (GtkEntry *entry,
2529                               gint     *x,
2530                               gint     *y,
2531                               gint     *width,
2532                               gint     *height)
2533 {
2534   gint frame_height;
2535   gint xborder, yborder;
2536   GtkRequisition requisition;
2537   GtkWidget *widget = GTK_WIDGET (entry);
2538   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
2539
2540   gtk_widget_get_child_requisition (widget, &requisition);
2541   _gtk_entry_get_borders (entry, &xborder, &yborder);
2542
2543   if (GTK_WIDGET_REALIZED (widget))
2544     gdk_drawable_get_size (widget->window, NULL, &frame_height);
2545   else
2546     frame_height = requisition.height;
2547
2548   if (GTK_WIDGET_HAS_FOCUS (widget) && !priv->interior_focus)
2549       frame_height -= 2 * priv->focus_width;
2550
2551   if (x)
2552     *x = xborder;
2553
2554   if (y)
2555     *y = frame_height / 2 - (requisition.height - yborder * 2) / 2;
2556
2557   if (width)
2558     *width = GTK_WIDGET (entry)->allocation.width - xborder * 2;
2559
2560   if (height)
2561     *height = requisition.height - yborder * 2;
2562 }
2563
2564 static void
2565 get_widget_window_size (GtkEntry *entry,
2566                         gint     *x,
2567                         gint     *y,
2568                         gint     *width,
2569                         gint     *height)
2570 {
2571   GtkRequisition requisition;
2572   GtkWidget *widget = GTK_WIDGET (entry);
2573       
2574   gtk_widget_get_child_requisition (widget, &requisition);
2575
2576   if (x)
2577     *x = widget->allocation.x;
2578
2579   if (y)
2580     {
2581       if (entry->is_cell_renderer)
2582         *y = widget->allocation.y;
2583       else
2584         *y = widget->allocation.y + (widget->allocation.height - requisition.height) / 2;
2585     }
2586
2587   if (width)
2588     *width = widget->allocation.width;
2589
2590   if (height)
2591     {
2592       if (entry->is_cell_renderer)
2593         *height = widget->allocation.height;
2594       else
2595         *height = requisition.height;
2596     }
2597 }
2598
2599 void
2600 _gtk_entry_effective_inner_border (GtkEntry  *entry,
2601                                    GtkBorder *border)
2602 {
2603   GtkBorder *tmp_border;
2604
2605   tmp_border = g_object_get_qdata (G_OBJECT (entry), quark_inner_border);
2606
2607   if (tmp_border)
2608     {
2609       *border = *tmp_border;
2610       return;
2611     }
2612
2613   gtk_widget_style_get (GTK_WIDGET (entry), "inner-border", &tmp_border, NULL);
2614
2615   if (tmp_border)
2616     {
2617       *border = *tmp_border;
2618       gtk_border_free (tmp_border);
2619       return;
2620     }
2621
2622   *border = default_inner_border;
2623 }
2624
2625 static void
2626 gtk_entry_size_allocate (GtkWidget     *widget,
2627                          GtkAllocation *allocation)
2628 {
2629   GtkEntry *entry = GTK_ENTRY (widget);
2630   
2631   widget->allocation = *allocation;
2632   
2633   if (GTK_WIDGET_REALIZED (widget))
2634     {
2635       /* We call gtk_widget_get_child_requisition, since we want (for
2636        * backwards compatibility reasons) the realization here to
2637        * be affected by the usize of the entry, if set
2638        */
2639       gint x, y, width, height;
2640       GtkEntryCompletion* completion;
2641
2642       get_widget_window_size (entry, &x, &y, &width, &height);
2643       
2644       gdk_window_move_resize (widget->window,
2645                               x, y, width, height);   
2646
2647       gtk_entry_get_text_area_size (entry, &x, &y, &width, &height);
2648       
2649       gdk_window_move_resize (entry->text_area,
2650                               x, y, width, height);
2651
2652       gtk_entry_recompute (entry);
2653
2654       completion = gtk_entry_get_completion (entry);
2655       if (completion && GTK_WIDGET_MAPPED (completion->priv->popup_window))
2656         _gtk_entry_completion_resize_popup (completion);
2657
2658       place_windows (entry, allocation);
2659     }
2660 }
2661
2662 /* Kudos to the gnome-panel guys. */
2663 static void
2664 colorshift_pixbuf (GdkPixbuf *dest,
2665                    GdkPixbuf *src,
2666                    gint       shift)
2667 {
2668   gint i, j;
2669   gint width, height, has_alpha, src_rowstride, dest_rowstride;
2670   guchar *target_pixels;
2671   guchar *original_pixels;
2672   guchar *pix_src;
2673   guchar *pix_dest;
2674   int val;
2675   guchar r, g, b;
2676
2677   has_alpha       = gdk_pixbuf_get_has_alpha (src);
2678   width           = gdk_pixbuf_get_width (src);
2679   height          = gdk_pixbuf_get_height (src);
2680   src_rowstride   = gdk_pixbuf_get_rowstride (src);
2681   dest_rowstride  = gdk_pixbuf_get_rowstride (dest);
2682   original_pixels = gdk_pixbuf_get_pixels (src);
2683   target_pixels   = gdk_pixbuf_get_pixels (dest);
2684
2685   for (i = 0; i < height; i++)
2686     {
2687       pix_dest = target_pixels   + i * dest_rowstride;
2688       pix_src  = original_pixels + i * src_rowstride;
2689
2690       for (j = 0; j < width; j++)
2691         {
2692           r = *(pix_src++);
2693           g = *(pix_src++);
2694           b = *(pix_src++);
2695
2696           val = r + shift;
2697           *(pix_dest++) = CLAMP (val, 0, 255);
2698
2699           val = g + shift;
2700           *(pix_dest++) = CLAMP (val, 0, 255);
2701
2702           val = b + shift;
2703           *(pix_dest++) = CLAMP (val, 0, 255);
2704
2705           if (has_alpha)
2706             *(pix_dest++) = *(pix_src++);
2707         }
2708     }
2709 }
2710
2711 static gboolean
2712 should_prelight (GtkEntry             *entry,
2713                  GtkEntryIconPosition  icon_pos)
2714 {
2715   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2716   EntryIconInfo *icon_info = NULL;
2717   gboolean prelight;
2718
2719   if (!(icon_info = priv->icons[icon_pos]))
2720     return FALSE;
2721
2722   if (icon_info->nonactivatable && icon_info->target_list == NULL)
2723     return FALSE;
2724
2725   if (icon_info->pressed)
2726     return FALSE;
2727
2728   gtk_widget_style_get (GTK_WIDGET (entry),
2729                         "prelight", &prelight,
2730                         NULL);
2731
2732   return prelight;
2733 }
2734
2735 static void
2736 draw_icon (GtkWidget            *widget,
2737            GtkEntryIconPosition  icon_pos)
2738 {
2739   GtkEntry *entry = GTK_ENTRY (widget);
2740   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2741   EntryIconInfo *icon_info = NULL;
2742   GdkPixbuf *pixbuf;
2743   gint x, y, width, height;
2744
2745   if (!(icon_info = priv->icons[icon_pos]))
2746     return;
2747
2748   gtk_entry_ensure_pixbuf (entry, icon_pos);
2749
2750   if (icon_info->pixbuf == NULL)
2751     return;
2752
2753   gdk_drawable_get_size (icon_info->window, &width, &height);
2754
2755   /* size_allocate hasn't been called yet. These are the default values.
2756    */
2757   if (width == 1 || height == 1)
2758     return;
2759
2760   pixbuf = icon_info->pixbuf;
2761   g_object_ref (pixbuf);
2762
2763   if (gdk_pixbuf_get_height (pixbuf) > height)
2764     {
2765       GdkPixbuf *temp_pixbuf;
2766       gint scale;
2767
2768       scale = height - 2 * priv->icon_margin;
2769       temp_pixbuf = gdk_pixbuf_scale_simple (pixbuf, scale, scale,
2770                                              GDK_INTERP_BILINEAR);
2771       g_object_unref (pixbuf);
2772       pixbuf = temp_pixbuf;
2773     }
2774
2775   x = (width  - gdk_pixbuf_get_width (pixbuf)) / 2;
2776   y = (height - gdk_pixbuf_get_height (pixbuf)) / 2;
2777
2778   if (!GTK_WIDGET_IS_SENSITIVE (widget) ||
2779       icon_info->insensitive)
2780     {
2781       GdkPixbuf *temp_pixbuf;
2782
2783       temp_pixbuf = gdk_pixbuf_copy (pixbuf);
2784       gdk_pixbuf_saturate_and_pixelate (pixbuf,
2785                                         temp_pixbuf,
2786                                         0.8f,
2787                                         TRUE);
2788       g_object_unref (pixbuf);
2789       pixbuf = temp_pixbuf;
2790     }
2791   else if (icon_info->prelight)
2792     {
2793       GdkPixbuf *temp_pixbuf;
2794
2795       temp_pixbuf = gdk_pixbuf_copy (pixbuf);
2796       colorshift_pixbuf (temp_pixbuf, pixbuf, 30);
2797       g_object_unref (pixbuf);
2798       pixbuf = temp_pixbuf;
2799     }
2800
2801   gdk_draw_pixbuf (icon_info->window, widget->style->black_gc, pixbuf,
2802                    0, 0, x, y, -1, -1,
2803                    GDK_RGB_DITHER_NORMAL, 0, 0);
2804
2805   g_object_unref (pixbuf);
2806 }
2807
2808
2809 static void
2810 gtk_entry_draw_frame (GtkWidget    *widget,
2811                       GdkRectangle *area)
2812 {
2813   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
2814   gint x = 0, y = 0, width, height;
2815   gboolean state_hint;
2816   GtkStateType state;
2817
2818   gdk_drawable_get_size (widget->window, &width, &height);
2819
2820   /* Fix a problem with some themes which assume that entry->text_area's
2821    * width equals widget->window's width */
2822   if (GTK_IS_SPIN_BUTTON (widget))
2823     {
2824       gint xborder, yborder;
2825
2826       gtk_entry_get_text_area_size (GTK_ENTRY (widget), &x, NULL, &width, NULL);
2827       _gtk_entry_get_borders (GTK_ENTRY (widget), &xborder, &yborder);
2828
2829       x -= xborder;
2830       width += xborder * 2;
2831     }
2832
2833   if (GTK_WIDGET_HAS_FOCUS (widget) && !priv->interior_focus)
2834     {
2835       x += priv->focus_width;
2836       y += priv->focus_width;
2837       width -= 2 * priv->focus_width;
2838       height -= 2 * priv->focus_width;
2839     }
2840
2841   gtk_widget_style_get (widget, "state-hint", &state_hint, NULL);
2842   if (state_hint)
2843       state = GTK_WIDGET_HAS_FOCUS (widget) ?
2844         GTK_STATE_ACTIVE : GTK_WIDGET_STATE (widget);
2845   else
2846       state = GTK_STATE_NORMAL;
2847
2848   gtk_paint_shadow (widget->style, widget->window,
2849                     state, priv->shadow_type,
2850                     area, widget, "entry", x, y, width, height);
2851
2852   if (GTK_WIDGET_HAS_FOCUS (widget) && !priv->interior_focus)
2853     {
2854       x -= priv->focus_width;
2855       y -= priv->focus_width;
2856       width += 2 * priv->focus_width;
2857       height += 2 * priv->focus_width;
2858       
2859       gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget), 
2860                        area, widget, "entry",
2861                        0, 0, width, height);
2862     }
2863 }
2864
2865 static void
2866 gtk_entry_draw_progress (GtkWidget      *widget,
2867                          GdkEventExpose *event)
2868 {
2869   GtkEntryPrivate *private = GTK_ENTRY_GET_PRIVATE (widget);
2870   GtkEntry *entry = GTK_ENTRY (widget);
2871
2872   if (private->progress_pulse_mode)
2873     {
2874       gdouble value = private->progress_pulse_current;
2875       gint    area_width, area_height;
2876
2877       gdk_drawable_get_size (entry->text_area, &area_width, &area_height);
2878
2879       gtk_paint_box (widget->style, entry->text_area,
2880                      GTK_STATE_SELECTED, GTK_SHADOW_OUT,
2881                      &event->area, widget, "entry-progress",
2882                      value * area_width, 0,
2883                      private->progress_pulse_fraction * area_width, area_height);
2884     }
2885   else if (private->progress_fraction > 0)
2886     {
2887       gdouble value = private->progress_fraction;
2888       gint    area_width, area_height;
2889
2890       gdk_drawable_get_size (entry->text_area, &area_width, &area_height);
2891
2892       if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL)
2893         {
2894           gtk_paint_box (widget->style, entry->text_area,
2895                          GTK_STATE_SELECTED, GTK_SHADOW_OUT,
2896                          &event->area, widget, "entry-progress",
2897                          area_width - value * area_width, 0,
2898                          value * area_width, area_height);
2899         }
2900       else
2901         {
2902           gtk_paint_box (widget->style, entry->text_area,
2903                          GTK_STATE_SELECTED, GTK_SHADOW_OUT,
2904                          &event->area, widget, "entry-progress",
2905                          0, 0,
2906                          value * area_width, area_height);
2907         }
2908     }
2909 }
2910
2911 static gint
2912 gtk_entry_expose (GtkWidget      *widget,
2913                   GdkEventExpose *event)
2914 {
2915   GtkEntry *entry = GTK_ENTRY (widget);
2916   gboolean state_hint;
2917   GtkStateType state;
2918   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2919
2920   if (widget->window == event->window)
2921     {
2922       gtk_entry_draw_frame (widget, &event->area);
2923     }
2924   else if (entry->text_area == event->window)
2925     {
2926       gint area_width, area_height;
2927       gdk_drawable_get_size (entry->text_area, &area_width, &area_height);
2928
2929       gtk_widget_style_get (widget, "state-hint", &state_hint, NULL);
2930       if (state_hint)
2931         state = GTK_WIDGET_HAS_FOCUS (widget) ?
2932           GTK_STATE_ACTIVE : GTK_WIDGET_STATE (widget);
2933       else
2934         state = GTK_WIDGET_STATE(widget);
2935
2936       gtk_paint_flat_box (widget->style, entry->text_area, 
2937                           state, GTK_SHADOW_NONE,
2938                           &event->area, widget, "entry_bg",
2939                           0, 0, area_width, area_height);
2940
2941       gtk_entry_draw_progress (widget, event);
2942
2943       if (entry->dnd_position != -1)
2944         gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_DND);
2945       
2946       gtk_entry_draw_text (GTK_ENTRY (widget));
2947
2948       if ((entry->visible || entry->invisible_char != 0) &&
2949           GTK_WIDGET_HAS_FOCUS (widget) &&
2950           entry->selection_bound == entry->current_pos && entry->cursor_visible)
2951         gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_STANDARD);
2952     }
2953   else
2954     {
2955       gboolean found = FALSE;
2956       int i;
2957
2958       for (i = 0; i < MAX_ICONS && !found; i++)
2959         {
2960           EntryIconInfo *icon_info = NULL;
2961
2962           if ((icon_info = priv->icons[i]) != NULL)
2963             {
2964               if (event->window == icon_info->window)
2965                 {
2966                   gint width;
2967                   GtkAllocation text_area_alloc;
2968
2969                   get_text_area_size (entry, &text_area_alloc);
2970                   gdk_drawable_get_size (icon_info->window, &width, NULL);
2971
2972                   gtk_paint_flat_box (widget->style, icon_info->window,
2973                                       GTK_WIDGET_STATE (widget), GTK_SHADOW_NONE,
2974                                       NULL, widget, "entry_bg",
2975                                       0, 0, width, text_area_alloc.height);
2976
2977                   draw_icon (widget, i);
2978
2979                   found = TRUE;
2980                 }
2981             }
2982         }
2983     }
2984
2985   return FALSE;
2986 }
2987
2988 static gint
2989 gtk_entry_enter_notify (GtkWidget *widget,
2990                         GdkEventCrossing *event)
2991 {
2992   GtkEntry *entry = GTK_ENTRY (widget);
2993   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
2994   EntryIconInfo *icon_info = NULL;
2995   gint i;
2996
2997   for (i = 0; i < MAX_ICONS; i++)
2998     {
2999       if ((icon_info = priv->icons[i]) != NULL)
3000         {
3001           if (event->window == icon_info->window)
3002             {
3003               if (should_prelight (entry, i))
3004                 {
3005                   icon_info->prelight = TRUE;
3006                   gtk_widget_queue_draw (widget);
3007                   break;
3008                 }
3009             }
3010         }
3011     }
3012
3013     return FALSE;
3014 }
3015
3016 static gint
3017 gtk_entry_leave_notify (GtkWidget        *widget,
3018                         GdkEventCrossing *event)
3019 {
3020   GtkEntry *entry = GTK_ENTRY (widget);
3021   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
3022   EntryIconInfo *icon_info = NULL;
3023   gint i;
3024
3025   for (i = 0; i < MAX_ICONS; i++)
3026     {
3027       if ((icon_info = priv->icons[i]) != NULL)
3028         {
3029           if (event->window == icon_info->window)
3030             {
3031               if (should_prelight (entry, i))
3032                 {
3033                   icon_info->prelight = FALSE;
3034                   gtk_widget_queue_draw (widget);
3035                   break;
3036                 }
3037             }
3038         }
3039     }
3040
3041   return FALSE;
3042 }
3043
3044 static void
3045 gtk_entry_get_pixel_ranges (GtkEntry  *entry,
3046                             gint     **ranges,
3047                             gint      *n_ranges)
3048 {
3049   gint start_char, end_char;
3050
3051   if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_char, &end_char))
3052     {
3053       PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
3054       PangoLayoutLine *line = pango_layout_get_lines_readonly (layout)->data;
3055       const char *text = pango_layout_get_text (layout);
3056       gint start_index = g_utf8_offset_to_pointer (text, start_char) - text;
3057       gint end_index = g_utf8_offset_to_pointer (text, end_char) - text;
3058       gint real_n_ranges, i;
3059
3060       pango_layout_line_get_x_ranges (line, start_index, end_index, ranges, &real_n_ranges);
3061
3062       if (ranges)
3063         {
3064           gint *r = *ranges;
3065           
3066           for (i = 0; i < real_n_ranges; ++i)
3067             {
3068               r[2 * i + 1] = (r[2 * i + 1] - r[2 * i]) / PANGO_SCALE;
3069               r[2 * i] = r[2 * i] / PANGO_SCALE;
3070             }
3071         }
3072       
3073       if (n_ranges)
3074         *n_ranges = real_n_ranges;
3075     }
3076   else
3077     {
3078       if (n_ranges)
3079         *n_ranges = 0;
3080       if (ranges)
3081         *ranges = NULL;
3082     }
3083 }
3084
3085 static gboolean
3086 in_selection (GtkEntry *entry,
3087               gint      x)
3088 {
3089   gint *ranges;
3090   gint n_ranges, i;
3091   gint retval = FALSE;
3092
3093   gtk_entry_get_pixel_ranges (entry, &ranges, &n_ranges);
3094
3095   for (i = 0; i < n_ranges; ++i)
3096     {
3097       if (x >= ranges[2 * i] && x < ranges[2 * i] + ranges[2 * i + 1])
3098         {
3099           retval = TRUE;
3100           break;
3101         }
3102     }
3103
3104   g_free (ranges);
3105   return retval;
3106 }
3107               
3108 static gint
3109 gtk_entry_button_press (GtkWidget      *widget,
3110                         GdkEventButton *event)
3111 {
3112   GtkEntry *entry = GTK_ENTRY (widget);
3113   GtkEditable *editable = GTK_EDITABLE (widget);
3114   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
3115   EntryIconInfo *icon_info = NULL;
3116   gint tmp_pos;
3117   gint sel_start, sel_end;
3118   gint i;
3119
3120   for (i = 0; i < MAX_ICONS; i++)
3121     {
3122       icon_info = priv->icons[i];
3123
3124       if (!icon_info || icon_info->insensitive)
3125         continue;
3126
3127       if (event->window == icon_info->window)
3128         {
3129           if (should_prelight (entry, i))
3130             {
3131               icon_info->prelight = FALSE;
3132               gtk_widget_queue_draw (widget);
3133             }
3134
3135           priv->start_x = event->x;
3136           priv->start_y = event->y;
3137           icon_info->pressed = TRUE;
3138
3139           if (!icon_info->nonactivatable)
3140             g_signal_emit (entry, signals[ICON_PRESSED], 0, i, event);
3141
3142           return TRUE;
3143         }
3144     }
3145
3146   if (event->window != entry->text_area ||
3147       (entry->button && event->button != entry->button))
3148     return FALSE;
3149
3150   gtk_entry_reset_blink_time (entry);
3151
3152   entry->button = event->button;
3153   
3154   if (!GTK_WIDGET_HAS_FOCUS (widget))
3155     {
3156       entry->in_click = TRUE;
3157       gtk_widget_grab_focus (widget);
3158       entry->in_click = FALSE;
3159     }
3160   
3161   tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
3162     
3163   if (event->button == 1)
3164     {
3165       gboolean have_selection = gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end);
3166       
3167       entry->select_words = FALSE;
3168       entry->select_lines = FALSE;
3169
3170       if (event->state & GDK_SHIFT_MASK)
3171         {
3172           _gtk_entry_reset_im_context (entry);
3173           
3174           if (!have_selection) /* select from the current position to the clicked position */
3175             sel_start = sel_end = entry->current_pos;
3176           
3177           if (tmp_pos > sel_start && tmp_pos < sel_end)
3178             {
3179               /* Truncate current selection, but keep it as big as possible */
3180               if (tmp_pos - sel_start > sel_end - tmp_pos)
3181                 gtk_entry_set_positions (entry, sel_start, tmp_pos);
3182               else
3183                 gtk_entry_set_positions (entry, tmp_pos, sel_end);
3184             }
3185           else
3186             {
3187               gboolean extend_to_left;
3188               gint start, end;
3189
3190               /* Figure out what click selects and extend current selection */
3191               switch (event->type)
3192                 {
3193                 case GDK_BUTTON_PRESS:
3194                   gtk_entry_set_positions (entry, tmp_pos, tmp_pos);
3195                   break;
3196                   
3197                 case GDK_2BUTTON_PRESS:
3198                   entry->select_words = TRUE;
3199                   gtk_entry_select_word (entry);
3200                   break;
3201                   
3202                 case GDK_3BUTTON_PRESS:
3203                   entry->select_lines = TRUE;
3204                   gtk_entry_select_line (entry);
3205                   break;
3206
3207                 default:
3208                   break;
3209                 }
3210
3211               start = MIN (entry->current_pos, entry->selection_bound);
3212               start = MIN (sel_start, start);
3213               
3214               end = MAX (entry->current_pos, entry->selection_bound);
3215               end = MAX (sel_end, end);
3216
3217               if (tmp_pos == sel_start || tmp_pos == sel_end)
3218                 extend_to_left = (tmp_pos == start);
3219               else
3220                 extend_to_left = (end == sel_end);
3221               
3222               if (extend_to_left)
3223                 gtk_entry_set_positions (entry, start, end);
3224               else
3225                 gtk_entry_set_positions (entry, end, start);
3226             }
3227         }
3228       else /* no shift key */
3229         switch (event->type)
3230         {
3231         case GDK_BUTTON_PRESS:
3232           if (in_selection (entry, event->x + entry->scroll_offset))
3233             {
3234               /* Click inside the selection - we'll either start a drag, or
3235                * clear the selection
3236                */
3237               entry->in_drag = TRUE;
3238               entry->drag_start_x = event->x + entry->scroll_offset;
3239               entry->drag_start_y = event->y;
3240             }
3241           else
3242             gtk_editable_set_position (editable, tmp_pos);
3243           break;
3244  
3245         case GDK_2BUTTON_PRESS:
3246           /* We ALWAYS receive a GDK_BUTTON_PRESS immediately before 
3247            * receiving a GDK_2BUTTON_PRESS so we need to reset
3248            * entry->in_drag which may have been set above
3249            */
3250           entry->in_drag = FALSE;
3251           entry->select_words = TRUE;
3252           gtk_entry_select_word (entry);
3253           break;
3254         
3255         case GDK_3BUTTON_PRESS:
3256           /* We ALWAYS receive a GDK_BUTTON_PRESS immediately before
3257            * receiving a GDK_3BUTTON_PRESS so we need to reset
3258            * entry->in_drag which may have been set above
3259            */
3260           entry->in_drag = FALSE;
3261           entry->select_lines = TRUE;
3262           gtk_entry_select_line (entry);
3263           break;
3264
3265         default:
3266           break;
3267         }
3268
3269       return TRUE;
3270     }
3271   else if (event->button == 2 && event->type == GDK_BUTTON_PRESS)
3272     {
3273       if (entry->editable)
3274         {
3275           priv->insert_pos = tmp_pos;
3276           gtk_entry_paste (entry, GDK_SELECTION_PRIMARY);
3277           return TRUE;
3278         }
3279       else
3280         {
3281           gtk_widget_error_bell (widget);
3282         }
3283     }
3284   else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
3285     {
3286       gtk_entry_do_popup (entry, event);
3287       entry->button = 0;        /* Don't wait for release, since the menu will gtk_grab_add */
3288
3289       return TRUE;
3290     }
3291
3292   return FALSE;
3293 }
3294
3295 static gint
3296 gtk_entry_button_release (GtkWidget      *widget,
3297                           GdkEventButton *event)
3298 {
3299   GtkEntry *entry = GTK_ENTRY (widget);
3300   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
3301   EntryIconInfo *icon_info = NULL;
3302   gint i;
3303
3304   for (i = 0; i < MAX_ICONS; i++)
3305     {
3306       icon_info = priv->icons[i];
3307
3308       if (!icon_info || icon_info->insensitive)
3309         continue;
3310
3311       if (event->window == icon_info->window)
3312         {
3313           gint width, height;
3314
3315           gdk_drawable_get_size (icon_info->window, &width, &height);
3316
3317           icon_info->pressed = FALSE;
3318
3319           if (should_prelight (entry, i) &&
3320               event->x >= 0 && event->y >= 0 &&
3321               event->x < width && event->y < height)
3322             {
3323               icon_info->prelight = TRUE;
3324               gtk_widget_queue_draw (widget);
3325             }
3326
3327           if (!icon_info->nonactivatable)
3328             g_signal_emit (entry, signals[ICON_RELEASED], 0, i, event);
3329
3330           return TRUE;
3331         }
3332     }
3333
3334   if (event->window != entry->text_area || entry->button != event->button)
3335     return FALSE;
3336
3337   if (entry->in_drag)
3338     {
3339       gint tmp_pos = gtk_entry_find_position (entry, entry->drag_start_x);
3340
3341       gtk_editable_set_position (GTK_EDITABLE (entry), tmp_pos);
3342
3343       entry->in_drag = 0;
3344     }
3345   
3346   entry->button = 0;
3347   
3348   gtk_entry_update_primary_selection (entry);
3349               
3350   return TRUE;
3351 }
3352
3353 static gchar *
3354 _gtk_entry_get_selected_text (GtkEntry *entry)
3355 {
3356   GtkEditable *editable = GTK_EDITABLE (entry);
3357   gint         start_text, end_text;
3358   gchar       *text = NULL;
3359
3360   if (gtk_editable_get_selection_bounds (editable, &start_text, &end_text))
3361     text = gtk_editable_get_chars (editable, start_text, end_text);
3362
3363   return text;
3364 }
3365
3366 static gint
3367 gtk_entry_motion_notify (GtkWidget      *widget,
3368                          GdkEventMotion *event)
3369 {
3370   GtkEntry *entry = GTK_ENTRY (widget);
3371   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
3372   EntryIconInfo *icon_info = NULL;
3373   GdkDragContext *context;
3374   gint tmp_pos;
3375   gint i;
3376
3377   for (i = 0; i < MAX_ICONS; i++)
3378     {
3379       icon_info = priv->icons[i];
3380
3381       if (!icon_info || icon_info->insensitive)
3382         continue;
3383
3384       if (event->window == icon_info->window)
3385         {
3386           if (icon_info->pressed &&
3387               icon_info->target_list != NULL &&
3388               gtk_drag_check_threshold (widget,
3389                                         priv->start_x,
3390                                         priv->start_y,
3391                                         event->x,
3392                                         event->y))
3393             {
3394               icon_info->in_drag = TRUE;
3395               icon_info->pressed = FALSE;
3396               context = gtk_drag_begin (widget,
3397                                         icon_info->target_list,
3398                                         icon_info->actions,
3399                                         1,
3400                                         (GdkEvent*)event);
3401             }
3402
3403           return TRUE;
3404         }
3405     }
3406
3407   if (entry->mouse_cursor_obscured)
3408     {
3409       GdkCursor *cursor;
3410       
3411       cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM);
3412       gdk_window_set_cursor (entry->text_area, cursor);
3413       gdk_cursor_unref (cursor);
3414       entry->mouse_cursor_obscured = FALSE;
3415     }
3416
3417   if (event->window != entry->text_area || entry->button != 1)
3418     return FALSE;
3419
3420   if (entry->select_lines)
3421     return TRUE;
3422
3423   gdk_event_request_motions (event);
3424
3425   if (entry->in_drag)
3426     {
3427       if (entry->visible &&
3428           gtk_drag_check_threshold (widget,
3429                                     entry->drag_start_x, entry->drag_start_y,
3430                                     event->x + entry->scroll_offset, event->y))
3431         {
3432           GdkDragContext *context;
3433           GtkTargetList  *target_list = gtk_target_list_new (NULL, 0);
3434           guint actions = entry->editable ? GDK_ACTION_COPY | GDK_ACTION_MOVE : GDK_ACTION_COPY;
3435           gchar *text = NULL;
3436           GdkPixmap *pixmap = NULL;
3437
3438           gtk_target_list_add_text_targets (target_list, 0);
3439
3440           text = _gtk_entry_get_selected_text (entry);
3441           pixmap = _gtk_text_util_create_drag_icon (widget, text, -1);
3442
3443           context = gtk_drag_begin (widget, target_list, actions,
3444                                     entry->button, (GdkEvent *)event);
3445           
3446           if (pixmap)
3447             gtk_drag_set_icon_pixmap (context,
3448                                       gdk_drawable_get_colormap (pixmap),
3449                                       pixmap,
3450                                       NULL,
3451                                       -2, -2);
3452           else
3453             gtk_drag_set_icon_default (context);
3454           
3455           if (pixmap)
3456             g_object_unref (pixmap);
3457           g_free (text);
3458
3459           entry->in_drag = FALSE;
3460           entry->button = 0;
3461           
3462           gtk_target_list_unref (target_list);
3463         }
3464     }
3465   else
3466     {
3467       gint height;
3468       gdk_drawable_get_size (entry->text_area, NULL, &height);
3469
3470       if (event->y < 0)
3471         tmp_pos = 0;
3472       else if (event->y >= height)
3473         tmp_pos = entry->text_length;
3474       else
3475         tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
3476       
3477       if (entry->select_words) 
3478         {
3479           gint min, max;
3480           gint old_min, old_max;
3481           gint pos, bound;
3482           
3483           min = gtk_entry_move_backward_word (entry, tmp_pos, TRUE);
3484           max = gtk_entry_move_forward_word (entry, tmp_pos, TRUE);
3485           
3486           pos = entry->current_pos;
3487           bound = entry->selection_bound;
3488
3489           old_min = MIN(entry->current_pos, entry->selection_bound);
3490           old_max = MAX(entry->current_pos, entry->selection_bound);
3491           
3492           if (min < old_min)
3493             {
3494               pos = min;
3495               bound = old_max;
3496             }
3497           else if (old_max < max) 
3498             {
3499               pos = max;
3500               bound = old_min;
3501             }
3502           else if (pos == old_min) 
3503             {
3504               if (entry->current_pos != min)
3505                 pos = max;
3506             }
3507           else 
3508             {
3509               if (entry->current_pos != max)
3510                 pos = min;
3511             }
3512         
3513           gtk_entry_set_positions (entry, pos, bound);
3514         }
3515       else
3516       gtk_entry_set_positions (entry, tmp_pos, -1);
3517     }
3518       
3519   return TRUE;
3520 }
3521
3522 static void
3523 set_invisible_cursor (GdkWindow *window)
3524 {
3525   GdkBitmap *empty_bitmap;
3526   GdkCursor *cursor;
3527   GdkColor useless;
3528   char invisible_cursor_bits[] = { 0x0 };       
3529         
3530   useless.red = useless.green = useless.blue = 0;
3531   useless.pixel = 0;
3532   
3533   empty_bitmap = gdk_bitmap_create_from_data (window,
3534                                               invisible_cursor_bits,
3535                                               1, 1);
3536   
3537   cursor = gdk_cursor_new_from_pixmap (empty_bitmap,
3538                                        empty_bitmap,
3539                                        &useless,
3540                                        &useless, 0, 0);
3541   
3542   gdk_window_set_cursor (window, cursor);
3543   
3544   gdk_cursor_unref (cursor);
3545   
3546   g_object_unref (empty_bitmap);
3547 }
3548
3549 static void
3550 gtk_entry_obscure_mouse_cursor (GtkEntry *entry)
3551 {
3552   if (entry->mouse_cursor_obscured)
3553     return;
3554
3555   set_invisible_cursor (entry->text_area);
3556   
3557   entry->mouse_cursor_obscured = TRUE;  
3558 }
3559
3560 static gint
3561 gtk_entry_key_press (GtkWidget   *widget,
3562                      GdkEventKey *event)
3563 {
3564   GtkEntry *entry = GTK_ENTRY (widget);
3565
3566   gtk_entry_reset_blink_time (entry);
3567   gtk_entry_pend_cursor_blink (entry);
3568
3569   if (entry->editable)
3570     {
3571       if (gtk_im_context_filter_keypress (entry->im_context, event))
3572         {
3573           gtk_entry_obscure_mouse_cursor (entry);
3574           entry->need_im_reset = TRUE;
3575           return TRUE;
3576         }
3577     }
3578
3579   if (event->keyval == GDK_Return || 
3580       event->keyval == GDK_KP_Enter || 
3581       event->keyval == GDK_ISO_Enter || 
3582       event->keyval == GDK_Escape)
3583     {
3584       GtkEntryCompletion *completion = gtk_entry_get_completion (entry);
3585       
3586       if (completion && completion->priv->completion_timeout)
3587         {
3588           g_source_remove (completion->priv->completion_timeout);
3589           completion->priv->completion_timeout = 0;
3590         }
3591
3592       _gtk_entry_reset_im_context (entry);
3593     }
3594
3595   if (GTK_WIDGET_CLASS (gtk_entry_parent_class)->key_press_event (widget, event))
3596     /* Activate key bindings
3597      */
3598     return TRUE;
3599
3600   if (!entry->editable && event->length)
3601     gtk_widget_error_bell (widget);
3602
3603   return FALSE;
3604 }
3605
3606 static gint
3607 gtk_entry_key_release (GtkWidget   *widget,
3608                        GdkEventKey *event)
3609 {
3610   GtkEntry *entry = GTK_ENTRY (widget);
3611
3612   if (entry->editable)
3613     {
3614       if (gtk_im_context_filter_keypress (entry->im_context, event))
3615         {
3616           entry->need_im_reset = TRUE;
3617           return TRUE;
3618         }
3619     }
3620
3621   return GTK_WIDGET_CLASS (gtk_entry_parent_class)->key_release_event (widget, event);
3622 }
3623
3624 static gint
3625 gtk_entry_focus_in (GtkWidget     *widget,
3626                     GdkEventFocus *event)
3627 {
3628   GtkEntry *entry = GTK_ENTRY (widget);
3629   GdkKeymap *keymap;
3630
3631   gtk_widget_queue_draw (widget);
3632
3633   keymap = gdk_keymap_get_for_display (gtk_widget_get_display (widget));
3634
3635   if (entry->editable)
3636     {
3637       entry->need_im_reset = TRUE;
3638       gtk_im_context_focus_in (entry->im_context);
3639       keymap_state_changed (keymap, entry);
3640       g_signal_connect (keymap, "state-changed", 
3641                         G_CALLBACK (keymap_state_changed), entry);
3642     }
3643
3644   g_signal_connect (keymap, "direction-changed",
3645                     G_CALLBACK (keymap_direction_changed), entry);
3646
3647   gtk_entry_reset_blink_time (entry);
3648   gtk_entry_check_cursor_blink (entry);
3649
3650   return FALSE;
3651 }
3652
3653 static gint
3654 gtk_entry_focus_out (GtkWidget     *widget,
3655                      GdkEventFocus *event)
3656 {
3657   GtkEntry *entry = GTK_ENTRY (widget);
3658   GtkEntryCompletion *completion;
3659   GdkKeymap *keymap;
3660   
3661   gtk_widget_queue_draw (widget);
3662
3663   keymap = gdk_keymap_get_for_display (gtk_widget_get_display (widget));
3664
3665   if (entry->editable)
3666     {
3667       entry->need_im_reset = TRUE;
3668       gtk_im_context_focus_out (entry->im_context);
3669       remove_capslock_feedback (entry);
3670     }
3671
3672   gtk_entry_check_cursor_blink (entry);
3673   
3674   g_signal_handlers_disconnect_by_func (keymap, keymap_state_changed, entry);
3675   g_signal_handlers_disconnect_by_func (keymap, keymap_direction_changed, entry);
3676
3677   completion = gtk_entry_get_completion (entry);
3678   if (completion)
3679     _gtk_entry_completion_popdown (completion);
3680   
3681   return FALSE;
3682 }
3683
3684 static void
3685 gtk_entry_grab_focus (GtkWidget        *widget)
3686 {
3687   GtkEntry *entry = GTK_ENTRY (widget);
3688   gboolean select_on_focus;
3689   
3690   GTK_WIDGET_CLASS (gtk_entry_parent_class)->grab_focus (widget);
3691
3692   if (entry->editable && !entry->in_click)
3693     {
3694       g_object_get (gtk_widget_get_settings (widget),
3695                     "gtk-entry-select-on-focus",
3696                     &select_on_focus,
3697                     NULL);
3698   
3699       if (select_on_focus)
3700         gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
3701     }
3702 }
3703
3704 static void 
3705 gtk_entry_direction_changed (GtkWidget        *widget,
3706                              GtkTextDirection  previous_dir)
3707 {
3708   GtkEntry *entry = GTK_ENTRY (widget);
3709
3710   gtk_entry_recompute (entry);
3711       
3712   GTK_WIDGET_CLASS (gtk_entry_parent_class)->direction_changed (widget, previous_dir);
3713 }
3714
3715 static void
3716 gtk_entry_state_changed (GtkWidget      *widget,
3717                          GtkStateType    previous_state)
3718 {
3719   GtkEntry *entry = GTK_ENTRY (widget);
3720   GdkCursor *cursor;
3721   
3722   if (GTK_WIDGET_REALIZED (widget))
3723     {
3724       gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
3725       gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
3726
3727       if (GTK_WIDGET_IS_SENSITIVE (widget))
3728         cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM);
3729       else 
3730         cursor = NULL;
3731       
3732       gdk_window_set_cursor (entry->text_area, cursor);
3733
3734       if (cursor)
3735         gdk_cursor_unref (cursor);
3736
3737       entry->mouse_cursor_obscured = FALSE;
3738
3739       update_cursors (widget);
3740     }
3741
3742   if (!GTK_WIDGET_IS_SENSITIVE (widget))
3743     {
3744       /* Clear any selection */
3745       gtk_editable_select_region (GTK_EDITABLE (entry), entry->current_pos, entry->current_pos);      
3746     }
3747   
3748   gtk_widget_queue_draw (widget);
3749 }
3750
3751 static void
3752 gtk_entry_screen_changed (GtkWidget *widget,
3753                           GdkScreen *old_screen)
3754 {
3755   gtk_entry_recompute (GTK_ENTRY (widget));
3756 }
3757
3758 /* GtkEditable method implementations
3759  */
3760 static void
3761 gtk_entry_insert_text (GtkEditable *editable,
3762                        const gchar *new_text,
3763                        gint         new_text_length,
3764                        gint        *position)
3765 {
3766   GtkEntry *entry = GTK_ENTRY (editable);
3767   gchar buf[64];
3768   gchar *text;
3769
3770   if (*position < 0 || *position > entry->text_length)
3771     *position = entry->text_length;
3772   
3773   g_object_ref (editable);
3774   
3775   if (new_text_length <= 63)
3776     text = buf;
3777   else
3778     text = g_new (gchar, new_text_length + 1);
3779
3780   text[new_text_length] = '\0';
3781   strncpy (text, new_text, new_text_length);
3782
3783   g_signal_emit_by_name (editable, "insert-text", text, new_text_length, position);
3784
3785   if (!entry->visible)
3786     trash_area (text, new_text_length);
3787
3788   if (new_text_length > 63)
3789     g_free (text);
3790
3791   g_object_unref (editable);
3792 }
3793
3794 static void
3795 gtk_entry_delete_text (GtkEditable *editable,
3796                        gint         start_pos,
3797                        gint         end_pos)
3798 {
3799   GtkEntry *entry = GTK_ENTRY (editable);
3800
3801   if (end_pos < 0 || end_pos > entry->text_length)
3802     end_pos = entry->text_length;
3803   if (start_pos < 0)
3804     start_pos = 0;
3805   if (start_pos > end_pos)
3806     start_pos = end_pos;
3807   
3808   g_object_ref (editable);
3809
3810   g_signal_emit_by_name (editable, "delete-text", start_pos, end_pos);
3811
3812   g_object_unref (editable);
3813 }
3814
3815 static gchar *    
3816 gtk_entry_get_chars      (GtkEditable   *editable,
3817                           gint           start_pos,
3818                           gint           end_pos)
3819 {
3820   GtkEntry *entry = GTK_ENTRY (editable);
3821   gint start_index, end_index;
3822   
3823   if (end_pos < 0)
3824     end_pos = entry->text_length;
3825
3826   start_pos = MIN (entry->text_length, start_pos);
3827   end_pos = MIN (entry->text_length, end_pos);
3828
3829   start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text;
3830   end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text;
3831
3832   return g_strndup (entry->text + start_index, end_index - start_index);
3833 }
3834
3835 static void
3836 gtk_entry_real_set_position (GtkEditable *editable,
3837                              gint         position)
3838 {
3839   GtkEntry *entry = GTK_ENTRY (editable);
3840
3841   if (position < 0 || position > entry->text_length)
3842     position = entry->text_length;
3843
3844   if (position != entry->current_pos ||
3845       position != entry->selection_bound)
3846     {
3847       _gtk_entry_reset_im_context (entry);
3848       gtk_entry_set_positions (entry, position, position);
3849     }
3850 }
3851
3852 static gint
3853 gtk_entry_get_position (GtkEditable *editable)
3854 {
3855   return GTK_ENTRY (editable)->current_pos;
3856 }
3857
3858 static void
3859 gtk_entry_set_selection_bounds (GtkEditable *editable,
3860                                 gint         start,
3861                                 gint         end)
3862 {
3863   GtkEntry *entry = GTK_ENTRY (editable);
3864
3865   if (start < 0)
3866     start = entry->text_length;
3867   if (end < 0)
3868     end = entry->text_length;
3869   
3870   _gtk_entry_reset_im_context (entry);
3871
3872   gtk_entry_set_positions (entry,
3873                            MIN (end, entry->text_length),
3874                            MIN (start, entry->text_length));
3875
3876   gtk_entry_update_primary_selection (entry);
3877 }
3878
3879 static gboolean
3880 gtk_entry_get_selection_bounds (GtkEditable *editable,
3881                                 gint        *start,
3882                                 gint        *end)
3883 {
3884   GtkEntry *entry = GTK_ENTRY (editable);
3885
3886   *start = entry->selection_bound;
3887   *end = entry->current_pos;
3888
3889   return (entry->selection_bound != entry->current_pos);
3890 }
3891
3892 static void
3893 icon_theme_changed (GtkEntry *entry)
3894 {
3895   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
3896   EntryIconInfo *icon_info = NULL;
3897   gint i;
3898
3899   for (i = 0; i < MAX_ICONS; i++)
3900     {
3901       if ((icon_info = priv->icons[i]) != NULL)
3902         {
3903           if (icon_info->storage_type == GTK_IMAGE_ICON_NAME)
3904             gtk_entry_set_icon_from_icon_name (entry, i, icon_info->icon_name);
3905           else if (icon_info->storage_type == GTK_IMAGE_STOCK)
3906             gtk_entry_set_icon_from_stock (entry, i, icon_info->stock_id);
3907           else if (icon_info->storage_type == GTK_IMAGE_GICON)
3908             gtk_entry_set_icon_from_gicon (entry, i, icon_info->gicon);
3909         }
3910     }
3911
3912   gtk_widget_queue_draw (GTK_WIDGET (entry));
3913 }
3914
3915 static void
3916 icon_margin_changed (GtkEntry *entry)
3917 {
3918   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
3919   GtkBorder border;
3920
3921   _gtk_entry_effective_inner_border (GTK_ENTRY (entry), &border);
3922
3923   priv->icon_margin = border.left;
3924 }
3925
3926 static void 
3927 gtk_entry_style_set     (GtkWidget      *widget,
3928                          GtkStyle       *previous_style)
3929 {
3930   GtkEntry *entry = GTK_ENTRY (widget);
3931   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
3932   gint focus_width;
3933   gboolean interior_focus;
3934
3935   gtk_widget_style_get (widget,
3936                         "focus-line-width", &focus_width,
3937                         "interior-focus", &interior_focus,
3938                         NULL);
3939
3940   priv->focus_width = focus_width;
3941   priv->interior_focus = interior_focus;
3942
3943   if (!priv->invisible_char_set)
3944     entry->invisible_char = find_invisible_char (GTK_WIDGET (entry));
3945
3946   gtk_entry_recompute (entry);
3947
3948   if (previous_style && GTK_WIDGET_REALIZED (widget))
3949     {
3950       gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
3951       gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
3952     }
3953
3954   icon_theme_changed (entry);
3955   icon_margin_changed (entry);
3956 }
3957
3958 /* GtkCellEditable method implementations
3959  */
3960 static void
3961 gtk_cell_editable_entry_activated (GtkEntry *entry, gpointer data)
3962 {
3963   gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry));
3964   gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry));
3965 }
3966
3967 static gboolean
3968 gtk_cell_editable_key_press_event (GtkEntry    *entry,
3969                                    GdkEventKey *key_event,
3970                                    gpointer     data)
3971 {
3972   if (key_event->keyval == GDK_Escape)
3973     {
3974       entry->editing_canceled = TRUE;
3975       gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry));
3976       gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry));
3977
3978       return TRUE;
3979     }
3980
3981   /* override focus */
3982   if (key_event->keyval == GDK_Up || key_event->keyval == GDK_Down)
3983     {
3984       gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry));
3985       gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry));
3986
3987       return TRUE;
3988     }
3989
3990   return FALSE;
3991 }
3992
3993 static void
3994 gtk_entry_start_editing (GtkCellEditable *cell_editable,
3995                          GdkEvent        *event)
3996 {
3997   GTK_ENTRY (cell_editable)->is_cell_renderer = TRUE;
3998
3999   g_signal_connect (cell_editable, "activate",
4000                     G_CALLBACK (gtk_cell_editable_entry_activated), NULL);
4001   g_signal_connect (cell_editable, "key-press-event",
4002                     G_CALLBACK (gtk_cell_editable_key_press_event), NULL);
4003 }
4004
4005 static void
4006 gtk_entry_password_hint_free (GtkEntryPasswordHint *password_hint)
4007 {
4008   if (password_hint->password_hint_timeout_id)
4009     g_source_remove (password_hint->password_hint_timeout_id);
4010
4011   g_slice_free (GtkEntryPasswordHint, password_hint);
4012 }
4013
4014 /* Default signal handlers
4015  */
4016 static void
4017 gtk_entry_real_insert_text (GtkEditable *editable,
4018                             const gchar *new_text,
4019                             gint         new_text_length,
4020                             gint        *position)
4021 {
4022   GtkEntry *entry = GTK_ENTRY (editable);
4023   gint index;
4024   gint n_chars;
4025
4026   if (new_text_length < 0)
4027     new_text_length = strlen (new_text);
4028
4029   n_chars = g_utf8_strlen (new_text, new_text_length);
4030   if (entry->text_max_length > 0 && n_chars + entry->text_length > entry->text_max_length)
4031     {
4032       gtk_widget_error_bell (GTK_WIDGET (entry));
4033       n_chars = entry->text_max_length - entry->text_length;
4034       new_text_length = g_utf8_offset_to_pointer (new_text, n_chars) - new_text;
4035     }
4036
4037   if (new_text_length + entry->n_bytes + 1 > entry->text_size)
4038     {
4039       gsize prev_size = entry->text_size;
4040
4041       while (new_text_length + entry->n_bytes + 1 > entry->text_size)
4042         {
4043           if (entry->text_size == 0)
4044             entry->text_size = MIN_SIZE;
4045           else
4046             {
4047               if (2 * (guint)entry->text_size < MAX_SIZE &&
4048                   2 * (guint)entry->text_size > entry->text_size)
4049                 entry->text_size *= 2;
4050               else
4051                 {
4052                   entry->text_size = MAX_SIZE;
4053                   if (new_text_length > (gint)entry->text_size - (gint)entry->n_bytes - 1)
4054                     {
4055                       new_text_length = (gint)entry->text_size - (gint)entry->n_bytes - 1;
4056                       new_text_length = g_utf8_find_prev_char (new_text, new_text + new_text_length + 1) - new_text;
4057                       n_chars = g_utf8_strlen (new_text, new_text_length);
4058                     }
4059                   break;
4060                 }
4061             }
4062         }
4063
4064       if (entry->visible)
4065         entry->text = g_realloc (entry->text, entry->text_size);
4066       else
4067         {
4068           /* Same thing, just slower and without leaving stuff in memory.  */
4069           gchar *et_new = g_malloc (entry->text_size);
4070           memcpy (et_new, entry->text, MIN (prev_size, entry->text_size));
4071           trash_area (entry->text, prev_size);
4072           g_free (entry->text);
4073           entry->text = et_new;
4074         }
4075     }
4076
4077   index = g_utf8_offset_to_pointer (entry->text, *position) - entry->text;
4078
4079   g_memmove (entry->text + index + new_text_length, entry->text + index, entry->n_bytes - index);
4080   memcpy (entry->text + index, new_text, new_text_length);
4081
4082   entry->n_bytes += new_text_length;
4083   entry->text_length += n_chars;
4084
4085   /* NUL terminate for safety and convenience */
4086   entry->text[entry->n_bytes] = '\0';
4087   
4088   if (entry->current_pos > *position)
4089     entry->current_pos += n_chars;
4090   
4091   if (entry->selection_bound > *position)
4092     entry->selection_bound += n_chars;
4093
4094   if (n_chars == 1 && !entry->visible && (new_text_length < PASSWORD_HINT_MAX))
4095     {
4096       guint password_hint_timeout;
4097
4098       g_object_get (gtk_widget_get_settings (GTK_WIDGET (entry)),
4099                     "gtk-entry-password-hint-timeout", &password_hint_timeout,
4100                     NULL);
4101
4102       if (password_hint_timeout > 0)
4103         {
4104           GtkEntryPasswordHint *password_hint = g_object_get_qdata (G_OBJECT (entry),
4105                                                                     quark_password_hint);
4106
4107           if (!password_hint)
4108             {
4109               password_hint = g_slice_new0 (GtkEntryPasswordHint);
4110               g_object_set_qdata_full (G_OBJECT (entry), quark_password_hint,
4111                                        password_hint,
4112                                        (GDestroyNotify) gtk_entry_password_hint_free);
4113             }
4114
4115           memset (&password_hint->password_hint, 0x0, PASSWORD_HINT_MAX);
4116           password_hint->password_hint_length = new_text_length;
4117           memcpy (&password_hint->password_hint, new_text, new_text_length);
4118           password_hint->password_hint_position = *position + n_chars;
4119        }
4120     }
4121   else
4122     {
4123       g_object_set_qdata (G_OBJECT (entry), quark_password_hint, NULL);
4124     }
4125
4126   *position += n_chars;
4127
4128   gtk_entry_recompute (entry);
4129
4130   emit_changed (entry);
4131   g_object_notify (G_OBJECT (editable), "text");
4132   g_object_notify (G_OBJECT (editable), "text-length");
4133 }
4134
4135 static void
4136 gtk_entry_real_delete_text (GtkEditable *editable,
4137                             gint         start_pos,
4138                             gint         end_pos)
4139 {
4140   GtkEntry *entry = GTK_ENTRY (editable);
4141
4142   if (start_pos < 0)
4143     start_pos = 0;
4144   if (end_pos < 0 || end_pos > entry->text_length)
4145     end_pos = entry->text_length;
4146   
4147   if (start_pos < end_pos)
4148     {
4149       gint start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text;
4150       gint end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text;
4151       gint current_pos;
4152       gint selection_bound;
4153
4154       g_memmove (entry->text + start_index, entry->text + end_index, entry->n_bytes + 1 - end_index);
4155       entry->text_length -= (end_pos - start_pos);
4156       entry->n_bytes -= (end_index - start_index);
4157
4158       /* In password-mode, make sure we don't leave anything sensitive after
4159        * the terminating zero.  Note, that the terminating zero already trashed
4160        * one byte.
4161        */
4162       if (!entry->visible)
4163         trash_area (entry->text + entry->n_bytes + 1, end_index - start_index - 1);
4164       
4165       current_pos = entry->current_pos;
4166       if (current_pos > start_pos)
4167         current_pos -= MIN (current_pos, end_pos) - start_pos;
4168
4169       selection_bound = entry->selection_bound;
4170       if (selection_bound > start_pos)
4171         selection_bound -= MIN (selection_bound, end_pos) - start_pos;
4172
4173       gtk_entry_set_positions (entry, current_pos, selection_bound);
4174
4175       /* We might have deleted the selection
4176        */
4177       gtk_entry_update_primary_selection (entry);
4178       
4179       gtk_entry_recompute (entry);
4180
4181       emit_changed (entry);
4182       g_object_notify (G_OBJECT (editable), "text");
4183       g_object_notify (G_OBJECT (editable), "text-length");
4184     }
4185 }
4186
4187 /* Compute the X position for an offset that corresponds to the "more important
4188  * cursor position for that offset. We use this when trying to guess to which
4189  * end of the selection we should go to when the user hits the left or
4190  * right arrow key.
4191  */
4192 static gint
4193 get_better_cursor_x (GtkEntry *entry,
4194                      gint      offset)
4195 {
4196   GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (entry)));
4197   PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
4198   gboolean split_cursor;
4199   
4200   PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
4201   const gchar *text = pango_layout_get_text (layout);
4202   gint index = g_utf8_offset_to_pointer (text, offset) - text;
4203   
4204   PangoRectangle strong_pos, weak_pos;
4205   
4206   g_object_get (gtk_widget_get_settings (GTK_WIDGET (entry)),
4207                 "gtk-split-cursor", &split_cursor,
4208                 NULL);
4209
4210   pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos);
4211
4212   if (split_cursor)
4213     return strong_pos.x / PANGO_SCALE;
4214   else
4215     return (keymap_direction == entry->resolved_dir) ? strong_pos.x / PANGO_SCALE : weak_pos.x / PANGO_SCALE;
4216 }
4217
4218 static void
4219 gtk_entry_move_cursor (GtkEntry       *entry,
4220                        GtkMovementStep step,
4221                        gint            count,
4222                        gboolean        extend_selection)
4223 {
4224   gint new_pos = entry->current_pos;
4225
4226   _gtk_entry_reset_im_context (entry);
4227
4228   if (entry->current_pos != entry->selection_bound && !extend_selection)
4229     {
4230       /* If we have a current selection and aren't extending it, move to the
4231        * start/or end of the selection as appropriate
4232        */
4233       switch (step)
4234         {
4235         case GTK_MOVEMENT_VISUAL_POSITIONS:
4236           {
4237             gint current_x = get_better_cursor_x (entry, entry->current_pos);
4238             gint bound_x = get_better_cursor_x (entry, entry->selection_bound);
4239
4240             if (count <= 0)
4241               new_pos = current_x < bound_x ? entry->current_pos : entry->selection_bound;
4242             else 
4243               new_pos = current_x > bound_x ? entry->current_pos : entry->selection_bound;
4244             break;
4245           }
4246         case GTK_MOVEMENT_LOGICAL_POSITIONS:
4247         case GTK_MOVEMENT_WORDS:
4248           if (count < 0)
4249             new_pos = MIN (entry->current_pos, entry->selection_bound);
4250           else
4251             new_pos = MAX (entry->current_pos, entry->selection_bound);
4252           break;
4253         case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
4254         case GTK_MOVEMENT_PARAGRAPH_ENDS:
4255         case GTK_MOVEMENT_BUFFER_ENDS:
4256           new_pos = count < 0 ? 0 : entry->text_length;
4257           break;
4258         case GTK_MOVEMENT_DISPLAY_LINES:
4259         case GTK_MOVEMENT_PARAGRAPHS:
4260         case GTK_MOVEMENT_PAGES:
4261         case GTK_MOVEMENT_HORIZONTAL_PAGES:
4262           break;
4263         }
4264     }
4265   else
4266     {
4267       switch (step)
4268         {
4269         case GTK_MOVEMENT_LOGICAL_POSITIONS:
4270           new_pos = gtk_entry_move_logically (entry, new_pos, count);
4271           break;
4272         case GTK_MOVEMENT_VISUAL_POSITIONS:
4273           new_pos = gtk_entry_move_visually (entry, new_pos, count);
4274           if (entry->current_pos == new_pos)
4275             {
4276               if (!extend_selection)
4277                 {
4278                   if (!gtk_widget_keynav_failed (GTK_WIDGET (entry),
4279                                                  count > 0 ?
4280                                                  GTK_DIR_RIGHT : GTK_DIR_LEFT))
4281                     {
4282                       GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (entry));
4283
4284                       if (toplevel)
4285                         gtk_widget_child_focus (toplevel,
4286                                                 count > 0 ?
4287                                                 GTK_DIR_RIGHT : GTK_DIR_LEFT);
4288                     }
4289                 }
4290               else
4291                 {
4292                   gtk_widget_error_bell (GTK_WIDGET (entry));
4293                 }
4294             }
4295           break;
4296         case GTK_MOVEMENT_WORDS:
4297           while (count > 0)
4298             {
4299               new_pos = gtk_entry_move_forward_word (entry, new_pos, FALSE);
4300               count--;
4301             }
4302           while (count < 0)
4303             {
4304               new_pos = gtk_entry_move_backward_word (entry, new_pos, FALSE);
4305               count++;
4306             }
4307           if (entry->current_pos == new_pos)
4308             gtk_widget_error_bell (GTK_WIDGET (entry));
4309           break;
4310         case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
4311         case GTK_MOVEMENT_PARAGRAPH_ENDS:
4312         case GTK_MOVEMENT_BUFFER_ENDS:
4313           new_pos = count < 0 ? 0 : entry->text_length;
4314           if (entry->current_pos == new_pos)
4315             gtk_widget_error_bell (GTK_WIDGET (entry));
4316           break;
4317         case GTK_MOVEMENT_DISPLAY_LINES:
4318         case GTK_MOVEMENT_PARAGRAPHS:
4319         case GTK_MOVEMENT_PAGES:
4320         case GTK_MOVEMENT_HORIZONTAL_PAGES:
4321           break;
4322         }
4323     }
4324
4325   if (extend_selection)
4326     gtk_editable_select_region (GTK_EDITABLE (entry), entry->selection_bound, new_pos);
4327   else
4328     gtk_editable_set_position (GTK_EDITABLE (entry), new_pos);
4329   
4330   gtk_entry_pend_cursor_blink (entry);
4331 }
4332
4333 static void
4334 gtk_entry_insert_at_cursor (GtkEntry    *entry,
4335                             const gchar *str)
4336 {
4337   GtkEditable *editable = GTK_EDITABLE (entry);
4338   gint pos = entry->current_pos;
4339
4340   if (entry->editable)
4341     {
4342       _gtk_entry_reset_im_context (entry);
4343
4344       gtk_editable_insert_text (editable, str, -1, &pos);
4345       gtk_editable_set_position (editable, pos);
4346     }
4347 }
4348
4349 static void
4350 gtk_entry_delete_from_cursor (GtkEntry       *entry,
4351                               GtkDeleteType   type,
4352                               gint            count)
4353 {
4354   GtkEditable *editable = GTK_EDITABLE (entry);
4355   gint start_pos = entry->current_pos;
4356   gint end_pos = entry->current_pos;
4357   gint old_n_bytes = entry->n_bytes;
4358   
4359   _gtk_entry_reset_im_context (entry);
4360
4361   if (!entry->editable)
4362     {
4363       gtk_widget_error_bell (GTK_WIDGET (entry));
4364       return;
4365     }
4366
4367   if (entry->selection_bound != entry->current_pos)
4368     {
4369       gtk_editable_delete_selection (editable);
4370       return;
4371     }
4372   
4373   switch (type)
4374     {
4375     case GTK_DELETE_CHARS:
4376       end_pos = gtk_entry_move_logically (entry, entry->current_pos, count);
4377       gtk_editable_delete_text (editable, MIN (start_pos, end_pos), MAX (start_pos, end_pos));
4378       break;
4379     case GTK_DELETE_WORDS:
4380       if (count < 0)
4381         {
4382           /* Move to end of current word, or if not on a word, end of previous word */
4383           end_pos = gtk_entry_move_backward_word (entry, end_pos, FALSE);
4384           end_pos = gtk_entry_move_forward_word (entry, end_pos, FALSE);
4385         }
4386       else if (count > 0)
4387         {
4388           /* Move to beginning of current word, or if not on a word, begining of next word */
4389           start_pos = gtk_entry_move_forward_word (entry, start_pos, FALSE);
4390           start_pos = gtk_entry_move_backward_word (entry, start_pos, FALSE);
4391         }
4392         
4393       /* Fall through */
4394     case GTK_DELETE_WORD_ENDS:
4395       while (count < 0)
4396         {
4397           start_pos = gtk_entry_move_backward_word (entry, start_pos, FALSE);
4398           count++;
4399         }
4400       while (count > 0)
4401         {
4402           end_pos = gtk_entry_move_forward_word (entry, end_pos, FALSE);
4403           count--;
4404         }
4405       gtk_editable_delete_text (editable, start_pos, end_pos);
4406       break;
4407     case GTK_DELETE_DISPLAY_LINE_ENDS:
4408     case GTK_DELETE_PARAGRAPH_ENDS:
4409       if (count < 0)
4410         gtk_editable_delete_text (editable, 0, entry->current_pos);
4411       else
4412         gtk_editable_delete_text (editable, entry->current_pos, -1);
4413       break;
4414     case GTK_DELETE_DISPLAY_LINES:
4415     case GTK_DELETE_PARAGRAPHS:
4416       gtk_editable_delete_text (editable, 0, -1);  
4417       break;
4418     case GTK_DELETE_WHITESPACE:
4419       gtk_entry_delete_whitespace (entry);
4420       break;
4421     }
4422
4423   if (entry->n_bytes == old_n_bytes)
4424     gtk_widget_error_bell (GTK_WIDGET (entry));
4425
4426   gtk_entry_pend_cursor_blink (entry);
4427 }
4428
4429 static void
4430 gtk_entry_backspace (GtkEntry *entry)
4431 {
4432   GtkEditable *editable = GTK_EDITABLE (entry);
4433   gint prev_pos;
4434
4435   _gtk_entry_reset_im_context (entry);
4436
4437   if (!entry->editable || !entry->text)
4438     {
4439       gtk_widget_error_bell (GTK_WIDGET (entry));
4440       return;
4441     }
4442
4443   if (entry->selection_bound != entry->current_pos)
4444     {
4445       gtk_editable_delete_selection (editable);
4446       return;
4447     }
4448
4449   prev_pos = gtk_entry_move_logically (entry, entry->current_pos, -1);
4450
4451   if (prev_pos < entry->current_pos)
4452     {
4453       PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE);
4454       PangoLogAttr *log_attrs;
4455       gint n_attrs;
4456
4457       pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
4458
4459       if (entry->visible &&
4460           log_attrs[entry->current_pos].backspace_deletes_character)
4461         {
4462           gchar *cluster_text;
4463           gchar *normalized_text;
4464           glong  len;
4465
4466           cluster_text = gtk_editable_get_chars (editable,
4467                                                  prev_pos,
4468                                                  entry->current_pos);
4469           normalized_text = g_utf8_normalize (cluster_text,
4470                                               strlen (cluster_text),
4471                                               G_NORMALIZE_NFD);
4472           len = g_utf8_strlen (normalized_text, -1);
4473
4474           gtk_editable_delete_text (editable, prev_pos, entry->current_pos);
4475           if (len > 1)
4476             {
4477               gint pos = entry->current_pos;
4478
4479               gtk_editable_insert_text (editable, normalized_text,
4480                                         g_utf8_offset_to_pointer (normalized_text, len - 1) - normalized_text,
4481                                         &pos);
4482               gtk_editable_set_position (editable, pos);
4483             }
4484
4485           g_free (normalized_text);
4486           g_free (cluster_text);
4487         }
4488       else
4489         {
4490           gtk_editable_delete_text (editable, prev_pos, entry->current_pos);
4491         }
4492       
4493       g_free (log_attrs);
4494     }
4495   else
4496     {
4497       gtk_widget_error_bell (GTK_WIDGET (entry));
4498     }
4499
4500   gtk_entry_pend_cursor_blink (entry);
4501 }
4502
4503 static void
4504 gtk_entry_copy_clipboard (GtkEntry *entry)
4505 {
4506   GtkEditable *editable = GTK_EDITABLE (entry);
4507   gint start, end;
4508   gchar *str;
4509
4510   if (gtk_editable_get_selection_bounds (editable, &start, &end))
4511     {
4512       if (!entry->visible)
4513         {
4514           gtk_widget_error_bell (GTK_WIDGET (entry));
4515           return;
4516         }
4517
4518       str = gtk_entry_get_public_chars (entry, start, end);
4519       gtk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (entry),
4520                                                         GDK_SELECTION_CLIPBOARD),
4521                               str, -1);
4522       g_free (str);
4523     }
4524 }
4525
4526 static void
4527 gtk_entry_cut_clipboard (GtkEntry *entry)
4528 {
4529   GtkEditable *editable = GTK_EDITABLE (entry);
4530   gint start, end;
4531
4532   if (!entry->visible)
4533     {
4534       gtk_widget_error_bell (GTK_WIDGET (entry));
4535       return;
4536     }
4537
4538   gtk_entry_copy_clipboard (entry);
4539
4540   if (entry->editable)
4541     {
4542       if (gtk_editable_get_selection_bounds (editable, &start, &end))
4543         gtk_editable_delete_text (editable, start, end);
4544     }
4545   else
4546     {
4547       gtk_widget_error_bell (GTK_WIDGET (entry));
4548     }
4549 }
4550
4551 static void
4552 gtk_entry_paste_clipboard (GtkEntry *entry)
4553 {
4554   if (entry->editable)
4555     gtk_entry_paste (entry, GDK_NONE);
4556   else
4557     gtk_widget_error_bell (GTK_WIDGET (entry));
4558 }
4559
4560 static void
4561 gtk_entry_delete_cb (GtkEntry *entry)
4562 {
4563   GtkEditable *editable = GTK_EDITABLE (entry);
4564   gint start, end;
4565
4566   if (entry->editable)
4567     {
4568       if (gtk_editable_get_selection_bounds (editable, &start, &end))
4569         gtk_editable_delete_text (editable, start, end);
4570     }
4571 }
4572
4573 static void
4574 gtk_entry_toggle_overwrite (GtkEntry *entry)
4575 {
4576   entry->overwrite_mode = !entry->overwrite_mode;
4577   gtk_entry_pend_cursor_blink (entry);
4578   gtk_widget_queue_draw (GTK_WIDGET (entry));
4579 }
4580
4581 static void
4582 gtk_entry_select_all (GtkEntry *entry)
4583 {
4584   gtk_entry_select_line (entry);
4585 }
4586
4587 static void
4588 gtk_entry_real_activate (GtkEntry *entry)
4589 {
4590   GtkWindow *window;
4591   GtkWidget *toplevel;
4592   GtkWidget *widget;
4593
4594   widget = GTK_WIDGET (entry);
4595
4596   if (entry->activates_default)
4597     {
4598       toplevel = gtk_widget_get_toplevel (widget);
4599       if (GTK_IS_WINDOW (toplevel))
4600         {
4601           window = GTK_WINDOW (toplevel);
4602       
4603           if (window &&
4604               widget != window->default_widget &&
4605               !(widget == window->focus_widget &&
4606                 (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget))))
4607             gtk_window_activate_default (window);
4608         }
4609     }
4610 }
4611
4612 static void
4613 keymap_direction_changed (GdkKeymap *keymap,
4614                           GtkEntry  *entry)
4615 {
4616   gtk_entry_recompute (entry);
4617 }
4618
4619 /* IM Context Callbacks
4620  */
4621
4622 static void
4623 gtk_entry_commit_cb (GtkIMContext *context,
4624                      const gchar  *str,
4625                      GtkEntry     *entry)
4626 {
4627   if (entry->editable)
4628     gtk_entry_enter_text (entry, str);
4629 }
4630
4631 static void 
4632 gtk_entry_preedit_changed_cb (GtkIMContext *context,
4633                               GtkEntry     *entry)
4634 {
4635   if (entry->editable)
4636     {
4637       gchar *preedit_string;
4638       gint cursor_pos;
4639       
4640       gtk_im_context_get_preedit_string (entry->im_context,
4641                                          &preedit_string, NULL,
4642                                          &cursor_pos);
4643       entry->preedit_length = strlen (preedit_string);
4644       cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (preedit_string, -1));
4645       entry->preedit_cursor = cursor_pos;
4646       g_free (preedit_string);
4647     
4648       gtk_entry_recompute (entry);
4649     }
4650 }
4651
4652 static gboolean
4653 gtk_entry_retrieve_surrounding_cb (GtkIMContext *context,
4654                                GtkEntry         *entry)
4655 {
4656   gtk_im_context_set_surrounding (context,
4657                                   entry->text,
4658                                   entry->n_bytes,
4659                                   g_utf8_offset_to_pointer (entry->text, entry->current_pos) - entry->text);
4660
4661   return TRUE;
4662 }
4663
4664 static gboolean
4665 gtk_entry_delete_surrounding_cb (GtkIMContext *slave,
4666                                  gint          offset,
4667                                  gint          n_chars,
4668                                  GtkEntry     *entry)
4669 {
4670   if (entry->editable)
4671     gtk_editable_delete_text (GTK_EDITABLE (entry),
4672                               entry->current_pos + offset,
4673                               entry->current_pos + offset + n_chars);
4674
4675   return TRUE;
4676 }
4677
4678 /* Internal functions
4679  */
4680
4681 /* Used for im_commit_cb and inserting Unicode chars */
4682 static void
4683 gtk_entry_enter_text (GtkEntry       *entry,
4684                       const gchar    *str)
4685 {
4686   GtkEditable *editable = GTK_EDITABLE (entry);
4687   gint tmp_pos;
4688   gboolean old_need_im_reset;
4689
4690   old_need_im_reset = entry->need_im_reset;
4691   entry->need_im_reset = FALSE;
4692
4693   if (gtk_editable_get_selection_bounds (editable, NULL, NULL))
4694     gtk_editable_delete_selection (editable);
4695   else
4696     {
4697       if (entry->overwrite_mode)
4698         gtk_entry_delete_from_cursor (entry, GTK_DELETE_CHARS, 1);
4699     }
4700
4701   tmp_pos = entry->current_pos;
4702   gtk_editable_insert_text (editable, str, strlen (str), &tmp_pos);
4703   gtk_editable_set_position (editable, tmp_pos);
4704
4705   entry->need_im_reset = old_need_im_reset;
4706 }
4707
4708 /* All changes to entry->current_pos and entry->selection_bound
4709  * should go through this function.
4710  */
4711 static void
4712 gtk_entry_set_positions (GtkEntry *entry,
4713                          gint      current_pos,
4714                          gint      selection_bound)
4715 {
4716   gboolean changed = FALSE;
4717
4718   g_object_freeze_notify (G_OBJECT (entry));
4719   
4720   if (current_pos != -1 &&
4721       entry->current_pos != current_pos)
4722     {
4723       entry->current_pos = current_pos;
4724       changed = TRUE;
4725
4726       g_object_notify (G_OBJECT (entry), "cursor-position");
4727     }
4728
4729   if (selection_bound != -1 &&
4730       entry->selection_bound != selection_bound)
4731     {
4732       entry->selection_bound = selection_bound;
4733       changed = TRUE;
4734       
4735       g_object_notify (G_OBJECT (entry), "selection-bound");
4736     }
4737
4738   g_object_thaw_notify (G_OBJECT (entry));
4739
4740   if (changed) 
4741     {
4742       gtk_entry_move_adjustments (entry);
4743       gtk_entry_recompute (entry);
4744     }
4745 }
4746
4747 static void
4748 gtk_entry_reset_layout (GtkEntry *entry)
4749 {
4750   if (entry->cached_layout)
4751     {
4752       g_object_unref (entry->cached_layout);
4753       entry->cached_layout = NULL;
4754     }
4755 }
4756
4757 static void
4758 update_im_cursor_location (GtkEntry *entry)
4759 {
4760   GdkRectangle area;
4761   gint strong_x;
4762   gint strong_xoffset;
4763   gint area_width, area_height;
4764
4765   gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, NULL);
4766   gtk_entry_get_text_area_size (entry, NULL, NULL, &area_width, &area_height);
4767
4768   strong_xoffset = strong_x - entry->scroll_offset;
4769   if (strong_xoffset < 0)
4770     {
4771       strong_xoffset = 0;
4772     }
4773   else if (strong_xoffset > area_width)
4774     {
4775       strong_xoffset = area_width;
4776     }
4777   area.x = strong_xoffset;
4778   area.y = 0;
4779   area.width = 0;
4780   area.height = area_height;
4781
4782   gtk_im_context_set_cursor_location (entry->im_context, &area);
4783 }
4784
4785 static gboolean
4786 recompute_idle_func (gpointer data)
4787 {
4788   GtkEntry *entry;
4789
4790   entry = GTK_ENTRY (data);
4791
4792   entry->recompute_idle = 0;
4793   
4794   if (gtk_widget_has_screen (GTK_WIDGET (entry)))
4795     {
4796       gtk_entry_adjust_scroll (entry);
4797       gtk_entry_queue_draw (entry);
4798       
4799       update_im_cursor_location (entry);
4800     }
4801
4802   return FALSE;
4803 }
4804
4805 static void
4806 gtk_entry_recompute (GtkEntry *entry)
4807 {
4808   gtk_entry_reset_layout (entry);
4809   gtk_entry_check_cursor_blink (entry);
4810   
4811   if (!entry->recompute_idle)
4812     {
4813       entry->recompute_idle = gdk_threads_add_idle_full (G_PRIORITY_HIGH_IDLE + 15, /* between resize and redraw */
4814                                                recompute_idle_func, entry, NULL); 
4815     }
4816 }
4817
4818 static void
4819 append_char (GString *str,
4820              gunichar ch,
4821              gint     count)
4822 {
4823   gint i;
4824   gint char_len;
4825   gchar buf[7];
4826   
4827   char_len = g_unichar_to_utf8 (ch, buf);
4828   
4829   i = 0;
4830   while (i < count)
4831     {
4832       g_string_append_len (str, buf, char_len);
4833       ++i;
4834     }
4835 }
4836
4837 static gboolean
4838 gtk_entry_remove_password_hint (gpointer data)
4839 {
4840   /* Force the string to be redrawn, but now without a visible character */
4841   gtk_entry_recompute (GTK_ENTRY (data));
4842
4843   return FALSE;
4844 }
4845
4846 static PangoLayout *
4847 gtk_entry_create_layout (GtkEntry *entry,
4848                          gboolean  include_preedit)
4849 {
4850   GtkWidget *widget = GTK_WIDGET (entry);
4851   PangoLayout *layout = gtk_widget_create_pango_layout (widget, NULL);
4852   PangoAttrList *tmp_attrs = pango_attr_list_new ();
4853   
4854   gchar *preedit_string = NULL;
4855   gint preedit_length = 0;
4856   PangoAttrList *preedit_attrs = NULL;
4857
4858   pango_layout_set_single_paragraph_mode (layout, TRUE);
4859
4860   if (include_preedit)
4861     {
4862       gtk_im_context_get_preedit_string (entry->im_context,
4863                                          &preedit_string, &preedit_attrs, NULL);
4864       preedit_length = entry->preedit_length;
4865     }
4866
4867   if (preedit_length)
4868     {
4869       GString *tmp_string = g_string_new (NULL);
4870       
4871       gint cursor_index = g_utf8_offset_to_pointer (entry->text, entry->current_pos) - entry->text;
4872       
4873       if (entry->visible)
4874         {
4875           g_string_prepend_len (tmp_string, entry->text, entry->n_bytes);
4876           g_string_insert (tmp_string, cursor_index, preedit_string);
4877         }
4878       else
4879         {
4880           gint ch_len;
4881           gunichar invisible_char;
4882
4883           if (entry->invisible_char != 0)
4884             invisible_char = entry->invisible_char;
4885           else
4886             invisible_char = ' '; /* just pick a char */
4887
4888           ch_len = g_utf8_strlen (entry->text, entry->n_bytes);
4889           append_char (tmp_string, invisible_char, ch_len);
4890           cursor_index =
4891             g_utf8_offset_to_pointer (tmp_string->str, entry->current_pos) -
4892             tmp_string->str;
4893           g_string_insert (tmp_string, cursor_index, preedit_string);
4894         }
4895       
4896       pango_layout_set_text (layout, tmp_string->str, tmp_string->len);
4897       
4898       pango_attr_list_splice (tmp_attrs, preedit_attrs,
4899                               cursor_index, preedit_length);
4900       
4901       g_string_free (tmp_string, TRUE);
4902     }
4903   else
4904     {
4905       PangoDirection pango_dir;
4906       
4907       if (entry->visible)
4908         pango_dir = pango_find_base_dir (entry->text, entry->n_bytes);
4909
4910       else
4911         pango_dir = PANGO_DIRECTION_NEUTRAL;
4912
4913       if (pango_dir == PANGO_DIRECTION_NEUTRAL)
4914         {
4915           if (GTK_WIDGET_HAS_FOCUS (widget))
4916             {
4917               GdkDisplay *display = gtk_widget_get_display (widget);
4918               GdkKeymap *keymap = gdk_keymap_get_for_display (display);
4919               if (gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_RTL)
4920                 pango_dir = PANGO_DIRECTION_RTL;
4921               else
4922                 pango_dir = PANGO_DIRECTION_LTR;
4923             }
4924           else
4925             {
4926               if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
4927                 pango_dir = PANGO_DIRECTION_RTL;
4928               else
4929                 pango_dir = PANGO_DIRECTION_LTR;
4930             }
4931         }
4932
4933       pango_context_set_base_dir (gtk_widget_get_pango_context (widget),
4934                                   pango_dir);
4935
4936       entry->resolved_dir = pango_dir;
4937       
4938       if (entry->visible)
4939         {
4940           pango_layout_set_text (layout, entry->text, entry->n_bytes);
4941         }
4942       else
4943         {
4944           GString *str = g_string_new (NULL);
4945           gunichar invisible_char;
4946           guint password_hint_timeout;
4947           GtkEntryPasswordHint *password_hint;
4948
4949           g_object_get (gtk_widget_get_settings (widget),
4950                         "gtk-entry-password-hint-timeout", &password_hint_timeout,
4951                         NULL);
4952
4953           if (entry->invisible_char != 0)
4954             invisible_char = entry->invisible_char;
4955           else
4956             invisible_char = ' '; /* just pick a char */
4957
4958           password_hint = g_object_get_qdata (G_OBJECT (entry),
4959                                               quark_password_hint);
4960
4961           if (password_hint && password_hint->password_hint_timeout_id)
4962             {
4963               g_source_remove (password_hint->password_hint_timeout_id);
4964               password_hint->password_hint_timeout_id = 0;
4965             }
4966
4967           if (password_hint_timeout == 0 || password_hint == NULL ||
4968               (password_hint && password_hint->password_hint_length == 0))
4969             {
4970               append_char (str, invisible_char, entry->text_length);
4971             }
4972           else if (password_hint)
4973             {
4974               /* Draw hidden characters upto the inserted position,
4975                * then the real thing, pad up to full length
4976                */
4977               if (password_hint->password_hint_position > 1)
4978                 append_char (str, invisible_char,
4979                              password_hint->password_hint_position - 1);
4980
4981               g_string_append_len (str, password_hint->password_hint,
4982                                    password_hint->password_hint_length);
4983
4984               if (password_hint->password_hint_position < entry->text_length)
4985                 append_char (str, invisible_char,
4986                              entry->text_length -
4987                              password_hint->password_hint_position);
4988
4989               /* Now remove this last input character, don't need
4990                * it anymore
4991                */
4992               memset (password_hint->password_hint, 0, PASSWORD_HINT_MAX);
4993               password_hint->password_hint_length = 0;
4994
4995               password_hint->password_hint_timeout_id =
4996                 gdk_threads_add_timeout (password_hint_timeout,
4997                                (GSourceFunc) gtk_entry_remove_password_hint,
4998                                entry);
4999             }
5000
5001           pango_layout_set_text (layout, str->str, str->len);
5002           g_string_free (str, TRUE);
5003         }
5004     }
5005       
5006   pango_layout_set_attributes (layout, tmp_attrs);
5007
5008   g_free (preedit_string);
5009   if (preedit_attrs)
5010     pango_attr_list_unref (preedit_attrs);
5011       
5012   pango_attr_list_unref (tmp_attrs);
5013
5014   return layout;
5015 }
5016
5017 static PangoLayout *
5018 gtk_entry_ensure_layout (GtkEntry *entry,
5019                          gboolean  include_preedit)
5020 {
5021   if (entry->preedit_length > 0 &&
5022       !include_preedit != !entry->cache_includes_preedit)
5023     gtk_entry_reset_layout (entry);
5024
5025   if (!entry->cached_layout)
5026     {
5027       entry->cached_layout = gtk_entry_create_layout (entry, include_preedit);
5028       entry->cache_includes_preedit = include_preedit;
5029     }
5030   
5031   return entry->cached_layout;
5032 }
5033
5034 static void
5035 get_layout_position (GtkEntry *entry,
5036                      gint     *x,
5037                      gint     *y)
5038 {
5039   PangoLayout *layout;
5040   PangoRectangle logical_rect;
5041   gint area_width, area_height;
5042   GtkBorder inner_border;
5043   gint y_pos;
5044   PangoLayoutLine *line;
5045   
5046   layout = gtk_entry_ensure_layout (entry, TRUE);
5047
5048   gtk_entry_get_text_area_size (entry, NULL, NULL, &area_width, &area_height);
5049   _gtk_entry_effective_inner_border (entry, &inner_border);
5050
5051   area_height = PANGO_SCALE * (area_height - inner_border.top - inner_border.bottom);
5052
5053   line = pango_layout_get_lines_readonly (layout)->data;
5054   pango_layout_line_get_extents (line, NULL, &logical_rect);
5055   
5056   /* Align primarily for locale's ascent/descent */
5057   y_pos = ((area_height - entry->ascent - entry->descent) / 2 + 
5058            entry->ascent + logical_rect.y);
5059   
5060   /* Now see if we need to adjust to fit in actual drawn string */
5061   if (logical_rect.height > area_height)
5062     y_pos = (area_height - logical_rect.height) / 2;
5063   else if (y_pos < 0)
5064     y_pos = 0;
5065   else if (y_pos + logical_rect.height > area_height)
5066     y_pos = area_height - logical_rect.height;
5067   
5068   y_pos = inner_border.top + y_pos / PANGO_SCALE;
5069
5070   if (x)
5071     *x = inner_border.left - entry->scroll_offset;
5072
5073   if (y)
5074     *y = y_pos;
5075 }
5076
5077 static void
5078 gtk_entry_draw_text (GtkEntry *entry)
5079 {
5080   GtkWidget *widget;
5081   
5082   if (!entry->visible && entry->invisible_char == 0)
5083     return;
5084   
5085   if (GTK_WIDGET_DRAWABLE (entry))
5086     {
5087       PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
5088       cairo_t *cr;
5089       gint x, y;
5090       gint start_pos, end_pos;
5091       
5092       widget = GTK_WIDGET (entry);
5093       
5094       get_layout_position (entry, &x, &y);
5095
5096       cr = gdk_cairo_create (entry->text_area);
5097
5098       cairo_move_to (cr, x, y);
5099       gdk_cairo_set_source_color (cr, &widget->style->text [widget->state]);
5100       pango_cairo_show_layout (cr, layout);
5101
5102       if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_pos, &end_pos))
5103         {
5104           gint *ranges;
5105           gint n_ranges, i;
5106           PangoRectangle logical_rect;
5107           GdkColor *selection_color, *text_color;
5108           GtkBorder inner_border;
5109
5110           pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
5111           gtk_entry_get_pixel_ranges (entry, &ranges, &n_ranges);
5112
5113           if (GTK_WIDGET_HAS_FOCUS (entry))
5114             {
5115               selection_color = &widget->style->base [GTK_STATE_SELECTED];
5116               text_color = &widget->style->text [GTK_STATE_SELECTED];
5117             }
5118           else
5119             {
5120               selection_color = &widget->style->base [GTK_STATE_ACTIVE];
5121               text_color = &widget->style->text [GTK_STATE_ACTIVE];
5122             }
5123
5124           _gtk_entry_effective_inner_border (entry, &inner_border);
5125
5126           for (i = 0; i < n_ranges; ++i)
5127             cairo_rectangle (cr,
5128                              inner_border.left - entry->scroll_offset + ranges[2 * i],
5129                              y,
5130                              ranges[2 * i + 1],
5131                              logical_rect.height);
5132
5133           cairo_clip (cr);
5134           
5135           gdk_cairo_set_source_color (cr, selection_color);
5136           cairo_paint (cr);
5137
5138           cairo_move_to (cr, x, y);
5139           gdk_cairo_set_source_color (cr, text_color);
5140           pango_cairo_show_layout (cr, layout);
5141           
5142           g_free (ranges);
5143         }
5144
5145       cairo_destroy (cr);
5146     }
5147 }
5148
5149 static void
5150 draw_insertion_cursor (GtkEntry      *entry,
5151                        GdkRectangle  *cursor_location,
5152                        gboolean       is_primary,
5153                        PangoDirection direction,
5154                        gboolean       draw_arrow)
5155 {
5156   GtkWidget *widget = GTK_WIDGET (entry);
5157   GtkTextDirection text_dir;
5158
5159   if (direction == PANGO_DIRECTION_LTR)
5160     text_dir = GTK_TEXT_DIR_LTR;
5161   else
5162     text_dir = GTK_TEXT_DIR_RTL;
5163
5164   gtk_draw_insertion_cursor (widget, entry->text_area, NULL,
5165                              cursor_location,
5166                              is_primary, text_dir, draw_arrow);
5167 }
5168
5169 static void
5170 gtk_entry_draw_cursor (GtkEntry  *entry,
5171                        CursorType type)
5172 {
5173   GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (entry)));
5174   PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
5175   
5176   if (GTK_WIDGET_DRAWABLE (entry))
5177     {
5178       GtkWidget *widget = GTK_WIDGET (entry);
5179       GdkRectangle cursor_location;
5180       gboolean split_cursor;
5181       PangoRectangle cursor_rect;
5182       GtkBorder inner_border;
5183       gint xoffset;
5184       gint text_area_height;
5185       gint cursor_index;
5186       gboolean block;
5187       gboolean block_at_line_end;
5188       PangoLayout *layout;
5189       const char *text;
5190
5191       _gtk_entry_effective_inner_border (entry, &inner_border);
5192
5193       xoffset = inner_border.left - entry->scroll_offset;
5194
5195       gdk_drawable_get_size (entry->text_area, NULL, &text_area_height);
5196
5197       layout = gtk_entry_ensure_layout (entry, TRUE);
5198       text = pango_layout_get_text (layout);
5199       cursor_index = g_utf8_offset_to_pointer (text, entry->current_pos + entry->preedit_cursor) - text;
5200       if (!entry->overwrite_mode)
5201         block = FALSE;
5202       else
5203         block = _gtk_text_util_get_block_cursor_location (layout,
5204                                                           cursor_index, &cursor_rect, &block_at_line_end);
5205
5206       if (!block)
5207         {
5208           gint strong_x, weak_x;
5209           PangoDirection dir1 = PANGO_DIRECTION_NEUTRAL;
5210           PangoDirection dir2 = PANGO_DIRECTION_NEUTRAL;
5211           gint x1 = 0;
5212           gint x2 = 0;
5213
5214           gtk_entry_get_cursor_locations (entry, type, &strong_x, &weak_x);
5215
5216           g_object_get (gtk_widget_get_settings (widget),
5217                         "gtk-split-cursor", &split_cursor,
5218                         NULL);
5219
5220           dir1 = entry->resolved_dir;
5221       
5222           if (split_cursor)
5223             {
5224               x1 = strong_x;
5225
5226               if (weak_x != strong_x)
5227                 {
5228                   dir2 = (entry->resolved_dir == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
5229                   x2 = weak_x;
5230                 }
5231             }
5232           else
5233             {
5234               if (keymap_direction == entry->resolved_dir)
5235                 x1 = strong_x;
5236               else
5237                 x1 = weak_x;
5238             }
5239
5240           cursor_location.x = xoffset + x1;
5241           cursor_location.y = inner_border.top;
5242           cursor_location.width = 0;
5243           cursor_location.height = text_area_height - inner_border.top - inner_border.bottom;
5244
5245           draw_insertion_cursor (entry,
5246                                  &cursor_location, TRUE, dir1,
5247                                  dir2 != PANGO_DIRECTION_NEUTRAL);
5248       
5249           if (dir2 != PANGO_DIRECTION_NEUTRAL)
5250             {
5251               cursor_location.x = xoffset + x2;
5252               draw_insertion_cursor (entry,
5253                                      &cursor_location, FALSE, dir2,
5254                                      TRUE);
5255             }
5256         }
5257       else /* overwrite_mode */
5258         {
5259           GdkColor cursor_color;
5260           GdkRectangle rect;
5261           cairo_t *cr;
5262           gint x, y;
5263
5264           get_layout_position (entry, &x, &y);
5265
5266           rect.x = PANGO_PIXELS (cursor_rect.x) + x;
5267           rect.y = PANGO_PIXELS (cursor_rect.y) + y;
5268           rect.width = PANGO_PIXELS (cursor_rect.width);
5269           rect.height = PANGO_PIXELS (cursor_rect.height);
5270
5271           cr = gdk_cairo_create (entry->text_area);
5272
5273           _gtk_widget_get_cursor_color (widget, &cursor_color);
5274           gdk_cairo_set_source_color (cr, &cursor_color);
5275           gdk_cairo_rectangle (cr, &rect);
5276           cairo_fill (cr);
5277
5278           if (!block_at_line_end)
5279             {
5280               gdk_cairo_rectangle (cr, &rect);
5281               cairo_clip (cr);
5282               cairo_move_to (cr, x, y);
5283               gdk_cairo_set_source_color (cr, &widget->style->base[widget->state]);
5284               pango_cairo_show_layout (cr, layout);
5285             }
5286
5287           cairo_destroy (cr);
5288         }
5289     }
5290 }
5291
5292 static void
5293 gtk_entry_queue_draw (GtkEntry *entry)
5294 {
5295   if (GTK_WIDGET_DRAWABLE (entry))
5296     gdk_window_invalidate_rect (entry->text_area, NULL, FALSE);
5297 }
5298
5299 void
5300 _gtk_entry_reset_im_context (GtkEntry *entry)
5301 {
5302   if (entry->need_im_reset)
5303     {
5304       entry->need_im_reset = FALSE;
5305       gtk_im_context_reset (entry->im_context);
5306     }
5307 }
5308
5309 static gint
5310 gtk_entry_find_position (GtkEntry *entry,
5311                          gint      x)
5312 {
5313   PangoLayout *layout;
5314   PangoLayoutLine *line;
5315   gint index;
5316   gint pos;
5317   gint trailing;
5318   const gchar *text;
5319   gint cursor_index;
5320   
5321   layout = gtk_entry_ensure_layout (entry, TRUE);
5322   text = pango_layout_get_text (layout);
5323   cursor_index = g_utf8_offset_to_pointer (text, entry->current_pos) - text;
5324   
5325   line = pango_layout_get_lines_readonly (layout)->data;
5326   pango_layout_line_x_to_index (line, x * PANGO_SCALE, &index, &trailing);
5327
5328   if (index >= cursor_index && entry->preedit_length)
5329     {
5330       if (index >= cursor_index + entry->preedit_length)
5331         index -= entry->preedit_length;
5332       else
5333         {
5334           index = cursor_index;
5335           trailing = 0;
5336         }
5337     }
5338
5339   pos = g_utf8_pointer_to_offset (text, text + index);
5340   pos += trailing;
5341
5342   return pos;
5343 }
5344
5345 static void
5346 gtk_entry_get_cursor_locations (GtkEntry   *entry,
5347                                 CursorType  type,
5348                                 gint       *strong_x,
5349                                 gint       *weak_x)
5350 {
5351   if (!entry->visible && !entry->invisible_char)
5352     {
5353       if (strong_x)
5354         *strong_x = 0;
5355       
5356       if (weak_x)
5357         *weak_x = 0;
5358     }
5359   else
5360     {
5361       PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
5362       const gchar *text = pango_layout_get_text (layout);
5363       PangoRectangle strong_pos, weak_pos;
5364       gint index;
5365   
5366       if (type == CURSOR_STANDARD)
5367         {
5368           index = g_utf8_offset_to_pointer (text, entry->current_pos + entry->preedit_cursor) - text;
5369         }
5370       else /* type == CURSOR_DND */
5371         {
5372           index = g_utf8_offset_to_pointer (text, entry->dnd_position) - text;
5373
5374           if (entry->dnd_position > entry->current_pos)
5375             {
5376               if (entry->visible)
5377                 index += entry->preedit_length;
5378               else
5379                 {
5380                   gint preedit_len_chars = g_utf8_strlen (text, -1) - entry->text_length;
5381                   index += preedit_len_chars * g_unichar_to_utf8 (entry->invisible_char, NULL);
5382                 }
5383             }
5384         }
5385       
5386       pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos);
5387       
5388       if (strong_x)
5389         *strong_x = strong_pos.x / PANGO_SCALE;
5390       
5391       if (weak_x)
5392         *weak_x = weak_pos.x / PANGO_SCALE;
5393     }
5394 }
5395
5396 static void
5397 gtk_entry_adjust_scroll (GtkEntry *entry)
5398 {
5399   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
5400   gint min_offset, max_offset;
5401   gint text_area_width, text_width;
5402   GtkBorder inner_border;
5403   gint strong_x, weak_x;
5404   gint strong_xoffset, weak_xoffset;
5405   gfloat xalign;
5406   PangoLayout *layout;
5407   PangoLayoutLine *line;
5408   PangoRectangle logical_rect;
5409
5410   if (!GTK_WIDGET_REALIZED (entry))
5411     return;
5412
5413   _gtk_entry_effective_inner_border (entry, &inner_border);
5414
5415   gdk_drawable_get_size (entry->text_area, &text_area_width, NULL);
5416   text_area_width -= inner_border.left + inner_border.right;
5417   if (text_area_width < 0)
5418     text_area_width = 0;
5419
5420   layout = gtk_entry_ensure_layout (entry, TRUE);
5421   line = pango_layout_get_lines_readonly (layout)->data;
5422
5423   pango_layout_line_get_extents (line, NULL, &logical_rect);
5424
5425   /* Display as much text as we can */
5426
5427   if (entry->resolved_dir == PANGO_DIRECTION_LTR)
5428       xalign = priv->xalign;
5429   else
5430       xalign = 1.0 - priv->xalign;
5431
5432   text_width = PANGO_PIXELS(logical_rect.width);
5433
5434   if (text_width > text_area_width)
5435     {
5436       min_offset = 0;
5437       max_offset = text_width - text_area_width;
5438     }
5439   else
5440     {
5441       min_offset = (text_width - text_area_width) * xalign;
5442       max_offset = min_offset;
5443     }
5444
5445   entry->scroll_offset = CLAMP (entry->scroll_offset, min_offset, max_offset);
5446
5447   /* And make sure cursors are on screen. Note that the cursor is
5448    * actually drawn one pixel into the INNER_BORDER space on
5449    * the right, when the scroll is at the utmost right. This
5450    * looks better to to me than confining the cursor inside the
5451    * border entirely, though it means that the cursor gets one
5452    * pixel closer to the edge of the widget on the right than
5453    * on the left. This might need changing if one changed
5454    * INNER_BORDER from 2 to 1, as one would do on a
5455    * small-screen-real-estate display.
5456    *
5457    * We always make sure that the strong cursor is on screen, and
5458    * put the weak cursor on screen if possible.
5459    */
5460
5461   gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, &weak_x);
5462   
5463   strong_xoffset = strong_x - entry->scroll_offset;
5464
5465   if (strong_xoffset < 0)
5466     {
5467       entry->scroll_offset += strong_xoffset;
5468       strong_xoffset = 0;
5469     }
5470   else if (strong_xoffset > text_area_width)
5471     {
5472       entry->scroll_offset += strong_xoffset - text_area_width;
5473       strong_xoffset = text_area_width;
5474     }
5475
5476   weak_xoffset = weak_x - entry->scroll_offset;
5477
5478   if (weak_xoffset < 0 && strong_xoffset - weak_xoffset <= text_area_width)
5479     {
5480       entry->scroll_offset += weak_xoffset;
5481     }
5482   else if (weak_xoffset > text_area_width &&
5483            strong_xoffset - (weak_xoffset - text_area_width) >= 0)
5484     {
5485       entry->scroll_offset += weak_xoffset - text_area_width;
5486     }
5487
5488   g_object_notify (G_OBJECT (entry), "scroll-offset");
5489 }
5490
5491 static void
5492 gtk_entry_move_adjustments (GtkEntry *entry)
5493 {
5494   PangoContext *context;
5495   PangoFontMetrics *metrics;
5496   gint x, layout_x, border_x, border_y;
5497   gint char_width;
5498   GtkAdjustment *adjustment;
5499
5500   adjustment = g_object_get_qdata (G_OBJECT (entry), quark_cursor_hadjustment);
5501   if (!adjustment)
5502     return;
5503
5504   /* Cursor position, layout offset, border width, and widget allocation */
5505   gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &x, NULL);
5506   get_layout_position (entry, &layout_x, NULL);
5507   _gtk_entry_get_borders (entry, &border_x, &border_y);
5508   x += entry->widget.allocation.x + layout_x + border_x;
5509
5510   /* Approximate width of a char, so user can see what is ahead/behind */
5511   context = gtk_widget_get_pango_context (GTK_WIDGET (entry));
5512   metrics = pango_context_get_metrics (context, 
5513                                        entry->widget.style->font_desc,
5514                                        pango_context_get_language (context));
5515   char_width = pango_font_metrics_get_approximate_char_width (metrics) / PANGO_SCALE;
5516
5517   /* Scroll it */
5518   gtk_adjustment_clamp_page (adjustment, 
5519                              x - (char_width + 1),   /* one char + one pixel before */
5520                              x + (char_width + 2));  /* one char + cursor + one pixel after */
5521 }
5522
5523 static gint
5524 gtk_entry_move_visually (GtkEntry *entry,
5525                          gint      start,
5526                          gint      count)
5527 {
5528   gint index;
5529   PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE);
5530   const gchar *text;
5531
5532   text = pango_layout_get_text (layout);
5533   
5534   index = g_utf8_offset_to_pointer (text, start) - text;
5535
5536   while (count != 0)
5537     {
5538       int new_index, new_trailing;
5539       gboolean split_cursor;
5540       gboolean strong;
5541
5542       g_object_get (gtk_widget_get_settings (GTK_WIDGET (entry)),
5543                     "gtk-split-cursor", &split_cursor,
5544                     NULL);
5545
5546       if (split_cursor)
5547         strong = TRUE;
5548       else
5549         {
5550           GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (entry)));
5551           PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
5552
5553           strong = keymap_direction == entry->resolved_dir;
5554         }
5555       
5556       if (count > 0)
5557         {
5558           pango_layout_move_cursor_visually (layout, strong, index, 0, 1, &new_index, &new_trailing);
5559           count--;
5560         }
5561       else
5562         {
5563           pango_layout_move_cursor_visually (layout, strong, index, 0, -1, &new_index, &new_trailing);
5564           count++;
5565         }
5566
5567       if (new_index < 0)
5568         index = 0;
5569       else if (new_index != G_MAXINT)
5570         index = new_index;
5571       
5572       while (new_trailing--)
5573         index = g_utf8_next_char (text + index) - text;
5574     }
5575   
5576   return g_utf8_pointer_to_offset (text, text + index);
5577 }
5578
5579 static gint
5580 gtk_entry_move_logically (GtkEntry *entry,
5581                           gint      start,
5582                           gint      count)
5583 {
5584   gint new_pos = start;
5585
5586   /* Prevent any leak of information */
5587   if (!entry->visible)
5588     {
5589       new_pos = CLAMP (start + count, 0, entry->text_length);
5590     }
5591   else if (entry->text)
5592     {
5593       PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE);
5594       PangoLogAttr *log_attrs;
5595       gint n_attrs;
5596
5597       pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
5598
5599       while (count > 0 && new_pos < entry->text_length)
5600         {
5601           do
5602             new_pos++;
5603           while (new_pos < entry->text_length && !log_attrs[new_pos].is_cursor_position);
5604           
5605           count--;
5606         }
5607       while (count < 0 && new_pos > 0)
5608         {
5609           do
5610             new_pos--;
5611           while (new_pos > 0 && !log_attrs[new_pos].is_cursor_position);
5612           
5613           count++;
5614         }
5615       
5616       g_free (log_attrs);
5617     }
5618
5619   return new_pos;
5620 }
5621
5622 static gint
5623 gtk_entry_move_forward_word (GtkEntry *entry,
5624                              gint      start,
5625                              gboolean  allow_whitespace)
5626 {
5627   gint new_pos = start;
5628
5629   /* Prevent any leak of information */
5630   if (!entry->visible)
5631     {
5632       new_pos = entry->text_length;
5633     }
5634   else if (entry->text && (new_pos < entry->text_length))
5635     {
5636       PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE);
5637       PangoLogAttr *log_attrs;
5638       gint n_attrs;
5639
5640       pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
5641       
5642       /* Find the next word boundary */
5643       new_pos++;
5644       while (new_pos < n_attrs - 1 && !(log_attrs[new_pos].is_word_end ||
5645                                         (log_attrs[new_pos].is_word_start && allow_whitespace)))
5646         new_pos++;
5647
5648       g_free (log_attrs);
5649     }
5650
5651   return new_pos;
5652 }
5653
5654
5655 static gint
5656 gtk_entry_move_backward_word (GtkEntry *entry,
5657                               gint      start,
5658                               gboolean  allow_whitespace)
5659 {
5660   gint new_pos = start;
5661
5662   /* Prevent any leak of information */
5663   if (!entry->visible)
5664     {
5665       new_pos = 0;
5666     }
5667   else if (entry->text && start > 0)
5668     {
5669       PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE);
5670       PangoLogAttr *log_attrs;
5671       gint n_attrs;
5672
5673       pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
5674
5675       new_pos = start - 1;
5676
5677       /* Find the previous word boundary */
5678       while (new_pos > 0 && !(log_attrs[new_pos].is_word_start || 
5679                               (log_attrs[new_pos].is_word_end && allow_whitespace)))
5680         new_pos--;
5681
5682       g_free (log_attrs);
5683     }
5684
5685   return new_pos;
5686 }
5687
5688 static void
5689 gtk_entry_delete_whitespace (GtkEntry *entry)
5690 {
5691   PangoLayout *layout = gtk_entry_ensure_layout (entry, FALSE);
5692   PangoLogAttr *log_attrs;
5693   gint n_attrs;
5694   gint start, end;
5695
5696   pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
5697
5698   start = end = entry->current_pos;
5699   
5700   while (start > 0 && log_attrs[start-1].is_white)
5701     start--;
5702
5703   while (end < n_attrs && log_attrs[end].is_white)
5704     end++;
5705
5706   g_free (log_attrs);
5707
5708   if (start != end)
5709     gtk_editable_delete_text (GTK_EDITABLE (entry), start, end);
5710 }
5711
5712
5713 static void
5714 gtk_entry_select_word (GtkEntry *entry)
5715 {
5716   gint start_pos = gtk_entry_move_backward_word (entry, entry->current_pos, TRUE);
5717   gint end_pos = gtk_entry_move_forward_word (entry, entry->current_pos, TRUE);
5718
5719   gtk_editable_select_region (GTK_EDITABLE (entry), start_pos, end_pos);
5720 }
5721
5722 static void
5723 gtk_entry_select_line (GtkEntry *entry)
5724 {
5725   gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
5726 }
5727
5728 /*
5729  * Like gtk_editable_get_chars, but handle not-visible entries
5730  * correctly.
5731  */
5732 static char *    
5733 gtk_entry_get_public_chars (GtkEntry *entry,
5734                             gint      start,
5735                             gint      end)
5736 {
5737   if (end < 0)
5738     end = entry->text_length;
5739   
5740   if (entry->visible)
5741     return gtk_editable_get_chars (GTK_EDITABLE (entry), start, end);
5742   else if (!entry->invisible_char)
5743     return g_strdup ("");
5744   else
5745     {
5746       GString *str = g_string_new (NULL);
5747       append_char (str, entry->invisible_char, end - start);
5748       return g_string_free (str, FALSE);
5749     }
5750 }
5751
5752 static gint
5753 truncate_multiline (const gchar *text)
5754 {
5755   gint length;
5756
5757   for (length = 0;
5758        text[length] && text[length] != '\n' && text[length] != '\r';
5759        length++);
5760
5761   return length;
5762 }
5763
5764 static void
5765 paste_received (GtkClipboard *clipboard,
5766                 const gchar  *text,
5767                 gpointer      data)
5768 {
5769   GtkEntry *entry = GTK_ENTRY (data);
5770   GtkEditable *editable = GTK_EDITABLE (entry);
5771   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
5772       
5773   if (entry->button == 2)
5774     {
5775       gint pos, start, end;
5776       pos = priv->insert_pos;
5777       gtk_editable_get_selection_bounds (editable, &start, &end);
5778       if (!((start <= pos && pos <= end) || (end <= pos && pos <= start)))
5779         gtk_editable_select_region (editable, pos, pos);
5780     }
5781       
5782   if (text)
5783     {
5784       gint pos, start, end;
5785       gint length = -1;
5786       gboolean popup_completion;
5787       GtkEntryCompletion *completion;
5788
5789       completion = gtk_entry_get_completion (entry);
5790
5791       if (entry->truncate_multiline)
5792         length = truncate_multiline (text);
5793
5794       /* only complete if the selection is at the end */
5795       popup_completion = (entry->text_length == MAX (entry->current_pos, entry->selection_bound));
5796
5797       if (completion)
5798         {
5799           if (GTK_WIDGET_MAPPED (completion->priv->popup_window))
5800             _gtk_entry_completion_popdown (completion);
5801
5802           if (!popup_completion && completion->priv->changed_id > 0)
5803             g_signal_handler_block (entry, completion->priv->changed_id);
5804         }
5805
5806       begin_change (entry);
5807       g_object_freeze_notify (G_OBJECT (entry));
5808       if (gtk_editable_get_selection_bounds (editable, &start, &end))
5809         gtk_editable_delete_text (editable, start, end);
5810
5811       pos = entry->current_pos;
5812       gtk_editable_insert_text (editable, text, length, &pos);
5813       gtk_editable_set_position (editable, pos);
5814       g_object_thaw_notify (G_OBJECT (entry));
5815       end_change (entry);
5816
5817       if (completion &&
5818           !popup_completion && completion->priv->changed_id > 0)
5819         g_signal_handler_unblock (entry, completion->priv->changed_id);
5820     }
5821
5822   g_object_unref (entry);
5823 }
5824
5825 static void
5826 gtk_entry_paste (GtkEntry *entry,
5827                  GdkAtom   selection)
5828 {
5829   g_object_ref (entry);
5830   gtk_clipboard_request_text (gtk_widget_get_clipboard (GTK_WIDGET (entry), selection),
5831                               paste_received, entry);
5832 }
5833
5834 static void
5835 primary_get_cb (GtkClipboard     *clipboard,
5836                 GtkSelectionData *selection_data,
5837                 guint             info,
5838                 gpointer          data)
5839 {
5840   GtkEntry *entry = GTK_ENTRY (data);
5841   gint start, end;
5842   
5843   if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end))
5844     {
5845       gchar *str = gtk_entry_get_public_chars (entry, start, end);
5846       gtk_selection_data_set_text (selection_data, str, -1);
5847       g_free (str);
5848     }
5849 }
5850
5851 static void
5852 primary_clear_cb (GtkClipboard *clipboard,
5853                   gpointer      data)
5854 {
5855   GtkEntry *entry = GTK_ENTRY (data);
5856
5857   gtk_editable_select_region (GTK_EDITABLE (entry), entry->current_pos, entry->current_pos);
5858 }
5859
5860 static void
5861 gtk_entry_update_primary_selection (GtkEntry *entry)
5862 {
5863   GtkTargetList *list;
5864   GtkTargetEntry *targets;
5865   GtkClipboard *clipboard;
5866   gint start, end;
5867   gint n_targets;
5868
5869   if (!GTK_WIDGET_REALIZED (entry))
5870     return;
5871
5872   list = gtk_target_list_new (NULL, 0);
5873   gtk_target_list_add_text_targets (list, 0);
5874
5875   targets = gtk_target_table_new_from_list (list, &n_targets);
5876
5877   clipboard = gtk_widget_get_clipboard (GTK_WIDGET (entry), GDK_SELECTION_PRIMARY);
5878   
5879   if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end))
5880     {
5881       if (!gtk_clipboard_set_with_owner (clipboard, targets, n_targets,
5882                                          primary_get_cb, primary_clear_cb, G_OBJECT (entry)))
5883         primary_clear_cb (clipboard, entry);
5884     }
5885   else
5886     {
5887       if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (entry))
5888         gtk_clipboard_clear (clipboard);
5889     }
5890
5891   gtk_target_table_free (targets, n_targets);
5892   gtk_target_list_unref (list);
5893 }
5894
5895 static void
5896 gtk_entry_clear (GtkEntry             *entry,
5897                  GtkEntryIconPosition  icon_pos)
5898 {
5899   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
5900   EntryIconInfo *icon_info = priv->icons[icon_pos];
5901
5902   if (!icon_info || icon_info->storage_type == GTK_IMAGE_EMPTY)
5903     return;
5904
5905   g_object_freeze_notify (G_OBJECT (entry));
5906
5907   /* Explicitly check, as the pointer may become invalidated
5908    * during destruction.
5909    */
5910   if (GDK_IS_WINDOW (icon_info->window))
5911     gdk_window_hide (icon_info->window);
5912
5913   if (icon_info->pixbuf)
5914     {
5915       g_object_unref (icon_info->pixbuf);
5916       icon_info->pixbuf = NULL;
5917     }
5918
5919   switch (icon_info->storage_type)
5920     {
5921     case GTK_IMAGE_PIXBUF:
5922       g_object_notify (G_OBJECT (entry),
5923                        icon_pos == GTK_ENTRY_ICON_PRIMARY ? "pixbuf-primary" : "pixbuf-secondary");
5924       break;
5925
5926     case GTK_IMAGE_STOCK:
5927       g_free (icon_info->stock_id);
5928       icon_info->stock_id = NULL;
5929       g_object_notify (G_OBJECT (entry),
5930                        icon_pos == GTK_ENTRY_ICON_PRIMARY ? "stock-primary" : "stock-secondary");
5931       break;
5932
5933     case GTK_IMAGE_ICON_NAME:
5934       g_free (icon_info->icon_name);
5935       icon_info->icon_name = NULL;
5936       g_object_notify (G_OBJECT (entry),
5937                        icon_pos == GTK_ENTRY_ICON_PRIMARY ? "icon-name-primary" : "icon-name-secondary");
5938       break;
5939
5940     case GTK_IMAGE_GICON:
5941       if (icon_info->gicon)
5942         {
5943           g_object_unref (icon_info->gicon);
5944           icon_info->gicon = NULL;
5945         }
5946       g_object_notify (G_OBJECT (entry),
5947                        icon_pos == GTK_ENTRY_ICON_PRIMARY ? "gicon-primary" : "gicon-secondary");
5948       break;
5949
5950     default:
5951       g_assert_not_reached ();
5952       break;
5953     }
5954
5955   icon_info->storage_type = GTK_IMAGE_EMPTY;
5956   g_object_notify (G_OBJECT (entry),
5957                    icon_pos == GTK_ENTRY_ICON_PRIMARY ? "storage-type-primary" : "storage-type-secondary");
5958
5959   g_object_thaw_notify (G_OBJECT (entry));
5960 }
5961
5962 static void
5963 gtk_entry_ensure_pixbuf (GtkEntry             *entry,
5964                          GtkEntryIconPosition  icon_pos)
5965 {
5966   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
5967   EntryIconInfo *icon_info = priv->icons[icon_pos];
5968   GdkScreen *screen;
5969   GtkIconTheme *icon_theme;
5970   GtkSettings *settings;
5971   gint width, height;
5972   GtkIconInfo *info;
5973
5974   if (!icon_info || icon_info->pixbuf)
5975     return;
5976
5977   switch (icon_info->storage_type)
5978     {
5979     case GTK_IMAGE_EMPTY:
5980     case GTK_IMAGE_PIXBUF:
5981       break;
5982     case GTK_IMAGE_STOCK:
5983       icon_info->pixbuf = gtk_widget_render_icon (GTK_WIDGET (entry),
5984                                                   icon_info->stock_id,
5985                                                   GTK_ICON_SIZE_MENU,
5986                                                   NULL);
5987       break;
5988
5989     case GTK_IMAGE_ICON_NAME:
5990       screen = gtk_widget_get_screen (GTK_WIDGET (entry));
5991       if (screen)
5992         {
5993           icon_theme = gtk_icon_theme_get_for_screen (screen);
5994           settings = gtk_settings_get_for_screen (screen);
5995           
5996           gtk_icon_size_lookup_for_settings (settings,
5997                                              GTK_ICON_SIZE_MENU,
5998                                              &width, &height);
5999
6000           icon_info->pixbuf = gtk_icon_theme_load_icon (icon_theme,
6001                                                         icon_info->icon_name,
6002                                                         MIN (width, height),
6003                                                         0, NULL);
6004
6005           if (icon_info->pixbuf == NULL)
6006             icon_info->pixbuf = gtk_widget_render_icon (GTK_WIDGET (entry),
6007                                                         GTK_STOCK_MISSING_IMAGE,
6008                                                         GTK_ICON_SIZE_MENU,
6009                                                         NULL);
6010         }
6011       break;
6012
6013     case GTK_IMAGE_GICON:
6014       screen = gtk_widget_get_screen (GTK_WIDGET (entry));
6015       if (screen)
6016         {
6017           icon_theme = gtk_icon_theme_get_for_screen (screen);
6018           settings = gtk_settings_get_for_screen (screen);
6019
6020           gtk_icon_size_lookup_for_settings (settings,
6021                                              GTK_ICON_SIZE_MENU,
6022                                              &width, &height);
6023
6024           info = gtk_icon_theme_lookup_by_gicon (icon_theme,
6025                                                  icon_info->gicon,
6026                                                  MIN (width, height), 
6027                                                  GTK_ICON_LOOKUP_USE_BUILTIN);
6028           if (info)
6029             {
6030               icon_info->pixbuf = gtk_icon_info_load_icon (info, NULL);
6031               gtk_icon_info_free (info);
6032             }
6033
6034           if (icon_info->pixbuf == NULL)
6035             icon_info->pixbuf = gtk_widget_render_icon (GTK_WIDGET (entry),
6036                                                         GTK_STOCK_MISSING_IMAGE,
6037                                                         GTK_ICON_SIZE_MENU,
6038                                                         NULL);
6039         }
6040       break;
6041
6042     default:
6043       g_assert_not_reached ();
6044       break;
6045     }
6046
6047   if (GDK_IS_WINDOW (icon_info->window))
6048     gdk_window_show (icon_info->window);
6049
6050   gtk_widget_queue_resize (GTK_WIDGET (entry));
6051 }
6052
6053
6054 /* Public API
6055  */
6056
6057 /**
6058  * gtk_entry_new:
6059  *
6060  * Creates a new entry.
6061  *
6062  * Return value: a new #GtkEntry.
6063  */
6064 GtkWidget*
6065 gtk_entry_new (void)
6066 {
6067   return g_object_new (GTK_TYPE_ENTRY, NULL);
6068 }
6069
6070 /**
6071  * gtk_entry_new_with_max_length:
6072  * @max: the maximum length of the entry, or 0 for no maximum.
6073  *   (other than the maximum length of entries.) The value passed in will
6074  *   be clamped to the range 0-65536.
6075  *
6076  * Creates a new #GtkEntry widget with the given maximum length.
6077  * 
6078  * Return value: a new #GtkEntry
6079  *
6080  * Deprecated: Use gtk_entry_set_max_length() instead.
6081  **/
6082 GtkWidget*
6083 gtk_entry_new_with_max_length (gint max)
6084 {
6085   GtkEntry *entry;
6086
6087   max = CLAMP (max, 0, MAX_SIZE);
6088
6089   entry = g_object_new (GTK_TYPE_ENTRY, NULL);
6090   entry->text_max_length = max;
6091
6092   return GTK_WIDGET (entry);
6093 }
6094
6095 /**
6096  * gtk_entry_set_text:
6097  * @entry: a #GtkEntry
6098  * @text: the new text
6099  *
6100  * Sets the text in the widget to the given
6101  * value, replacing the current contents.
6102  */
6103 void
6104 gtk_entry_set_text (GtkEntry    *entry,
6105                     const gchar *text)
6106 {
6107   gint tmp_pos;
6108   GtkEntryCompletion *completion;
6109
6110   g_return_if_fail (GTK_IS_ENTRY (entry));
6111   g_return_if_fail (text != NULL);
6112
6113   /* Actually setting the text will affect the cursor and selection;
6114    * if the contents don't actually change, this will look odd to the user.
6115    */
6116   if (strcmp (entry->text, text) == 0)
6117     return;
6118
6119   completion = gtk_entry_get_completion (entry);
6120   if (completion && completion->priv->changed_id > 0)
6121     g_signal_handler_block (entry, completion->priv->changed_id);
6122
6123   begin_change (entry);
6124   g_object_freeze_notify (G_OBJECT (entry));
6125   gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1);
6126
6127   tmp_pos = 0;
6128   gtk_editable_insert_text (GTK_EDITABLE (entry), text, strlen (text), &tmp_pos);
6129   g_object_thaw_notify (G_OBJECT (entry));
6130   end_change (entry);
6131
6132   if (completion && completion->priv->changed_id > 0)
6133     g_signal_handler_unblock (entry, completion->priv->changed_id);
6134 }
6135
6136 /**
6137  * gtk_entry_append_text:
6138  * @entry: a #GtkEntry
6139  * @text: the text to append
6140  *
6141  * Appends the given text to the contents of the widget.
6142  *
6143  * Deprecated: 2.0: Use gtk_editable_insert_text() instead.
6144  */
6145 void
6146 gtk_entry_append_text (GtkEntry *entry,
6147                        const gchar *text)
6148 {
6149   gint tmp_pos;
6150
6151   g_return_if_fail (GTK_IS_ENTRY (entry));
6152   g_return_if_fail (text != NULL);
6153
6154   tmp_pos = entry->text_length;
6155   gtk_editable_insert_text (GTK_EDITABLE (entry), text, -1, &tmp_pos);
6156 }
6157
6158 /**
6159  * gtk_entry_prepend_text:
6160  * @entry: a #GtkEntry
6161  * @text: the text to prepend
6162  *
6163  * Prepends the given text to the contents of the widget.
6164  *
6165  * Deprecated: 2.0: Use gtk_editable_insert_text() instead.
6166  */
6167 void
6168 gtk_entry_prepend_text (GtkEntry *entry,
6169                         const gchar *text)
6170 {
6171   gint tmp_pos;
6172
6173   g_return_if_fail (GTK_IS_ENTRY (entry));
6174   g_return_if_fail (text != NULL);
6175
6176   tmp_pos = 0;
6177   gtk_editable_insert_text (GTK_EDITABLE (entry), text, -1, &tmp_pos);
6178 }
6179
6180 /**
6181  * gtk_entry_set_position:
6182  * @entry: a #GtkEntry
6183  * @position: the position of the cursor. The cursor is displayed
6184  *    before the character with the given (base 0) index in the widget. 
6185  *    The value must be less than or equal to the number of characters 
6186  *    in the widget. A value of -1 indicates that the position should
6187  *    be set after the last character in the entry. Note that this 
6188  *    position is in characters, not in bytes.
6189  *
6190  * Sets the cursor position in an entry to the given value. 
6191  *
6192  * Deprecated: 2.0: Use gtk_editable_set_position() instead.
6193  */
6194 void
6195 gtk_entry_set_position (GtkEntry *entry,
6196                         gint      position)
6197 {
6198   g_return_if_fail (GTK_IS_ENTRY (entry));
6199
6200   gtk_editable_set_position (GTK_EDITABLE (entry), position);
6201 }
6202
6203 /**
6204  * gtk_entry_set_visibility:
6205  * @entry: a #GtkEntry
6206  * @visible: %TRUE if the contents of the entry are displayed
6207  *           as plaintext
6208  *
6209  * Sets whether the contents of the entry are visible or not. 
6210  * When visibility is set to %FALSE, characters are displayed 
6211  * as the invisible char, and will also appear that way when 
6212  * the text in the entry widget is copied elsewhere.
6213  *
6214  * By default, GTK+ picks the best invisible character available
6215  * in the current font, but it can be changed with
6216  * gtk_entry_set_invisible_char().
6217  */
6218 void
6219 gtk_entry_set_visibility (GtkEntry *entry,
6220                           gboolean visible)
6221 {
6222   g_return_if_fail (GTK_IS_ENTRY (entry));
6223
6224   visible = visible != FALSE;
6225
6226   if (entry->visible != visible)
6227     {
6228       entry->visible = visible;
6229
6230       g_object_notify (G_OBJECT (entry), "visibility");
6231       gtk_entry_recompute (entry);
6232     }
6233 }
6234
6235 /**
6236  * gtk_entry_get_visibility:
6237  * @entry: a #GtkEntry
6238  *
6239  * Retrieves whether the text in @entry is visible. See
6240  * gtk_entry_set_visibility().
6241  *
6242  * Return value: %TRUE if the text is currently visible
6243  **/
6244 gboolean
6245 gtk_entry_get_visibility (GtkEntry *entry)
6246 {
6247   g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
6248
6249   return entry->visible;
6250 }
6251
6252 /**
6253  * gtk_entry_set_invisible_char:
6254  * @entry: a #GtkEntry
6255  * @ch: a Unicode character
6256  * 
6257  * Sets the character to use in place of the actual text when
6258  * gtk_entry_set_visibility() has been called to set text visibility
6259  * to %FALSE. i.e. this is the character used in "password mode" to
6260  * show the user how many characters have been typed. By default, GTK+
6261  * picks the best invisible char available in the current font. If you
6262  * set the invisible char to 0, then the user will get no feedback
6263  * at all; there will be no text on the screen as they type.
6264  **/
6265 void
6266 gtk_entry_set_invisible_char (GtkEntry *entry,
6267                               gunichar  ch)
6268 {
6269   GtkEntryPrivate *priv;
6270
6271   g_return_if_fail (GTK_IS_ENTRY (entry));
6272
6273   priv = GTK_ENTRY_GET_PRIVATE (entry);
6274
6275   if (!priv->invisible_char_set)
6276     {
6277       priv->invisible_char_set = TRUE;
6278       g_object_notify (G_OBJECT (entry), "invisible-char-set");
6279     }
6280
6281   if (ch == entry->invisible_char)
6282     return;
6283
6284   entry->invisible_char = ch;
6285   g_object_notify (G_OBJECT (entry), "invisible-char");
6286   gtk_entry_recompute (entry);  
6287 }
6288
6289 /**
6290  * gtk_entry_get_invisible_char:
6291  * @entry: a #GtkEntry
6292  *
6293  * Retrieves the character displayed in place of the real characters
6294  * for entries with visibility set to false. See gtk_entry_set_invisible_char().
6295  *
6296  * Return value: the current invisible char, or 0, if the entry does not
6297  *               show invisible text at all. 
6298  **/
6299 gunichar
6300 gtk_entry_get_invisible_char (GtkEntry *entry)
6301 {
6302   g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
6303
6304   return entry->invisible_char;
6305 }
6306
6307 /**
6308  * gtk_entry_unset_invisible_char:
6309  * @entry: a #GtkEntry
6310  *
6311  * Unsets the invisible char previously set with
6312  * gtk_entry_set_invisible_char(). So that the
6313  * default invisible char is used again.
6314  *
6315  * Since: 2.16
6316  **/
6317 void
6318 gtk_entry_unset_invisible_char (GtkEntry *entry)
6319 {
6320   GtkEntryPrivate *priv;
6321   gunichar ch;
6322
6323   g_return_if_fail (GTK_IS_ENTRY (entry));
6324
6325   priv = GTK_ENTRY_GET_PRIVATE (entry);
6326
6327   if (!priv->invisible_char_set)
6328     return;
6329
6330   priv->invisible_char_set = FALSE;
6331   ch = find_invisible_char (GTK_WIDGET (entry));
6332
6333   if (entry->invisible_char != ch)
6334     {
6335       entry->invisible_char = ch;
6336       g_object_notify (G_OBJECT (entry), "invisible-char");
6337     }
6338
6339   g_object_notify (G_OBJECT (entry), "invisible-char-set");
6340   gtk_entry_recompute (entry);
6341 }
6342
6343 /**
6344  * gtk_entry_set_editable:
6345  * @entry: a #GtkEntry
6346  * @editable: %TRUE if the user is allowed to edit the text
6347  *   in the widget
6348  *
6349  * Determines if the user can edit the text in the editable
6350  * widget or not. 
6351  *
6352  * Deprecated: 2.0: Use gtk_editable_set_editable() instead.
6353  */
6354 void
6355 gtk_entry_set_editable (GtkEntry *entry,
6356                         gboolean  editable)
6357 {
6358   g_return_if_fail (GTK_IS_ENTRY (entry));
6359
6360   gtk_editable_set_editable (GTK_EDITABLE (entry), editable);
6361 }
6362
6363 /**
6364  * gtk_entry_set_overwrite_mode:
6365  * @entry: a #GtkEntry
6366  * @overwrite: new value
6367  * 
6368  * Sets whether the text is overwritten when typing in the #GtkEntry.
6369  *
6370  * Since: 2.14
6371  **/
6372 void
6373 gtk_entry_set_overwrite_mode (GtkEntry *entry,
6374                               gboolean  overwrite)
6375 {
6376   g_return_if_fail (GTK_IS_ENTRY (entry));
6377   
6378   if (entry->overwrite_mode == overwrite) 
6379     return;
6380   
6381   gtk_entry_toggle_overwrite (entry);
6382
6383   g_object_notify (G_OBJECT (entry), "overwrite-mode");
6384 }
6385
6386 /**
6387  * gtk_entry_get_overwrite_mode:
6388  * @entry: a #GtkEntry
6389  * 
6390  * Gets the value set by gtk_entry_set_overwrite_mode().
6391  * 
6392  * Return value: whether the text is overwritten when typing.
6393  *
6394  * Since: 2.14
6395  **/
6396 gboolean
6397 gtk_entry_get_overwrite_mode (GtkEntry *entry)
6398 {
6399   g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
6400
6401   return entry->overwrite_mode;
6402 }
6403
6404 /**
6405  * gtk_entry_get_text:
6406  * @entry: a #GtkEntry
6407  *
6408  * Retrieves the contents of the entry widget.
6409  * See also gtk_editable_get_chars().
6410  *
6411  * Return value: a pointer to the contents of the widget as a
6412  *      string. This string points to internally allocated
6413  *      storage in the widget and must not be freed, modified or
6414  *      stored.
6415  **/
6416 G_CONST_RETURN gchar*
6417 gtk_entry_get_text (GtkEntry *entry)
6418 {
6419   g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
6420
6421   return entry->text;
6422 }
6423
6424 /**
6425  * gtk_entry_select_region:
6426  * @entry: a #GtkEntry
6427  * @start: the starting position
6428  * @end: the end position
6429  *
6430  * Selects a region of text. The characters that are selected are 
6431  * those characters at positions from @start_pos up to, but not 
6432  * including @end_pos. If @end_pos is negative, then the the characters 
6433  * selected will be those characters from @start_pos to the end of 
6434  * the text. 
6435  *
6436  * Deprecated: 2.0: Use gtk_editable_select_region() instead.
6437  */
6438 void       
6439 gtk_entry_select_region  (GtkEntry       *entry,
6440                           gint            start,
6441                           gint            end)
6442 {
6443   gtk_editable_select_region (GTK_EDITABLE (entry), start, end);
6444 }
6445
6446 /**
6447  * gtk_entry_set_max_length:
6448  * @entry: a #GtkEntry
6449  * @max: the maximum length of the entry, or 0 for no maximum.
6450  *   (other than the maximum length of entries.) The value passed in will
6451  *   be clamped to the range 0-65536.
6452  * 
6453  * Sets the maximum allowed length of the contents of the widget. If
6454  * the current contents are longer than the given length, then they
6455  * will be truncated to fit.
6456  **/
6457 void
6458 gtk_entry_set_max_length (GtkEntry     *entry,
6459                           gint          max)
6460 {
6461   g_return_if_fail (GTK_IS_ENTRY (entry));
6462
6463   max = CLAMP (max, 0, MAX_SIZE);
6464
6465   if (max > 0 && entry->text_length > max)
6466     gtk_editable_delete_text (GTK_EDITABLE (entry), max, -1);
6467   
6468   entry->text_max_length = max;
6469   g_object_notify (G_OBJECT (entry), "max-length");
6470 }
6471
6472 /**
6473  * gtk_entry_get_max_length:
6474  * @entry: a #GtkEntry
6475  *
6476  * Retrieves the maximum allowed length of the text in
6477  * @entry. See gtk_entry_set_max_length().
6478  *
6479  * Return value: the maximum allowed number of characters
6480  *               in #GtkEntry, or 0 if there is no maximum.
6481  **/
6482 gint
6483 gtk_entry_get_max_length (GtkEntry *entry)
6484 {
6485   g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
6486
6487   return entry->text_max_length;
6488 }
6489
6490 /**
6491  * gtk_entry_get_text_length:
6492  * @entry: a #GtkEntry
6493  *
6494  * Retrieves the current length of the text in
6495  * @entry. 
6496  *
6497  * Return value: the current number of characters
6498  *               in #GtkEntry, or 0 if there are none.
6499  *
6500  * Since: 2.14
6501  **/
6502 guint16
6503 gtk_entry_get_text_length (GtkEntry *entry)
6504 {
6505   g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
6506
6507   return entry->text_length;
6508 }
6509
6510 /**
6511  * gtk_entry_set_activates_default:
6512  * @entry: a #GtkEntry
6513  * @setting: %TRUE to activate window's default widget on Enter keypress
6514  *
6515  * If @setting is %TRUE, pressing Enter in the @entry will activate the default
6516  * widget for the window containing the entry. This usually means that
6517  * the dialog box containing the entry will be closed, since the default
6518  * widget is usually one of the dialog buttons.
6519  *
6520  * (For experts: if @setting is %TRUE, the entry calls
6521  * gtk_window_activate_default() on the window containing the entry, in
6522  * the default handler for the #GtkWidget::activate signal.)
6523  **/
6524 void
6525 gtk_entry_set_activates_default (GtkEntry *entry,
6526                                  gboolean  setting)
6527 {
6528   g_return_if_fail (GTK_IS_ENTRY (entry));
6529   setting = setting != FALSE;
6530
6531   if (setting != entry->activates_default)
6532     {
6533       entry->activates_default = setting;
6534       g_object_notify (G_OBJECT (entry), "activates-default");
6535     }
6536 }
6537
6538 /**
6539  * gtk_entry_get_activates_default:
6540  * @entry: a #GtkEntry
6541  * 
6542  * Retrieves the value set by gtk_entry_set_activates_default().
6543  * 
6544  * Return value: %TRUE if the entry will activate the default widget
6545  **/
6546 gboolean
6547 gtk_entry_get_activates_default (GtkEntry *entry)
6548 {
6549   g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
6550
6551   return entry->activates_default;
6552 }
6553
6554 /**
6555  * gtk_entry_set_width_chars:
6556  * @entry: a #GtkEntry
6557  * @n_chars: width in chars
6558  *
6559  * Changes the size request of the entry to be about the right size
6560  * for @n_chars characters. Note that it changes the size
6561  * <emphasis>request</emphasis>, the size can still be affected by
6562  * how you pack the widget into containers. If @n_chars is -1, the
6563  * size reverts to the default entry size.
6564  **/
6565 void
6566 gtk_entry_set_width_chars (GtkEntry *entry,
6567                            gint      n_chars)
6568 {
6569   g_return_if_fail (GTK_IS_ENTRY (entry));
6570
6571   if (entry->width_chars != n_chars)
6572     {
6573       entry->width_chars = n_chars;
6574       g_object_notify (G_OBJECT (entry), "width-chars");
6575       gtk_widget_queue_resize (GTK_WIDGET (entry));
6576     }
6577 }
6578
6579 /**
6580  * gtk_entry_get_width_chars:
6581  * @entry: a #GtkEntry
6582  * 
6583  * Gets the value set by gtk_entry_set_width_chars().
6584  * 
6585  * Return value: number of chars to request space for, or negative if unset
6586  **/
6587 gint
6588 gtk_entry_get_width_chars (GtkEntry *entry)
6589 {
6590   g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
6591
6592   return entry->width_chars;
6593 }
6594
6595 /**
6596  * gtk_entry_set_has_frame:
6597  * @entry: a #GtkEntry
6598  * @setting: new value
6599  * 
6600  * Sets whether the entry has a beveled frame around it.
6601  **/
6602 void
6603 gtk_entry_set_has_frame (GtkEntry *entry,
6604                          gboolean  setting)
6605 {
6606   g_return_if_fail (GTK_IS_ENTRY (entry));
6607
6608   setting = (setting != FALSE);
6609
6610   if (entry->has_frame == setting)
6611     return;
6612
6613   gtk_widget_queue_resize (GTK_WIDGET (entry));
6614   entry->has_frame = setting;
6615   g_object_notify (G_OBJECT (entry), "has-frame");
6616 }
6617
6618 /**
6619  * gtk_entry_get_has_frame:
6620  * @entry: a #GtkEntry
6621  * 
6622  * Gets the value set by gtk_entry_set_has_frame().
6623  * 
6624  * Return value: whether the entry has a beveled frame
6625  **/
6626 gboolean
6627 gtk_entry_get_has_frame (GtkEntry *entry)
6628 {
6629   g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
6630
6631   return entry->has_frame;
6632 }
6633
6634 /**
6635  * gtk_entry_set_inner_border:
6636  * @entry: a #GtkEntry
6637  * @border: a #GtkBorder, or %NULL
6638  *
6639  * Sets %entry's inner-border property to %border, or clears it if %NULL
6640  * is passed. The inner-border is the area around the entry's text, but
6641  * inside its frame.
6642  *
6643  * If set, this property overrides the inner-border style property.
6644  * Overriding the style-provided border is useful when you want to do
6645  * in-place editing of some text in a canvas or list widget, where
6646  * pixel-exact positioning of the entry is important.
6647  *
6648  * Since: 2.10
6649  **/
6650 void
6651 gtk_entry_set_inner_border (GtkEntry        *entry,
6652                             const GtkBorder *border)
6653 {
6654   g_return_if_fail (GTK_IS_ENTRY (entry));
6655
6656   gtk_widget_queue_resize (GTK_WIDGET (entry));
6657
6658   if (border)
6659     g_object_set_qdata_full (G_OBJECT (entry), quark_inner_border,
6660                              gtk_border_copy (border),
6661                              (GDestroyNotify) gtk_border_free);
6662   else
6663     g_object_set_qdata (G_OBJECT (entry), quark_inner_border, NULL);
6664
6665   g_object_notify (G_OBJECT (entry), "inner-border");
6666 }
6667
6668 /**
6669  * gtk_entry_get_inner_border:
6670  * @entry: a #GtkEntry
6671  *
6672  * This function returns the entry's #GtkEntry:inner-border property. See
6673  * gtk_entry_set_inner_border() for more information.
6674  *
6675  * Return value: the entry's #GtkBorder, or %NULL if none was set.
6676  *
6677  * Since: 2.10
6678  **/
6679 G_CONST_RETURN GtkBorder *
6680 gtk_entry_get_inner_border (GtkEntry *entry)
6681 {
6682   g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
6683
6684   return g_object_get_qdata (G_OBJECT (entry), quark_inner_border);
6685 }
6686
6687 /**
6688  * gtk_entry_get_layout:
6689  * @entry: a #GtkEntry
6690  * 
6691  * Gets the #PangoLayout used to display the entry.
6692  * The layout is useful to e.g. convert text positions to
6693  * pixel positions, in combination with gtk_entry_get_layout_offsets().
6694  * The returned layout is owned by the entry and must not be 
6695  * modified or freed by the caller.
6696  *
6697  * Keep in mind that the layout text may contain a preedit string, so
6698  * gtk_entry_layout_index_to_text_index() and
6699  * gtk_entry_text_index_to_layout_index() are needed to convert byte
6700  * indices in the layout to byte indices in the entry contents.
6701  * 
6702  * Return value: the #PangoLayout for this entry
6703  **/
6704 PangoLayout*
6705 gtk_entry_get_layout (GtkEntry *entry)
6706 {
6707   PangoLayout *layout;
6708   
6709   g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
6710
6711   layout = gtk_entry_ensure_layout (entry, TRUE);
6712
6713   return layout;
6714 }
6715
6716
6717 /**
6718  * gtk_entry_layout_index_to_text_index:
6719  * @entry: a #GtkEntry
6720  * @layout_index: byte index into the entry layout text
6721  * 
6722  * Converts from a position in the entry contents (returned
6723  * by gtk_entry_get_text()) to a position in the
6724  * entry's #PangoLayout (returned by gtk_entry_get_layout(),
6725  * with text retrieved via pango_layout_get_text()).
6726  * 
6727  * Return value: byte index into the entry contents
6728  **/
6729 gint
6730 gtk_entry_layout_index_to_text_index (GtkEntry *entry,
6731                                       gint      layout_index)
6732 {
6733   PangoLayout *layout;
6734   const gchar *text;
6735   gint cursor_index;
6736   
6737   g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
6738
6739   layout = gtk_entry_ensure_layout (entry, TRUE);
6740   text = pango_layout_get_text (layout);
6741   cursor_index = g_utf8_offset_to_pointer (text, entry->current_pos) - text;
6742   
6743   if (layout_index >= cursor_index && entry->preedit_length)
6744     {
6745       if (layout_index >= cursor_index + entry->preedit_length)
6746         layout_index -= entry->preedit_length;
6747       else
6748         layout_index = cursor_index;
6749     }
6750
6751   return layout_index;
6752 }
6753
6754 /**
6755  * gtk_entry_text_index_to_layout_index:
6756  * @entry: a #GtkEntry
6757  * @text_index: byte index into the entry contents
6758  * 
6759  * Converts from a position in the entry's #PangoLayout (returned by
6760  * gtk_entry_get_layout()) to a position in the entry contents
6761  * (returned by gtk_entry_get_text()).
6762  * 
6763  * Return value: byte index into the entry layout text
6764  **/
6765 gint
6766 gtk_entry_text_index_to_layout_index (GtkEntry *entry,
6767                                       gint      text_index)
6768 {
6769   PangoLayout *layout;
6770   const gchar *text;
6771   gint cursor_index;
6772   g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
6773
6774   layout = gtk_entry_ensure_layout (entry, TRUE);
6775   text = pango_layout_get_text (layout);
6776   cursor_index = g_utf8_offset_to_pointer (text, entry->current_pos) - text;
6777   
6778   if (text_index > cursor_index)
6779     text_index += entry->preedit_length;
6780
6781   return text_index;
6782 }
6783
6784 /**
6785  * gtk_entry_get_layout_offsets:
6786  * @entry: a #GtkEntry
6787  * @x: location to store X offset of layout, or %NULL
6788  * @y: location to store Y offset of layout, or %NULL
6789  *
6790  *
6791  * Obtains the position of the #PangoLayout used to render text
6792  * in the entry, in widget coordinates. Useful if you want to line
6793  * up the text in an entry with some other text, e.g. when using the
6794  * entry to implement editable cells in a sheet widget.
6795  *
6796  * Also useful to convert mouse events into coordinates inside the
6797  * #PangoLayout, e.g. to take some action if some part of the entry text
6798  * is clicked.
6799  * 
6800  * Note that as the user scrolls around in the entry the offsets will
6801  * change; you'll need to connect to the "notify::scroll-offset"
6802  * signal to track this. Remember when using the #PangoLayout
6803  * functions you need to convert to and from pixels using
6804  * PANGO_PIXELS() or #PANGO_SCALE.
6805  *
6806  * Keep in mind that the layout text may contain a preedit string, so
6807  * gtk_entry_layout_index_to_text_index() and
6808  * gtk_entry_text_index_to_layout_index() are needed to convert byte
6809  * indices in the layout to byte indices in the entry contents.
6810  **/
6811 void
6812 gtk_entry_get_layout_offsets (GtkEntry *entry,
6813                               gint     *x,
6814                               gint     *y)
6815 {
6816   gint text_area_x, text_area_y;
6817   
6818   g_return_if_fail (GTK_IS_ENTRY (entry));
6819
6820   /* this gets coords relative to text area */
6821   get_layout_position (entry, x, y);
6822
6823   /* convert to widget coords */
6824   gtk_entry_get_text_area_size (entry, &text_area_x, &text_area_y, NULL, NULL);
6825   
6826   if (x)
6827     *x += text_area_x;
6828
6829   if (y)
6830     *y += text_area_y;
6831 }
6832
6833
6834 /**
6835  * gtk_entry_set_alignment:
6836  * @entry: a #GtkEntry
6837  * @xalign: The horizontal alignment, from 0 (left) to 1 (right).
6838  *          Reversed for RTL layouts
6839  * 
6840  * Sets the alignment for the contents of the entry. This controls
6841  * the horizontal positioning of the contents when the displayed
6842  * text is shorter than the width of the entry.
6843  *
6844  * Since: 2.4
6845  **/
6846 void
6847 gtk_entry_set_alignment (GtkEntry *entry, gfloat xalign)
6848 {
6849   GtkEntryPrivate *priv;
6850   
6851   g_return_if_fail (GTK_IS_ENTRY (entry));
6852
6853   priv = GTK_ENTRY_GET_PRIVATE (entry);
6854
6855   if (xalign < 0.0)
6856     xalign = 0.0;
6857   else if (xalign > 1.0)
6858     xalign = 1.0;
6859
6860   if (xalign != priv->xalign)
6861     {
6862       priv->xalign = xalign;
6863
6864       gtk_entry_recompute (entry);
6865
6866       g_object_notify (G_OBJECT (entry), "xalign");
6867     }
6868 }
6869
6870 /**
6871  * gtk_entry_get_alignment:
6872  * @entry: a #GtkEntry
6873  * 
6874  * Gets the value set by gtk_entry_set_alignment().
6875  * 
6876  * Return value: the alignment
6877  *
6878  * Since: 2.4
6879  **/
6880 gfloat
6881 gtk_entry_get_alignment (GtkEntry *entry)
6882 {
6883   GtkEntryPrivate *priv;
6884   
6885   g_return_val_if_fail (GTK_IS_ENTRY (entry), 0.0);
6886
6887   priv = GTK_ENTRY_GET_PRIVATE (entry);
6888
6889   return priv->xalign;
6890 }
6891
6892 /**
6893  * gtk_entry_set_icon_from_pixbuf:
6894  * @entry: a #GtkEntry
6895  * @icon_pos: Icon position
6896  * @pixbuf: A #GdkPixbuf, or %NULL
6897  *
6898  * Sets the icon shown in the specified position using a pixbuf.
6899  *
6900  * If @pixbuf is %NULL, no icon will be shown in the specified position.
6901  *
6902  * Since: 2.16
6903  */
6904 void
6905 gtk_entry_set_icon_from_pixbuf (GtkEntry             *entry,
6906                                 GtkEntryIconPosition  icon_pos,
6907                                 GdkPixbuf            *pixbuf)
6908 {
6909   GtkEntryPrivate *priv;
6910   EntryIconInfo *icon_info;
6911
6912   g_return_if_fail (GTK_IS_ENTRY (entry));
6913   g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
6914
6915   priv = GTK_ENTRY_GET_PRIVATE (entry);
6916
6917   if (!(icon_info = priv->icons[icon_pos]))
6918     icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
6919
6920   g_object_freeze_notify (G_OBJECT (entry));
6921
6922   if (pixbuf)
6923     g_object_ref (pixbuf);
6924
6925   gtk_entry_clear (entry, icon_pos);
6926
6927   if (pixbuf)
6928     {
6929       icon_info->storage_type = GTK_IMAGE_PIXBUF;
6930       icon_info->pixbuf = pixbuf;
6931
6932       if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
6933         {
6934           g_object_notify (G_OBJECT (entry), "pixbuf-primary");
6935           g_object_notify (G_OBJECT (entry), "storage-type-primary");
6936         }
6937       else
6938         {
6939           g_object_notify (G_OBJECT (entry), "pixbuf-secondary");
6940           g_object_notify (G_OBJECT (entry), "storage-type-secondary");
6941         }
6942     }
6943
6944   gtk_entry_ensure_pixbuf (entry, icon_pos);
6945   
6946   g_object_thaw_notify (G_OBJECT (entry));
6947 }
6948
6949 /**
6950  * gtk_entry_set_icon_from_stock:
6951  * @entry: A #GtkEntry
6952  * @icon_pos: Icon position
6953  * @stock_id: The name of the stock item, or %NULL
6954  *
6955  * Sets the icon shown in the entry at the specified position from
6956  * a stock image.
6957  *
6958  * If @stock_id is %NULL, no icon will be shown in the specified position.
6959  *
6960  * Since: 2.16
6961  */
6962 void
6963 gtk_entry_set_icon_from_stock (GtkEntry             *entry,
6964                                GtkEntryIconPosition  icon_pos,
6965                                const gchar          *stock_id)
6966 {
6967   GtkEntryPrivate *priv;
6968   EntryIconInfo *icon_info;
6969   gchar *new_id;
6970
6971   g_return_if_fail (GTK_IS_ENTRY (entry));
6972   g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
6973
6974   priv = GTK_ENTRY_GET_PRIVATE (entry);
6975
6976   if (!(icon_info = priv->icons[icon_pos]))
6977     icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
6978
6979   g_object_freeze_notify (G_OBJECT (entry));
6980
6981   gtk_widget_ensure_style (GTK_WIDGET (entry));
6982
6983   /* need to dup before clearing */
6984   new_id = g_strdup (stock_id);
6985
6986   gtk_entry_clear (entry, icon_pos);
6987
6988   if (new_id != NULL)
6989     {
6990       icon_info->storage_type = GTK_IMAGE_STOCK;
6991       icon_info->stock_id = new_id;
6992
6993       if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
6994         {
6995           g_object_notify (G_OBJECT (entry), "stock-primary");
6996           g_object_notify (G_OBJECT (entry), "storage-type-primary");
6997         }
6998       else
6999         {
7000           g_object_notify (G_OBJECT (entry), "stock-secondary");
7001           g_object_notify (G_OBJECT (entry), "storage-type-secondary");
7002         }
7003     }
7004
7005   gtk_entry_ensure_pixbuf (entry, icon_pos);
7006
7007   g_object_thaw_notify (G_OBJECT (entry));
7008 }
7009
7010 /**
7011  * gtk_entry_set_icon_from_icon_name:
7012  * @entry: A #GtkEntry
7013  * @icon_pos: The position at which to set the icon
7014  * @icon_name: An icon name, or %NULL
7015  *
7016  * Sets the icon shown in the entry at the specified position
7017  * from the current icon theme.
7018  *
7019  * If the icon name isn't known, a "broken image" icon will be displayed
7020  * instead.
7021  *
7022  * If @icon_name is %NULL, no icon will be shown in the specified position.
7023  *
7024  * Since: 2.16
7025  */
7026 void
7027 gtk_entry_set_icon_from_icon_name (GtkEntry             *entry,
7028                                    GtkEntryIconPosition  icon_pos,
7029                                    const gchar          *icon_name)
7030 {
7031   GtkEntryPrivate *priv;
7032   EntryIconInfo *icon_info;
7033   gchar *new_name;
7034
7035   g_return_if_fail (GTK_IS_ENTRY (entry));
7036   g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
7037
7038   priv = GTK_ENTRY_GET_PRIVATE (entry);
7039
7040   if (!(icon_info = priv->icons[icon_pos]))
7041     icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
7042
7043   g_object_freeze_notify (G_OBJECT (entry));
7044
7045   gtk_widget_ensure_style (GTK_WIDGET (entry));
7046
7047   /* need to dup before clearing */
7048   new_name = g_strdup (icon_name);
7049
7050   gtk_entry_clear (entry, icon_pos);
7051
7052   if (new_name != NULL)
7053     {
7054       icon_info->storage_type = GTK_IMAGE_ICON_NAME;
7055       icon_info->icon_name = new_name;
7056
7057       if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
7058         {
7059           g_object_notify (G_OBJECT (entry), "icon-name-primary");
7060           g_object_notify (G_OBJECT (entry), "storage-type-primary");
7061         }
7062       else
7063         {
7064           g_object_notify (G_OBJECT (entry), "icon-name-secondary");
7065           g_object_notify (G_OBJECT (entry), "storage-type-secondary");
7066         }
7067     }
7068
7069   gtk_entry_ensure_pixbuf (entry, icon_pos);
7070
7071   g_object_thaw_notify (G_OBJECT (entry));
7072 }
7073
7074 /**
7075  * gtk_entry_set_icon_from_gicon:
7076  * @entry: A #GtkEntry
7077  * @icon_pos: The position at which to set the icon
7078  * @icon: The icon to set, or %NULL
7079  *
7080  * Sets the icon shown in the entry at the specified position
7081  * from the current icon theme.
7082  * If the icon isn't known, a "broken image" icon will be displayed
7083  * instead.
7084  *
7085  * If @icon is %NULL, no icon will be shown in the specified position.
7086  *
7087  * Since: 2.16
7088  */
7089 void
7090 gtk_entry_set_icon_from_gicon (GtkEntry             *entry,
7091                                GtkEntryIconPosition  icon_pos,
7092                                GIcon                *icon)
7093 {
7094   GtkEntryPrivate *priv;
7095   EntryIconInfo *icon_info;
7096
7097   g_return_if_fail (GTK_IS_ENTRY (entry));
7098   g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
7099
7100   priv = GTK_ENTRY_GET_PRIVATE (entry);
7101
7102   if (!(icon_info = priv->icons[icon_pos]))
7103     icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
7104
7105   g_object_freeze_notify (G_OBJECT (entry));
7106
7107   /* need to ref before clearing */
7108   if (icon)
7109     g_object_ref (icon);
7110
7111   gtk_entry_clear (entry, icon_pos);
7112
7113   if (icon)
7114     {
7115       icon_info->storage_type = GTK_IMAGE_GICON;
7116       icon_info->gicon = icon;
7117
7118       if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
7119         {
7120           g_object_notify (G_OBJECT (entry), "gicon-primary");
7121           g_object_notify (G_OBJECT (entry), "storage-type-primary");
7122         }
7123       else
7124         {
7125           g_object_notify (G_OBJECT (entry), "gicon-secondary");
7126           g_object_notify (G_OBJECT (entry), "storage-type-secondary");
7127         }
7128     }
7129
7130   gtk_entry_ensure_pixbuf (entry, icon_pos);
7131
7132   g_object_thaw_notify (G_OBJECT (entry));
7133 }
7134
7135 /**
7136  * gtk_entry_set_icon_activatable:
7137  * @entry: A #GtkEntry
7138  * @icon_pos: Icon position
7139  * @activatable: %TRUE if the icon should be activatable
7140  *
7141  * Sets whether the icon is activatable.
7142  *
7143  * Since: 2.16
7144  */
7145 void
7146 gtk_entry_set_icon_activatable (GtkEntry             *entry,
7147                                 GtkEntryIconPosition  icon_pos,
7148                                 gboolean              activatable)
7149 {
7150   GtkEntryPrivate *priv;
7151   EntryIconInfo *icon_info;
7152
7153   g_return_if_fail (GTK_IS_ENTRY (entry));
7154   g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
7155
7156   priv = GTK_ENTRY_GET_PRIVATE (entry);
7157
7158   if (!(icon_info = priv->icons[icon_pos]))
7159     icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
7160
7161   activatable = activatable != FALSE;
7162
7163   if (icon_info->nonactivatable != !activatable)
7164     {
7165       icon_info->nonactivatable = !activatable;
7166
7167       if (GTK_WIDGET_REALIZED (GTK_WIDGET (entry)))
7168         update_cursors (GTK_WIDGET (entry));
7169
7170       g_object_notify (G_OBJECT (entry),
7171                        icon_pos == GTK_ENTRY_ICON_PRIMARY ? "activatable-primary" : "activatable-secondary");
7172     }
7173 }
7174
7175 /**
7176  * gtk_entry_get_icon_activtable:
7177  * @entry: a #GtkEntry
7178  * @icon_pos: Icon position
7179  *
7180  * Returns whether the icon is activatable.
7181  *
7182  * Returns: %TRUE if the icon is activatable.
7183  *
7184  * Since: 2.16
7185  */
7186 gboolean
7187 gtk_entry_get_icon_activatable (GtkEntry             *entry,
7188                                 GtkEntryIconPosition  icon_pos)
7189 {
7190   GtkEntryPrivate *priv;
7191   EntryIconInfo *icon_info;
7192
7193   g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
7194   g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), FALSE);
7195
7196   priv = GTK_ENTRY_GET_PRIVATE (entry);
7197   icon_info = priv->icons[icon_pos];
7198
7199   return (icon_info != NULL && !icon_info->nonactivatable);
7200 }
7201
7202 /**
7203  * gtk_entry_get_pixbuf:
7204  * @entry: A #GtkEntry
7205  * @icon_pos: Icon position
7206  *
7207  * Retrieves the image used for the icon.
7208  *
7209  * Unlike the other methods of setting and getting icon data, this
7210  * method will work regardless of whether the icon was set using a
7211  * #GdkPixbuf, a #GIcon, a stock item, or an icon name.
7212  *
7213  * Returns: A #GdkPixbuf, or %NULL if no icon is set for this position.
7214  *
7215  * Since: 2.16
7216  */
7217 GdkPixbuf *
7218 gtk_entry_get_pixbuf (GtkEntry             *entry,
7219                       GtkEntryIconPosition  icon_pos)
7220 {
7221   GtkEntryPrivate *priv;
7222   EntryIconInfo *icon_info;
7223
7224   g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
7225   g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL);
7226
7227   priv = GTK_ENTRY_GET_PRIVATE (entry);
7228   icon_info = priv->icons[icon_pos];
7229
7230   if (!icon_info)
7231     return NULL;
7232
7233   gtk_entry_ensure_pixbuf (entry, icon_pos);
7234
7235   return icon_info->pixbuf;
7236 }
7237
7238 /**
7239  * gtk_entry_get_gicon:
7240  * @entry: A #GtkEntry
7241  * @icon_pos: Icon position
7242  *
7243  * Retrieves the #GIcon used for the icon, or %NULL if there is
7244  * no icon or if the icon was set by some other method (e.g., by
7245  * stock, pixbuf, or icon name).
7246  *
7247  * Returns: A #GIcon, or %NULL if no icon is set or if the icon
7248  *          is not a #GIcon
7249  *
7250  * Since: 2.16
7251  */
7252 GIcon *
7253 gtk_entry_get_gicon (GtkEntry             *entry,
7254                      GtkEntryIconPosition  icon_pos)
7255 {
7256   GtkEntryPrivate *priv;
7257   EntryIconInfo *icon_info;
7258
7259   g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
7260   g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL);
7261
7262   priv = GTK_ENTRY_GET_PRIVATE (entry);
7263   icon_info = priv->icons[icon_pos];
7264
7265   if (!icon_info)
7266     return NULL;
7267
7268   return icon_info->storage_type == GTK_IMAGE_GICON ? icon_info->gicon : NULL;
7269 }
7270
7271 /**
7272  * gtk_entry_get_stock:
7273  * @entry: A #GtkEntry
7274  * @icon_pos: Icon position
7275  *
7276  * Retrieves the stock id used for the icon, or %NULL if there is
7277  * no icon or if the icon was set by some other method (e.g., by
7278  * pixbuf, icon name or gicon).
7279  *
7280  * Returns: A stock id, or %NULL if no icon is set or if the icon
7281  *          wasn't set from a stock id
7282  *
7283  * Since: 2.16
7284  */
7285 const gchar *
7286 gtk_entry_get_stock (GtkEntry             *entry,
7287                      GtkEntryIconPosition  icon_pos)
7288 {
7289   GtkEntryPrivate *priv;
7290   EntryIconInfo *icon_info;
7291
7292   g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
7293   g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL);
7294
7295   priv = GTK_ENTRY_GET_PRIVATE (entry);
7296   icon_info = priv->icons[icon_pos];
7297
7298   if (!icon_info)
7299     return NULL;
7300
7301   return icon_info->storage_type == GTK_IMAGE_STOCK ? icon_info->stock_id : NULL;
7302 }
7303
7304 /**
7305  * gtk_entry_get_icon_name:
7306  * @entry: A #GtkEntry
7307  * @icon_pos: Icon position
7308  *
7309  * Retrieves the icon name used for the icon, or %NULL if there is
7310  * no icon or if the icon was set by some other method (e.g., by
7311  * pixbuf, stock or gicon).
7312  *
7313  * Returns: An icon name, or %NULL if no icon is set or if the icon
7314  *          wasn't set from an icon name
7315  *
7316  * Since: 2.16
7317  */
7318 const gchar *
7319 gtk_entry_get_icon_name (GtkEntry             *entry,
7320                          GtkEntryIconPosition  icon_pos)
7321 {
7322   GtkEntryPrivate *priv;
7323   EntryIconInfo *icon_info;
7324
7325   g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
7326   g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL);
7327
7328   priv = GTK_ENTRY_GET_PRIVATE (entry);
7329   icon_info = priv->icons[icon_pos];
7330
7331   if (!icon_info)
7332     return NULL;
7333
7334   return icon_info->storage_type == GTK_IMAGE_ICON_NAME ? icon_info->icon_name : NULL;
7335 }
7336
7337 /**
7338  * gtk_entry_set_icon_sensitive:
7339  * @entry: A #GtkEntry
7340  * @icon_pos: Icon position
7341  * @sensitive: Specifies whether the icon should appear
7342  *             sensitive or insensitive
7343  *
7344  * Sets the sensitivity for the specified icon.
7345  *
7346  * Since: 2.16
7347  */
7348 void
7349 gtk_entry_set_icon_sensitive (GtkEntry             *entry,
7350                               GtkEntryIconPosition  icon_pos,
7351                               gboolean              sensitive)
7352 {
7353   GtkEntryPrivate *priv;
7354   EntryIconInfo *icon_info;
7355
7356   g_return_if_fail (GTK_IS_ENTRY (entry));
7357   g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
7358
7359   priv = GTK_ENTRY_GET_PRIVATE (entry);
7360
7361   if (!(icon_info = priv->icons[icon_pos]))
7362     icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
7363
7364   if (icon_info->insensitive != !sensitive)
7365     {
7366       icon_info->insensitive = !sensitive;
7367
7368       if (GTK_WIDGET_REALIZED (GTK_WIDGET (entry)))
7369         update_cursors (GTK_WIDGET (entry));
7370
7371       g_object_notify (G_OBJECT (entry),
7372                        icon_pos == GTK_ENTRY_ICON_PRIMARY ? "sensitive-primary" : "sensitive-secondary");
7373     }
7374 }
7375
7376 /**
7377  * gtk_entry_get_icon_sensitive:
7378  * @entry: a #GtkEntry
7379  * @icon_pos: Icon position
7380  *
7381  * Returns whether the icon appears sensitive or insensitive.
7382  *
7383  * Returns: %TRUE if the icon is sensitive.
7384  *
7385  * Since: 2.16
7386  */
7387 gboolean
7388 gtk_entry_get_icon_sensitive (GtkEntry             *entry,
7389                               GtkEntryIconPosition  icon_pos)
7390 {
7391   GtkEntryPrivate *priv;
7392   EntryIconInfo *icon_info;
7393
7394   g_return_val_if_fail (GTK_IS_ENTRY (entry), TRUE);
7395   g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), TRUE);
7396
7397   priv = GTK_ENTRY_GET_PRIVATE (entry);
7398   icon_info = priv->icons[icon_pos];
7399
7400   return (icon_info != NULL && !icon_info->insensitive);
7401 }
7402
7403 /**
7404  * gtk_entry_get_storage_type:
7405  * @image: a #GtkImage
7406  *
7407  * Gets the type of representation being used by the icon
7408  * to store image data. If the icon has no image data,
7409  * the return value will be %GTK_IMAGE_EMPTY.
7410  *
7411  * Return value: image representation being used
7412  *
7413  * Since: 2.16
7414  **/
7415 GtkImageType
7416 gtk_entry_get_storage_type (GtkEntry             *entry,
7417                             GtkEntryIconPosition  icon_pos)
7418 {
7419   GtkEntryPrivate *priv;
7420   EntryIconInfo *icon_info;
7421
7422   g_return_val_if_fail (GTK_IS_ENTRY (entry), GTK_IMAGE_EMPTY);
7423   g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), GTK_IMAGE_EMPTY);
7424
7425   priv = GTK_ENTRY_GET_PRIVATE (entry);
7426   icon_info = priv->icons[icon_pos];
7427
7428   if (!icon_info)
7429     return GTK_IMAGE_EMPTY;
7430
7431   return icon_info->storage_type;
7432 }
7433
7434 /**
7435  * gtk_entry_get_icon_at_pos:
7436  * @entry: a #GtkEntry
7437  * @x: the x coordinate of the position to find
7438  * @y: the y coordinate of the position to find
7439  *
7440  * Finds the icon at the given position and return its index.
7441  * If @x, @y doesn't lie inside an icon, -1 is returned.
7442  * This function is intended for use in a #GtkWidget::query-tooltip
7443  * signal handler.
7444  *
7445  * Returns: the index of the icon at the given position, or -1
7446  *
7447  * Since: 2.16
7448  */
7449 gint
7450 gtk_entry_get_icon_at_pos (GtkEntry *entry,
7451                                 gint          x,
7452                                 gint          y)
7453 {
7454   GtkEntryPrivate *priv;
7455   GtkEntryIconPosition left_icon_pos;
7456   GtkEntryIconPosition right_icon_pos;
7457   GtkAllocation left_icon_alloc;
7458   GtkAllocation right_icon_alloc;
7459   GtkAllocation text_area_alloc;
7460   GtkAllocation *widget_alloc;
7461
7462   g_return_val_if_fail (GTK_IS_ENTRY (entry), -1);
7463
7464   priv = GTK_ENTRY_GET_PRIVATE (entry);
7465
7466   widget_alloc = &GTK_WIDGET (entry)->allocation;
7467
7468   get_text_area_size (entry, &text_area_alloc);
7469   get_icon_allocation (entry, TRUE, widget_alloc, &text_area_alloc,
7470                        &left_icon_alloc, &left_icon_pos);
7471   get_icon_allocation (entry, FALSE, widget_alloc, &text_area_alloc,
7472                        &right_icon_alloc, &right_icon_pos);
7473
7474   if (left_icon_alloc.width > 0)
7475     text_area_alloc.x = left_icon_alloc.x + left_icon_alloc.width + priv->icon_margin;
7476
7477   if (right_icon_alloc.width > 0)
7478     text_area_alloc.width -= right_icon_alloc.width + priv->icon_margin;
7479
7480   text_area_alloc.width -= text_area_alloc.x;
7481
7482   if (left_icon_alloc.x <= x &&
7483       left_icon_alloc.y <= y &&
7484       x < left_icon_alloc.x + left_icon_alloc.width &&
7485       y < left_icon_alloc.y + left_icon_alloc.height)
7486     return left_icon_pos;
7487
7488   if (right_icon_alloc.x <= x &&
7489       right_icon_alloc.y <= y &&
7490       x < right_icon_alloc.x + right_icon_alloc.width &&
7491       y < right_icon_alloc.y + right_icon_alloc.height)
7492     return right_icon_pos;
7493
7494   return -1;
7495 }
7496
7497 /**
7498  * gtk_entry_set_icon_drag_source:
7499  * @entry: a #GtkIconEntry
7500  * @icon_pos: icon position
7501  * @target_list: the targets (data formats) in which the data can be provided
7502  * @actions: a bitmask of the allowed drag actions
7503  *
7504  * Sets up the icon at the given position so that GTK+ will start a drag
7505  * operation when the user clicks and drags the icon.
7506  *
7507  * To handle the drag operation, you need to connect to the usual
7508  * #GtkWidget::drag-data-get (or possibly #GtkWidget::drag-data-delete)
7509  * signal, and use gtk_icon_entry_get_current_icon_drag_source() in
7510  * your signal handler to find out if the drag was started from
7511  * an icon.
7512  */
7513 void
7514 gtk_entry_set_icon_drag_source (GtkEntry             *entry,
7515                                 GtkEntryIconPosition  icon_pos,
7516                                 GtkTargetList        *target_list,
7517                                 GdkDragAction         actions)
7518 {
7519   GtkEntryPrivate *priv;
7520   EntryIconInfo *icon_info;
7521
7522   g_return_if_fail (GTK_IS_ENTRY (entry));
7523   g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
7524
7525   priv = GTK_ENTRY_GET_PRIVATE (entry);
7526
7527   if (!(icon_info = priv->icons[icon_pos]))
7528     icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
7529
7530   if (icon_info->target_list)
7531     gtk_target_list_unref (icon_info->target_list);
7532   icon_info->target_list = target_list;
7533   if (icon_info->target_list)
7534     gtk_target_list_ref (icon_info->target_list);
7535
7536   icon_info->actions = actions;
7537 }
7538
7539 /**
7540  * gtk_entry_get_current_icon_drag_source:
7541  * @entry: a #GtkIconEntry
7542  *
7543  * Returns the index of the icon which is the source of the current
7544  * DND operation, or -1.
7545  *
7546  * This function is meant to be used in a #GtkWidget::drag-data-get
7547  * callback.
7548  *
7549  * Returns: index of the icon which is the source of the current
7550  *          DND operation, or -1.
7551  */
7552 gint
7553 gtk_entry_get_current_icon_drag_source (GtkEntry *entry)
7554 {
7555   GtkEntryPrivate *priv;
7556   EntryIconInfo *icon_info = NULL;
7557   gint i;
7558
7559   g_return_val_if_fail (GTK_IS_ENTRY (entry), -1);
7560
7561   priv = GTK_ENTRY_GET_PRIVATE (entry);
7562
7563   for (i = 0; i < MAX_ICONS; i++)
7564     {
7565       if ((icon_info = priv->icons[i]))
7566         {
7567           if (icon_info->in_drag)
7568             return i;
7569         }
7570     }
7571
7572   return -1;
7573 }
7574
7575 static void
7576 ensure_has_tooltip (GtkEntry *entry)
7577 {
7578   GtkEntryPrivate *priv;
7579   EntryIconInfo *icon_info;
7580   int i;
7581   gboolean has_tooltip = FALSE;
7582
7583   priv = GTK_ENTRY_GET_PRIVATE (entry);
7584
7585   for (i = 0; i < MAX_ICONS; i++)
7586     {
7587       if ((icon_info = priv->icons[i]) != NULL)
7588         {
7589           if (icon_info->tooltip != NULL)
7590             {
7591               has_tooltip = TRUE;
7592               break;
7593             }
7594         }
7595     }
7596
7597   gtk_widget_set_has_tooltip (GTK_WIDGET (entry), has_tooltip);
7598 }
7599
7600 /**
7601  * gtk_entry_set_icon_tooltip_text:
7602  * @entry: a #GtkEntry
7603  * @icon_pos: the icon position
7604  * @tooltip: the contents of the tooltip for the icon, or %NULL
7605  *
7606  * Sets @tooltip as the contents of the tooltip for the icon
7607  * at the specified position.
7608  *
7609  * Use %NULL for @tooltip to remove an existing tooltip.
7610  *
7611  * See also gtk_widget_set_tooltip_text() and 
7612  * gtk_entry_set_icon_tooltip_markup().
7613  *
7614  * Since: 2.16
7615  */
7616 void
7617 gtk_entry_set_icon_tooltip_text (GtkEntry             *entry,
7618                                  GtkEntryIconPosition  icon_pos,
7619                                  const gchar          *tooltip)
7620 {
7621   GtkEntryPrivate *priv;
7622   EntryIconInfo *icon_info;
7623
7624   g_return_if_fail (GTK_IS_ENTRY (entry));
7625   g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
7626
7627   priv = GTK_ENTRY_GET_PRIVATE (entry);
7628
7629   if (!(icon_info = priv->icons[icon_pos]))
7630     icon_info = priv->icons[icon_pos];
7631
7632   if (icon_info->tooltip)
7633     g_free (icon_info->tooltip);
7634
7635   icon_info->tooltip = tooltip ? g_markup_escape_text (tooltip, -1) : NULL;
7636
7637   ensure_has_tooltip (entry);
7638 }
7639
7640 /**
7641  * gtk_entry_set_icon_tooltip_markup:
7642  * @entry: a #GtkEntry
7643  * @icon_pos: the icon position
7644  * @tooltip: the contents of the tooltip for the icon, or %NULL
7645  *
7646  * Sets @tooltip as the contents of the tooltip for the icon at
7647  * the specified position. @tooltip is assumed to be marked up with
7648  * the <link linkend="PangoMarkupFormat">Pango text markup language</link>.
7649  *
7650  * Use %NULL for @tooltip to remove an existing tooltip.
7651  *
7652  * See also gtk_widget_set_tooltip_markup() and 
7653  * gtk_enty_set_icon_tooltip_text().
7654  *
7655  * Since: 2.16
7656  */
7657 void
7658 gtk_entry_set_icon_tooltip_markup (GtkEntry             *entry,
7659                                    GtkEntryIconPosition  icon_pos,
7660                                    const gchar          *tooltip)
7661 {
7662   GtkEntryPrivate *priv;
7663   EntryIconInfo *icon_info;
7664
7665   g_return_if_fail (GTK_IS_ENTRY (entry));
7666   g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
7667
7668   priv = GTK_ENTRY_GET_PRIVATE (entry);
7669
7670   if (!(icon_info = priv->icons[icon_pos]))
7671     icon_info = priv->icons[icon_pos];
7672
7673   if (icon_info->tooltip)
7674     g_free (icon_info->tooltip);
7675
7676   icon_info->tooltip = g_strdup (tooltip);
7677
7678   ensure_has_tooltip (entry);
7679 }
7680
7681 static gboolean
7682 gtk_entry_query_tooltip (GtkWidget  *widget,
7683                          gint        x,
7684                          gint        y,
7685                          gboolean    keyboard_tip,
7686                          GtkTooltip *tooltip)
7687 {
7688   GtkEntry *entry;
7689   GtkEntryPrivate *priv;
7690   EntryIconInfo *icon_info;
7691   gint icon_pos;
7692
7693   entry = GTK_ENTRY (widget);
7694   priv = GTK_ENTRY_GET_PRIVATE (entry);
7695
7696   if (!keyboard_tip)
7697     {
7698       icon_pos = gtk_entry_get_icon_at_pos (entry, x, y);
7699       if (icon_pos != -1)
7700         {
7701           if ((icon_info = priv->icons[icon_pos]) != NULL)
7702             {
7703               if (icon_info->tooltip)
7704                 {
7705                   gtk_tooltip_set_markup (tooltip, icon_info->tooltip);
7706                   return TRUE;
7707                 }
7708
7709               return FALSE;
7710             }
7711         }
7712     }
7713
7714   return GTK_WIDGET_CLASS (gtk_entry_parent_class)->query_tooltip (widget,
7715                                                                    x, y,
7716                                                                    keyboard_tip,
7717                                                                    tooltip);
7718 }
7719
7720
7721 /* Quick hack of a popup menu
7722  */
7723 static void
7724 activate_cb (GtkWidget *menuitem,
7725              GtkEntry  *entry)
7726 {
7727   const gchar *signal = g_object_get_data (G_OBJECT (menuitem), "gtk-signal");
7728   g_signal_emit_by_name (entry, signal);
7729 }
7730
7731
7732 static gboolean
7733 gtk_entry_mnemonic_activate (GtkWidget *widget,
7734                              gboolean   group_cycling)
7735 {
7736   gtk_widget_grab_focus (widget);
7737   return TRUE;
7738 }
7739
7740 static void
7741 append_action_signal (GtkEntry     *entry,
7742                       GtkWidget    *menu,
7743                       const gchar  *stock_id,
7744                       const gchar  *signal,
7745                       gboolean      sensitive)
7746 {
7747   GtkWidget *menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL);
7748
7749   g_object_set_data (G_OBJECT (menuitem), I_("gtk-signal"), (char *)signal);
7750   g_signal_connect (menuitem, "activate",
7751                     G_CALLBACK (activate_cb), entry);
7752
7753   gtk_widget_set_sensitive (menuitem, sensitive);
7754   
7755   gtk_widget_show (menuitem);
7756   gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
7757 }
7758         
7759 static void
7760 popup_menu_detach (GtkWidget *attach_widget,
7761                    GtkMenu   *menu)
7762 {
7763   GTK_ENTRY (attach_widget)->popup_menu = NULL;
7764 }
7765
7766 static void
7767 popup_position_func (GtkMenu   *menu,
7768                      gint      *x,
7769                      gint      *y,
7770                      gboolean  *push_in,
7771                      gpointer   user_data)
7772 {
7773   GtkEntry *entry = GTK_ENTRY (user_data);
7774   GtkWidget *widget = GTK_WIDGET (entry);
7775   GdkScreen *screen;
7776   GtkRequisition menu_req;
7777   GdkRectangle monitor;
7778   GtkBorder inner_border;
7779   gint monitor_num, strong_x, height;
7780  
7781   g_return_if_fail (GTK_WIDGET_REALIZED (entry));
7782
7783   gdk_window_get_origin (entry->text_area, x, y);
7784
7785   screen = gtk_widget_get_screen (widget);
7786   monitor_num = gdk_screen_get_monitor_at_window (screen, entry->text_area);
7787   if (monitor_num < 0)
7788     monitor_num = 0;
7789   gtk_menu_set_monitor (menu, monitor_num);
7790
7791   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
7792   gtk_widget_size_request (entry->popup_menu, &menu_req);
7793   gdk_drawable_get_size (entry->text_area, NULL, &height);
7794   gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, NULL);
7795   _gtk_entry_effective_inner_border (entry, &inner_border);
7796
7797   *x += inner_border.left + strong_x - entry->scroll_offset;
7798   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
7799     *x -= menu_req.width;
7800
7801   if ((*y + height + menu_req.height) <= monitor.y + monitor.height)
7802     *y += height;
7803   else if ((*y - menu_req.height) >= monitor.y)
7804     *y -= menu_req.height;
7805   else if (monitor.y + monitor.height - (*y + height) > *y)
7806     *y += height;
7807   else
7808     *y -= menu_req.height;
7809
7810   *push_in = FALSE;
7811 }
7812
7813 static void
7814 unichar_chosen_func (const char *text,
7815                      gpointer    data)
7816 {
7817   GtkEntry *entry = GTK_ENTRY (data);
7818
7819   if (entry->editable)
7820     gtk_entry_enter_text (entry, text);
7821 }
7822
7823 typedef struct
7824 {
7825   GtkEntry *entry;
7826   gint button;
7827   guint time;
7828 } PopupInfo;
7829
7830 static void
7831 popup_targets_received (GtkClipboard     *clipboard,
7832                         GtkSelectionData *data,
7833                         gpointer          user_data)
7834 {
7835   PopupInfo *info = user_data;
7836   GtkEntry *entry = info->entry;
7837   
7838   if (GTK_WIDGET_REALIZED (entry))
7839     {
7840       gboolean clipboard_contains_text;
7841       GtkWidget *menuitem;
7842       GtkWidget *submenu;
7843       gboolean show_input_method_menu;
7844       gboolean show_unicode_menu;
7845       
7846       clipboard_contains_text = gtk_selection_data_targets_include_text (data);
7847       if (entry->popup_menu)
7848         gtk_widget_destroy (entry->popup_menu);
7849       
7850       entry->popup_menu = gtk_menu_new ();
7851       
7852       gtk_menu_attach_to_widget (GTK_MENU (entry->popup_menu),
7853                                  GTK_WIDGET (entry),
7854                                  popup_menu_detach);
7855       
7856       append_action_signal (entry, entry->popup_menu, GTK_STOCK_CUT, "cut-clipboard",
7857                             entry->editable && entry->visible && entry->current_pos != entry->selection_bound);
7858       append_action_signal (entry, entry->popup_menu, GTK_STOCK_COPY, "copy-clipboard",
7859                             entry->visible && entry->current_pos != entry->selection_bound);
7860       append_action_signal (entry, entry->popup_menu, GTK_STOCK_PASTE, "paste-clipboard",
7861                             entry->editable && clipboard_contains_text);
7862       
7863       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_DELETE, NULL);
7864       gtk_widget_set_sensitive (menuitem, entry->editable && entry->current_pos != entry->selection_bound);
7865       g_signal_connect_swapped (menuitem, "activate",
7866                                 G_CALLBACK (gtk_entry_delete_cb), entry);
7867       gtk_widget_show (menuitem);
7868       gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);
7869
7870       menuitem = gtk_separator_menu_item_new ();
7871       gtk_widget_show (menuitem);
7872       gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);
7873       
7874       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SELECT_ALL, NULL);
7875       g_signal_connect_swapped (menuitem, "activate",
7876                                 G_CALLBACK (gtk_entry_select_all), entry);
7877       gtk_widget_show (menuitem);
7878       gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);
7879       
7880       g_object_get (gtk_widget_get_settings (GTK_WIDGET (entry)),
7881                     "gtk-show-input-method-menu", &show_input_method_menu,
7882                     "gtk-show-unicode-menu", &show_unicode_menu,
7883                     NULL);
7884
7885       if (show_input_method_menu || show_unicode_menu)
7886         {
7887           menuitem = gtk_separator_menu_item_new ();
7888           gtk_widget_show (menuitem);
7889           gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);
7890         }
7891       
7892       if (show_input_method_menu)
7893         {
7894           menuitem = gtk_menu_item_new_with_mnemonic (_("Input _Methods"));
7895           gtk_widget_set_sensitive (menuitem, entry->editable);      
7896           gtk_widget_show (menuitem);
7897           submenu = gtk_menu_new ();
7898           gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
7899           
7900           gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);
7901       
7902           gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (entry->im_context),
7903                                                 GTK_MENU_SHELL (submenu));
7904         }
7905       
7906       if (show_unicode_menu)
7907         {
7908           menuitem = gtk_menu_item_new_with_mnemonic (_("_Insert Unicode Control Character"));
7909           gtk_widget_set_sensitive (menuitem, entry->editable);      
7910           gtk_widget_show (menuitem);
7911           
7912           submenu = gtk_menu_new ();
7913           gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu);
7914           gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);      
7915           
7916           _gtk_text_util_append_special_char_menuitems (GTK_MENU_SHELL (submenu),
7917                                                         unichar_chosen_func,
7918                                                         entry);
7919         }
7920       
7921       g_signal_emit (entry,
7922                      signals[POPULATE_POPUP],
7923                      0,
7924                      entry->popup_menu);
7925   
7926
7927       if (info->button)
7928         gtk_menu_popup (GTK_MENU (entry->popup_menu), NULL, NULL,
7929                         NULL, NULL,
7930                         info->button, info->time);
7931       else
7932         {
7933           gtk_menu_popup (GTK_MENU (entry->popup_menu), NULL, NULL,
7934                           popup_position_func, entry,
7935                           info->button, info->time);
7936           gtk_menu_shell_select_first (GTK_MENU_SHELL (entry->popup_menu), FALSE);
7937         }
7938     }
7939
7940   g_object_unref (entry);
7941   g_slice_free (PopupInfo, info);
7942 }
7943                         
7944 static void
7945 gtk_entry_do_popup (GtkEntry       *entry,
7946                     GdkEventButton *event)
7947 {
7948   PopupInfo *info = g_slice_new (PopupInfo);
7949
7950   /* In order to know what entries we should make sensitive, we
7951    * ask for the current targets of the clipboard, and when
7952    * we get them, then we actually pop up the menu.
7953    */
7954   info->entry = g_object_ref (entry);
7955   
7956   if (event)
7957     {
7958       info->button = event->button;
7959       info->time = event->time;
7960     }
7961   else
7962     {
7963       info->button = 0;
7964       info->time = gtk_get_current_event_time ();
7965     }
7966
7967   gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (entry), GDK_SELECTION_CLIPBOARD),
7968                                   gdk_atom_intern_static_string ("TARGETS"),
7969                                   popup_targets_received,
7970                                   info);
7971 }
7972
7973 static gboolean
7974 gtk_entry_popup_menu (GtkWidget *widget)
7975 {
7976   gtk_entry_do_popup (GTK_ENTRY (widget), NULL);
7977   return TRUE;
7978 }
7979
7980 static void
7981 gtk_entry_drag_begin (GtkWidget      *widget,
7982                       GdkDragContext *context)
7983 {
7984   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
7985   EntryIconInfo *icon_info;
7986   gint i;
7987
7988   for (i = 0; i < MAX_ICONS; i++)
7989     {
7990       if ((icon_info = priv->icons[i]) != NULL)
7991         {
7992           if (icon_info->in_drag) 
7993             {
7994               switch (icon_info->storage_type)
7995                 {
7996                 case GTK_IMAGE_STOCK:
7997                   gtk_drag_set_icon_stock (context, icon_info->stock_id, -2, -2);
7998                   break;
7999
8000                 case GTK_IMAGE_ICON_NAME:
8001                   gtk_drag_set_icon_name (context, icon_info->icon_name, -2, -2);
8002                   break;
8003
8004                   /* FIXME: No GIcon support for dnd icons */
8005                 case GTK_IMAGE_GICON:
8006                 case GTK_IMAGE_PIXBUF:
8007                   gtk_drag_set_icon_pixbuf (context, icon_info->pixbuf, -2, -2);
8008                   break;
8009                 default:
8010                   g_assert_not_reached ();
8011                 }
8012             }
8013         }
8014     }
8015 }
8016
8017 static void
8018 gtk_entry_drag_end (GtkWidget      *widget,
8019                     GdkDragContext *context)
8020 {
8021   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
8022   gint i;
8023
8024   for (i = 0; i < MAX_ICONS; i++)
8025     {
8026       EntryIconInfo *icon_info;
8027
8028       if ((icon_info = priv->icons[i]) != NULL)
8029         icon_info->in_drag = 0;
8030     }
8031 }
8032
8033 static void
8034 gtk_entry_drag_leave (GtkWidget        *widget,
8035                       GdkDragContext   *context,
8036                       guint             time)
8037 {
8038   GtkEntry *entry = GTK_ENTRY (widget);
8039
8040   entry->dnd_position = -1;
8041   gtk_widget_queue_draw (widget);
8042 }
8043
8044 static gboolean
8045 gtk_entry_drag_drop  (GtkWidget        *widget,
8046                       GdkDragContext   *context,
8047                       gint              x,
8048                       gint              y,
8049                       guint             time)
8050 {
8051   GtkEntry *entry = GTK_ENTRY (widget);
8052   GdkAtom target = GDK_NONE;
8053   
8054   if (entry->editable)
8055     target = gtk_drag_dest_find_target (widget, context, NULL);
8056
8057   if (target != GDK_NONE)
8058     gtk_drag_get_data (widget, context, target, time);
8059   else
8060     gtk_drag_finish (context, FALSE, FALSE, time);
8061   
8062   return TRUE;
8063 }
8064
8065 static gboolean
8066 gtk_entry_drag_motion (GtkWidget        *widget,
8067                        GdkDragContext   *context,
8068                        gint              x,
8069                        gint              y,
8070                        guint             time)
8071 {
8072   GtkEntry *entry = GTK_ENTRY (widget);
8073   GtkWidget *source_widget;
8074   GdkDragAction suggested_action;
8075   gint new_position, old_position;
8076   gint sel1, sel2;
8077   
8078   x -= widget->style->xthickness;
8079   y -= widget->style->ythickness;
8080   
8081   old_position = entry->dnd_position;
8082   new_position = gtk_entry_find_position (entry, x + entry->scroll_offset);
8083
8084   if (entry->editable &&
8085       gtk_drag_dest_find_target (widget, context, NULL) != GDK_NONE)
8086     {
8087       source_widget = gtk_drag_get_source_widget (context);
8088       suggested_action = context->suggested_action;
8089
8090       if (!gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &sel1, &sel2) ||
8091           new_position < sel1 || new_position > sel2)
8092         {
8093           if (source_widget == widget)
8094             {
8095               /* Default to MOVE, unless the user has
8096                * pressed ctrl or alt to affect available actions
8097                */
8098               if ((context->actions & GDK_ACTION_MOVE) != 0)
8099                 suggested_action = GDK_ACTION_MOVE;
8100             }
8101               
8102           entry->dnd_position = new_position;
8103         }
8104       else
8105         {
8106           if (source_widget == widget)
8107             suggested_action = 0;       /* Can't drop in selection where drag started */
8108           
8109           entry->dnd_position = -1;
8110         }
8111     }
8112   else
8113     {
8114       /* Entry not editable, or no text */
8115       suggested_action = 0;
8116       entry->dnd_position = -1;
8117     }
8118   
8119   gdk_drag_status (context, suggested_action, time);
8120   
8121   if (entry->dnd_position != old_position)
8122     gtk_widget_queue_draw (widget);
8123
8124   return TRUE;
8125 }
8126
8127 static void
8128 gtk_entry_drag_data_received (GtkWidget        *widget,
8129                               GdkDragContext   *context,
8130                               gint              x,
8131                               gint              y,
8132                               GtkSelectionData *selection_data,
8133                               guint             info,
8134                               guint             time)
8135 {
8136   GtkEntry *entry = GTK_ENTRY (widget);
8137   GtkEditable *editable = GTK_EDITABLE (widget);
8138   gchar *str;
8139
8140   str = (gchar *) gtk_selection_data_get_text (selection_data);
8141
8142   x -= widget->style->xthickness;
8143   y -= widget->style->ythickness;
8144
8145   if (str && entry->editable)
8146     {
8147       gint new_position;
8148       gint sel1, sel2;
8149       gint length = -1;
8150
8151       if (entry->truncate_multiline)
8152         length = truncate_multiline (str);
8153
8154       new_position = gtk_entry_find_position (entry, x + entry->scroll_offset);
8155
8156       if (!gtk_editable_get_selection_bounds (editable, &sel1, &sel2) ||
8157           new_position < sel1 || new_position > sel2)
8158         {
8159           gtk_editable_insert_text (editable, str, length, &new_position);
8160         }
8161       else
8162         {
8163           /* Replacing selection */
8164           begin_change (entry);
8165           g_object_freeze_notify (G_OBJECT (entry));
8166           gtk_editable_delete_text (editable, sel1, sel2);
8167           gtk_editable_insert_text (editable, str, length, &sel1);
8168           g_object_thaw_notify (G_OBJECT (entry));
8169           end_change (entry);
8170         }
8171       
8172       gtk_drag_finish (context, TRUE, context->action == GDK_ACTION_MOVE, time);
8173     }
8174   else
8175     {
8176       /* Drag and drop didn't happen! */
8177       gtk_drag_finish (context, FALSE, FALSE, time);
8178     }
8179
8180   g_free (str);
8181 }
8182
8183 static void
8184 gtk_entry_drag_data_get (GtkWidget        *widget,
8185                          GdkDragContext   *context,
8186                          GtkSelectionData *selection_data,
8187                          guint             info,
8188                          guint             time)
8189 {
8190   gint sel_start, sel_end;
8191   gint i;
8192
8193   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
8194   GtkEditable *editable = GTK_EDITABLE (widget);
8195   EntryIconInfo *icon_info = NULL;
8196
8197   /* If there is an icon drag going on, exit early. */
8198   for (i = 0; i < MAX_ICONS; i++)
8199     {
8200       if ((icon_info = priv->icons[i]) != NULL)
8201         {
8202           if (icon_info->in_drag)
8203             return;
8204         }
8205     }
8206
8207   if (gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end))
8208     {
8209       gchar *str = gtk_entry_get_public_chars (GTK_ENTRY (widget), sel_start, sel_end);
8210
8211       gtk_selection_data_set_text (selection_data, str, -1);
8212       
8213       g_free (str);
8214     }
8215
8216 }
8217
8218 static void
8219 gtk_entry_drag_data_delete (GtkWidget      *widget,
8220                             GdkDragContext *context)
8221 {
8222   gint sel_start, sel_end;
8223   gint i;
8224
8225   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (widget);
8226   GtkEditable *editable = GTK_EDITABLE (widget);
8227   EntryIconInfo *icon_info = NULL;
8228
8229   /* If there is an icon drag going on, exit early. */
8230   for (i = 0; i < MAX_ICONS; i++)
8231     {
8232       if ((icon_info = priv->icons[i]) != NULL)
8233         {
8234           if (icon_info->in_drag)
8235             return;
8236         }
8237     }
8238   
8239   if (GTK_ENTRY (widget)->editable &&
8240       gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end))
8241     gtk_editable_delete_text (editable, sel_start, sel_end);
8242 }
8243
8244 /* We display the cursor when
8245  *
8246  *  - the selection is empty, AND
8247  *  - the widget has focus
8248  */
8249
8250 #define CURSOR_ON_MULTIPLIER 2
8251 #define CURSOR_OFF_MULTIPLIER 1
8252 #define CURSOR_PEND_MULTIPLIER 3
8253 #define CURSOR_DIVIDER 3
8254
8255 static gboolean
8256 cursor_blinks (GtkEntry *entry)
8257 {
8258   if (GTK_WIDGET_HAS_FOCUS (entry) &&
8259       entry->editable &&
8260       entry->selection_bound == entry->current_pos)
8261     {
8262       GtkSettings *settings;
8263       gboolean blink;
8264
8265       settings = gtk_widget_get_settings (GTK_WIDGET (entry));
8266       g_object_get (settings, "gtk-cursor-blink", &blink, NULL);
8267
8268       return blink;
8269     }
8270   else
8271     return FALSE;
8272 }
8273
8274 static gint
8275 get_cursor_time (GtkEntry *entry)
8276 {
8277   GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (entry));
8278   gint time;
8279
8280   g_object_get (settings, "gtk-cursor-blink-time", &time, NULL);
8281
8282   return time;
8283 }
8284
8285 static gint
8286 get_cursor_blink_timeout (GtkEntry *entry)
8287 {
8288   GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (entry));
8289   gint timeout;
8290
8291   g_object_get (settings, "gtk-cursor-blink-timeout", &timeout, NULL);
8292
8293   return timeout;
8294 }
8295
8296 static void
8297 show_cursor (GtkEntry *entry)
8298 {
8299   if (!entry->cursor_visible)
8300     {
8301       entry->cursor_visible = TRUE;
8302
8303       if (GTK_WIDGET_HAS_FOCUS (entry) && entry->selection_bound == entry->current_pos)
8304         gtk_widget_queue_draw (GTK_WIDGET (entry));
8305     }
8306 }
8307
8308 static void
8309 hide_cursor (GtkEntry *entry)
8310 {
8311   if (entry->cursor_visible)
8312     {
8313       entry->cursor_visible = FALSE;
8314
8315       if (GTK_WIDGET_HAS_FOCUS (entry) && entry->selection_bound == entry->current_pos)
8316         gtk_widget_queue_draw (GTK_WIDGET (entry));
8317     }
8318 }
8319
8320 /*
8321  * Blink!
8322  */
8323 static gint
8324 blink_cb (gpointer data)
8325 {
8326   GtkEntry *entry;
8327   GtkEntryPrivate *priv; 
8328   gint blink_timeout;
8329
8330   entry = GTK_ENTRY (data);
8331   priv = GTK_ENTRY_GET_PRIVATE (entry);
8332  
8333   if (!GTK_WIDGET_HAS_FOCUS (entry))
8334     {
8335       g_warning ("GtkEntry - did not receive focus-out-event. If you\n"
8336                  "connect a handler to this signal, it must return\n"
8337                  "FALSE so the entry gets the event as well");
8338
8339       gtk_entry_check_cursor_blink (entry);
8340
8341       return FALSE;
8342     }
8343   
8344   g_assert (entry->selection_bound == entry->current_pos);
8345   
8346   blink_timeout = get_cursor_blink_timeout (entry);
8347   if (priv->blink_time > 1000 * blink_timeout && 
8348       blink_timeout < G_MAXINT/1000) 
8349     {
8350       /* we've blinked enough without the user doing anything, stop blinking */
8351       show_cursor (entry);
8352       entry->blink_timeout = 0;
8353     } 
8354   else if (entry->cursor_visible)
8355     {
8356       hide_cursor (entry);
8357       entry->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_OFF_MULTIPLIER / CURSOR_DIVIDER,
8358                                             blink_cb,
8359                                             entry);
8360     }
8361   else
8362     {
8363       show_cursor (entry);
8364       priv->blink_time += get_cursor_time (entry);
8365       entry->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER,
8366                                             blink_cb,
8367                                             entry);
8368     }
8369
8370   /* Remove ourselves */
8371   return FALSE;
8372 }
8373
8374 static void
8375 gtk_entry_check_cursor_blink (GtkEntry *entry)
8376 {
8377   GtkEntryPrivate *priv; 
8378   
8379   priv = GTK_ENTRY_GET_PRIVATE (entry);
8380
8381   if (cursor_blinks (entry))
8382     {
8383       if (!entry->blink_timeout)
8384         {
8385           show_cursor (entry);
8386           entry->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_ON_MULTIPLIER / CURSOR_DIVIDER,
8387                                                 blink_cb,
8388                                                 entry);
8389         }
8390     }
8391   else
8392     {
8393       if (entry->blink_timeout)  
8394         { 
8395           g_source_remove (entry->blink_timeout);
8396           entry->blink_timeout = 0;
8397         }
8398       
8399       entry->cursor_visible = TRUE;
8400     }
8401   
8402 }
8403
8404 static void
8405 gtk_entry_pend_cursor_blink (GtkEntry *entry)
8406 {
8407   if (cursor_blinks (entry))
8408     {
8409       if (entry->blink_timeout != 0)
8410         g_source_remove (entry->blink_timeout);
8411       
8412       entry->blink_timeout = gdk_threads_add_timeout (get_cursor_time (entry) * CURSOR_PEND_MULTIPLIER / CURSOR_DIVIDER,
8413                                             blink_cb,
8414                                             entry);
8415       show_cursor (entry);
8416     }
8417 }
8418
8419 static void
8420 gtk_entry_reset_blink_time (GtkEntry *entry)
8421 {
8422   GtkEntryPrivate *priv; 
8423   
8424   priv = GTK_ENTRY_GET_PRIVATE (entry);
8425   
8426   priv->blink_time = 0;
8427 }
8428
8429
8430 /* completion */
8431 static gint
8432 gtk_entry_completion_timeout (gpointer data)
8433 {
8434   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
8435
8436   completion->priv->completion_timeout = 0;
8437
8438   if (completion->priv->filter_model &&
8439       g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (completion->priv->entry)), -1)
8440       >= completion->priv->minimum_key_length)
8441     {
8442       gint matches;
8443       gint actions;
8444       GtkTreeSelection *s;
8445       gboolean popup_single;
8446
8447       gtk_entry_completion_complete (completion);
8448       matches = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
8449
8450       gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
8451
8452       s = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view));
8453
8454       gtk_tree_selection_unselect_all (s);
8455
8456       actions = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->actions), NULL);
8457
8458       g_object_get (completion, "popup-single-match", &popup_single, NULL);
8459       if ((matches > (popup_single ? 0: 1)) || actions > 0)
8460         { 
8461           if (GTK_WIDGET_VISIBLE (completion->priv->popup_window))
8462             _gtk_entry_completion_resize_popup (completion);
8463           else
8464             _gtk_entry_completion_popup (completion);
8465         }
8466       else 
8467         _gtk_entry_completion_popdown (completion);
8468     }
8469   else if (GTK_WIDGET_VISIBLE (completion->priv->popup_window))
8470     _gtk_entry_completion_popdown (completion);
8471
8472   return FALSE;
8473 }
8474
8475 static inline gboolean
8476 keyval_is_cursor_move (guint keyval)
8477 {
8478   if (keyval == GDK_Up || keyval == GDK_KP_Up)
8479     return TRUE;
8480
8481   if (keyval == GDK_Down || keyval == GDK_KP_Down)
8482     return TRUE;
8483
8484   if (keyval == GDK_Page_Up)
8485     return TRUE;
8486
8487   if (keyval == GDK_Page_Down)
8488     return TRUE;
8489
8490   return FALSE;
8491 }
8492
8493 static gboolean
8494 gtk_entry_completion_key_press (GtkWidget   *widget,
8495                                 GdkEventKey *event,
8496                                 gpointer     user_data)
8497 {
8498   gint matches, actions = 0;
8499   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
8500
8501   if (!GTK_WIDGET_MAPPED (completion->priv->popup_window))
8502     return FALSE;
8503
8504   matches = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
8505
8506   if (completion->priv->actions)
8507     actions = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->actions), NULL);
8508
8509   if (keyval_is_cursor_move (event->keyval))
8510     {
8511       GtkTreePath *path = NULL;
8512       
8513       if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
8514         {
8515           if (completion->priv->current_selected < 0)
8516             completion->priv->current_selected = matches + actions - 1;
8517           else
8518             completion->priv->current_selected--;
8519         }
8520       else if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
8521         {
8522           if (completion->priv->current_selected < matches + actions - 1)
8523             completion->priv->current_selected++;
8524           else
8525             completion->priv->current_selected = -1;
8526         }
8527       else if (event->keyval == GDK_Page_Up)
8528         {
8529           if (completion->priv->current_selected < 0)
8530             completion->priv->current_selected = matches + actions - 1;
8531           else if (completion->priv->current_selected == 0)
8532             completion->priv->current_selected = -1;
8533           else if (completion->priv->current_selected < matches) 
8534             {
8535               completion->priv->current_selected -= 14;
8536               if (completion->priv->current_selected < 0)
8537                 completion->priv->current_selected = 0;
8538             }
8539           else 
8540             {
8541               completion->priv->current_selected -= 14;
8542               if (completion->priv->current_selected < matches - 1)
8543                 completion->priv->current_selected = matches - 1;
8544             }
8545         }
8546       else if (event->keyval == GDK_Page_Down)
8547         {
8548           if (completion->priv->current_selected < 0)
8549             completion->priv->current_selected = 0;
8550           else if (completion->priv->current_selected < matches - 1)
8551             {
8552               completion->priv->current_selected += 14;
8553               if (completion->priv->current_selected > matches - 1)
8554                 completion->priv->current_selected = matches - 1;
8555             }
8556           else if (completion->priv->current_selected == matches + actions - 1)
8557             {
8558               completion->priv->current_selected = -1;
8559             }
8560           else
8561             {
8562               completion->priv->current_selected += 14;
8563               if (completion->priv->current_selected > matches + actions - 1)
8564                 completion->priv->current_selected = matches + actions - 1;
8565             }
8566         }
8567
8568       if (completion->priv->current_selected < 0)
8569         {
8570           gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
8571           gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view)));
8572
8573           if (completion->priv->inline_selection &&
8574               completion->priv->completion_prefix)
8575             {
8576               gtk_entry_set_text (GTK_ENTRY (completion->priv->entry), 
8577                                   completion->priv->completion_prefix);
8578               gtk_editable_set_position (GTK_EDITABLE (widget), -1);
8579             }
8580         }
8581       else if (completion->priv->current_selected < matches)
8582         {
8583           gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view)));
8584
8585           path = gtk_tree_path_new_from_indices (completion->priv->current_selected, -1);
8586           gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->tree_view),
8587                                     path, NULL, FALSE);
8588
8589           if (completion->priv->inline_selection)
8590             {
8591
8592               GtkTreeIter iter;
8593               GtkTreeModel *model = NULL;
8594               GtkTreeSelection *sel;
8595               gboolean entry_set;
8596
8597               sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view));
8598               if (!gtk_tree_selection_get_selected (sel, &model, &iter))
8599                 return FALSE;
8600               
8601               if (completion->priv->completion_prefix == NULL)
8602                 completion->priv->completion_prefix = g_strdup (gtk_entry_get_text (GTK_ENTRY (completion->priv->entry)));
8603
8604               g_signal_emit_by_name (completion, "cursor-on-match", model,
8605                                      &iter, &entry_set);
8606             }
8607         }
8608       else if (completion->priv->current_selected - matches >= 0)
8609         {
8610           gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
8611
8612           path = gtk_tree_path_new_from_indices (completion->priv->current_selected - matches, -1);
8613           gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->action_view),
8614                                     path, NULL, FALSE);
8615
8616           if (completion->priv->inline_selection &&
8617               completion->priv->completion_prefix)
8618             {
8619               gtk_entry_set_text (GTK_ENTRY (completion->priv->entry), 
8620                                   completion->priv->completion_prefix);
8621               gtk_editable_set_position (GTK_EDITABLE (widget), -1);
8622             }
8623         }
8624
8625       gtk_tree_path_free (path);
8626
8627       return TRUE;
8628     }
8629   else if (event->keyval == GDK_Escape ||
8630            event->keyval == GDK_Left ||
8631            event->keyval == GDK_KP_Left ||
8632            event->keyval == GDK_Right ||
8633            event->keyval == GDK_KP_Right) 
8634     {
8635       gboolean retval = TRUE;
8636
8637       _gtk_entry_reset_im_context (GTK_ENTRY (widget));
8638       _gtk_entry_completion_popdown (completion);
8639
8640       if (completion->priv->current_selected < 0)
8641         {
8642           retval = FALSE;
8643           goto keypress_completion_out;
8644         }
8645       else if (completion->priv->inline_selection)
8646         {
8647           /* Escape rejects the tentative completion */
8648           if (event->keyval == GDK_Escape)
8649             {
8650               if (completion->priv->completion_prefix)
8651                 gtk_entry_set_text (GTK_ENTRY (completion->priv->entry), 
8652                                     completion->priv->completion_prefix);
8653               else 
8654                 gtk_entry_set_text (GTK_ENTRY (completion->priv->entry), "");
8655             }
8656
8657           /* Move the cursor to the end for Right/Esc, to the
8658              beginning for Left */
8659           if (event->keyval == GDK_Right ||
8660               event->keyval == GDK_KP_Right ||
8661               event->keyval == GDK_Escape)
8662             gtk_editable_set_position (GTK_EDITABLE (widget), -1);
8663           else
8664             gtk_editable_set_position (GTK_EDITABLE (widget), 0);
8665         }
8666
8667 keypress_completion_out:
8668       if (completion->priv->inline_selection)
8669         {
8670           g_free (completion->priv->completion_prefix);
8671           completion->priv->completion_prefix = NULL;
8672         }
8673
8674       return retval;
8675     }
8676   else if (event->keyval == GDK_Tab || 
8677            event->keyval == GDK_KP_Tab ||
8678            event->keyval == GDK_ISO_Left_Tab) 
8679     {
8680       GtkDirectionType dir = event->keyval == GDK_ISO_Left_Tab ? 
8681         GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD;
8682       
8683       _gtk_entry_reset_im_context (GTK_ENTRY (widget));
8684       _gtk_entry_completion_popdown (completion);
8685
8686       g_free (completion->priv->completion_prefix);
8687       completion->priv->completion_prefix = NULL;
8688
8689       gtk_widget_child_focus (gtk_widget_get_toplevel (widget), dir);
8690
8691       return TRUE;
8692     }
8693   else if (event->keyval == GDK_ISO_Enter ||
8694            event->keyval == GDK_KP_Enter ||
8695            event->keyval == GDK_Return)
8696     {
8697       gboolean retval = TRUE;
8698
8699       _gtk_entry_reset_im_context (GTK_ENTRY (widget));
8700       _gtk_entry_completion_popdown (completion);
8701
8702       if (completion->priv->current_selected < matches)
8703         {
8704           GtkTreeIter iter;
8705           GtkTreeModel *model = NULL;
8706           GtkTreeSelection *sel;
8707           gboolean entry_set;
8708
8709           sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view));
8710           if (gtk_tree_selection_get_selected (sel, &model, &iter))
8711             {
8712               g_signal_handler_block (widget, completion->priv->changed_id);
8713               g_signal_emit_by_name (completion, "match-selected",
8714                                      model, &iter, &entry_set);
8715               g_signal_handler_unblock (widget, completion->priv->changed_id);
8716
8717               if (!entry_set)
8718                 {
8719                   gchar *str = NULL;
8720
8721                   gtk_tree_model_get (model, &iter,
8722                                       completion->priv->text_column, &str,
8723                                       -1);
8724
8725                   gtk_entry_set_text (GTK_ENTRY (widget), str);
8726
8727                   /* move the cursor to the end */
8728                   gtk_editable_set_position (GTK_EDITABLE (widget), -1);
8729
8730                   g_free (str);
8731                 }
8732             }
8733           else
8734             retval = FALSE;
8735         }
8736       else if (completion->priv->current_selected - matches >= 0)
8737         {
8738           GtkTreePath *path;
8739
8740           _gtk_entry_reset_im_context (GTK_ENTRY (widget));
8741
8742           path = gtk_tree_path_new_from_indices (completion->priv->current_selected - matches, -1);
8743
8744           g_signal_emit_by_name (completion, "action-activated",
8745                                  gtk_tree_path_get_indices (path)[0]);
8746           gtk_tree_path_free (path);
8747         }
8748
8749       g_free (completion->priv->completion_prefix);
8750       completion->priv->completion_prefix = NULL;
8751
8752       return retval;
8753     }
8754
8755   return FALSE;
8756 }
8757
8758 static void
8759 gtk_entry_completion_changed (GtkWidget *entry,
8760                               gpointer   user_data)
8761 {
8762   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
8763
8764   /* (re)install completion timeout */
8765   if (completion->priv->completion_timeout)
8766     g_source_remove (completion->priv->completion_timeout);
8767
8768   if (!gtk_entry_get_text (GTK_ENTRY (entry)))
8769     return;
8770
8771   /* no need to normalize for this test */
8772   if (completion->priv->minimum_key_length > 0 &&
8773       strcmp ("", gtk_entry_get_text (GTK_ENTRY (entry))) == 0)
8774     {
8775       if (GTK_WIDGET_VISIBLE (completion->priv->popup_window))
8776         _gtk_entry_completion_popdown (completion);
8777       return;
8778     }
8779
8780   completion->priv->completion_timeout =
8781     gdk_threads_add_timeout (COMPLETION_TIMEOUT,
8782                    gtk_entry_completion_timeout,
8783                    completion);
8784 }
8785
8786 static gboolean
8787 check_completion_callback (GtkEntryCompletion *completion)
8788 {
8789   completion->priv->check_completion_idle = NULL;
8790   
8791   gtk_entry_completion_complete (completion);
8792   gtk_entry_completion_insert_prefix (completion);
8793
8794   return FALSE;
8795 }
8796
8797 static void
8798 clear_completion_callback (GtkEntry   *entry,
8799                            GParamSpec *pspec)
8800 {
8801   if (pspec->name == I_("cursor-position") ||
8802       pspec->name == I_("selection-bound"))
8803     {
8804       GtkEntryCompletion *completion = gtk_entry_get_completion (entry);
8805       
8806       completion->priv->has_completion = FALSE;
8807     }
8808 }
8809
8810 static gboolean
8811 accept_completion_callback (GtkEntry *entry)
8812 {
8813   GtkEntryCompletion *completion = gtk_entry_get_completion (entry);
8814
8815   if (completion->priv->has_completion)
8816     gtk_editable_set_position (GTK_EDITABLE (entry),
8817                                entry->text_length);
8818
8819   return FALSE;
8820 }
8821
8822 static void
8823 completion_insert_text_callback (GtkEntry           *entry,
8824                                  const gchar        *text,
8825                                  gint                length,
8826                                  gint                position,
8827                                  GtkEntryCompletion *completion)
8828 {
8829   /* idle to update the selection based on the file list */
8830   if (completion->priv->check_completion_idle == NULL)
8831     {
8832       completion->priv->check_completion_idle = g_idle_source_new ();
8833       g_source_set_priority (completion->priv->check_completion_idle, G_PRIORITY_HIGH);
8834       g_source_set_closure (completion->priv->check_completion_idle,
8835                             g_cclosure_new_object (G_CALLBACK (check_completion_callback),
8836                                                    G_OBJECT (completion)));
8837       g_source_attach (completion->priv->check_completion_idle, NULL);
8838     }
8839 }
8840
8841 static void
8842 completion_changed (GtkEntryCompletion *completion,
8843                     GParamSpec         *pspec,
8844                     gpointer            data)
8845 {
8846   GtkEntry *entry = GTK_ENTRY (data);
8847
8848   if (pspec->name == I_("popup-completion") ||
8849       pspec->name == I_("inline-completion"))
8850     {
8851       disconnect_completion_signals (entry, completion);
8852       connect_completion_signals (entry, completion);
8853     }
8854 }
8855
8856 static void
8857 disconnect_completion_signals (GtkEntry           *entry,
8858                                GtkEntryCompletion *completion)
8859 {
8860   g_signal_handlers_disconnect_by_func (completion, 
8861                                        G_CALLBACK (completion_changed), entry);
8862   if (completion->priv->changed_id > 0 &&
8863       g_signal_handler_is_connected (entry, completion->priv->changed_id))
8864     {
8865       g_signal_handler_disconnect (entry, completion->priv->changed_id);
8866       completion->priv->changed_id = 0;
8867     }
8868   g_signal_handlers_disconnect_by_func (entry, 
8869                                         G_CALLBACK (gtk_entry_completion_key_press), completion);
8870   if (completion->priv->insert_text_id > 0 &&
8871       g_signal_handler_is_connected (entry, completion->priv->insert_text_id))
8872     {
8873       g_signal_handler_disconnect (entry, completion->priv->insert_text_id);
8874       completion->priv->insert_text_id = 0;
8875     }
8876   g_signal_handlers_disconnect_by_func (entry, 
8877                                         G_CALLBACK (completion_insert_text_callback), completion);
8878   g_signal_handlers_disconnect_by_func (entry, 
8879                                         G_CALLBACK (clear_completion_callback), completion);
8880   g_signal_handlers_disconnect_by_func (entry, 
8881                                         G_CALLBACK (accept_completion_callback), completion);
8882 }
8883
8884 static void
8885 connect_completion_signals (GtkEntry           *entry,
8886                             GtkEntryCompletion *completion)
8887 {
8888   if (completion->priv->popup_completion)
8889     {
8890       completion->priv->changed_id =
8891         g_signal_connect (entry, "changed",
8892                           G_CALLBACK (gtk_entry_completion_changed), completion);
8893       g_signal_connect (entry, "key-press-event",
8894                         G_CALLBACK (gtk_entry_completion_key_press), completion);
8895     }
8896  
8897   if (completion->priv->inline_completion)
8898     {
8899       completion->priv->insert_text_id =
8900         g_signal_connect (entry, "insert-text",
8901                           G_CALLBACK (completion_insert_text_callback), completion);
8902       g_signal_connect (entry, "notify",
8903                         G_CALLBACK (clear_completion_callback), completion);
8904       g_signal_connect (entry, "activate",
8905                         G_CALLBACK (accept_completion_callback), completion);
8906       g_signal_connect (entry, "focus-out-event",
8907                         G_CALLBACK (accept_completion_callback), completion);
8908     }
8909
8910   g_signal_connect (completion, "notify",
8911                     G_CALLBACK (completion_changed), entry);
8912 }
8913
8914 /**
8915  * gtk_entry_set_completion:
8916  * @entry: A #GtkEntry
8917  * @completion: The #GtkEntryCompletion or %NULL
8918  *
8919  * Sets @completion to be the auxiliary completion object to use with @entry.
8920  * All further configuration of the completion mechanism is done on
8921  * @completion using the #GtkEntryCompletion API. Completion is disabled if
8922  * @completion is set to %NULL.
8923  *
8924  * Since: 2.4
8925  */
8926 void
8927 gtk_entry_set_completion (GtkEntry           *entry,
8928                           GtkEntryCompletion *completion)
8929 {
8930   GtkEntryCompletion *old;
8931
8932   g_return_if_fail (GTK_IS_ENTRY (entry));
8933   g_return_if_fail (!completion || GTK_IS_ENTRY_COMPLETION (completion));
8934
8935   old = gtk_entry_get_completion (entry);
8936
8937   if (old == completion)
8938     return;
8939   
8940   if (old)
8941     {
8942       if (old->priv->completion_timeout)
8943         {
8944           g_source_remove (old->priv->completion_timeout);
8945           old->priv->completion_timeout = 0;
8946         }
8947
8948       if (GTK_WIDGET_MAPPED (old->priv->popup_window))
8949         _gtk_entry_completion_popdown (old);
8950
8951       disconnect_completion_signals (entry, old);
8952       old->priv->entry = NULL;
8953
8954       g_object_unref (old);
8955     }
8956
8957   if (!completion)
8958     {
8959       g_object_set_data (G_OBJECT (entry), I_(GTK_ENTRY_COMPLETION_KEY), NULL);
8960       return;
8961     }
8962
8963   /* hook into the entry */
8964   g_object_ref (completion);
8965
8966   connect_completion_signals (entry, completion);    
8967   completion->priv->entry = GTK_WIDGET (entry);
8968   g_object_set_data (G_OBJECT (entry), I_(GTK_ENTRY_COMPLETION_KEY), completion);
8969 }
8970
8971 /**
8972  * gtk_entry_get_completion:
8973  * @entry: A #GtkEntry
8974  *
8975  * Returns the auxiliary completion object currently in use by @entry.
8976  *
8977  * Return value: The auxiliary completion object currently in use by @entry.
8978  *
8979  * Since: 2.4
8980  */
8981 GtkEntryCompletion *
8982 gtk_entry_get_completion (GtkEntry *entry)
8983 {
8984   GtkEntryCompletion *completion;
8985
8986   g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
8987
8988   completion = GTK_ENTRY_COMPLETION (g_object_get_data (G_OBJECT (entry),
8989                                      GTK_ENTRY_COMPLETION_KEY));
8990
8991   return completion;
8992 }
8993
8994 /**
8995  * gtk_entry_set_cursor_hadjustment:
8996  * @entry: a #GtkEntry
8997  * @adjustment: an adjustment which should be adjusted when the cursor 
8998  *              is moved, or %NULL
8999  *
9000  * Hooks up an adjustment to the cursor position in an entry, so that when 
9001  * the cursor is moved, the adjustment is scrolled to show that position. 
9002  * See gtk_scrolled_window_get_hadjustment() for a typical way of obtaining 
9003  * the adjustment.
9004  *
9005  * The adjustment has to be in pixel units and in the same coordinate system 
9006  * as the entry. 
9007  * 
9008  * Since: 2.12
9009  */
9010 void
9011 gtk_entry_set_cursor_hadjustment (GtkEntry      *entry,
9012                                   GtkAdjustment *adjustment)
9013 {
9014   g_return_if_fail (GTK_IS_ENTRY (entry));
9015   if (adjustment)
9016     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
9017
9018   if (adjustment)
9019     g_object_ref (adjustment);
9020
9021   g_object_set_qdata_full (G_OBJECT (entry), 
9022                            quark_cursor_hadjustment,
9023                            adjustment, 
9024                            g_object_unref);
9025 }
9026
9027 /**
9028  * gtk_entry_get_cursor_hadjustment:
9029  * @entry: a #GtkEntry
9030  *
9031  * Retrieves the horizontal cursor adjustment for the entry. 
9032  * See gtk_entry_set_cursor_hadjustment().
9033  *
9034  * Return value: the horizontal cursor adjustment, or %NULL 
9035  *   if none has been set.
9036  * 
9037  * Since: 2.12
9038  */
9039 GtkAdjustment*
9040 gtk_entry_get_cursor_hadjustment (GtkEntry *entry)
9041 {
9042   g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
9043
9044   return g_object_get_qdata (G_OBJECT (entry), quark_cursor_hadjustment);
9045 }
9046
9047 /**
9048  * gtk_entry_set_progress_fraction:
9049  * @entry: a #GtkEntry
9050  * @fraction: fraction of the task that's been completed
9051  *
9052  * Causes the entry's progress indicator to "fill in" the given
9053  * fraction of the bar. The fraction should be between 0.0 and 1.0,
9054  * inclusive.
9055  *
9056  * Since: 2.16
9057  */
9058 void
9059 gtk_entry_set_progress_fraction (GtkEntry *entry,
9060                                  gdouble   fraction)
9061 {
9062   GtkEntryPrivate *private;
9063   gdouble          old_fraction;
9064
9065   g_return_if_fail (GTK_IS_ENTRY (entry));
9066
9067   private = GTK_ENTRY_GET_PRIVATE (entry);
9068
9069   if (private->progress_pulse_mode)
9070     old_fraction = -1;
9071   else
9072     old_fraction = private->progress_fraction;
9073
9074   fraction = CLAMP (fraction, 0.0, 1.0);
9075
9076   private->progress_fraction = fraction;
9077   private->progress_pulse_mode = FALSE;
9078   private->progress_pulse_current = 0.0;
9079
9080   if (fabs (fraction - old_fraction) > 0.0001)
9081     gtk_entry_queue_draw (entry);
9082
9083   if (fraction != old_fraction)
9084     g_object_notify (G_OBJECT (entry), "progress-fraction");
9085 }
9086
9087 /**
9088  * gtk_entry_get_progress_fraction:
9089  * @entry: a #GtkEntry
9090  *
9091  * Returns the current fraction of the task that's been completed.
9092  * See gtk_entry_set_progress_fraction().
9093  *
9094  * Return value: a fraction from 0.0 to 1.0
9095  *
9096  * Since: 2.16
9097  */
9098 gdouble
9099 gtk_entry_get_progress_fraction (GtkEntry *entry)
9100 {
9101   GtkEntryPrivate *private;
9102
9103   g_return_val_if_fail (GTK_IS_ENTRY (entry), 0.0);
9104
9105   private = GTK_ENTRY_GET_PRIVATE (entry);
9106
9107   return private->progress_fraction;
9108 }
9109
9110 /**
9111  * gtk_entry_set_progress_pulse_step:
9112  * @entry: a #GtkEntry
9113  * @fraction: fraction between 0.0 and 1.0
9114  *
9115  * Sets the fraction of total entry width to move the progress
9116  * bouncing block for each call to gtk_entry_progress_pulse().
9117  *
9118  * Since: 2.16
9119  */
9120 void
9121 gtk_entry_set_progress_pulse_step (GtkEntry *entry,
9122                                    gdouble   fraction)
9123 {
9124   GtkEntryPrivate *private;
9125
9126   g_return_if_fail (GTK_IS_ENTRY (entry));
9127
9128   private = GTK_ENTRY_GET_PRIVATE (entry);
9129
9130   fraction = CLAMP (fraction, 0.0, 1.0);
9131
9132   if (fraction != private->progress_pulse_fraction)
9133     {
9134       private->progress_pulse_fraction = fraction;
9135
9136       gtk_entry_queue_draw (entry);
9137
9138       g_object_notify (G_OBJECT (entry), "progress-pulse-step");
9139     }
9140 }
9141
9142 /**
9143  * gtk_entry_get_progress_pulse_step:
9144  * @entry: a #GtkEntry
9145  *
9146  * Retrieves the pulse step set with gtk_entry_set_progress_pulse_step().
9147  *
9148  * Return value: a fraction from 0.0 to 1.0
9149  *
9150  * Since: 2.16
9151  */
9152 gdouble
9153 gtk_entry_get_progress_pulse_step (GtkEntry *entry)
9154 {
9155   GtkEntryPrivate *private;
9156
9157   g_return_val_if_fail (GTK_IS_ENTRY (entry), 0.0);
9158
9159   private = GTK_ENTRY_GET_PRIVATE (entry);
9160
9161   return private->progress_pulse_fraction;
9162 }
9163
9164 /**
9165  * gtk_entry_progress_pulse:
9166  * @entry: a #GtkEntry
9167  *
9168  * Indicates that some progress is made, but you don't know how much.
9169  * Causes the entry's progress indicator to enter "activity mode,"
9170  * where a block bounces back and forth. Each call to
9171  * gtk_entry_progress_pulse() causes the block to move by a little bit
9172  * (the amount of movement per pulse is determined by
9173  * gtk_entry_set_progress_pulse_step()).
9174  *
9175  * Since: 2.16
9176  */
9177 void
9178 gtk_entry_progress_pulse (GtkEntry *entry)
9179 {
9180   GtkEntryPrivate *private;
9181
9182   g_return_if_fail (GTK_IS_ENTRY (entry));
9183
9184   private = GTK_ENTRY_GET_PRIVATE (entry);
9185
9186   if (private->progress_pulse_mode)
9187     {
9188       if (private->progress_pulse_way_back)
9189         {
9190           private->progress_pulse_current -= private->progress_pulse_fraction;
9191
9192           if (private->progress_pulse_current < 0.0)
9193             {
9194               private->progress_pulse_current = 0.0;
9195               private->progress_pulse_way_back = FALSE;
9196             }
9197         }
9198       else
9199         {
9200           private->progress_pulse_current += private->progress_pulse_fraction;
9201
9202           if (private->progress_pulse_current > 1.0 - private->progress_pulse_fraction)
9203             {
9204               private->progress_pulse_current = 1.0 - private->progress_pulse_fraction;
9205               private->progress_pulse_way_back = TRUE;
9206             }
9207         }
9208     }
9209   else
9210     {
9211       private->progress_fraction = 0.0;
9212       private->progress_pulse_mode = TRUE;
9213       private->progress_pulse_way_back = FALSE;
9214       private->progress_pulse_current = 0.0;
9215     }
9216
9217   gtk_entry_queue_draw (entry);
9218 }
9219
9220 /* Caps Lock warning for password entries */
9221
9222 static void
9223 capslock_feedback_free (GtkEntryCapslockFeedback *feedback)
9224 {
9225   if (feedback->window)
9226     gtk_widget_destroy (feedback->window);
9227
9228   g_slice_free (GtkEntryCapslockFeedback, feedback);
9229 }
9230
9231 static gboolean
9232 capslock_feedback_expose_event_cb (GtkWidget                *widget,
9233                                    GdkEventExpose           *event,
9234                                    GtkEntryCapslockFeedback *feedback)
9235 {
9236   gtk_paint_flat_box (feedback->window->style,
9237                       feedback->window->window,
9238                       GTK_STATE_NORMAL,
9239                       GTK_SHADOW_OUT,
9240                       NULL,
9241                       feedback->window,
9242                       "tooltip",
9243                       0, 0,
9244                       feedback->window->allocation.width,
9245                       feedback->window->allocation.height);
9246   return FALSE;
9247 }
9248
9249 static gboolean
9250 capslock_feedback_enter_notify (GtkWidget                *widget,
9251                                 GdkEventCrossing         *event,
9252                                 GtkEntryCapslockFeedback *feedback)
9253 {
9254   remove_capslock_feedback (GTK_ENTRY (feedback->entry));
9255   return TRUE;
9256 }
9257
9258 static void
9259 create_capslock_feedback_window (GtkEntryCapslockFeedback *feedback)
9260 {
9261   GtkWidget *window;
9262   GtkWidget *alignment;
9263   GtkWidget *label;
9264   
9265   /* Keep in sync with gtk_tooltip_init() */
9266   window = feedback->window = gtk_window_new (GTK_WINDOW_POPUP);
9267   gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_TOOLTIP);
9268   gtk_widget_set_app_paintable (window, TRUE);
9269   gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
9270   gtk_widget_set_name (window, "gtk-tooltip");
9271
9272   alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
9273   gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
9274                              window->style->ythickness, 
9275                              window->style->ythickness,
9276                              window->style->xthickness,
9277                              window->style->xthickness);
9278   gtk_container_add (GTK_CONTAINER (window), alignment);
9279   gtk_widget_show (alignment);
9280
9281   g_signal_connect (window, "expose-event",
9282                     G_CALLBACK (capslock_feedback_expose_event_cb), feedback);
9283   g_signal_connect (window, "enter-notify-event",
9284                     G_CALLBACK (capslock_feedback_enter_notify), feedback);
9285
9286   label = feedback->label = gtk_label_new (NULL);
9287   gtk_container_add (GTK_CONTAINER (alignment), label);
9288   gtk_widget_show (label);
9289 }
9290
9291 static void
9292 show_capslock_feedback_window (GtkEntryCapslockFeedback *feedback)
9293 {
9294   GtkRequisition feedback_req;
9295   gint entry_x, entry_y;
9296   GtkAllocation *entry_allocation;
9297   int feedback_x, feedback_y;
9298   GdkScreen *screen;
9299   gint monitor_num;
9300   GdkRectangle monitor;
9301   GtkWidget *entry;
9302
9303   entry = feedback->entry;
9304   screen = gtk_widget_get_screen (entry);
9305   monitor_num = gdk_screen_get_monitor_at_window (screen, entry->window);
9306   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
9307
9308   feedback = g_object_get_qdata (G_OBJECT (entry), quark_capslock_feedback);
9309
9310   gtk_widget_size_request (feedback->window, &feedback_req);
9311
9312   gdk_window_get_origin (entry->window, &entry_x, &entry_y);
9313   entry_allocation = &(entry->allocation);
9314
9315   if (entry_x + feedback_req.width <= monitor.x + monitor.width)
9316       feedback_x = MAX (entry_x, monitor.x);
9317   else
9318     feedback_x = monitor.x + monitor.width - feedback_req.width;
9319
9320   if (entry_y + entry_allocation->height + feedback_req.height <= monitor.y + monitor.height)
9321     feedback_y = entry_y + entry_allocation->height;
9322   else
9323     feedback_y = MAX (entry_y - feedback_req.height, monitor.y);
9324
9325   gtk_window_move (GTK_WINDOW (feedback->window), feedback_x, feedback_y);
9326   gtk_widget_show (feedback->window);
9327 }
9328
9329 static void
9330 pop_up_capslock_feedback (GtkEntry    *entry,
9331                           const gchar *text)
9332 {
9333   GtkEntryCapslockFeedback *feedback;
9334
9335   feedback = g_object_get_qdata (G_OBJECT (entry), quark_capslock_feedback);
9336
9337   if (feedback == NULL)
9338     {
9339       feedback = g_slice_new0 (GtkEntryCapslockFeedback);
9340       feedback->entry = GTK_WIDGET (entry);
9341       g_object_set_qdata_full (G_OBJECT (entry), quark_capslock_feedback,
9342                                feedback,
9343                                (GDestroyNotify) capslock_feedback_free);
9344       create_capslock_feedback_window (feedback);
9345     }
9346
9347   gtk_label_set_text (GTK_LABEL (feedback->label), text);
9348   show_capslock_feedback_window (feedback);
9349 }
9350
9351 static void
9352 remove_capslock_feedback (GtkEntry *entry)
9353 {
9354   g_object_set_qdata (G_OBJECT (entry), quark_capslock_feedback, NULL);
9355 }
9356
9357 static void
9358 keymap_state_changed (GdkKeymap *keymap, 
9359                       GtkEntry  *entry)
9360 {
9361   GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
9362   char *text = NULL;
9363
9364   if (!entry->visible && priv->caps_lock_warning)
9365     { 
9366       gboolean capslock_on;
9367       gboolean im_on;
9368
9369       capslock_on = gdk_keymap_get_caps_lock_state (keymap);
9370       im_on = g_strcmp0 (gtk_im_multicontext_get_context_id (GTK_IM_MULTICONTEXT (entry->im_context)), "gtk-im-context-simple") != 0;
9371       if (capslock_on && im_on)
9372         text = _("You have the Caps Lock key on\nand an active input method");
9373       else if (capslock_on)
9374         text = _("You have the Caps Lock key on");
9375       else if (im_on)
9376         text = _("You have an active input method");    
9377     }
9378
9379   if (text)
9380     pop_up_capslock_feedback (entry, text);
9381   else
9382     remove_capslock_feedback (entry);
9383 }
9384
9385 #define __GTK_ENTRY_C__
9386 #include "gtkaliasdef.c"