]> git.cworth.org Git - sup/blobdiff - lib/sup/buffer.rb
protect getch from ctrl-c's outside of the main event loop
[sup] / lib / sup / buffer.rb
index 3bd3fe8e96a1563ff3ae4fa748b80203a1320cb8..df5d23c455fbaeb9fa53a5d9d66305249d9d6f17 100644 (file)
@@ -25,17 +25,24 @@ module Ncurses
   def mutex; @mutex ||= Mutex.new; end
   def sync &b; mutex.synchronize(&b); end
 
-  ## magically, this stuff seems to work now. i could swear it didn't
-  ## before. hm.
   def nonblocking_getch
-    if IO.select([$stdin], nil, nil, 1)
-      Ncurses.getch
-    else
-      nil
+    ## 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
+  ## pretends ctrl-c's are ctrl-g's
+  def safe_nonblocking_getch
+    nonblocking_getch
+  rescue Interrupt
+    KEY_CANCEL
+  end
+
+  module_function :rows, :cols, :curx, :nonblocking_getch, :safe_nonblocking_getch, :mutex, :sync
 
   remove_const :KEY_ENTER
   remove_const :KEY_CANCEL
@@ -70,7 +77,7 @@ class Buffer
   def content_height; @height - 1; end
   def content_width; @width; end
 
-  def resize rows, cols 
+  def resize rows, cols
     return if cols == @width && rows == @height
     @width = cols
     @height = rows
@@ -196,10 +203,13 @@ EOS
     @flash = nil
     @shelled = @asking = false
     @in_x = ENV["TERM"] =~ /(xterm|rxvt|screen)/
-
-    self.class.i_am_the_instance self
+    @sigwinch_happened = false
+    @sigwinch_mutex = Mutex.new
   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
@@ -230,14 +240,20 @@ EOS
   ## have to change this. but it's not clear that we will ever actually
   ## do that.
   def roll_buffers
-    @buffers.last.force_to_top = false
-    raise_to_front @buffers.first
+    bufs = rollable_buffers
+    bufs.last.force_to_top = false
+    raise_to_front bufs.first
   end
 
   def roll_buffers_backwards
-    return unless @buffers.length > 1
-    @buffers.last.force_to_top = false
-    raise_to_front @buffers[@buffers.length - 2]
+    bufs = rollable_buffers
+    return unless bufs.length > 1
+    bufs.last.force_to_top = false
+    raise_to_front bufs[bufs.length - 2]
+  end
+
+  def rollable_buffers
+    @buffers.select { |b| !b.system? || @buffers.last == b }
   end
 
   def handle_input c
@@ -261,6 +277,14 @@ EOS
   def completely_redraw_screen
     return if @shelled
 
+    ## this magic makes Ncurses get the new size of the screen
+    Ncurses.endwin
+    Ncurses.stdscr.keypad 1
+    Ncurses.curs_set 0
+    Ncurses.refresh
+    @sigwinch_mutex.synchronize { @sigwinch_happened = false }
+    debug "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
@@ -366,7 +390,7 @@ EOS
     draw_screen
 
     until mode.done?
-      c = Ncurses.nonblocking_getch
+      c = Ncurses.safe_nonblocking_getch
       next unless c # getch timeout
       break if c == Ncurses::KEY_CANCEL
       begin
@@ -484,7 +508,7 @@ EOS
   ## returns an array of labels
   def ask_for_labels domain, question, default_labels, forbidden_labels=[]
     default_labels = default_labels - forbidden_labels - LabelManager::RESERVED_LABELS
-    default = default_labels.join(" ")
+    default = default_labels.to_a.join(" ")
     default += " " unless default.empty?
 
     # here I would prefer to give more control and allow all_labels instead of
@@ -542,7 +566,7 @@ EOS
     end
 
     while true
-      c = Ncurses.nonblocking_getch
+      c = Ncurses.safe_nonblocking_getch
       next unless c # getch timeout
       break unless tf.handle_input c # process keystroke
 
@@ -595,7 +619,7 @@ EOS
     ret = nil
     done = false
     until done
-      key = Ncurses.nonblocking_getch or next
+      key = Ncurses.safe_nonblocking_getch or next
       if key == Ncurses::KEY_CANCEL
         done = true
       elsif accept.nil? || accept.empty? || accept.member?(key)