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