Details
-
Suggestion
-
Resolution: Unresolved
-
Not Evaluated
-
None
-
None
-
None
Description
Revisiting my very first patch in qtdeclarative: https://codereview.qt-project.org/c/qt/qtdeclarative/+/24189
The result was an increase in complexity that I don't think I want to repeat in the same way, if the need arises again. It made Qt Quick responsible for this kind of delivery. QtGui can't do it the same way, because it's not responsible for the "visitor pattern": only QQuickWindow (QQuickDeliveryAgent now) knows how to visit each item in the scene, and for each item that doesn't handle the QTouchEvent, it has to try again with a QMouseEvent right there and then. Synthetic event delivery should not be done in a second pass.
But QtGui can also do touch->mouse synthesis. And, touch->mouse is of course not the only kind of event synthesis. Usually QtGui is responsible for it, resulting in more cases of multi-pass delivery: the original event is sent all the way through first (it visits every potential recipient object), and then the synthetic event is sent all the way through too. There can always be a surprise that the original event is handled and accepted by something out of sight and the synthesis doesn't happen.
The latest kind of synthesis that comes up again is mouse->QContextMenuEvent. In https://codereview.qt-project.org/c/qt/qtbase/+/603535 we move the logic for that to QWindowPrivate::maybeSynthesizeContextMenuEvent(). It can happen that a Qt Quick scene includes a TapHandler to directly handle right-mouse-button events to open a Menu, maybe even in the root window's contentItem. That may be intended as a "last resort" context menu: but actually by handling mouse events directly, it can act as the "first responder", in spite of other context menus in the scene that are waiting for a QContextMenuEvent. So we end up with a problem that the two techniques can't be mixed (if you use ContextMenu, you probably shouldn't use TapHandler to open menus unless you are very careful about doing it only on "topmost" items); and we can expect users to write bugs about it, especially if they already have used this pattern to get context menus prior to 6.9. And with https://codereview.qt-project.org/c/qt/qtdeclarative/+/612253 every text control will have a default context menu. We might continue doing that with other controls.
I was loathe to handle QContextMenuEvent at all in Qt Quick, because it's yet another event type that DeliveryAgent has to deal with: it's not quite like any of the others, and delivery logic needed some duplication and refactoring to do that nicely.
Delivery of synthetic events in general has to happen at just the right place in the code; but it's also predictable that every QTouchEvent or QTabletEvent could result in a synthetic QMouseEvent, and every right-button QMouseEvent could result in a QContextMenuEvent.
So what about some sort of chaining? What if the original event had a pointer to whatever the followup event would be, so that every recipient object can choose which one to handle? (What if this was a bit like "data flavors", the inspiration for handling different data types on the clipboard? and maybe the implementation would resemble a linked list.) Well then we'd have more construction overhead, needing to build all possible "flavors" before we can start delivery. So it would have to be made lazy somehow: the synth event would be created the first time delivery logic or a potential event recipient tries to access the child event; so it just needs an accessor that constructs it on-demand.
We should be able to handle multiple stages of synthesis too, e.g. touch long-press might generate a right mouse event and then a context menu event, or something like that; so the child event can have its own child, and so on. It's a lazy linked list.