[Development] QPushButton: drag and drop
Volker Hilsheimer
volker.hilsheimer at qt.io
Fri Jun 10 12:00:12 CEST 2022
> On 9 Jun 2022, at 17:54, Giuseppe D'Angelo <giuseppe.dangelo at kdab.com> wrote:
>
> Hi,
>
> On 09/06/2022 17:20, Volker Hilsheimer wrote:
>> Let’s put things into a perspective here. You are proposing a flag that we perhaps flip on by default within Qt 6, and that might break a whole ton of widgets out there that today correctly implement drag’n’drop and that will start failing in mysterious, and largely untestable (because testing drag’n’drop requires special tools) ways. “Adventurous” indeed :P
>> We are having this discussion is because a widget doesn’t get a QEvent::MouseButtonRelease in symmetry with an earlier MouseButtonPress. As I pointed out earlier, a widget also won’t get a symmetrical MouseButtonRelease when a modal dialog opens in response to press; the release gets eaten by the dialog. (And we have bugs with enter/leave like the one Gatis pointed at, which in my mind are orthogonal to this, and is not addressed by any of the proposals made in this thread so far anyway; but those would be good bugs to fix in order to familiar with the complexity of the code involved here).
>> You are suggesting that all widgets in Qt, and possibly thousands of custom widget implementations out there, have to start adding special code to their mouseReleaseEvent, ignoring specially flagged events because someone might
>> * subclass that widget class and exec() a QDrag or a QDialog in mousePressEvent
>> * or connect to a pressed() signal (if that exists) and do the same
>
> I think there's been a misunderstanding: I am 100% *agreeing* with you here. Changing this behavior suddenly/blindly is a a big no-no, exactly for the reasons you're stating.
>
> Just like you here I was challenging the claim that "well it's a behavior change but any fix is a change so let's fix this". This is what I said:
>
>> There's behaviour break and behaviour break.
>> which is a long way to say "any QWidget subclass handling mouse events needs to be changed". And that's a very high bar for a behavioral change.
>
> ^^^ In other words, I'm NOT for start sending mouse release events around.
>
> Trying to be constructive: the most conservative approach would probably be a custom event. Not a mouse release with a special source, another event altogether, so that existing widgets do not handle it at all, and cannot possibly misbehave. (Then QPushButton & friends could be "fixed" by handling this event instead.)
>
> Sending a release instead/in addition to a custom event _might_ be added, but only behind an opt-in fence (per-widget attribute), which has to be opt-in for a very long time, which makes it unpalatable to me (niche use case; noone will enable it => lack of testing; already covered by the custom event anyways).
>
>
>> And since the argument is “we must be symmetrical with our events so widgets don’t remain in a pressed state”, we cannot really fix the one (QDrag) and not the other (QDialog). If a widget author cannot be expected to maintain their widget state before or after calling QDrag::exec in a mousePressEvent handler, then they cannot be expected to manage their widget state before or after calling QDialog::exec, either.
>> So, if we deliver the release at the end (or beginning?) of the QDrag, then we have to deliver the release when a modal dialog opens (or closes?), because these are the exact same things (user interface enters a different mode, so events get eaten and handled by that mode, which results in asymmetry). And I am not at all convinced that we should send a QEvent::MouseButtonRelease to a widget that opens a modal dialog in their mousePressEvent handler. I’d consider that a bug, breaking the meaning of “modal”. And a drag’n’drop, as it stands today, is modal (no dialog and window activation state as the visual cue, but instead the mouse cursor shows that you are dragging something; your desktop will behave differently, maybe give you other visual cues).
>
> Indeed modal dialog and modal DND are the same thing here. They could both deliver a special event ("mouse grab lost event" or whatever).
>
> (Here's a twist: is the grab truly lost? What if the modal dialog/DND closes, and you never released the mouse? Do you still get mouse events or not? If yes, do we also need a "mouse grab re-acquired" event? :-))
>
>
>> Perhaps you don’t agree that QDrag::exec starts a modal user interface state similar to a modal dialog? Then the next question is whether we need to deal with key events during the drag. Should we send shift/alt/control key presses to the widget as well? Today those are entirely handled by the drag’n’drop machinery to switch the drag operation. How about wheeling the mouse during a drag? Either we are modal (events get eaten) or we are not (events get processed by the grabbing or focus widget). Today we are modal. Changing that is a huge change, and IMHO a wrong change, also deviating from how every desktop environment seems to think about “drag and drop”.
>
> But I also agree that DND is modal, where did I say otherwise?
Excellent, good to have that cleared up :)
Since at least the two of us agree that DND is a modal operation (just like opening a dialog), then sending a release event would be wrong, just like it would be with a dialog. Not “it’s a bug but we can’t change current behavior” wrong, but “the current behavior is correct” wrong - a modally blocked widget must not receive input events.
Which leaves us with the question on whether we should send a new event to inform a widget that its grab has been lost. That could be useful, at this point primarily for the dialog case (where we have a non-blocking way of starting a modal session), but not particularly for the DND case. Implementing the handling of that event then for a meaningful set of widget classes is then a gradual process.
> I just don't like the _current QDrag API_ (implemented via blocking exec()). But that's another story entirely!
Yop, would indeed be an interesting challenge to see how we can implement something non-blocking for this. Might not be possible on all platforms, but figuring that out would be part of the fun.
Volker
More information about the Development
mailing list