]> Pileus Git - ~andy/gtk/blob - tests/testwindows.c
tests/testwindows - play with GdkWindows
[~andy/gtk] / tests / testwindows.c
1 #include <gtk/gtk.h>
2 #include <X11/Xlib.h>
3
4 static GtkWidget *darea;
5 static GtkTreeStore *window_store = NULL;
6 static GtkWidget *treeview;
7
8 static void update_store (void);
9
10 static gboolean
11 window_has_impl (GdkWindow *window)
12 {
13   GdkWindowObject *w;
14   w = (GdkWindowObject *)window;
15   return w->parent == NULL || w->parent->impl != w->impl;
16 }
17
18 GdkWindow *
19 create_window (GdkWindow *parent,
20                int x, int y, int w, int h,
21                GdkColor *color)
22 {
23   GdkWindowAttr attributes;
24   gint attributes_mask;
25   GdkWindow *window;
26   GdkColor *bg;
27
28   attributes.x = x;
29   attributes.y = y;
30   attributes.width = w;
31   attributes.height = h;
32   attributes.window_type = GDK_WINDOW_CHILD;
33   attributes.event_mask = GDK_STRUCTURE_MASK
34                         | GDK_BUTTON_MOTION_MASK
35                         | GDK_BUTTON_PRESS_MASK
36                         | GDK_BUTTON_RELEASE_MASK
37                         | GDK_EXPOSURE_MASK
38                         | GDK_ENTER_NOTIFY_MASK
39                         | GDK_LEAVE_NOTIFY_MASK;
40   attributes.wclass = GDK_INPUT_OUTPUT;
41       
42   attributes_mask = GDK_WA_X | GDK_WA_Y;
43       
44   window = gdk_window_new (parent, &attributes, attributes_mask);
45   gdk_window_set_user_data (window, darea);
46
47   bg = g_new (GdkColor, 1);
48   if (color)
49     *bg = *color;
50   else
51     {
52       bg->red = g_random_int_range (0, 0xffff);
53       bg->blue = g_random_int_range (0, 0xffff);
54       bg->green = g_random_int_range (0, 0xffff);;
55     }
56   
57   gdk_rgb_find_color (gtk_widget_get_colormap (darea), bg);
58   gdk_window_set_background (window, bg);
59   g_object_set_data_full (G_OBJECT (window), "color", bg, g_free);
60   
61   gdk_window_show (window);
62   
63   return window;
64 }
65
66 static GdkWindow *
67 get_selected_window (void)
68 {
69   GtkTreeSelection *sel;
70   GtkTreeIter iter;
71   GdkWindow *window;
72   
73   sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
74   if (!gtk_tree_selection_get_selected (sel, NULL, &iter))
75     return NULL;
76
77   gtk_tree_model_get (GTK_TREE_MODEL (window_store),
78                       &iter,
79                       0, &window,
80                       -1);
81   return window;
82 }
83
84 static gboolean
85 find_window_helper (GtkTreeModel *model,
86                     GdkWindow *window,
87                     GtkTreeIter *iter,
88                     GtkTreeIter *selected_iter)
89 {
90   GtkTreeIter child_iter;
91   GdkWindow *w;
92
93   do
94     {
95       gtk_tree_model_get (model, iter,
96                           0, &w,
97                           -1);
98       if (w == window)
99         {
100           *selected_iter = *iter;
101           return TRUE;
102         }
103       
104       if (gtk_tree_model_iter_children (model,
105                                         &child_iter,
106                                         iter))
107         {
108           if (find_window_helper (model, window, &child_iter, selected_iter))
109             return TRUE;
110         }
111     } while (gtk_tree_model_iter_next (model, iter));
112
113   return FALSE;
114 }
115
116 static gboolean
117 find_window (GdkWindow *window,
118              GtkTreeIter *window_iter)
119 {
120   GtkTreeIter iter;
121
122   if (!gtk_tree_model_get_iter_first  (GTK_TREE_MODEL (window_store), &iter))
123     return FALSE;
124
125   return find_window_helper (GTK_TREE_MODEL (window_store),
126                              window,
127                              &iter,
128                              window_iter);
129 }
130
131 static void
132 select_window (GdkWindow *window)
133 {
134   GtkTreeIter iter;
135   GtkTreeSelection *selection;
136
137   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
138
139   if (window != NULL &&
140       find_window (window, &iter))
141     gtk_tree_selection_select_iter (selection,  &iter);
142   else
143     gtk_tree_selection_unselect_all (selection);
144 }
145
146 static void
147 add_window_clicked (GtkWidget *button, 
148                     gpointer data)
149 {
150   GdkWindow *parent;
151
152   parent = get_selected_window ();
153   if (parent == NULL)
154     parent = darea->window;
155   
156   create_window (parent, 10, 10, 100, 100, NULL);
157   update_store ();
158 }
159
160 static void
161 remove_window_clicked (GtkWidget *button, 
162                        gpointer data)
163 {
164   GdkWindow *window;
165
166   window = get_selected_window ();
167   if (window == NULL)
168     return;
169
170   gdk_window_destroy (window);
171 }
172
173 static void save_children (GString *s, GdkWindow *window);
174
175 static void
176 save_window (GString *s,
177              GdkWindow *window)
178 {
179   gint x, y, w, h;
180   GdkColor *color;
181
182   gdk_window_get_position (window, &x, &y);
183   gdk_drawable_get_size (GDK_DRAWABLE (window), &w, &h);
184   color = g_object_get_data (G_OBJECT (window), "color");
185   
186   g_string_append_printf (s, "%d,%d %dx%d (%d,%d,%d) %d %d\n",
187                           x, y, w, h,
188                           color->red, color->green, color->blue,
189                           window_has_impl (window),
190                           g_list_length (gdk_window_peek_children (window)));
191
192   save_children (s, window);
193 }
194
195
196 static void
197 save_children (GString *s,
198                GdkWindow *window)
199 {
200   GList *l;
201   GdkWindow *child;
202
203   for (l = g_list_reverse (gdk_window_peek_children (window));
204        l != NULL;
205        l = l->next)
206     {
207       child = l->data;
208
209       save_window (s, child);
210     }
211 }
212
213
214 static void
215 save_clicked (GtkWidget *button, 
216               gpointer data)
217 {
218   GString *s;
219   GtkWidget *dialog;
220   GFile *file;
221
222   s = g_string_new ("");
223
224   save_children (s, darea->window);
225
226   dialog = gtk_file_chooser_dialog_new ("Filename for window data",
227                                         NULL,
228                                         GTK_FILE_CHOOSER_ACTION_SAVE,
229                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
230                                         GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
231                                         NULL);
232   
233   gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
234   
235   if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
236     {
237       file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
238
239       g_file_replace_contents (file,
240                                s->str, s->len,
241                                NULL, FALSE,
242                                0, NULL, NULL, NULL);
243
244       g_object_unref (file);
245     }
246
247   gtk_widget_destroy (dialog);
248   g_string_free (s, TRUE);
249 }
250
251 static void
252 destroy_children (GdkWindow *window)
253 {
254   GList *l;
255   GdkWindow *child;
256
257   for (l = gdk_window_peek_children (window);
258        l != NULL;
259        l = l->next)
260     {
261       child = l->data;
262       
263       destroy_children (child);
264       gdk_window_destroy (child);
265     }
266 }
267
268 static char **
269 parse_window (GdkWindow *parent, char **lines)
270 {
271   int x, y, w, h, r, g, b, native, n_children;
272   GdkWindow *window;
273   GdkColor color;
274   int i;
275
276   if (*lines == NULL)
277     return lines;
278   
279   if (sscanf(*lines, "%d,%d %dx%d (%d,%d,%d) %d %d",
280              &x, &y, &w, &h, &r, &g, &b, &native, &n_children) == 9)
281     {
282       lines++;
283       color.red = r;
284       color.green = g;
285       color.blue = b;
286       window = create_window (parent, x, y, w, h, &color);
287       if (native)
288         gdk_window_set_has_native (window, TRUE);
289       
290       for (i = 0; i < n_children; i++)
291         lines = parse_window (window, lines);
292     }
293   else
294     lines++;
295   
296   return lines;
297 }
298   
299 static void
300 load_file (GFile *file)
301 {
302   char *data;
303   char **lines, **l;
304   
305   if (g_file_load_contents (file, NULL, &data, NULL, NULL, NULL))
306     {
307       destroy_children (darea->window);
308
309       lines = g_strsplit (data, "\n", -1);
310
311       l = lines;
312       while (*l != NULL)
313         l = parse_window (darea->window, l);
314     }
315
316   update_store ();
317 }
318
319 static void
320 move_window_clicked (GtkWidget *button, 
321                      gpointer data)
322 {
323   GdkWindow *window;
324   GtkDirectionType direction;
325   gint x, y;
326
327   direction = GPOINTER_TO_INT (data);
328     
329   window = get_selected_window ();
330   
331   if (window == NULL)
332     return;
333
334   gdk_window_get_position (window, &x, &y);
335
336   switch (direction) {
337   case GTK_DIR_UP:
338     y -= 10;
339     break;
340   case GTK_DIR_DOWN:
341     y += 10;
342     break;
343   case GTK_DIR_LEFT:
344     x -= 10;
345     break;
346   case GTK_DIR_RIGHT:
347     x += 10;
348     break;
349   default:
350     break;
351   }
352
353   gdk_window_move (window, x, y);
354 }
355
356 static void
357 raise_window_clicked (GtkWidget *button, 
358                       gpointer data)
359 {
360   GdkWindow *window;
361     
362   window = get_selected_window ();
363   if (window == NULL)
364     return;
365
366   gdk_window_raise (window);
367   update_store ();
368 }
369
370 static void
371 lower_window_clicked (GtkWidget *button, 
372                       gpointer data)
373 {
374   GdkWindow *window;
375     
376   window = get_selected_window ();
377   if (window == NULL)
378     return;
379
380   gdk_window_lower (window);
381   update_store ();
382 }
383
384
385 static void
386 smaller_window_clicked (GtkWidget *button, 
387                         gpointer data)
388 {
389   GdkWindow *window;
390   int w, h;
391
392   window = get_selected_window ();
393   if (window == NULL)
394     return;
395
396   gdk_drawable_get_size (GDK_DRAWABLE (window), &w, &h);
397
398   w -= 10;
399   h -= 10;
400   if (w < 1)
401     w = 1;
402   if (h < 1)
403     h = 1;
404
405   gdk_window_resize (window, w, h);
406 }
407
408 static void
409 larger_window_clicked (GtkWidget *button, 
410                         gpointer data)
411 {
412   GdkWindow *window;
413   int w, h;
414
415   window = get_selected_window ();
416   if (window == NULL)
417     return;
418
419   gdk_drawable_get_size (GDK_DRAWABLE (window), &w, &h);
420
421   w += 10;
422   h += 10;
423
424   gdk_window_resize (window, w, h);
425 }
426
427 static void
428 native_window_clicked (GtkWidget *button, 
429                         gpointer data)
430 {
431   GdkWindow *window;
432
433   window = get_selected_window ();
434   if (window == NULL)
435     return;
436
437   gdk_window_set_has_native (window, TRUE);
438   update_store ();
439 }
440
441 static gboolean
442 darea_button_release_event (GtkWidget *widget,
443                             GdkEventButton *event)
444 {
445   select_window (event->window);
446   return TRUE;
447 }
448
449 static void
450 render_window_cell (GtkTreeViewColumn *tree_column,
451                     GtkCellRenderer   *cell,
452                     GtkTreeModel      *tree_model,
453                     GtkTreeIter       *iter,
454                     gpointer           data)
455 {
456   GdkWindow *window;
457   char *name;
458
459   gtk_tree_model_get (GTK_TREE_MODEL (window_store),
460                       iter,
461                       0, &window,
462                       -1);
463
464   if (window_has_impl (window))
465       name = g_strdup_printf ("%p (native)", window);
466   else
467       name = g_strdup_printf ("%p", window);
468   g_object_set (cell,
469                 "text", name,
470                 "background-gdk", &((GdkWindowObject *)window)->bg_color,
471                 NULL);  
472 }
473
474 static void
475 add_children (GtkTreeStore *store,
476               GdkWindow *window,
477               GtkTreeIter *window_iter)
478 {
479   GList *l;
480   GtkTreeIter child_iter;
481
482   for (l = gdk_window_peek_children (window);
483        l != NULL;
484        l = l->next)
485     {
486       gtk_tree_store_append (store, &child_iter, window_iter);
487       gtk_tree_store_set (store, &child_iter,
488                           0, l->data,
489                           -1);
490
491       add_children (store, l->data, &child_iter);
492     }
493 }
494
495 static void
496 update_store (void)
497 {
498   GdkWindow *selected;
499
500   selected = get_selected_window ();
501
502   gtk_tree_store_clear (window_store);
503
504   add_children (window_store, darea->window, NULL);
505   gtk_tree_view_expand_all (GTK_TREE_VIEW (treeview));
506
507   select_window (selected);
508 }
509
510
511 int
512 main (int argc, char **argv)
513 {
514   GtkWidget *window, *vbox, *hbox, *frame;
515   GtkWidget *button, *scrolled, *table;
516   GtkTreeViewColumn *column;
517   GtkCellRenderer *renderer;
518   GdkColor black = {0};
519   GFile *file;
520   
521   gtk_init (&argc, &argv);
522
523   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
524   gtk_container_set_border_width (GTK_CONTAINER (window), 0);
525
526   g_signal_connect (G_OBJECT (window), "delete-event", gtk_main_quit, NULL);
527
528   hbox = gtk_hbox_new (FALSE, 5);
529   gtk_container_add (GTK_CONTAINER (window), hbox);
530   gtk_widget_show (hbox);
531
532   frame = gtk_frame_new ("GdkWindows");
533   gtk_box_pack_start (GTK_BOX (hbox),
534                       frame,
535                       FALSE, FALSE,
536                       5);
537   gtk_widget_show (frame);
538
539   darea =  gtk_drawing_area_new ();
540   /*gtk_widget_set_double_buffered (darea, FALSE);*/
541   gtk_widget_add_events (darea, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
542   gtk_widget_set_size_request (darea, 500, 500);
543   g_signal_connect (darea, "button_release_event", 
544                     G_CALLBACK (darea_button_release_event), 
545                     NULL);
546
547   
548   gtk_container_add (GTK_CONTAINER (frame), darea);
549   gtk_widget_realize (darea);
550   gtk_widget_show (darea);
551   gtk_widget_modify_bg (darea, GTK_STATE_NORMAL,
552                         &black);
553                         
554   
555   vbox = gtk_vbox_new (FALSE, 5);
556   gtk_box_pack_start (GTK_BOX (hbox),
557                       vbox,
558                       FALSE, FALSE,
559                       5);
560   gtk_widget_show (vbox);
561
562   window_store = gtk_tree_store_new (1, GDK_TYPE_WINDOW);
563   
564   treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (window_store));
565   gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
566                                GTK_SELECTION_SINGLE);
567   column = gtk_tree_view_column_new ();
568   gtk_tree_view_column_set_title (column, "Window");
569   renderer = gtk_cell_renderer_text_new ();
570   gtk_tree_view_column_pack_start (column, renderer, TRUE);
571   gtk_tree_view_column_set_cell_data_func (column,
572                                            renderer,
573                                            render_window_cell,
574                                            NULL, NULL);
575
576   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
577
578
579   scrolled = gtk_scrolled_window_new (NULL, NULL);
580   gtk_widget_set_size_request (scrolled, 200, 400);
581   gtk_container_add (GTK_CONTAINER (scrolled), treeview);
582   gtk_box_pack_start (GTK_BOX (vbox),
583                       scrolled,
584                       FALSE, FALSE,
585                       5);
586   gtk_widget_show (scrolled);
587   gtk_widget_show (treeview);
588   
589   table = gtk_table_new (3, 3, TRUE);
590   gtk_box_pack_start (GTK_BOX (vbox),
591                       table,
592                       FALSE, FALSE,
593                       2);
594   gtk_widget_show (table);
595
596   button = gtk_button_new ();
597   gtk_button_set_image (GTK_BUTTON (button),
598                         gtk_image_new_from_stock (GTK_STOCK_GO_BACK,
599                                                   GTK_ICON_SIZE_BUTTON));
600   g_signal_connect (button, "clicked", 
601                     G_CALLBACK (move_window_clicked), 
602                     GINT_TO_POINTER (GTK_DIR_LEFT));
603   gtk_table_attach_defaults (GTK_TABLE (table),
604                              button,
605                              0, 1,
606                              1, 2);
607   gtk_widget_show (button);
608
609   button = gtk_button_new ();
610   gtk_button_set_image (GTK_BUTTON (button),
611                         gtk_image_new_from_stock (GTK_STOCK_GO_UP,
612                                                   GTK_ICON_SIZE_BUTTON));
613   g_signal_connect (button, "clicked", 
614                     G_CALLBACK (move_window_clicked), 
615                     GINT_TO_POINTER (GTK_DIR_UP));
616   gtk_table_attach_defaults (GTK_TABLE (table),
617                              button,
618                              1, 2,
619                              0, 1);
620   gtk_widget_show (button);
621
622   button = gtk_button_new ();
623   gtk_button_set_image (GTK_BUTTON (button),
624                         gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD,
625                                                   GTK_ICON_SIZE_BUTTON));
626   g_signal_connect (button, "clicked", 
627                     G_CALLBACK (move_window_clicked), 
628                     GINT_TO_POINTER (GTK_DIR_RIGHT));
629   gtk_table_attach_defaults (GTK_TABLE (table),
630                              button,
631                              2, 3,
632                              1, 2);
633   gtk_widget_show (button);
634
635   button = gtk_button_new ();
636   gtk_button_set_image (GTK_BUTTON (button),
637                         gtk_image_new_from_stock (GTK_STOCK_GO_DOWN,
638                                                   GTK_ICON_SIZE_BUTTON));
639   g_signal_connect (button, "clicked", 
640                     G_CALLBACK (move_window_clicked), 
641                     GINT_TO_POINTER (GTK_DIR_DOWN));
642   gtk_table_attach_defaults (GTK_TABLE (table),
643                              button,
644                              1, 2,
645                              2, 3);
646   gtk_widget_show (button);
647
648
649   button = gtk_button_new_with_label ("Raise");
650   g_signal_connect (button, "clicked", 
651                     G_CALLBACK (raise_window_clicked), 
652                     NULL);
653   gtk_table_attach_defaults (GTK_TABLE (table),
654                              button,
655                              0, 1,
656                              0, 1);
657   gtk_widget_show (button);
658
659   button = gtk_button_new_with_label ("Lower");
660   g_signal_connect (button, "clicked", 
661                     G_CALLBACK (lower_window_clicked), 
662                     NULL);
663   gtk_table_attach_defaults (GTK_TABLE (table),
664                              button,
665                              0, 1,
666                              2, 3);
667   gtk_widget_show (button);
668
669
670   button = gtk_button_new_with_label ("Smaller");
671   g_signal_connect (button, "clicked", 
672                     G_CALLBACK (smaller_window_clicked), 
673                     NULL);
674   gtk_table_attach_defaults (GTK_TABLE (table),
675                              button,
676                              2, 3,
677                              0, 1);
678   gtk_widget_show (button);
679
680   button = gtk_button_new_with_label ("Larger");
681   g_signal_connect (button, "clicked", 
682                     G_CALLBACK (larger_window_clicked), 
683                     NULL);
684   gtk_table_attach_defaults (GTK_TABLE (table),
685                              button,
686                              2, 3,
687                              2, 3);
688   gtk_widget_show (button);
689
690   button = gtk_button_new_with_label ("Native");
691   g_signal_connect (button, "clicked", 
692                     G_CALLBACK (native_window_clicked), 
693                     NULL);
694   gtk_table_attach_defaults (GTK_TABLE (table),
695                              button,
696                              1, 2,
697                              1, 2);
698   gtk_widget_show (button);
699
700
701   button = gtk_button_new_with_label ("Add window");
702   gtk_box_pack_start (GTK_BOX (vbox),
703                       button,
704                       FALSE, FALSE,
705                       2);
706   gtk_widget_show (button);
707   g_signal_connect (button, "clicked", 
708                     G_CALLBACK (add_window_clicked), 
709                     NULL);
710   
711   button = gtk_button_new_with_label ("Remove window");
712   gtk_box_pack_start (GTK_BOX (vbox),
713                       button,
714                       FALSE, FALSE,
715                       2);
716   gtk_widget_show (button);
717   g_signal_connect (button, "clicked", 
718                     G_CALLBACK (remove_window_clicked), 
719                     NULL);
720
721   button = gtk_button_new_with_label ("Save");
722   gtk_box_pack_start (GTK_BOX (vbox),
723                       button,
724                       FALSE, FALSE,
725                       2);
726   gtk_widget_show (button);
727   g_signal_connect (button, "clicked", 
728                     G_CALLBACK (save_clicked), 
729                     NULL);
730
731   gtk_widget_show (window);
732
733   if (argc == 2)
734     {
735       file = g_file_new_for_commandline_arg (argv[1]);
736       load_file (file);
737       g_object_unref (file);
738     }
739   
740   gtk_main ();
741
742   return 0;
743 }