Statistics
| Branch: | Revision:

root / console.c @ 7b5d76da

History | View | Annotate | Download (44.5 kB)

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

    
28
//#define DEBUG_CONSOLE
29
#define DEFAULT_BACKSCROLL 512
30
#define MAX_CONSOLES 12
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
typedef enum {
111
    GRAPHIC_CONSOLE,
112
    TEXT_CONSOLE,
113
    TEXT_CONSOLE_FIXED_SIZE
114
} console_type_t;
115

    
116
/* ??? This is mis-named.
117
   It is used for both text and graphical consoles.  */
118
struct TextConsole {
119
    console_type_t console_type;
120
    DisplayState *ds;
121
    /* Graphic console state.  */
122
    vga_hw_update_ptr hw_update;
123
    vga_hw_invalidate_ptr hw_invalidate;
124
    vga_hw_screen_dump_ptr hw_screen_dump;
125
    vga_hw_text_update_ptr hw_text_update;
126
    void *hw;
127

    
128
    int g_width, g_height;
129
    int width;
130
    int height;
131
    int total_height;
132
    int backscroll_height;
133
    int x, y;
134
    int x_saved, y_saved;
135
    int y_displayed;
136
    int y_base;
137
    TextAttributes t_attrib_default; /* default text attributes */
138
    TextAttributes t_attrib; /* currently active text attributes */
139
    TextCell *cells;
140
    int text_x[2], text_y[2], cursor_invalidate;
141

    
142
    int update_x0;
143
    int update_y0;
144
    int update_x1;
145
    int update_y1;
146

    
147
    enum TTYState state;
148
    int esc_params[MAX_ESC_PARAMS];
149
    int nb_esc_params;
150

    
151
    CharDriverState *chr;
152
    /* fifo for key pressed */
153
    QEMUFIFO out_fifo;
154
    uint8_t out_fifo_buf[16];
155
    QEMUTimer *kbd_timer;
156
};
157

    
158
static TextConsole *active_console;
159
static TextConsole *consoles[MAX_CONSOLES];
160
static int nb_consoles = 0;
161

    
162
void vga_hw_update(void)
163
{
164
    if (active_console && active_console->hw_update)
165
        active_console->hw_update(active_console->hw);
166
}
167

    
168
void vga_hw_invalidate(void)
169
{
170
    if (active_console->hw_invalidate)
171
        active_console->hw_invalidate(active_console->hw);
172
}
173

    
174
void vga_hw_screen_dump(const char *filename)
175
{
176
    TextConsole *previous_active_console;
177

    
178
    previous_active_console = active_console;
179
    active_console = consoles[0];
180
    /* There is currently no way of specifying which screen we want to dump,
181
       so always dump the first one.  */
182
    if (consoles[0]->hw_screen_dump)
183
        consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
184
    active_console = previous_active_console;
185
}
186

    
187
void vga_hw_text_update(console_ch_t *chardata)
188
{
189
    if (active_console && active_console->hw_text_update)
190
        active_console->hw_text_update(active_console->hw, chardata);
191
}
192

    
193
/* convert a RGBA color to a color index usable in graphic primitives */
194
static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
195
{
196
    unsigned int r, g, b, color;
197

    
198
    switch(ds_get_bits_per_pixel(ds)) {
199
#if 0
200
    case 8:
201
        r = (rgba >> 16) & 0xff;
202
        g = (rgba >> 8) & 0xff;
203
        b = (rgba) & 0xff;
204
        color = (rgb_to_index[r] * 6 * 6) +
205
            (rgb_to_index[g] * 6) +
206
            (rgb_to_index[b]);
207
        break;
208
#endif
209
    case 15:
210
        r = (rgba >> 16) & 0xff;
211
        g = (rgba >> 8) & 0xff;
212
        b = (rgba) & 0xff;
213
        color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
214
        break;
215
    case 16:
216
        r = (rgba >> 16) & 0xff;
217
        g = (rgba >> 8) & 0xff;
218
        b = (rgba) & 0xff;
219
        color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
220
        break;
221
    case 32:
222
    default:
223
        color = rgba;
224
        break;
225
    }
226
    return color;
227
}
228

    
229
static void vga_fill_rect (DisplayState *ds,
230
                           int posx, int posy, int width, int height, uint32_t color)
231
{
232
    uint8_t *d, *d1;
233
    int x, y, bpp;
234

    
235
    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
236
    d1 = ds_get_data(ds) +
237
        ds_get_linesize(ds) * posy + bpp * posx;
238
    for (y = 0; y < height; y++) {
239
        d = d1;
240
        switch(bpp) {
241
        case 1:
242
            for (x = 0; x < width; x++) {
243
                *((uint8_t *)d) = color;
244
                d++;
245
            }
246
            break;
247
        case 2:
248
            for (x = 0; x < width; x++) {
249
                *((uint16_t *)d) = color;
250
                d += 2;
251
            }
252
            break;
253
        case 4:
254
            for (x = 0; x < width; x++) {
255
                *((uint32_t *)d) = color;
256
                d += 4;
257
            }
258
            break;
259
        }
260
        d1 += ds_get_linesize(ds);
261
    }
262
}
263

    
264
/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
265
static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
266
{
267
    const uint8_t *s;
268
    uint8_t *d;
269
    int wb, y, bpp;
270

    
271
    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
272
    wb = w * bpp;
273
    if (yd <= ys) {
274
        s = ds_get_data(ds) +
275
            ds_get_linesize(ds) * ys + bpp * xs;
276
        d = ds_get_data(ds) +
277
            ds_get_linesize(ds) * yd + bpp * xd;
278
        for (y = 0; y < h; y++) {
279
            memmove(d, s, wb);
280
            d += ds_get_linesize(ds);
281
            s += ds_get_linesize(ds);
282
        }
283
    } else {
284
        s = ds_get_data(ds) +
285
            ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
286
        d = ds_get_data(ds) +
287
            ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
288
       for (y = 0; y < h; y++) {
289
            memmove(d, s, wb);
290
            d -= ds_get_linesize(ds);
291
            s -= ds_get_linesize(ds);
292
        }
293
    }
294
}
295

    
296
/***********************************************************/
297
/* basic char display */
298

    
299
#define FONT_HEIGHT 16
300
#define FONT_WIDTH 8
301

    
302
#include "vgafont.h"
303

    
304
#define cbswap_32(__x) \
305
((uint32_t)( \
306
                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
307
                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
308
                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
309
                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
310

    
311
#ifdef WORDS_BIGENDIAN
312
#define PAT(x) x
313
#else
314
#define PAT(x) cbswap_32(x)
315
#endif
316

    
317
static const uint32_t dmask16[16] = {
318
    PAT(0x00000000),
319
    PAT(0x000000ff),
320
    PAT(0x0000ff00),
321
    PAT(0x0000ffff),
322
    PAT(0x00ff0000),
323
    PAT(0x00ff00ff),
324
    PAT(0x00ffff00),
325
    PAT(0x00ffffff),
326
    PAT(0xff000000),
327
    PAT(0xff0000ff),
328
    PAT(0xff00ff00),
329
    PAT(0xff00ffff),
330
    PAT(0xffff0000),
331
    PAT(0xffff00ff),
332
    PAT(0xffffff00),
333
    PAT(0xffffffff),
334
};
335

    
336
static const uint32_t dmask4[4] = {
337
    PAT(0x00000000),
338
    PAT(0x0000ffff),
339
    PAT(0xffff0000),
340
    PAT(0xffffffff),
341
};
342

    
343
static uint32_t color_table[2][8];
344

    
345
enum color_names {
346
    COLOR_BLACK   = 0,
347
    COLOR_RED     = 1,
348
    COLOR_GREEN   = 2,
349
    COLOR_YELLOW  = 3,
350
    COLOR_BLUE    = 4,
351
    COLOR_MAGENTA = 5,
352
    COLOR_CYAN    = 6,
353
    COLOR_WHITE   = 7
354
};
355

    
356
static const uint32_t color_table_rgb[2][8] = {
357
    {   /* dark */
358
        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
359
        QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
360
        QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
361
        QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
362
        QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
363
        QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
364
        QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
365
        QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
366
    },
367
    {   /* bright */
368
        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
369
        QEMU_RGB(0xff, 0x00, 0x00),  /* red */
370
        QEMU_RGB(0x00, 0xff, 0x00),  /* green */
371
        QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
372
        QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
373
        QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
374
        QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
375
        QEMU_RGB(0xff, 0xff, 0xff),  /* white */
376
    }
377
};
378

    
379
static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
380
{
381
    switch(ds_get_bits_per_pixel(ds)) {
382
    case 8:
383
        col |= col << 8;
384
        col |= col << 16;
385
        break;
386
    case 15:
387
    case 16:
388
        col |= col << 16;
389
        break;
390
    default:
391
        break;
392
    }
393

    
394
    return col;
395
}
396
#ifdef DEBUG_CONSOLE
397
static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
398
{
399
    if (t_attrib->bold) {
400
        printf("b");
401
    } else {
402
        printf(" ");
403
    }
404
    if (t_attrib->uline) {
405
        printf("u");
406
    } else {
407
        printf(" ");
408
    }
409
    if (t_attrib->blink) {
410
        printf("l");
411
    } else {
412
        printf(" ");
413
    }
414
    if (t_attrib->invers) {
415
        printf("i");
416
    } else {
417
        printf(" ");
418
    }
419
    if (t_attrib->unvisible) {
420
        printf("n");
421
    } else {
422
        printf(" ");
423
    }
424

    
425
    printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
426
}
427
#endif
428

    
429
static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
430
                          TextAttributes *t_attrib)
431
{
432
    uint8_t *d;
433
    const uint8_t *font_ptr;
434
    unsigned int font_data, linesize, xorcol, bpp;
435
    int i;
436
    unsigned int fgcol, bgcol;
437

    
438
#ifdef DEBUG_CONSOLE
439
    printf("x: %2i y: %2i", x, y);
440
    console_print_text_attributes(t_attrib, ch);
441
#endif
442

    
443
    if (t_attrib->invers) {
444
        bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
445
        fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
446
    } else {
447
        fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
448
        bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
449
    }
450

    
451
    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
452
    d = ds_get_data(ds) +
453
        ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
454
    linesize = ds_get_linesize(ds);
455
    font_ptr = vgafont16 + FONT_HEIGHT * ch;
456
    xorcol = bgcol ^ fgcol;
457
    switch(ds_get_bits_per_pixel(ds)) {
458
    case 8:
459
        for(i = 0; i < FONT_HEIGHT; i++) {
460
            font_data = *font_ptr++;
461
            if (t_attrib->uline
462
                && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
463
                font_data = 0xFFFF;
464
            }
465
            ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
466
            ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
467
            d += linesize;
468
        }
469
        break;
470
    case 16:
471
    case 15:
472
        for(i = 0; i < FONT_HEIGHT; i++) {
473
            font_data = *font_ptr++;
474
            if (t_attrib->uline
475
                && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
476
                font_data = 0xFFFF;
477
            }
478
            ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
479
            ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
480
            ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
481
            ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
482
            d += linesize;
483
        }
484
        break;
485
    case 32:
486
        for(i = 0; i < FONT_HEIGHT; i++) {
487
            font_data = *font_ptr++;
488
            if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
489
                font_data = 0xFFFF;
490
            }
491
            ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
492
            ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
493
            ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
494
            ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
495
            ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
496
            ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
497
            ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
498
            ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
499
            d += linesize;
500
        }
501
        break;
502
    }
503
}
504

    
505
static void text_console_resize(TextConsole *s)
506
{
507
    TextCell *cells, *c, *c1;
508
    int w1, x, y, last_width;
509

    
510
    last_width = s->width;
511
    s->width = s->g_width / FONT_WIDTH;
512
    s->height = s->g_height / FONT_HEIGHT;
513

    
514
    w1 = last_width;
515
    if (s->width < w1)
516
        w1 = s->width;
517

    
518
    cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
519
    for(y = 0; y < s->total_height; y++) {
520
        c = &cells[y * s->width];
521
        if (w1 > 0) {
522
            c1 = &s->cells[y * last_width];
523
            for(x = 0; x < w1; x++) {
524
                *c++ = *c1++;
525
            }
526
        }
527
        for(x = w1; x < s->width; x++) {
528
            c->ch = ' ';
529
            c->t_attrib = s->t_attrib_default;
530
            c++;
531
        }
532
    }
533
    qemu_free(s->cells);
534
    s->cells = cells;
535
}
536

    
537
static inline void text_update_xy(TextConsole *s, int x, int y)
538
{
539
    s->text_x[0] = MIN(s->text_x[0], x);
540
    s->text_x[1] = MAX(s->text_x[1], x);
541
    s->text_y[0] = MIN(s->text_y[0], y);
542
    s->text_y[1] = MAX(s->text_y[1], y);
543
}
544

    
545
static void invalidate_xy(TextConsole *s, int x, int y)
546
{
547
    if (s->update_x0 > x * FONT_WIDTH)
548
        s->update_x0 = x * FONT_WIDTH;
549
    if (s->update_y0 > y * FONT_HEIGHT)
550
        s->update_y0 = y * FONT_HEIGHT;
551
    if (s->update_x1 < (x + 1) * FONT_WIDTH)
552
        s->update_x1 = (x + 1) * FONT_WIDTH;
553
    if (s->update_y1 < (y + 1) * FONT_HEIGHT)
554
        s->update_y1 = (y + 1) * FONT_HEIGHT;
555
}
556

    
557
static void update_xy(TextConsole *s, int x, int y)
558
{
559
    TextCell *c;
560
    int y1, y2;
561

    
562
    if (s == active_console) {
563
        if (!ds_get_bits_per_pixel(s->ds)) {
564
            text_update_xy(s, x, y);
565
            return;
566
        }
567

    
568
        y1 = (s->y_base + y) % s->total_height;
569
        y2 = y1 - s->y_displayed;
570
        if (y2 < 0)
571
            y2 += s->total_height;
572
        if (y2 < s->height) {
573
            c = &s->cells[y1 * s->width + x];
574
            vga_putcharxy(s->ds, x, y2, c->ch,
575
                          &(c->t_attrib));
576
            invalidate_xy(s, x, y2);
577
        }
578
    }
579
}
580

    
581
static void console_show_cursor(TextConsole *s, int show)
582
{
583
    TextCell *c;
584
    int y, y1;
585

    
586
    if (s == active_console) {
587
        int x = s->x;
588

    
589
        if (!ds_get_bits_per_pixel(s->ds)) {
590
            s->cursor_invalidate = 1;
591
            return;
592
        }
593

    
594
        if (x >= s->width) {
595
            x = s->width - 1;
596
        }
597
        y1 = (s->y_base + s->y) % s->total_height;
598
        y = y1 - s->y_displayed;
599
        if (y < 0)
600
            y += s->total_height;
601
        if (y < s->height) {
602
            c = &s->cells[y1 * s->width + x];
603
            if (show) {
604
                TextAttributes t_attrib = s->t_attrib_default;
605
                t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
606
                vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
607
            } else {
608
                vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
609
            }
610
            invalidate_xy(s, x, y);
611
        }
612
    }
613
}
614

    
615
static void console_refresh(TextConsole *s)
616
{
617
    TextCell *c;
618
    int x, y, y1;
619

    
620
    if (s != active_console)
621
        return;
622
    if (!ds_get_bits_per_pixel(s->ds)) {
623
        s->text_x[0] = 0;
624
        s->text_y[0] = 0;
625
        s->text_x[1] = s->width - 1;
626
        s->text_y[1] = s->height - 1;
627
        s->cursor_invalidate = 1;
628
        return;
629
    }
630

    
631
    vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
632
                  color_table[0][COLOR_BLACK]);
633
    y1 = s->y_displayed;
634
    for(y = 0; y < s->height; y++) {
635
        c = s->cells + y1 * s->width;
636
        for(x = 0; x < s->width; x++) {
637
            vga_putcharxy(s->ds, x, y, c->ch,
638
                          &(c->t_attrib));
639
            c++;
640
        }
641
        if (++y1 == s->total_height)
642
            y1 = 0;
643
    }
644
    console_show_cursor(s, 1);
645
    dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
646
}
647

    
648
static void console_scroll(int ydelta)
649
{
650
    TextConsole *s;
651
    int i, y1;
652

    
653
    s = active_console;
654
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
655
        return;
656

    
657
    if (ydelta > 0) {
658
        for(i = 0; i < ydelta; i++) {
659
            if (s->y_displayed == s->y_base)
660
                break;
661
            if (++s->y_displayed == s->total_height)
662
                s->y_displayed = 0;
663
        }
664
    } else {
665
        ydelta = -ydelta;
666
        i = s->backscroll_height;
667
        if (i > s->total_height - s->height)
668
            i = s->total_height - s->height;
669
        y1 = s->y_base - i;
670
        if (y1 < 0)
671
            y1 += s->total_height;
672
        for(i = 0; i < ydelta; i++) {
673
            if (s->y_displayed == y1)
674
                break;
675
            if (--s->y_displayed < 0)
676
                s->y_displayed = s->total_height - 1;
677
        }
678
    }
679
    console_refresh(s);
680
}
681

    
682
static void console_put_lf(TextConsole *s)
683
{
684
    TextCell *c;
685
    int x, y1;
686

    
687
    s->y++;
688
    if (s->y >= s->height) {
689
        s->y = s->height - 1;
690

    
691
        if (s->y_displayed == s->y_base) {
692
            if (++s->y_displayed == s->total_height)
693
                s->y_displayed = 0;
694
        }
695
        if (++s->y_base == s->total_height)
696
            s->y_base = 0;
697
        if (s->backscroll_height < s->total_height)
698
            s->backscroll_height++;
699
        y1 = (s->y_base + s->height - 1) % s->total_height;
700
        c = &s->cells[y1 * s->width];
701
        for(x = 0; x < s->width; x++) {
702
            c->ch = ' ';
703
            c->t_attrib = s->t_attrib_default;
704
            c++;
705
        }
706
        if (s == active_console && s->y_displayed == s->y_base) {
707
            if (!ds_get_bits_per_pixel(s->ds)) {
708
                s->text_x[0] = 0;
709
                s->text_y[0] = 0;
710
                s->text_x[1] = s->width - 1;
711
                s->text_y[1] = s->height - 1;
712
                return;
713
            }
714

    
715
            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
716
                       s->width * FONT_WIDTH,
717
                       (s->height - 1) * FONT_HEIGHT);
718
            vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
719
                          s->width * FONT_WIDTH, FONT_HEIGHT,
720
                          color_table[0][s->t_attrib_default.bgcol]);
721
            s->update_x0 = 0;
722
            s->update_y0 = 0;
723
            s->update_x1 = s->width * FONT_WIDTH;
724
            s->update_y1 = s->height * FONT_HEIGHT;
725
        }
726
    }
727
}
728

    
729
/* Set console attributes depending on the current escape codes.
730
 * NOTE: I know this code is not very efficient (checking every color for it
731
 * self) but it is more readable and better maintainable.
732
 */
733
static void console_handle_escape(TextConsole *s)
734
{
735
    int i;
736

    
737
    for (i=0; i<s->nb_esc_params; i++) {
738
        switch (s->esc_params[i]) {
739
            case 0: /* reset all console attributes to default */
740
                s->t_attrib = s->t_attrib_default;
741
                break;
742
            case 1:
743
                s->t_attrib.bold = 1;
744
                break;
745
            case 4:
746
                s->t_attrib.uline = 1;
747
                break;
748
            case 5:
749
                s->t_attrib.blink = 1;
750
                break;
751
            case 7:
752
                s->t_attrib.invers = 1;
753
                break;
754
            case 8:
755
                s->t_attrib.unvisible = 1;
756
                break;
757
            case 22:
758
                s->t_attrib.bold = 0;
759
                break;
760
            case 24:
761
                s->t_attrib.uline = 0;
762
                break;
763
            case 25:
764
                s->t_attrib.blink = 0;
765
                break;
766
            case 27:
767
                s->t_attrib.invers = 0;
768
                break;
769
            case 28:
770
                s->t_attrib.unvisible = 0;
771
                break;
772
            /* set foreground color */
773
            case 30:
774
                s->t_attrib.fgcol=COLOR_BLACK;
775
                break;
776
            case 31:
777
                s->t_attrib.fgcol=COLOR_RED;
778
                break;
779
            case 32:
780
                s->t_attrib.fgcol=COLOR_GREEN;
781
                break;
782
            case 33:
783
                s->t_attrib.fgcol=COLOR_YELLOW;
784
                break;
785
            case 34:
786
                s->t_attrib.fgcol=COLOR_BLUE;
787
                break;
788
            case 35:
789
                s->t_attrib.fgcol=COLOR_MAGENTA;
790
                break;
791
            case 36:
792
                s->t_attrib.fgcol=COLOR_CYAN;
793
                break;
794
            case 37:
795
                s->t_attrib.fgcol=COLOR_WHITE;
796
                break;
797
            /* set background color */
798
            case 40:
799
                s->t_attrib.bgcol=COLOR_BLACK;
800
                break;
801
            case 41:
802
                s->t_attrib.bgcol=COLOR_RED;
803
                break;
804
            case 42:
805
                s->t_attrib.bgcol=COLOR_GREEN;
806
                break;
807
            case 43:
808
                s->t_attrib.bgcol=COLOR_YELLOW;
809
                break;
810
            case 44:
811
                s->t_attrib.bgcol=COLOR_BLUE;
812
                break;
813
            case 45:
814
                s->t_attrib.bgcol=COLOR_MAGENTA;
815
                break;
816
            case 46:
817
                s->t_attrib.bgcol=COLOR_CYAN;
818
                break;
819
            case 47:
820
                s->t_attrib.bgcol=COLOR_WHITE;
821
                break;
822
        }
823
    }
824
}
825

    
826
static void console_clear_xy(TextConsole *s, int x, int y)
827
{
828
    int y1 = (s->y_base + y) % s->total_height;
829
    TextCell *c = &s->cells[y1 * s->width + x];
830
    c->ch = ' ';
831
    c->t_attrib = s->t_attrib_default;
832
    c++;
833
    update_xy(s, x, y);
834
}
835

    
836
static void console_putchar(TextConsole *s, int ch)
837
{
838
    TextCell *c;
839
    int y1, i;
840
    int x, y;
841

    
842
    switch(s->state) {
843
    case TTY_STATE_NORM:
844
        switch(ch) {
845
        case '\r':  /* carriage return */
846
            s->x = 0;
847
            break;
848
        case '\n':  /* newline */
849
            console_put_lf(s);
850
            break;
851
        case '\b':  /* backspace */
852
            if (s->x > 0)
853
                s->x--;
854
            break;
855
        case '\t':  /* tabspace */
856
            if (s->x + (8 - (s->x % 8)) > s->width) {
857
                s->x = 0;
858
                console_put_lf(s);
859
            } else {
860
                s->x = s->x + (8 - (s->x % 8));
861
            }
862
            break;
863
        case '\a':  /* alert aka. bell */
864
            /* TODO: has to be implemented */
865
            break;
866
        case 14:
867
            /* SI (shift in), character set 0 (ignored) */
868
            break;
869
        case 15:
870
            /* SO (shift out), character set 1 (ignored) */
871
            break;
872
        case 27:    /* esc (introducing an escape sequence) */
873
            s->state = TTY_STATE_ESC;
874
            break;
875
        default:
876
            if (s->x >= s->width) {
877
                /* line wrap */
878
                s->x = 0;
879
                console_put_lf(s);
880
            }
881
            y1 = (s->y_base + s->y) % s->total_height;
882
            c = &s->cells[y1 * s->width + s->x];
883
            c->ch = ch;
884
            c->t_attrib = s->t_attrib;
885
            update_xy(s, s->x, s->y);
886
            s->x++;
887
            break;
888
        }
889
        break;
890
    case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
891
        if (ch == '[') {
892
            for(i=0;i<MAX_ESC_PARAMS;i++)
893
                s->esc_params[i] = 0;
894
            s->nb_esc_params = 0;
895
            s->state = TTY_STATE_CSI;
896
        } else {
897
            s->state = TTY_STATE_NORM;
898
        }
899
        break;
900
    case TTY_STATE_CSI: /* handle escape sequence parameters */
901
        if (ch >= '0' && ch <= '9') {
902
            if (s->nb_esc_params < MAX_ESC_PARAMS) {
903
                s->esc_params[s->nb_esc_params] =
904
                    s->esc_params[s->nb_esc_params] * 10 + ch - '0';
905
            }
906
        } else {
907
            s->nb_esc_params++;
908
            if (ch == ';')
909
                break;
910
#ifdef DEBUG_CONSOLE
911
            fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
912
                    s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
913
#endif
914
            s->state = TTY_STATE_NORM;
915
            switch(ch) {
916
            case 'A':
917
                /* move cursor up */
918
                if (s->esc_params[0] == 0) {
919
                    s->esc_params[0] = 1;
920
                }
921
                s->y -= s->esc_params[0];
922
                if (s->y < 0) {
923
                    s->y = 0;
924
                }
925
                break;
926
            case 'B':
927
                /* move cursor down */
928
                if (s->esc_params[0] == 0) {
929
                    s->esc_params[0] = 1;
930
                }
931
                s->y += s->esc_params[0];
932
                if (s->y >= s->height) {
933
                    s->y = s->height - 1;
934
                }
935
                break;
936
            case 'C':
937
                /* move cursor right */
938
                if (s->esc_params[0] == 0) {
939
                    s->esc_params[0] = 1;
940
                }
941
                s->x += s->esc_params[0];
942
                if (s->x >= s->width) {
943
                    s->x = s->width - 1;
944
                }
945
                break;
946
            case 'D':
947
                /* move cursor left */
948
                if (s->esc_params[0] == 0) {
949
                    s->esc_params[0] = 1;
950
                }
951
                s->x -= s->esc_params[0];
952
                if (s->x < 0) {
953
                    s->x = 0;
954
                }
955
                break;
956
            case 'G':
957
                /* move cursor to column */
958
                s->x = s->esc_params[0] - 1;
959
                if (s->x < 0) {
960
                    s->x = 0;
961
                }
962
                break;
963
            case 'f':
964
            case 'H':
965
                /* move cursor to row, column */
966
                s->x = s->esc_params[1] - 1;
967
                if (s->x < 0) {
968
                    s->x = 0;
969
                }
970
                s->y = s->esc_params[0] - 1;
971
                if (s->y < 0) {
972
                    s->y = 0;
973
                }
974
                break;
975
            case 'J':
976
                switch (s->esc_params[0]) {
977
                case 0:
978
                    /* clear to end of screen */
979
                    for (y = s->y; y < s->height; y++) {
980
                        for (x = 0; x < s->width; x++) {
981
                            if (y == s->y && x < s->x) {
982
                                continue;
983
                            }
984
                            console_clear_xy(s, x, y);
985
                        }
986
                    }
987
                    break;
988
                case 1:
989
                    /* clear from beginning of screen */
990
                    for (y = 0; y <= s->y; y++) {
991
                        for (x = 0; x < s->width; x++) {
992
                            if (y == s->y && x > s->x) {
993
                                break;
994
                            }
995
                            console_clear_xy(s, x, y);
996
                        }
997
                    }
998
                    break;
999
                case 2:
1000
                    /* clear entire screen */
1001
                    for (y = 0; y <= s->height; y++) {
1002
                        for (x = 0; x < s->width; x++) {
1003
                            console_clear_xy(s, x, y);
1004
                        }
1005
                    }
1006
                break;
1007
                }
1008
            case 'K':
1009
                switch (s->esc_params[0]) {
1010
                case 0:
1011
                /* clear to eol */
1012
                for(x = s->x; x < s->width; x++) {
1013
                        console_clear_xy(s, x, s->y);
1014
                }
1015
                break;
1016
                case 1:
1017
                    /* clear from beginning of line */
1018
                    for (x = 0; x <= s->x; x++) {
1019
                        console_clear_xy(s, x, s->y);
1020
                    }
1021
                    break;
1022
                case 2:
1023
                    /* clear entire line */
1024
                    for(x = 0; x < s->width; x++) {
1025
                        console_clear_xy(s, x, s->y);
1026
                    }
1027
                break;
1028
            }
1029
                break;
1030
            case 'm':
1031
            console_handle_escape(s);
1032
            break;
1033
            case 'n':
1034
                /* report cursor position */
1035
                /* TODO: send ESC[row;colR */
1036
                break;
1037
            case 's':
1038
                /* save cursor position */
1039
                s->x_saved = s->x;
1040
                s->y_saved = s->y;
1041
                break;
1042
            case 'u':
1043
                /* restore cursor position */
1044
                s->x = s->x_saved;
1045
                s->y = s->y_saved;
1046
                break;
1047
            default:
1048
#ifdef DEBUG_CONSOLE
1049
                fprintf(stderr, "unhandled escape character '%c'\n", ch);
1050
#endif
1051
                break;
1052
            }
1053
            break;
1054
        }
1055
    }
1056
}
1057

    
1058
void console_select(unsigned int index)
1059
{
1060
    TextConsole *s;
1061

    
1062
    if (index >= MAX_CONSOLES)
1063
        return;
1064
    active_console->g_width = ds_get_width(active_console->ds);
1065
    active_console->g_height = ds_get_height(active_console->ds);
1066
    s = consoles[index];
1067
    if (s) {
1068
        DisplayState *ds = s->ds;
1069
        active_console = s;
1070
        if (ds_get_bits_per_pixel(s->ds)) {
1071
            ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
1072
        } else {
1073
            s->ds->surface->width = s->width;
1074
            s->ds->surface->height = s->height;
1075
        }
1076
        dpy_resize(s->ds);
1077
        vga_hw_invalidate();
1078
    }
1079
}
1080

    
1081
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1082
{
1083
    TextConsole *s = chr->opaque;
1084
    int i;
1085

    
1086
    s->update_x0 = s->width * FONT_WIDTH;
1087
    s->update_y0 = s->height * FONT_HEIGHT;
1088
    s->update_x1 = 0;
1089
    s->update_y1 = 0;
1090
    console_show_cursor(s, 0);
1091
    for(i = 0; i < len; i++) {
1092
        console_putchar(s, buf[i]);
1093
    }
1094
    console_show_cursor(s, 1);
1095
    if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1096
        dpy_update(s->ds, s->update_x0, s->update_y0,
1097
                   s->update_x1 - s->update_x0,
1098
                   s->update_y1 - s->update_y0);
1099
    }
1100
    return len;
1101
}
1102

    
1103
static void console_send_event(CharDriverState *chr, int event)
1104
{
1105
    TextConsole *s = chr->opaque;
1106
    int i;
1107

    
1108
    if (event == CHR_EVENT_FOCUS) {
1109
        for(i = 0; i < nb_consoles; i++) {
1110
            if (consoles[i] == s) {
1111
                console_select(i);
1112
                break;
1113
            }
1114
        }
1115
    }
1116
}
1117

    
1118
static void kbd_send_chars(void *opaque)
1119
{
1120
    TextConsole *s = opaque;
1121
    int len;
1122
    uint8_t buf[16];
1123

    
1124
    len = qemu_chr_can_read(s->chr);
1125
    if (len > s->out_fifo.count)
1126
        len = s->out_fifo.count;
1127
    if (len > 0) {
1128
        if (len > sizeof(buf))
1129
            len = sizeof(buf);
1130
        qemu_fifo_read(&s->out_fifo, buf, len);
1131
        qemu_chr_read(s->chr, buf, len);
1132
    }
1133
    /* characters are pending: we send them a bit later (XXX:
1134
       horrible, should change char device API) */
1135
    if (s->out_fifo.count > 0) {
1136
        qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
1137
    }
1138
}
1139

    
1140
/* called when an ascii key is pressed */
1141
void kbd_put_keysym(int keysym)
1142
{
1143
    TextConsole *s;
1144
    uint8_t buf[16], *q;
1145
    int c;
1146

    
1147
    s = active_console;
1148
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
1149
        return;
1150

    
1151
    switch(keysym) {
1152
    case QEMU_KEY_CTRL_UP:
1153
        console_scroll(-1);
1154
        break;
1155
    case QEMU_KEY_CTRL_DOWN:
1156
        console_scroll(1);
1157
        break;
1158
    case QEMU_KEY_CTRL_PAGEUP:
1159
        console_scroll(-10);
1160
        break;
1161
    case QEMU_KEY_CTRL_PAGEDOWN:
1162
        console_scroll(10);
1163
        break;
1164
    default:
1165
        /* convert the QEMU keysym to VT100 key string */
1166
        q = buf;
1167
        if (keysym >= 0xe100 && keysym <= 0xe11f) {
1168
            *q++ = '\033';
1169
            *q++ = '[';
1170
            c = keysym - 0xe100;
1171
            if (c >= 10)
1172
                *q++ = '0' + (c / 10);
1173
            *q++ = '0' + (c % 10);
1174
            *q++ = '~';
1175
        } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1176
            *q++ = '\033';
1177
            *q++ = '[';
1178
            *q++ = keysym & 0xff;
1179
        } else {
1180
                *q++ = keysym;
1181
        }
1182
        if (s->chr->chr_read) {
1183
            qemu_fifo_write(&s->out_fifo, buf, q - buf);
1184
            kbd_send_chars(s);
1185
        }
1186
        break;
1187
    }
1188
}
1189

    
1190
static void text_console_invalidate(void *opaque)
1191
{
1192
    TextConsole *s = (TextConsole *) opaque;
1193
    if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1194
        s->g_width = ds_get_width(s->ds);
1195
        s->g_height = ds_get_height(s->ds);
1196
        text_console_resize(s);
1197
    }
1198
    console_refresh(s);
1199
}
1200

    
1201
static void text_console_update(void *opaque, console_ch_t *chardata)
1202
{
1203
    TextConsole *s = (TextConsole *) opaque;
1204
    int i, j, src;
1205

    
1206
    if (s->text_x[0] <= s->text_x[1]) {
1207
        src = (s->y_base + s->text_y[0]) * s->width;
1208
        chardata += s->text_y[0] * s->width;
1209
        for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1210
            for (j = 0; j < s->width; j ++, src ++)
1211
                console_write_ch(chardata ++, s->cells[src].ch |
1212
                                (s->cells[src].t_attrib.fgcol << 12) |
1213
                                (s->cells[src].t_attrib.bgcol << 8) |
1214
                                (s->cells[src].t_attrib.bold << 21));
1215
        dpy_update(s->ds, s->text_x[0], s->text_y[0],
1216
                   s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1217
        s->text_x[0] = s->width;
1218
        s->text_y[0] = s->height;
1219
        s->text_x[1] = 0;
1220
        s->text_y[1] = 0;
1221
    }
1222
    if (s->cursor_invalidate) {
1223
        dpy_cursor(s->ds, s->x, s->y);
1224
        s->cursor_invalidate = 0;
1225
    }
1226
}
1227

    
1228
static TextConsole *get_graphic_console(DisplayState *ds)
1229
{
1230
    int i;
1231
    TextConsole *s;
1232
    for (i = 0; i < nb_consoles; i++) {
1233
        s = consoles[i];
1234
        if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
1235
            return s;
1236
    }
1237
    return NULL;
1238
}
1239

    
1240
static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1241
{
1242
    TextConsole *s;
1243
    int i;
1244

    
1245
    if (nb_consoles >= MAX_CONSOLES)
1246
        return NULL;
1247
    s = qemu_mallocz(sizeof(TextConsole));
1248
    if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1249
        (console_type == GRAPHIC_CONSOLE))) {
1250
        active_console = s;
1251
    }
1252
    s->ds = ds;
1253
    s->console_type = console_type;
1254
    if (console_type != GRAPHIC_CONSOLE) {
1255
        consoles[nb_consoles++] = s;
1256
    } else {
1257
        /* HACK: Put graphical consoles before text consoles.  */
1258
        for (i = nb_consoles; i > 0; i--) {
1259
            if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1260
                break;
1261
            consoles[i] = consoles[i - 1];
1262
        }
1263
        consoles[i] = s;
1264
        nb_consoles++;
1265
    }
1266
    return s;
1267
}
1268

    
1269
DisplayState *graphic_console_init(vga_hw_update_ptr update,
1270
                                   vga_hw_invalidate_ptr invalidate,
1271
                                   vga_hw_screen_dump_ptr screen_dump,
1272
                                   vga_hw_text_update_ptr text_update,
1273
                                   void *opaque)
1274
{
1275
    TextConsole *s;
1276
    DisplayState *ds;
1277

    
1278
    ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
1279
    ds->allocator = &default_allocator; 
1280
    ds->surface = qemu_create_displaysurface(ds, 640, 480);
1281

    
1282
    s = new_console(ds, GRAPHIC_CONSOLE);
1283
    if (s == NULL) {
1284
        qemu_free_displaysurface(ds);
1285
        qemu_free(ds);
1286
        return NULL;
1287
    }
1288
    s->hw_update = update;
1289
    s->hw_invalidate = invalidate;
1290
    s->hw_screen_dump = screen_dump;
1291
    s->hw_text_update = text_update;
1292
    s->hw = opaque;
1293

    
1294
    register_displaystate(ds);
1295
    return ds;
1296
}
1297

    
1298
int is_graphic_console(void)
1299
{
1300
    return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1301
}
1302

    
1303
int is_fixedsize_console(void)
1304
{
1305
    return active_console && active_console->console_type != TEXT_CONSOLE;
1306
}
1307

    
1308
void console_color_init(DisplayState *ds)
1309
{
1310
    int i, j;
1311
    for (j = 0; j < 2; j++) {
1312
        for (i = 0; i < 8; i++) {
1313
            color_table[j][i] = col_expand(ds,
1314
                   vga_get_color(ds, color_table_rgb[j][i]));
1315
        }
1316
    }
1317
}
1318

    
1319
static int n_text_consoles;
1320
static CharDriverState *text_consoles[128];
1321
static char *text_console_strs[128];
1322

    
1323
static void text_console_do_init(CharDriverState *chr, DisplayState *ds, const char *p)
1324
{
1325
    TextConsole *s;
1326
    unsigned width;
1327
    unsigned height;
1328
    static int color_inited;
1329

    
1330
    s = new_console(ds, (p == NULL) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
1331
    if (!s) {
1332
        free(chr);
1333
        return;
1334
    }
1335
    chr->opaque = s;
1336
    chr->chr_write = console_puts;
1337
    chr->chr_send_event = console_send_event;
1338

    
1339
    s->chr = chr;
1340
    s->out_fifo.buf = s->out_fifo_buf;
1341
    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1342
    s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1343
    s->ds = ds;
1344

    
1345
    if (!color_inited) {
1346
        color_inited = 1;
1347
        console_color_init(s->ds);
1348
    }
1349
    s->y_displayed = 0;
1350
    s->y_base = 0;
1351
    s->total_height = DEFAULT_BACKSCROLL;
1352
    s->x = 0;
1353
    s->y = 0;
1354
    width = ds_get_width(s->ds);
1355
    height = ds_get_height(s->ds);
1356
    if (p != NULL) {
1357
        width = strtoul(p, (char **)&p, 10);
1358
        if (*p == 'C') {
1359
            p++;
1360
            width *= FONT_WIDTH;
1361
        }
1362
        if (*p == 'x') {
1363
            p++;
1364
            height = strtoul(p, (char **)&p, 10);
1365
            if (*p == 'C') {
1366
                p++;
1367
                height *= FONT_HEIGHT;
1368
            }
1369
        }
1370
    }
1371
    s->g_width = width;
1372
    s->g_height = height;
1373

    
1374
    s->hw_invalidate = text_console_invalidate;
1375
    s->hw_text_update = text_console_update;
1376
    s->hw = s;
1377

    
1378
    /* Set text attribute defaults */
1379
    s->t_attrib_default.bold = 0;
1380
    s->t_attrib_default.uline = 0;
1381
    s->t_attrib_default.blink = 0;
1382
    s->t_attrib_default.invers = 0;
1383
    s->t_attrib_default.unvisible = 0;
1384
    s->t_attrib_default.fgcol = COLOR_WHITE;
1385
    s->t_attrib_default.bgcol = COLOR_BLACK;
1386
    /* set current text attributes to default */
1387
    s->t_attrib = s->t_attrib_default;
1388
    text_console_resize(s);
1389

    
1390
    qemu_chr_reset(chr);
1391
    if (chr->init)
1392
        chr->init(chr);
1393
}
1394

    
1395
CharDriverState *text_console_init(const char *p)
1396
{
1397
    CharDriverState *chr;
1398

    
1399
    chr = qemu_mallocz(sizeof(CharDriverState));
1400

    
1401
    if (n_text_consoles == 128) {
1402
        fprintf(stderr, "Too many text consoles\n");
1403
        exit(1);
1404
    }
1405
    text_consoles[n_text_consoles] = chr;
1406
    text_console_strs[n_text_consoles] = p ? qemu_strdup(p) : NULL;
1407
    n_text_consoles++;
1408

    
1409
    return chr;
1410
}
1411

    
1412
void text_consoles_set_display(DisplayState *ds)
1413
{
1414
    int i;
1415

    
1416
    for (i = 0; i < n_text_consoles; i++) {
1417
        text_console_do_init(text_consoles[i], ds, text_console_strs[i]);
1418
        qemu_free(text_console_strs[i]);
1419
    }
1420

    
1421
    n_text_consoles = 0;
1422
}
1423

    
1424
void qemu_console_resize(DisplayState *ds, int width, int height)
1425
{
1426
    TextConsole *s = get_graphic_console(ds);
1427
    if (!s) return;
1428

    
1429
    s->g_width = width;
1430
    s->g_height = height;
1431
    if (is_graphic_console()) {
1432
        ds->surface = qemu_resize_displaysurface(ds, width, height);
1433
        dpy_resize(ds);
1434
    }
1435
}
1436

    
1437
void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1438
                       int dst_x, int dst_y, int w, int h)
1439
{
1440
    if (is_graphic_console()) {
1441
        dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1442
    }
1443
}
1444

    
1445
PixelFormat qemu_different_endianness_pixelformat(int bpp)
1446
{
1447
    PixelFormat pf;
1448

    
1449
    memset(&pf, 0x00, sizeof(PixelFormat));
1450

    
1451
    pf.bits_per_pixel = bpp;
1452
    pf.bytes_per_pixel = bpp / 8;
1453
    pf.depth = bpp == 32 ? 24 : bpp;
1454

    
1455
    switch (bpp) {
1456
        case 24:
1457
            pf.rmask = 0x000000FF;
1458
            pf.gmask = 0x0000FF00;
1459
            pf.bmask = 0x00FF0000;
1460
            pf.rmax = 255;
1461
            pf.gmax = 255;
1462
            pf.bmax = 255;
1463
            pf.rshift = 0;
1464
            pf.gshift = 8;
1465
            pf.bshift = 16;
1466
            pf.rbits = 8;
1467
            pf.gbits = 8;
1468
            pf.bbits = 8;
1469
            break;
1470
        case 32:
1471
            pf.rmask = 0x0000FF00;
1472
            pf.gmask = 0x00FF0000;
1473
            pf.bmask = 0xFF000000;
1474
            pf.amask = 0x00000000;
1475
            pf.amax = 255;
1476
            pf.rmax = 255;
1477
            pf.gmax = 255;
1478
            pf.bmax = 255;
1479
            pf.ashift = 0;
1480
            pf.rshift = 8;
1481
            pf.gshift = 16;
1482
            pf.bshift = 24;
1483
            pf.rbits = 8;
1484
            pf.gbits = 8;
1485
            pf.bbits = 8;
1486
            pf.abits = 8;
1487
            break;
1488
        default:
1489
            break;
1490
    }
1491
    return pf;
1492
}
1493

    
1494
PixelFormat qemu_default_pixelformat(int bpp)
1495
{
1496
    PixelFormat pf;
1497

    
1498
    memset(&pf, 0x00, sizeof(PixelFormat));
1499

    
1500
    pf.bits_per_pixel = bpp;
1501
    pf.bytes_per_pixel = bpp / 8;
1502
    pf.depth = bpp == 32 ? 24 : bpp;
1503

    
1504
    switch (bpp) {
1505
        case 16:
1506
            pf.rmask = 0x0000F800;
1507
            pf.gmask = 0x000007E0;
1508
            pf.bmask = 0x0000001F;
1509
            pf.rmax = 31;
1510
            pf.gmax = 63;
1511
            pf.bmax = 31;
1512
            pf.rshift = 11;
1513
            pf.gshift = 5;
1514
            pf.bshift = 0;
1515
            pf.rbits = 5;
1516
            pf.gbits = 6;
1517
            pf.bbits = 5;
1518
            break;
1519
        case 24:
1520
            pf.rmask = 0x00FF0000;
1521
            pf.gmask = 0x0000FF00;
1522
            pf.bmask = 0x000000FF;
1523
            pf.rmax = 255;
1524
            pf.gmax = 255;
1525
            pf.bmax = 255;
1526
            pf.rshift = 16;
1527
            pf.gshift = 8;
1528
            pf.bshift = 0;
1529
            pf.rbits = 8;
1530
            pf.gbits = 8;
1531
            pf.bbits = 8;
1532
        case 32:
1533
            pf.rmask = 0x00FF0000;
1534
            pf.gmask = 0x0000FF00;
1535
            pf.bmask = 0x000000FF;
1536
            pf.amax = 255;
1537
            pf.rmax = 255;
1538
            pf.gmax = 255;
1539
            pf.bmax = 255;
1540
            pf.ashift = 24;
1541
            pf.rshift = 16;
1542
            pf.gshift = 8;
1543
            pf.bshift = 0;
1544
            pf.rbits = 8;
1545
            pf.gbits = 8;
1546
            pf.bbits = 8;
1547
            pf.abits = 8;
1548
            break;
1549
        default:
1550
            break;
1551
    }
1552
    return pf;
1553
}
1554

    
1555
DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1556
{
1557
    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1558

    
1559
    surface->width = width;
1560
    surface->height = height;
1561
    surface->linesize = width * 4;
1562
    surface->pf = qemu_default_pixelformat(32);
1563
#ifdef WORDS_BIGENDIAN
1564
    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1565
#else
1566
    surface->flags = QEMU_ALLOCATED_FLAG;
1567
#endif
1568
    surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
1569

    
1570
    return surface;
1571
}
1572

    
1573
DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1574
                                          int width, int height)
1575
{
1576
    surface->width = width;
1577
    surface->height = height;
1578
    surface->linesize = width * 4;
1579
    surface->pf = qemu_default_pixelformat(32);
1580
    if (surface->flags & QEMU_ALLOCATED_FLAG)
1581
        surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1582
    else
1583
        surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
1584
#ifdef WORDS_BIGENDIAN
1585
    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1586
#else
1587
    surface->flags = QEMU_ALLOCATED_FLAG;
1588
#endif
1589

    
1590
    return surface;
1591
}
1592

    
1593
DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1594
                                              int linesize, uint8_t *data)
1595
{
1596
    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1597

    
1598
    surface->width = width;
1599
    surface->height = height;
1600
    surface->linesize = linesize;
1601
    surface->pf = qemu_default_pixelformat(bpp);
1602
#ifdef WORDS_BIGENDIAN
1603
    surface->flags = QEMU_BIG_ENDIAN_FLAG;
1604
#endif
1605
    surface->data = data;
1606

    
1607
    return surface;
1608
}
1609

    
1610
void defaultallocator_free_displaysurface(DisplaySurface *surface)
1611
{
1612
    if (surface == NULL)
1613
        return;
1614
    if (surface->flags & QEMU_ALLOCATED_FLAG)
1615
        qemu_free(surface->data);
1616
    qemu_free(surface);
1617
}