/* GDK - The GIMP Drawing Kit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library 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. * * You should have received a copy of the GNU Library 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 * 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 #include #ifndef G_PI #define G_PI 3.14159265358979323846 #endif #include "gdkdrawable.h" #include "gdkprivate.h" #include "gdkwindow.h" #include "gdkwin32.h" static void gdk_win32_drawable_destroy (GdkDrawable *drawable); static void gdk_win32_draw_rectangle (GdkDrawable *drawable, GdkGC *gc, gint filled, gint x, gint y, gint width, gint height); static void gdk_win32_draw_arc (GdkDrawable *drawable, GdkGC *gc, gint filled, gint x, gint y, gint width, gint height, gint angle1, gint angle2); static void gdk_win32_draw_polygon (GdkDrawable *drawable, GdkGC *gc, gint 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); 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 }; /***************************************************** * Win32 specific implementations of generic functions * *****************************************************/ GdkColormap* gdk_drawable_get_colormap (GdkDrawable *drawable) { GdkDrawablePrivate *drawable_private; g_return_val_if_fail (drawable != NULL, NULL); drawable_private = (GdkDrawablePrivate*) drawable; if (!GDK_DRAWABLE_DESTROYED (drawable)) { if (drawable_private->colormap == NULL) return gdk_colormap_get_system (); /* XXX ??? */ else return drawable_private->colormap; } return NULL; } void gdk_drawable_set_colormap (GdkDrawable *drawable, GdkColormap *colormap) { GdkDrawablePrivate *drawable_private; GdkColormapPrivateWin32 *colormap_private; g_return_if_fail (drawable != NULL); g_return_if_fail (colormap != NULL); drawable_private = (GdkDrawablePrivate *) drawable; colormap_private = (GdkColormapPrivateWin32 *) colormap; if (!GDK_DRAWABLE_DESTROYED (drawable)) { if (GDK_IS_WINDOW (drawable)) { 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)); } 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); } } /* Drawing */ static void gdk_win32_drawable_destroy (GdkDrawable *drawable) { } static void gdk_win32_draw_rectangle (GdkDrawable *drawable, GdkGC *gc, gint 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; GDK_NOTE (MISC, g_print ("gdk_win32_draw_rectangle: %#x (%d) %s%dx%d@+%d+%d\n", GDK_DRAWABLE_XID (drawable), gc_private, (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_API_FAILED ("BeginPath"), ok = FALSE; /* 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_API_FAILED ("Polyline"), ok = FALSE; if (ok && !CloseFigure (hdc)) WIN32_API_FAILED ("CloseFigure"), ok = FALSE; if (ok && !EndPath (hdc)) WIN32_API_FAILED ("EndPath"), ok = FALSE; if (ok && !filled) if (!WidenPath (hdc)) WIN32_API_FAILED ("WidenPath"), ok = FALSE; if (ok && !FillPath (hdc)) WIN32_API_FAILED ("FillPath"), ok = FALSE; if (hbr != NULL) if (!DeleteObject (hbr)) WIN32_API_FAILED ("DeleteObject"); } 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_API_FAILED ("Rectangle"); if (filled) SelectObject (hdc, oldpen); else SelectObject (hdc, oldbrush); } gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND); } static void gdk_win32_draw_arc (GdkDrawable *drawable, GdkGC *gc, gint filled, gint x, gint y, gint width, gint height, gint angle1, gint angle2) { GdkGCPrivate *gc_private; HDC hdc; int nXStartArc, nYStartArc, nXEndArc, nYEndArc; gc_private = (GdkGCPrivate*) gc; GDK_NOTE (MISC, g_print ("gdk_draw_arc: %#x %d,%d,%d,%d %d %d\n", GDK_DRAWABLE_XID (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 (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.); } /* GDK_OPAQUE_STIPPLED arcs not implemented. */ 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)); Pie (hdc, x, y, x+width, y+height, nXStartArc, nYStartArc, nXEndArc, nYEndArc); } 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); } gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND); } } static void gdk_win32_draw_polygon (GdkDrawable *drawable, GdkGC *gc, gint filled, GdkPoint *points, gint npoints) { GdkGCPrivate *gc_private = (GdkGCPrivate*) gc; GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private); HDC hdc; HBRUSH hbr = NULL; 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, npoints)); if (npoints < 2) return; hdc = gdk_gc_predraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND); pts = g_new (POINT, npoints+1); for (i = 0; i < npoints; i++) { pts[i].x = points[i].x; pts[i].y = points[i].y; } if (gc_data->fill_style == GDK_OPAQUE_STIPPLED) { if (!BeginPath (hdc)) WIN32_API_FAILED ("BeginPath"), ok = FALSE; MoveToEx (hdc, points[0].x, points[0].y, NULL); if (pts[0].x == pts[npoints-1].x && pts[0].y == pts[npoints-1].y) npoints--; if (ok && !Polyline (hdc, pts, 4)) WIN32_API_FAILED ("Polyline"), ok = FALSE; if (ok && !CloseFigure (hdc)) WIN32_API_FAILED ("CloseFigure"), ok = FALSE; if (ok && !EndPath (hdc)) WIN32_API_FAILED ("EndPath"), ok = FALSE; if (ok && !filled) if (!WidenPath (hdc)) WIN32_API_FAILED ("WidenPath"), ok = FALSE; if (ok && !FillPath (hdc)) WIN32_API_FAILED ("FillPath"), ok = FALSE; if (hbr != NULL) if (!DeleteObject (hbr)) WIN32_API_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_API_FAILED ("Polygon"); } else { if (!Polyline (hdc, pts, npoints)) WIN32_API_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; static void gdk_draw_text_handler (GdkWin32SingleFont *singlefont, const wchar_t *wcstr, int wclen, void *arg) { HGDIOBJ oldfont; SIZE size; gdk_draw_text_arg *argp = (gdk_draw_text_arg *) arg; if (!singlefont) return; if ((oldfont = SelectObject (argp->hdc, singlefont->xfont)) == NULL) { WIN32_API_FAILED ("SelectObject"); return; } if (!TextOutW (argp->hdc, argp->x, argp->y, wcstr, wclen)) WIN32_API_FAILED ("TextOutW"); GetTextExtentPoint32W (argp->hdc, wcstr, wclen, &size); argp->x += size.cx; SelectObject (argp->hdc, oldfont); } static void gdk_win32_draw_text (GdkDrawable *drawable, GdkFont *font, GdkGC *gc, gint x, gint y, const gchar *text, gint text_length) { GdkGCPrivate *gc_private; wchar_t *wcstr; gint 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); GDK_NOTE (MISC, g_print ("gdk_draw_text: %#x (%d,%d) \"%.*s\" (len %d)\n", GDK_DRAWABLE_XID (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"); else 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); } static void gdk_win32_draw_text_wc (GdkDrawable *drawable, GdkFont *font, GdkGC *gc, gint x, gint y, const GdkWChar *text, gint text_length) { GdkGCPrivate *gc_private; gint i, wlen; 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); GDK_NOTE (MISC, g_print ("gdk_draw_text_wc: %#x (%d,%d) len: %d\n", GDK_DRAWABLE_XID (drawable), x, y, text_length)); if (sizeof (wchar_t) != sizeof (GdkWChar)) { wcstr = g_new (wchar_t, text_length); for (i = 0; i < text_length; i++) wcstr[i] = text[i]; } else wcstr = (wchar_t *) text; 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); } static void gdk_win32_draw_drawable (GdkDrawable *drawable, GdkGC *gc, GdkPixmap *src, gint xsrc, gint ysrc, gint xdest, gint ydest, gint width, gint height) { GdkDrawablePrivate *src_private; GdkGCPrivate *gc_private; HDC hdc; HDC srcdc; HGDIOBJ hgdiobj; HRGN src_rgn, draw_rgn, outside_rgn; RECT r; src_private = (GdkDrawablePrivate*) src; gc_private = (GdkGCPrivate*) gc; 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)); hdc = gdk_gc_predraw (drawable, gc_private, 0); 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) { /* 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) { 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); } } #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"); 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 DeleteObject (src_rgn); DeleteObject (draw_rgn); DeleteObject (outside_rgn); /* Strangely enough, this function is called also to bitblt * from a window. */ if (src_private->window_type == GDK_DRAWABLE_PIXMAP) { if ((srcdc = CreateCompatibleDC (hdc)) == NULL) WIN32_API_FAILED ("CreateCompatibleDC"); if ((hgdiobj = SelectObject (srcdc, GDK_DRAWABLE_XID (src))) == NULL) WIN32_API_FAILED ("SelectObject #1"); if (!BitBlt (hdc, xdest, ydest, width, height, srcdc, xsrc, ysrc, SRCCOPY)) WIN32_API_FAILED ("BitBlt"); if ((SelectObject (srcdc, hgdiobj) == NULL)) WIN32_API_FAILED ("SelectObject #2"); if (!DeleteDC (srcdc)) WIN32_API_FAILED ("DeleteDC"); } else { if (GDK_DRAWABLE_XID(drawable) == GDK_DRAWABLE_XID (src)) { /* 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_API_FAILED ("ScrollDC"); if (!InvalidateRgn (GDK_DRAWABLE_XID (drawable), updateRgn, FALSE)) WIN32_API_FAILED ("InvalidateRgn"); if (!UpdateWindow (GDK_DRAWABLE_XID (drawable))) WIN32_API_FAILED ("UpdateWindow"); } else { if ((srcdc = GetDC (GDK_DRAWABLE_XID (src))) == NULL) WIN32_API_FAILED ("GetDC"); if (!BitBlt (hdc, xdest, ydest, width, height, srcdc, xsrc, ysrc, SRCCOPY)) WIN32_API_FAILED ("BitBlt"); ReleaseDC (GDK_DRAWABLE_XID (src), srcdc); } } gdk_gc_postdraw (drawable, gc_private, 0); } static void gdk_win32_draw_points (GdkDrawable *drawable, GdkGC *gc, GdkPoint *points, gint npoints) { GdkGCPrivate *gc_private = (GdkGCPrivate*) gc; GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private); HDC hdc; COLORREF fg; int i; GDK_NOTE (MISC, g_print ("gdk_draw_points: %#x destdc: (%d) %#x " "npoints: %d\n", GDK_DRAWABLE_XID (drawable), gc_private, hdc, npoints)); hdc = gdk_gc_predraw (drawable, gc_private, GDK_GC_FOREGROUND); fg = GetTextColor (hdc); for (i = 0; i < npoints; i++) { SetPixel (hdc, points[i].x, points[i].y, fg); } gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND); } static void gdk_win32_draw_segments (GdkDrawable *drawable, GdkGC *gc, GdkSegment *segs, gint nsegs) { GdkGCPrivate *gc_private = (GdkGCPrivate*) gc; GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private); HDC hdc; HBRUSH hbr = NULL; gboolean ok = TRUE; int i; GDK_NOTE (MISC, g_print ("gdk_win32_draw_segments: %#x destdc: (%d) %#x " "nsegs: %d\n", GDK_DRAWABLE_XID (drawable), gc_private, hdc, nsegs)); hdc = gdk_gc_predraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND); if (gc_data->fill_style == GDK_OPAQUE_STIPPLED) { if (!BeginPath (hdc)) WIN32_API_FAILED ("BeginPath"), ok = FALSE; for (i = 0; i < nsegs; i++) { if (ok && !MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL)) WIN32_API_FAILED ("MoveToEx"), ok = FALSE; if (ok && !LineTo (hdc, segs[i].x2, segs[i].y2)) WIN32_API_FAILED ("LineTo #1"), ok = FALSE; /* Draw end pixel */ if (ok && gc_data->pen_width == 1) if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2)) WIN32_API_FAILED ("LineTo #2"), ok = FALSE; } if (ok && !EndPath (hdc)) WIN32_API_FAILED ("EndPath"), ok = FALSE; if (ok && !WidenPath (hdc)) WIN32_API_FAILED ("WidenPath"), ok = FALSE; if (ok && !FillPath (hdc)) WIN32_API_FAILED ("FillPath"), ok = FALSE; if (hbr != NULL) if (!DeleteObject (hbr)) WIN32_API_FAILED ("DeleteObject"); } else { for (i = 0; i < nsegs; i++) { if (!MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL)) WIN32_API_FAILED ("MoveToEx"); if (!LineTo (hdc, segs[i].x2, segs[i].y2)) WIN32_API_FAILED ("LineTo #1"); /* Draw end pixel */ if (gc_data->pen_width == 1) if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2)) WIN32_API_FAILED ("LineTo #2"); } } 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) { GdkGCPrivate *gc_private = (GdkGCPrivate*) gc; GdkGCWin32Data *gc_data = GDK_GC_WIN32DATA (gc_private); HDC hdc; POINT *pts; int i; if (npoints < 2) return; hdc = gdk_gc_predraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND); #if 1 pts = g_new (POINT, npoints); for (i = 0; i < npoints; i++) { pts[i].x = points[i].x; pts[i].y = points[i].y; } if (!Polyline (hdc, pts, npoints)) WIN32_API_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_API_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_API_FAILED ("LineTo #1"); /* 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_API_FAILED ("LineTo #2"); #endif gdk_gc_postdraw (drawable, gc_private, GDK_GC_FOREGROUND|GDK_GC_BACKGROUND); }