]> git.proxmox.com Git - qemu.git/blame - console.c
Add missing dependencies for qemu-doc.* (Stefan Weil)
[qemu.git] / console.c
CommitLineData
e7f0ad58
FB
1/*
2 * QEMU graphical console
5fafdf24 3 *
e7f0ad58 4 * Copyright (c) 2004 Fabrice Bellard
5fafdf24 5 *
e7f0ad58
FB
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 */
87ecb68b
PB
24#include "qemu-common.h"
25#include "console.h"
26#include "qemu-timer.h"
e7f0ad58 27
6d6f7c28 28//#define DEBUG_CONSOLE
e7f0ad58
FB
29#define DEFAULT_BACKSCROLL 512
30#define MAX_CONSOLES 12
c60e08d9 31#define DEFAULT_MONITOR_SIZE "800x600"
e7f0ad58 32
26489844
FB
33#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
34#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
e7f0ad58 35
6d6f7c28
PB
36typedef struct TextAttributes {
37 uint8_t fgcol:4;
38 uint8_t bgcol:4;
39 uint8_t bold:1;
40 uint8_t uline:1;
41 uint8_t blink:1;
42 uint8_t invers:1;
43 uint8_t unvisible:1;
44} TextAttributes;
45
e7f0ad58
FB
46typedef struct TextCell {
47 uint8_t ch;
6d6f7c28 48 TextAttributes t_attrib;
e7f0ad58
FB
49} TextCell;
50
51#define MAX_ESC_PARAMS 3
52
53enum TTYState {
54 TTY_STATE_NORM,
55 TTY_STATE_ESC,
56 TTY_STATE_CSI,
57};
58
e15d7371
FB
59typedef struct QEMUFIFO {
60 uint8_t *buf;
61 int buf_size;
62 int count, wptr, rptr;
63} QEMUFIFO;
64
9596ebb7 65static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
e15d7371
FB
66{
67 int l, len;
68
69 l = f->buf_size - f->count;
70 if (len1 > l)
71 len1 = l;
72 len = len1;
73 while (len > 0) {
74 l = f->buf_size - f->wptr;
75 if (l > len)
76 l = len;
77 memcpy(f->buf + f->wptr, buf, l);
78 f->wptr += l;
79 if (f->wptr >= f->buf_size)
80 f->wptr = 0;
81 buf += l;
82 len -= l;
83 }
84 f->count += len1;
85 return len1;
86}
87
9596ebb7 88static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
e15d7371
FB
89{
90 int l, len;
91
92 if (len1 > f->count)
93 len1 = f->count;
94 len = len1;
95 while (len > 0) {
96 l = f->buf_size - f->rptr;
97 if (l > len)
98 l = len;
99 memcpy(buf, f->buf + f->rptr, l);
100 f->rptr += l;
101 if (f->rptr >= f->buf_size)
102 f->rptr = 0;
103 buf += l;
104 len -= l;
105 }
106 f->count -= len1;
107 return len1;
108}
109
af3a9031
TS
110typedef enum {
111 GRAPHIC_CONSOLE,
c60e08d9 112 TEXT_CONSOLE
af3a9031
TS
113} console_type_t;
114
95219897
PB
115/* ??? This is mis-named.
116 It is used for both text and graphical consoles. */
e7f0ad58 117struct TextConsole {
af3a9031 118 console_type_t console_type;
e7f0ad58 119 DisplayState *ds;
95219897
PB
120 /* Graphic console state. */
121 vga_hw_update_ptr hw_update;
122 vga_hw_invalidate_ptr hw_invalidate;
123 vga_hw_screen_dump_ptr hw_screen_dump;
4d3b6f6e 124 vga_hw_text_update_ptr hw_text_update;
95219897
PB
125 void *hw;
126
e7f0ad58
FB
127 int g_width, g_height;
128 int width;
129 int height;
130 int total_height;
131 int backscroll_height;
e7f0ad58 132 int x, y;
adb47967 133 int x_saved, y_saved;
e7f0ad58
FB
134 int y_displayed;
135 int y_base;
6d6f7c28
PB
136 TextAttributes t_attrib_default; /* default text attributes */
137 TextAttributes t_attrib; /* currently active text attributes */
e7f0ad58 138 TextCell *cells;
4d3b6f6e 139 int text_x[2], text_y[2], cursor_invalidate;
e7f0ad58
FB
140
141 enum TTYState state;
142 int esc_params[MAX_ESC_PARAMS];
143 int nb_esc_params;
144
e5b0bc44 145 CharDriverState *chr;
e15d7371
FB
146 /* fifo for key pressed */
147 QEMUFIFO out_fifo;
148 uint8_t out_fifo_buf[16];
149 QEMUTimer *kbd_timer;
e7f0ad58
FB
150};
151
152static TextConsole *active_console;
153static TextConsole *consoles[MAX_CONSOLES];
154static int nb_consoles = 0;
155
95219897
PB
156void vga_hw_update(void)
157{
adb47967 158 if (active_console && active_console->hw_update)
95219897
PB
159 active_console->hw_update(active_console->hw);
160}
161
162void vga_hw_invalidate(void)
163{
164 if (active_console->hw_invalidate)
165 active_console->hw_invalidate(active_console->hw);
166}
167
168void vga_hw_screen_dump(const char *filename)
169{
8571c055
AZ
170 TextConsole *previous_active_console;
171
172 previous_active_console = active_console;
173 active_console = consoles[0];
174 /* There is currently no way of specifying which screen we want to dump,
7b455225 175 so always dump the first one. */
95219897
PB
176 if (consoles[0]->hw_screen_dump)
177 consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
8571c055 178 active_console = previous_active_console;
95219897
PB
179}
180
4d3b6f6e
AZ
181void vga_hw_text_update(console_ch_t *chardata)
182{
183 if (active_console && active_console->hw_text_update)
184 active_console->hw_text_update(active_console->hw, chardata);
185}
186
e7f0ad58
FB
187/* convert a RGBA color to a color index usable in graphic primitives */
188static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
189{
190 unsigned int r, g, b, color;
191
192 switch(ds->depth) {
193#if 0
194 case 8:
195 r = (rgba >> 16) & 0xff;
196 g = (rgba >> 8) & 0xff;
197 b = (rgba) & 0xff;
5fafdf24
TS
198 color = (rgb_to_index[r] * 6 * 6) +
199 (rgb_to_index[g] * 6) +
e7f0ad58
FB
200 (rgb_to_index[b]);
201 break;
202#endif
203 case 15:
204 r = (rgba >> 16) & 0xff;
205 g = (rgba >> 8) & 0xff;
206 b = (rgba) & 0xff;
207 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
208 break;
209 case 16:
210 r = (rgba >> 16) & 0xff;
211 g = (rgba >> 8) & 0xff;
212 b = (rgba) & 0xff;
213 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
214 break;
215 case 32:
216 default:
217 color = rgba;
218 break;
219 }
220 return color;
221}
222
5fafdf24 223static void vga_fill_rect (DisplayState *ds,
e7f0ad58
FB
224 int posx, int posy, int width, int height, uint32_t color)
225{
226 uint8_t *d, *d1;
227 int x, y, bpp;
3b46e624 228
e7f0ad58 229 bpp = (ds->depth + 7) >> 3;
5fafdf24 230 d1 = ds->data +
e7f0ad58
FB
231 ds->linesize * posy + bpp * posx;
232 for (y = 0; y < height; y++) {
233 d = d1;
234 switch(bpp) {
235 case 1:
236 for (x = 0; x < width; x++) {
237 *((uint8_t *)d) = color;
238 d++;
239 }
240 break;
241 case 2:
242 for (x = 0; x < width; x++) {
243 *((uint16_t *)d) = color;
244 d += 2;
245 }
246 break;
247 case 4:
248 for (x = 0; x < width; x++) {
249 *((uint32_t *)d) = color;
250 d += 4;
251 }
252 break;
253 }
254 d1 += ds->linesize;
255 }
256}
257
258/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
259static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
260{
261 const uint8_t *s;
262 uint8_t *d;
263 int wb, y, bpp;
264
265 bpp = (ds->depth + 7) >> 3;
266 wb = w * bpp;
267 if (yd <= ys) {
5fafdf24 268 s = ds->data +
e7f0ad58 269 ds->linesize * ys + bpp * xs;
5fafdf24 270 d = ds->data +
e7f0ad58
FB
271 ds->linesize * yd + bpp * xd;
272 for (y = 0; y < h; y++) {
273 memmove(d, s, wb);
274 d += ds->linesize;
275 s += ds->linesize;
276 }
277 } else {
5fafdf24 278 s = ds->data +
e7f0ad58 279 ds->linesize * (ys + h - 1) + bpp * xs;
5fafdf24 280 d = ds->data +
e7f0ad58
FB
281 ds->linesize * (yd + h - 1) + bpp * xd;
282 for (y = 0; y < h; y++) {
283 memmove(d, s, wb);
284 d -= ds->linesize;
285 s -= ds->linesize;
286 }
287 }
288}
289
290/***********************************************************/
291/* basic char display */
292
293#define FONT_HEIGHT 16
294#define FONT_WIDTH 8
295
296#include "vgafont.h"
297
298#define cbswap_32(__x) \
299((uint32_t)( \
300 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
301 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
302 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
303 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
304
305#ifdef WORDS_BIGENDIAN
306#define PAT(x) x
307#else
308#define PAT(x) cbswap_32(x)
309#endif
310
311static const uint32_t dmask16[16] = {
312 PAT(0x00000000),
313 PAT(0x000000ff),
314 PAT(0x0000ff00),
315 PAT(0x0000ffff),
316 PAT(0x00ff0000),
317 PAT(0x00ff00ff),
318 PAT(0x00ffff00),
319 PAT(0x00ffffff),
320 PAT(0xff000000),
321 PAT(0xff0000ff),
322 PAT(0xff00ff00),
323 PAT(0xff00ffff),
324 PAT(0xffff0000),
325 PAT(0xffff00ff),
326 PAT(0xffffff00),
327 PAT(0xffffffff),
328};
329
330static const uint32_t dmask4[4] = {
331 PAT(0x00000000),
332 PAT(0x0000ffff),
333 PAT(0xffff0000),
334 PAT(0xffffffff),
335};
336
6d6f7c28
PB
337static uint32_t color_table[2][8];
338
339enum color_names {
340 COLOR_BLACK = 0,
341 COLOR_RED = 1,
342 COLOR_GREEN = 2,
343 COLOR_YELLOW = 3,
344 COLOR_BLUE = 4,
345 COLOR_MAGENTA = 5,
346 COLOR_CYAN = 6,
347 COLOR_WHITE = 7
348};
349
350static const uint32_t color_table_rgb[2][8] = {
351 { /* dark */
26489844
FB
352 QEMU_RGB(0x00, 0x00, 0x00), /* black */
353 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
354 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
355 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
356 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
357 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
358 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
359 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
6d6f7c28
PB
360 },
361 { /* bright */
26489844
FB
362 QEMU_RGB(0x00, 0x00, 0x00), /* black */
363 QEMU_RGB(0xff, 0x00, 0x00), /* red */
364 QEMU_RGB(0x00, 0xff, 0x00), /* green */
365 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
366 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
367 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
368 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
369 QEMU_RGB(0xff, 0xff, 0xff), /* white */
6d6f7c28 370 }
e7f0ad58
FB
371};
372
373static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
374{
375 switch(ds->depth) {
376 case 8:
377 col |= col << 8;
378 col |= col << 16;
379 break;
380 case 15:
381 case 16:
382 col |= col << 16;
383 break;
384 default:
385 break;
386 }
387
388 return col;
389}
6d6f7c28
PB
390#ifdef DEBUG_CONSOLE
391static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
392{
393 if (t_attrib->bold) {
394 printf("b");
395 } else {
396 printf(" ");
397 }
398 if (t_attrib->uline) {
399 printf("u");
400 } else {
401 printf(" ");
402 }
403 if (t_attrib->blink) {
404 printf("l");
405 } else {
406 printf(" ");
407 }
408 if (t_attrib->invers) {
409 printf("i");
410 } else {
411 printf(" ");
412 }
413 if (t_attrib->unvisible) {
414 printf("n");
415 } else {
416 printf(" ");
417 }
418
419 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
420}
421#endif
e7f0ad58 422
5fafdf24 423static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
6d6f7c28 424 TextAttributes *t_attrib)
e7f0ad58
FB
425{
426 uint8_t *d;
427 const uint8_t *font_ptr;
428 unsigned int font_data, linesize, xorcol, bpp;
429 int i;
6d6f7c28
PB
430 unsigned int fgcol, bgcol;
431
432#ifdef DEBUG_CONSOLE
433 printf("x: %2i y: %2i", x, y);
434 console_print_text_attributes(t_attrib, ch);
435#endif
436
437 if (t_attrib->invers) {
438 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
439 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
440 } else {
441 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
442 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
443 }
e7f0ad58
FB
444
445 bpp = (ds->depth + 7) >> 3;
5fafdf24 446 d = ds->data +
e7f0ad58
FB
447 ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
448 linesize = ds->linesize;
449 font_ptr = vgafont16 + FONT_HEIGHT * ch;
450 xorcol = bgcol ^ fgcol;
451 switch(ds->depth) {
452 case 8:
453 for(i = 0; i < FONT_HEIGHT; i++) {
454 font_data = *font_ptr++;
6d6f7c28
PB
455 if (t_attrib->uline
456 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
457 font_data = 0xFFFF;
458 }
e7f0ad58
FB
459 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
460 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
461 d += linesize;
462 }
463 break;
464 case 16:
465 case 15:
466 for(i = 0; i < FONT_HEIGHT; i++) {
467 font_data = *font_ptr++;
6d6f7c28
PB
468 if (t_attrib->uline
469 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
470 font_data = 0xFFFF;
471 }
e7f0ad58
FB
472 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
473 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
474 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
475 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
476 d += linesize;
477 }
478 break;
479 case 32:
480 for(i = 0; i < FONT_HEIGHT; i++) {
481 font_data = *font_ptr++;
6d6f7c28
PB
482 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
483 font_data = 0xFFFF;
484 }
e7f0ad58
FB
485 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
486 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
487 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
488 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
489 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
490 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
491 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
492 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
493 d += linesize;
494 }
495 break;
496 }
497}
498
499static void text_console_resize(TextConsole *s)
500{
501 TextCell *cells, *c, *c1;
502 int w1, x, y, last_width;
503
504 last_width = s->width;
505 s->width = s->g_width / FONT_WIDTH;
506 s->height = s->g_height / FONT_HEIGHT;
507
508 w1 = last_width;
509 if (s->width < w1)
510 w1 = s->width;
511
512 cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
513 for(y = 0; y < s->total_height; y++) {
514 c = &cells[y * s->width];
515 if (w1 > 0) {
516 c1 = &s->cells[y * last_width];
517 for(x = 0; x < w1; x++) {
518 *c++ = *c1++;
519 }
520 }
521 for(x = w1; x < s->width; x++) {
522 c->ch = ' ';
6d6f7c28 523 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
524 c++;
525 }
526 }
a528b80c 527 qemu_free(s->cells);
e7f0ad58
FB
528 s->cells = cells;
529}
530
4d3b6f6e
AZ
531static inline void text_update_xy(TextConsole *s, int x, int y)
532{
533 s->text_x[0] = MIN(s->text_x[0], x);
534 s->text_x[1] = MAX(s->text_x[1], x);
535 s->text_y[0] = MIN(s->text_y[0], y);
536 s->text_y[1] = MAX(s->text_y[1], y);
537}
538
e7f0ad58
FB
539static void update_xy(TextConsole *s, int x, int y)
540{
541 TextCell *c;
542 int y1, y2;
543
544 if (s == active_console) {
4d3b6f6e
AZ
545 if (!s->ds->depth) {
546 text_update_xy(s, x, y);
547 return;
548 }
549
e7f0ad58
FB
550 y1 = (s->y_base + y) % s->total_height;
551 y2 = y1 - s->y_displayed;
552 if (y2 < 0)
553 y2 += s->total_height;
554 if (y2 < s->height) {
555 c = &s->cells[y1 * s->width + x];
5fafdf24 556 vga_putcharxy(s->ds, x, y2, c->ch,
6d6f7c28 557 &(c->t_attrib));
5fafdf24 558 dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
e7f0ad58
FB
559 FONT_WIDTH, FONT_HEIGHT);
560 }
561 }
562}
563
564static void console_show_cursor(TextConsole *s, int show)
565{
566 TextCell *c;
567 int y, y1;
568
569 if (s == active_console) {
ed8276ac 570 int x = s->x;
4d3b6f6e
AZ
571
572 if (!s->ds->depth) {
573 s->cursor_invalidate = 1;
574 return;
575 }
576
ed8276ac
TS
577 if (x >= s->width) {
578 x = s->width - 1;
579 }
e7f0ad58
FB
580 y1 = (s->y_base + s->y) % s->total_height;
581 y = y1 - s->y_displayed;
582 if (y < 0)
583 y += s->total_height;
584 if (y < s->height) {
ed8276ac 585 c = &s->cells[y1 * s->width + x];
e7f0ad58 586 if (show) {
6d6f7c28
PB
587 TextAttributes t_attrib = s->t_attrib_default;
588 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
ed8276ac 589 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
e7f0ad58 590 } else {
ed8276ac 591 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
e7f0ad58 592 }
5fafdf24 593 dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT,
e7f0ad58
FB
594 FONT_WIDTH, FONT_HEIGHT);
595 }
596 }
597}
598
599static void console_refresh(TextConsole *s)
600{
601 TextCell *c;
602 int x, y, y1;
603
5fafdf24 604 if (s != active_console)
e7f0ad58 605 return;
4d3b6f6e
AZ
606 if (!s->ds->depth) {
607 s->text_x[0] = 0;
608 s->text_y[0] = 0;
609 s->text_x[1] = s->width - 1;
610 s->text_y[1] = s->height - 1;
611 s->cursor_invalidate = 1;
612 return;
613 }
e7f0ad58
FB
614
615 vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
6d6f7c28 616 color_table[0][COLOR_BLACK]);
e7f0ad58
FB
617 y1 = s->y_displayed;
618 for(y = 0; y < s->height; y++) {
619 c = s->cells + y1 * s->width;
620 for(x = 0; x < s->width; x++) {
5fafdf24 621 vga_putcharxy(s->ds, x, y, c->ch,
6d6f7c28 622 &(c->t_attrib));
e7f0ad58
FB
623 c++;
624 }
625 if (++y1 == s->total_height)
626 y1 = 0;
627 }
628 dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
629 console_show_cursor(s, 1);
630}
631
632static void console_scroll(int ydelta)
633{
634 TextConsole *s;
635 int i, y1;
3b46e624 636
e7f0ad58 637 s = active_console;
af3a9031 638 if (!s || (s->console_type == GRAPHIC_CONSOLE))
e7f0ad58
FB
639 return;
640
641 if (ydelta > 0) {
642 for(i = 0; i < ydelta; i++) {
643 if (s->y_displayed == s->y_base)
644 break;
645 if (++s->y_displayed == s->total_height)
646 s->y_displayed = 0;
647 }
648 } else {
649 ydelta = -ydelta;
650 i = s->backscroll_height;
651 if (i > s->total_height - s->height)
652 i = s->total_height - s->height;
653 y1 = s->y_base - i;
654 if (y1 < 0)
655 y1 += s->total_height;
656 for(i = 0; i < ydelta; i++) {
657 if (s->y_displayed == y1)
658 break;
659 if (--s->y_displayed < 0)
660 s->y_displayed = s->total_height - 1;
661 }
662 }
663 console_refresh(s);
664}
665
666static void console_put_lf(TextConsole *s)
667{
668 TextCell *c;
669 int x, y1;
670
e7f0ad58
FB
671 s->y++;
672 if (s->y >= s->height) {
673 s->y = s->height - 1;
6d6f7c28 674
e7f0ad58
FB
675 if (s->y_displayed == s->y_base) {
676 if (++s->y_displayed == s->total_height)
677 s->y_displayed = 0;
678 }
679 if (++s->y_base == s->total_height)
680 s->y_base = 0;
681 if (s->backscroll_height < s->total_height)
682 s->backscroll_height++;
683 y1 = (s->y_base + s->height - 1) % s->total_height;
684 c = &s->cells[y1 * s->width];
685 for(x = 0; x < s->width; x++) {
686 c->ch = ' ';
6d6f7c28 687 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
688 c++;
689 }
690 if (s == active_console && s->y_displayed == s->y_base) {
4d3b6f6e
AZ
691 if (!s->ds->depth) {
692 s->text_x[0] = 0;
693 s->text_y[0] = 0;
694 s->text_x[1] = s->width - 1;
695 s->text_y[1] = s->height - 1;
696 return;
697 }
698
5fafdf24
TS
699 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
700 s->width * FONT_WIDTH,
e7f0ad58
FB
701 (s->height - 1) * FONT_HEIGHT);
702 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
5fafdf24 703 s->width * FONT_WIDTH, FONT_HEIGHT,
6d6f7c28 704 color_table[0][s->t_attrib_default.bgcol]);
5fafdf24 705 dpy_update(s->ds, 0, 0,
e7f0ad58
FB
706 s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
707 }
708 }
709}
710
6d6f7c28
PB
711/* Set console attributes depending on the current escape codes.
712 * NOTE: I know this code is not very efficient (checking every color for it
713 * self) but it is more readable and better maintainable.
714 */
715static void console_handle_escape(TextConsole *s)
716{
717 int i;
718
6d6f7c28
PB
719 for (i=0; i<s->nb_esc_params; i++) {
720 switch (s->esc_params[i]) {
721 case 0: /* reset all console attributes to default */
722 s->t_attrib = s->t_attrib_default;
723 break;
724 case 1:
725 s->t_attrib.bold = 1;
726 break;
727 case 4:
728 s->t_attrib.uline = 1;
729 break;
730 case 5:
731 s->t_attrib.blink = 1;
732 break;
733 case 7:
734 s->t_attrib.invers = 1;
735 break;
736 case 8:
737 s->t_attrib.unvisible = 1;
738 break;
739 case 22:
740 s->t_attrib.bold = 0;
741 break;
742 case 24:
743 s->t_attrib.uline = 0;
744 break;
745 case 25:
746 s->t_attrib.blink = 0;
747 break;
748 case 27:
749 s->t_attrib.invers = 0;
750 break;
751 case 28:
752 s->t_attrib.unvisible = 0;
753 break;
754 /* set foreground color */
755 case 30:
756 s->t_attrib.fgcol=COLOR_BLACK;
757 break;
758 case 31:
759 s->t_attrib.fgcol=COLOR_RED;
760 break;
761 case 32:
762 s->t_attrib.fgcol=COLOR_GREEN;
763 break;
764 case 33:
765 s->t_attrib.fgcol=COLOR_YELLOW;
766 break;
767 case 34:
768 s->t_attrib.fgcol=COLOR_BLUE;
769 break;
770 case 35:
771 s->t_attrib.fgcol=COLOR_MAGENTA;
772 break;
773 case 36:
774 s->t_attrib.fgcol=COLOR_CYAN;
775 break;
776 case 37:
777 s->t_attrib.fgcol=COLOR_WHITE;
778 break;
779 /* set background color */
780 case 40:
781 s->t_attrib.bgcol=COLOR_BLACK;
782 break;
783 case 41:
784 s->t_attrib.bgcol=COLOR_RED;
785 break;
786 case 42:
787 s->t_attrib.bgcol=COLOR_GREEN;
788 break;
789 case 43:
790 s->t_attrib.bgcol=COLOR_YELLOW;
791 break;
792 case 44:
793 s->t_attrib.bgcol=COLOR_BLUE;
794 break;
795 case 45:
796 s->t_attrib.bgcol=COLOR_MAGENTA;
797 break;
798 case 46:
799 s->t_attrib.bgcol=COLOR_CYAN;
800 break;
801 case 47:
802 s->t_attrib.bgcol=COLOR_WHITE;
803 break;
804 }
805 }
806}
807
adb47967
TS
808static void console_clear_xy(TextConsole *s, int x, int y)
809{
810 int y1 = (s->y_base + y) % s->total_height;
811 TextCell *c = &s->cells[y1 * s->width + x];
812 c->ch = ' ';
813 c->t_attrib = s->t_attrib_default;
814 c++;
815 update_xy(s, x, y);
816}
817
e7f0ad58
FB
818static void console_putchar(TextConsole *s, int ch)
819{
820 TextCell *c;
adb47967
TS
821 int y1, i;
822 int x, y;
e7f0ad58
FB
823
824 switch(s->state) {
825 case TTY_STATE_NORM:
826 switch(ch) {
6d6f7c28 827 case '\r': /* carriage return */
e7f0ad58
FB
828 s->x = 0;
829 break;
6d6f7c28 830 case '\n': /* newline */
e7f0ad58
FB
831 console_put_lf(s);
832 break;
6d6f7c28 833 case '\b': /* backspace */
5fafdf24 834 if (s->x > 0)
e15d7371 835 s->x--;
6d6f7c28
PB
836 break;
837 case '\t': /* tabspace */
838 if (s->x + (8 - (s->x % 8)) > s->width) {
bd468840 839 s->x = 0;
6d6f7c28
PB
840 console_put_lf(s);
841 } else {
842 s->x = s->x + (8 - (s->x % 8));
843 }
844 break;
845 case '\a': /* alert aka. bell */
846 /* TODO: has to be implemented */
847 break;
adb47967
TS
848 case 14:
849 /* SI (shift in), character set 0 (ignored) */
850 break;
851 case 15:
852 /* SO (shift out), character set 1 (ignored) */
853 break;
6d6f7c28 854 case 27: /* esc (introducing an escape sequence) */
e7f0ad58
FB
855 s->state = TTY_STATE_ESC;
856 break;
857 default:
ed8276ac
TS
858 if (s->x >= s->width) {
859 /* line wrap */
860 s->x = 0;
861 console_put_lf(s);
adb47967 862 }
e7f0ad58
FB
863 y1 = (s->y_base + s->y) % s->total_height;
864 c = &s->cells[y1 * s->width + s->x];
865 c->ch = ch;
6d6f7c28 866 c->t_attrib = s->t_attrib;
e7f0ad58
FB
867 update_xy(s, s->x, s->y);
868 s->x++;
e7f0ad58
FB
869 break;
870 }
871 break;
6d6f7c28 872 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
e7f0ad58
FB
873 if (ch == '[') {
874 for(i=0;i<MAX_ESC_PARAMS;i++)
875 s->esc_params[i] = 0;
876 s->nb_esc_params = 0;
877 s->state = TTY_STATE_CSI;
878 } else {
879 s->state = TTY_STATE_NORM;
880 }
881 break;
6d6f7c28 882 case TTY_STATE_CSI: /* handle escape sequence parameters */
e7f0ad58
FB
883 if (ch >= '0' && ch <= '9') {
884 if (s->nb_esc_params < MAX_ESC_PARAMS) {
5fafdf24 885 s->esc_params[s->nb_esc_params] =
e7f0ad58
FB
886 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
887 }
888 } else {
889 s->nb_esc_params++;
890 if (ch == ';')
891 break;
adb47967
TS
892#ifdef DEBUG_CONSOLE
893 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
894 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
895#endif
e7f0ad58
FB
896 s->state = TTY_STATE_NORM;
897 switch(ch) {
adb47967
TS
898 case 'A':
899 /* move cursor up */
900 if (s->esc_params[0] == 0) {
901 s->esc_params[0] = 1;
902 }
903 s->y -= s->esc_params[0];
904 if (s->y < 0) {
905 s->y = 0;
906 }
907 break;
908 case 'B':
909 /* move cursor down */
910 if (s->esc_params[0] == 0) {
911 s->esc_params[0] = 1;
912 }
913 s->y += s->esc_params[0];
914 if (s->y >= s->height) {
915 s->y = s->height - 1;
916 }
e7f0ad58
FB
917 break;
918 case 'C':
adb47967
TS
919 /* move cursor right */
920 if (s->esc_params[0] == 0) {
921 s->esc_params[0] = 1;
922 }
923 s->x += s->esc_params[0];
924 if (s->x >= s->width) {
925 s->x = s->width - 1;
926 }
e7f0ad58 927 break;
adb47967
TS
928 case 'D':
929 /* move cursor left */
930 if (s->esc_params[0] == 0) {
931 s->esc_params[0] = 1;
932 }
933 s->x -= s->esc_params[0];
934 if (s->x < 0) {
935 s->x = 0;
936 }
937 break;
938 case 'G':
939 /* move cursor to column */
940 s->x = s->esc_params[0] - 1;
941 if (s->x < 0) {
942 s->x = 0;
943 }
944 break;
945 case 'f':
946 case 'H':
947 /* move cursor to row, column */
948 s->x = s->esc_params[1] - 1;
949 if (s->x < 0) {
950 s->x = 0;
951 }
952 s->y = s->esc_params[0] - 1;
953 if (s->y < 0) {
954 s->y = 0;
955 }
956 break;
957 case 'J':
958 switch (s->esc_params[0]) {
959 case 0:
960 /* clear to end of screen */
961 for (y = s->y; y < s->height; y++) {
962 for (x = 0; x < s->width; x++) {
963 if (y == s->y && x < s->x) {
964 continue;
965 }
966 console_clear_xy(s, x, y);
967 }
968 }
969 break;
970 case 1:
971 /* clear from beginning of screen */
972 for (y = 0; y <= s->y; y++) {
973 for (x = 0; x < s->width; x++) {
974 if (y == s->y && x > s->x) {
975 break;
976 }
977 console_clear_xy(s, x, y);
978 }
979 }
980 break;
981 case 2:
982 /* clear entire screen */
983 for (y = 0; y <= s->height; y++) {
984 for (x = 0; x < s->width; x++) {
985 console_clear_xy(s, x, y);
986 }
987 }
988 break;
989 }
e7f0ad58 990 case 'K':
adb47967
TS
991 switch (s->esc_params[0]) {
992 case 0:
e7f0ad58 993 /* clear to eol */
e7f0ad58 994 for(x = s->x; x < s->width; x++) {
adb47967 995 console_clear_xy(s, x, s->y);
e7f0ad58
FB
996 }
997 break;
adb47967
TS
998 case 1:
999 /* clear from beginning of line */
1000 for (x = 0; x <= s->x; x++) {
1001 console_clear_xy(s, x, s->y);
1002 }
1003 break;
1004 case 2:
1005 /* clear entire line */
1006 for(x = 0; x < s->width; x++) {
1007 console_clear_xy(s, x, s->y);
1008 }
e7f0ad58
FB
1009 break;
1010 }
adb47967
TS
1011 break;
1012 case 'm':
6d6f7c28 1013 console_handle_escape(s);
e7f0ad58 1014 break;
adb47967
TS
1015 case 'n':
1016 /* report cursor position */
1017 /* TODO: send ESC[row;colR */
1018 break;
1019 case 's':
1020 /* save cursor position */
1021 s->x_saved = s->x;
1022 s->y_saved = s->y;
1023 break;
1024 case 'u':
1025 /* restore cursor position */
1026 s->x = s->x_saved;
1027 s->y = s->y_saved;
1028 break;
1029 default:
1030#ifdef DEBUG_CONSOLE
1031 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1032#endif
1033 break;
1034 }
1035 break;
e7f0ad58
FB
1036 }
1037 }
1038}
1039
1040void console_select(unsigned int index)
1041{
1042 TextConsole *s;
6d6f7c28 1043
e7f0ad58
FB
1044 if (index >= MAX_CONSOLES)
1045 return;
1046 s = consoles[index];
1047 if (s) {
1048 active_console = s;
c60e08d9
PB
1049 if (s->g_width && s->g_height
1050 && (s->g_width != s->ds->width || s->g_height != s->ds->height))
1051 dpy_resize(s->ds, s->g_width, s->g_height);
4d3b6f6e 1052 vga_hw_invalidate();
e7f0ad58
FB
1053 }
1054}
1055
1056static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1057{
1058 TextConsole *s = chr->opaque;
1059 int i;
1060
1061 console_show_cursor(s, 0);
1062 for(i = 0; i < len; i++) {
1063 console_putchar(s, buf[i]);
1064 }
1065 console_show_cursor(s, 1);
1066 return len;
1067}
1068
6fcfafb7
FB
1069static void console_send_event(CharDriverState *chr, int event)
1070{
1071 TextConsole *s = chr->opaque;
1072 int i;
1073
1074 if (event == CHR_EVENT_FOCUS) {
1075 for(i = 0; i < nb_consoles; i++) {
1076 if (consoles[i] == s) {
1077 console_select(i);
1078 break;
1079 }
1080 }
1081 }
1082}
1083
e15d7371
FB
1084static void kbd_send_chars(void *opaque)
1085{
1086 TextConsole *s = opaque;
1087 int len;
1088 uint8_t buf[16];
3b46e624 1089
e5b0bc44 1090 len = qemu_chr_can_read(s->chr);
e15d7371
FB
1091 if (len > s->out_fifo.count)
1092 len = s->out_fifo.count;
1093 if (len > 0) {
1094 if (len > sizeof(buf))
1095 len = sizeof(buf);
1096 qemu_fifo_read(&s->out_fifo, buf, len);
e5b0bc44 1097 qemu_chr_read(s->chr, buf, len);
e15d7371
FB
1098 }
1099 /* characters are pending: we send them a bit later (XXX:
1100 horrible, should change char device API) */
1101 if (s->out_fifo.count > 0) {
1102 qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
1103 }
1104}
1105
e7f0ad58
FB
1106/* called when an ascii key is pressed */
1107void kbd_put_keysym(int keysym)
1108{
1109 TextConsole *s;
1110 uint8_t buf[16], *q;
1111 int c;
1112
1113 s = active_console;
af3a9031 1114 if (!s || (s->console_type == GRAPHIC_CONSOLE))
e7f0ad58
FB
1115 return;
1116
1117 switch(keysym) {
1118 case QEMU_KEY_CTRL_UP:
1119 console_scroll(-1);
1120 break;
1121 case QEMU_KEY_CTRL_DOWN:
1122 console_scroll(1);
1123 break;
1124 case QEMU_KEY_CTRL_PAGEUP:
1125 console_scroll(-10);
1126 break;
1127 case QEMU_KEY_CTRL_PAGEDOWN:
1128 console_scroll(10);
1129 break;
1130 default:
e15d7371
FB
1131 /* convert the QEMU keysym to VT100 key string */
1132 q = buf;
1133 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1134 *q++ = '\033';
1135 *q++ = '[';
1136 c = keysym - 0xe100;
1137 if (c >= 10)
1138 *q++ = '0' + (c / 10);
1139 *q++ = '0' + (c % 10);
1140 *q++ = '~';
1141 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1142 *q++ = '\033';
1143 *q++ = '[';
1144 *q++ = keysym & 0xff;
1145 } else {
e7f0ad58 1146 *q++ = keysym;
e15d7371 1147 }
e5b0bc44 1148 if (s->chr->chr_read) {
e15d7371
FB
1149 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1150 kbd_send_chars(s);
e7f0ad58
FB
1151 }
1152 break;
1153 }
1154}
1155
4d3b6f6e
AZ
1156static void text_console_invalidate(void *opaque)
1157{
1158 TextConsole *s = (TextConsole *) opaque;
1159
4d3b6f6e
AZ
1160 console_refresh(s);
1161}
1162
1163static void text_console_update(void *opaque, console_ch_t *chardata)
1164{
1165 TextConsole *s = (TextConsole *) opaque;
1166 int i, j, src;
1167
1168 if (s->text_x[0] <= s->text_x[1]) {
1169 src = (s->y_base + s->text_y[0]) * s->width;
1170 chardata += s->text_y[0] * s->width;
1171 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1172 for (j = 0; j < s->width; j ++, src ++)
1173 console_write_ch(chardata ++, s->cells[src].ch |
1174 (s->cells[src].t_attrib.fgcol << 12) |
1175 (s->cells[src].t_attrib.bgcol << 8) |
1176 (s->cells[src].t_attrib.bold << 21));
1177 dpy_update(s->ds, s->text_x[0], s->text_y[0],
1178 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1179 s->text_x[0] = s->width;
1180 s->text_y[0] = s->height;
1181 s->text_x[1] = 0;
1182 s->text_y[1] = 0;
1183 }
1184 if (s->cursor_invalidate) {
1185 dpy_cursor(s->ds, s->x, s->y);
1186 s->cursor_invalidate = 0;
1187 }
1188}
1189
af3a9031 1190static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
e7f0ad58
FB
1191{
1192 TextConsole *s;
95219897 1193 int i;
e7f0ad58
FB
1194
1195 if (nb_consoles >= MAX_CONSOLES)
1196 return NULL;
1197 s = qemu_mallocz(sizeof(TextConsole));
1198 if (!s) {
1199 return NULL;
1200 }
af3a9031
TS
1201 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1202 (console_type == GRAPHIC_CONSOLE))) {
e7f0ad58 1203 active_console = s;
af3a9031 1204 }
e7f0ad58 1205 s->ds = ds;
af3a9031
TS
1206 s->console_type = console_type;
1207 if (console_type != GRAPHIC_CONSOLE) {
95219897
PB
1208 consoles[nb_consoles++] = s;
1209 } else {
1210 /* HACK: Put graphical consoles before text consoles. */
1211 for (i = nb_consoles; i > 0; i--) {
af3a9031 1212 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
95219897
PB
1213 break;
1214 consoles[i] = consoles[i - 1];
1215 }
1216 consoles[i] = s;
1217 }
1218 return s;
1219}
1220
1221TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
1222 vga_hw_invalidate_ptr invalidate,
1223 vga_hw_screen_dump_ptr screen_dump,
4d3b6f6e 1224 vga_hw_text_update_ptr text_update,
95219897
PB
1225 void *opaque)
1226{
1227 TextConsole *s;
1228
af3a9031 1229 s = new_console(ds, GRAPHIC_CONSOLE);
95219897
PB
1230 if (!s)
1231 return NULL;
1232 s->hw_update = update;
1233 s->hw_invalidate = invalidate;
1234 s->hw_screen_dump = screen_dump;
4d3b6f6e 1235 s->hw_text_update = text_update;
95219897 1236 s->hw = opaque;
e7f0ad58
FB
1237 return s;
1238}
1239
95219897 1240int is_graphic_console(void)
e7f0ad58 1241{
4d3b6f6e 1242 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
e7f0ad58
FB
1243}
1244
a528b80c
AZ
1245void console_color_init(DisplayState *ds)
1246{
1247 int i, j;
1248 for (j = 0; j < 2; j++) {
1249 for (i = 0; i < 8; i++) {
1250 color_table[j][i] = col_expand(ds,
1251 vga_get_color(ds, color_table_rgb[j][i]));
1252 }
1253 }
1254}
1255
af3a9031 1256CharDriverState *text_console_init(DisplayState *ds, const char *p)
e7f0ad58
FB
1257{
1258 CharDriverState *chr;
1259 TextConsole *s;
af3a9031
TS
1260 unsigned width;
1261 unsigned height;
e7f0ad58 1262 static int color_inited;
6d6f7c28 1263
e7f0ad58
FB
1264 chr = qemu_mallocz(sizeof(CharDriverState));
1265 if (!chr)
1266 return NULL;
c60e08d9 1267 s = new_console(ds, TEXT_CONSOLE);
e7f0ad58
FB
1268 if (!s) {
1269 free(chr);
1270 return NULL;
1271 }
c60e08d9
PB
1272 if (!p)
1273 p = DEFAULT_MONITOR_SIZE;
1274
e7f0ad58
FB
1275 chr->opaque = s;
1276 chr->chr_write = console_puts;
6fcfafb7
FB
1277 chr->chr_send_event = console_send_event;
1278
e5b0bc44 1279 s->chr = chr;
e15d7371
FB
1280 s->out_fifo.buf = s->out_fifo_buf;
1281 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1282 s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
3b46e624 1283
e7f0ad58
FB
1284 if (!color_inited) {
1285 color_inited = 1;
a528b80c 1286 console_color_init(s->ds);
e7f0ad58
FB
1287 }
1288 s->y_displayed = 0;
1289 s->y_base = 0;
1290 s->total_height = DEFAULT_BACKSCROLL;
1291 s->x = 0;
1292 s->y = 0;
af3a9031
TS
1293 width = s->ds->width;
1294 height = s->ds->height;
1295 if (p != 0) {
1296 width = strtoul(p, (char **)&p, 10);
1297 if (*p == 'C') {
1298 p++;
1299 width *= FONT_WIDTH;
1300 }
1301 if (*p == 'x') {
1302 p++;
1303 height = strtoul(p, (char **)&p, 10);
1304 if (*p == 'C') {
1305 p++;
1306 height *= FONT_HEIGHT;
1307 }
1308 }
1309 }
1310 s->g_width = width;
1311 s->g_height = height;
6d6f7c28 1312
4d3b6f6e
AZ
1313 s->hw_invalidate = text_console_invalidate;
1314 s->hw_text_update = text_console_update;
1315 s->hw = s;
1316
6d6f7c28
PB
1317 /* Set text attribute defaults */
1318 s->t_attrib_default.bold = 0;
1319 s->t_attrib_default.uline = 0;
1320 s->t_attrib_default.blink = 0;
1321 s->t_attrib_default.invers = 0;
1322 s->t_attrib_default.unvisible = 0;
1323 s->t_attrib_default.fgcol = COLOR_WHITE;
1324 s->t_attrib_default.bgcol = COLOR_BLACK;
1325
1326 /* set current text attributes to default */
1327 s->t_attrib = s->t_attrib_default;
e7f0ad58
FB
1328 text_console_resize(s);
1329
86e94dea
TS
1330 qemu_chr_reset(chr);
1331
e7f0ad58
FB
1332 return chr;
1333}
c60e08d9
PB
1334
1335void qemu_console_resize(QEMUConsole *console, int width, int height)
1336{
3bba22de
AZ
1337 if (console->g_width != width || console->g_height != height
1338 || !console->ds->data) {
c60e08d9
PB
1339 console->g_width = width;
1340 console->g_height = height;
1341 if (active_console == console) {
1342 dpy_resize(console->ds, width, height);
1343 }
1344 }
1345}