/*    
	GdiObjects.c	2.42
    	Copyright 1997 Willows Software, Inc. 

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; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.


For more information about the Willows Twin Libraries.

	http://www.willows.com	

To send email to the maintainer of the Willows Twin Libraries.

	mailto:twin@willows.com 

 */

#include <string.h>

#include "windows.h"

#include "GdiObjects.h"
#include "Log.h"
#include "Objects.h"
#include "Kernel.h"
#include "GdiDC.h"
#include "GdiText.h" /* FONTINFO */
#include "DeviceData.h"
#include "Driver.h"
#include "WinConfig.h"

/* imported routines */
extern HFONT DriverCreateFont(LPLOGFONT);
extern BOOL GdiDeleteFont(HFONT);
extern HBRUSH GdiCreateBrush(LPLOGBRUSH);
extern BOOL GdiDeleteBrush(HBRUSH);
extern BOOL GdiDeleteBitmap(HBITMAP);
extern HFONT GdiCreateFont(LPLOGFONT lpLogFont);
extern BOOL GdiDeleteRgn(HRGN hRgn);
extern VOID TWIN_MetaNotify(LPOBJHEAD);

/* internal routines */
static HPEN GdiCreatePen(LPLOGPEN);
static BOOL GdiDeletePen(HPEN);
static BOOL GdiDeletePalette(HPALETTE);

HBITMAP LoadHatchBitmap(int);
BOOL TWIN_DeleteObject(HGDIOBJ, BOOL);

/* API functions */

int WINAPI
EnumObjects(HDC hDC, int fnObjectType, GOBJENUMPROC goEnumProc,
#ifdef	STRICT
		LPARAM lParam)
#else
		LPSTR lParam)
#endif
{
    HDC32 hDC32;
    LSDS_PARAMS argptr;
    int nRet;

    APISTR((LF_API,"EnumObjects: hDC %x, type %x, proc %x\n",
		hDC,fnObjectType,goEnumProc));

    ASSERT_HDC(hDC32,hDC,0);

    argptr.lsde_validate.dwInvalidMask = 0;

    argptr.lsde.enumobj.fnObjectType = fnObjectType;
    argptr.lsde.enumobj.goenmprc = goEnumProc;
    argptr.lsde.enumobj.lParam = (LPARAM)lParam;

    nRet = (int)DC_OUTPUT(LSD_ENUMOBJECTS,hDC32,0L,&argptr);

    RELEASEDCINFO(hDC32);

    return nRet;
}

HGDIOBJ WINAPI
GetStockObject(int nIndex)
{
    int	nObjType = -1;
    LPOBJHEAD	lpObjHead;
    HANDLE	hObj = 0;
    LOGBRUSH	lBrush;
    LOGPEN	lPen;
    LOGFONT	lFont;
    LPLOGPALETTE lpLogPal;
    int		count;

    APISTR((LF_API,"GetStockObject: %x h=%x,\n",nIndex,
		StockObjects[nIndex]));

    /* StockObjects is a cache of handles to objects */
    /* they do NOT get removed */

    if(StockObjects[nIndex])
	return StockObjects[nIndex];

    switch (nIndex) {
	case WHITE_BRUSH:
	    nObjType = OT_BRUSH;
	    lBrush.lbStyle = BS_SOLID;
	    lBrush.lbHatch = 0;
    	    lBrush.lbColor = RGB(255,255,255);
	    break;
	case LTGRAY_BRUSH:
	    nObjType = OT_BRUSH;
	    lBrush.lbStyle = BS_SOLID;
	    lBrush.lbHatch = 0;
    	    lBrush.lbColor = RGB(192,192,192);
	    break;
	case GRAY_BRUSH:
	    nObjType = OT_BRUSH;
	    lBrush.lbStyle = BS_SOLID;
	    lBrush.lbHatch = 0;
    	    lBrush.lbColor = RGB(128,128,128);
	    break;
	case DKGRAY_BRUSH:
	    nObjType = OT_BRUSH;
	    lBrush.lbStyle = BS_SOLID;
	    lBrush.lbHatch = 0;
    	    lBrush.lbColor = RGB(64,64,64);
	    break;
	case BLACK_BRUSH:
	    nObjType = OT_BRUSH;
	    lBrush.lbStyle = BS_SOLID;
	    lBrush.lbHatch = 0;
    	    lBrush.lbColor = RGB(0,0,0);
	    break;
	case NULL_BRUSH:
	    nObjType = OT_BRUSH;
	    lBrush.lbStyle = BS_NULL;
	    lBrush.lbHatch = 0;
    	    lBrush.lbColor = 0;
	    break;
	case WHITE_PEN:
	    nObjType = OT_PEN;
	    lPen.lopnColor = RGB(255,255,255);
	    lPen.lopnStyle = PS_SOLID;
	    break;
	case BLACK_PEN:
	    nObjType = OT_PEN;
	    lPen.lopnColor = RGB(0,0,0);
	    lPen.lopnStyle = PS_SOLID;
	    break;
	case NULL_PEN:
	    nObjType = OT_PEN;
	    lPen.lopnColor = 0;
	    lPen.lopnStyle = PS_NULL;
	    break;
	
    	case SYSTEM_FONT:
    	case SYSTEM_FIXED_FONT:
	    nObjType = OT_FONT;
	    memset((LPVOID)&lFont, 0, sizeof(LOGFONT));

	    lFont.lfHeight = GetTwinInt(WCP_FONTSIZE);
            lFont.lfWeight = GetTwinInt(WCP_FONTBOLD);

	    if (nIndex == SYSTEM_FIXED_FONT)
		strcpy(lFont.lfFaceName,"fixed");
	    else
		GetTwinString(WCP_FONTFACE,lFont.lfFaceName,LF_FACESIZE);
	    break;

	case ANSI_FIXED_FONT:
	    nObjType = OT_FONT;
	    memset((LPVOID)&lFont, 0, sizeof(LOGFONT));
	    lFont.lfHeight = 12;
	    lFont.lfWidth  = 9;
	    lFont.lfClipPrecision = CLIP_STROKE_PRECIS;
	    lFont.lfPitchAndFamily = FIXED_PITCH;
	    strcpy(lFont.lfFaceName, "Courier");
	    break;
    	case ANSI_VAR_FONT:
	    nObjType = OT_FONT;
	    memset((LPVOID)&lFont, 0, sizeof(LOGFONT));
	    lFont.lfHeight = 12;
	    lFont.lfWidth  = 9;
	    lFont.lfClipPrecision = CLIP_STROKE_PRECIS;
	    lFont.lfPitchAndFamily = VARIABLE_PITCH;
	    strcpy(lFont.lfFaceName, "Helv");
	    break;
	case DEVICE_DEFAULT_FONT:
	    nObjType = OT_FONT;
	    memset((LPVOID)&lFont, 0, sizeof(LOGFONT));
	    lFont.lfPitchAndFamily = FIXED_PITCH;
	    break;
	case OEM_FIXED_FONT:
	    nObjType = OT_FONT;
	    memset((LPVOID)&lFont, 0, sizeof(LOGFONT));
	    lFont.lfHeight = 12;
	    lFont.lfWidth  = 8;
	    lFont.lfCharSet = 0xff;
	    lFont.lfClipPrecision = CLIP_STROKE_PRECIS;
	    lFont.lfPitchAndFamily = FIXED_PITCH;
	    strcpy(lFont.lfFaceName, "Terminal");
	    break;

	case DEFAULT_PALETTE:
	    nObjType = OT_PALETTE;
	    lpLogPal = (LPLOGPALETTE)WinMalloc(sizeof(LOGPALETTE)+
				sizeof(PALETTEENTRY)*20);
	    lpLogPal->palVersion = 0x300;
	    lpLogPal->palNumEntries = 20;
	    for (count = 0; count < 8; count ++) {
		    lpLogPal->palPalEntry[count].peRed =
				VGAColors[count].rgbRed;
		    lpLogPal->palPalEntry[count].peGreen =
				VGAColors[count].rgbGreen;
		    lpLogPal->palPalEntry[count].peBlue =
				VGAColors[count].rgbBlue;
		    lpLogPal->palPalEntry[count].peFlags = 0;
	    }
	    for (count = 8; count < 12; count ++) {
		    lpLogPal->palPalEntry[count].peRed =
				NiceColors[count-8].rgbRed;
		    lpLogPal->palPalEntry[count].peGreen =
				NiceColors[count-8].rgbGreen;
		    lpLogPal->palPalEntry[count].peBlue =
				NiceColors[count-8].rgbBlue;
		    lpLogPal->palPalEntry[count].peFlags = 0;
	    }
	    for (count = 12; count < 20; count ++) {
		    lpLogPal->palPalEntry[count].peRed =
				VGAColors[count-4].rgbRed;
		    lpLogPal->palPalEntry[count].peGreen =
				VGAColors[count-4].rgbGreen;
		    lpLogPal->palPalEntry[count].peBlue =
				VGAColors[count-4].rgbBlue;
		    lpLogPal->palPalEntry[count].peFlags = 0;
	    }
	    hObj = (HANDLE)CreatePalette(lpLogPal);
	    WinFree((LPSTR)lpLogPal);
            LOGSTR((LF_OBJECTS,"GetStockObject: DEFAULT_PALETTE %x\n",hObj));
	    break;

	case SYSTEM_BITMAP:
	    hObj = (HANDLE)CreateBitmap(1,1,1,1,NULL);
            LOGSTR((LF_OBJECTS,"GetStockObject: SYSTEM_BITMAP %x\n",hObj));
	    break;

	default:
            LOGSTR((LF_OBJECTS,
			"GetStockObject failed: Unknown object type\n"));
	    return 0;
    }

    if (!hObj) {
	switch(nObjType) {
	    case OT_BRUSH:
    		hObj = CreateBrushIndirect(&lBrush);
		break;
	    case OT_PEN:
		lPen.lopnWidth.x = 1;
		lPen.lopnWidth.y = 1;
    		hObj = CreatePenIndirect(&lPen);
		break;
	    case OT_FONT:
		hObj = (HANDLE)CreateFontIndirect(&lFont);
		break;
	    default:
		break;
	}
    }

    if (hObj) {
	LOGSTR((LF_OBJECTS,"StockObject %x created, h=%x,\n",nIndex,hObj));
	StockObjects[nIndex] = hObj;
	lpObjHead = GETGDIINFO(hObj);
	lpObjHead->wRefCount = (WORD)-1;
    }
    else 
	LOGSTR((LF_OBJECTS,"GetStockObject: failed to create %x\n",nIndex));

    return hObj;
}

HBRUSH WINAPI
CreateSolidBrush(COLORREF crColor)
{
    LOGBRUSH lBrush;

    LOGSTR((LF_API,"CreateSolidBrush: color %x\n",crColor));

    lBrush.lbStyle = BS_SOLID;
    lBrush.lbColor = crColor;
    lBrush.lbHatch = 0;

    return CreateBrushIndirect(&lBrush);
}

HBRUSH WINAPI
CreateHatchBrush(int nIndex,COLORREF crColor)
{
    LOGBRUSH lBrush;

    LOGSTR((LF_API,"CreateHatchBrush: index %d color %x\n",nIndex,crColor));

    lBrush.lbStyle = BS_HATCHED;
    lBrush.lbColor = crColor;
    lBrush.lbHatch = nIndex;

    return CreateBrushIndirect(&lBrush);
}

HBRUSH WINAPI
CreatePatternBrush(HBITMAP hBitmap)
{
    LOGBRUSH lBrush;

    LOGSTR((LF_API,"CreatePatternBrush: pattern bitmap %x\n",hBitmap));

    lBrush.lbStyle = BS_PATTERN;
    lBrush.lbColor = 0;
    lBrush.lbHatch = (int)hBitmap;

    return CreateBrushIndirect(&lBrush);
}

HBRUSH WINAPI
CreateDIBPatternBrush(HGLOBAL hPacked, UINT fnColorSpec)
{
    LOGBRUSH lb;

    LOGSTR((LF_GDI,"CreateDIBPatternBrush: hGlobal %x color %x\n",
	hPacked,fnColorSpec));

    lb.lbStyle = BS_DIBPATTERN;
    lb.lbColor = (COLORREF)fnColorSpec;
    lb.lbHatch = (int)hPacked;
    return CreateBrushIndirect(&lb);
}

HBRUSH WINAPI
CreateBrushIndirect(LPLOGBRUSH lpLogBrush)
{
    LOGSTR((LF_OBJECTS,"CreateBrushIndirect\n"));
    return (HBRUSH)GdiCreateBrush(lpLogBrush);
}

HPEN WINAPI
CreatePen(int nPenStyle, int nWidth, COLORREF crColor)
{
    LOGPEN lPenInfo;

    APISTR((LF_API,"CreatePen: style %x, width %d, color %x\n",
		nPenStyle,nWidth,crColor));

    lPenInfo.lopnStyle = nPenStyle;
    lPenInfo.lopnWidth.x = nWidth;
    lPenInfo.lopnWidth.y = nWidth;
    lPenInfo.lopnColor = crColor;

    return CreatePenIndirect(&lPenInfo);
}

HPEN WINAPI
CreatePenIndirect(LPLOGPEN lpLogPen)
{
    APISTR((LF_API,"CreatePenIndirect\n"));
    return (HPEN)GdiCreatePen(lpLogPen);
}

int WINAPI 
AddFontResource(LPCSTR lpcstr)
{
    APISTR((LF_API,"AddFontResource: STUB %s\n",lpcstr));
    return 1;
}

BOOL WINAPI
RemoveFontResource(LPCSTR lpcstr)
{
    LOGSTR((LF_OBJECTS,"RemoveFontResource: STUB %x\n",lpcstr));
    return TRUE;
}

HFONT WINAPI
CreateFont(int nHeight, int nWidth, int nEsc, int nOrient,
	   int nWeight, BYTE cItalic, BYTE cUnder, BYTE cStrike,
	   BYTE cCharSet, BYTE cOutPrec, BYTE cClipPrec, BYTE cQuality,
	   BYTE cPitchFamily, LPCSTR FaceName)
{
    LOGFONT LogFont;

    APISTR((LF_API,"CreateFont: %s, h/w %x/%x, etc.\n",
		FaceName?FaceName:"NULL",nHeight,nWidth));

    memset((LPVOID)&LogFont,'\0',sizeof(LOGFONT));
    LogFont.lfHeight        = nHeight;
    LogFont.lfWidth         = nWidth;
    LogFont.lfEscapement    = nEsc;
    LogFont.lfOrientation   = nOrient;
    LogFont.lfWeight        = nWeight;
    LogFont.lfItalic        = cItalic;
    LogFont.lfUnderline     = cUnder;
    LogFont.lfStrikeOut     = cStrike;
    LogFont.lfCharSet	    = cCharSet;
    LogFont.lfOutPrecision  = cOutPrec;
    LogFont.lfClipPrecision = cClipPrec;
    LogFont.lfQuality       = cQuality;
    LogFont.lfPitchAndFamily = cPitchFamily;
    if (FaceName && FaceName[0])
	strncpy(LogFont.lfFaceName,FaceName,
			min(strlen(FaceName),LF_FACESIZE-1));
    else
	strcpy(LogFont.lfFaceName,"Helv");

    return CreateFontIndirect(&LogFont);
}


HFONT WINAPI
CreateFontIndirect(const LOGFONT FAR *lpLogFont)
{
    APISTR((LF_API,"CreateFontIndirect\n"));

    return (HFONT)GdiCreateFont((LPLOGFONT)lpLogFont);
}

int WINAPI
EnumFonts(HDC hDC, LPCSTR lpcstr, OLDFONTENUMPROC fenumproc, LPARAM lParam)
{
    HDC32 hDC32;
    LSDS_PARAMS argptr;
    int nRet;

    APISTR((LF_API,"EnumFonts: hDC %x %s\n",hDC,lpcstr?lpcstr:"NULL"));

    ASSERT_HDC(hDC32,hDC,0);

    argptr.lsde_validate.dwInvalidMask = 0;

    argptr.lsde.enumfonts.hDC32 = hDC32;
    argptr.lsde.enumfonts.lpszFamily = (LPSTR)lpcstr;
    argptr.lsde.enumfonts.fntenmprc = (FONTENUMPROC)fenumproc;
    argptr.lsde.enumfonts.lParam = (LPARAM)lParam;
    nRet = (int)DC_OUTPUT(LSD_ENUMFONTS,hDC32,0L,&argptr);

    RELEASEDCINFO(hDC32);

    return nRet;
}

int     WINAPI 
EnumFontFamilies(HDC hDC, LPCSTR lpcstr, FONTENUMPROC fenumproc, LPARAM lParam)
{
    HDC32 hDC32;
    LSDS_PARAMS argptr;
    int nRet;

    APISTR((LF_API,"EnumFontFamilies: hDC %x %s\n",hDC,lpcstr?lpcstr:"NULL"));

    ASSERT_HDC(hDC32,hDC,0);

    argptr.lsde_validate.dwInvalidMask = 0;

    argptr.lsde.enumfonts.hDC32 = hDC32;
    argptr.lsde.enumfonts.lpszFamily = (LPSTR)lpcstr;
    argptr.lsde.enumfonts.fntenmprc = (FONTENUMPROC)fenumproc;
    argptr.lsde.enumfonts.lParam = (LPARAM)lParam;
    nRet = (int)DC_OUTPUT(LSD_ENUMFONTS,hDC32,1L,&argptr);

    RELEASEDCINFO(hDC32);

    return nRet;
}

BOOL WINAPI 
IsGDIObject(HGDIOBJ hgdi)
{
    BOOL bRet;
    bRet = (CHECKGDIINFO(hgdi))?TRUE:FALSE;
    RELEASEGDIINFO(hgdi);
    return bRet;
}

int WINAPI
GetObject(HGDIOBJ hObject, int nObjectSize, LPVOID lpObject)
{
    WORD        	objType;
    LPOBJHEAD   	lpObjInfo;
    BITMAP		Bitmap;
    LPLOGBRUSH		lpLogBrush;
    LPLOGPEN		lpLogPen;
    LPEXTLOGPEN		lpExtLogPen;
    LPLOGFONT   	lpf;
    LPIMAGEINFO   	lpimage;
    LPPALETTE		lpPalette;

    APISTR((LF_API,"GetObject: hObject %x nObjectSize %d lpObject %p\n",
	hObject, nObjectSize, lpObject));

    if (!(lpObjInfo = GETGDIINFO(hObject)))
    {
	ERRSTR((LF_ERR, "GetObject: ERROR - GETGDIINFO failed\n"));
	SetLastErrorEx(1, 0);
	return 0;
    }
	
    objType = GET_OBJECT_TYPE(lpObjInfo);

    switch (objType)
    {
	case OT_BRUSH:
		if (!lpObject)
		{
			nObjectSize = sizeof(LOGBRUSH);
			LOGSTR((LF_LOG, "GetObject: sizeof(LOGBRUSH) = %d\n",
				nObjectSize));
			break;
		}
		if (nObjectSize < sizeof(LOGBRUSH))
		{
			ERRSTR((LF_ERR, "GetObject: sizeof(LOGBRUSH) > %d\n",
				nObjectSize));
			nObjectSize = 0;
			break;
		}
		lpLogBrush = (LPLOGBRUSH)lpObject;
		*lpLogBrush = ((LPBRUSHINFO)lpObjInfo)->lpBrush; 
		break;

	case OT_PEN:
		if (!lpObject)
		{
			nObjectSize = sizeof(LOGPEN);
			LOGSTR((LF_LOG, "GetObject: sizeof(LOGPEN) = %d\n",
				nObjectSize));
			break;
		}
		if (nObjectSize < sizeof(LOGPEN))
		{
			ERRSTR((LF_ERR, "GetObject: sizeof(LOGPEN) > %d\n",
				nObjectSize));
			nObjectSize = 0;
			break;
		}
		if (((LPPENINFO)lpObjInfo)->lpExtPen == NULL)
		{
			/* LOGPEN */
			lpLogPen = (LPLOGPEN)lpObject;
			*lpLogPen = ((LPPENINFO)lpObjInfo)->lpPen;
		}
		else
		{
			/* EXTLOGPEN */
			lpExtLogPen = (LPEXTLOGPEN)lpObject;
			*lpExtLogPen = *(((LPPENINFO)lpObjInfo)->lpExtPen);
		}
		break;

	case OT_FONT:
		if (!lpObject)
		{
			nObjectSize = sizeof(LOGFONT);
			LOGSTR((LF_LOG, "GetObject: sizeof(LOGFONT) = %d\n",
				nObjectSize));
			break;
		}
		if (nObjectSize < sizeof(LOGFONT))
		{
			ERRSTR((LF_ERR, "GetObject: sizeof(LOGFONT) > %d\n",
				nObjectSize));
			nObjectSize = 0;
			break;
		}
                lpf = (LPLOGFONT) lpObject;
                *lpf = ((LPFONTINFO)lpObjInfo)->LogFont;
		lpf->lfCharSet = ANSI_CHARSET;
		lpf->lfPitchAndFamily = VARIABLE_PITCH|FF_SWISS;
                break;

	case OT_BITMAP:
		lpimage = (LPIMAGEINFO) lpObjInfo;

#ifdef	DEBUG
		memset((LPSTR)&Bitmap,'\0',sizeof(BITMAP));
#endif

		Bitmap.bmType       = 0;
		Bitmap.bmWidth      = lpimage->ImageWidth;
		Bitmap.bmHeight     = lpimage->ImageHeight;
		Bitmap.bmPlanes     = lpimage->ImagePlanes;
		Bitmap.bmBitsPixel  = lpimage->ImageDepth;
#ifdef LATER
		if ( Bitmap.bmBitsPixel == 4 )
			Bitmap.bmBitsPixel = 8;
#endif
		Bitmap.bmWidthBytes = lpimage->WidthBytes; 
		Bitmap.bmBits       = 0;

		memcpy(lpObject,(LPSTR)&Bitmap,min(nObjectSize,sizeof(BITMAP)));
		LOGSTR((LF_LOG, "BITMAP: w/h=0x%x/0x%x p/c=0x%x/0x%x\n",
			Bitmap.bmWidth,Bitmap.bmHeight,
			Bitmap.bmPlanes,Bitmap.bmBitsPixel));

		/* (WIN32) DIBSECTION */
		if ((lpimage->lpdsBmi != NULL)
		 && (nObjectSize >= sizeof(DIBSECTION)))
		{
			/* Copy everything to DIBSECTION except initial
			 * BITMAP structure, which was already copied by
			 * the above code.
			 */
			((DIBSECTION FAR *)lpObject)->dsBm.bmBits
				= lpimage->ds.dsBm.bmBits;
			((DIBSECTION FAR *)lpObject)->dsBmih
				= lpimage->ds.dsBmih;
			((DIBSECTION FAR *)lpObject)->dsBitfields[0]
				= lpimage->ds.dsBitfields[0];
			((DIBSECTION FAR *)lpObject)->dsBitfields[1]
				= lpimage->ds.dsBitfields[1];
			((DIBSECTION FAR *)lpObject)->dsBitfields[2]
				= lpimage->ds.dsBitfields[2];
			((DIBSECTION FAR *)lpObject)->dshSection
				= lpimage->ds.dshSection;
			((DIBSECTION FAR *)lpObject)->dsOffset
				= lpimage->ds.dsOffset;
		}

		break;

	case OT_PALETTE:
		if (!lpObject)
		{
			nObjectSize = sizeof(UINT);
			LOGSTR((LF_LOG, "GetObject: sizeof(palette) = %d\n",
				nObjectSize));
			break;
		}
		if (nObjectSize < sizeof(UINT))
		{
			ERRSTR((LF_ERR, "GetObject: sizeof(palette) > %d\n",
				nObjectSize));
			nObjectSize = 0;
			break;
		}
		lpPalette = (LPPALETTE) lpObjInfo;
		*((UINT *) lpObject) = lpPalette->lpLogPalette->palNumEntries;
		break;

	default:
		ERRSTR((LF_ERR, "GetObject: ERROR - unknown type %x\n",
			objType));
		SetLastErrorEx(1, 0);
		nObjectSize = 0;
		break;
    }

    RELEASEGDIINFO(lpObjInfo);

    return nObjectSize;

}

BOOL WINAPI
UnrealizeObject(HGDIOBJ hGDIObj)
{
    LPOBJHEAD   lpObjInfo;
    WORD        wObjType;
    BOOL bRet;

    APISTR((LF_API,"UnrealizeObject: hObj %x\n",hGDIObj));

    if (!(lpObjInfo = GETGDIINFO(hGDIObj))) {
	ERRSTR((LF_ERR,"****ERROR**** bad hObject %x\n",hGDIObj));
       	return FALSE;
    }
	
    wObjType= GET_OBJECT_TYPE(lpObjInfo);

    if (wObjType == OT_BRUSH || wObjType == OT_PALETTE) {
	/* say the object is not realized */
	((LPGDIOBJ)lpObjInfo)->fIsRealized = FALSE;
	bRet = TRUE;
    }
    else
	bRet = FALSE;

    RELEASEGDIINFO(hGDIObj);

    return bRet;
}

BOOL WINAPI
DeleteObject(HGDIOBJ hObject)
{
    return TWIN_DeleteObject(hObject, TRUE);
}

BOOL
TWIN_DeleteObject(HGDIOBJ hObject, BOOL fNotifyMetafile)
{
    LPOBJHEAD   lpObjInfo;
    WORD	wObjType;
    BOOL	bRet = FALSE;

    APISTR((LF_API,"DeleteObject: hObject %x\n",hObject));

    if (hObject == 0)
	return FALSE;

    if (!(lpObjInfo = (LPOBJHEAD)GETGDIINFO(hObject))) {
	ERRSTR((LF_ERR,"DeleteObject: bad handle %x\n",hObject));
	return FALSE;
    }

    wObjType = GET_OBJECT_TYPE(lpObjInfo);

    switch (wObjType) {
	case OT_FONT:
	    if (lpObjInfo->wRefCount == 0) {
		LOGSTR((LF_LOG,"DeleteObject: FONT\n"));
		if (fNotifyMetafile)
		    TWIN_MetaNotify(lpObjInfo);
		bRet = GdiDeleteFont((HFONT)hObject);
	    }
	    break;

	case OT_REGION:
	    if (lpObjInfo->wRefCount == 0) {
		LOGSTR((LF_LOG,"DeleteObject: REGION\n"));
		bRet = GdiDeleteRgn((HRGN)hObject);
	    }
	    break;

	case OT_PEN:
	    if (lpObjInfo->wRefCount == 0) {
		LOGSTR((LF_LOG,"DeleteObject: PEN\n"));
		if (fNotifyMetafile)
		    TWIN_MetaNotify(lpObjInfo);
		bRet = GdiDeletePen((HPEN)hObject);
	    }
	    break;

	case OT_BRUSH:
	    if (lpObjInfo->wRefCount == 0) {
		LOGSTR((LF_LOG,"DeleteObject: BRUSH\n"));
		if (fNotifyMetafile)
		    TWIN_MetaNotify(lpObjInfo);
		bRet = GdiDeleteBrush((HBRUSH)hObject);
	    }
	    break;

	case OT_PALETTE:
	    if (lpObjInfo->wRefCount == 0) {
		LOGSTR((LF_LOG,"DeleteObject: PALETTE\n"));
		bRet = GdiDeletePalette((HPALETTE)hObject);
	    }
	    break;

	case OT_BITMAP:
	    RELEASEGDIINFO(lpObjInfo);
	    if (lpObjInfo->wRefCount == 0) {
		LOGSTR((LF_LOG,"DeleteObject: BITMAP\n"));
		bRet = GdiDeleteBitmap((HBITMAP)hObject);
	    }
	    else {
		if (((LPGDIOBJ)lpObjInfo)->fIsRealized)
		    ((LPGDIOBJ)lpObjInfo)->fIsRealized = FALSE;
		bRet = TRUE;
	    }
	    if (bRet)
	        FREEGDI(hObject);
	    return bRet;

	case OT_DC:
	    RELEASEGDIINFO(lpObjInfo);
	    if (lpObjInfo->wRefCount == 0) {
		LOGSTR((LF_LOG,"DeleteObject: DC\n"));
		return DeleteDC((HDC)hObject);
	    }
	    return FALSE;

	default:
	    ERRSTR((LF_ERR,
		"****ERROR**** unknown object type %x\n", wObjType));
	    break;
    }

    RELEASEGDIINFO(lpObjInfo);

    if (bRet)
	FREEGDI(hObject);

    return bRet;
}

/********************************************************************/
/*		Internal routines				    */
/********************************************************************/

static HPEN
GdiCreatePen(LPLOGPEN lpPen)
{
    LPPENINFO lpPenInfo;
    HPEN hPen;

    if (!(lpPenInfo = CREATEHPEN(hPen))) {
	ERRSTR((LF_ERR,"****ERROR**** CREATEHPEN failed\n"));
	return (HPEN)0;
    }
    lpPenInfo->lpPen.lopnStyle   = lpPen->lopnStyle;
    lpPenInfo->lpPen.lopnWidth.x = lpPen->lopnWidth.x;
    lpPenInfo->lpPen.lopnWidth.y = lpPen->lopnWidth.y;
    lpPenInfo->lpPen.lopnColor   = lpPen->lopnColor;
    lpPenInfo->lpExtPen = NULL;

    RELEASEPENINFO(lpPenInfo);

    return hPen;
}

static HPEN
GdiExtCreatePen(LPEXTLOGPEN lpExtPen, DWORD dwNumEntries, LPDWORD lpStyleEntry)
{
	LPPENINFO lpPenInfo;
	HPEN hPen;
	DWORD i;

	if ((lpPenInfo = CREATEHPEN(hPen)) == NULL)
	{
		SetLastErrorEx(1, 0);
		return ((HPEN) 0);
	}
	lpPenInfo->lpPen.lopnStyle = 0;
	lpPenInfo->lpPen.lopnWidth.x = 0;
	lpPenInfo->lpPen.lopnWidth.y = 0;
	lpPenInfo->lpPen.lopnColor = 0;
	lpPenInfo->lpExtPen = (LPEXTLOGPEN) WinMalloc(sizeof(EXTLOGPEN)
		+ dwNumEntries * sizeof(DWORD));
	if (lpPenInfo->lpExtPen == NULL)
	{
		SetLastErrorEx(1, 0);
		DeleteObject(hPen);
		RELEASEPENINFO(lpPenInfo);
		return ((HPEN) 0);
	}
	lpPenInfo->lpExtPen->elpPenStyle   = lpExtPen->elpPenStyle;
	lpPenInfo->lpExtPen->elpWidth      = lpExtPen->elpWidth;
	lpPenInfo->lpExtPen->elpBrushStyle = lpExtPen->elpBrushStyle;
	lpPenInfo->lpExtPen->elpColor      = lpExtPen->elpColor;
	lpPenInfo->lpExtPen->elpHatch      = lpExtPen->elpHatch;
	lpPenInfo->lpExtPen->elpNumEntries = dwNumEntries;
	for (i = 0; i < dwNumEntries; i++)
		lpPenInfo->lpExtPen->elpStyleEntry[i] = lpStyleEntry[i];

	RELEASEPENINFO(lpPenInfo);

	return (hPen);

}

static BOOL
GdiDeletePen(HPEN hPen)
{
	LPPENINFO lpPenInfo;

	if ((lpPenInfo = GETPENINFO(hPen)) == NULL)
	{
		SetLastErrorEx(1, 0);
		return (FALSE);
	}
	if (lpPenInfo->lpExtPen)
		WinFree((LPSTR) lpPenInfo->lpExtPen);

	RELEASEPENINFO(lpPenInfo);

	return (TRUE);
}

static BOOL
GdiDeletePalette(HPALETTE hPalette)
{
	LPPALETTE lpPalette;

	APISTR((LF_API, "GdiDeletePalette: hPalette %x\n", hPalette));

	ASSERT_PALETTE(lpPalette, hPalette, FALSE);

	if (lpPalette->lpLogPalette)
	{
		WinFree(lpPalette->lpLogPalette);
	}

	UNLOCK_PALETTE(hPalette);

	return (TRUE);

#if 0
    LPPALETTEINFO lpPalInfo;

    if (!(lpPalInfo = GETPALETTEINFO(hPalette))) {
	ERRSTR((LF_ERR,"****ERROR**** bad palette %x\n",hPalette));
	return FALSE;
    }
    if (lpPalInfo->lpPalEntries)
	WinFree((LPSTR)lpPalInfo->lpPalEntries);

    RELEASEPALETTEINFO(lpPalInfo);

    return TRUE;
#endif
}

#define HATCH_BASE 0x4000 /* needs to be defined in rc file, too */

HBITMAP
LoadHatchBitmap(int nHatchIndex)
{
    static HBITMAP HatchBitmaps[6];

    if (HatchBitmaps[nHatchIndex] == 0)
	HatchBitmaps[nHatchIndex] =
			LoadBitmap(0,(LPSTR)(HATCH_BASE+nHatchIndex));

    return HatchBitmaps[nHatchIndex];
}

/* (WIN32) GDI Pen ********************************************************* */

HPEN	WINAPI
ExtCreatePen(DWORD dwPenStyle, DWORD dwPenWidth,
	LPLOGBRUSH lpLogBrush,
	DWORD dwNumEntries,
	LPDWORD lpStyleEntry)
{
	BOOL bError;
	EXTLOGPEN elp;

	/* error checking */
	bError = FALSE;
	switch (dwPenStyle & PS_TYPE_MASK)
	{
	case PS_GEOMETRIC:
		if (lpLogBrush == NULL)
			bError = TRUE;
		break;
	case PS_COSMETIC:
		if (((dwPenStyle & PS_STYLE_MASK) == PS_INSIDEFRAME)
		 || ((dwPenStyle & PS_ENDCAP_MASK) != 0)
		 || ((dwPenStyle & PS_JOIN_MASK) != 0)
		 || (dwPenWidth != 1)
		 || (lpLogBrush == NULL)
		 || (lpLogBrush->lbStyle != BS_SOLID))
			bError = TRUE;
		break;
	default:
		bError = TRUE;
		break;
	}
	if (((dwPenStyle & PS_STYLE_MASK) != PS_USERSTYLE)
	 && ((dwNumEntries != 0) || (lpStyleEntry != NULL)))
		bError = TRUE;
	if (bError)
	{
		SetLastErrorEx(1, 0);
		return ((HPEN) 0);
	}

	/* create extended logical pen */
	elp.elpPenStyle = dwPenStyle;
	elp.elpWidth = dwPenWidth;
	switch (elp.elpBrushStyle = lpLogBrush->lbStyle)
	{
	case BS_SOLID:
		elp.elpColor = lpLogBrush->lbColor;
		elp.elpHatch = 0;		/* ignored */
		break;
	case BS_HATCHED:
		elp.elpColor = lpLogBrush->lbColor;
		elp.elpHatch = lpLogBrush->lbHatch;
		break;
	case BS_HOLLOW:
		elp.elpColor = 0;		/* ignored */
		elp.elpHatch = 0;		/* ignored */
		break;
	case BS_PATTERN:
		elp.elpColor = 0;		/* ignored */
		elp.elpHatch = lpLogBrush->lbHatch;
		break;
	case BS_DIBPATTERN:
		elp.elpColor = lpLogBrush->lbColor;
		elp.elpHatch = lpLogBrush->lbHatch;
		break;
	case BS_DIBPATTERNPT:
		elp.elpColor = lpLogBrush->lbColor;
		elp.elpHatch = lpLogBrush->lbHatch;
		break;
	default:
		SetLastErrorEx(1, 0);
		return ((HPEN) 0);
	}
	return GdiExtCreatePen(&elp, dwNumEntries, lpStyleEntry);

}


void
TWIN_DeleteStockObjects()
{
	int i;
	LPOBJHEAD     lpObjHead;

	logstr(LF_OBJECTS,"DeleteStockObjects\n");
	for(i=0;i<20;i++) {
		if(StockObjects[i]) {
			logstr(LF_OBJECTS,"DeleteStockObjects %d %x\n",i,
				StockObjects[i]);
			lpObjHead = GETGDIINFO(StockObjects[i]);
			lpObjHead->wRefCount = 0;
			DeleteObject(StockObjects[i]);
		}
	}
}
