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
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
@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
## 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
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
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
## 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
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
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)