Kaynağa Gözat

Fix URL Handling in OSX.

Fixes issue 954.


git-svn-id: http://svn.dmdirc.com/trunk@4054 00569f92-eb28-0410-84fd-f71c24880f
tags/0.6
Shane Mc Cormack 16 yıl önce
ebeveyn
işleme
3a6f1865b0

+ 121
- 0
installer/osx/DMDirc-Apple.c Dosyayı Görüntüle

@@ -0,0 +1,121 @@
1
+/*
2
+ * Copyright (c) 2006-2008 Chris Smith, Shane Mc Cormack, Gregory Holmes
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ *
22
+ * JNI library for OS X url handling.
23
+ * Compile with:
24
+ *     gcc -dynamiclib -framework JavaVM -framework Carbon -o libDMDirc-Apple.jnilib DMDirc-Apple.c -arch x86_64
25
+ */
26
+
27
+#include <Carbon/Carbon.h>
28
+#include <JavaVM/jni.h>
29
+
30
+/** The method to callback */
31
+static jmethodID callbackMethod;
32
+
33
+/** The JVM our callback is in */
34
+static JavaVM *jvm;
35
+
36
+/** The global reference to the Apple object that wants the callback */
37
+static jobject apple;
38
+
39
+/** Callback from OS X with URL. */
40
+static OSErr openURLCallback(const AppleEvent *theAppleEvent, AppleEvent* reply, long handlerRefcon);
41
+
42
+/**
43
+ * JNI Method to register interest in callback.
44
+ * Obtained from:
45
+ *     javah -classpath DMDirc.jar com.dmdirc.ui.swing.Apple
46
+ * Reference:
47
+ *     http://developer.apple.com/documentation/Carbon/Reference/Apple_Event_Manager/Reference/reference.html#//apple_ref/c/func/AEInstallEventHandler
48
+ *
49
+ * @param env The JNIEnvironment for this callback.
50
+ * @param this The object that is registering the callback
51
+ */
52
+JNIEXPORT jint JNICALL Java_com_dmdirc_ui_swing_Apple_registerOpenURLCallback (JNIEnv *env, jobject object) {
53
+	// Find the callback in the object
54
+	callbackMethod = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, object), "handleOpenURL", "(Ljava/lang/String;)V");
55
+	
56
+	// Check if the callback exists.
57
+	if (callbackMethod != 0) {
58
+		// Store the JVM for this callback, and a global reference to the Apple object
59
+		(*env)->GetJavaVM(env, &jvm);
60
+		apple = (*env)->NewGlobalRef(env, object);
61
+	
62
+		// Now register the callback to ourself.
63
+		return (jint)AEInstallEventHandler(kInternetEventClass, kAEGetURL, NewAEEventHandlerUPP((AEEventHandlerProcPtr)openURLCallback), 0, false);
64
+	} else {
65
+		return 1;
66
+	}
67
+}
68
+
69
+
70
+/**
71
+ * Callback from OS X with URL.
72
+ * Reference:
73
+ *     http://developer.apple.com/documentation/Carbon/Reference/Apple_Event_Manager/Reference/reference.html#//apple_ref/c/func/NewAEEventHandlerUPP
74
+ *     http://developer.apple.com/documentation/Carbon/Reference/Apple_Event_Manager/Reference/reference.html#//apple_ref/c/tdef/AEEventHandlerUPP
75
+ *     http://developer.apple.com/documentation/Carbon/Reference/Apple_Event_Manager/Reference/reference.html#//apple_ref/c/tdef/AEEventHandlerProcPtr
76
+ *
77
+ * @param theAppleEvent Pointer to apple event handle
78
+ * @param reply Pointer to default reply event
79
+ * @param handlerRefcon Reference constant for this callback. (Ignored)
80
+ */
81
+static OSErr openURLCallback(const AppleEvent *theAppleEvent, AppleEvent* reply, long handlerRefcon) {
82
+	OSErr result = noErr;
83
+	Size givenLength = 0;
84
+	DescType type = typeChar;
85
+	
86
+	// Get the size of the string the callback wants to give us, and then
87
+	// check that it is > 0 in length.
88
+	result = AESizeOfParam(theAppleEvent, keyDirectObject, &type, &givenLength);
89
+	if (result == noErr && givenLength != 0) {
90
+		// Allocate a buffer for the result
91
+		// givenLength +1 for the \0
92
+		Size length = givenLength + 1;
93
+		char *dataPtr = (char*)malloc(length);
94
+		
95
+		if (dataPtr != 0) {
96
+			// Empty the buffer
97
+			memset(dataPtr, 0, length);
98
+			
99
+			// Get the url
100
+			result = AEGetParamPtr(theAppleEvent, keyDirectObject, typeChar, 0, dataPtr, givenLength, &givenLength);
101
+			// Did we get it?
102
+			if (result == noErr) {
103
+				// Get the java environment for the jvm we want to callback to
104
+				JNIEnv *env;
105
+				(*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
106
+				
107
+				// Convert the url into a java string
108
+				jstring theURL = (*env)->NewStringUTF(env, dataPtr);
109
+				
110
+				// Call the method!
111
+				(*env)->CallVoidMethod(env, apple, callbackMethod, theURL);
112
+			}
113
+			
114
+			// Free the buffer
115
+			free(dataPtr);
116
+		}
117
+	}
118
+	
119
+	// And return!
120
+	return result;
121
+}

BIN
installer/osx/libDMDirc-Apple.jnilib Dosyayı Görüntüle


+ 17
- 0
installer/osx/makeInstallerOSX.sh Dosyayı Görüntüle

@@ -44,6 +44,22 @@ MKHFS=`which mkfs.hfs`
44 44
 MKHFSPLUS=`which mkfs.hfsplus`
45 45
 HDIUTIL=`which hdiutil`
46 46
 
47
+JNIName="libDMDirc-Apple.jnilib"
48
+
49
+if [ ! -e "${JNIName}" ]; then
50
+	if [ -e "/System/Library/Frameworks/JavaVM.framework/Headers" ]; then
51
+		GCC=`which gcc`
52
+		${GCC} -dynamiclib -framework JavaVM -framework Carbon -o ${JNIName} DMDirc-Apple.c -arch x86_64
53
+		if [ ! -e "${JNIName}" ]; then
54
+			echo "JNI Lib not found and failed to compile. Aborting."
55
+			exit 1;
56
+		fi;
57
+	else
58
+		echo "JNI Lib not found, unable to compile on this system. Aborting."
59
+		exit 1;
60
+	fi;
61
+fi;
62
+
47 63
 if [ "" = "${HDIUTIL}" ]; then
48 64
 	if [ "" = "${MKHFS}" -a "" = "${MKHFSPLUS}" ]; then
49 65
 		echo "This machine is unable to produce dmg images. Aborting."
@@ -280,6 +296,7 @@ EOF
280 296
 #	</dict>
281 297
 
282 298
 cp DMDirc.jar ${RESDIR}/Java/DMDirc.jar
299
+cp ${JNIName} ${RESDIR}/Java/${JNIName}
283 300
 
284 301
 #if [ -e "../common/installer.jar" ]; then
285 302
 #	ln -sf ../common/installer.jar ./installer.jar

+ 7
- 5
launcher/osx/DMDirc.sh Dosyayı Görüntüle

@@ -84,7 +84,8 @@ messagedialog() {
84 84
 	fi;
85 85
 }
86 86
 
87
-jar=`dirname $0`/../Resources/Java/DMDirc.jar
87
+jarDir=`dirname $0`/../Resources/Java/
88
+jar=${jarDir}DMDirc.jar
88 89
 launcherUpdater=${profiledir}/updateLauncher.sh
89 90
 echo "---------------------"
90 91
 echo "DMDirc - Open Source IRC Client"
@@ -215,8 +216,8 @@ else
215 216
 	echo "Failed!"
216 217
 	ERROR="Sorry, java is not installed on this machine.";
217 218
 	ERROR=${ERROR}"\n"
218
-	ERROR=${ERROR}"\nDMDirc requires a 1.6.0 compatible JVM, this is currently:";
219
-	ERROR=${ERROR}"\nonly availble as a Developer Preview from the Apple Developer site.";
219
+	ERROR=${ERROR}"\nDMDirc requires a 1.6.0 compatible JVM, this is currently";
220
+	ERROR=${ERROR}"only availble as a Developer Preview from the Apple Developer site.";
220 221
 	errordialog "Unable to launch dmdirc!" "${ERROR}";
221 222
 	exit 1;
222 223
 fi
@@ -232,8 +233,8 @@ if [ -e "${jar}" ]; then
232 233
 		ERROR="Sorry, the currently installed version of java is not compatible with";
233 234
 		ERROR=${ERROR}"\nDMDirc.";
234 235
 		ERROR=${ERROR}"\n";
235
-		ERROR=${ERROR}"\nDMDirc requires a 1.6.0 compatible JVM, this is currently:";
236
-		ERROR=${ERROR}"\nonly availble as a Developer Preview from the Apple Developer site.";
236
+		ERROR=${ERROR}"\nDMDirc requires a 1.6.0 compatible JVM, this is currently";
237
+		ERROR=${ERROR}"only availble as a Developer Preview from the Apple Developer site.";
237 238
 		errordialog "Unable to launch dmdirc!" "${ERROR}";
238 239
 		exit 1;
239 240
 	fi
@@ -242,6 +243,7 @@ if [ -e "${jar}" ]; then
242 243
 	# to be seen, and the shell script exits with the correct exit code.
243 244
 	
244 245
 	APPLEOPTS=""
246
+	APPLEOPTS="${APPLEOPTS} -Djava.library.path=${jarDir}"
245 247
 #	APPLEOPTS="${APPLEOPTS} -Dcom.apple.mrj.application.growbox.intrudes=false"
246 248
 #	APPLEOPTS="${APPLEOPTS} -Dcom.apple.mrj.application.live-resize=true"
247 249
 #	APPLEOPTS="${APPLEOPTS} -Dcom.apple.mrj.application.apple.menu.about.name=DMDirc"

+ 90
- 3
src/com/dmdirc/ui/swing/Apple.java Dosyayı Görüntüle

@@ -23,19 +23,31 @@
23 23
 package com.dmdirc.ui.swing;
24 24
 
25 25
 import com.dmdirc.Main;
26
+import com.dmdirc.actions.ActionManager;
27
+import com.dmdirc.actions.CoreActionType;
28
+import com.dmdirc.actions.interfaces.ActionType;
26 29
 import com.dmdirc.config.IdentityManager;
30
+import com.dmdirc.interfaces.ActionListener;
31
+import com.dmdirc.util.IrcAddress;
32
+import com.dmdirc.util.InvalidAddressException;
33
+
34
+import com.dmdirc.logger.ErrorLevel;
35
+import com.dmdirc.logger.Logger;
27 36
 
28 37
 import java.awt.event.ActionEvent;
38
+
29 39
 import java.lang.reflect.InvocationHandler;
30 40
 import java.lang.reflect.Method;
31 41
 import java.lang.reflect.Field;
32 42
 import java.lang.reflect.Proxy;
33 43
 import java.lang.reflect.InvocationTargetException;
34 44
 
45
+import java.util.ArrayList;
46
+
35 47
 /**
36 48
  * Integrate DMDirc with OS X better.
37 49
  */
38
-public final class Apple implements InvocationHandler {
50
+public final class Apple implements InvocationHandler, ActionListener {
39 51
 	/** ApplicationEvent */
40 52
 	private interface ApplicationEvent {
41 53
 		String getFilename();
@@ -60,6 +72,12 @@ public final class Apple implements InvocationHandler {
60 72
 	/** The MenuBar for the application */
61 73
 	private MenuBar menuBar = null;
62 74
 
75
+	/** Has the CLIENT_OPENED action been called? */
76
+	private volatile boolean clientOpened = false;
77
+	
78
+	/** Store any addresses that are opened before CLIENT_OPENED. */
79
+	private volatile ArrayList<IrcAddress> addresses = new ArrayList<IrcAddress>();
80
+
63 81
 	/**
64 82
 	 * Get the "Apple" instance.
65 83
 	 *
@@ -71,6 +89,25 @@ public final class Apple implements InvocationHandler {
71 89
 		}
72 90
 		return me;
73 91
 	}
92
+	
93
+	/**
94
+	 * Create the Apple class.
95
+	 * This attempts to:
96
+	 *   - load the JNI library
97
+	 *   - register the callback
98
+	 *   - register a CLIENT_OPENED listener
99
+	 */
100
+	private Apple() {
101
+		if (isApple()) {
102
+			try {
103
+				System.loadLibrary("DMDirc-Apple");
104
+				registerOpenURLCallback();
105
+				ActionManager.addListener(this, CoreActionType.CLIENT_OPENED);
106
+			} catch (UnsatisfiedLinkError ule) {
107
+				Logger.appError(ErrorLevel.MEDIUM, "Unable to load JNI library.", ule);
108
+			}
109
+		}
110
+	}
74 111
 
75 112
 	/**
76 113
 	 * Get the "Application" object
@@ -124,7 +161,6 @@ public final class Apple implements InvocationHandler {
124 161
 	 * @return true if we are running on OS X
125 162
 	 */
126 163
 	public static boolean isApple() {
127
-//		return (Main.getUI() instanceof SwingController && System.getProperty("os.name").startsWith("Mac OS"));
128 164
 		return (System.getProperty("mrj.version") != null);
129 165
 	}
130 166
 
@@ -147,7 +183,6 @@ public final class Apple implements InvocationHandler {
147 183
 		System.setProperty("apple.laf.useScreenMenuBar", "true");
148 184
 		System.setProperty("com.apple.mrj.application.growbox.intrudes", "false");
149 185
 		System.setProperty("com.apple.mrj.application.live-resize", "true");
150
-//		System.setProperty("com.apple.mrj.application.apple.menu.about.name", "DMDirc: " + Main.VERSION);
151 186
 		System.setProperty("com.apple.mrj.application.apple.menu.about.name", "DMDirc");
152 187
 	}
153 188
 	
@@ -209,6 +244,7 @@ public final class Apple implements InvocationHandler {
209 244
 	}
210 245
 	
211 246
 	/** {@inheritDoc} */
247
+	@Override
212 248
 	public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
213 249
 		if (!isApple()) { return null; }
214 250
 		
@@ -305,4 +341,55 @@ public final class Apple implements InvocationHandler {
305 341
 	 * @param event an ApplicationEvent object
306 342
 	 */
307 343
 	public void handleReopenApplication(final ApplicationEvent event) { }
344
+	
345
+	/** {@inheritDoc} */
346
+	@Override
347
+	public void processEvent(final ActionType type, final StringBuffer format, final Object... arguments) {
348
+		if (type == CoreActionType.CLIENT_OPENED) {
349
+			synchronized (addresses) {
350
+				clientOpened = true;
351
+				for (IrcAddress addr : addresses) {
352
+					addr.connect();
353
+				}
354
+				addresses.clear();
355
+			}
356
+		}
357
+	}
358
+
359
+	/**
360
+	 * Callback from JNI library.
361
+	 * If called before the client has finished opening, the URL will be added to
362
+	 * a list that will be connected to once the CLIENT_OPENED action is called.
363
+	 * Otherwise we connect right away.
364
+	 *
365
+	 * @param url The irc url to connect to.
366
+	 */
367
+	@SuppressWarnings("unused")
368
+	public void handleOpenURL(final String url) {
369
+		if (isApple()) {
370
+			try {
371
+				synchronized (addresses) {
372
+					final IrcAddress addr = new IrcAddress(url);
373
+					if (!clientOpened) {
374
+						addresses.add(addr);
375
+					} else {
376
+						// When the JNI callback is called there is no ContextClassLoader set.
377
+						// This causes an NPE in IconManager if no servers have been connected to yet
378
+						// This solves it.
379
+						if (Thread.currentThread().getContextClassLoader() == null) {
380
+							Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
381
+						}
382
+						addr.connect();
383
+					}
384
+				}
385
+			} catch (InvalidAddressException iae) { }
386
+		}
387
+	}
388
+
389
+	/**
390
+	 * Register the getURL Callback.
391
+	 *
392
+	 * @return 0 on success, 1 on failure.
393
+	 */
394
+	private synchronized final native int registerOpenURLCallback();
308 395
 }

Loading…
İptal
Kaydet