|  | /* | 
|  | * Copyright 1999 - Joseph Pranevich | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library 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 | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  |  | 
|  | #include <stdio.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 "wine/debug.h" | 
|  | #include "options.h" | 
|  |  | 
|  | WINE_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 */ |