PDA

View Full Version : Closing an application without killing main loop


vranki
2013-12-04, 17:11
Hi,

I'm writing an application which has to do dome network operations after user has closed the UI. Normally this is not possible, as the applications Qt main loop exits when closing the UI.

On Harmattan i found a workaround - re-starting the mainloop by calling QGuiApplication::exec(). This seems to crash on Sailfish.

The next workaround i tried to use is to create an event filter for the QGuiApplication and try to filter out the close event. QEvent::Close never happens, but QEvent::ApplicationDeactivate does. It can be used to prevent killing main loop, but unfortunately it also happens when user swipes the application to the background.

Any ideas on how can i accomplish this?

qwazix
2013-12-04, 17:15
It's not exactly what you're asking, but you could create a daemon and control it from your application via dbus, so you don't have to work around the close event.

xerxes2
2013-12-04, 17:22
I think what you want is the aboutToQuit signal which doesn't quit the mainloop until its callback returns.

http://qt-project.org/doc/qt-5.0/qtcore/qcoreapplication.html#aboutToQuit

pycage
2013-12-04, 17:48
How about


app->setQuitOnLastWindowClosed(false);


in main.cpp?

javispedro
2013-12-04, 17:48
I'm writing an application which has to do dome network operations after user has closed the UI. Normally this is not possible, as the applications Qt main loop exits when closing the UI.

Actually the reason is that closing the last window generates a quit event. See http://qt-project.org/doc/qt-4.8/qapplication.html#quitOnLastWindowClosed-prop

vranki
2013-12-04, 19:36
app->setQuitOnLastWindowClosed(false);



Does not work - the main loop still exits. Same with Harmattan.

vranki
2013-12-04, 19:47
I think what you want is the aboutToQuit signal which doesn't quit the mainloop until its callback returns.

http://qt-project.org/doc/qt-5.0/qtcore/qcoreapplication.html#aboutToQuit

I created a aboutToQuit slot like this:


// Called when app about to quit - handle upsync & quitting
void ClientLogic::aboutToQuit() {
qDebug() << Q_FUNC_INFO;
QEventLoop eventLoop;
eventLoop.exec();
}


On emulator quitting with this results in output:


virtual void ClientLogic::aboutToQuit()
The Wayland connection broke. Did the Wayland compositor die?
Killing all inferiors
Debugging has finished


Debugger just displays ??'s as stack trace so it's useless. The crash happens when eventLoop.exec() is called.

coderus
2013-12-04, 19:54
why you need this? isnt better to rewrite logics?
set event filter, catch close event, do whatever.

xerxes2
2013-12-04, 20:00
I created a aboutToQuit slot like this:


// Called when app about to quit - handle upsync & quitting
void ClientLogic::aboutToQuit() {
qDebug() << Q_FUNC_INFO;
QEventLoop eventLoop;
eventLoop.exec();
}


On emulator quitting with this results in output:


virtual void ClientLogic::aboutToQuit()
The Wayland connection broke. Did the Wayland compositor die?
Killing all inferiors
Debugging has finished


Debugger just displays ??'s as stack trace so it's useless. The crash happens when eventLoop.exec() is called.
Why are you calling eventLoop.exec()? You already has one mainloop running so just put your cleanup code in the aboutToQuit callback instead. The mainloop will not exit before the aboutToQuit callback returns. There was a bug in earlier sdk but in the latest version it works just fine.

http://talk.maemo.org/showthread.php?t=91595&highlight=abouttoquit

vranki
2013-12-04, 20:05
why you need this?


Because the application needs to synchronize it's state to a remote server when it is closed.


isnt better to rewrite logics?
set event filter, catch close event, do whatever.


I have been planning to make a separate daemon and ui, but due to limited time available i am not going to do this anytime soon.

I'd be even happy to write a patch to Qt or Sailfish itself if it is the only way and would be accepted into upstream.

coderus
2013-12-04, 20:10
install event filter

vranki
2013-12-04, 20:10
Why are you calling eventLoop.exec()? You already has one mainloop running so just put your cleanup code in the aboutToQuit callback instead. The mainloop will not exit before the aboutToQuit callback returns. There was a bug in earlier sdk but in the latest version it works just fine.


The app is single threaded - everything happens in the main event loop. Everything (signals, slots, timers, networking) is frozen during aboutToQuit() call. That's why i'd need a second event loop to do processing without exiting aboutToQuit() in main thread.

vranki
2013-12-04, 20:13
install event filter

..to which event in which object? As i wrote in the original post, i already tried it with no success.

xerxes2
2013-12-04, 20:26
The app is single threaded - everything happens in the main event loop. Everything (signals, slots, timers, networking) is frozen during aboutToQuit() call. That's why i'd need a second event loop to do processing without exiting aboutToQuit() in main thread.

Afaik you can only have one mainloop in both gtk and qt. I've never heard anything about having two.

vranki
2013-12-04, 20:35
I think the reason for newly started main loop is in qwaylandeventthread.cpp line 37:

https://qt.gitorious.org/qt/qtwayland/source/f404c9e9069b27f50aaa21493a512915acd0a57a:src/plugins/platforms/wayland_common/qwaylandeventthread.cpp#L37

When app window is closed, the Wayland connection is broken and if something (in the new mainloop?) calls readWaylandEvents(), the process is killed.

coderus
2013-12-04, 20:59
okay, event filtering seems not to work in emulator, try: app->connect( app, SIGNAL(lastWindowClosed()), app, SLOT(quit()) );
app->connect( app, SIGNAL(aboutToQuit()), app, SLOT(quit()) );

and why not to use main class destructor for this purpose?

and int retVal = app->exec();
qDebug() << "App exiting with code:" << QString::number(retVal);
//you can do whatever here
return retVal;

vranki
2013-12-04, 21:28
and why not to use main class destructor for this purpose?


//you can do whatever here


Signals, slots, networking, and all other asynchronous stuff does not work without a event loop. And i need those.

coderus
2013-12-04, 21:32
what about other methods?

uvatbc
2013-12-05, 00:04
Does not work - the main loop still exits. Same with Harmattan.

Well thats surprising - I've been using setQuitOnLastWindowClosed in Maemo, Harmattan, Windows and desktop Linux at least for the last two years in qgvdial to achieve exactly what you need: Running the application in the background.

https://code.google.com/p/qgvdial/source/browse/trunk/src/main.cpp

vranki
2013-12-05, 12:19
Well thats surprising - I've been using setQuitOnLastWindowClosed in Maemo, Harmattan, Windows and desktop Linux at least for the last two years in qgvdial to achieve exactly what you need: Running the application in the background.

https://code.google.com/p/qgvdial/source/browse/trunk/src/main.cpp

Ok, i think i'll need to create a simple test application for this issue.

vranki
2013-12-05, 13:23
I attached a simple test application to this message. It creates a sailfish app and a timer printing a message every second. Before starting the app, it calls app->setQuitOnLastWindowClosed(false).

When you close the window, the mainloop exits and messages stop appearing.

Can anyone modify it so that after closing the window it still keeps running? Is current behavior a bug?

w00t
2013-12-05, 13:48
This was a bug in the early SDK releases. Make sure you have the latest SDK.

See also: http://talk.maemo.org/showthread.php?t=91595

Note that I have no problems running this on device.

vranki
2013-12-05, 14:00
This was a bug in the early SDK releases. Make sure you have the latest SDK.


Maintenance tool reports no updates available.


See also: http://talk.maemo.org/showthread.php?t=91595

Note that I have no problems running this on device.

Could you elaborate a little.. What exactly is printed to console when you close the app by swiping down? Does the process really stay running?

w00t
2013-12-05, 14:18
Maintenance tool reports no updates available.

I don't know what to tell you, then. All I can say is that it's working fine, and I'm fairly sure we already fixed this :)

Could you elaborate a little.. What exactly is printed to console when you close the app by swiping down? Does the process really stay running?

The timer keeps running and printing. Yes.

ggabriel
2013-12-05, 15:20
I don't know what to tell you, then. All I can say is that it's working fine, and I'm fairly sure we already fixed this :)

Is there any way to tell for certain the version of the SDK, aside from Alpha? (perhaps a git revision or similar?)

Alternatively, I suggest resintalling the SDK :-D

vranki
2013-12-06, 11:01
Is there any way to tell for certain the version of the SDK, aside from Alpha? (perhaps a git revision or similar?)

Alternatively, I suggest resintalling the SDK :-D

I checked my SDK version (0.0.8-2) and Mer VM (2013.10.18-0) and they are the latest.


Can anyone give a third opinion how the app behaves on close?

vranki
2013-12-06, 13:18
I just tested in SDK with another PC and the application still behaves incorrectly:


Timer (and main loop) is still alive
Timer (and main loop) is still alive
Timer (and main loop) is still alive
Timer (and main loop) is still alive
Timer (and main loop) is still alive
app->exec() exited - main loop stopped. This should NOT happen if user closed the window. But it does.
Remote application finished with exit code 0.

vranki
2013-12-18, 15:54
The issue is now resolved. The bug was in still in latest SDK and was recently fixed by a SDK update. It also works correctly on device. Thanks for help!

mikecomputing
2013-12-22, 16:58
No I am really confused.

Because in my case my app dont leave mainloop and in my case I want it to leave :confused:



QGuiApplication *app = SailfishApp::application(argc, argv);
app->setQuitOnLastWindowClosed(true);
UDPManager *udp = new UDPManager();
QQuickView *view = SailfishApp::createView();
QObject::connect(app, SIGNAL(lastWindowClosed()), app, SLOT(quit()));
view->rootContext()->setContextProperty("version", QString(VERSION));
view->rootContext()->setContextProperty("udp", udp);
view->setSource(QString("/usr/share/harbour-push2sail/qml/push2sail.qml"));
view->showFullScreen();
res = app->exec(); // stays here even when user swipe down and window closes
delete app;
delete udp;
return res;

coderus
2013-12-22, 18:23
maybe just emulator bug. test on device and ignore emulator bug if arm build works okay :)