Search code examples
c++gtkgtk2

Signal handler of old window getting replaced by new windows signal handler GTK+


My GUI application has 2 windows. The Main window destroy signal is set to quit the application using gtk_main_quit.

The other window destroy signal is set just to destroy that particular window using method gtk_widget_destroy.

From Main window we launch the other window. After launching the other window when we click on close button(X) then the other window successfully destroys but the main window keeps on running, so far all good.

Now when we click on Main windows close button(X) it did not exits the whole application rather it just destroys the main window and the process keeps on running.

If I don't launch the other window from main window then everything works fine and application exits successfully.

Here is a sample code which reproduces the issue:

#include <gtk/gtk.h>

#include <iostream>

using namespace std;

class OtherWindow {
    private:
        int number;

        GtkWidget* window;

        GtkWidget* button;

    public:
        OtherWindow(int num);

        static void read_number(GtkWidget *widget, gpointer data);

};

OtherWindow::OtherWindow(int num)
{
    number = num;
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    button = gtk_button_new_with_label("Read Number");

    gtk_container_add(GTK_CONTAINER(window), button);

    // signal handler
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_widget_destroy), NULL);

    g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(OtherWindow::read_number), this);

    gtk_widget_show_all(window);

    gtk_main();

}

void OtherWindow::read_number(GtkWidget *widget, gpointer data)
{
    OtherWindow* other_win = static_cast<OtherWindow*>(data);
    cout << other_win->number << endl;
}

class MainWindow {

    private:
        GtkWidget* window;

        GtkWidget* button;

    public:
        MainWindow();

        static void open_other_window(GtkWidget *widget, gpointer data);
};


MainWindow::MainWindow()
{
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    button = gtk_button_new_with_label("Open Another Window");

    gtk_container_add(GTK_CONTAINER(window), button);

    // signal handler
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);

    g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(MainWindow::open_other_window), NULL);

    gtk_widget_show_all(window);

    gtk_main();    
}

void MainWindow::open_other_window(GtkWidget *widget, gpointer data)
{
    OtherWindow other(10);
}

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

    MainWindow win;

}

One more doubt is that when I tried removing gtk_main loop from the OtherWindow constructor then application exits successfully but if I remove gtk_main loop from OtherWindow constructor and then click on the button present on the Other window to access the member variable using pointer reference my application then gets segmentation fault.

Also I am not using gtkmm because I have few limitations as I have to run application on old Solaris servers which don't have compiler to support the same.

It would be a very common thing to launch other windows from main window, I think I am missing something basic. Anything which can help here.


Solution

  • One more question answering myself. First thing to note here is why I am using two main loops as noted by @jku. I was using two main loops because earlier with only one loop my process was dumping core and I didn't concentrated on checking what went wrong rather I started thinking in other way and inserted one more main loop which was not required.

    Now why it was dumping core just struck my mind as I was writing comments on my post. It was object which was getting freed whose reference I was still using in the OtherWindow's Button's signal handler. As I created object on the stack and as soon as the function ended the object got deleted but later in signal handler when I tried using it, it will definitely dump core which I just got to know.

    Hence, the way I handled seg fault by introducing one more main loop was a very bad idea as we should be using only one main loop, as introducing more main loops caused further other issues as stated in the post.

    So, only few changes in above code makes everything right:

    First remove the gtk main loop from OtherWindow Constructor.

    Second create the OtherWindow object dynamically as below:

    void MainWindow::open_other_window(GtkWidget *widget, gpointer data)
    {
        OtherWindow* other = new OtherWindow(10);
    }