Statistics
| Branch: | Revision:

root / sdl.c @ 3af12c86

History | View | Annotate | Download (27.8 kB)

1
/*
2
 * QEMU SDL display driver
3
 *
4
 * Copyright (c) 2003 Fabrice Bellard
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include <SDL.h>
25
#include <SDL_syswm.h>
26

    
27
#ifndef _WIN32
28
#include <signal.h>
29
#endif
30

    
31
#include "qemu-common.h"
32
#include "console.h"
33
#include "sysemu.h"
34
#include "x_keymap.h"
35
#include "sdl_zoom.h"
36

    
37
static DisplayChangeListener *dcl;
38
static SDL_Surface *real_screen;
39
static SDL_Surface *guest_screen = NULL;
40
static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
41
static int last_vm_running;
42
static int gui_saved_grab;
43
static int gui_fullscreen;
44
static int gui_noframe;
45
static int gui_key_modifier_pressed;
46
static int gui_keysym;
47
static int gui_fullscreen_initial_grab;
48
static int gui_grab_code = KMOD_LALT | KMOD_LCTRL;
49
static uint8_t modifiers_state[256];
50
static int width, height;
51
static SDL_Cursor *sdl_cursor_normal;
52
static SDL_Cursor *sdl_cursor_hidden;
53
static int absolute_enabled = 0;
54
static int guest_cursor = 0;
55
static int guest_x, guest_y;
56
static SDL_Cursor *guest_sprite = NULL;
57
static uint8_t allocator;
58
static SDL_PixelFormat host_format;
59
static int scaling_active = 0;
60
static Notifier mouse_mode_notifier;
61

    
62
static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
63
{
64
    //    printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
65
    SDL_Rect rec;
66
    rec.x = x;
67
    rec.y = y;
68
    rec.w = w;
69
    rec.h = h;
70

    
71
    if (guest_screen) {
72
        if (!scaling_active) {
73
            SDL_BlitSurface(guest_screen, &rec, real_screen, &rec);
74
        } else {
75
            if (sdl_zoom_blit(guest_screen, real_screen, SMOOTHING_ON, &rec) < 0) {
76
                fprintf(stderr, "Zoom blit failed\n");
77
                exit(1);
78
            }
79
        }
80
    } 
81
    SDL_UpdateRect(real_screen, rec.x, rec.y, rec.w, rec.h);
82
}
83

    
84
static void sdl_setdata(DisplayState *ds)
85
{
86
    SDL_Rect rec;
87
    rec.x = 0;
88
    rec.y = 0;
89
    rec.w = real_screen->w;
90
    rec.h = real_screen->h;
91

    
92
    if (guest_screen != NULL) SDL_FreeSurface(guest_screen);
93

    
94
    guest_screen = SDL_CreateRGBSurfaceFrom(ds_get_data(ds), ds_get_width(ds), ds_get_height(ds),
95
                                            ds_get_bits_per_pixel(ds), ds_get_linesize(ds),
96
                                            ds->surface->pf.rmask, ds->surface->pf.gmask,
97
                                            ds->surface->pf.bmask, ds->surface->pf.amask);
98
}
99

    
100
static void do_sdl_resize(int new_width, int new_height, int bpp)
101
{
102
    int flags;
103

    
104
    //    printf("resizing to %d %d\n", w, h);
105

    
106
    flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_RESIZABLE;
107
    if (gui_fullscreen)
108
        flags |= SDL_FULLSCREEN;
109
    if (gui_noframe)
110
        flags |= SDL_NOFRAME;
111

    
112
    width = new_width;
113
    height = new_height;
114
    real_screen = SDL_SetVideoMode(width, height, bpp, flags);
115
    if (!real_screen) {
116
        fprintf(stderr, "Could not open SDL display (%dx%dx%d): %s\n", width, 
117
                height, bpp, SDL_GetError());
118
        exit(1);
119
    }
120
}
121

    
122
static void sdl_resize(DisplayState *ds)
123
{
124
    if  (!allocator) {
125
        if (!scaling_active)
126
            do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
127
        else if (real_screen->format->BitsPerPixel != ds_get_bits_per_pixel(ds))
128
            do_sdl_resize(real_screen->w, real_screen->h, ds_get_bits_per_pixel(ds));
129
        sdl_setdata(ds);
130
    } else {
131
        if (guest_screen != NULL) {
132
            SDL_FreeSurface(guest_screen);
133
            guest_screen = NULL;
134
        }
135
    }
136
}
137

    
138
static PixelFormat sdl_to_qemu_pixelformat(SDL_PixelFormat *sdl_pf)
139
{
140
    PixelFormat qemu_pf;
141

    
142
    memset(&qemu_pf, 0x00, sizeof(PixelFormat));
143

    
144
    qemu_pf.bits_per_pixel = sdl_pf->BitsPerPixel;
145
    qemu_pf.bytes_per_pixel = sdl_pf->BytesPerPixel;
146
    qemu_pf.depth = (qemu_pf.bits_per_pixel) == 32 ? 24 : (qemu_pf.bits_per_pixel);
147

    
148
    qemu_pf.rmask = sdl_pf->Rmask;
149
    qemu_pf.gmask = sdl_pf->Gmask;
150
    qemu_pf.bmask = sdl_pf->Bmask;
151
    qemu_pf.amask = sdl_pf->Amask;
152

    
153
    qemu_pf.rshift = sdl_pf->Rshift;
154
    qemu_pf.gshift = sdl_pf->Gshift;
155
    qemu_pf.bshift = sdl_pf->Bshift;
156
    qemu_pf.ashift = sdl_pf->Ashift;
157

    
158
    qemu_pf.rbits = 8 - sdl_pf->Rloss;
159
    qemu_pf.gbits = 8 - sdl_pf->Gloss;
160
    qemu_pf.bbits = 8 - sdl_pf->Bloss;
161
    qemu_pf.abits = 8 - sdl_pf->Aloss;
162

    
163
    qemu_pf.rmax = ((1 << qemu_pf.rbits) - 1);
164
    qemu_pf.gmax = ((1 << qemu_pf.gbits) - 1);
165
    qemu_pf.bmax = ((1 << qemu_pf.bbits) - 1);
166
    qemu_pf.amax = ((1 << qemu_pf.abits) - 1);
167

    
168
    return qemu_pf;
169
}
170

    
171
static DisplaySurface* sdl_create_displaysurface(int width, int height)
172
{
173
    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
174
    if (surface == NULL) {
175
        fprintf(stderr, "sdl_create_displaysurface: malloc failed\n");
176
        exit(1);
177
    }
178

    
179
    surface->width = width;
180
    surface->height = height;
181
    
182
    if (scaling_active) {
183
        if (host_format.BytesPerPixel != 2 && host_format.BytesPerPixel != 4) {
184
            surface->linesize = width * 4;
185
            surface->pf = qemu_default_pixelformat(32);
186
        } else {
187
            surface->linesize = width * host_format.BytesPerPixel;
188
            surface->pf = sdl_to_qemu_pixelformat(&host_format);
189
        }
190
#ifdef HOST_WORDS_BIGENDIAN
191
        surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
192
#else
193
        surface->flags = QEMU_ALLOCATED_FLAG;
194
#endif
195
        surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
196

    
197
        return surface;
198
    }
199

    
200
    if (host_format.BitsPerPixel == 16)
201
        do_sdl_resize(width, height, 16);
202
    else
203
        do_sdl_resize(width, height, 32);
204

    
205
    surface->pf = sdl_to_qemu_pixelformat(real_screen->format);
206
    surface->linesize = real_screen->pitch;
207
    surface->data = real_screen->pixels;
208

    
209
#ifdef HOST_WORDS_BIGENDIAN
210
    surface->flags = QEMU_REALPIXELS_FLAG | QEMU_BIG_ENDIAN_FLAG;
211
#else
212
    surface->flags = QEMU_REALPIXELS_FLAG;
213
#endif
214
    allocator = 1;
215

    
216
    return surface;
217
}
218

    
219
static void sdl_free_displaysurface(DisplaySurface *surface)
220
{
221
    allocator = 0;
222
    if (surface == NULL)
223
        return;
224

    
225
    if (surface->flags & QEMU_ALLOCATED_FLAG)
226
        qemu_free(surface->data);
227
    qemu_free(surface);
228
}
229

    
230
static DisplaySurface* sdl_resize_displaysurface(DisplaySurface *surface, int width, int height)
231
{
232
    sdl_free_displaysurface(surface);
233
    return sdl_create_displaysurface(width, height);
234
}
235

    
236
/* generic keyboard conversion */
237

    
238
#include "sdl_keysym.h"
239

    
240
static kbd_layout_t *kbd_layout = NULL;
241

    
242
static uint8_t sdl_keyevent_to_keycode_generic(const SDL_KeyboardEvent *ev)
243
{
244
    int keysym;
245
    /* workaround for X11+SDL bug with AltGR */
246
    keysym = ev->keysym.sym;
247
    if (keysym == 0 && ev->keysym.scancode == 113)
248
        keysym = SDLK_MODE;
249
    /* For Japanese key '\' and '|' */
250
    if (keysym == 92 && ev->keysym.scancode == 133) {
251
        keysym = 0xa5;
252
    }
253
    return keysym2scancode(kbd_layout, keysym) & SCANCODE_KEYMASK;
254
}
255

    
256
/* specific keyboard conversions from scan codes */
257

    
258
#if defined(_WIN32)
259

    
260
static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
261
{
262
    return ev->keysym.scancode;
263
}
264

    
265
#else
266

    
267
#if defined(SDL_VIDEO_DRIVER_X11)
268
#include <X11/XKBlib.h>
269

    
270
static int check_for_evdev(void)
271
{
272
    SDL_SysWMinfo info;
273
    XkbDescPtr desc = NULL;
274
    int has_evdev = 0;
275
    char *keycodes = NULL;
276

    
277
    SDL_VERSION(&info.version);
278
    if (!SDL_GetWMInfo(&info)) {
279
        return 0;
280
    }
281
    desc = XkbGetKeyboard(info.info.x11.display,
282
                          XkbGBN_AllComponentsMask,
283
                          XkbUseCoreKbd);
284
    if (desc && desc->names) {
285
        keycodes = XGetAtomName(info.info.x11.display, desc->names->keycodes);
286
        if (keycodes == NULL) {
287
            fprintf(stderr, "could not lookup keycode name\n");
288
        } else if (strstart(keycodes, "evdev", NULL)) {
289
            has_evdev = 1;
290
        } else if (!strstart(keycodes, "xfree86", NULL)) {
291
            fprintf(stderr, "unknown keycodes `%s', please report to "
292
                    "qemu-devel@nongnu.org\n", keycodes);
293
        }
294
    }
295

    
296
    if (desc) {
297
        XkbFreeKeyboard(desc, XkbGBN_AllComponentsMask, True);
298
    }
299
    if (keycodes) {
300
        XFree(keycodes);
301
    }
302
    return has_evdev;
303
}
304
#else
305
static int check_for_evdev(void)
306
{
307
        return 0;
308
}
309
#endif
310

    
311
static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
312
{
313
    int keycode;
314
    static int has_evdev = -1;
315

    
316
    if (has_evdev == -1)
317
        has_evdev = check_for_evdev();
318

    
319
    keycode = ev->keysym.scancode;
320

    
321
    if (keycode < 9) {
322
        keycode = 0;
323
    } else if (keycode < 97) {
324
        keycode -= 8; /* just an offset */
325
    } else if (keycode < 158) {
326
        /* use conversion table */
327
        if (has_evdev)
328
            keycode = translate_evdev_keycode(keycode - 97);
329
        else
330
            keycode = translate_xfree86_keycode(keycode - 97);
331
    } else if (keycode == 208) { /* Hiragana_Katakana */
332
        keycode = 0x70;
333
    } else if (keycode == 211) { /* backslash */
334
        keycode = 0x73;
335
    } else {
336
        keycode = 0;
337
    }
338
    return keycode;
339
}
340

    
341
#endif
342

    
343
static void reset_keys(void)
344
{
345
    int i;
346
    for(i = 0; i < 256; i++) {
347
        if (modifiers_state[i]) {
348
            if (i & SCANCODE_GREY)
349
                kbd_put_keycode(SCANCODE_EMUL0);
350
            kbd_put_keycode(i | SCANCODE_UP);
351
            modifiers_state[i] = 0;
352
        }
353
    }
354
}
355

    
356
static void sdl_process_key(SDL_KeyboardEvent *ev)
357
{
358
    int keycode, v;
359

    
360
    if (ev->keysym.sym == SDLK_PAUSE) {
361
        /* specific case */
362
        v = 0;
363
        if (ev->type == SDL_KEYUP)
364
            v |= SCANCODE_UP;
365
        kbd_put_keycode(0xe1);
366
        kbd_put_keycode(0x1d | v);
367
        kbd_put_keycode(0x45 | v);
368
        return;
369
    }
370

    
371
    if (kbd_layout) {
372
        keycode = sdl_keyevent_to_keycode_generic(ev);
373
    } else {
374
        keycode = sdl_keyevent_to_keycode(ev);
375
    }
376

    
377
    switch(keycode) {
378
    case 0x00:
379
        /* sent when leaving window: reset the modifiers state */
380
        reset_keys();
381
        return;
382
    case 0x2a:                          /* Left Shift */
383
    case 0x36:                          /* Right Shift */
384
    case 0x1d:                          /* Left CTRL */
385
    case 0x9d:                          /* Right CTRL */
386
    case 0x38:                          /* Left ALT */
387
    case 0xb8:                         /* Right ALT */
388
        if (ev->type == SDL_KEYUP)
389
            modifiers_state[keycode] = 0;
390
        else
391
            modifiers_state[keycode] = 1;
392
        break;
393
    case 0x45: /* num lock */
394
    case 0x3a: /* caps lock */
395
        /* SDL does not send the key up event, so we generate it */
396
        kbd_put_keycode(keycode);
397
        kbd_put_keycode(keycode | SCANCODE_UP);
398
        return;
399
    }
400

    
401
    /* now send the key code */
402
    if (keycode & SCANCODE_GREY)
403
        kbd_put_keycode(SCANCODE_EMUL0);
404
    if (ev->type == SDL_KEYUP)
405
        kbd_put_keycode(keycode | SCANCODE_UP);
406
    else
407
        kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
408
}
409

    
410
static void sdl_update_caption(void)
411
{
412
    char win_title[1024];
413
    char icon_title[1024];
414
    const char *status = "";
415

    
416
    if (!vm_running)
417
        status = " [Stopped]";
418
    else if (gui_grab) {
419
        if (alt_grab)
420
            status = " - Press Ctrl-Alt-Shift to exit mouse grab";
421
        else if (ctrl_grab)
422
            status = " - Press Right-Ctrl to exit mouse grab";
423
        else
424
            status = " - Press Ctrl-Alt to exit mouse grab";
425
    }
426

    
427
    if (qemu_name) {
428
        snprintf(win_title, sizeof(win_title), "QEMU (%s)%s", qemu_name, status);
429
        snprintf(icon_title, sizeof(icon_title), "QEMU (%s)", qemu_name);
430
    } else {
431
        snprintf(win_title, sizeof(win_title), "QEMU%s", status);
432
        snprintf(icon_title, sizeof(icon_title), "QEMU");
433
    }
434

    
435
    SDL_WM_SetCaption(win_title, icon_title);
436
}
437

    
438
static void sdl_hide_cursor(void)
439
{
440
    if (!cursor_hide)
441
        return;
442

    
443
    if (kbd_mouse_is_absolute()) {
444
        SDL_ShowCursor(1);
445
        SDL_SetCursor(sdl_cursor_hidden);
446
    } else {
447
        SDL_ShowCursor(0);
448
    }
449
}
450

    
451
static void sdl_show_cursor(void)
452
{
453
    if (!cursor_hide)
454
        return;
455

    
456
    if (!kbd_mouse_is_absolute()) {
457
        SDL_ShowCursor(1);
458
        if (guest_cursor &&
459
                (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
460
            SDL_SetCursor(guest_sprite);
461
        else
462
            SDL_SetCursor(sdl_cursor_normal);
463
    }
464
}
465

    
466
static void sdl_grab_start(void)
467
{
468
    if (guest_cursor) {
469
        SDL_SetCursor(guest_sprite);
470
        if (!kbd_mouse_is_absolute() && !absolute_enabled)
471
            SDL_WarpMouse(guest_x, guest_y);
472
    } else
473
        sdl_hide_cursor();
474

    
475
    if (SDL_WM_GrabInput(SDL_GRAB_ON) == SDL_GRAB_ON) {
476
        gui_grab = 1;
477
        sdl_update_caption();
478
    } else
479
        sdl_show_cursor();
480
}
481

    
482
static void sdl_grab_end(void)
483
{
484
    SDL_WM_GrabInput(SDL_GRAB_OFF);
485
    gui_grab = 0;
486
    sdl_show_cursor();
487
    sdl_update_caption();
488
}
489

    
490
static void sdl_mouse_mode_change(Notifier *notify)
491
{
492
    if (kbd_mouse_is_absolute()) {
493
        if (!absolute_enabled) {
494
            sdl_hide_cursor();
495
            if (gui_grab) {
496
                sdl_grab_end();
497
            }
498
            absolute_enabled = 1;
499
        }
500
    } else if (absolute_enabled) {
501
        sdl_show_cursor();
502
        absolute_enabled = 0;
503
    }
504
}
505

    
506
static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state)
507
{
508
    int buttons;
509
    buttons = 0;
510
    if (state & SDL_BUTTON(SDL_BUTTON_LEFT))
511
        buttons |= MOUSE_EVENT_LBUTTON;
512
    if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
513
        buttons |= MOUSE_EVENT_RBUTTON;
514
    if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE))
515
        buttons |= MOUSE_EVENT_MBUTTON;
516

    
517
    if (kbd_mouse_is_absolute()) {
518
       dx = x * 0x7FFF / (width - 1);
519
       dy = y * 0x7FFF / (height - 1);
520
    } else if (guest_cursor) {
521
        x -= guest_x;
522
        y -= guest_y;
523
        guest_x += x;
524
        guest_y += y;
525
        dx = x;
526
        dy = y;
527
    }
528

    
529
    kbd_mouse_event(dx, dy, dz, buttons);
530
}
531

    
532
static void toggle_full_screen(DisplayState *ds)
533
{
534
    gui_fullscreen = !gui_fullscreen;
535
    do_sdl_resize(real_screen->w, real_screen->h, real_screen->format->BitsPerPixel);
536
    if (gui_fullscreen) {
537
        scaling_active = 0;
538
        gui_saved_grab = gui_grab;
539
        sdl_grab_start();
540
    } else {
541
        if (!gui_saved_grab)
542
            sdl_grab_end();
543
    }
544
    vga_hw_invalidate();
545
    vga_hw_update();
546
}
547

    
548
static void sdl_refresh(DisplayState *ds)
549
{
550
    SDL_Event ev1, *ev = &ev1;
551
    int mod_state;
552
    int buttonstate = SDL_GetMouseState(NULL, NULL);
553

    
554
    if (last_vm_running != vm_running) {
555
        last_vm_running = vm_running;
556
        sdl_update_caption();
557
    }
558

    
559
    vga_hw_update();
560
    SDL_EnableUNICODE(!is_graphic_console());
561

    
562
    while (SDL_PollEvent(ev)) {
563
        switch (ev->type) {
564
        case SDL_VIDEOEXPOSE:
565
            sdl_update(ds, 0, 0, real_screen->w, real_screen->h);
566
            break;
567
        case SDL_KEYDOWN:
568
        case SDL_KEYUP:
569
            if (ev->type == SDL_KEYDOWN) {
570
                if (alt_grab) {
571
                    mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) ==
572
                                (gui_grab_code | KMOD_LSHIFT);
573
                } else if (ctrl_grab) {
574
                    mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL;
575
                } else {
576
                    mod_state = (SDL_GetModState() & gui_grab_code) ==
577
                                gui_grab_code;
578
                }
579
                gui_key_modifier_pressed = mod_state;
580
                if (gui_key_modifier_pressed) {
581
                    int keycode;
582
                    keycode = sdl_keyevent_to_keycode(&ev->key);
583
                    switch(keycode) {
584
                    case 0x21: /* 'f' key on US keyboard */
585
                        toggle_full_screen(ds);
586
                        gui_keysym = 1;
587
                        break;
588
                    case 0x16: /* 'u' key on US keyboard */
589
                        scaling_active = 0;
590
                        sdl_resize(ds);
591
                        vga_hw_invalidate();
592
                        vga_hw_update();
593
                        break;
594
                    case 0x02 ... 0x0a: /* '1' to '9' keys */
595
                        /* Reset the modifiers sent to the current console */
596
                        reset_keys();
597
                        console_select(keycode - 0x02);
598
                        if (!is_graphic_console()) {
599
                            /* display grab if going to a text console */
600
                            if (gui_grab)
601
                                sdl_grab_end();
602
                        }
603
                        gui_keysym = 1;
604
                        break;
605
                    default:
606
                        break;
607
                    }
608
                } else if (!is_graphic_console()) {
609
                    int keysym;
610
                    keysym = 0;
611
                    if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
612
                        switch(ev->key.keysym.sym) {
613
                        case SDLK_UP: keysym = QEMU_KEY_CTRL_UP; break;
614
                        case SDLK_DOWN: keysym = QEMU_KEY_CTRL_DOWN; break;
615
                        case SDLK_LEFT: keysym = QEMU_KEY_CTRL_LEFT; break;
616
                        case SDLK_RIGHT: keysym = QEMU_KEY_CTRL_RIGHT; break;
617
                        case SDLK_HOME: keysym = QEMU_KEY_CTRL_HOME; break;
618
                        case SDLK_END: keysym = QEMU_KEY_CTRL_END; break;
619
                        case SDLK_PAGEUP: keysym = QEMU_KEY_CTRL_PAGEUP; break;
620
                        case SDLK_PAGEDOWN: keysym = QEMU_KEY_CTRL_PAGEDOWN; break;
621
                        default: break;
622
                        }
623
                    } else {
624
                        switch(ev->key.keysym.sym) {
625
                        case SDLK_UP: keysym = QEMU_KEY_UP; break;
626
                        case SDLK_DOWN: keysym = QEMU_KEY_DOWN; break;
627
                        case SDLK_LEFT: keysym = QEMU_KEY_LEFT; break;
628
                        case SDLK_RIGHT: keysym = QEMU_KEY_RIGHT; break;
629
                        case SDLK_HOME: keysym = QEMU_KEY_HOME; break;
630
                        case SDLK_END: keysym = QEMU_KEY_END; break;
631
                        case SDLK_PAGEUP: keysym = QEMU_KEY_PAGEUP; break;
632
                        case SDLK_PAGEDOWN: keysym = QEMU_KEY_PAGEDOWN; break;
633
                        case SDLK_BACKSPACE: keysym = QEMU_KEY_BACKSPACE; break;
634
                        case SDLK_DELETE: keysym = QEMU_KEY_DELETE; break;
635
                        default: break;
636
                        }
637
                    }
638
                    if (keysym) {
639
                        kbd_put_keysym(keysym);
640
                    } else if (ev->key.keysym.unicode != 0) {
641
                        kbd_put_keysym(ev->key.keysym.unicode);
642
                    }
643
                }
644
            } else if (ev->type == SDL_KEYUP) {
645
                if (!alt_grab) {
646
                    mod_state = (ev->key.keysym.mod & gui_grab_code);
647
                } else {
648
                    mod_state = (ev->key.keysym.mod &
649
                                 (gui_grab_code | KMOD_LSHIFT));
650
                }
651
                if (!mod_state) {
652
                    if (gui_key_modifier_pressed) {
653
                        gui_key_modifier_pressed = 0;
654
                        if (gui_keysym == 0) {
655
                            /* exit/enter grab if pressing Ctrl-Alt */
656
                            if (!gui_grab) {
657
                                /* if the application is not active,
658
                                   do not try to enter grab state. It
659
                                   prevents
660
                                   'SDL_WM_GrabInput(SDL_GRAB_ON)'
661
                                   from blocking all the application
662
                                   (SDL bug). */
663
                                if (SDL_GetAppState() & SDL_APPACTIVE)
664
                                    sdl_grab_start();
665
                            } else {
666
                                sdl_grab_end();
667
                            }
668
                            /* SDL does not send back all the
669
                               modifiers key, so we must correct it */
670
                            reset_keys();
671
                            break;
672
                        }
673
                        gui_keysym = 0;
674
                    }
675
                }
676
            }
677
            if (is_graphic_console() && !gui_keysym)
678
                sdl_process_key(&ev->key);
679
            break;
680
        case SDL_QUIT:
681
            if (!no_quit)
682
                qemu_system_shutdown_request();
683
            break;
684
        case SDL_MOUSEMOTION:
685
            if (gui_grab || kbd_mouse_is_absolute() ||
686
                absolute_enabled) {
687
                sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0,
688
                       ev->motion.x, ev->motion.y, ev->motion.state);
689
            }
690
            break;
691
        case SDL_MOUSEBUTTONDOWN:
692
        case SDL_MOUSEBUTTONUP:
693
            {
694
                SDL_MouseButtonEvent *bev = &ev->button;
695
                if (!gui_grab && !kbd_mouse_is_absolute()) {
696
                    if (ev->type == SDL_MOUSEBUTTONDOWN &&
697
                        (bev->button == SDL_BUTTON_LEFT)) {
698
                        /* start grabbing all events */
699
                        sdl_grab_start();
700
                    }
701
                } else {
702
                    int dz;
703
                    dz = 0;
704
                    if (ev->type == SDL_MOUSEBUTTONDOWN) {
705
                        buttonstate |= SDL_BUTTON(bev->button);
706
                    } else {
707
                        buttonstate &= ~SDL_BUTTON(bev->button);
708
                    }
709
#ifdef SDL_BUTTON_WHEELUP
710
                    if (bev->button == SDL_BUTTON_WHEELUP && ev->type == SDL_MOUSEBUTTONDOWN) {
711
                        dz = -1;
712
                    } else if (bev->button == SDL_BUTTON_WHEELDOWN && ev->type == SDL_MOUSEBUTTONDOWN) {
713
                        dz = 1;
714
                    }
715
#endif
716
                    sdl_send_mouse_event(0, 0, dz, bev->x, bev->y, buttonstate);
717
                }
718
            }
719
            break;
720
        case SDL_ACTIVEEVENT:
721
            if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
722
                !ev->active.gain && !gui_fullscreen_initial_grab) {
723
                sdl_grab_end();
724
            }
725
            if (ev->active.state & SDL_APPACTIVE) {
726
                if (ev->active.gain) {
727
                    /* Back to default interval */
728
                    dcl->gui_timer_interval = 0;
729
                    dcl->idle = 0;
730
                } else {
731
                    /* Sleeping interval */
732
                    dcl->gui_timer_interval = 500;
733
                    dcl->idle = 1;
734
                }
735
            }
736
            break;
737
        case SDL_VIDEORESIZE:
738
        {
739
            SDL_ResizeEvent *rev = &ev->resize;
740
            int bpp = real_screen->format->BitsPerPixel;
741
            if (bpp != 16 && bpp != 32)
742
                bpp = 32;
743
            do_sdl_resize(rev->w, rev->h, bpp);
744
            scaling_active = 1;
745
            if (!is_buffer_shared(ds->surface)) {
746
                ds->surface = qemu_resize_displaysurface(ds, ds_get_width(ds), ds_get_height(ds));
747
                dpy_resize(ds);
748
            }
749
            vga_hw_invalidate();
750
            vga_hw_update();
751
            break;
752
        }
753
        default:
754
            break;
755
        }
756
    }
757
}
758

    
759
static void sdl_fill(DisplayState *ds, int x, int y, int w, int h, uint32_t c)
760
{
761
    SDL_Rect dst = { x, y, w, h };
762
    SDL_FillRect(real_screen, &dst, c);
763
}
764

    
765
static void sdl_mouse_warp(int x, int y, int on)
766
{
767
    if (on) {
768
        if (!guest_cursor)
769
            sdl_show_cursor();
770
        if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
771
            SDL_SetCursor(guest_sprite);
772
            if (!kbd_mouse_is_absolute() && !absolute_enabled)
773
                SDL_WarpMouse(x, y);
774
        }
775
    } else if (gui_grab)
776
        sdl_hide_cursor();
777
    guest_cursor = on;
778
    guest_x = x, guest_y = y;
779
}
780

    
781
static void sdl_mouse_define(int width, int height, int bpp,
782
                             int hot_x, int hot_y,
783
                             uint8_t *image, uint8_t *mask)
784
{
785
    uint8_t sprite[256], *line;
786
    int x, y, dst, bypl, src = 0;
787
    if (guest_sprite)
788
        SDL_FreeCursor(guest_sprite);
789

    
790
    memset(sprite, 0, 256);
791
    bypl = ((width * bpp + 31) >> 5) << 2;
792
    for (y = 0, dst = 0; y < height; y ++, image += bypl) {
793
        line = image;
794
        for (x = 0; x < width; x ++, dst ++) {
795
            switch (bpp) {
796
            case 32:
797
                src = *(line ++); src |= *(line ++); src |= *(line ++); line++;
798
                break;
799
            case 24:
800
                src = *(line ++); src |= *(line ++); src |= *(line ++);
801
                break;
802
            case 16:
803
            case 15:
804
                src = *(line ++); src |= *(line ++);
805
                break;
806
            case 8:
807
                src = *(line ++);
808
                break;
809
            case 4:
810
                src = 0xf & (line[x >> 1] >> ((x & 1)) << 2);
811
                break;
812
            case 2:
813
                src = 3 & (line[x >> 2] >> ((x & 3)) << 1);
814
                break;
815
            case 1:
816
                src = 1 & (line[x >> 3] >> (x & 7));
817
                break;
818
            }
819
            if (!src)
820
                sprite[dst >> 3] |= (1 << (~dst & 7)) & mask[dst >> 3];
821
        }
822
    }
823
    guest_sprite = SDL_CreateCursor(sprite, mask, width, height, hot_x, hot_y);
824

    
825
    if (guest_cursor &&
826
            (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
827
        SDL_SetCursor(guest_sprite);
828
}
829

    
830
static void sdl_cleanup(void)
831
{
832
    if (guest_sprite)
833
        SDL_FreeCursor(guest_sprite);
834
    SDL_QuitSubSystem(SDL_INIT_VIDEO);
835
}
836

    
837
void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
838
{
839
    int flags;
840
    uint8_t data = 0;
841
    DisplayAllocator *da;
842
    const SDL_VideoInfo *vi;
843

    
844
#if defined(__APPLE__)
845
    /* always use generic keymaps */
846
    if (!keyboard_layout)
847
        keyboard_layout = "en-us";
848
#endif
849
    if(keyboard_layout) {
850
        kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
851
        if (!kbd_layout)
852
            exit(1);
853
    }
854

    
855
    if (no_frame)
856
        gui_noframe = 1;
857

    
858
    flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
859
    if (SDL_Init (flags)) {
860
        fprintf(stderr, "Could not initialize SDL(%s) - exiting\n",
861
                SDL_GetError());
862
        exit(1);
863
    }
864
    vi = SDL_GetVideoInfo();
865
    host_format = *(vi->vfmt);
866

    
867
    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
868
    dcl->dpy_update = sdl_update;
869
    dcl->dpy_resize = sdl_resize;
870
    dcl->dpy_refresh = sdl_refresh;
871
    dcl->dpy_setdata = sdl_setdata;
872
    dcl->dpy_fill = sdl_fill;
873
    ds->mouse_set = sdl_mouse_warp;
874
    ds->cursor_define = sdl_mouse_define;
875
    register_displaychangelistener(ds, dcl);
876

    
877
    da = qemu_mallocz(sizeof(DisplayAllocator));
878
    da->create_displaysurface = sdl_create_displaysurface;
879
    da->resize_displaysurface = sdl_resize_displaysurface;
880
    da->free_displaysurface = sdl_free_displaysurface;
881
    if (register_displayallocator(ds, da) == da) {
882
        dpy_resize(ds);
883
    }
884

    
885
    mouse_mode_notifier.notify = sdl_mouse_mode_change;
886
    qemu_add_mouse_mode_change_notifier(&mouse_mode_notifier);
887

    
888
    sdl_update_caption();
889
    SDL_EnableKeyRepeat(250, 50);
890
    gui_grab = 0;
891

    
892
    sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0);
893
    sdl_cursor_normal = SDL_GetCursor();
894

    
895
    atexit(sdl_cleanup);
896
    if (full_screen) {
897
        gui_fullscreen = 1;
898
        gui_fullscreen_initial_grab = 1;
899
        sdl_grab_start();
900
    }
901
}