Update nbdview.
authorRichard W.M. Jones <rjones@redhat.com>
Sat, 3 Nov 2018 17:50:53 +0000 (17:50 +0000)
committerRichard W.M. Jones <rjones@redhat.com>
Sat, 3 Nov 2018 18:10:16 +0000 (18:10 +0000)
2019-fosdem/nbdview/README
2019-fosdem/nbdview/nbdcanvas.tcl
2019-fosdem/nbdview/nbdview.tcl

index 0f42bd1..ad14699 100644 (file)
@@ -6,7 +6,16 @@ filter.  For example, using the memory plugin (but any plugin may be
 used):
 
   size=$((64 * 1024 * 1024))
-  nbdkit --filter=log memory size=$size logfile=/tmp/log
+  delay=20ms
+  nbdkit --filter=log --filter=delay \
+         memory \
+         size=$size \
+         logfile=/tmp/log \
+         rdelay=$delay wdelay=$delay &
+
+In this example I have also added a delay which helps to make the
+stuff happening on screen easier to see and more "animated", but it is
+not required.
 
 Then start nbdview.tcl specifying the log file and virtual size:
 
index f5e8b75..012c642 100644 (file)
@@ -44,9 +44,13 @@ package require Tk
 #
 # Returns an opaque handle which should be passed to nbdpoll.
 proc nbdcanvas { canvas logfile size blocksize width scale } {
-    canvas $canvas -bg white
     set height [expr {$size / $blocksize / $width}]
 
+    # Width and height of the canvas.
+    set w_scaled [expr {$width*$scale}]
+    set h_scaled [expr {$height*$scale}]
+    canvas $canvas -bg white -width $w_scaled -height $h_scaled
+
     # Because Tk's canvas cannot scale images, we use a very
     # inefficient double buffering here where we have $img which
     # contains the raw data but is not displayed, and $dispimg which
@@ -54,9 +58,10 @@ proc nbdcanvas { canvas logfile size blocksize width scale } {
     # $img changes.
     set img [image create photo -width $width -height $height]
     $img put "white" -to 0 0 $width $height
-    set dispimg [image create photo -width [expr {$width*$scale}] \
-                     -height [expr {$height*$scale}]]
-    $canvas create image 0 0 -anchor nw -image $dispimg
+    set dispimg [image create photo -width $w_scaled -height $h_scaled]
+    # -borderwidth somehow counts towards the canvas area?!  So we have
+    # to offset the image by 4, 4 here to make it fully visible.
+    $canvas create image 4 4 -anchor nw -image $dispimg
 
     # Open the log file.
     set fp [open $logfile "r"]
@@ -79,12 +84,14 @@ proc nbdheight { h } {
     return [dict get $h height]
 }
 
-# Blit $img to $dispimg, with scaling.
-proc update_dispimg { h } {
-    set img [dict get $h img]
+# Blit $img to $dispimg, with scaling.  If the optional img parameter
+# is given, blit that image to $dispimg instead, else use the normal
+# img stored in the handle.
+proc update_dispimg { h { img - } } {
+    if { "$img" eq "-" } {
+        set img [dict get $h img]
+    }
     set dispimg [dict get $h dispimg]
-    set width [dict get $h width]
-    set height [dict get $h height]
     set scale [dict get $h scale]
     $dispimg copy $img -zoom $scale $scale
 }
@@ -94,38 +101,40 @@ proc update_dispimg { h } {
 proc handle_read { h offset count } {
     set blocksize [dict get $h blocksize]
     set width [dict get $h width]
+    set height [dict get $h height]
     set img [dict get $h img]
 
+    # We only write into a temporary image here.
+    set tmpimg [image create photo -width $width -height $height]
+    $tmpimg copy $img
+
     while { $count > 0 } {
         set lba [expr {$offset/$blocksize}]
         set x [expr {$lba % $width}]
         set y [expr {$lba / $width}]
 
-        set oldcol [$img get $x $y]
-        set oldcol [format "#%02x%02x%02x" \
-                        [lindex $oldcol 0] \
-                        [lindex $oldcol 1] \
-                        [lindex $oldcol 2]]
-        # Flash the pixel to black.
-        $img put "black" -to $x $y [expr {$x+1}] [expr {$y+1}]
-        update_dispimg $h
-        update
-        # Restore old colour.
-        $img put $oldcol -to $x $y [expr {$x+1}] [expr {$y+1}]
-        update_dispimg $h
+        # Set the read pixel to black.
+        $tmpimg put "black" -to $x $y [expr {$x+1}] [expr {$y+1}]
 
         incr offset $blocksize
         incr count [expr {-$blocksize}]
     }
+
+    # Update the display buffer with the temporary image.
+    update_dispimg $h $tmpimg
+    update
+
+    # Discard the temporary copy.
+    image delete $tmpimg
+
+    # We don't actually update the display image again.  It will be
+    # restored next time something happens.
 }
 
 # Operation colours.
 array set colours {
-    # write => red
     w "#ff0000"
-    # trim => grey
-    t "#e0e0e0"
-    # zero => white
+    t "#e0e0f0"
     z "#ffffff"
 }
 
@@ -172,9 +181,16 @@ proc handle { h line } {
     # else just ignore any lines we don't understand
 }
 
+# If nothing happens in nbdpoll for a few iterations then we update
+# the displayed image.  This is so that black read bars don't appear
+# permanently if nothing else is happening.
+set pollcount 50
+
 # Poll the logfile and update the canvas.
-# This has to be called every so often.
+# This has to be called every so often from the main program.
 proc nbdpoll { h } {
+    global pollcount
+
     set fp [dict get $h fp]
 
     # Read as much as we can from the log file.
@@ -184,5 +200,12 @@ proc nbdpoll { h } {
         foreach line $lines {
             handle $h $line
         }
+    } else {
+        # Nothing happening, did pollcount go to zero yet?
+        incr pollcount -1
+        if { $pollcount == 0 } {
+            update_dispimg $h
+            set pollcount 50
+        }
     }
 }
index fa6343e..9e41014 100755 (executable)
@@ -37,7 +37,7 @@ source "nbdcanvas.tcl"
 
 set blocksize 4096
 set width 128
-set scale 2
+set scale 4
 
 # This is used to store the canvas handle.
 set h ""
@@ -59,9 +59,6 @@ if { $argc != 2 } {
 set logfile [lindex $argv 0]
 set size [lindex $argv 1]
 
-# Set up the window.
-wm title . "nbdview $logfile"
-
 # Menubar.
 option add *tearOff 0
 menu .menubar
@@ -70,14 +67,17 @@ menu .menubar.file
 .menubar add cascade -menu .menubar.file -label File
 .menubar.file add command -label "Quit" -command { exit }
 
+# Frame.
+frame .f
+pack .f -anchor center -expand 1 -fill both -ipadx 10 -ipady 10
+
 # Canvas.
-set h [nbdcanvas .c $logfile $size $blocksize $width $scale]
-pack .c -in . -expand 1 -fill both
+set h [nbdcanvas .f.c $logfile $size $blocksize $width $scale]
+.f.c configure -borderwidth 4 -relief groove
+pack .f.c -anchor center -expand 0 -fill none
 
-# Set the width and height of the window.
-set h_ [expr {[nbdheight $h] * $scale + 40}]
-set w [expr {$width * $scale + 16}]
-wm geometry . "${w}x${h_}"
+# Set up the window.
+wm title . "nbdview $logfile"
 wm resizable . false false
 
 # Start polling the log file.