I have a wxWidgets console application, and I need to handle SIGINT / SIGTERM signals to shutdown program properly.
I've tried "classic" signals handling, but it does not works:
#include <signal.h>
bool MainApp::OnInit()
{ // terminate gracefully:
// term threads, wait them for terminate, etc.
}
static void OnSignal(int sig)
{ // captured signal:
cout<<"Terminating...\r\n";
wxGetApp().OnExit();
}
bool MainApp::OnInit()
{
// init app here, create working threads, etc.
// set own handler:
cout<<"Signal set handler result: "<<signal(SIGINT,OnSignal);// returns 0
return true;// app inited successfully
}
When I send SIGINT or SIGTERM signals (using integrated CodeLite's terminal for debugging), nothing happens.
Looks like wxWidgets still does not have signal processing - at least, I've found nothing in documentation.
The question is: how to capture INT/TERM signals? (At least in Linux, but cross-platform solution is of course better).
You can't use cout nor exit the application from a signal handler, so while I don't know why it isn't called at all for you, things would only be worse, not better, if it was.
wxWidgets has private (i.e. undocumented, liable to change) wxApp::SetSignalHandler() in Unix ports which implements proper signal handling, with the handler itself just waking up the event loop and telling it to wait for the signals. If you do anything other than just setting a flag in your signal handler, this is what you should do as well.
Related
I am trying to connect a signal and slot in qt c++. What I want to achieve is that when the browser finishes rendering the page I want it to emit the signal and receive it in my slot. I initially wrote it for urlChanged() signal and it works fine but when I change it to renderProcessTerminated, it doesnt output the statements in the slot function.
The following is a snippet of the MyClass.h file where the slot is declared:
private slots:
void onRenderProcessTerminated(QWebEnginePage::RenderProcessTerminationStatus terminationStatus, int exitCode);
The following is a snippet from the constructor of MyClass.cpp file where the signal and slot are connected:
connect(ui->webEngineView, &QWebEngineView::renderProcessTerminated, this, &MyClass::onRenderProcessTerminated);
The following is the slot function onRenderProcessTerminated from MyClass.cpp (cout is a function I created to output messages in the web engine view and works fine):
void MyClass::onRenderProcessTerminated(QWebEnginePage::RenderProcessTerminationStatus terminationStatus, int exitCode) {
cout("INSIDE RENDER PROCESS TERMINATED");
}
What I want to achieve is that when the browser finishes rendering the page I want it to emit the signal
RenderProcessTerminated doesn't mean "finished rendering the page". It means that the operating system's process that was used for rendering has terminated abnormally. It happens e.g. when the renderer crashes. Qt documentation clearly states:
This signal is emitted when the render process is terminated with a non-zero exit status. terminationStatus is the termination status of the process and exitCode is the status code with which the process terminated.
In English, the verb you'd be looking for is finished instead of terminated. The former implies the latter: when a process is finished, it has terminated. But the reverse is not necessary: a process may well terminate before it's finished with its task, e.g. if it crashes, or is terminated when the parent process exits, etc. But also: the RenderProcess doesn't mean "a task of rendering something". It literally means "the operating system process that performs the rendering". That process normally must stay alive for as long as you have any web views active.
The only signal I can see that approximates what you want is QWebEngineView::loadFinished(bool ok). Try it out.
Ohterwise, for finer notifications, you'll need to inject some javascript into the view, and interact with it. It may be more effort than it's worth.
I have a launcher application which will fork and exec a Qt application when the user clicks on the relevant icon.
For visual feedback, I want to display a wait cursor from the time when the user selects an icon, until the requested app's main window is on-screen.
void RocketLauncher::onItemSelect(QListWidgetItem* item)
{
QApplication::setOverrideCursor(Qt::WaitCursor);
const AppConfig& app = getAppConfig(item);
forkAndExec(app.cwd(), app.cmd(), app.args(), app.env());
// TODO: wait until app's main window is being displayed
QApplication::restoreOverrideCursor();
}
The problem that I'm having is that in my launcher app, I get back the child process's pid from fork immediately, but it still takes some time for the child process to exec and for its main window to show up on-screen.
As such, my call to QApplication::restoreOverrideCursor() executes immediately, and there is no visual cue to the user that the application is still being launched.
Is there some way I can get signalled that the child is running?
I can see two ways to implement this:
With explicit inter-process communication. The child app can tell the launcher app once its main window has been created, for example via a DBus call, standard output, shared memory or any other of the many IPC mechanisms available. There is a startup notification library for X11 that uses explicit IPC by passing X messages, used by KDE and GNOME.
Depending on the OS and the used window manager in there, you might be able to ask the window manager for a list of opened windows and be notified when a new window is created. I don't think there is a Qt API for that, you'd need to use platform-specific code. For X11, you'd do something similar to the xwininfo program. Also, there is a LGPL-licensed KDE Frameworks API for this called KWindowSystem, which has a windowAdded signal. I haven't check on which platforms this is actually implemented, the docs suggest at least X11 and Mac OS.
I suggest you start a thread (with QtConcurrentRun and handled with QFutureWatcher) which is responsible for starting child process and waiting for the end displaying GUI. This mechanism can be done using a pipe in wich you send data from the place in child code where you believe that the GUI is displayed (catch showEvent() or the end of the MainWindow constrcutor...). The thread in parent process must sleep until receiving data on the pipe for waking up.
there is a lot of example of using pipe in linux. Also you can use Unix socket, shared memory or other IPC or maybe you can test with creatin a file in /tmp but is a bad idea.
Another simple idea is to proceed with QProcess and write from your new program some string on standard output to signal end of GUI display (to test...):
bool Class::startExternalProgram(QString _file)
{
QtConcurrent::run(this, &Class::starting, _file);
return true;
}
bool Class::starting(QString file)
{
QProcess *p = new QProcess;
params << file;
p->start("your program", params);
if (!p->waitForStarted(5000)) {
p->close();
delete p;
crashFinish(1, QProcess::CrashExit);
return false;
}
else {
processes.push_back(p);
/*to handle crash*/
QObject::connect(p, SIGNAL(finished(int,QProcess::ExitStatus)),
this, SLOT(crashFinish(int, QProcess::ExitStatus)));
p->waitForReadyRead(600000);/*10mn*/
... /*handle timeout here*/
return true;
}
}
void Class::crashFinish(int, QProcess::ExitStatus) {
auto p = qobject_cast<QProcess*>(QObject::sender());
...
}
I would like to ask what is the signal that is called when the user logs out? I have a Qt gui app that has handler for SIGTERM and SIGHUP signals. The app also has its own close event handler, so user can't close it by clicking on "X". The problem is that when the user logs out then the ubuntu hangs (the icon from taskbar disappears but the process keeps running) and does not let the user log out because (imo) it waits for the process to be terminated. When I use kill -15 'myapp' command then the app closes normally as it is supposed to so the problem shouldn't be in my handler.
static int setupHandlers(){
struct sigaction hup,term;
hup.sa_handler = signalHandler;
sigemptyset(&hup.sa_mask);
hup.sa_flags = 0;
if (sigaction(SIGHUP, &hup, 0) > 0){
return 1;
}
term.sa_handler = signalHandler;
sigemptyset(&term.sa_mask);
if (sigaction(SIGTERM, &term, 0) > 0){
return 2;
}
return 0;
}
signalHandler just calls exit(0) (also tried _exit(0) and abort())
There are 3 standart terminating signals, that you can handle - SIGINT, SIGQUIT and SIGTERM. Try to subscribe to each one of them and look.
signalHandler just calls exit(0) (also tried _exit(0) and abort())
You rather need to tell Qt to exit. Your signal handler need to have a reference on the application object and call QCoreApplication::exit(0);.
Whether it is by SIGTERM or by the user user input, your application need to nicely handle termination requests. In particular ensure that all objects which launch a process or a thread are cleanly destroyed when it happens. The classic code inspired from QtCreator :
d->m_guiProcess.terminate();
if (!d->m_guiProcess.waitForFinished(1000)) { // This is blocking, so be fast.
d->m_guiProcess.kill();
d->m_guiProcess.waitForFinished();
}
The code executing this need to stop, so it first forward nicely a SIGTERM (terminate), wait for small amount of time and then ask rudely with a SIGKILL (kill).
I've been trying to figure out how to make the program stop in a for-loop and wait for a button to be clicked and the for-loop continues.
Isn't there any easy way to stop the loop like QSystem.stop() and in the button clicked function QSystem.star() and the loop continues.
In C++ you could use system("pause") or the program stopped when you used a cin<<. But how do i do this in QT?
Since the userinterface needs its code to run, if you halt event loop (which also means that any function that gets called from within the event loop is blocking, waiting for some event), you also halt the user interface, which means clicks into the window won't be processed. That's why in event based programming, which is what all UI kits do, it is essential to return to the main event handler loop as quickly as possible.
What you can do is create a second thread and wait on a condition variable. The GUI thread can signal that condition variable in the button click event slot.
In C++ you could use system("pause") or the program stopped
Exactly: The program is stopped. Which means it won't fetch events from the operating system. However receiving data from stdin is not an event. It's blocking on streamed I/O. Graphical user interfaces are event based though.
Note that conceptually it's not really impossible to think of a user interface to provide streaming I/O channels. However that doesn't work in single threaded programs. You need parallel execution (coroutines, threads, or such) for a concept like this to work.
You don't need threads, nested event loop will do the job.
int waitUntilSignalIsEmitted(QObject *sender, const char *signal) {
QEventLoop loop;
connect(sender, signal,
&loop, SLOT(quit()));
return loop.exec();
}
// usage:
while(yourLoopCondition) {
// some stuff
...
// pause here
waitUntilSignalIsEmitted(yourContinuationButton, SIGNAL(clicked()));
// loop continuation
...
}
I am porting a Linux app to Windows written in Qt. The application needs to save some settings before closing. On Linux, we can do that by signal handlers for SIGTERM etc. How can I implement the same on Windows.
If you are using the Qt event loop, you can catch the following signal:
void QCoreApplication::aboutToQuit() [signal]
This signal is emitted when the application is about to quit the main event loop, e.g. when the event loop level drops to zero. This may happen either after a call to quit() from inside the application or when the users shuts down the entire desktop session.
The signal is particularly useful if your application has to do some last-second cleanup. Note that no user interaction is possible in this state.
Other than that, you may be looking for the following messages below if the aforementioned signal is not appropriate for your use case:
WM_QUIT: http://msdn.microsoft.com/en-us/library/windows/desktop/ms632641(v=vs.85).aspx
WM_CLOSE: http://msdn.microsoft.com/en-us/library/windows/desktop/ms632617(v=vs.85).aspx
WM_QUERYENDSESSION: http://msdn.microsoft.com/en-US/library/windows/desktop/aa376890.aspx
WM_ENDSESSION: http://msdn.microsoft.com/en-US/library/windows/desktop/aa376889.aspx
I think the other answers completely miss the point: When you forcibly end an application, it's like SIGKILL on Unix. There's no way to handle it - except ahead of time. What I mean by handling it ahead of time is making sure that you save the settings every time they are changed. Of course you can optimize this behavior, for example save the settings every few seconds if they are dirty, if you want to minimize the number of disk accesses (think power consumption on mobile devices).
A lot of this is handled by QSettings for you. As long as you use QSettings, you'll get reasonable behavior. If you're saving files yourself, use QSaveFile as it deals with flushing the file and approximating atomic file replacement, so that you won't lose the settings if the kill (forced termination) comes in the middle of you doing the writing.
The aboutToQuit signal emitted by QCoreApplication is what you want to react to if you want to simply do something when the application being asked to quit. This is equivalent to handling the WM_QUIT message, or dealing with SIGTERM on Unix. So doing it in platform-specific way is pointless as Qt does it for you already. There's equally no point in handling WM_CLOSE since that's a message that only windows get, and again Qt already handles it for you.
You can also participate in the logoff/shutdown process by installing a QAbstractNativeEventFilter and processing the WM_ENDSESSION and WM_QUERYENDSESSION. This only makes sense if you want to know ahead of time that the application will be quit. Unless you explicitly want to stop the shutdown/logoff, you don't need to worry about it.
I think it might be better to handle the QApplication::commitDataRequest signal (or QGuiApplication::commitDataRequest in Qt5) instead of aboutToQuit. Just connect the signal to your function for saving settings.
Here are some related discussions: http://qt-project.org/forums/viewthread/33329
session logoff will emit aboutToQuit
case WM_ENDSESSION: {
sm_smActive = false;
sm_blockUserInput = false;
bool endsession = (bool) wParam;
// we receive the message for each toplevel window included internal hidden ones,
// but the aboutToQuit signal should be emitted only once.
QApplicationPrivate *qAppPriv = QApplicationPrivate::instance();
if (endsession && !qAppPriv->aboutToQuitEmitted) {
qAppPriv->aboutToQuitEmitted = true;
int index = QApplication::staticMetaObject.indexOfSignal("aboutToQuit()");
qApp->qt_metacall(QMetaObject::InvokeMetaMethod, index,0);
// since the process will be killed immediately quit() has no real effect
QApplication::quit();
}
RETURN(0);
}
I do not know Qt. If you can afford to be Windows only WM_QUERYENDSESSION and WM_ENDSESSION messages might be the right thing to do.