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 "gtkselection.h"
35 #include "gtksignal.h"
37 #define MIN_EDITABLE_WIDTH 150
38 #define DRAW_TIMEOUT 20
39 #define INNER_BORDER 2
68 /* values for selection info */
76 static void gtk_old_editable_class_init (GtkOldEditableClass *klass);
77 static void gtk_old_editable_editable_init (GtkEditableClass *iface);
78 static void gtk_old_editable_init (GtkOldEditable *editable);
79 static void gtk_old_editable_set_arg (GtkObject *object,
82 static void gtk_old_editable_get_arg (GtkObject *object,
85 static void *gtk_old_editable_get_public_chars (GtkOldEditable *old_editable,
89 static gint gtk_old_editable_selection_clear (GtkWidget *widget,
90 GdkEventSelection *event);
91 static void gtk_old_editable_selection_get (GtkWidget *widget,
92 GtkSelectionData *selection_data,
95 static void gtk_old_editable_selection_received (GtkWidget *widget,
96 GtkSelectionData *selection_data,
99 static void gtk_old_editable_set_selection (GtkOldEditable *old_editable,
103 static void gtk_old_editable_real_set_editable (GtkOldEditable *old_editable,
104 gboolean is_editable);
105 static void gtk_old_editable_real_cut_clipboard (GtkOldEditable *old_editable);
106 static void gtk_old_editable_real_copy_clipboard (GtkOldEditable *old_editable);
107 static void gtk_old_editable_real_paste_clipboard (GtkOldEditable *old_editable);
109 static void gtk_old_editable_insert_text (GtkEditable *editable,
110 const gchar *new_text,
111 gint new_text_length,
113 static void gtk_old_editable_delete_text (GtkEditable *editable,
116 static gchar * gtk_old_editable_get_chars (GtkEditable *editable,
119 static void gtk_old_editable_set_selection_bounds (GtkEditable *editable,
122 static gboolean gtk_old_editable_get_selection_bounds (GtkEditable *editable,
125 static void gtk_old_editable_set_position (GtkEditable *editable,
127 static gint gtk_old_editable_get_position (GtkEditable *editable);
129 static GtkWidgetClass *parent_class = NULL;
130 static guint editable_signals[LAST_SIGNAL] = { 0 };
133 gtk_old_editable_get_type (void)
135 static GtkType old_editable_type = 0;
137 if (!old_editable_type)
139 static const GtkTypeInfo old_editable_info =
142 sizeof (GtkOldEditable),
143 sizeof (GtkOldEditableClass),
144 (GtkClassInitFunc) gtk_old_editable_class_init,
145 (GtkObjectInitFunc) gtk_old_editable_init,
146 /* reserved_1 */ NULL,
147 /* reserved_2 */ NULL,
148 (GtkClassInitFunc) NULL,
151 static const GInterfaceInfo editable_info =
153 (GInterfaceInitFunc) gtk_old_editable_editable_init, /* interface_init */
154 NULL, /* interface_finalize */
155 NULL /* interface_data */
158 old_editable_type = gtk_type_unique (GTK_TYPE_WIDGET, &old_editable_info);
159 g_type_add_interface_static (old_editable_type,
164 return old_editable_type;
168 gtk_old_editable_class_init (GtkOldEditableClass *class)
170 GtkObjectClass *object_class;
171 GtkWidgetClass *widget_class;
173 object_class = (GtkObjectClass*) class;
174 widget_class = (GtkWidgetClass*) class;
176 parent_class = gtk_type_class (GTK_TYPE_WIDGET);
178 object_class->set_arg = gtk_old_editable_set_arg;
179 object_class->get_arg = gtk_old_editable_get_arg;
181 widget_class->selection_clear_event = gtk_old_editable_selection_clear;
182 widget_class->selection_received = gtk_old_editable_selection_received;
183 widget_class->selection_get = gtk_old_editable_selection_get;
185 class->insert_text = NULL;
186 class->delete_text = NULL;
188 class->activate = NULL;
189 class->set_editable = gtk_old_editable_real_set_editable;
191 class->move_cursor = NULL;
192 class->move_word = NULL;
193 class->move_page = NULL;
194 class->move_to_row = NULL;
195 class->move_to_column = NULL;
197 class->kill_char = NULL;
198 class->kill_word = NULL;
199 class->kill_line = NULL;
201 class->cut_clipboard = gtk_old_editable_real_cut_clipboard;
202 class->copy_clipboard = gtk_old_editable_real_copy_clipboard;
203 class->paste_clipboard = gtk_old_editable_real_paste_clipboard;
205 class->update_text = NULL;
206 class->get_chars = NULL;
207 class->set_selection = NULL;
208 class->set_position = NULL;
210 editable_signals[CHANGED] =
211 gtk_signal_new ("changed",
213 GTK_CLASS_TYPE (object_class),
214 GTK_SIGNAL_OFFSET (GtkOldEditableClass, changed),
215 gtk_marshal_NONE__NONE,
218 editable_signals[INSERT_TEXT] =
219 gtk_signal_new ("insert_text",
221 GTK_CLASS_TYPE (object_class),
222 GTK_SIGNAL_OFFSET (GtkOldEditableClass, insert_text),
223 gtk_marshal_NONE__STRING_INT_POINTER,
230 editable_signals[DELETE_TEXT] =
231 gtk_signal_new ("delete_text",
233 GTK_CLASS_TYPE (object_class),
234 GTK_SIGNAL_OFFSET (GtkOldEditableClass, delete_text),
235 gtk_marshal_NONE__INT_INT,
241 editable_signals[ACTIVATE] =
242 gtk_signal_new ("activate",
243 GTK_RUN_LAST | GTK_RUN_ACTION,
244 GTK_CLASS_TYPE (object_class),
245 GTK_SIGNAL_OFFSET (GtkOldEditableClass, activate),
246 gtk_marshal_NONE__NONE,
248 widget_class->activate_signal = editable_signals[ACTIVATE];
250 editable_signals[SET_EDITABLE] =
251 gtk_signal_new ("set-editable",
252 GTK_RUN_LAST | GTK_RUN_ACTION,
253 GTK_CLASS_TYPE (object_class),
254 GTK_SIGNAL_OFFSET (GtkOldEditableClass, set_editable),
255 gtk_marshal_NONE__BOOL,
259 editable_signals[MOVE_CURSOR] =
260 gtk_signal_new ("move_cursor",
261 GTK_RUN_LAST | GTK_RUN_ACTION,
262 GTK_CLASS_TYPE (object_class),
263 GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_cursor),
264 gtk_marshal_NONE__INT_INT,
269 editable_signals[MOVE_WORD] =
270 gtk_signal_new ("move_word",
271 GTK_RUN_LAST | GTK_RUN_ACTION,
272 GTK_CLASS_TYPE (object_class),
273 GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_word),
274 gtk_marshal_NONE__INT,
278 editable_signals[MOVE_PAGE] =
279 gtk_signal_new ("move_page",
280 GTK_RUN_LAST | GTK_RUN_ACTION,
281 GTK_CLASS_TYPE (object_class),
282 GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_page),
283 gtk_marshal_NONE__INT_INT,
288 editable_signals[MOVE_TO_ROW] =
289 gtk_signal_new ("move_to_row",
290 GTK_RUN_LAST | GTK_RUN_ACTION,
291 GTK_CLASS_TYPE (object_class),
292 GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_to_row),
293 gtk_marshal_NONE__INT,
297 editable_signals[MOVE_TO_COLUMN] =
298 gtk_signal_new ("move_to_column",
299 GTK_RUN_LAST | GTK_RUN_ACTION,
300 GTK_CLASS_TYPE (object_class),
301 GTK_SIGNAL_OFFSET (GtkOldEditableClass, move_to_column),
302 gtk_marshal_NONE__INT,
306 editable_signals[KILL_CHAR] =
307 gtk_signal_new ("kill_char",
308 GTK_RUN_LAST | GTK_RUN_ACTION,
309 GTK_CLASS_TYPE (object_class),
310 GTK_SIGNAL_OFFSET (GtkOldEditableClass, kill_char),
311 gtk_marshal_NONE__INT,
315 editable_signals[KILL_WORD] =
316 gtk_signal_new ("kill_word",
317 GTK_RUN_LAST | GTK_RUN_ACTION,
318 GTK_CLASS_TYPE (object_class),
319 GTK_SIGNAL_OFFSET (GtkOldEditableClass, kill_word),
320 gtk_marshal_NONE__INT,
324 editable_signals[KILL_LINE] =
325 gtk_signal_new ("kill_line",
326 GTK_RUN_LAST | GTK_RUN_ACTION,
327 GTK_CLASS_TYPE (object_class),
328 GTK_SIGNAL_OFFSET (GtkOldEditableClass, kill_line),
329 gtk_marshal_NONE__INT,
333 editable_signals[CUT_CLIPBOARD] =
334 gtk_signal_new ("cut_clipboard",
335 GTK_RUN_LAST | GTK_RUN_ACTION,
336 GTK_CLASS_TYPE (object_class),
337 GTK_SIGNAL_OFFSET (GtkOldEditableClass, cut_clipboard),
338 gtk_marshal_NONE__NONE,
341 editable_signals[COPY_CLIPBOARD] =
342 gtk_signal_new ("copy_clipboard",
343 GTK_RUN_LAST | GTK_RUN_ACTION,
344 GTK_CLASS_TYPE (object_class),
345 GTK_SIGNAL_OFFSET (GtkOldEditableClass, copy_clipboard),
346 gtk_marshal_NONE__NONE,
349 editable_signals[PASTE_CLIPBOARD] =
350 gtk_signal_new ("paste_clipboard",
351 GTK_RUN_LAST | GTK_RUN_ACTION,
352 GTK_CLASS_TYPE (object_class),
353 GTK_SIGNAL_OFFSET (GtkOldEditableClass, paste_clipboard),
354 gtk_marshal_NONE__NONE,
357 gtk_object_add_arg_type ("GtkOldEditable::text_position", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_TEXT_POSITION);
358 gtk_object_add_arg_type ("GtkOldEditable::editable", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_EDITABLE);
362 gtk_old_editable_editable_init (GtkEditableClass *iface)
364 iface->insert_text = gtk_old_editable_insert_text;
365 iface->delete_text = gtk_old_editable_delete_text;
366 iface->get_chars = gtk_old_editable_get_chars;
367 iface->set_selection_bounds = gtk_old_editable_set_selection_bounds;
368 iface->get_selection_bounds = gtk_old_editable_get_selection_bounds;
369 iface->set_position = gtk_old_editable_set_position;
370 iface->get_position = gtk_old_editable_get_position;
374 gtk_old_editable_set_arg (GtkObject *object,
378 GtkEditable *editable = GTK_EDITABLE (object);
382 case ARG_TEXT_POSITION:
383 gtk_editable_set_position (editable, GTK_VALUE_INT (*arg));
386 gtk_signal_emit (object, editable_signals[SET_EDITABLE],
387 GTK_VALUE_BOOL (*arg) != FALSE);
395 gtk_old_editable_get_arg (GtkObject *object,
399 GtkOldEditable *old_editable;
401 old_editable = GTK_OLD_EDITABLE (object);
405 case ARG_TEXT_POSITION:
406 GTK_VALUE_INT (*arg) = old_editable->current_pos;
409 GTK_VALUE_BOOL (*arg) = old_editable->editable;
412 arg->type = GTK_TYPE_INVALID;
418 gtk_old_editable_init (GtkOldEditable *old_editable)
420 static const GtkTargetEntry targets[] = {
421 { "UTF8_STRING", 0, 0 },
424 { "COMPOUND_TEXT", 0, 0 }
427 GTK_WIDGET_SET_FLAGS (old_editable, GTK_CAN_FOCUS);
429 old_editable->selection_start_pos = 0;
430 old_editable->selection_end_pos = 0;
431 old_editable->has_selection = FALSE;
432 old_editable->editable = 1;
433 old_editable->visible = 1;
434 old_editable->clipboard_text = NULL;
437 old_editable->ic = NULL;
440 gtk_selection_add_targets (GTK_WIDGET (old_editable), GDK_SELECTION_PRIMARY,
441 targets, G_N_ELEMENTS (targets));
445 gtk_old_editable_insert_text (GtkEditable *editable,
446 const gchar *new_text,
447 gint new_text_length,
453 gtk_widget_ref (GTK_WIDGET (editable));
455 if (new_text_length <= 63)
458 text = g_new (gchar, new_text_length + 1);
460 text[new_text_length] = '\0';
461 strncpy (text, new_text, new_text_length);
463 gtk_signal_emit (GTK_OBJECT (editable), editable_signals[INSERT_TEXT], text, new_text_length, position);
464 gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]);
466 if (new_text_length > 63)
469 gtk_widget_unref (GTK_WIDGET (editable));
473 gtk_old_editable_delete_text (GtkEditable *editable,
477 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (editable);
479 gtk_widget_ref (GTK_WIDGET (old_editable));
481 gtk_signal_emit (GTK_OBJECT (old_editable), editable_signals[DELETE_TEXT], start_pos, end_pos);
482 gtk_signal_emit (GTK_OBJECT (old_editable), editable_signals[CHANGED]);
484 if (old_editable->selection_start_pos == old_editable->selection_end_pos &&
485 old_editable->has_selection)
486 gtk_old_editable_claim_selection (old_editable, FALSE, GDK_CURRENT_TIME);
488 gtk_widget_unref (GTK_WIDGET (old_editable));
492 gtk_old_editable_update_text (GtkOldEditable *old_editable,
496 GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (old_editable);
497 klass->update_text (GTK_OLD_EDITABLE (old_editable), start_pos, end_pos);
501 gtk_old_editable_get_chars (GtkEditable *editable,
505 GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (editable);
506 return klass->get_chars (GTK_OLD_EDITABLE (editable), start, end);
510 * Like gtk_editable_get_chars, but if the editable is not
511 * visible, return asterisks; also convert result to UTF-8.
514 gtk_old_editable_get_public_chars (GtkOldEditable *old_editable,
520 gboolean need_conversion = !g_get_charset (&charset);
522 if (old_editable->visible)
525 gchar *tmp = gtk_editable_get_chars (GTK_EDITABLE (old_editable), start, end);
529 str = g_convert (tmp, -1,
535 g_warning ("Cannot convert text from charset to UTF-8 %s: %s", charset, error->message);
536 g_error_free (error);
547 gint nchars = end - start;
552 str = g_new (gchar, nchars + 1);
553 for (i = 0; i<nchars; i++)
562 gtk_old_editable_set_selection (GtkOldEditable *old_editable,
566 GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (old_editable);
567 klass->set_selection (old_editable, start_pos, end_pos);
571 gtk_old_editable_set_position (GtkEditable *editable,
574 GtkOldEditableClass *klass = GTK_OLD_EDITABLE_GET_CLASS (editable);
576 klass->set_position (GTK_OLD_EDITABLE (editable), position);
580 gtk_old_editable_get_position (GtkEditable *editable)
582 return GTK_OLD_EDITABLE (editable)->current_pos;
586 gtk_old_editable_selection_clear (GtkWidget *widget,
587 GdkEventSelection *event)
589 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (widget);
591 /* Let the selection handling code know that the selection
592 * has been changed, since we've overriden the default handler */
593 if (!gtk_selection_clear (widget, event))
596 if (old_editable->has_selection)
598 old_editable->has_selection = FALSE;
599 gtk_old_editable_update_text (old_editable, old_editable->selection_start_pos,
600 old_editable->selection_end_pos);
607 gtk_old_editable_selection_get (GtkWidget *widget,
608 GtkSelectionData *selection_data,
612 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (widget);
613 gint selection_start_pos;
614 gint selection_end_pos;
618 selection_start_pos = MIN (old_editable->selection_start_pos, old_editable->selection_end_pos);
619 selection_end_pos = MAX (old_editable->selection_start_pos, old_editable->selection_end_pos);
621 str = gtk_old_editable_get_public_chars (old_editable,
627 gtk_selection_data_set_text (selection_data, str);
633 gtk_old_editable_paste_received (GtkOldEditable *old_editable,
635 gboolean is_clipboard)
637 const gchar *str = NULL;
639 gboolean need_conversion = FALSE;
645 need_conversion = !g_get_charset (&charset);
649 str = g_convert_with_fallback (text, -1,
650 charset, "UTF-8", NULL,
654 g_warning ("Cannot convert text from UTF-8 to %s: %s",
655 charset, error->message);
656 g_error_free (error);
672 if ((old_editable->selection_start_pos != old_editable->selection_end_pos) &&
673 (!old_editable->has_selection || is_clipboard))
677 /* Don't want to call gtk_editable_delete_selection here if we are going
678 * to reclaim the selection to avoid extra server traffic */
679 if (old_editable->has_selection)
681 gtk_editable_delete_text (GTK_EDITABLE (old_editable),
682 MIN (old_editable->selection_start_pos, old_editable->selection_end_pos),
683 MAX (old_editable->selection_start_pos, old_editable->selection_end_pos));
686 gtk_editable_delete_selection (GTK_EDITABLE (old_editable));
689 tmp_pos = old_pos = old_editable->current_pos;
691 gtk_editable_insert_text (GTK_EDITABLE (old_editable), str, -1, &tmp_pos);
694 gtk_old_editable_set_selection (old_editable, old_pos, old_editable->current_pos);
696 if (str && str != text)
697 g_free ((gchar *) str);
702 gtk_old_editable_selection_received (GtkWidget *widget,
703 GtkSelectionData *selection_data,
706 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (widget);
708 gchar *text = gtk_selection_data_get_text (selection_data);
712 /* If we asked for UTF8 and didn't get it, try text; if we asked
713 * for text and didn't get it, try string. If we asked for
714 * anything else and didn't get it, give up.
716 if (selection_data->target == gdk_atom_intern ("UTF8_STRING", FALSE))
718 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
719 gdk_atom_intern ("TEXT", FALSE),
723 else if (selection_data->target == gdk_atom_intern ("TEXT", FALSE))
725 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
734 gtk_old_editable_paste_received (old_editable, text, FALSE);
740 old_editable_text_received_cb (GtkClipboard *clipboard,
744 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (data);
746 gtk_old_editable_paste_received (old_editable, text, TRUE);
747 g_object_unref (G_OBJECT (old_editable));
751 gtk_old_editable_claim_selection (GtkOldEditable *old_editable,
755 g_return_if_fail (old_editable != NULL);
756 g_return_if_fail (GTK_IS_OLD_EDITABLE (old_editable));
757 g_return_if_fail (GTK_WIDGET_REALIZED (old_editable));
759 old_editable->has_selection = FALSE;
763 if (gtk_selection_owner_set (GTK_WIDGET (old_editable), GDK_SELECTION_PRIMARY, time))
764 old_editable->has_selection = TRUE;
768 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == GTK_WIDGET (old_editable)->window)
769 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, time);
774 gtk_old_editable_set_selection_bounds (GtkEditable *editable,
778 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (editable);
780 if (GTK_WIDGET_REALIZED (editable))
781 gtk_old_editable_claim_selection (old_editable, start != end, GDK_CURRENT_TIME);
783 gtk_old_editable_set_selection (old_editable, start, end);
787 gtk_old_editable_get_selection_bounds (GtkEditable *editable,
791 GtkOldEditable *old_editable = GTK_OLD_EDITABLE (editable);
793 *start = old_editable->selection_start_pos;
794 *end = old_editable->selection_end_pos;
796 return (old_editable->selection_start_pos != old_editable->selection_end_pos);
800 gtk_old_editable_real_set_editable (GtkOldEditable *old_editable,
801 gboolean is_editable)
803 is_editable = is_editable != FALSE;
805 if (old_editable->editable != is_editable)
807 old_editable->editable = is_editable;
808 gtk_widget_queue_draw (GTK_WIDGET (old_editable));
813 gtk_old_editable_real_cut_clipboard (GtkOldEditable *old_editable)
815 gtk_old_editable_real_copy_clipboard (old_editable);
816 gtk_editable_delete_selection (GTK_EDITABLE (old_editable));
820 gtk_old_editable_real_copy_clipboard (GtkOldEditable *old_editable)
822 gint selection_start_pos;
823 gint selection_end_pos;
825 selection_start_pos = MIN (old_editable->selection_start_pos, old_editable->selection_end_pos);
826 selection_end_pos = MAX (old_editable->selection_start_pos, old_editable->selection_end_pos);
828 if (selection_start_pos != selection_end_pos)
830 gchar *text = gtk_old_editable_get_public_chars (old_editable,
836 gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), text, -1);
843 gtk_old_editable_real_paste_clipboard (GtkOldEditable *old_editable)
845 g_object_ref (G_OBJECT (old_editable));
846 gtk_clipboard_request_text (gtk_clipboard_get (GDK_NONE),
847 old_editable_text_received_cb, old_editable);
851 gtk_old_editable_changed (GtkOldEditable *old_editable)
853 g_return_if_fail (old_editable != NULL);
854 g_return_if_fail (GTK_IS_OLD_EDITABLE (old_editable));
856 gtk_signal_emit (GTK_OBJECT (old_editable), editable_signals[CHANGED]);