java-gobject-introspection r105 - in trunk: src/org/gnome/gir/compiler src/org/gnome/gir/gobject stub-examples



Author: walters
Date: Thu Oct 23 03:15:12 2008
New Revision: 105
URL: http://svn.gnome.org/viewvc/java-gobject-introspection?rev=105&view=rev

Log:
Generate DestroyNotify handlers for functions which take them


Added:
   trunk/src/org/gnome/gir/gobject/GSourceFunc.java
   trunk/src/org/gnome/gir/gobject/GlibRuntime.java
Modified:
   trunk/src/org/gnome/gir/compiler/CodeFactory.java
   trunk/src/org/gnome/gir/gobject/GObject.java
   trunk/src/org/gnome/gir/gobject/GSource.java
   trunk/src/org/gnome/gir/gobject/GType.java
   trunk/src/org/gnome/gir/gobject/GlibAPI.java
   trunk/src/org/gnome/gir/gobject/MainLoop.java
   trunk/stub-examples/Test.java

Modified: trunk/src/org/gnome/gir/compiler/CodeFactory.java
==============================================================================
--- trunk/src/org/gnome/gir/compiler/CodeFactory.java	(original)
+++ trunk/src/org/gnome/gir/compiler/CodeFactory.java	Thu Oct 23 03:15:12 2008
@@ -78,6 +78,8 @@
 import org.gnome.gir.gobject.GObjectAPI;
 import org.gnome.gir.gobject.GSList;
 import org.gnome.gir.gobject.GType;
+import org.gnome.gir.gobject.GlibAPI;
+import org.gnome.gir.gobject.GlibRuntime;
 import org.gnome.gir.gobject.UnmappedPointer;
 import org.gnome.gir.gobject.annotation.Return;
 import org.gnome.gir.repository.ArgInfo;
@@ -115,6 +117,7 @@
 import org.objectweb.asm.Type;
 import org.objectweb.asm.util.CheckClassAdapter;
 
+import com.sun.jna.Callback;
 import com.sun.jna.Function;
 import com.sun.jna.Native;
 import com.sun.jna.NativeLibrary;
@@ -1392,7 +1395,7 @@
 		Map<Integer, Integer> lengthOfArrayIndices = new HashMap<Integer,Integer>();
 		Map<Integer, Integer> arrayToLengthIndices = new HashMap<Integer,Integer>();
 		Set<Integer> userDataIndices = new HashSet<Integer>();
-		Set<Integer> destroyNotifyIndices = new HashSet<Integer>();		
+		Map<Integer,Integer> destroyNotifyIndices = new HashMap<Integer,Integer>();		
 		
 		public CallableCompilationContext() {
 			// TODO Auto-generated constructor stub
@@ -1410,7 +1413,7 @@
 			Set<Integer> eliminated = new HashSet<Integer>();
 			eliminated.addAll(lengthOfArrayIndices.keySet());
 			eliminated.addAll(userDataIndices);
-			eliminated.addAll(destroyNotifyIndices);
+			eliminated.addAll(destroyNotifyIndices.keySet());
 			return eliminated;
 		}
 		
@@ -1473,6 +1476,7 @@
 		ArgInfo[] args = ctx.args;
 		
 		List<Type> types = new ArrayList<Type>();		
+		int firstSeenCallback = -1;
 		for (int i = 0; i < args.length; i++) {
 			ArgInfo arg = args[i];
 			Type t;
@@ -1484,34 +1488,38 @@
 				logger.warning("Skipping callable with invalid error argument: " + si.getIdentifier());
 				return null;
 			}
+			int argOffset = i;
+			if (ctx.isMethod) argOffset++;			
 			if (tag.equals(TypeTag.VOID) && arg.getName().contains("data")) {
-				int dataIdx = i;
-				if (ctx.isMethod) dataIdx++;
-				ctx.userDataIndices.add(dataIdx);
+				ctx.userDataIndices.add(argOffset);
 				continue;
 			} else if (isDestroyNotify(arg)) {
-				int dataIdx = i;
-				if (ctx.isMethod) dataIdx++;
-				ctx.destroyNotifyIndices.add(dataIdx);
+				if (firstSeenCallback == -1) {
+					logger.warning("Skipping callable with unpaired DestroyNotify: " + si.getIdentifier());
+					return null;
+				}
+				ctx.destroyNotifyIndices.put(argOffset, firstSeenCallback);
 				continue;
-			}
+			} else if (arg.getDirection() == Direction.IN &&
+					info.getTag().equals(TypeTag.INTERFACE) &&
+					info.getInterface() instanceof CallbackInfo) {
+				if (firstSeenCallback >= 0) {
+					logger.warning("Skipping callable with unpaired multiple callbacks: " + si.getIdentifier());
+					return null;					
+				}			
+				firstSeenCallback = argOffset;
+			} else if (tag.equals(TypeTag.ARRAY) && arg.getDirection().equals(Direction.IN)) {
+				int lenIdx = arg.getType().getArrayLength();
+				if (lenIdx >= 0) {
+					ctx.lengthOfArrayIndices.put(lenIdx, argOffset);
+					ctx.arrayToLengthIndices.put(argOffset, lenIdx);
+				}
+			}	
 			t = toJava(arg);
 			if (t == null) {
 				logger.warning(String.format("Unhandled argument %s in callable %s", arg, si.getIdentifier()));
 				return null;
 			}
-			if (tag.equals(TypeTag.ARRAY) && arg.getDirection().equals(Direction.IN)) {
-				int lenIdx = arg.getType().getArrayLength();
-				if (lenIdx >= 0) {
-					/* FIXME - remove this hack when the repository is fixed */
-					int arrIdx = i;
-					if (ctx.isMethod) {
-						arrIdx++;
-					} 
-					ctx.lengthOfArrayIndices.put(lenIdx, arrIdx);
-					ctx.arrayToLengthIndices.put(arrIdx, lenIdx);
-				}
-			}			
 			types.add(t);
 			ctx.argNames.add(arg.getName());
 		}
@@ -1723,6 +1731,7 @@
 			mv.visitIntInsn(BIPUSH, i);
 			Integer arraySource = ctx.lengthOfArrayIndices.get(i);
 			Integer lengthOfArray = ctx.arrayToLengthIndices.get(i);
+			Integer callbackIdx = ctx.destroyNotifyIndices.get(i);
 			if (arraySource != null) {
 				ArgInfo source = ctx.args[arraySource - (ctx.isMethod ? 1 : 0)];
 				assert source.getType().getTag().equals(TypeTag.ARRAY);
@@ -1735,12 +1744,15 @@
 			} else if (lengthOfArray != null) {
 				LocalVariable var = locals.get(lengthOfArray);
 				writeLoadArgument(mv, var.offset, var.type);
-			} else if (ctx.userDataIndices.contains(i) || ctx.destroyNotifyIndices.contains(i)) {
+			} else if (ctx.userDataIndices.contains(i)) {
 				/* Always pass null for user datas - Java allows environment capture */
-				/* For destroy notifies, we always pass null too; in the future we may want
-				 * to clean up any allocated callback data here?
-				 */
 				mv.visitInsn(ACONST_NULL);
+			} else if (callbackIdx != null) {
+				int offset = ctx.argOffsetToApi(callbackIdx);
+				LocalVariable var = locals.get(offset);
+				writeLoadArgument(mv, var.offset, var.type);				
+				mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(GlibRuntime.class), "createDestroyNotify", 
+						Type.getMethodDescriptor(getType(GlibAPI.GDestroyNotify.class), new Type[] { getType(Callback.class) } ));
 			} else if (!ctx.isMethod || i > 0) {
 				int localOff = ctx.argOffsetToApi(i);
 				LocalVariable var = locals.get(localOff);	

Modified: trunk/src/org/gnome/gir/gobject/GObject.java
==============================================================================
--- trunk/src/org/gnome/gir/gobject/GObject.java	(original)
+++ trunk/src/org/gnome/gir/gobject/GObject.java	Thu Oct 23 03:15:12 2008
@@ -71,7 +71,7 @@
     
     private static final boolean debugMemory = false;
     
-    private static final void debugMemory(String fmt, String... args) {
+    private static final void debugMemory(String fmt, Object... args) {
     	if (debugMemory)
     		System.err.println(String.format(fmt, (Object[])args));
     }
@@ -105,7 +105,6 @@
     public GObject(Initializer init) { 
         super(init.needRef ? initializer(init.ptr, false, init.ownsHandle) : init);
         if (init.ownsHandle) {
-        	debugMemory("INIT OWNERSHIP " + this);
             strongReferences.put(this, Boolean.TRUE);
             
             /* Floating refs are just a convenience for C; we always want only strong
@@ -113,7 +112,6 @@
              */
             boolean wasFloating = GObjectAPI.gobj.g_object_is_floating(this);
             if (wasFloating) {
-            	debugMemory("Sinking " + this);
             	GObjectAPI.gobj.g_object_ref_sink(this);
             }
             
@@ -224,22 +222,22 @@
     }
     @Override
     protected void ref() {
-    	debugMemory("REF " + this);    	
+    	debugMemory("REF %s", this);    	
     	GObjectAPI.gobj.g_object_ref(this);
     }
 
     @Override
     protected void unref() {
-    	debugMemory("UNREF " + this);    	
+    	debugMemory("UNREF %s", this);    	
     	GObjectAPI.gobj.g_object_unref(this);
     }
     protected void invalidate() {
         try {
-        	debugMemory("INVALIDATE " + this);        	
+        	debugMemory("INVALIDATE %s", this);        	
             // Need to increase the ref count before removing the toggle ref, so 
             // ensure the native object is not destroyed.
             if (ownsHandle.get()) {
-            	debugMemory("REMOVING TOGGLE " + this);             	
+            	debugMemory("REMOVING TOGGLE %s", this);             	
                 ref();
 
                 // Disconnect the callback.
@@ -323,7 +321,6 @@
              * be retained for later retrieval
              */
             GObject o = (GObject) NativeObject.instanceFor(ptr);
-            debugMemory(String.format("TOGGLE o=%s is_last=%s", o, is_last_ref));
             if (o == null) {
                 return;
             }
@@ -339,7 +336,7 @@
 		@Override
 		public void callback(Pointer data, Pointer obj) {
 			GObject o = (GObject) NativeObject.instanceFor(obj);
-            debugMemory(String.format("WEAK o=%s obj=%s", o, obj));			
+            debugMemory("WEAK o=%s obj=%s", o, obj);			
 			// Clear out the signal handler references
 			if (o == null)
 				return;

Modified: trunk/src/org/gnome/gir/gobject/GSource.java
==============================================================================
--- trunk/src/org/gnome/gir/gobject/GSource.java	(original)
+++ trunk/src/org/gnome/gir/gobject/GSource.java	Thu Oct 23 03:15:12 2008
@@ -61,7 +61,7 @@
         return GlibAPI.glib.g_source_attach(this, context);
     }
     public void setCallback(final Callable<Boolean> call) {
-        this.callback = new GlibAPI.GSourceFunc() {
+        this.callback = new GSourceFunc() {
             public boolean callback(Pointer data) {
                 if (GlibAPI.glib.g_source_is_destroyed(handle())) {
                     return false;
@@ -75,7 +75,7 @@
         };
         GlibAPI.glib.g_source_set_callback(this, callback, null, null);
     }
-    private GlibAPI.GSourceFunc callback;
+    private GSourceFunc callback;
     
     protected void ref() {
         GlibAPI.glib.g_source_ref(handle());

Added: trunk/src/org/gnome/gir/gobject/GSourceFunc.java
==============================================================================
--- (empty file)
+++ trunk/src/org/gnome/gir/gobject/GSourceFunc.java	Thu Oct 23 03:15:12 2008
@@ -0,0 +1,11 @@
+/**
+ * 
+ */
+package org.gnome.gir.gobject;
+
+import com.sun.jna.Callback;
+import com.sun.jna.Pointer;
+
+public interface GSourceFunc extends Callback {
+    boolean callback(Pointer data);
+}
\ No newline at end of file

Modified: trunk/src/org/gnome/gir/gobject/GType.java
==============================================================================
--- trunk/src/org/gnome/gir/gobject/GType.java	(original)
+++ trunk/src/org/gnome/gir/gobject/GType.java	Thu Oct 23 03:15:12 2008
@@ -86,9 +86,10 @@
 			put("GLib.Mutex", "org/gnome/gir/gobject/GlibAPI$GMutex");
 			put("GLib.StaticRecMutex", "org/gnome/gir/gobject/GlibAPI$GStaticRecMutex");
 			put("GLib.IOFunc", "org/gnome/gir/gobject/GIOFunc");
+			put("GLib.SourceFunc", "org/gnome/gir/gobject/GSourceFunc");		
 			
 			String[] glibPointerUnmapped = new String[] { "Mutex", "Cond", "FreeFunc", "DestroyNotify", "MarkupParser",
-					"SpawnChildSetupFunc", "SourceFunc", "Node", "CompareFunc", "KeyFile", "PtrArray", "Func",
+					"SpawnChildSetupFunc", "Node", "CompareFunc", "KeyFile", "PtrArray", "Func",
 					"ThreadPool", "Source", "CompareDataFunc", "Array", "Data", "DataSet", "Date", "IOChannel" };
 			for (String unmapped : glibPointerUnmapped)
 				put("GLib." + unmapped, "com/sun/jna/Pointer");
@@ -99,6 +100,7 @@
 			put("GObject.ParamSpec", "org/gnome/gir/gobject/GObjectAPI$GParamSpec");
 			put("GObject.Parameter", "org/gnome/gir/gobject/GObjectAPI$GParameter");				
 			put("GObject.Object", "org/gnome/gir/gobject/GObject");
+			put("GObject.Callback", "com/sun/jna/Callback");
 			put("GObject.InitiallyUnowned", "org/gnome/gir/gobject/GInitiallyUnowned");					
 			put("GObject.Type", "org/gnome/gir/gobject/GType");
 			put("GObject.Value", "org/gnome/gir/gobject/GValue");			
@@ -124,7 +126,7 @@
 			put("GObject.FlagsValue", "org/gnome/gir/gobject/GObjectAPI$GFlagsValue");
 			put("GObject.FlagsClass", "org/gnome/gir/gobject/GObjectAPI$GFlagsClass");
 			
-			String[] gobjectUnmapped = new String[] { "Callback", "BaseInitFunc", "InstanceInitFunc", 
+			String[] gobjectUnmapped = new String[] { "BaseInitFunc", "InstanceInitFunc", 
 					"SignalAccumulator", "ClosureMarshal", "ClassInitFunc", "SignalEmissionHook",
 					"IOChannel", "Date", "BaseFinalizeFunc", "ClassFinalizeFunc", "ValueArray" };
 			for (String unmapped : gobjectUnmapped)

Modified: trunk/src/org/gnome/gir/gobject/GlibAPI.java
==============================================================================
--- trunk/src/org/gnome/gir/gobject/GlibAPI.java	(original)
+++ trunk/src/org/gnome/gir/gobject/GlibAPI.java	Thu Oct 23 03:15:12 2008
@@ -114,11 +114,7 @@
     void g_thread_set_priority(Pointer thread, int priority);
     void g_thread_exit(Pointer retval);
     
-    
-    
-    interface GSourceFunc extends Callback {
-        boolean callback(Pointer data);
-    }
+
     NativeLong g_idle_add(GSourceFunc function, Pointer data);
     interface GDestroyNotify extends Callback {
         void callback(Pointer data);
@@ -128,6 +124,7 @@
     int g_timeout_add_full(int priority, int interval, GSourceFunc function,
             Pointer data, GDestroyNotify notify);
     int g_timeout_add_seconds(int interval, GSourceFunc function, Pointer data);
+    int g_timeout_add_seconds_full(int priority, int interval, GSourceFunc function, Pointer data, GDestroyNotify destroy);    
     void g_error_free(Pointer error);
     void g_error_free(GErrorStruct error);
     

Added: trunk/src/org/gnome/gir/gobject/GlibRuntime.java
==============================================================================
--- (empty file)
+++ trunk/src/org/gnome/gir/gobject/GlibRuntime.java	Thu Oct 23 03:15:12 2008
@@ -0,0 +1,57 @@
+/* 
+ * Copyright (c) 2008 Colin Walters <walters verbum org>
+ * 
+ * This file is part of java-gobject-introspection.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
+ * Boston, MA  02111-1307  USA.
+ *
+ */
+
+package org.gnome.gir.gobject;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import com.sun.jna.Callback;
+import com.sun.jna.Pointer;
+
+public class GlibRuntime {
+	private static final class CallbackData {
+		Callback callback;
+		GlibAPI.GDestroyNotify destroy;
+	}
+	/*
+	 * We want to hold a strong reference to both the callback and the destroy
+	 * notify, until the notify is called.
+	 */
+	private static final Set<CallbackData> outstandingCallbacks 
+		= Collections.synchronizedSet(new HashSet<CallbackData>());
+	
+	public static final GlibAPI.GDestroyNotify createDestroyNotify(Callback callback) {
+		final CallbackData data = new CallbackData();
+		GlibAPI.GDestroyNotify destroy = new GlibAPI.GDestroyNotify() {
+			@Override
+			public void callback(Pointer data) {
+				outstandingCallbacks.remove(data);
+			}
+		};
+		data.callback = callback;
+		data.destroy = destroy;
+		outstandingCallbacks.add(data);
+		return destroy;
+	}
+}

Modified: trunk/src/org/gnome/gir/gobject/MainLoop.java
==============================================================================
--- trunk/src/org/gnome/gir/gobject/MainLoop.java	(original)
+++ trunk/src/org/gnome/gir/gobject/MainLoop.java	Thu Oct 23 03:15:12 2008
@@ -54,7 +54,6 @@
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicLong;
 
-import org.gnome.gir.gobject.GlibAPI.GSourceFunc;
 
 import com.sun.jna.Pointer;
 
@@ -219,7 +218,7 @@
 			public boolean callback(Pointer data) {
 				try {
 					r.run();
-				} catch (Throwable e) {
+				} catch (Exception e) {
 					Thread.currentThread().getUncaughtExceptionHandler()
 						.uncaughtException(Thread.currentThread(), e);
 				} finally {
@@ -234,7 +233,8 @@
     
     private int rawInvokeLater(final Runnable r) {
     	GSourceFunc func = sourceFuncForRunnable(r, null);
-    	return GlibAPI.glib.g_timeout_add(0, func, null);   	
+    	GlibAPI.GDestroyNotify destroy = GlibRuntime.createDestroyNotify(func);
+    	return GlibAPI.glib.g_timeout_add_full(0, 0, func, null, destroy);   	
     }
     
     /**
@@ -255,11 +255,12 @@
 				handle.setComplete();
 			}
     	});
+    	GlibAPI.GDestroyNotify destroy = GlibRuntime.createDestroyNotify(func);    	
     	int id;
     	if (units.equals(TimeUnit.SECONDS)) {
-    		id = GlibAPI.glib.g_timeout_add_seconds(timeout, func, null);
+    		id = GlibAPI.glib.g_timeout_add_seconds_full(0, timeout, func, null, destroy);
     	} else {
-    		id = GlibAPI.glib.g_timeout_add((int) units.toMillis(timeout), func, null);
+    		id = GlibAPI.glib.g_timeout_add_full(0, (int) units.toMillis(timeout), func, null, destroy);
     	}
     	handle.srcId = id;
     	return handle;

Modified: trunk/stub-examples/Test.java
==============================================================================
--- trunk/stub-examples/Test.java	(original)
+++ trunk/stub-examples/Test.java	Thu Oct 23 03:15:12 2008
@@ -33,7 +33,8 @@
 	}
 	
 	public int bar(String foo, byte[] bytes) {
-		Function target = Internals.library.getFunction("gtk_write_buf");	
+		Function target = Internals.library.getFunction("gtk_write_buf");
+		
 		Object[] args = new Object[] { foo, bytes.length, bytes };
 		Integer result = (Integer) target.invoke(Integer.class, args, Internals.invocationOptions);
 		return result;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]