1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
29 #include <pango/pango.h>
31 #include "gdk/gdkkeysyms.h"
32 #include "gtkbindings.h"
33 #include "gtkclipboard.h"
36 #include "gtkimmulticontext.h"
40 #include "gtkmenuitem.h"
41 #include "gtkselection.h"
42 #include "gtksignal.h"
44 #define MIN_ENTRY_WIDTH 150
45 #define DRAW_TIMEOUT 20
46 #define INNER_BORDER 2
48 /* Initial size of buffer, in bytes */
51 /* Maximum size of text buffer, in bytes */
52 #define MAX_SIZE G_MAXUSHORT
78 static guint signals[LAST_SIGNAL] = { 0 };
85 static GtkTargetEntry target_table[] = {
86 { "UTF8_STRING", 0, 0 },
87 { "COMPOUND_TEXT", 0, 0 },
89 { "text/plain", 0, 0 },
93 /* GObject, GtkObject methods
95 static void gtk_entry_class_init (GtkEntryClass *klass);
96 static void gtk_entry_editable_init (GtkEditableClass *iface);
97 static void gtk_entry_init (GtkEntry *entry);
98 static void gtk_entry_set_arg (GtkObject *object,
101 static void gtk_entry_get_arg (GtkObject *object,
104 static void gtk_entry_finalize (GObject *object);
108 static void gtk_entry_realize (GtkWidget *widget);
109 static void gtk_entry_unrealize (GtkWidget *widget);
110 static void gtk_entry_size_request (GtkWidget *widget,
111 GtkRequisition *requisition);
112 static void gtk_entry_size_allocate (GtkWidget *widget,
113 GtkAllocation *allocation);
114 static void gtk_entry_draw_focus (GtkWidget *widget);
115 static gint gtk_entry_expose (GtkWidget *widget,
116 GdkEventExpose *event);
117 static gint gtk_entry_button_press (GtkWidget *widget,
118 GdkEventButton *event);
119 static gint gtk_entry_button_release (GtkWidget *widget,
120 GdkEventButton *event);
121 static gint gtk_entry_motion_notify (GtkWidget *widget,
122 GdkEventMotion *event);
123 static gint gtk_entry_key_press (GtkWidget *widget,
125 static gint gtk_entry_focus_in (GtkWidget *widget,
126 GdkEventFocus *event);
127 static gint gtk_entry_focus_out (GtkWidget *widget,
128 GdkEventFocus *event);
129 static void gtk_entry_style_set (GtkWidget *widget,
130 GtkStyle *previous_style);
131 static void gtk_entry_direction_changed (GtkWidget *widget,
132 GtkTextDirection previous_dir);
133 static void gtk_entry_state_changed (GtkWidget *widget,
134 GtkStateType previous_state);
136 static gboolean gtk_entry_drag_motion (GtkWidget *widget,
137 GdkDragContext *context,
141 static void gtk_entry_drag_leave (GtkWidget *widget,
142 GdkDragContext *context,
144 static void gtk_entry_drag_data_received (GtkWidget *widget,
145 GdkDragContext *context,
148 GtkSelectionData *selection_data,
151 static void gtk_entry_drag_data_get (GtkWidget *widget,
152 GdkDragContext *context,
153 GtkSelectionData *selection_data,
156 static void gtk_entry_drag_data_delete (GtkWidget *widget,
157 GdkDragContext *context);
159 /* GtkEditable method implementations
161 static void gtk_entry_insert_text (GtkEditable *editable,
162 const gchar *new_text,
163 gint new_text_length,
165 static void gtk_entry_delete_text (GtkEditable *editable,
168 static gchar * gtk_entry_get_chars (GtkEditable *editable,
171 static void gtk_entry_real_set_position (GtkEditable *editable,
173 static gint gtk_entry_get_position (GtkEditable *editable);
174 static void gtk_entry_set_selection_bounds (GtkEditable *editable,
177 static gboolean gtk_entry_get_selection_bounds (GtkEditable *editable,
181 /* Default signal handlers
183 static void gtk_entry_real_insert_text (GtkEntry *entry,
184 const gchar *new_text,
185 gint new_text_length,
187 static void gtk_entry_real_delete_text (GtkEntry *entry,
190 static void gtk_entry_move_cursor (GtkEntry *entry,
191 GtkMovementStep step,
193 gboolean extend_selection);
194 static void gtk_entry_insert_at_cursor (GtkEntry *entry,
196 static void gtk_entry_delete_from_cursor (GtkEntry *entry,
199 static void gtk_entry_cut_clipboard (GtkEntry *entry);
200 static void gtk_entry_copy_clipboard (GtkEntry *entry);
201 static void gtk_entry_paste_clipboard (GtkEntry *entry);
202 static void gtk_entry_toggle_overwrite (GtkEntry *entry);
204 /* IM Context Callbacks
206 static void gtk_entry_commit_cb (GtkIMContext *context,
209 static void gtk_entry_preedit_changed_cb (GtkIMContext *context,
213 static void gtk_entry_draw_text (GtkEntry *entry);
214 static void gtk_entry_draw_cursor (GtkEntry *entry,
216 static PangoLayout *gtk_entry_get_layout (GtkEntry *entry,
217 gboolean include_preedit);
218 static void gtk_entry_queue_draw (GtkEntry *entry);
219 static void gtk_entry_reset_im_context (GtkEntry *entry);
220 static void gtk_entry_recompute (GtkEntry *entry);
221 static gint gtk_entry_find_position (GtkEntry *entry,
223 static void gtk_entry_get_cursor_locations (GtkEntry *entry,
227 static void gtk_entry_adjust_scroll (GtkEntry *entry);
228 static gint gtk_entry_move_visually (GtkEntry *editable,
231 static gint gtk_entry_move_forward_word (GtkEntry *entry,
233 static gint gtk_entry_move_backward_word (GtkEntry *entry,
235 static void gtk_entry_delete_whitespace (GtkEntry *entry);
236 static void gtk_entry_select_word (GtkEntry *entry);
237 static void gtk_entry_select_line (GtkEntry *entry);
238 static char * gtk_entry_get_public_chars (GtkEntry *entry,
241 static void gtk_entry_paste (GtkEntry *entry,
243 static void gtk_entry_update_primary_selection (GtkEntry *entry);
244 static void gtk_entry_popup_menu (GtkEntry *entry,
245 GdkEventButton *event);
247 static GtkWidgetClass *parent_class = NULL;
250 gtk_entry_get_type (void)
252 static GtkType entry_type = 0;
256 static const GtkTypeInfo entry_info =
260 sizeof (GtkEntryClass),
261 (GtkClassInitFunc) gtk_entry_class_init,
262 (GtkObjectInitFunc) gtk_entry_init,
263 /* reserved_1 */ NULL,
264 /* reserved_2 */ NULL,
265 (GtkClassInitFunc) NULL,
268 static const GInterfaceInfo editable_info =
270 (GInterfaceInitFunc) gtk_entry_editable_init, /* interface_init */
271 NULL, /* interface_finalize */
272 NULL /* interface_data */
275 entry_type = gtk_type_unique (GTK_TYPE_WIDGET, &entry_info);
276 g_type_add_interface_static (entry_type,
285 add_move_binding (GtkBindingSet *binding_set,
288 GtkMovementStep step,
291 g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0);
293 gtk_binding_entry_add_signal (binding_set, keyval, modmask,
297 G_TYPE_BOOLEAN, FALSE);
299 /* Selection-extending version */
300 gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
304 G_TYPE_BOOLEAN, TRUE);
308 gtk_entry_class_init (GtkEntryClass *class)
310 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
311 GtkObjectClass *object_class;
312 GtkWidgetClass *widget_class;
313 GtkBindingSet *binding_set;
315 object_class = (GtkObjectClass*) class;
316 widget_class = (GtkWidgetClass*) class;
317 parent_class = gtk_type_class (GTK_TYPE_WIDGET);
319 gobject_class->finalize = gtk_entry_finalize;
321 object_class->set_arg = gtk_entry_set_arg;
322 object_class->get_arg = gtk_entry_get_arg;
324 widget_class->realize = gtk_entry_realize;
325 widget_class->unrealize = gtk_entry_unrealize;
326 widget_class->draw_focus = gtk_entry_draw_focus;
327 widget_class->size_request = gtk_entry_size_request;
328 widget_class->size_allocate = gtk_entry_size_allocate;
329 widget_class->expose_event = gtk_entry_expose;
330 widget_class->button_press_event = gtk_entry_button_press;
331 widget_class->button_release_event = gtk_entry_button_release;
332 widget_class->motion_notify_event = gtk_entry_motion_notify;
333 widget_class->key_press_event = gtk_entry_key_press;
334 widget_class->focus_in_event = gtk_entry_focus_in;
335 widget_class->focus_out_event = gtk_entry_focus_out;
336 widget_class->style_set = gtk_entry_style_set;
337 widget_class->direction_changed = gtk_entry_direction_changed;
338 widget_class->state_changed = gtk_entry_state_changed;
340 widget_class->drag_motion = gtk_entry_drag_motion;
341 widget_class->drag_leave = gtk_entry_drag_leave;
342 widget_class->drag_data_received = gtk_entry_drag_data_received;
343 widget_class->drag_data_get = gtk_entry_drag_data_get;
344 widget_class->drag_data_delete = gtk_entry_drag_data_delete;
346 class->insert_text = gtk_entry_real_insert_text;
347 class->delete_text = gtk_entry_real_delete_text;
348 class->move_cursor = gtk_entry_move_cursor;
349 class->insert_at_cursor = gtk_entry_insert_at_cursor;
350 class->delete_from_cursor = gtk_entry_delete_from_cursor;
351 class->cut_clipboard = gtk_entry_cut_clipboard;
352 class->copy_clipboard = gtk_entry_copy_clipboard;
353 class->paste_clipboard = gtk_entry_paste_clipboard;
354 class->toggle_overwrite = gtk_entry_toggle_overwrite;
356 gtk_object_add_arg_type ("GtkEntry::text_position", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_TEXT_POSITION);
357 gtk_object_add_arg_type ("GtkEntry::editable", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_EDITABLE);
358 gtk_object_add_arg_type ("GtkEntry::max_length", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_MAX_LENGTH);
359 gtk_object_add_arg_type ("GtkEntry::visibility", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_VISIBILITY);
360 gtk_object_add_arg_type ("GtkEntry::invisible_char", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_INVISIBLE_CHAR);
362 signals[INSERT_TEXT] =
363 gtk_signal_new ("insert_text",
365 GTK_CLASS_TYPE (object_class),
366 GTK_SIGNAL_OFFSET (GtkEntryClass, insert_text),
367 gtk_marshal_VOID__STRING_INT_POINTER,
374 signals[DELETE_TEXT] =
375 gtk_signal_new ("delete_text",
377 GTK_CLASS_TYPE (object_class),
378 GTK_SIGNAL_OFFSET (GtkEntryClass, delete_text),
379 gtk_marshal_VOID__INT_INT,
386 gtk_signal_new ("changed",
388 GTK_CLASS_TYPE (object_class),
389 GTK_SIGNAL_OFFSET (GtkEntryClass, changed),
390 gtk_marshal_VOID__VOID,
396 gtk_signal_new ("activate",
397 GTK_RUN_LAST | GTK_RUN_ACTION,
398 GTK_CLASS_TYPE (object_class),
399 GTK_SIGNAL_OFFSET (GtkEntryClass, activate),
400 gtk_marshal_VOID__VOID,
402 widget_class->activate_signal = signals[ACTIVATE];
404 signals[MOVE_CURSOR] =
405 gtk_signal_new ("move_cursor",
406 GTK_RUN_LAST | GTK_RUN_ACTION,
407 GTK_CLASS_TYPE (object_class),
408 GTK_SIGNAL_OFFSET (GtkEntryClass, move_cursor),
409 gtk_marshal_VOID__ENUM_INT_BOOLEAN,
410 GTK_TYPE_NONE, 3, GTK_TYPE_MOVEMENT_STEP, GTK_TYPE_INT, GTK_TYPE_BOOL);
412 signals[INSERT_AT_CURSOR] =
413 gtk_signal_new ("insert_at_cursor",
414 GTK_RUN_LAST | GTK_RUN_ACTION,
415 GTK_CLASS_TYPE (object_class),
416 GTK_SIGNAL_OFFSET (GtkEntryClass, insert_at_cursor),
417 gtk_marshal_VOID__STRING,
418 GTK_TYPE_NONE, 1, GTK_TYPE_STRING);
420 signals[DELETE_FROM_CURSOR] =
421 gtk_signal_new ("delete_from_cursor",
422 GTK_RUN_LAST | GTK_RUN_ACTION,
423 GTK_CLASS_TYPE (object_class),
424 GTK_SIGNAL_OFFSET (GtkEntryClass, delete_from_cursor),
425 gtk_marshal_VOID__ENUM_INT,
426 GTK_TYPE_NONE, 2, GTK_TYPE_DELETE_TYPE, GTK_TYPE_INT);
428 signals[CUT_CLIPBOARD] =
429 gtk_signal_new ("cut_clipboard",
430 GTK_RUN_LAST | GTK_RUN_ACTION,
431 GTK_CLASS_TYPE (object_class),
432 GTK_SIGNAL_OFFSET (GtkEntryClass, cut_clipboard),
433 gtk_marshal_VOID__VOID,
436 signals[COPY_CLIPBOARD] =
437 gtk_signal_new ("copy_clipboard",
438 GTK_RUN_LAST | GTK_RUN_ACTION,
439 GTK_CLASS_TYPE (object_class),
440 GTK_SIGNAL_OFFSET (GtkEntryClass, copy_clipboard),
441 gtk_marshal_VOID__VOID,
444 signals[PASTE_CLIPBOARD] =
445 gtk_signal_new ("paste_clipboard",
446 GTK_RUN_LAST | GTK_RUN_ACTION,
447 GTK_CLASS_TYPE (object_class),
448 GTK_SIGNAL_OFFSET (GtkEntryClass, paste_clipboard),
449 gtk_marshal_VOID__VOID,
452 signals[TOGGLE_OVERWRITE] =
453 gtk_signal_new ("toggle_overwrite",
454 GTK_RUN_LAST | GTK_RUN_ACTION,
455 GTK_CLASS_TYPE (object_class),
456 GTK_SIGNAL_OFFSET (GtkEntryClass, toggle_overwrite),
457 gtk_marshal_VOID__VOID,
464 binding_set = gtk_binding_set_by_class (class);
466 /* Moving the insertion point */
467 add_move_binding (binding_set, GDK_Right, 0,
468 GTK_MOVEMENT_VISUAL_POSITIONS, 1);
470 add_move_binding (binding_set, GDK_Left, 0,
471 GTK_MOVEMENT_VISUAL_POSITIONS, -1);
473 add_move_binding (binding_set, GDK_f, GDK_CONTROL_MASK,
474 GTK_MOVEMENT_LOGICAL_POSITIONS, 1);
476 add_move_binding (binding_set, GDK_b, GDK_CONTROL_MASK,
477 GTK_MOVEMENT_LOGICAL_POSITIONS, -1);
479 add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
480 GTK_MOVEMENT_WORDS, 1);
482 add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
483 GTK_MOVEMENT_WORDS, -1);
485 add_move_binding (binding_set, GDK_a, GDK_CONTROL_MASK,
486 GTK_MOVEMENT_PARAGRAPH_ENDS, -1);
488 add_move_binding (binding_set, GDK_e, GDK_CONTROL_MASK,
489 GTK_MOVEMENT_PARAGRAPH_ENDS, 1);
491 add_move_binding (binding_set, GDK_f, GDK_MOD1_MASK,
492 GTK_MOVEMENT_WORDS, 1);
494 add_move_binding (binding_set, GDK_b, GDK_MOD1_MASK,
495 GTK_MOVEMENT_WORDS, -1);
497 add_move_binding (binding_set, GDK_Home, 0,
498 GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
500 add_move_binding (binding_set, GDK_End, 0,
501 GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
503 add_move_binding (binding_set, GDK_Home, GDK_CONTROL_MASK,
504 GTK_MOVEMENT_BUFFER_ENDS, -1);
506 add_move_binding (binding_set, GDK_End, GDK_CONTROL_MASK,
507 GTK_MOVEMENT_BUFFER_ENDS, 1);
510 gtk_binding_entry_add_signal (binding_set, GDK_Delete, 0,
511 "delete_from_cursor", 2,
512 GTK_TYPE_ENUM, GTK_DELETE_CHARS,
515 gtk_binding_entry_add_signal (binding_set, GDK_d, GDK_CONTROL_MASK,
516 "delete_from_cursor", 2,
517 GTK_TYPE_ENUM, GTK_DELETE_CHARS,
520 gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0,
521 "delete_from_cursor", 2,
522 GTK_TYPE_ENUM, GTK_DELETE_CHARS,
525 gtk_binding_entry_add_signal (binding_set, GDK_Delete, GDK_CONTROL_MASK,
526 "delete_from_cursor", 2,
527 GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
530 gtk_binding_entry_add_signal (binding_set, GDK_d, GDK_MOD1_MASK,
531 "delete_from_cursor", 2,
532 GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
535 gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK,
536 "delete_from_cursor", 2,
537 GTK_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
540 gtk_binding_entry_add_signal (binding_set, GDK_k, GDK_CONTROL_MASK,
541 "delete_from_cursor", 2,
542 GTK_TYPE_ENUM, GTK_DELETE_PARAGRAPH_ENDS,
545 gtk_binding_entry_add_signal (binding_set, GDK_u, GDK_CONTROL_MASK,
546 "delete_from_cursor", 2,
547 GTK_TYPE_ENUM, GTK_DELETE_PARAGRAPHS,
550 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK,
551 "delete_from_cursor", 2,
552 GTK_TYPE_ENUM, GTK_DELETE_WHITESPACE,
554 gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_MOD1_MASK,
555 "insert_at_cursor", 1,
556 GTK_TYPE_STRING, " ");
558 gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_MOD1_MASK,
559 "delete_from_cursor", 2,
560 GTK_TYPE_ENUM, GTK_DELETE_WHITESPACE,
565 gtk_binding_entry_add_signal (binding_set, GDK_x, GDK_CONTROL_MASK,
568 gtk_binding_entry_add_signal (binding_set, GDK_w, GDK_CONTROL_MASK,
571 gtk_binding_entry_add_signal (binding_set, GDK_c, GDK_CONTROL_MASK,
572 "copy_clipboard", 0);
574 gtk_binding_entry_add_signal (binding_set, GDK_v, GDK_CONTROL_MASK,
575 "paste_clipboard", 0);
577 gtk_binding_entry_add_signal (binding_set, GDK_y, GDK_CONTROL_MASK,
578 "paste_clipboard", 0);
581 gtk_binding_entry_add_signal (binding_set, GDK_Insert, 0,
582 "toggle_overwrite", 0);
586 gtk_entry_editable_init (GtkEditableClass *iface)
588 iface->insert_text = gtk_entry_insert_text;
589 iface->delete_text = gtk_entry_delete_text;
590 iface->get_chars = gtk_entry_get_chars;
591 iface->set_selection_bounds = gtk_entry_set_selection_bounds;
592 iface->get_selection_bounds = gtk_entry_get_selection_bounds;
593 iface->set_position = gtk_entry_real_set_position;
594 iface->get_position = gtk_entry_get_position;
598 gtk_entry_set_arg (GtkObject *object,
602 GtkEntry *entry = GTK_ENTRY (object);
606 case ARG_TEXT_POSITION:
607 gtk_editable_set_position (GTK_EDITABLE (object), GTK_VALUE_INT (*arg));
611 gboolean new_value = GTK_VALUE_BOOL (*arg) != 0;
612 if (new_value != entry->editable)
614 entry->editable = new_value;
615 gtk_entry_queue_draw (entry);
620 gtk_entry_set_max_length (entry, GTK_VALUE_UINT (*arg));
623 gtk_entry_set_visibility (entry, GTK_VALUE_BOOL (*arg));
625 case ARG_INVISIBLE_CHAR:
626 gtk_entry_set_invisible_char (entry, GTK_VALUE_INT (*arg));
634 gtk_entry_get_arg (GtkObject *object,
640 entry = GTK_ENTRY (object);
644 case ARG_TEXT_POSITION:
645 GTK_VALUE_INT (*arg) = entry->current_pos;
648 GTK_VALUE_BOOL (*arg) = entry->editable;
651 GTK_VALUE_UINT (*arg) = entry->text_max_length;
654 GTK_VALUE_BOOL (*arg) = entry->visible;
656 case ARG_INVISIBLE_CHAR:
657 GTK_VALUE_INT (*arg) = entry->invisible_char;
660 arg->type = GTK_TYPE_INVALID;
666 gtk_entry_init (GtkEntry *entry)
668 GTK_WIDGET_SET_FLAGS (entry, GTK_CAN_FOCUS);
670 entry->text_size = MIN_SIZE;
671 entry->text = g_malloc (entry->text_size);
672 entry->text[0] = '\0';
674 entry->editable = TRUE;
675 entry->visible = TRUE;
676 entry->invisible_char = '*';
677 entry->dnd_position = -1;
679 entry->has_frame = TRUE;
681 gtk_drag_dest_set (GTK_WIDGET (entry),
682 GTK_DEST_DEFAULT_DROP | GTK_DEST_DEFAULT_HIGHLIGHT,
683 target_table, G_N_ELEMENTS (target_table),
684 GDK_ACTION_COPY | GDK_ACTION_MOVE);
686 /* This object is completely private. No external entity can gain a reference
687 * to it; so we create it here and destroy it in finalize().
689 entry->im_context = gtk_im_multicontext_new ();
691 gtk_signal_connect (GTK_OBJECT (entry->im_context), "commit",
692 GTK_SIGNAL_FUNC (gtk_entry_commit_cb), entry);
693 gtk_signal_connect (GTK_OBJECT (entry->im_context), "preedit_changed",
694 GTK_SIGNAL_FUNC (gtk_entry_preedit_changed_cb), entry);
698 gtk_entry_finalize (GObject *object)
702 g_return_if_fail (GTK_IS_ENTRY (object));
704 entry = GTK_ENTRY (object);
706 if (entry->cached_layout)
707 g_object_unref (G_OBJECT (entry->cached_layout));
709 gtk_object_unref (GTK_OBJECT (entry->im_context));
712 g_source_remove (entry->timer);
714 if (entry->recompute_idle)
715 g_source_remove (entry->recompute_idle);
717 entry->text_size = 0;
720 g_free (entry->text);
723 G_OBJECT_CLASS (parent_class)->finalize (object);
727 gtk_entry_realize (GtkWidget *widget)
730 GtkEditable *editable;
731 GtkRequisition requisition;
732 GdkWindowAttr attributes;
733 gint attributes_mask;
735 g_return_if_fail (widget != NULL);
736 g_return_if_fail (GTK_IS_ENTRY (widget));
738 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
739 entry = GTK_ENTRY (widget);
740 editable = GTK_EDITABLE (widget);
742 gtk_widget_get_child_requisition (widget, &requisition);
744 attributes.window_type = GDK_WINDOW_CHILD;
745 attributes.x = widget->allocation.x;
746 attributes.y = widget->allocation.y + (widget->allocation.height -
747 requisition.height) / 2;
748 attributes.width = widget->allocation.width;
749 attributes.height = requisition.height;
750 attributes.wclass = GDK_INPUT_OUTPUT;
751 attributes.visual = gtk_widget_get_visual (widget);
752 attributes.colormap = gtk_widget_get_colormap (widget);
753 attributes.event_mask = gtk_widget_get_events (widget);
754 attributes.event_mask |= (GDK_EXPOSURE_MASK |
755 GDK_BUTTON_PRESS_MASK |
756 GDK_BUTTON_RELEASE_MASK |
757 GDK_BUTTON1_MOTION_MASK |
758 GDK_BUTTON3_MOTION_MASK |
759 GDK_POINTER_MOTION_HINT_MASK);
760 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
762 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
763 gdk_window_set_user_data (widget->window, entry);
765 if (entry->has_frame)
767 attributes.x = widget->style->xthickness;
768 attributes.y = widget->style->ythickness;
776 attributes.width = widget->allocation.width - attributes.x * 2;
777 attributes.height = requisition.height - attributes.y * 2;
778 attributes.cursor = gdk_cursor_new (GDK_XTERM);
779 attributes_mask |= GDK_WA_CURSOR;
781 entry->text_area = gdk_window_new (widget->window, &attributes, attributes_mask);
782 gdk_window_set_user_data (entry->text_area, entry);
784 widget->style = gtk_style_attach (widget->style, widget->window);
786 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
787 gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
789 gdk_window_show (entry->text_area);
791 gtk_im_context_set_client_window (entry->im_context, entry->text_area);
793 gtk_entry_adjust_scroll (entry);
797 gtk_entry_unrealize (GtkWidget *widget)
801 g_return_if_fail (widget != NULL);
802 g_return_if_fail (GTK_IS_ENTRY (widget));
804 entry = GTK_ENTRY (widget);
806 gtk_im_context_set_client_window (entry->im_context, entry->text_area);
808 if (entry->text_area)
810 gdk_window_set_user_data (entry->text_area, NULL);
811 gdk_window_destroy (entry->text_area);
812 entry->text_area = NULL;
815 if (entry->popup_menu)
816 gtk_widget_destroy (entry->popup_menu);
818 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
819 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
823 gtk_entry_size_request (GtkWidget *widget,
824 GtkRequisition *requisition)
827 PangoFontMetrics metrics;
830 gint xborder, yborder;
832 g_return_if_fail (widget != NULL);
833 g_return_if_fail (GTK_IS_ENTRY (widget));
834 g_return_if_fail (requisition != NULL);
836 entry = GTK_ENTRY (widget);
838 /* hackish for now, get metrics
840 font = pango_context_load_font (gtk_widget_get_pango_context (widget),
841 widget->style->font_desc);
842 lang = pango_context_get_lang (gtk_widget_get_pango_context (widget));
843 pango_font_get_metrics (font, lang, &metrics);
846 g_object_unref (G_OBJECT (font));
848 entry->ascent = metrics.ascent;
849 entry->descent = metrics.descent;
851 xborder = INNER_BORDER;
852 yborder = INNER_BORDER;
854 if (entry->has_frame)
856 xborder += widget->style->xthickness;
857 yborder += widget->style->ythickness;
861 /* add 1 pixel to draw focus rect in widget->window */
866 requisition->width = MIN_ENTRY_WIDTH + xborder * 2;
867 requisition->height = ((metrics.ascent + metrics.descent) / PANGO_SCALE +
872 gtk_entry_size_allocate (GtkWidget *widget,
873 GtkAllocation *allocation)
876 GtkEditable *editable;
877 gint xborder, yborder;
879 g_return_if_fail (widget != NULL);
880 g_return_if_fail (GTK_IS_ENTRY (widget));
881 g_return_if_fail (allocation != NULL);
883 widget->allocation = *allocation;
884 entry = GTK_ENTRY (widget);
885 editable = GTK_EDITABLE (widget);
887 if (entry->has_frame)
889 xborder = widget->style->xthickness;
890 yborder = widget->style->ythickness;
894 /* 1 pixel for focus rect */
899 if (GTK_WIDGET_REALIZED (widget))
901 /* We call gtk_widget_get_child_requisition, since we want (for
902 * backwards compatibility reasons) the realization here to
903 * be affected by the usize of the entry, if set
905 GtkRequisition requisition;
906 gtk_widget_get_child_requisition (widget, &requisition);
908 gdk_window_move_resize (widget->window,
910 allocation->y + (allocation->height - requisition.height) / 2,
911 allocation->width, requisition.height);
912 gdk_window_move_resize (entry->text_area,
915 allocation->width - xborder * 2,
916 requisition.height - yborder * 2);
918 gtk_entry_recompute (entry);
923 gtk_entry_draw_focus (GtkWidget *widget)
928 g_return_if_fail (widget != NULL);
929 g_return_if_fail (GTK_IS_ENTRY (widget));
931 entry = GTK_ENTRY (widget);
933 if (GTK_WIDGET_DRAWABLE (widget))
935 if (entry->has_frame)
939 gdk_window_get_size (widget->window, &width, &height);
941 if (GTK_WIDGET_HAS_FOCUS (widget))
950 gtk_paint_shadow (widget->style, widget->window,
951 GTK_STATE_NORMAL, GTK_SHADOW_IN,
952 NULL, widget, "entry",
953 x, y, width, height);
956 gdk_window_clear (widget->window);
958 if (GTK_WIDGET_HAS_FOCUS (widget))
960 gdk_window_get_size (widget->window, &width, &height);
961 gtk_paint_focus (widget->style, widget->window,
962 NULL, widget, "entry",
963 0, 0, width - 1, height - 1);
969 gtk_entry_expose (GtkWidget *widget,
970 GdkEventExpose *event)
974 g_return_val_if_fail (widget != NULL, FALSE);
975 g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
976 g_return_val_if_fail (event != NULL, FALSE);
978 entry = GTK_ENTRY (widget);
980 if (widget->window == event->window)
981 gtk_widget_draw_focus (widget);
982 else if (entry->text_area == event->window)
984 gtk_entry_draw_text (GTK_ENTRY (widget));
986 if ((entry->visible || entry->invisible_char != 0) &&
987 GTK_WIDGET_HAS_FOCUS (widget) &&
988 entry->selection_bound == entry->current_pos)
989 gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_STANDARD);
991 if (entry->dnd_position != -1)
992 gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_DND);
999 gtk_entry_button_press (GtkWidget *widget,
1000 GdkEventButton *event)
1002 GtkEntry *entry = GTK_ENTRY (widget);
1003 GtkEditable *editable = GTK_EDITABLE (widget);
1005 gint sel_start, sel_end;
1007 entry = GTK_ENTRY (widget);
1008 editable = GTK_EDITABLE (widget);
1010 if (event->window != entry->text_area ||
1011 (entry->button && event->button != entry->button))
1014 entry->button = event->button;
1016 if (!GTK_WIDGET_HAS_FOCUS (widget))
1017 gtk_widget_grab_focus (widget);
1019 tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
1021 if (event->button == 1)
1023 switch (event->type)
1025 case GDK_BUTTON_PRESS:
1026 if (gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end) &&
1027 tmp_pos >= sel_start && tmp_pos <= sel_end)
1029 /* Click inside the selection - we'll either start a drag, or
1030 * clear the selection
1033 entry->in_drag = TRUE;
1034 entry->drag_start_x = event->x + entry->scroll_offset;
1035 entry->drag_start_y = event->y + entry->scroll_offset;
1039 gtk_entry_reset_im_context (entry);
1041 entry->current_pos = tmp_pos;
1042 entry->selection_bound = tmp_pos;
1044 gtk_entry_recompute (entry);
1049 case GDK_2BUTTON_PRESS:
1050 gtk_entry_select_word (entry);
1053 case GDK_3BUTTON_PRESS:
1054 gtk_entry_select_line (entry);
1063 else if (event->button == 2 && event->type == GDK_BUTTON_PRESS && entry->editable)
1065 gtk_editable_select_region (editable, tmp_pos, tmp_pos);
1066 gtk_entry_paste (entry, GDK_SELECTION_PRIMARY);
1070 else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
1072 gtk_entry_popup_menu (entry, event);
1073 entry->button = 0; /* Don't wait for release, since the menu will gtk_grab_add */
1082 gtk_entry_button_release (GtkWidget *widget,
1083 GdkEventButton *event)
1085 GtkEntry *entry = GTK_ENTRY (widget);
1087 if (event->window != entry->text_area || entry->button != event->button)
1092 gint tmp_pos = gtk_entry_find_position (entry, entry->drag_start_x);
1094 gtk_entry_reset_im_context (entry);
1096 entry->current_pos = tmp_pos;
1097 entry->selection_bound = tmp_pos;
1099 gtk_entry_recompute (entry);
1106 gtk_entry_update_primary_selection (entry);
1112 gtk_entry_motion_notify (GtkWidget *widget,
1113 GdkEventMotion *event)
1115 GtkEntry *entry = GTK_ENTRY (widget);
1118 if (event->window != entry->text_area || entry->button != 1)
1121 if (event->is_hint || (entry->text_area != event->window))
1122 gdk_window_get_pointer (entry->text_area, NULL, NULL, NULL);
1126 if (gtk_drag_check_threshold (widget,
1127 entry->drag_start_x, entry->drag_start_y,
1128 event->x + entry->scroll_offset, event->y))
1130 GdkDragContext *context;
1131 GtkTargetList *target_list = gtk_target_list_new (target_table, G_N_ELEMENTS (target_table));
1133 context = gtk_drag_begin (widget, target_list, GDK_ACTION_COPY | GDK_ACTION_MOVE,
1134 entry->button, (GdkEvent *)event);
1137 entry->in_drag = FALSE;
1140 gtk_target_list_unref (target_list);
1141 gtk_drag_set_icon_default (context);
1146 tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
1148 if (tmp_pos != entry->current_pos)
1150 entry->current_pos = tmp_pos;
1151 gtk_entry_recompute (entry);
1159 gtk_entry_key_press (GtkWidget *widget,
1162 GtkEntry *entry = GTK_ENTRY (widget);
1164 if (!entry->editable)
1167 if (gtk_im_context_filter_keypress (entry->im_context, event))
1169 entry->need_im_reset = TRUE;
1172 else if (GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
1173 /* Activate key bindings
1176 else if (event->keyval == GDK_Return)
1178 gtk_widget_activate (widget);
1186 gtk_entry_focus_in (GtkWidget *widget,
1187 GdkEventFocus *event)
1189 g_return_val_if_fail (widget != NULL, FALSE);
1190 g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
1191 g_return_val_if_fail (event != NULL, FALSE);
1193 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
1194 gtk_widget_draw_focus (widget);
1195 gtk_entry_queue_draw (GTK_ENTRY (widget));
1197 GTK_ENTRY (widget)->need_im_reset = TRUE;
1198 gtk_im_context_focus_in (GTK_ENTRY (widget)->im_context);
1204 gtk_entry_focus_out (GtkWidget *widget,
1205 GdkEventFocus *event)
1207 g_return_val_if_fail (widget != NULL, FALSE);
1208 g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
1209 g_return_val_if_fail (event != NULL, FALSE);
1211 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
1212 gtk_widget_draw_focus (widget);
1213 gtk_entry_queue_draw (GTK_ENTRY (widget));
1215 GTK_ENTRY (widget)->need_im_reset = TRUE;
1216 gtk_im_context_focus_out (GTK_ENTRY (widget)->im_context);
1222 gtk_entry_direction_changed (GtkWidget *widget,
1223 GtkTextDirection previous_dir)
1225 GtkEntry *entry = GTK_ENTRY (widget);
1227 gtk_entry_recompute (entry);
1229 GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir);
1233 gtk_entry_state_changed (GtkWidget *widget,
1234 GtkStateType previous_state)
1236 g_return_if_fail (widget != NULL);
1237 g_return_if_fail (GTK_IS_ENTRY (widget));
1239 if (GTK_WIDGET_REALIZED (widget))
1241 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
1242 gdk_window_set_background (GTK_ENTRY (widget)->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
1245 gtk_widget_queue_clear (widget);
1248 /* GtkEditable method implementations
1251 gtk_entry_insert_text (GtkEditable *editable,
1252 const gchar *new_text,
1253 gint new_text_length,
1256 GtkEntry *entry = GTK_ENTRY (editable);
1260 if (*position < 0 || *position > entry->text_length)
1261 *position = entry->text_length;
1263 g_object_ref (G_OBJECT (editable));
1265 if (new_text_length <= 63)
1268 text = g_new (gchar, new_text_length + 1);
1270 text[new_text_length] = '\0';
1271 strncpy (text, new_text, new_text_length);
1273 gtk_signal_emit (GTK_OBJECT (editable), signals[INSERT_TEXT], text, new_text_length, position);
1274 gtk_signal_emit (GTK_OBJECT (editable), signals[CHANGED]);
1276 if (new_text_length > 63)
1279 g_object_unref (G_OBJECT (editable));
1283 gtk_entry_delete_text (GtkEditable *editable,
1287 GtkEntry *entry = GTK_ENTRY (editable);
1289 if (end_pos < 0 || end_pos > entry->text_length)
1290 end_pos = entry->text_length;
1293 if (start_pos > end_pos)
1294 start_pos = end_pos;
1296 g_object_ref (G_OBJECT (editable));
1298 gtk_signal_emit (GTK_OBJECT (editable), signals[DELETE_TEXT], start_pos, end_pos);
1299 gtk_signal_emit (GTK_OBJECT (editable), signals[CHANGED]);
1301 g_object_unref (G_OBJECT (editable));
1305 gtk_entry_get_chars (GtkEditable *editable,
1310 gint start_index, end_index;
1312 g_return_val_if_fail (editable != NULL, NULL);
1313 g_return_val_if_fail (GTK_IS_ENTRY (editable), NULL);
1315 entry = GTK_ENTRY (editable);
1318 end_pos = entry->text_length;
1320 start_pos = MIN (entry->text_length, start_pos);
1321 end_pos = MIN (entry->text_length, end_pos);
1323 start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text;
1324 end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text;
1326 return g_strndup (entry->text + start_index, end_index - start_index);
1330 gtk_entry_real_set_position (GtkEditable *editable,
1333 GtkEntry *entry = GTK_ENTRY (editable);
1335 if (position < 0 || position > entry->text_length)
1336 position = entry->text_length;
1338 if (position != entry->current_pos)
1340 gtk_entry_reset_im_context (entry);
1342 entry->current_pos = entry->selection_bound = position;
1343 gtk_entry_recompute (entry);
1348 gtk_entry_get_position (GtkEditable *editable)
1350 return GTK_ENTRY (editable)->current_pos;
1354 gtk_entry_set_selection_bounds (GtkEditable *editable,
1358 GtkEntry *entry = GTK_ENTRY (editable);
1361 start = entry->text_length;
1363 end = entry->text_length;
1365 gtk_entry_reset_im_context (entry);
1367 entry->selection_bound = MIN (start, entry->text_length);
1368 entry->current_pos = MIN (end, entry->text_length);
1370 gtk_entry_update_primary_selection (entry);
1372 gtk_entry_recompute (entry);
1376 gtk_entry_get_selection_bounds (GtkEditable *editable,
1380 GtkEntry *entry = GTK_ENTRY (editable);
1382 *start = entry->selection_bound;
1383 *end = entry->current_pos;
1385 return (entry->selection_bound != entry->current_pos);
1389 gtk_entry_style_set (GtkWidget *widget,
1390 GtkStyle *previous_style)
1392 GtkEntry *entry = GTK_ENTRY (widget);
1394 if (previous_style && GTK_WIDGET_REALIZED (widget))
1396 gtk_entry_recompute (entry);
1398 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
1399 gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
1404 strstr_len (const char *haystack,
1410 g_return_val_if_fail (haystack != NULL, NULL);
1411 g_return_val_if_fail (needle != NULL, NULL);
1413 if (haystack_len < 0)
1414 return strstr (haystack, needle);
1417 const char *p = haystack;
1418 int needle_len = strlen (needle);
1419 const char *end = haystack + haystack_len - needle_len;
1421 if (needle_len == 0)
1422 return (char *)haystack;
1424 while (*p && p <= end)
1426 for (i = 0; i < needle_len; i++)
1427 if (p[i] != needle[i])
1440 /* Default signal handlers
1443 gtk_entry_real_insert_text (GtkEntry *entry,
1444 const gchar *new_text,
1445 gint new_text_length,
1450 gchar line_separator[7];
1454 if (new_text_length < 0)
1455 new_text_length = strlen (new_text);
1457 /* We don't want to allow inserting paragraph delimeters
1459 pango_find_paragraph_boundary (new_text, new_text_length, &new_text_length, NULL);
1461 /* Or line separators - this is really painful
1463 len = g_unichar_to_utf8 (0x2028, line_separator); /* 0x2028 == LS */
1464 line_separator[len] = '\0';
1466 p = strstr_len (new_text, new_text_length, line_separator);
1468 new_text_length = p - new_text;
1470 n_chars = g_utf8_strlen (new_text, new_text_length);
1471 if (entry->text_max_length > 0 && n_chars + entry->text_length > entry->text_max_length)
1474 n_chars = entry->text_max_length - entry->text_length;
1477 if (new_text_length + entry->n_bytes + 1 > entry->text_size)
1479 while (new_text_length + entry->n_bytes + 1 > entry->text_size)
1481 if (entry->text_size == 0)
1482 entry->text_size = MIN_SIZE;
1485 if (2 * (guint)entry->text_size < MAX_SIZE &&
1486 2 * (guint)entry->text_size > entry->text_size)
1487 entry->text_size *= 2;
1490 entry->text_size = MAX_SIZE;
1491 new_text_length = entry->text_size - new_text_length - 1;
1497 entry->text = g_realloc (entry->text, entry->text_size);
1500 index = g_utf8_offset_to_pointer (entry->text, *position) - entry->text;
1502 g_memmove (entry->text + index + new_text_length, entry->text + index, entry->n_bytes - index);
1503 memcpy (entry->text + index, new_text, new_text_length);
1505 entry->n_bytes += new_text_length;
1506 entry->text_length += n_chars;
1508 /* NUL terminate for safety and convenience */
1509 entry->text[entry->n_bytes] = '\0';
1511 if (entry->current_pos > *position)
1512 entry->current_pos += n_chars;
1514 if (entry->selection_bound > *position)
1515 entry->selection_bound += n_chars;
1517 *position += n_chars;
1519 gtk_entry_recompute (entry);
1523 gtk_entry_real_delete_text (GtkEntry *entry,
1529 if (end_pos < 0 || end_pos > entry->text_length)
1530 end_pos = entry->text_length;
1532 if (start_pos < end_pos)
1534 gint start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text;
1535 gint end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text;
1537 g_memmove (entry->text + start_index, entry->text + end_index, entry->n_bytes - end_index);
1538 entry->text_length -= (end_pos - start_pos);
1539 entry->n_bytes -= (end_index - start_index);
1541 if (entry->current_pos > start_pos)
1542 entry->current_pos -= MIN (entry->current_pos, end_pos) - start_pos;
1544 if (entry->selection_bound > start_pos)
1545 entry->selection_bound -= MIN (entry->selection_bound, end_pos) - start_pos;
1548 /* We might have deleted the selection
1550 gtk_entry_update_primary_selection (entry);
1552 gtk_entry_recompute (entry);
1557 gtk_entry_move_cursor (GtkEntry *entry,
1558 GtkMovementStep step,
1560 gboolean extend_selection)
1562 gint new_pos = entry->current_pos;
1564 gtk_entry_reset_im_context (entry);
1568 case GTK_MOVEMENT_LOGICAL_POSITIONS:
1569 new_pos = CLAMP (new_pos + count, 0, entry->text_length);
1571 case GTK_MOVEMENT_VISUAL_POSITIONS:
1572 new_pos = gtk_entry_move_visually (entry, new_pos, count);
1574 case GTK_MOVEMENT_WORDS:
1577 new_pos = gtk_entry_move_forward_word (entry, new_pos);
1582 new_pos = gtk_entry_move_backward_word (entry, new_pos);
1586 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
1587 case GTK_MOVEMENT_PARAGRAPH_ENDS:
1588 case GTK_MOVEMENT_BUFFER_ENDS:
1589 new_pos = count < 0 ? 0 : entry->text_length;
1591 case GTK_MOVEMENT_DISPLAY_LINES:
1592 case GTK_MOVEMENT_PARAGRAPHS:
1593 case GTK_MOVEMENT_PAGES:
1597 if (extend_selection)
1598 gtk_editable_select_region (GTK_EDITABLE (entry), entry->selection_bound, new_pos);
1600 gtk_editable_set_position (GTK_EDITABLE (entry), new_pos);
1604 gtk_entry_insert_at_cursor (GtkEntry *entry,
1607 GtkEditable *editable = GTK_EDITABLE (entry);
1608 gint pos = entry->current_pos;
1610 gtk_entry_reset_im_context (entry);
1612 gtk_editable_insert_text (editable, str, -1, &pos);
1613 gtk_editable_set_position (editable, pos);
1617 gtk_entry_delete_from_cursor (GtkEntry *entry,
1621 GtkEditable *editable = GTK_EDITABLE (entry);
1622 gint start_pos = entry->current_pos;
1623 gint end_pos = entry->current_pos;
1625 gtk_entry_reset_im_context (entry);
1627 if (!entry->editable)
1630 if (entry->selection_bound != entry->current_pos)
1632 gtk_editable_delete_selection (editable);
1638 case GTK_DELETE_CHARS:
1639 end_pos = entry->current_pos + count;
1640 gtk_editable_delete_text (editable, MIN (start_pos, end_pos), MAX (start_pos, end_pos));
1642 case GTK_DELETE_WORDS:
1645 /* Move to end of current word, or if not on a word, end of previous word */
1646 end_pos = gtk_entry_move_backward_word (entry, end_pos);
1647 end_pos = gtk_entry_move_forward_word (entry, end_pos);
1651 /* Move to beginning of current word, or if not on a word, begining of next word */
1652 start_pos = gtk_entry_move_forward_word (entry, start_pos);
1653 start_pos = gtk_entry_move_backward_word (entry, start_pos);
1657 case GTK_DELETE_WORD_ENDS:
1660 start_pos = gtk_entry_move_backward_word (entry, start_pos);
1665 end_pos = gtk_entry_move_forward_word (entry, end_pos);
1668 gtk_editable_delete_text (editable, start_pos, end_pos);
1670 case GTK_DELETE_DISPLAY_LINE_ENDS:
1671 case GTK_DELETE_PARAGRAPH_ENDS:
1673 gtk_editable_delete_text (editable, 0, entry->current_pos);
1675 gtk_editable_delete_text (editable, entry->current_pos, -1);
1677 case GTK_DELETE_DISPLAY_LINES:
1678 case GTK_DELETE_PARAGRAPHS:
1679 gtk_editable_delete_text (editable, 0, -1);
1681 case GTK_DELETE_WHITESPACE:
1682 gtk_entry_delete_whitespace (entry);
1688 gtk_entry_copy_clipboard (GtkEntry *entry)
1690 GtkEditable *editable = GTK_EDITABLE (entry);
1693 if (gtk_editable_get_selection_bounds (editable, &start, &end))
1695 gchar *str = gtk_entry_get_public_chars (entry, start, end);
1696 gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), str, -1);
1702 gtk_entry_cut_clipboard (GtkEntry *entry)
1704 GtkEditable *editable = GTK_EDITABLE (entry);
1707 gtk_entry_copy_clipboard (entry);
1708 if (gtk_editable_get_selection_bounds (editable, &start, &end))
1709 gtk_editable_delete_text (editable, start, end);
1713 gtk_entry_paste_clipboard (GtkEntry *entry)
1715 gtk_entry_paste (entry, GDK_NONE);
1719 gtk_entry_toggle_overwrite (GtkEntry *entry)
1721 entry->overwrite_mode = !entry->overwrite_mode;
1724 /* IM Context Callbacks
1728 gtk_entry_commit_cb (GtkIMContext *context,
1732 GtkEditable *editable = GTK_EDITABLE (entry);
1733 gint tmp_pos = entry->current_pos;
1735 gtk_editable_insert_text (editable, str, strlen (str), &tmp_pos);
1736 gtk_editable_set_position (editable, tmp_pos);
1740 gtk_entry_preedit_changed_cb (GtkIMContext *context,
1743 gchar *preedit_string;
1746 gtk_im_context_get_preedit_string (entry->im_context,
1747 &preedit_string, NULL,
1749 entry->preedit_length = strlen (preedit_string);
1750 cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (preedit_string, -1));
1751 entry->preedit_cursor = cursor_pos;
1752 g_free (preedit_string);
1754 gtk_entry_recompute (entry);
1757 /* Internal functions
1761 gtk_entry_reset_layout (GtkEntry *entry)
1763 if (entry->cached_layout)
1765 g_object_unref (G_OBJECT (entry->cached_layout));
1766 entry->cached_layout = NULL;
1771 recompute_idle_func (gpointer data)
1773 GtkEntry *entry = GTK_ENTRY (data);
1775 gtk_entry_adjust_scroll (entry);
1776 gtk_entry_queue_draw (entry);
1778 entry->recompute_idle = FALSE;
1784 gtk_entry_recompute (GtkEntry *entry)
1786 gtk_entry_reset_layout (entry);
1788 if (!entry->recompute_idle)
1790 entry->recompute_idle = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 15, /* between resize and redraw */
1791 recompute_idle_func, entry, NULL);
1796 append_char (GString *str,
1804 char_len = g_unichar_to_utf8 (ch, buf);
1809 g_string_append_len (str, buf, char_len);
1814 static PangoLayout *
1815 gtk_entry_create_layout (GtkEntry *entry,
1816 gboolean include_preedit)
1818 PangoLayout *layout = gtk_widget_create_pango_layout (GTK_WIDGET (entry), NULL);
1819 PangoAttrList *tmp_attrs = pango_attr_list_new ();
1821 gchar *preedit_string = NULL;
1822 gint preedit_length = 0;
1823 PangoAttrList *preedit_attrs = NULL;
1825 if (include_preedit)
1827 gtk_im_context_get_preedit_string (entry->im_context,
1828 &preedit_string, &preedit_attrs, NULL);
1829 preedit_length = entry->preedit_length;
1834 GString *tmp_string = g_string_new (NULL);
1836 gint cursor_index = g_utf8_offset_to_pointer (entry->text, entry->current_pos) - entry->text;
1840 g_string_prepend_len (tmp_string, entry->text, entry->n_bytes);
1841 g_string_insert (tmp_string, cursor_index, preedit_string);
1846 gint preedit_len_chars;
1847 gunichar invisible_char;
1849 ch_len = g_utf8_strlen (entry->text, entry->n_bytes);
1850 preedit_len_chars = g_utf8_strlen (preedit_string, -1);
1851 ch_len += preedit_len_chars;
1853 if (entry->invisible_char != 0)
1854 invisible_char = entry->invisible_char;
1856 invisible_char = ' '; /* just pick a char */
1858 append_char (tmp_string, invisible_char, ch_len);
1860 /* Fix cursor index to point to invisible char corresponding
1861 * to the preedit, fix preedit_length to be the length of
1862 * the invisible chars representing the preedit
1865 g_utf8_offset_to_pointer (tmp_string->str, entry->current_pos) -
1869 g_unichar_to_utf8 (invisible_char, NULL);
1872 pango_layout_set_text (layout, tmp_string->str, tmp_string->len);
1874 pango_attr_list_splice (tmp_attrs, preedit_attrs,
1875 cursor_index, preedit_length);
1877 g_string_free (tmp_string, TRUE);
1883 pango_layout_set_text (layout, entry->text, entry->n_bytes);
1887 GString *str = g_string_new (NULL);
1888 gunichar invisible_char;
1890 if (entry->invisible_char != 0)
1891 invisible_char = entry->invisible_char;
1893 invisible_char = ' '; /* just pick a char */
1895 append_char (str, invisible_char, entry->text_length);
1896 pango_layout_set_text (layout, str->str, str->len);
1897 g_string_free (str, TRUE);
1901 pango_layout_set_attributes (layout, tmp_attrs);
1904 g_free (preedit_string);
1906 pango_attr_list_unref (preedit_attrs);
1908 pango_attr_list_unref (tmp_attrs);
1913 static PangoLayout *
1914 gtk_entry_get_layout (GtkEntry *entry,
1915 gboolean include_preedit)
1917 if (entry->preedit_length > 0 &&
1918 !include_preedit != !entry->cache_includes_preedit)
1919 gtk_entry_reset_layout (entry);
1921 if (!entry->cached_layout)
1923 entry->cached_layout = gtk_entry_create_layout (entry, include_preedit);
1924 entry->cache_includes_preedit = include_preedit;
1927 g_object_ref (G_OBJECT (entry->cached_layout));
1928 return entry->cached_layout;
1932 gtk_entry_draw_text (GtkEntry *entry)
1935 PangoLayoutLine *line;
1937 g_return_if_fail (entry != NULL);
1938 g_return_if_fail (GTK_IS_ENTRY (entry));
1940 if (!entry->visible && entry->invisible_char == 0)
1943 if (GTK_WIDGET_DRAWABLE (entry))
1945 PangoLayout *layout = gtk_entry_get_layout (entry, TRUE);
1946 PangoRectangle logical_rect;
1947 gint area_width, area_height;
1948 gint start_pos, end_pos;
1951 gdk_window_get_size (entry->text_area, &area_width, &area_height);
1952 area_height = PANGO_SCALE * (area_height - 2 * INNER_BORDER);
1954 widget = GTK_WIDGET (entry);
1956 gtk_paint_flat_box (widget->style, entry->text_area,
1957 GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
1958 NULL, widget, "entry_bg",
1959 0, 0, area_width, area_height);
1961 line = pango_layout_get_lines (layout)->data;
1962 pango_layout_line_get_extents (line, NULL, &logical_rect);
1964 /* Align primarily for locale's ascent/descent */
1965 y_pos = ((area_height - entry->ascent - entry->descent) / 2 +
1966 entry->ascent + logical_rect.y);
1968 /* Now see if we need to adjust to fit in actual drawn string */
1969 if (logical_rect.height > area_height)
1970 y_pos = (area_height - logical_rect.height) / 2;
1973 else if (y_pos + logical_rect.height > area_height)
1974 y_pos = area_height - logical_rect.height;
1976 y_pos = INNER_BORDER + y_pos / PANGO_SCALE;
1978 gdk_draw_layout (entry->text_area, widget->style->text_gc [widget->state],
1979 INNER_BORDER - entry->scroll_offset, y_pos,
1982 if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start_pos, &end_pos))
1986 gint start_index = g_utf8_offset_to_pointer (entry->text, start_pos) - entry->text;
1987 gint end_index = g_utf8_offset_to_pointer (entry->text, end_pos) - entry->text;
1988 GdkRegion *clip_region = gdk_region_new ();
1990 pango_layout_line_get_x_ranges (line, start_index, end_index, &ranges, &n_ranges);
1992 for (i=0; i < n_ranges; i++)
1996 rect.x = INNER_BORDER - entry->scroll_offset + ranges[2*i] / PANGO_SCALE;
1998 rect.width = (ranges[2*i + 1] - ranges[2*i]) / PANGO_SCALE;
1999 rect.height = logical_rect.height / PANGO_SCALE;
2001 gdk_draw_rectangle (entry->text_area, widget->style->bg_gc [GTK_STATE_SELECTED], TRUE,
2002 rect.x, rect.y, rect.width, rect.height);
2004 gdk_region_union_with_rect (clip_region, &rect);
2007 gdk_gc_set_clip_region (widget->style->fg_gc [GTK_STATE_SELECTED], clip_region);
2008 gdk_draw_layout (entry->text_area, widget->style->fg_gc [GTK_STATE_SELECTED],
2009 INNER_BORDER - entry->scroll_offset, y_pos,
2011 gdk_gc_set_clip_region (widget->style->fg_gc [GTK_STATE_SELECTED], NULL);
2013 gdk_region_destroy (clip_region);
2017 g_object_unref (G_OBJECT (layout));
2022 gtk_entry_draw_cursor (GtkEntry *entry,
2025 g_return_if_fail (entry != NULL);
2026 g_return_if_fail (GTK_IS_ENTRY (entry));
2028 if (GTK_WIDGET_DRAWABLE (entry))
2030 GtkWidget *widget = GTK_WIDGET (entry);
2032 gint xoffset = INNER_BORDER - entry->scroll_offset;
2033 gint strong_x, weak_x;
2034 gint text_area_height;
2036 gdk_window_get_size (entry->text_area, NULL, &text_area_height);
2038 gtk_entry_get_cursor_locations (entry, type, &strong_x, &weak_x);
2040 gdk_draw_line (entry->text_area, widget->style->bg_gc[GTK_STATE_SELECTED],
2041 xoffset + strong_x, INNER_BORDER,
2042 xoffset + strong_x, text_area_height - INNER_BORDER);
2044 if (weak_x != strong_x)
2045 gdk_draw_line (entry->text_area, widget->style->fg_gc[GTK_STATE_NORMAL],
2046 xoffset + weak_x, INNER_BORDER,
2047 xoffset + weak_x, text_area_height - INNER_BORDER);
2052 gtk_entry_queue_draw (GtkEntry *entry)
2054 g_return_if_fail (entry != NULL);
2055 g_return_if_fail (GTK_IS_ENTRY (entry));
2057 if (GTK_WIDGET_REALIZED (entry))
2059 GdkRectangle rect = { 0 };
2061 gdk_window_get_size (entry->text_area, &rect.width, &rect.height);
2062 gdk_window_invalidate_rect (entry->text_area, &rect, FALSE);
2067 gtk_entry_reset_im_context (GtkEntry *entry)
2069 if (entry->need_im_reset)
2071 entry->need_im_reset = 0;
2072 gtk_im_context_reset (entry->im_context);
2077 gtk_entry_find_position (GtkEntry *entry,
2080 PangoLayout *layout;
2081 PangoLayoutLine *line;
2085 gint cursor_index = g_utf8_offset_to_pointer (entry->text, entry->current_pos) - entry->text;
2087 layout = gtk_entry_get_layout (entry, TRUE);
2089 line = pango_layout_get_lines (layout)->data;
2090 pango_layout_line_x_to_index (line, x * PANGO_SCALE, &index, &trailing);
2092 g_object_unref (G_OBJECT (layout));
2094 if (index >= cursor_index && entry->preedit_length)
2096 if (index >= cursor_index + entry->preedit_length)
2097 index -= entry->preedit_length;
2100 index = cursor_index;
2105 pos = g_utf8_pointer_to_offset (entry->text, entry->text + index);
2114 gtk_entry_get_cursor_locations (GtkEntry *entry,
2119 PangoLayout *layout = gtk_entry_get_layout (entry, TRUE);
2121 PangoRectangle strong_pos, weak_pos;
2124 if (type == CURSOR_STANDARD)
2126 text = pango_layout_get_text (layout);
2127 index = g_utf8_offset_to_pointer (text, entry->current_pos + entry->preedit_cursor) - text;
2129 else /* type == CURSOR_DND */
2131 index = g_utf8_offset_to_pointer (entry->text, entry->dnd_position) - entry->text;
2132 if (entry->dnd_position > entry->current_pos)
2133 index += entry->preedit_length;
2136 pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos);
2137 g_object_unref (G_OBJECT (layout));
2140 *strong_x = strong_pos.x / PANGO_SCALE;
2143 *weak_x = weak_pos.x / PANGO_SCALE;
2147 gtk_entry_adjust_scroll (GtkEntry *entry)
2150 gint min_offset, max_offset;
2151 gint text_area_width;
2152 gint strong_x, weak_x;
2153 gint strong_xoffset, weak_xoffset;
2154 PangoLayout *layout;
2155 PangoLayoutLine *line;
2156 PangoRectangle logical_rect;
2158 g_return_if_fail (entry != NULL);
2159 g_return_if_fail (GTK_IS_ENTRY (entry));
2161 widget = GTK_WIDGET (entry);
2163 if (!GTK_WIDGET_REALIZED (entry))
2166 gdk_window_get_size (entry->text_area, &text_area_width, NULL);
2167 text_area_width -= 2 * INNER_BORDER;
2169 layout = gtk_entry_get_layout (entry, TRUE);
2170 line = pango_layout_get_lines (layout)->data;
2172 pango_layout_line_get_extents (line, NULL, &logical_rect);
2173 g_object_unref (G_OBJECT (layout));
2175 /* Display as much text as we can */
2177 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
2180 max_offset = MAX (min_offset, logical_rect.width / PANGO_SCALE - text_area_width);
2184 max_offset = logical_rect.width / PANGO_SCALE - text_area_width;
2185 min_offset = MIN (0, max_offset);
2188 entry->scroll_offset = CLAMP (entry->scroll_offset, min_offset, max_offset);
2190 /* And make sure cursors are on screen. Note that the cursor is
2191 * actually drawn one pixel into the INNER_BORDER space on
2192 * the right, when the scroll is at the utmost right. This
2193 * looks better to to me than confining the cursor inside the
2194 * border entirely, though it means that the cursor gets one
2195 * pixel closer to the the edge of the widget on the right than
2196 * on the left. This might need changing if one changed
2197 * INNER_BORDER from 2 to 1, as one would do on a
2198 * small-screen-real-estate display.
2200 * We always make sure that the strong cursor is on screen, and
2201 * put the weak cursor on screen if possible.
2204 gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, &weak_x);
2206 strong_xoffset = strong_x - entry->scroll_offset;
2208 if (strong_xoffset < 0)
2210 entry->scroll_offset += strong_xoffset;
2213 else if (strong_xoffset > text_area_width)
2215 entry->scroll_offset += strong_xoffset - text_area_width;
2216 strong_xoffset = text_area_width;
2219 weak_xoffset = weak_x - entry->scroll_offset;
2221 if (weak_xoffset < 0 && strong_xoffset - weak_xoffset <= text_area_width)
2223 entry->scroll_offset += weak_xoffset;
2225 else if (weak_xoffset > text_area_width &&
2226 strong_xoffset - (weak_xoffset - text_area_width) >= 0)
2228 entry->scroll_offset += weak_xoffset - text_area_width;
2233 gtk_entry_move_visually (GtkEntry *entry,
2238 PangoLayout *layout = gtk_entry_get_layout (entry, FALSE);
2241 text = pango_layout_get_text (layout);
2243 index = g_utf8_offset_to_pointer (text, start) - text;
2247 int new_index, new_trailing;
2251 pango_layout_move_cursor_visually (layout, index, 0, 1, &new_index, &new_trailing);
2256 pango_layout_move_cursor_visually (layout, index, 0, -1, &new_index, &new_trailing);
2260 if (new_index < 0 || new_index == G_MAXINT)
2264 index = g_utf8_next_char (entry->text + new_index) - entry->text;
2269 g_object_unref (G_OBJECT (layout));
2271 return g_utf8_pointer_to_offset (text, text + index);
2275 gtk_entry_move_forward_word (GtkEntry *entry,
2278 gint new_pos = start;
2280 /* Prevent any leak of information */
2281 if (!entry->visible)
2283 new_pos = entry->text_length;
2285 else if (entry->text && (new_pos < entry->text_length))
2287 PangoLayout *layout = gtk_entry_get_layout (entry, FALSE);
2288 PangoLogAttr *log_attrs;
2291 pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
2293 /* Find the next word end */
2295 while (new_pos < n_attrs && !log_attrs[new_pos].is_word_end)
2299 g_object_unref (G_OBJECT (layout));
2307 gtk_entry_move_backward_word (GtkEntry *entry,
2310 gint new_pos = start;
2312 /* Prevent any leak of information */
2313 if (!entry->visible)
2317 else if (entry->text && start > 0)
2319 PangoLayout *layout = gtk_entry_get_layout (entry, FALSE);
2320 PangoLogAttr *log_attrs;
2323 pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
2325 new_pos = start - 1;
2327 /* Find the previous word beginning */
2328 while (new_pos > 0 && !log_attrs[new_pos].is_word_start)
2332 g_object_unref (G_OBJECT (layout));
2339 gtk_entry_delete_whitespace (GtkEntry *entry)
2341 PangoLayout *layout = gtk_entry_get_layout (entry, FALSE);
2342 PangoLogAttr *log_attrs;
2346 pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
2348 start = end = entry->current_pos;
2350 while (start > 0 && log_attrs[start-1].is_white)
2353 while (end < n_attrs && log_attrs[start-1].is_white)
2357 g_object_unref (G_OBJECT (layout));
2360 gtk_editable_delete_text (GTK_EDITABLE (entry), start, end);
2365 gtk_entry_select_word (GtkEntry *entry)
2367 gint start_pos = gtk_entry_move_backward_word (entry, entry->current_pos);
2368 gint end_pos = gtk_entry_move_forward_word (entry, entry->current_pos);
2370 gtk_editable_select_region (GTK_EDITABLE (entry), start_pos, end_pos);
2374 gtk_entry_select_line (GtkEntry *entry)
2376 gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
2380 * Like gtk_editable_get_chars, but if the editable is not
2381 * visible, return asterisks; also convert result to UTF-8.
2384 gtk_entry_get_public_chars (GtkEntry *entry,
2389 end = entry->text_length;
2392 return gtk_editable_get_chars (GTK_EDITABLE (entry), start, end);
2397 gint n_chars = end - start;
2399 str = g_malloc (n_chars + 1);
2400 for (i = 0; i < n_chars; i++)
2410 paste_received (GtkClipboard *clipboard,
2414 GtkEntry *entry = GTK_ENTRY (data);
2415 GtkEditable *editable = GTK_EDITABLE (entry);
2419 gint pos = entry->current_pos;
2421 gtk_editable_insert_text (editable, text, -1, &pos);
2422 gtk_editable_set_position (editable, pos);
2425 g_object_unref (G_OBJECT (entry));
2429 gtk_entry_paste (GtkEntry *entry,
2432 g_object_ref (G_OBJECT (entry));
2433 gtk_clipboard_request_text (gtk_clipboard_get (selection),
2434 paste_received, entry);
2438 primary_get_cb (GtkClipboard *clipboard,
2439 GtkSelectionData *selection_data,
2443 GtkEntry *entry = GTK_ENTRY (data);
2446 if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end))
2448 gchar *str = gtk_entry_get_public_chars (entry, start, end);
2449 gtk_selection_data_set_text (selection_data, str);
2455 primary_clear_cb (GtkClipboard *clipboard,
2458 GtkEntry *entry = GTK_ENTRY (data);
2460 gtk_editable_select_region (GTK_EDITABLE (entry), entry->current_pos, entry->current_pos);
2464 gtk_entry_update_primary_selection (GtkEntry *entry)
2466 static const GtkTargetEntry targets[] = {
2467 { "UTF8_STRING", 0, 0 },
2470 { "COMPOUND_TEXT", 0, 0 }
2473 GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
2476 if (gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &start, &end))
2478 if (!gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
2479 primary_get_cb, primary_clear_cb, G_OBJECT (entry)))
2480 primary_clear_cb (clipboard, entry);
2484 if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (entry))
2485 gtk_clipboard_clear (clipboard);
2493 gtk_entry_new (void)
2495 return GTK_WIDGET (gtk_type_new (GTK_TYPE_ENTRY));
2499 gtk_entry_new_with_max_length (guint16 max)
2503 entry = gtk_type_new (GTK_TYPE_ENTRY);
2504 entry->text_max_length = max;
2506 return GTK_WIDGET (entry);
2510 gtk_entry_set_text (GtkEntry *entry,
2515 GtkEditable *editable;
2517 g_return_if_fail (entry != NULL);
2518 g_return_if_fail (GTK_IS_ENTRY (entry));
2519 g_return_if_fail (text != NULL);
2521 editable = GTK_EDITABLE (entry);
2523 gtk_editable_delete_text (GTK_EDITABLE(entry), 0, -1);
2526 gtk_editable_insert_text (editable, text, strlen (text), &tmp_pos);
2530 gtk_entry_append_text (GtkEntry *entry,
2535 g_return_if_fail (entry != NULL);
2536 g_return_if_fail (GTK_IS_ENTRY (entry));
2537 g_return_if_fail (text != NULL);
2539 tmp_pos = entry->text_length;
2540 gtk_editable_insert_text (GTK_EDITABLE(entry), text, -1, &tmp_pos);
2544 gtk_entry_prepend_text (GtkEntry *entry,
2549 g_return_if_fail (entry != NULL);
2550 g_return_if_fail (GTK_IS_ENTRY (entry));
2551 g_return_if_fail (text != NULL);
2554 gtk_editable_insert_text (GTK_EDITABLE(entry), text, -1, &tmp_pos);
2558 gtk_entry_set_position (GtkEntry *entry,
2561 g_return_if_fail (entry != NULL);
2562 g_return_if_fail (GTK_IS_ENTRY (entry));
2564 gtk_editable_set_position (GTK_EDITABLE (entry), position);
2568 gtk_entry_set_visibility (GtkEntry *entry,
2571 g_return_if_fail (entry != NULL);
2572 g_return_if_fail (GTK_IS_ENTRY (entry));
2574 entry->visible = visible ? TRUE : FALSE;
2576 gtk_entry_recompute (entry);
2580 gtk_entry_set_invisible_char (GtkEntry *entry,
2583 g_return_if_fail (GTK_IS_ENTRY (entry));
2585 if (ch == entry->invisible_char)
2588 entry->invisible_char = ch;
2590 gtk_entry_recompute (entry);
2594 gtk_entry_set_editable(GtkEntry *entry,
2597 g_return_if_fail (entry != NULL);
2598 g_return_if_fail (GTK_IS_ENTRY (entry));
2600 gtk_editable_set_editable (GTK_EDITABLE (entry), editable);
2604 gtk_entry_get_text (GtkEntry *entry)
2606 g_return_val_if_fail (entry != NULL, NULL);
2607 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
2613 gtk_entry_select_region (GtkEntry *entry,
2617 gtk_editable_select_region (GTK_EDITABLE (entry), start, end);
2621 gtk_entry_set_max_length (GtkEntry *entry,
2624 g_return_if_fail (entry != NULL);
2625 g_return_if_fail (GTK_IS_ENTRY (entry));
2627 if (max && entry->text_length > max)
2628 gtk_editable_delete_text (GTK_EDITABLE(entry), max, -1);
2630 entry->text_max_length = max;
2634 * gtk_entry_set_has_frame:
2635 * @entry: a #GtkEntry
2636 * @setting: new value
2638 * Sets whether the entry has a beveled frame around it.
2641 gtk_entry_set_has_frame (GtkEntry *entry,
2644 g_return_if_fail (GTK_IS_ENTRY (entry));
2646 setting = (setting != FALSE);
2648 if (entry->has_frame != setting)
2649 gtk_widget_queue_resize (GTK_WIDGET (entry));
2651 entry->has_frame = setting;
2655 * gtk_entry_get_has_frame:
2656 * @entry: a #GtkEntry
2660 * Return value: whether the entry has a beveled frame
2663 gtk_entry_get_has_frame (GtkEntry *entry)
2665 g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
2667 return entry->has_frame;
2670 /* Quick hack of a popup menu
2673 activate_cb (GtkWidget *menuitem,
2676 const gchar *signal = gtk_object_get_data (GTK_OBJECT (menuitem), "gtk-signal");
2677 gtk_signal_emit_by_name (GTK_OBJECT (entry), signal);
2681 append_action_signal (GtkEntry *entry,
2684 const gchar *signal)
2686 GtkWidget *menuitem = gtk_menu_item_new_with_label (label);
2688 gtk_object_set_data (GTK_OBJECT (menuitem), "gtk-signal", (char *)signal);
2689 gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
2690 activate_cb, entry);
2692 gtk_widget_show (menuitem);
2693 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
2697 popup_menu_detach (GtkWidget *attach_widget,
2700 GTK_ENTRY (attach_widget)->popup_menu = NULL;
2704 gtk_entry_popup_menu (GtkEntry *entry,
2705 GdkEventButton *event)
2707 if (!entry->popup_menu)
2709 GtkWidget *menuitem;
2711 entry->popup_menu = gtk_menu_new ();
2713 gtk_menu_attach_to_widget (GTK_MENU (entry->popup_menu),
2717 append_action_signal (entry, entry->popup_menu, _("Cut"), "cut_clipboard");
2718 append_action_signal (entry, entry->popup_menu, _("Copy"), "copy_clipboard");
2719 append_action_signal (entry, entry->popup_menu, _("Paste"), "paste_clipboard");
2721 menuitem = gtk_menu_item_new (); /* Separator */
2722 gtk_widget_show (menuitem);
2723 gtk_menu_shell_append (GTK_MENU_SHELL (entry->popup_menu), menuitem);
2725 gtk_im_multicontext_append_menuitems (GTK_IM_MULTICONTEXT (entry->im_context),
2726 GTK_MENU_SHELL (entry->popup_menu));
2729 gtk_menu_popup (GTK_MENU (entry->popup_menu), NULL, NULL,
2731 event->button, event->time);
2735 gtk_entry_drag_leave (GtkWidget *widget,
2736 GdkDragContext *context,
2741 entry = GTK_ENTRY (widget);
2743 entry->dnd_position = -1;
2744 gtk_widget_queue_draw (widget);
2748 gtk_entry_drag_motion (GtkWidget *widget,
2749 GdkDragContext *context,
2755 GtkWidget *source_widget;
2756 GdkDragAction suggested_action;
2757 gint new_position, old_position;
2760 entry = GTK_ENTRY (widget);
2762 x -= widget->style->xthickness;
2763 y -= widget->style->ythickness;
2765 old_position = entry->dnd_position;
2766 new_position = gtk_entry_find_position (entry, x + entry->scroll_offset);
2768 source_widget = gtk_drag_get_source_widget (context);
2769 suggested_action = context->suggested_action;
2771 if (!gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &sel1, &sel2) ||
2772 new_position < sel1 || new_position > sel2)
2774 if (source_widget == widget)
2776 /* Default to MOVE, unless the user has
2777 * pressed ctrl or alt to affect available actions
2779 if ((context->actions & GDK_ACTION_MOVE) != 0)
2780 suggested_action = GDK_ACTION_MOVE;
2783 entry->dnd_position = new_position;
2787 if (source_widget == widget)
2788 suggested_action = 0; /* Can't drop in selection where drag started */
2790 entry->dnd_position = -1;
2793 gdk_drag_status (context, suggested_action, time);
2795 if (entry->dnd_position != old_position)
2796 gtk_widget_queue_draw (widget);
2802 gtk_entry_drag_data_received (GtkWidget *widget,
2803 GdkDragContext *context,
2806 GtkSelectionData *selection_data,
2811 GtkEditable *editable;
2814 entry = GTK_ENTRY (widget);
2815 editable = GTK_EDITABLE (widget);
2817 str = gtk_selection_data_get_text (selection_data);
2824 new_position = gtk_entry_find_position (entry, x + entry->scroll_offset);
2826 if (!gtk_editable_get_selection_bounds (editable, &sel1, &sel2) ||
2827 new_position < sel1 || new_position > sel2)
2829 gtk_editable_insert_text (editable, str, -1, &new_position);
2833 /* Replacing selection */
2834 gtk_editable_delete_text (editable, sel1, sel2);
2835 gtk_editable_insert_text (editable, str, -1, &sel1);
2843 gtk_entry_drag_data_get (GtkWidget *widget,
2844 GdkDragContext *context,
2845 GtkSelectionData *selection_data,
2849 gint sel_start, sel_end;
2851 GtkEditable *editable = GTK_EDITABLE (widget);
2853 if (gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end))
2855 gchar *str = gtk_editable_get_chars (editable, sel_start, sel_end);
2857 gtk_selection_data_set_text (selection_data, str);
2865 gtk_entry_drag_data_delete (GtkWidget *widget,
2866 GdkDragContext *context)
2868 gint sel_start, sel_end;
2870 GtkEditable *editable = GTK_EDITABLE (widget);
2872 if (gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end))
2873 gtk_editable_delete_text (editable, sel_start, sel_end);