]> Pileus Git - ~andy/gtk/blob - tests/testselection.c
Several portability fixes from Michael Callahan <callahan@xmission.com>
[~andy/gtk] / tests / testselection.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 Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <string.h>
20 #include "gtk.h"
21
22 typedef enum {
23   SEL_TYPE_NONE,
24   APPLE_PICT,
25   ATOM,
26   ATOM_PAIR,
27   BITMAP,
28   C_STRING,
29   COLORMAP,
30   COMPOUND_TEXT,
31   DRAWABLE,
32   INTEGER,
33   PIXEL,
34   PIXMAP,
35   SPAN,
36   STRING,
37   TEXT,
38   WINDOW,
39   LAST_SEL_TYPE
40 } SelType;
41
42 GdkAtom seltypes[LAST_SEL_TYPE];
43
44 typedef struct _Target {
45   gchar *target_name;
46   SelType type;
47   GdkAtom target;
48   gint format;
49   GtkSelectionFunction *handler;
50 } Target;
51
52 /* The following is a list of all the selection targets defined
53    in the ICCCM */
54
55 static Target targets[] = {
56   { "ADOBE_PORTABLE_DOCUMENT_FORMAT",       STRING,        0, 8,  NULL },
57   { "APPLE_PICT",                           APPLE_PICT,    0, 8,  NULL },
58   { "BACKGROUND",                           PIXEL,         0, 32, NULL },
59   { "BITMAP",                               BITMAP,        0, 32, NULL },
60   { "CHARACTER_POSITION",                   SPAN,          0, 32, NULL },
61   { "CLASS",                                TEXT,          0, 8,  NULL },
62   { "CLIENT_WINDOW",                        WINDOW,        0, 32, NULL },
63   { "COLORMAP",                             COLORMAP,      0, 32, NULL },
64   { "COLUMN_NUMBER",                        SPAN,          0, 32, NULL },
65   { "COMPOUND_TEXT",                        COMPOUND_TEXT, 0, 8,  NULL },
66   /*  { "DELETE", "NULL", 0, ?, NULL }, */
67   { "DRAWABLE",                             DRAWABLE,      0, 32, NULL },
68   { "ENCAPSULATED_POSTSCRIPT",              STRING,        0, 8,  NULL },
69   { "ENCAPSULATED_POSTSCRIPT_INTERCHANGE",  STRING,        0, 8,  NULL },
70   { "FILE_NAME",                            TEXT,          0, 8,  NULL },
71   { "FOREGROUND",                           PIXEL,         0, 32, NULL },
72   { "HOST_NAME",                            TEXT,          0, 8,  NULL },
73   /*  { "INSERT_PROPERTY", "NULL", 0, ? NULL }, */
74   /*  { "INSERT_SELECTION", "NULL", 0, ? NULL }, */
75   { "LENGTH",                               INTEGER,       0, 32, NULL },
76   { "LINE_NUMBER",                          SPAN,          0, 32, NULL },
77   { "LIST_LENGTH",                          INTEGER,       0, 32, NULL },
78   { "MODULE",                               TEXT,          0, 8,  NULL },
79   /*  { "MULTIPLE", "ATOM_PAIR", 0, 32, NULL }, */
80   { "NAME",                                 TEXT,          0, 8,  NULL },
81   { "ODIF",                                 TEXT,          0, 8,  NULL },
82   { "OWNER_OS",                             TEXT,          0, 8,  NULL },
83   { "PIXMAP",                               PIXMAP,        0, 32, NULL },
84   { "POSTSCRIPT",                           STRING,        0, 8,  NULL },
85   { "PROCEDURE",                            TEXT,          0, 8,  NULL },
86   { "PROCESS",                              INTEGER,       0, 32, NULL },
87   { "STRING",                               STRING,        0, 8,  NULL },
88   { "TARGETS",                              ATOM,          0, 32, NULL },
89   { "TASK",                                 INTEGER,       0, 32, NULL },
90   { "TEXT",                                 TEXT,          0, 8 , NULL },
91   { "TIMESTAMP",                            INTEGER,       0, 32, NULL },
92   { "USER",                                 TEXT,          0, 8,  NULL },
93 };
94
95 static int num_targets = sizeof(targets)/sizeof(Target);
96
97 static int have_selection = FALSE;
98
99 GtkWidget *selection_text;
100 GtkWidget *selection_button;
101 GString *selection_string = NULL;
102
103 static void
104 init_atoms ()
105 {
106   int i;
107
108   seltypes[SEL_TYPE_NONE] = GDK_NONE;
109   seltypes[APPLE_PICT] = gdk_atom_intern ("APPLE_PICT",FALSE);
110   seltypes[ATOM]       = gdk_atom_intern ("ATOM",FALSE);
111   seltypes[ATOM_PAIR]  = gdk_atom_intern ("ATOM_PAIR",FALSE);
112   seltypes[BITMAP]     = gdk_atom_intern ("BITMAP",FALSE);
113   seltypes[C_STRING]   = gdk_atom_intern ("C_STRING",FALSE);
114   seltypes[COLORMAP]   = gdk_atom_intern ("COLORMAP",FALSE);
115   seltypes[COMPOUND_TEXT] = gdk_atom_intern ("COMPOUND_TEXT",FALSE);
116   seltypes[DRAWABLE]   = gdk_atom_intern ("DRAWABLE",FALSE);
117   seltypes[INTEGER]    = gdk_atom_intern ("INTEGER",FALSE);
118   seltypes[PIXEL]      = gdk_atom_intern ("PIXEL",FALSE);
119   seltypes[PIXMAP]     = gdk_atom_intern ("PIXMAP",FALSE);
120   seltypes[SPAN]       = gdk_atom_intern ("SPAN",FALSE);
121   seltypes[STRING]     = gdk_atom_intern ("STRING",FALSE);
122   seltypes[TEXT]       = gdk_atom_intern ("TEXT",FALSE);
123   seltypes[WINDOW]     = gdk_atom_intern ("WINDOW",FALSE);
124
125   for (i=0; i<num_targets; i++)
126     targets[i].target = gdk_atom_intern (targets[i].target_name, FALSE);
127 }
128
129 void
130 selection_toggled (GtkWidget *widget)
131 {
132   if (GTK_TOGGLE_BUTTON(widget)->active)
133     {
134       have_selection = gtk_selection_owner_set (widget,
135                                                 GDK_SELECTION_PRIMARY,
136                                                 GDK_CURRENT_TIME);
137       if (!have_selection)
138         gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
139     }
140   else
141     {
142       if (have_selection)
143         {
144           if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
145             gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
146                                      GDK_CURRENT_TIME);
147           have_selection = FALSE;
148         }
149     }
150 }
151
152 void
153 selection_handle (GtkWidget *widget, 
154                   GtkSelectionData *selection_data, gpointer data)
155 {
156   guchar *buffer;
157   gint len;
158
159   if (!selection_string)
160     {
161       buffer = NULL;
162       len = 0;
163     }      
164   else
165     {
166       buffer = selection_string->str;
167       len = selection_string->len;
168     }
169   
170   gtk_selection_data_set (selection_data,
171                           selection_data->target == seltypes[COMPOUND_TEXT] ?
172                                   seltypes[COMPOUND_TEXT] : seltypes[STRING],
173                           8, buffer, len);
174 }
175
176 gint
177 selection_clear (GtkWidget *widget, GdkEventSelection *event)
178 {
179   have_selection = FALSE;
180   gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
181
182   return TRUE;
183 }
184
185 gchar *
186 stringify_atom (guchar *data, gint *position)
187 {
188   gchar *str = gdk_atom_name (*(GdkAtom *)(data+*position));
189   *position += sizeof(GdkAtom);
190     
191   return str;
192 }
193
194 gchar *
195 stringify_text (guchar *data, gint *position)
196 {
197   gchar *str = g_strdup ((gchar *)(data+*position));
198   *position += strlen (str) + 1;
199     
200   return str;
201 }
202
203 gchar *
204 stringify_xid (guchar *data, gint *position)
205 {
206   gchar buffer[20];
207   gchar *str;
208
209   sprintf(buffer,"0x%x",*(guint32 *)(data+*position));
210   str = g_strdup (buffer);
211
212   *position += sizeof(guint32);
213     
214   return str;
215 }
216
217 gchar *
218 stringify_integer (guchar *data, gint *position)
219 {
220   gchar buffer[20];
221   gchar *str;
222
223   sprintf(buffer,"%d",*(int *)(data+*position));
224   str = g_strdup (buffer);
225
226   *position += sizeof(int);
227     
228   return str;
229 }
230
231 gchar *
232 stringify_span (guchar *data, gint *position)
233 {
234   gchar buffer[42];
235   gchar *str;
236
237   sprintf(buffer,"%d - %d",((int *)(data+*position))[0],
238           ((int *)(data+*position))[1]);
239   str = g_strdup (buffer);
240
241   *position += 2*sizeof(int);
242     
243   return str;
244 }
245
246 void
247 selection_received (GtkWidget *widget, GtkSelectionData *data)
248 {
249   int position;
250   int i;
251   SelType seltype;
252   char *str;
253   
254   if (data->length < 0)
255     {
256       g_print("Error retrieving selection\n");
257       return;
258     }
259
260   seltype = SEL_TYPE_NONE;
261   for (i=0; i<LAST_SEL_TYPE; i++)
262     {
263       if (seltypes[i] == data->type)
264         {
265           seltype = i;
266           break;
267         }
268     }
269
270   if (seltype == SEL_TYPE_NONE)
271     {
272       char *name = gdk_atom_name (data->type);
273       g_print("Don't know how to handle type: %s (%ld)\n",
274               name?name:"<unknown>",
275               data->type);
276       return;
277     }
278
279   if (selection_string != NULL)
280     g_string_free (selection_string, TRUE);
281
282   selection_string = g_string_new (NULL);
283
284   gtk_text_freeze (GTK_TEXT (selection_text));
285   gtk_text_set_point (GTK_TEXT (selection_text), 0);
286   gtk_text_forward_delete (GTK_TEXT (selection_text), 
287                            gtk_text_get_length (GTK_TEXT (selection_text)));
288
289   position = 0;
290   while (position < data->length)
291     {
292       switch (seltype)
293         {
294         case ATOM:
295           str = stringify_atom (data->data, &position);
296           break;
297         case COMPOUND_TEXT:
298         case STRING:
299         case TEXT:
300           str = stringify_text (data->data, &position);
301           break;
302         case BITMAP:
303         case DRAWABLE:
304         case PIXMAP:
305         case WINDOW:
306         case COLORMAP:
307           str = stringify_xid (data->data, &position);
308           break;
309         case INTEGER:
310         case PIXEL:
311           str = stringify_integer (data->data, &position);
312           break;
313         case SPAN:
314           str = stringify_span (data->data, &position);
315           break;
316         default:
317           {
318             char *name = gdk_atom_name (data->type);
319             g_print("Can't convert type %s (%ld) to string\n",
320                     name?name:"<unknown>",
321                     data->type);
322             position = data->length;
323             continue;
324           }
325         }
326       gtk_text_insert (GTK_TEXT (selection_text), NULL, 
327                        &selection_text->style->black, 
328                        NULL, str, -1);
329       gtk_text_insert (GTK_TEXT (selection_text), NULL, 
330                        &selection_text->style->black, 
331                        NULL, "\n", -1);
332       g_string_append (selection_string, str);
333       g_free (str);
334     }
335   gtk_text_thaw (GTK_TEXT (selection_text));
336 }
337
338 void
339 paste (GtkWidget *widget, GtkWidget *entry)
340 {
341   char *name;
342   GdkAtom atom;
343
344   name = gtk_entry_get_text (GTK_ENTRY(entry));
345   atom = gdk_atom_intern (name, FALSE);
346
347   if (atom == GDK_NONE)
348     {
349       g_print("Could not create atom: \"%s\"\n",name);
350       return;
351     }
352
353   gtk_selection_convert (selection_button, GDK_SELECTION_PRIMARY, atom, 
354                          GDK_CURRENT_TIME);
355 }
356
357 void
358 quit ()
359 {
360   gtk_exit (0);
361 }
362
363 int
364 main (int argc, char *argv[])
365 {
366   GtkWidget *dialog;
367   GtkWidget *button;
368   GtkWidget *table;
369   GtkWidget *label;
370   GtkWidget *entry;
371   GtkWidget *hscrollbar;
372   GtkWidget *vscrollbar;
373   GtkWidget *hbox;
374   
375   gtk_init (&argc, &argv);
376
377   init_atoms();
378
379   dialog = gtk_dialog_new ();
380   gtk_widget_set_name (dialog, "Test Input");
381   gtk_container_border_width (GTK_CONTAINER(dialog), 0);
382
383   gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
384                       GTK_SIGNAL_FUNC (quit), NULL);
385
386   table = gtk_table_new (4, 2, FALSE);
387   gtk_container_border_width (GTK_CONTAINER(table), 10);
388
389   gtk_table_set_row_spacing (GTK_TABLE (table), 0, 5);
390   gtk_table_set_row_spacing (GTK_TABLE (table), 1, 2);
391   gtk_table_set_row_spacing (GTK_TABLE (table), 2, 2);
392   gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
393   gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->vbox), 
394                       table, TRUE, TRUE, 0);
395   gtk_widget_show (table);
396   
397   selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
398   gtk_table_attach (GTK_TABLE (table), selection_button, 0, 2, 0, 1,
399                     GTK_EXPAND | GTK_FILL, 0, 0, 0);
400   gtk_widget_show (selection_button);
401
402   gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
403                       GTK_SIGNAL_FUNC (selection_toggled), NULL);
404   gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
405                       GTK_SIGNAL_FUNC (selection_clear), NULL);
406   gtk_signal_connect (GTK_OBJECT(selection_button), "selection_received",
407                       GTK_SIGNAL_FUNC (selection_received), NULL);
408
409   gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
410                              seltypes[STRING], selection_handle, NULL, NULL);
411
412   gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
413                              seltypes[TEXT], selection_handle, NULL, NULL);
414
415   gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
416                              seltypes[COMPOUND_TEXT],
417                              selection_handle, NULL, NULL);
418
419   selection_text = gtk_text_new (NULL, NULL);
420   gtk_table_attach_defaults (GTK_TABLE (table), selection_text, 0, 1, 1, 2);
421   gtk_widget_show (selection_text);
422   
423   hscrollbar = gtk_hscrollbar_new (GTK_TEXT (selection_text)->hadj);
424   gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 2, 3,
425                     GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
426   gtk_widget_show (hscrollbar);
427   
428   vscrollbar = gtk_vscrollbar_new (GTK_TEXT (selection_text)->vadj);
429   gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 1, 2,
430                     GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
431   gtk_widget_show (vscrollbar);
432
433   hbox = gtk_hbox_new (FALSE, 2);
434   gtk_table_attach (GTK_TABLE (table), hbox, 0, 2, 3, 4,
435                     GTK_EXPAND | GTK_FILL, 0, 0, 0);
436   gtk_widget_show (hbox);
437
438   label = gtk_label_new ("Target:");
439   gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0);
440   gtk_widget_show (label);
441
442   entry = gtk_entry_new ();
443   gtk_box_pack_start (GTK_BOX(hbox), entry, TRUE, TRUE, 0);
444   gtk_widget_show (entry);
445
446   /* .. And create some buttons */
447   button = gtk_button_new_with_label ("Paste");
448   gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area), 
449                       button, TRUE, TRUE, 0);
450   gtk_signal_connect (GTK_OBJECT (button), "clicked",
451                       GTK_SIGNAL_FUNC (paste), entry);
452   gtk_widget_show (button);
453
454   button = gtk_button_new_with_label ("Quit");
455   gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area), 
456                       button, TRUE, TRUE, 0);
457
458   gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
459                              GTK_SIGNAL_FUNC (gtk_widget_destroy), 
460                              GTK_OBJECT (dialog));
461   gtk_widget_show (button);
462
463   gtk_widget_show (dialog);
464
465   gtk_main ();
466
467   return 0;
468 }