blob: 25e06a5cb3885d764fbd4d899a62c18aa57ccffa [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"
Paolo Bonzini28ecbae2012-11-28 12:06:30 +010025#include "ui/console.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010026#include "qemu/timer.h"
Luiz Capitulinoad39cf62012-05-24 13:48:23 -030027#include "qmp-commands.h"
Paolo Bonzini927d4872012-12-17 18:20:05 +010028#include "char/char.h"
bellarde7f0ad52004-07-14 17:28:59 +000029
pbrook6d6f7c22006-03-11 15:35:30 +000030//#define DEBUG_CONSOLE
bellarde7f0ad52004-07-14 17:28:59 +000031#define DEFAULT_BACKSCROLL 512
32#define MAX_CONSOLES 12
Jan Kiszkabf1bed82012-07-10 22:00:55 +020033#define CONSOLE_CURSOR_PERIOD 500
bellarde7f0ad52004-07-14 17:28:59 +000034
bellard26489842006-06-25 17:37:36 +000035#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
36#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
bellarde7f0ad52004-07-14 17:28:59 +000037
pbrook6d6f7c22006-03-11 15:35:30 +000038typedef struct TextAttributes {
39 uint8_t fgcol:4;
40 uint8_t bgcol:4;
41 uint8_t bold:1;
42 uint8_t uline:1;
43 uint8_t blink:1;
44 uint8_t invers:1;
45 uint8_t unvisible:1;
46} TextAttributes;
47
bellarde7f0ad52004-07-14 17:28:59 +000048typedef struct TextCell {
49 uint8_t ch;
pbrook6d6f7c22006-03-11 15:35:30 +000050 TextAttributes t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +000051} TextCell;
52
53#define MAX_ESC_PARAMS 3
54
55enum TTYState {
56 TTY_STATE_NORM,
57 TTY_STATE_ESC,
58 TTY_STATE_CSI,
59};
60
bellarde15d7372006-06-25 16:26:29 +000061typedef struct QEMUFIFO {
62 uint8_t *buf;
63 int buf_size;
64 int count, wptr, rptr;
65} QEMUFIFO;
66
pbrook9596ebb2007-11-18 01:44:38 +000067static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
bellarde15d7372006-06-25 16:26:29 +000068{
69 int l, len;
70
71 l = f->buf_size - f->count;
72 if (len1 > l)
73 len1 = l;
74 len = len1;
75 while (len > 0) {
76 l = f->buf_size - f->wptr;
77 if (l > len)
78 l = len;
79 memcpy(f->buf + f->wptr, buf, l);
80 f->wptr += l;
81 if (f->wptr >= f->buf_size)
82 f->wptr = 0;
83 buf += l;
84 len -= l;
85 }
86 f->count += len1;
87 return len1;
88}
89
pbrook9596ebb2007-11-18 01:44:38 +000090static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
bellarde15d7372006-06-25 16:26:29 +000091{
92 int l, len;
93
94 if (len1 > f->count)
95 len1 = f->count;
96 len = len1;
97 while (len > 0) {
98 l = f->buf_size - f->rptr;
99 if (l > len)
100 l = len;
101 memcpy(buf, f->buf + f->rptr, l);
102 f->rptr += l;
103 if (f->rptr >= f->buf_size)
104 f->rptr = 0;
105 buf += l;
106 len -= l;
107 }
108 f->count -= len1;
109 return len1;
110}
111
thsaf3a9032007-07-11 23:14:59 +0000112typedef enum {
113 GRAPHIC_CONSOLE,
balrogc21bbcf2008-09-24 03:32:33 +0000114 TEXT_CONSOLE,
115 TEXT_CONSOLE_FIXED_SIZE
Anthony Liguoric227f092009-10-01 16:12:16 -0500116} console_type_t;
thsaf3a9032007-07-11 23:14:59 +0000117
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200118struct QemuConsole {
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200119 int index;
Anthony Liguoric227f092009-10-01 16:12:16 -0500120 console_type_t console_type;
bellarde7f0ad52004-07-14 17:28:59 +0000121 DisplayState *ds;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200122
pbrook95219892006-04-09 01:06:34 +0000123 /* Graphic console state. */
124 vga_hw_update_ptr hw_update;
125 vga_hw_invalidate_ptr hw_invalidate;
126 vga_hw_screen_dump_ptr hw_screen_dump;
balrog4d3b6f62008-02-10 16:33:14 +0000127 vga_hw_text_update_ptr hw_text_update;
pbrook95219892006-04-09 01:06:34 +0000128 void *hw;
bellarde7f0ad52004-07-14 17:28:59 +0000129 int g_width, g_height;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200130
131 /* Text console state */
bellarde7f0ad52004-07-14 17:28:59 +0000132 int width;
133 int height;
134 int total_height;
135 int backscroll_height;
bellarde7f0ad52004-07-14 17:28:59 +0000136 int x, y;
thsadb47962007-01-16 23:02:36 +0000137 int x_saved, y_saved;
bellarde7f0ad52004-07-14 17:28:59 +0000138 int y_displayed;
139 int y_base;
pbrook6d6f7c22006-03-11 15:35:30 +0000140 TextAttributes t_attrib_default; /* default text attributes */
141 TextAttributes t_attrib; /* currently active text attributes */
bellarde7f0ad52004-07-14 17:28:59 +0000142 TextCell *cells;
balrog4d3b6f62008-02-10 16:33:14 +0000143 int text_x[2], text_y[2], cursor_invalidate;
Paolo Bonzini41048332010-12-23 13:42:52 +0100144 int echo;
Jan Kiszkabf1bed82012-07-10 22:00:55 +0200145 bool cursor_visible_phase;
146 QEMUTimer *cursor_timer;
bellarde7f0ad52004-07-14 17:28:59 +0000147
pbrook14778c22009-01-21 03:02:52 +0000148 int update_x0;
149 int update_y0;
150 int update_x1;
151 int update_y1;
152
bellarde7f0ad52004-07-14 17:28:59 +0000153 enum TTYState state;
154 int esc_params[MAX_ESC_PARAMS];
155 int nb_esc_params;
156
pbrooke5b0bc42007-01-27 23:46:43 +0000157 CharDriverState *chr;
bellarde15d7372006-06-25 16:26:29 +0000158 /* fifo for key pressed */
159 QEMUFIFO out_fifo;
160 uint8_t out_fifo_buf[16];
161 QEMUTimer *kbd_timer;
bellarde7f0ad52004-07-14 17:28:59 +0000162};
163
Paolo Bonzini98b50082010-02-11 00:29:57 +0100164static DisplayState *display_state;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200165static QemuConsole *active_console;
166static QemuConsole *consoles[MAX_CONSOLES];
bellarde7f0ad52004-07-14 17:28:59 +0000167static int nb_consoles = 0;
168
pbrook95219892006-04-09 01:06:34 +0000169void vga_hw_update(void)
170{
thsadb47962007-01-16 23:02:36 +0000171 if (active_console && active_console->hw_update)
pbrook95219892006-04-09 01:06:34 +0000172 active_console->hw_update(active_console->hw);
173}
174
175void vga_hw_invalidate(void)
176{
Gerd Hoffmann26572b82010-05-20 15:23:06 +0200177 if (active_console && active_console->hw_invalidate)
pbrook95219892006-04-09 01:06:34 +0000178 active_console->hw_invalidate(active_console->hw);
179}
180
Luiz Capitulinoad39cf62012-05-24 13:48:23 -0300181void qmp_screendump(const char *filename, Error **errp)
pbrook95219892006-04-09 01:06:34 +0000182{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200183 QemuConsole *previous_active_console;
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100184 bool cswitch;
balrog8571c052008-07-19 13:04:26 +0000185
186 previous_active_console = active_console;
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100187 cswitch = previous_active_console && previous_active_console->index != 0;
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200188
balrog8571c052008-07-19 13:04:26 +0000189 /* There is currently no way of specifying which screen we want to dump,
aurel327b455222008-09-02 00:09:16 +0000190 so always dump the first one. */
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100191 if (cswitch) {
192 console_select(0);
193 }
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200194 if (consoles[0] && consoles[0]->hw_screen_dump) {
Luiz Capitulinoad39cf62012-05-24 13:48:23 -0300195 consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch, errp);
Gerd Hoffmann16735102012-02-24 12:43:44 +0100196 } else {
Markus Armbruster312fd5f2013-02-08 21:22:16 +0100197 error_setg(errp, "device doesn't support screendump");
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200198 }
199
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100200 if (cswitch) {
Alexander Graf33bcd982011-11-18 16:41:59 +0100201 console_select(previous_active_console->index);
202 }
pbrook95219892006-04-09 01:06:34 +0000203}
204
Anthony Liguoric227f092009-10-01 16:12:16 -0500205void vga_hw_text_update(console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +0000206{
207 if (active_console && active_console->hw_text_update)
208 active_console->hw_text_update(active_console->hw, chardata);
209}
210
bellarde7f0ad52004-07-14 17:28:59 +0000211/* convert a RGBA color to a color index usable in graphic primitives */
212static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
213{
214 unsigned int r, g, b, color;
215
aliguori0e1f5a02008-11-24 19:29:13 +0000216 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000217#if 0
218 case 8:
219 r = (rgba >> 16) & 0xff;
220 g = (rgba >> 8) & 0xff;
221 b = (rgba) & 0xff;
ths5fafdf22007-09-16 21:08:06 +0000222 color = (rgb_to_index[r] * 6 * 6) +
223 (rgb_to_index[g] * 6) +
bellarde7f0ad52004-07-14 17:28:59 +0000224 (rgb_to_index[b]);
225 break;
226#endif
227 case 15:
228 r = (rgba >> 16) & 0xff;
229 g = (rgba >> 8) & 0xff;
230 b = (rgba) & 0xff;
231 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
232 break;
233 case 16:
234 r = (rgba >> 16) & 0xff;
235 g = (rgba >> 8) & 0xff;
236 b = (rgba) & 0xff;
237 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
238 break;
239 case 32:
240 default:
241 color = rgba;
242 break;
243 }
244 return color;
245}
246
ths5fafdf22007-09-16 21:08:06 +0000247static void vga_fill_rect (DisplayState *ds,
bellarde7f0ad52004-07-14 17:28:59 +0000248 int posx, int posy, int width, int height, uint32_t color)
249{
250 uint8_t *d, *d1;
251 int x, y, bpp;
ths3b46e622007-09-17 08:09:54 +0000252
aliguori0e1f5a02008-11-24 19:29:13 +0000253 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
254 d1 = ds_get_data(ds) +
255 ds_get_linesize(ds) * posy + bpp * posx;
bellarde7f0ad52004-07-14 17:28:59 +0000256 for (y = 0; y < height; y++) {
257 d = d1;
258 switch(bpp) {
259 case 1:
260 for (x = 0; x < width; x++) {
261 *((uint8_t *)d) = color;
262 d++;
263 }
264 break;
265 case 2:
266 for (x = 0; x < width; x++) {
267 *((uint16_t *)d) = color;
268 d += 2;
269 }
270 break;
271 case 4:
272 for (x = 0; x < width; x++) {
273 *((uint32_t *)d) = color;
274 d += 4;
275 }
276 break;
277 }
aliguori0e1f5a02008-11-24 19:29:13 +0000278 d1 += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000279 }
280}
281
282/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
283static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
284{
285 const uint8_t *s;
286 uint8_t *d;
287 int wb, y, bpp;
288
aliguori0e1f5a02008-11-24 19:29:13 +0000289 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
bellarde7f0ad52004-07-14 17:28:59 +0000290 wb = w * bpp;
291 if (yd <= ys) {
aliguori0e1f5a02008-11-24 19:29:13 +0000292 s = ds_get_data(ds) +
293 ds_get_linesize(ds) * ys + bpp * xs;
294 d = ds_get_data(ds) +
295 ds_get_linesize(ds) * yd + bpp * xd;
bellarde7f0ad52004-07-14 17:28:59 +0000296 for (y = 0; y < h; y++) {
297 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000298 d += ds_get_linesize(ds);
299 s += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000300 }
301 } else {
aliguori0e1f5a02008-11-24 19:29:13 +0000302 s = ds_get_data(ds) +
303 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
304 d = ds_get_data(ds) +
305 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
bellarde7f0ad52004-07-14 17:28:59 +0000306 for (y = 0; y < h; y++) {
307 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000308 d -= ds_get_linesize(ds);
309 s -= ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000310 }
311 }
312}
313
314/***********************************************************/
315/* basic char display */
316
317#define FONT_HEIGHT 16
318#define FONT_WIDTH 8
319
320#include "vgafont.h"
321
322#define cbswap_32(__x) \
323((uint32_t)( \
324 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
325 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
326 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
327 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
328
Juan Quintelae2542fe2009-07-27 16:13:06 +0200329#ifdef HOST_WORDS_BIGENDIAN
bellarde7f0ad52004-07-14 17:28:59 +0000330#define PAT(x) x
331#else
332#define PAT(x) cbswap_32(x)
333#endif
334
335static const uint32_t dmask16[16] = {
336 PAT(0x00000000),
337 PAT(0x000000ff),
338 PAT(0x0000ff00),
339 PAT(0x0000ffff),
340 PAT(0x00ff0000),
341 PAT(0x00ff00ff),
342 PAT(0x00ffff00),
343 PAT(0x00ffffff),
344 PAT(0xff000000),
345 PAT(0xff0000ff),
346 PAT(0xff00ff00),
347 PAT(0xff00ffff),
348 PAT(0xffff0000),
349 PAT(0xffff00ff),
350 PAT(0xffffff00),
351 PAT(0xffffffff),
352};
353
354static const uint32_t dmask4[4] = {
355 PAT(0x00000000),
356 PAT(0x0000ffff),
357 PAT(0xffff0000),
358 PAT(0xffffffff),
359};
360
pbrook6d6f7c22006-03-11 15:35:30 +0000361static uint32_t color_table[2][8];
bellarde7f0ad52004-07-14 17:28:59 +0000362
Devin J. Pohlydf00bed2011-09-07 15:44:36 -0400363#ifndef CONFIG_CURSES
pbrook6d6f7c22006-03-11 15:35:30 +0000364enum color_names {
365 COLOR_BLACK = 0,
366 COLOR_RED = 1,
367 COLOR_GREEN = 2,
368 COLOR_YELLOW = 3,
369 COLOR_BLUE = 4,
370 COLOR_MAGENTA = 5,
371 COLOR_CYAN = 6,
372 COLOR_WHITE = 7
373};
Devin J. Pohlydf00bed2011-09-07 15:44:36 -0400374#endif
pbrook6d6f7c22006-03-11 15:35:30 +0000375
376static const uint32_t color_table_rgb[2][8] = {
377 { /* dark */
bellard26489842006-06-25 17:37:36 +0000378 QEMU_RGB(0x00, 0x00, 0x00), /* black */
379 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
380 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
381 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
382 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
383 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
384 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
385 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000386 },
387 { /* bright */
bellard26489842006-06-25 17:37:36 +0000388 QEMU_RGB(0x00, 0x00, 0x00), /* black */
389 QEMU_RGB(0xff, 0x00, 0x00), /* red */
390 QEMU_RGB(0x00, 0xff, 0x00), /* green */
391 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
392 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
393 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
394 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
395 QEMU_RGB(0xff, 0xff, 0xff), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000396 }
bellarde7f0ad52004-07-14 17:28:59 +0000397};
398
399static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
400{
aliguori0e1f5a02008-11-24 19:29:13 +0000401 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000402 case 8:
403 col |= col << 8;
404 col |= col << 16;
405 break;
406 case 15:
407 case 16:
408 col |= col << 16;
409 break;
410 default:
411 break;
412 }
413
414 return col;
415}
pbrook6d6f7c22006-03-11 15:35:30 +0000416#ifdef DEBUG_CONSOLE
417static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
418{
419 if (t_attrib->bold) {
420 printf("b");
421 } else {
422 printf(" ");
423 }
424 if (t_attrib->uline) {
425 printf("u");
426 } else {
427 printf(" ");
428 }
429 if (t_attrib->blink) {
430 printf("l");
431 } else {
432 printf(" ");
433 }
434 if (t_attrib->invers) {
435 printf("i");
436 } else {
437 printf(" ");
438 }
439 if (t_attrib->unvisible) {
440 printf("n");
441 } else {
442 printf(" ");
443 }
444
445 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
446}
447#endif
bellarde7f0ad52004-07-14 17:28:59 +0000448
ths5fafdf22007-09-16 21:08:06 +0000449static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000450 TextAttributes *t_attrib)
bellarde7f0ad52004-07-14 17:28:59 +0000451{
452 uint8_t *d;
453 const uint8_t *font_ptr;
454 unsigned int font_data, linesize, xorcol, bpp;
455 int i;
pbrook6d6f7c22006-03-11 15:35:30 +0000456 unsigned int fgcol, bgcol;
457
458#ifdef DEBUG_CONSOLE
459 printf("x: %2i y: %2i", x, y);
460 console_print_text_attributes(t_attrib, ch);
461#endif
462
463 if (t_attrib->invers) {
464 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
465 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
466 } else {
467 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
468 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
469 }
bellarde7f0ad52004-07-14 17:28:59 +0000470
aliguori0e1f5a02008-11-24 19:29:13 +0000471 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
472 d = ds_get_data(ds) +
473 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
474 linesize = ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000475 font_ptr = vgafont16 + FONT_HEIGHT * ch;
476 xorcol = bgcol ^ fgcol;
aliguori0e1f5a02008-11-24 19:29:13 +0000477 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000478 case 8:
479 for(i = 0; i < FONT_HEIGHT; i++) {
480 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000481 if (t_attrib->uline
482 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100483 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000484 }
bellarde7f0ad52004-07-14 17:28:59 +0000485 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
486 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
487 d += linesize;
488 }
489 break;
490 case 16:
491 case 15:
492 for(i = 0; i < FONT_HEIGHT; i++) {
493 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000494 if (t_attrib->uline
495 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100496 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000497 }
bellarde7f0ad52004-07-14 17:28:59 +0000498 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
499 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
500 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
501 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
502 d += linesize;
503 }
504 break;
505 case 32:
506 for(i = 0; i < FONT_HEIGHT; i++) {
507 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000508 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100509 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000510 }
bellarde7f0ad52004-07-14 17:28:59 +0000511 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
512 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
513 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
514 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
515 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
516 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
517 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
518 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
519 d += linesize;
520 }
521 break;
522 }
523}
524
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200525static void text_console_resize(QemuConsole *s)
bellarde7f0ad52004-07-14 17:28:59 +0000526{
527 TextCell *cells, *c, *c1;
528 int w1, x, y, last_width;
529
530 last_width = s->width;
531 s->width = s->g_width / FONT_WIDTH;
532 s->height = s->g_height / FONT_HEIGHT;
533
534 w1 = last_width;
535 if (s->width < w1)
536 w1 = s->width;
537
Anthony Liguori7267c092011-08-20 22:09:37 -0500538 cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
bellarde7f0ad52004-07-14 17:28:59 +0000539 for(y = 0; y < s->total_height; y++) {
540 c = &cells[y * s->width];
541 if (w1 > 0) {
542 c1 = &s->cells[y * last_width];
543 for(x = 0; x < w1; x++) {
544 *c++ = *c1++;
545 }
546 }
547 for(x = w1; x < s->width; x++) {
548 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000549 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000550 c++;
551 }
552 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500553 g_free(s->cells);
bellarde7f0ad52004-07-14 17:28:59 +0000554 s->cells = cells;
555}
556
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200557static inline void text_update_xy(QemuConsole *s, int x, int y)
balrog4d3b6f62008-02-10 16:33:14 +0000558{
559 s->text_x[0] = MIN(s->text_x[0], x);
560 s->text_x[1] = MAX(s->text_x[1], x);
561 s->text_y[0] = MIN(s->text_y[0], y);
562 s->text_y[1] = MAX(s->text_y[1], y);
563}
564
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200565static void invalidate_xy(QemuConsole *s, int x, int y)
pbrook14778c22009-01-21 03:02:52 +0000566{
567 if (s->update_x0 > x * FONT_WIDTH)
568 s->update_x0 = x * FONT_WIDTH;
569 if (s->update_y0 > y * FONT_HEIGHT)
570 s->update_y0 = y * FONT_HEIGHT;
571 if (s->update_x1 < (x + 1) * FONT_WIDTH)
572 s->update_x1 = (x + 1) * FONT_WIDTH;
573 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
574 s->update_y1 = (y + 1) * FONT_HEIGHT;
575}
576
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200577static void update_xy(QemuConsole *s, int x, int y)
bellarde7f0ad52004-07-14 17:28:59 +0000578{
579 TextCell *c;
580 int y1, y2;
581
582 if (s == active_console) {
aliguori0e1f5a02008-11-24 19:29:13 +0000583 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000584 text_update_xy(s, x, y);
585 return;
586 }
587
bellarde7f0ad52004-07-14 17:28:59 +0000588 y1 = (s->y_base + y) % s->total_height;
589 y2 = y1 - s->y_displayed;
590 if (y2 < 0)
591 y2 += s->total_height;
592 if (y2 < s->height) {
593 c = &s->cells[y1 * s->width + x];
ths5fafdf22007-09-16 21:08:06 +0000594 vga_putcharxy(s->ds, x, y2, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000595 &(c->t_attrib));
pbrook14778c22009-01-21 03:02:52 +0000596 invalidate_xy(s, x, y2);
bellarde7f0ad52004-07-14 17:28:59 +0000597 }
598 }
599}
600
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200601static void console_show_cursor(QemuConsole *s, int show)
bellarde7f0ad52004-07-14 17:28:59 +0000602{
603 TextCell *c;
604 int y, y1;
605
606 if (s == active_console) {
thsed8276a2007-02-10 22:37:56 +0000607 int x = s->x;
balrog4d3b6f62008-02-10 16:33:14 +0000608
aliguori0e1f5a02008-11-24 19:29:13 +0000609 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000610 s->cursor_invalidate = 1;
611 return;
612 }
613
thsed8276a2007-02-10 22:37:56 +0000614 if (x >= s->width) {
615 x = s->width - 1;
616 }
bellarde7f0ad52004-07-14 17:28:59 +0000617 y1 = (s->y_base + s->y) % s->total_height;
618 y = y1 - s->y_displayed;
619 if (y < 0)
620 y += s->total_height;
621 if (y < s->height) {
thsed8276a2007-02-10 22:37:56 +0000622 c = &s->cells[y1 * s->width + x];
Jan Kiszkabf1bed82012-07-10 22:00:55 +0200623 if (show && s->cursor_visible_phase) {
pbrook6d6f7c22006-03-11 15:35:30 +0000624 TextAttributes t_attrib = s->t_attrib_default;
625 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
thsed8276a2007-02-10 22:37:56 +0000626 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
bellarde7f0ad52004-07-14 17:28:59 +0000627 } else {
thsed8276a2007-02-10 22:37:56 +0000628 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000629 }
pbrook14778c22009-01-21 03:02:52 +0000630 invalidate_xy(s, x, y);
bellarde7f0ad52004-07-14 17:28:59 +0000631 }
632 }
633}
634
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200635static void console_refresh(QemuConsole *s)
bellarde7f0ad52004-07-14 17:28:59 +0000636{
637 TextCell *c;
638 int x, y, y1;
639
ths5fafdf22007-09-16 21:08:06 +0000640 if (s != active_console)
bellarde7f0ad52004-07-14 17:28:59 +0000641 return;
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +0200642
643 if (s->ds->have_text) {
balrog4d3b6f62008-02-10 16:33:14 +0000644 s->text_x[0] = 0;
645 s->text_y[0] = 0;
646 s->text_x[1] = s->width - 1;
647 s->text_y[1] = s->height - 1;
648 s->cursor_invalidate = 1;
balrog4d3b6f62008-02-10 16:33:14 +0000649 }
bellarde7f0ad52004-07-14 17:28:59 +0000650
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +0200651 if (s->ds->have_gfx) {
652 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
653 color_table[0][COLOR_BLACK]);
654 y1 = s->y_displayed;
655 for (y = 0; y < s->height; y++) {
656 c = s->cells + y1 * s->width;
657 for (x = 0; x < s->width; x++) {
658 vga_putcharxy(s->ds, x, y, c->ch,
659 &(c->t_attrib));
660 c++;
661 }
662 if (++y1 == s->total_height) {
663 y1 = 0;
664 }
bellarde7f0ad52004-07-14 17:28:59 +0000665 }
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +0200666 console_show_cursor(s, 1);
667 dpy_gfx_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
bellarde7f0ad52004-07-14 17:28:59 +0000668 }
bellarde7f0ad52004-07-14 17:28:59 +0000669}
670
671static void console_scroll(int ydelta)
672{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200673 QemuConsole *s;
bellarde7f0ad52004-07-14 17:28:59 +0000674 int i, y1;
ths3b46e622007-09-17 08:09:54 +0000675
bellarde7f0ad52004-07-14 17:28:59 +0000676 s = active_console;
thsaf3a9032007-07-11 23:14:59 +0000677 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +0000678 return;
679
680 if (ydelta > 0) {
681 for(i = 0; i < ydelta; i++) {
682 if (s->y_displayed == s->y_base)
683 break;
684 if (++s->y_displayed == s->total_height)
685 s->y_displayed = 0;
686 }
687 } else {
688 ydelta = -ydelta;
689 i = s->backscroll_height;
690 if (i > s->total_height - s->height)
691 i = s->total_height - s->height;
692 y1 = s->y_base - i;
693 if (y1 < 0)
694 y1 += s->total_height;
695 for(i = 0; i < ydelta; i++) {
696 if (s->y_displayed == y1)
697 break;
698 if (--s->y_displayed < 0)
699 s->y_displayed = s->total_height - 1;
700 }
701 }
702 console_refresh(s);
703}
704
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200705static void console_put_lf(QemuConsole *s)
bellarde7f0ad52004-07-14 17:28:59 +0000706{
707 TextCell *c;
708 int x, y1;
709
bellarde7f0ad52004-07-14 17:28:59 +0000710 s->y++;
711 if (s->y >= s->height) {
712 s->y = s->height - 1;
pbrook6d6f7c22006-03-11 15:35:30 +0000713
bellarde7f0ad52004-07-14 17:28:59 +0000714 if (s->y_displayed == s->y_base) {
715 if (++s->y_displayed == s->total_height)
716 s->y_displayed = 0;
717 }
718 if (++s->y_base == s->total_height)
719 s->y_base = 0;
720 if (s->backscroll_height < s->total_height)
721 s->backscroll_height++;
722 y1 = (s->y_base + s->height - 1) % s->total_height;
723 c = &s->cells[y1 * s->width];
724 for(x = 0; x < s->width; x++) {
725 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000726 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000727 c++;
728 }
729 if (s == active_console && s->y_displayed == s->y_base) {
aliguori0e1f5a02008-11-24 19:29:13 +0000730 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000731 s->text_x[0] = 0;
732 s->text_y[0] = 0;
733 s->text_x[1] = s->width - 1;
734 s->text_y[1] = s->height - 1;
735 return;
736 }
737
ths5fafdf22007-09-16 21:08:06 +0000738 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
739 s->width * FONT_WIDTH,
bellarde7f0ad52004-07-14 17:28:59 +0000740 (s->height - 1) * FONT_HEIGHT);
741 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
ths5fafdf22007-09-16 21:08:06 +0000742 s->width * FONT_WIDTH, FONT_HEIGHT,
pbrook6d6f7c22006-03-11 15:35:30 +0000743 color_table[0][s->t_attrib_default.bgcol]);
pbrook14778c22009-01-21 03:02:52 +0000744 s->update_x0 = 0;
745 s->update_y0 = 0;
746 s->update_x1 = s->width * FONT_WIDTH;
747 s->update_y1 = s->height * FONT_HEIGHT;
bellarde7f0ad52004-07-14 17:28:59 +0000748 }
749 }
750}
751
pbrook6d6f7c22006-03-11 15:35:30 +0000752/* Set console attributes depending on the current escape codes.
753 * NOTE: I know this code is not very efficient (checking every color for it
754 * self) but it is more readable and better maintainable.
755 */
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200756static void console_handle_escape(QemuConsole *s)
pbrook6d6f7c22006-03-11 15:35:30 +0000757{
758 int i;
759
pbrook6d6f7c22006-03-11 15:35:30 +0000760 for (i=0; i<s->nb_esc_params; i++) {
761 switch (s->esc_params[i]) {
762 case 0: /* reset all console attributes to default */
763 s->t_attrib = s->t_attrib_default;
764 break;
765 case 1:
766 s->t_attrib.bold = 1;
767 break;
768 case 4:
769 s->t_attrib.uline = 1;
770 break;
771 case 5:
772 s->t_attrib.blink = 1;
773 break;
774 case 7:
775 s->t_attrib.invers = 1;
776 break;
777 case 8:
778 s->t_attrib.unvisible = 1;
779 break;
780 case 22:
781 s->t_attrib.bold = 0;
782 break;
783 case 24:
784 s->t_attrib.uline = 0;
785 break;
786 case 25:
787 s->t_attrib.blink = 0;
788 break;
789 case 27:
790 s->t_attrib.invers = 0;
791 break;
792 case 28:
793 s->t_attrib.unvisible = 0;
794 break;
795 /* set foreground color */
796 case 30:
797 s->t_attrib.fgcol=COLOR_BLACK;
798 break;
799 case 31:
800 s->t_attrib.fgcol=COLOR_RED;
801 break;
802 case 32:
803 s->t_attrib.fgcol=COLOR_GREEN;
804 break;
805 case 33:
806 s->t_attrib.fgcol=COLOR_YELLOW;
807 break;
808 case 34:
809 s->t_attrib.fgcol=COLOR_BLUE;
810 break;
811 case 35:
812 s->t_attrib.fgcol=COLOR_MAGENTA;
813 break;
814 case 36:
815 s->t_attrib.fgcol=COLOR_CYAN;
816 break;
817 case 37:
818 s->t_attrib.fgcol=COLOR_WHITE;
819 break;
820 /* set background color */
821 case 40:
822 s->t_attrib.bgcol=COLOR_BLACK;
823 break;
824 case 41:
825 s->t_attrib.bgcol=COLOR_RED;
826 break;
827 case 42:
828 s->t_attrib.bgcol=COLOR_GREEN;
829 break;
830 case 43:
831 s->t_attrib.bgcol=COLOR_YELLOW;
832 break;
833 case 44:
834 s->t_attrib.bgcol=COLOR_BLUE;
835 break;
836 case 45:
837 s->t_attrib.bgcol=COLOR_MAGENTA;
838 break;
839 case 46:
840 s->t_attrib.bgcol=COLOR_CYAN;
841 break;
842 case 47:
843 s->t_attrib.bgcol=COLOR_WHITE;
844 break;
845 }
846 }
847}
848
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200849static void console_clear_xy(QemuConsole *s, int x, int y)
thsadb47962007-01-16 23:02:36 +0000850{
851 int y1 = (s->y_base + y) % s->total_height;
852 TextCell *c = &s->cells[y1 * s->width + x];
853 c->ch = ' ';
854 c->t_attrib = s->t_attrib_default;
thsadb47962007-01-16 23:02:36 +0000855 update_xy(s, x, y);
856}
857
Ian Campbell3eea5492012-09-04 10:26:09 -0500858/* set cursor, checking bounds */
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200859static void set_cursor(QemuConsole *s, int x, int y)
Ian Campbell3eea5492012-09-04 10:26:09 -0500860{
861 if (x < 0) {
862 x = 0;
863 }
864 if (y < 0) {
865 y = 0;
866 }
867 if (y >= s->height) {
868 y = s->height - 1;
869 }
870 if (x >= s->width) {
871 x = s->width - 1;
872 }
873
874 s->x = x;
875 s->y = y;
876}
877
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200878static void console_putchar(QemuConsole *s, int ch)
bellarde7f0ad52004-07-14 17:28:59 +0000879{
880 TextCell *c;
thsadb47962007-01-16 23:02:36 +0000881 int y1, i;
882 int x, y;
bellarde7f0ad52004-07-14 17:28:59 +0000883
884 switch(s->state) {
885 case TTY_STATE_NORM:
886 switch(ch) {
pbrook6d6f7c22006-03-11 15:35:30 +0000887 case '\r': /* carriage return */
bellarde7f0ad52004-07-14 17:28:59 +0000888 s->x = 0;
889 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000890 case '\n': /* newline */
bellarde7f0ad52004-07-14 17:28:59 +0000891 console_put_lf(s);
892 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000893 case '\b': /* backspace */
ths5fafdf22007-09-16 21:08:06 +0000894 if (s->x > 0)
bellarde15d7372006-06-25 16:26:29 +0000895 s->x--;
pbrook6d6f7c22006-03-11 15:35:30 +0000896 break;
897 case '\t': /* tabspace */
898 if (s->x + (8 - (s->x % 8)) > s->width) {
bellardbd468842006-07-14 20:24:31 +0000899 s->x = 0;
pbrook6d6f7c22006-03-11 15:35:30 +0000900 console_put_lf(s);
901 } else {
902 s->x = s->x + (8 - (s->x % 8));
903 }
904 break;
905 case '\a': /* alert aka. bell */
906 /* TODO: has to be implemented */
907 break;
thsadb47962007-01-16 23:02:36 +0000908 case 14:
909 /* SI (shift in), character set 0 (ignored) */
910 break;
911 case 15:
912 /* SO (shift out), character set 1 (ignored) */
913 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000914 case 27: /* esc (introducing an escape sequence) */
bellarde7f0ad52004-07-14 17:28:59 +0000915 s->state = TTY_STATE_ESC;
916 break;
917 default:
thsed8276a2007-02-10 22:37:56 +0000918 if (s->x >= s->width) {
919 /* line wrap */
920 s->x = 0;
921 console_put_lf(s);
thsadb47962007-01-16 23:02:36 +0000922 }
bellarde7f0ad52004-07-14 17:28:59 +0000923 y1 = (s->y_base + s->y) % s->total_height;
924 c = &s->cells[y1 * s->width + s->x];
925 c->ch = ch;
pbrook6d6f7c22006-03-11 15:35:30 +0000926 c->t_attrib = s->t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +0000927 update_xy(s, s->x, s->y);
928 s->x++;
bellarde7f0ad52004-07-14 17:28:59 +0000929 break;
930 }
931 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000932 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
bellarde7f0ad52004-07-14 17:28:59 +0000933 if (ch == '[') {
934 for(i=0;i<MAX_ESC_PARAMS;i++)
935 s->esc_params[i] = 0;
936 s->nb_esc_params = 0;
937 s->state = TTY_STATE_CSI;
938 } else {
939 s->state = TTY_STATE_NORM;
940 }
941 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000942 case TTY_STATE_CSI: /* handle escape sequence parameters */
bellarde7f0ad52004-07-14 17:28:59 +0000943 if (ch >= '0' && ch <= '9') {
944 if (s->nb_esc_params < MAX_ESC_PARAMS) {
Laszlo Ersekc10600a2012-09-17 11:10:03 +0200945 int *param = &s->esc_params[s->nb_esc_params];
946 int digit = (ch - '0');
947
948 *param = (*param <= (INT_MAX - digit) / 10) ?
949 *param * 10 + digit : INT_MAX;
bellarde7f0ad52004-07-14 17:28:59 +0000950 }
951 } else {
Ian Campbell3eea5492012-09-04 10:26:09 -0500952 if (s->nb_esc_params < MAX_ESC_PARAMS)
953 s->nb_esc_params++;
bellarde7f0ad52004-07-14 17:28:59 +0000954 if (ch == ';')
955 break;
thsadb47962007-01-16 23:02:36 +0000956#ifdef DEBUG_CONSOLE
957 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
958 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
959#endif
bellarde7f0ad52004-07-14 17:28:59 +0000960 s->state = TTY_STATE_NORM;
961 switch(ch) {
thsadb47962007-01-16 23:02:36 +0000962 case 'A':
963 /* move cursor up */
964 if (s->esc_params[0] == 0) {
965 s->esc_params[0] = 1;
966 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500967 set_cursor(s, s->x, s->y - s->esc_params[0]);
bellarde7f0ad52004-07-14 17:28:59 +0000968 break;
thsadb47962007-01-16 23:02:36 +0000969 case 'B':
970 /* move cursor down */
971 if (s->esc_params[0] == 0) {
972 s->esc_params[0] = 1;
973 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500974 set_cursor(s, s->x, s->y + s->esc_params[0]);
thsadb47962007-01-16 23:02:36 +0000975 break;
976 case 'C':
977 /* move cursor right */
978 if (s->esc_params[0] == 0) {
979 s->esc_params[0] = 1;
980 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500981 set_cursor(s, s->x + s->esc_params[0], s->y);
thsadb47962007-01-16 23:02:36 +0000982 break;
983 case 'D':
984 /* move cursor left */
985 if (s->esc_params[0] == 0) {
986 s->esc_params[0] = 1;
987 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500988 set_cursor(s, s->x - s->esc_params[0], s->y);
thsadb47962007-01-16 23:02:36 +0000989 break;
990 case 'G':
991 /* move cursor to column */
Ian Campbell3eea5492012-09-04 10:26:09 -0500992 set_cursor(s, s->esc_params[0] - 1, s->y);
thsadb47962007-01-16 23:02:36 +0000993 break;
994 case 'f':
995 case 'H':
996 /* move cursor to row, column */
Ian Campbell3eea5492012-09-04 10:26:09 -0500997 set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
thsadb47962007-01-16 23:02:36 +0000998 break;
999 case 'J':
1000 switch (s->esc_params[0]) {
1001 case 0:
1002 /* clear to end of screen */
1003 for (y = s->y; y < s->height; y++) {
1004 for (x = 0; x < s->width; x++) {
1005 if (y == s->y && x < s->x) {
1006 continue;
1007 }
1008 console_clear_xy(s, x, y);
1009 }
1010 }
1011 break;
1012 case 1:
1013 /* clear from beginning of screen */
1014 for (y = 0; y <= s->y; y++) {
1015 for (x = 0; x < s->width; x++) {
1016 if (y == s->y && x > s->x) {
1017 break;
1018 }
1019 console_clear_xy(s, x, y);
1020 }
1021 }
1022 break;
1023 case 2:
1024 /* clear entire screen */
1025 for (y = 0; y <= s->height; y++) {
1026 for (x = 0; x < s->width; x++) {
1027 console_clear_xy(s, x, y);
1028 }
1029 }
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001030 break;
thsadb47962007-01-16 23:02:36 +00001031 }
Markus Armbruster95d8f9f2011-11-22 11:59:07 +01001032 break;
thsadb47962007-01-16 23:02:36 +00001033 case 'K':
1034 switch (s->esc_params[0]) {
1035 case 0:
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001036 /* clear to eol */
1037 for(x = s->x; x < s->width; x++) {
thsadb47962007-01-16 23:02:36 +00001038 console_clear_xy(s, x, s->y);
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001039 }
1040 break;
thsadb47962007-01-16 23:02:36 +00001041 case 1:
1042 /* clear from beginning of line */
1043 for (x = 0; x <= s->x; x++) {
1044 console_clear_xy(s, x, s->y);
1045 }
1046 break;
1047 case 2:
1048 /* clear entire line */
1049 for(x = 0; x < s->width; x++) {
1050 console_clear_xy(s, x, s->y);
1051 }
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001052 break;
1053 }
thsadb47962007-01-16 23:02:36 +00001054 break;
1055 case 'm':
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001056 console_handle_escape(s);
1057 break;
thsadb47962007-01-16 23:02:36 +00001058 case 'n':
1059 /* report cursor position */
1060 /* TODO: send ESC[row;colR */
1061 break;
1062 case 's':
1063 /* save cursor position */
1064 s->x_saved = s->x;
1065 s->y_saved = s->y;
1066 break;
1067 case 'u':
1068 /* restore cursor position */
1069 s->x = s->x_saved;
1070 s->y = s->y_saved;
1071 break;
1072 default:
1073#ifdef DEBUG_CONSOLE
1074 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1075#endif
1076 break;
1077 }
1078 break;
bellarde7f0ad52004-07-14 17:28:59 +00001079 }
1080 }
1081}
1082
1083void console_select(unsigned int index)
1084{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001085 QemuConsole *s;
pbrook6d6f7c22006-03-11 15:35:30 +00001086
bellarde7f0ad52004-07-14 17:28:59 +00001087 if (index >= MAX_CONSOLES)
1088 return;
Stefan Hajnoczi358664c2010-09-20 14:11:19 +01001089 if (active_console) {
1090 active_console->g_width = ds_get_width(active_console->ds);
1091 active_console->g_height = ds_get_height(active_console->ds);
1092 }
bellarde7f0ad52004-07-14 17:28:59 +00001093 s = consoles[index];
1094 if (s) {
aliguori7d957bd2009-01-15 22:14:11 +00001095 DisplayState *ds = s->ds;
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001096
Stefan Weil8bd6b062012-08-17 15:50:44 +02001097 if (active_console && active_console->cursor_timer) {
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001098 qemu_del_timer(active_console->cursor_timer);
1099 }
bellarde7f0ad52004-07-14 17:28:59 +00001100 active_console = s;
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001101 if (ds->have_gfx) {
aliguori7b5d76d2009-03-13 15:02:13 +00001102 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001103 dpy_gfx_resize(ds);
1104 }
1105 if (ds->have_text) {
1106 dpy_text_resize(ds, s->width, s->height);
aliguori68f00992009-01-21 18:59:12 +00001107 }
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001108 if (s->cursor_timer) {
1109 qemu_mod_timer(s->cursor_timer,
1110 qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1111 }
balrog4d3b6f62008-02-10 16:33:14 +00001112 vga_hw_invalidate();
bellarde7f0ad52004-07-14 17:28:59 +00001113 }
1114}
1115
1116static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1117{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001118 QemuConsole *s = chr->opaque;
bellarde7f0ad52004-07-14 17:28:59 +00001119 int i;
1120
pbrook14778c22009-01-21 03:02:52 +00001121 s->update_x0 = s->width * FONT_WIDTH;
1122 s->update_y0 = s->height * FONT_HEIGHT;
1123 s->update_x1 = 0;
1124 s->update_y1 = 0;
bellarde7f0ad52004-07-14 17:28:59 +00001125 console_show_cursor(s, 0);
1126 for(i = 0; i < len; i++) {
1127 console_putchar(s, buf[i]);
1128 }
1129 console_show_cursor(s, 1);
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001130 if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
1131 dpy_gfx_update(s->ds, s->update_x0, s->update_y0,
1132 s->update_x1 - s->update_x0,
1133 s->update_y1 - s->update_y0);
pbrook14778c22009-01-21 03:02:52 +00001134 }
bellarde7f0ad52004-07-14 17:28:59 +00001135 return len;
1136}
1137
bellarde15d7372006-06-25 16:26:29 +00001138static void kbd_send_chars(void *opaque)
1139{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001140 QemuConsole *s = opaque;
bellarde15d7372006-06-25 16:26:29 +00001141 int len;
1142 uint8_t buf[16];
ths3b46e622007-09-17 08:09:54 +00001143
Anthony Liguori909cda12011-08-15 11:17:31 -05001144 len = qemu_chr_be_can_write(s->chr);
bellarde15d7372006-06-25 16:26:29 +00001145 if (len > s->out_fifo.count)
1146 len = s->out_fifo.count;
1147 if (len > 0) {
1148 if (len > sizeof(buf))
1149 len = sizeof(buf);
1150 qemu_fifo_read(&s->out_fifo, buf, len);
Anthony Liguorifa5efcc2011-08-15 11:17:30 -05001151 qemu_chr_be_write(s->chr, buf, len);
bellarde15d7372006-06-25 16:26:29 +00001152 }
1153 /* characters are pending: we send them a bit later (XXX:
1154 horrible, should change char device API) */
1155 if (s->out_fifo.count > 0) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001156 qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
bellarde15d7372006-06-25 16:26:29 +00001157 }
1158}
1159
bellarde7f0ad52004-07-14 17:28:59 +00001160/* called when an ascii key is pressed */
1161void kbd_put_keysym(int keysym)
1162{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001163 QemuConsole *s;
bellarde7f0ad52004-07-14 17:28:59 +00001164 uint8_t buf[16], *q;
1165 int c;
1166
1167 s = active_console;
thsaf3a9032007-07-11 23:14:59 +00001168 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +00001169 return;
1170
1171 switch(keysym) {
1172 case QEMU_KEY_CTRL_UP:
1173 console_scroll(-1);
1174 break;
1175 case QEMU_KEY_CTRL_DOWN:
1176 console_scroll(1);
1177 break;
1178 case QEMU_KEY_CTRL_PAGEUP:
1179 console_scroll(-10);
1180 break;
1181 case QEMU_KEY_CTRL_PAGEDOWN:
1182 console_scroll(10);
1183 break;
1184 default:
bellarde15d7372006-06-25 16:26:29 +00001185 /* convert the QEMU keysym to VT100 key string */
1186 q = buf;
1187 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1188 *q++ = '\033';
1189 *q++ = '[';
1190 c = keysym - 0xe100;
1191 if (c >= 10)
1192 *q++ = '0' + (c / 10);
1193 *q++ = '0' + (c % 10);
1194 *q++ = '~';
1195 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1196 *q++ = '\033';
1197 *q++ = '[';
1198 *q++ = keysym & 0xff;
Paolo Bonzini41048332010-12-23 13:42:52 +01001199 } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1200 console_puts(s->chr, (const uint8_t *) "\r", 1);
1201 *q++ = '\n';
bellarde15d7372006-06-25 16:26:29 +00001202 } else {
Paolo Bonzini41048332010-12-23 13:42:52 +01001203 *q++ = keysym;
1204 }
1205 if (s->echo) {
1206 console_puts(s->chr, buf, q - buf);
bellarde15d7372006-06-25 16:26:29 +00001207 }
pbrooke5b0bc42007-01-27 23:46:43 +00001208 if (s->chr->chr_read) {
bellarde15d7372006-06-25 16:26:29 +00001209 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1210 kbd_send_chars(s);
bellarde7f0ad52004-07-14 17:28:59 +00001211 }
1212 break;
1213 }
1214}
1215
balrog4d3b6f62008-02-10 16:33:14 +00001216static void text_console_invalidate(void *opaque)
1217{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001218 QemuConsole *s = (QemuConsole *) opaque;
aliguori68f00992009-01-21 18:59:12 +00001219 if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1220 s->g_width = ds_get_width(s->ds);
1221 s->g_height = ds_get_height(s->ds);
1222 text_console_resize(s);
1223 }
balrog4d3b6f62008-02-10 16:33:14 +00001224 console_refresh(s);
1225}
1226
Anthony Liguoric227f092009-10-01 16:12:16 -05001227static void text_console_update(void *opaque, console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +00001228{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001229 QemuConsole *s = (QemuConsole *) opaque;
balrog4d3b6f62008-02-10 16:33:14 +00001230 int i, j, src;
1231
1232 if (s->text_x[0] <= s->text_x[1]) {
1233 src = (s->y_base + s->text_y[0]) * s->width;
1234 chardata += s->text_y[0] * s->width;
1235 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1236 for (j = 0; j < s->width; j ++, src ++)
1237 console_write_ch(chardata ++, s->cells[src].ch |
1238 (s->cells[src].t_attrib.fgcol << 12) |
1239 (s->cells[src].t_attrib.bgcol << 8) |
1240 (s->cells[src].t_attrib.bold << 21));
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001241 dpy_text_update(s->ds, s->text_x[0], s->text_y[0],
1242 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
balrog4d3b6f62008-02-10 16:33:14 +00001243 s->text_x[0] = s->width;
1244 s->text_y[0] = s->height;
1245 s->text_x[1] = 0;
1246 s->text_y[1] = 0;
1247 }
1248 if (s->cursor_invalidate) {
Gerd Hoffmannbf2fde72012-09-12 07:56:45 +02001249 dpy_text_cursor(s->ds, s->x, s->y);
balrog4d3b6f62008-02-10 16:33:14 +00001250 s->cursor_invalidate = 0;
1251 }
1252}
1253
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001254static QemuConsole *get_graphic_console(DisplayState *ds)
blueswir1a147d622009-01-16 19:41:04 +00001255{
aliguori3023f332009-01-16 19:04:14 +00001256 int i;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001257 QemuConsole *s;
aliguori3023f332009-01-16 19:04:14 +00001258 for (i = 0; i < nb_consoles; i++) {
1259 s = consoles[i];
aliguori42aa98e2009-01-16 21:01:48 +00001260 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
aliguori3023f332009-01-16 19:04:14 +00001261 return s;
1262 }
1263 return NULL;
1264}
1265
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001266static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
bellarde7f0ad52004-07-14 17:28:59 +00001267{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001268 QemuConsole *s;
pbrook95219892006-04-09 01:06:34 +00001269 int i;
bellarde7f0ad52004-07-14 17:28:59 +00001270
1271 if (nb_consoles >= MAX_CONSOLES)
1272 return NULL;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001273 s = g_malloc0(sizeof(QemuConsole));
thsaf3a9032007-07-11 23:14:59 +00001274 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1275 (console_type == GRAPHIC_CONSOLE))) {
bellarde7f0ad52004-07-14 17:28:59 +00001276 active_console = s;
thsaf3a9032007-07-11 23:14:59 +00001277 }
bellarde7f0ad52004-07-14 17:28:59 +00001278 s->ds = ds;
thsaf3a9032007-07-11 23:14:59 +00001279 s->console_type = console_type;
1280 if (console_type != GRAPHIC_CONSOLE) {
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001281 s->index = nb_consoles;
pbrook95219892006-04-09 01:06:34 +00001282 consoles[nb_consoles++] = s;
1283 } else {
1284 /* HACK: Put graphical consoles before text consoles. */
1285 for (i = nb_consoles; i > 0; i--) {
thsaf3a9032007-07-11 23:14:59 +00001286 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
pbrook95219892006-04-09 01:06:34 +00001287 break;
1288 consoles[i] = consoles[i - 1];
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001289 consoles[i]->index = i;
pbrook95219892006-04-09 01:06:34 +00001290 }
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001291 s->index = i;
pbrook95219892006-04-09 01:06:34 +00001292 consoles[i] = s;
aliguori3023f332009-01-16 19:04:14 +00001293 nb_consoles++;
pbrook95219892006-04-09 01:06:34 +00001294 }
bellarde7f0ad52004-07-14 17:28:59 +00001295 return s;
1296}
1297
Gerd Hoffmann537a4392012-09-27 11:06:36 +02001298static void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1299 int linesize, PixelFormat pf, int newflags)
Jes Sorensenffe8b822011-03-16 13:33:30 +01001300{
Jes Sorensenffe8b822011-03-16 13:33:30 +01001301 surface->pf = pf;
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001302
1303 qemu_pixman_image_unref(surface->image);
1304 surface->image = NULL;
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001305
1306 surface->format = qemu_pixman_get_format(&pf);
1307 assert(surface->format != 0);
1308 surface->image = pixman_image_create_bits(surface->format,
1309 width, height,
1310 NULL, linesize);
1311 assert(surface->image != NULL);
1312
Jes Sorensenffe8b822011-03-16 13:33:30 +01001313 surface->flags = newflags | QEMU_ALLOCATED_FLAG;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001314#ifdef HOST_WORDS_BIGENDIAN
Jes Sorensenffe8b822011-03-16 13:33:30 +01001315 surface->flags |= QEMU_BIG_ENDIAN_FLAG;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001316#endif
Paolo Bonzini98b50082010-02-11 00:29:57 +01001317}
1318
Gerd Hoffmann537a4392012-09-27 11:06:36 +02001319DisplaySurface *qemu_create_displaysurface(DisplayState *ds,
1320 int width, int height)
1321{
1322 DisplaySurface *surface = g_new0(DisplaySurface, 1);
1323
1324 int linesize = width * 4;
1325 qemu_alloc_display(surface, width, height, linesize,
1326 qemu_default_pixelformat(32), 0);
1327 return surface;
1328}
1329
1330DisplaySurface *qemu_resize_displaysurface(DisplayState *ds,
1331 int width, int height)
1332{
1333 int linesize = width * 4;
1334
1335 trace_displaysurface_resize(ds, ds->surface, width, height);
1336 qemu_alloc_display(ds->surface, width, height, linesize,
1337 qemu_default_pixelformat(32), 0);
1338 return ds->surface;
1339}
1340
Gerd Hoffmann187cd1d2012-09-26 07:46:20 +02001341DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
Gerd Hoffmannb1424e02013-02-20 09:37:12 +01001342 int linesize, uint8_t *data,
1343 bool byteswap)
Paolo Bonzini98b50082010-02-11 00:29:57 +01001344{
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001345 DisplaySurface *surface = g_new0(DisplaySurface, 1);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001346
Gerd Hoffmannb1424e02013-02-20 09:37:12 +01001347 if (byteswap) {
1348 surface->pf = qemu_different_endianness_pixelformat(bpp);
1349 } else {
1350 surface->pf = qemu_default_pixelformat(bpp);
1351 }
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001352
1353 surface->format = qemu_pixman_get_format(&surface->pf);
1354 assert(surface->format != 0);
1355 surface->image = pixman_image_create_bits(surface->format,
1356 width, height,
1357 (void *)data, linesize);
1358 assert(surface->image != NULL);
1359
Paolo Bonzini98b50082010-02-11 00:29:57 +01001360#ifdef HOST_WORDS_BIGENDIAN
1361 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1362#endif
Paolo Bonzini98b50082010-02-11 00:29:57 +01001363
1364 return surface;
1365}
1366
Gerd Hoffmann187cd1d2012-09-26 07:46:20 +02001367void qemu_free_displaysurface(DisplayState *ds)
Paolo Bonzini98b50082010-02-11 00:29:57 +01001368{
Gerd Hoffmann187cd1d2012-09-26 07:46:20 +02001369 trace_displaysurface_free(ds, ds->surface);
1370 if (ds->surface == NULL) {
Paolo Bonzini98b50082010-02-11 00:29:57 +01001371 return;
Gerd Hoffmann187cd1d2012-09-26 07:46:20 +02001372 }
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001373 qemu_pixman_image_unref(ds->surface->image);
Gerd Hoffmann187cd1d2012-09-26 07:46:20 +02001374 g_free(ds->surface);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001375}
1376
Paolo Bonzini98b50082010-02-11 00:29:57 +01001377static void dumb_display_init(void)
1378{
Anthony Liguori7267c092011-08-20 22:09:37 -05001379 DisplayState *ds = g_malloc0(sizeof(DisplayState));
Jan Kiszka18026512011-06-19 11:53:02 +02001380 int width = 640;
1381 int height = 480;
1382
Jan Kiszka18026512011-06-19 11:53:02 +02001383 if (is_fixedsize_console()) {
1384 width = active_console->g_width;
1385 height = active_console->g_height;
1386 }
1387 ds->surface = qemu_create_displaysurface(ds, width, height);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001388 register_displaystate(ds);
1389}
1390
1391/***********************************************************/
1392/* register display */
1393
1394void register_displaystate(DisplayState *ds)
1395{
1396 DisplayState **s;
1397 s = &display_state;
1398 while (*s != NULL)
1399 s = &(*s)->next;
1400 ds->next = NULL;
1401 *s = ds;
1402}
1403
1404DisplayState *get_displaystate(void)
1405{
1406 if (!display_state) {
1407 dumb_display_init ();
1408 }
1409 return display_state;
1410}
1411
aliguori3023f332009-01-16 19:04:14 +00001412DisplayState *graphic_console_init(vga_hw_update_ptr update,
1413 vga_hw_invalidate_ptr invalidate,
1414 vga_hw_screen_dump_ptr screen_dump,
1415 vga_hw_text_update_ptr text_update,
1416 void *opaque)
bellarde7f0ad52004-07-14 17:28:59 +00001417{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001418 QemuConsole *s;
aliguori3023f332009-01-16 19:04:14 +00001419 DisplayState *ds;
aurel32f0f2f972009-01-16 21:13:49 +00001420
Anthony Liguori7267c092011-08-20 22:09:37 -05001421 ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
aliguori7b5d76d2009-03-13 15:02:13 +00001422 ds->surface = qemu_create_displaysurface(ds, 640, 480);
pbrook95219892006-04-09 01:06:34 +00001423
thsaf3a9032007-07-11 23:14:59 +00001424 s = new_console(ds, GRAPHIC_CONSOLE);
aliguori3023f332009-01-16 19:04:14 +00001425 if (s == NULL) {
aliguori7b5d76d2009-03-13 15:02:13 +00001426 qemu_free_displaysurface(ds);
Anthony Liguori7267c092011-08-20 22:09:37 -05001427 g_free(ds);
aliguori3023f332009-01-16 19:04:14 +00001428 return NULL;
1429 }
pbrook95219892006-04-09 01:06:34 +00001430 s->hw_update = update;
1431 s->hw_invalidate = invalidate;
1432 s->hw_screen_dump = screen_dump;
balrog4d3b6f62008-02-10 16:33:14 +00001433 s->hw_text_update = text_update;
pbrook95219892006-04-09 01:06:34 +00001434 s->hw = opaque;
aliguori3023f332009-01-16 19:04:14 +00001435
aurel32f0f2f972009-01-16 21:13:49 +00001436 register_displaystate(ds);
aliguori3023f332009-01-16 19:04:14 +00001437 return ds;
pbrook95219892006-04-09 01:06:34 +00001438}
1439
1440int is_graphic_console(void)
1441{
balrog4d3b6f62008-02-10 16:33:14 +00001442 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
bellarde7f0ad52004-07-14 17:28:59 +00001443}
1444
balrogc21bbcf2008-09-24 03:32:33 +00001445int is_fixedsize_console(void)
1446{
1447 return active_console && active_console->console_type != TEXT_CONSOLE;
1448}
1449
balroga528b802007-10-30 22:38:53 +00001450void console_color_init(DisplayState *ds)
1451{
1452 int i, j;
1453 for (j = 0; j < 2; j++) {
1454 for (i = 0; i < 8; i++) {
aurel32f0f2f972009-01-16 21:13:49 +00001455 color_table[j][i] = col_expand(ds,
balroga528b802007-10-30 22:38:53 +00001456 vga_get_color(ds, color_table_rgb[j][i]));
1457 }
1458 }
1459}
1460
Paolo Bonzini41048332010-12-23 13:42:52 +01001461static void text_console_set_echo(CharDriverState *chr, bool echo)
1462{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001463 QemuConsole *s = chr->opaque;
Paolo Bonzini41048332010-12-23 13:42:52 +01001464
1465 s->echo = echo;
1466}
1467
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001468static void text_console_update_cursor(void *opaque)
1469{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001470 QemuConsole *s = opaque;
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001471
1472 s->cursor_visible_phase = !s->cursor_visible_phase;
1473 vga_hw_invalidate();
1474 qemu_mod_timer(s->cursor_timer,
1475 qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1476}
1477
Paolo Bonzini44b37b92010-12-23 13:42:53 +01001478static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
bellarde7f0ad52004-07-14 17:28:59 +00001479{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001480 QemuConsole *s;
bellarde7f0ad52004-07-14 17:28:59 +00001481 static int color_inited;
pbrook6d6f7c22006-03-11 15:35:30 +00001482
Paolo Bonzini491e1142010-12-23 13:42:51 +01001483 s = chr->opaque;
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001484
bellarde7f0ad52004-07-14 17:28:59 +00001485 chr->chr_write = console_puts;
bellard6fcfafb2004-08-01 21:48:30 +00001486
bellarde15d7372006-06-25 16:26:29 +00001487 s->out_fifo.buf = s->out_fifo_buf;
1488 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001489 s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
aliguori3023f332009-01-16 19:04:14 +00001490 s->ds = ds;
ths3b46e622007-09-17 08:09:54 +00001491
bellarde7f0ad52004-07-14 17:28:59 +00001492 if (!color_inited) {
1493 color_inited = 1;
balroga528b802007-10-30 22:38:53 +00001494 console_color_init(s->ds);
bellarde7f0ad52004-07-14 17:28:59 +00001495 }
1496 s->y_displayed = 0;
1497 s->y_base = 0;
1498 s->total_height = DEFAULT_BACKSCROLL;
1499 s->x = 0;
1500 s->y = 0;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001501 if (s->console_type == TEXT_CONSOLE) {
1502 s->g_width = ds_get_width(s->ds);
1503 s->g_height = ds_get_height(s->ds);
1504 }
pbrook6d6f7c22006-03-11 15:35:30 +00001505
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001506 s->cursor_timer =
1507 qemu_new_timer_ms(rt_clock, text_console_update_cursor, s);
1508
balrog4d3b6f62008-02-10 16:33:14 +00001509 s->hw_invalidate = text_console_invalidate;
1510 s->hw_text_update = text_console_update;
1511 s->hw = s;
1512
pbrook6d6f7c22006-03-11 15:35:30 +00001513 /* Set text attribute defaults */
1514 s->t_attrib_default.bold = 0;
1515 s->t_attrib_default.uline = 0;
1516 s->t_attrib_default.blink = 0;
1517 s->t_attrib_default.invers = 0;
1518 s->t_attrib_default.unvisible = 0;
1519 s->t_attrib_default.fgcol = COLOR_WHITE;
1520 s->t_attrib_default.bgcol = COLOR_BLACK;
pbrook6d6f7c22006-03-11 15:35:30 +00001521 /* set current text attributes to default */
1522 s->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +00001523 text_console_resize(s);
1524
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001525 if (chr->label) {
1526 char msg[128];
1527 int len;
1528
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001529 s->t_attrib.bgcol = COLOR_BLUE;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001530 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1531 console_puts(chr, (uint8_t*)msg, len);
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001532 s->t_attrib = s->t_attrib_default;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001533 }
1534
Amit Shah127338e2009-11-03 19:59:56 +05301535 qemu_chr_generic_open(chr);
aurel32ceecf1d2009-01-18 14:08:04 +00001536 if (chr->init)
1537 chr->init(chr);
bellarde7f0ad52004-07-14 17:28:59 +00001538}
pbrookc60e08d2008-07-01 16:24:38 +00001539
Markus Armbruster1f514702012-02-07 15:09:08 +01001540CharDriverState *text_console_init(QemuOpts *opts)
aliguori2796dae2009-01-16 20:23:27 +00001541{
1542 CharDriverState *chr;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001543 QemuConsole *s;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001544 unsigned width;
1545 unsigned height;
aliguori2796dae2009-01-16 20:23:27 +00001546
Anthony Liguori7267c092011-08-20 22:09:37 -05001547 chr = g_malloc0(sizeof(CharDriverState));
aliguori2796dae2009-01-16 20:23:27 +00001548
Paolo Bonzini491e1142010-12-23 13:42:51 +01001549 width = qemu_opt_get_number(opts, "width", 0);
1550 if (width == 0)
1551 width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1552
1553 height = qemu_opt_get_number(opts, "height", 0);
1554 if (height == 0)
1555 height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1556
1557 if (width == 0 || height == 0) {
1558 s = new_console(NULL, TEXT_CONSOLE);
1559 } else {
1560 s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1561 }
1562
1563 if (!s) {
Stefan Weil5354d082011-10-02 18:53:09 +02001564 g_free(chr);
Markus Armbruster1f514702012-02-07 15:09:08 +01001565 return NULL;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001566 }
1567
1568 s->chr = chr;
1569 s->g_width = width;
1570 s->g_height = height;
1571 chr->opaque = s;
Paolo Bonzini41048332010-12-23 13:42:52 +01001572 chr->chr_set_echo = text_console_set_echo;
Markus Armbruster1f514702012-02-07 15:09:08 +01001573 return chr;
aliguori2796dae2009-01-16 20:23:27 +00001574}
1575
1576void text_consoles_set_display(DisplayState *ds)
1577{
1578 int i;
1579
Markus Armbruster8811e1e2012-02-07 15:09:21 +01001580 for (i = 0; i < nb_consoles; i++) {
1581 if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1582 text_console_do_init(consoles[i]->chr, ds);
1583 }
aliguori2796dae2009-01-16 20:23:27 +00001584 }
aliguori2796dae2009-01-16 20:23:27 +00001585}
1586
aliguori3023f332009-01-16 19:04:14 +00001587void qemu_console_resize(DisplayState *ds, int width, int height)
pbrookc60e08d2008-07-01 16:24:38 +00001588{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001589 QemuConsole *s = get_graphic_console(ds);
aliguorif497f142009-01-21 19:18:00 +00001590 if (!s) return;
1591
aliguori3023f332009-01-16 19:04:14 +00001592 s->g_width = width;
1593 s->g_height = height;
1594 if (is_graphic_console()) {
aliguori7b5d76d2009-03-13 15:02:13 +00001595 ds->surface = qemu_resize_displaysurface(ds, width, height);
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001596 dpy_gfx_resize(ds);
pbrookc60e08d2008-07-01 16:24:38 +00001597 }
1598}
balrog38334f72008-09-24 02:21:24 +00001599
aliguori3023f332009-01-16 19:04:14 +00001600void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1601 int dst_x, int dst_y, int w, int h)
balrogc21bbcf2008-09-24 03:32:33 +00001602{
aliguori3023f332009-01-16 19:04:14 +00001603 if (is_graphic_console()) {
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001604 dpy_gfx_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
balrog38334f72008-09-24 02:21:24 +00001605 }
1606}
aliguori7d957bd2009-01-15 22:14:11 +00001607
malc0da2ea12009-01-23 19:56:19 +00001608PixelFormat qemu_different_endianness_pixelformat(int bpp)
aliguori7d957bd2009-01-15 22:14:11 +00001609{
1610 PixelFormat pf;
1611
1612 memset(&pf, 0x00, sizeof(PixelFormat));
1613
1614 pf.bits_per_pixel = bpp;
BALATON Zoltanfeadf1a2012-08-22 17:19:42 +02001615 pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
aliguori7d957bd2009-01-15 22:14:11 +00001616 pf.depth = bpp == 32 ? 24 : bpp;
1617
1618 switch (bpp) {
malc0da2ea12009-01-23 19:56:19 +00001619 case 24:
1620 pf.rmask = 0x000000FF;
1621 pf.gmask = 0x0000FF00;
1622 pf.bmask = 0x00FF0000;
1623 pf.rmax = 255;
1624 pf.gmax = 255;
1625 pf.bmax = 255;
1626 pf.rshift = 0;
1627 pf.gshift = 8;
1628 pf.bshift = 16;
aliguori90a1e3c2009-01-26 15:37:30 +00001629 pf.rbits = 8;
1630 pf.gbits = 8;
1631 pf.bbits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001632 break;
malc0da2ea12009-01-23 19:56:19 +00001633 case 32:
1634 pf.rmask = 0x0000FF00;
1635 pf.gmask = 0x00FF0000;
1636 pf.bmask = 0xFF000000;
1637 pf.amask = 0x00000000;
1638 pf.amax = 255;
1639 pf.rmax = 255;
1640 pf.gmax = 255;
1641 pf.bmax = 255;
1642 pf.ashift = 0;
1643 pf.rshift = 8;
1644 pf.gshift = 16;
1645 pf.bshift = 24;
aliguori90a1e3c2009-01-26 15:37:30 +00001646 pf.rbits = 8;
1647 pf.gbits = 8;
1648 pf.bbits = 8;
1649 pf.abits = 8;
malc0da2ea12009-01-23 19:56:19 +00001650 break;
1651 default:
1652 break;
1653 }
1654 return pf;
1655}
1656
1657PixelFormat qemu_default_pixelformat(int bpp)
1658{
1659 PixelFormat pf;
1660
1661 memset(&pf, 0x00, sizeof(PixelFormat));
1662
1663 pf.bits_per_pixel = bpp;
BALATON Zoltanfeadf1a2012-08-22 17:19:42 +02001664 pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
malc0da2ea12009-01-23 19:56:19 +00001665 pf.depth = bpp == 32 ? 24 : bpp;
1666
1667 switch (bpp) {
Gerd Hoffmannb6278082010-05-21 11:59:14 +02001668 case 15:
1669 pf.bits_per_pixel = 16;
Gerd Hoffmannb6278082010-05-21 11:59:14 +02001670 pf.rmask = 0x00007c00;
1671 pf.gmask = 0x000003E0;
1672 pf.bmask = 0x0000001F;
1673 pf.rmax = 31;
1674 pf.gmax = 31;
1675 pf.bmax = 31;
1676 pf.rshift = 10;
1677 pf.gshift = 5;
1678 pf.bshift = 0;
1679 pf.rbits = 5;
1680 pf.gbits = 5;
1681 pf.bbits = 5;
1682 break;
aliguori7d957bd2009-01-15 22:14:11 +00001683 case 16:
1684 pf.rmask = 0x0000F800;
1685 pf.gmask = 0x000007E0;
1686 pf.bmask = 0x0000001F;
1687 pf.rmax = 31;
1688 pf.gmax = 63;
1689 pf.bmax = 31;
1690 pf.rshift = 11;
1691 pf.gshift = 5;
1692 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001693 pf.rbits = 5;
1694 pf.gbits = 6;
1695 pf.bbits = 5;
aliguori7d957bd2009-01-15 22:14:11 +00001696 break;
1697 case 24:
aliguori7d957bd2009-01-15 22:14:11 +00001698 pf.rmask = 0x00FF0000;
1699 pf.gmask = 0x0000FF00;
1700 pf.bmask = 0x000000FF;
1701 pf.rmax = 255;
1702 pf.gmax = 255;
1703 pf.bmax = 255;
1704 pf.rshift = 16;
1705 pf.gshift = 8;
1706 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001707 pf.rbits = 8;
1708 pf.gbits = 8;
1709 pf.bbits = 8;
Markus Armbruster0eba62e2011-11-22 12:56:10 +01001710 break;
malc0da2ea12009-01-23 19:56:19 +00001711 case 32:
1712 pf.rmask = 0x00FF0000;
1713 pf.gmask = 0x0000FF00;
1714 pf.bmask = 0x000000FF;
malc0da2ea12009-01-23 19:56:19 +00001715 pf.rmax = 255;
1716 pf.gmax = 255;
1717 pf.bmax = 255;
malc0da2ea12009-01-23 19:56:19 +00001718 pf.rshift = 16;
1719 pf.gshift = 8;
1720 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001721 pf.rbits = 8;
1722 pf.gbits = 8;
1723 pf.bbits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001724 break;
1725 default:
1726 break;
1727 }
1728 return pf;
1729}