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