]> git.cworth.org Git - sup/commitdiff
rewrap getch in select, handle sigwinch manually
authorWilliam Morgan <wmorgan-sup@masanjin.net>
Thu, 6 Aug 2009 16:21:46 +0000 (12:21 -0400)
committerWilliam Morgan <wmorgan-sup@masanjin.net>
Thu, 6 Aug 2009 16:21:46 +0000 (12:21 -0400)
This is necessary to operate with many versions of the ruby ncurses library,
all of which block threads when getch is being called. But this means we can't
use getch to determine a sigwich, since we won't see it until an actual key is
pressed. so we handle sigwinch ourselves.

bin/sup
lib/sup/buffer.rb

diff --git a/bin/sup b/bin/sup
index d52a0ad1f441ad696323d205015984753112810b..2d5de6733fcdf76f1a58caa3d64aadce0c02c143 100755 (executable)
--- a/bin/sup
+++ b/bin/sup
@@ -161,6 +161,7 @@ begin
   Index.load
 
   trap("TERM") { |x| raise "so speaking as i think, i die, i die!" }
+  trap("WINCH") { |x| BufferManager.sigwinch_happened! }
 
   if(s = Redwood::SourceManager.source_for DraftManager.source_name)
     DraftManager.source = s
@@ -228,7 +229,20 @@ begin
       nil
     end
 
-    next unless c
+    if c.nil?
+      if BufferManager.sigwinch_happened?
+        Redwood::log "redrawing screen on sigwinch"
+        BufferManager.completely_redraw_screen
+      end
+      next
+    end
+
+    if c == 410
+      ## this is ncurses's way of telling us it's detected a refresh.
+      ## since we have our own sigwinch handler, we don't do anything.
+      next
+    end
+
     bm.erase_flash
 
     action = begin
index 7939e2739f579d760ff153dc34276f35f280b45c..5881febcf7e68c12df715d61baea7d05393232a9 100644 (file)
@@ -26,12 +26,13 @@ module Ncurses
   def sync &b; mutex.synchronize(&b); end
 
   def nonblocking_getch
-    ## INSANITY
-    ## it is NECESSARY to call nodelay EVERY TIME otherwise a single ctrl-c
-    ## will turn a blocking call into a nonblocking one. hours of my life
-    ## wasted on this trivial bullshit: 3.
-    Ncurses.nodelay Ncurses.stdscr, false
-    Ncurses.getch
+    ## INSANTIY
+    ## it is NECESSARY to wrap Ncurses.getch in a select() otherwise all
+    ## background threads will be BLOCKED. (except in very modern versions
+    ## of libncurses-ruby. the current one on ubuntu seems to work well.)
+    if IO.select([$stdin], nil, nil, 0.5)
+      c = Ncurses.getch
+    end
   end
 
   module_function :rows, :cols, :curx, :nonblocking_getch, :mutex, :sync
@@ -195,10 +196,15 @@ EOS
     @flash = nil
     @shelled = @asking = false
     @in_x = ENV["TERM"] =~ /(xterm|rxvt|screen)/
+    @sigwinch_happened = false
+    @sigwinch_mutex = Mutex.new
 
     self.class.i_am_the_instance self
   end
 
+  def sigwinch_happened!; @sigwinch_mutex.synchronize { @sigwinch_happened = true } end
+  def sigwinch_happened?; @sigwinch_mutex.synchronize { @sigwinch_happened } end
+
   def buffers; @name_map.to_a; end
 
   def focus_on buf
@@ -260,6 +266,12 @@ EOS
   def completely_redraw_screen
     return if @shelled
 
+    ## this magic makes Ncurses get the new size of the screen
+    Ncurses.endwin
+    Ncurses.refresh
+    @sigwinch_mutex.synchronize { @sigwinch_happened = false }
+    Redwood::log "new screen size is #{Ncurses.rows} x #{Ncurses.cols}"
+
     status, title = get_status_and_title(@focus_buf) # must be called outside of the ncurses lock
 
     Ncurses.sync do