source: trunk/third/gtk/gtk/gtkentry.c @ 17071

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