Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-107994

Modal objects do not fully capture the mouse

    XMLWordPrintable

Details

    Description

      Hello!

      According to our current understanding, Qt fundamentally can't handle creation of modal objects (menus, mainly) on mouse down events properly. The problem seems to be that Qt has a hard-coded mechanism of exclusively grabbing (similar to "capturing" in Windows API terms) the mouse upon a button down event to the QuickItem which accepted the event and the said grab is active until all mouse button downs are released. It doesn't seem that this mechanism can be overridden, at least not in a required way.

      The problem with this mechanism in particular is that if one creates a modal menu on this button down event, the menu modality (that is the expectation that more or less all mouse input goes to this menu exclusively) is overridden by the said hard-coded grab mechanism, and the mouse input doesn't go to the menu until all mouse buttons are released and the hard-coded grab is released too.

      This yields the following symptoms:

      • "one-click" menu operations (clicking on the button which activates the menu on button down, moving over the menu items while still holding the button pressed and releasing the button over the desired menu item) do not work properly. The menu neither updates its item highlight while the mouse is moved over the menu, nor does it react to the mouse button release. Only after all mouse buttons are released the first time (and the hard-coded exclusive grab is released) the menu starts to react to the mouse moves and one can issue a second mouse click to select the menu item.
      • In our specific situation we also had a special generic handling of mouse button up events. This handling was expected to kick in in cases when mouse down event does not create a menu (while, in cases when menu is created on mouse down, the opening of a modal menu would steal the mouse, and thus the mouse up would normally not arrive at the original item). After migration to Qt the mouse up event always arrives at the original item, even if a modal menu is created, and we had to change the UI logic at such places.

      It does not seem possible to properly workaround the situation by the existing Qt mechanism. The problem is that the hard-coded exclusive grab is happening inside the Qt framework after we return from our QuickItem's mouse down handler routine and thus we don't have execution control anymore to undo this grab. We probably could try to undo the grab upon whatever next event arrives at the said QuickItem, but that might be too late, and we also have an impression that the menu modality is already somewhat generally broken by the said hard-coded grab and we don't know how to fully restore it.

      Even if somehow the said workaround could be made to work, all in all we do not believe that such complexities are appropriate for such a generic operation as "one-click menu handling". The example code below also illustrates that the problem doesn't seem to be with the (rather complicated) way we're dealing with menus in our C++ code, but already exists in a basic Qml example.

      Example repro steps 1:

      • click on the button, but don't release mouse button just yet. Instead move the mouse over the menu. Expected: the menu highlight follows the mouse. Observed: nothing happens.
      • while still holding the mouse button down, position the mouse over one of the menu items and release the mouse. Expected: the menu item is selected and the menu is closed. Observed: nothing happens.

      Example repro steps 2:

      • click on the button, move the mouse a little bit and release mouse button while mouse cursor is still over the button and not over the menu or the background. Expected: nothing happens, the menu just stays open. Observed: the button color is changed (because the button receives a mouse up event, which we didn't expect to receive, since the mouse must be grabbed by the menu at this point). Strangely this doesn't happen if the mouse is not moved in between, we have no explanation for this discrepancy in the behavior.
      import QtQuick 2.15
      import QtQuick.Controls 2.15FocusScope {
          id: root
          anchors.fill: parent
          
          component MyItem: MenuItem {
              text: hovered ? `Hovered ${text}` : text
              hoverEnabled: true
          
              onReleased: button.background.color = "green"
              
              HoverHandler {
                  id: mouse
                  acceptedDevices: PointerDevice.Mouse
                  cursorShape: Qt.PointingHandCursor
              }
          }
          
          Menu {
              id: menu
              x: 0
              y: 32
              
              modal: true
              
              MyItem { text: "A" }
              MyItem { text: "B" }
          }
          
          Button {
              text: "Open Menu"
              id: button
              background : Rectangle {
                  color: "red" 
              }
              width: 150
              height: 32
              
              onPressed: { 
                  button.background.color = "red" 
                  menu.open()
              }
              onReleased: button.background.color = "blue"
          }
      }
      

      Attachments

        Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

              srutledg Shawn Rutledge
              aqn Vadim Zavalishin
              Votes:
              4 Vote for this issue
              Watchers:
              8 Start watching this issue

              Dates

                Created:
                Updated:

                Gerrit Reviews

                  There are no open Gerrit changes