views:

524

answers:

4

I have a QApplication that, depending on command line parameters, sometimes doesn't actually has a GUI window, but just runs without GUI. In this case, I want to shut it down gracefully if CTRL-C was hit. Basically my code looks like this:

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

    ... // parse command line options

    if (no_gui) {
        QObject::connect(&app, SIGNAL(unixSignal(int)),
                         &app, SLOT(quit()));
        app.watchUnixSignal(SIGINT, true);
        app.watchUnixSignal(SIGTERM, true);
    }

    ... 

    return app.exec();
}

However, this does not work. CTRL-C seems to be caught (the application doesn't get killed), but it also doesn't exit. What am I missing?

+1  A: 

I haven't found much more about QApplication::watchUnixSignal documentation except for a one liner for Qt 4.0; especially it's not documented in later versions of Qt. Thus it looks like this functionality isn't advertised (and therefore supposed) to work. While doing it the "Qt way" is obviously nice I'd simply fall back to using the signal system call instead.

bluebrother
+1  A: 

There may be a way to do this natively with Qt -- I poked around the QKeySequence docs for a bit before giving up, but you can just use signal. I don't have Qt/C++ setup on my machine at the moment, but I do have the Python bindings.

import sys, signal
from PyQt4 import QtGui

app = QtGui.QApplication(sys.argv)
signal.signal(signal.SIGINT, signal.SIG_DFL)

sys.exit(app.exec_())

This works and will close the application when I do Ctrl-C. So I believe that your application could adapt this code and it would end up something like this:

#include <signal.h>

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

    ... // parse command line options

    if (no_gui) {
        signal(SIGINT, SIG_DFL);
    }

    ... 

    return app.exec();
}

Unfortunately, I cannot compile this so it will probably need a few fixes, but this should give you the general idea. By using the SIG_DFL handler you are instructing your program to use the default action associated with Ctrl-C.

swanson
+6  A: 

As it isn't documented, QApplication::watchUnixSignal shouldn't be used. And, from reading the code, it will not work properly when using the glib event dispatcher (which is the default on Linux).

However, in general you can safely catch Unix signals in Qt applications, you just have to write a bit of the code yourself. There is even an example in the documentation - Calling Qt Functions From Unix Signal Handlers.

Intransigent Parsnip
A: 

As Jerkface Jones mentioned, this looks like it doesn't work using the default event handler on Linux.

If Qt is using the raw Unix (non-glib) event handler, Qt will catch and absorb the ^C right away in its signal handler, but the unixSignal(int) signal won't be emitted until Qt does event processing.

If you have code running (rather than idling around waiting for Qt to send signals), then you'll need to call QApplication::processEvents() for Qt to send the signal.

Andrew