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