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 }