[gtk-vnc] Add a cairo based framebuffer implementation
- From: Daniel P. Berrange <dberrange src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk-vnc] Add a cairo based framebuffer implementation
- Date: Fri, 20 Aug 2010 17:28:33 +0000 (UTC)
commit 44dd203e80b5310feaa3af6969a83dc54186069c
Author: Daniel P. Berrange <berrange redhat com>
Date: Fri Aug 20 16:26:32 2010 +0100
Add a cairo based framebuffer implementation
In GTK3, GdkImage has been removed completely. The vncimageframebuffer
class cannot thus be used. Replace it with a vnccairoframebuffer
class instead, but keep the old one around in GTK2 builds for ABI
compatability.
* src/vnccairoframebuffer.c, src/vnccairoframebuffer.h,
src/libgtk-vnc_sym.version: Add new framebuffer impl
based on Cairo.
* src/Makefile.am: Disable GdkImage based framebuffer on
GTK3 builds
* src/vncdisplay.c: Always use Cairo based framebuffer
src/Makefile.am | 17 ++++-
src/libgtk-vnc_sym.version | 4 +
src/vnccairoframebuffer.c | 178 ++++++++++++++++++++++++++++++++++++++++++++
src/vnccairoframebuffer.h | 83 ++++++++++++++++++++
src/vncdisplay.c | 90 ++++++++++-------------
5 files changed, 319 insertions(+), 53 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 5ea1c51..85649fb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -98,13 +98,20 @@ gtk_vnc_include_HEADERS = \
vncimageframebuffer.h
gtk_vnc_SOURCES = \
- vncimageframebuffer.h vncimageframebuffer.c \
+ vnccairoframebuffer.h vnccairoframebuffer.c \
vncdisplay.h vncdisplay.c \
vncdisplayenums.h vncdisplayenums.c \
vncdisplaykeymap.h vncdisplaykeymap.c \
vncgrabsequence.h vncgrabsequence.c \
vncmarshal.h vncmarshal.c
+if HAVE_GTK_2
+gtk_vnc_SOURCES += \
+ vncimageframebuffer.h vncimageframebuffer.c
+else
+EXTRA_DIST += vncimageframebuffer.h vncimageframebuffer.c
+endif
+
gtk_vnc_LDFLAGS = \
$(VERSION_SCRIPT_FLAGS)$(GTK_VNC_VERSION_FILE) \
$(NO_UNDEFINED_FLAGS)
@@ -269,11 +276,17 @@ GVNC_INTROSPECTION_SRCS = \
$(srcdir)/vncutil.h $(srcdir)/vncutil.c
GTK_VNC_INTROSPECTION_SRCS = \
- $(srcdir)/vncimageframebuffer.h $(srcdir)/vncimageframebuffer.c \
+ $(srcdir)/vnccairoframebuffer.h $(srcdir)/vnccairoframebuffer.c \
$(srcdir)/vncdisplay.h $(srcdir)/vncdisplay.c \
$(srcdir)/vncgrabsequence.h $(srcdir)/vncgrabsequence.c \
$(builddir)/vncdisplayenums.h $(builddir)/vncdisplayenums.c
+if HAVE_GTK_2
+GTK_VNC_INTROSPECTION_SRCS += \
+ $(srcdir)/vncimageframebuffer.h $(srcdir)/vncimageframebuffer.c \
+else
+endif
+
GVnc-1.0.gir: libgvnc-1.0.la $(G_IR_SCANNER) Makefile.am
$(AM_V_GEN)$(G_IR_SCANNER) -v \
--namespace GVnc \
diff --git a/src/libgtk-vnc_sym.version b/src/libgtk-vnc_sym.version
index dc219d4..7b641ec 100644
--- a/src/libgtk-vnc_sym.version
+++ b/src/libgtk-vnc_sym.version
@@ -68,6 +68,10 @@
vnc_image_framebuffer_new;
vnc_image_framebuffer_get_image;
+ vnc_cairo_framebuffer_get_type;
+ vnc_cairo_framebuffer_new;
+ vnc_cairo_framebuffer_get_surface;
+
# grab key settings support
vnc_display_set_grab_keys;
vnc_display_get_grab_keys;
diff --git a/src/vnccairoframebuffer.c b/src/vnccairoframebuffer.c
new file mode 100644
index 0000000..48e2f2a
--- /dev/null
+++ b/src/vnccairoframebuffer.c
@@ -0,0 +1,178 @@
+/*
+ * GTK VNC Widget
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony codemonkey ws>
+ * Copyright (C) 2009-2010 Daniel P. Berrange <dan berrange com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.0 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <gtk/gtk.h>
+
+#include "vnccairoframebuffer.h"
+#include "vncutil.h"
+
+#define VNC_CAIRO_FRAMEBUFFER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), VNC_TYPE_CAIRO_FRAMEBUFFER, VncCairoFramebufferPrivate))
+
+struct _VncCairoFramebufferPrivate {
+ cairo_surface_t *surface;
+};
+
+
+G_DEFINE_TYPE(VncCairoFramebuffer, vnc_cairo_framebuffer, VNC_TYPE_BASE_FRAMEBUFFER);
+
+
+enum {
+ PROP_0,
+ PROP_SURFACE,
+};
+
+
+static void vnc_cairo_framebuffer_get_property(GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ VncCairoFramebuffer *framebuffer = VNC_CAIRO_FRAMEBUFFER(object);
+ VncCairoFramebufferPrivate *priv = framebuffer->priv;
+
+ switch (prop_id) {
+ case PROP_SURFACE:
+ g_value_set_pointer(value, priv->surface);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ }
+}
+
+static void vnc_cairo_framebuffer_set_property(GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ VncCairoFramebuffer *framebuffer = VNC_CAIRO_FRAMEBUFFER(object);
+ VncCairoFramebufferPrivate *priv = framebuffer->priv;
+
+ switch (prop_id) {
+ case PROP_SURFACE:
+ priv->surface = g_value_get_pointer(value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ }
+}
+
+static void vnc_cairo_framebuffer_finalize (GObject *object)
+{
+ VncCairoFramebuffer *fb = VNC_CAIRO_FRAMEBUFFER(object);
+ VncCairoFramebufferPrivate *priv = fb->priv;
+
+ if (priv->surface)
+ cairo_surface_destroy(priv->surface);
+
+ G_OBJECT_CLASS(vnc_cairo_framebuffer_parent_class)->finalize (object);
+}
+
+static void vnc_cairo_framebuffer_class_init(VncCairoFramebufferClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = vnc_cairo_framebuffer_finalize;
+ object_class->get_property = vnc_cairo_framebuffer_get_property;
+ object_class->set_property = vnc_cairo_framebuffer_set_property;
+
+ g_object_class_install_property(object_class,
+ PROP_SURFACE,
+ g_param_spec_pointer("surface",
+ "The cairo surface",
+ "The cairo surface for the framebuffer",
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK |
+ G_PARAM_STATIC_BLURB));
+
+ g_type_class_add_private(klass, sizeof(VncCairoFramebufferPrivate));
+}
+
+
+void vnc_cairo_framebuffer_init(VncCairoFramebuffer *fb)
+{
+ VncCairoFramebufferPrivate *priv;
+
+ priv = fb->priv = VNC_CAIRO_FRAMEBUFFER_GET_PRIVATE(fb);
+
+ memset(priv, 0, sizeof(*priv));
+}
+
+
+VncCairoFramebuffer *vnc_cairo_framebuffer_new(guint16 width, guint16 height,
+ const VncPixelFormat *remoteFormat)
+{
+ VncPixelFormat localFormat;
+ cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
+ guint8 *pixels;
+
+ VNC_DEBUG("Surface %dx%d", width, height);
+
+ localFormat.red_max = 255;
+ localFormat.green_max = 255;
+ localFormat.blue_max = 255;
+ localFormat.red_shift = 16;
+ localFormat.green_shift = 8;
+ localFormat.blue_shift = 0;
+ localFormat.depth = 32;
+ localFormat.bits_per_pixel = 32;
+ /* XXX is cairo native endian ? */
+ localFormat.byte_order = G_LITTLE_ENDIAN;
+
+ pixels = cairo_image_surface_get_data(surface);
+
+ memset(pixels, 0, width * height * 4);
+
+ return VNC_CAIRO_FRAMEBUFFER(g_object_new(VNC_TYPE_CAIRO_FRAMEBUFFER,
+ "surface", surface,
+ "buffer", pixels,
+ "width", width,
+ "height", height,
+ "rowstride", cairo_image_surface_get_stride(surface),
+ "local-format", &localFormat,
+ "remote-format", remoteFormat,
+ NULL));
+}
+
+
+cairo_surface_t *vnc_cairo_framebuffer_get_surface(VncCairoFramebuffer *fb)
+{
+ VncCairoFramebufferPrivate *priv = fb->priv;
+
+ return priv->surface;
+}
+
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * tab-width: 8
+ * End:
+ */
diff --git a/src/vnccairoframebuffer.h b/src/vnccairoframebuffer.h
new file mode 100644
index 0000000..5d4d675
--- /dev/null
+++ b/src/vnccairoframebuffer.h
@@ -0,0 +1,83 @@
+/*
+ * GTK VNC Widget
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony codemonkey ws>
+ * Copyright (C) 2009-2010 Daniel P. Berrange <dan berrange com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.0 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef VNC_CAIRO_FRAMEBUFFER_H
+#define VNC_CAIRO_FRAMEBUFFER_H
+
+#include <gdk/gdk.h>
+
+#include <vncbaseframebuffer.h>
+#include <vncutil.h>
+
+G_BEGIN_DECLS
+
+#define VNC_TYPE_CAIRO_FRAMEBUFFER (vnc_cairo_framebuffer_get_type ())
+#define VNC_CAIRO_FRAMEBUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VNC_TYPE_CAIRO_FRAMEBUFFER, VncCairoFramebuffer))
+#define VNC_CAIRO_FRAMEBUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VNC_TYPE_CAIRO_FRAMEBUFFER, VncCairoFramebufferClass))
+#define VNC_IS_CAIRO_FRAMEBUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VNC_TYPE_CAIRO_FRAMEBUFFER))
+#define VNC_IS_CAIRO_FRAMEBUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VNC_TYPE_CAIRO_FRAMEBUFFER))
+#define VNC_CAIRO_FRAMEBUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VNC_TYPE_CAIRO_FRAMEBUFFER, VncCairoFramebufferClass))
+
+
+typedef struct _VncCairoFramebuffer VncCairoFramebuffer;
+typedef struct _VncCairoFramebufferPrivate VncCairoFramebufferPrivate;
+typedef struct _VncCairoFramebufferClass VncCairoFramebufferClass;
+
+struct _VncCairoFramebuffer
+{
+ VncBaseFramebuffer parent;
+
+ VncCairoFramebufferPrivate *priv;
+
+ /* Do not add fields to this struct */
+};
+
+struct _VncCairoFramebufferClass
+{
+ VncBaseFramebufferClass parent_class;
+
+ /*
+ * If adding fields to this struct, remove corresponding
+ * amount of padding to avoid changing overall struct size
+ */
+ gpointer _vnc_reserved[VNC_PADDING];
+};
+
+
+GType vnc_cairo_framebuffer_get_type(void) G_GNUC_CONST;
+
+VncCairoFramebuffer *vnc_cairo_framebuffer_new(guint16 width, guint16 height,
+ const VncPixelFormat *remoteFormat);
+
+cairo_surface_t *vnc_cairo_framebuffer_get_surface(VncCairoFramebuffer *fb);
+
+
+G_END_DECLS
+
+#endif /* VNC_CAIRO_FRAMEBUFFER_H */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * tab-width: 8
+ * End:
+ */
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index 60a25fd..5c7845e 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -24,11 +24,11 @@
#include "vncdisplay.h"
#include "vncconnection.h"
-#include "vncimageframebuffer.h"
#include "vncutil.h"
#include "vncmarshal.h"
#include "vncdisplaykeymap.h"
#include "vncdisplayenums.h"
+#include "vnccairoframebuffer.h"
#include <gtk/gtk.h>
#include <glib/gi18n.h>
@@ -45,13 +45,12 @@
struct _VncDisplayPrivate
{
- GdkGC *gc;
GdkPixmap *pixmap;
GdkCursor *null_cursor;
GdkCursor *remote_cursor;
VncConnection *conn;
- VncImageFramebuffer *fb;
+ VncCairoFramebuffer *fb;
VncDisplayDepthColor depth;
@@ -258,17 +257,20 @@ GtkWidget *vnc_display_new(void)
static GdkCursor *create_null_cursor(void)
{
- GdkBitmap *image;
- gchar data[4] = {0};
+ cairo_t *cr;
GdkColor fg = { 0, 0, 0, 0 };
GdkCursor *cursor;
+ GdkPixmap *pixmap;
- image = gdk_bitmap_create_from_data(NULL, data, 1, 1);
+ pixmap = gdk_pixmap_new(NULL, 1, 1, 1);
+ cr = gdk_cairo_create(pixmap);
+ cairo_rectangle(cr, 0, 0, 1, 1);
+ cairo_fill(cr);
+ cairo_destroy(cr);
- cursor = gdk_cursor_new_from_pixmap(GDK_PIXMAP(image),
- GDK_PIXMAP(image),
+ cursor = gdk_cursor_new_from_pixmap(pixmap, pixmap,
&fg, &fg, 0, 0);
- g_object_unref(image);
+ g_object_unref(pixmap);
return cursor;
}
@@ -302,10 +304,10 @@ static gboolean expose_event(GtkWidget *widget, GdkEventExpose *expose)
cr = gdk_cairo_create(gtk_widget_get_window(GTK_WIDGET(obj)));
cairo_rectangle(cr,
- expose->area.x,
- expose->area.y,
- expose->area.width + 1,
- expose->area.height + 1);
+ expose->area.x-1,
+ expose->area.y-1,
+ expose->area.width + 2,
+ expose->area.height + 2);
cairo_clip(cr);
/* If we don't have a pixmap, or we're not scaling, then
@@ -820,17 +822,22 @@ static void on_framebuffer_update(VncConnection *conn G_GNUC_UNUSED,
VncDisplay *obj = VNC_DISPLAY(widget);
VncDisplayPrivate *priv = obj->priv;
int ww, wh;
- GdkRectangle r = { x, y, w, h };
int fbw, fbh;
+ cairo_surface_t *surface;
+ cairo_t *cr;
fbw = vnc_framebuffer_get_width(VNC_FRAMEBUFFER(priv->fb));
fbh = vnc_framebuffer_get_height(VNC_FRAMEBUFFER(priv->fb));
- /* Copy pixbuf to pixmap */
- gdk_gc_set_clip_rectangle(priv->gc, &r);
- gdk_draw_image(priv->pixmap, priv->gc,
- vnc_image_framebuffer_get_image(priv->fb),
- x, y, x, y, w, h);
+ cr = gdk_cairo_create(priv->pixmap);
+ cairo_rectangle(cr, x, y, w, h);
+ cairo_clip(cr);
+
+ surface = vnc_cairo_framebuffer_get_surface(priv->fb);
+ cairo_set_source_surface(cr, surface, 0, 0);
+ cairo_paint(cr);
+
+ cairo_destroy(cr);
gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
@@ -873,8 +880,6 @@ static void do_framebuffer_init(VncDisplay *obj,
int width, int height, gboolean quiet)
{
VncDisplayPrivate *priv = obj->priv;
- GdkVisual *visual;
- GdkImage *image;
if (priv->conn == NULL || !vnc_connection_is_initialized(priv->conn))
return;
@@ -888,24 +893,17 @@ static void do_framebuffer_init(VncDisplay *obj,
priv->pixmap = NULL;
}
- if (priv->gc == NULL) {
- if (!priv->null_cursor)
- priv->null_cursor = create_null_cursor();
+ if (priv->null_cursor == NULL) {
+ priv->null_cursor = create_null_cursor();
if (priv->local_pointer)
do_pointer_show(obj);
else if (priv->in_pointer_grab || priv->absolute)
do_pointer_hide(obj);
- priv->gc = gdk_gc_new(gtk_widget_get_window(GTK_WIDGET(obj)));
}
- visual = gdk_drawable_get_visual(gtk_widget_get_window(GTK_WIDGET(obj)));
- image = gdk_image_new(GDK_IMAGE_FASTEST, visual, width, height);
-
- priv->fb = vnc_image_framebuffer_new(image, remoteFormat);
+ priv->fb = vnc_cairo_framebuffer_new(width, height, remoteFormat);
priv->pixmap = gdk_pixmap_new(gtk_widget_get_window(GTK_WIDGET(obj)), width, height, -1);
- g_object_unref(G_OBJECT(image));
-
vnc_connection_set_framebuffer(priv->conn, VNC_FRAMEBUFFER(priv->fb));
if (priv->force_size)
@@ -1479,10 +1477,6 @@ static void vnc_display_finalize (GObject *obj)
priv->remote_cursor = NULL;
}
- if (priv->gc) {
- g_object_unref (priv->gc);
- priv->gc = NULL;
- }
if (priv->vncgrabseq) {
vnc_grab_sequence_free(priv->vncgrabseq);
priv->vncgrabseq = NULL;
@@ -1913,7 +1907,7 @@ gboolean vnc_display_set_credential(VncDisplay *obj, int type, const gchar *data
void vnc_display_set_pointer_local(VncDisplay *obj, gboolean enable)
{
- if (obj->priv->gc) {
+ if (obj->priv->null_cursor) {
if (enable)
do_pointer_show(obj);
else if (obj->priv->in_pointer_grab || obj->priv->absolute)
@@ -1967,32 +1961,26 @@ GdkPixbuf *vnc_display_get_pixbuf(VncDisplay *obj)
{
VncDisplayPrivate *priv = obj->priv;
GdkPixbuf *pixbuf;
- GdkImage *image;
+ cairo_surface_t *surface;
gint w, h;
if (!priv->conn ||
!vnc_connection_is_initialized(priv->conn))
return NULL;
- image = vnc_image_framebuffer_get_image(priv->fb);
- #if GTK_CHECK_VERSION(2, 21, 1)
- w = gdk_image_get_width (image);
- h = gdk_image_get_height (image);
- #else
- w = image->width;
- h = image->height;
- #endif
+ surface = vnc_cairo_framebuffer_get_surface(priv->fb);
+ w = vnc_framebuffer_get_width(VNC_FRAMEBUFFER(priv->fb));
+ h = vnc_framebuffer_get_height(VNC_FRAMEBUFFER(priv->fb));
pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
w,
h);
- if (!gdk_pixbuf_get_from_image(pixbuf,
- image,
- gdk_colormap_get_system(),
- 0, 0, 0, 0,
- w,
- h))
+ if (!gdk_pixbuf_get_from_drawable(pixbuf,
+ priv->pixmap,
+ NULL,
+ 0, 0, 0, 0,
+ w, h))
return NULL;
return pixbuf;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]