blob: 260a029246566c6823b08412356e8f0fbeb47633 [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"
Luiz Capitulinoad39cf62012-05-24 13:48:23 -030027#include "qmp-commands.h"
bellarde7f0ad52004-07-14 17:28:59 +000028
pbrook6d6f7c22006-03-11 15:35:30 +000029//#define DEBUG_CONSOLE
bellarde7f0ad52004-07-14 17:28:59 +000030#define DEFAULT_BACKSCROLL 512
31#define MAX_CONSOLES 12
Jan Kiszkabf1bed82012-07-10 22:00:55 +020032#define CONSOLE_CURSOR_PERIOD 500
bellarde7f0ad52004-07-14 17:28:59 +000033
bellard26489842006-06-25 17:37:36 +000034#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
35#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
bellarde7f0ad52004-07-14 17:28:59 +000036
pbrook6d6f7c22006-03-11 15:35:30 +000037typedef struct TextAttributes {
38 uint8_t fgcol:4;
39 uint8_t bgcol:4;
40 uint8_t bold:1;
41 uint8_t uline:1;
42 uint8_t blink:1;
43 uint8_t invers:1;
44 uint8_t unvisible:1;
45} TextAttributes;
46
bellarde7f0ad52004-07-14 17:28:59 +000047typedef struct TextCell {
48 uint8_t ch;
pbrook6d6f7c22006-03-11 15:35:30 +000049 TextAttributes t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +000050} TextCell;
51
52#define MAX_ESC_PARAMS 3
53
54enum TTYState {
55 TTY_STATE_NORM,
56 TTY_STATE_ESC,
57 TTY_STATE_CSI,
58};
59
bellarde15d7372006-06-25 16:26:29 +000060typedef struct QEMUFIFO {
61 uint8_t *buf;
62 int buf_size;
63 int count, wptr, rptr;
64} QEMUFIFO;
65
pbrook9596ebb2007-11-18 01:44:38 +000066static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
bellarde15d7372006-06-25 16:26:29 +000067{
68 int l, len;
69
70 l = f->buf_size - f->count;
71 if (len1 > l)
72 len1 = l;
73 len = len1;
74 while (len > 0) {
75 l = f->buf_size - f->wptr;
76 if (l > len)
77 l = len;
78 memcpy(f->buf + f->wptr, buf, l);
79 f->wptr += l;
80 if (f->wptr >= f->buf_size)
81 f->wptr = 0;
82 buf += l;
83 len -= l;
84 }
85 f->count += len1;
86 return len1;
87}
88
pbrook9596ebb2007-11-18 01:44:38 +000089static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
bellarde15d7372006-06-25 16:26:29 +000090{
91 int l, len;
92
93 if (len1 > f->count)
94 len1 = f->count;
95 len = len1;
96 while (len > 0) {
97 l = f->buf_size - f->rptr;
98 if (l > len)
99 l = len;
100 memcpy(buf, f->buf + f->rptr, l);
101 f->rptr += l;
102 if (f->rptr >= f->buf_size)
103 f->rptr = 0;
104 buf += l;
105 len -= l;
106 }
107 f->count -= len1;
108 return len1;
109}
110
thsaf3a9032007-07-11 23:14:59 +0000111typedef enum {
112 GRAPHIC_CONSOLE,
balrogc21bbcf2008-09-24 03:32:33 +0000113 TEXT_CONSOLE,
114 TEXT_CONSOLE_FIXED_SIZE
Anthony Liguoric227f092009-10-01 16:12:16 -0500115} console_type_t;
thsaf3a9032007-07-11 23:14:59 +0000116
pbrook95219892006-04-09 01:06:34 +0000117/* ??? This is mis-named.
118 It is used for both text and graphical consoles. */
bellarde7f0ad52004-07-14 17:28:59 +0000119struct TextConsole {
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200120 int index;
Anthony Liguoric227f092009-10-01 16:12:16 -0500121 console_type_t console_type;
bellarde7f0ad52004-07-14 17:28:59 +0000122 DisplayState *ds;
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;
129
bellarde7f0ad52004-07-14 17:28:59 +0000130 int g_width, g_height;
131 int width;
132 int height;
133 int total_height;
134 int backscroll_height;
bellarde7f0ad52004-07-14 17:28:59 +0000135 int x, y;
thsadb47962007-01-16 23:02:36 +0000136 int x_saved, y_saved;
bellarde7f0ad52004-07-14 17:28:59 +0000137 int y_displayed;
138 int y_base;
pbrook6d6f7c22006-03-11 15:35:30 +0000139 TextAttributes t_attrib_default; /* default text attributes */
140 TextAttributes t_attrib; /* currently active text attributes */
bellarde7f0ad52004-07-14 17:28:59 +0000141 TextCell *cells;
balrog4d3b6f62008-02-10 16:33:14 +0000142 int text_x[2], text_y[2], cursor_invalidate;
Paolo Bonzini41048332010-12-23 13:42:52 +0100143 int echo;
Jan Kiszkabf1bed82012-07-10 22:00:55 +0200144 bool cursor_visible_phase;
145 QEMUTimer *cursor_timer;
bellarde7f0ad52004-07-14 17:28:59 +0000146
pbrook14778c22009-01-21 03:02:52 +0000147 int update_x0;
148 int update_y0;
149 int update_x1;
150 int update_y1;
151
bellarde7f0ad52004-07-14 17:28:59 +0000152 enum TTYState state;
153 int esc_params[MAX_ESC_PARAMS];
154 int nb_esc_params;
155
pbrooke5b0bc42007-01-27 23:46:43 +0000156 CharDriverState *chr;
bellarde15d7372006-06-25 16:26:29 +0000157 /* fifo for key pressed */
158 QEMUFIFO out_fifo;
159 uint8_t out_fifo_buf[16];
160 QEMUTimer *kbd_timer;
bellarde7f0ad52004-07-14 17:28:59 +0000161};
162
Paolo Bonzini98b50082010-02-11 00:29:57 +0100163static DisplayState *display_state;
bellarde7f0ad52004-07-14 17:28:59 +0000164static TextConsole *active_console;
165static TextConsole *consoles[MAX_CONSOLES];
166static int nb_consoles = 0;
167
pbrook95219892006-04-09 01:06:34 +0000168void vga_hw_update(void)
169{
thsadb47962007-01-16 23:02:36 +0000170 if (active_console && active_console->hw_update)
pbrook95219892006-04-09 01:06:34 +0000171 active_console->hw_update(active_console->hw);
172}
173
174void vga_hw_invalidate(void)
175{
Gerd Hoffmann26572b82010-05-20 15:23:06 +0200176 if (active_console && active_console->hw_invalidate)
pbrook95219892006-04-09 01:06:34 +0000177 active_console->hw_invalidate(active_console->hw);
178}
179
Luiz Capitulinoad39cf62012-05-24 13:48:23 -0300180void qmp_screendump(const char *filename, Error **errp)
pbrook95219892006-04-09 01:06:34 +0000181{
balrog8571c052008-07-19 13:04:26 +0000182 TextConsole *previous_active_console;
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100183 bool cswitch;
balrog8571c052008-07-19 13:04:26 +0000184
185 previous_active_console = active_console;
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100186 cswitch = previous_active_console && previous_active_console->index != 0;
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200187
balrog8571c052008-07-19 13:04:26 +0000188 /* There is currently no way of specifying which screen we want to dump,
aurel327b455222008-09-02 00:09:16 +0000189 so always dump the first one. */
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100190 if (cswitch) {
191 console_select(0);
192 }
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200193 if (consoles[0] && consoles[0]->hw_screen_dump) {
Luiz Capitulinoad39cf62012-05-24 13:48:23 -0300194 consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch, errp);
Gerd Hoffmann16735102012-02-24 12:43:44 +0100195 } else {
Luiz Capitulinoad39cf62012-05-24 13:48:23 -0300196 error_setg(errp, "device doesn't support screendump\n");
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200197 }
198
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100199 if (cswitch) {
Alexander Graf33bcd982011-11-18 16:41:59 +0100200 console_select(previous_active_console->index);
201 }
pbrook95219892006-04-09 01:06:34 +0000202}
203
Anthony Liguoric227f092009-10-01 16:12:16 -0500204void vga_hw_text_update(console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +0000205{
206 if (active_console && active_console->hw_text_update)
207 active_console->hw_text_update(active_console->hw, chardata);
208}
209
bellarde7f0ad52004-07-14 17:28:59 +0000210/* convert a RGBA color to a color index usable in graphic primitives */
211static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
212{
213 unsigned int r, g, b, color;
214
aliguori0e1f5a02008-11-24 19:29:13 +0000215 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000216#if 0
217 case 8:
218 r = (rgba >> 16) & 0xff;
219 g = (rgba >> 8) & 0xff;
220 b = (rgba) & 0xff;
ths5fafdf22007-09-16 21:08:06 +0000221 color = (rgb_to_index[r] * 6 * 6) +
222 (rgb_to_index[g] * 6) +
bellarde7f0ad52004-07-14 17:28:59 +0000223 (rgb_to_index[b]);
224 break;
225#endif
226 case 15:
227 r = (rgba >> 16) & 0xff;
228 g = (rgba >> 8) & 0xff;
229 b = (rgba) & 0xff;
230 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
231 break;
232 case 16:
233 r = (rgba >> 16) & 0xff;
234 g = (rgba >> 8) & 0xff;
235 b = (rgba) & 0xff;
236 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
237 break;
238 case 32:
239 default:
240 color = rgba;
241 break;
242 }
243 return color;
244}
245
ths5fafdf22007-09-16 21:08:06 +0000246static void vga_fill_rect (DisplayState *ds,
bellarde7f0ad52004-07-14 17:28:59 +0000247 int posx, int posy, int width, int height, uint32_t color)
248{
249 uint8_t *d, *d1;
250 int x, y, bpp;
ths3b46e622007-09-17 08:09:54 +0000251
aliguori0e1f5a02008-11-24 19:29:13 +0000252 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
253 d1 = ds_get_data(ds) +
254 ds_get_linesize(ds) * posy + bpp * posx;
bellarde7f0ad52004-07-14 17:28:59 +0000255 for (y = 0; y < height; y++) {
256 d = d1;
257 switch(bpp) {
258 case 1:
259 for (x = 0; x < width; x++) {
260 *((uint8_t *)d) = color;
261 d++;
262 }
263 break;
264 case 2:
265 for (x = 0; x < width; x++) {
266 *((uint16_t *)d) = color;
267 d += 2;
268 }
269 break;
270 case 4:
271 for (x = 0; x < width; x++) {
272 *((uint32_t *)d) = color;
273 d += 4;
274 }
275 break;
276 }
aliguori0e1f5a02008-11-24 19:29:13 +0000277 d1 += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000278 }
279}
280
281/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
282static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
283{
284 const uint8_t *s;
285 uint8_t *d;
286 int wb, y, bpp;
287
aliguori0e1f5a02008-11-24 19:29:13 +0000288 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
bellarde7f0ad52004-07-14 17:28:59 +0000289 wb = w * bpp;
290 if (yd <= ys) {
aliguori0e1f5a02008-11-24 19:29:13 +0000291 s = ds_get_data(ds) +
292 ds_get_linesize(ds) * ys + bpp * xs;
293 d = ds_get_data(ds) +
294 ds_get_linesize(ds) * yd + bpp * xd;
bellarde7f0ad52004-07-14 17:28:59 +0000295 for (y = 0; y < h; y++) {
296 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000297 d += ds_get_linesize(ds);
298 s += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000299 }
300 } else {
aliguori0e1f5a02008-11-24 19:29:13 +0000301 s = ds_get_data(ds) +
302 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
303 d = ds_get_data(ds) +
304 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
bellarde7f0ad52004-07-14 17:28:59 +0000305 for (y = 0; y < h; y++) {
306 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000307 d -= ds_get_linesize(ds);
308 s -= ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000309 }
310 }
311}
312
313/***********************************************************/
314/* basic char display */
315
316#define FONT_HEIGHT 16
317#define FONT_WIDTH 8
318
319#include "vgafont.h"
320
321#define cbswap_32(__x) \
322((uint32_t)( \
323 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
324 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
325 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
326 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
327
Juan Quintelae2542fe2009-07-27 16:13:06 +0200328#ifdef HOST_WORDS_BIGENDIAN
bellarde7f0ad52004-07-14 17:28:59 +0000329#define PAT(x) x
330#else
331#define PAT(x) cbswap_32(x)
332#endif
333
334static const uint32_t dmask16[16] = {
335 PAT(0x00000000),
336 PAT(0x000000ff),
337 PAT(0x0000ff00),
338 PAT(0x0000ffff),
339 PAT(0x00ff0000),
340 PAT(0x00ff00ff),
341 PAT(0x00ffff00),
342 PAT(0x00ffffff),
343 PAT(0xff000000),
344 PAT(0xff0000ff),
345 PAT(0xff00ff00),
346 PAT(0xff00ffff),
347 PAT(0xffff0000),
348 PAT(0xffff00ff),
349 PAT(0xffffff00),
350 PAT(0xffffffff),
351};
352
353static const uint32_t dmask4[4] = {
354 PAT(0x00000000),
355 PAT(0x0000ffff),
356 PAT(0xffff0000),
357 PAT(0xffffffff),
358};
359
pbrook6d6f7c22006-03-11 15:35:30 +0000360static uint32_t color_table[2][8];
bellarde7f0ad52004-07-14 17:28:59 +0000361
Devin J. Pohlydf00bed2011-09-07 15:44:36 -0400362#ifndef CONFIG_CURSES
pbrook6d6f7c22006-03-11 15:35:30 +0000363enum color_names {
364 COLOR_BLACK = 0,
365 COLOR_RED = 1,
366 COLOR_GREEN = 2,
367 COLOR_YELLOW = 3,
368 COLOR_BLUE = 4,
369 COLOR_MAGENTA = 5,
370 COLOR_CYAN = 6,
371 COLOR_WHITE = 7
372};
Devin J. Pohlydf00bed2011-09-07 15:44:36 -0400373#endif
pbrook6d6f7c22006-03-11 15:35:30 +0000374
375static const uint32_t color_table_rgb[2][8] = {
376 { /* dark */
bellard26489842006-06-25 17:37:36 +0000377 QEMU_RGB(0x00, 0x00, 0x00), /* black */
378 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
379 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
380 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
381 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
382 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
383 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
384 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000385 },
386 { /* bright */
bellard26489842006-06-25 17:37:36 +0000387 QEMU_RGB(0x00, 0x00, 0x00), /* black */
388 QEMU_RGB(0xff, 0x00, 0x00), /* red */
389 QEMU_RGB(0x00, 0xff, 0x00), /* green */
390 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
391 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
392 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
393 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
394 QEMU_RGB(0xff, 0xff, 0xff), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000395 }
bellarde7f0ad52004-07-14 17:28:59 +0000396};
397
398static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
399{
aliguori0e1f5a02008-11-24 19:29:13 +0000400 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000401 case 8:
402 col |= col << 8;
403 col |= col << 16;
404 break;
405 case 15:
406 case 16:
407 col |= col << 16;
408 break;
409 default:
410 break;
411 }
412
413 return col;
414}
pbrook6d6f7c22006-03-11 15:35:30 +0000415#ifdef DEBUG_CONSOLE
416static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
417{
418 if (t_attrib->bold) {
419 printf("b");
420 } else {
421 printf(" ");
422 }
423 if (t_attrib->uline) {
424 printf("u");
425 } else {
426 printf(" ");
427 }
428 if (t_attrib->blink) {
429 printf("l");
430 } else {
431 printf(" ");
432 }
433 if (t_attrib->invers) {
434 printf("i");
435 } else {
436 printf(" ");
437 }
438 if (t_attrib->unvisible) {
439 printf("n");
440 } else {
441 printf(" ");
442 }
443
444 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
445}
446#endif
bellarde7f0ad52004-07-14 17:28:59 +0000447
ths5fafdf22007-09-16 21:08:06 +0000448static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000449 TextAttributes *t_attrib)
bellarde7f0ad52004-07-14 17:28:59 +0000450{
451 uint8_t *d;
452 const uint8_t *font_ptr;
453 unsigned int font_data, linesize, xorcol, bpp;
454 int i;
pbrook6d6f7c22006-03-11 15:35:30 +0000455 unsigned int fgcol, bgcol;
456
457#ifdef DEBUG_CONSOLE
458 printf("x: %2i y: %2i", x, y);
459 console_print_text_attributes(t_attrib, ch);
460#endif
461
462 if (t_attrib->invers) {
463 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
464 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
465 } else {
466 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
467 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
468 }
bellarde7f0ad52004-07-14 17:28:59 +0000469
aliguori0e1f5a02008-11-24 19:29:13 +0000470 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
471 d = ds_get_data(ds) +
472 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
473 linesize = ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000474 font_ptr = vgafont16 + FONT_HEIGHT * ch;
475 xorcol = bgcol ^ fgcol;
aliguori0e1f5a02008-11-24 19:29:13 +0000476 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000477 case 8:
478 for(i = 0; i < FONT_HEIGHT; i++) {
479 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000480 if (t_attrib->uline
481 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100482 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000483 }
bellarde7f0ad52004-07-14 17:28:59 +0000484 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
485 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
486 d += linesize;
487 }
488 break;
489 case 16:
490 case 15:
491 for(i = 0; i < FONT_HEIGHT; i++) {
492 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000493 if (t_attrib->uline
494 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100495 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000496 }
bellarde7f0ad52004-07-14 17:28:59 +0000497 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
498 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
499 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
500 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
501 d += linesize;
502 }
503 break;
504 case 32:
505 for(i = 0; i < FONT_HEIGHT; i++) {
506 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000507 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100508 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000509 }
bellarde7f0ad52004-07-14 17:28:59 +0000510 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
511 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
512 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
513 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
514 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
515 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
516 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
517 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
518 d += linesize;
519 }
520 break;
521 }
522}
523
524static void text_console_resize(TextConsole *s)
525{
526 TextCell *cells, *c, *c1;
527 int w1, x, y, last_width;
528
529 last_width = s->width;
530 s->width = s->g_width / FONT_WIDTH;
531 s->height = s->g_height / FONT_HEIGHT;
532
533 w1 = last_width;
534 if (s->width < w1)
535 w1 = s->width;
536
Anthony Liguori7267c092011-08-20 22:09:37 -0500537 cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
bellarde7f0ad52004-07-14 17:28:59 +0000538 for(y = 0; y < s->total_height; y++) {
539 c = &cells[y * s->width];
540 if (w1 > 0) {
541 c1 = &s->cells[y * last_width];
542 for(x = 0; x < w1; x++) {
543 *c++ = *c1++;
544 }
545 }
546 for(x = w1; x < s->width; x++) {
547 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000548 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000549 c++;
550 }
551 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500552 g_free(s->cells);
bellarde7f0ad52004-07-14 17:28:59 +0000553 s->cells = cells;
554}
555
balrog4d3b6f62008-02-10 16:33:14 +0000556static inline void text_update_xy(TextConsole *s, int x, int y)
557{
558 s->text_x[0] = MIN(s->text_x[0], x);
559 s->text_x[1] = MAX(s->text_x[1], x);
560 s->text_y[0] = MIN(s->text_y[0], y);
561 s->text_y[1] = MAX(s->text_y[1], y);
562}
563
pbrook14778c22009-01-21 03:02:52 +0000564static void invalidate_xy(TextConsole *s, int x, int y)
565{
566 if (s->update_x0 > x * FONT_WIDTH)
567 s->update_x0 = x * FONT_WIDTH;
568 if (s->update_y0 > y * FONT_HEIGHT)
569 s->update_y0 = y * FONT_HEIGHT;
570 if (s->update_x1 < (x + 1) * FONT_WIDTH)
571 s->update_x1 = (x + 1) * FONT_WIDTH;
572 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
573 s->update_y1 = (y + 1) * FONT_HEIGHT;
574}
575
bellarde7f0ad52004-07-14 17:28:59 +0000576static void update_xy(TextConsole *s, int x, int y)
577{
578 TextCell *c;
579 int y1, y2;
580
581 if (s == active_console) {
aliguori0e1f5a02008-11-24 19:29:13 +0000582 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000583 text_update_xy(s, x, y);
584 return;
585 }
586
bellarde7f0ad52004-07-14 17:28:59 +0000587 y1 = (s->y_base + y) % s->total_height;
588 y2 = y1 - s->y_displayed;
589 if (y2 < 0)
590 y2 += s->total_height;
591 if (y2 < s->height) {
592 c = &s->cells[y1 * s->width + x];
ths5fafdf22007-09-16 21:08:06 +0000593 vga_putcharxy(s->ds, x, y2, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000594 &(c->t_attrib));
pbrook14778c22009-01-21 03:02:52 +0000595 invalidate_xy(s, x, y2);
bellarde7f0ad52004-07-14 17:28:59 +0000596 }
597 }
598}
599
600static void console_show_cursor(TextConsole *s, int show)
601{
602 TextCell *c;
603 int y, y1;
604
605 if (s == active_console) {
thsed8276a2007-02-10 22:37:56 +0000606 int x = s->x;
balrog4d3b6f62008-02-10 16:33:14 +0000607
aliguori0e1f5a02008-11-24 19:29:13 +0000608 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000609 s->cursor_invalidate = 1;
610 return;
611 }
612
thsed8276a2007-02-10 22:37:56 +0000613 if (x >= s->width) {
614 x = s->width - 1;
615 }
bellarde7f0ad52004-07-14 17:28:59 +0000616 y1 = (s->y_base + s->y) % s->total_height;
617 y = y1 - s->y_displayed;
618 if (y < 0)
619 y += s->total_height;
620 if (y < s->height) {
thsed8276a2007-02-10 22:37:56 +0000621 c = &s->cells[y1 * s->width + x];
Jan Kiszkabf1bed82012-07-10 22:00:55 +0200622 if (show && s->cursor_visible_phase) {
pbrook6d6f7c22006-03-11 15:35:30 +0000623 TextAttributes t_attrib = s->t_attrib_default;
624 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
thsed8276a2007-02-10 22:37:56 +0000625 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
bellarde7f0ad52004-07-14 17:28:59 +0000626 } else {
thsed8276a2007-02-10 22:37:56 +0000627 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000628 }
pbrook14778c22009-01-21 03:02:52 +0000629 invalidate_xy(s, x, y);
bellarde7f0ad52004-07-14 17:28:59 +0000630 }
631 }
632}
633
634static void console_refresh(TextConsole *s)
635{
636 TextCell *c;
637 int x, y, y1;
638
ths5fafdf22007-09-16 21:08:06 +0000639 if (s != active_console)
bellarde7f0ad52004-07-14 17:28:59 +0000640 return;
aliguori0e1f5a02008-11-24 19:29:13 +0000641 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000642 s->text_x[0] = 0;
643 s->text_y[0] = 0;
644 s->text_x[1] = s->width - 1;
645 s->text_y[1] = s->height - 1;
646 s->cursor_invalidate = 1;
647 return;
648 }
bellarde7f0ad52004-07-14 17:28:59 +0000649
aliguori0e1f5a02008-11-24 19:29:13 +0000650 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
pbrook6d6f7c22006-03-11 15:35:30 +0000651 color_table[0][COLOR_BLACK]);
bellarde7f0ad52004-07-14 17:28:59 +0000652 y1 = s->y_displayed;
653 for(y = 0; y < s->height; y++) {
654 c = s->cells + y1 * s->width;
655 for(x = 0; x < s->width; x++) {
ths5fafdf22007-09-16 21:08:06 +0000656 vga_putcharxy(s->ds, x, y, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000657 &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000658 c++;
659 }
660 if (++y1 == s->total_height)
661 y1 = 0;
662 }
bellarde7f0ad52004-07-14 17:28:59 +0000663 console_show_cursor(s, 1);
pbrook14778c22009-01-21 03:02:52 +0000664 dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
bellarde7f0ad52004-07-14 17:28:59 +0000665}
666
667static void console_scroll(int ydelta)
668{
669 TextConsole *s;
670 int i, y1;
ths3b46e622007-09-17 08:09:54 +0000671
bellarde7f0ad52004-07-14 17:28:59 +0000672 s = active_console;
thsaf3a9032007-07-11 23:14:59 +0000673 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +0000674 return;
675
676 if (ydelta > 0) {
677 for(i = 0; i < ydelta; i++) {
678 if (s->y_displayed == s->y_base)
679 break;
680 if (++s->y_displayed == s->total_height)
681 s->y_displayed = 0;
682 }
683 } else {
684 ydelta = -ydelta;
685 i = s->backscroll_height;
686 if (i > s->total_height - s->height)
687 i = s->total_height - s->height;
688 y1 = s->y_base - i;
689 if (y1 < 0)
690 y1 += s->total_height;
691 for(i = 0; i < ydelta; i++) {
692 if (s->y_displayed == y1)
693 break;
694 if (--s->y_displayed < 0)
695 s->y_displayed = s->total_height - 1;
696 }
697 }
698 console_refresh(s);
699}
700
701static void console_put_lf(TextConsole *s)
702{
703 TextCell *c;
704 int x, y1;
705
bellarde7f0ad52004-07-14 17:28:59 +0000706 s->y++;
707 if (s->y >= s->height) {
708 s->y = s->height - 1;
pbrook6d6f7c22006-03-11 15:35:30 +0000709
bellarde7f0ad52004-07-14 17:28:59 +0000710 if (s->y_displayed == s->y_base) {
711 if (++s->y_displayed == s->total_height)
712 s->y_displayed = 0;
713 }
714 if (++s->y_base == s->total_height)
715 s->y_base = 0;
716 if (s->backscroll_height < s->total_height)
717 s->backscroll_height++;
718 y1 = (s->y_base + s->height - 1) % s->total_height;
719 c = &s->cells[y1 * s->width];
720 for(x = 0; x < s->width; x++) {
721 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000722 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000723 c++;
724 }
725 if (s == active_console && s->y_displayed == s->y_base) {
aliguori0e1f5a02008-11-24 19:29:13 +0000726 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000727 s->text_x[0] = 0;
728 s->text_y[0] = 0;
729 s->text_x[1] = s->width - 1;
730 s->text_y[1] = s->height - 1;
731 return;
732 }
733
ths5fafdf22007-09-16 21:08:06 +0000734 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
735 s->width * FONT_WIDTH,
bellarde7f0ad52004-07-14 17:28:59 +0000736 (s->height - 1) * FONT_HEIGHT);
737 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
ths5fafdf22007-09-16 21:08:06 +0000738 s->width * FONT_WIDTH, FONT_HEIGHT,
pbrook6d6f7c22006-03-11 15:35:30 +0000739 color_table[0][s->t_attrib_default.bgcol]);
pbrook14778c22009-01-21 03:02:52 +0000740 s->update_x0 = 0;
741 s->update_y0 = 0;
742 s->update_x1 = s->width * FONT_WIDTH;
743 s->update_y1 = s->height * FONT_HEIGHT;
bellarde7f0ad52004-07-14 17:28:59 +0000744 }
745 }
746}
747
pbrook6d6f7c22006-03-11 15:35:30 +0000748/* Set console attributes depending on the current escape codes.
749 * NOTE: I know this code is not very efficient (checking every color for it
750 * self) but it is more readable and better maintainable.
751 */
752static void console_handle_escape(TextConsole *s)
753{
754 int i;
755
pbrook6d6f7c22006-03-11 15:35:30 +0000756 for (i=0; i<s->nb_esc_params; i++) {
757 switch (s->esc_params[i]) {
758 case 0: /* reset all console attributes to default */
759 s->t_attrib = s->t_attrib_default;
760 break;
761 case 1:
762 s->t_attrib.bold = 1;
763 break;
764 case 4:
765 s->t_attrib.uline = 1;
766 break;
767 case 5:
768 s->t_attrib.blink = 1;
769 break;
770 case 7:
771 s->t_attrib.invers = 1;
772 break;
773 case 8:
774 s->t_attrib.unvisible = 1;
775 break;
776 case 22:
777 s->t_attrib.bold = 0;
778 break;
779 case 24:
780 s->t_attrib.uline = 0;
781 break;
782 case 25:
783 s->t_attrib.blink = 0;
784 break;
785 case 27:
786 s->t_attrib.invers = 0;
787 break;
788 case 28:
789 s->t_attrib.unvisible = 0;
790 break;
791 /* set foreground color */
792 case 30:
793 s->t_attrib.fgcol=COLOR_BLACK;
794 break;
795 case 31:
796 s->t_attrib.fgcol=COLOR_RED;
797 break;
798 case 32:
799 s->t_attrib.fgcol=COLOR_GREEN;
800 break;
801 case 33:
802 s->t_attrib.fgcol=COLOR_YELLOW;
803 break;
804 case 34:
805 s->t_attrib.fgcol=COLOR_BLUE;
806 break;
807 case 35:
808 s->t_attrib.fgcol=COLOR_MAGENTA;
809 break;
810 case 36:
811 s->t_attrib.fgcol=COLOR_CYAN;
812 break;
813 case 37:
814 s->t_attrib.fgcol=COLOR_WHITE;
815 break;
816 /* set background color */
817 case 40:
818 s->t_attrib.bgcol=COLOR_BLACK;
819 break;
820 case 41:
821 s->t_attrib.bgcol=COLOR_RED;
822 break;
823 case 42:
824 s->t_attrib.bgcol=COLOR_GREEN;
825 break;
826 case 43:
827 s->t_attrib.bgcol=COLOR_YELLOW;
828 break;
829 case 44:
830 s->t_attrib.bgcol=COLOR_BLUE;
831 break;
832 case 45:
833 s->t_attrib.bgcol=COLOR_MAGENTA;
834 break;
835 case 46:
836 s->t_attrib.bgcol=COLOR_CYAN;
837 break;
838 case 47:
839 s->t_attrib.bgcol=COLOR_WHITE;
840 break;
841 }
842 }
843}
844
thsadb47962007-01-16 23:02:36 +0000845static void console_clear_xy(TextConsole *s, int x, int y)
846{
847 int y1 = (s->y_base + y) % s->total_height;
848 TextCell *c = &s->cells[y1 * s->width + x];
849 c->ch = ' ';
850 c->t_attrib = s->t_attrib_default;
thsadb47962007-01-16 23:02:36 +0000851 update_xy(s, x, y);
852}
853
Ian Campbell3eea5492012-09-04 10:26:09 -0500854/* set cursor, checking bounds */
855static void set_cursor(TextConsole *s, int x, int y)
856{
857 if (x < 0) {
858 x = 0;
859 }
860 if (y < 0) {
861 y = 0;
862 }
863 if (y >= s->height) {
864 y = s->height - 1;
865 }
866 if (x >= s->width) {
867 x = s->width - 1;
868 }
869
870 s->x = x;
871 s->y = y;
872}
873
bellarde7f0ad52004-07-14 17:28:59 +0000874static void console_putchar(TextConsole *s, int ch)
875{
876 TextCell *c;
thsadb47962007-01-16 23:02:36 +0000877 int y1, i;
878 int x, y;
bellarde7f0ad52004-07-14 17:28:59 +0000879
880 switch(s->state) {
881 case TTY_STATE_NORM:
882 switch(ch) {
pbrook6d6f7c22006-03-11 15:35:30 +0000883 case '\r': /* carriage return */
bellarde7f0ad52004-07-14 17:28:59 +0000884 s->x = 0;
885 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000886 case '\n': /* newline */
bellarde7f0ad52004-07-14 17:28:59 +0000887 console_put_lf(s);
888 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000889 case '\b': /* backspace */
ths5fafdf22007-09-16 21:08:06 +0000890 if (s->x > 0)
bellarde15d7372006-06-25 16:26:29 +0000891 s->x--;
pbrook6d6f7c22006-03-11 15:35:30 +0000892 break;
893 case '\t': /* tabspace */
894 if (s->x + (8 - (s->x % 8)) > s->width) {
bellardbd468842006-07-14 20:24:31 +0000895 s->x = 0;
pbrook6d6f7c22006-03-11 15:35:30 +0000896 console_put_lf(s);
897 } else {
898 s->x = s->x + (8 - (s->x % 8));
899 }
900 break;
901 case '\a': /* alert aka. bell */
902 /* TODO: has to be implemented */
903 break;
thsadb47962007-01-16 23:02:36 +0000904 case 14:
905 /* SI (shift in), character set 0 (ignored) */
906 break;
907 case 15:
908 /* SO (shift out), character set 1 (ignored) */
909 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000910 case 27: /* esc (introducing an escape sequence) */
bellarde7f0ad52004-07-14 17:28:59 +0000911 s->state = TTY_STATE_ESC;
912 break;
913 default:
thsed8276a2007-02-10 22:37:56 +0000914 if (s->x >= s->width) {
915 /* line wrap */
916 s->x = 0;
917 console_put_lf(s);
thsadb47962007-01-16 23:02:36 +0000918 }
bellarde7f0ad52004-07-14 17:28:59 +0000919 y1 = (s->y_base + s->y) % s->total_height;
920 c = &s->cells[y1 * s->width + s->x];
921 c->ch = ch;
pbrook6d6f7c22006-03-11 15:35:30 +0000922 c->t_attrib = s->t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +0000923 update_xy(s, s->x, s->y);
924 s->x++;
bellarde7f0ad52004-07-14 17:28:59 +0000925 break;
926 }
927 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000928 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
bellarde7f0ad52004-07-14 17:28:59 +0000929 if (ch == '[') {
930 for(i=0;i<MAX_ESC_PARAMS;i++)
931 s->esc_params[i] = 0;
932 s->nb_esc_params = 0;
933 s->state = TTY_STATE_CSI;
934 } else {
935 s->state = TTY_STATE_NORM;
936 }
937 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000938 case TTY_STATE_CSI: /* handle escape sequence parameters */
bellarde7f0ad52004-07-14 17:28:59 +0000939 if (ch >= '0' && ch <= '9') {
940 if (s->nb_esc_params < MAX_ESC_PARAMS) {
Laszlo Ersekc10600a2012-09-17 11:10:03 +0200941 int *param = &s->esc_params[s->nb_esc_params];
942 int digit = (ch - '0');
943
944 *param = (*param <= (INT_MAX - digit) / 10) ?
945 *param * 10 + digit : INT_MAX;
bellarde7f0ad52004-07-14 17:28:59 +0000946 }
947 } else {
Ian Campbell3eea5492012-09-04 10:26:09 -0500948 if (s->nb_esc_params < MAX_ESC_PARAMS)
949 s->nb_esc_params++;
bellarde7f0ad52004-07-14 17:28:59 +0000950 if (ch == ';')
951 break;
thsadb47962007-01-16 23:02:36 +0000952#ifdef DEBUG_CONSOLE
953 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
954 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
955#endif
bellarde7f0ad52004-07-14 17:28:59 +0000956 s->state = TTY_STATE_NORM;
957 switch(ch) {
thsadb47962007-01-16 23:02:36 +0000958 case 'A':
959 /* move cursor up */
960 if (s->esc_params[0] == 0) {
961 s->esc_params[0] = 1;
962 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500963 set_cursor(s, s->x, s->y - s->esc_params[0]);
bellarde7f0ad52004-07-14 17:28:59 +0000964 break;
thsadb47962007-01-16 23:02:36 +0000965 case 'B':
966 /* move cursor down */
967 if (s->esc_params[0] == 0) {
968 s->esc_params[0] = 1;
969 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500970 set_cursor(s, s->x, s->y + s->esc_params[0]);
thsadb47962007-01-16 23:02:36 +0000971 break;
972 case 'C':
973 /* move cursor right */
974 if (s->esc_params[0] == 0) {
975 s->esc_params[0] = 1;
976 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500977 set_cursor(s, s->x + s->esc_params[0], s->y);
thsadb47962007-01-16 23:02:36 +0000978 break;
979 case 'D':
980 /* move cursor left */
981 if (s->esc_params[0] == 0) {
982 s->esc_params[0] = 1;
983 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500984 set_cursor(s, s->x - s->esc_params[0], s->y);
thsadb47962007-01-16 23:02:36 +0000985 break;
986 case 'G':
987 /* move cursor to column */
Ian Campbell3eea5492012-09-04 10:26:09 -0500988 set_cursor(s, s->esc_params[0] - 1, s->y);
thsadb47962007-01-16 23:02:36 +0000989 break;
990 case 'f':
991 case 'H':
992 /* move cursor to row, column */
Ian Campbell3eea5492012-09-04 10:26:09 -0500993 set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
thsadb47962007-01-16 23:02:36 +0000994 break;
995 case 'J':
996 switch (s->esc_params[0]) {
997 case 0:
998 /* clear to end of screen */
999 for (y = s->y; y < s->height; y++) {
1000 for (x = 0; x < s->width; x++) {
1001 if (y == s->y && x < s->x) {
1002 continue;
1003 }
1004 console_clear_xy(s, x, y);
1005 }
1006 }
1007 break;
1008 case 1:
1009 /* clear from beginning of screen */
1010 for (y = 0; y <= s->y; y++) {
1011 for (x = 0; x < s->width; x++) {
1012 if (y == s->y && x > s->x) {
1013 break;
1014 }
1015 console_clear_xy(s, x, y);
1016 }
1017 }
1018 break;
1019 case 2:
1020 /* clear entire screen */
1021 for (y = 0; y <= s->height; y++) {
1022 for (x = 0; x < s->width; x++) {
1023 console_clear_xy(s, x, y);
1024 }
1025 }
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001026 break;
thsadb47962007-01-16 23:02:36 +00001027 }
Markus Armbruster95d8f9f2011-11-22 11:59:07 +01001028 break;
thsadb47962007-01-16 23:02:36 +00001029 case 'K':
1030 switch (s->esc_params[0]) {
1031 case 0:
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001032 /* clear to eol */
1033 for(x = s->x; x < s->width; x++) {
thsadb47962007-01-16 23:02:36 +00001034 console_clear_xy(s, x, s->y);
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001035 }
1036 break;
thsadb47962007-01-16 23:02:36 +00001037 case 1:
1038 /* clear from beginning of line */
1039 for (x = 0; x <= s->x; x++) {
1040 console_clear_xy(s, x, s->y);
1041 }
1042 break;
1043 case 2:
1044 /* clear entire line */
1045 for(x = 0; x < s->width; x++) {
1046 console_clear_xy(s, x, s->y);
1047 }
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001048 break;
1049 }
thsadb47962007-01-16 23:02:36 +00001050 break;
1051 case 'm':
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001052 console_handle_escape(s);
1053 break;
thsadb47962007-01-16 23:02:36 +00001054 case 'n':
1055 /* report cursor position */
1056 /* TODO: send ESC[row;colR */
1057 break;
1058 case 's':
1059 /* save cursor position */
1060 s->x_saved = s->x;
1061 s->y_saved = s->y;
1062 break;
1063 case 'u':
1064 /* restore cursor position */
1065 s->x = s->x_saved;
1066 s->y = s->y_saved;
1067 break;
1068 default:
1069#ifdef DEBUG_CONSOLE
1070 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1071#endif
1072 break;
1073 }
1074 break;
bellarde7f0ad52004-07-14 17:28:59 +00001075 }
1076 }
1077}
1078
1079void console_select(unsigned int index)
1080{
1081 TextConsole *s;
pbrook6d6f7c22006-03-11 15:35:30 +00001082
bellarde7f0ad52004-07-14 17:28:59 +00001083 if (index >= MAX_CONSOLES)
1084 return;
Stefan Hajnoczi358664c2010-09-20 14:11:19 +01001085 if (active_console) {
1086 active_console->g_width = ds_get_width(active_console->ds);
1087 active_console->g_height = ds_get_height(active_console->ds);
1088 }
bellarde7f0ad52004-07-14 17:28:59 +00001089 s = consoles[index];
1090 if (s) {
aliguori7d957bd2009-01-15 22:14:11 +00001091 DisplayState *ds = s->ds;
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001092
Stefan Weil8bd6b062012-08-17 15:50:44 +02001093 if (active_console && active_console->cursor_timer) {
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001094 qemu_del_timer(active_console->cursor_timer);
1095 }
bellarde7f0ad52004-07-14 17:28:59 +00001096 active_console = s;
aliguori68f00992009-01-21 18:59:12 +00001097 if (ds_get_bits_per_pixel(s->ds)) {
aliguori7b5d76d2009-03-13 15:02:13 +00001098 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
aliguori68f00992009-01-21 18:59:12 +00001099 } else {
1100 s->ds->surface->width = s->width;
1101 s->ds->surface->height = s->height;
1102 }
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001103 if (s->cursor_timer) {
1104 qemu_mod_timer(s->cursor_timer,
1105 qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1106 }
aliguori7d957bd2009-01-15 22:14:11 +00001107 dpy_resize(s->ds);
balrog4d3b6f62008-02-10 16:33:14 +00001108 vga_hw_invalidate();
bellarde7f0ad52004-07-14 17:28:59 +00001109 }
1110}
1111
1112static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1113{
1114 TextConsole *s = chr->opaque;
1115 int i;
1116
pbrook14778c22009-01-21 03:02:52 +00001117 s->update_x0 = s->width * FONT_WIDTH;
1118 s->update_y0 = s->height * FONT_HEIGHT;
1119 s->update_x1 = 0;
1120 s->update_y1 = 0;
bellarde7f0ad52004-07-14 17:28:59 +00001121 console_show_cursor(s, 0);
1122 for(i = 0; i < len; i++) {
1123 console_putchar(s, buf[i]);
1124 }
1125 console_show_cursor(s, 1);
pbrook14778c22009-01-21 03:02:52 +00001126 if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1127 dpy_update(s->ds, s->update_x0, s->update_y0,
1128 s->update_x1 - s->update_x0,
1129 s->update_y1 - s->update_y0);
1130 }
bellarde7f0ad52004-07-14 17:28:59 +00001131 return len;
1132}
1133
bellarde15d7372006-06-25 16:26:29 +00001134static void kbd_send_chars(void *opaque)
1135{
1136 TextConsole *s = opaque;
1137 int len;
1138 uint8_t buf[16];
ths3b46e622007-09-17 08:09:54 +00001139
Anthony Liguori909cda12011-08-15 11:17:31 -05001140 len = qemu_chr_be_can_write(s->chr);
bellarde15d7372006-06-25 16:26:29 +00001141 if (len > s->out_fifo.count)
1142 len = s->out_fifo.count;
1143 if (len > 0) {
1144 if (len > sizeof(buf))
1145 len = sizeof(buf);
1146 qemu_fifo_read(&s->out_fifo, buf, len);
Anthony Liguorifa5efcc2011-08-15 11:17:30 -05001147 qemu_chr_be_write(s->chr, buf, len);
bellarde15d7372006-06-25 16:26:29 +00001148 }
1149 /* characters are pending: we send them a bit later (XXX:
1150 horrible, should change char device API) */
1151 if (s->out_fifo.count > 0) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001152 qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
bellarde15d7372006-06-25 16:26:29 +00001153 }
1154}
1155
bellarde7f0ad52004-07-14 17:28:59 +00001156/* called when an ascii key is pressed */
1157void kbd_put_keysym(int keysym)
1158{
1159 TextConsole *s;
1160 uint8_t buf[16], *q;
1161 int c;
1162
1163 s = active_console;
thsaf3a9032007-07-11 23:14:59 +00001164 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +00001165 return;
1166
1167 switch(keysym) {
1168 case QEMU_KEY_CTRL_UP:
1169 console_scroll(-1);
1170 break;
1171 case QEMU_KEY_CTRL_DOWN:
1172 console_scroll(1);
1173 break;
1174 case QEMU_KEY_CTRL_PAGEUP:
1175 console_scroll(-10);
1176 break;
1177 case QEMU_KEY_CTRL_PAGEDOWN:
1178 console_scroll(10);
1179 break;
1180 default:
bellarde15d7372006-06-25 16:26:29 +00001181 /* convert the QEMU keysym to VT100 key string */
1182 q = buf;
1183 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1184 *q++ = '\033';
1185 *q++ = '[';
1186 c = keysym - 0xe100;
1187 if (c >= 10)
1188 *q++ = '0' + (c / 10);
1189 *q++ = '0' + (c % 10);
1190 *q++ = '~';
1191 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1192 *q++ = '\033';
1193 *q++ = '[';
1194 *q++ = keysym & 0xff;
Paolo Bonzini41048332010-12-23 13:42:52 +01001195 } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1196 console_puts(s->chr, (const uint8_t *) "\r", 1);
1197 *q++ = '\n';
bellarde15d7372006-06-25 16:26:29 +00001198 } else {
Paolo Bonzini41048332010-12-23 13:42:52 +01001199 *q++ = keysym;
1200 }
1201 if (s->echo) {
1202 console_puts(s->chr, buf, q - buf);
bellarde15d7372006-06-25 16:26:29 +00001203 }
pbrooke5b0bc42007-01-27 23:46:43 +00001204 if (s->chr->chr_read) {
bellarde15d7372006-06-25 16:26:29 +00001205 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1206 kbd_send_chars(s);
bellarde7f0ad52004-07-14 17:28:59 +00001207 }
1208 break;
1209 }
1210}
1211
balrog4d3b6f62008-02-10 16:33:14 +00001212static void text_console_invalidate(void *opaque)
1213{
1214 TextConsole *s = (TextConsole *) opaque;
aliguori68f00992009-01-21 18:59:12 +00001215 if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1216 s->g_width = ds_get_width(s->ds);
1217 s->g_height = ds_get_height(s->ds);
1218 text_console_resize(s);
1219 }
balrog4d3b6f62008-02-10 16:33:14 +00001220 console_refresh(s);
1221}
1222
Anthony Liguoric227f092009-10-01 16:12:16 -05001223static void text_console_update(void *opaque, console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +00001224{
1225 TextConsole *s = (TextConsole *) opaque;
1226 int i, j, src;
1227
1228 if (s->text_x[0] <= s->text_x[1]) {
1229 src = (s->y_base + s->text_y[0]) * s->width;
1230 chardata += s->text_y[0] * s->width;
1231 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1232 for (j = 0; j < s->width; j ++, src ++)
1233 console_write_ch(chardata ++, s->cells[src].ch |
1234 (s->cells[src].t_attrib.fgcol << 12) |
1235 (s->cells[src].t_attrib.bgcol << 8) |
1236 (s->cells[src].t_attrib.bold << 21));
1237 dpy_update(s->ds, s->text_x[0], s->text_y[0],
1238 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1239 s->text_x[0] = s->width;
1240 s->text_y[0] = s->height;
1241 s->text_x[1] = 0;
1242 s->text_y[1] = 0;
1243 }
1244 if (s->cursor_invalidate) {
Gerd Hoffmannbf2fde72012-09-12 07:56:45 +02001245 dpy_text_cursor(s->ds, s->x, s->y);
balrog4d3b6f62008-02-10 16:33:14 +00001246 s->cursor_invalidate = 0;
1247 }
1248}
1249
aliguori42aa98e2009-01-16 21:01:48 +00001250static TextConsole *get_graphic_console(DisplayState *ds)
blueswir1a147d622009-01-16 19:41:04 +00001251{
aliguori3023f332009-01-16 19:04:14 +00001252 int i;
1253 TextConsole *s;
1254 for (i = 0; i < nb_consoles; i++) {
1255 s = consoles[i];
aliguori42aa98e2009-01-16 21:01:48 +00001256 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
aliguori3023f332009-01-16 19:04:14 +00001257 return s;
1258 }
1259 return NULL;
1260}
1261
Anthony Liguoric227f092009-10-01 16:12:16 -05001262static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
bellarde7f0ad52004-07-14 17:28:59 +00001263{
1264 TextConsole *s;
pbrook95219892006-04-09 01:06:34 +00001265 int i;
bellarde7f0ad52004-07-14 17:28:59 +00001266
1267 if (nb_consoles >= MAX_CONSOLES)
1268 return NULL;
Anthony Liguori7267c092011-08-20 22:09:37 -05001269 s = g_malloc0(sizeof(TextConsole));
thsaf3a9032007-07-11 23:14:59 +00001270 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1271 (console_type == GRAPHIC_CONSOLE))) {
bellarde7f0ad52004-07-14 17:28:59 +00001272 active_console = s;
thsaf3a9032007-07-11 23:14:59 +00001273 }
bellarde7f0ad52004-07-14 17:28:59 +00001274 s->ds = ds;
thsaf3a9032007-07-11 23:14:59 +00001275 s->console_type = console_type;
1276 if (console_type != GRAPHIC_CONSOLE) {
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001277 s->index = nb_consoles;
pbrook95219892006-04-09 01:06:34 +00001278 consoles[nb_consoles++] = s;
1279 } else {
1280 /* HACK: Put graphical consoles before text consoles. */
1281 for (i = nb_consoles; i > 0; i--) {
thsaf3a9032007-07-11 23:14:59 +00001282 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
pbrook95219892006-04-09 01:06:34 +00001283 break;
1284 consoles[i] = consoles[i - 1];
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001285 consoles[i]->index = i;
pbrook95219892006-04-09 01:06:34 +00001286 }
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001287 s->index = i;
pbrook95219892006-04-09 01:06:34 +00001288 consoles[i] = s;
aliguori3023f332009-01-16 19:04:14 +00001289 nb_consoles++;
pbrook95219892006-04-09 01:06:34 +00001290 }
bellarde7f0ad52004-07-14 17:28:59 +00001291 return s;
1292}
1293
Paolo Bonzini98b50082010-02-11 00:29:57 +01001294static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1295{
Anthony Liguori7267c092011-08-20 22:09:37 -05001296 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
Paolo Bonzini98b50082010-02-11 00:29:57 +01001297
Jes Sorensenffe8b822011-03-16 13:33:30 +01001298 int linesize = width * 4;
1299 qemu_alloc_display(surface, width, height, linesize,
1300 qemu_default_pixelformat(32), 0);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001301 return surface;
1302}
1303
1304static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1305 int width, int height)
1306{
Jes Sorensenffe8b822011-03-16 13:33:30 +01001307 int linesize = width * 4;
1308 qemu_alloc_display(surface, width, height, linesize,
1309 qemu_default_pixelformat(32), 0);
1310 return surface;
1311}
1312
1313void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1314 int linesize, PixelFormat pf, int newflags)
1315{
1316 void *data;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001317 surface->width = width;
1318 surface->height = height;
Jes Sorensenffe8b822011-03-16 13:33:30 +01001319 surface->linesize = linesize;
1320 surface->pf = pf;
1321 if (surface->flags & QEMU_ALLOCATED_FLAG) {
Anthony Liguori7267c092011-08-20 22:09:37 -05001322 data = g_realloc(surface->data,
Jes Sorensenffe8b822011-03-16 13:33:30 +01001323 surface->linesize * surface->height);
1324 } else {
Anthony Liguori7267c092011-08-20 22:09:37 -05001325 data = g_malloc(surface->linesize * surface->height);
Jes Sorensenffe8b822011-03-16 13:33:30 +01001326 }
1327 surface->data = (uint8_t *)data;
1328 surface->flags = newflags | QEMU_ALLOCATED_FLAG;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001329#ifdef HOST_WORDS_BIGENDIAN
Jes Sorensenffe8b822011-03-16 13:33:30 +01001330 surface->flags |= QEMU_BIG_ENDIAN_FLAG;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001331#endif
Paolo Bonzini98b50082010-02-11 00:29:57 +01001332}
1333
1334DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1335 int linesize, uint8_t *data)
1336{
Anthony Liguori7267c092011-08-20 22:09:37 -05001337 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
Paolo Bonzini98b50082010-02-11 00:29:57 +01001338
1339 surface->width = width;
1340 surface->height = height;
1341 surface->linesize = linesize;
1342 surface->pf = qemu_default_pixelformat(bpp);
1343#ifdef HOST_WORDS_BIGENDIAN
1344 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1345#endif
1346 surface->data = data;
1347
1348 return surface;
1349}
1350
1351static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1352{
1353 if (surface == NULL)
1354 return;
1355 if (surface->flags & QEMU_ALLOCATED_FLAG)
Anthony Liguori7267c092011-08-20 22:09:37 -05001356 g_free(surface->data);
1357 g_free(surface);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001358}
1359
1360static struct DisplayAllocator default_allocator = {
1361 defaultallocator_create_displaysurface,
1362 defaultallocator_resize_displaysurface,
1363 defaultallocator_free_displaysurface
1364};
1365
1366static void dumb_display_init(void)
1367{
Anthony Liguori7267c092011-08-20 22:09:37 -05001368 DisplayState *ds = g_malloc0(sizeof(DisplayState));
Jan Kiszka18026512011-06-19 11:53:02 +02001369 int width = 640;
1370 int height = 480;
1371
Paolo Bonzini98b50082010-02-11 00:29:57 +01001372 ds->allocator = &default_allocator;
Jan Kiszka18026512011-06-19 11:53:02 +02001373 if (is_fixedsize_console()) {
1374 width = active_console->g_width;
1375 height = active_console->g_height;
1376 }
1377 ds->surface = qemu_create_displaysurface(ds, width, height);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001378 register_displaystate(ds);
1379}
1380
1381/***********************************************************/
1382/* register display */
1383
1384void register_displaystate(DisplayState *ds)
1385{
1386 DisplayState **s;
1387 s = &display_state;
1388 while (*s != NULL)
1389 s = &(*s)->next;
1390 ds->next = NULL;
1391 *s = ds;
1392}
1393
1394DisplayState *get_displaystate(void)
1395{
1396 if (!display_state) {
1397 dumb_display_init ();
1398 }
1399 return display_state;
1400}
1401
1402DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1403{
1404 if(ds->allocator == &default_allocator) {
1405 DisplaySurface *surf;
1406 surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1407 defaultallocator_free_displaysurface(ds->surface);
1408 ds->surface = surf;
1409 ds->allocator = da;
1410 }
1411 return ds->allocator;
1412}
1413
aliguori3023f332009-01-16 19:04:14 +00001414DisplayState *graphic_console_init(vga_hw_update_ptr update,
1415 vga_hw_invalidate_ptr invalidate,
1416 vga_hw_screen_dump_ptr screen_dump,
1417 vga_hw_text_update_ptr text_update,
1418 void *opaque)
bellarde7f0ad52004-07-14 17:28:59 +00001419{
pbrook95219892006-04-09 01:06:34 +00001420 TextConsole *s;
aliguori3023f332009-01-16 19:04:14 +00001421 DisplayState *ds;
aurel32f0f2f972009-01-16 21:13:49 +00001422
Anthony Liguori7267c092011-08-20 22:09:37 -05001423 ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
aliguori7b5d76d2009-03-13 15:02:13 +00001424 ds->allocator = &default_allocator;
1425 ds->surface = qemu_create_displaysurface(ds, 640, 480);
pbrook95219892006-04-09 01:06:34 +00001426
thsaf3a9032007-07-11 23:14:59 +00001427 s = new_console(ds, GRAPHIC_CONSOLE);
aliguori3023f332009-01-16 19:04:14 +00001428 if (s == NULL) {
aliguori7b5d76d2009-03-13 15:02:13 +00001429 qemu_free_displaysurface(ds);
Anthony Liguori7267c092011-08-20 22:09:37 -05001430 g_free(ds);
aliguori3023f332009-01-16 19:04:14 +00001431 return NULL;
1432 }
pbrook95219892006-04-09 01:06:34 +00001433 s->hw_update = update;
1434 s->hw_invalidate = invalidate;
1435 s->hw_screen_dump = screen_dump;
balrog4d3b6f62008-02-10 16:33:14 +00001436 s->hw_text_update = text_update;
pbrook95219892006-04-09 01:06:34 +00001437 s->hw = opaque;
aliguori3023f332009-01-16 19:04:14 +00001438
aurel32f0f2f972009-01-16 21:13:49 +00001439 register_displaystate(ds);
aliguori3023f332009-01-16 19:04:14 +00001440 return ds;
pbrook95219892006-04-09 01:06:34 +00001441}
1442
1443int is_graphic_console(void)
1444{
balrog4d3b6f62008-02-10 16:33:14 +00001445 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
bellarde7f0ad52004-07-14 17:28:59 +00001446}
1447
balrogc21bbcf2008-09-24 03:32:33 +00001448int is_fixedsize_console(void)
1449{
1450 return active_console && active_console->console_type != TEXT_CONSOLE;
1451}
1452
balroga528b802007-10-30 22:38:53 +00001453void console_color_init(DisplayState *ds)
1454{
1455 int i, j;
1456 for (j = 0; j < 2; j++) {
1457 for (i = 0; i < 8; i++) {
aurel32f0f2f972009-01-16 21:13:49 +00001458 color_table[j][i] = col_expand(ds,
balroga528b802007-10-30 22:38:53 +00001459 vga_get_color(ds, color_table_rgb[j][i]));
1460 }
1461 }
1462}
1463
Paolo Bonzini41048332010-12-23 13:42:52 +01001464static void text_console_set_echo(CharDriverState *chr, bool echo)
1465{
1466 TextConsole *s = chr->opaque;
1467
1468 s->echo = echo;
1469}
1470
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001471static void text_console_update_cursor(void *opaque)
1472{
1473 TextConsole *s = opaque;
1474
1475 s->cursor_visible_phase = !s->cursor_visible_phase;
1476 vga_hw_invalidate();
1477 qemu_mod_timer(s->cursor_timer,
1478 qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1479}
1480
Paolo Bonzini44b37b92010-12-23 13:42:53 +01001481static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
bellarde7f0ad52004-07-14 17:28:59 +00001482{
bellarde7f0ad52004-07-14 17:28:59 +00001483 TextConsole *s;
bellarde7f0ad52004-07-14 17:28:59 +00001484 static int color_inited;
pbrook6d6f7c22006-03-11 15:35:30 +00001485
Paolo Bonzini491e1142010-12-23 13:42:51 +01001486 s = chr->opaque;
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001487
bellarde7f0ad52004-07-14 17:28:59 +00001488 chr->chr_write = console_puts;
bellard6fcfafb2004-08-01 21:48:30 +00001489
bellarde15d7372006-06-25 16:26:29 +00001490 s->out_fifo.buf = s->out_fifo_buf;
1491 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001492 s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
aliguori3023f332009-01-16 19:04:14 +00001493 s->ds = ds;
ths3b46e622007-09-17 08:09:54 +00001494
bellarde7f0ad52004-07-14 17:28:59 +00001495 if (!color_inited) {
1496 color_inited = 1;
balroga528b802007-10-30 22:38:53 +00001497 console_color_init(s->ds);
bellarde7f0ad52004-07-14 17:28:59 +00001498 }
1499 s->y_displayed = 0;
1500 s->y_base = 0;
1501 s->total_height = DEFAULT_BACKSCROLL;
1502 s->x = 0;
1503 s->y = 0;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001504 if (s->console_type == TEXT_CONSOLE) {
1505 s->g_width = ds_get_width(s->ds);
1506 s->g_height = ds_get_height(s->ds);
1507 }
pbrook6d6f7c22006-03-11 15:35:30 +00001508
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001509 s->cursor_timer =
1510 qemu_new_timer_ms(rt_clock, text_console_update_cursor, s);
1511
balrog4d3b6f62008-02-10 16:33:14 +00001512 s->hw_invalidate = text_console_invalidate;
1513 s->hw_text_update = text_console_update;
1514 s->hw = s;
1515
pbrook6d6f7c22006-03-11 15:35:30 +00001516 /* Set text attribute defaults */
1517 s->t_attrib_default.bold = 0;
1518 s->t_attrib_default.uline = 0;
1519 s->t_attrib_default.blink = 0;
1520 s->t_attrib_default.invers = 0;
1521 s->t_attrib_default.unvisible = 0;
1522 s->t_attrib_default.fgcol = COLOR_WHITE;
1523 s->t_attrib_default.bgcol = COLOR_BLACK;
pbrook6d6f7c22006-03-11 15:35:30 +00001524 /* set current text attributes to default */
1525 s->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +00001526 text_console_resize(s);
1527
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001528 if (chr->label) {
1529 char msg[128];
1530 int len;
1531
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001532 s->t_attrib.bgcol = COLOR_BLUE;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001533 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1534 console_puts(chr, (uint8_t*)msg, len);
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001535 s->t_attrib = s->t_attrib_default;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001536 }
1537
Amit Shah127338e2009-11-03 19:59:56 +05301538 qemu_chr_generic_open(chr);
aurel32ceecf1d2009-01-18 14:08:04 +00001539 if (chr->init)
1540 chr->init(chr);
bellarde7f0ad52004-07-14 17:28:59 +00001541}
pbrookc60e08d2008-07-01 16:24:38 +00001542
Markus Armbruster1f514702012-02-07 15:09:08 +01001543CharDriverState *text_console_init(QemuOpts *opts)
aliguori2796dae2009-01-16 20:23:27 +00001544{
1545 CharDriverState *chr;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001546 TextConsole *s;
1547 unsigned width;
1548 unsigned height;
aliguori2796dae2009-01-16 20:23:27 +00001549
Anthony Liguori7267c092011-08-20 22:09:37 -05001550 chr = g_malloc0(sizeof(CharDriverState));
aliguori2796dae2009-01-16 20:23:27 +00001551
Paolo Bonzini491e1142010-12-23 13:42:51 +01001552 width = qemu_opt_get_number(opts, "width", 0);
1553 if (width == 0)
1554 width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1555
1556 height = qemu_opt_get_number(opts, "height", 0);
1557 if (height == 0)
1558 height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1559
1560 if (width == 0 || height == 0) {
1561 s = new_console(NULL, TEXT_CONSOLE);
1562 } else {
1563 s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1564 }
1565
1566 if (!s) {
Stefan Weil5354d082011-10-02 18:53:09 +02001567 g_free(chr);
Markus Armbruster1f514702012-02-07 15:09:08 +01001568 return NULL;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001569 }
1570
1571 s->chr = chr;
1572 s->g_width = width;
1573 s->g_height = height;
1574 chr->opaque = s;
Paolo Bonzini41048332010-12-23 13:42:52 +01001575 chr->chr_set_echo = text_console_set_echo;
Markus Armbruster1f514702012-02-07 15:09:08 +01001576 return chr;
aliguori2796dae2009-01-16 20:23:27 +00001577}
1578
1579void text_consoles_set_display(DisplayState *ds)
1580{
1581 int i;
1582
Markus Armbruster8811e1e2012-02-07 15:09:21 +01001583 for (i = 0; i < nb_consoles; i++) {
1584 if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1585 text_console_do_init(consoles[i]->chr, ds);
1586 }
aliguori2796dae2009-01-16 20:23:27 +00001587 }
aliguori2796dae2009-01-16 20:23:27 +00001588}
1589
aliguori3023f332009-01-16 19:04:14 +00001590void qemu_console_resize(DisplayState *ds, int width, int height)
pbrookc60e08d2008-07-01 16:24:38 +00001591{
aliguori42aa98e2009-01-16 21:01:48 +00001592 TextConsole *s = get_graphic_console(ds);
aliguorif497f142009-01-21 19:18:00 +00001593 if (!s) return;
1594
aliguori3023f332009-01-16 19:04:14 +00001595 s->g_width = width;
1596 s->g_height = height;
1597 if (is_graphic_console()) {
aliguori7b5d76d2009-03-13 15:02:13 +00001598 ds->surface = qemu_resize_displaysurface(ds, width, height);
aliguori3023f332009-01-16 19:04:14 +00001599 dpy_resize(ds);
pbrookc60e08d2008-07-01 16:24:38 +00001600 }
1601}
balrog38334f72008-09-24 02:21:24 +00001602
aliguori3023f332009-01-16 19:04:14 +00001603void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1604 int dst_x, int dst_y, int w, int h)
balrogc21bbcf2008-09-24 03:32:33 +00001605{
aliguori3023f332009-01-16 19:04:14 +00001606 if (is_graphic_console()) {
1607 dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
balrog38334f72008-09-24 02:21:24 +00001608 }
1609}
aliguori7d957bd2009-01-15 22:14:11 +00001610
malc0da2ea12009-01-23 19:56:19 +00001611PixelFormat qemu_different_endianness_pixelformat(int bpp)
aliguori7d957bd2009-01-15 22:14:11 +00001612{
1613 PixelFormat pf;
1614
1615 memset(&pf, 0x00, sizeof(PixelFormat));
1616
1617 pf.bits_per_pixel = bpp;
BALATON Zoltanfeadf1a2012-08-22 17:19:42 +02001618 pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
aliguori7d957bd2009-01-15 22:14:11 +00001619 pf.depth = bpp == 32 ? 24 : bpp;
1620
1621 switch (bpp) {
malc0da2ea12009-01-23 19:56:19 +00001622 case 24:
1623 pf.rmask = 0x000000FF;
1624 pf.gmask = 0x0000FF00;
1625 pf.bmask = 0x00FF0000;
1626 pf.rmax = 255;
1627 pf.gmax = 255;
1628 pf.bmax = 255;
1629 pf.rshift = 0;
1630 pf.gshift = 8;
1631 pf.bshift = 16;
aliguori90a1e3c2009-01-26 15:37:30 +00001632 pf.rbits = 8;
1633 pf.gbits = 8;
1634 pf.bbits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001635 break;
malc0da2ea12009-01-23 19:56:19 +00001636 case 32:
1637 pf.rmask = 0x0000FF00;
1638 pf.gmask = 0x00FF0000;
1639 pf.bmask = 0xFF000000;
1640 pf.amask = 0x00000000;
1641 pf.amax = 255;
1642 pf.rmax = 255;
1643 pf.gmax = 255;
1644 pf.bmax = 255;
1645 pf.ashift = 0;
1646 pf.rshift = 8;
1647 pf.gshift = 16;
1648 pf.bshift = 24;
aliguori90a1e3c2009-01-26 15:37:30 +00001649 pf.rbits = 8;
1650 pf.gbits = 8;
1651 pf.bbits = 8;
1652 pf.abits = 8;
malc0da2ea12009-01-23 19:56:19 +00001653 break;
1654 default:
1655 break;
1656 }
1657 return pf;
1658}
1659
1660PixelFormat qemu_default_pixelformat(int bpp)
1661{
1662 PixelFormat pf;
1663
1664 memset(&pf, 0x00, sizeof(PixelFormat));
1665
1666 pf.bits_per_pixel = bpp;
BALATON Zoltanfeadf1a2012-08-22 17:19:42 +02001667 pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
malc0da2ea12009-01-23 19:56:19 +00001668 pf.depth = bpp == 32 ? 24 : bpp;
1669
1670 switch (bpp) {
Gerd Hoffmannb6278082010-05-21 11:59:14 +02001671 case 15:
1672 pf.bits_per_pixel = 16;
Gerd Hoffmannb6278082010-05-21 11:59:14 +02001673 pf.rmask = 0x00007c00;
1674 pf.gmask = 0x000003E0;
1675 pf.bmask = 0x0000001F;
1676 pf.rmax = 31;
1677 pf.gmax = 31;
1678 pf.bmax = 31;
1679 pf.rshift = 10;
1680 pf.gshift = 5;
1681 pf.bshift = 0;
1682 pf.rbits = 5;
1683 pf.gbits = 5;
1684 pf.bbits = 5;
1685 break;
aliguori7d957bd2009-01-15 22:14:11 +00001686 case 16:
1687 pf.rmask = 0x0000F800;
1688 pf.gmask = 0x000007E0;
1689 pf.bmask = 0x0000001F;
1690 pf.rmax = 31;
1691 pf.gmax = 63;
1692 pf.bmax = 31;
1693 pf.rshift = 11;
1694 pf.gshift = 5;
1695 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001696 pf.rbits = 5;
1697 pf.gbits = 6;
1698 pf.bbits = 5;
aliguori7d957bd2009-01-15 22:14:11 +00001699 break;
1700 case 24:
aliguori7d957bd2009-01-15 22:14:11 +00001701 pf.rmask = 0x00FF0000;
1702 pf.gmask = 0x0000FF00;
1703 pf.bmask = 0x000000FF;
1704 pf.rmax = 255;
1705 pf.gmax = 255;
1706 pf.bmax = 255;
1707 pf.rshift = 16;
1708 pf.gshift = 8;
1709 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001710 pf.rbits = 8;
1711 pf.gbits = 8;
1712 pf.bbits = 8;
Markus Armbruster0eba62e2011-11-22 12:56:10 +01001713 break;
malc0da2ea12009-01-23 19:56:19 +00001714 case 32:
1715 pf.rmask = 0x00FF0000;
1716 pf.gmask = 0x0000FF00;
1717 pf.bmask = 0x000000FF;
1718 pf.amax = 255;
1719 pf.rmax = 255;
1720 pf.gmax = 255;
1721 pf.bmax = 255;
1722 pf.ashift = 24;
1723 pf.rshift = 16;
1724 pf.gshift = 8;
1725 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001726 pf.rbits = 8;
1727 pf.gbits = 8;
1728 pf.bbits = 8;
1729 pf.abits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001730 break;
1731 default:
1732 break;
1733 }
1734 return pf;
1735}