/* * Copyright 2010-2015 Institut Pasteur. * * This file is part of Icy. * * Icy is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Icy is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Icy. If not, see <http://www.gnu.org/licenses/>. */ package icy.system; import icy.gui.dialog.LoaderDialog; import icy.gui.frame.AboutFrame; import icy.gui.preferences.GeneralPreferencePanel; import icy.gui.preferences.PreferenceFrame; import icy.main.Icy; import icy.resource.ResourceUtil; import icy.system.thread.ThreadUtil; import java.awt.Toolkit; import java.beans.PropertyChangeListener; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * OSX application compatibility class * * @author stephane */ public class AppleUtil { static final Thread fixThread = new Thread(new Runnable() { @Override public void run() { appleFixLiveRun(); } }, "AppleFix"); @SuppressWarnings({"unchecked", "rawtypes"}) public static void init() { // only when we have the GUI if (!Icy.getMainInterface().isHeadLess()) { try { final ClassLoader classLoader = SystemUtil.getSystemClassLoader(); final Class appClass = classLoader.loadClass("com.apple.eawt.Application"); final Object app = appClass.newInstance(); final Class listenerClass = classLoader.loadClass("com.apple.eawt.ApplicationListener"); final Object listener = Proxy.newProxyInstance(classLoader, new Class[] {listenerClass}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { final Object applicationEvent = args[0]; final Class appEventClass = applicationEvent.getClass(); final Method m = appEventClass.getMethod("setHandled", boolean.class); if (method.getName().equals("handleQuit")) { m.invoke(applicationEvent, Boolean.valueOf(Icy.exit(false))); } if (method.getName().equals("handleAbout")) { new AboutFrame(); m.invoke(applicationEvent, Boolean.valueOf(true)); } if (method.getName().equals("handleOpenFile")) { new LoaderDialog(); m.invoke(applicationEvent, Boolean.valueOf(true)); } if (method.getName().equals("handlePreferences")) { new PreferenceFrame(GeneralPreferencePanel.NODE_NAME); m.invoke(applicationEvent, Boolean.valueOf(true)); } return null; } }); Method m; m = appClass.getMethod("addApplicationListener", listenerClass); m.invoke(app, listener); m = appClass.getMethod("setDockIconImage", java.awt.Image.class); m.invoke(app, ResourceUtil.IMAGE_ICY_256); m = appClass.getMethod("addPreferencesMenuItem"); m.invoke(app); // set menu bar name SystemUtil.setProperty("com.apple.mrj.application.apple.menu.about.name", "Icy"); } catch (Exception e) { System.err.println("Can't install OSX application wrapper..."); } } // start the fix thread fixThread.start(); } /** * Apple fix live run (fixes specific OS X JVM stuff) */ static void appleFixLiveRun() { while (true) { final Toolkit toolkit = Toolkit.getDefaultToolkit(); // fix memory leak introduced in java 1.6.0_29 in Mac OS X JVM // TODO : remove this when issue will be resolved in JVM final PropertyChangeListener[] leak = toolkit.getPropertyChangeListeners("apple.awt.contentScaleFactor"); // remove listener for (int i = 0; i < leak.length; i++) toolkit.removePropertyChangeListener("apple.awt.contentScaleFactor", leak[i]); // no need more... ThreadUtil.sleep(500); } } }