on Anne's karmic koala, gtk_events_pending() is much more often true than on my machi...
authorGuillaume Cottenceau <gcottenc@gmail.com>
Sun, 29 Nov 2009 21:24:58 +0000 (22:24 +0100)
committerGuillaume Cottenceau <gcottenc@gmail.com>
Sun, 29 Nov 2009 21:24:58 +0000 (22:24 +0100)
bin/booh-classifier
ext/rbbooh.cc

index 9a7584888034155e95392fdcf11f699ecc5a10e1..a3c6beba40f36cd0341cc3c90f980d765ef68203 100644 (file)
@@ -271,7 +271,7 @@ class Entry
         return $config['thumbnails-height'].to_i
     end
 
-    attr_accessor :path, :guipath, :type, :angle, :button, :image, :alignment, :removed, :labeled
+    attr_accessor :path, :guipath, :type, :angle, :button, :image, :alignment, :removed, :labeled, :loader
 
     def initialize(path, type, guipath)
         @path = path
@@ -411,11 +411,6 @@ class Entry
     end
 
     private
-    def cleanup_dir(dir)
-        Dir.entries(dir).each { |file| file != '.' && file != '..' and File.delete(File.join(dir, file)) }
-        Dir.delete(dir)
-    end
-
     def load_into_pixbuf_full
         if @pixbuf_full.nil?
             msg 3, ">>> load_into_pixbuf_full #{path}"
@@ -440,18 +435,16 @@ class Entry
     end
 
     def load_into_pixbuf_at_size(&specify_size)
-        pixbuf = nil
         if @type == 'video'
-            tmp = Tempfile.new("boohclassifiertemp")
-            dest_dir = tmp.path
-            tmp.close!
-            Dir.mkdir(dest_dir)
-            orig_base = File.basename(path)
-            tmpdir = gen_video_thumbnail(path, false, 0)
-            if tmpdir.nil?
-                return
+            if @video_image_path.nil?
+                orig_base = File.basename(path)
+                tmpdir = gen_video_thumbnail(path, false, 0)
+                if tmpdir.nil?
+                    return
+                end
+                @video_image_path = "#{tmpdir}/00000001.jpg"
             end
-            image_path = "#{tmpdir}/00000001.jpg"
+            image_path = @video_image_path
         else
             image_path = @path
         end
@@ -463,41 +456,45 @@ class Entry
             end
         end
         begin
-            #- use a pixbuf loader and trigger Gtk.main_iteration on each chunk if needed, to keep the UI responsive even
+            #- use a pixbuf loader and check Gtk.events_pending? on each chunk, to keep the UI responsive even
             #- if loaded pictures are several MBs large
-            loader = Gdk::PixbufLoader.new
-            loader.signal_connect('size-prepared') { |l, w, h|
-                r = specify_size.call(w, h)
-                #msg 3, "specified sizes: #{r[0]} #{r[1]}"
-                loader.set_size(*specify_size.call(w, h))
-            }
-            id = loader.signal_connect('area-prepared') { pixbuf = loader.pixbuf }
-            if ! loader.load_not_freezing_ui(image_path, id)
+            if @loader.nil?
+                @loader = Gdk::PixbufLoader.new
+                @loader.signal_connect('size-prepared') { |l, w, h|
+                    @loader.set_size(*specify_size.call(w, h))
+                }
+                @loader.signal_connect('area-prepared') { @loaded_pixbuf = @loader.pixbuf }
+                @loader_offset = 0
+            end
+            msg 3, "calling load_not_freezing_ui on #{image_path}, offset #{@loader_offset}"
+            @loader_offset = @loader.load_not_freezing_ui(image_path, @loader_offset)
+            if @loader_offset > 0
                 #- interrupted
                 raise InterruptedLoading
             end
-            if pixbuf.nil?
+            @loader = nil
+            if @loaded_pixbuf.nil?
                 raise "Loaded pixbuf nil - #{path} #{image_path}"
             end
         rescue
             msg 0, "Cannot load #{image_path}: #{$!}"
             return
         ensure
-            if @type == 'video'
-                File.delete(image_path)
-                Dir.rmdir(tmpdir)
+            if @video_image_path && @loader.nil?
+                File.delete(@video_image_path)
+                Dir.rmdir(File.dirname(@video_image_path))
+                @video_image_path = nil
             end
         end
-        if pixbuf
+        if @loaded_pixbuf
             if @angle != 0
                 msg 3, ">>> load_into_pixbuf_full #{image_path} => rotate #{@angle}"
-                pixbuf = rotate_pixbuf(pixbuf, @angle)
+                @loaded_pixbuf = rotate_pixbuf(@loaded_pixbuf, @angle)
             end
         end
-        if @type == 'video'
-            cleanup_dir(dest_dir)
-        end
-        return pixbuf
+        retval = @loaded_pixbuf
+        @loaded_pixbuf = nil
+        return retval
     end
 
     def to_s
@@ -1898,7 +1895,20 @@ def reset_labels
     evt.modify_bg(Gtk::StateType::ACTIVE, $color_red.lighter)
 end
 
+def cleanup_loaders
+    $allentries.each { |e| 
+        if ! e.loader.nil?
+            begin
+                e.loader.close
+            rescue
+                #- ignore loader errors, at that point they are fairly normal
+            end
+        end
+    }
+end
+
 def reset_thumbnails
+    cleanup_loaders
     $allentries = []
     if $preloader_running
         $preloader_force_exit = true
@@ -1986,4 +1996,6 @@ if ARGV[0]
 end
 Gtk.main
 
+cleanup_loaders
+
 write_config
index 9becd2f75dcfe15f0f494a3946e554e9c20a6306..29c097d96b1f75466be0ded6ef2059c234e54219 100644 (file)
@@ -176,9 +176,10 @@ static VALUE modify_bg(VALUE self, VALUE state, VALUE color) {
 }
 
 // internalize pixbuf loading for 30% more speedup
-static VALUE load_not_freezing_ui(VALUE self, VALUE path, VALUE area_prepared_signal_id) {
+static VALUE load_not_freezing_ui(VALUE self, VALUE path, VALUE offset) {
         char buf[65536];
         size_t amount;
+        size_t off = NUM2INT(offset);
         GdkPixbufLoader* loader = GDK_PIXBUF_LOADER(RVAL2GOBJ(self));
         GError* error = NULL;
         FILE* f = fopen(RVAL2CSTR(path), "r");
@@ -186,26 +187,30 @@ static VALUE load_not_freezing_ui(VALUE self, VALUE path, VALUE area_prepared_si
                 gdk_pixbuf_loader_close(loader, NULL);
                 rb_raise(rb_eRuntimeError, "Unable to open file %s for reading", RVAL2CSTR(path));
         }
+        if (off > 0) {
+                if (fseek(f, off, SEEK_SET) != 0) {
+                        rb_raise(rb_eRuntimeError, "Unable to seek file %s", RVAL2CSTR(path));
+                        fclose(f);
+                        return 0;
+                }
+        }
         while ((amount = fread(buf, 1, 65536, f)) > 0) {
                 if (!gdk_pixbuf_loader_write(loader, (const guchar*) buf, amount, &error)) {
                         gdk_pixbuf_loader_close(loader, NULL);
                         fclose(f);
                         RAISE_GERROR(error);
                 }
-                if (gtk_events_pending()) {
+                off += amount;
+                if (gtk_events_pending() && !feof(f)) {
                         // interrupted, case when the user clicked/keyboarded too quickly for this image to
-                        // display; we cancel this loading, but before we disconnect the area-prepared
-                        // signal handler, else the call to gdk_pixbuf_loader_get_pixbuf will take ages
-                        // (between 100 and 400 ms on my p4 for a large photo!)
-                        g_signal_handler_disconnect(loader, NUM2INT(area_prepared_signal_id));
-                        gdk_pixbuf_loader_close(loader, NULL);
+                        // display; we temporarily interrupt this loading
                         fclose(f);
-                        return Qfalse;
+                        return INT2NUM(off);
                 }
         }
         gdk_pixbuf_loader_close(loader, NULL);
         fclose(f);
-        return Qtrue;
+        return INT2NUM(0);
 }
 
 extern "C" {