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();
}
}