From 3cf77a8b3c80b0306a0e73677ac6faeb1f83e0a2 Mon Sep 17 00:00:00 2001 From: Andrzej Zaborowski Date: Sun, 11 Mar 2007 15:31:12 +0100 Subject: [PATCH] Host-accelerated mouse cursor support in SDL. --- sdl.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- vl.c | 4 ++ vl.h | 9 +++++- 3 files changed, 114 insertions(+), 4 deletions(-) diff --git a/sdl.c b/sdl.c index 0cb2241..784049c 100644 --- a/sdl.c +++ b/sdl.c @@ -44,6 +44,9 @@ static int width, height; static SDL_Cursor *sdl_cursor_normal; static SDL_Cursor *sdl_cursor_hidden; static int absolute_enabled = 0; +static int guest_cursor = 0; +static int guest_x, guest_y; +static SDL_Cursor *guest_sprite = 0; static void sdl_update(DisplayState *ds, int x, int y, int w, int h) { @@ -240,13 +243,20 @@ static void sdl_show_cursor(void) { if (!kbd_mouse_is_absolute()) { SDL_ShowCursor(1); - SDL_SetCursor(sdl_cursor_normal); + if (guest_cursor && + (gui_grab || kbd_mouse_is_absolute() || absolute_enabled)) + SDL_SetCursor(guest_sprite); + else + SDL_SetCursor(sdl_cursor_normal); } } static void sdl_grab_start(void) { - sdl_hide_cursor(); + if (guest_cursor) + SDL_SetCursor(guest_sprite); + else + sdl_hide_cursor(); SDL_WM_GrabInput(SDL_GRAB_ON); /* dummy read to avoid moving the mouse */ SDL_GetRelativeMouseState(NULL, NULL); @@ -257,8 +267,8 @@ static void sdl_grab_start(void) static void sdl_grab_end(void) { SDL_WM_GrabInput(SDL_GRAB_OFF); - sdl_show_cursor(); gui_grab = 0; + sdl_show_cursor(); sdl_update_caption(); } @@ -289,6 +299,12 @@ static void sdl_send_mouse_event(int dz) } 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; } kbd_mouse_event(dx, dy, dz, buttons); @@ -467,8 +483,86 @@ static void sdl_refresh(DisplayState *ds) } } +static void sdl_copy(DisplayState *ds, int src_x, int src_y, + int dst_x, int dst_y, int w, int h) +{ + SDL_Rect src = { src_x, src_y, w, h }; + SDL_Rect dst = { dst_x, dst_y, w, h }; + SDL_LowerBlit(screen, &src, screen, &dst); +} + +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); +} + +static void sdl_mouse_warp(int x, int y, int on) +{ + guest_cursor = on; + if (on) { + sdl_show_cursor(); + if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) { + SDL_SetCursor(guest_sprite); + SDL_WarpMouse(guest_x = x, guest_y = y); + } + } else if (gui_grab) + sdl_hide_cursor(); +} + +static void sdl_mouse_define(int width, int height, int bpp, + int hot_x, int hot_y, + uint8_t *image, uint8_t *mask) +{ + uint8_t sprite[256], *line; + int x, y, dst, bypl, src = 0; + if (guest_sprite) + SDL_FreeCursor(guest_sprite); + + memset(sprite, 0, 256); + bypl = ((width * bpp + 31) >> 5) << 2; + for (y = 0, dst = 0; y < height; y ++, image += bypl) { + line = image; + for (x = 0; x < width; x ++, dst ++) { + switch (bpp) { + case 24: + src = *(line ++); src |= *(line ++); src |= *(line ++); + break; + case 16: + case 15: + src = *(line ++); src |= *(line ++); + break; + case 8: + src = *(line ++); + break; + case 4: + src = 0xf & (line[x >> 1] >> ((x & 1)) << 2); + break; + case 2: + src = 3 & (line[x >> 2] >> ((x & 3)) << 1); + break; + case 1: + src = 1 & (line[x >> 3] >> (x & 7)); + break; + } + if (!src) + sprite[dst >> 3] |= (1 << (~dst & 7)) & mask[dst >> 3]; + } + } + guest_sprite = SDL_CreateCursor(sprite, mask, width, height, hot_x, hot_y); + + if (guest_cursor && + (gui_grab || kbd_mouse_is_absolute() || absolute_enabled)) + SDL_SetCursor(guest_sprite); +} + static void sdl_cleanup(void) { + kbd_mouse_set = 0; + kbd_cursor_define = 0; + + if (guest_sprite) + SDL_FreeCursor(guest_sprite); SDL_Quit(); } @@ -505,6 +599,8 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) ds->dpy_update = sdl_update; ds->dpy_resize = sdl_resize; ds->dpy_refresh = sdl_refresh; + ds->dpy_copy = sdl_copy; + ds->dpy_fill = sdl_fill; sdl_resize(ds, 640, 400); sdl_update_caption(); @@ -515,6 +611,9 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0); sdl_cursor_normal = SDL_GetCursor(); + kbd_mouse_set = sdl_mouse_warp; + kbd_cursor_define = sdl_mouse_define; + atexit(sdl_cleanup); if (full_screen) { gui_fullscreen = 1; diff --git a/vl.c b/vl.c index e871c8c..98fef9d 100644 --- a/vl.c +++ b/vl.c @@ -542,6 +542,10 @@ int kbd_mouse_is_absolute(void) return qemu_put_mouse_event_current->qemu_put_mouse_event_absolute; } +void (*kbd_mouse_set)(int x, int y, int on) = NULL; +void (*kbd_cursor_define)(int width, int height, int bpp, int hot_x, int hot_y, + uint8_t *image, uint8_t *mask) = NULL; + void do_info_mice(void) { QEMUPutMouseEntry *cursor; diff --git a/vl.h b/vl.h index c7c7d73..04fe3cc 100644 --- a/vl.h +++ b/vl.h @@ -201,6 +201,10 @@ void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry); void kbd_put_keycode(int keycode); void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); int kbd_mouse_is_absolute(void); +extern void (*kbd_mouse_set)(int x, int y, int on); +extern void (*kbd_cursor_define)(int width, int height, int bpp, + int hot_x, int hot_y, + uint8_t *image, uint8_t *mask); void do_info_mice(void); void do_mouse_set(int index); @@ -890,7 +894,10 @@ struct DisplayState { void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h); void (*dpy_resize)(struct DisplayState *s, int w, int h); void (*dpy_refresh)(struct DisplayState *s); - void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y, int dst_x, int dst_y, int w, int h); + void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y, + int dst_x, int dst_y, int w, int h); + void (*dpy_fill)(struct DisplayState *s, int x, int y, + int w, int h, uint32_t c); }; static inline void dpy_update(DisplayState *s, int x, int y, int w, int h) -- 1.4.4.3