Statistics
| Branch: | Revision:

root / console.c @ 3023f332

History | View | Annotate | Download (41.9 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
    enum TTYState state;
143
    int esc_params[MAX_ESC_PARAMS];
144
    int nb_esc_params;
145

    
146
    CharDriverState *chr;
147
    /* fifo for key pressed */
148
    QEMUFIFO out_fifo;
149
    uint8_t out_fifo_buf[16];
150
    QEMUTimer *kbd_timer;
151
};
152

    
153
static TextConsole *active_console;
154
static TextConsole *consoles[MAX_CONSOLES];
155
static int nb_consoles = 0;
156

    
157
void vga_hw_update(void)
158
{
159
    if (active_console && active_console->hw_update)
160
        active_console->hw_update(active_console->hw);
161
}
162

    
163
void vga_hw_invalidate(void)
164
{
165
    if (active_console->hw_invalidate)
166
        active_console->hw_invalidate(active_console->hw);
167
}
168

    
169
void vga_hw_screen_dump(const char *filename)
170
{
171
    TextConsole *previous_active_console;
172

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

    
182
void vga_hw_text_update(console_ch_t *chardata)
183
{
184
    if (active_console && active_console->hw_text_update)
185
        active_console->hw_text_update(active_console->hw, chardata);
186
}
187

    
188
/* convert a RGBA color to a color index usable in graphic primitives */
189
static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
190
{
191
    unsigned int r, g, b, color;
192

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

    
224
static void vga_fill_rect (DisplayState *ds,
225
                           int posx, int posy, int width, int height, uint32_t color)
226
{
227
    uint8_t *d, *d1;
228
    int x, y, bpp;
229

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

    
259
/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
260
static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
261
{
262
    const uint8_t *s;
263
    uint8_t *d;
264
    int wb, y, bpp;
265

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

    
291
/***********************************************************/
292
/* basic char display */
293

    
294
#define FONT_HEIGHT 16
295
#define FONT_WIDTH 8
296

    
297
#include "vgafont.h"
298

    
299
#define cbswap_32(__x) \
300
((uint32_t)( \
301
                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
302
                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
303
                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
304
                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
305

    
306
#ifdef WORDS_BIGENDIAN
307
#define PAT(x) x
308
#else
309
#define PAT(x) cbswap_32(x)
310
#endif
311

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

    
331
static const uint32_t dmask4[4] = {
332
    PAT(0x00000000),
333
    PAT(0x0000ffff),
334
    PAT(0xffff0000),
335
    PAT(0xffffffff),
336
};
337

    
338
static uint32_t color_table[2][8];
339

    
340
enum color_names {
341
    COLOR_BLACK   = 0,
342
    COLOR_RED     = 1,
343
    COLOR_GREEN   = 2,
344
    COLOR_YELLOW  = 3,
345
    COLOR_BLUE    = 4,
346
    COLOR_MAGENTA = 5,
347
    COLOR_CYAN    = 6,
348
    COLOR_WHITE   = 7
349
};
350

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

    
374
static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
375
{
376
    switch(ds_get_bits_per_pixel(ds)) {
377
    case 8:
378
        col |= col << 8;
379
        col |= col << 16;
380
        break;
381
    case 15:
382
    case 16:
383
        col |= col << 16;
384
        break;
385
    default:
386
        break;
387
    }
388

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

    
420
    printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
421
}
422
#endif
423

    
424
static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
425
                          TextAttributes *t_attrib)
426
{
427
    uint8_t *d;
428
    const uint8_t *font_ptr;
429
    unsigned int font_data, linesize, xorcol, bpp;
430
    int i;
431
    unsigned int fgcol, bgcol;
432

    
433
#ifdef DEBUG_CONSOLE
434
    printf("x: %2i y: %2i", x, y);
435
    console_print_text_attributes(t_attrib, ch);
436
#endif
437

    
438
    if (t_attrib->invers) {
439
        bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
440
        fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
441
    } else {
442
        fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
443
        bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
444
    }
445

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

    
500
static void text_console_resize(TextConsole *s)
501
{
502
    TextCell *cells, *c, *c1;
503
    int w1, x, y, last_width;
504

    
505
    last_width = s->width;
506
    s->width = s->g_width / FONT_WIDTH;
507
    s->height = s->g_height / FONT_HEIGHT;
508

    
509
    w1 = last_width;
510
    if (s->width < w1)
511
        w1 = s->width;
512

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

    
532
static inline void text_update_xy(TextConsole *s, int x, int y)
533
{
534
    s->text_x[0] = MIN(s->text_x[0], x);
535
    s->text_x[1] = MAX(s->text_x[1], x);
536
    s->text_y[0] = MIN(s->text_y[0], y);
537
    s->text_y[1] = MAX(s->text_y[1], y);
538
}
539

    
540
static void update_xy(TextConsole *s, int x, int y)
541
{
542
    TextCell *c;
543
    int y1, y2;
544

    
545
    if (s == active_console) {
546
        if (!ds_get_bits_per_pixel(s->ds)) {
547
            text_update_xy(s, x, y);
548
            return;
549
        }
550

    
551
        y1 = (s->y_base + y) % s->total_height;
552
        y2 = y1 - s->y_displayed;
553
        if (y2 < 0)
554
            y2 += s->total_height;
555
        if (y2 < s->height) {
556
            c = &s->cells[y1 * s->width + x];
557
            vga_putcharxy(s->ds, x, y2, c->ch,
558
                          &(c->t_attrib));
559
            dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
560
                       FONT_WIDTH, FONT_HEIGHT);
561
        }
562
    }
563
}
564

    
565
static void console_show_cursor(TextConsole *s, int show)
566
{
567
    TextCell *c;
568
    int y, y1;
569

    
570
    if (s == active_console) {
571
        int x = s->x;
572

    
573
        if (!ds_get_bits_per_pixel(s->ds)) {
574
            s->cursor_invalidate = 1;
575
            return;
576
        }
577

    
578
        if (x >= s->width) {
579
            x = s->width - 1;
580
        }
581
        y1 = (s->y_base + s->y) % s->total_height;
582
        y = y1 - s->y_displayed;
583
        if (y < 0)
584
            y += s->total_height;
585
        if (y < s->height) {
586
            c = &s->cells[y1 * s->width + x];
587
            if (show) {
588
                TextAttributes t_attrib = s->t_attrib_default;
589
                t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
590
                vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
591
            } else {
592
                vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
593
            }
594
            dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT,
595
                       FONT_WIDTH, FONT_HEIGHT);
596
        }
597
    }
598
}
599

    
600
static void console_refresh(TextConsole *s)
601
{
602
    TextCell *c;
603
    int x, y, y1;
604

    
605
    if (s != active_console)
606
        return;
607
    if (!ds_get_bits_per_pixel(s->ds)) {
608
        s->text_x[0] = 0;
609
        s->text_y[0] = 0;
610
        s->text_x[1] = s->width - 1;
611
        s->text_y[1] = s->height - 1;
612
        s->cursor_invalidate = 1;
613
        return;
614
    }
615

    
616
    vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
617
                  color_table[0][COLOR_BLACK]);
618
    y1 = s->y_displayed;
619
    for(y = 0; y < s->height; y++) {
620
        c = s->cells + y1 * s->width;
621
        for(x = 0; x < s->width; x++) {
622
            vga_putcharxy(s->ds, x, y, c->ch,
623
                          &(c->t_attrib));
624
            c++;
625
        }
626
        if (++y1 == s->total_height)
627
            y1 = 0;
628
    }
629
    dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
630
    console_show_cursor(s, 1);
631
}
632

    
633
static void console_scroll(int ydelta)
634
{
635
    TextConsole *s;
636
    int i, y1;
637

    
638
    s = active_console;
639
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
640
        return;
641

    
642
    if (ydelta > 0) {
643
        for(i = 0; i < ydelta; i++) {
644
            if (s->y_displayed == s->y_base)
645
                break;
646
            if (++s->y_displayed == s->total_height)
647
                s->y_displayed = 0;
648
        }
649
    } else {
650
        ydelta = -ydelta;
651
        i = s->backscroll_height;
652
        if (i > s->total_height - s->height)
653
            i = s->total_height - s->height;
654
        y1 = s->y_base - i;
655
        if (y1 < 0)
656
            y1 += s->total_height;
657
        for(i = 0; i < ydelta; i++) {
658
            if (s->y_displayed == y1)
659
                break;
660
            if (--s->y_displayed < 0)
661
                s->y_displayed = s->total_height - 1;
662
        }
663
    }
664
    console_refresh(s);
665
}
666

    
667
static void console_put_lf(TextConsole *s)
668
{
669
    TextCell *c;
670
    int x, y1;
671

    
672
    s->y++;
673
    if (s->y >= s->height) {
674
        s->y = s->height - 1;
675

    
676
        if (s->y_displayed == s->y_base) {
677
            if (++s->y_displayed == s->total_height)
678
                s->y_displayed = 0;
679
        }
680
        if (++s->y_base == s->total_height)
681
            s->y_base = 0;
682
        if (s->backscroll_height < s->total_height)
683
            s->backscroll_height++;
684
        y1 = (s->y_base + s->height - 1) % s->total_height;
685
        c = &s->cells[y1 * s->width];
686
        for(x = 0; x < s->width; x++) {
687
            c->ch = ' ';
688
            c->t_attrib = s->t_attrib_default;
689
            c++;
690
        }
691
        if (s == active_console && s->y_displayed == s->y_base) {
692
            if (!ds_get_bits_per_pixel(s->ds)) {
693
                s->text_x[0] = 0;
694
                s->text_y[0] = 0;
695
                s->text_x[1] = s->width - 1;
696
                s->text_y[1] = s->height - 1;
697
                return;
698
            }
699

    
700
            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
701
                       s->width * FONT_WIDTH,
702
                       (s->height - 1) * FONT_HEIGHT);
703
            vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
704
                          s->width * FONT_WIDTH, FONT_HEIGHT,
705
                          color_table[0][s->t_attrib_default.bgcol]);
706
            dpy_update(s->ds, 0, 0,
707
                       s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
708
        }
709
    }
710
}
711

    
712
/* Set console attributes depending on the current escape codes.
713
 * NOTE: I know this code is not very efficient (checking every color for it
714
 * self) but it is more readable and better maintainable.
715
 */
716
static void console_handle_escape(TextConsole *s)
717
{
718
    int i;
719

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

    
809
static void console_clear_xy(TextConsole *s, int x, int y)
810
{
811
    int y1 = (s->y_base + y) % s->total_height;
812
    TextCell *c = &s->cells[y1 * s->width + x];
813
    c->ch = ' ';
814
    c->t_attrib = s->t_attrib_default;
815
    c++;
816
    update_xy(s, x, y);
817
}
818

    
819
static void console_putchar(TextConsole *s, int ch)
820
{
821
    TextCell *c;
822
    int y1, i;
823
    int x, y;
824

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

    
1041
void console_select(unsigned int index)
1042
{
1043
    TextConsole *s;
1044

    
1045
    if (index >= MAX_CONSOLES)
1046
        return;
1047
    active_console->g_width = ds_get_width(active_console->ds);
1048
    active_console->g_height = ds_get_height(active_console->ds);
1049
    s = consoles[index];
1050
    if (s) {
1051
        DisplayState *ds = s->ds;
1052
        active_console = s;
1053
        ds->surface = qemu_resize_displaysurface(ds->surface, s->g_width,
1054
                                                s->g_height, 32, 4 * s->g_width);
1055
        dpy_resize(s->ds);
1056
        vga_hw_invalidate();
1057
    }
1058
}
1059

    
1060
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1061
{
1062
    TextConsole *s = chr->opaque;
1063
    int i;
1064

    
1065
    console_show_cursor(s, 0);
1066
    for(i = 0; i < len; i++) {
1067
        console_putchar(s, buf[i]);
1068
    }
1069
    console_show_cursor(s, 1);
1070
    return len;
1071
}
1072

    
1073
static void console_send_event(CharDriverState *chr, int event)
1074
{
1075
    TextConsole *s = chr->opaque;
1076
    int i;
1077

    
1078
    if (event == CHR_EVENT_FOCUS) {
1079
        for(i = 0; i < nb_consoles; i++) {
1080
            if (consoles[i] == s) {
1081
                console_select(i);
1082
                break;
1083
            }
1084
        }
1085
    }
1086
}
1087

    
1088
static void kbd_send_chars(void *opaque)
1089
{
1090
    TextConsole *s = opaque;
1091
    int len;
1092
    uint8_t buf[16];
1093

    
1094
    len = qemu_chr_can_read(s->chr);
1095
    if (len > s->out_fifo.count)
1096
        len = s->out_fifo.count;
1097
    if (len > 0) {
1098
        if (len > sizeof(buf))
1099
            len = sizeof(buf);
1100
        qemu_fifo_read(&s->out_fifo, buf, len);
1101
        qemu_chr_read(s->chr, buf, len);
1102
    }
1103
    /* characters are pending: we send them a bit later (XXX:
1104
       horrible, should change char device API) */
1105
    if (s->out_fifo.count > 0) {
1106
        qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
1107
    }
1108
}
1109

    
1110
/* called when an ascii key is pressed */
1111
void kbd_put_keysym(int keysym)
1112
{
1113
    TextConsole *s;
1114
    uint8_t buf[16], *q;
1115
    int c;
1116

    
1117
    s = active_console;
1118
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
1119
        return;
1120

    
1121
    switch(keysym) {
1122
    case QEMU_KEY_CTRL_UP:
1123
        console_scroll(-1);
1124
        break;
1125
    case QEMU_KEY_CTRL_DOWN:
1126
        console_scroll(1);
1127
        break;
1128
    case QEMU_KEY_CTRL_PAGEUP:
1129
        console_scroll(-10);
1130
        break;
1131
    case QEMU_KEY_CTRL_PAGEDOWN:
1132
        console_scroll(10);
1133
        break;
1134
    default:
1135
        /* convert the QEMU keysym to VT100 key string */
1136
        q = buf;
1137
        if (keysym >= 0xe100 && keysym <= 0xe11f) {
1138
            *q++ = '\033';
1139
            *q++ = '[';
1140
            c = keysym - 0xe100;
1141
            if (c >= 10)
1142
                *q++ = '0' + (c / 10);
1143
            *q++ = '0' + (c % 10);
1144
            *q++ = '~';
1145
        } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1146
            *q++ = '\033';
1147
            *q++ = '[';
1148
            *q++ = keysym & 0xff;
1149
        } else {
1150
                *q++ = keysym;
1151
        }
1152
        if (s->chr->chr_read) {
1153
            qemu_fifo_write(&s->out_fifo, buf, q - buf);
1154
            kbd_send_chars(s);
1155
        }
1156
        break;
1157
    }
1158
}
1159

    
1160
static void text_console_invalidate(void *opaque)
1161
{
1162
    TextConsole *s = (TextConsole *) opaque;
1163
    console_refresh(s);
1164
}
1165

    
1166
static void text_console_update(void *opaque, console_ch_t *chardata)
1167
{
1168
    TextConsole *s = (TextConsole *) opaque;
1169
    int i, j, src;
1170

    
1171
    if (s->text_x[0] <= s->text_x[1]) {
1172
        src = (s->y_base + s->text_y[0]) * s->width;
1173
        chardata += s->text_y[0] * s->width;
1174
        for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1175
            for (j = 0; j < s->width; j ++, src ++)
1176
                console_write_ch(chardata ++, s->cells[src].ch |
1177
                                (s->cells[src].t_attrib.fgcol << 12) |
1178
                                (s->cells[src].t_attrib.bgcol << 8) |
1179
                                (s->cells[src].t_attrib.bold << 21));
1180
        dpy_update(s->ds, s->text_x[0], s->text_y[0],
1181
                   s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1182
        s->text_x[0] = s->width;
1183
        s->text_y[0] = s->height;
1184
        s->text_x[1] = 0;
1185
        s->text_y[1] = 0;
1186
    }
1187
    if (s->cursor_invalidate) {
1188
        dpy_cursor(s->ds, s->x, s->y);
1189
        s->cursor_invalidate = 0;
1190
    }
1191
}
1192

    
1193
static TextConsole *get_graphic_console() {
1194
    int i;
1195
    TextConsole *s;
1196
    for (i = 0; i < nb_consoles; i++) {
1197
        s = consoles[i];
1198
        if (s->console_type == GRAPHIC_CONSOLE)
1199
            return s;
1200
    }
1201
    return NULL;
1202
}
1203

    
1204
static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1205
{
1206
    TextConsole *s;
1207
    int i;
1208

    
1209
    if (nb_consoles >= MAX_CONSOLES)
1210
        return NULL;
1211
    s = qemu_mallocz(sizeof(TextConsole));
1212
    if (!s) {
1213
        return NULL;
1214
    }
1215
    if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1216
        (console_type == GRAPHIC_CONSOLE))) {
1217
        active_console = s;
1218
    }
1219
    s->ds = ds;
1220
    s->console_type = console_type;
1221
    if (console_type != GRAPHIC_CONSOLE) {
1222
        consoles[nb_consoles++] = s;
1223
    } else {
1224
        /* HACK: Put graphical consoles before text consoles.  */
1225
        for (i = nb_consoles; i > 0; i--) {
1226
            if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1227
                break;
1228
            consoles[i] = consoles[i - 1];
1229
        }
1230
        consoles[i] = s;
1231
        nb_consoles++;
1232
    }
1233
    return s;
1234
}
1235

    
1236
DisplayState *graphic_console_init(vga_hw_update_ptr update,
1237
                                   vga_hw_invalidate_ptr invalidate,
1238
                                   vga_hw_screen_dump_ptr screen_dump,
1239
                                   vga_hw_text_update_ptr text_update,
1240
                                   void *opaque)
1241
{
1242
    TextConsole *s;
1243
    DisplayState *ds;
1244
    
1245
    ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
1246
    if (ds == NULL)
1247
        return NULL;
1248
    ds->surface = qemu_create_displaysurface(640, 480, 32, 640 * 4);
1249

    
1250
    s = new_console(ds, GRAPHIC_CONSOLE);
1251
    if (s == NULL) {
1252
        qemu_free_displaysurface(ds->surface);
1253
        qemu_free(ds);
1254
        return NULL;
1255
    }
1256
    s->hw_update = update;
1257
    s->hw_invalidate = invalidate;
1258
    s->hw_screen_dump = screen_dump;
1259
    s->hw_text_update = text_update;
1260
    s->hw = opaque;
1261

    
1262
    register_displaystate(ds); 
1263
    return ds;
1264
}
1265

    
1266
int is_graphic_console(void)
1267
{
1268
    return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1269
}
1270

    
1271
int is_fixedsize_console(void)
1272
{
1273
    return active_console && active_console->console_type != TEXT_CONSOLE;
1274
}
1275

    
1276
void console_color_init(DisplayState *ds)
1277
{
1278
    int i, j;
1279
    for (j = 0; j < 2; j++) {
1280
        for (i = 0; i < 8; i++) {
1281
            color_table[j][i] = col_expand(ds, 
1282
                   vga_get_color(ds, color_table_rgb[j][i]));
1283
        }
1284
    }
1285
}
1286

    
1287
CharDriverState *text_console_init(DisplayState *ds, const char *p)
1288
{
1289
    CharDriverState *chr;
1290
    TextConsole *s;
1291
    unsigned width;
1292
    unsigned height;
1293
    static int color_inited;
1294

    
1295
    chr = qemu_mallocz(sizeof(CharDriverState));
1296
    if (!chr)
1297
        return NULL;
1298
    s = new_console(ds, (p == 0) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
1299
    if (!s) {
1300
        free(chr);
1301
        return NULL;
1302
    }
1303
    chr->opaque = s;
1304
    chr->chr_write = console_puts;
1305
    chr->chr_send_event = console_send_event;
1306

    
1307
    s->chr = chr;
1308
    s->out_fifo.buf = s->out_fifo_buf;
1309
    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1310
    s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1311
    s->ds = ds;
1312

    
1313
    if (!color_inited) {
1314
        color_inited = 1;
1315
        console_color_init(s->ds);
1316
    }
1317
    s->y_displayed = 0;
1318
    s->y_base = 0;
1319
    s->total_height = DEFAULT_BACKSCROLL;
1320
    s->x = 0;
1321
    s->y = 0;
1322
    width = ds_get_width(s->ds);
1323
    height = ds_get_height(s->ds);
1324
    if (p != 0) {
1325
        width = strtoul(p, (char **)&p, 10);
1326
        if (*p == 'C') {
1327
            p++;
1328
            width *= FONT_WIDTH;
1329
        }
1330
        if (*p == 'x') {
1331
            p++;
1332
            height = strtoul(p, (char **)&p, 10);
1333
            if (*p == 'C') {
1334
                p++;
1335
                height *= FONT_HEIGHT;
1336
            }
1337
        }
1338
    }
1339
    s->g_width = width;
1340
    s->g_height = height;
1341

    
1342
    s->hw_invalidate = text_console_invalidate;
1343
    s->hw_text_update = text_console_update;
1344
    s->hw = s;
1345

    
1346
    /* Set text attribute defaults */
1347
    s->t_attrib_default.bold = 0;
1348
    s->t_attrib_default.uline = 0;
1349
    s->t_attrib_default.blink = 0;
1350
    s->t_attrib_default.invers = 0;
1351
    s->t_attrib_default.unvisible = 0;
1352
    s->t_attrib_default.fgcol = COLOR_WHITE;
1353
    s->t_attrib_default.bgcol = COLOR_BLACK;
1354

    
1355
    /* set current text attributes to default */
1356
    s->t_attrib = s->t_attrib_default;
1357
    text_console_resize(s);
1358

    
1359
    qemu_chr_reset(chr);
1360

    
1361
    return chr;
1362
}
1363

    
1364
void qemu_console_resize(DisplayState *ds, int width, int height)
1365
{
1366
    TextConsole *s = get_graphic_console();
1367
    s->g_width = width;
1368
    s->g_height = height;
1369
    if (is_graphic_console()) {
1370
        ds->surface = qemu_resize_displaysurface(ds->surface, width, height, 32, 4 * width);
1371
        dpy_resize(ds);
1372
    }
1373
}
1374

    
1375
void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1376
                       int dst_x, int dst_y, int w, int h)
1377
{
1378
    if (is_graphic_console()) {
1379
        dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1380
    }
1381
}
1382

    
1383
static PixelFormat qemu_default_pixelformat(int bpp)
1384
{
1385
    PixelFormat pf;
1386

    
1387
    memset(&pf, 0x00, sizeof(PixelFormat));
1388

    
1389
    pf.bits_per_pixel = bpp;
1390
    pf.bytes_per_pixel = bpp / 8;
1391
    pf.depth = bpp == 32 ? 24 : bpp;
1392

    
1393
    switch (bpp) {
1394
        case 8:
1395
            pf.rmask = 0x000000E0;
1396
            pf.gmask = 0x0000001C;
1397
            pf.bmask = 0x00000003;
1398
            pf.rmax = 7;
1399
            pf.gmax = 7;
1400
            pf.bmax = 3;
1401
            pf.rshift = 5;
1402
            pf.gshift = 2;
1403
            pf.bshift = 0;
1404
            break;
1405
        case 16:
1406
            pf.rmask = 0x0000F800;
1407
            pf.gmask = 0x000007E0;
1408
            pf.bmask = 0x0000001F;
1409
            pf.rmax = 31;
1410
            pf.gmax = 63;
1411
            pf.bmax = 31;
1412
            pf.rshift = 11;
1413
            pf.gshift = 5;
1414
            pf.bshift = 0;
1415
            break;
1416
        case 24:
1417
        case 32:
1418
            pf.rmask = 0x00FF0000;
1419
            pf.gmask = 0x0000FF00;
1420
            pf.bmask = 0x000000FF;
1421
            pf.rmax = 255;
1422
            pf.gmax = 255;
1423
            pf.bmax = 255;
1424
            pf.rshift = 16;
1425
            pf.gshift = 8;
1426
            pf.bshift = 0;
1427
            break;
1428
        default:
1429
            break;
1430
    }
1431
    return pf;
1432
}
1433

    
1434
DisplaySurface* qemu_create_displaysurface(int width, int height, int bpp, int linesize)
1435
{
1436
    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1437
    if (surface == NULL) {
1438
        fprintf(stderr, "qemu_create_displaysurface: malloc failed\n");
1439
        exit(1);
1440
    }
1441

    
1442
    surface->width = width;
1443
    surface->height = height;
1444
    surface->linesize = linesize;
1445
    surface->pf = qemu_default_pixelformat(bpp);
1446
#ifdef WORDS_BIGENDIAN
1447
    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1448
#else
1449
    surface->flags = QEMU_ALLOCATED_FLAG;
1450
#endif
1451
    surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
1452
    if (surface->data == NULL) {
1453
        fprintf(stderr, "qemu_create_displaysurface: malloc failed\n");
1454
        exit(1);
1455
    }
1456

    
1457
    return surface;
1458
}
1459

    
1460
DisplaySurface* qemu_resize_displaysurface(DisplaySurface *surface,
1461
                                          int width, int height, int bpp, int linesize)
1462
{
1463
    surface->width = width;
1464
    surface->height = height;
1465
    surface->linesize = linesize;
1466
    surface->pf = qemu_default_pixelformat(bpp);
1467
    if (surface->flags & QEMU_ALLOCATED_FLAG)
1468
        surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1469
    else
1470
        surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
1471
    if (surface->data == NULL) {
1472
        fprintf(stderr, "qemu_resize_displaysurface: malloc failed\n");
1473
        exit(1);
1474
    }
1475
#ifdef WORDS_BIGENDIAN
1476
    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1477
#else
1478
    surface->flags = QEMU_ALLOCATED_FLAG;
1479
#endif
1480

    
1481
    return surface;
1482
}
1483

    
1484
DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1485
                                              int linesize, uint8_t *data)
1486
{
1487
    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1488
    if (surface == NULL) {
1489
        fprintf(stderr, "qemu_create_displaysurface_from: malloc failed\n");
1490
        exit(1);
1491
    }
1492

    
1493
    surface->width = width;
1494
    surface->height = height;
1495
    surface->linesize = linesize;
1496
    surface->pf = qemu_default_pixelformat(bpp);
1497
#ifdef WORDS_BIGENDIAN
1498
    surface->flags = QEMU_BIG_ENDIAN_FLAG;
1499
#endif
1500
    surface->data = data;
1501

    
1502
    return surface;
1503
}
1504

    
1505
void qemu_free_displaysurface(DisplaySurface *surface)
1506
{
1507
    if (surface == NULL)
1508
        return;
1509
    if (surface->flags & QEMU_ALLOCATED_FLAG)
1510
        qemu_free(surface->data);
1511
    qemu_free(surface);
1512
}