eclipse.platform.swt icon indicating copy to clipboard operation
eclipse.platform.swt copied to clipboard

[Win32] Showing a dialog breaks setCapture contract

Open tmssngr opened this issue 1 year ago • 2 comments
trafficstars

Describe the bug setCapture(true) can be used to get notified about all mouse events until setCapture(false) is invoked. This contract is broken if a dialog is shown while the user drags - the mouse-up event is not sent to the control.

To Reproduce

  • launch the below snippet
  • immediately start dragging by clicking (and holding) the left mouse button inside the window (a mouse-down event is logged as well as mouse-move events)
  • after 2s a dialog occurs
  • release the mouse and close the dialog (no mouse-up event is logged)
  • try the drag again
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;

public class DragTest {

	public static void main(String[] args) {
		final Display display = new Display();

		final Shell shell = new Shell(display);
		final Listener listener = new Listener() {
			private boolean dragging;

			@Override
			public void handleEvent(Event event) {
				if (event.type == SWT.MouseDown) {
					System.out.println("mouse down " + event.button);
					if (event.button == 1) {
						if (dragging) {
							throw new IllegalStateException();
						}
						dragging = true;
						shell.setCapture(true);
					}
				}
				else if (event.type == SWT.MouseUp) {
					System.out.println("mouse up " + event.button);
					if (event.button == 1) {
						dragging = false;
						shell.setCapture(false);
					}
				}
				else if (event.type == SWT.MouseMove) {
					System.out.println("mouse move " + Integer.toHexString(event.stateMask & SWT.BUTTON_MASK));
				}
			}
		};
		shell.addListener(SWT.MouseDown, listener);
		shell.addListener(SWT.MouseUp, listener);
		shell.addListener(SWT.MouseMove, listener);
		shell.setSize(400, 300);
		shell.open();

		display.timerExec(2000, ()-> {
			if (shell.isDisposed()) {
				return;
			}

			final Shell shell2 = new Shell(shell, SWT.DIALOG_TRIM | SWT.PRIMARY_MODAL);
			shell2.setSize(200, 100);
			shell2.open();
		});

		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}

		display.dispose();
	}
}

Expected behavior The mouse up event is sent when releasing the mouse button (or if not possible, when showing the dialog; or allow to receive an event about showing a dialog).

Environment:

  1. Select the platform(s) on which the behavior is seen:
    • [ ] All OS
    • [x] Windows
    • [ ] Linux
    • [ ] macOS
  1. Additional OS info (e.g. OS version, Linux Desktop, etc)

Workaround (or) Additional context Maybe check the mouse move events for the mouse button to simulate a mouse-up event.

tmssngr avatar Apr 29 '24 13:04 tmssngr

@tmssngr can you contribute a fix, please?

jukzi avatar May 13 '24 11:05 jukzi

I doubt I'd have the required knowledge about SWT internals or Windows API to solve that correctly.

tmssngr avatar May 14 '24 19:05 tmssngr