Create qemu-option.h
[qemu] / sdl.c
diff --git a/sdl.c b/sdl.c
index cfdf852..178b553 100644 (file)
--- a/sdl.c
+++ b/sdl.c
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#include "qemu-common.h"
-#include "console.h"
-#include "sysemu.h"
-
 #include <SDL.h>
+#include <SDL_syswm.h>
 
 #ifndef _WIN32
 #include <signal.h>
 #endif
 
+#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;
@@ -51,17 +53,20 @@ 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)
 {
-    SDL_Rect rec;
-    rec.x = x;
-    rec.y = y;
-    rec.w = w;
-    rec.h = h;
     //    printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
-
-    SDL_BlitSurface(guest_screen, &rec, real_screen, &rec);
+    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);
 }
 
@@ -81,7 +86,7 @@ static void sdl_setdata(DisplayState *ds)
                                             ds->surface->pf.bmask, ds->surface->pf.amask);
 }
 
-static void sdl_resize(DisplayState *ds)
+static void do_sdl_resize(int new_width, int new_height, int bpp)
 {
     int flags;
 
@@ -93,21 +98,108 @@ static void sdl_resize(DisplayState *ds)
     if (gui_noframe)
         flags |= SDL_NOFRAME;
 
-    width = ds_get_width(ds);
-    height = ds_get_height(ds);
-    real_screen = SDL_SetVideoMode(width, height, 0, flags);
+    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);
     }
+}
 
-    sdl_setdata(ds);
+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;
+        }
+    }
+}
+
+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);
+    }
+
+    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;
 
@@ -136,9 +228,54 @@ static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
 
 #else
 
+#if defined(SDL_VIDEO_DRIVER_X11)
+#include <X11/XKBlib.h>
+
+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;
 
@@ -146,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;
     }
@@ -338,7 +482,7 @@ static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state
 static void toggle_full_screen(DisplayState *ds)
 {
     gui_fullscreen = !gui_fullscreen;
-    sdl_resize(ds);
+    do_sdl_resize(real_screen->w, real_screen->h, real_screen->format->BitsPerPixel);
     if (gui_fullscreen) {
         gui_saved_grab = gui_grab;
         sdl_grab_start();
@@ -609,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 */
@@ -623,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);
     }
@@ -636,10 +782,10 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
         fprintf(stderr, "Could not initialize SDL - exiting\n");
         exit(1);
     }
+    vi = SDL_GetVideoInfo();
+    hostbpp = vi->vfmt->BitsPerPixel;
 
     dcl = qemu_mallocz(sizeof(DisplayChangeListener));
-    if (!dcl)
-        exit(1);
     dcl->dpy_update = sdl_update;
     dcl->dpy_resize = sdl_resize;
     dcl->dpy_refresh = sdl_refresh;
@@ -649,6 +795,18 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
     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_update_caption();
     SDL_EnableKeyRepeat(250, 50);
     gui_grab = 0;