Commit 4d3b6f6e126553107a78999bd1070b086ae3c023
1 parent
c0be16d3
Add an ncurses UI.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3976 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
21 changed files
with
1238 additions
and
34 deletions
Makefile
... | ... | @@ -99,6 +99,9 @@ OBJS+=$(addprefix audio/, $(AUDIO_OBJS)) |
99 | 99 | ifdef CONFIG_SDL |
100 | 100 | OBJS+=sdl.o x_keymap.o |
101 | 101 | endif |
102 | +ifdef CONFIG_CURSES | |
103 | +OBJS+=curses.o | |
104 | +endif | |
102 | 105 | OBJS+=vnc.o d3des.o |
103 | 106 | |
104 | 107 | ifdef CONFIG_COCOA |
... | ... | @@ -122,6 +125,9 @@ sdl.o: sdl.c keymaps.c sdl_keysym.h |
122 | 125 | vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h d3des.c d3des.h |
123 | 126 | $(CC) $(CFLAGS) $(CPPFLAGS) $(CONFIG_VNC_TLS_CFLAGS) -c -o $@ $< |
124 | 127 | |
128 | +curses.o: curses.c keymaps.c curses_keys.h | |
129 | + $(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< | |
130 | + | |
125 | 131 | audio/sdlaudio.o: audio/sdlaudio.c |
126 | 132 | $(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) -c -o $@ $< |
127 | 133 | ... | ... |
Makefile.target
... | ... | @@ -647,7 +647,7 @@ main.o: CFLAGS+=-p |
647 | 647 | endif |
648 | 648 | |
649 | 649 | $(QEMU_PROG): $(OBJS) ../libqemu_common.a libqemu.a |
650 | - $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) | |
650 | + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(CURSES_LIBS) | |
651 | 651 | |
652 | 652 | endif # !CONFIG_USER_ONLY |
653 | 653 | ... | ... |
configure
... | ... | @@ -108,6 +108,7 @@ linux_user="no" |
108 | 108 | darwin_user="no" |
109 | 109 | build_docs="no" |
110 | 110 | uname_release="" |
111 | +curses="yes" | |
111 | 112 | |
112 | 113 | # OS specific |
113 | 114 | targetos=`uname -s` |
... | ... | @@ -323,6 +324,8 @@ for opt do |
323 | 324 | ;; |
324 | 325 | --disable-werror) werror="no" |
325 | 326 | ;; |
327 | + --disable-curses) curses="no" | |
328 | + ;; | |
326 | 329 | *) echo "ERROR: unknown option $opt"; show_help="yes" |
327 | 330 | ;; |
328 | 331 | esac |
... | ... | @@ -669,6 +672,20 @@ EOF |
669 | 672 | fi |
670 | 673 | fi |
671 | 674 | |
675 | +########################################## | |
676 | +# curses probe | |
677 | + | |
678 | +if test "$curses" = "yes" ; then | |
679 | + curses=no | |
680 | + cat > $TMPC << EOF | |
681 | +#include <curses.h> | |
682 | +int main(void) { return curses_version(); } | |
683 | +EOF | |
684 | + if $cc -o $TMPE $TMPC -lcurses 2> /dev/null ; then | |
685 | + curses=yes | |
686 | + fi | |
687 | +fi # test "$curses" | |
688 | + | |
672 | 689 | # Check if tools are available to build documentation. |
673 | 690 | if [ -x "`which texi2html 2>/dev/null`" ] && \ |
674 | 691 | [ -x "`which pod2man 2>/dev/null`" ]; then |
... | ... | @@ -720,6 +737,7 @@ echo "SDL support $sdl" |
720 | 737 | if test "$sdl" != "no" ; then |
721 | 738 | echo "SDL static link $sdl_static" |
722 | 739 | fi |
740 | +echo "curses support $curses" | |
723 | 741 | echo "mingw32 support $mingw32" |
724 | 742 | echo "Adlib support $adlib" |
725 | 743 | echo "AC97 support $ac97" |
... | ... | @@ -974,8 +992,13 @@ if test "$sdl1" = "yes" ; then |
974 | 992 | fi |
975 | 993 | fi |
976 | 994 | if test "$cocoa" = "yes" ; then |
977 | - echo "#define CONFIG_COCOA 1" >> $config_h | |
978 | - echo "CONFIG_COCOA=yes" >> $config_mak | |
995 | + echo "#define CONFIG_COCOA 1" >> $config_h | |
996 | + echo "CONFIG_COCOA=yes" >> $config_mak | |
997 | +fi | |
998 | +if test "$curses" = "yes" ; then | |
999 | + echo "#define CONFIG_CURSES 1" >> $config_h | |
1000 | + echo "CONFIG_CURSES=yes" >> $config_mak | |
1001 | + echo "CURSES_LIBS=-lcurses" >> $config_mak | |
979 | 1002 | fi |
980 | 1003 | |
981 | 1004 | # XXX: suppress that |
... | ... | @@ -1040,7 +1063,8 @@ if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \ |
1040 | 1063 | -a "$sdl" = "no" -a "$cocoa" = "no" ; then |
1041 | 1064 | echo "ERROR: QEMU requires SDL or Cocoa for graphical output" |
1042 | 1065 | echo "To build QEMU without graphical output configure with --disable-gfx-check" |
1043 | - echo "Note that this will disable all output from the virtual graphics card." | |
1066 | + echo "Note that this will disable all output from the virtual graphics card" | |
1067 | + echo "except through VNC or curses." | |
1044 | 1068 | exit 1; |
1045 | 1069 | fi |
1046 | 1070 | ... | ... |
console.c
... | ... | @@ -121,6 +121,7 @@ struct TextConsole { |
121 | 121 | vga_hw_update_ptr hw_update; |
122 | 122 | vga_hw_invalidate_ptr hw_invalidate; |
123 | 123 | vga_hw_screen_dump_ptr hw_screen_dump; |
124 | + vga_hw_text_update_ptr hw_text_update; | |
124 | 125 | void *hw; |
125 | 126 | |
126 | 127 | int g_width, g_height; |
... | ... | @@ -135,6 +136,7 @@ struct TextConsole { |
135 | 136 | TextAttributes t_attrib_default; /* default text attributes */ |
136 | 137 | TextAttributes t_attrib; /* currently active text attributes */ |
137 | 138 | TextCell *cells; |
139 | + int text_x[2], text_y[2], cursor_invalidate; | |
138 | 140 | |
139 | 141 | enum TTYState state; |
140 | 142 | int esc_params[MAX_ESC_PARAMS]; |
... | ... | @@ -171,6 +173,12 @@ void vga_hw_screen_dump(const char *filename) |
171 | 173 | consoles[0]->hw_screen_dump(consoles[0]->hw, filename); |
172 | 174 | } |
173 | 175 | |
176 | +void vga_hw_text_update(console_ch_t *chardata) | |
177 | +{ | |
178 | + if (active_console && active_console->hw_text_update) | |
179 | + active_console->hw_text_update(active_console->hw, chardata); | |
180 | +} | |
181 | + | |
174 | 182 | /* convert a RGBA color to a color index usable in graphic primitives */ |
175 | 183 | static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba) |
176 | 184 | { |
... | ... | @@ -515,12 +523,25 @@ static void text_console_resize(TextConsole *s) |
515 | 523 | s->cells = cells; |
516 | 524 | } |
517 | 525 | |
526 | +static inline void text_update_xy(TextConsole *s, int x, int y) | |
527 | +{ | |
528 | + s->text_x[0] = MIN(s->text_x[0], x); | |
529 | + s->text_x[1] = MAX(s->text_x[1], x); | |
530 | + s->text_y[0] = MIN(s->text_y[0], y); | |
531 | + s->text_y[1] = MAX(s->text_y[1], y); | |
532 | +} | |
533 | + | |
518 | 534 | static void update_xy(TextConsole *s, int x, int y) |
519 | 535 | { |
520 | 536 | TextCell *c; |
521 | 537 | int y1, y2; |
522 | 538 | |
523 | 539 | if (s == active_console) { |
540 | + if (!s->ds->depth) { | |
541 | + text_update_xy(s, x, y); | |
542 | + return; | |
543 | + } | |
544 | + | |
524 | 545 | y1 = (s->y_base + y) % s->total_height; |
525 | 546 | y2 = y1 - s->y_displayed; |
526 | 547 | if (y2 < 0) |
... | ... | @@ -542,6 +563,12 @@ static void console_show_cursor(TextConsole *s, int show) |
542 | 563 | |
543 | 564 | if (s == active_console) { |
544 | 565 | int x = s->x; |
566 | + | |
567 | + if (!s->ds->depth) { | |
568 | + s->cursor_invalidate = 1; | |
569 | + return; | |
570 | + } | |
571 | + | |
545 | 572 | if (x >= s->width) { |
546 | 573 | x = s->width - 1; |
547 | 574 | } |
... | ... | @@ -571,6 +598,14 @@ static void console_refresh(TextConsole *s) |
571 | 598 | |
572 | 599 | if (s != active_console) |
573 | 600 | return; |
601 | + if (!s->ds->depth) { | |
602 | + s->text_x[0] = 0; | |
603 | + s->text_y[0] = 0; | |
604 | + s->text_x[1] = s->width - 1; | |
605 | + s->text_y[1] = s->height - 1; | |
606 | + s->cursor_invalidate = 1; | |
607 | + return; | |
608 | + } | |
574 | 609 | |
575 | 610 | vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height, |
576 | 611 | color_table[0][COLOR_BLACK]); |
... | ... | @@ -648,6 +683,14 @@ static void console_put_lf(TextConsole *s) |
648 | 683 | c++; |
649 | 684 | } |
650 | 685 | if (s == active_console && s->y_displayed == s->y_base) { |
686 | + if (!s->ds->depth) { | |
687 | + s->text_x[0] = 0; | |
688 | + s->text_y[0] = 0; | |
689 | + s->text_x[1] = s->width - 1; | |
690 | + s->text_y[1] = s->height - 1; | |
691 | + return; | |
692 | + } | |
693 | + | |
651 | 694 | vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, |
652 | 695 | s->width * FONT_WIDTH, |
653 | 696 | (s->height - 1) * FONT_HEIGHT); |
... | ... | @@ -998,21 +1041,7 @@ void console_select(unsigned int index) |
998 | 1041 | s = consoles[index]; |
999 | 1042 | if (s) { |
1000 | 1043 | active_console = s; |
1001 | - if (s->console_type != GRAPHIC_CONSOLE) { | |
1002 | - if (s->g_width != s->ds->width || | |
1003 | - s->g_height != s->ds->height) { | |
1004 | - if (s->console_type == TEXT_CONSOLE_FIXED_SIZE) { | |
1005 | - dpy_resize(s->ds, s->g_width, s->g_height); | |
1006 | - } else { | |
1007 | - s->g_width = s->ds->width; | |
1008 | - s->g_height = s->ds->height; | |
1009 | - text_console_resize(s); | |
1010 | - } | |
1011 | - } | |
1012 | - console_refresh(s); | |
1013 | - } else { | |
1014 | - vga_hw_invalidate(); | |
1015 | - } | |
1044 | + vga_hw_invalidate(); | |
1016 | 1045 | } |
1017 | 1046 | } |
1018 | 1047 | |
... | ... | @@ -1116,6 +1145,52 @@ void kbd_put_keysym(int keysym) |
1116 | 1145 | } |
1117 | 1146 | } |
1118 | 1147 | |
1148 | +static void text_console_invalidate(void *opaque) | |
1149 | +{ | |
1150 | + TextConsole *s = (TextConsole *) opaque; | |
1151 | + | |
1152 | + if (s->console_type != GRAPHIC_CONSOLE) { | |
1153 | + if (s->g_width != s->ds->width || | |
1154 | + s->g_height != s->ds->height) { | |
1155 | + if (s->console_type == TEXT_CONSOLE_FIXED_SIZE) | |
1156 | + dpy_resize(s->ds, s->g_width, s->g_height); | |
1157 | + else { | |
1158 | + s->g_width = s->ds->width; | |
1159 | + s->g_height = s->ds->height; | |
1160 | + text_console_resize(s); | |
1161 | + } | |
1162 | + } | |
1163 | + } | |
1164 | + console_refresh(s); | |
1165 | +} | |
1166 | + | |
1167 | +static void text_console_update(void *opaque, console_ch_t *chardata) | |
1168 | +{ | |
1169 | + TextConsole *s = (TextConsole *) opaque; | |
1170 | + int i, j, src; | |
1171 | + | |
1172 | + if (s->text_x[0] <= s->text_x[1]) { | |
1173 | + src = (s->y_base + s->text_y[0]) * s->width; | |
1174 | + chardata += s->text_y[0] * s->width; | |
1175 | + for (i = s->text_y[0]; i <= s->text_y[1]; i ++) | |
1176 | + for (j = 0; j < s->width; j ++, src ++) | |
1177 | + console_write_ch(chardata ++, s->cells[src].ch | | |
1178 | + (s->cells[src].t_attrib.fgcol << 12) | | |
1179 | + (s->cells[src].t_attrib.bgcol << 8) | | |
1180 | + (s->cells[src].t_attrib.bold << 21)); | |
1181 | + dpy_update(s->ds, s->text_x[0], s->text_y[0], | |
1182 | + s->text_x[1] - s->text_x[0], i - s->text_y[0]); | |
1183 | + s->text_x[0] = s->width; | |
1184 | + s->text_y[0] = s->height; | |
1185 | + s->text_x[1] = 0; | |
1186 | + s->text_y[1] = 0; | |
1187 | + } | |
1188 | + if (s->cursor_invalidate) { | |
1189 | + dpy_cursor(s->ds, s->x, s->y); | |
1190 | + s->cursor_invalidate = 0; | |
1191 | + } | |
1192 | +} | |
1193 | + | |
1119 | 1194 | static TextConsole *new_console(DisplayState *ds, console_type_t console_type) |
1120 | 1195 | { |
1121 | 1196 | TextConsole *s; |
... | ... | @@ -1150,6 +1225,7 @@ static TextConsole *new_console(DisplayState *ds, console_type_t console_type) |
1150 | 1225 | TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update, |
1151 | 1226 | vga_hw_invalidate_ptr invalidate, |
1152 | 1227 | vga_hw_screen_dump_ptr screen_dump, |
1228 | + vga_hw_text_update_ptr text_update, | |
1153 | 1229 | void *opaque) |
1154 | 1230 | { |
1155 | 1231 | TextConsole *s; |
... | ... | @@ -1160,13 +1236,14 @@ TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update, |
1160 | 1236 | s->hw_update = update; |
1161 | 1237 | s->hw_invalidate = invalidate; |
1162 | 1238 | s->hw_screen_dump = screen_dump; |
1239 | + s->hw_text_update = text_update; | |
1163 | 1240 | s->hw = opaque; |
1164 | 1241 | return s; |
1165 | 1242 | } |
1166 | 1243 | |
1167 | 1244 | int is_graphic_console(void) |
1168 | 1245 | { |
1169 | - return active_console->console_type == GRAPHIC_CONSOLE; | |
1246 | + return active_console && active_console->console_type == GRAPHIC_CONSOLE; | |
1170 | 1247 | } |
1171 | 1248 | |
1172 | 1249 | void console_color_init(DisplayState *ds) |
... | ... | @@ -1234,6 +1311,10 @@ CharDriverState *text_console_init(DisplayState *ds, const char *p) |
1234 | 1311 | s->g_width = width; |
1235 | 1312 | s->g_height = height; |
1236 | 1313 | |
1314 | + s->hw_invalidate = text_console_invalidate; | |
1315 | + s->hw_text_update = text_console_update; | |
1316 | + s->hw = s; | |
1317 | + | |
1237 | 1318 | /* Set text attribute defaults */ |
1238 | 1319 | s->t_attrib_default.bold = 0; |
1239 | 1320 | s->t_attrib_default.uline = 0; | ... | ... |
console.h
... | ... | @@ -79,6 +79,7 @@ struct DisplayState { |
79 | 79 | int dst_x, int dst_y, int w, int h); |
80 | 80 | void (*dpy_fill)(struct DisplayState *s, int x, int y, |
81 | 81 | int w, int h, uint32_t c); |
82 | + void (*dpy_text_cursor)(struct DisplayState *s, int x, int y); | |
82 | 83 | void (*mouse_set)(int x, int y, int on); |
83 | 84 | void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y, |
84 | 85 | uint8_t *image, uint8_t *mask); |
... | ... | @@ -94,17 +95,32 @@ static inline void dpy_resize(DisplayState *s, int w, int h) |
94 | 95 | s->dpy_resize(s, w, h); |
95 | 96 | } |
96 | 97 | |
98 | +static inline void dpy_cursor(DisplayState *s, int x, int y) | |
99 | +{ | |
100 | + if (s->dpy_text_cursor) | |
101 | + s->dpy_text_cursor(s, x, y); | |
102 | +} | |
103 | + | |
104 | +typedef unsigned long console_ch_t; | |
105 | +static inline void console_write_ch(console_ch_t *dest, uint32_t ch) | |
106 | +{ | |
107 | + cpu_to_le32wu((uint32_t *) dest, ch); | |
108 | +} | |
109 | + | |
97 | 110 | typedef void (*vga_hw_update_ptr)(void *); |
98 | 111 | typedef void (*vga_hw_invalidate_ptr)(void *); |
99 | 112 | typedef void (*vga_hw_screen_dump_ptr)(void *, const char *); |
113 | +typedef void (*vga_hw_text_update_ptr)(void *, console_ch_t *); | |
100 | 114 | |
101 | 115 | TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update, |
102 | 116 | vga_hw_invalidate_ptr invalidate, |
103 | 117 | vga_hw_screen_dump_ptr screen_dump, |
118 | + vga_hw_text_update_ptr text_update, | |
104 | 119 | void *opaque); |
105 | 120 | void vga_hw_update(void); |
106 | 121 | void vga_hw_invalidate(void); |
107 | 122 | void vga_hw_screen_dump(const char *filename); |
123 | +void vga_hw_text_update(console_ch_t *chardata); | |
108 | 124 | |
109 | 125 | int is_graphic_console(void); |
110 | 126 | CharDriverState *text_console_init(DisplayState *ds, const char *p); |
... | ... | @@ -124,6 +140,9 @@ int vnc_display_open(DisplayState *ds, const char *display); |
124 | 140 | int vnc_display_password(DisplayState *ds, const char *password); |
125 | 141 | void do_info_vnc(void); |
126 | 142 | |
143 | +/* curses.c */ | |
144 | +void curses_display_init(DisplayState *ds, int full_screen); | |
145 | + | |
127 | 146 | /* x_keymap.c */ |
128 | 147 | extern uint8_t _translate_keycode(const int key); |
129 | 148 | ... | ... |
curses.c
0 โ 100644
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 | + | |
25 | +#include "qemu-common.h" | |
26 | +#include "console.h" | |
27 | +#include "sysemu.h" | |
28 | + | |
29 | +#include <curses.h> | |
30 | + | |
31 | +#ifndef _WIN32 | |
32 | +#include <signal.h> | |
33 | +#include <sys/ioctl.h> | |
34 | +#include <termios.h> | |
35 | +#endif | |
36 | + | |
37 | +#define FONT_HEIGHT 16 | |
38 | +#define FONT_WIDTH 8 | |
39 | + | |
40 | +static console_ch_t screen[160 * 100]; | |
41 | +static WINDOW *screenpad = NULL; | |
42 | +static int width, height, gwidth, gheight, invalidate; | |
43 | +static int px, py, sminx, sminy, smaxx, smaxy; | |
44 | + | |
45 | +static void curses_update(DisplayState *ds, int x, int y, int w, int h) | |
46 | +{ | |
47 | + chtype *line; | |
48 | + | |
49 | + line = ((chtype *) screen) + y * width; | |
50 | + for (h += y; y < h; y ++, line += width) | |
51 | + mvwaddchnstr(screenpad, y, 0, line, width); | |
52 | + | |
53 | + pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1); | |
54 | + refresh(); | |
55 | +} | |
56 | + | |
57 | +static void curses_calc_pad(void) | |
58 | +{ | |
59 | + if (is_graphic_console()) { | |
60 | + width = gwidth; | |
61 | + height = gheight; | |
62 | + } else { | |
63 | + width = COLS; | |
64 | + height = LINES; | |
65 | + } | |
66 | + | |
67 | + if (screenpad) | |
68 | + delwin(screenpad); | |
69 | + | |
70 | + clear(); | |
71 | + refresh(); | |
72 | + | |
73 | + screenpad = newpad(height, width); | |
74 | + | |
75 | + if (width > COLS) { | |
76 | + px = (width - COLS) / 2; | |
77 | + sminx = 0; | |
78 | + smaxx = COLS; | |
79 | + } else { | |
80 | + px = 0; | |
81 | + sminx = (COLS - width) / 2; | |
82 | + smaxx = sminx + width; | |
83 | + } | |
84 | + | |
85 | + if (height > LINES) { | |
86 | + py = (height - LINES) / 2; | |
87 | + sminy = 0; | |
88 | + smaxy = LINES; | |
89 | + } else { | |
90 | + py = 0; | |
91 | + sminy = (LINES - height) / 2; | |
92 | + smaxy = sminy + height; | |
93 | + } | |
94 | +} | |
95 | + | |
96 | +static void curses_resize(DisplayState *ds, int w, int h) | |
97 | +{ | |
98 | + if (w == gwidth && h == gheight) | |
99 | + return; | |
100 | + | |
101 | + gwidth = w; | |
102 | + gheight = h; | |
103 | + | |
104 | + curses_calc_pad(); | |
105 | +} | |
106 | + | |
107 | +#ifndef _WIN32 | |
108 | +#ifdef SIGWINCH | |
109 | +static void curses_winch_handler(int signum) | |
110 | +{ | |
111 | + struct winsize { | |
112 | + unsigned short ws_row; | |
113 | + unsigned short ws_col; | |
114 | + unsigned short ws_xpixel; /* unused */ | |
115 | + unsigned short ws_ypixel; /* unused */ | |
116 | + } ws; | |
117 | + | |
118 | + /* terminal size changed */ | |
119 | + if (ioctl(1, TIOCGWINSZ, &ws) == -1) | |
120 | + return; | |
121 | + | |
122 | + resize_term(ws.ws_row, ws.ws_col); | |
123 | + curses_calc_pad(); | |
124 | + invalidate = 1; | |
125 | + | |
126 | + /* some systems require this */ | |
127 | + signal(SIGWINCH, curses_winch_handler); | |
128 | +} | |
129 | +#endif | |
130 | +#endif | |
131 | + | |
132 | +static void curses_cursor_position(DisplayState *ds, int x, int y) | |
133 | +{ | |
134 | + if (x >= 0) { | |
135 | + x = sminx + x - px; | |
136 | + y = sminy + y - py; | |
137 | + | |
138 | + if (x >= 0 && y >= 0 && x < COLS && y < LINES) { | |
139 | + move(y, x); | |
140 | + curs_set(1); | |
141 | + /* it seems that curs_set(1) must always be called before | |
142 | + * curs_set(2) for the latter to have effect */ | |
143 | + if (!is_graphic_console()) | |
144 | + curs_set(2); | |
145 | + return; | |
146 | + } | |
147 | + } | |
148 | + | |
149 | + curs_set(0); | |
150 | +} | |
151 | + | |
152 | +/* generic keyboard conversion */ | |
153 | + | |
154 | +#include "curses_keys.h" | |
155 | +#include "keymaps.c" | |
156 | + | |
157 | +static kbd_layout_t *kbd_layout = 0; | |
158 | +static int keycode2keysym[CURSES_KEYS]; | |
159 | + | |
160 | +static void curses_refresh(DisplayState *ds) | |
161 | +{ | |
162 | + int chr, nextchr, keysym, keycode; | |
163 | + | |
164 | + if (invalidate) { | |
165 | + clear(); | |
166 | + refresh(); | |
167 | + curses_calc_pad(); | |
168 | + ds->width = FONT_WIDTH * width; | |
169 | + ds->height = FONT_HEIGHT * height; | |
170 | + vga_hw_invalidate(); | |
171 | + invalidate = 0; | |
172 | + } | |
173 | + | |
174 | + vga_hw_text_update(screen); | |
175 | + | |
176 | + nextchr = ERR; | |
177 | + while (1) { | |
178 | + /* while there are any pending key strokes to process */ | |
179 | + if (nextchr == ERR) | |
180 | + chr = getch(); | |
181 | + else { | |
182 | + chr = nextchr; | |
183 | + nextchr = ERR; | |
184 | + } | |
185 | + | |
186 | + if (chr == ERR) | |
187 | + break; | |
188 | + | |
189 | + /* this shouldn't occur when we use a custom SIGWINCH handler */ | |
190 | + if (chr == KEY_RESIZE) { | |
191 | + clear(); | |
192 | + refresh(); | |
193 | + curses_calc_pad(); | |
194 | + curses_update(ds, 0, 0, width, height); | |
195 | + ds->width = FONT_WIDTH * width; | |
196 | + ds->height = FONT_HEIGHT * height; | |
197 | + continue; | |
198 | + } | |
199 | + | |
200 | + keycode = curses2keycode[chr]; | |
201 | + if (keycode == -1) | |
202 | + continue; | |
203 | + | |
204 | + /* alt key */ | |
205 | + if (keycode == 1) { | |
206 | + nextchr = getch(); | |
207 | + | |
208 | + if (nextchr != ERR) { | |
209 | + keycode = curses2keycode[nextchr]; | |
210 | + nextchr = ERR; | |
211 | + if (keycode == -1) | |
212 | + continue; | |
213 | + | |
214 | + keycode |= ALT; | |
215 | + | |
216 | + /* process keys reserved for qemu */ | |
217 | + if (keycode >= QEMU_KEY_CONSOLE0 && | |
218 | + keycode < QEMU_KEY_CONSOLE0 + 9) { | |
219 | + erase(); | |
220 | + wnoutrefresh(stdscr); | |
221 | + console_select(keycode - QEMU_KEY_CONSOLE0); | |
222 | + | |
223 | + invalidate = 1; | |
224 | + continue; | |
225 | + } | |
226 | + } | |
227 | + } | |
228 | + | |
229 | + if (kbd_layout && !(keycode & GREY)) { | |
230 | + keysym = keycode2keysym[keycode & KEY_MASK]; | |
231 | + if (keysym == -1) | |
232 | + keysym = chr; | |
233 | + | |
234 | + keycode &= ~KEY_MASK; | |
235 | + keycode |= keysym2scancode(kbd_layout, keysym); | |
236 | + } | |
237 | + | |
238 | + if (is_graphic_console()) { | |
239 | + /* since terminals don't know about key press and release | |
240 | + * events, we need to emit both for each key received */ | |
241 | + if (keycode & SHIFT) | |
242 | + kbd_put_keycode(SHIFT_CODE); | |
243 | + if (keycode & CNTRL) | |
244 | + kbd_put_keycode(CNTRL_CODE); | |
245 | + if (keycode & ALT) | |
246 | + kbd_put_keycode(ALT_CODE); | |
247 | + if (keycode & GREY) | |
248 | + kbd_put_keycode(GREY_CODE); | |
249 | + kbd_put_keycode(keycode & KEY_MASK); | |
250 | + if (keycode & GREY) | |
251 | + kbd_put_keycode(GREY_CODE); | |
252 | + kbd_put_keycode((keycode & KEY_MASK) | KEY_RELEASE); | |
253 | + if (keycode & ALT) | |
254 | + kbd_put_keycode(ALT_CODE | KEY_RELEASE); | |
255 | + if (keycode & CNTRL) | |
256 | + kbd_put_keycode(CNTRL_CODE | KEY_RELEASE); | |
257 | + if (keycode & SHIFT) | |
258 | + kbd_put_keycode(SHIFT_CODE | KEY_RELEASE); | |
259 | + } else { | |
260 | + keysym = curses2keysym[chr]; | |
261 | + if (keysym == -1) | |
262 | + keysym = chr; | |
263 | + | |
264 | + kbd_put_keysym(keysym); | |
265 | + } | |
266 | + } | |
267 | +} | |
268 | + | |
269 | +static void curses_cleanup(void *opaque) | |
270 | +{ | |
271 | + endwin(); | |
272 | +} | |
273 | + | |
274 | +static void curses_atexit(void) | |
275 | +{ | |
276 | + curses_cleanup(NULL); | |
277 | +} | |
278 | + | |
279 | +static void curses_setup(void) | |
280 | +{ | |
281 | + int i, colour_default[8] = { | |
282 | + COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, | |
283 | + COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE, | |
284 | + }; | |
285 | + | |
286 | + /* input as raw as possible, let everything be interpreted | |
287 | + * by the guest system */ | |
288 | + initscr(); noecho(); intrflush(stdscr, FALSE); | |
289 | + nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE); | |
290 | + start_color(); raw(); scrollok(stdscr, FALSE); | |
291 | + | |
292 | + for (i = 0; i < 64; i ++) | |
293 | + init_pair(i, colour_default[i & 7], colour_default[i >> 3]); | |
294 | +} | |
295 | + | |
296 | +static void curses_keyboard_setup(void) | |
297 | +{ | |
298 | + int i, keycode, keysym; | |
299 | + | |
300 | +#if defined(__APPLE__) | |
301 | + /* always use generic keymaps */ | |
302 | + if (!keyboard_layout) | |
303 | + keyboard_layout = "en-us"; | |
304 | +#endif | |
305 | + if(keyboard_layout) { | |
306 | + kbd_layout = init_keyboard_layout(keyboard_layout); | |
307 | + if (!kbd_layout) | |
308 | + exit(1); | |
309 | + } | |
310 | + | |
311 | + for (i = 0; i < CURSES_KEYS; i ++) | |
312 | + keycode2keysym[i] = -1; | |
313 | + | |
314 | + for (i = 0; i < CURSES_KEYS; i ++) { | |
315 | + if (curses2keycode[i] == -1) | |
316 | + continue; | |
317 | + | |
318 | + keycode = curses2keycode[i] & KEY_MASK; | |
319 | + if (keycode2keysym[keycode] >= 0) | |
320 | + continue; | |
321 | + | |
322 | + for (keysym = 0; keysym < CURSES_KEYS; keysym ++) | |
323 | + if (curses2keycode[keysym] == keycode) { | |
324 | + keycode2keysym[keycode] = keysym; | |
325 | + break; | |
326 | + } | |
327 | + | |
328 | + if (keysym >= CURSES_KEYS) | |
329 | + keycode2keysym[keycode] = i; | |
330 | + } | |
331 | +} | |
332 | + | |
333 | +void curses_display_init(DisplayState *ds, int full_screen) | |
334 | +{ | |
335 | +#ifndef _WIN32 | |
336 | + if (!isatty(1)) { | |
337 | + fprintf(stderr, "We need a terminal output\n"); | |
338 | + exit(1); | |
339 | + } | |
340 | +#endif | |
341 | + | |
342 | + curses_setup(); | |
343 | + curses_keyboard_setup(); | |
344 | + atexit(curses_atexit); | |
345 | + | |
346 | +#ifndef _WIN32 | |
347 | + signal(SIGINT, SIG_DFL); | |
348 | + signal(SIGQUIT, SIG_DFL); | |
349 | +#ifdef SIGWINCH | |
350 | + /* some curses implementations provide a handler, but we | |
351 | + * want to be sure this is handled regardless of the library */ | |
352 | + signal(SIGWINCH, curses_winch_handler); | |
353 | +#endif | |
354 | +#endif | |
355 | + | |
356 | + ds->data = (void *) screen; | |
357 | + ds->linesize = 0; | |
358 | + ds->depth = 0; | |
359 | + ds->width = 640; | |
360 | + ds->height = 400; | |
361 | + ds->dpy_update = curses_update; | |
362 | + ds->dpy_resize = curses_resize; | |
363 | + ds->dpy_refresh = curses_refresh; | |
364 | + ds->dpy_text_cursor = curses_cursor_position; | |
365 | + | |
366 | + invalidate = 1; | |
367 | + | |
368 | + /* Standard VGA initial text mode dimensions */ | |
369 | + curses_resize(ds, 80, 25); | |
370 | +} | ... | ... |
curses_keys.h
0 โ 100644
1 | +/* | |
2 | + * Keycode and keysyms conversion tables for curses | |
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 | +#define KEY_RELEASE 0x80 | |
25 | +#define KEY_MASK 0x7f | |
26 | +#define SHIFT_CODE 0x2a | |
27 | +#define SHIFT 0x0080 | |
28 | +#define GREY_CODE 0xe0 | |
29 | +#define GREY 0x0100 | |
30 | +#define CNTRL_CODE 0x1d | |
31 | +#define CNTRL 0x0200 | |
32 | +#define ALT_CODE 0x38 | |
33 | +#define ALT 0x0400 | |
34 | + | |
35 | +/* curses won't detect a Control + Alt + 1, so use Alt + 1 */ | |
36 | +#define QEMU_KEY_CONSOLE0 (2 | ALT) /* (curses2keycode['1'] | ALT) */ | |
37 | + | |
38 | +#define CURSES_KEYS KEY_MAX /* KEY_MAX defined in <curses.h> */ | |
39 | + | |
40 | +int curses2keycode[CURSES_KEYS] = { | |
41 | + [0 ... (CURSES_KEYS - 1)] = -1, | |
42 | + | |
43 | + [0x01b] = 1, /* Escape */ | |
44 | + ['1'] = 2, | |
45 | + ['2'] = 3, | |
46 | + ['3'] = 4, | |
47 | + ['4'] = 5, | |
48 | + ['5'] = 6, | |
49 | + ['6'] = 7, | |
50 | + ['7'] = 8, | |
51 | + ['8'] = 9, | |
52 | + ['9'] = 10, | |
53 | + ['0'] = 11, | |
54 | + ['-'] = 12, | |
55 | + ['='] = 13, | |
56 | + [0x07f] = 14, /* Backspace */ | |
57 | + [0x107] = 14, /* Backspace */ | |
58 | + | |
59 | + ['\t'] = 15, /* Tab */ | |
60 | + ['q'] = 16, | |
61 | + ['w'] = 17, | |
62 | + ['e'] = 18, | |
63 | + ['r'] = 19, | |
64 | + ['t'] = 20, | |
65 | + ['y'] = 21, | |
66 | + ['u'] = 22, | |
67 | + ['i'] = 23, | |
68 | + ['o'] = 24, | |
69 | + ['p'] = 25, | |
70 | + ['['] = 26, | |
71 | + [']'] = 27, | |
72 | + ['\n'] = 28, /* Return */ | |
73 | + ['\r'] = 28, /* Return */ | |
74 | + [0x157] = 28, /* Return */ | |
75 | + | |
76 | + ['a'] = 30, | |
77 | + ['s'] = 31, | |
78 | + ['d'] = 32, | |
79 | + ['f'] = 33, | |
80 | + ['g'] = 34, | |
81 | + ['h'] = 35, | |
82 | + ['j'] = 36, | |
83 | + ['k'] = 37, | |
84 | + ['l'] = 38, | |
85 | + [';'] = 39, | |
86 | + ['\''] = 40, /* Single quote */ | |
87 | + ['`'] = 41, | |
88 | + ['\\'] = 43, /* Backslash */ | |
89 | + | |
90 | + ['z'] = 44, | |
91 | + ['x'] = 45, | |
92 | + ['c'] = 46, | |
93 | + ['v'] = 47, | |
94 | + ['b'] = 48, | |
95 | + ['n'] = 49, | |
96 | + ['m'] = 50, | |
97 | + [','] = 51, | |
98 | + ['.'] = 52, | |
99 | + ['/'] = 53, | |
100 | + | |
101 | + [' '] = 57, | |
102 | + | |
103 | + [0x109] = 59, /* Function Key 1 */ | |
104 | + [0x10a] = 60, /* Function Key 2 */ | |
105 | + [0x10b] = 61, /* Function Key 3 */ | |
106 | + [0x10c] = 62, /* Function Key 4 */ | |
107 | + [0x10d] = 63, /* Function Key 5 */ | |
108 | + [0x10e] = 64, /* Function Key 6 */ | |
109 | + [0x10f] = 65, /* Function Key 7 */ | |
110 | + [0x110] = 66, /* Function Key 8 */ | |
111 | + [0x111] = 67, /* Function Key 9 */ | |
112 | + [0x112] = 68, /* Function Key 10 */ | |
113 | + [0x113] = 87, /* Function Key 11 */ | |
114 | + [0x114] = 88, /* Function Key 12 */ | |
115 | + | |
116 | + [0x106] = 71 | GREY, /* Home */ | |
117 | + [0x103] = 72 | GREY, /* Up Arrow */ | |
118 | + [0x153] = 73 | GREY, /* Page Up */ | |
119 | + [0x104] = 75 | GREY, /* Left Arrow */ | |
120 | + [0x105] = 77 | GREY, /* Right Arrow */ | |
121 | + [0x168] = 79 | GREY, /* End */ | |
122 | + [0x102] = 80 | GREY, /* Down Arrow */ | |
123 | + [0x152] = 81 | GREY, /* Page Down */ | |
124 | + [0x14b] = 82 | GREY, /* Insert */ | |
125 | + [0x14a] = 83 | GREY, /* Delete */ | |
126 | + | |
127 | + ['!'] = 2 | SHIFT, | |
128 | + ['@'] = 3 | SHIFT, | |
129 | + ['#'] = 4 | SHIFT, | |
130 | + ['$'] = 5 | SHIFT, | |
131 | + ['%'] = 6 | SHIFT, | |
132 | + ['^'] = 7 | SHIFT, | |
133 | + ['&'] = 8 | SHIFT, | |
134 | + ['*'] = 9 | SHIFT, | |
135 | + ['('] = 10 | SHIFT, | |
136 | + [')'] = 11 | SHIFT, | |
137 | + ['_'] = 12 | SHIFT, | |
138 | + ['+'] = 13 | SHIFT, | |
139 | + | |
140 | + [0x161] = 15 | SHIFT, /* Shift + Tab */ | |
141 | + ['Q'] = 16 | SHIFT, | |
142 | + ['W'] = 17 | SHIFT, | |
143 | + ['E'] = 18 | SHIFT, | |
144 | + ['R'] = 19 | SHIFT, | |
145 | + ['T'] = 20 | SHIFT, | |
146 | + ['Y'] = 21 | SHIFT, | |
147 | + ['U'] = 22 | SHIFT, | |
148 | + ['I'] = 23 | SHIFT, | |
149 | + ['O'] = 24 | SHIFT, | |
150 | + ['P'] = 25 | SHIFT, | |
151 | + ['{'] = 26 | SHIFT, | |
152 | + ['}'] = 27 | SHIFT, | |
153 | + | |
154 | + ['A'] = 30 | SHIFT, | |
155 | + ['S'] = 31 | SHIFT, | |
156 | + ['D'] = 32 | SHIFT, | |
157 | + ['F'] = 33 | SHIFT, | |
158 | + ['G'] = 34 | SHIFT, | |
159 | + ['H'] = 35 | SHIFT, | |
160 | + ['J'] = 36 | SHIFT, | |
161 | + ['K'] = 37 | SHIFT, | |
162 | + ['L'] = 38 | SHIFT, | |
163 | + [':'] = 39 | SHIFT, | |
164 | + ['"'] = 40 | SHIFT, | |
165 | + ['~'] = 41 | SHIFT, | |
166 | + ['|'] = 43 | SHIFT, | |
167 | + | |
168 | + ['Z'] = 44 | SHIFT, | |
169 | + ['X'] = 45 | SHIFT, | |
170 | + ['C'] = 46 | SHIFT, | |
171 | + ['V'] = 47 | SHIFT, | |
172 | + ['B'] = 48 | SHIFT, | |
173 | + ['N'] = 49 | SHIFT, | |
174 | + ['M'] = 50 | SHIFT, | |
175 | + ['<'] = 51 | SHIFT, | |
176 | + ['>'] = 52 | SHIFT, | |
177 | + ['?'] = 53 | SHIFT, | |
178 | + | |
179 | + [0x115] = 59 | SHIFT, /* Shift + Function Key 1 */ | |
180 | + [0x116] = 60 | SHIFT, /* Shift + Function Key 2 */ | |
181 | + [0x117] = 61 | SHIFT, /* Shift + Function Key 3 */ | |
182 | + [0x118] = 62 | SHIFT, /* Shift + Function Key 4 */ | |
183 | + [0x119] = 63 | SHIFT, /* Shift + Function Key 5 */ | |
184 | + [0x11a] = 64 | SHIFT, /* Shift + Function Key 6 */ | |
185 | + [0x11b] = 65 | SHIFT, /* Shift + Function Key 7 */ | |
186 | + [0x11c] = 66 | SHIFT, /* Shift + Function Key 8 */ | |
187 | + | |
188 | + [0x011] = 16 | CNTRL, /* Control + q */ | |
189 | + [0x017] = 17 | CNTRL, /* Control + w */ | |
190 | + [0x005] = 18 | CNTRL, /* Control + e */ | |
191 | + [0x012] = 19 | CNTRL, /* Control + r */ | |
192 | + [0x014] = 20 | CNTRL, /* Control + t */ | |
193 | + [0x019] = 21 | CNTRL, /* Control + y */ | |
194 | + [0x015] = 22 | CNTRL, /* Control + u */ | |
195 | + [0x009] = 23 | CNTRL, /* Control + i */ | |
196 | + [0x00f] = 24 | CNTRL, /* Control + o */ | |
197 | + [0x010] = 25 | CNTRL, /* Control + p */ | |
198 | + | |
199 | + [0x001] = 30 | CNTRL, /* Control + a */ | |
200 | + [0x013] = 31 | CNTRL, /* Control + s */ | |
201 | + [0x014] = 32 | CNTRL, /* Control + d */ | |
202 | + [0x006] = 33 | CNTRL, /* Control + f */ | |
203 | + [0x007] = 34 | CNTRL, /* Control + g */ | |
204 | + [0x008] = 35 | CNTRL, /* Control + h */ | |
205 | + [0x00a] = 36 | CNTRL, /* Control + j */ | |
206 | + [0x00b] = 37 | CNTRL, /* Control + k */ | |
207 | + [0x00c] = 38 | CNTRL, /* Control + l */ | |
208 | + | |
209 | + [0x01a] = 44 | CNTRL, /* Control + z */ | |
210 | + [0x018] = 45 | CNTRL, /* Control + x */ | |
211 | + [0x003] = 46 | CNTRL, /* Control + c */ | |
212 | + [0x016] = 47 | CNTRL, /* Control + v */ | |
213 | + [0x002] = 48 | CNTRL, /* Control + b */ | |
214 | + [0x00e] = 49 | CNTRL, /* Control + n */ | |
215 | + /* Control + m collides with the keycode for Enter */ | |
216 | + | |
217 | +}; | |
218 | + | |
219 | +int curses2keysym[CURSES_KEYS] = { | |
220 | + [0 ... (CURSES_KEYS - 1)] = -1, | |
221 | + | |
222 | + ['\n'] = '\n', | |
223 | + ['\r'] = '\n', | |
224 | + | |
225 | + [0x07f] = QEMU_KEY_BACKSPACE, | |
226 | + | |
227 | + [0x102] = QEMU_KEY_DOWN, | |
228 | + [0x103] = QEMU_KEY_UP, | |
229 | + [0x104] = QEMU_KEY_LEFT, | |
230 | + [0x105] = QEMU_KEY_RIGHT, | |
231 | + [0x106] = QEMU_KEY_HOME, | |
232 | + [0x107] = QEMU_KEY_BACKSPACE, | |
233 | + | |
234 | + [0x14a] = QEMU_KEY_DELETE, | |
235 | + [0x152] = QEMU_KEY_PAGEDOWN, | |
236 | + [0x153] = QEMU_KEY_PAGEUP, | |
237 | + [0x157] = '\n', | |
238 | + [0x168] = QEMU_KEY_END, | |
239 | + | |
240 | +}; | |
241 | + | |
242 | +typedef struct { | |
243 | + const char* name; | |
244 | + int keysym; | |
245 | +} name2keysym_t; | |
246 | + | |
247 | +static name2keysym_t name2keysym[] = { | |
248 | + /* Plain ASCII */ | |
249 | + { "space", 0x020 }, | |
250 | + { "exclam", 0x021 }, | |
251 | + { "quotedbl", 0x022 }, | |
252 | + { "numbersign", 0x023 }, | |
253 | + { "dollar", 0x024 }, | |
254 | + { "percent", 0x025 }, | |
255 | + { "ampersand", 0x026 }, | |
256 | + { "apostrophe", 0x027 }, | |
257 | + { "parenleft", 0x028 }, | |
258 | + { "parenright", 0x029 }, | |
259 | + { "asterisk", 0x02a }, | |
260 | + { "plus", 0x02b }, | |
261 | + { "comma", 0x02c }, | |
262 | + { "minus", 0x02d }, | |
263 | + { "period", 0x02e }, | |
264 | + { "slash", 0x02f }, | |
265 | + { "0", 0x030 }, | |
266 | + { "1", 0x031 }, | |
267 | + { "2", 0x032 }, | |
268 | + { "3", 0x033 }, | |
269 | + { "4", 0x034 }, | |
270 | + { "5", 0x035 }, | |
271 | + { "6", 0x036 }, | |
272 | + { "7", 0x037 }, | |
273 | + { "8", 0x038 }, | |
274 | + { "9", 0x039 }, | |
275 | + { "colon", 0x03a }, | |
276 | + { "semicolon", 0x03b }, | |
277 | + { "less", 0x03c }, | |
278 | + { "equal", 0x03d }, | |
279 | + { "greater", 0x03e }, | |
280 | + { "question", 0x03f }, | |
281 | + { "at", 0x040 }, | |
282 | + { "A", 0x041 }, | |
283 | + { "B", 0x042 }, | |
284 | + { "C", 0x043 }, | |
285 | + { "D", 0x044 }, | |
286 | + { "E", 0x045 }, | |
287 | + { "F", 0x046 }, | |
288 | + { "G", 0x047 }, | |
289 | + { "H", 0x048 }, | |
290 | + { "I", 0x049 }, | |
291 | + { "J", 0x04a }, | |
292 | + { "K", 0x04b }, | |
293 | + { "L", 0x04c }, | |
294 | + { "M", 0x04d }, | |
295 | + { "N", 0x04e }, | |
296 | + { "O", 0x04f }, | |
297 | + { "P", 0x050 }, | |
298 | + { "Q", 0x051 }, | |
299 | + { "R", 0x052 }, | |
300 | + { "S", 0x053 }, | |
301 | + { "T", 0x054 }, | |
302 | + { "U", 0x055 }, | |
303 | + { "V", 0x056 }, | |
304 | + { "W", 0x057 }, | |
305 | + { "X", 0x058 }, | |
306 | + { "Y", 0x059 }, | |
307 | + { "Z", 0x05a }, | |
308 | + { "bracketleft", 0x05b }, | |
309 | + { "backslash", 0x05c }, | |
310 | + { "bracketright", 0x05d }, | |
311 | + { "asciicircum", 0x05e }, | |
312 | + { "underscore", 0x05f }, | |
313 | + { "grave", 0x060 }, | |
314 | + { "a", 0x061 }, | |
315 | + { "b", 0x062 }, | |
316 | + { "c", 0x063 }, | |
317 | + { "d", 0x064 }, | |
318 | + { "e", 0x065 }, | |
319 | + { "f", 0x066 }, | |
320 | + { "g", 0x067 }, | |
321 | + { "h", 0x068 }, | |
322 | + { "i", 0x069 }, | |
323 | + { "j", 0x06a }, | |
324 | + { "k", 0x06b }, | |
325 | + { "l", 0x06c }, | |
326 | + { "m", 0x06d }, | |
327 | + { "n", 0x06e }, | |
328 | + { "o", 0x06f }, | |
329 | + { "p", 0x070 }, | |
330 | + { "q", 0x071 }, | |
331 | + { "r", 0x072 }, | |
332 | + { "s", 0x073 }, | |
333 | + { "t", 0x074 }, | |
334 | + { "u", 0x075 }, | |
335 | + { "v", 0x076 }, | |
336 | + { "w", 0x077 }, | |
337 | + { "x", 0x078 }, | |
338 | + { "y", 0x079 }, | |
339 | + { "z", 0x07a }, | |
340 | + { "braceleft", 0x07b }, | |
341 | + { "bar", 0x07c }, | |
342 | + { "braceright", 0x07d }, | |
343 | + { "asciitilde", 0x07e }, | |
344 | + | |
345 | + /* Latin-1 extensions */ | |
346 | + { "nobreakspace", 0x0a0 }, | |
347 | + { "exclamdown", 0x0a1 }, | |
348 | + { "cent", 0x0a2 }, | |
349 | + { "sterling", 0x0a3 }, | |
350 | + { "currency", 0x0a4 }, | |
351 | + { "yen", 0x0a5 }, | |
352 | + { "brokenbar", 0x0a6 }, | |
353 | + { "section", 0x0a7 }, | |
354 | + { "diaeresis", 0x0a8 }, | |
355 | + { "copyright", 0x0a9 }, | |
356 | + { "ordfeminine", 0x0aa }, | |
357 | + { "guillemotleft", 0x0ab }, | |
358 | + { "notsign", 0x0ac }, | |
359 | + { "hyphen", 0x0ad }, | |
360 | + { "registered", 0x0ae }, | |
361 | + { "macron", 0x0af }, | |
362 | + { "degree", 0x0b0 }, | |
363 | + { "plusminus", 0x0b1 }, | |
364 | + { "twosuperior", 0x0b2 }, | |
365 | + { "threesuperior", 0x0b3 }, | |
366 | + { "acute", 0x0b4 }, | |
367 | + { "mu", 0x0b5 }, | |
368 | + { "paragraph", 0x0b6 }, | |
369 | + { "periodcentered", 0x0b7 }, | |
370 | + { "cedilla", 0x0b8 }, | |
371 | + { "onesuperior", 0x0b9 }, | |
372 | + { "masculine", 0x0ba }, | |
373 | + { "guillemotright", 0x0bb }, | |
374 | + { "onequarter", 0x0bc }, | |
375 | + { "onehalf", 0x0bd }, | |
376 | + { "threequarters", 0x0be }, | |
377 | + { "questiondown", 0x0bf }, | |
378 | + { "Agrave", 0x0c0 }, | |
379 | + { "Aacute", 0x0c1 }, | |
380 | + { "Acircumflex", 0x0c2 }, | |
381 | + { "Atilde", 0x0c3 }, | |
382 | + { "Adiaeresis", 0x0c4 }, | |
383 | + { "Aring", 0x0c5 }, | |
384 | + { "AE", 0x0c6 }, | |
385 | + { "Ccedilla", 0x0c7 }, | |
386 | + { "Egrave", 0x0c8 }, | |
387 | + { "Eacute", 0x0c9 }, | |
388 | + { "Ecircumflex", 0x0ca }, | |
389 | + { "Ediaeresis", 0x0cb }, | |
390 | + { "Igrave", 0x0cc }, | |
391 | + { "Iacute", 0x0cd }, | |
392 | + { "Icircumflex", 0x0ce }, | |
393 | + { "Idiaeresis", 0x0cf }, | |
394 | + { "ETH", 0x0d0 }, | |
395 | + { "Eth", 0x0d0 }, | |
396 | + { "Ntilde", 0x0d1 }, | |
397 | + { "Ograve", 0x0d2 }, | |
398 | + { "Oacute", 0x0d3 }, | |
399 | + { "Ocircumflex", 0x0d4 }, | |
400 | + { "Otilde", 0x0d5 }, | |
401 | + { "Odiaeresis", 0x0d6 }, | |
402 | + { "multiply", 0x0d7 }, | |
403 | + { "Ooblique", 0x0d8 }, | |
404 | + { "Oslash", 0x0d8 }, | |
405 | + { "Ugrave", 0x0d9 }, | |
406 | + { "Uacute", 0x0da }, | |
407 | + { "Ucircumflex", 0x0db }, | |
408 | + { "Udiaeresis", 0x0dc }, | |
409 | + { "Yacute", 0x0dd }, | |
410 | + { "THORN", 0x0de }, | |
411 | + { "Thorn", 0x0de }, | |
412 | + { "ssharp", 0x0df }, | |
413 | + { "agrave", 0x0e0 }, | |
414 | + { "aacute", 0x0e1 }, | |
415 | + { "acircumflex", 0x0e2 }, | |
416 | + { "atilde", 0x0e3 }, | |
417 | + { "adiaeresis", 0x0e4 }, | |
418 | + { "aring", 0x0e5 }, | |
419 | + { "ae", 0x0e6 }, | |
420 | + { "ccedilla", 0x0e7 }, | |
421 | + { "egrave", 0x0e8 }, | |
422 | + { "eacute", 0x0e9 }, | |
423 | + { "ecircumflex", 0x0ea }, | |
424 | + { "ediaeresis", 0x0eb }, | |
425 | + { "igrave", 0x0ec }, | |
426 | + { "iacute", 0x0ed }, | |
427 | + { "icircumflex", 0x0ee }, | |
428 | + { "idiaeresis", 0x0ef }, | |
429 | + { "eth", 0x0f0 }, | |
430 | + { "ntilde", 0x0f1 }, | |
431 | + { "ograve", 0x0f2 }, | |
432 | + { "oacute", 0x0f3 }, | |
433 | + { "ocircumflex", 0x0f4 }, | |
434 | + { "otilde", 0x0f5 }, | |
435 | + { "odiaeresis", 0x0f6 }, | |
436 | + { "division", 0x0f7 }, | |
437 | + { "oslash", 0x0f8 }, | |
438 | + { "ooblique", 0x0f8 }, | |
439 | + { "ugrave", 0x0f9 }, | |
440 | + { "uacute", 0x0fa }, | |
441 | + { "ucircumflex", 0x0fb }, | |
442 | + { "udiaeresis", 0x0fc }, | |
443 | + { "yacute", 0x0fd }, | |
444 | + { "thorn", 0x0fe }, | |
445 | + { "ydiaeresis", 0x0ff }, | |
446 | + | |
447 | + /* Special keys */ | |
448 | + { "BackSpace", 0x07f }, | |
449 | + { "Tab", '\t' }, | |
450 | + { "Return", '\r' }, | |
451 | + { "Right", 0x105 }, | |
452 | + { "Left", 0x104 }, | |
453 | + { "Up", 0x103 }, | |
454 | + { "Down", 0x102 }, | |
455 | + { "Page_Down", 0x152 }, | |
456 | + { "Page_Up", 0x153 }, | |
457 | + { "Insert", 0x14b }, | |
458 | + { "Delete", 0x14a }, | |
459 | + { "Home", 0x106 }, | |
460 | + { "End", 0x168 }, | |
461 | + { "F1", 0x109 }, | |
462 | + { "F2", 0x10a }, | |
463 | + { "F3", 0x10b }, | |
464 | + { "F4", 0x10c }, | |
465 | + { "F5", 0x10d }, | |
466 | + { "F6", 0x10e }, | |
467 | + { "F7", 0x10f }, | |
468 | + { "F8", 0x110 }, | |
469 | + { "F9", 0x111 }, | |
470 | + { "F10", 0x112 }, | |
471 | + { "F11", 0x113 }, | |
472 | + { "F12", 0x114 }, | |
473 | + { "F13", 0x115 }, | |
474 | + { "F14", 0x116 }, | |
475 | + { "F15", 0x117 }, | |
476 | + { "F16", 0x118 }, | |
477 | + { "F17", 0x119 }, | |
478 | + { "F18", 0x11a }, | |
479 | + { "F19", 0x11b }, | |
480 | + { "F20", 0x11c }, | |
481 | + { "Escape", 27 }, | |
482 | + | |
483 | + { 0, 0 }, | |
484 | +}; | ... | ... |
hw/cirrus_vga.c
... | ... | @@ -3257,7 +3257,8 @@ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, |
3257 | 3257 | ds, vga_ram_base, vga_ram_offset, vga_ram_size); |
3258 | 3258 | cirrus_init_common(s, device_id, 1); |
3259 | 3259 | |
3260 | - graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); | |
3260 | + graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, | |
3261 | + s->text_update, s); | |
3261 | 3262 | |
3262 | 3263 | s->pci_dev = (PCIDevice *)d; |
3263 | 3264 | ... | ... |
hw/jazz_led.c
... | ... | @@ -285,6 +285,22 @@ static void jazz_led_screen_dump(void *opaque, const char *filename) |
285 | 285 | printf("jazz_led_screen_dump() not implemented\n"); |
286 | 286 | } |
287 | 287 | |
288 | +static void jazz_led_text_update(void *opaque, console_ch_t *chardata) | |
289 | +{ | |
290 | + LedState *s = opaque; | |
291 | + char buf[2]; | |
292 | + | |
293 | + dpy_cursor(s->ds, -1, -1); | |
294 | + dpy_resize(s->ds, 2, 1); | |
295 | + | |
296 | + /* TODO: draw the segments */ | |
297 | + snprintf(buf, 2, "%02hhx\n", s->segments); | |
298 | + console_write_ch(chardata++, 0x00200100 | buf[0]); | |
299 | + console_write_ch(chardata++, 0x00200100 | buf[1]); | |
300 | + | |
301 | + dpy_update(s->ds, 0, 0, 2, 1); | |
302 | +} | |
303 | + | |
288 | 304 | void jazz_led_init(DisplayState *ds, target_phys_addr_t base) |
289 | 305 | { |
290 | 306 | LedState *s; |
... | ... | @@ -301,5 +317,7 @@ void jazz_led_init(DisplayState *ds, target_phys_addr_t base) |
301 | 317 | io = cpu_register_io_memory(0, led_read, led_write, s); |
302 | 318 | cpu_register_physical_memory(s->base, 1, io); |
303 | 319 | |
304 | - graphic_console_init(ds, jazz_led_update_display, jazz_led_invalidate_display, jazz_led_screen_dump, s); | |
320 | + graphic_console_init(ds, jazz_led_update_display, | |
321 | + jazz_led_invalidate_display, jazz_led_screen_dump, | |
322 | + jazz_led_text_update, s); | |
305 | 323 | } | ... | ... |
hw/omap_lcdc.c
... | ... | @@ -495,7 +495,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq, |
495 | 495 | cpu_register_physical_memory(s->base, 0x100, iomemtype); |
496 | 496 | |
497 | 497 | graphic_console_init(ds, omap_update_display, |
498 | - omap_invalidate_display, omap_screen_dump, s); | |
498 | + omap_invalidate_display, omap_screen_dump, NULL, s); | |
499 | 499 | |
500 | 500 | return s; |
501 | 501 | } | ... | ... |
hw/pl110.c
... | ... | @@ -426,7 +426,7 @@ void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq, |
426 | 426 | s->versatile = versatile; |
427 | 427 | s->irq = irq; |
428 | 428 | graphic_console_init(ds, pl110_update_display, pl110_invalidate_display, |
429 | - NULL, s); | |
429 | + NULL, NULL, s); | |
430 | 430 | /* ??? Save/restore. */ |
431 | 431 | return s; |
432 | 432 | } | ... | ... |
hw/pxa2xx_lcd.c
... | ... | @@ -1002,7 +1002,7 @@ struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq, |
1002 | 1002 | cpu_register_physical_memory(base, 0x00100000, iomemtype); |
1003 | 1003 | |
1004 | 1004 | graphic_console_init(ds, pxa2xx_update_display, |
1005 | - pxa2xx_invalidate_display, pxa2xx_screen_dump, s); | |
1005 | + pxa2xx_invalidate_display, pxa2xx_screen_dump, NULL, s); | |
1006 | 1006 | |
1007 | 1007 | switch (s->ds->depth) { |
1008 | 1008 | case 0: | ... | ... |
hw/ssd0303.c
... | ... | @@ -270,6 +270,6 @@ void ssd0303_init(DisplayState *ds, i2c_bus *bus, int address) |
270 | 270 | s->i2c.recv = ssd0303_recv; |
271 | 271 | s->i2c.send = ssd0303_send; |
272 | 272 | graphic_console_init(ds, ssd0303_update_display, ssd0303_invalidate_display, |
273 | - NULL, s); | |
273 | + NULL, NULL, s); | |
274 | 274 | dpy_resize(s->ds, 96 * MAGNIFY, 16 * MAGNIFY); |
275 | 275 | } | ... | ... |
hw/ssd0323.c
... | ... | @@ -280,7 +280,7 @@ void *ssd0323_init(DisplayState *ds, qemu_irq *cmd_p) |
280 | 280 | s = (ssd0323_state *)qemu_mallocz(sizeof(ssd0323_state)); |
281 | 281 | s->ds = ds; |
282 | 282 | graphic_console_init(ds, ssd0323_update_display, ssd0323_invalidate_display, |
283 | - NULL, s); | |
283 | + NULL, NULL, s); | |
284 | 284 | dpy_resize(s->ds, 128 * MAGNIFY, 64 * MAGNIFY); |
285 | 285 | s->col_end = 63; |
286 | 286 | s->row_end = 79; | ... | ... |
hw/tcx.c
... | ... | @@ -537,12 +537,13 @@ void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base, |
537 | 537 | s->cplane_offset = vram_offset; |
538 | 538 | cpu_register_physical_memory(addr + 0x0a000000ULL, size, vram_offset); |
539 | 539 | graphic_console_init(s->ds, tcx24_update_display, |
540 | - tcx24_invalidate_display, tcx24_screen_dump, s); | |
540 | + tcx24_invalidate_display, | |
541 | + tcx24_screen_dump, NULL, s); | |
541 | 542 | } else { |
542 | 543 | cpu_register_physical_memory(addr + 0x00300000ULL, TCX_THC_NREGS_8, |
543 | 544 | dummy_memory); |
544 | 545 | graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display, |
545 | - tcx_screen_dump, s); | |
546 | + tcx_screen_dump, NULL, s); | |
546 | 547 | } |
547 | 548 | // NetBSD writes here even with 8-bit display |
548 | 549 | cpu_register_physical_memory(addr + 0x00301000ULL, TCX_THC_NREGS_24, | ... | ... |
hw/vga.c
... | ... | @@ -1660,6 +1660,165 @@ static void vga_reset(VGAState *s) |
1660 | 1660 | s->graphic_mode = -1; /* force full update */ |
1661 | 1661 | } |
1662 | 1662 | |
1663 | +#define TEXTMODE_X(x) ((x) % width) | |
1664 | +#define TEXTMODE_Y(x) ((x) / width) | |
1665 | +#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \ | |
1666 | + ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1)) | |
1667 | +/* relay text rendering to the display driver | |
1668 | + * instead of doing a full vga_update_display() */ | |
1669 | +static void vga_update_text(void *opaque, console_ch_t *chardata) | |
1670 | +{ | |
1671 | + VGAState *s = (VGAState *) opaque; | |
1672 | + int graphic_mode, i, cursor_offset, cursor_visible; | |
1673 | + int cw, cheight, width, height, size, c_min, c_max; | |
1674 | + uint32_t *src; | |
1675 | + console_ch_t *dst, val; | |
1676 | + char msg_buffer[80]; | |
1677 | + int full_update; | |
1678 | + full_update = 0; | |
1679 | + | |
1680 | + if (!(s->ar_index & 0x20)) { | |
1681 | + graphic_mode = GMODE_BLANK; | |
1682 | + } else { | |
1683 | + graphic_mode = s->gr[6] & 1; | |
1684 | + } | |
1685 | + if (graphic_mode != s->graphic_mode) { | |
1686 | + s->graphic_mode = graphic_mode; | |
1687 | + full_update = 1; | |
1688 | + } | |
1689 | + if (s->last_width == -1) { | |
1690 | + s->last_width = 0; | |
1691 | + full_update = 1; | |
1692 | + } | |
1693 | + | |
1694 | + switch (graphic_mode) { | |
1695 | + case GMODE_TEXT: | |
1696 | + /* TODO: update palette */ | |
1697 | + full_update |= update_basic_params(s); | |
1698 | + | |
1699 | + /* total width & height */ | |
1700 | + cheight = (s->cr[9] & 0x1f) + 1; | |
1701 | + cw = 8; | |
1702 | + if (!(s->sr[1] & 0x01)) | |
1703 | + cw = 9; | |
1704 | + if (s->sr[1] & 0x08) | |
1705 | + cw = 16; /* NOTE: no 18 pixel wide */ | |
1706 | + width = (s->cr[0x01] + 1); | |
1707 | + if (s->cr[0x06] == 100) { | |
1708 | + /* ugly hack for CGA 160x100x16 - explain me the logic */ | |
1709 | + height = 100; | |
1710 | + } else { | |
1711 | + height = s->cr[0x12] | | |
1712 | + ((s->cr[0x07] & 0x02) << 7) | | |
1713 | + ((s->cr[0x07] & 0x40) << 3); | |
1714 | + height = (height + 1) / cheight; | |
1715 | + } | |
1716 | + | |
1717 | + size = (height * width); | |
1718 | + if (size > CH_ATTR_SIZE) { | |
1719 | + if (!full_update) | |
1720 | + return; | |
1721 | + | |
1722 | + sprintf(msg_buffer, "%i x %i Text mode", width, height); | |
1723 | + break; | |
1724 | + } | |
1725 | + | |
1726 | + if (width != s->last_width || height != s->last_height || | |
1727 | + cw != s->last_cw || cheight != s->last_ch) { | |
1728 | + s->last_scr_width = width * cw; | |
1729 | + s->last_scr_height = height * cheight; | |
1730 | + dpy_resize(s->ds, width, height); | |
1731 | + s->last_width = width; | |
1732 | + s->last_height = height; | |
1733 | + s->last_ch = cheight; | |
1734 | + s->last_cw = cw; | |
1735 | + full_update = 1; | |
1736 | + } | |
1737 | + | |
1738 | + /* Update "hardware" cursor */ | |
1739 | + cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr; | |
1740 | + if (cursor_offset != s->cursor_offset || | |
1741 | + s->cr[0xa] != s->cursor_start || | |
1742 | + s->cr[0xb] != s->cursor_end || full_update) { | |
1743 | + cursor_visible = !(s->cr[0xa] & 0x20); | |
1744 | + if (cursor_visible && cursor_offset < size && cursor_offset >= 0) | |
1745 | + dpy_cursor(s->ds, | |
1746 | + TEXTMODE_X(cursor_offset), | |
1747 | + TEXTMODE_Y(cursor_offset)); | |
1748 | + else | |
1749 | + dpy_cursor(s->ds, -1, -1); | |
1750 | + s->cursor_offset = cursor_offset; | |
1751 | + s->cursor_start = s->cr[0xa]; | |
1752 | + s->cursor_end = s->cr[0xb]; | |
1753 | + } | |
1754 | + | |
1755 | + src = (uint32_t *) s->vram_ptr + s->start_addr; | |
1756 | + dst = chardata; | |
1757 | + | |
1758 | + if (full_update) { | |
1759 | + for (i = 0; i < size; src ++, dst ++, i ++) | |
1760 | + console_write_ch(dst, VMEM2CHTYPE(*src)); | |
1761 | + | |
1762 | + dpy_update(s->ds, 0, 0, width, height); | |
1763 | + } else { | |
1764 | + c_max = 0; | |
1765 | + | |
1766 | + for (i = 0; i < size; src ++, dst ++, i ++) { | |
1767 | + console_write_ch(&val, VMEM2CHTYPE(*src)); | |
1768 | + if (*dst != val) { | |
1769 | + *dst = val; | |
1770 | + c_max = i; | |
1771 | + break; | |
1772 | + } | |
1773 | + } | |
1774 | + c_min = i; | |
1775 | + for (; i < size; src ++, dst ++, i ++) { | |
1776 | + console_write_ch(&val, VMEM2CHTYPE(*src)); | |
1777 | + if (*dst != val) { | |
1778 | + *dst = val; | |
1779 | + c_max = i; | |
1780 | + } | |
1781 | + } | |
1782 | + | |
1783 | + if (c_min <= c_max) { | |
1784 | + i = TEXTMODE_Y(c_min); | |
1785 | + dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1); | |
1786 | + } | |
1787 | + } | |
1788 | + | |
1789 | + return; | |
1790 | + case GMODE_GRAPH: | |
1791 | + if (!full_update) | |
1792 | + return; | |
1793 | + | |
1794 | + s->get_resolution(s, &width, &height); | |
1795 | + sprintf(msg_buffer, "%i x %i Graphic mode", width, height); | |
1796 | + break; | |
1797 | + case GMODE_BLANK: | |
1798 | + default: | |
1799 | + if (!full_update) | |
1800 | + return; | |
1801 | + | |
1802 | + sprintf(msg_buffer, "VGA Blank mode"); | |
1803 | + break; | |
1804 | + } | |
1805 | + | |
1806 | + /* Display a message */ | |
1807 | + dpy_cursor(s->ds, -1, -1); | |
1808 | + dpy_resize(s->ds, 60, 3); | |
1809 | + | |
1810 | + for (dst = chardata, i = 0; i < 60 * 3; i ++) | |
1811 | + console_write_ch(dst ++, ' '); | |
1812 | + | |
1813 | + size = strlen(msg_buffer); | |
1814 | + width = (60 - size) / 2; | |
1815 | + dst = chardata + 60 + width; | |
1816 | + for (i = 0; i < size; i ++) | |
1817 | + console_write_ch(dst ++, 0x00200100 | msg_buffer[i]); | |
1818 | + | |
1819 | + dpy_update(s->ds, 0, 0, 60, 3); | |
1820 | +} | |
1821 | + | |
1663 | 1822 | static CPUReadMemoryFunc *vga_mem_read[3] = { |
1664 | 1823 | vga_mem_readb, |
1665 | 1824 | vga_mem_readw, |
... | ... | @@ -1830,6 +1989,7 @@ void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, |
1830 | 1989 | s->update = vga_update_display; |
1831 | 1990 | s->invalidate = vga_invalidate_display; |
1832 | 1991 | s->screen_dump = vga_screen_dump; |
1992 | + s->text_update = vga_update_text; | |
1833 | 1993 | } |
1834 | 1994 | |
1835 | 1995 | /* used by both ISA and PCI */ |
... | ... | @@ -1971,7 +2131,8 @@ int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, |
1971 | 2131 | vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); |
1972 | 2132 | vga_init(s); |
1973 | 2133 | |
1974 | - graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); | |
2134 | + graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, | |
2135 | + s->text_update, s); | |
1975 | 2136 | |
1976 | 2137 | #ifdef CONFIG_BOCHS_VBE |
1977 | 2138 | /* XXX: use optimized standard vga accesses */ |
... | ... | @@ -1995,7 +2156,8 @@ int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base, |
1995 | 2156 | vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); |
1996 | 2157 | vga_mm_init(s, vram_base, ctrl_base, it_shift); |
1997 | 2158 | |
1998 | - graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); | |
2159 | + graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, | |
2160 | + s->text_update, s); | |
1999 | 2161 | |
2000 | 2162 | #ifdef CONFIG_BOCHS_VBE |
2001 | 2163 | /* XXX: use optimized standard vga accesses */ |
... | ... | @@ -2023,7 +2185,8 @@ int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, |
2023 | 2185 | vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); |
2024 | 2186 | vga_init(s); |
2025 | 2187 | |
2026 | - graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s); | |
2188 | + graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, | |
2189 | + s->text_update, s); | |
2027 | 2190 | |
2028 | 2191 | s->pci_dev = &d->dev; |
2029 | 2192 | ... | ... |
hw/vga_int.h
... | ... | @@ -139,6 +139,7 @@ |
139 | 139 | vga_hw_update_ptr update; \ |
140 | 140 | vga_hw_invalidate_ptr invalidate; \ |
141 | 141 | vga_hw_screen_dump_ptr screen_dump; \ |
142 | + vga_hw_text_update_ptr text_update; \ | |
142 | 143 | /* hardware mouse cursor support */ \ |
143 | 144 | uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32]; \ |
144 | 145 | void (*cursor_invalidate)(struct VGAState *s); \ | ... | ... |
hw/vmware_vga.c
... | ... | @@ -949,6 +949,14 @@ static void vmsvga_screen_dump(void *opaque, const char *filename) |
949 | 949 | } |
950 | 950 | } |
951 | 951 | |
952 | +static void vmsvga_text_update(void *opaque, console_ch_t *chardata) | |
953 | +{ | |
954 | + struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque; | |
955 | + | |
956 | + if (s->text_update) | |
957 | + s->text_update(opaque, chardata); | |
958 | +} | |
959 | + | |
952 | 960 | #ifdef DIRECT_VRAM |
953 | 961 | static uint32_t vmsvga_vram_readb(void *opaque, target_phys_addr_t addr) |
954 | 962 | { |
... | ... | @@ -1101,7 +1109,8 @@ static void vmsvga_init(struct vmsvga_state_s *s, DisplayState *ds, |
1101 | 1109 | iomemtype); |
1102 | 1110 | |
1103 | 1111 | graphic_console_init(ds, vmsvga_update_display, |
1104 | - vmsvga_invalidate_display, vmsvga_screen_dump, s); | |
1112 | + vmsvga_invalidate_display, vmsvga_screen_dump, | |
1113 | + vmsvga_text_update, s); | |
1105 | 1114 | |
1106 | 1115 | #ifdef EMBED_STDVGA |
1107 | 1116 | vga_common_init((VGAState *) s, ds, | ... | ... |
monitor.c
vl.c
... | ... | @@ -172,6 +172,7 @@ BlockDriverState *bs_snapshots; |
172 | 172 | int vga_ram_size; |
173 | 173 | static DisplayState display_state; |
174 | 174 | int nographic; |
175 | +int curses; | |
175 | 176 | const char* keyboard_layout = NULL; |
176 | 177 | int64_t ticks_per_sec; |
177 | 178 | int ram_size; |
... | ... | @@ -7652,6 +7653,9 @@ static void help(int exitcode) |
7652 | 7653 | " (default is CL-GD5446 PCI VGA)\n" |
7653 | 7654 | "-no-acpi disable ACPI\n" |
7654 | 7655 | #endif |
7656 | +#ifdef CONFIG_CURSES | |
7657 | + "-curses use a curses/ncurses interface instead of SDL\n" | |
7658 | +#endif | |
7655 | 7659 | "-no-reboot exit instead of rebooting\n" |
7656 | 7660 | "-loadvm file start right away with a saved state (loadvm in monitor)\n" |
7657 | 7661 | "-vnc display start a VNC server on display\n" |
... | ... | @@ -7757,6 +7761,7 @@ enum { |
7757 | 7761 | QEMU_OPTION_smp, |
7758 | 7762 | QEMU_OPTION_vnc, |
7759 | 7763 | QEMU_OPTION_no_acpi, |
7764 | + QEMU_OPTION_curses, | |
7760 | 7765 | QEMU_OPTION_no_reboot, |
7761 | 7766 | QEMU_OPTION_show_cursor, |
7762 | 7767 | QEMU_OPTION_daemonize, |
... | ... | @@ -7853,6 +7858,9 @@ const QEMUOption qemu_options[] = { |
7853 | 7858 | { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, |
7854 | 7859 | { "smp", HAS_ARG, QEMU_OPTION_smp }, |
7855 | 7860 | { "vnc", HAS_ARG, QEMU_OPTION_vnc }, |
7861 | +#ifdef CONFIG_CURSES | |
7862 | + { "curses", 0, QEMU_OPTION_curses }, | |
7863 | +#endif | |
7856 | 7864 | |
7857 | 7865 | /* temporary options */ |
7858 | 7866 | { "usb", 0, QEMU_OPTION_usb }, |
... | ... | @@ -8189,6 +8197,7 @@ int main(int argc, char **argv) |
8189 | 8197 | #endif |
8190 | 8198 | snapshot = 0; |
8191 | 8199 | nographic = 0; |
8200 | + curses = 0; | |
8192 | 8201 | kernel_filename = NULL; |
8193 | 8202 | kernel_cmdline = ""; |
8194 | 8203 | cyls = heads = secs = 0; |
... | ... | @@ -8363,6 +8372,11 @@ int main(int argc, char **argv) |
8363 | 8372 | pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); |
8364 | 8373 | nographic = 1; |
8365 | 8374 | break; |
8375 | +#ifdef CONFIG_CURSES | |
8376 | + case QEMU_OPTION_curses: | |
8377 | + curses = 1; | |
8378 | + break; | |
8379 | +#endif | |
8366 | 8380 | case QEMU_OPTION_portrait: |
8367 | 8381 | graphic_rotate = 1; |
8368 | 8382 | break; |
... | ... | @@ -8903,13 +8917,23 @@ int main(int argc, char **argv) |
8903 | 8917 | /* terminal init */ |
8904 | 8918 | memset(&display_state, 0, sizeof(display_state)); |
8905 | 8919 | if (nographic) { |
8920 | + if (curses) { | |
8921 | + fprintf(stderr, "fatal: -nographic can't be used with -curses\n"); | |
8922 | + exit(1); | |
8923 | + } | |
8906 | 8924 | /* nearly nothing to do */ |
8907 | 8925 | dumb_display_init(ds); |
8908 | 8926 | } else if (vnc_display != NULL) { |
8909 | 8927 | vnc_display_init(ds); |
8910 | 8928 | if (vnc_display_open(ds, vnc_display) < 0) |
8911 | 8929 | exit(1); |
8912 | - } else { | |
8930 | + } else | |
8931 | +#if defined(CONFIG_CURSES) | |
8932 | + if (curses) { | |
8933 | + curses_display_init(ds, full_screen); | |
8934 | + } else | |
8935 | +#endif | |
8936 | + { | |
8913 | 8937 | #if defined(CONFIG_SDL) |
8914 | 8938 | sdl_display_init(ds, full_screen, no_frame); |
8915 | 8939 | #elif defined(CONFIG_COCOA) | ... | ... |