#include #ifdef GDK_WINDOWING_X11 #include #endif static GtkWidget *darea; static GtkTreeStore *window_store = NULL; static GtkWidget *treeview; static void update_store (void); static GtkWidget *main_window; GdkWindow * create_window (GdkWindow *parent, int x, int y, int w, int h, GdkRGBA *color) { GdkWindowAttr attributes; gint attributes_mask; GdkWindow *window; GdkRGBA *bg; attributes.x = x; attributes.y = y; attributes.width = w; attributes.height = h; attributes.window_type = GDK_WINDOW_CHILD; attributes.event_mask = GDK_STRUCTURE_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK; attributes.wclass = GDK_INPUT_OUTPUT; attributes_mask = GDK_WA_X | GDK_WA_Y; window = gdk_window_new (parent, &attributes, attributes_mask); gdk_window_set_user_data (window, darea); bg = g_new (GdkRGBA, 1); if (color) *bg = *color; else { bg->red = g_random_double (); bg->blue = g_random_double (); bg->green = g_random_double (); bg->alpha = 1.0; } gdk_window_set_background_rgba (window, bg); g_object_set_data_full (G_OBJECT (window), "color", bg, g_free); gdk_window_show (window); return window; } static void add_window_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { GList **selected = data; GdkWindow *window; gtk_tree_model_get (GTK_TREE_MODEL (window_store), iter, 0, &window, -1); *selected = g_list_prepend (*selected, window); } static GList * get_selected_windows (void) { GtkTreeSelection *sel; GList *selected; sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); selected = NULL; gtk_tree_selection_selected_foreach (sel, add_window_cb, &selected); return selected; } static gboolean find_window_helper (GtkTreeModel *model, GdkWindow *window, GtkTreeIter *iter, GtkTreeIter *selected_iter) { GtkTreeIter child_iter; GdkWindow *w; do { gtk_tree_model_get (model, iter, 0, &w, -1); if (w == window) { *selected_iter = *iter; return TRUE; } if (gtk_tree_model_iter_children (model, &child_iter, iter)) { if (find_window_helper (model, window, &child_iter, selected_iter)) return TRUE; } } while (gtk_tree_model_iter_next (model, iter)); return FALSE; } static gboolean find_window (GdkWindow *window, GtkTreeIter *window_iter) { GtkTreeIter iter; if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (window_store), &iter)) return FALSE; return find_window_helper (GTK_TREE_MODEL (window_store), window, &iter, window_iter); } static void toggle_selection_window (GdkWindow *window) { GtkTreeSelection *selection; GtkTreeIter iter; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); if (window != NULL && find_window (window, &iter)) { if (gtk_tree_selection_iter_is_selected (selection, &iter)) gtk_tree_selection_unselect_iter (selection, &iter); else gtk_tree_selection_select_iter (selection, &iter); } } static void unselect_windows (void) { GtkTreeSelection *selection; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); gtk_tree_selection_unselect_all (selection); } static void select_window (GdkWindow *window) { GtkTreeSelection *selection; GtkTreeIter iter; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); if (window != NULL && find_window (window, &iter)) gtk_tree_selection_select_iter (selection, &iter); } static void select_windows (GList *windows) { GtkTreeSelection *selection; GtkTreeIter iter; GList *l; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); gtk_tree_selection_unselect_all (selection); for (l = windows; l != NULL; l = l->next) { if (find_window (l->data, &iter)) gtk_tree_selection_select_iter (selection, &iter); } } static void add_window_clicked (GtkWidget *button, gpointer data) { GdkWindow *parent; GList *l; l = get_selected_windows (); if (l != NULL) parent = l->data; else parent = gtk_widget_get_window (darea); g_list_free (l); create_window (parent, 10, 10, 100, 100, NULL); update_store (); } static void remove_window_clicked (GtkWidget *button, gpointer data) { GList *l, *selected; selected = get_selected_windows (); for (l = selected; l != NULL; l = l->next) gdk_window_destroy (l->data); g_list_free (selected); update_store (); } static void save_children (GString *s, GdkWindow *window); static void save_window (GString *s, GdkWindow *window) { gint x, y; GdkRGBA *color; gdk_window_get_position (window, &x, &y); color = g_object_get_data (G_OBJECT (window), "color"); g_string_append_printf (s, "%d,%d %dx%d (%f,%f,%f,%f) %d %d\n", x, y, gdk_window_get_width (window), gdk_window_get_height (window), color->red, color->green, color->blue, color->alpha, gdk_window_has_native (window), g_list_length (gdk_window_peek_children (window))); save_children (s, window); } static void save_children (GString *s, GdkWindow *window) { GList *l; GdkWindow *child; for (l = g_list_reverse (gdk_window_peek_children (window)); l != NULL; l = l->next) { child = l->data; save_window (s, child); } } static void refresh_clicked (GtkWidget *button, gpointer data) { gtk_widget_queue_draw (darea); } static void save_clicked (GtkWidget *button, gpointer data) { GString *s; GtkWidget *dialog; GFile *file; s = g_string_new (""); save_children (s, gtk_widget_get_window (darea)); dialog = gtk_file_chooser_dialog_new ("Filename for window data", NULL, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE); if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog)); g_file_replace_contents (file, s->str, s->len, NULL, FALSE, 0, NULL, NULL, NULL); g_object_unref (file); } gtk_widget_destroy (dialog); g_string_free (s, TRUE); } static void destroy_children (GdkWindow *window) { GList *l; GdkWindow *child; for (l = gdk_window_peek_children (window); l != NULL; l = l->next) { child = l->data; destroy_children (child); gdk_window_destroy (child); } } static char ** parse_window (GdkWindow *parent, char **lines) { int x, y, w, h, native, n_children; double r, g, b, a; GdkWindow *window; GdkRGBA color; int i; if (*lines == NULL) return lines; if (sscanf(*lines, "%d,%d %dx%d (%lf,%lf,%lf,%lf) %d %d", &x, &y, &w, &h, &r, &g, &b, &a, &native, &n_children) == 10) { lines++; color.red = r; color.green = g; color.blue = b; color.alpha = a; window = create_window (parent, x, y, w, h, &color); if (native) gdk_window_ensure_native (window); for (i = 0; i < n_children; i++) lines = parse_window (window, lines); } else lines++; return lines; } static void load_file (GFile *file) { GdkWindow *window; char *data; char **lines, **l; if (g_file_load_contents (file, NULL, &data, NULL, NULL, NULL)) { window = gtk_widget_get_window (darea); destroy_children (window); lines = g_strsplit (data, "\n", -1); l = lines; while (*l != NULL) l = parse_window (window, l); } update_store (); } static void move_window_clicked (GtkWidget *button, gpointer data) { GdkWindow *window; GtkDirectionType direction; GList *selected, *l; gint x, y; direction = GPOINTER_TO_INT (data); selected = get_selected_windows (); for (l = selected; l != NULL; l = l->next) { window = l->data; gdk_window_get_position (window, &x, &y); switch (direction) { case GTK_DIR_UP: y -= 10; break; case GTK_DIR_DOWN: y += 10; break; case GTK_DIR_LEFT: x -= 10; break; case GTK_DIR_RIGHT: x += 10; break; default: break; } gdk_window_move (window, x, y); } g_list_free (selected); } static void manual_clicked (GtkWidget *button, gpointer data) { GdkWindow *window; GList *selected, *l; int x, y, w, h; GtkWidget *dialog, *grid, *label, *xspin, *yspin, *wspin, *hspin; selected = get_selected_windows (); if (selected == NULL) return; gdk_window_get_position (selected->data, &x, &y); w = gdk_window_get_width (selected->data); h = gdk_window_get_height (selected->data); dialog = gtk_dialog_new_with_buttons ("Select new position and size", GTK_WINDOW (main_window), GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); grid = gtk_grid_new (); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), grid, FALSE, FALSE, 2); label = gtk_label_new ("x:"); gtk_widget_set_halign (label, GTK_ALIGN_START); gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1); label = gtk_label_new ("y:"); gtk_widget_set_halign (label, GTK_ALIGN_START); gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1); label = gtk_label_new ("width:"); gtk_widget_set_halign (label, GTK_ALIGN_START); gtk_grid_attach (GTK_GRID (grid), label, 0, 2, 1, 1); label = gtk_label_new ("height:"); gtk_widget_set_halign (label, GTK_ALIGN_START); gtk_grid_attach (GTK_GRID (grid), label, 0, 3, 1, 1); xspin = gtk_spin_button_new_with_range (G_MININT, G_MAXINT, 1); gtk_widget_set_hexpand (xspin, TRUE); gtk_spin_button_set_value (GTK_SPIN_BUTTON (xspin), x); gtk_grid_attach (GTK_GRID (grid), xspin, 1, 0, 1, 1); yspin = gtk_spin_button_new_with_range (G_MININT, G_MAXINT, 1); gtk_widget_set_hexpand (yspin, TRUE); gtk_spin_button_set_value (GTK_SPIN_BUTTON (yspin), y); gtk_grid_attach (GTK_GRID (grid), yspin, 1, 1, 1, 1); wspin = gtk_spin_button_new_with_range (G_MININT, G_MAXINT, 1); gtk_widget_set_hexpand (wspin, TRUE); gtk_spin_button_set_value (GTK_SPIN_BUTTON (wspin), w); gtk_grid_attach (GTK_GRID (grid), wspin, 1, 2, 1, 1); hspin = gtk_spin_button_new_with_range (G_MININT, G_MAXINT, 1); gtk_widget_set_hexpand (hspin, TRUE); gtk_spin_button_set_value (GTK_SPIN_BUTTON (hspin), h); gtk_grid_attach (GTK_GRID (grid), hspin, 1, 3, 1, 1); gtk_widget_show_all (dialog); gtk_dialog_run (GTK_DIALOG (dialog)); x = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (xspin)); y = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (yspin)); w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (wspin)); h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (hspin)); gtk_widget_destroy (dialog); for (l = selected; l != NULL; l = l->next) { window = l->data; gdk_window_move_resize (window, x, y, w, h); } g_list_free (selected); } static void restack_clicked (GtkWidget *button, gpointer data) { GList *selected; selected = get_selected_windows (); if (g_list_length (selected) != 2) { g_warning ("select two windows"); } gdk_window_restack (selected->data, selected->next->data, GPOINTER_TO_INT (data)); g_list_free (selected); update_store (); } static void scroll_window_clicked (GtkWidget *button, gpointer data) { GdkWindow *window; GtkDirectionType direction; GList *selected, *l; gint dx, dy; direction = GPOINTER_TO_INT (data); selected = get_selected_windows (); dx = 0; dy = 0; switch (direction) { case GTK_DIR_UP: dy = 10; break; case GTK_DIR_DOWN: dy = -10; break; case GTK_DIR_LEFT: dx = 10; break; case GTK_DIR_RIGHT: dx = -10; break; default: break; } for (l = selected; l != NULL; l = l->next) { window = l->data; gdk_window_scroll (window, dx, dy); } g_list_free (selected); } static void raise_window_clicked (GtkWidget *button, gpointer data) { GList *selected, *l; GdkWindow *window; selected = get_selected_windows (); for (l = selected; l != NULL; l = l->next) { window = l->data; gdk_window_raise (window); } g_list_free (selected); update_store (); } static void lower_window_clicked (GtkWidget *button, gpointer data) { GList *selected, *l; GdkWindow *window; selected = get_selected_windows (); for (l = selected; l != NULL; l = l->next) { window = l->data; gdk_window_lower (window); } g_list_free (selected); update_store (); } static void smaller_window_clicked (GtkWidget *button, gpointer data) { GList *selected, *l; GdkWindow *window; int w, h; selected = get_selected_windows (); for (l = selected; l != NULL; l = l->next) { window = l->data; w = gdk_window_get_width (window) - 10; h = gdk_window_get_height (window) - 10; if (w < 1) w = 1; if (h < 1) h = 1; gdk_window_resize (window, w, h); } g_list_free (selected); } static void larger_window_clicked (GtkWidget *button, gpointer data) { GList *selected, *l; GdkWindow *window; int w, h; selected = get_selected_windows (); for (l = selected; l != NULL; l = l->next) { window = l->data; w = gdk_window_get_width (window) + 10; h = gdk_window_get_height (window) + 10; gdk_window_resize (window, w, h); } g_list_free (selected); } static void native_window_clicked (GtkWidget *button, gpointer data) { GList *selected, *l; GdkWindow *window; selected = get_selected_windows (); for (l = selected; l != NULL; l = l->next) { window = l->data; gdk_window_ensure_native (window); } g_list_free (selected); update_store (); } static void alpha_clicked (GtkWidget *button, gpointer data) { GList *selected, *l; GdkWindow *window; GdkRGBA *color; selected = get_selected_windows (); for (l = selected; l != NULL; l = l->next) { window = l->data; color = g_object_get_data (G_OBJECT (window), "color"); if (GPOINTER_TO_INT(data) > 0) color->alpha += 0.2; else color->alpha -= 0.2; if (color->alpha < 0) color->alpha = 0; if (color->alpha > 1) color->alpha = 1; gdk_window_set_background_rgba (window, color); } g_list_free (selected); update_store (); } static gboolean darea_button_release_event (GtkWidget *widget, GdkEventButton *event) { if ((event->state & GDK_CONTROL_MASK) != 0) { toggle_selection_window (event->window); } else { unselect_windows (); select_window (event->window); } return TRUE; } static void render_window_cell (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) { GdkWindow *window; char *name; gtk_tree_model_get (GTK_TREE_MODEL (window_store), iter, 0, &window, -1); if (gdk_window_has_native (window)) name = g_strdup_printf ("%p (native)", window); else name = g_strdup_printf ("%p", window); g_object_set (cell, "text", name, NULL); } static void add_children (GtkTreeStore *store, GdkWindow *window, GtkTreeIter *window_iter) { GList *l; GtkTreeIter child_iter; for (l = gdk_window_peek_children (window); l != NULL; l = l->next) { gtk_tree_store_append (store, &child_iter, window_iter); gtk_tree_store_set (store, &child_iter, 0, l->data, -1); add_children (store, l->data, &child_iter); } } static void update_store (void) { GList *selected; selected = get_selected_windows (); gtk_tree_store_clear (window_store); add_children (window_store, gtk_widget_get_window (darea), NULL); gtk_tree_view_expand_all (GTK_TREE_VIEW (treeview)); select_windows (selected); g_list_free (selected); } int main (int argc, char **argv) { GtkWidget *window, *vbox, *hbox, *frame; GtkWidget *button, *scrolled, *grid; GtkTreeViewColumn *column; GtkCellRenderer *renderer; GdkRGBA black = {0,0,0,1}; GFile *file; gtk_init (&argc, &argv); main_window = window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_container_set_border_width (GTK_CONTAINER (window), 0); g_signal_connect (G_OBJECT (window), "delete-event", gtk_main_quit, NULL); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); gtk_container_add (GTK_CONTAINER (window), hbox); gtk_widget_show (hbox); frame = gtk_frame_new ("GdkWindows"); gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 5); gtk_widget_show (frame); darea = gtk_drawing_area_new (); /*gtk_widget_set_double_buffered (darea, FALSE);*/ gtk_widget_add_events (darea, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); gtk_widget_set_size_request (darea, 500, 500); g_signal_connect (darea, "button_release_event", G_CALLBACK (darea_button_release_event), NULL); gtk_container_add (GTK_CONTAINER (frame), darea); gtk_widget_realize (darea); gtk_widget_show (darea); gtk_widget_override_background_color (darea, 0, &black); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 5); gtk_widget_show (vbox); window_store = gtk_tree_store_new (1, GDK_TYPE_WINDOW); treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (window_store)); gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), GTK_SELECTION_MULTIPLE); column = gtk_tree_view_column_new (); gtk_tree_view_column_set_title (column, "Window"); renderer = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start (column, renderer, TRUE); gtk_tree_view_column_set_cell_data_func (column, renderer, render_window_cell, NULL, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); scrolled = gtk_scrolled_window_new (NULL, NULL); gtk_widget_set_size_request (scrolled, 200, 400); gtk_container_add (GTK_CONTAINER (scrolled), treeview); gtk_box_pack_start (GTK_BOX (vbox), scrolled, FALSE, FALSE, 5); gtk_widget_show (scrolled); gtk_widget_show (treeview); grid = gtk_grid_new (); gtk_grid_set_row_homogeneous (GTK_GRID (grid), TRUE); gtk_grid_set_column_homogeneous (GTK_GRID (grid), TRUE); gtk_box_pack_start (GTK_BOX (vbox), grid, FALSE, FALSE, 2); gtk_widget_show (grid); button = gtk_button_new (); gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_stock (GTK_STOCK_GO_BACK, GTK_ICON_SIZE_BUTTON)); g_signal_connect (button, "clicked", G_CALLBACK (move_window_clicked), GINT_TO_POINTER (GTK_DIR_LEFT)); gtk_grid_attach (GTK_GRID (grid), button, 0, 1, 1, 1); gtk_widget_show (button); button = gtk_button_new (); gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_BUTTON)); g_signal_connect (button, "clicked", G_CALLBACK (move_window_clicked), GINT_TO_POINTER (GTK_DIR_UP)); gtk_grid_attach (GTK_GRID (grid), button, 1, 0, 1, 1); gtk_widget_show (button); button = gtk_button_new (); gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_BUTTON)); g_signal_connect (button, "clicked", G_CALLBACK (move_window_clicked), GINT_TO_POINTER (GTK_DIR_RIGHT)); gtk_grid_attach (GTK_GRID (grid), button, 2, 1, 1, 1); gtk_widget_show (button); button = gtk_button_new (); gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_stock (GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_BUTTON)); g_signal_connect (button, "clicked", G_CALLBACK (move_window_clicked), GINT_TO_POINTER (GTK_DIR_DOWN)); gtk_grid_attach (GTK_GRID (grid), button, 1, 2, 1, 1); gtk_widget_show (button); button = gtk_button_new_with_label ("Raise"); g_signal_connect (button, "clicked", G_CALLBACK (raise_window_clicked), NULL); gtk_grid_attach (GTK_GRID (grid), button, 0, 0, 1, 1); gtk_widget_show (button); button = gtk_button_new_with_label ("Lower"); g_signal_connect (button, "clicked", G_CALLBACK (lower_window_clicked), NULL); gtk_grid_attach (GTK_GRID (grid), button, 0, 2, 1, 1); gtk_widget_show (button); button = gtk_button_new_with_label ("Smaller"); g_signal_connect (button, "clicked", G_CALLBACK (smaller_window_clicked), NULL); gtk_grid_attach (GTK_GRID (grid), button, 2, 0, 1, 1); gtk_widget_show (button); button = gtk_button_new_with_label ("Larger"); g_signal_connect (button, "clicked", G_CALLBACK (larger_window_clicked), NULL); gtk_grid_attach (GTK_GRID (grid), button, 2, 2, 1, 1); gtk_widget_show (button); button = gtk_button_new_with_label ("Native"); g_signal_connect (button, "clicked", G_CALLBACK (native_window_clicked), NULL); gtk_grid_attach (GTK_GRID (grid), button, 1, 1, 1, 1); gtk_widget_show (button); button = gtk_button_new_with_label ("scroll"); gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_BUTTON)); g_signal_connect (button, "clicked", G_CALLBACK (scroll_window_clicked), GINT_TO_POINTER (GTK_DIR_UP)); gtk_grid_attach (GTK_GRID (grid), button, 3, 0, 1, 1); gtk_widget_show (button); button = gtk_button_new_with_label ("scroll"); gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_stock (GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_BUTTON)); g_signal_connect (button, "clicked", G_CALLBACK (scroll_window_clicked), GINT_TO_POINTER (GTK_DIR_DOWN)); gtk_grid_attach (GTK_GRID (grid), button, 3, 1, 1, 1); gtk_widget_show (button); button = gtk_button_new_with_label ("Manual"); g_signal_connect (button, "clicked", G_CALLBACK (manual_clicked), NULL); gtk_grid_attach (GTK_GRID (grid), button, 3, 2, 1, 1); gtk_widget_show (button); button = gtk_button_new_with_label ("More transparent"); g_signal_connect (button, "clicked", G_CALLBACK (alpha_clicked), GINT_TO_POINTER (-1)); gtk_grid_attach (GTK_GRID (grid), button, 0, 3, 1, 1); gtk_widget_show (button); button = gtk_button_new_with_label ("Less transparent"); g_signal_connect (button, "clicked", G_CALLBACK (alpha_clicked), GINT_TO_POINTER (1)); gtk_grid_attach (GTK_GRID (grid), button, 1, 3, 1, 1); gtk_widget_show (button); button = gtk_button_new_with_label ("Restack above"); g_signal_connect (button, "clicked", G_CALLBACK (restack_clicked), GINT_TO_POINTER (1)); gtk_grid_attach (GTK_GRID (grid), button, 2, 3, 1, 1); gtk_widget_show (button); button = gtk_button_new_with_label ("Restack below"); g_signal_connect (button, "clicked", G_CALLBACK (restack_clicked), 0); gtk_grid_attach (GTK_GRID (grid), button, 3, 3, 1, 1); gtk_widget_show (button); button = gtk_button_new_with_label ("Add window"); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 2); gtk_widget_show (button); g_signal_connect (button, "clicked", G_CALLBACK (add_window_clicked), NULL); button = gtk_button_new_with_label ("Remove window"); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 2); gtk_widget_show (button); g_signal_connect (button, "clicked", G_CALLBACK (remove_window_clicked), NULL); button = gtk_button_new_with_label ("Save"); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 2); gtk_widget_show (button); g_signal_connect (button, "clicked", G_CALLBACK (save_clicked), NULL); button = gtk_button_new_with_label ("Refresh"); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 2); gtk_widget_show (button); g_signal_connect (button, "clicked", G_CALLBACK (refresh_clicked), NULL); gtk_widget_show (window); if (argc == 2) { file = g_file_new_for_commandline_arg (argv[1]); load_file (file); g_object_unref (file); } gtk_main (); return 0; }