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