bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

cheesy ncurses console client for testing


From: Marcus Brinkmann
Subject: cheesy ncurses console client for testing
Date: Sun, 9 Jun 2002 02:03:34 +0200
User-agent: Mutt/1.3.28i

Hi,

here is some

  cheesy
       adj : (informal) of very poor quality [syn: {bum}, {cheap}, {chintzy},
              {crummy}, {punk}, {sleazy}, {tinny}]

ncurses based console client code that will work with the io_read() polling
interface in the hurd/console/* console code of tonight.

This already features unicode support, proper scrolling, cursor positioning
and curser status flag (invisibility and standout of cursor), but don't take
it too seriously.  It uses a polling interface, and updates the screen every
10 miliseconds.  It does block frequently for longer, though, epsecially the
input loop (I am not sure what the effect here is, maybe a bug in term or in
select, I will leave this for later).

It seems to be quite fast actually.  find on /share runs 0:24m if output goes to
/dev/null, for 1:01m if it goes to my console server with the above polling
client attached once, and for 2:14m if the output goes to a screen pseudo
terminal with synchronous update.  When scrolling this fast, and with the
current polling interface which always updates the whole screen, the
difference between asynchronous and synchronous display mode is clearly
visible.  It will be interesting to see how the effect is reduced by
optimizing the display client.

Next thing is scrollback and multiple virtual consoles in the display
client, which is not hard to do, and more debugging of the console server
itself and term (the term hurdio backend has at least one bug, which makes
it to get into a state sometimes where it outputs the same char all the time
regardless of what you typed).  Oh, and attributes support (colors etc).

On the server side, the next thing to come is update notifications, so we
don't need to poll and update the whole screen every time.  This should have
a dramatic effect on usability, I guess.  And only then I will use an io_map
based interface rather than an io_read interface.  This should speed up
things a lot, but I want to deal with problems and bugs one by one, rather
than in parallel :)

Compile the code (if you want) with the following Makefile:

------------------------------------------------------------------------------
CFLAGS=-Wall -g -I. -D_GNU_SOURCE

all: console-client-unix

console-client-unix: console-client-unix.o
        $(CC) console-client-unix.o -lncursesw -lthreads -o console-client-unix
------------------------------------------------------------------------------

As you see, you need the libncursesw5-dev stuff (ncurses with wide char
support).

Please, if you are interested in learning how to write good code, don't look
at this, go elsewhere ;)  This is only for testing the console server code
(and may evolve into a unix display client much later).

Thanks,
Marcus

Following the code of console-client-unix.c

/* console-client-unix.c -- A console client.
   Copyright (C) 2002 Free Software Foundation, Inc.
   Written by Marcus Brinkmann.

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2, or (at
   your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <wchar.h>
#include <error.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/types.h>

#include <ncursesw/curses.h>

#include <cthreads.h>

struct mutex ncurses_lock;

any_t
input_loop (any_t fdp)
{
  int fd = 0;
  int wfd = *(int *) fdp;
  fd_set rfds;

  FD_ZERO (&rfds);
  FD_SET (fd, &rfds);

  while (1)
    {
      int ret;

      FD_SET (fd, &rfds);

      ret = select (fd + 1, &rfds, 0, 0, 0);
      if (ret == 1)
        {
          char buffer[100];
          char *buf = buffer;
          size_t size = 0;

          mutex_lock (&ncurses_lock);
          while ((ret = getch ()) != ERR)
            {
              switch (ret)
                {
                case KEY_DOWN:
                  /* etc */
                  /* Do something */
                  break;
                default:
                  buf[size++] = ret;
                  assert (size != 100);
                  break;
                }
            }
          mutex_unlock (&ncurses_lock);
          do
            {
              ret = write (wfd, buf, size);
              if (ret > 0)
                {
                  size -= ret;
                  buf += ret;
                }
            }
          while (ret != -1 || errno == EINTR);
        }
    }
}
          

void
mvwputsn (wchar_t *str, size_t len, int x, int y)
{
  cchar_t chr;
  wchar_t wch[2] = { L'\0', L'\0' };

  move (y, x);
  while (len)
    {
      int ret;

      wch[0] = *str;
      ret = setcchar (&chr, wch, 0, 0, NULL);
      /*      if (ret == ERR)
        {
          printf ("setcchar failed: %s\n", strerror (errno));
          printf ("[%lc]\n", wch[0]);
          assert (!"Do something if setcchar fails.");
          }*/
      ret = add_wch (&chr);
      /*      if (ret == ERR)
        {
          printf ("add_wch failed: %i, %s\n", ret, strerror (errno));
          printf ("[%lc]\n", wch[0]);
          assert (!"Do something if add_wchr fails.");
          }*/
      len--;
      str++;
    }
} 

int
main (int argc, char *argv[])
{
  struct
  {
    u_int32_t width;
    u_int32_t height;
    u_int32_t lines;
    u_int32_t current_line;
    u_int32_t scrolling_max;
    u_int32_t cursor_x;
    u_int32_t cursor_y;
    u_int32_t cursor_status;
    wchar_t matrix[2000];
  } buffer;
  char *display_name;
  char *input_name;
  int disp;
  int inpt;
  int ret;
#define SLEEP_MSECS 10
#if defined(HAVE_NANOSLEEP)
  struct timespec to;
#else
#if defined(__GNU__)
  mach_port_t recv = mach_reply_port ();
#else
#error Need nanosleep or equivalent.
#endif
#endif
  mutex_init (&ncurses_lock);

  initscr ();
  cbreak ();
  noecho ();
  nonl ();
  intrflush (stdscr, FALSE);
  //  timeout (1000);
  nodelay (stdscr, TRUE);
  keypad (stdscr, TRUE);

  if (argc != 2)
    error (1, 0, "missing vc dir name");

  asprintf (&display_name, "%s/display", argv[1]);
  asprintf (&input_name, "%s/input", argv[1]);

  disp = open (display_name, O_RDONLY);
  if (disp < 0)
    error (2, errno, "opening %s failed", display_name);
  inpt = open (input_name, O_WRONLY);
  if (inpt < 0)
    error (2, errno, "opening %s failed", input_name);

  cthread_detach (cthread_fork (input_loop, &inpt));

  while (1)
    {
      ret = lseek (disp, 0, SEEK_SET);
      if (ret < 0)
        error (3, errno, "seek failed");
      ret = read (disp, (char *) &buffer, sizeof (buffer));
      if (ret < 0)
        error (3, errno, "read failed");
      if (ret != sizeof (buffer))
        error (3, errno, "read failed");
      mutex_lock (&ncurses_lock);
      mvwputsn (buffer.matrix + buffer.current_line * buffer.width,
                ((buffer.lines - buffer.current_line < buffer.height)
                 ? buffer.lines - buffer.current_line : buffer.height)
                * buffer.width, 0, 0);
      if (buffer.lines - buffer.current_line < buffer.height)
        mvwputsn (buffer.matrix,
                  2000 - (buffer.lines - buffer.current_line)
                  * buffer.width, 0, buffer.lines - buffer.current_line);
      move (buffer.cursor_y, buffer.cursor_x);
      curs_set (buffer.cursor_status
                ? (buffer.cursor_status == 1 ? 0 : 2) : 1);
      refresh ();
      mutex_unlock (&ncurses_lock);
#if defined(HAVE_NANOSLEEP)
      to.tv_sec = 0;
      to.tv_nsec = SLEEP_MSECS * 1000000;
      nanosleep (&to, 0);
#else
#if defined(__GNU__)
      mach_msg (NULL, MACH_RCV_MSG | MACH_RCV_INTERRUPT | MACH_RCV_TIMEOUT,
        0, 0, recv, SLEEP_MSECS, MACH_PORT_NULL);
#endif
#endif
    }
  endwin ();
  return 0;
}



reply via email to

[Prev in Thread] Current Thread [Next in Thread]