Fix mouse click event leak on context menu close - #1931
Conversation
f2b66f7 to
d95770b
Compare
CendioOssman
left a comment
There was a problem hiding this comment.
This sounds like a FLTK issue, so it should be ideally be fixed there. Have you reported it to them?
That said, a minimal workaround is acceptable if it causes practical practical problems for you.
| if (menuOpened) | ||
| return; |
There was a problem hiding this comment.
This is very non-obvious, so a comment would be nice, explaining that this is a workaround and for what
|
|
||
| menuOpened = true; | ||
| m = contextMenu->popup(); | ||
| Fl::add_timeout(0.0, handleMenuClosed, this); |
There was a problem hiding this comment.
Why the timer? Isn't the mouse press handled by the time popup() returns?
There was a problem hiding this comment.
No. But when the contextMenu->popup(); returns, the mouse events that caused the popup to close are already queued (and they fire Viewport::handle(int)). So we queue this instant timer event after them and ignore the mouse events until the timeout event happens.
All subsequent mouse events will be queued after our timer, so they will be handled normally.
It seems like it's NOT a FLTK bug per se. Tested with FLTK 1.3.11, which is the old legacy version, and it works fine even there.
Not that I use this popup menu a lot. But when I do and decide to click it away it causes unwanted input to be sent to the server potentially messing with the running application. |
I have modified the above class My_Box : public Fl_Box {
public:
using Fl_Box::Fl_Box;
int handle(int event) {
printf("My_Box::event(%d)\n", event);
return Fl_Box::handle(event);
}
}; My_Box b(200,200,200,100,"Press right button\nfor a pop-up menu");
And in TigerVNC's viewer it's the FL_RELEASE event that is being sent to the server. FLTK must handle this situation internally for its widgets not to act on these events. So we would either need to filter it out somehow which might be tricky (FL_RELEASE with no earlier FL_PUSH after FL_ENTER?), or simply use this workaround. |
d95770b to
0357199
Compare
|
Ah, I see what's going on. Unfortunately, it's pretty fundamental to how VNC and vncviewer work. So it will be difficult to work around in a nice way. The problem is that VNC isn't concerned with FL_MOVE vs FL_PUSH vs FL_RELEASE. It only cares about the current state of the mouse. So we never look at what type of event we got, only what buttons are pressed. The menu closes when a mouse button is pressed. This is consistent with other toolkits. But after that press, we'll start getting move events. Again, I'd say this is consistent with other toolkits. The issue is that for those move events, we'll correctly deduce that a mouse button is pressed. So we'll send that to the server. Which will result in the applications seeing a mouse press. |
|
Subsequent move events (and ButtonPress events they may cause) are not an issue here. Clicking away any popup menu (Qt, GTK, FLTK) with mouse pointer over a locally running This never generates click events in the underlying windows, so they do not perform any unwanted actions. But when you click away the TigerVNC's context menu over a Indeed we have a problem with ButtonPress Event generated by the VNC. Clicking away TigerVNC's context menu causes remote applications to perform actions related to this unwanted click event. This patch suppresses the orphaned Release Event, which solves this problem. And if you click away the context menu by pressing-and-holding the left mouse button over the remote |
0357199 to
680fa09
Compare
|
Updated:
You are right, they are all indeed move events (reported from FLTK), 11 == FL_MOVE: But the mouse pointer didn't move during the click! Are these move events which occurred when the mouse pointer left the context menu and was moving over the main window, before the click? |
680fa09 to
3fc1071
Compare
| if (menuOpened) { | ||
| if (buttonMask != 0) { | ||
| vlog.debug("Ignored mouse event %d,%d while closing menu.", event, buttonMask); | ||
| return 1; | ||
| } | ||
| vlog.debug("Allowed mouse event %d,%d while closing menu.", event, buttonMask); | ||
| } |
There was a problem hiding this comment.
Updated to allow (move) events that report no buttons pressed in buttonMask.
This properly updates the mouse position when closing the context menu with an ESC key.
It seems there is some kind of race condition in FLTK when a popup menu is being closed, because these move events have buttons pressed randomly reported for them.
Or maybe reading Fl::event_button1/2/3() for such events queued while closing a popup menu does not work reliably?
Fri Mar 21 23:17:39 2025
Viewport: Ignored mouse event 11,1 while closing menu.
Viewport: Ignored mouse event 11,1 while closing menu.
Viewport: Ignored mouse event 11,1 while closing menu.
Viewport: Ignored mouse event 11,1 while closing menu.
Fri Mar 21 23:17:40 2025
Viewport: Allowed mouse event 11,0 while closing menu.
Viewport: Allowed mouse event 11,0 while closing menu.
Viewport: Allowed mouse event 11,0 while closing menu.
Viewport: Allowed mouse event 11,0 while closing menu.
11,1 = event,buttonMask
There was a problem hiding this comment.
I have added one more temporary debug() to log every mouse event occurring in those situations:
if (menuOpened) {
if (buttonMask != 0) {
vlog.debug("Ignored mouse event %d,(%d,%d),%d while closing the menu.", event, Fl::event_x(), Fl::event_y(), buttonMask);
return 1;
}
vlog.debug("Allowed mouse event %d,(%d,%d),%d while closing the menu.", event, Fl::event_x(), Fl::event_y(), buttonMask);
} else {
vlog.debug("Allowed mouse event %d,(%d,%d),%d.", event, Fl::event_x(), Fl::event_y(), buttonMask);
}Clicking away the menu, button pressed randomly reported:
Fri Mar 21 23:57:33 2025
Viewport: Ignored mouse event 11,(980,525),1 while closing the menu.
Viewport: Ignored mouse event 11,(980,525),1 while closing the menu.
Viewport: Ignored mouse event 11,(980,525),1 while closing the menu.
Viewport: Ignored mouse event 11,(980,525),1 while closing the menu.
Viewport: Allowed mouse event 2,(980,525),0.
Viewport: Allowed mouse event 11,(980,525),0.
Clicking away the menu, no buttons randomly reported:
Fri Mar 21 23:57:34 2025
Viewport: Allowed mouse event 11,(941,556),0 while closing the menu.
Viewport: Allowed mouse event 11,(941,556),0 while closing the menu.
Viewport: Allowed mouse event 11,(941,556),0 while closing the menu.
Viewport: Allowed mouse event 11,(941,556),0 while closing the menu.
Clicking away the menu with press & hold & drag & release:
Fri Mar 21 23:58:11 2025
Viewport: Ignored mouse event 11,(952,473),1 while closing the menu.
Viewport: Ignored mouse event 11,(952,473),1 while closing the menu.
Viewport: Ignored mouse event 11,(952,473),1 while closing the menu.
Viewport: Ignored mouse event 11,(952,473),1 while closing the menu.
Viewport: Allowed mouse event 11,(953,473),1.
Viewport: Allowed mouse event 11,(954,473),1.
Viewport: Allowed mouse event 11,(955,473),1.
[...]
Viewport: Allowed mouse event 11,(980,486),1.
Viewport: Allowed mouse event 2,(980,486),0.
Viewport: Allowed mouse event 11,(980,486),0.
Clicking away the menu with press & hold & release:
Fri Mar 21 23:58:55 2025
Viewport: Ignored mouse event 11,(920,503),1 while closing the menu.
Viewport: Ignored mouse event 11,(920,503),1 while closing the menu.
Viewport: Ignored mouse event 11,(920,503),1 while closing the menu.
Viewport: Ignored mouse event 11,(920,503),1 while closing the menu.
Fri Mar 21 23:58:56 2025
Viewport: Allowed mouse event 2,(920,503),0.
Viewport: Allowed mouse event 11,(920,503),0.
Closing the menu with an ESC key:
Fri Mar 21 23:59:38 2025
Viewport: Allowed mouse event 11,(1213,468),0 while closing the menu.
Viewport: Allowed mouse event 11,(1213,468),0 while closing the menu.
Viewport: Allowed mouse event 11,(1213,468),0 while closing the menu.
Viewport: Allowed mouse event 11,(1213,468),0 while closing the menu.
These 4 phantom move events at constant pointer position are consistent.
And it seems the patch properly filters out the random reports for the button still being pressed when the menu is being closed.
8cf562e to
39a8436
Compare
39a8436 to
6466ffc
Compare
But as shown in your output, remote applications will see a click, not just movement. Which means that the workaround suggested in this PR is very fragile and will often fail.
The pointer is grabbed by the menu. I suspect we get a fake movement event when the grab is released. |
|
@CendioOssman Please check my later comments: The problem is with 4 phantom Move Events (FL_MOVE == 11) which should probably never occur in FLTK in the first place. |
6466ffc to
7697a55
Compare
|
The problem is not just any stray events we get just as the menu closes. We can get more events after that. This is broken for me:
At step 3, I get a mouse click, even with your changes. Are you seeing the same thing? |
I'm also getting a mouse click here, but at step 4. xev: https://phd.github.io/js-mouse-events.html (events order from bottom to top): This behavior is different from what all other toolkits do - they eat also the mouse release event after clicking away the a popup menu. |
7697a55 to
9708a74
Compare
|
I think this will give a rather unpredictable user experience. If the mouse is sensitive enough, or if the user is not still enough, they'll still get clicks, but now more randomly. This needs to be fixed more fully for it to be merged. |
9708a74 to
bca2935
Compare
bca2935 to
8596f21
Compare
8596f21 to
cb5c7a5
Compare
When closing the F8 popup menu by clicking somewhere on the TigerVNC viewer's window a mouse click event is sent to the server.
No other toolkit nor application behaves like that when closing a popup menu - the closing click is ignored as an input.
And so it should be ignored here, especially that this input is being sent to a remote machine.
This commit fixes it by relying on FLTK's event loop which lets us know the lifetime of our popup menu and therefore easily filter out the closing mouse click event.