[PATCH 13/25] Replace 'local_cursor' operation callback with a signal



Remove the 'local_cursor' operation callback from VncConnection.
Introduce a signal 'vnc-cursor-changed' and pass it as a
VncCursor object
---
 src/vncconnection.c |  124 ++++++++++++++++++++++++++++++++++++++++++++------
 src/vncconnection.h |    7 +++-
 src/vncdisplay.c    |   33 ++++++++++----
 3 files changed, 139 insertions(+), 25 deletions(-)

diff --git a/src/vncconnection.c b/src/vncconnection.c
index bbe862e..88579ec 100644
--- a/src/vncconnection.c
+++ b/src/vncconnection.c
@@ -150,6 +150,8 @@ struct _VncConnectionPrivate
 	VncFramebuffer *fb;
 	gboolean fbSwapRemote;
 
+	VncCursor *cursor;
+
 	vnc_connection_rich_cursor_blt_func *rich_cursor_blt;
 	vnc_connection_tight_compute_predicted_func *tight_compute_predicted;
 	vnc_connection_tight_sum_pixel_func *tight_sum_pixel;
@@ -184,6 +186,15 @@ struct _VncConnectionPrivate
 
 G_DEFINE_TYPE(VncConnection, vnc_connection, G_TYPE_OBJECT);
 
+
+enum {
+	VNC_CURSOR_CHANGED,
+
+	VNC_LAST_SIGNAL,
+};
+
+static guint signals[VNC_LAST_SIGNAL] = { 0, };
+
 #define nibhi(a) (((a) >> 4) & 0x0F)
 #define niblo(a) ((a) & 0x0F)
 
@@ -344,6 +355,55 @@ static void vnc_connection_set_property(GObject *object,
         }
 }
 
+struct signal_data
+{
+	VncConnection *conn;
+	struct coroutine *caller;
+
+	int signum;
+
+	union {
+		VncCursor *cursor;
+	} params;
+};
+
+static gboolean do_vnc_connection_emit_main_context(gpointer opaque)
+{
+	struct signal_data *data = opaque;
+
+	switch (data->signum) {
+	case VNC_CURSOR_CHANGED:
+		g_signal_emit(G_OBJECT(data->conn),
+			      signals[data->signum],
+			      0,
+			      data->params.cursor);
+		break;
+	}
+
+	coroutine_yieldto(data->caller, NULL);
+
+	return FALSE;
+}
+
+static void vnc_connection_emit_main_context(VncConnection *conn,
+					     int signum,
+					     struct signal_data *data)
+{
+	data->conn = conn;
+	data->caller = coroutine_self();
+	data->signum = signum;
+
+	g_idle_add(do_vnc_connection_emit_main_context, data);
+
+	/* This switches to the system coroutine context, lets
+	 * the idle function run to dispatch the signal, and
+	 * finally returns once complete. ie this is synchronous
+	 * from the POV of the VNC coroutine despite there being
+	 * an idle function involved
+	 */
+	coroutine_yield(NULL);
+}
+
 
 static gboolean vnc_connection_use_compression(VncConnection *conn)
 {
@@ -2154,10 +2214,16 @@ static void vnc_connection_rich_cursor_blt(VncConnection *conn, guint8 *pixbuf,
 static void vnc_connection_rich_cursor(VncConnection *conn, int x, int y, int width, int height)
 {
 	VncConnectionPrivate *priv = conn->priv;
-	guint8 *pixbuf = NULL;
+	struct signal_data sigdata;
+
+	if (priv->cursor) {
+		g_object_unref(priv->cursor);
+		priv->cursor = NULL;
+	}
 
 	if (width && height) {
-		guint8 *image, *mask;
+		guint8 *pixbuf = NULL;
+		guint8 *image = NULL, *mask = NULL;
 		int imagelen, masklen;
 
 		imagelen = width * height * (priv->fmt.bits_per_pixel / 8);
@@ -2176,24 +2242,30 @@ static void vnc_connection_rich_cursor(VncConnection *conn, int x, int y, int wi
 
 		g_free(image);
 		g_free(mask);
+
+		priv->cursor = vnc_cursor_new(pixbuf, x, y, width, height);
 	}
 
-	if (priv->has_error || !priv->ops.local_cursor)
+	if (priv->has_error)
 		return;
-	if (!priv->ops.local_cursor(priv->ops_data, x, y, width, height, pixbuf)) {
-		GVNC_DEBUG("Closing the connection: vnc_connection_rich_cursor() - !ops.local_cursor()");
-		priv->has_error = TRUE;
-	}
 
-	g_free(pixbuf);
+	sigdata.params.cursor = priv->cursor;
+
+	vnc_connection_emit_main_context(conn, VNC_CURSOR_CHANGED, &sigdata);
 }
 
 static void vnc_connection_xcursor(VncConnection *conn, int x, int y, int width, int height)
 {
 	VncConnectionPrivate *priv = conn->priv;
-	guint8 *pixbuf = NULL;
+	struct signal_data sigdata;
+
+	if (priv->cursor) {
+		g_object_unref(priv->cursor);
+		priv->cursor = NULL;
+	}
 
 	if (width && height) {
+		guint8 *pixbuf = NULL;
 		guint8 *data, *mask, *datap, *maskp;
 		guint32 *pixp;
 		int rowlen;
@@ -2225,16 +2297,16 @@ static void vnc_connection_xcursor(VncConnection *conn, int x, int y, int width,
 		}
 		g_free(data);
 		g_free(mask);
+
+		priv->cursor = vnc_cursor_new(pixbuf, x, y, width, height);
 	}
 
-	if (priv->has_error || !priv->ops.local_cursor)
+	if (priv->has_error)
 		return;
-	if (!priv->ops.local_cursor(priv->ops_data, x, y, width, height, pixbuf)) {
-		GVNC_DEBUG("Closing the connection: vnc_connection_xcursor() - !ops.local_cursor()");
-		priv->has_error = TRUE;
-	}
 
-	g_free(pixbuf);
+	sigdata.params.cursor = priv->cursor;
+
+	vnc_connection_emit_main_context(conn, VNC_CURSOR_CHANGED, &sigdata);
 }
 
 static void vnc_connection_ext_key_event(VncConnection *conn)
@@ -3510,6 +3582,9 @@ static void vnc_connection_finalize (GObject *object)
 	if (vnc_connection_is_open(conn))
 		vnc_connection_close(conn);
 
+	if (priv->cursor)
+		g_object_unref(G_OBJECT(priv->cursor));
+
 	if (priv->fb)
 		g_object_unref(G_OBJECT(priv->fb));
 
@@ -3536,6 +3611,17 @@ static void vnc_connection_class_init(VncConnectionClass *klass)
 							    G_PARAM_STATIC_NICK |
 							    G_PARAM_STATIC_BLURB));
 
+	signals[VNC_CURSOR_CHANGED] =
+		g_signal_new ("vnc-cursor-changed",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (VncConnectionClass, vnc_cursor_changed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__OBJECT,
+			      G_TYPE_NONE,
+			      1,
+			      VNC_TYPE_CURSOR);
+
 	g_type_class_add_private(klass, sizeof(VncConnectionPrivate));
 }
 
@@ -4106,6 +4192,14 @@ gboolean vnc_connection_using_raw_keycodes(VncConnection *conn)
 	return priv->has_ext_key_event;
 }
 
+VncCursor *vnc_connection_get_cursor(VncConnection *conn)
+{
+	VncConnectionPrivate *priv = conn->priv;
+
+	return priv->cursor;
+}
+
+
 /*
  * Local variables:
  *  c-indent-level: 8
diff --git a/src/vncconnection.h b/src/vncconnection.h
index 68a348e..42a6e05 100644
--- a/src/vncconnection.h
+++ b/src/vncconnection.h
@@ -24,6 +24,7 @@
 #include <glib.h>
 
 #include "vncframebuffer.h"
+#include "vnccursor.h"
 
 G_BEGIN_DECLS
 
@@ -49,6 +50,9 @@ struct _VncConnection
 struct _VncConnectionClass
 {
 	GObjectClass parent_class;
+
+	/* Signals */
+	void (*vnc_cursor_changed)(VncConnection *conn, VncCursor *cursor);
 };
 
 typedef void (rgb24_render_func)(void *, int, int, int, int, guint8 *, int);
@@ -66,7 +70,6 @@ struct vnc_connection_ops
 	gboolean (*resize)(void *, int, int);
 	gboolean (*pixel_format)(void *, VncPixelFormat *);
 	gboolean (*pointer_type_change)(void *, int);
-	gboolean (*local_cursor)(void *, int, int, int, int, guint8 *);
 	gboolean (*auth_unsupported)(void *, unsigned int);
 	gboolean (*render_jpeg)(void *, rgb24_render_func *render, void *,
 				int, int, int, int, guint8 *, int);
@@ -193,6 +196,8 @@ const char *vnc_connection_get_name(VncConnection *conn);
 int vnc_connection_get_width(VncConnection *conn);
 int vnc_connection_get_height(VncConnection *conn);
 
+VncCursor *vnc_connection_get_cursor(VncConnection *conn);
+
 /* HACK this is temporary */
 gboolean vnc_connection_using_raw_keycodes(VncConnection *conn);
 
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index 165f67a..d796da0 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -939,6 +939,7 @@ static void emit_signal_delayed(VncDisplay *obj, int signum,
 	data->obj = obj;
 	data->caller = coroutine_self();
 	data->signum = signum;
+
 	g_idle_add(emit_signal_auth_cred, data);
 	coroutine_yield(NULL);
 }
@@ -1238,24 +1239,38 @@ static gboolean on_bell(void *opaque)
 	return TRUE;
 }
 
-static gboolean on_local_cursor(void *opaque, int x, int y, int width, int height, guint8 *image)
+static void on_cursor_changed(VncConnection *conn G_GNUC_UNUSED,
+			      VncCursor *cursor,
+			      gpointer opaque)
 {
 	VncDisplay *obj = VNC_DISPLAY(opaque);
 	VncDisplayPrivate *priv = obj->priv;
 
+	GVNC_DEBUG("Cursor changed %p x=%d y=%d w=%d h=%d",
+		   cursor,
+		   cursor ? vnc_cursor_get_hotx(cursor) : -1,
+		   cursor ? vnc_cursor_get_hoty(cursor) : -1,
+		   cursor ? vnc_cursor_get_width(cursor) : -1,
+		   cursor ? vnc_cursor_get_height(cursor) : -1);
+
 	if (priv->remote_cursor) {
 		gdk_cursor_unref(priv->remote_cursor);
 		priv->remote_cursor = NULL;
 	}
 
-	if (width && height) {
+	if (cursor) {
 		GdkDisplay *display = gdk_drawable_get_display(GDK_DRAWABLE(GTK_WIDGET(obj)->window));
-		GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data(image, GDK_COLORSPACE_RGB,
-							     TRUE, 8, width, height,
-							     width * 4, NULL, NULL);
+		GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data(vnc_cursor_get_data(cursor),
+							     GDK_COLORSPACE_RGB,
+							     TRUE, 8,
+							     vnc_cursor_get_width(cursor),
+							     vnc_cursor_get_height(cursor),
+							     vnc_cursor_get_width(cursor) * 4,
+							     NULL, NULL);
 		priv->remote_cursor = gdk_cursor_new_from_pixbuf(display,
 								 pixbuf,
-								 x, y);
+								 vnc_cursor_get_hotx(cursor),
+								 vnc_cursor_get_hoty(cursor));
 		g_object_unref(pixbuf);
 	}
 
@@ -1265,8 +1280,6 @@ static gboolean on_local_cursor(void *opaque, int x, int y, int width, int heigh
 	} else if (priv->absolute) {
 		do_pointer_hide(obj);
 	}
-
-	return TRUE;
 }
 
 static gboolean check_pixbuf_support(const char *name)
@@ -1329,7 +1342,6 @@ static const struct vnc_connection_ops vnc_display_ops = {
 	.resize = on_resize,
         .pixel_format = on_pixel_format,
 	.pointer_type_change = on_pointer_type_change,
-	.local_cursor = on_local_cursor,
 	.auth_unsupported = on_auth_unsupported,
 	.server_cut_text = on_server_cut_text,
 	.bell = on_bell,
@@ -2013,6 +2025,9 @@ static void vnc_display_init(VncDisplay *display)
 	priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_NONE));
 
 	priv->conn = vnc_connection_new(&vnc_display_ops, obj);
+
+	g_signal_connect(G_OBJECT(priv->conn), "vnc-cursor-changed",
+			 G_CALLBACK(on_cursor_changed), display);
 }
 
 static int vnc_display_best_path(char *buf,
-- 
1.6.5.2



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