Fix excess enter/leave event generation for native widgets
Native widgets have a native window each, so QPA plugin sends enter and leave events for associated QWindow whenever mouse cursor moves from one widget to another. QWidgetWindow had no context to interpret these events as moves from one widget to another, since they were sent separately. This resulted in leaves and enters for each widget in parent chain, when only the bottom child should have gotten them. Fixed by peeking into window system message queue when handling leave in QWidgetWindow and retrieving the entered window from queued enter event. Also provided a convenience function that QPA plugin can use to ensure both leave and enter events are in the event queue when moving from one QWindow to another. Task-number: QTBUG-27550 Change-Id: I74fec0ac90f6848495c2392c5f7e41624ad8aea2 Reviewed-by: Morten Johan Sørvig <morten.sorvig@digia.com> Reviewed-by: Samuel Rødal <samuel.rodal@digia.com>
This commit is contained in:
parent
f948294f5e
commit
bdc0eaae6b
@ -89,6 +89,26 @@ void QWindowSystemInterface::handleLeaveEvent(QWindow *tlw)
|
||||
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
|
||||
}
|
||||
|
||||
/*!
|
||||
This method can be used to ensure leave and enter events are both in queue when moving from
|
||||
one QWindow to another. This allows QWindow subclasses to check for a queued enter event
|
||||
when handling the leave event (\c QWindowSystemInterfacePrivate::peekWindowSystemEvent) to
|
||||
determine where mouse went and act accordingly. E.g. QWidgetWindow needs to know if mouse
|
||||
cursor moves between windows in same window hierarchy.
|
||||
*/
|
||||
void QWindowSystemInterface::handleEnterLeaveEvent(QWindow *enter, QWindow *leave)
|
||||
{
|
||||
bool wasSynchronous = QWindowSystemInterfacePrivate::synchronousWindowsSystemEvents;
|
||||
if (wasSynchronous)
|
||||
setSynchronousWindowsSystemEvents(false);
|
||||
handleLeaveEvent(leave);
|
||||
handleEnterEvent(enter);
|
||||
if (wasSynchronous) {
|
||||
flushWindowSystemEvents();
|
||||
setSynchronousWindowsSystemEvents(true);
|
||||
}
|
||||
}
|
||||
|
||||
void QWindowSystemInterface::handleWindowActivated(QWindow *tlw)
|
||||
{
|
||||
QWindowSystemInterfacePrivate::ActivatedWindowEvent *e = new QWindowSystemInterfacePrivate::ActivatedWindowEvent(tlw);
|
||||
@ -324,6 +344,16 @@ QWindowSystemInterfacePrivate::WindowSystemEvent * QWindowSystemInterfacePrivate
|
||||
return windowSystemEventQueue.takeFirstOrReturnNull();
|
||||
}
|
||||
|
||||
QWindowSystemInterfacePrivate::WindowSystemEvent *QWindowSystemInterfacePrivate::peekWindowSystemEvent(EventType t)
|
||||
{
|
||||
return windowSystemEventQueue.peekAtFirstOfType(t);
|
||||
}
|
||||
|
||||
void QWindowSystemInterfacePrivate::removeWindowSystemEvent(WindowSystemEvent *event)
|
||||
{
|
||||
windowSystemEventQueue.remove(event);
|
||||
}
|
||||
|
||||
void QWindowSystemInterfacePrivate::handleWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *ev)
|
||||
{
|
||||
if (synchronousWindowsSystemEvents) {
|
||||
|
@ -136,6 +136,7 @@ public:
|
||||
static void handleCloseEvent(QWindow *w);
|
||||
static void handleEnterEvent(QWindow *w);
|
||||
static void handleLeaveEvent(QWindow *w);
|
||||
static void handleEnterLeaveEvent(QWindow *enter, QWindow *leave);
|
||||
static void handleWindowActivated(QWindow *w);
|
||||
static void handleWindowStateChanged(QWindow *w, Qt::WindowState newState);
|
||||
|
||||
|
@ -52,7 +52,7 @@ QT_BEGIN_HEADER
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QWindowSystemInterfacePrivate {
|
||||
class Q_GUI_EXPORT QWindowSystemInterfacePrivate {
|
||||
public:
|
||||
enum EventType {
|
||||
Close,
|
||||
@ -349,6 +349,25 @@ public:
|
||||
{ const QMutexLocker locker(&mutex); impl.append(e); }
|
||||
int count() const
|
||||
{ const QMutexLocker locker(&mutex); return impl.count(); }
|
||||
WindowSystemEvent *peekAtFirstOfType(EventType t) const
|
||||
{
|
||||
const QMutexLocker locker(&mutex);
|
||||
for (int i = 0; i < impl.size(); ++i) {
|
||||
if (impl.at(i)->type == t)
|
||||
return impl.at(i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void remove(const WindowSystemEvent *e)
|
||||
{
|
||||
const QMutexLocker locker(&mutex);
|
||||
for (int i = 0; i < impl.size(); ++i) {
|
||||
if (impl.at(i) == e) {
|
||||
impl.removeAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
Q_DISABLE_COPY(WindowSystemEventList);
|
||||
};
|
||||
@ -357,6 +376,8 @@ public:
|
||||
|
||||
static int windowSystemEventsQueued();
|
||||
static WindowSystemEvent *getWindowSystemEvent();
|
||||
static WindowSystemEvent *peekWindowSystemEvent(EventType t);
|
||||
static void removeWindowSystemEvent(WindowSystemEvent *event);
|
||||
static void handleWindowSystemEvent(WindowSystemEvent *ev);
|
||||
|
||||
static QElapsedTimer eventTime;
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include <QtGui/qaccessible.h>
|
||||
#endif
|
||||
#include <private/qwidgetbackingstore_p.h>
|
||||
#include <qpa/qwindowsysteminterface_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -212,9 +213,31 @@ QPointer<QWidget> qt_last_mouse_receiver = 0;
|
||||
void QWidgetWindow::handleEnterLeaveEvent(QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::Leave) {
|
||||
QWidget *enter = 0;
|
||||
// Check from window system event queue if the next queued enter targets a window
|
||||
// in the same window hierarchy (e.g. enter a child of this window). If so,
|
||||
// remove the enter event from queue and handle both in single dispatch.
|
||||
QWindowSystemInterfacePrivate::EnterEvent *systemEvent =
|
||||
static_cast<QWindowSystemInterfacePrivate::EnterEvent *>
|
||||
(QWindowSystemInterfacePrivate::peekWindowSystemEvent(QWindowSystemInterfacePrivate::Enter));
|
||||
if (systemEvent) {
|
||||
if (QWidgetWindow *enterWindow = qobject_cast<QWidgetWindow *>(systemEvent->enter))
|
||||
{
|
||||
QWindow *thisParent = this;
|
||||
QWindow *enterParent = enterWindow;
|
||||
while (thisParent->parent())
|
||||
thisParent = thisParent->parent();
|
||||
while (enterParent->parent())
|
||||
enterParent = enterParent->parent();
|
||||
if (thisParent == enterParent) {
|
||||
enter = enterWindow->widget();
|
||||
QWindowSystemInterfacePrivate::removeWindowSystemEvent(systemEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
QWidget *leave = qt_last_mouse_receiver ? qt_last_mouse_receiver.data() : m_widget;
|
||||
QApplicationPrivate::dispatchEnterLeave(0, leave);
|
||||
qt_last_mouse_receiver = 0;
|
||||
QApplicationPrivate::dispatchEnterLeave(enter, leave);
|
||||
qt_last_mouse_receiver = enter;
|
||||
} else {
|
||||
QApplicationPrivate::dispatchEnterLeave(m_widget, 0);
|
||||
qt_last_mouse_receiver = m_widget;
|
||||
|
Loading…
x
Reference in New Issue
Block a user