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