blob: 6a463f5918d58d7fc6153e87ec472c6404f445c6 [file] [log] [blame]
bellarde7f0ad52004-07-14 17:28:59 +00001/*
2 * QEMU graphical console
ths5fafdf22007-09-16 21:08:06 +00003 *
bellarde7f0ad52004-07-14 17:28:59 +00004 * Copyright (c) 2004 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
bellarde7f0ad52004-07-14 17:28:59 +00006 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
pbrook87ecb682007-11-17 17:14:51 +000024#include "qemu-common.h"
25#include "console.h"
26#include "qemu-timer.h"
bellarde7f0ad52004-07-14 17:28:59 +000027
pbrook6d6f7c22006-03-11 15:35:30 +000028//#define DEBUG_CONSOLE
bellarde7f0ad52004-07-14 17:28:59 +000029#define DEFAULT_BACKSCROLL 512
30#define MAX_CONSOLES 12
31
bellard26489842006-06-25 17:37:36 +000032#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
33#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
bellarde7f0ad52004-07-14 17:28:59 +000034
pbrook6d6f7c22006-03-11 15:35:30 +000035typedef struct TextAttributes {
36 uint8_t fgcol:4;
37 uint8_t bgcol:4;
38 uint8_t bold:1;
39 uint8_t uline:1;
40 uint8_t blink:1;
41 uint8_t invers:1;
42 uint8_t unvisible:1;
43} TextAttributes;
44
bellarde7f0ad52004-07-14 17:28:59 +000045typedef struct TextCell {
46 uint8_t ch;
pbrook6d6f7c22006-03-11 15:35:30 +000047 TextAttributes t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +000048} TextCell;
49
50#define MAX_ESC_PARAMS 3
51
52enum TTYState {
53 TTY_STATE_NORM,
54 TTY_STATE_ESC,
55 TTY_STATE_CSI,
56};
57
bellarde15d7372006-06-25 16:26:29 +000058typedef struct QEMUFIFO {
59 uint8_t *buf;
60 int buf_size;
61 int count, wptr, rptr;
62} QEMUFIFO;
63
pbrook9596ebb2007-11-18 01:44:38 +000064static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
bellarde15d7372006-06-25 16:26:29 +000065{
66 int l, len;
67
68 l = f->buf_size - f->count;
69 if (len1 > l)
70 len1 = l;
71 len = len1;
72 while (len > 0) {
73 l = f->buf_size - f->wptr;
74 if (l > len)
75 l = len;
76 memcpy(f->buf + f->wptr, buf, l);
77 f->wptr += l;
78 if (f->wptr >= f->buf_size)
79 f->wptr = 0;
80 buf += l;
81 len -= l;
82 }
83 f->count += len1;
84 return len1;
85}
86
pbrook9596ebb2007-11-18 01:44:38 +000087static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
bellarde15d7372006-06-25 16:26:29 +000088{
89 int l, len;
90
91 if (len1 > f->count)
92 len1 = f->count;
93 len = len1;
94 while (len > 0) {
95 l = f->buf_size - f->rptr;
96 if (l > len)
97 l = len;
98 memcpy(buf, f->buf + f->rptr, l);
99 f->rptr += l;
100 if (f->rptr >= f->buf_size)
101 f->rptr = 0;
102 buf += l;
103 len -= l;
104 }
105 f->count -= len1;
106 return len1;
107}
108
thsaf3a9032007-07-11 23:14:59 +0000109typedef enum {
110 GRAPHIC_CONSOLE,
balrogc21bbcf2008-09-24 03:32:33 +0000111 TEXT_CONSOLE,
112 TEXT_CONSOLE_FIXED_SIZE
Anthony Liguoric227f092009-10-01 16:12:16 -0500113} console_type_t;
thsaf3a9032007-07-11 23:14:59 +0000114
pbrook95219892006-04-09 01:06:34 +0000115/* ??? This is mis-named.
116 It is used for both text and graphical consoles. */
bellarde7f0ad52004-07-14 17:28:59 +0000117struct TextConsole {
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200118 int index;
Anthony Liguoric227f092009-10-01 16:12:16 -0500119 console_type_t console_type;
bellarde7f0ad52004-07-14 17:28:59 +0000120 DisplayState *ds;
pbrook95219892006-04-09 01:06:34 +0000121 /* Graphic console state. */
122 vga_hw_update_ptr hw_update;
123 vga_hw_invalidate_ptr hw_invalidate;
124 vga_hw_screen_dump_ptr hw_screen_dump;
balrog4d3b6f62008-02-10 16:33:14 +0000125 vga_hw_text_update_ptr hw_text_update;
pbrook95219892006-04-09 01:06:34 +0000126 void *hw;
127
bellarde7f0ad52004-07-14 17:28:59 +0000128 int g_width, g_height;
129 int width;
130 int height;
131 int total_height;
132 int backscroll_height;
bellarde7f0ad52004-07-14 17:28:59 +0000133 int x, y;
thsadb47962007-01-16 23:02:36 +0000134 int x_saved, y_saved;
bellarde7f0ad52004-07-14 17:28:59 +0000135 int y_displayed;
136 int y_base;
pbrook6d6f7c22006-03-11 15:35:30 +0000137 TextAttributes t_attrib_default; /* default text attributes */
138 TextAttributes t_attrib; /* currently active text attributes */
bellarde7f0ad52004-07-14 17:28:59 +0000139 TextCell *cells;
balrog4d3b6f62008-02-10 16:33:14 +0000140 int text_x[2], text_y[2], cursor_invalidate;
Paolo Bonzini41048332010-12-23 13:42:52 +0100141 int echo;
bellarde7f0ad52004-07-14 17:28:59 +0000142
pbrook14778c22009-01-21 03:02:52 +0000143 int update_x0;
144 int update_y0;
145 int update_x1;
146 int update_y1;
147
bellarde7f0ad52004-07-14 17:28:59 +0000148 enum TTYState state;
149 int esc_params[MAX_ESC_PARAMS];
150 int nb_esc_params;
151
pbrooke5b0bc42007-01-27 23:46:43 +0000152 CharDriverState *chr;
bellarde15d7372006-06-25 16:26:29 +0000153 /* fifo for key pressed */
154 QEMUFIFO out_fifo;
155 uint8_t out_fifo_buf[16];
156 QEMUTimer *kbd_timer;
bellarde7f0ad52004-07-14 17:28:59 +0000157};
158
Paolo Bonzini98b50082010-02-11 00:29:57 +0100159static DisplayState *display_state;
bellarde7f0ad52004-07-14 17:28:59 +0000160static TextConsole *active_console;
161static TextConsole *consoles[MAX_CONSOLES];
162static int nb_consoles = 0;
163
pbrook95219892006-04-09 01:06:34 +0000164void vga_hw_update(void)
165{
thsadb47962007-01-16 23:02:36 +0000166 if (active_console && active_console->hw_update)
pbrook95219892006-04-09 01:06:34 +0000167 active_console->hw_update(active_console->hw);
168}
169
170void vga_hw_invalidate(void)
171{
Gerd Hoffmann26572b82010-05-20 15:23:06 +0200172 if (active_console && active_console->hw_invalidate)
pbrook95219892006-04-09 01:06:34 +0000173 active_console->hw_invalidate(active_console->hw);
174}
175
176void vga_hw_screen_dump(const char *filename)
177{
balrog8571c052008-07-19 13:04:26 +0000178 TextConsole *previous_active_console;
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100179 bool cswitch;
balrog8571c052008-07-19 13:04:26 +0000180
181 previous_active_console = active_console;
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100182 cswitch = previous_active_console && previous_active_console->index != 0;
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200183
balrog8571c052008-07-19 13:04:26 +0000184 /* There is currently no way of specifying which screen we want to dump,
aurel327b455222008-09-02 00:09:16 +0000185 so always dump the first one. */
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100186 if (cswitch) {
187 console_select(0);
188 }
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200189 if (consoles[0] && consoles[0]->hw_screen_dump) {
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100190 consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch);
Gerd Hoffmann16735102012-02-24 12:43:44 +0100191 } else {
192 error_report("screen dump not implemented");
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200193 }
194
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100195 if (cswitch) {
Alexander Graf33bcd982011-11-18 16:41:59 +0100196 console_select(previous_active_console->index);
197 }
pbrook95219892006-04-09 01:06:34 +0000198}
199
Anthony Liguoric227f092009-10-01 16:12:16 -0500200void vga_hw_text_update(console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +0000201{
202 if (active_console && active_console->hw_text_update)
203 active_console->hw_text_update(active_console->hw, chardata);
204}
205
bellarde7f0ad52004-07-14 17:28:59 +0000206/* convert a RGBA color to a color index usable in graphic primitives */
207static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
208{
209 unsigned int r, g, b, color;
210
aliguori0e1f5a02008-11-24 19:29:13 +0000211 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000212#if 0
213 case 8:
214 r = (rgba >> 16) & 0xff;
215 g = (rgba >> 8) & 0xff;
216 b = (rgba) & 0xff;
ths5fafdf22007-09-16 21:08:06 +0000217 color = (rgb_to_index[r] * 6 * 6) +
218 (rgb_to_index[g] * 6) +
bellarde7f0ad52004-07-14 17:28:59 +0000219 (rgb_to_index[b]);
220 break;
221#endif
222 case 15:
223 r = (rgba >> 16) & 0xff;
224 g = (rgba >> 8) & 0xff;
225 b = (rgba) & 0xff;
226 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
227 break;
228 case 16:
229 r = (rgba >> 16) & 0xff;
230 g = (rgba >> 8) & 0xff;
231 b = (rgba) & 0xff;
232 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
233 break;
234 case 32:
235 default:
236 color = rgba;
237 break;
238 }
239 return color;
240}
241
ths5fafdf22007-09-16 21:08:06 +0000242static void vga_fill_rect (DisplayState *ds,
bellarde7f0ad52004-07-14 17:28:59 +0000243 int posx, int posy, int width, int height, uint32_t color)
244{
245 uint8_t *d, *d1;
246 int x, y, bpp;
ths3b46e622007-09-17 08:09:54 +0000247
aliguori0e1f5a02008-11-24 19:29:13 +0000248 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
249 d1 = ds_get_data(ds) +
250 ds_get_linesize(ds) * posy + bpp * posx;
bellarde7f0ad52004-07-14 17:28:59 +0000251 for (y = 0; y < height; y++) {
252 d = d1;
253 switch(bpp) {
254 case 1:
255 for (x = 0; x < width; x++) {
256 *((uint8_t *)d) = color;
257 d++;
258 }
259 break;
260 case 2:
261 for (x = 0; x < width; x++) {
262 *((uint16_t *)d) = color;
263 d += 2;
264 }
265 break;
266 case 4:
267 for (x = 0; x < width; x++) {
268 *((uint32_t *)d) = color;
269 d += 4;
270 }
271 break;
272 }
aliguori0e1f5a02008-11-24 19:29:13 +0000273 d1 += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000274 }
275}
276
277/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
278static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
279{
280 const uint8_t *s;
281 uint8_t *d;
282 int wb, y, bpp;
283
aliguori0e1f5a02008-11-24 19:29:13 +0000284 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
bellarde7f0ad52004-07-14 17:28:59 +0000285 wb = w * bpp;
286 if (yd <= ys) {
aliguori0e1f5a02008-11-24 19:29:13 +0000287 s = ds_get_data(ds) +
288 ds_get_linesize(ds) * ys + bpp * xs;
289 d = ds_get_data(ds) +
290 ds_get_linesize(ds) * yd + bpp * xd;
bellarde7f0ad52004-07-14 17:28:59 +0000291 for (y = 0; y < h; y++) {
292 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000293 d += ds_get_linesize(ds);
294 s += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000295 }
296 } else {
aliguori0e1f5a02008-11-24 19:29:13 +0000297 s = ds_get_data(ds) +
298 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
299 d = ds_get_data(ds) +
300 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
bellarde7f0ad52004-07-14 17:28:59 +0000301 for (y = 0; y < h; y++) {
302 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000303 d -= ds_get_linesize(ds);
304 s -= ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000305 }
306 }
307}
308
309/***********************************************************/
310/* basic char display */
311
312#define FONT_HEIGHT 16
313#define FONT_WIDTH 8
314
315#include "vgafont.h"
316
317#define cbswap_32(__x) \
318((uint32_t)( \
319 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
320 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
321 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
322 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
323
Juan Quintelae2542fe2009-07-27 16:13:06 +0200324#ifdef HOST_WORDS_BIGENDIAN
bellarde7f0ad52004-07-14 17:28:59 +0000325#define PAT(x) x
326#else
327#define PAT(x) cbswap_32(x)
328#endif
329
330static const uint32_t dmask16[16] = {
331 PAT(0x00000000),
332 PAT(0x000000ff),
333 PAT(0x0000ff00),
334 PAT(0x0000ffff),
335 PAT(0x00ff0000),
336 PAT(0x00ff00ff),
337 PAT(0x00ffff00),
338 PAT(0x00ffffff),
339 PAT(0xff000000),
340 PAT(0xff0000ff),
341 PAT(0xff00ff00),
342 PAT(0xff00ffff),
343 PAT(0xffff0000),
344 PAT(0xffff00ff),
345 PAT(0xffffff00),
346 PAT(0xffffffff),
347};
348
349static const uint32_t dmask4[4] = {
350 PAT(0x00000000),
351 PAT(0x0000ffff),
352 PAT(0xffff0000),
353 PAT(0xffffffff),
354};
355
pbrook6d6f7c22006-03-11 15:35:30 +0000356static uint32_t color_table[2][8];
bellarde7f0ad52004-07-14 17:28:59 +0000357
Devin J. Pohlydf00bed2011-09-07 15:44:36 -0400358#ifndef CONFIG_CURSES
pbrook6d6f7c22006-03-11 15:35:30 +0000359enum color_names {
360 COLOR_BLACK = 0,
361 COLOR_RED = 1,
362 COLOR_GREEN = 2,
363 COLOR_YELLOW = 3,
364 COLOR_BLUE = 4,
365 COLOR_MAGENTA = 5,
366 COLOR_CYAN = 6,
367 COLOR_WHITE = 7
368};
Devin J. Pohlydf00bed2011-09-07 15:44:36 -0400369#endif
pbrook6d6f7c22006-03-11 15:35:30 +0000370
371static const uint32_t color_table_rgb[2][8] = {
372 { /* dark */
bellard26489842006-06-25 17:37:36 +0000373 QEMU_RGB(0x00, 0x00, 0x00), /* black */
374 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
375 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
376 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
377 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
378 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
379 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
380 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000381 },
382 { /* bright */
bellard26489842006-06-25 17:37:36 +0000383 QEMU_RGB(0x00, 0x00, 0x00), /* black */
384 QEMU_RGB(0xff, 0x00, 0x00), /* red */
385 QEMU_RGB(0x00, 0xff, 0x00), /* green */
386 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
387 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
388 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
389 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
390 QEMU_RGB(0xff, 0xff, 0xff), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000391 }
bellarde7f0ad52004-07-14 17:28:59 +0000392};
393
394static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
395{
aliguori0e1f5a02008-11-24 19:29:13 +0000396 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000397 case 8:
398 col |= col << 8;
399 col |= col << 16;
400 break;
401 case 15:
402 case 16:
403 col |= col << 16;
404 break;
405 default:
406 break;
407 }
408
409 return col;
410}
pbrook6d6f7c22006-03-11 15:35:30 +0000411#ifdef DEBUG_CONSOLE
412static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
413{
414 if (t_attrib->bold) {
415 printf("b");
416 } else {
417 printf(" ");
418 }
419 if (t_attrib->uline) {
420 printf("u");
421 } else {
422 printf(" ");
423 }
424 if (t_attrib->blink) {
425 printf("l");
426 } else {
427 printf(" ");
428 }
429 if (t_attrib->invers) {
430 printf("i");
431 } else {
432 printf(" ");
433 }
434 if (t_attrib->unvisible) {
435 printf("n");
436 } else {
437 printf(" ");
438 }
439
440 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
441}
442#endif
bellarde7f0ad52004-07-14 17:28:59 +0000443
ths5fafdf22007-09-16 21:08:06 +0000444static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000445 TextAttributes *t_attrib)
bellarde7f0ad52004-07-14 17:28:59 +0000446{
447 uint8_t *d;
448 const uint8_t *font_ptr;
449 unsigned int font_data, linesize, xorcol, bpp;
450 int i;
pbrook6d6f7c22006-03-11 15:35:30 +0000451 unsigned int fgcol, bgcol;
452
453#ifdef DEBUG_CONSOLE
454 printf("x: %2i y: %2i", x, y);
455 console_print_text_attributes(t_attrib, ch);
456#endif
457
458 if (t_attrib->invers) {
459 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
460 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
461 } else {
462 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
463 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
464 }
bellarde7f0ad52004-07-14 17:28:59 +0000465
aliguori0e1f5a02008-11-24 19:29:13 +0000466 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
467 d = ds_get_data(ds) +
468 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
469 linesize = ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000470 font_ptr = vgafont16 + FONT_HEIGHT * ch;
471 xorcol = bgcol ^ fgcol;
aliguori0e1f5a02008-11-24 19:29:13 +0000472 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000473 case 8:
474 for(i = 0; i < FONT_HEIGHT; i++) {
475 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000476 if (t_attrib->uline
477 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100478 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000479 }
bellarde7f0ad52004-07-14 17:28:59 +0000480 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
481 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
482 d += linesize;
483 }
484 break;
485 case 16:
486 case 15:
487 for(i = 0; i < FONT_HEIGHT; i++) {
488 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000489 if (t_attrib->uline
490 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100491 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000492 }
bellarde7f0ad52004-07-14 17:28:59 +0000493 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
494 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
495 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
496 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
497 d += linesize;
498 }
499 break;
500 case 32:
501 for(i = 0; i < FONT_HEIGHT; i++) {
502 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000503 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100504 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000505 }
bellarde7f0ad52004-07-14 17:28:59 +0000506 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
507 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
508 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
509 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
510 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
511 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
512 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
513 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
514 d += linesize;
515 }
516 break;
517 }
518}
519
520static void text_console_resize(TextConsole *s)
521{
522 TextCell *cells, *c, *c1;
523 int w1, x, y, last_width;
524
525 last_width = s->width;
526 s->width = s->g_width / FONT_WIDTH;
527 s->height = s->g_height / FONT_HEIGHT;
528
529 w1 = last_width;
530 if (s->width < w1)
531 w1 = s->width;
532
Anthony Liguori7267c092011-08-20 22:09:37 -0500533 cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
bellarde7f0ad52004-07-14 17:28:59 +0000534 for(y = 0; y < s->total_height; y++) {
535 c = &cells[y * s->width];
536 if (w1 > 0) {
537 c1 = &s->cells[y * last_width];
538 for(x = 0; x < w1; x++) {
539 *c++ = *c1++;
540 }
541 }
542 for(x = w1; x < s->width; x++) {
543 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000544 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000545 c++;
546 }
547 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500548 g_free(s->cells);
bellarde7f0ad52004-07-14 17:28:59 +0000549 s->cells = cells;
550}
551
balrog4d3b6f62008-02-10 16:33:14 +0000552static inline void text_update_xy(TextConsole *s, int x, int y)
553{
554 s->text_x[0] = MIN(s->text_x[0], x);
555 s->text_x[1] = MAX(s->text_x[1], x);
556 s->text_y[0] = MIN(s->text_y[0], y);
557 s->text_y[1] = MAX(s->text_y[1], y);
558}
559
pbrook14778c22009-01-21 03:02:52 +0000560static void invalidate_xy(TextConsole *s, int x, int y)
561{
562 if (s->update_x0 > x * FONT_WIDTH)
563 s->update_x0 = x * FONT_WIDTH;
564 if (s->update_y0 > y * FONT_HEIGHT)
565 s->update_y0 = y * FONT_HEIGHT;
566 if (s->update_x1 < (x + 1) * FONT_WIDTH)
567 s->update_x1 = (x + 1) * FONT_WIDTH;
568 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
569 s->update_y1 = (y + 1) * FONT_HEIGHT;
570}
571
bellarde7f0ad52004-07-14 17:28:59 +0000572static void update_xy(TextConsole *s, int x, int y)
573{
574 TextCell *c;
575 int y1, y2;
576
577 if (s == active_console) {
aliguori0e1f5a02008-11-24 19:29:13 +0000578 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000579 text_update_xy(s, x, y);
580 return;
581 }
582
bellarde7f0ad52004-07-14 17:28:59 +0000583 y1 = (s->y_base + y) % s->total_height;
584 y2 = y1 - s->y_displayed;
585 if (y2 < 0)
586 y2 += s->total_height;
587 if (y2 < s->height) {
588 c = &s->cells[y1 * s->width + x];
ths5fafdf22007-09-16 21:08:06 +0000589 vga_putcharxy(s->ds, x, y2, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000590 &(c->t_attrib));
pbrook14778c22009-01-21 03:02:52 +0000591 invalidate_xy(s, x, y2);
bellarde7f0ad52004-07-14 17:28:59 +0000592 }
593 }
594}
595
596static void console_show_cursor(TextConsole *s, int show)
597{
598 TextCell *c;
599 int y, y1;
600
601 if (s == active_console) {
thsed8276a2007-02-10 22:37:56 +0000602 int x = s->x;
balrog4d3b6f62008-02-10 16:33:14 +0000603
aliguori0e1f5a02008-11-24 19:29:13 +0000604 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000605 s->cursor_invalidate = 1;
606 return;
607 }
608
thsed8276a2007-02-10 22:37:56 +0000609 if (x >= s->width) {
610 x = s->width - 1;
611 }
bellarde7f0ad52004-07-14 17:28:59 +0000612 y1 = (s->y_base + s->y) % s->total_height;
613 y = y1 - s->y_displayed;
614 if (y < 0)
615 y += s->total_height;
616 if (y < s->height) {
thsed8276a2007-02-10 22:37:56 +0000617 c = &s->cells[y1 * s->width + x];
bellarde7f0ad52004-07-14 17:28:59 +0000618 if (show) {
pbrook6d6f7c22006-03-11 15:35:30 +0000619 TextAttributes t_attrib = s->t_attrib_default;
620 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
thsed8276a2007-02-10 22:37:56 +0000621 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
bellarde7f0ad52004-07-14 17:28:59 +0000622 } else {
thsed8276a2007-02-10 22:37:56 +0000623 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000624 }
pbrook14778c22009-01-21 03:02:52 +0000625 invalidate_xy(s, x, y);
bellarde7f0ad52004-07-14 17:28:59 +0000626 }
627 }
628}
629
630static void console_refresh(TextConsole *s)
631{
632 TextCell *c;
633 int x, y, y1;
634
ths5fafdf22007-09-16 21:08:06 +0000635 if (s != active_console)
bellarde7f0ad52004-07-14 17:28:59 +0000636 return;
aliguori0e1f5a02008-11-24 19:29:13 +0000637 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000638 s->text_x[0] = 0;
639 s->text_y[0] = 0;
640 s->text_x[1] = s->width - 1;
641 s->text_y[1] = s->height - 1;
642 s->cursor_invalidate = 1;
643 return;
644 }
bellarde7f0ad52004-07-14 17:28:59 +0000645
aliguori0e1f5a02008-11-24 19:29:13 +0000646 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
pbrook6d6f7c22006-03-11 15:35:30 +0000647 color_table[0][COLOR_BLACK]);
bellarde7f0ad52004-07-14 17:28:59 +0000648 y1 = s->y_displayed;
649 for(y = 0; y < s->height; y++) {
650 c = s->cells + y1 * s->width;
651 for(x = 0; x < s->width; x++) {
ths5fafdf22007-09-16 21:08:06 +0000652 vga_putcharxy(s->ds, x, y, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000653 &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000654 c++;
655 }
656 if (++y1 == s->total_height)
657 y1 = 0;
658 }
bellarde7f0ad52004-07-14 17:28:59 +0000659 console_show_cursor(s, 1);
pbrook14778c22009-01-21 03:02:52 +0000660 dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
bellarde7f0ad52004-07-14 17:28:59 +0000661}
662
663static void console_scroll(int ydelta)
664{
665 TextConsole *s;
666 int i, y1;
ths3b46e622007-09-17 08:09:54 +0000667
bellarde7f0ad52004-07-14 17:28:59 +0000668 s = active_console;
thsaf3a9032007-07-11 23:14:59 +0000669 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +0000670 return;
671
672 if (ydelta > 0) {
673 for(i = 0; i < ydelta; i++) {
674 if (s->y_displayed == s->y_base)
675 break;
676 if (++s->y_displayed == s->total_height)
677 s->y_displayed = 0;
678 }
679 } else {
680 ydelta = -ydelta;
681 i = s->backscroll_height;
682 if (i > s->total_height - s->height)
683 i = s->total_height - s->height;
684 y1 = s->y_base - i;
685 if (y1 < 0)
686 y1 += s->total_height;
687 for(i = 0; i < ydelta; i++) {
688 if (s->y_displayed == y1)
689 break;
690 if (--s->y_displayed < 0)
691 s->y_displayed = s->total_height - 1;
692 }
693 }
694 console_refresh(s);
695}
696
697static void console_put_lf(TextConsole *s)
698{
699 TextCell *c;
700 int x, y1;
701
bellarde7f0ad52004-07-14 17:28:59 +0000702 s->y++;
703 if (s->y >= s->height) {
704 s->y = s->height - 1;
pbrook6d6f7c22006-03-11 15:35:30 +0000705
bellarde7f0ad52004-07-14 17:28:59 +0000706 if (s->y_displayed == s->y_base) {
707 if (++s->y_displayed == s->total_height)
708 s->y_displayed = 0;
709 }
710 if (++s->y_base == s->total_height)
711 s->y_base = 0;
712 if (s->backscroll_height < s->total_height)
713 s->backscroll_height++;
714 y1 = (s->y_base + s->height - 1) % s->total_height;
715 c = &s->cells[y1 * s->width];
716 for(x = 0; x < s->width; x++) {
717 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000718 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000719 c++;
720 }
721 if (s == active_console && s->y_displayed == s->y_base) {
aliguori0e1f5a02008-11-24 19:29:13 +0000722 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000723 s->text_x[0] = 0;
724 s->text_y[0] = 0;
725 s->text_x[1] = s->width - 1;
726 s->text_y[1] = s->height - 1;
727 return;
728 }
729
ths5fafdf22007-09-16 21:08:06 +0000730 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
731 s->width * FONT_WIDTH,
bellarde7f0ad52004-07-14 17:28:59 +0000732 (s->height - 1) * FONT_HEIGHT);
733 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
ths5fafdf22007-09-16 21:08:06 +0000734 s->width * FONT_WIDTH, FONT_HEIGHT,
pbrook6d6f7c22006-03-11 15:35:30 +0000735 color_table[0][s->t_attrib_default.bgcol]);
pbrook14778c22009-01-21 03:02:52 +0000736 s->update_x0 = 0;
737 s->update_y0 = 0;
738 s->update_x1 = s->width * FONT_WIDTH;
739 s->update_y1 = s->height * FONT_HEIGHT;
bellarde7f0ad52004-07-14 17:28:59 +0000740 }
741 }
742}
743
pbrook6d6f7c22006-03-11 15:35:30 +0000744/* Set console attributes depending on the current escape codes.
745 * NOTE: I know this code is not very efficient (checking every color for it
746 * self) but it is more readable and better maintainable.
747 */
748static void console_handle_escape(TextConsole *s)
749{
750 int i;
751
pbrook6d6f7c22006-03-11 15:35:30 +0000752 for (i=0; i<s->nb_esc_params; i++) {
753 switch (s->esc_params[i]) {
754 case 0: /* reset all console attributes to default */
755 s->t_attrib = s->t_attrib_default;
756 break;
757 case 1:
758 s->t_attrib.bold = 1;
759 break;
760 case 4:
761 s->t_attrib.uline = 1;
762 break;
763 case 5:
764 s->t_attrib.blink = 1;
765 break;
766 case 7:
767 s->t_attrib.invers = 1;
768 break;
769 case 8:
770 s->t_attrib.unvisible = 1;
771 break;
772 case 22:
773 s->t_attrib.bold = 0;
774 break;
775 case 24:
776 s->t_attrib.uline = 0;
777 break;
778 case 25:
779 s->t_attrib.blink = 0;
780 break;
781 case 27:
782 s->t_attrib.invers = 0;
783 break;
784 case 28:
785 s->t_attrib.unvisible = 0;
786 break;
787 /* set foreground color */
788 case 30:
789 s->t_attrib.fgcol=COLOR_BLACK;
790 break;
791 case 31:
792 s->t_attrib.fgcol=COLOR_RED;
793 break;
794 case 32:
795 s->t_attrib.fgcol=COLOR_GREEN;
796 break;
797 case 33:
798 s->t_attrib.fgcol=COLOR_YELLOW;
799 break;
800 case 34:
801 s->t_attrib.fgcol=COLOR_BLUE;
802 break;
803 case 35:
804 s->t_attrib.fgcol=COLOR_MAGENTA;
805 break;
806 case 36:
807 s->t_attrib.fgcol=COLOR_CYAN;
808 break;
809 case 37:
810 s->t_attrib.fgcol=COLOR_WHITE;
811 break;
812 /* set background color */
813 case 40:
814 s->t_attrib.bgcol=COLOR_BLACK;
815 break;
816 case 41:
817 s->t_attrib.bgcol=COLOR_RED;
818 break;
819 case 42:
820 s->t_attrib.bgcol=COLOR_GREEN;
821 break;
822 case 43:
823 s->t_attrib.bgcol=COLOR_YELLOW;
824 break;
825 case 44:
826 s->t_attrib.bgcol=COLOR_BLUE;
827 break;
828 case 45:
829 s->t_attrib.bgcol=COLOR_MAGENTA;
830 break;
831 case 46:
832 s->t_attrib.bgcol=COLOR_CYAN;
833 break;
834 case 47:
835 s->t_attrib.bgcol=COLOR_WHITE;
836 break;
837 }
838 }
839}
840
thsadb47962007-01-16 23:02:36 +0000841static void console_clear_xy(TextConsole *s, int x, int y)
842{
843 int y1 = (s->y_base + y) % s->total_height;
844 TextCell *c = &s->cells[y1 * s->width + x];
845 c->ch = ' ';
846 c->t_attrib = s->t_attrib_default;
thsadb47962007-01-16 23:02:36 +0000847 update_xy(s, x, y);
848}
849
bellarde7f0ad52004-07-14 17:28:59 +0000850static void console_putchar(TextConsole *s, int ch)
851{
852 TextCell *c;
thsadb47962007-01-16 23:02:36 +0000853 int y1, i;
854 int x, y;
bellarde7f0ad52004-07-14 17:28:59 +0000855
856 switch(s->state) {
857 case TTY_STATE_NORM:
858 switch(ch) {
pbrook6d6f7c22006-03-11 15:35:30 +0000859 case '\r': /* carriage return */
bellarde7f0ad52004-07-14 17:28:59 +0000860 s->x = 0;
861 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000862 case '\n': /* newline */
bellarde7f0ad52004-07-14 17:28:59 +0000863 console_put_lf(s);
864 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000865 case '\b': /* backspace */
ths5fafdf22007-09-16 21:08:06 +0000866 if (s->x > 0)
bellarde15d7372006-06-25 16:26:29 +0000867 s->x--;
pbrook6d6f7c22006-03-11 15:35:30 +0000868 break;
869 case '\t': /* tabspace */
870 if (s->x + (8 - (s->x % 8)) > s->width) {
bellardbd468842006-07-14 20:24:31 +0000871 s->x = 0;
pbrook6d6f7c22006-03-11 15:35:30 +0000872 console_put_lf(s);
873 } else {
874 s->x = s->x + (8 - (s->x % 8));
875 }
876 break;
877 case '\a': /* alert aka. bell */
878 /* TODO: has to be implemented */
879 break;
thsadb47962007-01-16 23:02:36 +0000880 case 14:
881 /* SI (shift in), character set 0 (ignored) */
882 break;
883 case 15:
884 /* SO (shift out), character set 1 (ignored) */
885 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000886 case 27: /* esc (introducing an escape sequence) */
bellarde7f0ad52004-07-14 17:28:59 +0000887 s->state = TTY_STATE_ESC;
888 break;
889 default:
thsed8276a2007-02-10 22:37:56 +0000890 if (s->x >= s->width) {
891 /* line wrap */
892 s->x = 0;
893 console_put_lf(s);
thsadb47962007-01-16 23:02:36 +0000894 }
bellarde7f0ad52004-07-14 17:28:59 +0000895 y1 = (s->y_base + s->y) % s->total_height;
896 c = &s->cells[y1 * s->width + s->x];
897 c->ch = ch;
pbrook6d6f7c22006-03-11 15:35:30 +0000898 c->t_attrib = s->t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +0000899 update_xy(s, s->x, s->y);
900 s->x++;
bellarde7f0ad52004-07-14 17:28:59 +0000901 break;
902 }
903 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000904 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
bellarde7f0ad52004-07-14 17:28:59 +0000905 if (ch == '[') {
906 for(i=0;i<MAX_ESC_PARAMS;i++)
907 s->esc_params[i] = 0;
908 s->nb_esc_params = 0;
909 s->state = TTY_STATE_CSI;
910 } else {
911 s->state = TTY_STATE_NORM;
912 }
913 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000914 case TTY_STATE_CSI: /* handle escape sequence parameters */
bellarde7f0ad52004-07-14 17:28:59 +0000915 if (ch >= '0' && ch <= '9') {
916 if (s->nb_esc_params < MAX_ESC_PARAMS) {
ths5fafdf22007-09-16 21:08:06 +0000917 s->esc_params[s->nb_esc_params] =
bellarde7f0ad52004-07-14 17:28:59 +0000918 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
919 }
920 } else {
921 s->nb_esc_params++;
922 if (ch == ';')
923 break;
thsadb47962007-01-16 23:02:36 +0000924#ifdef DEBUG_CONSOLE
925 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
926 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
927#endif
bellarde7f0ad52004-07-14 17:28:59 +0000928 s->state = TTY_STATE_NORM;
929 switch(ch) {
thsadb47962007-01-16 23:02:36 +0000930 case 'A':
931 /* move cursor up */
932 if (s->esc_params[0] == 0) {
933 s->esc_params[0] = 1;
934 }
935 s->y -= s->esc_params[0];
936 if (s->y < 0) {
937 s->y = 0;
bellarde7f0ad52004-07-14 17:28:59 +0000938 }
939 break;
thsadb47962007-01-16 23:02:36 +0000940 case 'B':
941 /* move cursor down */
942 if (s->esc_params[0] == 0) {
943 s->esc_params[0] = 1;
944 }
945 s->y += s->esc_params[0];
946 if (s->y >= s->height) {
947 s->y = s->height - 1;
948 }
949 break;
950 case 'C':
951 /* move cursor right */
952 if (s->esc_params[0] == 0) {
953 s->esc_params[0] = 1;
954 }
955 s->x += s->esc_params[0];
956 if (s->x >= s->width) {
957 s->x = s->width - 1;
958 }
959 break;
960 case 'D':
961 /* move cursor left */
962 if (s->esc_params[0] == 0) {
963 s->esc_params[0] = 1;
964 }
965 s->x -= s->esc_params[0];
966 if (s->x < 0) {
967 s->x = 0;
968 }
969 break;
970 case 'G':
971 /* move cursor to column */
972 s->x = s->esc_params[0] - 1;
973 if (s->x < 0) {
974 s->x = 0;
975 }
976 break;
977 case 'f':
978 case 'H':
979 /* move cursor to row, column */
980 s->x = s->esc_params[1] - 1;
981 if (s->x < 0) {
982 s->x = 0;
983 }
984 s->y = s->esc_params[0] - 1;
985 if (s->y < 0) {
986 s->y = 0;
987 }
988 break;
989 case 'J':
990 switch (s->esc_params[0]) {
991 case 0:
992 /* clear to end of screen */
993 for (y = s->y; y < s->height; y++) {
994 for (x = 0; x < s->width; x++) {
995 if (y == s->y && x < s->x) {
996 continue;
997 }
998 console_clear_xy(s, x, y);
999 }
1000 }
1001 break;
1002 case 1:
1003 /* clear from beginning of screen */
1004 for (y = 0; y <= s->y; y++) {
1005 for (x = 0; x < s->width; x++) {
1006 if (y == s->y && x > s->x) {
1007 break;
1008 }
1009 console_clear_xy(s, x, y);
1010 }
1011 }
1012 break;
1013 case 2:
1014 /* clear entire screen */
1015 for (y = 0; y <= s->height; y++) {
1016 for (x = 0; x < s->width; x++) {
1017 console_clear_xy(s, x, y);
1018 }
1019 }
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001020 break;
thsadb47962007-01-16 23:02:36 +00001021 }
Markus Armbruster95d8f9f2011-11-22 11:59:07 +01001022 break;
thsadb47962007-01-16 23:02:36 +00001023 case 'K':
1024 switch (s->esc_params[0]) {
1025 case 0:
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001026 /* clear to eol */
1027 for(x = s->x; x < s->width; x++) {
thsadb47962007-01-16 23:02:36 +00001028 console_clear_xy(s, x, s->y);
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001029 }
1030 break;
thsadb47962007-01-16 23:02:36 +00001031 case 1:
1032 /* clear from beginning of line */
1033 for (x = 0; x <= s->x; x++) {
1034 console_clear_xy(s, x, s->y);
1035 }
1036 break;
1037 case 2:
1038 /* clear entire line */
1039 for(x = 0; x < s->width; x++) {
1040 console_clear_xy(s, x, s->y);
1041 }
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001042 break;
1043 }
thsadb47962007-01-16 23:02:36 +00001044 break;
1045 case 'm':
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001046 console_handle_escape(s);
1047 break;
thsadb47962007-01-16 23:02:36 +00001048 case 'n':
1049 /* report cursor position */
1050 /* TODO: send ESC[row;colR */
1051 break;
1052 case 's':
1053 /* save cursor position */
1054 s->x_saved = s->x;
1055 s->y_saved = s->y;
1056 break;
1057 case 'u':
1058 /* restore cursor position */
1059 s->x = s->x_saved;
1060 s->y = s->y_saved;
1061 break;
1062 default:
1063#ifdef DEBUG_CONSOLE
1064 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1065#endif
1066 break;
1067 }
1068 break;
bellarde7f0ad52004-07-14 17:28:59 +00001069 }
1070 }
1071}
1072
1073void console_select(unsigned int index)
1074{
1075 TextConsole *s;
pbrook6d6f7c22006-03-11 15:35:30 +00001076
bellarde7f0ad52004-07-14 17:28:59 +00001077 if (index >= MAX_CONSOLES)
1078 return;
Stefan Hajnoczi358664c2010-09-20 14:11:19 +01001079 if (active_console) {
1080 active_console->g_width = ds_get_width(active_console->ds);
1081 active_console->g_height = ds_get_height(active_console->ds);
1082 }
bellarde7f0ad52004-07-14 17:28:59 +00001083 s = consoles[index];
1084 if (s) {
aliguori7d957bd2009-01-15 22:14:11 +00001085 DisplayState *ds = s->ds;
bellarde7f0ad52004-07-14 17:28:59 +00001086 active_console = s;
aliguori68f00992009-01-21 18:59:12 +00001087 if (ds_get_bits_per_pixel(s->ds)) {
aliguori7b5d76d2009-03-13 15:02:13 +00001088 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
aliguori68f00992009-01-21 18:59:12 +00001089 } else {
1090 s->ds->surface->width = s->width;
1091 s->ds->surface->height = s->height;
1092 }
aliguori7d957bd2009-01-15 22:14:11 +00001093 dpy_resize(s->ds);
balrog4d3b6f62008-02-10 16:33:14 +00001094 vga_hw_invalidate();
bellarde7f0ad52004-07-14 17:28:59 +00001095 }
1096}
1097
1098static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1099{
1100 TextConsole *s = chr->opaque;
1101 int i;
1102
pbrook14778c22009-01-21 03:02:52 +00001103 s->update_x0 = s->width * FONT_WIDTH;
1104 s->update_y0 = s->height * FONT_HEIGHT;
1105 s->update_x1 = 0;
1106 s->update_y1 = 0;
bellarde7f0ad52004-07-14 17:28:59 +00001107 console_show_cursor(s, 0);
1108 for(i = 0; i < len; i++) {
1109 console_putchar(s, buf[i]);
1110 }
1111 console_show_cursor(s, 1);
pbrook14778c22009-01-21 03:02:52 +00001112 if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1113 dpy_update(s->ds, s->update_x0, s->update_y0,
1114 s->update_x1 - s->update_x0,
1115 s->update_y1 - s->update_y0);
1116 }
bellarde7f0ad52004-07-14 17:28:59 +00001117 return len;
1118}
1119
bellarde15d7372006-06-25 16:26:29 +00001120static void kbd_send_chars(void *opaque)
1121{
1122 TextConsole *s = opaque;
1123 int len;
1124 uint8_t buf[16];
ths3b46e622007-09-17 08:09:54 +00001125
Anthony Liguori909cda12011-08-15 11:17:31 -05001126 len = qemu_chr_be_can_write(s->chr);
bellarde15d7372006-06-25 16:26:29 +00001127 if (len > s->out_fifo.count)
1128 len = s->out_fifo.count;
1129 if (len > 0) {
1130 if (len > sizeof(buf))
1131 len = sizeof(buf);
1132 qemu_fifo_read(&s->out_fifo, buf, len);
Anthony Liguorifa5efcc2011-08-15 11:17:30 -05001133 qemu_chr_be_write(s->chr, buf, len);
bellarde15d7372006-06-25 16:26:29 +00001134 }
1135 /* characters are pending: we send them a bit later (XXX:
1136 horrible, should change char device API) */
1137 if (s->out_fifo.count > 0) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001138 qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
bellarde15d7372006-06-25 16:26:29 +00001139 }
1140}
1141
bellarde7f0ad52004-07-14 17:28:59 +00001142/* called when an ascii key is pressed */
1143void kbd_put_keysym(int keysym)
1144{
1145 TextConsole *s;
1146 uint8_t buf[16], *q;
1147 int c;
1148
1149 s = active_console;
thsaf3a9032007-07-11 23:14:59 +00001150 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +00001151 return;
1152
1153 switch(keysym) {
1154 case QEMU_KEY_CTRL_UP:
1155 console_scroll(-1);
1156 break;
1157 case QEMU_KEY_CTRL_DOWN:
1158 console_scroll(1);
1159 break;
1160 case QEMU_KEY_CTRL_PAGEUP:
1161 console_scroll(-10);
1162 break;
1163 case QEMU_KEY_CTRL_PAGEDOWN:
1164 console_scroll(10);
1165 break;
1166 default:
bellarde15d7372006-06-25 16:26:29 +00001167 /* convert the QEMU keysym to VT100 key string */
1168 q = buf;
1169 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1170 *q++ = '\033';
1171 *q++ = '[';
1172 c = keysym - 0xe100;
1173 if (c >= 10)
1174 *q++ = '0' + (c / 10);
1175 *q++ = '0' + (c % 10);
1176 *q++ = '~';
1177 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1178 *q++ = '\033';
1179 *q++ = '[';
1180 *q++ = keysym & 0xff;
Paolo Bonzini41048332010-12-23 13:42:52 +01001181 } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1182 console_puts(s->chr, (const uint8_t *) "\r", 1);
1183 *q++ = '\n';
bellarde15d7372006-06-25 16:26:29 +00001184 } else {
Paolo Bonzini41048332010-12-23 13:42:52 +01001185 *q++ = keysym;
1186 }
1187 if (s->echo) {
1188 console_puts(s->chr, buf, q - buf);
bellarde15d7372006-06-25 16:26:29 +00001189 }
pbrooke5b0bc42007-01-27 23:46:43 +00001190 if (s->chr->chr_read) {
bellarde15d7372006-06-25 16:26:29 +00001191 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1192 kbd_send_chars(s);
bellarde7f0ad52004-07-14 17:28:59 +00001193 }
1194 break;
1195 }
1196}
1197
balrog4d3b6f62008-02-10 16:33:14 +00001198static void text_console_invalidate(void *opaque)
1199{
1200 TextConsole *s = (TextConsole *) opaque;
aliguori68f00992009-01-21 18:59:12 +00001201 if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1202 s->g_width = ds_get_width(s->ds);
1203 s->g_height = ds_get_height(s->ds);
1204 text_console_resize(s);
1205 }
balrog4d3b6f62008-02-10 16:33:14 +00001206 console_refresh(s);
1207}
1208
Anthony Liguoric227f092009-10-01 16:12:16 -05001209static void text_console_update(void *opaque, console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +00001210{
1211 TextConsole *s = (TextConsole *) opaque;
1212 int i, j, src;
1213
1214 if (s->text_x[0] <= s->text_x[1]) {
1215 src = (s->y_base + s->text_y[0]) * s->width;
1216 chardata += s->text_y[0] * s->width;
1217 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1218 for (j = 0; j < s->width; j ++, src ++)
1219 console_write_ch(chardata ++, s->cells[src].ch |
1220 (s->cells[src].t_attrib.fgcol << 12) |
1221 (s->cells[src].t_attrib.bgcol << 8) |
1222 (s->cells[src].t_attrib.bold << 21));
1223 dpy_update(s->ds, s->text_x[0], s->text_y[0],
1224 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1225 s->text_x[0] = s->width;
1226 s->text_y[0] = s->height;
1227 s->text_x[1] = 0;
1228 s->text_y[1] = 0;
1229 }
1230 if (s->cursor_invalidate) {
1231 dpy_cursor(s->ds, s->x, s->y);
1232 s->cursor_invalidate = 0;
1233 }
1234}
1235
aliguori42aa98e2009-01-16 21:01:48 +00001236static TextConsole *get_graphic_console(DisplayState *ds)
blueswir1a147d622009-01-16 19:41:04 +00001237{
aliguori3023f332009-01-16 19:04:14 +00001238 int i;
1239 TextConsole *s;
1240 for (i = 0; i < nb_consoles; i++) {
1241 s = consoles[i];
aliguori42aa98e2009-01-16 21:01:48 +00001242 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
aliguori3023f332009-01-16 19:04:14 +00001243 return s;
1244 }
1245 return NULL;
1246}
1247
Anthony Liguoric227f092009-10-01 16:12:16 -05001248static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
bellarde7f0ad52004-07-14 17:28:59 +00001249{
1250 TextConsole *s;
pbrook95219892006-04-09 01:06:34 +00001251 int i;
bellarde7f0ad52004-07-14 17:28:59 +00001252
1253 if (nb_consoles >= MAX_CONSOLES)
1254 return NULL;
Anthony Liguori7267c092011-08-20 22:09:37 -05001255 s = g_malloc0(sizeof(TextConsole));
thsaf3a9032007-07-11 23:14:59 +00001256 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1257 (console_type == GRAPHIC_CONSOLE))) {
bellarde7f0ad52004-07-14 17:28:59 +00001258 active_console = s;
thsaf3a9032007-07-11 23:14:59 +00001259 }
bellarde7f0ad52004-07-14 17:28:59 +00001260 s->ds = ds;
thsaf3a9032007-07-11 23:14:59 +00001261 s->console_type = console_type;
1262 if (console_type != GRAPHIC_CONSOLE) {
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001263 s->index = nb_consoles;
pbrook95219892006-04-09 01:06:34 +00001264 consoles[nb_consoles++] = s;
1265 } else {
1266 /* HACK: Put graphical consoles before text consoles. */
1267 for (i = nb_consoles; i > 0; i--) {
thsaf3a9032007-07-11 23:14:59 +00001268 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
pbrook95219892006-04-09 01:06:34 +00001269 break;
1270 consoles[i] = consoles[i - 1];
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001271 consoles[i]->index = i;
pbrook95219892006-04-09 01:06:34 +00001272 }
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001273 s->index = i;
pbrook95219892006-04-09 01:06:34 +00001274 consoles[i] = s;
aliguori3023f332009-01-16 19:04:14 +00001275 nb_consoles++;
pbrook95219892006-04-09 01:06:34 +00001276 }
bellarde7f0ad52004-07-14 17:28:59 +00001277 return s;
1278}
1279
Paolo Bonzini98b50082010-02-11 00:29:57 +01001280static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1281{
Anthony Liguori7267c092011-08-20 22:09:37 -05001282 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
Paolo Bonzini98b50082010-02-11 00:29:57 +01001283
Jes Sorensenffe8b822011-03-16 13:33:30 +01001284 int linesize = width * 4;
1285 qemu_alloc_display(surface, width, height, linesize,
1286 qemu_default_pixelformat(32), 0);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001287 return surface;
1288}
1289
1290static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1291 int width, int height)
1292{
Jes Sorensenffe8b822011-03-16 13:33:30 +01001293 int linesize = width * 4;
1294 qemu_alloc_display(surface, width, height, linesize,
1295 qemu_default_pixelformat(32), 0);
1296 return surface;
1297}
1298
1299void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1300 int linesize, PixelFormat pf, int newflags)
1301{
1302 void *data;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001303 surface->width = width;
1304 surface->height = height;
Jes Sorensenffe8b822011-03-16 13:33:30 +01001305 surface->linesize = linesize;
1306 surface->pf = pf;
1307 if (surface->flags & QEMU_ALLOCATED_FLAG) {
Anthony Liguori7267c092011-08-20 22:09:37 -05001308 data = g_realloc(surface->data,
Jes Sorensenffe8b822011-03-16 13:33:30 +01001309 surface->linesize * surface->height);
1310 } else {
Anthony Liguori7267c092011-08-20 22:09:37 -05001311 data = g_malloc(surface->linesize * surface->height);
Jes Sorensenffe8b822011-03-16 13:33:30 +01001312 }
1313 surface->data = (uint8_t *)data;
1314 surface->flags = newflags | QEMU_ALLOCATED_FLAG;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001315#ifdef HOST_WORDS_BIGENDIAN
Jes Sorensenffe8b822011-03-16 13:33:30 +01001316 surface->flags |= QEMU_BIG_ENDIAN_FLAG;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001317#endif
Paolo Bonzini98b50082010-02-11 00:29:57 +01001318}
1319
1320DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1321 int linesize, uint8_t *data)
1322{
Anthony Liguori7267c092011-08-20 22:09:37 -05001323 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
Paolo Bonzini98b50082010-02-11 00:29:57 +01001324
1325 surface->width = width;
1326 surface->height = height;
1327 surface->linesize = linesize;
1328 surface->pf = qemu_default_pixelformat(bpp);
1329#ifdef HOST_WORDS_BIGENDIAN
1330 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1331#endif
1332 surface->data = data;
1333
1334 return surface;
1335}
1336
1337static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1338{
1339 if (surface == NULL)
1340 return;
1341 if (surface->flags & QEMU_ALLOCATED_FLAG)
Anthony Liguori7267c092011-08-20 22:09:37 -05001342 g_free(surface->data);
1343 g_free(surface);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001344}
1345
1346static struct DisplayAllocator default_allocator = {
1347 defaultallocator_create_displaysurface,
1348 defaultallocator_resize_displaysurface,
1349 defaultallocator_free_displaysurface
1350};
1351
1352static void dumb_display_init(void)
1353{
Anthony Liguori7267c092011-08-20 22:09:37 -05001354 DisplayState *ds = g_malloc0(sizeof(DisplayState));
Jan Kiszka18026512011-06-19 11:53:02 +02001355 int width = 640;
1356 int height = 480;
1357
Paolo Bonzini98b50082010-02-11 00:29:57 +01001358 ds->allocator = &default_allocator;
Jan Kiszka18026512011-06-19 11:53:02 +02001359 if (is_fixedsize_console()) {
1360 width = active_console->g_width;
1361 height = active_console->g_height;
1362 }
1363 ds->surface = qemu_create_displaysurface(ds, width, height);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001364 register_displaystate(ds);
1365}
1366
1367/***********************************************************/
1368/* register display */
1369
1370void register_displaystate(DisplayState *ds)
1371{
1372 DisplayState **s;
1373 s = &display_state;
1374 while (*s != NULL)
1375 s = &(*s)->next;
1376 ds->next = NULL;
1377 *s = ds;
1378}
1379
1380DisplayState *get_displaystate(void)
1381{
1382 if (!display_state) {
1383 dumb_display_init ();
1384 }
1385 return display_state;
1386}
1387
1388DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1389{
1390 if(ds->allocator == &default_allocator) {
1391 DisplaySurface *surf;
1392 surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1393 defaultallocator_free_displaysurface(ds->surface);
1394 ds->surface = surf;
1395 ds->allocator = da;
1396 }
1397 return ds->allocator;
1398}
1399
aliguori3023f332009-01-16 19:04:14 +00001400DisplayState *graphic_console_init(vga_hw_update_ptr update,
1401 vga_hw_invalidate_ptr invalidate,
1402 vga_hw_screen_dump_ptr screen_dump,
1403 vga_hw_text_update_ptr text_update,
1404 void *opaque)
bellarde7f0ad52004-07-14 17:28:59 +00001405{
pbrook95219892006-04-09 01:06:34 +00001406 TextConsole *s;
aliguori3023f332009-01-16 19:04:14 +00001407 DisplayState *ds;
aurel32f0f2f972009-01-16 21:13:49 +00001408
Anthony Liguori7267c092011-08-20 22:09:37 -05001409 ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
aliguori7b5d76d2009-03-13 15:02:13 +00001410 ds->allocator = &default_allocator;
1411 ds->surface = qemu_create_displaysurface(ds, 640, 480);
pbrook95219892006-04-09 01:06:34 +00001412
thsaf3a9032007-07-11 23:14:59 +00001413 s = new_console(ds, GRAPHIC_CONSOLE);
aliguori3023f332009-01-16 19:04:14 +00001414 if (s == NULL) {
aliguori7b5d76d2009-03-13 15:02:13 +00001415 qemu_free_displaysurface(ds);
Anthony Liguori7267c092011-08-20 22:09:37 -05001416 g_free(ds);
aliguori3023f332009-01-16 19:04:14 +00001417 return NULL;
1418 }
pbrook95219892006-04-09 01:06:34 +00001419 s->hw_update = update;
1420 s->hw_invalidate = invalidate;
1421 s->hw_screen_dump = screen_dump;
balrog4d3b6f62008-02-10 16:33:14 +00001422 s->hw_text_update = text_update;
pbrook95219892006-04-09 01:06:34 +00001423 s->hw = opaque;
aliguori3023f332009-01-16 19:04:14 +00001424
aurel32f0f2f972009-01-16 21:13:49 +00001425 register_displaystate(ds);
aliguori3023f332009-01-16 19:04:14 +00001426 return ds;
pbrook95219892006-04-09 01:06:34 +00001427}
1428
1429int is_graphic_console(void)
1430{
balrog4d3b6f62008-02-10 16:33:14 +00001431 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
bellarde7f0ad52004-07-14 17:28:59 +00001432}
1433
balrogc21bbcf2008-09-24 03:32:33 +00001434int is_fixedsize_console(void)
1435{
1436 return active_console && active_console->console_type != TEXT_CONSOLE;
1437}
1438
balroga528b802007-10-30 22:38:53 +00001439void console_color_init(DisplayState *ds)
1440{
1441 int i, j;
1442 for (j = 0; j < 2; j++) {
1443 for (i = 0; i < 8; i++) {
aurel32f0f2f972009-01-16 21:13:49 +00001444 color_table[j][i] = col_expand(ds,
balroga528b802007-10-30 22:38:53 +00001445 vga_get_color(ds, color_table_rgb[j][i]));
1446 }
1447 }
1448}
1449
Paolo Bonzini41048332010-12-23 13:42:52 +01001450static void text_console_set_echo(CharDriverState *chr, bool echo)
1451{
1452 TextConsole *s = chr->opaque;
1453
1454 s->echo = echo;
1455}
1456
Paolo Bonzini44b37b92010-12-23 13:42:53 +01001457static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
bellarde7f0ad52004-07-14 17:28:59 +00001458{
bellarde7f0ad52004-07-14 17:28:59 +00001459 TextConsole *s;
bellarde7f0ad52004-07-14 17:28:59 +00001460 static int color_inited;
pbrook6d6f7c22006-03-11 15:35:30 +00001461
Paolo Bonzini491e1142010-12-23 13:42:51 +01001462 s = chr->opaque;
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001463
bellarde7f0ad52004-07-14 17:28:59 +00001464 chr->chr_write = console_puts;
bellard6fcfafb2004-08-01 21:48:30 +00001465
bellarde15d7372006-06-25 16:26:29 +00001466 s->out_fifo.buf = s->out_fifo_buf;
1467 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001468 s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
aliguori3023f332009-01-16 19:04:14 +00001469 s->ds = ds;
ths3b46e622007-09-17 08:09:54 +00001470
bellarde7f0ad52004-07-14 17:28:59 +00001471 if (!color_inited) {
1472 color_inited = 1;
balroga528b802007-10-30 22:38:53 +00001473 console_color_init(s->ds);
bellarde7f0ad52004-07-14 17:28:59 +00001474 }
1475 s->y_displayed = 0;
1476 s->y_base = 0;
1477 s->total_height = DEFAULT_BACKSCROLL;
1478 s->x = 0;
1479 s->y = 0;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001480 if (s->console_type == TEXT_CONSOLE) {
1481 s->g_width = ds_get_width(s->ds);
1482 s->g_height = ds_get_height(s->ds);
1483 }
pbrook6d6f7c22006-03-11 15:35:30 +00001484
balrog4d3b6f62008-02-10 16:33:14 +00001485 s->hw_invalidate = text_console_invalidate;
1486 s->hw_text_update = text_console_update;
1487 s->hw = s;
1488
pbrook6d6f7c22006-03-11 15:35:30 +00001489 /* Set text attribute defaults */
1490 s->t_attrib_default.bold = 0;
1491 s->t_attrib_default.uline = 0;
1492 s->t_attrib_default.blink = 0;
1493 s->t_attrib_default.invers = 0;
1494 s->t_attrib_default.unvisible = 0;
1495 s->t_attrib_default.fgcol = COLOR_WHITE;
1496 s->t_attrib_default.bgcol = COLOR_BLACK;
pbrook6d6f7c22006-03-11 15:35:30 +00001497 /* set current text attributes to default */
1498 s->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +00001499 text_console_resize(s);
1500
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001501 if (chr->label) {
1502 char msg[128];
1503 int len;
1504
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001505 s->t_attrib.bgcol = COLOR_BLUE;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001506 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1507 console_puts(chr, (uint8_t*)msg, len);
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001508 s->t_attrib = s->t_attrib_default;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001509 }
1510
Amit Shah127338e2009-11-03 19:59:56 +05301511 qemu_chr_generic_open(chr);
aurel32ceecf1d2009-01-18 14:08:04 +00001512 if (chr->init)
1513 chr->init(chr);
bellarde7f0ad52004-07-14 17:28:59 +00001514}
pbrookc60e08d2008-07-01 16:24:38 +00001515
Markus Armbruster1f514702012-02-07 15:09:08 +01001516CharDriverState *text_console_init(QemuOpts *opts)
aliguori2796dae2009-01-16 20:23:27 +00001517{
1518 CharDriverState *chr;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001519 TextConsole *s;
1520 unsigned width;
1521 unsigned height;
aliguori2796dae2009-01-16 20:23:27 +00001522
Anthony Liguori7267c092011-08-20 22:09:37 -05001523 chr = g_malloc0(sizeof(CharDriverState));
aliguori2796dae2009-01-16 20:23:27 +00001524
Paolo Bonzini491e1142010-12-23 13:42:51 +01001525 width = qemu_opt_get_number(opts, "width", 0);
1526 if (width == 0)
1527 width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1528
1529 height = qemu_opt_get_number(opts, "height", 0);
1530 if (height == 0)
1531 height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1532
1533 if (width == 0 || height == 0) {
1534 s = new_console(NULL, TEXT_CONSOLE);
1535 } else {
1536 s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1537 }
1538
1539 if (!s) {
Stefan Weil5354d082011-10-02 18:53:09 +02001540 g_free(chr);
Markus Armbruster1f514702012-02-07 15:09:08 +01001541 return NULL;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001542 }
1543
1544 s->chr = chr;
1545 s->g_width = width;
1546 s->g_height = height;
1547 chr->opaque = s;
Paolo Bonzini41048332010-12-23 13:42:52 +01001548 chr->chr_set_echo = text_console_set_echo;
Markus Armbruster1f514702012-02-07 15:09:08 +01001549 return chr;
aliguori2796dae2009-01-16 20:23:27 +00001550}
1551
1552void text_consoles_set_display(DisplayState *ds)
1553{
1554 int i;
1555
Markus Armbruster8811e1e2012-02-07 15:09:21 +01001556 for (i = 0; i < nb_consoles; i++) {
1557 if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1558 text_console_do_init(consoles[i]->chr, ds);
1559 }
aliguori2796dae2009-01-16 20:23:27 +00001560 }
aliguori2796dae2009-01-16 20:23:27 +00001561}
1562
aliguori3023f332009-01-16 19:04:14 +00001563void qemu_console_resize(DisplayState *ds, int width, int height)
pbrookc60e08d2008-07-01 16:24:38 +00001564{
aliguori42aa98e2009-01-16 21:01:48 +00001565 TextConsole *s = get_graphic_console(ds);
aliguorif497f142009-01-21 19:18:00 +00001566 if (!s) return;
1567
aliguori3023f332009-01-16 19:04:14 +00001568 s->g_width = width;
1569 s->g_height = height;
1570 if (is_graphic_console()) {
aliguori7b5d76d2009-03-13 15:02:13 +00001571 ds->surface = qemu_resize_displaysurface(ds, width, height);
aliguori3023f332009-01-16 19:04:14 +00001572 dpy_resize(ds);
pbrookc60e08d2008-07-01 16:24:38 +00001573 }
1574}
balrog38334f72008-09-24 02:21:24 +00001575
aliguori3023f332009-01-16 19:04:14 +00001576void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1577 int dst_x, int dst_y, int w, int h)
balrogc21bbcf2008-09-24 03:32:33 +00001578{
aliguori3023f332009-01-16 19:04:14 +00001579 if (is_graphic_console()) {
1580 dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
balrog38334f72008-09-24 02:21:24 +00001581 }
1582}
aliguori7d957bd2009-01-15 22:14:11 +00001583
malc0da2ea12009-01-23 19:56:19 +00001584PixelFormat qemu_different_endianness_pixelformat(int bpp)
aliguori7d957bd2009-01-15 22:14:11 +00001585{
1586 PixelFormat pf;
1587
1588 memset(&pf, 0x00, sizeof(PixelFormat));
1589
1590 pf.bits_per_pixel = bpp;
1591 pf.bytes_per_pixel = bpp / 8;
1592 pf.depth = bpp == 32 ? 24 : bpp;
1593
1594 switch (bpp) {
malc0da2ea12009-01-23 19:56:19 +00001595 case 24:
1596 pf.rmask = 0x000000FF;
1597 pf.gmask = 0x0000FF00;
1598 pf.bmask = 0x00FF0000;
1599 pf.rmax = 255;
1600 pf.gmax = 255;
1601 pf.bmax = 255;
1602 pf.rshift = 0;
1603 pf.gshift = 8;
1604 pf.bshift = 16;
aliguori90a1e3c2009-01-26 15:37:30 +00001605 pf.rbits = 8;
1606 pf.gbits = 8;
1607 pf.bbits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001608 break;
malc0da2ea12009-01-23 19:56:19 +00001609 case 32:
1610 pf.rmask = 0x0000FF00;
1611 pf.gmask = 0x00FF0000;
1612 pf.bmask = 0xFF000000;
1613 pf.amask = 0x00000000;
1614 pf.amax = 255;
1615 pf.rmax = 255;
1616 pf.gmax = 255;
1617 pf.bmax = 255;
1618 pf.ashift = 0;
1619 pf.rshift = 8;
1620 pf.gshift = 16;
1621 pf.bshift = 24;
aliguori90a1e3c2009-01-26 15:37:30 +00001622 pf.rbits = 8;
1623 pf.gbits = 8;
1624 pf.bbits = 8;
1625 pf.abits = 8;
malc0da2ea12009-01-23 19:56:19 +00001626 break;
1627 default:
1628 break;
1629 }
1630 return pf;
1631}
1632
1633PixelFormat qemu_default_pixelformat(int bpp)
1634{
1635 PixelFormat pf;
1636
1637 memset(&pf, 0x00, sizeof(PixelFormat));
1638
1639 pf.bits_per_pixel = bpp;
1640 pf.bytes_per_pixel = bpp / 8;
1641 pf.depth = bpp == 32 ? 24 : bpp;
1642
1643 switch (bpp) {
Gerd Hoffmannb6278082010-05-21 11:59:14 +02001644 case 15:
1645 pf.bits_per_pixel = 16;
1646 pf.bytes_per_pixel = 2;
1647 pf.rmask = 0x00007c00;
1648 pf.gmask = 0x000003E0;
1649 pf.bmask = 0x0000001F;
1650 pf.rmax = 31;
1651 pf.gmax = 31;
1652 pf.bmax = 31;
1653 pf.rshift = 10;
1654 pf.gshift = 5;
1655 pf.bshift = 0;
1656 pf.rbits = 5;
1657 pf.gbits = 5;
1658 pf.bbits = 5;
1659 break;
aliguori7d957bd2009-01-15 22:14:11 +00001660 case 16:
1661 pf.rmask = 0x0000F800;
1662 pf.gmask = 0x000007E0;
1663 pf.bmask = 0x0000001F;
1664 pf.rmax = 31;
1665 pf.gmax = 63;
1666 pf.bmax = 31;
1667 pf.rshift = 11;
1668 pf.gshift = 5;
1669 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001670 pf.rbits = 5;
1671 pf.gbits = 6;
1672 pf.bbits = 5;
aliguori7d957bd2009-01-15 22:14:11 +00001673 break;
1674 case 24:
aliguori7d957bd2009-01-15 22:14:11 +00001675 pf.rmask = 0x00FF0000;
1676 pf.gmask = 0x0000FF00;
1677 pf.bmask = 0x000000FF;
1678 pf.rmax = 255;
1679 pf.gmax = 255;
1680 pf.bmax = 255;
1681 pf.rshift = 16;
1682 pf.gshift = 8;
1683 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001684 pf.rbits = 8;
1685 pf.gbits = 8;
1686 pf.bbits = 8;
Markus Armbruster0eba62e2011-11-22 12:56:10 +01001687 break;
malc0da2ea12009-01-23 19:56:19 +00001688 case 32:
1689 pf.rmask = 0x00FF0000;
1690 pf.gmask = 0x0000FF00;
1691 pf.bmask = 0x000000FF;
1692 pf.amax = 255;
1693 pf.rmax = 255;
1694 pf.gmax = 255;
1695 pf.bmax = 255;
1696 pf.ashift = 24;
1697 pf.rshift = 16;
1698 pf.gshift = 8;
1699 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001700 pf.rbits = 8;
1701 pf.gbits = 8;
1702 pf.bbits = 8;
1703 pf.abits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001704 break;
1705 default:
1706 break;
1707 }
1708 return pf;
1709}