blob: f6fe44195be825e0e60a3ebff8df7e02d5890871 [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;
179
180 previous_active_console = active_console;
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200181
balrog8571c052008-07-19 13:04:26 +0000182 /* There is currently no way of specifying which screen we want to dump,
aurel327b455222008-09-02 00:09:16 +0000183 so always dump the first one. */
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200184 console_select(0);
185 if (consoles[0] && consoles[0]->hw_screen_dump) {
pbrook95219892006-04-09 01:06:34 +0000186 consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200187 }
188
189 console_select(previous_active_console->index);
pbrook95219892006-04-09 01:06:34 +0000190}
191
Anthony Liguoric227f092009-10-01 16:12:16 -0500192void vga_hw_text_update(console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +0000193{
194 if (active_console && active_console->hw_text_update)
195 active_console->hw_text_update(active_console->hw, chardata);
196}
197
bellarde7f0ad52004-07-14 17:28:59 +0000198/* convert a RGBA color to a color index usable in graphic primitives */
199static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
200{
201 unsigned int r, g, b, color;
202
aliguori0e1f5a02008-11-24 19:29:13 +0000203 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000204#if 0
205 case 8:
206 r = (rgba >> 16) & 0xff;
207 g = (rgba >> 8) & 0xff;
208 b = (rgba) & 0xff;
ths5fafdf22007-09-16 21:08:06 +0000209 color = (rgb_to_index[r] * 6 * 6) +
210 (rgb_to_index[g] * 6) +
bellarde7f0ad52004-07-14 17:28:59 +0000211 (rgb_to_index[b]);
212 break;
213#endif
214 case 15:
215 r = (rgba >> 16) & 0xff;
216 g = (rgba >> 8) & 0xff;
217 b = (rgba) & 0xff;
218 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
219 break;
220 case 16:
221 r = (rgba >> 16) & 0xff;
222 g = (rgba >> 8) & 0xff;
223 b = (rgba) & 0xff;
224 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
225 break;
226 case 32:
227 default:
228 color = rgba;
229 break;
230 }
231 return color;
232}
233
ths5fafdf22007-09-16 21:08:06 +0000234static void vga_fill_rect (DisplayState *ds,
bellarde7f0ad52004-07-14 17:28:59 +0000235 int posx, int posy, int width, int height, uint32_t color)
236{
237 uint8_t *d, *d1;
238 int x, y, bpp;
ths3b46e622007-09-17 08:09:54 +0000239
aliguori0e1f5a02008-11-24 19:29:13 +0000240 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
241 d1 = ds_get_data(ds) +
242 ds_get_linesize(ds) * posy + bpp * posx;
bellarde7f0ad52004-07-14 17:28:59 +0000243 for (y = 0; y < height; y++) {
244 d = d1;
245 switch(bpp) {
246 case 1:
247 for (x = 0; x < width; x++) {
248 *((uint8_t *)d) = color;
249 d++;
250 }
251 break;
252 case 2:
253 for (x = 0; x < width; x++) {
254 *((uint16_t *)d) = color;
255 d += 2;
256 }
257 break;
258 case 4:
259 for (x = 0; x < width; x++) {
260 *((uint32_t *)d) = color;
261 d += 4;
262 }
263 break;
264 }
aliguori0e1f5a02008-11-24 19:29:13 +0000265 d1 += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000266 }
267}
268
269/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
270static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
271{
272 const uint8_t *s;
273 uint8_t *d;
274 int wb, y, bpp;
275
aliguori0e1f5a02008-11-24 19:29:13 +0000276 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
bellarde7f0ad52004-07-14 17:28:59 +0000277 wb = w * bpp;
278 if (yd <= ys) {
aliguori0e1f5a02008-11-24 19:29:13 +0000279 s = ds_get_data(ds) +
280 ds_get_linesize(ds) * ys + bpp * xs;
281 d = ds_get_data(ds) +
282 ds_get_linesize(ds) * yd + bpp * xd;
bellarde7f0ad52004-07-14 17:28:59 +0000283 for (y = 0; y < h; y++) {
284 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000285 d += ds_get_linesize(ds);
286 s += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000287 }
288 } else {
aliguori0e1f5a02008-11-24 19:29:13 +0000289 s = ds_get_data(ds) +
290 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
291 d = ds_get_data(ds) +
292 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
bellarde7f0ad52004-07-14 17:28:59 +0000293 for (y = 0; y < h; y++) {
294 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000295 d -= ds_get_linesize(ds);
296 s -= ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000297 }
298 }
299}
300
301/***********************************************************/
302/* basic char display */
303
304#define FONT_HEIGHT 16
305#define FONT_WIDTH 8
306
307#include "vgafont.h"
308
309#define cbswap_32(__x) \
310((uint32_t)( \
311 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
312 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
313 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
314 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
315
Juan Quintelae2542fe2009-07-27 16:13:06 +0200316#ifdef HOST_WORDS_BIGENDIAN
bellarde7f0ad52004-07-14 17:28:59 +0000317#define PAT(x) x
318#else
319#define PAT(x) cbswap_32(x)
320#endif
321
322static const uint32_t dmask16[16] = {
323 PAT(0x00000000),
324 PAT(0x000000ff),
325 PAT(0x0000ff00),
326 PAT(0x0000ffff),
327 PAT(0x00ff0000),
328 PAT(0x00ff00ff),
329 PAT(0x00ffff00),
330 PAT(0x00ffffff),
331 PAT(0xff000000),
332 PAT(0xff0000ff),
333 PAT(0xff00ff00),
334 PAT(0xff00ffff),
335 PAT(0xffff0000),
336 PAT(0xffff00ff),
337 PAT(0xffffff00),
338 PAT(0xffffffff),
339};
340
341static const uint32_t dmask4[4] = {
342 PAT(0x00000000),
343 PAT(0x0000ffff),
344 PAT(0xffff0000),
345 PAT(0xffffffff),
346};
347
pbrook6d6f7c22006-03-11 15:35:30 +0000348static uint32_t color_table[2][8];
bellarde7f0ad52004-07-14 17:28:59 +0000349
Devin J. Pohlydf00bed2011-09-07 15:44:36 -0400350#ifndef CONFIG_CURSES
pbrook6d6f7c22006-03-11 15:35:30 +0000351enum color_names {
352 COLOR_BLACK = 0,
353 COLOR_RED = 1,
354 COLOR_GREEN = 2,
355 COLOR_YELLOW = 3,
356 COLOR_BLUE = 4,
357 COLOR_MAGENTA = 5,
358 COLOR_CYAN = 6,
359 COLOR_WHITE = 7
360};
Devin J. Pohlydf00bed2011-09-07 15:44:36 -0400361#endif
pbrook6d6f7c22006-03-11 15:35:30 +0000362
363static const uint32_t color_table_rgb[2][8] = {
364 { /* dark */
bellard26489842006-06-25 17:37:36 +0000365 QEMU_RGB(0x00, 0x00, 0x00), /* black */
366 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
367 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
368 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
369 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
370 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
371 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
372 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000373 },
374 { /* bright */
bellard26489842006-06-25 17:37:36 +0000375 QEMU_RGB(0x00, 0x00, 0x00), /* black */
376 QEMU_RGB(0xff, 0x00, 0x00), /* red */
377 QEMU_RGB(0x00, 0xff, 0x00), /* green */
378 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
379 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
380 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
381 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
382 QEMU_RGB(0xff, 0xff, 0xff), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000383 }
bellarde7f0ad52004-07-14 17:28:59 +0000384};
385
386static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
387{
aliguori0e1f5a02008-11-24 19:29:13 +0000388 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000389 case 8:
390 col |= col << 8;
391 col |= col << 16;
392 break;
393 case 15:
394 case 16:
395 col |= col << 16;
396 break;
397 default:
398 break;
399 }
400
401 return col;
402}
pbrook6d6f7c22006-03-11 15:35:30 +0000403#ifdef DEBUG_CONSOLE
404static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
405{
406 if (t_attrib->bold) {
407 printf("b");
408 } else {
409 printf(" ");
410 }
411 if (t_attrib->uline) {
412 printf("u");
413 } else {
414 printf(" ");
415 }
416 if (t_attrib->blink) {
417 printf("l");
418 } else {
419 printf(" ");
420 }
421 if (t_attrib->invers) {
422 printf("i");
423 } else {
424 printf(" ");
425 }
426 if (t_attrib->unvisible) {
427 printf("n");
428 } else {
429 printf(" ");
430 }
431
432 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
433}
434#endif
bellarde7f0ad52004-07-14 17:28:59 +0000435
ths5fafdf22007-09-16 21:08:06 +0000436static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000437 TextAttributes *t_attrib)
bellarde7f0ad52004-07-14 17:28:59 +0000438{
439 uint8_t *d;
440 const uint8_t *font_ptr;
441 unsigned int font_data, linesize, xorcol, bpp;
442 int i;
pbrook6d6f7c22006-03-11 15:35:30 +0000443 unsigned int fgcol, bgcol;
444
445#ifdef DEBUG_CONSOLE
446 printf("x: %2i y: %2i", x, y);
447 console_print_text_attributes(t_attrib, ch);
448#endif
449
450 if (t_attrib->invers) {
451 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
452 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
453 } else {
454 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
455 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
456 }
bellarde7f0ad52004-07-14 17:28:59 +0000457
aliguori0e1f5a02008-11-24 19:29:13 +0000458 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
459 d = ds_get_data(ds) +
460 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
461 linesize = ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000462 font_ptr = vgafont16 + FONT_HEIGHT * ch;
463 xorcol = bgcol ^ fgcol;
aliguori0e1f5a02008-11-24 19:29:13 +0000464 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000465 case 8:
466 for(i = 0; i < FONT_HEIGHT; i++) {
467 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000468 if (t_attrib->uline
469 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100470 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000471 }
bellarde7f0ad52004-07-14 17:28:59 +0000472 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
473 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
474 d += linesize;
475 }
476 break;
477 case 16:
478 case 15:
479 for(i = 0; i < FONT_HEIGHT; i++) {
480 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000481 if (t_attrib->uline
482 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100483 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000484 }
bellarde7f0ad52004-07-14 17:28:59 +0000485 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
486 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
487 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
488 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
489 d += linesize;
490 }
491 break;
492 case 32:
493 for(i = 0; i < FONT_HEIGHT; i++) {
494 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000495 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100496 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000497 }
bellarde7f0ad52004-07-14 17:28:59 +0000498 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
499 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
500 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
501 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
502 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
503 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
504 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
505 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
506 d += linesize;
507 }
508 break;
509 }
510}
511
512static void text_console_resize(TextConsole *s)
513{
514 TextCell *cells, *c, *c1;
515 int w1, x, y, last_width;
516
517 last_width = s->width;
518 s->width = s->g_width / FONT_WIDTH;
519 s->height = s->g_height / FONT_HEIGHT;
520
521 w1 = last_width;
522 if (s->width < w1)
523 w1 = s->width;
524
Anthony Liguori7267c092011-08-20 22:09:37 -0500525 cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
bellarde7f0ad52004-07-14 17:28:59 +0000526 for(y = 0; y < s->total_height; y++) {
527 c = &cells[y * s->width];
528 if (w1 > 0) {
529 c1 = &s->cells[y * last_width];
530 for(x = 0; x < w1; x++) {
531 *c++ = *c1++;
532 }
533 }
534 for(x = w1; x < s->width; x++) {
535 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000536 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000537 c++;
538 }
539 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500540 g_free(s->cells);
bellarde7f0ad52004-07-14 17:28:59 +0000541 s->cells = cells;
542}
543
balrog4d3b6f62008-02-10 16:33:14 +0000544static inline void text_update_xy(TextConsole *s, int x, int y)
545{
546 s->text_x[0] = MIN(s->text_x[0], x);
547 s->text_x[1] = MAX(s->text_x[1], x);
548 s->text_y[0] = MIN(s->text_y[0], y);
549 s->text_y[1] = MAX(s->text_y[1], y);
550}
551
pbrook14778c22009-01-21 03:02:52 +0000552static void invalidate_xy(TextConsole *s, int x, int y)
553{
554 if (s->update_x0 > x * FONT_WIDTH)
555 s->update_x0 = x * FONT_WIDTH;
556 if (s->update_y0 > y * FONT_HEIGHT)
557 s->update_y0 = y * FONT_HEIGHT;
558 if (s->update_x1 < (x + 1) * FONT_WIDTH)
559 s->update_x1 = (x + 1) * FONT_WIDTH;
560 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
561 s->update_y1 = (y + 1) * FONT_HEIGHT;
562}
563
bellarde7f0ad52004-07-14 17:28:59 +0000564static void update_xy(TextConsole *s, int x, int y)
565{
566 TextCell *c;
567 int y1, y2;
568
569 if (s == active_console) {
aliguori0e1f5a02008-11-24 19:29:13 +0000570 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000571 text_update_xy(s, x, y);
572 return;
573 }
574
bellarde7f0ad52004-07-14 17:28:59 +0000575 y1 = (s->y_base + y) % s->total_height;
576 y2 = y1 - s->y_displayed;
577 if (y2 < 0)
578 y2 += s->total_height;
579 if (y2 < s->height) {
580 c = &s->cells[y1 * s->width + x];
ths5fafdf22007-09-16 21:08:06 +0000581 vga_putcharxy(s->ds, x, y2, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000582 &(c->t_attrib));
pbrook14778c22009-01-21 03:02:52 +0000583 invalidate_xy(s, x, y2);
bellarde7f0ad52004-07-14 17:28:59 +0000584 }
585 }
586}
587
588static void console_show_cursor(TextConsole *s, int show)
589{
590 TextCell *c;
591 int y, y1;
592
593 if (s == active_console) {
thsed8276a2007-02-10 22:37:56 +0000594 int x = s->x;
balrog4d3b6f62008-02-10 16:33:14 +0000595
aliguori0e1f5a02008-11-24 19:29:13 +0000596 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000597 s->cursor_invalidate = 1;
598 return;
599 }
600
thsed8276a2007-02-10 22:37:56 +0000601 if (x >= s->width) {
602 x = s->width - 1;
603 }
bellarde7f0ad52004-07-14 17:28:59 +0000604 y1 = (s->y_base + s->y) % s->total_height;
605 y = y1 - s->y_displayed;
606 if (y < 0)
607 y += s->total_height;
608 if (y < s->height) {
thsed8276a2007-02-10 22:37:56 +0000609 c = &s->cells[y1 * s->width + x];
bellarde7f0ad52004-07-14 17:28:59 +0000610 if (show) {
pbrook6d6f7c22006-03-11 15:35:30 +0000611 TextAttributes t_attrib = s->t_attrib_default;
612 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
thsed8276a2007-02-10 22:37:56 +0000613 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
bellarde7f0ad52004-07-14 17:28:59 +0000614 } else {
thsed8276a2007-02-10 22:37:56 +0000615 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000616 }
pbrook14778c22009-01-21 03:02:52 +0000617 invalidate_xy(s, x, y);
bellarde7f0ad52004-07-14 17:28:59 +0000618 }
619 }
620}
621
622static void console_refresh(TextConsole *s)
623{
624 TextCell *c;
625 int x, y, y1;
626
ths5fafdf22007-09-16 21:08:06 +0000627 if (s != active_console)
bellarde7f0ad52004-07-14 17:28:59 +0000628 return;
aliguori0e1f5a02008-11-24 19:29:13 +0000629 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000630 s->text_x[0] = 0;
631 s->text_y[0] = 0;
632 s->text_x[1] = s->width - 1;
633 s->text_y[1] = s->height - 1;
634 s->cursor_invalidate = 1;
635 return;
636 }
bellarde7f0ad52004-07-14 17:28:59 +0000637
aliguori0e1f5a02008-11-24 19:29:13 +0000638 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
pbrook6d6f7c22006-03-11 15:35:30 +0000639 color_table[0][COLOR_BLACK]);
bellarde7f0ad52004-07-14 17:28:59 +0000640 y1 = s->y_displayed;
641 for(y = 0; y < s->height; y++) {
642 c = s->cells + y1 * s->width;
643 for(x = 0; x < s->width; x++) {
ths5fafdf22007-09-16 21:08:06 +0000644 vga_putcharxy(s->ds, x, y, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000645 &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000646 c++;
647 }
648 if (++y1 == s->total_height)
649 y1 = 0;
650 }
bellarde7f0ad52004-07-14 17:28:59 +0000651 console_show_cursor(s, 1);
pbrook14778c22009-01-21 03:02:52 +0000652 dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
bellarde7f0ad52004-07-14 17:28:59 +0000653}
654
655static void console_scroll(int ydelta)
656{
657 TextConsole *s;
658 int i, y1;
ths3b46e622007-09-17 08:09:54 +0000659
bellarde7f0ad52004-07-14 17:28:59 +0000660 s = active_console;
thsaf3a9032007-07-11 23:14:59 +0000661 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +0000662 return;
663
664 if (ydelta > 0) {
665 for(i = 0; i < ydelta; i++) {
666 if (s->y_displayed == s->y_base)
667 break;
668 if (++s->y_displayed == s->total_height)
669 s->y_displayed = 0;
670 }
671 } else {
672 ydelta = -ydelta;
673 i = s->backscroll_height;
674 if (i > s->total_height - s->height)
675 i = s->total_height - s->height;
676 y1 = s->y_base - i;
677 if (y1 < 0)
678 y1 += s->total_height;
679 for(i = 0; i < ydelta; i++) {
680 if (s->y_displayed == y1)
681 break;
682 if (--s->y_displayed < 0)
683 s->y_displayed = s->total_height - 1;
684 }
685 }
686 console_refresh(s);
687}
688
689static void console_put_lf(TextConsole *s)
690{
691 TextCell *c;
692 int x, y1;
693
bellarde7f0ad52004-07-14 17:28:59 +0000694 s->y++;
695 if (s->y >= s->height) {
696 s->y = s->height - 1;
pbrook6d6f7c22006-03-11 15:35:30 +0000697
bellarde7f0ad52004-07-14 17:28:59 +0000698 if (s->y_displayed == s->y_base) {
699 if (++s->y_displayed == s->total_height)
700 s->y_displayed = 0;
701 }
702 if (++s->y_base == s->total_height)
703 s->y_base = 0;
704 if (s->backscroll_height < s->total_height)
705 s->backscroll_height++;
706 y1 = (s->y_base + s->height - 1) % s->total_height;
707 c = &s->cells[y1 * s->width];
708 for(x = 0; x < s->width; x++) {
709 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000710 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000711 c++;
712 }
713 if (s == active_console && s->y_displayed == s->y_base) {
aliguori0e1f5a02008-11-24 19:29:13 +0000714 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000715 s->text_x[0] = 0;
716 s->text_y[0] = 0;
717 s->text_x[1] = s->width - 1;
718 s->text_y[1] = s->height - 1;
719 return;
720 }
721
ths5fafdf22007-09-16 21:08:06 +0000722 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
723 s->width * FONT_WIDTH,
bellarde7f0ad52004-07-14 17:28:59 +0000724 (s->height - 1) * FONT_HEIGHT);
725 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
ths5fafdf22007-09-16 21:08:06 +0000726 s->width * FONT_WIDTH, FONT_HEIGHT,
pbrook6d6f7c22006-03-11 15:35:30 +0000727 color_table[0][s->t_attrib_default.bgcol]);
pbrook14778c22009-01-21 03:02:52 +0000728 s->update_x0 = 0;
729 s->update_y0 = 0;
730 s->update_x1 = s->width * FONT_WIDTH;
731 s->update_y1 = s->height * FONT_HEIGHT;
bellarde7f0ad52004-07-14 17:28:59 +0000732 }
733 }
734}
735
pbrook6d6f7c22006-03-11 15:35:30 +0000736/* Set console attributes depending on the current escape codes.
737 * NOTE: I know this code is not very efficient (checking every color for it
738 * self) but it is more readable and better maintainable.
739 */
740static void console_handle_escape(TextConsole *s)
741{
742 int i;
743
pbrook6d6f7c22006-03-11 15:35:30 +0000744 for (i=0; i<s->nb_esc_params; i++) {
745 switch (s->esc_params[i]) {
746 case 0: /* reset all console attributes to default */
747 s->t_attrib = s->t_attrib_default;
748 break;
749 case 1:
750 s->t_attrib.bold = 1;
751 break;
752 case 4:
753 s->t_attrib.uline = 1;
754 break;
755 case 5:
756 s->t_attrib.blink = 1;
757 break;
758 case 7:
759 s->t_attrib.invers = 1;
760 break;
761 case 8:
762 s->t_attrib.unvisible = 1;
763 break;
764 case 22:
765 s->t_attrib.bold = 0;
766 break;
767 case 24:
768 s->t_attrib.uline = 0;
769 break;
770 case 25:
771 s->t_attrib.blink = 0;
772 break;
773 case 27:
774 s->t_attrib.invers = 0;
775 break;
776 case 28:
777 s->t_attrib.unvisible = 0;
778 break;
779 /* set foreground color */
780 case 30:
781 s->t_attrib.fgcol=COLOR_BLACK;
782 break;
783 case 31:
784 s->t_attrib.fgcol=COLOR_RED;
785 break;
786 case 32:
787 s->t_attrib.fgcol=COLOR_GREEN;
788 break;
789 case 33:
790 s->t_attrib.fgcol=COLOR_YELLOW;
791 break;
792 case 34:
793 s->t_attrib.fgcol=COLOR_BLUE;
794 break;
795 case 35:
796 s->t_attrib.fgcol=COLOR_MAGENTA;
797 break;
798 case 36:
799 s->t_attrib.fgcol=COLOR_CYAN;
800 break;
801 case 37:
802 s->t_attrib.fgcol=COLOR_WHITE;
803 break;
804 /* set background color */
805 case 40:
806 s->t_attrib.bgcol=COLOR_BLACK;
807 break;
808 case 41:
809 s->t_attrib.bgcol=COLOR_RED;
810 break;
811 case 42:
812 s->t_attrib.bgcol=COLOR_GREEN;
813 break;
814 case 43:
815 s->t_attrib.bgcol=COLOR_YELLOW;
816 break;
817 case 44:
818 s->t_attrib.bgcol=COLOR_BLUE;
819 break;
820 case 45:
821 s->t_attrib.bgcol=COLOR_MAGENTA;
822 break;
823 case 46:
824 s->t_attrib.bgcol=COLOR_CYAN;
825 break;
826 case 47:
827 s->t_attrib.bgcol=COLOR_WHITE;
828 break;
829 }
830 }
831}
832
thsadb47962007-01-16 23:02:36 +0000833static void console_clear_xy(TextConsole *s, int x, int y)
834{
835 int y1 = (s->y_base + y) % s->total_height;
836 TextCell *c = &s->cells[y1 * s->width + x];
837 c->ch = ' ';
838 c->t_attrib = s->t_attrib_default;
thsadb47962007-01-16 23:02:36 +0000839 update_xy(s, x, y);
840}
841
bellarde7f0ad52004-07-14 17:28:59 +0000842static void console_putchar(TextConsole *s, int ch)
843{
844 TextCell *c;
thsadb47962007-01-16 23:02:36 +0000845 int y1, i;
846 int x, y;
bellarde7f0ad52004-07-14 17:28:59 +0000847
848 switch(s->state) {
849 case TTY_STATE_NORM:
850 switch(ch) {
pbrook6d6f7c22006-03-11 15:35:30 +0000851 case '\r': /* carriage return */
bellarde7f0ad52004-07-14 17:28:59 +0000852 s->x = 0;
853 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000854 case '\n': /* newline */
bellarde7f0ad52004-07-14 17:28:59 +0000855 console_put_lf(s);
856 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000857 case '\b': /* backspace */
ths5fafdf22007-09-16 21:08:06 +0000858 if (s->x > 0)
bellarde15d7372006-06-25 16:26:29 +0000859 s->x--;
pbrook6d6f7c22006-03-11 15:35:30 +0000860 break;
861 case '\t': /* tabspace */
862 if (s->x + (8 - (s->x % 8)) > s->width) {
bellardbd468842006-07-14 20:24:31 +0000863 s->x = 0;
pbrook6d6f7c22006-03-11 15:35:30 +0000864 console_put_lf(s);
865 } else {
866 s->x = s->x + (8 - (s->x % 8));
867 }
868 break;
869 case '\a': /* alert aka. bell */
870 /* TODO: has to be implemented */
871 break;
thsadb47962007-01-16 23:02:36 +0000872 case 14:
873 /* SI (shift in), character set 0 (ignored) */
874 break;
875 case 15:
876 /* SO (shift out), character set 1 (ignored) */
877 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000878 case 27: /* esc (introducing an escape sequence) */
bellarde7f0ad52004-07-14 17:28:59 +0000879 s->state = TTY_STATE_ESC;
880 break;
881 default:
thsed8276a2007-02-10 22:37:56 +0000882 if (s->x >= s->width) {
883 /* line wrap */
884 s->x = 0;
885 console_put_lf(s);
thsadb47962007-01-16 23:02:36 +0000886 }
bellarde7f0ad52004-07-14 17:28:59 +0000887 y1 = (s->y_base + s->y) % s->total_height;
888 c = &s->cells[y1 * s->width + s->x];
889 c->ch = ch;
pbrook6d6f7c22006-03-11 15:35:30 +0000890 c->t_attrib = s->t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +0000891 update_xy(s, s->x, s->y);
892 s->x++;
bellarde7f0ad52004-07-14 17:28:59 +0000893 break;
894 }
895 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000896 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
bellarde7f0ad52004-07-14 17:28:59 +0000897 if (ch == '[') {
898 for(i=0;i<MAX_ESC_PARAMS;i++)
899 s->esc_params[i] = 0;
900 s->nb_esc_params = 0;
901 s->state = TTY_STATE_CSI;
902 } else {
903 s->state = TTY_STATE_NORM;
904 }
905 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000906 case TTY_STATE_CSI: /* handle escape sequence parameters */
bellarde7f0ad52004-07-14 17:28:59 +0000907 if (ch >= '0' && ch <= '9') {
908 if (s->nb_esc_params < MAX_ESC_PARAMS) {
ths5fafdf22007-09-16 21:08:06 +0000909 s->esc_params[s->nb_esc_params] =
bellarde7f0ad52004-07-14 17:28:59 +0000910 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
911 }
912 } else {
913 s->nb_esc_params++;
914 if (ch == ';')
915 break;
thsadb47962007-01-16 23:02:36 +0000916#ifdef DEBUG_CONSOLE
917 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
918 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
919#endif
bellarde7f0ad52004-07-14 17:28:59 +0000920 s->state = TTY_STATE_NORM;
921 switch(ch) {
thsadb47962007-01-16 23:02:36 +0000922 case 'A':
923 /* move cursor up */
924 if (s->esc_params[0] == 0) {
925 s->esc_params[0] = 1;
926 }
927 s->y -= s->esc_params[0];
928 if (s->y < 0) {
929 s->y = 0;
bellarde7f0ad52004-07-14 17:28:59 +0000930 }
931 break;
thsadb47962007-01-16 23:02:36 +0000932 case 'B':
933 /* move cursor down */
934 if (s->esc_params[0] == 0) {
935 s->esc_params[0] = 1;
936 }
937 s->y += s->esc_params[0];
938 if (s->y >= s->height) {
939 s->y = s->height - 1;
940 }
941 break;
942 case 'C':
943 /* move cursor right */
944 if (s->esc_params[0] == 0) {
945 s->esc_params[0] = 1;
946 }
947 s->x += s->esc_params[0];
948 if (s->x >= s->width) {
949 s->x = s->width - 1;
950 }
951 break;
952 case 'D':
953 /* move cursor left */
954 if (s->esc_params[0] == 0) {
955 s->esc_params[0] = 1;
956 }
957 s->x -= s->esc_params[0];
958 if (s->x < 0) {
959 s->x = 0;
960 }
961 break;
962 case 'G':
963 /* move cursor to column */
964 s->x = s->esc_params[0] - 1;
965 if (s->x < 0) {
966 s->x = 0;
967 }
968 break;
969 case 'f':
970 case 'H':
971 /* move cursor to row, column */
972 s->x = s->esc_params[1] - 1;
973 if (s->x < 0) {
974 s->x = 0;
975 }
976 s->y = s->esc_params[0] - 1;
977 if (s->y < 0) {
978 s->y = 0;
979 }
980 break;
981 case 'J':
982 switch (s->esc_params[0]) {
983 case 0:
984 /* clear to end of screen */
985 for (y = s->y; y < s->height; y++) {
986 for (x = 0; x < s->width; x++) {
987 if (y == s->y && x < s->x) {
988 continue;
989 }
990 console_clear_xy(s, x, y);
991 }
992 }
993 break;
994 case 1:
995 /* clear from beginning of screen */
996 for (y = 0; y <= s->y; y++) {
997 for (x = 0; x < s->width; x++) {
998 if (y == s->y && x > s->x) {
999 break;
1000 }
1001 console_clear_xy(s, x, y);
1002 }
1003 }
1004 break;
1005 case 2:
1006 /* clear entire screen */
1007 for (y = 0; y <= s->height; y++) {
1008 for (x = 0; x < s->width; x++) {
1009 console_clear_xy(s, x, y);
1010 }
1011 }
1012 break;
1013 }
1014 case 'K':
1015 switch (s->esc_params[0]) {
1016 case 0:
1017 /* clear to eol */
1018 for(x = s->x; x < s->width; x++) {
1019 console_clear_xy(s, x, s->y);
1020 }
1021 break;
1022 case 1:
1023 /* clear from beginning of line */
1024 for (x = 0; x <= s->x; x++) {
1025 console_clear_xy(s, x, s->y);
1026 }
1027 break;
1028 case 2:
1029 /* clear entire line */
1030 for(x = 0; x < s->width; x++) {
1031 console_clear_xy(s, x, s->y);
1032 }
bellarde7f0ad52004-07-14 17:28:59 +00001033 break;
1034 }
thsadb47962007-01-16 23:02:36 +00001035 break;
1036 case 'm':
pbrook6d6f7c22006-03-11 15:35:30 +00001037 console_handle_escape(s);
bellarde7f0ad52004-07-14 17:28:59 +00001038 break;
thsadb47962007-01-16 23:02:36 +00001039 case 'n':
1040 /* report cursor position */
1041 /* TODO: send ESC[row;colR */
1042 break;
1043 case 's':
1044 /* save cursor position */
1045 s->x_saved = s->x;
1046 s->y_saved = s->y;
1047 break;
1048 case 'u':
1049 /* restore cursor position */
1050 s->x = s->x_saved;
1051 s->y = s->y_saved;
1052 break;
1053 default:
1054#ifdef DEBUG_CONSOLE
1055 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1056#endif
1057 break;
1058 }
1059 break;
bellarde7f0ad52004-07-14 17:28:59 +00001060 }
1061 }
1062}
1063
1064void console_select(unsigned int index)
1065{
1066 TextConsole *s;
pbrook6d6f7c22006-03-11 15:35:30 +00001067
bellarde7f0ad52004-07-14 17:28:59 +00001068 if (index >= MAX_CONSOLES)
1069 return;
Stefan Hajnoczi358664c2010-09-20 14:11:19 +01001070 if (active_console) {
1071 active_console->g_width = ds_get_width(active_console->ds);
1072 active_console->g_height = ds_get_height(active_console->ds);
1073 }
bellarde7f0ad52004-07-14 17:28:59 +00001074 s = consoles[index];
1075 if (s) {
aliguori7d957bd2009-01-15 22:14:11 +00001076 DisplayState *ds = s->ds;
bellarde7f0ad52004-07-14 17:28:59 +00001077 active_console = s;
aliguori68f00992009-01-21 18:59:12 +00001078 if (ds_get_bits_per_pixel(s->ds)) {
aliguori7b5d76d2009-03-13 15:02:13 +00001079 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
aliguori68f00992009-01-21 18:59:12 +00001080 } else {
1081 s->ds->surface->width = s->width;
1082 s->ds->surface->height = s->height;
1083 }
aliguori7d957bd2009-01-15 22:14:11 +00001084 dpy_resize(s->ds);
balrog4d3b6f62008-02-10 16:33:14 +00001085 vga_hw_invalidate();
bellarde7f0ad52004-07-14 17:28:59 +00001086 }
1087}
1088
1089static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1090{
1091 TextConsole *s = chr->opaque;
1092 int i;
1093
pbrook14778c22009-01-21 03:02:52 +00001094 s->update_x0 = s->width * FONT_WIDTH;
1095 s->update_y0 = s->height * FONT_HEIGHT;
1096 s->update_x1 = 0;
1097 s->update_y1 = 0;
bellarde7f0ad52004-07-14 17:28:59 +00001098 console_show_cursor(s, 0);
1099 for(i = 0; i < len; i++) {
1100 console_putchar(s, buf[i]);
1101 }
1102 console_show_cursor(s, 1);
pbrook14778c22009-01-21 03:02:52 +00001103 if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1104 dpy_update(s->ds, s->update_x0, s->update_y0,
1105 s->update_x1 - s->update_x0,
1106 s->update_y1 - s->update_y0);
1107 }
bellarde7f0ad52004-07-14 17:28:59 +00001108 return len;
1109}
1110
bellarde15d7372006-06-25 16:26:29 +00001111static void kbd_send_chars(void *opaque)
1112{
1113 TextConsole *s = opaque;
1114 int len;
1115 uint8_t buf[16];
ths3b46e622007-09-17 08:09:54 +00001116
Anthony Liguori909cda12011-08-15 11:17:31 -05001117 len = qemu_chr_be_can_write(s->chr);
bellarde15d7372006-06-25 16:26:29 +00001118 if (len > s->out_fifo.count)
1119 len = s->out_fifo.count;
1120 if (len > 0) {
1121 if (len > sizeof(buf))
1122 len = sizeof(buf);
1123 qemu_fifo_read(&s->out_fifo, buf, len);
Anthony Liguorifa5efcc2011-08-15 11:17:30 -05001124 qemu_chr_be_write(s->chr, buf, len);
bellarde15d7372006-06-25 16:26:29 +00001125 }
1126 /* characters are pending: we send them a bit later (XXX:
1127 horrible, should change char device API) */
1128 if (s->out_fifo.count > 0) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001129 qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
bellarde15d7372006-06-25 16:26:29 +00001130 }
1131}
1132
bellarde7f0ad52004-07-14 17:28:59 +00001133/* called when an ascii key is pressed */
1134void kbd_put_keysym(int keysym)
1135{
1136 TextConsole *s;
1137 uint8_t buf[16], *q;
1138 int c;
1139
1140 s = active_console;
thsaf3a9032007-07-11 23:14:59 +00001141 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +00001142 return;
1143
1144 switch(keysym) {
1145 case QEMU_KEY_CTRL_UP:
1146 console_scroll(-1);
1147 break;
1148 case QEMU_KEY_CTRL_DOWN:
1149 console_scroll(1);
1150 break;
1151 case QEMU_KEY_CTRL_PAGEUP:
1152 console_scroll(-10);
1153 break;
1154 case QEMU_KEY_CTRL_PAGEDOWN:
1155 console_scroll(10);
1156 break;
1157 default:
bellarde15d7372006-06-25 16:26:29 +00001158 /* convert the QEMU keysym to VT100 key string */
1159 q = buf;
1160 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1161 *q++ = '\033';
1162 *q++ = '[';
1163 c = keysym - 0xe100;
1164 if (c >= 10)
1165 *q++ = '0' + (c / 10);
1166 *q++ = '0' + (c % 10);
1167 *q++ = '~';
1168 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1169 *q++ = '\033';
1170 *q++ = '[';
1171 *q++ = keysym & 0xff;
Paolo Bonzini41048332010-12-23 13:42:52 +01001172 } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1173 console_puts(s->chr, (const uint8_t *) "\r", 1);
1174 *q++ = '\n';
bellarde15d7372006-06-25 16:26:29 +00001175 } else {
Paolo Bonzini41048332010-12-23 13:42:52 +01001176 *q++ = keysym;
1177 }
1178 if (s->echo) {
1179 console_puts(s->chr, buf, q - buf);
bellarde15d7372006-06-25 16:26:29 +00001180 }
pbrooke5b0bc42007-01-27 23:46:43 +00001181 if (s->chr->chr_read) {
bellarde15d7372006-06-25 16:26:29 +00001182 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1183 kbd_send_chars(s);
bellarde7f0ad52004-07-14 17:28:59 +00001184 }
1185 break;
1186 }
1187}
1188
balrog4d3b6f62008-02-10 16:33:14 +00001189static void text_console_invalidate(void *opaque)
1190{
1191 TextConsole *s = (TextConsole *) opaque;
aliguori68f00992009-01-21 18:59:12 +00001192 if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1193 s->g_width = ds_get_width(s->ds);
1194 s->g_height = ds_get_height(s->ds);
1195 text_console_resize(s);
1196 }
balrog4d3b6f62008-02-10 16:33:14 +00001197 console_refresh(s);
1198}
1199
Anthony Liguoric227f092009-10-01 16:12:16 -05001200static void text_console_update(void *opaque, console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +00001201{
1202 TextConsole *s = (TextConsole *) opaque;
1203 int i, j, src;
1204
1205 if (s->text_x[0] <= s->text_x[1]) {
1206 src = (s->y_base + s->text_y[0]) * s->width;
1207 chardata += s->text_y[0] * s->width;
1208 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1209 for (j = 0; j < s->width; j ++, src ++)
1210 console_write_ch(chardata ++, s->cells[src].ch |
1211 (s->cells[src].t_attrib.fgcol << 12) |
1212 (s->cells[src].t_attrib.bgcol << 8) |
1213 (s->cells[src].t_attrib.bold << 21));
1214 dpy_update(s->ds, s->text_x[0], s->text_y[0],
1215 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1216 s->text_x[0] = s->width;
1217 s->text_y[0] = s->height;
1218 s->text_x[1] = 0;
1219 s->text_y[1] = 0;
1220 }
1221 if (s->cursor_invalidate) {
1222 dpy_cursor(s->ds, s->x, s->y);
1223 s->cursor_invalidate = 0;
1224 }
1225}
1226
aliguori42aa98e2009-01-16 21:01:48 +00001227static TextConsole *get_graphic_console(DisplayState *ds)
blueswir1a147d622009-01-16 19:41:04 +00001228{
aliguori3023f332009-01-16 19:04:14 +00001229 int i;
1230 TextConsole *s;
1231 for (i = 0; i < nb_consoles; i++) {
1232 s = consoles[i];
aliguori42aa98e2009-01-16 21:01:48 +00001233 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
aliguori3023f332009-01-16 19:04:14 +00001234 return s;
1235 }
1236 return NULL;
1237}
1238
Anthony Liguoric227f092009-10-01 16:12:16 -05001239static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
bellarde7f0ad52004-07-14 17:28:59 +00001240{
1241 TextConsole *s;
pbrook95219892006-04-09 01:06:34 +00001242 int i;
bellarde7f0ad52004-07-14 17:28:59 +00001243
1244 if (nb_consoles >= MAX_CONSOLES)
1245 return NULL;
Anthony Liguori7267c092011-08-20 22:09:37 -05001246 s = g_malloc0(sizeof(TextConsole));
thsaf3a9032007-07-11 23:14:59 +00001247 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1248 (console_type == GRAPHIC_CONSOLE))) {
bellarde7f0ad52004-07-14 17:28:59 +00001249 active_console = s;
thsaf3a9032007-07-11 23:14:59 +00001250 }
bellarde7f0ad52004-07-14 17:28:59 +00001251 s->ds = ds;
thsaf3a9032007-07-11 23:14:59 +00001252 s->console_type = console_type;
1253 if (console_type != GRAPHIC_CONSOLE) {
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001254 s->index = nb_consoles;
pbrook95219892006-04-09 01:06:34 +00001255 consoles[nb_consoles++] = s;
1256 } else {
1257 /* HACK: Put graphical consoles before text consoles. */
1258 for (i = nb_consoles; i > 0; i--) {
thsaf3a9032007-07-11 23:14:59 +00001259 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
pbrook95219892006-04-09 01:06:34 +00001260 break;
1261 consoles[i] = consoles[i - 1];
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001262 consoles[i]->index = i;
pbrook95219892006-04-09 01:06:34 +00001263 }
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001264 s->index = i;
pbrook95219892006-04-09 01:06:34 +00001265 consoles[i] = s;
aliguori3023f332009-01-16 19:04:14 +00001266 nb_consoles++;
pbrook95219892006-04-09 01:06:34 +00001267 }
bellarde7f0ad52004-07-14 17:28:59 +00001268 return s;
1269}
1270
Paolo Bonzini98b50082010-02-11 00:29:57 +01001271static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1272{
Anthony Liguori7267c092011-08-20 22:09:37 -05001273 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
Paolo Bonzini98b50082010-02-11 00:29:57 +01001274
Jes Sorensenffe8b822011-03-16 13:33:30 +01001275 int linesize = width * 4;
1276 qemu_alloc_display(surface, width, height, linesize,
1277 qemu_default_pixelformat(32), 0);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001278 return surface;
1279}
1280
1281static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1282 int width, int height)
1283{
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);
1287 return surface;
1288}
1289
1290void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1291 int linesize, PixelFormat pf, int newflags)
1292{
1293 void *data;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001294 surface->width = width;
1295 surface->height = height;
Jes Sorensenffe8b822011-03-16 13:33:30 +01001296 surface->linesize = linesize;
1297 surface->pf = pf;
1298 if (surface->flags & QEMU_ALLOCATED_FLAG) {
Anthony Liguori7267c092011-08-20 22:09:37 -05001299 data = g_realloc(surface->data,
Jes Sorensenffe8b822011-03-16 13:33:30 +01001300 surface->linesize * surface->height);
1301 } else {
Anthony Liguori7267c092011-08-20 22:09:37 -05001302 data = g_malloc(surface->linesize * surface->height);
Jes Sorensenffe8b822011-03-16 13:33:30 +01001303 }
1304 surface->data = (uint8_t *)data;
1305 surface->flags = newflags | QEMU_ALLOCATED_FLAG;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001306#ifdef HOST_WORDS_BIGENDIAN
Jes Sorensenffe8b822011-03-16 13:33:30 +01001307 surface->flags |= QEMU_BIG_ENDIAN_FLAG;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001308#endif
Paolo Bonzini98b50082010-02-11 00:29:57 +01001309}
1310
1311DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1312 int linesize, uint8_t *data)
1313{
Anthony Liguori7267c092011-08-20 22:09:37 -05001314 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
Paolo Bonzini98b50082010-02-11 00:29:57 +01001315
1316 surface->width = width;
1317 surface->height = height;
1318 surface->linesize = linesize;
1319 surface->pf = qemu_default_pixelformat(bpp);
1320#ifdef HOST_WORDS_BIGENDIAN
1321 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1322#endif
1323 surface->data = data;
1324
1325 return surface;
1326}
1327
1328static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1329{
1330 if (surface == NULL)
1331 return;
1332 if (surface->flags & QEMU_ALLOCATED_FLAG)
Anthony Liguori7267c092011-08-20 22:09:37 -05001333 g_free(surface->data);
1334 g_free(surface);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001335}
1336
1337static struct DisplayAllocator default_allocator = {
1338 defaultallocator_create_displaysurface,
1339 defaultallocator_resize_displaysurface,
1340 defaultallocator_free_displaysurface
1341};
1342
1343static void dumb_display_init(void)
1344{
Anthony Liguori7267c092011-08-20 22:09:37 -05001345 DisplayState *ds = g_malloc0(sizeof(DisplayState));
Jan Kiszka18026512011-06-19 11:53:02 +02001346 int width = 640;
1347 int height = 480;
1348
Paolo Bonzini98b50082010-02-11 00:29:57 +01001349 ds->allocator = &default_allocator;
Jan Kiszka18026512011-06-19 11:53:02 +02001350 if (is_fixedsize_console()) {
1351 width = active_console->g_width;
1352 height = active_console->g_height;
1353 }
1354 ds->surface = qemu_create_displaysurface(ds, width, height);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001355 register_displaystate(ds);
1356}
1357
1358/***********************************************************/
1359/* register display */
1360
1361void register_displaystate(DisplayState *ds)
1362{
1363 DisplayState **s;
1364 s = &display_state;
1365 while (*s != NULL)
1366 s = &(*s)->next;
1367 ds->next = NULL;
1368 *s = ds;
1369}
1370
1371DisplayState *get_displaystate(void)
1372{
1373 if (!display_state) {
1374 dumb_display_init ();
1375 }
1376 return display_state;
1377}
1378
1379DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1380{
1381 if(ds->allocator == &default_allocator) {
1382 DisplaySurface *surf;
1383 surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1384 defaultallocator_free_displaysurface(ds->surface);
1385 ds->surface = surf;
1386 ds->allocator = da;
1387 }
1388 return ds->allocator;
1389}
1390
aliguori3023f332009-01-16 19:04:14 +00001391DisplayState *graphic_console_init(vga_hw_update_ptr update,
1392 vga_hw_invalidate_ptr invalidate,
1393 vga_hw_screen_dump_ptr screen_dump,
1394 vga_hw_text_update_ptr text_update,
1395 void *opaque)
bellarde7f0ad52004-07-14 17:28:59 +00001396{
pbrook95219892006-04-09 01:06:34 +00001397 TextConsole *s;
aliguori3023f332009-01-16 19:04:14 +00001398 DisplayState *ds;
aurel32f0f2f972009-01-16 21:13:49 +00001399
Anthony Liguori7267c092011-08-20 22:09:37 -05001400 ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
aliguori7b5d76d2009-03-13 15:02:13 +00001401 ds->allocator = &default_allocator;
1402 ds->surface = qemu_create_displaysurface(ds, 640, 480);
pbrook95219892006-04-09 01:06:34 +00001403
thsaf3a9032007-07-11 23:14:59 +00001404 s = new_console(ds, GRAPHIC_CONSOLE);
aliguori3023f332009-01-16 19:04:14 +00001405 if (s == NULL) {
aliguori7b5d76d2009-03-13 15:02:13 +00001406 qemu_free_displaysurface(ds);
Anthony Liguori7267c092011-08-20 22:09:37 -05001407 g_free(ds);
aliguori3023f332009-01-16 19:04:14 +00001408 return NULL;
1409 }
pbrook95219892006-04-09 01:06:34 +00001410 s->hw_update = update;
1411 s->hw_invalidate = invalidate;
1412 s->hw_screen_dump = screen_dump;
balrog4d3b6f62008-02-10 16:33:14 +00001413 s->hw_text_update = text_update;
pbrook95219892006-04-09 01:06:34 +00001414 s->hw = opaque;
aliguori3023f332009-01-16 19:04:14 +00001415
aurel32f0f2f972009-01-16 21:13:49 +00001416 register_displaystate(ds);
aliguori3023f332009-01-16 19:04:14 +00001417 return ds;
pbrook95219892006-04-09 01:06:34 +00001418}
1419
1420int is_graphic_console(void)
1421{
balrog4d3b6f62008-02-10 16:33:14 +00001422 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
bellarde7f0ad52004-07-14 17:28:59 +00001423}
1424
balrogc21bbcf2008-09-24 03:32:33 +00001425int is_fixedsize_console(void)
1426{
1427 return active_console && active_console->console_type != TEXT_CONSOLE;
1428}
1429
balroga528b802007-10-30 22:38:53 +00001430void console_color_init(DisplayState *ds)
1431{
1432 int i, j;
1433 for (j = 0; j < 2; j++) {
1434 for (i = 0; i < 8; i++) {
aurel32f0f2f972009-01-16 21:13:49 +00001435 color_table[j][i] = col_expand(ds,
balroga528b802007-10-30 22:38:53 +00001436 vga_get_color(ds, color_table_rgb[j][i]));
1437 }
1438 }
1439}
1440
aliguori2796dae2009-01-16 20:23:27 +00001441static int n_text_consoles;
1442static CharDriverState *text_consoles[128];
aliguori2796dae2009-01-16 20:23:27 +00001443
Paolo Bonzini41048332010-12-23 13:42:52 +01001444static void text_console_set_echo(CharDriverState *chr, bool echo)
1445{
1446 TextConsole *s = chr->opaque;
1447
1448 s->echo = echo;
1449}
1450
Paolo Bonzini44b37b92010-12-23 13:42:53 +01001451static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
bellarde7f0ad52004-07-14 17:28:59 +00001452{
bellarde7f0ad52004-07-14 17:28:59 +00001453 TextConsole *s;
bellarde7f0ad52004-07-14 17:28:59 +00001454 static int color_inited;
pbrook6d6f7c22006-03-11 15:35:30 +00001455
Paolo Bonzini491e1142010-12-23 13:42:51 +01001456 s = chr->opaque;
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001457
bellarde7f0ad52004-07-14 17:28:59 +00001458 chr->chr_write = console_puts;
bellard6fcfafb2004-08-01 21:48:30 +00001459
bellarde15d7372006-06-25 16:26:29 +00001460 s->out_fifo.buf = s->out_fifo_buf;
1461 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001462 s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
aliguori3023f332009-01-16 19:04:14 +00001463 s->ds = ds;
ths3b46e622007-09-17 08:09:54 +00001464
bellarde7f0ad52004-07-14 17:28:59 +00001465 if (!color_inited) {
1466 color_inited = 1;
balroga528b802007-10-30 22:38:53 +00001467 console_color_init(s->ds);
bellarde7f0ad52004-07-14 17:28:59 +00001468 }
1469 s->y_displayed = 0;
1470 s->y_base = 0;
1471 s->total_height = DEFAULT_BACKSCROLL;
1472 s->x = 0;
1473 s->y = 0;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001474 if (s->console_type == TEXT_CONSOLE) {
1475 s->g_width = ds_get_width(s->ds);
1476 s->g_height = ds_get_height(s->ds);
1477 }
pbrook6d6f7c22006-03-11 15:35:30 +00001478
balrog4d3b6f62008-02-10 16:33:14 +00001479 s->hw_invalidate = text_console_invalidate;
1480 s->hw_text_update = text_console_update;
1481 s->hw = s;
1482
pbrook6d6f7c22006-03-11 15:35:30 +00001483 /* Set text attribute defaults */
1484 s->t_attrib_default.bold = 0;
1485 s->t_attrib_default.uline = 0;
1486 s->t_attrib_default.blink = 0;
1487 s->t_attrib_default.invers = 0;
1488 s->t_attrib_default.unvisible = 0;
1489 s->t_attrib_default.fgcol = COLOR_WHITE;
1490 s->t_attrib_default.bgcol = COLOR_BLACK;
pbrook6d6f7c22006-03-11 15:35:30 +00001491 /* set current text attributes to default */
1492 s->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +00001493 text_console_resize(s);
1494
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001495 if (chr->label) {
1496 char msg[128];
1497 int len;
1498
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001499 s->t_attrib.bgcol = COLOR_BLUE;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001500 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1501 console_puts(chr, (uint8_t*)msg, len);
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001502 s->t_attrib = s->t_attrib_default;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001503 }
1504
Amit Shah127338e2009-11-03 19:59:56 +05301505 qemu_chr_generic_open(chr);
aurel32ceecf1d2009-01-18 14:08:04 +00001506 if (chr->init)
1507 chr->init(chr);
bellarde7f0ad52004-07-14 17:28:59 +00001508}
pbrookc60e08d2008-07-01 16:24:38 +00001509
Kevin Wolf6e1db572011-06-01 13:29:11 +02001510int text_console_init(QemuOpts *opts, CharDriverState **_chr)
aliguori2796dae2009-01-16 20:23:27 +00001511{
1512 CharDriverState *chr;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001513 TextConsole *s;
1514 unsigned width;
1515 unsigned height;
aliguori2796dae2009-01-16 20:23:27 +00001516
Anthony Liguori7267c092011-08-20 22:09:37 -05001517 chr = g_malloc0(sizeof(CharDriverState));
aliguori2796dae2009-01-16 20:23:27 +00001518
1519 if (n_text_consoles == 128) {
1520 fprintf(stderr, "Too many text consoles\n");
1521 exit(1);
1522 }
1523 text_consoles[n_text_consoles] = chr;
aliguori2796dae2009-01-16 20:23:27 +00001524 n_text_consoles++;
1525
Paolo Bonzini491e1142010-12-23 13:42:51 +01001526 width = qemu_opt_get_number(opts, "width", 0);
1527 if (width == 0)
1528 width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1529
1530 height = qemu_opt_get_number(opts, "height", 0);
1531 if (height == 0)
1532 height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1533
1534 if (width == 0 || height == 0) {
1535 s = new_console(NULL, TEXT_CONSOLE);
1536 } else {
1537 s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1538 }
1539
1540 if (!s) {
Stefan Weil5354d082011-10-02 18:53:09 +02001541 g_free(chr);
Kevin Wolf6e1db572011-06-01 13:29:11 +02001542 return -EBUSY;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001543 }
1544
1545 s->chr = chr;
1546 s->g_width = width;
1547 s->g_height = height;
1548 chr->opaque = s;
Paolo Bonzini41048332010-12-23 13:42:52 +01001549 chr->chr_set_echo = text_console_set_echo;
Kevin Wolf6e1db572011-06-01 13:29:11 +02001550
1551 *_chr = chr;
1552 return 0;
aliguori2796dae2009-01-16 20:23:27 +00001553}
1554
1555void text_consoles_set_display(DisplayState *ds)
1556{
1557 int i;
1558
1559 for (i = 0; i < n_text_consoles; i++) {
Paolo Bonzini44b37b92010-12-23 13:42:53 +01001560 text_console_do_init(text_consoles[i], ds);
aliguori2796dae2009-01-16 20:23:27 +00001561 }
1562
1563 n_text_consoles = 0;
1564}
1565
aliguori3023f332009-01-16 19:04:14 +00001566void qemu_console_resize(DisplayState *ds, int width, int height)
pbrookc60e08d2008-07-01 16:24:38 +00001567{
aliguori42aa98e2009-01-16 21:01:48 +00001568 TextConsole *s = get_graphic_console(ds);
aliguorif497f142009-01-21 19:18:00 +00001569 if (!s) return;
1570
aliguori3023f332009-01-16 19:04:14 +00001571 s->g_width = width;
1572 s->g_height = height;
1573 if (is_graphic_console()) {
aliguori7b5d76d2009-03-13 15:02:13 +00001574 ds->surface = qemu_resize_displaysurface(ds, width, height);
aliguori3023f332009-01-16 19:04:14 +00001575 dpy_resize(ds);
pbrookc60e08d2008-07-01 16:24:38 +00001576 }
1577}
balrog38334f72008-09-24 02:21:24 +00001578
aliguori3023f332009-01-16 19:04:14 +00001579void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1580 int dst_x, int dst_y, int w, int h)
balrogc21bbcf2008-09-24 03:32:33 +00001581{
aliguori3023f332009-01-16 19:04:14 +00001582 if (is_graphic_console()) {
1583 dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
balrog38334f72008-09-24 02:21:24 +00001584 }
1585}
aliguori7d957bd2009-01-15 22:14:11 +00001586
malc0da2ea12009-01-23 19:56:19 +00001587PixelFormat qemu_different_endianness_pixelformat(int bpp)
aliguori7d957bd2009-01-15 22:14:11 +00001588{
1589 PixelFormat pf;
1590
1591 memset(&pf, 0x00, sizeof(PixelFormat));
1592
1593 pf.bits_per_pixel = bpp;
1594 pf.bytes_per_pixel = bpp / 8;
1595 pf.depth = bpp == 32 ? 24 : bpp;
1596
1597 switch (bpp) {
malc0da2ea12009-01-23 19:56:19 +00001598 case 24:
1599 pf.rmask = 0x000000FF;
1600 pf.gmask = 0x0000FF00;
1601 pf.bmask = 0x00FF0000;
1602 pf.rmax = 255;
1603 pf.gmax = 255;
1604 pf.bmax = 255;
1605 pf.rshift = 0;
1606 pf.gshift = 8;
1607 pf.bshift = 16;
aliguori90a1e3c2009-01-26 15:37:30 +00001608 pf.rbits = 8;
1609 pf.gbits = 8;
1610 pf.bbits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001611 break;
malc0da2ea12009-01-23 19:56:19 +00001612 case 32:
1613 pf.rmask = 0x0000FF00;
1614 pf.gmask = 0x00FF0000;
1615 pf.bmask = 0xFF000000;
1616 pf.amask = 0x00000000;
1617 pf.amax = 255;
1618 pf.rmax = 255;
1619 pf.gmax = 255;
1620 pf.bmax = 255;
1621 pf.ashift = 0;
1622 pf.rshift = 8;
1623 pf.gshift = 16;
1624 pf.bshift = 24;
aliguori90a1e3c2009-01-26 15:37:30 +00001625 pf.rbits = 8;
1626 pf.gbits = 8;
1627 pf.bbits = 8;
1628 pf.abits = 8;
malc0da2ea12009-01-23 19:56:19 +00001629 break;
1630 default:
1631 break;
1632 }
1633 return pf;
1634}
1635
1636PixelFormat qemu_default_pixelformat(int bpp)
1637{
1638 PixelFormat pf;
1639
1640 memset(&pf, 0x00, sizeof(PixelFormat));
1641
1642 pf.bits_per_pixel = bpp;
1643 pf.bytes_per_pixel = bpp / 8;
1644 pf.depth = bpp == 32 ? 24 : bpp;
1645
1646 switch (bpp) {
Gerd Hoffmannb6278082010-05-21 11:59:14 +02001647 case 15:
1648 pf.bits_per_pixel = 16;
1649 pf.bytes_per_pixel = 2;
1650 pf.rmask = 0x00007c00;
1651 pf.gmask = 0x000003E0;
1652 pf.bmask = 0x0000001F;
1653 pf.rmax = 31;
1654 pf.gmax = 31;
1655 pf.bmax = 31;
1656 pf.rshift = 10;
1657 pf.gshift = 5;
1658 pf.bshift = 0;
1659 pf.rbits = 5;
1660 pf.gbits = 5;
1661 pf.bbits = 5;
1662 break;
aliguori7d957bd2009-01-15 22:14:11 +00001663 case 16:
1664 pf.rmask = 0x0000F800;
1665 pf.gmask = 0x000007E0;
1666 pf.bmask = 0x0000001F;
1667 pf.rmax = 31;
1668 pf.gmax = 63;
1669 pf.bmax = 31;
1670 pf.rshift = 11;
1671 pf.gshift = 5;
1672 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001673 pf.rbits = 5;
1674 pf.gbits = 6;
1675 pf.bbits = 5;
aliguori7d957bd2009-01-15 22:14:11 +00001676 break;
1677 case 24:
aliguori7d957bd2009-01-15 22:14:11 +00001678 pf.rmask = 0x00FF0000;
1679 pf.gmask = 0x0000FF00;
1680 pf.bmask = 0x000000FF;
1681 pf.rmax = 255;
1682 pf.gmax = 255;
1683 pf.bmax = 255;
1684 pf.rshift = 16;
1685 pf.gshift = 8;
1686 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001687 pf.rbits = 8;
1688 pf.gbits = 8;
1689 pf.bbits = 8;
malc0da2ea12009-01-23 19:56:19 +00001690 case 32:
1691 pf.rmask = 0x00FF0000;
1692 pf.gmask = 0x0000FF00;
1693 pf.bmask = 0x000000FF;
1694 pf.amax = 255;
1695 pf.rmax = 255;
1696 pf.gmax = 255;
1697 pf.bmax = 255;
1698 pf.ashift = 24;
1699 pf.rshift = 16;
1700 pf.gshift = 8;
1701 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001702 pf.rbits = 8;
1703 pf.gbits = 8;
1704 pf.bbits = 8;
1705 pf.abits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001706 break;
1707 default:
1708 break;
1709 }
1710 return pf;
1711}