[vala/gsource] Support subclassing of GLib.Source



commit 22ec8fe6c183fce66917136787dd6b9e28c49419
Author: JÃrg Billeter <j bitron ch>
Date:   Wed Aug 15 22:22:34 2012 +0200

    Support subclassing of GLib.Source

 codegen/valaccodebasemodule.vala       |    2 ++
 codegen/valaccodemethodcallmodule.vala |   21 +++++++++++++++++++++
 codegen/valagtypemodule.vala           |   31 ++++++++++++++++++++++---------
 vala/valaclass.vala                    |    2 +-
 vala/valamethod.vala                   |    2 +-
 vala/valasemanticanalyzer.vala         |    3 +++
 vapi/glib-2.0.vapi                     |    8 ++++++--
 7 files changed, 56 insertions(+), 13 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 0d1472c..5881751 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -318,6 +318,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
 	public Struct grecmutex_type;
 	public Struct grwlock_type;
 	public Struct gcond_type;
+	public Class gsource_type;
 	public TypeSymbol type_module_type;
 	public TypeSymbol dbus_proxy_type;
 
@@ -460,6 +461,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
 		gquark_type = new IntegerType ((Struct) glib_ns.scope.lookup ("Quark"));
 		gvalue_type = (Struct) glib_ns.scope.lookup ("Value");
 		gvariant_type = (Class) glib_ns.scope.lookup ("Variant");
+		gsource_type = (Class) glib_ns.scope.lookup ("Source");
 		mutex_type = (Struct) glib_ns.scope.lookup ("StaticRecMutex");
 
 		if (context.require_glib_version (2, 32)) {
diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala
index bd81609..8cb1171 100644
--- a/codegen/valaccodemethodcallmodule.vala
+++ b/codegen/valaccodemethodcallmodule.vala
@@ -150,6 +150,21 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
 						type_param_index++;
 					}
 				}
+			} else if (current_class.base_class == gsource_type) {
+				// g_source_new
+
+				string class_prefix = CCodeBaseModule.get_ccode_lower_case_name (current_class);
+
+				var funcs = new CCodeDeclaration ("const GSourceFuncs");
+				funcs.modifiers = CCodeModifiers.STATIC;
+				funcs.add_declarator (new CCodeVariableDeclarator ("_source_funcs", new CCodeConstant ("{ %s_real_prepare, %s_real_check, %s_real_dispatch, %s_finalize}".printf (class_prefix, class_prefix, class_prefix, class_prefix))));
+				ccode.add_statement (funcs);
+
+				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_source_funcs")));
+
+				var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+				csizeof.add_argument (new CCodeIdentifier (get_ccode_name (current_class)));
+				ccall.add_argument (csizeof);
 			}
 		} else if (m is CreationMethod && m.parent_symbol is Struct) {
 			ccall.add_argument (get_this_cexpression ());
@@ -795,6 +810,12 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
 			// assign new value
 			store_value (unary.inner.target_value, transform_value (unary.target_value, unary.inner.value_type, arg));
 		}
+
+		if (m is CreationMethod && m.parent_symbol is Class && current_class.base_class == gsource_type) {
+			var cinitcall = new CCodeFunctionCall (new CCodeIdentifier ("%s_instance_init".printf (get_ccode_lower_case_name (current_class, null))));
+			cinitcall.add_argument (get_this_cexpression ());
+			ccode.add_expression (cinitcall);
+		}
 	}
 
 	private string generate_enum_tostring_function (Enum en) {
diff --git a/codegen/valagtypemodule.vala b/codegen/valagtypemodule.vala
index ab29c58..3be2d29 100644
--- a/codegen/valagtypemodule.vala
+++ b/codegen/valagtypemodule.vala
@@ -60,6 +60,7 @@ public class Vala.GTypeModule : GErrorModule {
 
 		bool is_gtypeinstance = !cl.is_compact;
 		bool is_fundamental = is_gtypeinstance && cl.base_class == null;
+		bool is_gsource = cl.base_class == gsource_type;
 
 		if (is_gtypeinstance) {
 			decl_space.add_type_declaration (new CCodeNewline ());
@@ -83,7 +84,7 @@ public class Vala.GTypeModule : GErrorModule {
 			decl_space.add_type_declaration (new CCodeNewline ());
 		}
 
-		if (cl.is_compact && cl.base_class != null) {
+		if (cl.is_compact && cl.base_class != null && !is_gsource) {
 			decl_space.add_type_declaration (new CCodeTypeDefinition (get_ccode_name (cl.base_class), new CCodeVariableDeclarator (get_ccode_name (cl))));
 		} else {
 			decl_space.add_type_declaration (new CCodeTypeDefinition ("struct _%s".printf (get_ccode_name (cl)), new CCodeVariableDeclarator (get_ccode_name (cl))));
@@ -155,7 +156,7 @@ public class Vala.GTypeModule : GErrorModule {
 			}
 
 			decl_space.add_function_declaration (function);
-		} else if (!is_gtypeinstance) {
+		} else if (!is_gtypeinstance && !is_gsource) {
 			if (cl.base_class == null) {
 				var function = new CCodeFunction (get_ccode_lower_case_prefix (cl) + "free", "void");
 				if (cl.access == SymbolAccessibility.PRIVATE) {
@@ -197,6 +198,7 @@ public class Vala.GTypeModule : GErrorModule {
 
 		bool is_gtypeinstance = !cl.is_compact;
 		bool is_fundamental = is_gtypeinstance && cl.base_class == null;
+		bool is_gsource = cl.base_class == gsource_type;
 
 		var instance_struct = new CCodeStruct ("_%s".printf (get_ccode_name (cl)));
 		var type_struct = new CCodeStruct ("_%sClass".printf (get_ccode_name (cl)));
@@ -350,7 +352,7 @@ public class Vala.GTypeModule : GErrorModule {
 			}
 		}
 
-		if (!cl.is_compact || cl.base_class == null) {
+		if (!cl.is_compact || cl.base_class == null || is_gsource) {
 			// derived compact classes do not have a struct
 			decl_space.add_type_definition (instance_struct);
 		}
@@ -574,7 +576,7 @@ public class Vala.GTypeModule : GErrorModule {
 			begin_class_finalize_function (cl);
 			begin_finalize_function (cl);
 		} else {
-			if (cl.base_class == null) {
+			if (cl.base_class == null || cl.base_class == gsource_type) {
 				begin_instance_init_function (cl);
 				begin_finalize_function (cl);
 			}
@@ -698,7 +700,7 @@ public class Vala.GTypeModule : GErrorModule {
 				cfile.add_function (unref_fun);
 			}
 		} else {
-			if (cl.base_class == null) {
+			if (cl.base_class == null || cl.base_class == gsource_type) {
 				// derived compact classes do not have fields
 				add_instance_init_function (cl);
 				add_finalize_function (cl);
@@ -1645,7 +1647,9 @@ public class Vala.GTypeModule : GErrorModule {
 	private void begin_finalize_function (Class cl) {
 		push_context (instance_finalize_context);
 
-		if (!cl.is_compact) {
+		bool is_gsource = cl.base_class == gsource_type;
+
+		if (!cl.is_compact || is_gsource) {
 			var fundamental_class = cl;
 			while (fundamental_class.base_class != null) {
 				fundamental_class = fundamental_class.base_class;
@@ -1657,10 +1661,19 @@ public class Vala.GTypeModule : GErrorModule {
 
 			push_function (func);
 
-			CCodeFunctionCall ccall = generate_instance_cast (new CCodeIdentifier ("obj"), cl);
+			if (is_gsource) {
+				cfile.add_function_declaration (func);
+			}
+
+			CCodeExpression ccast;
+			if (!cl.is_compact) {
+				ccast = generate_instance_cast (new CCodeIdentifier ("obj"), cl);
+			} else {
+				ccast = new CCodeCastExpression (new CCodeIdentifier ("obj"), get_ccode_name (cl) + "*");
+			}
 
 			ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self"));
-			ccode.add_assignment (new CCodeIdentifier ("self"), ccall);
+			ccode.add_assignment (new CCodeIdentifier ("self"), ccast);
 		} else {
 			var function = new CCodeFunction (get_ccode_lower_case_prefix (cl) + "free", "void");
 			if (cl.access == SymbolAccessibility.PRIVATE) {
@@ -1707,7 +1720,7 @@ public class Vala.GTypeModule : GErrorModule {
 			}
 
 			cfile.add_function_declaration (instance_finalize_context.ccode);
-		} else {
+		} else if (cl.base_class == null) {
 			var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
 			ccall.add_argument (new CCodeIdentifier (get_ccode_name (cl)));
 			ccall.add_argument (new CCodeIdentifier ("self"));
diff --git a/vala/valaclass.vala b/vala/valaclass.vala
index 6327878..5110a7a 100644
--- a/vala/valaclass.vala
+++ b/vala/valaclass.vala
@@ -720,7 +720,7 @@ public class Vala.Class : ObjectTypeSymbol {
 				}
 			}
 
-			if (!external && !external_package && base_class != null) {
+			if (!external && !external_package && base_class != null && base_class != context.analyzer.gsource_type) {
 				foreach (Field f in fields) {
 					if (f.binding == MemberBinding.INSTANCE) {
 						error = true;
diff --git a/vala/valamethod.vala b/vala/valamethod.vala
index 942f0d2..7af50e8 100644
--- a/vala/valamethod.vala
+++ b/vala/valamethod.vala
@@ -589,7 +589,7 @@ public class Vala.Method : Subroutine {
 
 			if (parent_symbol is Class) {
 				var cl = (Class) parent_symbol;
-				if (cl.is_compact) {
+				if (cl.is_compact && cl != context.analyzer.gsource_type) {
 					Report.error (source_reference, "Virtual methods may not be declared in compact classes");
 					return false;
 				}
diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala
index 8afe175..90923ac 100644
--- a/vala/valasemanticanalyzer.vala
+++ b/vala/valasemanticanalyzer.vala
@@ -161,6 +161,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
 	public DataType list_type;
 	public DataType tuple_type;
 	public DataType error_type;
+	public Class gsource_type;
 
 	public int next_lambda_id = 0;
 
@@ -216,6 +217,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
 		gerror_type = (Class) glib_ns.scope.lookup ("Error");
 		regex_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Regex"));
 
+		gsource_type = (Class) glib_ns.scope.lookup ("Source");
+
 		current_symbol = root_symbol;
 		context.root.check (context);
 		context.accept (this);
diff --git a/vapi/glib-2.0.vapi b/vapi/glib-2.0.vapi
index cb7ccd0..5080523 100644
--- a/vapi/glib-2.0.vapi
+++ b/vapi/glib-2.0.vapi
@@ -1584,8 +1584,8 @@ namespace GLib {
 
 	[Compact]
 	[CCode (ref_function = "g_source_ref", unref_function = "g_source_unref")]
-	public class Source {
-		public Source (SourceFuncs source_funcs, uint struct_size /* = sizeof (Source) */);
+	public abstract class Source {
+		protected Source ();
 		public void set_funcs (SourceFuncs funcs);
 		public uint attach (MainContext? context);
 		public void destroy ();
@@ -1611,6 +1611,10 @@ namespace GLib {
 		public static bool remove (uint id);
 		public static bool remove_by_funcs_user_data (void* user_data);
 		public static bool remove_by_user_data (void* user_data);
+
+		protected abstract bool prepare (out int timeout_);
+		protected abstract bool check ();
+		protected abstract bool dispatch (SourceFunc _callback);
 	}
 
 	[CCode (has_target = false)]



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