[gtk-vnc] Move all coroutine stuff into VncConnection



commit 87f6d4de1ec037357153973ef6523c3b52c0baa0
Author: Daniel P. Berrange <berrange redhat com>
Date:   Sat Nov 21 12:32:27 2009 +0000

    Move all coroutine stuff into VncConnection
    
    The VncDisplay class currently runs the main coroutine for the
    VncConnection. This means some VncConnection APIs need to be
    invoked from the VNC coroutine context, while others need to be
    invoked from the main system context. This will make the
    VncConnection class very hard to use from non-C languages like
    Python/Perl/Java/etc.
    
    Move all the coroutine code into the VncConnection class. All
    its APIs are now to be invoked from system context. This means
    it can now easily be used from any language

 src/utils.h         |    2 +-
 src/vncconnection.c |  384 ++++++++++++++++++++++++++++++++++++++-------------
 src/vncconnection.h |   19 ++--
 src/vncdisplay.c    |  228 ++++++++-----------------------
 4 files changed, 350 insertions(+), 283 deletions(-)
---
diff --git a/src/utils.h b/src/utils.h
index e32db11..c4e5207 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -25,6 +25,6 @@
 
 extern gboolean debug_enabled;
 
-#define GVNC_DEBUG(fmt, ...) do { if (G_UNLIKELY(debug_enabled)) g_debug(fmt, ## __VA_ARGS__); } while (0)
+#define GVNC_DEBUG(fmt, ...) do { if (G_UNLIKELY(debug_enabled)) g_debug(__FILE__ " " fmt, ## __VA_ARGS__); } while (0)
 
 #endif
diff --git a/src/vncconnection.c b/src/vncconnection.c
index 94fb170..15f6691 100644
--- a/src/vncconnection.c
+++ b/src/vncconnection.c
@@ -84,6 +84,7 @@ typedef void vnc_connection_tight_compute_predicted_func(VncConnection *conn, gu
 							  guint8 *);
 
 typedef void vnc_connection_tight_sum_pixel_func(VncConnection *conn, guint8 *, guint8 *);
+static void vnc_connection_close(VncConnection *conn);
 
 /*
  * A special GSource impl which allows us to wait on a certain
@@ -110,6 +111,8 @@ struct g_condition_wait_source
 
 struct _VncConnectionPrivate
 {
+	struct coroutine coroutine;
+	guint open_id;
 	GIOChannel *channel;
 	int fd;
 	char *host;
@@ -156,6 +159,7 @@ struct _VncConnectionPrivate
 
 	VncCursor *cursor;
 	gboolean absPointer;
+	gboolean sharedFlag;
 
 	vnc_connection_rich_cursor_blt_func *rich_cursor_blt;
 	vnc_connection_tight_compute_predicted_func *tight_compute_predicted;
@@ -204,12 +208,17 @@ enum {
 	VNC_AUTH_CHOOSE_TYPE,
 	VNC_AUTH_CHOOSE_SUBTYPE,
 
+	VNC_CONNECTED,
+	VNC_INITIALIZED,
+	VNC_DISCONNECTED,
+
 	VNC_LAST_SIGNAL,
 };
 
 static guint signals[VNC_LAST_SIGNAL] = { 0, 0, 0, 0,
 					  0, 0, 0, 0,
-					  0, 0, 0, 0};
+					  0, 0, 0, 0,
+					  0, 0, 0 };
 
 #define nibhi(a) (((a) >> 4) & 0x0F)
 #define niblo(a) ((a) & 0x0F)
@@ -404,6 +413,7 @@ static gboolean do_vnc_connection_emit_main_context(gpointer opaque)
 {
 	struct signal_data *data = opaque;
 
+	GVNC_DEBUG("Emit main context %d", data->signum);
 	switch (data->signum) {
 	case VNC_CURSOR_CHANGED:
 		g_signal_emit(G_OBJECT(data->conn),
@@ -493,6 +503,13 @@ static gboolean do_vnc_connection_emit_main_context(gpointer opaque)
 			      data->params.authTypes);
 		break;
 
+	case VNC_CONNECTED:
+	case VNC_INITIALIZED:
+	case VNC_DISCONNECTED:
+		g_signal_emit(G_OBJECT(data->conn),
+			      signals[data->signum],
+			      0);
+		break;
 	}
 
 	coroutine_yieldto(data->caller, NULL);
@@ -1268,44 +1285,109 @@ gboolean vnc_connection_has_error(VncConnection *conn)
 	return priv->has_error;
 }
 
-gboolean vnc_connection_set_pixel_format(VncConnection *conn,
-					 const VncPixelFormat *fmt)
+const VncPixelFormat *vnc_connection_get_pixel_format(VncConnection *conn)
 {
 	VncConnectionPrivate *priv = conn->priv;
-	guint8 pad[3] = {0};
 
-	vnc_connection_write_u8(conn, 0);
-	vnc_connection_write(conn, pad, 3);
-
-	vnc_connection_write_u8(conn, fmt->bits_per_pixel);
-	vnc_connection_write_u8(conn, fmt->depth);
-	vnc_connection_write_u8(conn, fmt->byte_order == G_BIG_ENDIAN ? 1 : 0);
-	vnc_connection_write_u8(conn, fmt->true_color_flag);
+	return &priv->fmt;
+}
 
-	vnc_connection_write_u16(conn, fmt->red_max);
-	vnc_connection_write_u16(conn, fmt->green_max);
-	vnc_connection_write_u16(conn, fmt->blue_max);
 
-	vnc_connection_write_u8(conn, fmt->red_shift);
-	vnc_connection_write_u8(conn, fmt->green_shift);
-	vnc_connection_write_u8(conn, fmt->blue_shift);
+gboolean vnc_connection_set_shared(VncConnection *conn, gboolean sharedFlag)
+{
+	VncConnectionPrivate *priv = conn->priv;
 
-	vnc_connection_write(conn, pad, 3);
-	vnc_connection_flush(conn);
+	if (vnc_connection_is_open(conn))
+		return FALSE;
 
-	memcpy(&priv->fmt, fmt, sizeof(*fmt));
+	priv->sharedFlag = sharedFlag;
 
 	return !vnc_connection_has_error(conn);
 }
 
 
-const VncPixelFormat *vnc_connection_get_pixel_format(VncConnection *conn)
+gboolean vnc_connection_get_shared(VncConnection *conn)
 {
 	VncConnectionPrivate *priv = conn->priv;
 
-	return &priv->fmt;
+	return priv->sharedFlag;
 }
 
+
+static void vnc_connection_buffered_write(VncConnection *conn, const void *data, size_t size)
+{
+	VncConnectionPrivate *priv = conn->priv;
+	size_t left;
+
+	left = priv->xmit_buffer_capacity - priv->xmit_buffer_size;
+	if (left < size) {
+		priv->xmit_buffer_capacity += size + 4095;
+		priv->xmit_buffer_capacity &= ~4095;
+
+		priv->xmit_buffer = g_realloc(priv->xmit_buffer, priv->xmit_buffer_capacity);
+	}
+
+	memcpy(&priv->xmit_buffer[priv->xmit_buffer_size],
+	       data, size);
+
+	priv->xmit_buffer_size += size;
+}
+
+static void vnc_connection_buffered_write_u8(VncConnection *conn, guint8 value)
+{
+	vnc_connection_buffered_write(conn, &value, 1);
+}
+
+static void vnc_connection_buffered_write_u16(VncConnection *conn, guint16 value)
+{
+	value = htons(value);
+	vnc_connection_buffered_write(conn, &value, 2);
+}
+
+static void vnc_connection_buffered_write_u32(VncConnection *conn, guint32 value)
+{
+	value = htonl(value);
+	vnc_connection_buffered_write(conn, &value, 4);
+}
+
+static void vnc_connection_buffered_flush(VncConnection *conn)
+{
+	VncConnectionPrivate *priv = conn->priv;
+
+	g_io_wakeup(&priv->wait);
+}
+
+gboolean vnc_connection_set_pixel_format(VncConnection *conn,
+					 const VncPixelFormat *fmt)
+{
+	VncConnectionPrivate *priv = conn->priv;
+	guint8 pad[3] = {0};
+
+	vnc_connection_buffered_write_u8(conn, 0);
+	vnc_connection_buffered_write(conn, pad, 3);
+
+	vnc_connection_buffered_write_u8(conn, fmt->bits_per_pixel);
+	vnc_connection_buffered_write_u8(conn, fmt->depth);
+	vnc_connection_buffered_write_u8(conn, fmt->byte_order == G_BIG_ENDIAN ? 1 : 0);
+	vnc_connection_buffered_write_u8(conn, fmt->true_color_flag);
+
+	vnc_connection_buffered_write_u16(conn, fmt->red_max);
+	vnc_connection_buffered_write_u16(conn, fmt->green_max);
+	vnc_connection_buffered_write_u16(conn, fmt->blue_max);
+
+	vnc_connection_buffered_write_u8(conn, fmt->red_shift);
+	vnc_connection_buffered_write_u8(conn, fmt->green_shift);
+	vnc_connection_buffered_write_u8(conn, fmt->blue_shift);
+
+	vnc_connection_buffered_write(conn, pad, 3);
+	vnc_connection_buffered_flush(conn);
+
+	memcpy(&priv->fmt, fmt, sizeof(*fmt));
+
+	return !vnc_connection_has_error(conn);
+}
+
+
 gboolean vnc_connection_set_encodings(VncConnection *conn, int n_encoding, gint32 *encoding)
 {
 	VncConnectionPrivate *priv = conn->priv;
@@ -1353,58 +1435,16 @@ gboolean vnc_connection_framebuffer_update_request(VncConnection *conn,
 						   guint16 x, guint16 y,
 						   guint16 width, guint16 height)
 {
-	vnc_connection_write_u8(conn, 3);
-	vnc_connection_write_u8(conn, incremental);
-	vnc_connection_write_u16(conn, x);
-	vnc_connection_write_u16(conn, y);
-	vnc_connection_write_u16(conn, width);
-	vnc_connection_write_u16(conn, height);
-	vnc_connection_flush(conn);
+	vnc_connection_buffered_write_u8(conn, 3);
+	vnc_connection_buffered_write_u8(conn, incremental);
+	vnc_connection_buffered_write_u16(conn, x);
+	vnc_connection_buffered_write_u16(conn, y);
+	vnc_connection_buffered_write_u16(conn, width);
+	vnc_connection_buffered_write_u16(conn, height);
+	vnc_connection_buffered_flush(conn);
 	return !vnc_connection_has_error(conn);
 }
 
-static void vnc_connection_buffered_write(VncConnection *conn, const void *data, size_t size)
-{
-	VncConnectionPrivate *priv = conn->priv;
-	size_t left;
-
-	left = priv->xmit_buffer_capacity - priv->xmit_buffer_size;
-	if (left < size) {
-		priv->xmit_buffer_capacity += size + 4095;
-		priv->xmit_buffer_capacity &= ~4095;
-
-		priv->xmit_buffer = g_realloc(priv->xmit_buffer, priv->xmit_buffer_capacity);
-	}
-
-	memcpy(&priv->xmit_buffer[priv->xmit_buffer_size],
-	       data, size);
-
-	priv->xmit_buffer_size += size;
-}
-
-static void vnc_connection_buffered_write_u8(VncConnection *conn, guint8 value)
-{
-	vnc_connection_buffered_write(conn, &value, 1);
-}
-
-static void vnc_connection_buffered_write_u16(VncConnection *conn, guint16 value)
-{
-	value = htons(value);
-	vnc_connection_buffered_write(conn, &value, 2);
-}
-
-static void vnc_connection_buffered_write_u32(VncConnection *conn, guint32 value)
-{
-	value = htonl(value);
-	vnc_connection_buffered_write(conn, &value, 4);
-}
-
-static void vnc_connection_buffered_flush(VncConnection *conn)
-{
-	VncConnectionPrivate *priv = conn->priv;
-
-	g_io_wakeup(&priv->wait);
-}
 
 gboolean vnc_connection_key_event(VncConnection *conn, guint8 down_flag,
 				  guint32 key, guint16 scancode)
@@ -2552,7 +2592,7 @@ static void vnc_connection_framebuffer_update(VncConnection *conn, gint32 etype,
 	}
 }
 
-gboolean vnc_connection_server_message(VncConnection *conn)
+static gboolean vnc_connection_server_message(VncConnection *conn)
 {
 	VncConnectionPrivate *priv = conn->priv;
 	guint8 msg;
@@ -3792,6 +3832,8 @@ static void vnc_connection_finalize (GObject *object)
 	VncConnection *conn = VNC_CONNECTION(object);
 	VncConnectionPrivate *priv = conn->priv;
 
+	GVNC_DEBUG("Finalize VncConnection=%p", conn);
+
 	if (vnc_connection_is_open(conn))
 		vnc_connection_close(conn);
 
@@ -3962,15 +4004,46 @@ static void vnc_connection_class_init(VncConnectionClass *klass)
 			      G_TYPE_VALUE_ARRAY);
 
 
+	signals[VNC_CONNECTED] =
+		g_signal_new ("vnc-connected",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (VncConnectionClass, vnc_connected),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE,
+			      0);
+	signals[VNC_INITIALIZED] =
+		g_signal_new ("vnc-initialized",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (VncConnectionClass, vnc_initialized),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE,
+			      0);
+	signals[VNC_DISCONNECTED] =
+		g_signal_new ("vnc-disconnected",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (VncConnectionClass, vnc_disconnected),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE,
+			      0);
+
+
 	g_type_class_add_private(klass, sizeof(VncConnectionPrivate));
 }
 
 
-void vnc_connection_init(VncConnection *fb)
+void vnc_connection_init(VncConnection *conn)
 {
 	VncConnectionPrivate *priv;
 
-	priv = fb->priv = VNC_CONNECTION_GET_PRIVATE(fb);
+	GVNC_DEBUG("Init VncConnection=%p", conn);
+
+	priv = conn->priv = VNC_CONNECTION_GET_PRIVATE(conn);
 
 	memset(priv, 0, sizeof(*priv));
 
@@ -3986,11 +4059,13 @@ VncConnection *vnc_connection_new(void)
 					   NULL));
 }
 
-void vnc_connection_close(VncConnection *conn)
+static void vnc_connection_close(VncConnection *conn)
 {
 	VncConnectionPrivate *priv = conn->priv;
 	int i;
 
+	GVNC_DEBUG("Close VncConnection=%p", conn);
+
 	if (priv->tls_session) {
 		gnutls_bye(priv->tls_session, GNUTLS_SHUT_RDWR);
 		priv->tls_session = NULL;
@@ -4057,7 +4132,7 @@ void vnc_connection_close(VncConnection *conn)
 
 	priv->auth_type = VNC_CONNECTION_AUTH_INVALID;
 	priv->auth_subtype = VNC_CONNECTION_AUTH_INVALID;
-
+	priv->sharedFlag = FALSE;
 	priv->has_error = 0;
 }
 
@@ -4065,6 +4140,13 @@ void vnc_connection_shutdown(VncConnection *conn)
 {
 	VncConnectionPrivate *priv = conn->priv;
 
+	GVNC_DEBUG("Shutdown VncConnection=%p", conn);
+
+	if (priv->open_id) {
+		g_source_remove(priv->open_id);
+		priv->open_id = 0;
+	}
+
 	close(priv->fd);
 	priv->fd = -1;
 	priv->has_error = 1;
@@ -4113,7 +4195,7 @@ static gboolean vnc_connection_after_version (VncConnection *conn, int major, in
 }
 
 
-gboolean vnc_connection_initialize(VncConnection *conn, gboolean shared_flag)
+static gboolean vnc_connection_initialize(VncConnection *conn)
 {
 	VncConnectionPrivate *priv = conn->priv;
 	int ret, i;
@@ -4153,7 +4235,7 @@ gboolean vnc_connection_initialize(VncConnection *conn, gboolean shared_flag)
 		goto fail;
 	}
 
-	vnc_connection_write_u8(conn, shared_flag); /* shared flag */
+	vnc_connection_write_u8(conn, priv->sharedFlag);
 	vnc_connection_flush(conn);
 	priv->width = vnc_connection_read_u16(conn);
 	priv->height = vnc_connection_read_u16(conn);
@@ -4219,53 +4301,42 @@ static gboolean vnc_connection_set_nonblock(int fd)
 	return TRUE;
 }
 
-gboolean vnc_connection_open_fd(VncConnection *conn, int fd)
+static gboolean vnc_connection_open_fd_internal(VncConnection *conn)
 {
 	VncConnectionPrivate *priv = conn->priv;
 
-	if (vnc_connection_is_open(conn)) {
-		GVNC_DEBUG ("Error: already connected?");
-		return FALSE;
-	}
-
-	GVNC_DEBUG("Connecting to FD %d", fd);
+	GVNC_DEBUG("Connecting to FD %d", priv->fd);
 
-	if (!vnc_connection_set_nonblock(fd))
+	if (!vnc_connection_set_nonblock(priv->fd))
 		return FALSE;
 
 	if (!(priv->channel =
 #ifdef WIN32
-	      g_io_channel_win32_new_socket(_get_osfhandle(fd))
+	      g_io_channel_win32_new_socket(_get_osfhandle(priv->fd))
 #else
-	      g_io_channel_unix_new(fd)
+	      g_io_channel_unix_new(priv->fd)
 #endif
 	      )) {
 		GVNC_DEBUG ("Failed to g_io_channel_unix_new()");
 		return FALSE;
 	}
-	priv->fd = fd;
 
 	return !vnc_connection_has_error(conn);
 }
 
-gboolean vnc_connection_open_host(VncConnection *conn, const char *host, const char *port)
+static gboolean vnc_connection_open_host_internal(VncConnection *conn)
 {
 	VncConnectionPrivate *priv = conn->priv;
         struct addrinfo *ai, *runp, hints;
         int ret;
-	if (vnc_connection_is_open(conn))
-		return FALSE;
-
-	priv->host = g_strdup(host);
-	priv->port = g_strdup(port);
 
-        GVNC_DEBUG("Resolving host %s %s", host, port);
+        GVNC_DEBUG("Resolving host %s %s", priv->host, priv->port);
         memset (&hints, '\0', sizeof (hints));
         hints.ai_flags = AI_ADDRCONFIG;
         hints.ai_socktype = SOCK_STREAM;
         hints.ai_protocol = IPPROTO_TCP;
 
-        if ((ret = getaddrinfo(host, port, &hints, &ai)) != 0) {
+        if ((ret = getaddrinfo(priv->host, priv->port, &hints, &ai)) != 0) {
 		GVNC_DEBUG ("Failed to resolve hostname");
 		return FALSE;
 	}
@@ -4327,6 +4398,121 @@ gboolean vnc_connection_open_host(VncConnection *conn, const char *host, const c
 }
 
 
+/* we use an idle function to allow the coroutine to exit before we actually
+ * unref the object since the coroutine's state is part of the object */
+static gboolean vnc_connection_delayed_unref(gpointer data)
+{
+	VncConnection *conn = VNC_CONNECTION(data);
+	VncConnectionPrivate *priv = conn->priv;
+
+	GVNC_DEBUG("Delayed unref VncConnection=%p", conn);
+
+	g_assert(priv->coroutine.exited == TRUE);
+
+ 	g_object_unref(G_OBJECT(data));
+
+	return FALSE;
+}
+
+static void *vnc_connection_coroutine(void *opaque)
+{
+	VncConnection *conn = VNC_CONNECTION(opaque);
+	VncConnectionPrivate *priv = conn->priv;
+	int ret;
+	struct signal_data s;
+
+	GVNC_DEBUG("Started background coroutine");
+
+	if (priv->fd != -1) {
+		if (!vnc_connection_open_fd_internal(conn))
+			goto cleanup;
+	} else {
+		if (!vnc_connection_open_host_internal(conn))
+			goto cleanup;
+	}
+
+	vnc_connection_emit_main_context(conn, VNC_CONNECTED, &s);
+
+	GVNC_DEBUG("Protocol initialization");
+	if (!vnc_connection_initialize(conn))
+		goto cleanup;
+
+	vnc_connection_emit_main_context(conn, VNC_INITIALIZED, &s);
+
+	GVNC_DEBUG("Running main loop");
+	while ((ret = vnc_connection_server_message(conn)))
+		;
+
+ cleanup:
+	GVNC_DEBUG("Doing final VNC cleanup");
+	vnc_connection_close(conn);
+	vnc_connection_emit_main_context(conn, VNC_DISCONNECTED, &s);
+	g_idle_add(vnc_connection_delayed_unref, conn);
+	/* Co-routine exits now - the VncDisplay object may no longer exist,
+	   so don't do anything else now unless you like SEGVs */
+	return NULL;
+}
+
+static gboolean do_vnc_connection_open(gpointer data)
+{
+	VncConnection *conn = VNC_CONNECTION(data);
+	VncConnectionPrivate *priv = conn->priv;
+	struct coroutine *co;
+
+	GVNC_DEBUG("Open coroutine starting");
+	priv->open_id = 0;
+
+	co = &priv->coroutine;
+
+	co->stack_size = 16 << 20;
+	co->entry = vnc_connection_coroutine;
+	co->release = NULL;
+
+	coroutine_init(co);
+	coroutine_yieldto(co, conn);
+
+	return FALSE;
+}
+
+gboolean vnc_connection_open_fd(VncConnection *conn, int fd)
+{
+	VncConnectionPrivate *priv = conn->priv;
+
+	GVNC_DEBUG("Open fd=%d", fd);
+
+	if (vnc_connection_is_open(conn))
+		return FALSE;
+
+	priv->fd = fd;
+	priv->host = NULL;
+	priv->port = NULL;
+
+	g_object_ref(G_OBJECT(conn)); /* Unref'd when co-routine exits */
+	priv->open_id = g_idle_add(do_vnc_connection_open, conn);
+
+	return TRUE;
+}
+
+gboolean vnc_connection_open_host(VncConnection *conn, const char *host, const char *port)
+{
+	VncConnectionPrivate *priv = conn->priv;
+
+	GVNC_DEBUG("Open host=%s port=%s", host, port);
+
+	if (vnc_connection_is_open(conn))
+		return FALSE;
+
+	priv->fd = -1;
+	priv->host = g_strdup(host);
+	priv->port = g_strdup(port);
+
+	g_object_ref(G_OBJECT(conn)); /* Unref'd when co-routine exits */
+	priv->open_id = g_idle_add(do_vnc_connection_open, conn);
+
+	return TRUE;
+}
+
+
 gboolean vnc_connection_set_auth_type(VncConnection *conn, unsigned int type)
 {
 	VncConnectionPrivate *priv = conn->priv;
@@ -4513,7 +4699,7 @@ int vnc_connection_get_height(VncConnection *conn)
 	return priv->height;
 }
 
-gboolean vnc_connection_using_raw_keycodes(VncConnection *conn)
+gboolean vnc_connection_get_ext_key_event(VncConnection *conn)
 {
 	VncConnectionPrivate *priv = conn->priv;
 
@@ -4528,7 +4714,7 @@ VncCursor *vnc_connection_get_cursor(VncConnection *conn)
 }
 
 
-gboolean vnc_connection_abs_pointer(VncConnection *conn)
+gboolean vnc_connection_get_abs_pointer(VncConnection *conn)
 {
 	VncConnectionPrivate *priv = conn->priv;
 
diff --git a/src/vncconnection.h b/src/vncconnection.h
index 949dfaa..04baec6 100644
--- a/src/vncconnection.h
+++ b/src/vncconnection.h
@@ -64,6 +64,9 @@ struct _VncConnectionClass
 	void (*vnc_auth_credential)(VncConnection *conn, GValueArray *creds);
 	void (*vnc_auth_choose_type)(VncConnection *conn, GValueArray *types);
 	void (*vnc_auth_choose_subtype)(VncConnection *conn, unsigned int type, GValueArray *subtypes);
+	void (*vnc_connected)(VncConnection *conn);
+	void (*vnc_initialized)(VncConnection *conn);
+	void (*vnc_disconnected)(VncConnection *conn);
 };
 
 struct vnc_connection_ops
@@ -143,22 +146,17 @@ GType vnc_connection_get_type(void) G_GNUC_CONST;
 
 VncConnection *vnc_connection_new(void);
 
-void vnc_connection_close(VncConnection *conn);
-void vnc_connection_shutdown(VncConnection *conn);
-
 gboolean vnc_connection_open_fd(VncConnection *conn, int fd);
 gboolean vnc_connection_open_host(VncConnection *conn, const char *host, const char *port);
 gboolean vnc_connection_is_open(VncConnection *conn);
+void vnc_connection_shutdown(VncConnection *conn);
 
 gboolean vnc_connection_set_auth_type(VncConnection *conn, unsigned int type);
 gboolean vnc_connection_set_auth_subtype(VncConnection *conn, unsigned int type);
 gboolean vnc_connection_set_credential(VncConnection *conn, int type, const gchar *data);
 
-gboolean vnc_connection_initialize(VncConnection *conn, gboolean shared_flag);
 gboolean vnc_connection_is_initialized(VncConnection *conn);
 
-gboolean vnc_connection_server_message(VncConnection *conn);
-
 gboolean vnc_connection_client_cut_text(VncConnection *conn,
 					const void *data, size_t length);
 
@@ -180,6 +178,9 @@ gboolean vnc_connection_set_pixel_format(VncConnection *conn,
 
 const VncPixelFormat *vnc_connection_get_pixel_format(VncConnection *conn);
 
+gboolean vnc_connection_set_shared(VncConnection *conn, gboolean sharedFlag);
+gboolean vnc_connection_get_shared(VncConnection *conn);
+
 gboolean vnc_connection_has_error(VncConnection *conn);
 
 gboolean vnc_connection_set_framebuffer(VncConnection *conn,
@@ -191,10 +192,8 @@ int vnc_connection_get_height(VncConnection *conn);
 
 VncCursor *vnc_connection_get_cursor(VncConnection *conn);
 
-gboolean vnc_connection_abs_pointer(VncConnection *conn);
-
-/* HACK this is temporary */
-gboolean vnc_connection_using_raw_keycodes(VncConnection *conn);
+gboolean vnc_connection_get_abs_pointer(VncConnection *conn);
+gboolean vnc_connection_get_ext_key_event(VncConnection *conn);
 
 G_END_DECLS
 
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index afd59c2..a0ee28d 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -22,7 +22,6 @@
 #include <locale.h>
 
 #include "vncdisplay.h"
-#include "coroutine.h"
 #include "vncconnection.h"
 #include "vncimageframebuffer.h"
 #include "utils.h"
@@ -53,19 +52,14 @@ static void winsock_cleanup (void);
 
 struct _VncDisplayPrivate
 {
-	int fd;
-	char *host;
-	char *port;
 	GdkGC *gc;
 	GdkPixmap *pixmap;
 	GdkCursor *null_cursor;
 	GdkCursor *remote_cursor;
 
-	struct coroutine coroutine;
 	VncConnection *conn;
 	VncImageFramebuffer *fb;
 
-	guint open_id;
 	VncDisplayDepthColor depth;
 
 	gboolean in_pointer_grab;
@@ -93,23 +87,6 @@ struct _VncDisplayPrivate
 	const guint8 const *keycode_map;
 };
 
-/* Delayed signal emission.
- *
- * We want signals to be delivered in the system coroutine.  This helps avoid
- * confusing applications.  This is particularly important when using
- * GThread based coroutines since GTK gets very upset if a signal handler is
- * run in a different thread from the main loop if that signal handler isn't
- * written to use explicit locking.
- */
-struct signal_data
-{
-	VncDisplay *obj;
-	struct coroutine *caller;
-
-	int signum;
-	GValueArray *cred_list;
-};
-
 G_DEFINE_TYPE(VncDisplay, vnc_display, GTK_TYPE_DRAWING_AREA)
 
 /* Properties */
@@ -881,39 +858,13 @@ static void on_framebuffer_update(VncConnection *conn G_GNUC_UNUSED,
 	}
 
 	gtk_widget_queue_draw_area(widget, x, y, w + 1, h + 1);
-}
-
-
-static gboolean emit_signal_auth_cred(gpointer opaque)
-{
-	struct signal_data *s = opaque;
-
-	switch (s->signum) {
-	case VNC_CONNECTED:
-	case VNC_INITIALIZED:
-	case VNC_DISCONNECTED:
-		g_signal_emit(G_OBJECT(s->obj),
-			      signals[s->signum],
-			      0);
-		break;
-	}
 
-	coroutine_yieldto(s->caller, NULL);
-
-	return FALSE;
+	vnc_connection_framebuffer_update_request(priv->conn, 1,
+						  0, 0,
+						  vnc_connection_get_width(priv->conn),
+						  vnc_connection_get_height(priv->conn));
 }
 
-/* This function should be used to emit signals from VncConnection callbacks */
-static void emit_signal_delayed(VncDisplay *obj, int signum,
-				struct signal_data *data)
-{
-	data->obj = obj;
-	data->caller = coroutine_self();
-	data->signum = signum;
-
-	g_idle_add(emit_signal_auth_cred, data);
-	coroutine_yield(NULL);
-}
 
 static void do_framebuffer_init(VncDisplay *obj,
 				const VncPixelFormat *remoteFormat,
@@ -1263,37 +1214,24 @@ static gboolean check_pixbuf_support(const char *name)
 	return !!(i);
 }
 
-/* we use an idle function to allow the coroutine to exit before we actually
- * unref the object since the coroutine's state is part of the object */
-static gboolean delayed_unref_object(gpointer data)
+static void on_connected(VncConnection *conn G_GNUC_UNUSED,
+			 gpointer opaque)
 {
-	VncDisplay *obj = VNC_DISPLAY(data);
-
-	g_assert(obj->priv->coroutine.exited == TRUE);
-
-	if (obj->priv->fb) {
-		g_object_unref(obj->priv->fb);
-		obj->priv->fb = NULL;
-	}
-	if (obj->priv->pixmap) {
-		g_object_unref(obj->priv->pixmap);
-		obj->priv->pixmap = NULL;
-	}
-
-	g_object_unref(G_OBJECT(data));
-
-	winsock_cleanup ();
+	VncDisplay *obj = VNC_DISPLAY(opaque);
 
-	return FALSE;
+	g_signal_emit(G_OBJECT(obj), signals[VNC_CONNECTED], 0);
+	GVNC_DEBUG("Connected to VNC server");
 }
 
-static void *vnc_coroutine(void *opaque)
+
+static void on_initialized(VncConnection *conn G_GNUC_UNUSED,
+			   gpointer opaque)
 {
 	VncDisplay *obj = VNC_DISPLAY(opaque);
 	VncDisplayPrivate *priv = obj->priv;
 
 	/* this order is extremely important! */
-	gint32 encodings[] = {	VNC_CONNECTION_ENCODING_TIGHT_JPEG5,
+	gint32 encodings[] = {  VNC_CONNECTION_ENCODING_TIGHT_JPEG5,
 				VNC_CONNECTION_ENCODING_TIGHT,
 				VNC_CONNECTION_ENCODING_EXT_KEY_EVENT,
 				VNC_CONNECTION_ENCODING_DESKTOP_RESIZE,
@@ -1308,32 +1246,9 @@ static void *vnc_coroutine(void *opaque)
 				VNC_CONNECTION_ENCODING_RAW };
 	gint32 *encodingsp;
 	int n_encodings;
-	int ret;
-	struct signal_data s;
-
-	if (priv->conn == NULL || vnc_connection_is_open(priv->conn)) {
-		g_idle_add(delayed_unref_object, obj);
-		return NULL;
-	}
-
-	GVNC_DEBUG("Started background coroutine");
-
-	if (priv->fd != -1) {
-		if (!vnc_connection_open_fd(priv->conn, priv->fd))
-			goto cleanup;
-	} else {
-		if (!vnc_connection_open_host(priv->conn, priv->host, priv->port))
-			goto cleanup;
-	}
-
-	emit_signal_delayed(obj, VNC_CONNECTED, &s);
-
-	GVNC_DEBUG("Protocol initialization");
-	if (!vnc_connection_initialize(priv->conn, priv->shared_flag))
-		goto cleanup;
 
 	if (!vnc_display_set_preferred_pixel_format(obj))
-		goto cleanup;
+		goto error;
 
 	do_framebuffer_init(obj,
 			    vnc_connection_get_pixel_format(priv->conn),
@@ -1341,8 +1256,6 @@ static void *vnc_coroutine(void *opaque)
 			    vnc_connection_get_height(priv->conn),
 			    FALSE);
 
-	emit_signal_delayed(obj, VNC_INITIALIZED, &s);
-
 	encodingsp = encodings;
 	n_encodings = G_N_ELEMENTS(encodings);
 
@@ -1357,96 +1270,69 @@ static void *vnc_coroutine(void *opaque)
 	}
 
 	if (!vnc_connection_set_encodings(priv->conn, n_encodings, encodingsp))
-			goto cleanup;
+		goto error;
 
 	if (!vnc_connection_framebuffer_update_request(priv->conn, 0, 0, 0,
 						       vnc_connection_get_width(priv->conn),
 						       vnc_connection_get_height(priv->conn)))
-		goto cleanup;
-
-	GVNC_DEBUG("Running main loop");
-	while ((ret = vnc_connection_server_message(priv->conn))) {
-		if (!vnc_connection_framebuffer_update_request(priv->conn, 1, 0, 0,
-							       vnc_connection_get_width(priv->conn),
-							       vnc_connection_get_height(priv->conn)))
-			goto cleanup;
-	}
-
- cleanup:
-	GVNC_DEBUG("Doing final VNC cleanup");
-	vnc_connection_close(priv->conn);
-	emit_signal_delayed(obj, VNC_DISCONNECTED, &s);
-	g_idle_add(delayed_unref_object, obj);
-	/* Co-routine exits now - the VncDisplay object may no longer exist,
-	   so don't do anything else now unless you like SEGVs */
-	return NULL;
-}
-
-static gboolean do_vnc_display_open(gpointer data)
-{
-	VncDisplay *obj = VNC_DISPLAY(data);
-	struct coroutine *co;
+		goto error;
 
-	if (obj->priv->conn == NULL || vnc_connection_is_open(obj->priv->conn)) {
-		g_object_unref(G_OBJECT(obj));
-		return FALSE;
-	}
+	g_signal_emit(G_OBJECT(obj), signals[VNC_INITIALIZED], 0);
 
-	obj->priv->open_id = 0;
+	GVNC_DEBUG("Initialized VNC server");
+	return;
 
-	co = &obj->priv->coroutine;
+ error:
+	vnc_connection_shutdown(priv->conn);
+}
 
-	co->stack_size = 16 << 20;
-	co->entry = vnc_coroutine;
-	co->release = NULL;
 
-	coroutine_init(co);
-	coroutine_yieldto(co, obj);
+static void on_disconnected(VncConnection *conn G_GNUC_UNUSED,
+			    gpointer opaque)
+{
+	VncDisplay *obj = VNC_DISPLAY(opaque);
+	GVNC_DEBUG("Disconnected from VNC server");
 
-	return FALSE;
+	g_signal_emit(G_OBJECT(obj), signals[VNC_DISCONNECTED], 0);
+	g_object_unref(G_OBJECT(obj));
 }
 
+
 gboolean vnc_display_open_fd(VncDisplay *obj, int fd)
 {
-	if (obj->priv->conn == NULL || vnc_connection_is_open(obj->priv->conn))
+	VncDisplayPrivate *priv = obj->priv;
+
+	if (vnc_connection_is_open(priv->conn))
 		return FALSE;
 
-	obj->priv->fd = fd;
-	obj->priv->host = NULL;
-	obj->priv->port = NULL;
+	if (!vnc_connection_open_fd(priv->conn, fd))
+		return FALSE;
 
-	g_object_ref(G_OBJECT(obj)); /* Unref'd when co-routine exits */
-	obj->priv->open_id = g_idle_add(do_vnc_display_open, obj);
+	g_object_ref(G_OBJECT(obj));
 
 	return TRUE;
 }
 
 gboolean vnc_display_open_host(VncDisplay *obj, const char *host, const char *port)
 {
-	if (obj->priv->conn == NULL || vnc_connection_is_open(obj->priv->conn))
-		return FALSE;
+	VncDisplayPrivate *priv = obj->priv;
 
-	obj->priv->host = g_strdup(host);
-	if (!obj->priv->host) {
+	if (vnc_connection_is_open(priv->conn))
 		return FALSE;
-	}
-	obj->priv->port = g_strdup(port);
-	if (!obj->priv->port) {
-		g_free(obj->priv->host);
-		obj->priv->host = NULL;
+
+	if (!vnc_connection_open_host(priv->conn, host, port))
 		return FALSE;
-	}
 
-	g_object_ref(G_OBJECT(obj)); /* Unref'd when co-routine exits */
-	obj->priv->open_id = g_idle_add(do_vnc_display_open, obj);
+	g_object_ref(G_OBJECT(obj));
+
 	return TRUE;
 }
 
 gboolean vnc_display_is_open(VncDisplay *obj)
 {
-	if (obj->priv->conn == NULL)
-		return FALSE;
-	return vnc_connection_is_open(obj->priv->conn);
+	VncDisplayPrivate *priv = obj->priv;
+
+	return vnc_connection_is_open(priv->conn);
 }
 
 void vnc_display_close(VncDisplay *obj)
@@ -1454,14 +1340,6 @@ void vnc_display_close(VncDisplay *obj)
 	VncDisplayPrivate *priv = obj->priv;
 	GtkWidget *widget = GTK_WIDGET(obj);
 
-	if (priv->open_id) {
-		g_source_remove(priv->open_id);
-		obj->priv->open_id = 0;
-	}
-
-	if (priv->conn == NULL)
-		return;
-
 	if (vnc_connection_is_open(priv->conn)) {
 		GVNC_DEBUG("Requesting graceful shutdown of connection");
 		vnc_connection_shutdown(priv->conn);
@@ -1538,7 +1416,7 @@ void vnc_display_send_pointer(VncDisplay *obj, gint x, gint y, int button_mask)
 static void vnc_display_destroy (GtkObject *obj)
 {
 	VncDisplay *display = VNC_DISPLAY (obj);
-	GVNC_DEBUG("Requesting that VNC close");
+	GVNC_DEBUG("Display destroy, requesting that VNC connection close");
 	vnc_display_close(display);
 	GTK_OBJECT_CLASS (vnc_display_parent_class)->destroy (obj);
 }
@@ -1576,14 +1454,13 @@ static void vnc_display_finalize (GObject *obj)
 		priv->gc = NULL;
 	}
 
-	g_free (priv->host);
-	g_free (priv->port);
-
 	g_slist_free (priv->preferable_auths);
 
 	vnc_display_keyval_free_entries();
 
 	G_OBJECT_CLASS (vnc_display_parent_class)->finalize (obj);
+
+	winsock_cleanup();
 }
 
 static void vnc_display_class_init(VncDisplayClass *klass)
@@ -1919,8 +1796,7 @@ static void vnc_display_init(VncDisplay *display)
 	memset(priv, 0, sizeof(VncDisplayPrivate));
 	priv->last_x = -1;
 	priv->last_y = -1;
-	priv->absolute = 1;
-	priv->fd = -1;
+	priv->absolute = TRUE;
 	priv->read_only = FALSE;
 	priv->allow_lossy = FALSE;
 	priv->allow_scaling = FALSE;
@@ -1976,6 +1852,12 @@ static void vnc_display_init(VncDisplay *display)
 			 G_CALLBACK(on_auth_choose_type), display);
 	g_signal_connect(G_OBJECT(priv->conn), "vnc-auth-choose-subtype",
 			 G_CALLBACK(on_auth_choose_subtype), display);
+	g_signal_connect(G_OBJECT(priv->conn), "vnc-connected",
+			 G_CALLBACK(on_connected), display);
+	g_signal_connect(G_OBJECT(priv->conn), "vnc-initialized",
+			 G_CALLBACK(on_initialized), display);
+	g_signal_connect(G_OBJECT(priv->conn), "vnc-disconnected",
+			 G_CALLBACK(on_disconnected), display);
 
 	priv->keycode_map = vnc_display_keymap_x2pc_table();
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]