diff options
author | Gerd Hoffmann <kraxel@redhat.com> | 2010-09-13 17:35:55 +0200 |
---|---|---|
committer | Gerd Hoffmann <kraxel@redhat.com> | 2010-09-13 17:35:55 +0200 |
commit | 1f8613b8839dfd7356823d518fa73e3cc8e01895 (patch) | |
tree | 2beab1a81c0048ff3c814409ee0be7c33501836d | |
parent | 3c30063945d67cd452a59c5445b29492749b623e (diff) |
cursor bits.
guest agent bits.
-rw-r--r-- | gtk/README | 4 | ||||
-rw-r--r-- | gtk/channel-cursor.c | 136 | ||||
-rw-r--r-- | gtk/channel-display.c | 92 | ||||
-rw-r--r-- | gtk/channel-inputs.c | 4 | ||||
-rw-r--r-- | gtk/channel-main.c | 108 | ||||
-rw-r--r-- | gtk/spice-channel-priv.h | 17 | ||||
-rw-r--r-- | gtk/spice-channel.c | 14 | ||||
-rw-r--r-- | gtk/spice-channel.h | 10 | ||||
-rw-r--r-- | gtk/spice-marshal.txt | 3 | ||||
-rw-r--r-- | gtk/spice-widget.c | 62 |
10 files changed, 348 insertions, 102 deletions
@@ -8,13 +8,11 @@ Porting spice client to gtk ... current state ------------- -Starts running stable. -Not really usable due to missing features (especially keyboard). +Starts becoming usable. Lots of features are missing: - No password authentication. - No TLS support. - - No keyboard input. - No server mouse mode support. - No sound support. - No vdagent support. diff --git a/gtk/channel-cursor.c b/gtk/channel-cursor.c index 306b337..c16f81b 100644 --- a/gtk/channel-cursor.c +++ b/gtk/channel-cursor.c @@ -1,9 +1,129 @@ +#include <assert.h> + #include "spice-client.h" #include "spice-channel-priv.h" +#include "spice-channel-cache.h" + +static void mono_cursor(display_cursor *cursor, uint8_t *data) +{ + uint8_t *xor, *and, *dest; + int bpl, x, y, bit; + + bpl = (cursor->hdr.width + 7) / 8; + and = data; + xor = and + bpl * cursor->hdr.height; + dest = cursor->data; + for (y = 0; y < cursor->hdr.height; y++) { + bit = 0x80; + for (x = 0; x < cursor->hdr.width; x++, dest += 4) { + if (and[x/8] & bit) { + if (xor[x/8] & bit) { + /* flip -> hmm? */ + dest[0] = 0x00; + dest[1] = 0x00; + dest[2] = 0x00; + dest[3] = 0x80; + } else { + /* unchanged -> transparent */ + dest[0] = 0x00; + dest[1] = 0x00; + dest[2] = 0x00; + dest[3] = 0x00; + } + } else { + if (xor[x/8] & bit) { + /* set -> white */ + dest[0] = 0xff; + dest[1] = 0xff; + dest[2] = 0xff; + dest[3] = 0xff; + } else { + /* clear -> black */ + dest[0] = 0x00; + dest[1] = 0x00; + dest[2] = 0x00; + dest[3] = 0xff; + } + } + bit >>= 1; + if (bit == 0) { + bit = 0x80; + } + } + and += bpl; + xor += bpl; + } +} + +static display_cursor *set_cursor(SpiceChannel *channel, SpiceCursor *scursor) +{ + spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); + SpiceCursorHeader *hdr = &scursor->header; + display_cache_item *item; + display_cursor *cursor; + size_t size; + +#if 0 + fprintf(stderr, "%s: type %d, %" PRIx64 ", %dx%d, flags %d, size %d\n", + __FUNCTION__, hdr->type, hdr->unique, hdr->width, hdr->height, + scursor->flags, scursor->data_size); +#endif + + if (scursor->flags & SPICE_CURSOR_FLAGS_FROM_CACHE) { + item = cache_find(&c->cursor.cursors, hdr->unique); + if (!item) { + return NULL; + } + return item->ptr.cursor; + } + if (scursor->data_size == 0) { + return NULL; + } + + size = 4 * hdr->width * hdr->height; + cursor = spice_malloc(sizeof(*cursor) + size); + cursor->hdr = *hdr; + + switch (hdr->type) { + case SPICE_CURSOR_TYPE_MONO: + mono_cursor(cursor, scursor->data); + break; + case SPICE_CURSOR_TYPE_ALPHA: + memcpy(cursor->data, scursor->data, size); + break; + default: + fprintf(stderr, "%s: unimplemented cursor type %d\n", __FUNCTION__, + hdr->type); + free(cursor); + cursor = NULL; + break; + } + + if (cursor && (scursor->flags & SPICE_CURSOR_FLAGS_CACHE_ME)) { + item = cache_add(&c->cursor.cursors, hdr->unique); + item->ptr.cursor = cursor; + } + + return cursor; +} + +static void emit_cursor(SpiceChannel *channel, display_cursor *cursor) +{ + if (!cursor) + return; + g_signal_emit(channel, channel_signals[SPICE_CURSOR_SET], 0, + cursor->hdr.width, cursor->hdr.height, + cursor->hdr.hot_spot_x, cursor->hdr.hot_spot_y, + cursor->data); +} static void cursor_handle_init(SpiceChannel *channel, spice_msg_in *in) { -// SpiceMsgCursorInit *init = spice_msg_in_parsed(in); + SpiceMsgCursorInit *init = spice_msg_in_parsed(in); + display_cursor *cursor; + + cursor = set_cursor(channel, &init->cursor); + emit_cursor(channel, cursor); #if 0 attach_to_screen(get_client().get_application(), get_id()); @@ -21,7 +141,11 @@ static void cursor_handle_reset(SpiceChannel *channel, spice_msg_in *in) static void cursor_handle_set(SpiceChannel *channel, spice_msg_in *in) { - fprintf(stderr, "%s: TODO\n", __FUNCTION__); + SpiceMsgCursorSet *set = spice_msg_in_parsed(in); + display_cursor *cursor; + + cursor = set_cursor(channel, &set->cursor); + emit_cursor(channel, cursor); } static void cursor_handle_move(SpiceChannel *channel, spice_msg_in *in) @@ -49,6 +173,13 @@ static void cursor_handle_inval_all(SpiceChannel *channel, spice_msg_in *in) fprintf(stderr, "%s: TODO\n", __FUNCTION__); } +static void cursor_alloc(SpiceChannel *channel) +{ + spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); + + cache_init(&c->cursor.cursors, "cursor"); +} + static spice_msg_handler cursor_handlers[] = { [ SPICE_MSG_SET_ACK ] = base_handle_set_ack, [ SPICE_MSG_PING ] = base_handle_ping, @@ -67,6 +198,7 @@ static spice_msg_handler cursor_handlers[] = { spice_channel_info cursor_channel_info = { .type = SPICE_CHANNEL_CURSOR, .name = "cursor", + .alloc = cursor_alloc, .handlers = cursor_handlers, .nhandlers = SPICE_N_ELEMENTS(cursor_handlers), }; diff --git a/gtk/channel-display.c b/gtk/channel-display.c index 0327198..4493346 100644 --- a/gtk/channel-display.c +++ b/gtk/channel-display.c @@ -3,84 +3,7 @@ #include "spice-client.h" #include "spice-channel-priv.h" - -static void cache_init(display_cache *cache, const char *name) -{ - int i; - - cache->name = name; - ring_init(&cache->lru); - for (i = 0; i < SPICE_N_ELEMENTS(cache->hash); i++) { - ring_init(&cache->hash[i]); - } -} - -static Ring *cache_head(display_cache *cache, uint64_t id) -{ - return &cache->hash[id % SPICE_N_ELEMENTS(cache->hash)]; -} - -static void cache_used(display_cache *cache, display_cache_item *item) -{ - ring_remove(&item->lru_link); - ring_add(&cache->lru, &item->lru_link); -} - -static display_cache_item *cache_get_lru(display_cache *cache) -{ - display_cache_item *item; - RingItem *ring; - - ring = ring_get_tail(&cache->lru); - item = SPICE_CONTAINEROF(ring, display_cache_item, lru_link); - return item; -} - -static display_cache_item *cache_find(display_cache *cache, uint64_t id) -{ - display_cache_item *item; - RingItem *ring; - Ring *head; - - head = cache_head(cache, id); - for (ring = head; ring != NULL; ring = ring_next(head, ring)) { - item = SPICE_CONTAINEROF(ring, display_cache_item, hash_link); - if (item->id == id) { - return item; - } - } - fprintf(stderr, "%s: %s %" PRIx64 " [not found]\n", __FUNCTION__, - cache->name, id); - return NULL; -} - -static display_cache_item *cache_add(display_cache *cache, uint64_t id) -{ - display_cache_item *item; - - item = spice_new0(display_cache_item, 1); - item->id = id; - ring_add(cache_head(cache, item->id), &item->hash_link); - ring_add(&cache->lru, &item->lru_link); - cache->nitems++; -#if 0 - fprintf(stderr, "%s: %s %" PRIx64 " (%d)\n", __FUNCTION__, - cache->name, id, cache->nitems); -#endif - return item; -} - -static void cache_del(display_cache *cache, display_cache_item *item) -{ -#if 0 - fprintf(stderr, "%s: %s %" PRIx64 "\n", __FUNCTION__, - cache->name, item->id); -#endif - ring_remove(&item->hash_link); - ring_remove(&item->lru_link); - free(item); - cache->nitems--; -} +#include "spice-channel-cache.h" static void image_put(SpiceImageCache *cache, uint64_t id, pixman_image_t *image) { @@ -261,19 +184,6 @@ static void display_ready(SpiceChannel *channel) c->marshallers->msgc_display_init(out->marshaller, &init); spice_msg_out_send(out); spice_msg_out_put(out); - -#if 0 - Message* message = new Message(SPICE_MSGC_DISPLAY_INIT); - SpiceMsgcDisplayInit init; - init.pixmap_cache_id = 1; - init.pixmap_cache_size = get_client().get_pixmap_cache_size(); - init.glz_dictionary_id = 1; - init.glz_dictionary_window_size = get_client().get_glz_window_size(); - _marshallers->msgc_display_init(message->marshaller(), &init); - post_message(message); - AutoRef<AttachChannelsEvent> attach_channels(new AttachChannelsEvent(*this)); - get_client().push_event(*attach_channels); -#endif } #define DRAW(type) { \ diff --git a/gtk/channel-inputs.c b/gtk/channel-inputs.c index 9e2b604..c679d91 100644 --- a/gtk/channel-inputs.c +++ b/gtk/channel-inputs.c @@ -156,7 +156,9 @@ void spice_inputs_key_press(SpiceChannel *channel, guint scancode) SpiceMsgcKeyDown down; spice_msg_out *msg; +#if 0 fprintf(stderr, "%s: scancode %d\n", __FUNCTION__, scancode); +#endif if (scancode < 0x100) { down.code = scancode; } else { @@ -175,7 +177,9 @@ void spice_inputs_key_release(SpiceChannel *channel, guint scancode) SpiceMsgcKeyUp up; spice_msg_out *msg; +#if 0 fprintf(stderr, "%s: scancode %d\n", __FUNCTION__, scancode); +#endif if (scancode < 0x100) { up.code = scancode | 0x80; } else { diff --git a/gtk/channel-main.c b/gtk/channel-main.c index 8c39832..c5c8300 100644 --- a/gtk/channel-main.c +++ b/gtk/channel-main.c @@ -2,6 +2,68 @@ #include "spice-channel-priv.h" #include "spice-session-priv.h" +#include <spice/vd_agent.h> + +static void agent_monitors_config(SpiceChannel *channel) +{ + spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); + spice_msg_out *out; + VDAgentMessage* msg; + VDAgentMonitorsConfig *mon; + int i, monitors = 1; + size_t size; + + if (!c->main.agent_connected) + return; + for (i = 0; i < monitors; i++) { + if (!c->main.display[i].width || + !c->main.display[i].height) + return; + } + + size = sizeof(VDAgentMonitorsConfig) + sizeof(VDAgentMonConfig) * monitors; + out = spice_msg_out_new(channel, SPICE_MSGC_MAIN_AGENT_DATA); + msg = (VDAgentMessage*) + spice_marshaller_reserve_space(out->marshaller, sizeof(VDAgentMessage)); + mon = (VDAgentMonitorsConfig*) + spice_marshaller_reserve_space(out->marshaller, size); + + msg->type = VD_AGENT_MONITORS_CONFIG; + msg->opaque = 0; + msg->size = size; + + mon->num_of_monitors = monitors; + mon->flags = 0; + for (i = 0; i < monitors; i++) { + mon->monitors[i].depth = 32; + mon->monitors[i].width = c->main.display[i].width; + mon->monitors[i].height = c->main.display[i].height; + mon->monitors[i].x = 0; + mon->monitors[i].y = 0; + } + + fprintf(stderr, "%s: sending\n", __FUNCTION__); + spice_msg_out_send(out); + spice_msg_out_put(out); +} + +static void agent_start(SpiceChannel *channel) +{ + spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); + SpiceMsgcMainAgentStart agent_start = { + .num_tokens = ~0, + }; + spice_msg_out *out; + + fprintf(stderr, "%s\n", __FUNCTION__); + out = spice_msg_out_new(channel, SPICE_MSGC_MAIN_AGENT_START); + c->marshallers->msgc_main_agent_start(out->marshaller, &agent_start); + spice_msg_out_send(out); + spice_msg_out_put(out); + + agent_monitors_config(channel); +} + static void set_mouse_mode(SpiceChannel *channel, uint32_t supported, uint32_t current) { spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); @@ -40,6 +102,12 @@ static void main_handle_init(SpiceChannel *channel, spice_msg_in *in) set_mouse_mode(channel, init->supported_mouse_modes, init->current_mouse_mode); + c->main.agent_tokens = init->agent_tokens; + c->main.agent_connected = !!init->agent_connected; + if (c->main.agent_connected) { + agent_start(channel); + } + #if 0 set_mm_time(init->multi_media_time); calc_pixmap_cach_and_glz_window_size(init->display_channels_hint, init->ram_hint); @@ -106,6 +174,29 @@ static void main_handle_mouse_mode(SpiceChannel *channel, spice_msg_in *in) set_mouse_mode(channel, msg->supported_modes, msg->current_mode); } +static void main_handle_agent_connected(SpiceChannel *channel, spice_msg_in *in) +{ + spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); + + c->main.agent_connected = true; + agent_start(channel); +} + +static void main_handle_agent_disconnected(SpiceChannel *channel, spice_msg_in *in) +{ + fprintf(stderr, "%s: TODO\n", __FUNCTION__); +} + +static void main_handle_agent_data(SpiceChannel *channel, spice_msg_in *in) +{ + fprintf(stderr, "%s: TODO\n", __FUNCTION__); +} + +static void main_handle_agent_token(SpiceChannel *channel, spice_msg_in *in) +{ + fprintf(stderr, "%s: TODO\n", __FUNCTION__); +} + static spice_msg_handler main_handlers[] = { [ SPICE_MSG_SET_ACK ] = base_handle_set_ack, [ SPICE_MSG_PING ] = base_handle_ping, @@ -114,6 +205,11 @@ static spice_msg_handler main_handlers[] = { [ SPICE_MSG_MAIN_INIT ] = main_handle_init, [ SPICE_MSG_MAIN_CHANNELS_LIST ] = main_handle_channels_list, [ SPICE_MSG_MAIN_MOUSE_MODE ] = main_handle_mouse_mode, + + [ SPICE_MSG_MAIN_AGENT_CONNECTED ] = main_handle_agent_connected, + [ SPICE_MSG_MAIN_AGENT_DISCONNECTED ] = main_handle_agent_disconnected, + [ SPICE_MSG_MAIN_AGENT_DATA ] = main_handle_agent_data, + [ SPICE_MSG_MAIN_AGENT_TOKEN ] = main_handle_agent_token, }; spice_channel_info main_channel_info = { @@ -128,3 +224,15 @@ enum SpiceMouseMode spice_main_get_mouse_mode(SpiceChannel *channel) spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); return c->main.mouse_mode; } + +void spice_main_set_display(SpiceChannel *channel, int id, + int x, int y, int width, int height) +{ + spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); + + if (id < SPICE_N_ELEMENTS(c->main.display)) { + c->main.display[id].width = width; + c->main.display[id].height = height; + agent_monitors_config(channel); + } +} diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h index d7e6596..7e1dbc5 100644 --- a/gtk/spice-channel-priv.h +++ b/gtk/spice-channel-priv.h @@ -39,7 +39,13 @@ enum spice_channel_state { }; struct main_channel { - enum SpiceMouseMode mouse_mode; + enum SpiceMouseMode mouse_mode; + int agent_connected; + int agent_tokens; + struct { + int width; + int height; + } display[1]; }; #define DISPLAY_PIXMAP_CACHE (1024 * 1024 * 32) @@ -57,6 +63,11 @@ typedef struct display_surface { SpiceGlzDecoder *glz_decoder; } display_surface; +typedef struct display_cursor { + SpiceCursorHeader hdr; + uint8_t data[]; +} display_cursor; + typedef struct display_cache_item { RingItem hash_link; RingItem lru_link; @@ -64,6 +75,7 @@ typedef struct display_cache_item { union { pixman_image_t *image; SpicePalette *palette; + display_cursor *cursor; } ptr; } display_cache_item; @@ -84,6 +96,7 @@ struct display_channel { }; struct cursor_channel { + display_cache cursors; }; struct inputs_channel { @@ -132,6 +145,8 @@ enum { SPICE_DISPLAY_PRIMARY_DESTROY, SPICE_DISPLAY_INVALIDATE, + SPICE_CURSOR_SET, + SPICE_CHANNEL_LAST_SIGNAL, }; diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c index bc0e6a9..ecb8cf4 100644 --- a/gtk/spice-channel.c +++ b/gtk/spice-channel.c @@ -6,6 +6,7 @@ #include <openssl/rsa.h> #include <openssl/evp.h> #include <openssl/x509.h> +#include <openssl/ssl.h> #include <sys/socket.h> @@ -100,6 +101,19 @@ static void spice_channel_class_init(SpiceChannelClass *klass) 4, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); + channel_signals[SPICE_CURSOR_SET] = + g_signal_new("spice-cursor-set", + G_OBJECT_CLASS_TYPE(gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET(SpiceChannelClass, spice_cursor_set), + NULL, NULL, + g_cclosure_user_marshal_VOID__INT_INT_INT_INT_POINTER, + G_TYPE_NONE, + 5, + G_TYPE_INT, G_TYPE_INT, + G_TYPE_INT, G_TYPE_INT, + G_TYPE_POINTER); + g_type_class_add_private(klass, sizeof(spice_channel)); sw_canvas_init(); diff --git a/gtk/spice-channel.h b/gtk/spice-channel.h index 86183a2..0b1fb25 100644 --- a/gtk/spice-channel.h +++ b/gtk/spice-channel.h @@ -8,9 +8,9 @@ G_BEGIN_DECLS #define SPICE_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SPICE_TYPE_CHANNEL, SpiceChannelClass)) enum SpiceChannelEvent { - SPICE_CHANNEL_OPENED, + SPICE_CHANNEL_OPENED = 10, SPICE_CHANNEL_CLOSED, - SPICE_CHANNEL_ERROR_CONNECT, + SPICE_CHANNEL_ERROR_CONNECT = 20, SPICE_CHANNEL_ERROR_AUTH, SPICE_CHANNEL_ERROR_IO, }; @@ -40,6 +40,10 @@ struct _SpiceChannelClass void (*spice_display_invalidate)(SpiceChannel *channel, gint x, gint y, gint w, gint h); + /* cursor signals */ + void (*spice_cursor_set)(SpiceChannel *channel, gint width, gint height, + gint hot_x, gint hot_y, gpointer rgba); + #if 0 /* * If adding fields to this struct, remove corresponding @@ -67,6 +71,8 @@ int spice_channel_type(SpiceChannel *channel); int spice_channel_id(SpiceChannel *channel); enum SpiceMouseMode spice_main_get_mouse_mode(SpiceChannel *channel); +void spice_main_set_display(SpiceChannel *channel, int id, + int x, int y, int width, int height); void spice_inputs_motion(SpiceChannel *channel, gint dx, gint dy, gint button_state); void spice_inputs_position(SpiceChannel *channel, gint x, gint y, diff --git a/gtk/spice-marshal.txt b/gtk/spice-marshal.txt index 0720e51..130060b 100644 --- a/gtk/spice-marshal.txt +++ b/gtk/spice-marshal.txt @@ -1,2 +1,3 @@ -VOID:INT,INT,INT,INT,INT,POINTER VOID:INT,INT,INT,INT +VOID:INT,INT,INT,INT,POINTER +VOID:INT,INT,INT,INT,INT,POINTER diff --git a/gtk/spice-widget.c b/gtk/spice-widget.c index f7f7515..9ec3866 100644 --- a/gtk/spice-widget.c +++ b/gtk/spice-widget.c @@ -38,6 +38,7 @@ struct spice_display { enum SpiceMouseMode mouse_mode; bool mouse_have_pointer; + GdkCursor *mouse_cursor; bool keyboard_grab_enable; bool keyboard_grab_active; @@ -45,6 +46,8 @@ struct spice_display { const guint16 const *keycode_map; size_t keycode_maplen; + + gint timer_id; }; G_DEFINE_TYPE(SpiceDisplay, spice_display, GTK_TYPE_DRAWING_AREA) @@ -143,7 +146,7 @@ static void try_keyboard_grab(GtkWidget *widget) if (!d->mouse_have_pointer) return; - fprintf(stderr, "grab keyboard\n"); +// fprintf(stderr, "grab keyboard\n"); gdk_keyboard_grab(gtk_widget_get_window(widget), FALSE, GDK_CURRENT_TIME); d->keyboard_grab_active = true; @@ -158,10 +161,21 @@ static void try_keyboard_ungrab(GtkWidget *widget) if (!d->keyboard_grab_active) return; - fprintf(stderr, "ungrab keyboard\n"); +// fprintf(stderr, "ungrab keyboard\n"); gdk_keyboard_ungrab(GDK_CURRENT_TIME); } +static gboolean geometry_timer(gpointer data) +{ + SpiceDisplay *display = data; + spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display); + + d->timer_id = 0; + spice_main_set_display(d->main, d->channel_id, + 0, 0, d->width, d->height); + return false; +} + static void recalc_geometry(GtkWidget *widget) { SpiceDisplay *display = SPICE_DISPLAY(widget); @@ -175,6 +189,11 @@ static void recalc_geometry(GtkWidget *widget) d->my = (d->wh - d->height) / 2; fprintf(stderr, "%s: guest %dx%d, window %dx%d, offset +%d+%d\n", __FUNCTION__, d->width, d->height, d->ww, d->wh, d->mx, d->my); + + if (d->timer_id) { + g_source_remove(d->timer_id); + } + d->timer_id = g_timeout_add_seconds(1, geometry_timer, display); } static XVisualInfo *get_visual_for_format(GtkWidget *widget, enum SpiceSurfaceFmt format) @@ -405,7 +424,9 @@ static gboolean enter_event(GtkWidget *widget, GdkEventCrossing *crossing G_GNUC SpiceDisplay *display = SPICE_DISPLAY(widget); spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display); +#if 0 fprintf(stderr, "%s\n", __FUNCTION__); +#endif d->mouse_have_pointer = true; try_keyboard_grab(widget); return true; @@ -416,7 +437,9 @@ static gboolean leave_event(GtkWidget *widget, GdkEventCrossing *crossing G_GNUC SpiceDisplay *display = SPICE_DISPLAY(widget); spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display); +#if 0 fprintf(stderr, "%s\n", __FUNCTION__); +#endif d->mouse_have_pointer = false; try_keyboard_ungrab(widget); return true; @@ -427,7 +450,9 @@ static gboolean focus_in_event(GtkWidget *widget, GdkEventFocus *focus G_GNUC_UN SpiceDisplay *display = SPICE_DISPLAY(widget); spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display); +#if 0 fprintf(stderr, "%s\n", __FUNCTION__); +#endif d->keyboard_have_focus = true; try_keyboard_grab(widget); return true; @@ -438,7 +463,9 @@ static gboolean focus_out_event(GtkWidget *widget, GdkEventFocus *focus G_GNUC_U SpiceDisplay *display = SPICE_DISPLAY(widget); spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display); +#if 0 fprintf(stderr, "%s\n", __FUNCTION__); +#endif d->keyboard_have_focus = false; try_keyboard_ungrab(widget); return true; @@ -633,6 +660,35 @@ static void invalidate(SpiceChannel *channel, x + d->mx, y + d->my, w, h); } +static void cursor_set(SpiceChannel *channel, + gint width, gint height, gint hot_x, gint hot_y, + gpointer rgba, gpointer data) +{ + SpiceDisplay *display = data; + spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display); + GdkDrawable *window; + GdkDisplay *gtkdpy; + GdkPixbuf *pixbuf; + + window = gtk_widget_get_window(GTK_WIDGET(display)); + if (!window) + return; + gtkdpy = gdk_drawable_get_display(window); + + pixbuf = gdk_pixbuf_new_from_data(rgba, + GDK_COLORSPACE_RGB, + TRUE, 8, + width, + height, + width * 4, + NULL, NULL); + d->mouse_cursor = gdk_cursor_new_from_pixbuf(gtkdpy, pixbuf, + hot_x, hot_y); + g_object_unref(pixbuf); + + gdk_window_set_cursor(window, d->mouse_cursor); +} + static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data) { SpiceDisplay *display = data; @@ -657,6 +713,8 @@ static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data) if (id != d->channel_id) return; d->cursor = channel; + g_signal_connect(channel, "spice-cursor-set", + G_CALLBACK(cursor_set), display); spice_channel_connect(channel); break; case SPICE_CHANNEL_INPUTS: |