wine/objects/dc.c
Alexandre Julliard a69b88b2f2 Release 980315
Sun Mar 15 03:46:50 1998  Dimitrie O. Paun  <dimi@mail.cs.toronto.edu>

	* [*/*]
	Fixed some dprintf_ such that there is one and only one
	new line for each dprintf and that new line occurs at the end.
	Transformed some fprintfs into proper debug statements.
	Removed much redundancy from most of the debug statements. The
	redundancy appeared because now the component and function
	name is output automatically. Most debug statements also used to
	output the name of the function.
	All these changes prepared the source to switch completely to
	the new debugging interface.
	For more info, refer to ./documentation/debug-msg

Sat Mar 14 19:45:23 1997  Andreas Mohr <100.30936@germany.net>

	* [misc/shell.c] [if1632/kernel.spec]
	Changed parameters of FUNC004() to fix a crash.
	Not sure if this fix is correct (doc wanted).

	* [windows/user.c] [if1632/user.spec] [include/user.h]
	Implemented UserSeeUserDo.

	* [msdos/int21.c] [include/msdos.h]
	Added "GET LIST OF LISTS" (INT 21/52h).

Sat Mar 14 15:48:02 1998  Douglas Ridgway <ridgway@gmcl.com>

	* [include/windows.h] [relay32/gdi32.spec] [objects/enhmetafile.c]
	Beginnings of enhanced metafile support.

Fri Mar 13 20:53:09 1998  John Richardson <jrichard@zko.dec.com>

	* [win32/console.c]
	Restart interrupted console writes.

Fri Mar 13 18:59:24 1998  Matthew Becker <mbecker@glasscity.net>

	* [*/*.c]
	Updated documentation for API manpages.

	* [windows/dce.c]
	ReleaseDC16: Fixed cast.

	* [include/windows.h] [memory/virtual.c]
	VirtualQuery{Ex} should return DWORD instead of BOOL32.

Fri Mar 13 13:03:06 1998  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>

	* [README][documentation/status/]
	README updated, added lzexpand,version and multimedia
	status notes to new documentation/status directory.

	* [ole/*.c][if1632/typelib.spec]
	Added typelib stubs, several small additions and fixes.

	* [loader/pe_image.c]
	Fixed a small bug (fixup_imports got passed the wrong hModule in a
	remapcase).

	* [loader/signal.c][if1632/signal.c][misc/winsock_dns.c]
	  [loader/module.c]
	Fixed some recursive debugger crashes (caused by invalid FS).

	* [misc/registry.c]
	Two bugs fixed.

Fri Mar 13 04:55:01 1998  David Lee Lambert <lamber45@egr.msu.edu>

	* [include/winnt.h] [include/winnls.h]
	Moved LANG_xxx flags to winnls.h

	* [include/winnls.h]
	Added flags for GetDateFormat(); fixed validity of
	LOCALE_SYSTEM_DEFAULT.

	* [include/windows.h] 
	Added GetTimeFormat() prototypes.

	* [ole/ole2nls.c]
	Implemented ASCII date- and time-functions,  using an
	optimized common core;  added stubs for Unicode versions;  
	started work on a Unicode core.

	* [AUTHORS]
	Added my name.

Mon Mar  9 20:10:15 1998  Eric Kohl <ekohl@abo.rhein-zeitung.de>

	* [relay32/comctl32.spec] [include/imagelist.h]
	  [include/commctrl.h] [misc/imagelist.c] [misc/Makefile.in]
	First attempt at implementing ImageLists.

Sun Mar  8 20:19:49 1998  Uwe Bonnes  <bon@elektron.ikp.physik.tu-darmstadt.de>

	* [files/dos_fs.c] [configure.in]
	Try to get FileTimeToLocalFileTime,FileTimeToSystemTime and
	SystemTimeToFileTime right.
	Use timegm() where available.

	* [misc/lstr.c]
	Fix an off by one error in FormatMessage and handle the case 
	when args = NULL (used by programs to get the length of the 
	string).

	* [win32/console.c]
	Actual display a per-process Title string, better working
	attempt for WriteConsole32W and ReadConsole32W.

Fri Mar  6 20:33:45 1998  Slaven Rezic  <eserte@cs.tu-berlin.de>

	* [include/config.h.in][configure.in][multimedia/audio.c]
	  [multimedia/dsound.c]
	Added check for FreeBSD sound system.

Sun Mar  1 17:40:10 1998  Jason Schonberg <schon@mti.sgi.com>

	* [controls/edit.c] [include/ole.h] [include/shlobj.h]
	Removed final commas in enum types.

Mon Feb 23 07:52:18 1998  Luiz Otavio L. Zorzella  <zorzella@nr.conexware.com>

	* [multimedia/time.c]
	Workaround to avoid infinite recursion inside timeGetTime.

	* [multimedia/audio.c]
	WODM_GETNUMDEVS and WIDM_GETNUMDEVS only return 1 now if the
	SOUND_DEV can be opened, or if it's busy.
1998-03-15 20:29:56 +00:00

1322 lines
38 KiB
C

/*
* GDI Device Context functions
*
* Copyright 1993 Alexandre Julliard
*
*/
#include <stdlib.h>
#include <string.h>
#include "gdi.h"
#include "heap.h"
#include "metafile.h"
#include "color.h"
#include "debug.h"
#include "font.h"
#include "winerror.h"
#include "x11font.h"
extern void CLIPPING_UpdateGCRegion( DC * dc ); /* objects/clipping.c */
/* ROP code to GC function conversion */
const int DC_XROPfunction[16] =
{
GXclear, /* R2_BLACK */
GXnor, /* R2_NOTMERGEPEN */
GXandInverted, /* R2_MASKNOTPEN */
GXcopyInverted, /* R2_NOTCOPYPEN */
GXandReverse, /* R2_MASKPENNOT */
GXinvert, /* R2_NOT */
GXxor, /* R2_XORPEN */
GXnand, /* R2_NOTMASKPEN */
GXand, /* R2_MASKPEN */
GXequiv, /* R2_NOTXORPEN */
GXnoop, /* R2_NOP */
GXorInverted, /* R2_MERGENOTPEN */
GXcopy, /* R2_COPYPEN */
GXorReverse, /* R2_MERGEPENNOT */
GXor, /* R2_MERGEPEN */
GXset /* R2_WHITE */
};
/***********************************************************************
* DC_FillDevCaps
*
* Fill the device caps structure.
*/
void DC_FillDevCaps( DeviceCaps * caps )
{
caps->version = 0x300;
caps->technology = DT_RASDISPLAY;
caps->horzSize = WidthMMOfScreen(screen) * screenWidth / WidthOfScreen(screen);
caps->vertSize = HeightMMOfScreen(screen) * screenHeight / HeightOfScreen(screen);
caps->horzRes = screenWidth;
caps->vertRes = screenHeight;
caps->bitsPixel = screenDepth;
caps->planes = 1;
caps->numBrushes = 16+6; /* 16 solid + 6 hatched brushes */
caps->numPens = 16; /* 16 solid pens */
caps->numMarkers = 0;
caps->numFonts = 0;
caps->numColors = 100;
caps->pdeviceSize = 0;
caps->curveCaps = CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES |
CC_WIDE | CC_STYLED | CC_WIDESTYLED |
CC_INTERIORS | CC_ROUNDRECT;
caps->lineCaps = LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE |
LC_STYLED | LC_WIDESTYLED | LC_INTERIORS;
caps->polygonalCaps = PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON |
PC_SCANLINE | PC_WIDE | PC_STYLED |
PC_WIDESTYLED | PC_INTERIORS;
caps->textCaps = TC_OP_CHARACTER | TC_OP_STROKE | TC_CP_STROKE |
TC_IA_ABLE | TC_UA_ABLE | TC_SO_ABLE | TC_RA_ABLE;
caps->clipCaps = CP_REGION;
caps->rasterCaps = RC_BITBLT | RC_BANDING | RC_SCALING | RC_BITMAP64 |
RC_DI_BITMAP | RC_DIBTODEV | RC_BIGFONT|
RC_STRETCHBLT | RC_STRETCHDIB | RC_DEVBITS;
if( !(COLOR_GetSystemPaletteFlags() & COLOR_VIRTUAL) )
caps->rasterCaps |= RC_PALETTE;
caps->aspectX = 36; /* ?? */
caps->aspectY = 36; /* ?? */
caps->aspectXY = 51;
caps->logPixelsX = (int)(caps->horzRes * 25.4 / caps->horzSize);
caps->logPixelsY = (int)(caps->vertRes * 25.4 / caps->vertSize);
caps->sizePalette = (caps->rasterCaps & RC_PALETTE)
? DefaultVisual(display,DefaultScreen(display))->map_entries
: 0;
caps->numReserved = 0;
caps->colorRes = 0;
}
/***********************************************************************
* DC_Init_DC_INFO
*
* Fill the WIN_DC_INFO structure.
*/
static void DC_Init_DC_INFO( WIN_DC_INFO *win_dc_info )
{
win_dc_info->flags = 0;
win_dc_info->devCaps = NULL;
win_dc_info->hClipRgn = 0;
win_dc_info->hVisRgn = 0;
win_dc_info->hGCClipRgn = 0;
win_dc_info->hPen = STOCK_BLACK_PEN;
win_dc_info->hBrush = STOCK_WHITE_BRUSH;
win_dc_info->hFont = STOCK_SYSTEM_FONT;
win_dc_info->hBitmap = 0;
win_dc_info->hFirstBitmap = 0;
win_dc_info->hDevice = 0;
win_dc_info->hPalette = STOCK_DEFAULT_PALETTE;
win_dc_info->ROPmode = R2_COPYPEN;
win_dc_info->polyFillMode = ALTERNATE;
win_dc_info->stretchBltMode = BLACKONWHITE;
win_dc_info->relAbsMode = ABSOLUTE;
win_dc_info->backgroundMode = OPAQUE;
win_dc_info->backgroundColor = RGB( 255, 255, 255 );
win_dc_info->textColor = RGB( 0, 0, 0 );
win_dc_info->backgroundPixel = 0;
win_dc_info->textPixel = 0;
win_dc_info->brushOrgX = 0;
win_dc_info->brushOrgY = 0;
win_dc_info->textAlign = TA_LEFT | TA_TOP | TA_NOUPDATECP;
win_dc_info->charExtra = 0;
win_dc_info->breakTotalExtra = 0;
win_dc_info->breakCount = 0;
win_dc_info->breakExtra = 0;
win_dc_info->breakRem = 0;
win_dc_info->bitsPerPixel = 1;
win_dc_info->MapMode = MM_TEXT;
win_dc_info->GraphicsMode = GM_COMPATIBLE;
win_dc_info->DCOrgX = 0;
win_dc_info->DCOrgY = 0;
win_dc_info->CursPosX = 0;
win_dc_info->CursPosY = 0;
win_dc_info->ArcDirection = AD_COUNTERCLOCKWISE;
win_dc_info->UseWorldXform = FALSE;
win_dc_info->WorldXform.eM11 = 1.0f;
win_dc_info->WorldXform.eM12 = 0.0f;
win_dc_info->WorldXform.eM21 = 0.0f;
win_dc_info->WorldXform.eM22 = 1.0f;
win_dc_info->WorldXform.eDx = 0.0f;
win_dc_info->WorldXform.eDy = 0.0f;
PATH_InitGdiPath(&win_dc_info->path);
}
/***********************************************************************
* DC_AllocDC
*/
DC *DC_AllocDC( const DC_FUNCTIONS *funcs )
{
HDC16 hdc;
DC *dc;
if (!(hdc = GDI_AllocObject( sizeof(DC), DC_MAGIC ))) return NULL;
dc = (DC *) GDI_HEAP_LOCK( hdc );
dc->hSelf = hdc;
dc->funcs = funcs;
dc->physDev = NULL;
dc->saveLevel = 0;
dc->dwHookData = 0L;
dc->hookProc = NULL;
dc->wndOrgX = 0;
dc->wndOrgY = 0;
dc->wndExtX = 1;
dc->wndExtY = 1;
dc->vportOrgX = 0;
dc->vportOrgY = 0;
dc->vportExtX = 1;
dc->vportExtY = 1;
DC_Init_DC_INFO( &dc->w );
return dc;
}
/***********************************************************************
* DC_GetDCPtr
*/
DC *DC_GetDCPtr( HDC32 hdc )
{
GDIOBJHDR *ptr = (GDIOBJHDR *)GDI_HEAP_LOCK( hdc );
if (!ptr) return NULL;
if ((ptr->wMagic == DC_MAGIC) || (ptr->wMagic == METAFILE_DC_MAGIC))
return (DC *)ptr;
GDI_HEAP_UNLOCK( hdc );
return NULL;
}
/***********************************************************************
* DC_InitDC
*
* Setup device-specific DC values for a newly created DC.
*/
void DC_InitDC( DC* dc )
{
RealizeDefaultPalette( dc->hSelf );
SetTextColor32( dc->hSelf, dc->w.textColor );
SetBkColor32( dc->hSelf, dc->w.backgroundColor );
SelectObject32( dc->hSelf, dc->w.hPen );
SelectObject32( dc->hSelf, dc->w.hBrush );
SelectObject32( dc->hSelf, dc->w.hFont );
CLIPPING_UpdateGCRegion( dc );
}
/***********************************************************************
* DC_SetupGCForPatBlt
*
* Setup the GC for a PatBlt operation using current brush.
* If fMapColors is TRUE, X pixels are mapped to Windows colors.
* Return FALSE if brush is BS_NULL, TRUE otherwise.
*/
BOOL32 DC_SetupGCForPatBlt( DC * dc, GC gc, BOOL32 fMapColors )
{
XGCValues val;
unsigned long mask;
Pixmap pixmap = 0;
if (dc->u.x.brush.style == BS_NULL) return FALSE;
if (dc->u.x.brush.pixel == -1)
{
/* Special case used for monochrome pattern brushes.
* We need to swap foreground and background because
* Windows does it the wrong way...
*/
val.foreground = dc->w.backgroundPixel;
val.background = dc->w.textPixel;
}
else
{
val.foreground = dc->u.x.brush.pixel;
val.background = dc->w.backgroundPixel;
}
if (fMapColors && COLOR_PixelToPalette)
{
val.foreground = COLOR_PixelToPalette[val.foreground];
val.background = COLOR_PixelToPalette[val.background];
}
if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
val.function = DC_XROPfunction[dc->w.ROPmode-1];
/*
** Let's replace GXinvert by GXxor with (black xor white)
** This solves the selection color and leak problems in excel
** FIXME : Let's do that only if we work with X-pixels, not with Win-pixels
*/
if (val.function == GXinvert)
{
val.foreground = BlackPixelOfScreen(screen) ^ WhitePixelOfScreen(screen);
val.function = GXxor;
}
val.fill_style = dc->u.x.brush.fillStyle;
switch(val.fill_style)
{
case FillStippled:
case FillOpaqueStippled:
if (dc->w.backgroundMode==OPAQUE) val.fill_style = FillOpaqueStippled;
val.stipple = dc->u.x.brush.pixmap;
mask = GCStipple;
break;
case FillTiled:
if (fMapColors && COLOR_PixelToPalette)
{
register int x, y;
XImage *image;
EnterCriticalSection( &X11DRV_CritSection );
pixmap = XCreatePixmap( display, rootWindow, 8, 8, screenDepth );
image = XGetImage( display, dc->u.x.brush.pixmap, 0, 0, 8, 8,
AllPlanes, ZPixmap );
for (y = 0; y < 8; y++)
for (x = 0; x < 8; x++)
XPutPixel( image, x, y,
COLOR_PixelToPalette[XGetPixel( image, x, y)] );
XPutImage( display, pixmap, gc, image, 0, 0, 0, 0, 8, 8 );
XDestroyImage( image );
LeaveCriticalSection( &X11DRV_CritSection );
val.tile = pixmap;
}
else val.tile = dc->u.x.brush.pixmap;
mask = GCTile;
break;
default:
mask = 0;
break;
}
val.ts_x_origin = dc->w.DCOrgX + dc->w.brushOrgX;
val.ts_y_origin = dc->w.DCOrgY + dc->w.brushOrgY;
val.fill_rule = (dc->w.polyFillMode==WINDING) ? WindingRule : EvenOddRule;
TSXChangeGC( display, gc,
GCFunction | GCForeground | GCBackground | GCFillStyle |
GCFillRule | GCTileStipXOrigin | GCTileStipYOrigin | mask,
&val );
if (pixmap) TSXFreePixmap( display, pixmap );
return TRUE;
}
/***********************************************************************
* DC_SetupGCForBrush
*
* Setup dc->u.x.gc for drawing operations using current brush.
* Return FALSE if brush is BS_NULL, TRUE otherwise.
*/
BOOL32 DC_SetupGCForBrush( DC * dc )
{
return DC_SetupGCForPatBlt( dc, dc->u.x.gc, FALSE );
}
/***********************************************************************
* DC_SetupGCForPen
*
* Setup dc->u.x.gc for drawing operations using current pen.
* Return FALSE if pen is PS_NULL, TRUE otherwise.
*/
BOOL32 DC_SetupGCForPen( DC * dc )
{
XGCValues val;
if (dc->u.x.pen.style == PS_NULL) return FALSE;
if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
switch (dc->w.ROPmode)
{
case R2_BLACK :
val.foreground = BlackPixelOfScreen( screen );
val.function = GXcopy;
break;
case R2_WHITE :
val.foreground = WhitePixelOfScreen( screen );
val.function = GXcopy;
break;
case R2_XORPEN :
val.foreground = dc->u.x.pen.pixel;
/* It is very unlikely someone wants to XOR with 0 */
/* This fixes the rubber-drawings in paintbrush */
if (val.foreground == 0)
val.foreground = BlackPixelOfScreen( screen )
^ WhitePixelOfScreen( screen );
val.function = GXxor;
break;
default :
val.foreground = dc->u.x.pen.pixel;
val.function = DC_XROPfunction[dc->w.ROPmode-1];
}
val.background = dc->w.backgroundPixel;
val.fill_style = FillSolid;
if ((dc->u.x.pen.style!=PS_SOLID) && (dc->u.x.pen.style!=PS_INSIDEFRAME))
{
TSXSetDashes( display, dc->u.x.gc, 0,
dc->u.x.pen.dashes, dc->u.x.pen.dash_len );
val.line_style = (dc->w.backgroundMode == OPAQUE) ?
LineDoubleDash : LineOnOffDash;
}
else val.line_style = LineSolid;
val.line_width = dc->u.x.pen.width;
if (val.line_width <= 1) {
val.cap_style = CapNotLast;
} else {
switch (dc->u.x.pen.endcap)
{
case PS_ENDCAP_SQUARE:
val.cap_style = CapProjecting;
break;
case PS_ENDCAP_FLAT:
val.cap_style = CapButt;
break;
case PS_ENDCAP_ROUND:
default:
val.cap_style = CapRound;
}
}
switch (dc->u.x.pen.linejoin)
{
case PS_JOIN_BEVEL:
val.join_style = JoinBevel;
case PS_JOIN_MITER:
val.join_style = JoinMiter;
case PS_JOIN_ROUND:
default:
val.join_style = JoinRound;
}
TSXChangeGC( display, dc->u.x.gc,
GCFunction | GCForeground | GCBackground | GCLineWidth |
GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle, &val );
return TRUE;
}
/***********************************************************************
* DC_SetupGCForText
*
* Setup dc->u.x.gc for text drawing operations.
* Return FALSE if the font is null, TRUE otherwise.
*/
BOOL32 DC_SetupGCForText( DC * dc )
{
XFontStruct* xfs = XFONT_GetFontStruct( dc->u.x.font );
if( xfs )
{
XGCValues val;
if (dc->w.flags & DC_DIRTY) CLIPPING_UpdateGCRegion(dc);
val.function = GXcopy; /* Text is always GXcopy */
val.foreground = dc->w.textPixel;
val.background = dc->w.backgroundPixel;
val.fill_style = FillSolid;
val.font = xfs->fid;
TSXChangeGC( display, dc->u.x.gc,
GCFunction | GCForeground | GCBackground | GCFillStyle |
GCFont, &val );
return TRUE;
}
fprintf( stderr, "DC_SetupGCForText: physical font failure\n" );
return FALSE;
}
/***********************************************************************
* GetDCState (GDI.179)
*/
HDC16 WINAPI GetDCState( HDC16 hdc )
{
DC * newdc, * dc;
HGDIOBJ16 handle;
if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
if (!(handle = GDI_AllocObject( sizeof(DC), DC_MAGIC )))
{
GDI_HEAP_UNLOCK( hdc );
return 0;
}
newdc = (DC *) GDI_HEAP_LOCK( handle );
TRACE(dc, "(%04x): returning %04x\n", hdc, handle );
memset( &newdc->u.x, 0, sizeof(newdc->u.x) );
newdc->w.flags = dc->w.flags | DC_SAVED;
newdc->w.devCaps = dc->w.devCaps;
newdc->w.hPen = dc->w.hPen;
newdc->w.hBrush = dc->w.hBrush;
newdc->w.hFont = dc->w.hFont;
newdc->w.hBitmap = dc->w.hBitmap;
newdc->w.hFirstBitmap = dc->w.hFirstBitmap;
newdc->w.hDevice = dc->w.hDevice;
newdc->w.hPalette = dc->w.hPalette;
newdc->w.bitsPerPixel = dc->w.bitsPerPixel;
newdc->w.ROPmode = dc->w.ROPmode;
newdc->w.polyFillMode = dc->w.polyFillMode;
newdc->w.stretchBltMode = dc->w.stretchBltMode;
newdc->w.relAbsMode = dc->w.relAbsMode;
newdc->w.backgroundMode = dc->w.backgroundMode;
newdc->w.backgroundColor = dc->w.backgroundColor;
newdc->w.textColor = dc->w.textColor;
newdc->w.backgroundPixel = dc->w.backgroundPixel;
newdc->w.textPixel = dc->w.textPixel;
newdc->w.brushOrgX = dc->w.brushOrgX;
newdc->w.brushOrgY = dc->w.brushOrgY;
newdc->w.textAlign = dc->w.textAlign;
newdc->w.charExtra = dc->w.charExtra;
newdc->w.breakTotalExtra = dc->w.breakTotalExtra;
newdc->w.breakCount = dc->w.breakCount;
newdc->w.breakExtra = dc->w.breakExtra;
newdc->w.breakRem = dc->w.breakRem;
newdc->w.MapMode = dc->w.MapMode;
newdc->w.GraphicsMode = dc->w.GraphicsMode;
newdc->w.DCOrgX = dc->w.DCOrgX;
newdc->w.DCOrgY = dc->w.DCOrgY;
newdc->w.CursPosX = dc->w.CursPosX;
newdc->w.CursPosY = dc->w.CursPosY;
newdc->w.ArcDirection = dc->w.ArcDirection;
newdc->w.UseWorldXform = dc->w.UseWorldXform;
newdc->w.WorldXform = dc->w.WorldXform;
newdc->wndOrgX = dc->wndOrgX;
newdc->wndOrgY = dc->wndOrgY;
newdc->wndExtX = dc->wndExtX;
newdc->wndExtY = dc->wndExtY;
newdc->vportOrgX = dc->vportOrgX;
newdc->vportOrgY = dc->vportOrgY;
newdc->vportExtX = dc->vportExtX;
newdc->vportExtY = dc->vportExtY;
newdc->hSelf = (HDC32)handle;
newdc->saveLevel = 0;
PATH_InitGdiPath( &newdc->w.path );
/* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
newdc->w.hGCClipRgn = newdc->w.hVisRgn = 0;
if (dc->w.hClipRgn)
{
newdc->w.hClipRgn = CreateRectRgn32( 0, 0, 0, 0 );
CombineRgn32( newdc->w.hClipRgn, dc->w.hClipRgn, 0, RGN_COPY );
}
else
newdc->w.hClipRgn = 0;
GDI_HEAP_UNLOCK( handle );
GDI_HEAP_UNLOCK( hdc );
return handle;
}
/***********************************************************************
* SetDCState (GDI.180)
*/
void WINAPI SetDCState( HDC16 hdc, HDC16 hdcs )
{
DC *dc, *dcs;
if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return;
if (!(dcs = (DC *) GDI_GetObjPtr( hdcs, DC_MAGIC )))
{
GDI_HEAP_UNLOCK( hdc );
return;
}
if (!dcs->w.flags & DC_SAVED)
{
GDI_HEAP_UNLOCK( hdc );
GDI_HEAP_UNLOCK( hdcs );
return;
}
TRACE(dc, "%04x %04x\n", hdc, hdcs );
dc->w.flags = dcs->w.flags & ~DC_SAVED;
dc->w.devCaps = dcs->w.devCaps;
dc->w.hFirstBitmap = dcs->w.hFirstBitmap;
dc->w.hDevice = dcs->w.hDevice;
dc->w.ROPmode = dcs->w.ROPmode;
dc->w.polyFillMode = dcs->w.polyFillMode;
dc->w.stretchBltMode = dcs->w.stretchBltMode;
dc->w.relAbsMode = dcs->w.relAbsMode;
dc->w.backgroundMode = dcs->w.backgroundMode;
dc->w.backgroundColor = dcs->w.backgroundColor;
dc->w.textColor = dcs->w.textColor;
dc->w.backgroundPixel = dcs->w.backgroundPixel;
dc->w.textPixel = dcs->w.textPixel;
dc->w.brushOrgX = dcs->w.brushOrgX;
dc->w.brushOrgY = dcs->w.brushOrgY;
dc->w.textAlign = dcs->w.textAlign;
dc->w.charExtra = dcs->w.charExtra;
dc->w.breakTotalExtra = dcs->w.breakTotalExtra;
dc->w.breakCount = dcs->w.breakCount;
dc->w.breakExtra = dcs->w.breakExtra;
dc->w.breakRem = dcs->w.breakRem;
dc->w.MapMode = dcs->w.MapMode;
dc->w.GraphicsMode = dcs->w.GraphicsMode;
dc->w.DCOrgX = dcs->w.DCOrgX;
dc->w.DCOrgY = dcs->w.DCOrgY;
dc->w.CursPosX = dcs->w.CursPosX;
dc->w.CursPosY = dcs->w.CursPosY;
dc->w.ArcDirection = dcs->w.ArcDirection;
dc->w.UseWorldXform = dcs->w.UseWorldXform;
dc->w.WorldXform = dcs->w.WorldXform;
dc->wndOrgX = dcs->wndOrgX;
dc->wndOrgY = dcs->wndOrgY;
dc->wndExtX = dcs->wndExtX;
dc->wndExtY = dcs->wndExtY;
dc->vportOrgX = dcs->vportOrgX;
dc->vportOrgY = dcs->vportOrgY;
dc->vportExtX = dcs->vportExtX;
dc->vportExtY = dcs->vportExtY;
if (!(dc->w.flags & DC_MEMORY)) dc->w.bitsPerPixel = dcs->w.bitsPerPixel;
SelectClipRgn32( hdc, dcs->w.hClipRgn );
SelectObject32( hdc, dcs->w.hBitmap );
SelectObject32( hdc, dcs->w.hBrush );
SelectObject32( hdc, dcs->w.hFont );
SelectObject32( hdc, dcs->w.hPen );
GDISelectPalette( hdc, dcs->w.hPalette, FALSE );
GDI_HEAP_UNLOCK( hdc );
GDI_HEAP_UNLOCK( hdcs );
}
/***********************************************************************
* SaveDC16 (GDI.30)
*/
INT16 WINAPI SaveDC16( HDC16 hdc )
{
return (INT16)SaveDC32( hdc );
}
/***********************************************************************
* SaveDC32 (GDI32.292)
*/
INT32 WINAPI SaveDC32( HDC32 hdc )
{
HDC32 hdcs;
DC * dc, * dcs;
INT32 ret;
dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
if (!dc)
{
dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
if (!dc) return 0;
MF_MetaParam0(dc, META_SAVEDC);
GDI_HEAP_UNLOCK( hdc );
return 1; /* ?? */
}
if (!(hdcs = GetDCState( hdc )))
{
GDI_HEAP_UNLOCK( hdc );
return 0;
}
dcs = (DC *) GDI_HEAP_LOCK( hdcs );
/* Copy path. The reason why path saving / restoring is in SaveDC/
* RestoreDC and not in GetDCState/SetDCState is that the ...DCState
* functions are only in Win16 (which doesn't have paths) and that
* SetDCState doesn't allow us to signal an error (which can happen
* when copying paths).
*/
if (!PATH_AssignGdiPath( &dcs->w.path, &dc->w.path ))
{
GDI_HEAP_UNLOCK( hdc );
GDI_HEAP_UNLOCK( hdcs );
DeleteDC32( hdcs );
return 0;
}
dcs->header.hNext = dc->header.hNext;
dc->header.hNext = hdcs;
TRACE(dc, "(%04x): returning %d\n", hdc, dc->saveLevel+1 );
ret = ++dc->saveLevel;
GDI_HEAP_UNLOCK( hdcs );
GDI_HEAP_UNLOCK( hdc );
return ret;
}
/***********************************************************************
* RestoreDC16 (GDI.39)
*/
BOOL16 WINAPI RestoreDC16( HDC16 hdc, INT16 level )
{
return RestoreDC32( hdc, level );
}
/***********************************************************************
* RestoreDC32 (GDI32.290)
*/
BOOL32 WINAPI RestoreDC32( HDC32 hdc, INT32 level )
{
DC * dc, * dcs;
BOOL32 success;
TRACE(dc, "%04x %d\n", hdc, level );
dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
if (!dc)
{
dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
if (!dc) return FALSE;
if (level != -1)
{
GDI_HEAP_UNLOCK( hdc );
return FALSE;
}
MF_MetaParam1(dc, META_RESTOREDC, level);
GDI_HEAP_UNLOCK( hdc );
return TRUE;
}
if (level == -1) level = dc->saveLevel;
if ((level < 1) || (level > dc->saveLevel))
{
GDI_HEAP_UNLOCK( hdc );
return FALSE;
}
success=TRUE;
while (dc->saveLevel >= level)
{
HDC16 hdcs = dc->header.hNext;
if (!(dcs = (DC *) GDI_GetObjPtr( hdcs, DC_MAGIC )))
{
GDI_HEAP_UNLOCK( hdc );
return FALSE;
}
dc->header.hNext = dcs->header.hNext;
if (--dc->saveLevel < level)
{
SetDCState( hdc, hdcs );
if (!PATH_AssignGdiPath( &dc->w.path, &dcs->w.path ))
/* FIXME: This might not be quite right, since we're
* returning FALSE but still destroying the saved DC state */
success=FALSE;
}
DeleteDC32( hdcs );
}
GDI_HEAP_UNLOCK( hdc );
return success;
}
/***********************************************************************
* CreateDC16 (GDI.53)
*/
HDC16 WINAPI CreateDC16( LPCSTR driver, LPCSTR device, LPCSTR output,
const DEVMODE16 *initData )
{
DC * dc;
const DC_FUNCTIONS *funcs;
if (!(funcs = DRIVER_FindDriver( driver ))) return 0;
if (!(dc = DC_AllocDC( funcs ))) return 0;
dc->w.flags = 0;
TRACE(dc, "(%s %s %s): returning %04x\n",
driver, device, output, dc->hSelf );
if (dc->funcs->pCreateDC &&
!dc->funcs->pCreateDC( dc, driver, device, output, initData ))
{
WARN(dc, "creation aborted by device\n" );
GDI_HEAP_FREE( dc->hSelf );
return 0;
}
DC_InitDC( dc );
GDI_HEAP_UNLOCK( dc->hSelf );
return dc->hSelf;
}
/***********************************************************************
* CreateDC32A (GDI32.)
*/
HDC32 WINAPI CreateDC32A( LPCSTR driver, LPCSTR device, LPCSTR output,
const DEVMODE32A *initData )
{
return CreateDC16( driver, device, output, (const DEVMODE16 *)initData );
}
/***********************************************************************
* CreateDC32W (GDI32.)
*/
HDC32 WINAPI CreateDC32W( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
const DEVMODE32W *initData )
{
LPSTR driverA = HEAP_strdupWtoA( GetProcessHeap(), 0, driver );
LPSTR deviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, device );
LPSTR outputA = HEAP_strdupWtoA( GetProcessHeap(), 0, output );
HDC32 res = CreateDC16( driverA, deviceA, outputA,
(const DEVMODE16 *)initData /*FIXME*/ );
HeapFree( GetProcessHeap(), 0, driverA );
HeapFree( GetProcessHeap(), 0, deviceA );
HeapFree( GetProcessHeap(), 0, outputA );
return res;
}
/***********************************************************************
* CreateIC16 (GDI.153)
*/
HDC16 WINAPI CreateIC16( LPCSTR driver, LPCSTR device, LPCSTR output,
const DEVMODE16* initData )
{
/* Nothing special yet for ICs */
return CreateDC16( driver, device, output, initData );
}
/***********************************************************************
* CreateIC32A (GDI32.49)
*/
HDC32 WINAPI CreateIC32A( LPCSTR driver, LPCSTR device, LPCSTR output,
const DEVMODE32A* initData )
{
/* Nothing special yet for ICs */
return CreateDC32A( driver, device, output, initData );
}
/***********************************************************************
* CreateIC32W (GDI32.50)
*/
HDC32 WINAPI CreateIC32W( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
const DEVMODE32W* initData )
{
/* Nothing special yet for ICs */
return CreateDC32W( driver, device, output, initData );
}
/***********************************************************************
* CreateCompatibleDC16 (GDI.52)
*/
HDC16 WINAPI CreateCompatibleDC16( HDC16 hdc )
{
return (HDC16)CreateCompatibleDC32( hdc );
}
/***********************************************************************
* CreateCompatibleDC32 (GDI32.31)
*/
HDC32 WINAPI CreateCompatibleDC32( HDC32 hdc )
{
DC *dc, *origDC;
HBITMAP32 hbitmap;
const DC_FUNCTIONS *funcs;
if ((origDC = (DC *)GDI_GetObjPtr( hdc, DC_MAGIC ))) funcs = origDC->funcs;
else funcs = DRIVER_FindDriver( "DISPLAY" );
if (!funcs) return 0;
if (!(dc = DC_AllocDC( funcs ))) return 0;
TRACE(dc, "(%04x): returning %04x\n",
hdc, dc->hSelf );
/* Create default bitmap */
if (!(hbitmap = CreateBitmap32( 1, 1, 1, 1, NULL )))
{
GDI_HEAP_FREE( dc->hSelf );
return 0;
}
dc->w.flags = DC_MEMORY;
dc->w.bitsPerPixel = 1;
dc->w.hBitmap = hbitmap;
dc->w.hFirstBitmap = hbitmap;
if (dc->funcs->pCreateDC &&
!dc->funcs->pCreateDC( dc, NULL, NULL, NULL, NULL ))
{
WARN(dc, "creation aborted by device\n");
DeleteObject32( hbitmap );
GDI_HEAP_FREE( dc->hSelf );
return 0;
}
DC_InitDC( dc );
GDI_HEAP_UNLOCK( dc->hSelf );
return dc->hSelf;
}
/***********************************************************************
* DeleteDC16 (GDI.68)
*/
BOOL16 WINAPI DeleteDC16( HDC16 hdc )
{
return DeleteDC32( hdc );
}
/***********************************************************************
* DeleteDC32 (GDI32.67)
*/
BOOL32 WINAPI DeleteDC32( HDC32 hdc )
{
DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
if (!dc) return FALSE;
TRACE(dc, "%04x\n", hdc );
while (dc->saveLevel)
{
DC * dcs;
HDC16 hdcs = dc->header.hNext;
if (!(dcs = (DC *) GDI_GetObjPtr( hdcs, DC_MAGIC ))) break;
dc->header.hNext = dcs->header.hNext;
dc->saveLevel--;
DeleteDC32( hdcs );
}
if (!(dc->w.flags & DC_SAVED))
{
SelectObject32( hdc, STOCK_BLACK_PEN );
SelectObject32( hdc, STOCK_WHITE_BRUSH );
SelectObject32( hdc, STOCK_SYSTEM_FONT );
if (dc->w.flags & DC_MEMORY) DeleteObject32( dc->w.hFirstBitmap );
if (dc->funcs->pDeleteDC) dc->funcs->pDeleteDC(dc);
}
if (dc->w.hClipRgn) DeleteObject32( dc->w.hClipRgn );
if (dc->w.hVisRgn) DeleteObject32( dc->w.hVisRgn );
if (dc->w.hGCClipRgn) DeleteObject32( dc->w.hGCClipRgn );
PATH_DestroyGdiPath(&dc->w.path);
return GDI_FreeObject( hdc );
}
/***********************************************************************
* ResetDC16 (GDI.376)
*/
HDC16 WINAPI ResetDC16( HDC16 hdc, const DEVMODE16 *devmode )
{
fprintf( stderr, "ResetDC16: empty stub!\n" );
return hdc;
}
/***********************************************************************
* ResetDC32A (GDI32.287)
*/
HDC32 WINAPI ResetDC32A( HDC32 hdc, const DEVMODE32A *devmode )
{
fprintf( stderr, "ResetDC32A: empty stub!\n" );
return hdc;
}
/***********************************************************************
* ResetDC32W (GDI32.288)
*/
HDC32 WINAPI ResetDC32W( HDC32 hdc, const DEVMODE32W *devmode )
{
fprintf( stderr, "ResetDC32A: empty stub!\n" );
return hdc;
}
/***********************************************************************
* GetDeviceCaps16 (GDI.80)
*/
INT16 WINAPI GetDeviceCaps16( HDC16 hdc, INT16 cap )
{
return GetDeviceCaps32( hdc, cap );
}
/***********************************************************************
* GetDeviceCaps32 (GDI32.171)
*/
INT32 WINAPI GetDeviceCaps32( HDC32 hdc, INT32 cap )
{
DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
INT32 ret;
if (!dc) return 0;
if ((cap < 0) || (cap > sizeof(DeviceCaps)-sizeof(WORD)))
{
GDI_HEAP_UNLOCK( hdc );
return 0;
}
TRACE(dc, "(%04x,%d): returning %d\n",
hdc, cap, *(WORD *)(((char *)dc->w.devCaps) + cap) );
ret = *(WORD *)(((char *)dc->w.devCaps) + cap);
GDI_HEAP_UNLOCK( hdc );
return ret;
}
/***********************************************************************
* SetBkColor16 (GDI.1)
*/
COLORREF WINAPI SetBkColor16( HDC16 hdc, COLORREF color )
{
return SetBkColor32( hdc, color );
}
/***********************************************************************
* SetBkColor32 (GDI32.305)
*/
COLORREF WINAPI SetBkColor32( HDC32 hdc, COLORREF color )
{
COLORREF oldColor;
DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
if (!dc)
{
dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
if (!dc) return 0x80000000;
MF_MetaParam2(dc, META_SETBKCOLOR, HIWORD(color), LOWORD(color));
GDI_HEAP_UNLOCK( hdc );
return 0; /* ?? */
}
oldColor = dc->w.backgroundColor;
dc->w.backgroundColor = color;
dc->w.backgroundPixel = COLOR_ToPhysical( dc, color );
GDI_HEAP_UNLOCK( hdc );
return oldColor;
}
/***********************************************************************
* SetTextColor16 (GDI.9)
*/
COLORREF WINAPI SetTextColor16( HDC16 hdc, COLORREF color )
{
return SetTextColor32( hdc, color );
}
/***********************************************************************
* SetTextColor32 (GDI32.338)
*/
COLORREF WINAPI SetTextColor32( HDC32 hdc, COLORREF color )
{
COLORREF oldColor;
DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
if (!dc)
{
dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
if (!dc) return 0x80000000;
MF_MetaParam2(dc, META_SETTEXTCOLOR, HIWORD(color), LOWORD(color));
GDI_HEAP_UNLOCK( hdc );
return 0; /* ?? */
}
oldColor = dc->w.textColor;
dc->w.textColor = color;
dc->w.textPixel = COLOR_ToPhysical( dc, color );
GDI_HEAP_UNLOCK( hdc );
return oldColor;
}
/***********************************************************************
* SetTextAlign16 (GDI.346)
*/
UINT16 WINAPI SetTextAlign16( HDC16 hdc, UINT16 textAlign )
{
return SetTextAlign32( hdc, textAlign );
}
/***********************************************************************
* SetTextAlign32 (GDI32.336)
*/
UINT32 WINAPI SetTextAlign32( HDC32 hdc, UINT32 textAlign )
{
UINT32 prevAlign;
DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
if (!dc)
{
if (!(dc = (DC *)GDI_GetObjPtr( hdc, METAFILE_DC_MAGIC ))) return 0;
MF_MetaParam1( dc, META_SETTEXTALIGN, textAlign );
GDI_HEAP_UNLOCK( hdc );
return 1;
}
prevAlign = dc->w.textAlign;
dc->w.textAlign = textAlign;
GDI_HEAP_UNLOCK( hdc );
return prevAlign;
}
/***********************************************************************
* GetDCOrgEx (GDI32.168)
*/
BOOL32 WINAPI GetDCOrgEx( HDC32 hDC, LPPOINT32 lpp )
{
DC * dc;
if (!lpp) return FALSE;
if (!(dc = (DC *) GDI_GetObjPtr( hDC, DC_MAGIC ))) return FALSE;
if (!(dc->w.flags & DC_MEMORY))
{
Window root;
int w, h, border, depth;
/* FIXME: this is not correct for managed windows */
TSXGetGeometry( display, dc->u.x.drawable, &root,
&lpp->x, &lpp->y, &w, &h, &border, &depth );
}
else lpp->x = lpp->y = 0;
lpp->x += dc->w.DCOrgX; lpp->y += dc->w.DCOrgY;
GDI_HEAP_UNLOCK( hDC );
return TRUE;
}
/***********************************************************************
* GetDCOrg (GDI.79)
*/
DWORD WINAPI GetDCOrg( HDC16 hdc )
{
POINT32 pt;
if( GetDCOrgEx( hdc, &pt) )
return MAKELONG( (WORD)pt.x, (WORD)pt.y );
return 0;
}
/***********************************************************************
* SetDCOrg (GDI.117)
*/
DWORD WINAPI SetDCOrg( HDC16 hdc, INT16 x, INT16 y )
{
DWORD prevOrg;
DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
if (!dc) return 0;
prevOrg = dc->w.DCOrgX | (dc->w.DCOrgY << 16);
dc->w.DCOrgX = x;
dc->w.DCOrgY = y;
GDI_HEAP_UNLOCK( hdc );
return prevOrg;
}
/***********************************************************************
* GetGraphicsMode (GDI32.188)
*/
INT32 WINAPI GetGraphicsMode( HDC32 hdc )
{
DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
if (!dc) return 0;
return dc->w.GraphicsMode;
}
/***********************************************************************
* SetGraphicsMode (GDI32.317)
*/
INT32 WINAPI SetGraphicsMode( HDC32 hdc, INT32 mode )
{
INT32 ret;
DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
/* One would think that setting the graphics mode to GM_COMPATIBLE
* would also reset the world transformation matrix to the unity
* matrix. However, in Windows, this is not the case. This doesn't
* make a lot of sense to me, but that's the way it is.
*/
if (!dc) return 0;
if ((mode <= 0) || (mode > GM_LAST)) return 0;
ret = dc->w.GraphicsMode;
dc->w.GraphicsMode = mode;
return ret;
}
/***********************************************************************
* GetArcDirection16 (GDI.524)
*/
INT16 WINAPI GetArcDirection16( HDC16 hdc )
{
return GetArcDirection32( (HDC32)hdc );
}
/***********************************************************************
* GetArcDirection32 (GDI32.141)
*/
INT32 WINAPI GetArcDirection32( HDC32 hdc )
{
DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
if (!dc)
return 0;
return dc->w.ArcDirection;
}
/***********************************************************************
* SetArcDirection16 (GDI.525)
*/
INT16 WINAPI SetArcDirection16( HDC16 hdc, INT16 nDirection )
{
return SetArcDirection32( (HDC32)hdc, (INT32)nDirection );
}
/***********************************************************************
* SetArcDirection32 (GDI32.302)
*/
INT32 WINAPI SetArcDirection32( HDC32 hdc, INT32 nDirection )
{
DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
INT32 nOldDirection;
if (!dc)
return 0;
if (nDirection!=AD_COUNTERCLOCKWISE && nDirection!=AD_CLOCKWISE)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
nOldDirection = dc->w.ArcDirection;
dc->w.ArcDirection = nDirection;
return nOldDirection;
}
/***********************************************************************
* GetWorldTransform (GDI32.244)
* FIXME
* Check that SetLastError is being called correctly
*/
BOOL32 WINAPI GetWorldTransform( HDC32 hdc, LPXFORM xform )
{
DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
if (!dc)
/* FIXME: Call SetLastError? */
return FALSE;
if (!xform)
/* FIXME: Call SetLastError? */
return FALSE;
*xform = dc->w.WorldXform;
return TRUE;
}
/***********************************************************************
* SetWorldTransform (GDI32.346)
*/
BOOL32 WINAPI SetWorldTransform( HDC32 hdc, const XFORM *xform )
{
DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
if (!dc)
{
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
if (!xform)
return FALSE;
/* Check that graphics mode is GM_ADVANCED */
if (dc->w.GraphicsMode!=GM_ADVANCED)
return FALSE;
dc->w.WorldXform = *xform;
/* We only have to use the new world transform if it's not the
* identity transformation
*/
dc->w.UseWorldXform=
(xform->eM11!=1.0f || xform->eM12!=0.0f ||
xform->eM21!=0.0f || xform->eM22!=1.0f ||
xform->eDx!=0.0f || xform->eDy!=0.0f);
return TRUE;
}
/***********************************************************************
* SetDCHook (GDI.190)
*/
BOOL16 WINAPI SetDCHook( HDC16 hdc, FARPROC16 hookProc, DWORD dwHookData )
{
DC *dc = (DC *)GDI_GetObjPtr( hdc, DC_MAGIC );
TRACE(dc, "hookProc %08x, default is %08x\n",
(UINT32)hookProc, (UINT32)DCHook );
if (!dc) return FALSE;
dc->hookProc = hookProc;
dc->dwHookData = dwHookData;
GDI_HEAP_UNLOCK( hdc );
return TRUE;
}
/***********************************************************************
* GetDCHook (GDI.191)
*/
DWORD WINAPI GetDCHook( HDC16 hdc, FARPROC16 *phookProc )
{
DC *dc = (DC *)GDI_GetObjPtr( hdc, DC_MAGIC );
if (!dc) return 0;
*phookProc = dc->hookProc;
GDI_HEAP_UNLOCK( hdc );
return dc->dwHookData;
}
/***********************************************************************
* SetHookFlags (GDI.192)
*/
WORD WINAPI SetHookFlags(HDC16 hDC, WORD flags)
{
DC* dc = (DC*)GDI_GetObjPtr( hDC, DC_MAGIC );
if( dc )
{
WORD wRet = dc->w.flags & DC_DIRTY;
/* "Undocumented Windows" info is slightly confusing.
*/
TRACE(dc,"hDC %04x, flags %04x\n",hDC,flags);
if( flags & DCHF_INVALIDATEVISRGN )
dc->w.flags |= DC_DIRTY;
else if( flags & DCHF_VALIDATEVISRGN || !flags )
dc->w.flags &= ~DC_DIRTY;
GDI_HEAP_UNLOCK( hDC );
return wRet;
}
return 0;
}