diff --git a/README.md b/README.md
index 86b0bd2..e9b168d 100644
--- a/README.md
+++ b/README.md
@@ -96,6 +96,8 @@ implementation of Objective-C interfaces in Java.
* separate same parts of jna-platform (like jna-platform-extended)
* deprecate rococoa-contrib
* ~~selector and java method binding for notification~~
+* exception in callback method cannot be shown as reason, shown as "Exception calling method for selector foo:"
+ * `OCInvocationCallbacks.java:170`
----
diff --git a/rococoa-contrib/src/main/java/org/rococoa/cocoa/coregraphics/RococaRobot.java b/rococoa-contrib/src/main/java/org/rococoa/cocoa/coregraphics/RococaRobot.java
deleted file mode 100644
index 9bad78d..0000000
--- a/rococoa-contrib/src/main/java/org/rococoa/cocoa/coregraphics/RococaRobot.java
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (c) 2024 by Naohide Sano, All rights reserved.
- *
- * Programmed by Naohide Sano
- */
-
-package org.rococoa.cocoa.coregraphics;
-
-import java.awt.MouseInfo;
-import java.awt.Point;
-
-import com.sun.jna.Pointer;
-import org.rococoa.cocoa.corefoundation.CoreFoundation;
-
-import static org.rococoa.carbon.CarbonCoreLibrary.kVK_Command;
-import static org.rococoa.carbon.CarbonCoreLibrary.kVK_Control;
-import static org.rococoa.carbon.CarbonCoreLibrary.kVK_Option;
-import static org.rococoa.carbon.CarbonCoreLibrary.kVK_Shift;
-import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventFlagMaskAlternate;
-import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventFlagMaskCommand;
-import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventFlagMaskControl;
-import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventFlagMaskShift;
-import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventLeftMouseDown;
-import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventLeftMouseUp;
-import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventMouseMoved;
-import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventRightMouseDown;
-import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventRightMouseUp;
-import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventScrollWheel;
-import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGEventSourceStateHIDSystemState;
-import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGHIDEventTap;
-import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGMouseEventDeltaX;
-import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGMouseEventDeltaY;
-import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.kCGScrollEventUnitPixel;
-import static org.rococoa.cocoa.coregraphics.CoreGraphicsLibrary.library;
-
-
-/**
- * RococaRobot. like {@link java.awt.Robot}.
- *
- * @author Naohide Sano (nsano)
- * @version 0.00 2024-03-22 nsano initial version
- */
-public class RococaRobot {
-
- /** HID event source */
- private final Pointer /* CGEventSourceRef */ src = library.CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
-
- /** Constructs a Robot object. */
- public RococaRobot() {
- Runtime.getRuntime().addShutdownHook(new Thread(() -> CoreFoundation.library.CFRelease(src)));
-
- Point p = MouseInfo.getPointerInfo().getLocation();
- prev = new CGPoint(p.x, p.y);
- }
-
- /** */
- private boolean command;
- /** */
- private boolean option;
- /** */
- private boolean control;
- /** */
- private boolean shift;
-
- /**
- * Presses a given key. The key should be released using the keyRelease method.
- * @param code get by karabiner-eventviewer etc.
- */
- public void keyPress(int code) {
- if (code == kVK_Command) {
- command = true;
- } else if (code == kVK_Option) {
- option = true;
- } else if (code == kVK_Control) {
- control = true;
- } else if (code == kVK_Shift) {
- shift = true;
- } else {
- Pointer /* CGEventRef */ event = library.CGEventCreateKeyboardEvent(src, (char) code, true);
-
- long flags = 0;
- if (command) flags |= kCGEventFlagMaskCommand;
- if (option) flags |= kCGEventFlagMaskAlternate;
- if (control) flags |= kCGEventFlagMaskControl;
- if (shift) flags |= kCGEventFlagMaskShift;
- library.CGEventSetFlags(event, flags);
-
- library.CGEventPost(kCGHIDEventTap, event);
-
- CoreFoundation.library.CFRelease(event);
- }
- }
-
- /**
- * Presses a given key. The key should be released using the keyRelease method.
- * @param code get by karabiner-eventviewer etc.
- */
- public void keyPress2(int code) {
- Pointer /* CGEventRef */ event = library.CGEventCreateKeyboardEvent(src, (char) code, true);
-
- library.CGEventPost(kCGHIDEventTap, event);
-
- CoreFoundation.library.CFRelease(event);
- }
-
- /**
- * Releases a given key.
- * @param code get by karabiner-eventviewer etc.
- */
- public void keyRelease(int code) {
- if (code == kVK_Command) {
- command = false;
- } else if (code == kVK_Option) {
- option = false;
- } else if (code == kVK_Control) {
- control = false;
- } else if (code == kVK_Shift) {
- command = false;
- } else {
- Pointer /* CGEventRef */ event = library.CGEventCreateKeyboardEvent(src, (char) code, false);
-
- long flags = 0;
- if (command) flags |= kCGEventFlagMaskCommand;
- if (option) flags |= kCGEventFlagMaskAlternate;
- if (control) flags |= kCGEventFlagMaskControl;
- if (shift) flags |= kCGEventFlagMaskShift;
- library.CGEventSetFlags(event, flags);
-
- library.CGEventPost(kCGHIDEventTap, event);
-
- CoreFoundation.library.CFRelease(event);
- }
- }
-
- /**
- * Releases a given key.
- * @param code get by karabiner-eventviewer etc.
- */
- public void keyRelease2(int code) {
- Pointer /* CGEventRef */ event = library.CGEventCreateKeyboardEvent(src, (char) code, false);
-
- library.CGEventPost(kCGHIDEventTap, event);
-
- CoreFoundation.library.CFRelease(event);
- }
-
- /** the previous pointer */
- private CGPoint prev;
-
- /** Moves mouse pointer to given screen coordinates with moving motion. */
- public void mouseMove(int x, int y) {
- int dx = x - prev.x.intValue();
- int dy = y - prev.y.intValue();
- prev = new CGPoint(x, y);
- Pointer /* CGEventRef */ event = library.CGEventCreateMouseEvent(
- null, kCGEventMouseMoved,
- prev,
- 0 // ignored
- );
- // Now, execute these events with an interval to make them noticeable
- library.CGEventSetIntegerValueField(event, kCGMouseEventDeltaX, dx);
- library.CGEventSetIntegerValueField(event, kCGMouseEventDeltaY, dy);
- library.CGEventPost(kCGHIDEventTap, event);
- CoreFoundation.library.CFRelease(event);
- }
-
- /** Moves mouse pointer to given screen coordinates w/o moving motion means like teleportation. */
- public void mouseMove0(int x, int y) {
- prev = new CGPoint(x, y);
- Pointer /* CGEventRef */ event = library.CGEventCreateMouseEvent(
- null, kCGEventMouseMoved,
- prev,
- 0 // ignored
- );
- // Now, execute these events with an interval to make them noticeable
- library.CGEventPost(kCGHIDEventTap, event);
- CoreFoundation.library.CFRelease(event);
- }
-
- /** Moves mouse pointer to given deltas. */
- public void mouseMove2(int dx, int dy) {
- Pointer /* CGEventRef */ event = library.CGEventCreateMouseEvent(
- null, kCGEventMouseMoved,
- prev,
- 0 // ignored
- );
- // Now, execute these events with an interval to make them noticeable
- library.CGEventSetIntegerValueField(event, kCGMouseEventDeltaX, dx);
- library.CGEventSetIntegerValueField(event, kCGMouseEventDeltaY, dy);
- library.CGEventPost(kCGHIDEventTap, event);
- CoreFoundation.library.CFRelease(event);
- }
-
- /**
- * Presses one or more mouse buttons. The mouse buttons should be released using the mouseRelease(int) method.
- * @param buttons kCGMouseButtonLeft, kCGMouseButtonRight
- */
- public void mousePress(int buttons) {
- int[] events = {kCGEventLeftMouseDown, kCGEventRightMouseDown};
- Pointer /* CGEventRef */ event = library.CGEventCreateMouseEvent(
- null, events[buttons],
- prev,
- buttons
- );
- library.CGEventPost(kCGHIDEventTap, event);
- CoreFoundation.library.CFRelease(event);
- }
-
- /**
- * Presses one or more mouse buttons. The mouse buttons should be released using the mouseRelease(int) method.
- * @param buttons kCGMouseButtonLeft, kCGMouseButtonRight
- */
- public void mousePress2(int buttons, int x, int y) {
- prev = new CGPoint(x, y);
- int[] events = {kCGEventLeftMouseDown, kCGEventRightMouseDown};
- Pointer /* CGEventRef */ event = library.CGEventCreateMouseEvent(
- null, events[buttons],
- prev,
- buttons
- );
- library.CGEventPost(kCGHIDEventTap, event);
- CoreFoundation.library.CFRelease(event);
- }
-
- /**
- * Releases one or more mouse buttons using previous point.
- * @param buttons kCGMouseButtonLeft, kCGMouseButtonRight
- */
- public void mouseRelease(int buttons) {
- int[] events = {kCGEventLeftMouseUp, kCGEventRightMouseUp};
- Pointer /* CGEventRef */ event = library.CGEventCreateMouseEvent(
- null, events[buttons],
- prev,
- buttons
- );
- library.CGEventPost(kCGHIDEventTap, event);
- CoreFoundation.library.CFRelease(event);
- }
- /**
- * Releases one or more mouse buttons.
- * @param buttons kCGMouseButtonLeft, kCGMouseButtonRight
- */
- public void mouseRelease2(int buttons, int x, int y) {
- prev = new CGPoint(x, y);
- int[] events = {kCGEventLeftMouseUp, kCGEventRightMouseUp};
- Pointer /* CGEventRef */ event = library.CGEventCreateMouseEvent(
- null, events[buttons],
- prev,
- buttons
- );
- library.CGEventPost(kCGHIDEventTap, event);
- CoreFoundation.library.CFRelease(event);
- }
-
- /** Rotates the scroll wheel on wheel-equipped mice. */
- public void mouseWheel(int wheelAmt) {
- Pointer /* CGEventRef */ event = library.CGEventCreateScrollWheelEvent2(
- null, kCGScrollEventUnitPixel, 1, wheelAmt, 0, 0);
- library.CGEventSetType(event, kCGEventScrollWheel);
- library.CGEventPost(kCGHIDEventTap, event);
- CoreFoundation.library.CFRelease(event);
- }
-}
diff --git a/rococoa-contrib/src/test/java/org/rococoa/cocoa/coregraphics/CoreGraphicsLibraryTest.java b/rococoa-contrib/src/test/java/org/rococoa/cocoa/coregraphics/CoreGraphicsLibraryTest.java
index 78898cb..2febb1e 100644
--- a/rococoa-contrib/src/test/java/org/rococoa/cocoa/coregraphics/CoreGraphicsLibraryTest.java
+++ b/rococoa-contrib/src/test/java/org/rococoa/cocoa/coregraphics/CoreGraphicsLibraryTest.java
@@ -19,7 +19,6 @@
import com.sun.tools.attach.VirtualMachineDescriptor;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
import org.rococoa.Foundation;
import org.rococoa.ObjCObject;
@@ -29,13 +28,10 @@
import org.rococoa.cocoa.appkit.NSWorkspace;
import org.rococoa.cocoa.corefoundation.CoreFoundation;
import org.rococoa.cocoa.coreimage.CIImage;
-import org.rococoa.cocoa.foundation.NSBundle;
import org.rococoa.cocoa.foundation.NSDictionary;
import org.rococoa.cocoa.foundation.NSNotification;
import org.rococoa.cocoa.foundation.NSNotificationCenter;
-import org.rococoa.cocoa.foundation.NSObject;
import org.rococoa.cocoa.foundation.NSString;
-import org.rococoa.cocoa.gamecontroller.GCController;
import vavi.util.Debug;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -171,8 +167,6 @@ void test62() throws Exception {
if (!a.active()) {
a.activateWithOptions(0);
}
- RococaRobot ide = new RococaRobot();
-// ide.keyClick(kVK_ANSI_);
} catch (NoSuchElementException e) {
Debug.println(Level.WARNING, "run minecraft before running this test");
}
@@ -207,7 +201,7 @@ void test8() throws Exception {
CountDownLatch cdl = new CountDownLatch(1);
- class MyObserver implements Callback {
+ static class MyObserver implements Callback {
public void applicationWasActivated(NSNotification notification) {
NSWorkspace workspace = Rococoa.cast(notification.object(), NSWorkspace.class);
@@ -225,7 +219,7 @@ public void applicationWasDeactivated(NSNotification notification) {
@Test
@EnabledIfSystemProperty(named = "vavi.test", matches = "ide")
void test9() throws Exception {
- ObjCObject proxy = Rococoa.proxy(new CoreGraphicsLibraryTest.MyObserver());
+ ObjCObject proxy = Rococoa.proxy(new MyObserver());
Selector sel1 = Foundation.selector("applicationWasActivated:");
Selector sel2 = Foundation.selector("applicationWasDeactivated:");
diff --git a/rococoa-core/src/main/java/org/rococoa/cocoa/foundation/NSArray.java b/rococoa-core/src/main/java/org/rococoa/cocoa/foundation/NSArray.java
index 34a22c9..31951cd 100755
--- a/rococoa-core/src/main/java/org/rococoa/cocoa/foundation/NSArray.java
+++ b/rococoa-core/src/main/java/org/rococoa/cocoa/foundation/NSArray.java
@@ -69,7 +69,7 @@ static NSMutableArray toArray(NSObject...objects) {
@SuppressWarnings("unchecked")
public List toList() {
List result = new ArrayList<>();
- for (int i = 0; i ) result;
diff --git a/rococoa-core/src/main/java/org/rococoa/internal/ObjCObjectInvocationHandler.java b/rococoa-core/src/main/java/org/rococoa/internal/ObjCObjectInvocationHandler.java
index bdf0475..50ff0bf 100644
--- a/rococoa-core/src/main/java/org/rococoa/internal/ObjCObjectInvocationHandler.java
+++ b/rococoa-core/src/main/java/org/rococoa/internal/ObjCObjectInvocationHandler.java
@@ -28,6 +28,7 @@
import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.concurrent.Callable;
+import java.util.logging.Level;
import java.util.logging.Logger;
import com.sun.jna.Pointer;
@@ -170,7 +171,12 @@ public Object intercept(@This Object proxy, @Origin Method method, @AllArguments
if (!Modifier.isAbstract(method.getModifiers())) {
// method is not abstract, so a Java override has been provided, which we call
logging.finest(String.format("superMethod.invoke [%s %s].%s(%s)", javaClassName, ocInstance, method.getName(), new VarArgsUnpacker(args)));
- return superMethod.invoke(proxy, args);
+ try {
+ return superMethod.invoke(proxy, args);
+ } catch (Throwable t) {
+logging.log(Level.WARNING, String.format("superMethod.invoke [%s %s].%s(%s) failure", javaClassName, ocInstance, method.getName(), new VarArgsUnpacker(args)), t);
+ throw t;
+ }
}
// normal case
return invokeCocoa(method, args);
diff --git a/rococoa-core/src/test/java/Test1.java b/rococoa-core/src/test/java/Test1.java
index f58c4e1..82f6353 100644
--- a/rococoa-core/src/test/java/Test1.java
+++ b/rococoa-core/src/test/java/Test1.java
@@ -10,7 +10,6 @@
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable;
import org.rococoa.cocoa.foundation.NSString;
@@ -20,29 +19,13 @@
/**
- * Test1.
+ * Integration Test.
*
* @author Naohide Sano (nsano)
* @version 0.00 2023-06-30 nsano initial version
*/
public class Test1 {
- @Test
- @Disabled
- void test1() throws Exception {
-// MethodHandle methodHandleFieldDirect = lookup.unreflectGetter(fieldName);
-// CallSite callSiteField = new ConstantCallSite(methodHandleFieldDirect);
-// methodHandleFieldDirect = callSiteField.dynamicInvoker();
-// name = (String) methodHandleFieldDirect.invokeExact(new Employee());
-//
-//
-////Lookup invoke dynamic
-// methodType = MethodType.methodType(String.class);
-// methodHandle = lookup.findVirtual(Employee.class, "getName", methodType);
-// CallSite callSiteMethod = new ConstantCallSite(methodHandleFieldDirect);
-// methodHandle = callSiteMethod.dynamicInvoker();
- }
-
@Test
@DisabledIfEnvironmentVariable(named = "GITHUB_WORKFLOW", matches = ".*")
void test2() throws Exception {
diff --git a/rococoa-core/src/test/java/TestCase.java b/rococoa-core/src/test/java/TestCase.java
new file mode 100644
index 0000000..986ef78
--- /dev/null
+++ b/rococoa-core/src/test/java/TestCase.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2024 by Naohide Sano, All rights reserved.
+ *
+ * Programmed by Naohide Sano
+ */
+
+import java.util.List;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.rococoa.cocoa.foundation.NSArray;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+
+/**
+ * TestCase.
+ *
+ * @author Naohide Sano (nsano)
+ * @version 0.00 2024-03-26 nsano initial version
+ */
+public class TestCase {
+
+ @Test
+ @Disabled
+ void test1() throws Exception {
+// MethodHandle methodHandleFieldDirect = lookup.unreflectGetter(fieldName);
+// CallSite callSiteField = new ConstantCallSite(methodHandleFieldDirect);
+// methodHandleFieldDirect = callSiteField.dynamicInvoker();
+// name = (String) methodHandleFieldDirect.invokeExact(new Employee());
+//
+//
+////Lookup invoke dynamic
+// methodType = MethodType.methodType(String.class);
+// methodHandle = lookup.findVirtual(Employee.class, "getName", methodType);
+// CallSite callSiteMethod = new ConstantCallSite(methodHandleFieldDirect);
+// methodHandle = callSiteMethod.dynamicInvoker();
+ }
+
+ NSArray array() {
+ return null;
+ }
+
+ @Test
+ void test2() throws Exception {
+ NSArray array = array();
+ assertThrows(NullPointerException.class, () -> {
+ List> list = array.toList();
+ });
+ }
+}