How to port QApplication::x11EventFilter to XCB QAbstractNativeEventFilter



  • Hi,

    We are currently porting an application from Qt4 to Qt5 and there is not much documentation on how to replace MyApplication::x11EventFilter implementation to a QAbstractNativeEventFilter installed with QCoreApplication::installNativeEventFilter (as explained in https://doc.qt.io/qt-5/sourcebreaks.html#changes-to-qcoreapplication).
    We just started the implementation of

    MyXcbEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *)
    

    as explained in https://doc.qt.io/qt-5/qabstractnativeeventfilter.html#nativeEventFilter in "Linux example" section.
    And, with what we found on the web, for example replacing this in MyApplication:

    bool MyApplication::x11EventFilter(XEvent* p_event)
    {
        int eventType = p_event->type;
    
        QSharedPointer<QEvent> eventToSend;
    
        if (eventType == ButtonPress)
        {
            XButtonPressedEvent& bpe = p_event->xbutton;
            const QPoint pos(bpe.x_root,bpe.y_root);
            QWidget* widget = qApp->widgetAt(pos);
            if (widget && widget->window() != qApp->activeWindow())
            {
                QPoint local_pos = widget->mapFromGlobal(pos);
                eventToSend = QSharedPointer<QEvent>((QEvent*)new QMouseEvent(QEvent::MouseButtonPress, local_pos, pos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
            }
        }
    
        return false;
    }
    

    To something like this (with installNativeEventFilter(m_myXcbEventFilter) called in MyApplication constructor):

    bool MyXcbEventFilter::nativeEventFilter(const QByteArray& p_eventType, void* p_message, long*)
    {
        if (p_eventType == "xcb_generic_event_t")
        {
            xcb_generic_event_t* ev = static_cast<xcb_generic_event_t *>(p_message);
            uint16_t xcbEventType = ev->response_type & ~0x80;
    
            if (xcbEventType == XCB_BUTTON_PRESS)
            {
                xcb_button_press_event_t* buttonPressEvent = static_cast<xcb_button_press_event_t*>(p_message);
                // Do stuff
            }
        }
    }
    

    But we never fall in xcbEventType == XCB_BUTTON_PRESS, it seems instead there is (at least for button press/release) a XCB_GE_GENERIC that we can cast to xcb_ge_generic_event_t that has an event_type member that contains for example a XCB_BUTTON_PRESS, the code then changed to:

    bool MyXcbEventFilter::nativeEventFilter(const QByteArray& p_eventType, void* p_message, long*)
    {
        if (p_eventType == "xcb_generic_event_t")
        {
            xcb_generic_event_t* ev = static_cast<xcb_generic_event_t *>(p_message);
            uint16_t xcbEventType = ev->response_type & ~0x80;
    
            if (xcb_eventType == XCB_GE_GENERIC)
            {
                xcb_ge_generic_event_t* genericEvent = static_cast<xcb_ge_generic_event_t*>(p_message);
                xcbEventType = genericEvent->event_type;
            }
    
            if (xcbEventType == XCB_BUTTON_PRESS)
            {
                xcb_button_press_event_t* buttonPressEvent = static_cast<xcb_button_press_event_t*>(p_message);
                // Do stuff
            }
        }
    }
    

    Now we fall in xcbEventType == XCB_BUTTON_PRESS on button press but casting to xcb_button_press_event_t seems to have no meaning since root_x, root_y, event_y and event_y members have always the same values anywhere we click.

    Anyone knows how to properly implement this ?

    Thanks


  • Qt Champions 2018



  • @Christian-Ehrlicher Thanks, but if I follow what is happening from the *QXcbConnection::handleXcbEvent(xcb_generic_event_t event) function you pointed, I can see first there is the same

    uint response_type = event->response_type & ~0x80
    

    From which I never get a XCB_BUTTON_PRESS, and, if I follow XCB_GE_GENERIC I get, it goes to:

    QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
    

    That, for XCB_BUTTON_PRESS calls an event filter got from:

    QXcbWindowEventListener *QXcbConnection::windowEventListenerFromId(xcb_window_t id)
    {
        return m_mapper.value(id, 0);
    }
    

    And here I'm lost since QXcbWindowEventListener are added to m_mapper with QXcbConnection::addWindowEventListener I can't seen where it is called, I tried searching where this function is called in other Qt classes and I either found dead ends or classes calling functions just returning false.



  • And in addition, I just tried to implement key press filter and it works fine (we directly got the XCB_KEY_PRESS event type from event->response_type & ~0x80 instead of getting a XCB_GE_GENERIC):

    if (xcbEventType == XCB_KEY_PRESS)
    {
        xcb_key_press_event_t* keyPressEvent = reinterpret_cast<xcb_key_press_event_t*>(ev);
        // Here keyPressEvent->detail has its value changing according to key press
    }
    

  • Qt Champions 2018

    Since XCB_BUTTON_PRESS is directly evaluated in handleXcbEvent() I would guess you must be doing something wrong.



  • Indeed, but I'm not sure I'm doing something wrong, since, all I've done is following Qt's instruction on how to replace QApplication::x11EventFilter with a QAbstractNativeEventFilter class implementing its nativeEventFilter and catching eventType == "xcb_generic_event_t", after that, what comes in nativeEventFilter parameters is definitively not something I have the hand on, and then, in my opinion, the real problem here is, for some reason, I got a XCB_GE_GENERIC event instead of XCB_BUTTON_PRESS event, and I would like to know either how to be able, with current behaviour to manage XCB_BUTTON_PRESS event as a XCB_GE_GENERIC event or to have directly XCB_BUTTON_PRESS event (changing a parameter on Qt for example ?) in nativeEventFilter.



  • Hi again,

    I came back on this subject after a while since updated to Qt5.13 but unfortunately with no amelioration on behaviour, and I then created a small application to reproduce the issue if it can help (https://we.tl/t-SUhYHVWOTj), and if it can help too, here are which event are logged on mouse click:

    virtual bool XcbEventFilter::nativeEventFilter(const QByteArray&, void*, long int*) ; Event type is ["XCB_ALLOC_NAMED_COLOR (uint16_t: 85)"]
    virtual bool XcbEventFilter::nativeEventFilter(const QByteArray&, void*, long int*) ; Event type is ["XCB_CLIENT_MESSAGE (uint16_t: 33)"]
    virtual bool XcbEventFilter::nativeEventFilter(const QByteArray&, void*, long int*) ; Event type is ["XCB_PROPERTY_NOTIFY (uint16_t: 28)"]
    virtual bool XcbEventFilter::nativeEventFilter(const QByteArray&, void*, long int*) ; Event type is ["XCB_GE_GENERIC (uint16_t: 35)"]
    virtual bool XcbEventFilter::nativeEventFilter(const QByteArray&, void*, long int*) ; Event type is ["XCB_PROPERTY_NOTIFY (uint16_t: 28)"]
    

    And on mouse release:

    virtual bool XcbEventFilter::nativeEventFilter(const QByteArray&, void*, long int*) ; Event type is ["XCB_GE_GENERIC (uint16_t: 35)"]
    virtual bool XcbEventFilter::nativeEventFilter(const QByteArray&, void*, long int*) ; Event type is ["XCB_ALLOC_NAMED_COLOR (uint16_t: 85)"]
    

    I somebody can try (notice I put a timer that writes endl to cout every half second in order to properly separate click from release), is it the same result ?

    Or should I follow the handleXcbEvent ? That for what I see is only in QXcbConnection for which I found no documentation. Or follow another way ?

    Thanks


Log in to reply