gdk/win32 and cairo [was: Cairo now a dependency of HEAD GTK+]



On 04.02.2005 00:31, Owen Taylor wrote:
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,
	Hans

diff --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



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