processEvents blocking on MacOS when app started from the command line
-
Hey all,
I've run into a problem where, when I start my application from the command line on MacOS, it ends up blocking on any calls to processEvents().
The application has recently been ported from Qt5 to Qt6, and is running fine on Windows and Linux, so this is a Qt6 + MacOS specific issue.
I am actually starting the application via a python script, that communicates with the app to run scripts, and do some automated testing.
However this process works fine with the Qt5 based version, just as it does on windows.
Clicking the .app from the finder runs the application fine, as does running it from Xcode.It's just that when I start it from my python script, it ends up getting blocked inside the first call to QApplication::processEvents().
The app shows in the taskbar, but does not maximize, if I manually click on the app in the taskbar it will suddenly come good.The first processEvents usage is to actually before the GUI or any windows have even been displayed, as I am doing it to flush out some events that I configure during startup.
After discovering this, I have commented out the processEvents() line, and now the application proceeds. However later on I have a QProgressDialog that can be displayed when opening a large project. My class based on QProgressDialog has some QCoreApplication::processEvents() calls in it too, and it appears all of these are also blocking.I've now commented out all these processEvents() call sites and my application is starting up and executing as expected. Well the script interface starts, and my test now now talk to the script server and run.
So whats up with processEvents() not returning when the application is started from a script or command line?
I've tried passing arguments and a timeout to processEvents, but it still never returns?
Is it related to not having a GUI displayed yet, and processEvents not working?
What would cause the app to be fine, when I click on the .app?
What about clicking in the app icon in the taskbar would cause processEvents() to stop blocking and return?Cheers,
James -
Hi,
Can you provide a minimal compilable example that reproduce this behaviour ?
-
@SGaist
I might be able to find the time to build such an example in the new few days.I know the event loop handling in Qt can be quite different on Mac v Windows,
I was hoping for some insight as to why it might not be working as expected. -
@Jammin44fm said in processEvents blocking on MacOS when app started from the command line:
It's just that when I start it from my python script, it ends up getting blocked inside the first call to QApplication::processEvents().
A typical Qt program will contain no such calls and they are discouraged by the documentation. This function should not block unless any event handler triggered blocks or recursively generates new events: if you have overrides of event handlers look there. If you must use this function and it must be non-blocking then ensure you are not passing QEventLoop::WaitForMoreEvents, see if ignoring certain classes of events help, or use the function version with a timeout.
-
OK this is actually very easy to reproduce.
I've modified the calculator example to have a processEvents() call,
From the Examples/widgets/widgets/calculator example
to be as follows...// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause #include <QApplication> #include "calculator.h" int main(int argc, char *argv[]) { qDebug("1."); QApplication app(argc, argv); qDebug("2."); // QApplication::processEvents(); // QApplication::processEvents(QEventLoop::AllEvents, 50); qDebug("3."); Calculator calc; calc.show(); return app.exec(); }
Enabling either of the process events calls and starting the application from the commend line shows the problem. Eg. The app starts and appears in the toolbar, but never maximizes to the screen correctly. Commenting out both the calls and the app starts fine.
Qt 6.5.3 Mac OS Sonoma 14.0 ( x86_64 )
Now I understand that calling processEvents() is not always recommended, but surely it should behave the same across platforms? and if I call it with a timeout argument it should not block in this manner?
Clicking the compiled calculator.app form the finder, results in the application running correctly, but running it from the command line stalls at the processEvents().- James
-
@Jammin44fm Unfortunately I do not have a Mac to use to reproduce the problem. I can confirm, as you state in the original post, this modified calculator works on a Linux build (Qt 5.15.3 and 6.6.2). This at least eliminates anything your actual application code is doing causing an endless event stream.
If you install an event filter on the QApplication you might gain some insight:
// eventmonitor.h #include <QObject> class EventMonitor : public QObject { Q_OBJECT public: EventMonitor(QObject *p = nullptr); ~EventMonitor(); protected: bool eventFilter(QObject *obj, QEvent *event) override; };
// eventmonitor.cpp #include "eventmonitor.h" #include <QDebug> EventMonitor::EventMonitor(QObject *p) : QObject(p) {} EventMonitor::~EventMonitor() {} bool EventMonitor::eventFilter(QObject *obj, QEvent *event) { qDebug() << "Event seen" << obj << event; return QObject::eventFilter(obj, event); };
// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause #include <QApplication> #include <QDebug> #include "calculator.h" #include "eventmonitor.h" int main(int argc, char *argv[]) { qDebug("1."); QApplication app(argc, argv); QObject *filter = new EventMonitor(qApp); app.installEventFilter(filter); qDebug("2."); QApplication::processEvents(); qDebug("3."); Calculator calc; calc.show(); return app.exec(); }
In my build I see only four events between "2." and "3.":
1. 2. Event seen KFontSettingsData(0x558e428c9660) 0x558e428c79b0 Event seen KHintsSettings(0x558e428c9cd0) 0x558e428ca460 Event seen KHintsSettings(0x558e428c9cd0) 0x558e428cc350 Event seen QDBusConnectionDispatchEnabler(0x558e428f7e10) 0x558e428d7b20 Event seen QSocketNotifier(0x558e428d8b50) 0x7ffcbd82d980 3. Event seen QWidget(0x7ffcbd82db50) 0x7ffcbd82d990 ...
You will obviously expect different specifics.
-
I've added in the Event watching code as per your suggestion above.
But sadly I do not get anything after "2."
My guess is that it's not even starting to process the event loop at all!
If it was starting to process the event lop then I would expect the timeout to work.If I click on the Icon in the taskbar, My Log looks like..
1. 2. Event seen Qapplication(0x7ff7b26b8650) 0x7ff7b26b83b0 Event seen Qapplication(0x7ff7b26b8650) 0x7ff7b26b83b0 Event seen Qapplication(0x7ff7b26b8650) 0x7ff7b26b83b0 Event seen Qapplication(0x7ff7b26b8650) 0x7ff7b26b83b0 3. Event seen QWidget(0x7ff7b26b8500) 0x7ff7b26b8420 ... ...
But unless I manually click on the applications icon in the taskbar it just stops at "2."
very frustrating.- James
-
@Jammin44fm
You are callingQApplication::processEvents()
before/outside of starting the Qt main event loop viaQApplication::exec()
. Unless an expert corrects me, that seems wrong/has undefined behaviour? I don't know why it seems to be OK in a UI application but not a command-line one, but I don't think you can do this. I don't think it can process events when no event loop has been started, and I don't know what it would do even if it is acceptable. -
@Jammin44fm Normally you use process events when you have differents events that can impact or slow down the main thread .
In the main file you just want to start your application.Is there even in your main file that can impact the main thread?following your code no.So you can't call QApplication::processEvents() in the main.cppNow a situation where you can use QApplication::processEvents() for instance, lets say you have an application that capture frames from the camera , display that in the UI and also send them to a server.
This in a situation where we have multiple events.Now when handling these events you can use in one of them QApplication::processEvents(), or QThread to avoid that the app freezes