|
22 | 22 |
|
23 | 23 | package processing.core; |
24 | 24 |
|
25 | | -import java.awt.Image; |
26 | | -import java.lang.reflect.InvocationHandler; |
27 | | -import java.lang.reflect.InvocationTargetException; |
28 | | -import java.lang.reflect.Method; |
29 | | -import java.lang.reflect.Proxy; |
30 | | - |
31 | | -import com.apple.eawt.Application; |
| 25 | +import java.awt.*; |
32 | 26 |
|
33 | 27 |
|
34 | 28 | /** |
35 | | - * Deal with issues related to thinking differently. |
| 29 | + * Deal with issues related to Mac OS window behavior. |
36 | 30 | * |
37 | 31 | * We have to register a quit handler to safely shut down the sketch, |
38 | 32 | * otherwise OS X will just kill the sketch when a user hits Cmd-Q. |
39 | 33 | * In addition, we have a method to set the dock icon image so we look more |
40 | | - * like a native application. |
| 34 | + * like a native desktop. |
41 | 35 | * |
42 | 36 | * This is a stripped-down version of what's in processing.app.platform to fix |
43 | 37 | * <a href="https://github.com/processing/processing/issues/3301">3301</a>. |
44 | 38 | */ |
45 | 39 | public class ThinkDifferent { |
46 | 40 |
|
47 | | - // http://developer.apple.com/documentation/Java/Reference/1.4.2/appledoc/api/com/apple/eawt/Application.html |
48 | | - private static Application application; |
| 41 | + private static Desktop desktop; |
| 42 | + private static Taskbar taskbar; |
49 | 43 |
|
50 | 44 | // True if user has tried to quit once. Prevents us from canceling the quit |
51 | 45 | // call if the sketch is held up for some reason, like an exception that's |
52 | 46 | // managed to put the sketch in a bad state. |
53 | 47 | static boolean attemptedQuit; |
54 | 48 |
|
55 | | - |
| 49 | + /** |
| 50 | + * Initialize the sketch with the quit handler. |
| 51 | + * |
| 52 | + * Initialize the sketch with the quit handler such that, if there is no known |
| 53 | + * crash, the application will not exit on its own if this is the first quit |
| 54 | + * attempt. |
| 55 | + * |
| 56 | + * @param sketch The sketch whose quit handler callback should be set. |
| 57 | + */ |
56 | 58 | static public void init(final PApplet sketch) { |
57 | | - if (application == null) { |
58 | | - application = Application.getApplication(); |
59 | | - } |
60 | | - |
61 | | - setHandler(application, "setQuitHandler", (proxy, method, args) -> { |
| 59 | + getDesktop().setQuitHandler((event, quitResponse) -> { |
62 | 60 | sketch.exit(); |
63 | | - if (PApplet.uncaughtThrowable == null && // no known crash |
64 | | - !attemptedQuit) { // haven't tried yet |
65 | | - args[1].getClass().getMethod("cancelQuit").invoke(args[1]); // tell OS X we'll handle this |
| 61 | + |
| 62 | + boolean noKnownCrash = PApplet.uncaughtThrowable == null; |
| 63 | + |
| 64 | + if (noKnownCrash && !attemptedQuit) { // haven't tried yet |
| 65 | + quitResponse.cancelQuit(); // tell OS X we'll handle this |
66 | 66 | attemptedQuit = true; |
67 | 67 | } else { |
68 | | - args[1].getClass().getMethod("performQuit").invoke(args[1]); // just force it this time |
| 68 | + quitResponse.performQuit(); // just force it this time |
69 | 69 | } |
70 | | - return null; |
71 | 70 | }); |
72 | 71 | } |
73 | 72 |
|
74 | 73 | /** |
75 | | - * Sets a handler on an instance of {@link Application}, taking into account JVM version |
76 | | - * differences. |
| 74 | + * Remove the quit handler. |
| 75 | + */ |
| 76 | + static public void cleanup() { |
| 77 | + getDesktop().setQuitHandler(null); |
| 78 | + } |
| 79 | + |
| 80 | + /** |
| 81 | + * Called via reflection from PSurfaceAWT and others, set the dock icon image. |
77 | 82 | * |
78 | | - * @param app an instance of {@link Application} |
79 | | - * @param name the "set handler" method name |
80 | | - * @param handler the handler |
| 83 | + * @param image The image to provide for Processing icon. |
81 | 84 | */ |
82 | | - private static void setHandler(Application app, String name, InvocationHandler handler) { |
83 | | - // Determine which version of com.apple.eawt.Application to use and pass it a handler of the |
84 | | - // appropriate type |
85 | | - Method[] methods = app.getClass().getMethods(); |
86 | | - for (Method m : methods) { |
87 | | - if (!name.equals(m.getName())) { |
88 | | - continue; |
89 | | - } |
90 | | - if (m.getParameterCount() != 1) { |
91 | | - continue; |
92 | | - } |
93 | | - Class paramType = m.getParameterTypes()[0]; |
94 | | - try { |
95 | | - // Allow a null handler |
96 | | - Object proxy = null; |
97 | | - if (handler != null) { |
98 | | - proxy = Proxy.newProxyInstance( |
99 | | - paramType.getClassLoader(), new Class<?>[] { paramType }, handler); |
100 | | - } |
101 | | - m.invoke(app, proxy); |
102 | | - } catch (IllegalArgumentException ex) { |
103 | | - // TODO: Print error?: method doesn't take an interface, etc. |
104 | | - } catch (IllegalAccessException ex) { |
105 | | - // TODO: Print error?: Other method invocation problem |
106 | | - } catch (InvocationTargetException ex) { |
107 | | - ex.getCause().printStackTrace(); |
108 | | - // TODO: Print ex.getCause() a different way? |
109 | | - } |
110 | | - break; |
111 | | - } |
| 85 | + static public void setIconImage(Image image) { |
| 86 | + getTaskbar().setIconImage(image); |
112 | 87 | } |
113 | 88 |
|
114 | | - static public void cleanup() { |
115 | | - if (application == null) { |
116 | | - application = Application.getApplication(); |
| 89 | + /** |
| 90 | + * Get the taskbar where OS visual settings can be provided. |
| 91 | + * |
| 92 | + * @return Cached taskbar singleton instance. |
| 93 | + */ |
| 94 | + static private Taskbar getTaskbar() { |
| 95 | + if (taskbar == null) { |
| 96 | + taskbar = Taskbar.getTaskbar(); |
117 | 97 | } |
118 | | - setHandler(application, "setQuitHandler", null); |
| 98 | + |
| 99 | + return taskbar; |
119 | 100 | } |
120 | 101 |
|
121 | | - // Called via reflection from PSurfaceAWT and others |
122 | | - static public void setIconImage(Image image) { |
123 | | - // When already set, is a sun.awt.image.MultiResolutionCachedImage on OS X |
124 | | -// Image current = application.getDockIconImage(); |
125 | | -// System.out.println("current dock icon image is " + current); |
126 | | -// System.out.println("changing to " + image); |
| 102 | + /** |
| 103 | + * Get the desktop where OS behavior can be provided. |
| 104 | + * |
| 105 | + * @return Cached desktop singleton instance. |
| 106 | + */ |
| 107 | + static private Desktop getDesktop() { |
| 108 | + if (desktop == null) { |
| 109 | + desktop = Desktop.getDesktop(); |
| 110 | + } |
127 | 111 |
|
128 | | - application.setDockIconImage(image); |
| 112 | + return desktop; |
129 | 113 | } |
130 | 114 |
|
131 | 115 |
|
132 | 116 | // Instead, just use Application.getApplication() inside your app |
133 | 117 | // static public Application getApplication() { |
134 | | -// return application; |
| 118 | +// return desktop; |
135 | 119 | // } |
136 | 120 | } |
0 commit comments