Allow socket events processing with a foreign event loop on Windows
While a native dialog is open, the application message queue is handled by the native event loop which is external to Qt. In this case, QEventDispatcherWin32::processEvents() does not run and socket notifiers will not be activated. So, this patch moves the notifier activation code into the window procedure, which enables socket event processing with native dialogs. Task-number: QTBUG-49782 Task-number: QTBUG-48901 Change-Id: Icbdd96b2e80c50b73505f4fe74957575b83d6cf1 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com> Reviewed-by: Kai Koehne <kai.koehne@theqtcompany.com> Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>bb10
parent
e0a5f661e5
commit
02f70004c2
|
|
@ -79,6 +79,7 @@ extern uint qGlobalPostedEventsCount();
|
|||
enum {
|
||||
WM_QT_SOCKETNOTIFIER = WM_USER,
|
||||
WM_QT_SENDPOSTEDEVENTS = WM_USER + 1,
|
||||
WM_QT_ACTIVATENOTIFIERS = WM_USER + 2,
|
||||
SendPostedEventsWindowsTimerId = ~1u
|
||||
};
|
||||
|
||||
|
|
@ -309,7 +310,7 @@ static void resolveTimerAPI()
|
|||
QEventDispatcherWin32Private::QEventDispatcherWin32Private()
|
||||
: threadId(GetCurrentThreadId()), interrupt(false), closingDown(false), internalHwnd(0),
|
||||
getMessageHook(0), serialNumber(0), lastSerialNumber(0), sendPostedEventsWindowsTimerId(0),
|
||||
wakeUps(0)
|
||||
wakeUps(0), activateNotifiersPosted(false)
|
||||
{
|
||||
resolveTimerAPI();
|
||||
}
|
||||
|
|
@ -393,6 +394,7 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
|
|||
if (sn) {
|
||||
d->doWsaAsyncSelect(sn->fd, 0);
|
||||
d->active_fd[sn->fd].selected = false;
|
||||
d->postActivateSocketNotifiers();
|
||||
if (type < 3) {
|
||||
QEvent event(QEvent::SockAct);
|
||||
QCoreApplication::sendEvent(sn->obj, &event);
|
||||
|
|
@ -403,6 +405,20 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
|
|||
}
|
||||
}
|
||||
return 0;
|
||||
} else if (message == WM_QT_ACTIVATENOTIFIERS) {
|
||||
Q_ASSERT(d != 0);
|
||||
|
||||
// register all socket notifiers
|
||||
for (QSFDict::iterator it = d->active_fd.begin(), end = d->active_fd.end();
|
||||
it != end; ++it) {
|
||||
QSockFd &sd = it.value();
|
||||
if (!sd.selected) {
|
||||
d->doWsaAsyncSelect(it.key(), sd.event);
|
||||
sd.selected = true;
|
||||
}
|
||||
}
|
||||
d->activateNotifiersPosted = false;
|
||||
return 0;
|
||||
} else if (message == WM_QT_SENDPOSTEDEVENTS
|
||||
// we also use a Windows timer to send posted events when the message queue is full
|
||||
|| (message == WM_TIMER
|
||||
|
|
@ -643,6 +659,12 @@ void QEventDispatcherWin32Private::doWsaAsyncSelect(int socket, long event)
|
|||
WSAAsyncSelect(socket, internalHwnd, event ? int(WM_QT_SOCKETNOTIFIER) : 0, event);
|
||||
}
|
||||
|
||||
void QEventDispatcherWin32Private::postActivateSocketNotifiers()
|
||||
{
|
||||
if (!activateNotifiersPosted)
|
||||
activateNotifiersPosted = PostMessage(internalHwnd, WM_QT_ACTIVATENOTIFIERS, 0, 0);
|
||||
}
|
||||
|
||||
void QEventDispatcherWin32::createInternalHwnd()
|
||||
{
|
||||
Q_D(QEventDispatcherWin32);
|
||||
|
|
@ -761,16 +783,6 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
|
|||
d->queuedSocketEvents.append(msg);
|
||||
continue;
|
||||
}
|
||||
} else if (!(flags & QEventLoop::ExcludeSocketNotifiers)) {
|
||||
// register all socket notifiers
|
||||
for (QSFDict::iterator it = d->active_fd.begin(), end = d->active_fd.end();
|
||||
it != end; ++it) {
|
||||
QSockFd &sd = it.value();
|
||||
if (!sd.selected) {
|
||||
d->doWsaAsyncSelect(it.key(), sd.event);
|
||||
sd.selected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!haveMessage) {
|
||||
|
|
@ -891,6 +903,8 @@ void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
|
|||
"same socket %d and type %s", sockfd, t[type]);
|
||||
}
|
||||
|
||||
createInternalHwnd();
|
||||
|
||||
QSockNot *sn = new QSockNot;
|
||||
sn->obj = notifier;
|
||||
sn->fd = sockfd;
|
||||
|
|
@ -915,6 +929,8 @@ void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
|
|||
} else {
|
||||
d->active_fd.insert(sockfd, QSockFd(event));
|
||||
}
|
||||
|
||||
d->postActivateSocketNotifiers();
|
||||
}
|
||||
|
||||
void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier)
|
||||
|
|
@ -940,10 +956,12 @@ void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier)
|
|||
d->doWsaAsyncSelect(sockfd, 0);
|
||||
const long event[3] = { FD_READ | FD_CLOSE | FD_ACCEPT, FD_WRITE | FD_CONNECT, FD_OOB };
|
||||
sd.event ^= event[type];
|
||||
if (sd.event == 0)
|
||||
if (sd.event == 0) {
|
||||
d->active_fd.erase(it);
|
||||
else
|
||||
} else if (sd.selected) {
|
||||
sd.selected = false;
|
||||
d->postActivateSocketNotifiers();
|
||||
}
|
||||
}
|
||||
|
||||
QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
|
||||
|
|
|
|||
|
|
@ -178,7 +178,9 @@ public:
|
|||
QSNDict sn_write;
|
||||
QSNDict sn_except;
|
||||
QSFDict active_fd;
|
||||
bool activateNotifiersPosted;
|
||||
void doWsaAsyncSelect(int socket, long event);
|
||||
void postActivateSocketNotifiers();
|
||||
|
||||
QList<QWinEventNotifier *> winEventNotifierList;
|
||||
void activateEventNotifier(QWinEventNotifier * wen);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ SUBDIRS=\
|
|||
qopenglwindow \
|
||||
qrasterwindow
|
||||
|
||||
win32:!wince*:!winrt: SUBDIRS += noqteventloop
|
||||
win32:!wince:!winrt:qtHaveModule(network): SUBDIRS += noqteventloop
|
||||
|
||||
!qtHaveModule(widgets): SUBDIRS -= \
|
||||
qmouseevent_modal \
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
CONFIG += testcase
|
||||
TARGET = tst_noqteventloop
|
||||
|
||||
QT += core-private gui-private testlib
|
||||
QT += core-private network gui-private testlib
|
||||
|
||||
SOURCES += tst_noqteventloop.cpp
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@
|
|||
#include <QEvent>
|
||||
#include <QtCore/qthread.h>
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#include <QtNetwork/qtcpserver.h>
|
||||
#include <QtNetwork/qtcpsocket.h>
|
||||
#include <QtCore/qelapsedtimer.h>
|
||||
|
||||
#include <QtCore/qt_windows.h>
|
||||
|
||||
|
|
@ -47,6 +50,7 @@ private slots:
|
|||
void initTestCase();
|
||||
void cleanup();
|
||||
void consumeMouseEvents();
|
||||
void consumeSocketEvents();
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -265,6 +269,36 @@ void tst_NoQtEventLoop::consumeMouseEvents()
|
|||
|
||||
}
|
||||
|
||||
void tst_NoQtEventLoop::consumeSocketEvents()
|
||||
{
|
||||
int argc = 1;
|
||||
char *argv[] = { const_cast<char *>("test"), 0 };
|
||||
QGuiApplication app(argc, argv);
|
||||
QTcpServer server;
|
||||
QTcpSocket client;
|
||||
|
||||
QVERIFY(server.listen(QHostAddress::LocalHost));
|
||||
client.connectToHost(server.serverAddress(), server.serverPort());
|
||||
QVERIFY(client.waitForConnected());
|
||||
|
||||
QElapsedTimer elapsedTimer;
|
||||
elapsedTimer.start();
|
||||
|
||||
// Exec own message loop
|
||||
MSG msg;
|
||||
forever {
|
||||
if (elapsedTimer.hasExpired(3000) || server.hasPendingConnections())
|
||||
break;
|
||||
|
||||
if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
::TranslateMessage(&msg);
|
||||
::DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
QVERIFY(server.hasPendingConnections());
|
||||
}
|
||||
|
||||
#include <tst_noqteventloop.moc>
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_NoQtEventLoop)
|
||||
|
|
|
|||
Loading…
Reference in New Issue