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