Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to port QApplication::x11EventFilter to XCB QAbstractNativeEventFilter
Forum Updated to NodeBB v4.3 + New Features

How to port QApplication::x11EventFilter to XCB QAbstractNativeEventFilter

Scheduled Pinned Locked Moved Unsolved General and Desktop
8 Posts 3 Posters 2.4k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • G Offline
    G Offline
    Gluttony
    wrote on last edited by
    #1

    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

    1 Reply Last reply
    0
    • Christian EhrlicherC Offline
      Christian EhrlicherC Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Since Qt is opensource you can take a look to the place where the eventFilter is called:
      https://code.woboq.org/qt5/qtbase/src/plugins/platforms/xcb/qxcbconnection.cpp.html#_ZN14QXcbConnection14handleXcbEventEP19xcb_generic_event_t

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      G 1 Reply Last reply
      1
      • Christian EhrlicherC Christian Ehrlicher

        Since Qt is opensource you can take a look to the place where the eventFilter is called:
        https://code.woboq.org/qt5/qtbase/src/plugins/platforms/xcb/qxcbconnection.cpp.html#_ZN14QXcbConnection14handleXcbEventEP19xcb_generic_event_t

        G Offline
        G Offline
        Gluttony
        wrote on last edited by
        #3

        @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.

        1 Reply Last reply
        0
        • G Offline
          G Offline
          Gluttony
          wrote on last edited by
          #4

          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
          }
          
          1 Reply Last reply
          0
          • Christian EhrlicherC Offline
            Christian EhrlicherC Offline
            Christian Ehrlicher
            Lifetime Qt Champion
            wrote on last edited by
            #5

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

            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
            Visit the Qt Academy at https://academy.qt.io/catalog

            1 Reply Last reply
            0
            • G Offline
              G Offline
              Gluttony
              wrote on last edited by
              #6

              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.

              1 Reply Last reply
              0
              • G Offline
                G Offline
                Gluttony
                wrote on last edited by
                #7

                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

                D 1 Reply Last reply
                0
                • G Gluttony

                  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

                  D Offline
                  D Offline
                  DalePennington
                  wrote on last edited by
                  #8

                  @Gluttony
                  I am also doing a QT4 to QT5 port and ran into the same issue. But I have also found the answer.

                  The problem lies in that QT5 will use the XInput extension if it is present (and I think it almost always is). This means your button presses will come via the xcb_input_button_press_event_t (defined in xcb/xinput.h) as opposed to xcb_button_press_event_t. The good news is that most of the fields in the the xcb_button_press_event_t are in the xcb_input_button_press_event_t (I did not find state and same_screen), with the same name and meaning. The bad news is that they are not at the same offsets, so you cannot just do a structure map. I ended up creating a helper function that I passed the fields I was interested in.

                  Now the even is delivered via the XCB_GE_GENERIC event. This is one of the common ways for extensions to pass in events. To get to it properly you need to do the following :

                  1. Check if XInput is installed and query xcb for its major opcode. QXcbBasicConnection::initializeXInput2() has a good example of this.
                  2. Check to see if the XCB_GE_GENERIC event is from XInput. This is done by comparing the extension field with the major opcode you got from (1)
                  3. Now the event_type field will contain the extension specific opcodes. For XInput, they are defined in xcb/xinput.h. You then recast and go like you do for normal events.

                  As an example

                  void HandleButtonPress(uint8_t button)
                  {
                      ...DoStuff...
                  }
                  
                  // Main thread 
                  
                  DoXInputInitialize(); // gets bHasXi2 and iXi2Opcode
                  
                  switch( eventType )
                  {
                    case XCB_BUTTON_PRESS:
                      auto *pButtonEvent = 
                        reinterpret_cast<xcb_button_press_event_t *>(pEvent);
                      HandleButtonPress(pButtonEvent->detail);
                      return true;
                         /// More Stuff
                    case XCB_GE_GENERIC:
                      auto *pGeEvent = reinterpret_cast<xcb_ge_generic_event_t *>(pEvent);
                      if( bHasXi2 && iXi2Opcode == pGeEvent->extension )
                      {
                        // This is from XInput
                        switch( pGeEvent->event_type )
                        {
                          case XCB_INPUT_BUTTON_PRESS:
                            auto *pXiButtonEvent = 
                              reinterpret_cast<xcb_input_button_press_event_t *>(pGeEvent);
                            HandleButtonPress(pXiButtonEvent->detail);
                            return true;
                        }
                      }
                  }
                  

                  I hope this answers your issues.

                  Dale Pennington

                  1 Reply Last reply
                  2

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved