|
@@ -32,8 +32,9 @@ import com.dmdirc.interfaces.actions.ActionType;
|
32
|
32
|
import com.dmdirc.logger.ErrorLevel;
|
33
|
33
|
import com.dmdirc.logger.Logger;
|
34
|
34
|
|
|
35
|
+import java.awt.Image;
|
|
36
|
+import java.awt.PopupMenu;
|
35
|
37
|
import java.awt.event.ActionEvent;
|
36
|
|
-import java.lang.reflect.Field;
|
37
|
38
|
import java.lang.reflect.InvocationHandler;
|
38
|
39
|
import java.lang.reflect.InvocationTargetException;
|
39
|
40
|
import java.lang.reflect.Method;
|
|
@@ -41,9 +42,11 @@ import java.lang.reflect.Proxy;
|
41
|
42
|
import java.net.URI;
|
42
|
43
|
import java.net.URISyntaxException;
|
43
|
44
|
import java.util.ArrayList;
|
|
45
|
+import java.util.EventObject;
|
44
|
46
|
import java.util.List;
|
45
|
47
|
|
46
|
48
|
import javax.swing.JMenu;
|
|
49
|
+import javax.swing.JMenuBar;
|
47
|
50
|
import javax.swing.JMenuItem;
|
48
|
51
|
import javax.swing.UIManager;
|
49
|
52
|
|
|
@@ -51,66 +54,24 @@ import javax.swing.UIManager;
|
51
|
54
|
* Integrate DMDirc with OS X better.
|
52
|
55
|
*/
|
53
|
56
|
public final class Apple implements InvocationHandler, ActionListener {
|
54
|
|
-
|
55
|
|
- /**
|
56
|
|
- * Dummy interface for ApplicationEvent from the Apple UI on non-Apple
|
57
|
|
- * platforms.
|
58
|
|
- * http://developer.apple.com/documentation/Java/Reference/1.5.0/appledoc/
|
59
|
|
- * api/com/apple/eawt/ApplicationEvent.html
|
60
|
|
- */
|
61
|
|
- public interface ApplicationEvent {
|
62
|
|
-
|
63
|
|
- /**
|
64
|
|
- * Provides the filename associated with a particular AppleEvent.
|
65
|
|
- *
|
66
|
|
- * @return The filename associated with a particular AppleEvent.
|
67
|
|
- */
|
68
|
|
- String getFilename();
|
69
|
|
-
|
70
|
|
- /**
|
71
|
|
- * Whether or not this event is handled.
|
72
|
|
- *
|
73
|
|
- * @return True if the event is handled, false otherwise
|
74
|
|
- */
|
75
|
|
- boolean isHandled();
|
76
|
|
-
|
77
|
|
- /**
|
78
|
|
- * Sets the handled state of this event.
|
79
|
|
- *
|
80
|
|
- * @param handled The new 'handled' state for this event.
|
81
|
|
- */
|
82
|
|
- void setHandled(boolean handled);
|
83
|
|
-
|
84
|
|
- /**
|
85
|
|
- * Retrieves the source of this event.
|
86
|
|
- *
|
87
|
|
- * @return This event's source
|
88
|
|
- */
|
89
|
|
- Object getSource();
|
90
|
|
-
|
91
|
|
- /**
|
92
|
|
- * Get a string representation of this object.
|
93
|
|
- *
|
94
|
|
- * @return A string representation of this object.
|
95
|
|
- */
|
96
|
|
- @Override
|
97
|
|
- String toString();
|
98
|
|
- }
|
99
|
|
-
|
100
|
57
|
/** Store any addresses that are opened before CLIENT_OPENED. */
|
101
|
58
|
private final List<URI> addresses = new ArrayList<URI>();
|
|
59
|
+
|
102
|
60
|
/** Config manager used to read settings. */
|
103
|
61
|
private final ConfigManager configManager;
|
|
62
|
+
|
104
|
63
|
/** The "Application" object used to do stuff on OS X. */
|
105
|
64
|
private Object application;
|
106
|
|
- /** The "NSApplication" object used to do cocoa stuff on OS X. */
|
107
|
|
- private Object nsApplication;
|
|
65
|
+
|
108
|
66
|
/** Are we listening? */
|
109
|
67
|
private boolean isListener = false;
|
|
68
|
+
|
110
|
69
|
/** The MenuBar for the application. */
|
111
|
70
|
private MenuBar menuBar = null;
|
|
71
|
+
|
112
|
72
|
/** Has the CLIENT_OPENED action been called? */
|
113
|
73
|
private boolean clientOpened = false;
|
|
74
|
+
|
114
|
75
|
/** Our swing controller. */
|
115
|
76
|
private final SwingController controller;
|
116
|
77
|
|
|
@@ -135,72 +96,76 @@ public final class Apple implements InvocationHandler, ActionListener {
|
135
|
96
|
try {
|
136
|
97
|
System.loadLibrary("DMDirc-Apple"); // NOPMD
|
137
|
98
|
registerOpenURLCallback();
|
138
|
|
- ActionManager.getActionManager().registerListener(this,
|
139
|
|
- CoreActionType.CLIENT_OPENED);
|
140
|
|
- } catch (final UnsatisfiedLinkError ule) {
|
141
|
|
- Logger.userError(ErrorLevel.MEDIUM,
|
142
|
|
- "Unable to load JNI library.", ule);
|
|
99
|
+ ActionManager.getActionManager().registerListener(this, CoreActionType.CLIENT_OPENED);
|
|
100
|
+ } catch (UnsatisfiedLinkError ule) {
|
|
101
|
+ Logger.appError(ErrorLevel.MEDIUM, "Unable to load JNI library.", ule);
|
143
|
102
|
}
|
144
|
103
|
}
|
145
|
104
|
}
|
146
|
105
|
|
147
|
106
|
/**
|
148
|
|
- * Get the "Application" object.
|
|
107
|
+ * Register the getURL Callback.
|
149
|
108
|
*
|
150
|
|
- * @return Object that on OSX will be an "Application"
|
|
109
|
+ * @return 0 on success, 1 on failure.
|
151
|
110
|
*/
|
152
|
|
- public Object getApplication() {
|
153
|
|
- synchronized (Apple.class) {
|
154
|
|
- if (isApple() && application == null) {
|
155
|
|
- try {
|
156
|
|
- final Class<?> app = Class.forName(
|
157
|
|
- "com.apple.eawt.Application");
|
158
|
|
- final Method method = app.getMethod("getApplication",
|
159
|
|
- new Class[0]);
|
160
|
|
- application = method.invoke(null, new Object[0]);
|
161
|
|
- } catch (final ClassNotFoundException ex) {
|
162
|
|
- application = null;
|
163
|
|
- } catch (final NoSuchMethodException ex) {
|
164
|
|
- application = null;
|
165
|
|
- } catch (final SecurityException ex) {
|
166
|
|
- application = null;
|
167
|
|
- } catch (final IllegalAccessException ex) {
|
168
|
|
- application = null;
|
169
|
|
- } catch (final IllegalArgumentException ex) {
|
170
|
|
- application = null;
|
171
|
|
- } catch (final InvocationTargetException ex) {
|
172
|
|
- application = null;
|
173
|
|
- }
|
174
|
|
- }
|
175
|
|
- return application;
|
|
111
|
+ private synchronized native int registerOpenURLCallback();
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+ /**
|
|
115
|
+ * Call a method on the given object.
|
|
116
|
+ *
|
|
117
|
+ * @param obj Object to call method on.
|
|
118
|
+ * @oaram className Name of class that object really is.
|
|
119
|
+ * @param methodName Method to call
|
|
120
|
+ * @param classes Array of classes to pass when calling getMethod
|
|
121
|
+ * @param objects Array of objects to pass when invoking.
|
|
122
|
+ * @return Output from method.invoke()
|
|
123
|
+ */
|
|
124
|
+ private Object reflectMethod(final Object obj, final String className, final String methodName, final Class[] classes, final Object[] objects) {
|
|
125
|
+ try {
|
|
126
|
+ final Class<?> clazz = className == null ? obj.getClass() : Class.forName(className);
|
|
127
|
+ final Method method = clazz.getMethod(methodName, classes == null ? new Class[0] : classes);
|
|
128
|
+ return method.invoke(obj, objects == null ? new Object[0] : objects);
|
|
129
|
+ } catch (IllegalArgumentException ex) {
|
|
130
|
+ Logger.userError(ErrorLevel.LOW, "Unable to find OS X classes");
|
|
131
|
+ } catch (InvocationTargetException ex) {
|
|
132
|
+ Logger.userError(ErrorLevel.LOW, "Unable to find OS X classes");
|
|
133
|
+ } catch (final ClassNotFoundException ex) {
|
|
134
|
+ Logger.userError(ErrorLevel.LOW, "Unable to find OS X classes");
|
|
135
|
+ } catch (final NoSuchMethodException ex) {
|
|
136
|
+ Logger.userError(ErrorLevel.LOW, "Unable to find OS X classes");
|
|
137
|
+ } catch (final IllegalAccessException ex) {
|
|
138
|
+ Logger.userError(ErrorLevel.LOW, "Unable to find OS X classes");
|
176
|
139
|
}
|
|
140
|
+
|
|
141
|
+ return null;
|
177
|
142
|
}
|
178
|
143
|
|
179
|
144
|
/**
|
180
|
|
- * Get the "NSApplication" object.
|
|
145
|
+ * Handle a method call to the apple Application class.
|
|
146
|
+ *
|
|
147
|
+ * @param methodName Method to call
|
|
148
|
+ * @param classes Array of classes to pass when calling getMethod
|
|
149
|
+ * @param objects Array of objects to pass when invoking.
|
|
150
|
+ * @return Output from method.invoke()
|
|
151
|
+ */
|
|
152
|
+ private Object doAppleMethod(final String methodName, final Class[] classes, final Object[] objects) {
|
|
153
|
+ if (!isApple()) { return null; }
|
|
154
|
+
|
|
155
|
+ return reflectMethod(getApplication(), null, methodName, classes, objects);
|
|
156
|
+ }
|
|
157
|
+
|
|
158
|
+ /**
|
|
159
|
+ * Get the "Application" object.
|
181
|
160
|
*
|
182
|
|
- * @return Object that on OSX will be an "NSApplication"
|
|
161
|
+ * @return Object that on OSX will be an "Application"
|
183
|
162
|
*/
|
184
|
|
- public Object getNSApplication() {
|
|
163
|
+ public Object getApplication() {
|
185
|
164
|
synchronized (Apple.class) {
|
186
|
|
- if (isApple() && nsApplication == null) {
|
187
|
|
- try {
|
188
|
|
- final Class<?> app = Class.forName(
|
189
|
|
- "com.apple.cocoa.application.NSApplication");
|
190
|
|
- final Method method = app.getMethod("sharedApplication",
|
191
|
|
- new Class[0]);
|
192
|
|
- nsApplication = method.invoke(null, new Object[0]);
|
193
|
|
- } catch (final ClassNotFoundException ex) {
|
194
|
|
- nsApplication = null;
|
195
|
|
- } catch (final NoSuchMethodException ex) {
|
196
|
|
- nsApplication = null;
|
197
|
|
- } catch (final IllegalAccessException ex) {
|
198
|
|
- nsApplication = null;
|
199
|
|
- } catch (final InvocationTargetException ex) {
|
200
|
|
- nsApplication = null;
|
201
|
|
- }
|
|
165
|
+ if (isApple() && application == null) {
|
|
166
|
+ application = reflectMethod(null, "com.apple.eawt.Application", "getApplication", null, null);
|
202
|
167
|
}
|
203
|
|
- return nsApplication;
|
|
168
|
+ return application;
|
204
|
169
|
}
|
205
|
170
|
}
|
206
|
171
|
|
|
@@ -232,81 +197,114 @@ public final class Apple implements InvocationHandler, ActionListener {
|
232
|
197
|
}
|
233
|
198
|
|
234
|
199
|
// Set some Apple OS X related stuff from http://tinyurl.com/6xwuld
|
235
|
|
- final String aaText = configManager
|
236
|
|
- .getOptionBool("ui", "antialias") ? "on" : "off";
|
|
200
|
+ final String aaText = configManager.getOptionBool("ui", "antialias") ? "on" : "off";
|
237
|
201
|
|
238
|
202
|
System.setProperty("apple.awt.antialiasing", aaText);
|
239
|
203
|
System.setProperty("apple.awt.textantialiasing", aaText);
|
240
|
204
|
System.setProperty("apple.awt.showGrowBox", "true");
|
241
|
|
- System.setProperty("com.apple.mrj.application.apple.menu.about.name",
|
242
|
|
- "DMDirc");
|
|
205
|
+ System.setProperty("com.apple.mrj.application.apple.menu.about.name", "DMDirc");
|
243
|
206
|
System.setProperty("apple.laf.useScreenMenuBar", "true");
|
244
|
|
- System.setProperty("com.apple.mrj.application.growbox.intrudes",
|
245
|
|
- "false");
|
|
207
|
+ System.setProperty("com.apple.mrj.application.growbox.intrudes", "false");
|
246
|
208
|
System.setProperty("com.apple.mrj.application.live-resize", "true");
|
247
|
209
|
}
|
248
|
210
|
|
249
|
211
|
/**
|
250
|
|
- * Request user attention (Bounce the dock).
|
|
212
|
+ * Requests this application to move to the foreground.
|
|
213
|
+ *
|
|
214
|
+ * @param allWindows if all windows of this application should be moved to
|
|
215
|
+ * the foreground, or only the foremost one
|
|
216
|
+ */
|
|
217
|
+ public void requestForeground(final boolean allWindows) {
|
|
218
|
+ doAppleMethod("requestForeground", new Class[]{Boolean.TYPE}, new Object[]{allWindows});
|
|
219
|
+ }
|
|
220
|
+
|
|
221
|
+ /**
|
|
222
|
+ * Requests user attention to this application (usually through bouncing
|
|
223
|
+ * the Dock icon). Critical requests will continue to bounce the Dock icon
|
|
224
|
+ * until the app is activated. An already active application requesting
|
|
225
|
+ * attention does nothing.
|
251
|
226
|
*
|
252
|
227
|
* @param isCritical If this is false, the dock icon only bounces once,
|
253
|
228
|
* otherwise it will bounce until clicked on.
|
254
|
229
|
*/
|
255
|
230
|
public void requestUserAttention(final boolean isCritical) {
|
256
|
|
- if (!isApple()) {
|
257
|
|
- return;
|
258
|
|
- }
|
|
231
|
+ doAppleMethod("requestUserAttention", new Class[]{Boolean.TYPE}, new Object[]{isCritical});
|
|
232
|
+ }
|
259
|
233
|
|
260
|
|
- try {
|
261
|
|
- final Field type = isCritical ? getNSApplication().getClass().
|
262
|
|
- getField("UserAttentionRequestCritical")
|
263
|
|
- : getNSApplication().
|
264
|
|
- getClass().getField("Informational");
|
265
|
|
- final Method method = getNSApplication().getClass().getMethod(
|
266
|
|
- "requestUserAttention", new Class[] { Integer.TYPE });
|
267
|
|
- method.invoke(getNSApplication(), new Object[] { type.get(null) });
|
268
|
|
- } catch (final NoSuchFieldException ex) {
|
269
|
|
- Logger.userError(ErrorLevel.LOW, "Unable to find OS X classes");
|
270
|
|
- } catch (final NoSuchMethodException ex) {
|
271
|
|
- Logger.userError(ErrorLevel.LOW, "Unable to find OS X classes");
|
272
|
|
- } catch (final IllegalAccessException ex) {
|
273
|
|
- Logger.userError(ErrorLevel.LOW, "Unable to find OS X classes");
|
274
|
|
- } catch (final InvocationTargetException ex) {
|
275
|
|
- Logger.userError(ErrorLevel.LOW, "Unable to find OS X classes");
|
276
|
|
- }
|
|
234
|
+ /**
|
|
235
|
+ * Attaches the contents of the provided PopupMenu to the application's Dock icon.
|
|
236
|
+ *
|
|
237
|
+ * @param menu the PopupMenu to attach to this application's Dock icon
|
|
238
|
+ */
|
|
239
|
+ public void setDockMenu(final PopupMenu menu) {
|
|
240
|
+ doAppleMethod("setDockMenu", new Class[]{PopupMenu.class}, new Object[]{menu});
|
277
|
241
|
}
|
278
|
242
|
|
279
|
243
|
/**
|
280
|
|
- * Set this up as a listener for the Apple Events.
|
|
244
|
+ * Get the PopupMenu attached to the application's Dock icon.
|
281
|
245
|
*
|
282
|
|
- * @return True if the listener was added, else false.
|
|
246
|
+ * @return the PopupMenu attached to this application's Dock icon
|
283
|
247
|
*/
|
284
|
|
- public boolean setListener() {
|
285
|
|
- if (!isApple() || isListener) {
|
286
|
|
- return false;
|
287
|
|
- }
|
|
248
|
+ public PopupMenu getDockMenu() {
|
|
249
|
+ final Object result = doAppleMethod("getDockMenu", null, null);
|
|
250
|
+ return (result instanceof PopupMenu) ? (PopupMenu)result : null;
|
|
251
|
+ }
|
288
|
252
|
|
289
|
|
- try {
|
290
|
|
- final Class<?> listenerClass = Class.forName(
|
291
|
|
- "com.apple.eawt.ApplicationListener");
|
292
|
|
- final Object listener = Proxy.newProxyInstance(getClass().
|
293
|
|
- getClassLoader(), new Class[] { listenerClass }, this);
|
|
253
|
+ /**
|
|
254
|
+ * Changes this application's Dock icon to the provided image.
|
|
255
|
+ *
|
|
256
|
+ * @param image The image to use
|
|
257
|
+ */
|
|
258
|
+ public void setDockIconImage(final Image image) {
|
|
259
|
+ doAppleMethod("setDockIconImage", new Class[]{Image.class}, new Object[]{image});
|
|
260
|
+ }
|
294
|
261
|
|
295
|
|
- Method method = getApplication().getClass().getMethod(
|
296
|
|
- "addApplicationListener", new Class[] { listenerClass });
|
297
|
|
- method.invoke(getApplication(), listener);
|
|
262
|
+ /**
|
|
263
|
+ * Obtains an image of this application's Dock icon.
|
|
264
|
+ *
|
|
265
|
+ * @return The application's dock icon.
|
|
266
|
+ */
|
|
267
|
+ public Image getDockIconImage() {
|
|
268
|
+ final Object result = doAppleMethod("getDockIconImage", null, null);
|
|
269
|
+ return (result instanceof Image) ? (Image)result : null;
|
|
270
|
+ }
|
298
|
271
|
|
299
|
|
- isListener = true;
|
|
272
|
+ /**
|
|
273
|
+ * Affixes a small system provided badge to this application's Dock icon.
|
|
274
|
+ * Usually a number.
|
|
275
|
+ *
|
|
276
|
+ * @param badge textual label to affix to the Dock icon
|
|
277
|
+ */
|
|
278
|
+ public void setDockIconBadge(final String badge) {
|
|
279
|
+ doAppleMethod("setDockIconBadge", new Class[]{String.class}, new Object[]{badge});
|
|
280
|
+ }
|
|
281
|
+
|
|
282
|
+ /**
|
|
283
|
+ * Sets the default menu bar to use when there are no active frames.
|
|
284
|
+ * Only used when the system property "apple.laf.useScreenMenuBar" is
|
|
285
|
+ * "true", and the Aqua Look and Feel is active.
|
|
286
|
+ *
|
|
287
|
+ * @param menuBar to use when no other frames are active
|
|
288
|
+ */
|
|
289
|
+ public void setDefaultMenuBar(final JMenuBar menuBar) {
|
|
290
|
+ doAppleMethod("setDefaultMenuBar", new Class[]{JMenuBar.class}, new Object[]{menuBar});
|
|
291
|
+ }
|
300
|
292
|
|
301
|
|
- method = getApplication().getClass().getMethod(
|
302
|
|
- "setEnabledPreferencesMenu", new Class[] { Boolean.TYPE });
|
303
|
|
- method.invoke(getApplication(), new Object[] { Boolean.TRUE });
|
|
293
|
+ /**
|
|
294
|
+ * Add this application as a handler for the given event.
|
|
295
|
+ *
|
|
296
|
+ * @param handlerClass Class used as the handler.
|
|
297
|
+ * @param handlerMethod Method used to set the handler.
|
|
298
|
+ * @return True if we succeeded.
|
|
299
|
+ */
|
|
300
|
+ private boolean addHandler(final String handlerClass, final String handlerMethod) {
|
|
301
|
+ try {
|
|
302
|
+ final Class<?> listenerClass = Class.forName(handlerClass);
|
|
303
|
+ final Object listener = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{listenerClass}, this);
|
|
304
|
+
|
|
305
|
+ final Method method = getApplication().getClass().getMethod(handlerMethod, new Class[]{listenerClass});
|
|
306
|
+ method.invoke(getApplication(), listener);
|
304
|
307
|
|
305
|
|
- method =
|
306
|
|
- getApplication().getClass().getMethod(
|
307
|
|
- "setEnabledAboutMenu",
|
308
|
|
- new Class[] { Boolean.TYPE });
|
309
|
|
- method.invoke(getApplication(), new Object[] { Boolean.TRUE });
|
310
|
308
|
return true;
|
311
|
309
|
} catch (final ClassNotFoundException ex) {
|
312
|
310
|
return false;
|
|
@@ -319,37 +317,54 @@ public final class Apple implements InvocationHandler, ActionListener {
|
319
|
317
|
}
|
320
|
318
|
}
|
321
|
319
|
|
|
320
|
+ /**
|
|
321
|
+ * Set this up as a listener for the Apple Events.
|
|
322
|
+ *
|
|
323
|
+ * @return True if the listener was added, else false.
|
|
324
|
+ */
|
|
325
|
+ public boolean setListener() {
|
|
326
|
+ if (!isApple() || isListener) {
|
|
327
|
+ return false;
|
|
328
|
+ }
|
|
329
|
+
|
|
330
|
+ addHandler("com.apple.eawt.OpenURIHandler", "setOpenURIHandler");
|
|
331
|
+ addHandler("com.apple.eawt.AboutHandler", "setAboutHandler");
|
|
332
|
+ addHandler("com.apple.eawt.QuitHandler", "setQuitHandler");
|
|
333
|
+ addHandler("com.apple.eawt.PreferencesHandler", "setPreferencesHandler");
|
|
334
|
+ isListener = true;
|
|
335
|
+
|
|
336
|
+ return true;
|
|
337
|
+ }
|
|
338
|
+
|
322
|
339
|
/**
|
323
|
340
|
* {@inheritDoc}
|
324
|
341
|
*
|
325
|
342
|
* @throws Throwable Throws stuff on errors
|
326
|
343
|
*/
|
327
|
344
|
@Override
|
328
|
|
- public Object invoke(final Object proxy, final Method method,
|
329
|
|
- final Object[] args) throws Throwable {
|
|
345
|
+ public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
|
330
|
346
|
if (!isApple()) {
|
331
|
347
|
return null;
|
332
|
348
|
}
|
333
|
349
|
|
334
|
350
|
try {
|
335
|
|
- final ApplicationEvent event = (ApplicationEvent) Proxy.
|
336
|
|
- newProxyInstance(getClass().getClassLoader(), new Class[] {
|
337
|
|
- ApplicationEvent.class }, new InvocationHandler() {
|
338
|
|
-
|
339
|
|
- /** {@inheritDoc} */
|
340
|
|
- @Override
|
341
|
|
- public Object invoke(final Object p,
|
342
|
|
- final Method m,
|
343
|
|
- final Object[] a) throws Throwable {
|
344
|
|
- return args[0].getClass()
|
345
|
|
- .getMethod(m.getName(), m.
|
346
|
|
- getParameterTypes())
|
347
|
|
- .invoke(args[0], a);
|
348
|
|
- }
|
349
|
|
- });
|
350
|
|
- final Method thisMethod = this.getClass().getMethod(
|
351
|
|
- method.getName(), new Class[] { ApplicationEvent.class });
|
352
|
|
- return thisMethod.invoke(this, event);
|
|
351
|
+ final Class[] classes = new Class[args.length];
|
|
352
|
+
|
|
353
|
+ for (int i = 0; i < args.length; i++) {
|
|
354
|
+ if (EventObject.class.isInstance(args[i])) {
|
|
355
|
+ classes[i] = EventObject.class;
|
|
356
|
+ } else {
|
|
357
|
+ final Class c = args[i].getClass();
|
|
358
|
+ if (c.getCanonicalName().equals("com.apple.eawt.QuitResponse")) {
|
|
359
|
+ classes[i] = Object.class;
|
|
360
|
+ } else {
|
|
361
|
+ classes[i] = c;
|
|
362
|
+ }
|
|
363
|
+ }
|
|
364
|
+ }
|
|
365
|
+
|
|
366
|
+ final Method thisMethod = this.getClass().getMethod(method.getName(), classes);
|
|
367
|
+ return thisMethod.invoke(this, args);
|
353
|
368
|
} catch (final NoSuchMethodException e) {
|
354
|
369
|
if (method.getName().equals("equals") && args.length == 1) {
|
355
|
370
|
return Boolean.valueOf(proxy == args[0]);
|
|
@@ -389,41 +404,28 @@ public final class Apple implements InvocationHandler, ActionListener {
|
389
|
404
|
* Handle an event using the menuBar.
|
390
|
405
|
*
|
391
|
406
|
* @param name The name of the event according to the menubar
|
392
|
|
- * @param event The ApplicationEvent we are handingle
|
393
|
407
|
*/
|
394
|
|
- public void handleMenuBarEvent(final String name,
|
395
|
|
- final ApplicationEvent event) {
|
|
408
|
+ public void handleMenuBarEvent(final String name) {
|
396
|
409
|
if (!isApple() || menuBar == null) {
|
397
|
410
|
return;
|
398
|
411
|
}
|
399
|
|
- final ActionEvent actionEvent = new ActionEvent(this,
|
400
|
|
- ActionEvent.ACTION_PERFORMED, name);
|
|
412
|
+ final ActionEvent actionEvent = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, name);
|
401
|
413
|
|
402
|
414
|
for (int i = 0; i < menuBar.getMenuCount(); i++) {
|
403
|
415
|
final JMenu menu = menuBar.getMenu(i);
|
404
|
416
|
if (menu instanceof java.awt.event.ActionListener) {
|
405
|
417
|
((java.awt.event.ActionListener)menu).actionPerformed(actionEvent);
|
406
|
|
- event.setHandled(true);
|
407
|
418
|
}
|
408
|
419
|
}
|
409
|
420
|
}
|
410
|
421
|
|
411
|
|
- /**
|
412
|
|
- * This is called when Quit is selected from the Application menu.
|
413
|
|
- *
|
414
|
|
- * @param event an ApplicationEvent object
|
415
|
|
- */
|
416
|
|
- public void handleQuit(final ApplicationEvent event) {
|
417
|
|
- handleMenuBarEvent("Exit", event);
|
418
|
|
- }
|
419
|
|
-
|
420
|
422
|
/**
|
421
|
423
|
* This is called when About is selected from the Application menu.
|
422
|
424
|
*
|
423
|
425
|
* @param event an ApplicationEvent object
|
424
|
426
|
*/
|
425
|
|
- public void handleAbout(final ApplicationEvent event) {
|
426
|
|
- handleMenuBarEvent("About", event);
|
|
427
|
+ public void handleAbout(final EventObject event) {
|
|
428
|
+ handleMenuBarEvent("About");
|
427
|
429
|
}
|
428
|
430
|
|
429
|
431
|
/**
|
|
@@ -431,99 +433,95 @@ public final class Apple implements InvocationHandler, ActionListener {
|
431
|
433
|
*
|
432
|
434
|
* @param event an ApplicationEvent object
|
433
|
435
|
*/
|
434
|
|
- public void handlePreferences(final ApplicationEvent event) {
|
435
|
|
- handleMenuBarEvent("Preferences", event);
|
|
436
|
+ public void handlePreferences(final EventObject event) {
|
|
437
|
+ handleMenuBarEvent("Preferences");
|
436
|
438
|
}
|
437
|
439
|
|
438
|
|
- /**
|
439
|
|
- * This is called when the Application is opened.
|
440
|
|
- *
|
441
|
|
- * @param event an ApplicationEvent object
|
442
|
|
- */
|
443
|
|
- public void handleOpenApplication(final ApplicationEvent event) {
|
444
|
|
- // We don't currently support this
|
|
440
|
+ /** {@inheritDoc} */
|
|
441
|
+ @Override
|
|
442
|
+ public void processEvent(final ActionType type, final StringBuffer format, final Object... arguments) {
|
|
443
|
+ if (type == CoreActionType.CLIENT_OPENED) {
|
|
444
|
+ synchronized (addresses) {
|
|
445
|
+ clientOpened = true;
|
|
446
|
+ for (final URI addr : addresses) {
|
|
447
|
+ controller.getMain().getServerManager().connectToAddress(addr);
|
|
448
|
+ }
|
|
449
|
+ addresses.clear();
|
|
450
|
+ }
|
|
451
|
+ }
|
445
|
452
|
}
|
446
|
453
|
|
447
|
454
|
/**
|
448
|
|
- * This is called when the application is asked to open a file.
|
|
455
|
+ * This is called when Quit is selected from the Application menu.
|
449
|
456
|
*
|
450
|
457
|
* @param event an ApplicationEvent object
|
|
458
|
+ * @param quitResponse QuitResponse object.
|
451
|
459
|
*/
|
452
|
|
- public void handleOpenFile(final ApplicationEvent event) {
|
453
|
|
- // We don't currently support this
|
|
460
|
+ public void handleQuitRequestWith(final EventObject event, final Object quitResponse) {
|
|
461
|
+ // Technically we should tell OS X if the quit succeeds or not, but we
|
|
462
|
+ // have no way of knowing the result just yet.
|
|
463
|
+ //
|
|
464
|
+ // So instead we will just tell it that the quit was cancelled every
|
|
465
|
+ // time, and then just quit anyway if we need to.
|
|
466
|
+ reflectMethod(quitResponse, null, "cancelQuit", null, null);
|
|
467
|
+
|
|
468
|
+ handleMenuBarEvent("Exit");
|
454
|
469
|
}
|
455
|
470
|
|
456
|
471
|
/**
|
457
|
|
- * This is called when asked to print.
|
|
472
|
+ * Callback from our JNI library.
|
|
473
|
+ * This should work when not launcher via JavaApplicationStub
|
458
|
474
|
*
|
459
|
|
- * @param event an ApplicationEvent object
|
|
475
|
+ * @param url The irc url string to connect to.
|
460
|
476
|
*/
|
461
|
|
- public void handlePrintFile(final ApplicationEvent event) {
|
462
|
|
- // We don't currently support this
|
|
477
|
+ public void handleOpenURL(final String url) {
|
|
478
|
+ try {
|
|
479
|
+ final URI addr = NewServer.getURI(url);
|
|
480
|
+ handleURI(addr);
|
|
481
|
+ } catch (final URISyntaxException use) { }
|
463
|
482
|
}
|
464
|
483
|
|
465
|
484
|
/**
|
466
|
|
- * This is called when the application is reopened.
|
|
485
|
+ * Callback from OSX Directly.
|
|
486
|
+ * This will work if we were launched using the JavaApplicationStub
|
467
|
487
|
*
|
468
|
|
- * @param event an ApplicationEvent object
|
|
488
|
+ * @param event Event related to this callback. This event will have a
|
|
489
|
+ * reflectable getURI method to get a URI.
|
469
|
490
|
*/
|
470
|
|
- public void handleReopenApplication(final ApplicationEvent event) {
|
471
|
|
- // We don't currently support this
|
472
|
|
- }
|
|
491
|
+ public void openURI(final EventObject event) {
|
|
492
|
+ if (!isApple()) {
|
|
493
|
+ return;
|
|
494
|
+ }
|
473
|
495
|
|
474
|
|
- /** {@inheritDoc} */
|
475
|
|
- @Override
|
476
|
|
- public void processEvent(final ActionType type, final StringBuffer format,
|
477
|
|
- final Object... arguments) {
|
478
|
|
- if (type == CoreActionType.CLIENT_OPENED) {
|
479
|
|
- synchronized (addresses) {
|
480
|
|
- clientOpened = true;
|
481
|
|
- for (final URI addr : addresses) {
|
482
|
|
- controller.getMain().getServerManager().connectToAddress(addr);
|
483
|
|
- }
|
484
|
|
- addresses.clear();
|
485
|
|
- }
|
|
496
|
+ final Object obj = reflectMethod(event, null, "getURI", null, null);
|
|
497
|
+ if (obj instanceof URI) {
|
|
498
|
+ final URI uri = (URI)obj;
|
|
499
|
+ handleURI(uri);
|
486
|
500
|
}
|
487
|
501
|
}
|
488
|
502
|
|
489
|
503
|
/**
|
490
|
|
- * Callback from JNI library.
|
491
|
|
- * If called before the client has finished opening, the URL will be added
|
|
504
|
+ * Handle connecting to a URI.
|
|
505
|
+ *
|
|
506
|
+ * If called before the client has finished opening, the URI will be added
|
492
|
507
|
* to a list that will be connected to once the CLIENT_OPENED action is
|
493
|
508
|
* called. Otherwise we connect right away.
|
494
|
509
|
*
|
495
|
|
- * @param url The irc url to connect to.
|
|
510
|
+ * @param uri URI to connect to.
|
496
|
511
|
*/
|
497
|
|
- public void handleOpenURL(final String url) {
|
498
|
|
- if (!isApple()) {
|
499
|
|
- return;
|
500
|
|
- }
|
|
512
|
+ private void handleURI(final URI uri) {
|
501
|
513
|
synchronized (addresses) {
|
502
|
|
- try {
|
503
|
|
- final URI addr = NewServer.getURI(url);
|
504
|
|
- if (clientOpened) {
|
505
|
|
- // When the JNI callback is called there is no
|
506
|
|
- // ContextClassLoader set, which causes an NPE in
|
507
|
|
- // IconManager if no servers have been connected to yet.
|
508
|
|
- if (Thread.currentThread().getContextClassLoader()
|
509
|
|
- == null) {
|
510
|
|
- Thread.currentThread().setContextClassLoader(
|
511
|
|
- ClassLoader.getSystemClassLoader());
|
512
|
|
- }
|
513
|
|
- controller.getMain().getServerManager().connectToAddress(addr);
|
514
|
|
- } else {
|
515
|
|
- addresses.add(addr);
|
|
514
|
+ if (clientOpened) {
|
|
515
|
+ // When the JNI callback is called there is no
|
|
516
|
+ // ContextClassLoader set, which causes an NPE in
|
|
517
|
+ // IconManager if no servers have been connected to yet.
|
|
518
|
+ if (Thread.currentThread().getContextClassLoader() == null) {
|
|
519
|
+ Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
|
516
|
520
|
}
|
517
|
|
- } catch (final URISyntaxException iae) {
|
518
|
|
- // Do nothing
|
|
521
|
+ controller.getMain().getServerManager().connectToAddress(uri);
|
|
522
|
+ } else {
|
|
523
|
+ addresses.add(uri);
|
519
|
524
|
}
|
520
|
525
|
}
|
521
|
526
|
}
|
522
|
|
-
|
523
|
|
- /**
|
524
|
|
- * Register the getURL Callback.
|
525
|
|
- *
|
526
|
|
- * @return 0 on success, 1 on failure.
|
527
|
|
- */
|
528
|
|
- private synchronized native int registerOpenURLCallback();
|
529
|
527
|
}
|