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/.
27 #undef GTK_DISABLE_DEPRECATED
30 #include "gdk/gdkkeysyms.h"
31 #include "gdk/gdki18n.h"
32 #include "gtkclipboard.h"
33 #include "gtkoldeditable.h"
35 #include "gtkmarshalers.h"
36 #include "gtkselection.h"
37 #include "gtksignal.h"
39 #define MIN_EDITABLE_WIDTH 150
40 #define DRAW_TIMEOUT 20
41 #define INNER_BORDER 2
67 /* values for selection info */
75 static void gtk_old_editable_class_init (GtkOldEditableClass *klass);
76 static void gtk_old_editable_editable_init (GtkEditableClass *iface);
77 static void gtk_old_editable_init (GtkOldEditable *editable);
78 static void gtk_old_editable_set_arg (GtkObject *object,
81 static void gtk_old_editable_get_arg (GtkObject *object,
84 static void *gtk_old_editable_get_public_chars (GtkOldEditable *old_editable,
88 static gint gtk_old_editable_selection_clear (GtkWidget *widget,
89 GdkEventSelection *event);
90 static void gtk_old_editable_selection_get (GtkWidget *widget,
91 GtkSelectionData *selection_data,
94 static void gtk_old_editable_selection_received (GtkWidget *widget,
95 GtkSelectionData *selection_data,
98 static void gtk_old_editable_set_selection (GtkOldEditable *old_editable,
102 static void gtk_old_editable_real_set_editable (GtkOldEditable *old_editable,
103 gboolean is_editable);
104 static void gtk_old_editable_real_cut_clipboard (GtkOldEditable *old_editable);
105 static void gtk_old_editable_real_copy_clipboard (GtkOldEditable *old_editable);
106 static void gtk_old_editable_real_paste_clipboard (GtkOldEditable *old_editable);
108 static void gtk_old_editable_insert_text (GtkEditable *editable,
109 const gchar *new_text,
110 gint new_text_length,
112 static void gtk_old_editable_delete_text (GtkEditable *editable,
115 static gchar * gtk_old_editable_get_chars (GtkEditable *editable,
118 static void gtk_old_editable_set_selection_bounds (GtkEditable *editable,
121 static gboolean gtk_old_editable_get_selection_bounds (GtkEditable *editable,
124 static void gtk_old_editable_set_position (GtkEditable *editable,
126 static gint gtk_old_editable_get_position (GtkEditable *editable);
128 static GtkWidgetClass *parent_class = NULL;
129 static guint editable_signals[LAST_SIGNAL] = { 0 };
132 gtk_old_editable_get_type (void)
134 static GtkType old_editable_type = 0;
136 if (!old_editable_type)
138 static const GTypeInfo old_editable_info =
140 sizeof (GtkOldEditableClass),
141 NULL, /* base_init */
142 NULL, /* base_finalize */
143 (GClassInitFunc) gtk_old_editable_class_init,
144 NULL, /* class_finalize */
145 NULL, /* class_data */
146 sizeof (GtkOldEditable),
148 (GInstanceInitFunc) gtk_old_editable_init,
149 NULL, /* value_table */
152 static const GInterfaceInfo editable_info =
154 (GInterfaceInitFunc) gtk_old_editable_editable_init, /* interface_init */
155 NULL, /* interface_finalize */
156 NULL /* interface_data */
159 old_editable_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkOldEditable",
160 &old_editable_info, G_TYPE_FLAG_ABSTRACT);
161 g_type_add_interface_static (old_editable_type,
166 return old_editable_type;
170 gtk_old_editable_class_init (GtkOldEditableClass *class)
172 GtkObjectClass *object_class;
173 GtkWidgetClass *widget_class;
175 object_class = (GtkObjectClass*) class;
176 widget_class = (GtkWidgetClass*) class;
178 parent_class = gtk_type_class (GTK_TYPE_WIDGET);
180 object_class->set_arg = gtk_old_editable_set_arg;
181 object_class->get_arg = gtk_old_editable_get_arg;
183 widget_class->selection_clear_event = gtk_old_editable_selection_clear;
184 widget_class->selection_received = gtk_old_editable_selection_received;
185 widget_class->selection_get = gtk_old_editable_selection_get;
187 class->activate = NULL;
188 class->set_editable = gtk_old_editable_real_set_editable;
190 class->move_cursor = NULL;
191 class->move_word = NULL;
192 class->move_page = NULL;
193 class->move_to_row = NULL;
194 class->move_to_column = NULL;
196 class->kill_char = NULL;
197 class->kill_word = NULL;
198 class->kill_line = NULL;
200 class->cut_clipboard = gtk_old_editable_real_cut_clipboard;
201 class->copy_clipboard = gtk_old_editable_real_copy_clipboard;
202 class->paste_clipboard = gtk_old_editable_real_paste_clipboard;
204 class->update_text = NULL;
205 class->get_chars = NULL;
206 class->set_selection = NULL;
207 class->set_position = NULL;
209 editable_signals[ACTIVATE] =
210 gtk_signal_new ("activate",
211 GTK_RUN_LAST | GTK_RUN_ACTION,
212 GTK_CLASS_TYPE (object_class),
213 GTK_SIGNAL_OFFSET (GtkOldEditableClass, activate),
214 _gtk_marshal_NONE__NONE,
216 widget_class->activate_signal = editable_signals[ACTIVATE];
218 editable_signals[SET_EDITABLE] =
219 gtk_signal_new ("set-editable",
220 GTK_RUN_LAST | GTK_RUN_ACTION,
221 GTK_CLASS_TYPE (object_class),
222 GTK_SIGNAL_OFFSET (GtkOldEditableClass, set_editable),
223 _gtk_marshal_NONE__BOOLEAN,
227 editable_signals[MOVE_CURSOR] =
228 gtk_signal_new ("move_cursor",
229 GTK_RUN_LAST | GTK_RUN_ACTION,
230 GTK_CLASS_TYPE (object_class),
231 GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_cursor),
232 _gtk_marshal_NONE__INT_INT,
237 editable_signals[MOVE_WORD] =
238 gtk_signal_new ("move_word",
239 GTK_RUN_LAST | GTK_RUN_ACTION,
240 GTK_CLASS_TYPE (object_class),
241 GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_word),
242 _gtk_marshal_NONE__INT,
246 editable_signals[MOVE_PAGE] =
247 gtk_signal_new ("move_page",
248 GTK_RUN_LAST | GTK_RUN_ACTION,
249 GTK_CLASS_TYPE (object_class),
250 GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_page),
251 _gtk_marshal_NONE__INT_INT,
256 editable_signals[MOVE_TO_ROW] =
257 gtk_signal_new ("move_to_row",
258 GTK_RUN_LAST | GTK_RUN_ACTION,
259 GTK_CLASS_TYPE (object_class),
260 GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_to_row),
261 _gtk_marshal_NONE__INT,
265 editable_signals[MOVE_TO_COLUMN] =
266 gtk_signal_new ("move_to_column",
267 GTK_RUN_LAST | GTK_RUN_ACTION,
268 GTK_CLASS_TYPE (object_class),
269 GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_to_column),
270 _gtk_marshal_NONE__INT,
274 editable_signals[KILL_CHAR] =
275 gtk_signal_new ("kill_char",
276 GTK_RUN_LAST | GTK_RUN_ACTION,
277 GTK_CLASS_TYPE (object_class),
278 GTK_SIGNAL_OFFSET (GtkOldEditableClass, kill_char),
279 _gtk_marshal_NONE__INT,
283 editable_signals[KILL_WORD] =
284 gtk_signal_new ("kill_word",
285 GTK_RUN_LAST | GTK_RUN_ACTION,
286 GTK_CLASS_TYPE (object_class),
287 GTK_SIGNAL_OFFSET (GtkOldEditableClass, kill_word),
288 _gtk_marshal_NONE__INT,
292 editable_signals[KILL_LINE] =
293 gtk_signal_new ("kill_line",
294 GTK_RUN_LAST | GTK_RUN_ACTION,
295 GTK_CLASS_TYPE (object_class),
296 GTK_SIGNAL_OFFSET (GtkOldEditableClass, kill_line),
297 _gtk_marshal_NONE__INT,
301 editable_signals[CUT_CLIPBOARD] =
302 gtk_signal_new ("cut_clipboard",
303 GTK_RUN_LAST | GTK_RUN_ACTION,
304 GTK_CLASS_TYPE (object_class),
305 GTK_SIGNAL_OFFSET (GtkOldEditableClass, cut_clipboard),
306 _gtk_marshal_NONE__NONE,
309 editable_signals[COPY_CLIPBOARD] =
310 gtk_signal_new ("copy_clipboard",
311 GTK_RUN_LAST | GTK_RUN_ACTION,
312 GTK_CLASS_TYPE (object_class),
313 GTK_SIGNAL_OFFSET (GtkOldEditableClass, copy_clipboard),
314 _gtk_marshal_NONE__NONE,
317 editable_signals[PASTE_CLIPBOARD] =
318 gtk_signal_new ("paste_clipboard",
319 GTK_RUN_LAST | GTK_RUN_ACTION,
320 GTK_CLASS_TYPE (object_class),
321 GTK_SIGNAL_OFFSET (GtkOldEditableClass, paste_clipboard),
322 _gtk_marshal_NONE__NONE,
325 gtk_object_add_arg_type ("GtkOldEditable::text_position", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_TEXT_POSITION);
326 gtk_object_add_arg_type ("GtkOldEditable::editable", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_EDITABLE);
330 gtk_old_editable_editable_init (GtkEditableClass *iface)
332 iface->do_insert_text = gtk_old_editable_insert_text;
333 iface->do_delete_text = gtk_old_editable_delete_text;
334 iface->get_chars = gtk_old_editable_get_chars;
335 iface->set_selection_bounds = gtk_old_editable_set_selection_bounds;
336 iface->get_selection_bounds = gtk_old_editable_get_selection_bounds;
337 iface->set_position = gtk_old_editable_set_position;
338 iface->get_position = gtk_old_editable_get_position;
342 gtk_old_editable_set_arg (GtkObject *object,
346 GtkEditable *editable = GTK_EDITABLE (object);
350 case ARG_TEXT_POSITION:
351 gtk_editable_set_position (editable, GTK_VALUE_INT (*arg));
354 gtk_signal_emit (object, editable_signals[SET_EDITABLE],
355 GTK_VALUE_BOOL (*arg) != FALSE);
363 gtk_old_editable_get_arg (GtkObject *object,
367 GtkOldEditable *old_editable;
369 old_editable = GTK_OLD_EDITABLE (object);
373 case ARG_TEXT_POSITION:
374 GTK_VALUE_INT (*arg) = old_editable->current_pos;
377 GTK_VALUE_BOOL (*arg) = old_editable->editable;
380 arg->type = GTK_TYPE_INVALID;
386 gtk_old_editable_init (GtkOldEditable *old_editable)
388 static const GtkTargetEntry targets[] = {
389 { "UTF8_STRING", 0, 0 },
392 { "COMPOUND_TEXT", 0, 0 }
395 GTK_WIDGET_SET_FLAGS (old_editable, GTK_CAN_FOCUS);
397 old_editable->selection_start_pos = 0;
398 old_editable->selection_end_pos = 0;
399 old_editable->has_selection = FALSE;
400 old_editable->editable = 1;
401 old_editable->visible = 1;
402 old_editable->clipboard_text = NULL;
404 gtk_selection_add_targets (GTK_WIDGET (old_editable), GDK_SELECTION_PRIMARY,
405 targets, G_N_ELEMENTS (targets));
409 gtk_old_editable_insert_text (GtkEditable *editable,
410 const gchar *new_text,
411 gint new_text_length,
417 gtk_widget_ref (GTK_WIDGET (editable));
419 if (new_text_length <= 63)
422 text = g_new (gchar, new_text_length + 1);
424 text[new_text_length] = '\0';
425 strncpy (text, new_text, new_text_length);
427 g_signal_emit_by_name (editable, "insert_text", text, new_text_length,
429 g_signal_emit_by_name (editable, "changed");
431 if (new_text_length > 63)
434 gtk_widget_unref (GTK_WIDGET (editable));
438 gtk_old_editable_delete_text (GtkEditable *editable,
442 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (editable);
444 gtk_widget_ref (GTK_WIDGET (old_editable));
446 g_signal_emit_by_name (editable, "delete_text", start_pos, end_pos);
447 g_signal_emit_by_name (editable, "changed");
449 if (old_editable->selection_start_pos == old_editable->selection_end_pos &&
450 old_editable->has_selection)
451 gtk_old_editable_claim_selection (old_editable, FALSE, GDK_CURRENT_TIME);
453 gtk_widget_unref (GTK_WIDGET (old_editable));
457 gtk_old_editable_update_text (GtkOldEditable *old_editable,
461 GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (old_editable);
462 klass->update_text (GTK_OLD_EDITABLE (old_editable), start_pos, end_pos);
466 gtk_old_editable_get_chars (GtkEditable *editable,
470 GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (editable);
471 return klass->get_chars (GTK_OLD_EDITABLE (editable), start, end);
475 * Like gtk_editable_get_chars, but if the editable is not
476 * visible, return asterisks; also convert result to UTF-8.
479 gtk_old_editable_get_public_chars (GtkOldEditable *old_editable,
484 const gchar *charset;
485 gboolean need_conversion = !g_get_charset (&charset);
487 if (old_editable->visible)
489 GError *error = NULL;
490 gchar *tmp = gtk_editable_get_chars (GTK_EDITABLE (old_editable), start, end);
494 str = g_convert (tmp, -1,
500 g_warning ("Cannot convert text from charset to UTF-8 %s: %s", charset, error->message);
501 g_error_free (error);
512 gint nchars = end - start;
517 str = g_new (gchar, nchars + 1);
518 for (i = 0; i<nchars; i++)
527 gtk_old_editable_set_selection (GtkOldEditable *old_editable,
531 GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (old_editable);
532 klass->set_selection (old_editable, start_pos, end_pos);
536 gtk_old_editable_set_position (GtkEditable *editable,
539 GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (editable);
541 klass->set_position (GTK_OLD_EDITABLE (editable), position);
545 gtk_old_editable_get_position (GtkEditable *editable)
547 return GTK_OLD_EDITABLE (editable)->current_pos;
551 gtk_old_editable_selection_clear (GtkWidget *widget,
552 GdkEventSelection *event)
554 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (widget);
556 /* Let the selection handling code know that the selection
557 * has been changed, since we've overriden the default handler */
558 if (!parent_class->selection_clear_event (widget, event))
561 if (old_editable->has_selection)
563 old_editable->has_selection = FALSE;
564 gtk_old_editable_update_text (old_editable, old_editable->selection_start_pos,
565 old_editable->selection_end_pos);
572 gtk_old_editable_selection_get (GtkWidget *widget,
573 GtkSelectionData *selection_data,
577 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (widget);
578 gint selection_start_pos;
579 gint selection_end_pos;
583 selection_start_pos = MIN (old_editable->selection_start_pos, old_editable->selection_end_pos);
584 selection_end_pos = MAX (old_editable->selection_start_pos, old_editable->selection_end_pos);
586 str = gtk_old_editable_get_public_chars (old_editable,
592 gtk_selection_data_set_text (selection_data, str, -1);
598 gtk_old_editable_paste_received (GtkOldEditable *old_editable,
600 gboolean is_clipboard)
602 const gchar *str = NULL;
603 const gchar *charset;
604 gboolean need_conversion = FALSE;
608 GError *error = NULL;
610 need_conversion = !g_get_charset (&charset);
614 str = g_convert_with_fallback (text, -1,
615 charset, "UTF-8", NULL,
619 g_warning ("Cannot convert text from UTF-8 to %s: %s",
620 charset, error->message);
621 g_error_free (error);
637 if ((old_editable->selection_start_pos != old_editable->selection_end_pos) &&
638 (!old_editable->has_selection || is_clipboard))
642 /* Don't want to call gtk_editable_delete_selection here if we are going
643 * to reclaim the selection to avoid extra server traffic */
644 if (old_editable->has_selection)
646 gtk_editable_delete_text (GTK_EDITABLE (old_editable),
647 MIN (old_editable->selection_start_pos, old_editable->selection_end_pos),
648 MAX (old_editable->selection_start_pos, old_editable->selection_end_pos));
651 gtk_editable_delete_selection (GTK_EDITABLE (old_editable));
654 tmp_pos = old_pos = old_editable->current_pos;
656 gtk_editable_insert_text (GTK_EDITABLE (old_editable), str, -1, &tmp_pos);
659 gtk_old_editable_set_selection (old_editable, old_pos, old_editable->current_pos);
661 if (str && str != text)
662 g_free ((gchar *) str);
667 gtk_old_editable_selection_received (GtkWidget *widget,
668 GtkSelectionData *selection_data,
671 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (widget);
673 gchar *text = gtk_selection_data_get_text (selection_data);
677 /* If we asked for UTF8 and didn't get it, try text; if we asked
678 * for text and didn't get it, try string. If we asked for
679 * anything else and didn't get it, give up.
681 if (selection_data->target == gdk_atom_intern ("UTF8_STRING", FALSE))
683 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
684 gdk_atom_intern ("TEXT", FALSE),
688 else if (selection_data->target == gdk_atom_intern ("TEXT", FALSE))
690 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
699 gtk_old_editable_paste_received (old_editable, text, FALSE);
705 old_editable_text_received_cb (GtkClipboard *clipboard,
709 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (data);
711 gtk_old_editable_paste_received (old_editable, text, TRUE);
712 g_object_unref (G_OBJECT (old_editable));
716 * gtk_old_editable_claim_selection:
717 * @old_editable: a #GtkOldEditable
718 * @claim: if %TRUE, claim ownership of the selection, if %FALSE, give
720 * @time_: timestamp for this operation
722 * Claims or gives up ownership of the selection.
725 gtk_old_editable_claim_selection (GtkOldEditable *old_editable,
729 GtkWidget *widget = GTK_WIDGET (old_editable);
730 GdkDisplay *display = gtk_widget_get_display (widget);
732 g_return_if_fail (GTK_IS_OLD_EDITABLE (old_editable));
733 g_return_if_fail (GTK_WIDGET_REALIZED (old_editable));
735 old_editable->has_selection = FALSE;
739 if (gtk_selection_owner_set_for_display (display, widget,
740 GDK_SELECTION_PRIMARY, time))
741 old_editable->has_selection = TRUE;
745 if (gdk_selection_owner_get_for_display (display, GDK_SELECTION_PRIMARY) == widget->window)
746 gtk_selection_owner_set_for_display (display,
748 GDK_SELECTION_PRIMARY, time);
753 gtk_old_editable_set_selection_bounds (GtkEditable *editable,
757 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (editable);
759 if (GTK_WIDGET_REALIZED (editable))
760 gtk_old_editable_claim_selection (old_editable, start != end, GDK_CURRENT_TIME);
762 gtk_old_editable_set_selection (old_editable, start, end);
766 gtk_old_editable_get_selection_bounds (GtkEditable *editable,
770 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (editable);
772 *start = old_editable->selection_start_pos;
773 *end = old_editable->selection_end_pos;
775 return (old_editable->selection_start_pos != old_editable->selection_end_pos);
779 gtk_old_editable_real_set_editable (GtkOldEditable *old_editable,
780 gboolean is_editable)
782 is_editable = is_editable != FALSE;
784 if (old_editable->editable != is_editable)
786 old_editable->editable = is_editable;
787 gtk_widget_queue_draw (GTK_WIDGET (old_editable));
792 gtk_old_editable_real_cut_clipboard (GtkOldEditable *old_editable)
794 gtk_old_editable_real_copy_clipboard (old_editable);
795 gtk_editable_delete_selection (GTK_EDITABLE (old_editable));
799 gtk_old_editable_real_copy_clipboard (GtkOldEditable *old_editable)
801 gint selection_start_pos;
802 gint selection_end_pos;
804 selection_start_pos = MIN (old_editable->selection_start_pos, old_editable->selection_end_pos);
805 selection_end_pos = MAX (old_editable->selection_start_pos, old_editable->selection_end_pos);
807 if (selection_start_pos != selection_end_pos)
809 gchar *text = gtk_old_editable_get_public_chars (old_editable,
815 GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (old_editable),
816 GDK_SELECTION_CLIPBOARD);
818 gtk_clipboard_set_text (clipboard, text, -1);
825 gtk_old_editable_real_paste_clipboard (GtkOldEditable *old_editable)
827 GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (old_editable),
828 GDK_SELECTION_CLIPBOARD);
830 g_object_ref (G_OBJECT (old_editable));
831 gtk_clipboard_request_text (clipboard, old_editable_text_received_cb, old_editable);
835 * gtk_old_editable_changed:
836 * @old_editable: a #GtkOldEditable
838 * Emits the ::changed signal on @old_editable.
841 gtk_old_editable_changed (GtkOldEditable *old_editable)
843 g_return_if_fail (GTK_IS_OLD_EDITABLE (old_editable));
845 g_signal_emit_by_name (old_editable, "changed");