interrupt loading of current image in case user is moving fast, in order to display...
authorgc <gc>
Tue, 1 Apr 2008 08:29:16 +0000 (08:29 +0000)
committergc <gc>
Tue, 1 Apr 2008 08:29:16 +0000 (08:29 +0000)
bin/booh-classifier
ext/rbbooh.cc

index 65f0c62..456becf 100644 (file)
@@ -267,7 +267,7 @@ class Entry
             return true
         end
     end
-    def pixbuf_main
+    def pixbuf_main(interruptable)
         width, height = $mainview.window.size 
         width = MainView.get_usable_width(width)
         height = MainView.get_usable_height(height)
@@ -275,7 +275,7 @@ class Entry
             msg 3, ">>> pixbuf_main #{path}"
             @width = width
             @height = height
-            load_into_pixbuf_full  #- make sure it is loaded
+            load_into_pixbuf_full(interruptable)  #- make sure it is loaded
             if @pixbuf_full.nil?
                 return
             end
@@ -313,7 +313,7 @@ class Entry
                 @pixbuf_thumbnail = @pixbuf_main.scale(@pixbuf_main.width * (@@thumbnails_height.to_f/@pixbuf_main.height), @@thumbnails_height, Gdk::Pixbuf::INTERP_BILINEAR)
             else
                 msg 3, ">>> pixbuf_thumbnail from file #{path}"
-                @pixbuf_thumbnail = load_into_pixbuf_at_size { |w, h|
+                @pixbuf_thumbnail = load_into_pixbuf_at_size(false) { |w, h|
                     if @angle == 0
                         if h > @@thumbnails_height
                             [ w * @@thumbnails_height.to_f/h, @@thumbnails_height ]
@@ -383,10 +383,10 @@ class Entry
         Dir.delete(dir)
     end
 
-    def load_into_pixbuf_full
+    def load_into_pixbuf_full(interruptable)
         if @pixbuf_full.nil?
             msg 3, ">>> load_into_pixbuf_full #{path}"
-            @pixbuf_full = load_into_pixbuf_at_size { |w, h|
+            @pixbuf_full = load_into_pixbuf_at_size(interruptable) { |w, h|
                 if @angle == 0
                     if w > @@max_width
                         #- save memory and speedup (+35%) loading 
@@ -405,7 +405,7 @@ class Entry
         end
     end
 
-    def load_into_pixbuf_at_size(&specify_size)
+    def load_into_pixbuf_at_size(interruptable, &specify_size)
         pixbuf = nil
         if @type == 'video'
             tmp = Tempfile.new("boohclassifiertemp")
@@ -436,8 +436,10 @@ class Entry
                 #msg 3, "specified sizes: #{r[0]} #{r[1]}"
                 loader.set_size(*specify_size.call(w, h))
             }
-            loader.signal_connect('area-prepared') { pixbuf = loader.pixbuf }
-            loader.load_not_freezing_ui(image_path)
+            id = loader.signal_connect('area-prepared') { pixbuf = loader.pixbuf }
+            if ! loader.load_not_freezing_ui(image_path, interruptable, id)
+                return
+            end
             loader.close
             if pixbuf.nil?
                 raise "Loaded pixbuf nil - #{path} #{image_path}"
@@ -515,9 +517,10 @@ def run_preloader_real
         end
         index = $allentries.index($mainview.get_shown_entry)
         for j in 1 .. $config['preload-distance'].to_i
+
             i = index + j
             if i < $allentries.size
-                $allentries[i].pixbuf_main
+                $allentries[i].pixbuf_main(false)
             end
             #- in case just loaded another directory
             if $preloader_force_exit
@@ -525,9 +528,17 @@ def run_preloader_real
                 $preloader_force_exit = false
                 return
             end
+            #- in case moved fast
+            if index != $allentries.index($mainview.get_shown_entry)
+                msg 3, "*** >>>> moved already, rerun"
+                $preloader_running = false
+                run_preloader_real
+                return
+            end
+
             i = index - j
             if i >= 0
-                $allentries[i].pixbuf_main
+                $allentries[i].pixbuf_main(false)
             end
             #- in case just loaded another directory
             if $preloader_force_exit
@@ -535,15 +546,18 @@ def run_preloader_real
                 $preloader_force_exit = false
                 return
             end
+            #- in case moved fast
+            if index != $allentries.index($mainview.get_shown_entry)
+                msg 3, "*** >>>> moved already, rerun"
+                $preloader_running = false
+                run_preloader_real
+                return
+            end
         end
         free_cache
     end
     $preloader_running = false
     msg 3, "*** << main preloading finished"
-    #- if we're already on a different image, rerun the preloader
-    if index != $allentries.index($mainview.get_shown_entry)
-        run_preloader_real
-    end
 end
 
 def run_preloader
@@ -578,7 +592,6 @@ class MainView < Gtk::DrawingArea
         super()
         signal_connect('expose-event') { draw }
         signal_connect('configure-event') { update_shown }
-        @preloader_running = false
     end
 
     def set_shown_entry(entry)
@@ -612,21 +625,29 @@ class MainView < Gtk::DrawingArea
     end
 
     def redraw
-        update_shown
+        if ! update_shown
+            return
+        end
         w, h = window.size
         window.begin_paint(Gdk::Rectangle.new(0, 0, w, h))
         window.clear
         draw
         window.end_paint
+        @entry and sb_msg(_("Selected %s") % @entry.get_beautified_name)
         Gtk.main_iteration while Gtk.events_pending?
     end
 
     def update_shown
         if @entry
-            @pixbuf = @entry.pixbuf_main
-            width, height = window.size 
-            @xpos = (width - @pixbuf.width)/2
-            @ypos = (height - @pixbuf.height)/2
+            $interrupt_loading = false
+            pixbuf = @entry.pixbuf_main(true)
+            $interrupt_loading = true
+            if pixbuf
+                @pixbuf = pixbuf
+                width, height = window.size 
+                @xpos = (width - @pixbuf.width)/2
+                @ypos = (height - @pixbuf.height)/2
+            end
         else
             @pixbuf = nil
         end
@@ -970,7 +991,6 @@ def show_entry(entry, i, tips)
             entry.alignment.set(0.5, 0, 0, 0)
             last_shown and last_shown.alignment.set(0.5, 1, 0, 0)
             $mainview.set_shown_entry(entry)
-            sb_msg(_("Selected %s") % entry.get_beautified_name)
         end
     }
     entry.button.signal_connect('button-press-event') { |w, event|
@@ -978,7 +998,7 @@ def show_entry(entry, i, tips)
             video_view(entry)
         end
     }
-    entry.button.signal_connect('focus-in-event') { entry.button.clicked; autoscroll_if_needed(entry.button) }
+    entry.button.signal_connect('focus-in-event') { autoscroll_if_needed(entry.button); entry.button.clicked }
     entry.button.signal_connect('key-press-event') { |w, e| thumbnail_keypressed(entry, e) }
     if i == 0
         entry.button.grab_focus
@@ -1001,7 +1021,7 @@ def show_entries(allentries)
 #        printf "%d %s\n", i, __LINE__
         entry = allentries[i]
         if i == 0
-            loaded_pixbuf = entry.pixbuf_main
+            loaded_pixbuf = entry.pixbuf_main(false)
         else
             loaded_pixbuf = entry.pixbuf_thumbnail
         end
@@ -1024,7 +1044,7 @@ def show_entries(allentries)
             i += 1
             if i > $config['preload-distance'].to_i && i <= $config['preload-distance'].to_i * 2
                 #- when we're at preload distance, beging preloading to preload distance
-                allentries[i - $config['preload-distance'].to_i].pixbuf_main
+                allentries[i - $config['preload-distance'].to_i].pixbuf_main(false)
             end
             if i == $config['preload-distance'].to_i * 2 + 1
                 #- when we're after double preload distance, activate normal preloading
index c3e1fa5..02cba67 100644 (file)
@@ -175,7 +175,8 @@ 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) {
+static VALUE load_not_freezing_ui(VALUE self, VALUE path, VALUE interruptable, VALUE area_prepared_signal_id) {
+        int interruptable_ = RTEST(interruptable);
         char buf[65536];
         size_t amount;
         GdkPixbufLoader* loader = GDK_PIXBUF_LOADER(RVAL2GOBJ(self));
@@ -189,9 +190,19 @@ static VALUE load_not_freezing_ui(VALUE self, VALUE path) {
                 while (gtk_events_pending()) {
                         gtk_main_iteration();
                 }
+                if (interruptable_ && RTEST(rb_eval_string("$interrupt_loading"))) {
+                        // 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);
+                        fclose(f);
+                        return Qfalse;
+                }
         }
         fclose(f);
-        return self;
+        return Qtrue;
 }
 
 extern "C" {
@@ -210,7 +221,7 @@ Init_libadds()
     rb_define_method(cinfo->klass, "modify_bg", (VALUE (*)(...)) modify_bg, 2);
 
     cinfo = (RGObjClassInfo*)rbgobj_lookup_class_by_gtype(GDK_TYPE_PIXBUF_LOADER, Qnil);
-    rb_define_method(cinfo->klass, "load_not_freezing_ui", (VALUE (*)(...)) load_not_freezing_ui, 1);
+    rb_define_method(cinfo->klass, "load_not_freezing_ui", (VALUE (*)(...)) load_not_freezing_ui, 3);
 
     VALUE exif = rb_define_module("Exif");
     rb_define_module_function(exif, "orientation", (VALUE (*)(...)) exif_orientation, 1);