This should allow the emulated video cards that support hardware accelerated cursors to relay the cursor drawing to host, possibly using real hardware cursor. This way the guest and host effectively share one cursor. Only SDL support is included. Not tested with mice that report absolute coordinates.
The cursor does not appear in the framebuffer seen by the guest, it's only drawn on the host. One funny effect is that it's not clipped to the size of the framebuffer and can stick out of the SDL window. I think the sdl.c could use a small rewrite to have all cursor hiding and showing in one place instead of spread across the file. VNC support would need employing an extension for this, according to Anthony Liguori. VMware made a documented VNC extension that does it.
From 3cf77a8b3c80b0306a0e73677ac6faeb1f83e0a2 Mon Sep 17 00:00:00 2001 From: Andrzej Zaborowski <[EMAIL PROTECTED]> 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
_______________________________________________ Qemu-devel mailing list Qemu-devel@nongnu.org http://lists.nongnu.org/mailman/listinfo/qemu-devel