Statistics
| Branch: | Revision:

root / sdl.c @ 649c9078

History | View | Annotate | Download (24.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

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

    
59
static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
60
{
61
    //    printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
62
    if (guest_screen) {
63
        SDL_Rect rec;
64
        rec.x = x;
65
        rec.y = y;
66
        rec.w = w;
67
        rec.h = h;
68
        SDL_BlitSurface(guest_screen, &rec, real_screen, &rec);
69
    }
70
    SDL_UpdateRect(real_screen, x, y, w, h);
71
}
72

    
73
static void sdl_setdata(DisplayState *ds)
74
{
75
    SDL_Rect rec;
76
    rec.x = 0;
77
    rec.y = 0;
78
    rec.w = real_screen->w;
79
    rec.h = real_screen->h;
80

    
81
    if (guest_screen != NULL) SDL_FreeSurface(guest_screen);
82

    
83
    guest_screen = SDL_CreateRGBSurfaceFrom(ds_get_data(ds), ds_get_width(ds), ds_get_height(ds),
84
                                            ds_get_bits_per_pixel(ds), ds_get_linesize(ds),
85
                                            ds->surface->pf.rmask, ds->surface->pf.gmask,
86
                                            ds->surface->pf.bmask, ds->surface->pf.amask);
87
}
88

    
89
static void do_sdl_resize(int new_width, int new_height, int bpp)
90
{
91
    int flags;
92

    
93
    //    printf("resizing to %d %d\n", w, h);
94

    
95
    flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
96
    if (gui_fullscreen)
97
        flags |= SDL_FULLSCREEN;
98
    if (gui_noframe)
99
        flags |= SDL_NOFRAME;
100

    
101
    width = new_width;
102
    height = new_height;
103
    real_screen = SDL_SetVideoMode(width, height, bpp, flags);
104
    if (!real_screen) {
105
        fprintf(stderr, "Could not open SDL display\n");
106
        exit(1);
107
    }
108
}
109

    
110
static void sdl_resize(DisplayState *ds)
111
{
112
    if  (!allocator) {
113
        do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
114
        sdl_setdata(ds);
115
    } else {
116
        if (guest_screen != NULL) {
117
            SDL_FreeSurface(guest_screen);
118
            guest_screen = NULL;
119
        }
120
    }
121
}
122

    
123
static PixelFormat sdl_to_qemu_pixelformat(SDL_PixelFormat *sdl_pf)
124
{
125
    PixelFormat qemu_pf;
126

    
127
    memset(&qemu_pf, 0x00, sizeof(PixelFormat));
128

    
129
    qemu_pf.bits_per_pixel = sdl_pf->BitsPerPixel;
130
    qemu_pf.bytes_per_pixel = sdl_pf->BytesPerPixel;
131
    qemu_pf.depth = (qemu_pf.bits_per_pixel) == 32 ? 24 : (qemu_pf.bits_per_pixel);
132

    
133
    qemu_pf.rmask = sdl_pf->Rmask;
134
    qemu_pf.gmask = sdl_pf->Gmask;
135
    qemu_pf.bmask = sdl_pf->Bmask;
136
    qemu_pf.amask = sdl_pf->Amask;
137

    
138
    qemu_pf.rshift = sdl_pf->Rshift;
139
    qemu_pf.gshift = sdl_pf->Gshift;
140
    qemu_pf.bshift = sdl_pf->Bshift;
141
    qemu_pf.ashift = sdl_pf->Ashift;
142

    
143
    qemu_pf.rbits = 8 - sdl_pf->Rloss;
144
    qemu_pf.gbits = 8 - sdl_pf->Gloss;
145
    qemu_pf.bbits = 8 - sdl_pf->Bloss;
146
    qemu_pf.abits = 8 - sdl_pf->Aloss;
147

    
148
    qemu_pf.rmax = ((1 << qemu_pf.rbits) - 1);
149
    qemu_pf.gmax = ((1 << qemu_pf.gbits) - 1);
150
    qemu_pf.bmax = ((1 << qemu_pf.bbits) - 1);
151
    qemu_pf.amax = ((1 << qemu_pf.abits) - 1);
152

    
153
    return qemu_pf;
154
}
155

    
156
static DisplaySurface* sdl_create_displaysurface(int width, int height)
157
{
158
    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
159
    if (surface == NULL) {
160
        fprintf(stderr, "sdl_create_displaysurface: malloc failed\n");
161
        exit(1);
162
    }
163

    
164
    surface->width = width;
165
    surface->height = height;
166

    
167
    if (hostbpp == 16)
168
        do_sdl_resize(width, height, 16);
169
    else
170
        do_sdl_resize(width, height, 32);
171

    
172
    surface->pf = sdl_to_qemu_pixelformat(real_screen->format);
173
    surface->linesize = real_screen->pitch;
174
    surface->data = real_screen->pixels;
175

    
176
#ifdef WORDS_BIGENDIAN
177
    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
178
#else
179
    surface->flags = QEMU_ALLOCATED_FLAG;
180
#endif
181
    allocator = 1;
182

    
183
    return surface;
184
}
185

    
186
static void sdl_free_displaysurface(DisplaySurface *surface)
187
{
188
    allocator = 0;
189
    if (surface == NULL)
190
        return;
191
    qemu_free(surface);
192
}
193

    
194
static DisplaySurface* sdl_resize_displaysurface(DisplaySurface *surface, int width, int height)
195
{
196
    sdl_free_displaysurface(surface);
197
    return sdl_create_displaysurface(width, height);
198
}
199

    
200
/* generic keyboard conversion */
201

    
202
#include "sdl_keysym.h"
203

    
204
static kbd_layout_t *kbd_layout = NULL;
205

    
206
static uint8_t sdl_keyevent_to_keycode_generic(const SDL_KeyboardEvent *ev)
207
{
208
    int keysym;
209
    /* workaround for X11+SDL bug with AltGR */
210
    keysym = ev->keysym.sym;
211
    if (keysym == 0 && ev->keysym.scancode == 113)
212
        keysym = SDLK_MODE;
213
    /* For Japanese key '\' and '|' */
214
    if (keysym == 92 && ev->keysym.scancode == 133) {
215
        keysym = 0xa5;
216
    }
217
    return keysym2scancode(kbd_layout, keysym);
218
}
219

    
220
/* specific keyboard conversions from scan codes */
221

    
222
#if defined(_WIN32)
223

    
224
static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
225
{
226
    return ev->keysym.scancode;
227
}
228

    
229
#else
230

    
231
#if defined(SDL_VIDEO_DRIVER_X11)
232
#include <X11/XKBlib.h>
233

    
234
static int check_for_evdev(void)
235
{
236
    SDL_SysWMinfo info;
237
    XkbDescPtr desc;
238
    int has_evdev = 0;
239
    const char *keycodes;
240

    
241
    SDL_VERSION(&info.version);
242
    if (!SDL_GetWMInfo(&info))
243
        return 0;
244

    
245
    desc = XkbGetKeyboard(info.info.x11.display,
246
                          XkbGBN_AllComponentsMask,
247
                          XkbUseCoreKbd);
248
    if (desc == NULL || desc->names == NULL)
249
        return 0;
250

    
251
    keycodes = XGetAtomName(info.info.x11.display, desc->names->keycodes);
252
    if (keycodes == NULL)
253
        fprintf(stderr, "could not lookup keycode name\n");
254
    else if (strstart(keycodes, "evdev_", NULL))
255
        has_evdev = 1;
256
    else if (!strstart(keycodes, "xfree86_", NULL))
257
        fprintf(stderr,
258
                "unknown keycodes `%s', please report to qemu-devel@nongnu.org\n",
259
                keycodes);
260

    
261
    XkbFreeClientMap(desc, XkbGBN_AllComponentsMask, True);
262

    
263
    return has_evdev;
264
}
265
#else
266
static int check_for_evdev(void)
267
{
268
        return 0;
269
}
270
#endif
271

    
272
static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
273
{
274
    int keycode;
275
    static int has_evdev = -1;
276

    
277
    if (has_evdev == -1)
278
        has_evdev = check_for_evdev();
279

    
280
    keycode = ev->keysym.scancode;
281

    
282
    if (keycode < 9) {
283
        keycode = 0;
284
    } else if (keycode < 97) {
285
        keycode -= 8; /* just an offset */
286
    } else if (keycode < 158) {
287
        /* use conversion table */
288
        if (has_evdev)
289
            keycode = translate_evdev_keycode(keycode - 97);
290
        else
291
            keycode = translate_xfree86_keycode(keycode - 97);
292
    } else if (keycode == 208) { /* Hiragana_Katakana */
293
        keycode = 0x70;
294
    } else if (keycode == 211) { /* backslash */
295
        keycode = 0x73;
296
    } else {
297
        keycode = 0;
298
    }
299
    return keycode;
300
}
301

    
302
#endif
303

    
304
static void reset_keys(void)
305
{
306
    int i;
307
    for(i = 0; i < 256; i++) {
308
        if (modifiers_state[i]) {
309
            if (i & 0x80)
310
                kbd_put_keycode(0xe0);
311
            kbd_put_keycode(i | 0x80);
312
            modifiers_state[i] = 0;
313
        }
314
    }
315
}
316

    
317
static void sdl_process_key(SDL_KeyboardEvent *ev)
318
{
319
    int keycode, v;
320

    
321
    if (ev->keysym.sym == SDLK_PAUSE) {
322
        /* specific case */
323
        v = 0;
324
        if (ev->type == SDL_KEYUP)
325
            v |= 0x80;
326
        kbd_put_keycode(0xe1);
327
        kbd_put_keycode(0x1d | v);
328
        kbd_put_keycode(0x45 | v);
329
        return;
330
    }
331

    
332
    if (kbd_layout) {
333
        keycode = sdl_keyevent_to_keycode_generic(ev);
334
    } else {
335
        keycode = sdl_keyevent_to_keycode(ev);
336
    }
337

    
338
    switch(keycode) {
339
    case 0x00:
340
        /* sent when leaving window: reset the modifiers state */
341
        reset_keys();
342
        return;
343
    case 0x2a:                          /* Left Shift */
344
    case 0x36:                          /* Right Shift */
345
    case 0x1d:                          /* Left CTRL */
346
    case 0x9d:                          /* Right CTRL */
347
    case 0x38:                          /* Left ALT */
348
    case 0xb8:                         /* Right ALT */
349
        if (ev->type == SDL_KEYUP)
350
            modifiers_state[keycode] = 0;
351
        else
352
            modifiers_state[keycode] = 1;
353
        break;
354
    case 0x45: /* num lock */
355
    case 0x3a: /* caps lock */
356
        /* SDL does not send the key up event, so we generate it */
357
        kbd_put_keycode(keycode);
358
        kbd_put_keycode(keycode | 0x80);
359
        return;
360
    }
361

    
362
    /* now send the key code */
363
    if (keycode & 0x80)
364
        kbd_put_keycode(0xe0);
365
    if (ev->type == SDL_KEYUP)
366
        kbd_put_keycode(keycode | 0x80);
367
    else
368
        kbd_put_keycode(keycode & 0x7f);
369
}
370

    
371
static void sdl_update_caption(void)
372
{
373
    char buf[1024];
374
    const char *status = "";
375

    
376
    if (!vm_running)
377
        status = " [Stopped]";
378
    else if (gui_grab) {
379
        if (!alt_grab)
380
            status = " - Press Ctrl-Alt to exit grab";
381
        else
382
            status = " - Press Ctrl-Alt-Shift to exit grab";
383
    }
384

    
385
    if (qemu_name)
386
        snprintf(buf, sizeof(buf), "QEMU (%s)%s", qemu_name, status);
387
    else
388
        snprintf(buf, sizeof(buf), "QEMU%s", status);
389

    
390
    SDL_WM_SetCaption(buf, "QEMU");
391
}
392

    
393
static void sdl_hide_cursor(void)
394
{
395
    if (!cursor_hide)
396
        return;
397

    
398
    if (kbd_mouse_is_absolute()) {
399
        SDL_ShowCursor(1);
400
        SDL_SetCursor(sdl_cursor_hidden);
401
    } else {
402
        SDL_ShowCursor(0);
403
    }
404
}
405

    
406
static void sdl_show_cursor(void)
407
{
408
    if (!cursor_hide)
409
        return;
410

    
411
    if (!kbd_mouse_is_absolute()) {
412
        SDL_ShowCursor(1);
413
        if (guest_cursor &&
414
                (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
415
            SDL_SetCursor(guest_sprite);
416
        else
417
            SDL_SetCursor(sdl_cursor_normal);
418
    }
419
}
420

    
421
static void sdl_grab_start(void)
422
{
423
    if (guest_cursor) {
424
        SDL_SetCursor(guest_sprite);
425
        if (!kbd_mouse_is_absolute() && !absolute_enabled)
426
            SDL_WarpMouse(guest_x, guest_y);
427
    } else
428
        sdl_hide_cursor();
429

    
430
    if (SDL_WM_GrabInput(SDL_GRAB_ON) == SDL_GRAB_ON) {
431
        gui_grab = 1;
432
        sdl_update_caption();
433
    } else
434
        sdl_show_cursor();
435
}
436

    
437
static void sdl_grab_end(void)
438
{
439
    SDL_WM_GrabInput(SDL_GRAB_OFF);
440
    gui_grab = 0;
441
    sdl_show_cursor();
442
    sdl_update_caption();
443
}
444

    
445
static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state)
446
{
447
    int buttons;
448
    buttons = 0;
449
    if (state & SDL_BUTTON(SDL_BUTTON_LEFT))
450
        buttons |= MOUSE_EVENT_LBUTTON;
451
    if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
452
        buttons |= MOUSE_EVENT_RBUTTON;
453
    if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE))
454
        buttons |= MOUSE_EVENT_MBUTTON;
455

    
456
    if (kbd_mouse_is_absolute()) {
457
        if (!absolute_enabled) {
458
            sdl_hide_cursor();
459
            if (gui_grab) {
460
                sdl_grab_end();
461
            }
462
            absolute_enabled = 1;
463
        }
464

    
465
       dx = x * 0x7FFF / (width - 1);
466
       dy = y * 0x7FFF / (height - 1);
467
    } else if (absolute_enabled) {
468
        sdl_show_cursor();
469
        absolute_enabled = 0;
470
    } else if (guest_cursor) {
471
        x -= guest_x;
472
        y -= guest_y;
473
        guest_x += x;
474
        guest_y += y;
475
        dx = x;
476
        dy = y;
477
    }
478

    
479
    kbd_mouse_event(dx, dy, dz, buttons);
480
}
481

    
482
static void toggle_full_screen(DisplayState *ds)
483
{
484
    gui_fullscreen = !gui_fullscreen;
485
    do_sdl_resize(real_screen->w, real_screen->h, real_screen->format->BitsPerPixel);
486
    if (gui_fullscreen) {
487
        gui_saved_grab = gui_grab;
488
        sdl_grab_start();
489
    } else {
490
        if (!gui_saved_grab)
491
            sdl_grab_end();
492
    }
493
    vga_hw_invalidate();
494
    vga_hw_update();
495
}
496

    
497
static void sdl_refresh(DisplayState *ds)
498
{
499
    SDL_Event ev1, *ev = &ev1;
500
    int mod_state;
501
    int buttonstate = SDL_GetMouseState(NULL, NULL);
502

    
503
    if (last_vm_running != vm_running) {
504
        last_vm_running = vm_running;
505
        sdl_update_caption();
506
    }
507

    
508
    vga_hw_update();
509
    SDL_EnableUNICODE(!is_graphic_console());
510

    
511
    while (SDL_PollEvent(ev)) {
512
        switch (ev->type) {
513
        case SDL_VIDEOEXPOSE:
514
            sdl_update(ds, 0, 0, real_screen->w, real_screen->h);
515
            break;
516
        case SDL_KEYDOWN:
517
        case SDL_KEYUP:
518
            if (ev->type == SDL_KEYDOWN) {
519
                if (!alt_grab) {
520
                    mod_state = (SDL_GetModState() & gui_grab_code) ==
521
                                gui_grab_code;
522
                } else {
523
                    mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) ==
524
                                (gui_grab_code | KMOD_LSHIFT);
525
                }
526
                gui_key_modifier_pressed = mod_state;
527
                if (gui_key_modifier_pressed) {
528
                    int keycode;
529
                    keycode = sdl_keyevent_to_keycode(&ev->key);
530
                    switch(keycode) {
531
                    case 0x21: /* 'f' key on US keyboard */
532
                        toggle_full_screen(ds);
533
                        gui_keysym = 1;
534
                        break;
535
                    case 0x02 ... 0x0a: /* '1' to '9' keys */
536
                        /* Reset the modifiers sent to the current console */
537
                        reset_keys();
538
                        console_select(keycode - 0x02);
539
                        if (!is_graphic_console()) {
540
                            /* display grab if going to a text console */
541
                            if (gui_grab)
542
                                sdl_grab_end();
543
                        }
544
                        gui_keysym = 1;
545
                        break;
546
                    default:
547
                        break;
548
                    }
549
                } else if (!is_graphic_console()) {
550
                    int keysym;
551
                    keysym = 0;
552
                    if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
553
                        switch(ev->key.keysym.sym) {
554
                        case SDLK_UP: keysym = QEMU_KEY_CTRL_UP; break;
555
                        case SDLK_DOWN: keysym = QEMU_KEY_CTRL_DOWN; break;
556
                        case SDLK_LEFT: keysym = QEMU_KEY_CTRL_LEFT; break;
557
                        case SDLK_RIGHT: keysym = QEMU_KEY_CTRL_RIGHT; break;
558
                        case SDLK_HOME: keysym = QEMU_KEY_CTRL_HOME; break;
559
                        case SDLK_END: keysym = QEMU_KEY_CTRL_END; break;
560
                        case SDLK_PAGEUP: keysym = QEMU_KEY_CTRL_PAGEUP; break;
561
                        case SDLK_PAGEDOWN: keysym = QEMU_KEY_CTRL_PAGEDOWN; break;
562
                        default: break;
563
                        }
564
                    } else {
565
                        switch(ev->key.keysym.sym) {
566
                        case SDLK_UP: keysym = QEMU_KEY_UP; break;
567
                        case SDLK_DOWN: keysym = QEMU_KEY_DOWN; break;
568
                        case SDLK_LEFT: keysym = QEMU_KEY_LEFT; break;
569
                        case SDLK_RIGHT: keysym = QEMU_KEY_RIGHT; break;
570
                        case SDLK_HOME: keysym = QEMU_KEY_HOME; break;
571
                        case SDLK_END: keysym = QEMU_KEY_END; break;
572
                        case SDLK_PAGEUP: keysym = QEMU_KEY_PAGEUP; break;
573
                        case SDLK_PAGEDOWN: keysym = QEMU_KEY_PAGEDOWN; break;
574
                        case SDLK_BACKSPACE: keysym = QEMU_KEY_BACKSPACE; break;
575
                        case SDLK_DELETE: keysym = QEMU_KEY_DELETE; break;
576
                        default: break;
577
                        }
578
                    }
579
                    if (keysym) {
580
                        kbd_put_keysym(keysym);
581
                    } else if (ev->key.keysym.unicode != 0) {
582
                        kbd_put_keysym(ev->key.keysym.unicode);
583
                    }
584
                }
585
            } else if (ev->type == SDL_KEYUP) {
586
                if (!alt_grab) {
587
                    mod_state = (ev->key.keysym.mod & gui_grab_code);
588
                } else {
589
                    mod_state = (ev->key.keysym.mod &
590
                                 (gui_grab_code | KMOD_LSHIFT));
591
                }
592
                if (!mod_state) {
593
                    if (gui_key_modifier_pressed) {
594
                        gui_key_modifier_pressed = 0;
595
                        if (gui_keysym == 0) {
596
                            /* exit/enter grab if pressing Ctrl-Alt */
597
                            if (!gui_grab) {
598
                                /* if the application is not active,
599
                                   do not try to enter grab state. It
600
                                   prevents
601
                                   'SDL_WM_GrabInput(SDL_GRAB_ON)'
602
                                   from blocking all the application
603
                                   (SDL bug). */
604
                                if (SDL_GetAppState() & SDL_APPACTIVE)
605
                                    sdl_grab_start();
606
                            } else {
607
                                sdl_grab_end();
608
                            }
609
                            /* SDL does not send back all the
610
                               modifiers key, so we must correct it */
611
                            reset_keys();
612
                            break;
613
                        }
614
                        gui_keysym = 0;
615
                    }
616
                }
617
            }
618
            if (is_graphic_console() && !gui_keysym)
619
                sdl_process_key(&ev->key);
620
            break;
621
        case SDL_QUIT:
622
            if (!no_quit)
623
                qemu_system_shutdown_request();
624
            break;
625
        case SDL_MOUSEMOTION:
626
            if (gui_grab || kbd_mouse_is_absolute() ||
627
                absolute_enabled) {
628
                sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0,
629
                       ev->motion.x, ev->motion.y, ev->motion.state);
630
            }
631
            break;
632
        case SDL_MOUSEBUTTONDOWN:
633
        case SDL_MOUSEBUTTONUP:
634
            {
635
                SDL_MouseButtonEvent *bev = &ev->button;
636
                if (!gui_grab && !kbd_mouse_is_absolute()) {
637
                    if (ev->type == SDL_MOUSEBUTTONDOWN &&
638
                        (bev->button == SDL_BUTTON_LEFT)) {
639
                        /* start grabbing all events */
640
                        sdl_grab_start();
641
                    }
642
                } else {
643
                    int dz;
644
                    dz = 0;
645
                    if (ev->type == SDL_MOUSEBUTTONDOWN) {
646
                        buttonstate |= SDL_BUTTON(bev->button);
647
                    } else {
648
                        buttonstate &= ~SDL_BUTTON(bev->button);
649
                    }
650
#ifdef SDL_BUTTON_WHEELUP
651
                    if (bev->button == SDL_BUTTON_WHEELUP && ev->type == SDL_MOUSEBUTTONDOWN) {
652
                        dz = -1;
653
                    } else if (bev->button == SDL_BUTTON_WHEELDOWN && ev->type == SDL_MOUSEBUTTONDOWN) {
654
                        dz = 1;
655
                    }
656
#endif
657
                    sdl_send_mouse_event(0, 0, dz, bev->x, bev->y, buttonstate);
658
                }
659
            }
660
            break;
661
        case SDL_ACTIVEEVENT:
662
            if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
663
                !ev->active.gain && !gui_fullscreen_initial_grab) {
664
                sdl_grab_end();
665
            }
666
            if (ev->active.state & SDL_APPACTIVE) {
667
                if (ev->active.gain) {
668
                    /* Back to default interval */
669
                    dcl->gui_timer_interval = 0;
670
                    dcl->idle = 0;
671
                } else {
672
                    /* Sleeping interval */
673
                    dcl->gui_timer_interval = 500;
674
                    dcl->idle = 1;
675
                }
676
            }
677
            break;
678
        default:
679
            break;
680
        }
681
    }
682
}
683

    
684
static void sdl_fill(DisplayState *ds, int x, int y, int w, int h, uint32_t c)
685
{
686
    SDL_Rect dst = { x, y, w, h };
687
    SDL_FillRect(real_screen, &dst, c);
688
}
689

    
690
static void sdl_mouse_warp(int x, int y, int on)
691
{
692
    if (on) {
693
        if (!guest_cursor)
694
            sdl_show_cursor();
695
        if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
696
            SDL_SetCursor(guest_sprite);
697
            if (!kbd_mouse_is_absolute() && !absolute_enabled)
698
                SDL_WarpMouse(x, y);
699
        }
700
    } else if (gui_grab)
701
        sdl_hide_cursor();
702
    guest_cursor = on;
703
    guest_x = x, guest_y = y;
704
}
705

    
706
static void sdl_mouse_define(int width, int height, int bpp,
707
                             int hot_x, int hot_y,
708
                             uint8_t *image, uint8_t *mask)
709
{
710
    uint8_t sprite[256], *line;
711
    int x, y, dst, bypl, src = 0;
712
    if (guest_sprite)
713
        SDL_FreeCursor(guest_sprite);
714

    
715
    memset(sprite, 0, 256);
716
    bypl = ((width * bpp + 31) >> 5) << 2;
717
    for (y = 0, dst = 0; y < height; y ++, image += bypl) {
718
        line = image;
719
        for (x = 0; x < width; x ++, dst ++) {
720
            switch (bpp) {
721
            case 24:
722
                src = *(line ++); src |= *(line ++); src |= *(line ++);
723
                break;
724
            case 16:
725
            case 15:
726
                src = *(line ++); src |= *(line ++);
727
                break;
728
            case 8:
729
                src = *(line ++);
730
                break;
731
            case 4:
732
                src = 0xf & (line[x >> 1] >> ((x & 1)) << 2);
733
                break;
734
            case 2:
735
                src = 3 & (line[x >> 2] >> ((x & 3)) << 1);
736
                break;
737
            case 1:
738
                src = 1 & (line[x >> 3] >> (x & 7));
739
                break;
740
            }
741
            if (!src)
742
                sprite[dst >> 3] |= (1 << (~dst & 7)) & mask[dst >> 3];
743
        }
744
    }
745
    guest_sprite = SDL_CreateCursor(sprite, mask, width, height, hot_x, hot_y);
746

    
747
    if (guest_cursor &&
748
            (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
749
        SDL_SetCursor(guest_sprite);
750
}
751

    
752
static void sdl_cleanup(void)
753
{
754
    if (guest_sprite)
755
        SDL_FreeCursor(guest_sprite);
756
    SDL_Quit();
757
}
758

    
759
void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
760
{
761
    int flags;
762
    uint8_t data = 0;
763
    DisplayAllocator *da;
764
    const SDL_VideoInfo *vi;
765

    
766
#if defined(__APPLE__)
767
    /* always use generic keymaps */
768
    if (!keyboard_layout)
769
        keyboard_layout = "en-us";
770
#endif
771
    if(keyboard_layout) {
772
        kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
773
        if (!kbd_layout)
774
            exit(1);
775
    }
776

    
777
    if (no_frame)
778
        gui_noframe = 1;
779

    
780
    flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
781
    if (SDL_Init (flags)) {
782
        fprintf(stderr, "Could not initialize SDL - exiting\n");
783
        exit(1);
784
    }
785
    vi = SDL_GetVideoInfo();
786
    hostbpp = vi->vfmt->BitsPerPixel;
787

    
788
    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
789
    dcl->dpy_update = sdl_update;
790
    dcl->dpy_resize = sdl_resize;
791
    dcl->dpy_refresh = sdl_refresh;
792
    dcl->dpy_setdata = sdl_setdata;
793
    dcl->dpy_fill = sdl_fill;
794
    ds->mouse_set = sdl_mouse_warp;
795
    ds->cursor_define = sdl_mouse_define;
796
    register_displaychangelistener(ds, dcl);
797

    
798
    da = qemu_mallocz(sizeof(DisplayAllocator));
799
    da->create_displaysurface = sdl_create_displaysurface;
800
    da->resize_displaysurface = sdl_resize_displaysurface;
801
    da->free_displaysurface = sdl_free_displaysurface;
802
    if (register_displayallocator(ds, da) == da) {
803
        DisplaySurface *surf;
804
        surf = sdl_create_displaysurface(ds_get_width(ds), ds_get_height(ds));
805
        defaultallocator_free_displaysurface(ds->surface);
806
        ds->surface = surf;
807
        dpy_resize(ds);
808
    }
809

    
810
    sdl_update_caption();
811
    SDL_EnableKeyRepeat(250, 50);
812
    gui_grab = 0;
813

    
814
    sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0);
815
    sdl_cursor_normal = SDL_GetCursor();
816

    
817
    atexit(sdl_cleanup);
818
    if (full_screen) {
819
        gui_fullscreen = 1;
820
        gui_fullscreen_initial_grab = 1;
821
        sdl_grab_start();
822
    }
823
}