Statistics
| Branch: | Revision:

root / ui / console.c @ feature-archipelago

History | View | Annotate | Download (53.6 kB)

1 e7f0ad58 bellard
/*
2 e7f0ad58 bellard
 * QEMU graphical console
3 5fafdf24 ths
 *
4 e7f0ad58 bellard
 * Copyright (c) 2004 Fabrice Bellard
5 5fafdf24 ths
 *
6 e7f0ad58 bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 e7f0ad58 bellard
 * of this software and associated documentation files (the "Software"), to deal
8 e7f0ad58 bellard
 * in the Software without restriction, including without limitation the rights
9 e7f0ad58 bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 e7f0ad58 bellard
 * copies of the Software, and to permit persons to whom the Software is
11 e7f0ad58 bellard
 * furnished to do so, subject to the following conditions:
12 e7f0ad58 bellard
 *
13 e7f0ad58 bellard
 * The above copyright notice and this permission notice shall be included in
14 e7f0ad58 bellard
 * all copies or substantial portions of the Software.
15 e7f0ad58 bellard
 *
16 e7f0ad58 bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 e7f0ad58 bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 e7f0ad58 bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 e7f0ad58 bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 e7f0ad58 bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 e7f0ad58 bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 e7f0ad58 bellard
 * THE SOFTWARE.
23 e7f0ad58 bellard
 */
24 87ecb68b pbrook
#include "qemu-common.h"
25 28ecbaee Paolo Bonzini
#include "ui/console.h"
26 aa2beaa1 Gerd Hoffmann
#include "hw/qdev-core.h"
27 1de7afc9 Paolo Bonzini
#include "qemu/timer.h"
28 ad39cf6d Luiz Capitulino
#include "qmp-commands.h"
29 dccfcd0e Paolo Bonzini
#include "sysemu/char.h"
30 ac86048b Stefan Weil
#include "trace.h"
31 e7f0ad58 bellard
32 e7f0ad58 bellard
#define DEFAULT_BACKSCROLL 512
33 e7f0ad58 bellard
#define MAX_CONSOLES 12
34 bf1bed81 Jan Kiszka
#define CONSOLE_CURSOR_PERIOD 500
35 e7f0ad58 bellard
36 6d6f7c28 pbrook
typedef struct TextAttributes {
37 6d6f7c28 pbrook
    uint8_t fgcol:4;
38 6d6f7c28 pbrook
    uint8_t bgcol:4;
39 6d6f7c28 pbrook
    uint8_t bold:1;
40 6d6f7c28 pbrook
    uint8_t uline:1;
41 6d6f7c28 pbrook
    uint8_t blink:1;
42 6d6f7c28 pbrook
    uint8_t invers:1;
43 6d6f7c28 pbrook
    uint8_t unvisible:1;
44 6d6f7c28 pbrook
} TextAttributes;
45 6d6f7c28 pbrook
46 e7f0ad58 bellard
typedef struct TextCell {
47 e7f0ad58 bellard
    uint8_t ch;
48 6d6f7c28 pbrook
    TextAttributes t_attrib;
49 e7f0ad58 bellard
} TextCell;
50 e7f0ad58 bellard
51 e7f0ad58 bellard
#define MAX_ESC_PARAMS 3
52 e7f0ad58 bellard
53 e7f0ad58 bellard
enum TTYState {
54 e7f0ad58 bellard
    TTY_STATE_NORM,
55 e7f0ad58 bellard
    TTY_STATE_ESC,
56 e7f0ad58 bellard
    TTY_STATE_CSI,
57 e7f0ad58 bellard
};
58 e7f0ad58 bellard
59 e15d7371 bellard
typedef struct QEMUFIFO {
60 e15d7371 bellard
    uint8_t *buf;
61 e15d7371 bellard
    int buf_size;
62 e15d7371 bellard
    int count, wptr, rptr;
63 e15d7371 bellard
} QEMUFIFO;
64 e15d7371 bellard
65 9596ebb7 pbrook
static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
66 e15d7371 bellard
{
67 e15d7371 bellard
    int l, len;
68 e15d7371 bellard
69 e15d7371 bellard
    l = f->buf_size - f->count;
70 e15d7371 bellard
    if (len1 > l)
71 e15d7371 bellard
        len1 = l;
72 e15d7371 bellard
    len = len1;
73 e15d7371 bellard
    while (len > 0) {
74 e15d7371 bellard
        l = f->buf_size - f->wptr;
75 e15d7371 bellard
        if (l > len)
76 e15d7371 bellard
            l = len;
77 e15d7371 bellard
        memcpy(f->buf + f->wptr, buf, l);
78 e15d7371 bellard
        f->wptr += l;
79 e15d7371 bellard
        if (f->wptr >= f->buf_size)
80 e15d7371 bellard
            f->wptr = 0;
81 e15d7371 bellard
        buf += l;
82 e15d7371 bellard
        len -= l;
83 e15d7371 bellard
    }
84 e15d7371 bellard
    f->count += len1;
85 e15d7371 bellard
    return len1;
86 e15d7371 bellard
}
87 e15d7371 bellard
88 9596ebb7 pbrook
static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
89 e15d7371 bellard
{
90 e15d7371 bellard
    int l, len;
91 e15d7371 bellard
92 e15d7371 bellard
    if (len1 > f->count)
93 e15d7371 bellard
        len1 = f->count;
94 e15d7371 bellard
    len = len1;
95 e15d7371 bellard
    while (len > 0) {
96 e15d7371 bellard
        l = f->buf_size - f->rptr;
97 e15d7371 bellard
        if (l > len)
98 e15d7371 bellard
            l = len;
99 e15d7371 bellard
        memcpy(buf, f->buf + f->rptr, l);
100 e15d7371 bellard
        f->rptr += l;
101 e15d7371 bellard
        if (f->rptr >= f->buf_size)
102 e15d7371 bellard
            f->rptr = 0;
103 e15d7371 bellard
        buf += l;
104 e15d7371 bellard
        len -= l;
105 e15d7371 bellard
    }
106 e15d7371 bellard
    f->count -= len1;
107 e15d7371 bellard
    return len1;
108 e15d7371 bellard
}
109 e15d7371 bellard
110 af3a9031 ths
typedef enum {
111 af3a9031 ths
    GRAPHIC_CONSOLE,
112 c21bbcfa balrog
    TEXT_CONSOLE,
113 c21bbcfa balrog
    TEXT_CONSOLE_FIXED_SIZE
114 c227f099 Anthony Liguori
} console_type_t;
115 af3a9031 ths
116 76ffb0b4 Gerd Hoffmann
struct QemuConsole {
117 95be0669 Gerd Hoffmann
    Object parent;
118 95be0669 Gerd Hoffmann
119 f81bdefb Jan Kiszka
    int index;
120 c227f099 Anthony Liguori
    console_type_t console_type;
121 e7f0ad58 bellard
    DisplayState *ds;
122 321f048d Gerd Hoffmann
    DisplaySurface *surface;
123 284d1c6b Gerd Hoffmann
    int dcls;
124 76ffb0b4 Gerd Hoffmann
125 95219897 pbrook
    /* Graphic console state.  */
126 aa2beaa1 Gerd Hoffmann
    Object *device;
127 380cd056 Gerd Hoffmann
    const GraphicHwOps *hw_ops;
128 95219897 pbrook
    void *hw;
129 76ffb0b4 Gerd Hoffmann
130 76ffb0b4 Gerd Hoffmann
    /* Text console state */
131 e7f0ad58 bellard
    int width;
132 e7f0ad58 bellard
    int height;
133 e7f0ad58 bellard
    int total_height;
134 e7f0ad58 bellard
    int backscroll_height;
135 e7f0ad58 bellard
    int x, y;
136 adb47967 ths
    int x_saved, y_saved;
137 e7f0ad58 bellard
    int y_displayed;
138 e7f0ad58 bellard
    int y_base;
139 6d6f7c28 pbrook
    TextAttributes t_attrib_default; /* default text attributes */
140 6d6f7c28 pbrook
    TextAttributes t_attrib; /* currently active text attributes */
141 e7f0ad58 bellard
    TextCell *cells;
142 4d3b6f6e balrog
    int text_x[2], text_y[2], cursor_invalidate;
143 4104833f Paolo Bonzini
    int echo;
144 bf1bed81 Jan Kiszka
    bool cursor_visible_phase;
145 bf1bed81 Jan Kiszka
    QEMUTimer *cursor_timer;
146 e7f0ad58 bellard
147 14778c20 pbrook
    int update_x0;
148 14778c20 pbrook
    int update_y0;
149 14778c20 pbrook
    int update_x1;
150 14778c20 pbrook
    int update_y1;
151 14778c20 pbrook
152 e7f0ad58 bellard
    enum TTYState state;
153 e7f0ad58 bellard
    int esc_params[MAX_ESC_PARAMS];
154 e7f0ad58 bellard
    int nb_esc_params;
155 e7f0ad58 bellard
156 e5b0bc44 pbrook
    CharDriverState *chr;
157 e15d7371 bellard
    /* fifo for key pressed */
158 e15d7371 bellard
    QEMUFIFO out_fifo;
159 e15d7371 bellard
    uint8_t out_fifo_buf[16];
160 e15d7371 bellard
    QEMUTimer *kbd_timer;
161 e7f0ad58 bellard
};
162 e7f0ad58 bellard
163 27be5587 Gerd Hoffmann
struct DisplayState {
164 1246b259 Stefan Weil
    QEMUTimer *gui_timer;
165 0f7b2864 Gerd Hoffmann
    uint64_t last_update;
166 0f7b2864 Gerd Hoffmann
    uint64_t update_interval;
167 0f7b2864 Gerd Hoffmann
    bool refreshing;
168 27be5587 Gerd Hoffmann
    bool have_gfx;
169 27be5587 Gerd Hoffmann
    bool have_text;
170 27be5587 Gerd Hoffmann
171 27be5587 Gerd Hoffmann
    QLIST_HEAD(, DisplayChangeListener) listeners;
172 27be5587 Gerd Hoffmann
};
173 27be5587 Gerd Hoffmann
174 98b50080 Paolo Bonzini
static DisplayState *display_state;
175 76ffb0b4 Gerd Hoffmann
static QemuConsole *active_console;
176 76ffb0b4 Gerd Hoffmann
static QemuConsole *consoles[MAX_CONSOLES];
177 e7f0ad58 bellard
static int nb_consoles = 0;
178 e7f0ad58 bellard
179 64840c66 Gerd Hoffmann
static void text_console_do_init(CharDriverState *chr, DisplayState *ds);
180 0f7b2864 Gerd Hoffmann
static void dpy_refresh(DisplayState *s);
181 5209089f Gerd Hoffmann
static DisplayState *get_alloc_displaystate(void);
182 64840c66 Gerd Hoffmann
183 98a9ad90 Gerd Hoffmann
static void gui_update(void *opaque)
184 98a9ad90 Gerd Hoffmann
{
185 0f7b2864 Gerd Hoffmann
    uint64_t interval = GUI_REFRESH_INTERVAL_IDLE;
186 0f7b2864 Gerd Hoffmann
    uint64_t dcl_interval;
187 98a9ad90 Gerd Hoffmann
    DisplayState *ds = opaque;
188 98a9ad90 Gerd Hoffmann
    DisplayChangeListener *dcl;
189 dea1b0bd Gerd Hoffmann
    int i;
190 98a9ad90 Gerd Hoffmann
191 0f7b2864 Gerd Hoffmann
    ds->refreshing = true;
192 98a9ad90 Gerd Hoffmann
    dpy_refresh(ds);
193 0f7b2864 Gerd Hoffmann
    ds->refreshing = false;
194 98a9ad90 Gerd Hoffmann
195 98a9ad90 Gerd Hoffmann
    QLIST_FOREACH(dcl, &ds->listeners, next) {
196 0f7b2864 Gerd Hoffmann
        dcl_interval = dcl->update_interval ?
197 0f7b2864 Gerd Hoffmann
            dcl->update_interval : GUI_REFRESH_INTERVAL_DEFAULT;
198 0f7b2864 Gerd Hoffmann
        if (interval > dcl_interval) {
199 0f7b2864 Gerd Hoffmann
            interval = dcl_interval;
200 98a9ad90 Gerd Hoffmann
        }
201 98a9ad90 Gerd Hoffmann
    }
202 0f7b2864 Gerd Hoffmann
    if (ds->update_interval != interval) {
203 0f7b2864 Gerd Hoffmann
        ds->update_interval = interval;
204 dea1b0bd Gerd Hoffmann
        for (i = 0; i < nb_consoles; i++) {
205 dea1b0bd Gerd Hoffmann
            if (consoles[i]->hw_ops->update_interval) {
206 dea1b0bd Gerd Hoffmann
                consoles[i]->hw_ops->update_interval(consoles[i]->hw, interval);
207 dea1b0bd Gerd Hoffmann
            }
208 dea1b0bd Gerd Hoffmann
        }
209 0f7b2864 Gerd Hoffmann
        trace_console_refresh(interval);
210 0f7b2864 Gerd Hoffmann
    }
211 bc72ad67 Alex Bligh
    ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
212 bc72ad67 Alex Bligh
    timer_mod(ds->gui_timer, ds->last_update + interval);
213 98a9ad90 Gerd Hoffmann
}
214 98a9ad90 Gerd Hoffmann
215 98a9ad90 Gerd Hoffmann
static void gui_setup_refresh(DisplayState *ds)
216 98a9ad90 Gerd Hoffmann
{
217 98a9ad90 Gerd Hoffmann
    DisplayChangeListener *dcl;
218 98a9ad90 Gerd Hoffmann
    bool need_timer = false;
219 98a9ad90 Gerd Hoffmann
    bool have_gfx = false;
220 98a9ad90 Gerd Hoffmann
    bool have_text = false;
221 98a9ad90 Gerd Hoffmann
222 98a9ad90 Gerd Hoffmann
    QLIST_FOREACH(dcl, &ds->listeners, next) {
223 98a9ad90 Gerd Hoffmann
        if (dcl->ops->dpy_refresh != NULL) {
224 98a9ad90 Gerd Hoffmann
            need_timer = true;
225 98a9ad90 Gerd Hoffmann
        }
226 98a9ad90 Gerd Hoffmann
        if (dcl->ops->dpy_gfx_update != NULL) {
227 98a9ad90 Gerd Hoffmann
            have_gfx = true;
228 98a9ad90 Gerd Hoffmann
        }
229 98a9ad90 Gerd Hoffmann
        if (dcl->ops->dpy_text_update != NULL) {
230 98a9ad90 Gerd Hoffmann
            have_text = true;
231 98a9ad90 Gerd Hoffmann
        }
232 98a9ad90 Gerd Hoffmann
    }
233 98a9ad90 Gerd Hoffmann
234 98a9ad90 Gerd Hoffmann
    if (need_timer && ds->gui_timer == NULL) {
235 bc72ad67 Alex Bligh
        ds->gui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, gui_update, ds);
236 bc72ad67 Alex Bligh
        timer_mod(ds->gui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
237 98a9ad90 Gerd Hoffmann
    }
238 98a9ad90 Gerd Hoffmann
    if (!need_timer && ds->gui_timer != NULL) {
239 bc72ad67 Alex Bligh
        timer_del(ds->gui_timer);
240 bc72ad67 Alex Bligh
        timer_free(ds->gui_timer);
241 98a9ad90 Gerd Hoffmann
        ds->gui_timer = NULL;
242 98a9ad90 Gerd Hoffmann
    }
243 98a9ad90 Gerd Hoffmann
244 98a9ad90 Gerd Hoffmann
    ds->have_gfx = have_gfx;
245 98a9ad90 Gerd Hoffmann
    ds->have_text = have_text;
246 98a9ad90 Gerd Hoffmann
}
247 98a9ad90 Gerd Hoffmann
248 1dbfa005 Gerd Hoffmann
void graphic_hw_update(QemuConsole *con)
249 95219897 pbrook
{
250 1dbfa005 Gerd Hoffmann
    if (!con) {
251 1dbfa005 Gerd Hoffmann
        con = active_console;
252 1dbfa005 Gerd Hoffmann
    }
253 380cd056 Gerd Hoffmann
    if (con && con->hw_ops->gfx_update) {
254 380cd056 Gerd Hoffmann
        con->hw_ops->gfx_update(con->hw);
255 1dbfa005 Gerd Hoffmann
    }
256 95219897 pbrook
}
257 95219897 pbrook
258 1dbfa005 Gerd Hoffmann
void graphic_hw_invalidate(QemuConsole *con)
259 95219897 pbrook
{
260 1dbfa005 Gerd Hoffmann
    if (!con) {
261 1dbfa005 Gerd Hoffmann
        con = active_console;
262 1dbfa005 Gerd Hoffmann
    }
263 380cd056 Gerd Hoffmann
    if (con && con->hw_ops->invalidate) {
264 380cd056 Gerd Hoffmann
        con->hw_ops->invalidate(con->hw);
265 1dbfa005 Gerd Hoffmann
    }
266 95219897 pbrook
}
267 95219897 pbrook
268 2c62f08d Gerd Hoffmann
static void ppm_save(const char *filename, struct DisplaySurface *ds,
269 2c62f08d Gerd Hoffmann
                     Error **errp)
270 95219897 pbrook
{
271 2c62f08d Gerd Hoffmann
    int width = pixman_image_get_width(ds->image);
272 2c62f08d Gerd Hoffmann
    int height = pixman_image_get_height(ds->image);
273 cdd5b937 Gerd Hoffmann
    int fd;
274 2c62f08d Gerd Hoffmann
    FILE *f;
275 2c62f08d Gerd Hoffmann
    int y;
276 2c62f08d Gerd Hoffmann
    int ret;
277 2c62f08d Gerd Hoffmann
    pixman_image_t *linebuf;
278 2c62f08d Gerd Hoffmann
279 2c62f08d Gerd Hoffmann
    trace_ppm_save(filename, ds);
280 cdd5b937 Gerd Hoffmann
    fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
281 cdd5b937 Gerd Hoffmann
    if (fd == -1) {
282 2c62f08d Gerd Hoffmann
        error_setg(errp, "failed to open file '%s': %s", filename,
283 2c62f08d Gerd Hoffmann
                   strerror(errno));
284 2c62f08d Gerd Hoffmann
        return;
285 45efb161 Gerd Hoffmann
    }
286 cdd5b937 Gerd Hoffmann
    f = fdopen(fd, "wb");
287 2c62f08d Gerd Hoffmann
    ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255);
288 2c62f08d Gerd Hoffmann
    if (ret < 0) {
289 2c62f08d Gerd Hoffmann
        linebuf = NULL;
290 2c62f08d Gerd Hoffmann
        goto write_err;
291 2c62f08d Gerd Hoffmann
    }
292 2c62f08d Gerd Hoffmann
    linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
293 2c62f08d Gerd Hoffmann
    for (y = 0; y < height; y++) {
294 2c62f08d Gerd Hoffmann
        qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y);
295 2c62f08d Gerd Hoffmann
        clearerr(f);
296 2c62f08d Gerd Hoffmann
        ret = fwrite(pixman_image_get_data(linebuf), 1,
297 2c62f08d Gerd Hoffmann
                     pixman_image_get_stride(linebuf), f);
298 2c62f08d Gerd Hoffmann
        (void)ret;
299 2c62f08d Gerd Hoffmann
        if (ferror(f)) {
300 2c62f08d Gerd Hoffmann
            goto write_err;
301 2c62f08d Gerd Hoffmann
        }
302 f81bdefb Jan Kiszka
    }
303 f81bdefb Jan Kiszka
304 2c62f08d Gerd Hoffmann
out:
305 2c62f08d Gerd Hoffmann
    qemu_pixman_image_unref(linebuf);
306 2c62f08d Gerd Hoffmann
    fclose(f);
307 2c62f08d Gerd Hoffmann
    return;
308 2c62f08d Gerd Hoffmann
309 2c62f08d Gerd Hoffmann
write_err:
310 2c62f08d Gerd Hoffmann
    error_setg(errp, "failed to write to file '%s': %s", filename,
311 2c62f08d Gerd Hoffmann
               strerror(errno));
312 2c62f08d Gerd Hoffmann
    unlink(filename);
313 2c62f08d Gerd Hoffmann
    goto out;
314 2c62f08d Gerd Hoffmann
}
315 2c62f08d Gerd Hoffmann
316 2c62f08d Gerd Hoffmann
void qmp_screendump(const char *filename, Error **errp)
317 2c62f08d Gerd Hoffmann
{
318 284d1c6b Gerd Hoffmann
    QemuConsole *con = qemu_console_lookup_by_index(0);
319 2c62f08d Gerd Hoffmann
    DisplaySurface *surface;
320 2c62f08d Gerd Hoffmann
321 2c62f08d Gerd Hoffmann
    if (con == NULL) {
322 2c62f08d Gerd Hoffmann
        error_setg(errp, "There is no QemuConsole I can screendump from.");
323 2c62f08d Gerd Hoffmann
        return;
324 33bcd98c Alexander Graf
    }
325 2c62f08d Gerd Hoffmann
326 2c62f08d Gerd Hoffmann
    graphic_hw_update(con);
327 2c62f08d Gerd Hoffmann
    surface = qemu_console_surface(con);
328 2c62f08d Gerd Hoffmann
    ppm_save(filename, surface, errp);
329 95219897 pbrook
}
330 95219897 pbrook
331 1dbfa005 Gerd Hoffmann
void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
332 4d3b6f6e balrog
{
333 1dbfa005 Gerd Hoffmann
    if (!con) {
334 1dbfa005 Gerd Hoffmann
        con = active_console;
335 1dbfa005 Gerd Hoffmann
    }
336 380cd056 Gerd Hoffmann
    if (con && con->hw_ops->text_update) {
337 380cd056 Gerd Hoffmann
        con->hw_ops->text_update(con->hw, chardata);
338 380cd056 Gerd Hoffmann
    }
339 4d3b6f6e balrog
}
340 4d3b6f6e balrog
341 1562e531 Gerd Hoffmann
static void vga_fill_rect(QemuConsole *con,
342 1562e531 Gerd Hoffmann
                          int posx, int posy, int width, int height,
343 e27bd65a Gerd Hoffmann
                          pixman_color_t color)
344 e7f0ad58 bellard
{
345 1562e531 Gerd Hoffmann
    DisplaySurface *surface = qemu_console_surface(con);
346 68db6dc5 Gerd Hoffmann
    pixman_rectangle16_t rect = {
347 68db6dc5 Gerd Hoffmann
        .x = posx, .y = posy, .width = width, .height = height
348 68db6dc5 Gerd Hoffmann
    };
349 68db6dc5 Gerd Hoffmann
350 68db6dc5 Gerd Hoffmann
    pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image,
351 e27bd65a Gerd Hoffmann
                                 &color, 1, &rect);
352 e7f0ad58 bellard
}
353 e7f0ad58 bellard
354 e7f0ad58 bellard
/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
355 1562e531 Gerd Hoffmann
static void vga_bitblt(QemuConsole *con,
356 1562e531 Gerd Hoffmann
                       int xs, int ys, int xd, int yd, int w, int h)
357 e7f0ad58 bellard
{
358 1562e531 Gerd Hoffmann
    DisplaySurface *surface = qemu_console_surface(con);
359 68db6dc5 Gerd Hoffmann
360 68db6dc5 Gerd Hoffmann
    pixman_image_composite(PIXMAN_OP_SRC,
361 68db6dc5 Gerd Hoffmann
                           surface->image, NULL, surface->image,
362 68db6dc5 Gerd Hoffmann
                           xs, ys, 0, 0, xd, yd, w, h);
363 e7f0ad58 bellard
}
364 e7f0ad58 bellard
365 e7f0ad58 bellard
/***********************************************************/
366 e7f0ad58 bellard
/* basic char display */
367 e7f0ad58 bellard
368 e7f0ad58 bellard
#define FONT_HEIGHT 16
369 e7f0ad58 bellard
#define FONT_WIDTH 8
370 e7f0ad58 bellard
371 e7f0ad58 bellard
#include "vgafont.h"
372 e7f0ad58 bellard
373 df00bed0 Devin J. Pohly
#ifndef CONFIG_CURSES
374 6d6f7c28 pbrook
enum color_names {
375 6d6f7c28 pbrook
    COLOR_BLACK   = 0,
376 6d6f7c28 pbrook
    COLOR_RED     = 1,
377 6d6f7c28 pbrook
    COLOR_GREEN   = 2,
378 6d6f7c28 pbrook
    COLOR_YELLOW  = 3,
379 6d6f7c28 pbrook
    COLOR_BLUE    = 4,
380 6d6f7c28 pbrook
    COLOR_MAGENTA = 5,
381 6d6f7c28 pbrook
    COLOR_CYAN    = 6,
382 6d6f7c28 pbrook
    COLOR_WHITE   = 7
383 6d6f7c28 pbrook
};
384 df00bed0 Devin J. Pohly
#endif
385 6d6f7c28 pbrook
386 e27bd65a Gerd Hoffmann
#define QEMU_RGB(r, g, b)                                               \
387 e27bd65a Gerd Hoffmann
    { .red = r << 8, .green = g << 8, .blue = b << 8, .alpha = 0xffff }
388 e27bd65a Gerd Hoffmann
389 e27bd65a Gerd Hoffmann
static const pixman_color_t color_table_rgb[2][8] = {
390 6d6f7c28 pbrook
    {   /* dark */
391 26489844 bellard
        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
392 26489844 bellard
        QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
393 26489844 bellard
        QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
394 26489844 bellard
        QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
395 26489844 bellard
        QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
396 26489844 bellard
        QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
397 26489844 bellard
        QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
398 26489844 bellard
        QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
399 6d6f7c28 pbrook
    },
400 6d6f7c28 pbrook
    {   /* bright */
401 26489844 bellard
        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
402 26489844 bellard
        QEMU_RGB(0xff, 0x00, 0x00),  /* red */
403 26489844 bellard
        QEMU_RGB(0x00, 0xff, 0x00),  /* green */
404 26489844 bellard
        QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
405 26489844 bellard
        QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
406 26489844 bellard
        QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
407 26489844 bellard
        QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
408 26489844 bellard
        QEMU_RGB(0xff, 0xff, 0xff),  /* white */
409 6d6f7c28 pbrook
    }
410 e7f0ad58 bellard
};
411 e7f0ad58 bellard
412 1562e531 Gerd Hoffmann
static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
413 6d6f7c28 pbrook
                          TextAttributes *t_attrib)
414 e7f0ad58 bellard
{
415 7d6ba01c Gerd Hoffmann
    static pixman_image_t *glyphs[256];
416 1562e531 Gerd Hoffmann
    DisplaySurface *surface = qemu_console_surface(s);
417 e27bd65a Gerd Hoffmann
    pixman_color_t fgcol, bgcol;
418 6d6f7c28 pbrook
419 6d6f7c28 pbrook
    if (t_attrib->invers) {
420 cf6f0548 Gerd Hoffmann
        bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
421 cf6f0548 Gerd Hoffmann
        fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
422 6d6f7c28 pbrook
    } else {
423 cf6f0548 Gerd Hoffmann
        fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
424 cf6f0548 Gerd Hoffmann
        bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
425 6d6f7c28 pbrook
    }
426 e7f0ad58 bellard
427 7d6ba01c Gerd Hoffmann
    if (!glyphs[ch]) {
428 7d6ba01c Gerd Hoffmann
        glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch);
429 e7f0ad58 bellard
    }
430 7d6ba01c Gerd Hoffmann
    qemu_pixman_glyph_render(glyphs[ch], surface->image,
431 e27bd65a Gerd Hoffmann
                             &fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
432 e7f0ad58 bellard
}
433 e7f0ad58 bellard
434 76ffb0b4 Gerd Hoffmann
static void text_console_resize(QemuConsole *s)
435 e7f0ad58 bellard
{
436 e7f0ad58 bellard
    TextCell *cells, *c, *c1;
437 e7f0ad58 bellard
    int w1, x, y, last_width;
438 e7f0ad58 bellard
439 e7f0ad58 bellard
    last_width = s->width;
440 36671fbd Gerd Hoffmann
    s->width = surface_width(s->surface) / FONT_WIDTH;
441 36671fbd Gerd Hoffmann
    s->height = surface_height(s->surface) / FONT_HEIGHT;
442 e7f0ad58 bellard
443 e7f0ad58 bellard
    w1 = last_width;
444 e7f0ad58 bellard
    if (s->width < w1)
445 e7f0ad58 bellard
        w1 = s->width;
446 e7f0ad58 bellard
447 7267c094 Anthony Liguori
    cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
448 e7f0ad58 bellard
    for(y = 0; y < s->total_height; y++) {
449 e7f0ad58 bellard
        c = &cells[y * s->width];
450 e7f0ad58 bellard
        if (w1 > 0) {
451 e7f0ad58 bellard
            c1 = &s->cells[y * last_width];
452 e7f0ad58 bellard
            for(x = 0; x < w1; x++) {
453 e7f0ad58 bellard
                *c++ = *c1++;
454 e7f0ad58 bellard
            }
455 e7f0ad58 bellard
        }
456 e7f0ad58 bellard
        for(x = w1; x < s->width; x++) {
457 e7f0ad58 bellard
            c->ch = ' ';
458 6d6f7c28 pbrook
            c->t_attrib = s->t_attrib_default;
459 e7f0ad58 bellard
            c++;
460 e7f0ad58 bellard
        }
461 e7f0ad58 bellard
    }
462 7267c094 Anthony Liguori
    g_free(s->cells);
463 e7f0ad58 bellard
    s->cells = cells;
464 e7f0ad58 bellard
}
465 e7f0ad58 bellard
466 76ffb0b4 Gerd Hoffmann
static inline void text_update_xy(QemuConsole *s, int x, int y)
467 4d3b6f6e balrog
{
468 4d3b6f6e balrog
    s->text_x[0] = MIN(s->text_x[0], x);
469 4d3b6f6e balrog
    s->text_x[1] = MAX(s->text_x[1], x);
470 4d3b6f6e balrog
    s->text_y[0] = MIN(s->text_y[0], y);
471 4d3b6f6e balrog
    s->text_y[1] = MAX(s->text_y[1], y);
472 4d3b6f6e balrog
}
473 4d3b6f6e balrog
474 76ffb0b4 Gerd Hoffmann
static void invalidate_xy(QemuConsole *s, int x, int y)
475 14778c20 pbrook
{
476 14778c20 pbrook
    if (s->update_x0 > x * FONT_WIDTH)
477 14778c20 pbrook
        s->update_x0 = x * FONT_WIDTH;
478 14778c20 pbrook
    if (s->update_y0 > y * FONT_HEIGHT)
479 14778c20 pbrook
        s->update_y0 = y * FONT_HEIGHT;
480 14778c20 pbrook
    if (s->update_x1 < (x + 1) * FONT_WIDTH)
481 14778c20 pbrook
        s->update_x1 = (x + 1) * FONT_WIDTH;
482 14778c20 pbrook
    if (s->update_y1 < (y + 1) * FONT_HEIGHT)
483 14778c20 pbrook
        s->update_y1 = (y + 1) * FONT_HEIGHT;
484 14778c20 pbrook
}
485 14778c20 pbrook
486 76ffb0b4 Gerd Hoffmann
static void update_xy(QemuConsole *s, int x, int y)
487 e7f0ad58 bellard
{
488 e7f0ad58 bellard
    TextCell *c;
489 e7f0ad58 bellard
    int y1, y2;
490 e7f0ad58 bellard
491 81c0d5a6 Gerd Hoffmann
    if (!qemu_console_is_visible(s)) {
492 1562e531 Gerd Hoffmann
        return;
493 1562e531 Gerd Hoffmann
    }
494 1562e531 Gerd Hoffmann
495 1562e531 Gerd Hoffmann
    if (s->ds->have_text) {
496 1562e531 Gerd Hoffmann
        text_update_xy(s, x, y);
497 1562e531 Gerd Hoffmann
    }
498 4d3b6f6e balrog
499 1562e531 Gerd Hoffmann
    if (s->ds->have_gfx) {
500 e7f0ad58 bellard
        y1 = (s->y_base + y) % s->total_height;
501 e7f0ad58 bellard
        y2 = y1 - s->y_displayed;
502 e7f0ad58 bellard
        if (y2 < 0)
503 e7f0ad58 bellard
            y2 += s->total_height;
504 e7f0ad58 bellard
        if (y2 < s->height) {
505 e7f0ad58 bellard
            c = &s->cells[y1 * s->width + x];
506 1562e531 Gerd Hoffmann
            vga_putcharxy(s, x, y2, c->ch,
507 6d6f7c28 pbrook
                          &(c->t_attrib));
508 14778c20 pbrook
            invalidate_xy(s, x, y2);
509 e7f0ad58 bellard
        }
510 e7f0ad58 bellard
    }
511 e7f0ad58 bellard
}
512 e7f0ad58 bellard
513 76ffb0b4 Gerd Hoffmann
static void console_show_cursor(QemuConsole *s, int show)
514 e7f0ad58 bellard
{
515 e7f0ad58 bellard
    TextCell *c;
516 e7f0ad58 bellard
    int y, y1;
517 1562e531 Gerd Hoffmann
    int x = s->x;
518 e7f0ad58 bellard
519 81c0d5a6 Gerd Hoffmann
    if (!qemu_console_is_visible(s)) {
520 1562e531 Gerd Hoffmann
        return;
521 1562e531 Gerd Hoffmann
    }
522 4d3b6f6e balrog
523 1562e531 Gerd Hoffmann
    if (s->ds->have_text) {
524 1562e531 Gerd Hoffmann
        s->cursor_invalidate = 1;
525 1562e531 Gerd Hoffmann
    }
526 4d3b6f6e balrog
527 1562e531 Gerd Hoffmann
    if (s->ds->have_gfx) {
528 ed8276ac ths
        if (x >= s->width) {
529 ed8276ac ths
            x = s->width - 1;
530 ed8276ac ths
        }
531 e7f0ad58 bellard
        y1 = (s->y_base + s->y) % s->total_height;
532 e7f0ad58 bellard
        y = y1 - s->y_displayed;
533 e7f0ad58 bellard
        if (y < 0)
534 e7f0ad58 bellard
            y += s->total_height;
535 e7f0ad58 bellard
        if (y < s->height) {
536 ed8276ac ths
            c = &s->cells[y1 * s->width + x];
537 bf1bed81 Jan Kiszka
            if (show && s->cursor_visible_phase) {
538 6d6f7c28 pbrook
                TextAttributes t_attrib = s->t_attrib_default;
539 6d6f7c28 pbrook
                t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
540 1562e531 Gerd Hoffmann
                vga_putcharxy(s, x, y, c->ch, &t_attrib);
541 e7f0ad58 bellard
            } else {
542 1562e531 Gerd Hoffmann
                vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
543 e7f0ad58 bellard
            }
544 14778c20 pbrook
            invalidate_xy(s, x, y);
545 e7f0ad58 bellard
        }
546 e7f0ad58 bellard
    }
547 e7f0ad58 bellard
}
548 e7f0ad58 bellard
549 76ffb0b4 Gerd Hoffmann
static void console_refresh(QemuConsole *s)
550 e7f0ad58 bellard
{
551 1562e531 Gerd Hoffmann
    DisplaySurface *surface = qemu_console_surface(s);
552 e7f0ad58 bellard
    TextCell *c;
553 e7f0ad58 bellard
    int x, y, y1;
554 e7f0ad58 bellard
555 81c0d5a6 Gerd Hoffmann
    if (!qemu_console_is_visible(s)) {
556 e7f0ad58 bellard
        return;
557 81c0d5a6 Gerd Hoffmann
    }
558 a93a4a22 Gerd Hoffmann
559 a93a4a22 Gerd Hoffmann
    if (s->ds->have_text) {
560 4d3b6f6e balrog
        s->text_x[0] = 0;
561 4d3b6f6e balrog
        s->text_y[0] = 0;
562 4d3b6f6e balrog
        s->text_x[1] = s->width - 1;
563 4d3b6f6e balrog
        s->text_y[1] = s->height - 1;
564 4d3b6f6e balrog
        s->cursor_invalidate = 1;
565 4d3b6f6e balrog
    }
566 e7f0ad58 bellard
567 a93a4a22 Gerd Hoffmann
    if (s->ds->have_gfx) {
568 1562e531 Gerd Hoffmann
        vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
569 cf6f0548 Gerd Hoffmann
                      color_table_rgb[0][COLOR_BLACK]);
570 a93a4a22 Gerd Hoffmann
        y1 = s->y_displayed;
571 a93a4a22 Gerd Hoffmann
        for (y = 0; y < s->height; y++) {
572 a93a4a22 Gerd Hoffmann
            c = s->cells + y1 * s->width;
573 a93a4a22 Gerd Hoffmann
            for (x = 0; x < s->width; x++) {
574 1562e531 Gerd Hoffmann
                vga_putcharxy(s, x, y, c->ch,
575 a93a4a22 Gerd Hoffmann
                              &(c->t_attrib));
576 a93a4a22 Gerd Hoffmann
                c++;
577 a93a4a22 Gerd Hoffmann
            }
578 a93a4a22 Gerd Hoffmann
            if (++y1 == s->total_height) {
579 a93a4a22 Gerd Hoffmann
                y1 = 0;
580 a93a4a22 Gerd Hoffmann
            }
581 e7f0ad58 bellard
        }
582 a93a4a22 Gerd Hoffmann
        console_show_cursor(s, 1);
583 1562e531 Gerd Hoffmann
        dpy_gfx_update(s, 0, 0,
584 1562e531 Gerd Hoffmann
                       surface_width(surface), surface_height(surface));
585 e7f0ad58 bellard
    }
586 e7f0ad58 bellard
}
587 e7f0ad58 bellard
588 81c0d5a6 Gerd Hoffmann
static void console_scroll(QemuConsole *s, int ydelta)
589 e7f0ad58 bellard
{
590 e7f0ad58 bellard
    int i, y1;
591 3b46e624 ths
592 e7f0ad58 bellard
    if (ydelta > 0) {
593 e7f0ad58 bellard
        for(i = 0; i < ydelta; i++) {
594 e7f0ad58 bellard
            if (s->y_displayed == s->y_base)
595 e7f0ad58 bellard
                break;
596 e7f0ad58 bellard
            if (++s->y_displayed == s->total_height)
597 e7f0ad58 bellard
                s->y_displayed = 0;
598 e7f0ad58 bellard
        }
599 e7f0ad58 bellard
    } else {
600 e7f0ad58 bellard
        ydelta = -ydelta;
601 e7f0ad58 bellard
        i = s->backscroll_height;
602 e7f0ad58 bellard
        if (i > s->total_height - s->height)
603 e7f0ad58 bellard
            i = s->total_height - s->height;
604 e7f0ad58 bellard
        y1 = s->y_base - i;
605 e7f0ad58 bellard
        if (y1 < 0)
606 e7f0ad58 bellard
            y1 += s->total_height;
607 e7f0ad58 bellard
        for(i = 0; i < ydelta; i++) {
608 e7f0ad58 bellard
            if (s->y_displayed == y1)
609 e7f0ad58 bellard
                break;
610 e7f0ad58 bellard
            if (--s->y_displayed < 0)
611 e7f0ad58 bellard
                s->y_displayed = s->total_height - 1;
612 e7f0ad58 bellard
        }
613 e7f0ad58 bellard
    }
614 e7f0ad58 bellard
    console_refresh(s);
615 e7f0ad58 bellard
}
616 e7f0ad58 bellard
617 76ffb0b4 Gerd Hoffmann
static void console_put_lf(QemuConsole *s)
618 e7f0ad58 bellard
{
619 e7f0ad58 bellard
    TextCell *c;
620 e7f0ad58 bellard
    int x, y1;
621 e7f0ad58 bellard
622 e7f0ad58 bellard
    s->y++;
623 e7f0ad58 bellard
    if (s->y >= s->height) {
624 e7f0ad58 bellard
        s->y = s->height - 1;
625 6d6f7c28 pbrook
626 e7f0ad58 bellard
        if (s->y_displayed == s->y_base) {
627 e7f0ad58 bellard
            if (++s->y_displayed == s->total_height)
628 e7f0ad58 bellard
                s->y_displayed = 0;
629 e7f0ad58 bellard
        }
630 e7f0ad58 bellard
        if (++s->y_base == s->total_height)
631 e7f0ad58 bellard
            s->y_base = 0;
632 e7f0ad58 bellard
        if (s->backscroll_height < s->total_height)
633 e7f0ad58 bellard
            s->backscroll_height++;
634 e7f0ad58 bellard
        y1 = (s->y_base + s->height - 1) % s->total_height;
635 e7f0ad58 bellard
        c = &s->cells[y1 * s->width];
636 e7f0ad58 bellard
        for(x = 0; x < s->width; x++) {
637 e7f0ad58 bellard
            c->ch = ' ';
638 6d6f7c28 pbrook
            c->t_attrib = s->t_attrib_default;
639 e7f0ad58 bellard
            c++;
640 e7f0ad58 bellard
        }
641 81c0d5a6 Gerd Hoffmann
        if (qemu_console_is_visible(s) && s->y_displayed == s->y_base) {
642 1562e531 Gerd Hoffmann
            if (s->ds->have_text) {
643 4d3b6f6e balrog
                s->text_x[0] = 0;
644 4d3b6f6e balrog
                s->text_y[0] = 0;
645 4d3b6f6e balrog
                s->text_x[1] = s->width - 1;
646 4d3b6f6e balrog
                s->text_y[1] = s->height - 1;
647 4d3b6f6e balrog
            }
648 4d3b6f6e balrog
649 1562e531 Gerd Hoffmann
            if (s->ds->have_gfx) {
650 1562e531 Gerd Hoffmann
                vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
651 1562e531 Gerd Hoffmann
                           s->width * FONT_WIDTH,
652 1562e531 Gerd Hoffmann
                           (s->height - 1) * FONT_HEIGHT);
653 1562e531 Gerd Hoffmann
                vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
654 1562e531 Gerd Hoffmann
                              s->width * FONT_WIDTH, FONT_HEIGHT,
655 1562e531 Gerd Hoffmann
                              color_table_rgb[0][s->t_attrib_default.bgcol]);
656 1562e531 Gerd Hoffmann
                s->update_x0 = 0;
657 1562e531 Gerd Hoffmann
                s->update_y0 = 0;
658 1562e531 Gerd Hoffmann
                s->update_x1 = s->width * FONT_WIDTH;
659 1562e531 Gerd Hoffmann
                s->update_y1 = s->height * FONT_HEIGHT;
660 1562e531 Gerd Hoffmann
            }
661 e7f0ad58 bellard
        }
662 e7f0ad58 bellard
    }
663 e7f0ad58 bellard
}
664 e7f0ad58 bellard
665 6d6f7c28 pbrook
/* Set console attributes depending on the current escape codes.
666 6d6f7c28 pbrook
 * NOTE: I know this code is not very efficient (checking every color for it
667 6d6f7c28 pbrook
 * self) but it is more readable and better maintainable.
668 6d6f7c28 pbrook
 */
669 76ffb0b4 Gerd Hoffmann
static void console_handle_escape(QemuConsole *s)
670 6d6f7c28 pbrook
{
671 6d6f7c28 pbrook
    int i;
672 6d6f7c28 pbrook
673 6d6f7c28 pbrook
    for (i=0; i<s->nb_esc_params; i++) {
674 6d6f7c28 pbrook
        switch (s->esc_params[i]) {
675 6d6f7c28 pbrook
            case 0: /* reset all console attributes to default */
676 6d6f7c28 pbrook
                s->t_attrib = s->t_attrib_default;
677 6d6f7c28 pbrook
                break;
678 6d6f7c28 pbrook
            case 1:
679 6d6f7c28 pbrook
                s->t_attrib.bold = 1;
680 6d6f7c28 pbrook
                break;
681 6d6f7c28 pbrook
            case 4:
682 6d6f7c28 pbrook
                s->t_attrib.uline = 1;
683 6d6f7c28 pbrook
                break;
684 6d6f7c28 pbrook
            case 5:
685 6d6f7c28 pbrook
                s->t_attrib.blink = 1;
686 6d6f7c28 pbrook
                break;
687 6d6f7c28 pbrook
            case 7:
688 6d6f7c28 pbrook
                s->t_attrib.invers = 1;
689 6d6f7c28 pbrook
                break;
690 6d6f7c28 pbrook
            case 8:
691 6d6f7c28 pbrook
                s->t_attrib.unvisible = 1;
692 6d6f7c28 pbrook
                break;
693 6d6f7c28 pbrook
            case 22:
694 6d6f7c28 pbrook
                s->t_attrib.bold = 0;
695 6d6f7c28 pbrook
                break;
696 6d6f7c28 pbrook
            case 24:
697 6d6f7c28 pbrook
                s->t_attrib.uline = 0;
698 6d6f7c28 pbrook
                break;
699 6d6f7c28 pbrook
            case 25:
700 6d6f7c28 pbrook
                s->t_attrib.blink = 0;
701 6d6f7c28 pbrook
                break;
702 6d6f7c28 pbrook
            case 27:
703 6d6f7c28 pbrook
                s->t_attrib.invers = 0;
704 6d6f7c28 pbrook
                break;
705 6d6f7c28 pbrook
            case 28:
706 6d6f7c28 pbrook
                s->t_attrib.unvisible = 0;
707 6d6f7c28 pbrook
                break;
708 6d6f7c28 pbrook
            /* set foreground color */
709 6d6f7c28 pbrook
            case 30:
710 6d6f7c28 pbrook
                s->t_attrib.fgcol=COLOR_BLACK;
711 6d6f7c28 pbrook
                break;
712 6d6f7c28 pbrook
            case 31:
713 6d6f7c28 pbrook
                s->t_attrib.fgcol=COLOR_RED;
714 6d6f7c28 pbrook
                break;
715 6d6f7c28 pbrook
            case 32:
716 6d6f7c28 pbrook
                s->t_attrib.fgcol=COLOR_GREEN;
717 6d6f7c28 pbrook
                break;
718 6d6f7c28 pbrook
            case 33:
719 6d6f7c28 pbrook
                s->t_attrib.fgcol=COLOR_YELLOW;
720 6d6f7c28 pbrook
                break;
721 6d6f7c28 pbrook
            case 34:
722 6d6f7c28 pbrook
                s->t_attrib.fgcol=COLOR_BLUE;
723 6d6f7c28 pbrook
                break;
724 6d6f7c28 pbrook
            case 35:
725 6d6f7c28 pbrook
                s->t_attrib.fgcol=COLOR_MAGENTA;
726 6d6f7c28 pbrook
                break;
727 6d6f7c28 pbrook
            case 36:
728 6d6f7c28 pbrook
                s->t_attrib.fgcol=COLOR_CYAN;
729 6d6f7c28 pbrook
                break;
730 6d6f7c28 pbrook
            case 37:
731 6d6f7c28 pbrook
                s->t_attrib.fgcol=COLOR_WHITE;
732 6d6f7c28 pbrook
                break;
733 6d6f7c28 pbrook
            /* set background color */
734 6d6f7c28 pbrook
            case 40:
735 6d6f7c28 pbrook
                s->t_attrib.bgcol=COLOR_BLACK;
736 6d6f7c28 pbrook
                break;
737 6d6f7c28 pbrook
            case 41:
738 6d6f7c28 pbrook
                s->t_attrib.bgcol=COLOR_RED;
739 6d6f7c28 pbrook
                break;
740 6d6f7c28 pbrook
            case 42:
741 6d6f7c28 pbrook
                s->t_attrib.bgcol=COLOR_GREEN;
742 6d6f7c28 pbrook
                break;
743 6d6f7c28 pbrook
            case 43:
744 6d6f7c28 pbrook
                s->t_attrib.bgcol=COLOR_YELLOW;
745 6d6f7c28 pbrook
                break;
746 6d6f7c28 pbrook
            case 44:
747 6d6f7c28 pbrook
                s->t_attrib.bgcol=COLOR_BLUE;
748 6d6f7c28 pbrook
                break;
749 6d6f7c28 pbrook
            case 45:
750 6d6f7c28 pbrook
                s->t_attrib.bgcol=COLOR_MAGENTA;
751 6d6f7c28 pbrook
                break;
752 6d6f7c28 pbrook
            case 46:
753 6d6f7c28 pbrook
                s->t_attrib.bgcol=COLOR_CYAN;
754 6d6f7c28 pbrook
                break;
755 6d6f7c28 pbrook
            case 47:
756 6d6f7c28 pbrook
                s->t_attrib.bgcol=COLOR_WHITE;
757 6d6f7c28 pbrook
                break;
758 6d6f7c28 pbrook
        }
759 6d6f7c28 pbrook
    }
760 6d6f7c28 pbrook
}
761 6d6f7c28 pbrook
762 76ffb0b4 Gerd Hoffmann
static void console_clear_xy(QemuConsole *s, int x, int y)
763 adb47967 ths
{
764 adb47967 ths
    int y1 = (s->y_base + y) % s->total_height;
765 adb47967 ths
    TextCell *c = &s->cells[y1 * s->width + x];
766 adb47967 ths
    c->ch = ' ';
767 adb47967 ths
    c->t_attrib = s->t_attrib_default;
768 adb47967 ths
    update_xy(s, x, y);
769 adb47967 ths
}
770 adb47967 ths
771 3eea5498 Ian Campbell
/* set cursor, checking bounds */
772 76ffb0b4 Gerd Hoffmann
static void set_cursor(QemuConsole *s, int x, int y)
773 3eea5498 Ian Campbell
{
774 3eea5498 Ian Campbell
    if (x < 0) {
775 3eea5498 Ian Campbell
        x = 0;
776 3eea5498 Ian Campbell
    }
777 3eea5498 Ian Campbell
    if (y < 0) {
778 3eea5498 Ian Campbell
        y = 0;
779 3eea5498 Ian Campbell
    }
780 3eea5498 Ian Campbell
    if (y >= s->height) {
781 3eea5498 Ian Campbell
        y = s->height - 1;
782 3eea5498 Ian Campbell
    }
783 3eea5498 Ian Campbell
    if (x >= s->width) {
784 3eea5498 Ian Campbell
        x = s->width - 1;
785 3eea5498 Ian Campbell
    }
786 3eea5498 Ian Campbell
787 3eea5498 Ian Campbell
    s->x = x;
788 3eea5498 Ian Campbell
    s->y = y;
789 3eea5498 Ian Campbell
}
790 3eea5498 Ian Campbell
791 76ffb0b4 Gerd Hoffmann
static void console_putchar(QemuConsole *s, int ch)
792 e7f0ad58 bellard
{
793 e7f0ad58 bellard
    TextCell *c;
794 adb47967 ths
    int y1, i;
795 adb47967 ths
    int x, y;
796 e7f0ad58 bellard
797 e7f0ad58 bellard
    switch(s->state) {
798 e7f0ad58 bellard
    case TTY_STATE_NORM:
799 e7f0ad58 bellard
        switch(ch) {
800 6d6f7c28 pbrook
        case '\r':  /* carriage return */
801 e7f0ad58 bellard
            s->x = 0;
802 e7f0ad58 bellard
            break;
803 6d6f7c28 pbrook
        case '\n':  /* newline */
804 e7f0ad58 bellard
            console_put_lf(s);
805 e7f0ad58 bellard
            break;
806 6d6f7c28 pbrook
        case '\b':  /* backspace */
807 5fafdf24 ths
            if (s->x > 0)
808 e15d7371 bellard
                s->x--;
809 6d6f7c28 pbrook
            break;
810 6d6f7c28 pbrook
        case '\t':  /* tabspace */
811 6d6f7c28 pbrook
            if (s->x + (8 - (s->x % 8)) > s->width) {
812 bd468840 bellard
                s->x = 0;
813 6d6f7c28 pbrook
                console_put_lf(s);
814 6d6f7c28 pbrook
            } else {
815 6d6f7c28 pbrook
                s->x = s->x + (8 - (s->x % 8));
816 6d6f7c28 pbrook
            }
817 6d6f7c28 pbrook
            break;
818 6d6f7c28 pbrook
        case '\a':  /* alert aka. bell */
819 6d6f7c28 pbrook
            /* TODO: has to be implemented */
820 6d6f7c28 pbrook
            break;
821 adb47967 ths
        case 14:
822 adb47967 ths
            /* SI (shift in), character set 0 (ignored) */
823 adb47967 ths
            break;
824 adb47967 ths
        case 15:
825 adb47967 ths
            /* SO (shift out), character set 1 (ignored) */
826 adb47967 ths
            break;
827 6d6f7c28 pbrook
        case 27:    /* esc (introducing an escape sequence) */
828 e7f0ad58 bellard
            s->state = TTY_STATE_ESC;
829 e7f0ad58 bellard
            break;
830 e7f0ad58 bellard
        default:
831 ed8276ac ths
            if (s->x >= s->width) {
832 ed8276ac ths
                /* line wrap */
833 ed8276ac ths
                s->x = 0;
834 ed8276ac ths
                console_put_lf(s);
835 adb47967 ths
            }
836 e7f0ad58 bellard
            y1 = (s->y_base + s->y) % s->total_height;
837 e7f0ad58 bellard
            c = &s->cells[y1 * s->width + s->x];
838 e7f0ad58 bellard
            c->ch = ch;
839 6d6f7c28 pbrook
            c->t_attrib = s->t_attrib;
840 e7f0ad58 bellard
            update_xy(s, s->x, s->y);
841 e7f0ad58 bellard
            s->x++;
842 e7f0ad58 bellard
            break;
843 e7f0ad58 bellard
        }
844 e7f0ad58 bellard
        break;
845 6d6f7c28 pbrook
    case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
846 e7f0ad58 bellard
        if (ch == '[') {
847 e7f0ad58 bellard
            for(i=0;i<MAX_ESC_PARAMS;i++)
848 e7f0ad58 bellard
                s->esc_params[i] = 0;
849 e7f0ad58 bellard
            s->nb_esc_params = 0;
850 e7f0ad58 bellard
            s->state = TTY_STATE_CSI;
851 e7f0ad58 bellard
        } else {
852 e7f0ad58 bellard
            s->state = TTY_STATE_NORM;
853 e7f0ad58 bellard
        }
854 e7f0ad58 bellard
        break;
855 6d6f7c28 pbrook
    case TTY_STATE_CSI: /* handle escape sequence parameters */
856 e7f0ad58 bellard
        if (ch >= '0' && ch <= '9') {
857 e7f0ad58 bellard
            if (s->nb_esc_params < MAX_ESC_PARAMS) {
858 c10600af Laszlo Ersek
                int *param = &s->esc_params[s->nb_esc_params];
859 c10600af Laszlo Ersek
                int digit = (ch - '0');
860 c10600af Laszlo Ersek
861 c10600af Laszlo Ersek
                *param = (*param <= (INT_MAX - digit) / 10) ?
862 c10600af Laszlo Ersek
                         *param * 10 + digit : INT_MAX;
863 e7f0ad58 bellard
            }
864 e7f0ad58 bellard
        } else {
865 3eea5498 Ian Campbell
            if (s->nb_esc_params < MAX_ESC_PARAMS)
866 3eea5498 Ian Campbell
                s->nb_esc_params++;
867 e7f0ad58 bellard
            if (ch == ';')
868 e7f0ad58 bellard
                break;
869 5d28b0e9 Stefan Weil
            trace_console_putchar_csi(s->esc_params[0], s->esc_params[1],
870 5d28b0e9 Stefan Weil
                                      ch, s->nb_esc_params);
871 e7f0ad58 bellard
            s->state = TTY_STATE_NORM;
872 e7f0ad58 bellard
            switch(ch) {
873 adb47967 ths
            case 'A':
874 adb47967 ths
                /* move cursor up */
875 adb47967 ths
                if (s->esc_params[0] == 0) {
876 adb47967 ths
                    s->esc_params[0] = 1;
877 adb47967 ths
                }
878 3eea5498 Ian Campbell
                set_cursor(s, s->x, s->y - s->esc_params[0]);
879 adb47967 ths
                break;
880 adb47967 ths
            case 'B':
881 adb47967 ths
                /* move cursor down */
882 adb47967 ths
                if (s->esc_params[0] == 0) {
883 adb47967 ths
                    s->esc_params[0] = 1;
884 adb47967 ths
                }
885 3eea5498 Ian Campbell
                set_cursor(s, s->x, s->y + s->esc_params[0]);
886 e7f0ad58 bellard
                break;
887 e7f0ad58 bellard
            case 'C':
888 adb47967 ths
                /* move cursor right */
889 adb47967 ths
                if (s->esc_params[0] == 0) {
890 adb47967 ths
                    s->esc_params[0] = 1;
891 adb47967 ths
                }
892 3eea5498 Ian Campbell
                set_cursor(s, s->x + s->esc_params[0], s->y);
893 e7f0ad58 bellard
                break;
894 adb47967 ths
            case 'D':
895 adb47967 ths
                /* move cursor left */
896 adb47967 ths
                if (s->esc_params[0] == 0) {
897 adb47967 ths
                    s->esc_params[0] = 1;
898 adb47967 ths
                }
899 3eea5498 Ian Campbell
                set_cursor(s, s->x - s->esc_params[0], s->y);
900 adb47967 ths
                break;
901 adb47967 ths
            case 'G':
902 adb47967 ths
                /* move cursor to column */
903 3eea5498 Ian Campbell
                set_cursor(s, s->esc_params[0] - 1, s->y);
904 adb47967 ths
                break;
905 adb47967 ths
            case 'f':
906 adb47967 ths
            case 'H':
907 adb47967 ths
                /* move cursor to row, column */
908 3eea5498 Ian Campbell
                set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
909 adb47967 ths
                break;
910 adb47967 ths
            case 'J':
911 adb47967 ths
                switch (s->esc_params[0]) {
912 adb47967 ths
                case 0:
913 adb47967 ths
                    /* clear to end of screen */
914 adb47967 ths
                    for (y = s->y; y < s->height; y++) {
915 adb47967 ths
                        for (x = 0; x < s->width; x++) {
916 adb47967 ths
                            if (y == s->y && x < s->x) {
917 adb47967 ths
                                continue;
918 adb47967 ths
                            }
919 adb47967 ths
                            console_clear_xy(s, x, y);
920 adb47967 ths
                        }
921 adb47967 ths
                    }
922 adb47967 ths
                    break;
923 adb47967 ths
                case 1:
924 adb47967 ths
                    /* clear from beginning of screen */
925 adb47967 ths
                    for (y = 0; y <= s->y; y++) {
926 adb47967 ths
                        for (x = 0; x < s->width; x++) {
927 adb47967 ths
                            if (y == s->y && x > s->x) {
928 adb47967 ths
                                break;
929 adb47967 ths
                            }
930 adb47967 ths
                            console_clear_xy(s, x, y);
931 adb47967 ths
                        }
932 adb47967 ths
                    }
933 adb47967 ths
                    break;
934 adb47967 ths
                case 2:
935 adb47967 ths
                    /* clear entire screen */
936 adb47967 ths
                    for (y = 0; y <= s->height; y++) {
937 adb47967 ths
                        for (x = 0; x < s->width; x++) {
938 adb47967 ths
                            console_clear_xy(s, x, y);
939 adb47967 ths
                        }
940 adb47967 ths
                    }
941 f94a950f Markus Armbruster
                    break;
942 adb47967 ths
                }
943 95d8f9f4 Markus Armbruster
                break;
944 e7f0ad58 bellard
            case 'K':
945 adb47967 ths
                switch (s->esc_params[0]) {
946 adb47967 ths
                case 0:
947 f94a950f Markus Armbruster
                    /* clear to eol */
948 f94a950f Markus Armbruster
                    for(x = s->x; x < s->width; x++) {
949 adb47967 ths
                        console_clear_xy(s, x, s->y);
950 f94a950f Markus Armbruster
                    }
951 f94a950f Markus Armbruster
                    break;
952 adb47967 ths
                case 1:
953 adb47967 ths
                    /* clear from beginning of line */
954 adb47967 ths
                    for (x = 0; x <= s->x; x++) {
955 adb47967 ths
                        console_clear_xy(s, x, s->y);
956 adb47967 ths
                    }
957 adb47967 ths
                    break;
958 adb47967 ths
                case 2:
959 adb47967 ths
                    /* clear entire line */
960 adb47967 ths
                    for(x = 0; x < s->width; x++) {
961 adb47967 ths
                        console_clear_xy(s, x, s->y);
962 adb47967 ths
                    }
963 f94a950f Markus Armbruster
                    break;
964 f94a950f Markus Armbruster
                }
965 adb47967 ths
                break;
966 adb47967 ths
            case 'm':
967 f94a950f Markus Armbruster
                console_handle_escape(s);
968 f94a950f Markus Armbruster
                break;
969 adb47967 ths
            case 'n':
970 adb47967 ths
                /* report cursor position */
971 adb47967 ths
                /* TODO: send ESC[row;colR */
972 adb47967 ths
                break;
973 adb47967 ths
            case 's':
974 adb47967 ths
                /* save cursor position */
975 adb47967 ths
                s->x_saved = s->x;
976 adb47967 ths
                s->y_saved = s->y;
977 adb47967 ths
                break;
978 adb47967 ths
            case 'u':
979 adb47967 ths
                /* restore cursor position */
980 adb47967 ths
                s->x = s->x_saved;
981 adb47967 ths
                s->y = s->y_saved;
982 adb47967 ths
                break;
983 adb47967 ths
            default:
984 5d28b0e9 Stefan Weil
                trace_console_putchar_unhandled(ch);
985 adb47967 ths
                break;
986 adb47967 ths
            }
987 adb47967 ths
            break;
988 e7f0ad58 bellard
        }
989 e7f0ad58 bellard
    }
990 e7f0ad58 bellard
}
991 e7f0ad58 bellard
992 e7f0ad58 bellard
void console_select(unsigned int index)
993 e7f0ad58 bellard
{
994 284d1c6b Gerd Hoffmann
    DisplayChangeListener *dcl;
995 76ffb0b4 Gerd Hoffmann
    QemuConsole *s;
996 6d6f7c28 pbrook
997 e7f0ad58 bellard
    if (index >= MAX_CONSOLES)
998 e7f0ad58 bellard
        return;
999 437fe106 Gerd Hoffmann
1000 437fe106 Gerd Hoffmann
    trace_console_select(index);
1001 284d1c6b Gerd Hoffmann
    s = qemu_console_lookup_by_index(index);
1002 e7f0ad58 bellard
    if (s) {
1003 7d957bd8 aliguori
        DisplayState *ds = s->ds;
1004 bf1bed81 Jan Kiszka
1005 8bd6b06d Stefan Weil
        if (active_console && active_console->cursor_timer) {
1006 bc72ad67 Alex Bligh
            timer_del(active_console->cursor_timer);
1007 bf1bed81 Jan Kiszka
        }
1008 e7f0ad58 bellard
        active_console = s;
1009 a93a4a22 Gerd Hoffmann
        if (ds->have_gfx) {
1010 284d1c6b Gerd Hoffmann
            QLIST_FOREACH(dcl, &ds->listeners, next) {
1011 284d1c6b Gerd Hoffmann
                if (dcl->con != NULL) {
1012 284d1c6b Gerd Hoffmann
                    continue;
1013 284d1c6b Gerd Hoffmann
                }
1014 284d1c6b Gerd Hoffmann
                if (dcl->ops->dpy_gfx_switch) {
1015 284d1c6b Gerd Hoffmann
                    dcl->ops->dpy_gfx_switch(dcl, s->surface);
1016 284d1c6b Gerd Hoffmann
                }
1017 284d1c6b Gerd Hoffmann
            }
1018 321f048d Gerd Hoffmann
            dpy_gfx_update(s, 0, 0, surface_width(s->surface),
1019 321f048d Gerd Hoffmann
                           surface_height(s->surface));
1020 a93a4a22 Gerd Hoffmann
        }
1021 a93a4a22 Gerd Hoffmann
        if (ds->have_text) {
1022 c78f7137 Gerd Hoffmann
            dpy_text_resize(s, s->width, s->height);
1023 68f00996 aliguori
        }
1024 bf1bed81 Jan Kiszka
        if (s->cursor_timer) {
1025 bc72ad67 Alex Bligh
            timer_mod(s->cursor_timer,
1026 bc72ad67 Alex Bligh
                   qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2);
1027 bf1bed81 Jan Kiszka
        }
1028 e7f0ad58 bellard
    }
1029 e7f0ad58 bellard
}
1030 e7f0ad58 bellard
1031 e7f0ad58 bellard
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1032 e7f0ad58 bellard
{
1033 76ffb0b4 Gerd Hoffmann
    QemuConsole *s = chr->opaque;
1034 e7f0ad58 bellard
    int i;
1035 e7f0ad58 bellard
1036 14778c20 pbrook
    s->update_x0 = s->width * FONT_WIDTH;
1037 14778c20 pbrook
    s->update_y0 = s->height * FONT_HEIGHT;
1038 14778c20 pbrook
    s->update_x1 = 0;
1039 14778c20 pbrook
    s->update_y1 = 0;
1040 e7f0ad58 bellard
    console_show_cursor(s, 0);
1041 e7f0ad58 bellard
    for(i = 0; i < len; i++) {
1042 e7f0ad58 bellard
        console_putchar(s, buf[i]);
1043 e7f0ad58 bellard
    }
1044 e7f0ad58 bellard
    console_show_cursor(s, 1);
1045 a93a4a22 Gerd Hoffmann
    if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
1046 c78f7137 Gerd Hoffmann
        dpy_gfx_update(s, s->update_x0, s->update_y0,
1047 a93a4a22 Gerd Hoffmann
                       s->update_x1 - s->update_x0,
1048 a93a4a22 Gerd Hoffmann
                       s->update_y1 - s->update_y0);
1049 14778c20 pbrook
    }
1050 e7f0ad58 bellard
    return len;
1051 e7f0ad58 bellard
}
1052 e7f0ad58 bellard
1053 e15d7371 bellard
static void kbd_send_chars(void *opaque)
1054 e15d7371 bellard
{
1055 76ffb0b4 Gerd Hoffmann
    QemuConsole *s = opaque;
1056 e15d7371 bellard
    int len;
1057 e15d7371 bellard
    uint8_t buf[16];
1058 3b46e624 ths
1059 909cda12 Anthony Liguori
    len = qemu_chr_be_can_write(s->chr);
1060 e15d7371 bellard
    if (len > s->out_fifo.count)
1061 e15d7371 bellard
        len = s->out_fifo.count;
1062 e15d7371 bellard
    if (len > 0) {
1063 e15d7371 bellard
        if (len > sizeof(buf))
1064 e15d7371 bellard
            len = sizeof(buf);
1065 e15d7371 bellard
        qemu_fifo_read(&s->out_fifo, buf, len);
1066 fa5efccb Anthony Liguori
        qemu_chr_be_write(s->chr, buf, len);
1067 e15d7371 bellard
    }
1068 e15d7371 bellard
    /* characters are pending: we send them a bit later (XXX:
1069 e15d7371 bellard
       horrible, should change char device API) */
1070 e15d7371 bellard
    if (s->out_fifo.count > 0) {
1071 bc72ad67 Alex Bligh
        timer_mod(s->kbd_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1);
1072 e15d7371 bellard
    }
1073 e15d7371 bellard
}
1074 e15d7371 bellard
1075 e7f0ad58 bellard
/* called when an ascii key is pressed */
1076 e7f0ad58 bellard
void kbd_put_keysym(int keysym)
1077 e7f0ad58 bellard
{
1078 76ffb0b4 Gerd Hoffmann
    QemuConsole *s;
1079 e7f0ad58 bellard
    uint8_t buf[16], *q;
1080 e7f0ad58 bellard
    int c;
1081 e7f0ad58 bellard
1082 e7f0ad58 bellard
    s = active_console;
1083 af3a9031 ths
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
1084 e7f0ad58 bellard
        return;
1085 e7f0ad58 bellard
1086 e7f0ad58 bellard
    switch(keysym) {
1087 e7f0ad58 bellard
    case QEMU_KEY_CTRL_UP:
1088 81c0d5a6 Gerd Hoffmann
        console_scroll(s, -1);
1089 e7f0ad58 bellard
        break;
1090 e7f0ad58 bellard
    case QEMU_KEY_CTRL_DOWN:
1091 81c0d5a6 Gerd Hoffmann
        console_scroll(s, 1);
1092 e7f0ad58 bellard
        break;
1093 e7f0ad58 bellard
    case QEMU_KEY_CTRL_PAGEUP:
1094 81c0d5a6 Gerd Hoffmann
        console_scroll(s, -10);
1095 e7f0ad58 bellard
        break;
1096 e7f0ad58 bellard
    case QEMU_KEY_CTRL_PAGEDOWN:
1097 81c0d5a6 Gerd Hoffmann
        console_scroll(s, 10);
1098 e7f0ad58 bellard
        break;
1099 e7f0ad58 bellard
    default:
1100 e15d7371 bellard
        /* convert the QEMU keysym to VT100 key string */
1101 e15d7371 bellard
        q = buf;
1102 e15d7371 bellard
        if (keysym >= 0xe100 && keysym <= 0xe11f) {
1103 e15d7371 bellard
            *q++ = '\033';
1104 e15d7371 bellard
            *q++ = '[';
1105 e15d7371 bellard
            c = keysym - 0xe100;
1106 e15d7371 bellard
            if (c >= 10)
1107 e15d7371 bellard
                *q++ = '0' + (c / 10);
1108 e15d7371 bellard
            *q++ = '0' + (c % 10);
1109 e15d7371 bellard
            *q++ = '~';
1110 e15d7371 bellard
        } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1111 e15d7371 bellard
            *q++ = '\033';
1112 e15d7371 bellard
            *q++ = '[';
1113 e15d7371 bellard
            *q++ = keysym & 0xff;
1114 4104833f Paolo Bonzini
        } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1115 4104833f Paolo Bonzini
            console_puts(s->chr, (const uint8_t *) "\r", 1);
1116 4104833f Paolo Bonzini
            *q++ = '\n';
1117 e15d7371 bellard
        } else {
1118 4104833f Paolo Bonzini
            *q++ = keysym;
1119 4104833f Paolo Bonzini
        }
1120 4104833f Paolo Bonzini
        if (s->echo) {
1121 4104833f Paolo Bonzini
            console_puts(s->chr, buf, q - buf);
1122 e15d7371 bellard
        }
1123 e5b0bc44 pbrook
        if (s->chr->chr_read) {
1124 e15d7371 bellard
            qemu_fifo_write(&s->out_fifo, buf, q - buf);
1125 e15d7371 bellard
            kbd_send_chars(s);
1126 e7f0ad58 bellard
        }
1127 e7f0ad58 bellard
        break;
1128 e7f0ad58 bellard
    }
1129 e7f0ad58 bellard
}
1130 e7f0ad58 bellard
1131 4d3b6f6e balrog
static void text_console_invalidate(void *opaque)
1132 4d3b6f6e balrog
{
1133 76ffb0b4 Gerd Hoffmann
    QemuConsole *s = (QemuConsole *) opaque;
1134 1562e531 Gerd Hoffmann
1135 1562e531 Gerd Hoffmann
    if (s->ds->have_text && s->console_type == TEXT_CONSOLE) {
1136 68f00996 aliguori
        text_console_resize(s);
1137 68f00996 aliguori
    }
1138 4d3b6f6e balrog
    console_refresh(s);
1139 4d3b6f6e balrog
}
1140 4d3b6f6e balrog
1141 c227f099 Anthony Liguori
static void text_console_update(void *opaque, console_ch_t *chardata)
1142 4d3b6f6e balrog
{
1143 76ffb0b4 Gerd Hoffmann
    QemuConsole *s = (QemuConsole *) opaque;
1144 4d3b6f6e balrog
    int i, j, src;
1145 4d3b6f6e balrog
1146 4d3b6f6e balrog
    if (s->text_x[0] <= s->text_x[1]) {
1147 4d3b6f6e balrog
        src = (s->y_base + s->text_y[0]) * s->width;
1148 4d3b6f6e balrog
        chardata += s->text_y[0] * s->width;
1149 4d3b6f6e balrog
        for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1150 4d3b6f6e balrog
            for (j = 0; j < s->width; j ++, src ++)
1151 4d3b6f6e balrog
                console_write_ch(chardata ++, s->cells[src].ch |
1152 4d3b6f6e balrog
                                (s->cells[src].t_attrib.fgcol << 12) |
1153 4d3b6f6e balrog
                                (s->cells[src].t_attrib.bgcol << 8) |
1154 4d3b6f6e balrog
                                (s->cells[src].t_attrib.bold << 21));
1155 c78f7137 Gerd Hoffmann
        dpy_text_update(s, s->text_x[0], s->text_y[0],
1156 a93a4a22 Gerd Hoffmann
                        s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1157 4d3b6f6e balrog
        s->text_x[0] = s->width;
1158 4d3b6f6e balrog
        s->text_y[0] = s->height;
1159 4d3b6f6e balrog
        s->text_x[1] = 0;
1160 4d3b6f6e balrog
        s->text_y[1] = 0;
1161 4d3b6f6e balrog
    }
1162 4d3b6f6e balrog
    if (s->cursor_invalidate) {
1163 c78f7137 Gerd Hoffmann
        dpy_text_cursor(s, s->x, s->y);
1164 4d3b6f6e balrog
        s->cursor_invalidate = 0;
1165 4d3b6f6e balrog
    }
1166 4d3b6f6e balrog
}
1167 4d3b6f6e balrog
1168 76ffb0b4 Gerd Hoffmann
static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
1169 e7f0ad58 bellard
{
1170 aa2beaa1 Gerd Hoffmann
    Error *local_err = NULL;
1171 95be0669 Gerd Hoffmann
    Object *obj;
1172 76ffb0b4 Gerd Hoffmann
    QemuConsole *s;
1173 95219897 pbrook
    int i;
1174 e7f0ad58 bellard
1175 e7f0ad58 bellard
    if (nb_consoles >= MAX_CONSOLES)
1176 e7f0ad58 bellard
        return NULL;
1177 aa2beaa1 Gerd Hoffmann
1178 95be0669 Gerd Hoffmann
    obj = object_new(TYPE_QEMU_CONSOLE);
1179 95be0669 Gerd Hoffmann
    s = QEMU_CONSOLE(obj);
1180 aa2beaa1 Gerd Hoffmann
    object_property_add_link(obj, "device", TYPE_DEVICE,
1181 aa2beaa1 Gerd Hoffmann
                             (Object **)&s->device, &local_err);
1182 aa2beaa1 Gerd Hoffmann
1183 af3a9031 ths
    if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1184 af3a9031 ths
        (console_type == GRAPHIC_CONSOLE))) {
1185 e7f0ad58 bellard
        active_console = s;
1186 af3a9031 ths
    }
1187 e7f0ad58 bellard
    s->ds = ds;
1188 af3a9031 ths
    s->console_type = console_type;
1189 af3a9031 ths
    if (console_type != GRAPHIC_CONSOLE) {
1190 f81bdefb Jan Kiszka
        s->index = nb_consoles;
1191 95219897 pbrook
        consoles[nb_consoles++] = s;
1192 95219897 pbrook
    } else {
1193 95219897 pbrook
        /* HACK: Put graphical consoles before text consoles.  */
1194 95219897 pbrook
        for (i = nb_consoles; i > 0; i--) {
1195 af3a9031 ths
            if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1196 95219897 pbrook
                break;
1197 95219897 pbrook
            consoles[i] = consoles[i - 1];
1198 f81bdefb Jan Kiszka
            consoles[i]->index = i;
1199 95219897 pbrook
        }
1200 f81bdefb Jan Kiszka
        s->index = i;
1201 95219897 pbrook
        consoles[i] = s;
1202 3023f332 aliguori
        nb_consoles++;
1203 95219897 pbrook
    }
1204 95219897 pbrook
    return s;
1205 95219897 pbrook
}
1206 95219897 pbrook
1207 537a4391 Gerd Hoffmann
static void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1208 537a4391 Gerd Hoffmann
                               int linesize, PixelFormat pf, int newflags)
1209 ffe8b821 Jes Sorensen
{
1210 ffe8b821 Jes Sorensen
    surface->pf = pf;
1211 69c77777 Gerd Hoffmann
1212 69c77777 Gerd Hoffmann
    qemu_pixman_image_unref(surface->image);
1213 69c77777 Gerd Hoffmann
    surface->image = NULL;
1214 69c77777 Gerd Hoffmann
1215 69c77777 Gerd Hoffmann
    surface->format = qemu_pixman_get_format(&pf);
1216 69c77777 Gerd Hoffmann
    assert(surface->format != 0);
1217 69c77777 Gerd Hoffmann
    surface->image = pixman_image_create_bits(surface->format,
1218 69c77777 Gerd Hoffmann
                                              width, height,
1219 69c77777 Gerd Hoffmann
                                              NULL, linesize);
1220 69c77777 Gerd Hoffmann
    assert(surface->image != NULL);
1221 69c77777 Gerd Hoffmann
1222 ffe8b821 Jes Sorensen
    surface->flags = newflags | QEMU_ALLOCATED_FLAG;
1223 98b50080 Paolo Bonzini
#ifdef HOST_WORDS_BIGENDIAN
1224 ffe8b821 Jes Sorensen
    surface->flags |= QEMU_BIG_ENDIAN_FLAG;
1225 98b50080 Paolo Bonzini
#endif
1226 98b50080 Paolo Bonzini
}
1227 98b50080 Paolo Bonzini
1228 da229ef3 Gerd Hoffmann
DisplaySurface *qemu_create_displaysurface(int width, int height)
1229 537a4391 Gerd Hoffmann
{
1230 537a4391 Gerd Hoffmann
    DisplaySurface *surface = g_new0(DisplaySurface, 1);
1231 537a4391 Gerd Hoffmann
    int linesize = width * 4;
1232 da229ef3 Gerd Hoffmann
1233 da229ef3 Gerd Hoffmann
    trace_displaysurface_create(surface, width, height);
1234 537a4391 Gerd Hoffmann
    qemu_alloc_display(surface, width, height, linesize,
1235 537a4391 Gerd Hoffmann
                       qemu_default_pixelformat(32), 0);
1236 537a4391 Gerd Hoffmann
    return surface;
1237 537a4391 Gerd Hoffmann
}
1238 537a4391 Gerd Hoffmann
1239 187cd1d9 Gerd Hoffmann
DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
1240 b1424e03 Gerd Hoffmann
                                                int linesize, uint8_t *data,
1241 b1424e03 Gerd Hoffmann
                                                bool byteswap)
1242 98b50080 Paolo Bonzini
{
1243 69c77777 Gerd Hoffmann
    DisplaySurface *surface = g_new0(DisplaySurface, 1);
1244 98b50080 Paolo Bonzini
1245 da229ef3 Gerd Hoffmann
    trace_displaysurface_create_from(surface, width, height, bpp, byteswap);
1246 b1424e03 Gerd Hoffmann
    if (byteswap) {
1247 b1424e03 Gerd Hoffmann
        surface->pf = qemu_different_endianness_pixelformat(bpp);
1248 b1424e03 Gerd Hoffmann
    } else {
1249 b1424e03 Gerd Hoffmann
        surface->pf = qemu_default_pixelformat(bpp);
1250 b1424e03 Gerd Hoffmann
    }
1251 69c77777 Gerd Hoffmann
1252 69c77777 Gerd Hoffmann
    surface->format = qemu_pixman_get_format(&surface->pf);
1253 69c77777 Gerd Hoffmann
    assert(surface->format != 0);
1254 69c77777 Gerd Hoffmann
    surface->image = pixman_image_create_bits(surface->format,
1255 69c77777 Gerd Hoffmann
                                              width, height,
1256 69c77777 Gerd Hoffmann
                                              (void *)data, linesize);
1257 69c77777 Gerd Hoffmann
    assert(surface->image != NULL);
1258 69c77777 Gerd Hoffmann
1259 98b50080 Paolo Bonzini
#ifdef HOST_WORDS_BIGENDIAN
1260 98b50080 Paolo Bonzini
    surface->flags = QEMU_BIG_ENDIAN_FLAG;
1261 98b50080 Paolo Bonzini
#endif
1262 98b50080 Paolo Bonzini
1263 98b50080 Paolo Bonzini
    return surface;
1264 98b50080 Paolo Bonzini
}
1265 98b50080 Paolo Bonzini
1266 d3002b04 Gerd Hoffmann
static DisplaySurface *qemu_create_dummy_surface(void)
1267 d3002b04 Gerd Hoffmann
{
1268 d3002b04 Gerd Hoffmann
    static const char msg[] =
1269 d3002b04 Gerd Hoffmann
        "This VM has no graphic display device.";
1270 d3002b04 Gerd Hoffmann
    DisplaySurface *surface = qemu_create_displaysurface(640, 480);
1271 d3002b04 Gerd Hoffmann
    pixman_color_t bg = color_table_rgb[0][COLOR_BLACK];
1272 d3002b04 Gerd Hoffmann
    pixman_color_t fg = color_table_rgb[0][COLOR_WHITE];
1273 d3002b04 Gerd Hoffmann
    pixman_image_t *glyph;
1274 d3002b04 Gerd Hoffmann
    int len, x, y, i;
1275 d3002b04 Gerd Hoffmann
1276 d3002b04 Gerd Hoffmann
    len = strlen(msg);
1277 d3002b04 Gerd Hoffmann
    x = (640/FONT_WIDTH  - len) / 2;
1278 d3002b04 Gerd Hoffmann
    y = (480/FONT_HEIGHT - 1)   / 2;
1279 d3002b04 Gerd Hoffmann
    for (i = 0; i < len; i++) {
1280 d3002b04 Gerd Hoffmann
        glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
1281 d3002b04 Gerd Hoffmann
        qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
1282 d3002b04 Gerd Hoffmann
                                 x+i, y, FONT_WIDTH, FONT_HEIGHT);
1283 d3002b04 Gerd Hoffmann
        qemu_pixman_image_unref(glyph);
1284 d3002b04 Gerd Hoffmann
    }
1285 d3002b04 Gerd Hoffmann
    return surface;
1286 d3002b04 Gerd Hoffmann
}
1287 d3002b04 Gerd Hoffmann
1288 da229ef3 Gerd Hoffmann
void qemu_free_displaysurface(DisplaySurface *surface)
1289 98b50080 Paolo Bonzini
{
1290 da229ef3 Gerd Hoffmann
    if (surface == NULL) {
1291 98b50080 Paolo Bonzini
        return;
1292 187cd1d9 Gerd Hoffmann
    }
1293 da229ef3 Gerd Hoffmann
    trace_displaysurface_free(surface);
1294 da229ef3 Gerd Hoffmann
    qemu_pixman_image_unref(surface->image);
1295 da229ef3 Gerd Hoffmann
    g_free(surface);
1296 98b50080 Paolo Bonzini
}
1297 98b50080 Paolo Bonzini
1298 5209089f Gerd Hoffmann
void register_displaychangelistener(DisplayChangeListener *dcl)
1299 7c20b4a3 Gerd Hoffmann
{
1300 d3002b04 Gerd Hoffmann
    static DisplaySurface *dummy;
1301 284d1c6b Gerd Hoffmann
    QemuConsole *con;
1302 284d1c6b Gerd Hoffmann
1303 7c20b4a3 Gerd Hoffmann
    trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
1304 5209089f Gerd Hoffmann
    dcl->ds = get_alloc_displaystate();
1305 5209089f Gerd Hoffmann
    QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
1306 5209089f Gerd Hoffmann
    gui_setup_refresh(dcl->ds);
1307 284d1c6b Gerd Hoffmann
    if (dcl->con) {
1308 284d1c6b Gerd Hoffmann
        dcl->con->dcls++;
1309 284d1c6b Gerd Hoffmann
        con = dcl->con;
1310 284d1c6b Gerd Hoffmann
    } else {
1311 284d1c6b Gerd Hoffmann
        con = active_console;
1312 284d1c6b Gerd Hoffmann
    }
1313 d3002b04 Gerd Hoffmann
    if (dcl->ops->dpy_gfx_switch) {
1314 d3002b04 Gerd Hoffmann
        if (con) {
1315 d3002b04 Gerd Hoffmann
            dcl->ops->dpy_gfx_switch(dcl, con->surface);
1316 d3002b04 Gerd Hoffmann
        } else {
1317 d3002b04 Gerd Hoffmann
            if (!dummy) {
1318 d3002b04 Gerd Hoffmann
                dummy = qemu_create_dummy_surface();
1319 d3002b04 Gerd Hoffmann
            }
1320 d3002b04 Gerd Hoffmann
            dcl->ops->dpy_gfx_switch(dcl, dummy);
1321 d3002b04 Gerd Hoffmann
        }
1322 7c20b4a3 Gerd Hoffmann
    }
1323 7c20b4a3 Gerd Hoffmann
}
1324 7c20b4a3 Gerd Hoffmann
1325 0f7b2864 Gerd Hoffmann
void update_displaychangelistener(DisplayChangeListener *dcl,
1326 0f7b2864 Gerd Hoffmann
                                  uint64_t interval)
1327 0f7b2864 Gerd Hoffmann
{
1328 0f7b2864 Gerd Hoffmann
    DisplayState *ds = dcl->ds;
1329 0f7b2864 Gerd Hoffmann
1330 0f7b2864 Gerd Hoffmann
    dcl->update_interval = interval;
1331 0f7b2864 Gerd Hoffmann
    if (!ds->refreshing && ds->update_interval > interval) {
1332 bc72ad67 Alex Bligh
        timer_mod(ds->gui_timer, ds->last_update + interval);
1333 0f7b2864 Gerd Hoffmann
    }
1334 0f7b2864 Gerd Hoffmann
}
1335 0f7b2864 Gerd Hoffmann
1336 7c20b4a3 Gerd Hoffmann
void unregister_displaychangelistener(DisplayChangeListener *dcl)
1337 7c20b4a3 Gerd Hoffmann
{
1338 7c20b4a3 Gerd Hoffmann
    DisplayState *ds = dcl->ds;
1339 7c20b4a3 Gerd Hoffmann
    trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
1340 284d1c6b Gerd Hoffmann
    if (dcl->con) {
1341 284d1c6b Gerd Hoffmann
        dcl->con->dcls--;
1342 284d1c6b Gerd Hoffmann
    }
1343 7c20b4a3 Gerd Hoffmann
    QLIST_REMOVE(dcl, next);
1344 7c20b4a3 Gerd Hoffmann
    gui_setup_refresh(ds);
1345 7c20b4a3 Gerd Hoffmann
}
1346 7c20b4a3 Gerd Hoffmann
1347 c78f7137 Gerd Hoffmann
void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
1348 7c20b4a3 Gerd Hoffmann
{
1349 c78f7137 Gerd Hoffmann
    DisplayState *s = con->ds;
1350 284d1c6b Gerd Hoffmann
    DisplayChangeListener *dcl;
1351 321f048d Gerd Hoffmann
    int width = surface_width(con->surface);
1352 321f048d Gerd Hoffmann
    int height = surface_height(con->surface);
1353 7c20b4a3 Gerd Hoffmann
1354 7c20b4a3 Gerd Hoffmann
    x = MAX(x, 0);
1355 7c20b4a3 Gerd Hoffmann
    y = MAX(y, 0);
1356 7c20b4a3 Gerd Hoffmann
    x = MIN(x, width);
1357 7c20b4a3 Gerd Hoffmann
    y = MIN(y, height);
1358 7c20b4a3 Gerd Hoffmann
    w = MIN(w, width - x);
1359 7c20b4a3 Gerd Hoffmann
    h = MIN(h, height - y);
1360 7c20b4a3 Gerd Hoffmann
1361 81c0d5a6 Gerd Hoffmann
    if (!qemu_console_is_visible(con)) {
1362 321f048d Gerd Hoffmann
        return;
1363 321f048d Gerd Hoffmann
    }
1364 7c20b4a3 Gerd Hoffmann
    QLIST_FOREACH(dcl, &s->listeners, next) {
1365 284d1c6b Gerd Hoffmann
        if (con != (dcl->con ? dcl->con : active_console)) {
1366 284d1c6b Gerd Hoffmann
            continue;
1367 284d1c6b Gerd Hoffmann
        }
1368 7c20b4a3 Gerd Hoffmann
        if (dcl->ops->dpy_gfx_update) {
1369 bc2ed970 Gerd Hoffmann
            dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
1370 7c20b4a3 Gerd Hoffmann
        }
1371 7c20b4a3 Gerd Hoffmann
    }
1372 7c20b4a3 Gerd Hoffmann
}
1373 7c20b4a3 Gerd Hoffmann
1374 321f048d Gerd Hoffmann
void dpy_gfx_replace_surface(QemuConsole *con,
1375 321f048d Gerd Hoffmann
                             DisplaySurface *surface)
1376 321f048d Gerd Hoffmann
{
1377 321f048d Gerd Hoffmann
    DisplayState *s = con->ds;
1378 321f048d Gerd Hoffmann
    DisplaySurface *old_surface = con->surface;
1379 284d1c6b Gerd Hoffmann
    DisplayChangeListener *dcl;
1380 321f048d Gerd Hoffmann
1381 321f048d Gerd Hoffmann
    con->surface = surface;
1382 284d1c6b Gerd Hoffmann
    QLIST_FOREACH(dcl, &s->listeners, next) {
1383 284d1c6b Gerd Hoffmann
        if (con != (dcl->con ? dcl->con : active_console)) {
1384 284d1c6b Gerd Hoffmann
            continue;
1385 284d1c6b Gerd Hoffmann
        }
1386 284d1c6b Gerd Hoffmann
        if (dcl->ops->dpy_gfx_switch) {
1387 284d1c6b Gerd Hoffmann
            dcl->ops->dpy_gfx_switch(dcl, surface);
1388 284d1c6b Gerd Hoffmann
        }
1389 321f048d Gerd Hoffmann
    }
1390 da229ef3 Gerd Hoffmann
    qemu_free_displaysurface(old_surface);
1391 7c20b4a3 Gerd Hoffmann
}
1392 7c20b4a3 Gerd Hoffmann
1393 7c20b4a3 Gerd Hoffmann
void dpy_refresh(DisplayState *s)
1394 7c20b4a3 Gerd Hoffmann
{
1395 284d1c6b Gerd Hoffmann
    DisplayChangeListener *dcl;
1396 284d1c6b Gerd Hoffmann
1397 7c20b4a3 Gerd Hoffmann
    QLIST_FOREACH(dcl, &s->listeners, next) {
1398 7c20b4a3 Gerd Hoffmann
        if (dcl->ops->dpy_refresh) {
1399 bc2ed970 Gerd Hoffmann
            dcl->ops->dpy_refresh(dcl);
1400 7c20b4a3 Gerd Hoffmann
        }
1401 7c20b4a3 Gerd Hoffmann
    }
1402 7c20b4a3 Gerd Hoffmann
}
1403 7c20b4a3 Gerd Hoffmann
1404 c78f7137 Gerd Hoffmann
void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y,
1405 c78f7137 Gerd Hoffmann
                  int dst_x, int dst_y, int w, int h)
1406 7c20b4a3 Gerd Hoffmann
{
1407 c78f7137 Gerd Hoffmann
    DisplayState *s = con->ds;
1408 284d1c6b Gerd Hoffmann
    DisplayChangeListener *dcl;
1409 321f048d Gerd Hoffmann
1410 81c0d5a6 Gerd Hoffmann
    if (!qemu_console_is_visible(con)) {
1411 321f048d Gerd Hoffmann
        return;
1412 321f048d Gerd Hoffmann
    }
1413 7c20b4a3 Gerd Hoffmann
    QLIST_FOREACH(dcl, &s->listeners, next) {
1414 284d1c6b Gerd Hoffmann
        if (con != (dcl->con ? dcl->con : active_console)) {
1415 284d1c6b Gerd Hoffmann
            continue;
1416 284d1c6b Gerd Hoffmann
        }
1417 7c20b4a3 Gerd Hoffmann
        if (dcl->ops->dpy_gfx_copy) {
1418 bc2ed970 Gerd Hoffmann
            dcl->ops->dpy_gfx_copy(dcl, src_x, src_y, dst_x, dst_y, w, h);
1419 7c20b4a3 Gerd Hoffmann
        } else { /* TODO */
1420 bc2ed970 Gerd Hoffmann
            dcl->ops->dpy_gfx_update(dcl, dst_x, dst_y, w, h);
1421 7c20b4a3 Gerd Hoffmann
        }
1422 7c20b4a3 Gerd Hoffmann
    }
1423 7c20b4a3 Gerd Hoffmann
}
1424 7c20b4a3 Gerd Hoffmann
1425 c78f7137 Gerd Hoffmann
void dpy_text_cursor(QemuConsole *con, int x, int y)
1426 7c20b4a3 Gerd Hoffmann
{
1427 c78f7137 Gerd Hoffmann
    DisplayState *s = con->ds;
1428 284d1c6b Gerd Hoffmann
    DisplayChangeListener *dcl;
1429 321f048d Gerd Hoffmann
1430 81c0d5a6 Gerd Hoffmann
    if (!qemu_console_is_visible(con)) {
1431 321f048d Gerd Hoffmann
        return;
1432 321f048d Gerd Hoffmann
    }
1433 7c20b4a3 Gerd Hoffmann
    QLIST_FOREACH(dcl, &s->listeners, next) {
1434 284d1c6b Gerd Hoffmann
        if (con != (dcl->con ? dcl->con : active_console)) {
1435 284d1c6b Gerd Hoffmann
            continue;
1436 284d1c6b Gerd Hoffmann
        }
1437 7c20b4a3 Gerd Hoffmann
        if (dcl->ops->dpy_text_cursor) {
1438 bc2ed970 Gerd Hoffmann
            dcl->ops->dpy_text_cursor(dcl, x, y);
1439 7c20b4a3 Gerd Hoffmann
        }
1440 7c20b4a3 Gerd Hoffmann
    }
1441 7c20b4a3 Gerd Hoffmann
}
1442 7c20b4a3 Gerd Hoffmann
1443 c78f7137 Gerd Hoffmann
void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
1444 7c20b4a3 Gerd Hoffmann
{
1445 c78f7137 Gerd Hoffmann
    DisplayState *s = con->ds;
1446 284d1c6b Gerd Hoffmann
    DisplayChangeListener *dcl;
1447 321f048d Gerd Hoffmann
1448 81c0d5a6 Gerd Hoffmann
    if (!qemu_console_is_visible(con)) {
1449 321f048d Gerd Hoffmann
        return;
1450 321f048d Gerd Hoffmann
    }
1451 7c20b4a3 Gerd Hoffmann
    QLIST_FOREACH(dcl, &s->listeners, next) {
1452 284d1c6b Gerd Hoffmann
        if (con != (dcl->con ? dcl->con : active_console)) {
1453 284d1c6b Gerd Hoffmann
            continue;
1454 284d1c6b Gerd Hoffmann
        }
1455 7c20b4a3 Gerd Hoffmann
        if (dcl->ops->dpy_text_update) {
1456 bc2ed970 Gerd Hoffmann
            dcl->ops->dpy_text_update(dcl, x, y, w, h);
1457 7c20b4a3 Gerd Hoffmann
        }
1458 7c20b4a3 Gerd Hoffmann
    }
1459 7c20b4a3 Gerd Hoffmann
}
1460 7c20b4a3 Gerd Hoffmann
1461 c78f7137 Gerd Hoffmann
void dpy_text_resize(QemuConsole *con, int w, int h)
1462 7c20b4a3 Gerd Hoffmann
{
1463 c78f7137 Gerd Hoffmann
    DisplayState *s = con->ds;
1464 7c20b4a3 Gerd Hoffmann
    struct DisplayChangeListener *dcl;
1465 321f048d Gerd Hoffmann
1466 81c0d5a6 Gerd Hoffmann
    if (!qemu_console_is_visible(con)) {
1467 321f048d Gerd Hoffmann
        return;
1468 321f048d Gerd Hoffmann
    }
1469 7c20b4a3 Gerd Hoffmann
    QLIST_FOREACH(dcl, &s->listeners, next) {
1470 284d1c6b Gerd Hoffmann
        if (con != (dcl->con ? dcl->con : active_console)) {
1471 284d1c6b Gerd Hoffmann
            continue;
1472 284d1c6b Gerd Hoffmann
        }
1473 7c20b4a3 Gerd Hoffmann
        if (dcl->ops->dpy_text_resize) {
1474 bc2ed970 Gerd Hoffmann
            dcl->ops->dpy_text_resize(dcl, w, h);
1475 7c20b4a3 Gerd Hoffmann
        }
1476 7c20b4a3 Gerd Hoffmann
    }
1477 7c20b4a3 Gerd Hoffmann
}
1478 7c20b4a3 Gerd Hoffmann
1479 c78f7137 Gerd Hoffmann
void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
1480 7c20b4a3 Gerd Hoffmann
{
1481 c78f7137 Gerd Hoffmann
    DisplayState *s = con->ds;
1482 284d1c6b Gerd Hoffmann
    DisplayChangeListener *dcl;
1483 321f048d Gerd Hoffmann
1484 81c0d5a6 Gerd Hoffmann
    if (!qemu_console_is_visible(con)) {
1485 321f048d Gerd Hoffmann
        return;
1486 321f048d Gerd Hoffmann
    }
1487 7c20b4a3 Gerd Hoffmann
    QLIST_FOREACH(dcl, &s->listeners, next) {
1488 284d1c6b Gerd Hoffmann
        if (con != (dcl->con ? dcl->con : active_console)) {
1489 284d1c6b Gerd Hoffmann
            continue;
1490 284d1c6b Gerd Hoffmann
        }
1491 7c20b4a3 Gerd Hoffmann
        if (dcl->ops->dpy_mouse_set) {
1492 bc2ed970 Gerd Hoffmann
            dcl->ops->dpy_mouse_set(dcl, x, y, on);
1493 7c20b4a3 Gerd Hoffmann
        }
1494 7c20b4a3 Gerd Hoffmann
    }
1495 7c20b4a3 Gerd Hoffmann
}
1496 7c20b4a3 Gerd Hoffmann
1497 c78f7137 Gerd Hoffmann
void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
1498 7c20b4a3 Gerd Hoffmann
{
1499 c78f7137 Gerd Hoffmann
    DisplayState *s = con->ds;
1500 284d1c6b Gerd Hoffmann
    DisplayChangeListener *dcl;
1501 321f048d Gerd Hoffmann
1502 81c0d5a6 Gerd Hoffmann
    if (!qemu_console_is_visible(con)) {
1503 321f048d Gerd Hoffmann
        return;
1504 321f048d Gerd Hoffmann
    }
1505 7c20b4a3 Gerd Hoffmann
    QLIST_FOREACH(dcl, &s->listeners, next) {
1506 284d1c6b Gerd Hoffmann
        if (con != (dcl->con ? dcl->con : active_console)) {
1507 284d1c6b Gerd Hoffmann
            continue;
1508 284d1c6b Gerd Hoffmann
        }
1509 7c20b4a3 Gerd Hoffmann
        if (dcl->ops->dpy_cursor_define) {
1510 bc2ed970 Gerd Hoffmann
            dcl->ops->dpy_cursor_define(dcl, cursor);
1511 7c20b4a3 Gerd Hoffmann
        }
1512 7c20b4a3 Gerd Hoffmann
    }
1513 7c20b4a3 Gerd Hoffmann
}
1514 7c20b4a3 Gerd Hoffmann
1515 c78f7137 Gerd Hoffmann
bool dpy_cursor_define_supported(QemuConsole *con)
1516 7c20b4a3 Gerd Hoffmann
{
1517 c78f7137 Gerd Hoffmann
    DisplayState *s = con->ds;
1518 284d1c6b Gerd Hoffmann
    DisplayChangeListener *dcl;
1519 284d1c6b Gerd Hoffmann
1520 7c20b4a3 Gerd Hoffmann
    QLIST_FOREACH(dcl, &s->listeners, next) {
1521 7c20b4a3 Gerd Hoffmann
        if (dcl->ops->dpy_cursor_define) {
1522 7c20b4a3 Gerd Hoffmann
            return true;
1523 7c20b4a3 Gerd Hoffmann
        }
1524 7c20b4a3 Gerd Hoffmann
    }
1525 7c20b4a3 Gerd Hoffmann
    return false;
1526 7c20b4a3 Gerd Hoffmann
}
1527 7c20b4a3 Gerd Hoffmann
1528 98b50080 Paolo Bonzini
/***********************************************************/
1529 98b50080 Paolo Bonzini
/* register display */
1530 98b50080 Paolo Bonzini
1531 64840c66 Gerd Hoffmann
/* console.c internal use only */
1532 64840c66 Gerd Hoffmann
static DisplayState *get_alloc_displaystate(void)
1533 98b50080 Paolo Bonzini
{
1534 64840c66 Gerd Hoffmann
    if (!display_state) {
1535 64840c66 Gerd Hoffmann
        display_state = g_new0(DisplayState, 1);
1536 64840c66 Gerd Hoffmann
    }
1537 64840c66 Gerd Hoffmann
    return display_state;
1538 98b50080 Paolo Bonzini
}
1539 98b50080 Paolo Bonzini
1540 64840c66 Gerd Hoffmann
/*
1541 64840c66 Gerd Hoffmann
 * Called by main(), after creating QemuConsoles
1542 64840c66 Gerd Hoffmann
 * and before initializing ui (sdl/vnc/...).
1543 64840c66 Gerd Hoffmann
 */
1544 64840c66 Gerd Hoffmann
DisplayState *init_displaystate(void)
1545 98b50080 Paolo Bonzini
{
1546 43f420f8 Gerd Hoffmann
    Error *local_err = NULL;
1547 43f420f8 Gerd Hoffmann
    gchar *name;
1548 64840c66 Gerd Hoffmann
    int i;
1549 64840c66 Gerd Hoffmann
1550 98b50080 Paolo Bonzini
    if (!display_state) {
1551 64840c66 Gerd Hoffmann
        display_state = g_new0(DisplayState, 1);
1552 98b50080 Paolo Bonzini
    }
1553 64840c66 Gerd Hoffmann
1554 64840c66 Gerd Hoffmann
    for (i = 0; i < nb_consoles; i++) {
1555 64840c66 Gerd Hoffmann
        if (consoles[i]->console_type != GRAPHIC_CONSOLE &&
1556 64840c66 Gerd Hoffmann
            consoles[i]->ds == NULL) {
1557 64840c66 Gerd Hoffmann
            text_console_do_init(consoles[i]->chr, display_state);
1558 64840c66 Gerd Hoffmann
        }
1559 43f420f8 Gerd Hoffmann
1560 43f420f8 Gerd Hoffmann
        /* Hook up into the qom tree here (not in new_console()), once
1561 43f420f8 Gerd Hoffmann
         * all QemuConsoles are created and the order / numbering
1562 43f420f8 Gerd Hoffmann
         * doesn't change any more */
1563 43f420f8 Gerd Hoffmann
        name = g_strdup_printf("console[%d]", i);
1564 43f420f8 Gerd Hoffmann
        object_property_add_child(container_get(object_get_root(), "/backend"),
1565 43f420f8 Gerd Hoffmann
                                  name, OBJECT(consoles[i]), &local_err);
1566 43f420f8 Gerd Hoffmann
        g_free(name);
1567 64840c66 Gerd Hoffmann
    }
1568 64840c66 Gerd Hoffmann
1569 98b50080 Paolo Bonzini
    return display_state;
1570 98b50080 Paolo Bonzini
}
1571 98b50080 Paolo Bonzini
1572 aa2beaa1 Gerd Hoffmann
QemuConsole *graphic_console_init(DeviceState *dev,
1573 aa2beaa1 Gerd Hoffmann
                                  const GraphicHwOps *hw_ops,
1574 c78f7137 Gerd Hoffmann
                                  void *opaque)
1575 95219897 pbrook
{
1576 aa2beaa1 Gerd Hoffmann
    Error *local_err = NULL;
1577 64840c66 Gerd Hoffmann
    int width = 640;
1578 64840c66 Gerd Hoffmann
    int height = 480;
1579 76ffb0b4 Gerd Hoffmann
    QemuConsole *s;
1580 3023f332 aliguori
    DisplayState *ds;
1581 f0f2f976 aurel32
1582 64840c66 Gerd Hoffmann
    ds = get_alloc_displaystate();
1583 437fe106 Gerd Hoffmann
    trace_console_gfx_new();
1584 af3a9031 ths
    s = new_console(ds, GRAPHIC_CONSOLE);
1585 380cd056 Gerd Hoffmann
    s->hw_ops = hw_ops;
1586 95219897 pbrook
    s->hw = opaque;
1587 aa2beaa1 Gerd Hoffmann
    if (dev) {
1588 aa2beaa1 Gerd Hoffmann
        object_property_set_link(OBJECT(s), OBJECT(dev),
1589 aa2beaa1 Gerd Hoffmann
                                 "device", &local_err);
1590 aa2beaa1 Gerd Hoffmann
    }
1591 3023f332 aliguori
1592 321f048d Gerd Hoffmann
    s->surface = qemu_create_displaysurface(width, height);
1593 c78f7137 Gerd Hoffmann
    return s;
1594 e7f0ad58 bellard
}
1595 e7f0ad58 bellard
1596 284d1c6b Gerd Hoffmann
QemuConsole *qemu_console_lookup_by_index(unsigned int index)
1597 284d1c6b Gerd Hoffmann
{
1598 284d1c6b Gerd Hoffmann
    if (index >= MAX_CONSOLES) {
1599 284d1c6b Gerd Hoffmann
        return NULL;
1600 284d1c6b Gerd Hoffmann
    }
1601 284d1c6b Gerd Hoffmann
    return consoles[index];
1602 284d1c6b Gerd Hoffmann
}
1603 284d1c6b Gerd Hoffmann
1604 14a93649 Gerd Hoffmann
QemuConsole *qemu_console_lookup_by_device(DeviceState *dev)
1605 14a93649 Gerd Hoffmann
{
1606 14a93649 Gerd Hoffmann
    Error *local_err = NULL;
1607 14a93649 Gerd Hoffmann
    Object *obj;
1608 14a93649 Gerd Hoffmann
    int i;
1609 14a93649 Gerd Hoffmann
1610 14a93649 Gerd Hoffmann
    for (i = 0; i < nb_consoles; i++) {
1611 14a93649 Gerd Hoffmann
        if (!consoles[i]) {
1612 14a93649 Gerd Hoffmann
            continue;
1613 14a93649 Gerd Hoffmann
        }
1614 14a93649 Gerd Hoffmann
        obj = object_property_get_link(OBJECT(consoles[i]),
1615 14a93649 Gerd Hoffmann
                                       "device", &local_err);
1616 14a93649 Gerd Hoffmann
        if (DEVICE(obj) == dev) {
1617 14a93649 Gerd Hoffmann
            return consoles[i];
1618 14a93649 Gerd Hoffmann
        }
1619 14a93649 Gerd Hoffmann
    }
1620 14a93649 Gerd Hoffmann
    return NULL;
1621 14a93649 Gerd Hoffmann
}
1622 14a93649 Gerd Hoffmann
1623 81c0d5a6 Gerd Hoffmann
bool qemu_console_is_visible(QemuConsole *con)
1624 e7f0ad58 bellard
{
1625 284d1c6b Gerd Hoffmann
    return (con == active_console) || (con->dcls > 0);
1626 e7f0ad58 bellard
}
1627 e7f0ad58 bellard
1628 81c0d5a6 Gerd Hoffmann
bool qemu_console_is_graphic(QemuConsole *con)
1629 c21bbcfa balrog
{
1630 81c0d5a6 Gerd Hoffmann
    if (con == NULL) {
1631 81c0d5a6 Gerd Hoffmann
        con = active_console;
1632 81c0d5a6 Gerd Hoffmann
    }
1633 81c0d5a6 Gerd Hoffmann
    return con && (con->console_type == GRAPHIC_CONSOLE);
1634 81c0d5a6 Gerd Hoffmann
}
1635 81c0d5a6 Gerd Hoffmann
1636 81c0d5a6 Gerd Hoffmann
bool qemu_console_is_fixedsize(QemuConsole *con)
1637 81c0d5a6 Gerd Hoffmann
{
1638 81c0d5a6 Gerd Hoffmann
    if (con == NULL) {
1639 81c0d5a6 Gerd Hoffmann
        con = active_console;
1640 81c0d5a6 Gerd Hoffmann
    }
1641 81c0d5a6 Gerd Hoffmann
    return con && (con->console_type != TEXT_CONSOLE);
1642 c21bbcfa balrog
}
1643 c21bbcfa balrog
1644 4104833f Paolo Bonzini
static void text_console_set_echo(CharDriverState *chr, bool echo)
1645 4104833f Paolo Bonzini
{
1646 76ffb0b4 Gerd Hoffmann
    QemuConsole *s = chr->opaque;
1647 4104833f Paolo Bonzini
1648 4104833f Paolo Bonzini
    s->echo = echo;
1649 4104833f Paolo Bonzini
}
1650 4104833f Paolo Bonzini
1651 bf1bed81 Jan Kiszka
static void text_console_update_cursor(void *opaque)
1652 bf1bed81 Jan Kiszka
{
1653 76ffb0b4 Gerd Hoffmann
    QemuConsole *s = opaque;
1654 bf1bed81 Jan Kiszka
1655 bf1bed81 Jan Kiszka
    s->cursor_visible_phase = !s->cursor_visible_phase;
1656 1dbfa005 Gerd Hoffmann
    graphic_hw_invalidate(s);
1657 bc72ad67 Alex Bligh
    timer_mod(s->cursor_timer,
1658 bc72ad67 Alex Bligh
                   qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2);
1659 bf1bed81 Jan Kiszka
}
1660 bf1bed81 Jan Kiszka
1661 380cd056 Gerd Hoffmann
static const GraphicHwOps text_console_ops = {
1662 380cd056 Gerd Hoffmann
    .invalidate  = text_console_invalidate,
1663 380cd056 Gerd Hoffmann
    .text_update = text_console_update,
1664 380cd056 Gerd Hoffmann
};
1665 380cd056 Gerd Hoffmann
1666 44b37b93 Paolo Bonzini
static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1667 e7f0ad58 bellard
{
1668 76ffb0b4 Gerd Hoffmann
    QemuConsole *s;
1669 36671fbd Gerd Hoffmann
    int g_width = 80 * FONT_WIDTH;
1670 36671fbd Gerd Hoffmann
    int g_height = 24 * FONT_HEIGHT;
1671 6d6f7c28 pbrook
1672 491e114a Paolo Bonzini
    s = chr->opaque;
1673 6ea314d9 Gerd Hoffmann
1674 e7f0ad58 bellard
    chr->chr_write = console_puts;
1675 6fcfafb7 bellard
1676 e15d7371 bellard
    s->out_fifo.buf = s->out_fifo_buf;
1677 e15d7371 bellard
    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1678 bc72ad67 Alex Bligh
    s->kbd_timer = timer_new_ms(QEMU_CLOCK_REALTIME, kbd_send_chars, s);
1679 3023f332 aliguori
    s->ds = ds;
1680 3b46e624 ths
1681 e7f0ad58 bellard
    s->y_displayed = 0;
1682 e7f0ad58 bellard
    s->y_base = 0;
1683 e7f0ad58 bellard
    s->total_height = DEFAULT_BACKSCROLL;
1684 e7f0ad58 bellard
    s->x = 0;
1685 e7f0ad58 bellard
    s->y = 0;
1686 36671fbd Gerd Hoffmann
    if (!s->surface) {
1687 321f048d Gerd Hoffmann
        if (active_console && active_console->surface) {
1688 36671fbd Gerd Hoffmann
            g_width = surface_width(active_console->surface);
1689 36671fbd Gerd Hoffmann
            g_height = surface_height(active_console->surface);
1690 321f048d Gerd Hoffmann
        }
1691 36671fbd Gerd Hoffmann
        s->surface = qemu_create_displaysurface(g_width, g_height);
1692 491e114a Paolo Bonzini
    }
1693 6d6f7c28 pbrook
1694 bf1bed81 Jan Kiszka
    s->cursor_timer =
1695 bc72ad67 Alex Bligh
        timer_new_ms(QEMU_CLOCK_REALTIME, text_console_update_cursor, s);
1696 bf1bed81 Jan Kiszka
1697 380cd056 Gerd Hoffmann
    s->hw_ops = &text_console_ops;
1698 4d3b6f6e balrog
    s->hw = s;
1699 4d3b6f6e balrog
1700 6d6f7c28 pbrook
    /* Set text attribute defaults */
1701 6d6f7c28 pbrook
    s->t_attrib_default.bold = 0;
1702 6d6f7c28 pbrook
    s->t_attrib_default.uline = 0;
1703 6d6f7c28 pbrook
    s->t_attrib_default.blink = 0;
1704 6d6f7c28 pbrook
    s->t_attrib_default.invers = 0;
1705 6d6f7c28 pbrook
    s->t_attrib_default.unvisible = 0;
1706 6d6f7c28 pbrook
    s->t_attrib_default.fgcol = COLOR_WHITE;
1707 6d6f7c28 pbrook
    s->t_attrib_default.bgcol = COLOR_BLACK;
1708 6d6f7c28 pbrook
    /* set current text attributes to default */
1709 6d6f7c28 pbrook
    s->t_attrib = s->t_attrib_default;
1710 e7f0ad58 bellard
    text_console_resize(s);
1711 e7f0ad58 bellard
1712 51bfa4d3 Gerd Hoffmann
    if (chr->label) {
1713 51bfa4d3 Gerd Hoffmann
        char msg[128];
1714 51bfa4d3 Gerd Hoffmann
        int len;
1715 51bfa4d3 Gerd Hoffmann
1716 735ba588 Gerd Hoffmann
        s->t_attrib.bgcol = COLOR_BLUE;
1717 51bfa4d3 Gerd Hoffmann
        len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1718 51bfa4d3 Gerd Hoffmann
        console_puts(chr, (uint8_t*)msg, len);
1719 735ba588 Gerd Hoffmann
        s->t_attrib = s->t_attrib_default;
1720 51bfa4d3 Gerd Hoffmann
    }
1721 51bfa4d3 Gerd Hoffmann
1722 fee204fd Hans de Goede
    qemu_chr_be_generic_open(chr);
1723 ceecf1d1 aurel32
    if (chr->init)
1724 ceecf1d1 aurel32
        chr->init(chr);
1725 e7f0ad58 bellard
}
1726 c60e08d9 pbrook
1727 702ec69c Gerd Hoffmann
static CharDriverState *text_console_init(ChardevVC *vc)
1728 2796dae0 aliguori
{
1729 2796dae0 aliguori
    CharDriverState *chr;
1730 76ffb0b4 Gerd Hoffmann
    QemuConsole *s;
1731 702ec69c Gerd Hoffmann
    unsigned width = 0;
1732 702ec69c Gerd Hoffmann
    unsigned height = 0;
1733 2796dae0 aliguori
1734 7267c094 Anthony Liguori
    chr = g_malloc0(sizeof(CharDriverState));
1735 2796dae0 aliguori
1736 702ec69c Gerd Hoffmann
    if (vc->has_width) {
1737 702ec69c Gerd Hoffmann
        width = vc->width;
1738 702ec69c Gerd Hoffmann
    } else if (vc->has_cols) {
1739 702ec69c Gerd Hoffmann
        width = vc->cols * FONT_WIDTH;
1740 702ec69c Gerd Hoffmann
    }
1741 491e114a Paolo Bonzini
1742 702ec69c Gerd Hoffmann
    if (vc->has_height) {
1743 702ec69c Gerd Hoffmann
        height = vc->height;
1744 702ec69c Gerd Hoffmann
    } else if (vc->has_rows) {
1745 702ec69c Gerd Hoffmann
        height = vc->rows * FONT_HEIGHT;
1746 702ec69c Gerd Hoffmann
    }
1747 491e114a Paolo Bonzini
1748 437fe106 Gerd Hoffmann
    trace_console_txt_new(width, height);
1749 491e114a Paolo Bonzini
    if (width == 0 || height == 0) {
1750 491e114a Paolo Bonzini
        s = new_console(NULL, TEXT_CONSOLE);
1751 491e114a Paolo Bonzini
    } else {
1752 491e114a Paolo Bonzini
        s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1753 36671fbd Gerd Hoffmann
        s->surface = qemu_create_displaysurface(width, height);
1754 491e114a Paolo Bonzini
    }
1755 491e114a Paolo Bonzini
1756 491e114a Paolo Bonzini
    if (!s) {
1757 5354d083 Stefan Weil
        g_free(chr);
1758 1f51470d Markus Armbruster
        return NULL;
1759 491e114a Paolo Bonzini
    }
1760 491e114a Paolo Bonzini
1761 491e114a Paolo Bonzini
    s->chr = chr;
1762 491e114a Paolo Bonzini
    chr->opaque = s;
1763 4104833f Paolo Bonzini
    chr->chr_set_echo = text_console_set_echo;
1764 bd5c51ee Michael Roth
    /* console/chardev init sometimes completes elsewhere in a 2nd
1765 bd5c51ee Michael Roth
     * stage, so defer OPENED events until they are fully initialized
1766 bd5c51ee Michael Roth
     */
1767 bd5c51ee Michael Roth
    chr->explicit_be_open = true;
1768 64840c66 Gerd Hoffmann
1769 64840c66 Gerd Hoffmann
    if (display_state) {
1770 64840c66 Gerd Hoffmann
        text_console_do_init(chr, display_state);
1771 64840c66 Gerd Hoffmann
    }
1772 1f51470d Markus Armbruster
    return chr;
1773 2796dae0 aliguori
}
1774 2796dae0 aliguori
1775 d82831db Anthony Liguori
static VcHandler *vc_handler = text_console_init;
1776 d82831db Anthony Liguori
1777 702ec69c Gerd Hoffmann
CharDriverState *vc_init(ChardevVC *vc)
1778 d82831db Anthony Liguori
{
1779 702ec69c Gerd Hoffmann
    return vc_handler(vc);
1780 d82831db Anthony Liguori
}
1781 d82831db Anthony Liguori
1782 d82831db Anthony Liguori
void register_vc_handler(VcHandler *handler)
1783 d82831db Anthony Liguori
{
1784 d82831db Anthony Liguori
    vc_handler = handler;
1785 d82831db Anthony Liguori
}
1786 d82831db Anthony Liguori
1787 c78f7137 Gerd Hoffmann
void qemu_console_resize(QemuConsole *s, int width, int height)
1788 c60e08d9 pbrook
{
1789 321f048d Gerd Hoffmann
    DisplaySurface *surface;
1790 321f048d Gerd Hoffmann
1791 321f048d Gerd Hoffmann
    assert(s->console_type == GRAPHIC_CONSOLE);
1792 321f048d Gerd Hoffmann
    surface = qemu_create_displaysurface(width, height);
1793 321f048d Gerd Hoffmann
    dpy_gfx_replace_surface(s, surface);
1794 c60e08d9 pbrook
}
1795 38334f76 balrog
1796 c78f7137 Gerd Hoffmann
void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
1797 3023f332 aliguori
                       int dst_x, int dst_y, int w, int h)
1798 c21bbcfa balrog
{
1799 321f048d Gerd Hoffmann
    assert(con->console_type == GRAPHIC_CONSOLE);
1800 321f048d Gerd Hoffmann
    dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h);
1801 38334f76 balrog
}
1802 7d957bd8 aliguori
1803 c78f7137 Gerd Hoffmann
DisplaySurface *qemu_console_surface(QemuConsole *console)
1804 c78f7137 Gerd Hoffmann
{
1805 321f048d Gerd Hoffmann
    return console->surface;
1806 c78f7137 Gerd Hoffmann
}
1807 c78f7137 Gerd Hoffmann
1808 c78f7137 Gerd Hoffmann
DisplayState *qemu_console_displaystate(QemuConsole *console)
1809 c78f7137 Gerd Hoffmann
{
1810 c78f7137 Gerd Hoffmann
    return console->ds;
1811 c78f7137 Gerd Hoffmann
}
1812 c78f7137 Gerd Hoffmann
1813 0da2ea1b malc
PixelFormat qemu_different_endianness_pixelformat(int bpp)
1814 7d957bd8 aliguori
{
1815 7d957bd8 aliguori
    PixelFormat pf;
1816 7d957bd8 aliguori
1817 7d957bd8 aliguori
    memset(&pf, 0x00, sizeof(PixelFormat));
1818 7d957bd8 aliguori
1819 7d957bd8 aliguori
    pf.bits_per_pixel = bpp;
1820 feadf1a4 BALATON Zoltan
    pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
1821 7d957bd8 aliguori
    pf.depth = bpp == 32 ? 24 : bpp;
1822 7d957bd8 aliguori
1823 7d957bd8 aliguori
    switch (bpp) {
1824 0da2ea1b malc
        case 24:
1825 0da2ea1b malc
            pf.rmask = 0x000000FF;
1826 0da2ea1b malc
            pf.gmask = 0x0000FF00;
1827 0da2ea1b malc
            pf.bmask = 0x00FF0000;
1828 0da2ea1b malc
            pf.rmax = 255;
1829 0da2ea1b malc
            pf.gmax = 255;
1830 0da2ea1b malc
            pf.bmax = 255;
1831 0da2ea1b malc
            pf.rshift = 0;
1832 0da2ea1b malc
            pf.gshift = 8;
1833 0da2ea1b malc
            pf.bshift = 16;
1834 90a1e3c0 aliguori
            pf.rbits = 8;
1835 90a1e3c0 aliguori
            pf.gbits = 8;
1836 90a1e3c0 aliguori
            pf.bbits = 8;
1837 7d957bd8 aliguori
            break;
1838 0da2ea1b malc
        case 32:
1839 0da2ea1b malc
            pf.rmask = 0x0000FF00;
1840 0da2ea1b malc
            pf.gmask = 0x00FF0000;
1841 0da2ea1b malc
            pf.bmask = 0xFF000000;
1842 0da2ea1b malc
            pf.amask = 0x00000000;
1843 0da2ea1b malc
            pf.amax = 255;
1844 0da2ea1b malc
            pf.rmax = 255;
1845 0da2ea1b malc
            pf.gmax = 255;
1846 0da2ea1b malc
            pf.bmax = 255;
1847 0da2ea1b malc
            pf.ashift = 0;
1848 0da2ea1b malc
            pf.rshift = 8;
1849 0da2ea1b malc
            pf.gshift = 16;
1850 0da2ea1b malc
            pf.bshift = 24;
1851 90a1e3c0 aliguori
            pf.rbits = 8;
1852 90a1e3c0 aliguori
            pf.gbits = 8;
1853 90a1e3c0 aliguori
            pf.bbits = 8;
1854 90a1e3c0 aliguori
            pf.abits = 8;
1855 0da2ea1b malc
            break;
1856 0da2ea1b malc
        default:
1857 0da2ea1b malc
            break;
1858 0da2ea1b malc
    }
1859 0da2ea1b malc
    return pf;
1860 0da2ea1b malc
}
1861 0da2ea1b malc
1862 0da2ea1b malc
PixelFormat qemu_default_pixelformat(int bpp)
1863 0da2ea1b malc
{
1864 0da2ea1b malc
    PixelFormat pf;
1865 0da2ea1b malc
1866 0da2ea1b malc
    memset(&pf, 0x00, sizeof(PixelFormat));
1867 0da2ea1b malc
1868 0da2ea1b malc
    pf.bits_per_pixel = bpp;
1869 feadf1a4 BALATON Zoltan
    pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
1870 0da2ea1b malc
    pf.depth = bpp == 32 ? 24 : bpp;
1871 0da2ea1b malc
1872 0da2ea1b malc
    switch (bpp) {
1873 b6278084 Gerd Hoffmann
        case 15:
1874 b6278084 Gerd Hoffmann
            pf.bits_per_pixel = 16;
1875 b6278084 Gerd Hoffmann
            pf.rmask = 0x00007c00;
1876 b6278084 Gerd Hoffmann
            pf.gmask = 0x000003E0;
1877 b6278084 Gerd Hoffmann
            pf.bmask = 0x0000001F;
1878 b6278084 Gerd Hoffmann
            pf.rmax = 31;
1879 b6278084 Gerd Hoffmann
            pf.gmax = 31;
1880 b6278084 Gerd Hoffmann
            pf.bmax = 31;
1881 b6278084 Gerd Hoffmann
            pf.rshift = 10;
1882 b6278084 Gerd Hoffmann
            pf.gshift = 5;
1883 b6278084 Gerd Hoffmann
            pf.bshift = 0;
1884 b6278084 Gerd Hoffmann
            pf.rbits = 5;
1885 b6278084 Gerd Hoffmann
            pf.gbits = 5;
1886 b6278084 Gerd Hoffmann
            pf.bbits = 5;
1887 b6278084 Gerd Hoffmann
            break;
1888 7d957bd8 aliguori
        case 16:
1889 7d957bd8 aliguori
            pf.rmask = 0x0000F800;
1890 7d957bd8 aliguori
            pf.gmask = 0x000007E0;
1891 7d957bd8 aliguori
            pf.bmask = 0x0000001F;
1892 7d957bd8 aliguori
            pf.rmax = 31;
1893 7d957bd8 aliguori
            pf.gmax = 63;
1894 7d957bd8 aliguori
            pf.bmax = 31;
1895 7d957bd8 aliguori
            pf.rshift = 11;
1896 7d957bd8 aliguori
            pf.gshift = 5;
1897 7d957bd8 aliguori
            pf.bshift = 0;
1898 90a1e3c0 aliguori
            pf.rbits = 5;
1899 90a1e3c0 aliguori
            pf.gbits = 6;
1900 90a1e3c0 aliguori
            pf.bbits = 5;
1901 7d957bd8 aliguori
            break;
1902 7d957bd8 aliguori
        case 24:
1903 0da2ea1b malc
            pf.rmask = 0x00FF0000;
1904 0da2ea1b malc
            pf.gmask = 0x0000FF00;
1905 0da2ea1b malc
            pf.bmask = 0x000000FF;
1906 0da2ea1b malc
            pf.rmax = 255;
1907 0da2ea1b malc
            pf.gmax = 255;
1908 0da2ea1b malc
            pf.bmax = 255;
1909 0da2ea1b malc
            pf.rshift = 16;
1910 0da2ea1b malc
            pf.gshift = 8;
1911 0da2ea1b malc
            pf.bshift = 0;
1912 90a1e3c0 aliguori
            pf.rbits = 8;
1913 90a1e3c0 aliguori
            pf.gbits = 8;
1914 90a1e3c0 aliguori
            pf.bbits = 8;
1915 0eba62e0 Markus Armbruster
            break;
1916 7d957bd8 aliguori
        case 32:
1917 7d957bd8 aliguori
            pf.rmask = 0x00FF0000;
1918 7d957bd8 aliguori
            pf.gmask = 0x0000FF00;
1919 7d957bd8 aliguori
            pf.bmask = 0x000000FF;
1920 7d957bd8 aliguori
            pf.rmax = 255;
1921 7d957bd8 aliguori
            pf.gmax = 255;
1922 7d957bd8 aliguori
            pf.bmax = 255;
1923 7d957bd8 aliguori
            pf.rshift = 16;
1924 7d957bd8 aliguori
            pf.gshift = 8;
1925 7d957bd8 aliguori
            pf.bshift = 0;
1926 90a1e3c0 aliguori
            pf.rbits = 8;
1927 90a1e3c0 aliguori
            pf.gbits = 8;
1928 90a1e3c0 aliguori
            pf.bbits = 8;
1929 7d957bd8 aliguori
            break;
1930 7d957bd8 aliguori
        default:
1931 7d957bd8 aliguori
            break;
1932 7d957bd8 aliguori
    }
1933 7d957bd8 aliguori
    return pf;
1934 7d957bd8 aliguori
}
1935 01f45d98 Anthony Liguori
1936 702ec69c Gerd Hoffmann
static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend,
1937 702ec69c Gerd Hoffmann
                              Error **errp)
1938 702ec69c Gerd Hoffmann
{
1939 702ec69c Gerd Hoffmann
    int val;
1940 702ec69c Gerd Hoffmann
1941 702ec69c Gerd Hoffmann
    backend->vc = g_new0(ChardevVC, 1);
1942 702ec69c Gerd Hoffmann
1943 702ec69c Gerd Hoffmann
    val = qemu_opt_get_number(opts, "width", 0);
1944 702ec69c Gerd Hoffmann
    if (val != 0) {
1945 702ec69c Gerd Hoffmann
        backend->vc->has_width = true;
1946 702ec69c Gerd Hoffmann
        backend->vc->width = val;
1947 702ec69c Gerd Hoffmann
    }
1948 702ec69c Gerd Hoffmann
1949 702ec69c Gerd Hoffmann
    val = qemu_opt_get_number(opts, "height", 0);
1950 702ec69c Gerd Hoffmann
    if (val != 0) {
1951 702ec69c Gerd Hoffmann
        backend->vc->has_height = true;
1952 702ec69c Gerd Hoffmann
        backend->vc->height = val;
1953 702ec69c Gerd Hoffmann
    }
1954 702ec69c Gerd Hoffmann
1955 702ec69c Gerd Hoffmann
    val = qemu_opt_get_number(opts, "cols", 0);
1956 702ec69c Gerd Hoffmann
    if (val != 0) {
1957 702ec69c Gerd Hoffmann
        backend->vc->has_cols = true;
1958 702ec69c Gerd Hoffmann
        backend->vc->cols = val;
1959 702ec69c Gerd Hoffmann
    }
1960 702ec69c Gerd Hoffmann
1961 702ec69c Gerd Hoffmann
    val = qemu_opt_get_number(opts, "rows", 0);
1962 702ec69c Gerd Hoffmann
    if (val != 0) {
1963 702ec69c Gerd Hoffmann
        backend->vc->has_rows = true;
1964 702ec69c Gerd Hoffmann
        backend->vc->rows = val;
1965 702ec69c Gerd Hoffmann
    }
1966 702ec69c Gerd Hoffmann
}
1967 702ec69c Gerd Hoffmann
1968 95be0669 Gerd Hoffmann
static const TypeInfo qemu_console_info = {
1969 95be0669 Gerd Hoffmann
    .name = TYPE_QEMU_CONSOLE,
1970 95be0669 Gerd Hoffmann
    .parent = TYPE_OBJECT,
1971 95be0669 Gerd Hoffmann
    .instance_size = sizeof(QemuConsole),
1972 95be0669 Gerd Hoffmann
    .class_size = sizeof(QemuConsoleClass),
1973 95be0669 Gerd Hoffmann
};
1974 95be0669 Gerd Hoffmann
1975 95be0669 Gerd Hoffmann
1976 01f45d98 Anthony Liguori
static void register_types(void)
1977 01f45d98 Anthony Liguori
{
1978 95be0669 Gerd Hoffmann
    type_register_static(&qemu_console_info);
1979 702ec69c Gerd Hoffmann
    register_char_driver_qapi("vc", CHARDEV_BACKEND_KIND_VC,
1980 702ec69c Gerd Hoffmann
                              qemu_chr_parse_vc);
1981 01f45d98 Anthony Liguori
}
1982 01f45d98 Anthony Liguori
1983 01f45d98 Anthony Liguori
type_init(register_types);