| /* ncurses.c */ | |
| /* Copyright 1999 - Joseph Pranevich */ | |
| #include <stdio.h> | |
| #include "config.h" | |
| #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 <ncurses.h> | |
| #else | |
| # ifdef HAVE_CURSES_H | |
| # include <curses.h> | |
| # 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 */ |