summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2010-09-08 23:53:16 +0200
committerGerd Hoffmann <kraxel@redhat.com>2010-09-08 23:53:16 +0200
commit2556e8cd07bb07fce081d3aa6480794a1c8367fe (patch)
tree9efd747b08c148896e4e51f2a3b7b80b00361e07
parent0162e57a0c396358f2b48f1878f3d022bbcc856f (diff)
lot of mouse input stuff
spicy exiting on error and window close minor tweaks
-rw-r--r--gtk/channel-inputs.c134
-rw-r--r--gtk/channel-main.c39
-rw-r--r--gtk/spice-channel-priv.h33
-rw-r--r--gtk/spice-channel.c66
-rw-r--r--gtk/spice-channel.h26
-rw-r--r--gtk/spice-session.c5
-rw-r--r--gtk/spice-widget.c159
-rw-r--r--gtk/spicy.c53
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;
+ }
}
/* ------------------------------------------------------------------ */