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