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