]> Pileus Git - ~andy/gtk/blob - gtk/gtkeditable.c
Adapt cast macros to standard.
[~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 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.
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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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-1999.  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                     object_class->type,
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                     object_class->type,
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                     object_class->type,
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                     object_class->type,
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                     object_class->type,
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                     object_class->type,
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                     object_class->type,
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                     object_class->type,
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                     object_class->type,
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                     object_class->type,
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                     object_class->type,
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                     object_class->type,
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                     object_class->type,
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                     object_class->type,
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                     object_class->type,
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                     object_class->type,
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_CLASS (GTK_OBJECT (editable)->klass);
426
427   if (new_text_length <= 64)
428     text = buf;
429   else
430     text = g_new (gchar, new_text_length);
431
432   strncpy (text, new_text, new_text_length);
433
434   gtk_signal_emit (GTK_OBJECT (editable), editable_signals[INSERT_TEXT], text, new_text_length, position);
435   gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]);
436
437   if (new_text_length > 64)
438     g_free (text);
439
440   gtk_widget_unref (GTK_WIDGET (editable));
441 }
442
443 void
444 gtk_editable_delete_text (GtkEditable *editable,
445                           gint         start_pos,
446                           gint         end_pos)
447 {
448   GtkEditableClass *klass;
449
450   g_return_if_fail (editable != NULL);
451   g_return_if_fail (GTK_IS_EDITABLE (editable));
452
453   gtk_widget_ref (GTK_WIDGET (editable));
454
455   klass = GTK_EDITABLE_CLASS (GTK_OBJECT (editable)->klass);
456
457   gtk_signal_emit (GTK_OBJECT (editable), editable_signals[DELETE_TEXT], start_pos, end_pos);
458   gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]);
459
460   gtk_widget_unref (GTK_WIDGET (editable));
461 }
462
463 static void
464 gtk_editable_update_text (GtkEditable *editable,
465                        gint      start_pos,
466                        gint      end_pos)
467 {
468   GtkEditableClass *klass;
469
470   g_return_if_fail (editable != NULL);
471   g_return_if_fail (GTK_IS_EDITABLE (editable));
472
473   klass = GTK_EDITABLE_CLASS (GTK_OBJECT (editable)->klass);
474
475   klass->update_text (editable, start_pos, end_pos);
476 }
477
478 gchar *    
479 gtk_editable_get_chars      (GtkEditable      *editable,
480                              gint              start,
481                              gint              end)
482 {
483   GtkEditableClass *klass;
484
485   g_return_val_if_fail (editable != NULL, NULL);
486   g_return_val_if_fail (GTK_IS_EDITABLE (editable), NULL);
487
488   klass = GTK_EDITABLE_CLASS (GTK_OBJECT (editable)->klass);
489
490   return klass->get_chars (editable, start, end);
491 }
492
493 /*
494  * Like gtk_editable_get_chars, but if the editable is not
495  * visible, return asterisks
496  */
497 static void *    
498 gtk_editable_get_public_chars (GtkEditable      *editable,
499                                gint              start,
500                                gint              end)
501 {
502   if (editable->visible)
503     return gtk_editable_get_chars (editable, start, end);
504   else
505     {
506       gint i;
507       gint nchars = end - start;
508       gchar *str;
509        
510       if (nchars < 0)
511         nchars = -nchars;
512
513       str = g_new (gchar, nchars + 1);
514       for (i = 0; i<nchars; i++)
515         str[i] = '*';
516       str[i] = '\0';
517
518       return str;
519     }
520 }
521
522 static void
523 gtk_editable_set_selection (GtkEditable *editable,
524                             gint      start_pos,
525                             gint      end_pos)
526 {
527   GtkEditableClass *klass;
528
529   g_return_if_fail (editable != NULL);
530   g_return_if_fail (GTK_IS_EDITABLE (editable));
531
532   klass = GTK_EDITABLE_CLASS (GTK_OBJECT (editable)->klass);
533
534   klass->set_selection (editable, start_pos, end_pos);
535 }
536
537 void
538 gtk_editable_set_position (GtkEditable      *editable,
539                            gint              position)
540 {
541   GtkEditableClass *klass;
542
543   g_return_if_fail (editable != NULL);
544   g_return_if_fail (GTK_IS_EDITABLE (editable));
545
546   klass = GTK_EDITABLE_CLASS (GTK_OBJECT (editable)->klass);
547
548   klass->set_position (editable, position);
549 }
550
551 gint
552 gtk_editable_get_position (GtkEditable      *editable)
553 {
554   g_return_val_if_fail (editable != NULL, -1);
555   g_return_val_if_fail (GTK_IS_EDITABLE (editable), -1);
556
557   return editable->current_pos;
558 }
559
560 static gint
561 gtk_editable_selection_clear (GtkWidget         *widget,
562                               GdkEventSelection *event)
563 {
564   GtkEditable *editable;
565   
566   g_return_val_if_fail (widget != NULL, FALSE);
567   g_return_val_if_fail (GTK_IS_EDITABLE (widget), FALSE);
568   g_return_val_if_fail (event != NULL, FALSE);
569   
570   /* Let the selection handling code know that the selection
571    * has been changed, since we've overriden the default handler */
572   if (!gtk_selection_clear (widget, event))
573     return FALSE;
574   
575   editable = GTK_EDITABLE (widget);
576   
577   if (event->selection == GDK_SELECTION_PRIMARY)
578     {
579       if (editable->has_selection)
580         {
581           editable->has_selection = FALSE;
582           gtk_editable_update_text (editable, editable->selection_start_pos,
583                                     editable->selection_end_pos);
584         }
585     }
586   else if (event->selection == clipboard_atom)
587     {
588       g_free (editable->clipboard_text);
589       editable->clipboard_text = NULL;
590     }
591   
592   return TRUE;
593 }
594
595 static void
596 gtk_editable_selection_get (GtkWidget        *widget,
597                             GtkSelectionData *selection_data,
598                             guint             info,
599                             guint             time)
600 {
601   GtkEditable *editable;
602   gint selection_start_pos;
603   gint selection_end_pos;
604
605   gchar *str;
606   gint length;
607
608   g_return_if_fail (widget != NULL);
609   g_return_if_fail (GTK_IS_EDITABLE (widget));
610
611   editable = GTK_EDITABLE (widget);
612
613   if (selection_data->selection == GDK_SELECTION_PRIMARY)
614     {
615       selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos);
616       selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos);
617       str = gtk_editable_get_public_chars(editable, 
618                                           selection_start_pos, 
619                                           selection_end_pos);
620       if (!str)
621          return;                /* Refuse */
622       length = strlen (str);
623     }
624   else                          /* CLIPBOARD */
625     {
626       if (!editable->clipboard_text)
627         return;                 /* Refuse */
628
629       str = editable->clipboard_text;
630       length = strlen (editable->clipboard_text);
631     }
632   
633   if (info == TARGET_STRING)
634     {
635       gtk_selection_data_set (selection_data,
636                               GDK_SELECTION_TYPE_STRING,
637                               8*sizeof(gchar), (guchar *)str, length);
638     }
639   else if ((info == TARGET_TEXT) || (info == TARGET_COMPOUND_TEXT))
640     {
641       guchar *text;
642       gchar c;
643       GdkAtom encoding;
644       gint format;
645       gint new_length;
646
647       c = str[length];
648       str[length] = '\0';
649       gdk_string_to_compound_text (str, &encoding, &format, &text, &new_length);
650       gtk_selection_data_set (selection_data, encoding, format, text, new_length);
651       gdk_free_compound_text (text);
652       str[length] = c;
653     }
654
655   if (str != editable->clipboard_text)
656     g_free (str);
657 }
658
659 static void
660 gtk_editable_selection_received  (GtkWidget         *widget,
661                                   GtkSelectionData  *selection_data,
662                                   guint              time)
663 {
664   GtkEditable *editable;
665   gint reselect;
666   gint old_pos;
667   gint tmp_pos;
668   enum {INVALID, STRING, CTEXT} type;
669
670   g_return_if_fail (widget != NULL);
671   g_return_if_fail (GTK_IS_EDITABLE (widget));
672
673   editable = GTK_EDITABLE (widget);
674
675   if (selection_data->type == GDK_TARGET_STRING)
676     type = STRING;
677   else if ((selection_data->type == gdk_atom_intern ("COMPOUND_TEXT", FALSE)) ||
678            (selection_data->type == gdk_atom_intern ("TEXT", FALSE)))
679     type = CTEXT;
680   else
681     type = INVALID;
682
683   if (type == INVALID || selection_data->length < 0)
684     {
685     /* avoid infinite loop */
686     if (selection_data->target != GDK_TARGET_STRING)
687       gtk_selection_convert (widget, selection_data->selection,
688                              GDK_TARGET_STRING, time);
689     return;
690   }
691
692   reselect = FALSE;
693
694   if ((editable->selection_start_pos != editable->selection_end_pos) && 
695       (!editable->has_selection || 
696        (selection_data->selection == clipboard_atom)))
697     {
698       reselect = TRUE;
699
700       /* Don't want to call gtk_editable_delete_selection here if we are going
701        * to reclaim the selection to avoid extra server traffic */
702       if (editable->has_selection)
703         {
704           gtk_editable_delete_text (editable,
705                                  MIN (editable->selection_start_pos, editable->selection_end_pos),
706                                  MAX (editable->selection_start_pos, editable->selection_end_pos));
707         }
708       else
709         gtk_editable_delete_selection (editable);
710     }
711
712   tmp_pos = old_pos = editable->current_pos;
713
714   switch (type)
715     {
716     case STRING:
717       selection_data->data[selection_data->length] = 0;
718       gtk_editable_insert_text (editable, (gchar *)selection_data->data,
719                                 strlen ((gchar *)selection_data->data), 
720                                 &tmp_pos);
721       editable->current_pos = tmp_pos;
722       break;
723     case CTEXT:
724       {
725         gchar **list;
726         gint count;
727         gint i;
728
729         count = gdk_text_property_to_text_list (selection_data->type,
730                                                 selection_data->format, 
731                                                 selection_data->data,
732                                                 selection_data->length,
733                                                 &list);
734         for (i=0; i<count; i++) 
735           {
736             gtk_editable_insert_text (editable, list[i], strlen (list[i]), &tmp_pos);
737             editable->current_pos = tmp_pos;
738           }
739         if (count > 0)
740           gdk_free_text_list (list);
741       }
742       break;
743     case INVALID:               /* quiet compiler */
744       break;
745     }
746
747   if (reselect)
748     gtk_editable_set_selection (editable, old_pos, editable->current_pos);
749 }
750
751 void
752 gtk_editable_delete_selection (GtkEditable *editable)
753 {
754   guint start;
755   guint end;
756
757   g_return_if_fail (editable != NULL);
758   g_return_if_fail (GTK_IS_EDITABLE (editable));
759
760   if (!editable->editable)
761     return;
762
763   start = editable->selection_start_pos;
764   end = editable->selection_end_pos;
765
766   editable->selection_start_pos = 0;
767   editable->selection_end_pos = 0;
768
769   if (start != end)
770     gtk_editable_delete_text (editable, MIN (start, end), MAX (start,end));
771
772   if (editable->has_selection)
773     {
774       editable->has_selection = FALSE;
775       if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == GTK_WIDGET (editable)->window)
776         gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
777     }
778 }
779
780 void
781 gtk_editable_claim_selection (GtkEditable *editable, 
782                               gboolean  claim, 
783                               guint32   time)
784 {
785   g_return_if_fail (editable != NULL);
786   g_return_if_fail (GTK_IS_EDITABLE (editable));
787   g_return_if_fail (GTK_WIDGET_REALIZED (editable));
788
789   editable->has_selection = FALSE;
790   
791   if (claim)
792     {
793       if (gtk_selection_owner_set (GTK_WIDGET(editable), GDK_SELECTION_PRIMARY, time))
794         editable->has_selection = TRUE;
795     }
796   else
797     {
798       if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == 
799           GTK_WIDGET(editable)->window)
800         gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, time);
801     }
802 }
803
804 void
805 gtk_editable_select_region (GtkEditable *editable,
806                             gint         start,
807                             gint         end)
808 {
809   g_return_if_fail (editable != NULL);
810   g_return_if_fail (GTK_IS_EDITABLE (editable));
811   
812   if (GTK_WIDGET_REALIZED (editable))
813     gtk_editable_claim_selection (editable, start != end, GDK_CURRENT_TIME);
814   
815   gtk_editable_set_selection (editable, start, end);
816 }
817
818 /* Get the timestamp of the current event. Actually, the only thing
819  * we really care about below is the key event
820  */
821 static guint32
822 gtk_editable_get_event_time (GtkEditable *editable)
823 {
824   GdkEvent *event;
825   guint32 tm = GDK_CURRENT_TIME;
826   
827   event = gtk_get_current_event();
828   
829   if (event)
830     switch (event->type)
831       {
832       case GDK_MOTION_NOTIFY:
833         tm = event->motion.time; break;
834       case GDK_BUTTON_PRESS:
835       case GDK_2BUTTON_PRESS:
836       case GDK_3BUTTON_PRESS:
837       case GDK_BUTTON_RELEASE:
838         tm = event->button.time; break;
839       case GDK_KEY_PRESS:
840       case GDK_KEY_RELEASE:
841         tm = event->key.time; break;
842       case GDK_ENTER_NOTIFY:
843       case GDK_LEAVE_NOTIFY:
844         tm = event->crossing.time; break;
845       case GDK_PROPERTY_NOTIFY:
846         tm = event->property.time; break;
847       case GDK_SELECTION_CLEAR:
848       case GDK_SELECTION_REQUEST:
849       case GDK_SELECTION_NOTIFY:
850         tm = event->selection.time; break;
851       case GDK_PROXIMITY_IN:
852       case GDK_PROXIMITY_OUT:
853         tm = event->proximity.time; break;
854       default:                  /* use current time */
855         break;
856       }
857   gdk_event_free(event);
858   
859   return tm;
860 }
861
862 void
863 gtk_editable_cut_clipboard (GtkEditable *editable)
864 {
865   g_return_if_fail (editable != NULL);
866   g_return_if_fail (GTK_IS_EDITABLE (editable));
867   
868   gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CUT_CLIPBOARD]);
869 }
870
871 void
872 gtk_editable_copy_clipboard (GtkEditable *editable)
873 {
874   g_return_if_fail (editable != NULL);
875   g_return_if_fail (GTK_IS_EDITABLE (editable));
876   
877   gtk_signal_emit (GTK_OBJECT (editable), editable_signals[COPY_CLIPBOARD]);
878 }
879
880 void
881 gtk_editable_paste_clipboard (GtkEditable *editable)
882 {
883   g_return_if_fail (editable != NULL);
884   g_return_if_fail (GTK_IS_EDITABLE (editable));
885   
886   gtk_signal_emit (GTK_OBJECT (editable), editable_signals[PASTE_CLIPBOARD]);
887 }
888
889 void
890 gtk_editable_set_editable (GtkEditable    *editable,
891                            gboolean        is_editable)
892 {
893   g_return_if_fail (editable != NULL);
894   g_return_if_fail (GTK_IS_EDITABLE (editable));
895   
896   gtk_signal_emit (GTK_OBJECT (editable), editable_signals[SET_EDITABLE], is_editable != FALSE);
897 }
898
899 static void
900 gtk_editable_real_set_editable (GtkEditable    *editable,
901                                 gboolean        is_editable)
902 {
903   g_return_if_fail (editable != NULL);
904   g_return_if_fail (GTK_IS_EDITABLE (editable));
905
906   editable->editable = is_editable != FALSE;
907   gtk_widget_queue_draw (GTK_WIDGET (editable));
908 }
909
910 static void
911 gtk_editable_real_cut_clipboard (GtkEditable *editable)
912 {
913   g_return_if_fail (editable != NULL);
914   g_return_if_fail (GTK_IS_EDITABLE (editable));
915   
916   gtk_editable_real_copy_clipboard (editable);
917   gtk_editable_delete_selection (editable);
918 }
919
920 static void
921 gtk_editable_real_copy_clipboard (GtkEditable *editable)
922 {
923   guint32 time;
924   gint selection_start_pos; 
925   gint selection_end_pos;
926
927   g_return_if_fail (editable != NULL);
928   g_return_if_fail (GTK_IS_EDITABLE (editable));
929   
930   time = gtk_editable_get_event_time (editable);
931   selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos);
932   selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos);
933  
934   if (selection_start_pos != selection_end_pos)
935     {
936       if (gtk_selection_owner_set (GTK_WIDGET (editable),
937                                    clipboard_atom,
938                                    time))
939         editable->clipboard_text = gtk_editable_get_public_chars (editable,
940                                                                   selection_start_pos,
941                                                                   selection_end_pos);
942     }
943 }
944
945 static void
946 gtk_editable_real_paste_clipboard (GtkEditable *editable)
947 {
948   guint32 time;
949
950   g_return_if_fail (editable != NULL);
951   g_return_if_fail (GTK_IS_EDITABLE (editable));
952   
953   time = gtk_editable_get_event_time (editable);
954   if (editable->editable)
955     gtk_selection_convert (GTK_WIDGET(editable), 
956                            clipboard_atom, 
957                            gdk_atom_intern ("COMPOUND_TEXT", FALSE), time);
958 }
959
960 void
961 gtk_editable_changed (GtkEditable *editable)
962 {
963   g_return_if_fail (editable != NULL);
964   g_return_if_fail (GTK_IS_EDITABLE (editable));
965   
966   gtk_signal_emit (GTK_OBJECT (editable), editable_signals[CHANGED]);
967 }
968
969 #if 0
970 static void
971 gtk_editable_parent_set (GtkWidget *widget, 
972                          GtkWidget *old_parent, 
973                          GtkWidget *editable)
974 {
975   GtkWidget *parent;
976
977   parent = old_parent;
978   while (parent)
979     {
980       gtk_signal_disconnect_by_func (GTK_OBJECT (parent),
981                                      GTK_SIGNAL_FUNC (gtk_editable_parent_set),
982                                      editable);
983       parent = parent->parent;
984     }
985
986   parent = widget->parent;
987   while (parent)
988     {
989       gtk_signal_connect (GTK_OBJECT (parent), "parent_set",
990                           GTK_SIGNAL_FUNC (gtk_editable_parent_set), 
991                           editable);
992       
993       parent = parent->parent;
994     }
995 }
996 #endif