summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGatis Paeglis <gatis.paeglis@qt.io>2018-09-19 11:40:31 +0200
committerGatis Paeglis <gatis.paeglis@qt.io>2018-10-16 06:57:01 +0000
commit00ae1e6b7bf6efa5f5e57d37844e44d521604fb6 (patch)
tree7e6c8177f2f9796b30df490f8d582d6668d9f9fa
parentdd8a66daa497f0547f2fcddc0ee1e722d13ab98b (diff)
xcb: respect QEventLoop::ExcludeUserInputEvents in native event handlers
This was a regression from Qt 4. Before this patch, we supported filtering events only at QWindowSystemInterface level, but to properly support filtering in QAbstractEventDispatcher::filterNativeEvent, we have to filter the events earlier. Now it is possible to enable/disable this feature for platforms that support native event filtering. The mapping of which events are user input events were taken from QWindowSystemInterfacePrivate::EventType. Task-number: QTBUG-69687 Change-Id: I9a5fb9f999451c47abcdc83fdcc129b5eeb55447 Reviewed-by: Paul Wicking <paul.wicking@qt.io> Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r--src/gui/kernel/qwindowsysteminterface.cpp29
-rw-r--r--src/gui/kernel/qwindowsysteminterface.h1
-rw-r--r--src/gui/kernel/qwindowsysteminterface_p.h1
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp54
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h4
-rw-r--r--src/plugins/platforms/xcb/qxcbeventdispatcher.cpp7
-rw-r--r--src/plugins/platforms/xcb/qxcbeventqueue.cpp29
-rw-r--r--src/plugins/platforms/xcb/qxcbeventqueue.h5
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp2
-rw-r--r--src/widgets/kernel/qwidget.cpp14
10 files changed, 126 insertions, 20 deletions
diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp
index 07ece5689e..67e1283462 100644
--- a/src/gui/kernel/qwindowsysteminterface.cpp
+++ b/src/gui/kernel/qwindowsysteminterface.cpp
@@ -57,6 +57,7 @@ QT_BEGIN_NAMESPACE
QElapsedTimer QWindowSystemInterfacePrivate::eventTime;
bool QWindowSystemInterfacePrivate::synchronousWindowSystemEvents = false;
+bool QWindowSystemInterfacePrivate::platformFiltersEvents = false;
bool QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse = true;
QWaitCondition QWindowSystemInterfacePrivate::eventsFlushed;
QMutex QWindowSystemInterfacePrivate::flushEventMutex;
@@ -1047,10 +1048,15 @@ bool QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::ProcessEventsFla
int nevents = 0;
while (QWindowSystemInterfacePrivate::windowSystemEventsQueued()) {
- QWindowSystemInterfacePrivate::WindowSystemEvent *event =
- (flags & QEventLoop::ExcludeUserInputEvents) ?
- QWindowSystemInterfacePrivate::getNonUserInputWindowSystemEvent() :
- QWindowSystemInterfacePrivate::getWindowSystemEvent();
+ QWindowSystemInterfacePrivate::WindowSystemEvent *event = nullptr;
+
+ if (QWindowSystemInterfacePrivate::platformFiltersEvents) {
+ event = QWindowSystemInterfacePrivate::getWindowSystemEvent();
+ } else {
+ event = flags & QEventLoop::ExcludeUserInputEvents ?
+ QWindowSystemInterfacePrivate::getNonUserInputWindowSystemEvent() :
+ QWindowSystemInterfacePrivate::getWindowSystemEvent();
+ }
if (!event)
break;
@@ -1089,6 +1095,21 @@ bool QWindowSystemInterface::nonUserInputEventsQueued()
return QWindowSystemInterfacePrivate::nonUserInputEventsQueued();
}
+/*!
+ Platforms that implement UserInputEvent filtering at native event level must
+ set this property to \c true. The default is \c false, which means that event
+ filtering logic is handled by QWindowSystemInterface. Doing the filtering in
+ platform plugins is necessary when supporting AbstractEventDispatcher::filterNativeEvent(),
+ which should respect flags that were passed to event dispatcher's processEvents()
+ call.
+
+ \since 5.12
+*/
+void QWindowSystemInterface::setPlatformFiltersEvents(bool enable)
+{
+ QWindowSystemInterfacePrivate::platformFiltersEvents = enable;
+}
+
// --------------------- QtTestLib support ---------------------
// The following functions are used by testlib, and need to be synchronous to avoid
diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h
index 6bf6ee645c..1dde9130ac 100644
--- a/src/gui/kernel/qwindowsysteminterface.h
+++ b/src/gui/kernel/qwindowsysteminterface.h
@@ -292,6 +292,7 @@ public:
static void deferredFlushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags);
static int windowSystemEventsQueued();
static bool nonUserInputEventsQueued();
+ static void setPlatformFiltersEvents(bool enable);
};
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h
index 492f559f22..9cb4e191cc 100644
--- a/src/gui/kernel/qwindowsysteminterface_p.h
+++ b/src/gui/kernel/qwindowsysteminterface_p.h
@@ -525,6 +525,7 @@ public:
public:
static QElapsedTimer eventTime;
static bool synchronousWindowSystemEvents;
+ static bool platformFiltersEvents;
static QWaitCondition eventsFlushed;
static QMutex flushEventMutex;
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index c1f0b71414..a4294956c1 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -1020,11 +1020,10 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
printXcbEvent(lcQpaEvents(), "Event", event);
long result = 0; // Used only by MS Windows
- QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance();
- bool handledByNativeEventFilter = dispatcher && dispatcher->filterNativeEvent(
- m_nativeInterface->nativeEventType(), event, &result);
- if (handledByNativeEventFilter)
- return;
+ if (QAbstractEventDispatcher *dispatcher = QAbstractEventDispatcher::instance()) {
+ if (dispatcher->filterNativeEvent(m_nativeInterface->nativeEventType(), event, &result))
+ return;
+ }
uint response_type = event->response_type & ~0x80;
@@ -1451,7 +1450,47 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event) const
return false;
}
-void QXcbConnection::processXcbEvents()
+bool QXcbConnection::isUserInputEvent(xcb_generic_event_t *event) const
+{
+ auto eventType = event->response_type & ~0x80;
+ bool isInputEvent = eventType == XCB_BUTTON_PRESS ||
+ eventType == XCB_BUTTON_RELEASE ||
+ eventType == XCB_KEY_PRESS ||
+ eventType == XCB_KEY_RELEASE ||
+ eventType == XCB_MOTION_NOTIFY ||
+ eventType == XCB_ENTER_NOTIFY ||
+ eventType == XCB_LEAVE_NOTIFY;
+ if (isInputEvent)
+ return true;
+
+#if QT_CONFIG(xcb_xinput)
+ if (connection()->hasXInput2()) {
+ isInputEvent = isXIType(event, m_xiOpCode, XCB_INPUT_BUTTON_PRESS) ||
+ isXIType(event, m_xiOpCode, XCB_INPUT_BUTTON_RELEASE) ||
+ isXIType(event, m_xiOpCode, XCB_INPUT_MOTION) ||
+ isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_BEGIN) ||
+ isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE) ||
+ isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_END) ||
+ isXIType(event, m_xiOpCode, XCB_INPUT_ENTER) ||
+ isXIType(event, m_xiOpCode, XCB_INPUT_LEAVE) ||
+ // wacom driver's way of reporting tool proximity
+ isXIType(event, m_xiOpCode, XCB_INPUT_PROPERTY);
+ }
+ if (isInputEvent)
+ return true;
+#endif
+
+ if (eventType == XCB_CLIENT_MESSAGE) {
+ auto clientMessage = reinterpret_cast<const xcb_client_message_event_t *>(event);
+ if (clientMessage->format == 32 && clientMessage->type == atom(QXcbAtom::WM_PROTOCOLS))
+ if (clientMessage->data.data32[0] == atom(QXcbAtom::WM_DELETE_WINDOW))
+ isInputEvent = true;
+ }
+
+ return isInputEvent;
+}
+
+void QXcbConnection::processXcbEvents(QEventLoop::ProcessEventsFlags flags)
{
int connection_error = xcb_connection_has_error(xcb_connection());
if (connection_error) {
@@ -1461,13 +1500,14 @@ void QXcbConnection::processXcbEvents()
m_eventQueue->flushBufferedEvents();
- while (xcb_generic_event_t *event = m_eventQueue->takeFirst()) {
+ while (xcb_generic_event_t *event = m_eventQueue->takeFirst(flags)) {
QScopedPointer<xcb_generic_event_t, QScopedPointerPodDeleter> eventGuard(event);
if (!(event->response_type & ~0x80)) {
handleXcbError(reinterpret_cast<xcb_generic_error_t *>(event));
continue;
}
+
if (compressEvent(event))
continue;
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 3fb64f01a4..96591c7994 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -475,6 +475,8 @@ public:
Qt::MouseButtons queryMouseButtons() const;
Qt::KeyboardModifiers queryKeyboardModifiers() const;
+ bool isUserInputEvent(xcb_generic_event_t *event) const;
+
#if QT_CONFIG(xcb_xinput)
void xi2SelectStateEvents();
void xi2SelectDeviceEvents(xcb_window_t window);
@@ -495,7 +497,7 @@ public:
QXcbGlIntegration *glIntegration() const;
void flush() { xcb_flush(m_connection); }
- void processXcbEvents();
+ void processXcbEvents(QEventLoop::ProcessEventsFlags flags);
protected:
bool event(QEvent *e) override;
diff --git a/src/plugins/platforms/xcb/qxcbeventdispatcher.cpp b/src/plugins/platforms/xcb/qxcbeventdispatcher.cpp
index 252c1c62e3..3cb2a5b5ef 100644
--- a/src/plugins/platforms/xcb/qxcbeventdispatcher.cpp
+++ b/src/plugins/platforms/xcb/qxcbeventdispatcher.cpp
@@ -58,7 +58,7 @@ QXcbUnixEventDispatcher::~QXcbUnixEventDispatcher()
bool QXcbUnixEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
{
const bool didSendEvents = QEventDispatcherUNIX::processEvents(flags);
- m_connection->processXcbEvents();
+ m_connection->processXcbEvents(flags);
// The following line should not be necessary after QTBUG-70095
return QWindowSystemInterface::sendWindowSystemEvents(flags) || didSendEvents;
}
@@ -99,9 +99,10 @@ static gboolean xcbSourceCheck(GSource *source)
static gboolean xcbSourceDispatch(GSource *source, GSourceFunc, gpointer)
{
auto xcbEventSource = reinterpret_cast<XcbEventSource *>(source);
- xcbEventSource->connection->processXcbEvents();
+ QEventLoop::ProcessEventsFlags flags = xcbEventSource->dispatcher->flags();
+ xcbEventSource->connection->processXcbEvents(flags);
// The following line should not be necessary after QTBUG-70095
- QWindowSystemInterface::sendWindowSystemEvents(xcbEventSource->dispatcher->flags());
+ QWindowSystemInterface::sendWindowSystemEvents(flags);
return true;
}
diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.cpp b/src/plugins/platforms/xcb/qxcbeventqueue.cpp
index d7d70536a0..20589fc550 100644
--- a/src/plugins/platforms/xcb/qxcbeventqueue.cpp
+++ b/src/plugins/platforms/xcb/qxcbeventqueue.cpp
@@ -114,6 +114,35 @@ QXcbEventQueue::~QXcbEventQueue()
qCDebug(lcQpaEventReader) << "nodes on heap:" << m_nodesOnHeap;
}
+xcb_generic_event_t *QXcbEventQueue::takeFirst(QEventLoop::ProcessEventsFlags flags)
+{
+ // This is the level at which we were moving excluded user input events into
+ // separate queue in Qt 4 (see qeventdispatcher_x11.cpp). In this case
+ // QXcbEventQueue represents Xlib's internal event queue. In Qt 4, Xlib's
+ // event queue peeking APIs would not see these events anymore, the same way
+ // our peeking functions do not consider m_inputEvents. This design is
+ // intentional to keep the same behavior. We could do filtering directly on
+ // QXcbEventQueue, without the m_inputEvents, but it is not clear if it is
+ // needed by anyone who peeks at the native event queue.
+
+ bool excludeUserInputEvents = flags.testFlag(QEventLoop::ExcludeUserInputEvents);
+ if (excludeUserInputEvents) {
+ xcb_generic_event_t *event = nullptr;
+ while ((event = takeFirst())) {
+ if (m_connection->isUserInputEvent(event)) {
+ m_inputEvents << event;
+ continue;
+ }
+ break;
+ }
+ return event;
+ }
+
+ if (!m_inputEvents.isEmpty())
+ return m_inputEvents.takeFirst();
+ return takeFirst();
+}
+
xcb_generic_event_t *QXcbEventQueue::takeFirst()
{
if (isEmpty())
diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.h b/src/plugins/platforms/xcb/qxcbeventqueue.h
index 0096437dba..235f2824be 100644
--- a/src/plugins/platforms/xcb/qxcbeventqueue.h
+++ b/src/plugins/platforms/xcb/qxcbeventqueue.h
@@ -41,6 +41,8 @@
#include <QtCore/QThread>
#include <QtCore/QHash>
+#include <QtCore/QEventLoop>
+#include <QtCore/QVector>
#include <xcb/xcb.h>
@@ -81,6 +83,7 @@ public:
void run() override;
bool isEmpty() const { return m_head == m_flushedTail && !m_head->event; }
+ xcb_generic_event_t *takeFirst(QEventLoop::ProcessEventsFlags flags);
xcb_generic_event_t *takeFirst();
void flushBufferedEvents();
void wakeUpDispatcher();
@@ -124,6 +127,8 @@ private:
bool m_peekerIndexCacheDirty = false;
QHash<qint32, QXcbEventNode *> m_peekerToNode;
+ QVector<xcb_generic_event_t *> m_inputEvents;
+
// debug stats
quint64 m_nodesOnHeap = 0;
};
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index d030b22fc8..9a7d193767 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -137,6 +137,8 @@ QXcbIntegration::QXcbIntegration(const QStringList &parameters, int &argc, char
m_instance = this;
qApp->setAttribute(Qt::AA_CompressHighFrequencyEvents, true);
+ QWindowSystemInterface::setPlatformFiltersEvents(true);
+
qRegisterMetaType<QXcbWindow*>();
#if QT_CONFIG(xcb_xlib)
XInitThreads();
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 6753c35cfc..30e34c419e 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -10096,20 +10096,24 @@ void QWidget::hideEvent(QHideEvent *)
which are passed in the \a message parameter.
In your reimplementation of this function, if you want to stop the
- event being handled by Qt, return true and set \a result.
- If you return false, this native event is passed back to Qt,
- which translates the event into a Qt event and sends it to the widget.
+ event being handled by Qt, return true and set \a result. The \a result
+ parameter has meaning only on Windows. If you return false, this native
+ event is passed back to Qt, which translates the event into a Qt event
+ and sends it to the widget.
- \note Events are only delivered to this event handler if the widget is
- has a native Window handle.
+ \note Events are only delivered to this event handler if the widget
+ has a native window handle.
\note This function superseedes the event filter functions
x11Event(), winEvent() and macEvent() of Qt 4.
+ \sa QAbstractNativeEventFilter
+
\table
\header \li Platform \li Event Type Identifier \li Message Type \li Result Type
\row \li Windows \li "windows_generic_MSG" \li MSG * \li LRESULT
\row \li macOS \li "NSEvent" \li NSEvent * \li
+ \row \li XCB \li "xcb_generic_event_t" \li xcb_generic_event_t * \li
\endtable
*/