]> Pileus Git - ~andy/gtk/blob - gtk/gtkentry.c
7271156b0a4ad6645253c9622bb51648bea90e67
[~andy/gtk] / gtk / gtkentry.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 #include <ctype.h>
20 #include <string.h>
21 #include "gdk/gdkkeysyms.h"
22 #include "gdk/gdki18n.h"
23 #include "gtkentry.h"
24 #include "gtkmain.h"
25 #include "gtkselection.h"
26 #include "gtksignal.h"
27 #include "gtkstyle.h"
28
29 #define MIN_ENTRY_WIDTH  150
30 #define DRAW_TIMEOUT     20
31 #define INNER_BORDER     2
32
33 enum {
34   ARG_0,
35   ARG_MAX_LENGTH,
36   ARG_VISIBILITY
37 };
38
39
40 static void gtk_entry_class_init          (GtkEntryClass     *klass);
41 static void gtk_entry_init                (GtkEntry          *entry);
42 static void gtk_entry_set_arg             (GtkObject         *object,
43                                            GtkArg            *arg,
44                                            guint              arg_id);
45 static void gtk_entry_get_arg             (GtkObject         *object,
46                                            GtkArg            *arg,
47                                            guint              arg_id);
48 static void gtk_entry_finalize            (GtkObject         *object);
49 static void gtk_entry_realize             (GtkWidget         *widget);
50 static void gtk_entry_unrealize           (GtkWidget         *widget);
51 static void gtk_entry_draw_focus          (GtkWidget         *widget);
52 static void gtk_entry_size_request        (GtkWidget         *widget,
53                                            GtkRequisition    *requisition);
54 static void gtk_entry_size_allocate       (GtkWidget         *widget,
55                                            GtkAllocation     *allocation);
56 static void gtk_entry_make_backing_pixmap (GtkEntry *entry,
57                                            gint width, gint height);
58 static void gtk_entry_draw                (GtkWidget         *widget,
59                                            GdkRectangle      *area);
60 static gint gtk_entry_expose              (GtkWidget         *widget,
61                                            GdkEventExpose    *event);
62 static gint gtk_entry_button_press        (GtkWidget         *widget,
63                                            GdkEventButton    *event);
64 static gint gtk_entry_button_release      (GtkWidget         *widget,
65                                            GdkEventButton    *event);
66 static gint gtk_entry_motion_notify       (GtkWidget         *widget,
67                                            GdkEventMotion    *event);
68 static gint gtk_entry_key_press           (GtkWidget         *widget,
69                                            GdkEventKey       *event);
70 static gint gtk_entry_focus_in            (GtkWidget         *widget,
71                                            GdkEventFocus     *event);
72 static gint gtk_entry_focus_out           (GtkWidget         *widget,
73                                            GdkEventFocus     *event);
74 static void gtk_entry_draw_text           (GtkEntry          *entry);
75 static void gtk_entry_draw_cursor         (GtkEntry          *entry);
76 static void gtk_entry_draw_cursor_on_drawable
77                                           (GtkEntry          *entry,
78                                            GdkDrawable       *drawable);
79 static void gtk_entry_style_set           (GtkWidget         *widget,
80                                            GtkStyle          *previous_style);
81 static void gtk_entry_state_changed       (GtkWidget         *widget,
82                                            GtkStateType       previous_state);
83 #ifdef USE_XIM
84 static void gtk_entry_update_ic_attr      (GtkWidget         *widget);
85 #endif
86 static void gtk_entry_queue_draw          (GtkEntry          *entry);
87 static gint gtk_entry_timer               (gpointer           data);
88 static gint gtk_entry_position            (GtkEntry          *entry,
89                                            gint               x);
90 static void entry_adjust_scroll           (GtkEntry          *entry);
91 static void gtk_entry_grow_text           (GtkEntry          *entry);
92 static void gtk_entry_insert_text         (GtkEditable       *editable,
93                                            const gchar       *new_text,
94                                            gint               new_text_length,
95                                            gint              *position);
96 static void gtk_entry_delete_text         (GtkEditable       *editable,
97                                            gint               start_pos,
98                                            gint               end_pos);
99 static void gtk_entry_update_text         (GtkEditable       *editable,
100                                            gint               start_pos,
101                                            gint               end_pos);
102 static gchar *gtk_entry_get_chars         (GtkEditable       *editable,
103                                            gint               start_pos,
104                                            gint               end_pos);
105
106 /* Binding actions */
107 static void gtk_entry_move_cursor         (GtkEditable *editable,
108                                            gint         x,
109                                            gint         y);
110 static void gtk_entry_move_word           (GtkEditable *editable,
111                                            gint         n);
112 static void gtk_entry_move_to_column      (GtkEditable *editable,
113                                            gint         row);
114 static void gtk_entry_kill_char           (GtkEditable *editable,
115                                            gint         direction);
116 static void gtk_entry_kill_word           (GtkEditable *editable,
117                                            gint         direction);
118 static void gtk_entry_kill_line           (GtkEditable *editable,
119                                            gint         direction);
120
121 /* To be removed */
122 static void gtk_move_forward_character    (GtkEntry          *entry);
123 static void gtk_move_backward_character   (GtkEntry          *entry);
124 static void gtk_move_forward_word         (GtkEntry          *entry);
125 static void gtk_move_backward_word        (GtkEntry          *entry);
126 static void gtk_move_beginning_of_line    (GtkEntry          *entry);
127 static void gtk_move_end_of_line          (GtkEntry          *entry);
128 static void gtk_delete_forward_character  (GtkEntry          *entry);
129 static void gtk_delete_backward_character (GtkEntry          *entry);
130 static void gtk_delete_forward_word       (GtkEntry          *entry);
131 static void gtk_delete_backward_word      (GtkEntry          *entry);
132 static void gtk_delete_line               (GtkEntry          *entry);
133 static void gtk_delete_to_line_end        (GtkEntry          *entry);
134 static void gtk_select_word               (GtkEntry          *entry,
135                                            guint32            time);
136 static void gtk_select_line               (GtkEntry          *entry,
137                                            guint32            time);
138
139
140 static void gtk_entry_set_selection       (GtkEditable       *editable,
141                                            gint               start,
142                                            gint               end);
143
144 static void gtk_entry_recompute_offsets   (GtkEntry          *entry);
145 static gint gtk_entry_find_position       (GtkEntry          *entry, 
146                                            gint               position);
147 static void gtk_entry_set_position_from_editable (GtkEditable *editable,
148                                                   gint         position);
149
150 static GtkWidgetClass *parent_class = NULL;
151 static GdkAtom ctext_atom = GDK_NONE;
152
153 static const GtkTextFunction control_keys[26] =
154 {
155   (GtkTextFunction)gtk_move_beginning_of_line,    /* a */
156   (GtkTextFunction)gtk_move_backward_character,   /* b */
157   (GtkTextFunction)gtk_editable_copy_clipboard,   /* c */
158   (GtkTextFunction)gtk_delete_forward_character,  /* d */
159   (GtkTextFunction)gtk_move_end_of_line,          /* e */
160   (GtkTextFunction)gtk_move_forward_character,    /* f */
161   NULL,                                           /* g */
162   (GtkTextFunction)gtk_delete_backward_character, /* h */
163   NULL,                                           /* i */
164   NULL,                                           /* j */
165   (GtkTextFunction)gtk_delete_to_line_end,        /* k */
166   NULL,                                           /* l */
167   NULL,                                           /* m */
168   NULL,                                           /* n */
169   NULL,                                           /* o */
170   NULL,                                           /* p */
171   NULL,                                           /* q */
172   NULL,                                           /* r */
173   NULL,                                           /* s */
174   NULL,                                           /* t */
175   (GtkTextFunction)gtk_delete_line,               /* u */
176   (GtkTextFunction)gtk_editable_paste_clipboard,  /* v */
177   (GtkTextFunction)gtk_delete_backward_word,      /* w */
178   (GtkTextFunction)gtk_editable_cut_clipboard,    /* x */
179   NULL,                                           /* y */
180   NULL,                                           /* z */
181 };
182
183 static const GtkTextFunction alt_keys[26] =
184 {
185   NULL,                                           /* a */
186   (GtkTextFunction)gtk_move_backward_word,        /* b */
187   NULL,                                           /* c */
188   (GtkTextFunction)gtk_delete_forward_word,       /* d */
189   NULL,                                           /* e */
190   (GtkTextFunction)gtk_move_forward_word,         /* f */
191   NULL,                                           /* g */
192   NULL,                                           /* h */
193   NULL,                                           /* i */
194   NULL,                                           /* j */
195   NULL,                                           /* k */
196   NULL,                                           /* l */
197   NULL,                                           /* m */
198   NULL,                                           /* n */
199   NULL,                                           /* o */
200   NULL,                                           /* p */
201   NULL,                                           /* q */
202   NULL,                                           /* r */
203   NULL,                                           /* s */
204   NULL,                                           /* t */
205   NULL,                                           /* u */
206   NULL,                                           /* v */
207   NULL,                                           /* w */
208   NULL,                                           /* x */
209   NULL,                                           /* y */
210   NULL,                                           /* z */
211 };
212
213
214 GtkType
215 gtk_entry_get_type (void)
216 {
217   static GtkType entry_type = 0;
218
219   if (!entry_type)
220     {
221       static const GtkTypeInfo entry_info =
222       {
223         "GtkEntry",
224         sizeof (GtkEntry),
225         sizeof (GtkEntryClass),
226         (GtkClassInitFunc) gtk_entry_class_init,
227         (GtkObjectInitFunc) gtk_entry_init,
228         /* reserved_1 */ NULL,
229         /* reserved_2 */ NULL,
230         (GtkClassInitFunc) NULL,
231       };
232
233       entry_type = gtk_type_unique (GTK_TYPE_EDITABLE, &entry_info);
234     }
235
236   return entry_type;
237 }
238
239 static void
240 gtk_entry_class_init (GtkEntryClass *class)
241 {
242   GtkObjectClass *object_class;
243   GtkWidgetClass *widget_class;
244   GtkEditableClass *editable_class;
245
246   object_class = (GtkObjectClass*) class;
247   widget_class = (GtkWidgetClass*) class;
248   editable_class = (GtkEditableClass*) class;
249   parent_class = gtk_type_class (GTK_TYPE_EDITABLE);
250
251   gtk_object_add_arg_type ("GtkEntry::max_length", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_MAX_LENGTH);
252   gtk_object_add_arg_type ("GtkEntry::visibility", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_VISIBILITY);
253
254   object_class->set_arg = gtk_entry_set_arg;
255   object_class->get_arg = gtk_entry_get_arg;
256   object_class->finalize = gtk_entry_finalize;
257
258   widget_class->realize = gtk_entry_realize;
259   widget_class->unrealize = gtk_entry_unrealize;
260   widget_class->draw_focus = gtk_entry_draw_focus;
261   widget_class->size_request = gtk_entry_size_request;
262   widget_class->size_allocate = gtk_entry_size_allocate;
263   widget_class->draw = gtk_entry_draw;
264   widget_class->expose_event = gtk_entry_expose;
265   widget_class->button_press_event = gtk_entry_button_press;
266   widget_class->button_release_event = gtk_entry_button_release;
267   widget_class->motion_notify_event = gtk_entry_motion_notify;
268   widget_class->key_press_event = gtk_entry_key_press;
269   widget_class->focus_in_event = gtk_entry_focus_in;
270   widget_class->focus_out_event = gtk_entry_focus_out;
271   widget_class->style_set = gtk_entry_style_set;
272   widget_class->state_changed = gtk_entry_state_changed;
273
274   editable_class->insert_text = gtk_entry_insert_text;
275   editable_class->delete_text = gtk_entry_delete_text;
276   editable_class->changed = (void (*)(GtkEditable *)) entry_adjust_scroll;
277
278   editable_class->move_cursor = gtk_entry_move_cursor;
279   editable_class->move_word = gtk_entry_move_word;
280   editable_class->move_to_column = gtk_entry_move_to_column;
281
282   editable_class->kill_char = gtk_entry_kill_char;
283   editable_class->kill_word = gtk_entry_kill_word;
284   editable_class->kill_line = gtk_entry_kill_line;
285
286   editable_class->update_text = gtk_entry_update_text;
287   editable_class->get_chars   = gtk_entry_get_chars;
288   editable_class->set_selection = gtk_entry_set_selection;
289   editable_class->set_position = gtk_entry_set_position_from_editable;
290 }
291
292 static void
293 gtk_entry_set_arg (GtkObject      *object,
294                    GtkArg         *arg,
295                    guint           arg_id)
296 {
297   GtkEntry *entry;
298
299   entry = GTK_ENTRY (object);
300
301   switch (arg_id)
302     {
303     case ARG_MAX_LENGTH:
304       gtk_entry_set_max_length (entry, GTK_VALUE_UINT (*arg));
305       break;
306     case ARG_VISIBILITY:
307       gtk_entry_set_visibility (entry, GTK_VALUE_BOOL (*arg));
308       break;
309     default:
310       break;
311     }
312 }
313
314 static void
315 gtk_entry_get_arg (GtkObject      *object,
316                    GtkArg         *arg,
317                    guint           arg_id)
318 {
319   GtkEntry *entry;
320
321   entry = GTK_ENTRY (object);
322
323   switch (arg_id)
324     {
325     case ARG_MAX_LENGTH:
326       GTK_VALUE_UINT (*arg) = entry->text_max_length;
327       break;
328     case ARG_VISIBILITY:
329       GTK_VALUE_BOOL (*arg) = entry->visible;
330       break;
331     default:
332       arg->type = GTK_TYPE_INVALID;
333       break;
334     }
335 }
336
337 static void
338 gtk_entry_init (GtkEntry *entry)
339 {
340   GTK_WIDGET_SET_FLAGS (entry, GTK_CAN_FOCUS);
341
342   entry->text_area = NULL;
343   entry->backing_pixmap = NULL;
344   entry->text = NULL;
345   entry->text_size = 0;
346   entry->text_length = 0;
347   entry->text_max_length = 0;
348   entry->scroll_offset = 0;
349   entry->timer = 0;
350   entry->button = 0;
351   entry->visible = 1;
352
353   entry->char_offset = NULL;
354   entry->text_mb = NULL;
355   entry->text_mb_dirty = TRUE;
356   entry->use_wchar = FALSE;
357
358   gtk_entry_grow_text (entry);
359 }
360
361 GtkWidget*
362 gtk_entry_new (void)
363 {
364   return GTK_WIDGET (gtk_type_new (GTK_TYPE_ENTRY));
365 }
366
367 GtkWidget*
368 gtk_entry_new_with_max_length (guint16 max)
369 {
370   GtkEntry *entry;
371
372   entry = gtk_type_new (GTK_TYPE_ENTRY);
373   entry->text_max_length = max;
374
375   return GTK_WIDGET (entry);
376 }
377
378 void
379 gtk_entry_set_text (GtkEntry *entry,
380                     const gchar *text)
381 {
382   gint tmp_pos;
383
384   GtkEditable *editable;
385
386   g_return_if_fail (entry != NULL);
387   g_return_if_fail (GTK_IS_ENTRY (entry));
388   g_return_if_fail (text != NULL);
389
390   editable = GTK_EDITABLE (entry);
391   
392   gtk_entry_delete_text (GTK_EDITABLE(entry), 0, entry->text_length);
393
394   tmp_pos = 0;
395   gtk_editable_insert_text (editable, text, strlen (text), &tmp_pos);
396   editable->current_pos = tmp_pos;
397
398   editable->selection_start_pos = 0;
399   editable->selection_end_pos = 0;
400
401   if (GTK_WIDGET_DRAWABLE (entry))
402     gtk_entry_draw_text (entry);
403 }
404
405 void
406 gtk_entry_append_text (GtkEntry *entry,
407                        const gchar *text)
408 {
409   gint tmp_pos;
410
411   g_return_if_fail (entry != NULL);
412   g_return_if_fail (GTK_IS_ENTRY (entry));
413   g_return_if_fail (text != NULL);
414
415   tmp_pos = entry->text_length;
416   gtk_editable_insert_text (GTK_EDITABLE(entry), text, strlen (text), &tmp_pos);
417   GTK_EDITABLE(entry)->current_pos = tmp_pos;
418 }
419
420 void
421 gtk_entry_prepend_text (GtkEntry *entry,
422                         const gchar *text)
423 {
424   gint tmp_pos;
425
426   g_return_if_fail (entry != NULL);
427   g_return_if_fail (GTK_IS_ENTRY (entry));
428   g_return_if_fail (text != NULL);
429
430   tmp_pos = 0;
431   gtk_editable_insert_text (GTK_EDITABLE(entry), text, strlen (text), &tmp_pos);
432   GTK_EDITABLE(entry)->current_pos = tmp_pos;
433 }
434
435 void
436 gtk_entry_set_position (GtkEntry *entry,
437                         gint      position)
438 {
439   g_return_if_fail (entry != NULL);
440   g_return_if_fail (GTK_IS_ENTRY (entry));
441
442   if ((position == -1) || (position > entry->text_length))
443     GTK_EDITABLE(entry)->current_pos = entry->text_length;
444   else
445     GTK_EDITABLE(entry)->current_pos = position;
446   entry_adjust_scroll (entry);
447 }
448
449 static void
450 gtk_entry_set_position_from_editable (GtkEditable *editable,
451                                       gint position)
452 {
453   gtk_entry_set_position (GTK_ENTRY (editable), position);
454 }
455
456 void
457 gtk_entry_set_visibility (GtkEntry *entry,
458                           gboolean visible)
459 {
460   g_return_if_fail (entry != NULL);
461   g_return_if_fail (GTK_IS_ENTRY (entry));
462
463   entry->visible = visible;
464   gtk_entry_recompute_offsets (entry);
465   gtk_widget_queue_draw (GTK_WIDGET (entry));
466 }
467
468 void
469 gtk_entry_set_editable(GtkEntry *entry,
470                        gboolean  editable)
471 {
472   g_return_if_fail (entry != NULL);
473   g_return_if_fail (GTK_IS_ENTRY (entry));
474
475   gtk_editable_set_editable (GTK_EDITABLE (entry), editable);
476 }
477
478 gchar*
479 gtk_entry_get_text (GtkEntry *entry)
480 {
481   g_return_val_if_fail (entry != NULL, NULL);
482   g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
483
484   if (!entry->text_mb_dirty)
485     return entry->text_mb;
486
487   if (entry->text_mb)
488     g_free(entry->text_mb);
489
490   if (!entry->text)
491     {
492       entry->text_mb = g_new(gchar, 1);
493       entry->text_mb[0] = 0;
494     }
495   else
496     {
497       entry->text_mb = gtk_entry_get_chars(GTK_EDITABLE(entry), 0, -1);
498     }
499   entry->text_mb_dirty = 0;
500
501   return entry->text_mb;
502 }
503
504 static void
505 gtk_entry_finalize (GtkObject *object)
506 {
507   GtkEntry *entry;
508
509   g_return_if_fail (object != NULL);
510   g_return_if_fail (GTK_IS_ENTRY (object));
511
512   entry = GTK_ENTRY (object);
513
514   if (entry->timer)
515     gtk_timeout_remove (entry->timer);
516
517   entry->text_size = 0;
518
519   if (entry->text)
520     g_free (entry->text);
521   if (entry->char_offset)
522     g_free (entry->char_offset);
523   entry->text = NULL;
524
525   if (entry->text_mb)
526     g_free (entry->text_mb);
527   entry->text_mb = NULL;
528  
529    if (entry->backing_pixmap)
530   if (entry->backing_pixmap)
531     gdk_pixmap_unref (entry->backing_pixmap);
532
533   (* GTK_OBJECT_CLASS (parent_class)->finalize) (object);
534 }
535
536 static void
537 gtk_entry_realize (GtkWidget *widget)
538 {
539   GtkEntry *entry;
540   GtkEditable *editable;
541   GdkWindowAttr attributes;
542   gint attributes_mask;
543
544   g_return_if_fail (widget != NULL);
545   g_return_if_fail (GTK_IS_ENTRY (widget));
546
547   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
548   entry = GTK_ENTRY (widget);
549   editable = GTK_EDITABLE (widget);
550   
551   attributes.window_type = GDK_WINDOW_CHILD;
552   attributes.x = widget->allocation.x;
553   attributes.y = widget->allocation.y + (widget->allocation.height -
554                                          widget->requisition.height) / 2;
555   attributes.width = widget->allocation.width;
556   attributes.height = widget->requisition.height;
557   attributes.wclass = GDK_INPUT_OUTPUT;
558   attributes.visual = gtk_widget_get_visual (widget);
559   attributes.colormap = gtk_widget_get_colormap (widget);
560   attributes.event_mask = gtk_widget_get_events (widget);
561   attributes.event_mask |= (GDK_EXPOSURE_MASK |
562                             GDK_BUTTON_PRESS_MASK |
563                             GDK_BUTTON_RELEASE_MASK |
564                             GDK_BUTTON1_MOTION_MASK |
565                             GDK_BUTTON3_MOTION_MASK |
566                             GDK_POINTER_MOTION_HINT_MASK |
567                             GDK_ENTER_NOTIFY_MASK |
568                             GDK_LEAVE_NOTIFY_MASK |
569                             GDK_KEY_PRESS_MASK);
570   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
571
572   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
573   gdk_window_set_user_data (widget->window, entry);
574
575   attributes.x = widget->style->klass->xthickness;
576   attributes.y = widget->style->klass->ythickness;
577   attributes.width = widget->allocation.width - attributes.x * 2;
578   attributes.height = widget->requisition.height - attributes.y * 2;
579   attributes.cursor = entry->cursor = gdk_cursor_new (GDK_XTERM);
580   attributes_mask |= GDK_WA_CURSOR;
581
582   entry->text_area = gdk_window_new (widget->window, &attributes, attributes_mask);
583   gdk_window_set_user_data (entry->text_area, entry);
584
585   widget->style = gtk_style_attach (widget->style, widget->window);
586
587   gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
588   gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
589
590 #ifdef USE_XIM
591   if (gdk_im_ready () && (editable->ic_attr = gdk_ic_attr_new ()) != NULL)
592     {
593       gint width, height;
594       GdkEventMask mask;
595       GdkColormap *colormap;
596       GdkICAttr *attr = editable->ic_attr;
597       GdkICAttributesType attrmask = GDK_IC_ALL_REQ;
598       GdkIMStyle style;
599       GdkIMStyle supported_style = GDK_IM_PREEDIT_NONE |
600                                    GDK_IM_PREEDIT_NOTHING |
601                                    GDK_IM_PREEDIT_POSITION |
602                                    GDK_IM_STATUS_NONE |
603                                    GDK_IM_STATUS_NOTHING;
604
605       if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
606         supported_style &= ~GDK_IM_PREEDIT_POSITION;
607
608       attr->style = style = gdk_im_decide_style (supported_style);
609       attr->client_window = entry->text_area;
610
611       if ((colormap = gtk_widget_get_colormap (widget)) !=
612             gtk_widget_get_default_colormap ())
613         {
614           attrmask |= GDK_IC_PREEDIT_COLORMAP;
615           attr->preedit_colormap = colormap;
616         }
617       attrmask |= GDK_IC_PREEDIT_FOREGROUND;
618       attrmask |= GDK_IC_PREEDIT_BACKGROUND;
619       attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
620       attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
621
622       switch (style & GDK_IM_PREEDIT_MASK)
623         {
624         case GDK_IM_PREEDIT_POSITION:
625           if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
626             {
627               g_warning ("over-the-spot style requires fontset");
628               break;
629             }
630
631           gdk_window_get_size (entry->text_area, &width, &height);
632
633           attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
634           attr->spot_location.x = 0;
635           attr->spot_location.y = height;
636           attr->preedit_area.x = 0;
637           attr->preedit_area.y = 0;
638           attr->preedit_area.width = width;
639           attr->preedit_area.height = height;
640           attr->preedit_fontset = widget->style->font;
641
642           break;
643         }
644       editable->ic = gdk_ic_new (attr, attrmask);
645      
646       if (editable->ic == NULL)
647         g_warning ("Can't create input context.");
648       else
649         {
650           mask = gdk_window_get_events (entry->text_area);
651           mask |= gdk_ic_get_events (editable->ic);
652           gdk_window_set_events (entry->text_area, mask);
653
654           if (GTK_WIDGET_HAS_FOCUS(widget))
655             gdk_im_begin (editable->ic, entry->text_area);
656         }
657     }
658 #endif
659
660   gdk_window_show (entry->text_area);
661
662   if (editable->selection_start_pos != editable->selection_end_pos)
663     gtk_editable_claim_selection (editable, TRUE, GDK_CURRENT_TIME);
664
665   gtk_entry_recompute_offsets (entry);
666 }
667
668 static void
669 gtk_entry_unrealize (GtkWidget *widget)
670 {
671   GtkEntry *entry;
672
673   g_return_if_fail (widget != NULL);
674   g_return_if_fail (GTK_IS_ENTRY (widget));
675
676   entry = GTK_ENTRY (widget);
677
678 #ifdef USE_XIM
679   if (GTK_EDITABLE (widget)->ic)
680     {
681       gdk_ic_destroy (GTK_EDITABLE (widget)->ic);
682       GTK_EDITABLE (widget)->ic = NULL;
683     }
684   if (GTK_EDITABLE (widget)->ic_attr)
685     {
686       gdk_ic_attr_destroy (GTK_EDITABLE (widget)->ic_attr);
687       GTK_EDITABLE (widget)->ic_attr = NULL;
688     }
689 #endif
690
691   if (entry->text_area)
692     {
693       gdk_window_set_user_data (entry->text_area, NULL);
694       gdk_window_destroy (entry->text_area);
695       entry->text_area = NULL;
696       gdk_cursor_destroy (entry->cursor);
697       entry->cursor = NULL;
698     }
699
700   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
701     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
702 }
703
704 static void
705 gtk_entry_draw_focus (GtkWidget *widget)
706 {
707   gint width, height;
708   gint x, y;
709
710   g_return_if_fail (widget != NULL);
711   g_return_if_fail (GTK_IS_ENTRY (widget));
712
713   if (GTK_WIDGET_DRAWABLE (widget))
714     {
715       x = 0;
716       y = 0;
717       gdk_window_get_size (widget->window, &width, &height);
718
719       if (GTK_WIDGET_HAS_FOCUS (widget))
720         {
721           x += 1;
722           y += 1;
723           width -= 2;
724           height -= 2;
725         }
726
727       gtk_paint_shadow (widget->style, widget->window,
728                         GTK_STATE_NORMAL, GTK_SHADOW_IN,
729                         NULL, widget, "entry",
730                         x, y, width, height);
731
732       if (GTK_WIDGET_HAS_FOCUS (widget))
733         {
734            gdk_window_get_size (widget->window, &width, &height);
735            gtk_paint_focus (widget->style, widget->window, 
736                             NULL, widget, "entry",
737                             0, 0, width - 1, height - 1);
738         }
739
740       if (GTK_EDITABLE (widget)->editable)
741         gtk_entry_draw_cursor (GTK_ENTRY (widget));
742     }
743 }
744
745 static void
746 gtk_entry_size_request (GtkWidget      *widget,
747                         GtkRequisition *requisition)
748 {
749   g_return_if_fail (widget != NULL);
750   g_return_if_fail (GTK_IS_ENTRY (widget));
751   g_return_if_fail (requisition != NULL);
752
753   requisition->width = MIN_ENTRY_WIDTH + (widget->style->klass->xthickness + INNER_BORDER) * 2;
754   requisition->height = (widget->style->font->ascent +
755                          widget->style->font->descent +
756                          (widget->style->klass->ythickness + INNER_BORDER) * 2);
757 }
758
759 static void
760 gtk_entry_size_allocate (GtkWidget     *widget,
761                          GtkAllocation *allocation)
762 {
763   GtkEntry *entry;
764   GtkEditable *editable;
765
766   g_return_if_fail (widget != NULL);
767   g_return_if_fail (GTK_IS_ENTRY (widget));
768   g_return_if_fail (allocation != NULL);
769
770   widget->allocation = *allocation;
771   entry = GTK_ENTRY (widget);
772   editable = GTK_EDITABLE (widget);
773
774   if (GTK_WIDGET_REALIZED (widget))
775     {
776       gdk_window_move_resize (widget->window,
777                               allocation->x,
778                               allocation->y + (allocation->height - widget->requisition.height) / 2,
779                               allocation->width, widget->requisition.height);
780       gdk_window_move_resize (entry->text_area,
781                               widget->style->klass->xthickness,
782                               widget->style->klass->ythickness,
783                               allocation->width - widget->style->klass->xthickness * 2,
784                               widget->requisition.height - widget->style->klass->ythickness * 2);
785
786       /* And make sure the cursor is on screen */
787       entry_adjust_scroll (entry);
788       
789 #ifdef USE_XIM
790       if (editable->ic &&
791           (gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION))
792         {
793           gint width, height;
794
795           gdk_window_get_size (entry->text_area, &width, &height);
796           editable->ic_attr->preedit_area.width = width;
797           editable->ic_attr->preedit_area.height = height;
798           gdk_ic_set_attr (editable->ic, editable->ic_attr,
799                            GDK_IC_PREEDIT_AREA);
800         }
801 #endif
802     }
803 }
804
805 static void
806 gtk_entry_draw (GtkWidget    *widget,
807                 GdkRectangle *area)
808 {
809   g_return_if_fail (widget != NULL);
810   g_return_if_fail (GTK_IS_ENTRY (widget));
811   g_return_if_fail (area != NULL);
812
813   if (GTK_WIDGET_DRAWABLE (widget))
814     {
815       gtk_widget_draw_focus (widget);
816       gtk_entry_draw_text (GTK_ENTRY (widget));
817     }
818 }
819
820 static gint
821 gtk_entry_expose (GtkWidget      *widget,
822                   GdkEventExpose *event)
823 {
824   GtkEntry *entry;
825
826   g_return_val_if_fail (widget != NULL, FALSE);
827   g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
828   g_return_val_if_fail (event != NULL, FALSE);
829
830   entry = GTK_ENTRY (widget);
831
832   if (widget->window == event->window)
833     gtk_widget_draw_focus (widget);
834   else if (entry->text_area == event->window)
835     gtk_entry_draw_text (GTK_ENTRY (widget));
836
837   return FALSE;
838 }
839
840 static gint
841 gtk_entry_button_press (GtkWidget      *widget,
842                         GdkEventButton *event)
843 {
844   GtkEntry *entry;
845   GtkEditable *editable;
846   gint tmp_pos;
847
848   g_return_val_if_fail (widget != NULL, FALSE);
849   g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
850   g_return_val_if_fail (event != NULL, FALSE);
851
852   if (ctext_atom == GDK_NONE)
853     ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
854
855   entry = GTK_ENTRY (widget);
856   editable = GTK_EDITABLE (widget);
857   
858   if (entry->button && (event->button != entry->button))
859     return FALSE;
860
861   entry->button = event->button;
862   
863   if (!GTK_WIDGET_HAS_FOCUS (widget))
864     gtk_widget_grab_focus (widget);
865
866   if (event->button == 1)
867     {
868       switch (event->type)
869         {
870         case GDK_BUTTON_PRESS:
871           gtk_grab_add (widget);
872
873           tmp_pos = gtk_entry_position (entry, event->x + entry->scroll_offset);
874           /* Set it now, so we display things right. We'll unset it
875            * later if things don't work out */
876           editable->has_selection = TRUE;
877           gtk_entry_set_selection (editable, tmp_pos, tmp_pos);
878           editable->current_pos = editable->selection_start_pos;
879           break;
880
881         case GDK_2BUTTON_PRESS:
882           gtk_select_word (entry, event->time);
883           break;
884
885         case GDK_3BUTTON_PRESS:
886           gtk_select_line (entry, event->time);
887           break;
888
889         default:
890           break;
891         }
892     }
893   else if (event->type == GDK_BUTTON_PRESS)
894     {
895       if ((event->button == 2) && editable->editable)
896         {
897           if (editable->selection_start_pos == editable->selection_end_pos ||
898               editable->has_selection)
899             editable->current_pos = gtk_entry_position (entry, event->x + entry->scroll_offset);
900           gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
901                                  ctext_atom, event->time);
902         }
903       else
904         {
905           gtk_grab_add (widget);
906
907           tmp_pos = gtk_entry_position (entry, event->x + entry->scroll_offset);
908           gtk_entry_set_selection (editable, tmp_pos, tmp_pos);
909           editable->has_selection = FALSE;
910           editable->current_pos = editable->selection_start_pos;
911
912           if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
913             gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
914         }
915     }
916
917   return FALSE;
918 }
919
920 static gint
921 gtk_entry_button_release (GtkWidget      *widget,
922                           GdkEventButton *event)
923 {
924   GtkEntry *entry;
925   GtkEditable *editable;
926
927   g_return_val_if_fail (widget != NULL, FALSE);
928   g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
929   g_return_val_if_fail (event != NULL, FALSE);
930
931   entry = GTK_ENTRY (widget);
932   editable = GTK_EDITABLE (widget);
933
934   if (entry->button != event->button)
935     return FALSE;
936
937   entry->button = 0;
938   
939   if (event->button == 1)
940     {
941       gtk_grab_remove (widget);
942
943       editable->has_selection = FALSE;
944       if (editable->selection_start_pos != editable->selection_end_pos)
945         {
946           if (gtk_selection_owner_set (widget,
947                                        GDK_SELECTION_PRIMARY,
948                                        event->time))
949             editable->has_selection = TRUE;
950           else
951             gtk_entry_queue_draw (entry);
952         }
953       else
954         {
955           if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
956             gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
957         }
958     }
959   else if (event->button == 3)
960     {
961       gtk_grab_remove (widget);
962     }
963
964   return FALSE;
965 }
966
967 static gint
968 gtk_entry_motion_notify (GtkWidget      *widget,
969                          GdkEventMotion *event)
970 {
971   GtkEntry *entry;
972   gint x;
973
974   g_return_val_if_fail (widget != NULL, FALSE);
975   g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
976   g_return_val_if_fail (event != NULL, FALSE);
977
978   entry = GTK_ENTRY (widget);
979
980   if (entry->button == 0)
981     return FALSE;
982
983   x = event->x;
984   if (event->is_hint || (entry->text_area != event->window))
985     gdk_window_get_pointer (entry->text_area, &x, NULL, NULL);
986
987   GTK_EDITABLE(entry)->selection_end_pos = gtk_entry_position (entry, x + entry->scroll_offset);
988   GTK_EDITABLE(entry)->current_pos = GTK_EDITABLE(entry)->selection_end_pos;
989   entry_adjust_scroll (entry);
990   gtk_entry_queue_draw (entry);
991
992   return FALSE;
993 }
994
995 static gint
996 gtk_entry_key_press (GtkWidget   *widget,
997                      GdkEventKey *event)
998 {
999   GtkEntry *entry;
1000   GtkEditable *editable;
1001
1002   gint return_val;
1003   gint key;
1004   guint initial_pos;
1005   gint extend_selection;
1006   gint extend_start;
1007
1008   g_return_val_if_fail (widget != NULL, FALSE);
1009   g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
1010   g_return_val_if_fail (event != NULL, FALSE);
1011
1012   entry = GTK_ENTRY (widget);
1013   editable = GTK_EDITABLE (widget);
1014   return_val = FALSE;
1015
1016   if(editable->editable == FALSE)
1017     return FALSE;
1018
1019   initial_pos = editable->current_pos;
1020
1021   extend_selection = event->state & GDK_SHIFT_MASK;
1022   extend_start = FALSE;
1023
1024   if (extend_selection)
1025     {
1026       if (editable->selection_start_pos == editable->selection_end_pos)
1027         {
1028           editable->selection_start_pos = editable->current_pos;
1029           editable->selection_end_pos = editable->current_pos;
1030         }
1031       
1032       extend_start = (editable->current_pos == editable->selection_start_pos);
1033     }
1034
1035   switch (event->keyval)
1036     {
1037     case GDK_BackSpace:
1038       return_val = TRUE;
1039       if (event->state & GDK_CONTROL_MASK)
1040         gtk_delete_backward_word (entry);
1041       else
1042         gtk_delete_backward_character (entry);
1043       break;
1044     case GDK_Clear:
1045       return_val = TRUE;
1046       gtk_delete_line (entry);
1047       break;
1048     case GDK_Insert:
1049       return_val = TRUE;
1050       if (event->state & GDK_SHIFT_MASK)
1051         {
1052           extend_selection = FALSE;
1053           gtk_editable_paste_clipboard (editable);
1054         }
1055       else if (event->state & GDK_CONTROL_MASK)
1056         {
1057           gtk_editable_copy_clipboard (editable);
1058         }
1059       else
1060         {
1061           /* gtk_toggle_insert(entry) -- IMPLEMENT */
1062         }
1063       break;
1064     case GDK_Delete:
1065       return_val = TRUE;
1066       if (event->state & GDK_CONTROL_MASK)
1067         gtk_delete_forward_word (entry);
1068       else if (event->state & GDK_SHIFT_MASK)
1069         {
1070           extend_selection = FALSE;
1071           gtk_editable_cut_clipboard (editable);
1072         }
1073       else
1074         gtk_delete_forward_character (entry);
1075       break;
1076     case GDK_Home:
1077       return_val = TRUE;
1078       gtk_move_beginning_of_line (entry);
1079       break;
1080     case GDK_End:
1081       return_val = TRUE;
1082       gtk_move_end_of_line (entry);
1083       break;
1084     case GDK_Left:
1085       return_val = TRUE;
1086       if (event->state & GDK_CONTROL_MASK)
1087         gtk_move_backward_word (entry);
1088       else
1089         gtk_move_backward_character (entry);
1090       break;
1091     case GDK_Right:
1092       return_val = TRUE;
1093       if (event->state & GDK_CONTROL_MASK)
1094         gtk_move_forward_word (entry);
1095       else
1096         gtk_move_forward_character (entry);
1097       break;
1098     case GDK_Return:
1099       return_val = TRUE;
1100       gtk_signal_emit_by_name (GTK_OBJECT (entry), "activate");
1101       break;
1102     /* The next two keys should not be inserted literally. Any others ??? */
1103     case GDK_Tab:
1104     case GDK_Escape:
1105       break;
1106     default:
1107       if ((event->keyval >= 0x20) && (event->keyval <= 0xFF))
1108         {
1109           key = event->keyval;
1110
1111           if (event->state & GDK_CONTROL_MASK)
1112             {
1113               if ((key >= 'A') && (key <= 'Z'))
1114                 key -= 'A' - 'a';
1115
1116               if ((key >= 'a') && (key <= 'z') && control_keys[key - 'a'])
1117                 {
1118                   (* control_keys[key - 'a']) (editable, event->time);
1119                   return_val = TRUE;
1120                 }
1121               break;
1122             }
1123           else if (event->state & GDK_MOD1_MASK)
1124             {
1125               if ((key >= 'A') && (key <= 'Z'))
1126                 key -= 'A' - 'a';
1127
1128               if ((key >= 'a') && (key <= 'z') && alt_keys[key - 'a'])
1129                 {
1130                   (* alt_keys[key - 'a']) (editable, event->time);
1131                   return_val = TRUE;
1132                 }
1133               break;
1134             }
1135         }
1136       if (event->length > 0)
1137         {
1138           gint tmp_pos;
1139
1140           extend_selection = FALSE;
1141           gtk_editable_delete_selection (editable);
1142
1143           tmp_pos = editable->current_pos;
1144           gtk_editable_insert_text (editable, event->string, event->length, &tmp_pos);
1145           editable->current_pos = tmp_pos;
1146
1147           return_val = TRUE;
1148         }
1149       break;
1150     }
1151
1152   /* since we emit signals from within the above code,
1153    * the widget might already be destroyed or at least
1154    * unrealized.
1155    */
1156   if (GTK_WIDGET_REALIZED (editable) &&
1157       return_val && (editable->current_pos != initial_pos))
1158     {
1159       if (extend_selection)
1160         {
1161           if (editable->current_pos < editable->selection_start_pos)
1162             editable->selection_start_pos = editable->current_pos;
1163           else if (editable->current_pos > editable->selection_end_pos)
1164             editable->selection_end_pos = editable->current_pos;
1165           else
1166             {
1167               if (extend_start)
1168                 editable->selection_start_pos = editable->current_pos;
1169               else
1170                 editable->selection_end_pos = editable->current_pos;
1171             }
1172         }
1173       else
1174         {
1175           editable->selection_start_pos = 0;
1176           editable->selection_end_pos = 0;
1177         }
1178
1179       gtk_editable_claim_selection (editable,
1180                                     editable->selection_start_pos != editable->selection_end_pos,
1181                                     event->time);
1182       
1183       entry_adjust_scroll (entry);
1184       gtk_entry_queue_draw (entry);
1185     }
1186
1187   return return_val;
1188 }
1189
1190 static gint
1191 gtk_entry_focus_in (GtkWidget     *widget,
1192                     GdkEventFocus *event)
1193 {
1194   g_return_val_if_fail (widget != NULL, FALSE);
1195   g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
1196   g_return_val_if_fail (event != NULL, FALSE);
1197
1198   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
1199   gtk_widget_draw_focus (widget);
1200
1201 #ifdef USE_XIM
1202   if (GTK_EDITABLE(widget)->ic)
1203     gdk_im_begin (GTK_EDITABLE(widget)->ic, GTK_ENTRY(widget)->text_area);
1204 #endif
1205
1206   return FALSE;
1207 }
1208
1209 static gint
1210 gtk_entry_focus_out (GtkWidget     *widget,
1211                      GdkEventFocus *event)
1212 {
1213   g_return_val_if_fail (widget != NULL, FALSE);
1214   g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
1215   g_return_val_if_fail (event != NULL, FALSE);
1216
1217   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
1218   gtk_widget_draw_focus (widget);
1219
1220 #ifdef USE_XIM
1221   gdk_im_end ();
1222 #endif
1223
1224   return FALSE;
1225 }
1226
1227 static void
1228 gtk_entry_make_backing_pixmap (GtkEntry *entry, gint width, gint height)
1229 {
1230   gint pixmap_width, pixmap_height;
1231
1232   if (!entry->backing_pixmap)
1233     {
1234       /* allocate */
1235       entry->backing_pixmap = gdk_pixmap_new (entry->text_area,
1236                                               width, height,
1237                                               -1);
1238     }
1239   else
1240     {
1241       /* reallocate if sizes don't match */
1242       gdk_window_get_size (entry->backing_pixmap,
1243                            &pixmap_width, &pixmap_height);
1244       if ((pixmap_width != width) || (pixmap_height != height))
1245         {
1246           gdk_pixmap_unref (entry->backing_pixmap);
1247           entry->backing_pixmap = gdk_pixmap_new (entry->text_area,
1248                                                   width, height,
1249                                                   -1);
1250         }
1251     }
1252 }
1253
1254 static void
1255 gtk_entry_draw_text (GtkEntry *entry)
1256 {
1257   GtkWidget *widget;
1258   GtkEditable *editable;
1259   GtkStateType selected_state;
1260   gint start_pos;
1261   gint end_pos;
1262   gint start_xoffset;
1263   gint selection_start_pos;
1264   gint selection_end_pos;
1265   gint selection_start_xoffset;
1266   gint selection_end_xoffset;
1267   gint width, height;
1268   gint y;
1269   GdkDrawable *drawable;
1270   gint use_backing_pixmap;
1271   GdkWChar *stars;
1272   GdkWChar *toprint;
1273
1274   g_return_if_fail (entry != NULL);
1275   g_return_if_fail (GTK_IS_ENTRY (entry));
1276
1277   if (entry->timer)
1278     {
1279       gtk_timeout_remove (entry->timer);
1280       entry->timer = 0;
1281     }
1282
1283   if (GTK_WIDGET_DRAWABLE (entry))
1284     {
1285       widget = GTK_WIDGET (entry);
1286       editable = GTK_EDITABLE (entry);
1287
1288       if (!entry->text)
1289         {         
1290           gtk_paint_flat_box (widget->style, entry->text_area,
1291                               GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
1292                               NULL, widget, "entry_bg", 
1293                               0, 0, -1, -1);
1294
1295           if (editable->editable)
1296             gtk_entry_draw_cursor (entry);
1297           return;
1298         }
1299
1300       gdk_window_get_size (entry->text_area, &width, &height);
1301
1302       /*
1303         If the widget has focus, draw on a backing pixmap to avoid flickering
1304         and copy it to the text_area.
1305         Otherwise draw to text_area directly for better speed.
1306       */
1307       use_backing_pixmap = GTK_WIDGET_HAS_FOCUS (widget) && (entry->text != NULL);
1308       if (use_backing_pixmap)
1309         {
1310            gtk_entry_make_backing_pixmap (entry, width, height);
1311            drawable = entry->backing_pixmap;
1312         }
1313        else
1314          {
1315             drawable = entry->text_area;
1316          }
1317        gtk_paint_flat_box (widget->style, drawable, 
1318                            GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
1319                            NULL, widget, "entry_bg", 
1320                            0, 0, width, height);
1321
1322       y = (height - (widget->style->font->ascent + widget->style->font->descent)) / 2;
1323       y += widget->style->font->ascent;
1324
1325       start_pos = gtk_entry_find_position (entry, entry->scroll_offset);
1326       start_xoffset = entry->char_offset[start_pos] - entry->scroll_offset;
1327
1328       end_pos = gtk_entry_find_position (entry, entry->scroll_offset + width);
1329       if (end_pos < entry->text_length)
1330         end_pos += 1;
1331
1332       selected_state = GTK_STATE_SELECTED;
1333       if (!editable->has_selection)
1334         selected_state = GTK_STATE_ACTIVE;
1335
1336       selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos);
1337       selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos);
1338       
1339       selection_start_pos = CLAMP (selection_start_pos, start_pos, end_pos);
1340       selection_end_pos = CLAMP (selection_end_pos, start_pos, end_pos);
1341
1342       selection_start_xoffset = 
1343         entry->char_offset[selection_start_pos] - entry->scroll_offset;
1344       selection_end_xoffset = 
1345         entry->char_offset[selection_end_pos] -entry->scroll_offset;
1346
1347       /* if entry->visible, print a bunch of stars.  If not, print the standard text. */
1348       if (entry->visible)
1349         {
1350           toprint = entry->text + start_pos;
1351         }
1352       else
1353         {
1354           gint i;
1355           
1356           stars = g_new (GdkWChar, end_pos - start_pos);
1357           for (i = 0; i < end_pos - start_pos; i++)
1358             stars[i] = '*';
1359           toprint = stars;
1360         }
1361       
1362       if (selection_start_pos > start_pos)
1363         gdk_draw_text_wc (drawable, widget->style->font,
1364                           widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
1365                           INNER_BORDER + start_xoffset, y,
1366                           toprint,
1367                           selection_start_pos - start_pos);
1368       
1369       if ((selection_end_pos >= start_pos) && 
1370           (selection_start_pos < end_pos) &&
1371           (selection_start_pos != selection_end_pos))
1372          {
1373             gtk_paint_flat_box (widget->style, drawable, 
1374                                 selected_state, GTK_SHADOW_NONE,
1375                                 NULL, widget, "text",
1376                                 INNER_BORDER + selection_start_xoffset,
1377                                 INNER_BORDER,
1378                                 selection_end_xoffset - selection_start_xoffset,
1379                                 height - 2*INNER_BORDER);
1380             gdk_draw_text_wc (drawable, widget->style->font,
1381                               widget->style->fg_gc[selected_state],
1382                               INNER_BORDER + selection_start_xoffset, y,
1383                               toprint + selection_start_pos - start_pos,
1384                               selection_end_pos - selection_start_pos);
1385          }          
1386        
1387        if (selection_end_pos < end_pos)
1388          gdk_draw_text_wc (drawable, widget->style->font,
1389                            widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
1390                            INNER_BORDER + selection_end_xoffset, y,
1391                            toprint + selection_end_pos - start_pos,
1392                            end_pos - selection_end_pos);
1393        /* free the space allocated for the stars if it's neccessary. */
1394       if (!entry->visible)
1395         g_free (toprint);
1396
1397       if (editable->editable)
1398         gtk_entry_draw_cursor_on_drawable (entry, drawable);
1399
1400       if (use_backing_pixmap)
1401         gdk_draw_pixmap(entry->text_area,
1402                         widget->style->fg_gc[GTK_STATE_NORMAL],
1403                         entry->backing_pixmap,
1404                         0, 0, 0, 0, width, height);       
1405     }
1406 }
1407
1408 static void
1409 gtk_entry_draw_cursor (GtkEntry *entry)
1410 {
1411   g_return_if_fail (entry != NULL);
1412   g_return_if_fail (GTK_IS_ENTRY (entry));
1413
1414   gtk_entry_draw_cursor_on_drawable (entry, entry->text_area);
1415 }
1416
1417 static void
1418 gtk_entry_draw_cursor_on_drawable (GtkEntry *entry, GdkDrawable *drawable)
1419 {
1420   GtkWidget *widget;
1421   GtkEditable *editable;
1422   gint xoffset;
1423   gint text_area_height;
1424
1425   g_return_if_fail (entry != NULL);
1426   g_return_if_fail (GTK_IS_ENTRY (entry));
1427
1428   if (GTK_WIDGET_DRAWABLE (entry))
1429     {
1430       widget = GTK_WIDGET (entry);
1431       editable = GTK_EDITABLE (entry);
1432
1433       xoffset = INNER_BORDER + entry->char_offset[editable->current_pos];
1434       xoffset -= entry->scroll_offset;
1435
1436       gdk_window_get_size (entry->text_area, NULL, &text_area_height);
1437
1438       if (GTK_WIDGET_HAS_FOCUS (widget) &&
1439           (editable->selection_start_pos == editable->selection_end_pos))
1440         {
1441           gdk_draw_line (drawable, widget->style->fg_gc[GTK_STATE_NORMAL], 
1442                          xoffset, INNER_BORDER,
1443                          xoffset, text_area_height - INNER_BORDER);
1444         }
1445       else
1446         {
1447           gint yoffset = 
1448             (text_area_height - 
1449              (widget->style->font->ascent + widget->style->font->descent)) / 2
1450             + widget->style->font->ascent;
1451
1452           gtk_paint_flat_box (widget->style, drawable,
1453                               GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
1454                               NULL, widget, "entry_bg", 
1455                               xoffset, INNER_BORDER, 
1456                               1, text_area_height - INNER_BORDER);
1457           /* Draw the character under the cursor again */
1458
1459           gdk_draw_text_wc (drawable, widget->style->font,
1460                             widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
1461                             xoffset, yoffset,
1462                             entry->text + editable->current_pos, 1);
1463     }
1464
1465
1466 #ifdef USE_XIM
1467       if (GTK_WIDGET_HAS_FOCUS(widget) && gdk_im_ready() && editable->ic && 
1468           (gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION))
1469         {
1470           editable->ic_attr->spot_location.x = xoffset;
1471           editable->ic_attr->spot_location.y =
1472             (text_area_height + (widget->style->font->ascent
1473                 - widget->style->font->descent) + 1) / 2;
1474
1475           gdk_ic_set_attr (editable->ic,
1476                            editable->ic_attr, GDK_IC_SPOT_LOCATION);
1477         }
1478 #endif 
1479     }
1480 }
1481
1482 static void
1483 gtk_entry_queue_draw (GtkEntry *entry)
1484 {
1485   g_return_if_fail (entry != NULL);
1486   g_return_if_fail (GTK_IS_ENTRY (entry));
1487
1488   if (!entry->timer)
1489     entry->timer = gtk_timeout_add (DRAW_TIMEOUT, gtk_entry_timer, entry);
1490 }
1491
1492 static gint
1493 gtk_entry_timer (gpointer data)
1494 {
1495   GtkEntry *entry;
1496
1497   GDK_THREADS_ENTER ();
1498
1499   entry = GTK_ENTRY (data);
1500   entry->timer = 0;
1501   gtk_entry_draw_text (entry);
1502
1503   GDK_THREADS_LEAVE ();
1504
1505   return FALSE;
1506 }
1507
1508 static gint
1509 gtk_entry_find_position (GtkEntry *entry,
1510                          gint      x)
1511 {
1512   gint start = 0;
1513   gint end = entry->text_length;
1514   gint half;
1515
1516   if (x <= 0)
1517     return 0;
1518   if (x >= entry->char_offset[end])
1519     return end;
1520   
1521   /* invariant - char_offset[start] <= x < char_offset[end] */
1522
1523   while (start != end)
1524     {
1525       half = (start+end)/2;
1526       if (half == start)
1527         return half;
1528       else if (entry->char_offset[half] <= x)
1529         start = half;
1530       else
1531         end = half;
1532     }
1533
1534   return start;
1535 }
1536
1537 static gint
1538 gtk_entry_position (GtkEntry *entry,
1539                     gint      x)
1540 {
1541   return gtk_entry_find_position(entry, x);
1542 }
1543
1544 void
1545 gtk_entry_adjust_scroll (GtkEntry *entry)
1546 {
1547   g_return_if_fail (entry != NULL);
1548   g_return_if_fail (GTK_IS_ENTRY (entry));
1549
1550   g_message ("gtk_entry_adjust_scroll() is deprecated");
1551
1552   entry_adjust_scroll (entry);
1553 }
1554
1555 static void
1556 entry_adjust_scroll (GtkEntry *entry)
1557 {
1558   gint xoffset, max_offset;
1559   gint text_area_width;
1560
1561   g_return_if_fail (entry != NULL);
1562   g_return_if_fail (GTK_IS_ENTRY (entry));
1563
1564   if (!entry->text_area)
1565     return;
1566
1567   gdk_window_get_size (entry->text_area, &text_area_width, NULL);
1568
1569   /* Display as much text as we can */
1570   max_offset = MAX(0, entry->char_offset[entry->text_length] - text_area_width);
1571
1572   if (entry->scroll_offset > max_offset)
1573     entry->scroll_offset = max_offset;
1574
1575   /* And make sure cursor is on screen */
1576   xoffset = entry->char_offset[GTK_EDITABLE(entry)->current_pos];
1577   xoffset -= entry->scroll_offset;
1578
1579   if (xoffset < 0)
1580     entry->scroll_offset += xoffset;
1581   else if (xoffset > text_area_width)
1582     entry->scroll_offset += xoffset - text_area_width + 1;
1583
1584   gtk_widget_queue_draw (GTK_WIDGET (entry));
1585 }
1586
1587 static void
1588 gtk_entry_grow_text (GtkEntry *entry)
1589 {
1590   gint previous_size;
1591   gint i;
1592
1593   g_return_if_fail (entry != NULL);
1594   g_return_if_fail (GTK_IS_ENTRY (entry));
1595
1596   previous_size = entry->text_size;
1597   if (!entry->text_size)
1598     entry->text_size = 128;
1599   else
1600     entry->text_size *= 2;
1601   entry->text = g_realloc (entry->text, entry->text_size * sizeof(GdkWChar));
1602   entry->char_offset = g_realloc (entry->char_offset, 
1603                                   entry->text_size * sizeof(guint));
1604
1605   if (entry->text_length == 0)  /* initial allocation */
1606     {
1607       entry->char_offset[0] = 0;
1608     }
1609
1610   for (i = previous_size; i < entry->text_size; i++)
1611     entry->text[i] = '\0';
1612 }
1613
1614 static void
1615 gtk_entry_insert_text (GtkEditable *editable,
1616                        const gchar *new_text,
1617                        gint         new_text_length,
1618                        gint        *position)
1619 {
1620   GdkWChar *text;
1621   gint start_pos;
1622   gint end_pos;
1623   gint last_pos;
1624   gint max_length;
1625   gint i;
1626
1627   guchar *new_text_nt;
1628   gint insertion_length;
1629   GdkWChar *insertion_text;
1630   
1631   GtkEntry *entry;
1632   GtkWidget *widget;
1633   
1634   g_return_if_fail (editable != NULL);
1635   g_return_if_fail (GTK_IS_ENTRY (editable));
1636
1637   entry = GTK_ENTRY (editable);
1638   widget = GTK_WIDGET (editable);
1639
1640   if ((entry->text_length == 0) && (entry->use_wchar == FALSE))
1641     {
1642       if (!GTK_WIDGET_REALIZED (widget))
1643         gtk_widget_ensure_style (widget);
1644       if ((widget->style) && (widget->style->font->type == GDK_FONT_FONTSET))
1645         entry->use_wchar = TRUE;
1646     }
1647
1648   if (new_text_length < 0)
1649     {
1650       new_text_nt = (gchar *)new_text;
1651       new_text_length = strlen (new_text);
1652       if (new_text_length <= 0) return;
1653     }
1654   else if (new_text_length == 0)
1655     {
1656       return;
1657     }
1658   else
1659     {
1660       /* make a null-terminated copy of new_text */
1661       new_text_nt = g_new (gchar, new_text_length + 1);
1662       memcpy (new_text_nt, new_text, new_text_length);
1663       new_text_nt[new_text_length] = 0;
1664     }
1665     
1666   /* The algorithms here will work as long as, the text size (a
1667    * multiple of 2), fits into a guint16 but we specify a shorter
1668    * maximum length so that if the user pastes a very long text, there
1669    * is not a long hang from the slow X_LOCALE functions.  */
1670  
1671   if (entry->text_max_length == 0)
1672     max_length = 2047;
1673   else
1674     max_length = MIN (2047, entry->text_max_length);
1675
1676   /* Convert to wide characters */
1677   insertion_text = g_new (GdkWChar, new_text_length);
1678   if (entry->use_wchar)
1679     insertion_length = gdk_mbstowcs (insertion_text, new_text_nt,
1680                                      new_text_length);
1681   else
1682     for (insertion_length=0; new_text_nt[insertion_length]; insertion_length++)
1683       insertion_text[insertion_length] = new_text_nt[insertion_length];
1684   if (new_text_nt != (guchar *)new_text)
1685     g_free (new_text_nt);
1686
1687   /* Make sure we do not exceed the maximum size of the entry. */
1688   if (insertion_length + entry->text_length > max_length)
1689     insertion_length = max_length - entry->text_length;
1690
1691   /* Don't insert anything, if there was nothing to insert. */
1692   if (insertion_length <= 0)
1693     {
1694       g_free(insertion_text);
1695       return;
1696     }
1697
1698   /* Make sure we are inserting at integral character position */
1699   start_pos = *position;
1700   if (start_pos < 0)
1701     start_pos = 0;
1702   else if (start_pos > entry->text_length)
1703     start_pos = entry->text_length;
1704
1705   end_pos = start_pos + insertion_length;
1706   last_pos = insertion_length + entry->text_length;
1707
1708   if (editable->selection_start_pos >= *position)
1709     editable->selection_start_pos += insertion_length;
1710   if (editable->selection_end_pos >= *position)
1711     editable->selection_end_pos += insertion_length;
1712
1713   while (last_pos >= entry->text_size)
1714     gtk_entry_grow_text (entry);
1715
1716   text = entry->text;
1717   for (i = last_pos - 1; i >= end_pos; i--)
1718     text[i] = text[i- (end_pos - start_pos)];
1719   for (i = start_pos; i < end_pos; i++)
1720     text[i] = insertion_text[i - start_pos];
1721   g_free (insertion_text);
1722
1723   /* Fix up the the character offsets */
1724   
1725   if (GTK_WIDGET_REALIZED (entry))
1726     {
1727       gint offset = 0;
1728       
1729       for (i = last_pos; i >= end_pos; i--)
1730         entry->char_offset[i] 
1731           = entry->char_offset[i - insertion_length];
1732       
1733       for (i=start_pos; i<end_pos; i++)
1734         {
1735           entry->char_offset[i] = entry->char_offset[start_pos] + offset;
1736           if (entry->visible)
1737             {
1738               offset += gdk_char_width_wc (GTK_WIDGET (entry)->style->font,
1739                                            entry->text[i]);
1740             }
1741           else
1742             {
1743               offset += gdk_char_width (GTK_WIDGET (entry)->style->font, '*');
1744             }
1745         }
1746       for (i = end_pos; i <= last_pos; i++)
1747         entry->char_offset[i] += offset;
1748     }
1749
1750   entry->text_length += insertion_length;
1751   *position = end_pos;
1752
1753   entry->text_mb_dirty = 1;
1754   gtk_entry_queue_draw (entry);
1755 }
1756
1757 /* Recompute the x offsets of all characters in the buffer */
1758 static void
1759 gtk_entry_recompute_offsets (GtkEntry *entry)
1760 {
1761   gint i;
1762   gint offset = 0;
1763
1764   for (i=0; i<entry->text_length; i++)
1765     {
1766       entry->char_offset[i] = offset;
1767       if (entry->visible)
1768         {
1769           offset += gdk_char_width_wc (GTK_WIDGET (entry)->style->font,
1770                                        entry->text[i]);
1771         }
1772       else
1773         {
1774           offset += gdk_char_width (GTK_WIDGET (entry)->style->font, '*');
1775         }
1776     }
1777
1778   entry->char_offset[i] = offset;
1779 }
1780
1781 static void
1782 gtk_entry_delete_text (GtkEditable *editable,
1783                        gint         start_pos,
1784                        gint         end_pos)
1785 {
1786   GdkWChar *text;
1787   gint deletion_length;
1788   gint i;
1789
1790   GtkEntry *entry;
1791   
1792   g_return_if_fail (editable != NULL);
1793   g_return_if_fail (GTK_IS_ENTRY (editable));
1794
1795   entry = GTK_ENTRY (editable);
1796
1797   if (end_pos < 0)
1798     end_pos = entry->text_length;
1799
1800   if (editable->selection_start_pos > start_pos)
1801     editable->selection_start_pos -= MIN(end_pos, editable->selection_start_pos) - start_pos;
1802   if (editable->selection_end_pos > start_pos)
1803     editable->selection_end_pos -= MIN(end_pos, editable->selection_end_pos) - start_pos;
1804   
1805   if ((start_pos < end_pos) &&
1806       (start_pos >= 0) &&
1807       (end_pos <= entry->text_length))
1808     {
1809       text = entry->text;
1810       deletion_length = end_pos - start_pos;
1811
1812       /* Fix up the character offsets */
1813       if (GTK_WIDGET_REALIZED (entry))
1814         {
1815           gint deletion_width = 
1816             entry->char_offset[end_pos] - entry->char_offset[start_pos];
1817
1818           for (i = 0 ; i <= entry->text_length - end_pos; i++)
1819             entry->char_offset[start_pos+i] = entry->char_offset[end_pos+i] - deletion_width;
1820         }
1821
1822       for (i = end_pos; i < entry->text_length; i++)
1823         text[i - deletion_length] = text[i];
1824
1825       for (i = entry->text_length - deletion_length; i < entry->text_length; i++)
1826         text[i] = '\0';
1827
1828       entry->text_length -= deletion_length;
1829       editable->current_pos = start_pos;
1830     }
1831
1832   entry->text_mb_dirty = 1;
1833   gtk_entry_queue_draw (entry);
1834 }
1835
1836 static void
1837 gtk_entry_update_text (GtkEditable *editable,
1838                        gint         start_pos,
1839                        gint         end_pos)
1840 {
1841   gtk_entry_queue_draw (GTK_ENTRY(editable));
1842 }
1843
1844 static gchar *    
1845 gtk_entry_get_chars      (GtkEditable   *editable,
1846                           gint           start_pos,
1847                           gint           end_pos)
1848 {
1849   GtkEntry *entry;
1850   
1851   g_return_val_if_fail (editable != NULL, NULL);
1852   g_return_val_if_fail (GTK_IS_ENTRY (editable), NULL);
1853
1854   entry = GTK_ENTRY (editable);
1855
1856   if (end_pos < 0)
1857     end_pos = entry->text_length;
1858
1859   start_pos = MIN(entry->text_length, start_pos);
1860   end_pos = MIN(entry->text_length, end_pos);
1861
1862   if (start_pos <= end_pos)
1863     {
1864       guchar *mbstr;
1865       if (entry->use_wchar)
1866         {
1867           GdkWChar ch;
1868           if (end_pos >= entry->text_size)
1869             gtk_entry_grow_text(entry);
1870           ch = entry->text[end_pos];
1871           entry->text[end_pos] = 0;
1872           mbstr = gdk_wcstombs (entry->text + start_pos);
1873           entry->text[end_pos] = ch;
1874           return (gchar *)mbstr;
1875         }
1876       else
1877         {
1878           gint i;
1879           mbstr = g_new (gchar, end_pos - start_pos + 1);
1880           for (i=0; i<end_pos-start_pos; i++)
1881             mbstr[i] = entry->text[start_pos + i];
1882           mbstr[i] = 0;
1883           return (gchar *)mbstr;
1884         }
1885     }
1886   else
1887     return NULL;
1888 }
1889
1890 static void 
1891 gtk_entry_move_cursor (GtkEditable *editable,
1892                        gint         x,
1893                        gint         y)
1894 {
1895   GtkEntry *entry;
1896   entry = GTK_ENTRY (editable);
1897
1898   /* Horizontal motion */
1899   if ((gint)editable->current_pos < -x)
1900     editable->current_pos = 0;
1901   else if (editable->current_pos + x > entry->text_length)
1902     editable->current_pos = entry->text_length;
1903   else
1904     editable->current_pos += x;
1905
1906   /* Ignore vertical motion */
1907 }
1908
1909 static void
1910 gtk_move_forward_character (GtkEntry *entry)
1911 {
1912   gtk_entry_move_cursor (GTK_EDITABLE (entry), 1, 0);
1913 }
1914
1915 static void
1916 gtk_move_backward_character (GtkEntry *entry)
1917 {
1918   gtk_entry_move_cursor (GTK_EDITABLE (entry), -1, 0);
1919 }
1920
1921 static void 
1922 gtk_entry_move_word (GtkEditable *editable,
1923                      gint         n)
1924 {
1925   while (n-- > 0)
1926     gtk_move_forward_word (GTK_ENTRY (editable));
1927   while (n++ < 0)
1928     gtk_move_backward_word (GTK_ENTRY (editable));
1929 }
1930
1931 static void
1932 gtk_move_forward_word (GtkEntry *entry)
1933 {
1934   GtkEditable *editable;
1935   GdkWChar *text;
1936   gint i;
1937
1938   editable = GTK_EDITABLE (entry);
1939
1940   if (entry->text && (editable->current_pos < entry->text_length))
1941     {
1942       text = entry->text;
1943       i = editable->current_pos;
1944           
1945       if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
1946         for (; i < entry->text_length; i++)
1947           {
1948             if ((entry->use_wchar) ? gdk_iswalnum (text[i]) : isalnum (text[i]))
1949               break;
1950           }
1951
1952       for (; i < entry->text_length; i++)
1953         {
1954           if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
1955             break;
1956         }
1957
1958       editable->current_pos = i;
1959     }
1960 }
1961
1962 static void
1963 gtk_move_backward_word (GtkEntry *entry)
1964 {
1965   GtkEditable *editable;
1966   GdkWChar *text;
1967   gint i;
1968
1969   editable = GTK_EDITABLE (entry);
1970
1971   if (entry->text && editable->current_pos > 0)
1972     {
1973       text = entry->text;
1974       i = editable->current_pos - 1;
1975       if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
1976         for (; i >= 0; i--)
1977           {
1978             if ((entry->use_wchar) ? gdk_iswalnum (text[i]) : isalnum (text[i]))
1979               break;
1980           }
1981       for (; i >= 0; i--)
1982         {
1983           if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
1984             {
1985               i++;
1986               break;
1987             }
1988         }
1989           
1990       if (i < 0)
1991         i = 0;
1992           
1993       editable->current_pos = i;
1994     }
1995 }
1996
1997 static void
1998 gtk_entry_move_to_column (GtkEditable *editable, gint column)
1999 {
2000   GtkEntry *entry;
2001
2002   entry = GTK_ENTRY (editable);
2003   
2004   if (column < 0 || column > entry->text_length)
2005     editable->current_pos = entry->text_length;
2006   else
2007     editable->current_pos = column;
2008 }
2009
2010 static void
2011 gtk_move_beginning_of_line (GtkEntry *entry)
2012 {
2013   gtk_entry_move_to_column (GTK_EDITABLE (entry), 0);
2014 }
2015
2016 static void
2017 gtk_move_end_of_line (GtkEntry *entry)
2018 {
2019   gtk_entry_move_to_column (GTK_EDITABLE (entry), -1);
2020 }
2021
2022 static void
2023 gtk_entry_kill_char (GtkEditable *editable,
2024                      gint         direction)
2025 {
2026   if (editable->selection_start_pos != editable->selection_end_pos)
2027     gtk_editable_delete_selection (editable);
2028   else
2029     {
2030       gint old_pos = editable->current_pos;
2031       if (direction >= 0)
2032         {
2033           gtk_entry_move_cursor (editable, 1, 0);
2034           gtk_editable_delete_text (editable, old_pos, editable->current_pos);
2035         }
2036       else
2037         {
2038           gtk_entry_move_cursor (editable, -1, 0);
2039           gtk_editable_delete_text (editable, editable->current_pos, old_pos);
2040         }
2041     }
2042 }
2043
2044 static void
2045 gtk_delete_forward_character (GtkEntry *entry)
2046 {
2047   gtk_entry_kill_char (GTK_EDITABLE (entry), 1);
2048 }
2049
2050 static void
2051 gtk_delete_backward_character (GtkEntry *entry)
2052 {
2053   gtk_entry_kill_char (GTK_EDITABLE (entry), -1);
2054 }
2055
2056 static void
2057 gtk_entry_kill_word (GtkEditable *editable,
2058                      gint         direction)
2059 {
2060   if (editable->selection_start_pos != editable->selection_end_pos)
2061     gtk_editable_delete_selection (editable);
2062   else
2063     {
2064       gint old_pos = editable->current_pos;
2065       if (direction >= 0)
2066         {
2067           gtk_entry_move_word (editable, 1);
2068           gtk_editable_delete_text (editable, old_pos, editable->current_pos);
2069         }
2070       else
2071         {
2072           gtk_entry_move_word (editable, -1);
2073           gtk_editable_delete_text (editable, editable->current_pos, old_pos);
2074         }
2075     }
2076 }
2077
2078 static void
2079 gtk_delete_forward_word (GtkEntry *entry)
2080 {
2081   gtk_entry_kill_word (GTK_EDITABLE (entry), 1);
2082 }
2083
2084 static void
2085 gtk_delete_backward_word (GtkEntry *entry)
2086 {
2087   gtk_entry_kill_word (GTK_EDITABLE (entry), -1);
2088 }
2089
2090 static void
2091 gtk_entry_kill_line (GtkEditable *editable,
2092                      gint         direction)
2093 {
2094   gint old_pos = editable->current_pos;
2095   if (direction >= 0)
2096     {
2097       gtk_entry_move_to_column (editable, -1);
2098       gtk_editable_delete_text (editable, old_pos, editable->current_pos);
2099     }
2100   else
2101     {
2102       gtk_entry_move_to_column (editable, 0);
2103       gtk_editable_delete_text (editable, editable->current_pos, old_pos);
2104     }
2105 }
2106
2107 static void
2108 gtk_delete_line (GtkEntry *entry)
2109 {
2110   gtk_entry_move_to_column (GTK_EDITABLE (entry), 0);
2111   gtk_entry_kill_line (GTK_EDITABLE (entry), 1);
2112 }
2113
2114 static void
2115 gtk_delete_to_line_end (GtkEntry *entry)
2116 {
2117   gtk_editable_delete_text (GTK_EDITABLE(entry), GTK_EDITABLE(entry)->current_pos, entry->text_length);
2118 }
2119
2120 static void
2121 gtk_select_word (GtkEntry *entry,
2122                  guint32   time)
2123 {
2124   GtkEditable *editable;
2125   gint start_pos;
2126   gint end_pos;
2127
2128   editable = GTK_EDITABLE (entry);
2129
2130   gtk_move_backward_word (entry);
2131   start_pos = editable->current_pos;
2132
2133   gtk_move_forward_word (entry);
2134   end_pos = editable->current_pos;
2135
2136   editable->has_selection = TRUE;
2137   gtk_entry_set_selection (editable, start_pos, end_pos);
2138   gtk_editable_claim_selection (editable, start_pos != end_pos, time);
2139 }
2140
2141 static void
2142 gtk_select_line (GtkEntry *entry,
2143                  guint32   time)
2144 {
2145   GtkEditable *editable;
2146
2147   editable = GTK_EDITABLE (entry);
2148
2149   editable->has_selection = TRUE;
2150   gtk_entry_set_selection (editable, 0, entry->text_length);
2151   gtk_editable_claim_selection (editable, entry->text_length != 0, time);
2152
2153   editable->current_pos = editable->selection_end_pos;
2154 }
2155
2156 static void 
2157 gtk_entry_set_selection (GtkEditable       *editable,
2158                          gint               start,
2159                          gint               end)
2160 {
2161   g_return_if_fail (editable != NULL);
2162   g_return_if_fail (GTK_IS_ENTRY (editable));
2163
2164   if (end < 0)
2165     end = GTK_ENTRY (editable)->text_length;
2166   
2167   editable->selection_start_pos = start;
2168   editable->selection_end_pos = end;
2169
2170   gtk_entry_queue_draw (GTK_ENTRY (editable));
2171 }
2172
2173 void       
2174 gtk_entry_select_region  (GtkEntry       *entry,
2175                           gint            start,
2176                           gint            end)
2177 {
2178   gtk_editable_select_region (GTK_EDITABLE (entry), start, end);
2179 }
2180
2181 void
2182 gtk_entry_set_max_length (GtkEntry     *entry,
2183                           guint16       max)
2184 {
2185   g_return_if_fail (entry != NULL);
2186   g_return_if_fail (GTK_IS_ENTRY (entry));
2187
2188   if (max && entry->text_length > max)
2189         gtk_editable_delete_text(GTK_EDITABLE(entry), max, -1);
2190   entry->text_max_length = max;
2191 }
2192
2193 #ifdef USE_XIM
2194 static void
2195 gtk_entry_update_ic_attr (GtkWidget *widget)
2196 {
2197   GtkEditable *editable = (GtkEditable *) widget;
2198   GdkICAttributesType mask = 0;
2199
2200   gdk_ic_get_attr (editable->ic, editable->ic_attr,
2201                    GDK_IC_PREEDIT_FOREGROUND |
2202                    GDK_IC_PREEDIT_BACKGROUND |
2203                    GDK_IC_PREEDIT_FONTSET);
2204
2205   if (editable->ic_attr->preedit_foreground.pixel != 
2206       widget->style->fg[GTK_STATE_NORMAL].pixel)
2207     {
2208       mask |= GDK_IC_PREEDIT_FOREGROUND;
2209       editable->ic_attr->preedit_foreground
2210         = widget->style->fg[GTK_STATE_NORMAL];
2211     }
2212   if (editable->ic_attr->preedit_background.pixel != 
2213       widget->style->base[GTK_STATE_NORMAL].pixel)
2214     {
2215       mask |= GDK_IC_PREEDIT_BACKGROUND;
2216       editable->ic_attr->preedit_background
2217         = widget->style->base[GTK_STATE_NORMAL];
2218     }
2219   if ((gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION) && 
2220       !gdk_font_equal (editable->ic_attr->preedit_fontset,
2221                        widget->style->font))
2222     {
2223       mask |= GDK_IC_PREEDIT_FONTSET;
2224       editable->ic_attr->preedit_fontset = widget->style->font;
2225     }
2226   
2227   if (mask)
2228     gdk_ic_set_attr (editable->ic, editable->ic_attr, mask);
2229 }
2230 #endif /* USE_XIM */
2231                           
2232 static void 
2233 gtk_entry_style_set     (GtkWidget      *widget,
2234                          GtkStyle       *previous_style)
2235 {
2236   GtkEntry *entry;
2237   gint scroll_char;
2238
2239   g_return_if_fail (widget != NULL);
2240   g_return_if_fail (GTK_IS_ENTRY (widget));
2241
2242   if (previous_style && GTK_WIDGET_REALIZED (widget))
2243     {
2244       entry = GTK_ENTRY (widget);
2245   
2246       scroll_char = gtk_entry_find_position (entry, entry->scroll_offset);
2247       gtk_entry_recompute_offsets (GTK_ENTRY (widget));
2248       entry->scroll_offset = entry->char_offset[scroll_char];
2249       entry_adjust_scroll (entry);
2250
2251       gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2252       gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2253
2254 #ifdef USE_XIM
2255       gtk_entry_update_ic_attr (widget);
2256 #endif
2257     }
2258
2259   if (GTK_WIDGET_DRAWABLE (widget))
2260     gtk_widget_queue_clear(widget);
2261 }
2262
2263 static void
2264 gtk_entry_state_changed (GtkWidget      *widget,
2265                          GtkStateType    previous_state)
2266 {
2267   g_return_if_fail (widget != NULL);
2268   g_return_if_fail (GTK_IS_ENTRY (widget));
2269
2270   if (GTK_WIDGET_REALIZED (widget))
2271     {
2272       gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2273       gdk_window_set_background (GTK_ENTRY (widget)->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2274
2275 #ifdef USE_XIM
2276       gtk_entry_update_ic_attr (widget);
2277 #endif
2278     }
2279
2280   if (GTK_WIDGET_DRAWABLE (widget))
2281     gtk_widget_queue_clear(widget);
2282 }