Skip to content

Commit

Permalink
WIP: first solution for lost references issue
Browse files Browse the repository at this point in the history
* The solution consists of attaching a bridge object
  to QObjects. If the host object is destroyed, the
  bridge object will notify the script client
* The bridge object attachment is optimized so it
  only happens if required (but still too often ...)
* The child object of QChildEvent gets a special
  handling since this object is almost dead in case
  of remove. This special handling consists of
  a special, stripped class which is used to
  only represent QObject in that particular case.
  • Loading branch information
klayoutmatthias committed Feb 21, 2017
1 parent c15179a commit 92fd337
Show file tree
Hide file tree
Showing 1,297 changed files with 28,436 additions and 66 deletions.
59 changes: 59 additions & 0 deletions scripts/mkqtdecl/mkqtdecl.conf
Expand Up @@ -192,6 +192,7 @@ drop_method "QObject", /QObject::findChild/ # template member
drop_method "QObject", /QObject::findChildren/ # template member
drop_method "QObject", /QObject::setUserData/ # QObjectUserData not available
drop_method "QObject", /QObject::userData/ # QObjectUserData not available
drop_method "QChildEvent", /QChildEvent::child/ # provided through a special implementation
drop_method "QFile", /QFile::setDecodingFunction/ # uses callbacks
drop_method "QFile", /QFile::setEncodingFunction/ # uses callbacks
drop_method "QFile", /QFile::open.*IO_FILE/ # uses internal struct
Expand Down Expand Up @@ -272,6 +273,64 @@ CODE
gsi::method_ext("findChild", &find_child_impl, "@brief Specialisation for findChild (uses QObject as T).")
DECL

# alternative implementation for QChildEvent::child
# Reason: this method does not supply a true QObject pointer. Instead it will
# deliver a pointer to an object that is almost destroyed. Normal RTTI will
# not work on this. Neighter can it be attached an gsi::ObjectBase object.
add_native_impl("QChildEvent", <<'CODE', <<'DECL')

namespace gsi
{
gsi::Class<QObject> &qtdecl_QObject ();
}

namespace
{
struct DummyQObject { };

class RawQObjectClass
: public gsi::Class<QObject>
{
public:
RawQObjectClass ()
: gsi::Class<QObject> (gsi::qtdecl_QObject (), "QObject_Raw", gsi::Methods (), "@hide")
{
}

// Final class - because of missing RTTI, subclassing won't work.
virtual const gsi::ClassBase *subclass_decl (const void *) const { return this; }
virtual bool can_upcast (const void *) const { return false; }

// Does not bind to a particular type
virtual bool is_of_type (const std::type_info & /*ti*/) const { return false; }
virtual const std::type_info &type () const { return typeid (DummyQObject); }
};
}

static void _init_f_child (qt_gsi::GenericMethod *decl)
{
// Make the QChildEvent::child method return a special class which is final
// and does not try to return a gsi::ObjectBase object.
static RawQObjectClass s_cls;
decl->set_return<QObject * > ();
decl->ret_type ().set_cls (&s_cls);
}

static void _call_f_child (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs & /*args*/, gsi::SerialArgs &ret)
{
ret.write<QObject * > ((QObject *)((QChildEvent *)cls)->child ());
}

CODE
gsi::Methods(new qt_gsi::GenericMethod ("child",
"@brief Method QObject *QChildEvent::child()\n"
"NOTE: the object returned by this method is not memory managed. It may be destroyed internally without notice. \n"
"The returned object shall not be stored or used outside the childEvent handler. "
"If used outside this handler, the reference might get lost and the application may crash.\n"
"Furthermore, the object returned will only represent a QObject, not any derived type.\n",
true, &_init_f_child, &_call_f_child))
DECL

# alternative implementation for QFont::Light, QFont::Bold, QFont::Normal, QFont::DemiBold, QFont::Black
add_native_impl("QFont", <<'CODE', <<'DECL')
static unsigned int font_const_light () { return (unsigned int) QFont::Light; }
Expand Down
6 changes: 5 additions & 1 deletion scripts/mkqtdecl_common/produce.rb
Expand Up @@ -2211,7 +2211,11 @@ def produce_class(conf, decl_obj, ofile)
ofile.puts("}")
ofile.puts("")

decl_type = "gsi::Class<#{cls}>"
if is_qobject
decl_type = "qt_gsi::QtNativeClass<#{cls}>"
else
decl_type = "gsi::Class<#{cls}>"
end

if base_cls
ofile.puts("gsi::Class<#{base_cls}> &qtdecl_#{base_clsn} ();")
Expand Down
18 changes: 9 additions & 9 deletions src/gsi/gsiClass.h
Expand Up @@ -729,29 +729,29 @@ class Class
typedef typename tl::type_traits<X>::has_default_constructor has_default_ctor;
typedef typename tl::type_traits<X>::has_public_destructor has_public_dtor;

Class (const std::string &name, const Methods &mm, const std::string &doc = std::string ())
: ClassBase (doc, mm)
Class (const std::string &name, const Methods &mm, const std::string &doc = std::string (), bool do_register = true)
: ClassBase (doc, mm, do_register)
{
set_name (name);
}

template <class B>
Class (const Class<B> &base, const std::string &name, const Methods &mm, const std::string &doc = std::string ())
: ClassBase (doc, mm), m_subclass_tester (new SubClassTester<X, B, typename is_polymorphic<B>::value> ())
Class (const Class<B> &base, const std::string &name, const Methods &mm, const std::string &doc = std::string (), bool do_register = true)
: ClassBase (doc, mm, do_register), m_subclass_tester (new SubClassTester<X, B, typename is_polymorphic<B>::value> ())
{
set_name (name);
set_base (&base);
}

Class (const std::string &name, const std::string &doc = std::string ())
: ClassBase (doc, Methods ())
Class (const std::string &name, const std::string &doc = std::string (), bool do_register = true)
: ClassBase (doc, Methods (), do_register)
{
set_name (name);
}

template <class B>
Class (const Class<B> &base, const std::string &name, const std::string &doc = std::string ())
: ClassBase (doc, Methods ()), m_subclass_tester (new SubClassTester<X, B, typename is_polymorphic<B>::value> ())
Class (const Class<B> &base, const std::string &name, const std::string &doc = std::string (), bool do_register = true)
: ClassBase (doc, Methods (), do_register), m_subclass_tester (new SubClassTester<X, B, typename is_polymorphic<B>::value> ())
{
set_name (name);
set_base (&base);
Expand Down Expand Up @@ -785,7 +785,7 @@ class Class
return tl::is_derived<gsi::ObjectBase, X> ();
}

gsi::ObjectBase *gsi_object (void *p) const
gsi::ObjectBase *gsi_object (void *p, bool /*required*/) const
{
return tl::try_static_cast<gsi::ObjectBase, X> ((X *) p);
}
Expand Down
10 changes: 6 additions & 4 deletions src/gsi/gsiClassBase.cc
Expand Up @@ -39,13 +39,15 @@ namespace gsi

ClassBase::class_collection *ClassBase::mp_class_collection = 0;

ClassBase::ClassBase (const std::string &doc, const Methods &mm)
ClassBase::ClassBase (const std::string &doc, const Methods &mm, bool do_register)
: mp_base (0), mp_parent (0), m_doc (doc), m_methods (mm)
{
if (! mp_class_collection) {
mp_class_collection = new class_collection ();
if (do_register) {
if (! mp_class_collection) {
mp_class_collection = new class_collection ();
}
mp_class_collection->push_back (this);
}
mp_class_collection->push_back (this);
}

ClassBase::~ClassBase ()
Expand Down
9 changes: 7 additions & 2 deletions src/gsi/gsiClassBase.h
Expand Up @@ -85,7 +85,7 @@ class GSI_PUBLIC ClassBase
*
* The constructor supplies information about the connector class (can be 0), a documentation string and the method declarations.
*/
ClassBase (const std::string &doc, const Methods &mm);
ClassBase (const std::string &doc, const Methods &mm, bool do_register = true);

/**
* @brief Destructor
Expand Down Expand Up @@ -437,8 +437,13 @@ class GSI_PUBLIC ClassBase
/**
* @brief Gets the basic gsi::ObjectBase object from a generic pointer
* This method will return 0, if the object is not managed.
* If required is false, a return value of 0 is permitted, indicating that
* no dynamic allocation of a gsi::ObjectBase has happened yet. This is useful
* in case of the Qt-GSI bridge which means a special Qt object needs to be
* created in order to provide the gsi::ObjectBase interface. If required is
* false, this initialization does not need to happen.
*/
virtual gsi::ObjectBase *gsi_object (void * /*p*/) const
virtual gsi::ObjectBase *gsi_object (void * /*p*/, bool /*required*/ = true) const
{
tl_assert (false);
return 0;
Expand Down
2 changes: 1 addition & 1 deletion src/gsi/gsiDeclInternal.cc
Expand Up @@ -226,7 +226,7 @@ Class<MethodBase> decl_Method ("Method",
gsi::iterator ("each_argument", &MethodBase::begin_arguments, &MethodBase::end_arguments,
"@brief Iterate over all arguments of this method\n"
) +
gsi::method ("ret_type", &MethodBase::ret_type,
gsi::method ("ret_type", (const gsi::ArgType &(MethodBase::*)() const) &MethodBase::ret_type,
"@brief The return type of this method\n"
) +
gsi::method ("is_protected?", &MethodBase::is_protected,
Expand Down
25 changes: 25 additions & 0 deletions src/gsi/gsiMethods.h
Expand Up @@ -193,6 +193,14 @@ class GSI_PUBLIC MethodBase
return m_doc;
}

/**
* @brief Sets the documentation text
*/
void set_doc (const std::string &d)
{
m_doc = d;
}

/**
* @brief Returns the nth (index) argument
*/
Expand All @@ -202,6 +210,15 @@ class GSI_PUBLIC MethodBase
return m_arg_types [index];
}

/**
* @brief Returns the nth (index) argument (non_const version)
*/
ArgType &arg (size_t index)
{
tl_assert (m_arg_types.size () > index);
return m_arg_types [index];
}

/**
* @brief Iterates the arguments (begin)
*/
Expand All @@ -226,6 +243,14 @@ class GSI_PUBLIC MethodBase
return m_ret_type;
}

/**
* @brief Gets the return type (non-const version)
*/
ArgType &ret_type ()
{
return m_ret_type;
}

/**
* @brief Gets a value indicating whether this method is a const method
*/
Expand Down
19 changes: 9 additions & 10 deletions src/gsi/gsiObject.cc
Expand Up @@ -92,7 +92,10 @@ void
Proxy::detach ()
{
if (m_cls_decl && m_cls_decl->is_managed ()) {
m_cls_decl->gsi_object (m_obj)->status_changed_event ().remove (this, &Proxy::object_status_changed);
gsi::ObjectBase *gsi_object = m_cls_decl->gsi_object (m_obj, false);
if (gsi_object) {
gsi_object->status_changed_event ().remove (this, &Proxy::object_status_changed);
}
}

m_obj = 0;
Expand Down Expand Up @@ -157,7 +160,10 @@ Proxy::set (void *obj, bool owned, bool const_ref, bool can_destroy)
if (m_obj) {

if (cls->is_managed ()) {
cls->gsi_object (m_obj)->status_changed_event ().remove (this, &Proxy::object_status_changed);
gsi::ObjectBase *gsi_object = cls->gsi_object (m_obj, false);
if (gsi_object) {
gsi_object->status_changed_event ().remove (this, &Proxy::object_status_changed);
}
}

// Destroy the object if we are owner. We don't destroy the object if it was locked
Expand Down Expand Up @@ -211,14 +217,7 @@ void
Proxy::object_status_changed (gsi::ObjectBase::StatusEventType type)
{
if (type == gsi::ObjectBase::ObjectDestroyed) {

// external reset - the object no longer will be available so we unlink from it
m_obj = 0;
m_destroyed = true;
m_const_ref = false;
m_owned = false;
m_can_destroy = false;

detach ();
} else if (type == gsi::ObjectBase::ObjectKeep) {
m_owned = false;
} else if (type == gsi::ObjectBase::ObjectRelease) {
Expand Down
22 changes: 22 additions & 0 deletions src/gsiqt/gsiDeclQAbstractButton.cc
@@ -1,3 +1,25 @@

/*
KLayout Layout Viewer
Copyright (C) 2006-2017 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

/**
* @file gsiDeclQAbstractButton.cc
*
Expand Down
22 changes: 22 additions & 0 deletions src/gsiqt/gsiDeclQAbstractFormBuilder.cc
@@ -1,3 +1,25 @@

/*
KLayout Layout Viewer
Copyright (C) 2006-2017 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

/**
* @file gsiDeclQAbstractFormBuilder.cc
*
Expand Down
22 changes: 22 additions & 0 deletions src/gsiqt/gsiDeclQAbstractGraphicsShapeItem.cc
@@ -1,3 +1,25 @@

/*
KLayout Layout Viewer
Copyright (C) 2006-2017 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

/**
* @file gsiDeclQAbstractGraphicsShapeItem.cc
*
Expand Down
22 changes: 22 additions & 0 deletions src/gsiqt/gsiDeclQAbstractItemDelegate.cc
@@ -1,3 +1,25 @@

/*
KLayout Layout Viewer
Copyright (C) 2006-2017 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

/**
* @file gsiDeclQAbstractItemDelegate.cc
*
Expand Down

0 comments on commit 92fd337

Please sign in to comment.