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