Fixed #36: harding against destruction of object inside event handler

Plus: declare the form builder to return a new
widget object (the way it is).
This commit is contained in:
Matthias Koefferlein 2017-12-16 01:45:35 +01:00
parent 6e14460334
commit ad741d0eb7
5 changed files with 21 additions and 8 deletions

View File

@ -1418,6 +1418,8 @@ drop_class "QSqlDriverPlugin" # not required ?
drop_method "QFormBuilder", /QFormBuilder::customWidgets\(\s*\)/ # Requires QDesignerCustomWidgetInterface which is not (yet) available
return_new "QAbstractFormBuilder", /::load/ # returns a free object
no_copy_ctor "QAbstractFormBuilder"
no_copy_ctor "QFormBuilder"

View File

@ -1602,6 +1602,8 @@ drop_class "QSqlDriverPlugin" # not required ?
drop_method "QFormBuilder", /QFormBuilder::customWidgets\(\s*\)/ # Requires QDesignerCustomWidgetInterface which is not (yet) available
return_new "QAbstractFormBuilder", /::load/ # returns a free object
no_copy_ctor "QAbstractFormBuilder"
no_copy_ctor "QFormBuilder"

View File

@ -97,7 +97,7 @@ static void _init_f_load_2654 (qt_gsi::GenericMethod *decl)
decl->add_arg<QIODevice * > (argspec_0);
static gsi::ArgSpecBase argspec_1 ("parentWidget", true, "0");
decl->add_arg<QWidget * > (argspec_1);
decl->set_return<QWidget * > ();
decl->set_return_new<QWidget * > ();
}
static void _call_f_load_2654 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret)

View File

@ -97,7 +97,7 @@ static void _init_f_load_2654 (qt_gsi::GenericMethod *decl)
decl->add_arg<QIODevice * > (argspec_0);
static gsi::ArgSpecBase argspec_1 ("parentWidget", true, "0");
decl->add_arg<QWidget * > (argspec_1);
decl->set_return<QWidget * > ();
decl->set_return_new<QWidget * > ();
}
static void _call_f_load_2654 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret)

View File

@ -221,19 +221,28 @@ void SignalHandler::call (const gsi::MethodBase *meth, gsi::SerialArgs &args, gs
PyTuple_SetItem (argv.get (), int (a - meth->begin_arguments ()), pop_arg (*a, args, NULL, heap).release ());
}
PythonRef result;
// NOTE: in case one event handler deletes the object, it's safer to first collect the handlers and
// then call them.
std::vector<PythonRef> callables;
callables.reserve (m_cbfuncs.size ());
for (std::vector<CallbackFunction>::const_iterator c = m_cbfuncs.begin (); c != m_cbfuncs.end (); ++c) {
callables.push_back (c->callable ());
}
PythonRef result;
for (std::vector<PythonRef>::const_iterator c = callables.begin (); c != callables.end (); ++c) {
// determine the number of arguments required
int arg_count = args_avail;
if (args_avail > 0) {
PythonRef fc (PyObject_GetAttrString (c->callable ().get (), "__code__"));
PythonRef fc (PyObject_GetAttrString (c->get (), "__code__"));
if (fc) {
PythonRef ac (PyObject_GetAttrString (fc.get (), "co_argcount"));
if (ac) {
arg_count = python2c<int> (ac.get ());
if (PyObject_HasAttrString (c->callable ().get (), "__self__")) {
if (PyObject_HasAttrString (c->get (), "__self__")) {
arg_count -= 1;
}
}
@ -243,12 +252,12 @@ void SignalHandler::call (const gsi::MethodBase *meth, gsi::SerialArgs &args, gs
// use less arguments if applicable
if (arg_count == 0) {
result = PythonRef (PyObject_CallObject (c->callable ().get (), NULL));
result = PythonRef (PyObject_CallObject (c->get (), NULL));
} else if (arg_count < args_avail) {
PythonRef argv_less (PyTuple_GetSlice (argv.get (), 0, arg_count));
result = PythonRef (PyObject_CallObject (c->callable ().get (), argv_less.get ()));
result = PythonRef (PyObject_CallObject (c->get (), argv_less.get ()));
} else {
result = PythonRef (PyObject_CallObject (c->callable ().get (), argv.get ()));
result = PythonRef (PyObject_CallObject (c->get (), argv.get ()));
}
if (! result) {