From 057b2a310582ea16dc147e948fc42bb61dc53b0d Mon Sep 17 00:00:00 2001 From: Marcus Brinkmann Date: Thu, 22 Aug 2002 21:33:02 +0000 Subject: 2002-08-22 Marcus Brinkmann * aclocal.m4 (hurd_LIB_NCURSESW): New test, modified from GNU inetutils 1.4.0. * configure.in: Use hurd_LIB_NCURSESW. * config.make.in (LIBNCURSESW): New variable, substituted by configure. (NCURSESW_INCLUDE): Likewise. * Makefile (lib-subdirs): Add libcons. (prog-subdirs): Add console. console/ 2002-08-22 Marcus Brinkmann * console.h: Move file to ../hurd/. * Makefile (LCLHDRS): Remove console.h. * display.c: Include instead "console.h". * console.c: Likewise. hurd/ 2002-08-22 Marcus Brinkmann * console.h: Move here from ../console/. * Makefile (INSTHDRS): Add console.h. utils/ 2002-08-22 Marcus Brinkmann * Makefile: Include `../config.make' early on to get LIBNCURSESW variable from configure before including Makeconf. (targets) [LIBNCURSES]: Add console-ncurses. (SRCS) [LIBNCURSES]: Add console-ncurses.c. (HURDLIBS) [LIBNCURSES]: Add cons. (console-ncurses): New target. (console-ncurses-CPPFLAGS): New variable. (console-ncurses-LDLIBS): Likewise. --- utils/console-ncurses.c | 584 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 584 insertions(+) create mode 100644 utils/console-ncurses.c (limited to 'utils') diff --git a/utils/console-ncurses.c b/utils/console-ncurses.c new file mode 100644 index 00000000..4ec60d7d --- /dev/null +++ b/utils/console-ncurses.c @@ -0,0 +1,584 @@ +/* console-ncurses.c -- A console client based on ncurses. + 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 +#include +#include +#include +#include +#include +#include +#include + +/* The makefiles make sure that this program is compiled with + -I${prefix}/ncursesw. */ +#include + +#include + +#include +#include + +#include + +struct mutex ncurses_lock; + +const char *cons_client_name = "console-ncurses"; +const char *cons_client_version = HURD_VERSION; + + +struct curses_kc_to_cons_kc +{ + int curses; + char *cons; +}; + +struct curses_kc_to_cons_kc keycodes[] = + { + { KEY_BREAK, NULL }, /* XXX */ + { KEY_DOWN, CONS_KEY_DOWN }, + { KEY_UP, CONS_KEY_UP }, + { KEY_RIGHT, CONS_KEY_RIGHT }, + { KEY_LEFT, CONS_KEY_LEFT }, + { KEY_HOME, CONS_KEY_HOME }, + { KEY_BACKSPACE, CONS_KEY_BACKSPACE }, + { KEY_F(1), CONS_KEY_F1 }, + { KEY_F(2), CONS_KEY_F2 }, + { KEY_F(3), CONS_KEY_F3 }, + { KEY_F(4), CONS_KEY_F4 }, + { KEY_F(5), CONS_KEY_F5 }, + { KEY_F(6), CONS_KEY_F6 }, + { KEY_F(7), CONS_KEY_F7 }, + { KEY_F(8), CONS_KEY_F8 }, + { KEY_F(9), CONS_KEY_F9 }, + { KEY_F(10), CONS_KEY_F10 }, + { KEY_DL, NULL }, /* XXX Delete line. */ + { KEY_IL, NULL }, /* XXX Insert line. */ + { KEY_DC, CONS_KEY_DC }, + { KEY_IC, CONS_KEY_IC }, + { KEY_EIC, NULL }, /* XXX Exit insert mode. */ + { KEY_CLEAR, NULL }, /* XXX Clear screen. */ + { KEY_EOS, NULL }, /* XXX Clear to end of screen. */ + { KEY_EOL, NULL }, /* XXX Clear to end of line. */ + { KEY_SF, NULL }, /* XXX Scroll one line forward. */ + { KEY_SR, NULL }, /* XXX Scroll one line backward. */ + { KEY_NPAGE, CONS_KEY_NPAGE }, + { KEY_PPAGE, CONS_KEY_PPAGE }, + { KEY_STAB, NULL }, /* XXX Set tab. */ + { KEY_CTAB, NULL }, /* XXX Clear tab. */ + { KEY_CATAB, NULL }, /* XXX Clear all tabs. */ + { KEY_ENTER, NULL }, /* XXX Enter or send. */ + { KEY_SRESET, NULL }, /* XXX Soft (partial) reset. */ + { KEY_RESET, NULL }, /* XXX Reset or hard reset. */ + { KEY_PRINT, NULL }, /* XXX Print or copy. */ + { KEY_LL, NULL }, /* XXX Home down or bottom (lower left). */ + { KEY_A1, NULL }, /* XXX Upper left of keypad. */ + { KEY_A3, NULL }, /* XXX Upper right of keypad. */ + { KEY_B2, NULL }, /* XXX Center of keypad. */ + { KEY_C1, NULL }, /* XXX Lower left of keypad. */ + { KEY_C3, NULL }, /* XXX Lower right of keypad. */ + { KEY_BTAB, CONS_KEY_BTAB }, + { KEY_BEG, NULL }, /* XXX Beg(inning) key. */ + { KEY_CANCEL, NULL }, /* XXX Cancel key. */ + { KEY_CLOSE, NULL }, /* XXX Close key. */ + { KEY_COMMAND, NULL }, /* XXX Cmd (command) key. */ + { KEY_COPY, NULL }, /* XXX Copy key. */ + { KEY_CREATE, NULL }, /* XXX Create key. */ + { KEY_END, CONS_KEY_END }, + { KEY_EXIT, NULL }, /* XXX Exit key. */ + { KEY_FIND, NULL }, /* XXX Find key. */ + { KEY_HELP, NULL }, /* XXX Help key. */ + { KEY_MARK, NULL }, /* XXX Mark key. */ + { KEY_MESSAGE, NULL }, /* XXX Message key. */ + { KEY_MOUSE, NULL }, /* XXX Mouse event read. */ + { KEY_MOVE, NULL }, /* XXX Move key. */ + { KEY_NEXT, NULL }, /* XXX Next object key. */ + { KEY_OPEN, NULL }, /* XXX Open key. */ + { KEY_OPTIONS, NULL }, /* XXX Options key. */ + { KEY_PREVIOUS, NULL }, /* XXX Previous object key. */ + { KEY_REDO, NULL }, /* XXX Redo key. */ + { KEY_REFERENCE, NULL }, /* XXX Ref(erence) key. */ + { KEY_REFRESH, NULL }, /* XXX Refresh key. */ + { KEY_REPLACE, NULL }, /* XXX Replace key. */ + { KEY_RESIZE, NULL }, /* XXX Screen resized. */ + { KEY_RESTART, NULL }, /* XXX Restart key. */ + { KEY_RESUME, NULL }, /* XXX Resume key. */ + { KEY_SAVE, NULL }, /* XXX Save key. */ + { KEY_SBEG, NULL }, /* XXX Shifted beginning key. */ + { KEY_SCANCEL, NULL }, /* XXX Shifted cancel key. */ + { KEY_SCOMMAND, NULL }, /* XXX Shifted command key. */ + { KEY_SCOPY, NULL }, /* XXX Shifted copy key. */ + { KEY_SCREATE, NULL }, /* XXX Shifted create key. */ + { KEY_SDC, NULL }, /* XXX Shifted delete char key. */ + { KEY_SDL, NULL }, /* XXX Shifted delete line key. */ + { KEY_SELECT, NULL }, /* XXX Select key. */ + { KEY_SEND, NULL }, /* XXX Shifted end key. */ + { KEY_SEOL, NULL }, /* XXX Shifted clear line key. */ + { KEY_SEXIT, NULL }, /* XXX Shifted exit key. */ + { KEY_SFIND, NULL }, /* XXX Shifted find key. */ + { KEY_SHELP, NULL }, /* XXX Shifted help key. */ + { KEY_SHOME, NULL }, /* XXX Shifted home key. */ + { KEY_SIC, NULL }, /* XXX Shifted input key. */ + { KEY_SLEFT, NULL }, /* XXX Shifted left arrow key. */ + { KEY_SMESSAGE, NULL }, /* XXX Shifted message key. */ + { KEY_SMOVE, NULL }, /* XXX Shifted move key. */ + { KEY_SNEXT, NULL }, /* XXX Shifted next key. */ + { KEY_SOPTIONS, NULL }, /* XXX Shifted options key. */ + { KEY_SPREVIOUS, NULL }, /* XXX Shifted prev key. */ + { KEY_SPRINT, NULL }, /* XXX Shifted print key. */ + { KEY_SREDO, NULL }, /* XXX Shifted redo key. */ + { KEY_SREPLACE, NULL }, /* XXX Shifted replace key. */ + { KEY_SRIGHT, NULL }, /* XXX Shifted right arrow. */ + { KEY_SRSUME, NULL }, /* XXX Shifted resume key. */ + { KEY_SSAVE, NULL }, /* XXX Shifted save key. */ + { KEY_SSUSPEND, NULL }, /* XXX Shifted suspend key. */ + { KEY_SUNDO, NULL }, /* XXX Shifted undo key. */ + { KEY_SUSPEND, NULL }, /* XXX Suspend key. */ + { KEY_UNDO, NULL } /* XXX Undo key. */ + }; + +int +ucs4_to_altchar (wchar_t chr, chtype *achr) +{ + switch (chr) + { + case CONS_CHAR_RARROW: + *achr = ACS_RARROW; + break; + case CONS_CHAR_LARROW: + *achr = ACS_LARROW; + break; + case CONS_CHAR_UARROW: + *achr = ACS_UARROW; + break; + case CONS_CHAR_DARROW: + *achr = ACS_DARROW; + break; + case CONS_CHAR_BLOCK: + *achr = ACS_BLOCK; + break; + case CONS_CHAR_LANTERN: + *achr = ACS_LANTERN; + break; + case CONS_CHAR_DIAMOND: + *achr = ACS_DIAMOND; + break; + case CONS_CHAR_CKBOARD: + *achr = ACS_CKBOARD; + break; + case CONS_CHAR_DEGREE: + *achr = ACS_DEGREE; + break; + case CONS_CHAR_PLMINUS: + *achr = ACS_PLMINUS; + break; + case CONS_CHAR_BOARD: + *achr = ACS_BOARD; + break; + case CONS_CHAR_LRCORNER: + *achr = ACS_LRCORNER; + break; + case CONS_CHAR_URCORNER: + *achr = ACS_URCORNER; + break; + case CONS_CHAR_ULCORNER: + *achr = ACS_ULCORNER; + break; + case CONS_CHAR_LLCORNER: + *achr = ACS_LLCORNER; + break; + case CONS_CHAR_PLUS: + *achr = ACS_PLUS; + break; + case CONS_CHAR_S1: + *achr = ACS_S1; + break; + case CONS_CHAR_S3: + *achr = ACS_S3; + break; + case CONS_CHAR_HLINE: + *achr = ACS_HLINE; + break; + case CONS_CHAR_S7: + *achr = ACS_S7; + break; + case CONS_CHAR_S9: + *achr = ACS_S9; + break; + case CONS_CHAR_LTEE: + *achr = ACS_LTEE; + break; + case CONS_CHAR_RTEE: + *achr = ACS_RTEE; + break; + case CONS_CHAR_BTEE: + *achr = ACS_BTEE; + break; + case CONS_CHAR_TTEE: + *achr = ACS_TTEE; + break; + case CONS_CHAR_VLINE: + *achr = ACS_VLINE; + break; + case CONS_CHAR_LEQUAL: + *achr = ACS_LEQUAL; + break; + case CONS_CHAR_GEQUAL: + *achr = ACS_GEQUAL; + break; + case CONS_CHAR_PI: + *achr = ACS_PI; + break; + case CONS_CHAR_NEQUAL: + *achr = ACS_NEQUAL; + break; + case CONS_CHAR_STERLING: + *achr = ACS_STERLING; + break; + case CONS_CHAR_BULLET: + *achr = ACS_BULLET; + break; + default: + return 0; + } + return 1; +} + +static vcons_t active_vcons = NULL; + +error_t +cons_vcons_activate (vcons_t vcons) +{ + error_t err; + + assert (vcons); + assert (vcons != active_vcons); + + err = cons_vcons_open (vcons); + if (err) + return err; + + if (active_vcons) + cons_vcons_close (active_vcons); + active_vcons = vcons; + return 0; +} + +any_t +input_loop (any_t unused) +{ + int fd = 0; + fd_set rfds; + int w_escaped = 0; + + 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) + { + int i; + int found; + + if (w_escaped) + { + switch (ret) + { + case 'x': + endwin (); + exit (0); + break; + case 23: /* ^W */ + assert (size < 100); + buf[size++] = ret; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* Avoid a dead lock. */ + mutex_unlock (&ncurses_lock); + /* XXX: We ignore any error here. */ + cons_switch (active_vcons->cons, 1 + (ret - '1'), 0); + mutex_lock (&ncurses_lock); + break; + default: + break; + } + w_escaped = 0; + } + else + switch (ret) + { + case 23: /* ^W */ + w_escaped = 1; + break; + default: + found = 0; + for (i =0; i < sizeof(keycodes) / sizeof(keycodes[0]); i++) + { + if (keycodes[i].curses == ret) + { + if (keycodes[i].cons) + { + assert (size < 101 - strlen(keycodes[i].cons)); + strcpy (&buf[size], keycodes[i].cons); + size += strlen (keycodes[i].cons); + } + found = 1; + break; + } + } + if (!found) + { + assert (size < 100); + buf[size++] = ret; + } + break; + } + } + mutex_unlock (&ncurses_lock); + if (size) + { + if (active_vcons) + { + mutex_lock (&active_vcons->lock); + do + { + ret = write (active_vcons->input, buf, size); + if (ret > 0) + { + size -= ret; + buf += ret; + } + } + while (size && (ret != -1 || errno == EINTR)); + mutex_unlock (&active_vcons->lock); + } + } + } + } +} + +inline attr_t +conchar_attr_to_attr (conchar_attr_t attr) +{ + return ((attr.intensity == CONS_ATTR_INTENSITY_BOLD + ? A_BOLD : (attr.intensity == CONS_ATTR_INTENSITY_DIM + ? A_DIM : A_NORMAL)) + | (attr.underlined ? A_UNDERLINE : 0) + | (attr.reversed ? A_REVERSE : 0) + | (attr.blinking ? A_BLINK: 0) + | (attr.concealed ? A_INVIS : 0)); +} + +inline short +conchar_attr_to_color_pair (conchar_attr_t attr) +{ + return COLOR_PAIR (attr.bgcol << 3 | attr.fgcol); +} + +void +mvwputsn (conchar_t *str, size_t len, off_t x, off_t y) +{ + cchar_t chr; + wchar_t wch[2] = { L'\0', L'\0' }; + uint32_t last_attr = * (uint32_t *) &str->attr; + attr_t attr = conchar_attr_to_attr (str->attr); + short color_pair = conchar_attr_to_color_pair (str->attr); + + move (y, x); + while (len) + { + int ret; + chtype ac; + + if (last_attr != *(uint32_t *) &str->attr) + { + last_attr = * (uint32_t *) &str->attr; + attr = conchar_attr_to_attr (str->attr); + color_pair = conchar_attr_to_color_pair (str->attr); + } + + if (ucs4_to_altchar (str->chr, &ac)) + addch (ac | attr | color_pair); + else + { + wch[0] = str->chr; + ret = setcchar (&chr, wch, attr, color_pair, NULL); +#if 0 + if (ret == ERR) + { + printf ("setcchar failed: %s\n", strerror (errno)); + printf ("[%lc]\n", wch[0]); + assert (!"Do something if setcchar fails."); + } +#endif + ret = add_wch (&chr); +#if 0 + 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."); + } +#endif + } + len--; + str++; + } +} + + +void +cons_vcons_update (vcons_t vcons) +{ + if (vcons != active_vcons) + return; + refresh (); +} + +void +cons_vcons_set_cursor_pos (vcons_t vcons, uint32_t col, uint32_t row) +{ + if (vcons != active_vcons) + return; + mutex_lock (&ncurses_lock); + move (row, col); + mutex_unlock (&ncurses_lock); +} + +void +cons_vcons_set_cursor_status (vcons_t vcons, uint32_t status) +{ + if (vcons != active_vcons) + return; + mutex_lock (&ncurses_lock); + curs_set (status ? (status == 1 ? 1 : 2) : 0); + mutex_unlock (&ncurses_lock); +} + +void +cons_vcons_scroll (vcons_t vcons, int delta) +{ + assert (delta >= 0); + if (vcons != active_vcons) + return; + + mutex_lock (&ncurses_lock); + idlok (stdscr, TRUE); + scrollok (stdscr, TRUE); + scrl (delta); + idlok (stdscr, FALSE); + scrollok (stdscr, FALSE); + mutex_unlock (&ncurses_lock); +} + +void +cons_vcons_write (vcons_t vcons, conchar_t *str, size_t length, + uint32_t col, uint32_t row) +{ + int x; + int y; + + if (vcons != active_vcons) + return; + + mutex_lock (&ncurses_lock); + getsyx (y, x); + mvwputsn (str, length, col, row); + setsyx (y, x); + mutex_unlock (&ncurses_lock); +} + +void +cons_vcons_beep (vcons_t vcons) +{ + if (vcons != active_vcons) + return; + + mutex_lock (&ncurses_lock); + beep (); + mutex_unlock (&ncurses_lock); +} + +void +cons_vcons_flash (vcons_t vcons) +{ + if (vcons != active_vcons) + return; + + mutex_lock (&ncurses_lock); + flash (); + mutex_unlock (&ncurses_lock); +} + + +int +main (int argc, char *argv[]) +{ + error_t err; + int i; + + /* Parse our command line. This shouldn't ever return an error. */ + argp_parse (&cons_startup_argp, argc, argv, 0, 0, 0); + + mutex_init (&ncurses_lock); + + initscr (); + start_color (); + for (i = 0; i < 64; i++) + init_pair (i, i & 7, i >> 3); + raw (); + noecho (); + nonl (); + intrflush (stdscr, FALSE); + nodelay (stdscr, TRUE); + timeout (1); + keypad (stdscr, TRUE); + + cthread_detach (cthread_fork (input_loop, NULL)); + + err = cons_init (); + if (err) + error (5, err, "Console library initialization failed"); + + cons_server_loop (); + + /* Never reached. */ + endwin (); + return 0; +} -- cgit v1.2.3