3

I have a java swing application which has a processWindowEvent method. below is the snippet

@Override
  protected void processWindowEvent(WindowEvent e) {
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
        //exit application with proper error message
    }
  }

Now when my swing application is launched in windows.

  1. close with the cross in swing UI. ==> proper error message is shown
  2. close the application from taskbar ==>proper error message is shown

but now if the same step is done in mac.

  1. close with the cross in swing UI. ==> proper error message is shown
  2. close the application from taskbar ==>does not come inside above method. So no proper message.

I wanted to know what is the default method which will be called in mac when java swing app is closed from taskbar(the dock)

Naik Ashwini
  • 750
  • 12
  • 32

2 Answers2

3

A world without com.apple.eawt.*

You need to look towards java.awt.Desktop instead.

For example...

Desktop.getDesktop().setQuitHandler(new QuitHandler() {
    @Override
    public void handleQuitRequestWith(QuitEvent e, QuitResponse response) {
        // Do some stuff
        //response.cancelQuit();
        //response.performQuit();
    }
});
Desktop.getDesktop().setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);

Original Answer

Welcome to the wonderful world of "Apple does everything differently"

Basically what's happening is, when you "Quit" the program, Apple is calling System.exit(0), basically the same thing that would occur if your used CMD+Q

Now, Apple provides an API which provides functionality which you can use to "configure" your App with MacOS and perform some functionality which is unique to Apple, the problem is, it's a complete pain in the ... code to find useful information about and use.

What you're looking for is com.apple.eawt.ApplictionsetQuitStrategy. This defaults to calling System.exit(0), but you can change it to "close all windows" instead.

In this case, it would allow you to trap the WindowEvent and do what ever it is you want to do

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.addWindowListener(new WindowAdapter() {
                    @Override
                    public void windowClosing(WindowEvent e) {
                        System.out.println("Closing");
                        System.exit(0);
                    }
                });
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                try {
                    Class quitStrategies = Class.forName("com.apple.eawt.QuitStrategy");
                    Object quitStrategy = null;
                    for (Object o : quitStrategies.getEnumConstants()) {
                        if ("CLOSE_ALL_WINDOWS".equals(o.toString())) {
                            quitStrategy = o;
                        }
                    }
                    if (quitStrategy != null) {
                        Class appClass = Class.forName("com.apple.eawt.Application");
                        Class params[] = new Class[]{};

                        Method getApplication = appClass.getMethod("getApplication", params);
                        Object application = getApplication.invoke(appClass);
                        Method setQuitStrategy = application.getClass().getMethod("setQuitStrategy", quitStrategies);
                        setQuitStrategy.invoke(application, quitStrategy);
                    }

                } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | ClassNotFoundException ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    public class TestPane extends JPanel {
    }
}

My general advice is, build a nice "Mac" utilities class which encapsulates the functionality you want to play with and call that.

Also beware, this functionality may disappear suddenly in future releases.

It should be noted that if you intend to have a "one for all" application, you will need to use reflection, as the required API is not available in the standard API, but if you wanted to make a "Apple" only release, you should have a look at this for more information about how you can compile the code on MacOS, because using...

Application.getApplication().setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);

is hell of a lot easier to write and understand

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • I had a System.exit(0) for success scenario. and for mac as it returns System.exit(0) when closed, it was showing as success. Thanx for the information. I will change success code to something else other then 0 – Naik Ashwini Apr 12 '17 at 04:47
  • As of Java 9, [com.apple.eawt.Application is not exported](https://bugs.openjdk.java.net/browse/JDK-8160437). Is there some new way to solve this when the user clicks `Apple Menu -> Application -> Quit `. Catching Cmd-Q is no problem but I now see no way to capture the default quit operation. – Jeff Holt May 11 '20 at 21:42
  • @JeffHolt https://stackoverflow.com/questions/38381824/how-can-i-use-apple-com-apple-eawt-functionality-on-java-8 - but, I've not used it – MadProgrammer May 12 '20 at 01:41
  • Rats. java.awt.desktop with quit handling is new in 1.9+ and most people I think are still hanging onto 1.8. What a mess. – Jeff Holt May 12 '20 at 02:09
  • @JeffHolt Yep :/ – MadProgrammer May 12 '20 at 04:22
1

To catch window close event you need to add WindowListener and override method windowClosing. Use this code:

    JFrame frame = new JFrame(...);
    frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

    frame.addWindowListener( new WindowAdapter()
    {
        public void windowClosing(WindowEvent e)
        {
            JFrame frame = (JFrame)e.getSource();
    ....................
}
}
Jay Smith
  • 2,331
  • 3
  • 16
  • 27
  • If `processWindowEvent` is not been called, the `WindowListener` won't be called – MadProgrammer Apr 11 '17 at 05:23
  • (1+) maybe this won't solve the problem, but yes you should be using a `WindowListener` to handle closing of a window instead of overriding the processWindowEvent(...) method. – camickr Apr 11 '17 at 14:33