mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-29 06:51:10 +00:00
d142187b38
directory hierarchy like this, with common gdk.h and gdktypes.h for all backends. gdkrectangles.c and gdkrgb.c is copied before compilation from the x11 backed (which still is in .., but eventually will be in ..\x11).
1380 lines
36 KiB
C
1380 lines
36 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 <string.h>
|
|
|
|
#include <gdk/gdk.h>
|
|
#include "gdkprivate.h"
|
|
|
|
GdkGC*
|
|
gdk_gc_new (GdkWindow *window)
|
|
{
|
|
return gdk_gc_new_with_values (window, NULL, 0);
|
|
}
|
|
|
|
GdkGC*
|
|
gdk_gc_new_with_values (GdkWindow *window,
|
|
GdkGCValues *values,
|
|
GdkGCValuesMask values_mask)
|
|
{
|
|
GdkWindowPrivate *window_private;
|
|
GdkGC *gc;
|
|
GdkGCPrivate *private;
|
|
static GdkColor black;
|
|
static GdkColor white;
|
|
static gboolean beenhere = FALSE;
|
|
|
|
if (!beenhere)
|
|
{
|
|
gdk_color_black (gdk_colormap_get_system (), &black);
|
|
gdk_color_white (gdk_colormap_get_system (), &white);
|
|
beenhere = TRUE;
|
|
}
|
|
|
|
g_return_val_if_fail (window != NULL, NULL);
|
|
|
|
window_private = (GdkWindowPrivate*) window;
|
|
if (window_private->destroyed)
|
|
return NULL;
|
|
|
|
private = g_new (GdkGCPrivate, 1);
|
|
gc = (GdkGC*) private;
|
|
|
|
private->ref_count = 1;
|
|
private->rop2 = R2_COPYPEN;
|
|
private->fill_style = GDK_SOLID;
|
|
private->values_mask = values_mask;
|
|
private->values_mask |= GDK_GC_FUNCTION | GDK_GC_FILL;
|
|
|
|
GDK_NOTE (MISC, g_print ("gdk_gc_new: {"));
|
|
|
|
if (values_mask & GDK_GC_FOREGROUND)
|
|
{
|
|
private->foreground = values->foreground;
|
|
}
|
|
else
|
|
private->foreground = black;
|
|
|
|
if (values_mask & GDK_GC_BACKGROUND)
|
|
{
|
|
private->background = values->background;
|
|
}
|
|
else
|
|
private->background = white;
|
|
|
|
if ((values_mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT))
|
|
{
|
|
private->font = (HFONT) ((GdkFontPrivate*) values->font)->xfont;
|
|
GDK_NOTE (MISC, g_print (" font=%#x", private->font));
|
|
}
|
|
|
|
if (values_mask & GDK_GC_FUNCTION)
|
|
{
|
|
switch (values->function)
|
|
{
|
|
case GDK_COPY:
|
|
private->rop2 = R2_COPYPEN; break;
|
|
case GDK_INVERT:
|
|
private->rop2 = R2_NOT; break;
|
|
case GDK_XOR:
|
|
private->rop2 = R2_XORPEN; break;
|
|
case GDK_CLEAR:
|
|
private->rop2 = R2_BLACK; break;
|
|
case GDK_AND:
|
|
private->rop2 = R2_MASKPEN; break;
|
|
case GDK_AND_REVERSE:
|
|
private->rop2 = R2_MASKPENNOT; break;
|
|
case GDK_AND_INVERT:
|
|
private->rop2 = R2_MASKNOTPEN; break;
|
|
case GDK_NOOP:
|
|
private->rop2 = R2_NOP; break;
|
|
case GDK_OR:
|
|
private->rop2 = R2_MERGEPEN; break;
|
|
case GDK_EQUIV:
|
|
private->rop2 = R2_NOTXORPEN; break;
|
|
case GDK_OR_REVERSE:
|
|
private->rop2 = R2_MERGEPENNOT; break;
|
|
case GDK_COPY_INVERT:
|
|
private->rop2 = R2_NOTCOPYPEN; break;
|
|
case GDK_OR_INVERT:
|
|
private->rop2 = R2_MERGENOTPEN; break;
|
|
case GDK_NAND:
|
|
private->rop2 = R2_NOTMASKPEN; break;
|
|
case GDK_SET:
|
|
private->rop2 = R2_WHITE; break;
|
|
}
|
|
GDK_NOTE (MISC, g_print (" function=%d", private->rop2));
|
|
}
|
|
|
|
if (values_mask & GDK_GC_FILL)
|
|
{
|
|
private->fill_style = values->fill;
|
|
GDK_NOTE (MISC, g_print (" fill=%d", private->fill_style));
|
|
}
|
|
|
|
if (values_mask & GDK_GC_TILE)
|
|
{
|
|
private->tile = values->tile;
|
|
gdk_pixmap_ref (private->tile);
|
|
GDK_NOTE (MISC, g_print (" tile=%#x", ((GdkPixmapPrivate *)private->tile)->xwindow));
|
|
}
|
|
else
|
|
private->tile = NULL;
|
|
|
|
if (values_mask & GDK_GC_STIPPLE)
|
|
{
|
|
private->stipple = values->tile;
|
|
gdk_pixmap_ref (private->stipple);
|
|
GDK_NOTE (MISC, g_print (" stipple=%#x", ((GdkPixmapPrivate *)private->stipple)->xwindow));
|
|
}
|
|
else
|
|
private->stipple = NULL;
|
|
|
|
if (values_mask & GDK_GC_CLIP_MASK)
|
|
{
|
|
private->clip_region =
|
|
BitmapToRegion (((GdkPixmapPrivate *)values->clip_mask)->xwindow);
|
|
GDK_NOTE (MISC, g_print (" clip=%#x", private->clip_region));
|
|
}
|
|
else
|
|
private->clip_region = NULL;
|
|
|
|
if (values_mask & GDK_GC_SUBWINDOW)
|
|
{
|
|
private->subwindow_mode = values->subwindow_mode;
|
|
GDK_NOTE (MISC, g_print (" subw=%d", private->subwindow_mode));
|
|
}
|
|
|
|
if (values_mask & GDK_GC_TS_X_ORIGIN)
|
|
{
|
|
private->ts_x_origin = values->ts_x_origin;
|
|
GDK_NOTE (MISC, g_print (" ts_x=%d", private->ts_x_origin));
|
|
}
|
|
|
|
if (values_mask & GDK_GC_TS_Y_ORIGIN)
|
|
{
|
|
private->ts_y_origin = values->ts_y_origin;
|
|
GDK_NOTE (MISC, g_print (" ts_y=%d", private->ts_y_origin));
|
|
}
|
|
|
|
if (values_mask & GDK_GC_CLIP_X_ORIGIN)
|
|
{
|
|
private->clip_x_origin = values->clip_x_origin;
|
|
GDK_NOTE (MISC, g_print (" clip_x=%d", private->clip_x_origin));
|
|
}
|
|
|
|
if (values_mask & GDK_GC_CLIP_Y_ORIGIN)
|
|
{
|
|
private->clip_y_origin = values->clip_y_origin;
|
|
GDK_NOTE (MISC, g_print (" clip_y=%d", private->clip_y_origin));
|
|
}
|
|
|
|
if (values_mask & GDK_GC_EXPOSURES)
|
|
{
|
|
private->graphics_exposures = values->graphics_exposures;
|
|
GDK_NOTE (MISC, g_print (" exp=%d", private->graphics_exposures));
|
|
}
|
|
|
|
private->pen_style = PS_GEOMETRIC;
|
|
private->pen_width = 1;
|
|
|
|
if (values_mask & (GDK_GC_LINE_WIDTH | GDK_GC_LINE_STYLE))
|
|
{
|
|
if (values_mask & GDK_GC_LINE_WIDTH)
|
|
{
|
|
private->pen_width = values->line_width;
|
|
GDK_NOTE (MISC, g_print (" pw=%d", private->pen_width));
|
|
}
|
|
if (values_mask & GDK_GC_LINE_STYLE)
|
|
{
|
|
switch (values->line_style)
|
|
{
|
|
case GDK_LINE_SOLID:
|
|
private->pen_style |= PS_SOLID; break;
|
|
case GDK_LINE_ON_OFF_DASH:
|
|
case GDK_LINE_DOUBLE_DASH: /* ??? */
|
|
private->pen_style |= PS_DASH; break;
|
|
}
|
|
GDK_NOTE (MISC, g_print (" ps=%#x", private->pen_style));
|
|
}
|
|
}
|
|
|
|
if (values_mask & GDK_GC_CAP_STYLE)
|
|
{
|
|
switch (values->cap_style)
|
|
{
|
|
case GDK_CAP_NOT_LAST: /* ??? */
|
|
case GDK_CAP_BUTT:
|
|
private->pen_style |= PS_ENDCAP_FLAT; break;
|
|
case GDK_CAP_ROUND:
|
|
private->pen_style |= PS_ENDCAP_ROUND; break;
|
|
case GDK_CAP_PROJECTING:
|
|
private->pen_style |= PS_ENDCAP_SQUARE; break;
|
|
}
|
|
GDK_NOTE (MISC, g_print (" ps=%#x", private->pen_style));
|
|
}
|
|
|
|
if (values_mask & GDK_GC_JOIN_STYLE)
|
|
{
|
|
switch (values->join_style)
|
|
{
|
|
case GDK_JOIN_MITER:
|
|
private->pen_style |= PS_JOIN_MITER;
|
|
break;
|
|
case GDK_JOIN_ROUND:
|
|
private->pen_style |= PS_JOIN_ROUND;
|
|
break;
|
|
case GDK_JOIN_BEVEL:
|
|
private->pen_style |= PS_JOIN_BEVEL;
|
|
break;
|
|
}
|
|
GDK_NOTE (MISC, g_print (" ps=%#x", private->pen_style));
|
|
}
|
|
|
|
private->hwnd = NULL;
|
|
private->xgc = NULL;
|
|
|
|
GDK_NOTE (MISC, g_print ("} = %p\n", private));
|
|
|
|
return gc;
|
|
}
|
|
|
|
void
|
|
gdk_gc_destroy (GdkGC *gc)
|
|
{
|
|
gdk_gc_unref (gc);
|
|
}
|
|
|
|
GdkGC *
|
|
gdk_gc_ref (GdkGC *gc)
|
|
{
|
|
GdkGCPrivate *private = (GdkGCPrivate*) gc;
|
|
|
|
g_return_val_if_fail (gc != NULL, NULL);
|
|
private->ref_count += 1;
|
|
|
|
return gc;
|
|
}
|
|
|
|
void
|
|
gdk_gc_unref (GdkGC *gc)
|
|
{
|
|
GdkGCPrivate *private = (GdkGCPrivate*) gc;
|
|
|
|
g_return_if_fail (gc != NULL);
|
|
|
|
if (private->ref_count > 1)
|
|
private->ref_count -= 1;
|
|
else
|
|
{
|
|
if (private->values_mask & GDK_GC_FONT)
|
|
{
|
|
#if 0
|
|
if (!DeleteObject (private->font))
|
|
g_warning ("gdk_gc_unref: DeleteObject #3 failed");
|
|
#endif
|
|
}
|
|
|
|
if (private->values_mask & GDK_GC_TILE)
|
|
{
|
|
gdk_pixmap_unref (private->tile);
|
|
}
|
|
|
|
if (private->values_mask & GDK_GC_STIPPLE)
|
|
{
|
|
gdk_pixmap_unref (private->stipple);
|
|
}
|
|
|
|
if (private->values_mask & GDK_GC_CLIP_MASK)
|
|
{
|
|
DeleteObject (private->clip_region);
|
|
}
|
|
memset (gc, 0, sizeof (GdkGCPrivate));
|
|
g_free (gc);
|
|
}
|
|
}
|
|
|
|
void
|
|
gdk_gc_get_values (GdkGC *gc,
|
|
GdkGCValues *values)
|
|
{
|
|
GdkGCPrivate *private;
|
|
|
|
g_return_if_fail (gc != NULL);
|
|
g_return_if_fail (values != NULL);
|
|
|
|
private = (GdkGCPrivate*) gc;
|
|
|
|
values->foreground = private->foreground;
|
|
values->background = private->background;
|
|
values->font = gdk_font_lookup (private->font);
|
|
|
|
switch (private->rop2)
|
|
{
|
|
case R2_COPYPEN:
|
|
values->function = GDK_COPY; break;
|
|
case R2_NOT:
|
|
values->function = GDK_INVERT; break;
|
|
case R2_XORPEN:
|
|
values->function = GDK_XOR; break;
|
|
case R2_BLACK:
|
|
values->function = GDK_CLEAR; break;
|
|
case R2_MASKPEN:
|
|
values->function = GDK_AND; break;
|
|
case R2_MASKPENNOT:
|
|
values->function = GDK_AND_REVERSE; break;
|
|
case R2_MASKNOTPEN:
|
|
values->function = GDK_AND_INVERT; break;
|
|
case R2_NOP:
|
|
values->function = GDK_NOOP; break;
|
|
case R2_MERGEPEN:
|
|
values->function = GDK_OR; break;
|
|
case R2_NOTXORPEN:
|
|
values->function = GDK_EQUIV; break;
|
|
case R2_MERGEPENNOT:
|
|
values->function = GDK_OR_REVERSE; break;
|
|
case R2_NOTCOPYPEN:
|
|
values->function = GDK_COPY_INVERT; break;
|
|
case R2_MERGENOTPEN:
|
|
values->function = GDK_OR_INVERT; break;
|
|
case R2_NOTMASKPEN:
|
|
values->function = GDK_NAND; break;
|
|
case R2_WHITE:
|
|
values->function = GDK_SET; break;
|
|
}
|
|
|
|
values->fill = private->fill_style;
|
|
|
|
values->tile = private->tile;
|
|
values->stipple = private->stipple;
|
|
if (private->clip_region != NULL)
|
|
{
|
|
RECT rect;
|
|
HBRUSH hbr;
|
|
HDC hdc;
|
|
HGDIOBJ oldbitmap;
|
|
GdkPixmap *pixmap;
|
|
|
|
GetRgnBox (private->clip_region, &rect);
|
|
pixmap =
|
|
gdk_pixmap_new (NULL, rect.right - rect.left, rect.bottom - rect.top,
|
|
1);
|
|
hbr = GetStockObject (WHITE_BRUSH);
|
|
if ((hdc = CreateCompatibleDC (NULL)) == NULL)
|
|
g_warning ("gdk_gc_get_values: CreateCompatibleDC failed");
|
|
if ((oldbitmap =
|
|
SelectObject (hdc, ((GdkPixmapPrivate *) pixmap)->xwindow)) == NULL)
|
|
g_warning ("gdk_gc_get_values: SelectObject #1 failed");
|
|
hbr = GetStockObject (BLACK_BRUSH);
|
|
if (!FillRect (hdc, &rect, hbr))
|
|
g_warning ("gdk_gc_get_values: FillRect failed");
|
|
hbr = GetStockObject (WHITE_BRUSH);
|
|
if (!FillRgn (hdc, private->clip_region, hbr))
|
|
g_warning ("gdk_gc_get_values: FillRgn failed");
|
|
if (SelectObject (hdc, oldbitmap) == NULL)
|
|
g_warning ("gdk_gc_get_values: SelectObject #2 failed");
|
|
DeleteDC (hdc);
|
|
values->clip_mask = pixmap;
|
|
}
|
|
else
|
|
values->clip_mask = NULL;
|
|
values->subwindow_mode = private->subwindow_mode;
|
|
values->ts_x_origin = private->ts_x_origin;
|
|
values->ts_y_origin = private->ts_y_origin;
|
|
values->clip_x_origin = private->clip_x_origin;
|
|
values->clip_y_origin = private->clip_y_origin;
|
|
values->graphics_exposures = private->graphics_exposures;
|
|
values->line_width = private->pen_width;
|
|
|
|
if (private->pen_style & PS_SOLID)
|
|
values->line_style = GDK_LINE_SOLID;
|
|
else if (private->pen_style & PS_DASH)
|
|
values->line_style = GDK_LINE_ON_OFF_DASH;
|
|
else
|
|
values->line_style = GDK_LINE_SOLID;
|
|
|
|
/* PS_ENDCAP_ROUND is zero */
|
|
if (private->pen_style & PS_ENDCAP_FLAT)
|
|
values->cap_style = GDK_CAP_BUTT;
|
|
else if (private->pen_style & PS_ENDCAP_SQUARE)
|
|
values->cap_style = GDK_CAP_PROJECTING;
|
|
else
|
|
values->cap_style = GDK_CAP_ROUND;
|
|
|
|
/* PS_JOIN_ROUND is zero */
|
|
if (private->pen_style & PS_JOIN_MITER)
|
|
values->join_style = GDK_JOIN_MITER;
|
|
else if (private->pen_style & PS_JOIN_BEVEL)
|
|
values->join_style = GDK_JOIN_BEVEL;
|
|
else
|
|
values->join_style = GDK_JOIN_ROUND;
|
|
}
|
|
|
|
void
|
|
gdk_gc_set_foreground (GdkGC *gc,
|
|
GdkColor *color)
|
|
{
|
|
GdkGCPrivate *private;
|
|
|
|
g_return_if_fail (gc != NULL);
|
|
g_return_if_fail (color != NULL);
|
|
|
|
private = (GdkGCPrivate*) gc;
|
|
{
|
|
GDK_NOTE (MISC, g_print ("gdk_gc_set_foreground: (%d) %s\n",
|
|
private, gdk_color_to_string (color)));
|
|
private->foreground = *color;
|
|
private->values_mask |= GDK_GC_FOREGROUND;
|
|
}
|
|
}
|
|
|
|
void
|
|
gdk_gc_set_background (GdkGC *gc,
|
|
GdkColor *color)
|
|
{
|
|
GdkGCPrivate *private;
|
|
|
|
g_return_if_fail (gc != NULL);
|
|
g_return_if_fail (color != NULL);
|
|
|
|
private = (GdkGCPrivate*) gc;
|
|
|
|
GDK_NOTE (MISC, g_print ("gdk_gc_set_backround: (%d) %s\n",
|
|
private, gdk_color_to_string(color)));
|
|
private->background = *color;
|
|
private->values_mask |= GDK_GC_BACKGROUND;
|
|
}
|
|
|
|
void
|
|
gdk_gc_set_font (GdkGC *gc,
|
|
GdkFont *font)
|
|
{
|
|
GdkGCPrivate *gc_private;
|
|
GdkFontPrivate *font_private;
|
|
|
|
g_return_if_fail (gc != NULL);
|
|
g_return_if_fail (font != NULL);
|
|
|
|
if (font->type == GDK_FONT_FONT)
|
|
{
|
|
gc_private = (GdkGCPrivate*) gc;
|
|
font_private = (GdkFontPrivate*) font;
|
|
|
|
GDK_NOTE (MISC, g_print ("gdk_gc_set_font: (%d) %#x\n",
|
|
gc_private, font_private->xfont));
|
|
|
|
gc_private->font = font_private->xfont;
|
|
gc_private->values_mask |= GDK_GC_FONT;
|
|
}
|
|
}
|
|
|
|
void
|
|
gdk_gc_set_function (GdkGC *gc,
|
|
GdkFunction function)
|
|
{
|
|
GdkGCPrivate *private;
|
|
|
|
g_return_if_fail (gc != NULL);
|
|
|
|
private = (GdkGCPrivate*) gc;
|
|
|
|
GDK_NOTE (MISC, g_print ("gdk_gc_set_function: (%d) %d\n", private, function));
|
|
|
|
switch (function)
|
|
{
|
|
case GDK_COPY:
|
|
private->rop2 = R2_COPYPEN; break;
|
|
case GDK_INVERT:
|
|
private->rop2 = R2_NOT; break;
|
|
case GDK_XOR:
|
|
private->rop2 = R2_XORPEN; break;
|
|
case GDK_CLEAR:
|
|
private->rop2 = R2_BLACK; break;
|
|
case GDK_AND:
|
|
private->rop2 = R2_MASKPEN; break;
|
|
case GDK_AND_REVERSE:
|
|
private->rop2 = R2_MASKPENNOT; break;
|
|
case GDK_AND_INVERT:
|
|
private->rop2 = R2_MASKNOTPEN; break;
|
|
case GDK_NOOP:
|
|
private->rop2 = R2_NOP; break;
|
|
case GDK_OR:
|
|
private->rop2 = R2_MERGEPEN; break;
|
|
case GDK_EQUIV:
|
|
private->rop2 = R2_NOTXORPEN; break;
|
|
case GDK_OR_REVERSE:
|
|
private->rop2 = R2_MERGEPENNOT; break;
|
|
case GDK_COPY_INVERT:
|
|
private->rop2 = R2_NOTCOPYPEN; break;
|
|
case GDK_OR_INVERT:
|
|
private->rop2 = R2_MERGENOTPEN; break;
|
|
case GDK_NAND:
|
|
private->rop2 = R2_NOTMASKPEN; break;
|
|
case GDK_SET:
|
|
private->rop2 = R2_WHITE; break;
|
|
}
|
|
private->values_mask |= GDK_GC_FUNCTION;
|
|
}
|
|
|
|
void
|
|
gdk_gc_set_fill (GdkGC *gc,
|
|
GdkFill fill)
|
|
{
|
|
GdkGCPrivate *private;
|
|
|
|
g_return_if_fail (gc != NULL);
|
|
|
|
private = (GdkGCPrivate*) gc;
|
|
|
|
private->fill_style = fill;
|
|
private->values_mask |= GDK_GC_FILL;
|
|
}
|
|
|
|
void
|
|
gdk_gc_set_tile (GdkGC *gc,
|
|
GdkPixmap *tile)
|
|
{
|
|
GdkGCPrivate *private;
|
|
GdkPixmapPrivate *pixmap_private;
|
|
HBITMAP pixmap;
|
|
|
|
g_return_if_fail (gc != NULL);
|
|
|
|
private = (GdkGCPrivate*) gc;
|
|
|
|
pixmap = NULL;
|
|
|
|
if (tile)
|
|
{
|
|
pixmap_private = (GdkPixmapPrivate*) tile;
|
|
pixmap = pixmap_private->xwindow;
|
|
}
|
|
|
|
if (private->tile != NULL)
|
|
gdk_pixmap_unref (private->tile);
|
|
private->tile = tile;
|
|
if (tile)
|
|
gdk_pixmap_ref (tile);
|
|
if (pixmap != NULL)
|
|
private->values_mask |= GDK_GC_TILE;
|
|
else
|
|
private->values_mask &= ~GDK_GC_TILE;
|
|
}
|
|
|
|
void
|
|
gdk_gc_set_stipple (GdkGC *gc,
|
|
GdkPixmap *stipple)
|
|
{
|
|
GdkGCPrivate *private;
|
|
GdkPixmapPrivate *pixmap_private;
|
|
HBITMAP pixmap;
|
|
|
|
g_return_if_fail (gc != NULL);
|
|
|
|
private = (GdkGCPrivate*) gc;
|
|
|
|
pixmap = NULL;
|
|
|
|
if (stipple)
|
|
{
|
|
pixmap_private = (GdkPixmapPrivate*) stipple;
|
|
pixmap = pixmap_private->xwindow;
|
|
}
|
|
|
|
if (private->stipple != NULL)
|
|
gdk_pixmap_unref (private->stipple);
|
|
private->stipple = stipple;
|
|
if (stipple)
|
|
gdk_pixmap_ref (stipple);
|
|
if (pixmap != NULL)
|
|
private->values_mask |= GDK_GC_STIPPLE;
|
|
else
|
|
private->values_mask &= ~GDK_GC_STIPPLE;
|
|
}
|
|
|
|
void
|
|
gdk_gc_set_ts_origin (GdkGC *gc,
|
|
gint x,
|
|
gint y)
|
|
{
|
|
GdkGCPrivate *private;
|
|
|
|
g_return_if_fail (gc != NULL);
|
|
|
|
private = (GdkGCPrivate*) gc;
|
|
|
|
private->ts_x_origin = x;
|
|
private->ts_y_origin = y;
|
|
private->values_mask |= GDK_GC_TS_X_ORIGIN |GDK_GC_TS_Y_ORIGIN;
|
|
}
|
|
|
|
void
|
|
gdk_gc_set_clip_origin (GdkGC *gc,
|
|
gint x,
|
|
gint y)
|
|
{
|
|
GdkGCPrivate *private;
|
|
|
|
g_return_if_fail (gc != NULL);
|
|
|
|
private = (GdkGCPrivate*) gc;
|
|
|
|
GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_origin: (%d) +%d+%d\n",
|
|
private, x, y));
|
|
|
|
private->clip_x_origin = x;
|
|
private->clip_y_origin = y;
|
|
private->values_mask |= GDK_GC_CLIP_X_ORIGIN |GDK_GC_CLIP_Y_ORIGIN;
|
|
}
|
|
|
|
void
|
|
gdk_gc_set_clip_mask (GdkGC *gc,
|
|
GdkBitmap *mask)
|
|
{
|
|
GdkGCPrivate *private;
|
|
HBITMAP xmask;
|
|
|
|
g_return_if_fail (gc != NULL);
|
|
|
|
if (mask)
|
|
{
|
|
GdkWindowPrivate *mask_private;
|
|
|
|
mask_private = (GdkWindowPrivate*) mask;
|
|
if (mask_private->destroyed)
|
|
return;
|
|
xmask = mask_private->xwindow;
|
|
}
|
|
else
|
|
xmask = NULL;
|
|
|
|
private = (GdkGCPrivate*) gc;
|
|
|
|
GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_mask: (%d) %#x\n", private, xmask));
|
|
|
|
if (private->clip_region != NULL)
|
|
if (!DeleteObject (private->clip_region))
|
|
g_warning ("gdk_gc_set_clip_mask: DeleteObject failed");
|
|
if (xmask != NULL)
|
|
{
|
|
private->clip_region = BitmapToRegion (xmask);
|
|
{
|
|
RECT rect;
|
|
GetRgnBox (private->clip_region, &rect);
|
|
GDK_NOTE (MISC, g_print ("...box = %dx%d@+%d+%d\n",
|
|
rect.right - rect.left, rect.bottom - rect.top,
|
|
rect.left, rect.top));
|
|
}
|
|
#if 0
|
|
/* Test code that sets clip region to whole of mask */
|
|
{
|
|
BITMAP bm;
|
|
GetObject (xmask, sizeof (bm), &bm);
|
|
private->clip_region = CreateRectRgn (0, 0, bm.bmWidth, bm.bmHeight);
|
|
}
|
|
#endif
|
|
private->values_mask |= GDK_GC_CLIP_MASK;
|
|
}
|
|
else
|
|
{
|
|
private->values_mask &= ~GDK_GC_CLIP_MASK;
|
|
private->clip_region = NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
gdk_gc_set_clip_rectangle (GdkGC *gc,
|
|
GdkRectangle *rectangle)
|
|
{
|
|
GdkGCPrivate *private;
|
|
|
|
g_return_if_fail (gc != NULL);
|
|
|
|
private = (GdkGCPrivate*) gc;
|
|
|
|
if (private->clip_region != NULL)
|
|
if (!DeleteObject (private->clip_region))
|
|
g_warning ("gdk_gc_set_clip_rectangle: DeleteObject failed");
|
|
if (rectangle)
|
|
{
|
|
GDK_NOTE (MISC,
|
|
g_print ("gdk_gc_set_clip_rectangle: (%d) %dx%d@+%d+%d\n",
|
|
private,
|
|
rectangle->width, rectangle->height,
|
|
rectangle->x, rectangle->y));
|
|
if ((private->clip_region =
|
|
CreateRectRgn (rectangle->x, rectangle->y,
|
|
rectangle->x + rectangle->width,
|
|
rectangle->y + rectangle->height)) == NULL)
|
|
g_warning ("gdk_gc_set_clip_rectangle: CreateRectRgn failed");
|
|
|
|
private->values_mask |= GDK_GC_CLIP_MASK;
|
|
}
|
|
else
|
|
{
|
|
GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_rectangle: (%d) None\n",
|
|
private));
|
|
private->clip_region = NULL;
|
|
private->values_mask &= ~GDK_GC_CLIP_MASK;
|
|
}
|
|
private->values_mask &= ~(GDK_GC_CLIP_X_ORIGIN |GDK_GC_CLIP_Y_ORIGIN);
|
|
}
|
|
|
|
void
|
|
gdk_gc_set_clip_region (GdkGC *gc,
|
|
GdkRegion *region)
|
|
{
|
|
GdkGCPrivate *private;
|
|
|
|
g_return_if_fail (gc != NULL);
|
|
|
|
private = (GdkGCPrivate*) gc;
|
|
|
|
GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_region: (%d) %s\n",
|
|
private, (region != NULL ? "xxx" : "None")));
|
|
|
|
if (private->clip_region != NULL)
|
|
if (!DeleteObject (private->clip_region))
|
|
g_warning ("gdk_gc_set_clip_region: DeleteObject failed");
|
|
if (region)
|
|
{
|
|
GdkRegionPrivate *region_private;
|
|
|
|
region_private = (GdkRegionPrivate*) region;
|
|
private->clip_region = CreateRectRgn (1, 1, 0, 0);
|
|
CombineRgn (private->clip_region, region_private->xregion, NULL, RGN_COPY);
|
|
private->values_mask |= GDK_GC_CLIP_MASK;
|
|
}
|
|
else
|
|
{
|
|
private->clip_region = NULL;
|
|
private->values_mask &= ~GDK_GC_CLIP_MASK;
|
|
}
|
|
}
|
|
|
|
void
|
|
gdk_gc_set_subwindow (GdkGC *gc,
|
|
GdkSubwindowMode mode)
|
|
{
|
|
GdkGCPrivate *private;
|
|
|
|
g_return_if_fail (gc != NULL);
|
|
|
|
private = (GdkGCPrivate*) gc;
|
|
|
|
private->subwindow_mode = mode;
|
|
private->values_mask |= GDK_GC_SUBWINDOW;
|
|
}
|
|
|
|
void
|
|
gdk_gc_set_exposures (GdkGC *gc,
|
|
gint exposures)
|
|
{
|
|
GdkGCPrivate *private;
|
|
|
|
g_return_if_fail (gc != NULL);
|
|
|
|
private = (GdkGCPrivate*) gc;
|
|
|
|
private->graphics_exposures = exposures;
|
|
private->values_mask |= GDK_GC_EXPOSURES;;
|
|
}
|
|
|
|
void
|
|
gdk_gc_set_line_attributes (GdkGC *gc,
|
|
gint line_width,
|
|
GdkLineStyle line_style,
|
|
GdkCapStyle cap_style,
|
|
GdkJoinStyle join_style)
|
|
{
|
|
GdkGCPrivate *private;
|
|
int xline_style;
|
|
int xcap_style;
|
|
int xjoin_style;
|
|
|
|
g_return_if_fail (gc != NULL);
|
|
|
|
private = (GdkGCPrivate*) gc;
|
|
|
|
GDK_NOTE (MISC,
|
|
g_print ("gdk_gc_set_line_attributes: (%d) %d %s %s %s\n",
|
|
private, line_width,
|
|
(line_style == GDK_LINE_SOLID ? "SOLID" :
|
|
(line_style == GDK_LINE_ON_OFF_DASH ? "ON_OFF_DASH" :
|
|
(line_style == GDK_LINE_DOUBLE_DASH ? "DOUBLE_DASH" :
|
|
"???"))),
|
|
(cap_style == GDK_CAP_BUTT ? "BUTT" :
|
|
(cap_style == GDK_CAP_ROUND ? "ROUND" :
|
|
(cap_style == GDK_CAP_PROJECTING ? "PROJECTING" :
|
|
"???"))),
|
|
(join_style == GDK_JOIN_MITER ? "MITER" :
|
|
(join_style == GDK_JOIN_ROUND ? "ROUND" :
|
|
(join_style == GDK_JOIN_BEVEL ? "BEVEL" :
|
|
"???")))));
|
|
|
|
private->pen_width = line_width;
|
|
|
|
/* Mask old style bits away */
|
|
private->pen_style &= ~(PS_STYLE_MASK|PS_ENDCAP_MASK|PS_JOIN_MASK);
|
|
|
|
/* Add new bits */
|
|
switch (line_style)
|
|
{
|
|
case GDK_LINE_SOLID:
|
|
private->pen_style |= PS_SOLID; break;
|
|
case GDK_LINE_ON_OFF_DASH:
|
|
case GDK_LINE_DOUBLE_DASH: /* ??? */
|
|
private->pen_style |= PS_DASH; break;
|
|
}
|
|
|
|
switch (cap_style)
|
|
{
|
|
case GDK_CAP_NOT_LAST:
|
|
/* ??? */
|
|
break;
|
|
case GDK_CAP_BUTT:
|
|
private->pen_style |= PS_ENDCAP_FLAT; break;
|
|
case GDK_CAP_ROUND:
|
|
private->pen_style |= PS_ENDCAP_ROUND; break;
|
|
case GDK_CAP_PROJECTING:
|
|
private->pen_style |= PS_ENDCAP_SQUARE; break;
|
|
}
|
|
|
|
switch (join_style)
|
|
{
|
|
case GDK_JOIN_MITER:
|
|
private->pen_style |= PS_JOIN_MITER;
|
|
break;
|
|
case GDK_JOIN_ROUND:
|
|
private->pen_style |= PS_JOIN_ROUND;
|
|
break;
|
|
case GDK_JOIN_BEVEL:
|
|
private->pen_style |= PS_JOIN_BEVEL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
gdk_gc_set_dashes (GdkGC *gc,
|
|
gint dash_offset,
|
|
gchar dash_list[],
|
|
gint n)
|
|
{
|
|
GdkGCPrivate *private;
|
|
|
|
g_return_if_fail (gc != NULL);
|
|
g_return_if_fail (dash_list != NULL);
|
|
|
|
/* XXX ??? */
|
|
|
|
private = (GdkGCPrivate *) gc;
|
|
|
|
private->pen_style &= ~(PS_STYLE_MASK);
|
|
private->pen_style |= PS_DASH;
|
|
}
|
|
|
|
void
|
|
gdk_gc_copy (GdkGC *dst_gc, GdkGC *src_gc)
|
|
{
|
|
GdkGCPrivate *dst_private, *src_private;
|
|
|
|
src_private = (GdkGCPrivate *) src_gc;
|
|
dst_private = (GdkGCPrivate *) dst_gc;
|
|
|
|
*dst_private = *src_private;
|
|
}
|
|
|
|
HDC
|
|
gdk_gc_predraw (GdkWindowPrivate *window_private,
|
|
GdkGCPrivate *gc_private)
|
|
{
|
|
GdkColormapPrivate *colormap_private =
|
|
(GdkColormapPrivate *) window_private->colormap;
|
|
COLORREF bg;
|
|
COLORREF fg;
|
|
LOGBRUSH logbrush;
|
|
HPEN hpen;
|
|
HBRUSH hbr;
|
|
|
|
g_assert (gc_private->xgc == NULL);
|
|
|
|
if (window_private->window_type == GDK_WINDOW_PIXMAP)
|
|
{
|
|
if ((gc_private->xgc = CreateCompatibleDC (NULL)) == NULL)
|
|
g_warning ("gdk_gc_predraw: CreateCompatibleDC failed");
|
|
|
|
if ((gc_private->saved_dc = SaveDC (gc_private->xgc)) == 0)
|
|
g_warning ("gdk_gc_predraw: SaveDC #1 failed");
|
|
|
|
if (SelectObject (gc_private->xgc, window_private->xwindow) == NULL)
|
|
g_warning ("gdk_gc_predraw: SelectObject #1 failed");
|
|
}
|
|
else
|
|
{
|
|
if ((gc_private->xgc = GetDC (window_private->xwindow)) == NULL)
|
|
g_warning ("gdk_gc_predraw: GetDC failed");
|
|
|
|
if ((gc_private->saved_dc = SaveDC (gc_private->xgc)) == 0)
|
|
g_warning ("gdk_gc_predraw: SaveDC #2 failed");
|
|
}
|
|
|
|
gc_private->hwnd = window_private->xwindow;
|
|
|
|
if (colormap_private == NULL)
|
|
{
|
|
/* A 1 bit deep bitmap */
|
|
struct
|
|
{
|
|
WORD palVersion;
|
|
WORD palNumEntries;
|
|
PALETTEENTRY palPalEntry[2];
|
|
} logpal;
|
|
static HPALETTE hpal = NULL;
|
|
|
|
if (hpal == NULL)
|
|
{
|
|
/* Create a b&w palette */
|
|
logpal.palVersion = 0x300;
|
|
logpal.palNumEntries = 2;
|
|
logpal.palPalEntry[0].peRed =
|
|
logpal.palPalEntry[0].peGreen =
|
|
logpal.palPalEntry[0].peBlue = 0x00;
|
|
logpal.palPalEntry[0].peFlags = 0x00;
|
|
logpal.palPalEntry[1].peRed =
|
|
logpal.palPalEntry[1].peGreen =
|
|
logpal.palPalEntry[1].peBlue = 0xFF;
|
|
logpal.palPalEntry[1].peFlags = 0x00;
|
|
if ((hpal = CreatePalette ((LOGPALETTE *) &logpal)) == NULL)
|
|
g_warning ("gdk_gc_predraw: CreatePalette failed");
|
|
}
|
|
SelectPalette (gc_private->xgc, hpal, FALSE);
|
|
RealizePalette (gc_private->xgc);
|
|
fg = PALETTEINDEX (gc_private->foreground.pixel);
|
|
}
|
|
else if (colormap_private != NULL
|
|
&& colormap_private->xcolormap->rc_palette)
|
|
{
|
|
int k;
|
|
if (SelectPalette (gc_private->xgc,
|
|
colormap_private->xcolormap->palette, FALSE) == NULL)
|
|
g_warning ("gdk_gc_predraw: SelectPalette failed");
|
|
if (TRUE || colormap_private->xcolormap->stale)
|
|
{
|
|
if ((k = RealizePalette (gc_private->xgc)) == GDI_ERROR)
|
|
g_warning ("gdk_gc_predraw: RealizePalette failed");
|
|
colormap_private->xcolormap->stale = FALSE;
|
|
}
|
|
#if 0
|
|
g_print ("Selected palette %#x for gc %#x, realized %d colors\n",
|
|
colormap_private->xcolormap->palette, gc_private->xgc, k);
|
|
#endif
|
|
fg = PALETTEINDEX (gc_private->foreground.pixel);
|
|
}
|
|
else
|
|
{
|
|
COLORREF foreground = RGB (gc_private->foreground.red >> 8,
|
|
gc_private->foreground.green >> 8,
|
|
gc_private->foreground.blue >> 8);
|
|
fg = GetNearestColor (gc_private->xgc, foreground);
|
|
}
|
|
logbrush.lbStyle = BS_SOLID;
|
|
logbrush.lbColor = fg;
|
|
if ((hpen = ExtCreatePen (gc_private->pen_style, gc_private->pen_width,
|
|
&logbrush, 0, NULL)) == NULL)
|
|
g_warning ("gdk_gc_predraw: CreatePen failed");
|
|
|
|
if (SelectObject (gc_private->xgc, hpen) == NULL)
|
|
g_warning ("gdk_gc_predraw: SelectObject #2 failed");
|
|
|
|
if (SetTextColor (gc_private->xgc, fg) == CLR_INVALID)
|
|
g_warning ("gdk_gc_predraw: SetTextColor failed");
|
|
|
|
if ((hbr = CreateSolidBrush (fg)) == NULL)
|
|
g_warning ("gdk_gc_predraw: CreateSolidBrush failed");
|
|
|
|
if (SelectObject (gc_private->xgc, hbr) == NULL)
|
|
g_warning ("gdk_gc_predraw: SelectObject #3 failed");
|
|
|
|
if (gc_private->values_mask & GDK_GC_BACKGROUND)
|
|
{
|
|
if (colormap_private == NULL)
|
|
{
|
|
/* a bitmap */
|
|
bg = PALETTEINDEX (gc_private->background.pixel);
|
|
}
|
|
else if (colormap_private != NULL
|
|
&& colormap_private->xcolormap->rc_palette)
|
|
{
|
|
bg = PALETTEINDEX (gc_private->background.pixel);
|
|
}
|
|
else
|
|
{
|
|
COLORREF background = RGB (gc_private->background.red >> 8,
|
|
gc_private->background.green >> 8,
|
|
gc_private->background.blue >> 8);
|
|
bg = GetNearestColor (gc_private->xgc, background);
|
|
}
|
|
if (SetBkColor (gc_private->xgc, bg) == CLR_INVALID)
|
|
g_warning ("gdk_gc_predraw: SetBkColor failed");
|
|
}
|
|
|
|
if (SetBkMode (gc_private->xgc, TRANSPARENT) == 0)
|
|
g_warning ("gdk_gc_predraw: SetBkMode failed");
|
|
|
|
if (SetTextAlign (gc_private->xgc, TA_BASELINE) == GDI_ERROR)
|
|
g_warning ("gdk_gc_predraw: SetTextAlign failed");
|
|
|
|
if (gc_private->values_mask & GDK_GC_FONT)
|
|
if (SelectObject (gc_private->xgc, gc_private->font) == NULL)
|
|
g_warning ("gdk_gc_predraw: SelectObject #4 failed");
|
|
|
|
if (gc_private->values_mask & GDK_GC_FUNCTION)
|
|
if (SetROP2 (gc_private->xgc, gc_private->rop2) == 0)
|
|
g_warning ("gdk_gc_predraw: SetROP2 failed");
|
|
|
|
if (gc_private->values_mask & GDK_GC_CLIP_MASK
|
|
&& gc_private->clip_region != NULL)
|
|
{
|
|
if (gc_private->values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN))
|
|
OffsetRgn (gc_private->clip_region,
|
|
gc_private->clip_x_origin, gc_private->clip_y_origin);
|
|
SelectClipRgn (gc_private->xgc, gc_private->clip_region);
|
|
}
|
|
|
|
return gc_private->xgc;
|
|
}
|
|
|
|
void
|
|
gdk_gc_postdraw (GdkWindowPrivate *window_private,
|
|
GdkGCPrivate *gc_private)
|
|
{
|
|
HGDIOBJ hpen;
|
|
HGDIOBJ hbr;
|
|
GdkColormapPrivate *colormap_private =
|
|
(GdkColormapPrivate *) window_private->colormap;
|
|
|
|
if ((hpen = GetCurrentObject (gc_private->xgc, OBJ_PEN)) == NULL)
|
|
g_warning ("gdk_gc_postdraw: GetCurrentObject #1 failed");
|
|
|
|
if ((hbr = GetCurrentObject (gc_private->xgc, OBJ_BRUSH)) == NULL)
|
|
g_warning ("gdk_gc_postdraw: GetCurrentObject #2 failed");
|
|
|
|
if (!RestoreDC (gc_private->xgc, gc_private->saved_dc))
|
|
g_warning ("gdk_gc_postdraw: RestoreDC failed");
|
|
#if 0
|
|
if (colormap_private != NULL
|
|
&& colormap_private->xcolormap->rc_palette
|
|
&& colormap_private->xcolormap->stale)
|
|
{
|
|
SelectPalette (gc_private->xgc, GetStockObject (DEFAULT_PALETTE), FALSE);
|
|
if (!UnrealizeObject (colormap_private->xcolormap->palette))
|
|
g_warning ("gdk_gc_postraw: UnrealizeObject failed");
|
|
}
|
|
#endif
|
|
if (window_private->window_type == GDK_WINDOW_PIXMAP)
|
|
{
|
|
if (!DeleteDC (gc_private->xgc))
|
|
g_warning ("gdk_gc_postdraw: DeleteDC failed");
|
|
}
|
|
else
|
|
{
|
|
ReleaseDC (gc_private->hwnd, gc_private->xgc);
|
|
}
|
|
|
|
if (hpen != NULL)
|
|
if (!DeleteObject (hpen))
|
|
g_warning ("gdk_gc_postdraw: DeleteObject #1 failed");
|
|
|
|
if (hbr != NULL)
|
|
if (!DeleteObject (hbr))
|
|
g_warning ("gdk_gc_postdraw: DeleteObject #2 failed");
|
|
|
|
gc_private->xgc = NULL;
|
|
}
|
|
|
|
/* This function originally from Jean-Edouard Lachand-Robert, and
|
|
* available at www.codeguru.com. Simplified for our needs, now
|
|
* handles just one-bit deep bitmaps (in Window parlance, ie those
|
|
* that GDK calls bitmaps (and not pixmaps), with zero pixels being
|
|
* transparent.
|
|
*/
|
|
|
|
/*
|
|
* BitmapToRegion : Create a region from the "non-transparent" pixels of
|
|
* a bitmap
|
|
* Author : Jean-Edouard Lachand-Robert
|
|
* (http://www.geocities.com/Paris/LeftBank/1160/resume.htm), June 1998.
|
|
*/
|
|
|
|
HRGN
|
|
BitmapToRegion (HBITMAP hBmp)
|
|
{
|
|
HRGN hRgn = NULL;
|
|
HDC hMemDC;
|
|
BITMAP bm;
|
|
|
|
struct
|
|
{
|
|
BITMAPINFOHEADER bmiHeader;
|
|
#if 1
|
|
WORD bmiColors[2];
|
|
#else
|
|
RGBQUAD bmiColors[2];
|
|
#endif
|
|
} bmi;
|
|
VOID *pbits8;
|
|
HBITMAP hbm8;
|
|
struct
|
|
{
|
|
WORD palVersion;
|
|
WORD palNumEntries;
|
|
PALETTEENTRY palPalEntry[2];
|
|
} logpal;
|
|
static HPALETTE bwPalette = NULL;
|
|
|
|
HBITMAP holdBmp;
|
|
HDC hDC;
|
|
|
|
BITMAP bm8;
|
|
HBITMAP holdBmp2;
|
|
DWORD maxRects;
|
|
RGNDATA *pData;
|
|
BYTE *p8;
|
|
int x, y;
|
|
HRGN h;
|
|
|
|
/* Create a B&W palette */
|
|
if (bwPalette == NULL)
|
|
{
|
|
/* Create a b&w palette */
|
|
logpal.palVersion = 0x300;
|
|
logpal.palNumEntries = 2;
|
|
logpal.palPalEntry[0].peRed =
|
|
logpal.palPalEntry[0].peGreen =
|
|
logpal.palPalEntry[0].peBlue = 0;
|
|
logpal.palPalEntry[0].peFlags = 0;
|
|
logpal.palPalEntry[1].peRed =
|
|
logpal.palPalEntry[1].peGreen =
|
|
logpal.palPalEntry[1].peBlue = 0xFF;
|
|
logpal.palPalEntry[1].peFlags = 0;
|
|
if ((bwPalette = CreatePalette ((LOGPALETTE *) &logpal)) == NULL)
|
|
g_warning ("BitmapToRegion: CreatePalette failed");
|
|
}
|
|
|
|
/* Create a memory DC inside which we will scan the bitmap content */
|
|
hMemDC = CreateCompatibleDC (NULL);
|
|
if (!hMemDC)
|
|
{
|
|
g_warning ("BitmapToRegion: CreateCompatibleDC #1 failed");
|
|
return NULL;
|
|
}
|
|
|
|
SelectPalette (hMemDC, bwPalette, FALSE);
|
|
RealizePalette (hMemDC);
|
|
|
|
/* Get bitmap size */
|
|
GetObject(hBmp, sizeof(bm), &bm);
|
|
|
|
/* Create a 8 bits depth bitmap and select it into the memory DC */
|
|
bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
|
|
bmi.bmiHeader.biWidth = bm.bmWidth;
|
|
bmi.bmiHeader.biHeight = bm.bmHeight;
|
|
bmi.bmiHeader.biPlanes = 1;
|
|
bmi.bmiHeader.biBitCount = 8;
|
|
bmi.bmiHeader.biCompression = BI_RGB;
|
|
bmi.bmiHeader.biSizeImage = 0;
|
|
bmi.bmiHeader.biXPelsPerMeter = 0;
|
|
bmi.bmiHeader.biYPelsPerMeter = 0;
|
|
bmi.bmiHeader.biClrUsed = 2;
|
|
bmi.bmiHeader.biClrImportant = 2;
|
|
#if 1
|
|
bmi.bmiColors[0] = 0;
|
|
bmi.bmiColors[1] = 1;
|
|
hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi,
|
|
DIB_PAL_COLORS, &pbits8, NULL, 0);
|
|
#else
|
|
bmi.bmiColors[0].rgbBlue =
|
|
bmi.bmiColors[0].rgbGreen =
|
|
bmi.bmiColors[0].rgbRed = 0x00;
|
|
bmi.bmiColors[0].rgbReserved = 0x00;
|
|
|
|
bmi.bmiColors[1].rgbBlue =
|
|
bmi.bmiColors[1].rgbGreen =
|
|
bmi.bmiColors[1].rgbRed = 0xFF;
|
|
bmi.bmiColors[0].rgbReserved = 0x00;
|
|
|
|
hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi,
|
|
DIB_RGB_COLORS, &pbits8, NULL, 0);
|
|
#endif
|
|
if (!hbm8)
|
|
{
|
|
g_warning ("BitmapToRegion: CreateDIBSection failed");
|
|
DeleteDC (hMemDC);
|
|
return NULL;
|
|
}
|
|
|
|
holdBmp = (HBITMAP) SelectObject (hMemDC, hbm8);
|
|
|
|
/* Create a DC just to copy the bitmap into the memory DC*/
|
|
hDC = CreateCompatibleDC (hMemDC);
|
|
if (!hDC)
|
|
{
|
|
g_warning ("BitmapToRegion: CreateCompatibleDC #2 failed");
|
|
SelectObject (hMemDC, holdBmp);
|
|
DeleteObject (hbm8);
|
|
DeleteDC (hMemDC);
|
|
return NULL;
|
|
}
|
|
|
|
/* Get how many bytes per row we have for the bitmap bits */
|
|
GetObject (hbm8, sizeof (bm8), &bm8);
|
|
|
|
/* Hans Breuer found a fix to the long-standing erroneous behaviour
|
|
* on NT 4.0: There seems to be a bug in Win NT 4.0 GDI: scanlines
|
|
* in bitmaps are dword aligned on both Win95 and NT. In the case of
|
|
* a bitmap with 22 bytes worth of width, GetObject above returns
|
|
* with bmWidth == 22. On Win95 bmWidthBytes == 24, as it should be,
|
|
* but on NT is it 22. We need to correct this here.
|
|
*/
|
|
bm8.bmWidthBytes = (((bm8.bmWidthBytes-1)/4)+1)*4; /* dword aligned!! */
|
|
|
|
/* Copy the bitmap into the memory DC*/
|
|
holdBmp2 = (HBITMAP) SelectObject (hDC, hBmp);
|
|
|
|
if (!BitBlt (hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY))
|
|
{
|
|
g_warning ("BitmapToRegion: BitBlt failed");
|
|
SelectObject (hDC, holdBmp2);
|
|
SelectObject (hMemDC, holdBmp);
|
|
DeleteObject (hbm8);
|
|
DeleteDC (hMemDC);
|
|
return NULL;
|
|
}
|
|
SelectObject (hDC, holdBmp2);
|
|
DeleteDC (hDC);
|
|
|
|
/* For better performances, we will use the ExtCreateRegion()
|
|
* function to create the region. This function take a RGNDATA
|
|
* structure on entry. We will add rectangles by amount of
|
|
* ALLOC_UNIT number in this structure.
|
|
*/
|
|
#define ALLOC_UNIT 100
|
|
maxRects = ALLOC_UNIT;
|
|
|
|
pData = g_malloc (sizeof (RGNDATAHEADER) + (sizeof (RECT) * maxRects));
|
|
pData->rdh.dwSize = sizeof (RGNDATAHEADER);
|
|
pData->rdh.iType = RDH_RECTANGLES;
|
|
pData->rdh.nCount = pData->rdh.nRgnSize = 0;
|
|
SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
|
|
|
|
/* Scan each bitmap from bottom to top (the bitmap is inverted vertically)*/
|
|
p8 = (BYTE *) pbits8 + (bm8.bmHeight - 1) * bm8.bmWidthBytes;
|
|
for (y = 0; y < bm.bmHeight; y++)
|
|
{
|
|
/* Scan each bitmap row from left to right*/
|
|
for (x = 0; x < bm.bmWidth; x++)
|
|
{
|
|
/* Search for a continuous range of "non transparent pixels"*/
|
|
int x0 = x;
|
|
BYTE *p = p8 + x;
|
|
while (x < bm.bmWidth)
|
|
{
|
|
if (*p == 0)
|
|
/* This pixel is "transparent"*/
|
|
break;
|
|
p++;
|
|
x++;
|
|
}
|
|
|
|
if (x > x0)
|
|
{
|
|
RECT *pr;
|
|
/* Add the pixels (x0, y) to (x, y+1) as a new rectangle
|
|
* in the region
|
|
*/
|
|
if (pData->rdh.nCount >= maxRects)
|
|
{
|
|
maxRects += ALLOC_UNIT;
|
|
pData = g_realloc (pData, sizeof(RGNDATAHEADER)
|
|
+ (sizeof(RECT) * maxRects));
|
|
}
|
|
pr = (RECT *) &pData->Buffer;
|
|
SetRect (&pr[pData->rdh.nCount], x0, y, x, y+1);
|
|
if (x0 < pData->rdh.rcBound.left)
|
|
pData->rdh.rcBound.left = x0;
|
|
if (y < pData->rdh.rcBound.top)
|
|
pData->rdh.rcBound.top = y;
|
|
if (x > pData->rdh.rcBound.right)
|
|
pData->rdh.rcBound.right = x;
|
|
if (y+1 > pData->rdh.rcBound.bottom)
|
|
pData->rdh.rcBound.bottom = y+1;
|
|
pData->rdh.nCount++;
|
|
|
|
/* On Windows98, ExtCreateRegion() may fail if the
|
|
* number of rectangles is too large (ie: >
|
|
* 4000). Therefore, we have to create the region by
|
|
* multiple steps.
|
|
*/
|
|
if (pData->rdh.nCount == 2000)
|
|
{
|
|
HRGN h = ExtCreateRegion (NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
|
|
if (hRgn)
|
|
{
|
|
CombineRgn(hRgn, hRgn, h, RGN_OR);
|
|
DeleteObject(h);
|
|
}
|
|
else
|
|
hRgn = h;
|
|
pData->rdh.nCount = 0;
|
|
SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Go to next row (remember, the bitmap is inverted vertically)*/
|
|
p8 -= bm8.bmWidthBytes;
|
|
}
|
|
|
|
/* Create or extend the region with the remaining rectangles*/
|
|
h = ExtCreateRegion (NULL, sizeof (RGNDATAHEADER)
|
|
+ (sizeof (RECT) * maxRects), pData);
|
|
if (hRgn)
|
|
{
|
|
CombineRgn (hRgn, hRgn, h, RGN_OR);
|
|
DeleteObject (h);
|
|
}
|
|
else
|
|
hRgn = h;
|
|
|
|
/* Clean up*/
|
|
SelectObject(hMemDC, holdBmp);
|
|
DeleteObject (hbm8);
|
|
DeleteDC (hMemDC);
|
|
|
|
return hRgn;
|
|
}
|