JDK-8160570 : [macosx] modal dialog can skip the activation/focus events
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 8u92,9
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: os_x
  • Submitted: 2016-06-29
  • Updated: 2017-11-29
  • Resolved: 2016-09-08
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u152Fixed 9 b137Fixed
Related Reports
Relates :  
Relates :  
Description
This is timing dependent, but it can happen that a modal dialog doesn't receive  WINDOW_ACTIVATION & WINDOW_GAINED_FOCUS events when first shown. The following test forces "the right timings" & reproduces the bug:

public class Main {
    public static void main(String[] args) throws InterruptedException {
        EventQueue.invokeLater(() -> runGUI());
    }

    static void runGUI() {
        JFrame f = new JFrame("frame");
        JDialog d = new MyModalDialog(f, "dialog");
        d.addWindowListener(new WindowAdapter() {
            @Override
            public void windowActivated(WindowEvent e) {
                System.out.println(e);
            }
        });
        d.addWindowFocusListener(new WindowAdapter() {
            @Override
            public void windowGainedFocus(WindowEvent e) {
                System.out.println(e);
            }
        });
        f.setVisible(true);
        d.setVisible(true);
    }

    static class MyModalDialog extends JDialog {
        public MyModalDialog(Frame owner, String title) {
            super(owner, title, true);
        }

        @Override
        public boolean getFocusableWindowState() {
            try {
                Thread.sleep(100);
            } catch (InterruptedException ignore) {
            }
            return super.getFocusableWindowState();
        }
    }
}

Comments
Victor, yes, the fix is on review already.
29-08-2016

Anton, is this bug fix still in your plans to meet ZBB (Oct 20)? http://openjdk.java.net/projects/jdk9/
23-08-2016

Anton, are you still working on this fix? ZBB is approaching next couple of weeks, so a heads up for you do not delay, but proceed now to avoid last minute confusion
16-08-2016

The problem is this. In Dialog.conditionalShow() there's the following logic: if (modal) { ... modalShow(); } ... peer.setVisible(true); Then: modalShow() -> blockWindows() -> peer.blockWindows() -> LWWindowPeer.setModalBlocked() -> CPlatformWindow.setModalBlocked() -> checkBlockingAndOrder() -> CWrapper.NSWindow.orderFrontRegardless(nsWindowPtr); CWrapper.NSWindow.makeKeyAndOrderFront(nsWindowPtr); CWrapper.NSWindow.makeMainWindow(nsWindowPtr); This actually shows the platform window, triggering all the focus stuff, including LWWindowPeer.changeFocusedWindow() where: if (!isFocusableWindow() && becomesFocused) { focusLog.fine("the window is not focusable"); return; } returns due to !isFocusableWindow(), implemented as: private boolean isFocusableWindow() { boolean focusable = targetFocusable; ... return focusable; } where: public void updateFocusableWindowState() { targetFocusable = getTarget().isFocusableWindow(); ... } the latter method is called only from the peer.setVisible() chain, which has not yet been executed. So 'targetFocusable' remains false (its initialised value). The fact that a modal dialog is shown before peer.setVisible is actually little bit unexpected. Not sure if it can break something apart from focus. As to the focus issue, a simple fix is to init the cache for the "focusability" state in the peer ctor.
29-06-2016