284 lines
6.5 KiB
C
284 lines
6.5 KiB
C
/* 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 "debug.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(console, "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(console, "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(console, "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(console, "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(console, "Color pair: already allocated\n");
|
|
return x;
|
|
}
|
|
}
|
|
|
|
/* Need to allocate new color */
|
|
current++;
|
|
fg[current] = fg_color;
|
|
bg[current] = bg_color;
|
|
TRACE(console, "Color pair: allocated.\n");
|
|
return init_pair(current, fg_color, bg_color);
|
|
}
|
|
|
|
#endif /* WINE_NCURSES */
|