mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-28 14:31:10 +00:00
2823963703
2000-07-12 Tor Lillqvist <tml@iki.fi> Win32 changes, still doesn't build though. * gdk/makefile.cygwin * gdk/win32/makefile.cygwin * gtk/makefile.cygwin: Updates. * gdk/win32/gdkgc-win32.c (_gdk_win32_gc_new): Use the same default values for fg and bg pixel as X11 does (0 and 1), not black and white. Use PS_ENDCAP_FLAT and PS_JOIN_MITER by default. Use 0 for pen width by default (treated as 1 anyway later, but for apps that might check the value in the GdkGC). (gdk_win32_hdc_get, gdk_win32_hdc_release): New functions, public interface to gdk_gc_predraw and _postdraw. * gdk/win32/gdkwin32.h * gdk/gdk.def: Add gdk_win32_hdc_{get,release}. * gdk/win32/gdkcolor-win32.c (gdk_colormap_alloc1): Remove extraneous semicolon. * gdk/win32/gdkdrawable-win32.c: Check also for pen_width == 0. * gdk/win32/gdkimage-win32.c (gdk_image_new): Use the visual's depth, not the Win32 bitspixel value.
885 lines
24 KiB
C
885 lines
24 KiB
C
/* 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 <math.h>
|
|
#include <glib.h>
|
|
|
|
#ifndef G_PI
|
|
#define G_PI 3.14159265358979323846
|
|
#endif
|
|
|
|
#include "gdkinternals.h"
|
|
#include "gdkprivate-win32.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_GDI_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_GDI_FAILED ("Polyline"), ok = FALSE;
|
|
|
|
if (ok && !CloseFigure (hdc))
|
|
WIN32_GDI_FAILED ("CloseFigure"), ok = FALSE;
|
|
|
|
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 (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");
|
|
|
|
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));
|
|
|
|
/* Seems that drawing arcs with width or height <= 2 fails, at least
|
|
* with my TNT card.
|
|
*/
|
|
if (width > 2 && height > 2 && 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));
|
|
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);
|
|
}
|
|
}
|
|
|
|
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_GDI_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_GDI_FAILED ("Polyline"), ok = FALSE;
|
|
|
|
if (ok && !CloseFigure (hdc))
|
|
WIN32_GDI_FAILED ("CloseFigure"), ok = FALSE;
|
|
|
|
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;
|
|
|
|
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_GDI_FAILED ("SelectObject");
|
|
return;
|
|
}
|
|
|
|
if (!TextOutW (argp->hdc, argp->x, argp->y, wcstr, wclen))
|
|
WIN32_GDI_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 (text_length == 1)
|
|
{
|
|
/* For single characters, don't try to interpret as UTF-8. */
|
|
wcstr[0] = (guchar) text[0];
|
|
gdk_wchar_text_handle (font, wcstr, 1, gdk_draw_text_handler, &arg);
|
|
}
|
|
else
|
|
{
|
|
if ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1)
|
|
g_warning ("gdk_win32_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_win32_draw_drawable: 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_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");
|
|
}
|
|
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_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");
|
|
}
|
|
else
|
|
{
|
|
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_gc_postdraw (drawable, gc_private, 0);
|
|
}
|
|
|
|
static void
|
|
gdk_win32_draw_points (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkPoint *points,
|
|
gint npoints)
|
|
{
|
|
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;
|
|
|
|
hdc = gdk_gc_predraw (drawable, gc_private, 0);
|
|
|
|
fg = gdk_colormap_color (colormap_private, gc_data->foreground);
|
|
|
|
GDK_NOTE (MISC, g_print ("gdk_draw_points: %#x %dx%.06x\n",
|
|
GDK_DRAWABLE_XID (drawable), npoints, fg));
|
|
|
|
for (i = 0; i < npoints; i++)
|
|
SetPixel (hdc, points[i].x, points[i].y, fg);
|
|
|
|
gdk_gc_postdraw (drawable, gc_private, 0);
|
|
}
|
|
|
|
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 nsegs: %d\n",
|
|
GDK_DRAWABLE_XID (drawable), 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_GDI_FAILED ("BeginPath"), ok = FALSE;
|
|
|
|
for (i = 0; i < nsegs; i++)
|
|
{
|
|
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;
|
|
|
|
/* 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 (ok && !EndPath (hdc))
|
|
WIN32_GDI_FAILED ("EndPath"), ok = FALSE;
|
|
|
|
if (ok && !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
|
|
{
|
|
for (i = 0; i < nsegs; i++)
|
|
{
|
|
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");
|
|
|
|
/* Draw end pixel */
|
|
if (gc_data->pen_width <= 1)
|
|
if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
|
|
WIN32_GDI_FAILED ("LineTo");
|
|
}
|
|
}
|
|
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_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);
|
|
}
|