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