Statistics
| Branch: | Revision:

root / console.c @ 14ce26e7

History | View | Annotate | Download (19.1 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 8e3a9fd2 bellard
                s->g_height != s->ds->height) {
574 8e3a9fd2 bellard
                s->g_width = s->ds->width;
575 8e3a9fd2 bellard
                s->g_height = s->ds->height;
576 e7f0ad58 bellard
                text_console_resize(s);
577 8e3a9fd2 bellard
            }
578 e7f0ad58 bellard
            console_refresh(s);
579 e7f0ad58 bellard
        }
580 e7f0ad58 bellard
    }
581 e7f0ad58 bellard
}
582 e7f0ad58 bellard
583 e7f0ad58 bellard
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
584 e7f0ad58 bellard
{
585 e7f0ad58 bellard
    TextConsole *s = chr->opaque;
586 e7f0ad58 bellard
    int i;
587 e7f0ad58 bellard
588 e7f0ad58 bellard
    console_show_cursor(s, 0);
589 e7f0ad58 bellard
    for(i = 0; i < len; i++) {
590 e7f0ad58 bellard
        console_putchar(s, buf[i]);
591 e7f0ad58 bellard
    }
592 e7f0ad58 bellard
    console_show_cursor(s, 1);
593 e7f0ad58 bellard
    return len;
594 e7f0ad58 bellard
}
595 e7f0ad58 bellard
596 e7f0ad58 bellard
static void console_chr_add_read_handler(CharDriverState *chr, 
597 e7f0ad58 bellard
                                         IOCanRWHandler *fd_can_read, 
598 e7f0ad58 bellard
                                         IOReadHandler *fd_read, void *opaque)
599 e7f0ad58 bellard
{
600 e7f0ad58 bellard
    TextConsole *s = chr->opaque;
601 e7f0ad58 bellard
    s->fd_read = fd_read;
602 e7f0ad58 bellard
    s->fd_opaque = opaque;
603 e7f0ad58 bellard
}
604 e7f0ad58 bellard
605 6fcfafb7 bellard
static void console_send_event(CharDriverState *chr, int event)
606 6fcfafb7 bellard
{
607 6fcfafb7 bellard
    TextConsole *s = chr->opaque;
608 6fcfafb7 bellard
    int i;
609 6fcfafb7 bellard
610 6fcfafb7 bellard
    if (event == CHR_EVENT_FOCUS) {
611 6fcfafb7 bellard
        for(i = 0; i < nb_consoles; i++) {
612 6fcfafb7 bellard
            if (consoles[i] == s) {
613 6fcfafb7 bellard
                console_select(i);
614 6fcfafb7 bellard
                break;
615 6fcfafb7 bellard
            }
616 6fcfafb7 bellard
        }
617 6fcfafb7 bellard
    }
618 6fcfafb7 bellard
}
619 6fcfafb7 bellard
620 e7f0ad58 bellard
/* called when an ascii key is pressed */
621 e7f0ad58 bellard
void kbd_put_keysym(int keysym)
622 e7f0ad58 bellard
{
623 e7f0ad58 bellard
    TextConsole *s;
624 e7f0ad58 bellard
    uint8_t buf[16], *q;
625 e7f0ad58 bellard
    int c;
626 e7f0ad58 bellard
627 e7f0ad58 bellard
    s = active_console;
628 e7f0ad58 bellard
    if (!s || !s->text_console)
629 e7f0ad58 bellard
        return;
630 e7f0ad58 bellard
631 e7f0ad58 bellard
    switch(keysym) {
632 e7f0ad58 bellard
    case QEMU_KEY_CTRL_UP:
633 e7f0ad58 bellard
        console_scroll(-1);
634 e7f0ad58 bellard
        break;
635 e7f0ad58 bellard
    case QEMU_KEY_CTRL_DOWN:
636 e7f0ad58 bellard
        console_scroll(1);
637 e7f0ad58 bellard
        break;
638 e7f0ad58 bellard
    case QEMU_KEY_CTRL_PAGEUP:
639 e7f0ad58 bellard
        console_scroll(-10);
640 e7f0ad58 bellard
        break;
641 e7f0ad58 bellard
    case QEMU_KEY_CTRL_PAGEDOWN:
642 e7f0ad58 bellard
        console_scroll(10);
643 e7f0ad58 bellard
        break;
644 e7f0ad58 bellard
    default:
645 e7f0ad58 bellard
        if (s->fd_read) {
646 e7f0ad58 bellard
            /* convert the QEMU keysym to VT100 key string */
647 e7f0ad58 bellard
            q = buf;
648 e7f0ad58 bellard
            if (keysym >= 0xe100 && keysym <= 0xe11f) {
649 e7f0ad58 bellard
                *q++ = '\033';
650 e7f0ad58 bellard
                *q++ = '[';
651 e7f0ad58 bellard
                c = keysym - 0xe100;
652 e7f0ad58 bellard
                if (c >= 10)
653 e7f0ad58 bellard
                    *q++ = '0' + (c / 10);
654 e7f0ad58 bellard
                *q++ = '0' + (c % 10);
655 e7f0ad58 bellard
                *q++ = '~';
656 e7f0ad58 bellard
            } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
657 e7f0ad58 bellard
                *q++ = '\033';
658 e7f0ad58 bellard
                *q++ = '[';
659 e7f0ad58 bellard
                *q++ = keysym & 0xff;
660 e7f0ad58 bellard
            } else {
661 e7f0ad58 bellard
                *q++ = keysym;
662 e7f0ad58 bellard
            }
663 e7f0ad58 bellard
            s->fd_read(s->fd_opaque, buf, q - buf);
664 e7f0ad58 bellard
        }
665 e7f0ad58 bellard
        break;
666 e7f0ad58 bellard
    }
667 e7f0ad58 bellard
}
668 e7f0ad58 bellard
669 e7f0ad58 bellard
TextConsole *graphic_console_init(DisplayState *ds)
670 e7f0ad58 bellard
{
671 e7f0ad58 bellard
    TextConsole *s;
672 e7f0ad58 bellard
673 e7f0ad58 bellard
    if (nb_consoles >= MAX_CONSOLES)
674 e7f0ad58 bellard
        return NULL;
675 e7f0ad58 bellard
    s = qemu_mallocz(sizeof(TextConsole));
676 e7f0ad58 bellard
    if (!s) {
677 e7f0ad58 bellard
        return NULL;
678 e7f0ad58 bellard
    }
679 e7f0ad58 bellard
    if (!active_console)
680 e7f0ad58 bellard
        active_console = s;
681 e7f0ad58 bellard
    s->ds = ds;
682 e7f0ad58 bellard
    consoles[nb_consoles++] = s;
683 e7f0ad58 bellard
    return s;
684 e7f0ad58 bellard
}
685 e7f0ad58 bellard
686 e7f0ad58 bellard
int is_active_console(TextConsole *s)
687 e7f0ad58 bellard
{
688 e7f0ad58 bellard
    return s == active_console;
689 e7f0ad58 bellard
}
690 e7f0ad58 bellard
691 e7f0ad58 bellard
CharDriverState *text_console_init(DisplayState *ds)
692 e7f0ad58 bellard
{
693 e7f0ad58 bellard
    CharDriverState *chr;
694 e7f0ad58 bellard
    TextConsole *s;
695 e7f0ad58 bellard
    int i;
696 e7f0ad58 bellard
    static int color_inited;
697 e7f0ad58 bellard
    
698 e7f0ad58 bellard
    chr = qemu_mallocz(sizeof(CharDriverState));
699 e7f0ad58 bellard
    if (!chr)
700 e7f0ad58 bellard
        return NULL;
701 e7f0ad58 bellard
    s = graphic_console_init(ds);
702 e7f0ad58 bellard
    if (!s) {
703 e7f0ad58 bellard
        free(chr);
704 e7f0ad58 bellard
        return NULL;
705 e7f0ad58 bellard
    }
706 e7f0ad58 bellard
    s->text_console = 1;
707 e7f0ad58 bellard
    chr->opaque = s;
708 e7f0ad58 bellard
    chr->chr_write = console_puts;
709 e7f0ad58 bellard
    chr->chr_add_read_handler = console_chr_add_read_handler;
710 6fcfafb7 bellard
    chr->chr_send_event = console_send_event;
711 6fcfafb7 bellard
712 e7f0ad58 bellard
    if (!color_inited) {
713 e7f0ad58 bellard
        color_inited = 1;
714 e7f0ad58 bellard
        for(i = 0; i < 8; i++) {
715 e7f0ad58 bellard
            color_table[i] = col_expand(s->ds, 
716 e7f0ad58 bellard
                                        vga_get_color(s->ds, color_table_rgb[i]));
717 e7f0ad58 bellard
        }
718 e7f0ad58 bellard
    }
719 e7f0ad58 bellard
    s->y_displayed = 0;
720 e7f0ad58 bellard
    s->y_base = 0;
721 e7f0ad58 bellard
    s->total_height = DEFAULT_BACKSCROLL;
722 e7f0ad58 bellard
    s->x = 0;
723 e7f0ad58 bellard
    s->y = 0;
724 e7f0ad58 bellard
    s->fgcol = 7;
725 e7f0ad58 bellard
    s->bgcol = 0;
726 e7f0ad58 bellard
    s->g_width = s->ds->width;
727 e7f0ad58 bellard
    s->g_height = s->ds->height;
728 e7f0ad58 bellard
    text_console_resize(s);
729 e7f0ad58 bellard
730 e7f0ad58 bellard
    return chr;
731 e7f0ad58 bellard
}