/* 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>
+
+#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
+
+#define LINE_ATTRIBUTES (GDK_GC_LINE_WIDTH|GDK_GC_LINE_STYLE| \
+ GDK_GC_CAP_STYLE|GDK_GC_JOIN_STYLE)
+
+#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,
+ gboolean filled,
+ gint x,
+ gint y,
+ gint width,
+ gint height);
+static void gdk_win32_draw_arc (GdkDrawable *drawable,
+ GdkGC *gc,
+ gboolean filled,
+ gint x,
+ gint y,
+ gint width,
+ gint height,
+ gint angle1,
+ gint angle2);
+static void gdk_win32_draw_polygon (GdkDrawable *drawable,
+ GdkGC *gc,
+ gboolean filled,
+ GdkPoint *points,
+ gint npoints);
+static void gdk_win32_draw_text (GdkDrawable *drawable,
+ GdkFont *font,
+ GdkGC *gc,
+ gint x,
+ gint y,
+ const gchar *text,
+ gint text_length);
+static void gdk_win32_draw_text_wc (GdkDrawable *drawable,
+ GdkFont *font,
+ GdkGC *gc,
+ gint x,
+ gint y,
+ const GdkWChar *text,
+ gint text_length);
+static void gdk_win32_draw_drawable (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkPixmap *src,
+ gint xsrc,
+ gint ysrc,
+ gint xdest,
+ gint ydest,
+ gint width,
+ gint height);
+static void gdk_win32_draw_points (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkPoint *points,
+ gint npoints);
+static void gdk_win32_draw_segments (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkSegment *segs,
+ gint nsegs);
+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);
+
+static cairo_surface_t *gdk_win32_ref_cairo_surface (GdkDrawable *drawable);
+
+static void gdk_win32_set_colormap (GdkDrawable *drawable,
+ GdkColormap *colormap);
+
+static GdkColormap* gdk_win32_get_colormap (GdkDrawable *drawable);
+
+static gint gdk_win32_get_depth (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)
+{
+ static GType object_type = 0;
-#include "gdkdrawable.h"
-#include "gdkprivate.h"
-#include "gdkwindow.h"
-#include "gdkx.h"
-
-#ifndef G_PI
-#define G_PI 3.14159265358979323846
-#endif
+ if (!object_type)
+ {
+ 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 object_type;
+}
-/* Manipulation of drawables
- */
-void
-gdk_drawable_set_data (GdkDrawable *drawable,
- const gchar *key,
- gpointer data,
- GDestroyNotify destroy_func)
+static void
+gdk_drawable_impl_win32_class_init (GdkDrawableImplWin32Class *klass)
{
- g_dataset_set_data_full (drawable, key, data, destroy_func);
+ 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;
+
+ drawable_class->ref_cairo_surface = gdk_win32_ref_cairo_surface;
+
+ 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;
}
-void
-gdk_drawable_get_data (GdkDrawable *drawable,
- const gchar *key)
+static void
+gdk_drawable_impl_win32_finalize (GObject *object)
{
- g_dataset_get_data (drawable, key);
+ gdk_drawable_set_colormap (GDK_DRAWABLE (object), NULL);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
}
-GdkDrawableType
-gdk_drawable_get_type (GdkDrawable *drawable)
+/*****************************************************
+ * Win32 specific implementations of generic functions *
+ *****************************************************/
+
+static GdkColormap*
+gdk_win32_get_colormap (GdkDrawable *drawable)
{
- g_return_val_if_fail (drawable != NULL, (GdkDrawableType) -1);
-
- return GDK_DRAWABLE_TYPE (drawable);
+ return GDK_DRAWABLE_IMPL_WIN32 (drawable)->colormap;
}
-void
-gdk_drawable_get_size (GdkDrawable *drawable,
- gint *width,
- gint *height)
+static void
+gdk_win32_set_colormap (GdkDrawable *drawable,
+ GdkColormap *colormap)
{
- GdkDrawablePrivate *drawable_private;
-
- g_return_if_fail (drawable != NULL);
-
- drawable_private = (GdkDrawablePrivate*) drawable;
+ GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
+
+ if (impl->colormap == colormap)
+ return;
- if (width)
- *width = drawable_private->width;
- if (height)
- *height = drawable_private->height;
+ if (impl->colormap)
+ gdk_colormap_unref (impl->colormap);
+ impl->colormap = colormap;
+ if (impl->colormap)
+ gdk_colormap_ref (impl->colormap);
}
-void
-gdk_drawable_set_colormap (GdkDrawable *drawable,
- GdkColormap *colormap)
+/* Drawing
+ */
+
+static int
+rop2_to_rop3 (int rop2)
{
- GdkDrawablePrivate *drawable_private;
- GdkColormapPrivate *colormap_private;
-
- g_return_if_fail (drawable != NULL);
- g_return_if_fail (colormap != NULL);
-
- drawable_private = (GdkDrawablePrivate*) drawable;
- colormap_private = (GdkColormapPrivate*) colormap;
-
- if (!GDK_DRAWABLE_DESTROYED (drawable))
+ switch (rop2)
{
- if (GDK_IS_WINDOW (drawable))
- {
- g_return_if_fail (colormap_private->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));
- }
- 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);
+ /* 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;
}
}
-GdkColormap*
-gdk_drawable_get_colormap (GdkDrawable *drawable)
+static int
+rop2_to_patblt_rop (int rop2)
{
- GdkDrawablePrivate *drawable_private;
-
- g_return_val_if_fail (drawable != NULL, NULL);
- drawable_private = (GdkDrawablePrivate*) drawable;
-
- if (!GDK_DRAWABLE_DESTROYED (drawable))
+ switch (rop2)
{
- if (drawable_private->colormap == NULL)
- return gdk_colormap_get_system (); /* XXX ??? */
- else
- return drawable_private->colormap;
+#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;
}
-
- return NULL;
}
-GdkVisual*
-gdk_drawable_get_visual (GdkDrawable *drawable)
+static inline int
+align_with_dash_offset (int a, DWORD *dashes, int num_dashes, GdkGCWin32 *gcwin32)
{
- GdkColormap *colormap;
+ 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);
- g_return_val_if_fail (drawable != NULL, NULL);
+ 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;
- colormap = gdk_drawable_get_colormap (drawable);
- return colormap ? gdk_colormap_get_visual (colormap) : NULL;
+ 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;
}
-void
-gdk_draw_point (GdkDrawable *drawable,
- GdkGC *gc,
- gint x,
- gint y)
+static inline gboolean
+render_line_vertical (GdkGCWin32 *gcwin32,
+ int x,
+ int y1,
+ int y2)
{
- GdkDrawablePrivate *drawable_private;
- GdkGCPrivate *gc_private;
- HDC hdc;
+ int n;
+ const int pen_width = MAX (gcwin32->pen_width, 1);
+ const int _y1 = y1;
- g_return_if_fail (drawable != NULL);
- g_return_if_fail (gc != NULL);
+ g_assert (gcwin32->pen_dashes);
- if (GDK_DRAWABLE_DESTROYED (drawable))
- return;
- drawable_private = (GdkDrawablePrivate*) drawable;
- gc_private = (GdkGCPrivate*) gc;
+ 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];
+ }
- hdc = gdk_gc_predraw (drawable_private, gc_private);
+ if (gcwin32->line_style == GDK_LINE_DOUBLE_DASH)
+ {
+ HBRUSH hbr;
- /* We use LineTo because SetPixel wants the COLORREF directly,
- * and doesn't use the current pen, which is what we want.
- */
- if (!MoveToEx (hdc, x, y, NULL))
- g_warning ("gdk_draw_point: MoveToEx failed");
- if (!LineTo (hdc, x + 1, y))
- g_warning ("gdk_draw_point: LineTo failed");
-
- gdk_gc_postdraw (drawable_private, gc_private);
+ 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;
}
-void
-gdk_draw_line (GdkDrawable *drawable,
- GdkGC *gc,
- gint x1,
- gint y1,
- gint x2,
- gint y2)
-{
- GdkDrawablePrivate *drawable_private;
- GdkGCPrivate *gc_private;
- HDC hdc;
+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;
+ }
+}
- g_return_if_fail (drawable != NULL);
- g_return_if_fail (gc != NULL);
+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;
- if (GDK_DRAWABLE_DESTROYED (drawable))
- return;
- drawable_private = (GdkDrawablePrivate*) drawable;
- gc_private = (GdkGCPrivate*) gc;
+ 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);
- hdc = gdk_gc_predraw (drawable_private, gc_private);
-
- GDK_NOTE (MISC, g_print ("gdk_draw_line: %#x (%d) +%d+%d..+%d+%d\n",
- drawable_private->xwindow, gc_private,
- x1, y1, x2, y2));
-
- MoveToEx (hdc, x1, y1, NULL);
- if (!LineTo (hdc, x2, y2))
- g_warning ("gdk_draw_line: LineTo #1 failed");
- /* 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_private->pen_width == 1 && windows_version > 0x80000000)
- if (!LineTo (hdc, x2 + 1, y2))
- g_warning ("gdk_draw_line: LineTo #2 failed");
- gdk_gc_postdraw (drawable_private, gc_private);
+ 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);
}
-void
-gdk_draw_rectangle (GdkDrawable *drawable,
- GdkGC *gc,
- gint filled,
- gint x,
- gint y,
- gint width,
- gint height)
+static void
+generic_draw (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkGCValuesMask mask,
+ void (*function) (GdkGCWin32 *, HDC, gint, gint, va_list),
+ const GdkRegion *region,
+ ...)
{
- GdkDrawablePrivate *drawable_private;
- GdkGCPrivate *gc_private;
+ GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
+ GdkGCWin32 *gcwin32 = GDK_GC_WIN32 (gc);
HDC hdc;
- HGDIOBJ oldpen, oldbrush;
+ va_list args;
+ GdkFill fill_style = _gdk_gc_get_fill (gc);
- g_return_if_fail (drawable != NULL);
- g_return_if_fail (gc != NULL);
+ va_start (args, region);
- if (GDK_DRAWABLE_DESTROYED (drawable))
- return;
- drawable_private = (GdkDrawablePrivate*) drawable;
- gc_private = (GdkGCPrivate*) gc;
+ /* If tiled or stippled, draw to a temp pixmap and do blitting magic.
+ */
- if (width == -1)
- width = drawable_private->width;
- if (height == -1)
- height = drawable_private->height;
+ 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)))
+ {
+ 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 = gdk_gc_predraw (drawable_private, gc_private);
+ HDC mask_hdc;
+ HDC tile_hdc;
- GDK_NOTE (MISC, g_print ("gdk_draw_rectangle: %#x (%d) %s%dx%d@+%d+%d\n",
- drawable_private->xwindow,
- gc_private,
- (filled ? "fill " : ""),
- width, height, x, y));
-
-#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
+ HGDIOBJ old_mask_hbm;
+ HGDIOBJ old_tile_hbm;
- 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))
- g_warning ("gdk_draw_rectangle: Rectangle failed");
-
- if (filled)
- SelectObject (hdc, oldpen);
- else
- SelectObject (hdc, oldbrush);
+ GdkGCValues gcvalues;
- gdk_gc_postdraw (drawable_private, gc_private);
-}
+ hdc = gdk_win32_hdc_get (drawable, gc, blitting_mask);
+ tile_hdc = CreateCompatibleDC (hdc);
-void
-gdk_draw_arc (GdkDrawable *drawable,
- GdkGC *gc,
- gint filled,
- gint x,
- gint y,
- gint width,
- gint height,
- gint angle1,
- gint angle2)
-{
- GdkDrawablePrivate *drawable_private;
- GdkGCPrivate *gc_private;
- HDC hdc;
- int nXStartArc, nYStartArc, nXEndArc, nYEndArc;
+ 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;
- g_return_if_fail (drawable != NULL);
- g_return_if_fail (gc != NULL);
+ ts_x_origin -= region->extents.x1;
+ ts_y_origin -= region->extents.y1;
- if (GDK_DRAWABLE_DESTROYED (drawable))
- return;
- drawable_private = (GdkDrawablePrivate*) drawable;
- gc_private = (GdkGCPrivate*) gc;
+ /* 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);
- if (width == -1)
- width = drawable_private->width;
- if (height == -1)
- height = drawable_private->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);
- GDK_NOTE (MISC, g_print ("gdk_draw_arc: %#x %d,%d,%d,%d %d %d\n",
- drawable_private->xwindow,
- x, y, width, height, angle1, angle2));
+ /* 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;
+ }
- if (width != 0 && height != 0 && angle2 != 0)
- {
- hdc = gdk_gc_predraw (drawable_private, gc_private);
+ /* Ditto, if the drawing function draws text, set up for that. */
+ if (mask & GDK_GC_FONT)
+ drawing_mask |= GDK_GC_FONT;
- if (angle2 >= 360*64)
+ 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)
{
- nXStartArc = nYStartArc = nXEndArc = nYEndArc = 0;
+ /* 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 if (angle2 > 0)
+ else
{
- /* 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.);
+ /* 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);
}
- else
+
+ 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)
{
- 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.);
+ 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);
}
- if (filled)
+ /* 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 ())
{
- 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));
- Pie (hdc, x, y, x+width, y+height,
- nXStartArc, nYStartArc, nXEndArc, nYEndArc);
+ 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
{
- 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));
- Arc (hdc, x, y, x+width, y+height,
- nXStartArc, nYStartArc, nXEndArc, nYEndArc);
+ 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);
}
- gdk_gc_postdraw (drawable_private, gc_private);
+
+ /* 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);
}
-void
-gdk_draw_polygon (GdkDrawable *drawable,
- GdkGC *gc,
- gint filled,
- GdkPoint *points,
- gint npoints)
-{
- GdkDrawablePrivate *drawable_private;
- GdkGCPrivate *gc_private;
- HDC hdc;
- POINT *pts;
- int i;
+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,
+ gboolean filled,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ GdkRectangle bounds;
+ GdkRegion *region;
+
+ 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));
+
+ 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);
+}
+
+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;
+
+ 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);
+
+ 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
+ {
+ 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)
+ {
+ 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));
+ }
+}
- g_return_if_fail (drawable != NULL);
- g_return_if_fail (gc != NULL);
+static void
+gdk_win32_draw_arc (GdkDrawable *drawable,
+ GdkGC *gc,
+ gboolean filled,
+ gint x,
+ gint y,
+ gint width,
+ gint height,
+ gint angle1,
+ gint angle2)
+{
+ GdkRectangle bounds;
+ GdkRegion *region;
- if (GDK_DRAWABLE_DESTROYED (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 <= 2 || height <= 2 || angle2 == 0)
return;
- drawable_private = (GdkDrawablePrivate*) drawable;
- gc_private = (GdkGCPrivate*) gc;
- GDK_NOTE (MISC, g_print ("gdk_draw_polygon: %#x (%d) %d\n",
- drawable_private->xwindow, gc_private,
+ 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 | (filled ? 0 : LINE_ATTRIBUTES),
+ draw_arc, region, filled, x, y, width, height, angle1, angle2);
+
+ 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,
+ gboolean filled,
+ GdkPoint *points,
+ gint npoints)
+{
+ GdkRectangle bounds;
+ GdkRegion *region;
+ POINT *pts;
+ int i;
+
+ 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_private, gc_private);
- pts = g_malloc ((npoints+1) * sizeof (POINT));
+ 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 ((points[0].x != points[npoints-1].x) ||
- (points[0].y != points[npoints-1].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);
+ }
+
+ 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))
- g_warning ("gdk_draw_polygon: Polygon failed");
- }
- else
- {
- if (!Polyline (hdc, pts, npoints))
- g_warning ("gdk_draw_polygon: Polyline failed");
- }
+
+ region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
+
+ generic_draw (drawable, gc,
+ GDK_GC_FOREGROUND | (filled ? 0 : LINE_ATTRIBUTES),
+ draw_polygon, region, filled, pts, npoints);
+
+ gdk_region_destroy (region);
g_free (pts);
- gdk_gc_postdraw (drawable_private, gc_private);
}
typedef struct
HDC hdc;
} gdk_draw_text_arg;
-/* gdk_draw_string
- */
-void
-gdk_draw_string (GdkDrawable *drawable,
- GdkFont *font,
- GdkGC *gc,
- gint x,
- gint y,
- const gchar *string)
-{
- gdk_draw_text (drawable, font, gc, x, y, string, strlen (string));
-}
-
static void
gdk_draw_text_handler (GdkWin32SingleFont *singlefont,
const wchar_t *wcstr,
int wclen,
void *arg)
{
- HDC hdc;
HGDIOBJ oldfont;
SIZE size;
- GdkDrawablePrivate *drawable_private;
- GdkGCPrivate *gc_private;
gdk_draw_text_arg *argp = (gdk_draw_text_arg *) arg;
- if ((oldfont = SelectObject (argp->hdc, singlefont->xfont)) == NULL)
+ if (!singlefont)
+ return;
+
+ if ((oldfont = SelectObject (argp->hdc, singlefont->hfont)) == NULL)
{
- g_warning ("gdk_draw_text_handler: SelectObject failed");
+ WIN32_GDI_FAILED ("SelectObject");
return;
}
if (!TextOutW (argp->hdc, argp->x, argp->y, wcstr, wclen))
- g_warning ("gdk_draw_text_handler: TextOutW failed");
+ WIN32_GDI_FAILED ("TextOutW");
GetTextExtentPoint32W (argp->hdc, wcstr, wclen, &size);
argp->x += size.cx;
- SelectObject (hdc, oldfont);
+ SelectObject (argp->hdc, oldfont);
}
-/* gdk_draw_text
- *
- */
-void
-gdk_draw_text (GdkDrawable *drawable,
- GdkFont *font,
- GdkGC *gc,
- gint x,
- gint y,
- const gchar *text,
- gint text_length)
+static void
+gdk_win32_draw_text (GdkDrawable *drawable,
+ GdkFont *font,
+ GdkGC *gc,
+ gint x,
+ gint y,
+ const gchar *text,
+ gint text_length)
{
- HDC hdc;
- GdkDrawablePrivate *drawable_private;
- 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;
- g_return_if_fail (drawable != NULL);
- g_return_if_fail (font != NULL);
- g_return_if_fail (gc != NULL);
- g_return_if_fail (text != NULL);
-
- if (GDK_DRAWABLE_DESTROYED (drawable))
- return;
-
if (text_length == 0)
return;
g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
- drawable_private = (GdkDrawablePrivate*) drawable;
- gc_private = (GdkGCPrivate*) gc;
-
arg.x = x;
arg.y = y;
- arg.hdc = gdk_gc_predraw (drawable_private, gc_private);
+ arg.hdc = gdk_win32_hdc_get (drawable, gc, mask);
- GDK_NOTE (MISC, g_print ("gdk_draw_text: %#x (%d,%d) \"%.*s\" (len %d)\n",
- drawable_private->xwindow,
+ 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_private, gc_private);
+ gdk_win32_hdc_release (drawable, gc, mask);
}
-void
-gdk_draw_text_wc (GdkDrawable *drawable,
- GdkFont *font,
- GdkGC *gc,
- gint x,
- gint y,
- const GdkWChar *text,
- gint text_length)
+static void
+gdk_win32_draw_text_wc (GdkDrawable *drawable,
+ GdkFont *font,
+ GdkGC *gc,
+ gint x,
+ gint y,
+ const GdkWChar *text,
+ gint text_length)
{
- HDC hdc;
- GdkDrawablePrivate *drawable_private;
- 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;
- g_return_if_fail (drawable != NULL);
- g_return_if_fail (font != NULL);
- g_return_if_fail (gc != NULL);
- g_return_if_fail (text != NULL);
-
- if (GDK_DRAWABLE_DESTROYED (drawable))
- return;
-
if (text_length == 0)
return;
g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
- drawable_private = (GdkDrawablePrivate*) drawable;
- gc_private = (GdkGCPrivate*) gc;
-
arg.x = x;
arg.y = y;
- arg.hdc = gdk_gc_predraw (drawable_private, gc_private);
+ arg.hdc = gdk_win32_hdc_get (drawable, gc, mask);
- GDK_NOTE (MISC, g_print ("gdk_draw_text_wc: %#x (%d,%d) len: %d\n",
- drawable_private->xwindow,
+ 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))
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_private, gc_private);
+ gdk_win32_hdc_release (drawable, gc, mask);
}
-void
-gdk_draw_pixmap (GdkDrawable *drawable,
- GdkGC *gc,
- GdkPixmap *src,
- gint xsrc,
- gint ysrc,
- gint xdest,
- gint ydest,
- gint width,
- gint height)
-{
- GdkDrawablePrivate *drawable_private;
- GdkDrawablePrivate *src_private;
- GdkGCPrivate *gc_private;
+static void
+gdk_win32_draw_drawable (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkPixmap *src,
+ gint xsrc,
+ gint ysrc,
+ gint xdest,
+ gint ydest,
+ gint width,
+ gint height)
+{
+ 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;
- g_return_if_fail (drawable != NULL);
- g_return_if_fail (src != NULL);
- g_return_if_fail (gc != NULL);
+ 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));
- if (GDK_DRAWABLE_DESTROYED (drawable) || GDK_DRAWABLE_DESTROYED (src))
- return;
- drawable_private = (GdkDrawablePrivate*) drawable;
- src_private = (GdkDrawablePrivate*) src;
- gc_private = (GdkGCPrivate*) gc;
-
- if (width == -1)
- width = src_private->width; /* Or should we subtract xsrc? */
- if (height == -1)
- height = src_private->height; /* Ditto? */
-
- GDK_NOTE (MISC, g_print ("gdk_draw_pixmap: dest: %#x "
- "src: %#x %dx%d@+%d+%d"
- " dest: %#x @+%d+%d\n",
- drawable_private->xwindow,
- src_private->xwindow,
- width, height, xsrc, ysrc,
- drawable_private->xwindow, 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_private, gc_private);
+ 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 (drawable_private->window_type != 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++)
{
- 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 (drawable_private->xwindow, outside_rgn, TRUE);
+ 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++)
+ {
+ 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;
+
+ GDK_NOTE (MISC, g_print ("gdk_win32_draw_segments: %s %d segs\n",
+ _gdk_win32_drawable_description (drawable),
+ nsegs));
+
+ bounds.x = G_MAXINT;
+ bounds.y = G_MAXINT;
+ bounds.width = 0;
+ bounds.height = 0;
+
+ for (i = 0; i < nsegs; i++)
+ {
+ 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);
+ }
-#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");
+ 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);
+ }
+
+ region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
+
+ generic_draw (drawable, gc, GDK_GC_FOREGROUND | LINE_ATTRIBUTES,
+ draw_segments, region, segs, nsegs);
- GetRgnBox (draw_rgn, &r);
- if (r.left != xsrc
- || r.top != ysrc
- || r.right != xsrc + width + 1
- || r.bottom != ysrc + height + 1)
+ 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))
{
- 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));
+ 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));
+ }
}
-#endif
+ else
+ GDI_CALL (Polyline, (hdc, pts, npoints));
+}
- DeleteObject (src_rgn);
- DeleteObject (draw_rgn);
- DeleteObject (outside_rgn);
+static void
+gdk_win32_draw_lines (GdkDrawable *drawable,
+ GdkGC *gc,
+ GdkPoint *points,
+ gint npoints)
+{
+ GdkRectangle bounds;
+ GdkRegion *region;
+ POINT *pts;
+ int i;
- /* Strangely enough, this function is called also to bitblt
- * from a window.
- */
- if (src_private->window_type == GDK_DRAWABLE_PIXMAP)
+ 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 ((srcdc = CreateCompatibleDC (hdc)) == NULL)
- g_warning ("gdk_draw_pixmap: CreateCompatibleDC failed");
-
- if ((hgdiobj = SelectObject (srcdc, src_private->xwindow)) == NULL)
- g_warning ("gdk_draw_pixmap: SelectObject #1 failed");
-
- if (!BitBlt (hdc, xdest, ydest, width, height,
- srcdc, xsrc, ysrc, SRCCOPY))
- g_warning ("gdk_draw_pixmap: BitBlt failed");
-
- if ((SelectObject (srcdc, hgdiobj) == NULL))
- g_warning ("gdk_draw_pixmap: SelectObject #2 failed");
-
- if (!DeleteDC (srcdc))
- g_warning ("gdk_draw_pixmap: DeleteDC failed");
+ 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 (drawable_private->xwindow == src_private->xwindow)
+ 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))
- g_warning ("gdk_draw_pixmap: ScrollDC failed");
- if (!InvalidateRgn (drawable_private->xwindow, updateRgn, FALSE))
- g_warning ("gdk_draw_pixmap: InvalidateRgn failed");
- if (!UpdateWindow (drawable_private->xwindow))
- g_warning ("gdk_draw_pixmap: UpdateWindow failed");
+ /* 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 (src_private->xwindow)) == NULL)
- g_warning ("gdk_draw_pixmap: GetDC failed");
-
- if (!BitBlt (hdc, xdest, ydest, width, height,
- srcdc, xsrc, ysrc, SRCCOPY))
- g_warning ("gdk_draw_pixmap: BitBlt failed");
- ReleaseDC (src_private->xwindow, 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_private, gc_private);
+
+ _gdk_win32_drawable_release_dc (GDK_DRAWABLE (src));
}
-void
-gdk_draw_image (GdkDrawable *drawable,
- GdkGC *gc,
- GdkImage *image,
- gint xsrc,
- gint ysrc,
- gint xdest,
- gint ydest,
- gint width,
- gint height)
+static void
+blit_inside_drawable (HDC hdc,
+ GdkGCWin32 *gcwin32,
+ gint xsrc,
+ gint ysrc,
+ gint xdest,
+ gint ydest,
+ gint width,
+ gint height)
+
{
- GdkImagePrivate *image_private;
+ GDK_NOTE (MISC, g_print ("blit_inside_drawable\n"));
- g_return_if_fail (drawable != NULL);
- g_return_if_fail (image != NULL);
- g_return_if_fail (gc != NULL);
+ GDI_CALL (BitBlt, (hdc, xdest, ydest, width, height,
+ hdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)));
+}
- image_private = (GdkImagePrivate*) image;
+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 ();
- g_return_if_fail (image_private->image_put != NULL);
+ GDK_NOTE (MISC, g_print ("blit_from_window\n"));
- if (width == -1)
- width = image->width;
- if (height == -1)
- height = image->height;
+ if ((srcdc = GetDC (src->handle)) == NULL)
+ {
+ WIN32_GDI_FAILED ("GetDC");
+ return;
+ }
- (* image_private->image_put) (drawable, gc, image, xsrc, ysrc,
- xdest, ydest, width, height);
+ 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));
}
void
-gdk_draw_points (GdkDrawable *drawable,
- GdkGC *gc,
- GdkPoint *points,
- gint npoints)
+_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)
{
- GdkDrawablePrivate *drawable_private;
- GdkGCPrivate *gc_private;
HDC hdc;
- 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));
+
+ /* 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;
+ }
- g_return_if_fail (drawable != NULL);
- g_return_if_fail ((points != NULL) && (npoints > 0));
- g_return_if_fail (gc != NULL);
+ 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 ();
- if (GDK_DRAWABLE_DESTROYED (drawable))
- return;
- drawable_private = (GdkDrawablePrivate*) drawable;
- gc_private = (GdkGCPrivate*) gc;
+ hdc = gdk_win32_hdc_get (&draw_impl->parent_instance, gc, GDK_GC_FOREGROUND);
+
+ 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 (GDK_IS_WINDOW_IMPL_WIN32 (draw_impl))
+ {
+ 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);
+
+ 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 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;
+
+ GDK_NOTE (MISC, g_print ("... restricted to src: %dx%d@%+d%+d, "
+ "dest: @%+d%+d\n",
+ width, height, xsrc, ysrc,
+ xdest, ydest));
+ }
+#endif
+
+ 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);
+}
- hdc = gdk_gc_predraw (drawable_private, gc_private);
+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);
- GDK_NOTE (MISC, g_print ("gdk_draw_points: %#x destdc: (%d) %#x "
- "npoints: %d\n",
- drawable_private->xwindow, gc_private, hdc,
- npoints));
+ if (GDK_IS_WINDOW_IMPL_WIN32 (drawable) &&
+ GDK_WINDOW_DESTROYED (impl->wrapper))
+ return NULL;
- for (i = 0; i < npoints; i++)
+ if (!impl->hdc)
{
- if (!MoveToEx (hdc, points[i].x, points[i].y, NULL))
- g_warning ("gdk_draw_points: MoveToEx failed");
- if (!LineTo (hdc, points[i].x + 1, points[i].y))
- g_warning ("gdk_draw_points: LineTo failed");
+ if (GDK_IS_PIXMAP_IMPL_WIN32 (impl))
+ {
+ impl->hdc = CreateCompatibleDC (NULL);
+ if (!impl->hdc)
+ WIN32_GDI_FAILED ("CreateCompatibleDC");
+
+ 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");
+ }
}
- gdk_gc_postdraw (drawable_private, gc_private);
+
+ 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_draw_segments (GdkDrawable *drawable,
- GdkGC *gc,
- GdkSegment *segs,
- gint nsegs)
+_gdk_win32_drawable_release_dc (GdkDrawable *drawable)
{
- GdkDrawablePrivate *drawable_private;
- GdkGCPrivate *gc_private;
- HDC hdc;
- int i;
+ GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
+
+ g_return_if_fail (impl->hdc_count > 0);
- if (nsegs <= 0)
- return;
+ 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;
+ }
+ }
+}
- g_return_if_fail (drawable != NULL);
- g_return_if_fail (segs != NULL);
- g_return_if_fail (gc != NULL);
+static void
+gdk_win32_cairo_surface_destroy (void *data)
+{
+ GdkDrawableImplWin32 *impl = data;
- if (GDK_DRAWABLE_DESTROYED (drawable))
- return;
- drawable_private = (GdkDrawablePrivate*) drawable;
- gc_private = (GdkGCPrivate*) gc;
+ _gdk_win32_drawable_release_dc (GDK_DRAWABLE (impl));
+ impl->cairo_surface = NULL;
+}
- hdc = gdk_gc_predraw (drawable_private, gc_private);
+static cairo_surface_t *
+gdk_win32_ref_cairo_surface (GdkDrawable *drawable)
+{
+ GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
- for (i = 0; i < nsegs; i++)
+ if (GDK_IS_WINDOW_IMPL_WIN32 (drawable) &&
+ GDK_WINDOW_DESTROYED (impl->wrapper))
+ return NULL;
+
+ if (!impl->cairo_surface)
{
- if (!MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL))
- g_warning ("gdk_draw_segments: MoveToEx failed");
- if (!LineTo (hdc, segs[i].x2, segs[i].y2))
- g_warning ("gdk_draw_segments: LineTo #1 failed");
-
- /* Draw end pixel */
- if (gc_private->pen_width == 1)
- if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
- g_warning ("gdk_draw_segments: LineTo #2 failed");
+ 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);
}
- gdk_gc_postdraw (drawable_private, gc_private);
+ else
+ cairo_surface_reference (impl->cairo_surface);
+
+ return impl->cairo_surface;
}
-void
-gdk_draw_lines (GdkDrawable *drawable,
- GdkGC *gc,
- GdkPoint *points,
- gint npoints)
+static gint
+gdk_win32_get_depth (GdkDrawable *drawable)
{
- GdkDrawablePrivate *drawable_private;
- GdkGCPrivate *gc_private;
- HDC hdc;
- POINT *pts;
- int i;
+ /* This is a bit bogus but I'm not sure the other way is better */
- if (npoints < 2)
- return;
+ return gdk_drawable_get_depth (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
+}
- g_return_if_fail (drawable != NULL);
- g_return_if_fail (points != NULL);
- g_return_if_fail (gc != NULL);
+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);
+}
- if (GDK_DRAWABLE_DESTROYED (drawable))
- return;
- drawable_private = (GdkDrawablePrivate*) drawable;
- gc_private = (GdkGCPrivate*) gc;
+HGDIOBJ
+gdk_win32_drawable_get_handle (GdkDrawable *drawable)
+{
+ return GDK_DRAWABLE_HANDLE (drawable);
+}
- hdc = gdk_gc_predraw (drawable_private, gc_private);
-#if 1
- pts = g_malloc (npoints * sizeof (POINT));
+/**
+ * _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);
- for (i = 0; i < npoints; i++)
+ if (impl->cairo_surface)
{
- pts[i].x = points[i].x;
- pts[i].y = points[i].y;
+ 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))
- g_warning ("gdk_draw_lines: Polyline(,,%d) failed", npoints);
-
- g_free (pts);
-
- /* Draw end pixel */
- if (gc_private->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))
- g_warning ("gdk_draw_lines: LineTo failed");
- }
-#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))
- g_warning ("gdk_draw_lines: LineTo #1 failed");
-
- /* Draw end pixel */
- if (gc_private->pen_width == 1)
- if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
- g_warning ("gdk_draw_lines: LineTo #2 failed");
-#endif
- gdk_gc_postdraw (drawable_private, gc_private);
+ g_assert (impl->hdc_count == 0);
}
+