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