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