253
|
1 /**
|
|
2 *
|
|
3 * Copyright: Copyright QtD Team, 2008-2009
|
|
4 * License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>
|
258
|
5 * Authors: Max Samukha, Eldar Insafutdinov
|
253
|
6 *
|
|
7 * Copyright QtD Team, 2008-2009
|
|
8 * Distributed under the Boost Software License, Version 1.0.
|
|
9 * (See accompanying file boost-license-1.0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
258
|
10 *
|
253
|
11 */
|
|
12
|
|
13 module qt.QtdObject;
|
|
14
|
|
15 import qt.Signal;
|
258
|
16 import tango.core.Memory;
|
|
17 debug (QtdVerbose)
|
|
18 import tango.io.Stdout;
|
|
19
|
253
|
20
|
|
21 enum QtdObjectFlags : ubyte
|
|
22 {
|
|
23 none,
|
258
|
24 // The native object will not be deleted when the wrapper is deleted
|
|
25 skipNativeDelete = 0b0001,
|
|
26 skipDDelete = 0b0010,
|
|
27 hasDId = 0b0100,
|
|
28 stackAllocated = 0b1000
|
|
29 /+
|
|
30 // The will be deleted when is goes out of scope. Implies skipNativeDelete
|
|
31 scoped = 0x08
|
|
32 +/
|
253
|
33 }
|
|
34
|
258
|
35 class MetaObject
|
253
|
36 {
|
258
|
37 alias typeof(this) This;
|
|
38
|
|
39 private
|
|
40 {
|
|
41 MetaObject _base;
|
|
42 ClassInfo _classInfo;
|
|
43 }
|
|
44
|
|
45 //COMPILER BUG: not accessible from QMetaObject
|
|
46 protected
|
|
47 {
|
|
48 This _firstDerived;
|
|
49 This _next;
|
|
50 }
|
|
51
|
|
52 private void addDerived(This mo)
|
|
53 {
|
|
54 mo._next = _firstDerived;
|
|
55 _firstDerived = mo;
|
|
56 }
|
|
57
|
|
58 /++
|
|
59 Next sibling on this derivation level
|
|
60 +/
|
|
61 final This next()
|
|
62 {
|
|
63 return _next;
|
|
64 }
|
|
65
|
|
66 /++
|
|
67 Head of the linked list of derived classes
|
|
68 +/
|
|
69 final This firstDerived()
|
|
70 {
|
|
71 return _firstDerived;
|
|
72 }
|
|
73
|
|
74 // NOTE: construction is split between this non-templated constructor and 'construct' function below.
|
|
75 this(This base)
|
|
76 {
|
|
77 if (base)
|
|
78 {
|
|
79 base.addDerived(this);
|
|
80 _base = base;
|
|
81 }
|
|
82 }
|
|
83
|
|
84 // TODO: can be removed when D acquires templated constructors
|
|
85 void construct(T : Object)()
|
|
86 {
|
|
87 _classInfo = T.classinfo;
|
|
88 }
|
|
89
|
|
90 final This base()
|
|
91 {
|
|
92 return _base;
|
|
93 }
|
|
94
|
|
95 final ClassInfo classInfo()
|
|
96 {
|
|
97 return _classInfo;
|
|
98 }
|
|
99 }
|
|
100
|
|
101
|
260
|
102 abstract class QtdMetaObjectBase : MetaObject
|
258
|
103 {
|
|
104 QtdObjectBase function(void* nativeId, QtdObjectFlags flags) _createWrapper;
|
|
105
|
260
|
106 this(QtdMetaObjectBase base)
|
|
107 {
|
|
108 super(base);
|
|
109 }
|
|
110
|
258
|
111 void construct(T : QtdObject, Concrete = T)()
|
|
112 {
|
|
113 super.construct!(T);
|
|
114 _createWrapper = &T.__createWrapper;
|
|
115 }
|
|
116 }
|
|
117
|
|
118 /++
|
|
119 Meta-object for polymorphic Qt classes.
|
|
120 +/
|
260
|
121 final class QtdMetaObject : QtdMetaObjectBase
|
258
|
122 {
|
|
123 alias typeof(this) This;
|
|
124
|
|
125 private void* _typeId;
|
|
126
|
|
127 this(void* typeId, QtdMetaObject base)
|
|
128 {
|
|
129 super(base);
|
|
130 _typeId = typeId;
|
|
131 }
|
|
132
|
|
133 QtdObject wrap(void* nativeId, void* typeId, QtdObjectFlags flags = QtdObjectFlags.skipNativeDelete)
|
|
134 {
|
|
135 if (typeId == _typeId)
|
|
136 {
|
|
137 /+
|
|
138 if (auto p = nativeId in _nativeToDMap)
|
|
139 return *p;
|
|
140 +/
|
|
141 }
|
|
142 else
|
|
143 {
|
|
144 for (auto mo = static_cast!(This)(_firstDerived); mo; mo = static_cast!(This)(mo._next))
|
|
145 {
|
|
146 if (auto obj = mo.wrap(nativeId, typeId, flags))
|
|
147 return obj;
|
|
148 }
|
|
149 }
|
|
150
|
260
|
151 return static_cast!(QtdObject)(_createWrapper(nativeId, flags));
|
258
|
152 }
|
|
153 }
|
|
154
|
|
155 abstract class QtdObjectBase
|
|
156 {
|
|
157 alias typeof(this) This;
|
|
158
|
253
|
159 void* __nativeId;
|
258
|
160 QtdObjectFlags __flags;
|
|
161
|
|
162 new (size_t size, QtdObjectFlags flags = QtdObjectFlags.none)
|
|
163 {
|
|
164 return flags & QtdObjectFlags.stackAllocated ? __stackAlloc.alloc(size) :
|
|
165 GC.malloc(size, GC.BlkAttr.FINALIZE);
|
|
166 }
|
|
167
|
|
168 delete (void* p)
|
|
169 {
|
|
170 if ((cast(This)p).__flags & QtdObjectFlags.stackAllocated)
|
|
171 __stackAlloc.free(this.classinfo.init.length);
|
|
172 else
|
|
173 GC.free(p);
|
|
174 }
|
|
175
|
253
|
176 this(void* nativeId, QtdObjectFlags flags = QtdObjectFlags.none)
|
|
177 {
|
|
178 __nativeId = nativeId;
|
258
|
179 __flags = flags;
|
|
180 debug(QtdVerbose) __print("D wrapper constructed");
|
253
|
181 }
|
258
|
182
|
|
183 debug(QtdVerbose)
|
|
184 {
|
|
185 void __print(string msg)
|
|
186 {
|
|
187 Stdout.formatln("{} (native: {}, D: {}, flags 0b{:b})", msg, __nativeId, cast(void*)this, __flags);
|
|
188 }
|
253
|
189 }
|
258
|
190
|
253
|
191 protected void __deleteNative()
|
|
192 {
|
258
|
193 assert(false, "Cannot delete native "
|
|
194 ~ this.classinfo.name
|
|
195 ~ " because it has no public destructor");
|
253
|
196 }
|
258
|
197
|
253
|
198 ~this()
|
|
199 {
|
258
|
200 debug(QtdVerbose) __print("In QtdObjectBase destructor");
|
|
201
|
|
202 if (!(__flags & QtdObjectFlags.skipNativeDelete))
|
253
|
203 {
|
258
|
204 __flags |= QtdObjectFlags.skipDDelete;
|
|
205 debug(QtdVerbose) __print("About to call native delete");
|
253
|
206 __deleteNative;
|
258
|
207 }
|
|
208 }
|
|
209 }
|
|
210
|
|
211 // Base class for by-reference objects
|
|
212 abstract class QtdObject : QtdObjectBase
|
|
213 {
|
|
214 private
|
|
215 {
|
|
216 typeof(this) __next, __prev;
|
|
217 static typeof(this) __root;
|
|
218 }
|
|
219
|
|
220 /++
|
|
221 Use this method instead of 'is' operator to check if two D objects
|
|
222 wrap the same native object.
|
|
223 +/
|
|
224 bool isSame(QtdObject other)
|
|
225 {
|
|
226 return __nativeId == other.__nativeId;
|
|
227 }
|
|
228
|
|
229 mixin SignalHandlerOps;
|
|
230
|
|
231 this(void* nativeId, QtdObjectFlags flags)
|
|
232 {
|
|
233 super (nativeId, flags);
|
|
234 if (!(flags & QtdObjectFlags.skipNativeDelete))
|
|
235 __pin;
|
|
236 }
|
|
237
|
|
238 final void __pin()
|
|
239 {
|
|
240 debug(QtdVerbose) __print("Pinning");
|
|
241
|
|
242 __next = __root;
|
|
243 __root = this;
|
|
244 if (__next)
|
|
245 __next.__prev = this;
|
|
246 }
|
|
247
|
|
248 final void __unpin()
|
|
249 {
|
|
250 debug(QtdVerbose) __print("Unpinning");
|
|
251
|
|
252 if (__prev)
|
|
253 __prev.__next = __next;
|
|
254 else
|
|
255 __root = __next;
|
|
256
|
|
257 if (__next)
|
|
258 __next.__prev = __prev;
|
|
259 }
|
|
260
|
|
261 void __nativeOwnership(bool value)
|
|
262 {
|
|
263 if (value)
|
|
264 {
|
|
265 assert (!(__flags & QtdObjectFlags.skipNativeDelete));
|
|
266 __flags |= QtdObjectFlags.skipNativeDelete;
|
|
267 __unpin;
|
253
|
268 }
|
258
|
269 else
|
|
270 {
|
|
271 assert (__flags & QtdObjectFlags.skipNativeDelete);
|
|
272 __flags = __flags &= ~QtdObjectFlags.skipNativeDelete;
|
|
273 __pin;
|
|
274 }
|
|
275 }
|
|
276
|
|
277 ~this()
|
|
278 {
|
|
279 debug(QtdVerbose) __print("In QtdObject destructor");
|
|
280
|
260
|
281 if (__prev || __root is this)
|
258
|
282 __unpin;
|
|
283 }
|
|
284 }
|
|
285
|
|
286 /++
|
|
287 +/
|
|
288 void dispose(QtdObjectBase obj)
|
|
289 {
|
|
290 obj.__flags &= ~QtdObjectFlags.skipNativeDelete;
|
|
291 delete obj;
|
|
292 }
|
|
293
|
|
294 // Called from shell destructors
|
|
295 extern(C) void qtd_delete_d_object(void* dId)
|
|
296 {
|
|
297 auto obj = cast(QtdObject)dId;
|
|
298 debug(QtdVerbose) obj.__print("In qtd_delete_d_object");
|
|
299
|
|
300 if (!(obj.__flags & QtdObjectFlags.skipDDelete))
|
|
301 {
|
|
302 // Avoid deleting native object twice
|
|
303 obj.__flags |= QtdObjectFlags.skipNativeDelete;
|
|
304 delete obj;
|
253
|
305 }
|
|
306 } |