]> Pileus Git - ~andy/gtk/blob - gtk/gtkentry.c
Destroy widgets _after_ propagating unrealize signals through the widget
[~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, 0, xoffset, text_area_height);
1443         }
1444       else
1445         {
1446           gtk_paint_flat_box (widget->style, drawable,
1447                               GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
1448                               NULL, widget, "entry_bg", 
1449                               xoffset, 0, 1, text_area_height);
1450         }
1451
1452 #ifdef USE_XIM
1453       if (GTK_WIDGET_HAS_FOCUS(widget) && gdk_im_ready() && editable->ic && 
1454           (gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION))
1455         {
1456           editable->ic_attr->spot_location.x = xoffset;
1457           editable->ic_attr->spot_location.y =
1458             (text_area_height + (widget->style->font->ascent
1459                 - widget->style->font->descent) + 1) / 2;
1460
1461           gdk_ic_set_attr (editable->ic,
1462                            editable->ic_attr, GDK_IC_SPOT_LOCATION);
1463         }
1464 #endif 
1465     }
1466 }
1467
1468 static void
1469 gtk_entry_queue_draw (GtkEntry *entry)
1470 {
1471   g_return_if_fail (entry != NULL);
1472   g_return_if_fail (GTK_IS_ENTRY (entry));
1473
1474   if (!entry->timer)
1475     entry->timer = gtk_timeout_add (DRAW_TIMEOUT, gtk_entry_timer, entry);
1476 }
1477
1478 static gint
1479 gtk_entry_timer (gpointer data)
1480 {
1481   GtkEntry *entry;
1482
1483   g_return_val_if_fail (data != NULL, FALSE);
1484
1485   entry = GTK_ENTRY (data);
1486   entry->timer = 0;
1487   gtk_entry_draw_text (entry);
1488
1489   return FALSE;
1490 }
1491
1492 static gint
1493 gtk_entry_find_position (GtkEntry *entry,
1494                          gint      x)
1495 {
1496   gint start = 0;
1497   gint end = entry->text_length;
1498   gint half;
1499
1500   if (x <= 0)
1501     return 0;
1502   if (x >= entry->char_offset[end])
1503     return end;
1504   
1505   /* invariant - char_offset[start] <= x < char_offset[end] */
1506
1507   while (start != end)
1508     {
1509       half = (start+end)/2;
1510       if (half == start)
1511         return half;
1512       else if (entry->char_offset[half] <= x)
1513         start = half;
1514       else
1515         end = half;
1516     }
1517
1518   return start;
1519 }
1520
1521 static gint
1522 gtk_entry_position (GtkEntry *entry,
1523                     gint      x)
1524 {
1525   return gtk_entry_find_position(entry, x);
1526 }
1527
1528 void
1529 gtk_entry_adjust_scroll (GtkEntry *entry)
1530 {
1531   g_return_if_fail (entry != NULL);
1532   g_return_if_fail (GTK_IS_ENTRY (entry));
1533
1534   g_message ("gtk_entry_adjust_scroll() is deprecated");
1535
1536   entry_adjust_scroll (entry);
1537 }
1538
1539 static void
1540 entry_adjust_scroll (GtkEntry *entry)
1541 {
1542   gint xoffset, max_offset;
1543   gint text_area_width;
1544
1545   g_return_if_fail (entry != NULL);
1546   g_return_if_fail (GTK_IS_ENTRY (entry));
1547
1548   if (!entry->text_area)
1549     return;
1550
1551   gdk_window_get_size (entry->text_area, &text_area_width, NULL);
1552
1553   /* Display as much text as we can */
1554   max_offset = MAX(0, entry->char_offset[entry->text_length] - text_area_width);
1555
1556   if (entry->scroll_offset > max_offset)
1557     entry->scroll_offset = max_offset;
1558
1559   /* And make sure cursor is on screen */
1560   xoffset = entry->char_offset[GTK_EDITABLE(entry)->current_pos];
1561   xoffset -= entry->scroll_offset;
1562
1563   if (xoffset < 0)
1564     entry->scroll_offset += xoffset;
1565   else if (xoffset > text_area_width)
1566     entry->scroll_offset += xoffset - text_area_width + 1;
1567
1568   gtk_widget_queue_draw (GTK_WIDGET (entry));
1569 }
1570
1571 static void
1572 gtk_entry_grow_text (GtkEntry *entry)
1573 {
1574   gint previous_size;
1575   gint i;
1576
1577   g_return_if_fail (entry != NULL);
1578   g_return_if_fail (GTK_IS_ENTRY (entry));
1579
1580   previous_size = entry->text_size;
1581   if (!entry->text_size)
1582     entry->text_size = 128;
1583   else
1584     entry->text_size *= 2;
1585   entry->text = g_realloc (entry->text, entry->text_size * sizeof(GdkWChar));
1586   entry->char_offset = g_realloc (entry->char_offset, 
1587                                   entry->text_size * sizeof(guint));
1588
1589   if (entry->text_length == 0)  /* initial allocation */
1590     {
1591       entry->char_offset[0] = 0;
1592     }
1593
1594   for (i = previous_size; i < entry->text_size; i++)
1595     entry->text[i] = '\0';
1596 }
1597
1598 static void
1599 gtk_entry_insert_text (GtkEditable *editable,
1600                        const gchar *new_text,
1601                        gint         new_text_length,
1602                        gint        *position)
1603 {
1604   GdkWChar *text;
1605   gint start_pos;
1606   gint end_pos;
1607   gint last_pos;
1608   gint max_length;
1609   gint i;
1610
1611   guchar *new_text_nt;
1612   gint insertion_length;
1613   GdkWChar *insertion_text;
1614   
1615   GtkEntry *entry;
1616   GtkWidget *widget;
1617   
1618   g_return_if_fail (editable != NULL);
1619   g_return_if_fail (GTK_IS_ENTRY (editable));
1620
1621   entry = GTK_ENTRY (editable);
1622   widget = GTK_WIDGET (editable);
1623
1624   if ((entry->text_length == 0) && (entry->use_wchar == FALSE))
1625     {
1626       if (!GTK_WIDGET_REALIZED (widget))
1627         gtk_widget_ensure_style (widget);
1628       if ((widget->style) && (widget->style->font->type == GDK_FONT_FONTSET))
1629         entry->use_wchar = TRUE;
1630     }
1631
1632   if (new_text_length < 0)
1633     {
1634       new_text_nt = (gchar *)new_text;
1635       new_text_length = strlen (new_text);
1636       if (new_text_length <= 0) return;
1637     }
1638   else if (new_text_length == 0)
1639     {
1640       return;
1641     }
1642   else
1643     {
1644       /* make a null-terminated copy of new_text */
1645       new_text_nt = g_new (gchar, new_text_length + 1);
1646       memcpy (new_text_nt, new_text, new_text_length);
1647       new_text_nt[new_text_length] = 0;
1648     }
1649     
1650   /* The algorithms here will work as long as, the text size (a
1651    * multiple of 2), fits into a guint16 but we specify a shorter
1652    * maximum length so that if the user pastes a very long text, there
1653    * is not a long hang from the slow X_LOCALE functions.  */
1654  
1655   if (entry->text_max_length == 0)
1656     max_length = 2047;
1657   else
1658     max_length = MIN (2047, entry->text_max_length);
1659
1660   /* Convert to wide characters */
1661   insertion_text = g_new (GdkWChar, new_text_length);
1662   if (entry->use_wchar)
1663     insertion_length = gdk_mbstowcs (insertion_text, new_text_nt,
1664                                      new_text_length);
1665   else
1666     for (insertion_length=0; new_text_nt[insertion_length]; insertion_length++)
1667       insertion_text[insertion_length] = new_text_nt[insertion_length];
1668   if (new_text_nt != (guchar *)new_text)
1669     g_free (new_text_nt);
1670
1671   /* Make sure we do not exceed the maximum size of the entry. */
1672   if (insertion_length + entry->text_length > max_length)
1673     insertion_length = max_length - entry->text_length;
1674
1675   /* Don't insert anything, if there was nothing to insert. */
1676   if (insertion_length <= 0)
1677     {
1678       g_free(insertion_text);
1679       return;
1680     }
1681
1682   /* Make sure we are inserting at integral character position */
1683   start_pos = *position;
1684   if (start_pos < 0)
1685     start_pos = 0;
1686   else if (start_pos > entry->text_length)
1687     start_pos = entry->text_length;
1688
1689   end_pos = start_pos + insertion_length;
1690   last_pos = insertion_length + entry->text_length;
1691
1692   if (editable->selection_start_pos >= *position)
1693     editable->selection_start_pos += insertion_length;
1694   if (editable->selection_end_pos >= *position)
1695     editable->selection_end_pos += insertion_length;
1696
1697   while (last_pos >= entry->text_size)
1698     gtk_entry_grow_text (entry);
1699
1700   text = entry->text;
1701   for (i = last_pos - 1; i >= end_pos; i--)
1702     text[i] = text[i- (end_pos - start_pos)];
1703   for (i = start_pos; i < end_pos; i++)
1704     text[i] = insertion_text[i - start_pos];
1705   g_free (insertion_text);
1706
1707   /* Fix up the the character offsets */
1708   
1709   if (GTK_WIDGET_REALIZED (entry))
1710     {
1711       gint offset = 0;
1712       
1713       for (i = last_pos; i >= end_pos; i--)
1714         entry->char_offset[i] 
1715           = entry->char_offset[i - insertion_length];
1716       
1717       for (i=start_pos; i<end_pos; i++)
1718         {
1719           entry->char_offset[i] = entry->char_offset[start_pos] + offset;
1720           if (entry->visible)
1721             {
1722               offset += gdk_char_width_wc (GTK_WIDGET (entry)->style->font,
1723                                            entry->text[i]);
1724             }
1725           else
1726             {
1727               offset += gdk_char_width (GTK_WIDGET (entry)->style->font, '*');
1728             }
1729         }
1730       for (i = end_pos; i <= last_pos; i++)
1731         entry->char_offset[i] += offset;
1732     }
1733
1734   entry->text_length += insertion_length;
1735   *position = end_pos;
1736
1737   entry->text_mb_dirty = 1;
1738   gtk_entry_queue_draw (entry);
1739 }
1740
1741 /* Recompute the x offsets of all characters in the buffer */
1742 static void
1743 gtk_entry_recompute_offsets (GtkEntry *entry)
1744 {
1745   gint i;
1746   gint offset = 0;
1747
1748   for (i=0; i<entry->text_length; i++)
1749     {
1750       entry->char_offset[i] = offset;
1751       if (entry->visible)
1752         {
1753           offset += gdk_char_width_wc (GTK_WIDGET (entry)->style->font,
1754                                        entry->text[i]);
1755         }
1756       else
1757         {
1758           offset += gdk_char_width (GTK_WIDGET (entry)->style->font, '*');
1759         }
1760     }
1761
1762   entry->char_offset[i] = offset;
1763 }
1764
1765 static void
1766 gtk_entry_delete_text (GtkEditable *editable,
1767                        gint         start_pos,
1768                        gint         end_pos)
1769 {
1770   GdkWChar *text;
1771   gint deletion_length;
1772   gint i;
1773
1774   GtkEntry *entry;
1775   
1776   g_return_if_fail (editable != NULL);
1777   g_return_if_fail (GTK_IS_ENTRY (editable));
1778
1779   entry = GTK_ENTRY (editable);
1780
1781   if (end_pos < 0)
1782     end_pos = entry->text_length;
1783
1784   if (editable->selection_start_pos > start_pos)
1785     editable->selection_start_pos -= MIN(end_pos, editable->selection_start_pos) - start_pos;
1786   if (editable->selection_end_pos > start_pos)
1787     editable->selection_end_pos -= MIN(end_pos, editable->selection_end_pos) - start_pos;
1788   
1789   if ((start_pos < end_pos) &&
1790       (start_pos >= 0) &&
1791       (end_pos <= entry->text_length))
1792     {
1793       text = entry->text;
1794       deletion_length = end_pos - start_pos;
1795
1796       /* Fix up the character offsets */
1797       if (GTK_WIDGET_REALIZED (entry))
1798         {
1799           gint deletion_width = 
1800             entry->char_offset[end_pos] - entry->char_offset[start_pos];
1801
1802           for (i = 0 ; i <= entry->text_length - end_pos; i++)
1803             entry->char_offset[start_pos+i] = entry->char_offset[end_pos+i] - deletion_width;
1804         }
1805
1806       for (i = end_pos; i < entry->text_length; i++)
1807         text[i - deletion_length] = text[i];
1808
1809       for (i = entry->text_length - deletion_length; i < entry->text_length; i++)
1810         text[i] = '\0';
1811
1812       entry->text_length -= deletion_length;
1813       editable->current_pos = start_pos;
1814     }
1815
1816   entry->text_mb_dirty = 1;
1817   gtk_entry_queue_draw (entry);
1818 }
1819
1820 static void
1821 gtk_entry_update_text (GtkEditable *editable,
1822                        gint         start_pos,
1823                        gint         end_pos)
1824 {
1825   gtk_entry_queue_draw (GTK_ENTRY(editable));
1826 }
1827
1828 static gchar *    
1829 gtk_entry_get_chars      (GtkEditable   *editable,
1830                           gint           start_pos,
1831                           gint           end_pos)
1832 {
1833   GtkEntry *entry;
1834   
1835   g_return_val_if_fail (editable != NULL, NULL);
1836   g_return_val_if_fail (GTK_IS_ENTRY (editable), NULL);
1837
1838   entry = GTK_ENTRY (editable);
1839
1840   if (end_pos < 0)
1841     end_pos = entry->text_length;
1842
1843   start_pos = MIN(entry->text_length, start_pos);
1844   end_pos = MIN(entry->text_length, end_pos);
1845
1846   if (start_pos <= end_pos)
1847     {
1848       guchar *mbstr;
1849       if (entry->use_wchar)
1850         {
1851           GdkWChar ch;
1852           if (end_pos >= entry->text_size)
1853             gtk_entry_grow_text(entry);
1854           ch = entry->text[end_pos];
1855           entry->text[end_pos] = 0;
1856           mbstr = gdk_wcstombs (entry->text + start_pos);
1857           entry->text[end_pos] = ch;
1858           return (gchar *)mbstr;
1859         }
1860       else
1861         {
1862           gint i;
1863           mbstr = g_new (gchar, end_pos - start_pos + 1);
1864           for (i=0; i<end_pos-start_pos; i++)
1865             mbstr[i] = entry->text[start_pos + i];
1866           mbstr[i] = 0;
1867           return (gchar *)mbstr;
1868         }
1869     }
1870   else
1871     return NULL;
1872 }
1873
1874 static void 
1875 gtk_entry_move_cursor (GtkEditable *editable,
1876                        gint         x,
1877                        gint         y)
1878 {
1879   GtkEntry *entry;
1880   entry = GTK_ENTRY (editable);
1881
1882   /* Horizontal motion */
1883   if ((gint)editable->current_pos < -x)
1884     editable->current_pos = 0;
1885   else if (editable->current_pos + x > entry->text_length)
1886     editable->current_pos = entry->text_length;
1887   else
1888     editable->current_pos += x;
1889
1890   /* Ignore vertical motion */
1891 }
1892
1893 static void
1894 gtk_move_forward_character (GtkEntry *entry)
1895 {
1896   gtk_entry_move_cursor (GTK_EDITABLE (entry), 1, 0);
1897 }
1898
1899 static void
1900 gtk_move_backward_character (GtkEntry *entry)
1901 {
1902   gtk_entry_move_cursor (GTK_EDITABLE (entry), -1, 0);
1903 }
1904
1905 static void 
1906 gtk_entry_move_word (GtkEditable *editable,
1907                      gint         n)
1908 {
1909   while (n-- > 0)
1910     gtk_move_forward_word (GTK_ENTRY (editable));
1911   while (n++ < 0)
1912     gtk_move_backward_word (GTK_ENTRY (editable));
1913 }
1914
1915 static void
1916 gtk_move_forward_word (GtkEntry *entry)
1917 {
1918   GtkEditable *editable;
1919   GdkWChar *text;
1920   gint i;
1921
1922   editable = GTK_EDITABLE (entry);
1923
1924   if (entry->text && (editable->current_pos < entry->text_length))
1925     {
1926       text = entry->text;
1927       i = editable->current_pos;
1928           
1929       if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
1930         for (; i < entry->text_length; i++)
1931           {
1932             if ((entry->use_wchar) ? gdk_iswalnum (text[i]) : isalnum (text[i]))
1933               break;
1934           }
1935
1936       for (; i < entry->text_length; i++)
1937         {
1938           if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
1939             break;
1940         }
1941
1942       editable->current_pos = i;
1943     }
1944 }
1945
1946 static void
1947 gtk_move_backward_word (GtkEntry *entry)
1948 {
1949   GtkEditable *editable;
1950   GdkWChar *text;
1951   gint i;
1952
1953   editable = GTK_EDITABLE (entry);
1954
1955   if (entry->text && editable->current_pos > 0)
1956     {
1957       text = entry->text;
1958       i = editable->current_pos - 1;
1959       if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
1960         for (; i >= 0; i--)
1961           {
1962             if ((entry->use_wchar) ? gdk_iswalnum (text[i]) : isalnum (text[i]))
1963               break;
1964           }
1965       for (; i >= 0; i--)
1966         {
1967           if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
1968             {
1969               i++;
1970               break;
1971             }
1972         }
1973           
1974       if (i < 0)
1975         i = 0;
1976           
1977       editable->current_pos = i;
1978     }
1979 }
1980
1981 static void
1982 gtk_entry_move_to_column (GtkEditable *editable, gint column)
1983 {
1984   GtkEntry *entry;
1985
1986   entry = GTK_ENTRY (editable);
1987   
1988   if (column < 0 || column > entry->text_length)
1989     editable->current_pos = entry->text_length;
1990   else
1991     editable->current_pos = column;
1992 }
1993
1994 static void
1995 gtk_move_beginning_of_line (GtkEntry *entry)
1996 {
1997   gtk_entry_move_to_column (GTK_EDITABLE (entry), 0);
1998 }
1999
2000 static void
2001 gtk_move_end_of_line (GtkEntry *entry)
2002 {
2003   gtk_entry_move_to_column (GTK_EDITABLE (entry), -1);
2004 }
2005
2006 static void
2007 gtk_entry_kill_char (GtkEditable *editable,
2008                      gint         direction)
2009 {
2010   if (editable->selection_start_pos != editable->selection_end_pos)
2011     gtk_editable_delete_selection (editable);
2012   else
2013     {
2014       gint old_pos = editable->current_pos;
2015       if (direction >= 0)
2016         {
2017           gtk_entry_move_cursor (editable, 1, 0);
2018           gtk_editable_delete_text (editable, old_pos, editable->current_pos);
2019         }
2020       else
2021         {
2022           gtk_entry_move_cursor (editable, -1, 0);
2023           gtk_editable_delete_text (editable, editable->current_pos, old_pos);
2024         }
2025     }
2026 }
2027
2028 static void
2029 gtk_delete_forward_character (GtkEntry *entry)
2030 {
2031   gtk_entry_kill_char (GTK_EDITABLE (entry), 1);
2032 }
2033
2034 static void
2035 gtk_delete_backward_character (GtkEntry *entry)
2036 {
2037   gtk_entry_kill_char (GTK_EDITABLE (entry), -1);
2038 }
2039
2040 static void
2041 gtk_entry_kill_word (GtkEditable *editable,
2042                      gint         direction)
2043 {
2044   if (editable->selection_start_pos != editable->selection_end_pos)
2045     gtk_editable_delete_selection (editable);
2046   else
2047     {
2048       gint old_pos = editable->current_pos;
2049       if (direction >= 0)
2050         {
2051           gtk_entry_move_word (editable, 1);
2052           gtk_editable_delete_text (editable, old_pos, editable->current_pos);
2053         }
2054       else
2055         {
2056           gtk_entry_move_word (editable, -1);
2057           gtk_editable_delete_text (editable, editable->current_pos, old_pos);
2058         }
2059     }
2060 }
2061
2062 static void
2063 gtk_delete_forward_word (GtkEntry *entry)
2064 {
2065   gtk_entry_kill_word (GTK_EDITABLE (entry), 1);
2066 }
2067
2068 static void
2069 gtk_delete_backward_word (GtkEntry *entry)
2070 {
2071   gtk_entry_kill_word (GTK_EDITABLE (entry), -1);
2072 }
2073
2074 static void
2075 gtk_entry_kill_line (GtkEditable *editable,
2076                      gint         direction)
2077 {
2078   gint old_pos = editable->current_pos;
2079   if (direction >= 0)
2080     {
2081       gtk_entry_move_to_column (editable, -1);
2082       gtk_editable_delete_text (editable, old_pos, editable->current_pos);
2083     }
2084   else
2085     {
2086       gtk_entry_move_to_column (editable, 0);
2087       gtk_editable_delete_text (editable, editable->current_pos, old_pos);
2088     }
2089 }
2090
2091 static void
2092 gtk_delete_line (GtkEntry *entry)
2093 {
2094   gtk_entry_move_to_column (GTK_EDITABLE (entry), 0);
2095   gtk_entry_kill_line (GTK_EDITABLE (entry), 1);
2096 }
2097
2098 static void
2099 gtk_delete_to_line_end (GtkEntry *entry)
2100 {
2101   gtk_editable_delete_text (GTK_EDITABLE(entry), GTK_EDITABLE(entry)->current_pos, entry->text_length);
2102 }
2103
2104 static void
2105 gtk_select_word (GtkEntry *entry,
2106                  guint32   time)
2107 {
2108   GtkEditable *editable;
2109   gint start_pos;
2110   gint end_pos;
2111
2112   editable = GTK_EDITABLE (entry);
2113
2114   gtk_move_backward_word (entry);
2115   start_pos = editable->current_pos;
2116
2117   gtk_move_forward_word (entry);
2118   end_pos = editable->current_pos;
2119
2120   editable->has_selection = TRUE;
2121   gtk_entry_set_selection (editable, start_pos, end_pos);
2122   gtk_editable_claim_selection (editable, start_pos != end_pos, time);
2123 }
2124
2125 static void
2126 gtk_select_line (GtkEntry *entry,
2127                  guint32   time)
2128 {
2129   GtkEditable *editable;
2130
2131   editable = GTK_EDITABLE (entry);
2132
2133   editable->has_selection = TRUE;
2134   gtk_entry_set_selection (editable, 0, entry->text_length);
2135   gtk_editable_claim_selection (editable, entry->text_length != 0, time);
2136
2137   editable->current_pos = editable->selection_end_pos;
2138 }
2139
2140 static void 
2141 gtk_entry_set_selection (GtkEditable       *editable,
2142                          gint               start,
2143                          gint               end)
2144 {
2145   g_return_if_fail (editable != NULL);
2146   g_return_if_fail (GTK_IS_ENTRY (editable));
2147
2148   if (end < 0)
2149     end = GTK_ENTRY (editable)->text_length;
2150   
2151   editable->selection_start_pos = start;
2152   editable->selection_end_pos = end;
2153
2154   gtk_entry_queue_draw (GTK_ENTRY (editable));
2155 }
2156
2157 void       
2158 gtk_entry_select_region  (GtkEntry       *entry,
2159                           gint            start,
2160                           gint            end)
2161 {
2162   gtk_editable_select_region (GTK_EDITABLE (entry), start, end);
2163 }
2164
2165 void
2166 gtk_entry_set_max_length (GtkEntry     *entry,
2167                           guint16       max)
2168 {
2169   g_return_if_fail (entry != NULL);
2170   g_return_if_fail (GTK_IS_ENTRY (entry));
2171
2172   if (max && entry->text_length > max)
2173         gtk_editable_delete_text(GTK_EDITABLE(entry), max, -1);
2174   entry->text_max_length = max;
2175 }
2176
2177 #ifdef USE_XIM
2178 static void
2179 gtk_entry_update_ic_attr (GtkWidget *widget)
2180 {
2181   GtkEditable *editable = (GtkEditable *) widget;
2182   GdkICAttributesType mask = 0;
2183
2184   gdk_ic_get_attr (editable->ic, editable->ic_attr,
2185                    GDK_IC_PREEDIT_FOREGROUND |
2186                    GDK_IC_PREEDIT_BACKGROUND |
2187                    GDK_IC_PREEDIT_FONTSET);
2188
2189   if (editable->ic_attr->preedit_foreground.pixel != 
2190       widget->style->fg[GTK_STATE_NORMAL].pixel)
2191     {
2192       mask |= GDK_IC_PREEDIT_FOREGROUND;
2193       editable->ic_attr->preedit_foreground
2194         = widget->style->fg[GTK_STATE_NORMAL];
2195     }
2196   if (editable->ic_attr->preedit_background.pixel != 
2197       widget->style->base[GTK_STATE_NORMAL].pixel)
2198     {
2199       mask |= GDK_IC_PREEDIT_BACKGROUND;
2200       editable->ic_attr->preedit_background
2201         = widget->style->base[GTK_STATE_NORMAL];
2202     }
2203   if ((gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION) && 
2204       !gdk_font_equal (editable->ic_attr->preedit_fontset,
2205                        widget->style->font))
2206     {
2207       mask |= GDK_IC_PREEDIT_FONTSET;
2208       editable->ic_attr->preedit_fontset = widget->style->font;
2209     }
2210   
2211   if (mask)
2212     gdk_ic_set_attr (editable->ic, editable->ic_attr, mask);
2213 }
2214 #endif /* USE_XIM */
2215                           
2216 static void 
2217 gtk_entry_style_set     (GtkWidget      *widget,
2218                          GtkStyle       *previous_style)
2219 {
2220   GtkEntry *entry;
2221   gint scroll_char;
2222
2223   g_return_if_fail (widget != NULL);
2224   g_return_if_fail (GTK_IS_ENTRY (widget));
2225
2226   if (previous_style && GTK_WIDGET_REALIZED (widget))
2227     {
2228       entry = GTK_ENTRY (widget);
2229   
2230       scroll_char = gtk_entry_find_position (entry, entry->scroll_offset);
2231       gtk_entry_recompute_offsets (GTK_ENTRY (widget));
2232       entry->scroll_offset = entry->char_offset[scroll_char];
2233       entry_adjust_scroll (entry);
2234
2235       gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2236       gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2237
2238 #ifdef USE_XIM
2239       gtk_entry_update_ic_attr (widget);
2240 #endif
2241     }
2242
2243   if (GTK_WIDGET_DRAWABLE (widget))
2244     gtk_widget_queue_clear(widget);
2245 }
2246
2247 static void
2248 gtk_entry_state_changed (GtkWidget      *widget,
2249                          GtkStateType    previous_state)
2250 {
2251   g_return_if_fail (widget != NULL);
2252   g_return_if_fail (GTK_IS_ENTRY (widget));
2253
2254   if (GTK_WIDGET_REALIZED (widget))
2255     {
2256       gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2257       gdk_window_set_background (GTK_ENTRY (widget)->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2258
2259 #ifdef USE_XIM
2260       gtk_entry_update_ic_attr (widget);
2261 #endif
2262     }
2263
2264   if (GTK_WIDGET_DRAWABLE (widget))
2265     gtk_widget_queue_clear(widget);
2266 }