blob: 785710a8b6e2fc45ed6d57e56c2ff5e876a9d47c [file] [log] [blame]
bellarde7f0ad52004-07-14 17:28:59 +00001/*
2 * QEMU graphical console
ths5fafdf22007-09-16 21:08:06 +00003 *
bellarde7f0ad52004-07-14 17:28:59 +00004 * Copyright (c) 2004 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
bellarde7f0ad52004-07-14 17:28:59 +00006 * 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 */
pbrook87ecb682007-11-17 17:14:51 +000024#include "qemu-common.h"
25#include "console.h"
26#include "qemu-timer.h"
bellarde7f0ad52004-07-14 17:28:59 +000027
pbrook6d6f7c22006-03-11 15:35:30 +000028//#define DEBUG_CONSOLE
bellarde7f0ad52004-07-14 17:28:59 +000029#define DEFAULT_BACKSCROLL 512
30#define MAX_CONSOLES 12
pbrookc60e08d2008-07-01 16:24:38 +000031#define DEFAULT_MONITOR_SIZE "800x600"
bellarde7f0ad52004-07-14 17:28:59 +000032
bellard26489842006-06-25 17:37:36 +000033#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
34#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
bellarde7f0ad52004-07-14 17:28:59 +000035
pbrook6d6f7c22006-03-11 15:35:30 +000036typedef struct TextAttributes {
37 uint8_t fgcol:4;
38 uint8_t bgcol:4;
39 uint8_t bold:1;
40 uint8_t uline:1;
41 uint8_t blink:1;
42 uint8_t invers:1;
43 uint8_t unvisible:1;
44} TextAttributes;
45
bellarde7f0ad52004-07-14 17:28:59 +000046typedef struct TextCell {
47 uint8_t ch;
pbrook6d6f7c22006-03-11 15:35:30 +000048 TextAttributes t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +000049} TextCell;
50
51#define MAX_ESC_PARAMS 3
52
53enum TTYState {
54 TTY_STATE_NORM,
55 TTY_STATE_ESC,
56 TTY_STATE_CSI,
57};
58
bellarde15d7372006-06-25 16:26:29 +000059typedef struct QEMUFIFO {
60 uint8_t *buf;
61 int buf_size;
62 int count, wptr, rptr;
63} QEMUFIFO;
64
pbrook9596ebb2007-11-18 01:44:38 +000065static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
bellarde15d7372006-06-25 16:26:29 +000066{
67 int l, len;
68
69 l = f->buf_size - f->count;
70 if (len1 > l)
71 len1 = l;
72 len = len1;
73 while (len > 0) {
74 l = f->buf_size - f->wptr;
75 if (l > len)
76 l = len;
77 memcpy(f->buf + f->wptr, buf, l);
78 f->wptr += l;
79 if (f->wptr >= f->buf_size)
80 f->wptr = 0;
81 buf += l;
82 len -= l;
83 }
84 f->count += len1;
85 return len1;
86}
87
pbrook9596ebb2007-11-18 01:44:38 +000088static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
bellarde15d7372006-06-25 16:26:29 +000089{
90 int l, len;
91
92 if (len1 > f->count)
93 len1 = f->count;
94 len = len1;
95 while (len > 0) {
96 l = f->buf_size - f->rptr;
97 if (l > len)
98 l = len;
99 memcpy(buf, f->buf + f->rptr, l);
100 f->rptr += l;
101 if (f->rptr >= f->buf_size)
102 f->rptr = 0;
103 buf += l;
104 len -= l;
105 }
106 f->count -= len1;
107 return len1;
108}
109
thsaf3a9032007-07-11 23:14:59 +0000110typedef enum {
111 GRAPHIC_CONSOLE,
pbrookc60e08d2008-07-01 16:24:38 +0000112 TEXT_CONSOLE
thsaf3a9032007-07-11 23:14:59 +0000113} console_type_t;
114
pbrook95219892006-04-09 01:06:34 +0000115/* ??? This is mis-named.
116 It is used for both text and graphical consoles. */
bellarde7f0ad52004-07-14 17:28:59 +0000117struct TextConsole {
thsaf3a9032007-07-11 23:14:59 +0000118 console_type_t console_type;
bellarde7f0ad52004-07-14 17:28:59 +0000119 DisplayState *ds;
pbrook95219892006-04-09 01:06:34 +0000120 /* 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;
balrog4d3b6f62008-02-10 16:33:14 +0000124 vga_hw_text_update_ptr hw_text_update;
pbrook95219892006-04-09 01:06:34 +0000125 void *hw;
126
bellarde7f0ad52004-07-14 17:28:59 +0000127 int g_width, g_height;
128 int width;
129 int height;
130 int total_height;
131 int backscroll_height;
bellarde7f0ad52004-07-14 17:28:59 +0000132 int x, y;
thsadb47962007-01-16 23:02:36 +0000133 int x_saved, y_saved;
bellarde7f0ad52004-07-14 17:28:59 +0000134 int y_displayed;
135 int y_base;
pbrook6d6f7c22006-03-11 15:35:30 +0000136 TextAttributes t_attrib_default; /* default text attributes */
137 TextAttributes t_attrib; /* currently active text attributes */
bellarde7f0ad52004-07-14 17:28:59 +0000138 TextCell *cells;
balrog4d3b6f62008-02-10 16:33:14 +0000139 int text_x[2], text_y[2], cursor_invalidate;
bellarde7f0ad52004-07-14 17:28:59 +0000140
141 enum TTYState state;
142 int esc_params[MAX_ESC_PARAMS];
143 int nb_esc_params;
144
pbrooke5b0bc42007-01-27 23:46:43 +0000145 CharDriverState *chr;
bellarde15d7372006-06-25 16:26:29 +0000146 /* fifo for key pressed */
147 QEMUFIFO out_fifo;
148 uint8_t out_fifo_buf[16];
149 QEMUTimer *kbd_timer;
bellarde7f0ad52004-07-14 17:28:59 +0000150};
151
152static TextConsole *active_console;
153static TextConsole *consoles[MAX_CONSOLES];
154static int nb_consoles = 0;
155
pbrook95219892006-04-09 01:06:34 +0000156void vga_hw_update(void)
157{
thsadb47962007-01-16 23:02:36 +0000158 if (active_console && active_console->hw_update)
pbrook95219892006-04-09 01:06:34 +0000159 active_console->hw_update(active_console->hw);
160}
161
162void vga_hw_invalidate(void)
163{
164 if (active_console->hw_invalidate)
165 active_console->hw_invalidate(active_console->hw);
166}
167
168void vga_hw_screen_dump(const char *filename)
169{
balrog8571c052008-07-19 13:04:26 +0000170 TextConsole *previous_active_console;
171
172 previous_active_console = active_console;
173 active_console = consoles[0];
174 /* There is currently no way of specifying which screen we want to dump,
aurel327b455222008-09-02 00:09:16 +0000175 so always dump the first one. */
pbrook95219892006-04-09 01:06:34 +0000176 if (consoles[0]->hw_screen_dump)
177 consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
balrog8571c052008-07-19 13:04:26 +0000178 active_console = previous_active_console;
pbrook95219892006-04-09 01:06:34 +0000179}
180
balrog4d3b6f62008-02-10 16:33:14 +0000181void vga_hw_text_update(console_ch_t *chardata)
182{
183 if (active_console && active_console->hw_text_update)
184 active_console->hw_text_update(active_console->hw, chardata);
185}
186
bellarde7f0ad52004-07-14 17:28:59 +0000187/* convert a RGBA color to a color index usable in graphic primitives */
188static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
189{
190 unsigned int r, g, b, color;
191
192 switch(ds->depth) {
193#if 0
194 case 8:
195 r = (rgba >> 16) & 0xff;
196 g = (rgba >> 8) & 0xff;
197 b = (rgba) & 0xff;
ths5fafdf22007-09-16 21:08:06 +0000198 color = (rgb_to_index[r] * 6 * 6) +
199 (rgb_to_index[g] * 6) +
bellarde7f0ad52004-07-14 17:28:59 +0000200 (rgb_to_index[b]);
201 break;
202#endif
203 case 15:
204 r = (rgba >> 16) & 0xff;
205 g = (rgba >> 8) & 0xff;
206 b = (rgba) & 0xff;
207 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
208 break;
209 case 16:
210 r = (rgba >> 16) & 0xff;
211 g = (rgba >> 8) & 0xff;
212 b = (rgba) & 0xff;
213 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
214 break;
215 case 32:
216 default:
217 color = rgba;
218 break;
219 }
220 return color;
221}
222
ths5fafdf22007-09-16 21:08:06 +0000223static void vga_fill_rect (DisplayState *ds,
bellarde7f0ad52004-07-14 17:28:59 +0000224 int posx, int posy, int width, int height, uint32_t color)
225{
226 uint8_t *d, *d1;
227 int x, y, bpp;
ths3b46e622007-09-17 08:09:54 +0000228
bellarde7f0ad52004-07-14 17:28:59 +0000229 bpp = (ds->depth + 7) >> 3;
ths5fafdf22007-09-16 21:08:06 +0000230 d1 = ds->data +
bellarde7f0ad52004-07-14 17:28:59 +0000231 ds->linesize * posy + bpp * posx;
232 for (y = 0; y < height; y++) {
233 d = d1;
234 switch(bpp) {
235 case 1:
236 for (x = 0; x < width; x++) {
237 *((uint8_t *)d) = color;
238 d++;
239 }
240 break;
241 case 2:
242 for (x = 0; x < width; x++) {
243 *((uint16_t *)d) = color;
244 d += 2;
245 }
246 break;
247 case 4:
248 for (x = 0; x < width; x++) {
249 *((uint32_t *)d) = color;
250 d += 4;
251 }
252 break;
253 }
254 d1 += ds->linesize;
255 }
256}
257
258/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
259static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
260{
261 const uint8_t *s;
262 uint8_t *d;
263 int wb, y, bpp;
264
265 bpp = (ds->depth + 7) >> 3;
266 wb = w * bpp;
267 if (yd <= ys) {
ths5fafdf22007-09-16 21:08:06 +0000268 s = ds->data +
bellarde7f0ad52004-07-14 17:28:59 +0000269 ds->linesize * ys + bpp * xs;
ths5fafdf22007-09-16 21:08:06 +0000270 d = ds->data +
bellarde7f0ad52004-07-14 17:28:59 +0000271 ds->linesize * yd + bpp * xd;
272 for (y = 0; y < h; y++) {
273 memmove(d, s, wb);
274 d += ds->linesize;
275 s += ds->linesize;
276 }
277 } else {
ths5fafdf22007-09-16 21:08:06 +0000278 s = ds->data +
bellarde7f0ad52004-07-14 17:28:59 +0000279 ds->linesize * (ys + h - 1) + bpp * xs;
ths5fafdf22007-09-16 21:08:06 +0000280 d = ds->data +
bellarde7f0ad52004-07-14 17:28:59 +0000281 ds->linesize * (yd + h - 1) + bpp * xd;
282 for (y = 0; y < h; y++) {
283 memmove(d, s, wb);
284 d -= ds->linesize;
285 s -= ds->linesize;
286 }
287 }
288}
289
290/***********************************************************/
291/* basic char display */
292
293#define FONT_HEIGHT 16
294#define FONT_WIDTH 8
295
296#include "vgafont.h"
297
298#define cbswap_32(__x) \
299((uint32_t)( \
300 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
301 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
302 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
303 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
304
305#ifdef WORDS_BIGENDIAN
306#define PAT(x) x
307#else
308#define PAT(x) cbswap_32(x)
309#endif
310
311static const uint32_t dmask16[16] = {
312 PAT(0x00000000),
313 PAT(0x000000ff),
314 PAT(0x0000ff00),
315 PAT(0x0000ffff),
316 PAT(0x00ff0000),
317 PAT(0x00ff00ff),
318 PAT(0x00ffff00),
319 PAT(0x00ffffff),
320 PAT(0xff000000),
321 PAT(0xff0000ff),
322 PAT(0xff00ff00),
323 PAT(0xff00ffff),
324 PAT(0xffff0000),
325 PAT(0xffff00ff),
326 PAT(0xffffff00),
327 PAT(0xffffffff),
328};
329
330static const uint32_t dmask4[4] = {
331 PAT(0x00000000),
332 PAT(0x0000ffff),
333 PAT(0xffff0000),
334 PAT(0xffffffff),
335};
336
pbrook6d6f7c22006-03-11 15:35:30 +0000337static uint32_t color_table[2][8];
bellarde7f0ad52004-07-14 17:28:59 +0000338
pbrook6d6f7c22006-03-11 15:35:30 +0000339enum color_names {
340 COLOR_BLACK = 0,
341 COLOR_RED = 1,
342 COLOR_GREEN = 2,
343 COLOR_YELLOW = 3,
344 COLOR_BLUE = 4,
345 COLOR_MAGENTA = 5,
346 COLOR_CYAN = 6,
347 COLOR_WHITE = 7
348};
349
350static const uint32_t color_table_rgb[2][8] = {
351 { /* dark */
bellard26489842006-06-25 17:37:36 +0000352 QEMU_RGB(0x00, 0x00, 0x00), /* black */
353 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
354 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
355 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
356 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
357 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
358 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
359 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000360 },
361 { /* bright */
bellard26489842006-06-25 17:37:36 +0000362 QEMU_RGB(0x00, 0x00, 0x00), /* black */
363 QEMU_RGB(0xff, 0x00, 0x00), /* red */
364 QEMU_RGB(0x00, 0xff, 0x00), /* green */
365 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
366 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
367 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
368 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
369 QEMU_RGB(0xff, 0xff, 0xff), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000370 }
bellarde7f0ad52004-07-14 17:28:59 +0000371};
372
373static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
374{
375 switch(ds->depth) {
376 case 8:
377 col |= col << 8;
378 col |= col << 16;
379 break;
380 case 15:
381 case 16:
382 col |= col << 16;
383 break;
384 default:
385 break;
386 }
387
388 return col;
389}
pbrook6d6f7c22006-03-11 15:35:30 +0000390#ifdef DEBUG_CONSOLE
391static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
392{
393 if (t_attrib->bold) {
394 printf("b");
395 } else {
396 printf(" ");
397 }
398 if (t_attrib->uline) {
399 printf("u");
400 } else {
401 printf(" ");
402 }
403 if (t_attrib->blink) {
404 printf("l");
405 } else {
406 printf(" ");
407 }
408 if (t_attrib->invers) {
409 printf("i");
410 } else {
411 printf(" ");
412 }
413 if (t_attrib->unvisible) {
414 printf("n");
415 } else {
416 printf(" ");
417 }
418
419 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
420}
421#endif
bellarde7f0ad52004-07-14 17:28:59 +0000422
ths5fafdf22007-09-16 21:08:06 +0000423static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000424 TextAttributes *t_attrib)
bellarde7f0ad52004-07-14 17:28:59 +0000425{
426 uint8_t *d;
427 const uint8_t *font_ptr;
428 unsigned int font_data, linesize, xorcol, bpp;
429 int i;
pbrook6d6f7c22006-03-11 15:35:30 +0000430 unsigned int fgcol, bgcol;
431
432#ifdef DEBUG_CONSOLE
433 printf("x: %2i y: %2i", x, y);
434 console_print_text_attributes(t_attrib, ch);
435#endif
436
437 if (t_attrib->invers) {
438 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
439 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
440 } else {
441 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
442 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
443 }
bellarde7f0ad52004-07-14 17:28:59 +0000444
445 bpp = (ds->depth + 7) >> 3;
ths5fafdf22007-09-16 21:08:06 +0000446 d = ds->data +
bellarde7f0ad52004-07-14 17:28:59 +0000447 ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
448 linesize = ds->linesize;
449 font_ptr = vgafont16 + FONT_HEIGHT * ch;
450 xorcol = bgcol ^ fgcol;
451 switch(ds->depth) {
452 case 8:
453 for(i = 0; i < FONT_HEIGHT; i++) {
454 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000455 if (t_attrib->uline
456 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
457 font_data = 0xFFFF;
458 }
bellarde7f0ad52004-07-14 17:28:59 +0000459 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
460 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
461 d += linesize;
462 }
463 break;
464 case 16:
465 case 15:
466 for(i = 0; i < FONT_HEIGHT; i++) {
467 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000468 if (t_attrib->uline
469 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
470 font_data = 0xFFFF;
471 }
bellarde7f0ad52004-07-14 17:28:59 +0000472 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
473 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
474 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
475 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
476 d += linesize;
477 }
478 break;
479 case 32:
480 for(i = 0; i < FONT_HEIGHT; i++) {
481 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000482 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
483 font_data = 0xFFFF;
484 }
bellarde7f0ad52004-07-14 17:28:59 +0000485 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
486 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
487 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
488 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
489 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
490 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
491 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
492 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
493 d += linesize;
494 }
495 break;
496 }
497}
498
499static void text_console_resize(TextConsole *s)
500{
501 TextCell *cells, *c, *c1;
502 int w1, x, y, last_width;
503
504 last_width = s->width;
505 s->width = s->g_width / FONT_WIDTH;
506 s->height = s->g_height / FONT_HEIGHT;
507
508 w1 = last_width;
509 if (s->width < w1)
510 w1 = s->width;
511
512 cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
513 for(y = 0; y < s->total_height; y++) {
514 c = &cells[y * s->width];
515 if (w1 > 0) {
516 c1 = &s->cells[y * last_width];
517 for(x = 0; x < w1; x++) {
518 *c++ = *c1++;
519 }
520 }
521 for(x = w1; x < s->width; x++) {
522 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000523 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000524 c++;
525 }
526 }
balroga528b802007-10-30 22:38:53 +0000527 qemu_free(s->cells);
bellarde7f0ad52004-07-14 17:28:59 +0000528 s->cells = cells;
529}
530
balrog4d3b6f62008-02-10 16:33:14 +0000531static inline void text_update_xy(TextConsole *s, int x, int y)
532{
533 s->text_x[0] = MIN(s->text_x[0], x);
534 s->text_x[1] = MAX(s->text_x[1], x);
535 s->text_y[0] = MIN(s->text_y[0], y);
536 s->text_y[1] = MAX(s->text_y[1], y);
537}
538
bellarde7f0ad52004-07-14 17:28:59 +0000539static void update_xy(TextConsole *s, int x, int y)
540{
541 TextCell *c;
542 int y1, y2;
543
544 if (s == active_console) {
balrog4d3b6f62008-02-10 16:33:14 +0000545 if (!s->ds->depth) {
546 text_update_xy(s, x, y);
547 return;
548 }
549
bellarde7f0ad52004-07-14 17:28:59 +0000550 y1 = (s->y_base + y) % s->total_height;
551 y2 = y1 - s->y_displayed;
552 if (y2 < 0)
553 y2 += s->total_height;
554 if (y2 < s->height) {
555 c = &s->cells[y1 * s->width + x];
ths5fafdf22007-09-16 21:08:06 +0000556 vga_putcharxy(s->ds, x, y2, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000557 &(c->t_attrib));
ths5fafdf22007-09-16 21:08:06 +0000558 dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
bellarde7f0ad52004-07-14 17:28:59 +0000559 FONT_WIDTH, FONT_HEIGHT);
560 }
561 }
562}
563
564static void console_show_cursor(TextConsole *s, int show)
565{
566 TextCell *c;
567 int y, y1;
568
569 if (s == active_console) {
thsed8276a2007-02-10 22:37:56 +0000570 int x = s->x;
balrog4d3b6f62008-02-10 16:33:14 +0000571
572 if (!s->ds->depth) {
573 s->cursor_invalidate = 1;
574 return;
575 }
576
thsed8276a2007-02-10 22:37:56 +0000577 if (x >= s->width) {
578 x = s->width - 1;
579 }
bellarde7f0ad52004-07-14 17:28:59 +0000580 y1 = (s->y_base + s->y) % s->total_height;
581 y = y1 - s->y_displayed;
582 if (y < 0)
583 y += s->total_height;
584 if (y < s->height) {
thsed8276a2007-02-10 22:37:56 +0000585 c = &s->cells[y1 * s->width + x];
bellarde7f0ad52004-07-14 17:28:59 +0000586 if (show) {
pbrook6d6f7c22006-03-11 15:35:30 +0000587 TextAttributes t_attrib = s->t_attrib_default;
588 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
thsed8276a2007-02-10 22:37:56 +0000589 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
bellarde7f0ad52004-07-14 17:28:59 +0000590 } else {
thsed8276a2007-02-10 22:37:56 +0000591 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000592 }
ths5fafdf22007-09-16 21:08:06 +0000593 dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT,
bellarde7f0ad52004-07-14 17:28:59 +0000594 FONT_WIDTH, FONT_HEIGHT);
595 }
596 }
597}
598
599static void console_refresh(TextConsole *s)
600{
601 TextCell *c;
602 int x, y, y1;
603
ths5fafdf22007-09-16 21:08:06 +0000604 if (s != active_console)
bellarde7f0ad52004-07-14 17:28:59 +0000605 return;
balrog4d3b6f62008-02-10 16:33:14 +0000606 if (!s->ds->depth) {
607 s->text_x[0] = 0;
608 s->text_y[0] = 0;
609 s->text_x[1] = s->width - 1;
610 s->text_y[1] = s->height - 1;
611 s->cursor_invalidate = 1;
612 return;
613 }
bellarde7f0ad52004-07-14 17:28:59 +0000614
615 vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
pbrook6d6f7c22006-03-11 15:35:30 +0000616 color_table[0][COLOR_BLACK]);
bellarde7f0ad52004-07-14 17:28:59 +0000617 y1 = s->y_displayed;
618 for(y = 0; y < s->height; y++) {
619 c = s->cells + y1 * s->width;
620 for(x = 0; x < s->width; x++) {
ths5fafdf22007-09-16 21:08:06 +0000621 vga_putcharxy(s->ds, x, y, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000622 &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000623 c++;
624 }
625 if (++y1 == s->total_height)
626 y1 = 0;
627 }
628 dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
629 console_show_cursor(s, 1);
630}
631
632static void console_scroll(int ydelta)
633{
634 TextConsole *s;
635 int i, y1;
ths3b46e622007-09-17 08:09:54 +0000636
bellarde7f0ad52004-07-14 17:28:59 +0000637 s = active_console;
thsaf3a9032007-07-11 23:14:59 +0000638 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +0000639 return;
640
641 if (ydelta > 0) {
642 for(i = 0; i < ydelta; i++) {
643 if (s->y_displayed == s->y_base)
644 break;
645 if (++s->y_displayed == s->total_height)
646 s->y_displayed = 0;
647 }
648 } else {
649 ydelta = -ydelta;
650 i = s->backscroll_height;
651 if (i > s->total_height - s->height)
652 i = s->total_height - s->height;
653 y1 = s->y_base - i;
654 if (y1 < 0)
655 y1 += s->total_height;
656 for(i = 0; i < ydelta; i++) {
657 if (s->y_displayed == y1)
658 break;
659 if (--s->y_displayed < 0)
660 s->y_displayed = s->total_height - 1;
661 }
662 }
663 console_refresh(s);
664}
665
666static void console_put_lf(TextConsole *s)
667{
668 TextCell *c;
669 int x, y1;
670
bellarde7f0ad52004-07-14 17:28:59 +0000671 s->y++;
672 if (s->y >= s->height) {
673 s->y = s->height - 1;
pbrook6d6f7c22006-03-11 15:35:30 +0000674
bellarde7f0ad52004-07-14 17:28:59 +0000675 if (s->y_displayed == s->y_base) {
676 if (++s->y_displayed == s->total_height)
677 s->y_displayed = 0;
678 }
679 if (++s->y_base == s->total_height)
680 s->y_base = 0;
681 if (s->backscroll_height < s->total_height)
682 s->backscroll_height++;
683 y1 = (s->y_base + s->height - 1) % s->total_height;
684 c = &s->cells[y1 * s->width];
685 for(x = 0; x < s->width; x++) {
686 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000687 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000688 c++;
689 }
690 if (s == active_console && s->y_displayed == s->y_base) {
balrog4d3b6f62008-02-10 16:33:14 +0000691 if (!s->ds->depth) {
692 s->text_x[0] = 0;
693 s->text_y[0] = 0;
694 s->text_x[1] = s->width - 1;
695 s->text_y[1] = s->height - 1;
696 return;
697 }
698
ths5fafdf22007-09-16 21:08:06 +0000699 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
700 s->width * FONT_WIDTH,
bellarde7f0ad52004-07-14 17:28:59 +0000701 (s->height - 1) * FONT_HEIGHT);
702 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
ths5fafdf22007-09-16 21:08:06 +0000703 s->width * FONT_WIDTH, FONT_HEIGHT,
pbrook6d6f7c22006-03-11 15:35:30 +0000704 color_table[0][s->t_attrib_default.bgcol]);
ths5fafdf22007-09-16 21:08:06 +0000705 dpy_update(s->ds, 0, 0,
bellarde7f0ad52004-07-14 17:28:59 +0000706 s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
707 }
708 }
709}
710
pbrook6d6f7c22006-03-11 15:35:30 +0000711/* Set console attributes depending on the current escape codes.
712 * NOTE: I know this code is not very efficient (checking every color for it
713 * self) but it is more readable and better maintainable.
714 */
715static void console_handle_escape(TextConsole *s)
716{
717 int i;
718
pbrook6d6f7c22006-03-11 15:35:30 +0000719 for (i=0; i<s->nb_esc_params; i++) {
720 switch (s->esc_params[i]) {
721 case 0: /* reset all console attributes to default */
722 s->t_attrib = s->t_attrib_default;
723 break;
724 case 1:
725 s->t_attrib.bold = 1;
726 break;
727 case 4:
728 s->t_attrib.uline = 1;
729 break;
730 case 5:
731 s->t_attrib.blink = 1;
732 break;
733 case 7:
734 s->t_attrib.invers = 1;
735 break;
736 case 8:
737 s->t_attrib.unvisible = 1;
738 break;
739 case 22:
740 s->t_attrib.bold = 0;
741 break;
742 case 24:
743 s->t_attrib.uline = 0;
744 break;
745 case 25:
746 s->t_attrib.blink = 0;
747 break;
748 case 27:
749 s->t_attrib.invers = 0;
750 break;
751 case 28:
752 s->t_attrib.unvisible = 0;
753 break;
754 /* set foreground color */
755 case 30:
756 s->t_attrib.fgcol=COLOR_BLACK;
757 break;
758 case 31:
759 s->t_attrib.fgcol=COLOR_RED;
760 break;
761 case 32:
762 s->t_attrib.fgcol=COLOR_GREEN;
763 break;
764 case 33:
765 s->t_attrib.fgcol=COLOR_YELLOW;
766 break;
767 case 34:
768 s->t_attrib.fgcol=COLOR_BLUE;
769 break;
770 case 35:
771 s->t_attrib.fgcol=COLOR_MAGENTA;
772 break;
773 case 36:
774 s->t_attrib.fgcol=COLOR_CYAN;
775 break;
776 case 37:
777 s->t_attrib.fgcol=COLOR_WHITE;
778 break;
779 /* set background color */
780 case 40:
781 s->t_attrib.bgcol=COLOR_BLACK;
782 break;
783 case 41:
784 s->t_attrib.bgcol=COLOR_RED;
785 break;
786 case 42:
787 s->t_attrib.bgcol=COLOR_GREEN;
788 break;
789 case 43:
790 s->t_attrib.bgcol=COLOR_YELLOW;
791 break;
792 case 44:
793 s->t_attrib.bgcol=COLOR_BLUE;
794 break;
795 case 45:
796 s->t_attrib.bgcol=COLOR_MAGENTA;
797 break;
798 case 46:
799 s->t_attrib.bgcol=COLOR_CYAN;
800 break;
801 case 47:
802 s->t_attrib.bgcol=COLOR_WHITE;
803 break;
804 }
805 }
806}
807
thsadb47962007-01-16 23:02:36 +0000808static void console_clear_xy(TextConsole *s, int x, int y)
809{
810 int y1 = (s->y_base + y) % s->total_height;
811 TextCell *c = &s->cells[y1 * s->width + x];
812 c->ch = ' ';
813 c->t_attrib = s->t_attrib_default;
814 c++;
815 update_xy(s, x, y);
816}
817
bellarde7f0ad52004-07-14 17:28:59 +0000818static void console_putchar(TextConsole *s, int ch)
819{
820 TextCell *c;
thsadb47962007-01-16 23:02:36 +0000821 int y1, i;
822 int x, y;
bellarde7f0ad52004-07-14 17:28:59 +0000823
824 switch(s->state) {
825 case TTY_STATE_NORM:
826 switch(ch) {
pbrook6d6f7c22006-03-11 15:35:30 +0000827 case '\r': /* carriage return */
bellarde7f0ad52004-07-14 17:28:59 +0000828 s->x = 0;
829 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000830 case '\n': /* newline */
bellarde7f0ad52004-07-14 17:28:59 +0000831 console_put_lf(s);
832 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000833 case '\b': /* backspace */
ths5fafdf22007-09-16 21:08:06 +0000834 if (s->x > 0)
bellarde15d7372006-06-25 16:26:29 +0000835 s->x--;
pbrook6d6f7c22006-03-11 15:35:30 +0000836 break;
837 case '\t': /* tabspace */
838 if (s->x + (8 - (s->x % 8)) > s->width) {
bellardbd468842006-07-14 20:24:31 +0000839 s->x = 0;
pbrook6d6f7c22006-03-11 15:35:30 +0000840 console_put_lf(s);
841 } else {
842 s->x = s->x + (8 - (s->x % 8));
843 }
844 break;
845 case '\a': /* alert aka. bell */
846 /* TODO: has to be implemented */
847 break;
thsadb47962007-01-16 23:02:36 +0000848 case 14:
849 /* SI (shift in), character set 0 (ignored) */
850 break;
851 case 15:
852 /* SO (shift out), character set 1 (ignored) */
853 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000854 case 27: /* esc (introducing an escape sequence) */
bellarde7f0ad52004-07-14 17:28:59 +0000855 s->state = TTY_STATE_ESC;
856 break;
857 default:
thsed8276a2007-02-10 22:37:56 +0000858 if (s->x >= s->width) {
859 /* line wrap */
860 s->x = 0;
861 console_put_lf(s);
thsadb47962007-01-16 23:02:36 +0000862 }
bellarde7f0ad52004-07-14 17:28:59 +0000863 y1 = (s->y_base + s->y) % s->total_height;
864 c = &s->cells[y1 * s->width + s->x];
865 c->ch = ch;
pbrook6d6f7c22006-03-11 15:35:30 +0000866 c->t_attrib = s->t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +0000867 update_xy(s, s->x, s->y);
868 s->x++;
bellarde7f0ad52004-07-14 17:28:59 +0000869 break;
870 }
871 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000872 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
bellarde7f0ad52004-07-14 17:28:59 +0000873 if (ch == '[') {
874 for(i=0;i<MAX_ESC_PARAMS;i++)
875 s->esc_params[i] = 0;
876 s->nb_esc_params = 0;
877 s->state = TTY_STATE_CSI;
878 } else {
879 s->state = TTY_STATE_NORM;
880 }
881 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000882 case TTY_STATE_CSI: /* handle escape sequence parameters */
bellarde7f0ad52004-07-14 17:28:59 +0000883 if (ch >= '0' && ch <= '9') {
884 if (s->nb_esc_params < MAX_ESC_PARAMS) {
ths5fafdf22007-09-16 21:08:06 +0000885 s->esc_params[s->nb_esc_params] =
bellarde7f0ad52004-07-14 17:28:59 +0000886 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
887 }
888 } else {
889 s->nb_esc_params++;
890 if (ch == ';')
891 break;
thsadb47962007-01-16 23:02:36 +0000892#ifdef DEBUG_CONSOLE
893 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
894 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
895#endif
bellarde7f0ad52004-07-14 17:28:59 +0000896 s->state = TTY_STATE_NORM;
897 switch(ch) {
thsadb47962007-01-16 23:02:36 +0000898 case 'A':
899 /* move cursor up */
900 if (s->esc_params[0] == 0) {
901 s->esc_params[0] = 1;
902 }
903 s->y -= s->esc_params[0];
904 if (s->y < 0) {
905 s->y = 0;
bellarde7f0ad52004-07-14 17:28:59 +0000906 }
907 break;
thsadb47962007-01-16 23:02:36 +0000908 case 'B':
909 /* move cursor down */
910 if (s->esc_params[0] == 0) {
911 s->esc_params[0] = 1;
912 }
913 s->y += s->esc_params[0];
914 if (s->y >= s->height) {
915 s->y = s->height - 1;
916 }
917 break;
918 case 'C':
919 /* move cursor right */
920 if (s->esc_params[0] == 0) {
921 s->esc_params[0] = 1;
922 }
923 s->x += s->esc_params[0];
924 if (s->x >= s->width) {
925 s->x = s->width - 1;
926 }
927 break;
928 case 'D':
929 /* move cursor left */
930 if (s->esc_params[0] == 0) {
931 s->esc_params[0] = 1;
932 }
933 s->x -= s->esc_params[0];
934 if (s->x < 0) {
935 s->x = 0;
936 }
937 break;
938 case 'G':
939 /* move cursor to column */
940 s->x = s->esc_params[0] - 1;
941 if (s->x < 0) {
942 s->x = 0;
943 }
944 break;
945 case 'f':
946 case 'H':
947 /* move cursor to row, column */
948 s->x = s->esc_params[1] - 1;
949 if (s->x < 0) {
950 s->x = 0;
951 }
952 s->y = s->esc_params[0] - 1;
953 if (s->y < 0) {
954 s->y = 0;
955 }
956 break;
957 case 'J':
958 switch (s->esc_params[0]) {
959 case 0:
960 /* clear to end of screen */
961 for (y = s->y; y < s->height; y++) {
962 for (x = 0; x < s->width; x++) {
963 if (y == s->y && x < s->x) {
964 continue;
965 }
966 console_clear_xy(s, x, y);
967 }
968 }
969 break;
970 case 1:
971 /* clear from beginning of screen */
972 for (y = 0; y <= s->y; y++) {
973 for (x = 0; x < s->width; x++) {
974 if (y == s->y && x > s->x) {
975 break;
976 }
977 console_clear_xy(s, x, y);
978 }
979 }
980 break;
981 case 2:
982 /* clear entire screen */
983 for (y = 0; y <= s->height; y++) {
984 for (x = 0; x < s->width; x++) {
985 console_clear_xy(s, x, y);
986 }
987 }
988 break;
989 }
990 case 'K':
991 switch (s->esc_params[0]) {
992 case 0:
993 /* clear to eol */
994 for(x = s->x; x < s->width; x++) {
995 console_clear_xy(s, x, s->y);
996 }
997 break;
998 case 1:
999 /* clear from beginning of line */
1000 for (x = 0; x <= s->x; x++) {
1001 console_clear_xy(s, x, s->y);
1002 }
1003 break;
1004 case 2:
1005 /* clear entire line */
1006 for(x = 0; x < s->width; x++) {
1007 console_clear_xy(s, x, s->y);
1008 }
bellarde7f0ad52004-07-14 17:28:59 +00001009 break;
1010 }
thsadb47962007-01-16 23:02:36 +00001011 break;
1012 case 'm':
pbrook6d6f7c22006-03-11 15:35:30 +00001013 console_handle_escape(s);
bellarde7f0ad52004-07-14 17:28:59 +00001014 break;
thsadb47962007-01-16 23:02:36 +00001015 case 'n':
1016 /* report cursor position */
1017 /* TODO: send ESC[row;colR */
1018 break;
1019 case 's':
1020 /* save cursor position */
1021 s->x_saved = s->x;
1022 s->y_saved = s->y;
1023 break;
1024 case 'u':
1025 /* restore cursor position */
1026 s->x = s->x_saved;
1027 s->y = s->y_saved;
1028 break;
1029 default:
1030#ifdef DEBUG_CONSOLE
1031 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1032#endif
1033 break;
1034 }
1035 break;
bellarde7f0ad52004-07-14 17:28:59 +00001036 }
1037 }
1038}
1039
1040void console_select(unsigned int index)
1041{
1042 TextConsole *s;
pbrook6d6f7c22006-03-11 15:35:30 +00001043
bellarde7f0ad52004-07-14 17:28:59 +00001044 if (index >= MAX_CONSOLES)
1045 return;
1046 s = consoles[index];
1047 if (s) {
1048 active_console = s;
pbrookc60e08d2008-07-01 16:24:38 +00001049 if (s->g_width && s->g_height
1050 && (s->g_width != s->ds->width || s->g_height != s->ds->height))
1051 dpy_resize(s->ds, s->g_width, s->g_height);
balrog4d3b6f62008-02-10 16:33:14 +00001052 vga_hw_invalidate();
bellarde7f0ad52004-07-14 17:28:59 +00001053 }
1054}
1055
1056static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1057{
1058 TextConsole *s = chr->opaque;
1059 int i;
1060
1061 console_show_cursor(s, 0);
1062 for(i = 0; i < len; i++) {
1063 console_putchar(s, buf[i]);
1064 }
1065 console_show_cursor(s, 1);
1066 return len;
1067}
1068
bellard6fcfafb2004-08-01 21:48:30 +00001069static void console_send_event(CharDriverState *chr, int event)
1070{
1071 TextConsole *s = chr->opaque;
1072 int i;
1073
1074 if (event == CHR_EVENT_FOCUS) {
1075 for(i = 0; i < nb_consoles; i++) {
1076 if (consoles[i] == s) {
1077 console_select(i);
1078 break;
1079 }
1080 }
1081 }
1082}
1083
bellarde15d7372006-06-25 16:26:29 +00001084static void kbd_send_chars(void *opaque)
1085{
1086 TextConsole *s = opaque;
1087 int len;
1088 uint8_t buf[16];
ths3b46e622007-09-17 08:09:54 +00001089
pbrooke5b0bc42007-01-27 23:46:43 +00001090 len = qemu_chr_can_read(s->chr);
bellarde15d7372006-06-25 16:26:29 +00001091 if (len > s->out_fifo.count)
1092 len = s->out_fifo.count;
1093 if (len > 0) {
1094 if (len > sizeof(buf))
1095 len = sizeof(buf);
1096 qemu_fifo_read(&s->out_fifo, buf, len);
pbrooke5b0bc42007-01-27 23:46:43 +00001097 qemu_chr_read(s->chr, buf, len);
bellarde15d7372006-06-25 16:26:29 +00001098 }
1099 /* characters are pending: we send them a bit later (XXX:
1100 horrible, should change char device API) */
1101 if (s->out_fifo.count > 0) {
1102 qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
1103 }
1104}
1105
bellarde7f0ad52004-07-14 17:28:59 +00001106/* called when an ascii key is pressed */
1107void kbd_put_keysym(int keysym)
1108{
1109 TextConsole *s;
1110 uint8_t buf[16], *q;
1111 int c;
1112
1113 s = active_console;
thsaf3a9032007-07-11 23:14:59 +00001114 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +00001115 return;
1116
1117 switch(keysym) {
1118 case QEMU_KEY_CTRL_UP:
1119 console_scroll(-1);
1120 break;
1121 case QEMU_KEY_CTRL_DOWN:
1122 console_scroll(1);
1123 break;
1124 case QEMU_KEY_CTRL_PAGEUP:
1125 console_scroll(-10);
1126 break;
1127 case QEMU_KEY_CTRL_PAGEDOWN:
1128 console_scroll(10);
1129 break;
1130 default:
bellarde15d7372006-06-25 16:26:29 +00001131 /* convert the QEMU keysym to VT100 key string */
1132 q = buf;
1133 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1134 *q++ = '\033';
1135 *q++ = '[';
1136 c = keysym - 0xe100;
1137 if (c >= 10)
1138 *q++ = '0' + (c / 10);
1139 *q++ = '0' + (c % 10);
1140 *q++ = '~';
1141 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1142 *q++ = '\033';
1143 *q++ = '[';
1144 *q++ = keysym & 0xff;
1145 } else {
bellarde7f0ad52004-07-14 17:28:59 +00001146 *q++ = keysym;
bellarde15d7372006-06-25 16:26:29 +00001147 }
pbrooke5b0bc42007-01-27 23:46:43 +00001148 if (s->chr->chr_read) {
bellarde15d7372006-06-25 16:26:29 +00001149 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1150 kbd_send_chars(s);
bellarde7f0ad52004-07-14 17:28:59 +00001151 }
1152 break;
1153 }
1154}
1155
balrog4d3b6f62008-02-10 16:33:14 +00001156static void text_console_invalidate(void *opaque)
1157{
1158 TextConsole *s = (TextConsole *) opaque;
1159
balrog4d3b6f62008-02-10 16:33:14 +00001160 console_refresh(s);
1161}
1162
1163static void text_console_update(void *opaque, console_ch_t *chardata)
1164{
1165 TextConsole *s = (TextConsole *) opaque;
1166 int i, j, src;
1167
1168 if (s->text_x[0] <= s->text_x[1]) {
1169 src = (s->y_base + s->text_y[0]) * s->width;
1170 chardata += s->text_y[0] * s->width;
1171 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1172 for (j = 0; j < s->width; j ++, src ++)
1173 console_write_ch(chardata ++, s->cells[src].ch |
1174 (s->cells[src].t_attrib.fgcol << 12) |
1175 (s->cells[src].t_attrib.bgcol << 8) |
1176 (s->cells[src].t_attrib.bold << 21));
1177 dpy_update(s->ds, s->text_x[0], s->text_y[0],
1178 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1179 s->text_x[0] = s->width;
1180 s->text_y[0] = s->height;
1181 s->text_x[1] = 0;
1182 s->text_y[1] = 0;
1183 }
1184 if (s->cursor_invalidate) {
1185 dpy_cursor(s->ds, s->x, s->y);
1186 s->cursor_invalidate = 0;
1187 }
1188}
1189
thsaf3a9032007-07-11 23:14:59 +00001190static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
bellarde7f0ad52004-07-14 17:28:59 +00001191{
1192 TextConsole *s;
pbrook95219892006-04-09 01:06:34 +00001193 int i;
bellarde7f0ad52004-07-14 17:28:59 +00001194
1195 if (nb_consoles >= MAX_CONSOLES)
1196 return NULL;
1197 s = qemu_mallocz(sizeof(TextConsole));
1198 if (!s) {
1199 return NULL;
1200 }
thsaf3a9032007-07-11 23:14:59 +00001201 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1202 (console_type == GRAPHIC_CONSOLE))) {
bellarde7f0ad52004-07-14 17:28:59 +00001203 active_console = s;
thsaf3a9032007-07-11 23:14:59 +00001204 }
bellarde7f0ad52004-07-14 17:28:59 +00001205 s->ds = ds;
thsaf3a9032007-07-11 23:14:59 +00001206 s->console_type = console_type;
1207 if (console_type != GRAPHIC_CONSOLE) {
pbrook95219892006-04-09 01:06:34 +00001208 consoles[nb_consoles++] = s;
1209 } else {
1210 /* HACK: Put graphical consoles before text consoles. */
1211 for (i = nb_consoles; i > 0; i--) {
thsaf3a9032007-07-11 23:14:59 +00001212 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
pbrook95219892006-04-09 01:06:34 +00001213 break;
1214 consoles[i] = consoles[i - 1];
1215 }
1216 consoles[i] = s;
1217 }
bellarde7f0ad52004-07-14 17:28:59 +00001218 return s;
1219}
1220
pbrook95219892006-04-09 01:06:34 +00001221TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
1222 vga_hw_invalidate_ptr invalidate,
1223 vga_hw_screen_dump_ptr screen_dump,
balrog4d3b6f62008-02-10 16:33:14 +00001224 vga_hw_text_update_ptr text_update,
pbrook95219892006-04-09 01:06:34 +00001225 void *opaque)
bellarde7f0ad52004-07-14 17:28:59 +00001226{
pbrook95219892006-04-09 01:06:34 +00001227 TextConsole *s;
1228
thsaf3a9032007-07-11 23:14:59 +00001229 s = new_console(ds, GRAPHIC_CONSOLE);
pbrook95219892006-04-09 01:06:34 +00001230 if (!s)
1231 return NULL;
1232 s->hw_update = update;
1233 s->hw_invalidate = invalidate;
1234 s->hw_screen_dump = screen_dump;
balrog4d3b6f62008-02-10 16:33:14 +00001235 s->hw_text_update = text_update;
pbrook95219892006-04-09 01:06:34 +00001236 s->hw = opaque;
1237 return s;
1238}
1239
1240int is_graphic_console(void)
1241{
balrog4d3b6f62008-02-10 16:33:14 +00001242 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
bellarde7f0ad52004-07-14 17:28:59 +00001243}
1244
balroga528b802007-10-30 22:38:53 +00001245void console_color_init(DisplayState *ds)
1246{
1247 int i, j;
1248 for (j = 0; j < 2; j++) {
1249 for (i = 0; i < 8; i++) {
1250 color_table[j][i] = col_expand(ds,
1251 vga_get_color(ds, color_table_rgb[j][i]));
1252 }
1253 }
1254}
1255
thsaf3a9032007-07-11 23:14:59 +00001256CharDriverState *text_console_init(DisplayState *ds, const char *p)
bellarde7f0ad52004-07-14 17:28:59 +00001257{
1258 CharDriverState *chr;
1259 TextConsole *s;
thsaf3a9032007-07-11 23:14:59 +00001260 unsigned width;
1261 unsigned height;
bellarde7f0ad52004-07-14 17:28:59 +00001262 static int color_inited;
pbrook6d6f7c22006-03-11 15:35:30 +00001263
bellarde7f0ad52004-07-14 17:28:59 +00001264 chr = qemu_mallocz(sizeof(CharDriverState));
1265 if (!chr)
1266 return NULL;
pbrookc60e08d2008-07-01 16:24:38 +00001267 s = new_console(ds, TEXT_CONSOLE);
bellarde7f0ad52004-07-14 17:28:59 +00001268 if (!s) {
1269 free(chr);
1270 return NULL;
1271 }
pbrookc60e08d2008-07-01 16:24:38 +00001272 if (!p)
1273 p = DEFAULT_MONITOR_SIZE;
1274
bellarde7f0ad52004-07-14 17:28:59 +00001275 chr->opaque = s;
1276 chr->chr_write = console_puts;
bellard6fcfafb2004-08-01 21:48:30 +00001277 chr->chr_send_event = console_send_event;
1278
pbrooke5b0bc42007-01-27 23:46:43 +00001279 s->chr = chr;
bellarde15d7372006-06-25 16:26:29 +00001280 s->out_fifo.buf = s->out_fifo_buf;
1281 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1282 s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
ths3b46e622007-09-17 08:09:54 +00001283
bellarde7f0ad52004-07-14 17:28:59 +00001284 if (!color_inited) {
1285 color_inited = 1;
balroga528b802007-10-30 22:38:53 +00001286 console_color_init(s->ds);
bellarde7f0ad52004-07-14 17:28:59 +00001287 }
1288 s->y_displayed = 0;
1289 s->y_base = 0;
1290 s->total_height = DEFAULT_BACKSCROLL;
1291 s->x = 0;
1292 s->y = 0;
thsaf3a9032007-07-11 23:14:59 +00001293 width = s->ds->width;
1294 height = s->ds->height;
1295 if (p != 0) {
1296 width = strtoul(p, (char **)&p, 10);
1297 if (*p == 'C') {
1298 p++;
1299 width *= FONT_WIDTH;
1300 }
1301 if (*p == 'x') {
1302 p++;
1303 height = strtoul(p, (char **)&p, 10);
1304 if (*p == 'C') {
1305 p++;
1306 height *= FONT_HEIGHT;
1307 }
1308 }
1309 }
1310 s->g_width = width;
1311 s->g_height = height;
pbrook6d6f7c22006-03-11 15:35:30 +00001312
balrog4d3b6f62008-02-10 16:33:14 +00001313 s->hw_invalidate = text_console_invalidate;
1314 s->hw_text_update = text_console_update;
1315 s->hw = s;
1316
pbrook6d6f7c22006-03-11 15:35:30 +00001317 /* Set text attribute defaults */
1318 s->t_attrib_default.bold = 0;
1319 s->t_attrib_default.uline = 0;
1320 s->t_attrib_default.blink = 0;
1321 s->t_attrib_default.invers = 0;
1322 s->t_attrib_default.unvisible = 0;
1323 s->t_attrib_default.fgcol = COLOR_WHITE;
1324 s->t_attrib_default.bgcol = COLOR_BLACK;
1325
1326 /* set current text attributes to default */
1327 s->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +00001328 text_console_resize(s);
1329
ths86e94de2007-01-05 22:01:59 +00001330 qemu_chr_reset(chr);
1331
bellarde7f0ad52004-07-14 17:28:59 +00001332 return chr;
1333}
pbrookc60e08d2008-07-01 16:24:38 +00001334
1335void qemu_console_resize(QEMUConsole *console, int width, int height)
1336{
balrog3bba22d2008-07-19 14:09:20 +00001337 if (console->g_width != width || console->g_height != height
1338 || !console->ds->data) {
pbrookc60e08d2008-07-01 16:24:38 +00001339 console->g_width = width;
1340 console->g_height = height;
1341 if (active_console == console) {
1342 dpy_resize(console->ds, width, height);
1343 }
1344 }
1345}