summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2010-09-13 17:35:55 +0200
committerGerd Hoffmann <kraxel@redhat.com>2010-09-13 17:35:55 +0200
commit1f8613b8839dfd7356823d518fa73e3cc8e01895 (patch)
tree2beab1a81c0048ff3c814409ee0be7c33501836d
parent3c30063945d67cd452a59c5445b29492749b623e (diff)
cursor bits.
guest agent bits.
-rw-r--r--gtk/README4
-rw-r--r--gtk/channel-cursor.c136
-rw-r--r--gtk/channel-display.c92
-rw-r--r--gtk/channel-inputs.c4
-rw-r--r--gtk/channel-main.c108
-rw-r--r--gtk/spice-channel-priv.h17
-rw-r--r--gtk/spice-channel.c14
-rw-r--r--gtk/spice-channel.h10
-rw-r--r--gtk/spice-marshal.txt3
-rw-r--r--gtk/spice-widget.c62
10 files changed, 348 insertions, 102 deletions
diff --git a/gtk/README b/gtk/README
index fe14306..bfda36c 100644
--- a/gtk/README
+++ b/gtk/README
@@ -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: