|
1 /* |
|
2 * QEMU graphical console |
|
3 * |
|
4 * Copyright (c) 2004 Fabrice Bellard |
|
5 * |
|
6 * 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 */ |
|
24 #include "qemu-common.h" |
|
25 #include "console.h" |
|
26 #include "qemu-timer.h" |
|
27 #include "gui_host.h" |
|
28 |
|
29 //#define DEBUG_CONSOLE |
|
30 #define DEFAULT_BACKSCROLL 512 |
|
31 #define DEFAULT_MONITOR_SIZE "800x600" |
|
32 |
|
33 #define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) |
|
34 #define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff) |
|
35 |
|
36 typedef struct TextAttributes { |
|
37 uint8_t fgcol:4; |
|
38 uint8_t bgcol:4; |
|
39 uint8_t bold:1; |
|
40 uint8_t uline:1; |
|
41 uint8_t blink:1; |
|
42 uint8_t invers:1; |
|
43 uint8_t unvisible:1; |
|
44 } TextAttributes; |
|
45 |
|
46 typedef struct TextCell { |
|
47 uint8_t ch; |
|
48 TextAttributes t_attrib; |
|
49 } TextCell; |
|
50 |
|
51 #define MAX_ESC_PARAMS 3 |
|
52 |
|
53 enum TTYState { |
|
54 TTY_STATE_NORM, |
|
55 TTY_STATE_ESC, |
|
56 TTY_STATE_CSI, |
|
57 }; |
|
58 |
|
59 typedef struct QEMUFIFO { |
|
60 uint8_t *buf; |
|
61 int buf_size; |
|
62 int count, wptr, rptr; |
|
63 } QEMUFIFO; |
|
64 |
|
65 static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1) |
|
66 { |
|
67 int l, len; |
|
68 |
|
69 l = f->buf_size - f->count; |
|
70 if (len1 > l) |
|
71 len1 = l; |
|
72 len = len1; |
|
73 while (len > 0) { |
|
74 l = f->buf_size - f->wptr; |
|
75 if (l > len) |
|
76 l = len; |
|
77 memcpy(f->buf + f->wptr, buf, l); |
|
78 f->wptr += l; |
|
79 if (f->wptr >= f->buf_size) |
|
80 f->wptr = 0; |
|
81 buf += l; |
|
82 len -= l; |
|
83 } |
|
84 f->count += len1; |
|
85 return len1; |
|
86 } |
|
87 |
|
88 static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1) |
|
89 { |
|
90 int l, len; |
|
91 |
|
92 if (len1 > f->count) |
|
93 len1 = f->count; |
|
94 len = len1; |
|
95 while (len > 0) { |
|
96 l = f->buf_size - f->rptr; |
|
97 if (l > len) |
|
98 l = len; |
|
99 memcpy(buf, f->buf + f->rptr, l); |
|
100 f->rptr += l; |
|
101 if (f->rptr >= f->buf_size) |
|
102 f->rptr = 0; |
|
103 buf += l; |
|
104 len -= l; |
|
105 } |
|
106 f->count -= len1; |
|
107 return len1; |
|
108 } |
|
109 |
|
110 struct TextConsole { |
|
111 int fixed_size; |
|
112 DisplayState *ds; |
|
113 /* Graphic console state. */ |
|
114 vga_hw_text_update_ptr hw_text_update; |
|
115 void *hw; |
|
116 |
|
117 int g_width, g_height; |
|
118 int width; |
|
119 int height; |
|
120 int total_height; |
|
121 int backscroll_height; |
|
122 int x, y; |
|
123 int x_saved, y_saved; |
|
124 int y_displayed; |
|
125 int y_base; |
|
126 TextAttributes t_attrib_default; /* default text attributes */ |
|
127 TextAttributes t_attrib; /* currently active text attributes */ |
|
128 TextCell *cells; |
|
129 int text_x[2], text_y[2], cursor_invalidate; |
|
130 |
|
131 enum TTYState state; |
|
132 int esc_params[MAX_ESC_PARAMS]; |
|
133 int nb_esc_params; |
|
134 |
|
135 CharDriverState *chr; |
|
136 /* fifo for key pressed */ |
|
137 QEMUFIFO out_fifo; |
|
138 uint8_t out_fifo_buf[16]; |
|
139 QEMUTimer *kbd_timer; |
|
140 }; |
|
141 |
|
142 /* convert a RGBA color to a color index usable in graphic primitives */ |
|
143 static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba) |
|
144 { |
|
145 unsigned int r, g, b, color; |
|
146 |
|
147 switch(ds_get_bits_per_pixel(ds)) { |
|
148 #if 0 |
|
149 case 8: |
|
150 r = (rgba >> 16) & 0xff; |
|
151 g = (rgba >> 8) & 0xff; |
|
152 b = (rgba) & 0xff; |
|
153 color = (rgb_to_index[r] * 6 * 6) + |
|
154 (rgb_to_index[g] * 6) + |
|
155 (rgb_to_index[b]); |
|
156 break; |
|
157 #endif |
|
158 case 15: |
|
159 r = (rgba >> 16) & 0xff; |
|
160 g = (rgba >> 8) & 0xff; |
|
161 b = (rgba) & 0xff; |
|
162 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); |
|
163 break; |
|
164 case 16: |
|
165 r = (rgba >> 16) & 0xff; |
|
166 g = (rgba >> 8) & 0xff; |
|
167 b = (rgba) & 0xff; |
|
168 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); |
|
169 break; |
|
170 case 32: |
|
171 default: |
|
172 color = rgba; |
|
173 break; |
|
174 } |
|
175 return color; |
|
176 } |
|
177 |
|
178 static void vga_fill_rect (DisplayState *ds, |
|
179 int posx, int posy, int width, int height, uint32_t color) |
|
180 { |
|
181 uint8_t *d, *d1; |
|
182 int x, y, bpp; |
|
183 |
|
184 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3; |
|
185 d1 = ds_get_data(ds) + |
|
186 ds_get_linesize(ds) * posy + bpp * posx; |
|
187 for (y = 0; y < height; y++) { |
|
188 d = d1; |
|
189 switch(bpp) { |
|
190 case 1: |
|
191 for (x = 0; x < width; x++) { |
|
192 *((uint8_t *)d) = color; |
|
193 d++; |
|
194 } |
|
195 break; |
|
196 case 2: |
|
197 for (x = 0; x < width; x++) { |
|
198 *((uint16_t *)d) = color; |
|
199 d += 2; |
|
200 } |
|
201 break; |
|
202 case 4: |
|
203 for (x = 0; x < width; x++) { |
|
204 *((uint32_t *)d) = color; |
|
205 d += 4; |
|
206 } |
|
207 break; |
|
208 } |
|
209 d1 += ds_get_linesize(ds); |
|
210 } |
|
211 } |
|
212 |
|
213 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */ |
|
214 static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h) |
|
215 { |
|
216 const uint8_t *s; |
|
217 uint8_t *d; |
|
218 int wb, y, bpp; |
|
219 |
|
220 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3; |
|
221 wb = w * bpp; |
|
222 if (yd <= ys) { |
|
223 s = ds_get_data(ds) + |
|
224 ds_get_linesize(ds) * ys + bpp * xs; |
|
225 d = ds_get_data(ds) + |
|
226 ds_get_linesize(ds) * yd + bpp * xd; |
|
227 for (y = 0; y < h; y++) { |
|
228 memmove(d, s, wb); |
|
229 d += ds_get_linesize(ds); |
|
230 s += ds_get_linesize(ds); |
|
231 } |
|
232 } else { |
|
233 s = ds_get_data(ds) + |
|
234 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs; |
|
235 d = ds_get_data(ds) + |
|
236 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd; |
|
237 for (y = 0; y < h; y++) { |
|
238 memmove(d, s, wb); |
|
239 d -= ds_get_linesize(ds); |
|
240 s -= ds_get_linesize(ds); |
|
241 } |
|
242 } |
|
243 } |
|
244 |
|
245 /***********************************************************/ |
|
246 /* basic char display */ |
|
247 |
|
248 #define FONT_HEIGHT 16 |
|
249 #define FONT_WIDTH 8 |
|
250 |
|
251 #include "vgafont.h" |
|
252 |
|
253 #define cbswap_32(__x) \ |
|
254 ((uint32_t)( \ |
|
255 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ |
|
256 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ |
|
257 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ |
|
258 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )) |
|
259 |
|
260 #ifdef WORDS_BIGENDIAN |
|
261 #define PAT(x) x |
|
262 #else |
|
263 #define PAT(x) cbswap_32(x) |
|
264 #endif |
|
265 |
|
266 static const uint32_t dmask16[16] = { |
|
267 PAT(0x00000000), |
|
268 PAT(0x000000ff), |
|
269 PAT(0x0000ff00), |
|
270 PAT(0x0000ffff), |
|
271 PAT(0x00ff0000), |
|
272 PAT(0x00ff00ff), |
|
273 PAT(0x00ffff00), |
|
274 PAT(0x00ffffff), |
|
275 PAT(0xff000000), |
|
276 PAT(0xff0000ff), |
|
277 PAT(0xff00ff00), |
|
278 PAT(0xff00ffff), |
|
279 PAT(0xffff0000), |
|
280 PAT(0xffff00ff), |
|
281 PAT(0xffffff00), |
|
282 PAT(0xffffffff), |
|
283 }; |
|
284 |
|
285 static const uint32_t dmask4[4] = { |
|
286 PAT(0x00000000), |
|
287 PAT(0x0000ffff), |
|
288 PAT(0xffff0000), |
|
289 PAT(0xffffffff), |
|
290 }; |
|
291 |
|
292 static uint32_t color_table[2][8]; |
|
293 |
|
294 enum color_names { |
|
295 COLOR_BLACK = 0, |
|
296 COLOR_RED = 1, |
|
297 COLOR_GREEN = 2, |
|
298 COLOR_YELLOW = 3, |
|
299 COLOR_BLUE = 4, |
|
300 COLOR_MAGENTA = 5, |
|
301 COLOR_CYAN = 6, |
|
302 COLOR_WHITE = 7 |
|
303 }; |
|
304 |
|
305 static const uint32_t color_table_rgb[2][8] = { |
|
306 { /* dark */ |
|
307 QEMU_RGB(0x00, 0x00, 0x00), /* black */ |
|
308 QEMU_RGB(0xaa, 0x00, 0x00), /* red */ |
|
309 QEMU_RGB(0x00, 0xaa, 0x00), /* green */ |
|
310 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */ |
|
311 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */ |
|
312 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */ |
|
313 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */ |
|
314 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */ |
|
315 }, |
|
316 { /* bright */ |
|
317 QEMU_RGB(0x00, 0x00, 0x00), /* black */ |
|
318 QEMU_RGB(0xff, 0x00, 0x00), /* red */ |
|
319 QEMU_RGB(0x00, 0xff, 0x00), /* green */ |
|
320 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */ |
|
321 QEMU_RGB(0x00, 0x00, 0xff), /* blue */ |
|
322 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */ |
|
323 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */ |
|
324 QEMU_RGB(0xff, 0xff, 0xff), /* white */ |
|
325 } |
|
326 }; |
|
327 |
|
328 static inline unsigned int col_expand(DisplayState *ds, unsigned int col) |
|
329 { |
|
330 switch(ds_get_bits_per_pixel(ds)) { |
|
331 case 8: |
|
332 col |= col << 8; |
|
333 col |= col << 16; |
|
334 break; |
|
335 case 15: |
|
336 case 16: |
|
337 col |= col << 16; |
|
338 break; |
|
339 default: |
|
340 break; |
|
341 } |
|
342 |
|
343 return col; |
|
344 } |
|
345 #ifdef DEBUG_CONSOLE |
|
346 static void console_print_text_attributes(TextAttributes *t_attrib, char ch) |
|
347 { |
|
348 if (t_attrib->bold) { |
|
349 printf("b"); |
|
350 } else { |
|
351 printf(" "); |
|
352 } |
|
353 if (t_attrib->uline) { |
|
354 printf("u"); |
|
355 } else { |
|
356 printf(" "); |
|
357 } |
|
358 if (t_attrib->blink) { |
|
359 printf("l"); |
|
360 } else { |
|
361 printf(" "); |
|
362 } |
|
363 if (t_attrib->invers) { |
|
364 printf("i"); |
|
365 } else { |
|
366 printf(" "); |
|
367 } |
|
368 if (t_attrib->unvisible) { |
|
369 printf("n"); |
|
370 } else { |
|
371 printf(" "); |
|
372 } |
|
373 |
|
374 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch); |
|
375 } |
|
376 #endif |
|
377 |
|
378 static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, |
|
379 TextAttributes *t_attrib) |
|
380 { |
|
381 uint8_t *d; |
|
382 const uint8_t *font_ptr; |
|
383 unsigned int font_data, linesize, xorcol, bpp; |
|
384 int i; |
|
385 unsigned int fgcol, bgcol; |
|
386 |
|
387 #ifdef DEBUG_CONSOLE |
|
388 printf("x: %2i y: %2i", x, y); |
|
389 console_print_text_attributes(t_attrib, ch); |
|
390 #endif |
|
391 |
|
392 if (t_attrib->invers) { |
|
393 bgcol = color_table[t_attrib->bold][t_attrib->fgcol]; |
|
394 fgcol = color_table[t_attrib->bold][t_attrib->bgcol]; |
|
395 } else { |
|
396 fgcol = color_table[t_attrib->bold][t_attrib->fgcol]; |
|
397 bgcol = color_table[t_attrib->bold][t_attrib->bgcol]; |
|
398 } |
|
399 |
|
400 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3; |
|
401 d = ds_get_data(ds) + |
|
402 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH; |
|
403 linesize = ds_get_linesize(ds); |
|
404 font_ptr = vgafont16 + FONT_HEIGHT * ch; |
|
405 xorcol = bgcol ^ fgcol; |
|
406 switch(ds_get_bits_per_pixel(ds)) { |
|
407 case 8: |
|
408 for(i = 0; i < FONT_HEIGHT; i++) { |
|
409 font_data = *font_ptr++; |
|
410 if (t_attrib->uline |
|
411 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) { |
|
412 font_data = 0xFFFF; |
|
413 } |
|
414 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol; |
|
415 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol; |
|
416 d += linesize; |
|
417 } |
|
418 break; |
|
419 case 16: |
|
420 case 15: |
|
421 for(i = 0; i < FONT_HEIGHT; i++) { |
|
422 font_data = *font_ptr++; |
|
423 if (t_attrib->uline |
|
424 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) { |
|
425 font_data = 0xFFFF; |
|
426 } |
|
427 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol; |
|
428 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol; |
|
429 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol; |
|
430 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol; |
|
431 d += linesize; |
|
432 } |
|
433 break; |
|
434 case 32: |
|
435 for(i = 0; i < FONT_HEIGHT; i++) { |
|
436 font_data = *font_ptr++; |
|
437 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) { |
|
438 font_data = 0xFFFF; |
|
439 } |
|
440 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol; |
|
441 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol; |
|
442 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol; |
|
443 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol; |
|
444 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol; |
|
445 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol; |
|
446 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol; |
|
447 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol; |
|
448 d += linesize; |
|
449 } |
|
450 break; |
|
451 } |
|
452 } |
|
453 |
|
454 static void text_console_resize_int(TextConsole *s) |
|
455 { |
|
456 TextCell *cells, *c, *c1; |
|
457 int w1, x, y, last_width; |
|
458 |
|
459 last_width = s->width; |
|
460 s->width = s->g_width / FONT_WIDTH; |
|
461 s->height = s->g_height / FONT_HEIGHT; |
|
462 |
|
463 w1 = last_width; |
|
464 if (s->width < w1) |
|
465 w1 = s->width; |
|
466 |
|
467 cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell)); |
|
468 for(y = 0; y < s->total_height; y++) { |
|
469 c = &cells[y * s->width]; |
|
470 if (w1 > 0) { |
|
471 c1 = &s->cells[y * last_width]; |
|
472 for(x = 0; x < w1; x++) { |
|
473 *c++ = *c1++; |
|
474 } |
|
475 } |
|
476 for(x = w1; x < s->width; x++) { |
|
477 c->ch = ' '; |
|
478 c->t_attrib = s->t_attrib_default; |
|
479 c++; |
|
480 } |
|
481 } |
|
482 qemu_free(s->cells); |
|
483 s->cells = cells; |
|
484 } |
|
485 |
|
486 static inline void text_update_xy(TextConsole *s, int x, int y) |
|
487 { |
|
488 s->text_x[0] = MIN(s->text_x[0], x); |
|
489 s->text_x[1] = MAX(s->text_x[1], x); |
|
490 s->text_y[0] = MIN(s->text_y[0], y); |
|
491 s->text_y[1] = MAX(s->text_y[1], y); |
|
492 } |
|
493 |
|
494 static void update_xy(TextConsole *s, int x, int y) |
|
495 { |
|
496 TextCell *c; |
|
497 int y1, y2; |
|
498 |
|
499 if (gui_is_display_active(s->ds)) { |
|
500 if (!ds_get_bits_per_pixel(s->ds)) { |
|
501 text_update_xy(s, x, y); |
|
502 return; |
|
503 } |
|
504 |
|
505 y1 = (s->y_base + y) % s->total_height; |
|
506 y2 = y1 - s->y_displayed; |
|
507 if (y2 < 0) |
|
508 y2 += s->total_height; |
|
509 if (y2 < s->height) { |
|
510 c = &s->cells[y1 * s->width + x]; |
|
511 vga_putcharxy(s->ds, x, y2, c->ch, |
|
512 &(c->t_attrib)); |
|
513 dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT, |
|
514 FONT_WIDTH, FONT_HEIGHT); |
|
515 } |
|
516 } |
|
517 } |
|
518 |
|
519 static void console_show_cursor(TextConsole *s, int show) |
|
520 { |
|
521 TextCell *c; |
|
522 int y, y1; |
|
523 |
|
524 if (gui_is_display_active(s->ds)) { |
|
525 int x = s->x; |
|
526 |
|
527 if (!ds_get_bits_per_pixel(s->ds)) { |
|
528 s->cursor_invalidate = 1; |
|
529 return; |
|
530 } |
|
531 |
|
532 if (x >= s->width) { |
|
533 x = s->width - 1; |
|
534 } |
|
535 y1 = (s->y_base + s->y) % s->total_height; |
|
536 y = y1 - s->y_displayed; |
|
537 if (y < 0) |
|
538 y += s->total_height; |
|
539 if (y < s->height) { |
|
540 c = &s->cells[y1 * s->width + x]; |
|
541 if (show) { |
|
542 TextAttributes t_attrib = s->t_attrib_default; |
|
543 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */ |
|
544 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib); |
|
545 } else { |
|
546 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib)); |
|
547 } |
|
548 dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT, |
|
549 FONT_WIDTH, FONT_HEIGHT); |
|
550 } |
|
551 } |
|
552 } |
|
553 |
|
554 static void console_refresh(TextConsole *s) |
|
555 { |
|
556 TextCell *c; |
|
557 int x, y, y1; |
|
558 |
|
559 if (!gui_is_display_active(s->ds)) |
|
560 return; |
|
561 if (!ds_get_bits_per_pixel(s->ds)) { |
|
562 s->text_x[0] = 0; |
|
563 s->text_y[0] = 0; |
|
564 s->text_x[1] = s->width - 1; |
|
565 s->text_y[1] = s->height - 1; |
|
566 s->cursor_invalidate = 1; |
|
567 return; |
|
568 } |
|
569 |
|
570 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds), |
|
571 color_table[0][COLOR_BLACK]); |
|
572 y1 = s->y_displayed; |
|
573 for(y = 0; y < s->height; y++) { |
|
574 c = s->cells + y1 * s->width; |
|
575 for(x = 0; x < s->width; x++) { |
|
576 vga_putcharxy(s->ds, x, y, c->ch, |
|
577 &(c->t_attrib)); |
|
578 c++; |
|
579 } |
|
580 if (++y1 == s->total_height) |
|
581 y1 = 0; |
|
582 } |
|
583 dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds)); |
|
584 console_show_cursor(s, 1); |
|
585 } |
|
586 |
|
587 static void console_scroll(TextConsole *s, int ydelta) |
|
588 { |
|
589 |
|
590 int i, y1; |
|
591 |
|
592 if (!s) |
|
593 return; |
|
594 |
|
595 if (ydelta > 0) { |
|
596 for(i = 0; i < ydelta; i++) { |
|
597 if (s->y_displayed == s->y_base) |
|
598 break; |
|
599 if (++s->y_displayed == s->total_height) |
|
600 s->y_displayed = 0; |
|
601 } |
|
602 } else { |
|
603 ydelta = -ydelta; |
|
604 i = s->backscroll_height; |
|
605 if (i > s->total_height - s->height) |
|
606 i = s->total_height - s->height; |
|
607 y1 = s->y_base - i; |
|
608 if (y1 < 0) |
|
609 y1 += s->total_height; |
|
610 for(i = 0; i < ydelta; i++) { |
|
611 if (s->y_displayed == y1) |
|
612 break; |
|
613 if (--s->y_displayed < 0) |
|
614 s->y_displayed = s->total_height - 1; |
|
615 } |
|
616 } |
|
617 console_refresh(s); |
|
618 } |
|
619 |
|
620 static void console_put_lf(TextConsole *s) |
|
621 { |
|
622 TextCell *c; |
|
623 int x, y1; |
|
624 |
|
625 s->y++; |
|
626 if (s->y >= s->height) { |
|
627 s->y = s->height - 1; |
|
628 |
|
629 if (s->y_displayed == s->y_base) { |
|
630 if (++s->y_displayed == s->total_height) |
|
631 s->y_displayed = 0; |
|
632 } |
|
633 if (++s->y_base == s->total_height) |
|
634 s->y_base = 0; |
|
635 if (s->backscroll_height < s->total_height) |
|
636 s->backscroll_height++; |
|
637 y1 = (s->y_base + s->height - 1) % s->total_height; |
|
638 c = &s->cells[y1 * s->width]; |
|
639 for(x = 0; x < s->width; x++) { |
|
640 c->ch = ' '; |
|
641 c->t_attrib = s->t_attrib_default; |
|
642 c++; |
|
643 } |
|
644 if (gui_is_display_active(s->ds) && s->y_displayed == s->y_base) { |
|
645 if (!ds_get_bits_per_pixel(s->ds)) { |
|
646 s->text_x[0] = 0; |
|
647 s->text_y[0] = 0; |
|
648 s->text_x[1] = s->width - 1; |
|
649 s->text_y[1] = s->height - 1; |
|
650 return; |
|
651 } |
|
652 |
|
653 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, |
|
654 s->width * FONT_WIDTH, |
|
655 (s->height - 1) * FONT_HEIGHT); |
|
656 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT, |
|
657 s->width * FONT_WIDTH, FONT_HEIGHT, |
|
658 color_table[0][s->t_attrib_default.bgcol]); |
|
659 dpy_update(s->ds, 0, 0, |
|
660 s->width * FONT_WIDTH, s->height * FONT_HEIGHT); |
|
661 } |
|
662 } |
|
663 } |
|
664 |
|
665 /* Set console attributes depending on the current escape codes. |
|
666 * NOTE: I know this code is not very efficient (checking every color for it |
|
667 * self) but it is more readable and better maintainable. |
|
668 */ |
|
669 static void console_handle_escape(TextConsole *s) |
|
670 { |
|
671 int i; |
|
672 |
|
673 for (i=0; i<s->nb_esc_params; i++) { |
|
674 switch (s->esc_params[i]) { |
|
675 case 0: /* reset all console attributes to default */ |
|
676 s->t_attrib = s->t_attrib_default; |
|
677 break; |
|
678 case 1: |
|
679 s->t_attrib.bold = 1; |
|
680 break; |
|
681 case 4: |
|
682 s->t_attrib.uline = 1; |
|
683 break; |
|
684 case 5: |
|
685 s->t_attrib.blink = 1; |
|
686 break; |
|
687 case 7: |
|
688 s->t_attrib.invers = 1; |
|
689 break; |
|
690 case 8: |
|
691 s->t_attrib.unvisible = 1; |
|
692 break; |
|
693 case 22: |
|
694 s->t_attrib.bold = 0; |
|
695 break; |
|
696 case 24: |
|
697 s->t_attrib.uline = 0; |
|
698 break; |
|
699 case 25: |
|
700 s->t_attrib.blink = 0; |
|
701 break; |
|
702 case 27: |
|
703 s->t_attrib.invers = 0; |
|
704 break; |
|
705 case 28: |
|
706 s->t_attrib.unvisible = 0; |
|
707 break; |
|
708 /* set foreground color */ |
|
709 case 30: |
|
710 s->t_attrib.fgcol=COLOR_BLACK; |
|
711 break; |
|
712 case 31: |
|
713 s->t_attrib.fgcol=COLOR_RED; |
|
714 break; |
|
715 case 32: |
|
716 s->t_attrib.fgcol=COLOR_GREEN; |
|
717 break; |
|
718 case 33: |
|
719 s->t_attrib.fgcol=COLOR_YELLOW; |
|
720 break; |
|
721 case 34: |
|
722 s->t_attrib.fgcol=COLOR_BLUE; |
|
723 break; |
|
724 case 35: |
|
725 s->t_attrib.fgcol=COLOR_MAGENTA; |
|
726 break; |
|
727 case 36: |
|
728 s->t_attrib.fgcol=COLOR_CYAN; |
|
729 break; |
|
730 case 37: |
|
731 s->t_attrib.fgcol=COLOR_WHITE; |
|
732 break; |
|
733 /* set background color */ |
|
734 case 40: |
|
735 s->t_attrib.bgcol=COLOR_BLACK; |
|
736 break; |
|
737 case 41: |
|
738 s->t_attrib.bgcol=COLOR_RED; |
|
739 break; |
|
740 case 42: |
|
741 s->t_attrib.bgcol=COLOR_GREEN; |
|
742 break; |
|
743 case 43: |
|
744 s->t_attrib.bgcol=COLOR_YELLOW; |
|
745 break; |
|
746 case 44: |
|
747 s->t_attrib.bgcol=COLOR_BLUE; |
|
748 break; |
|
749 case 45: |
|
750 s->t_attrib.bgcol=COLOR_MAGENTA; |
|
751 break; |
|
752 case 46: |
|
753 s->t_attrib.bgcol=COLOR_CYAN; |
|
754 break; |
|
755 case 47: |
|
756 s->t_attrib.bgcol=COLOR_WHITE; |
|
757 break; |
|
758 } |
|
759 } |
|
760 } |
|
761 |
|
762 static void console_clear_xy(TextConsole *s, int x, int y) |
|
763 { |
|
764 int y1 = (s->y_base + y) % s->total_height; |
|
765 TextCell *c = &s->cells[y1 * s->width + x]; |
|
766 c->ch = ' '; |
|
767 c->t_attrib = s->t_attrib_default; |
|
768 c++; |
|
769 update_xy(s, x, y); |
|
770 } |
|
771 |
|
772 static void console_putchar(TextConsole *s, int ch) |
|
773 { |
|
774 TextCell *c; |
|
775 int y1, i; |
|
776 int x, y; |
|
777 |
|
778 switch(s->state) { |
|
779 case TTY_STATE_NORM: |
|
780 switch(ch) { |
|
781 case '\r': /* carriage return */ |
|
782 s->x = 0; |
|
783 break; |
|
784 case '\n': /* newline */ |
|
785 console_put_lf(s); |
|
786 break; |
|
787 case '\b': /* backspace */ |
|
788 if (s->x > 0) |
|
789 s->x--; |
|
790 break; |
|
791 case '\t': /* tabspace */ |
|
792 if (s->x + (8 - (s->x % 8)) > s->width) { |
|
793 s->x = 0; |
|
794 console_put_lf(s); |
|
795 } else { |
|
796 s->x = s->x + (8 - (s->x % 8)); |
|
797 } |
|
798 break; |
|
799 case '\a': /* alert aka. bell */ |
|
800 /* TODO: has to be implemented */ |
|
801 break; |
|
802 case 14: |
|
803 /* SI (shift in), character set 0 (ignored) */ |
|
804 break; |
|
805 case 15: |
|
806 /* SO (shift out), character set 1 (ignored) */ |
|
807 break; |
|
808 case 27: /* esc (introducing an escape sequence) */ |
|
809 s->state = TTY_STATE_ESC; |
|
810 break; |
|
811 default: |
|
812 if (s->x >= s->width) { |
|
813 /* line wrap */ |
|
814 s->x = 0; |
|
815 console_put_lf(s); |
|
816 } |
|
817 y1 = (s->y_base + s->y) % s->total_height; |
|
818 c = &s->cells[y1 * s->width + s->x]; |
|
819 c->ch = ch; |
|
820 c->t_attrib = s->t_attrib; |
|
821 update_xy(s, s->x, s->y); |
|
822 s->x++; |
|
823 break; |
|
824 } |
|
825 break; |
|
826 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */ |
|
827 if (ch == '[') { |
|
828 for(i=0;i<MAX_ESC_PARAMS;i++) |
|
829 s->esc_params[i] = 0; |
|
830 s->nb_esc_params = 0; |
|
831 s->state = TTY_STATE_CSI; |
|
832 } else { |
|
833 s->state = TTY_STATE_NORM; |
|
834 } |
|
835 break; |
|
836 case TTY_STATE_CSI: /* handle escape sequence parameters */ |
|
837 if (ch >= '0' && ch <= '9') { |
|
838 if (s->nb_esc_params < MAX_ESC_PARAMS) { |
|
839 s->esc_params[s->nb_esc_params] = |
|
840 s->esc_params[s->nb_esc_params] * 10 + ch - '0'; |
|
841 } |
|
842 } else { |
|
843 s->nb_esc_params++; |
|
844 if (ch == ';') |
|
845 break; |
|
846 #ifdef DEBUG_CONSOLE |
|
847 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n", |
|
848 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params); |
|
849 #endif |
|
850 s->state = TTY_STATE_NORM; |
|
851 switch(ch) { |
|
852 case 'A': |
|
853 /* move cursor up */ |
|
854 if (s->esc_params[0] == 0) { |
|
855 s->esc_params[0] = 1; |
|
856 } |
|
857 s->y -= s->esc_params[0]; |
|
858 if (s->y < 0) { |
|
859 s->y = 0; |
|
860 } |
|
861 break; |
|
862 case 'B': |
|
863 /* move cursor down */ |
|
864 if (s->esc_params[0] == 0) { |
|
865 s->esc_params[0] = 1; |
|
866 } |
|
867 s->y += s->esc_params[0]; |
|
868 if (s->y >= s->height) { |
|
869 s->y = s->height - 1; |
|
870 } |
|
871 break; |
|
872 case 'C': |
|
873 /* move cursor right */ |
|
874 if (s->esc_params[0] == 0) { |
|
875 s->esc_params[0] = 1; |
|
876 } |
|
877 s->x += s->esc_params[0]; |
|
878 if (s->x >= s->width) { |
|
879 s->x = s->width - 1; |
|
880 } |
|
881 break; |
|
882 case 'D': |
|
883 /* move cursor left */ |
|
884 if (s->esc_params[0] == 0) { |
|
885 s->esc_params[0] = 1; |
|
886 } |
|
887 s->x -= s->esc_params[0]; |
|
888 if (s->x < 0) { |
|
889 s->x = 0; |
|
890 } |
|
891 break; |
|
892 case 'G': |
|
893 /* move cursor to column */ |
|
894 s->x = s->esc_params[0] - 1; |
|
895 if (s->x < 0) { |
|
896 s->x = 0; |
|
897 } |
|
898 break; |
|
899 case 'f': |
|
900 case 'H': |
|
901 /* move cursor to row, column */ |
|
902 s->x = s->esc_params[1] - 1; |
|
903 if (s->x < 0) { |
|
904 s->x = 0; |
|
905 } |
|
906 s->y = s->esc_params[0] - 1; |
|
907 if (s->y < 0) { |
|
908 s->y = 0; |
|
909 } |
|
910 break; |
|
911 case 'J': |
|
912 switch (s->esc_params[0]) { |
|
913 case 0: |
|
914 /* clear to end of screen */ |
|
915 for (y = s->y; y < s->height; y++) { |
|
916 for (x = 0; x < s->width; x++) { |
|
917 if (y == s->y && x < s->x) { |
|
918 continue; |
|
919 } |
|
920 console_clear_xy(s, x, y); |
|
921 } |
|
922 } |
|
923 break; |
|
924 case 1: |
|
925 /* clear from beginning of screen */ |
|
926 for (y = 0; y <= s->y; y++) { |
|
927 for (x = 0; x < s->width; x++) { |
|
928 if (y == s->y && x > s->x) { |
|
929 break; |
|
930 } |
|
931 console_clear_xy(s, x, y); |
|
932 } |
|
933 } |
|
934 break; |
|
935 case 2: |
|
936 /* clear entire screen */ |
|
937 for (y = 0; y <= s->height; y++) { |
|
938 for (x = 0; x < s->width; x++) { |
|
939 console_clear_xy(s, x, y); |
|
940 } |
|
941 } |
|
942 break; |
|
943 } |
|
944 case 'K': |
|
945 switch (s->esc_params[0]) { |
|
946 case 0: |
|
947 /* clear to eol */ |
|
948 for(x = s->x; x < s->width; x++) { |
|
949 console_clear_xy(s, x, s->y); |
|
950 } |
|
951 break; |
|
952 case 1: |
|
953 /* clear from beginning of line */ |
|
954 for (x = 0; x <= s->x; x++) { |
|
955 console_clear_xy(s, x, s->y); |
|
956 } |
|
957 break; |
|
958 case 2: |
|
959 /* clear entire line */ |
|
960 for(x = 0; x < s->width; x++) { |
|
961 console_clear_xy(s, x, s->y); |
|
962 } |
|
963 break; |
|
964 } |
|
965 break; |
|
966 case 'm': |
|
967 console_handle_escape(s); |
|
968 break; |
|
969 case 'n': |
|
970 /* report cursor position */ |
|
971 /* TODO: send ESC[row;colR */ |
|
972 break; |
|
973 case 's': |
|
974 /* save cursor position */ |
|
975 s->x_saved = s->x; |
|
976 s->y_saved = s->y; |
|
977 break; |
|
978 case 'u': |
|
979 /* restore cursor position */ |
|
980 s->x = s->x_saved; |
|
981 s->y = s->y_saved; |
|
982 break; |
|
983 default: |
|
984 #ifdef DEBUG_CONSOLE |
|
985 fprintf(stderr, "unhandled escape character '%c'\n", ch); |
|
986 #endif |
|
987 break; |
|
988 } |
|
989 break; |
|
990 } |
|
991 } |
|
992 } |
|
993 |
|
994 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len) |
|
995 { |
|
996 TextConsole *s = chr->opaque; |
|
997 int i; |
|
998 |
|
999 console_show_cursor(s, 0); |
|
1000 for(i = 0; i < len; i++) { |
|
1001 console_putchar(s, buf[i]); |
|
1002 } |
|
1003 console_show_cursor(s, 1); |
|
1004 return len; |
|
1005 } |
|
1006 |
|
1007 static void console_send_event(CharDriverState *chr, int event) |
|
1008 { |
|
1009 TextConsole *s = chr->opaque; |
|
1010 |
|
1011 if (event == CHR_EVENT_FOCUS) { |
|
1012 gui_notify_activate_display(s->ds); |
|
1013 } |
|
1014 } |
|
1015 |
|
1016 static void kbd_send_chars(void *opaque) |
|
1017 { |
|
1018 TextConsole *s = opaque; |
|
1019 int len; |
|
1020 uint8_t buf[16]; |
|
1021 |
|
1022 len = qemu_chr_can_read(s->chr); |
|
1023 if (len > s->out_fifo.count) |
|
1024 len = s->out_fifo.count; |
|
1025 if (len > 0) { |
|
1026 if (len > sizeof(buf)) |
|
1027 len = sizeof(buf); |
|
1028 qemu_fifo_read(&s->out_fifo, buf, len); |
|
1029 qemu_chr_read(s->chr, buf, len); |
|
1030 } |
|
1031 /* characters are pending: we send them a bit later (XXX: |
|
1032 horrible, should change char device API) */ |
|
1033 if (s->out_fifo.count > 0) { |
|
1034 qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1); |
|
1035 } |
|
1036 } |
|
1037 |
|
1038 /* called when an ascii key is pressed */ |
|
1039 static void kbd_put_keysym(void *opaque, int keysym) |
|
1040 { |
|
1041 TextConsole * const s = opaque; |
|
1042 uint8_t buf[16], *q; |
|
1043 int c; |
|
1044 |
|
1045 if (!s) |
|
1046 return; |
|
1047 |
|
1048 switch(keysym) { |
|
1049 case QEMU_KEY_CTRL_UP: |
|
1050 console_scroll(s, -1); |
|
1051 break; |
|
1052 case QEMU_KEY_CTRL_DOWN: |
|
1053 console_scroll(s, 1); |
|
1054 break; |
|
1055 case QEMU_KEY_CTRL_PAGEUP: |
|
1056 console_scroll(s, -10); |
|
1057 break; |
|
1058 case QEMU_KEY_CTRL_PAGEDOWN: |
|
1059 console_scroll(s, 10); |
|
1060 break; |
|
1061 default: |
|
1062 /* convert the QEMU keysym to VT100 key string */ |
|
1063 q = buf; |
|
1064 if (keysym >= 0xe100 && keysym <= 0xe11f) { |
|
1065 *q++ = '\033'; |
|
1066 *q++ = '['; |
|
1067 c = keysym - 0xe100; |
|
1068 if (c >= 10) |
|
1069 *q++ = '0' + (c / 10); |
|
1070 *q++ = '0' + (c % 10); |
|
1071 *q++ = '~'; |
|
1072 } else if (keysym >= 0xe120 && keysym <= 0xe17f) { |
|
1073 *q++ = '\033'; |
|
1074 *q++ = '['; |
|
1075 *q++ = keysym & 0xff; |
|
1076 } else { |
|
1077 *q++ = keysym; |
|
1078 } |
|
1079 if (s->chr->chr_read) { |
|
1080 qemu_fifo_write(&s->out_fifo, buf, q - buf); |
|
1081 kbd_send_chars(s); |
|
1082 } |
|
1083 break; |
|
1084 } |
|
1085 } |
|
1086 |
|
1087 static void text_console_invalidate(void *opaque) |
|
1088 { |
|
1089 TextConsole *s = (TextConsole *) opaque; |
|
1090 |
|
1091 if (s->g_width != ds_get_width(s->ds) || s->g_height != ds_get_height(s->ds)) { |
|
1092 if (s->fixed_size) { |
|
1093 gui_resize_vt(s->ds, s->g_width, s->g_height); |
|
1094 } else { |
|
1095 s->g_width = ds_get_width(s->ds); |
|
1096 s->g_height = ds_get_height(s->ds); |
|
1097 text_console_resize_int(s); |
|
1098 } |
|
1099 } |
|
1100 console_refresh(s); |
|
1101 } |
|
1102 |
|
1103 static void text_console_update(void *opaque, console_ch_t *chardata) |
|
1104 { |
|
1105 TextConsole *s = (TextConsole *) opaque; |
|
1106 int i, j, src; |
|
1107 |
|
1108 if (s->text_x[0] <= s->text_x[1]) { |
|
1109 src = (s->y_base + s->text_y[0]) * s->width; |
|
1110 chardata += s->text_y[0] * s->width; |
|
1111 for (i = s->text_y[0]; i <= s->text_y[1]; i ++) |
|
1112 for (j = 0; j < s->width; j ++, src ++) |
|
1113 console_write_ch(chardata ++, s->cells[src].ch | |
|
1114 (s->cells[src].t_attrib.fgcol << 12) | |
|
1115 (s->cells[src].t_attrib.bgcol << 8) | |
|
1116 (s->cells[src].t_attrib.bold << 21)); |
|
1117 dpy_update(s->ds, s->text_x[0], s->text_y[0], |
|
1118 s->text_x[1] - s->text_x[0], i - s->text_y[0]); |
|
1119 s->text_x[0] = s->width; |
|
1120 s->text_y[0] = s->height; |
|
1121 s->text_x[1] = 0; |
|
1122 s->text_y[1] = 0; |
|
1123 } |
|
1124 if (s->cursor_invalidate) { |
|
1125 dpy_cursor(s->ds, s->x, s->y); |
|
1126 s->cursor_invalidate = 0; |
|
1127 } |
|
1128 } |
|
1129 |
|
1130 int is_fixed_size_console(const TextConsole *console) |
|
1131 { |
|
1132 return console->fixed_size; |
|
1133 } |
|
1134 |
|
1135 void console_color_init(DisplayState *ds) |
|
1136 { |
|
1137 int i, j; |
|
1138 for (j = 0; j < 2; j++) { |
|
1139 for (i = 0; i < 8; i++) { |
|
1140 color_table[j][i] = col_expand(ds, |
|
1141 vga_get_color(ds, color_table_rgb[j][i])); |
|
1142 } |
|
1143 } |
|
1144 } |
|
1145 |
|
1146 CharDriverState *text_console_init(DisplayState *ds, const char *p) |
|
1147 { |
|
1148 CharDriverState *chr; |
|
1149 TextConsole *s; |
|
1150 unsigned width; |
|
1151 unsigned height; |
|
1152 static int color_inited; |
|
1153 const int fixed_size = (p != 0); |
|
1154 |
|
1155 chr = qemu_mallocz(sizeof(CharDriverState)); |
|
1156 if (!chr) |
|
1157 return NULL; |
|
1158 |
|
1159 s = qemu_mallocz(sizeof(TextConsole)); |
|
1160 if (!s) { |
|
1161 free(chr); |
|
1162 return NULL; |
|
1163 } |
|
1164 s->ds = ds; |
|
1165 s->fixed_size = fixed_size; |
|
1166 |
|
1167 chr->opaque = s; |
|
1168 chr->chr_write = console_puts; |
|
1169 chr->chr_send_event = console_send_event; |
|
1170 |
|
1171 s->chr = chr; |
|
1172 s->out_fifo.buf = s->out_fifo_buf; |
|
1173 s->out_fifo.buf_size = sizeof(s->out_fifo_buf); |
|
1174 s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s); |
|
1175 gui_register_vt_key_callback(s->ds, kbd_put_keysym, s); |
|
1176 |
|
1177 if (!color_inited) { |
|
1178 color_inited = 1; |
|
1179 console_color_init(s->ds); |
|
1180 } |
|
1181 s->y_displayed = 0; |
|
1182 s->y_base = 0; |
|
1183 s->total_height = DEFAULT_BACKSCROLL; |
|
1184 s->x = 0; |
|
1185 s->y = 0; |
|
1186 width = ds_get_width(s->ds); |
|
1187 height = ds_get_height(s->ds); |
|
1188 if (p != 0) { |
|
1189 width = strtoul(p, (char **)&p, 10); |
|
1190 if (*p == 'C') { |
|
1191 p++; |
|
1192 width *= FONT_WIDTH; |
|
1193 } |
|
1194 if (*p == 'x') { |
|
1195 p++; |
|
1196 height = strtoul(p, (char **)&p, 10); |
|
1197 if (*p == 'C') { |
|
1198 p++; |
|
1199 height *= FONT_HEIGHT; |
|
1200 } |
|
1201 } |
|
1202 } |
|
1203 s->g_width = width; |
|
1204 s->g_height = height; |
|
1205 |
|
1206 #if 0 |
|
1207 s->hw_invalidate = text_console_invalidate; |
|
1208 #endif |
|
1209 gui_set_paint_callbacks(s->ds, NULL, text_console_invalidate, NULL, s); |
|
1210 s->hw_text_update = text_console_update; |
|
1211 s->hw = s; |
|
1212 |
|
1213 /* Set text attribute defaults */ |
|
1214 s->t_attrib_default.bold = 0; |
|
1215 s->t_attrib_default.uline = 0; |
|
1216 s->t_attrib_default.blink = 0; |
|
1217 s->t_attrib_default.invers = 0; |
|
1218 s->t_attrib_default.unvisible = 0; |
|
1219 s->t_attrib_default.fgcol = COLOR_WHITE; |
|
1220 s->t_attrib_default.bgcol = COLOR_BLACK; |
|
1221 |
|
1222 /* set current text attributes to default */ |
|
1223 s->t_attrib = s->t_attrib_default; |
|
1224 text_console_resize_int(s); |
|
1225 |
|
1226 qemu_chr_reset(chr); |
|
1227 |
|
1228 return chr; |
|
1229 } |
|
1230 |
|
1231 CharDriverState *new_text_console(const char *p) |
|
1232 { |
|
1233 DisplayState * const ds = gui_new_vt(SKINLESS_TEXT_VT_PRIORITY_ORDER); |
|
1234 |
|
1235 if (ds != NULL) |
|
1236 return text_console_init(ds, p); |
|
1237 else |
|
1238 return NULL; |
|
1239 } |
|
1240 |
|
1241 /* Just for unloaded GUIs. gui_resize can be used instead */ |
|
1242 void text_console_resize(TextConsole *console, int width, int height) |
|
1243 { |
|
1244 if (gui_resize_vt(console->ds, width, height)) { |
|
1245 console->g_width = width; |
|
1246 console->g_height = height; |
|
1247 } |
|
1248 } |
|
1249 |
|
1250 void text_console_copy(TextConsole *console, int src_x, int src_y, |
|
1251 int dst_x, int dst_y, int w, int h) |
|
1252 { |
|
1253 if (gui_is_display_active(console->ds)) { |
|
1254 if (console->ds->dpy_copy) |
|
1255 console->ds->dpy_copy(console->ds, |
|
1256 src_x, src_y, dst_x, dst_y, w, h); |
|
1257 else { |
|
1258 /* TODO */ |
|
1259 console->ds->dpy_update(console->ds, dst_x, dst_y, w, h); |
|
1260 } |
|
1261 } |
|
1262 } |
|
1263 |