]> Pileus Git - ~andy/gtk/blob - gtk/gtkentry.c
Fix problem where computation was depending on widget->allocation instead
[~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 Lesser 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <ctype.h>
28 #include <string.h>
29 #include "gdk/gdkkeysyms.h"
30 #include "gdk/gdki18n.h"
31 #include "gtkentry.h"
32 #include "gtkimmulticontext.h"
33 #include "gtkmain.h"
34 #include "gtkselection.h"
35 #include "gtksignal.h"
36 #include "gtkstyle.h"
37
38 #include <pango/pango.h>
39 #include <glib-object.h>
40
41 #define MIN_ENTRY_WIDTH  150
42 #define DRAW_TIMEOUT     20
43 #define INNER_BORDER     2
44
45 /* Initial size of buffer, in bytes */
46 #define MIN_SIZE 16
47
48 /* Maximum size of text buffer, in bytes */
49 #define MAX_SIZE G_MAXUSHORT
50
51 enum {
52   ARG_0,
53   ARG_MAX_LENGTH,
54   ARG_VISIBILITY
55 };
56
57
58 static void   gtk_entry_class_init           (GtkEntryClass    *klass);
59 static void   gtk_entry_init                 (GtkEntry         *entry);
60 static void   gtk_entry_set_arg              (GtkObject        *object,
61                                               GtkArg           *arg,
62                                               guint             arg_id);
63 static void   gtk_entry_get_arg              (GtkObject        *object,
64                                               GtkArg           *arg,
65                                               guint             arg_id);
66 static void   gtk_entry_finalize             (GObject          *object);
67 static void   gtk_entry_realize              (GtkWidget        *widget);
68 static void   gtk_entry_unrealize            (GtkWidget        *widget);
69 static void   gtk_entry_draw_focus           (GtkWidget        *widget);
70 static void   gtk_entry_size_request         (GtkWidget        *widget,
71                                               GtkRequisition   *requisition);
72 static void   gtk_entry_size_allocate        (GtkWidget        *widget,
73                                               GtkAllocation    *allocation);
74 static void   gtk_entry_draw                 (GtkWidget        *widget,
75                                               GdkRectangle     *area);
76 static gint   gtk_entry_expose               (GtkWidget        *widget,
77                                               GdkEventExpose   *event);
78 static gint   gtk_entry_button_press         (GtkWidget        *widget,
79                                               GdkEventButton   *event);
80 static gint   gtk_entry_button_release       (GtkWidget        *widget,
81                                               GdkEventButton   *event);
82 static gint   gtk_entry_motion_notify        (GtkWidget        *widget,
83                                               GdkEventMotion   *event);
84 static gint   gtk_entry_key_press            (GtkWidget        *widget,
85                                               GdkEventKey      *event);
86 static gint   gtk_entry_focus_in             (GtkWidget        *widget,
87                                               GdkEventFocus    *event);
88 static gint   gtk_entry_focus_out            (GtkWidget        *widget,
89                                               GdkEventFocus    *event);
90 static void   gtk_entry_draw_text            (GtkEntry         *entry);
91 static void   gtk_entry_ensure_layout        (GtkEntry         *entry);
92 static void   gtk_entry_draw_cursor          (GtkEntry         *entry);
93 static void   gtk_entry_style_set            (GtkWidget        *widget,
94                                               GtkStyle         *previous_style);
95 static void   gtk_entry_direction_changed    (GtkWidget        *widget,
96                                               GtkTextDirection  previous_dir);
97 static void   gtk_entry_state_changed        (GtkWidget        *widget,
98                                               GtkStateType      previous_state);
99 static void   gtk_entry_queue_draw           (GtkEntry         *entry);
100 static gint   gtk_entry_find_position        (GtkEntry         *entry,
101                                               gint              x);
102 static void   gtk_entry_get_cursor_locations (GtkEntry         *entry,
103                                               gint             *strong_x,
104                                               gint             *weak_x);
105 static void   entry_adjust_scroll            (GtkEntry         *entry);
106 static void   gtk_entry_insert_text          (GtkEditable      *editable,
107                                               const gchar      *new_text,
108                                               gint              new_text_length,
109                                               gint             *position);
110 static void   gtk_entry_delete_text          (GtkEditable      *editable,
111                                               gint              start_pos,
112                                               gint              end_pos);
113 static void   gtk_entry_update_text          (GtkEditable      *editable,
114                                               gint              start_pos,
115                                               gint              end_pos);
116 static gchar *gtk_entry_get_chars            (GtkEditable      *editable,
117                                               gint              start_pos,
118                                               gint              end_pos);
119
120 /* Binding actions */
121 static void gtk_entry_move_cursor         (GtkEditable *editable,
122                                            gint         x,
123                                            gint         y);
124 static void gtk_entry_move_word           (GtkEditable *editable,
125                                            gint         n);
126 static void gtk_entry_move_to_column      (GtkEditable *editable,
127                                            gint         row);
128 static void gtk_entry_kill_char           (GtkEditable *editable,
129                                            gint         direction);
130 static void gtk_entry_kill_word           (GtkEditable *editable,
131                                            gint         direction);
132 static void gtk_entry_kill_line           (GtkEditable *editable,
133                                            gint         direction);
134
135 /* To be removed */
136 static void gtk_move_forward_character    (GtkEntry          *entry);
137 static void gtk_move_backward_character   (GtkEntry          *entry);
138 static void gtk_move_forward_word         (GtkEntry          *entry);
139 static void gtk_move_backward_word        (GtkEntry          *entry);
140 static void gtk_move_beginning_of_line    (GtkEntry          *entry);
141 static void gtk_move_end_of_line          (GtkEntry          *entry);
142 static void gtk_delete_forward_character  (GtkEntry          *entry);
143 static void gtk_delete_backward_character (GtkEntry          *entry);
144 static void gtk_delete_forward_word       (GtkEntry          *entry);
145 static void gtk_delete_backward_word      (GtkEntry          *entry);
146 static void gtk_delete_line               (GtkEntry          *entry);
147 static void gtk_delete_to_line_end        (GtkEntry          *entry);
148 static void gtk_select_word               (GtkEntry          *entry,
149                                            guint32            time);
150 static void gtk_select_line               (GtkEntry          *entry,
151                                            guint32            time);
152
153
154 static void gtk_entry_set_selection       (GtkEditable       *editable,
155                                            gint               start,
156                                            gint               end);
157
158 static void gtk_entry_set_position_from_editable (GtkEditable *editable,
159                                                   gint         position);
160
161 static void gtk_entry_commit_cb           (GtkIMContext      *context,
162                                            const gchar       *str,
163                                            GtkEntry          *entry);
164
165
166 static GtkWidgetClass *parent_class = NULL;
167 static GdkAtom ctext_atom = GDK_NONE;
168
169 static const GtkTextFunction control_keys[26] =
170 {
171   (GtkTextFunction)gtk_move_beginning_of_line,    /* a */
172   (GtkTextFunction)gtk_move_backward_character,   /* b */
173   (GtkTextFunction)gtk_editable_copy_clipboard,   /* c */
174   (GtkTextFunction)gtk_delete_forward_character,  /* d */
175   (GtkTextFunction)gtk_move_end_of_line,          /* e */
176   (GtkTextFunction)gtk_move_forward_character,    /* f */
177   NULL,                                           /* g */
178   (GtkTextFunction)gtk_delete_backward_character, /* h */
179   NULL,                                           /* i */
180   NULL,                                           /* j */
181   (GtkTextFunction)gtk_delete_to_line_end,        /* k */
182   NULL,                                           /* l */
183   NULL,                                           /* m */
184   NULL,                                           /* n */
185   NULL,                                           /* o */
186   NULL,                                           /* p */
187   NULL,                                           /* q */
188   NULL,                                           /* r */
189   NULL,                                           /* s */
190   NULL,                                           /* t */
191   (GtkTextFunction)gtk_delete_line,               /* u */
192   (GtkTextFunction)gtk_editable_paste_clipboard,  /* v */
193   (GtkTextFunction)gtk_delete_backward_word,      /* w */
194   (GtkTextFunction)gtk_editable_cut_clipboard,    /* x */
195   NULL,                                           /* y */
196   NULL,                                           /* z */
197 };
198
199 static const GtkTextFunction alt_keys[26] =
200 {
201   NULL,                                           /* a */
202   (GtkTextFunction)gtk_move_backward_word,        /* b */
203   NULL,                                           /* c */
204   (GtkTextFunction)gtk_delete_forward_word,       /* d */
205   NULL,                                           /* e */
206   (GtkTextFunction)gtk_move_forward_word,         /* f */
207   NULL,                                           /* g */
208   NULL,                                           /* h */
209   NULL,                                           /* i */
210   NULL,                                           /* j */
211   NULL,                                           /* k */
212   NULL,                                           /* l */
213   NULL,                                           /* m */
214   NULL,                                           /* n */
215   NULL,                                           /* o */
216   NULL,                                           /* p */
217   NULL,                                           /* q */
218   NULL,                                           /* r */
219   NULL,                                           /* s */
220   NULL,                                           /* t */
221   NULL,                                           /* u */
222   NULL,                                           /* v */
223   NULL,                                           /* w */
224   NULL,                                           /* x */
225   NULL,                                           /* y */
226   NULL,                                           /* z */
227 };
228
229
230 GtkType
231 gtk_entry_get_type (void)
232 {
233   static GtkType entry_type = 0;
234
235   if (!entry_type)
236     {
237       static const GtkTypeInfo entry_info =
238       {
239         "GtkEntry",
240         sizeof (GtkEntry),
241         sizeof (GtkEntryClass),
242         (GtkClassInitFunc) gtk_entry_class_init,
243         (GtkObjectInitFunc) gtk_entry_init,
244         /* reserved_1 */ NULL,
245         /* reserved_2 */ NULL,
246         (GtkClassInitFunc) NULL,
247       };
248
249       entry_type = gtk_type_unique (GTK_TYPE_EDITABLE, &entry_info);
250     }
251
252   return entry_type;
253 }
254
255 static void
256 gtk_entry_class_init (GtkEntryClass *class)
257 {
258   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
259   GtkObjectClass *object_class;
260   GtkWidgetClass *widget_class;
261   GtkEditableClass *editable_class;
262
263   object_class = (GtkObjectClass*) class;
264   widget_class = (GtkWidgetClass*) class;
265   editable_class = (GtkEditableClass*) class;
266   parent_class = gtk_type_class (GTK_TYPE_EDITABLE);
267
268   gobject_class->finalize = gtk_entry_finalize;
269
270   gtk_object_add_arg_type ("GtkEntry::max_length", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_MAX_LENGTH);
271   gtk_object_add_arg_type ("GtkEntry::visibility", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_VISIBILITY);
272
273   object_class->set_arg = gtk_entry_set_arg;
274   object_class->get_arg = gtk_entry_get_arg;
275
276   widget_class->realize = gtk_entry_realize;
277   widget_class->unrealize = gtk_entry_unrealize;
278   widget_class->draw_focus = gtk_entry_draw_focus;
279   widget_class->size_request = gtk_entry_size_request;
280   widget_class->size_allocate = gtk_entry_size_allocate;
281   widget_class->draw = gtk_entry_draw;
282   widget_class->expose_event = gtk_entry_expose;
283   widget_class->button_press_event = gtk_entry_button_press;
284   widget_class->button_release_event = gtk_entry_button_release;
285   widget_class->motion_notify_event = gtk_entry_motion_notify;
286   widget_class->key_press_event = gtk_entry_key_press;
287   widget_class->focus_in_event = gtk_entry_focus_in;
288   widget_class->focus_out_event = gtk_entry_focus_out;
289   widget_class->style_set = gtk_entry_style_set;
290   widget_class->direction_changed = gtk_entry_direction_changed;
291   widget_class->state_changed = gtk_entry_state_changed;
292
293   editable_class->insert_text = gtk_entry_insert_text;
294   editable_class->delete_text = gtk_entry_delete_text;
295   editable_class->changed = (void (*)(GtkEditable *)) entry_adjust_scroll;
296
297   editable_class->move_cursor = gtk_entry_move_cursor;
298   editable_class->move_word = gtk_entry_move_word;
299   editable_class->move_to_column = gtk_entry_move_to_column;
300
301   editable_class->kill_char = gtk_entry_kill_char;
302   editable_class->kill_word = gtk_entry_kill_word;
303   editable_class->kill_line = gtk_entry_kill_line;
304
305   editable_class->update_text = gtk_entry_update_text;
306   editable_class->get_chars   = gtk_entry_get_chars;
307   editable_class->set_selection = gtk_entry_set_selection;
308   editable_class->set_position = gtk_entry_set_position_from_editable;
309 }
310
311 static void
312 gtk_entry_set_arg (GtkObject      *object,
313                    GtkArg         *arg,
314                    guint           arg_id)
315 {
316   GtkEntry *entry;
317
318   entry = GTK_ENTRY (object);
319
320   switch (arg_id)
321     {
322     case ARG_MAX_LENGTH:
323       gtk_entry_set_max_length (entry, GTK_VALUE_UINT (*arg));
324       break;
325     case ARG_VISIBILITY:
326       gtk_entry_set_visibility (entry, GTK_VALUE_BOOL (*arg));
327       break;
328     default:
329       break;
330     }
331 }
332
333 static void
334 gtk_entry_get_arg (GtkObject      *object,
335                    GtkArg         *arg,
336                    guint           arg_id)
337 {
338   GtkEntry *entry;
339
340   entry = GTK_ENTRY (object);
341
342   switch (arg_id)
343     {
344     case ARG_MAX_LENGTH:
345       GTK_VALUE_UINT (*arg) = entry->text_max_length;
346       break;
347     case ARG_VISIBILITY:
348       GTK_VALUE_BOOL (*arg) = GTK_EDITABLE (entry)->visible;
349       break;
350     default:
351       arg->type = GTK_TYPE_INVALID;
352       break;
353     }
354 }
355
356 static void
357 gtk_entry_init (GtkEntry *entry)
358 {
359   GTK_WIDGET_SET_FLAGS (entry, GTK_CAN_FOCUS);
360
361   entry->text_area = NULL;
362   
363   entry->text_size = MIN_SIZE;
364   entry->text = g_malloc (entry->text_size);
365   entry->text[0] = '\0';
366   
367   entry->text_length = 0;
368   entry->text_max_length = 0;
369   entry->n_bytes = 0;
370   entry->scroll_offset = 0;
371   entry->timer = 0;
372   entry->button = 0;
373   entry->ascent = 0;
374   entry->descent = 0;
375
376   /* This object is completely private. No external entity can gain a reference
377    * to it; so we create it here and destroy it in finalize().
378    */
379   entry->im_context = gtk_im_multicontext_new ();
380   
381   gtk_signal_connect (GTK_OBJECT (entry->im_context), "commit",
382                       GTK_SIGNAL_FUNC (gtk_entry_commit_cb), entry);
383 }
384
385 GtkWidget*
386 gtk_entry_new (void)
387 {
388   return GTK_WIDGET (gtk_type_new (GTK_TYPE_ENTRY));
389 }
390
391 GtkWidget*
392 gtk_entry_new_with_max_length (guint16 max)
393 {
394   GtkEntry *entry;
395
396   entry = gtk_type_new (GTK_TYPE_ENTRY);
397   entry->text_max_length = max;
398
399   return GTK_WIDGET (entry);
400 }
401
402 void
403 gtk_entry_set_text (GtkEntry *entry,
404                     const gchar *text)
405 {
406   gint tmp_pos;
407
408   GtkEditable *editable;
409
410   g_return_if_fail (entry != NULL);
411   g_return_if_fail (GTK_IS_ENTRY (entry));
412   g_return_if_fail (text != NULL);
413
414   editable = GTK_EDITABLE (entry);
415   
416   gtk_entry_delete_text (GTK_EDITABLE(entry), 0, entry->text_length);
417
418   tmp_pos = 0;
419   gtk_editable_insert_text (editable, text, strlen (text), &tmp_pos);
420   editable->current_pos = tmp_pos;
421 }
422
423 void
424 gtk_entry_append_text (GtkEntry *entry,
425                        const gchar *text)
426 {
427   gint tmp_pos;
428
429   g_return_if_fail (entry != NULL);
430   g_return_if_fail (GTK_IS_ENTRY (entry));
431   g_return_if_fail (text != NULL);
432
433   tmp_pos = entry->text_length;
434   gtk_editable_insert_text (GTK_EDITABLE(entry), text, strlen (text), &tmp_pos);
435 }
436
437 void
438 gtk_entry_prepend_text (GtkEntry *entry,
439                         const gchar *text)
440 {
441   gint tmp_pos;
442
443   g_return_if_fail (entry != NULL);
444   g_return_if_fail (GTK_IS_ENTRY (entry));
445   g_return_if_fail (text != NULL);
446
447   tmp_pos = 0;
448   gtk_editable_insert_text (GTK_EDITABLE(entry), text, strlen (text), &tmp_pos);
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     GTK_EDITABLE(entry)->current_pos = entry->text_length;
460   else
461     GTK_EDITABLE(entry)->current_pos = position;
462   entry_adjust_scroll (entry);
463 }
464
465 static void
466 gtk_entry_set_position_from_editable (GtkEditable *editable,
467                                       gint position)
468 {
469   gtk_entry_set_position (GTK_ENTRY (editable), position);
470 }
471
472 void
473 gtk_entry_set_visibility (GtkEntry *entry,
474                           gboolean visible)
475 {
476   g_return_if_fail (entry != NULL);
477   g_return_if_fail (GTK_IS_ENTRY (entry));
478
479   GTK_EDITABLE (entry)->visible = visible ? TRUE : FALSE;
480   
481   gtk_entry_queue_draw (entry);
482 }
483
484 void
485 gtk_entry_set_editable(GtkEntry *entry,
486                        gboolean  editable)
487 {
488   g_return_if_fail (entry != NULL);
489   g_return_if_fail (GTK_IS_ENTRY (entry));
490
491   gtk_editable_set_editable (GTK_EDITABLE (entry), editable);
492 }
493
494 gchar*
495 gtk_entry_get_text (GtkEntry *entry)
496 {
497   g_return_val_if_fail (entry != NULL, NULL);
498   g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
499
500   return entry->text;
501 }
502
503 static void
504 gtk_entry_finalize (GObject *object)
505 {
506   GtkEntry *entry;
507
508   g_return_if_fail (GTK_IS_ENTRY (object));
509
510   entry = GTK_ENTRY (object);
511
512   if (entry->layout)
513     g_object_unref (G_OBJECT (entry->layout));
514
515   gtk_object_unref (GTK_OBJECT (entry->im_context));
516
517   if (entry->timer)
518     gtk_timeout_remove (entry->timer);
519
520   entry->text_size = 0;
521
522   if (entry->text)
523     g_free (entry->text);
524   entry->text = NULL;
525
526   G_OBJECT_CLASS (parent_class)->finalize (object);
527 }
528
529 static void
530 gtk_entry_realize (GtkWidget *widget)
531 {
532   GtkEntry *entry;
533   GtkEditable *editable;
534   GtkRequisition requisition;
535   GdkWindowAttr attributes;
536   gint attributes_mask;
537
538   g_return_if_fail (widget != NULL);
539   g_return_if_fail (GTK_IS_ENTRY (widget));
540
541   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
542   entry = GTK_ENTRY (widget);
543   editable = GTK_EDITABLE (widget);
544
545   gtk_widget_get_child_requisition (widget, &requisition);
546   
547   attributes.window_type = GDK_WINDOW_CHILD;
548   attributes.x = widget->allocation.x;
549   attributes.y = widget->allocation.y + (widget->allocation.height -
550                                          requisition.height) / 2;
551   attributes.width = widget->allocation.width;
552   attributes.height = requisition.height;
553   attributes.wclass = GDK_INPUT_OUTPUT;
554   attributes.visual = gtk_widget_get_visual (widget);
555   attributes.colormap = gtk_widget_get_colormap (widget);
556   attributes.event_mask = gtk_widget_get_events (widget);
557   attributes.event_mask |= (GDK_EXPOSURE_MASK |
558                             GDK_BUTTON_PRESS_MASK |
559                             GDK_BUTTON_RELEASE_MASK |
560                             GDK_BUTTON1_MOTION_MASK |
561                             GDK_BUTTON3_MOTION_MASK |
562                             GDK_POINTER_MOTION_HINT_MASK |
563                             GDK_ENTER_NOTIFY_MASK |
564                             GDK_LEAVE_NOTIFY_MASK |
565                             GDK_KEY_PRESS_MASK);
566   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
567
568   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
569   gdk_window_set_user_data (widget->window, entry);
570
571   attributes.x = widget->style->xthickness;
572   attributes.y = widget->style->ythickness;
573   attributes.width = widget->allocation.width - attributes.x * 2;
574   attributes.height = requisition.height - attributes.y * 2;
575   attributes.cursor = entry->cursor = gdk_cursor_new (GDK_XTERM);
576   attributes_mask |= GDK_WA_CURSOR;
577
578   entry->text_area = gdk_window_new (widget->window, &attributes, attributes_mask);
579   gdk_window_set_user_data (entry->text_area, entry);
580
581   widget->style = gtk_style_attach (widget->style, widget->window);
582
583   gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
584   gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
585
586   gdk_window_show (entry->text_area);
587
588   if (editable->selection_start_pos != editable->selection_end_pos)
589     gtk_editable_claim_selection (editable, TRUE, GDK_CURRENT_TIME);
590
591   gtk_im_context_set_client_window (entry->im_context, entry->text_area);
592
593   entry_adjust_scroll (entry);
594 }
595
596 static void
597 gtk_entry_unrealize (GtkWidget *widget)
598 {
599   GtkEntry *entry;
600
601   g_return_if_fail (widget != NULL);
602   g_return_if_fail (GTK_IS_ENTRY (widget));
603
604   entry = GTK_ENTRY (widget);
605
606   gtk_im_context_set_client_window (entry->im_context, entry->text_area);
607   
608   if (entry->text_area)
609     {
610       gdk_window_set_user_data (entry->text_area, NULL);
611       gdk_window_destroy (entry->text_area);
612       entry->text_area = NULL;
613       gdk_cursor_destroy (entry->cursor);
614       entry->cursor = NULL;
615     }
616
617   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
618     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
619 }
620
621 static void
622 gtk_entry_draw_focus (GtkWidget *widget)
623 {
624   gint width, height;
625   gint x, y;
626
627   g_return_if_fail (widget != NULL);
628   g_return_if_fail (GTK_IS_ENTRY (widget));
629
630   if (GTK_WIDGET_DRAWABLE (widget))
631     {
632       x = 0;
633       y = 0;
634       gdk_window_get_size (widget->window, &width, &height);
635
636       if (GTK_WIDGET_HAS_FOCUS (widget))
637         {
638           x += 1;
639           y += 1;
640           width -= 2;
641           height -= 2;
642         }
643
644       gtk_paint_shadow (widget->style, widget->window,
645                         GTK_STATE_NORMAL, GTK_SHADOW_IN,
646                         NULL, widget, "entry",
647                         x, y, width, height);
648
649       if (GTK_WIDGET_HAS_FOCUS (widget))
650         {
651            gdk_window_get_size (widget->window, &width, &height);
652            gtk_paint_focus (widget->style, widget->window, 
653                             NULL, widget, "entry",
654                             0, 0, width - 1, height - 1);
655         }
656     }
657 }
658
659 static void
660 gtk_entry_size_request (GtkWidget      *widget,
661                         GtkRequisition *requisition)
662 {
663   GtkEntry *entry;
664   PangoFontMetrics metrics;
665   PangoFont *font;
666   gchar *lang;
667   
668   g_return_if_fail (widget != NULL);
669   g_return_if_fail (GTK_IS_ENTRY (widget));
670   g_return_if_fail (requisition != NULL);
671
672   entry = GTK_ENTRY (widget);
673   
674   gtk_entry_ensure_layout (entry);
675
676   /* hackish for now, get metrics
677    */
678   font = pango_context_load_font (pango_layout_get_context (entry->layout),
679                                   widget->style->font_desc);
680   lang = pango_context_get_lang (pango_layout_get_context (entry->layout));
681   pango_font_get_metrics (font, lang, &metrics);
682   g_free (lang);
683   
684   g_object_unref (G_OBJECT (font));
685
686   entry->ascent = metrics.ascent;
687   entry->descent = metrics.descent;
688   
689   requisition->width = MIN_ENTRY_WIDTH + (widget->style->xthickness + INNER_BORDER) * 2;
690   requisition->height = ((metrics.ascent + metrics.descent) / PANGO_SCALE + 
691                          (widget->style->ythickness + INNER_BORDER) * 2);
692 }
693
694 static void
695 gtk_entry_size_allocate (GtkWidget     *widget,
696                          GtkAllocation *allocation)
697 {
698   GtkEntry *entry;
699   GtkEditable *editable;
700
701   g_return_if_fail (widget != NULL);
702   g_return_if_fail (GTK_IS_ENTRY (widget));
703   g_return_if_fail (allocation != NULL);
704
705   widget->allocation = *allocation;
706   entry = GTK_ENTRY (widget);
707   editable = GTK_EDITABLE (widget);
708
709   if (GTK_WIDGET_REALIZED (widget))
710     {
711       /* We call gtk_widget_get_child_requisition, since we want (for
712        * backwards compatibility reasons) the realization here to
713        * be affected by the usize of the entry, if set
714        */
715       GtkRequisition requisition;
716       gtk_widget_get_child_requisition (widget, &requisition);
717   
718       gdk_window_move_resize (widget->window,
719                               allocation->x,
720                               allocation->y + (allocation->height - requisition.height) / 2,
721                               allocation->width, requisition.height);
722       gdk_window_move_resize (entry->text_area,
723                               widget->style->xthickness,
724                               widget->style->ythickness,
725                               allocation->width - widget->style->xthickness * 2,
726                               requisition.height - widget->style->ythickness * 2);
727
728       /* And make sure the cursor is on screen */
729       entry_adjust_scroll (entry);
730     }
731 }
732
733 static void
734 gtk_entry_draw (GtkWidget    *widget,
735                 GdkRectangle *area)
736 {
737   GtkEntry *entry;
738   
739   g_return_if_fail (widget != NULL);
740   g_return_if_fail (GTK_IS_ENTRY (widget));
741   g_return_if_fail (area != NULL);
742
743   entry = GTK_ENTRY (widget);
744   
745   if (GTK_WIDGET_DRAWABLE (widget))
746     {
747       GdkRectangle tmp_area = *area;
748
749       tmp_area.x -= widget->style->xthickness;
750       tmp_area.y -= widget->style->xthickness;
751       
752       gdk_window_begin_paint_rect (entry->text_area, &tmp_area);
753       gtk_widget_draw_focus (widget);
754       gtk_entry_draw_text (GTK_ENTRY (widget));
755       gtk_entry_draw_cursor (GTK_ENTRY (widget));
756       gdk_window_end_paint (entry->text_area);
757     }
758 }
759
760 static gint
761 gtk_entry_expose (GtkWidget      *widget,
762                   GdkEventExpose *event)
763 {
764   GtkEntry *entry;
765
766   g_return_val_if_fail (widget != NULL, FALSE);
767   g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
768   g_return_val_if_fail (event != NULL, FALSE);
769
770   entry = GTK_ENTRY (widget);
771
772   if (widget->window == event->window)
773     gtk_widget_draw_focus (widget);
774   else if (entry->text_area == event->window)
775     {
776       gtk_entry_draw_text (GTK_ENTRY (widget));
777       gtk_entry_draw_cursor (GTK_ENTRY (widget));
778     }
779
780   return FALSE;
781 }
782
783 static gint
784 gtk_entry_button_press (GtkWidget      *widget,
785                         GdkEventButton *event)
786 {
787   GtkEntry *entry;
788   GtkEditable *editable;
789   gint tmp_pos;
790
791   g_return_val_if_fail (widget != NULL, FALSE);
792   g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
793   g_return_val_if_fail (event != NULL, FALSE);
794
795   if (ctext_atom == GDK_NONE)
796     ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
797
798   entry = GTK_ENTRY (widget);
799   editable = GTK_EDITABLE (widget);
800   
801   if (entry->button && (event->button != entry->button))
802     return FALSE;
803
804   entry->button = event->button;
805   
806   if (!GTK_WIDGET_HAS_FOCUS (widget))
807     gtk_widget_grab_focus (widget);
808
809   if (event->button == 1)
810     {
811       switch (event->type)
812         {
813         case GDK_BUTTON_PRESS:
814           gtk_grab_add (widget);
815
816           tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
817           /* Set it now, so we display things right. We'll unset it
818            * later if things don't work out */
819           editable->has_selection = TRUE;
820           gtk_entry_set_selection (editable, tmp_pos, tmp_pos);
821           editable->current_pos = editable->selection_start_pos;
822           break;
823
824         case GDK_2BUTTON_PRESS:
825           gtk_select_word (entry, event->time);
826           break;
827
828         case GDK_3BUTTON_PRESS:
829           gtk_select_line (entry, event->time);
830           break;
831
832         default:
833           break;
834         }
835
836       return TRUE;
837     }
838   else if (event->type == GDK_BUTTON_PRESS)
839     {
840       if ((event->button == 2) && editable->editable)
841         {
842           if (editable->selection_start_pos == editable->selection_end_pos ||
843               editable->has_selection)
844             editable->current_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
845           gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
846                                  ctext_atom, event->time);
847         }
848       else
849         {
850           gtk_grab_add (widget);
851
852           tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
853           gtk_entry_set_selection (editable, tmp_pos, tmp_pos);
854           editable->has_selection = FALSE;
855           editable->current_pos = editable->selection_start_pos;
856
857           if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
858             gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
859         }
860
861       return TRUE;
862     }
863
864   return FALSE;
865 }
866
867 static gint
868 gtk_entry_button_release (GtkWidget      *widget,
869                           GdkEventButton *event)
870 {
871   GtkEntry *entry;
872   GtkEditable *editable;
873
874   g_return_val_if_fail (widget != NULL, FALSE);
875   g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
876   g_return_val_if_fail (event != NULL, FALSE);
877
878   entry = GTK_ENTRY (widget);
879   editable = GTK_EDITABLE (widget);
880
881   if (entry->button != event->button)
882     return FALSE;
883
884   entry->button = 0;
885   
886   if (event->button == 1)
887     {
888       gtk_grab_remove (widget);
889
890       editable->has_selection = FALSE;
891       if (editable->selection_start_pos != editable->selection_end_pos)
892         {
893           if (gtk_selection_owner_set (widget,
894                                        GDK_SELECTION_PRIMARY,
895                                        event->time))
896             editable->has_selection = TRUE;
897           else
898             gtk_entry_queue_draw (entry);
899         }
900       else
901         {
902           if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
903             gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
904         }
905
906       return TRUE;
907     }
908   else if (event->button == 3)
909     {
910       gtk_grab_remove (widget);
911
912       return TRUE;
913     }
914
915   return FALSE;
916 }
917
918 static gint
919 gtk_entry_motion_notify (GtkWidget      *widget,
920                          GdkEventMotion *event)
921 {
922   GtkEntry *entry;
923   gint x;
924
925   g_return_val_if_fail (widget != NULL, FALSE);
926   g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
927   g_return_val_if_fail (event != NULL, FALSE);
928
929   entry = GTK_ENTRY (widget);
930
931   if (entry->button == 0)
932     return FALSE;
933
934   x = event->x;
935   if (event->is_hint || (entry->text_area != event->window))
936     gdk_window_get_pointer (entry->text_area, &x, NULL, NULL);
937
938   GTK_EDITABLE(entry)->selection_end_pos = gtk_entry_find_position (entry, x + entry->scroll_offset);
939   GTK_EDITABLE(entry)->current_pos = GTK_EDITABLE(entry)->selection_end_pos;
940   entry_adjust_scroll (entry);
941   gtk_entry_queue_draw (entry);
942
943   return TRUE;
944 }
945
946 static gint
947 gtk_entry_key_press (GtkWidget   *widget,
948                      GdkEventKey *event)
949 {
950   GtkEntry *entry;
951   GtkEditable *editable;
952
953   gint return_val;
954   gint key;
955   guint initial_pos;
956   gint extend_selection;
957   gint extend_start;
958
959   g_return_val_if_fail (widget != NULL, FALSE);
960   g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
961   g_return_val_if_fail (event != NULL, FALSE);
962
963   entry = GTK_ENTRY (widget);
964   editable = GTK_EDITABLE (widget);
965   return_val = FALSE;
966
967   if(editable->editable == FALSE)
968     return FALSE;
969
970   initial_pos = editable->current_pos;
971
972   extend_selection = event->state & GDK_SHIFT_MASK;
973   extend_start = FALSE;
974
975   if (extend_selection)
976     {
977       if (editable->selection_start_pos == editable->selection_end_pos)
978         {
979           editable->selection_start_pos = editable->current_pos;
980           editable->selection_end_pos = editable->current_pos;
981         }
982       
983       extend_start = (editable->current_pos == editable->selection_start_pos);
984     }
985
986   switch (event->keyval)
987     {
988     case GDK_BackSpace:
989       return_val = TRUE;
990       if (event->state & GDK_CONTROL_MASK)
991         gtk_delete_backward_word (entry);
992       else
993         gtk_delete_backward_character (entry);
994       break;
995     case GDK_Clear:
996       return_val = TRUE;
997       gtk_delete_line (entry);
998       break;
999     case GDK_Insert:
1000       return_val = TRUE;
1001       if (event->state & GDK_SHIFT_MASK)
1002         {
1003           extend_selection = FALSE;
1004           gtk_editable_paste_clipboard (editable);
1005         }
1006       else if (event->state & GDK_CONTROL_MASK)
1007         {
1008           gtk_editable_copy_clipboard (editable);
1009         }
1010       else
1011         {
1012           /* gtk_toggle_insert(entry) -- IMPLEMENT */
1013         }
1014       break;
1015     case GDK_Delete:
1016       return_val = TRUE;
1017       if (event->state & GDK_CONTROL_MASK)
1018         gtk_delete_forward_word (entry);
1019       else if (event->state & GDK_SHIFT_MASK)
1020         {
1021           extend_selection = FALSE;
1022           gtk_editable_cut_clipboard (editable);
1023         }
1024       else
1025         gtk_delete_forward_character (entry);
1026       break;
1027     case GDK_Home:
1028       return_val = TRUE;
1029       gtk_move_beginning_of_line (entry);
1030       break;
1031     case GDK_End:
1032       return_val = TRUE;
1033       gtk_move_end_of_line (entry);
1034       break;
1035     case GDK_Left:
1036       return_val = TRUE;
1037       if (event->state & GDK_CONTROL_MASK)
1038         gtk_move_backward_word (entry);
1039       else
1040         gtk_move_backward_character (entry);
1041       break;
1042     case GDK_Right:
1043       return_val = TRUE;
1044       if (event->state & GDK_CONTROL_MASK)
1045         gtk_move_forward_word (entry);
1046       else
1047         gtk_move_forward_character (entry);
1048       break;
1049     case GDK_Return:
1050       return_val = TRUE;
1051       gtk_widget_activate (widget);
1052       break;
1053     /* The next two keys should not be inserted literally. Any others ??? */
1054     case GDK_Tab:
1055     case GDK_Escape:
1056       break;
1057     default:
1058       if ((event->keyval >= 0x20) && (event->keyval <= 0xFF))
1059         {
1060           key = event->keyval;
1061
1062           if (event->state & GDK_CONTROL_MASK)
1063             {
1064               if ((key >= 'A') && (key <= 'Z'))
1065                 key -= 'A' - 'a';
1066
1067               if ((key >= 'a') && (key <= 'z') && control_keys[key - 'a'])
1068                 {
1069                   (* control_keys[key - 'a']) (editable, event->time);
1070                   return_val = TRUE;
1071                 }
1072               break;
1073             }
1074           else if (event->state & GDK_MOD1_MASK)
1075             {
1076               if ((key >= 'A') && (key <= 'Z'))
1077                 key -= 'A' - 'a';
1078
1079               if ((key >= 'a') && (key <= 'z') && alt_keys[key - 'a'])
1080                 {
1081                   (* alt_keys[key - 'a']) (editable, event->time);
1082                   return_val = TRUE;
1083                 }
1084               break;
1085             }
1086         }
1087       gtk_im_context_filter_keypress (entry->im_context, event);
1088       
1089       break;
1090     }
1091
1092   /* since we emit signals from within the above code,
1093    * the widget might already be destroyed or at least
1094    * unrealized.
1095    */
1096   if (GTK_WIDGET_REALIZED (editable) &&
1097       return_val && (editable->current_pos != initial_pos))
1098     {
1099       if (extend_selection)
1100         {
1101           if (editable->current_pos < editable->selection_start_pos)
1102             editable->selection_start_pos = editable->current_pos;
1103           else if (editable->current_pos > editable->selection_end_pos)
1104             editable->selection_end_pos = editable->current_pos;
1105           else
1106             {
1107               if (extend_start)
1108                 editable->selection_start_pos = editable->current_pos;
1109               else
1110                 editable->selection_end_pos = editable->current_pos;
1111             }
1112         }
1113       else
1114         {
1115           editable->selection_start_pos = 0;
1116           editable->selection_end_pos = 0;
1117         }
1118
1119       gtk_editable_claim_selection (editable,
1120                                     editable->selection_start_pos != editable->selection_end_pos,
1121                                     event->time);
1122       
1123       entry_adjust_scroll (entry);
1124       gtk_entry_queue_draw (entry);
1125     }
1126
1127   return return_val;
1128 }
1129
1130 static gint
1131 gtk_entry_focus_in (GtkWidget     *widget,
1132                     GdkEventFocus *event)
1133 {
1134   g_return_val_if_fail (widget != NULL, FALSE);
1135   g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
1136   g_return_val_if_fail (event != NULL, FALSE);
1137
1138   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
1139   gtk_widget_draw_focus (widget);
1140   gtk_entry_queue_draw (GTK_ENTRY (widget));
1141   
1142   gtk_im_context_focus_in (GTK_ENTRY (widget)->im_context);
1143
1144   return FALSE;
1145 }
1146
1147 static gint
1148 gtk_entry_focus_out (GtkWidget     *widget,
1149                      GdkEventFocus *event)
1150 {
1151   g_return_val_if_fail (widget != NULL, FALSE);
1152   g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
1153   g_return_val_if_fail (event != NULL, FALSE);
1154
1155   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
1156   gtk_widget_draw_focus (widget);
1157   gtk_entry_queue_draw (GTK_ENTRY (widget));
1158
1159   gtk_im_context_focus_out (GTK_ENTRY (widget)->im_context);
1160
1161   return FALSE;
1162 }
1163
1164 static void
1165 gtk_entry_ensure_layout (GtkEntry *entry)
1166 {
1167   GtkWidget *widget = GTK_WIDGET (entry);
1168   
1169   if (!entry->layout)
1170     {
1171       entry->layout = gtk_widget_create_pango_layout (widget, NULL);
1172       pango_layout_set_text (entry->layout, entry->text, entry->n_bytes);
1173     }
1174 }
1175
1176 static void
1177 gtk_entry_draw_text (GtkEntry *entry)
1178 {
1179   GtkWidget *widget;
1180   PangoLayoutLine *line;
1181   GtkEditable *editable = GTK_EDITABLE (entry);
1182   
1183   g_return_if_fail (entry != NULL);
1184   g_return_if_fail (GTK_IS_ENTRY (entry));
1185
1186   if (GTK_WIDGET_DRAWABLE (entry))
1187     {
1188       PangoRectangle logical_rect;
1189       gint area_width, area_height;
1190       gint y_pos;
1191
1192       gdk_window_get_size (entry->text_area, &area_width, &area_height);
1193       area_height = PANGO_SCALE * (area_height - 2 * INNER_BORDER);
1194       
1195       widget = GTK_WIDGET (entry);
1196
1197       gtk_paint_flat_box (widget->style, entry->text_area, 
1198                           GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
1199                           NULL, widget, "entry_bg", 
1200                           0, 0, area_width, area_height);
1201       
1202       gtk_entry_ensure_layout (entry);
1203       
1204       line = pango_layout_get_lines (entry->layout)->data;
1205       pango_layout_line_get_extents (line, NULL, &logical_rect);
1206
1207       /* Align primarily for locale's ascent/descent */
1208       y_pos = ((area_height - entry->ascent - entry->descent) / 2 + 
1209                entry->ascent + logical_rect.y);
1210
1211       /* Now see if we need to adjust to fit in actual drawn string */
1212       if (logical_rect.height > area_height)
1213         y_pos = (area_height - logical_rect.height) / 2;
1214       else if (y_pos < 0)
1215         y_pos = 0;
1216       else if (y_pos + logical_rect.height > area_height)
1217         y_pos = area_height - logical_rect.height;
1218       
1219       y_pos = INNER_BORDER + y_pos / PANGO_SCALE;
1220
1221       gdk_draw_layout (entry->text_area, widget->style->text_gc [widget->state], 
1222                        INNER_BORDER - entry->scroll_offset, y_pos,
1223                        entry->layout);
1224
1225       if (editable->selection_start_pos != editable->selection_end_pos)
1226         {
1227           gint *ranges;
1228           gint n_ranges, i;
1229           gint start_index = g_utf8_offset_to_pointer (entry->text,
1230                                                        MIN (editable->selection_start_pos, editable->selection_end_pos)) - entry->text;
1231           gint end_index = g_utf8_offset_to_pointer (entry->text,
1232                                                      MAX (editable->selection_start_pos, editable->selection_end_pos)) - entry->text;
1233           GtkStateType selected_state = editable->has_selection ? GTK_STATE_SELECTED : GTK_STATE_ACTIVE;
1234           GdkRegion *clip_region = gdk_region_new ();
1235
1236           pango_layout_line_get_x_ranges (line, start_index, end_index, &ranges, &n_ranges);
1237
1238           for (i=0; i < n_ranges; i++)
1239             {
1240               GdkRectangle rect;
1241
1242               rect.x = INNER_BORDER - entry->scroll_offset + ranges[2*i] / PANGO_SCALE;
1243               rect.y = y_pos;
1244               rect.width = (ranges[2*i + 1] - ranges[2*i]) / PANGO_SCALE;
1245               rect.height = logical_rect.height / PANGO_SCALE;
1246               
1247               gdk_draw_rectangle (entry->text_area, widget->style->bg_gc [selected_state], TRUE,
1248                                   rect.x, rect.y, rect.width, rect.height);
1249
1250               gdk_region_union_with_rect (clip_region, &rect);
1251             }
1252
1253           gdk_gc_set_clip_region (widget->style->fg_gc [selected_state], clip_region);
1254           gdk_draw_layout (entry->text_area, widget->style->fg_gc [selected_state], 
1255                            INNER_BORDER - entry->scroll_offset, y_pos,
1256                            entry->layout);
1257           gdk_gc_set_clip_region (widget->style->fg_gc [selected_state], NULL);
1258           
1259           gdk_region_destroy (clip_region);
1260           g_free (ranges);
1261         }
1262     }
1263 }
1264
1265 static void
1266 gtk_entry_draw_cursor (GtkEntry *entry)
1267 {
1268   g_return_if_fail (entry != NULL);
1269   g_return_if_fail (GTK_IS_ENTRY (entry));
1270
1271   if (GTK_WIDGET_DRAWABLE (entry))
1272     {
1273       GtkWidget *widget = GTK_WIDGET (entry);
1274       GtkEditable *editable = GTK_EDITABLE (entry);
1275
1276       if (GTK_WIDGET_HAS_FOCUS (widget) &&
1277           (editable->selection_start_pos == editable->selection_end_pos))
1278         {
1279           gint xoffset = INNER_BORDER - entry->scroll_offset;
1280           gint strong_x, weak_x;
1281           gint text_area_height;
1282
1283           gdk_window_get_size (entry->text_area, NULL, &text_area_height);
1284
1285           gtk_entry_get_cursor_locations (entry, &strong_x, &weak_x);
1286
1287           gdk_draw_line (entry->text_area, widget->style->bg_gc[GTK_STATE_SELECTED], 
1288                          xoffset + strong_x, INNER_BORDER,
1289                          xoffset + strong_x, text_area_height - INNER_BORDER);
1290
1291           if (weak_x != strong_x)
1292             gdk_draw_line (entry->text_area, widget->style->fg_gc[GTK_STATE_NORMAL], 
1293                            xoffset + weak_x, INNER_BORDER,
1294                            xoffset + weak_x, text_area_height - INNER_BORDER);
1295
1296         }
1297     }
1298 }
1299
1300 static void
1301 gtk_entry_queue_draw (GtkEntry *entry)
1302 {
1303   g_return_if_fail (entry != NULL);
1304   g_return_if_fail (GTK_IS_ENTRY (entry));
1305
1306   if (GTK_WIDGET_REALIZED (entry))
1307     {
1308       GdkRectangle rect = { 0 };
1309
1310       gdk_window_get_size (entry->text_area, &rect.width, &rect.height);
1311       gdk_window_invalidate_rect (entry->text_area, &rect, 0);
1312     }
1313 }
1314
1315 #if 0
1316 static gint
1317 gtk_entry_timer (gpointer data)
1318 {
1319   GtkEntry *entry;
1320
1321   GDK_THREADS_ENTER ();
1322
1323   entry = GTK_ENTRY (data);
1324   entry->timer = 0;
1325
1326   GDK_THREADS_LEAVE ();
1327
1328   return FALSE;
1329 }
1330 #endif
1331
1332 static gint
1333 gtk_entry_find_position (GtkEntry *entry,
1334                          gint      x)
1335 {
1336   PangoLayoutLine *line;
1337   gint index;
1338   gint pos;
1339   gboolean trailing;
1340   
1341   gtk_entry_ensure_layout (entry);
1342
1343   line = pango_layout_get_lines (entry->layout)->data;
1344   pango_layout_line_x_to_index (line, x * PANGO_SCALE, &index, &trailing);
1345
1346   pos = g_utf8_pointer_to_offset (entry->text, entry->text + index);
1347   
1348   if (trailing)
1349     pos += 1;
1350
1351   return pos;
1352 }
1353
1354 static void
1355 gtk_entry_get_cursor_locations (GtkEntry *entry,
1356                                 gint     *strong_x,
1357                                 gint     *weak_x)
1358 {
1359   GtkEditable *editable = GTK_EDITABLE (entry);
1360   int index;
1361
1362   PangoRectangle strong_pos, weak_pos;
1363
1364   gtk_entry_ensure_layout (entry);
1365   
1366   index = g_utf8_offset_to_pointer (entry->text, editable->current_pos) - entry->text;
1367   pango_layout_get_cursor_pos (entry->layout, index, &strong_pos, &weak_pos);
1368
1369   if (strong_x)
1370     *strong_x = strong_pos.x / PANGO_SCALE;
1371
1372   if (weak_x)
1373     *weak_x = weak_pos.x / PANGO_SCALE;
1374 }
1375
1376 static void
1377 entry_adjust_scroll (GtkEntry *entry)
1378 {
1379   GtkWidget *widget;
1380   gint min_offset, max_offset;
1381   gint text_area_width;
1382   gint strong_x, weak_x;
1383   gint strong_xoffset, weak_xoffset;
1384   PangoLayoutLine *line;
1385   PangoRectangle logical_rect;
1386
1387   g_return_if_fail (entry != NULL);
1388   g_return_if_fail (GTK_IS_ENTRY (entry));
1389
1390   widget = GTK_WIDGET (entry);
1391
1392   if (!entry->layout || !GTK_WIDGET_REALIZED (entry))
1393     return;
1394   
1395   gdk_window_get_size (entry->text_area, &text_area_width, NULL);
1396   text_area_width -= 2 * INNER_BORDER;
1397
1398   line = pango_layout_get_lines (entry->layout)->data;
1399   
1400   /* Display as much text as we can */
1401
1402   pango_layout_line_get_extents (line, NULL, &logical_rect);
1403
1404   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1405     {
1406       min_offset = 0;
1407       max_offset = MAX (min_offset, logical_rect.width / PANGO_SCALE - text_area_width);
1408     }
1409   else
1410     {
1411       max_offset = logical_rect.width / PANGO_SCALE - text_area_width;
1412       min_offset = MIN (0, max_offset);
1413     }
1414
1415   entry->scroll_offset = CLAMP (entry->scroll_offset, min_offset, max_offset);
1416
1417   /* And make sure cursors are on screen. Note that the cursor is
1418    * actually drawn one pixel into the INNER_BORDER space on
1419    * the right, when the scroll is at the utmost right. This
1420    * looks better to to me than confining the cursor inside the
1421    * border entirely, though it means that the cursor gets one
1422    * pixel closer to the the edge of the widget on the right than
1423    * on the left. This might need changing if one changed
1424    * INNER_BORDER from 2 to 1, as one would do on a
1425    * small-screen-real-estate display.
1426    *
1427    * We always make sure that the strong cursor is on screen, and
1428    * put the weak cursor on screen if possible.
1429    */
1430
1431   gtk_entry_get_cursor_locations (entry, &strong_x, &weak_x);
1432   
1433   strong_xoffset = strong_x - entry->scroll_offset;
1434
1435   if (strong_xoffset < 0)
1436     {
1437       entry->scroll_offset += strong_xoffset;
1438       strong_xoffset = 0;
1439     }
1440   else if (strong_xoffset > text_area_width)
1441     {
1442       entry->scroll_offset += strong_xoffset - text_area_width;
1443       strong_xoffset = text_area_width;
1444     }
1445
1446   weak_xoffset = weak_x - entry->scroll_offset;
1447
1448   if (weak_xoffset < 0 && strong_xoffset - weak_xoffset <= text_area_width)
1449     {
1450       entry->scroll_offset += weak_xoffset;
1451     }
1452   else if (weak_xoffset > text_area_width &&
1453            strong_xoffset - (weak_xoffset - text_area_width) >= 0)
1454     {
1455       entry->scroll_offset += weak_xoffset - text_area_width;
1456     }
1457
1458   gtk_widget_queue_draw (GTK_WIDGET (entry));
1459 }
1460
1461 static void
1462 gtk_entry_insert_text (GtkEditable *editable,
1463                        const gchar *new_text,
1464                        gint         new_text_length,
1465                        gint        *position)
1466 {
1467   gint index;
1468   gint n_chars;
1469   GtkEntry *entry;
1470   GtkWidget *widget;
1471   
1472   g_return_if_fail (editable != NULL);
1473   g_return_if_fail (GTK_IS_ENTRY (editable));
1474   g_return_if_fail (position != NULL);
1475   g_return_if_fail (*position >= 0 || *position < GTK_ENTRY (editable)->text_size);
1476
1477   entry = GTK_ENTRY (editable);
1478   widget = GTK_WIDGET (editable);
1479
1480   if (new_text_length < 0)
1481     new_text_length = strlen (new_text);
1482
1483   n_chars = g_utf8_strlen (new_text, new_text_length);
1484   if (entry->text_max_length > 0 && n_chars + entry->text_length > entry->text_max_length)
1485     {
1486       gdk_beep ();
1487       n_chars = entry->text_max_length - entry->text_length;
1488     }
1489
1490   if (new_text_length + entry->n_bytes + 1 > entry->text_size)
1491     {
1492       while (new_text_length + entry->n_bytes + 1 > entry->text_size)
1493         {
1494           if (entry->text_size == 0)
1495             entry->text_size = MIN_SIZE;
1496           else
1497             {
1498               if (2 * (guint)entry->text_size < MAX_SIZE &&
1499                   2 * (guint)entry->text_size > entry->text_size)
1500                 entry->text_size *= 2;
1501               else
1502                 {
1503                   entry->text_size = MAX_SIZE;
1504                   new_text_length = entry->text_size - new_text_length - 1;
1505                   break;
1506                 }
1507             }
1508         }
1509
1510       entry->text = g_realloc (entry->text, entry->text_size);
1511     }
1512
1513   index = g_utf8_offset_to_pointer (entry->text, *position) - entry->text;
1514
1515   g_memmove (entry->text + index + new_text_length, entry->text + index, entry->n_bytes - index);
1516   memcpy (entry->text + index, new_text, new_text_length);
1517
1518   entry->n_bytes += new_text_length;
1519   entry->text_length += n_chars;
1520
1521   /* NUL terminate for safety and convenience */
1522   entry->text[entry->n_bytes] = '\0';
1523   
1524   if (editable->current_pos > *position)
1525     editable->current_pos += n_chars;
1526   
1527   if (editable->selection_start_pos > *position)
1528     editable->selection_start_pos += n_chars;
1529
1530   if (editable->selection_end_pos > *position)
1531     editable->selection_end_pos += n_chars;
1532
1533   *position += n_chars;
1534
1535   if (entry->layout)
1536     pango_layout_set_text (entry->layout, entry->text, entry->n_bytes);
1537
1538   gtk_entry_queue_draw (entry);
1539 }
1540
1541 static void
1542 gtk_entry_delete_text (GtkEditable *editable,
1543                        gint         start_pos,
1544                        gint         end_pos)
1545 {
1546   GtkEntry *entry;
1547   
1548   g_return_if_fail (editable != NULL);
1549   g_return_if_fail (GTK_IS_ENTRY (editable));
1550
1551   entry = GTK_ENTRY (editable);
1552
1553   if (end_pos < 0)
1554     end_pos = entry->text_length;
1555   
1556   if ((start_pos < end_pos) &&
1557       (start_pos >= 0) &&
1558       (end_pos <= entry->text_length))
1559     {
1560       gint start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text;
1561       gint end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text;
1562
1563       g_memmove (entry->text + start_index, entry->text + end_index, entry->n_bytes - end_index);
1564       entry->text_length -= (end_pos - start_pos);
1565       entry->n_bytes -= (end_index - start_index);
1566       
1567       if (editable->current_pos > start_pos)
1568         editable->current_pos -= MIN (editable->current_pos, end_pos) - start_pos;
1569
1570       if (editable->selection_start_pos > start_pos)
1571         editable->selection_start_pos -= MIN (editable->selection_start_pos, end_pos) - start_pos;
1572
1573       if (editable->selection_end_pos > start_pos)
1574         editable->selection_end_pos -= MIN (editable->selection_end_pos, end_pos) - start_pos;
1575
1576     }
1577
1578   gtk_entry_queue_draw (entry);
1579
1580   if (entry->layout)
1581     pango_layout_set_text (entry->layout, entry->text, entry->n_bytes);
1582 }
1583
1584 static void
1585 gtk_entry_update_text (GtkEditable *editable,
1586                        gint         start_pos,
1587                        gint         end_pos)
1588 {
1589   GtkEntry *entry = GTK_ENTRY (editable);
1590   
1591   gtk_entry_queue_draw (entry);
1592 }
1593
1594 static gchar *    
1595 gtk_entry_get_chars      (GtkEditable   *editable,
1596                           gint           start_pos,
1597                           gint           end_pos)
1598 {
1599   GtkEntry *entry;
1600   gint start_index, end_index;
1601   
1602   g_return_val_if_fail (editable != NULL, NULL);
1603   g_return_val_if_fail (GTK_IS_ENTRY (editable), NULL);
1604
1605   entry = GTK_ENTRY (editable);
1606
1607   if (end_pos < 0)
1608     end_pos = entry->text_length;
1609
1610   start_pos = MIN (entry->text_length, start_pos);
1611   end_pos = MIN (entry->text_length, end_pos);
1612
1613   start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text;
1614   end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text;
1615
1616   return g_strndup (entry->text + start_index, end_index - start_index);
1617 }
1618
1619 static void 
1620 gtk_entry_move_cursor (GtkEditable *editable,
1621                        gint         x,
1622                        gint         y)
1623 {
1624   GtkEntry *entry;
1625   gint index;
1626
1627   entry = GTK_ENTRY (editable);
1628
1629   index = g_utf8_offset_to_pointer (entry->text, editable->current_pos) - entry->text;
1630   
1631   /* Horizontal motion */
1632
1633   if ((gint)editable->current_pos < -x)
1634     editable->current_pos = 0;
1635   else if (editable->current_pos + x > entry->text_length)
1636     editable->current_pos = entry->text_length;
1637   else
1638     editable->current_pos += x;
1639
1640   /* Ignore vertical motion */
1641 }
1642
1643 static void 
1644 gtk_entry_move_cursor_visually (GtkEditable *editable,
1645                                 gint         count)
1646 {
1647   GtkEntry *entry;
1648   gint index;
1649
1650   entry = GTK_ENTRY (editable);
1651
1652   index = g_utf8_offset_to_pointer (entry->text, editable->current_pos) - entry->text;
1653   
1654   gtk_entry_ensure_layout (entry);
1655
1656   while (count != 0)
1657     {
1658       int new_index, new_trailing;
1659       
1660       if (count > 0)
1661         {
1662           pango_layout_move_cursor_visually (entry->layout, index, 0, 1, &new_index, &new_trailing);
1663           count--;
1664         }
1665       else
1666         {
1667           pango_layout_move_cursor_visually (entry->layout, index, 0, -1, &new_index, &new_trailing);
1668           count++;
1669         }
1670
1671       if (new_index < 0 || new_index == G_MAXINT)
1672         break;
1673       
1674       if (new_trailing)
1675         index = g_utf8_next_char (entry->text + new_index) - entry->text;
1676       else
1677         index = new_index;
1678     }
1679
1680   editable->current_pos = g_utf8_pointer_to_offset (entry->text, entry->text + index);
1681 }
1682
1683 static void
1684 gtk_move_forward_character (GtkEntry *entry)
1685 {
1686   gtk_entry_move_cursor_visually (GTK_EDITABLE (entry), 1);
1687 }
1688
1689 static void
1690 gtk_move_backward_character (GtkEntry *entry)
1691 {
1692   gtk_entry_move_cursor_visually (GTK_EDITABLE (entry), -1);
1693 }
1694
1695 static void 
1696 gtk_entry_move_word (GtkEditable *editable,
1697                      gint         n)
1698 {
1699   while (n-- > 0)
1700     gtk_move_forward_word (GTK_ENTRY (editable));
1701   while (n++ < 0)
1702     gtk_move_backward_word (GTK_ENTRY (editable));
1703 }
1704
1705 static void
1706 gtk_move_forward_word (GtkEntry *entry)
1707 {
1708   GtkEditable *editable;
1709   gint i;
1710
1711   editable = GTK_EDITABLE (entry);
1712
1713   /* Prevent any leak of information */
1714   if (!editable->visible)
1715     {
1716       editable->current_pos = entry->text_length;
1717       return;
1718     }
1719
1720   if (entry->text && (editable->current_pos < entry->text_length))
1721     {
1722       PangoLogAttr *log_attrs;
1723       gint n_attrs, old_pos;
1724
1725       gtk_entry_ensure_layout (entry);
1726       pango_layout_get_log_attrs (entry->layout, &log_attrs, &n_attrs);
1727
1728       i = old_pos = editable->current_pos;
1729
1730       /* Advance over white space */
1731       while (i < n_attrs && log_attrs[i].is_white)
1732         i++;
1733       
1734       /* Find the next word beginning */
1735       i++;
1736       while (i < n_attrs && !log_attrs[i].is_word_stop)
1737         i++;
1738
1739       editable->current_pos = MAX (entry->text_length, i);
1740
1741       /* Back up over white space */
1742       while (i > 0 && log_attrs[i - 1].is_white)
1743         i--;
1744
1745       if (i != old_pos)
1746         editable->current_pos = i;
1747
1748       g_free (log_attrs);
1749     }
1750 }
1751
1752 static void
1753 gtk_move_backward_word (GtkEntry *entry)
1754 {
1755   GtkEditable *editable;
1756   gint i;
1757
1758   editable = GTK_EDITABLE (entry);
1759
1760   /* Prevent any leak of information */
1761   if (!editable->visible)
1762     {
1763       editable->current_pos = 0;
1764       return;
1765     }
1766
1767   if (entry->text && editable->current_pos > 0)
1768     {
1769       PangoLogAttr *log_attrs;
1770       gint n_attrs;
1771
1772       gtk_entry_ensure_layout (entry);
1773       pango_layout_get_log_attrs (entry->layout, &log_attrs, &n_attrs);
1774
1775       i = editable->current_pos - 1;
1776
1777       /* Find the previous word beginning */
1778       while (i > 0 && !log_attrs[i].is_word_stop)
1779         i--;
1780
1781       g_free (log_attrs);
1782     }
1783 }
1784
1785 static void
1786 gtk_entry_move_to_column (GtkEditable *editable, gint column)
1787 {
1788   GtkEntry *entry;
1789
1790   entry = GTK_ENTRY (editable);
1791   
1792   if (column < 0 || column > entry->text_length)
1793     editable->current_pos = entry->text_length;
1794   else
1795     editable->current_pos = column;
1796 }
1797
1798 static void
1799 gtk_move_beginning_of_line (GtkEntry *entry)
1800 {
1801   gtk_entry_move_to_column (GTK_EDITABLE (entry), 0);
1802 }
1803
1804 static void
1805 gtk_move_end_of_line (GtkEntry *entry)
1806 {
1807   gtk_entry_move_to_column (GTK_EDITABLE (entry), -1);
1808 }
1809
1810 static void
1811 gtk_entry_kill_char (GtkEditable *editable,
1812                      gint         direction)
1813 {
1814   if (editable->selection_start_pos != editable->selection_end_pos)
1815     gtk_editable_delete_selection (editable);
1816   else
1817     {
1818       gint old_pos = editable->current_pos;
1819       if (direction >= 0)
1820         {
1821           gtk_entry_move_cursor (editable, 1, 0);
1822           gtk_editable_delete_text (editable, old_pos, editable->current_pos);
1823         }
1824       else
1825         {
1826           gtk_entry_move_cursor (editable, -1, 0);
1827           gtk_editable_delete_text (editable, editable->current_pos, old_pos);
1828         }
1829     }
1830 }
1831
1832 static void
1833 gtk_delete_forward_character (GtkEntry *entry)
1834 {
1835   gtk_entry_kill_char (GTK_EDITABLE (entry), 1);
1836 }
1837
1838 static void
1839 gtk_delete_backward_character (GtkEntry *entry)
1840 {
1841   gtk_entry_kill_char (GTK_EDITABLE (entry), -1);
1842 }
1843
1844 static void
1845 gtk_entry_kill_word (GtkEditable *editable,
1846                      gint         direction)
1847 {
1848   if (editable->selection_start_pos != editable->selection_end_pos)
1849     gtk_editable_delete_selection (editable);
1850   else
1851     {
1852       gint old_pos = editable->current_pos;
1853       if (direction >= 0)
1854         {
1855           gtk_entry_move_word (editable, 1);
1856           gtk_editable_delete_text (editable, old_pos, editable->current_pos);
1857         }
1858       else
1859         {
1860           gtk_entry_move_word (editable, -1);
1861           gtk_editable_delete_text (editable, editable->current_pos, old_pos);
1862         }
1863     }
1864 }
1865
1866 static void
1867 gtk_delete_forward_word (GtkEntry *entry)
1868 {
1869   gtk_entry_kill_word (GTK_EDITABLE (entry), 1);
1870 }
1871
1872 static void
1873 gtk_delete_backward_word (GtkEntry *entry)
1874 {
1875   gtk_entry_kill_word (GTK_EDITABLE (entry), -1);
1876 }
1877
1878 static void
1879 gtk_entry_kill_line (GtkEditable *editable,
1880                      gint         direction)
1881 {
1882   gint old_pos = editable->current_pos;
1883   if (direction >= 0)
1884     {
1885       gtk_entry_move_to_column (editable, -1);
1886       gtk_editable_delete_text (editable, old_pos, editable->current_pos);
1887     }
1888   else
1889     {
1890       gtk_entry_move_to_column (editable, 0);
1891       gtk_editable_delete_text (editable, editable->current_pos, old_pos);
1892     }
1893 }
1894
1895 static void
1896 gtk_delete_line (GtkEntry *entry)
1897 {
1898   gtk_entry_move_to_column (GTK_EDITABLE (entry), 0);
1899   gtk_entry_kill_line (GTK_EDITABLE (entry), 1);
1900 }
1901
1902 static void
1903 gtk_delete_to_line_end (GtkEntry *entry)
1904 {
1905   gtk_editable_delete_text (GTK_EDITABLE(entry), GTK_EDITABLE(entry)->current_pos, entry->text_length);
1906 }
1907
1908 static void
1909 gtk_select_word (GtkEntry *entry,
1910                  guint32   time)
1911 {
1912   GtkEditable *editable;
1913   gint start_pos;
1914   gint end_pos;
1915
1916   editable = GTK_EDITABLE (entry);
1917
1918   gtk_move_backward_word (entry);
1919   start_pos = editable->current_pos;
1920
1921   gtk_move_forward_word (entry);
1922   end_pos = editable->current_pos;
1923
1924   editable->has_selection = TRUE;
1925   gtk_entry_set_selection (editable, start_pos, end_pos);
1926   gtk_editable_claim_selection (editable, start_pos != end_pos, time);
1927 }
1928
1929 static void
1930 gtk_select_line (GtkEntry *entry,
1931                  guint32   time)
1932 {
1933   GtkEditable *editable;
1934
1935   editable = GTK_EDITABLE (entry);
1936
1937   editable->has_selection = TRUE;
1938   gtk_entry_set_selection (editable, 0, entry->text_length);
1939   gtk_editable_claim_selection (editable, entry->text_length != 0, time);
1940
1941   editable->current_pos = editable->selection_end_pos;
1942 }
1943
1944 static void 
1945 gtk_entry_set_selection (GtkEditable       *editable,
1946                          gint               start,
1947                          gint               end)
1948 {
1949   GtkEntry *entry;
1950   
1951   g_return_if_fail (editable != NULL);
1952   g_return_if_fail (GTK_IS_ENTRY (editable));
1953
1954   entry = GTK_ENTRY (editable);
1955
1956   if (end < 0)
1957     end = GTK_ENTRY (editable)->text_length;
1958   
1959   editable->selection_start_pos = start;
1960   editable->selection_end_pos = end;
1961
1962   gtk_entry_queue_draw (GTK_ENTRY (editable));
1963 }
1964
1965 void       
1966 gtk_entry_select_region  (GtkEntry       *entry,
1967                           gint            start,
1968                           gint            end)
1969 {
1970   gtk_editable_select_region (GTK_EDITABLE (entry), start, end);
1971 }
1972
1973 void
1974 gtk_entry_set_max_length (GtkEntry     *entry,
1975                           guint16       max)
1976 {
1977   g_return_if_fail (entry != NULL);
1978   g_return_if_fail (GTK_IS_ENTRY (entry));
1979
1980   if (max && entry->text_length > max)
1981     gtk_editable_delete_text (GTK_EDITABLE(entry), max, -1);
1982   
1983   entry->text_max_length = max;
1984 }
1985
1986                           
1987 static void 
1988 gtk_entry_style_set     (GtkWidget      *widget,
1989                          GtkStyle       *previous_style)
1990 {
1991   GtkEntry *entry = GTK_ENTRY (widget);
1992
1993   if (previous_style && GTK_WIDGET_REALIZED (widget))
1994     {
1995       entry_adjust_scroll (entry);
1996
1997       gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
1998       gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
1999     }
2000
2001   if (entry->layout)
2002     pango_layout_context_changed (entry->layout);
2003 }
2004
2005 static void 
2006 gtk_entry_direction_changed (GtkWidget        *widget,
2007                              GtkTextDirection  previous_dir)
2008 {
2009   GtkEntry *entry = GTK_ENTRY (widget);
2010
2011   if (entry->layout)
2012     pango_layout_context_changed (entry->layout);
2013
2014   GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir);
2015 }
2016
2017 static void
2018 gtk_entry_state_changed (GtkWidget      *widget,
2019                          GtkStateType    previous_state)
2020 {
2021   g_return_if_fail (widget != NULL);
2022   g_return_if_fail (GTK_IS_ENTRY (widget));
2023
2024   if (GTK_WIDGET_REALIZED (widget))
2025     {
2026       gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2027       gdk_window_set_background (GTK_ENTRY (widget)->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2028     }
2029
2030   if (GTK_WIDGET_DRAWABLE (widget))
2031     gtk_widget_queue_clear(widget);
2032 }
2033
2034 static void
2035 gtk_entry_commit_cb (GtkIMContext *context,
2036                      const gchar  *str,
2037                      GtkEntry     *entry)
2038 {
2039   GtkEditable *editable = GTK_EDITABLE (entry);
2040   gint tmp_pos = editable->current_pos;
2041
2042   gtk_editable_insert_text (editable, str, strlen (str), &tmp_pos);
2043   editable->current_pos = tmp_pos;
2044 }
2045