1 /*
2  * This file is part of gtkD.
3  *
4  * gtkD is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation; either version 3
7  * of the License, or (at your option) any later version, with
8  * some exceptions, please read the COPYING file.
9  *
10  * gtkD is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with gtkD; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
18  */
19 
20 // generated automatically - do not change
21 // find conversion definition on APILookup.txt
22 // implement new conversion functionalities on the wrap.utils pakage
23 
24 
25 module gobject.DClosure;
26 
27 private import core.memory;
28 private import glib.Str;
29 private import glib.Variant;
30 private import gobject.Closure;
31 private import gobject.ObjectG;
32 private import gobject.ParamSpec;
33 private import gobject.c.functions;
34 public  import gobject.c.types;
35 public  import gtkc.gobjecttypes;
36 private import std.algorithm;
37 private import std.conv;
38 private import std.traits;
39 private import std.typecons;
40 
41 
42 /** */
43 struct DGClosure(T)
44 {
45 	GClosure closure;
46 
47 	static if ( isDelegate!T )
48 	{
49 		DGClosureWrapDelegate!(T)* wrap;
50 		alias wrap this;
51 	}
52 	else
53 	{
54 		T callback;
55 	}
56 }
57 
58 struct DGClosureWrapDelegate(T)
59 {
60 	T callback;
61 }
62 
63 /**
64  * DClosure is a wrapper around the gobject library's GClosure with special handling for marshalling D delegates and function pointers as callbacks.
65  *
66  * Closures are central to the concept of asynchronous signal delivery which is widely used throughout GTK+ and GNOME applications.
67  * A closure is an abstraction, a generic representation of a callback.
68  */
69 class DClosure : Closure
70 {
71 	/** Get the main Gtk struct */
72 	public GClosure* getDClosureStruct(bool transferOwnership = false)
73 	{
74 		if (transferOwnership)
75 			ownedRef = false;
76 		return gClosure;
77 	}
78 
79 	/**
80 	 * Sets our main struct and passes it to the parent class.
81 	 */
82 	public this (GClosure* gClosure, bool ownedRef = false)
83 	{
84 		super(gClosure, ownedRef);
85 	}
86 
87 	/**
88 	 * Create a new Closure that will call `callback` when it's invoked.
89 	 *
90 	 * Params:
91 	 *     callback = a delegate or function to call when the DClosure is invoked.
92 	 *     swap     = Should the first and last parameter passed to the callback be swapped.
93 	 *                This is usefull when using the closure for a Signal, where the instance is
94 	 *                 the first parameter, but when using delegates it usually isn't used.
95 	 */
96 	this(T)(T callback, bool swap = false)
97 	if ( isCallable!T )
98 	{
99 		GClosure* gClosure = g_closure_new_simple(DGClosure!(T).sizeof, null);
100 		g_closure_ref(gClosure);
101 		g_closure_sink(gClosure);
102 		g_closure_set_marshal(gClosure, &d_closure_marshal!T);
103 		if ( swap ) gClosure.derivativeFlag = true;
104 
105 		auto dClosure = cast(DGClosure!(T)*)gClosure;
106 
107 		static if ( isDelegate!T )
108 		{
109 			dClosure.wrap = new DGClosureWrapDelegate!T;
110 			GC.addRoot(dClosure.wrap);
111 			g_closure_add_finalize_notifier(gClosure, null, &d_finalize_nofify);
112 		}
113 
114 		dClosure.callback = callback;
115 		super(gClosure, true);
116 	}
117 
118 	extern(C) static void d_finalize_nofify(void* data, GClosure* dClosure)
119 	{
120 		GC.removeRoot((cast(DGClosure!(void delegate())*)dClosure).wrap);
121 	}
122 
123 	extern(C) static void d_closure_marshal(T)(GClosure* closure, GValue* return_value, uint n_param_values, /*const*/ GValue* param_values, void* invocation_hint, void* marshal_data)
124 	{
125 		DGClosure!(T)* cl = cast(DGClosure!(T)*)closure;
126 
127 		if ( Parameters!(T).length > n_param_values )
128 			assert(false, "DClosure doesn't have enough parameters.");
129 
130 		if ( closure.derivativeFlag )
131 		{
132 			GValue[] swapped = new GValue[n_param_values];
133 			swapped[0..n_param_values-1] = param_values[1..n_param_values];
134 			swapped[n_param_values-1] = param_values[0];
135 			param_values = swapped.ptr;
136 		}
137 
138 		mixin(getCallbackCall!T());
139 	}
140 
141 	private static string getCallbackCall(T)()
142 	{
143 		if (!__ctfe) assert(false);
144 
145 		string call;
146 
147 		alias Params = Parameters!T;
148 		foreach ( param; Params )
149 		{
150 			static if ( __traits(compiles, TemplateOf!param) && __traits(isSame, TemplateOf!param, glib.c.types.Scoped) )
151 				call ~= "import "~moduleName!(TemplateArgsOf!(param)[0])~";\n";
152 			else static if ( is(param == class) || is(param == interface) || is(param == struct) || is(param == enum) )
153 				call ~= "import "~moduleName!param~";\n";
154 			else static if ( isPointer!param && ( is(PointerTarget!param == struct) || is(PointerTarget!param == enum)) )
155 				//The moduleName template gives an forward reference error here.
156 			call ~= "import "~fullyQualifiedName!param.findSplitAfter(".c.types")[0]~";\n";
157 		}
158 		alias Ret = ReturnType!T;
159 		static if ( is(Ret == class) || is(Ret == interface) || is(Ret == struct) || is(Ret == enum) )
160 			call ~= "import "~moduleName!Ret~";\n";
161 		else static if ( isPointer!Ret && ( is(PointerTarget!Ret == struct) || is(PointerTarget!Ret == enum)) )
162 			call ~= "import "~fullyQualifiedName!Ret.findSplitAfter(".c.types")[0]~";\n";
163 
164 		static if ( !is(Ret == void) )
165 			call ~= "auto ret = ";
166 		call ~= "cl.callback(";
167 
168 		foreach ( i, param; Params )
169 		{
170 			if ( i > 0 )
171 				call ~= ", ";
172 			call ~= getValue!param(i);
173 		}
174 		call ~= ");\n";
175 
176 		static if ( is(Ret == bool) )
177 			call ~= "g_value_set_boolean(return_value, ret);";
178 		else static if ( is(Ret == byte) )
179 			call ~= "g_value_set_schar(return_value, ret);";
180 		else static if ( is(Ret == ubyte) )
181 			call ~= "g_value_set_uchar(return_value, ret);";
182 		else static if ( is(Ret == int) )
183 			call ~= "g_value_set_int(return_value, ret);";
184 		else static if ( is(Ret == uint) )
185 			call ~= "g_value_set_uint(return_value, ret);";
186 		else static if ( is(Ret == long) )
187 			call ~= "g_value_set_int64(return_value, ret);";
188 		else static if ( is(Ret == ulong) )
189 			call ~= "g_value_set_uint64(return_value, ret);";
190 		else static if ( is(Ret == float) )
191 			call ~= "g_value_set_float(return_value, ret);";
192 		else static if ( is(Ret == double) )
193 			call ~= "g_value_set_double(return_value, ret);";
194 		else static if ( is(Ret == string) )
195 			call ~= "g_value_set_string(return_value, Str.toStringz(ret));";
196 		else static if ( is(Ret == string[]) )
197 			call ~= "g_value_set_pointer(return_value, Str.toStringzArray(ret));";
198 		else static if ( is(Ret == enum) )
199 			call ~= "g_type_is_a(return_value.gType, GType.ENUM) ? g_value_set_enum(return_value, ret) : g_value_set_flags(return_value, ret);";
200 		else static if ( isPointer!Ret )
201 			call ~= "g_type_is_a(return_value.gType, GType.POINTER) ? g_value_set_pointer(return_value, ret) : (g_type_is_a(return_value.gType, GType.BOXED) ? g_value_set_boxed(return_value, ret) : g_value_set_object(return_value, ret));";
202 		else static if ( is(Ret == interface) )
203 			call ~= "g_value_set_object(return_value, (cast(ObjectG)ret).getObjectGStruct());";
204 		else static if ( is(Ret == class) )
205 		{
206 			static if ( is(Ret == Variant) )
207 				call ~= "g_value_set_variant(return_value, ret.getVariantStruct());";
208 			else static if ( is(Ret == ParamSpec) )
209 				call ~= "g_value_set_param(return_value, ret.getParamSpecStruct());";
210 			else static if ( is(Ret : ObjectG) )
211 				call ~= "g_value_set_object(return_value, ret.getObjectGStruct());";
212 			else
213 				call ~= "g_type_is_a(return_value.gType, GType.POINTER) ? g_value_set_pointer(return_value, ret.get"~Ret.stringof~"Struct()) : (g_type_is_a(return_value.gType, GType.BOXED) ? g_value_set_boxed(return_value, ret.get"~Ret.stringof~"Struct()) : g_value_set_object(return_value, ret.get"~Ret.stringof~"Struct()));";
214 		}
215 
216 		return call;
217 	}
218 
219 	private static string getValue(Param)(int index)
220 	{
221 		if (!__ctfe) assert(false);
222 
223 		static if ( is(Param == bool) )
224 			return "g_value_get_boolean(&param_values["~to!string(index)~"]) != 0";
225 		else static if ( is(Param == byte) )
226 			return "g_value_get_schar(&param_values["~to!string(index)~"])";
227 		else static if ( is(Param == ubyte) )
228 			return "g_value_get_uchar(&param_values["~to!string(index)~"])";
229 		else static if ( is(Param == int) )
230 			return "g_value_get_int(&param_values["~to!string(index)~"])";
231 		else static if ( is(Param == uint) )
232 			return "g_value_get_uint(&param_values["~to!string(index)~"])";
233 		else static if ( is(Param == long) )
234 			return "g_value_get_int64(&param_values["~to!string(index)~"])";
235 		else static if ( is(Param == ulong) )
236 			return "g_value_get_uint64(&param_values["~to!string(index)~"])";
237 		else static if ( is(Param == float) )
238 			return "g_value_get_float(&param_values["~to!string(index)~"])";
239 		else static if ( is(Param == double) )
240 			return "g_value_get_double(&param_values["~to!string(index)~"])";
241 		else static if ( is(Param == string) )
242 			return "Str.toString(g_value_get_string(&param_values["~to!string(index)~"]))";
243 		else static if ( is(Param == string[]) )
244 			return "Str.toStringArray(cast(const(char*)*)g_value_get_pointer(&param_values["~to!string(index)~"]))";
245 		else static if ( is(Param == enum) )
246 			return "cast("~fullyQualifiedName!Param~")(g_type_is_a(param_values["~to!string(index)~"].gType, GType.ENUM) ? g_value_get_enum(&param_values["~to!string(index)~"]) : g_value_get_flags(&param_values["~to!string(index)~"]))";
247 		else static if ( isPointer!Param )
248 			return "cast("~fullyQualifiedName!Param~")(g_type_is_a(param_values["~to!string(index)~"].gType, GType.POINTER) ? g_value_get_pointer(&param_values["~to!string(index)~"]) : (g_type_is_a(param_values["~to!string(index)~"].gType, GType.BOXED) ? g_value_get_boxed(&param_values["~to!string(index)~"]) : g_value_get_object(&param_values["~to!string(index)~"])))";
249 		else static if ( __traits(compiles, TemplateOf!Param) && __traits(isSame, TemplateOf!Param, glib.c.types.Scoped) )
250 			return "getScopedGobject!("~fullyQualifiedName!(TemplateArgsOf!(Param)[0])~")(cast(typeof("~fullyQualifiedName!(TemplateArgsOf!(Param)[0])~".tupleof[0]))(g_type_is_a(param_values["~to!string(index)~"].gType, GType.POINTER) ? g_value_get_pointer(&param_values["~to!string(index)~"]) : (g_type_is_a(param_values["~to!string(index)~"].gType, GType.BOXED) ? g_value_get_boxed(&param_values["~to!string(index)~"]) : g_value_get_object(&param_values["~to!string(index)~"]))))";
251 		else static if ( is(Param == interface) )
252 			return "ObjectG.getDObject!("~fullyQualifiedName!Param~")(cast(GObject*)g_value_get_object(&param_values["~to!string(index)~"]))";
253 		else static if ( is(Param == class) )
254 		{
255 			static if ( is(Param == Variant) )
256 				return "new Variant(g_value_get_variant(&param_values["~to!string(index)~"]))";
257 			else static if ( is(Param== ParamSpec) )
258 				return "new ParamSpec(g_value_get_param(&param_values["~to!string(index)~"]))";
259 			else static if ( is(Param : ObjectG) )
260 				return "ObjectG.getDObject!("~fullyQualifiedName!Param~")(cast(typeof("~fullyQualifiedName!Param~".tupleof[0]))g_value_get_object(&param_values["~to!string(index)~"]))";
261 			else
262 				return "ObjectG.getDObject!("~fullyQualifiedName!Param~")(cast(typeof("~fullyQualifiedName!Param~".tupleof[0]))(g_type_is_a(param_values["~to!string(index)~"].gType, GType.POINTER) ? g_value_get_pointer(&param_values["~to!string(index)~"]) : (g_type_is_a(param_values["~to!string(index)~"].gType, GType.BOXED) ? g_value_get_boxed(&param_values["~to!string(index)~"]) : g_value_get_object(&param_values["~to!string(index)~"]))))";
263 		}
264 	}
265 }
266 
267 /**
268  */