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