diff --git a/ChangeLog b/ChangeLog index 37d5e975b..4c1ef253c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2005-08-09 Dan Winship + + * generator/OpaqueGen.cs (Generate): Tweak the generated Ref/Unref + a bit; only Ref the pointer if Owned is false (and then set it to + true), and vice versa for Unref. + + * glib/Opaque.cs (Opaque): set owned before setting Raw, so + that Raw will be reffed properly. + (GetOpaque): Fix this up to dtrt in all cases with refcounted + opaques. + + * gtk/TreeView.custom (GetPathAtPos): Use "GetOpaque(...)" rather + than "new TreePath()" + + * sample/opaquetest/*: regression test for opaque free/ref/unref + handling + + * sample/Makefile.am (SUBDIRS): add opaquetest + + * configure.in.in (AC_OUTPUT): add opaquetest files + 2005-08-04 Dan Winship Change the way generatable validation works. Some generatable diff --git a/configure.in.in b/configure.in.in index 867f2175d..bac1da4dd 100644 --- a/configure.in.in +++ b/configure.in.in @@ -313,6 +313,8 @@ sample/rsvg/Makefile sample/test/Makefile sample/valtest/Makefile sample/valtest/valtest.exe.config +sample/opaquetest/Makefile +sample/opaquetest/opaquetest.exe.config sample/cairo-sample.exe.config ]) diff --git a/doc/en/GLib/Opaque.xml b/doc/en/GLib/Opaque.xml index adaf4e312..e3d4d1a6a 100644 --- a/doc/en/GLib/Opaque.xml +++ b/doc/en/GLib/Opaque.xml @@ -177,7 +177,7 @@ Whether or not this wrapper owns the raw object. - if the wrapper owns the raw object. + if the wrapper owns the raw object and will / it when the wrapper is disposed. By default, this is set to for opaque objects created with the no-argument constructor, and for opaque objects created with the constructor. Methods that return an opaque object can override this by setting the property accordingly to obey the memory-management conventions of the underlying C code. diff --git a/generator/OpaqueGen.cs b/generator/OpaqueGen.cs index 44cc7dcf6..c47c739b4 100644 --- a/generator/OpaqueGen.cs +++ b/generator/OpaqueGen.cs @@ -78,7 +78,10 @@ namespace GtkSharp.Generation { ref_.GenerateImport (sw); sw.WriteLine ("\t\tprotected override void Ref (IntPtr raw)"); sw.WriteLine ("\t\t{"); - sw.WriteLine ("\t\t\t" + ref_.CName + " (raw);"); + sw.WriteLine ("\t\t\tif (!Owned) {"); + sw.WriteLine ("\t\t\t\t" + ref_.CName + " (raw);"); + sw.WriteLine ("\t\t\t\tOwned = true;"); + sw.WriteLine ("\t\t\t}"); sw.WriteLine ("\t\t}"); sw.WriteLine (); @@ -95,7 +98,10 @@ namespace GtkSharp.Generation { unref.GenerateImport (sw); sw.WriteLine ("\t\tprotected override void Unref (IntPtr raw)"); sw.WriteLine ("\t\t{"); - sw.WriteLine ("\t\t\t" + unref.CName + " (raw);"); + sw.WriteLine ("\t\t\tif (Owned) {"); + sw.WriteLine ("\t\t\t\t" + unref.CName + " (raw);"); + sw.WriteLine ("\t\t\t\tOwned = false;"); + sw.WriteLine ("\t\t\t}"); sw.WriteLine ("\t\t}"); sw.WriteLine (); diff --git a/glib/Opaque.cs b/glib/Opaque.cs index f75ff8ee2..986413ae2 100644 --- a/glib/Opaque.cs +++ b/glib/Opaque.cs @@ -65,7 +65,13 @@ namespace GLib { } opaque = (Opaque)Activator.CreateInstance (type, new object[] { o }); - opaque.owned = owned; + if (owned) { + if (opaque.owned) { + // The constructor took a Ref it shouldn't have, so undo it + opaque.Unref (o); + } else + opaque.owned = true; + } return opaque; } @@ -76,8 +82,8 @@ namespace GLib { public Opaque (IntPtr raw) { - Raw = raw; owned = false; + Raw = raw; } protected IntPtr Raw { diff --git a/gtk/TreeView.custom b/gtk/TreeView.custom index 9323f6adb..0e3c817ac 100644 --- a/gtk/TreeView.custom +++ b/gtk/TreeView.custom @@ -81,8 +81,7 @@ bool raw_ret = gtk_tree_view_get_path_at_pos (Handle, x, y, out pathHandle, out columnHandle, out cell_x, out cell_y); if (raw_ret) { column = (Gtk.TreeViewColumn) GLib.Object.GetObject (columnHandle, false); - path = new TreePath (pathHandle); - path.Owned = true; + path = (Gtk.TreePath) GLib.Opaque.GetOpaque (pathHandle, typeof (Gtk.TreePath), true); } else { path = null; column = null; @@ -97,10 +96,9 @@ IntPtr pathHandle; IntPtr columnHandle; bool raw_ret = gtk_tree_view_get_path_at_pos_intptr (Handle, x, y, out pathHandle, out columnHandle, IntPtr.Zero, IntPtr.Zero); - if (raw_ret) { - path = new TreePath (pathHandle); - path.Owned = true; - } else + if (raw_ret) + path = (Gtk.TreePath) GLib.Opaque.GetOpaque (pathHandle, typeof (Gtk.TreePath), true); + else path = null; return raw_ret; @@ -112,8 +110,7 @@ IntPtr columnHandle; bool raw_ret = gtk_tree_view_get_path_at_pos_intptr (Handle, x, y, out pathHandle, out columnHandle, IntPtr.Zero, IntPtr.Zero); if (raw_ret) { - path = new TreePath (pathHandle); - path.Owned = true; + path = (Gtk.TreePath) GLib.Opaque.GetOpaque (pathHandle, typeof (Gtk.TreePath), true); column = (Gtk.TreeViewColumn) GLib.Object.GetObject (columnHandle, false); } else { path = null; diff --git a/sample/Makefile.am b/sample/Makefile.am index a62d0f9fc..31132223e 100755 --- a/sample/Makefile.am +++ b/sample/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gconf rsvg test GtkDemo pixmaps gnomevfs valtest +SUBDIRS = gconf rsvg test GtkDemo pixmaps gnomevfs valtest opaquetest if ENABLE_GNOME GNOME_TARGETS=gnome-hello-world.exe canvas-example.exe fifteen.exe print.exe diff --git a/sample/opaquetest/Makefile.am b/sample/opaquetest/Makefile.am new file mode 100644 index 000000000..177d003fc --- /dev/null +++ b/sample/opaquetest/Makefile.am @@ -0,0 +1,30 @@ +noinst_SCRIPTS = opaquetest.exe +lib_LTLIBRARIES = libopaque.la + +assemblies=../../glib/glib-sharp.dll ../../pango/pango-sharp.dll ../../atk/atk-sharp.dll ../../gdk/gdk-sharp.dll ../../gtk/gtk-sharp.dll +references=$(addprefix /r:, $(assemblies)) + +opaquetest.exe: OpaqueTest.cs generated/*.cs $(assemblies) + $(CSC) /out:opaquetest.exe $(references) $(srcdir)/OpaqueTest.cs generated/*.cs + +libopaque_la_SOURCES = \ + opaques.c \ + opaques.h + +libopaque_la_LDFLAGS = -module -avoid-version -no-undefined + +libopaque_la_LIBADD = $(GTK_LIBS) + +INCLUDES = $(GTK_CFLAGS) + +generated/*.cs: opaque-api.xml + $(RUNTIME) ../../generator/gapi_codegen.exe --generate opaque-api.xml --include ../../gtk/gtk-api.xml ../../gdk/gdk-api.xml --outdir=generated --assembly-name=opaque-sharp + +api: + PATH=../../parser:$PATH $(RUNTIME) ../../parser/gapi-parser.exe opaque-sources.xml + $(RUNTIME) ../../parser/gapi-fixup.exe --metadata=Opaque.metadata --api=opaque-api.xml + +install: + +CLEANFILES = \ + generated/*.cs diff --git a/sample/opaquetest/Opaque.metadata b/sample/opaquetest/Opaque.metadata new file mode 100644 index 000000000..5d05f152e --- /dev/null +++ b/sample/opaquetest/Opaque.metadata @@ -0,0 +1,5 @@ + + + 1 + 1 + diff --git a/sample/opaquetest/OpaqueTest.cs b/sample/opaquetest/OpaqueTest.cs new file mode 100644 index 000000000..f8bef9366 --- /dev/null +++ b/sample/opaquetest/OpaqueTest.cs @@ -0,0 +1,282 @@ +// Opaquetest.cs: GLib.Opaque regression test +// +// Copyright (c) 2005 Novell, Inc. + +using Gtksharp; +using System; + +public class OpaqueTest { + + static int errors = 0; + + static void GC () + { + System.GC.Collect (); + System.GC.WaitForPendingFinalizers (); + System.GC.Collect (); + System.GC.WaitForPendingFinalizers (); + } + + public static int Main () + { + Gtk.Application.Init (); + + TestOpaque (); + Console.WriteLine (); + TestRefcounted (); + Console.WriteLine (); + + Console.WriteLine ("{0} errors", errors); + + return errors; + } + + static Opaque ret_op; + + static Opaque ReturnOpaque () + { + return ret_op; + } + + static void TestOpaque () + { + Opaque op, op1; + IntPtr handle; + + Console.WriteLine ("Testing Opaque new/free"); + op = new Opaque (); + if (!op.Owned) + Error ("Newly-created Opaque is not Owned"); + handle = op.Handle; + op.Dispose (); + op = new Opaque (handle); + if (op.Owned) + Error ("IntPtr-created Opaque is Owned"); + if (Opaquetest.Error) + Error ("Memory error after initial new/free."); + Opaquetest.ExpectError = true; + if (op.Serial != Opaque.LastSerial) + Error ("Serial mismatch. Expected {0}, Got {1}", Opaque.LastSerial, op.Serial); + if (!Opaquetest.Error) + Error ("Opaque not properly freed."); + op.Dispose (); + if (Opaquetest.Error) + Error ("Opaque created from IntPtr was freed by gtk#"); + + Console.WriteLine ("Testing Opaque copy/free"); + op = new Opaque (); + op1 = op.Copy (); + handle = op1.Handle; + op.Dispose (); + op1.Dispose (); + if (Opaquetest.Error) + Error ("Memory error after initial copy/free."); + op = new Opaque (handle); + Opaquetest.ExpectError = true; + if (op.Serial != Opaque.LastSerial) + Error ("Serial mismatch. Expected {0}, Got {1}", Opaque.LastSerial, op.Serial); + + if (!Opaquetest.Error) + Error ("Opaque not properly freed."); + op.Dispose (); + if (Opaquetest.Error) + Error ("Opaque created from IntPtr was freed by gtk#"); + + Console.WriteLine ("Testing non-owned return."); + op = new Opaque (); + op1 = new Opaque (); + op.Friend = op1; + if (Opaquetest.Error) + Error ("Memory error after setting op.Friend."); + op1 = op.Friend; + if (op1.Serial != Opaque.LastSerial || Opaquetest.Error) + Error ("Error reading op.Friend. Expected {0}, Got {1}", Opaque.LastSerial, op1.Serial); + if (!op1.Owned) + Error ("op1 not Owned after being read off op.Friend"); + op.Dispose (); + op1.Dispose (); + if (Opaquetest.Error) + Error ("Memory error after freeing op and op1."); + + Console.WriteLine ("Testing returning a Gtk#-owned opaque from C# to C"); + ret_op = new Opaque (); + op = Opaque.Check (ReturnOpaque, GC); + if (op.Serial != Opaque.LastSerial || Opaquetest.Error) + Error ("Error during Opaque.Check. Expected {0}, Got {1}", Opaque.LastSerial, op.Serial); + op.Dispose (); + if (Opaquetest.Error) + Error ("Memory error after clearing op."); + + Console.WriteLine ("Testing returning a Gtk#-owned opaque to a C method that will free it"); + ret_op = new Opaque (); + op = Opaque.CheckFree (ReturnOpaque, GC); + if (Opaquetest.Error) + Error ("Error during Opaque.CheckFree."); + Opaquetest.ExpectError = true; + if (op.Serial != Opaque.LastSerial) + Error ("Error during Opaque.CheckFree. Expected {0}, Got {1}", Opaque.LastSerial, op.Serial); + if (!Opaquetest.Error) + Error ("Didn't get expected error accessing op.Serial!"); + Opaquetest.ExpectError = true; + op.Dispose (); + if (!Opaquetest.Error) + Error ("Didn't get expected double free on op after CheckFree!"); + + Console.WriteLine ("Testing leaking a C-owned opaque"); + ret_op = new Opaque (); + ret_op.Owned = false; + op = Opaque.Check (ReturnOpaque, GC); + if (op.Serial != Opaque.LastSerial || Opaquetest.Error) + Error ("Error during Opaque.Check. Expected {0}, Got {1}", Opaque.LastSerial, op.Serial); + handle = op.Handle; + op.Dispose (); + if (Opaquetest.Error) + Error ("Memory error after disposing op."); + op = new Opaque (handle); + if (op.Serial != Opaque.LastSerial || Opaquetest.Error) + Error ("Failed to leak op. Expected {0}, Got {1}", Opaque.LastSerial, op.Serial); + + Console.WriteLine ("Testing handing over a C-owned opaque to a C method that will free it"); + ret_op = new Opaque (); + ret_op.Owned = false; + op = Opaque.CheckFree (ReturnOpaque, GC); + if (Opaquetest.Error) + Error ("Error during Opaque.CheckFree."); + Opaquetest.ExpectError = true; + if (op.Serial != Opaque.LastSerial) + Error ("Error during Opaque.CheckFree. Expected {0}, Got {1}", Opaque.LastSerial, op.Serial); + if (!Opaquetest.Error) + Error ("Didn't get expected error accessing op.Serial!"); + op.Dispose (); + if (Opaquetest.Error) + Error ("Double free on op!"); + } + + static Refcounted ret_ref; + + static Refcounted ReturnRefcounted () + { + return ret_ref; + } + + static void TestRefcounted () + { + Refcounted ref1, ref2; + IntPtr handle; + + Console.WriteLine ("Testing Refcounted new/free"); + ref1 = new Refcounted (); + if (!ref1.Owned) + Error ("Newly-created Refcounted is not Owned"); + handle = ref1.Handle; + ref1.Dispose (); + Opaquetest.ExpectError = true; + ref1 = new Refcounted (handle); + if (!Opaquetest.Error) + Error ("Didn't get expected ref error resurrecting ref1."); + if (!ref1.Owned) + Error ("IntPtr-created Refcounted is not Owned"); + Opaquetest.ExpectError = true; + if (ref1.Serial != Refcounted.LastSerial) + Error ("Serial mismatch. Expected {0}, Got {1}", Refcounted.LastSerial, ref1.Serial); + // We caused it to take a ref on the "freed" underlying object, so + // undo that now so it doesn't cause an error later when we're not + // expecting it. + Opaquetest.ExpectError = true; + ref1.Dispose (); + Opaquetest.Error = false; + + Console.WriteLine ("Testing Refcounted leak/non-free"); + ref1 = new Refcounted (); + ref1.Owned = false; + handle = ref1.Handle; + ref1.Dispose (); + ref1 = new Refcounted (handle); + if (Opaquetest.Error) + Error ("Non-owned ref was freed by gtk#"); + if (ref1.Serial != Refcounted.LastSerial) + Error ("Serial mismatch. Expected {0}, Got {1}", Refcounted.LastSerial, ref1.Serial); + if (Opaquetest.Error) + Error ("Non-owned ref was freed by gtk#"); + + Console.WriteLine ("Testing non-owned return."); + ref1 = new Refcounted (); + ref2 = new Refcounted (); + ref1.Friend = ref2; + if (Opaquetest.Error) + Error ("Memory error after setting ref1.Friend."); + if (ref2.Refcount != 2) + Error ("Refcount wrong for ref2 after setting ref1.Friend. Expected 2, Got {0}", ref2.Refcount); + ref2.Dispose (); + ref2 = ref1.Friend; + if (ref2.Serial != Refcounted.LastSerial || Opaquetest.Error) + Error ("Error reading ref1.Friend. Expected {0}, Got {1}", Refcounted.LastSerial, ref2.Serial); + if (ref2.Refcount != 2 || Opaquetest.Error) + Error ("Refcount wrong for ref2 after reading ref1.Friend. Expected 2, Got {0}", ref2.Refcount); + if (!ref2.Owned) + Error ("ref2 not Owned after being read off ref1.Friend"); + ref1.Dispose (); + ref2.Dispose (); + if (Opaquetest.Error) + Error ("Memory error after freeing ref1 and ref2."); + + Console.WriteLine ("Testing returning a Gtk#-owned refcounted from C# to C"); + ret_ref = new Refcounted (); + ref1 = Refcounted.Check (ReturnRefcounted, GC); + if (ref1.Serial != Refcounted.LastSerial || Opaquetest.Error) + Error ("Error during Refcounted.Check. Expected {0}, Got {1}", Refcounted.LastSerial, ref1.Serial); + ref1.Dispose (); + if (Opaquetest.Error) + Error ("Memory error after clearing ref1."); + + Console.WriteLine ("Testing returning a Gtk#-owned refcounted to a C method that will free it"); + ret_ref = new Refcounted (); + ref1 = Refcounted.CheckUnref (ReturnRefcounted, GC); + if (Opaquetest.Error) + Error ("Error during Refcounted.CheckUnref."); + Opaquetest.ExpectError = true; + if (ref1.Serial != Refcounted.LastSerial) + Error ("Error during Refcounted.CheckUnref. Expected {0}, Got {1}", Refcounted.LastSerial, ref1.Serial); + if (!Opaquetest.Error) + Error ("Didn't get expected error accessing ref1.Serial!"); + Opaquetest.ExpectError = true; + ref1.Dispose (); + if (!Opaquetest.Error) + Error ("Didn't get expected double free on ref1 after CheckUnref!"); + + Console.WriteLine ("Testing leaking a C-owned refcounted"); + ret_ref = new Refcounted (); + ret_ref.Owned = false; + ref1 = Refcounted.Check (ReturnRefcounted, GC); + if (ref1.Serial != Refcounted.LastSerial || Opaquetest.Error) + Error ("Error during Refcounted.Check. Expected {0}, Got {1}", Refcounted.LastSerial, ref1.Serial); + handle = ref1.Handle; + ref1.Dispose (); + if (Opaquetest.Error) + Error ("Memory error after disposing ref1."); + ref1 = new Refcounted (handle); + if (ref1.Serial != Refcounted.LastSerial || Opaquetest.Error) + Error ("Failed to leak ref1. Expected {0}, Got {1}", Refcounted.LastSerial, ref1.Serial); + + Console.WriteLine ("Testing handing over a C-owned refcounted to a C method that will free it"); + ret_ref = new Refcounted (); + ret_ref.Owned = false; + ref1 = Refcounted.CheckUnref (ReturnRefcounted, GC); + if (Opaquetest.Error) + Error ("Error during Refcounted.CheckUnref."); + Opaquetest.ExpectError = true; + if (ref1.Serial != Refcounted.LastSerial) + Error ("Error during Refcounted.CheckUnref. Expected {0}, Got {1}", Refcounted.LastSerial, ref1.Serial); + if (!Opaquetest.Error) + Error ("Didn't get expected error accessing ref1.Serial!"); + ref1.Dispose (); + if (Opaquetest.Error) + Error ("Double free on ref1!"); + } + + static void Error (string message, params object[] args) + { + Console.Error.WriteLine (" MANAGED ERROR: " + message, args); + errors++; + } +} diff --git a/sample/opaquetest/opaque-api.xml b/sample/opaquetest/opaque-api.xml new file mode 100644 index 000000000..96ab46c0e --- /dev/null +++ b/sample/opaquetest/opaque-api.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sample/opaquetest/opaque-sources.xml b/sample/opaquetest/opaque-sources.xml new file mode 100644 index 000000000..3edcc6aff --- /dev/null +++ b/sample/opaquetest/opaque-sources.xml @@ -0,0 +1,9 @@ + + + + + . + + + + diff --git a/sample/opaquetest/opaques.c b/sample/opaquetest/opaques.c new file mode 100644 index 000000000..4b53107bf --- /dev/null +++ b/sample/opaquetest/opaques.c @@ -0,0 +1,226 @@ +/* opaques.c: Opaque memory management test objects + * + * Copyright (c) 2005 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the Lesser GNU General + * Public License as published by the Free Software Foundation. + * + * This program 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "opaques.h" +#include + +static int opserial, refserial; +static gboolean error = FALSE, expect_error = FALSE; + +static gboolean check_error (gboolean valid, const char *msg, ...); + +GtksharpOpaque * +gtksharp_opaque_new (void) +{ + GtksharpOpaque *op = g_new0 (GtksharpOpaque, 1); + op->valid = TRUE; + op->serial = opserial++; + return op; +} + +int +gtksharp_opaque_get_serial (GtksharpOpaque *op) +{ + check_error (op->valid, "get_serial on freed GtksharpOpaque serial %d\n", op->serial); + return op->serial; +} + +void gtksharp_opaque_set_friend (GtksharpOpaque *op, GtksharpOpaque *friend) +{ + check_error (op->valid, "set_friend on freed GtksharpOpaque serial %d\n", op->serial); + op->friend = friend; +} + +GtksharpOpaque * +gtksharp_opaque_get_friend (GtksharpOpaque *op) +{ + check_error (op->valid, "get_friend on freed GtksharpOpaque serial %d\n", op->serial); + return op->friend; +} + +GtksharpOpaque * +gtksharp_opaque_copy (GtksharpOpaque *op) +{ + check_error (op->valid, "copying freed GtksharpOpaque serial %d\n", op->serial); + return gtksharp_opaque_new (); +} + +void +gtksharp_opaque_free (GtksharpOpaque *op) +{ + check_error (op->valid, "Double free of GtksharpOpaque serial %d\n", op->serial); + op->valid = FALSE; + /* We don't actually free it */ +} + +GtksharpOpaque * +gtksharp_opaque_check (GtksharpOpaqueReturnFunc func, GtksharpGCFunc gc) +{ + GtksharpOpaque *op = func (); + gc (); + return op; +} + +GtksharpOpaque * +gtksharp_opaque_check_free (GtksharpOpaqueReturnFunc func, GtksharpGCFunc gc) +{ + GtksharpOpaque *op = func (); + gc (); + gtksharp_opaque_free (op); + gc (); + return op; +} + +int +gtksharp_opaque_get_last_serial (void) +{ + return opserial - 1; +} + + +GtksharpRefcounted * +gtksharp_refcounted_new (void) +{ + GtksharpRefcounted *ref = g_new0 (GtksharpRefcounted, 1); + ref->valid = TRUE; + ref->refcount = 1; + ref->serial = refserial++; + return ref; +} + +int +gtksharp_refcounted_get_serial (GtksharpRefcounted *ref) +{ + check_error (ref->valid, "get_serial on freed GtksharpRefcounted serial %d\n", ref->serial); + return ref->serial; +} + +void +gtksharp_refcounted_ref (GtksharpRefcounted *ref) +{ + if (check_error (ref->valid, "ref on freed GtksharpRefcounted serial %d\n", ref->serial)) + return; + ref->refcount++; +} + +void +gtksharp_refcounted_unref (GtksharpRefcounted *ref) +{ + if (check_error (ref->valid, "unref on freed GtksharpRefcounted serial %d\n", ref->serial)) + return; + if (--ref->refcount == 0) { + ref->valid = FALSE; + /* We don't actually free it */ + } +} + +int +gtksharp_refcounted_get_refcount (GtksharpRefcounted *ref) +{ + check_error (ref->valid, "get_refcount on freed GtksharpRefcounted serial %d\n", ref->serial); + return ref->refcount; +} + +void +gtksharp_refcounted_set_friend (GtksharpRefcounted *ref, GtksharpRefcounted *friend) +{ + check_error (ref->valid, "set_friend on freed GtksharpRefcounted serial %d\n", ref->serial); + if (ref->friend) + gtksharp_refcounted_unref (ref->friend); + ref->friend = friend; + if (ref->friend) + gtksharp_refcounted_ref (ref->friend); +} + +GtksharpRefcounted * +gtksharp_refcounted_get_friend (GtksharpRefcounted *ref) +{ + check_error (ref->valid, "get_friend on freed GtksharpRefcounted serial %d\n", ref->serial); + return ref->friend; +} + +GtksharpRefcounted * +gtksharp_refcounted_check (GtksharpRefcountedReturnFunc func, GtksharpGCFunc gc) +{ + GtksharpRefcounted *ref = func (); + gc (); + return ref; +} + +GtksharpRefcounted * +gtksharp_refcounted_check_unref (GtksharpRefcountedReturnFunc func, GtksharpGCFunc gc) +{ + GtksharpRefcounted *ref = func (); + gc (); + gtksharp_refcounted_unref (ref); + gc (); + return ref; +} + +int +gtksharp_refcounted_get_last_serial (void) +{ + return refserial - 1; +} + + +static gboolean +check_error (gboolean valid, const char *msg, ...) +{ + va_list ap; + + if (valid) + return FALSE; + + error = TRUE; + if (expect_error) { + expect_error = FALSE; + return FALSE; + } + + expect_error = FALSE; + + fprintf (stderr, " UNMANAGED ERROR: "); + va_start (ap, msg); + vfprintf (stderr, msg, ap); + va_end (ap); + + return TRUE; +} + + +gboolean +gtksharp_opaquetest_get_error (void) +{ + gboolean old_error = error; + error = expect_error = FALSE; + return old_error; +} + +void +gtksharp_opaquetest_set_error (gboolean err) +{ + error = err; +} + +void +gtksharp_opaquetest_set_expect_error (gboolean err) +{ + expect_error = err; +} diff --git a/sample/opaquetest/opaques.h b/sample/opaquetest/opaques.h new file mode 100644 index 000000000..14520e817 --- /dev/null +++ b/sample/opaquetest/opaques.h @@ -0,0 +1,70 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2000-2003, Ximian, Inc. + */ + +#ifndef GTKSHARP_OPAQUES_H +#define GTKSHARP_OPAQUES_H 1 + +#include + +typedef void (*GtksharpGCFunc) (void); + +typedef struct GtksharpOpaque GtksharpOpaque; +struct GtksharpOpaque { + int serial; + gboolean valid; + + GtksharpOpaque *friend; +}; + +typedef GtksharpOpaque *(*GtksharpOpaqueReturnFunc) (void); + +GtksharpOpaque *gtksharp_opaque_new (void); +int gtksharp_opaque_get_serial (GtksharpOpaque *op); +void gtksharp_opaque_set_friend (GtksharpOpaque *op, + GtksharpOpaque *friend); +GtksharpOpaque *gtksharp_opaque_get_friend (GtksharpOpaque *op); +GtksharpOpaque *gtksharp_opaque_copy (GtksharpOpaque *op); +void gtksharp_opaque_free (GtksharpOpaque *op); + +GtksharpOpaque *gtksharp_opaque_check (GtksharpOpaqueReturnFunc func, + GtksharpGCFunc gc); +GtksharpOpaque *gtksharp_opaque_check_free (GtksharpOpaqueReturnFunc func, + GtksharpGCFunc gc); + +int gtksharp_opaque_get_last_serial (void); + + +typedef struct GtksharpRefcounted GtksharpRefcounted; +struct GtksharpRefcounted { + int serial, refcount; + gboolean valid; + + GtksharpRefcounted *friend; +}; + +typedef GtksharpRefcounted *(*GtksharpRefcountedReturnFunc) (void); + +GtksharpRefcounted *gtksharp_refcounted_new (void); +int gtksharp_refcounted_get_serial (GtksharpRefcounted *ref); +void gtksharp_refcounted_ref (GtksharpRefcounted *ref); +void gtksharp_refcounted_unref (GtksharpRefcounted *ref); +int gtksharp_refcounted_get_refcount (GtksharpRefcounted *ref); +void gtksharp_refcounted_set_friend (GtksharpRefcounted *ref, + GtksharpRefcounted *friend); +GtksharpRefcounted *gtksharp_refcounted_get_friend (GtksharpRefcounted *ref); + +GtksharpRefcounted *gtksharp_refcounted_check (GtksharpRefcountedReturnFunc func, + GtksharpGCFunc gc); +GtksharpRefcounted *gtksharp_refcounted_check_unref (GtksharpRefcountedReturnFunc func, + GtksharpGCFunc gc); + +int gtksharp_refcounted_get_last_serial (void); + + +gboolean gtksharp_opaquetest_get_error (void); +void gtksharp_opaquetest_set_error (gboolean err); +void gtksharp_opaquetest_set_expect_error (gboolean err); + +#endif /* GTKSHARP_OPAQUES_H */ diff --git a/sample/opaquetest/opaquetest.exe.config.in b/sample/opaquetest/opaquetest.exe.config.in new file mode 100644 index 000000000..6f971a86b --- /dev/null +++ b/sample/opaquetest/opaquetest.exe.config.in @@ -0,0 +1,3 @@ + + +