c - tutorial - messagebox example




GTK implementation of MessageBox (4)

I have been trying to implement Win32's MessageBox using GTK. The app using SDL/OpenGL, so this isn't a GTK app.

I handle the initialisation (gtk_init) sort of stuff inside the MessageBox function as follows:

int MessageBox(HWND hwnd, const char* text, const char* caption, UINT type)
{
    GtkWidget *window = NULL;
    GtkWidget *dialog = NULL;

    gtk_init(&gtkArgc, &gtkArgv);
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete_event), NULL);
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL);
    // gcallback calls gtk_main_quit()
    gtk_init_add((GtkFunction)gcallback, NULL);

    if (type & MB_YESNO) {
        dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, text);
    } else {
        dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, text);
    }

    gtk_window_set_title(GTK_WINDOW(dialog), caption);
    gint result = gtk_dialog_run(GTK_DIALOG(dialog));

    gtk_main();

    gtk_widget_destroy(dialog);

    if (type & MB_YESNO) {
        switch (result) {
        default:
        case GTK_RESPONSE_DELETE_EVENT:
        case GTK_RESPONSE_NO:
            return IDNO;
            break;
        case GTK_RESPONSE_YES:
            return IDYES;
            break;
        }
    }

    return IDOK;
} 

Now, I am by no means an experienced GTK programmer, and I realise that I'm probably doing something horribly wrong.

However, my problem is that the last dialog popped up with this function stays around until the process exits. Any ideas?


A few things:

You are creating (and not using) an unnecessary toplevel window, named window. You can just delete these lines:

window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete_event), NULL);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL);

Also, the flow doesn't seem quite right. gtk_main() starts the GTK main loop, which blocks until something exits it. gtk_dialog_run() also starts a main loop, but it exits as soon as one of the buttons is clicked.

I think it might be enough for you to remove the gtk_init_add() and gtk_main() calls, and simply deal with the return value. Also the gtk_widget_destroy() call is unnecessary, as the dialog window is automatically destroyed when gtk_dialog_run() returns.


Hmm, ok. I'd suggest code like this, then:

typedef struct {
    int type;
    int result;
} DialogData;

static gboolean
display_dialog(gpointer user_data)
{
    DialogData *dialog_data = user_data;
    GtkWidget *dialog;

    if (dialog_data->type & MB_YESNO)
        dialog = gtk_message_dialog_new(...);
    else
        dialog = gtk_message_dialog_new(...);

    // Set title, etc.

    dialog_data->result = gtk_dialog_run(...);

    gtk_main_quit();  // Quits the main loop run in MessageBox()

    return FALSE;
}

int MessageBox(...)
{
    DialogData dialog_data;

    dialog_data.type = type;

    gtk_idle_add(display_dialog, &dialog_data);

    gtk_main();

    // Do stuff based on dialog_data.result
}

The struct is because you need to pass around a couple pieces of data. The gtk_idle_add() call adds a method to be run when the main loop is running and idle, and the FALSE return value from the display_dialog() call means that it's only run once. After we get the result from the dialog, we quit the main loop. That'll cause the gtk_main() in your main MessageBox() method to return, and you'll be able to access the result from there.

Hope this helps!


Qt implementation of MessageBox

You are tring to show a message box from a console application right ?

If this is correct you need to add this line in your pro file:

QT += gui

After you have done that in your main.cpp file write something like this. Qt creates an event loop for you

#include <QtCore/QCoreApplication>
#include <QTextStream>
#include <QMessageBox>
#include <QApplication>




int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QMessageBox::information(NULL,"Hello","Salut","Ok");

    return a.exec();
}

SFML and GTK+ - GtkFileChooserDialog

In the gtk_dialog_run documentation there is a note

After gtk_dialog_run() returns, you are responsible for hiding or destroying the dialog if you wish to do so.

So the dialog should not get destroyed automaticaly, the programmer must do it.


EDIT:

The another problem is that you are not running GTK main loop (gtk_main() or its variant) so the GTK can not deal with events necessary to destroy a widget (no part of GTK is running in the time the events are present). The sollution for this is in answer to another question using gtk_idle_add() to invoke function after gtk_main() is called. In this function the dialog is shown, the result is given to the caller, the dialog is destroyed and gtk_main_quit() is called to terminate GTK main loop.

However, gtk_idle_add() is deprecated in GTK+2.6 and is not present in GTK+3.0, so g_idle_add() should be used instead. Your code could be somethink like

struct fch_result {
    gint response;
    // other information to return like filename,...
};

static gboolean fch_dialog(gpointer user_data)
{
    struct fch_result *result = (struct fch_result *) user_data;
    GtkWidget *dialog = gtk_file_chooser_dialog_new ( ... );
    result->response = gtk_dialog_run (GTK_DIALOG(dialog));
    // now add other information to result

    gtk_widget_destroy(dialog);
    gtk_main_quit();  // terminate the gtk_main loop called from caller
    return FALSE;
}

int main(int argc, char** argv)
{
    gtk_init(&argc, &argv);

    struct fch_result data;
    g_idle_add(fch_dialog, &data);

    gtk_main();

    // continue with the program
    return 0;
}






x11