aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2023-07-08 01:43:47 +0200
committerSven Gothel <[email protected]>2023-07-08 01:43:47 +0200
commit701311d6fc507b1e21681dd60c6851fbc50c2304 (patch)
tree85bc26b705a9549454ac20f3092c86b566253e3e
parent4267e223e33acdc098cc5b4371765f8e31b96eff (diff)
GlueGen JavaCallback: Add capability to have UserParam as (part of) key
Resolves use case where UserParam reflects e.g. a context (AL_SOFT_events) and will be (part of) the key mapping. Implementation required an additional userParamID -> userParam mapping for default Object/ID usage. Added 2 test cases.
-rw-r--r--doc/GlueGen_Mapping.html48
-rw-r--r--doc/GlueGen_Mapping.md51
-rw-r--r--src/java/com/jogamp/gluegen/JavaCallbackEmitter.java151
-rw-r--r--src/java/com/jogamp/gluegen/JavaEmitter.java2
-rw-r--r--src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java11
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/Test4JavaCallback.java318
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/test2-CustomJavaIfCode.java.stub4
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/test2-CustomJavaImplCode.java.stub46
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/test2.c109
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg58
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/test2.h17
11 files changed, 709 insertions, 106 deletions
diff --git a/doc/GlueGen_Mapping.html b/doc/GlueGen_Mapping.html
index 775835e..bde318d 100644
--- a/doc/GlueGen_Mapping.html
+++ b/doc/GlueGen_Mapping.html
@@ -468,6 +468,9 @@
Example 2b (Custom <em>KeyClass</em>, different key-parameter
order)</a></li>
<li><a
+ href="#javacallback-example-5b-userparam-part-of-2-component-key">JavaCallback
+ Example 5b (UserParam part of 2 component-key)</a></li>
+ <li><a
href="#javacallback-example-11a-homogeneous-struct-type">JavaCallback
Example 11a (<em>Homogeneous Struct Type</em>)</a></li>
<li><a
@@ -2421,6 +2424,51 @@ which uses one key, i.e. <code>buffer</code>.</p>
return &quot;CustomALKey[this &quot;+toHexString(System.identityHashCode(this))+&quot;, buffer &quot;+buffer+&quot;]&quot;;
}
}</code></pre>
+<h3
+id="javacallback-example-5b-userparam-part-of-2-component-key">JavaCallback
+Example 5b (UserParam part of 2 component-key)</h3>
+<p>Similar example as example 2a, but having the <code>UserParam</code>
+as part of the 2 component-key.</p>
+<p>C-API Header snipped</p>
+<pre><code> typedef void ( * ALEVENTPROCSOFT)(int eventType, int object, int param, int length, const char *message, void *userParam /* key */);
+
+ void alEventCallback1(int object /* key */, ALEVENTPROCSOFT callback, void *userParam /* key */);</code></pre>
+<p>GlueGen configuration snippet with the added option attribute for the
+<code>SetCallback-KeyClass</code> in directive
+<code>JavaCallbackDef</code>.</p>
+<pre><code>ArgumentIsPascalString ALEVENTPROCSOFT 3 4
+
+JavaCallbackDef alEventCallback1 2 ALEVENTPROCSOFT 5
+JavaCallbackKey alEventCallback1 0 2 ALEVENTPROCSOFT 1 5</code></pre>
+<p>Resulting to the default <code>KeyClass</code></p>
+<pre><code> /** Key { int object, java.lang.Object userParam } for &lt;br&gt; &lt;code&gt; void alEventCallback1(int object, ALEVENTPROCSOFT callback, Object userParam)&lt;/code&gt; */
+ public static class AlEventCallback1Key {
+ public final int object;
+ public final java.lang.Object userParam;
+ public AlEventCallback1Key(int object, java.lang.Object userParam) {
+ this.object = object;
+ this.userParam = userParam;
+ }
+ @Override
+ public boolean equals(final Object o) {
+ if( this == o ) {
+ return true;
+ }
+ if( !(o instanceof AlEventCallback1Key) ) {
+ return false;
+ }
+ final AlEventCallback1Key o2 = (AlEventCallback1Key)o;
+ return object == o2.object &amp;&amp;
+ userParam == o2.userParam;
+ }
+ @Override
+ public int hashCode() {
+ // 31 * x == (x &lt;&lt; 5) - x
+ int hash = object;
+ hash = ((hash &lt;&lt; 5) - hash) + System.identityHashCode( userParam );
+ return hash;
+ }
+ }</code></pre>
<h3 id="javacallback-example-11a-homogeneous-struct-type">JavaCallback
Example 11a (<em>Homogeneous Struct Type</em>)</h3>
<p>This example demonstrates a <a
diff --git a/doc/GlueGen_Mapping.md b/doc/GlueGen_Mapping.md
index ae43f33..060a9b6 100644
--- a/doc/GlueGen_Mapping.md
+++ b/doc/GlueGen_Mapping.md
@@ -1135,6 +1135,57 @@ which uses one key, i.e. `buffer`.
}
```
+### JavaCallback Example 5b (UserParam part of 2 component-key)
+
+Similar example as example 2a, but having the `UserParam` as part of the 2 component-key.
+
+C-API Header snipped
+```
+ typedef void ( * ALEVENTPROCSOFT)(int eventType, int object, int param, int length, const char *message, void *userParam /* key */);
+
+ void alEventCallback1(int object /* key */, ALEVENTPROCSOFT callback, void *userParam /* key */);
+```
+
+GlueGen configuration snippet with the added option attribute for the `SetCallback-KeyClass` in directive `JavaCallbackDef`.
+```
+ArgumentIsPascalString ALEVENTPROCSOFT 3 4
+
+JavaCallbackDef alEventCallback1 2 ALEVENTPROCSOFT 5
+JavaCallbackKey alEventCallback1 0 2 ALEVENTPROCSOFT 1 5
+```
+
+Resulting to the default `KeyClass`
+```
+ /** Key { int object, java.lang.Object userParam } for <br> <code> void alEventCallback1(int object, ALEVENTPROCSOFT callback, Object userParam)</code> */
+ public static class AlEventCallback1Key {
+ public final int object;
+ public final java.lang.Object userParam;
+ public AlEventCallback1Key(int object, java.lang.Object userParam) {
+ this.object = object;
+ this.userParam = userParam;
+ }
+ @Override
+ public boolean equals(final Object o) {
+ if( this == o ) {
+ return true;
+ }
+ if( !(o instanceof AlEventCallback1Key) ) {
+ return false;
+ }
+ final AlEventCallback1Key o2 = (AlEventCallback1Key)o;
+ return object == o2.object &&
+ userParam == o2.userParam;
+ }
+ @Override
+ public int hashCode() {
+ // 31 * x == (x << 5) - x
+ int hash = object;
+ hash = ((hash << 5) - hash) + System.identityHashCode( userParam );
+ return hash;
+ }
+ }
+```
+
### JavaCallback Example 11a (*Homogeneous Struct Type*)
This example demonstrates a [homogeneous *Struct* `UserParam` mapping](#struct-type-user-param-homogeneous) with a [key-mapped](#javacallback-key-definition) `CallbackFunction` and `UserParam`.
diff --git a/src/java/com/jogamp/gluegen/JavaCallbackEmitter.java b/src/java/com/jogamp/gluegen/JavaCallbackEmitter.java
index e4046ac..05192d3 100644
--- a/src/java/com/jogamp/gluegen/JavaCallbackEmitter.java
+++ b/src/java/com/jogamp/gluegen/JavaCallbackEmitter.java
@@ -50,6 +50,10 @@ public final class JavaCallbackEmitter {
final JavaType setFuncUserParamJType;
final String setFuncUserParamTypeName;
final String setFuncUserParamArgName;
+ final boolean userParamIsKey;
+ final boolean userParamIsCompound;
+ final boolean userParamIsMappedToID;
+ final String userParamIDMapInstanceName;
final boolean customKeyClass;
final String KeyClassName;
@@ -77,6 +81,23 @@ public final class JavaCallbackEmitter {
setFuncUserParamTypeName = setFuncUserParamJType.getName();
setFuncUserParamArgName = binding.getArgumentName(javaCallback.setFuncUserParamIdx);
+ userParamIsKey = info.setFuncKeyIndices.contains(info.setFuncUserParamIdx);
+ if( !setFuncUserParamJType.isLong() ) {
+ if( setFuncUserParamJType.isCompoundTypeWrapper() ) {
+ userParamIsCompound = true;
+ userParamIsMappedToID = false;
+ userParamIDMapInstanceName = null;
+ } else {
+ userParamIsCompound = false;
+ userParamIsMappedToID = true;
+ userParamIDMapInstanceName = userParamIsKey ? lowIfaceName+"UserObjIDMap" : null;
+ }
+ } else {
+ userParamIsCompound = false;
+ userParamIsMappedToID = false;
+ userParamIDMapInstanceName = null;
+ }
+
if( null != javaCallback.setFuncKeyClassName ) {
customKeyClass = true;;
KeyClassName = javaCallback.setFuncKeyClassName;
@@ -88,36 +109,6 @@ public final class JavaCallbackEmitter {
}
}
- public void emitJavaSetFuncPreCall(final CodeUnit unit) {
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emit (" final long nativeUserParam = ");
- if( setFuncUserParamJType.isLong() ) {
- unit.emitln(" "+setFuncUserParamArgName+";");
- } else if( setFuncUserParamJType.isCompoundTypeWrapper() ) {
- unit.emitln(" null != "+setFuncUserParamArgName+" ? "+setFuncUserParamArgName+".getDirectBufferAddress() : 0;");
- } else {
- unit.emitln(""+jcbNextIDVarName+"++;");
- unit.emitln(" if( 0 >= "+jcbNextIDVarName+" ) { "+jcbNextIDVarName+" = 1; }");
- }
- unit.emitln(" if( null != "+setFuncCBArgName+" ) {");
- unit.emitln(" add"+capIfaceName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), info.setFuncKeyIndices, true).toString()+
- "new "+DataClassName+"("+setFuncCBArgName+", "+setFuncUserParamArgName+"));");
- unit.emitln(" }");
- unit.emitln();
- }
-
- public void emitJavaSetFuncPostCall(final CodeUnit unit) {
- unit.emitln(" if( null == "+setFuncCBArgName+" ) {");
- unit.emitln(" // callback released (null func) -> release a previously mapped instance ");
- if( useDataMap ) {
- unit.emitln(" release"+capIfaceName+"( new "+KeyClassName+"( "+binding.getJavaCallSelectArguments(new StringBuilder(), info.setFuncKeyIndices, false).toString()+" ) );");
- } else {
- unit.emitln(" release"+capIfaceName+"();");
- }
- unit.emitln(" }");
- unit.emitln(" } // synchronized ");
- }
-
public void emitJavaAdditionalCode(final CodeUnit unit, final boolean isInterface) {
if( isInterface ) {
if( useDataMap ) {
@@ -213,7 +204,14 @@ public final class JavaCallbackEmitter {
emitJavaBriefAPIDoc(unit, "Releases callback data ", "mapped to ", "", "skipping toolkit API. Favor passing `null` callback ref to ");
unit.emitln(" public final void release"+capIfaceName+"("+KeyClassName+" key) {");
unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" /* final "+DataClassName+" value = */ "+dataMapInstanceName+".remove(key);");
+ if( userParamIsMappedToID && userParamIsKey ) {
+ unit.emitln(" "+DataClassName+" value = "+dataMapInstanceName+".remove(key);");
+ unit.emitln(" if( null != value ) {");
+ unit.emitln(" "+userParamIDMapInstanceName+".remove(value.paramID);");
+ unit.emitln(" }");
+ } else {
+ unit.emitln(" /* "+DataClassName+" value = */ "+dataMapInstanceName+".remove(key);");
+ }
unit.emitln(" }");
unit.emitln(" }");
unit.emitln();
@@ -248,6 +246,9 @@ public final class JavaCallbackEmitter {
unit.emitln(" public final void release"+capIfaceName+"() {");
unit.emitln(" synchronized( "+lockInstanceName+" ) {");
unit.emitln(" // final "+DataClassName+" value = "+dataInstanceName+";");
+ if( userParamIsMappedToID && userParamIsKey ) {
+ unit.emitln(" "+userParamIDMapInstanceName+".remove(dataInstanceName.paramID);");
+ }
unit.emitln(" "+dataInstanceName+" = null;");
unit.emitln(" }");
unit.emitln(" }");
@@ -256,11 +257,27 @@ public final class JavaCallbackEmitter {
unit.emitln(" private final void add"+capIfaceName+"("+binding.getJavaSelectParameter(new StringBuilder(), info.setFuncKeyIndices, true).toString()+DataClassName+" value) {");
if( useDataMap ) {
unit.emitln(" final "+KeyClassName+" key = new "+KeyClassName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), info.setFuncKeyIndices, false).toString()+");");
- unit.emitln(" /* final "+DataClassName+" old = */ "+dataMapInstanceName+".put(key, value);");
+ if( userParamIsMappedToID && userParamIsKey ) {
+ unit.emitln(" final "+DataClassName+" old = "+dataMapInstanceName+".put(key, value);");
+ } else {
+ unit.emitln(" /* final "+DataClassName+" old = */ "+dataMapInstanceName+".put(key, value);");
+ }
} else {
- unit.emitln(" // final "+DataClassName+" old = "+dataInstanceName+";");
+ if( userParamIsMappedToID && userParamIsKey ) {
+ unit.emitln(" final "+DataClassName+" old = "+dataInstanceName+";");
+ } else {
+ unit.emitln(" // final "+DataClassName+" old = "+dataInstanceName+";");
+ }
unit.emitln(" "+dataInstanceName+" = value;");
}
+ if( userParamIsMappedToID && userParamIsKey ) {
+ unit.emitln(" if( null != old ) {");
+ unit.emitln(" "+userParamIDMapInstanceName+".remove(old.paramID);");
+ unit.emitln(" }");
+ unit.emitln(" if( null != value.param ) {");
+ unit.emitln(" "+userParamIDMapInstanceName+".put(value.paramID, value.param);");
+ unit.emitln(" }");
+ }
unit.emitln(" }");
unit.emitln();
if( !cfg.emittedJavaCallbackUserParamClasses.contains(fqUsrParamClassName) ) {
@@ -272,6 +289,9 @@ public final class JavaCallbackEmitter {
} else {
unit.emitln(" private static "+DataClassName+" "+dataInstanceName+" = null;");
}
+ if( userParamIsMappedToID && userParamIsKey ) {
+ unit.emitln(" private static final LongObjectHashMap "+userParamIDMapInstanceName+" = new LongObjectHashMap();");
+ }
unit.emitln(" private static long "+jcbNextIDVarName+" = 1;");
unit.emitln(" private static final Object "+lockInstanceName+" = new Object();");
unit.emitln();
@@ -390,9 +410,19 @@ public final class JavaCallbackEmitter {
unit.emitln(" // userParamArgCType "+setFuncUserParamCType);
unit.emitln(" // userParamArgJType "+setFuncUserParamJType);
unit.emitln(" final "+info.cbFuncTypeName+" func;");
+ if( userParamIsMappedToID ) {
+ unit.emitln(" final long paramID;");
+ }
unit.emitln(" final "+setFuncUserParamTypeName+" param;");
- unit.emitln(" "+DataClassName+"("+info.cbFuncTypeName+" func, "+setFuncUserParamTypeName+" param) {");
+ unit.emit (" "+DataClassName+"(final "+info.cbFuncTypeName+" func, ");
+ if( userParamIsMappedToID ) {
+ unit.emit("final long paramID, ");
+ }
+ unit.emitln("final "+setFuncUserParamTypeName+" param) {");
unit.emitln(" this.func = func;");
+ if( userParamIsMappedToID ) {
+ unit.emitln(" this.paramID = paramID;");
+ }
unit.emitln(" this.param = param;");
unit.emitln(" }");
unit.emitln(" }");
@@ -426,6 +456,45 @@ public final class JavaCallbackEmitter {
buf.append("this.getClass(), \"" + getJavaStaticCallbackSignature()+ "\", nativeUserParam");
return 3;
}
+
+ public void emitJavaSetFuncPreCall(final CodeUnit unit) {
+ unit.emitln(" final long nativeUserParam;");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ if( setFuncUserParamJType.isLong() ) {
+ unit.emitln(" nativeUserParam = "+setFuncUserParamArgName+";");
+ } else {
+ unit.emitln(" if( null != "+setFuncUserParamArgName+" ) {");
+ if( setFuncUserParamJType.isCompoundTypeWrapper() ) {
+ // userParamIsCompound == true
+ unit.emitln(" nativeUserParam = "+setFuncUserParamArgName+".getDirectBufferAddress();");
+ } else {
+ // userParamIsMappedToID == true
+ unit.emitln(" nativeUserParam = "+jcbNextIDVarName+"++;");
+ unit.emitln(" if( 0 >= "+jcbNextIDVarName+" ) { "+jcbNextIDVarName+" = 1; }");
+ }
+ unit.emitln(" } else {");
+ unit.emitln(" nativeUserParam = 0;");
+ unit.emitln(" }");
+ }
+ unit.emitln(" if( null != "+setFuncCBArgName+" ) {");
+ unit.emit (" add"+capIfaceName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), info.setFuncKeyIndices, true).toString()+
+ "new "+DataClassName+"("+setFuncCBArgName+", ");
+ if( userParamIsMappedToID ) {
+ unit.emit("nativeUserParam, ");
+ }
+ unit.emitln(setFuncUserParamArgName+"));");
+ unit.emitln(" } else { ");
+ unit.emitln(" // release a previously mapped instance ");
+ if( useDataMap ) {
+ unit.emitln(" release"+capIfaceName+"( new "+KeyClassName+"( "+binding.getJavaCallSelectArguments(new StringBuilder(), info.setFuncKeyIndices, false).toString()+" ) );");
+ } else {
+ unit.emitln(" release"+capIfaceName+"();");
+ }
+ unit.emitln(" }");
+ unit.emitln(" } // synchronized ");
+ unit.emitln();
+ }
+
private final void emitJavaStaticCallback(final CodeUnit unit) {
unit.emitln(" /** Static callback invocation, dispatching to "+info.cbSimpleClazzName+" for callback <br> <code>"+
info.cbFuncType.toString(info.cbFuncTypeName, false, true)+"</code> */");
@@ -436,7 +505,7 @@ public final class JavaCallbackEmitter {
if( !cType.isVoid() ) {
if( 0 < consumedCount ) { unit.emit(", "); }
if( idx == info.cbFuncUserParamIdx ) {
- unit.emit("long nativeUserParamPtr");
+ unit.emit("long nativeUserParam");
if( jType.isCompoundTypeWrapper() ) {
mapNativePtrToCompound[0] = true;
origUserParamJType[0] = jType;
@@ -450,11 +519,19 @@ public final class JavaCallbackEmitter {
}
} );
unit.emitln(") {");
+ final boolean useParamLocal[] = { false };
if( mapNativePtrToCompound[0] ) {
- unit.emitln(" final "+origUserParamJType[0]+" "+info.cbFuncUserParamName+" = "+origUserParamJType[0]+".derefPointer(nativeUserParamPtr);");
+ unit.emitln(" final "+origUserParamJType[0]+" "+info.cbFuncUserParamName+" = "+origUserParamJType[0]+".derefPointer(nativeUserParam);");
+ useParamLocal[0] = true;
+ } else if( userParamIsMappedToID && userParamIsKey ) {
+ unit.emitln(" final Object "+info.cbFuncUserParamName+";");
}
unit.emitln(" final "+DataClassName+" value;");
unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ if( userParamIsMappedToID && userParamIsKey && !mapNativePtrToCompound[0] ) {
+ unit.emitln(" "+info.cbFuncUserParamName+" = "+userParamIDMapInstanceName+".get(nativeUserParam);");
+ useParamLocal[0] = true;
+ }
if( useDataMap ) {
unit.emitln(" final "+KeyClassName+" key = new "+KeyClassName+"("+info.cbFuncBinding.getJavaCallSelectArguments(new StringBuilder(), info.cbFuncKeyIndices, false).toString()+");");
unit.emitln(" value = "+dataMapInstanceName+".get(key);");
@@ -478,7 +555,7 @@ public final class JavaCallbackEmitter {
info.cbFuncBinding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
if( !cType.isVoid() ) {
if( 0 < consumedCount ) { unit.emit(", "); }
- if( idx == info.cbFuncUserParamIdx && !mapNativePtrToCompound[0] ) {
+ if( idx == info.cbFuncUserParamIdx && !useParamLocal[0] ) {
unit.emit("value.param");
} else {
unit.emit(name);
diff --git a/src/java/com/jogamp/gluegen/JavaEmitter.java b/src/java/com/jogamp/gluegen/JavaEmitter.java
index 07bd55d..88cff27 100644
--- a/src/java/com/jogamp/gluegen/JavaEmitter.java
+++ b/src/java/com/jogamp/gluegen/JavaEmitter.java
@@ -1473,7 +1473,7 @@ public class JavaEmitter implements GlueEmitter {
funcType.toString(jcbd.cbFuncTypeName, false, true));
}
final JavaCallbackInfo jcbi1 = new JavaCallbackInfo(jcbd.cbFuncTypeName, cbSimpleClazzName, cbFQClazzName, jcbi0.staticCBMethodSignature,
- funcType, jcbi0.cbFuncBinding, jcbi0.cbFuncUserParamIdx, jcbi0.cbFuncKeyIndices,
+ funcType, jcbi0.cbFuncBinding, jcbi0.cbFuncUserParamIdx, jcbd.cbFuncKeyIndices,
jcbd.setFuncName, jcbd.setFuncUserParamIdx, jcbd.setFuncKeyIndices, jcbd.setFuncKeyClassName);
cfg.setFuncToJavaCallbackMap.put(jcbd.setFuncName, jcbi1);
LOG.log(INFO, "JavaCallbackInfo: Reusing {0} -> {1}", jcbd.setFuncName, jcbi0);
diff --git a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java
index fe4f82a..1b510c0 100644
--- a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java
@@ -604,7 +604,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
javaCallbackEmitter.emitJavaSetFuncPreCall(unit);
}
if (!returnType.isVoid()) {
- unit.emit(" ");
+ unit.emit(" ");
if (returnType.isCompoundTypeWrapper() ||
returnType.isNIOBuffer()) {
unit.emitln("final ByteBuffer _res;");
@@ -622,9 +622,9 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
}
if (needsResultAssignment) {
- unit.emit(" _res = ");
+ unit.emit(" _res = ");
} else {
- unit.emit(" ");
+ unit.emit(" ");
if (!returnType.isVoid()) {
unit.emit("return ");
}
@@ -633,11 +633,6 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
emitCall(binding);
unit.emitln();
- if( null != javaCallbackEmitter ) {
- unit.emitln();
- javaCallbackEmitter.emitJavaSetFuncPostCall(unit);
- }
-
emitPostCallCleanup(binding);
emitPrologueOrEpilogue(epilogue);
if (needsResultAssignment) {
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/Test4JavaCallback.java b/src/junit/com/jogamp/gluegen/test/junit/generation/Test4JavaCallback.java
index bc04977..90e01df 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/Test4JavaCallback.java
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/Test4JavaCallback.java
@@ -33,7 +33,10 @@ import java.util.Set;
import com.jogamp.common.os.NativeLibrary;
import com.jogamp.gluegen.test.junit.generation.Bindingtest2.ALBUFFERCALLBACKTYPESOFT;
+import com.jogamp.gluegen.test.junit.generation.Bindingtest2.ALEVENTPROCSOFT;
import com.jogamp.gluegen.test.junit.generation.Bindingtest2.AlBufferCallback0Key;
+import com.jogamp.gluegen.test.junit.generation.Bindingtest2.AlEventCallback0Key;
+import com.jogamp.gluegen.test.junit.generation.Bindingtest2.AlEventCallback1Key;
import com.jogamp.gluegen.test.junit.generation.Bindingtest2.MessageCallback11aKey;
import com.jogamp.gluegen.test.junit.generation.Bindingtest2.MessageCallback11bKey;
import com.jogamp.gluegen.test.junit.generation.Bindingtest2.T2_CallbackFunc01;
@@ -363,6 +366,48 @@ public class Test4JavaCallback extends BaseClass {
Assert.assertEquals(false, keys.contains(buffer3Key));
}
+ // Switch the callback function for buffer2 -> myCallback01, myUserParam02
+ {
+ // pre-condition
+ Assert.assertEquals(true, bt2.isAlBufferCallback0Mapped(buffer1Key));
+ Assert.assertEquals(false, bt2.isAlBufferCallback0Mapped(buffer2Key));
+ Assert.assertEquals(false, bt2.isAlBufferCallback0Mapped(buffer3Key));
+ Assert.assertEquals(myUserParam01, bt2.getAlBufferCallback0UserParam(buffer1Key));
+ Assert.assertEquals(null, bt2.getAlBufferCallback0UserParam(buffer2Key));
+ Assert.assertEquals(null, bt2.getAlBufferCallback0UserParam(buffer3Key));
+ Assert.assertEquals(myCallback01, bt2.getAlBufferCallback0(buffer1Key));
+ Assert.assertEquals(null, bt2.getAlBufferCallback0(buffer2Key));
+ Assert.assertEquals(null, bt2.getAlBufferCallback0(buffer3Key));
+ Assert.assertEquals(1, bt2.getAlBufferCallback0Keys().size());
+ }
+ bt2.alBufferCallback0(buffer1, 0, 0, myCallback02, myUserParam02);
+ {
+ // post-state
+ Assert.assertEquals(true, bt2.isAlBufferCallback0Mapped(buffer1Key));
+ Assert.assertEquals(false, bt2.isAlBufferCallback0Mapped(buffer2Key));
+ Assert.assertEquals(false, bt2.isAlBufferCallback0Mapped(buffer3Key));
+ Assert.assertEquals(myUserParam02, bt2.getAlBufferCallback0UserParam(buffer1Key));
+ Assert.assertEquals(null, bt2.getAlBufferCallback0UserParam(buffer2Key));
+ Assert.assertEquals(null, bt2.getAlBufferCallback0UserParam(buffer3Key));
+ Assert.assertEquals(myCallback02, bt2.getAlBufferCallback0(buffer1Key));
+ Assert.assertEquals(null, bt2.getAlBufferCallback0(buffer2Key));
+ Assert.assertEquals(null, bt2.getAlBufferCallback0(buffer3Key));
+ }
+ {
+ myUserParam01.j = 0;
+ myUserParam01.buffer = 0;
+ myUserParam02.j = 0;
+ myUserParam02.buffer = 0;
+ bt2.alBufferCallback0Inject(buffer1, 2, 10); // buffer1 -> myCallback01, myUserParam01
+ Assert.assertEquals( 2*10+2, id_res[0]);
+ Assert.assertEquals( 1, myUserParam01.i);
+ Assert.assertEquals( 0, myUserParam01.j);
+ Assert.assertEquals( 0, myUserParam01.buffer);
+ Assert.assertEquals( 2, myUserParam02.i);
+ Assert.assertEquals( 2*10+2, myUserParam02.j);
+ Assert.assertEquals( 1, myUserParam02.buffer);
+ }
+
// Just release the buffer1 callback and mapped resources
bt2.alBufferCallback0(buffer1, 0, 0, null, null); // usrptr is not key, only buffer is key!
Assert.assertEquals(false, bt2.isAlBufferCallback0Mapped(buffer1Key));
@@ -383,14 +428,19 @@ public class Test4JavaCallback extends BaseClass {
}
{
+ id_res[0] = 0;
+ myUserParam01.j = 0;
+ myUserParam01.buffer = 0;
+ myUserParam02.j = 0;
+ myUserParam02.buffer = 0;
bt2.alBufferCallback0Inject(buffer2, 1, 10); // unmapped, no change in data
- Assert.assertEquals( 1+ 10+2, id_res[0]);
+ Assert.assertEquals( 0, id_res[0]);
Assert.assertEquals( 1, myUserParam01.i);
- Assert.assertEquals(11+101+1, myUserParam01.j);
- Assert.assertEquals( 1, myUserParam01.buffer);
+ Assert.assertEquals( 0, myUserParam01.j);
+ Assert.assertEquals( 0, myUserParam01.buffer);
Assert.assertEquals( 2, myUserParam02.i);
- Assert.assertEquals( 1+ 10+2, myUserParam02.j);
- Assert.assertEquals( 2, myUserParam02.buffer);
+ Assert.assertEquals( 0, myUserParam02.j);
+ Assert.assertEquals( 0, myUserParam02.buffer);
}
}
@@ -882,6 +932,264 @@ public class Test4JavaCallback extends BaseClass {
}
/**
+ * Test Bindingtest2 with ALEVENTPROCSOFT JavaCallback
+ * on alEventCallback0(..) having the 'Object userParam` as single key.
+ */
+ @Test
+ public void chapter05a() throws Exception {
+ final Bindingtest2 bt2 = new Bindingtest2Impl();
+
+ final int[] id_res = { -1 };
+ final String[] msg_res = { null };
+ final ALEVENTPROCSOFT myCallback01 = new ALEVENTPROCSOFT() {
+ @Override
+ public void callback(final int eventType, final int object, final int param, final int length, final String message, final Object userParam) {
+ id_res[0] = object;
+ msg_res[0] = message;
+ System.err.println("chapter05a.myCallback01: type "+eventType+", obj "+object+", param "+param+", '"+message+"', userParam 0x"+
+ Integer.toHexString(System.identityHashCode(userParam)));
+ }
+ };
+ final ALEVENTPROCSOFT myCallback02 = new ALEVENTPROCSOFT() {
+ @Override
+ public void callback(final int eventType, final int object, final int param, final int length, final String message, final Object userParam) {
+ id_res[0] = 1000 * object;
+ msg_res[0] = message;
+ System.err.println("chapter05a.myCallback02: type "+eventType+", obj "+object+", param "+param+", '"+message+"', userParam 0x"+
+ Integer.toHexString(System.identityHashCode(userParam)));
+ }
+ };
+ final Object myUserParam01 = new Object();
+ final Object myUserParam02 = new Object();
+ final AlEventCallback0Key myKey01 = new AlEventCallback0Key(myUserParam01);
+ final AlEventCallback0Key myKey02 = new AlEventCallback0Key(myUserParam02);
+ Assert.assertEquals(false, bt2.isAlEventCallback0Mapped(myKey01));
+ Assert.assertEquals(false, bt2.isAlEventCallback0Mapped(myKey02));
+
+ bt2.alEventCallback0(myCallback01, myUserParam01);
+ Assert.assertEquals(true, bt2.isAlEventCallback0Mapped(myKey01));
+ Assert.assertEquals(false, bt2.isAlEventCallback0Mapped(myKey02));
+ {
+ final Set<AlEventCallback0Key> keys = bt2.getAlEventCallback0Keys();
+ Assert.assertEquals(1, keys.size());
+ Assert.assertEquals(true, keys.contains(myKey01));
+ Assert.assertEquals(false, keys.contains(myKey02));
+ }
+ Assert.assertEquals(myCallback01, bt2.getAlEventCallback0(myKey01));
+ Assert.assertEquals(null, bt2.getAlEventCallback0(myKey02));
+ Assert.assertEquals(-1, id_res[0]);
+ Assert.assertEquals(null, msg_res[0]);
+
+ {
+ final String msgNo1 = "First message";
+ id_res[0] = -1;
+ msg_res[0] = null;
+ bt2.alEventCallback0Inject(myUserParam01, 0, 1, 0, msgNo1);
+ Assert.assertEquals( 1, id_res[0]);
+ Assert.assertEquals(msgNo1, msg_res[0]);
+ }
+ {
+ final String msgNo2 = "Second message";
+ id_res[0] = -1;
+ msg_res[0] = null;
+ bt2.alEventCallback0Inject(myUserParam02, 0, 2, 0, msgNo2);
+ Assert.assertEquals( -1, id_res[0]);
+ Assert.assertEquals( null, msg_res[0]);
+
+ bt2.alEventCallback0Inject(myUserParam01, 0, 2, 0, msgNo2);
+ Assert.assertEquals( 2, id_res[0]);
+ Assert.assertEquals( msgNo2, msg_res[0]);
+ }
+
+ // Switch the callback function
+ // The previously mapped myCallback01 (myUserParam01) gets released
+ // and remapped to myCallback02 + ( myUserParam01 )(key)
+ bt2.alEventCallback0(myCallback02, myUserParam01);
+ Assert.assertEquals(true, bt2.isAlEventCallback0Mapped(myKey01));
+ Assert.assertEquals(false, bt2.isAlEventCallback0Mapped(myKey02));
+ {
+ final Set<AlEventCallback0Key> keys = bt2.getAlEventCallback0Keys();
+ Assert.assertEquals(1, keys.size());
+ Assert.assertEquals(true, keys.contains(myKey01));
+ Assert.assertEquals(false, keys.contains(myKey02));
+ }
+ Assert.assertEquals(myCallback02, bt2.getAlEventCallback0(myKey01));
+ Assert.assertEquals(null, bt2.getAlEventCallback0(myKey02));
+
+ {
+ final String msgNo3 = "Third message";
+ id_res[0] = -1;
+ msg_res[0] = null;
+ bt2.alEventCallback0Inject(myUserParam02, 0, 3, 0, msgNo3);
+ Assert.assertEquals( -1, id_res[0]);
+ Assert.assertEquals( null, msg_res[0]);
+
+ bt2.alEventCallback0Inject(myUserParam01, 0, 3, 0, msgNo3);
+ Assert.assertEquals( 3000, id_res[0]);
+ Assert.assertEquals( msgNo3, msg_res[0]);
+ }
+
+ // Fake release (wrong key)
+ bt2.alEventCallback0(null, myUserParam02);
+ Assert.assertEquals(true, bt2.isAlEventCallback0Mapped(myKey01));
+ Assert.assertEquals(false, bt2.isAlEventCallback0Mapped(myKey02));
+
+ // Just release the callback and mapped myUserParam01
+ bt2.alEventCallback0(null, myUserParam01);
+ Assert.assertEquals(false, bt2.isAlEventCallback0Mapped(myKey01));
+ Assert.assertEquals(false, bt2.isAlEventCallback0Mapped(myKey02));
+ Assert.assertEquals(0, bt2.getAlEventCallback0Keys().size());
+
+ {
+ final String msgNo4 = "Forth message";
+ id_res[0] = -1;
+ msg_res[0] = null;
+ bt2.alEventCallback0Inject(myUserParam01, 0, 4, 0, msgNo4);
+ Assert.assertEquals( -1, id_res[0]);
+ Assert.assertEquals( null, msg_res[0]);
+
+ bt2.alEventCallback0Inject(myUserParam02, 0, 4, 0, msgNo4);
+ Assert.assertEquals( -1, id_res[0]);
+ Assert.assertEquals( null, msg_res[0]);
+ }
+ }
+
+ /**
+ * Test Bindingtest2 with ALEVENTPROCSOFT JavaCallback
+ * on alEventCallback0(..) having the 'Object userParam` and `int object` as keys.
+ */
+ @Test
+ public void chapter05b() throws Exception {
+ final Bindingtest2 bt2 = new Bindingtest2Impl();
+
+ final int[] id_res = { -1 };
+ final String[] msg_res = { null };
+ final ALEVENTPROCSOFT myCallback01 = new ALEVENTPROCSOFT() {
+ @Override
+ public void callback(final int eventType, final int object, final int param, final int length, final String message, final Object userParam) {
+ id_res[0] = object;
+ msg_res[0] = message;
+ System.err.println("chapter05.myCallback01: type "+eventType+", obj "+object+", param "+param+", '"+message+"', userParam 0x"+
+ Integer.toHexString(System.identityHashCode(userParam)));
+ }
+ };
+ final ALEVENTPROCSOFT myCallback02 = new ALEVENTPROCSOFT() {
+ @Override
+ public void callback(final int eventType, final int object, final int param, final int length, final String message, final Object userParam) {
+ id_res[0] = 1000 * object;
+ msg_res[0] = message;
+ System.err.println("chapter05.myCallback02: type "+eventType+", obj "+object+", param "+param+", '"+message+"', userParam 0x"+
+ Integer.toHexString(System.identityHashCode(userParam)));
+ }
+ };
+ final Object myUserParam01 = new Object();
+ final Object myUserParam02 = new Object();
+ final AlEventCallback1Key myKey01 = new AlEventCallback1Key(1, myUserParam01);
+ final AlEventCallback1Key myKey02 = new AlEventCallback1Key(2, myUserParam02);
+ Assert.assertEquals(false, bt2.isAlEventCallback1Mapped(myKey01));
+ Assert.assertEquals(false, bt2.isAlEventCallback1Mapped(myKey02));
+
+ bt2.alEventCallback1(1, myCallback01, myUserParam01);
+ Assert.assertEquals(true, bt2.isAlEventCallback1Mapped(myKey01));
+ Assert.assertEquals(false, bt2.isAlEventCallback1Mapped(myKey02));
+ {
+ final Set<AlEventCallback1Key> keys = bt2.getAlEventCallback1Keys();
+ Assert.assertEquals(1, keys.size());
+ Assert.assertEquals(true, keys.contains(myKey01));
+ Assert.assertEquals(false, keys.contains(myKey02));
+ }
+ Assert.assertEquals(myCallback01, bt2.getAlEventCallback1(myKey01));
+ Assert.assertEquals(null, bt2.getAlEventCallback1(myKey02));
+ Assert.assertEquals(-1, id_res[0]);
+ Assert.assertEquals(null, msg_res[0]);
+
+ {
+ final String msgNo1 = "First message";
+ id_res[0] = -1;
+ msg_res[0] = null;
+ bt2.alEventCallback1Inject(myUserParam01, 0, 1, 0, msgNo1);
+ Assert.assertEquals( 1, id_res[0]);
+ Assert.assertEquals(msgNo1, msg_res[0]);
+ }
+ {
+ final String msgNo2 = "Second message";
+ id_res[0] = -1;
+ msg_res[0] = null;
+ bt2.alEventCallback1Inject(myUserParam02, 0, 2, 0, msgNo2);
+ Assert.assertEquals( -1, id_res[0]);
+ Assert.assertEquals( null, msg_res[0]);
+
+ bt2.alEventCallback1Inject(myUserParam01, 0, 2, 0, msgNo2);
+ Assert.assertEquals( -1, id_res[0]);
+ Assert.assertEquals( null, msg_res[0]);
+
+ bt2.alEventCallback1Inject(myUserParam01, 0, 1, 0, msgNo2);
+ Assert.assertEquals( 1, id_res[0]);
+ Assert.assertEquals( msgNo2, msg_res[0]);
+ }
+
+ // Switch the callback function
+ // The previously mapped myCallback01 (1, myUserParam01) gets released
+ // and remapped to myCallback02 + ( 1, myUserParam01 )(key)
+ bt2.alEventCallback1(1, myCallback02, myUserParam01);
+ Assert.assertEquals(true, bt2.isAlEventCallback1Mapped(myKey01));
+ Assert.assertEquals(false, bt2.isAlEventCallback1Mapped(myKey02));
+ {
+ final Set<AlEventCallback1Key> keys = bt2.getAlEventCallback1Keys();
+ Assert.assertEquals(1, keys.size());
+ Assert.assertEquals(true, keys.contains(myKey01));
+ Assert.assertEquals(false, keys.contains(myKey02));
+ }
+ Assert.assertEquals(myCallback02, bt2.getAlEventCallback1(myKey01));
+ Assert.assertEquals(null, bt2.getAlEventCallback1(myKey02));
+
+ {
+ final String msgNo3 = "Third message";
+ id_res[0] = -1;
+ msg_res[0] = null;
+ bt2.alEventCallback1Inject(myUserParam02, 0, 2, 0, msgNo3);
+ Assert.assertEquals( -1, id_res[0]);
+ Assert.assertEquals( null, msg_res[0]);
+
+ bt2.alEventCallback1Inject(myUserParam01, 0, 2, 0, msgNo3);
+ Assert.assertEquals( -1, id_res[0]);
+ Assert.assertEquals( null, msg_res[0]);
+
+ bt2.alEventCallback1Inject(myUserParam01, 0, 1, 0, msgNo3);
+ Assert.assertEquals( 1000, id_res[0]);
+ Assert.assertEquals( msgNo3, msg_res[0]);
+ }
+
+ // Fake release (wrong key)
+ bt2.alEventCallback1(2, null, myUserParam02);
+ Assert.assertEquals(true, bt2.isAlEventCallback1Mapped(myKey01));
+ Assert.assertEquals(false, bt2.isAlEventCallback1Mapped(myKey02));
+
+ bt2.alEventCallback1(2, null, myUserParam01);
+ Assert.assertEquals(true, bt2.isAlEventCallback1Mapped(myKey01));
+ Assert.assertEquals(false, bt2.isAlEventCallback1Mapped(myKey02));
+
+ // Just release the callback and mapped myUserParam01
+ bt2.alEventCallback1(1, null, myUserParam01);
+ Assert.assertEquals(false, bt2.isAlEventCallback1Mapped(myKey01));
+ Assert.assertEquals(false, bt2.isAlEventCallback1Mapped(myKey02));
+ Assert.assertEquals(0, bt2.getAlEventCallback1Keys().size());
+
+ {
+ final String msgNo4 = "Forth message";
+ id_res[0] = -1;
+ msg_res[0] = null;
+ bt2.alEventCallback1Inject(myUserParam01, 0, 4, 0, msgNo4);
+ Assert.assertEquals( -1, id_res[0]);
+ Assert.assertEquals( null, msg_res[0]);
+
+ bt2.alEventCallback1Inject(myUserParam02, 0, 4, 0, msgNo4);
+ Assert.assertEquals( -1, id_res[0]);
+ Assert.assertEquals( null, msg_res[0]);
+ }
+ }
+
+ /**
* Test Bindingtest2 with T2_CallbackFunc11 JavaCallback via MessageCallback11a()
* using the default MessageCallback11aKey class.
*/
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test2-CustomJavaIfCode.java.stub b/src/junit/com/jogamp/gluegen/test/junit/generation/test2-CustomJavaIfCode.java.stub
new file mode 100644
index 0000000..28d46a6
--- /dev/null
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test2-CustomJavaIfCode.java.stub
@@ -0,0 +1,4 @@
+ public void alEventCallback0Inject(Object userParam, int eventType, int object, int param, String message);
+
+ public void alEventCallback1Inject(Object userParam, int eventType, int object, int param, String message);
+
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test2-CustomJavaImplCode.java.stub b/src/junit/com/jogamp/gluegen/test/junit/generation/test2-CustomJavaImplCode.java.stub
new file mode 100644
index 0000000..6643108
--- /dev/null
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test2-CustomJavaImplCode.java.stub
@@ -0,0 +1,46 @@
+ public void alEventCallback0Inject(Object userParam, int eventType, int object, int param, String message) {
+ final Object userParam2;
+ final AlEventCallback0Data value;
+ synchronized( alEventCallback0Lock ) {
+ final AlEventCallback0Data value0 = alEventCallback0DataMap.get( new AlEventCallback0Key( userParam ) );
+ if( null != value0 ) {
+ userParam2 = alEventCallback0UserObjIDMap.get(value0.paramID);
+ if( userParam != userParam2 ) {
+ throw new InternalError("Impl issue-1: Arg userParam "+userParam+" != "+userParam2);
+ }
+ final AlEventCallback0Key key = new AlEventCallback0Key(userParam2);
+ value = alEventCallback0DataMap.get( key );
+ } else {
+ userParam2 = null;
+ value = null;
+ }
+ } // synchronized
+ if( null == value ) {
+ return;
+ }
+ value.func.callback(eventType, object, param, message.length(), message, userParam2);
+ }
+
+ public void alEventCallback1Inject(Object userParam, int eventType, int object, int param, String message) {
+ final Object userParam2;
+ final AlEventCallback1Data value;
+ synchronized( alEventCallback1Lock ) {
+ final AlEventCallback1Data value0 = alEventCallback1DataMap.get( new AlEventCallback1Key( object, userParam ) );
+ if( null != value0 ) {
+ userParam2 = alEventCallback1UserObjIDMap.get(value0.paramID);
+ if( userParam != userParam2 ) {
+ throw new InternalError("Impl issue-1: Arg userParam "+userParam+" != "+userParam2);
+ }
+ final AlEventCallback1Key key = new AlEventCallback1Key(object, userParam2);
+ value = alEventCallback1DataMap.get( key );
+ } else {
+ userParam2 = null;
+ value = null;
+ }
+ } // synchronized
+ if( null == value ) {
+ return;
+ }
+ value.func.callback(eventType, object, param, message.length(), message, userParam2);
+ }
+
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.c b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.c
index dafad7c..b9ad4aa 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.c
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.c
@@ -112,25 +112,6 @@ void InjectMessageCallback01(size_t id, const char* msg) {
//
//
-static ALEVENTPROCSOFT alEventCallback_cb = NULL;
-static void* alEventCallback_up = NULL;
-
-void alEventCallback(ALEVENTPROCSOFT callback, void *userParam) {
- alEventCallback_cb = callback;
- alEventCallback_up = userParam;
-}
-void alEventCallbackInject(int eventType, int object, int param, const char* msg) {
- if( NULL != alEventCallback_cb ) {
- fprintf(stderr, "XXX InjectMessageCallback01 func %p, user %p\n", alEventCallback_cb, alEventCallback_up);
- fflush(NULL);
- (*alEventCallback_cb)(eventType, object, param, strlen(msg), msg, alEventCallback_up);
- }
-}
-
-//
-//
-//
-
static const int MAX_AL_BUFFER = 5;
static ALBUFFERCALLBACKTYPESOFT alBufferCallback0_callback[] = { NULL, NULL, NULL, NULL, NULL };
static void* alBufferCallback0_userptr[] = { NULL, NULL, NULL, NULL, NULL };
@@ -192,6 +173,94 @@ void alBufferCallback1Inject(int buffer, int sampledata, int numbytes) {
//
//
+// typedef void ( * ALEVENTPROCSOFT)(int eventType, int object, int param, int length, const char *message, void *userParam);
+static const int MAX_EVENTCB_BUFFER = 5;
+
+static ALEVENTPROCSOFT ALEvent_callback0[] = { NULL, NULL, NULL, NULL, NULL };
+static void* ALEvent_userptr0[] = { NULL, NULL, NULL, NULL, NULL };
+
+void alEventCallback0(ALEVENTPROCSOFT callback, void *userParam /* key */) {
+ int idx;
+ if( NULL == callback ) {
+ // try matching key
+ for(idx = 0; idx<MAX_EVENTCB_BUFFER; ++idx) {
+ if( ALEvent_userptr0[idx] == userParam ) {
+ break;
+ }
+ }
+ } else {
+ // try matching callback first
+ for(idx = 0; idx<MAX_EVENTCB_BUFFER; ++idx) {
+ if( ALEvent_callback0[idx] == callback ) {
+ break;
+ }
+ }
+ if( MAX_EVENTCB_BUFFER <= idx ) {
+ // find free slot
+ for(idx = 0; idx<MAX_EVENTCB_BUFFER; ++idx) {
+ if( ALEvent_callback0[idx] == NULL ) {
+ break;
+ }
+ }
+ }
+ }
+ if( idx < 0 || MAX_EVENTCB_BUFFER <= idx ) {
+ fprintf(stderr, "Error: alEventCallback0: idx not in range [0..%d), is %d\n", MAX_EVENTCB_BUFFER, idx);
+ } else {
+ ALEvent_callback0[idx] = callback;
+ ALEvent_userptr0[idx] = (ALEVENTPROCSOFT*)userParam;
+ fprintf(stderr, "XXX alEventCallback0 idx %d -> func %p, user %p\n", idx, callback, userParam);
+ }
+ fflush(NULL);
+}
+
+//
+//
+//
+
+static ALEVENTPROCSOFT ALEvent_callback1[] = { NULL, NULL, NULL, NULL, NULL };
+static void* ALEvent_userptr1[] = { NULL, NULL, NULL, NULL, NULL };
+
+void alEventCallback1(int object /* key */, ALEVENTPROCSOFT callback, void *userParam /* key */) {
+ // TODO: Track object key
+ int idx;
+ if( NULL == callback ) {
+ // try matching key
+ for(idx = 0; idx<MAX_EVENTCB_BUFFER; ++idx) {
+ if( ALEvent_userptr1[idx] == userParam ) {
+ break;
+ }
+ }
+ } else {
+ // try matching callback first
+ for(idx = 0; idx<MAX_EVENTCB_BUFFER; ++idx) {
+ if( ALEvent_callback1[idx] == callback ) {
+ break;
+ }
+ }
+ if( MAX_EVENTCB_BUFFER <= idx ) {
+ // find free slot
+ for(idx = 0; idx<MAX_EVENTCB_BUFFER; ++idx) {
+ if( ALEvent_callback1[idx] == NULL ) {
+ break;
+ }
+ }
+ }
+ }
+ if( idx < 0 || MAX_EVENTCB_BUFFER <= idx ) {
+ fprintf(stderr, "Error: alEventCallback1: idx not in range [0..%d), is %d\n", MAX_EVENTCB_BUFFER, idx);
+ } else {
+ ALEvent_callback1[idx] = callback;
+ ALEvent_userptr1[idx] = (ALEVENTPROCSOFT*)userParam;
+ fprintf(stderr, "XXX alEventCallback1 idx %d -> func %p, user %p\n", idx, callback, userParam);
+ }
+ fflush(NULL);
+}
+
+//
+//
+//
+
static const int MAX_C11_BUFFER = 5;
static T2_CallbackFunc11 MessageCallback11a_callback[] = { NULL, NULL, NULL, NULL, NULL };
@@ -228,7 +297,7 @@ void MessageCallback11aInject(size_t id, long val) {
//
static T2_CallbackFunc11 MessageCallback11b_callback[] = { NULL, NULL, NULL, NULL, NULL };
-static T2_Callback11UserType MessageCallback11b_userptr[];
+static T2_Callback11UserType MessageCallback11b_userptr[5];
void MessageCallback11b(size_t id /* key */, T2_CallbackFunc11 cbFunc, void* Data) {
if( id < 0 || MAX_C11_BUFFER <= id ) {
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg
index d4ea72d..3a1c7b3 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg
@@ -71,33 +71,6 @@ JavaCallbackDef MessageCallback01 1 T2_CallbackFunc01 2
#
# End JavaCallback
-# Begin JavaCallback.
-#
-# typedef void ( * ALEVENTPROCSOFT)(int eventType, int object, int param, int length, const char *message, void *userParam);
-# void alEventCallback(ALEVENTPROCSOFT callback, void *userParam);
-# void alEventCallbackInject(int eventType, int object, int param, const char* msg);
-ArgumentIsPascalString ALEVENTPROCSOFT 3 4
-ArgumentIsString alEventCallbackInject 3
-
-# Define a JavaCallback (OpenAL AL_SOFT_events)
-# Set JavaCallback via function `alEventCallback` if `ALEVENTPROCSOFT` argument is non-null, otherwise removes the mapped callback and associated resources.
-#
-# It uses the function-pointer argument `ALEVENTPROCSOFT` as the callback function type
-# and marks `ALEVENTPROCSOFT`s 6th argument (index 5) as the mandatory user-param.
-#
-# This callback has no keys defines, rendering it of global scope!
-# The global key-less scope matches `AL_SOFT_events` semantics.
-#
-# Explicit maintenance methods are generated, passing the keys as paramters
-# - `boolean isAlEventCallbackMapped()` queries whether `alEventCallback` is mapped globally
-# - `ALEVENTPROCSOFT getAlEventCallback()` returns the global ALEVENTPROCSOFT, null if not mapped
-# - `Object getAlEventCallbackUserParam()` returns the global `userParam` object, null if not mapped
-# - `void releaseAlEventCallback()` releases callback data skipping toolkit API. Favor passing `null` callback ref to `alEventCallback(..)`
-JavaCallbackDef alEventCallback 1 ALEVENTPROCSOFT 5
-# JavaCallbackKey alEventCallback 1 ALEVENTPROCSOFT 5
-#
-# End JavaCallback
-
# Begin JavaCallback (OpanAL AL_SOFT_callback_buffer)
#
# // typedef void ( * ALBUFFERCALLBACKTYPESOFT)(int buffer /* key */, void *userptr, void *sampledata, int numbytes);
@@ -159,6 +132,37 @@ JavaCallbackKey alBufferCallback1 1 ALBUFFERCALLBACKTYPESOFT 0
#
# End JavaCallback
+# Begin JavaCallback.
+#
+# typedef void ( * ALEVENTPROCSOFT)(int eventType, int object, int param, int length, const char *message, void *userParam /* key */);
+#
+# void alEventCallback0(ALEVENTPROCSOFT callback, void *userParam /* key */);
+ArgumentIsPascalString ALEVENTPROCSOFT 3 4
+
+# Define a JavaCallback (OpenAL AL_SOFT_events)
+# Set JavaCallback via function `alEventCallback` if `ALEVENTPROCSOFT` argument is non-null, otherwise removes the mapped callback and associated resources.
+#
+# It uses the function-pointer argument `ALEVENTPROCSOFT` as the callback function type
+# and marks `ALEVENTPROCSOFT`s 6th argument (index 5) as the mandatory user-param.
+#
+# This callback uses 'Object userParam' as its key (for a context), similar to `AL_SOFT_events` context binding.
+JavaCallbackDef alEventCallback0 1 ALEVENTPROCSOFT 5
+JavaCallbackKey alEventCallback0 1 ALEVENTPROCSOFT 5
+#
+# End JavaCallback
+
+# Begin JavaCallback.
+#
+# void alEventCallback1(int object /* key */, ALEVENTPROCSOFT callback, void *userParam /* key */);
+JavaCallbackDef alEventCallback1 2 ALEVENTPROCSOFT 5
+JavaCallbackKey alEventCallback1 0 2 ALEVENTPROCSOFT 1 5
+
+#
+# End JavaCallback
+
+IncludeAs CustomJavaCode Bindingtest2 test2-CustomJavaIfCode.java.stub
+IncludeAs CustomJavaCode Bindingtest2Impl test2-CustomJavaImplCode.java.stub
+
# Begin JavaCallback
#
# typedef void ( * T2_CallbackFunc11)(size_t id, const T2_Callback11UserType* usrParam);
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.h b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.h
index dea6d72..ddd8c8a 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.h
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.h
@@ -67,14 +67,6 @@ void MessageCallback01(T2_CallbackFunc01 cbFunc, void* usrParam);
void InjectMessageCallback01(size_t id, const char* msg);
//
-// ALEVENTPROCSOFT (similar to OpenAL's AL_SOFT_events)
-//
-typedef void ( * ALEVENTPROCSOFT)(int eventType, int object, int param, int length, const char *message, void *userParam);
-
-void alEventCallback(ALEVENTPROCSOFT callback, void *userParam);
-void alEventCallbackInject(int eventType, int object, int param, const char* msg);
-
-//
// ALBUFFERCALLBACKTYPESOFT (similar to OpenAL's AL_SOFT_callback_buffer)
//
// typedef void ( * ALBUFFERCALLBACKTYPESOFT)(int buffer, void *userptr, void *sampledata, int numbytes);
@@ -89,6 +81,15 @@ void alBufferCallback1(void* user_ptr, int buffer_key /* key */, int format, int
void alBufferCallback1Inject(int buffer, int sampledata, int numbytes);
//
+// ALEVENTPROCSOFT (similar to OpenAL's AL_SOFT_events)
+//
+typedef void ( * ALEVENTPROCSOFT)(int eventType, int object, int param, int length, const char *message, void *userParam /* key */);
+
+void alEventCallback0(ALEVENTPROCSOFT callback, void *userParam /* key */);
+
+void alEventCallback1(int object /* key */, ALEVENTPROCSOFT callback, void *userParam /* key */);
+
+//
// T2_CallbackFunc11[ab]
//
typedef struct {