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