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