maxter@253: /** maxter@253: * maxter@372: * Copyright: Copyright QtD Team, 2008-2010 maxter@372: * License: Boost License 1.0 maxter@372: * Authors: Max Samukha, Eldar Insafutdinov maxter@253: * maxter@253: */ maxter@253: maxter@344: module qtd.QtdObject; maxter@253: maxter@372: import maxter@372: core.memory, maxter@372: std.bitmanip, maxter@372: qtd.Core, maxter@372: qtd.Debug, maxter@382: qtd.meta.Runtime; maxter@372: maxter@372: /** maxter@372: QtdObject initialization options. maxter@372: */ maxter@372: enum QtdObjectInitFlags maxter@253: { maxter@253: none, maxter@372: /// The wrapper is being created by user code. maxter@372: createdByD = 0x1, maxter@372: /// The wrapper is being created with native ownership. maxter@372: nativeOwnership = 0x2, maxter@372: /// The wrapper is allocated on stack. maxter@372: onStack = 0x4 maxter@372: } maxter@372: maxter@372: /** maxter@372: */ maxter@372: enum QtdObjectOwnership maxter@372: { maxter@372: /// maxter@372: native, maxter@372: /// maxter@372: d maxter@372: } maxter@372: maxter@372: /** maxter@372: */ maxter@372: struct QtdObjectFlags maxter@372: { maxter@372: mixin (bitfields!( maxter@372: bool, "nativeDeleteDisabled" , 1, maxter@372: bool, "wrapperDeleteDisabled" , 1, maxter@372: bool, "createdByD" , 1, maxter@372: bool, "pinned" , 1, maxter@372: bool, "isQObject" , 1, maxter@372: bool, "polymorphic" , 1, maxter@372: bool, "onStack" , 1, maxter@372: int , "reserved" , 1 maxter@372: )); maxter@253: } maxter@253: maxter@372: maxter@372: /* package */ abstract class QtdObject maxter@253: { maxter@372: alias typeof(this) This; maxter@372: maxter@372: private maxter@372: { maxter@372: void* _nativeId; maxter@372: This _next; maxter@372: This _prev; maxter@372: __gshared static This _root; maxter@372: } maxter@372: maxter@372: protected QtdObjectFlags _flags; maxter@372: maxter@372: /** maxter@372: */ maxter@372: @property QtdObjectFlags qtdFlags() maxter@372: { maxter@372: return _flags; maxter@372: } maxter@253: maxter@372: /** maxter@372: */ maxter@372: @property final const maxter@372: { maxter@372: void* qtdNativeId() maxter@372: { maxter@372: return cast(void*)_nativeId; maxter@372: } maxter@372: maxter@372: void qtdNativeId(void* v) maxter@372: { maxter@372: unqual(_nativeId) = v; maxter@372: } maxter@372: } maxter@372: maxter@372: this(void* nativeId, QtdObjectInitFlags initFlags = QtdObjectInitFlags.none) maxter@253: { maxter@372: _nativeId = nativeId; maxter@372: maxter@372: if (initFlags & QtdObjectInitFlags.createdByD) maxter@372: _flags.createdByD = true; maxter@372: maxter@372: if (initFlags & QtdObjectInitFlags.nativeOwnership) maxter@372: qtdSetOwnership(QtdObjectOwnership.native); maxter@372: maxter@372: if (initFlags & QtdObjectInitFlags.onStack) maxter@372: { maxter@372: //assert(!_flags.isQObject); maxter@372: assert(!(initFlags & QtdObjectInitFlags.nativeOwnership)); maxter@372: maxter@372: _flags.nativeDeleteDisabled = true; maxter@372: _flags.wrapperDeleteDisabled = true; maxter@372: } maxter@372: maxter@372: mixin(debugHandler("onWrapperConstructed", "this")); maxter@253: } maxter@253: maxter@372: /** maxter@372: Disables GC for this object; maxter@372: */ maxter@372: // TODO: needs to be properly synchronized maxter@372: final void qtdPin() const maxter@253: { maxter@372: assert(!_flags.pinned); maxter@372: //GC.addRoot(cast(void*)this); maxter@372: maxter@372: auto obj = unqual(this); maxter@372: maxter@372: obj._next = _root; maxter@372: _root = obj; maxter@372: if (_next) maxter@372: obj._next._prev = obj; maxter@372: maxter@372: obj._flags.pinned = true; maxter@372: } maxter@372: maxter@372: /** maxter@372: Multiple wrappers for a single native object may exist. maxter@372: This function is used to test that this and the other wrapper point maxter@372: to the same native object (identity test). maxter@372: maxter@372: Note that wrappers for QObject instances and instances of classes maxter@372: derived from QObject are always unique, therefore maxter@382: the 'is' operator can be used instead of this function. maxter@372: */ maxter@372: final bool isSame(const(QtdObject) other) const maxter@372: { maxter@372: return other !is null && (other is this || other.qtdNativeId == qtdNativeId); maxter@253: } maxter@253: maxter@372: /** maxter@372: Enables GC for this object. maxter@372: */ maxter@372: // TODO: needs to be properly synchronized maxter@372: final void qtdUnpin() const maxter@253: { maxter@372: assert(_flags.pinned); maxter@372: //GC.removeRoot(cast(void*)this); maxter@372: maxter@372: auto obj = unqual(this); maxter@372: if (_prev) maxter@372: obj._prev._next = obj._next; maxter@253: else maxter@372: _root = obj._next; maxter@372: maxter@372: if (_next) maxter@372: obj._next._prev = obj._prev; maxter@372: maxter@372: obj._flags.pinned = false; maxter@372: } maxter@372: maxter@372: /** maxter@372: Sets the ownership of this object. maxter@372: Setting the same ownership twice results in undefined behavior. maxter@372: The function is not thread-safe. maxter@372: */ maxter@372: void qtdSetOwnership(QtdObjectOwnership own) const maxter@372: { maxter@372: if (_flags.isQObject) maxter@372: return; maxter@372: maxter@372: assert(!_flags.onStack); maxter@372: auto obj = unqual(this); maxter@372: maxter@372: if (own == QtdObjectOwnership.native) maxter@372: { maxter@372: if (_flags.polymorphic && _flags.createdByD) maxter@372: qtdPin(); maxter@372: else maxter@372: obj._flags.nativeDeleteDisabled = true; maxter@372: } maxter@372: else if (own == QtdObjectOwnership.d) maxter@372: { maxter@372: if (_flags.polymorphic && _flags.createdByD) maxter@372: qtdUnpin(); maxter@372: else maxter@372: obj._flags.nativeDeleteDisabled = false; maxter@372: } maxter@372: else maxter@372: assert(false); maxter@372: maxter@382: mixin(debugHandler("onObjectOwnershipChanged", "obj")); maxter@253: } maxter@253: maxter@253: // COMPILER BUG: 3206 maxter@372: protected void qtdDeleteNative() maxter@253: { maxter@253: assert(false); maxter@253: } maxter@253: maxter@253: ~this() maxter@253: { maxter@372: mixin(debugHandler("onWrapperDestruction", "this")); maxter@372: maxter@372: if (!_flags.nativeDeleteDisabled) maxter@253: { maxter@253: // avoid deleting D object twice. maxter@372: maxter@372: _flags.wrapperDeleteDisabled = true; maxter@372: qtdDeleteNative; maxter@372: maxter@372: mixin(debugHandler("onNativeDeleted", "this")); maxter@253: } maxter@372: maxter@372: if (_flags.pinned) maxter@372: qtdUnpin(); maxter@372: maxter@372: mixin(debugHandler("onWrapperDestroyed", "this")); maxter@372: } maxter@372: } maxter@372: maxter@372: /** maxter@372: Base class for polymorphic non-QObjects (TBD). maxter@372: */ maxter@372: /* package */ abstract class NonQObject : QtdObject maxter@372: { maxter@372: alias NonQObjectMetaClass Meta; maxter@372: maxter@372: this(void* nativeId, QtdObjectInitFlags initFlags) maxter@372: { maxter@372: _flags.polymorphic = true; maxter@372: super(nativeId, initFlags); maxter@253: } maxter@253: } maxter@354: maxter@372: /** maxter@372: Base class for QtD meta-object classes. maxter@372: */ maxter@372: abstract class QtdMetaClass : MetaClass maxter@372: { maxter@372: alias QtdObject function(void* nativeId, QtdObjectInitFlags initFlags) CreateWrapper; maxter@372: maxter@372: private void* _nativeId; maxter@372: protected CreateWrapper _createWrapper; maxter@372: maxter@372: this() {} maxter@372: maxter@372: /** maxter@372: */ maxter@372: @property maxter@372: void* nativeId() maxter@372: { maxter@372: return _nativeId; maxter@372: } maxter@372: maxter@372: void construct(T)() maxter@372: { maxter@372: super.construct!T(); maxter@372: _nativeId = T.qtdNativeStaticMetaObject(); maxter@372: _createWrapper = &T.qtdCreateWrapper; maxter@372: } maxter@372: maxter@372: abstract QtdObject getWrapper(void* nativeId, QtdObjectInitFlags initFlags = QtdObjectInitFlags.none); maxter@372: } maxter@372: maxter@372: /** maxter@372: Meta-object class for non-QObject polymorphic classes. maxter@372: */ maxter@372: final class NonQObjectMetaClass : QtdMetaClass maxter@372: { maxter@372: alias typeof(this) This; maxter@372: alias createImpl!This create; maxter@372: maxter@372: @property override This next() maxter@372: { maxter@372: return static_cast!This(super.next); maxter@372: } maxter@372: maxter@372: @property override This firstDerived() maxter@372: { maxter@372: return static_cast!This(super.firstDerived); maxter@372: } maxter@372: maxter@372: override QtdObject getWrapper(void* nativeId, QtdObjectInitFlags initFlags) maxter@372: { maxter@372: // traverse the inheritance tree to find a matching meta-object. maxter@372: // if the exact match is not found, return the closest base. maxter@372: This lookUp(This mo) maxter@372: { maxter@372: if (!qtdTypeInfosEqual(mo.nativeId, nativeId)) maxter@372: { maxter@372: for (auto mo2 = mo.firstDerived; mo2 !is null; mo2 = mo2.next) maxter@372: { maxter@372: mo2 = lookUp(mo2); maxter@372: if (mo != mo2) maxter@372: break; maxter@372: } maxter@372: } maxter@372: return mo; maxter@372: } maxter@372: maxter@372: auto mo = lookUp(this); maxter@372: return static_cast!NonQObject(mo._createWrapper(nativeId, initFlags)); maxter@372: } maxter@372: } maxter@372: maxter@372: extern (C) bool qtdTypeInfosEqual(void* info1, void* info2); maxter@372: maxter@357: mixin(qtdExport("void", "QtdObject_delete", "void* dId", maxter@357: q{ maxter@357: auto obj = cast(QtdObject)dId; maxter@354: maxter@372: mixin(debugHandler("onDeletingWrapperFromNative", "dId")); maxter@372: maxter@372: if (!obj._flags.wrapperDeleteDisabled) maxter@357: { maxter@357: // Avoid deleting native object twice maxter@372: obj._flags.nativeDeleteDisabled = true; maxter@357: delete obj; maxter@357: } maxter@357: }));