]> Pileus Git - ~andy/gtk/blob - gtk/gtkeditable.c
applied patch from Andreas Persenius <ndap@swipnet.se> that updates the
[~andy/gtk] / gtk / gtkeditable.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /*
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/. 
25  */
26
27 #include <ctype.h>
28 #include <string.h>
29 #include "gdk/gdkkeysyms.h"
30 #include "gdk/gdki18n.h"
31 #include "gtkeditable.h"
32 #include "gtkmain.h"
33 #include "gtkselection.h"
34 #include "gtksignal.h"
35
36 #define MIN_EDITABLE_WIDTH  150
37 #define DRAW_TIMEOUT     20
38 #define INNER_BORDER     2
39
40 enum {
41   CHANGED,
42   INSERT_TEXT,
43   DELETE_TEXT,
44   /* Binding actions */
45   ACTIVATE,
46   SET_EDITABLE,
47   MOVE_CURSOR,
48   MOVE_WORD,
49   MOVE_PAGE,
50   MOVE_TO_ROW,
51   MOVE_TO_COLUMN,
52   KILL_CHAR,
53   KILL_WORD,
54   KILL_LINE,
55   CUT_CLIPBOARD,
56   COPY_CLIPBOARD,
57   PASTE_CLIPBOARD,
58   LAST_SIGNAL
59 };
60
61 enum {
62   ARG_0,
63   ARG_TEXT_POSITION,
64   ARG_EDITABLE
65 };
66
67 /* values for selection info */
68
69 enum {
70   TARGET_STRING,
71   TARGET_TEXT,
72   TARGET_COMPOUND_TEXT
73 };
74
75 static void gtk_editable_class_init          (GtkEditableClass *klass);
76 static void gtk_editable_init                (GtkEditable      *editable);
77 static void gtk_editable_set_arg             (GtkObject        *object,
78                                               GtkArg           *arg,
79                                               guint             arg_id);
80 static void gtk_editable_get_arg             (GtkObject        *object,
81                                               GtkArg           *arg,
82                                               guint             arg_id);
83 static void *gtk_editable_get_public_chars   (GtkEditable      *editable,
84                                               gint              start,
85                                               gint              end);
86 static gint gtk_editable_selection_clear     (GtkWidget        *widget,
87                                              GdkEventSelection *event);
88 static void gtk_editable_selection_get      (GtkWidget         *widget,
89                                              GtkSelectionData  *selection_data,
90                                              guint              info,
91                                              guint              time);
92 static void gtk_editable_selection_received  (GtkWidget        *widget,
93                                               GtkSelectionData *selection_data,
94                                               guint             time);
95
96 static void gtk_editable_set_selection    (GtkEditable      *editable,
97                                            gint              start,
98                                            gint              end);
99 static guint32 gtk_editable_get_event_time (GtkEditable     *editable);
100
101 static void gtk_editable_real_cut_clipboard   (GtkEditable     *editable);
102 static void gtk_editable_real_copy_clipboard  (GtkEditable     *editable);
103 static void gtk_editable_real_paste_clipboard (GtkEditable     *editable);
104 static void gtk_editable_real_set_editable    (GtkEditable     *editable,
105                                                gboolean         is_editable);
106      
107 static GtkWidgetClass *parent_class = NULL;
108 static guint editable_signals[LAST_SIGNAL] = { 0 };
109
110 static GdkAtom clipboard_atom = GDK_NONE;
111
112 GtkType
113 gtk_editable_get_type (void)
114 {
115   static GtkType editable_type = 0;
116
117   if (!editable_type)
118     {
119       static const GtkTypeInfo editable_info =
120       {
121         "GtkEditable",
122         sizeof (GtkEditable),
123         sizeof (GtkEditableClass),
124         (GtkClassInitFunc) gtk_editable_class_init,
125         (GtkObjectInitFunc) gtk_editable_init,
126         /* reserved_1 */ NULL,
127         /* reserved_2 */ NULL,
128         (GtkClassInitFunc) NULL,
129       };
130
131       editable_type = gtk_type_unique (GTK_TYPE_WIDGET, &editable_info);
132     }
133
134   return editable_type;
135 }
136
137 static void
138 gtk_editable_class_init (GtkEditableClass *class)
139 {
140   GtkObjectClass *object_class;
141   GtkWidgetClass *widget_class;
142
143   object_class = (GtkObjectClass*) class;
144   widget_class = (GtkWidgetClass*) class;
145
146   parent_class = gtk_type_class (GTK_TYPE_WIDGET);
147
148   editable_signals[CHANGED] =
149     gtk_signal_new ("changed",
150                     GTK_RUN_LAST,
151                     GTK_CLASS_TYPE (object_class),
152                     GTK_SIGNAL_OFFSET (GtkEditableClass, changed),
153                     gtk_marshal_NONE__NONE,
154                     GTK_TYPE_NONE, 0);
155
156   editable_signals[INSERT_TEXT] =
157     gtk_signal_new ("insert_text",
158                     GTK_RUN_LAST,
159                     GTK_CLASS_TYPE (object_class),
160                     GTK_SIGNAL_OFFSET (GtkEditableClass, insert_text),
161                     gtk_marshal_NONE__POINTER_INT_POINTER,
162                     GTK_TYPE_NONE,
163                     3,
164                     GTK_TYPE_STRING,
165                     GTK_TYPE_INT,
166                     GTK_TYPE_POINTER);
167
168   editable_signals[DELETE_TEXT] =
169     gtk_signal_new ("delete_text",
170                     GTK_RUN_LAST,
171                     GTK_CLASS_TYPE (object_class),
172                     GTK_SIGNAL_OFFSET (GtkEditableClass, delete_text),
173                     gtk_marshal_NONE__INT_INT,
174                     GTK_TYPE_NONE,
175                     2,
176                     GTK_TYPE_INT,
177                     GTK_TYPE_INT);                  
178
179   editable_signals[ACTIVATE] =
180     gtk_signal_new ("activate",
181                     GTK_RUN_LAST | GTK_RUN_ACTION,
182                     GTK_CLASS_TYPE (object_class),
183                     GTK_SIGNAL_OFFSET (GtkEditableClass, activate),
184                     gtk_marshal_NONE__NONE,
185                     GTK_TYPE_NONE, 0);
186   widget_class->activate_signal = editable_signals[ACTIVATE];
187
188   editable_signals[SET_EDITABLE] =
189     gtk_signal_new ("set-editable",
190                     GTK_RUN_LAST | GTK_RUN_ACTION,
191                     GTK_CLASS_TYPE (object_class),
192                     GTK_SIGNAL_OFFSET (GtkEditableClass, set_editable),
193                     gtk_marshal_NONE__BOOL,
194                     GTK_TYPE_NONE, 1,
195                     GTK_TYPE_BOOL);
196
197   editable_signals[MOVE_CURSOR] =
198     gtk_signal_new ("move_cursor",
199                     GTK_RUN_LAST | GTK_RUN_ACTION,
200                     GTK_CLASS_TYPE (object_class),
201                     GTK_SIGNAL_OFFSET (GtkEditableClass, move_cursor),
202                     gtk_marshal_NONE__INT_INT,
203                     GTK_TYPE_NONE, 2, 
204                     GTK_TYPE_INT, 
205                     GTK_TYPE_INT);
206
207   editable_signals[MOVE_WORD] =
208     gtk_signal_new ("move_word",
209                     GTK_RUN_LAST | GTK_RUN_ACTION,
210                     GTK_CLASS_TYPE (object_class),
211                     GTK_SIGNAL_OFFSET (GtkEditableClass, move_word),
212                     gtk_marshal_NONE__INT,
213                     GTK_TYPE_NONE, 1, 
214                     GTK_TYPE_INT);
215
216   editable_signals[MOVE_PAGE] =
217     gtk_signal_new ("move_page",
218                     GTK_RUN_LAST | GTK_RUN_ACTION,
219                     GTK_CLASS_TYPE (object_class),
220                     GTK_SIGNAL_OFFSET (GtkEditableClass, move_page),
221                     gtk_marshal_NONE__INT_INT,
222                     GTK_TYPE_NONE, 2, 
223                     GTK_TYPE_INT, 
224                     GTK_TYPE_INT);
225
226   editable_signals[MOVE_TO_ROW] =
227     gtk_signal_new ("move_to_row",
228                     GTK_RUN_LAST | GTK_RUN_ACTION,
229                     GTK_CLASS_TYPE (object_class),
230                     GTK_SIGNAL_OFFSET (GtkEditableClass, move_to_row),
231                     gtk_marshal_NONE__INT,
232                     GTK_TYPE_NONE, 1, 
233                     GTK_TYPE_INT);
234
235   editable_signals[MOVE_TO_COLUMN] =
236     gtk_signal_new ("move_to_column",
237                     GTK_RUN_LAST | GTK_RUN_ACTION,
238                     GTK_CLASS_TYPE (object_class),
239                     GTK_SIGNAL_OFFSET (GtkEditableClass, move_to_column),
240                     gtk_marshal_NONE__INT,
241                     GTK_TYPE_NONE, 1, 
242                     GTK_TYPE_INT);
243
244   editable_signals[KILL_CHAR] =
245     gtk_signal_new ("kill_char",
246                     GTK_RUN_LAST | GTK_RUN_ACTION,
247                     GTK_CLASS_TYPE (object_class),
248                     GTK_SIGNAL_OFFSET (GtkEditableClass, kill_char),
249                     gtk_marshal_NONE__INT,
250                     GTK_TYPE_NONE, 1, 
251                     GTK_TYPE_INT);
252
253   editable_signals[KILL_WORD] =
254     gtk_signal_new ("kill_word",
255                     GTK_RUN_LAST | GTK_RUN_ACTION,
256                     GTK_CLASS_TYPE (object_class),
257                     GTK_SIGNAL_OFFSET (GtkEditableClass, kill_word),
258                     gtk_marshal_NONE__INT,
259                     GTK_TYPE_NONE, 1, 
260                     GTK_TYPE_INT);
261
262   editable_signals[KILL_LINE] =
263     gtk_signal_new ("kill_line",
264                     GTK_RUN_LAST | GTK_RUN_ACTION,
265                     GTK_CLASS_TYPE (object_class),
266                     GTK_SIGNAL_OFFSET (GtkEditableClass, kill_line),
267                     gtk_marshal_NONE__INT,
268                     GTK_TYPE_NONE, 1, 
269                     GTK_TYPE_INT);
270
271   editable_signals[CUT_CLIPBOARD] =
272     gtk_signal_new ("cut_clipboard",
273                     GTK_RUN_LAST | GTK_RUN_ACTION,
274                     GTK_CLASS_TYPE (object_class),
275                     GTK_SIGNAL_OFFSET (GtkEditableClass, cut_clipboard),
276                     gtk_marshal_NONE__NONE,
277                     GTK_TYPE_NONE, 0);
278
279   editable_signals[COPY_CLIPBOARD] =
280     gtk_signal_new ("copy_clipboard",
281                     GTK_RUN_LAST | GTK_RUN_ACTION,
282                     GTK_CLASS_TYPE (object_class),
283                     GTK_SIGNAL_OFFSET (GtkEditableClass, copy_clipboard),
284                     gtk_marshal_NONE__NONE,
285                     GTK_TYPE_NONE, 0);
286
287   editable_signals[PASTE_CLIPBOARD] =
288     gtk_signal_new ("paste_clipboard",
289                     GTK_RUN_LAST | GTK_RUN_ACTION,
290                     GTK_CLASS_TYPE (object_class),
291                     GTK_SIGNAL_OFFSET (GtkEditableClass, paste_clipboard),
292                     gtk_marshal_NONE__NONE,
293                     GTK_TYPE_NONE, 0);
294
295   gtk_object_class_add_signals (object_class, editable_signals, LAST_SIGNAL);
296
297   gtk_object_add_arg_type ("GtkEditable::text_position", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_TEXT_POSITION);
298   gtk_object_add_arg_type ("GtkEditable::editable", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_EDITABLE);
299     
300   object_class->set_arg = gtk_editable_set_arg;
301   object_class->get_arg = gtk_editable_get_arg;
302
303   widget_class->selection_clear_event = gtk_editable_selection_clear;
304   widget_class->selection_received = gtk_editable_selection_received;
305   widget_class->selection_get = gtk_editable_selection_get;
306
307   class->insert_text = NULL;
308   class->delete_text = NULL;
309
310   class->activate = NULL;
311   class->set_editable = gtk_editable_real_set_editable;
312
313   class->move_cursor = NULL;
314   class->move_word = NULL;
315   class->move_page = NULL;
316   class->move_to_row = NULL;
317   class->move_to_column = NULL;
318
319   class->kill_char = NULL;
320   class->kill_word = NULL;
321   class->kill_line = NULL;
322
323   class->cut_clipboard = gtk_editable_real_cut_clipboard;
324   class->copy_clipboard = gtk_editable_real_copy_clipboard;
325   class->paste_clipboard = gtk_editable_real_paste_clipboard;
326
327   class->update_text = NULL;
328   class->get_chars = NULL;
329   class->set_selection = NULL;
330   class->set_position = NULL;
331 }
332
333 static void
334 gtk_editable_set_arg (GtkObject      *object,
335                       GtkArg         *arg,
336                       guint           arg_id)
337 {
338   GtkEditable *editable;
339
340   editable = GTK_EDITABLE (object);
341
342   switch (arg_id)
343     {
344     case ARG_TEXT_POSITION:
345       gtk_editable_set_position (editable, GTK_VALUE_INT (*arg));
346       break;
347     case ARG_EDITABLE:
348       gtk_editable_set_editable (editable, GTK_VALUE_BOOL (*arg));
349       break;
350     default:
351       break;
352     }
353 }
354
355 static void
356 gtk_editable_get_arg (GtkObject      *object,
357                       GtkArg         *arg,
358                       guint           arg_id)
359 {
360   GtkEditable *editable;
361
362   editable = GTK_EDITABLE (object);
363
364   switch (arg_id)
365     {
366     case ARG_TEXT_POSITION:
367       GTK_VALUE_INT (*arg) = editable->current_pos;
368       break;
369     case ARG_EDITABLE:
370       GTK_VALUE_BOOL (*arg) = editable->editable;
371       break;
372     default:
373       arg->type = GTK_TYPE_INVALID;
374       break;
375     }
376 }
377
378 static void
379 gtk_editable_init (GtkEditable *editable)
380 {
381   static const GtkTargetEntry targets[] = {
382     { "STRING", 0, TARGET_STRING },
383     { "TEXT",   0, TARGET_TEXT }, 
384     { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT }
385   };
386   static const gint n_targets = sizeof(targets) / sizeof(targets[0]);
387   
388   GTK_WIDGET_SET_FLAGS (editable, GTK_CAN_FOCUS);
389
390   editable->selection_start_pos = 0;
391   editable->selection_end_pos = 0;
392   editable->has_selection = FALSE;
393   editable->editable = 1;
394   editable->visible = 1;
395   editable->clipboard_text = NULL;
396
397 #ifdef USE_XIM
398   editable->ic = NULL;
399 #endif
400
401   if (!clipboard_atom)
402     clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
403
404   gtk_selection_add_targets (GTK_WIDGET (editable), GDK_SELECTION_PRIMARY,
405                              targets, n_targets);
406   gtk_selection_add_targets (GTK_WIDGET (editable), clipboard_atom,
407                              targets, n_targets);
408 }
409
410 void
411 gtk_editable_insert_text (GtkEditable *editable,
412                           const gchar *new_text,
413                           gint         new_text_length,
414                           gint        *position)
415 {
416   GtkEditableClass *klass;
417   gchar buf[64];
418   gchar *text;
419
420   g_return_if_fail (editable != NULL);
421   g_return_if_fail (GTK_IS_EDITABLE (editable));
422
423   gtk_widget_ref (GTK_WIDGET (editable));
424
425   klass = GTK_EDITABLE_GET_CLASS (editable);
426
427   if (new_text_length < 0)
428     new_text_length = strlen (new_text);
429   
430   if (new_text_length <= 64)
431     text = buf;
432   else
433     text = g_new (gchar, new_text_length);
434
435   strncpy (text, new_text, new_text_length);
436
437   gtk_signal_emit (GTK_OBJECT (editable), editable_signals[INSERT_TEXT], text, new_text_length, position);
438   gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]);
439
440   if (new_text_length > 64)
441     g_free (text);
442
443   gtk_widget_unref (GTK_WIDGET (editable));
444 }
445
446 void
447 gtk_editable_delete_text (GtkEditable *editable,
448                           gint         start_pos,
449                           gint         end_pos)
450 {
451   GtkEditableClass *klass;
452
453   g_return_if_fail (editable != NULL);
454   g_return_if_fail (GTK_IS_EDITABLE (editable));
455
456   gtk_widget_ref (GTK_WIDGET (editable));
457
458   klass = GTK_EDITABLE_GET_CLASS (editable);
459
460   gtk_signal_emit (GTK_OBJECT (editable), editable_signals[DELETE_TEXT], start_pos, end_pos);
461   gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]);
462
463   gtk_widget_unref (GTK_WIDGET (editable));
464 }
465
466 static void
467 gtk_editable_update_text (GtkEditable *editable,
468                        gint      start_pos,
469                        gint      end_pos)
470 {
471   GtkEditableClass *klass;
472
473   g_return_if_fail (editable != NULL);
474   g_return_if_fail (GTK_IS_EDITABLE (editable));
475
476   klass = GTK_EDITABLE_GET_CLASS (editable);
477
478   klass->update_text (editable, start_pos, end_pos);
479 }
480
481 gchar *    
482 gtk_editable_get_chars      (GtkEditable      *editable,
483                              gint              start,
484                              gint              end)
485 {
486   GtkEditableClass *klass;
487
488   g_return_val_if_fail (editable != NULL, NULL);
489   g_return_val_if_fail (GTK_IS_EDITABLE (editable), NULL);
490
491   klass = GTK_EDITABLE_GET_CLASS (editable);
492
493   return klass->get_chars (editable, start, end);
494 }
495
496 /*
497  * Like gtk_editable_get_chars, but if the editable is not
498  * visible, return asterisks
499  */
500 static void *    
501 gtk_editable_get_public_chars (GtkEditable      *editable,
502                                gint              start,
503                                gint              end)
504 {
505   if (editable->visible)
506     return gtk_editable_get_chars (editable, start, end);
507   else
508     {
509       gint i;
510       gint nchars = end - start;
511       gchar *str;
512        
513       if (nchars < 0)
514         nchars = -nchars;
515
516       str = g_new (gchar, nchars + 1);
517       for (i = 0; i<nchars; i++)
518         str[i] = '*';
519       str[i] = '\0';
520
521       return str;
522     }
523 }
524
525 static void
526 gtk_editable_set_selection (GtkEditable *editable,
527                             gint      start_pos,
528                             gint      end_pos)
529 {
530   GtkEditableClass *klass;
531
532   g_return_if_fail (editable != NULL);
533   g_return_if_fail (GTK_IS_EDITABLE (editable));
534
535   klass = GTK_EDITABLE_GET_CLASS (editable);
536
537   klass->set_selection (editable, start_pos, end_pos);
538 }
539
540 void
541 gtk_editable_set_position (GtkEditable      *editable,
542                            gint              position)
543 {
544   GtkEditableClass *klass;
545
546   g_return_if_fail (editable != NULL);
547   g_return_if_fail (GTK_IS_EDITABLE (editable));
548
549   klass = GTK_EDITABLE_GET_CLASS (editable);
550
551   klass->set_position (editable, position);
552 }
553
554 gint
555 gtk_editable_get_position (GtkEditable      *editable)
556 {
557   g_return_val_if_fail (editable != NULL, -1);
558   g_return_val_if_fail (GTK_IS_EDITABLE (editable), -1);
559
560   return editable->current_pos;
561 }
562
563 static gint
564 gtk_editable_selection_clear (GtkWidget         *widget,
565                               GdkEventSelection *event)
566 {
567   GtkEditable *editable;
568   
569   g_return_val_if_fail (widget != NULL, FALSE);
570   g_return_val_if_fail (GTK_IS_EDITABLE (widget), FALSE);
571   g_return_val_if_fail (event != NULL, FALSE);
572   
573   /* Let the selection handling code know that the selection
574    * has been changed, since we've overriden the default handler */
575   if (!gtk_selection_clear (widget, event))
576     return FALSE;
577   
578   editable = GTK_EDITABLE (widget);
579   
580   if (event->selection == GDK_SELECTION_PRIMARY)
581     {
582       if (editable->has_selection)
583         {
584           editable->has_selection = FALSE;
585           gtk_editable_update_text (editable, editable->selection_start_pos,
586                                     editable->selection_end_pos);
587         }
588     }
589   else if (event->selection == clipboard_atom)
590     {
591       g_free (editable->clipboard_text);
592       editable->clipboard_text = NULL;
593     }
594   
595   return TRUE;
596 }
597
598 static void
599 gtk_editable_selection_get (GtkWidget        *widget,
600                             GtkSelectionData *selection_data,
601                             guint             info,
602                             guint             time)
603 {
604   GtkEditable *editable;
605   gint selection_start_pos;
606   gint selection_end_pos;
607
608   gchar *str;
609   gint length;
610
611   g_return_if_fail (widget != NULL);
612   g_return_if_fail (GTK_IS_EDITABLE (widget));
613
614   editable = GTK_EDITABLE (widget);
615
616   if (selection_data->selection == GDK_SELECTION_PRIMARY)
617     {
618       selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos);
619       selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos);
620       str = gtk_editable_get_public_chars(editable, 
621                                           selection_start_pos, 
622                                           selection_end_pos);
623       if (!str)
624          return;                /* Refuse */
625       length = strlen (str);
626     }
627   else                          /* CLIPBOARD */
628     {
629       if (!editable->clipboard_text)
630         return;                 /* Refuse */
631
632       str = editable->clipboard_text;
633       length = strlen (editable->clipboard_text);
634     }
635   
636   if (info == TARGET_STRING)
637     {
638       gtk_selection_data_set (selection_data,
639                               GDK_SELECTION_TYPE_STRING,
640                               8*sizeof(gchar), (guchar *)str, length);
641     }
642   else if ((info == TARGET_TEXT) || (info == TARGET_COMPOUND_TEXT))
643     {
644       guchar *text;
645       gchar c;
646       GdkAtom encoding;
647       gint format;
648       gint new_length;
649
650       c = str[length];
651       str[length] = '\0';
652       gdk_string_to_compound_text (str, &encoding, &format, &text, &new_length);
653       gtk_selection_data_set (selection_data, encoding, format, text, new_length);
654       gdk_free_compound_text (text);
655       str[length] = c;
656     }
657
658   if (str != editable->clipboard_text)
659     g_free (str);
660 }
661
662 static void
663 gtk_editable_selection_received  (GtkWidget         *widget,
664                                   GtkSelectionData  *selection_data,
665                                   guint              time)
666 {
667   GtkEditable *editable;
668   gint reselect;
669   gint old_pos;
670   gint tmp_pos;
671   enum {INVALID, STRING, CTEXT} type;
672
673   g_return_if_fail (widget != NULL);
674   g_return_if_fail (GTK_IS_EDITABLE (widget));
675
676   editable = GTK_EDITABLE (widget);
677
678   if (selection_data->type == GDK_TARGET_STRING)
679     type = STRING;
680   else if ((selection_data->type == gdk_atom_intern ("COMPOUND_TEXT", FALSE)) ||
681            (selection_data->type == gdk_atom_intern ("TEXT", FALSE)))
682     type = CTEXT;
683   else
684     type = INVALID;
685
686   if (type == INVALID || selection_data->length < 0)
687     {
688     /* avoid infinite loop */
689     if (selection_data->target != GDK_TARGET_STRING)
690       gtk_selection_convert (widget, selection_data->selection,
691                              GDK_TARGET_STRING, time);
692     return;
693   }
694
695   reselect = FALSE;
696
697   if ((editable->selection_start_pos != editable->selection_end_pos) && 
698       (!editable->has_selection || 
699        (selection_data->selection == clipboard_atom)))
700     {
701       reselect = TRUE;
702
703       /* Don't want to call gtk_editable_delete_selection here if we are going
704        * to reclaim the selection to avoid extra server traffic */
705       if (editable->has_selection)
706         {
707           gtk_editable_delete_text (editable,
708                                  MIN (editable->selection_start_pos, editable->selection_end_pos),
709                                  MAX (editable->selection_start_pos, editable->selection_end_pos));
710         }
711       else
712         gtk_editable_delete_selection (editable);
713     }
714
715   tmp_pos = old_pos = editable->current_pos;
716
717   switch (type)
718     {
719     case STRING:
720       selection_data->data[selection_data->length] = 0;
721       gtk_editable_insert_text (editable, (gchar *)selection_data->data,
722                                 strlen ((gchar *)selection_data->data), 
723                                 &tmp_pos);
724       editable->current_pos = tmp_pos;
725       break;
726     case CTEXT:
727       {
728         gchar **list;
729         gint count;
730         gint i;
731
732         count = gdk_text_property_to_text_list (selection_data->type,
733                                                 selection_data->format, 
734                                                 selection_data->data,
735                                                 selection_data->length,
736                                                 &list);
737         for (i=0; i<count; i++) 
738           {
739             gtk_editable_insert_text (editable, list[i], strlen (list[i]), &tmp_pos);
740             editable->current_pos = tmp_pos;
741           }
742         if (count > 0)
743           gdk_free_text_list (list);
744       }
745       break;
746     case INVALID:               /* quiet compiler */
747       break;
748     }
749
750   if (reselect)
751     gtk_editable_set_selection (editable, old_pos, editable->current_pos);
752 }
753
754 void
755 gtk_editable_delete_selection (GtkEditable *editable)
756 {
757   guint start;
758   guint end;
759
760   g_return_if_fail (editable != NULL);
761   g_return_if_fail (GTK_IS_EDITABLE (editable));
762
763   if (!editable->editable)
764     return;
765
766   start = editable->selection_start_pos;
767   end = editable->selection_end_pos;
768
769   editable->selection_start_pos = 0;
770   editable->selection_end_pos = 0;
771
772   if (start != end)
773     gtk_editable_delete_text (editable, MIN (start, end), MAX (start,end));
774
775   if (editable->has_selection)
776     {
777       editable->has_selection = FALSE;
778       if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == GTK_WIDGET (editable)->window)
779         gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
780     }
781 }
782
783 void
784 gtk_editable_claim_selection (GtkEditable *editable, 
785                               gboolean  claim, 
786                               guint32   time)
787 {
788   g_return_if_fail (editable != NULL);
789   g_return_if_fail (GTK_IS_EDITABLE (editable));
790   g_return_if_fail (GTK_WIDGET_REALIZED (editable));
791
792   editable->has_selection = FALSE;
793   
794   if (claim)
795     {
796       if (gtk_selection_owner_set (GTK_WIDGET(editable), GDK_SELECTION_PRIMARY, time))
797         editable->has_selection = TRUE;
798     }
799   else
800     {
801       if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == 
802           GTK_WIDGET(editable)->window)
803         gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, time);
804     }
805 }
806
807 void
808 gtk_editable_select_region (GtkEditable *editable,
809                             gint         start,
810                             gint         end)
811 {
812   g_return_if_fail (editable != NULL);
813   g_return_if_fail (GTK_IS_EDITABLE (editable));
814   
815   if (GTK_WIDGET_REALIZED (editable))
816     gtk_editable_claim_selection (editable, start != end, GDK_CURRENT_TIME);
817   
818   gtk_editable_set_selection (editable, start, end);
819 }
820
821 /* Get the timestamp of the current event. Actually, the only thing
822  * we really care about below is the key event
823  */
824 static guint32
825 gtk_editable_get_event_time (GtkEditable *editable)
826 {
827   GdkEvent *event;
828   guint32 tm = GDK_CURRENT_TIME;
829   
830   event = gtk_get_current_event();
831   
832   if (event)
833     switch (event->type)
834       {
835       case GDK_MOTION_NOTIFY:
836         tm = event->motion.time; break;
837       case GDK_BUTTON_PRESS:
838       case GDK_2BUTTON_PRESS:
839       case GDK_3BUTTON_PRESS:
840       case GDK_BUTTON_RELEASE:
841         tm = event->button.time; break;
842       case GDK_KEY_PRESS:
843       case GDK_KEY_RELEASE:
844         tm = event->key.time; break;
845       case GDK_ENTER_NOTIFY:
846       case GDK_LEAVE_NOTIFY:
847         tm = event->crossing.time; break;
848       case GDK_PROPERTY_NOTIFY:
849         tm = event->property.time; break;
850       case GDK_SELECTION_CLEAR:
851       case GDK_SELECTION_REQUEST:
852       case GDK_SELECTION_NOTIFY:
853         tm = event->selection.time; break;
854       case GDK_PROXIMITY_IN:
855       case GDK_PROXIMITY_OUT:
856         tm = event->proximity.time; break;
857       default:                  /* use current time */
858         break;
859       }
860   gdk_event_free(event);
861   
862   return tm;
863 }
864
865 void
866 gtk_editable_cut_clipboard (GtkEditable *editable)
867 {
868   g_return_if_fail (editable != NULL);
869   g_return_if_fail (GTK_IS_EDITABLE (editable));
870   
871   gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CUT_CLIPBOARD]);
872 }
873
874 void
875 gtk_editable_copy_clipboard (GtkEditable *editable)
876 {
877   g_return_if_fail (editable != NULL);
878   g_return_if_fail (GTK_IS_EDITABLE (editable));
879   
880   gtk_signal_emit (GTK_OBJECT (editable), editable_signals[COPY_CLIPBOARD]);
881 }
882
883 void
884 gtk_editable_paste_clipboard (GtkEditable *editable)
885 {
886   g_return_if_fail (editable != NULL);
887   g_return_if_fail (GTK_IS_EDITABLE (editable));
888   
889   gtk_signal_emit (GTK_OBJECT (editable), editable_signals[PASTE_CLIPBOARD]);
890 }
891
892 void
893 gtk_editable_set_editable (GtkEditable    *editable,
894                            gboolean        is_editable)
895 {
896   g_return_if_fail (editable != NULL);
897   g_return_if_fail (GTK_IS_EDITABLE (editable));
898   
899   gtk_signal_emit (GTK_OBJECT (editable), editable_signals[SET_EDITABLE], is_editable != FALSE);
900 }
901
902 static void
903 gtk_editable_real_set_editable (GtkEditable    *editable,
904                                 gboolean        is_editable)
905 {
906   g_return_if_fail (editable != NULL);
907   g_return_if_fail (GTK_IS_EDITABLE (editable));
908
909   editable->editable = is_editable != FALSE;
910   gtk_widget_queue_draw (GTK_WIDGET (editable));
911 }
912
913 static void
914 gtk_editable_real_cut_clipboard (GtkEditable *editable)
915 {
916   g_return_if_fail (editable != NULL);
917   g_return_if_fail (GTK_IS_EDITABLE (editable));
918   
919   gtk_editable_real_copy_clipboard (editable);
920   gtk_editable_delete_selection (editable);
921 }
922
923 static void
924 gtk_editable_real_copy_clipboard (GtkEditable *editable)
925 {
926   guint32 time;
927   gint selection_start_pos; 
928   gint selection_end_pos;
929
930   g_return_if_fail (editable != NULL);
931   g_return_if_fail (GTK_IS_EDITABLE (editable));
932   
933   time = gtk_editable_get_event_time (editable);
934   selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos);
935   selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos);
936  
937   if (selection_start_pos != selection_end_pos)
938     {
939       if (gtk_selection_owner_set (GTK_WIDGET (editable),
940                                    clipboard_atom,
941                                    time))
942         editable->clipboard_text = gtk_editable_get_public_chars (editable,
943                                                                   selection_start_pos,
944                                                                   selection_end_pos);
945     }
946 }
947
948 static void
949 gtk_editable_real_paste_clipboard (GtkEditable *editable)
950 {
951   guint32 time;
952
953   g_return_if_fail (editable != NULL);
954   g_return_if_fail (GTK_IS_EDITABLE (editable));
955   
956   time = gtk_editable_get_event_time (editable);
957   if (editable->editable)
958     gtk_selection_convert (GTK_WIDGET(editable), 
959                            clipboard_atom, 
960                            gdk_atom_intern ("COMPOUND_TEXT", FALSE), time);
961 }
962
963 void
964 gtk_editable_changed (GtkEditable *editable)
965 {
966   g_return_if_fail (editable != NULL);
967   g_return_if_fail (GTK_IS_EDITABLE (editable));
968   
969   gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]);
970 }