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