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 Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "gdk/gdkkeysyms.h"
24 #include "gdk/gdki18n.h"
25 #include "gtkeditable.h"
27 #include "gtkselection.h"
28 #include "gtksignal.h"
30 #define MIN_EDITABLE_WIDTH 150
31 #define DRAW_TIMEOUT 20
32 #define INNER_BORDER 2
45 typedef void (*GtkEditableSignal1) (GtkObject *object,
50 typedef void (*GtkEditableSignal2) (GtkObject *object,
55 typedef gpointer (*GtkEditableSignal3) (GtkObject *object,
61 static void gtk_editable_marshal_signal_1 (GtkObject *object,
65 static void gtk_editable_marshal_signal_2 (GtkObject *object,
69 static void gtk_editable_marshal_signal_3 (GtkObject *object,
74 static void gtk_editable_class_init (GtkEditableClass *klass);
75 static void gtk_editable_init (GtkEditable *editable);
76 static void gtk_editable_finalize (GtkObject *object);
77 static gint gtk_editable_selection_clear (GtkWidget *widget,
78 GdkEventSelection *event);
79 static void gtk_editable_selection_handler (GtkWidget *widget,
80 GtkSelectionData *selection_data,
82 static void gtk_editable_selection_received (GtkWidget *widget,
83 GtkSelectionData *selection_data);
85 static void gtk_editable_set_selection (GtkEditable *editable,
89 static GtkWidgetClass *parent_class = NULL;
90 static gint editable_signals[LAST_SIGNAL] = { 0 };
91 static GdkAtom ctext_atom = GDK_NONE;
92 static GdkAtom text_atom = GDK_NONE;
93 static GdkAtom clipboard_atom = GDK_NONE;
96 gtk_editable_get_type ()
98 static guint editable_type = 0;
102 GtkTypeInfo editable_info =
105 sizeof (GtkEditable),
106 sizeof (GtkEditableClass),
107 (GtkClassInitFunc) gtk_editable_class_init,
108 (GtkObjectInitFunc) gtk_editable_init,
109 (GtkArgSetFunc) NULL,
110 (GtkArgGetFunc) NULL,
113 editable_type = gtk_type_unique (gtk_widget_get_type (), &editable_info);
116 return editable_type;
120 gtk_editable_class_init (GtkEditableClass *class)
122 GtkObjectClass *object_class;
123 GtkWidgetClass *widget_class;
125 object_class = (GtkObjectClass*) class;
126 widget_class = (GtkWidgetClass*) class;
128 parent_class = gtk_type_class (gtk_widget_get_type ());
130 editable_signals[INSERT_TEXT] =
131 gtk_signal_new ("insert_text",
134 GTK_SIGNAL_OFFSET (GtkEditableClass, insert_text),
135 gtk_editable_marshal_signal_1,
137 GTK_TYPE_STRING, GTK_TYPE_INT,
139 editable_signals[DELETE_TEXT] =
140 gtk_signal_new ("delete_text",
143 GTK_SIGNAL_OFFSET (GtkEditableClass, delete_text),
144 gtk_editable_marshal_signal_2,
146 GTK_TYPE_INT, GTK_TYPE_INT);
147 editable_signals[UPDATE_TEXT] =
148 gtk_signal_new ("update_text",
151 GTK_SIGNAL_OFFSET (GtkEditableClass, update_text),
152 gtk_editable_marshal_signal_2,
154 GTK_TYPE_INT, GTK_TYPE_INT);
155 editable_signals[GET_CHARS] =
156 gtk_signal_new ("get_chars",
159 GTK_SIGNAL_OFFSET (GtkEditableClass, get_chars),
160 gtk_editable_marshal_signal_3,
162 GTK_TYPE_INT, GTK_TYPE_INT);
163 editable_signals[SET_SELECTION] =
164 gtk_signal_new ("set_selection",
167 GTK_SIGNAL_OFFSET (GtkEditableClass, set_selection),
168 gtk_editable_marshal_signal_2,
170 GTK_TYPE_INT, GTK_TYPE_INT);
171 editable_signals[CHANGED] =
172 gtk_signal_new ("changed",
175 GTK_SIGNAL_OFFSET (GtkEditableClass, changed),
176 gtk_signal_default_marshaller,
179 gtk_object_class_add_signals (object_class, editable_signals, LAST_SIGNAL);
181 object_class->finalize = gtk_editable_finalize;
183 widget_class->selection_clear_event = gtk_editable_selection_clear;
184 widget_class->selection_received = gtk_editable_selection_received;
186 class->insert_text = NULL;
187 class->delete_text = NULL;
188 class->update_text = NULL;
189 class->get_chars = NULL;
190 class->set_selection = NULL;
191 class->changed = NULL;
195 gtk_editable_init (GtkEditable *editable)
197 GTK_WIDGET_SET_FLAGS (editable, GTK_CAN_FOCUS);
199 editable->selection_start_pos = 0;
200 editable->selection_end_pos = 0;
201 editable->has_selection = FALSE;
202 editable->editable = 1;
203 editable->clipboard_text = NULL;
210 clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
212 gtk_selection_add_handler (GTK_WIDGET(editable), GDK_SELECTION_PRIMARY,
213 GDK_TARGET_STRING, gtk_editable_selection_handler,
215 gtk_selection_add_handler (GTK_WIDGET(editable), clipboard_atom,
216 GDK_TARGET_STRING, gtk_editable_selection_handler,
220 text_atom = gdk_atom_intern ("TEXT", FALSE);
222 gtk_selection_add_handler (GTK_WIDGET(editable), GDK_SELECTION_PRIMARY,
224 gtk_editable_selection_handler,
226 gtk_selection_add_handler (GTK_WIDGET(editable), clipboard_atom,
228 gtk_editable_selection_handler,
232 ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
234 gtk_selection_add_handler (GTK_WIDGET(editable), GDK_SELECTION_PRIMARY,
236 gtk_editable_selection_handler,
238 gtk_selection_add_handler (GTK_WIDGET(editable), clipboard_atom,
240 gtk_editable_selection_handler,
245 gtk_editable_marshal_signal_1 (GtkObject *object,
250 GtkEditableSignal1 rfunc;
252 rfunc = (GtkEditableSignal1) func;
254 (* rfunc) (object, GTK_VALUE_STRING (args[0]), GTK_VALUE_INT (args[1]),
255 GTK_VALUE_POINTER (args[2]), func_data);
259 gtk_editable_marshal_signal_2 (GtkObject *object,
264 GtkEditableSignal2 rfunc;
266 rfunc = (GtkEditableSignal2) func;
268 (* rfunc) (object, GTK_VALUE_INT (args[0]), GTK_VALUE_INT (args[1]),
273 gtk_editable_marshal_signal_3 (GtkObject *object,
278 GtkEditableSignal3 rfunc;
279 gpointer *return_val;
281 rfunc = (GtkEditableSignal3) func;
283 return_val = GTK_RETLOC_POINTER (args[2]);
285 *return_val = (* rfunc) (object,
286 GTK_VALUE_INT (args[0]),
287 GTK_VALUE_INT (args[1]),
292 gtk_editable_finalize (GtkObject *object)
294 GtkEditable *editable;
296 g_return_if_fail (object != NULL);
297 g_return_if_fail (GTK_IS_EDITABLE (object));
299 editable = GTK_EDITABLE (object);
304 gdk_ic_destroy (editable->ic);
309 (* GTK_OBJECT_CLASS (parent_class)->finalize) (object);
313 gtk_editable_insert_text (GtkEditable *editable,
314 const gchar *new_text,
315 gint new_text_length,
321 g_return_if_fail (editable != NULL);
322 g_return_if_fail (GTK_IS_EDITABLE (editable));
324 if (new_text_length <= 64)
327 text = g_new (gchar, new_text_length);
329 strncpy (text, new_text, new_text_length);
331 gtk_signal_emit (GTK_OBJECT (editable), editable_signals[INSERT_TEXT],
332 text, new_text_length, position);
333 gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]);
335 if (new_text_length > 64)
340 gtk_editable_delete_text (GtkEditable *editable,
344 g_return_if_fail (editable != NULL);
345 g_return_if_fail (GTK_IS_EDITABLE (editable));
347 gtk_signal_emit (GTK_OBJECT (editable), editable_signals[DELETE_TEXT],
349 gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]);
353 gtk_editable_update_text (GtkEditable *editable,
357 g_return_if_fail (editable != NULL);
358 g_return_if_fail (GTK_IS_EDITABLE (editable));
360 gtk_signal_emit (GTK_OBJECT (editable), editable_signals[UPDATE_TEXT],
365 gtk_editable_get_chars (GtkEditable *editable,
369 gchar *retval = NULL;
371 g_return_val_if_fail (editable != NULL, NULL);
372 g_return_val_if_fail (GTK_IS_EDITABLE (editable), NULL);
374 gtk_signal_emit (GTK_OBJECT (editable), editable_signals[GET_CHARS],
375 start, end, &retval);
381 gtk_editable_set_selection (GtkEditable *editable,
385 g_return_if_fail (editable != NULL);
386 g_return_if_fail (GTK_IS_EDITABLE (editable));
388 gtk_signal_emit (GTK_OBJECT (editable), editable_signals[SET_SELECTION],
393 gtk_editable_selection_clear (GtkWidget *widget,
394 GdkEventSelection *event)
396 GtkEditable *editable;
398 g_return_val_if_fail (widget != NULL, FALSE);
399 g_return_val_if_fail (GTK_IS_EDITABLE (widget), FALSE);
400 g_return_val_if_fail (event != NULL, FALSE);
402 /* Let the selection handling code know that the selection
403 * has been changed, since we've overriden the default handler */
404 gtk_selection_clear (widget, event);
406 editable = GTK_EDITABLE (widget);
408 if (event->selection == GDK_SELECTION_PRIMARY)
410 if (editable->has_selection)
412 editable->has_selection = FALSE;
413 gtk_editable_update_text (editable, editable->selection_start_pos,
414 editable->selection_end_pos);
417 else if (event->selection == clipboard_atom)
419 g_free (editable->clipboard_text);
420 editable->clipboard_text = NULL;
427 gtk_editable_selection_handler (GtkWidget *widget,
428 GtkSelectionData *selection_data,
431 GtkEditable *editable;
432 gint selection_start_pos;
433 gint selection_end_pos;
438 g_return_if_fail (widget != NULL);
439 g_return_if_fail (GTK_IS_EDITABLE (widget));
441 editable = GTK_EDITABLE (widget);
443 if (selection_data->selection == GDK_SELECTION_PRIMARY)
445 selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos);
446 selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos);
447 str = gtk_editable_get_chars(editable,
450 length = selection_end_pos - selection_start_pos;
454 if (!editable->clipboard_text)
457 str = editable->clipboard_text;
458 length = strlen (editable->clipboard_text);
461 if (selection_data->target == GDK_SELECTION_TYPE_STRING)
463 gtk_selection_data_set (selection_data,
464 GDK_SELECTION_TYPE_STRING,
465 8*sizeof(gchar), str, length);
467 else if (selection_data->target == text_atom ||
468 selection_data->target == ctext_atom)
478 gdk_string_to_compound_text (str, &encoding, &format, &text, &new_length);
479 gtk_selection_data_set (selection_data, encoding, format, text, new_length);
480 gdk_free_compound_text (text);
484 if (str != editable->clipboard_text)
489 gtk_editable_selection_received (GtkWidget *widget,
490 GtkSelectionData *selection_data)
492 GtkEditable *editable;
496 enum {INVALID, STRING, CTEXT} type;
498 g_return_if_fail (widget != NULL);
499 g_return_if_fail (GTK_IS_EDITABLE (widget));
501 editable = GTK_EDITABLE (widget);
503 if (selection_data->type == GDK_TARGET_STRING)
505 else if (selection_data->type == ctext_atom)
510 if (type == INVALID || selection_data->length < 0)
512 /* avoid infinite loop */
513 if (selection_data->target != GDK_TARGET_STRING)
514 gtk_selection_convert (widget, selection_data->selection,
515 GDK_TARGET_STRING, GDK_CURRENT_TIME);
521 if ((editable->selection_start_pos != editable->selection_end_pos) &&
522 (!editable->has_selection ||
523 (selection_data->selection == clipboard_atom)))
527 /* Don't want to call gtk_editable_delete_selection here if we are going
528 * to reclaim the selection to avoid extra server traffic */
529 if (editable->has_selection)
531 gtk_editable_delete_text (editable,
532 MIN (editable->selection_start_pos, editable->selection_end_pos),
533 MAX (editable->selection_start_pos, editable->selection_end_pos));
536 gtk_editable_delete_selection (editable);
539 tmp_pos = old_pos = editable->current_pos;
544 selection_data->data[selection_data->length] = 0;
545 gtk_editable_insert_text (editable, selection_data->data,
546 strlen (selection_data->data), &tmp_pos);
547 editable->current_pos = tmp_pos;
555 count = gdk_text_property_to_text_list (selection_data->type,
556 selection_data->format,
557 selection_data->data,
558 selection_data->length,
560 for (i=0; i<count; i++)
562 gtk_editable_insert_text (editable, list[i], strlen (list[i]), &tmp_pos);
563 editable->current_pos = tmp_pos;
566 gdk_free_text_list (list);
569 case INVALID: /* quiet compiler */
574 gtk_editable_set_selection (editable, old_pos, editable->current_pos);
578 gtk_editable_delete_selection (GtkEditable *editable)
583 if (!editable->editable)
586 start = editable->selection_start_pos;
587 end = editable->selection_end_pos;
589 editable->selection_start_pos = 0;
590 editable->selection_end_pos = 0;
593 gtk_editable_delete_text (editable, MIN (start, end), MAX (start,end));
595 if (editable->has_selection)
597 editable->has_selection = FALSE;
598 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == GTK_WIDGET (editable)->window)
599 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
604 gtk_editable_claim_selection (GtkEditable *editable,
608 g_return_if_fail (GTK_WIDGET_REALIZED (editable));
610 editable->has_selection = FALSE;
614 if (gtk_selection_owner_set (GTK_WIDGET(editable), GDK_SELECTION_PRIMARY, time))
615 editable->has_selection = TRUE;
619 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) ==
620 GTK_WIDGET(editable)->window)
621 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, time);
626 gtk_editable_select_region (GtkEditable *editable,
630 if (GTK_WIDGET_REALIZED (editable))
631 gtk_editable_claim_selection (editable, start != end, GDK_CURRENT_TIME);
633 gtk_editable_set_selection (editable, start, end);
637 gtk_editable_cut_clipboard (GtkEditable *editable, guint32 time)
639 gtk_editable_copy_clipboard (editable, time);
640 gtk_editable_delete_selection (editable);
644 gtk_editable_copy_clipboard (GtkEditable *editable, guint32 time)
646 gint selection_start_pos;
647 gint selection_end_pos;
649 selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos);
650 selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos);
652 if (selection_start_pos != selection_end_pos)
654 if (gtk_selection_owner_set (GTK_WIDGET (editable),
657 editable->clipboard_text = gtk_editable_get_chars (editable,
664 gtk_editable_paste_clipboard (GtkEditable *editable, guint32 time)
666 if (editable->editable)
667 gtk_selection_convert (GTK_WIDGET(editable),
668 clipboard_atom, ctext_atom, time);
672 gtk_editable_changed (GtkEditable *editable)
674 gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]);