eclipse-platform / eclipse.platform.swt

Eclipse SWT
https://www.eclipse.org/swt/
Eclipse Public License 2.0
114 stars 132 forks source link

[GTK] Display.getActiveShell() may report wrong shell #726

Open SyntevoAlex opened 1 year ago

SyntevoAlex commented 1 year ago

Describe the bug In GTK, Shell.bringToTop() optimistically sets active shell to this: https://github.com/eclipse-platform/eclipse.platform.swt/blob/24247323f81c3fe5fa231f3ccd6ad8eb36a6c97b/bundles/org.eclipse.swt/Eclipse%20SWT/gtk/org/eclipse/swt/widgets/Shell.java#L638-L639

This causes it to 1) Report shell as already active too early 2) If Linux window manager decides NOT to activate shell, it will report wrong shell

Note that Shell.bringToTop() is called from various places, notably Shell.open()

To Reproduce

final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout (new GridLayout (1, true));

Label hint = new Label(shell, 0);
hint.setText(
    "1) Run on Linux\n" +
    "2) Click the test button below\n" +
    "3) Issue #726: For a short while, new Shell is reported as active while it is not yet\n" +
    "4) Click the test button below and quickly press and hold mouse on this Shell's title\n" +
    "5) This time, new Shell will not be activated\n" +
    "6) Issue #726: new Shell is reported as active despite it is not\n"
);

Button button = new Button(shell, SWT.PUSH);
button.setText("Test");
button.addListener(SWT.Selection, e -> {
    Shell shell2 = new Shell(shell);
    shell2.setSize(300, 300);

    boolean[] realIsActive = new boolean[1];
    shell2.addListener(SWT.Activate, e2 -> {
        realIsActive[0] = true;
        System.out.format("%d SWT.Activate received%n", System.nanoTime());
    });

    // Let user click and hold Shell title
    try {
        Thread.sleep(1000);
    } catch (InterruptedException ex) {
        throw new RuntimeException(ex);
    }

    shell2.open();

    while (!realIsActive[0] && !shell.isDisposed()) {
        if (!display.readAndDispatch()) display.sleep();
        boolean reportedIsActive = display.getActiveShell() == shell2;
        System.out.format(
            "%d Shell is active real/reported: %c/%c%n",
            System.nanoTime(),
            realIsActive[0]  ? 'Y' : 'N',
            reportedIsActive ? 'Y' : 'N'
        );
    }
});

shell.pack();
shell.open();

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

display.dispose();

Expected behavior Correct Shell shall be reported by Display.getActiveShell()

Environment:

  1. Select the platform(s) on which the behavior is seen:
      • [ ] All OS
      • [ ] Windows
      • [x] Linux
      • [ ] macOS

Workaround Wait until SWT.Activate is really received before thinking that new shell has been activated.

SyntevoAlex commented 1 year ago

I don't plan to prepare a fix for this any soon.

Phillipus commented 1 year ago

I don't plan to prepare a fix for this any soon.

There's a solution for this situation:

Issue issue726 = new Issue();
SyntevoAlex syntevoAlex2 = SyntevoAlex.clone();
syntevoAlex2.fix(issue726);