diff options
Diffstat (limited to 'launcher/org/simplericity/macify')
5 files changed, 694 insertions, 0 deletions
diff --git a/launcher/org/simplericity/macify/eawt/Application.java b/launcher/org/simplericity/macify/eawt/Application.java new file mode 100644 index 00000000..153bb9ee --- /dev/null +++ b/launcher/org/simplericity/macify/eawt/Application.java @@ -0,0 +1,176 @@ +package org.simplericity.macify.eawt; + +/* + * Copyright 2007 Eirik Bjorsnos. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.awt.*; +import java.awt.image.BufferedImage; + +/** + * The Macify Library API interface provides integration with the OS X platform for Java Applications. + * The API includes a facade to the + * <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/index.html"> + * Apple Java Extensions API + * </a>. + * Additionally, it provides access to several useful methods in the Cocoa NSApplication API. + * + * The default implementation of this interface is {@link org.simplericity.macify.eawt.DefaultApplication}. + */ +public interface Application { + + static int REQUEST_USER_ATTENTION_TYPE_CRITICAL = 1 ; + static int REQUEST_USER_ATTENTION_TYPE_INFORMATIONAL = 2 ; + + /** + * See + * <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#addAboutMenuItem()"> + * Apple's API + * </a>. + */ + void addAboutMenuItem(); + + /** + * See + * <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#addApplicationListener(com.apple.eawt.ApplicationListener)"> + * Apple's API + * </a>. + */ + void addApplicationListener(ApplicationListener applicationListener); + + /** + * See + * <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#addPreferencesMenuItem()"> + * Apple's API + * </a>. + */ + void addPreferencesMenuItem(); + + /** + * See + * <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#getEnabledAboutMenu()"> + * Apple's API + * </a>. + */ + boolean getEnabledAboutMenu(); + + /** + * See + * <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#getEnabledPreferencesMenu()"> + * Apple's API + * </a>. + */ + boolean getEnabledPreferencesMenu(); + + /** + * See + * <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#isAboutMenuItemPresent()"> + * Apple's API + * </a>. + */ + boolean isAboutMenuItemPresent(); + + /** + * See + * <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#isPreferencesMenuItemPresent()"> + * Apple's API + * </a>. + */ + boolean isPreferencesMenuItemPresent(); + + /** + * See + * <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#removeAboutMenuItem()"> + * Apple's API + * </a>. + */ + void removeAboutMenuItem(); + + /** + * See + * <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#removeApplicationListener(com.apple.eawt.ApplicationListener)"> + * Apple's API + * </a>. + */ + void removeApplicationListener(ApplicationListener applicationListener); + + /** + * See + * <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#removePreferencesMenuItem()"> + * Apple's API + * </a>. + */ + void removePreferencesMenuItem(); + + /** + * See + * <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#getEnabledAboutMenu()"> + * Apple's API + * </a>. + */ + void setEnabledAboutMenu(boolean enabled); + + /** + * See + * <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#getEnabledPreferencesMenu()"> + * Apple's API + * </a>. + */ + void setEnabledPreferencesMenu(boolean enabled); + + /** + * See + * <a href="http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/api/com/apple/eawt/Application.html#getMouseLocationOnScreen()"> + * Apple's API + * </a>. + */ + Point getMouseLocationOnScreen(); + + /** + * See + * <a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSApplication_Class/index.html#//apple_ref/doc/uid/TP40004004"> + * Apple's NSApplication Class Reference + * </a>. + * @param type on of {@link #REQUEST_USER_ATTENTION_TYPE_CRITICAL} or {@link #REQUEST_USER_ATTENTION_TYPE_INFORMATIONAL}. + */ + int requestUserAttention(int type); + + /** + * See + * <a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSApplication_Class/index.html#//apple_ref/doc/uid/TP40004004"> + * Apple's NSApplication Class Reference + * </a> + */ + void cancelUserAttentionRequest(int request); + + /** + * Update the application's icon image + * @param image + */ + void setApplicationIconImage(BufferedImage image); + + /** + * Get the application's icon image. + */ + BufferedImage getApplicationIconImage(); + + /** + * Determines whether the application is running on a Mac AND the Apple Extensions API classes are available. + * @return + */ + boolean isMac(); + + +} diff --git a/launcher/org/simplericity/macify/eawt/ApplicationAdapter.java b/launcher/org/simplericity/macify/eawt/ApplicationAdapter.java new file mode 100644 index 00000000..e9c3db7d --- /dev/null +++ b/launcher/org/simplericity/macify/eawt/ApplicationAdapter.java @@ -0,0 +1,48 @@ +package org.simplericity.macify.eawt; + +/* + * Copyright 2007 Eirik Bjorsnos. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class ApplicationAdapter implements ApplicationListener { + + public void handleQuit(ApplicationEvent event) { + + } + + public void handleAbout(ApplicationEvent event) { + + } + + public void handleOpenApplication(ApplicationEvent event) { + + } + + public void handleOpenFile(ApplicationEvent event) { + + } + + public void handlePreferences(ApplicationEvent event) { + + } + + public void handlePrintFile(ApplicationEvent event) { + + } + + public void handleReOpenApplication(ApplicationEvent event) { + + } +} diff --git a/launcher/org/simplericity/macify/eawt/ApplicationEvent.java b/launcher/org/simplericity/macify/eawt/ApplicationEvent.java new file mode 100644 index 00000000..78420355 --- /dev/null +++ b/launcher/org/simplericity/macify/eawt/ApplicationEvent.java @@ -0,0 +1,25 @@ +package org.simplericity.macify.eawt; + +/* + * Copyright 2007 Eirik Bjorsnos. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public interface ApplicationEvent { + String getFilename(); + boolean isHandled(); + void setHandled(boolean handled); + Object getSource(); + String toString(); +} diff --git a/launcher/org/simplericity/macify/eawt/ApplicationListener.java b/launcher/org/simplericity/macify/eawt/ApplicationListener.java new file mode 100644 index 00000000..a291bee4 --- /dev/null +++ b/launcher/org/simplericity/macify/eawt/ApplicationListener.java @@ -0,0 +1,27 @@ +package org.simplericity.macify.eawt; + +/* + * Copyright 2007 Eirik Bjorsnos. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public interface ApplicationListener { + void handleAbout(ApplicationEvent event); + void handleOpenApplication(ApplicationEvent event); + void handleOpenFile(ApplicationEvent event); + void handlePreferences(ApplicationEvent event); + void handlePrintFile(ApplicationEvent event); + void handleQuit(ApplicationEvent event); + void handleReOpenApplication(ApplicationEvent event); +} diff --git a/launcher/org/simplericity/macify/eawt/DefaultApplication.java b/launcher/org/simplericity/macify/eawt/DefaultApplication.java new file mode 100644 index 00000000..5752a350 --- /dev/null +++ b/launcher/org/simplericity/macify/eawt/DefaultApplication.java @@ -0,0 +1,418 @@ +package org.simplericity.macify.eawt; + +/* + * Copyright 2007 Eirik Bjorsnos. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.*; +import java.lang.reflect.*; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.MalformedURLException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + + +/** + * Implements Application by calling the Mac OS X API through reflection. + * If this class is used on a non-OS X platform the operations will have no effect or they will simulate + * what the Apple API would do for those who manipulate state. ({@link #setEnabledAboutMenu(boolean)} etc.) + */ +@SuppressWarnings("unchecked") +public class DefaultApplication implements Application { + + private Object application; + private Class applicationListenerClass; + + Map listenerMap = Collections.synchronizedMap(new HashMap<Object, Object>()); + private boolean enabledAboutMenu = true; + private boolean enabledPreferencesMenu; + private boolean aboutMenuItemPresent = true; + private boolean preferencesMenuItemPresent; + private ClassLoader classLoader; + + public DefaultApplication() { + try { + final File file = new File("/System/Library/Java"); + if (file.exists()) { + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Class clc = scl.getClass(); + if (URLClassLoader.class.isAssignableFrom(clc)) { + Method addUrl = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class}); + addUrl.setAccessible(true); + addUrl.invoke(scl, new Object[]{file.toURI().toURL()}); + } + } + + Class appClass = Class.forName("com.apple.eawt.Application"); + application = appClass.getMethod("getApplication", new Class[0]).invoke(null, new Object[0]); + applicationListenerClass = Class.forName("com.apple.eawt.ApplicationListener"); + } catch (ClassNotFoundException e) { + application = null; + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + + } + + public boolean isMac() { + return application != null; + } + + public void addAboutMenuItem() { + if (isMac()) { + callMethod(application, "addAboutMenuItem"); + } else { + this.aboutMenuItemPresent = true; + } + } + + public void addApplicationListener(ApplicationListener applicationListener) { + + if (!Modifier.isPublic(applicationListener.getClass().getModifiers())) { + throw new IllegalArgumentException("ApplicationListener must be a public class"); + } + if (isMac()) { + Object listener = Proxy.newProxyInstance(getClass().getClassLoader(), + new Class[]{applicationListenerClass}, + new ApplicationListenerInvocationHandler(applicationListener)); + + callMethod(application, "addApplicationListener", new Class[]{applicationListenerClass}, new Object[]{listener}); + listenerMap.put(applicationListener, listener); + } else { + listenerMap.put(applicationListener, applicationListener); + } + } + + public void addPreferencesMenuItem() { + if (isMac()) { + callMethod("addPreferencesMenuItem"); + } else { + this.preferencesMenuItemPresent = true; + } + } + + public boolean getEnabledAboutMenu() { + if (isMac()) { + return callMethod("getEnabledAboutMenu").equals(Boolean.TRUE); + } else { + return enabledAboutMenu; + } + } + + public boolean getEnabledPreferencesMenu() { + if (isMac()) { + Object result = callMethod("getEnabledPreferencesMenu"); + return result.equals(Boolean.TRUE); + } else { + return enabledPreferencesMenu; + } + } + + public Point getMouseLocationOnScreen() { + if (isMac()) { + try { + Method method = application.getClass().getMethod("getMouseLocationOnScreen", new Class[0]); + return (Point) method.invoke(null, new Object[0]); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } else { + return new Point(0, 0); + } + } + + public boolean isAboutMenuItemPresent() { + if (isMac()) { + return callMethod("isAboutMenuItemPresent").equals(Boolean.TRUE); + } else { + return aboutMenuItemPresent; + } + } + + public boolean isPreferencesMenuItemPresent() { + if (isMac()) { + return callMethod("isPreferencesMenuItemPresent").equals(Boolean.TRUE); + } else { + return this.preferencesMenuItemPresent; + } + } + + public void removeAboutMenuItem() { + if (isMac()) { + callMethod("removeAboutMenuItem"); + } else { + this.aboutMenuItemPresent = false; + } + } + + public synchronized void removeApplicationListener(ApplicationListener applicationListener) { + if (isMac()) { + Object listener = listenerMap.get(applicationListener); + callMethod(application, "removeApplicationListener", new Class[]{applicationListenerClass}, new Object[]{listener}); + + } + listenerMap.remove(applicationListener); + } + + public void removePreferencesMenuItem() { + if (isMac()) { + callMethod("removeAboutMenuItem"); + } else { + this.preferencesMenuItemPresent = false; + } + } + + public void setEnabledAboutMenu(boolean enabled) { + if (isMac()) { + callMethod(application, "setEnabledAboutMenu", new Class[]{Boolean.TYPE}, new Object[]{Boolean.valueOf(enabled)}); + } else { + this.enabledAboutMenu = enabled; + } + } + + public void setEnabledPreferencesMenu(boolean enabled) { + if (isMac()) { + callMethod(application, "setEnabledPreferencesMenu", new Class[]{Boolean.TYPE}, new Object[]{Boolean.valueOf(enabled)}); + } else { + this.enabledPreferencesMenu = enabled; + } + + } + + public int requestUserAttention(int type) { + if (type != REQUEST_USER_ATTENTION_TYPE_CRITICAL && type != REQUEST_USER_ATTENTION_TYPE_INFORMATIONAL) { + throw new IllegalArgumentException("Requested user attention type is not allowed: " + type); + } + try { + Object application = getNSApplication(); + Field critical = application.getClass().getField("UserAttentionRequestCritical"); + Field informational = application.getClass().getField("UserAttentionRequestInformational"); + Field actual = type == REQUEST_USER_ATTENTION_TYPE_CRITICAL ? critical : informational; + + return ((Integer) application.getClass().getMethod("requestUserAttention", new Class[]{Integer.TYPE}).invoke(application, new Object[]{actual.get(null)})).intValue(); + + } catch (ClassNotFoundException e) { + return -1; + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + } + + public void cancelUserAttentionRequest(int request) { + try { + Object application = getNSApplication(); + application.getClass().getMethod("cancelUserAttentionRequest", new Class[]{Integer.TYPE}).invoke(application, new Object[]{new Integer(request)}); + } catch (ClassNotFoundException e) { + // Nada + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + private Object getNSApplication() throws ClassNotFoundException { + try { + Class applicationClass = Class.forName("com.apple.cocoa.application.NSApplication"); + return applicationClass.getMethod("sharedApplication", new Class[0]).invoke(null, new Object[0]); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + public void setApplicationIconImage(BufferedImage image) { + if (isMac()) { + try { + Method setDockIconImage = application.getClass().getMethod("setDockIconImage", Image.class); + + try { + setDockIconImage.invoke(application, image); + } catch (IllegalAccessException e) { + + } catch (InvocationTargetException e) { + + } + } catch (NoSuchMethodException mnfe) { + + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + try { + ImageIO.write(image, "png", stream); + } catch (IOException e) { + throw new RuntimeException(e); + } + + try { + Class nsDataClass = Class.forName("com.apple.cocoa.foundation.NSData"); + Constructor constructor = nsDataClass.getConstructor(new Class[]{new byte[0].getClass()}); + + Object nsData = constructor.newInstance(new Object[]{stream.toByteArray()}); + + Class nsImageClass = Class.forName("com.apple.cocoa.application.NSImage"); + Object nsImage = nsImageClass.getConstructor(new Class[]{nsDataClass}).newInstance(new Object[]{nsData}); + + Object application = getNSApplication(); + + application.getClass().getMethod("setApplicationIconImage", new Class[]{nsImageClass}).invoke(application, new Object[]{nsImage}); + + } catch (ClassNotFoundException e) { + + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } + + } + + } + } + + public BufferedImage getApplicationIconImage() { + if (isMac()) { + + try { + Method getDockIconImage = application.getClass().getMethod("getDockIconImage"); + try { + return (BufferedImage) getDockIconImage.invoke(application); + } catch (IllegalAccessException e) { + + } catch (InvocationTargetException e) { + + } + } catch (NoSuchMethodException nsme) { + + try { + Class nsDataClass = Class.forName("com.apple.cocoa.foundation.NSData"); + Class nsImageClass = Class.forName("com.apple.cocoa.application.NSImage"); + Object application = getNSApplication(); + Object nsImage = application.getClass().getMethod("applicationIconImage", new Class[0]).invoke(application, new Object[0]); + + Object nsData = nsImageClass.getMethod("TIFFRepresentation", new Class[0]).invoke(nsImage, new Object[0]); + + Integer length = (Integer) nsDataClass.getMethod("length", new Class[0]).invoke(nsData, new Object[0]); + byte[] bytes = (byte[]) nsDataClass.getMethod("bytes", new Class[]{Integer.TYPE, Integer.TYPE}).invoke(nsData, new Object[]{Integer.valueOf(0), length}); + + BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes)); + return image; + + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + } + + return null; + } + + private Object callMethod(String methodname) { + return callMethod(application, methodname, new Class[0], new Object[0]); + } + + private Object callMethod(Object object, String methodname) { + return callMethod(object, methodname, new Class[0], new Object[0]); + } + + private Object callMethod(Object object, String methodname, Class[] classes, Object[] arguments) { + try { + if (classes == null) { + classes = new Class[arguments.length]; + for (int i = 0; i < classes.length; i++) { + classes[i] = arguments[i].getClass(); + + } + } + Method addListnerMethod = object.getClass().getMethod(methodname, classes); + return addListnerMethod.invoke(object, arguments); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + class ApplicationListenerInvocationHandler implements InvocationHandler { + private ApplicationListener applicationListener; + + ApplicationListenerInvocationHandler(ApplicationListener applicationListener) { + this.applicationListener = applicationListener; + } + + public Object invoke(Object object, Method appleMethod, Object[] objects) throws Throwable { + + ApplicationEvent event = createApplicationEvent(objects[0]); + try { + Method method = applicationListener.getClass().getMethod(appleMethod.getName(), new Class[]{ApplicationEvent.class}); + return method.invoke(applicationListener, new Object[]{event}); + } catch (NoSuchMethodException e) { + if (appleMethod.getName().equals("equals") && objects.length == 1) { + return Boolean.valueOf(object == objects[0]); + } + return null; + } + } + } + + private ApplicationEvent createApplicationEvent(final Object appleApplicationEvent) { + return (ApplicationEvent) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{ApplicationEvent.class}, new InvocationHandler() { + public Object invoke(Object o, Method method, Object[] objects) throws Throwable { + return appleApplicationEvent.getClass().getMethod(method.getName(), method.getParameterTypes()).invoke(appleApplicationEvent, objects); + } + }); + } +} |