]> Pileus Git - ~andy/gtk/blob - tests/testwindows.c
Merge branch 'client-side-windows'
[~andy/gtk] / tests / testwindows.c
1 #include <gtk/gtk.h>
2 #ifdef GDK_WINDOWING_X11
3 #include <X11/Xlib.h>
4 #endif
5
6 static GtkWidget *darea;
7 static GtkTreeStore *window_store = NULL;
8 static GtkWidget *treeview;
9
10 static void update_store (void);
11
12 static GtkWidget *main_window;
13
14 static gboolean
15 window_has_impl (GdkWindow *window)
16 {
17   GdkWindowObject *w;
18   w = (GdkWindowObject *)window;
19   return w->parent == NULL || w->parent->impl != w->impl;
20 }
21
22 GdkWindow *
23 create_window (GdkWindow *parent,
24                int x, int y, int w, int h,
25                GdkColor *color)
26 {
27   GdkWindowAttr attributes;
28   gint attributes_mask;
29   GdkWindow *window;
30   GdkColor *bg;
31
32   attributes.x = x;
33   attributes.y = y;
34   attributes.width = w;
35   attributes.height = h;
36   attributes.window_type = GDK_WINDOW_CHILD;
37   attributes.event_mask = GDK_STRUCTURE_MASK
38                         | GDK_BUTTON_MOTION_MASK
39                         | GDK_BUTTON_PRESS_MASK
40                         | GDK_BUTTON_RELEASE_MASK
41                         | GDK_EXPOSURE_MASK
42                         | GDK_ENTER_NOTIFY_MASK
43                         | GDK_LEAVE_NOTIFY_MASK;
44   attributes.wclass = GDK_INPUT_OUTPUT;
45       
46   attributes_mask = GDK_WA_X | GDK_WA_Y;
47       
48   window = gdk_window_new (parent, &attributes, attributes_mask);
49   gdk_window_set_user_data (window, darea);
50
51   bg = g_new (GdkColor, 1);
52   if (color)
53     *bg = *color;
54   else
55     {
56       bg->red = g_random_int_range (0, 0xffff);
57       bg->blue = g_random_int_range (0, 0xffff);
58       bg->green = g_random_int_range (0, 0xffff);;
59     }
60   
61   gdk_rgb_find_color (gtk_widget_get_colormap (darea), bg);
62   gdk_window_set_background (window, bg);
63   g_object_set_data_full (G_OBJECT (window), "color", bg, g_free);
64   
65   gdk_window_show (window);
66   
67   return window;
68 }
69
70 static void
71 add_window_cb (GtkTreeModel      *model,
72                GtkTreePath       *path,
73                GtkTreeIter       *iter,
74                gpointer           data)
75 {
76   GList **selected = data;
77   GdkWindow *window;
78
79   gtk_tree_model_get (GTK_TREE_MODEL (window_store),
80                       iter,
81                       0, &window,
82                       -1);
83
84   *selected = g_list_prepend (*selected, window);
85 }
86
87 static GList *
88 get_selected_windows (void)
89 {
90   GtkTreeSelection *sel;
91   GList *selected;
92
93   sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
94
95   selected = NULL;
96   gtk_tree_selection_selected_foreach (sel, add_window_cb, &selected);
97   
98   return selected;
99 }
100
101 static gboolean
102 find_window_helper (GtkTreeModel *model,
103                     GdkWindow *window,
104                     GtkTreeIter *iter,
105                     GtkTreeIter *selected_iter)
106 {
107   GtkTreeIter child_iter;
108   GdkWindow *w;
109
110   do
111     {
112       gtk_tree_model_get (model, iter,
113                           0, &w,
114                           -1);
115       if (w == window)
116         {
117           *selected_iter = *iter;
118           return TRUE;
119         }
120       
121       if (gtk_tree_model_iter_children (model,
122                                         &child_iter,
123                                         iter))
124         {
125           if (find_window_helper (model, window, &child_iter, selected_iter))
126             return TRUE;
127         }
128     } while (gtk_tree_model_iter_next (model, iter));
129
130   return FALSE;
131 }
132
133 static gboolean
134 find_window (GdkWindow *window,
135              GtkTreeIter *window_iter)
136 {
137   GtkTreeIter iter;
138
139   if (!gtk_tree_model_get_iter_first  (GTK_TREE_MODEL (window_store), &iter))
140     return FALSE;
141
142   return find_window_helper (GTK_TREE_MODEL (window_store),
143                              window,
144                              &iter,
145                              window_iter);
146 }
147
148 static void
149 toggle_selection_window (GdkWindow *window)
150 {
151   GtkTreeSelection *selection;
152   GtkTreeIter iter;
153
154   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
155
156   if (window != NULL &&
157       find_window (window, &iter))
158     {
159       if (gtk_tree_selection_iter_is_selected (selection, &iter))
160         gtk_tree_selection_unselect_iter (selection,  &iter);
161       else
162         gtk_tree_selection_select_iter (selection,  &iter);
163     }
164 }
165
166 static void
167 unselect_windows (void)
168 {
169   GtkTreeSelection *selection;
170
171   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
172   
173   gtk_tree_selection_unselect_all (selection);
174 }
175
176
177 static void
178 select_window (GdkWindow *window)
179 {
180   GtkTreeSelection *selection;
181   GtkTreeIter iter;
182
183   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
184
185   if (window != NULL &&
186       find_window (window, &iter))
187     gtk_tree_selection_select_iter (selection,  &iter);
188 }
189
190 static void
191 select_windows (GList *windows)
192 {
193   GtkTreeSelection *selection;
194   GtkTreeIter iter;
195   GList *l;
196
197   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
198   gtk_tree_selection_unselect_all (selection);
199   
200   for (l = windows; l != NULL; l = l->next)
201     {
202       if (find_window (l->data, &iter))
203         gtk_tree_selection_select_iter (selection,  &iter);
204     }
205 }
206
207 static void
208 add_window_clicked (GtkWidget *button, 
209                     gpointer data)
210 {
211   GdkWindow *parent;
212   GList *l;
213
214   l = get_selected_windows ();
215   if (l != NULL)
216     parent = l->data;
217   else
218     parent = darea->window;
219
220   g_list_free (l);
221   
222   create_window (parent, 10, 10, 100, 100, NULL);
223   update_store ();
224 }
225
226 static void
227 draw_drawable_clicked (GtkWidget *button, 
228                        gpointer data)
229 {
230   GdkGC *gc;
231   gc = gdk_gc_new (darea->window);
232   gdk_draw_drawable (darea->window,
233                      gc,
234                      darea->window,
235                      -15, -15,
236                      40, 70,
237                      100, 100);
238   g_object_unref (gc);
239 }
240
241
242 static void
243 remove_window_clicked (GtkWidget *button, 
244                        gpointer data)
245 {
246   GList *l, *selected;
247
248   selected = get_selected_windows ();
249
250   for (l = selected; l != NULL; l = l->next)
251     gdk_window_destroy (l->data);
252
253   g_list_free (selected);
254
255   update_store ();
256 }
257
258 static void save_children (GString *s, GdkWindow *window);
259
260 static void
261 save_window (GString *s,
262              GdkWindow *window)
263 {
264   gint x, y, w, h;
265   GdkColor *color;
266
267   gdk_window_get_position (window, &x, &y);
268   gdk_drawable_get_size (GDK_DRAWABLE (window), &w, &h);
269   color = g_object_get_data (G_OBJECT (window), "color");
270   
271   g_string_append_printf (s, "%d,%d %dx%d (%d,%d,%d) %d %d\n",
272                           x, y, w, h,
273                           color->red, color->green, color->blue,
274                           window_has_impl (window),
275                           g_list_length (gdk_window_peek_children (window)));
276
277   save_children (s, window);
278 }
279
280
281 static void
282 save_children (GString *s,
283                GdkWindow *window)
284 {
285   GList *l;
286   GdkWindow *child;
287
288   for (l = g_list_reverse (gdk_window_peek_children (window));
289        l != NULL;
290        l = l->next)
291     {
292       child = l->data;
293
294       save_window (s, child);
295     }
296 }
297
298
299 static void
300 save_clicked (GtkWidget *button, 
301               gpointer data)
302 {
303   GString *s;
304   GtkWidget *dialog;
305   GFile *file;
306
307   s = g_string_new ("");
308
309   save_children (s, darea->window);
310
311   dialog = gtk_file_chooser_dialog_new ("Filename for window data",
312                                         NULL,
313                                         GTK_FILE_CHOOSER_ACTION_SAVE,
314                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
315                                         GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
316                                         NULL);
317   
318   gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
319   
320   if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
321     {
322       file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
323
324       g_file_replace_contents (file,
325                                s->str, s->len,
326                                NULL, FALSE,
327                                0, NULL, NULL, NULL);
328
329       g_object_unref (file);
330     }
331
332   gtk_widget_destroy (dialog);
333   g_string_free (s, TRUE);
334 }
335
336 static void
337 destroy_children (GdkWindow *window)
338 {
339   GList *l;
340   GdkWindow *child;
341
342   for (l = gdk_window_peek_children (window);
343        l != NULL;
344        l = l->next)
345     {
346       child = l->data;
347       
348       destroy_children (child);
349       gdk_window_destroy (child);
350     }
351 }
352
353 static char **
354 parse_window (GdkWindow *parent, char **lines)
355 {
356   int x, y, w, h, r, g, b, native, n_children;
357   GdkWindow *window;
358   GdkColor color;
359   int i;
360
361   if (*lines == NULL)
362     return lines;
363   
364   if (sscanf(*lines, "%d,%d %dx%d (%d,%d,%d) %d %d",
365              &x, &y, &w, &h, &r, &g, &b, &native, &n_children) == 9)
366     {
367       lines++;
368       color.red = r;
369       color.green = g;
370       color.blue = b;
371       window = create_window (parent, x, y, w, h, &color);
372       if (native)
373         gdk_window_ensure_native (window);
374       
375       for (i = 0; i < n_children; i++)
376         lines = parse_window (window, lines);
377     }
378   else
379     lines++;
380   
381   return lines;
382 }
383   
384 static void
385 load_file (GFile *file)
386 {
387   char *data;
388   char **lines, **l;
389   
390   if (g_file_load_contents (file, NULL, &data, NULL, NULL, NULL))
391     {
392       destroy_children (darea->window);
393
394       lines = g_strsplit (data, "\n", -1);
395
396       l = lines;
397       while (*l != NULL)
398         l = parse_window (darea->window, l);
399     }
400
401   update_store ();
402 }
403
404 static void
405 move_window_clicked (GtkWidget *button, 
406                      gpointer data)
407 {
408   GdkWindow *window;
409   GtkDirectionType direction;
410   GList *selected, *l;
411   gint x, y;
412
413   direction = GPOINTER_TO_INT (data);
414     
415   selected = get_selected_windows ();
416
417   for (l = selected; l != NULL; l = l->next)
418     {
419       window = l->data;
420       
421       gdk_window_get_position (window, &x, &y);
422       
423       switch (direction) {
424       case GTK_DIR_UP:
425         y -= 10;
426         break;
427       case GTK_DIR_DOWN:
428         y += 10;
429         break;
430       case GTK_DIR_LEFT:
431         x -= 10;
432         break;
433       case GTK_DIR_RIGHT:
434         x += 10;
435         break;
436       default:
437         break;
438       }
439
440       gdk_window_move (window, x, y);
441     }
442
443   g_list_free (selected);
444 }
445
446 static void
447 manual_clicked (GtkWidget *button, 
448                 gpointer data)
449 {
450   GdkWindow *window;
451   GList *selected, *l;
452   int x, y, w, h;
453   GtkWidget *dialog, *table, *label, *xspin, *yspin, *wspin, *hspin;
454   
455
456   selected = get_selected_windows ();
457
458   if (selected == NULL)
459     return;
460
461   gdk_window_get_position (selected->data, &x, &y);
462   gdk_drawable_get_size (selected->data, &w, &h);
463
464   dialog = gtk_dialog_new_with_buttons ("Select new position and size",
465                                         GTK_WINDOW (main_window),
466                                         GTK_DIALOG_MODAL,
467                                         GTK_STOCK_OK, GTK_RESPONSE_OK,
468                                         NULL);
469   
470
471   table = gtk_table_new (2, 4, TRUE);
472   gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
473                       table,
474                       FALSE, FALSE,
475                       2);
476
477   
478   label = gtk_label_new ("x:");
479   gtk_table_attach_defaults (GTK_TABLE (table),
480                              label,
481                              0, 1,
482                              0, 1);
483   label = gtk_label_new ("y:");
484   gtk_table_attach_defaults (GTK_TABLE (table),
485                              label,
486                              0, 1,
487                              1, 2);
488   label = gtk_label_new ("width:");
489   gtk_table_attach_defaults (GTK_TABLE (table),
490                              label,
491                              0, 1,
492                              2, 3);
493   label = gtk_label_new ("height:");
494   gtk_table_attach_defaults (GTK_TABLE (table),
495                              label,
496                              0, 1,
497                              3, 4);
498
499   xspin = gtk_spin_button_new_with_range (G_MININT, G_MAXINT, 1);
500   gtk_spin_button_set_value (GTK_SPIN_BUTTON (xspin), x);
501   gtk_table_attach_defaults (GTK_TABLE (table),
502                              xspin,
503                              1, 2,
504                              0, 1);
505   yspin = gtk_spin_button_new_with_range (G_MININT, G_MAXINT, 1);
506   gtk_spin_button_set_value (GTK_SPIN_BUTTON (yspin), y);
507   gtk_table_attach_defaults (GTK_TABLE (table),
508                              yspin,
509                              1, 2,
510                              1, 2);
511   wspin = gtk_spin_button_new_with_range (G_MININT, G_MAXINT, 1);
512   gtk_spin_button_set_value (GTK_SPIN_BUTTON (wspin), w);
513   gtk_table_attach_defaults (GTK_TABLE (table),
514                              wspin,
515                              1, 2,
516                              2, 3);
517   hspin = gtk_spin_button_new_with_range (G_MININT, G_MAXINT, 1);
518   gtk_spin_button_set_value (GTK_SPIN_BUTTON (hspin), h);
519   gtk_table_attach_defaults (GTK_TABLE (table),
520                              hspin,
521                              1, 2,
522                              3, 4);
523   
524   gtk_widget_show_all (dialog);
525   
526   gtk_dialog_run (GTK_DIALOG (dialog));
527
528   x = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (xspin));
529   y = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (yspin));
530   w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (wspin));
531   h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (hspin));
532
533   gtk_widget_destroy (dialog);
534   
535   for (l = selected; l != NULL; l = l->next)
536     {
537       window = l->data;
538       
539       gdk_window_move_resize (window, x, y, w, h);
540     }
541
542   g_list_free (selected);
543 }
544
545 static void
546 scroll_window_clicked (GtkWidget *button, 
547                        gpointer data)
548 {
549   GdkWindow *window;
550   GtkDirectionType direction;
551   GList *selected, *l;
552   gint dx, dy;
553
554   direction = GPOINTER_TO_INT (data);
555     
556   selected = get_selected_windows ();
557
558   dx = 0; dy = 0;
559   switch (direction) {
560   case GTK_DIR_UP:
561     dy = 10;
562     break;
563   case GTK_DIR_DOWN:
564     dy = -10;
565     break;
566   case GTK_DIR_LEFT:
567     dx = 10;
568     break;
569   case GTK_DIR_RIGHT:
570     dx = -10;
571     break;
572   default:
573     break;
574   }
575   
576   for (l = selected; l != NULL; l = l->next)
577     {
578       window = l->data;
579
580       gdk_window_scroll (window, dx, dy);
581     }
582
583   g_list_free (selected);
584 }
585
586
587 static void
588 raise_window_clicked (GtkWidget *button, 
589                       gpointer data)
590 {
591   GList *selected, *l;
592   GdkWindow *window;
593     
594   selected = get_selected_windows ();
595
596   for (l = selected; l != NULL; l = l->next)
597     {
598       window = l->data;
599       
600       gdk_window_raise (window);
601     }
602
603   g_list_free (selected);
604   
605   update_store ();
606 }
607
608 static void
609 lower_window_clicked (GtkWidget *button, 
610                       gpointer data)
611 {
612   GList *selected, *l;
613   GdkWindow *window;
614     
615   selected = get_selected_windows ();
616
617   for (l = selected; l != NULL; l = l->next)
618     {
619       window = l->data;
620       
621       gdk_window_lower (window);
622     }
623
624   g_list_free (selected);
625   
626   update_store ();
627 }
628
629
630 static void
631 smaller_window_clicked (GtkWidget *button, 
632                         gpointer data)
633 {
634   GList *selected, *l;
635   GdkWindow *window;
636   int w, h;
637
638   selected = get_selected_windows ();
639
640   for (l = selected; l != NULL; l = l->next)
641     {
642       window = l->data;
643       
644       gdk_drawable_get_size (GDK_DRAWABLE (window), &w, &h);
645       
646       w -= 10;
647       h -= 10;
648       if (w < 1)
649         w = 1;
650       if (h < 1)
651         h = 1;
652       
653       gdk_window_resize (window, w, h);
654     }
655
656   g_list_free (selected);
657 }
658
659 static void
660 larger_window_clicked (GtkWidget *button, 
661                         gpointer data)
662 {
663   GList *selected, *l;
664   GdkWindow *window;
665   int w, h;
666
667   selected = get_selected_windows ();
668
669   for (l = selected; l != NULL; l = l->next)
670     {
671       window = l->data;
672       
673       gdk_drawable_get_size (GDK_DRAWABLE (window), &w, &h);
674       
675       w += 10;
676       h += 10;
677       
678       gdk_window_resize (window, w, h);
679     }
680
681   g_list_free (selected);
682 }
683
684 static void
685 native_window_clicked (GtkWidget *button, 
686                         gpointer data)
687 {
688   GList *selected, *l;
689   GdkWindow *window;
690
691   selected = get_selected_windows ();
692
693   for (l = selected; l != NULL; l = l->next)
694     {
695       window = l->data;
696       
697       gdk_window_ensure_native (window);
698     }
699   
700   g_list_free (selected);
701   
702   update_store ();
703 }
704
705 static gboolean
706 darea_button_release_event (GtkWidget *widget,
707                             GdkEventButton *event)
708 {
709   if ((event->state & GDK_CONTROL_MASK) != 0)
710     {
711       toggle_selection_window (event->window);
712     }
713   else
714     {
715       unselect_windows ();
716       select_window (event->window);
717     }
718     
719   return TRUE;
720 }
721
722 static void
723 render_window_cell (GtkTreeViewColumn *tree_column,
724                     GtkCellRenderer   *cell,
725                     GtkTreeModel      *tree_model,
726                     GtkTreeIter       *iter,
727                     gpointer           data)
728 {
729   GdkWindow *window;
730   char *name;
731
732   gtk_tree_model_get (GTK_TREE_MODEL (window_store),
733                       iter,
734                       0, &window,
735                       -1);
736
737   if (window_has_impl (window))
738       name = g_strdup_printf ("%p (native)", window);
739   else
740       name = g_strdup_printf ("%p", window);
741   g_object_set (cell,
742                 "text", name,
743                 "background-gdk", &((GdkWindowObject *)window)->bg_color,
744                 NULL);  
745 }
746
747 static void
748 add_children (GtkTreeStore *store,
749               GdkWindow *window,
750               GtkTreeIter *window_iter)
751 {
752   GList *l;
753   GtkTreeIter child_iter;
754
755   for (l = gdk_window_peek_children (window);
756        l != NULL;
757        l = l->next)
758     {
759       gtk_tree_store_append (store, &child_iter, window_iter);
760       gtk_tree_store_set (store, &child_iter,
761                           0, l->data,
762                           -1);
763
764       add_children (store, l->data, &child_iter);
765     }
766 }
767
768 static void
769 update_store (void)
770 {
771   GList *selected;
772
773   selected = get_selected_windows ();
774
775   gtk_tree_store_clear (window_store);
776
777   add_children (window_store, darea->window, NULL);
778   gtk_tree_view_expand_all (GTK_TREE_VIEW (treeview));
779
780   select_windows (selected);
781   g_list_free (selected);
782 }
783
784
785 int
786 main (int argc, char **argv)
787 {
788   GtkWidget *window, *vbox, *hbox, *frame;
789   GtkWidget *button, *scrolled, *table;
790   GtkTreeViewColumn *column;
791   GtkCellRenderer *renderer;
792   GdkColor black = {0};
793   GFile *file;
794   
795   gtk_init (&argc, &argv);
796
797   main_window = window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
798   gtk_container_set_border_width (GTK_CONTAINER (window), 0);
799
800   g_signal_connect (G_OBJECT (window), "delete-event", gtk_main_quit, NULL);
801
802   hbox = gtk_hbox_new (FALSE, 5);
803   gtk_container_add (GTK_CONTAINER (window), hbox);
804   gtk_widget_show (hbox);
805
806   frame = gtk_frame_new ("GdkWindows");
807   gtk_box_pack_start (GTK_BOX (hbox),
808                       frame,
809                       FALSE, FALSE,
810                       5);
811   gtk_widget_show (frame);
812
813   darea =  gtk_drawing_area_new ();
814   /*gtk_widget_set_double_buffered (darea, FALSE);*/
815   gtk_widget_add_events (darea, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
816   gtk_widget_set_size_request (darea, 500, 500);
817   g_signal_connect (darea, "button_release_event", 
818                     G_CALLBACK (darea_button_release_event), 
819                     NULL);
820
821   
822   gtk_container_add (GTK_CONTAINER (frame), darea);
823   gtk_widget_realize (darea);
824   gtk_widget_show (darea);
825   gtk_widget_modify_bg (darea, GTK_STATE_NORMAL,
826                         &black);
827                         
828   
829   vbox = gtk_vbox_new (FALSE, 5);
830   gtk_box_pack_start (GTK_BOX (hbox),
831                       vbox,
832                       FALSE, FALSE,
833                       5);
834   gtk_widget_show (vbox);
835
836   window_store = gtk_tree_store_new (1, GDK_TYPE_WINDOW);
837   
838   treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (window_store));
839   gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
840                                GTK_SELECTION_MULTIPLE);
841   column = gtk_tree_view_column_new ();
842   gtk_tree_view_column_set_title (column, "Window");
843   renderer = gtk_cell_renderer_text_new ();
844   gtk_tree_view_column_pack_start (column, renderer, TRUE);
845   gtk_tree_view_column_set_cell_data_func (column,
846                                            renderer,
847                                            render_window_cell,
848                                            NULL, NULL);
849
850   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
851
852
853   scrolled = gtk_scrolled_window_new (NULL, NULL);
854   gtk_widget_set_size_request (scrolled, 200, 400);
855   gtk_container_add (GTK_CONTAINER (scrolled), treeview);
856   gtk_box_pack_start (GTK_BOX (vbox),
857                       scrolled,
858                       FALSE, FALSE,
859                       5);
860   gtk_widget_show (scrolled);
861   gtk_widget_show (treeview);
862   
863   table = gtk_table_new (4, 4, TRUE);
864   gtk_box_pack_start (GTK_BOX (vbox),
865                       table,
866                       FALSE, FALSE,
867                       2);
868   gtk_widget_show (table);
869
870   button = gtk_button_new ();
871   gtk_button_set_image (GTK_BUTTON (button),
872                         gtk_image_new_from_stock (GTK_STOCK_GO_BACK,
873                                                   GTK_ICON_SIZE_BUTTON));
874   g_signal_connect (button, "clicked", 
875                     G_CALLBACK (move_window_clicked), 
876                     GINT_TO_POINTER (GTK_DIR_LEFT));
877   gtk_table_attach_defaults (GTK_TABLE (table),
878                              button,
879                              0, 1,
880                              1, 2);
881   gtk_widget_show (button);
882
883   button = gtk_button_new ();
884   gtk_button_set_image (GTK_BUTTON (button),
885                         gtk_image_new_from_stock (GTK_STOCK_GO_UP,
886                                                   GTK_ICON_SIZE_BUTTON));
887   g_signal_connect (button, "clicked", 
888                     G_CALLBACK (move_window_clicked), 
889                     GINT_TO_POINTER (GTK_DIR_UP));
890   gtk_table_attach_defaults (GTK_TABLE (table),
891                              button,
892                              1, 2,
893                              0, 1);
894   gtk_widget_show (button);
895
896   button = gtk_button_new ();
897   gtk_button_set_image (GTK_BUTTON (button),
898                         gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD,
899                                                   GTK_ICON_SIZE_BUTTON));
900   g_signal_connect (button, "clicked", 
901                     G_CALLBACK (move_window_clicked), 
902                     GINT_TO_POINTER (GTK_DIR_RIGHT));
903   gtk_table_attach_defaults (GTK_TABLE (table),
904                              button,
905                              2, 3,
906                              1, 2);
907   gtk_widget_show (button);
908
909   button = gtk_button_new ();
910   gtk_button_set_image (GTK_BUTTON (button),
911                         gtk_image_new_from_stock (GTK_STOCK_GO_DOWN,
912                                                   GTK_ICON_SIZE_BUTTON));
913   g_signal_connect (button, "clicked", 
914                     G_CALLBACK (move_window_clicked), 
915                     GINT_TO_POINTER (GTK_DIR_DOWN));
916   gtk_table_attach_defaults (GTK_TABLE (table),
917                              button,
918                              1, 2,
919                              2, 3);
920   gtk_widget_show (button);
921
922
923   button = gtk_button_new_with_label ("Raise");
924   g_signal_connect (button, "clicked", 
925                     G_CALLBACK (raise_window_clicked), 
926                     NULL);
927   gtk_table_attach_defaults (GTK_TABLE (table),
928                              button,
929                              0, 1,
930                              0, 1);
931   gtk_widget_show (button);
932
933   button = gtk_button_new_with_label ("Lower");
934   g_signal_connect (button, "clicked", 
935                     G_CALLBACK (lower_window_clicked), 
936                     NULL);
937   gtk_table_attach_defaults (GTK_TABLE (table),
938                              button,
939                              0, 1,
940                              2, 3);
941   gtk_widget_show (button);
942
943
944   button = gtk_button_new_with_label ("Smaller");
945   g_signal_connect (button, "clicked", 
946                     G_CALLBACK (smaller_window_clicked), 
947                     NULL);
948   gtk_table_attach_defaults (GTK_TABLE (table),
949                              button,
950                              2, 3,
951                              0, 1);
952   gtk_widget_show (button);
953
954   button = gtk_button_new_with_label ("Larger");
955   g_signal_connect (button, "clicked", 
956                     G_CALLBACK (larger_window_clicked), 
957                     NULL);
958   gtk_table_attach_defaults (GTK_TABLE (table),
959                              button,
960                              2, 3,
961                              2, 3);
962   gtk_widget_show (button);
963
964   button = gtk_button_new_with_label ("Native");
965   g_signal_connect (button, "clicked", 
966                     G_CALLBACK (native_window_clicked), 
967                     NULL);
968   gtk_table_attach_defaults (GTK_TABLE (table),
969                              button,
970                              1, 2,
971                              1, 2);
972   gtk_widget_show (button);
973
974
975   button = gtk_button_new_with_label ("scroll");
976   gtk_button_set_image (GTK_BUTTON (button),
977                         gtk_image_new_from_stock (GTK_STOCK_GO_UP,
978                                                   GTK_ICON_SIZE_BUTTON));
979   g_signal_connect (button, "clicked", 
980                     G_CALLBACK (scroll_window_clicked), 
981                     GINT_TO_POINTER (GTK_DIR_UP));
982   gtk_table_attach_defaults (GTK_TABLE (table),
983                              button,
984                              3, 4,
985                              0, 1);
986   gtk_widget_show (button);
987
988   button = gtk_button_new_with_label ("scroll");
989   gtk_button_set_image (GTK_BUTTON (button),
990                         gtk_image_new_from_stock (GTK_STOCK_GO_DOWN,
991                                                   GTK_ICON_SIZE_BUTTON));
992   g_signal_connect (button, "clicked", 
993                     G_CALLBACK (scroll_window_clicked), 
994                     GINT_TO_POINTER (GTK_DIR_DOWN));
995   gtk_table_attach_defaults (GTK_TABLE (table),
996                              button,
997                              3, 4,
998                              1, 2);
999   gtk_widget_show (button);
1000
1001   button = gtk_button_new_with_label ("Manual");
1002   g_signal_connect (button, "clicked", 
1003                     G_CALLBACK (manual_clicked),
1004                     NULL);
1005   gtk_table_attach_defaults (GTK_TABLE (table),
1006                              button,
1007                              3, 4,
1008                              2, 3);
1009   gtk_widget_show (button);
1010
1011   button = gtk_button_new_with_label ("draw drawable");
1012   gtk_box_pack_start (GTK_BOX (vbox),
1013                       button,
1014                       FALSE, FALSE,
1015                       2);
1016   gtk_widget_show (button);
1017   g_signal_connect (button, "clicked", 
1018                     G_CALLBACK (draw_drawable_clicked), 
1019                     NULL);
1020
1021   button = gtk_button_new_with_label ("Add window");
1022   gtk_box_pack_start (GTK_BOX (vbox),
1023                       button,
1024                       FALSE, FALSE,
1025                       2);
1026   gtk_widget_show (button);
1027   g_signal_connect (button, "clicked", 
1028                     G_CALLBACK (add_window_clicked), 
1029                     NULL);
1030   
1031   button = gtk_button_new_with_label ("Remove window");
1032   gtk_box_pack_start (GTK_BOX (vbox),
1033                       button,
1034                       FALSE, FALSE,
1035                       2);
1036   gtk_widget_show (button);
1037   g_signal_connect (button, "clicked", 
1038                     G_CALLBACK (remove_window_clicked), 
1039                     NULL);
1040
1041   button = gtk_button_new_with_label ("Save");
1042   gtk_box_pack_start (GTK_BOX (vbox),
1043                       button,
1044                       FALSE, FALSE,
1045                       2);
1046   gtk_widget_show (button);
1047   g_signal_connect (button, "clicked", 
1048                     G_CALLBACK (save_clicked), 
1049                     NULL);
1050
1051   gtk_widget_show (window);
1052
1053   if (argc == 2)
1054     {
1055       file = g_file_new_for_commandline_arg (argv[1]);
1056       load_file (file);
1057       g_object_unref (file);
1058     }
1059   
1060   gtk_main ();
1061
1062   return 0;
1063 }