From 3dd945fac0da966eb7e7bc576bf5793d6086c25a Mon Sep 17 00:00:00 2001 From: Shawn Silverman Date: Sun, 6 Jan 2019 18:48:24 -0800 Subject: [PATCH 1/2] Making the ThinkDifferent classes be JVM version-independent. JDK 1.9 and later have a new java.awt.desktop package that replaces the custom handlers in the com.apple.eawt package. This commit uses java.lang.reflect.Proxy to generate handlers of the correct type. --- .../app/platform/ThinkDifferent.java | 111 ++++++++++++------ core/src/processing/core/ThinkDifferent.java | 68 ++++++++--- 2 files changed, 129 insertions(+), 50 deletions(-) diff --git a/app/src/processing/app/platform/ThinkDifferent.java b/app/src/processing/app/platform/ThinkDifferent.java index dc905c62a3..01c9823bc3 100644 --- a/app/src/processing/app/platform/ThinkDifferent.java +++ b/app/src/processing/app/platform/ThinkDifferent.java @@ -24,11 +24,15 @@ import java.awt.event.*; import java.io.File; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.List; import javax.swing.*; -import com.apple.eawt.*; -import com.apple.eawt.AppEvent.*; +import com.apple.eawt.Application; import processing.app.*; import processing.app.ui.About; @@ -65,44 +69,40 @@ static protected void init(final Base base) { if (adapter == null) { adapter = new ThinkDifferent(); //base); } - - application.setAboutHandler(new AboutHandler() { - public void handleAbout(AboutEvent ae) { - new About(null); - } + + setHandler(application, "setAboutHandler", (proxy, method, args) -> { + new About(null); + return null; }); - - application.setPreferencesHandler(new PreferencesHandler() { - public void handlePreferences(PreferencesEvent arg0) { - base.handlePrefs(); - } + + setHandler(application, "setPreferencesHandler", (proxy, method, args) -> { + base.handlePrefs(); + return null; }); - application.setOpenFileHandler(new OpenFilesHandler() { - public void openFiles(OpenFilesEvent event) { - for (File file : event.getFiles()) { - base.handleOpen(file.getAbsolutePath()); - } + setHandler(application, "setOpenFileHandler", (proxy, method, args) -> { + Method m = args[0].getClass().getMethod("getFiles"); + for (File file : (List) m.invoke(args[0])) { + base.handleOpen(file.getAbsolutePath()); } + return null; }); - - application.setPrintFileHandler(new PrintFilesHandler() { - public void printFiles(PrintFilesEvent event) { - // TODO not yet implemented - } + + setHandler(application, "setPrintFileHandler", (proxy, method, args) -> { + // TODO not yet implemented + return null; }); - - application.setQuitHandler(new QuitHandler() { - public void handleQuitRequestWith(QuitEvent event, QuitResponse response) { - if (base.handleQuit()) { - response.performQuit(); - } else { - response.cancelQuit(); - } + + setHandler(application, "setQuitHandler", (proxy, method, args) -> { + if (base.handleQuit()) { + args[1].getClass().getMethod("performQuit").invoke(args[1]); + } else { + args[1].getClass().getMethod("cancelQuit").invoke(args[1]); } + return null; }); - // Set the menubar to be used when nothing else is open. + // Set the menubar to be used when nothing else is open. JMenuBar defaultMenuBar = new JMenuBar(); JMenu fileMenu = buildFileMenu(base); defaultMenuBar.add(fileMenu); @@ -117,12 +117,12 @@ public void handleQuitRequestWith(QuitEvent event, QuitResponse response) { e.printStackTrace(); // oh well, never mind } // } else { -// // The douchebags at Oracle didn't feel that a working f*king menubar -// // on OS X was important enough to make it into the 7u40 release. +// // The douchebags at Oracle didn't feel that a working f*king menubar +// // on OS X was important enough to make it into the 7u40 release. // //http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8007267 // // It languished in the JDK 8 source and has been backported for 7u60: // //http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8022667 -// +// // JFrame offscreen = new JFrame(); // offscreen.setUndecorated(true); // offscreen.setJMenuBar(defaultMenuBar); @@ -131,12 +131,51 @@ public void handleQuitRequestWith(QuitEvent event, QuitResponse response) { // offscreen.setVisible(true); // } } - + // public ThinkDifferent(Base base) { // this.base = base; // } + /** + * Sets a handler on an instance of {@link Application}, taking into account JVM version + * differences. + * + * @param app an instance of {@link Application} + * @param name the "set handler" method name + * @param handler the handler + */ + private static void setHandler(Application app, String name, InvocationHandler handler) { + // Determine which version of com.apple.eawt.Application to use and pass it a handler of the + // appropriate type + Method[] methods = app.getClass().getMethods(); + for (Method m : methods) { + if (!name.equals(m.getName())) { + continue; + } + if (m.getParameterCount() != 1) { + continue; + } + Class paramType = m.getParameterTypes()[0]; + try { + // Allow a null handler + Object proxy = null; + if (handler != null) { + proxy = Proxy.newProxyInstance( + paramType.getClassLoader(), new Class[] { paramType }, handler); + } + m.invoke(app, proxy); + } catch (IllegalArgumentException ex) { + // TODO: Print error?: method doesn't take an interface, etc. + } catch (IllegalAccessException ex) { + // TODO: Print error?: Other method invocation problem + } catch (InvocationTargetException ex) { + ex.getCause().printStackTrace(); + // TODO: Print ex.getCause() a different way? + } + break; + } + } /** * Gimpy file menu to be used on OS X when no sketches are open. @@ -162,7 +201,7 @@ public void actionPerformed(ActionEvent e) { fileMenu.add(item); item = Toolkit.newJMenuItemShift(Language.text("menu.file.sketchbook"), 'K'); - item.addActionListener(new ActionListener() { + item.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { base.getNextMode().showSketchbookFrame(); diff --git a/core/src/processing/core/ThinkDifferent.java b/core/src/processing/core/ThinkDifferent.java index 8596696198..af40d8a544 100644 --- a/core/src/processing/core/ThinkDifferent.java +++ b/core/src/processing/core/ThinkDifferent.java @@ -23,11 +23,12 @@ package processing.core; import java.awt.Image; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; -import com.apple.eawt.AppEvent.QuitEvent; import com.apple.eawt.Application; -import com.apple.eawt.QuitHandler; -import com.apple.eawt.QuitResponse; /** @@ -57,25 +58,64 @@ static public void init(final PApplet sketch) { application = Application.getApplication(); } - application.setQuitHandler(new QuitHandler() { - public void handleQuitRequestWith(QuitEvent event, QuitResponse response) { - sketch.exit(); - if (PApplet.uncaughtThrowable == null && // no known crash - !attemptedQuit) { // haven't tried yet - response.cancelQuit(); // tell OS X we'll handle this - attemptedQuit = true; - } else { - response.performQuit(); // just force it this time - } + setHandler(application, "setQuitHandler", (proxy, method, args) -> { + sketch.exit(); + if (PApplet.uncaughtThrowable == null && // no known crash + !attemptedQuit) { // haven't tried yet + args[1].getClass().getMethod("cancelQuit").invoke(args[1]); // tell OS X we'll handle this + attemptedQuit = true; + } else { + args[1].getClass().getMethod("performQuit").invoke(args[1]); // just force it this time } + return null; }); } + /** + * Sets a handler on an instance of {@link Application}, taking into account JVM version + * differences. + * + * @param app an instance of {@link Application} + * @param name the "set handler" method name + * @param handler the handler + */ + private static void setHandler(Application app, String name, InvocationHandler handler) { + // Determine which version of com.apple.eawt.Application to use and pass it a handler of the + // appropriate type + Method[] methods = app.getClass().getMethods(); + for (Method m : methods) { + if (!name.equals(m.getName())) { + continue; + } + if (m.getParameterCount() != 1) { + continue; + } + Class paramType = m.getParameterTypes()[0]; + try { + // Allow a null handler + Object proxy = null; + if (handler != null) { + proxy = Proxy.newProxyInstance( + paramType.getClassLoader(), new Class[] { paramType }, handler); + } + m.invoke(app, proxy); + } catch (IllegalArgumentException ex) { + // TODO: Print error?: method doesn't take an interface, etc. + } catch (IllegalAccessException ex) { + // TODO: Print error?: Other method invocation problem + } catch (InvocationTargetException ex) { + ex.getCause().printStackTrace(); + // TODO: Print ex.getCause() a different way? + } + break; + } + } + static public void cleanup() { if (application == null) { application = Application.getApplication(); } - application.setQuitHandler(null); + setHandler(application, "setQuitHandler", null); } // Called via reflection from PSurfaceAWT and others From 2ef86bf3b8d64eff3c499d4bdd3caa2fa72aa51e Mon Sep 17 00:00:00 2001 From: Shawn Silverman Date: Fri, 18 Jan 2019 17:25:13 -0800 Subject: [PATCH 2/2] Changing "JVM version differences" to "JDK version differences". --- app/src/processing/app/platform/ThinkDifferent.java | 2 +- core/src/processing/core/ThinkDifferent.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/processing/app/platform/ThinkDifferent.java b/app/src/processing/app/platform/ThinkDifferent.java index 01c9823bc3..9b80d42776 100644 --- a/app/src/processing/app/platform/ThinkDifferent.java +++ b/app/src/processing/app/platform/ThinkDifferent.java @@ -138,7 +138,7 @@ static protected void init(final Base base) { // } /** - * Sets a handler on an instance of {@link Application}, taking into account JVM version + * Sets a handler on an instance of {@link Application}, taking into account JDK version * differences. * * @param app an instance of {@link Application} diff --git a/core/src/processing/core/ThinkDifferent.java b/core/src/processing/core/ThinkDifferent.java index af40d8a544..6ef7203898 100644 --- a/core/src/processing/core/ThinkDifferent.java +++ b/core/src/processing/core/ThinkDifferent.java @@ -72,7 +72,7 @@ static public void init(final PApplet sketch) { } /** - * Sets a handler on an instance of {@link Application}, taking into account JVM version + * Sets a handler on an instance of {@link Application}, taking into account JDK version * differences. * * @param app an instance of {@link Application}