<div dir="ltr">I don't know why I added an extra NULL last argument to g_coroutine_signal_emit() calls. I removed that.<br></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, May 29, 2014 at 11:22 PM, Marc-André Lureau <span dir="ltr"><<a href="mailto:marcandre.lureau@gmail.com" target="_blank">marcandre.lureau@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Use va_list instead of an ugly trampoline hack<br>
---<br>
 gtk/channel-cursor.c     |  67 ++++-----------------<br>
 gtk/channel-display.c    |  84 +++++---------------------<br>
 gtk/channel-inputs.c     |  22 +------<br>
 gtk/channel-main.c       | 153 ++++++++---------------------------------------<br>
 gtk/channel-playback.c   |  64 +++-----------------<br>
 gtk/channel-port.c       |  39 ++----------<br>
 gtk/channel-record.c     |  40 ++-----------<br>
 gtk/gio-coroutine.c      |  70 ++++++++++------------<br>
 gtk/gio-coroutine.h      |   7 ++-<br>
 gtk/spice-channel-priv.h |  11 ----<br>
 gtk/spice-channel.c      |  61 ++++++-------------<br>
 gtk/spice-session.c      |  25 ++------<br>
 12 files changed, 133 insertions(+), 510 deletions(-)<br>
<br>
diff --git a/gtk/channel-cursor.c b/gtk/channel-cursor.c<br>
index d7242a6..740b6a6 100644<br>
--- a/gtk/channel-cursor.c<br>
+++ b/gtk/channel-cursor.c<br>
@@ -200,52 +200,6 @@ static void spice_cursor_channel_class_init(SpiceCursorChannelClass *klass)<br>
     channel_set_handlers(SPICE_CHANNEL_CLASS(klass));<br>
 }<br>
<br>
-/* signal trampoline---------------------------------------------------------- */<br>
-<br>
-struct SPICE_CURSOR_HIDE {<br>
-};<br>
-<br>
-struct SPICE_CURSOR_RESET {<br>
-};<br>
-<br>
-struct SPICE_CURSOR_SET {<br>
-    uint16_t width;<br>
-    uint16_t height;<br>
-    uint16_t hot_spot_x;<br>
-    uint16_t hot_spot_y;<br>
-    gpointer rgba;<br>
-};<br>
-<br>
-struct SPICE_CURSOR_MOVE {<br>
-    gint x;<br>
-    gint y;<br>
-};<br>
-<br>
-/* main context */<br>
-static void do_emit_main_context(GObject *object, int signum, gpointer params)<br>
-{<br>
-    switch (signum) {<br>
-    case SPICE_CURSOR_HIDE:<br>
-    case SPICE_CURSOR_RESET: {<br>
-        g_signal_emit(object, signals[signum], 0);<br>
-        break;<br>
-    }<br>
-    case SPICE_CURSOR_SET: {<br>
-        struct SPICE_CURSOR_SET *p = params;<br>
-        g_signal_emit(object, signals[signum], 0,<br>
-                      p->width, p->height, p->hot_spot_x, p->hot_spot_y, p->rgba);<br>
-        break;<br>
-    }<br>
-    case SPICE_CURSOR_MOVE: {<br>
-        struct SPICE_CURSOR_MOVE *p = params;<br>
-        g_signal_emit(object, signals[signum], 0, p->x, p->y);<br>
-        break;<br>
-    }<br>
-    default:<br>
-        g_warn_if_reached();<br>
-    }<br>
-}<br>
-<br>
 /* ------------------------------------------------------------------ */<br>
<br>
 #ifdef DEBUG_CURSOR<br>
@@ -446,10 +400,10 @@ cache_add:<br>
 static void emit_cursor_set(SpiceChannel *channel, display_cursor *cursor)<br>
 {<br>
     g_return_if_fail(cursor != NULL);<br>
-    emit_main_context(channel, SPICE_CURSOR_SET,<br>
-                      cursor->hdr.width, cursor->hdr.height,<br>
-                      cursor->hdr.hot_spot_x, cursor->hdr.hot_spot_y,<br>
-                      cursor->default_cursor ? NULL : cursor->data);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_CURSOR_SET], 0,<br>
+                            cursor->hdr.width, cursor->hdr.height,<br>
+                            cursor->hdr.hot_spot_x, cursor->hdr.hot_spot_y,<br>
+                            cursor->default_cursor ? NULL : cursor->data, NULL);<br>
 }<br>
<br>
 /* coroutine context */<br>
@@ -467,7 +421,7 @@ static void cursor_handle_init(SpiceChannel *channel, SpiceMsgIn *in)<br>
     if (cursor)<br>
         emit_cursor_set(channel, cursor);<br>
     if (!init->visible || !cursor)<br>
-        emit_main_context(channel, SPICE_CURSOR_HIDE);<br>
+        g_coroutine_signal_emit(channel, signals[SPICE_CURSOR_HIDE], 0, NULL);<br>
     if (cursor)<br>
         display_cursor_unref(cursor);<br>
 }<br>
@@ -480,7 +434,7 @@ static void cursor_handle_reset(SpiceChannel *channel, SpiceMsgIn *in)<br>
     CHANNEL_DEBUG(channel, "%s, init_done: %d", __FUNCTION__, c->init_done);<br>
<br>
     cache_clear(c->cursors);<br>
-    emit_main_context(channel, SPICE_CURSOR_RESET);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_CURSOR_RESET], 0, NULL);<br>
     c->init_done = FALSE;<br>
 }<br>
<br>
@@ -497,7 +451,7 @@ static void cursor_handle_set(SpiceChannel *channel, SpiceMsgIn *in)<br>
     if (cursor)<br>
         emit_cursor_set(channel, cursor);<br>
     else<br>
-        emit_main_context(channel, SPICE_CURSOR_HIDE);<br>
+        g_coroutine_signal_emit(channel, signals[SPICE_CURSOR_HIDE], 0, NULL);<br>
<br>
<br>
     if (cursor)<br>
@@ -512,8 +466,9 @@ static void cursor_handle_move(SpiceChannel *channel, SpiceMsgIn *in)<br>
<br>
     g_return_if_fail(c->init_done == TRUE);<br>
<br>
-    emit_main_context(channel, SPICE_CURSOR_MOVE,<br>
-                      move->position.x, move->position.y);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_CURSOR_MOVE], 0,<br>
+                            move->position.x, move->position.y,<br>
+                            NULL);<br>
 }<br>
<br>
 /* coroutine context */<br>
@@ -525,7 +480,7 @@ static void cursor_handle_hide(SpiceChannel *channel, SpiceMsgIn *in)<br>
     g_return_if_fail(c->init_done == TRUE);<br>
 #endif<br>
<br>
-    emit_main_context(channel, SPICE_CURSOR_HIDE);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_CURSOR_HIDE], 0, NULL);<br>
 }<br>
<br>
 /* coroutine context */<br>
diff --git a/gtk/channel-display.c b/gtk/channel-display.c<br>
index ff9f85c..b623002 100644<br>
--- a/gtk/channel-display.c<br>
+++ b/gtk/channel-display.c<br>
@@ -429,60 +429,6 @@ gboolean spice_display_get_primary(SpiceChannel *channel, guint32 surface_id,<br>
     return TRUE;<br>
 }<br>
<br>
-/* signal trampoline---------------------------------------------------------- */<br>
-<br>
-struct SPICE_DISPLAY_PRIMARY_CREATE {<br>
-    gint format;<br>
-    gint width;<br>
-    gint height;<br>
-    gint stride;<br>
-    gint shmid;<br>
-    gpointer imgdata;<br>
-};<br>
-<br>
-struct SPICE_DISPLAY_PRIMARY_DESTROY {<br>
-};<br>
-<br>
-struct SPICE_DISPLAY_INVALIDATE {<br>
-    gint x;<br>
-    gint y;<br>
-    gint w;<br>
-    gint h;<br>
-};<br>
-<br>
-struct SPICE_DISPLAY_MARK {<br>
-    gint mark;<br>
-};<br>
-<br>
-/* main context */<br>
-static void do_emit_main_context(GObject *object, int signum, gpointer params)<br>
-{<br>
-    switch (signum) {<br>
-    case SPICE_DISPLAY_PRIMARY_DESTROY: {<br>
-        g_signal_emit(object, signals[signum], 0);<br>
-        break;<br>
-    }<br>
-    case SPICE_DISPLAY_MARK: {<br>
-        struct SPICE_DISPLAY_MARK *p = params;<br>
-        g_signal_emit(object, signals[signum], 0, p->mark);<br>
-        break;<br>
-    }<br>
-    case SPICE_DISPLAY_PRIMARY_CREATE: {<br>
-        struct SPICE_DISPLAY_PRIMARY_CREATE *p = params;<br>
-        g_signal_emit(object, signals[signum], 0,<br>
-                      p->format, p->width, p->height, p->stride, p->shmid, p->imgdata);<br>
-        break;<br>
-    }<br>
-    case SPICE_DISPLAY_INVALIDATE: {<br>
-        struct SPICE_DISPLAY_INVALIDATE *p = params;<br>
-        g_signal_emit(object, signals[signum], 0, p->x, p->y, p->w, p->h);<br>
-        break;<br>
-    }<br>
-    default:<br>
-        g_warn_if_reached();<br>
-    }<br>
-}<br>
-<br>
 /* ------------------------------------------------------------------ */<br>
<br>
 static void image_put(SpiceImageCache *cache, uint64_t id, pixman_image_t *image)<br>
@@ -701,7 +647,7 @@ static int create_canvas(SpiceChannel *channel, display_surface *surface)<br>
                 return 0;<br>
             }<br>
<br>
-            emit_main_context(channel, SPICE_DISPLAY_PRIMARY_DESTROY);<br>
+            g_coroutine_signal_emit(channel, signals[SPICE_DISPLAY_PRIMARY_DESTROY], 0, NULL);<br>
<br>
             g_hash_table_remove(c->surfaces, GINT_TO_POINTER(c->primary->surface_id));<br>
         }<br>
@@ -757,9 +703,10 @@ static int create_canvas(SpiceChannel *channel, display_surface *surface)<br>
     if (surface->primary) {<br>
         g_warn_if_fail(c->primary == NULL);<br>
         c->primary = surface;<br>
-        emit_main_context(channel, SPICE_DISPLAY_PRIMARY_CREATE,<br>
+        g_coroutine_signal_emit(channel, signals[SPICE_DISPLAY_PRIMARY_CREATE], 0,<br>
                           surface->format, surface->width, surface->height,<br>
-                          surface->stride, surface->shmid, surface->data);<br>
+                          surface->stride, surface->shmid, surface->data,<br>
+                          NULL);<br>
<br>
         if (!spice_channel_test_capability(channel, SPICE_DISPLAY_CAP_MONITORS_CONFIG)) {<br>
             g_array_set_size(c->monitors, 1);<br>
@@ -767,7 +714,7 @@ static int create_canvas(SpiceChannel *channel, display_surface *surface)<br>
             config->x = config->y = 0;<br>
             config->width = surface->width;<br>
             config->height = surface->height;<br>
-            g_object_notify_main_context(G_OBJECT(channel), "monitors");<br>
+            g_coroutine_object_notify(G_OBJECT(channel), "monitors");<br>
         }<br>
     }<br>
<br>
@@ -816,7 +763,7 @@ static void clear_surfaces(SpiceChannel *channel, gboolean keep_primary)<br>
<br>
     if (!keep_primary) {<br>
         c->primary = NULL;<br>
-        emit_main_context(channel, SPICE_DISPLAY_PRIMARY_DESTROY);<br>
+        g_coroutine_signal_emit(channel, signals[SPICE_DISPLAY_PRIMARY_DESTROY], 0, NULL);<br>
     }<br>
<br>
     g_hash_table_iter_init(&iter, c->surfaces);<br>
@@ -834,10 +781,11 @@ static void clear_surfaces(SpiceChannel *channel, gboolean keep_primary)<br>
 /* coroutine context */<br>
 static void emit_invalidate(SpiceChannel *channel, SpiceRect *bbox)<br>
 {<br>
-    emit_main_context(channel, SPICE_DISPLAY_INVALIDATE,<br>
-                      bbox->left, bbox->top,<br>
-                      bbox->right - bbox->left,<br>
-                      bbox->bottom - bbox->top);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_DISPLAY_INVALIDATE], 0,<br>
+                            bbox->left, bbox->top,<br>
+                            bbox->right - bbox->left,<br>
+                            bbox->bottom - bbox->top,<br>
+                            NULL);<br>
 }<br>
<br>
 /* ------------------------------------------------------------------ */<br>
@@ -868,7 +816,7 @@ static void spice_display_channel_up(SpiceChannel *channel)<br>
     /* if we are not using monitors config, notify of existence of<br>
        this monitor */<br>
     if (channel->priv->channel_id != 0)<br>
-        g_object_notify_main_context(G_OBJECT(channel), "monitors");<br>
+        g_coroutine_object_notify(G_OBJECT(channel), "monitors");<br>
 }<br>
<br>
 #define DRAW(type) {                                                    \<br>
@@ -915,7 +863,7 @@ static void display_handle_mark(SpiceChannel *channel, SpiceMsgIn *in)<br>
 #endif<br>
<br>
     c->mark = TRUE;<br>
-    emit_main_context(channel, SPICE_DISPLAY_MARK, TRUE);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_DISPLAY_MARK], 0, TRUE, NULL);<br>
 }<br>
<br>
 /* coroutine context */<br>
@@ -932,7 +880,7 @@ static void display_handle_reset(SpiceChannel *channel, SpiceMsgIn *in)<br>
     cache_clear(c->palettes);<br>
<br>
     c->mark = FALSE;<br>
-    emit_main_context(channel, SPICE_DISPLAY_MARK, FALSE);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_DISPLAY_MARK], 0, FALSE, NULL);<br>
 }<br>
<br>
 /* coroutine context */<br>
@@ -1753,7 +1701,7 @@ static void display_handle_surface_destroy(SpiceChannel *channel, SpiceMsgIn *in<br>
             c->mark_false_event_id = g_timeout_add_seconds(1, display_mark_false, channel);<br>
         }<br>
         c->primary = NULL;<br>
-        emit_main_context(channel, SPICE_DISPLAY_PRIMARY_DESTROY);<br>
+        g_coroutine_signal_emit(channel, signals[SPICE_DISPLAY_PRIMARY_DESTROY], 0, NULL);<br>
     }<br>
<br>
     g_hash_table_remove(c->surfaces, GINT_TO_POINTER(surface->surface_id));<br>
@@ -1800,7 +1748,7 @@ static void display_handle_monitors_config(SpiceChannel *channel, SpiceMsgIn *in<br>
         mc->height = head->height;<br>
     }<br>
<br>
-    g_object_notify_main_context(G_OBJECT(channel), "monitors");<br>
+    g_coroutine_object_notify(G_OBJECT(channel), "monitors");<br>
 }<br>
<br>
 static void channel_set_handlers(SpiceChannelClass *klass)<br>
diff --git a/gtk/channel-inputs.c b/gtk/channel-inputs.c<br>
index 8a726e0..d27640b 100644<br>
--- a/gtk/channel-inputs.c<br>
+++ b/gtk/channel-inputs.c<br>
@@ -147,24 +147,6 @@ static void spice_inputs_channel_class_init(SpiceInputsChannelClass *klass)<br>
     channel_set_handlers(SPICE_CHANNEL_CLASS(klass));<br>
 }<br>
<br>
-/* signal trampoline---------------------------------------------------------- */<br>
-<br>
-struct SPICE_INPUTS_MODIFIERS {<br>
-};<br>
-<br>
-/* main context */<br>
-static void do_emit_main_context(GObject *object, int signum, gpointer params)<br>
-{<br>
-    switch (signum) {<br>
-    case SPICE_INPUTS_MODIFIERS: {<br>
-        g_signal_emit(object, signals[signum], 0);<br>
-        break;<br>
-    }<br>
-    default:<br>
-        g_warn_if_reached();<br>
-    }<br>
-}<br>
-<br>
 /* ------------------------------------------------------------------ */<br>
<br>
 static SpiceMsgOut* mouse_motion(SpiceInputsChannel *channel)<br>
@@ -251,7 +233,7 @@ static void inputs_handle_init(SpiceChannel *channel, SpiceMsgIn *in)<br>
     SpiceMsgInputsInit *init = spice_msg_in_parsed(in);<br>
<br>
     c->modifiers = init->keyboard_modifiers;<br>
-    emit_main_context(channel, SPICE_INPUTS_MODIFIERS);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_INPUTS_MODIFIERS], 0, NULL);<br>
 }<br>
<br>
 /* coroutine context */<br>
@@ -261,7 +243,7 @@ static void inputs_handle_modifiers(SpiceChannel *channel, SpiceMsgIn *in)<br>
     SpiceMsgInputsKeyModifiers *modifiers = spice_msg_in_parsed(in);<br>
<br>
     c->modifiers = modifiers->modifiers;<br>
-    emit_main_context(channel, SPICE_INPUTS_MODIFIERS);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_INPUTS_MODIFIERS], 0, NULL);<br>
 }<br>
<br>
 /* coroutine context */<br>
diff --git a/gtk/channel-main.c b/gtk/channel-main.c<br>
index 58f5d31..f7b4f48 100644<br>
--- a/gtk/channel-main.c<br>
+++ b/gtk/channel-main.c<br>
@@ -808,115 +808,6 @@ static void spice_main_channel_class_init(SpiceMainChannelClass *klass)<br>
     channel_set_handlers(SPICE_CHANNEL_CLASS(klass));<br>
 }<br>
<br>
-/* signal trampoline---------------------------------------------------------- */<br>
-<br>
-struct SPICE_MAIN_CLIPBOARD_RELEASE {<br>
-};<br>
-<br>
-struct SPICE_MAIN_AGENT_UPDATE {<br>
-};<br>
-<br>
-struct SPICE_MAIN_MOUSE_UPDATE {<br>
-};<br>
-<br>
-struct SPICE_MAIN_CLIPBOARD {<br>
-    guint type;<br>
-    gpointer data;<br>
-    gsize size;<br>
-};<br>
-<br>
-struct SPICE_MAIN_CLIPBOARD_GRAB {<br>
-    gpointer types;<br>
-    gsize ntypes;<br>
-    gboolean *ret;<br>
-};<br>
-<br>
-struct SPICE_MAIN_CLIPBOARD_REQUEST {<br>
-    guint type;<br>
-    gboolean *ret;<br>
-};<br>
-<br>
-struct SPICE_MAIN_CLIPBOARD_SELECTION {<br>
-    guint8 selection;<br>
-    guint type;<br>
-    gpointer data;<br>
-    gsize size;<br>
-};<br>
-<br>
-struct SPICE_MAIN_CLIPBOARD_SELECTION_GRAB {<br>
-    guint8 selection;<br>
-    gpointer types;<br>
-    gsize ntypes;<br>
-    gboolean *ret;<br>
-};<br>
-<br>
-struct SPICE_MAIN_CLIPBOARD_SELECTION_REQUEST {<br>
-    guint8 selection;<br>
-    guint type;<br>
-    gboolean *ret;<br>
-};<br>
-<br>
-struct SPICE_MAIN_CLIPBOARD_SELECTION_RELEASE {<br>
-    guint8 selection;<br>
-};<br>
-<br>
-/* main context */<br>
-static void do_emit_main_context(GObject *object, int signum, gpointer params)<br>
-{<br>
-    switch (signum) {<br>
-    case SPICE_MAIN_CLIPBOARD_RELEASE:<br>
-    case SPICE_MAIN_AGENT_UPDATE:<br>
-    case SPICE_MAIN_MOUSE_UPDATE: {<br>
-        g_signal_emit(object, signals[signum], 0);<br>
-        break;<br>
-    }<br>
-    case SPICE_MAIN_CLIPBOARD: {<br>
-        struct SPICE_MAIN_CLIPBOARD *p = params;<br>
-        g_signal_emit(object, signals[signum], 0,<br>
-                      p->type, p->data, p->size);<br>
-        break;<br>
-    }<br>
-    case SPICE_MAIN_CLIPBOARD_GRAB: {<br>
-        struct SPICE_MAIN_CLIPBOARD_GRAB *p = params;<br>
-        g_signal_emit(object, signals[signum], 0,<br>
-                      p->types, p->ntypes, p->ret);<br>
-        break;<br>
-    }<br>
-    case SPICE_MAIN_CLIPBOARD_REQUEST: {<br>
-        struct SPICE_MAIN_CLIPBOARD_REQUEST *p = params;<br>
-        g_signal_emit(object, signals[signum], 0,<br>
-                      p->type, p->ret);<br>
-        break;<br>
-    }<br>
-    case SPICE_MAIN_CLIPBOARD_SELECTION: {<br>
-        struct SPICE_MAIN_CLIPBOARD_SELECTION *p = params;<br>
-        g_signal_emit(object, signals[signum], 0,<br>
-                      p->selection, p->type, p->data, p->size);<br>
-        break;<br>
-    }<br>
-    case SPICE_MAIN_CLIPBOARD_SELECTION_GRAB: {<br>
-        struct SPICE_MAIN_CLIPBOARD_SELECTION_GRAB *p = params;<br>
-        g_signal_emit(object, signals[signum], 0,<br>
-                      p->selection, p->types, p->ntypes, p->ret);<br>
-        break;<br>
-    }<br>
-    case SPICE_MAIN_CLIPBOARD_SELECTION_REQUEST: {<br>
-        struct SPICE_MAIN_CLIPBOARD_SELECTION_REQUEST *p = params;<br>
-        g_signal_emit(object, signals[signum], 0,<br>
-                      p->selection, p->type, p->ret);<br>
-        break;<br>
-    }<br>
-    case SPICE_MAIN_CLIPBOARD_SELECTION_RELEASE: {<br>
-        struct SPICE_MAIN_CLIPBOARD_SELECTION_RELEASE *p = params;<br>
-        g_signal_emit(object, signals[signum], 0,<br>
-                      p->selection);<br>
-        break;<br>
-    }<br>
-    default:<br>
-        g_warn_if_reached();<br>
-    }<br>
-}<br>
-<br>
 /* ------------------------------------------------------------------ */<br>
<br>
<br>
@@ -1437,12 +1328,12 @@ static void set_agent_connected(SpiceMainChannel *channel, gboolean connected)<br>
     SPICE_DEBUG("agent connected: %s", spice_yes_no(connected));<br>
     if (connected != c->agent_connected) {<br>
         c->agent_connected = connected;<br>
-        g_object_notify_main_context(G_OBJECT(channel), "agent-connected");<br>
+        g_coroutine_object_notify(G_OBJECT(channel), "agent-connected");<br>
     }<br>
     if (!connected)<br>
         spice_main_channel_reset_agent(SPICE_MAIN_CHANNEL(channel));<br>
<br>
-    emit_main_context(channel, SPICE_MAIN_AGENT_UPDATE);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_MAIN_AGENT_UPDATE], 0, NULL);<br>
 }<br>
<br>
 /* coroutine context  */<br>
@@ -1480,8 +1371,8 @@ static void set_mouse_mode(SpiceMainChannel *channel, uint32_t supported, uint32<br>
<br>
     if (c->mouse_mode != current) {<br>
         c->mouse_mode = current;<br>
-        emit_main_context(channel, SPICE_MAIN_MOUSE_UPDATE);<br>
-        g_object_notify_main_context(G_OBJECT(channel), "mouse-mode");<br>
+        g_coroutine_signal_emit(channel, signals[SPICE_MAIN_MOUSE_UPDATE], 0, NULL);<br>
+        g_coroutine_object_notify(G_OBJECT(channel), "mouse-mode");<br>
     }<br>
<br>
     /* switch to client mode if possible */<br>
@@ -1590,7 +1481,7 @@ static void main_handle_channels_list(SpiceChannel *channel, SpiceMsgIn *in)<br>
<br>
     /* guarantee that uuid is notified before setting up the channels, even if<br>
      * the server is older and doesn't actually send the uuid */<br>
-    g_object_notify_main_context(G_OBJECT(session), "uuid");<br>
+    g_coroutine_object_notify(G_OBJECT(session), "uuid");<br>
<br>
     for (i = 0; i < msg->num_of_channels; i++) {<br>
         channel_new_t *c;<br>
@@ -1898,7 +1789,7 @@ static void main_agent_handle_msg(SpiceChannel *channel,<br>
             VD_AGENT_SET_CAPABILITY(c->agent_caps, i);<br>
         }<br>
         c->agent_caps_received = true;<br>
-        emit_main_context(self, SPICE_MAIN_AGENT_UPDATE);<br>
+        g_coroutine_signal_emit(self, signals[SPICE_MAIN_AGENT_UPDATE], 0, NULL);<br>
<br>
         if (caps->request)<br>
             agent_announce_caps(self);<br>
@@ -1918,42 +1809,46 @@ static void main_agent_handle_msg(SpiceChannel *channel,<br>
     case VD_AGENT_CLIPBOARD:<br>
     {<br>
         VDAgentClipboard *cb = payload;<br>
-        emit_main_context(self, SPICE_MAIN_CLIPBOARD_SELECTION, selection,<br>
-                          cb->type, cb->data, msg->size - sizeof(VDAgentClipboard));<br>
+        g_coroutine_signal_emit(self, signals[SPICE_MAIN_CLIPBOARD_SELECTION], 0, selection,<br>
+                          cb->type, cb->data, msg->size - sizeof(VDAgentClipboard),<br>
+                          NULL);<br>
<br>
        if (selection == VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD)<br>
-            emit_main_context(self, SPICE_MAIN_CLIPBOARD,<br>
-                              cb->type, cb->data, msg->size - sizeof(VDAgentClipboard));<br>
+           g_coroutine_signal_emit(self, signals[SPICE_MAIN_CLIPBOARD], 0,<br>
+                              cb->type, cb->data, msg->size - sizeof(VDAgentClipboard),<br>
+                              NULL);<br>
         break;<br>
     }<br>
     case VD_AGENT_CLIPBOARD_GRAB:<br>
     {<br>
         gboolean ret;<br>
-        emit_main_context(self, SPICE_MAIN_CLIPBOARD_SELECTION_GRAB, selection,<br>
-                          (guint8*)payload, msg->size / sizeof(uint32_t), &ret);<br>
+        g_coroutine_signal_emit(self, signals[SPICE_MAIN_CLIPBOARD_SELECTION_GRAB], 0, selection,<br>
+                          (guint8*)payload, msg->size / sizeof(uint32_t), &ret,<br>
+                          NULL);<br>
         if (selection == VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD)<br>
-            emit_main_context(self, SPICE_MAIN_CLIPBOARD_GRAB,<br>
-                              payload, msg->size / sizeof(uint32_t), &ret);<br>
+            g_coroutine_signal_emit(self, signals[SPICE_MAIN_CLIPBOARD_GRAB], 0,<br>
+                              payload, msg->size / sizeof(uint32_t), &ret,<br>
+                              NULL);<br>
         break;<br>
     }<br>
     case VD_AGENT_CLIPBOARD_REQUEST:<br>
     {<br>
         gboolean ret;<br>
         VDAgentClipboardRequest *req = payload;<br>
-        emit_main_context(self, SPICE_MAIN_CLIPBOARD_SELECTION_REQUEST, selection,<br>
-                          req->type, &ret);<br>
+        g_coroutine_signal_emit(self, signals[SPICE_MAIN_CLIPBOARD_SELECTION_REQUEST], 0, selection,<br>
+                          req->type, &ret, NULL);<br>
<br>
         if (selection == VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD)<br>
-            emit_main_context(self, SPICE_MAIN_CLIPBOARD_REQUEST,<br>
-                              req->type, &ret);<br>
+            g_coroutine_signal_emit(self, signals[SPICE_MAIN_CLIPBOARD_REQUEST], 0,<br>
+                              req->type, &ret, NULL);<br>
         break;<br>
     }<br>
     case VD_AGENT_CLIPBOARD_RELEASE:<br>
     {<br>
-        emit_main_context(self, SPICE_MAIN_CLIPBOARD_SELECTION_RELEASE, selection);<br>
+        g_coroutine_signal_emit(self, signals[SPICE_MAIN_CLIPBOARD_SELECTION_RELEASE], 0, selection, NULL);<br>
<br>
         if (selection == VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD)<br>
-            emit_main_context(self, SPICE_MAIN_CLIPBOARD_RELEASE);<br>
+            g_coroutine_signal_emit(self, signals[SPICE_MAIN_CLIPBOARD_RELEASE], 0, NULL);<br>
         break;<br>
     }<br>
     case VD_AGENT_REPLY:<br>
diff --git a/gtk/channel-playback.c b/gtk/channel-playback.c<br>
index 7789aa8..dc3c375 100644<br>
--- a/gtk/channel-playback.c<br>
+++ b/gtk/channel-playback.c<br>
@@ -298,52 +298,6 @@ static void spice_playback_channel_class_init(SpicePlaybackChannelClass *klass)<br>
     channel_set_handlers(SPICE_CHANNEL_CLASS(klass));<br>
 }<br>
<br>
-/* signal trampoline---------------------------------------------------------- */<br>
-<br>
-struct SPICE_PLAYBACK_START {<br>
-    gint format;<br>
-    gint channels;<br>
-    gint frequency;<br>
-    gint latency;<br>
-};<br>
-<br>
-struct SPICE_PLAYBACK_DATA {<br>
-    uint8_t *data;<br>
-    gsize data_size;<br>
-};<br>
-<br>
-struct SPICE_PLAYBACK_STOP {<br>
-};<br>
-<br>
-struct SPICE_PLAYBACK_GET_DELAY {<br>
-};<br>
-<br>
-/* main context */<br>
-static void do_emit_main_context(GObject *object, int signum, gpointer params)<br>
-{<br>
-    switch (signum) {<br>
-    case SPICE_PLAYBACK_GET_DELAY:<br>
-    case SPICE_PLAYBACK_STOP: {<br>
-        g_signal_emit(object, signals[signum], 0);<br>
-        break;<br>
-    }<br>
-    case SPICE_PLAYBACK_START: {<br>
-        struct SPICE_PLAYBACK_START *p = params;<br>
-        g_signal_emit(object, signals[signum], 0,<br>
-                      p->format, p->channels, p->frequency);<br>
-        break;<br>
-    }<br>
-    case SPICE_PLAYBACK_DATA: {<br>
-        struct SPICE_PLAYBACK_DATA *p = params;<br>
-        g_signal_emit(object, signals[signum], 0,<br>
-                      p->data, p->data_size);<br>
-        break;<br>
-    }<br>
-    default:<br>
-        g_warn_if_reached();<br>
-    }<br>
-}<br>
-<br>
 /* ------------------------------------------------------------------ */<br>
<br>
 /* coroutine context */<br>
@@ -377,10 +331,10 @@ static void playback_handle_data(SpiceChannel *channel, SpiceMsgIn *in)<br>
         }<br>
     }<br>
<br>
-    emit_main_context(channel, SPICE_PLAYBACK_DATA, data, n);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_PLAYBACK_DATA], 0, data, n, NULL);<br>
<br>
     if ((c->frame_count++ % 100) == 0) {<br>
-        emit_main_context(channel, SPICE_PLAYBACK_GET_DELAY);<br>
+        g_coroutine_signal_emit(channel, signals[SPICE_PLAYBACK_GET_DELAY], 0, NULL);<br>
     }<br>
 }<br>
<br>
@@ -426,8 +380,8 @@ static void playback_handle_start(SpiceChannel *channel, SpiceMsgIn *in)<br>
             return;<br>
         }<br>
     }<br>
-    emit_main_context(channel, SPICE_PLAYBACK_START,<br>
-         start->format, start->channels, start->frequency);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_PLAYBACK_START], 0,<br>
+                            start->format, start->channels, start->frequency, NULL);<br>
 }<br>
<br>
 /* coroutine context */<br>
@@ -435,7 +389,7 @@ static void playback_handle_stop(SpiceChannel *channel, SpiceMsgIn *in)<br>
 {<br>
     SpicePlaybackChannelPrivate *c = SPICE_PLAYBACK_CHANNEL(channel)->priv;<br>
<br>
-    emit_main_context(channel, SPICE_PLAYBACK_STOP);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_PLAYBACK_STOP], 0, NULL);<br>
     c->is_active = FALSE;<br>
 }<br>
<br>
@@ -454,7 +408,7 @@ static void playback_handle_set_volume(SpiceChannel *channel, SpiceMsgIn *in)<br>
     c->nchannels = vol->nchannels;<br>
     c->volume = g_new(guint16, c->nchannels);<br>
     memcpy(c->volume, vol->volume, sizeof(guint16) * c->nchannels);<br>
-    g_object_notify_main_context(G_OBJECT(channel), "volume");<br>
+    g_coroutine_object_notify(G_OBJECT(channel), "volume");<br>
 }<br>
<br>
 /* coroutine context */<br>
@@ -464,7 +418,7 @@ static void playback_handle_set_mute(SpiceChannel *channel, SpiceMsgIn *in)<br>
     SpiceMsgAudioMute *m = spice_msg_in_parsed(in);<br>
<br>
     c->mute = m->mute;<br>
-    g_object_notify_main_context(G_OBJECT(channel), "mute");<br>
+    g_coroutine_object_notify(G_OBJECT(channel), "mute");<br>
 }<br>
<br>
 /* coroutine context */<br>
@@ -475,7 +429,7 @@ static void playback_handle_set_latency(SpiceChannel *channel, SpiceMsgIn *in)<br>
<br>
     c->min_latency = msg->latency_ms;<br>
     SPICE_DEBUG("%s: notify latency update %u", __FUNCTION__, c->min_latency);<br>
-    g_object_notify_main_context(G_OBJECT(channel), "min-latency");<br>
+    g_coroutine_object_notify(G_OBJECT(channel), "min-latency");<br>
 }<br>
<br>
 static void channel_set_handlers(SpiceChannelClass *klass)<br>
@@ -530,5 +484,5 @@ void spice_playback_channel_sync_latency(SpicePlaybackChannel *channel)<br>
     g_return_if_fail(SPICE_IS_PLAYBACK_CHANNEL(channel));<br>
     g_return_if_fail(channel->priv->is_active);<br>
     SPICE_DEBUG("%s: notify latency update %u", __FUNCTION__, channel->priv->min_latency);<br>
-    g_object_notify_main_context(G_OBJECT(SPICE_CHANNEL(channel)), "min-latency");<br>
+    g_coroutine_object_notify(G_OBJECT(SPICE_CHANNEL(channel)), "min-latency");<br>
 }<br>
diff --git a/gtk/channel-port.c b/gtk/channel-port.c<br>
index ad85afd..742178d 100644<br>
--- a/gtk/channel-port.c<br>
+++ b/gtk/channel-port.c<br>
@@ -197,35 +197,6 @@ static void spice_port_channel_class_init(SpicePortChannelClass *klass)<br>
     channel_set_handlers(SPICE_CHANNEL_CLASS(klass));<br>
 }<br>
<br>
-/* signal trampoline---------------------------------------------------------- */<br>
-<br>
-struct SPICE_PORT_DATA {<br>
-    uint8_t *data;<br>
-    gsize data_size;<br>
-};<br>
-<br>
-struct SPICE_PORT_EVENT {<br>
-    int event;<br>
-};<br>
-<br>
-/* main context */<br>
-static void do_emit_main_context(GObject *object, int signum, gpointer params)<br>
-{<br>
-    switch (signum) {<br>
-    case SPICE_PORT_DATA: {<br>
-        struct SPICE_PORT_DATA *p = params;<br>
-        g_signal_emit(object, signals[signum], 0, p->data, p->data_size);<br>
-        break;<br>
-    }<br>
-    case SPICE_PORT_EVENT: {<br>
-        struct SPICE_PORT_EVENT *p = params;<br>
-        g_signal_emit(object, signals[signum], 0, p->event);<br>
-        break;<br>
-    }<br>
-    default:<br>
-        g_warn_if_reached();<br>
-    }<br>
-}<br>
<br>
 /* coroutine context */<br>
 static void port_set_opened(SpicePortChannel *self, gboolean opened)<br>
@@ -236,7 +207,7 @@ static void port_set_opened(SpicePortChannel *self, gboolean opened)<br>
         return;<br>
<br>
     c->opened = opened;<br>
-    g_object_notify_main_context(G_OBJECT(self), "port-opened");<br>
+    g_coroutine_object_notify(G_OBJECT(self), "port-opened");<br>
 }<br>
<br>
 /* coroutine context */<br>
@@ -254,9 +225,9 @@ static void port_handle_init(SpiceChannel *channel, SpiceMsgIn *in)<br>
<br>
     port_set_opened(self, init->opened);<br>
     if (init->opened)<br>
-        emit_main_context(channel, SPICE_PORT_EVENT, SPICE_PORT_EVENT_OPENED);<br>
+        g_coroutine_signal_emit(channel, signals[SPICE_PORT_EVENT], 0, SPICE_PORT_EVENT_OPENED, NULL);<br>
<br>
-    g_object_notify_main_context(G_OBJECT(channel), "port-name");<br>
+    g_coroutine_object_notify(G_OBJECT(channel), "port-name");<br>
 }<br>
<br>
 /* coroutine context */<br>
@@ -275,7 +246,7 @@ static void port_handle_event(SpiceChannel *channel, SpiceMsgIn *in)<br>
         break;<br>
     }<br>
<br>
-    emit_main_context(channel, SPICE_PORT_EVENT, event->event);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_PORT_EVENT], 0, event->event, NULL);<br>
 }<br>
<br>
 /* coroutine context */<br>
@@ -288,7 +259,7 @@ static void port_handle_msg(SpiceChannel *channel, SpiceMsgIn *in)<br>
     buf = spice_msg_in_raw(in, &size);<br>
     CHANNEL_DEBUG(channel, "port %p got %d %p", channel, size, buf);<br>
     port_set_opened(self, true);<br>
-    emit_main_context(channel, SPICE_PORT_DATA, buf, size);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_PORT_DATA], 0, buf, size, NULL);<br>
 }<br>
<br>
 /**<br>
diff --git a/gtk/channel-record.c b/gtk/channel-record.c<br>
index d4f47ba..bca3736 100644<br>
--- a/gtk/channel-record.c<br>
+++ b/gtk/channel-record.c<br>
@@ -251,36 +251,6 @@ static void spice_record_channel_class_init(SpiceRecordChannelClass *klass)<br>
     channel_set_handlers(SPICE_CHANNEL_CLASS(klass));<br>
 }<br>
<br>
-/* signal trampoline---------------------------------------------------------- */<br>
-<br>
-struct SPICE_RECORD_START {<br>
-    gint format;<br>
-    gint channels;<br>
-    gint frequency;<br>
-};<br>
-<br>
-struct SPICE_RECORD_STOP {<br>
-};<br>
-<br>
-/* main context */<br>
-static void do_emit_main_context(GObject *object, int signum, gpointer params)<br>
-{<br>
-    switch (signum) {<br>
-    case SPICE_RECORD_START: {<br>
-        struct SPICE_RECORD_START *p = params;<br>
-        g_signal_emit(object, signals[signum], 0,<br>
-                      p->format, p->channels, p->frequency);<br>
-        break;<br>
-    }<br>
-    case SPICE_RECORD_STOP: {<br>
-        g_signal_emit(object, signals[signum], 0);<br>
-        break;<br>
-    }<br>
-    default:<br>
-        g_warn_if_reached();<br>
-    }<br>
-}<br>
-<br>
 /* main context */<br>
 static void spice_record_mode(SpiceRecordChannel *channel, uint32_t time,<br>
                               uint32_t mode, uint8_t *data, uint32_t data_size)<br>
@@ -451,8 +421,8 @@ static void record_handle_start(SpiceChannel *channel, SpiceMsgIn *in)<br>
     c->last_frame = g_malloc(c->frame_bytes);<br>
     c->last_frame_current = 0;<br>
<br>
-    emit_main_context(channel, SPICE_RECORD_START,<br>
-                      start->format, start->channels, start->frequency);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_RECORD_START], 0,<br>
+                            start->format, start->channels, start->frequency, NULL);<br>
 }<br>
<br>
 /* coroutine context */<br>
@@ -460,7 +430,7 @@ static void record_handle_stop(SpiceChannel *channel, SpiceMsgIn *in)<br>
 {<br>
     SpiceRecordChannelPrivate *rc = SPICE_RECORD_CHANNEL(channel)->priv;<br>
<br>
-    emit_main_context(channel, SPICE_RECORD_STOP);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_RECORD_STOP], 0, NULL);<br>
     rc->started = FALSE;<br>
 }<br>
<br>
@@ -479,7 +449,7 @@ static void record_handle_set_volume(SpiceChannel *channel, SpiceMsgIn *in)<br>
     c->nchannels = vol->nchannels;<br>
     c->volume = g_new(guint16, c->nchannels);<br>
     memcpy(c->volume, vol->volume, sizeof(guint16) * c->nchannels);<br>
-    g_object_notify_main_context(G_OBJECT(channel), "volume");<br>
+    g_coroutine_object_notify(G_OBJECT(channel), "volume");<br>
 }<br>
<br>
 /* coroutine context */<br>
@@ -489,7 +459,7 @@ static void record_handle_set_mute(SpiceChannel *channel, SpiceMsgIn *in)<br>
     SpiceMsgAudioMute *m = spice_msg_in_parsed(in);<br>
<br>
     c->mute = m->mute;<br>
-    g_object_notify_main_context(G_OBJECT(channel), "mute");<br>
+    g_coroutine_object_notify(G_OBJECT(channel), "mute");<br>
 }<br>
<br>
 static void channel_set_handlers(SpiceChannelClass *klass)<br>
diff --git a/gtk/gio-coroutine.c b/gtk/gio-coroutine.c<br>
index d3ac16c..c903bd2 100644<br>
--- a/gtk/gio-coroutine.c<br>
+++ b/gtk/gio-coroutine.c<br>
@@ -184,20 +184,21 @@ gboolean g_coroutine_condition_wait(GCoroutine *self, GConditionWaitFunc func, g<br>
<br>
 struct signal_data<br>
 {<br>
-    GObject *object;<br>
+    gpointer instance;<br>
     struct coroutine *caller;<br>
-    int signum;<br>
-    gpointer params;<br>
-    GSignalEmitMainFunc func;<br>
-    const char *debug_info;<br>
+    guint signal_id;<br>
+    GQuark detail;<br>
+    const gchar *propname;<br>
     gboolean notified;<br>
+    va_list var_args;<br>
 };<br>
<br>
 static gboolean emit_main_context(gpointer opaque)<br>
 {<br>
     struct signal_data *signal = opaque;<br>
<br>
-    signal->func(signal->object, signal->signum, signal->params);<br>
+    g_signal_emit_valist(signal->instance, signal->signal_id,<br>
+                         signal->detail, signal->var_args);<br>
     signal->notified = TRUE;<br>
<br>
     coroutine_yieldto(signal->caller, NULL);<br>
@@ -205,41 +206,36 @@ static gboolean emit_main_context(gpointer opaque)<br>
     return FALSE;<br>
 }<br>
<br>
-/* coroutine -> main context */<br>
-void g_signal_emit_main_context(GObject *object,<br>
-                                GSignalEmitMainFunc emit_main_func,<br>
-                                int signum,<br>
-                                gpointer params,<br>
-                                const char *debug_info)<br>
+void<br>
+g_coroutine_signal_emit(gpointer instance, guint signal_id,<br>
+                        GQuark detail, ...)<br>
 {<br>
-    struct signal_data data;<br>
+    struct signal_data data = {<br>
+        .instance = instance,<br>
+        .signal_id = signal_id,<br>
+        .detail = detail,<br>
+        .caller = coroutine_self(),<br>
+    };<br>
<br>
-    g_return_if_fail(coroutine_self()->caller);<br>
-<br>
-    data.object = object;<br>
-    data.caller = coroutine_self();<br>
-    data.signum = signum;<br>
-    data.params = params;<br>
-    data.func = emit_main_func;<br>
-    data.debug_info = debug_info;<br>
-    data.notified = FALSE;<br>
-    g_idle_add(emit_main_context, &data);<br>
-<br>
-    /* This switches to the system coroutine context, lets<br>
-     * the idle function run to dispatch the signal, and<br>
-     * finally returns once complete. ie this is synchronous<br>
-     * from the POV of the coroutine despite there being<br>
-     * an idle function involved<br>
-     */<br>
-    coroutine_yield(NULL);<br>
-    g_warn_if_fail(data.notified);<br>
+    va_start (data.var_args, detail);<br>
+<br>
+    if (coroutine_self_is_main()) {<br>
+        g_signal_emit_valist(instance, signal_id, detail, data.var_args);<br>
+    } else {<br>
+        g_idle_add(emit_main_context, &data);<br>
+        coroutine_yield(NULL);<br>
+        g_warn_if_fail(data.notified);<br>
+    }<br>
+<br>
+    va_end (data.var_args);<br>
 }<br>
<br>
+<br>
 static gboolean notify_main_context(gpointer opaque)<br>
 {<br>
     struct signal_data *signal = opaque;<br>
<br>
-    g_object_notify(signal->object, signal->params);<br>
+    g_object_notify(signal->instance, signal->propname);<br>
     signal->notified = TRUE;<br>
<br>
     coroutine_yieldto(signal->caller, NULL);<br>
@@ -248,8 +244,8 @@ static gboolean notify_main_context(gpointer opaque)<br>
 }<br>
<br>
 /* coroutine -> main context */<br>
-void g_object_notify_main_context(GObject *object,<br>
-                                  const gchar *property_name)<br>
+void g_coroutine_object_notify(GObject *object,<br>
+                               const gchar *property_name)<br>
 {<br>
     struct signal_data data;<br>
<br>
@@ -257,9 +253,9 @@ void g_object_notify_main_context(GObject *object,<br>
         g_object_notify(object, property_name);<br>
     } else {<br>
<br>
-        data.object = object;<br>
+        data.instance = object;<br>
         data.caller = coroutine_self();<br>
-        data.params = (gpointer)property_name;<br>
+        data.propname = (gpointer)property_name;<br>
         data.notified = FALSE;<br>
<br>
         g_idle_add(notify_main_context, &data);<br>
diff --git a/gtk/gio-coroutine.h b/gtk/gio-coroutine.h<br>
index 1c4094e..b3a6d78 100644<br>
--- a/gtk/gio-coroutine.h<br>
+++ b/gtk/gio-coroutine.h<br>
@@ -56,9 +56,10 @@ gboolean     g_coroutine_condition_wait (GCoroutine *coroutine,<br>
                                          GConditionWaitFunc func, gpointer data);<br>
 void         g_coroutine_condition_cancel(GCoroutine *coroutine);<br>
<br>
-void         g_signal_emit_main_context(GObject *object, GSignalEmitMainFunc func,<br>
-                                        int signum, gpointer params, const char *debug_info);<br>
-void         g_object_notify_main_context(GObject *object, const gchar *property_name);<br>
+void         g_coroutine_signal_emit (gpointer instance, guint signal_id,<br>
+                                      GQuark detail, ...);<br>
+<br>
+void         g_coroutine_object_notify(GObject *object, const gchar *property_name);<br>
<br>
 G_END_DECLS<br>
<br>
diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h<br>
index 607c0d4..03eed38 100644<br>
--- a/gtk/spice-channel-priv.h<br>
+++ b/gtk/spice-channel-priv.h<br>
@@ -186,17 +186,6 @@ void spice_caps_set(GArray *caps, guint32 cap, const gchar *desc);<br>
 #define spice_channel_set_capability(channel, cap)                      \<br>
     spice_caps_set(SPICE_CHANNEL(channel)->priv->caps, cap, #cap)<br>
<br>
-/* coroutine context */<br>
-#define emit_main_context(object, event, args...)                                      \<br>
-    G_STMT_START {                                                                     \<br>
-        if (coroutine_self_is_main()) {                                 \<br>
-            do_emit_main_context(G_OBJECT(object), event, &((struct event) { args })); \<br>
-        } else {                                                                       \<br>
-            g_signal_emit_main_context(G_OBJECT(object), do_emit_main_context,         \<br>
-                                       event, &((struct event) { args }), G_STRLOC);   \<br>
-        }                                                                              \<br>
-    } G_STMT_END<br>
-<br>
 gchar *spice_channel_supported_string(void);<br>
<br>
 void spice_vmc_write_async(SpiceChannel *self,<br>
diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c<br>
index e460590..c9c4819 100644<br>
--- a/gtk/spice-channel.c<br>
+++ b/gtk/spice-channel.c<br>
@@ -734,29 +734,6 @@ void spice_msg_out_send_internal(SpiceMsgOut *out)<br>
     spice_channel_write_msg(out->channel, out);<br>
 }<br>
<br>
-/* ---------------------------------------------------------------- */<br>
-<br>
-struct SPICE_CHANNEL_EVENT {<br>
-    SpiceChannelEvent event;<br>
-};<br>
-<br>
-/* main context */<br>
-static void do_emit_main_context(GObject *object, int signum, gpointer params)<br>
-{<br>
-    switch (signum) {<br>
-    case SPICE_CHANNEL_EVENT: {<br>
-        struct SPICE_CHANNEL_EVENT *p = params;<br>
-        g_signal_emit(object, signals[signum], 0, p->event);<br>
-        break;<br>
-    }<br>
-    case SPICE_CHANNEL_OPEN_FD:<br>
-        g_warning("this signal is only sent directly from main context");<br>
-        break;<br>
-    default:<br>
-        g_warn_if_reached();<br>
-    }<br>
-}<br>
-<br>
 /*<br>
  * Write all 'data' of length 'datalen' bytes out to<br>
  * the wire<br>
@@ -1094,19 +1071,19 @@ static void spice_channel_recv_auth(SpiceChannel *channel)<br>
     if (rc != sizeof(link_res)) {<br>
         CHANNEL_DEBUG(channel, "incomplete auth reply (%d/%" G_GSIZE_FORMAT ")",<br>
                     rc, sizeof(link_res));<br>
-        emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_LINK);<br>
+        g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_LINK, NULL);<br>
         return;<br>
     }<br>
<br>
     if (link_res != SPICE_LINK_ERR_OK) {<br>
         CHANNEL_DEBUG(channel, "link result: reply %d", link_res);<br>
-        emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_AUTH);<br>
+        g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_AUTH, NULL);<br>
         return;<br>
     }<br>
<br>
     c->state = SPICE_CHANNEL_STATE_READY;<br>
<br>
-    emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_OPENED);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_OPENED, NULL);<br>
<br>
     if (c->state == SPICE_CHANNEL_STATE_MIGRATION_HANDSHAKE) {<br>
         spice_channel_send_migration_handshake(channel);<br>
@@ -1233,7 +1210,7 @@ error:<br>
         return FALSE;<br>
     }<br>
<br>
-    emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_LINK);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_LINK, NULL);<br>
     return FALSE;<br>
 }<br>
<br>
@@ -1648,7 +1625,7 @@ complete:<br>
     CHANNEL_DEBUG(channel, "%s", "SASL authentication complete");<br>
     spice_channel_read(channel, &len, sizeof(len));<br>
     if (len != SPICE_LINK_ERR_OK)<br>
-        emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_AUTH);<br>
+        g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_AUTH, NULL);<br>
     ret = len == SPICE_LINK_ERR_OK;<br>
     /* This must come *after* check-auth-result, because the former<br>
      * is defined to be sent unencrypted, and setting saslconn turns<br>
@@ -1659,7 +1636,7 @@ complete:<br>
 error:<br>
     if (saslconn)<br>
         sasl_dispose(&saslconn);<br>
-    emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_AUTH);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_AUTH, NULL);<br>
     c->has_error = TRUE; /* force disconnect */<br>
     ret = FALSE;<br>
<br>
@@ -1691,7 +1668,7 @@ static void spice_channel_recv_link_msg(SpiceChannel *channel, gboolean *switch_<br>
     if (c->peer_pos != c->peer_hdr.size) {<br>
         g_critical("%s: %s: incomplete link reply (%d/%d)",<br>
                   c->name, __FUNCTION__, rc, c->peer_hdr.size);<br>
-        emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_LINK);<br>
+        g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_LINK, NULL);<br>
         return;<br>
     }<br>
     switch (c->peer_msg->error) {<br>
@@ -1759,7 +1736,7 @@ static void spice_channel_recv_link_msg(SpiceChannel *channel, gboolean *switch_<br>
<br>
 error:<br>
     SPICE_CHANNEL_GET_CLASS(channel)->channel_disconnect(channel);<br>
-    emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_LINK);<br>
+    g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_LINK, NULL);<br>
 }<br>
<br>
 /* system context */<br>
@@ -2142,9 +2119,9 @@ static gboolean spice_channel_iterate(SpiceChannel *channel)<br>
     if (c->has_error) {<br>
         CHANNEL_DEBUG(channel, "channel got error");<br>
         if (c->state > SPICE_CHANNEL_STATE_CONNECTING)<br>
-            emit_main_context(channel, SPICE_CHANNEL_EVENT,<br>
-                              c->state == SPICE_CHANNEL_STATE_READY ?<br>
-                              SPICE_CHANNEL_ERROR_IO : SPICE_CHANNEL_ERROR_LINK);<br>
+            g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0,<br>
+                                    c->state == SPICE_CHANNEL_STATE_READY ?<br>
+                                    SPICE_CHANNEL_ERROR_IO : SPICE_CHANNEL_ERROR_LINK, NULL);<br>
         return FALSE;<br>
     }<br>
<br>
@@ -2272,13 +2249,13 @@ static void *spice_channel_coroutine(void *data)<br>
     if (spice_session_get_client_provided_socket(c->session)) {<br>
         if (c->fd < 0) {<br>
             g_critical("fd not provided!");<br>
-            emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_CONNECT);<br>
+            g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_CONNECT, NULL);<br>
             goto cleanup;<br>
         }<br>
<br>
         if (!(c->sock = g_socket_new_from_fd(c->fd, NULL))) {<br>
                 CHANNEL_DEBUG(channel, "Failed to open socket from fd %d", c->fd);<br>
-                emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_CONNECT);<br>
+                g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_CONNECT, NULL);<br>
                 goto cleanup;<br>
         }<br>
<br>
@@ -2298,7 +2275,7 @@ reconnect:<br>
             goto reconnect;<br>
         } else {<br>
             CHANNEL_DEBUG(channel, "Connect error");<br>
-            emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_CONNECT);<br>
+            g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_CONNECT, NULL);<br>
             g_clear_error(&c->error);<br>
             goto cleanup;<br>
         }<br>
@@ -2311,7 +2288,7 @@ reconnect:<br>
         c->ctx = SSL_CTX_new(SSLv23_method());<br>
         if (c->ctx == NULL) {<br>
             g_critical("SSL_CTX_new failed");<br>
-            emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_TLS);<br>
+            g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_TLS, NULL);<br>
             goto cleanup;<br>
         }<br>
<br>
@@ -2327,7 +2304,7 @@ reconnect:<br>
                     g_warning("only pubkey active");<br>
                     verify = SPICE_SESSION_VERIFY_PUBKEY;<br>
                 } else {<br>
-                    emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_TLS);<br>
+                    g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_TLS, NULL);<br>
                     goto cleanup;<br>
                 }<br>
             }<br>
@@ -2345,7 +2322,7 @@ reconnect:<br>
         c->ssl = SSL_new(c->ctx);<br>
         if (c->ssl == NULL) {<br>
             g_critical("SSL_new failed");<br>
-            emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_TLS);<br>
+            g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_TLS, NULL);<br>
             goto cleanup;<br>
         }<br>
<br>
@@ -2378,7 +2355,7 @@ ssl_reconnect:<br>
             } else {<br>
                 g_warning("%s: SSL_connect: %s",<br>
                           c->name, ERR_error_string(rc, NULL));<br>
-                emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_TLS);<br>
+                g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_TLS, NULL);<br>
                 goto cleanup;<br>
             }<br>
         }<br>
@@ -2611,7 +2588,7 @@ static void channel_disconnect(SpiceChannel *channel)<br>
     c->has_error = TRUE; /* break the loop */<br>
<br>
     if (c->state == SPICE_CHANNEL_STATE_READY)<br>
-        emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_CLOSED);<br>
+        g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_CLOSED, NULL);<br>
<br>
     c->state = SPICE_CHANNEL_STATE_UNCONNECTED;<br>
     spice_channel_reset(channel, FALSE);<br>
diff --git a/gtk/spice-session.c b/gtk/spice-session.c<br>
index c168bc3..2346187 100644<br>
--- a/gtk/spice-session.c<br>
+++ b/gtk/spice-session.c<br>
@@ -124,21 +124,6 @@ enum {<br>
<br>
 static guint signals[SPICE_SESSION_LAST_SIGNAL];<br>
<br>
-struct SPICE_SESSION_MM_TIME_RESET {<br>
-};<br>
-<br>
-/* main context */<br>
-static void do_emit_main_context(GObject *object, int signum, gpointer params)<br>
-{<br>
-    switch (signum) {<br>
-    case SPICE_SESSION_MM_TIME_RESET:<br>
-        g_signal_emit(object, signals[signum], 0);<br>
-        break;<br>
-    default:<br>
-        g_warn_if_reached();<br>
-    }<br>
-}<br>
-<br>
 static void update_proxy(SpiceSession *self, const gchar *str)<br>
 {<br>
     SpiceSessionPrivate *s = self->priv;<br>
@@ -616,7 +601,7 @@ static void spice_session_set_property(GObject      *gobject,<br>
         break;<br>
     case PROP_READ_ONLY:<br>
         s->read_only = g_value_get_boolean(value);<br>
-        g_object_notify_main_context(gobject, "read-only");<br>
+        g_coroutine_object_notify(gobject, "read-only");<br>
         break;<br>
     case PROP_CACHE_SIZE:<br>
         s->images_cache_size = g_value_get_int(value);<br>
@@ -2006,7 +1991,7 @@ void spice_session_set_mm_time(SpiceSession *session, guint32 time)<br>
     if (time > old_time + MM_TIME_DIFF_RESET_THRESH ||<br>
         time < old_time) {<br>
         SPICE_DEBUG("%s: mm-time-reset, old %u, new %u", __FUNCTION__, old_time, s->mm_time);<br>
-        emit_main_context(session, SPICE_SESSION_MM_TIME_RESET);<br>
+        g_coroutine_signal_emit(session, signals[SPICE_SESSION_MM_TIME_RESET], 0, NULL);<br>
     }<br>
 }<br>
<br>
@@ -2066,7 +2051,7 @@ void spice_session_set_migration_state(SpiceSession *session, SpiceSessionMigrat<br>
<br>
     g_return_if_fail(s != NULL);<br>
     s->migration_state = state;<br>
-    g_object_notify_main_context(G_OBJECT(session), "migration-state");<br>
+    g_coroutine_object_notify(G_OBJECT(session), "migration-state");<br>
 }<br>
<br>
 G_GNUC_INTERNAL<br>
@@ -2161,7 +2146,7 @@ void spice_session_set_uuid(SpiceSession *session, guint8 uuid[16])<br>
     g_return_if_fail(s != NULL);<br>
     memcpy(s->uuid, uuid, sizeof(s->uuid));<br>
<br>
-    g_object_notify_main_context(G_OBJECT(session), "uuid");<br>
+    g_coroutine_object_notify(G_OBJECT(session), "uuid");<br>
 }<br>
<br>
 G_GNUC_INTERNAL<br>
@@ -2173,7 +2158,7 @@ void spice_session_set_name(SpiceSession *session, const gchar *name)<br>
     g_free(s->name);<br>
     s->name = g_strdup(name);<br>
<br>
-    g_object_notify_main_context(G_OBJECT(session), "name");<br>
+    g_coroutine_object_notify(G_OBJECT(session), "name");<br>
 }<br>
<br>
 G_GNUC_INTERNAL<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.9.0<br>
<br>
</font></span></blockquote></div><br><br clear="all"><br>-- <br>Marc-André Lureau
</div>