When I instantiate an object from java.awt, the program causes a new macOS application named "Java", with no windows, to open.
How can I prevent this from happening?
Here is a minimal example:
import java.awt.Rectangle;
public class Main {
public static void main(String[] args) {
Rectangle rect = new Rectangle();
}
}
After compiling and running it in the most canonical way (javac Main.java; java Main), the following icon appears in the Dock: screenshot
I've traced the code, and the offending method is Toolkit.loadLibraries() (JDK 1.8.0_172-b11).
I found the solution based on #MadProgrammer's comment.
The answer is to set AWT to headless mode.
When executing the program:
$ java -Djava.awt.headless=true Main
Or programatically:
System.setProperty("java.awt.headless", "true");
What is the simplest way to customize this panel considered that the application is written in Java 7 and my favorite environment is Mac Os?
Thanks
You need to use the com.apple.eawt classes. For example, this scratch program shows a Java dialog instead of the Mac one.
import javax.swing.*;
import com.apple.eawt.*;
import com.apple.eawt.AppEvent.*;
public class Foo
extends JPanel
implements AboutHandler
{
public static void main(String[] args)
throws Exception
{
Foo r = new Foo();
}
public Foo() {
Application.getApplication().setAboutHandler(this);
}
public void handleAbout(final AboutEvent e) {
JOptionPane.showMessageDialog(null, "hello, world");
}
}
Unfortunately all of this stuff is deprecated. Apple used to develop and support all of this but doesn’t anymore, and there are a lot of dead links around the internet.
I figured out the API from reading the Javadoc comments in the source code for these classes.
And running mdfind -name apple | grep -i jar turned up /usr/share/java/Stubs/AppleJavaExtensions.jar on my machine, which allowed the above program to compile and run on my machine. But I have no idea where that file came from or if it’ll be in future versions of Mac OS.
I tried to set the application name and icon for the Mac OS X dock in my Java program.
I used the following code:
public static void main(String[] args)
{
Application.getApplication().setDockIconImage(icon); // Dock icon
System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Alfabet"); // Program name
new UpdateChecker(); // Check for an update
new Alfabet(); // Start the program
}
The object 'icon' is an java.awt.Image.
The class Alfabet creates the main JFrame of the program. The icon shows up correctly, but the application name doesn't, it still displays the name of the main class of the program. What am I doing wrong? Thank you.
It's not clear where things are going awry, but there's a complete working example here for reference.
Alternatively , try setting the name from the command line:
java -Xdock:name=Alfabet
See also Initial Threads.
I hitherto used the following code to set the Application Name (in the top "System" menu bar) on my Apple MacBook. (Actually, I think I copied this from stackoverflow.)
Basically, have a seperate AppLauncher class that uses System.setProperty() to set the application name before creating a new Runnable for the app itself.
Worked just fine.
However, since I downloaded and started using JDK 1.7, the solution stopped working - I'm getting the Class Name instead of the App Name in the menu, just like before I found that solution. I tried googling it, but to no avail.
Here is the defunct code that used to work under JDK 1.6, reduced to the relevant parts:
public class AppLauncher {
public static void main(String[] args) {
System.setProperty("apple.laf.useScreenMenuBar", "true");
System.setProperty("com.apple.mrj.application.apple.menu.about.name",
"My Application");
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MainWindow();
}
});
}
}
Thanks for suggestions!
ETA: invoking with java -Dapple.laf.useScreenMenuBar=true still works. Pu8tting the property into Info.plist might work, but I haven't tried it yet.
It appears that setting the property using -D solves the problem.
java -Dapple.laf.useScreenMenuBar=true …
Other approaches are mentioned in this related answer.
I couldn't get the Info.plist or -D approaches to work (I'm working on distributing a JRuby App, that might have something to do with it), but for me passing the -Xdock:name parameter as mentioned in this article under the section "More tinkering with the menu bar" seemed to work great.
Example: -Xdock:name="My Application"
After being convinced ("schooled") that Swing apps on Mac do look native, I'm trying to make mine look as native as possible. Everything looks great, but when I hit command+Q or do it from the menu, my windowStateChanged(WindowEvent e) is not firing on my main JFrame (if I exit in any other way, it does fire). How can I respond to the real Apple quit?
You can implement com.apple.eawt.ApplicationListener and respond to the Quit event. An example may be found in the Mac OS X Reference Library example, OSXAdapter.
Addendum: See Java for Mac OS X 10.6 Update 3 and 10.5 Update 8 Release Notes for information on deprecation, the redesigned com.apple.eawt.Application class, and the location of API documentation for the Apple Java extensions. Control-click or right-click on the .jdk file to Show Package Contents. You can browse the classes of com.apple.eawt among the OpenJDK sources.
As shown in this complete example, you can specify the desired
QuitStrategy; a WindowListener will respond to ⌘Q:
Application.getApplication().setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
As noted here, you can set the property from the command line
java -Dapple.eawt.quitStrategy=CLOSE_ALL_WINDOWS -cp build/classes gui.QuitStrategyTest
or early in the program, before posting any GUI events:
System.setProperty("apple.eawt.quitStrategy", "CLOSE_ALL_WINDOWS");
EventQueue.invokeLater(new QuitStrategyTest()::display);
Console, after ⌘Q:
java.vendor: Oracle Corporation
java.version: 1.8.0_60
os.name: Mac OS X
os.version: 10.11
apple.eawt.quitStrategy: CLOSE_ALL_WINDOWS
java.awt.event.WindowEvent[WINDOW_CLOSING,opposite=null,oldState=0,newState=0] on frame0
Code:
package gui;
import java.awt.EventQueue;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JTextArea;
/**
* #see https://stackoverflow.com/a/7457102/230513
*/
public class QuitStrategyTest {
private void display() {
JFrame f = new JFrame("QuitStrategyTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.out.println(e);
}
});
f.add(new JTextArea(getInfo()));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private String getInfo() {
String[] props = {
"java.vendor",
"java.version",
"os.name",
"os.version",
"apple.eawt.quitStrategy"
};
StringBuilder sb = new StringBuilder();
for (String prop : props) {
sb.append(prop);
sb.append(": ");
sb.append(System.getProperty(prop));
sb.append(System.getProperty("line.separator"));
}
System.out.print(sb);
return sb.toString();
}
public static void main(String[] args) {
System.setProperty("apple.eawt.quitStrategy", "CLOSE_ALL_WINDOWS");
EventQueue.invokeLater(new QuitStrategyTest()::display);
}
}
The top voted answer is excellent but just to fill in the "best way":
System.setProperty("apple.eawt.quitStrategy", "CLOSE_ALL_WINDOWS");
This will trigger the standard window closing callback event which should work really nicely for portable code.
As a result of the discussion below it seems that its crucial to do this really early in the app. I wrote this early in the static initializer of the main class before any UI code was executed.
This is a pretty good question, and I must admit I don't have the answer. However, a couple years ago when I was working on a Java app and faced this problem, I solved it by registering a shutdown hook with the runtime that would do what I wanted the app to do before quitting. It's a heavy-handed solution but it worked. You can take a look at my code and see if it helps.
I was originally seeing a 'access restriction' violation when trying to access the com.apple.eawt.Application and com.apple.eawt.* subclasses.
(Note: I'm programming on a MAC, using Eclipse, with Java 1.6 using Swing)
So I needed to modify my java build path to allow access to the apple subclasses by adding "com/apple/eawt/**" access rule. After that this code below was able to compile and work for me:
//NOTE: This code only works for MAC OS. If you run this on Windows
//the application never starts (so you literally need to remove this block of code)
import com.apple.eawt.*;
import com.apple.eawt.QuitHandler;
Application a = Application.getApplication();
a.setQuitHandler(new QuitHandler() {
#Override
public void handleQuitRequestWith(com.apple.eawt.AppEvent.QuitEvent qe, com.apple.eawt.QuitResponse qr) {
// TODO Auto-generated method stub
int res = JOptionPane.showConfirmDialog(frame, "Are you sure you want to exit the program?", "Quit ?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if (res == JOptionPane.YES_OPTION)
qr.performQuit();
else
qr.cancelQuit();
}
});
Have you tried setting up command-Q as an accelerator in your menu? Can you make your app respond to it?
I'm not positive, but I think this works in Linux and probably Windows with the equivalent Alt-F4. My app responds to the "killing" keystroke, I process some cleanup code and then I do a programmatic System.exit().
If you're "just" after graceful exit handling, you may also want to catch the WindowEvent WINDOW_CLOSING, where traditionally "are you sure?" stuff gets done.
Looking at the link to Java for Mac OS X 10.6 Update 3 and 10.5 Update 8 Release Notes I noticed that there is a section on Default Quit Action. This describes a system property to request that all windows are closed in response to the "Quit" menu item, which sounds like exactly what is needed? I have used this in my own application (using Info.plist to set the property on OS X only), and it seems to work as described. This would presumably only work on recent Java/OS X versions, but for those platforms seems like a neat solution, and doesn't require any code changes.