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