X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=sdl.c;h=178b5532b8d9dd2194a8662fbfdcd49b4bc04222;hb=73c632edc4e28d0a8cae3b34abf7ae46fa33bf1e;hp=cac1a036557a9c812a90df806c1e49bebf18a3b8;hpb=3b46e6242767a2c770c0aba0a6595e9511623c92;p=qemu diff --git a/sdl.c b/sdl.c index cac1a03..178b553 100644 --- a/sdl.c +++ b/sdl.c @@ -21,15 +21,21 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" - #include +#include #ifndef _WIN32 #include #endif -static SDL_Surface *screen; +#include "qemu-common.h" +#include "console.h" +#include "sysemu.h" +#include "x_keymap.h" + +static DisplayChangeListener *dcl; +static SDL_Surface *real_screen; +static SDL_Surface *guest_screen = NULL; static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ static int last_vm_running; static int gui_saved_grab; @@ -47,14 +53,40 @@ static int absolute_enabled = 0; static int guest_cursor = 0; static int guest_x, guest_y; static SDL_Cursor *guest_sprite = 0; +static uint8_t allocator; +static uint8_t hostbpp; static void sdl_update(DisplayState *ds, int x, int y, int w, int h) { // printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h); - SDL_UpdateRect(screen, x, y, w, h); + if (guest_screen) { + SDL_Rect rec; + rec.x = x; + rec.y = y; + rec.w = w; + rec.h = h; + SDL_BlitSurface(guest_screen, &rec, real_screen, &rec); + } + SDL_UpdateRect(real_screen, x, y, w, h); } -static void sdl_resize(DisplayState *ds, int w, int h) +static void sdl_setdata(DisplayState *ds) +{ + SDL_Rect rec; + rec.x = 0; + rec.y = 0; + rec.w = real_screen->w; + rec.h = real_screen->h; + + if (guest_screen != NULL) SDL_FreeSurface(guest_screen); + + guest_screen = SDL_CreateRGBSurfaceFrom(ds_get_data(ds), ds_get_width(ds), ds_get_height(ds), + ds_get_bits_per_pixel(ds), ds_get_linesize(ds), + ds->surface->pf.rmask, ds->surface->pf.gmask, + ds->surface->pf.bmask, ds->surface->pf.amask); +} + +static void do_sdl_resize(int new_width, int new_height, int bpp) { int flags; @@ -66,40 +98,108 @@ static void sdl_resize(DisplayState *ds, int w, int h) if (gui_noframe) flags |= SDL_NOFRAME; - width = w; - height = h; - - again: - screen = SDL_SetVideoMode(w, h, 0, flags); - if (!screen) { + width = new_width; + height = new_height; + real_screen = SDL_SetVideoMode(width, height, bpp, flags); + if (!real_screen) { fprintf(stderr, "Could not open SDL display\n"); exit(1); } - if (!screen->pixels && (flags & SDL_HWSURFACE) && (flags & SDL_FULLSCREEN)) { - flags &= ~SDL_HWSURFACE; - goto again; +} + +static void sdl_resize(DisplayState *ds) +{ + if (!allocator) { + do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0); + sdl_setdata(ds); + } else { + if (guest_screen != NULL) { + SDL_FreeSurface(guest_screen); + guest_screen = NULL; + } } +} - if (!screen->pixels) { - fprintf(stderr, "Could not open SDL display\n"); +static PixelFormat sdl_to_qemu_pixelformat(SDL_PixelFormat *sdl_pf) +{ + PixelFormat qemu_pf; + + memset(&qemu_pf, 0x00, sizeof(PixelFormat)); + + qemu_pf.bits_per_pixel = sdl_pf->BitsPerPixel; + qemu_pf.bytes_per_pixel = sdl_pf->BytesPerPixel; + qemu_pf.depth = (qemu_pf.bits_per_pixel) == 32 ? 24 : (qemu_pf.bits_per_pixel); + + qemu_pf.rmask = sdl_pf->Rmask; + qemu_pf.gmask = sdl_pf->Gmask; + qemu_pf.bmask = sdl_pf->Bmask; + qemu_pf.amask = sdl_pf->Amask; + + qemu_pf.rshift = sdl_pf->Rshift; + qemu_pf.gshift = sdl_pf->Gshift; + qemu_pf.bshift = sdl_pf->Bshift; + qemu_pf.ashift = sdl_pf->Ashift; + + qemu_pf.rbits = 8 - sdl_pf->Rloss; + qemu_pf.gbits = 8 - sdl_pf->Gloss; + qemu_pf.bbits = 8 - sdl_pf->Bloss; + qemu_pf.abits = 8 - sdl_pf->Aloss; + + qemu_pf.rmax = ((1 << qemu_pf.rbits) - 1); + qemu_pf.gmax = ((1 << qemu_pf.gbits) - 1); + qemu_pf.bmax = ((1 << qemu_pf.bbits) - 1); + qemu_pf.amax = ((1 << qemu_pf.abits) - 1); + + return qemu_pf; +} + +static DisplaySurface* sdl_create_displaysurface(int width, int height) +{ + DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface)); + if (surface == NULL) { + fprintf(stderr, "sdl_create_displaysurface: malloc failed\n"); exit(1); } - ds->data = screen->pixels; - ds->linesize = screen->pitch; - ds->depth = screen->format->BitsPerPixel; - if (screen->format->Bshift > screen->format->Rshift) { - ds->bgr = 1; - } else { - ds->bgr = 0; - } - ds->width = w; - ds->height = h; + + surface->width = width; + surface->height = height; + + if (hostbpp == 16) + do_sdl_resize(width, height, 16); + else + do_sdl_resize(width, height, 32); + + surface->pf = sdl_to_qemu_pixelformat(real_screen->format); + surface->linesize = real_screen->pitch; + surface->data = real_screen->pixels; + +#ifdef WORDS_BIGENDIAN + surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG; +#else + surface->flags = QEMU_ALLOCATED_FLAG; +#endif + allocator = 1; + + return surface; +} + +static void sdl_free_displaysurface(DisplaySurface *surface) +{ + allocator = 0; + if (surface == NULL) + return; + qemu_free(surface); +} + +static DisplaySurface* sdl_resize_displaysurface(DisplaySurface *surface, int width, int height) +{ + sdl_free_displaysurface(surface); + return sdl_create_displaysurface(width, height); } /* generic keyboard conversion */ #include "sdl_keysym.h" -#include "keymaps.c" static kbd_layout_t *kbd_layout = NULL; @@ -128,9 +228,54 @@ static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev) #else +#if defined(SDL_VIDEO_DRIVER_X11) +#include + +static int check_for_evdev(void) +{ + SDL_SysWMinfo info; + XkbDescPtr desc; + int has_evdev = 0; + const char *keycodes; + + SDL_VERSION(&info.version); + if (!SDL_GetWMInfo(&info)) + return 0; + + desc = XkbGetKeyboard(info.info.x11.display, + XkbGBN_AllComponentsMask, + XkbUseCoreKbd); + if (desc == NULL || desc->names == NULL) + return 0; + + keycodes = XGetAtomName(info.info.x11.display, desc->names->keycodes); + if (keycodes == NULL) + fprintf(stderr, "could not lookup keycode name\n"); + else if (strstart(keycodes, "evdev", NULL)) + has_evdev = 1; + else if (!strstart(keycodes, "xfree86", NULL)) + fprintf(stderr, + "unknown keycodes `%s', please report to qemu-devel@nongnu.org\n", + keycodes); + + XkbFreeClientMap(desc, XkbGBN_AllComponentsMask, True); + + return has_evdev; +} +#else +static int check_for_evdev(void) +{ + return 0; +} +#endif + static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev) { int keycode; + static int has_evdev = -1; + + if (has_evdev == -1) + has_evdev = check_for_evdev(); keycode = ev->keysym.scancode; @@ -138,9 +283,16 @@ static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev) keycode = 0; } else if (keycode < 97) { keycode -= 8; /* just an offset */ - } else if (keycode < 212) { + } else if (keycode < 158) { /* use conversion table */ - keycode = _translate_keycode(keycode - 97); + if (has_evdev) + keycode = translate_evdev_keycode(keycode - 97); + else + keycode = translate_xfree86_keycode(keycode - 97); + } else if (keycode == 208) { /* Hiragana_Katakana */ + keycode = 0x70; + } else if (keycode == 211) { /* backslash */ + keycode = 0x73; } else { keycode = 0; } @@ -270,14 +422,16 @@ static void sdl_grab_start(void) { if (guest_cursor) { SDL_SetCursor(guest_sprite); - SDL_WarpMouse(guest_x, guest_y); + if (!kbd_mouse_is_absolute() && !absolute_enabled) + SDL_WarpMouse(guest_x, guest_y); } else sdl_hide_cursor(); - SDL_WM_GrabInput(SDL_GRAB_ON); - /* dummy read to avoid moving the mouse */ - SDL_GetRelativeMouseState(NULL, NULL); - gui_grab = 1; - sdl_update_caption(); + + if (SDL_WM_GrabInput(SDL_GRAB_ON) == SDL_GRAB_ON) { + gui_grab = 1; + sdl_update_caption(); + } else + sdl_show_cursor(); } static void sdl_grab_end(void) @@ -288,10 +442,9 @@ static void sdl_grab_end(void) sdl_update_caption(); } -static void sdl_send_mouse_event(int dz) +static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state) { - int dx, dy, state, buttons; - state = SDL_GetRelativeMouseState(&dx, &dy); + int buttons; buttons = 0; if (state & SDL_BUTTON(SDL_BUTTON_LEFT)) buttons |= MOUSE_EVENT_LBUTTON; @@ -309,18 +462,18 @@ static void sdl_send_mouse_event(int dz) absolute_enabled = 1; } - SDL_GetMouseState(&dx, &dy); - dx = dx * 0x7FFF / width; - dy = dy * 0x7FFF / height; + dx = x * 0x7FFF / (width - 1); + dy = y * 0x7FFF / (height - 1); } else if (absolute_enabled) { sdl_show_cursor(); absolute_enabled = 0; } else if (guest_cursor) { - SDL_GetMouseState(&dx, &dy); - dx -= guest_x; - dy -= guest_y; - guest_x += dx; - guest_y += dy; + x -= guest_x; + y -= guest_y; + guest_x += x; + guest_y += y; + dx = x; + dy = y; } kbd_mouse_event(dx, dy, dz, buttons); @@ -329,7 +482,7 @@ static void sdl_send_mouse_event(int dz) static void toggle_full_screen(DisplayState *ds) { gui_fullscreen = !gui_fullscreen; - sdl_resize(ds, screen->w, screen->h); + do_sdl_resize(real_screen->w, real_screen->h, real_screen->format->BitsPerPixel); if (gui_fullscreen) { gui_saved_grab = gui_grab; sdl_grab_start(); @@ -345,6 +498,7 @@ static void sdl_refresh(DisplayState *ds) { SDL_Event ev1, *ev = &ev1; int mod_state; + int buttonstate = SDL_GetMouseState(NULL, NULL); if (last_vm_running != vm_running) { last_vm_running = vm_running; @@ -352,11 +506,12 @@ static void sdl_refresh(DisplayState *ds) } vga_hw_update(); + SDL_EnableUNICODE(!is_graphic_console()); while (SDL_PollEvent(ev)) { switch (ev->type) { case SDL_VIDEOEXPOSE: - sdl_update(ds, 0, 0, screen->w, screen->h); + sdl_update(ds, 0, 0, real_screen->w, real_screen->h); break; case SDL_KEYDOWN: case SDL_KEYUP: @@ -464,15 +619,14 @@ static void sdl_refresh(DisplayState *ds) sdl_process_key(&ev->key); break; case SDL_QUIT: - if (!no_quit) { + if (!no_quit) qemu_system_shutdown_request(); - vm_start(); /* In case we're paused */ - } break; case SDL_MOUSEMOTION: if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) { - sdl_send_mouse_event(0); + sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0, + ev->motion.x, ev->motion.y, ev->motion.state); } break; case SDL_MOUSEBUTTONDOWN: @@ -481,13 +635,18 @@ static void sdl_refresh(DisplayState *ds) SDL_MouseButtonEvent *bev = &ev->button; if (!gui_grab && !kbd_mouse_is_absolute()) { if (ev->type == SDL_MOUSEBUTTONDOWN && - (bev->state & SDL_BUTTON_LMASK)) { + (bev->button == SDL_BUTTON_LEFT)) { /* start grabbing all events */ sdl_grab_start(); } } else { int dz; dz = 0; + if (ev->type == SDL_MOUSEBUTTONDOWN) { + buttonstate |= SDL_BUTTON(bev->button); + } else { + buttonstate &= ~SDL_BUTTON(bev->button); + } #ifdef SDL_BUTTON_WHEELUP if (bev->button == SDL_BUTTON_WHEELUP && ev->type == SDL_MOUSEBUTTONDOWN) { dz = -1; @@ -495,7 +654,7 @@ static void sdl_refresh(DisplayState *ds) dz = 1; } #endif - sdl_send_mouse_event(dz); + sdl_send_mouse_event(0, 0, dz, bev->x, bev->y, buttonstate); } } break; @@ -504,6 +663,17 @@ static void sdl_refresh(DisplayState *ds) !ev->active.gain && !gui_fullscreen_initial_grab) { sdl_grab_end(); } + if (ev->active.state & SDL_APPACTIVE) { + if (ev->active.gain) { + /* Back to default interval */ + dcl->gui_timer_interval = 0; + dcl->idle = 0; + } else { + /* Sleeping interval */ + dcl->gui_timer_interval = 500; + dcl->idle = 1; + } + } break; default: break; @@ -514,7 +684,7 @@ static void sdl_refresh(DisplayState *ds) static void sdl_fill(DisplayState *ds, int x, int y, int w, int h, uint32_t c) { SDL_Rect dst = { x, y, w, h }; - SDL_FillRect(screen, &dst, c); + SDL_FillRect(real_screen, &dst, c); } static void sdl_mouse_warp(int x, int y, int on) @@ -524,7 +694,8 @@ static void sdl_mouse_warp(int x, int y, int on) sdl_show_cursor(); if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) { SDL_SetCursor(guest_sprite); - SDL_WarpMouse(x, y); + if (!kbd_mouse_is_absolute() && !absolute_enabled) + SDL_WarpMouse(x, y); } } else if (gui_grab) sdl_hide_cursor(); @@ -582,13 +753,15 @@ static void sdl_cleanup(void) { if (guest_sprite) SDL_FreeCursor(guest_sprite); - SDL_Quit(); + SDL_QuitSubSystem(SDL_INIT_VIDEO); } void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) { int flags; uint8_t data = 0; + DisplayAllocator *da; + const SDL_VideoInfo *vi; #if defined(__APPLE__) /* always use generic keymaps */ @@ -596,7 +769,7 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) keyboard_layout = "en-us"; #endif if(keyboard_layout) { - kbd_layout = init_keyboard_layout(keyboard_layout); + kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout); if (!kbd_layout) exit(1); } @@ -609,23 +782,33 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) fprintf(stderr, "Could not initialize SDL - exiting\n"); exit(1); } -#ifndef _WIN32 - /* NOTE: we still want Ctrl-C to work, so we undo the SDL redirections */ - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); -#endif - - ds->dpy_update = sdl_update; - ds->dpy_resize = sdl_resize; - ds->dpy_refresh = sdl_refresh; - ds->dpy_fill = sdl_fill; + vi = SDL_GetVideoInfo(); + hostbpp = vi->vfmt->BitsPerPixel; + + dcl = qemu_mallocz(sizeof(DisplayChangeListener)); + dcl->dpy_update = sdl_update; + dcl->dpy_resize = sdl_resize; + dcl->dpy_refresh = sdl_refresh; + dcl->dpy_setdata = sdl_setdata; + dcl->dpy_fill = sdl_fill; ds->mouse_set = sdl_mouse_warp; ds->cursor_define = sdl_mouse_define; + register_displaychangelistener(ds, dcl); + + da = qemu_mallocz(sizeof(DisplayAllocator)); + da->create_displaysurface = sdl_create_displaysurface; + da->resize_displaysurface = sdl_resize_displaysurface; + da->free_displaysurface = sdl_free_displaysurface; + if (register_displayallocator(ds, da) == da) { + DisplaySurface *surf; + surf = sdl_create_displaysurface(ds_get_width(ds), ds_get_height(ds)); + defaultallocator_free_displaysurface(ds->surface); + ds->surface = surf; + dpy_resize(ds); + } - sdl_resize(ds, 640, 400); sdl_update_caption(); SDL_EnableKeyRepeat(250, 50); - SDL_EnableUNICODE(1); gui_grab = 0; sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0);