Threads + Ncurses

Hi,

I'm fairly new to ruby and wanted to write some example programs in
ruby using ncurses-wrapper-library. That is, in fact, really simple
and works well.

But now I have a problem: I want ncurses to draw some things on the
screen and update it every second - until a key is pressed. I'm trying
to do it as follows (short example):

stop = nil
Thread.new do
  until stop
    Ncurses.printw("foo") # just an example...
    Ncurses.refresh
    sleep 1
  end
  Ncurses.endwin
end
Ncurses.getch
stop = 1

But I suppose Ncurses.getch blocks any other ncurses-functions from
writing anything on the window... so - what to do?

I just want to run the thread continuously until one key is pressed...
What other possibilities do I have?

Thanks in advance :slight_smile:

Julius

Julius,

You can just select on STDIN, or use the 'io/wait' module to check for
its status:

require 'io/wait'
require 'ncurses'

begin
  Ncurses.initscr; Ncurses.cbreak; Ncurses.noecho; Ncurses.nonl

  Ncurses.stdscr.addstr("Press a key to continue...")
  Ncurses.stdscr.refresh
  while not STDIN.ready?
    Ncurses.stdscr.addstr('.')
    Ncurses.stdscr.refresh
    sleep 1
  end
  Ncurses.stdscr.getch

ensure
  Ncurses.echo; Ncurses.nocbreak; Ncurses.nl; Ncurses.endwin
end

···

--
Lennon
rcoder.net

Julius Plenz wrote:

But now I have a problem: I want ncurses to draw some things on the
screen and update it every second - until a key is pressed. I'm trying
to do it as follows (short example):

stop = nil
Thread.new do
  until stop
    Ncurses.printw("foo") # just an example...
    Ncurses.refresh
    sleep 1
  end
  Ncurses.endwin
end
Ncurses.getch
stop = 1

But I suppose Ncurses.getch blocks any other ncurses-functions from
writing anything on the window... so - what to do?

I just want to run the thread continuously until one key is pressed...
What other possibilities do I have?

Ncurses.getch blocks not only other ncurses-functions. It blocks the complete ruby interpreter, all threads.

This has to change, obviously, and it will change before the 1.0 release of ncurses-ruby. In the meantime, you can work around the limitation in the way Lennon suggested [ruby-talk:109697].

Even when Ncurses.getch is fixed, you can not expect to call Ncurses functions concurrently from several threads and get the desired results.
Ncurses shares this limitation with most other UI libraries. They are basically state machines, i.e. order of commands matters. Your application is responsible for serializing Ncurses calls, not the ncurses wrapper.

regards,
   Tobias

Julius Plenz wrote:

[snipped]

>I just want to run the thread continuously until one key is pressed...
>What other possibilities do I have?

Ncurses.getch blocks not only other ncurses-functions. It blocks the
complete ruby interpreter, all threads.

This has to change, obviously, and it will change before the 1.0 release
of ncurses-ruby. In the meantime, you can work around the limitation in
the way Lennon suggested [ruby-talk:109697].

Raggle uses this approach, and it does have at least one caveat:
terminal resize events (and possibly mouse events as well, although I
believe those are still broken in Ncurses-Ruby) are not handled
properly.

That said, here's the code from Raggle:

  timeout = $config['input_select_timeout'] # defaults to 0.2
  $done = false
  until $done
    # handle keyboard input
    r = select [$stdin], nil, nil, timeout
    if r && r.size > 0
      c = Ncurses::getch
      $config['keys'][c].call($wins[$a_win],c) \
        if $config['keys'].has_key? c
    end
    
    # snipped irrelevant stuff
  end

[snipped]

···

* Tobias Peters (tpeters@invalid.uni-oldenburg.de) wrote:

regards,
  Tobias

--
Paul Duncan <pabs@pablotron.org> pabs in #ruby-lang (OPN IRC)
http://www.pablotron.org/ OpenPGP Key ID: 0x82C29562