forked from AuroraMiddleware/gtk
ef2c2326f0
2005-10-01 Tor Lillqvist <tml@novell.com> * gdk/win32/gdkdrawable-win32.c (blit_from_pixmap): In case BitBlt() fails with ERROR_INVALID_HANDLE, the most probable cause is that the the desktop isn't visible because the session has been switched, the screen is locked, or a terminal server session disconnected, so no error message necessary. (#137796) It is of course remotely possible that BitBlt() failing with ERROR_INVALID_HANDLE might also be caused by some other problem. We could strive for perfection and track whether the desktop is visible by using WTSRegisterSessionNotification() and handling WM_WTSESSION_CHANGE. I think that's overdoing it just for this issue, though. If we would track desktop visibility, we should then avoid even trying to update the display at all while the desktop isn't visible.
1993 lines
54 KiB
C
1993 lines
54 KiB
C
/* 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 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* 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-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 <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;
|
|
|
|
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;
|
|
}
|
|
|
|
static void
|
|
gdk_drawable_impl_win32_class_init (GdkDrawableImplWin32Class *klass)
|
|
{
|
|
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;
|
|
}
|
|
|
|
static void
|
|
gdk_drawable_impl_win32_finalize (GObject *object)
|
|
{
|
|
gdk_drawable_set_colormap (GDK_DRAWABLE (object), NULL);
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
}
|
|
|
|
/*****************************************************
|
|
* Win32 specific implementations of generic functions *
|
|
*****************************************************/
|
|
|
|
static GdkColormap*
|
|
gdk_win32_get_colormap (GdkDrawable *drawable)
|
|
{
|
|
return GDK_DRAWABLE_IMPL_WIN32 (drawable)->colormap;
|
|
}
|
|
|
|
static void
|
|
gdk_win32_set_colormap (GdkDrawable *drawable,
|
|
GdkColormap *colormap)
|
|
{
|
|
GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
|
|
|
|
if (impl->colormap == colormap)
|
|
return;
|
|
|
|
if (impl->colormap)
|
|
gdk_colormap_unref (impl->colormap);
|
|
impl->colormap = colormap;
|
|
if (impl->colormap)
|
|
gdk_colormap_ref (impl->colormap);
|
|
}
|
|
|
|
/* Drawing
|
|
*/
|
|
|
|
static int
|
|
rop2_to_rop3 (int rop2)
|
|
{
|
|
switch (rop2)
|
|
{
|
|
/* Oh, Microsoft's silly names for binary and ternary rops. */
|
|
#define CASE(rop2,rop3) case R2_##rop2: return rop3
|
|
CASE (BLACK, BLACKNESS);
|
|
CASE (NOTMERGEPEN, NOTSRCERASE);
|
|
CASE (MASKNOTPEN, 0x00220326);
|
|
CASE (NOTCOPYPEN, NOTSRCCOPY);
|
|
CASE (MASKPENNOT, SRCERASE);
|
|
CASE (NOT, DSTINVERT);
|
|
CASE (XORPEN, SRCINVERT);
|
|
CASE (NOTMASKPEN, 0x007700E6);
|
|
CASE (MASKPEN, SRCAND);
|
|
CASE (NOTXORPEN, 0x00990066);
|
|
CASE (NOP, 0x00AA0029);
|
|
CASE (MERGENOTPEN, MERGEPAINT);
|
|
CASE (COPYPEN, SRCCOPY);
|
|
CASE (MERGEPENNOT, 0x00DD0228);
|
|
CASE (MERGEPEN, SRCPAINT);
|
|
CASE (WHITE, WHITENESS);
|
|
#undef CASE
|
|
default: return SRCCOPY;
|
|
}
|
|
}
|
|
|
|
static int
|
|
rop2_to_patblt_rop (int rop2)
|
|
{
|
|
switch (rop2)
|
|
{
|
|
#define CASE(rop2,patblt_rop) case R2_##rop2: return patblt_rop
|
|
CASE (COPYPEN, PATCOPY);
|
|
CASE (XORPEN, PATINVERT);
|
|
CASE (NOT, DSTINVERT);
|
|
CASE (BLACK, BLACKNESS);
|
|
CASE (WHITE, WHITENESS);
|
|
#undef CASE
|
|
default:
|
|
g_warning ("Unhandled rop2 in GC to be used in PatBlt: %#x", rop2);
|
|
return PATCOPY;
|
|
}
|
|
}
|
|
|
|
static inline int
|
|
align_with_dash_offset (int a, DWORD *dashes, int num_dashes, GdkGCWin32 *gcwin32)
|
|
{
|
|
int n = 0;
|
|
int len_sum = 0;
|
|
/*
|
|
* We can't simply add the dashoffset, it can be an arbitrary larger
|
|
* or smaller value not even between x1 and x2. It just says use the
|
|
* dash pattern aligned to the offset. So ensure x1 is smaller _x1
|
|
* and we start with the appropriate dash.
|
|
*/
|
|
for (n = 0; n < num_dashes; n++)
|
|
len_sum += dashes[n];
|
|
if ( len_sum > 0 /* pathological api usage? */
|
|
&& gcwin32->pen_dash_offset > a)
|
|
a -= (((gcwin32->pen_dash_offset/len_sum - a/len_sum) + 1) * len_sum);
|
|
else
|
|
a = gcwin32->pen_dash_offset;
|
|
|
|
return a;
|
|
}
|
|
|
|
/* Render a dashed line 'by hand'. Used for all dashes on Win9x (where
|
|
* GDI is way too limited), and for double dashes on all Windowses.
|
|
*/
|
|
static inline gboolean
|
|
render_line_horizontal (GdkGCWin32 *gcwin32,
|
|
int x1,
|
|
int x2,
|
|
int y)
|
|
{
|
|
int n = 0;
|
|
const int pen_width = MAX (gcwin32->pen_width, 1);
|
|
const int _x1 = x1;
|
|
|
|
g_assert (gcwin32->pen_dashes);
|
|
|
|
x1 = align_with_dash_offset (x1, gcwin32->pen_dashes, gcwin32->pen_num_dashes, gcwin32);
|
|
|
|
for (n = 0; x1 < x2; n++)
|
|
{
|
|
int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
|
|
if (x1 + len > x2)
|
|
len = x2 - x1;
|
|
|
|
if (n % 2 == 0 && x1 + len > _x1)
|
|
if (!GDI_CALL (PatBlt, (gcwin32->hdc,
|
|
x1 < _x1 ? _x1 : x1,
|
|
y - pen_width / 2,
|
|
len, pen_width,
|
|
rop2_to_patblt_rop (gcwin32->rop2))))
|
|
return FALSE;
|
|
|
|
x1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
|
|
}
|
|
|
|
if (gcwin32->line_style == GDK_LINE_DOUBLE_DASH)
|
|
{
|
|
HBRUSH hbr;
|
|
|
|
if ((hbr = SelectObject (gcwin32->hdc, gcwin32->pen_hbrbg)) == HGDI_ERROR)
|
|
return FALSE;
|
|
x1 = _x1;
|
|
x1 += gcwin32->pen_dash_offset;
|
|
for (n = 0; x1 < x2; n++)
|
|
{
|
|
int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
|
|
if (x1 + len > x2)
|
|
len = x2 - x1;
|
|
|
|
if (n % 2)
|
|
if (!GDI_CALL (PatBlt, (gcwin32->hdc, x1, y - pen_width / 2,
|
|
len, pen_width,
|
|
rop2_to_patblt_rop (gcwin32->rop2))))
|
|
return FALSE;
|
|
|
|
x1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
|
|
}
|
|
if (SelectObject (gcwin32->hdc, hbr) == HGDI_ERROR)
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static inline gboolean
|
|
render_line_vertical (GdkGCWin32 *gcwin32,
|
|
int x,
|
|
int y1,
|
|
int y2)
|
|
{
|
|
int n;
|
|
const int pen_width = MAX (gcwin32->pen_width, 1);
|
|
const int _y1 = y1;
|
|
|
|
g_assert (gcwin32->pen_dashes);
|
|
|
|
y1 = align_with_dash_offset (y1, gcwin32->pen_dashes, gcwin32->pen_num_dashes, gcwin32);
|
|
for (n = 0; y1 < y2; n++)
|
|
{
|
|
int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
|
|
if (y1 + len > y2)
|
|
len = y2 - y1;
|
|
if (n % 2 == 0 && y1 + len > _y1)
|
|
if (!GDI_CALL (PatBlt, (gcwin32->hdc, x - pen_width / 2,
|
|
y1 < _y1 ? _y1 : y1,
|
|
pen_width, len,
|
|
rop2_to_patblt_rop (gcwin32->rop2))))
|
|
return FALSE;
|
|
|
|
y1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
|
|
}
|
|
|
|
if (gcwin32->line_style == GDK_LINE_DOUBLE_DASH)
|
|
{
|
|
HBRUSH hbr;
|
|
|
|
if ((hbr = SelectObject (gcwin32->hdc, gcwin32->pen_hbrbg)) == HGDI_ERROR)
|
|
return FALSE;
|
|
y1 = _y1;
|
|
y1 += gcwin32->pen_dash_offset;
|
|
for (n = 0; y1 < y2; n++)
|
|
{
|
|
int len = gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
|
|
if (y1 + len > y2)
|
|
len = y2 - y1;
|
|
if (n % 2)
|
|
if (!GDI_CALL (PatBlt, (gcwin32->hdc, x - pen_width / 2, y1,
|
|
pen_width, len,
|
|
rop2_to_patblt_rop (gcwin32->rop2))))
|
|
return FALSE;
|
|
|
|
y1 += gcwin32->pen_dashes[n % gcwin32->pen_num_dashes];
|
|
}
|
|
if (SelectObject (gcwin32->hdc, hbr) == HGDI_ERROR)
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
draw_tiles_lowlevel (HDC dest,
|
|
HDC tile,
|
|
int rop3,
|
|
gint dest_x,
|
|
gint dest_y,
|
|
gint tile_x_origin,
|
|
gint tile_y_origin,
|
|
gint width,
|
|
gint height,
|
|
gint tile_width,
|
|
gint tile_height)
|
|
{
|
|
gint x, y;
|
|
|
|
GDK_NOTE (MISC, g_print ("draw_tiles_lowlevel: %p %+d%+d tile=%p:%dx%d@%+d%+d %dx%d\n",
|
|
dest,
|
|
dest_x, dest_y,
|
|
tile, tile_width, tile_height,
|
|
tile_x_origin, tile_y_origin,
|
|
width, height));
|
|
|
|
y = tile_y_origin % tile_height;
|
|
if (y > 0)
|
|
y -= tile_height;
|
|
while (y < dest_y + height)
|
|
{
|
|
if (y + tile_height >= dest_y)
|
|
{
|
|
x = tile_x_origin % tile_width;
|
|
if (x > 0)
|
|
x -= tile_width;
|
|
while (x < dest_x + width)
|
|
{
|
|
if (x + tile_width >= dest_x)
|
|
{
|
|
gint src_x = MAX (0, dest_x - x);
|
|
gint src_y = MAX (0, dest_y - y);
|
|
|
|
if (!GDI_CALL (BitBlt, (dest, x + src_x, y + src_y,
|
|
MIN (tile_width, dest_x + width - (x + src_x)),
|
|
MIN (tile_height, dest_y + height - (y + src_y)),
|
|
tile,
|
|
src_x, src_y,
|
|
rop3)))
|
|
return;
|
|
}
|
|
x += tile_width;
|
|
}
|
|
}
|
|
y += tile_height;
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_tiles (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
int rop3,
|
|
GdkPixmap *tile,
|
|
gint dest_x,
|
|
gint dest_y,
|
|
gint tile_x_origin,
|
|
gint tile_y_origin,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
const GdkGCValuesMask mask = GDK_GC_FOREGROUND;
|
|
gint tile_width, tile_height;
|
|
GdkGC *gc_copy;
|
|
HDC dest_hdc, tile_hdc;
|
|
|
|
gc_copy = gdk_gc_new (tile);
|
|
gdk_gc_copy (gc_copy, gc);
|
|
dest_hdc = gdk_win32_hdc_get (drawable, gc, mask);
|
|
tile_hdc = gdk_win32_hdc_get (tile, gc_copy, mask);
|
|
|
|
gdk_drawable_get_size (tile, &tile_width, &tile_height);
|
|
|
|
draw_tiles_lowlevel (dest_hdc, tile_hdc, rop3,
|
|
dest_x, dest_y, tile_x_origin, tile_y_origin,
|
|
width, height, tile_width, tile_height);
|
|
|
|
gdk_win32_hdc_release (drawable, gc, mask);
|
|
gdk_win32_hdc_release (tile, gc_copy, mask);
|
|
gdk_gc_unref (gc_copy);
|
|
}
|
|
|
|
static void
|
|
generic_draw (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkGCValuesMask mask,
|
|
void (*function) (GdkGCWin32 *, HDC, gint, gint, va_list),
|
|
const GdkRegion *region,
|
|
...)
|
|
{
|
|
GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
|
|
GdkGCWin32 *gcwin32 = GDK_GC_WIN32 (gc);
|
|
HDC hdc;
|
|
va_list args;
|
|
GdkFill fill_style = _gdk_gc_get_fill (gc);
|
|
|
|
va_start (args, region);
|
|
|
|
/* If tiled or stippled, draw to a temp pixmap and do blitting magic.
|
|
*/
|
|
|
|
if (gcwin32->values_mask & GDK_GC_FILL &&
|
|
((fill_style == GDK_TILED &&
|
|
gcwin32->values_mask & GDK_GC_TILE &&
|
|
_gdk_gc_get_tile (gc) != NULL)
|
|
||
|
|
((fill_style == GDK_OPAQUE_STIPPLED ||
|
|
fill_style == GDK_STIPPLED) &&
|
|
gcwin32->values_mask & GDK_GC_STIPPLE &&
|
|
_gdk_gc_get_stipple (gc) != NULL)))
|
|
{
|
|
const GdkGCValuesMask blitting_mask = 0;
|
|
GdkGCValuesMask drawing_mask = GDK_GC_FOREGROUND;
|
|
gint ts_x_origin = 0, ts_y_origin = 0;
|
|
|
|
gint width = region->extents.x2 - region->extents.x1;
|
|
gint height = region->extents.y2 - region->extents.y1;
|
|
|
|
GdkPixmap *mask_pixmap =
|
|
gdk_pixmap_new (drawable, width, height, 1);
|
|
GdkPixmap *tile_pixmap =
|
|
gdk_pixmap_new (drawable, width, height, -1);
|
|
GdkPixmap *stipple_bitmap = NULL;
|
|
GdkColor fg;
|
|
|
|
GdkGC *mask_gc = gdk_gc_new (mask_pixmap);
|
|
GdkGC *tile_gc = gdk_gc_new (tile_pixmap);
|
|
|
|
HDC mask_hdc;
|
|
HDC tile_hdc;
|
|
|
|
HGDIOBJ old_mask_hbm;
|
|
HGDIOBJ old_tile_hbm;
|
|
|
|
GdkGCValues gcvalues;
|
|
|
|
hdc = gdk_win32_hdc_get (drawable, gc, blitting_mask);
|
|
tile_hdc = CreateCompatibleDC (hdc);
|
|
|
|
if (gcwin32->values_mask & GDK_GC_TS_X_ORIGIN)
|
|
ts_x_origin = gc->ts_x_origin;
|
|
if (gcwin32->values_mask & GDK_GC_TS_Y_ORIGIN)
|
|
ts_y_origin = gc->ts_y_origin;
|
|
|
|
ts_x_origin -= region->extents.x1;
|
|
ts_y_origin -= region->extents.y1;
|
|
|
|
/* Fill mask bitmap with zeros */
|
|
gdk_gc_set_function (mask_gc, GDK_CLEAR);
|
|
gdk_draw_rectangle (mask_pixmap, mask_gc, TRUE,
|
|
0, 0, width, height);
|
|
|
|
/* Paint into mask bitmap, drawing ones */
|
|
gdk_gc_set_function (mask_gc, GDK_COPY);
|
|
fg.pixel = 1;
|
|
gdk_gc_set_foreground (mask_gc, &fg);
|
|
|
|
/* If the drawing function uses line attributes, set them as in
|
|
* the real GC.
|
|
*/
|
|
if (mask & LINE_ATTRIBUTES)
|
|
{
|
|
gdk_gc_get_values (gc, &gcvalues);
|
|
if (gcvalues.line_width != 0 ||
|
|
gcvalues.line_style != GDK_LINE_SOLID ||
|
|
gcvalues.cap_style != GDK_CAP_BUTT ||
|
|
gcvalues.join_style != GDK_JOIN_MITER)
|
|
gdk_gc_set_line_attributes (mask_gc,
|
|
gcvalues.line_width,
|
|
gcvalues.line_style,
|
|
gcvalues.cap_style,
|
|
gcvalues.join_style);
|
|
drawing_mask |= LINE_ATTRIBUTES;
|
|
}
|
|
|
|
/* Ditto, if the drawing function draws text, set up for that. */
|
|
if (mask & GDK_GC_FONT)
|
|
drawing_mask |= GDK_GC_FONT;
|
|
|
|
mask_hdc = gdk_win32_hdc_get (mask_pixmap, mask_gc, drawing_mask);
|
|
(*function) (GDK_GC_WIN32 (mask_gc), mask_hdc,
|
|
region->extents.x1, region->extents.y1, args);
|
|
gdk_win32_hdc_release (mask_pixmap, mask_gc, drawing_mask);
|
|
|
|
if (fill_style == GDK_TILED)
|
|
{
|
|
/* Tile pixmap with tile */
|
|
draw_tiles (tile_pixmap, tile_gc, SRCCOPY,
|
|
_gdk_gc_get_tile (gc),
|
|
0, 0, ts_x_origin, ts_y_origin,
|
|
width, height);
|
|
}
|
|
else
|
|
{
|
|
/* Tile with stipple */
|
|
GdkGC *stipple_gc;
|
|
|
|
stipple_bitmap = gdk_pixmap_new (NULL, width, height, 1);
|
|
stipple_gc = gdk_gc_new (stipple_bitmap);
|
|
|
|
/* Tile stipple bitmap */
|
|
draw_tiles (stipple_bitmap, stipple_gc, SRCCOPY,
|
|
_gdk_gc_get_stipple (gc),
|
|
0, 0, ts_x_origin, ts_y_origin,
|
|
width, height);
|
|
|
|
if (fill_style == GDK_OPAQUE_STIPPLED)
|
|
{
|
|
/* Fill tile pixmap with background */
|
|
fg.pixel = _gdk_gc_get_bg_pixel (gc);
|
|
gdk_gc_set_foreground (tile_gc, &fg);
|
|
gdk_draw_rectangle (tile_pixmap, tile_gc, TRUE,
|
|
0, 0, width, height);
|
|
}
|
|
gdk_gc_unref (stipple_gc);
|
|
}
|
|
|
|
gdk_gc_unref (mask_gc);
|
|
gdk_gc_unref (tile_gc);
|
|
|
|
mask_hdc = CreateCompatibleDC (hdc);
|
|
|
|
if ((old_mask_hbm = SelectObject (mask_hdc, GDK_PIXMAP_HBITMAP (mask_pixmap))) == NULL)
|
|
WIN32_GDI_FAILED ("SelectObject");
|
|
|
|
if ((old_tile_hbm = SelectObject (tile_hdc, GDK_PIXMAP_HBITMAP (tile_pixmap))) == NULL)
|
|
WIN32_GDI_FAILED ("SelectObject");
|
|
|
|
if (fill_style == GDK_STIPPLED ||
|
|
fill_style == GDK_OPAQUE_STIPPLED)
|
|
{
|
|
HDC stipple_hdc;
|
|
HGDIOBJ old_stipple_hbm;
|
|
HBRUSH fg_brush;
|
|
HGDIOBJ old_tile_brush;
|
|
|
|
if ((stipple_hdc = CreateCompatibleDC (hdc)) == NULL)
|
|
WIN32_GDI_FAILED ("CreateCompatibleDC");
|
|
|
|
if ((old_stipple_hbm =
|
|
SelectObject (stipple_hdc,
|
|
GDK_PIXMAP_HBITMAP (stipple_bitmap))) == NULL)
|
|
WIN32_GDI_FAILED ("SelectObject");
|
|
|
|
if ((fg_brush = CreateSolidBrush
|
|
(_gdk_win32_colormap_color (impl->colormap,
|
|
_gdk_gc_get_fg_pixel (gc)))) == NULL)
|
|
WIN32_GDI_FAILED ("CreateSolidBrush");
|
|
|
|
if ((old_tile_brush = SelectObject (tile_hdc, fg_brush)) == NULL)
|
|
WIN32_GDI_FAILED ("SelectObject");
|
|
|
|
/* Paint tile with foreround where stipple is one
|
|
*
|
|
* Desired ternary ROP: (P=foreground, S=stipple, D=destination)
|
|
* P S D ?
|
|
* 0 0 0 0
|
|
* 0 0 1 1
|
|
* 0 1 0 0
|
|
* 0 1 1 0
|
|
* 1 0 0 0
|
|
* 1 0 1 1
|
|
* 1 1 0 1
|
|
* 1 1 1 1
|
|
*
|
|
* Reading bottom-up: 11100010 = 0xE2. PSDK docs say this is
|
|
* known as DSPDxax, with hex value 0x00E20746.
|
|
*/
|
|
GDI_CALL (BitBlt, (tile_hdc, 0, 0, width, height,
|
|
stipple_hdc, 0, 0, ROP3_DSPDxax));
|
|
|
|
if (fill_style == GDK_STIPPLED)
|
|
{
|
|
/* Punch holes in mask where stipple is zero */
|
|
GDI_CALL (BitBlt, (mask_hdc, 0, 0, width, height,
|
|
stipple_hdc, 0, 0, SRCAND));
|
|
}
|
|
|
|
GDI_CALL (SelectObject, (tile_hdc, old_tile_brush));
|
|
GDI_CALL (DeleteObject, (fg_brush));
|
|
GDI_CALL (SelectObject, (stipple_hdc, old_stipple_hbm));
|
|
GDI_CALL (DeleteDC, (stipple_hdc));
|
|
g_object_unref (stipple_bitmap);
|
|
}
|
|
|
|
/* Tile pixmap now contains the pattern that we should paint in
|
|
* the areas where mask is one. (It is filled with said pattern.)
|
|
*/
|
|
|
|
if (G_WIN32_IS_NT_BASED ())
|
|
{
|
|
GDI_CALL (MaskBlt, (hdc, region->extents.x1, region->extents.y1,
|
|
width, height,
|
|
tile_hdc, 0, 0,
|
|
GDK_PIXMAP_HBITMAP (mask_pixmap), 0, 0,
|
|
MAKEROP4 (rop2_to_rop3 (gcwin32->rop2), ROP3_D)));
|
|
}
|
|
else
|
|
{
|
|
GdkPixmap *temp1_pixmap =
|
|
gdk_pixmap_new (drawable, width, height, -1);
|
|
GdkPixmap *temp2_pixmap =
|
|
gdk_pixmap_new (drawable, width, height, -1);
|
|
HDC temp1_hdc = CreateCompatibleDC (hdc);
|
|
HDC temp2_hdc = CreateCompatibleDC (hdc);
|
|
HGDIOBJ old_temp1_hbm =
|
|
SelectObject (temp1_hdc, GDK_PIXMAP_HBITMAP (temp1_pixmap));
|
|
HGDIOBJ old_temp2_hbm =
|
|
SelectObject (temp2_hdc, GDK_PIXMAP_HBITMAP (temp2_pixmap));
|
|
|
|
/* Grab copy of dest region to temp1 */
|
|
GDI_CALL (BitBlt,(temp1_hdc, 0, 0, width, height,
|
|
hdc, region->extents.x1, region->extents.y1, SRCCOPY));
|
|
|
|
/* Paint tile to temp1 using correct function */
|
|
GDI_CALL (BitBlt, (temp1_hdc, 0, 0, width, height,
|
|
tile_hdc, 0, 0, rop2_to_rop3 (gcwin32->rop2)));
|
|
|
|
/* Mask out temp1 where function didn't paint */
|
|
GDI_CALL (BitBlt, (temp1_hdc, 0, 0, width, height,
|
|
mask_hdc, 0, 0, SRCAND));
|
|
|
|
/* Grab another copy of dest region to temp2 */
|
|
GDI_CALL (BitBlt, (temp2_hdc, 0, 0, width, height,
|
|
hdc, region->extents.x1, region->extents.y1, SRCCOPY));
|
|
|
|
/* Mask out temp2 where function did paint */
|
|
GDI_CALL (BitBlt, (temp2_hdc, 0, 0, width, height,
|
|
mask_hdc, 0, 0, ROP3_DSna));
|
|
|
|
/* Combine temp1 with temp2 */
|
|
GDI_CALL (BitBlt, (temp2_hdc, 0, 0, width, height,
|
|
temp1_hdc, 0, 0, SRCPAINT));
|
|
|
|
/* Blit back */
|
|
GDI_CALL (BitBlt, (hdc, region->extents.x1, region->extents.y1, width, height,
|
|
temp2_hdc, 0, 0, SRCCOPY));
|
|
|
|
/* Cleanup */
|
|
GDI_CALL (SelectObject, (temp1_hdc, old_temp1_hbm));
|
|
GDI_CALL (SelectObject, (temp2_hdc, old_temp2_hbm));
|
|
GDI_CALL (DeleteDC, (temp1_hdc));
|
|
GDI_CALL (DeleteDC, (temp2_hdc));
|
|
g_object_unref (temp1_pixmap);
|
|
g_object_unref (temp2_pixmap);
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
|
|
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));
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
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;
|
|
}
|
|
|
|
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++;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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->hfont)) == 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)
|
|
{
|
|
const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_FONT;
|
|
wchar_t *wcstr, wc;
|
|
glong wlen;
|
|
gdk_draw_text_arg arg;
|
|
|
|
if (text_length == 0)
|
|
return;
|
|
|
|
g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
|
|
|
|
arg.x = x;
|
|
arg.y = y;
|
|
arg.hdc = gdk_win32_hdc_get (drawable, gc, mask);
|
|
|
|
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));
|
|
|
|
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
|
|
{
|
|
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_win32_hdc_release (drawable, gc, mask);
|
|
}
|
|
|
|
static void
|
|
gdk_win32_draw_text_wc (GdkDrawable *drawable,
|
|
GdkFont *font,
|
|
GdkGC *gc,
|
|
gint x,
|
|
gint y,
|
|
const GdkWChar *text,
|
|
gint text_length)
|
|
{
|
|
const GdkGCValuesMask mask = GDK_GC_FOREGROUND|GDK_GC_FONT;
|
|
gint i;
|
|
wchar_t *wcstr;
|
|
gdk_draw_text_arg arg;
|
|
|
|
if (text_length == 0)
|
|
return;
|
|
|
|
g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
|
|
|
|
arg.x = x;
|
|
arg.y = y;
|
|
arg.hdc = gdk_win32_hdc_get (drawable, gc, mask);
|
|
|
|
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))
|
|
{
|
|
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_win32_hdc_release (drawable, gc, mask);
|
|
}
|
|
|
|
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;
|
|
HGDIOBJ old_pen;
|
|
int i;
|
|
|
|
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));
|
|
|
|
/* 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).
|
|
*/
|
|
|
|
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);
|
|
|
|
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)
|
|
{
|
|
/* must not modify in place, but could splice in the offset all below */
|
|
segs = g_memdup (segs, nsegs * sizeof (GdkSegment));
|
|
for (i = 0; i < nsegs; i++)
|
|
{
|
|
segs[i].x1 -= x_offset;
|
|
segs[i].y1 -= y_offset;
|
|
segs[i].x2 -= x_offset;
|
|
segs[i].y2 -= y_offset;
|
|
}
|
|
}
|
|
|
|
if (MUST_RENDER_DASHES_MANUALLY (gcwin32))
|
|
{
|
|
for (i = 0; i < nsegs; i++)
|
|
{
|
|
if (segs[i].x1 == segs[i].x2)
|
|
{
|
|
int y1, y2;
|
|
|
|
if (segs[i].y1 <= segs[i].y2)
|
|
y1 = segs[i].y1, y2 = segs[i].y2;
|
|
else
|
|
y1 = segs[i].y2, y2 = segs[i].y1;
|
|
|
|
render_line_vertical (gcwin32, segs[i].x1, y1, y2);
|
|
}
|
|
else if (segs[i].y1 == segs[i].y2)
|
|
{
|
|
int x1, x2;
|
|
|
|
if (segs[i].x1 <= segs[i].x2)
|
|
x1 = segs[i].x1, x2 = segs[i].x2;
|
|
else
|
|
x1 = segs[i].x2, x2 = segs[i].x1;
|
|
|
|
render_line_horizontal (gcwin32, x1, x2, segs[i].y1);
|
|
}
|
|
else
|
|
GDI_CALL (MoveToEx, (hdc, segs[i].x1, segs[i].y1, NULL)) &&
|
|
GDI_CALL (LineTo, (hdc, segs[i].x2, segs[i].y2));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < nsegs; i++)
|
|
{
|
|
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);
|
|
}
|
|
|
|
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);
|
|
|
|
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))
|
|
{
|
|
for (i = 0; i < npoints - 1; i++)
|
|
{
|
|
if (pts[i].x == pts[i+1].x)
|
|
{
|
|
int y1, y2;
|
|
if (pts[i].y > pts[i+1].y)
|
|
y1 = pts[i+1].y, y2 = pts[i].y;
|
|
else
|
|
y1 = pts[i].y, y2 = pts[i+1].y;
|
|
|
|
render_line_vertical (gcwin32, pts[i].x, y1, y2);
|
|
}
|
|
else if (pts[i].y == pts[i+1].y)
|
|
{
|
|
int x1, x2;
|
|
if (pts[i].x > pts[i+1].x)
|
|
x1 = pts[i+1].x, x2 = pts[i].x;
|
|
else
|
|
x1 = pts[i].x, x2 = pts[i+1].x;
|
|
|
|
render_line_horizontal (gcwin32, x1, x2, pts[i].y);
|
|
}
|
|
else
|
|
GDI_CALL (MoveToEx, (hdc, pts[i].x, pts[i].y, NULL)) &&
|
|
GDI_CALL (LineTo, (hdc, pts[i+1].x, pts[i+1].y));
|
|
}
|
|
}
|
|
else
|
|
GDI_CALL (Polyline, (hdc, pts, npoints));
|
|
}
|
|
|
|
static void
|
|
gdk_win32_draw_lines (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkPoint *points,
|
|
gint npoints)
|
|
{
|
|
GdkRectangle bounds;
|
|
GdkRegion *region;
|
|
POINT *pts;
|
|
int i;
|
|
|
|
GDK_NOTE (MISC, g_print ("gdk_win32_draw_lines: %s %d points\n",
|
|
_gdk_win32_drawable_description (drawable),
|
|
npoints));
|
|
|
|
if (npoints < 2)
|
|
return;
|
|
|
|
bounds.x = G_MAXINT;
|
|
bounds.y = G_MAXINT;
|
|
bounds.width = 0;
|
|
bounds.height = 0;
|
|
|
|
pts = g_new (POINT, npoints);
|
|
|
|
for (i = 0; i < npoints; i++)
|
|
{
|
|
bounds.x = MIN (bounds.x, points[i].x);
|
|
bounds.y = MIN (bounds.y, points[i].y);
|
|
pts[i].x = points[i].x;
|
|
pts[i].y = points[i].y;
|
|
}
|
|
|
|
for (i = 0; i < npoints; i++)
|
|
{
|
|
bounds.width = MAX (bounds.width, points[i].x - bounds.x);
|
|
bounds.height = MAX (bounds.height, points[i].y - bounds.y);
|
|
}
|
|
|
|
region = widen_bounds (&bounds, GDK_GC_WIN32 (gc)->pen_width);
|
|
|
|
generic_draw (drawable, gc, GDK_GC_FOREGROUND | GDK_GC_BACKGROUND |
|
|
LINE_ATTRIBUTES,
|
|
draw_lines, region, pts, npoints);
|
|
|
|
gdk_region_destroy (region);
|
|
g_free (pts);
|
|
}
|
|
|
|
static void
|
|
blit_from_pixmap (gboolean use_fg_bg,
|
|
GdkDrawableImplWin32 *dest,
|
|
HDC hdc,
|
|
GdkPixmapImplWin32 *src,
|
|
GdkGC *gc,
|
|
gint xsrc,
|
|
gint ysrc,
|
|
gint xdest,
|
|
gint ydest,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
GdkGCWin32 *gcwin32 = GDK_GC_WIN32 (gc);
|
|
HDC srcdc;
|
|
HBITMAP holdbitmap;
|
|
RGBQUAD oldtable[256], newtable[256];
|
|
COLORREF bg, fg;
|
|
|
|
gint newtable_size = 0, oldtable_size = 0;
|
|
gboolean ok = TRUE;
|
|
|
|
GDK_NOTE (MISC, g_print ("blit_from_pixmap\n"));
|
|
|
|
srcdc = _gdk_win32_drawable_acquire_dc (GDK_DRAWABLE (src));
|
|
if (!srcdc)
|
|
return;
|
|
|
|
if (!(holdbitmap = SelectObject (srcdc, ((GdkDrawableImplWin32 *) src)->handle)))
|
|
WIN32_GDI_FAILED ("SelectObject");
|
|
else
|
|
{
|
|
if (GDK_PIXMAP_OBJECT (src->parent_instance.wrapper)->depth <= 8)
|
|
{
|
|
/* Blitting 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;
|
|
}
|
|
}
|
|
|
|
if (ok)
|
|
if (!BitBlt (hdc, xdest, ydest, width, height,
|
|
srcdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)) &&
|
|
GetLastError () != ERROR_INVALID_HANDLE)
|
|
WIN32_GDI_FAILED ("BitBlt");
|
|
|
|
/* Restore source's color table if necessary */
|
|
if (ok && newtable_size > 0 && oldtable_size > 0)
|
|
{
|
|
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_win32_drawable_release_dc (GDK_DRAWABLE (src));
|
|
}
|
|
|
|
static void
|
|
blit_inside_drawable (HDC hdc,
|
|
GdkGCWin32 *gcwin32,
|
|
gint xsrc,
|
|
gint ysrc,
|
|
gint xdest,
|
|
gint ydest,
|
|
gint width,
|
|
gint height)
|
|
|
|
{
|
|
GDK_NOTE (MISC, g_print ("blit_inside_drawable\n"));
|
|
|
|
GDI_CALL (BitBlt, (hdc, xdest, ydest, width, height,
|
|
hdc, xsrc, ysrc, rop2_to_rop3 (gcwin32->rop2)));
|
|
}
|
|
|
|
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 ();
|
|
|
|
GDK_NOTE (MISC, g_print ("blit_from_window\n"));
|
|
|
|
if ((srcdc = GetDC (src->handle)) == NULL)
|
|
{
|
|
WIN32_GDI_FAILED ("GetDC");
|
|
return;
|
|
}
|
|
|
|
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_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)
|
|
{
|
|
HDC hdc;
|
|
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;
|
|
}
|
|
|
|
if (GDK_IS_DRAWABLE_IMPL_WIN32 (src))
|
|
src_impl = (GdkDrawableImplWin32 *) src;
|
|
else if (GDK_IS_WINDOW (src))
|
|
src_impl = (GdkDrawableImplWin32 *) GDK_WINDOW_OBJECT (src)->impl;
|
|
else if (GDK_IS_PIXMAP (src))
|
|
src_impl = (GdkDrawableImplWin32 *) GDK_PIXMAP_OBJECT (src)->impl;
|
|
else
|
|
g_assert_not_reached ();
|
|
|
|
hdc = gdk_win32_hdc_get (&draw_impl->parent_instance, gc, GDK_GC_FOREGROUND);
|
|
|
|
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);
|
|
}
|
|
|
|
static void
|
|
gdk_win32_draw_image (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkImage *image,
|
|
gint xsrc,
|
|
gint ysrc,
|
|
gint xdest,
|
|
gint ydest,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
g_assert (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable));
|
|
|
|
_gdk_win32_blit (TRUE, (GdkDrawableImplWin32 *) drawable,
|
|
gc, (GdkPixmap *) image->windowing_data,
|
|
xsrc, ysrc, xdest, ydest, width, height);
|
|
}
|
|
|
|
/**
|
|
* _gdk_win32_drawable_acquire_dc
|
|
* @drawable: a Win32 #GdkDrawable implementation
|
|
*
|
|
* Gets a DC with the given drawable selected into
|
|
* it.
|
|
*
|
|
* Return value: The DC, on success. Otherwise
|
|
* %NULL. If this function succeeded
|
|
* _gdk_win32_drawable_release_dc() must be called
|
|
* release the DC when you are done using it.
|
|
**/
|
|
HDC
|
|
_gdk_win32_drawable_acquire_dc (GdkDrawable *drawable)
|
|
{
|
|
GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
|
|
|
|
if (GDK_IS_WINDOW_IMPL_WIN32 (drawable) &&
|
|
GDK_WINDOW_DESTROYED (impl->wrapper))
|
|
return NULL;
|
|
|
|
if (!impl->hdc)
|
|
{
|
|
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");
|
|
}
|
|
}
|
|
|
|
if (impl->hdc)
|
|
{
|
|
impl->hdc_count++;
|
|
return impl->hdc;
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* _gdk_win32_drawable_release_dc
|
|
* @drawable: a Win32 #GdkDrawable implementation
|
|
*
|
|
* Releases the reference count for the DC
|
|
* from _gdk_win32_drawable_acquire_dc()
|
|
**/
|
|
void
|
|
_gdk_win32_drawable_release_dc (GdkDrawable *drawable)
|
|
{
|
|
GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
|
|
|
|
g_return_if_fail (impl->hdc_count > 0);
|
|
|
|
impl->hdc_count--;
|
|
if (impl->hdc_count == 0)
|
|
{
|
|
if (impl->saved_dc_bitmap)
|
|
{
|
|
GDI_CALL (SelectObject, (impl->hdc, impl->saved_dc_bitmap));
|
|
impl->saved_dc_bitmap = NULL;
|
|
}
|
|
|
|
if (impl->hdc)
|
|
{
|
|
GDI_CALL (DeleteDC, (impl->hdc));
|
|
impl->hdc = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
gdk_win32_cairo_surface_destroy (void *data)
|
|
{
|
|
GdkDrawableImplWin32 *impl = data;
|
|
|
|
_gdk_win32_drawable_release_dc (GDK_DRAWABLE (impl));
|
|
impl->cairo_surface = NULL;
|
|
}
|
|
|
|
static cairo_surface_t *
|
|
gdk_win32_ref_cairo_surface (GdkDrawable *drawable)
|
|
{
|
|
GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
|
|
|
|
if (GDK_IS_WINDOW_IMPL_WIN32 (drawable) &&
|
|
GDK_WINDOW_DESTROYED (impl->wrapper))
|
|
return NULL;
|
|
|
|
if (!impl->cairo_surface)
|
|
{
|
|
HDC hdc = _gdk_win32_drawable_acquire_dc (drawable);
|
|
if (!hdc)
|
|
return NULL;
|
|
|
|
impl->cairo_surface = cairo_win32_surface_create (hdc);
|
|
|
|
cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
|
|
drawable, gdk_win32_cairo_surface_destroy);
|
|
}
|
|
else
|
|
cairo_surface_reference (impl->cairo_surface);
|
|
|
|
return impl->cairo_surface;
|
|
}
|
|
|
|
static gint
|
|
gdk_win32_get_depth (GdkDrawable *drawable)
|
|
{
|
|
/* This is a bit bogus but I'm not sure the other way is better */
|
|
|
|
return gdk_drawable_get_depth (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
|
|
}
|
|
|
|
static GdkScreen*
|
|
gdk_win32_get_screen (GdkDrawable *drawable)
|
|
{
|
|
return gdk_screen_get_default ();
|
|
}
|
|
|
|
static GdkVisual*
|
|
gdk_win32_get_visual (GdkDrawable *drawable)
|
|
{
|
|
return gdk_drawable_get_visual (GDK_DRAWABLE_IMPL_WIN32 (drawable)->wrapper);
|
|
}
|
|
|
|
HGDIOBJ
|
|
gdk_win32_drawable_get_handle (GdkDrawable *drawable)
|
|
{
|
|
return GDK_DRAWABLE_HANDLE (drawable);
|
|
}
|
|
|
|
/**
|
|
* _gdk_win32_drawable_finish
|
|
* @drawable: a Win32 #GdkDrawable implementation
|
|
*
|
|
* Releases any resources allocated internally for the drawable.
|
|
* This is called when the drawable becomes unusable
|
|
* (gdk_window_destroy() for a window, or the refcount going to
|
|
* zero for a pixmap.)
|
|
**/
|
|
void
|
|
_gdk_win32_drawable_finish (GdkDrawable *drawable)
|
|
{
|
|
GdkDrawableImplWin32 *impl = GDK_DRAWABLE_IMPL_WIN32 (drawable);
|
|
|
|
if (impl->cairo_surface)
|
|
{
|
|
cairo_surface_finish (impl->cairo_surface);
|
|
cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
|
|
NULL, NULL);
|
|
}
|
|
|
|
g_assert (impl->hdc_count == 0);
|
|
}
|
|
|