From 1603ba23656c8c31dc05fe9b3f1e12b22e29989a Mon Sep 17 00:00:00 2001 From: David Faure Date: Sat, 23 Jun 2012 21:48:53 +0200 Subject: 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 --- src/corelib/kernel/qabstracteventdispatcher.cpp | 126 +++++++++++++----------- 1 file changed, 68 insertions(+), 58 deletions(-) (limited to 'src/corelib/kernel/qabstracteventdispatcher.cpp') diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp index 2ef98dba0f..d17d1c6335 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.cpp +++ b/src/corelib/kernel/qabstracteventdispatcher.cpp @@ -41,6 +41,7 @@ #include "qabstracteventdispatcher.h" #include "qabstracteventdispatcher_p.h" +#include "qabstractnativeeventfilter.h" #include "qthread.h" #include @@ -370,87 +371,96 @@ void QAbstractEventDispatcher::closingDown() */ /*! - \typedef QAbstractEventDispatcher::EventFilter - - Typedef for a function with the signature - - \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() + Installs an event filter \a filterObj for all native event filters + received by the application. + + The event filter \a filterObj receives events via its nativeEventFilter() + function, which is called for all events received by all threads. + + The nativeEventFilter() function should return true if the event should + be filtered, (i.e. stopped). It should return false to allow + 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(). + + 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 */ +void QAbstractEventDispatcher::installNativeEventFilter(QAbstractNativeEventFilter *filterObj) +{ + Q_D(QAbstractEventDispatcher); + + // clean up unused items in the list + d->eventFilters.removeAll(0); + d->eventFilters.removeAll(filterObj); + d->eventFilters.prepend(filterObj); +} /*! - 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 - be filtered, (i.e. stopped). It should return false to allow - processing the message to continue. + 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. - By default, no event filter function is set (i.e., this function - returns a null EventFilter the first time it is called). + 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 */ -QAbstractEventDispatcher::EventFilter QAbstractEventDispatcher::setEventFilter(EventFilter filter) +void QAbstractEventDispatcher::removeNativeEventFilter(QAbstractNativeEventFilter *filterObj) { Q_D(QAbstractEventDispatcher); - EventFilter oldFilter = d->event_filter; - d->event_filter = filter; - return oldFilter; + 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 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. + 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; } -- cgit v1.2.3