Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java stops capturing mouse movement events after maximizing or full screening a window in Mac OS X

Tags:

java

macos

swing

When I enlarge a window by either pressing the maximize button or the full screen button on OS X, mouse movement events are no longer captured (though dragging is).

I have included a demo program below that highlights the issue. The maximization problem can be replicated using the MouseEventDemo web start example on the Java Tutorials website.

After some troubleshooting, I noted that mouse movements are recaptured if the mouse leaves the window (e.g., moves to the top of the window to access the menu bar) and then returns. It seems the issue may have something to do with the relation between the mouse position and the window during resizing animations, since the mouse is not in the frame before the resizing, but is afterward even though it didn’t necessarily move in the process.

import java.awt.Window;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.lang.reflect.Method;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class Main implements MouseMotionListener {

    JLabel label = new JLabel("label");

    public static void main(String[] args) {
        Main main = new Main();
        main.init();
    }

    public void init() {
        JFrame frame = new JFrame();
        frame.setSize(640, 480);
        frame.setLocationRelativeTo(null);
        frame.getContentPane().add(label);
        frame.addMouseMotionListener(this);
        frame.setVisible(true);

        if (isMacOSX()) {
            enableFullScreenMode(frame);
        }
    }

    public void mouseDragged(MouseEvent e) {
        label.setText(e.toString());
    }

    public void mouseMoved(MouseEvent e) {
        label.setText(e.toString());
    }

    private static boolean isMacOSX() {
        return System.getProperty("os.name").indexOf("Mac OS X") >= 0;
    }

    public static void enableFullScreenMode(Window window) {
        try {
            Class<?> clazz = Class.forName("com.apple.eawt.FullScreenUtilities");
            Method method = clazz.getMethod("setWindowCanFullScreen", new Class<?>[] { Window.class, boolean.class });
            method.invoke(null, window, true);
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

Running the code above should reveal when the label does and does not update.

I am running OS X Version 10.9 Build 13A3017 with Java SE 7 [1.7.0_45].

like image 543
e4e5 Avatar asked Nov 18 '13 16:11

e4e5


2 Answers

Empirically, the problem disappears if one switches away from and back to the application while maximized. Adding a ComponentListener that forces the frame toFront() seems to work. As an aside, Swing GUI objects should be constructed and manipulated only on the event dispatch thread.

frame.addComponentListener(new ComponentAdapter() {

    @Override
    public void componentResized(ComponentEvent e) {
        frame.toFront();
    }
});

As tested:

import java.awt.EventQueue;
import java.awt.Window;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.lang.reflect.Method;
import javax.swing.JFrame;
import javax.swing.JLabel;

/** @see http://stackoverflow.com/a/20054242/230513 */
public class Main implements MouseMotionListener {

    JLabel label = new JLabel("label");

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                Main main = new Main();
                main.init();
            }
        });
    }

    public void init() {
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(label);
        frame.pack();
        frame.setSize(640, 480);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        if (isMacOSX()) {
            enableFullScreenMode(frame);
        }
        frame.addMouseMotionListener(this);
        frame.addComponentListener(new ComponentAdapter() {

            @Override
            public void componentResized(ComponentEvent e) {
                frame.toFront();
            }
        });
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        label.setText(e.toString());
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        label.setText(e.toString());
    }

    private static boolean isMacOSX() {
        return System.getProperty("os.name").indexOf("Mac OS X") >= 0;
    }

    public static void enableFullScreenMode(Window window) {
        try {
            Class<?> clazz = Class.forName("com.apple.eawt.FullScreenUtilities");
            Method method = clazz.getMethod("setWindowCanFullScreen",
                    new Class<?>[]{Window.class, boolean.class});
            method.invoke(null, window, true);
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
}
like image 73
trashgod Avatar answered Oct 26 '22 01:10

trashgod


Oracle responded to the bug report I submitted, noting in their comments that the issue should be resolved in Java 8. The code above works as expected on the 1.8.0 JRE (build 1.8.0-b132) using OS X 10.9.2.

like image 38
e4e5 Avatar answered Oct 26 '22 02:10

e4e5