QEventDispatcherWin32: get rid of the hook procedure
Instead of intercepting the WM_QT_SENDPOSTEDEVENTS message in the hook procedure, we can handle it at receive points, making qt_GetMessageHook() unnecessary. Including general performance improvements, this patch fixes the issue where some applications (e.g. Ableton Live) do not call a chain of nested hooks for plugins. Fixes: QTBUG-90949 Change-Id: If8e96848392c6f10d45af2aac0567707d16af673 Reviewed-by: Oliver Wolff <oliver.wolff@qt.io> Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io> Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> Reviewed-by: Nuno Santos <nunosantos@imaginando.net> (cherry picked from commit b7e08599cc784777d06d34e49e90c2d408ab629d) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
1c02584282
commit
26e34fcb52
@ -96,7 +96,7 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
|
|||||||
|
|
||||||
QEventDispatcherWin32Private::QEventDispatcherWin32Private()
|
QEventDispatcherWin32Private::QEventDispatcherWin32Private()
|
||||||
: interrupt(false), internalHwnd(0),
|
: interrupt(false), internalHwnd(0),
|
||||||
getMessageHook(0), sendPostedEventsTimerId(0), wakeUps(0),
|
sendPostedEventsTimerId(0), wakeUps(0),
|
||||||
activateNotifiersPosted(false)
|
activateNotifiersPosted(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -251,30 +251,21 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
|
|||||||
static const UINT mask = inputQueueMask();
|
static const UINT mask = inputQueueMask();
|
||||||
if (HIWORD(GetQueueStatus(mask)) == 0)
|
if (HIWORD(GetQueueStatus(mask)) == 0)
|
||||||
q->sendPostedEvents();
|
q->sendPostedEvents();
|
||||||
|
else
|
||||||
|
d->startPostedEventsTimer();
|
||||||
return 0;
|
return 0;
|
||||||
} // switch (message)
|
} // switch (message)
|
||||||
|
|
||||||
return DefWindowProc(hwnd, message, wp, lp);
|
return DefWindowProc(hwnd, message, wp, lp);
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp)
|
void QEventDispatcherWin32Private::startPostedEventsTimer()
|
||||||
{
|
{
|
||||||
QEventDispatcherWin32 *q = qobject_cast<QEventDispatcherWin32 *>(QAbstractEventDispatcher::instance());
|
if (sendPostedEventsTimerId == 0) {
|
||||||
Q_ASSERT(q != nullptr);
|
|
||||||
QEventDispatcherWin32Private *d = q->d_func();
|
|
||||||
MSG *msg = reinterpret_cast<MSG *>(lp);
|
|
||||||
// Windows unexpectedly passes PM_NOYIELD flag to the hook procedure,
|
|
||||||
// if ::PeekMessage(..., PM_REMOVE | PM_NOYIELD) is called from the event loop.
|
|
||||||
// So, retrieve 'removed' tag as a bit field.
|
|
||||||
const bool messageRemoved = (wp & PM_REMOVE) != 0;
|
|
||||||
|
|
||||||
if (msg->hwnd == d->internalHwnd && msg->message == WM_QT_SENDPOSTEDEVENTS
|
|
||||||
&& messageRemoved && d->sendPostedEventsTimerId == 0) {
|
|
||||||
// Start a timer to deliver posted events when the message queue is emptied.
|
// Start a timer to deliver posted events when the message queue is emptied.
|
||||||
d->sendPostedEventsTimerId = SetTimer(d->internalHwnd, SendPostedEventsTimerId,
|
sendPostedEventsTimerId = SetTimer(internalHwnd, SendPostedEventsTimerId,
|
||||||
USER_TIMER_MINIMUM, NULL);
|
USER_TIMER_MINIMUM, NULL);
|
||||||
}
|
}
|
||||||
return d->getMessageHook ? CallNextHookEx(0, code, wp, lp) : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provide class name and atom for the message window used by
|
// Provide class name and atom for the message window used by
|
||||||
@ -458,14 +449,6 @@ QEventDispatcherWin32::QEventDispatcherWin32(QEventDispatcherWin32Private &dd, Q
|
|||||||
Q_D(QEventDispatcherWin32);
|
Q_D(QEventDispatcherWin32);
|
||||||
|
|
||||||
d->internalHwnd = qt_create_internal_window(this);
|
d->internalHwnd = qt_create_internal_window(this);
|
||||||
|
|
||||||
// setup GetMessage hook needed to drive our posted events
|
|
||||||
d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId());
|
|
||||||
if (Q_UNLIKELY(!d->getMessageHook)) {
|
|
||||||
int errorCode = GetLastError();
|
|
||||||
qFatal("Qt: INTERNAL ERROR: failed to install GetMessage hook: %d, %ls",
|
|
||||||
errorCode, qUtf16Printable(qt_error_string(errorCode)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QEventDispatcherWin32::~QEventDispatcherWin32()
|
QEventDispatcherWin32::~QEventDispatcherWin32()
|
||||||
@ -536,6 +519,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) {
|
if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) {
|
||||||
|
d->startPostedEventsTimer();
|
||||||
// Set result to 'true' because the message was sent by wakeUp().
|
// Set result to 'true' because the message was sent by wakeUp().
|
||||||
retVal = true;
|
retVal = true;
|
||||||
continue;
|
continue;
|
||||||
@ -865,10 +849,6 @@ void QEventDispatcherWin32::closingDown()
|
|||||||
|
|
||||||
d->closingDown = true;
|
d->closingDown = true;
|
||||||
|
|
||||||
if (d->getMessageHook)
|
|
||||||
UnhookWindowsHookEx(d->getMessageHook);
|
|
||||||
d->getMessageHook = 0;
|
|
||||||
|
|
||||||
if (d->sendPostedEventsTimerId != 0)
|
if (d->sendPostedEventsTimerId != 0)
|
||||||
KillTimer(d->internalHwnd, d->sendPostedEventsTimerId);
|
KillTimer(d->internalHwnd, d->sendPostedEventsTimerId);
|
||||||
d->sendPostedEventsTimerId = 0;
|
d->sendPostedEventsTimerId = 0;
|
||||||
|
@ -104,7 +104,6 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
friend LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
|
friend LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
|
||||||
friend LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int, WPARAM, LPARAM);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QSockNot {
|
struct QSockNot {
|
||||||
@ -154,11 +153,11 @@ public:
|
|||||||
|
|
||||||
// internal window handle used for socketnotifiers/timers/etc
|
// internal window handle used for socketnotifiers/timers/etc
|
||||||
HWND internalHwnd;
|
HWND internalHwnd;
|
||||||
HHOOK getMessageHook;
|
|
||||||
|
|
||||||
// for controlling when to send posted events
|
// for controlling when to send posted events
|
||||||
UINT_PTR sendPostedEventsTimerId;
|
UINT_PTR sendPostedEventsTimerId;
|
||||||
QAtomicInt wakeUps;
|
QAtomicInt wakeUps;
|
||||||
|
void startPostedEventsTimer();
|
||||||
|
|
||||||
// timers
|
// timers
|
||||||
WinTimerDict timerDict;
|
WinTimerDict timerDict;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user