Drag & Drop bug (piece drops through to an underlying window) - advice needed

Investigating issue #12480, I’ve found that the issue arises because two (or more?) overlapping windows may generate a mouseReleased event from each of the windows from a single physical action. The events are received in the same order as the map windows listed in the buildFile. The first event is fully processed - moving the piece to what is typically the underlying map. Once this happens, the next event in the sequence will have no effect.

At least, that’s what I’ve observed. Here’s a typical log from a single Drag & Drop action:

mouseReleased() executing for: Main Map, event source: VASSAL.build.module.Map$View[,0,0,2279x1083,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=297,maximumSize=,minimumSize=,preferredSize=]
mouseReleased() executing for: Allies Hand, event source: VASSAL.build.module.PrivateMap$View[,0,0,1357x700,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=393,maximumSize=,minimumSize=,preferredSize=]

In this example the PrivateMap (a Player Hand) overlaid the Main Map but the piece was placed on the Main Map.

I’ve considered various ways to detect & workaround this error but without success. A key obstacle is that I can’t find a reliable way to determine if one window lies on top of another on screen.There seems to be no OS-independent solution to that (i.e. in Vassal or Java Swing), at least none that I can find. If this were possible, I’d propose to ignore mouseReleased from an occluded map (I’ve not yet seen an instance of an occluded map generating an event but the overlying map not generating one).

Could there be a solution in the way in which maps handle Drag & Drop events?

If anything jumps out at you from my findings so far or if you have any suggestions as to how I can take this further, please chip in.

I can only make a few general remarks from my experience with Qt. I am not sure they will help.

Do the windows have a child-parent relationship? If an event is not handled in the child will it propagate to the parent? An event is typically handled by the event handler returning true. Sometimes it’s better windows are siblings.

Is there a clear zorder? Do windows have a zorder? Is this zorder correct with what is actually displayed on the screen. Must a window be activated to accept drops?

Is it necessary for both windows to accept drops at the same time? Can drops be turned off if they are not wanted?

Can the error be replicated? Under given circumstances will it always occur? The event system can exhibit “race-conditions”. Then the result is unpredictable.

1 Like

That reminded me to see what happens if I make the main map detached from the Module window. Maybe this makes it a sibling rather than part of the parent of other map windows. Anyway, it means that behaviour is different. The main map window now pushes the others to the back when it is in focus and the problem didn’t recurr in the quick, inconclusive test I just did.

Z-order only applies within the same Swing structure (JFrame?). Not between separate windows, so I understand after investigating. Windows accept drops without apparently being activated. However, I reckon the window is activated when the drag / drop operations includes pausing for the target window to come back to the foreground.

Yes, except in that portion of a window that is occluded by another. The challenge would be to determine that.

It can be replicated, not yet reliably but I’ve observed that it seems more likely to occur where the drop is over an unpopulated section of a target window. Of course, this might indicate a timing dependency for a race condition.

Thanks for your thoughts so far.

An update.

I have found that even dragging a piece within the Main Map can generates two events. Whether or not the map is detached from the Module window.

Furthermore and perhaps pointing to a solution, the event clickCount() is, so far, consistently zero for the first of a “double event” and otherwise always 1. Other logged information indicates that in fact the “double event” is two separate events.

 mouseReleased() executing for: Main Map @ java.awt.Point[x=674,y=417] e#1740832628882, event clicks: 1, event source: VASSAL.build.module.Map$View[,0,0,2279x1083,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=297,maximumSize=,minimumSize=,preferredSize=]
 mouseReleased() executing for: Main Map @ java.awt.Point[x=937,y=699] e#1740832638568, event clicks: 1, event source: VASSAL.build.module.Map$View[,0,0,2279x1083,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=297,maximumSize=,minimumSize=,preferredSize=]
 mouseReleased() executing for: Main Map @ java.awt.Point[x=593,y=758] e#1740832642202, event clicks: 1, event source: VASSAL.build.module.Map$View[,0,0,2279x1083,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=297,maximumSize=,minimumSize=,preferredSize=]
 mouseReleased() executing for: Main Map @ java.awt.Point[x=304,y=718] e#1740832644283, event clicks: 1, event source: VASSAL.build.module.Map$View[,0,0,2279x1083,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=297,maximumSize=,minimumSize=,preferredSize=]
 mouseReleased() executing for: Main Map @ java.awt.Point[x=508,y=757] e#1740832645618, event clicks: 0, event source: VASSAL.build.module.Map$View[,0,0,2279x1083,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=297,maximumSize=,minimumSize=,preferredSize=]
 mouseReleased() executing for: Main Map @ java.awt.Point[x=510,y=733] e#1740832645876, event clicks: 1, event source: VASSAL.build.module.Map$View[,0,0,2279x1083,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=297,maximumSize=,minimumSize=,preferredSize=]
 mouseReleased() executing for: Main Map @ java.awt.Point[x=1285,y=511] e#1740832948153, event clicks: 0, event source: VASSAL.build.module.Map$View[,0,0,2279x1083,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=297,maximumSize=,minimumSize=,preferredSize=]
 mouseReleased() executing for: Allies Hand @ java.awt.Point[x=1230,y=448] e#1740832948307, event clicks: 1, event source: VASSAL.build.module.PrivateMap$View[,0,0,1357x700,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=393,maximumSize=,minimumSize=,preferredSize=]

Based on this information, I’m investigating canHandleEvent() within PieceMover.java which allows getClickCount() 0 or 1. Maybe it should only allow 1 or, failing that, perhaps mouseReleased() must specifically exclude zero.

I have submitted PR #13875 to prevent zero click events from being processed as drops. This works in my limited testing, including for band-selected moves. So far as my reading of the source code goes, the change only affects Drag & Drop so I am hopeful that it will pass review by the developers. If not, perhaps I will get useful feedback to pursue this further.

Meanwhile, for anyone experiencing the problem who wants to test this fix for themselves (please do), the development build is up here (you may need to page through from that link until you find the list of builds).

Fix released in Vassal 3.7.16.