1 /*
2  * DQt - D bindings for the Qt Toolkit
3  *
4  * GNU Lesser General Public License Usage
5  * This file may be used under the terms of the GNU Lesser
6  * General Public License version 3 as published by the Free Software
7  * Foundation and appearing in the file LICENSE.LGPL3 included in the
8  * packaging of this file. Please review the following information to
9  * ensure the GNU Lesser General Public License version 3 requirements
10  * will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
11  */
12 module qt.core.object;
13 extern(C++):
14 
15 import qt.config;
16 import qt.core.bindingstorage;
17 import qt.core.coreevent;
18 import qt.core.list;
19 import qt.core.metamacros;
20 import qt.core.metaobject;
21 import qt.core.namespace;
22 import qt.core.objectdefs;
23 import qt.core.objectdefs_impl;
24 import qt.core.property;
25 import qt.core.scopedpointer;
26 import qt.core.string;
27 import qt.core.thread;
28 import qt.helpers;
29 import std.traits;
30 import std.meta;
31 version(QT_NO_PROPERTIES){}else
32 {
33     import qt.core.bytearray;
34     import qt.core.variant;
35 }
36 
37 /+ #ifndef QT_NO_QOBJECT +/
38 
39 /+ #ifdef QT_INCLUDE_COMPAT
40 #endif
41 #if __has_include(<chrono>)
42 #endif +/
43 
44 
45 
46 extern(C++, class) struct QObjectPrivate;
47 extern(C++, class) struct QAccessibleWidget;
48 /+ #if QT_CONFIG(regularexpression)
49 class QRegularExpression;
50 #endif +/
51 struct QDynamicMetaObjectData;
52 
53 alias QObjectList = QList!(QObject);
54 
55 /+ Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QString &name,
56                                            const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);
57 Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re,
58                                            const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);
59 Q_CORE_EXPORT QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options); +/
60 
61 abstract class /+ Q_CORE_EXPORT +/ QObjectData
62 {
63 private:
64     /+ Q_DISABLE_COPY(QObjectData) +/
65 public:
66     /+ QObjectData() = default; +/
67     this()
68     {
69         children = QObjectList.create();
70         bindingStorage = QBindingStorage.create();
71     }
72     /+ virtual +/ /*abstract*/ ~this();
73     QObject q_ptr;
74     QObject parent;
75     QObjectList children;
76 
77     /+ uint isWidget : 1; +/
78     uint bitfieldData_isWidget;
79     final bool isWidget() const
80     {
81         return (bitfieldData_isWidget >> 0) & 0x1;
82     }
83     final bool isWidget(bool value)
84     {
85         bitfieldData_isWidget = (bitfieldData_isWidget & ~0x1) | ((value & 0x1) << 0);
86         return value;
87     }
88     /+ uint blockSig : 1; +/
89     final bool blockSig() const
90     {
91         return (bitfieldData_isWidget >> 1) & 0x1;
92     }
93     final bool blockSig(bool value)
94     {
95         bitfieldData_isWidget = (bitfieldData_isWidget & ~0x2) | ((value & 0x1) << 1);
96         return value;
97     }
98     /+ uint wasDeleted : 1; +/
99     final uint wasDeleted() const
100     {
101         return (bitfieldData_isWidget >> 2) & 0x1;
102     }
103     final uint wasDeleted(uint value)
104     {
105         bitfieldData_isWidget = (bitfieldData_isWidget & ~0x4) | ((value & 0x1) << 2);
106         return value;
107     }
108     /+ uint isDeletingChildren : 1; +/
109     final uint isDeletingChildren() const
110     {
111         return (bitfieldData_isWidget >> 3) & 0x1;
112     }
113     final uint isDeletingChildren(uint value)
114     {
115         bitfieldData_isWidget = (bitfieldData_isWidget & ~0x8) | ((value & 0x1) << 3);
116         return value;
117     }
118     /+ uint sendChildEvents : 1; +/
119     final uint sendChildEvents() const
120     {
121         return (bitfieldData_isWidget >> 4) & 0x1;
122     }
123     final uint sendChildEvents(uint value)
124     {
125         bitfieldData_isWidget = (bitfieldData_isWidget & ~0x10) | ((value & 0x1) << 4);
126         return value;
127     }
128     /+ uint receiveChildEvents : 1; +/
129     final uint receiveChildEvents() const
130     {
131         return (bitfieldData_isWidget >> 5) & 0x1;
132     }
133     final uint receiveChildEvents(uint value)
134     {
135         bitfieldData_isWidget = (bitfieldData_isWidget & ~0x20) | ((value & 0x1) << 5);
136         return value;
137     }
138     /+ uint isWindow : 1; +/ // for QWindow
139     final bool isWindow() const
140     {
141         return (bitfieldData_isWidget >> 6) & 0x1;
142     }
143     final bool isWindow(bool value)
144     {
145         bitfieldData_isWidget = (bitfieldData_isWidget & ~0x40) | ((value & 0x1) << 6);
146         return value;
147     }
148     /+ uint deleteLaterCalled : 1; +/
149     final uint deleteLaterCalled() const
150     {
151         return (bitfieldData_isWidget >> 7) & 0x1;
152     }
153     final uint deleteLaterCalled(uint value)
154     {
155         bitfieldData_isWidget = (bitfieldData_isWidget & ~0x80) | ((value & 0x1) << 7);
156         return value;
157     }
158     /+ uint unused : 24; +/
159     final uint unused() const
160     {
161         return (bitfieldData_isWidget >> 8) & 0xffffff;
162     }
163     final uint unused(uint value)
164     {
165         bitfieldData_isWidget = (bitfieldData_isWidget & ~0xffffff00) | ((value & 0xffffff) << 8);
166         return value;
167     }
168     int postedEvents;
169     QDynamicMetaObjectData* metaObject;
170     QBindingStorage bindingStorage;
171     final QMetaObject* dynamicMetaObject() const;
172 
173     version(QT_DEBUG)
174     {
175         enum { CheckForParentChildLoopsWarnDepth = 4096 }
176     }
177 }
178 
179 extern(D) struct DQtMember(T, Members_...) if(is(T: QObject))
180 {
181     alias Type = T;
182     alias Members = Members_;
183     T obj;
184 }
185 
186 template parametersSame(Params...)
187 {
188     template parametersSame(alias O)
189     {
190         enum parametersSame = is(Parameters!O == Params);
191     }
192 }
193 
194 /// Binding for C++ class [QObject](https://doc.qt.io/qt-6/qobject.html).
195 class /+ Q_CORE_EXPORT +/ QObject
196 {
197     mixin((){import std.array; return Q_OBJECT.replace("override", "");}());
198 
199     /+ Q_PROPERTY(QString objectName READ objectName WRITE setObjectName NOTIFY objectNameChanged
200                BINDABLE bindableObjectName)
201     Q_DECLARE_PRIVATE(QObject) +/
202 
203 public:
204     /+ explicit +/@QInvokable this(QObject parent = null);
205     /+ virtual +/~this();
206 
207 protected:
208     /++
209         UDA for marking member functions as signals.
210 
211         Meta data for marked member functions will be collected by
212         `Q_OBJECT_D` for use at runtime. Signals can be connected to
213         slots or delegates with `connect`. Signals for classes
214         implemented in D also need a body with mixin `Q_SIGNAL_IMPL_D`.
215     +/
216     struct QSignal{}
217 
218     /++
219         UDA for marking member functions as slots.
220 
221         Meta data for marked member functions will be collected by
222         `Q_OBJECT_D` for use at runtime. Signals can be connected to
223         slots with `connect`.
224     +/
225     struct QSlot{}
226 
227     /++
228         UDA for marking member functions as invokable.
229 
230         Meta data for marked member functions will be collected by
231         `Q_OBJECT_D` for use at runtime.
232     +/
233     struct QInvokable{}
234 
235     /++
236         UDA for marking member functions as scriptable.
237 
238         Meta data for marked member functions will be collected by
239         `Q_OBJECT_D` for use at runtime.
240     +/
241     struct QScriptable{}
242 
243     /++
244         String constant for mixin in every class inheriting `QObject`.
245 
246         This is equivalent to the C++ macro [Q_OBJECT](https://doc.qt.io/qt-6/qobject.html#Q_OBJECT).
247         Every class inheriting `QObject` should mixin `Q_OBJECT` or
248         `Q_OBJECT_D`. Bindings to classes implemented in C++ should use
249         `Q_OBJECT`, while classes implemented in D should use `Q_OBJECT_D`.
250         Both mixins will add declarations for meta data about the class.
251         `Q_OBJECT_D` will also collect the the meta data itself, which
252         is done by the [Meta-Object Compiler](https://doc.qt.io/qt-6/moc.html)
253         for C++ classes.
254     +/
255     enum Q_OBJECT = qt.core.metamacros.Q_OBJECT;
256     /// ditto
257     enum Q_OBJECT_D = qt.core.metamacros.Q_OBJECT_D;
258 
259     /// String constant for mixin in every signal in classes implemnted in D.
260     enum Q_SIGNAL_IMPL_D = qt.core.metamacros.Q_SIGNAL_IMPL_D;
261 
262 public:
263 
264     /+ virtual +/ bool event(QEvent event);
265     /+ virtual +/ bool eventFilter(QObject watched, QEvent event);
266 
267     version(QT_NO_TRANSLATION)
268     {
269         static QString tr(const(char)* sourceText, const(char)*  /+ = nullptr +/, int /+ = -1 +/)
270             { return QString.fromUtf8(sourceText); }
271     }
272 
273     final QString objectName() const;
274     final void setObjectName(ref const(QString) name);
275     extern(D) final void setObjectName(const(char)[] name)
276     {
277         QString s = QString.fromUtf8(name.ptr, cast(int)name.length);
278         setObjectName(s);
279     }
280     final QBindable!(QString) bindableObjectName();
281 
282     pragma(inline, true) final bool isWidgetType() const { return d_ptr.isWidget; }
283     pragma(inline, true) final bool isWindowType() const { return d_ptr.isWindow; }
284 
285     pragma(inline, true) final bool signalsBlocked() const/+ noexcept+/ { return d_ptr.blockSig; }
286     final bool blockSignals(bool b)/+ noexcept+/;
287 
288     final QThread thread() const;
289     final void moveToThread(QThread thread);
290 
291     final int startTimer(int interval, /+ Qt:: +/qt.core.namespace.TimerType timerType = /+ Qt:: +/qt.core.namespace.TimerType.CoarseTimer);
292 /+ #if __has_include(<chrono>) +/
293     /+ Q_ALWAYS_INLINE
294     int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer)
295     {
296         return startTimer(int(time.count()), timerType);
297     } +/
298 /+ #endif +/
299     final void killTimer(int id);
300 
301     /+ template<typename T> +/
302     /+ inline T findChild(const QString &aName = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
303     {
304         typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
305         return static_cast<T>(qt_qFindChild_helper(this, aName, ObjType::staticMetaObject, options));
306     } +/
307 
308     /+ template<typename T> +/
309     /+ inline QList<T> findChildren(const QString &aName = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
310     {
311         typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
312         QList<T> list;
313         qt_qFindChildren_helper(this, aName, ObjType::staticMetaObject,
314                                 reinterpret_cast<QList<void *> *>(&list), options);
315         return list;
316     } +/
317 
318 /+ #if QT_CONFIG(regularexpression) +/
319     /+ template<typename T> +/
320     /+ inline QList<T> findChildren(const QRegularExpression &re, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
321     {
322         typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
323         QList<T> list;
324         qt_qFindChildren_helper(this, re, ObjType::staticMetaObject,
325                                 reinterpret_cast<QList<void *> *>(&list), options);
326         return list;
327     } +/
328 /+ #endif +/ // QT_CONFIG(regularexpression)
329 
330     pragma(inline, true) final ref const(QObjectList) children() const { return d_ptr.children; }
331 
332     final void setParent(QObject parent);
333     final void installEventFilter(QObject filterObj);
334     final void removeEventFilter(QObject obj);
335 
336     // Workaround for https://issues.dlang.org/show_bug.cgi?id=22620
337     private enum dummyNamespaceConnectionType = __traits(getCppNamespaces, ConnectionType);
338 
339     mixin(changeWindowsMangling(q{mangleClassesTailConst}, q{
340     static QMetaObject.Connection connect(const QObject sender, const char *signal,
341                         const QObject receiver, const char *member, ConnectionType = ConnectionType.AutoConnection);
342     }));
343 
344     /+ static QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal,
345                         const QObject *receiver, const QMetaMethod &method,
346                         Qt::ConnectionType type = Qt::AutoConnection); +/
347 
348     /+ inline QMetaObject::Connection connect(const QObject *sender, const char *signal,
349                         const char *member, Qt::ConnectionType type = Qt::AutoConnection) const; +/
350 
351 /+ #ifdef Q_CLANG_QDOC
352     template<typename PointerToMemberFunction>
353     static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection);
354     template<typename PointerToMemberFunction, typename Functor>
355     static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor);
356     template<typename PointerToMemberFunction, typename Functor>
357     static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection);
358 #else +/
359     //Connect a signal to a pointer to qobject member function
360     /+ template <typename Func1, typename Func2> +/
361     /+ static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
362                                      const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot,
363                                      Qt::ConnectionType type = Qt::AutoConnection)
364     {
365         typedef QtPrivate::FunctionPointer<Func1> SignalType;
366         typedef QtPrivate::FunctionPointer<Func2> SlotType;
367 
368         static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
369                           "No Q_OBJECT in the class with the signal");
370 
371         //compilation error if the arguments does not match.
372         static_assert(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
373                           "The slot requires more arguments than the signal provides.");
374         static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
375                           "Signal and slot arguments are not compatible.");
376         static_assert((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
377                           "Return type of the slot is not compatible with the return type of the signal.");
378 
379         const int *types = nullptr;
380         if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
381             types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
382 
383         return connectImpl(sender, reinterpret_cast<void **>(&signal),
384                            receiver, reinterpret_cast<void **>(&slot),
385                            new QtPrivate::QSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
386                                            typename SignalType::ReturnType>(slot),
387                             type, types, &SignalType::Object::staticMetaObject);
388     } +/
389 
390     //connect to a function pointer  (not a member)
391     /+ template <typename Func1, typename Func2> +/
392     /+ static inline typename std::enable_if<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0, QMetaObject::Connection>::type
393             connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
394     {
395         return connect(sender, signal, sender, slot, Qt::DirectConnection);
396     } +/
397 
398     //connect to a function pointer  (not a member)
399     /+ template <typename Func1, typename Func2> +/
400     /+ static inline typename std::enable_if<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0 &&
401                                           !QtPrivate::FunctionPointer<Func2>::IsPointerToMemberFunction, QMetaObject::Connection>::type
402             connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,
403                     Qt::ConnectionType type = Qt::AutoConnection)
404     {
405         typedef QtPrivate::FunctionPointer<Func1> SignalType;
406         typedef QtPrivate::FunctionPointer<Func2> SlotType;
407 
408         static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
409                           "No Q_OBJECT in the class with the signal");
410 
411         //compilation error if the arguments does not match.
412         static_assert(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
413                           "The slot requires more arguments than the signal provides.");
414         static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
415                           "Signal and slot arguments are not compatible.");
416         static_assert((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
417                           "Return type of the slot is not compatible with the return type of the signal.");
418 
419         const int *types = nullptr;
420         if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
421             types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
422 
423         return connectImpl(sender, reinterpret_cast<void **>(&signal), context, nullptr,
424                            new QtPrivate::QStaticSlotObject<Func2,
425                                                  typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
426                                                  typename SignalType::ReturnType>(slot),
427                            type, types, &SignalType::Object::staticMetaObject);
428     } +/
429 
430     //connect to a functor
431     /+ template <typename Func1, typename Func2> +/
432     /+ static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::type
433             connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
434     {
435         return connect(sender, signal, sender, std::move(slot), Qt::DirectConnection);
436     } +/
437 
438     //connect to a functor, with a "context" object defining in which event loop is going to be executed
439     /+ template <typename Func1, typename Func2> +/
440     /+ static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::type
441             connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,
442                     Qt::ConnectionType type = Qt::AutoConnection)
443     {
444         typedef QtPrivate::FunctionPointer<Func1> SignalType;
445         const int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount<Func2 , typename SignalType::Arguments>::Value;
446 
447         static_assert((FunctorArgumentCount >= 0),
448                           "Signal and slot arguments are not compatible.");
449         const int SlotArgumentCount = (FunctorArgumentCount >= 0) ? FunctorArgumentCount : 0;
450         typedef typename QtPrivate::FunctorReturnType<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value>::Value SlotReturnType;
451 
452         static_assert((QtPrivate::AreArgumentsCompatible<SlotReturnType, typename SignalType::ReturnType>::value),
453                           "Return type of the slot is not compatible with the return type of the signal.");
454 
455         static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
456                           "No Q_OBJECT in the class with the signal");
457 
458         const int *types = nullptr;
459         if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
460             types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
461 
462         return connectImpl(sender, reinterpret_cast<void **>(&signal), context, nullptr,
463                            new QtPrivate::QFunctorSlotObject<Func2, SlotArgumentCount,
464                                 typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value,
465                                 typename SignalType::ReturnType>(std::move(slot)),
466                            type, types, &SignalType::Object::staticMetaObject);
467     } +/
468 /+ #endif +/ //Q_CLANG_QDOC
469 
470     /+ static bool disconnect(const QObject *sender, const char *signal,
471                            const QObject *receiver, const char *member); +/
472     /+ static bool disconnect(const QObject *sender, const QMetaMethod &signal,
473                            const QObject *receiver, const QMetaMethod &member); +/
474     /+ inline bool disconnect(const char *signal = nullptr,
475                            const QObject *receiver = nullptr, const char *member = nullptr) const
476         { return disconnect(this, signal, receiver, member); } +/
477     /+ inline bool disconnect(const QObject *receiver, const char *member = nullptr) const
478         { return disconnect(this, nullptr, receiver, member); } +/
479     static bool disconnect(ref const(QMetaObject.Connection));
480 
481 /+ #ifdef Q_CLANG_QDOC
482     template<typename PointerToMemberFunction>
483     static bool disconnect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method);
484 #else +/
485     /+ template <typename Func1, typename Func2> +/
486     /+ static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
487                                   const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot)
488     {
489         typedef QtPrivate::FunctionPointer<Func1> SignalType;
490         typedef QtPrivate::FunctionPointer<Func2> SlotType;
491 
492         static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
493                           "No Q_OBJECT in the class with the signal");
494 
495         //compilation error if the arguments does not match.
496         static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
497                           "Signal and slot arguments are not compatible.");
498 
499         return disconnectImpl(sender, reinterpret_cast<void **>(&signal), receiver, reinterpret_cast<void **>(&slot),
500                               &SignalType::Object::staticMetaObject);
501     } +/
502     /+ template <typename Func1> +/
503     /+ static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
504                                   const QObject *receiver, void **zero)
505     {
506         // This is the overload for when one wish to disconnect a signal from any slot. (slot=nullptr)
507         // Since the function template parameter cannot be deduced from '0', we use a
508         // dummy void ** parameter that must be equal to 0
509         Q_ASSERT(!zero);
510         typedef QtPrivate::FunctionPointer<Func1> SignalType;
511         return disconnectImpl(sender, reinterpret_cast<void **>(&signal), receiver, zero,
512                               &SignalType::Object::staticMetaObject);
513     } +/
514 /+ #endif +/ //Q_CLANG_QDOC
515 
516     /++
517         Returns the set of signals with given name and optionally filtered
518         by parameter types. All signals are used, if no parameter types are
519         given. Otherwise the parameter types have to match.
520 
521         Params:
522             name       = The signal name.
523             Params     = Parameter types for the signal.
524 
525         Returns:
526             Set of signals, which can be used with `connect`.
527     +/
528     template signal(string name, Params...)
529     {
530         extern(D) auto signal(this T)()
531         {
532             import std.meta;
533             static if(Params.length)
534                 return DQtMember!(T, Filter!(parametersSame!Params, __traits(getOverloads, T, name)))(cast(T)this);
535             else
536                 return DQtMember!(T, __traits(getOverloads, T, name))(cast(T)this);
537         }
538     }
539 
540     /++
541         Returns the set of slots with given name and optionally filtered
542         by parameter types. All slots are used, if no parameter types are
543         given. Otherwise the parameter types have to match.
544 
545         Params:
546             name       = The slot name.
547             Params     = Parameter types for the slot.
548 
549         Returns:
550             Set of slots, which can be used with `connect`.
551     +/
552     template slot(string name, Params...)
553     {
554         extern(D) auto slot(this T)()
555         {
556             import std.meta;
557             static if(Params.length)
558                 return DQtMember!(T, Filter!(parametersSame!Params, __traits(getOverloads, T, name)))(cast(T)this);
559             else
560                 return DQtMember!(T, __traits(getOverloads, T, name))(cast(T)this);
561         }
562     }
563 
564     /++
565         Connects a signal to a delegate.
566 
567         Params:
568             sender     = Signal to be connected.
569             context    = Optional object used for lifetime of delegate.
570             dg         = Delegate to be connected.
571             type       = Type of connection.
572 
573         Returns:
574             Connection.
575     +/
576     static extern(D) QMetaObject.Connection connect(Signal, Dg)(Signal sender, QObject context, Dg dg, ConnectionType type = ConnectionType.AutoConnection) if(is(Signal: DQtMember!P, P...) && !is(Dg: DQtMember!P2, P2...))
577     {
578         import core.stdcpp.new_;
579 
580         /*typedef QtPrivate::FunctionPointer<Func1> SignalType;
581         typedef QtPrivate::FunctionPointer<Func2> SlotType;
582 
583         Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
584                           "No Q_OBJECT in the class with the signal");*/
585 
586         //compilation error if the arguments does not match.
587         /*Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
588                           "The slot requires more arguments than the signal provides.");
589         Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
590                           "Signal and slot arguments are not compatible.");
591         Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
592                           "Return type of the slot is not compatible with the return type of the signal.");*/
593 
594         const int *types = null;
595         if (type == ConnectionType.QueuedConnection || type == ConnectionType.BlockingQueuedConnection)
596         {
597             assert(false);
598             //types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
599         }
600 
601         static assert(Signal.Members.length == 1);
602 
603         auto signal = &memberFunctionExternDeclaration!(Signal.Members[0]);
604 
605         auto slotObj = cpp_new!(DQtStaticSlotObject!(Parameters!Dg))(dg);
606 
607         //pragma(msg, __traits(parent, Signal.Type.staticMetaObject));
608 
609         auto mo = &Signal.Type.staticMetaObject;
610 
611         // TODO: ABI for virtual functions is different.
612         CPPMemberFunctionPointer!(Signal.Type) memberFunction = CPPMemberFunctionPointer!(Signal.Type)(signal);
613 
614         return connectImpl(sender.obj, cast(void**)&memberFunction, context, null,
615                            &slotObj.base,
616                            type, types, mo);
617     }
618     /// ditto
619     static extern(D) QMetaObject.Connection connect(Signal, Dg)(Signal sender, Dg dg, ConnectionType type = ConnectionType.AutoConnection) if(is(Signal: DQtMember!P, P...) && !is(Dg: DQtMember!P2, P2...))
620     {
621         return connect(sender, sender.obj, dg, type);
622     }
623 
624     /++
625         Connects a signal to a slot.
626 
627         Params:
628             sender     = Signal to be connected.
629             receiver   = Slot to be connected.
630             type       = Type of connection.
631 
632         Returns:
633             Connection.
634     +/
635     static extern(D) QMetaObject.Connection connect(Signal, Slot)(Signal sender, Slot receiver, ConnectionType type = ConnectionType.AutoConnection) if(is(Signal: DQtMember!P, P...) && is(Slot: DQtMember!P2, P2...))
636     {
637        import core.stdcpp.new_;
638 
639        /+ typedef QtPrivate::FunctionPointer<Func1> SignalType;
640         typedef QtPrivate::FunctionPointer<Func2> SlotType;
641 
642         Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
643                           "No Q_OBJECT in the class with the signal");
644 
645         //compilation error if the arguments does not match.
646         Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
647                           "The slot requires more arguments than the signal provides.");
648         Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
649                           "Signal and slot arguments are not compatible.");
650         Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
651                           "Return type of the slot is not compatible with the return type of the signal.");+/
652 
653         const int *types = null;
654         if (type == ConnectionType.QueuedConnection || type == ConnectionType.BlockingQueuedConnection)
655         {
656             assert(false); // TODO
657             //types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
658         }
659 
660         enum size_t[2] overloadIndices = delegate size_t[2](){
661             size_t[2] r = [size_t.max, size_t.max];
662             size_t numPossible;
663             static foreach(i, signal; Signal.Members)
664             static foreach(j, slot; Slot.Members)
665             {
666                 //pragma(msg, i, " ", j, " ", __traits(identifier, signal), " ", __traits(identifier, slot));
667                 static if(Parameters!(signal).length >= Parameters!(slot).length) // TODO: allow default arguments
668                 {{
669                     bool possible = true;
670                     static foreach(k; 0..Parameters!(slot).length)
671                     {
672                         static if(!__traits(compiles, {Parameters!(slot)[k] p = Parameters!(signal)[k].init;}))
673                         {
674                             //pragma(msg, " param ", k, " not compatible ", Parameters!(signal)[k], " ", Parameters!(slot)[k]);
675                             possible = false;
676                         }
677                         else
678                         {
679                             //pragma(msg, " param ", k, " compatible ", Parameters!(signal)[k], " ", Parameters!(slot)[k]);
680                         }
681                     }
682                     if(possible)
683                     {
684                         r = [i, j];
685                         numPossible++;
686                     }
687                 }}
688             }
689             if(numPossible == 1)
690                 return r;
691             return [size_t.max, size_t.max];
692         }();
693 
694         static if(overloadIndices[0] == size_t.max || overloadIndices[1] == size_t.max)
695         {
696             pragma(msg, "Signals:");
697             static foreach(signal; Signal.Members)
698                 pragma(msg, __traits(identifier, signal), " ", Parameters!(signal));
699             pragma(msg, "Slots:");
700             static foreach(slot; Slot.Members)
701                 pragma(msg, __traits(identifier, slot), " ", Parameters!(slot));
702         }
703         static assert(overloadIndices[0] != size_t.max);
704         static assert(overloadIndices[1] != size_t.max);
705 
706         auto signal = &memberFunctionExternDeclaration!(Signal.Members[overloadIndices[0]]);
707 
708         auto slot = &memberFunctionExternDeclaration!(Slot.Members[overloadIndices[1]]);
709 
710         alias UsedParams = Parameters!(Signal.Members[overloadIndices[0]])[0..Parameters!(Slot.Members[overloadIndices[1]]).length];
711 
712         auto slotObj = cpp_new!(DQtMemberSlotObject!(typeof(Slot.obj), Slot.Members[overloadIndices[1]], UsedParams))(0);
713 
714         auto mo = &Signal.Type.staticMetaObject;
715 
716         // TODO: ABI for virtual functions is different.
717         CPPMemberFunctionPointer!(Signal.Type) memberFunction = CPPMemberFunctionPointer!(Signal.Type)(signal);
718         CPPMemberFunctionPointer!(Slot.Type) memberFunction2 = CPPMemberFunctionPointer!(Slot.Type)(slot);
719 
720         return connectImpl(sender.obj, cast(void**)&memberFunction,
721                            receiver.obj, cast(void**)&memberFunction2,
722                            &slotObj.base,
723                             type, types, mo);
724     }
725 
726     final void dumpObjectTree() const;
727     final void dumpObjectInfo() const;
728 
729     version(QT_NO_PROPERTIES){}else
730     {
731         final bool setProperty(const(char)* name, ref const(QVariant) value);
732         final bool setProperty(T)(const(char)* name, auto ref T value)
733         {
734             QVariant v = QVariant(value);
735             return setProperty(name, v);
736         }
737         final QVariant property(const(char)* name) const;
738         final QList!(QByteArray) dynamicPropertyNames() const;
739         final QBindingStorage* bindingStorage() { return &d_ptr.bindingStorage; }
740         final const(QBindingStorage)* bindingStorage() const { return &d_ptr.bindingStorage; }
741     }
742 
743 /+ Q_SIGNALS +/public:
744     @QSignal final void destroyed(QObject  /+ = nullptr +/);
745     @QSignal final void objectNameChanged(ref const(QString) objectName, QPrivateSignal);
746 
747 public:
748     pragma(inline, true) final QObject parent() const { return d_ptr.data.parent; }
749 
750     pragma(inline, true) final bool inherits(const(char)* classname) const
751     {
752         return const_cast!(QObject)(this).qt_metacast(classname) !is null;
753     }
754 
755 public /+ Q_SLOTS +/:
756     @QSlot final void deleteLater();
757 
758 protected:
759     final QObject sender() const;
760     final int senderSignalIndex() const;
761     final int receivers(const(char)* signal) const;
762     final bool isSignalConnected(ref const(QMetaMethod) signal) const;
763 
764     /+ virtual +/ void timerEvent(QTimerEvent event);
765     /+ virtual +/ void childEvent(QChildEvent event);
766     /+ virtual +/ void customEvent(QEvent event);
767 
768     /+ virtual +/ void connectNotify(ref const(QMetaMethod) signal);
769     /+ virtual +/ void disconnectNotify(ref const(QMetaMethod) signal);
770 
771 protected:
772     this(ref QObjectPrivate dd, QObject parent = null);
773 
774 protected:
775     QScopedPointer!(QObjectData) d_ptr;
776 
777     /+ friend struct QMetaObject; +/
778     /+ friend struct QMetaObjectPrivate; +/
779     /+ friend class QMetaCallEvent; +/
780     /+ friend class QApplication; +/
781     /+ friend class QApplicationPrivate; +/
782     /+ friend class QCoreApplication; +/
783     /+ friend class QCoreApplicationPrivate; +/
784     /+ friend class QWidget; +/
785     /+ friend class QAccessibleWidget; +/
786     /+ friend class QThreadData; +/
787 
788 private:
789     /+ Q_DISABLE_COPY(QObject) +/
790     /+ Q_PRIVATE_SLOT(d_func(), void _q_reregisterTimers(void *)) +/
791 
792 private:
793     // Workaround for https://issues.dlang.org/show_bug.cgi?id=22620
794     enum dummyNamespaceQSlotObjectBase = __traits(getCppNamespaces, qt.core.objectdefs_impl.QSlotObjectBase);
795 
796     mixin(changeWindowsMangling(q{mangleClassesTailConst}, q{
797     static QMetaObject.Connection connectImpl(const(QObject) sender, void** signal,
798                                                    const(QObject) receiver, void** slotPtr,
799                                                    /+ QtPrivate:: +/qt.core.objectdefs_impl.QSlotObjectBase* slot, /+ Qt:: +/qt.core.namespace.ConnectionType type,
800                                                    const(int)* types, const(QMetaObject)* senderMetaObject);
801     }));
802 
803     mixin(changeWindowsMangling(q{mangleClassesTailConst}, q{
804     static bool disconnectImpl(const(QObject) sender, void** signal, const(QObject) receiver, void** slot,
805                                    const(QMetaObject)* senderMetaObject);
806     }));
807 
808     mixin(CREATE_CONVENIENCE_WRAPPERS);
809 }
810 
811 /+ inline QMetaObject::Connection QObject::connect(const QObject *asender, const char *asignal,
812                                             const char *amember, Qt::ConnectionType atype) const
813 { return connect(asender, asignal, this, amember, atype); }
814 
815 pragma(inline, true) const(QMetaObject)* qt_getQtMetaObject()/+ noexcept+/
816 { return &QObject.staticQtMetaObject; }
817 
818 version(QT_NO_USERDATA){}else
819 {
820     typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
821     static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
822                     "qobject_cast requires the type to have a Q_OBJECT macro");
823     return static_cast<T>(ObjType::staticMetaObject.cast(object));
824 } +/
825 
826 T qobject_cast(T)(QObject object) if(is(T : QObject))
827 {
828     static assert(is(__traits(parent, T.staticMetaObject) == T));
829     return static_cast!T(T.staticMetaObject.cast_(object));
830 }
831 
832 /+ template <class T>
833 inline T qobject_cast(const QObject *object)
834 {
835     typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
836     static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
837                       "qobject_cast requires the type to have a Q_OBJECT macro");
838     return static_cast<T>(ObjType::staticMetaObject.cast(object));
839 }
840 
841 template <class T> inline const char * qobject_interface_iid()
842 { return nullptr; } +/
843 
844 pragma(inline, true) const(QBindingStorage)* qGetBindingStorage(const(QObject) o)
845 {
846     return o.bindingStorage();
847 }
848 pragma(inline, true) QBindingStorage* qGetBindingStorage(QObject o)
849 {
850     return o.bindingStorage();
851 }
852 
853 /+ #if defined(Q_CLANG_QDOC)
854 #  define Q_DECLARE_INTERFACE(IFace, IId)
855 #elif !defined(Q_MOC_RUN)
856 #  define Q_DECLARE_INTERFACE(IFace, IId) \
857     template <> inline const char *qobject_interface_iid<IFace *>() \
858     { return IId; } \
859     template <> inline IFace *qobject_cast<IFace *>(QObject *object) \
860     { return reinterpret_cast<IFace *>((object ? object->qt_metacast(IId) : nullptr)); } \
861     template <> inline IFace *qobject_cast<IFace *>(const QObject *object) \
862     { return reinterpret_cast<IFace *>((object ? const_cast<QObject *>(object)->qt_metacast(IId) : nullptr)); }
863 #endif // Q_MOC_RUN
864 
865 #ifndef QT_NO_DEBUG_STREAM
866 Q_CORE_EXPORT QDebug operator<<(QDebug, const QObject *);
867 #endif
868 
869 class QSignalBlocker
870 {
871 public:
872     inline explicit QSignalBlocker(QObject *o) noexcept;
873     inline explicit QSignalBlocker(QObject &o) noexcept;
874     inline ~QSignalBlocker();
875 
876     inline QSignalBlocker(QSignalBlocker &&other) noexcept;
877     inline QSignalBlocker &operator=(QSignalBlocker &&other) noexcept;
878 
879     inline void reblock() noexcept;
880     inline void unblock() noexcept;
881 
882 private:
883     Q_DISABLE_COPY(QSignalBlocker)
884     QObject *m_o;
885     bool m_blocked;
886     bool m_inhibited;
887 };
888 
889 QSignalBlocker::QSignalBlocker(QSignalBlocker &&other) noexcept
890     : m_o(other.m_o),
891       m_blocked(other.m_blocked),
892       m_inhibited(other.m_inhibited)
893 {
894     other.m_o = nullptr;
895 }
896 
897 QSignalBlocker &QSignalBlocker::operator=(QSignalBlocker &&other) noexcept
898 {
899     if (this != &other) {
900         // if both *this and other block the same object's signals:
901         // unblock *this iff our dtor would unblock, but other's wouldn't
902         if (m_o != other.m_o || (!m_inhibited && other.m_inhibited))
903             unblock();
904         m_o = other.m_o;
905         m_blocked = other.m_blocked;
906         m_inhibited = other.m_inhibited;
907         // disable other:
908         other.m_o = nullptr;
909     }
910     return *this;
911 }
912 
913 namespace QtPrivate {
914     inline QObject & deref_for_methodcall(QObject &o) { return  o; }
915     inline QObject & deref_for_methodcall(QObject *o) { return *o; }
916 }
917 #define Q_SET_OBJECT_NAME(obj) QT_PREPEND_NAMESPACE(QtPrivate)::deref_for_methodcall(obj).setObjectName(QLatin1String(#obj)) +/
918 
919 
920 /+ #endif +/
921 
922 template IsQSignal(alias F)
923 {
924     enum IsQSignal = getUDAs!(F, QObject.QSignal).length > 0;
925 }
926 template IsQSlot(alias F)
927 {
928     enum IsQSlot = getUDAs!(F, QObject.QSlot).length > 0;
929 }
930 template IsQInvokable(alias F)
931 {
932     enum IsQInvokable = getUDAs!(F, QObject.QInvokable).length > 0;
933 }
934 template IsQScriptable(alias F)
935 {
936     enum IsQScriptable = getUDAs!(F, QObject.Scriptable).length > 0;
937 }