diff --git a/gdk_pixbuf2/ext/gdk_pixbuf2/extconf.rb b/gdk_pixbuf2/ext/gdk_pixbuf2/extconf.rb index 68401ab..2f2f937 100644 --- a/gdk_pixbuf2/ext/gdk_pixbuf2/extconf.rb +++ b/gdk_pixbuf2/ext/gdk_pixbuf2/extconf.rb @@ -39,6 +39,9 @@ end :target_build_dir => build_dir) end +ruby_header = "ruby.h" +have_func("rb_thread_blocking_region", ruby_header) + setup_win32(module_name, base_dir) PKGConfig.have_package(package_id) or exit 1 diff --git a/gdk_pixbuf2/ext/gdk_pixbuf2/rbgdk-pixbuf.c b/gdk_pixbuf2/ext/gdk_pixbuf2/rbgdk-pixbuf.c index 43de540..84a0211 100644 --- a/gdk_pixbuf2/ext/gdk_pixbuf2/rbgdk-pixbuf.c +++ b/gdk_pixbuf2/ext/gdk_pixbuf2/rbgdk-pixbuf.c @@ -85,6 +85,75 @@ get_option(VALUE self, VALUE key) return ret ? CSTR2RVAL(ret) : Qnil; } + +typedef struct { + enum { + load_from_file, + load_from_file_at_size, + load_from_file_at_scale + } call_type; + union { + struct { + char *filename; + } load_from_file; + struct { + char *filename; + gint width; + gint height; + } load_from_file_at_size; + struct { + char *filename; + gint width; + gint height; + gboolean preserve_aspect_ratio; + } load_from_file_at_scale; + } data; + GError *error; + GdkPixbuf *result; +} _init_args; + +static VALUE __load_pixbuf(_init_args *args) +{ + GdkPixbuf *buf = NULL; + + switch (args->call_type) { + case load_from_file: + buf = gdk_pixbuf_new_from_file(args->data.load_from_file_at_scale.filename, + &(args->error)); + break; + case load_from_file_at_size: + buf = gdk_pixbuf_new_from_file_at_size(args->data.load_from_file_at_scale.filename, + args->data.load_from_file_at_scale.width, + args->data.load_from_file_at_scale.height, + &(args->error)); + break; + case load_from_file_at_scale: + buf = gdk_pixbuf_new_from_file_at_scale(args->data.load_from_file_at_scale.filename, + args->data.load_from_file_at_scale.width, + args->data.load_from_file_at_scale.height, + args->data.load_from_file_at_scale.preserve_aspect_ratio, + &(args->error)); + break; + } + + args->result = buf; + return (args->error || !buf) ? Qfalse : Qtrue; +} + +static void __load_pixbuf_with_auto_gc(_init_args *args) { +#ifdef HAVE_RB_THREAD_BLOCKING_REGION + if (Qfalse == rb_thread_blocking_region((rb_blocking_function_t *)(__load_pixbuf), args, RUBY_UBF_IO, 0)) { + rb_gc(); + rb_thread_blocking_region((rb_blocking_function_t *)(__load_pixbuf), args, RUBY_UBF_IO, 0); + } +#else + if (Qfalse == __load_pixbuf(args)) { + rb_gc(); + __load_pixbuf(args); + } +#endif +} + /****************************************************/ /* File opening */ /* Image Data in Memory */ @@ -141,6 +210,8 @@ initialize(int argc, VALUE *argv, VALUE self) rb_raise(rb_eArgError, "Wrong type of 1st argument or wrong number of arguments"); } } else if (argc == 4) { + _init_args *args = g_new0(_init_args, 1); + #if RBGDK_PIXBUF_CHECK_VERSION(2,6,0) int width = NUM2INT(arg2); int height = NUM2INT(arg3); @@ -148,44 +219,42 @@ initialize(int argc, VALUE *argv, VALUE self) if (width < 0 || height < 0) rb_warning("For scaling on load, a negative value for width or height are not supported in GTK+ < 2.8.0"); #endif - buf = gdk_pixbuf_new_from_file_at_scale(RVAL2CSTR(arg1), - width, height, - RVAL2CBOOL(arg4), &error); - if (buf == NULL){ - rb_gc(); - error = NULL; - buf = gdk_pixbuf_new_from_file_at_scale(RVAL2CSTR(arg1), - NUM2INT(arg2), NUM2INT(arg3), - RVAL2CBOOL(arg4), &error); - } + args->call_type = load_from_file_at_scale; + args->data.load_from_file_at_scale.filename = RVAL2CSTR(arg1); + args->data.load_from_file_at_scale.width = width; + args->data.load_from_file_at_scale.height = height; + args->data.load_from_file_at_scale.preserve_aspect_ratio = RVAL2CBOOL(arg4); #else rb_warning("Scaling on load not supported in GTK+ < 2.6.0"); - buf = gdk_pixbuf_new_from_file(RVAL2CSTR(arg1), &error); - if (buf == NULL){ - error = NULL; - rb_gc(); - buf = gdk_pixbuf_new_from_file(RVAL2CSTR(arg1), &error); - } + + args->call_type = load_from_file; + args->data.load_from_file.filename = RVAL2CSTR(arg1); #endif + + __load_pixbuf_with_auto_gc(args); + buf = args->result; + error = args->error; + g_free(args); + } else if (argc == 3) { + _init_args *args = g_new0(_init_args, 1); #if RBGDK_PIXBUF_CHECK_VERSION(2,4,0) - buf = gdk_pixbuf_new_from_file_at_size(RVAL2CSTR(arg1), - NUM2INT(arg2), NUM2INT(arg3), &error); - if (buf == NULL){ - rb_gc(); - error = NULL; - buf = gdk_pixbuf_new_from_file_at_size(RVAL2CSTR(arg1), - NUM2INT(arg2), NUM2INT(arg3), &error); - } -#else + args->call_type = load_from_file_at_size; + args->data.load_from_file_at_size.filename = RVAL2CSTR(arg1); + args->data.load_from_file_at_size.width = NUM2INT(arg2); + args->data.load_from_file_at_size.height = NUM2INT(arg3); + #else rb_warning("Sizing on load not supported in GTK+ < 2.4.0"); - buf = gdk_pixbuf_new_from_file(RVAL2CSTR(arg1), &error); - if (buf == NULL){ - error = NULL; - rb_gc(); - buf = gdk_pixbuf_new_from_file(RVAL2CSTR(arg1), &error); - } + + args->call_type = load_from_file; + args->data.load_from_file.filename = RVAL2CSTR(arg1); #endif + + __load_pixbuf_with_auto_gc(args); + buf = args->result; + error = args->error; + g_free(args); + } else if (argc == 2){ int i; int len = RARRAY_LEN(arg1); @@ -203,12 +272,15 @@ initialize(int argc, VALUE *argv, VALUE self) rb_ivar_set(self, id_pixdata, Data_Wrap_Struct(rb_cData, NULL, g_free, gstream)); } else if (argc == 1){ if (TYPE(arg1) == T_STRING) { - buf = gdk_pixbuf_new_from_file(RVAL2CSTR(arg1), &error); - if (buf == NULL){ - rb_gc(); - error = NULL; - buf = gdk_pixbuf_new_from_file(RVAL2CSTR(arg1), &error); - } + _init_args *args = g_new0(_init_args, 1); + args->call_type = load_from_file; + args->data.load_from_file.filename = RVAL2CSTR(arg1); + + __load_pixbuf_with_auto_gc(args); + buf = args->result; + error = args->error; + g_free(args); + } else if (TYPE(arg1) == T_ARRAY) { const gchar **data = RVAL2STRV(arg1); buf = gdk_pixbuf_new_from_xpm_data(data);