Statistics
| Branch: | Revision:

root / console.c @ 3e11db9a

History | View | Annotate | Download (18.7 kB)

1 e7f0ad58 bellard
/*
2 e7f0ad58 bellard
 * QEMU graphical console
3 e7f0ad58 bellard
 * 
4 e7f0ad58 bellard
 * Copyright (c) 2004 Fabrice Bellard
5 e7f0ad58 bellard
 * 
6 e7f0ad58 bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 e7f0ad58 bellard
 * of this software and associated documentation files (the "Software"), to deal
8 e7f0ad58 bellard
 * in the Software without restriction, including without limitation the rights
9 e7f0ad58 bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 e7f0ad58 bellard
 * copies of the Software, and to permit persons to whom the Software is
11 e7f0ad58 bellard
 * furnished to do so, subject to the following conditions:
12 e7f0ad58 bellard
 *
13 e7f0ad58 bellard
 * The above copyright notice and this permission notice shall be included in
14 e7f0ad58 bellard
 * all copies or substantial portions of the Software.
15 e7f0ad58 bellard
 *
16 e7f0ad58 bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 e7f0ad58 bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 e7f0ad58 bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 e7f0ad58 bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 e7f0ad58 bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 e7f0ad58 bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 e7f0ad58 bellard
 * THE SOFTWARE.
23 e7f0ad58 bellard
 */
24 e7f0ad58 bellard
#include "vl.h"
25 e7f0ad58 bellard
26 e7f0ad58 bellard
#define DEFAULT_BACKSCROLL 512
27 e7f0ad58 bellard
#define MAX_CONSOLES 12
28 e7f0ad58 bellard
29 e7f0ad58 bellard
#define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
30 e7f0ad58 bellard
#define RGB(r, g, b) RGBA(r, g, b, 0xff)
31 e7f0ad58 bellard
32 e7f0ad58 bellard
typedef struct TextCell {
33 e7f0ad58 bellard
    uint8_t ch;
34 e7f0ad58 bellard
    uint8_t bgcol:4;
35 e7f0ad58 bellard
    uint8_t fgcol:4;
36 e7f0ad58 bellard
} TextCell;
37 e7f0ad58 bellard
38 e7f0ad58 bellard
#define MAX_ESC_PARAMS 3
39 e7f0ad58 bellard
40 e7f0ad58 bellard
enum TTYState {
41 e7f0ad58 bellard
    TTY_STATE_NORM,
42 e7f0ad58 bellard
    TTY_STATE_ESC,
43 e7f0ad58 bellard
    TTY_STATE_CSI,
44 e7f0ad58 bellard
};
45 e7f0ad58 bellard
46 e7f0ad58 bellard
struct TextConsole {
47 e7f0ad58 bellard
    int text_console; /* true if text console */
48 e7f0ad58 bellard
    DisplayState *ds;
49 e7f0ad58 bellard
    int g_width, g_height;
50 e7f0ad58 bellard
    int width;
51 e7f0ad58 bellard
    int height;
52 e7f0ad58 bellard
    int total_height;
53 e7f0ad58 bellard
    int backscroll_height;
54 e7f0ad58 bellard
    int fgcol;
55 e7f0ad58 bellard
    int bgcol;
56 e7f0ad58 bellard
    int x, y;
57 e7f0ad58 bellard
    int y_displayed;
58 e7f0ad58 bellard
    int y_base;
59 e7f0ad58 bellard
    TextCell *cells;
60 e7f0ad58 bellard
61 e7f0ad58 bellard
    enum TTYState state;
62 e7f0ad58 bellard
    int esc_params[MAX_ESC_PARAMS];
63 e7f0ad58 bellard
    int nb_esc_params;
64 e7f0ad58 bellard
65 e7f0ad58 bellard
    /* kbd read handler */
66 e7f0ad58 bellard
    IOReadHandler *fd_read;
67 e7f0ad58 bellard
    void *fd_opaque;
68 e7f0ad58 bellard
};
69 e7f0ad58 bellard
70 e7f0ad58 bellard
static TextConsole *active_console;
71 e7f0ad58 bellard
static TextConsole *consoles[MAX_CONSOLES];
72 e7f0ad58 bellard
static int nb_consoles = 0;
73 e7f0ad58 bellard
74 e7f0ad58 bellard
/* convert a RGBA color to a color index usable in graphic primitives */
75 e7f0ad58 bellard
static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
76 e7f0ad58 bellard
{
77 e7f0ad58 bellard
    unsigned int r, g, b, color;
78 e7f0ad58 bellard
79 e7f0ad58 bellard
    switch(ds->depth) {
80 e7f0ad58 bellard
#if 0
81 e7f0ad58 bellard
    case 8:
82 e7f0ad58 bellard
        r = (rgba >> 16) & 0xff;
83 e7f0ad58 bellard
        g = (rgba >> 8) & 0xff;
84 e7f0ad58 bellard
        b = (rgba) & 0xff;
85 e7f0ad58 bellard
        color = (rgb_to_index[r] * 6 * 6) + 
86 e7f0ad58 bellard
            (rgb_to_index[g] * 6) + 
87 e7f0ad58 bellard
            (rgb_to_index[b]);
88 e7f0ad58 bellard
        break;
89 e7f0ad58 bellard
#endif
90 e7f0ad58 bellard
    case 15:
91 e7f0ad58 bellard
        r = (rgba >> 16) & 0xff;
92 e7f0ad58 bellard
        g = (rgba >> 8) & 0xff;
93 e7f0ad58 bellard
        b = (rgba) & 0xff;
94 e7f0ad58 bellard
        color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
95 e7f0ad58 bellard
        break;
96 e7f0ad58 bellard
    case 16:
97 e7f0ad58 bellard
        r = (rgba >> 16) & 0xff;
98 e7f0ad58 bellard
        g = (rgba >> 8) & 0xff;
99 e7f0ad58 bellard
        b = (rgba) & 0xff;
100 e7f0ad58 bellard
        color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
101 e7f0ad58 bellard
        break;
102 e7f0ad58 bellard
    case 32:
103 e7f0ad58 bellard
    default:
104 e7f0ad58 bellard
        color = rgba;
105 e7f0ad58 bellard
        break;
106 e7f0ad58 bellard
    }
107 e7f0ad58 bellard
    return color;
108 e7f0ad58 bellard
}
109 e7f0ad58 bellard
110 e7f0ad58 bellard
static void vga_fill_rect (DisplayState *ds, 
111 e7f0ad58 bellard
                           int posx, int posy, int width, int height, uint32_t color)
112 e7f0ad58 bellard
{
113 e7f0ad58 bellard
    uint8_t *d, *d1;
114 e7f0ad58 bellard
    int x, y, bpp;
115 e7f0ad58 bellard
    
116 e7f0ad58 bellard
    bpp = (ds->depth + 7) >> 3;
117 e7f0ad58 bellard
    d1 = ds->data + 
118 e7f0ad58 bellard
        ds->linesize * posy + bpp * posx;
119 e7f0ad58 bellard
    for (y = 0; y < height; y++) {
120 e7f0ad58 bellard
        d = d1;
121 e7f0ad58 bellard
        switch(bpp) {
122 e7f0ad58 bellard
        case 1:
123 e7f0ad58 bellard
            for (x = 0; x < width; x++) {
124 e7f0ad58 bellard
                *((uint8_t *)d) = color;
125 e7f0ad58 bellard
                d++;
126 e7f0ad58 bellard
            }
127 e7f0ad58 bellard
            break;
128 e7f0ad58 bellard
        case 2:
129 e7f0ad58 bellard
            for (x = 0; x < width; x++) {
130 e7f0ad58 bellard
                *((uint16_t *)d) = color;
131 e7f0ad58 bellard
                d += 2;
132 e7f0ad58 bellard
            }
133 e7f0ad58 bellard
            break;
134 e7f0ad58 bellard
        case 4:
135 e7f0ad58 bellard
            for (x = 0; x < width; x++) {
136 e7f0ad58 bellard
                *((uint32_t *)d) = color;
137 e7f0ad58 bellard
                d += 4;
138 e7f0ad58 bellard
            }
139 e7f0ad58 bellard
            break;
140 e7f0ad58 bellard
        }
141 e7f0ad58 bellard
        d1 += ds->linesize;
142 e7f0ad58 bellard
    }
143 e7f0ad58 bellard
}
144 e7f0ad58 bellard
145 e7f0ad58 bellard
/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
146 e7f0ad58 bellard
static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
147 e7f0ad58 bellard
{
148 e7f0ad58 bellard
    const uint8_t *s;
149 e7f0ad58 bellard
    uint8_t *d;
150 e7f0ad58 bellard
    int wb, y, bpp;
151 e7f0ad58 bellard
152 e7f0ad58 bellard
    bpp = (ds->depth + 7) >> 3;
153 e7f0ad58 bellard
    wb = w * bpp;
154 e7f0ad58 bellard
    if (yd <= ys) {
155 e7f0ad58 bellard
        s = ds->data + 
156 e7f0ad58 bellard
            ds->linesize * ys + bpp * xs;
157 e7f0ad58 bellard
        d = ds->data + 
158 e7f0ad58 bellard
            ds->linesize * yd + bpp * xd;
159 e7f0ad58 bellard
        for (y = 0; y < h; y++) {
160 e7f0ad58 bellard
            memmove(d, s, wb);
161 e7f0ad58 bellard
            d += ds->linesize;
162 e7f0ad58 bellard
            s += ds->linesize;
163 e7f0ad58 bellard
        }
164 e7f0ad58 bellard
    } else {
165 e7f0ad58 bellard
        s = ds->data + 
166 e7f0ad58 bellard
            ds->linesize * (ys + h - 1) + bpp * xs;
167 e7f0ad58 bellard
        d = ds->data + 
168 e7f0ad58 bellard
            ds->linesize * (yd + h - 1) + bpp * xd;
169 e7f0ad58 bellard
       for (y = 0; y < h; y++) {
170 e7f0ad58 bellard
            memmove(d, s, wb);
171 e7f0ad58 bellard
            d -= ds->linesize;
172 e7f0ad58 bellard
            s -= ds->linesize;
173 e7f0ad58 bellard
        }
174 e7f0ad58 bellard
    }
175 e7f0ad58 bellard
}
176 e7f0ad58 bellard
177 e7f0ad58 bellard
/***********************************************************/
178 e7f0ad58 bellard
/* basic char display */
179 e7f0ad58 bellard
180 e7f0ad58 bellard
#define FONT_HEIGHT 16
181 e7f0ad58 bellard
#define FONT_WIDTH 8
182 e7f0ad58 bellard
183 e7f0ad58 bellard
#include "vgafont.h"
184 e7f0ad58 bellard
185 e7f0ad58 bellard
#define cbswap_32(__x) \
186 e7f0ad58 bellard
((uint32_t)( \
187 e7f0ad58 bellard
                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
188 e7f0ad58 bellard
                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
189 e7f0ad58 bellard
                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
190 e7f0ad58 bellard
                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
191 e7f0ad58 bellard
192 e7f0ad58 bellard
#ifdef WORDS_BIGENDIAN
193 e7f0ad58 bellard
#define PAT(x) x
194 e7f0ad58 bellard
#else
195 e7f0ad58 bellard
#define PAT(x) cbswap_32(x)
196 e7f0ad58 bellard
#endif
197 e7f0ad58 bellard
198 e7f0ad58 bellard
static const uint32_t dmask16[16] = {
199 e7f0ad58 bellard
    PAT(0x00000000),
200 e7f0ad58 bellard
    PAT(0x000000ff),
201 e7f0ad58 bellard
    PAT(0x0000ff00),
202 e7f0ad58 bellard
    PAT(0x0000ffff),
203 e7f0ad58 bellard
    PAT(0x00ff0000),
204 e7f0ad58 bellard
    PAT(0x00ff00ff),
205 e7f0ad58 bellard
    PAT(0x00ffff00),
206 e7f0ad58 bellard
    PAT(0x00ffffff),
207 e7f0ad58 bellard
    PAT(0xff000000),
208 e7f0ad58 bellard
    PAT(0xff0000ff),
209 e7f0ad58 bellard
    PAT(0xff00ff00),
210 e7f0ad58 bellard
    PAT(0xff00ffff),
211 e7f0ad58 bellard
    PAT(0xffff0000),
212 e7f0ad58 bellard
    PAT(0xffff00ff),
213 e7f0ad58 bellard
    PAT(0xffffff00),
214 e7f0ad58 bellard
    PAT(0xffffffff),
215 e7f0ad58 bellard
};
216 e7f0ad58 bellard
217 e7f0ad58 bellard
static const uint32_t dmask4[4] = {
218 e7f0ad58 bellard
    PAT(0x00000000),
219 e7f0ad58 bellard
    PAT(0x0000ffff),
220 e7f0ad58 bellard
    PAT(0xffff0000),
221 e7f0ad58 bellard
    PAT(0xffffffff),
222 e7f0ad58 bellard
};
223 e7f0ad58 bellard
224 e7f0ad58 bellard
static uint32_t color_table[8];
225 e7f0ad58 bellard
226 e7f0ad58 bellard
static const uint32_t color_table_rgb[8] = {
227 e7f0ad58 bellard
    RGB(0x00, 0x00, 0x00),
228 e7f0ad58 bellard
    RGB(0xff, 0x00, 0x00),
229 e7f0ad58 bellard
    RGB(0x00, 0xff, 0x00),
230 e7f0ad58 bellard
    RGB(0xff, 0xff, 0x00),
231 e7f0ad58 bellard
    RGB(0x00, 0x00, 0xff),
232 e7f0ad58 bellard
    RGB(0xff, 0x00, 0xff),
233 e7f0ad58 bellard
    RGB(0x00, 0xff, 0xff),
234 e7f0ad58 bellard
    RGB(0xff, 0xff, 0xff),
235 e7f0ad58 bellard
};
236 e7f0ad58 bellard
237 e7f0ad58 bellard
static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
238 e7f0ad58 bellard
{
239 e7f0ad58 bellard
    switch(ds->depth) {
240 e7f0ad58 bellard
    case 8:
241 e7f0ad58 bellard
        col |= col << 8;
242 e7f0ad58 bellard
        col |= col << 16;
243 e7f0ad58 bellard
        break;
244 e7f0ad58 bellard
    case 15:
245 e7f0ad58 bellard
    case 16:
246 e7f0ad58 bellard
        col |= col << 16;
247 e7f0ad58 bellard
        break;
248 e7f0ad58 bellard
    default:
249 e7f0ad58 bellard
        break;
250 e7f0ad58 bellard
    }
251 e7f0ad58 bellard
252 e7f0ad58 bellard
    return col;
253 e7f0ad58 bellard
}
254 e7f0ad58 bellard
255 e7f0ad58 bellard
static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, 
256 e7f0ad58 bellard
                          unsigned int fgcol, unsigned int bgcol)
257 e7f0ad58 bellard
{
258 e7f0ad58 bellard
    uint8_t *d;
259 e7f0ad58 bellard
    const uint8_t *font_ptr;
260 e7f0ad58 bellard
    unsigned int font_data, linesize, xorcol, bpp;
261 e7f0ad58 bellard
    int i;
262 e7f0ad58 bellard
263 e7f0ad58 bellard
    bpp = (ds->depth + 7) >> 3;
264 e7f0ad58 bellard
    d = ds->data + 
265 e7f0ad58 bellard
        ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
266 e7f0ad58 bellard
    linesize = ds->linesize;
267 e7f0ad58 bellard
    font_ptr = vgafont16 + FONT_HEIGHT * ch;
268 e7f0ad58 bellard
    xorcol = bgcol ^ fgcol;
269 e7f0ad58 bellard
    switch(ds->depth) {
270 e7f0ad58 bellard
    case 8:
271 e7f0ad58 bellard
        for(i = 0; i < FONT_HEIGHT; i++) {
272 e7f0ad58 bellard
            font_data = *font_ptr++;
273 e7f0ad58 bellard
            ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
274 e7f0ad58 bellard
            ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
275 e7f0ad58 bellard
            d += linesize;
276 e7f0ad58 bellard
        }
277 e7f0ad58 bellard
        break;
278 e7f0ad58 bellard
    case 16:
279 e7f0ad58 bellard
    case 15:
280 e7f0ad58 bellard
        for(i = 0; i < FONT_HEIGHT; i++) {
281 e7f0ad58 bellard
            font_data = *font_ptr++;
282 e7f0ad58 bellard
            ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
283 e7f0ad58 bellard
            ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
284 e7f0ad58 bellard
            ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
285 e7f0ad58 bellard
            ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
286 e7f0ad58 bellard
            d += linesize;
287 e7f0ad58 bellard
        }
288 e7f0ad58 bellard
        break;
289 e7f0ad58 bellard
    case 32:
290 e7f0ad58 bellard
        for(i = 0; i < FONT_HEIGHT; i++) {
291 e7f0ad58 bellard
            font_data = *font_ptr++;
292 e7f0ad58 bellard
            ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
293 e7f0ad58 bellard
            ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
294 e7f0ad58 bellard
            ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
295 e7f0ad58 bellard
            ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
296 e7f0ad58 bellard
            ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
297 e7f0ad58 bellard
            ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
298 e7f0ad58 bellard
            ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
299 e7f0ad58 bellard
            ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
300 e7f0ad58 bellard
            d += linesize;
301 e7f0ad58 bellard
        }
302 e7f0ad58 bellard
        break;
303 e7f0ad58 bellard
    }
304 e7f0ad58 bellard
}
305 e7f0ad58 bellard
306 e7f0ad58 bellard
static void text_console_resize(TextConsole *s)
307 e7f0ad58 bellard
{
308 e7f0ad58 bellard
    TextCell *cells, *c, *c1;
309 e7f0ad58 bellard
    int w1, x, y, last_width;
310 e7f0ad58 bellard
311 e7f0ad58 bellard
    last_width = s->width;
312 e7f0ad58 bellard
    s->width = s->g_width / FONT_WIDTH;
313 e7f0ad58 bellard
    s->height = s->g_height / FONT_HEIGHT;
314 e7f0ad58 bellard
315 e7f0ad58 bellard
    w1 = last_width;
316 e7f0ad58 bellard
    if (s->width < w1)
317 e7f0ad58 bellard
        w1 = s->width;
318 e7f0ad58 bellard
319 e7f0ad58 bellard
    cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
320 e7f0ad58 bellard
    for(y = 0; y < s->total_height; y++) {
321 e7f0ad58 bellard
        c = &cells[y * s->width];
322 e7f0ad58 bellard
        if (w1 > 0) {
323 e7f0ad58 bellard
            c1 = &s->cells[y * last_width];
324 e7f0ad58 bellard
            for(x = 0; x < w1; x++) {
325 e7f0ad58 bellard
                *c++ = *c1++;
326 e7f0ad58 bellard
            }
327 e7f0ad58 bellard
        }
328 e7f0ad58 bellard
        for(x = w1; x < s->width; x++) {
329 e7f0ad58 bellard
            c->ch = ' ';
330 e7f0ad58 bellard
            c->fgcol = 7;
331 e7f0ad58 bellard
            c->bgcol = 0;
332 e7f0ad58 bellard
            c++;
333 e7f0ad58 bellard
        }
334 e7f0ad58 bellard
    }
335 e7f0ad58 bellard
    free(s->cells);
336 e7f0ad58 bellard
    s->cells = cells;
337 e7f0ad58 bellard
}
338 e7f0ad58 bellard
339 e7f0ad58 bellard
static void update_xy(TextConsole *s, int x, int y)
340 e7f0ad58 bellard
{
341 e7f0ad58 bellard
    TextCell *c;
342 e7f0ad58 bellard
    int y1, y2;
343 e7f0ad58 bellard
344 e7f0ad58 bellard
    if (s == active_console) {
345 e7f0ad58 bellard
        y1 = (s->y_base + y) % s->total_height;
346 e7f0ad58 bellard
        y2 = y1 - s->y_displayed;
347 e7f0ad58 bellard
        if (y2 < 0)
348 e7f0ad58 bellard
            y2 += s->total_height;
349 e7f0ad58 bellard
        if (y2 < s->height) {
350 e7f0ad58 bellard
            c = &s->cells[y1 * s->width + x];
351 e7f0ad58 bellard
            vga_putcharxy(s->ds, x, y2, c->ch, 
352 e7f0ad58 bellard
                          color_table[c->fgcol], color_table[c->bgcol]);
353 e7f0ad58 bellard
            dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT, 
354 e7f0ad58 bellard
                       FONT_WIDTH, FONT_HEIGHT);
355 e7f0ad58 bellard
        }
356 e7f0ad58 bellard
    }
357 e7f0ad58 bellard
}
358 e7f0ad58 bellard
359 e7f0ad58 bellard
static void console_show_cursor(TextConsole *s, int show)
360 e7f0ad58 bellard
{
361 e7f0ad58 bellard
    TextCell *c;
362 e7f0ad58 bellard
    int y, y1;
363 e7f0ad58 bellard
364 e7f0ad58 bellard
    if (s == active_console) {
365 e7f0ad58 bellard
        y1 = (s->y_base + s->y) % s->total_height;
366 e7f0ad58 bellard
        y = y1 - s->y_displayed;
367 e7f0ad58 bellard
        if (y < 0)
368 e7f0ad58 bellard
            y += s->total_height;
369 e7f0ad58 bellard
        if (y < s->height) {
370 e7f0ad58 bellard
            c = &s->cells[y1 * s->width + s->x];
371 e7f0ad58 bellard
            if (show) {
372 e7f0ad58 bellard
                vga_putcharxy(s->ds, s->x, y, c->ch, 
373 e7f0ad58 bellard
                              color_table[0], color_table[7]);
374 e7f0ad58 bellard
            } else {
375 e7f0ad58 bellard
                vga_putcharxy(s->ds, s->x, y, c->ch, 
376 e7f0ad58 bellard
                              color_table[c->fgcol], color_table[c->bgcol]);
377 e7f0ad58 bellard
            }
378 e7f0ad58 bellard
            dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT, 
379 e7f0ad58 bellard
                       FONT_WIDTH, FONT_HEIGHT);
380 e7f0ad58 bellard
        }
381 e7f0ad58 bellard
    }
382 e7f0ad58 bellard
}
383 e7f0ad58 bellard
384 e7f0ad58 bellard
static void console_refresh(TextConsole *s)
385 e7f0ad58 bellard
{
386 e7f0ad58 bellard
    TextCell *c;
387 e7f0ad58 bellard
    int x, y, y1;
388 e7f0ad58 bellard
389 e7f0ad58 bellard
    if (s != active_console) 
390 e7f0ad58 bellard
        return;
391 e7f0ad58 bellard
392 e7f0ad58 bellard
    vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
393 e7f0ad58 bellard
                  color_table[0]);
394 e7f0ad58 bellard
    y1 = s->y_displayed;
395 e7f0ad58 bellard
    for(y = 0; y < s->height; y++) {
396 e7f0ad58 bellard
        c = s->cells + y1 * s->width;
397 e7f0ad58 bellard
        for(x = 0; x < s->width; x++) {
398 e7f0ad58 bellard
            vga_putcharxy(s->ds, x, y, c->ch, 
399 e7f0ad58 bellard
                          color_table[c->fgcol], color_table[c->bgcol]);
400 e7f0ad58 bellard
            c++;
401 e7f0ad58 bellard
        }
402 e7f0ad58 bellard
        if (++y1 == s->total_height)
403 e7f0ad58 bellard
            y1 = 0;
404 e7f0ad58 bellard
    }
405 e7f0ad58 bellard
    dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
406 e7f0ad58 bellard
    console_show_cursor(s, 1);
407 e7f0ad58 bellard
}
408 e7f0ad58 bellard
409 e7f0ad58 bellard
static void console_scroll(int ydelta)
410 e7f0ad58 bellard
{
411 e7f0ad58 bellard
    TextConsole *s;
412 e7f0ad58 bellard
    int i, y1;
413 e7f0ad58 bellard
    
414 e7f0ad58 bellard
    s = active_console;
415 e7f0ad58 bellard
    if (!s || !s->text_console)
416 e7f0ad58 bellard
        return;
417 e7f0ad58 bellard
418 e7f0ad58 bellard
    if (ydelta > 0) {
419 e7f0ad58 bellard
        for(i = 0; i < ydelta; i++) {
420 e7f0ad58 bellard
            if (s->y_displayed == s->y_base)
421 e7f0ad58 bellard
                break;
422 e7f0ad58 bellard
            if (++s->y_displayed == s->total_height)
423 e7f0ad58 bellard
                s->y_displayed = 0;
424 e7f0ad58 bellard
        }
425 e7f0ad58 bellard
    } else {
426 e7f0ad58 bellard
        ydelta = -ydelta;
427 e7f0ad58 bellard
        i = s->backscroll_height;
428 e7f0ad58 bellard
        if (i > s->total_height - s->height)
429 e7f0ad58 bellard
            i = s->total_height - s->height;
430 e7f0ad58 bellard
        y1 = s->y_base - i;
431 e7f0ad58 bellard
        if (y1 < 0)
432 e7f0ad58 bellard
            y1 += s->total_height;
433 e7f0ad58 bellard
        for(i = 0; i < ydelta; i++) {
434 e7f0ad58 bellard
            if (s->y_displayed == y1)
435 e7f0ad58 bellard
                break;
436 e7f0ad58 bellard
            if (--s->y_displayed < 0)
437 e7f0ad58 bellard
                s->y_displayed = s->total_height - 1;
438 e7f0ad58 bellard
        }
439 e7f0ad58 bellard
    }
440 e7f0ad58 bellard
    console_refresh(s);
441 e7f0ad58 bellard
}
442 e7f0ad58 bellard
443 e7f0ad58 bellard
static void console_put_lf(TextConsole *s)
444 e7f0ad58 bellard
{
445 e7f0ad58 bellard
    TextCell *c;
446 e7f0ad58 bellard
    int x, y1;
447 e7f0ad58 bellard
448 e7f0ad58 bellard
    s->x = 0;
449 e7f0ad58 bellard
    s->y++;
450 e7f0ad58 bellard
    if (s->y >= s->height) {
451 e7f0ad58 bellard
        s->y = s->height - 1;
452 e7f0ad58 bellard
        
453 e7f0ad58 bellard
        if (s->y_displayed == s->y_base) {
454 e7f0ad58 bellard
            if (++s->y_displayed == s->total_height)
455 e7f0ad58 bellard
                s->y_displayed = 0;
456 e7f0ad58 bellard
        }
457 e7f0ad58 bellard
        if (++s->y_base == s->total_height)
458 e7f0ad58 bellard
            s->y_base = 0;
459 e7f0ad58 bellard
        if (s->backscroll_height < s->total_height)
460 e7f0ad58 bellard
            s->backscroll_height++;
461 e7f0ad58 bellard
        y1 = (s->y_base + s->height - 1) % s->total_height;
462 e7f0ad58 bellard
        c = &s->cells[y1 * s->width];
463 e7f0ad58 bellard
        for(x = 0; x < s->width; x++) {
464 e7f0ad58 bellard
            c->ch = ' ';
465 e7f0ad58 bellard
            c->fgcol = s->fgcol;
466 e7f0ad58 bellard
            c->bgcol = s->bgcol;
467 e7f0ad58 bellard
            c++;
468 e7f0ad58 bellard
        }
469 e7f0ad58 bellard
        if (s == active_console && s->y_displayed == s->y_base) {
470 e7f0ad58 bellard
            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, 
471 e7f0ad58 bellard
                       s->width * FONT_WIDTH, 
472 e7f0ad58 bellard
                       (s->height - 1) * FONT_HEIGHT);
473 e7f0ad58 bellard
            vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
474 e7f0ad58 bellard
                          s->width * FONT_WIDTH, FONT_HEIGHT, 
475 e7f0ad58 bellard
                          color_table[s->bgcol]);
476 e7f0ad58 bellard
            dpy_update(s->ds, 0, 0, 
477 e7f0ad58 bellard
                       s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
478 e7f0ad58 bellard
        }
479 e7f0ad58 bellard
    }
480 e7f0ad58 bellard
}
481 e7f0ad58 bellard
482 e7f0ad58 bellard
static void console_putchar(TextConsole *s, int ch)
483 e7f0ad58 bellard
{
484 e7f0ad58 bellard
    TextCell *c;
485 e7f0ad58 bellard
    int y1, i, x;
486 e7f0ad58 bellard
487 e7f0ad58 bellard
    switch(s->state) {
488 e7f0ad58 bellard
    case TTY_STATE_NORM:
489 e7f0ad58 bellard
        switch(ch) {
490 e7f0ad58 bellard
        case '\r':
491 e7f0ad58 bellard
            s->x = 0;
492 e7f0ad58 bellard
            break;
493 e7f0ad58 bellard
        case '\n':
494 e7f0ad58 bellard
            console_put_lf(s);
495 e7f0ad58 bellard
            break;
496 e7f0ad58 bellard
        case 27:
497 e7f0ad58 bellard
            s->state = TTY_STATE_ESC;
498 e7f0ad58 bellard
            break;
499 e7f0ad58 bellard
        default:
500 e7f0ad58 bellard
            y1 = (s->y_base + s->y) % s->total_height;
501 e7f0ad58 bellard
            c = &s->cells[y1 * s->width + s->x];
502 e7f0ad58 bellard
            c->ch = ch;
503 e7f0ad58 bellard
            c->fgcol = s->fgcol;
504 e7f0ad58 bellard
            c->bgcol = s->bgcol;
505 e7f0ad58 bellard
            update_xy(s, s->x, s->y);
506 e7f0ad58 bellard
            s->x++;
507 e7f0ad58 bellard
            if (s->x >= s->width)
508 e7f0ad58 bellard
                console_put_lf(s);
509 e7f0ad58 bellard
            break;
510 e7f0ad58 bellard
        }
511 e7f0ad58 bellard
        break;
512 e7f0ad58 bellard
    case TTY_STATE_ESC:
513 e7f0ad58 bellard
        if (ch == '[') {
514 e7f0ad58 bellard
            for(i=0;i<MAX_ESC_PARAMS;i++)
515 e7f0ad58 bellard
                s->esc_params[i] = 0;
516 e7f0ad58 bellard
            s->nb_esc_params = 0;
517 e7f0ad58 bellard
            s->state = TTY_STATE_CSI;
518 e7f0ad58 bellard
        } else {
519 e7f0ad58 bellard
            s->state = TTY_STATE_NORM;
520 e7f0ad58 bellard
        }
521 e7f0ad58 bellard
        break;
522 e7f0ad58 bellard
    case TTY_STATE_CSI:
523 e7f0ad58 bellard
        if (ch >= '0' && ch <= '9') {
524 e7f0ad58 bellard
            if (s->nb_esc_params < MAX_ESC_PARAMS) {
525 e7f0ad58 bellard
                s->esc_params[s->nb_esc_params] = 
526 e7f0ad58 bellard
                    s->esc_params[s->nb_esc_params] * 10 + ch - '0';
527 e7f0ad58 bellard
            }
528 e7f0ad58 bellard
        } else {
529 e7f0ad58 bellard
            s->nb_esc_params++;
530 e7f0ad58 bellard
            if (ch == ';')
531 e7f0ad58 bellard
                break;
532 e7f0ad58 bellard
            s->state = TTY_STATE_NORM;
533 e7f0ad58 bellard
            switch(ch) {
534 e7f0ad58 bellard
            case 'D':
535 e7f0ad58 bellard
                if (s->x > 0)
536 e7f0ad58 bellard
                    s->x--;
537 e7f0ad58 bellard
                break;
538 e7f0ad58 bellard
            case 'C':
539 e7f0ad58 bellard
                if (s->x < (s->width - 1))
540 e7f0ad58 bellard
                    s->x++;
541 e7f0ad58 bellard
                break;
542 e7f0ad58 bellard
            case 'K':
543 e7f0ad58 bellard
                /* clear to eol */
544 e7f0ad58 bellard
                y1 = (s->y_base + s->y) % s->total_height;
545 e7f0ad58 bellard
                for(x = s->x; x < s->width; x++) {
546 e7f0ad58 bellard
                    c = &s->cells[y1 * s->width + x];
547 e7f0ad58 bellard
                    c->ch = ' ';
548 e7f0ad58 bellard
                    c->fgcol = s->fgcol;
549 e7f0ad58 bellard
                    c->bgcol = s->bgcol;
550 e7f0ad58 bellard
                    c++;
551 e7f0ad58 bellard
                    update_xy(s, x, s->y);
552 e7f0ad58 bellard
                }
553 e7f0ad58 bellard
                break;
554 e7f0ad58 bellard
            default:
555 e7f0ad58 bellard
                break;
556 e7f0ad58 bellard
            }
557 e7f0ad58 bellard
            break;
558 e7f0ad58 bellard
        }
559 e7f0ad58 bellard
    }
560 e7f0ad58 bellard
}
561 e7f0ad58 bellard
562 e7f0ad58 bellard
void console_select(unsigned int index)
563 e7f0ad58 bellard
{
564 e7f0ad58 bellard
    TextConsole *s;
565 e7f0ad58 bellard
    
566 e7f0ad58 bellard
    if (index >= MAX_CONSOLES)
567 e7f0ad58 bellard
        return;
568 e7f0ad58 bellard
    s = consoles[index];
569 e7f0ad58 bellard
    if (s) {
570 e7f0ad58 bellard
        active_console = s;
571 e7f0ad58 bellard
        if (s->text_console) {
572 e7f0ad58 bellard
            if (s->g_width != s->ds->width ||
573 e7f0ad58 bellard
                s->g_height != s->ds->height)
574 e7f0ad58 bellard
                text_console_resize(s);
575 e7f0ad58 bellard
            console_refresh(s);
576 e7f0ad58 bellard
        }
577 e7f0ad58 bellard
    }
578 e7f0ad58 bellard
}
579 e7f0ad58 bellard
580 e7f0ad58 bellard
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
581 e7f0ad58 bellard
{
582 e7f0ad58 bellard
    TextConsole *s = chr->opaque;
583 e7f0ad58 bellard
    int i;
584 e7f0ad58 bellard
585 e7f0ad58 bellard
    console_show_cursor(s, 0);
586 e7f0ad58 bellard
    for(i = 0; i < len; i++) {
587 e7f0ad58 bellard
        console_putchar(s, buf[i]);
588 e7f0ad58 bellard
    }
589 e7f0ad58 bellard
    console_show_cursor(s, 1);
590 e7f0ad58 bellard
    return len;
591 e7f0ad58 bellard
}
592 e7f0ad58 bellard
593 e7f0ad58 bellard
static void console_chr_add_read_handler(CharDriverState *chr, 
594 e7f0ad58 bellard
                                         IOCanRWHandler *fd_can_read, 
595 e7f0ad58 bellard
                                         IOReadHandler *fd_read, void *opaque)
596 e7f0ad58 bellard
{
597 e7f0ad58 bellard
    TextConsole *s = chr->opaque;
598 e7f0ad58 bellard
    s->fd_read = fd_read;
599 e7f0ad58 bellard
    s->fd_opaque = opaque;
600 e7f0ad58 bellard
}
601 e7f0ad58 bellard
602 e7f0ad58 bellard
/* called when an ascii key is pressed */
603 e7f0ad58 bellard
void kbd_put_keysym(int keysym)
604 e7f0ad58 bellard
{
605 e7f0ad58 bellard
    TextConsole *s;
606 e7f0ad58 bellard
    uint8_t buf[16], *q;
607 e7f0ad58 bellard
    int c;
608 e7f0ad58 bellard
609 e7f0ad58 bellard
    s = active_console;
610 e7f0ad58 bellard
    if (!s || !s->text_console)
611 e7f0ad58 bellard
        return;
612 e7f0ad58 bellard
613 e7f0ad58 bellard
    switch(keysym) {
614 e7f0ad58 bellard
    case QEMU_KEY_CTRL_UP:
615 e7f0ad58 bellard
        console_scroll(-1);
616 e7f0ad58 bellard
        break;
617 e7f0ad58 bellard
    case QEMU_KEY_CTRL_DOWN:
618 e7f0ad58 bellard
        console_scroll(1);
619 e7f0ad58 bellard
        break;
620 e7f0ad58 bellard
    case QEMU_KEY_CTRL_PAGEUP:
621 e7f0ad58 bellard
        console_scroll(-10);
622 e7f0ad58 bellard
        break;
623 e7f0ad58 bellard
    case QEMU_KEY_CTRL_PAGEDOWN:
624 e7f0ad58 bellard
        console_scroll(10);
625 e7f0ad58 bellard
        break;
626 e7f0ad58 bellard
    default:
627 e7f0ad58 bellard
        if (s->fd_read) {
628 e7f0ad58 bellard
            /* convert the QEMU keysym to VT100 key string */
629 e7f0ad58 bellard
            q = buf;
630 e7f0ad58 bellard
            if (keysym >= 0xe100 && keysym <= 0xe11f) {
631 e7f0ad58 bellard
                *q++ = '\033';
632 e7f0ad58 bellard
                *q++ = '[';
633 e7f0ad58 bellard
                c = keysym - 0xe100;
634 e7f0ad58 bellard
                if (c >= 10)
635 e7f0ad58 bellard
                    *q++ = '0' + (c / 10);
636 e7f0ad58 bellard
                *q++ = '0' + (c % 10);
637 e7f0ad58 bellard
                *q++ = '~';
638 e7f0ad58 bellard
            } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
639 e7f0ad58 bellard
                *q++ = '\033';
640 e7f0ad58 bellard
                *q++ = '[';
641 e7f0ad58 bellard
                *q++ = keysym & 0xff;
642 e7f0ad58 bellard
            } else {
643 e7f0ad58 bellard
                *q++ = keysym;
644 e7f0ad58 bellard
            }
645 e7f0ad58 bellard
            s->fd_read(s->fd_opaque, buf, q - buf);
646 e7f0ad58 bellard
        }
647 e7f0ad58 bellard
        break;
648 e7f0ad58 bellard
    }
649 e7f0ad58 bellard
}
650 e7f0ad58 bellard
651 e7f0ad58 bellard
TextConsole *graphic_console_init(DisplayState *ds)
652 e7f0ad58 bellard
{
653 e7f0ad58 bellard
    TextConsole *s;
654 e7f0ad58 bellard
655 e7f0ad58 bellard
    if (nb_consoles >= MAX_CONSOLES)
656 e7f0ad58 bellard
        return NULL;
657 e7f0ad58 bellard
    s = qemu_mallocz(sizeof(TextConsole));
658 e7f0ad58 bellard
    if (!s) {
659 e7f0ad58 bellard
        return NULL;
660 e7f0ad58 bellard
    }
661 e7f0ad58 bellard
    if (!active_console)
662 e7f0ad58 bellard
        active_console = s;
663 e7f0ad58 bellard
    s->ds = ds;
664 e7f0ad58 bellard
    consoles[nb_consoles++] = s;
665 e7f0ad58 bellard
    return s;
666 e7f0ad58 bellard
}
667 e7f0ad58 bellard
668 e7f0ad58 bellard
int is_active_console(TextConsole *s)
669 e7f0ad58 bellard
{
670 e7f0ad58 bellard
    return s == active_console;
671 e7f0ad58 bellard
}
672 e7f0ad58 bellard
673 e7f0ad58 bellard
CharDriverState *text_console_init(DisplayState *ds)
674 e7f0ad58 bellard
{
675 e7f0ad58 bellard
    CharDriverState *chr;
676 e7f0ad58 bellard
    TextConsole *s;
677 e7f0ad58 bellard
    int i;
678 e7f0ad58 bellard
    static int color_inited;
679 e7f0ad58 bellard
    
680 e7f0ad58 bellard
    chr = qemu_mallocz(sizeof(CharDriverState));
681 e7f0ad58 bellard
    if (!chr)
682 e7f0ad58 bellard
        return NULL;
683 e7f0ad58 bellard
    s = graphic_console_init(ds);
684 e7f0ad58 bellard
    if (!s) {
685 e7f0ad58 bellard
        free(chr);
686 e7f0ad58 bellard
        return NULL;
687 e7f0ad58 bellard
    }
688 e7f0ad58 bellard
    s->text_console = 1;
689 e7f0ad58 bellard
    chr->opaque = s;
690 e7f0ad58 bellard
    chr->chr_write = console_puts;
691 e7f0ad58 bellard
    chr->chr_add_read_handler = console_chr_add_read_handler;
692 e7f0ad58 bellard
    if (!color_inited) {
693 e7f0ad58 bellard
        color_inited = 1;
694 e7f0ad58 bellard
        for(i = 0; i < 8; i++) {
695 e7f0ad58 bellard
            color_table[i] = col_expand(s->ds, 
696 e7f0ad58 bellard
                                        vga_get_color(s->ds, color_table_rgb[i]));
697 e7f0ad58 bellard
        }
698 e7f0ad58 bellard
    }
699 e7f0ad58 bellard
    s->y_displayed = 0;
700 e7f0ad58 bellard
    s->y_base = 0;
701 e7f0ad58 bellard
    s->total_height = DEFAULT_BACKSCROLL;
702 e7f0ad58 bellard
    s->x = 0;
703 e7f0ad58 bellard
    s->y = 0;
704 e7f0ad58 bellard
    s->fgcol = 7;
705 e7f0ad58 bellard
    s->bgcol = 0;
706 e7f0ad58 bellard
    s->g_width = s->ds->width;
707 e7f0ad58 bellard
    s->g_height = s->ds->height;
708 e7f0ad58 bellard
    text_console_resize(s);
709 e7f0ad58 bellard
710 e7f0ad58 bellard
    return chr;
711 e7f0ad58 bellard
}