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