Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 366 lines (309 sloc) 10.021 kb
4d3b6f6 Add an ncurses UI.
balrog authored
1 /*
2 * QEMU curses/ncurses display driver
3 *
4 * Copyright (c) 2005 Andrzej Zaborowski <balrog@zabor.org>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 #include <curses.h>
25
26 #ifndef _WIN32
27 #include <signal.h>
28 #include <sys/ioctl.h>
29 #include <termios.h>
30 #endif
31
128ab2f Preliminary OpenBSD host support (based on OpenBSD patches by Todd T. Fr...
blueswir1 authored
32 #ifdef __OpenBSD__
33 #define resize_term resizeterm
34 #endif
35
511d2b1 Sparse fixes: NULL use, header order, ANSI prototypes, static
blueswir1 authored
36 #include "qemu-common.h"
37 #include "console.h"
38 #include "sysemu.h"
39
4d3b6f6 Add an ncurses UI.
balrog authored
40 #define FONT_HEIGHT 16
41 #define FONT_WIDTH 8
42
c227f09 Revert "Get rid of _t suffix"
Anthony Liguori authored
43 static console_ch_t screen[160 * 100];
4d3b6f6 Add an ncurses UI.
balrog authored
44 static WINDOW *screenpad = NULL;
45 static int width, height, gwidth, gheight, invalidate;
46 static int px, py, sminx, sminy, smaxx, smaxy;
47
48 static void curses_update(DisplayState *ds, int x, int y, int w, int h)
49 {
50 chtype *line;
51
52 line = ((chtype *) screen) + y * width;
53 for (h += y; y < h; y ++, line += width)
54 mvwaddchnstr(screenpad, y, 0, line, width);
55
56 pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1);
57 refresh();
58 }
59
60 static void curses_calc_pad(void)
61 {
c21bbcf Reintroduce TEXT_CONSOLE_FIXED_SIZE and TEXT_CONSOLE for resizable vc's.
balrog authored
62 if (is_fixedsize_console()) {
4d3b6f6 Add an ncurses UI.
balrog authored
63 width = gwidth;
64 height = gheight;
65 } else {
66 width = COLS;
67 height = LINES;
68 }
69
70 if (screenpad)
71 delwin(screenpad);
72
73 clear();
74 refresh();
75
76 screenpad = newpad(height, width);
77
78 if (width > COLS) {
79 px = (width - COLS) / 2;
80 sminx = 0;
81 smaxx = COLS;
82 } else {
83 px = 0;
84 sminx = (COLS - width) / 2;
85 smaxx = sminx + width;
86 }
87
88 if (height > LINES) {
89 py = (height - LINES) / 2;
90 sminy = 0;
91 smaxy = LINES;
92 } else {
93 py = 0;
94 sminy = (LINES - height) / 2;
95 smaxy = sminy + height;
96 }
97 }
98
7d957bd DisplayState interface change (Stefano Stabellini)
aliguori authored
99 static void curses_resize(DisplayState *ds)
4d3b6f6 Add an ncurses UI.
balrog authored
100 {
7d957bd DisplayState interface change (Stefano Stabellini)
aliguori authored
101 if (ds_get_width(ds) == gwidth && ds_get_height(ds) == gheight)
4d3b6f6 Add an ncurses UI.
balrog authored
102 return;
103
7d957bd DisplayState interface change (Stefano Stabellini)
aliguori authored
104 gwidth = ds_get_width(ds);
105 gheight = ds_get_height(ds);
4d3b6f6 Add an ncurses UI.
balrog authored
106
107 curses_calc_pad();
68f0099 fix curses interface (Stefano Stabellini)
aliguori authored
108 ds->surface->width = width * FONT_WIDTH;
109 ds->surface->height = height * FONT_HEIGHT;
4d3b6f6 Add an ncurses UI.
balrog authored
110 }
111
112 #ifndef _WIN32
b1314cf The non-ncurses curses doesn't have resize_term, so make resizing condit...
balrog authored
113 #if defined(SIGWINCH) && defined(KEY_RESIZE)
4d3b6f6 Add an ncurses UI.
balrog authored
114 static void curses_winch_handler(int signum)
115 {
116 struct winsize {
117 unsigned short ws_row;
118 unsigned short ws_col;
119 unsigned short ws_xpixel; /* unused */
120 unsigned short ws_ypixel; /* unused */
121 } ws;
122
123 /* terminal size changed */
124 if (ioctl(1, TIOCGWINSZ, &ws) == -1)
125 return;
126
127 resize_term(ws.ws_row, ws.ws_col);
128 curses_calc_pad();
129 invalidate = 1;
130
131 /* some systems require this */
132 signal(SIGWINCH, curses_winch_handler);
133 }
134 #endif
135 #endif
136
137 static void curses_cursor_position(DisplayState *ds, int x, int y)
138 {
139 if (x >= 0) {
140 x = sminx + x - px;
141 y = sminy + y - py;
142
143 if (x >= 0 && y >= 0 && x < COLS && y < LINES) {
144 move(y, x);
145 curs_set(1);
146 /* it seems that curs_set(1) must always be called before
147 * curs_set(2) for the latter to have effect */
148 if (!is_graphic_console())
149 curs_set(2);
150 return;
151 }
152 }
153
154 curs_set(0);
155 }
156
157 /* generic keyboard conversion */
158
159 #include "curses_keys.h"
160
c227f09 Revert "Get rid of _t suffix"
Anthony Liguori authored
161 static kbd_layout_t *kbd_layout = NULL;
4d3b6f6 Add an ncurses UI.
balrog authored
162
163 static void curses_refresh(DisplayState *ds)
164 {
44bb61c Fix curses interaction with keymaps
Samuel Thibault authored
165 int chr, nextchr, keysym, keycode, keycode_alt;
4d3b6f6 Add an ncurses UI.
balrog authored
166
167 if (invalidate) {
168 clear();
169 refresh();
170 curses_calc_pad();
7d957bd DisplayState interface change (Stefano Stabellini)
aliguori authored
171 ds->surface->width = FONT_WIDTH * width;
172 ds->surface->height = FONT_HEIGHT * height;
4d3b6f6 Add an ncurses UI.
balrog authored
173 vga_hw_invalidate();
174 invalidate = 0;
175 }
176
177 vga_hw_text_update(screen);
178
179 nextchr = ERR;
180 while (1) {
181 /* while there are any pending key strokes to process */
182 if (nextchr == ERR)
183 chr = getch();
184 else {
185 chr = nextchr;
186 nextchr = ERR;
187 }
188
189 if (chr == ERR)
190 break;
191
b1314cf The non-ncurses curses doesn't have resize_term, so make resizing condit...
balrog authored
192 #ifdef KEY_RESIZE
4d3b6f6 Add an ncurses UI.
balrog authored
193 /* this shouldn't occur when we use a custom SIGWINCH handler */
194 if (chr == KEY_RESIZE) {
195 clear();
196 refresh();
197 curses_calc_pad();
198 curses_update(ds, 0, 0, width, height);
7d957bd DisplayState interface change (Stefano Stabellini)
aliguori authored
199 ds->surface->width = FONT_WIDTH * width;
200 ds->surface->height = FONT_HEIGHT * height;
4d3b6f6 Add an ncurses UI.
balrog authored
201 continue;
202 }
b1314cf The non-ncurses curses doesn't have resize_term, so make resizing condit...
balrog authored
203 #endif
4d3b6f6 Add an ncurses UI.
balrog authored
204
205 keycode = curses2keycode[chr];
44bb61c Fix curses interaction with keymaps
Samuel Thibault authored
206 keycode_alt = 0;
4d3b6f6 Add an ncurses UI.
balrog authored
207
208 /* alt key */
209 if (keycode == 1) {
210 nextchr = getch();
211
212 if (nextchr != ERR) {
44bb61c Fix curses interaction with keymaps
Samuel Thibault authored
213 chr = nextchr;
214 keycode_alt = ALT;
4d3b6f6 Add an ncurses UI.
balrog authored
215 keycode = curses2keycode[nextchr];
216 nextchr = ERR;
217
44bb61c Fix curses interaction with keymaps
Samuel Thibault authored
218 if (keycode != -1) {
219 keycode |= ALT;
4d3b6f6 Add an ncurses UI.
balrog authored
220
44bb61c Fix curses interaction with keymaps
Samuel Thibault authored
221 /* process keys reserved for qemu */
222 if (keycode >= QEMU_KEY_CONSOLE0 &&
223 keycode < QEMU_KEY_CONSOLE0 + 9) {
224 erase();
225 wnoutrefresh(stdscr);
226 console_select(keycode - QEMU_KEY_CONSOLE0);
4d3b6f6 Add an ncurses UI.
balrog authored
227
44bb61c Fix curses interaction with keymaps
Samuel Thibault authored
228 invalidate = 1;
229 continue;
230 }
4d3b6f6 Add an ncurses UI.
balrog authored
231 }
232 }
233 }
234
44bb61c Fix curses interaction with keymaps
Samuel Thibault authored
235 if (kbd_layout) {
236 keysym = -1;
237 if (chr < CURSES_KEYS)
238 keysym = curses2keysym[chr];
239
240 if (keysym == -1) {
241 if (chr < ' ')
242 keysym = (chr + '@' - 'A' + 'a') | KEYSYM_CNTRL;
243 else
244 keysym = chr;
245 }
4d3b6f6 Add an ncurses UI.
balrog authored
246
44bb61c Fix curses interaction with keymaps
Samuel Thibault authored
247 keycode = keysym2scancode(kbd_layout, keysym & KEYSYM_MASK);
248 if (keycode == 0)
249 continue;
250
251 keycode |= (keysym & ~KEYSYM_MASK) >> 16;
252 keycode |= keycode_alt;
4d3b6f6 Add an ncurses UI.
balrog authored
253 }
254
44bb61c Fix curses interaction with keymaps
Samuel Thibault authored
255 if (keycode == -1)
256 continue;
257
4d3b6f6 Add an ncurses UI.
balrog authored
258 if (is_graphic_console()) {
259 /* since terminals don't know about key press and release
260 * events, we need to emit both for each key received */
261 if (keycode & SHIFT)
262 kbd_put_keycode(SHIFT_CODE);
263 if (keycode & CNTRL)
264 kbd_put_keycode(CNTRL_CODE);
265 if (keycode & ALT)
266 kbd_put_keycode(ALT_CODE);
44bb61c Fix curses interaction with keymaps
Samuel Thibault authored
267 if (keycode & ALTGR) {
268 kbd_put_keycode(SCANCODE_EMUL0);
269 kbd_put_keycode(ALT_CODE);
270 }
4d3b6f6 Add an ncurses UI.
balrog authored
271 if (keycode & GREY)
272 kbd_put_keycode(GREY_CODE);
273 kbd_put_keycode(keycode & KEY_MASK);
274 if (keycode & GREY)
275 kbd_put_keycode(GREY_CODE);
276 kbd_put_keycode((keycode & KEY_MASK) | KEY_RELEASE);
44bb61c Fix curses interaction with keymaps
Samuel Thibault authored
277 if (keycode & ALTGR) {
278 kbd_put_keycode(SCANCODE_EMUL0);
279 kbd_put_keycode(ALT_CODE | KEY_RELEASE);
280 }
4d3b6f6 Add an ncurses UI.
balrog authored
281 if (keycode & ALT)
282 kbd_put_keycode(ALT_CODE | KEY_RELEASE);
283 if (keycode & CNTRL)
284 kbd_put_keycode(CNTRL_CODE | KEY_RELEASE);
285 if (keycode & SHIFT)
286 kbd_put_keycode(SHIFT_CODE | KEY_RELEASE);
287 } else {
44bb61c Fix curses interaction with keymaps
Samuel Thibault authored
288 keysym = curses2qemu[chr];
4d3b6f6 Add an ncurses UI.
balrog authored
289 if (keysym == -1)
290 keysym = chr;
291
292 kbd_put_keysym(keysym);
293 }
294 }
295 }
296
aaf12c2 @blueswirl Revert 'Fix build'
blueswirl authored
297 static void curses_atexit(void)
4d3b6f6 Add an ncurses UI.
balrog authored
298 {
299 endwin();
300 }
301
302 static void curses_setup(void)
303 {
304 int i, colour_default[8] = {
305 COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN,
306 COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE,
307 };
308
309 /* input as raw as possible, let everything be interpreted
310 * by the guest system */
311 initscr(); noecho(); intrflush(stdscr, FALSE);
312 nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE);
313 start_color(); raw(); scrollok(stdscr, FALSE);
314
315 for (i = 0; i < 64; i ++)
316 init_pair(i, colour_default[i & 7], colour_default[i >> 3]);
317 }
318
319 static void curses_keyboard_setup(void)
320 {
321 #if defined(__APPLE__)
322 /* always use generic keymaps */
323 if (!keyboard_layout)
324 keyboard_layout = "en-us";
325 #endif
326 if(keyboard_layout) {
0483755 Refactor keymap code to avoid duplication ("Daniel P. Berrange")
aliguori authored
327 kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
4d3b6f6 Add an ncurses UI.
balrog authored
328 if (!kbd_layout)
329 exit(1);
330 }
331 }
332
333 void curses_display_init(DisplayState *ds, int full_screen)
334 {
7d957bd DisplayState interface change (Stefano Stabellini)
aliguori authored
335 DisplayChangeListener *dcl;
4d3b6f6 Add an ncurses UI.
balrog authored
336 #ifndef _WIN32
337 if (!isatty(1)) {
338 fprintf(stderr, "We need a terminal output\n");
339 exit(1);
340 }
341 #endif
342
343 curses_setup();
344 curses_keyboard_setup();
2869548 Revert "Convert atexit users to exit_notifier"
Anthony Liguori authored
345 atexit(curses_atexit);
4d3b6f6 Add an ncurses UI.
balrog authored
346
347 #ifndef _WIN32
b1314cf The non-ncurses curses doesn't have resize_term, so make resizing condit...
balrog authored
348 #if defined(SIGWINCH) && defined(KEY_RESIZE)
4d3b6f6 Add an ncurses UI.
balrog authored
349 /* some curses implementations provide a handler, but we
350 * want to be sure this is handled regardless of the library */
351 signal(SIGWINCH, curses_winch_handler);
352 #endif
353 #endif
354
7d957bd DisplayState interface change (Stefano Stabellini)
aliguori authored
355 dcl = (DisplayChangeListener *) qemu_mallocz(sizeof(DisplayChangeListener));
356 dcl->dpy_update = curses_update;
357 dcl->dpy_resize = curses_resize;
358 dcl->dpy_refresh = curses_refresh;
359 dcl->dpy_text_cursor = curses_cursor_position;
360 register_displaychangelistener(ds, dcl);
7b5d76d DisplayAllocator interface (Stefano Stabellini)
aliguori authored
361 qemu_free_displaysurface(ds);
68f0099 fix curses interface (Stefano Stabellini)
aliguori authored
362 ds->surface = qemu_create_displaysurface_from(640, 400, 0, 0, (uint8_t*) screen);
4d3b6f6 Add an ncurses UI.
balrog authored
363
364 invalidate = 1;
365 }
Something went wrong with that request. Please try again.