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