]> git.proxmox.com Git - mirror_qemu.git/blame - ui/curses.c
block/export: Conditionally ignore set-context error
[mirror_qemu.git] / ui / curses.c
CommitLineData
4d3b6f6e
AZ
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 */
0b8fa32f 24
e16f4c87 25#include "qemu/osdep.h"
4d3b6f6e
AZ
26
27#ifndef _WIN32
4d3b6f6e
AZ
28#include <sys/ioctl.h>
29#include <termios.h>
30#endif
2f8b7cd5
ST
31#include <locale.h>
32#include <wchar.h>
2f8b7cd5 33#include <iconv.h>
4d3b6f6e 34
ab4f931e 35#include "qapi/error.h"
0b8fa32f 36#include "qemu/module.h"
28ecbaee 37#include "ui/console.h"
cd100328 38#include "ui/input.h"
9c17d615 39#include "sysemu/sysemu.h"
511d2b14 40
e2f82e92
GH
41/* KEY_EVENT is defined in wincon.h and in curses.h. Avoid redefinition. */
42#undef KEY_EVENT
43#include <curses.h>
44#undef KEY_EVENT
45
4d3b6f6e
AZ
46#define FONT_HEIGHT 16
47#define FONT_WIDTH 8
48
459a707e
ST
49enum maybe_keycode {
50 CURSES_KEYCODE,
51 CURSES_CHAR,
52 CURSES_CHAR_OR_KEYCODE,
53};
54
7c20b4a3 55static DisplayChangeListener *dcl;
76c51fc3 56static console_ch_t *screen;
4d3b6f6e
AZ
57static WINDOW *screenpad = NULL;
58static int width, height, gwidth, gheight, invalidate;
59static int px, py, sminx, sminy, smaxx, smaxy;
60
2f8b7cd5 61static const char *font_charset = "CP437";
76c51fc3 62static cchar_t *vga_to_curses;
e2368dc9 63
7c20b4a3 64static void curses_update(DisplayChangeListener *dcl,
7c20b4a3 65 int x, int y, int w, int h)
4d3b6f6e 66{
e2f82e92 67 console_ch_t *line;
2f8b7cd5 68 cchar_t curses_line[width];
962cf8fd
ST
69 wchar_t wch[CCHARW_MAX];
70 attr_t attrs;
71 short colors;
72 int ret;
4d3b6f6e 73
e2f82e92
GH
74 line = screen + y * width;
75 for (h += y; y < h; y ++, line += width) {
76 for (x = 0; x < width; x++) {
cd54ea45
MK
77 chtype ch = line[x] & A_CHARTEXT;
78 chtype at = line[x] & A_ATTRIBUTES;
30f5a9dd
MK
79 short color_pair = PAIR_NUMBER(line[x]);
80
962cf8fd
ST
81 ret = getcchar(&vga_to_curses[ch], wch, &attrs, &colors, NULL);
82 if (ret == ERR || wch[0] == 0) {
83 wch[0] = ch;
84 wch[1] = 0;
e2f82e92 85 }
30f5a9dd 86 setcchar(&curses_line[x], wch, at, color_pair, NULL);
e2f82e92 87 }
2f8b7cd5 88 mvwadd_wchnstr(screenpad, y, 0, curses_line, width);
e2f82e92 89 }
4d3b6f6e
AZ
90
91 pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1);
92 refresh();
93}
94
95static void curses_calc_pad(void)
96{
81c0d5a6 97 if (qemu_console_is_fixedsize(NULL)) {
4d3b6f6e
AZ
98 width = gwidth;
99 height = gheight;
100 } else {
101 width = COLS;
102 height = LINES;
103 }
104
105 if (screenpad)
106 delwin(screenpad);
107
108 clear();
109 refresh();
110
111 screenpad = newpad(height, width);
112
113 if (width > COLS) {
114 px = (width - COLS) / 2;
115 sminx = 0;
116 smaxx = COLS;
117 } else {
118 px = 0;
119 sminx = (COLS - width) / 2;
120 smaxx = sminx + width;
121 }
122
123 if (height > LINES) {
124 py = (height - LINES) / 2;
125 sminy = 0;
126 smaxy = LINES;
127 } else {
128 py = 0;
129 sminy = (LINES - height) / 2;
130 smaxy = sminy + height;
131 }
132}
133
7c20b4a3 134static void curses_resize(DisplayChangeListener *dcl,
7c20b4a3 135 int width, int height)
4d3b6f6e 136{
a93a4a22 137 if (width == gwidth && height == gheight) {
4d3b6f6e 138 return;
a93a4a22 139 }
4d3b6f6e 140
a93a4a22
GH
141 gwidth = width;
142 gheight = height;
4d3b6f6e
AZ
143
144 curses_calc_pad();
145}
146
032ac6f8
GH
147#if !defined(_WIN32) && defined(SIGWINCH) && defined(KEY_RESIZE)
148static volatile sig_atomic_t got_sigwinch;
149static void curses_winch_check(void)
4d3b6f6e
AZ
150{
151 struct winsize {
152 unsigned short ws_row;
153 unsigned short ws_col;
154 unsigned short ws_xpixel; /* unused */
155 unsigned short ws_ypixel; /* unused */
156 } ws;
157
032ac6f8
GH
158 if (!got_sigwinch) {
159 return;
160 }
161 got_sigwinch = false;
162
163 if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
4d3b6f6e 164 return;
032ac6f8 165 }
4d3b6f6e
AZ
166
167 resize_term(ws.ws_row, ws.ws_col);
4d3b6f6e 168 invalidate = 1;
032ac6f8 169}
4d3b6f6e 170
032ac6f8
GH
171static void curses_winch_handler(int signum)
172{
173 got_sigwinch = true;
4d3b6f6e 174}
032ac6f8
GH
175
176static void curses_winch_init(void)
177{
178 struct sigaction old, winch = {
179 .sa_handler = curses_winch_handler,
180 };
181 sigaction(SIGWINCH, &winch, &old);
182}
183#else
184static void curses_winch_check(void) {}
185static void curses_winch_init(void) {}
4d3b6f6e
AZ
186#endif
187
7c20b4a3 188static void curses_cursor_position(DisplayChangeListener *dcl,
7c20b4a3 189 int x, int y)
4d3b6f6e
AZ
190{
191 if (x >= 0) {
192 x = sminx + x - px;
193 y = sminy + y - py;
194
195 if (x >= 0 && y >= 0 && x < COLS && y < LINES) {
196 move(y, x);
197 curs_set(1);
198 /* it seems that curs_set(1) must always be called before
199 * curs_set(2) for the latter to have effect */
81c0d5a6 200 if (!qemu_console_is_graphic(NULL)) {
4d3b6f6e 201 curs_set(2);
81c0d5a6 202 }
4d3b6f6e
AZ
203 return;
204 }
205 }
206
207 curs_set(0);
208}
209
210/* generic keyboard conversion */
211
212#include "curses_keys.h"
4d3b6f6e 213
c227f099 214static kbd_layout_t *kbd_layout = NULL;
4d3b6f6e 215
459a707e
ST
216static wint_t console_getch(enum maybe_keycode *maybe_keycode)
217{
218 wint_t ret;
219 switch (get_wch(&ret)) {
220 case KEY_CODE_YES:
221 *maybe_keycode = CURSES_KEYCODE;
222 break;
223 case OK:
224 *maybe_keycode = CURSES_CHAR;
225 break;
226 case ERR:
227 ret = -1;
228 break;
68097ed5
PB
229 default:
230 abort();
459a707e
ST
231 }
232 return ret;
233}
234
235static int curses2foo(const int _curses2foo[], const int _curseskey2foo[],
236 int chr, enum maybe_keycode maybe_keycode)
237{
238 int ret = -1;
239 if (maybe_keycode == CURSES_CHAR) {
240 if (chr < CURSES_CHARS) {
241 ret = _curses2foo[chr];
242 }
243 } else {
244 if (chr < CURSES_KEYS) {
245 ret = _curseskey2foo[chr];
246 }
247 if (ret == -1 && maybe_keycode == CURSES_CHAR_OR_KEYCODE &&
248 chr < CURSES_CHARS) {
249 ret = _curses2foo[chr];
250 }
251 }
252 return ret;
253}
254
255#define curses2keycode(chr, maybe_keycode) \
256 curses2foo(_curses2keycode, _curseskey2keycode, chr, maybe_keycode)
257#define curses2keysym(chr, maybe_keycode) \
258 curses2foo(_curses2keysym, _curseskey2keysym, chr, maybe_keycode)
259#define curses2qemu(chr, maybe_keycode) \
260 curses2foo(_curses2qemu, _curseskey2qemu, chr, maybe_keycode)
261
bc2ed970 262static void curses_refresh(DisplayChangeListener *dcl)
4d3b6f6e 263{
99a9ef44 264 int chr, keysym, keycode, keycode_alt;
65f52797 265 enum maybe_keycode maybe_keycode = CURSES_KEYCODE;
4d3b6f6e 266
032ac6f8
GH
267 curses_winch_check();
268
4d3b6f6e
AZ
269 if (invalidate) {
270 clear();
271 refresh();
272 curses_calc_pad();
1dbfa005 273 graphic_hw_invalidate(NULL);
4d3b6f6e
AZ
274 invalidate = 0;
275 }
276
1dbfa005 277 graphic_hw_text_update(NULL, screen);
4d3b6f6e 278
4d3b6f6e
AZ
279 while (1) {
280 /* while there are any pending key strokes to process */
459a707e 281 chr = console_getch(&maybe_keycode);
4d3b6f6e 282
459a707e 283 if (chr == -1)
4d3b6f6e
AZ
284 break;
285
b1314cf9 286#ifdef KEY_RESIZE
4d3b6f6e 287 /* this shouldn't occur when we use a custom SIGWINCH handler */
459a707e 288 if (maybe_keycode != CURSES_CHAR && chr == KEY_RESIZE) {
4d3b6f6e
AZ
289 clear();
290 refresh();
291 curses_calc_pad();
bc2ed970 292 curses_update(dcl, 0, 0, width, height);
4d3b6f6e
AZ
293 continue;
294 }
b1314cf9 295#endif
4d3b6f6e 296
459a707e 297 keycode = curses2keycode(chr, maybe_keycode);
44bb61c8 298 keycode_alt = 0;
4d3b6f6e 299
633786fe 300 /* alt or esc key */
4d3b6f6e 301 if (keycode == 1) {
65f52797 302 enum maybe_keycode next_maybe_keycode = CURSES_KEYCODE;
459a707e 303 int nextchr = console_getch(&next_maybe_keycode);
4d3b6f6e 304
459a707e 305 if (nextchr != -1) {
44bb61c8 306 chr = nextchr;
459a707e 307 maybe_keycode = next_maybe_keycode;
44bb61c8 308 keycode_alt = ALT;
459a707e 309 keycode = curses2keycode(chr, maybe_keycode);
4d3b6f6e 310
44bb61c8
ST
311 if (keycode != -1) {
312 keycode |= ALT;
4d3b6f6e 313
44bb61c8
ST
314 /* process keys reserved for qemu */
315 if (keycode >= QEMU_KEY_CONSOLE0 &&
316 keycode < QEMU_KEY_CONSOLE0 + 9) {
317 erase();
318 wnoutrefresh(stdscr);
319 console_select(keycode - QEMU_KEY_CONSOLE0);
4d3b6f6e 320
44bb61c8
ST
321 invalidate = 1;
322 continue;
323 }
4d3b6f6e
AZ
324 }
325 }
326 }
327
44bb61c8 328 if (kbd_layout) {
459a707e 329 keysym = curses2keysym(chr, maybe_keycode);
44bb61c8
ST
330
331 if (keysym == -1) {
d03703c8
ST
332 if (chr < ' ') {
333 keysym = chr + '@';
334 if (keysym >= 'A' && keysym <= 'Z')
335 keysym += 'a' - 'A';
336 keysym |= KEYSYM_CNTRL;
337 } else
44bb61c8
ST
338 keysym = chr;
339 }
4d3b6f6e 340
abb4f2c9 341 keycode = keysym2scancode(kbd_layout, keysym & KEYSYM_MASK,
19c1b9fd 342 NULL, false);
44bb61c8
ST
343 if (keycode == 0)
344 continue;
345
346 keycode |= (keysym & ~KEYSYM_MASK) >> 16;
347 keycode |= keycode_alt;
4d3b6f6e
AZ
348 }
349
44bb61c8
ST
350 if (keycode == -1)
351 continue;
352
81c0d5a6 353 if (qemu_console_is_graphic(NULL)) {
4d3b6f6e
AZ
354 /* since terminals don't know about key press and release
355 * events, we need to emit both for each key received */
cd100328
GH
356 if (keycode & SHIFT) {
357 qemu_input_event_send_key_number(NULL, SHIFT_CODE, true);
5a165668 358 qemu_input_event_send_key_delay(0);
cd100328
GH
359 }
360 if (keycode & CNTRL) {
361 qemu_input_event_send_key_number(NULL, CNTRL_CODE, true);
5a165668 362 qemu_input_event_send_key_delay(0);
cd100328
GH
363 }
364 if (keycode & ALT) {
365 qemu_input_event_send_key_number(NULL, ALT_CODE, true);
5a165668 366 qemu_input_event_send_key_delay(0);
cd100328 367 }
44bb61c8 368 if (keycode & ALTGR) {
cd100328 369 qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, true);
5a165668 370 qemu_input_event_send_key_delay(0);
44bb61c8 371 }
cd100328 372
f5c0ab13 373 qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, true);
5a165668 374 qemu_input_event_send_key_delay(0);
f5c0ab13 375 qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, false);
5a165668 376 qemu_input_event_send_key_delay(0);
cd100328 377
44bb61c8 378 if (keycode & ALTGR) {
cd100328 379 qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, false);
5a165668 380 qemu_input_event_send_key_delay(0);
cd100328
GH
381 }
382 if (keycode & ALT) {
383 qemu_input_event_send_key_number(NULL, ALT_CODE, false);
5a165668 384 qemu_input_event_send_key_delay(0);
cd100328
GH
385 }
386 if (keycode & CNTRL) {
387 qemu_input_event_send_key_number(NULL, CNTRL_CODE, false);
5a165668 388 qemu_input_event_send_key_delay(0);
cd100328
GH
389 }
390 if (keycode & SHIFT) {
391 qemu_input_event_send_key_number(NULL, SHIFT_CODE, false);
5a165668 392 qemu_input_event_send_key_delay(0);
44bb61c8 393 }
4d3b6f6e 394 } else {
459a707e 395 keysym = curses2qemu(chr, maybe_keycode);
4d3b6f6e
AZ
396 if (keysym == -1)
397 keysym = chr;
398
399 kbd_put_keysym(keysym);
400 }
401 }
402}
403
aaf12c25 404static void curses_atexit(void)
4d3b6f6e
AZ
405{
406 endwin();
76c51fc3
PMD
407 g_free(vga_to_curses);
408 g_free(screen);
4d3b6f6e
AZ
409}
410
b7b664a4
ST
411/*
412 * In the following:
413 * - fch is the font glyph number
414 * - uch is the unicode value
415 * - wch is the wchar_t value (may not be unicode, e.g. on BSD/solaris)
416 * - mbch is the native local-dependent multibyte representation
417 */
418
2f8b7cd5 419/* Setup wchar glyph for one UCS-2 char */
b7b664a4 420static void convert_ucs(unsigned char fch, uint16_t uch, iconv_t conv)
2f8b7cd5 421{
b7b664a4 422 char mbch[MB_LEN_MAX];
962cf8fd 423 wchar_t wch[2];
b7b664a4
ST
424 char *puch, *pmbch;
425 size_t such, smbch;
426 mbstate_t ps;
427
428 puch = (char *) &uch;
429 pmbch = (char *) mbch;
430 such = sizeof(uch);
431 smbch = sizeof(mbch);
432
433 if (iconv(conv, &puch, &such, &pmbch, &smbch) == (size_t) -1) {
434 fprintf(stderr, "Could not convert 0x%04x "
435 "from UCS-2 to a multibyte character: %s\n",
436 uch, strerror(errno));
437 return;
438 }
2f8b7cd5 439
b7b664a4 440 memset(&ps, 0, sizeof(ps));
962cf8fd 441 if (mbrtowc(&wch[0], mbch, sizeof(mbch) - smbch, &ps) == -1) {
b7b664a4
ST
442 fprintf(stderr, "Could not convert 0x%04x "
443 "from a multibyte character to wchar_t: %s\n",
444 uch, strerror(errno));
445 return;
2f8b7cd5 446 }
962cf8fd
ST
447
448 wch[1] = 0;
449 setcchar(&vga_to_curses[fch], wch, 0, 0, NULL);
2f8b7cd5
ST
450}
451
452/* Setup wchar glyph for one font character */
b7b664a4 453static void convert_font(unsigned char fch, iconv_t conv)
2f8b7cd5 454{
b7b664a4 455 char mbch[MB_LEN_MAX];
962cf8fd 456 wchar_t wch[2];
b7b664a4
ST
457 char *pfch, *pmbch;
458 size_t sfch, smbch;
459 mbstate_t ps;
460
461 pfch = (char *) &fch;
462 pmbch = (char *) &mbch;
463 sfch = sizeof(fch);
464 smbch = sizeof(mbch);
465
466 if (iconv(conv, &pfch, &sfch, &pmbch, &smbch) == (size_t) -1) {
467 fprintf(stderr, "Could not convert font glyph 0x%02x "
468 "from %s to a multibyte character: %s\n",
469 fch, font_charset, strerror(errno));
470 return;
471 }
2f8b7cd5 472
b7b664a4 473 memset(&ps, 0, sizeof(ps));
962cf8fd 474 if (mbrtowc(&wch[0], mbch, sizeof(mbch) - smbch, &ps) == -1) {
b7b664a4
ST
475 fprintf(stderr, "Could not convert font glyph 0x%02x "
476 "from a multibyte character to wchar_t: %s\n",
477 fch, strerror(errno));
478 return;
2f8b7cd5 479 }
962cf8fd
ST
480
481 wch[1] = 0;
482 setcchar(&vga_to_curses[fch], wch, 0, 0, NULL);
2f8b7cd5
ST
483}
484
485/* Convert one wchar to UCS-2 */
486static uint16_t get_ucs(wchar_t wch, iconv_t conv)
487{
b7b664a4
ST
488 char mbch[MB_LEN_MAX];
489 uint16_t uch;
490 char *pmbch, *puch;
491 size_t smbch, such;
492 mbstate_t ps;
493 int ret;
494
495 memset(&ps, 0, sizeof(ps));
496 ret = wcrtomb(mbch, wch, &ps);
497 if (ret == -1) {
dc3c871a 498 fprintf(stderr, "Could not convert 0x%04lx "
b7b664a4 499 "from wchar_t to a multibyte character: %s\n",
dc3c871a 500 (unsigned long)wch, strerror(errno));
b7b664a4
ST
501 return 0xFFFD;
502 }
503
504 pmbch = (char *) mbch;
505 puch = (char *) &uch;
506 smbch = ret;
507 such = sizeof(uch);
508
509 if (iconv(conv, &pmbch, &smbch, &puch, &such) == (size_t) -1) {
dc3c871a 510 fprintf(stderr, "Could not convert 0x%04lx "
b7b664a4 511 "from a multibyte character to UCS-2 : %s\n",
dc3c871a 512 (unsigned long)wch, strerror(errno));
2f8b7cd5
ST
513 return 0xFFFD;
514 }
515
b7b664a4 516 return uch;
2f8b7cd5
ST
517}
518
519/*
520 * Setup mapping for vga to curses line graphics.
521 */
522static void font_setup(void)
523{
b7b664a4
ST
524 iconv_t ucs2_to_nativecharset;
525 iconv_t nativecharset_to_ucs2;
526 iconv_t font_conv;
527 int i;
80d3ab61 528 g_autofree gchar *local_codeset = g_get_codeset();
b7b664a4 529
2f8b7cd5
ST
530 /*
531 * Control characters are normally non-printable, but VGA does have
532 * well-known glyphs for them.
533 */
80e8c2ed 534 static const uint16_t control_characters[0x20] = {
2f8b7cd5
ST
535 0x0020,
536 0x263a,
537 0x263b,
538 0x2665,
539 0x2666,
540 0x2663,
541 0x2660,
542 0x2022,
543 0x25d8,
544 0x25cb,
545 0x25d9,
546 0x2642,
547 0x2640,
548 0x266a,
549 0x266b,
550 0x263c,
551 0x25ba,
552 0x25c4,
553 0x2195,
554 0x203c,
555 0x00b6,
556 0x00a7,
557 0x25ac,
558 0x21a8,
559 0x2191,
560 0x2193,
561 0x2192,
562 0x2190,
563 0x221f,
564 0x2194,
565 0x25b2,
566 0x25bc
567 };
568
80d3ab61 569 ucs2_to_nativecharset = iconv_open(local_codeset, "UCS-2");
b7b664a4 570 if (ucs2_to_nativecharset == (iconv_t) -1) {
2f8b7cd5
ST
571 fprintf(stderr, "Could not convert font glyphs from UCS-2: '%s'\n",
572 strerror(errno));
573 exit(1);
574 }
575
80d3ab61 576 nativecharset_to_ucs2 = iconv_open("UCS-2", local_codeset);
b7b664a4
ST
577 if (nativecharset_to_ucs2 == (iconv_t) -1) {
578 iconv_close(ucs2_to_nativecharset);
2f8b7cd5
ST
579 fprintf(stderr, "Could not convert font glyphs to UCS-2: '%s'\n",
580 strerror(errno));
581 exit(1);
582 }
583
80d3ab61 584 font_conv = iconv_open(local_codeset, font_charset);
2f8b7cd5 585 if (font_conv == (iconv_t) -1) {
b7b664a4
ST
586 iconv_close(ucs2_to_nativecharset);
587 iconv_close(nativecharset_to_ucs2);
2f8b7cd5
ST
588 fprintf(stderr, "Could not convert font glyphs from %s: '%s'\n",
589 font_charset, strerror(errno));
590 exit(1);
591 }
592
593 /* Control characters */
594 for (i = 0; i <= 0x1F; i++) {
b7b664a4 595 convert_ucs(i, control_characters[i], ucs2_to_nativecharset);
2f8b7cd5
ST
596 }
597
598 for (i = 0x20; i <= 0xFF; i++) {
599 convert_font(i, font_conv);
600 }
601
602 /* DEL */
b7b664a4 603 convert_ucs(0x7F, 0x2302, ucs2_to_nativecharset);
2f8b7cd5 604
80d3ab61 605 if (strcmp(local_codeset, "UTF-8")) {
2f8b7cd5
ST
606 /* Non-Unicode capable, use termcap equivalents for those available */
607 for (i = 0; i <= 0xFF; i++) {
962cf8fd
ST
608 wchar_t wch[CCHARW_MAX];
609 attr_t attr;
610 short color;
611 int ret;
612
613 ret = getcchar(&vga_to_curses[i], wch, &attr, &color, NULL);
614 if (ret == ERR)
615 continue;
616
617 switch (get_ucs(wch[0], nativecharset_to_ucs2)) {
2f8b7cd5
ST
618 case 0x00a3:
619 vga_to_curses[i] = *WACS_STERLING;
620 break;
621 case 0x2591:
622 vga_to_curses[i] = *WACS_BOARD;
623 break;
624 case 0x2592:
625 vga_to_curses[i] = *WACS_CKBOARD;
626 break;
627 case 0x2502:
628 vga_to_curses[i] = *WACS_VLINE;
629 break;
630 case 0x2524:
631 vga_to_curses[i] = *WACS_RTEE;
632 break;
633 case 0x2510:
634 vga_to_curses[i] = *WACS_URCORNER;
635 break;
636 case 0x2514:
637 vga_to_curses[i] = *WACS_LLCORNER;
638 break;
639 case 0x2534:
640 vga_to_curses[i] = *WACS_BTEE;
641 break;
642 case 0x252c:
643 vga_to_curses[i] = *WACS_TTEE;
644 break;
645 case 0x251c:
646 vga_to_curses[i] = *WACS_LTEE;
647 break;
648 case 0x2500:
649 vga_to_curses[i] = *WACS_HLINE;
650 break;
651 case 0x253c:
652 vga_to_curses[i] = *WACS_PLUS;
653 break;
654 case 0x256c:
655 vga_to_curses[i] = *WACS_LANTERN;
656 break;
657 case 0x256a:
658 vga_to_curses[i] = *WACS_NEQUAL;
659 break;
660 case 0x2518:
661 vga_to_curses[i] = *WACS_LRCORNER;
662 break;
663 case 0x250c:
664 vga_to_curses[i] = *WACS_ULCORNER;
665 break;
666 case 0x2588:
667 vga_to_curses[i] = *WACS_BLOCK;
668 break;
669 case 0x03c0:
670 vga_to_curses[i] = *WACS_PI;
671 break;
672 case 0x00b1:
673 vga_to_curses[i] = *WACS_PLMINUS;
674 break;
675 case 0x2265:
676 vga_to_curses[i] = *WACS_GEQUAL;
677 break;
678 case 0x2264:
679 vga_to_curses[i] = *WACS_LEQUAL;
680 break;
681 case 0x00b0:
682 vga_to_curses[i] = *WACS_DEGREE;
683 break;
684 case 0x25a0:
685 vga_to_curses[i] = *WACS_BULLET;
686 break;
687 case 0x2666:
688 vga_to_curses[i] = *WACS_DIAMOND;
689 break;
690 case 0x2192:
691 vga_to_curses[i] = *WACS_RARROW;
692 break;
693 case 0x2190:
694 vga_to_curses[i] = *WACS_LARROW;
695 break;
696 case 0x2191:
697 vga_to_curses[i] = *WACS_UARROW;
698 break;
699 case 0x2193:
700 vga_to_curses[i] = *WACS_DARROW;
701 break;
702 case 0x23ba:
703 vga_to_curses[i] = *WACS_S1;
704 break;
705 case 0x23bb:
706 vga_to_curses[i] = *WACS_S3;
707 break;
708 case 0x23bc:
709 vga_to_curses[i] = *WACS_S7;
710 break;
711 case 0x23bd:
712 vga_to_curses[i] = *WACS_S9;
713 break;
714 }
715 }
716 }
b7b664a4
ST
717 iconv_close(ucs2_to_nativecharset);
718 iconv_close(nativecharset_to_ucs2);
a9fda247 719 iconv_close(font_conv);
2f8b7cd5
ST
720}
721
4d3b6f6e
AZ
722static void curses_setup(void)
723{
724 int i, colour_default[8] = {
4083733d
OH
725 [QEMU_COLOR_BLACK] = COLOR_BLACK,
726 [QEMU_COLOR_BLUE] = COLOR_BLUE,
727 [QEMU_COLOR_GREEN] = COLOR_GREEN,
728 [QEMU_COLOR_CYAN] = COLOR_CYAN,
729 [QEMU_COLOR_RED] = COLOR_RED,
730 [QEMU_COLOR_MAGENTA] = COLOR_MAGENTA,
731 [QEMU_COLOR_YELLOW] = COLOR_YELLOW,
732 [QEMU_COLOR_WHITE] = COLOR_WHITE,
4d3b6f6e
AZ
733 };
734
735 /* input as raw as possible, let everything be interpreted
736 * by the guest system */
737 initscr(); noecho(); intrflush(stdscr, FALSE);
738 nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE);
739 start_color(); raw(); scrollok(stdscr, FALSE);
633786fe 740 set_escdelay(25);
4d3b6f6e 741
4083733d 742 /* Make color pair to match color format (3bits bg:3bits fg) */
615220dd 743 for (i = 0; i < 64; i++) {
4d3b6f6e 744 init_pair(i, colour_default[i & 7], colour_default[i >> 3]);
615220dd 745 }
4083733d 746 /* Set default color for more than 64 for safety. */
615220dd
OH
747 for (i = 64; i < COLOR_PAIRS; i++) {
748 init_pair(i, COLOR_WHITE, COLOR_BLACK);
749 }
e2368dc9 750
2f8b7cd5 751 font_setup();
4d3b6f6e
AZ
752}
753
754static void curses_keyboard_setup(void)
755{
4d3b6f6e
AZ
756#if defined(__APPLE__)
757 /* always use generic keymaps */
758 if (!keyboard_layout)
759 keyboard_layout = "en-us";
760#endif
761 if(keyboard_layout) {
ab4f931e
FL
762 kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout,
763 &error_fatal);
4d3b6f6e 764 }
4d3b6f6e
AZ
765}
766
7c20b4a3
GH
767static const DisplayChangeListenerOps dcl_ops = {
768 .dpy_name = "curses",
769 .dpy_text_update = curses_update,
770 .dpy_text_resize = curses_resize,
771 .dpy_refresh = curses_refresh,
772 .dpy_text_cursor = curses_cursor_position,
773};
774
b0766612 775static void curses_display_init(DisplayState *ds, DisplayOptions *opts)
4d3b6f6e
AZ
776{
777#ifndef _WIN32
778 if (!isatty(1)) {
779 fprintf(stderr, "We need a terminal output\n");
780 exit(1);
781 }
782#endif
783
2f8b7cd5
ST
784 setlocale(LC_CTYPE, "");
785 if (opts->u.curses.charset) {
786 font_charset = opts->u.curses.charset;
787 }
76c51fc3
PMD
788 screen = g_new0(console_ch_t, 160 * 100);
789 vga_to_curses = g_new0(cchar_t, 256);
4d3b6f6e
AZ
790 curses_setup();
791 curses_keyboard_setup();
28695489 792 atexit(curses_atexit);
4d3b6f6e 793
032ac6f8 794 curses_winch_init();
4d3b6f6e 795
fedf0d35 796 dcl = g_new0(DisplayChangeListener, 1);
7c20b4a3 797 dcl->ops = &dcl_ops;
5209089f 798 register_displaychangelistener(dcl);
4d3b6f6e
AZ
799
800 invalidate = 1;
4d3b6f6e 801}
b0766612
GH
802
803static QemuDisplay qemu_display_curses = {
804 .type = DISPLAY_TYPE_CURSES,
805 .init = curses_display_init,
806};
807
808static void register_curses(void)
809{
810 qemu_display_register(&qemu_display_curses);
811}
812
813type_init(register_curses);