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