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