]> Pileus Git - ~andy/gtk/blobdiff - gdk/win32/gdkdrawable-win32.c
Rename from blit_inside_window(), as it now does blitting inside a bitmap,
[~andy/gtk] / gdk / win32 / gdkdrawable-win32.c
index 3dd9b20153a870933cea6a0dcf3090409d2b48f3..31d6a4195752e11333a5862862647aca79173540 100644 (file)
@@ -1,55 +1,66 @@
 /* GDK - The GIMP Drawing Kit
  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1998-2004 Tor Lillqvist
+ * Copyright (C) 2001-2005 Hans Breuer
  *
  * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2 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
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public
+ * 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., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
 
 /*
- * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
  * file for a list of people on the GTK+ Team.  See the ChangeLog
  * files for a list of changes.  These files are distributed with
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
-#include "config.h"
-
+#include <config.h>
 #include <math.h>
+#include <stdio.h>
 #include <glib.h>
 
-#ifndef G_PI
-#define G_PI 3.14159265358979323846
-#endif
+#include <pango/pangowin32.h>
+#include <cairo-win32.h>
+
+#include "gdkscreen.h" /* gdk_screen_get_default() */
+#include "gdkregion-generic.h"
+#include "gdkprivate-win32.h"
+
+#define ROP3_D 0x00AA0029
+#define ROP3_DSna 0x00220326
+#define ROP3_DSPDxax 0x00E20746
 
-#include "gdkdrawable.h"
-#include "gdkprivate.h"
-#include "gdkwindow.h"
-#include "gdkwin32.h"
+#define LINE_ATTRIBUTES (GDK_GC_LINE_WIDTH|GDK_GC_LINE_STYLE| \
+                        GDK_GC_CAP_STYLE|GDK_GC_JOIN_STYLE)
 
-static void gdk_win32_drawable_destroy   (GdkDrawable     *drawable);
+#define MUST_RENDER_DASHES_MANUALLY(gcwin32)                   \
+  (gcwin32->line_style == GDK_LINE_DOUBLE_DASH ||              \
+   (gcwin32->line_style == GDK_LINE_ON_OFF_DASH &&             \
+    (gcwin32->pen_dash_offset ||                               \
+     (!G_WIN32_IS_NT_BASED () && (gcwin32->pen_style & PS_STYLE_MASK) == PS_SOLID))))
 
 static void gdk_win32_draw_rectangle (GdkDrawable    *drawable,
                                      GdkGC          *gc,
-                                     gint            filled,
+                                     gboolean        filled,
                                      gint            x,
                                      gint            y,
                                      gint            width,
                                      gint            height);
 static void gdk_win32_draw_arc       (GdkDrawable    *drawable,
                                      GdkGC          *gc,
-                                     gint            filled,
+                                     gboolean        filled,
                                      gint            x,
                                      gint            y,
                                      gint            width,
@@ -58,7 +69,7 @@ static void gdk_win32_draw_arc       (GdkDrawable    *drawable,
                                      gint            angle2);
 static void gdk_win32_draw_polygon   (GdkDrawable    *drawable,
                                      GdkGC          *gc,
-                                     gint            filled,
+                                     gboolean        filled,
                                      GdkPoint       *points,
                                      gint            npoints);
 static void gdk_win32_draw_text      (GdkDrawable    *drawable,
@@ -96,196 +107,854 @@ static void gdk_win32_draw_lines     (GdkDrawable    *drawable,
                                      GdkGC          *gc,
                                      GdkPoint       *points,
                                      gint            npoints);
+static void gdk_win32_draw_image     (GdkDrawable     *drawable,
+                                     GdkGC           *gc,
+                                     GdkImage        *image,
+                                     gint             xsrc,
+                                     gint             ysrc,
+                                     gint             xdest,
+                                     gint             ydest,
+                                     gint             width,
+                                     gint             height);
 
-GdkDrawableClass _gdk_win32_drawable_class = {
-  gdk_win32_drawable_destroy,
-  _gdk_win32_gc_new,
-  gdk_win32_draw_rectangle,
-  gdk_win32_draw_arc,
-  gdk_win32_draw_polygon,
-  gdk_win32_draw_text,
-  gdk_win32_draw_text_wc,
-  gdk_win32_draw_drawable,
-  gdk_win32_draw_points,
-  gdk_win32_draw_segments,
-  gdk_win32_draw_lines
-};
+static cairo_surface_t *gdk_win32_ref_cairo_surface (GdkDrawable *drawable);
+     
+static void gdk_win32_set_colormap   (GdkDrawable    *drawable,
+                                     GdkColormap    *colormap);
 
-/*****************************************************
- * Win32 specific implementations of generic functions *
- *****************************************************/
+static GdkColormap* gdk_win32_get_colormap   (GdkDrawable    *drawable);
+
+static gint         gdk_win32_get_depth      (GdkDrawable    *drawable);
 
-GdkColormap*
-gdk_drawable_get_colormap (GdkDrawable *drawable)
+static GdkScreen *  gdk_win32_get_screen     (GdkDrawable    *drawable);
+
+static GdkVisual*   gdk_win32_get_visual     (GdkDrawable    *drawable);
+
+static void gdk_drawable_impl_win32_class_init (GdkDrawableImplWin32Class *klass);
+
+static void gdk_drawable_impl_win32_finalize   (GObject *object);
+
+static gpointer parent_class = NULL;
+static const cairo_user_data_key_t gdk_win32_cairo_key;
+
+GType
+gdk_drawable_impl_win32_get_type (void)
 {
-  GdkDrawablePrivate *drawable_private;
-  
-  g_return_val_if_fail (drawable != NULL, NULL);
-  drawable_private = (GdkDrawablePrivate*) drawable;
+  static GType object_type = 0;
 
-  if (!GDK_DRAWABLE_DESTROYED (drawable))
+  if (!object_type)
     {
-      if (drawable_private->colormap == NULL)
-       return gdk_colormap_get_system (); /* XXX ??? */
-      else
-       return drawable_private->colormap;
+      static const GTypeInfo object_info =
+      {
+        sizeof (GdkDrawableImplWin32Class),
+        (GBaseInitFunc) NULL,
+        (GBaseFinalizeFunc) NULL,
+        (GClassInitFunc) gdk_drawable_impl_win32_class_init,
+        NULL,           /* class_finalize */
+        NULL,           /* class_data */
+        sizeof (GdkDrawableImplWin32),
+        0,              /* n_preallocs */
+        (GInstanceInitFunc) NULL,
+      };
+      
+      object_type = g_type_register_static (GDK_TYPE_DRAWABLE,
+                                            "GdkDrawableImplWin32",
+                                            &object_info, 0);
     }
   
-  return NULL;
+  return object_type;
 }
 
-void
-gdk_drawable_set_colormap (GdkDrawable *drawable,
-                          GdkColormap *colormap)
+static void
+gdk_drawable_impl_win32_class_init (GdkDrawableImplWin32Class *klass)
 {
-  GdkDrawablePrivate *drawable_private;
-  GdkColormapPrivateWin32 *colormap_private;
+  GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  object_class->finalize = gdk_drawable_impl_win32_finalize;
+
+  drawable_class->create_gc = _gdk_win32_gc_new;
+  drawable_class->draw_rectangle = gdk_win32_draw_rectangle;
+  drawable_class->draw_arc = gdk_win32_draw_arc;
+  drawable_class->draw_polygon = gdk_win32_draw_polygon;
+  drawable_class->draw_text = gdk_win32_draw_text;
+  drawable_class->draw_text_wc = gdk_win32_draw_text_wc;
+  drawable_class->draw_drawable = gdk_win32_draw_drawable;
+  drawable_class->draw_points = gdk_win32_draw_points;
+  drawable_class->draw_segments = gdk_win32_draw_segments;
+  drawable_class->draw_lines = gdk_win32_draw_lines;
+  drawable_class->draw_image = gdk_win32_draw_image;
   
-  g_return_if_fail (drawable != NULL);
-  g_return_if_fail (colormap != NULL);
+  drawable_class->ref_cairo_surface = gdk_win32_ref_cairo_surface;
   
-  drawable_private = (GdkDrawablePrivate *) drawable;
-  colormap_private = (GdkColormapPrivateWin32 *) colormap;
+  drawable_class->set_colormap = gdk_win32_set_colormap;
+  drawable_class->get_colormap = gdk_win32_get_colormap;
+
+  drawable_class->get_depth = gdk_win32_get_depth;
+  drawable_class->get_screen = gdk_win32_get_screen;
+  drawable_class->get_visual = gdk_win32_get_visual;
+
+  drawable_class->_copy_to_image = _gdk_win32_copy_to_image;
+}
+
+static void
+gdk_drawable_impl_win32_finalize (GObject *object)
+{
+  gdk_drawable_set_colormap (GDK_DRAWABLE (object), NULL);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/*****************************************************
+ * Win32 specific implementations of generic functions *
+ *****************************************************/
+
+static GdkColormap*
+gdk_win32_get_colormap (GdkDrawable *drawable)
+{
+  return GDK_DRAWABLE_IMPL_WIN32 (drawable)->colormap;
+}
+
+static void
+gdk_win32_set_colormap (GdkDrawable *drawable,
+                       GdkColormap *colormap)
+{
+  GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
+
+  if (impl->colormap == colormap)
+    return;
   
-  if (!GDK_DRAWABLE_DESTROYED (drawable))
+  if (impl->colormap)
+    gdk_colormap_unref (impl->colormap);
+  impl->colormap = colormap;
+  if (impl->colormap)
+    gdk_colormap_ref (impl->colormap);
+}
+
+/* Drawing
+ */
+
+static int
+rop2_to_rop3 (int rop2)
+{
+  switch (rop2)
+    {
+    /* Oh, Microsoft's silly names for binary and ternary rops. */
+#define CASE(rop2,rop3) case R2_##rop2: return rop3
+      CASE (BLACK, BLACKNESS);
+      CASE (NOTMERGEPEN, NOTSRCERASE);
+      CASE (MASKNOTPEN, 0x00220326);
+      CASE (NOTCOPYPEN, NOTSRCCOPY);
+      CASE (MASKPENNOT, SRCERASE);
+      CASE (NOT, DSTINVERT);
+      CASE (XORPEN, SRCINVERT);
+      CASE (NOTMASKPEN, 0x007700E6);
+      CASE (MASKPEN, SRCAND);
+      CASE (NOTXORPEN, 0x00990066);
+      CASE (NOP, 0x00AA0029);
+      CASE (MERGENOTPEN, MERGEPAINT);
+      CASE (COPYPEN, SRCCOPY);
+      CASE (MERGEPENNOT, 0x00DD0228);
+      CASE (MERGEPEN, SRCPAINT);
+      CASE (WHITE, WHITENESS);
+#undef CASE
+    default: return SRCCOPY;
+    }
+}
+
+static int
+rop2_to_patblt_rop (int rop2)
+{
+  switch (rop2)
+    {
+#define CASE(rop2,patblt_rop) case R2_##rop2: return patblt_rop
+      CASE (COPYPEN, PATCOPY);
+      CASE (XORPEN, PATINVERT);
+      CASE (NOT, DSTINVERT);
+      CASE (BLACK, BLACKNESS);
+      CASE (WHITE, WHITENESS);
+#undef CASE
+    default:
+      g_warning ("Unhandled rop2 in GC to be used in PatBlt: %#x", rop2);
+      return PATCOPY;
+    }
+}
+
+static inline int
+align_with_dash_offset (int a, DWORD *dashes, int num_dashes, GdkGCWin32 *gcwin32)
+{
+  int     n = 0;
+  int    len_sum = 0;
+  /* 
+   * We can't simply add the dashoffset, it can be an arbitrary larger
+   * or smaller value not even between x1 and x2. It just says use the
+   * dash pattern aligned to the offset. So ensure x1 is smaller _x1
+   * and we start with the appropriate dash.
+   */
+  for (n = 0; n < num_dashes; n++)
+    len_sum += dashes[n];
+  if (   len_sum > 0 /* pathological api usage? */
+      && gcwin32->pen_dash_offset > a)
+    a -= (((gcwin32->pen_dash_offset/len_sum - a/len_sum) + 1) * len_sum);
+  else
+    a = gcwin32->pen_dash_offset;
+
+  return a;
+}
+/* Render a dashed line 'by hand'. Used for all dashes on Win9x (where
+ * GDI is way too limited), and for double dashes on all Windowses.
+ */
+static inline gboolean
+render_line_horizontal (GdkGCWin32 *gcwin32,
+                        int         x1,
+                        int         x2,
+                        int         y)
+{
+  int n = 0;
+  const int pen_width = MAX (gcwin32->pen_width, 1);
+  const int _x1 = x1;
+
+  g_assert (gcwin32->pen_dashes);
+
+  x1 = align_with_dash_offset (x1, gcwin32->pen_dashes, gcwin32->pen_num_dashes, gcwin32);
+
+  for (n = 0; x1 < x2; n++)
+    {
+      int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
+      if (x1 + len > x2)
+        len = x2 - x1;
+
+      if (n % 2 == 0 && x1 + len > _x1)
+        if (!GDI_CALL (PatBlt, (gcwin32->hdc, 
+                               x1 < _x1 ? _x1 : x1, 
+                               y - pen_width / 2, 
+                               len, pen_width, 
+                               rop2_to_patblt_rop (gcwin32->rop2))))
+         return FALSE;
+
+      x1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
+    }
+
+  if (gcwin32->line_style == GDK_LINE_DOUBLE_DASH)
+    {
+      HBRUSH hbr;
+
+      if ((hbr = SelectObject (gcwin32->hdc, gcwin32->pen_hbrbg)) == HGDI_ERROR)
+       return FALSE;
+      x1 = _x1;
+      x1 += gcwin32->pen_dash_offset;
+      for (n = 0; x1 < x2; n++)
+       {
+         int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
+         if (x1 + len > x2)
+           len = x2 - x1;
+
+         if (n % 2)
+           if (!GDI_CALL (PatBlt, (gcwin32->hdc, x1, y - pen_width / 2,
+                                   len, pen_width,
+                                   rop2_to_patblt_rop (gcwin32->rop2))))
+             return FALSE;
+
+         x1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
+       }
+      if (SelectObject (gcwin32->hdc, hbr) == HGDI_ERROR)
+       return FALSE;
+    }
+
+  return TRUE;
+}
+
+static inline gboolean
+render_line_vertical (GdkGCWin32 *gcwin32,
+                     int         x,
+                      int         y1,
+                      int         y2)
+{
+  int n;
+  const int pen_width = MAX (gcwin32->pen_width, 1);
+  const int _y1 = y1;
+
+  g_assert (gcwin32->pen_dashes);
+
+  y1 = align_with_dash_offset (y1, gcwin32->pen_dashes, gcwin32->pen_num_dashes, gcwin32);
+  for (n = 0; y1 < y2; n++)
+    {
+      int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
+      if (y1 + len > y2)
+        len = y2 - y1;
+      if (n % 2 == 0 && y1 + len > _y1)
+        if (!GDI_CALL (PatBlt, (gcwin32->hdc, x - pen_width / 2, 
+                               y1 < _y1 ? _y1 : y1, 
+                               pen_width, len, 
+                               rop2_to_patblt_rop (gcwin32->rop2))))
+         return FALSE;
+
+      y1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
+    }
+
+  if (gcwin32->line_style == GDK_LINE_DOUBLE_DASH)
+    {
+      HBRUSH hbr;
+
+      if ((hbr = SelectObject (gcwin32->hdc, gcwin32->pen_hbrbg)) == HGDI_ERROR)
+       return FALSE;
+      y1 = _y1;
+      y1 += gcwin32->pen_dash_offset;
+      for (n = 0; y1 < y2; n++)
+       {
+         int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
+         if (y1 + len > y2)
+           len = y2 - y1;
+         if (n % 2)
+           if (!GDI_CALL (PatBlt, (gcwin32->hdc, x - pen_width / 2, y1,
+                                   pen_width, len,
+                                   rop2_to_patblt_rop (gcwin32->rop2))))
+             return FALSE;
+
+         y1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
+       }
+      if (SelectObject (gcwin32->hdc, hbr) == HGDI_ERROR)
+       return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+draw_tiles_lowlevel (HDC  dest,
+                    HDC  tile,
+                    int  rop3,
+                    gint dest_x,
+                    gint dest_y,
+                    gint tile_x_origin,
+                    gint tile_y_origin,
+                    gint width,
+                    gint height,
+                    gint tile_width,
+                    gint tile_height)
+{
+  gint x, y;
+
+  GDK_NOTE (MISC, g_print ("draw_tiles_lowlevel: %p %+d%+d tile=%p:%dx%d@%+d%+d %dx%d\n",
+                          dest,
+                          dest_x, dest_y,
+                          tile, tile_width, tile_height,
+                          tile_x_origin, tile_y_origin,
+                          width, height));
+
+  y = tile_y_origin % tile_height;
+  if (y > 0)
+    y -= tile_height;
+  while (y < dest_y + height)
+    {
+      if (y + tile_height >= dest_y)
+       {
+         x = tile_x_origin % tile_width;
+         if (x > 0)
+           x -= tile_width;
+         while (x < dest_x + width)
+           {
+             if (x + tile_width >= dest_x)
+               {
+                 gint src_x = MAX (0, dest_x - x);
+                 gint src_y = MAX (0, dest_y - y);
+
+                 if (!GDI_CALL (BitBlt, (dest, x + src_x, y + src_y,
+                                         MIN (tile_width, dest_x + width - (x + src_x)),
+                                         MIN (tile_height, dest_y + height - (y + src_y)),
+                                         tile,
+                                         src_x, src_y,
+                                         rop3)))
+                   return;
+               }
+             x += tile_width;
+           }
+       }
+      y += tile_height;
+    }
+}
+
+static void
+draw_tiles (GdkDrawable *drawable,
+           GdkGC       *gc,
+           int          rop3,
+           GdkPixmap   *tile,
+           gint         dest_x,
+           gint         dest_y,
+           gint         tile_x_origin,
+           gint         tile_y_origin,
+           gint         width,
+           gint         height)
+{
+  const GdkGCValuesMask mask = GDK_GC_FOREGROUND;
+  gint tile_width, tile_height;
+  GdkGC *gc_copy;
+  HDC dest_hdc, tile_hdc;
+
+  gc_copy = gdk_gc_new (tile);
+  gdk_gc_copy (gc_copy, gc);
+  dest_hdc = gdk_win32_hdc_get (drawable, gc, mask);
+  tile_hdc = gdk_win32_hdc_get (tile, gc_copy, mask);
+
+  gdk_drawable_get_size (tile, &tile_width, &tile_height);
+
+  draw_tiles_lowlevel (dest_hdc, tile_hdc, rop3,
+                      dest_x, dest_y, tile_x_origin, tile_y_origin,
+                      width, height, tile_width, tile_height);
+
+  gdk_win32_hdc_release (drawable, gc, mask);
+  gdk_win32_hdc_release (tile, gc_copy, mask);
+  gdk_gc_unref (gc_copy);
+}
+
+static void
+generic_draw (GdkDrawable    *drawable,
+             GdkGC          *gc,
+             GdkGCValuesMask mask,
+             void (*function) (GdkGCWin32 *, HDC, gint, gint, va_list),
+             const GdkRegion *region,
+             ...)
+{
+  GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
+  GdkGCWin32 *gcwin32 = GDK_GC_WIN32 (gc);
+  HDC hdc;
+  va_list args;
+  GdkFill fill_style = _gdk_gc_get_fill (gc);
+
+  va_start (args, region);
+
+  /* If tiled or stippled, draw to a temp pixmap and do blitting magic.
+   */
+
+  if (gcwin32->values_mask & GDK_GC_FILL &&
+      ((fill_style == GDK_TILED &&
+       gcwin32->values_mask & GDK_GC_TILE &&
+       _gdk_gc_get_tile (gc) != NULL)
+       ||
+       ((fill_style == GDK_OPAQUE_STIPPLED ||
+        fill_style == GDK_STIPPLED) &&
+       gcwin32->values_mask & GDK_GC_STIPPLE &&
+       _gdk_gc_get_stipple (gc) != NULL)))
     {
-      if (GDK_IS_WINDOW (drawable))
+      const GdkGCValuesMask blitting_mask = 0;
+      GdkGCValuesMask drawing_mask = GDK_GC_FOREGROUND;
+      gint ts_x_origin = 0, ts_y_origin = 0;
+
+      gint width = region->extents.x2 - region->extents.x1;
+      gint height = region->extents.y2 - region->extents.y1;
+
+      GdkPixmap *mask_pixmap =
+       gdk_pixmap_new (drawable, width, height, 1);
+      GdkPixmap *tile_pixmap =
+       gdk_pixmap_new (drawable, width, height, -1);
+      GdkPixmap *stipple_bitmap = NULL;
+      GdkColor fg;
+      
+      GdkGC *mask_gc = gdk_gc_new (mask_pixmap);
+      GdkGC *tile_gc = gdk_gc_new (tile_pixmap);
+
+      HDC mask_hdc;
+      HDC tile_hdc;
+
+      HGDIOBJ old_mask_hbm;
+      HGDIOBJ old_tile_hbm;
+
+      GdkGCValues gcvalues;
+
+      hdc = gdk_win32_hdc_get (drawable, gc, blitting_mask);
+      tile_hdc = CreateCompatibleDC (hdc);
+
+      if (gcwin32->values_mask & GDK_GC_TS_X_ORIGIN)
+       ts_x_origin = gc->ts_x_origin;
+      if (gcwin32->values_mask & GDK_GC_TS_Y_ORIGIN)
+       ts_y_origin = gc->ts_y_origin;
+
+      ts_x_origin -= region->extents.x1;
+      ts_y_origin -= region->extents.y1;
+
+      /* Fill mask bitmap with zeros */
+      gdk_gc_set_function (mask_gc, GDK_CLEAR);
+      gdk_draw_rectangle (mask_pixmap, mask_gc, TRUE,
+                         0, 0, width, height);
+
+      /* Paint into mask bitmap, drawing ones */
+      gdk_gc_set_function (mask_gc, GDK_COPY);
+      fg.pixel = 1;
+      gdk_gc_set_foreground (mask_gc, &fg);
+
+      /* If the drawing function uses line attributes, set them as in
+       * the real GC.
+       */
+      if (mask & LINE_ATTRIBUTES)
+       {
+         gdk_gc_get_values (gc, &gcvalues);
+         if (gcvalues.line_width != 0 ||
+             gcvalues.line_style != GDK_LINE_SOLID ||
+             gcvalues.cap_style != GDK_CAP_BUTT ||
+             gcvalues.join_style != GDK_JOIN_MITER)
+           gdk_gc_set_line_attributes (mask_gc,
+                                       gcvalues.line_width,
+                                       gcvalues.line_style,
+                                       gcvalues.cap_style,
+                                       gcvalues.join_style);
+         drawing_mask |= LINE_ATTRIBUTES;
+       }
+
+      /* Ditto, if the drawing function draws text, set up for that. */
+      if (mask & GDK_GC_FONT)
+       drawing_mask |= GDK_GC_FONT;
+
+      mask_hdc = gdk_win32_hdc_get (mask_pixmap, mask_gc, drawing_mask);
+      (*function) (GDK_GC_WIN32 (mask_gc), mask_hdc,
+                  region->extents.x1, region->extents.y1, args);
+      gdk_win32_hdc_release (mask_pixmap, mask_gc, drawing_mask);
+
+      if (fill_style == GDK_TILED)
+       {
+         /* Tile pixmap with tile */
+         draw_tiles (tile_pixmap, tile_gc, SRCCOPY,
+                     _gdk_gc_get_tile (gc),
+                     0, 0, ts_x_origin, ts_y_origin,
+                     width, height);
+       }
+      else
+       {
+         /* Tile with stipple */
+         GdkGC *stipple_gc;
+
+         stipple_bitmap = gdk_pixmap_new (NULL, width, height, 1);
+         stipple_gc = gdk_gc_new (stipple_bitmap);
+
+         /* Tile stipple bitmap */
+         draw_tiles (stipple_bitmap, stipple_gc, SRCCOPY,
+                     _gdk_gc_get_stipple (gc),
+                     0, 0, ts_x_origin, ts_y_origin,
+                     width, height);
+
+         if (fill_style == GDK_OPAQUE_STIPPLED)
+           {
+             /* Fill tile pixmap with background */
+             fg.pixel = _gdk_gc_get_bg_pixel (gc);
+             gdk_gc_set_foreground (tile_gc, &fg);
+             gdk_draw_rectangle (tile_pixmap, tile_gc, TRUE,
+                                 0, 0, width, height);
+           }
+         gdk_gc_unref (stipple_gc);
+       }
+
+      gdk_gc_unref (mask_gc);
+      gdk_gc_unref (tile_gc);
+
+      mask_hdc = CreateCompatibleDC (hdc);
+
+      if ((old_mask_hbm = SelectObject (mask_hdc, GDK_PIXMAP_HBITMAP (mask_pixmap))) == NULL)
+       WIN32_GDI_FAILED ("SelectObject");
+
+      if ((old_tile_hbm = SelectObject (tile_hdc, GDK_PIXMAP_HBITMAP (tile_pixmap))) == NULL)
+       WIN32_GDI_FAILED ("SelectObject");
+
+      if (fill_style == GDK_STIPPLED ||
+         fill_style == GDK_OPAQUE_STIPPLED)
+       {
+         HDC stipple_hdc;
+         HGDIOBJ old_stipple_hbm;
+         HBRUSH fg_brush;
+         HGDIOBJ old_tile_brush;
+
+         if ((stipple_hdc = CreateCompatibleDC (hdc)) == NULL)
+           WIN32_GDI_FAILED ("CreateCompatibleDC");
+
+         if ((old_stipple_hbm =
+              SelectObject (stipple_hdc,
+                            GDK_PIXMAP_HBITMAP (stipple_bitmap))) == NULL)
+           WIN32_GDI_FAILED ("SelectObject");
+
+         if ((fg_brush = CreateSolidBrush
+              (_gdk_win32_colormap_color (impl->colormap,
+                                          _gdk_gc_get_fg_pixel (gc)))) == NULL)
+           WIN32_GDI_FAILED ("CreateSolidBrush");
+
+         if ((old_tile_brush = SelectObject (tile_hdc, fg_brush)) == NULL)
+           WIN32_GDI_FAILED ("SelectObject");
+
+         /* Paint tile with foreround where stipple is one
+          *
+          *  Desired ternary ROP: (P=foreground, S=stipple, D=destination)
+           *   P   S   D   ?
+           *   0   0   0   0
+           *   0   0   1   1
+           *   0   1   0   0
+           *   0   1   1   0
+           *   1   0   0   0
+           *   1   0   1   1
+           *   1   1   0   1
+           *   1   1   1   1
+          *
+          * Reading bottom-up: 11100010 = 0xE2. PSDK docs say this is
+          * known as DSPDxax, with hex value 0x00E20746.
+          */
+         GDI_CALL (BitBlt, (tile_hdc, 0, 0, width, height,
+                            stipple_hdc, 0, 0, ROP3_DSPDxax));
+
+         if (fill_style == GDK_STIPPLED)
+           {
+             /* Punch holes in mask where stipple is zero */
+             GDI_CALL (BitBlt, (mask_hdc, 0, 0, width, height,
+                                stipple_hdc, 0, 0, SRCAND));
+           }
+
+         GDI_CALL (SelectObject, (tile_hdc, old_tile_brush));
+         GDI_CALL (DeleteObject, (fg_brush));
+         GDI_CALL (SelectObject, (stipple_hdc, old_stipple_hbm));
+         GDI_CALL (DeleteDC, (stipple_hdc));
+         g_object_unref (stipple_bitmap);
+       }
+
+      /* Tile pixmap now contains the pattern that we should paint in
+       * the areas where mask is one. (It is filled with said pattern.)
+       */
+
+      if (G_WIN32_IS_NT_BASED ())
        {
-         g_return_if_fail (colormap_private->base.visual !=
-                           ((GdkColormapPrivate *) (drawable_private->colormap))->visual);
-         /* XXX ??? */
-         GDK_NOTE (MISC, g_print ("gdk_drawable_set_colormap: %#x %#x\n",
-                                  GDK_DRAWABLE_XID (drawable),
-                                  colormap_private->xcolormap));
+         GDI_CALL (MaskBlt, (hdc, region->extents.x1, region->extents.y1,
+                             width, height,
+                             tile_hdc, 0, 0,
+                             GDK_PIXMAP_HBITMAP (mask_pixmap), 0, 0,
+                             MAKEROP4 (rop2_to_rop3 (gcwin32->rop2), ROP3_D)));
+       }
+      else
+       {
+         GdkPixmap *temp1_pixmap =
+           gdk_pixmap_new (drawable, width, height, -1);
+         GdkPixmap *temp2_pixmap =
+           gdk_pixmap_new (drawable, width, height, -1);
+         HDC temp1_hdc = CreateCompatibleDC (hdc);
+         HDC temp2_hdc = CreateCompatibleDC (hdc);
+         HGDIOBJ old_temp1_hbm =
+           SelectObject (temp1_hdc, GDK_PIXMAP_HBITMAP (temp1_pixmap));
+         HGDIOBJ old_temp2_hbm =
+           SelectObject (temp2_hdc, GDK_PIXMAP_HBITMAP (temp2_pixmap));
+
+         /* Grab copy of dest region to temp1 */
+         GDI_CALL (BitBlt,(temp1_hdc, 0, 0, width, height,
+                           hdc, region->extents.x1, region->extents.y1, SRCCOPY));
+
+         /* Paint tile to temp1 using correct function */
+         GDI_CALL (BitBlt, (temp1_hdc, 0, 0, width, height,
+                            tile_hdc, 0, 0, rop2_to_rop3 (gcwin32->rop2)));
+
+         /* Mask out temp1 where function didn't paint */
+         GDI_CALL (BitBlt, (temp1_hdc, 0, 0, width, height,
+                            mask_hdc, 0, 0, SRCAND));
+
+         /* Grab another copy of dest region to temp2 */
+         GDI_CALL (BitBlt, (temp2_hdc, 0, 0, width, height,
+                            hdc, region->extents.x1, region->extents.y1, SRCCOPY));
+
+         /* Mask out temp2 where function did paint */
+         GDI_CALL (BitBlt, (temp2_hdc, 0, 0, width, height,
+                            mask_hdc, 0, 0, ROP3_DSna));
+
+         /* Combine temp1 with temp2 */
+         GDI_CALL (BitBlt, (temp2_hdc, 0, 0, width, height,
+                            temp1_hdc, 0, 0, SRCPAINT));
+
+         /* Blit back */
+         GDI_CALL (BitBlt, (hdc, region->extents.x1, region->extents.y1, width, height,
+                            temp2_hdc, 0, 0, SRCCOPY));
+
+         /* Cleanup */
+         GDI_CALL (SelectObject, (temp1_hdc, old_temp1_hbm));
+         GDI_CALL (SelectObject, (temp2_hdc, old_temp2_hbm));
+         GDI_CALL (DeleteDC, (temp1_hdc));
+         GDI_CALL (DeleteDC, (temp2_hdc));
+         g_object_unref (temp1_pixmap);
+         g_object_unref (temp2_pixmap);
        }
-      if (drawable_private->colormap)
-       gdk_colormap_unref (drawable_private->colormap);
-      drawable_private->colormap = colormap;
-      gdk_colormap_ref (drawable_private->colormap);
       
-      if (GDK_IS_WINDOW (drawable)
-         && drawable_private->window_type != GDK_WINDOW_TOPLEVEL)
-       gdk_window_add_colormap_windows (drawable);
+      /* Cleanup */
+      GDI_CALL (SelectObject, (mask_hdc, old_mask_hbm));
+      GDI_CALL (SelectObject, (tile_hdc, old_tile_hbm));
+      GDI_CALL (DeleteDC, (mask_hdc));
+      GDI_CALL (DeleteDC, (tile_hdc));
+      g_object_unref (mask_pixmap);
+      g_object_unref (tile_pixmap);
+
+      gdk_win32_hdc_release (drawable, gc, blitting_mask);
+    }
+  else
+    {
+      hdc = gdk_win32_hdc_get (drawable, gc, mask);
+      (*function) (gcwin32, hdc, 0, 0, args);
+      gdk_win32_hdc_release (drawable, gc, mask);
     }
+  va_end (args);
 }
 
-/* Drawing
- */
-static void 
-gdk_win32_drawable_destroy (GdkDrawable *drawable)
+static GdkRegion *
+widen_bounds (GdkRectangle *bounds,
+             gint          pen_width)
+{
+  if (pen_width == 0)
+    pen_width = 1;
+
+  bounds->x -= pen_width;
+  bounds->y -= pen_width;
+  bounds->width += 2 * pen_width;
+  bounds->height += 2 * pen_width;
+
+  return gdk_region_rectangle (bounds);
+}
+
+static void
+draw_rectangle (GdkGCWin32 *gcwin32,
+               HDC         hdc,
+               gint        x_offset,
+               gint        y_offset,
+               va_list     args)
 {
+  HGDIOBJ old_pen_or_brush;
+  gboolean filled;
+  gint x;
+  gint y;
+  gint width;
+  gint height;
+
+  filled = va_arg (args, gboolean);
+  x = va_arg (args, gint);
+  y = va_arg (args, gint);
+  width = va_arg (args, gint);
+  height = va_arg (args, gint);
   
+  x -= x_offset;
+  y -= y_offset;
+
+  if (!filled && MUST_RENDER_DASHES_MANUALLY (gcwin32))
+    {
+      render_line_vertical (gcwin32, x, y, y+height+1) &&
+      render_line_horizontal (gcwin32, x, x+width+1, y) &&
+      render_line_vertical (gcwin32, x+width+1, y, y+height+1) &&
+      render_line_horizontal (gcwin32, x, x+width+1, y+height+1);
+    }
+  else
+    {
+      if (filled)
+       old_pen_or_brush = SelectObject (hdc, GetStockObject (NULL_PEN));
+      else
+       old_pen_or_brush = SelectObject (hdc, GetStockObject (HOLLOW_BRUSH));
+      if (old_pen_or_brush == NULL)
+       WIN32_GDI_FAILED ("SelectObject");
+      else
+       GDI_CALL (Rectangle, (hdc, x, y, x+width+1, y+height+1));
+
+      if (old_pen_or_brush != NULL)
+       GDI_CALL (SelectObject, (hdc, old_pen_or_brush));
+    }
 }
 
 static void
 gdk_win32_draw_rectangle (GdkDrawable *drawable,
                          GdkGC       *gc,
-                         gint         filled,
+                         gboolean     filled,
                          gint         x,
                          gint         y,
                          gint         width,
                          gint         height)
 {
-  GdkGCPrivate *gc_private = (GdkGCPrivate*) gc;
-  GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private);
-  HDC hdc;
-  HGDIOBJ oldpen, oldbrush;
-  HBRUSH hbr = NULL;
-  POINT pts[4];
-  gboolean ok = TRUE;
+  GdkRectangle bounds;
+  GdkRegion *region;
 
-  GDK_NOTE (MISC, g_print ("gdk_win32_draw_rectangle: %#x (%d) %s%dx%d@+%d+%d\n",
-                          GDK_DRAWABLE_XID (drawable),
-                          gc_private,
+  GDK_NOTE (MISC, g_print ("gdk_win32_draw_rectangle: %s (%p) %s%dx%d@%+d%+d\n",
+                          _gdk_win32_drawable_description (drawable),
+                          gc,
                           (filled ? "fill " : ""),
                           width, height, x, y));
     
-  hdc = gdk_gc_predraw (drawable, gc_private,
-                       GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
-
-#if 0
-  {
-    HBRUSH hbr = GetCurrentObject (hdc, OBJ_BRUSH);
-    HPEN hpen = GetCurrentObject (hdc, OBJ_PEN);
-    LOGBRUSH lbr;
-    LOGPEN lpen;
-    GetObject (hbr, sizeof (lbr), &lbr);
-    GetObject (hpen, sizeof (lpen), &lpen);
-    
-    g_print ("current brush: style = %s, color = 0x%.08x\n",
-            (lbr.lbStyle == BS_SOLID ? "SOLID" : "???"),
-            lbr.lbColor);
-    g_print ("current pen: style = %s, width = %d, color = 0x%.08x\n",
-            (lpen.lopnStyle == PS_SOLID ? "SOLID" : "???"),
-            lpen.lopnWidth,
-            lpen.lopnColor);
-  }
-#endif
-
-  if (gc_data->fill_style == GDK_OPAQUE_STIPPLED)
-    {
-      if (!BeginPath (hdc))
-       WIN32_GDI_FAILED ("BeginPath"), ok = FALSE;
+  bounds.x = x;
+  bounds.y = y;
+  bounds.width = width;
+  bounds.height = height;
+  region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
+
+  generic_draw (drawable, gc,
+               GDK_GC_FOREGROUND | GDK_GC_BACKGROUND |
+               (filled ? 0 : LINE_ATTRIBUTES),
+               draw_rectangle, region, filled, x, y, width, height);
+
+  gdk_region_destroy (region);
+}
 
-      /* Win9x doesn't support Rectangle calls in a path,
-       * thus use Polyline.
-       */
-         
-      pts[0].x = x;
-      pts[0].y = y;
-      pts[1].x = x + width + 1;
-      pts[1].y = y;
-      pts[2].x = x + width + 1;
-      pts[2].y = y + height + 1;
-      pts[3].x = x;
-      pts[3].y = y + height + 1;
-      
-      if (ok)
-       MoveToEx (hdc, x, y, NULL);
-      
-      if (ok && !Polyline (hdc, pts, 4))
-       WIN32_GDI_FAILED ("Polyline"), ok = FALSE;
-         
-      if (ok && !CloseFigure (hdc))
-       WIN32_GDI_FAILED ("CloseFigure"), ok = FALSE;
+static void
+draw_arc (GdkGCWin32 *gcwin32,
+         HDC         hdc,
+         gint        x_offset,
+         gint        y_offset,
+         va_list     args)
+{
+  HGDIOBJ old_pen;
+  gboolean filled;
+  gint x, y;
+  gint width, height;
+  gint angle1, angle2;
+  int nXStartArc, nYStartArc, nXEndArc, nYEndArc;
 
-      if (ok && !EndPath (hdc))
-       WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
-         
-      if (ok && !filled)
-       if (!WidenPath (hdc))
-         WIN32_GDI_FAILED ("WidenPath"), ok = FALSE;
-         
-      if (ok && !FillPath (hdc))
-       WIN32_GDI_FAILED ("FillPath"), ok = FALSE;
+  filled = va_arg (args, gboolean);
+  x = va_arg (args, gint);
+  y = va_arg (args, gint);
+  width = va_arg (args, gint);
+  height = va_arg (args, gint);
+  angle1 = va_arg (args, gint);
+  angle2 = va_arg (args, gint);
 
-      if (hbr != NULL)
-       if (!DeleteObject (hbr))
-         WIN32_GDI_FAILED ("DeleteObject");
+  x -= x_offset;
+  y -= y_offset;
+  
+  if (angle2 >= 360*64)
+    {
+      nXStartArc = nYStartArc = nXEndArc = nYEndArc = 0;
+    }
+  else if (angle2 > 0)
+    {
+      nXStartArc = x + width/2 + width * cos(angle1/64.*2.*G_PI/360.);
+      nYStartArc = y + height/2 + -height * sin(angle1/64.*2.*G_PI/360.);
+      nXEndArc = x + width/2 + width * cos((angle1+angle2)/64.*2.*G_PI/360.);
+      nYEndArc = y + height/2 + -height * sin((angle1+angle2)/64.*2.*G_PI/360.);
     }
   else
     {
-      if (filled)
-       oldpen = SelectObject (hdc, GetStockObject (NULL_PEN));
-      else
-       oldbrush = SelectObject (hdc, GetStockObject (HOLLOW_BRUSH));
-  
-      if (!Rectangle (hdc, x, y, x+width+1, y+height+1))
-       WIN32_GDI_FAILED ("Rectangle");
+      nXEndArc = x + width/2 + width * cos(angle1/64.*2.*G_PI/360.);
+      nYEndArc = y + height/2 + -height * sin(angle1/64.*2.*G_PI/360.);
+      nXStartArc = x + width/2 + width * cos((angle1+angle2)/64.*2.*G_PI/360.);
+      nYStartArc = y + height/2 + -height * sin((angle1+angle2)/64.*2.*G_PI/360.);
+    }
   
-      if (filled)
-       SelectObject (hdc, oldpen);
-      else
-       SelectObject (hdc, oldbrush);
+  if (filled)
+    {
+      old_pen = SelectObject (hdc, GetStockObject (NULL_PEN));
+      GDK_NOTE (MISC, g_print ("... Pie(%p,%d,%d,%d,%d,%d,%d,%d,%d)\n",
+                              hdc, x, y, x+width, y+height,
+                              nXStartArc, nYStartArc, nXEndArc, nYEndArc));
+      GDI_CALL (Pie, (hdc, x, y, x+width, y+height,
+                     nXStartArc, nYStartArc, nXEndArc, nYEndArc));
+      GDI_CALL (SelectObject, (hdc, old_pen));
+    }
+  else
+    {
+      GDK_NOTE (MISC, g_print ("... Arc(%p,%d,%d,%d,%d,%d,%d,%d,%d)\n",
+                              hdc, x, y, x+width, y+height,
+                              nXStartArc, nYStartArc, nXEndArc, nYEndArc));
+      GDI_CALL (Arc, (hdc, x, y, x+width, y+height,
+                     nXStartArc, nYStartArc, nXEndArc, nYEndArc));
     }
-
-  gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
 }
 
 static void
 gdk_win32_draw_arc (GdkDrawable *drawable,
                    GdkGC       *gc,
-                   gint         filled,
+                   gboolean     filled,
                    gint         x,
                    gint         y,
                    gint         width,
@@ -293,160 +962,129 @@ gdk_win32_draw_arc (GdkDrawable *drawable,
                    gint         angle1,
                    gint         angle2)
 {
-  GdkGCPrivate *gc_private;
-  HDC hdc;
-  int nXStartArc, nYStartArc, nXEndArc, nYEndArc;
-
-  gc_private = (GdkGCPrivate*) gc;
+  GdkRectangle bounds;
+  GdkRegion *region;
 
-  GDK_NOTE (MISC, g_print ("gdk_draw_arc: %#x  %d,%d,%d,%d  %d %d\n",
-                          GDK_DRAWABLE_XID (drawable),
+  GDK_NOTE (MISC, g_print ("gdk_win32_draw_arc: %s  %d,%d,%d,%d  %d %d\n",
+                          _gdk_win32_drawable_description (drawable),
                           x, y, width, height, angle1, angle2));
 
-  if (width != 0 && height != 0 && angle2 != 0)
-    {
-      hdc = gdk_gc_predraw (drawable, gc_private,
-                           GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
+  if (width <= 2 || height <= 2 || angle2 == 0)
+    return;
 
-      if (angle2 >= 360*64)
-       {
-         nXStartArc = nYStartArc = nXEndArc = nYEndArc = 0;
-       }
-      else if (angle2 > 0)
-       {
-         /* The 100. is just an arbitrary value */
-         nXStartArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.);
-         nYStartArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.);
-         nXEndArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.);
-         nYEndArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.);
-       }
-      else
-       {
-         nXEndArc = x + width/2 + 100. * cos(angle1/64.*2.*G_PI/360.);
-         nYEndArc = y + height/2 + -100. * sin(angle1/64.*2.*G_PI/360.);
-         nXStartArc = x + width/2 + 100. * cos((angle1+angle2)/64.*2.*G_PI/360.);
-         nYStartArc = y + height/2 + -100. * sin((angle1+angle2)/64.*2.*G_PI/360.);
-       }
+  bounds.x = x;
+  bounds.y = y;
+  bounds.width = width;
+  bounds.height = height;
+  region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
 
-      /* GDK_OPAQUE_STIPPLED arcs not implemented. */
+  generic_draw (drawable, gc,
+               GDK_GC_FOREGROUND | (filled ? 0 : LINE_ATTRIBUTES),
+               draw_arc, region, filled, x, y, width, height, angle1, angle2);
 
-      if (filled)
-       {
-         GDK_NOTE (MISC, g_print ("...Pie(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n",
-                                  x, y, x+width, y+height,
-                                  nXStartArc, nYStartArc,
-                                  nXEndArc, nYEndArc));
-         if (!Pie (hdc, x, y, x+width, y+height,
-                   nXStartArc, nYStartArc, nXEndArc, nYEndArc))
-           WIN32_GDI_FAILED ("Pie");
-       }
-      else
-       {
-         GDK_NOTE (MISC, g_print ("...Arc(hdc,%d,%d,%d,%d,%d,%d,%d,%d)\n",
-                                  x, y, x+width, y+height,
-                                  nXStartArc, nYStartArc,
-                                  nXEndArc, nYEndArc));
-         if (!Arc (hdc, x, y, x+width, y+height,
-                   nXStartArc, nYStartArc, nXEndArc, nYEndArc))
-           WIN32_GDI_FAILED ("Arc");
-       }
-      gdk_gc_postdraw (drawable, gc_private,
-                      GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
+  gdk_region_destroy (region);
+}
+
+static void
+draw_polygon (GdkGCWin32 *gcwin32,
+             HDC         hdc,
+             gint        x_offset,
+             gint        y_offset,
+             va_list     args)
+{
+  gboolean filled;
+  POINT *pts;
+  HPEN old_pen;
+  gint npoints;
+  gint i;
+
+  filled = va_arg (args, gboolean);
+  pts = va_arg (args, POINT *);
+  npoints = va_arg (args, gint);
+
+  if (x_offset != 0 || y_offset != 0)
+    for (i = 0; i < npoints; i++)
+      {
+       pts[i].x -= x_offset;
+       pts[i].y -= y_offset;
+      }
+
+  if (filled)
+    {
+      old_pen = SelectObject (hdc, GetStockObject (NULL_PEN));
+      if (old_pen == NULL)
+       WIN32_GDI_FAILED ("SelectObject");
+      GDI_CALL (Polygon, (hdc, pts, npoints));
+      if (old_pen != NULL)
+       GDI_CALL (SelectObject, (hdc, old_pen));
     }
+  else
+    GDI_CALL (Polyline, (hdc, pts, npoints));
 }
 
 static void
 gdk_win32_draw_polygon (GdkDrawable *drawable,
                        GdkGC       *gc,
-                       gint         filled,
+                       gboolean     filled,
                        GdkPoint    *points,
                        gint         npoints)
 {
-  GdkGCPrivate *gc_private = (GdkGCPrivate*) gc;
-  GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private);
-  HDC hdc;
-  HBRUSH hbr = NULL;
+  GdkRectangle bounds;
+  GdkRegion *region;
   POINT *pts;
-  gboolean ok = TRUE;
   int i;
 
-  GDK_NOTE (MISC, g_print ("gdk_win32_draw_polygon: %#x (%d) %d\n",
-                          GDK_DRAWABLE_XID (drawable), gc_private,
+  GDK_NOTE (MISC, g_print ("gdk_win32_draw_polygon: %s %d points\n",
+                          _gdk_win32_drawable_description (drawable),
                           npoints));
 
   if (npoints < 2)
     return;
 
-  hdc = gdk_gc_predraw (drawable, gc_private,
-                       GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
+  bounds.x = G_MAXINT;
+  bounds.y = G_MAXINT;
+  bounds.width = 0;
+  bounds.height = 0;
+
   pts = g_new (POINT, npoints+1);
 
   for (i = 0; i < npoints; i++)
     {
+      bounds.x = MIN (bounds.x, points[i].x);
+      bounds.y = MIN (bounds.y, points[i].y);
       pts[i].x = points[i].x;
       pts[i].y = points[i].y;
     }
-  
-  if (gc_data->fill_style == GDK_OPAQUE_STIPPLED)
+
+  for (i = 0; i < npoints; i++)
     {
-      if (!BeginPath (hdc))
-       WIN32_GDI_FAILED ("BeginPath"), ok = FALSE;
+      bounds.width = MAX (bounds.width, points[i].x - bounds.x);
+      bounds.height = MAX (bounds.height, points[i].y - bounds.y);
+    }
 
-      MoveToEx (hdc, points[0].x, points[0].y, NULL);
+  if (points[0].x != points[npoints-1].x ||
+      points[0].y != points[npoints-1].y) 
+    {
+      pts[npoints].x = points[0].x;
+      pts[npoints].y = points[0].y;
+      npoints++;
+    }
+      
+  region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
 
-      if (pts[0].x == pts[npoints-1].x && pts[0].y == pts[npoints-1].y)
-       npoints--;
+  generic_draw (drawable, gc,
+               GDK_GC_FOREGROUND | (filled ? 0 : LINE_ATTRIBUTES),
+               draw_polygon, region, filled, pts, npoints);
 
-      if (ok && !Polyline (hdc, pts, 4))
-       WIN32_GDI_FAILED ("Polyline"), ok = FALSE;
-         
-      if (ok && !CloseFigure (hdc))
-       WIN32_GDI_FAILED ("CloseFigure"), ok = FALSE;
+  gdk_region_destroy (region);
+  g_free (pts);
+}
 
-      if (ok && !EndPath (hdc))
-       WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
-         
-      if (ok && !filled)
-       if (!WidenPath (hdc))
-         WIN32_GDI_FAILED ("WidenPath"), ok = FALSE;
-         
-      if (ok && !FillPath (hdc))
-       WIN32_GDI_FAILED ("FillPath"), ok = FALSE;
-
-      if (hbr != NULL)
-       if (!DeleteObject (hbr))
-         WIN32_GDI_FAILED ("DeleteObject");
-    }
-  else
-    {
-      if (points[0].x != points[npoints-1].x
-         || points[0].y != points[npoints-1].y) 
-       {
-         pts[npoints].x = points[0].x;
-         pts[npoints].y = points[0].y;
-         npoints++;
-       }
-      
-      if (filled)
-       {
-         if (!Polygon (hdc, pts, npoints))
-           WIN32_GDI_FAILED ("Polygon");
-       }
-      else
-       {
-         if (!Polyline (hdc, pts, npoints))
-           WIN32_GDI_FAILED ("Polyline");
-       }
-    }
-  g_free (pts);
-  gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
-}
-
-typedef struct
-{
-  gint x, y;
-  HDC hdc;
-} gdk_draw_text_arg;
+typedef struct
+{
+  gint x, y;
+  HDC hdc;
+} gdk_draw_text_arg;
 
 static void
 gdk_draw_text_handler (GdkWin32SingleFont *singlefont,
@@ -461,7 +1099,7 @@ gdk_draw_text_handler (GdkWin32SingleFont *singlefont,
   if (!singlefont)
     return;
 
-  if ((oldfont = SelectObject (argp->hdc, singlefont->xfont)) == NULL)
+  if ((oldfont = SelectObject (argp->hdc, singlefont->hfont)) == NULL)
     {
       WIN32_GDI_FAILED ("SelectObject");
       return;
@@ -484,43 +1122,40 @@ gdk_win32_draw_text (GdkDrawable *drawable,
                     const gchar *text,
                     gint         text_length)
 {
-  GdkGCPrivate *gc_private;
-  wchar_t *wcstr;
-  gint wlen;
+  const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_FONT;
+  wchar_t *wcstr, wc;
+  glong wlen;
   gdk_draw_text_arg arg;
 
-
-  if (GDK_DRAWABLE_DESTROYED (drawable))
-    return;
-
   if (text_length == 0)
     return;
 
   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
 
-  gc_private = (GdkGCPrivate*) gc;
-
   arg.x = x;
   arg.y = y;
-  arg.hdc = gdk_gc_predraw (drawable, gc_private,
-                           GDK_GC_FOREGROUND|GDK_GC_FONT);
+  arg.hdc = gdk_win32_hdc_get (drawable, gc, mask);
 
-  GDK_NOTE (MISC, g_print ("gdk_draw_text: %#x (%d,%d) \"%.*s\" (len %d)\n",
-                          GDK_DRAWABLE_XID (drawable),
+  GDK_NOTE (MISC, g_print ("gdk_win32_draw_text: %s (%d,%d) \"%.*s\" (len %d)\n",
+                          _gdk_win32_drawable_description (drawable),
                           x, y,
                           (text_length > 10 ? 10 : text_length),
                           text, text_length));
   
-  wcstr = g_new (wchar_t, text_length);
-  if ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1)
-    g_warning ("gdk_draw_text: gdk_nmbstowchar_ts failed");
+  if (text_length == 1)
+    {
+      /* For single characters, don't try to interpret as UTF-8. */
+      wc = (guchar) text[0];
+      _gdk_wchar_text_handle (font, &wc, 1, gdk_draw_text_handler, &arg);
+    }
   else
-    gdk_wchar_text_handle (font, wcstr, wlen,
-                          gdk_draw_text_handler, &arg);
-
-  g_free (wcstr);
+    {
+      wcstr = g_utf8_to_utf16 (text, text_length, NULL, &wlen, NULL);
+      _gdk_wchar_text_handle (font, wcstr, wlen, gdk_draw_text_handler, &arg);
+      g_free (wcstr);
+    }
 
-  gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_FONT);
+  gdk_win32_hdc_release (drawable, gc, mask);
 }
 
 static void
@@ -532,29 +1167,22 @@ gdk_win32_draw_text_wc (GdkDrawable       *drawable,
                        const GdkWChar *text,
                        gint              text_length)
 {
-  GdkGCPrivate *gc_private;
-  gint i, wlen;
+  const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_FONT;
+  gint i;
   wchar_t *wcstr;
   gdk_draw_text_arg arg;
 
-
-  if (GDK_DRAWABLE_DESTROYED (drawable))
-    return;
-
   if (text_length == 0)
     return;
 
   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
 
-  gc_private = (GdkGCPrivate*) gc;
-
   arg.x = x;
   arg.y = y;
-  arg.hdc = gdk_gc_predraw (drawable, gc_private,
-                           GDK_GC_FOREGROUND|GDK_GC_FONT);
+  arg.hdc = gdk_win32_hdc_get (drawable, gc, mask);
 
-  GDK_NOTE (MISC, g_print ("gdk_draw_text_wc: %#x (%d,%d) len: %d\n",
-                          GDK_DRAWABLE_XID (drawable),
+  GDK_NOTE (MISC, g_print ("gdk_win32_draw_text_wc: %s (%d,%d) len: %d\n",
+                          _gdk_win32_drawable_description (drawable),
                           x, y, text_length));
       
   if (sizeof (wchar_t) != sizeof (GdkWChar))
@@ -566,13 +1194,13 @@ gdk_win32_draw_text_wc (GdkDrawable       *drawable,
   else
     wcstr = (wchar_t *) text;
 
-  gdk_wchar_text_handle (font, wcstr, text_length,
+  _gdk_wchar_text_handle (font, wcstr, text_length,
                         gdk_draw_text_handler, &arg);
 
   if (sizeof (wchar_t) != sizeof (GdkWChar))
     g_free (wcstr);
 
-  gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_FONT);
+  gdk_win32_hdc_release (drawable, gc, mask);
 }
 
 static void
@@ -586,290 +1214,777 @@ gdk_win32_draw_drawable (GdkDrawable *drawable,
                         gint         width,
                         gint         height)
 {
-  GdkDrawablePrivate *src_private;
-  GdkGCPrivate *gc_private;
+  g_assert (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable));
+
+  _gdk_win32_blit (FALSE, (GdkDrawableImplWin32 *) drawable,
+                  gc, src, xsrc, ysrc,
+                  xdest, ydest, width, height);
+}
+
+static void
+gdk_win32_draw_points (GdkDrawable *drawable,
+                      GdkGC       *gc,
+                      GdkPoint    *points,
+                      gint         npoints)
+{
   HDC hdc;
-  HDC srcdc;
-  HGDIOBJ hgdiobj;
-  HRGN src_rgn, draw_rgn, outside_rgn;
-  RECT r;
+  HGDIOBJ old_pen;
+  int i;
 
-  src_private = (GdkDrawablePrivate*) src;
-  gc_private = (GdkGCPrivate*) gc;
+  hdc = gdk_win32_hdc_get (drawable, gc, GDK_GC_FOREGROUND);
+  
+  GDK_NOTE (MISC, g_print ("gdk_win32_draw_points: %s %d points\n",
+                          _gdk_win32_drawable_description (drawable),
+                          npoints));
 
-  GDK_NOTE (MISC, g_print ("gdk_draw_pixmap: dest: %#x "
-                          "src: %#x %dx%d@+%d+%d"
-                          " dest: %#x @+%d+%d\n",
-                          GDK_DRAWABLE_XID (drawable),
-                          GDK_DRAWABLE_XID (src),
-                          width, height, xsrc, ysrc,
-                          GDK_DRAWABLE_XID (drawable), xdest, ydest));
+  /* The X11 version uses XDrawPoint(), which doesn't use the fill
+   * mode, so don't use generic_draw. But we should use the current
+   * function, so we can't use SetPixel(). Draw single-pixel
+   * rectangles (sigh).
+   */
 
-  hdc = gdk_gc_predraw (drawable, gc_private, 0);
+  old_pen = SelectObject (hdc, GetStockObject (NULL_PEN));
+  for (i = 0; i < npoints; i++)
+    Rectangle (hdc, points[i].x, points[i].y,
+              points[i].x + 2, points[i].y + 2);
 
-  src_rgn = CreateRectRgn (0, 0, src_private->width + 1, src_private->height + 1);
-  draw_rgn = CreateRectRgn (xsrc, ysrc, xsrc + width + 1, ysrc + height + 1);
-  SetRectEmpty (&r);
-  outside_rgn = CreateRectRgnIndirect (&r);
-  
-  if (GDK_DRAWABLE_TYPE (drawable) != GDK_DRAWABLE_PIXMAP)
+  SelectObject (hdc, old_pen);
+  gdk_win32_hdc_release (drawable, gc, GDK_GC_FOREGROUND);
+}
+
+static void
+draw_segments (GdkGCWin32 *gcwin32,
+              HDC         hdc,
+              gint        x_offset,
+              gint        y_offset,
+              va_list     args)
+{
+  GdkSegment *segs;
+  gint nsegs;
+  gint i;
+
+  segs = va_arg (args, GdkSegment *);
+  nsegs = va_arg (args, gint);
+
+  if (x_offset != 0 || y_offset != 0)
     {
-      /* If we are drawing on a window, calculate the region that is
-       * outside the source pixmap, and invalidate that, causing it to
-       * be cleared. XXX
-       */
-      if (CombineRgn (outside_rgn, draw_rgn, src_rgn, RGN_DIFF) != NULLREGION)
+      /* must not modify in place, but could splice in the offset all below */
+      segs = g_memdup (segs, nsegs * sizeof (GdkSegment));
+      for (i = 0; i < nsegs; i++)
+        {
+          segs[i].x1 -= x_offset;
+          segs[i].y1 -= y_offset;
+          segs[i].x2 -= x_offset;
+          segs[i].y2 -= y_offset;
+        }
+    }
+
+  if (MUST_RENDER_DASHES_MANUALLY (gcwin32))
+    {
+      for (i = 0; i < nsegs; i++)
+       {
+         if (segs[i].x1 == segs[i].x2)
+           {
+             int y1, y2;
+             
+             if (segs[i].y1 <= segs[i].y2)
+               y1 = segs[i].y1, y2 = segs[i].y2;
+             else
+               y1 = segs[i].y2, y2 = segs[i].y1;
+             
+             render_line_vertical (gcwin32, segs[i].x1, y1, y2);
+           }
+         else if (segs[i].y1 == segs[i].y2)
+           {
+             int x1, x2;
+             
+             if (segs[i].x1 <= segs[i].x2)
+               x1 = segs[i].x1, x2 = segs[i].x2;
+             else
+               x1 = segs[i].x2, x2 = segs[i].x1;
+             
+             render_line_horizontal (gcwin32, x1, x2, segs[i].y1);
+           }
+         else
+           GDI_CALL (MoveToEx, (hdc, segs[i].x1, segs[i].y1, NULL)) &&
+             GDI_CALL (LineTo, (hdc, segs[i].x2, segs[i].y2));
+       }
+    }
+  else
+    {
+      for (i = 0; i < nsegs; i++)
        {
-         OffsetRgn (outside_rgn, xdest, ydest);
-         GDK_NOTE (MISC, (GetRgnBox (outside_rgn, &r),
-                          g_print ("...calling InvalidateRgn, "
-                                   "bbox: %dx%d@+%d+%d\n",
-                                   r.right - r.left - 1, r.bottom - r.top - 1,
-                                   r.left, r.top)));
-         InvalidateRgn (GDK_DRAWABLE_XID (drawable), outside_rgn, TRUE);
+         const GdkSegment *ps = &segs[i];
+         const int x1 = ps->x1, y1 = ps->y1;
+         int x2 = ps->x2, y2 = ps->y2;
+
+         GDK_NOTE (MISC, g_print (" +%d+%d..+%d+%d", x1, y1, x2, y2));
+         GDI_CALL (MoveToEx, (hdc, x1, y1, NULL)) &&
+           GDI_CALL (LineTo, (hdc, x2, y2));
        }
+
+      GDK_NOTE (MISC, g_print ("\n"));
     }
+  if (x_offset != 0 || y_offset != 0)
+    g_free (segs);
+}
+
+static void
+gdk_win32_draw_segments (GdkDrawable *drawable,
+                        GdkGC       *gc,
+                        GdkSegment  *segs,
+                        gint         nsegs)
+{
+  GdkRectangle bounds;
+  GdkRegion *region;
+  gint i;
 
-#if 1 /* Don't know if this is necessary  */
-  if (CombineRgn (draw_rgn, draw_rgn, src_rgn, RGN_AND) == COMPLEXREGION)
-    g_warning ("gdk_draw_pixmap: CombineRgn returned a COMPLEXREGION");
+  GDK_NOTE (MISC, g_print ("gdk_win32_draw_segments: %s %d segs\n",
+                          _gdk_win32_drawable_description (drawable),
+                          nsegs));
 
-  GetRgnBox (draw_rgn, &r);
-  if (r.left != xsrc
-      || r.top != ysrc
-      || r.right != xsrc + width + 1
-      || r.bottom != ysrc + height + 1)
+  bounds.x = G_MAXINT;
+  bounds.y = G_MAXINT;
+  bounds.width = 0;
+  bounds.height = 0;
+
+  for (i = 0; i < nsegs; i++)
     {
-      xdest += r.left - xsrc;
-      xsrc = r.left;
-      ydest += r.top - ysrc;
-      ysrc = r.top;
-      width = r.right - xsrc - 1;
-      height = r.bottom - ysrc - 1;
-      
-      GDK_NOTE (MISC, g_print ("... restricted to src: %dx%d@+%d+%d, "
-                              "dest: @+%d+%d\n",
-                              width, height, xsrc, ysrc,
-                              xdest, ydest));
+      bounds.x = MIN (bounds.x, segs[i].x1);
+      bounds.x = MIN (bounds.x, segs[i].x2);
+      bounds.y = MIN (bounds.y, segs[i].y1);
+      bounds.y = MIN (bounds.y, segs[i].y2);
     }
-#endif
 
-  DeleteObject (src_rgn);
-  DeleteObject (draw_rgn);
-  DeleteObject (outside_rgn);
+  for (i = 0; i < nsegs; i++)
+    {
+      bounds.width = MAX (bounds.width, segs[i].x1 - bounds.x);
+      bounds.width = MAX (bounds.width, segs[i].x2 - bounds.x);
+      bounds.height = MAX (bounds.height, segs[i].y1 - bounds.y);
+      bounds.height = MAX (bounds.height, segs[i].y2 - bounds.y);
+    }
 
-  /* Strangely enough, this function is called also to bitblt
-   * from a window.
-   */
-  if (src_private->window_type == GDK_DRAWABLE_PIXMAP)
+  region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
+
+  generic_draw (drawable, gc, GDK_GC_FOREGROUND | LINE_ATTRIBUTES,
+               draw_segments, region, segs, nsegs);
+
+  gdk_region_destroy (region);
+}
+
+static void
+draw_lines (GdkGCWin32 *gcwin32,
+           HDC         hdc,
+           gint        x_offset,
+           gint        y_offset,
+           va_list     args)
+{
+  POINT *pts;
+  gint npoints;
+  gint i;
+
+  pts = va_arg (args, POINT *);
+  npoints = va_arg (args, gint);
+
+  if (x_offset != 0 || y_offset != 0)
+    for (i = 0; i < npoints; i++)
+      {
+       pts[i].x -= x_offset;
+       pts[i].y -= y_offset;
+      }
+  
+  if (MUST_RENDER_DASHES_MANUALLY (gcwin32))
     {
-      if ((srcdc = CreateCompatibleDC (hdc)) == NULL)
-       WIN32_GDI_FAILED ("CreateCompatibleDC");
-      
-      if ((hgdiobj = SelectObject (srcdc, GDK_DRAWABLE_XID (src))) == NULL)
-       WIN32_GDI_FAILED ("SelectObject");
-      
-      if (!BitBlt (hdc, xdest, ydest, width, height,
-                  srcdc, xsrc, ysrc, SRCCOPY))
-       WIN32_GDI_FAILED ("BitBlt");
-      
-      if ((SelectObject (srcdc, hgdiobj) == NULL))
-       WIN32_GDI_FAILED ("SelectObject");
-      
-      if (!DeleteDC (srcdc))
-       WIN32_GDI_FAILED ("DeleteDC");
+      for (i = 0; i < npoints - 1; i++)
+        {
+         if (pts[i].x == pts[i+1].x)
+           {
+             int y1, y2;
+             if (pts[i].y > pts[i+1].y)
+               y1 = pts[i+1].y, y2 = pts[i].y;
+             else
+               y1 = pts[i].y, y2 = pts[i+1].y;
+             
+             render_line_vertical (gcwin32, pts[i].x, y1, y2);
+           }
+         else if (pts[i].y == pts[i+1].y)
+           {
+             int x1, x2;
+             if (pts[i].x > pts[i+1].x)
+               x1 = pts[i+1].x, x2 = pts[i].x;
+             else
+               x1 = pts[i].x, x2 = pts[i+1].x;
+
+             render_line_horizontal (gcwin32, x1, x2, pts[i].y);
+           }
+         else
+           GDI_CALL (MoveToEx, (hdc, pts[i].x, pts[i].y, NULL)) &&
+             GDI_CALL (LineTo, (hdc, pts[i+1].x, pts[i+1].y));
+       }
     }
   else
+    GDI_CALL (Polyline, (hdc, pts, npoints));
+}
+
+static void
+gdk_win32_draw_lines (GdkDrawable *drawable,
+                     GdkGC       *gc,
+                     GdkPoint    *points,
+                     gint         npoints)
+{
+  GdkRectangle bounds;
+  GdkRegion *region;
+  POINT *pts;
+  int i;
+
+  GDK_NOTE (MISC, g_print ("gdk_win32_draw_lines: %s %d points\n",
+                          _gdk_win32_drawable_description (drawable),
+                          npoints));
+
+  if (npoints < 2)
+    return;
+
+  bounds.x = G_MAXINT;
+  bounds.y = G_MAXINT;
+  bounds.width = 0;
+  bounds.height = 0;
+
+  pts = g_new (POINT, npoints);
+
+  for (i = 0; i < npoints; i++)
     {
-      if (GDK_DRAWABLE_XID(drawable) == GDK_DRAWABLE_XID (src))
+      bounds.x = MIN (bounds.x, points[i].x);
+      bounds.y = MIN (bounds.y, points[i].y);
+      pts[i].x = points[i].x;
+      pts[i].y = points[i].y;
+    }
+
+  for (i = 0; i < npoints; i++)
+    {
+      bounds.width = MAX (bounds.width, points[i].x - bounds.x);
+      bounds.height = MAX (bounds.height, points[i].y - bounds.y);
+    }
+
+  region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
+
+  generic_draw (drawable, gc, GDK_GC_FOREGROUND | GDK_GC_BACKGROUND |
+                             LINE_ATTRIBUTES,
+               draw_lines, region, pts, npoints);
+
+  gdk_region_destroy (region);
+  g_free (pts);
+}
+
+static void
+blit_from_pixmap (gboolean              use_fg_bg,
+                 GdkDrawableImplWin32 *dest,
+                 HDC                   hdc,
+                 GdkPixmapImplWin32   *src,
+                 GdkGC                *gc,
+                 gint                  xsrc,
+                 gint                  ysrc,
+                 gint                  xdest,
+                 gint                  ydest,
+                 gint                  width,
+                 gint                  height)
+{
+  GdkGCWin32 *gcwin32 = GDK_GC_WIN32 (gc);
+  HDC srcdc;
+  HBITMAP holdbitmap;
+  RGBQUAD oldtable[256], newtable[256];
+  COLORREF bg, fg;
+
+  gint newtable_size = 0, oldtable_size = 0;
+  gboolean ok = TRUE;
+  
+  GDK_NOTE (MISC, g_print ("blit_from_pixmap\n"));
+
+  srcdc = _gdk_win32_drawable_acquire_dc (GDK_DRAWABLE (src));
+  if (!srcdc)
+    return;
+  
+  if (!(holdbitmap = SelectObject (srcdc, ((GdkDrawableImplWin32 *) src)->handle)))
+    WIN32_GDI_FAILED ("SelectObject");
+  else
+    {
+      if (GDK_PIXMAP_OBJECT (src->parent_instance.wrapper)->depth <= 8)
        {
-         /* Blitting inside a window, use ScrollDC */
-         RECT scrollRect, clipRect, emptyRect;
-         HRGN updateRgn;
-
-         scrollRect.left = MIN (xsrc, xdest);
-         scrollRect.top = MIN (ysrc, ydest);
-         scrollRect.right = MAX (xsrc + width + 1, xdest + width + 1);
-         scrollRect.bottom = MAX (ysrc + height + 1, ydest + height + 1);
-
-         clipRect.left = xdest;
-         clipRect.top = ydest;
-         clipRect.right = xdest + width + 1;
-         clipRect.bottom = ydest + height + 1;
-
-         SetRectEmpty (&emptyRect);
-         updateRgn = CreateRectRgnIndirect (&emptyRect);
-         if (!ScrollDC (hdc, xdest - xsrc, ydest - ysrc,
-                        &scrollRect, &clipRect,
-                        updateRgn, NULL))
-           WIN32_GDI_FAILED ("ScrollDC");
-         if (!InvalidateRgn (GDK_DRAWABLE_XID (drawable), updateRgn, FALSE))
-           WIN32_GDI_FAILED ("InvalidateRgn");
-         if (!UpdateWindow (GDK_DRAWABLE_XID (drawable)))
-           WIN32_GDI_FAILED ("UpdateWindow");
+         /* Blitting from a 1, 4 or 8-bit pixmap */
+
+         if ((oldtable_size = GetDIBColorTable (srcdc, 0, 256, oldtable)) == 0)
+           WIN32_GDI_FAILED ("GetDIBColorTable");
+         else if (GDK_PIXMAP_OBJECT (src->parent_instance.wrapper)->depth == 1)
+           {
+             /* Blitting from an 1-bit pixmap */
+
+             gint bgix, fgix;
+             
+             if (use_fg_bg)
+               {
+                 bgix = _gdk_gc_get_bg_pixel (gc);
+                 fgix = _gdk_gc_get_fg_pixel (gc);
+               }
+             else
+               {
+                 bgix = 0;
+                 fgix = 1;
+               }
+             
+             if (GDK_IS_PIXMAP_IMPL_WIN32 (dest) &&
+                 GDK_PIXMAP_OBJECT (dest->wrapper)->depth <= 8)
+               {
+                 /* Destination is also pixmap, get fg and bg from
+                  * its palette. Either use the foreground and
+                  * background pixel values in the GC (only in the
+                  * case of gdk_image_put(), cf. XPutImage()), or 0
+                  * and 1 to index the palette.
+                  */
+                 if (!GDI_CALL (GetDIBColorTable, (hdc, bgix, 1, newtable)) ||
+                     !GDI_CALL (GetDIBColorTable, (hdc, fgix, 1, newtable+1)))
+                   ok = FALSE;
+               }
+             else
+               {
+                 /* Destination is a window, get fg and bg from its
+                  * colormap
+                  */
+
+                 bg = _gdk_win32_colormap_color (dest->colormap, bgix);
+                 fg = _gdk_win32_colormap_color (dest->colormap, fgix);
+                 newtable[0].rgbBlue = GetBValue (bg);
+                 newtable[0].rgbGreen = GetGValue (bg);
+                 newtable[0].rgbRed = GetRValue (bg);
+                 newtable[0].rgbReserved = 0;
+                 newtable[1].rgbBlue = GetBValue (fg);
+                 newtable[1].rgbGreen = GetGValue (fg);
+                 newtable[1].rgbRed = GetRValue (fg);
+                 newtable[1].rgbReserved = 0;
+               }
+             if (ok)
+               GDK_NOTE (MISC, g_print ("bg: %02x %02x %02x "
+                                        "fg: %02x %02x %02x\n",
+                                        newtable[0].rgbRed,
+                                        newtable[0].rgbGreen,
+                                        newtable[0].rgbBlue,
+                                        newtable[1].rgbRed,
+                                        newtable[1].rgbGreen,
+                                        newtable[1].rgbBlue));
+             newtable_size = 2;
+           }
+         else if (GDK_IS_PIXMAP_IMPL_WIN32 (dest))
+           {
+             /* Destination is pixmap, get its color table */
+             
+             if ((newtable_size = GetDIBColorTable (hdc, 0, 256, newtable)) == 0)
+               WIN32_GDI_FAILED ("GetDIBColorTable"), ok = FALSE;
+           }
+         
+         /* If blitting between pixmaps, set source's color table */
+         if (ok && newtable_size > 0)
+           {
+             GDK_NOTE (MISC_OR_COLORMAP,
+                       g_print ("blit_from_pixmap: set color table"
+                                " hdc=%p count=%d\n",
+                                srcdc, newtable_size));
+             if (!GDI_CALL (SetDIBColorTable, (srcdc, 0, newtable_size, newtable)))
+               ok = FALSE;
+           }
        }
-      else
+      
+      if (ok)
+       GDI_CALL (BitBlt, (hdc, xdest, ydest, width, height,
+                          srcdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)));
+      
+      /* Restore source's color table if necessary */
+      if (ok && newtable_size > 0 && oldtable_size > 0)
        {
-         if ((srcdc = GetDC (GDK_DRAWABLE_XID (src))) == NULL)
-           WIN32_GDI_FAILED ("GetDC");
-         
-         if (!BitBlt (hdc, xdest, ydest, width, height,
-                      srcdc, xsrc, ysrc, SRCCOPY))
-           WIN32_GDI_FAILED ("BitBlt");
-         ReleaseDC (GDK_DRAWABLE_XID (src), srcdc);
+         GDK_NOTE (MISC_OR_COLORMAP,
+                   g_print ("blit_from_pixmap: reset color table"
+                            " hdc=%p count=%d\n",
+                            srcdc, oldtable_size));
+         GDI_CALL (SetDIBColorTable, (srcdc, 0, oldtable_size, oldtable));
        }
+      
+      GDI_CALL (SelectObject, (srcdc, holdbitmap));
     }
-  gdk_gc_postdraw (drawable, gc_private, 0);
+  
+  _gdk_win32_drawable_release_dc (GDK_DRAWABLE (src));
 }
 
 static void
-gdk_win32_draw_points (GdkDrawable *drawable,
-                      GdkGC       *gc,
-                      GdkPoint    *points,
-                      gint         npoints)
+blit_inside_drawable (HDC              hdc,
+                     GdkGCWin32 *gcwin32,
+                     gint      xsrc,
+                     gint      ysrc,
+                     gint      xdest,
+                     gint      ydest,
+                     gint      width,
+                     gint      height)
+
 {
-  HDC hdc;
-  COLORREF fg;
-  GdkGCPrivate *gc_private = (GdkGCPrivate*) gc;
-  GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private);
-  GdkDrawablePrivate *drawable_private = (GdkDrawablePrivate *) drawable;
-  GdkColormapPrivateWin32 *colormap_private =
-    (GdkColormapPrivateWin32 *) drawable_private->colormap;
-  int i;
+  GDK_NOTE (MISC, g_print ("blit_inside_drawable\n"));
 
-  hdc = gdk_gc_predraw (drawable, gc_private, 0);
-  
-  fg = gdk_colormap_color (colormap_private, gc_data->foreground);
+  GDI_CALL (BitBlt, (hdc, xdest, ydest, width, height,
+                    hdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)));
+}
 
-  GDK_NOTE (MISC, g_print ("gdk_draw_points: %#x %dx%.06x\n",
-                          GDK_DRAWABLE_XID (drawable), npoints, fg));
+static void
+blit_from_window (HDC                   hdc,
+                 GdkGCWin32           *gcwin32,
+                 GdkDrawableImplWin32 *src,
+                 gint                  xsrc,
+                 gint                  ysrc,
+                 gint                  xdest,
+                 gint                  ydest,
+                 gint                  width,
+                 gint                  height)
+{
+  HDC srcdc;
+  HPALETTE holdpal = NULL;
+  GdkColormap *cmap = gdk_colormap_get_system ();
 
-  for (i = 0; i < npoints; i++)
-    SetPixel (hdc, points[i].x, points[i].y, fg);
+  GDK_NOTE (MISC, g_print ("blit_from_window\n"));
+
+  if ((srcdc = GetDC (src->handle)) == NULL)
+    {
+      WIN32_GDI_FAILED ("GetDC");
+      return;
+    }
 
-  gdk_gc_postdraw (drawable, gc_private, 0);
+  if (cmap->visual->type == GDK_VISUAL_PSEUDO_COLOR ||
+      cmap->visual->type == GDK_VISUAL_STATIC_COLOR)
+    {
+      gint k;
+      
+      if (!(holdpal = SelectPalette (srcdc, GDK_WIN32_COLORMAP_DATA (cmap)->hpal, FALSE)))
+       WIN32_GDI_FAILED ("SelectPalette");
+      else if ((k = RealizePalette (srcdc)) == GDI_ERROR)
+       WIN32_GDI_FAILED ("RealizePalette");
+      else if (k > 0)
+       GDK_NOTE (MISC_OR_COLORMAP,
+                 g_print ("blit_from_window: realized %d\n", k));
+    }
+  
+  GDI_CALL (BitBlt, (hdc, xdest, ydest, width, height,
+                    srcdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)));
+  
+  if (holdpal != NULL)
+    GDI_CALL (SelectPalette, (srcdc, holdpal, FALSE));
+  
+  GDI_CALL (ReleaseDC, (src->handle, srcdc));
 }
 
-static void
-gdk_win32_draw_segments (GdkDrawable *drawable,
-                        GdkGC       *gc,
-                        GdkSegment  *segs,
-                        gint         nsegs)
+void
+_gdk_win32_blit (gboolean              use_fg_bg,
+                GdkDrawableImplWin32 *draw_impl,
+                GdkGC                *gc,
+                GdkDrawable          *src,
+                gint                  xsrc,
+                gint                  ysrc,
+                gint                  xdest,
+                gint                  ydest,
+                gint                  width,
+                gint                  height)
 {
-  GdkGCPrivate *gc_private = (GdkGCPrivate*) gc;
-  GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private);
   HDC hdc;
-  HBRUSH hbr = NULL;
-  gboolean ok = TRUE;
-  int i;
+  HRGN src_rgn, draw_rgn, outside_rgn;
+  RECT r;
+  GdkDrawableImplWin32 *src_impl = NULL;
+  gint src_width, src_height;
+  
+  GDK_NOTE (MISC, g_print ("_gdk_win32_blit: src:%s %dx%d@%+d%+d\n"
+                          "                 dst:%s @%+d%+d use_fg_bg=%d\n",
+                          _gdk_win32_drawable_description (src),
+                          width, height, xsrc, ysrc,
+                          _gdk_win32_drawable_description (&draw_impl->parent_instance),
+                          xdest, ydest,
+                          use_fg_bg));
 
-  GDK_NOTE (MISC, g_print ("gdk_win32_draw_segments: %#x nsegs: %d\n",
-                          GDK_DRAWABLE_XID (drawable), nsegs));
+  /* If blitting from the root window, take the multi-monitor offset
+   * into account.
+   */
+  if (src == ((GdkWindowObject *)_gdk_root)->impl)
+    {
+      GDK_NOTE (MISC, g_print ("... offsetting src coords\n"));
+      xsrc -= _gdk_offset_x;
+      ysrc -= _gdk_offset_y;
+    }
 
-  hdc = gdk_gc_predraw (drawable, gc_private,
-                       GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
+  if (GDK_IS_DRAWABLE_IMPL_WIN32 (src))
+    src_impl = (GdkDrawableImplWin32 *) src;
+  else if (GDK_IS_WINDOW (src))
+    src_impl = (GdkDrawableImplWin32 *) GDK_WINDOW_OBJECT (src)->impl;
+  else if (GDK_IS_PIXMAP (src))
+    src_impl = (GdkDrawableImplWin32 *) GDK_PIXMAP_OBJECT (src)->impl;
+  else
+    g_assert_not_reached ();
+
+  hdc = gdk_win32_hdc_get (&draw_impl->parent_instance, gc, GDK_GC_FOREGROUND);
 
-  if (gc_data->fill_style == GDK_OPAQUE_STIPPLED)
+  gdk_drawable_get_size (src, &src_width, &src_height);
+
+  if ((src_rgn = CreateRectRgn (0, 0, src_width + 1, src_height + 1)) == NULL)
+    WIN32_GDI_FAILED ("CreateRectRgn");
+  else if ((draw_rgn = CreateRectRgn (xsrc, ysrc,
+                                     xsrc + width + 1,
+                                     ysrc + height + 1)) == NULL)
+    WIN32_GDI_FAILED ("CreateRectRgn");
+  else
     {
-      if (!BeginPath (hdc))
-       WIN32_GDI_FAILED ("BeginPath"), ok = FALSE;
-      
-      for (i = 0; i < nsegs; i++)
+      if (GDK_IS_WINDOW_IMPL_WIN32 (draw_impl))
        {
-         if (ok && !MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL))
-           WIN32_GDI_FAILED ("MoveToEx"), ok = FALSE;
-         if (ok && !LineTo (hdc, segs[i].x2, segs[i].y2))
-           WIN32_GDI_FAILED ("LineTo"), ok = FALSE;
+         int comb;
+         
+         /* If we are drawing on a window, calculate the region that is
+          * outside the source pixmap, and invalidate that, causing it to
+          * be cleared. Not completely sure whether this is always needed. XXX
+          */
+         SetRectEmpty (&r);
+         outside_rgn = CreateRectRgnIndirect (&r);
          
-         /* Draw end pixel */
-         if (ok && gc_data->pen_width == 1)
-           if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
-             WIN32_GDI_FAILED ("LineTo"), ok = FALSE;
+         if ((comb = CombineRgn (outside_rgn,
+                                 draw_rgn, src_rgn,
+                                 RGN_DIFF)) == ERROR)
+           WIN32_GDI_FAILED ("CombineRgn");
+         else if (comb != NULLREGION)
+           {
+             OffsetRgn (outside_rgn, xdest, ydest);
+             GDK_NOTE (MISC, (GetRgnBox (outside_rgn, &r),
+                              g_print ("... InvalidateRgn "
+                                       "bbox: %ldx%ld@%+ld%+ld\n",
+                                       r.right - r.left - 1, r.bottom - r.top - 1,
+                                       r.left, r.top)));
+             InvalidateRgn (draw_impl->handle, outside_rgn, TRUE);
+           }
+         GDI_CALL (DeleteObject, (outside_rgn));
        }
 
-      if (ok && !EndPath (hdc))
-       WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
-         
-      if (ok && !WidenPath (hdc))
-       WIN32_GDI_FAILED ("WidenPath"), ok = FALSE;
+#if 1 /* Don't know if this is necessary XXX */
+      if (CombineRgn (draw_rgn, draw_rgn, src_rgn, RGN_AND) == COMPLEXREGION)
+       g_warning ("gdk_win32_blit: CombineRgn returned a COMPLEXREGION");
+      
+      GetRgnBox (draw_rgn, &r);
+      if (r.left != xsrc || r.top != ysrc ||
+         r.right != xsrc + width + 1 || r.bottom != ysrc + height + 1)
+       {
+         xdest += r.left - xsrc;
+         xsrc = r.left;
+         ydest += r.top - ysrc;
+         ysrc = r.top;
+         width = r.right - xsrc - 1;
+         height = r.bottom - ysrc - 1;
          
-      if (ok && !FillPath (hdc))
-       WIN32_GDI_FAILED ("FillPath"), ok = FALSE;
+         GDK_NOTE (MISC, g_print ("... restricted to src: %dx%d@%+d%+d, "
+                                  "dest: @%+d%+d\n",
+                                  width, height, xsrc, ysrc,
+                                  xdest, ydest));
+       }
+#endif
 
-      if (hbr != NULL)
-       if (!DeleteObject (hbr))
-         WIN32_GDI_FAILED ("DeleteObject");
+      GDI_CALL (DeleteObject, (src_rgn));
+      GDI_CALL (DeleteObject, (draw_rgn));
     }
+
+  if (draw_impl->handle == src_impl->handle)
+    blit_inside_drawable (hdc, GDK_GC_WIN32 (gc), xsrc, ysrc, xdest, ydest, width, height);
+  else if (GDK_IS_PIXMAP_IMPL_WIN32 (src_impl))
+    blit_from_pixmap (use_fg_bg, draw_impl, hdc,
+                     (GdkPixmapImplWin32 *) src_impl, gc,
+                     xsrc, ysrc, xdest, ydest, width, height);
   else
+    blit_from_window (hdc, GDK_GC_WIN32 (gc), src_impl, xsrc, ysrc, xdest, ydest, width, height);
+  gdk_win32_hdc_release (&draw_impl->parent_instance, gc, GDK_GC_FOREGROUND);
+}
+
+static void
+gdk_win32_draw_image (GdkDrawable     *drawable,
+                     GdkGC           *gc,
+                     GdkImage        *image,
+                     gint             xsrc,
+                     gint             ysrc,
+                     gint             xdest,
+                     gint             ydest,
+                     gint             width,
+                     gint             height)
+{
+  g_assert (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable));
+
+  _gdk_win32_blit (TRUE, (GdkDrawableImplWin32 *) drawable,
+                  gc, (GdkPixmap *) image->windowing_data,
+                  xsrc, ysrc, xdest, ydest, width, height);
+}
+
+/**
+ * _gdk_win32_drawable_acquire_dc
+ * @drawable: a Win32 #GdkDrawable implementation
+ * 
+ * Gets a DC with the given drawable selected into
+ * it.
+ *
+ * Return value: The DC, on success. Otherwise
+ *  %NULL. If this function succeeded
+ *  _gdk_win32_drawable_release_dc()  must be called
+ *  release the DC when you are done using it.
+ **/
+HDC 
+_gdk_win32_drawable_acquire_dc (GdkDrawable *drawable)
+{
+  GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
+  
+  if (GDK_IS_WINDOW_IMPL_WIN32 (drawable) &&
+      GDK_WINDOW_DESTROYED (impl->wrapper))
+    return NULL;
+
+  if (!impl->hdc)
     {
-      for (i = 0; i < nsegs; i++)
+      if (GDK_IS_PIXMAP_IMPL_WIN32 (impl))
        {
-         if (!MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL))
-           WIN32_GDI_FAILED ("MoveToEx");
-         if (!LineTo (hdc, segs[i].x2, segs[i].y2))
-           WIN32_GDI_FAILED ("LineTo");
+         impl->hdc = CreateCompatibleDC (NULL);
+         if (!impl->hdc)
+           WIN32_GDI_FAILED ("CreateCompatibleDC");
          
-         /* Draw end pixel */
-         if (gc_data->pen_width == 1)
-           if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
-             WIN32_GDI_FAILED ("LineTo");
+         if (impl->hdc)
+           {
+             impl->saved_dc_bitmap = SelectObject (impl->hdc,
+                                                   impl->handle);
+             if (!impl->saved_dc_bitmap)
+               {
+                 WIN32_GDI_FAILED ("CreateCompatibleDC");
+                 DeleteDC (impl->hdc);
+                 impl->hdc = NULL;
+               }
+           }
+       }
+      else
+       {
+         impl->hdc = GetDC (impl->handle);
+         if (!impl->hdc)
+           WIN32_GDI_FAILED ("GetDC");
+       }
+    }
+
+  if (impl->hdc)
+    {
+      impl->hdc_count++;
+      return impl->hdc;
+    }
+  else
+    return NULL;
+}
+
+/**
+ * _gdk_win32_drawable_release_dc
+ * @drawable: a Win32 #GdkDrawable implementation
+ * 
+ * Releases the reference count for the DC
+ * from _gdk_win32_drawable_acquire_dc()
+ **/
+void
+_gdk_win32_drawable_release_dc (GdkDrawable *drawable)
+{
+  GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
+  
+  g_return_if_fail (impl->hdc_count > 0);
+
+  impl->hdc_count--;
+  if (impl->hdc_count == 0)
+    {
+      if (impl->saved_dc_bitmap)
+       {
+         GDI_CALL (SelectObject, (impl->hdc, impl->saved_dc_bitmap));
+         impl->saved_dc_bitmap = NULL;
+       }
+      
+      if (impl->hdc)
+       {
+         GDI_CALL (DeleteDC, (impl->hdc));
+         impl->hdc = NULL;
        }
     }
-  gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
 }
 
 static void
-gdk_win32_draw_lines (GdkDrawable *drawable,
-                     GdkGC       *gc,
-                     GdkPoint    *points,
-                     gint         npoints)
+gdk_win32_cairo_surface_destroy (void *data)
 {
-  GdkGCPrivate *gc_private = (GdkGCPrivate*) gc;
-  GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private);
-  HDC hdc;
-  POINT *pts;
-  int i;
+  GdkDrawableImplWin32 *impl = data;
 
-  if (npoints < 2)
-    return;
+  _gdk_win32_drawable_release_dc (GDK_DRAWABLE (impl));
+  impl->cairo_surface = NULL;
+}
 
-  hdc = gdk_gc_predraw (drawable, gc_private,
-                       GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
-#if 1
-  pts = g_new (POINT, npoints);
+static cairo_surface_t *
+gdk_win32_ref_cairo_surface (GdkDrawable *drawable)
+{
+  GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
 
-  for (i = 0; i < npoints; i++)
+  if (GDK_IS_WINDOW_IMPL_WIN32 (drawable) &&
+      GDK_WINDOW_DESTROYED (impl->wrapper))
+    return NULL;
+
+  if (!impl->cairo_surface)
     {
-      pts[i].x = points[i].x;
-      pts[i].y = points[i].y;
+      HDC hdc = _gdk_win32_drawable_acquire_dc (drawable);
+      if (!hdc)
+       return NULL;
+
+      impl->cairo_surface = cairo_win32_surface_create (hdc);
+
+      cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
+                                  drawable, gdk_win32_cairo_surface_destroy);
+    }
+  else
+    cairo_surface_reference (impl->cairo_surface);
+
+  return impl->cairo_surface;
+}
+
+static gint
+gdk_win32_get_depth (GdkDrawable *drawable)
+{
+  /* This is a bit bogus but I'm not sure the other way is better */
+
+  return gdk_drawable_get_depth (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
+}
+
+static GdkScreen*
+gdk_win32_get_screen (GdkDrawable *drawable)
+{
+  return gdk_screen_get_default ();
+}
+static GdkVisual*
+gdk_win32_get_visual (GdkDrawable *drawable)
+{
+  return gdk_drawable_get_visual (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
+}
+
+HGDIOBJ
+gdk_win32_drawable_get_handle (GdkDrawable *drawable)
+{
+  return GDK_DRAWABLE_HANDLE (drawable);
+}
+
+/**
+ * _gdk_win32_drawable_finish
+ * @drawable: a Win32 #GdkDrawable implementation
+ * 
+ * Releases any resources allocated internally for the drawable.
+ * This is called when the drawable becomes unusable
+ * (gdk_window_destroy() for a window, or the refcount going to
+ * zero for a pixmap.)
+ **/
+void
+_gdk_win32_drawable_finish (GdkDrawable *drawable)
+{
+  GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
+
+  if (impl->cairo_surface)
+    {
+      cairo_surface_finish (impl->cairo_surface);
+      cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
+                                  NULL, NULL);
     }
   
-  if (!Polyline (hdc, pts, npoints))
-    WIN32_GDI_FAILED ("Polyline");
-  
-  g_free (pts);
-  
-  /* Draw end pixel */
-  if (gc_data->pen_width == 1)
-    {
-      MoveToEx (hdc, points[npoints-1].x, points[npoints-1].y, NULL);
-      if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
-       WIN32_GDI_FAILED ("LineTo");
-    }
-#else
-  MoveToEx (hdc, points[0].x, points[0].y, NULL);
-  for (i = 1; i < npoints; i++)
-    if (!LineTo (hdc, points[i].x, points[i].y))
-      WIN32_GDI_FAILED ("LineTo");
-  
-  /* Draw end pixel */
-  /* LineTo doesn't draw the last point, so if we have a pen width of 1,
-   * we draw the end pixel separately... With wider pens we don't care.
-   * //HB: But the NT developers don't read their API documentation ...
-   */
-  if (gc_data->pen_width == 1 && windows_version > 0x80000000)
-    if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
-      WIN32_GDI_FAILED ("LineTo");
-#endif 
-  gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND);
+  g_assert (impl->hdc_count == 0);
 }
+