gtkentry.c 115 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1
2
3
4
/* GTK - The GIMP Toolkit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
6
7
8
9
10
11
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15
16
17
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
18
 */
19
20

/*
21
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22
23
24
25
26
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

Elliot Lee's avatar
Elliot Lee committed
27
#include <string.h>
Owen Taylor's avatar
Owen Taylor committed
28
29
30

#include <pango/pango.h>

Elliot Lee's avatar
Elliot Lee committed
31
#include "gdk/gdkkeysyms.h"
Owen Taylor's avatar
Owen Taylor committed
32
#include "gtkbindings.h"
33
#include "gtkcelleditable.h"
Owen Taylor's avatar
Owen Taylor committed
34
#include "gtkclipboard.h"
Owen Taylor's avatar
Owen Taylor committed
35
#include "gtkdnd.h"
Elliot Lee's avatar
Elliot Lee committed
36
#include "gtkentry.h"
37
#include "gtkimagemenuitem.h"
38
#include "gtkimmulticontext.h"
Owen Taylor's avatar
Owen Taylor committed
39
#include "gtkintl.h"
Elliot Lee's avatar
Elliot Lee committed
40
#include "gtkmain.h"
Owen Taylor's avatar
Owen Taylor committed
41
42
#include "gtkmenu.h"
#include "gtkmenuitem.h"
43
#include "gtkseparatormenuitem.h"
Elliot Lee's avatar
Elliot Lee committed
44
#include "gtkselection.h"
45
#include "gtksettings.h"
46
#include "gtkstock.h"
Elliot Lee's avatar
Elliot Lee committed
47
#include "gtksignal.h"
48
#include "gtkwindow.h"
49

Elliot Lee's avatar
Elliot Lee committed
50
51
52
53
#define MIN_ENTRY_WIDTH  150
#define DRAW_TIMEOUT     20
#define INNER_BORDER     2

54
55
56
57
58
59
/* Initial size of buffer, in bytes */
#define MIN_SIZE 16

/* Maximum size of text buffer, in bytes */
#define MAX_SIZE G_MAXUSHORT

Owen Taylor's avatar
Owen Taylor committed
60
61
enum {
  ACTIVATE,
Owen Taylor's avatar
Owen Taylor committed
62
  POPULATE_POPUP,
Owen Taylor's avatar
Owen Taylor committed
63
64
65
66
67
68
69
70
71
72
  MOVE_CURSOR,
  INSERT_AT_CURSOR,
  DELETE_FROM_CURSOR,
  CUT_CLIPBOARD,
  COPY_CLIPBOARD,
  PASTE_CLIPBOARD,
  TOGGLE_OVERWRITE,
  LAST_SIGNAL
};

73
enum {
Havoc Pennington's avatar
Havoc Pennington committed
74
  PROP_0,
75
76
  PROP_CURSOR_POSITION,
  PROP_SELECTION_BOUND,
Havoc Pennington's avatar
Havoc Pennington committed
77
78
79
  PROP_EDITABLE,
  PROP_MAX_LENGTH,
  PROP_VISIBILITY,
80
  PROP_HAS_FRAME,
81
  PROP_INVISIBLE_CHAR,
82
  PROP_ACTIVATES_DEFAULT,
83
  PROP_WIDTH_CHARS,
84
85
  PROP_SCROLL_OFFSET,
  PROP_TEXT
86
87
};

Owen Taylor's avatar
Owen Taylor committed
88
static guint signals[LAST_SIGNAL] = { 0 };
89

Owen Taylor's avatar
Owen Taylor committed
90
91
92
93
94
95
96
97
98
99
100
101
102
typedef enum {
  CURSOR_STANDARD,
  CURSOR_DND
} CursorType;

static GtkTargetEntry target_table[] = {
  { "UTF8_STRING",   0, 0 },
  { "COMPOUND_TEXT", 0, 0 },
  { "TEXT",          0, 0 },
  { "text/plain",    0, 0 },
  { "STRING",        0, 0 }
};

Owen Taylor's avatar
Owen Taylor committed
103
104
/* GObject, GtkObject methods
 */
105
106
107
static void   gtk_entry_class_init           (GtkEntryClass        *klass);
static void   gtk_entry_editable_init        (GtkEditableClass     *iface);
static void   gtk_entry_cell_editable_init   (GtkCellEditableIface *iface);
108
static void   gtk_entry_init                 (GtkEntry         *entry);
Havoc Pennington's avatar
Havoc Pennington committed
109
110
111
static void   gtk_entry_set_property (GObject         *object,
				      guint            prop_id,
				      const GValue    *value,
112
				      GParamSpec      *pspec);
Havoc Pennington's avatar
Havoc Pennington committed
113
114
115
static void   gtk_entry_get_property (GObject         *object,
				      guint            prop_id,
				      GValue          *value,
116
				      GParamSpec      *pspec);
117
static void   gtk_entry_finalize             (GObject          *object);
Owen Taylor's avatar
Owen Taylor committed
118
119
120

/* GtkWidget methods
 */
121
122
123
124
125
126
static void   gtk_entry_realize              (GtkWidget        *widget);
static void   gtk_entry_unrealize            (GtkWidget        *widget);
static void   gtk_entry_size_request         (GtkWidget        *widget,
					      GtkRequisition   *requisition);
static void   gtk_entry_size_allocate        (GtkWidget        *widget,
					      GtkAllocation    *allocation);
Owen Taylor's avatar
Owen Taylor committed
127
static void   gtk_entry_draw_focus           (GtkWidget        *widget);
128
129
130
131
132
133
134
135
136
137
138
139
140
141
static gint   gtk_entry_expose               (GtkWidget        *widget,
					      GdkEventExpose   *event);
static gint   gtk_entry_button_press         (GtkWidget        *widget,
					      GdkEventButton   *event);
static gint   gtk_entry_button_release       (GtkWidget        *widget,
					      GdkEventButton   *event);
static gint   gtk_entry_motion_notify        (GtkWidget        *widget,
					      GdkEventMotion   *event);
static gint   gtk_entry_key_press            (GtkWidget        *widget,
					      GdkEventKey      *event);
static gint   gtk_entry_focus_in             (GtkWidget        *widget,
					      GdkEventFocus    *event);
static gint   gtk_entry_focus_out            (GtkWidget        *widget,
					      GdkEventFocus    *event);
142
static void   gtk_entry_grab_focus           (GtkWidget        *widget);
143
144
145
146
147
148
static void   gtk_entry_style_set            (GtkWidget        *widget,
					      GtkStyle         *previous_style);
static void   gtk_entry_direction_changed    (GtkWidget        *widget,
					      GtkTextDirection  previous_dir);
static void   gtk_entry_state_changed        (GtkWidget        *widget,
					      GtkStateType      previous_state);
Owen Taylor's avatar
Owen Taylor committed
149

150
151
152
153
154
static gboolean gtk_entry_drag_drop          (GtkWidget        *widget,
                                              GdkDragContext   *context,
                                              gint              x,
                                              gint              y,
                                              guint             time);
Owen Taylor's avatar
Owen Taylor committed
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
static gboolean gtk_entry_drag_motion        (GtkWidget        *widget,
					      GdkDragContext   *context,
					      gint              x,
					      gint              y,
					      guint             time);
static void     gtk_entry_drag_leave         (GtkWidget        *widget,
					      GdkDragContext   *context,
					      guint             time);
static void     gtk_entry_drag_data_received (GtkWidget        *widget,
					      GdkDragContext   *context,
					      gint              x,
					      gint              y,
					      GtkSelectionData *selection_data,
					      guint             info,
					      guint             time);
static void     gtk_entry_drag_data_get      (GtkWidget        *widget,
					      GdkDragContext   *context,
					      GtkSelectionData *selection_data,
					      guint             info,
					      guint             time);
static void     gtk_entry_drag_data_delete   (GtkWidget        *widget,
					      GdkDragContext   *context);

Owen Taylor's avatar
Owen Taylor committed
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/* GtkEditable method implementations
 */
static void     gtk_entry_insert_text          (GtkEditable *editable,
						const gchar *new_text,
						gint         new_text_length,
						gint        *position);
static void     gtk_entry_delete_text          (GtkEditable *editable,
						gint         start_pos,
						gint         end_pos);
static gchar *  gtk_entry_get_chars            (GtkEditable *editable,
						gint         start_pos,
						gint         end_pos);
static void     gtk_entry_real_set_position    (GtkEditable *editable,
						gint         position);
static gint     gtk_entry_get_position         (GtkEditable *editable);
static void     gtk_entry_set_selection_bounds (GtkEditable *editable,
						gint         start,
						gint         end);
static gboolean gtk_entry_get_selection_bounds (GtkEditable *editable,
						gint        *start,
						gint        *end);

200
201
202
203
204
/* GtkCellEditable method implementations
 */
static void gtk_entry_start_editing (GtkCellEditable *cell_editable,
				     GdkEvent        *event);

Owen Taylor's avatar
Owen Taylor committed
205
206
/* Default signal handlers
 */
207
static void gtk_entry_real_insert_text   (GtkEditable     *editable,
208
209
210
					  const gchar     *new_text,
					  gint             new_text_length,
					  gint            *position);
211
static void gtk_entry_real_delete_text   (GtkEditable     *editable,
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
					  gint             start_pos,
					  gint             end_pos);
static void gtk_entry_move_cursor        (GtkEntry        *entry,
					  GtkMovementStep  step,
					  gint             count,
					  gboolean         extend_selection);
static void gtk_entry_insert_at_cursor   (GtkEntry        *entry,
					  const gchar     *str);
static void gtk_entry_delete_from_cursor (GtkEntry        *entry,
					  GtkDeleteType    type,
					  gint             count);
static void gtk_entry_cut_clipboard      (GtkEntry        *entry);
static void gtk_entry_copy_clipboard     (GtkEntry        *entry);
static void gtk_entry_paste_clipboard    (GtkEntry        *entry);
static void gtk_entry_toggle_overwrite   (GtkEntry        *entry);
227
static void gtk_entry_select_all         (GtkEntry        *entry);
228
static void gtk_entry_real_activate      (GtkEntry        *entry);
Owen Taylor's avatar
Owen Taylor committed
229
static void gtk_entry_popup_menu         (GtkWidget      *widget);
Owen Taylor's avatar
Owen Taylor committed
230

231
232
static void gtk_entry_keymap_direction_changed (GdkKeymap *keymap,
						GtkEntry  *entry);
Owen Taylor's avatar
Owen Taylor committed
233
234
/* IM Context Callbacks
 */
235
236
237
static void gtk_entry_commit_cb           (GtkIMContext      *context,
					   const gchar       *str,
					   GtkEntry          *entry);
Owen Taylor's avatar
Owen Taylor committed
238
239
240
241
static void gtk_entry_preedit_changed_cb  (GtkIMContext      *context,
					   GtkEntry          *entry);
/* Internal routines
 */
242
243
244
static void         gtk_entry_set_positions            (GtkEntry       *entry,
							gint            current_pos,
							gint            selection_bound);
Owen Taylor's avatar
Owen Taylor committed
245
static void         gtk_entry_draw_text                (GtkEntry       *entry);
Owen Taylor's avatar
Owen Taylor committed
246
247
static void         gtk_entry_draw_cursor              (GtkEntry       *entry,
							CursorType      type);
248
249
static PangoLayout *gtk_entry_ensure_layout            (GtkEntry       *entry,
                                                        gboolean        include_preedit);
Owen Taylor's avatar
Owen Taylor committed
250
251
252
253
254
255
static void         gtk_entry_queue_draw               (GtkEntry       *entry);
static void         gtk_entry_reset_im_context         (GtkEntry       *entry);
static void         gtk_entry_recompute                (GtkEntry       *entry);
static gint         gtk_entry_find_position            (GtkEntry       *entry,
							gint            x);
static void         gtk_entry_get_cursor_locations     (GtkEntry       *entry,
Owen Taylor's avatar
Owen Taylor committed
256
							CursorType      type,
Owen Taylor's avatar
Owen Taylor committed
257
258
259
260
261
262
							gint           *strong_x,
							gint           *weak_x);
static void         gtk_entry_adjust_scroll            (GtkEntry       *entry);
static gint         gtk_entry_move_visually            (GtkEntry       *editable,
							gint            start,
							gint            count);
263
264
265
static gint         gtk_entry_move_logically           (GtkEntry       *entry,
							gint            start,
							gint            count);
Owen Taylor's avatar
Owen Taylor committed
266
267
268
269
270
271
272
273
274
275
276
277
278
static gint         gtk_entry_move_forward_word        (GtkEntry       *entry,
							gint            start);
static gint         gtk_entry_move_backward_word       (GtkEntry       *entry,
							gint            start);
static void         gtk_entry_delete_whitespace        (GtkEntry       *entry);
static void         gtk_entry_select_word              (GtkEntry       *entry);
static void         gtk_entry_select_line              (GtkEntry       *entry);
static char *       gtk_entry_get_public_chars         (GtkEntry       *entry,
							gint            start,
							gint            end);
static void         gtk_entry_paste                    (GtkEntry       *entry,
							GdkAtom         selection);
static void         gtk_entry_update_primary_selection (GtkEntry       *entry);
Owen Taylor's avatar
Owen Taylor committed
279
static void         gtk_entry_do_popup                 (GtkEntry       *entry,
Owen Taylor's avatar
Owen Taylor committed
280
							GdkEventButton *event);
281
282
static gboolean     gtk_entry_mnemonic_activate        (GtkWidget      *widget,
							gboolean        group_cycling);
283
284
static void         gtk_entry_check_cursor_blink       (GtkEntry       *entry);
static void         gtk_entry_pend_cursor_blink        (GtkEntry       *entry);
285

Elliot Lee's avatar
Elliot Lee committed
286
287
static GtkWidgetClass *parent_class = NULL;

288
GtkType
289
gtk_entry_get_type (void)
Elliot Lee's avatar
Elliot Lee committed
290
{
291
  static GtkType entry_type = 0;
Elliot Lee's avatar
Elliot Lee committed
292
293
294

  if (!entry_type)
    {
295
      static const GtkTypeInfo entry_info =
Elliot Lee's avatar
Elliot Lee committed
296
297
298
299
300
301
      {
	"GtkEntry",
	sizeof (GtkEntry),
	sizeof (GtkEntryClass),
	(GtkClassInitFunc) gtk_entry_class_init,
	(GtkObjectInitFunc) gtk_entry_init,
302
303
	/* reserved_1 */ NULL,
	/* reserved_2 */ NULL,
304
        (GtkClassInitFunc) NULL,
Elliot Lee's avatar
Elliot Lee committed
305
      };
Owen Taylor's avatar
Owen Taylor committed
306
307
308
309
310
311
312
      
      static const GInterfaceInfo editable_info =
      {
	(GInterfaceInitFunc) gtk_entry_editable_init,	 /* interface_init */
	NULL,			                         /* interface_finalize */
	NULL			                         /* interface_data */
      };
Elliot Lee's avatar
Elliot Lee committed
313

314
315
316
317
318
319
320
      static const GInterfaceInfo cell_editable_info =
      {
	(GInterfaceInitFunc) gtk_entry_cell_editable_init,    /* interface_init */
	NULL,                                                 /* interface_finalize */
	NULL                                                  /* interface_data */
      };
      
Owen Taylor's avatar
Owen Taylor committed
321
322
323
324
      entry_type = gtk_type_unique (GTK_TYPE_WIDGET, &entry_info);
      g_type_add_interface_static (entry_type,
				   GTK_TYPE_EDITABLE,
				   &editable_info);
325
326
327
      g_type_add_interface_static (entry_type,
				   GTK_TYPE_CELL_EDITABLE,
				   &cell_editable_info);
Elliot Lee's avatar
Elliot Lee committed
328
329
330
331
332
    }

  return entry_type;
}

Owen Taylor's avatar
Owen Taylor committed
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
static void
add_move_binding (GtkBindingSet  *binding_set,
		  guint           keyval,
		  guint           modmask,
		  GtkMovementStep step,
		  gint            count)
{
  g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
  
  gtk_binding_entry_add_signal (binding_set, keyval, modmask,
				"move_cursor", 3,
				GTK_TYPE_ENUM, step,
				G_TYPE_INT, count,
                                G_TYPE_BOOLEAN, FALSE);

  /* Selection-extending version */
  gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
				"move_cursor", 3,
				GTK_TYPE_ENUM, step,
				G_TYPE_INT, count,
                                G_TYPE_BOOLEAN, TRUE);
}

Elliot Lee's avatar
Elliot Lee committed
356
357
358
static void
gtk_entry_class_init (GtkEntryClass *class)
{
359
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
Elliot Lee's avatar
Elliot Lee committed
360
361
  GtkObjectClass *object_class;
  GtkWidgetClass *widget_class;
Owen Taylor's avatar
Owen Taylor committed
362
  GtkBindingSet *binding_set;
Elliot Lee's avatar
Elliot Lee committed
363
364
365

  object_class = (GtkObjectClass*) class;
  widget_class = (GtkWidgetClass*) class;
Owen Taylor's avatar
Owen Taylor committed
366
  parent_class = gtk_type_class (GTK_TYPE_WIDGET);
Elliot Lee's avatar
Elliot Lee committed
367

368
  gobject_class->finalize = gtk_entry_finalize;
Havoc Pennington's avatar
Havoc Pennington committed
369
370
  gobject_class->set_property = gtk_entry_set_property;
  gobject_class->get_property = gtk_entry_get_property;
371
372
373
374
375
376
377
378
379
380
381
382

  widget_class->realize = gtk_entry_realize;
  widget_class->unrealize = gtk_entry_unrealize;
  widget_class->size_request = gtk_entry_size_request;
  widget_class->size_allocate = gtk_entry_size_allocate;
  widget_class->expose_event = gtk_entry_expose;
  widget_class->button_press_event = gtk_entry_button_press;
  widget_class->button_release_event = gtk_entry_button_release;
  widget_class->motion_notify_event = gtk_entry_motion_notify;
  widget_class->key_press_event = gtk_entry_key_press;
  widget_class->focus_in_event = gtk_entry_focus_in;
  widget_class->focus_out_event = gtk_entry_focus_out;
383
  widget_class->grab_focus = gtk_entry_grab_focus;
384
385
386
  widget_class->style_set = gtk_entry_style_set;
  widget_class->direction_changed = gtk_entry_direction_changed;
  widget_class->state_changed = gtk_entry_state_changed;
387
  widget_class->mnemonic_activate = gtk_entry_mnemonic_activate;
388

389
  widget_class->drag_drop = gtk_entry_drag_drop;
Owen Taylor's avatar
Owen Taylor committed
390
391
392
393
394
395
  widget_class->drag_motion = gtk_entry_drag_motion;
  widget_class->drag_leave = gtk_entry_drag_leave;
  widget_class->drag_data_received = gtk_entry_drag_data_received;
  widget_class->drag_data_get = gtk_entry_drag_data_get;
  widget_class->drag_data_delete = gtk_entry_drag_data_delete;

Owen Taylor's avatar
Owen Taylor committed
396
  widget_class->popup_menu = gtk_entry_popup_menu;
397

398
399
400
401
402
403
404
  class->move_cursor = gtk_entry_move_cursor;
  class->insert_at_cursor = gtk_entry_insert_at_cursor;
  class->delete_from_cursor = gtk_entry_delete_from_cursor;
  class->cut_clipboard = gtk_entry_cut_clipboard;
  class->copy_clipboard = gtk_entry_copy_clipboard;
  class->paste_clipboard = gtk_entry_paste_clipboard;
  class->toggle_overwrite = gtk_entry_toggle_overwrite;
405
406
  class->activate = gtk_entry_real_activate;
  
Havoc Pennington's avatar
Havoc Pennington committed
407
  g_object_class_install_property (gobject_class,
408
409
410
411
                                   PROP_CURSOR_POSITION,
                                   g_param_spec_int ("cursor_position",
                                                     _("Cursor Position"),
                                                     _("The current position of the insertion cursor in chars."),
Havoc Pennington's avatar
Havoc Pennington committed
412
413
414
                                                     0,
                                                     G_MAXINT,
                                                     0,
415
416
417
418
419
420
421
422
423
424
425
                                                     G_PARAM_READABLE));
  
  g_object_class_install_property (gobject_class,
                                   PROP_SELECTION_BOUND,
                                   g_param_spec_int ("selection_bound",
                                                     _("Selection Bound"),
                                                     _("The position of the opposite end of the selection from the cursor in chars."),
                                                     0,
                                                     G_MAXINT,
                                                     0,
                                                     G_PARAM_READABLE));
Havoc Pennington's avatar
Havoc Pennington committed
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
  
  g_object_class_install_property (gobject_class,
                                   PROP_EDITABLE,
                                   g_param_spec_boolean ("editable",
							 _("Editable"),
							 _("Whether the entry contents can be edited"),
                                                         TRUE,
							 G_PARAM_READABLE | G_PARAM_WRITABLE));
  
  g_object_class_install_property (gobject_class,
                                   PROP_MAX_LENGTH,
                                   g_param_spec_int ("max_length",
                                                     _("Maximum length"),
                                                     _("Maximum number of characters for this entry"),
                                                     -1,
                                                     G_MAXINT,
                                                     -1,
                                                     G_PARAM_READABLE | G_PARAM_WRITABLE));
  g_object_class_install_property (gobject_class,
                                   PROP_VISIBILITY,
                                   g_param_spec_boolean ("visibility",
							 _("Visibility"),
							 _("FALSE displays the \"invisible char\" instead of the actual text (password mode)"),
                                                         TRUE,
							 G_PARAM_READABLE | G_PARAM_WRITABLE));
451

Havoc Pennington's avatar
Havoc Pennington committed
452
  g_object_class_install_property (gobject_class,
453
454
455
456
457
458
459
460
                                   PROP_HAS_FRAME,
                                   g_param_spec_boolean ("has_frame",
							 _("Has Frame"),
							 _("FALSE removes outside bevel from entry."),
                                                         TRUE,
							 G_PARAM_READABLE | G_PARAM_WRITABLE));

    g_object_class_install_property (gobject_class,
Havoc Pennington's avatar
Havoc Pennington committed
461
                                   PROP_INVISIBLE_CHAR,
462
463
464
465
466
                                   g_param_spec_unichar ("invisible_char",
							 _("Invisible character"),
							 _("The character to use when masking entry contents (in \"password mode\")"),
							 '*',
							 G_PARAM_READABLE | G_PARAM_WRITABLE));
Havoc Pennington's avatar
Havoc Pennington committed
467

468
469
470
471
472
473
474
  g_object_class_install_property (gobject_class,
                                   PROP_ACTIVATES_DEFAULT,
                                   g_param_spec_boolean ("activates_default",
							 _("Activates default"),
							 _("Whether to activate the default widget (such as the default button in a dialog) when Enter is pressed."),
                                                         FALSE,
							 G_PARAM_READABLE | G_PARAM_WRITABLE));
475
476
477
478
479
480
481
482
483
  g_object_class_install_property (gobject_class,
                                   PROP_WIDTH_CHARS,
                                   g_param_spec_int ("width_chars",
                                                     _("Width in chars"),
                                                     _("Number of characters to leave space for in the entry."),
                                                     -1,
                                                     G_MAXINT,
                                                     -1,
                                                     G_PARAM_READABLE | G_PARAM_WRITABLE));
484

485
486
487
488
489
490
491
492
493
  g_object_class_install_property (gobject_class,
                                   PROP_SCROLL_OFFSET,
                                   g_param_spec_int ("scroll_offset",
                                                     _("Scroll offset"),
                                                     _("Number of pixels of the entry scrolled off the screen to the left"),
                                                     0,
                                                     G_MAXINT,
                                                     0,
                                                     G_PARAM_READABLE));
494
495
496
497
498
499
500
501

  g_object_class_install_property (gobject_class,
                                   PROP_TEXT,
                                   g_param_spec_string ("text",
							_("Text"),
							_("The contents of the entry"),
							"",
							G_PARAM_READABLE | G_PARAM_WRITABLE));
502
  
503
504
505
506
  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_boxed ("cursor_color",
							       _("Cursor color"),
							       _("Color with which to draw insertion cursor"),
507
							       GDK_TYPE_COLOR,
508
509
							       G_PARAM_READABLE));

Owen Taylor's avatar
Owen Taylor committed
510
511
512
513
514
515
516
517
  signals[POPULATE_POPUP] =
    gtk_signal_new ("populate_popup",
		    GTK_RUN_LAST,
		    GTK_CLASS_TYPE (object_class),
		    GTK_SIGNAL_OFFSET (GtkEntryClass, populate_popup),
		    gtk_marshal_VOID__OBJECT,
		    GTK_TYPE_NONE, 1, GTK_TYPE_MENU);
  
Owen Taylor's avatar
Owen Taylor committed
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
 /* Action signals */
  
  signals[ACTIVATE] =
    gtk_signal_new ("activate",
		    GTK_RUN_LAST | GTK_RUN_ACTION,
		    GTK_CLASS_TYPE (object_class),
		    GTK_SIGNAL_OFFSET (GtkEntryClass, activate),
		    gtk_marshal_VOID__VOID,
		    GTK_TYPE_NONE, 0);
  widget_class->activate_signal = signals[ACTIVATE];

  signals[MOVE_CURSOR] = 
      gtk_signal_new ("move_cursor",
                      GTK_RUN_LAST | GTK_RUN_ACTION,
                      GTK_CLASS_TYPE (object_class),
533
                      GTK_SIGNAL_OFFSET (GtkEntryClass, move_cursor),
Owen Taylor's avatar
Owen Taylor committed
534
535
536
537
538
539
540
                      gtk_marshal_VOID__ENUM_INT_BOOLEAN,
                      GTK_TYPE_NONE, 3, GTK_TYPE_MOVEMENT_STEP, GTK_TYPE_INT, GTK_TYPE_BOOL);

  signals[INSERT_AT_CURSOR] = 
      gtk_signal_new ("insert_at_cursor",
                      GTK_RUN_LAST | GTK_RUN_ACTION,
                      GTK_CLASS_TYPE (object_class),
541
                      GTK_SIGNAL_OFFSET (GtkEntryClass, insert_at_cursor),
Owen Taylor's avatar
Owen Taylor committed
542
543
544
545
546
547
548
                      gtk_marshal_VOID__STRING,
                      GTK_TYPE_NONE, 1, GTK_TYPE_STRING);

  signals[DELETE_FROM_CURSOR] = 
      gtk_signal_new ("delete_from_cursor",
                      GTK_RUN_LAST | GTK_RUN_ACTION,
                      GTK_CLASS_TYPE (object_class),
549
                      GTK_SIGNAL_OFFSET (GtkEntryClass, delete_from_cursor),
Owen Taylor's avatar
Owen Taylor committed
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
                      gtk_marshal_VOID__ENUM_INT,
                      GTK_TYPE_NONE, 2, GTK_TYPE_DELETE_TYPE, GTK_TYPE_INT);

  signals[CUT_CLIPBOARD] =
    gtk_signal_new ("cut_clipboard",
                    GTK_RUN_LAST | GTK_RUN_ACTION,
                    GTK_CLASS_TYPE (object_class),
                    GTK_SIGNAL_OFFSET (GtkEntryClass, cut_clipboard),
                    gtk_marshal_VOID__VOID,
                    GTK_TYPE_NONE, 0);

  signals[COPY_CLIPBOARD] =
    gtk_signal_new ("copy_clipboard",
                    GTK_RUN_LAST | GTK_RUN_ACTION,
                    GTK_CLASS_TYPE (object_class),
                    GTK_SIGNAL_OFFSET (GtkEntryClass, copy_clipboard),
                    gtk_marshal_VOID__VOID,
                    GTK_TYPE_NONE, 0);

  signals[PASTE_CLIPBOARD] =
    gtk_signal_new ("paste_clipboard",
                    GTK_RUN_LAST | GTK_RUN_ACTION,
                    GTK_CLASS_TYPE (object_class),
                    GTK_SIGNAL_OFFSET (GtkEntryClass, paste_clipboard),
                    gtk_marshal_VOID__VOID,
                    GTK_TYPE_NONE, 0);

  signals[TOGGLE_OVERWRITE] =
    gtk_signal_new ("toggle_overwrite",
                    GTK_RUN_LAST | GTK_RUN_ACTION,
                    GTK_CLASS_TYPE (object_class),
                    GTK_SIGNAL_OFFSET (GtkEntryClass, toggle_overwrite),
                    gtk_marshal_VOID__VOID,
                    GTK_TYPE_NONE, 0);

  /*
   * Key bindings
   */

  binding_set = gtk_binding_set_by_class (class);

  /* Moving the insertion point */
  add_move_binding (binding_set, GDK_Right, 0,
593
		    GTK_MOVEMENT_VISUAL_POSITIONS, 1);
Owen Taylor's avatar
Owen Taylor committed
594
595
  
  add_move_binding (binding_set, GDK_Left, 0,
596
		    GTK_MOVEMENT_VISUAL_POSITIONS, -1);
Owen Taylor's avatar
Owen Taylor committed
597

598
599
600
601
602
603
  add_move_binding (binding_set, GDK_KP_Right, 0,
		    GTK_MOVEMENT_VISUAL_POSITIONS, 1);
  
  add_move_binding (binding_set, GDK_KP_Left, 0,
		    GTK_MOVEMENT_VISUAL_POSITIONS, -1);
  
Owen Taylor's avatar
Owen Taylor committed
604
  add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
605
		    GTK_MOVEMENT_LOGICAL_POSITIONS, 1);
Owen Taylor's avatar
Owen Taylor committed
606
607
  
  add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
608
		    GTK_MOVEMENT_LOGICAL_POSITIONS, -1);
Owen Taylor's avatar
Owen Taylor committed
609
610
611
612
613
614
  
  add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
		    GTK_MOVEMENT_WORDS, 1);

  add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
		    GTK_MOVEMENT_WORDS, -1);
615
616
617
618
619
620

  add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
		    GTK_MOVEMENT_WORDS, 1);

  add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
		    GTK_MOVEMENT_WORDS, -1);
Owen Taylor's avatar
Owen Taylor committed
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
  
  add_move_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
		    GTK_MOVEMENT_PARAGRAPH_ENDS, -1);

  add_move_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
		    GTK_MOVEMENT_PARAGRAPH_ENDS, 1);

  add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
		    GTK_MOVEMENT_WORDS, 1);

  add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK,
		    GTK_MOVEMENT_WORDS, -1);

  add_move_binding (binding_set, GDK_Home, 0,
		    GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);

  add_move_binding (binding_set, GDK_End, 0,
		    GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
639
640
641
642
643
644

  add_move_binding (binding_set, GDK_KP_Home, 0,
		    GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);

  add_move_binding (binding_set, GDK_KP_End, 0,
		    GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
Owen Taylor's avatar
Owen Taylor committed
645
646
647
648
649
650
651
  
  add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
		    GTK_MOVEMENT_BUFFER_ENDS, -1);

  add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
		    GTK_MOVEMENT_BUFFER_ENDS, 1);

652
653
654
655
656
657
658
659
660
661
662
663
664
665
  add_move_binding (binding_set, GDK_KP_Home, GDK_CONTROL_MASK,
		    GTK_MOVEMENT_BUFFER_ENDS, -1);

  add_move_binding (binding_set, GDK_KP_End, GDK_CONTROL_MASK,
		    GTK_MOVEMENT_BUFFER_ENDS, 1);

  /* Activate */

  gtk_binding_entry_add_signal (binding_set, GDK_Return, 0,
				"activate", 0);

  gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0,
				"activate", 0);
  
Owen Taylor's avatar
Owen Taylor committed
666
667
668
669
670
671
  /* Deleting text */
  gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0,
				"delete_from_cursor", 2,
				GTK_TYPE_ENUM, GTK_DELETE_CHARS,
				GTK_TYPE_INT, 1);

672
673
674
675
676
  gtk_binding_entry_add_signal (binding_set, GDK_KP_Delete, 0,
				"delete_from_cursor", 2,
				GTK_TYPE_ENUM, GTK_DELETE_CHARS,
				GTK_TYPE_INT, 1);
  
Owen Taylor's avatar
Owen Taylor committed
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
  gtk_binding_entry_add_signal (binding_set, GDK_d, GDK_CONTROL_MASK,
				"delete_from_cursor", 2,
				GTK_TYPE_ENUM, GTK_DELETE_CHARS,
				GTK_TYPE_INT, 1);

  gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0,
				"delete_from_cursor", 2,
				GTK_TYPE_ENUM, GTK_DELETE_CHARS,
				GTK_TYPE_INT, -1);

  gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_CONTROL_MASK,
				"delete_from_cursor", 2,
				GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
				GTK_TYPE_INT, 1);

692
693
694
695
696
  gtk_binding_entry_add_signal (binding_set, GDK_KP_Delete, GDK_CONTROL_MASK,
				"delete_from_cursor", 2,
				GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
				GTK_TYPE_INT, 1);
  
Owen Taylor's avatar
Owen Taylor committed
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
  gtk_binding_entry_add_signal (binding_set, GDK_d, GDK_MOD1_MASK,
				"delete_from_cursor", 2,
				GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
				GTK_TYPE_INT, 1);

  gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK,
				"delete_from_cursor", 2,
				GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
				GTK_TYPE_INT, -1);

  gtk_binding_entry_add_signal (binding_set, GDK_k, GDK_CONTROL_MASK,
				"delete_from_cursor", 2,
				GTK_TYPE_ENUM, GTK_DELETE_PARAGRAPH_ENDS,
				GTK_TYPE_INT, 1);

  gtk_binding_entry_add_signal (binding_set, GDK_u, GDK_CONTROL_MASK,
				"delete_from_cursor", 2,
				GTK_TYPE_ENUM, GTK_DELETE_PARAGRAPHS,
				GTK_TYPE_INT, 1);

  gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK,
				"delete_from_cursor", 2,
				GTK_TYPE_ENUM, GTK_DELETE_WHITESPACE,
				GTK_TYPE_INT, 1);
721
722
723
724
  gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_MOD1_MASK,
				"delete_from_cursor", 2,
				GTK_TYPE_ENUM, GTK_DELETE_WHITESPACE,
				GTK_TYPE_INT, 1);
Owen Taylor's avatar
Owen Taylor committed
725
726
727
  gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK,
				"insert_at_cursor", 1,
				GTK_TYPE_STRING, " ");
728
729
730
731
  gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_MOD1_MASK,
				"insert_at_cursor", 1,
				GTK_TYPE_STRING, " ");
  
Owen Taylor's avatar
Owen Taylor committed
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
  gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_MOD1_MASK,
				"delete_from_cursor", 2,
				GTK_TYPE_ENUM, GTK_DELETE_WHITESPACE,
				GTK_TYPE_INT, 1);
  
  /* Cut/copy/paste */

  gtk_binding_entry_add_signal (binding_set, GDK_x, GDK_CONTROL_MASK,
				"cut_clipboard", 0);

  gtk_binding_entry_add_signal (binding_set, GDK_w, GDK_CONTROL_MASK,
				"cut_clipboard", 0);
  
  gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
				"copy_clipboard", 0);
  
  gtk_binding_entry_add_signal (binding_set, GDK_v, GDK_CONTROL_MASK,
				"paste_clipboard", 0);
Elliot Lee's avatar
Elliot Lee committed
750

Owen Taylor's avatar
Owen Taylor committed
751
752
753
754
755
756
  gtk_binding_entry_add_signal (binding_set, GDK_y, GDK_CONTROL_MASK,
				"paste_clipboard", 0);

  /* Overwrite */
  gtk_binding_entry_add_signal (binding_set, GDK_Insert, 0,
				"toggle_overwrite", 0);
757
758
  gtk_binding_entry_add_signal (binding_set, GDK_KP_Insert, 0,
				"toggle_overwrite", 0);
Owen Taylor's avatar
Owen Taylor committed
759
}
760

Owen Taylor's avatar
Owen Taylor committed
761
762
763
static void
gtk_entry_editable_init (GtkEditableClass *iface)
{
764
765
766
767
  iface->do_insert_text = gtk_entry_insert_text;
  iface->do_delete_text = gtk_entry_delete_text;
  iface->insert_text = gtk_entry_real_insert_text;
  iface->delete_text = gtk_entry_real_delete_text;
Owen Taylor's avatar
Owen Taylor committed
768
769
770
771
772
  iface->get_chars = gtk_entry_get_chars;
  iface->set_selection_bounds = gtk_entry_set_selection_bounds;
  iface->get_selection_bounds = gtk_entry_get_selection_bounds;
  iface->set_position = gtk_entry_real_set_position;
  iface->get_position = gtk_entry_get_position;
Elliot Lee's avatar
Elliot Lee committed
773
774
}

775
776
777
778
779
780
static void
gtk_entry_cell_editable_init (GtkCellEditableIface *iface)
{
  iface->start_editing = gtk_entry_start_editing;
}

781
782
783
784
785
static void
gtk_entry_set_property (GObject         *object,
                        guint            prop_id,
                        const GValue    *value,
                        GParamSpec      *pspec)
786
{
Owen Taylor's avatar
Owen Taylor committed
787
  GtkEntry *entry = GTK_ENTRY (object);
788

Havoc Pennington's avatar
Havoc Pennington committed
789
  switch (prop_id)
790
    {
Havoc Pennington's avatar
Havoc Pennington committed
791
    case PROP_EDITABLE:
Owen Taylor's avatar
Owen Taylor committed
792
      {
Havoc Pennington's avatar
Havoc Pennington committed
793
794
795
        gboolean new_value = g_value_get_boolean (value);

      	if (new_value != entry->editable)
Owen Taylor's avatar
Owen Taylor committed
796
797
798
799
800
801
	  {
	    entry->editable = new_value;
	    gtk_entry_queue_draw (entry);
	  }
      }
      break;
Havoc Pennington's avatar
Havoc Pennington committed
802
803
804

    case PROP_MAX_LENGTH:
      gtk_entry_set_max_length (entry, g_value_get_int (value));
805
      break;
Havoc Pennington's avatar
Havoc Pennington committed
806
807
808
      
    case PROP_VISIBILITY:
      gtk_entry_set_visibility (entry, g_value_get_boolean (value));
809
      break;
Havoc Pennington's avatar
Havoc Pennington committed
810

811
812
813
814
    case PROP_HAS_FRAME:
      gtk_entry_set_has_frame (entry, g_value_get_boolean (value));
      break;

Havoc Pennington's avatar
Havoc Pennington committed
815
    case PROP_INVISIBLE_CHAR:
816
      gtk_entry_set_invisible_char (entry, g_value_get_uint (value));
817
      break;
Havoc Pennington's avatar
Havoc Pennington committed
818

819
820
821
    case PROP_ACTIVATES_DEFAULT:
      gtk_entry_set_activates_default (entry, g_value_get_boolean (value));
      break;
822
823
824
825

    case PROP_WIDTH_CHARS:
      gtk_entry_set_width_chars (entry, g_value_get_int (value));
      break;
826

827
828
829
830
    case PROP_TEXT:
      gtk_entry_set_text (entry, g_value_get_string (value));
      break;

831
    case PROP_SCROLL_OFFSET:
832
    case PROP_CURSOR_POSITION:
833
    default:
Havoc Pennington's avatar
Havoc Pennington committed
834
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
835
836
837
838
      break;
    }
}

839
840
841
842
843
static void
gtk_entry_get_property (GObject         *object,
                        guint            prop_id,
                        GValue          *value,
                        GParamSpec      *pspec)
844
845
846
847
848
{
  GtkEntry *entry;

  entry = GTK_ENTRY (object);

Havoc Pennington's avatar
Havoc Pennington committed
849
  switch (prop_id)
850
    {
851
    case PROP_CURSOR_POSITION:
Havoc Pennington's avatar
Havoc Pennington committed
852
      g_value_set_int (value, entry->current_pos);
Owen Taylor's avatar
Owen Taylor committed
853
      break;
854
855
856
    case PROP_SELECTION_BOUND:
      g_value_set_int (value, entry->selection_bound);
      break;
Havoc Pennington's avatar
Havoc Pennington committed
857
858
    case PROP_EDITABLE:
      g_value_set_boolean (value, entry->editable);
Owen Taylor's avatar
Owen Taylor committed
859
      break;
Havoc Pennington's avatar
Havoc Pennington committed
860
861
    case PROP_MAX_LENGTH:
      g_value_set_int (value, entry->text_max_length); 
862
      break;
Havoc Pennington's avatar
Havoc Pennington committed
863
864
    case PROP_VISIBILITY:
      g_value_set_boolean (value, entry->visible);
865
      break;
866
867
868
    case PROP_HAS_FRAME:
      g_value_set_boolean (value, entry->has_frame);
      break;
Havoc Pennington's avatar
Havoc Pennington committed
869
    case PROP_INVISIBLE_CHAR:
870
      g_value_set_uint (value, entry->invisible_char);
871
      break;
872
873
874
    case PROP_ACTIVATES_DEFAULT:
      g_value_set_boolean (value, entry->activates_default);
      break;
875
876
877
    case PROP_WIDTH_CHARS:
      g_value_set_int (value, entry->width_chars);
      break;
878
879
880
    case PROP_SCROLL_OFFSET:
      g_value_set_int (value, entry->scroll_offset);
      break;
881
882
883
    case PROP_TEXT:
      g_value_set_string (value, gtk_entry_get_text (entry));
      break;
884
      
885
    default:
Havoc Pennington's avatar
Havoc Pennington committed
886
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
887
888
889
890
      break;
    }
}

Elliot Lee's avatar
Elliot Lee committed
891
892
893
894
895
static void
gtk_entry_init (GtkEntry *entry)
{
  GTK_WIDGET_SET_FLAGS (entry, GTK_CAN_FOCUS);

896
897
898
  entry->text_size = MIN_SIZE;
  entry->text = g_malloc (entry->text_size);
  entry->text[0] = '\0';
Owen Taylor's avatar
Owen Taylor committed
899
900
901

  entry->editable = TRUE;
  entry->visible = TRUE;
902
  entry->invisible_char = '*';
Owen Taylor's avatar
Owen Taylor committed
903
  entry->dnd_position = -1;
904
  entry->width_chars = -1;
905
  entry->is_cell_renderer = FALSE;
Havoc Pennington's avatar
Havoc Pennington committed
906
  entry->has_frame = TRUE;
907
  
Owen Taylor's avatar
Owen Taylor committed
908
  gtk_drag_dest_set (GTK_WIDGET (entry),
909
                     GTK_DEST_DEFAULT_HIGHLIGHT,
Owen Taylor's avatar
Owen Taylor committed
910
911
912
                     target_table, G_N_ELEMENTS (target_table),
                     GDK_ACTION_COPY | GDK_ACTION_MOVE);

913
914
915
916
917
  /* This object is completely private. No external entity can gain a reference
   * to it; so we create it here and destroy it in finalize().
   */
  entry->im_context = gtk_im_multicontext_new ();
  
918
919
920
921
  g_signal_connect (G_OBJECT (entry->im_context), "commit",
		    G_CALLBACK (gtk_entry_commit_cb), entry);
  g_signal_connect (G_OBJECT (entry->im_context), "preedit_changed",
		    G_CALLBACK (gtk_entry_preedit_changed_cb), entry);
Elliot Lee's avatar
Elliot Lee committed
922
923
924
}

static void
925
gtk_entry_finalize (GObject *object)
Elliot Lee's avatar
Elliot Lee committed
926
927
928
929
930
931
932
{
  GtkEntry *entry;

  g_return_if_fail (GTK_IS_ENTRY (object));

  entry = GTK_ENTRY (object);

Owen Taylor's avatar
Owen Taylor committed
933
934
  if (entry->cached_layout)
    g_object_unref (G_OBJECT (entry->cached_layout));
Owen Taylor's avatar
Owen Taylor committed
935

936
  g_object_unref (G_OBJECT (entry->im_context));
937

938
939
  if (entry->blink_timeout)
    g_source_remove (entry->blink_timeout);
Owen Taylor's avatar
Owen Taylor committed
940
941
942

  if (entry->recompute_idle)
    g_source_remove (entry->recompute_idle);
Elliot Lee's avatar
Elliot Lee committed
943

944
  entry->text_size = 0;
945

Elliot Lee's avatar
Elliot Lee committed
946
947
948
949
  if (entry->text)
    g_free (entry->text);
  entry->text = NULL;

950
  G_OBJECT_CLASS (parent_class)->finalize (object);
Elliot Lee's avatar
Elliot Lee committed
951
952
}

953
954
955
956
static void
gtk_entry_realize_cursor_gc (GtkEntry *entry)
{
  GdkColor *cursor_color;
957
  GdkColor red = {0, 0xffff, 0x0000, 0x0000};
958
959
960
961
962
963
  
  if (entry->cursor_gc)
    gdk_gc_unref (entry->cursor_gc);

  gtk_widget_style_get (GTK_WIDGET (entry), "cursor_color", &cursor_color, NULL);
      entry->cursor_gc = gdk_gc_new (entry->text_area);
964
965
  if (cursor_color)
    gdk_gc_set_rgb_fg_color (entry->cursor_gc, cursor_color);
966
  else
967
    gdk_gc_set_rgb_fg_color (entry->cursor_gc, &red);
968
969
}

Elliot Lee's avatar
Elliot Lee committed
970
971
972
973
static void
gtk_entry_realize (GtkWidget *widget)
{
  GtkEntry *entry;
974
  GtkEditable *editable;
975
  GtkRequisition requisition;
Elliot Lee's avatar
Elliot Lee committed
976
977
978
979
980
981
982
  GdkWindowAttr attributes;
  gint attributes_mask;

  g_return_if_fail (GTK_IS_ENTRY (widget));

  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
  entry = GTK_ENTRY (widget);
983
  editable = GTK_EDITABLE (widget);
984
985

  gtk_widget_get_child_requisition (widget, &requisition);
986
  
Elliot Lee's avatar
Elliot Lee committed
987
988
  attributes.window_type = GDK_WINDOW_CHILD;
  attributes.x = widget->allocation.x;
989
  attributes.y = widget->allocation.y + (widget->allocation.height -
990
					 requisition.height) / 2;
Elliot Lee's avatar
Elliot Lee committed
991
  attributes.width = widget->allocation.width;
992
  attributes.height = requisition.height;
Elliot Lee's avatar
Elliot Lee committed
993
994
995
996
997
998
999
1000
1001
  attributes.wclass = GDK_INPUT_OUTPUT;
  attributes.visual = gtk_widget_get_visual (widget);
  attributes.colormap = gtk_widget_get_colormap (widget);
  attributes.event_mask = gtk_widget_get_events (widget);
  attributes.event_mask |= (GDK_EXPOSURE_MASK |
			    GDK_BUTTON_PRESS_MASK |
			    GDK_BUTTON_RELEASE_MASK |
			    GDK_BUTTON1_MOTION_MASK |
			    GDK_BUTTON3_MOTION_MASK |
1002
1003
1004
			    GDK_POINTER_MOTION_HINT_MASK |
                            GDK_ENTER_NOTIFY_MASK |
			    GDK_LEAVE_NOTIFY_MASK);
Elliot Lee's avatar
Elliot Lee committed
1005
1006
  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;

1007
  widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
Elliot Lee's avatar
Elliot Lee committed
1008
1009
  gdk_window_set_user_data (widget->window, entry);

Havoc Pennington's avatar
Havoc Pennington committed
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
  if (entry->has_frame)
    {
      attributes.x = widget->style->xthickness;
      attributes.y = widget->style->ythickness;
    }
  else
    {
      attributes.x = 0;
      attributes.y = 0;
    }
  
Elliot Lee's avatar
Elliot Lee committed
1021
  attributes.width = widget->allocation.width - attributes.x * 2;
1022
  attributes.height = requisition.height - attributes.y * 2;
Owen Taylor's avatar
Owen Taylor committed
1023
  attributes.cursor = gdk_cursor_new (GDK_XTERM);
1024
  attributes_mask |= GDK_WA_CURSOR;
Elliot Lee's avatar
Elliot Lee committed
1025
1026
1027
1028

  entry->text_area = gdk_window_new (widget->window, &attributes, attributes_mask);
  gdk_window_set_user_data (entry->text_area, entry);

1029
  gdk_cursor_destroy (attributes.cursor);
1030

Elliot Lee's avatar
Elliot Lee committed
1031
1032
  widget->style = gtk_style_attach (widget->style, widget->window);

1033
1034
  gtk_entry_realize_cursor_gc (entry);

1035
1036
  gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
  gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
Elliot Lee's avatar
Elliot Lee committed
1037
1038

  gdk_window_show (entry->text_area);
1039

1040
  gtk_im_context_set_client_window (entry->im_context, entry->text_area);
1041

Owen Taylor's avatar
Owen Taylor committed
1042
  gtk_entry_adjust_scroll (entry);
Elliot Lee's avatar
Elliot Lee committed
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
}

static void
gtk_entry_unrealize (GtkWidget *widget)
{
  GtkEntry *entry;

  g_return_if_fail (GTK_IS_ENTRY (widget));

  entry = GTK_ENTRY (widget);

1054
1055
  gtk_im_context_set_client_window (entry->im_context, entry->text_area);
  
Elliot Lee's avatar
Elliot Lee committed
1056
1057
1058
1059
  if (entry->text_area)
    {
      gdk_window_set_user_data (entry->text_area, NULL);
      gdk_window_destroy (entry->text_area);
1060
      entry->text_area = NULL;
Elliot Lee's avatar
Elliot Lee committed
1061
    }
1062

1063
1064
1065
1066
1067
1068
  if (entry->cursor_gc)
    {
      gdk_gc_unref (entry->cursor_gc);
      entry->cursor_gc = NULL;
    }

Owen Taylor's avatar
Owen Taylor committed
1069
  if (entry->popup_menu)
1070
1071
1072
1073
    {
      gtk_widget_destroy (entry->popup_menu);
      entry->popup_menu = NULL;
    }
Owen Taylor's avatar
Owen Taylor committed
1074

1075
1076
  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
Elliot Lee's avatar
Elliot Lee committed
1077
1078
1079
1080
1081
1082
}

static void
gtk_entry_size_request (GtkWidget      *widget,
			GtkRequisition *requisition)
{
1083
  GtkEntry *entry;
1084
  PangoFontMetrics *metrics;
Havoc Pennington's avatar
Havoc Pennington committed
1085
  gint xborder, yborder;
1086
  PangoContext *context;
1087
  
Elliot Lee's avatar
Elliot Lee committed
1088
1089
1090
  g_return_if_fail (GTK_IS_ENTRY (widget));
  g_return_if_fail (requisition != NULL);

1091
  entry = GTK_ENTRY (widget);
1092
  
1093
  context = gtk_widget_get_pango_context (widget);
1094
1095
1096
  metrics = pango_context_get_metrics (context,
				       widget->style->font_desc,
				       pango_context_get_language (context));
1097

1098
1099
  entry->ascent = pango_font_metrics_get_ascent (metrics);
  entry->descent = pango_font_metrics_get_descent (metrics);
Havoc Pennington's avatar
Havoc Pennington committed
1100
1101
1102

  xborder = INNER_BORDER;
  yborder = INNER_BORDER;
1103
  
Havoc Pennington's avatar
Havoc Pennington committed
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
  if (entry->has_frame)
    {
      xborder += widget->style->xthickness;
      yborder += widget->style->ythickness;
    }
  else
    {
      /* add 1 pixel to draw focus rect in widget->window */
      xborder += 1;
      yborder += 1;
    }
1115
1116
1117
1118
1119

  if (entry->width_chars < 0)
    requisition->width = MIN_ENTRY_WIDTH + xborder * 2;
  else
    {
1120
1121
      gint char_width = pango_font_metrics_get_approximate_char_width (metrics);
      requisition->width = PANGO_PIXELS (char_width) * entry->width_chars + xborder * 2;
1122
1123
    }
    
1124
1125
1126
  requisition->height = PANGO_PIXELS (entry->ascent + entry->descent) + yborder * 2;

  pango_font_metrics_unref (metrics);
Elliot Lee's avatar
Elliot Lee committed
1127
1128
}

1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
static void
get_borders (GtkEntry *entry,
             gint     *xborder,
             gint     *yborder)
{
  GtkWidget *widget;

  widget = GTK_WIDGET (entry);
  
  if (entry->has_frame)
    {
      if (xborder)
        *xborder = widget->style->xthickness;
      if (yborder)
        *yborder = widget->style->ythickness;
    }
  else
    {
      /* 1 pixel for focus rect */
      if (xborder)
        *xborder = 1;
      if (yborder)
        *yborder = 1;
    }
}

static void
get_text_area_size (GtkEntry *entry,
                    gint     *x,
                    gint     *y,
                    gint     *width,
                    gint     *height)
{
  gint xborder, yborder;
  GtkRequisition requisition;
  GtkWidget *widget;

  widget = GTK_WIDGET (entry);
  
  gtk_widget_get_child_requisition (widget, &requisition);

  get_borders (entry, &xborder, &yborder);

  if (x)
    *x = xborder;

  if (y)
    *y = yborder;
  
  if (width)
    *width = GTK_WIDGET (entry)->allocation.width - xborder * 2;

  if (height)
    *height = requisition.height - yborder * 2;
}

static void
get_widget_window_size (GtkEntry *entry,
                        gint     *x,
                        gint     *y,
                        gint     *width,
                        gint     *height)
{
  GtkRequisition requisition;
  GtkWidget *widget;  

  widget = GTK_WIDGET (entry);
      
  gtk_widget_get_child_requisition (widget, &requisition);

  if (x)
    *x = widget->allocation.x;

  if (y)
1203
1204
1205
1206
1207
1208
    {
      if (entry->is_cell_renderer)
	*y = widget->allocation.y;
      else
	*y = widget->allocation.y + (widget->allocation.height - requisition.height) / 2;
    }
1209
1210
1211
1212
1213

  if (width)
    *width = widget->allocation.width;

  if (height)
1214
1215
1216
1217
1218
1219
    {
      if (entry->is_cell_renderer)
	*height = widget->allocation.height;
      else
	*height = requisition.height;
    }
1220
1221
}

Elliot Lee's avatar
Elliot Lee committed
1222
1223
1224
1225
1226
static void
gtk_entry_size_allocate (GtkWidget     *widget,
			 GtkAllocation *allocation)
{
  GtkEntry *entry;
1227
  GtkEditable *editable;
Havoc Pennington's avatar
Havoc Pennington committed
1228
  
Elliot Lee's avatar
Elliot Lee committed
1229
1230
1231
1232
1233
  g_return_if_fail (GTK_IS_ENTRY (widget));
  g_return_if_fail (allocation != NULL);

  widget->allocation = *allocation;
  entry = GTK_ENTRY (widget);
1234
  editable = GTK_EDITABLE (widget);
Havoc Pennington's avatar
Havoc Pennington committed
1235
  
Elliot Lee's avatar
Elliot Lee committed
1236
1237
  if (GTK_WIDGET_REALIZED (widget))
    {
1238
1239
1240
1241
      /* We call gtk_widget_get_child_requisition, since we want (for
       * backwards compatibility reasons) the realization here to
       * be affected by the usize of the entry, if set
       */
1242
1243
1244
1245
      gint x, y, width, height;

      get_widget_window_size (entry, &x, &y, &width, &height);
      
Elliot Lee's avatar
Elliot Lee committed
1246
      gdk_window_move_resize (widget->window,
1247
1248
1249
1250
                              x, y, width, height);   

      get_text_area_size (entry, &x, &y, &width, &height);
      
Elliot Lee's avatar
Elliot Lee committed
1251
      gdk_window_move_resize (entry->text_area,
1252
                              x, y, width, height);
Elliot Lee's avatar
Elliot Lee committed
1253

Owen Taylor's avatar
Owen Taylor committed
1254
      gtk_entry_recompute (entry);
Elliot Lee's avatar
Elliot Lee committed
1255
1256
1257
    }
}

Owen Taylor's avatar
Owen Taylor committed
1258
1259
static void
gtk_entry_draw_focus (GtkWidget *widget)
Elliot Lee's avatar
Elliot Lee committed
1260
{
Owen Taylor's avatar
Owen Taylor committed
1261
  gint width, height;
Havoc Pennington's avatar
Havoc Pennington committed
1262
  GtkEntry *entry;
1263
  gboolean interior_focus;
Havoc Pennington's avatar
Havoc Pennington committed
1264
  
Owen Taylor's avatar
Owen Taylor committed
1265
  g_return_if_fail (GTK_IS_ENTRY (widget));
Elliot Lee's avatar
Elliot Lee committed
1266

1267
1268
  gtk_widget_style_get (widget, "interior_focus", &interior_focus, NULL);

Havoc Pennington's avatar
Havoc Pennington committed
1269
1270
  entry = GTK_ENTRY (widget);
  
Owen Taylor's avatar
Owen Taylor committed
1271
  if (GTK_WIDGET_DRAWABLE (widget))
Havoc Pennington's avatar
Havoc Pennington committed
1272
1273
1274
1275
    {      
      if (entry->has_frame)
        {
          gint x = 0, y = 0;
Elliot Lee's avatar
Elliot Lee committed
1276

Havoc Pennington's avatar
Havoc Pennington committed
1277
1278
          gdk_window_get_size (widget->window, &width, &height);

1279
          if (GTK_WIDGET_HAS_FOCUS (widget) && !interior_focus)
Havoc Pennington's avatar
Havoc Pennington committed
1280
1281
1282
1283
1284
1285
            {
              x += 1;
              y += 1;
              width -= 2;
              height -= 2;
            }
Elliot Lee's avatar
Elliot Lee committed
1286

Havoc Pennington's avatar
Havoc Pennington committed
1287
1288
1289
1290
1291
1292
1293
1294
          gtk_paint_shadow (widget->style, widget->window,
                            GTK_STATE_NORMAL, GTK_SHADOW_IN,
                            NULL, widget, "entry",
                            x, y, width, height);
        }
      else
        gdk_window_clear (widget->window);
        
1295
      if (GTK_WIDGET_HAS_FOCUS (widget) && !interior_focus)
Havoc Pennington's avatar
Havoc Pennington committed
1296
1297
1298
1299
1300
1301
        {
          gdk_window_get_size (widget->window, &width, &height);
          gtk_paint_focus (widget->style, widget->window, 
                           NULL, widget, "entry",
                           0, 0, width - 1, height - 1);
        }
Owen Taylor's avatar
Owen Taylor committed
1302
1303
1304
1305
1306
1307
    }
}

static gint
gtk_entry_expose (GtkWidget      *widget,
		  GdkEventExpose *event)
Elliot Lee's avatar
Elliot Lee committed
1308
1309
1310
1311
1312
1313
{
  GtkEntry *entry;

  g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
  g_return_val_if_fail (event != NULL, FALSE);

Owen Taylor's avatar
Owen Taylor committed
1314
1315
1316
  entry = GTK_ENTRY (widget);

  if (widget->window == event->window)
1317
    gtk_entry_draw_focus (widget);
Owen Taylor's avatar
Owen Taylor committed
1318
1319
1320
  else if (entry->text_area == event->window)
    {
      gtk_entry_draw_text (GTK_ENTRY (widget));
Owen Taylor's avatar
Owen Taylor committed
1321
1322
1323

      if ((entry->visible || entry->invisible_char != 0) &&
	  GTK_WIDGET_HAS_FOCUS (widget) &&
1324
	  entry->selection_bound == entry->current_pos && entry->cursor_visible)
Owen Taylor's avatar
Owen Taylor committed
1325
1326
1327
1328
	gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_STANDARD);

      if (entry->dnd_position != -1)
	gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_DND);
Owen Taylor's avatar
Owen Taylor committed
1329