summaryrefslogtreecommitdiffstats
path: root/doc/manual/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'doc/manual/index.html')
-rwxr-xr-xdoc/manual/index.html293
1 files changed, 286 insertions, 7 deletions
diff --git a/doc/manual/index.html b/doc/manual/index.html
index e2e0fbc..ec1ff3a 100755
--- a/doc/manual/index.html
+++ b/doc/manual/index.html
@@ -44,13 +44,8 @@ Chapter 3 - Configuration File Examples<BR>
<LI> <a href = "#SecString">String handling</a>
<LI> <a href = "#SecMemory">Memory allocation</a>
<LI> <a href = "#SecStructs">Ingoing and outgoing structs</a>
-</UL>
-
-TO DO:
-
-<UL>
-<LI> Example with XVisualInfo* return type
-<LI> Example with GLXFBConfig* (e.g. glXChooseFBConfig)
+<LI> <a href = "#SecStructArrays">Returned arrays of structs</a>
+<LI> <a href = "#SecPointerArrays">Returned arrays of pointers</a>
</UL>
<H2> Chapter 1 - Introduction </H2>
@@ -1960,16 +1955,300 @@ is no longer reachable, as it is backed by a direct New I/O
<CODE>ByteBuffer</CODE>. The fields of the struct are exposed as
methods which supply both getters and setters. </P>
+<H3><a name="SecStructArrays">Returned arrays of structs</a></H3>
+
+Files:
+<UL>
+<LI> <a href="example6/function.h">function.h</a>
+<LI> <a href="example6/function.cfg">function.cfg</a>
+<LI> <a href="example6/gen.sh">gen.sh</a>
+</UL>
+
+<P> This example, taken from JOGL's X11 binding, illustrates how to
+return an array of structs from C to Java. The
+<CODE>XGetVisualInfo</CODE> function from the X library has the
+following signature: </P>
+
+<PRE>
+ XVisualInfo *XGetVisualInfo(
+ Display* display,
+ long vinfo_mask,
+ XVisualInfo* vinfo_template,
+ int* nitems_return
+ );
+</PRE>
+
+<P> Note that the <CODE>XVisualInfo</CODE> data structure itself
+contains many elements, including a pointer to the current visual. We
+use the following trick in the header file to cause GlueGen to treat
+the <CODE>Display*</CODE> in the above signature as well as the
+<CODE>Visual*</CODE> in the <CODE>XVisualInfo</CODE> as opaque
+pointers: </P>
+
+<PRE>
+ typedef struct {} Display;
+ typedef struct {} Visual;
+ typedef unsigned long VisualID;
+
+ typedef struct {
+ Visual *visual;
+ VisualID visualid;
+ int screen;
+ int depth;
+ int c_class; /* C++ */
+ unsigned long red_mask;
+ unsigned long green_mask;
+ unsigned long blue_mask;
+ int colormap_size;
+ int bits_per_rgb;
+ } XVisualInfo;
+</PRE>
+
+<P> <CODE>XGetVisualInfo</CODE> returns all of the available pixel
+formats in the form of <CODE>XVisualInfo</CODE>s which match a given
+template. <CODE>display</CODE> is the current connection to the X
+server. <CODE>vinfo_mask</CODE> indicates which fields from the
+template to match against. <CODE>vinfo_template</CODE> is a partially
+filled-in <CODE>XVisualInfo</CODE> specifying the characteristics to
+match. <CODE>nitems_return</CODE> is a pointer to an integer
+indicating how many <CODE>XVisualInfo</CODE>s were returned. The
+return value, rather than being a pointer to a single
+<CODE>XVisualInfo</CODE>, is a pointer to the start of an array of
+<CODE>XVisualInfo</CODE> data structures. </P>
+
+<P> There are two basic steps to being able to return this array
+properly to Java using GlueGen. The first is creating a direct
+ByteBuffer of the appropriate size in the autogenerated JNI code. The
+second is slicing up this ByteBuffer appropriately in order to return
+an <CODE>XVisualInfo[]</CODE> at the Java level. </P>
+
+<P> In the autogenerated JNI code, after the call to
+<CODE>XGetVisualInfo</CODE> is made, the outgoing
+<CODE>nitems_return</CODE> value points to the number of elements in
+the returned array, which indicates the size of the direct ByteBuffer
+which would need to wrap these elements. However, if we look at the
+implementation of one of the generated glue code variants for this
+method (specifically, the one taking an <CODE>int[]</CODE> as the
+third argument), we can see a problem in trying to access this value
+in the C code: </P>
+
+<PRE>
+JNIEXPORT jobject JNICALL
+Java_testfunction_TestFunction_XGetVisualInfo1__Ljava_nio_ByteBuffer_2JLjava_nio_ByteBuffer_2Ljava_lang_Object_2I(
+ JNIEnv *env, jclass _unused, jobject arg0, jlong arg1, jobject arg2, jobject arg3, jint arg3_byte_offset) {
+ ...
+ int * _ptr3 = NULL;
+ ...
+ if (arg3 != NULL) {
+ _ptr3 = (int *) (((char*) (*env)->GetPrimitiveArrayCritical(env, arg3, NULL)) + arg3_byte_offset);
+ }
+ _res = XGetVisualInfo((Display *) _ptr0, (long) arg1, (XVisualInfo *) _ptr2, (int *) _ptr3);
+ if (arg3 != NULL) {
+ (*env)->ReleasePrimitiveArrayCritical(env, arg3, _ptr3, 0);
+ }
+ if (_res == NULL) return NULL;
+ return (*env)->NewDirectByteBuffer(env, _res, ??? What to put here ???);
+}
+</PRE>
+
+<P> Note that at the point of the statement "What to put here?" the
+pointer to the storage of the <CODE>int[]</CODE>, <CODE>_ptr3</CODE>,
+has already been released via
+<CODE>ReleasePrimitiveArrayCritical</CODE>. This means that it may not
+be referenced at the point needed in the code. </P>
+
+<P> To solve this problem we use the <a
+href="#TemporaryCVariableDeclaration">TemporaryCVariableDeclaration</a>
+and <a
+href="#TemporaryCVariableAssignment">TemporaryCVariableAssignment</a>
+directives. We want to declare a persistent integer variable down in
+the C code and assign the returned array length to that variable
+before the primitive array is released. While in order to do this we
+unfortunately need to know something about the structure of the
+autogenerated JNI code, at least we don't have to hand-edit it
+afterward. We add the following directives to the configuration file: </P>
+
+<PRE>
+ # Get returned array's capacity from XGetVisualInfo to be correct
+ TemporaryCVariableDeclaration XGetVisualInfo int count;
+ TemporaryCVariableAssignment XGetVisualInfo count = _ptr3[0];
+</PRE>
+
+<P> Now in the autogenerated JNI code the variable "count" will
+contain the number of elements in the returned array. We can then
+reference this variable in a <a
+href="#ReturnValueCapacity">ReturnValueCapacity</a> directive: </P>
+
+<PRE>
+ ReturnValueCapacity XGetVisualInfo count * sizeof(XVisualInfo)
+</PRE>
+
+<P> At this point the <CODE>XGetVisualInfo</CODE> binding will return
+a Java-side <CODE>XVisualInfo</CODE> object whose backing ByteBuffer
+is the correct size. We now have to inform GlueGen that the underlying
+ByteBuffer represents not a single <CODE>XGetVisualInfo</CODE> struct,
+but an array of them, using the <a
+href="#ReturnedArrayLength">ReturnedArrayLength</a> directive. This
+conversion is performed on the Java side of the autogenerated code.
+Here, the first element of either the passed <CODE>IntBuffer</CODE> or
+<CODE>int[]</CODE> contains the number of elements in the returned
+array. (Alternatively, we could examine the length of the ByteBuffer
+returned from C to Java and divide by
+<CODE>XVisualInfo.size()</CODE>.) Because there are two overloadings
+produced by GlueGen for this method, if we reference the
+<CODE>nitems_return</CODE> argument in a <a
+href="#ReturnedArrayLength">ReturnedArrayLength</a> directive, we need
+to handle not only the differing data types properly
+(<CODE>IntBuffer</CODE> vs. <CODE>int[]</CODE>), but also the fact
+that both the integer array and its offset value are substituted for
+any reference to the fourth argument. </P>
+
+<P> To solve this problem, we define a pair of private helper
+functions whose purpose is to handle this overloading. </P>
+
+<PRE>
+ CustomJavaCode TestFunction private static int getFirstElement(IntBuffer buf) {
+ CustomJavaCode TestFunction return buf.get(buf.position());
+ CustomJavaCode TestFunction }
+ CustomJavaCode TestFunction private static int getFirstElement(int[] arr,
+ CustomJavaCode TestFunction int offset) {
+ CustomJavaCode TestFunction return arr[offset];
+ CustomJavaCode TestFunction }
+</PRE>
+
+<P> Now we can simply write for the returned array length: </P>
+
+<PRE>
+ ReturnedArrayLength XGetVisualInfo getFirstElement({3})
+</PRE>
+
+<P> That's all that is necessary. GlueGen will then produce the
+following Java-side overloadings for this function: </P>
+
+<PRE>
+ public static XVisualInfo[] XGetVisualInfo(Display arg0,
+ long arg1,
+ XVisualInfo arg2,
+ java.nio.IntBuffer arg3);
+ public static XVisualInfo[] XGetVisualInfo(Display arg0,
+ long arg1,
+ XVisualInfo arg2,
+ int[] arg3, int arg3_offset);
+</PRE>
+
+<P> As it happens, we don't really need the Display and Visual data
+structures to be produced; they can be treated as <CODE>long</CODE>s
+on the Java side. Therefore we can add the following directives to the
+configuration file: </P>
+
+<PRE>
+ # We don't need the Display and Visual data structures to be
+ # explicitly exposed
+ Opaque long Display *
+ Opaque long Visual *
+ # Ignore the empty Display and Visual data structures (though made
+ # opaque, the references from XVisualInfo and elsewhere are still
+ # traversed)
+ Ignore Display
+ Ignore Visual
+</PRE>
+
+<P> The final generated Java API is the following: </P>
+<PRE>
+ public static XVisualInfo[] XGetVisualInfo(long arg0,
+ long arg1,
+ XVisualInfo arg2,
+ java.nio.IntBuffer arg3);
+ public static XVisualInfo[] XGetVisualInfo(long arg0,
+ long arg1,
+ XVisualInfo arg2,
+ int[] arg3, int arg3_offset);
+</PRE>
+<H3><a name="SecPointerArrays">Returned arrays of pointers</a></H3>
+Files:
+<UL>
+<LI> <a href="example7/function.h">function.h</a>
+<LI> <a href="example7/function.cfg">function.cfg</a>
+<LI> <a href="example7/gen.sh">gen.sh</a>
+</UL>
+<P> As with the <a href="#SecStructArrays">example above</a>, this
+example is taken from JOGL's X11 binding. Here we show how to expose
+to Java a C routine returning an array of pointers to a data
+structure. </P>
+<P> The declaration of the function we are binding is as follows: </P>
+<PRE>
+ typedef struct __GLXFBConfigRec *GLXFBConfig;
+ GLXFBConfig *glXChooseFBConfig( Display *dpy, int screen,
+ const int *attribList, int *nitems );
+</PRE>
+<P> This function is used during allocation of a hardware-accelerated
+off-screen surface ("pbuffer") on X11 platforms; its exact meaning is
+not important. The semantics of the arguments and return value are as
+follows. As in the <a href="#SecStructArrays">previous example</a>, it
+accepts a connection to the current X display as one argument. The
+screen of this display is the second argument. The
+<CODE>attribList</CODE> is a zero-terminated list of integer
+attributes; because it is zero-terminated, the length of this list is
+not passed to the function. As in the previous example, the
+<CODE>nitems</CODE> argument points to an integer into which the
+number of returned <CODE>GLXFBConfig</CODE> objects is placed. The
+return value is an array of <CODE>GLXFBConfig</CODE> objects. </P>
+
+<P> Because the <CODE>GLXFBConfig</CODE> data type is typedefed as a
+pointer to an opaque (undefined) struct, the construct
+<CODE>GLXFBConfig*</CODE> is implicitly a "pointer-to-pointer" type.
+GlueGen automatically assumes this is convertible to a Java-side array
+of accessors to structs. The only configuration necessary is to tell
+GlueGen the length of this array. </P>
+
+<P> As in the previous example, we use the <a
+href="#TemporaryCVariableDeclaration">TemporaryCVariableDeclaration</a>
+and <a
+href="#TemporaryCVariableAssignment">TemporaryCVariableAssignment</a>
+directives to capture the length of the returned array: </P>
+TemporaryCVariableDeclaration glXChooseFBConfig int count;
+TemporaryCVariableAssignment glXChooseFBConfig count = _ptr3[0];
+
+<P> The structure of the generated glue code for the return value is
+subtly different than in the previous example. The question in this
+case is not whether the return value is a pointer to a single object
+vs. a pointer to an array of objects; it is what the length of the
+returned array is, since we already know that the return type is
+pointer-to-pointer and is therefore an array. We use the <a
+href="#ReturnValueLength">ReturnValueLength</a> directive for this
+case: </P>
+
+<PRE>
+ ReturnValueLength glXChooseFBConfig count
+</PRE>
+
+We add similar Opaque directives to the previous example to yield the
+resulting Java bindings for this function:
+
+<PRE>
+ public static GLXFBConfig[] glXChooseFBConfig(long dpy,
+ int screen,
+ java.nio.IntBuffer attribList,
+ java.nio.IntBuffer nitems);
+ public static GLXFBConfig[] glXChooseFBConfig(long dpy,
+ int screen,
+ int[] attribList, int attribList_offset,
+ int[] nitems, int nitems_offset);
+</PRE>
+Note that because the GLXFBConfig data type is returned as an element
+of an array, we can not use the Opaque directive to erase this data
+type to <CODE>long</CODE> as we did with the <CODE>Display</CODE> data
+type.
</BODY>
</HTML>