Subject: | Incorrect object initialization of inherited class created with Glib::Object::Subclass |
Glib::Object::Introspection initialize objects incorrectly if their classes have been inherited with Glib::Object::Subclass module.
For example, this code will fail with error "Can't locate object method "PARENT_SET" via package "MyButton"":
package MyButton;
use Gtk3;
use Glib::Object::Subclass
Gtk3::Button::,
signals => {},
properties => [],
;
sub INIT_INSTANCE {
my $self = shift;
return $self;
}
package main;
use Gtk3 -init;
my $window = Gtk3::Window->new();
$window->signal_connect(delete_event => sub { Gtk3->main_quit() });
my $my_button = MyButton->new("Test");
$window->add($my_button);
$window->show_all();
Gtk3->main();
"parent_set" is non-implemented vfunc. The problem is in gperl-i11n-vfunc-object.c :
...
/* If there is no implementation of this vfunc at INIT
* time, we assume that the intention is to provide no
* implementation and we thus skip setting up the class
* struct member. */
HV * stash = gv_stashpv (target_package, 0);
GV * slot = gv_fetchmethod (stash, perl_method_name);
if (!slot) {
dwarn ("skipping vfunc %s.%s because it has no implementation\n",
g_base_info_get_name (info), vfunc_name);
g_base_info_unref (vfunc_info);
g_free (perl_method_name);
continue;
}
}
...
where "gv_fetchmethod" is just a macro for "gv_fetchmethod_autoload":
#define gv_fetchmethod(stash, name) gv_fetchmethod_autoload(stash, name, TRUE)
But is doesn't allow us to find non-implemented vfuncs. Because it looks for them
in AUTOLOAD, if it can't find them in implemented methods. To fix this we need to
replace "gv_fetchmethod" with "gv_fetchmethod_autoload":
GV * slot = gv_fetchmethod_autoload (stash, perl_method_name, FALSE);
Patch has been attached.
Subject: | fix-searching-vfuncs.patch |
--- a.c 2015-04-14 19:58:49.000000000 +0300
+++ b.c 2015-04-14 13:39:05.437775480 +0300
@@ -46,7 +46,7 @@
* implementation and we thus skip setting up the class
* struct member. */
HV * stash = gv_stashpv (target_package, 0);
- GV * slot = gv_fetchmethod (stash, perl_method_name);
+ GV * slot = gv_fetchmethod_autoload (stash, perl_method_name, FALSE);
if (!slot) {
dwarn ("skipping vfunc %s.%s because it has no implementation\n",
g_base_info_get_name (info), vfunc_name);