From 79416171c35aa4989d628e590c102146facf1c72 Mon Sep 17 00:00:00 2001 From: ntwigg Date: Tue, 26 Aug 2025 10:51:37 -0700 Subject: [PATCH 01/10] First draft of `DeepLinkBridge.m` --- .gitattributes | 1 + CLAUDE.md | 39 +++ build.gradle | 1 + .../common/swt/widgets/MacDeepLink.java | 76 ++++++ .../durian-swt-natives/DeepLinkBridge.dylib | Bin 0 -> 55288 bytes .../common/swt/widgets/MacDeepLink.java | 76 ++++++ .../durian-swt-natives/DeepLinkBridge.dylib | Bin 0 -> 25304 bytes .../resources/durian-swt-natives/placeholder | 0 .../resources/durian-swt-natives/placeholder | 0 .../resources/durian-swt-natives/placeholder | 0 .../resources/durian-swt-natives/placeholder | 0 natives/mac-deep-link/DeepLinkBridge.m | 253 ++++++++++++++++++ natives/mac-deep-link/clean-and-build.sh | 12 + natives/mac-deep-link/compile-one.sh | 76 ++++++ 14 files changed, 534 insertions(+) create mode 100644 CLAUDE.md create mode 100644 durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java create mode 100755 durian-swt.cocoa.macosx.aarch64/src/main/resources/durian-swt-natives/DeepLinkBridge.dylib create mode 100644 durian-swt.cocoa.macosx.x86_64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java create mode 100755 durian-swt.cocoa.macosx.x86_64/src/main/resources/durian-swt-natives/DeepLinkBridge.dylib create mode 100644 durian-swt.gtk.linux.x86/src/main/resources/durian-swt-natives/placeholder create mode 100644 durian-swt.gtk.linux.x86_64/src/main/resources/durian-swt-natives/placeholder create mode 100644 durian-swt.win32.win32.x86/src/main/resources/durian-swt-natives/placeholder create mode 100644 durian-swt.win32.win32.x86_64/src/main/resources/durian-swt-natives/placeholder create mode 100644 natives/mac-deep-link/DeepLinkBridge.m create mode 100755 natives/mac-deep-link/clean-and-build.sh create mode 100755 natives/mac-deep-link/compile-one.sh diff --git a/.gitattributes b/.gitattributes index dae0ec2b..8cf0ac98 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,4 @@ * text=auto eol=lf *.MF text eol=crlf *.jar binary +*.dylib binary \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..a2438d63 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,39 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Build Commands + +This is a Gradle-based Java/Kotlin project focused on SWT (Standard Widget Toolkit) utilities. Standard gradle tasks. + +### macOS-specific Requirements +- On macOS, SWT tests require the `-XstartOnFirstThread` JVM argument (automatically configured in build.gradle). + +## Project Architecture +### Multi-Module Structure +DurianSwt is organized as a multi-module Gradle project with platform-specific implementations: + +- **durian-swt.os**: Platform detection utilities (OS, Arch, SwtPlatform) - no SWT dependencies +- **durian-swt**: Main module with core SWT utilities and builders +- **platform-specific modules**: (durian-swt.cocoa.macosx.aarch64, durian-swt.cocoa.macosx.x86_64, durian-swt.gtk.linux.x86_64, durian-swt.win32.win32.x86_64) + +## Native Components + +### macOS Deep Link Support (`natives/mac-deep-link/`) + +Contains Objective-C code for handling deep links via a custom `diffplug://` protocol on macOS without breaking SWT: + +- **DeepLinkBridge.m**: JNI bridge that intercepts URL open events from macOS +- **compile-one.sh**: Compiles the native library for a specific architecture (x86_64 or arm64) +- **clean-and-build.sh**: Builds for both architectures and deploys to appropriate module resources + +To rebuild native libraries: +```bash +cd natives/mac-deep-link +./clean-and-build.sh # Builds for both architectures +# Or compile for specific architecture: +./compile-one.sh arm64 # Apple Silicon +./compile-one.sh x86_64 # Intel +``` + +The resulting `DeepLinkBridge.dylib` files are placed in the platform-specific modules under `src/main/resources/durian-swt-natives/`. diff --git a/build.gradle b/build.gradle index daa6f8c8..7474a7e4 100644 --- a/build.gradle +++ b/build.gradle @@ -69,6 +69,7 @@ subprojects { subProject -> } dependencies { api project(':durian-swt') + implementation "com.diffplug.durian:durian-core:$VER_DURIAN" } configurations.all { resolutionStrategy.eachDependency { DependencyResolveDetails details -> diff --git a/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java b/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java new file mode 100644 index 00000000..450480e0 --- /dev/null +++ b/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2025 DiffPlug + * + * 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 + * + * https://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. + */ +package com.diffplug.common.swt.widgets; + +import com.diffplug.common.base.Preconditions; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import org.jetbrains.annotations.Nullable; + +public class MacDeepLink { + private static volatile @Nullable Consumer urlHandler; + private static final AtomicReference<@Nullable List> backlogUrls = new AtomicReference<>(); + + static { + // Load the native library - try multiple strategies + String libPath = System.getProperty("durian-swt.library.path"); + if (libPath != null) { + System.load(libPath + "/durian-swt-natives/DeepLinkBridge.dylib"); + } else { + throw new IllegalArgumentException("You need to set 'durian-swt.library.path'"); + } + } + + public static void setURLHandler(Consumer handler) { + Preconditions.checkArgument(urlHandler == null, "URL handler can only be set once"); + urlHandler = handler; + } + + public static void applicationStartBeforeSwt() { + Preconditions.checkArgument(urlHandler != null, "Call `setURLHandler()` first"); + backlogUrls.set(new ArrayList<>()); + nativeBeforeSwt(); + } + + public static void applicationStartAfterSwt() { + Preconditions.checkArgument(backlogUrls.get() != null, "Call `applicationStartBeforeSwt()` first."); + nativeAfterSwt(); + var accumulatedBacklog = backlogUrls.getAndSet(null); + accumulatedBacklog.forEach(urlHandler); + } + + // Native method declarations - implemented in DeepLinkBridge.m + private static native void nativeBeforeSwt(); + + private static native void nativeAfterSwt(); + + /** + * Called from native code when a URL is received. + * This method is invoked on various threads by the native code. + * + * @param url The URL string received from the operating system + */ + public static void deliverURL(String url) { + var backlog = backlogUrls.get(); + if (backlog != null) { + backlog.add(url); + } else { + urlHandler.accept(url); + } + } +} diff --git a/durian-swt.cocoa.macosx.aarch64/src/main/resources/durian-swt-natives/DeepLinkBridge.dylib b/durian-swt.cocoa.macosx.aarch64/src/main/resources/durian-swt-natives/DeepLinkBridge.dylib new file mode 100755 index 0000000000000000000000000000000000000000..7295cb836da0a99c48dce5c5b2bb8f7c76abe753 GIT binary patch literal 55288 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 O|KRPP{P`&!-2Vrp=11cI literal 0 HcmV?d00001 diff --git a/durian-swt.cocoa.macosx.x86_64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java b/durian-swt.cocoa.macosx.x86_64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java new file mode 100644 index 00000000..61726cd7 --- /dev/null +++ b/durian-swt.cocoa.macosx.x86_64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2025 DiffPlug + * + * 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 + * + * https://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. + */ +package com.diffplug.common.swt.widgets; + +import com.diffplug.common.base.Preconditions; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import org.jetbrains.annotations.Nullable; + +public class MacDeepLink { + private static volatile @Nullable Consumer urlHandler; + private static final AtomicReference<@Nullable List> backlogUrls = new AtomicReference<>(); + + static { + // Load the native library - try multiple strategies + String libPath = System.getProperty("durian-swt.library.path"); + if (libPath != null) { + System.load(libPath + "/durian-swt-natives/DeepLinkBridge.dylib"); + } else { + throw new IllegalArgumentException("You need to set 'durian-swt.library.path'"); + } + } + + public static void setURLHandler(Consumer handler) { + Preconditions.checkArgument(urlHandler == null, "URL handler can only be set once"); + urlHandler = handler; + } + + public static void applicationStartBeforeSwt() { + Preconditions.checkArgument(urlHandler != null, "Call `setURLHandler()` first"); + backlogUrls.set(new ArrayList<>()); + nativeBeforeSwt(); + } + + public static void applicationStartAfterSwt() { + Preconditions.checkArgument(backlogUrls.get() != null, "Call `applicationStartBeforeSwt()` first."); + nativeAfterSwt(); + var accumulatedBacklog = backlogUrls.getAndSet(null); + accumulatedBacklog.forEach(urlHandler); + } + + // Native method declarations - implemented in DeepLinkBridge.m + private static native void nativeBeforeSwt(); + + private static native void nativeAfterSwt(); + + /** + * Called from native code when a URL is received. + * This method is invoked on various threads by the native code. + * + * @param url The URL string received from the operating system + */ + public static void deliverURL(String url) { + var backlog = backlogUrls.get(); + if (backlog != null) { + backlog.add(url); + } else { + urlHandler.accept(url); + } + } +} diff --git a/durian-swt.cocoa.macosx.x86_64/src/main/resources/durian-swt-natives/DeepLinkBridge.dylib b/durian-swt.cocoa.macosx.x86_64/src/main/resources/durian-swt-natives/DeepLinkBridge.dylib new file mode 100755 index 0000000000000000000000000000000000000000..d2089cffb103352d22e941533a0e1471dc04fdb9 GIT binary patch literal 25304 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 Ro=4=9>7kAMA_vWn{u?oJxYz&y literal 0 HcmV?d00001 diff --git a/durian-swt.gtk.linux.x86/src/main/resources/durian-swt-natives/placeholder b/durian-swt.gtk.linux.x86/src/main/resources/durian-swt-natives/placeholder new file mode 100644 index 00000000..e69de29b diff --git a/durian-swt.gtk.linux.x86_64/src/main/resources/durian-swt-natives/placeholder b/durian-swt.gtk.linux.x86_64/src/main/resources/durian-swt-natives/placeholder new file mode 100644 index 00000000..e69de29b diff --git a/durian-swt.win32.win32.x86/src/main/resources/durian-swt-natives/placeholder b/durian-swt.win32.win32.x86/src/main/resources/durian-swt-natives/placeholder new file mode 100644 index 00000000..e69de29b diff --git a/durian-swt.win32.win32.x86_64/src/main/resources/durian-swt-natives/placeholder b/durian-swt.win32.win32.x86_64/src/main/resources/durian-swt-natives/placeholder new file mode 100644 index 00000000..e69de29b diff --git a/natives/mac-deep-link/DeepLinkBridge.m b/natives/mac-deep-link/DeepLinkBridge.m new file mode 100644 index 00000000..8a788597 --- /dev/null +++ b/natives/mac-deep-link/DeepLinkBridge.m @@ -0,0 +1,253 @@ +// DeepLinkBridge.m - Handle deep links on macOS without breaking SWT +// Build as a small .dylib and load it early (see Java below). +#import +#import +#import + +@class DPDelegateProxy; // Forward declaration + +static JavaVM *gJVM = NULL; +static jclass gHandlerClass = NULL; // Global ref to MacDeepLink class +static jmethodID gDeliverMID = NULL; // Method ID for deliverURL(String) +static DPDelegateProxy *gDelegateProxy = NULL; // Strong ref to prevent deallocation + +#pragma mark - Helpers + +static void abortWithMessage(NSString *message) { + NSLog(@"[DeepLink] FATAL: %@", message); + fflush(stdout); // Ensure message is printed before crash + + // Most aggressive crash - direct null pointer dereference + // This causes SIGSEGV which is very hard to catch + volatile int *p = NULL; + *p = 42; + + // Fallbacks in case the above somehow doesn't work + __builtin_trap(); + abort(); +} + +#pragma mark - JNI bootstrap + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { + gJVM = vm; + NSLog(@"[DeepLink] JNI_OnLoad: JavaVM stored"); + return JNI_VERSION_1_6; +} + +JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) { + NSLog(@"[DeepLink] JNI_OnUnload: Cleaning up"); + + // Deregister Apple Event handler + [[NSAppleEventManager sharedAppleEventManager] + removeEventHandlerForEventClass:kInternetEventClass + andEventID:kAEGetURL]; + NSLog(@"[DeepLink] Removed Apple Event handler"); + + // Restore original delegate before releasing proxy + if (gDelegateProxy && NSApp) { + // Access the original delegate directly via ivar + Ivar ivar = class_getInstanceVariable(object_getClass(gDelegateProxy), "_realDelegate"); + id originalDelegate = object_getIvar(gDelegateProxy, ivar); + [NSApp setDelegate:originalDelegate]; + NSLog(@"[DeepLink] Restored original delegate"); + } + + // Clean up global reference + if (gHandlerClass) { + JNIEnv *env; + if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_6) == JNI_OK) { + (*env)->DeleteGlobalRef(env, gHandlerClass); + gHandlerClass = NULL; + NSLog(@"[DeepLink] Released global class reference"); + } + } + + // Clear cached values + gDeliverMID = NULL; + gJVM = NULL; + gDelegateProxy = NULL; // Now safe to release the proxy +} + +static JNIEnv* getEnv(BOOL *didAttach) { + *didAttach = NO; + if (!gJVM) return NULL; + JNIEnv *env = NULL; + jint rs = (*gJVM)->GetEnv(gJVM, (void **)&env, JNI_VERSION_1_6); + if (rs == JNI_EDETACHED) { + // Use daemon attachment for system threads so they don't block JVM shutdown + if ((*gJVM)->AttachCurrentThreadAsDaemon(gJVM, (void **)&env, NULL) != 0) { + return NULL; + } + *didAttach = YES; + } else if (rs != JNI_OK) { + return NULL; + } + return env; +} + +static void deliverToJava(NSString *s) { + NSLog(@"[DeepLink] deliverToJava called with URL: %@", s); + // These should never be null since we control registration timing + if (!gHandlerClass || !gDeliverMID) { + abortWithMessage(@"JNI handler not initialized - applicationStartBeforeSwt must be called first"); + } + + BOOL didAttach = NO; + JNIEnv *env = getEnv(&didAttach); + if (!env) { + abortWithMessage(@"Cannot get JNI environment - JVM may be shutting down"); + } + + const char *utf8 = s.UTF8String; + if (utf8) { + jstring jstr = (*env)->NewStringUTF(env, utf8); + if (jstr) { + NSLog(@"[DeepLink] Calling Java deliverURL with: %@", s); + (*env)->CallStaticVoidMethod(env, gHandlerClass, gDeliverMID, jstr); + if ((*env)->ExceptionCheck(env)) { + NSLog(@"[DeepLink] Java exception occurred!"); + (*env)->ExceptionDescribe(env); + (*env)->ExceptionClear(env); + } + (*env)->DeleteLocalRef(env, jstr); + } + } + if (didAttach) (*gJVM)->DetachCurrentThread(gJVM); +} + +#pragma mark - Apple Event handler + +// Object to handle Apple Events +@interface DeepLinkAppleEventHandler : NSObject ++ (instancetype)sharedHandler; +- (void)handleGetURL:(NSAppleEventDescriptor *)event withReply:(NSAppleEventDescriptor *)reply; +@end + +@implementation DeepLinkAppleEventHandler + ++ (instancetype)sharedHandler { + static DeepLinkAppleEventHandler *handler = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + handler = [[DeepLinkAppleEventHandler alloc] init]; + }); + return handler; +} + +- (void)handleGetURL:(NSAppleEventDescriptor *)event withReply:(NSAppleEventDescriptor *)reply { + NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; + NSLog(@"[DeepLink] Apple Event received URL: %@", urlString); + if (urlString.length) { + deliverToJava(urlString); + } +} + +@end + +// Install Apple Event handler when Java is ready +static void installEarlyAEHandler(void) { + @autoreleasepool { + NSLog(@"[DeepLink] Installing Apple Event handler"); + + // Register handler for kAEGetURL events + [[NSAppleEventManager sharedAppleEventManager] + setEventHandler:[DeepLinkAppleEventHandler sharedHandler] + andSelector:@selector(handleGetURL:withReply:) + forEventClass:kInternetEventClass + andEventID:kAEGetURL]; + + NSLog(@"[DeepLink] Apple Event handler installed"); + } +} + +#pragma mark - NSApplicationDelegate proxy + +// Dynamic proxy that intercepts application:openURLs: and forwards all other messages +@interface DPDelegateProxy : NSProxy { + id _realDelegate; +} +- (instancetype)initWithDelegate:(id)delegate; +- (id)realDelegate; // Getter to access original delegate for restoration +@end + +@implementation DPDelegateProxy + +- (instancetype)initWithDelegate:(id)delegate { + _realDelegate = delegate; + return self; +} + +- (id)realDelegate { + return _realDelegate; +} + +- (id)forwardingTargetForSelector:(SEL)sel { + // Fast-forward everything except our intercepted method + if (sel == @selector(application:openURLs:)) { + return nil; // We'll handle this ourselves + } + return _realDelegate; +} + +- (BOOL)respondsToSelector:(SEL)sel { + if (sel == @selector(application:openURLs:)) return YES; + return [_realDelegate respondsToSelector:sel]; +} + +- (void)application:(NSApplication *)app openURLs:(NSArray *)urls { + NSLog(@"[DeepLink] DPDelegateProxy application:openURLs: received %lu URLs", (unsigned long)urls.count); + for (NSURL *u in urls) { + if (!u) continue; + NSString *s = u.absoluteString; + NSLog(@"[DeepLink] DPDelegateProxy processing URL: %@", s); + if (s.length) deliverToJava(s); + } +} +@end + +#pragma mark - JNI exports + +// Java calls this early, before SWT initialization +JNIEXPORT void JNICALL Java_com_diffplug_common_swt_widgets_MacDeepLink_nativeBeforeSwt + (JNIEnv *env, jclass clazz) { + + NSLog(@"[DeepLink] nativeBeforeSwt called from Java"); + + // Cache class & method (global ref so it survives) + if (!gHandlerClass) { + gHandlerClass = (*env)->NewGlobalRef(env, clazz); + NSLog(@"[DeepLink] Cached Java class reference"); + } + if (!gDeliverMID) { + gDeliverMID = (*env)->GetStaticMethodID(env, gHandlerClass, "deliverURL", "(Ljava/lang/String;)V"); + if (!gDeliverMID) { + NSLog(@"[DeepLink] ERROR: Could not find deliverURL method!"); + return; + } + NSLog(@"[DeepLink] Cached deliverURL method ID"); + } + + // Now that JNI is ready, register with macOS for Apple Events + installEarlyAEHandler(); +} + +// Java calls this after SWT is initialized to install the delegate proxy +JNIEXPORT void JNICALL Java_com_diffplug_common_swt_widgets_MacDeepLink_nativeAfterSwt + (JNIEnv *env, jclass clazz) { + + NSLog(@"[DeepLink] nativeAfterSwt called from Java"); + + if (!NSApp) { + abortWithMessage(@"NSApp is nil! Make sure SWT Display is created first"); + } + + // Wrap the existing delegate with our proxy + id current = [NSApp delegate]; + NSLog(@"[DeepLink] Current NSApp delegate: %@", current); + + // Store proxy in static to prevent deallocation (NSApp.delegate is weak) + gDelegateProxy = [[DPDelegateProxy alloc] initWithDelegate:current]; + [NSApp setDelegate:(id)gDelegateProxy]; + NSLog(@"[DeepLink] Installed delegate proxy"); +} \ No newline at end of file diff --git a/natives/mac-deep-link/clean-and-build.sh b/natives/mac-deep-link/clean-and-build.sh new file mode 100755 index 00000000..c77de5a7 --- /dev/null +++ b/natives/mac-deep-link/clean-and-build.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +for arch in aarch64 x86_64; do + rm -rf ../../durian-swt.cocoa.macosx.${arch}/src/main/resources/durian-swt-natives + mkdir -p ../../durian-swt.cocoa.macosx.${arch}/src/main/resources/durian-swt-natives + if [ "$arch" = "aarch64" ]; then + ./compile-one.sh arm64 + else + ./compile-one.sh ${arch} + fi + mv DeepLinkBridge.dylib ../../durian-swt.cocoa.macosx.${arch}/src/main/resources/durian-swt-natives +done \ No newline at end of file diff --git a/natives/mac-deep-link/compile-one.sh b/natives/mac-deep-link/compile-one.sh new file mode 100755 index 00000000..15bf8e24 --- /dev/null +++ b/natives/mac-deep-link/compile-one.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +# DeepLinkBridge Compilation Script +# +# Usage: ./compile-one.sh +# architecture: x86_64 (Intel) or arm64 (Apple Silicon) +# +# This script compiles native Objective-C code for handling deep links on macOS. +# +# Prerequisites: +# - Xcode Command Line Tools +# - Java Development Kit (JDK) installed +# +# Output: +# Produces DeepLinkBridge.dylib, a macOS dynamic library that can be loaded by the JVM +# to handle URL open events from the operating system. +# +# The library provides JNI functions that: +# 1. JNI_OnLoad - Stores a reference to the JVM when the library is loaded +# 2. Java_com_diffplug_deeplink_MacDeepLink_installOpenURLHandler - Installs a handler for URL open events that calls back to Java +# +# The library should be loaded early in the application lifecycle before the UI event loop starts. + +set -e # Exit on error + +# Check for required architecture argument +if [ $# -ne 1 ]; then + echo "Error: Architecture argument required" + echo "Usage: $0 " + echo " x86_64 - Compile for Intel Macs" + echo " arm64 - Compile for Apple Silicon Macs" + exit 1 +fi + +ARCH=$1 + +# Validate architecture argument +if [ "$ARCH" != "x86_64" ] && [ "$ARCH" != "arm64" ]; then + echo "Error: Invalid architecture '$ARCH'" + echo "Valid architectures: x86_64, arm64" + exit 1 +fi + +echo "Compiling for architecture: $ARCH" + +echo "Checking for Java installation..." +if ! /usr/libexec/java_home >/dev/null 2>&1; then + echo "Error: Java not found. Please install a JDK." + echo "Run: /usr/libexec/java_home to verify Java installation" + exit 1 +fi + +echo "Java found at: $(/usr/libexec/java_home)" + +# Verify the JNI headers exist +echo "Verifying JNI headers..." +if [ ! -f "$(/usr/libexec/java_home)/include/jni.h" ]; then + echo "Error: JNI headers not found at $(/usr/libexec/java_home)/include/jni.h" + echo "Ensure you have a JDK installed (not just JRE)" + exit 1 +fi +echo "JNI headers found." + +# Compile the dynamic library +echo "Compiling DeepLinkBridge.dylib for $ARCH..." +clang -arch $ARCH -dynamiclib \ + -I"$(/usr/libexec/java_home)/include" \ + -I"$(/usr/libexec/java_home)/include/darwin" \ + -framework Cocoa \ + -o DeepLinkBridge.dylib \ + DeepLinkBridge.m + +echo "Success! DeepLinkBridge.dylib has been created for $ARCH architecture." +echo "" +echo "Verifying architecture:" +file DeepLinkBridge.dylib \ No newline at end of file From 81a552f4a7acd519afd324a93e83a7f7cf81313e Mon Sep 17 00:00:00 2001 From: ntwigg Date: Thu, 28 Aug 2025 15:14:10 -0700 Subject: [PATCH 02/10] Don't log URLs because we don't want to leak user data. --- natives/mac-deep-link/DeepLinkBridge.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/natives/mac-deep-link/DeepLinkBridge.m b/natives/mac-deep-link/DeepLinkBridge.m index 8a788597..2809fa20 100644 --- a/natives/mac-deep-link/DeepLinkBridge.m +++ b/natives/mac-deep-link/DeepLinkBridge.m @@ -87,7 +87,7 @@ JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) { } static void deliverToJava(NSString *s) { - NSLog(@"[DeepLink] deliverToJava called with URL: %@", s); + NSLog(@"[DeepLink] deliverToJava called with URL"); // These should never be null since we control registration timing if (!gHandlerClass || !gDeliverMID) { abortWithMessage(@"JNI handler not initialized - applicationStartBeforeSwt must be called first"); @@ -103,7 +103,7 @@ static void deliverToJava(NSString *s) { if (utf8) { jstring jstr = (*env)->NewStringUTF(env, utf8); if (jstr) { - NSLog(@"[DeepLink] Calling Java deliverURL with: %@", s); + NSLog(@"[DeepLink] Calling Java deliverURL"); (*env)->CallStaticVoidMethod(env, gHandlerClass, gDeliverMID, jstr); if ((*env)->ExceptionCheck(env)) { NSLog(@"[DeepLink] Java exception occurred!"); @@ -137,7 +137,7 @@ + (instancetype)sharedHandler { - (void)handleGetURL:(NSAppleEventDescriptor *)event withReply:(NSAppleEventDescriptor *)reply { NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; - NSLog(@"[DeepLink] Apple Event received URL: %@", urlString); + NSLog(@"[DeepLink] Apple Event received URL"); if (urlString.length) { deliverToJava(urlString); } @@ -200,7 +200,7 @@ - (void)application:(NSApplication *)app openURLs:(NSArray *)urls { for (NSURL *u in urls) { if (!u) continue; NSString *s = u.absoluteString; - NSLog(@"[DeepLink] DPDelegateProxy processing URL: %@", s); + NSLog(@"[DeepLink] DPDelegateProxy processing URL"); if (s.length) deliverToJava(s); } } From 294c6e9f01e99ab3abf2b4939f02a44ff480bee9 Mon Sep 17 00:00:00 2001 From: ntwigg Date: Thu, 28 Aug 2025 15:29:51 -0700 Subject: [PATCH 03/10] Switch to modern logging. --- natives/mac-deep-link/DeepLinkBridge.m | 53 +++++++++++++++----------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/natives/mac-deep-link/DeepLinkBridge.m b/natives/mac-deep-link/DeepLinkBridge.m index 2809fa20..aa03df35 100644 --- a/natives/mac-deep-link/DeepLinkBridge.m +++ b/natives/mac-deep-link/DeepLinkBridge.m @@ -3,6 +3,7 @@ #import #import #import +#import @class DPDelegateProxy; // Forward declaration @@ -13,9 +14,17 @@ #pragma mark - Helpers +static os_log_t getLog(void) { + static os_log_t log = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + log = os_log_create("com.diffplug.deeplink", "DeepLinkBridge"); + }); + return log; +} + static void abortWithMessage(NSString *message) { - NSLog(@"[DeepLink] FATAL: %@", message); - fflush(stdout); // Ensure message is printed before crash + os_log_fault(getLog(), "FATAL: %{public}@", message); // Most aggressive crash - direct null pointer dereference // This causes SIGSEGV which is very hard to catch @@ -31,18 +40,18 @@ static void abortWithMessage(NSString *message) { JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { gJVM = vm; - NSLog(@"[DeepLink] JNI_OnLoad: JavaVM stored"); + os_log_info(getLog(), "JNI_OnLoad: JavaVM stored"); return JNI_VERSION_1_6; } JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) { - NSLog(@"[DeepLink] JNI_OnUnload: Cleaning up"); + os_log_info(getLog(), "JNI_OnUnload: Cleaning up"); // Deregister Apple Event handler [[NSAppleEventManager sharedAppleEventManager] removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL]; - NSLog(@"[DeepLink] Removed Apple Event handler"); + os_log_info(getLog(), "Removed Apple Event handler"); // Restore original delegate before releasing proxy if (gDelegateProxy && NSApp) { @@ -50,7 +59,7 @@ JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) { Ivar ivar = class_getInstanceVariable(object_getClass(gDelegateProxy), "_realDelegate"); id originalDelegate = object_getIvar(gDelegateProxy, ivar); [NSApp setDelegate:originalDelegate]; - NSLog(@"[DeepLink] Restored original delegate"); + os_log_info(getLog(), "Restored original delegate"); } // Clean up global reference @@ -59,7 +68,7 @@ JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) { if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_6) == JNI_OK) { (*env)->DeleteGlobalRef(env, gHandlerClass); gHandlerClass = NULL; - NSLog(@"[DeepLink] Released global class reference"); + os_log_info(getLog(), "Released global class reference"); } } @@ -87,7 +96,7 @@ JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) { } static void deliverToJava(NSString *s) { - NSLog(@"[DeepLink] deliverToJava called with URL"); + os_log_debug(getLog(), "deliverToJava called"); // These should never be null since we control registration timing if (!gHandlerClass || !gDeliverMID) { abortWithMessage(@"JNI handler not initialized - applicationStartBeforeSwt must be called first"); @@ -103,10 +112,10 @@ static void deliverToJava(NSString *s) { if (utf8) { jstring jstr = (*env)->NewStringUTF(env, utf8); if (jstr) { - NSLog(@"[DeepLink] Calling Java deliverURL"); + os_log_debug(getLog(), "Calling Java deliverURL"); (*env)->CallStaticVoidMethod(env, gHandlerClass, gDeliverMID, jstr); if ((*env)->ExceptionCheck(env)) { - NSLog(@"[DeepLink] Java exception occurred!"); + os_log_error(getLog(), "Java exception occurred"); (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); } @@ -137,7 +146,7 @@ + (instancetype)sharedHandler { - (void)handleGetURL:(NSAppleEventDescriptor *)event withReply:(NSAppleEventDescriptor *)reply { NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; - NSLog(@"[DeepLink] Apple Event received URL"); + os_log_debug(getLog(), "Apple Event received"); if (urlString.length) { deliverToJava(urlString); } @@ -148,7 +157,7 @@ - (void)handleGetURL:(NSAppleEventDescriptor *)event withReply:(NSAppleEventDesc // Install Apple Event handler when Java is ready static void installEarlyAEHandler(void) { @autoreleasepool { - NSLog(@"[DeepLink] Installing Apple Event handler"); + os_log_info(getLog(), "Installing Apple Event handler"); // Register handler for kAEGetURL events [[NSAppleEventManager sharedAppleEventManager] @@ -157,7 +166,7 @@ static void installEarlyAEHandler(void) { forEventClass:kInternetEventClass andEventID:kAEGetURL]; - NSLog(@"[DeepLink] Apple Event handler installed"); + os_log_info(getLog(), "Apple Event handler installed"); } } @@ -196,11 +205,11 @@ - (BOOL)respondsToSelector:(SEL)sel { } - (void)application:(NSApplication *)app openURLs:(NSArray *)urls { - NSLog(@"[DeepLink] DPDelegateProxy application:openURLs: received %lu URLs", (unsigned long)urls.count); + os_log_debug(getLog(), "DPDelegateProxy received %lu URL(s)", (unsigned long)urls.count); for (NSURL *u in urls) { if (!u) continue; NSString *s = u.absoluteString; - NSLog(@"[DeepLink] DPDelegateProxy processing URL"); + os_log_debug(getLog(), "Processing URL"); if (s.length) deliverToJava(s); } } @@ -212,20 +221,20 @@ - (void)application:(NSApplication *)app openURLs:(NSArray *)urls { JNIEXPORT void JNICALL Java_com_diffplug_common_swt_widgets_MacDeepLink_nativeBeforeSwt (JNIEnv *env, jclass clazz) { - NSLog(@"[DeepLink] nativeBeforeSwt called from Java"); + os_log_info(getLog(), "nativeBeforeSwt called from Java"); // Cache class & method (global ref so it survives) if (!gHandlerClass) { gHandlerClass = (*env)->NewGlobalRef(env, clazz); - NSLog(@"[DeepLink] Cached Java class reference"); + os_log_debug(getLog(), "Cached Java class reference"); } if (!gDeliverMID) { gDeliverMID = (*env)->GetStaticMethodID(env, gHandlerClass, "deliverURL", "(Ljava/lang/String;)V"); if (!gDeliverMID) { - NSLog(@"[DeepLink] ERROR: Could not find deliverURL method!"); + os_log_error(getLog(), "Could not find deliverURL method"); return; } - NSLog(@"[DeepLink] Cached deliverURL method ID"); + os_log_debug(getLog(), "Cached deliverURL method ID"); } // Now that JNI is ready, register with macOS for Apple Events @@ -236,7 +245,7 @@ - (void)application:(NSApplication *)app openURLs:(NSArray *)urls { JNIEXPORT void JNICALL Java_com_diffplug_common_swt_widgets_MacDeepLink_nativeAfterSwt (JNIEnv *env, jclass clazz) { - NSLog(@"[DeepLink] nativeAfterSwt called from Java"); + os_log_info(getLog(), "nativeAfterSwt called from Java"); if (!NSApp) { abortWithMessage(@"NSApp is nil! Make sure SWT Display is created first"); @@ -244,10 +253,10 @@ - (void)application:(NSApplication *)app openURLs:(NSArray *)urls { // Wrap the existing delegate with our proxy id current = [NSApp delegate]; - NSLog(@"[DeepLink] Current NSApp delegate: %@", current); + os_log_debug(getLog(), "Current NSApp delegate: %{public}@", NSStringFromClass([current class])); // Store proxy in static to prevent deallocation (NSApp.delegate is weak) gDelegateProxy = [[DPDelegateProxy alloc] initWithDelegate:current]; [NSApp setDelegate:(id)gDelegateProxy]; - NSLog(@"[DeepLink] Installed delegate proxy"); + os_log_info(getLog(), "Installed delegate proxy"); } \ No newline at end of file From 17b1266d26ce2b11b5d3f31299e6a7ab8705fa17 Mon Sep 17 00:00:00 2001 From: ntwigg Date: Thu, 28 Aug 2025 15:34:16 -0700 Subject: [PATCH 04/10] Less aggressive error reporting. --- natives/mac-deep-link/DeepLinkBridge.m | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/natives/mac-deep-link/DeepLinkBridge.m b/natives/mac-deep-link/DeepLinkBridge.m index aa03df35..adb7d345 100644 --- a/natives/mac-deep-link/DeepLinkBridge.m +++ b/natives/mac-deep-link/DeepLinkBridge.m @@ -28,12 +28,10 @@ static void abortWithMessage(NSString *message) { // Most aggressive crash - direct null pointer dereference // This causes SIGSEGV which is very hard to catch - volatile int *p = NULL; - *p = 42; - - // Fallbacks in case the above somehow doesn't work - __builtin_trap(); - abort(); + [[NSNotificationCenter defaultCenter] + postNotificationName:@"DiffPlug diffplug:// protocol error" + object:nil + userInfo:@{@"error": message}]; } #pragma mark - JNI bootstrap From c6fa0159b34898b3c655c223064f2dd86706c827 Mon Sep 17 00:00:00 2001 From: ntwigg Date: Thu, 28 Aug 2025 16:02:13 -0700 Subject: [PATCH 05/10] Refactor MacDeepLink to be more easier to use.. --- .../common/swt/widgets/MacDeepLink.java | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java b/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java index 450480e0..d719252e 100644 --- a/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java +++ b/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java @@ -17,14 +17,18 @@ import com.diffplug.common.base.Preconditions; import java.util.ArrayList; -import java.util.List; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import org.jetbrains.annotations.Nullable; +/** + * - immediately on app startup, call `MacDeepLink.startCapturingBeforeSwt()` + * - once SWT has initialized, call `MacDeepLink.swtHasInitializedBeginReceiving(Consumer)` + * + * That's all! Don't do anything else. + */ public class MacDeepLink { - private static volatile @Nullable Consumer urlHandler; - private static final AtomicReference<@Nullable List> backlogUrls = new AtomicReference<>(); + private static final AtomicReference<@Nullable Object> state = new AtomicReference<>(); static { // Load the native library - try multiple strategies @@ -36,22 +40,19 @@ public class MacDeepLink { } } - public static void setURLHandler(Consumer handler) { - Preconditions.checkArgument(urlHandler == null, "URL handler can only be set once"); - urlHandler = handler; - } - - public static void applicationStartBeforeSwt() { - Preconditions.checkArgument(urlHandler != null, "Call `setURLHandler()` first"); - backlogUrls.set(new ArrayList<>()); + public static void startCapturingBeforeSwt() { + var was = state.getAndSet(new ArrayList<>()); + Preconditions.checkArgument(was == null, "`startCapturingBeforeSwt() should be called first`"); nativeBeforeSwt(); } - public static void applicationStartAfterSwt() { - Preconditions.checkArgument(backlogUrls.get() != null, "Call `applicationStartBeforeSwt()` first."); + public static void swtHasInitializedBeginReceiving(Consumer handler) { + var was = state.getAndSet(handler); + Preconditions.checkArgument(was instanceof ArrayList, "Call `applicationStartBeforeSwt()` first."); + + var backlog = (ArrayList) was; + backlog.forEach(handler); nativeAfterSwt(); - var accumulatedBacklog = backlogUrls.getAndSet(null); - accumulatedBacklog.forEach(urlHandler); } // Native method declarations - implemented in DeepLinkBridge.m @@ -66,11 +67,13 @@ public static void applicationStartAfterSwt() { * @param url The URL string received from the operating system */ public static void deliverURL(String url) { - var backlog = backlogUrls.get(); - if (backlog != null) { - backlog.add(url); + var was = state.get(); + if (was instanceof Consumer) { + ((Consumer) was).accept(url); + } else if (was instanceof ArrayList) { + ((ArrayList) was).add(url); } else { - urlHandler.accept(url); + throw new IllegalStateException("Expected Consumer or ArrayList, was " + was); } } } From f26d30eb2c3aa0be64c3f12a4a23a6bcfb243e5e Mon Sep 17 00:00:00 2001 From: ntwigg Date: Thu, 28 Aug 2025 16:30:24 -0700 Subject: [PATCH 06/10] Better docs. --- .../diffplug/common/swt/widgets/MacDeepLink.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java b/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java index d719252e..977b5319 100644 --- a/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java +++ b/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java @@ -16,6 +16,7 @@ package com.diffplug.common.swt.widgets; import com.diffplug.common.base.Preconditions; +import com.diffplug.common.swt.SwtMisc; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; @@ -24,34 +25,40 @@ /** * - immediately on app startup, call `MacDeepLink.startCapturingBeforeSwt()` * - once SWT has initialized, call `MacDeepLink.swtHasInitializedBeginReceiving(Consumer)` + * - all urls which were captured before SWT initialized will be passed immediately (on the SWT thread) * * That's all! Don't do anything else. */ public class MacDeepLink { + /** + * state transitions are: + * - `null` on startup + * - `startCapturingBeforeSwt()` transitions to an `ArrayList`, backlog urls get added to it + * - `swtHasInitializedBeginReceiving()` transitions to a `Consumer`, all new urls go there + */ private static final AtomicReference<@Nullable Object> state = new AtomicReference<>(); - static { - // Load the native library - try multiple strategies + public static void startCapturingBeforeSwt() { String libPath = System.getProperty("durian-swt.library.path"); if (libPath != null) { System.load(libPath + "/durian-swt-natives/DeepLinkBridge.dylib"); } else { throw new IllegalArgumentException("You need to set 'durian-swt.library.path'"); } - } - public static void startCapturingBeforeSwt() { var was = state.getAndSet(new ArrayList<>()); Preconditions.checkArgument(was == null, "`startCapturingBeforeSwt() should be called first`"); nativeBeforeSwt(); } public static void swtHasInitializedBeginReceiving(Consumer handler) { + SwtMisc.assertUI(); var was = state.getAndSet(handler); Preconditions.checkArgument(was instanceof ArrayList, "Call `applicationStartBeforeSwt()` first."); var backlog = (ArrayList) was; backlog.forEach(handler); + nativeAfterSwt(); } From 097523fcc50805e0b5f055214ddd9f667b8a2600 Mon Sep 17 00:00:00 2001 From: ntwigg Date: Thu, 28 Aug 2025 16:32:37 -0700 Subject: [PATCH 07/10] Migrate `MacDeepLink` out of the widgets package. --- .../com/diffplug/common/swt/{widgets => }/MacDeepLink.java | 3 +-- .../com/diffplug/common/swt/{widgets => }/MacDeepLink.java | 2 +- natives/mac-deep-link/DeepLinkBridge.m | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) rename durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/{widgets => }/MacDeepLink.java (97%) rename durian-swt.cocoa.macosx.x86_64/src/main/java/com/diffplug/common/swt/{widgets => }/MacDeepLink.java (98%) diff --git a/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java b/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/MacDeepLink.java similarity index 97% rename from durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java rename to durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/MacDeepLink.java index 977b5319..9c6cd21d 100644 --- a/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java +++ b/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/MacDeepLink.java @@ -13,10 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.diffplug.common.swt.widgets; +package com.diffplug.common.swt; import com.diffplug.common.base.Preconditions; -import com.diffplug.common.swt.SwtMisc; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; diff --git a/durian-swt.cocoa.macosx.x86_64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java b/durian-swt.cocoa.macosx.x86_64/src/main/java/com/diffplug/common/swt/MacDeepLink.java similarity index 98% rename from durian-swt.cocoa.macosx.x86_64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java rename to durian-swt.cocoa.macosx.x86_64/src/main/java/com/diffplug/common/swt/MacDeepLink.java index 61726cd7..72b4208f 100644 --- a/durian-swt.cocoa.macosx.x86_64/src/main/java/com/diffplug/common/swt/widgets/MacDeepLink.java +++ b/durian-swt.cocoa.macosx.x86_64/src/main/java/com/diffplug/common/swt/MacDeepLink.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.diffplug.common.swt.widgets; +package com.diffplug.common.swt; import com.diffplug.common.base.Preconditions; import java.util.ArrayList; diff --git a/natives/mac-deep-link/DeepLinkBridge.m b/natives/mac-deep-link/DeepLinkBridge.m index adb7d345..d59ec517 100644 --- a/natives/mac-deep-link/DeepLinkBridge.m +++ b/natives/mac-deep-link/DeepLinkBridge.m @@ -216,7 +216,7 @@ - (void)application:(NSApplication *)app openURLs:(NSArray *)urls { #pragma mark - JNI exports // Java calls this early, before SWT initialization -JNIEXPORT void JNICALL Java_com_diffplug_common_swt_widgets_MacDeepLink_nativeBeforeSwt +JNIEXPORT void JNICALL Java_com_diffplug_common_swt_MacDeepLink_nativeBeforeSwt (JNIEnv *env, jclass clazz) { os_log_info(getLog(), "nativeBeforeSwt called from Java"); @@ -240,7 +240,7 @@ - (void)application:(NSApplication *)app openURLs:(NSArray *)urls { } // Java calls this after SWT is initialized to install the delegate proxy -JNIEXPORT void JNICALL Java_com_diffplug_common_swt_widgets_MacDeepLink_nativeAfterSwt +JNIEXPORT void JNICALL Java_com_diffplug_common_swt_MacDeepLink_nativeAfterSwt (JNIEnv *env, jclass clazz) { os_log_info(getLog(), "nativeAfterSwt called from Java"); From c0b3a4fb8a34552c0a6bc24887561f3dc75386af Mon Sep 17 00:00:00 2001 From: ntwigg Date: Thu, 28 Aug 2025 16:39:05 -0700 Subject: [PATCH 08/10] deliverURL -> __internal_deliverUrl --- .../com/diffplug/common/swt/MacDeepLink.java | 2 +- .../durian-swt-natives/DeepLinkBridge.dylib | Bin 55288 -> 56248 bytes .../durian-swt-natives/DeepLinkBridge.dylib | Bin 25304 -> 30176 bytes natives/mac-deep-link/DeepLinkBridge.m | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/MacDeepLink.java b/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/MacDeepLink.java index 9c6cd21d..e7fc6fb6 100644 --- a/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/MacDeepLink.java +++ b/durian-swt.cocoa.macosx.aarch64/src/main/java/com/diffplug/common/swt/MacDeepLink.java @@ -72,7 +72,7 @@ public static void swtHasInitializedBeginReceiving(Consumer handler) { * * @param url The URL string received from the operating system */ - public static void deliverURL(String url) { + public static void __internal_deliverUrl(String url) { var was = state.get(); if (was instanceof Consumer) { ((Consumer) was).accept(url); diff --git a/durian-swt.cocoa.macosx.aarch64/src/main/resources/durian-swt-natives/DeepLinkBridge.dylib b/durian-swt.cocoa.macosx.aarch64/src/main/resources/durian-swt-natives/DeepLinkBridge.dylib index 7295cb836da0a99c48dce5c5b2bb8f7c76abe753..b14dd7baa61bf4ab83ffc59b1d59a8a84f5ea6bd 100755 GIT binary patch literal 56248 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 H<#qpmzk?tF literal 55288 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 O|KRPP{P`&!-2Vrp=11cI diff --git a/durian-swt.cocoa.macosx.x86_64/src/main/resources/durian-swt-natives/DeepLinkBridge.dylib b/durian-swt.cocoa.macosx.x86_64/src/main/resources/durian-swt-natives/DeepLinkBridge.dylib index d2089cffb103352d22e941533a0e1471dc04fdb9..0aad9a1d3bc066108efabd32f82fddd1d1328fb1 100755 GIT binary patch literal 30176 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

iQ7iQOUm&@O=U=2OJmJ0oX6_C4jBE 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 Ro=4=9>7kAMA_vWn{u?oJxYz&y diff --git a/natives/mac-deep-link/DeepLinkBridge.m b/natives/mac-deep-link/DeepLinkBridge.m index d59ec517..37d39809 100644 --- a/natives/mac-deep-link/DeepLinkBridge.m +++ b/natives/mac-deep-link/DeepLinkBridge.m @@ -227,7 +227,7 @@ - (void)application:(NSApplication *)app openURLs:(NSArray *)urls { os_log_debug(getLog(), "Cached Java class reference"); } if (!gDeliverMID) { - gDeliverMID = (*env)->GetStaticMethodID(env, gHandlerClass, "deliverURL", "(Ljava/lang/String;)V"); + gDeliverMID = (*env)->GetStaticMethodID(env, gHandlerClass, "__internal_deliverUrl", "(Ljava/lang/String;)V"); if (!gDeliverMID) { os_log_error(getLog(), "Could not find deliverURL method"); return; From 8a6612cae27f522cb6fb771bd295db351bf283be Mon Sep 17 00:00:00 2001 From: ntwigg Date: Thu, 28 Aug 2025 16:43:37 -0700 Subject: [PATCH 09/10] Update changelog. --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 0f9a3fb5..3a3dff96 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # DurianSwt releases ## [Unreleased] +### Added +- `MacDeepLink` class and dylibs for supporting deep links on modern versions of macOS. ## [5.1.0] - 2025-08-21 ### Added From 88da585f1d0bd7221584b276a06a6fb0abaeb654 Mon Sep 17 00:00:00 2001 From: ntwigg Date: Thu, 28 Aug 2025 16:53:39 -0700 Subject: [PATCH 10/10] Bring x86_64 in sync with aarch64 --- .../com/diffplug/common/swt/MacDeepLink.java | 55 +++++++++++-------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/durian-swt.cocoa.macosx.x86_64/src/main/java/com/diffplug/common/swt/MacDeepLink.java b/durian-swt.cocoa.macosx.x86_64/src/main/java/com/diffplug/common/swt/MacDeepLink.java index 72b4208f..510b64c7 100644 --- a/durian-swt.cocoa.macosx.x86_64/src/main/java/com/diffplug/common/swt/MacDeepLink.java +++ b/durian-swt.cocoa.macosx.x86_64/src/main/java/com/diffplug/common/swt/MacDeepLink.java @@ -17,41 +17,48 @@ import com.diffplug.common.base.Preconditions; import java.util.ArrayList; -import java.util.List; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import org.jetbrains.annotations.Nullable; +/** + * - immediately on app startup, call `MacDeepLink.startCapturingBeforeSwt()` + * - once SWT has initialized, call `MacDeepLink.swtHasInitializedBeginReceiving(Consumer)` + * - all urls which were captured before SWT initialized will be passed immediately (on the SWT thread) + * + * That's all! Don't do anything else. + */ public class MacDeepLink { - private static volatile @Nullable Consumer urlHandler; - private static final AtomicReference<@Nullable List> backlogUrls = new AtomicReference<>(); + /** + * state transitions are: + * - `null` on startup + * - `startCapturingBeforeSwt()` transitions to an `ArrayList`, backlog urls get added to it + * - `swtHasInitializedBeginReceiving()` transitions to a `Consumer`, all new urls go there + */ + private static final AtomicReference<@Nullable Object> state = new AtomicReference<>(); - static { - // Load the native library - try multiple strategies + public static void startCapturingBeforeSwt() { String libPath = System.getProperty("durian-swt.library.path"); if (libPath != null) { System.load(libPath + "/durian-swt-natives/DeepLinkBridge.dylib"); } else { throw new IllegalArgumentException("You need to set 'durian-swt.library.path'"); } - } - public static void setURLHandler(Consumer handler) { - Preconditions.checkArgument(urlHandler == null, "URL handler can only be set once"); - urlHandler = handler; - } - - public static void applicationStartBeforeSwt() { - Preconditions.checkArgument(urlHandler != null, "Call `setURLHandler()` first"); - backlogUrls.set(new ArrayList<>()); + var was = state.getAndSet(new ArrayList<>()); + Preconditions.checkArgument(was == null, "`startCapturingBeforeSwt() should be called first`"); nativeBeforeSwt(); } - public static void applicationStartAfterSwt() { - Preconditions.checkArgument(backlogUrls.get() != null, "Call `applicationStartBeforeSwt()` first."); + public static void swtHasInitializedBeginReceiving(Consumer handler) { + SwtMisc.assertUI(); + var was = state.getAndSet(handler); + Preconditions.checkArgument(was instanceof ArrayList, "Call `applicationStartBeforeSwt()` first."); + + var backlog = (ArrayList) was; + backlog.forEach(handler); + nativeAfterSwt(); - var accumulatedBacklog = backlogUrls.getAndSet(null); - accumulatedBacklog.forEach(urlHandler); } // Native method declarations - implemented in DeepLinkBridge.m @@ -65,12 +72,14 @@ public static void applicationStartAfterSwt() { * * @param url The URL string received from the operating system */ - public static void deliverURL(String url) { - var backlog = backlogUrls.get(); - if (backlog != null) { - backlog.add(url); + public static void __internal_deliverUrl(String url) { + var was = state.get(); + if (was instanceof Consumer) { + ((Consumer) was).accept(url); + } else if (was instanceof ArrayList) { + ((ArrayList) was).add(url); } else { - urlHandler.accept(url); + throw new IllegalStateException("Expected Consumer or ArrayList, was " + was); } } }