Provide public API for native event filtering, moved up from QPA.

The previous API was hard to use (global function, no type safety,
manual chaining), and confusing (app vs dispatcher split only made
sense on Windows). Installing and removing out of order would have
the risk of setting back a dangling pointer (crash). Meanwhile QPA
added type safety, and this new API models the QObject::installEventFilter
API for ease of use. The virtual method is in a new interface,
QAbstractNativeEventFilter.

QPA was even calling the dispatcher event filter with QPA-private event
classes, which made no sense (refactoring leftover from when the code
was in the dispatcher). Now the QPA plugins trigger the qcoreapp event
filters with the actual native events directly.

Change-Id: Ie35e47c59c862383bcaf857b28d54f7c72547882
Reviewed-by: Marius Storm-Olsen <marius.storm-olsen@nokia.com>
This commit is contained in:
David Faure 2012-06-23 21:48:53 +02:00 committed by Qt by Nokia
parent 981ea7a1aa
commit 1603ba2365
32 changed files with 420 additions and 333 deletions

8
dist/changes-5.0.0 vendored
View File

@ -389,6 +389,14 @@ QtCore
* QEvent::AccessibilityPrepare, AccessibilityHelp and AccessibilityDescription removed:
* The enum values simply didn't make sense in the first place and should simply be dropped.
* Filtering of native events (QCoreApplication::setEventFilter, as well as
QApplication::x11EventFilter/macEventFilter/qwsEventFilter) have been replaced
with QCoreApplication::installNativeEventFilter and removeNativeEventFilter,
for an API much closer to QEvent filtering. Note that the native events that can be
filtered this way depend on which QPA backend is chosen, at runtime. On X11, XEvents are
not used anymore, and have been replaced with xcb_generic_event_t due to the switch to
XCB, which requires porting the application code to XCB as well.
* [QTBUG-23529] QHash is now more resilient to a family of denial of service
attacks exploiting algorithmic complexity, by supporting two-arguments overloads
of the qHash() hashing function.

View File

@ -39,5 +39,16 @@
****************************************************************************/
//! [0]
bool myEventFilter(void *message);
class MyXcbEventFilter : public QAbstractNativeEventFilter
{
public:
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *) Q_DECL_OVERRIDE
{
if (eventType == "xcb_generic_event_t") {
xcb_generic_event_t* ev = static_cast<xcb_generic_event_t *>(message);
// ...
}
return false;
}
};
//! [0]

View File

@ -57,7 +57,7 @@ foreach (const QString &path, app.libraryPaths())
//! [3]
bool myEventFilter(void *message, long *result);
//! [3]

View File

@ -2,6 +2,7 @@
HEADERS += \
kernel/qabstracteventdispatcher.h \
kernel/qabstractnativeeventfilter.h \
kernel/qbasictimer.h \
kernel/qeventloop.h\
kernel/qpointer.h \
@ -42,6 +43,7 @@ HEADERS += \
SOURCES += \
kernel/qabstracteventdispatcher.cpp \
kernel/qabstractnativeeventfilter.cpp \
kernel/qbasictimer.cpp \
kernel/qeventloop.cpp \
kernel/qcoreapplication.cpp \

View File

@ -41,6 +41,7 @@
#include "qabstracteventdispatcher.h"
#include "qabstracteventdispatcher_p.h"
#include "qabstractnativeeventfilter.h"
#include "qthread.h"
#include <private/qthread_p.h>
@ -370,87 +371,96 @@ void QAbstractEventDispatcher::closingDown()
*/
/*!
\typedef QAbstractEventDispatcher::EventFilter
Installs an event filter \a filterObj for all native event filters
received by the application.
Typedef for a function with the signature
The event filter \a filterObj receives events via its nativeEventFilter()
function, which is called for all events received by all threads.
\snippet code/src_corelib_kernel_qabstracteventdispatcher.cpp 0
Note that the type of the \a message is platform dependent. The
following table shows the \a {message}'s type on Windows, Mac, and
X11. You can do a static cast to these types.
\table
\header
\li Platform
\li type
\row
\li Windows
\li MSG
\row
\li X11
\li XEvent
\row
\li Mac
\li NSEvent
\endtable
\sa setEventFilter(), filterEvent()
*/
/*!
Replaces the event filter function for this
QAbstractEventDispatcher with \a filter and returns the replaced
event filter function. Only the current event filter function is
called. If you want to use both filter functions, save the
replaced EventFilter in a place where yours can call it.
The event filter function set here is called for all messages
taken from the system event loop before the event is dispatched to
the respective target, including the messages not meant for Qt
objects.
The event filter function should return true if the message should
The nativeEventFilter() function should return true if the event should
be filtered, (i.e. stopped). It should return false to allow
processing the message to continue.
normal Qt processing to continue: the native event can then be translated
into a QEvent and handled by the standard Qt \l{QEvent} {event} filtering,
e.g. QObject::installEventFilter().
By default, no event filter function is set (i.e., this function
returns a null EventFilter the first time it is called).
If multiple event filters are installed, the filter that was installed last
is activated first.
\note The filter function set here receives native messages,
i.e. MSG or XEvent structs.
For maximum portability, you should always try to use QEvents
and QObject::installEventFilter() whenever possible.
\sa QObject::installEventFilter()
\since 5.0
*/
QAbstractEventDispatcher::EventFilter QAbstractEventDispatcher::setEventFilter(EventFilter filter)
void QAbstractEventDispatcher::installNativeEventFilter(QAbstractNativeEventFilter *filterObj)
{
Q_D(QAbstractEventDispatcher);
EventFilter oldFilter = d->event_filter;
d->event_filter = filter;
return oldFilter;
// clean up unused items in the list
d->eventFilters.removeAll(0);
d->eventFilters.removeAll(filterObj);
d->eventFilters.prepend(filterObj);
}
/*!
Sends \a message through the event filter that was set by
setEventFilter(). If no event filter has been set, this function
returns false; otherwise, this function returns the result of the
event filter function.
Removes an event filter object \a obj from this object. The
request is ignored if such an event filter has not been installed.
All event filters for this object are automatically removed when
this object is destroyed.
It is always safe to remove an event filter, even during event
filter activation (i.e. from the nativeEventFilter() function).
\sa installNativeEventFilter(), QAbstractNativeEventFilter
\since 5.0
*/
void QAbstractEventDispatcher::removeNativeEventFilter(QAbstractNativeEventFilter *filterObj)
{
Q_D(QAbstractEventDispatcher);
for (int i = 0; i < d->eventFilters.count(); ++i) {
if (d->eventFilters.at(i) == filterObj) {
d->eventFilters[i] = 0;
break;
}
}
}
/*!
Sends \a message through the event filters that were set by
installNativeEventFilter(). This function returns true as soon as an
event filter returns true, and false otherwise to indicate that
the processing of the event should continue.
Subclasses of QAbstractEventDispatcher \e must call this function
for \e all messages received from the system to ensure
compatibility with any extensions that may be used in the
application.
Note that the type of \a message is platform dependent. See
QAbstractEventDispatcher::EventFilter for details.
Note that the type of \a message is platform dependent. See
QAbstractNativeEventFilter for details.
\sa setEventFilter()
\sa installNativeEventFilter()
\since 5.0
*/
bool QAbstractEventDispatcher::filterEvent(void *message)
bool QAbstractEventDispatcher::filterNativeEvent(const QByteArray &eventType, void *message, long *result)
{
Q_D(QAbstractEventDispatcher);
if (d->event_filter) {
if (!d->eventFilters.isEmpty()) {
// Raise the loopLevel so that deleteLater() calls in or triggered
// by event_filter() will be processed from the main event loop.
QScopedLoopLevelCounter loopLevelCounter(d->threadData);
return d->event_filter(message);
for (int i = 0; i < d->eventFilters.size(); ++i) {
QAbstractNativeEventFilter *filter = d->eventFilters.at(i);
if (!filter)
continue;
if (filter->nativeEventFilter(eventType, message, result))
return true;
}
}
return false;
}

View File

@ -49,7 +49,7 @@ QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QAbstractNativeEventFilter;
class QAbstractEventDispatcherPrivate;
class QSocketNotifier;
@ -111,9 +111,12 @@ public:
virtual void startingUp();
virtual void closingDown();
typedef bool(*EventFilter)(void *message);
EventFilter setEventFilter(EventFilter filter);
bool filterEvent(void *message);
void installNativeEventFilter(QAbstractNativeEventFilter *filterObj);
void removeNativeEventFilter(QAbstractNativeEventFilter *filterObj);
bool filterNativeEvent(const QByteArray &eventType, void *message, long *result);
#if QT_DEPRECATED_SINCE(5, 0)
QT_DEPRECATED bool filterEvent(void *message) { return filterNativeEvent("", message, 0); }
#endif
Q_SIGNALS:
void aboutToBlock();

View File

@ -65,9 +65,9 @@ class Q_CORE_EXPORT QAbstractEventDispatcherPrivate : public QObjectPrivate
Q_DECLARE_PUBLIC(QAbstractEventDispatcher)
public:
inline QAbstractEventDispatcherPrivate()
: event_filter(0)
{ }
QAbstractEventDispatcher::EventFilter event_filter;
QList<QAbstractNativeEventFilter *> eventFilters;
static int allocateTimerId();
static void releaseTimerId(int id);

View File

@ -0,0 +1,105 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qabstractnativeeventfilter.h"
#include "qabstracteventdispatcher.h"
QT_BEGIN_NAMESPACE
/*!
\class QAbstractNativeEventFilter
\since 5.0
\brief The QAbstractNativeEventFilter class provides an interface for receiving native
events, such as MSG or XCB event structs.
*/
/*!
Creates a native event filter.
By default this doesn't do anything. Remember to install it on the application
object.
*/
QAbstractNativeEventFilter::QAbstractNativeEventFilter()
{
}
/*!
Destroys the native event filter.
This automatically removes it from the application.
*/
QAbstractNativeEventFilter::~QAbstractNativeEventFilter()
{
QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance();
if (eventDispatcher)
eventDispatcher->removeNativeEventFilter(this);
}
/*!
\fn bool QAbstractNativeEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
This method is called for every native event.
\note The filter function here receives native messages,
for example, MSG or XCB event structs.
It is called by the QPA platform plugin. On Windows, it is called by
the event dispatcher.
The type of event \a eventType is specific to the platform plugin chosen at run-time,
and can be used to cast \a message to the right type.
On X11, \a eventType is set to "xcb_generic_event_t", and the \a message can be casted
to a xcb_generic_event_t pointer.
On Windows, \a eventType is set to "windows_generic_MSG" for messages sent to toplevel windows,
and "windows_dispatcher_MSG" for system-wide messages such as messages from a registered hot key.
In both cases, the \a message can be casted to a MSG pointer.
The \a result pointer is only used on Windows, and corresponds to the LRESULT pointer.
On Mac, \a eventType is set to "mac_generic_NSEvent", and the \a message can be casted to an EventRef.
Example:
\snippet code/src_corelib_kernel_qabstractnativeeventfilter.cpp 0
*/
QT_END_NAMESPACE

View File

@ -0,0 +1,70 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QABSTRACTNATIVEEVENTFILTER_H
#define QABSTRACTNATIVEEVENTFILTER_H
#include <QtCore/qnamespace.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QAbstractNativeEventFilterPrivate;
class Q_CORE_EXPORT QAbstractNativeEventFilter
{
public:
QAbstractNativeEventFilter();
virtual ~QAbstractNativeEventFilter();
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) = 0;
private:
Q_DISABLE_COPY(QAbstractNativeEventFilter)
QAbstractNativeEventFilterPrivate *d;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif /* QABSTRACTNATIVEEVENTFILTER_H */

View File

@ -286,7 +286,6 @@ QCoreApplicationPrivate::QCoreApplicationPrivate(int &aargc, char **aargv, uint
, origArgv(new char *[aargc])
#endif
, application_type(0)
, eventFilter(0)
, in_exec(false)
, aboutToQuitEmitted(false)
, threadData_clean(false)
@ -765,7 +764,7 @@ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event)
do not change the focus widget.
\endlist
\sa QObject::event(), installEventFilter()
\sa QObject::event(), installNativeEventFilter()
*/
bool QCoreApplication::notify(QObject *receiver, QEvent *event)
@ -2140,80 +2139,94 @@ void QCoreApplication::removeLibraryPath(const QString &path)
#endif //QT_NO_LIBRARY
/*!
\typedef QCoreApplication::EventFilter
Sends \a message through the event filters that were set by
installNativeEventFilter(). This function returns true as soon as an
event filter returns true, and false otherwise to indicate that
the processing of the event should continue.
A function with the following signature that can be used as an
event filter:
Subclasses of QAbstractEventDispatcher \e must call this function
for \e all messages received from the system to ensure
compatibility with any extensions that may be used in the
application.
\snippet code/src_corelib_kernel_qcoreapplication.cpp 3
Note that the type of \a message is platform dependent. See
QAbstractNativeEventFilter for details.
\sa setEventFilter()
\sa installNativeEventFilter()
\since 5.0
\internal
This method only exists for the Windows event dispatcher to call the winEventFilter virtual.
Every other platform can just use QAbstractNativeEventFilter::filterNativeEvent directly.
*/
bool QCoreApplication::filterNativeEvent(const QByteArray &eventType, void *message, long *result)
{
if (result)
*result = 0;
#ifdef Q_OS_WIN
if (winEventFilter(reinterpret_cast<MSG *>(message), result))
return true;
#endif
QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance();
if (dispatcher)
return dispatcher->filterNativeEvent(eventType, message, result);
return false;
}
/*!
\fn EventFilter QCoreApplication::setEventFilter(EventFilter filter)
Installs an event filter \a filterObj for all native events
received by the application in the main thread.
Replaces the event filter function for the QCoreApplication with
\a filter and returns the pointer to the replaced event filter
function. Only the current event filter function is called. If you
want to use both filter functions, save the replaced EventFilter
in a place where yours can call it.
The event filter \a filterObj receives events via its nativeEventFilter()
function, which is called for all native events received in the main thread.
The event filter function set here is called for all messages
received by all threads meant for all Qt objects. It is \e not
called for messages that are not meant for Qt objects.
The event filter function should return true if the message should
The nativeEventFilter() function should return true if the event should
be filtered, (i.e. stopped). It should return false to allow
processing the message to continue.
normal Qt processing to continue: the native event can then be translated
into a QEvent and handled by the standard Qt \l{QEvent} {event} filtering,
e.g. QObject::installEventFilter().
By default, no event filter function is set (i.e., this function
returns a null EventFilter the first time it is called).
If multiple event filters are installed, the filter that was
installed last is activated first.
\note The filter function set here receives native messages,
i.e. MSG or XEvent structs, that are going to Qt objects. It is
called by QCoreApplication::filterEvent(). If the filter function
returns false to indicate the message should be processed further,
the native message can then be translated into a QEvent and
handled by the standard Qt \l{QEvent} {event} filering, e.g.
QObject::installEventFilter().
i.e. MSG or XCB event structs.
\note The filter function set here is different form the filter
function set via QAbstractEventDispatcher::setEventFilter(), which
gets all messages received by its thread, even messages meant for
objects that are not handled by Qt.
For maximum portability, you should always try to use QEvents
and QObject::installEventFilter() whenever possible.
\sa QObject::installEventFilter(), QAbstractEventDispatcher::setEventFilter()
\sa QObject::installEventFilter()
\since 5.0
*/
QCoreApplication::EventFilter
QCoreApplication::setEventFilter(QCoreApplication::EventFilter filter)
void QCoreApplication::installNativeEventFilter(QAbstractNativeEventFilter *filterObj)
{
Q_D(QCoreApplication);
EventFilter old = d->eventFilter;
d->eventFilter = filter;
return old;
QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance(QCoreApplicationPrivate::theMainThread);
if (!filterObj || !eventDispatcher)
return;
eventDispatcher->installNativeEventFilter(filterObj);
}
/*!
Sends \a message through the event filter that was set by
setEventFilter(). If no event filter has been set, this function
returns false; otherwise, this function returns the result of the
event filter function in the \a result parameter.
Removes an event filter object \a obj from this object. The
request is ignored if such an event filter has not been installed.
\sa setEventFilter()
All event filters for this object are automatically removed when
this object is destroyed.
It is always safe to remove an event filter, even during event
filter activation (i.e. from the nativeEventFilter() function).
\sa installNativeEventFilter(), QAbstractNativeEventFilter
\since 5.0
*/
bool QCoreApplication::filterEvent(void *message, long *result)
void QCoreApplication::removeNativeEventFilter(QAbstractNativeEventFilter *filterObj)
{
Q_D(QCoreApplication);
if (result)
*result = 0;
if (d->eventFilter)
return d->eventFilter(message, result);
#ifdef Q_OS_WIN
return winEventFilter(reinterpret_cast<MSG *>(message), result);
#else
return false;
#endif
QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance();
if (!filterObj || !eventDispatcher)
return;
eventDispatcher->removeNativeEventFilter(filterObj);
}
/*!

View File

@ -61,6 +61,7 @@ class QTranslator;
class QPostEventList;
class QStringList;
class QAbstractEventDispatcher;
class QAbstractNativeEventFilter;
#define qApp QCoreApplication::instance()
@ -159,9 +160,9 @@ public:
static void watchUnixSignal(int signal, bool watch);
#endif
typedef bool (*EventFilter)(void *message, long *result);
EventFilter setEventFilter(EventFilter filter);
bool filterEvent(void *message, long *result);
void installNativeEventFilter(QAbstractNativeEventFilter *filterObj);
void removeNativeEventFilter(QAbstractNativeEventFilter *filterObj);
bool filterNativeEvent(const QByteArray &eventType, void *message, long *result);
static bool isQuitLockEnabled();
static void setQuitLockEnabled(bool enabled);

View File

@ -121,8 +121,6 @@ public:
#endif
uint application_type;
QCoreApplication::EventFilter eventFilter;
bool in_exec;
bool aboutToQuitEmitted;
bool threadData_clean;

View File

@ -207,12 +207,6 @@ void qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam,
the event to be processed by Qt, then return true and set \a result
to the value that the window procedure should return. Otherwise
return false.
It is only directly addressed messages that are filtered. To
handle system wide messages, such as messages from a registered
hot key, you need to install an event filter on the event
dispatcher, which is returned from
QAbstractEventDispatcher::instance().
*/
bool QCoreApplication::winEventFilter(MSG *msg, long *result) // Windows event filter
{

View File

@ -359,7 +359,7 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
if (message == WM_TIMER)
KillTimer(hwnd, wp);
return 0;
} else if (app->filterEvent(&msg, &result)) {
} else if (app->filterNativeEvent(QByteArrayLiteral("windows_dispatcher_MSG"), &msg, &result)) {
return result;
}

View File

@ -146,51 +146,4 @@ void QPlatformNativeInterface::setWindowProperty(QPlatformWindow *window, const
Q_UNUSED(value);
}
/*!
\typedef QPlatformNativeInterface::EventFilter
\since 5.0
A function with the following signature that can be used as an
event filter:
\code
bool myEventFilter(void *message, long *result);
\endcode
\sa setEventFilter()
*/
/*!
\fn EventFilter QPlatformNativeInterface::setEventFilter(const QByteArray &eventType, EventFilter filter)
\since 5.0
Replaces the event filter function for the native interface with
\a filter and returns the pointer to the replaced event filter
function. Only the current event filter function is called. If you
want to use both filter functions, save the replaced EventFilter
in a place where you can call it from.
The event filter function set here is called for all messages
received from the platform if they are given type \eventType.
It is \e not called for messages that are not meant for Qt objects.
The type of event is specific to the platform plugin chosen at run-time.
The event filter function should return \c true if the message should
be filtered, (i.e. stopped). It should return \c false to allow
processing the message to continue.
By default, no event filter function is set. For example, this function
returns a null EventFilter the first time it is called.
\note The filter function here receives native messages,
for example, MSG or XEvent structs. It is called by the platform plugin.
*/
QPlatformNativeInterface::EventFilter QPlatformNativeInterface::setEventFilter(const QByteArray &eventType, QPlatformNativeInterface::EventFilter filter)
{
Q_UNUSED(eventType);
Q_UNUSED(filter);
return 0;
}
QT_END_NAMESPACE

View File

@ -88,9 +88,6 @@ public:
virtual QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const;
virtual void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value);
typedef bool (*EventFilter)(void *message, long *result);
virtual EventFilter setEventFilter(const QByteArray &eventType, EventFilter filter);
Q_SIGNALS:
void windowPropertyChanged(QPlatformWindow *window, const QString &propertyName);
};

View File

@ -518,11 +518,6 @@ bool QWindowSystemInterface::sendWindowSystemEvents(QAbstractEventDispatcher *ev
break;
}
if (eventDispatcher->filterEvent(event)) {
delete event;
continue;
}
nevents++;
QGuiApplicationPrivate::processWindowSystemEvent(event);
@ -554,7 +549,6 @@ QPlatformDropQtResponse QWindowSystemInterface::handleDrop(QWindow *w, const QMi
\brief Passes a native event identified by \a eventType to the \a window.
\note This function can only be called from the GUI thread.
\sa QPlatformNativeInterface::setEventFilter()
*/
bool QWindowSystemInterface::handleNativeEvent(QWindow *window, const QByteArray &eventType, void *message, long *result)

View File

@ -122,7 +122,6 @@ QT_BEGIN_NAMESPACE
QBBEngine::QBBEngine(QObject *parent) :
QBearerEngineImpl(parent),
previousEventFilter(0),
pollingRequired(false),
initialized(false)
{
@ -130,7 +129,6 @@ QBBEngine::QBBEngine(QObject *parent) :
QBBEngine::~QBBEngine()
{
QAbstractEventDispatcher::instance()->setEventFilter(previousEventFilter);
}
@ -173,8 +171,7 @@ void QBBEngine::initialize()
const QMutexLocker locker(&pollingMutex);
pollingRequired = true;
} else {
previousEventFilter =
QAbstractEventDispatcher::instance()->setEventFilter(filterEvent);
QAbstractEventDispatcher::instance()->installEventFilter(this);
}
doRequestUpdate();
@ -288,34 +285,23 @@ bool QBBEngine::requiresPolling() const
return pollingRequired;
}
bool QBBEngine::filterEvent(void *message)
bool QBBEngine::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
Q_UNUSED(eventType);
Q_UNUSED(result);
bps_event_t * const event = static_cast<bps_event_t *>(message);
Q_ASSERT(event);
QBBEngine *self = instanceStorage()->localData()->instance;
Q_ASSERT(self);
if (bps_event_get_domain(event) == netstatus_get_domain())
self->filterEvent(event);
if (self->previousEventFilter)
return self->previousEventFilter(message);
if (bps_event_get_domain(event) == netstatus_get_domain()) {
qBearerDebug() << Q_FUNC_INFO << "got update request.";
doRequestUpdate();
}
return false;
}
void QBBEngine::filterEvent(bps_event_t *event)
{
Q_UNUSED(event);
qBearerDebug() << Q_FUNC_INFO << "got update request.";
doRequestUpdate();
}
void QBBEngine::updateConfiguration(const char *interface)
{
netstatus_interface_details_t *details = 0;
@ -421,4 +407,3 @@ void QBBEngine::removeConfiguration(const QString &id)
QT_END_NAMESPACE
#endif // QT_NO_BEARERMANAGEMENT

View File

@ -45,6 +45,7 @@
#include "../qbearerengine_impl.h"
#include <QAbstractEventDispatcher>
#include <QAbstractNativeEventFilter>
#ifndef QT_NO_BEARERMANAGEMENT
@ -55,7 +56,7 @@ QT_BEGIN_NAMESPACE
class QNetworkConfigurationPrivate;
class QNetworkSessionPrivate;
class QBBEngine : public QBearerEngineImpl
class QBBEngine : public QBearerEngineImpl, public QAbstractNativeEventFilter
{
Q_OBJECT
@ -82,6 +83,8 @@ public:
bool requiresPolling() const Q_DECL_OVERRIDE;
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE;
protected:
void updateConfiguration(const char *interface);
void removeConfiguration(const QString &id);
@ -90,14 +93,8 @@ private Q_SLOTS:
void doRequestUpdate();
private:
static bool filterEvent(void *message);
void filterEvent(bps_event_t *event);
QHash<QString, QString> configurationInterface;
QAbstractEventDispatcher::EventFilter previousEventFilter;
mutable QMutex pollingMutex;
bool pollingRequired;

View File

@ -90,13 +90,7 @@ void QQnxBpsEventFilter::installOnEventDispatcher(QAbstractEventDispatcher *disp
if (navigator_request_events(0) != BPS_SUCCESS)
qWarning("QQNX: failed to register for navigator events");
QAbstractEventDispatcher::EventFilter previousEventFilter = dispatcher->setEventFilter(dispatcherEventFilter);
// the QPA plugin creates the event dispatcher so we are the first event
// filter assert on that just in case somebody adds another event filter
// in the QQnxIntegration constructor instead of adding a new section in here
Q_ASSERT(previousEventFilter == 0);
Q_UNUSED(previousEventFilter);
dispatcher->installNativeEventFilter(this);
}
void QQnxBpsEventFilter::registerForScreenEvents(QQnxScreen *screen)
@ -137,19 +131,11 @@ void QQnxBpsEventFilter::unregisterForDialogEvents(QQnxFileDialogHelper *dialog)
qWarning("QQNX: attempting to unregister dialog that was not registered");
}
bool QQnxBpsEventFilter::dispatcherEventFilter(void *message)
bool QQnxBpsEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
qBpsEventFilterDebug() << Q_FUNC_INFO;
if (s_instance == 0)
return false;
Q_UNUSED(eventType);
Q_UNUSED(result);
bps_event_t *event = static_cast<bps_event_t *>(message);
return s_instance->bpsEventFilter(event);
}
bool QQnxBpsEventFilter::bpsEventFilter(bps_event_t *event)
{
const int eventDomain = bps_event_get_domain(event);
qBpsEventFilterDebug() << Q_FUNC_INFO << "event=" << event << "domain=" << eventDomain;

View File

@ -44,6 +44,7 @@
#include <QObject>
#include <QHash>
#include <QAbstractNativeEventFilter>
#include <bps/dialog.h>
@ -58,7 +59,7 @@ class QQnxScreen;
class QQnxScreenEventHandler;
class QQnxVirtualKeyboardBps;
class QQnxBpsEventFilter : public QObject
class QQnxBpsEventFilter : public QObject, public QAbstractNativeEventFilter
{
Q_OBJECT
public:
@ -76,8 +77,7 @@ public:
void unregisterForDialogEvents(QQnxFileDialogHelper *dialog);
private:
static bool dispatcherEventFilter(void *message);
bool bpsEventFilter(bps_event_t *event);
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE;
bool handleNavigatorEvent(bps_event_t *event);

View File

@ -240,13 +240,6 @@ QWindowsContext *QWindowsContext::m_instance = 0;
typedef QHash<HWND, QWindowsWindow *> HandleBaseWindowHash;
struct QWindowsContextPrivate {
typedef QPlatformNativeInterface::EventFilter EventFilter;
enum EventFilterType
{
GenericWindowsEventFilter,
EventFilterTypeCount
};
QWindowsContextPrivate();
@ -262,7 +255,6 @@ struct QWindowsContextPrivate {
QSharedPointer<QWindowCreationContext> m_creationContext;
const HRESULT m_oleInitializeResult;
const QByteArray m_eventType;
EventFilter m_eventFilters[EventFilterTypeCount];
QWindow *m_lastActiveWindow;
};
@ -289,7 +281,6 @@ QWindowsContextPrivate::QWindowsContextPrivate() :
m_systemInfo |= QWindowsContext::SI_RTL_Extensions;
m_keyMapper.setUseRTLExtensions(true);
}
qFill(m_eventFilters, m_eventFilters + EventFilterTypeCount, EventFilter(0));
}
QWindowsContext::QWindowsContext() :
@ -694,27 +685,6 @@ QByteArray QWindowsContext::comErrorString(HRESULT hr)
return "Unknown error 0x" + QByteArray::number(quint64(hr), 16);
}
/*!
\brief Set event filter.
\sa QWindowsNativeInterface
*/
QWindowsContext::EventFilter QWindowsContext::setEventFilter(const QByteArray &eventType, EventFilter filter)
{
int eventFilterType = -1;
if (eventType == d->m_eventType)
eventFilterType = QWindowsContextPrivate::GenericWindowsEventFilter;
if (eventFilterType < 0) {
qWarning("%s: Attempt to set unsupported event filter '%s'.",
__FUNCTION__, eventType.constData());
return 0;
}
const EventFilter previous = d->m_eventFilters[eventFilterType];
d->m_eventFilters[eventFilterType] = filter;
return previous;
}
/*!
\brief Main windows procedure registered for windows.
@ -736,11 +706,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
msg.pt.y = GET_Y_LPARAM(lParam);
long filterResult = 0;
if (d->m_eventFilters[QWindowsContextPrivate::GenericWindowsEventFilter]) {
if (d->m_eventFilters[QWindowsContextPrivate::GenericWindowsEventFilter](&msg, &filterResult)) {
*result = LRESULT(filterResult);
return true;
}
QCoreApplication* coreApp = QCoreApplication::instance();
if (coreApp && coreApp->filterNativeEvent(d->m_eventType, &msg, &filterResult)) {
*result = LRESULT(filterResult);
return true;
}
// Events without an associated QWindow or events we are not interested in.
switch (et) {

View File

@ -107,7 +107,6 @@ class QWindowsContext
{
Q_DISABLE_COPY(QWindowsContext)
public:
typedef bool (*EventFilter)(void *message, long *result);
enum SystemInfoFlags
{
@ -143,8 +142,6 @@ public:
HDC displayContext() const;
int screenDepth() const;
EventFilter setEventFilter(const QByteArray &eventType, EventFilter filter);
static QWindowsContext *instance();
static QString windowsErrorMessage(unsigned long errorCode);

View File

@ -102,8 +102,6 @@ public:
#endif
virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window);
virtual void *nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs);
virtual EventFilter setEventFilter(const QByteArray &eventType, EventFilter filter)
{ return QWindowsContext::instance()->setEventFilter(eventType, filter); }
Q_INVOKABLE void *createMessageWindow(const QString &classNameTemplate,
const QString &windowName,

View File

@ -270,7 +270,6 @@ QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id)
{ \
event_t *e = (event_t *)event; \
if (QXcbWindow *platformWindow = platformWindowFromId(e->windowMember)) { \
long result = 0; \
handled = QWindowSystemInterface::handleNativeEvent(platformWindow->window(), m_nativeInterface->genericEventFilterType(), event, &result); \
if (!handled) \
platformWindow->handler(e); \
@ -282,7 +281,6 @@ break;
{ \
event_t *e = (event_t *)event; \
if (QXcbWindow *platformWindow = platformWindowFromId(e->event)) { \
long result = 0; \
handled = QWindowSystemInterface::handleNativeEvent(platformWindow->window(), m_nativeInterface->genericEventFilterType(), event, &result); \
if (!handled) \
m_keyboard->handler(platformWindow, e); \
@ -543,10 +541,9 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
m_callLog.remove(0, i);
}
#endif
bool handled = false;
if (QPlatformNativeInterface::EventFilter filter = m_nativeInterface->eventFilter(QXcbNativeInterface::GenericEventFilter))
handled = filter(event, 0);
long result = 0;
bool handled = QCoreApplication::instance()->filterNativeEvent(m_nativeInterface->genericEventFilterType(), event, &result);
uint response_type = event->response_type & ~0x80;

View File

@ -80,7 +80,6 @@ QXcbNativeInterface::QXcbNativeInterface() :
m_genericEventFilterType(QByteArrayLiteral("xcb_generic_event_t"))
{
qFill(m_eventFilters, m_eventFilters + EventFilterCount, EventFilter(0));
}
void *QXcbNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context)
@ -142,21 +141,6 @@ QPlatformNativeInterface::NativeResourceForContextFunction QXcbNativeInterface::
return 0;
}
QPlatformNativeInterface::EventFilter QXcbNativeInterface::setEventFilter(const QByteArray &eventType, QPlatformNativeInterface::EventFilter filter)
{
int type = -1;
if (eventType == m_genericEventFilterType)
type = GenericEventFilter;
if (type == -1) {
qWarning("QXcbNativeInterface: %s: Attempt to set invalid event filter type '%s'.",
Q_FUNC_INFO, eventType.constData());
return 0;
}
const EventFilter oldFilter = m_eventFilters[type];
m_eventFilters[type] = filter;
return oldFilter;
}
QXcbScreen *QXcbNativeInterface::qPlatformScreenForWindow(QWindow *window)
{
QXcbScreen *screen;

View File

@ -61,11 +61,6 @@ public:
EglContext
};
enum EventFilterType {
GenericEventFilter,
EventFilterCount
};
QXcbNativeInterface();
void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context);
@ -74,8 +69,6 @@ public:
NativeResourceForContextFunction nativeResourceFunctionForContext(const QByteArray &resource);
inline const QByteArray &genericEventFilterType() const { return m_genericEventFilterType; }
EventFilter setEventFilter(const QByteArray &eventType, EventFilter filter);
EventFilter eventFilter(EventFilterType type) const { return m_eventFilters[type]; }
void *displayForWindow(QWindow *window);
void *eglDisplayForWindow(QWindow *window);
@ -86,7 +79,6 @@ public:
private:
const QByteArray m_genericEventFilterType;
EventFilter m_eventFilters[EventFilterCount];
static QXcbScreen *qPlatformScreenForWindow(QWindow *window);
};

View File

@ -46,8 +46,10 @@
QT_BEGIN_NAMESPACE
QAbstractEventDispatcher::EventFilter oldEventFilter = 0;
qint64 QBenchmarkEvent::eventCounter = 0;
QBenchmarkEvent::QBenchmarkEvent()
: eventCounter(0)
{
}
QBenchmarkEvent::~QBenchmarkEvent()
{
@ -55,21 +57,19 @@ QBenchmarkEvent::~QBenchmarkEvent()
void QBenchmarkEvent::start()
{
QBenchmarkEvent::eventCounter = 0;
QAbstractEventDispatcher *parent = QAbstractEventDispatcher::instance();
oldEventFilter = parent->setEventFilter(QBenchmarkEvent::eventCountingMechanism);
eventCounter = 0;
QAbstractEventDispatcher::instance()->installNativeEventFilter(this);
}
qint64 QBenchmarkEvent::checkpoint()
{
return QBenchmarkEvent::eventCounter;
return eventCounter;
}
qint64 QBenchmarkEvent::stop()
{
QAbstractEventDispatcher *parent = QAbstractEventDispatcher::instance();
parent->setEventFilter(oldEventFilter);
return QBenchmarkEvent::eventCounter;
QAbstractEventDispatcher::instance()->removeNativeEventFilter(this);
return eventCounter;
}
// It's very tempting to simply reject a measurement if 0 events
@ -98,10 +98,13 @@ QTest::QBenchmarkMetric QBenchmarkEvent::metricType()
}
// This could be done in a much better way, this is just the beginning.
bool QBenchmarkEvent::eventCountingMechanism(void *message)
bool QBenchmarkEvent::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
Q_UNUSED(eventType);
Q_UNUSED(message);
QBenchmarkEvent::eventCounter++;
Q_UNUSED(result);
eventCounter++;
return false;
}

View File

@ -56,12 +56,14 @@
#include <QtTest/private/qbenchmarkmeasurement_p.h>
#include <QAbstractEventDispatcher>
#include <QObject>
#include <QAbstractNativeEventFilter>
QT_BEGIN_NAMESPACE
class QBenchmarkEvent : public QBenchmarkMeasurerBase
class QBenchmarkEvent : public QBenchmarkMeasurerBase, public QAbstractNativeEventFilter
{
public:
QBenchmarkEvent();
~QBenchmarkEvent();
void start();
qint64 checkpoint();
@ -71,8 +73,8 @@ public:
int adjustMedianCount(int suggestion);
bool repeatCount() { return 1; }
QTest::QBenchmarkMetric metricType();
static bool eventCountingMechanism(void *message);
static qint64 eventCounter;
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *result);
qint64 eventCounter;
};
QT_END_NAMESPACE

View File

@ -87,7 +87,7 @@ void tst_BenchlibEventCounter::events()
QAbstractEventDispatcher* ed = QAbstractEventDispatcher::instance();
QBENCHMARK {
for (int i = 0; i < eventCount; ++i) {
ed->filterEvent(0);
ed->filterNativeEvent("", 0, 0);
}
}
}

View File

@ -88,9 +88,9 @@ void tst_BenchlibOptions::threeEvents()
{
QAbstractEventDispatcher* ed = QAbstractEventDispatcher::instance();
QBENCHMARK {
ed->filterEvent(0);
ed->filterEvent(0);
ed->filterEvent(0);
ed->filterNativeEvent("", 0, 0);
ed->filterNativeEvent("", 0, 0);
ed->filterNativeEvent("", 0, 0);
}
}

View File

@ -71,6 +71,7 @@
#include <qcompleter.h>
#include <qtableview.h>
#include <qtreewidget.h>
#include <qabstractnativeeventfilter.h>
#include <QtWidgets/QGraphicsView>
#include <QtWidgets/QGraphicsProxyWidget>
@ -5505,16 +5506,17 @@ void tst_QWidget::minAndMaxSizeWithX11BypassWindowManagerHint()
}
}
class ShowHideShowWidget : public QWidget
class ShowHideShowWidget : public QWidget, public QAbstractNativeEventFilter
{
Q_OBJECT
int state;
public:
bool gotExpectedMapNotify;
bool gotExpectedGlobalEvent;
ShowHideShowWidget()
: state(0), gotExpectedMapNotify(false)
: state(0), gotExpectedMapNotify(false), gotExpectedGlobalEvent(false)
{
startTimer(1000);
}
@ -5531,19 +5533,32 @@ public:
}
}
bool nativeEvent(const QByteArray &eventType, void *message, long *)
bool isMapNotify(const QByteArray &eventType, void *message)
{
enum { XCB_MAP_NOTIFY = 19 };
if (state == 1 && eventType == QByteArrayLiteral("xcb_generic_event_t")) {
// XCB events have a uint8 response_type member at the beginning.
const unsigned char responseType = *(const unsigned char *)(message);
if ((responseType & ~0x80) == XCB_MAP_NOTIFY)
gotExpectedMapNotify = true;
return ((responseType & ~0x80) == XCB_MAP_NOTIFY);
}
return false;
}
bool nativeEvent(const QByteArray &eventType, void *message, long *)
{
if (isMapNotify(eventType, message))
gotExpectedMapNotify = true;
return false;
}
// QAbstractNativeEventFilter interface
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *) Q_DECL_OVERRIDE
{
if (isMapNotify(eventType, message))
gotExpectedGlobalEvent = true;
return false;
}
signals:
void done();
};
@ -5554,6 +5569,8 @@ void tst_QWidget::showHideShowX11()
QSKIP("This test is for X11 only.");
ShowHideShowWidget w;
qApp->installNativeEventFilter(&w);
w.show();
w.hide();
@ -5561,6 +5578,7 @@ void tst_QWidget::showHideShowX11()
connect(&w, SIGNAL(done()), &eventLoop, SLOT(quit()));
eventLoop.exec();
QVERIFY(w.gotExpectedGlobalEvent);
QVERIFY(w.gotExpectedMapNotify);
}