QT 之wayland 事件处理分析基于qt5wayland5.14.2

1. Qt  wayland 初始化 接收鼠标/案件,触摸屏等事件事件

QWaylandNativeInterface : public QPlatformNativeInterface

在QWaylandNativeInterface 继承qpa 接口类QPlatformNativeInterface;

1.1 初始化鼠标:

void *QWaylandNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString)
{
    QByteArray lowerCaseResource = resourceString.toLower();

    if (lowerCaseResource == "display" || lowerCaseResource == "wl_display" || lowerCaseResource == "nativedisplay")
        return m_integration->display()->wl_display();
    if (lowerCaseResource == "compositor")
        return const_cast<wl_compositor *>(m_integration->display()->wl_compositor());
    if (lowerCaseResource == "server_buffer_integration")
        return m_integration->serverBufferIntegration();

    if (lowerCaseResource == "egldisplay" && m_integration->clientBufferIntegration())
        return m_integration->clientBufferIntegration()->nativeResource(QWaylandClientBufferIntegration::EglDisplay);

    if (lowerCaseResource == "wl_seat")
        return m_integration->display()->defaultInputDevice()->wl_seat();
    if (lowerCaseResource == "wl_keyboard") {
        auto *keyboard = m_integration->display()->defaultInputDevice()->keyboard();
        if (keyboard)
            return keyboard->wl_keyboard();
        return nullptr;
    }
    if (lowerCaseResource == "wl_pointer") {
        auto *pointer = m_integration->display()->defaultInputDevice()->pointer();
        if (pointer)
            return pointer->wl_pointer();
        return nullptr;
    }
    if (lowerCaseResource == "wl_touch") {
        auto *touch = m_integration->display()->defaultInputDevice()->touch();
        if (touch)
            return touch->wl_touch();
        return nullptr;
    }

    return nullptr;
}

QWaylandInputDevice::Point 主要实现 QtWayland::wl_pointer 类函数

 class Q_WAYLAND_CLIENT_WAYLAND_EXPORT wl_pointer
    {

    protected:
        virtual void pointer_enter(uint32_t serial, struct ::wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y);
        virtual void pointer_leave(uint32_t serial, struct ::wl_surface *surface);
        virtual void pointer_motion(uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y);
        virtual void pointer_button(uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
        virtual void pointer_axis(uint32_t time, uint32_t axis, wl_fixed_t value);
        virtual void pointer_frame();
        virtual void pointer_axis_source(uint32_t axis_source);
        virtual void pointer_axis_stop(uint32_t time, uint32_t axis);
        virtual void pointer_axis_discrete(uint32_t axis, int32_t discrete);

    private:
        void init_listener();
        static const struct wl_pointer_listener m_wl_pointer_listener;
        static void handle_enter(
            void *data,
            struct ::wl_pointer *object,
            uint32_t serial,
            struct ::wl_surface *surface,
            wl_fixed_t surface_x,
            wl_fixed_t surface_y);
        static void handle_leave(
            void *data,
            struct ::wl_pointer *object,
            uint32_t serial,
            struct ::wl_surface *surface);
        static void handle_motion(
            void *data,
            struct ::wl_pointer *object,
            uint32_t time,
            wl_fixed_t surface_x,
            wl_fixed_t surface_y);
        static void handle_button(
            void *data,
            struct ::wl_pointer *object,
            uint32_t serial,
            uint32_t time,
            uint32_t button,
            uint32_t state);
        static void handle_axis(
            void *data,
            struct ::wl_pointer *object,
            uint32_t time,
            uint32_t axis,
            wl_fixed_t value);
        static void handle_frame(
            void *data,
            struct ::wl_pointer *object);
        static void handle_axis_source(
            void *data,
            struct ::wl_pointer *object,
            uint32_t axis_source);
        static void handle_axis_stop(
            void *data,
            struct ::wl_pointer *object,
            uint32_t time,
            uint32_t axis);
        static void handle_axis_discrete(
            void *data,
            struct ::wl_pointer *object,
            uint32_t axis,
            int32_t discrete);
        struct ::wl_pointer *m_wl_pointer;
    };

2. wl_pointer 类向weston 注册监听鼠标事件

    const struct wl_pointer_listener wl_pointer::m_wl_pointer_listener = {
        wl_pointer::handle_enter,
        wl_pointer::handle_leave,
        wl_pointer::handle_motion,
        wl_pointer::handle_button,
        wl_pointer::handle_axis,
        wl_pointer::handle_frame,
        wl_pointer::handle_axis_source,
        wl_pointer::handle_axis_stop,
        wl_pointer::handle_axis_discrete,
    };

    void wl_pointer::init_listener()
    {
        wl_pointer_add_listener(m_wl_pointer, &m_wl_pointer_listener, this);
    }

weston 服务接收鼠标事件就调用m_wl_pointer_listener 函数集。

3. 事件产生流程:分析hand_enter 鼠标进入事件为例:


    void wl_pointer::handle_enter(
        void *data,
        struct ::wl_pointer *object,
        uint32_t serial,
        struct ::wl_surface *surface,
        wl_fixed_t surface_x,
        wl_fixed_t surface_y)
    {
        Q_UNUSED(object);
        static_cast<wl_pointer *>(data)->pointer_enter(
            serial,
            surface,
            surface_x,
            surface_y);
    }

hand_enter 处理调用虚函数pointer_enter。pointer_enter函数在QWaylandInputDevice::Pointe实现。

void QWaylandInputDevice::Pointer::pointer_enter(uint32_t serial, struct wl_surface *surface,
                                                 wl_fixed_t sx, wl_fixed_t sy)
{
    if (!surface)
        return;

    QWaylandWindow *window = QWaylandWindow::fromWlSurface(surface);

    if (!window)
        return; // Ignore foreign surfaces

    if (mFocus) {
        qCWarning(lcQpaWayland) << "The compositor sent a wl_pointer.enter event before sending a"
                                << "leave event first, this is not allowed by the wayland protocol"
                                << "attempting to work around it by invalidating the current focus";
        invalidateFocus();
    }
    mFocus = window->waylandSurface();
    connect(mFocus.data(), &QObject::destroyed, this, &Pointer::handleFocusDestroyed);

    mSurfacePos = QPointF(wl_fixed_to_double(sx), wl_fixed_to_double(sy));
    mGlobalPos = window->window()->mapToGlobal(mSurfacePos.toPoint());

    mParent->mSerial = serial;
    mEnterSerial = serial;

#if QT_CONFIG(cursor)
    // Depends on mEnterSerial being updated
    updateCursor();
#endif
    printf("%s %d \n",__FUNCTION__,__LINE__);
    QWaylandWindow *grab = QWaylandWindow::mouseGrab();
    if (!grab)
        setFrameEvent(new EnterEvent(window, mSurfacePos, mGlobalPos));
}

setFrameEvent 发送EnterEvent 事件。

void QWaylandInputDevice::Pointer::setFrameEvent(QWaylandPointerEvent *event)
{
    qCDebug(lcQpaWaylandInput) << "Setting frame event " << event->type;
    if (mFrameData.event && mFrameData.event->type != event->type) {
        qCDebug(lcQpaWaylandInput) << "Flushing; previous was " << mFrameData.event->type;
        flushFrameEvent();
    }

    mFrameData.event = event;

    if (mParent->mVersion < WL_POINTER_FRAME_SINCE_VERSION) {
        qCDebug(lcQpaWaylandInput) << "Flushing new event; no frame event in this version";
        flushFrameEvent();
    }
}

void QWaylandInputDevice::Pointer::flushFrameEvent()
{
    if (auto *event = mFrameData.event) {
        if (auto window = event->surface) {
            window->handleMouse(mParent, *event);
        } else if (mFrameData.event->type == QWaylandPointerEvent::Type::Release) {
            // If the window has been destroyed, we still need to report an up event, but it can't
            // be handled by the destroyed window (obviously), so send the event here instead.
            QWindowSystemInterface::handleMouseEvent(nullptr, event->timestamp, event->local,
                                                     event->global, event->buttons, event->modifiers);
        }
        delete mFrameData.event;
        mFrameData.event = nullptr;
    }

    //TODO: do modifiers get passed correctly here?
    flushScrollEvent();
}

void QWaylandInputDevice::Pointer::flushFrameEvent()
{
    if (auto *event = mFrameData.event) {
        if (auto window = event->surface) {
            window->handleMouse(mParent, *event);
        } else if (mFrameData.event->type == QWaylandPointerEvent::Type::Release) {
            // If the window has been destroyed, we still need to report an up event, but it can't
            // be handled by the destroyed window (obviously), so send the event here instead.
            QWindowSystemInterface::handleMouseEvent(nullptr, event->timestamp, event->local,
                                                     event->global, event->buttons, event->modifiers);
        }
        delete mFrameData.event;
        mFrameData.event = nullptr;
    }

    //TODO: do modifiers get passed correctly here?
    flushScrollEvent();
}

window->handleMouse

void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e)
{
    if (e.type == QWaylandPointerEvent::Leave) {
        if (mWindowDecoration) {
            if (mMouseEventsInContentArea)
                QWindowSystemInterface::handleLeaveEvent(window());
        } else {
            QWindowSystemInterface::handleLeaveEvent(window());
        }
#if QT_CONFIG(cursor)
        restoreMouseCursor(inputDevice);
#endif
        return;
    }

    if (mWindowDecoration) {
        handleMouseEventWithDecoration(inputDevice, e);
    } else {
        switch (e.type) {
            case QWaylandPointerEvent::Enter:
                QWindowSystemInterface::handleEnterEvent(window(), e.local, e.global);
                break;
            case QWaylandPointerEvent::Press:
            case QWaylandPointerEvent::Release:
            case QWaylandPointerEvent::Motion:
                QWindowSystemInterface::handleMouseEvent(window(), e.timestamp, e.local, e.global, e.buttons, e.modifiers);
                break;
            case QWaylandPointerEvent::Wheel:
                QWindowSystemInterface::handleWheelEvent(window(), e.timestamp, e.local, e.global,
                                                         e.pixelDelta, e.angleDelta, e.modifiers,
                                                         e.phase, e.source, false);
                break;
        }
    }

#if QT_CONFIG(cursor)
    if (e.type == QWaylandPointerEvent::Enter) {
        QRect contentGeometry = windowContentGeometry().marginsRemoved(frameMargins());
        if (contentGeometry.contains(e.local.toPoint()))
            restoreMouseCursor(inputDevice);
    }
#endif
}


调用 QWindowSystemInterface::handleMouseEvent(window()。 handleMouseEvent 函数是qtbase 代码中实现的。


QT_DEFINE_QPA_EVENT_HANDLER(void, handleMouseEvent, QWindow *window,
                            const QPointF &local, const QPointF &global, Qt::MouseButtons state,
                            Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods,
                            Qt::MouseEventSource source)
{
    unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
    handleMouseEvent<Delivery>(window, time, local, global, state, button, type, mods, source);
}

QT_DEFINE_QPA_EVENT_HANDLER(void, handleMouseEvent, QWindow *window, ulong timestamp,
                            const QPointF &local, const QPointF &global, Qt::MouseButtons state,
                            Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods,
                            Qt::MouseEventSource source)
{
    Q_ASSERT_X(type != QEvent::MouseButtonDblClick && type != QEvent::NonClientAreaMouseButtonDblClick,
               "QWindowSystemInterface::handleMouseEvent",
               "QTBUG-71263: Native double clicks are not implemented.");
    auto localPos = QHighDpi::fromNativeLocalPosition(local, window);
    auto globalPos = QHighDpi::fromNativePixels(global, window);

    QWindowSystemInterfacePrivate::MouseEvent *e =
        new QWindowSystemInterfacePrivate::MouseEvent(window, timestamp, localPos, globalPos,
                                                      state, mods, button, type, source);
    QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}

 handleMouseEvent 调用handleWindowSystemEvent 函数。

template<>
bool QWindowSystemInterfacePrivate::handleWindowSystemEvent<QWindowSystemInterface::DefaultDelivery>(QWindowSystemInterfacePrivate::WindowSystemEvent *ev)
{
    if (synchronousWindowSystemEvents)
        return handleWindowSystemEvent<QWindowSystemInterface::SynchronousDelivery>(ev);
    else
        return handleWindowSystemEvent<QWindowSystemInterface::AsynchronousDelivery>(ev);
}

handleWindowSystemEvent 同步处理及异步处理

template<>
bool QWindowSystemInterfacePrivate::handleWindowSystemEvent<QWindowSystemInterface::AsynchronousDelivery>(WindowSystemEvent *ev)
{
    windowSystemEventQueue.append(ev);
    if (QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::qt_qpa_core_dispatcher())
        dispatcher->wakeUp();
    return true;
}
异步处理实现:将事件加入到windowSystemEventQueue 队列处理。


 同步处理:

template<>
bool QWindowSystemInterfacePrivate::handleWindowSystemEvent<QWindowSystemInterface::SynchronousDelivery>(WindowSystemEvent *ev)
{
    bool accepted = true;
    if (QThread::currentThread() == QGuiApplication::instance()->thread()) {
        // Process the event immediately on the current thread and return the accepted state.
        QGuiApplicationPrivate::processWindowSystemEvent(ev);
        accepted = ev->eventAccepted;
        delete ev;
    } else {
        // Post the event on the Qt main thread queue and flush the queue.
        // This will wake up the Gui thread which will process the event.
        // Return the accepted state for the last event on the queue,
        // which is the event posted by this function.
        handleWindowSystemEvent<QWindowSystemInterface::AsynchronousDelivery>(ev);
        accepted = QWindowSystemInterface::flushWindowSystemEvents();
    }
    return accepted;
}


/*!
    Make Qt Gui process all events on the event queue immediately. Return the
    accepted state for the last event on the queue.
*/
bool QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
{
    const int count = QWindowSystemInterfacePrivate::windowSystemEventQueue.count();
    if (!count)
        return false;
    if (!QGuiApplication::instance()) {
        qWarning().nospace()
            << "QWindowSystemInterface::flushWindowSystemEvents() invoked after "
               "QGuiApplication destruction, discarding " << count << " events.";
        QWindowSystemInterfacePrivate::windowSystemEventQueue.clear();
        return false;
    }
    if (QThread::currentThread() != QGuiApplication::instance()->thread()) {
        // Post a FlushEvents event which will trigger a call back to
        // deferredFlushWindowSystemEvents from the Gui thread.
        QMutexLocker locker(&QWindowSystemInterfacePrivate::flushEventMutex);
        QWindowSystemInterfacePrivate::FlushEventsEvent *e = new QWindowSystemInterfacePrivate::FlushEventsEvent(flags);
        QWindowSystemInterfacePrivate::handleWindowSystemEvent<AsynchronousDelivery>(e);
        QWindowSystemInterfacePrivate::eventsFlushed.wait(&QWindowSystemInterfacePrivate::flushEventMutex);
    } else {
        sendWindowSystemEvents(flags);
    }
    return QWindowSystemInterfacePrivate::eventAccepted.loadRelaxed() > 0;
}
ool QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
{
    int nevents = 0;

    while (QWindowSystemInterfacePrivate::windowSystemEventsQueued()) {
        QWindowSystemInterfacePrivate::WindowSystemEvent *event = nullptr;

        if (QWindowSystemInterfacePrivate::platformFiltersEvents) {
            event = QWindowSystemInterfacePrivate::getWindowSystemEvent();
        } else {
            event = flags & QEventLoop::ExcludeUserInputEvents ?
                        QWindowSystemInterfacePrivate::getNonUserInputWindowSystemEvent() :
                        QWindowSystemInterfacePrivate::getWindowSystemEvent();
        }
        if (!event)
            break;

        if (QWindowSystemInterfacePrivate::eventHandler) {
            if (QWindowSystemInterfacePrivate::eventHandler->sendEvent(event))
                nevents++;
        } else {
            nevents++;
            QGuiApplicationPrivate::processWindowSystemEvent(event);
        }

        // Record the accepted state for the processed event
        // (excluding flush events). This state can then be
        // returned by flushWindowSystemEvents().
        if (event->type != QWindowSystemInterfacePrivate::FlushEvents)
            QWindowSystemInterfacePrivate::eventAccepted.storeRelaxed(event->eventAccepted);

        delete event;
    }

    return (nevents > 0);
}

void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e)
{
    Q_TRACE_SCOPE(QGuiApplicationPrivate_processWindowSystemEvent, e->type);

    switch(e->type) {
    case QWindowSystemInterfacePrivate::Mouse:
        QGuiApplicationPrivate::processMouseEvent(static_cast<QWindowSystemInterfacePrivate::MouseEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::Wheel:
        QGuiApplicationPrivate::processWheelEvent(static_cast<QWindowSystemInterfacePrivate::WheelEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::Key:
        QGuiApplicationPrivate::processKeyEvent(static_cast<QWindowSystemInterfacePrivate::KeyEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::Touch:
        QGuiApplicationPrivate::processTouchEvent(static_cast<QWindowSystemInterfacePrivate::TouchEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::GeometryChange:
        QGuiApplicationPrivate::processGeometryChangeEvent(static_cast<QWindowSystemInterfacePrivate::GeometryChangeEvent*>(e));
        break;
    case QWindowSystemInterfacePrivate::Enter:
        QGuiApplicationPrivate::processEnterEvent(static_cast<QWindowSystemInterfacePrivate::EnterEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::Leave:
        QGuiApplicationPrivate::processLeaveEvent(static_cast<QWindowSystemInterfacePrivate::LeaveEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::ActivatedWindow:
        QGuiApplicationPrivate::processActivatedEvent(static_cast<QWindowSystemInterfacePrivate::ActivatedWindowEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::WindowStateChanged:
        QGuiApplicationPrivate::processWindowStateChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowStateChangedEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::WindowScreenChanged:
        QGuiApplicationPrivate::processWindowScreenChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowScreenChangedEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::SafeAreaMarginsChanged:
        QGuiApplicationPrivate::processSafeAreaMarginsChangedEvent(static_cast<QWindowSystemInterfacePrivate::SafeAreaMarginsChangedEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::ApplicationStateChanged: {
        QWindowSystemInterfacePrivate::ApplicationStateChangedEvent * changeEvent = static_cast<QWindowSystemInterfacePrivate::ApplicationStateChangedEvent *>(e);
        QGuiApplicationPrivate::setApplicationState(changeEvent->newState, changeEvent->forcePropagate); }
        break;
    case QWindowSystemInterfacePrivate::ApplicationTermination:
        QGuiApplicationPrivate::processApplicationTermination(e);
        break;
    case QWindowSystemInterfacePrivate::FlushEvents: {
        QWindowSystemInterfacePrivate::FlushEventsEvent *flushEventsEvent = static_cast<QWindowSystemInterfacePrivate::FlushEventsEvent *>(e);
        QWindowSystemInterface::deferredFlushWindowSystemEvents(flushEventsEvent->flags); }
        break;
    case QWindowSystemInterfacePrivate::Close:
        QGuiApplicationPrivate::processCloseEvent(
                static_cast<QWindowSystemInterfacePrivate::CloseEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::ScreenOrientation:
        QGuiApplicationPrivate::processScreenOrientationChange(
                static_cast<QWindowSystemInterfacePrivate::ScreenOrientationEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::ScreenGeometry:
        QGuiApplicationPrivate::processScreenGeometryChange(
                static_cast<QWindowSystemInterfacePrivate::ScreenGeometryEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInch:
        QGuiApplicationPrivate::processScreenLogicalDotsPerInchChange(
                static_cast<QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::ScreenRefreshRate:
        QGuiApplicationPrivate::processScreenRefreshRateChange(
                static_cast<QWindowSystemInterfacePrivate::ScreenRefreshRateEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::ThemeChange:
        QGuiApplicationPrivate::processThemeChanged(
                    static_cast<QWindowSystemInterfacePrivate::ThemeChangeEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::Expose:
        QGuiApplicationPrivate::processExposeEvent(static_cast<QWindowSystemInterfacePrivate::ExposeEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::Tablet:
        QGuiApplicationPrivate::processTabletEvent(
                    static_cast<QWindowSystemInterfacePrivate::TabletEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::TabletEnterProximity:
        QGuiApplicationPrivate::processTabletEnterProximityEvent(
                    static_cast<QWindowSystemInterfacePrivate::TabletEnterProximityEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::TabletLeaveProximity:
        QGuiApplicationPrivate::processTabletLeaveProximityEvent(
                    static_cast<QWindowSystemInterfacePrivate::TabletLeaveProximityEvent *>(e));
        break;
#ifndef QT_NO_GESTURES
    case QWindowSystemInterfacePrivate::Gesture:
        QGuiApplicationPrivate::processGestureEvent(
                    static_cast<QWindowSystemInterfacePrivate::GestureEvent *>(e));
        break;
#endif
    case QWindowSystemInterfacePrivate::PlatformPanel:
        QGuiApplicationPrivate::processPlatformPanelEvent(
                    static_cast<QWindowSystemInterfacePrivate::PlatformPanelEvent *>(e));
        break;
    case QWindowSystemInterfacePrivate::FileOpen:
        QGuiApplicationPrivate::processFileOpenEvent(
                    static_cast<QWindowSystemInterfacePrivate::FileOpenEvent *>(e));
        break;
#ifndef QT_NO_CONTEXTMENU
        case QWindowSystemInterfacePrivate::ContextMenu:
        QGuiApplicationPrivate::processContextMenuEvent(
                    static_cast<QWindowSystemInterfacePrivate::ContextMenuEvent *>(e));
        break;
#endif
    case QWindowSystemInterfacePrivate::EnterWhatsThisMode:
        QGuiApplication::postEvent(QGuiApplication::instance(), new QEvent(QEvent::EnterWhatsThisMode));
        break;
    default:
        qWarning() << "Unknown user input event type:" << e->type;
        break;
    }
}

void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent *e)
{
    QEvent::Type type = QEvent::None;
    Qt::MouseButton button = Qt::NoButton;
    QWindow *window = e->window.data();
    bool positionChanged = QGuiApplicationPrivate::lastCursorPosition != e->globalPos;
    bool mouseMove = false;
    bool mousePress = false;

    if (e->enhancedMouseEvent()) {
        type = e->buttonType;
        button = e->button;

        if (type == QEvent::NonClientAreaMouseMove || type == QEvent::MouseMove)
            mouseMove = true;
        else if (type == QEvent::NonClientAreaMouseButtonPress || type == QEvent::MouseButtonPress)
            mousePress = true;

        if (!mouseMove && positionChanged) {
            QWindowSystemInterfacePrivate::MouseEvent moveEvent(window, e->timestamp,
                e->localPos, e->globalPos, e->buttons ^ button, e->modifiers, Qt::NoButton,
                e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove,
                e->source, e->nonClientArea);
            if (e->synthetic())
                moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
            processMouseEvent(&moveEvent); // mouse move excluding state change
            processMouseEvent(e); // the original mouse event
            return;
        }
    } else {
        Qt::MouseButtons stateChange = e->buttons ^ mouse_buttons;
        if (positionChanged && (stateChange != Qt::NoButton)) {
            QWindowSystemInterfacePrivate::MouseEvent moveEvent(window, e->timestamp, e->localPos,
                e->globalPos, mouse_buttons, e->modifiers, Qt::NoButton, QEvent::None, e->source,
                e->nonClientArea);
            if (e->synthetic())
                moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
            processMouseEvent(&moveEvent); // mouse move excluding state change
            processMouseEvent(e); // the original mouse event
            return;
        }

        // In the compatibility path we deduce event type and button that caused the event
        if (positionChanged) {
            mouseMove = true;
            type = e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove;
        } else {
            // Check to see if a new button has been pressed/released.
            for (uint mask = Qt::LeftButton; mask <= Qt::MaxMouseButton; mask <<= 1) {
                if (stateChange & mask) {
                    button = Qt::MouseButton(mask);
                    break;
                }
            }
            if (button == Qt::NoButton) {
                // Ignore mouse events that don't change the current state. This shouldn't
                // really happen, getting here can only mean that the stored button state
                // is out of sync with the actual physical button state.
                return;
            }
            if (button & e->buttons) {
                mousePress = true;
                type = e->nonClientArea ? QEvent::NonClientAreaMouseButtonPress
                                        : QEvent::MouseButtonPress;
             } else {
                type = e->nonClientArea ? QEvent::NonClientAreaMouseButtonRelease
                                        : QEvent::MouseButtonRelease;
            }
        }
    }

    modifier_buttons = e->modifiers;
    QPointF localPoint = e->localPos;
    QPointF globalPoint = e->globalPos;
    bool doubleClick = false;

    if (mouseMove) {
        QGuiApplicationPrivate::lastCursorPosition = globalPoint;
        const auto doubleClickDistance = e->source == Qt::MouseEventNotSynthesized ?
                    mouseDoubleClickDistance : touchDoubleTapDistance;
        if (qAbs(globalPoint.x() - mousePressX) > doubleClickDistance ||
            qAbs(globalPoint.y() - mousePressY) > doubleClickDistance)
            mousePressButton = Qt::NoButton;
    } else {
        mouse_buttons = e->buttons;
        if (mousePress) {
            ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval());
            doubleClick = e->timestamp - mousePressTime < doubleClickInterval && button == mousePressButton;
            mousePressTime = e->timestamp;
            mousePressButton = button;
            const QPoint point = QGuiApplicationPrivate::lastCursorPosition.toPoint();
            mousePressX = point.x();
            mousePressY = point.y();
        }
    }

    if (e->nullWindow()) {
        window = QGuiApplication::topLevelAt(globalPoint.toPoint());
        if (window) {
            // Moves and the release following a press must go to the same
            // window, even if the cursor has moved on over another window.
            if (e->buttons != Qt::NoButton) {
                if (!currentMousePressWindow)
                    currentMousePressWindow = window;
                else
                    window = currentMousePressWindow;
            } else if (currentMousePressWindow) {
                window = currentMousePressWindow;
                currentMousePressWindow = 0;
            }
            QPointF delta = globalPoint - globalPoint.toPoint();
            localPoint = window->mapFromGlobal(globalPoint.toPoint()) + delta;
        }
    }

    if (!window)
        return;

#ifndef QT_NO_CURSOR
    if (!e->synthetic()) {
        if (const QScreen *screen = window->screen())
            if (QPlatformCursor *cursor = screen->handle()->cursor()) {
                const QPointF nativeLocalPoint = QHighDpi::toNativePixels(localPoint, screen);
                const QPointF nativeGlobalPoint = QHighDpi::toNativePixels(globalPoint, screen);
                QMouseEvent ev(type, nativeLocalPoint, nativeLocalPoint, nativeGlobalPoint,
                                          button, e->buttons, e->modifiers, e->source);
                ev.setTimestamp(e->timestamp);
                cursor->pointerEvent(ev);
            }
    }
#endif

    QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, e->buttons, e->modifiers, e->source);
    ev.setTimestamp(e->timestamp);

    if (window->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) {
        // a modal window is blocking this window, don't allow mouse events through
        return;
    }

    if (doubleClick && (ev.type() == QEvent::MouseButtonPress)) {
        // QtBUG-25831, used to suppress delivery in qwidgetwindow.cpp
        setMouseEventFlags(&ev, ev.flags() | Qt::MouseEventCreatedDoubleClick);
    }

    QGuiApplication::sendSpontaneousEvent(window, &ev);
    e->eventAccepted = ev.isAccepted();
    if (!e->synthetic() && !ev.isAccepted()
        && !e->nonClientArea
        && qApp->testAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents)) {
        if (!m_fakeTouchDevice) {
            m_fakeTouchDevice = new QTouchDevice;
            QWindowSystemInterface::registerTouchDevice(m_fakeTouchDevice);
        }
        QList<QWindowSystemInterface::TouchPoint> points;
        QWindowSystemInterface::TouchPoint point;
        point.id = 1;
        point.area = QRectF(globalPoint.x() - 2, globalPoint.y() - 2, 4, 4);

        // only translate left button related events to
        // avoid strange touch event sequences when several
        // buttons are pressed
        if (type == QEvent::MouseButtonPress && button == Qt::LeftButton) {
            point.state = Qt::TouchPointPressed;
        } else if (type == QEvent::MouseButtonRelease && button == Qt::LeftButton) {
            point.state = Qt::TouchPointReleased;
        } else if (type == QEvent::MouseMove && (e->buttons & Qt::LeftButton)) {
            point.state = Qt::TouchPointMoved;
        } else {
            return;
        }

        points << point;

        QEvent::Type type;
        QList<QTouchEvent::TouchPoint> touchPoints =
                QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, QTouchDevicePrivate::get(m_fakeTouchDevice)->id, &type);

        QWindowSystemInterfacePrivate::TouchEvent fake(window, e->timestamp, type, m_fakeTouchDevice, touchPoints, e->modifiers);
        fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
        processTouchEvent(&fake);
    }
    if (doubleClick) {
        mousePressButton = Qt::NoButton;
        if (!e->window.isNull() || e->nullWindow()) { // QTBUG-36364, check if window closed in response to press
            const QEvent::Type doubleClickType = e->nonClientArea ? QEvent::NonClientAreaMouseButtonDblClick : QEvent::MouseButtonDblClick;
            QMouseEvent dblClickEvent(doubleClickType, localPoint, localPoint, globalPoint,
                                      button, e->buttons, e->modifiers, e->source);
            dblClickEvent.setTimestamp(e->timestamp);
            QGuiApplication::sendSpontaneousEvent(window, &dblClickEvent);
        }
    }
}

/*!
    \internal
*/
bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event)
{
    Q_TRACE(QCoreApplication_sendSpontaneousEvent, receiver, event, event->type());

    if (event)
        event->spont = true;
    return notifyInternal2(receiver, event);
}


/*!
    \internal
*/
bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event)
{
    Q_TRACE(QCoreApplication_sendSpontaneousEvent, receiver, event, event->type());

    if (event)
        event->spont = true;
    return notifyInternal2(receiver, event);
}


/*!
  \internal
  \since 5.6

  This function is here to make it possible for Qt extensions to
  hook into event notification without subclassing QApplication.
*/
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)) {
        return result;
    }

    // Qt enforces the rule that events can only be sent to objects in
    // the current thread, so receiver->d_func()->threadData is
    // equivalent to QThreadData::current(), just without the function
    // call overhead.
    QObjectPrivate *d = receiver->d_func();
    QThreadData *threadData = d->threadData;
    QScopedScopeLevelCounter scopeLevelCounter(threadData);
    if (!selfRequired)
        return doNotify(receiver, event);
    return self->notify(receiver, event);
}

bool QCoreApplication::notify(QObject *receiver, QEvent *event)
{
    // no events are delivered after ~QCoreApplication() has started
    if (QCoreApplicationPrivate::is_app_closing)
        return true;
    return doNotify(receiver, event);
}


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);
}


  Helper function called by QCoreApplicationPrivate::notify() and qapplication.cpp
 */
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);

    // send to all application event filters (only does anything in the main thread)
    if (QCoreApplication::self
            && receiver->d_func()->threadData->thread.loadAcquire() == mainThread()
            && QCoreApplication::self->d_func()->sendThroughApplicationEventFilters(receiver, event)) {
        filtered = true;
        return filtered;
    }
    // send to all receiver event filters
    if (sendThroughObjectEventFilters(receiver, event)) {
        filtered = true;
        return filtered;
    }

    // deliver the event
    consumed = receiver->event(event);
    return consumed;
}


receiver->event 指向QObject ;

可以看到,流程中涉及两个事件过滤器的调用:sendThroughApplicationEventFilters和sendThroughObjectEventFilters,事件过滤器调用完后,才是调用接收者的event函数。

QApplication的事件过滤器
上一小节提到的sendThroughApplicationEventFilters是处理app的事件过滤器。代码里会调用给app安装的所有事件过滤器(从代码中的注释看到,app的事件过滤器只能在主线程中被调用),我们给app安装的事件过滤器就是在这个阶段被执行的。

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->eventFilter(receiver, event))
                return true;
        }
    }
    return false;
}

QObject的事件过滤器
sendThroughObjectEventFilters是处理对象的事件过滤器。里面会调用给接收者安装的全部事件过滤器,我们通过installEventFilter给某个对象安装的事件过滤器就是在这个阶段执行的。

bool QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject *receiver, QEvent *event)
{
        ...
        for (int i = 0; i < receiver->d_func()->extraData->eventFilters.size(); ++i) {
            QObject *obj = receiver->d_func()->extraData->eventFilters.at(i);
            ...
            if (obj->eventFilter(receiver, event))
                return true;
        }
    }
    return false;
}

对象的event方法
从QCoreApplicationPrivate::notify_helper代码可以看到,处理完事件接收者的事件过滤器后,就会调用接收者的event方法来处理事件。
每一个从QObject继承出来的子类都有event方法,都可以处理自己的事件。
我们简单看下QWidget的event方法:

bool QWidget::event(QEvent *event)
{
    ...
    switch (event->type()) {
    ...
    case QEvent::MouseMove:
        mouseMoveEvent((QMouseEvent*)event);
        break;

    case QEvent::MouseButtonPress:
        mousePressEvent((QMouseEvent*)event);
        break;

    case QEvent::MouseButtonRelease:
        mouseReleaseEvent((QMouseEvent*)event);
        break;

    case QEvent::MouseButtonDblClick:
        mouseDoubleClickEvent((QMouseEvent*)event);
        break;
        ...
}

到这里

是不是很熟悉,各个具体的事件处理函数就是在这个阶段被调用的。

猜你喜欢

转载自blog.csdn.net/u012794472/article/details/129311477
QT