C++ – How to create multiple but independent modal dialogs in GTK+

cgtkmodal-dialog

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();
}

Best Answer

Put your call to gtk_dialog_run inside a function that is called by g_idle_add().

Related Topic