Just committed a change to make GTK+ HEAD depend on Cairo.
Below you'll find my first attempt on integrating Cairo rendering with gdk/win32. I've tried to put descriptive comments in the code, here a short summary of the problem:
cairo_win32(set_target|create_surface) requires a HDC - a device context - to render to. My patch provides one by gdk_win32_hdc_get(). But due to the nature of DCs this device context needs to be released before it can be used for something else, i.e. 'draw' it into another device context. The current pattern of Gdk is to draw onto a backing store pixmap which finally gets blitted on the visible window. That involves two DCs: source pixmap, destination window. But as long as Cairo's suface DC isn't released that call will fail. (SelectObject() in blit_from_pixmap())
The most dirty part of my patch does call gdk_win32_hdc_release() shortly before that blit and thus actually can show something like this: http://hans.breuer.org/dia/testcairo.png But it all feels wrong ;)
Also I think mixing Cairo and Gdk drawing in the same DC will not work this way.
Does anyone have a better sollution?
Thanks,
Hansdiff --exclude-from=c:\util\tool\diff.ign -u --recursive from-cvs/gtk+/gdk/win32/gdkdrawable-win32.c my-gtk/gtk+/gdk/win32/gdkdrawable-win32.c
--- from-cvs/gtk+/gdk/win32/gdkdrawable-win32.c Sat Jan 29 23:42:37 2005
+++ my-gtk/gtk+/gdk/win32/gdkdrawable-win32.c Sun Feb 06 22:38:14 2005
@@ -33,6 +33,8 @@
#include <pango/pangowin32.h>
+#include <cairo-win32.h>
+
#include "gdkscreen.h" /* gdk_screen_get_default() */
#include "gdkregion-generic.h"
#include "gdkprivate-win32.h"
@@ -123,6 +125,9 @@
gint width,
gint height);+static void gdk_win32_set_cairo_target (GdkDrawable *drawable,
+ cairo_t *cr);
+
static void gdk_win32_set_colormap (GdkDrawable *drawable,
GdkColormap *colormap);@@ -192,6 +197,8 @@ drawable_class->draw_glyphs_transformed = gdk_win32_draw_glyphs_transformed; drawable_class->draw_image = gdk_win32_draw_image;
+ drawable_class->set_cairo_target = gdk_win32_set_cairo_target; + drawable_class->set_colormap = gdk_win32_set_colormap; drawable_class->get_colormap = gdk_win32_get_colormap;
@@ -202,11 +209,33 @@ drawable_class->_copy_to_image = _gdk_win32_copy_to_image; }
+typedef struct _GdkCairoExtra
+{
+ HDC hdc; /* the DC passed to Cairo, it lives too long! */
+ GdkGC *gc; /* not really used but for getting the HDC */
+} GdkCairoExtra;
+
static void
gdk_drawable_impl_win32_finalize (GObject *object)
{
+ GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (object);
+ GdkCairoExtra *extra = g_object_get_data (G_OBJECT(impl->wrapper), "gdk-cairo-extra");
+
gdk_drawable_set_colormap (GDK_DRAWABLE (object), NULL);
+ if (extra)
+ {
+ if (extra->hdc)
+ gdk_win32_hdc_release (GDK_DRAWABLE (object), extra->gc, 0);
+ gdk_gc_unref (extra->gc);
+ g_free (extra);
+ g_object_set_data (G_OBJECT (impl->wrapper), "gdk-cairo-extra", NULL);
+ }
+ if (impl->cairo_surface)
+ {
+ cairo_surface_destroy (impl->cairo_surface);
+ impl->cairo_surface = NULL;
+ }
G_OBJECT_CLASS (parent_class)->finalize (object);
}@@ -1204,8 +1233,21 @@
gint width,
gint height)
{
+ GdkCairoExtra *extra = g_object_get_data (G_OBJECT (src), "gdk-cairo-extra");
+
g_assert (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable));+ /* FIXME: this is an ugly hack but the best I could come up with
+ * short term to get something from cairo at all (can't select the
+ * same bitmap into different HDCs)
+ */
+ if (extra)
+ {
+ if (extra->hdc)
+ gdk_win32_hdc_release (src, extra->gc, 0);
+ extra->hdc = NULL;
+ }
+
_gdk_win32_blit (FALSE, (GdkDrawableImplWin32 *) drawable,
gc, src, xsrc, ysrc,
xdest, ydest, width, height);
@@ -1961,6 +2003,54 @@
gdk_win32_drawable_get_handle (GdkDrawable *drawable)
{
return GDK_DRAWABLE_HANDLE (drawable);
+}
+
+static cairo_surface_t *
+gdk_win32_drawable_get_cairo_surface (GdkDrawable *drawable)
+{
+ GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
+ GdkCairoExtra *extra = g_object_get_data (G_OBJECT (impl->wrapper), "gdk-cairo-extra");
+
+ if (GDK_IS_WINDOW_IMPL_WIN32 (drawable) &&
+ GDK_WINDOW_DESTROYED (impl->wrapper))
+ return NULL;
+
+ if (extra)
+ {
+ /* this is much too late, but the best we can do with Cairo lacking
+ * destroy (show_page?) notification. Or wait, see the hack in
+ * gdk_win32_draw_drawable(), even messier.
+ */
+ if (extra->hdc)
+ gdk_win32_hdc_release (drawable, extra->gc, 0);
+ extra->hdc = NULL;
+ }
+ else
+ {
+ extra = g_new0 (GdkCairoExtra, 1);
+ extra->gc = gdk_gc_new (drawable);
+ g_object_set_data (G_OBJECT (impl->wrapper), "gdk-cairo-extra", extra);
+ }
+
+ extra->hdc = gdk_win32_hdc_get (impl->wrapper, extra->gc, 0);
+ if (impl->cairo_surface)
+ {
+ /* get rid of it (apparently there is no way to update the HDC in an existing
+ * win32 surface. And I doubt there should ;)
+ */
+ cairo_surface_destroy (impl->cairo_surface);
+ }
+ impl->cairo_surface = cairo_win32_surface_create (extra->hdc);
+ return impl->cairo_surface;
+}
+
+static void
+gdk_win32_set_cairo_target (GdkDrawable *drawable,
+ cairo_t *cr)
+{
+ cairo_surface_t *surface = gdk_win32_drawable_get_cairo_surface (drawable);
+ if (surface)
+ cairo_set_target_surface (cr, surface);
}
gboolean
diff --exclude-from=c:\util\tool\diff.ign -u --recursive from-cvs/gtk+/gdk/win32/gdkdrawable-win32.h my-gtk/gtk+/gdk/win32/gdkdrawable-win32.h
--- from-cvs/gtk+/gdk/win32/gdkdrawable-win32.h Sun Feb 17 16:57:18 2002
+++ my-gtk/gtk+/gdk/win32/gdkdrawable-win32.h Sun Feb 06 17:09:31 2005
@@ -53,6 +53,8 @@
GdkDrawable *wrapper;
GdkColormap *colormap;
HANDLE handle;
+
+ cairo_surface_t *cairo_surface;
};
struct _GdkDrawableImplWin32Class _______________________________________________ gtk-devel-list mailing list [email protected] http://mail.gnome.org/mailman/listinfo/gtk-devel-list
