Note(Nov-22-2018): Now updated with Valgrind output. See comments
OK, so I have some code that attempts to set many GValues at once via gtk_list_store_se_valuesv. I can set everything up, but when I use it, I get a Segmentation Fault. You can see this in action via this bit of self-contained code. Bear with me, it's a bit long.
use v6.c;
use NativeCall;
class GtkTreeIter is repr('CStruct') {
has int32 $.stamp;
has Pointer $.user_data;
has Pointer $.user_data2;
has Pointer $.user_data3;
}
class GTypeValueList is repr('CUnion') {
has int32 $.v_int is rw;
has uint32 $.v_uint is rw;
has long $.v_long is rw;
has ulong $.v_ulong is rw;
has int64 $.v_int64 is rw;
has uint64 $.v_uint64 is rw;
has num32 $.v_float is rw;
has num64 $.v_double is rw;
has Pointer $.v_pointer is rw;
};
class GValue is repr('CStruct') {
has ulong $.g_type is rw;
HAS GTypeValueList $.data1 is rw;
HAS GTypeValueList $.data2 is rw;
}
sub gtk_list_store_newv (int32 $n_columns, CArray[uint64] $types)
returns Pointer
is native('gtk-3')
is export
{ * }
sub gtk_list_store_set_valuesv (
Pointer $list_store,
GtkTreeIter $iter,
CArray[int32] $columns,
CArray[GValue] $values,
int32 $n_values
)
is native('gtk-3')
is export
{ * }
sub set_valuesv (
Pointer $store,
GtkTreeIter $iter,
@columns,
@values,
Int() $n_values
) {
my $c_columns = CArray[int32].new;
my $c_values = CArray[GValue].new;
$c_columns[$_] = @columns[$_].Int for (^$n_values);
$c_values[$_] = @values[$_] for (^$n_values);
gtk_list_store_set_valuesv($store, $iter, $c_columns, $c_values, $n_values);
}
sub g_value_init (GValue $value, uint64 $type)
returns GValue
is native('gobject-2.0')
is export
{ * }
sub gtk_list_store_append (Pointer $list_store, GtkTreeIter $iter)
is native('gtk-3')
is export
{ * }
sub g_value_set_string (GValue $value, Str $v_string)
is native('gobject-2.0')
is export
{ * }
sub g_value_set_boolean (GValue $value, uint32 $v_boolean)
is native('gobject-2.0')
is export
{ * }
sub gtk_list_store_set_value (
Pointer $list_store,
GtkTreeIter $iter,
int32 $column,
GValue $value
)
is native('gtk-3')
is export
{ * }
sub new_list_store (@types) {
my $t = CArray[uint64].new(@types);
my int32 $columns = @types.elems;
gtk_list_store_newv($columns, $t);
}
my @types = (64, 64, 20);
sub new_value($t) {
my $v = GValue.new;
g_value_init($v, $t);
$v;
}
my $store = new_list_store(@types);
my $iter = GtkTreeIter.new;
for (^5) -> $o {
my %data = (
0 => new_value(64), # String
1 => new_value(64), # String
2 => new_value(20), # Boolean
);
for (^3) {
when 0 | 1 {
g_value_set_string(%data{$_}, "String{ $_ + 1}-{ $o }");
}
default {
g_value_set_boolean(%data{$_}, (^1).pick);
}
}
gtk_list_store_append($store, $iter);
set_valuesv(
$store,
$iter,
%data.keys.sort,
%data.keys.sort.map({ %data{$_} }),
%data.keys.elems
);
#gtk_list_store_set_value($store, $iter, $_.Int, %data{$_}) for %data.keys;
}
If you run this code, you will get something akin to the following:
...
(process:14154): GLib-GObject-CRITICAL **: 10:48:17.398: g_value_type_transformable: assertion 'G_TYPE_IS_VALUE (src_type)' failed
(process:14154): Gtk-WARNING **: 10:48:17.398: ../../../../gtk/gtkliststore.c:836: Unable to convert from (null) to gchararray
(process:14154): GLib-GObject-CRITICAL **: 10:48:17.398: g_value_type_transformable: assertion 'G_TYPE_IS_VALUE (src_type)' failed
(process:14154): Gtk-WARNING **: 10:48:17.398: ../../../../gtk/gtkliststore.c:836: Unable to convert from (null) to gchararray
(process:14154): GLib-GObject-CRITICAL **: 10:48:17.398: g_value_type_transformable: assertion 'G_TYPE_IS_VALUE (src_type)' failed
(process:14154): Gtk-WARNING **: 10:48:17.398: ../../../../gtk/gtkliststore.c:836: Unable to convert from (null) to gboolean
Segmentation fault (core dumped)
I cannot explain why this happens, since this routine is supposed to take an array of GValue types, and that is what is being passed.
However, if I change the following code to read like so:
#set_valuesv(
# $store,
# $iter,
# %data.keys.sort,
# %data.keys.sort.map({ %data{$_} }),
# %data.keys.elems
#);
gtk_list_store_set_value($store, $iter, $_.Int, %data{$_}) for %data.keys;
It works just fine with no errors!
Even more confusing, if alter the code to take just a pointer to a GValue, it also works. But this means that set_valuesv can ONLY take one GValue. You can see this by altering the native call definition of gtk_list_store_set_valuesv to be:
sub gtk_list_store_set_valuesv (
Pointer $list_store,
GtkTreeIter $iter,
CArray[int32] $columns,
GValue $value,
int32 $n_values
)
is native('gtk-3')
is export
{ * }
And the set_valuesv function to be:
sub set_valuesv (
Pointer $store,
GtkTreeIter $iter,
@columns,
@values,
Int() $n_values
) {
my $c_columns = CArray[int32].new;
my $c_values = CArray[GValue].new;
$c_columns[$_] = @columns[$_].Int for (^$n_values);
$c_values[$_] = @values[$_] for (^$n_values);
gtk_list_store_set_valuesv($store, $iter, $c_columns, $c_values[0], $n_values);
} for %data.keys;
So the calls to set then become:
set_valuesv($store, $iter, ($_).Array, %data{$_}.Array, 1);
(Note: Please remember to uncomment the right bits of code so that this is the only set function being executed)
If you run the code again, suddenly everything works.
Is this a problem with my invocation, or is CArray not doing what I'm expecting it to do, here? Is this an issue with a CStruct with an embedded union?
On the off chance it was the union, I went back to the original program and tried it, with the following change:
class GValue is repr('CStruct') {
has ulong $.g_type is rw;
has uint64 $.data1 is rw;
has uint64 $.data2 is rw;
}
And while the errors persisted, there was no segfault (at leat on the first run... successive runs generated a segfault maybe 1 in 3 times!):
...
(process:14263): Gtk-WARNING **: 11:25:32.288: ../../../../gtk/gtkliststore.c:836: Unable to convert from (null) to gboolean
(process:14263): Gtk-WARNING **: 11:25:32.289: ../../../../gtk/gtkliststore.c:836: Unable to convert from GObject to gchararray
(process:14263): GLib-GObject-CRITICAL **: 11:25:32.289: g_value_type_transformable: assertion 'G_TYPE_IS_VALUE (src_type)' failed
(process:14263): Gtk-WARNING **: 11:25:32.289: ../../../../gtk/gtkliststore.c:836: Unable to convert from (null) to gboolean
(with segfault):
(process:14352): GLib-GObject-CRITICAL **: 11:34:57.639: g_value_type_transformable: assertion 'G_TYPE_IS_VALUE (src_type)' failed
(process:14352): Gtk-WARNING **: 11:34:57.639: ../../../../gtk/gtkliststore.c:836: Unable to convert from GEnum to gchararray
Segmentation fault (core dumped)
Maybe there is something there that can help?
As an update to this old, but still pertinent thread, Here is the valgrind output from this script: