Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 323272 - [GTK3] shell.traverse(SWT.TRAVERSE_RETURN) selects default button too late
Summary: [GTK3] shell.traverse(SWT.TRAVERSE_RETURN) selects default button too late
Status: CLOSED WONTFIX
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 3.7   Edit
Hardware: PC Linux-GTK
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Platform-SWT-Inbox CLA
QA Contact:
URL:
Whiteboard: stalebug
Keywords: triaged
Depends on:
Blocks:
 
Reported: 2010-08-20 13:12 EDT by Markus Keller CLA
Modified: 2020-11-20 03:37 EST (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Markus Keller CLA 2010-08-20 13:12:56 EDT
I20100817-0800

We're having trouble with an automated test (org.eclipse.ui.workbench.
texteditor.tests.FindReplaceDialogTest#testShiftEnterReversesSearchDirection()), but this problem can also hurt in real world scenarios.

The snippet below calls "shell.traverse(SWT.TRAVERSE_RETURN)", which will eventually send a selection event to the default button. I can accept that the event is added to the event queue and executed from there, but I would expect that flushing the event queue makes sure the selection event is sent. This works fine on Windows (XP).

But on GTK, Shell#traverse(..) does not add the event to the queue, and I found no solution to make sure the traversal is done. If you set longDelays to true in the snippet, then it kinda "works", but it's not reliable.


import org.eclipse.swt.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;

public class Snippet {
    public static void main(String[] args) throws InterruptedException {
        Display display= new Display();
        Shell shell= new Shell(display);
        shell.setLayout(new GridLayout(1, false));

        Button button= new Button(shell, SWT.PUSH);
        button.setText("OK");
        button.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                System.out.println("OK selected");
            }
        });

        shell.setDefaultButton(button);

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

        shell.traverse(SWT.TRAVERSE_RETURN);

        boolean longDelays= false;
        if (longDelays) {
            for (int i= 0; i < 10; i++) {
                while (display.readAndDispatch()) { /* flush*/ }
                Thread.sleep(100);
            }
        } else {
            while (display.readAndDispatch()) { /* flush */ }
        }

        System.out.println("after TRAVERSE_RETURN");

        display.dispose();
    }
}
Comment 1 Felipe Heidrich CLA 2010-08-20 14:52:48 EDT
In SWT we call gtk_window_activate_default() synchronously when shell.traverse(SWT.TRAVERSE_RETURN).

This delay is in GTK, we call gtk_window_activate_default() which sends the activate signal. GtkButton has a timeout of 250ms (sorry, GTK doing it) in the  activate to send click (our selection comes from the click signal).

How is this for a work around:
public static void main123(String[] args) {
    Display display= new Display();
    Shell shell= new Shell(display);
    shell.setLayout(new GridLayout(1, false));
    final boolean[] clicked = new boolean [1];
    Button button= new Button(shell, SWT.PUSH);
    button.setText("OK");
    button.addSelectionListener(new SelectionAdapter() {
        public void widgetSelected(SelectionEvent e) {
            System.out.println("OK selected");
            clicked[0] = true;
        }
    });
    shell.setDefaultButton(button);
    shell.pack();
    shell.open();
    shell.traverse(SWT.TRAVERSE_RETURN);
    long time = System.currentTimeMillis();
    while (!clicked[0] && (System.currentTimeMillis() - time) < 1000) {
       if (!display.readAndDispatch())
         display.sleep();
    }
    System.out.println("after TRAVERSE_RETURN");
    display.dispose();
}
Comment 2 Markus Keller CLA 2010-08-23 06:11:26 EDT
Yeah, we can work around it if necessary (already released a workaround in HEAD). But we can't use "display.sleep()", since that may block forever.
Comment 3 Eric Williams CLA 2018-11-30 11:39:07 EST
Still reproducible, likely broken due to GTK event caching or not flushing events quickly enough. In fact, calls like gdk_flush() are completely gone on GTK4 anyway.
Comment 4 Eclipse Genie CLA 2020-11-20 03:37:30 EST
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet. As such, we're closing this bug.

If you have further information on the current state of the bug, please add it and reopen this bug. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.