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