]> git.proxmox.com Git - qemu.git/blame - console.c
Remove blanks before \n in output strings
[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
31
26489844
FB
32#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
33#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
e7f0ad58 34
6d6f7c28
PB
35typedef struct TextAttributes {
36 uint8_t fgcol:4;
37 uint8_t bgcol:4;
38 uint8_t bold:1;
39 uint8_t uline:1;
40 uint8_t blink:1;
41 uint8_t invers:1;
42 uint8_t unvisible:1;
43} TextAttributes;
44
e7f0ad58
FB
45typedef struct TextCell {
46 uint8_t ch;
6d6f7c28 47 TextAttributes t_attrib;
e7f0ad58
FB
48} TextCell;
49
50#define MAX_ESC_PARAMS 3
51
52enum TTYState {
53 TTY_STATE_NORM,
54 TTY_STATE_ESC,
55 TTY_STATE_CSI,
56};
57
e15d7371
FB
58typedef struct QEMUFIFO {
59 uint8_t *buf;
60 int buf_size;
61 int count, wptr, rptr;
62} QEMUFIFO;
63
9596ebb7 64static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
e15d7371
FB
65{
66 int l, len;
67
68 l = f->buf_size - f->count;
69 if (len1 > l)
70 len1 = l;
71 len = len1;
72 while (len > 0) {
73 l = f->buf_size - f->wptr;
74 if (l > len)
75 l = len;
76 memcpy(f->buf + f->wptr, buf, l);
77 f->wptr += l;
78 if (f->wptr >= f->buf_size)
79 f->wptr = 0;
80 buf += l;
81 len -= l;
82 }
83 f->count += len1;
84 return len1;
85}
86
9596ebb7 87static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
e15d7371
FB
88{
89 int l, len;
90
91 if (len1 > f->count)
92 len1 = f->count;
93 len = len1;
94 while (len > 0) {
95 l = f->buf_size - f->rptr;
96 if (l > len)
97 l = len;
98 memcpy(buf, f->buf + f->rptr, l);
99 f->rptr += l;
100 if (f->rptr >= f->buf_size)
101 f->rptr = 0;
102 buf += l;
103 len -= l;
104 }
105 f->count -= len1;
106 return len1;
107}
108
af3a9031
TS
109typedef enum {
110 GRAPHIC_CONSOLE,
c21bbcfa
AZ
111 TEXT_CONSOLE,
112 TEXT_CONSOLE_FIXED_SIZE
c227f099 113} console_type_t;
af3a9031 114
95219897
PB
115/* ??? This is mis-named.
116 It is used for both text and graphical consoles. */
e7f0ad58 117struct TextConsole {
c227f099 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;
4104833f 140 int echo;
e7f0ad58 141
14778c20
PB
142 int update_x0;
143 int update_y0;
144 int update_x1;
145 int update_y1;
146
e7f0ad58
FB
147 enum TTYState state;
148 int esc_params[MAX_ESC_PARAMS];
149 int nb_esc_params;
150
e5b0bc44 151 CharDriverState *chr;
e15d7371
FB
152 /* fifo for key pressed */
153 QEMUFIFO out_fifo;
154 uint8_t out_fifo_buf[16];
155 QEMUTimer *kbd_timer;
e7f0ad58
FB
156};
157
98b50080 158static DisplayState *display_state;
e7f0ad58
FB
159static TextConsole *active_console;
160static TextConsole *consoles[MAX_CONSOLES];
161static int nb_consoles = 0;
162
95219897
PB
163void vga_hw_update(void)
164{
adb47967 165 if (active_console && active_console->hw_update)
95219897
PB
166 active_console->hw_update(active_console->hw);
167}
168
169void vga_hw_invalidate(void)
170{
26572b8a 171 if (active_console && active_console->hw_invalidate)
95219897
PB
172 active_console->hw_invalidate(active_console->hw);
173}
174
175void vga_hw_screen_dump(const char *filename)
176{
8571c055
AZ
177 TextConsole *previous_active_console;
178
179 previous_active_console = active_console;
180 active_console = consoles[0];
181 /* There is currently no way of specifying which screen we want to dump,
7b455225 182 so always dump the first one. */
e34b12ae 183 if (consoles[0] && consoles[0]->hw_screen_dump)
95219897 184 consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
8571c055 185 active_console = previous_active_console;
95219897
PB
186}
187
c227f099 188void vga_hw_text_update(console_ch_t *chardata)
4d3b6f6e
AZ
189{
190 if (active_console && active_console->hw_text_update)
191 active_console->hw_text_update(active_console->hw, chardata);
192}
193
e7f0ad58
FB
194/* convert a RGBA color to a color index usable in graphic primitives */
195static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
196{
197 unsigned int r, g, b, color;
198
0e1f5a0c 199 switch(ds_get_bits_per_pixel(ds)) {
e7f0ad58
FB
200#if 0
201 case 8:
202 r = (rgba >> 16) & 0xff;
203 g = (rgba >> 8) & 0xff;
204 b = (rgba) & 0xff;
5fafdf24
TS
205 color = (rgb_to_index[r] * 6 * 6) +
206 (rgb_to_index[g] * 6) +
e7f0ad58
FB
207 (rgb_to_index[b]);
208 break;
209#endif
210 case 15:
211 r = (rgba >> 16) & 0xff;
212 g = (rgba >> 8) & 0xff;
213 b = (rgba) & 0xff;
214 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
215 break;
216 case 16:
217 r = (rgba >> 16) & 0xff;
218 g = (rgba >> 8) & 0xff;
219 b = (rgba) & 0xff;
220 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
221 break;
222 case 32:
223 default:
224 color = rgba;
225 break;
226 }
227 return color;
228}
229
5fafdf24 230static void vga_fill_rect (DisplayState *ds,
e7f0ad58
FB
231 int posx, int posy, int width, int height, uint32_t color)
232{
233 uint8_t *d, *d1;
234 int x, y, bpp;
3b46e624 235
0e1f5a0c
AL
236 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
237 d1 = ds_get_data(ds) +
238 ds_get_linesize(ds) * posy + bpp * posx;
e7f0ad58
FB
239 for (y = 0; y < height; y++) {
240 d = d1;
241 switch(bpp) {
242 case 1:
243 for (x = 0; x < width; x++) {
244 *((uint8_t *)d) = color;
245 d++;
246 }
247 break;
248 case 2:
249 for (x = 0; x < width; x++) {
250 *((uint16_t *)d) = color;
251 d += 2;
252 }
253 break;
254 case 4:
255 for (x = 0; x < width; x++) {
256 *((uint32_t *)d) = color;
257 d += 4;
258 }
259 break;
260 }
0e1f5a0c 261 d1 += ds_get_linesize(ds);
e7f0ad58
FB
262 }
263}
264
265/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
266static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
267{
268 const uint8_t *s;
269 uint8_t *d;
270 int wb, y, bpp;
271
0e1f5a0c 272 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
e7f0ad58
FB
273 wb = w * bpp;
274 if (yd <= ys) {
0e1f5a0c
AL
275 s = ds_get_data(ds) +
276 ds_get_linesize(ds) * ys + bpp * xs;
277 d = ds_get_data(ds) +
278 ds_get_linesize(ds) * yd + bpp * xd;
e7f0ad58
FB
279 for (y = 0; y < h; y++) {
280 memmove(d, s, wb);
0e1f5a0c
AL
281 d += ds_get_linesize(ds);
282 s += ds_get_linesize(ds);
e7f0ad58
FB
283 }
284 } else {
0e1f5a0c
AL
285 s = ds_get_data(ds) +
286 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
287 d = ds_get_data(ds) +
288 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
e7f0ad58
FB
289 for (y = 0; y < h; y++) {
290 memmove(d, s, wb);
0e1f5a0c
AL
291 d -= ds_get_linesize(ds);
292 s -= ds_get_linesize(ds);
e7f0ad58
FB
293 }
294 }
295}
296
297/***********************************************************/
298/* basic char display */
299
300#define FONT_HEIGHT 16
301#define FONT_WIDTH 8
302
303#include "vgafont.h"
304
305#define cbswap_32(__x) \
306((uint32_t)( \
307 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
308 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
309 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
310 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
311
e2542fe2 312#ifdef HOST_WORDS_BIGENDIAN
e7f0ad58
FB
313#define PAT(x) x
314#else
315#define PAT(x) cbswap_32(x)
316#endif
317
318static const uint32_t dmask16[16] = {
319 PAT(0x00000000),
320 PAT(0x000000ff),
321 PAT(0x0000ff00),
322 PAT(0x0000ffff),
323 PAT(0x00ff0000),
324 PAT(0x00ff00ff),
325 PAT(0x00ffff00),
326 PAT(0x00ffffff),
327 PAT(0xff000000),
328 PAT(0xff0000ff),
329 PAT(0xff00ff00),
330 PAT(0xff00ffff),
331 PAT(0xffff0000),
332 PAT(0xffff00ff),
333 PAT(0xffffff00),
334 PAT(0xffffffff),
335};
336
337static const uint32_t dmask4[4] = {
338 PAT(0x00000000),
339 PAT(0x0000ffff),
340 PAT(0xffff0000),
341 PAT(0xffffffff),
342};
343
6d6f7c28
PB
344static uint32_t color_table[2][8];
345
df00bed0 346#ifndef CONFIG_CURSES
6d6f7c28
PB
347enum color_names {
348 COLOR_BLACK = 0,
349 COLOR_RED = 1,
350 COLOR_GREEN = 2,
351 COLOR_YELLOW = 3,
352 COLOR_BLUE = 4,
353 COLOR_MAGENTA = 5,
354 COLOR_CYAN = 6,
355 COLOR_WHITE = 7
356};
df00bed0 357#endif
6d6f7c28
PB
358
359static const uint32_t color_table_rgb[2][8] = {
360 { /* dark */
26489844
FB
361 QEMU_RGB(0x00, 0x00, 0x00), /* black */
362 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
363 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
364 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
365 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
366 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
367 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
368 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
6d6f7c28
PB
369 },
370 { /* bright */
26489844
FB
371 QEMU_RGB(0x00, 0x00, 0x00), /* black */
372 QEMU_RGB(0xff, 0x00, 0x00), /* red */
373 QEMU_RGB(0x00, 0xff, 0x00), /* green */
374 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
375 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
376 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
377 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
378 QEMU_RGB(0xff, 0xff, 0xff), /* white */
6d6f7c28 379 }
e7f0ad58
FB
380};
381
382static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
383{
0e1f5a0c 384 switch(ds_get_bits_per_pixel(ds)) {
e7f0ad58
FB
385 case 8:
386 col |= col << 8;
387 col |= col << 16;
388 break;
389 case 15:
390 case 16:
391 col |= col << 16;
392 break;
393 default:
394 break;
395 }
396
397 return col;
398}
6d6f7c28
PB
399#ifdef DEBUG_CONSOLE
400static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
401{
402 if (t_attrib->bold) {
403 printf("b");
404 } else {
405 printf(" ");
406 }
407 if (t_attrib->uline) {
408 printf("u");
409 } else {
410 printf(" ");
411 }
412 if (t_attrib->blink) {
413 printf("l");
414 } else {
415 printf(" ");
416 }
417 if (t_attrib->invers) {
418 printf("i");
419 } else {
420 printf(" ");
421 }
422 if (t_attrib->unvisible) {
423 printf("n");
424 } else {
425 printf(" ");
426 }
427
428 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
429}
430#endif
e7f0ad58 431
5fafdf24 432static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
6d6f7c28 433 TextAttributes *t_attrib)
e7f0ad58
FB
434{
435 uint8_t *d;
436 const uint8_t *font_ptr;
437 unsigned int font_data, linesize, xorcol, bpp;
438 int i;
6d6f7c28
PB
439 unsigned int fgcol, bgcol;
440
441#ifdef DEBUG_CONSOLE
442 printf("x: %2i y: %2i", x, y);
443 console_print_text_attributes(t_attrib, ch);
444#endif
445
446 if (t_attrib->invers) {
447 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
448 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
449 } else {
450 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
451 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
452 }
e7f0ad58 453
0e1f5a0c
AL
454 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
455 d = ds_get_data(ds) +
456 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
457 linesize = ds_get_linesize(ds);
e7f0ad58
FB
458 font_ptr = vgafont16 + FONT_HEIGHT * ch;
459 xorcol = bgcol ^ fgcol;
0e1f5a0c 460 switch(ds_get_bits_per_pixel(ds)) {
e7f0ad58
FB
461 case 8:
462 for(i = 0; i < FONT_HEIGHT; i++) {
463 font_data = *font_ptr++;
6d6f7c28
PB
464 if (t_attrib->uline
465 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
466 font_data = 0xFFFF;
467 }
e7f0ad58
FB
468 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
469 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
470 d += linesize;
471 }
472 break;
473 case 16:
474 case 15:
475 for(i = 0; i < FONT_HEIGHT; i++) {
476 font_data = *font_ptr++;
6d6f7c28
PB
477 if (t_attrib->uline
478 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
479 font_data = 0xFFFF;
480 }
e7f0ad58
FB
481 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
482 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
483 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
484 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
485 d += linesize;
486 }
487 break;
488 case 32:
489 for(i = 0; i < FONT_HEIGHT; i++) {
490 font_data = *font_ptr++;
6d6f7c28
PB
491 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
492 font_data = 0xFFFF;
493 }
e7f0ad58
FB
494 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
495 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
496 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
497 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
498 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
499 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
500 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
501 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
502 d += linesize;
503 }
504 break;
505 }
506}
507
508static void text_console_resize(TextConsole *s)
509{
510 TextCell *cells, *c, *c1;
511 int w1, x, y, last_width;
512
513 last_width = s->width;
514 s->width = s->g_width / FONT_WIDTH;
515 s->height = s->g_height / FONT_HEIGHT;
516
517 w1 = last_width;
518 if (s->width < w1)
519 w1 = s->width;
520
7267c094 521 cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
e7f0ad58
FB
522 for(y = 0; y < s->total_height; y++) {
523 c = &cells[y * s->width];
524 if (w1 > 0) {
525 c1 = &s->cells[y * last_width];
526 for(x = 0; x < w1; x++) {
527 *c++ = *c1++;
528 }
529 }
530 for(x = w1; x < s->width; x++) {
531 c->ch = ' ';
6d6f7c28 532 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
533 c++;
534 }
535 }
7267c094 536 g_free(s->cells);
e7f0ad58
FB
537 s->cells = cells;
538}
539
4d3b6f6e
AZ
540static inline void text_update_xy(TextConsole *s, int x, int y)
541{
542 s->text_x[0] = MIN(s->text_x[0], x);
543 s->text_x[1] = MAX(s->text_x[1], x);
544 s->text_y[0] = MIN(s->text_y[0], y);
545 s->text_y[1] = MAX(s->text_y[1], y);
546}
547
14778c20
PB
548static void invalidate_xy(TextConsole *s, int x, int y)
549{
550 if (s->update_x0 > x * FONT_WIDTH)
551 s->update_x0 = x * FONT_WIDTH;
552 if (s->update_y0 > y * FONT_HEIGHT)
553 s->update_y0 = y * FONT_HEIGHT;
554 if (s->update_x1 < (x + 1) * FONT_WIDTH)
555 s->update_x1 = (x + 1) * FONT_WIDTH;
556 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
557 s->update_y1 = (y + 1) * FONT_HEIGHT;
558}
559
e7f0ad58
FB
560static void update_xy(TextConsole *s, int x, int y)
561{
562 TextCell *c;
563 int y1, y2;
564
565 if (s == active_console) {
0e1f5a0c 566 if (!ds_get_bits_per_pixel(s->ds)) {
4d3b6f6e
AZ
567 text_update_xy(s, x, y);
568 return;
569 }
570
e7f0ad58
FB
571 y1 = (s->y_base + y) % s->total_height;
572 y2 = y1 - s->y_displayed;
573 if (y2 < 0)
574 y2 += s->total_height;
575 if (y2 < s->height) {
576 c = &s->cells[y1 * s->width + x];
5fafdf24 577 vga_putcharxy(s->ds, x, y2, c->ch,
6d6f7c28 578 &(c->t_attrib));
14778c20 579 invalidate_xy(s, x, y2);
e7f0ad58
FB
580 }
581 }
582}
583
584static void console_show_cursor(TextConsole *s, int show)
585{
586 TextCell *c;
587 int y, y1;
588
589 if (s == active_console) {
ed8276ac 590 int x = s->x;
4d3b6f6e 591
0e1f5a0c 592 if (!ds_get_bits_per_pixel(s->ds)) {
4d3b6f6e
AZ
593 s->cursor_invalidate = 1;
594 return;
595 }
596
ed8276ac
TS
597 if (x >= s->width) {
598 x = s->width - 1;
599 }
e7f0ad58
FB
600 y1 = (s->y_base + s->y) % s->total_height;
601 y = y1 - s->y_displayed;
602 if (y < 0)
603 y += s->total_height;
604 if (y < s->height) {
ed8276ac 605 c = &s->cells[y1 * s->width + x];
e7f0ad58 606 if (show) {
6d6f7c28
PB
607 TextAttributes t_attrib = s->t_attrib_default;
608 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
ed8276ac 609 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
e7f0ad58 610 } else {
ed8276ac 611 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
e7f0ad58 612 }
14778c20 613 invalidate_xy(s, x, y);
e7f0ad58
FB
614 }
615 }
616}
617
618static void console_refresh(TextConsole *s)
619{
620 TextCell *c;
621 int x, y, y1;
622
5fafdf24 623 if (s != active_console)
e7f0ad58 624 return;
0e1f5a0c 625 if (!ds_get_bits_per_pixel(s->ds)) {
4d3b6f6e
AZ
626 s->text_x[0] = 0;
627 s->text_y[0] = 0;
628 s->text_x[1] = s->width - 1;
629 s->text_y[1] = s->height - 1;
630 s->cursor_invalidate = 1;
631 return;
632 }
e7f0ad58 633
0e1f5a0c 634 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
6d6f7c28 635 color_table[0][COLOR_BLACK]);
e7f0ad58
FB
636 y1 = s->y_displayed;
637 for(y = 0; y < s->height; y++) {
638 c = s->cells + y1 * s->width;
639 for(x = 0; x < s->width; x++) {
5fafdf24 640 vga_putcharxy(s->ds, x, y, c->ch,
6d6f7c28 641 &(c->t_attrib));
e7f0ad58
FB
642 c++;
643 }
644 if (++y1 == s->total_height)
645 y1 = 0;
646 }
e7f0ad58 647 console_show_cursor(s, 1);
14778c20 648 dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
e7f0ad58
FB
649}
650
651static void console_scroll(int ydelta)
652{
653 TextConsole *s;
654 int i, y1;
3b46e624 655
e7f0ad58 656 s = active_console;
af3a9031 657 if (!s || (s->console_type == GRAPHIC_CONSOLE))
e7f0ad58
FB
658 return;
659
660 if (ydelta > 0) {
661 for(i = 0; i < ydelta; i++) {
662 if (s->y_displayed == s->y_base)
663 break;
664 if (++s->y_displayed == s->total_height)
665 s->y_displayed = 0;
666 }
667 } else {
668 ydelta = -ydelta;
669 i = s->backscroll_height;
670 if (i > s->total_height - s->height)
671 i = s->total_height - s->height;
672 y1 = s->y_base - i;
673 if (y1 < 0)
674 y1 += s->total_height;
675 for(i = 0; i < ydelta; i++) {
676 if (s->y_displayed == y1)
677 break;
678 if (--s->y_displayed < 0)
679 s->y_displayed = s->total_height - 1;
680 }
681 }
682 console_refresh(s);
683}
684
685static void console_put_lf(TextConsole *s)
686{
687 TextCell *c;
688 int x, y1;
689
e7f0ad58
FB
690 s->y++;
691 if (s->y >= s->height) {
692 s->y = s->height - 1;
6d6f7c28 693
e7f0ad58
FB
694 if (s->y_displayed == s->y_base) {
695 if (++s->y_displayed == s->total_height)
696 s->y_displayed = 0;
697 }
698 if (++s->y_base == s->total_height)
699 s->y_base = 0;
700 if (s->backscroll_height < s->total_height)
701 s->backscroll_height++;
702 y1 = (s->y_base + s->height - 1) % s->total_height;
703 c = &s->cells[y1 * s->width];
704 for(x = 0; x < s->width; x++) {
705 c->ch = ' ';
6d6f7c28 706 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
707 c++;
708 }
709 if (s == active_console && s->y_displayed == s->y_base) {
0e1f5a0c 710 if (!ds_get_bits_per_pixel(s->ds)) {
4d3b6f6e
AZ
711 s->text_x[0] = 0;
712 s->text_y[0] = 0;
713 s->text_x[1] = s->width - 1;
714 s->text_y[1] = s->height - 1;
715 return;
716 }
717
5fafdf24
TS
718 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
719 s->width * FONT_WIDTH,
e7f0ad58
FB
720 (s->height - 1) * FONT_HEIGHT);
721 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
5fafdf24 722 s->width * FONT_WIDTH, FONT_HEIGHT,
6d6f7c28 723 color_table[0][s->t_attrib_default.bgcol]);
14778c20
PB
724 s->update_x0 = 0;
725 s->update_y0 = 0;
726 s->update_x1 = s->width * FONT_WIDTH;
727 s->update_y1 = s->height * FONT_HEIGHT;
e7f0ad58
FB
728 }
729 }
730}
731
6d6f7c28
PB
732/* Set console attributes depending on the current escape codes.
733 * NOTE: I know this code is not very efficient (checking every color for it
734 * self) but it is more readable and better maintainable.
735 */
736static void console_handle_escape(TextConsole *s)
737{
738 int i;
739
6d6f7c28
PB
740 for (i=0; i<s->nb_esc_params; i++) {
741 switch (s->esc_params[i]) {
742 case 0: /* reset all console attributes to default */
743 s->t_attrib = s->t_attrib_default;
744 break;
745 case 1:
746 s->t_attrib.bold = 1;
747 break;
748 case 4:
749 s->t_attrib.uline = 1;
750 break;
751 case 5:
752 s->t_attrib.blink = 1;
753 break;
754 case 7:
755 s->t_attrib.invers = 1;
756 break;
757 case 8:
758 s->t_attrib.unvisible = 1;
759 break;
760 case 22:
761 s->t_attrib.bold = 0;
762 break;
763 case 24:
764 s->t_attrib.uline = 0;
765 break;
766 case 25:
767 s->t_attrib.blink = 0;
768 break;
769 case 27:
770 s->t_attrib.invers = 0;
771 break;
772 case 28:
773 s->t_attrib.unvisible = 0;
774 break;
775 /* set foreground color */
776 case 30:
777 s->t_attrib.fgcol=COLOR_BLACK;
778 break;
779 case 31:
780 s->t_attrib.fgcol=COLOR_RED;
781 break;
782 case 32:
783 s->t_attrib.fgcol=COLOR_GREEN;
784 break;
785 case 33:
786 s->t_attrib.fgcol=COLOR_YELLOW;
787 break;
788 case 34:
789 s->t_attrib.fgcol=COLOR_BLUE;
790 break;
791 case 35:
792 s->t_attrib.fgcol=COLOR_MAGENTA;
793 break;
794 case 36:
795 s->t_attrib.fgcol=COLOR_CYAN;
796 break;
797 case 37:
798 s->t_attrib.fgcol=COLOR_WHITE;
799 break;
800 /* set background color */
801 case 40:
802 s->t_attrib.bgcol=COLOR_BLACK;
803 break;
804 case 41:
805 s->t_attrib.bgcol=COLOR_RED;
806 break;
807 case 42:
808 s->t_attrib.bgcol=COLOR_GREEN;
809 break;
810 case 43:
811 s->t_attrib.bgcol=COLOR_YELLOW;
812 break;
813 case 44:
814 s->t_attrib.bgcol=COLOR_BLUE;
815 break;
816 case 45:
817 s->t_attrib.bgcol=COLOR_MAGENTA;
818 break;
819 case 46:
820 s->t_attrib.bgcol=COLOR_CYAN;
821 break;
822 case 47:
823 s->t_attrib.bgcol=COLOR_WHITE;
824 break;
825 }
826 }
827}
828
adb47967
TS
829static void console_clear_xy(TextConsole *s, int x, int y)
830{
831 int y1 = (s->y_base + y) % s->total_height;
832 TextCell *c = &s->cells[y1 * s->width + x];
833 c->ch = ' ';
834 c->t_attrib = s->t_attrib_default;
adb47967
TS
835 update_xy(s, x, y);
836}
837
e7f0ad58
FB
838static void console_putchar(TextConsole *s, int ch)
839{
840 TextCell *c;
adb47967
TS
841 int y1, i;
842 int x, y;
e7f0ad58
FB
843
844 switch(s->state) {
845 case TTY_STATE_NORM:
846 switch(ch) {
6d6f7c28 847 case '\r': /* carriage return */
e7f0ad58
FB
848 s->x = 0;
849 break;
6d6f7c28 850 case '\n': /* newline */
e7f0ad58
FB
851 console_put_lf(s);
852 break;
6d6f7c28 853 case '\b': /* backspace */
5fafdf24 854 if (s->x > 0)
e15d7371 855 s->x--;
6d6f7c28
PB
856 break;
857 case '\t': /* tabspace */
858 if (s->x + (8 - (s->x % 8)) > s->width) {
bd468840 859 s->x = 0;
6d6f7c28
PB
860 console_put_lf(s);
861 } else {
862 s->x = s->x + (8 - (s->x % 8));
863 }
864 break;
865 case '\a': /* alert aka. bell */
866 /* TODO: has to be implemented */
867 break;
adb47967
TS
868 case 14:
869 /* SI (shift in), character set 0 (ignored) */
870 break;
871 case 15:
872 /* SO (shift out), character set 1 (ignored) */
873 break;
6d6f7c28 874 case 27: /* esc (introducing an escape sequence) */
e7f0ad58
FB
875 s->state = TTY_STATE_ESC;
876 break;
877 default:
ed8276ac
TS
878 if (s->x >= s->width) {
879 /* line wrap */
880 s->x = 0;
881 console_put_lf(s);
adb47967 882 }
e7f0ad58
FB
883 y1 = (s->y_base + s->y) % s->total_height;
884 c = &s->cells[y1 * s->width + s->x];
885 c->ch = ch;
6d6f7c28 886 c->t_attrib = s->t_attrib;
e7f0ad58
FB
887 update_xy(s, s->x, s->y);
888 s->x++;
e7f0ad58
FB
889 break;
890 }
891 break;
6d6f7c28 892 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
e7f0ad58
FB
893 if (ch == '[') {
894 for(i=0;i<MAX_ESC_PARAMS;i++)
895 s->esc_params[i] = 0;
896 s->nb_esc_params = 0;
897 s->state = TTY_STATE_CSI;
898 } else {
899 s->state = TTY_STATE_NORM;
900 }
901 break;
6d6f7c28 902 case TTY_STATE_CSI: /* handle escape sequence parameters */
e7f0ad58
FB
903 if (ch >= '0' && ch <= '9') {
904 if (s->nb_esc_params < MAX_ESC_PARAMS) {
5fafdf24 905 s->esc_params[s->nb_esc_params] =
e7f0ad58
FB
906 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
907 }
908 } else {
909 s->nb_esc_params++;
910 if (ch == ';')
911 break;
adb47967
TS
912#ifdef DEBUG_CONSOLE
913 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
914 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
915#endif
e7f0ad58
FB
916 s->state = TTY_STATE_NORM;
917 switch(ch) {
adb47967
TS
918 case 'A':
919 /* move cursor up */
920 if (s->esc_params[0] == 0) {
921 s->esc_params[0] = 1;
922 }
923 s->y -= s->esc_params[0];
924 if (s->y < 0) {
925 s->y = 0;
926 }
927 break;
928 case 'B':
929 /* move cursor down */
930 if (s->esc_params[0] == 0) {
931 s->esc_params[0] = 1;
932 }
933 s->y += s->esc_params[0];
934 if (s->y >= s->height) {
935 s->y = s->height - 1;
936 }
e7f0ad58
FB
937 break;
938 case 'C':
adb47967
TS
939 /* move cursor right */
940 if (s->esc_params[0] == 0) {
941 s->esc_params[0] = 1;
942 }
943 s->x += s->esc_params[0];
944 if (s->x >= s->width) {
945 s->x = s->width - 1;
946 }
e7f0ad58 947 break;
adb47967
TS
948 case 'D':
949 /* move cursor left */
950 if (s->esc_params[0] == 0) {
951 s->esc_params[0] = 1;
952 }
953 s->x -= s->esc_params[0];
954 if (s->x < 0) {
955 s->x = 0;
956 }
957 break;
958 case 'G':
959 /* move cursor to column */
960 s->x = s->esc_params[0] - 1;
961 if (s->x < 0) {
962 s->x = 0;
963 }
964 break;
965 case 'f':
966 case 'H':
967 /* move cursor to row, column */
968 s->x = s->esc_params[1] - 1;
969 if (s->x < 0) {
970 s->x = 0;
971 }
972 s->y = s->esc_params[0] - 1;
973 if (s->y < 0) {
974 s->y = 0;
975 }
976 break;
977 case 'J':
978 switch (s->esc_params[0]) {
979 case 0:
980 /* clear to end of screen */
981 for (y = s->y; y < s->height; y++) {
982 for (x = 0; x < s->width; x++) {
983 if (y == s->y && x < s->x) {
984 continue;
985 }
986 console_clear_xy(s, x, y);
987 }
988 }
989 break;
990 case 1:
991 /* clear from beginning of screen */
992 for (y = 0; y <= s->y; y++) {
993 for (x = 0; x < s->width; x++) {
994 if (y == s->y && x > s->x) {
995 break;
996 }
997 console_clear_xy(s, x, y);
998 }
999 }
1000 break;
1001 case 2:
1002 /* clear entire screen */
1003 for (y = 0; y <= s->height; y++) {
1004 for (x = 0; x < s->width; x++) {
1005 console_clear_xy(s, x, y);
1006 }
1007 }
1008 break;
1009 }
e7f0ad58 1010 case 'K':
adb47967
TS
1011 switch (s->esc_params[0]) {
1012 case 0:
e7f0ad58 1013 /* clear to eol */
e7f0ad58 1014 for(x = s->x; x < s->width; x++) {
adb47967 1015 console_clear_xy(s, x, s->y);
e7f0ad58
FB
1016 }
1017 break;
adb47967
TS
1018 case 1:
1019 /* clear from beginning of line */
1020 for (x = 0; x <= s->x; x++) {
1021 console_clear_xy(s, x, s->y);
1022 }
1023 break;
1024 case 2:
1025 /* clear entire line */
1026 for(x = 0; x < s->width; x++) {
1027 console_clear_xy(s, x, s->y);
1028 }
e7f0ad58
FB
1029 break;
1030 }
adb47967
TS
1031 break;
1032 case 'm':
6d6f7c28 1033 console_handle_escape(s);
e7f0ad58 1034 break;
adb47967
TS
1035 case 'n':
1036 /* report cursor position */
1037 /* TODO: send ESC[row;colR */
1038 break;
1039 case 's':
1040 /* save cursor position */
1041 s->x_saved = s->x;
1042 s->y_saved = s->y;
1043 break;
1044 case 'u':
1045 /* restore cursor position */
1046 s->x = s->x_saved;
1047 s->y = s->y_saved;
1048 break;
1049 default:
1050#ifdef DEBUG_CONSOLE
1051 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1052#endif
1053 break;
1054 }
1055 break;
e7f0ad58
FB
1056 }
1057 }
1058}
1059
1060void console_select(unsigned int index)
1061{
1062 TextConsole *s;
6d6f7c28 1063
e7f0ad58
FB
1064 if (index >= MAX_CONSOLES)
1065 return;
358664cc
SH
1066 if (active_console) {
1067 active_console->g_width = ds_get_width(active_console->ds);
1068 active_console->g_height = ds_get_height(active_console->ds);
1069 }
e7f0ad58
FB
1070 s = consoles[index];
1071 if (s) {
7d957bd8 1072 DisplayState *ds = s->ds;
e7f0ad58 1073 active_console = s;
68f00996 1074 if (ds_get_bits_per_pixel(s->ds)) {
7b5d76da 1075 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
68f00996
AL
1076 } else {
1077 s->ds->surface->width = s->width;
1078 s->ds->surface->height = s->height;
1079 }
7d957bd8 1080 dpy_resize(s->ds);
4d3b6f6e 1081 vga_hw_invalidate();
e7f0ad58
FB
1082 }
1083}
1084
1085static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1086{
1087 TextConsole *s = chr->opaque;
1088 int i;
1089
14778c20
PB
1090 s->update_x0 = s->width * FONT_WIDTH;
1091 s->update_y0 = s->height * FONT_HEIGHT;
1092 s->update_x1 = 0;
1093 s->update_y1 = 0;
e7f0ad58
FB
1094 console_show_cursor(s, 0);
1095 for(i = 0; i < len; i++) {
1096 console_putchar(s, buf[i]);
1097 }
1098 console_show_cursor(s, 1);
14778c20
PB
1099 if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1100 dpy_update(s->ds, s->update_x0, s->update_y0,
1101 s->update_x1 - s->update_x0,
1102 s->update_y1 - s->update_y0);
1103 }
e7f0ad58
FB
1104 return len;
1105}
1106
e15d7371
FB
1107static void kbd_send_chars(void *opaque)
1108{
1109 TextConsole *s = opaque;
1110 int len;
1111 uint8_t buf[16];
3b46e624 1112
909cda12 1113 len = qemu_chr_be_can_write(s->chr);
e15d7371
FB
1114 if (len > s->out_fifo.count)
1115 len = s->out_fifo.count;
1116 if (len > 0) {
1117 if (len > sizeof(buf))
1118 len = sizeof(buf);
1119 qemu_fifo_read(&s->out_fifo, buf, len);
fa5efccb 1120 qemu_chr_be_write(s->chr, buf, len);
e15d7371
FB
1121 }
1122 /* characters are pending: we send them a bit later (XXX:
1123 horrible, should change char device API) */
1124 if (s->out_fifo.count > 0) {
7bd427d8 1125 qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
e15d7371
FB
1126 }
1127}
1128
e7f0ad58
FB
1129/* called when an ascii key is pressed */
1130void kbd_put_keysym(int keysym)
1131{
1132 TextConsole *s;
1133 uint8_t buf[16], *q;
1134 int c;
1135
1136 s = active_console;
af3a9031 1137 if (!s || (s->console_type == GRAPHIC_CONSOLE))
e7f0ad58
FB
1138 return;
1139
1140 switch(keysym) {
1141 case QEMU_KEY_CTRL_UP:
1142 console_scroll(-1);
1143 break;
1144 case QEMU_KEY_CTRL_DOWN:
1145 console_scroll(1);
1146 break;
1147 case QEMU_KEY_CTRL_PAGEUP:
1148 console_scroll(-10);
1149 break;
1150 case QEMU_KEY_CTRL_PAGEDOWN:
1151 console_scroll(10);
1152 break;
1153 default:
e15d7371
FB
1154 /* convert the QEMU keysym to VT100 key string */
1155 q = buf;
1156 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1157 *q++ = '\033';
1158 *q++ = '[';
1159 c = keysym - 0xe100;
1160 if (c >= 10)
1161 *q++ = '0' + (c / 10);
1162 *q++ = '0' + (c % 10);
1163 *q++ = '~';
1164 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1165 *q++ = '\033';
1166 *q++ = '[';
1167 *q++ = keysym & 0xff;
4104833f
PB
1168 } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1169 console_puts(s->chr, (const uint8_t *) "\r", 1);
1170 *q++ = '\n';
e15d7371 1171 } else {
4104833f
PB
1172 *q++ = keysym;
1173 }
1174 if (s->echo) {
1175 console_puts(s->chr, buf, q - buf);
e15d7371 1176 }
e5b0bc44 1177 if (s->chr->chr_read) {
e15d7371
FB
1178 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1179 kbd_send_chars(s);
e7f0ad58
FB
1180 }
1181 break;
1182 }
1183}
1184
4d3b6f6e
AZ
1185static void text_console_invalidate(void *opaque)
1186{
1187 TextConsole *s = (TextConsole *) opaque;
68f00996
AL
1188 if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1189 s->g_width = ds_get_width(s->ds);
1190 s->g_height = ds_get_height(s->ds);
1191 text_console_resize(s);
1192 }
4d3b6f6e
AZ
1193 console_refresh(s);
1194}
1195
c227f099 1196static void text_console_update(void *opaque, console_ch_t *chardata)
4d3b6f6e
AZ
1197{
1198 TextConsole *s = (TextConsole *) opaque;
1199 int i, j, src;
1200
1201 if (s->text_x[0] <= s->text_x[1]) {
1202 src = (s->y_base + s->text_y[0]) * s->width;
1203 chardata += s->text_y[0] * s->width;
1204 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1205 for (j = 0; j < s->width; j ++, src ++)
1206 console_write_ch(chardata ++, s->cells[src].ch |
1207 (s->cells[src].t_attrib.fgcol << 12) |
1208 (s->cells[src].t_attrib.bgcol << 8) |
1209 (s->cells[src].t_attrib.bold << 21));
1210 dpy_update(s->ds, s->text_x[0], s->text_y[0],
1211 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1212 s->text_x[0] = s->width;
1213 s->text_y[0] = s->height;
1214 s->text_x[1] = 0;
1215 s->text_y[1] = 0;
1216 }
1217 if (s->cursor_invalidate) {
1218 dpy_cursor(s->ds, s->x, s->y);
1219 s->cursor_invalidate = 0;
1220 }
1221}
1222
42aa98e8 1223static TextConsole *get_graphic_console(DisplayState *ds)
a147d62b 1224{
3023f332
AL
1225 int i;
1226 TextConsole *s;
1227 for (i = 0; i < nb_consoles; i++) {
1228 s = consoles[i];
42aa98e8 1229 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
3023f332
AL
1230 return s;
1231 }
1232 return NULL;
1233}
1234
c227f099 1235static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
e7f0ad58
FB
1236{
1237 TextConsole *s;
95219897 1238 int i;
e7f0ad58
FB
1239
1240 if (nb_consoles >= MAX_CONSOLES)
1241 return NULL;
7267c094 1242 s = g_malloc0(sizeof(TextConsole));
af3a9031
TS
1243 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1244 (console_type == GRAPHIC_CONSOLE))) {
e7f0ad58 1245 active_console = s;
af3a9031 1246 }
e7f0ad58 1247 s->ds = ds;
af3a9031
TS
1248 s->console_type = console_type;
1249 if (console_type != GRAPHIC_CONSOLE) {
95219897
PB
1250 consoles[nb_consoles++] = s;
1251 } else {
1252 /* HACK: Put graphical consoles before text consoles. */
1253 for (i = nb_consoles; i > 0; i--) {
af3a9031 1254 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
95219897
PB
1255 break;
1256 consoles[i] = consoles[i - 1];
1257 }
1258 consoles[i] = s;
3023f332 1259 nb_consoles++;
95219897
PB
1260 }
1261 return s;
1262}
1263
98b50080
PB
1264static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1265{
7267c094 1266 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
98b50080 1267
ffe8b821
JS
1268 int linesize = width * 4;
1269 qemu_alloc_display(surface, width, height, linesize,
1270 qemu_default_pixelformat(32), 0);
98b50080
PB
1271 return surface;
1272}
1273
1274static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1275 int width, int height)
1276{
ffe8b821
JS
1277 int linesize = width * 4;
1278 qemu_alloc_display(surface, width, height, linesize,
1279 qemu_default_pixelformat(32), 0);
1280 return surface;
1281}
1282
1283void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1284 int linesize, PixelFormat pf, int newflags)
1285{
1286 void *data;
98b50080
PB
1287 surface->width = width;
1288 surface->height = height;
ffe8b821
JS
1289 surface->linesize = linesize;
1290 surface->pf = pf;
1291 if (surface->flags & QEMU_ALLOCATED_FLAG) {
7267c094 1292 data = g_realloc(surface->data,
ffe8b821
JS
1293 surface->linesize * surface->height);
1294 } else {
7267c094 1295 data = g_malloc(surface->linesize * surface->height);
ffe8b821
JS
1296 }
1297 surface->data = (uint8_t *)data;
1298 surface->flags = newflags | QEMU_ALLOCATED_FLAG;
98b50080 1299#ifdef HOST_WORDS_BIGENDIAN
ffe8b821 1300 surface->flags |= QEMU_BIG_ENDIAN_FLAG;
98b50080 1301#endif
98b50080
PB
1302}
1303
1304DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1305 int linesize, uint8_t *data)
1306{
7267c094 1307 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
98b50080
PB
1308
1309 surface->width = width;
1310 surface->height = height;
1311 surface->linesize = linesize;
1312 surface->pf = qemu_default_pixelformat(bpp);
1313#ifdef HOST_WORDS_BIGENDIAN
1314 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1315#endif
1316 surface->data = data;
1317
1318 return surface;
1319}
1320
1321static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1322{
1323 if (surface == NULL)
1324 return;
1325 if (surface->flags & QEMU_ALLOCATED_FLAG)
7267c094
AL
1326 g_free(surface->data);
1327 g_free(surface);
98b50080
PB
1328}
1329
1330static struct DisplayAllocator default_allocator = {
1331 defaultallocator_create_displaysurface,
1332 defaultallocator_resize_displaysurface,
1333 defaultallocator_free_displaysurface
1334};
1335
1336static void dumb_display_init(void)
1337{
7267c094 1338 DisplayState *ds = g_malloc0(sizeof(DisplayState));
1802651c
JK
1339 int width = 640;
1340 int height = 480;
1341
98b50080 1342 ds->allocator = &default_allocator;
1802651c
JK
1343 if (is_fixedsize_console()) {
1344 width = active_console->g_width;
1345 height = active_console->g_height;
1346 }
1347 ds->surface = qemu_create_displaysurface(ds, width, height);
98b50080
PB
1348 register_displaystate(ds);
1349}
1350
1351/***********************************************************/
1352/* register display */
1353
1354void register_displaystate(DisplayState *ds)
1355{
1356 DisplayState **s;
1357 s = &display_state;
1358 while (*s != NULL)
1359 s = &(*s)->next;
1360 ds->next = NULL;
1361 *s = ds;
1362}
1363
1364DisplayState *get_displaystate(void)
1365{
1366 if (!display_state) {
1367 dumb_display_init ();
1368 }
1369 return display_state;
1370}
1371
1372DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1373{
1374 if(ds->allocator == &default_allocator) {
1375 DisplaySurface *surf;
1376 surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1377 defaultallocator_free_displaysurface(ds->surface);
1378 ds->surface = surf;
1379 ds->allocator = da;
1380 }
1381 return ds->allocator;
1382}
1383
3023f332
AL
1384DisplayState *graphic_console_init(vga_hw_update_ptr update,
1385 vga_hw_invalidate_ptr invalidate,
1386 vga_hw_screen_dump_ptr screen_dump,
1387 vga_hw_text_update_ptr text_update,
1388 void *opaque)
95219897
PB
1389{
1390 TextConsole *s;
3023f332 1391 DisplayState *ds;
f0f2f976 1392
7267c094 1393 ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
7b5d76da
AL
1394 ds->allocator = &default_allocator;
1395 ds->surface = qemu_create_displaysurface(ds, 640, 480);
95219897 1396
af3a9031 1397 s = new_console(ds, GRAPHIC_CONSOLE);
3023f332 1398 if (s == NULL) {
7b5d76da 1399 qemu_free_displaysurface(ds);
7267c094 1400 g_free(ds);
3023f332
AL
1401 return NULL;
1402 }
95219897
PB
1403 s->hw_update = update;
1404 s->hw_invalidate = invalidate;
1405 s->hw_screen_dump = screen_dump;
4d3b6f6e 1406 s->hw_text_update = text_update;
95219897 1407 s->hw = opaque;
3023f332 1408
f0f2f976 1409 register_displaystate(ds);
3023f332 1410 return ds;
e7f0ad58
FB
1411}
1412
95219897 1413int is_graphic_console(void)
e7f0ad58 1414{
4d3b6f6e 1415 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
e7f0ad58
FB
1416}
1417
c21bbcfa
AZ
1418int is_fixedsize_console(void)
1419{
1420 return active_console && active_console->console_type != TEXT_CONSOLE;
1421}
1422
a528b80c
AZ
1423void console_color_init(DisplayState *ds)
1424{
1425 int i, j;
1426 for (j = 0; j < 2; j++) {
1427 for (i = 0; i < 8; i++) {
f0f2f976 1428 color_table[j][i] = col_expand(ds,
a528b80c
AZ
1429 vga_get_color(ds, color_table_rgb[j][i]));
1430 }
1431 }
1432}
1433
2796dae0
AL
1434static int n_text_consoles;
1435static CharDriverState *text_consoles[128];
2796dae0 1436
4104833f
PB
1437static void text_console_set_echo(CharDriverState *chr, bool echo)
1438{
1439 TextConsole *s = chr->opaque;
1440
1441 s->echo = echo;
1442}
1443
44b37b93 1444static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
e7f0ad58 1445{
e7f0ad58 1446 TextConsole *s;
e7f0ad58 1447 static int color_inited;
6d6f7c28 1448
491e114a 1449 s = chr->opaque;
6ea314d9 1450
e7f0ad58 1451 chr->chr_write = console_puts;
6fcfafb7 1452
e15d7371
FB
1453 s->out_fifo.buf = s->out_fifo_buf;
1454 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
7bd427d8 1455 s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
3023f332 1456 s->ds = ds;
3b46e624 1457
e7f0ad58
FB
1458 if (!color_inited) {
1459 color_inited = 1;
a528b80c 1460 console_color_init(s->ds);
e7f0ad58
FB
1461 }
1462 s->y_displayed = 0;
1463 s->y_base = 0;
1464 s->total_height = DEFAULT_BACKSCROLL;
1465 s->x = 0;
1466 s->y = 0;
491e114a
PB
1467 if (s->console_type == TEXT_CONSOLE) {
1468 s->g_width = ds_get_width(s->ds);
1469 s->g_height = ds_get_height(s->ds);
1470 }
6d6f7c28 1471
4d3b6f6e
AZ
1472 s->hw_invalidate = text_console_invalidate;
1473 s->hw_text_update = text_console_update;
1474 s->hw = s;
1475
6d6f7c28
PB
1476 /* Set text attribute defaults */
1477 s->t_attrib_default.bold = 0;
1478 s->t_attrib_default.uline = 0;
1479 s->t_attrib_default.blink = 0;
1480 s->t_attrib_default.invers = 0;
1481 s->t_attrib_default.unvisible = 0;
1482 s->t_attrib_default.fgcol = COLOR_WHITE;
1483 s->t_attrib_default.bgcol = COLOR_BLACK;
6d6f7c28
PB
1484 /* set current text attributes to default */
1485 s->t_attrib = s->t_attrib_default;
e7f0ad58
FB
1486 text_console_resize(s);
1487
51bfa4d3
GH
1488 if (chr->label) {
1489 char msg[128];
1490 int len;
1491
735ba588 1492 s->t_attrib.bgcol = COLOR_BLUE;
51bfa4d3
GH
1493 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1494 console_puts(chr, (uint8_t*)msg, len);
735ba588 1495 s->t_attrib = s->t_attrib_default;
51bfa4d3
GH
1496 }
1497
127338e6 1498 qemu_chr_generic_open(chr);
ceecf1d1
AJ
1499 if (chr->init)
1500 chr->init(chr);
e7f0ad58 1501}
c60e08d9 1502
6e1db57b 1503int text_console_init(QemuOpts *opts, CharDriverState **_chr)
2796dae0
AL
1504{
1505 CharDriverState *chr;
491e114a
PB
1506 TextConsole *s;
1507 unsigned width;
1508 unsigned height;
2796dae0 1509
7267c094 1510 chr = g_malloc0(sizeof(CharDriverState));
2796dae0
AL
1511
1512 if (n_text_consoles == 128) {
1513 fprintf(stderr, "Too many text consoles\n");
1514 exit(1);
1515 }
1516 text_consoles[n_text_consoles] = chr;
2796dae0
AL
1517 n_text_consoles++;
1518
491e114a
PB
1519 width = qemu_opt_get_number(opts, "width", 0);
1520 if (width == 0)
1521 width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1522
1523 height = qemu_opt_get_number(opts, "height", 0);
1524 if (height == 0)
1525 height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1526
1527 if (width == 0 || height == 0) {
1528 s = new_console(NULL, TEXT_CONSOLE);
1529 } else {
1530 s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1531 }
1532
1533 if (!s) {
1534 free(chr);
6e1db57b 1535 return -EBUSY;
491e114a
PB
1536 }
1537
1538 s->chr = chr;
1539 s->g_width = width;
1540 s->g_height = height;
1541 chr->opaque = s;
4104833f 1542 chr->chr_set_echo = text_console_set_echo;
6e1db57b
KW
1543
1544 *_chr = chr;
1545 return 0;
2796dae0
AL
1546}
1547
1548void text_consoles_set_display(DisplayState *ds)
1549{
1550 int i;
1551
1552 for (i = 0; i < n_text_consoles; i++) {
44b37b93 1553 text_console_do_init(text_consoles[i], ds);
2796dae0
AL
1554 }
1555
1556 n_text_consoles = 0;
1557}
1558
3023f332 1559void qemu_console_resize(DisplayState *ds, int width, int height)
c60e08d9 1560{
42aa98e8 1561 TextConsole *s = get_graphic_console(ds);
f497f140
AL
1562 if (!s) return;
1563
3023f332
AL
1564 s->g_width = width;
1565 s->g_height = height;
1566 if (is_graphic_console()) {
7b5d76da 1567 ds->surface = qemu_resize_displaysurface(ds, width, height);
3023f332 1568 dpy_resize(ds);
c60e08d9
PB
1569 }
1570}
38334f76 1571
3023f332
AL
1572void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1573 int dst_x, int dst_y, int w, int h)
c21bbcfa 1574{
3023f332
AL
1575 if (is_graphic_console()) {
1576 dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
38334f76
AZ
1577 }
1578}
7d957bd8 1579
0da2ea1b 1580PixelFormat qemu_different_endianness_pixelformat(int bpp)
7d957bd8
AL
1581{
1582 PixelFormat pf;
1583
1584 memset(&pf, 0x00, sizeof(PixelFormat));
1585
1586 pf.bits_per_pixel = bpp;
1587 pf.bytes_per_pixel = bpp / 8;
1588 pf.depth = bpp == 32 ? 24 : bpp;
1589
1590 switch (bpp) {
0da2ea1b 1591 case 24:
1592 pf.rmask = 0x000000FF;
1593 pf.gmask = 0x0000FF00;
1594 pf.bmask = 0x00FF0000;
1595 pf.rmax = 255;
1596 pf.gmax = 255;
1597 pf.bmax = 255;
1598 pf.rshift = 0;
1599 pf.gshift = 8;
1600 pf.bshift = 16;
90a1e3c0
AL
1601 pf.rbits = 8;
1602 pf.gbits = 8;
1603 pf.bbits = 8;
7d957bd8 1604 break;
0da2ea1b 1605 case 32:
1606 pf.rmask = 0x0000FF00;
1607 pf.gmask = 0x00FF0000;
1608 pf.bmask = 0xFF000000;
1609 pf.amask = 0x00000000;
1610 pf.amax = 255;
1611 pf.rmax = 255;
1612 pf.gmax = 255;
1613 pf.bmax = 255;
1614 pf.ashift = 0;
1615 pf.rshift = 8;
1616 pf.gshift = 16;
1617 pf.bshift = 24;
90a1e3c0
AL
1618 pf.rbits = 8;
1619 pf.gbits = 8;
1620 pf.bbits = 8;
1621 pf.abits = 8;
0da2ea1b 1622 break;
1623 default:
1624 break;
1625 }
1626 return pf;
1627}
1628
1629PixelFormat qemu_default_pixelformat(int bpp)
1630{
1631 PixelFormat pf;
1632
1633 memset(&pf, 0x00, sizeof(PixelFormat));
1634
1635 pf.bits_per_pixel = bpp;
1636 pf.bytes_per_pixel = bpp / 8;
1637 pf.depth = bpp == 32 ? 24 : bpp;
1638
1639 switch (bpp) {
b6278084
GH
1640 case 15:
1641 pf.bits_per_pixel = 16;
1642 pf.bytes_per_pixel = 2;
1643 pf.rmask = 0x00007c00;
1644 pf.gmask = 0x000003E0;
1645 pf.bmask = 0x0000001F;
1646 pf.rmax = 31;
1647 pf.gmax = 31;
1648 pf.bmax = 31;
1649 pf.rshift = 10;
1650 pf.gshift = 5;
1651 pf.bshift = 0;
1652 pf.rbits = 5;
1653 pf.gbits = 5;
1654 pf.bbits = 5;
1655 break;
7d957bd8
AL
1656 case 16:
1657 pf.rmask = 0x0000F800;
1658 pf.gmask = 0x000007E0;
1659 pf.bmask = 0x0000001F;
1660 pf.rmax = 31;
1661 pf.gmax = 63;
1662 pf.bmax = 31;
1663 pf.rshift = 11;
1664 pf.gshift = 5;
1665 pf.bshift = 0;
90a1e3c0
AL
1666 pf.rbits = 5;
1667 pf.gbits = 6;
1668 pf.bbits = 5;
7d957bd8
AL
1669 break;
1670 case 24:
0da2ea1b 1671 pf.rmask = 0x00FF0000;
1672 pf.gmask = 0x0000FF00;
1673 pf.bmask = 0x000000FF;
1674 pf.rmax = 255;
1675 pf.gmax = 255;
1676 pf.bmax = 255;
1677 pf.rshift = 16;
1678 pf.gshift = 8;
1679 pf.bshift = 0;
90a1e3c0
AL
1680 pf.rbits = 8;
1681 pf.gbits = 8;
1682 pf.bbits = 8;
7d957bd8
AL
1683 case 32:
1684 pf.rmask = 0x00FF0000;
1685 pf.gmask = 0x0000FF00;
1686 pf.bmask = 0x000000FF;
0da2ea1b 1687 pf.amax = 255;
7d957bd8
AL
1688 pf.rmax = 255;
1689 pf.gmax = 255;
1690 pf.bmax = 255;
0da2ea1b 1691 pf.ashift = 24;
7d957bd8
AL
1692 pf.rshift = 16;
1693 pf.gshift = 8;
1694 pf.bshift = 0;
90a1e3c0
AL
1695 pf.rbits = 8;
1696 pf.gbits = 8;
1697 pf.bbits = 8;
1698 pf.abits = 8;
7d957bd8
AL
1699 break;
1700 default:
1701 break;
1702 }
1703 return pf;
1704}