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 "gdk/gdkkeysyms.h"
30 #include "gdk/gdki18n.h"
31 #include "gtkclipboard.h"
32 #include "gtkoldeditable.h"
34 #include "gtkmarshalers.h"
35 #include "gtkselection.h"
36 #include "gtksignal.h"
38 #define MIN_EDITABLE_WIDTH 150
39 #define DRAW_TIMEOUT 20
40 #define INNER_BORDER 2
66 /* values for selection info */
74 static void gtk_old_editable_class_init (GtkOldEditableClass *klass);
75 static void gtk_old_editable_editable_init (GtkEditableClass *iface);
76 static void gtk_old_editable_init (GtkOldEditable *editable);
77 static void gtk_old_editable_set_arg (GtkObject *object,
80 static void gtk_old_editable_get_arg (GtkObject *object,
83 static void *gtk_old_editable_get_public_chars (GtkOldEditable *old_editable,
87 static gint gtk_old_editable_selection_clear (GtkWidget *widget,
88 GdkEventSelection *event);
89 static void gtk_old_editable_selection_get (GtkWidget *widget,
90 GtkSelectionData *selection_data,
93 static void gtk_old_editable_selection_received (GtkWidget *widget,
94 GtkSelectionData *selection_data,
97 static void gtk_old_editable_set_selection (GtkOldEditable *old_editable,
101 static void gtk_old_editable_real_set_editable (GtkOldEditable *old_editable,
102 gboolean is_editable);
103 static void gtk_old_editable_real_cut_clipboard (GtkOldEditable *old_editable);
104 static void gtk_old_editable_real_copy_clipboard (GtkOldEditable *old_editable);
105 static void gtk_old_editable_real_paste_clipboard (GtkOldEditable *old_editable);
107 static void gtk_old_editable_insert_text (GtkEditable *editable,
108 const gchar *new_text,
109 gint new_text_length,
111 static void gtk_old_editable_delete_text (GtkEditable *editable,
114 static gchar * gtk_old_editable_get_chars (GtkEditable *editable,
117 static void gtk_old_editable_set_selection_bounds (GtkEditable *editable,
120 static gboolean gtk_old_editable_get_selection_bounds (GtkEditable *editable,
123 static void gtk_old_editable_set_position (GtkEditable *editable,
125 static gint gtk_old_editable_get_position (GtkEditable *editable);
127 static GtkWidgetClass *parent_class = NULL;
128 static guint editable_signals[LAST_SIGNAL] = { 0 };
131 gtk_old_editable_get_type (void)
133 static GtkType old_editable_type = 0;
135 if (!old_editable_type)
137 static const GtkTypeInfo old_editable_info =
140 sizeof (GtkOldEditable),
141 sizeof (GtkOldEditableClass),
142 (GtkClassInitFunc) gtk_old_editable_class_init,
143 (GtkObjectInitFunc) gtk_old_editable_init,
144 /* reserved_1 */ NULL,
145 /* reserved_2 */ NULL,
146 (GtkClassInitFunc) NULL,
149 static const GInterfaceInfo editable_info =
151 (GInterfaceInitFunc) gtk_old_editable_editable_init, /* interface_init */
152 NULL, /* interface_finalize */
153 NULL /* interface_data */
156 old_editable_type = gtk_type_unique (GTK_TYPE_WIDGET, &old_editable_info);
157 g_type_add_interface_static (old_editable_type,
162 return old_editable_type;
166 gtk_old_editable_class_init (GtkOldEditableClass *class)
168 GtkObjectClass *object_class;
169 GtkWidgetClass *widget_class;
171 object_class = (GtkObjectClass*) class;
172 widget_class = (GtkWidgetClass*) class;
174 parent_class = gtk_type_class (GTK_TYPE_WIDGET);
176 object_class->set_arg = gtk_old_editable_set_arg;
177 object_class->get_arg = gtk_old_editable_get_arg;
179 widget_class->selection_clear_event = gtk_old_editable_selection_clear;
180 widget_class->selection_received = gtk_old_editable_selection_received;
181 widget_class->selection_get = gtk_old_editable_selection_get;
183 class->activate = NULL;
184 class->set_editable = gtk_old_editable_real_set_editable;
186 class->move_cursor = NULL;
187 class->move_word = NULL;
188 class->move_page = NULL;
189 class->move_to_row = NULL;
190 class->move_to_column = NULL;
192 class->kill_char = NULL;
193 class->kill_word = NULL;
194 class->kill_line = NULL;
196 class->cut_clipboard = gtk_old_editable_real_cut_clipboard;
197 class->copy_clipboard = gtk_old_editable_real_copy_clipboard;
198 class->paste_clipboard = gtk_old_editable_real_paste_clipboard;
200 class->update_text = NULL;
201 class->get_chars = NULL;
202 class->set_selection = NULL;
203 class->set_position = NULL;
205 editable_signals[ACTIVATE] =
206 gtk_signal_new ("activate",
207 GTK_RUN_LAST | GTK_RUN_ACTION,
208 GTK_CLASS_TYPE (object_class),
209 GTK_SIGNAL_OFFSET (GtkOldEditableClass, activate),
210 _gtk_marshal_NONE__NONE,
212 widget_class->activate_signal = editable_signals[ACTIVATE];
214 editable_signals[SET_EDITABLE] =
215 gtk_signal_new ("set-editable",
216 GTK_RUN_LAST | GTK_RUN_ACTION,
217 GTK_CLASS_TYPE (object_class),
218 GTK_SIGNAL_OFFSET (GtkOldEditableClass, set_editable),
219 _gtk_marshal_NONE__BOOLEAN,
223 editable_signals[MOVE_CURSOR] =
224 gtk_signal_new ("move_cursor",
225 GTK_RUN_LAST | GTK_RUN_ACTION,
226 GTK_CLASS_TYPE (object_class),
227 GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_cursor),
228 _gtk_marshal_NONE__INT_INT,
233 editable_signals[MOVE_WORD] =
234 gtk_signal_new ("move_word",
235 GTK_RUN_LAST | GTK_RUN_ACTION,
236 GTK_CLASS_TYPE (object_class),
237 GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_word),
238 _gtk_marshal_NONE__INT,
242 editable_signals[MOVE_PAGE] =
243 gtk_signal_new ("move_page",
244 GTK_RUN_LAST | GTK_RUN_ACTION,
245 GTK_CLASS_TYPE (object_class),
246 GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_page),
247 _gtk_marshal_NONE__INT_INT,
252 editable_signals[MOVE_TO_ROW] =
253 gtk_signal_new ("move_to_row",
254 GTK_RUN_LAST | GTK_RUN_ACTION,
255 GTK_CLASS_TYPE (object_class),
256 GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_to_row),
257 _gtk_marshal_NONE__INT,
261 editable_signals[MOVE_TO_COLUMN] =
262 gtk_signal_new ("move_to_column",
263 GTK_RUN_LAST | GTK_RUN_ACTION,
264 GTK_CLASS_TYPE (object_class),
265 GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_to_column),
266 _gtk_marshal_NONE__INT,
270 editable_signals[KILL_CHAR] =
271 gtk_signal_new ("kill_char",
272 GTK_RUN_LAST | GTK_RUN_ACTION,
273 GTK_CLASS_TYPE (object_class),
274 GTK_SIGNAL_OFFSET (GtkOldEditableClass, kill_char),
275 _gtk_marshal_NONE__INT,
279 editable_signals[KILL_WORD] =
280 gtk_signal_new ("kill_word",
281 GTK_RUN_LAST | GTK_RUN_ACTION,
282 GTK_CLASS_TYPE (object_class),
283 GTK_SIGNAL_OFFSET (GtkOldEditableClass, kill_word),
284 _gtk_marshal_NONE__INT,
288 editable_signals[KILL_LINE] =
289 gtk_signal_new ("kill_line",
290 GTK_RUN_LAST | GTK_RUN_ACTION,
291 GTK_CLASS_TYPE (object_class),
292 GTK_SIGNAL_OFFSET (GtkOldEditableClass, kill_line),
293 _gtk_marshal_NONE__INT,
297 editable_signals[CUT_CLIPBOARD] =
298 gtk_signal_new ("cut_clipboard",
299 GTK_RUN_LAST | GTK_RUN_ACTION,
300 GTK_CLASS_TYPE (object_class),
301 GTK_SIGNAL_OFFSET (GtkOldEditableClass, cut_clipboard),
302 _gtk_marshal_NONE__NONE,
305 editable_signals[COPY_CLIPBOARD] =
306 gtk_signal_new ("copy_clipboard",
307 GTK_RUN_LAST | GTK_RUN_ACTION,
308 GTK_CLASS_TYPE (object_class),
309 GTK_SIGNAL_OFFSET (GtkOldEditableClass, copy_clipboard),
310 _gtk_marshal_NONE__NONE,
313 editable_signals[PASTE_CLIPBOARD] =
314 gtk_signal_new ("paste_clipboard",
315 GTK_RUN_LAST | GTK_RUN_ACTION,
316 GTK_CLASS_TYPE (object_class),
317 GTK_SIGNAL_OFFSET (GtkOldEditableClass, paste_clipboard),
318 _gtk_marshal_NONE__NONE,
321 gtk_object_add_arg_type ("GtkOldEditable::text_position", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_TEXT_POSITION);
322 gtk_object_add_arg_type ("GtkOldEditable::editable", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_EDITABLE);
326 gtk_old_editable_editable_init (GtkEditableClass *iface)
328 iface->do_insert_text = gtk_old_editable_insert_text;
329 iface->do_delete_text = gtk_old_editable_delete_text;
330 iface->get_chars = gtk_old_editable_get_chars;
331 iface->set_selection_bounds = gtk_old_editable_set_selection_bounds;
332 iface->get_selection_bounds = gtk_old_editable_get_selection_bounds;
333 iface->set_position = gtk_old_editable_set_position;
334 iface->get_position = gtk_old_editable_get_position;
338 gtk_old_editable_set_arg (GtkObject *object,
342 GtkEditable *editable = GTK_EDITABLE (object);
346 case ARG_TEXT_POSITION:
347 gtk_editable_set_position (editable, GTK_VALUE_INT (*arg));
350 gtk_signal_emit (object, editable_signals[SET_EDITABLE],
351 GTK_VALUE_BOOL (*arg) != FALSE);
359 gtk_old_editable_get_arg (GtkObject *object,
363 GtkOldEditable *old_editable;
365 old_editable = GTK_OLD_EDITABLE (object);
369 case ARG_TEXT_POSITION:
370 GTK_VALUE_INT (*arg) = old_editable->current_pos;
373 GTK_VALUE_BOOL (*arg) = old_editable->editable;
376 arg->type = GTK_TYPE_INVALID;
382 gtk_old_editable_init (GtkOldEditable *old_editable)
384 static const GtkTargetEntry targets[] = {
385 { "UTF8_STRING", 0, 0 },
388 { "COMPOUND_TEXT", 0, 0 }
391 GTK_WIDGET_SET_FLAGS (old_editable, GTK_CAN_FOCUS);
393 old_editable->selection_start_pos = 0;
394 old_editable->selection_end_pos = 0;
395 old_editable->has_selection = FALSE;
396 old_editable->editable = 1;
397 old_editable->visible = 1;
398 old_editable->clipboard_text = NULL;
400 gtk_selection_add_targets (GTK_WIDGET (old_editable), GDK_SELECTION_PRIMARY,
401 targets, G_N_ELEMENTS (targets));
405 gtk_old_editable_insert_text (GtkEditable *editable,
406 const gchar *new_text,
407 gint new_text_length,
413 gtk_widget_ref (GTK_WIDGET (editable));
415 if (new_text_length <= 63)
418 text = g_new (gchar, new_text_length + 1);
420 text[new_text_length] = '\0';
421 strncpy (text, new_text, new_text_length);
423 g_signal_emit_by_name (editable, "insert_text", text, new_text_length,
425 g_signal_emit_by_name (editable, "changed");
427 if (new_text_length > 63)
430 gtk_widget_unref (GTK_WIDGET (editable));
434 gtk_old_editable_delete_text (GtkEditable *editable,
438 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (editable);
440 gtk_widget_ref (GTK_WIDGET (old_editable));
442 g_signal_emit_by_name (editable, "delete_text", start_pos, end_pos);
443 g_signal_emit_by_name (editable, "changed");
445 if (old_editable->selection_start_pos == old_editable->selection_end_pos &&
446 old_editable->has_selection)
447 gtk_old_editable_claim_selection (old_editable, FALSE, GDK_CURRENT_TIME);
449 gtk_widget_unref (GTK_WIDGET (old_editable));
453 gtk_old_editable_update_text (GtkOldEditable *old_editable,
457 GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (old_editable);
458 klass->update_text (GTK_OLD_EDITABLE (old_editable), start_pos, end_pos);
462 gtk_old_editable_get_chars (GtkEditable *editable,
466 GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (editable);
467 return klass->get_chars (GTK_OLD_EDITABLE (editable), start, end);
471 * Like gtk_editable_get_chars, but if the editable is not
472 * visible, return asterisks; also convert result to UTF-8.
475 gtk_old_editable_get_public_chars (GtkOldEditable *old_editable,
480 const gchar *charset;
481 gboolean need_conversion = !g_get_charset (&charset);
483 if (old_editable->visible)
485 GError *error = NULL;
486 gchar *tmp = gtk_editable_get_chars (GTK_EDITABLE (old_editable), start, end);
490 str = g_convert (tmp, -1,
496 g_warning ("Cannot convert text from charset to UTF-8 %s: %s", charset, error->message);
497 g_error_free (error);
508 gint nchars = end - start;
513 str = g_new (gchar, nchars + 1);
514 for (i = 0; i<nchars; i++)
523 gtk_old_editable_set_selection (GtkOldEditable *old_editable,
527 GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (old_editable);
528 klass->set_selection (old_editable, start_pos, end_pos);
532 gtk_old_editable_set_position (GtkEditable *editable,
535 GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (editable);
537 klass->set_position (GTK_OLD_EDITABLE (editable), position);
541 gtk_old_editable_get_position (GtkEditable *editable)
543 return GTK_OLD_EDITABLE (editable)->current_pos;
547 gtk_old_editable_selection_clear (GtkWidget *widget,
548 GdkEventSelection *event)
550 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (widget);
552 /* Let the selection handling code know that the selection
553 * has been changed, since we've overriden the default handler */
554 if (!gtk_selection_clear (widget, event))
557 if (old_editable->has_selection)
559 old_editable->has_selection = FALSE;
560 gtk_old_editable_update_text (old_editable, old_editable->selection_start_pos,
561 old_editable->selection_end_pos);
568 gtk_old_editable_selection_get (GtkWidget *widget,
569 GtkSelectionData *selection_data,
573 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (widget);
574 gint selection_start_pos;
575 gint selection_end_pos;
579 selection_start_pos = MIN (old_editable->selection_start_pos, old_editable->selection_end_pos);
580 selection_end_pos = MAX (old_editable->selection_start_pos, old_editable->selection_end_pos);
582 str = gtk_old_editable_get_public_chars (old_editable,
588 gtk_selection_data_set_text (selection_data, str, -1);
594 gtk_old_editable_paste_received (GtkOldEditable *old_editable,
596 gboolean is_clipboard)
598 const gchar *str = NULL;
599 const gchar *charset;
600 gboolean need_conversion = FALSE;
604 GError *error = NULL;
606 need_conversion = !g_get_charset (&charset);
610 str = g_convert_with_fallback (text, -1,
611 charset, "UTF-8", NULL,
615 g_warning ("Cannot convert text from UTF-8 to %s: %s",
616 charset, error->message);
617 g_error_free (error);
633 if ((old_editable->selection_start_pos != old_editable->selection_end_pos) &&
634 (!old_editable->has_selection || is_clipboard))
638 /* Don't want to call gtk_editable_delete_selection here if we are going
639 * to reclaim the selection to avoid extra server traffic */
640 if (old_editable->has_selection)
642 gtk_editable_delete_text (GTK_EDITABLE (old_editable),
643 MIN (old_editable->selection_start_pos, old_editable->selection_end_pos),
644 MAX (old_editable->selection_start_pos, old_editable->selection_end_pos));
647 gtk_editable_delete_selection (GTK_EDITABLE (old_editable));
650 tmp_pos = old_pos = old_editable->current_pos;
652 gtk_editable_insert_text (GTK_EDITABLE (old_editable), str, -1, &tmp_pos);
655 gtk_old_editable_set_selection (old_editable, old_pos, old_editable->current_pos);
657 if (str && str != text)
658 g_free ((gchar *) str);
663 gtk_old_editable_selection_received (GtkWidget *widget,
664 GtkSelectionData *selection_data,
667 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (widget);
669 gchar *text = gtk_selection_data_get_text (selection_data);
673 /* If we asked for UTF8 and didn't get it, try text; if we asked
674 * for text and didn't get it, try string. If we asked for
675 * anything else and didn't get it, give up.
677 if (selection_data->target == gdk_atom_intern ("UTF8_STRING", FALSE))
679 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
680 gdk_atom_intern ("TEXT", FALSE),
684 else if (selection_data->target == gdk_atom_intern ("TEXT", FALSE))
686 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
695 gtk_old_editable_paste_received (old_editable, text, FALSE);
701 old_editable_text_received_cb (GtkClipboard *clipboard,
705 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (data);
707 gtk_old_editable_paste_received (old_editable, text, TRUE);
708 g_object_unref (G_OBJECT (old_editable));
712 * gtk_old_editable_claim_selection:
713 * @old_editable: a #GtkOldEditable
714 * @claim: if %TRUE, claim ownership of the selection, if %FALSE, give
716 * @time: timestamp for this operation
718 * Claims or gives up ownership of the selection.
721 gtk_old_editable_claim_selection (GtkOldEditable *old_editable,
725 g_return_if_fail (GTK_IS_OLD_EDITABLE (old_editable));
726 g_return_if_fail (GTK_WIDGET_REALIZED (old_editable));
728 old_editable->has_selection = FALSE;
732 if (gtk_selection_owner_set (GTK_WIDGET (old_editable), GDK_SELECTION_PRIMARY, time))
733 old_editable->has_selection = TRUE;
737 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == GTK_WIDGET (old_editable)->window)
738 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, time);
743 gtk_old_editable_set_selection_bounds (GtkEditable *editable,
747 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (editable);
749 if (GTK_WIDGET_REALIZED (editable))
750 gtk_old_editable_claim_selection (old_editable, start != end, GDK_CURRENT_TIME);
752 gtk_old_editable_set_selection (old_editable, start, end);
756 gtk_old_editable_get_selection_bounds (GtkEditable *editable,
760 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (editable);
762 *start = old_editable->selection_start_pos;
763 *end = old_editable->selection_end_pos;
765 return (old_editable->selection_start_pos != old_editable->selection_end_pos);
769 gtk_old_editable_real_set_editable (GtkOldEditable *old_editable,
770 gboolean is_editable)
772 is_editable = is_editable != FALSE;
774 if (old_editable->editable != is_editable)
776 old_editable->editable = is_editable;
777 gtk_widget_queue_draw (GTK_WIDGET (old_editable));
782 gtk_old_editable_real_cut_clipboard (GtkOldEditable *old_editable)
784 gtk_old_editable_real_copy_clipboard (old_editable);
785 gtk_editable_delete_selection (GTK_EDITABLE (old_editable));
789 gtk_old_editable_real_copy_clipboard (GtkOldEditable *old_editable)
791 gint selection_start_pos;
792 gint selection_end_pos;
794 selection_start_pos = MIN (old_editable->selection_start_pos, old_editable->selection_end_pos);
795 selection_end_pos = MAX (old_editable->selection_start_pos, old_editable->selection_end_pos);
797 if (selection_start_pos != selection_end_pos)
799 gchar *text = gtk_old_editable_get_public_chars (old_editable,
805 gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), text, -1);
812 gtk_old_editable_real_paste_clipboard (GtkOldEditable *old_editable)
814 g_object_ref (G_OBJECT (old_editable));
815 gtk_clipboard_request_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
816 old_editable_text_received_cb, old_editable);
820 * gtk_old_editable_changed:
821 * @old_editable: a #GtkOldEditable
823 * Emits the ::changed signal on @old_editable.
826 gtk_old_editable_changed (GtkOldEditable *old_editable)
828 g_return_if_fail (GTK_IS_OLD_EDITABLE (old_editable));
830 g_signal_emit_by_name (old_editable, "changed");