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