views:

480

answers:

1

I have the following code that uses GTK+ widget toolkit to display a window with a button. Clicking this button will show a modal dialog. Note that the call to gtk_dialog_run will recursively start another instance of the main loop, i.e. the on_click function will not return until the dialog box is dismissed.

I would like to have two of these top-level windows, each with a button and the ability to spawn their own modal dialog. Showing the dialog would only disable the window that spawned it and there could be up to two active modal dialogs at the same time, one for each top-level window.

In win32, I could accomplish this simply by running each top-level window in a separate thread. However, it seems that gtk_main can only be run from one thread. So how can I manage multiple window stacks in GTK+ (without sacrificing the simplicity of gtk_dialog_run if possible)?

Update: The code now displays both windows and adds them to their respective window groups.

#include <gtk/gtk.h>

struct modal_stack
{
    GtkWindowGroup * group;
    GtkWidget * window;
};

static void on_click(GtkWidget *widget, gpointer sptr)
{
    modal_stack * s = (modal_stack *)sptr;
    GtkWidget * dialog = gtk_file_chooser_dialog_new(
        "Open File", 0, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL,
        GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
    gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(s->window));
    gtk_window_group_add_window(s->group, GTK_WINDOW(dialog));
    gtk_dialog_run (GTK_DIALOG (dialog));
    gtk_window_group_remove_window(s->group, GTK_WINDOW(dialog));
    gtk_widget_destroy(dialog);
}

void create_window(modal_stack & s)
{
    s.group = gtk_window_group_new();
    s.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    gtk_widget_set_usize(s.window, 200, 200);
    g_signal_connect(G_OBJECT (s.window), "destroy",
        G_CALLBACK(gtk_main_quit), NULL);
    g_signal_connect(G_OBJECT (s.window), "delete_event",
        G_CALLBACK(gtk_main_quit), NULL);

    GtkWidget * button = gtk_button_new ();
    gtk_button_set_label(GTK_BUTTON(button), "show dialog");
    g_signal_connect(G_OBJECT (button), "clicked",
        G_CALLBACK(on_click), (gpointer) &s);
    gtk_widget_show(button);

    gtk_container_add(GTK_CONTAINER (s.window), button);
    gtk_widget_show(s.window);

    gtk_window_group_add_window(s.group, GTK_WINDOW(s.window));
}

int main(int argc, char *argv[])
{
    gtk_init (&argc, &argv);
    modal_stack wnd1, wnd2;
    create_window(wnd1);
    create_window(wnd2);
    gtk_main();
}
+2  A: 

There's a discrete mention in the gtk_dialog_run docs that gtk_dialog_run will only block interaction with windows in the same window group as your modal dialog.

Tobu
Thank you for answering. I tried putting each window into its own group, but after clicking the button in one of the windows, the other window still doesn't accept clicks (although it surprisingly does respond to mouse moves). Even if it worked correctly though, I still can't imagine how it could work without using multiple threads. If I click button 1, then button 2 and then hide dialog 1, if the loops are run in the same thread, the `gtk_dialog_run` for the first dialog can't possibly return until dialog 2 is closed as well. I think there is some fundamental point I'm missing.
avakar
Are you sure you added the dialogs to the window groups as well?
Tobu
Good catch. Unfortunately nothing changed after I fixed it. I've updated the question with my current code if you could look at it. In either case, you have my +1.
avakar