packing update
[qemu] / sdl.c
diff --git a/sdl.c b/sdl.c
index 431e527..a748426 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
 
-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;
@@ -52,11 +56,34 @@ static SDL_Cursor *guest_sprite = 0;
 
 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_UpdateRect(screen, x, y, w, 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 sdl_resize(DisplayState *ds)
 {
     int flags;
 
@@ -68,40 +95,20 @@ 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 = ds_get_width(ds);
+    height = ds_get_height(ds);
+    real_screen = SDL_SetVideoMode(width, height, 0, 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;
-    }
 
-    if (!screen->pixels) {
-        fprintf(stderr, "Could not open SDL display\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;
+    sdl_setdata(ds);
 }
 
 /* generic keyboard conversion */
 
 #include "sdl_keysym.h"
-#include "keymaps.c"
 
 static kbd_layout_t *kbd_layout = NULL;
 
@@ -130,9 +137,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;
 
@@ -140,9 +192,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;
     }
@@ -272,12 +331,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);
-    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)
@@ -328,7 +391,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, screen->w, screen->h);
+    sdl_resize(ds);
     if (gui_fullscreen) {
         gui_saved_grab = gui_grab;
         sdl_grab_start();
@@ -352,11 +415,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,10 +528,8 @@ 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() ||
@@ -513,10 +575,12 @@ static void sdl_refresh(DisplayState *ds)
             if (ev->active.state & SDL_APPACTIVE) {
                 if (ev->active.gain) {
                     /* Back to default interval */
-                    ds->gui_timer_interval = 0;
+                    dcl->gui_timer_interval = 0;
+                    dcl->idle = 0;
                 } else {
                     /* Sleeping interval */
-                    ds->gui_timer_interval = 500;
+                    dcl->gui_timer_interval = 500;
+                    dcl->idle = 1;
                 }
             }
             break;
@@ -529,7 +593,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)
@@ -539,7 +603,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();
@@ -611,7 +676,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);
     }
@@ -624,23 +689,19 @@ 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;
+    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);
 
-    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);