Tags: patch
Followup-For: Bug #494515
I found two revision in the upstream SVN that deal with garbage
collection (revisions 3255 and 3263). When I applied these changes to
the Debian package, the script runs without crashing.
(The script doesn't animate properly though, it should use a
GtkDrawingArea. Fixed version attached :)
--- a/glib/ChangeLog
+++ b/glib/ChangeLog
@@ -1,3 +1,17 @@
+2008-06-19 Kouhei Sutou <[EMAIL PROTECTED]>
+
+ * src/rbgobj_type.c (rbgobj_lookup_class_by_gtype_body): add
+ create_class option.
+
+ * src/rbgobject.h (GTYPE2CINFO_NO_CREATE): add.
+
+ * src/rbgobject.h, src/rbgobj_type.c
+ (rbgobj_lookup_class_by_gtype_full): add.
+
+ * src/rbgobj_typeinstance.c (each_cinfo): don't create object
+ during GC to work with ruby 1.8.7.
+ Reported by Kazuhiro NISHIYAMA. Thanks!!!
+
2008-05-23 Kouhei Sutou <[EMAIL PROTECTED]>
* test/run-test.rb: use which not --version to detect make.
--- a/glib/src/rbgobj_type.c
+++ b/glib/src/rbgobj_type.c
@@ -39,8 +39,9 @@
} RGObjClassInfoDynamic;
typedef struct {
- VALUE parent;
- GType gtype;
+ VALUE parent;
+ GType gtype;
+ gboolean create_class;
} RGObjClassByGtypeData;
static void
@@ -125,10 +126,14 @@
return (VALUE)NULL;
c = rb_hash_aref(gtype_to_cinfo, INT2NUM(gtype));
- if (!NIL_P(c)){
+ if (!NIL_P(c)) {
Data_Get_Struct(c, RGObjClassInfo, cinfo);
return (VALUE)cinfo;
}
+
+ if (!cdata->create_class)
+ return (VALUE)NULL;
+
c = Data_Make_Struct(rb_cData, RGObjClassInfo, cinfo_mark, NULL, cinfo);
cinfo->gtype = gtype;
cinfo->mark = NULL;
@@ -230,8 +235,19 @@
const RGObjClassInfo *
rbgobj_lookup_class_by_gtype(GType gtype, VALUE parent)
{
+ return rbgobj_lookup_class_by_gtype_full(gtype, parent, TRUE);
+}
+
+const RGObjClassInfo *
+rbgobj_lookup_class_by_gtype_full(GType gtype, VALUE parent,
+ gboolean create_class)
+{
VALUE critical = rb_thread_critical;
- RGObjClassByGtypeData data = { .parent = parent, .gtype = gtype };
+ RGObjClassByGtypeData data;
+
+ data.gtype = gtype;
+ data.parent = parent;
+ data.create_class = create_class;
rb_thread_critical = 1;
--- a/glib/src/rbgobject.h
+++ b/glib/src/rbgobject.h
@@ -76,6 +76,7 @@
#define CLASS2CINFO(klass) (rbgobj_lookup_class(klass))
#define GTYPE2CINFO(gtype) (rbgobj_lookup_class_by_gtype(gtype, Qnil))
+#define GTYPE2CINFO_NO_CREATE(gtype) (rbgobj_lookup_class_by_gtype_full(gtype, Qnil, FALSE))
#define RVAL2CINFO(obj) (rbgobj_lookup_class(CLASS_OF(obj)))
#define GTYPE2CLASS(gtype) (rbgobj_gtype_to_ruby_class(gtype))
#define CLASS2GTYPE(klass) (rbgobj_lookup_class(klass)->gtype)
@@ -150,8 +151,11 @@
/* rbgobj_type.c */
-extern const RGObjClassInfo* rbgobj_lookup_class(VALUE klass);
-extern const RGObjClassInfo* rbgobj_lookup_class_by_gtype(GType gtype, VALUE parent);
+extern const RGObjClassInfo *rbgobj_lookup_class(VALUE klass);
+extern const RGObjClassInfo *rbgobj_lookup_class_by_gtype(GType gtype, VALUE parent);
+extern const RGObjClassInfo *rbgobj_lookup_class_by_gtype_full(GType gtype,
+ VALUE parent,
+ gboolean create_object);
extern VALUE rbgobj_gtype_to_ruby_class(GType gtype);
extern VALUE rbgobj_define_class(GType gtype, const gchar* name, VALUE module,
void* mark, void* free, VALUE parent);
--- a/glib/src/rbgobj_typeinstance.c
+++ b/glib/src/rbgobj_typeinstance.c
@@ -16,6 +16,10 @@
VALUE cInstantiatable;
+typedef void (*ClassInfoCallbackFunc) (gpointer instance,
+ const RGObjClassInfo *class_info,
+ gpointer user_data);
+
static VALUE
instantiatable_s_allocate(klass)
VALUE klass;
@@ -40,9 +44,7 @@
/**********************************************************************/
static void
-each_cinfo(gpointer instance,
- void (*func)(gpointer instance, const RGObjClassInfo* cinfo, gpointer user_data),
- gpointer user_data)
+each_cinfo(gpointer instance, ClassInfoCallbackFunc func, gpointer user_data)
{
const GType gtype = G_TYPE_FROM_INSTANCE(instance);
GType* interfaces;
@@ -51,25 +53,35 @@
interfaces = g_type_interfaces(gtype, &n_interfaces);
{
guint i;
- for (i = 0; i < n_interfaces; i++)
- func(instance, GTYPE2CINFO(interfaces[i]), user_data);
+ for (i = 0; i < n_interfaces; i++) {
+ const RGObjClassInfo *info;
+
+ info = GTYPE2CINFO_NO_CREATE(interfaces[i]);
+ if (info)
+ func(instance, info, user_data);
+ }
}
{
- GType i;
- for (i = gtype; i != G_TYPE_INVALID; i = g_type_parent(i))
- func(instance, GTYPE2CINFO(i), user_data);
+ GType type;
+ for (type = gtype; type != G_TYPE_INVALID; type = g_type_parent(type)) {
+ const RGObjClassInfo *info;
+
+ info = GTYPE2CINFO_NO_CREATE(type);
+ if (info)
+ func(instance, info, user_data);
+ }
}
}
static void
-call_cinfo_free(gpointer instance, const RGObjClassInfo* cinfo, gpointer user_data)
+call_cinfo_free(gpointer instance, const RGObjClassInfo *cinfo, gpointer user_data)
{
if (cinfo->free) cinfo->free(instance);
}
static void
-call_cinfo_mark(gpointer instance, const RGObjClassInfo* cinfo, gpointer user_data)
+call_cinfo_mark(gpointer instance, const RGObjClassInfo *cinfo, gpointer user_data)
{
if (cinfo->mark) cinfo->mark(instance);
}
--- a/glib/ChangeLog
+++ b/glib/ChangeLog
@@ -1,3 +1,9 @@
+2008-07-27 Sjoerd Simons <[EMAIL PROTECTED]>
+
+ * src/rbgobj_closure.c: Only use G_REMOVE_RELATIVE when a closure is
+ directly invalidated. This prevents object creation when freeing the
+ closure from the garbage collector.
+
2008-06-19 Kouhei Sutou <[EMAIL PROTECTED]>
* src/rbgobj_type.c (rbgobj_lookup_class_by_gtype_body): add
--- a/glib/src/rbgobj_closure.c
+++ b/glib/src/rbgobj_closure.c
@@ -142,9 +142,6 @@
GList *next;
for (next = rclosure->objects; next; next = next->next) {
GObject *object = G_OBJECT(next->data);
- VALUE obj = rbgobj_ruby_object_from_instance2(object, FALSE);
- if (!NIL_P(rclosure->rb_holder) && !NIL_P(obj))
- G_REMOVE_RELATIVE(obj, id_closures, rclosure->rb_holder);
g_object_weak_unref(object, rclosure_weak_notify, rclosure);
}
g_list_free(rclosure->objects);
@@ -163,7 +160,16 @@
GRClosure *rclosure = (GRClosure*)closure;
if (rclosure->count > 0) {
+ GList *next;
+
rclosure->count = 1;
+ for (next = rclosure->objects; next; next = next->next) {
+ GObject *object = G_OBJECT(next->data);
+ VALUE obj = rbgobj_ruby_object_from_instance2(object, FALSE);
+ if (!NIL_P(rclosure->rb_holder) && !NIL_P(obj))
+ G_REMOVE_RELATIVE(obj, id_closures, rclosure->rb_holder);
+ }
+
rclosure_unref(rclosure);
}
}
@@ -178,7 +184,13 @@
static void
gr_closure_holder_free(GRClosure *rclosure)
{
- rclosure_invalidate(NULL, (GClosure*)rclosure);
+ if (rclosure->count > 0) {
+ rclosure->count = 1;
+
+ /* No need to remove us from the relatives hash of our objects, as
+ * those aren't alive anymore anyway */
+ rclosure_unref(rclosure);
+ }
}
GClosure*
#!/usr/bin/ruby
# This program displays a pixel-based animation in a window
# FIXME: Update the picture 20 times per second
require 'gtk2'
class BasicWindow < Gtk::Window
def initialize(title = nil)
super(Gtk::Window::TOPLEVEL)
if title
set_title("#{title} in Ruby/GTK")
end
signal_connect("key_press_event") do |widget, event|
if event.state.control_mask? and event.keyval == Gdk::Keyval::GDK_q
destroy
true
else
false
end
end
signal_connect("delete_event") do |widget, event|
quit
end
end
def quit
destroy
true
end
end
class Image < BasicWindow
# Create a string of 100x100x4 characters
def pixels
result = ""
@offset = 0 unless defined? @offset
100.times do |y|
100.times do |x|
# Red component
result << (((x + @offset) * 255) / (100 + @offset))
# Green component
result << (((y + @offset) * 255) / (100 + @offset))
# Blue component
result << 128
# Padding
result << 0
end
end
@offset += 1
return result
end
def initialize
super('Image')
signal_connect('destroy') do
Gtk.main_quit
end
self.border_width = 8
vbox = Gtk::VBox.new(false, 8)
vbox.border_width = 8
add(vbox)
label = Gtk::Label.new
label.set_markup('<u>Rendered image</u>')
vbox.pack_start(label, false, false, 0)
frame = Gtk::Frame.new
frame.shadow_type = Gtk::SHADOW_IN
# The alignment keeps the frame from growing when users resize
# the window
align = Gtk::Alignment.new(0.5, 0.5, 0, 0)
align.add(frame)
vbox.pack_start(align, false, false, 0)
# Realize the window to be able to properly do graphics operations
realize
image = Gtk::DrawingArea.new
image.set_size_request(100, 100)
frame.add(image)
image.realize
Gtk.timeout_add(50) do
gc = image.style.fg_gc(image.state)
Gdk::RGB.draw_rgb_32_image(image.window, gc, 0, 0, 100, 100, Gdk::RGB::DITHER_NONE, pixels, 100*4)
true
end
end
end
# Do the Disco Duck
image = Image.new
image.show_all
Gtk.main