QApplication and handling X server shutdown - qt

I have a Qt application that runs on a linux machine that displays UI windows on a Windows machine running an X server. There's a strong possibility that the users of my application will logout of Windows or kill the X server without quitting my application first.
Is there a way to handle the unexpected shutdown of the X server, so that the application can gracefully shutdown, save stored data, etc? So far I've tried tying QApplication's aboutToQuit signal to a slot in my app, plus catching all exceptions in main. Neither worked as I expected.

I think your best bet is to attempt to handle it via signal handling
depending on how application is being killed by the OS, exiting gracefully may or may not be possible at all.

I'm not sure, but maybe this QCoreApplication::aboutToQuit() signal can help you.

If connection with the X server is lost then libX11 inside the application calls _XIOError() function that calls _XDefaultError handler that calls exit(). It is possible to override that with a custom handler:
#include <X11/Xlib.h>
static int handler(Display *dpy)
{
/*
* cleanup
* ...
*/
exit(1);
return 0;
}
...
int main(int argc, char** argv)
{
QApplication app(argc, argv);
XSetIOErrorHandler(handler);
...
It's better to still call exit() in the handler because Qt will segfault anyway without a proper X connection.

Related

Detect QApplication exit as normal or crash

I need to detect the application get exit as normal or crash. QProcess have the finished() signal and can get the exit code. But i need this exit code for QApplication when the application get crash or close.
When your process crashes, it's gone. The crash means that the process has finished because of an unhandled exception. Your job should be to prevent the crash from happening. In other words: handle the exceptions. Note that the exceptions may not be C++ exceptions, they may be low-level platform-specific mechanisms, such as native exceptions on Windows or signals on UNIX. You'd have to handle those, but recognize that the underlying issue is not fixed merely because you catch such an exception. You must assume that the state of your application has been corrupted, and the only safe thing to do is to exit ASAP anyway. For example, do not try to modify any files: you're likely to corrupt them.
I don't think this is something you can do just like that. Reading the value returned by QApplication::exec() is related to the Qt infrastructure:
Enters the main event loop and waits until exit() is called, then
returns the value that was set to exit() (which is 0 if exit() is
called via quit()).
Usually your main looks like this:
#include <QApplication>
int main( int argc, char **argv )
{
QApplication a( argc, argv );
// Initialize your widget(s)
return a.exec(); // You can store this and check its value
}
However if I'm not mistaken this doesn't include handling a crash of your application (segmentation fault, unhandled exception etc.). In Linux people usually use a script which starts the application and then reads its exit code after the application quits or crashes. If you use Linux you can use echo $? to read the exit code from the bash scrip (or its equivalent for a different shell) and then do something based on its value.
Note also that you can at least do some exception handling since some crashes result in exactly that - an exception that has been thrown for some reason and has not been processed properly. Unhandled exceptions in Qt get propagated to the top level (that is QCoreApplication).

QtConcurrent::run => QWaitCondition: Destroyed while threads are still waiting

I have the message "QWaitCondition: Destroyed while threads are still waiting" following the launch of N threads in a loop, and waiting for each in another loop.
Here is the code :
int nb_threads = QThread::idealThreadCount();
QFuture<void> futures[nb_threads];
bool shared_boolean;
// launch threads
for(int i = 0;i<nb_threads;++i){
futures[i] = QtConcurrent::run(this,gpMainLoopMT,&shared_boolean,&next_pop_size,next_population);
}
// wait for threads to finish
for(int i = 0;i<nb_threads;++i){
futures[i].waitForFinished();
}
I just can't figure out why this is happening, while I am waiting for each thread.
Actually I had the same warning when using Qt in a DLL. Windows kills all threads at application exit, before the DLL's global objects are destroyed. A global object destructor is where I was deleting the QApplication instance. This leads to an inconsistency because the QWaitConditions still think a thread is waiting, when in fact the native thread isn't running anymore, killed by Windows with no chance of proper cleanup. That's what leads to this warning.
It's unfixable, even in Qt. Windows doesn't give us any chance to perform any cleanup, the threads just disappear.
You're not waiting for the threads, you're waiting for the tasks.
The threads keep running until QApplication deletes the global QThreadPool instance. So the question is - are you leaking QApplication or destroying it properly?

Qt SSL: Handshake failed for requests made from QML

I make some https requests directly from my qml views, for instance for image sources. As I have a self signed certificate server side, I need to tell qt to ignore some ssl errors (I control both the server and the client applications, so this shouldn't really be a problem).
I've made a QQmlNetworkAccessManagerFactory to create NAMs, where I connect to the sslErrors signal.
UltraQmlAccessManagerFactory.h:
#ifndef FACKFACKTORy_H
#define FACKFACKTORy_H
#include <QQmlNetworkAccessManagerFactory>
#include <QObject>
#include <QNetworkReply>
#include <QList>
#include <QSslError>
#include <QNetworkAccessManager>
#include <QDebug>
#include <QSslCertificate>
class UltraQmlNetworkAccessManagerFactory : public QObject,
public QQmlNetworkAccessManagerFactory {
Q_OBJECT
private:
QNetworkAccessManager* nam;
QList<QSslError> expectedSslErrors;
public:
explicit UltraQmlNetworkAccessManagerFactory();
~UltraQmlNetworkAccessManagerFactory();
virtual QNetworkAccessManager* create(QObject* parent);
public slots:
void onIgnoreSslErrors(QNetworkReply* reply, QList<QSslError> errors);
};
#endif
UltraQmlNetworkAccessManagerFactory.cpp:
#include "UltraQmlNetworkAccessManagerFactory.h"
UltraQmlNetworkAccessManagerFactory::UltraQmlNetworkAccessManagerFactory() {
}
UltraQmlNetworkAccessManagerFactory::~UltraQmlNetworkAccessManagerFactory() {
delete nam;
}
QNetworkAccessManager* UltraQmlNetworkAccessManagerFactory::create(QObject* parent) {
QNetworkAccessManager* nam = new QNetworkAccessManager(parent);
QObject::connect(nam, SIGNAL(sslErrors(QNetworkReply*, QList<QSslError>)),
this, SLOT(onIgnoreSslErrors(QNetworkReply*,QList<QSslError>))
);
return nam;
}
void UltraQmlNetworkAccessManagerFactory::onIgnoreSslErrors(QNetworkReply *reply, QList<QSslError> errors) {
for (int i = 0; i < errors.size(); i++) {
qDebug() << "e: " << errors.at(i) << endl;
}
reply->ignoreSslErrors(errors);
}
There is also some glue in main.cpp that sets this factory to be used, I doubt that part is a source of errors as the qDebug prints are visible in the output.
As can be seen in the .cpp file in the function/slot onIgnoreSslErrors, I try to ignore every error (as a test) that I receive, but in the output I do not get the expected results.
Output
e: "The certificate is self-signed, and untrusted"
qrc:/qml/file/ImageView.qml:16:5: QML Image: SSL handshake failed
I have successfully made QNetworkRequests from C++ directly with a QSslConfiguration, specifying TLSV1_0 and a certificate. As I have a suspicion that the handshake fails because one side expects SSL and the other TLS I have also tried to set the QSslConfiguration on the QNetworkRequest object throgh reply->request(); This, however, changes nothing.
(This is a very old one but as I stumbled over this recently and haven't found the answer, I think it's still worth answering)
You don't show the place where you actually setup the factory object but it is extremely likely that it does not belong to the same (actually, any) thread used when its create() method is called. Here's an excerpt from the Qt documentation on the class:
the developer should be careful if the signals of the object to be returned from create() are connected to the slots of an object that may be created in a different thread
It further mentions authenticationRequired() signal but sslErrors() acts in the same way: both signals, among a few others, need either a direct or a blocking queued connection so that by the time of returning to the place of emitting the signal the network reply object has already been configured by the slot.
What happens in your case is (very likely) the following (TL;DR: your slot is called asynchronously by a queued connection because it lives in a different thread, while sslErrors() requires a synchronous change to the running network reply object; despite the order of log lines, the request fails first and ignoreSslErrors() is called later):
The factory object is created, and the QML engine configured, in the main thread.
QML engine spawns a few threads to perform backend stuff, notably network requests for URLs (I'm making the assumption here that your ImageView.qml has an Image component). To perform the network request, these threads call UltraQmlNetworkAccessManagerFactory::create().
create() produces a NAM object and sets up a connection on it. The parent here is either the QQmlEngine object or (specifically for image requests) the backend thread object, as you can see e.g. here. Therefore, this NAM object belongs to the backend thread.
connect() uses Qt::AutoConnection type by default, which, since the threads of the factory and of the NAM object are different, corresponds to Qt::QueuedConnection. As a sidenote, the threads are checked at the time of signal invocation.
Eventually a QNetworkAccessManager::sslErrors() signal is emitted. Since this is a queued connection, the only thing that immediately happens is placing an invocation of onIgnoreSslErrors() on the event queue for the main thread.
If you're very lucky, you may have a context switch to the main thread right after that - but there's literally nothing to ensure that so it's much more likely that control returns to the site where QNetworkAccessManager::sslErrors() was emitted. And since ignoreSslErrors() wasn't called, the request fails the handshake. The backend thread posts relevant data from the (failed) QNetworkReply object back to the main thread - see the postReply call in the middle of the method (or it may do it a bit later - that doesn't matter anymore).
Once the context switches to the main thread ignoreSslErrors() is executed - alas, it's already too late, as the network reply has very likely finished with failure already; but that first log line comes out now.
The main thread goes on through the event loop and finds the QQuickPixmapReply::Event object with the failure data. After some unroll of the calls and signals the failed image ends up in QQuickImageBase::requestFinished() that prints the second log line for you .
As for the fix, it's tempting to just specify Qt::BlockingQueuedConnection as the fifth parameter to connect(). Unfortunately, this will deadlock if a request is ever made from QQmlEngine that runs in the main thread - and uses a NAM instance created by this factory to, e.g., request QML components over the network. Best I could come out with so far is an equivalent of
connect(nam, SIGNAL(sslErrors(QNetworkReply*, QList<QSslError>)),
this, SLOT(onIgnoreSslErrors(QNetworkReply*,QList<QSslError>)),
currentThread() == this->thread() ? Qt::DirectConnection
: Qt::BlockingQueuedConnection
);

Application is not restarting on device In Qt

I am developing an application on Qt symbian, in which I have to restart my application within my application, have used:
qApp->quit();
QProcess::startDetached(qApp->arguments()[0],qApp->arguments());
from a method in mainWindow. It is working fine on simulator but not on device, it closes but not restarting by itself, I have to restart it by myself, is there anything else I have to do to make it work on device.
One solution would be to create small console process that you can launch from your main program before closing it. Then this console process would just launch your program and close.
I have been using this kind of processes to keep track of my apps and restart them when they crash.
One minor but fundamental thing: on Symbian there is an emulator and not a simulator. The difference is that the later simulates the device on the assembly level while the former does it only on API support level. For example iPhone simulator simulates the phone on assembly level. Contrarily in Symbian the underlying API implementation might be and is completely different for the ARM and for the WINS architecture. Especially in such cases when you interact with the OS like exiting the application.
The application quit operation on Symbian is eventually implemented by throwing a special exception (I don't remember it's name, something like KExitException) that is caught by the main Active Scheduler loop that tells the kernel to shut down the process. In other words it means that it is a synchronous call. If you first call quit then startProcess then the later will be never executed. It is not that clear why does not it work if you first call startProcess and then quit: this might be an asynchronous call that can not complete before you exit, or you simple can not start the same (GUI) application in two instances. Anyway check the return value of startProcess to see whether it succeeded or not.
Your ultimate solution will be to create a watchdog process as #Riho suggested. You start the watchdog process before you call quit, in the watchdog main function you wait some seconds and restart your application. You will need SwEvent capability for your watchdog.
I have tried it with Qprocess() and it seems to be working fine (still testing for memory and thread issues)
in main.cpp I write this code (which I got from other link )
int main(int argc, char *argv[])
{
#define RESTART_CODE 1000
int return_from_event_loop_code;
QPointer<QApplication> app;
QPointer<MainWindow> main_window;
do
{
if(main_window) delete main_window;
if(app) delete app;
app = new QApplication(argc, argv);
main_window = new MainWindow;
QList<QString> lang = AppStatus::getCurrentLanguage();
QTranslator translator;
translator.load(lang.at(0));
app->installTranslator(&translator);
main_window->setOrientation(MainWindow::ScreenOrientationLockPortrait);
#if defined(Q_OS_SYMBIAN)
main_window->showMaximized();
#else
main_window->show();
#endif
return_from_event_loop_code = app->exec();
}
while(return_from_event_loop_code==RESTART_CODE);
return return_from_event_loop_code;
}
and in my method from where I have to restart my app I have written this.
QProcess::startDetached(qApp->applicationFilePath(),qApp->arguments());
qApp->exit(RESTART_CODE);
And my app is restarting like I wanted.. If any changes nedded plese let me know.

How to handle system buttons click in Qt console application

I want to create a console application in Qt which handles Close, Minimize and Maximize buttons of the console window. My goal is just to show some message before the application quits - i.e. Close button is clicked.
Further, I want the application to be minimized to the system tray instead of task bar. However, it seems there are no signals or events which I can process when user clicks on one of the system buttons.
Is it even possible?
I do not think you can handle such "signals" (minimize, maximize, and close the terminal window running a QCoreApplication) through the APIs provided by Qt.
But QCoreApplication sends a signal called aboutToQuit(). Probably you can use it to do what you want (write in the terminal, for example), just do not know if the user will be able to read in time.
About minimize the application to the tray: Again, probably not possible to do it in a terminal application using the Qt APIs. But it is perfectly possible in a QApplication (which has a window). See this answer to a similar SO question.
You can use POSIX signals both in Linux and Windows
#include
void quit_handle( int ) {
qApp->quit();
}
int main( int argc, char *argv[] ) {
QCoreApplication a(argc, argv);
...
signal( SIGINT, quit_handle );
return a.exec();
}
I tested it only in Windows+MinGW, but I think it would work in Linux too
Are you using a Unix / Linux or a Windows?
If you are using Unix or Linux you might want to look into the Posix / Unix Signals.
They do not offer any solution to the maximize / minimize buttons,
but they give you the possibility to at least catch the System Signal when you hit the close button. From my experience, the aboutToQuit() Signal is not as fast as a custom override of the Signal Handler.
As soon as you catch the Signal you can process it yourself.
Here's a good tutorial for the Custom Signal Handlers:
http://doc.qt.io/qt-5/unix-signals.html

Resources