diff options
author | Gerd Hoffmann <kraxel@redhat.com> | 2010-09-08 23:53:16 +0200 |
---|---|---|
committer | Gerd Hoffmann <kraxel@redhat.com> | 2010-09-08 23:53:16 +0200 |
commit | 2556e8cd07bb07fce081d3aa6480794a1c8367fe (patch) | |
tree | 9efd747b08c148896e4e51f2a3b7b80b00361e07 | |
parent | 0162e57a0c396358f2b48f1878f3d022bbcc856f (diff) |
lot of mouse input stuff
spicy exiting on error and window close
minor tweaks
-rw-r--r-- | gtk/channel-inputs.c | 134 | ||||
-rw-r--r-- | gtk/channel-main.c | 39 | ||||
-rw-r--r-- | gtk/spice-channel-priv.h | 33 | ||||
-rw-r--r-- | gtk/spice-channel.c | 66 | ||||
-rw-r--r-- | gtk/spice-channel.h | 26 | ||||
-rw-r--r-- | gtk/spice-session.c | 5 | ||||
-rw-r--r-- | gtk/spice-widget.c | 159 | ||||
-rw-r--r-- | gtk/spicy.c | 53 |
8 files changed, 460 insertions, 55 deletions
diff --git a/gtk/channel-inputs.c b/gtk/channel-inputs.c index 6a48c10..38cd26f 100644 --- a/gtk/channel-inputs.c +++ b/gtk/channel-inputs.c @@ -1,15 +1,67 @@ #include "spice-client.h" #include "spice-channel-priv.h" +static void send_motion(SpiceChannel *channel) +{ + spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); + SpiceMsgcMouseMotion motion; + spice_msg_out *msg; + + if (!c->inputs.dx && !c->inputs.dy) + return; + + fprintf(stderr, "%s\n", __FUNCTION__); + motion.buttons_state = c->inputs.bs; + motion.dx = c->inputs.dx; + motion.dy = c->inputs.dy; + msg = spice_msg_out_new(channel, SPICE_MSGC_INPUTS_MOUSE_MOTION); + c->marshallers->msgc_inputs_mouse_motion(msg->marshaller, &motion); + spice_msg_out_send(msg); + spice_msg_out_put(msg); + + c->inputs.motion_count++; + c->inputs.dx = 0; + c->inputs.dy = 0; +} + +static void send_position(SpiceChannel *channel) +{ + spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); + SpiceMsgcMousePosition position; + spice_msg_out *msg; + + if (c->inputs.dpy == -1) + return; + + fprintf(stderr, "%s: +%d+%d\n", __FUNCTION__, c->inputs.x, c->inputs.y); + position.buttons_state = c->inputs.bs; + position.x = c->inputs.x; + position.y = c->inputs.y; + position.display_id = c->inputs.dpy; + msg = spice_msg_out_new(channel, SPICE_MSGC_INPUTS_MOUSE_POSITION); + c->marshallers->msgc_inputs_mouse_position(msg->marshaller, &position); + spice_msg_out_send(msg); + spice_msg_out_put(msg); + + c->inputs.motion_count++; + c->inputs.dpy = -1; +} + static void inputs_handle_init(SpiceChannel *channel, spice_msg_in *in) { -// SpiceMsgInputsInit* init = spice_msg_in_parsed(in); +} + +static void inputs_handle_modifiers(SpiceChannel *channel, spice_msg_in *in) +{ + fprintf(stderr, "%s: TODO\n", __FUNCTION__); +} -#if 0 - _modifiers = init->keyboard_modifiers; - AutoRef<SetInputsHandlerEvent> set_handler_event(new SetInputsHandlerEvent(*this)); - get_client().push_event(*set_handler_event); -#endif +static void inputs_handle_ack(SpiceChannel *channel, spice_msg_in *in) +{ + spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); + c->inputs.motion_count -= SPICE_INPUT_MOTION_ACK_BUNCH; + send_motion(channel); + send_position(channel); } static spice_msg_handler inputs_handlers[] = { @@ -18,6 +70,8 @@ static spice_msg_handler inputs_handlers[] = { [ SPICE_MSG_NOTIFY ] = base_handle_notify, [ SPICE_MSG_INPUTS_INIT ] = inputs_handle_init, + [ SPICE_MSG_INPUTS_KEY_MODIFIERS ] = inputs_handle_modifiers, + [ SPICE_MSG_INPUTS_MOUSE_MOTION_ACK ] = inputs_handle_ack, }; spice_channel_info inputs_channel_info = { @@ -26,3 +80,71 @@ spice_channel_info inputs_channel_info = { .handlers = inputs_handlers, .nhandlers = SPICE_N_ELEMENTS(inputs_handlers), }; + +void spice_inputs_motion(SpiceChannel *channel, gint dx, gint dy, gint button_state) +{ + spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); + + c->inputs.bs = button_state; + c->inputs.dx += dx; + c->inputs.dy += dy; + + if (c->inputs.motion_count < SPICE_INPUT_MOTION_ACK_BUNCH * 2) { + send_motion(channel); + } +} + +void spice_inputs_position(SpiceChannel *channel, gint x, gint y, + gint display, gint button_state) +{ + spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); + + c->inputs.bs = button_state; + c->inputs.x = x; + c->inputs.y = y; + c->inputs.dpy = display; + + if (c->inputs.motion_count < SPICE_INPUT_MOTION_ACK_BUNCH * 2) { + send_position(channel); + } +} + +void spice_inputs_button_press(SpiceChannel *channel, gint button, gint button_state) +{ + spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); + SpiceMsgcMousePress press = { + .button = button, + .buttons_state = button_state, + }; + spice_msg_out *msg; + + c->inputs.bs = button_state; + + send_motion(channel); + send_position(channel); + + msg = spice_msg_out_new(channel, SPICE_MSGC_INPUTS_MOUSE_PRESS); + c->marshallers->msgc_inputs_mouse_press(msg->marshaller, &press); + spice_msg_out_send(msg); + spice_msg_out_put(msg); +} + +void spice_inputs_button_release(SpiceChannel *channel, gint button, gint button_state) +{ + spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); + SpiceMsgcMouseRelease release = { + .button = button, + .buttons_state = button_state, + }; + spice_msg_out *msg; + + c->inputs.bs = button_state; + + send_motion(channel); + send_position(channel); + + msg = spice_msg_out_new(channel, SPICE_MSGC_INPUTS_MOUSE_RELEASE); + c->marshallers->msgc_inputs_mouse_release(msg->marshaller, &release); + spice_msg_out_send(msg); + spice_msg_out_put(msg); +} diff --git a/gtk/channel-main.c b/gtk/channel-main.c index d56be61..29f8905 100644 --- a/gtk/channel-main.c +++ b/gtk/channel-main.c @@ -2,6 +2,30 @@ #include "spice-channel-priv.h" #include "spice-session-priv.h" +static void set_mouse_mode(SpiceChannel *channel, uint32_t supported, uint32_t current) +{ + spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); + + if (c->main.mouse_mode != current) { + c->main.mouse_mode = current; + fprintf(stderr, "%s: %s\n", __FUNCTION__, + current == SPICE_MOUSE_MODE_SERVER ? "server" : "client"); + /* send event */ + } + + /* switch to client mode if possible */ + if ((supported & SPICE_MOUSE_MODE_CLIENT) && (current != SPICE_MOUSE_MODE_CLIENT)) { + SpiceMsgcMainMouseModeRequest req = { + .mode = SPICE_MOUSE_MODE_CLIENT, + }; + spice_msg_out *out; + out = spice_msg_out_new(channel, SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST); + c->marshallers->msgc_main_mouse_mode_request(out->marshaller, &req); + spice_msg_out_send(out); + spice_msg_out_put(out); + } +} + static void main_handle_init(SpiceChannel *channel, spice_msg_in *in) { spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); @@ -14,6 +38,8 @@ static void main_handle_init(SpiceChannel *channel, spice_msg_in *in) spice_msg_out_send(out); spice_msg_out_put(out); + set_mouse_mode(channel, init->supported_mouse_modes, init->current_mouse_mode); + #if 0 set_mm_time(init->multi_media_time); calc_pixmap_cach_and_glz_window_size(init->display_channels_hint, init->ram_hint); @@ -74,6 +100,12 @@ static void main_handle_channels_list(SpiceChannel *channel, spice_msg_in *in) } } +static void main_handle_mouse_mode(SpiceChannel *channel, spice_msg_in *in) +{ + SpiceMsgMainMouseMode *msg = spice_msg_in_parsed(in); + set_mouse_mode(channel, msg->supported_modes, msg->current_mode); +} + static spice_msg_handler main_handlers[] = { [ SPICE_MSG_SET_ACK ] = base_handle_set_ack, [ SPICE_MSG_PING ] = base_handle_ping, @@ -81,6 +113,7 @@ 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_channel_info main_channel_info = { @@ -89,3 +122,9 @@ spice_channel_info main_channel_info = { .handlers = main_handlers, .nhandlers = SPICE_N_ELEMENTS(main_handlers), }; + +enum SpiceMouseMode spice_main_get_mouse_mode(SpiceChannel *channel) +{ + spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); + return c->main.mouse_mode; +} diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h index 0a84955..b3377e4 100644 --- a/gtk/spice-channel-priv.h +++ b/gtk/spice-channel-priv.h @@ -33,25 +33,33 @@ enum spice_channel_state { SPICE_CHANNEL_STATE_READY, }; +struct main_channel { + enum SpiceMouseMode mouse_mode; +}; + typedef struct display_surface { - RingItem link; - int surface_id; - bool primary; - enum SpiceSurfaceFmt format; - int width, height, stride, size; - int shmid; - uint8_t *data; - SpiceCanvas *canvas; + RingItem link; + int surface_id; + bool primary; + enum SpiceSurfaceFmt format; + int width, height, stride, size; + int shmid; + uint8_t *data; + SpiceCanvas *canvas; } display_surface; struct display_channel { - Ring surfaces; + Ring surfaces; }; struct cursor_channel { }; struct inputs_channel { + int bs; + int dx, dy; + unsigned int x, y, dpy; + int motion_count; }; struct spice_channel { @@ -75,6 +83,7 @@ struct spice_channel { spice_msg_in *msg_in; union { + struct main_channel main; struct display_channel display; struct cursor_channel cursor; struct inputs_channel inputs; @@ -82,9 +91,9 @@ struct spice_channel { }; enum { -#if 0 - SPICE_CHANNEL_STATUS_???, -#endif + SPICE_CHANNEL_EVENT, + + SPICE_MAIN_MOUSE_MODE, SPICE_DISPLAY_PRIMARY_CREATE, SPICE_DISPLAY_PRIMARY_DESTROY, diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c index 812c9be..78100b0 100644 --- a/gtk/spice-channel.c +++ b/gtk/spice-channel.c @@ -33,7 +33,7 @@ spice_channel_finalize(GObject *gobject) { SpiceChannel *channel = SPICE_CHANNEL(gobject); - spice_channel_disconnect(channel); + spice_channel_disconnect(channel, SPICE_CHANNEL_CLOSED); /* Chain up to the parent class */ G_OBJECT_CLASS(spice_channel_parent_class)->finalize(gobject); @@ -45,6 +45,28 @@ static void spice_channel_class_init(SpiceChannelClass *klass) gobject_class->finalize = spice_channel_finalize; + channel_signals[SPICE_CHANNEL_EVENT] = + g_signal_new("spice-channel-event", + G_OBJECT_CLASS_TYPE(gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET(SpiceChannelClass, spice_channel_event), + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, + 1, + G_TYPE_INT); + + channel_signals[SPICE_MAIN_MOUSE_MODE] = + g_signal_new("spice-main-mouse-mode", + G_OBJECT_CLASS_TYPE(gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET(SpiceChannelClass, spice_main_mouse_mode), + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, + 1, + G_TYPE_INT); + channel_signals[SPICE_DISPLAY_PRIMARY_CREATE] = g_signal_new("spice-display-primary-create", G_OBJECT_CLASS_TYPE(gobject_class), @@ -85,6 +107,12 @@ static void spice_channel_class_init(SpiceChannelClass *klass) rop3_init(); } +static void spice_channel_emit_event(SpiceChannel *channel, + enum SpiceChannelEvent event) +{ + g_signal_emit(channel, channel_signals[SPICE_CHANNEL_EVENT], 0, event); +} + /* ---------------------------------------------------------------- */ spice_msg_in *spice_msg_in_new(SpiceChannel *channel) @@ -194,7 +222,8 @@ void spice_msg_out_put(spice_msg_out *out) void spice_msg_out_send(spice_msg_out *out) { - out->header->size = spice_marshaller_get_total_size(out->marshaller); + out->header->size = + spice_marshaller_get_total_size(out->marshaller) - sizeof(SpiceDataHeader); spice_channel_send_msg(out->channel, out); } @@ -220,14 +249,12 @@ static int spice_channel_recv(SpiceChannel *channel, void *buf, int len) fprintf(stderr, "channel error: %d:%d (%s) %s\n", c->info->type, c->channel_id, c->info->name, strerror(errno)); - spice_channel_disconnect(channel); - /* TODO: signal up */ + spice_channel_disconnect(channel, SPICE_CHANNEL_ERROR_IO); return 0; case 0: fprintf(stderr, "channel eof: %d:%d (%s)\n", c->info->type, c->channel_id, c->info->name); - spice_channel_disconnect(channel); - /* TODO: signal up */ + spice_channel_disconnect(channel, SPICE_CHANNEL_CLOSED); return 0; default: return rc; @@ -278,14 +305,17 @@ static void spice_channel_recv_auth(SpiceChannel *channel) rc = spice_channel_recv(channel, &link_res, sizeof(link_res)); if (rc != sizeof(link_res)) PANIC("incomplete auth reply (%d/%zd)", rc, sizeof(link_res)); - if (link_res != SPICE_LINK_ERR_OK) - PANIC("auth error %u", link_res); + if (link_res != SPICE_LINK_ERR_OK) { + spice_channel_disconnect(channel, SPICE_CHANNEL_ERROR_AUTH); + return; + } fprintf(stderr, "channel up: %d:%d (%s)\n", c->info->type, c->channel_id, c->info->name); c->state = SPICE_CHANNEL_STATE_READY; if (c->info->ready) c->info->ready(channel); + spice_channel_emit_event(channel, SPICE_CHANNEL_OPENED); } static void spice_channel_send_link(SpiceChannel *channel) @@ -411,14 +441,11 @@ void spice_channel_send_msg(SpiceChannel *channel, spice_msg_out *out) size_t len; uint32_t res; - res = spice_channel_send(channel, out->header, sizeof(*out->header)); - if (res != sizeof(*out->header)) { - /* TODO: queue up */ - PANIC("sending message header failed"); - } - data = spice_marshaller_linearize(out->marshaller, 0, &len, &free_data); +#if 0 + spice_msg_out_hexdump(out, data, len); +#endif res = spice_channel_send(channel, data, len); if (free_data) { free(data); @@ -556,8 +583,10 @@ gboolean spice_channel_connect(SpiceChannel *channel) } c->socket = spice_session_channel_connect(c->session); - if (c->socket == -1) + if (c->socket == -1) { + spice_channel_emit_event(channel, SPICE_CHANNEL_ERROR_CONNECT); return false; + } c->watch = spice_watch_new(c->socket, SPICE_WATCH_EVENT_READ, spice_channel_data, channel); @@ -566,10 +595,14 @@ gboolean spice_channel_connect(SpiceChannel *channel) return true; } -void spice_channel_disconnect(SpiceChannel *channel) +void spice_channel_disconnect(SpiceChannel *channel, enum SpiceChannelEvent reason) { spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); + if (c->state == SPICE_CHANNEL_STATE_UNCONNECTED) { + return; + } + if (c->watch) { spice_watch_put(c->watch); c->watch = NULL; @@ -579,4 +612,5 @@ void spice_channel_disconnect(SpiceChannel *channel) c->socket = -1; } c->state = SPICE_CHANNEL_STATE_UNCONNECTED; + spice_channel_emit_event(channel, reason); } diff --git a/gtk/spice-channel.h b/gtk/spice-channel.h index cffaff5..cafa8a8 100644 --- a/gtk/spice-channel.h +++ b/gtk/spice-channel.h @@ -7,6 +7,14 @@ G_BEGIN_DECLS #define SPICE_IS_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SPICE_TYPE_CHANNEL)) #define SPICE_CHANNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SPICE_TYPE_CHANNEL, SpiceChannelClass)) +enum SpiceChannelEvent { + SPICE_CHANNEL_OPENED, + SPICE_CHANNEL_CLOSED, + SPICE_CHANNEL_ERROR_CONNECT, + SPICE_CHANNEL_ERROR_AUTH, + SPICE_CHANNEL_ERROR_IO, +}; + struct _SpiceChannel { GObject parent; @@ -18,7 +26,13 @@ struct _SpiceChannelClass { GObjectClass parent_class; - /* Signals */ + /* common signals */ + void (*spice_channel_event)(SpiceChannel *channel, enum SpiceChannelEvent event); + + /* main signals */ + void (*spice_main_mouse_mode)(SpiceChannel *channel, enum SpiceMouseMode mode); + + /* display signals */ void (*spice_display_primary_create)(SpiceChannel *channel, gint format, gint width, gint height, gint stride, gint shmid, gpointer data); @@ -48,10 +62,18 @@ typedef struct spice_channel_info spice_channel_info; SpiceChannel *spice_channel_new(SpiceSession *s, spice_channel_info *info, int id); gboolean spice_channel_connect(SpiceChannel *channel); -void spice_channel_disconnect(SpiceChannel *channel); +void spice_channel_disconnect(SpiceChannel *channel, enum SpiceChannelEvent event); int spice_channel_type(SpiceChannel *channel); int spice_channel_id(SpiceChannel *channel); +enum SpiceMouseMode spice_main_get_mouse_mode(SpiceChannel *channel); + +void spice_inputs_motion(SpiceChannel *channel, gint dx, gint dy, gint button_state); +void spice_inputs_position(SpiceChannel *channel, gint x, gint y, + gint display, gint button_state); +void spice_inputs_button_press(SpiceChannel *channel, gint button, gint button_state); +void spice_inputs_button_release(SpiceChannel *channel, gint button, gint button_state); + spice_msg_in *spice_msg_in_new(SpiceChannel *channel); void spice_msg_in_get(spice_msg_in *in); void spice_msg_in_put(spice_msg_in *in); diff --git a/gtk/spice-session.c b/gtk/spice-session.c index b8c3c66..08cf2fc 100644 --- a/gtk/spice-session.c +++ b/gtk/spice-session.c @@ -72,6 +72,8 @@ static void spice_session_class_init(SpiceSessionClass *klass) SPICE_TYPE_CHANNEL); g_type_class_add_private(klass, sizeof(spice_session)); + + tcp_verbose = 1; } /* ------------------------------------------------------------------ */ @@ -105,8 +107,7 @@ gboolean spice_session_connect(SpiceSession *session) spice_session_disconnect(session); cmain = spice_channel_new(session, NULL, 0); - spice_channel_connect(cmain); - return true; + return spice_channel_connect(cmain); } void spice_session_disconnect(SpiceSession *session) diff --git a/gtk/spice-widget.c b/gtk/spice-widget.c index 0f0ec4b..200173c 100644 --- a/gtk/spice-widget.c +++ b/gtk/spice-widget.c @@ -20,9 +20,12 @@ struct spice_display { GC gc; SpiceSession *session; + SpiceChannel *main; SpiceChannel *display; SpiceChannel *cursor; SpiceChannel *inputs; + + enum SpiceMouseMode mouse_mode; }; G_DEFINE_TYPE(SpiceDisplay, spice_display, GTK_TYPE_DRAWING_AREA) @@ -89,6 +92,14 @@ static void spice_display_init(SpiceDisplay *display) d = display->priv = SPICE_DISPLAY_GET_PRIVATE(display); memset(d, 0, sizeof(*d)); + gtk_widget_add_events(widget, + GDK_POINTER_MOTION_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_KEY_PRESS_MASK); gtk_widget_set_double_buffered(widget, false); } @@ -176,11 +187,13 @@ static gboolean expose_event(GtkWidget *widget, GdkEventExpose *expose) spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display); GdkDrawable *window = gtk_widget_get_window(widget); +#if 0 fprintf(stderr, "%s: area %dx%d at %d,%d\n", __FUNCTION__, expose->area.width, expose->area.height, expose->area.x, expose->area.y); +#endif if (d->data == NULL) return true; @@ -205,6 +218,119 @@ static gboolean expose_event(GtkWidget *widget, GdkEventExpose *expose) return true; } +static gboolean key_event(GtkWidget *widget, GdkEventKey *key) +{ +#if 0 + SpiceDisplay *display = SPICE_DISPLAY(widget); + spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display); +#endif + + fprintf(stderr, "%s %s: keycode: %d state: %d group %d, keyval: %d", + __FUNCTION__, key->type == GDK_KEY_PRESS ? "press" : "release", + key->hardware_keycode, key->state, key->group, key->keyval); + return true; +} + +static gboolean enter_event(GtkWidget *widget, GdkEventCrossing *crossing G_GNUC_UNUSED) +{ + fprintf(stderr, "%s\n", __FUNCTION__); + return true; +} + +static gboolean leave_event(GtkWidget *widget, GdkEventCrossing *crossing G_GNUC_UNUSED) +{ + fprintf(stderr, "%s\n", __FUNCTION__); + return true; +} + +static gboolean focus_out_event(GtkWidget *widget, GdkEventFocus *focus G_GNUC_UNUSED) +{ + fprintf(stderr, "%s\n", __FUNCTION__); + return true; +} + +static int button_gdk_to_spice(int gdk) +{ + static const int map[] = { + [ 1 ] = SPICE_MOUSE_BUTTON_LEFT, + [ 2 ] = SPICE_MOUSE_BUTTON_MIDDLE, + [ 3 ] = SPICE_MOUSE_BUTTON_RIGHT, + [ 4 ] = SPICE_MOUSE_BUTTON_UP, + [ 5 ] = SPICE_MOUSE_BUTTON_DOWN, + }; + + if (gdk < SPICE_N_ELEMENTS(map)) { + return map [ gdk ]; + } + return 0; +} + +static int button_mask_gdk_to_spice(int gdk) +{ + int spice = 0; + + if (gdk & GDK_BUTTON1_MASK) + spice |= SPICE_MOUSE_BUTTON_MASK_LEFT; + if (gdk & GDK_BUTTON2_MASK) + spice |= SPICE_MOUSE_BUTTON_MASK_MIDDLE; + if (gdk & GDK_BUTTON3_MASK) + spice |= SPICE_MOUSE_BUTTON_MASK_RIGHT; + return spice; +} + +static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion) +{ + SpiceDisplay *display = SPICE_DISPLAY(widget); + spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display); + +#if 0 + fprintf(stderr, "%s: +%.0f+%.0f\n", __FUNCTION__, motion->x, motion->y); +#endif + + if (!d->inputs) + return true; + switch (d->mouse_mode) { + case SPICE_MOUSE_MODE_CLIENT: + spice_inputs_position(d->inputs, motion->x, motion->y, d->channel_id, + button_mask_gdk_to_spice(motion->state)); + break; + case SPICE_MOUSE_MODE_SERVER: + /* TODO */ + break; + default: + break; + } + return true; +} + +static gboolean button_event(GtkWidget *widget, GdkEventButton *button) +{ + SpiceDisplay *display = SPICE_DISPLAY(widget); + spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display); + + fprintf(stderr, "%s %s: button %d\n", __FUNCTION__, + button->type == GDK_BUTTON_PRESS ? "press" : "release", + button->button); + + if (!d->inputs) + return true; + switch (button->type) { + case GDK_BUTTON_PRESS: + spice_inputs_button_press(d->inputs, + button_gdk_to_spice(button->button), + button_mask_gdk_to_spice(button->state)); + break; + case GDK_BUTTON_RELEASE: + spice_inputs_button_release(d->inputs, + button_gdk_to_spice(button->button), + button_mask_gdk_to_spice(button->state)); + break; + default: + break; + } + return true; +} + static void spice_display_class_init(SpiceDisplayClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS(klass); @@ -212,16 +338,16 @@ static void spice_display_class_init(SpiceDisplayClass *klass) GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS(klass); gtkwidget_class->expose_event = expose_event; -#if 0 - gtkwidget_class->motion_notify_event = motion_event; - gtkwidget_class->button_press_event = button_event; - gtkwidget_class->button_release_event = button_event; - gtkwidget_class->scroll_event = scroll_event; gtkwidget_class->key_press_event = key_event; gtkwidget_class->key_release_event = key_event; gtkwidget_class->enter_notify_event = enter_event; gtkwidget_class->leave_notify_event = leave_event; - gtkwidget_class->focus_out_event = focus_event; + gtkwidget_class->focus_out_event = focus_out_event; + gtkwidget_class->motion_notify_event = motion_event; + gtkwidget_class->button_press_event = button_event; + gtkwidget_class->button_release_event = button_event; +#if 0 + gtkwidget_class->scroll_event = scroll_event; #endif gtkobject_class->destroy = spice_display_destroy; @@ -233,6 +359,16 @@ static void spice_display_class_init(SpiceDisplayClass *klass) /* ---------------------------------------------------------------- */ +static void mouse_mode(SpiceChannel *channel, enum SpiceMouseMode mode, + gpointer data) +{ + SpiceDisplay *display = data; + spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display); + + fprintf(stderr, "%s: mouse mode: %d\n", __FUNCTION__, mode); + d->mouse_mode = mode; +} + static void primary_create(SpiceChannel *channel, gint format, gint width, gint height, gint stride, gint shmid, gpointer imgdata, gpointer data) @@ -291,20 +427,27 @@ static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data) G_CALLBACK(primary_destroy), display); g_signal_connect(channel, "spice-display-invalidate", G_CALLBACK(invalidate), display); + spice_channel_connect(channel); break; case SPICE_CHANNEL_CURSOR: if (id != d->channel_id) return; d->cursor = channel; + spice_channel_connect(channel); break; case SPICE_CHANNEL_INPUTS: d->inputs = channel; + spice_channel_connect(channel); + break; + case SPICE_CHANNEL_MAIN: + d->main = channel; + g_signal_connect(channel, "spice-main-mouse-mode", + G_CALLBACK(mouse_mode), display); + mouse_mode(channel, spice_main_get_mouse_mode(channel), display); break; default: return; } - - spice_channel_connect(channel); } GtkWidget *spice_display_new(SpiceSession *session, int id) diff --git a/gtk/spicy.c b/gtk/spicy.c index b374c64..7fe9455 100644 --- a/gtk/spicy.c +++ b/gtk/spicy.c @@ -17,6 +17,15 @@ static spice_window *wins[4]; /* ------------------------------------------------------------------ */ +static void destroy_cb(GtkWidget *widget, gpointer data) +{ + struct spice_window *win = data; + + if (win->id == 0) { + gtk_main_quit(); + } +} + static spice_window *create_spice_window(SpiceSession *s, int id) { char title[32]; @@ -34,6 +43,8 @@ static spice_window *create_spice_window(SpiceSession *s, int id) snprintf(title, sizeof(title), "spice display %d", id); gtk_window_set_title(GTK_WINDOW(win->toplevel), title); gtk_window_set_default_size(GTK_WINDOW(win->toplevel), 320, 280); + g_signal_connect(G_OBJECT(win->toplevel), "destroy", + G_CALLBACK(destroy_cb), win); /* spice display */ win->spice = spice_display_new(s, id); @@ -62,20 +73,44 @@ static spice_window *create_spice_window(SpiceSession *s, int id) return win; } +/* ------------------------------------------------------------------ */ + +static void main_channel_event(SpiceChannel *channel, enum SpiceChannelEvent event, + gpointer *data) +{ + fprintf(stderr, "main channel event: %d\n", event); + + switch (event) { + case SPICE_CHANNEL_OPENED: + /* nothing */ + break; + default: + /* TODO: more sophisticated error handling */ + gtk_main_quit(); + break; + } +} + static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer *data) { int type = spice_channel_type(channel); int id = spice_channel_id(channel); - if (type != SPICE_CHANNEL_DISPLAY) - return; - if (id >= SPICE_N_ELEMENTS(wins)) - return; - if (wins[id] != NULL) - return; - - fprintf(stderr, "new display channel (#%d), creating window\n", id); - wins[id] = create_spice_window(s, id); + switch (type) { + case SPICE_CHANNEL_MAIN: + g_signal_connect(channel, "spice-channel-event", + G_CALLBACK(main_channel_event), NULL); + fprintf(stderr, "new main channel\n"); + break; + case SPICE_CHANNEL_DISPLAY: + if (id >= SPICE_N_ELEMENTS(wins)) + return; + if (wins[id] != NULL) + return; + fprintf(stderr, "new display channel (#%d), creating window\n", id); + wins[id] = create_spice_window(s, id); + break; + } } /* ------------------------------------------------------------------ */ |