Hi,

Please see the attached reproducer which listens for an
WINDOW_LOST_FOCUS event on a dialog with a frame as parent. Once the
dialog is disposed I'd expect a WINDOW_LOST_FOCUS event being fired[1]
before a WINDOW_CLOSED event. However, this doesn't seem to be the case
sometimes. Example output:

--------------------- RUNNING TEST -------------------
got WINDOW_GAINED_FOCUS event on dialog
---> calling dialog1 dispose
correctly got WINDOW_LOST_FOCUS event on dialog
dialog closed
Test passed
--------------------- RUNNING TEST -------------------
got WINDOW_GAINED_FOCUS event on dialog
---> calling dialog1 dispose
correctly got WINDOW_LOST_FOCUS event on dialog
dialog closed
Test passed
--------------------- RUNNING TEST -------------------
got WINDOW_GAINED_FOCUS event on dialog
---> calling dialog1 dispose
Exception in thread "main" dialog closed
Test failed
java.lang.RuntimeException: Test failed
        at WindowLostFocusReproducer.main(WindowLostFocusReproducer.java:26)

So the event gets fired twice correctly, but on the third iteration this
event isn't fired. I've tested this on Fedora 21 with gnome-shell
3.14.4-2.fc21, F22 with gnome-shell 3.16 and on RHEL 6 with gnome 2.28.2
All of them seem to be affected. Is this a bug or a feature? Any
thoughts as to how to debug events?

This happens with both, an OpenJDK 8u45 and a recent OpenJDK 9 build.

Thanks,
Severin

[1] https://docs.oracle.com/javase/tutorial/uiswing/events/windowlistener.html
import static java.awt.EventQueue.invokeLater;

import java.awt.AWTEvent;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.WindowEvent;
import java.util.concurrent.CountDownLatch;

public class WindowLostFocusReproducer {

    private static int MAX_ITER = 100;
    
    public static void main(String[] args) throws Exception {
        int i = 0;
    	boolean testFailed = doTest();
    	i++;
    	while (!testFailed && i < MAX_ITER) {
    		testFailed = doTest();
    		i++;
    	}
    	if (i == MAX_ITER) {
    	    printAndFlush("Was able to successfully run " + MAX_ITER + " times. System seems unaffected.");
    	} else {
    	    throw new RuntimeException("Test failed");
    	}
    }
    
    static boolean doTest() throws Exception {
    	printAndFlush("--------------------- RUNNING TEST -------------------");
        invokeLater(() -> createWindows());
        sleep();
        invokeLater(() -> frame.setVisible(true));
        sleep();
        invokeLater(() -> focusOwner());
        sleep();
        
        CountDownLatch latch = new CountDownLatch(1);
        WindowFocusLostListener listener = new WindowFocusLostListener(latch, dialog1);
        Toolkit.getDefaultToolkit().addAWTEventListener(listener, WindowEvent.WINDOW_FOCUS_EVENT_MASK | WindowEvent.WINDOW_EVENT_MASK);
        
        invokeLater(() -> dialog1.setVisible(true));
        sleep();
        invokeLater(() -> focusDialog1());
        sleep();
        
        invokeLater(() -> {
            printAndFlush("---> calling dialog1 dispose");
            dialog1.dispose(); 
        });
        try {
            latch.await();
        } catch (InterruptedException e) {
            // ignored
        }
        Toolkit.getDefaultToolkit().removeAWTEventListener(listener);
        invokeLater(() -> frame.dispose());
        if (listener.gotWindowLostFocus) {
            printAndFlush("Test passed");
            return false;
        } else {
            printAndFlush("Test failed");
            return true;
        }
    }
    
    private static class WindowFocusLostListener implements AWTEventListener {

        private final CountDownLatch latch;
        private final Dialog dialog;
        private boolean gotWindowLostFocus = false;
        
        private WindowFocusLostListener(CountDownLatch latch, Dialog dialog) {
            this.latch = latch;
            this.dialog = dialog;
        }
        
        @Override
        public void eventDispatched(AWTEvent event) {
            if (event.getSource() == dialog) {
                if (event.getID() == WindowEvent.WINDOW_GAINED_FOCUS) {
                    printAndFlush("got WINDOW_GAINED_FOCUS event on dialog");
                }
                if (event.getID() == WindowEvent.WINDOW_LOST_FOCUS) {
                    gotWindowLostFocus = true;
                    printAndFlush("correctly got WINDOW_LOST_FOCUS event on dialog");
                }
                if (event.getID() == WindowEvent.WINDOW_CLOSED) {
                    printAndFlush("dialog closed");
                    latch.countDown();
                }
            }
        }
        
    }

	static void sleep() throws Exception {
        Thread.sleep(250);
    }

    private static Frame frame;
    private static Dialog dialog1;

    static void createWindows() {
        frame = new Frame();
        frame.setSize(100, 100);
        frame.setLocation(100, 100);
        dialog1 = new Dialog(frame);
        dialog1.setSize(100, 100);
    }
    
    private static void printAndFlush(String string) {
        System.out.println(string);
        System.out.flush();
	}
    
	static void focusOwner() {
		frame.requestFocus();
    }

    static void focusDialog1() {
    	dialog1.requestFocus();
    }
}

Reply via email to