接上一篇文章https://blog.csdn.net/Master_Cui/article/details/109182406,本文继续解析QCoreApplication::sendEvent和QCoreApplication::sendPostedEvents的代码
先看下QCoreApplication::sendEvent
bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event) { Q_TRACE(QCoreApplication_sendEvent, receiver, event, event->type()); if (event) event->spont = false; return notifyInternal2(receiver, event); }//sendEvent直接调用了notifyInternal2 bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event) { bool selfRequired = QCoreApplicationPrivate::threadRequiresCoreApplication(); if (!self && selfRequired) return false; // Make it possible for Qt Script to hook into events even // though QApplication is subclassed... bool result = false; void *cbdata[] = { receiver, event, &result }; if (QInternal::activateCallbacks(QInternal::EventNotifyCallback, cbdata)) {//将事件通知的回调函数放到一个qlist中,永远返回false return result; } // Qt强制执行以下规则:事件只能发送到当前线程中的对象 //所以receiver->d_func()->threadData和等效QThreadData::current() // 只是为了减少函数调用的开销 QObjectPrivate *d = receiver->d_func(); QThreadData *threadData = d->threadData; QScopedScopeLevelCounter scopeLevelCounter(threadData); if (!selfRequired) return doNotify(receiver, event);//分别调用doNotify和notify return self->notify(receiver, event); } bool QCoreApplication::notify(QObject *receiver, QEvent *event) { if (QCoreApplicationPrivate::is_app_closing)// no events are delivered after ~QCoreApplication() has started return true; return doNotify(receiver, event); }//即使调用notify,最终还是要调用doNotify上述代码的时序就是sendEvent-》notifyInternal2-》notify-》doNotify
接着看下doNotify的实现
static bool doNotify(QObject *receiver, QEvent *event) { if (receiver == 0) { // serious error qWarning("QCoreApplication::notify: Unexpected null receiver"); return true; } #ifndef QT_NO_DEBUG QCoreApplicationPrivate::checkReceiverThread(receiver);//检查接收者的线程是否和当前线程一致 #endif return receiver->isWidgetType() ? false : QCoreApplicationPrivate::notify_helper(receiver, event);//接收者是否是窗口,如果是,返回false,不处理,否则调用notify_helper } bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event) { // Note: when adjusting the tracepoints in here // consider adjusting QApplicationPrivate::notify_helper too. Q_TRACE(QCoreApplication_notify_entry, receiver, event, event->type()); bool consumed = false; bool filtered = false; Q_TRACE_EXIT(QCoreApplication_notify_exit, consumed, filtered); // 发送事件到所有应用程序的事件过滤器(仅在主线程中执行任何操作) if (QCoreApplication::self && receiver->d_func()->threadData->thread.loadAcquire() == mainThread() && QCoreApplication::self->d_func()->sendThroughApplicationEventFilters(receiver, event)) { filtered = true; return filtered; } // 发送事件到所有接收者的事件过滤器 if (sendThroughObjectEventFilters(receiver, event)) { filtered = true; return filtered; } // deliver the event consumed = receiver->event(event);//调用接受者的event函数处理事件,可由用户重写或者是父类的event函数 return consumed; }通过上面的分析,代码的时序就是doNotify-》notify_helper-》sendThroughApplicationEventFilters-》sendThroughObjectEventFilters-》event,而且可以得知。doNotify不处理窗口事件,并且事件过滤器接收事件比event函数早,和文章https://blog.csdn.net/Master_Cui/article/details/109093845与https://blog.csdn.net/Master_Cui/article/details/109109972中的说明一致
sendThroughApplicationEventFilters和sendThroughObjectEventFilters的实现就是调用应用程序或者接收者的eventFilter,具体实现如下
bool QCoreApplicationPrivate::sendThroughApplicationEventFilters(QObject *receiver, QEvent *event) { // We can't access the application event filters outside of the main thread (race conditions) Q_ASSERT(receiver->d_func()->threadData->thread.loadAcquire() == mainThread()); if (extraData) {// // application event filters are only called for objects in the GUI thread for (int i = 0; i < extraData->eventFilters.size(); ++i) { QObject *obj = extraData->eventFilters.at(i); if (!obj) continue; if (obj->d_func()->threadData != threadData) { qWarning("QCoreApplication: Application event filter cannot be in a different thread."); continue; } if (obj->eventFilter(receiver, event)) return true; } } return false; } bool QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject *receiver, QEvent *event) { if (receiver != QCoreApplication::instance() && receiver->d_func()->extraData) { for (int i = 0; i < receiver->d_func()->extraData->eventFilters.size(); ++i) { QObject *obj = receiver->d_func()->extraData->eventFilters.at(i); if (!obj) continue; if (obj->d_func()->threadData != receiver->d_func()->threadData) { qWarning("QCoreApplication: Object event filter cannot be in a different thread."); continue; } if (obj->eventFilter(receiver, event)) return true; } } return false; }通过上述代码也可以知道,事件过滤器是在元对象的extraData中,而且,如果eventFilter返回true,notify_helper函数直接返回,接受事件的函数就无法再收到并处理事件,和博客https://blog.csdn.net/Master_Cui/article/details/109093845中的描述符合
sendPostedEvents的实现稍微复杂,代码如下
void QCoreApplication::sendPostedEvents(QObject *receiver, int event_type) { QThreadData *data = QThreadData::current(); QCoreApplicationPrivate::sendPostedEvents(receiver, event_type, data); }//调用了QCoreApplicationPrivate::sendPostedEvents(receiver, event_type, data); void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type, QThreadData *data) { if (event_type == -1) { event_type = 0; } if (receiver && receiver->d_func()->threadData != data) { qWarning("QCoreApplication::sendPostedEvents: Cannot send posted events for objects in another thread"); return; } ++data->postEventList.recursion; auto locker = qt_unique_lock(data->postEventList.mutex); // by default, we assume that the event dispatcher can go to sleep after // processing all events. if any new events are posted while we send // events, canWait will be set to false. data->canWait = (data->postEventList.size() == 0);//查看事件队列中是否有事件,没有,则设置等待标志位 if (data->postEventList.size() == 0 || (receiver && !receiver->d_func()->postedEvents)) {//如果队列中没有事件或者接收者没有要发送的事件,退出 --data->postEventList.recursion; return; } data->canWait = true; int startOffset = data->postEventList.startOffset;//设置开始发送的事件下标 int &i = (!event_type && !receiver) ? data->postEventList.startOffset : startOffset;//设置事件的索引 data->postEventList.insertionOffset = data->postEventList.size();//如果有新的事件进入队列,设置插入队列的位置 // Exception-safe cleaning up without the need for a try/catch block struct CleanUp { QObject *receiver; int event_type; QThreadData *data; bool exceptionCaught; inline CleanUp(QObject *receiver, int event_type, QThreadData *data) : receiver(receiver), event_type(event_type), data(data), exceptionCaught(true) {} inline ~CleanUp() { if (exceptionCaught) { // since we were interrupted, we need another pass to make sure we clean everything up data->canWait = false; } --data->postEventList.recursion; if (!data->postEventList.recursion && !data->canWait && data->hasEventDispatcher()) data->eventDispatcher.loadRelaxed()->wakeUp(); // clear the global list, i.e. remove everything that was // delivered. if (!event_type && !receiver && data->postEventList.startOffset >= 0) { const QPostEventList::iterator it = data->postEventList.begin(); data->postEventList.erase(it, it + data->postEventList.startOffset); data->postEventList.insertionOffset -= data->postEventList.startOffset; Q_ASSERT(data->postEventList.insertionOffset >= 0); data->postEventList.startOffset = 0; } } }; CleanUp cleanup(receiver, event_type, data);//上述类主要就是为了当事件循环退出时,清除事件队列中的所有事件 while (i < data->postEventList.size()) {//遍历事件队列 // avoid live-lock if (i >= data->postEventList.insertionOffset) break; const QPostEvent &pe = data->postEventList.at(i); ++i; if (!pe.event) continue; if ((receiver && receiver != pe.receiver) || (event_type && event_type != pe.event->type())) {//一致性检测 data->canWait = false; continue; } if (pe.event->type() == QEvent::DeferredDelete) {//对DeferredDelete的事件进行特殊处理,不用太关注 // DeferredDelete events are sent either // 1) when the event loop that posted the event has returned; or // 2) if explicitly requested (with QEvent::DeferredDelete) for // events posted by the current event loop; or // 3) if the event was posted before the outermost event loop. int eventLevel = static_cast<QDeferredDeleteEvent *>(pe.event)->loopLevel(); int loopLevel = data->loopLevel + data->scopeLevel; const bool allowDeferredDelete = (eventLevel > loopLevel || (!eventLevel && loopLevel > 0) || (event_type == QEvent::DeferredDelete && eventLevel == loopLevel)); if (!allowDeferredDelete) { // cannot send deferred delete if (!event_type && !receiver) { // we must copy it first; we want to re-post the event // with the event pointer intact, but we can't delay // nulling the event ptr until after re-posting, as // addEvent may invalidate pe. QPostEvent pe_copy = pe; // null out the event so if sendPostedEvents recurses, it // will ignore this one, as it's been re-posted. const_cast<QPostEvent &>(pe).event = 0; // re-post the copied event so it isn't lost data->postEventList.addEvent(pe_copy); } continue; } } // first, we diddle the event so that we can deliver // it, and that no one will try to touch it later. pe.event->posted = false; QEvent *e = pe.event;//设置事件和接收者 QObject * r = pe.receiver; --r->d_func()->postedEvents;//要发送事件的计数-1 Q_ASSERT(r->d_func()->postedEvents >= 0); // next, update the data structure so that we're ready // for the next event. const_cast<QPostEvent &>(pe).event = 0; locker.unlock(); const auto relocker = qScopeGuard([&locker] { locker.lock(); }); QScopedPointer<QEvent> event_deleter(e); // will delete the event (with the mutex unlocked) // after all that work, it's time to deliver the event. QCoreApplication::sendEvent(r, e);//依然是调用QCoreApplication::sendEvent // careful when adding anything below this point - the // sendEvent() call might invalidate any invariants this // function depends on. }//循环结束 cleanup.exceptionCaught = false; }上述代码显示,sendPostedEvents就是多了一步对事件队列的遍历,然后将队列中的事件一个一个取出来,最后按顺序调用QCoreApplication::sendEvent(r, e)
上述代码中涉及的数据结构有QThreadData,使用该数据结构主要是为了取出当前线程的事件队列,代码如下
class QThreadData { public: QThreadData(int initialRefCount = 1); ~QThreadData(); //......省略 QStack<QEventLoop *> eventLoops; QPostEventList postEventList; QAtomicPointer<QThread> thread; QAtomicPointer<QAbstractEventDispatcher> eventDispatcher; bool quitNow; bool canWait; }而事件队列的存储使用的是如下数据结构
class QPostEventList : public QVector<QPostEvent> { public: // recursion == recursion count for sendPostedEvents() int recursion; // sendOffset == the current event to start sending int startOffset; // insertionOffset == set by sendPostedEvents to tell postEvent() where to start insertions int insertionOffset; QMutex mutex; inline QPostEventList() : QVector<QPostEvent>(), recursion(0), startOffset(0), insertionOffset(0) { } void addEvent(const QPostEvent &ev) { int priority = ev.priority; if (isEmpty() || constLast().priority >= priority || insertionOffset >= size()) { // optimization: we can simply append if the last event in // the queue has higher or equal priority append(ev); } else { // insert event in descending priority order, using upper // bound for a given priority (to ensure proper ordering // of events with the same priority) QPostEventList::iterator at = std::upper_bound(begin() + insertionOffset, end(), ev); insert(at, ev); } } private: //hides because they do not keep that list sorted. addEvent must be used using QVector<QPostEvent>::append; using QVector<QPostEvent>::insert; }; class QPostEvent { public: QObject *receiver; QEvent *event; int priority; inline QPostEvent() : receiver(nullptr), event(nullptr), priority(0){ } inline QPostEvent(QObject *r, QEvent *e, int p) : receiver(r), event(e), priority(p){ } };可见,事件队列本质是一个QPostEvent的vector
所以经过分析可知,事件机制的时序就是通过exec先进入事件循环,然后通过平台生成对应的子类来分发事件,在Ubuntu18.04下,使用的是类QEventDispatcherGlib中的processEvents来处理时间,之后,通过glib中的主事件循环机制将定时器事件source,网络事件source和一般事件source添加到程序的主上下文中并对主上下文进行迭代(上述过程实际是通过IO复用接口poll来完成的),接着对不同的事件进行分发,并分别调用 QCoreApplication::sendEvent和 QCoreApplication::sendPostedEvents,最后,通过这两个函数将事件交给事件过滤器函数eventfilter和事件函数event处理
参考
Qt5.14源码
欢迎大家评论交流,作者水平有限,如有错误,欢迎指出