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