Henning Hoffmann
[wine] / console / ncurses.c
1 /* ncurses.c */
2 /* Copyright 1999 - Joseph Pranevich */
3
4 #include <stdio.h>
5 #include "config.h"
6 #include "console.h"    /* Must define WINE_NCURSES */
7
8 #ifdef WINE_NCURSES
9
10 /* This is the console driver for systems that support the ncurses
11    interface. 
12 */
13
14 /* Actually, this should work for curses, as well. But there may be
15    individual functions that are unsupported in plain curses or other
16    variants. Those should be detected and special-cased by autoconf. 
17 */
18
19 /* When creating new drivers, you need to assign all the functions that
20    that driver supports into the driver struct. If it is a supplementary
21    driver, it should make sure to perserve the old values. 
22 */
23
24 #include "debugtools.h"
25 #include "options.h"
26
27 DEFAULT_DEBUG_CHANNEL(console)
28
29 #undef ERR /* Use ncurses's err() */
30 #ifdef HAVE_NCURSES_H
31 # include <ncurses.h>
32 #else
33 # ifdef HAVE_CURSES_H
34 #  include <curses.h>
35 # endif
36 #endif
37
38 SCREEN *ncurses_screen;
39
40 static int get_color_pair(int fg_color, int bg_color);
41
42 const char *color_names[] = {"null", "black", "blue", "green",
43    "cyan", "magenta", "brown", "red", "light gray", "dark gray",
44    "light blue", "light green", "light red", "light magenta",
45    "light cyan", "yellow", "white"};
46
47 void NCURSES_Start()
48 {
49    /* This should be the root driver so we can ignore anything
50       already in the struct. */
51
52    driver.norefresh = FALSE;
53
54    driver.init = NCURSES_Init;
55    driver.write = NCURSES_Write;
56    driver.close = NCURSES_Close;
57    driver.moveCursor = NCURSES_MoveCursor;
58    driver.getCursorPosition = NCURSES_GetCursorPosition;
59    driver.getCharacterAtCursor = NCURSES_GetCharacterAtCursor;
60    driver.clearScreen = NCURSES_ClearScreen;
61    driver.allocColor = NCURSES_AllocColor;
62 #ifdef HAVE_GETBKGD
63    driver.setBackgroundColor = NCURSES_SetBackgroundColor;
64 #endif   
65 #ifdef HAVE_RESIZETERM
66    driver.notifyResizeScreen = NCURSES_NotifyResizeScreen;
67 #endif /* HAVE_RESIZETERM */
68
69    driver.checkForKeystroke = NCURSES_CheckForKeystroke;
70    driver.getKeystroke = NCURSES_GetKeystroke;
71
72    driver.refresh = NCURSES_Refresh; 
73 }
74
75 void NCURSES_Init()
76 {
77    char terminal_type[80];
78
79    PROFILE_GetWineIniString("console", "TerminalType",
80       "xterm", terminal_type, 79);
81
82    ncurses_screen = newterm(terminal_type, driver.console_out,
83       driver.console_in);
84    set_term(ncurses_screen);
85    start_color();
86    raw();
87    noecho();
88    nonl();
89    intrflush(stdscr, FALSE);
90    keypad(stdscr, TRUE);
91    nodelay(stdscr, TRUE);
92 }
93
94 void NCURSES_Write(char output, int fg, int bg, int attribute)
95 {
96    char row, col;
97    int pair;
98    
99    if (!fg)
100       fg = COLOR_WHITE; /* Default */
101
102    if (!bg)
103       bg = COLOR_BLACK; /* Default */
104
105    pair = get_color_pair(fg, bg);
106
107    if (waddch(stdscr, output | COLOR_PAIR(pair)) == ERR)
108    {
109       NCURSES_GetCursorPosition(&row, &col);
110       FIXME("NCURSES: waddch() failed at %d, %d.\n", row, col);
111    }
112 }
113
114 void NCURSES_Close()
115 {
116    endwin();
117 }
118
119 void NCURSES_GetKeystroke(char *scan, char *ascii)
120 {
121    while (!NCURSES_CheckForKeystroke(scan, ascii))
122    {} /* Wait until keystroke is detected */
123    
124    /* When it is detected, we will already have the right value 
125       in scan and ascii, but we need to take this keystroke
126       out of the buffer. */
127    wgetch(stdscr);
128 }
129
130 int NCURSES_CheckForKeystroke(char *scan, char *ascii)
131 {
132    /* We don't currently support scan codes here */
133    /* FIXME */
134    int temp;
135    temp = wgetch(stdscr);
136    if (temp == ERR)
137    {
138       return FALSE;
139    }
140    else
141    {
142       ungetch(temp);  /* Keystroke not removed from buffer */
143       *ascii = (char) temp;
144       return TRUE;
145    }
146 }
147
148 void NCURSES_MoveCursor(char row, char col)
149 {
150    if (wmove(stdscr, row, col) == ERR)
151       FIXME("NCURSES: wmove() failed to %d, %d.\n", row, col);
152 }
153
154 void NCURSES_GetCursorPosition(char *row, char *col)
155 {
156    int trow, tcol;
157
158    getyx(stdscr, trow, tcol); /* MACRO, no need to pass pointer */
159
160    *row = (char) trow;
161    *col = (char) tcol;
162 }
163
164 void NCURSES_GetCharacterAtCursor(char *ch, int *fg_color, int
165    *bg_color, int *attribute)
166 {
167    /* If any of the pointers are NULL, ignore them */
168    /* We will eventually have to convert the color data */
169    if (ch)
170       *ch = (char) winch(stdscr);
171    if (fg_color)
172       *fg_color = WINE_WHITE;
173    if (bg_color)
174       *bg_color = WINE_BLACK;
175    if (attribute)
176       *attribute = 0;
177 }
178
179 void NCURSES_Refresh()
180 {
181    wrefresh(stdscr);
182 }
183
184 void NCURSES_ClearScreen()
185 {
186    werase(stdscr);
187 }
188
189 int NCURSES_AllocColor(int color)
190 {
191    /* Currently support only internal colors */
192    switch (color)
193    {
194       case WINE_BLACK:          return COLOR_BLACK;
195       case WINE_WHITE:          return COLOR_WHITE;
196       case WINE_RED:            return COLOR_RED;
197       case WINE_GREEN:          return COLOR_GREEN;
198       case WINE_YELLOW:         return COLOR_YELLOW;
199       case WINE_BLUE:           return COLOR_BLUE;
200       case WINE_MAGENTA:        return COLOR_MAGENTA;
201       case WINE_CYAN:           return COLOR_CYAN;
202    }
203
204    FIXME("Unable to allocate color %d (%s)\n", color,
205       color_names[color]);
206
207    /* Don't allocate a color... yet */
208    return 0;
209 }
210
211 void NCURSES_SetBackgroundColor(int fg, int bg)
212 {
213    int pair;
214
215    pair = get_color_pair(fg, bg);
216
217    wbkgd(stdscr, COLOR_PAIR(pair));
218 }
219
220 #ifdef HAVE_GETBKGD
221 void NCURSES_GetBackgroundColor(int *fg, int *bg)
222 {
223    chtype background;
224    short pair, sfg, sbg;
225      
226    background = getbkgd(stdscr);
227
228    pair = (!A_CHARTEXT & background);
229    
230    pair_content(pair, &sfg, &sbg);
231
232    *fg = sfg;
233    *bg = sbg;
234 }
235 #endif /* HAVE_GETBKGD */
236
237 #ifdef HAVE_RESIZETERM
238
239 void NCURSES_NotifyResizeScreen(int x, int y)
240 {
241    /* Note: This function gets called *after* another driver in the chain
242       calls ResizeScreen(). It is meant to resize the ncurses internal
243       data structures to know about the new window dimensions. */
244  
245    TRACE("Terminal resized to y: %d, x: %d\n", y, x);
246
247    resizeterm(y, x);
248 }
249
250 #endif /* HAVE_RESIZETERM */
251
252 static int get_color_pair(int fg_color, int bg_color)
253 {
254    /* ncurses internally uses "color pairs" in addition to the "pallet" */
255    /* This isn't the best way to do this. Or even close */
256
257    static int current = 0;
258    static int fg[255];     /* 16 x 16 is enough */
259    static int bg[255];
260    int x;
261
262    /* The first pair is hardwired into ncurses */
263    fg[0] = COLOR_WHITE;
264    bg[0] = COLOR_BLACK;
265
266    for (x = 0; x <= current; x++)
267    {
268       if ((fg_color == fg[x]) && (bg_color == bg[x]))
269       {
270          TRACE("Color pair: already allocated\n");
271          return x;  
272       }    
273    }
274
275    /* Need to allocate new color */
276    current++;
277    fg[current] = fg_color;
278    bg[current] = bg_color;
279    TRACE("Color pair: allocated.\n");
280    return init_pair(current, fg_color, bg_color);
281 }
282
283 #endif /* WINE_NCURSES */