/* ncurses.c */ /* Copyright 1999 - Joseph Pranevich */ #include "config.h" #include #include "console.h" /* Must define WINE_NCURSES */ #ifdef WINE_NCURSES /* This is the console driver for systems that support the ncurses interface. */ /* Actually, this should work for curses, as well. But there may be individual functions that are unsupported in plain curses or other variants. Those should be detected and special-cased by autoconf. */ /* When creating new drivers, you need to assign all the functions that that driver supports into the driver struct. If it is a supplementary driver, it should make sure to perserve the old values. */ #include "debugtools.h" #include "options.h" DEFAULT_DEBUG_CHANNEL(console); #undef ERR /* Use ncurses's err() */ #ifdef HAVE_NCURSES_H # include #else # ifdef HAVE_CURSES_H # include # endif #endif SCREEN *ncurses_screen; static int get_color_pair(int fg_color, int bg_color); const char *color_names[] = {"null", "black", "blue", "green", "cyan", "magenta", "brown", "red", "light gray", "dark gray", "light blue", "light green", "light red", "light magenta", "light cyan", "yellow", "white"}; void NCURSES_Start() { /* This should be the root driver so we can ignore anything already in the struct. */ driver.norefresh = FALSE; driver.init = NCURSES_Init; driver.write = NCURSES_Write; driver.close = NCURSES_Close; driver.moveCursor = NCURSES_MoveCursor; driver.getCursorPosition = NCURSES_GetCursorPosition; driver.getCharacterAtCursor = NCURSES_GetCharacterAtCursor; driver.clearScreen = NCURSES_ClearScreen; driver.allocColor = NCURSES_AllocColor; #ifdef HAVE_GETBKGD driver.setBackgroundColor = NCURSES_SetBackgroundColor; #endif #ifdef HAVE_RESIZETERM driver.notifyResizeScreen = NCURSES_NotifyResizeScreen; #endif /* HAVE_RESIZETERM */ driver.checkForKeystroke = NCURSES_CheckForKeystroke; driver.getKeystroke = NCURSES_GetKeystroke; driver.refresh = NCURSES_Refresh; } void NCURSES_Init() { char terminal_type[80]; PROFILE_GetWineIniString("console", "TerminalType", "xterm", terminal_type, 79); ncurses_screen = newterm(terminal_type, driver.console_out, driver.console_in); set_term(ncurses_screen); start_color(); raw(); noecho(); nonl(); intrflush(stdscr, FALSE); keypad(stdscr, TRUE); nodelay(stdscr, TRUE); } void NCURSES_Write(char output, int fg, int bg, int attribute) { char row, col; int pair; if (!fg) fg = COLOR_WHITE; /* Default */ if (!bg) bg = COLOR_BLACK; /* Default */ pair = get_color_pair(fg, bg); if (waddch(stdscr, output | COLOR_PAIR(pair)) == ERR) { NCURSES_GetCursorPosition(&row, &col); FIXME("NCURSES: waddch() failed at %d, %d.\n", row, col); } } void NCURSES_Close() { endwin(); } void NCURSES_GetKeystroke(char *scan, char *ascii) { while (!NCURSES_CheckForKeystroke(scan, ascii)) {} /* Wait until keystroke is detected */ /* When it is detected, we will already have the right value in scan and ascii, but we need to take this keystroke out of the buffer. */ wgetch(stdscr); } int NCURSES_CheckForKeystroke(char *scan, char *ascii) { /* We don't currently support scan codes here */ /* FIXME */ int temp; temp = wgetch(stdscr); if (temp == ERR) { return FALSE; } else { ungetch(temp); /* Keystroke not removed from buffer */ *ascii = (char) temp; return TRUE; } } void NCURSES_MoveCursor(char row, char col) { if (wmove(stdscr, row, col) == ERR) FIXME("NCURSES: wmove() failed to %d, %d.\n", row, col); } void NCURSES_GetCursorPosition(char *row, char *col) { int trow, tcol; getyx(stdscr, trow, tcol); /* MACRO, no need to pass pointer */ *row = (char) trow; *col = (char) tcol; } void NCURSES_GetCharacterAtCursor(char *ch, int *fg_color, int *bg_color, int *attribute) { /* If any of the pointers are NULL, ignore them */ /* We will eventually have to convert the color data */ if (ch) *ch = (char) winch(stdscr); if (fg_color) *fg_color = WINE_WHITE; if (bg_color) *bg_color = WINE_BLACK; if (attribute) *attribute = 0; } void NCURSES_Refresh() { wrefresh(stdscr); } void NCURSES_ClearScreen() { werase(stdscr); } int NCURSES_AllocColor(int color) { /* Currently support only internal colors */ switch (color) { case WINE_BLACK: return COLOR_BLACK; case WINE_WHITE: return COLOR_WHITE; case WINE_RED: return COLOR_RED; case WINE_GREEN: return COLOR_GREEN; case WINE_YELLOW: return COLOR_YELLOW; case WINE_BLUE: return COLOR_BLUE; case WINE_MAGENTA: return COLOR_MAGENTA; case WINE_CYAN: return COLOR_CYAN; } FIXME("Unable to allocate color %d (%s)\n", color, color_names[color]); /* Don't allocate a color... yet */ return 0; } void NCURSES_SetBackgroundColor(int fg, int bg) { int pair; pair = get_color_pair(fg, bg); wbkgd(stdscr, COLOR_PAIR(pair)); } #ifdef HAVE_GETBKGD void NCURSES_GetBackgroundColor(int *fg, int *bg) { chtype background; short pair, sfg, sbg; background = getbkgd(stdscr); pair = (!A_CHARTEXT & background); pair_content(pair, &sfg, &sbg); *fg = sfg; *bg = sbg; } #endif /* HAVE_GETBKGD */ #ifdef HAVE_RESIZETERM void NCURSES_NotifyResizeScreen(int x, int y) { /* Note: This function gets called *after* another driver in the chain calls ResizeScreen(). It is meant to resize the ncurses internal data structures to know about the new window dimensions. */ TRACE("Terminal resized to y: %d, x: %d\n", y, x); resizeterm(y, x); } #endif /* HAVE_RESIZETERM */ static int get_color_pair(int fg_color, int bg_color) { /* ncurses internally uses "color pairs" in addition to the "pallet" */ /* This isn't the best way to do this. Or even close */ static int current = 0; static int fg[255]; /* 16 x 16 is enough */ static int bg[255]; int x; /* The first pair is hardwired into ncurses */ fg[0] = COLOR_WHITE; bg[0] = COLOR_BLACK; for (x = 0; x <= current; x++) { if ((fg_color == fg[x]) && (bg_color == bg[x])) { TRACE("Color pair: already allocated\n"); return x; } } /* Need to allocate new color */ current++; fg[current] = fg_color; bg[current] = bg_color; TRACE("Color pair: allocated.\n"); return init_pair(current, fg_color, bg_color); } #endif /* WINE_NCURSES */