You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1774 lines
52 KiB
1774 lines
52 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: miscgdi.cxx
|
|
*
|
|
* Misc. GDI routines
|
|
*
|
|
* Created: 13-Aug-1990 by undead
|
|
*
|
|
* Copyright (c) 1989-1999 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
//
|
|
// GCAPS2_SYNCFLUSH and GCAPS2_SYNCTIMER globals
|
|
//
|
|
|
|
LONG gcSynchronizeFlush = -1;
|
|
LONG gcSynchronizeTimer = -1;
|
|
UINT_PTR gidSynchronizeTimer;
|
|
|
|
//
|
|
// GCAPS2_SYNCTIMER timer interval, in milliseconds
|
|
//
|
|
|
|
#define SYNCTIMER_FREQUENCY 50
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreSaveScreenBits (hdev,iMode,iIdent,prcl)
|
|
*
|
|
* Passes the call to the device driver, or returns doing nothing. This
|
|
* call is pretty fast, no locks are done.
|
|
*
|
|
* Fri 11-Sep-1992 -by- Patrick Haluptzok [patrickh]
|
|
* Add cursor exclusion.
|
|
*
|
|
* Thu 27-Aug-1992 16:40:42 -by- Charles Whitmer [chuckwh]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
ULONG_PTR GreSaveScreenBits(HDEV hdev,ULONG iMode,ULONG_PTR iIdent,RECTL *prcl)
|
|
{
|
|
ULONG_PTR ulReturn = 0;
|
|
RECTL rcl = {0,0,0,0};
|
|
|
|
PDEVOBJ po(hdev);
|
|
|
|
GreAcquireSemaphoreEx(po.hsemDevLock(), SEMORDER_DEVLOCK, NULL);
|
|
GreEnterMonitoredSection(po.ppdev, WD_DEVLOCK);
|
|
|
|
if (!po.bDisabled())
|
|
{
|
|
PFN_DrvSaveScreenBits pfn = PPFNDRV(po,SaveScreenBits);
|
|
|
|
if (pfn != (PFN_DrvSaveScreenBits) NULL)
|
|
{
|
|
DEVEXCLUDEOBJ dxo;
|
|
|
|
if (iMode == SS_FREE)
|
|
{
|
|
// Make if a very small rectangle.
|
|
|
|
prcl = &rcl;
|
|
}
|
|
|
|
ASSERTGDI(po.bDisplayPDEV(), "ERROR");
|
|
|
|
ulReturn = (*pfn)(po.pSurface()->pSurfobj(),iMode,iIdent,prcl);
|
|
}
|
|
}
|
|
#if DBG
|
|
else
|
|
{
|
|
if (iMode == SS_FREE)
|
|
WARNING("GreSaveScreenBits called to free memory in full screen - memory lost\n");
|
|
}
|
|
#endif
|
|
|
|
GreExitMonitoredSection(po.ppdev, WD_DEVLOCK);
|
|
GreReleaseSemaphoreEx(po.hsemDevLock());
|
|
|
|
return(ulReturn);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreValidateSurfaceHandle
|
|
*
|
|
* This allows USER to validate handles passed to it by the client side.
|
|
*
|
|
* Returns: TRUE if handle is valid and of the correct type,
|
|
* FALSE otherwise.
|
|
*
|
|
* History:
|
|
* 06-Sep-1991 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL GreValidateServerHandle(HANDLE hobj, ULONG ulType)
|
|
{
|
|
return(HmgValidHandle((HOBJ)hobj, (OBJTYPE) ulType));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreSetBrushOrg
|
|
*
|
|
* Set the application defined brush origin into the DC
|
|
*
|
|
* Returns: Old brush origin
|
|
*
|
|
* History:
|
|
* 30-Oct-1990 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL GreSetBrushOrg(
|
|
HDC hdc,
|
|
int x,
|
|
int y,
|
|
LPPOINT ptl_)
|
|
{
|
|
DCOBJ dco(hdc);
|
|
PPOINTL ptl = (PPOINTL)ptl_;
|
|
|
|
if (dco.bValid())
|
|
{
|
|
if (ptl != NULL)
|
|
*ptl = dco.pdc->ptlBrushOrigin();
|
|
|
|
//
|
|
// update DCATTR brush org
|
|
//
|
|
|
|
dco.pdc->pDCAttr->ptlBrushOrigin.x = x;
|
|
dco.pdc->pDCAttr->ptlBrushOrigin.y = y;
|
|
|
|
//
|
|
// update km brush prg
|
|
//
|
|
|
|
dco.pdc->ptlBrushOrigin((LONG)x,(LONG)y);
|
|
return(TRUE);
|
|
}
|
|
else
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreGetBrushOrg
|
|
*
|
|
* Returns: Old application brush origin
|
|
*
|
|
* History:
|
|
* 30-Oct-1990 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL GreGetBrushOrg(HDC hdc,PPOINT ptl_)
|
|
{
|
|
DCOBJ dco(hdc);
|
|
PPOINTL ptl = (PPOINTL)ptl_;
|
|
|
|
if (dco.bValid())
|
|
{
|
|
*ptl = dco.pdc->ptlBrushOrigin();
|
|
return(TRUE);
|
|
}
|
|
else
|
|
return(FALSE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vGetDeviceCaps()
|
|
*
|
|
* Common device capabilities routine.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vGetDeviceCaps(
|
|
PDEVOBJ& po,
|
|
PDEVCAPS pDevCaps
|
|
)
|
|
{
|
|
GDIINFO* pGdiInfo;
|
|
|
|
pGdiInfo = po.GdiInfoNotDynamic(); // Use of this local removes pointer
|
|
// dereferences
|
|
|
|
pDevCaps->ulVersion = pGdiInfo->ulVersion;
|
|
pDevCaps->ulTechnology = pGdiInfo->ulTechnology;
|
|
|
|
// Note that ul*Size fields are now in micrometers
|
|
|
|
pDevCaps->ulHorzSizeM = (pGdiInfo->ulHorzSize+500)/1000;
|
|
pDevCaps->ulVertSizeM = (pGdiInfo->ulVertSize+500)/1000;
|
|
pDevCaps->ulHorzSize = pGdiInfo->ulHorzSize;
|
|
pDevCaps->ulVertSize = pGdiInfo->ulVertSize;
|
|
pDevCaps->ulHorzRes = pGdiInfo->ulHorzRes;
|
|
pDevCaps->ulVertRes = pGdiInfo->ulVertRes;
|
|
pDevCaps->ulBitsPixel = pGdiInfo->cBitsPixel;
|
|
if (pDevCaps->ulBitsPixel == 15)
|
|
pDevCaps->ulBitsPixel = 16; // Some apps, such as PaintBrush or
|
|
// NetScape, break if we return 15bpp
|
|
|
|
pDevCaps->ulPlanes = pGdiInfo->cPlanes;
|
|
pDevCaps->ulNumPens = (pGdiInfo->ulNumColors == (ULONG)-1) ?
|
|
(ULONG)-1 : 5 * pGdiInfo->ulNumColors;
|
|
pDevCaps->ulNumFonts = po.cFonts();
|
|
pDevCaps->ulNumColors = pGdiInfo->ulNumColors;
|
|
pDevCaps->ulRasterCaps = pGdiInfo->flRaster;
|
|
pDevCaps->ulShadeBlendCaps = pGdiInfo->flShadeBlend;
|
|
pDevCaps->ulAspectX = pGdiInfo->ulAspectX;
|
|
pDevCaps->ulAspectY = pGdiInfo->ulAspectY;
|
|
pDevCaps->ulAspectXY = pGdiInfo->ulAspectXY;
|
|
pDevCaps->ulLogPixelsX = pGdiInfo->ulLogPixelsX;
|
|
pDevCaps->ulLogPixelsY = pGdiInfo->ulLogPixelsY;
|
|
pDevCaps->ulSizePalette = pGdiInfo->ulNumPalReg;
|
|
pDevCaps->ulColorRes = pGdiInfo->ulDACRed + pGdiInfo->ulDACGreen + pGdiInfo->ulDACBlue;
|
|
pDevCaps->ulPhysicalWidth = pGdiInfo->szlPhysSize.cx;
|
|
pDevCaps->ulPhysicalHeight = pGdiInfo->szlPhysSize.cy;
|
|
pDevCaps->ulPhysicalOffsetX = pGdiInfo->ptlPhysOffset.x;
|
|
pDevCaps->ulPhysicalOffsetY = pGdiInfo->ptlPhysOffset.y;
|
|
|
|
pDevCaps->ulTextCaps = pGdiInfo->flTextCaps;
|
|
pDevCaps->ulTextCaps |= (TC_OP_CHARACTER | TC_OP_STROKE | TC_CP_STROKE |
|
|
TC_UA_ABLE | TC_SO_ABLE);
|
|
|
|
if (pGdiInfo->ulTechnology != DT_PLOTTER)
|
|
pDevCaps->ulTextCaps |= TC_VA_ABLE;
|
|
|
|
pDevCaps->ulVRefresh = pGdiInfo->ulVRefresh;
|
|
pDevCaps->ulDesktopHorzRes = pGdiInfo->ulHorzRes;
|
|
pDevCaps->ulDesktopVertRes = pGdiInfo->ulVertRes;
|
|
pDevCaps->ulBltAlignment = pGdiInfo->ulBltAlignment;
|
|
|
|
pDevCaps->ulColorManagementCaps
|
|
= GetColorManagementCaps(po);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* NtGdiGetDeviceCapsAll()
|
|
*
|
|
* Get all the adjustable device caps for the dc. Allows us to cache this
|
|
* information on the client side.
|
|
*
|
|
* History:
|
|
* 09-Jan-1996 -by- Lingyun Wang [lingyunw]
|
|
* Made it based on GreGetDeviceCapsAll from the old client\server code.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
APIENTRY
|
|
NtGdiGetDeviceCapsAll(
|
|
HDC hdc,
|
|
PDEVCAPS pDevCaps
|
|
)
|
|
{
|
|
BOOL bRet = TRUE;
|
|
DEVCAPS devCapsTmp;
|
|
|
|
// Lock the destination and its transform.
|
|
|
|
DCOBJ dco(hdc);
|
|
|
|
// return FALSE if it is a invalid DC
|
|
|
|
if (!dco.bValid())
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
return(FALSE);
|
|
}
|
|
|
|
// Lock down the pdev
|
|
|
|
PDEVOBJ po(dco.hdev());
|
|
|
|
ASSERTGDI(po.bValid(), "Invalid PDEV");
|
|
|
|
__try
|
|
{
|
|
ProbeForWrite(pDevCaps, sizeof(DEVCAPS), sizeof(BYTE));
|
|
|
|
vGetDeviceCaps(po, pDevCaps);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING ("try-except failed IN NtGdiGetDeviceCapsAll\n");
|
|
|
|
// SetLastError(GetExceptionCode());
|
|
|
|
bRet = FALSE;
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreUpdateSharedDevCaps()
|
|
*
|
|
* Update the device caps in the shared memory
|
|
*
|
|
* History:
|
|
* 09-Jan-1996 -by- Lingyun Wang [lingyunw]
|
|
* Made it based on GreGetDeviceCapsAll from the old client\server code.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
GreUpdateSharedDevCaps(
|
|
HDEV hdev
|
|
)
|
|
{
|
|
PDEVOBJ po(hdev);
|
|
ASSERTGDI(po.bValid(), "Invalid HDEV");
|
|
|
|
vGetDeviceCaps(po, gpGdiDevCaps);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreGetDeviceCaps
|
|
*
|
|
* Returns: device driver specific information
|
|
*
|
|
* NOTE: This function MUST mirror NtGdiGetDeviceCapsAll and that in
|
|
* client\dcquery.c!
|
|
*
|
|
* History:
|
|
* 01-Mar-1992 -by- Donald Sidoroff [donalds]
|
|
* Rewritten to corrected GDIINFO structure.
|
|
*
|
|
* 30-Oct-1990 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int GreGetDeviceCaps(HDC hdc, int lIndex)
|
|
{
|
|
// Init return value
|
|
|
|
int iRet = 0;
|
|
|
|
// Lock the destination and its transform.
|
|
|
|
DCOBJ dco(hdc);
|
|
if (dco.bValid())
|
|
{
|
|
// Lock down the pdev
|
|
|
|
PDEVOBJ po(dco.hdev());
|
|
ASSERTGDI(po.bValid(), "Invalid PDEV");
|
|
|
|
// Note that dynamic mode changes may cause the GDIINFO data to change
|
|
// at any time (but not the actual 'pGdiInfo' pointer):
|
|
|
|
GDIINFO* pGdiInfo = po.GdiInfoNotDynamic();
|
|
|
|
switch (lIndex)
|
|
{
|
|
case DRIVERVERSION: // Version = 0100h for now
|
|
iRet = (pGdiInfo->ulVersion);
|
|
break;
|
|
|
|
case TECHNOLOGY: // Device classification
|
|
iRet = (pGdiInfo->ulTechnology);
|
|
break;
|
|
|
|
case HORZSIZE: // Horizontal size in millimeters
|
|
iRet = (pGdiInfo->ulHorzSize+500)/1000;
|
|
break;
|
|
|
|
case VERTSIZE: // Vertical size in millimeters
|
|
iRet = (pGdiInfo->ulVertSize+500)/1000;
|
|
break;
|
|
|
|
case HORZRES: // Horizontal width in pixels
|
|
iRet = (pGdiInfo->ulHorzRes);
|
|
break;
|
|
|
|
case VERTRES: // Vertical height in pixels
|
|
iRet = (pGdiInfo->ulVertRes);
|
|
break;
|
|
|
|
case BITSPIXEL: // Number of bits per pixel
|
|
iRet = (pGdiInfo->cBitsPixel);
|
|
if (iRet == 15)
|
|
iRet = 16; // Some apps, such as PaintBrush or
|
|
// NetScape, break if we return 15bpp
|
|
break;
|
|
|
|
case PLANES: // Number of planes
|
|
iRet = (pGdiInfo->cPlanes);
|
|
break;
|
|
|
|
case NUMBRUSHES: // Number of brushes the device has
|
|
iRet = (-1);
|
|
break;
|
|
|
|
case NUMPENS: // Number of pens the device has
|
|
iRet = (pGdiInfo->ulNumColors == (ULONG)-1) ?
|
|
(ULONG)-1 : 5 * pGdiInfo->ulNumColors;
|
|
break;
|
|
|
|
case NUMMARKERS: // Number of markers the device has
|
|
iRet = (0);
|
|
break;
|
|
|
|
case NUMFONTS: // Number of fonts the device has
|
|
iRet = (po.cFonts());
|
|
break;
|
|
|
|
case NUMCOLORS: // Number of colors in color table
|
|
iRet = (pGdiInfo->ulNumColors);
|
|
break;
|
|
|
|
case PDEVICESIZE: // Size required for the device descriptor
|
|
iRet = (0);
|
|
break;
|
|
|
|
case CURVECAPS: // Curves capabilities
|
|
iRet = (CC_CIRCLES |
|
|
CC_PIE |
|
|
CC_CHORD |
|
|
CC_ELLIPSES |
|
|
CC_WIDE |
|
|
CC_STYLED |
|
|
CC_WIDESTYLED |
|
|
CC_INTERIORS |
|
|
CC_ROUNDRECT);
|
|
break;
|
|
|
|
case LINECAPS: // Line capabilities
|
|
iRet = (LC_POLYLINE |
|
|
LC_MARKER |
|
|
LC_POLYMARKER |
|
|
LC_WIDE |
|
|
LC_STYLED |
|
|
LC_WIDESTYLED |
|
|
LC_INTERIORS);
|
|
break;
|
|
|
|
case POLYGONALCAPS: // Polygonal capabilities
|
|
iRet = (PC_POLYGON |
|
|
PC_RECTANGLE |
|
|
PC_WINDPOLYGON |
|
|
PC_TRAPEZOID |
|
|
PC_SCANLINE |
|
|
PC_WIDE |
|
|
PC_STYLED |
|
|
PC_WIDESTYLED |
|
|
PC_INTERIORS);
|
|
break;
|
|
|
|
case TEXTCAPS: // Text capabilities
|
|
{
|
|
|
|
FLONG fl = pGdiInfo->flTextCaps;
|
|
|
|
// Engine will simulate vector fonts on raster devices.
|
|
|
|
if (pGdiInfo->ulTechnology != DT_PLOTTER)
|
|
fl |= TC_VA_ABLE;
|
|
|
|
// Turn underlining, strikeout. Engine will do it for device if needed.
|
|
|
|
fl |= (TC_UA_ABLE | TC_SO_ABLE);
|
|
|
|
// Return flag.
|
|
|
|
iRet = fl;
|
|
break;
|
|
}
|
|
|
|
case CLIPCAPS: // Clipping capabilities
|
|
iRet = (CP_RECTANGLE);
|
|
break;
|
|
|
|
case RASTERCAPS: // Bitblt capabilities
|
|
iRet = (pGdiInfo->flRaster);
|
|
break;
|
|
|
|
case SHADEBLENDCAPS: // Shade and blend capabilities
|
|
iRet = (pGdiInfo->flShadeBlend);
|
|
break;
|
|
|
|
case ASPECTX: // Length of X leg
|
|
iRet = (pGdiInfo->ulAspectX);
|
|
break;
|
|
|
|
case ASPECTY: // Length of Y leg
|
|
iRet = (pGdiInfo->ulAspectY);
|
|
break;
|
|
|
|
case ASPECTXY: // Length of hypotenuse
|
|
iRet = (pGdiInfo->ulAspectXY);
|
|
break;
|
|
|
|
case LOGPIXELSX: // Logical pixels/inch in X
|
|
iRet = (pGdiInfo->ulLogPixelsX);
|
|
break;
|
|
|
|
case LOGPIXELSY: // Logical pixels/inch in Y
|
|
iRet = (pGdiInfo->ulLogPixelsY);
|
|
break;
|
|
|
|
case SIZEPALETTE: // # entries in physical palette
|
|
iRet = (pGdiInfo->ulNumPalReg);
|
|
break;
|
|
|
|
case NUMRESERVED: // # reserved entries in palette
|
|
iRet = (20);
|
|
break;
|
|
|
|
case COLORRES:
|
|
iRet = (pGdiInfo->ulDACRed + pGdiInfo->ulDACGreen + pGdiInfo->ulDACBlue);
|
|
break;
|
|
|
|
case PHYSICALWIDTH: // Physical Width in device units
|
|
iRet = (pGdiInfo->szlPhysSize.cx);
|
|
break;
|
|
|
|
case PHYSICALHEIGHT: // Physical Height in device units
|
|
iRet = (pGdiInfo->szlPhysSize.cy);
|
|
break;
|
|
|
|
case PHYSICALOFFSETX: // Physical Printable Area x margin
|
|
iRet = (pGdiInfo->ptlPhysOffset.x);
|
|
break;
|
|
|
|
case PHYSICALOFFSETY: // Physical Printable Area y margin
|
|
iRet = (pGdiInfo->ptlPhysOffset.y);
|
|
break;
|
|
|
|
case VREFRESH: // Vertical refresh rate of the device
|
|
iRet = (pGdiInfo->ulVRefresh);
|
|
break;
|
|
|
|
//
|
|
// NOTE : temporarily disable this feature for the BETA.
|
|
// We will reenable when the engine does it.
|
|
//
|
|
|
|
case DESKTOPHORZRES: // Width of entire virtual desktop
|
|
iRet = (pGdiInfo->ulHorzRes);
|
|
break;
|
|
|
|
case DESKTOPVERTRES: // Height of entire virtual desktop
|
|
iRet = (pGdiInfo->ulVertRes);
|
|
break;
|
|
|
|
case BLTALIGNMENT: // Preferred blt alignment
|
|
iRet = (pGdiInfo->ulBltAlignment);
|
|
break;
|
|
|
|
case HORZSIZEM: // Horizontal size in millimeters/1000
|
|
iRet = pGdiInfo->ulHorzSize;
|
|
break;
|
|
|
|
case VERTSIZEM: // Vertical size in millimeters/1000
|
|
iRet = pGdiInfo->ulVertSize;
|
|
break;
|
|
|
|
case CAPS1: // InternalCaps
|
|
iRet = (po.ppdev->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) ?
|
|
C1_MIRROR_DEVICE : 0;
|
|
break;
|
|
|
|
case COLORMGMTCAPS: // Color management capabilities
|
|
iRet = GetColorManagementCaps(po);
|
|
|
|
default:
|
|
iRet = 0;
|
|
}
|
|
}
|
|
|
|
return(iRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL GreDeleteObject(HOBJ)
|
|
*
|
|
* History:
|
|
* Fri 13-Sep-1991 -by- Patrick Haluptzok [patrickh]
|
|
* added DC deletion
|
|
*
|
|
* Tue 27-Nov-1990 -by- Patrick Haluptzok [patrickh]
|
|
* added palette deletion, surface deletion, brush deletion.
|
|
*
|
|
* Wed 22-Aug-1990 Greg Veres [w-gregv]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GreDeleteObject (HANDLE hobj)
|
|
{
|
|
int ii;
|
|
|
|
// don't allow deletion of stock objects, just succeed
|
|
|
|
if (HmgStockObj(hobj))
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
switch (HmgObjtype(hobj))
|
|
{
|
|
case RGN_TYPE:
|
|
return(bDeleteRegion((HRGN) hobj));
|
|
case SURF_TYPE:
|
|
return(bDeleteSurface((HSURF)hobj));
|
|
case PAL_TYPE:
|
|
return(bDeletePalette((HPAL) hobj));
|
|
case LFONT_TYPE:
|
|
// see if its in cfont list.
|
|
|
|
for (ii = 0; ii < MAX_PUBLIC_CFONT; ++ii)
|
|
{
|
|
if (gpGdiSharedMemory->acfPublic[ii].hf == hobj)
|
|
{
|
|
// just nuke the hfont as this invalidates the whole entry
|
|
|
|
gpGdiSharedMemory->acfPublic[ii].hf = 0;
|
|
break;
|
|
}
|
|
}
|
|
return(bDeleteFont((HLFONT) hobj, FALSE));
|
|
|
|
case BRUSH_TYPE:
|
|
return(bDeleteBrush((HBRUSH) hobj, FALSE));
|
|
case DC_TYPE:
|
|
return(bDeleteDCInternal((HDC) hobj,TRUE,FALSE));
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* NtGdiDeleteObjectApp()
|
|
*
|
|
* Same as DeleteObject() but doesn't allow public objects to be deleted.
|
|
* This should only be called from server.c coming from the client. User
|
|
* and console should call the DeleteObject().
|
|
*
|
|
* History:
|
|
* 01-Nov-1994 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
APIENTRY
|
|
NtGdiDeleteObjectApp(
|
|
HANDLE hobj
|
|
)
|
|
{
|
|
ULONG objt;
|
|
|
|
// don't allow deletion of stock objects, just succeed
|
|
|
|
if (HmgStockObj(hobj))
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
objt = HmgObjtype(hobj);
|
|
|
|
// check if it is a public object. If it is, check if it is a public deletable
|
|
// surface set by user.
|
|
|
|
if (GreGetObjectOwner((HOBJ)hobj,objt) == OBJECT_OWNER_PUBLIC)
|
|
{
|
|
if (objt == SURF_TYPE)
|
|
{
|
|
WARNING("Trying to delete public surface!");
|
|
}
|
|
|
|
#if 0
|
|
BOOL bMsg = TRUE;
|
|
|
|
if (objt == BRUSH_TYPE)
|
|
{
|
|
BRUSHSELOBJ bo(hbrush);
|
|
|
|
if (bo.bValid() || bo.bIsGlobal())
|
|
bMsg = FALSE;
|
|
}
|
|
|
|
if (bMsg)
|
|
{
|
|
DbgPrint("GDI Warning: app trying to delete public object %lx\n",hobj);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// return FALSE if hobj == NULL
|
|
// otherwise TRUE
|
|
//
|
|
return(hobj != NULL);
|
|
}
|
|
|
|
switch (objt)
|
|
{
|
|
case RGN_TYPE:
|
|
return(bDeleteRegion((HRGN) hobj));
|
|
case SURF_TYPE:
|
|
return(bDeleteSurface((HSURF)hobj));
|
|
case PAL_TYPE:
|
|
return(bDeletePalette((HPAL) hobj));
|
|
case LFONT_TYPE:
|
|
return(bDeleteFont((HLFONT) hobj, FALSE));
|
|
case BRUSH_TYPE:
|
|
return(bDeleteBrush((HBRUSH) hobj, FALSE));
|
|
case DC_TYPE:
|
|
// don't allow deletion of DC's by an app if the undeletable flag is set
|
|
|
|
return(bDeleteDCInternal((HDC) hobj,FALSE,FALSE));
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* cjGetBrushOrPen
|
|
*
|
|
* Gets brush or pen object data.
|
|
*
|
|
* For extended pens, some information such as the style array are kept
|
|
* only on this, the server side. Most of the brush data is also kept
|
|
* on the client side for GetObject.
|
|
*
|
|
* returns: Number of bytes needed if pvDest == NULL, else bytes copied out.
|
|
* For error it returns 0.
|
|
*
|
|
* History:
|
|
* Thu 23-Mar-1992 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
LONG cjGetBrushOrPen(HANDLE hobj, int iCount, LPVOID pvDest)
|
|
{
|
|
LONG lRet = 0;
|
|
|
|
BRUSHSELOBJ bro((HBRUSH) hobj);
|
|
|
|
// NOTE SIZE: Most of this is bunk, since for NT all brush data is kept on the
|
|
// client side, and so some of this code path won't even be
|
|
// executed. [andrewgo]
|
|
//
|
|
// And for DOS, we would return some fields as zero, whereas under
|
|
// NT we would always return what we were given. [andrewgo]
|
|
|
|
if (bro.bValid())
|
|
{
|
|
if (bro.bIsOldStylePen())
|
|
{
|
|
// Old style pen...
|
|
|
|
bSyncBrushObj(bro.pbrush());
|
|
|
|
if (pvDest == (LPVOID) NULL)
|
|
{
|
|
lRet = sizeof(LOGPEN);
|
|
}
|
|
else if (iCount >= sizeof(LOGPEN))
|
|
{
|
|
if ((iCount == (int) sizeof(EXTLOGPEN)) &&
|
|
((UINT) bro.flStylePen() == PS_NULL))
|
|
{
|
|
//moved the NULL extended pen handling from client
|
|
//side to server side
|
|
|
|
PEXTLOGPEN pelp = (PEXTLOGPEN) pvDest;
|
|
|
|
pelp->elpPenStyle = PS_NULL;
|
|
pelp->elpWidth = 0;
|
|
pelp->elpBrushStyle = 0;
|
|
pelp->elpColor = 0;
|
|
pelp->elpHatch = 0;
|
|
pelp->elpNumEntries = 0;
|
|
|
|
lRet = sizeof(EXTLOGPEN);
|
|
}
|
|
else
|
|
{
|
|
// Fill in the logical pen.
|
|
|
|
((LOGPEN *) pvDest)->lopnStyle = (UINT) bro.flStylePen();
|
|
((LOGPEN *) pvDest)->lopnWidth.x = (int) bro.lWidthPen();
|
|
((LOGPEN *) pvDest)->lopnWidth.y = 0;
|
|
((LOGPEN *) pvDest)->lopnColor = bro.clrPen();
|
|
lRet = sizeof(LOGPEN);
|
|
}
|
|
}
|
|
}
|
|
else if (bro.bIsPen())
|
|
{
|
|
// Extended pen...
|
|
|
|
ULONG cstyle = (bro.bIsUserStyled()) ? bro.cstyle() : 0;
|
|
|
|
int cj = (int) (sizeof(EXTLOGPEN) - sizeof(DWORD) +
|
|
sizeof(DWORD) * (SIZE_T) cstyle);
|
|
|
|
if (pvDest == (LPVOID) NULL)
|
|
{
|
|
lRet = cj;
|
|
}
|
|
else if (iCount >= cj)
|
|
{
|
|
PEXTLOGPEN pelp = (PEXTLOGPEN) pvDest;
|
|
|
|
pelp->elpPenStyle = (UINT) bro.flStylePen();
|
|
pelp->elpWidth = (UINT) bro.lWidthPen();
|
|
pelp->elpNumEntries = cstyle;
|
|
|
|
if (cstyle > 0)
|
|
{
|
|
// We can't just do a RtlCopyMemory for cosmetics, because
|
|
// we don't know how the LONGs are packed in the
|
|
// FLOAT_LONG array:
|
|
|
|
PFLOAT_LONG pelSrc = bro.pstyle();
|
|
PLONG plDest = (PLONG) &pelp->elpStyleEntry[0];
|
|
|
|
for (; cstyle > 0; cstyle--)
|
|
{
|
|
if (bro.bIsCosmetic())
|
|
*plDest = pelSrc->l;
|
|
else
|
|
{
|
|
EFLOATEXT efLength(pelSrc->e);
|
|
BOOL b = efLength.bEfToL(*plDest);
|
|
|
|
ASSERTGDI(b, "Shouldn't have overflowed");
|
|
}
|
|
|
|
plDest++;
|
|
pelSrc++;
|
|
}
|
|
}
|
|
|
|
// The client side GetObject will fill in the rest of the
|
|
// EXTLOGPEN struct. i.e. elpBrushStyle, elpColor, and elpHatch.
|
|
|
|
// Changed: added these here -30-11-94 -by- Lingyunw
|
|
// added lBrushStyle and lHatch to PEN
|
|
|
|
pelp->elpBrushStyle = bro.lBrushStyle();
|
|
pelp->elpColor = bro.crColor();
|
|
pelp->elpHatch = bro.lHatch();
|
|
|
|
lRet = cj;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Brush...
|
|
|
|
if (pvDest == (LPVOID) NULL)
|
|
{
|
|
lRet = sizeof(LOGBRUSH);
|
|
}
|
|
else if (iCount >= sizeof(LOGBRUSH))
|
|
{
|
|
// make sure the kernel attributes match
|
|
|
|
bSyncBrushObj(bro.pbrush());
|
|
|
|
// Fill in logical brush. Figure out what type it is.
|
|
|
|
// Duplicates of this info is kept on the client side,
|
|
// so most calls won't even get here:
|
|
|
|
if (bro.flAttrs() & BR_IS_SOLID)
|
|
{
|
|
((LOGBRUSH *) pvDest)->lbStyle = BS_SOLID;
|
|
((LOGBRUSH *) pvDest)->lbColor = bro.crColor();
|
|
((LOGBRUSH *) pvDest)->lbHatch = 0;
|
|
}
|
|
else if (bro.flAttrs() & BR_IS_BITMAP)
|
|
{
|
|
((LOGBRUSH *) pvDest)->lbStyle = BS_PATTERN;
|
|
((LOGBRUSH *) pvDest)->lbColor = 0;
|
|
((LOGBRUSH *) pvDest)->lbHatch = (ULONG_PTR)bro.hbmClient();
|
|
}
|
|
else if (bro.flAttrs() & BR_IS_HATCH)
|
|
{
|
|
((LOGBRUSH *) pvDest)->lbStyle = BS_HATCHED;
|
|
((LOGBRUSH *) pvDest)->lbColor = bro.crColor();
|
|
((LOGBRUSH *) pvDest)->lbHatch = bro.ulStyle();
|
|
}
|
|
else if (bro.flAttrs() & BR_IS_NULL)
|
|
{
|
|
((LOGBRUSH *) pvDest)->lbStyle = BS_HOLLOW;
|
|
((LOGBRUSH *) pvDest)->lbColor = 0;
|
|
((LOGBRUSH *) pvDest)->lbHatch = 0;
|
|
}
|
|
else if (bro.flAttrs() & BR_IS_DIB)
|
|
{
|
|
// Could be BS_DIBPATTERN or BS_DIBPATTERNPT, but we'll just
|
|
// return BS_DIBPATTERN.
|
|
|
|
((LOGBRUSH *) pvDest)->lbStyle = BS_DIBPATTERN;
|
|
((LOGBRUSH *) pvDest)->lbColor = bro.crColor();
|
|
((LOGBRUSH *) pvDest)->lbHatch = (ULONG_PTR)bro.hbmClient();
|
|
}
|
|
else
|
|
RIP("ERROR GreGetObject invalid brush type");
|
|
|
|
lRet = sizeof(LOGBRUSH);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING1("cjGetBrushOrPen():hobj is invalid\n");
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
return(lRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreGetObject
|
|
*
|
|
* API function
|
|
*
|
|
* returns: number of bytes needed if pvDest == NULL, else bytes copied out
|
|
* for error it returns 0
|
|
*
|
|
* in case a log font object is requested, the function will fill the buffer with
|
|
* as many bytes of the EXTLOGFONT structure as requested. If a caller
|
|
* wants a LOGFONTW structure in the buffer, he should specify
|
|
* ulCount == sizeof(LOGFONTW)
|
|
* The function will copy the first sizeof(LOGFONTW) bytes of the EXTLOGFONTW
|
|
* structure to the buffer, which is precisely the LOGFONTW structure. The rest
|
|
* of the EXTLOGFONTW structure will be chopped off.
|
|
*
|
|
* History:
|
|
*
|
|
* Thu 12-Dec-1996 -by- Bodin Dresevic [BodinD]
|
|
* update: changed EXTLOGFONT to ENUMLOGFONTEXDVW
|
|
*
|
|
* Thu 30-Jan-1992 -by- J. Andrew Goossen [andrewgo]
|
|
* added extended pen support.
|
|
*
|
|
* Wed 21-Aug-1991 -by- Bodin Dresevic [BodinD]
|
|
* update: converted to return EXTLOGFONTW
|
|
*
|
|
* Fri 24-May-1991 -by- Patrick Haluptzok [patrickh]
|
|
* added first pass pen and brush stuff.
|
|
*
|
|
* Tue 24-Apr-1991 -by- Patrick Haluptzok [patrickh]
|
|
* added surface stuff.
|
|
*
|
|
* 08-Dec-1990 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int APIENTRY GreExtGetObjectW(HANDLE hobj, int ulCount, LPVOID pvDest)
|
|
{
|
|
int cRet = 0;
|
|
|
|
switch (HmgObjtype(hobj))
|
|
{
|
|
case PAL_TYPE:
|
|
cRet = 2;
|
|
|
|
if (pvDest != NULL)
|
|
{
|
|
if (ulCount < 2)
|
|
{
|
|
cRet = 0;
|
|
}
|
|
else
|
|
{
|
|
SEMOBJ semo(ghsemPalette);
|
|
|
|
{
|
|
EPALOBJ pal((HPALETTE) hobj);
|
|
|
|
if (!(pal.bValid()))
|
|
cRet = 0;
|
|
else
|
|
*((PUSHORT) pvDest) = (USHORT) (pal.cEntries());
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case LFONT_TYPE:
|
|
|
|
// The output object is assumed to be
|
|
// an ENUMLOGFONTEXDVW structure.
|
|
// client side shall do the translation to LOGFONT if necessary
|
|
|
|
{
|
|
LFONTOBJ lfo((HLFONT) hobj);
|
|
if (lfo.bValid())
|
|
{
|
|
if (pvDest != (LPVOID) NULL)
|
|
{
|
|
SIZE_T cjCopy = MIN((SIZE_T) ulCount, lfo.cjElfw());
|
|
|
|
RtlCopyMemory(pvDest, lfo.pelfw(), (UINT) cjCopy);
|
|
|
|
cRet = (ULONG) cjCopy;
|
|
}
|
|
else
|
|
{
|
|
cRet = lfo.cjElfw();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("GreGetObject(): bad handle\n");
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SURF_TYPE:
|
|
if (pvDest != (LPVOID) NULL)
|
|
{
|
|
cRet = 0;
|
|
|
|
if (ulCount >= (int)sizeof(BITMAP))
|
|
{
|
|
SURFREF SurfBm((HSURF) hobj);
|
|
|
|
if ((SurfBm.bValid()) &&
|
|
(SurfBm.ps->bApiBitmap() || SurfBm.ps->bDirectDraw()))
|
|
{
|
|
BITMAP *pbm = (BITMAP *) pvDest;
|
|
|
|
pbm->bmType = 0;
|
|
pbm->bmWidth = SurfBm.ps->sizl().cx;
|
|
pbm->bmHeight = SurfBm.ps->sizl().cy;
|
|
|
|
pbm->bmBitsPixel = (WORD) gaulConvert[SurfBm.ps->iFormat()];
|
|
pbm->bmWidthBytes = ((SurfBm.ps->sizl().cx * pbm->bmBitsPixel + 15) >> 4) << 1;
|
|
pbm->bmPlanes = 1;
|
|
pbm->bmBits = (LPSTR) NULL;
|
|
|
|
cRet = sizeof(BITMAP);
|
|
|
|
// Get the bitmapinfoheader for the dibsection if the buffer
|
|
// can hold it.
|
|
|
|
if (SurfBm.ps->bDIBSection() || SurfBm.ps->bDirectDraw())
|
|
{
|
|
// Win95 compatability. They fill in the bits even if it
|
|
// is not big enough for a full DIBSECTION
|
|
|
|
pbm->bmBits = IS_USER_ADDRESS((LPSTR) SurfBm.ps->pvBits()) ? (LPSTR) SurfBm.ps->pvBits() : NULL;
|
|
|
|
// If this is a DIBSection/DirectDraw surface bmWidthBytes must be aligned
|
|
// on a DWORD boundary.
|
|
|
|
pbm->bmWidthBytes = ((SurfBm.ps->sizl().cx * pbm->bmBitsPixel + 31) & ~31) >> 3;
|
|
|
|
if (ulCount >= sizeof(DIBSECTION))
|
|
{
|
|
PBITMAPINFOHEADER pbmih = &((DIBSECTION *)pvDest)->dsBmih;
|
|
|
|
pbmih->biSize = sizeof(BITMAPINFOHEADER);
|
|
pbmih->biBitCount = 0;
|
|
|
|
if (GreGetDIBitsInternal(0,(HBITMAP)hobj,0,0,NULL,
|
|
(PBITMAPINFO)pbmih,DIB_RGB_COLORS,0,
|
|
sizeof(DIBSECTION)))
|
|
{
|
|
cRet = sizeof(DIBSECTION);
|
|
|
|
// More Win9x compatibility: for DDraw surfaces, the
|
|
// following field is always zero. GDI+ keys off
|
|
// this Win9x feature to do cheap detection of
|
|
// DDraw surfaces:
|
|
|
|
if (SurfBm.ps->bDirectDraw())
|
|
{
|
|
pbmih->biSizeImage = 0;
|
|
}
|
|
}
|
|
|
|
|
|
XEPALOBJ pal(SurfBm.ps->ppal());
|
|
|
|
if (pal.bValid() && pal.bIsBitfields())
|
|
{
|
|
((DIBSECTION *)pvDest)->dsBitfields[0] = pal.flRed();
|
|
((DIBSECTION *)pvDest)->dsBitfields[1] = pal.flGre();
|
|
((DIBSECTION *)pvDest)->dsBitfields[2] = pal.flBlu();
|
|
}
|
|
|
|
// to be consistent with win95, Getobject returns BI_RGB for
|
|
// 24bpp, and 32bpp when BI_RGB is set at creation time
|
|
|
|
else
|
|
{
|
|
if (pal.bValid() && pal.bIsBGR())
|
|
{
|
|
pbmih->biCompression = BI_RGB;
|
|
}
|
|
|
|
((DIBSECTION *)pvDest)->dsBitfields[0] = 0;
|
|
((DIBSECTION *)pvDest)->dsBitfields[1] = 0;
|
|
((DIBSECTION *)pvDest)->dsBitfields[2] = 0;
|
|
}
|
|
|
|
((DIBSECTION *)pvDest)->dshSection = SurfBm.ps->hDIBSection();
|
|
((DIBSECTION *)pvDest)->dsOffset = SurfBm.ps->dwOffset();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cRet = sizeof(BITMAP);
|
|
}
|
|
|
|
break;
|
|
|
|
case BRUSH_TYPE:
|
|
cRet = (int) cjGetBrushOrPen(hobj, ulCount, pvDest);
|
|
break;
|
|
|
|
case ICMLCS_TYPE:
|
|
cRet = cjGetLogicalColorSpace(hobj,ulCount,pvDest);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return(cRet);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreGetStockObject
|
|
*
|
|
* API function
|
|
*
|
|
* returns the handle to the stock object requested.
|
|
*
|
|
* History:
|
|
* 08-Dec-1990 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HANDLE gahStockObjects[PRIV_STOCK_LAST+1] = {0};
|
|
|
|
HANDLE GreGetStockObject(int ulIndex)
|
|
{
|
|
if (((UINT)ulIndex) <= PRIV_STOCK_LAST)
|
|
{
|
|
return(gahStockObjects[ulIndex]);
|
|
}
|
|
else
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
BOOL bSetStockObject(
|
|
HANDLE h,
|
|
int iObj
|
|
)
|
|
{
|
|
if (h)
|
|
{
|
|
gahStockObjects[iObj] = (HANDLE)((ULONG_PTR)h | GDISTOCKOBJ);
|
|
HmgModifyHandleType((HOBJ) gahStockObjects[iObj]);
|
|
}
|
|
return(h != NULL);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL GreGetColorAdjustment
|
|
*
|
|
* Get the color adjustment data of the given DC.
|
|
*
|
|
* History:
|
|
* 25-Aug-1992 -by- Wendy Wu [wendywu]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GreGetColorAdjustment(HDC hdc, COLORADJUSTMENT *pca)
|
|
{
|
|
DCOBJ dco(hdc);
|
|
BOOL Status;
|
|
|
|
if (!dco.bValid())
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
Status = FALSE;
|
|
|
|
} else {
|
|
|
|
// Retrieve info from the DC. Mask out the internal flag.
|
|
|
|
*pca = *dco.pColorAdjustment();
|
|
pca->caFlags &= (CA_NEGATIVE | CA_LOG_FILTER);
|
|
Status = TRUE;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL GreSetColorAdjustment
|
|
*
|
|
* Set the color adjustment data of the given DC.
|
|
*
|
|
* History:
|
|
* 25-Aug-1992 -by- Wendy Wu [wendywu]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GreSetColorAdjustment(HDC hdc, COLORADJUSTMENT *pcaNew)
|
|
{
|
|
DCOBJ dco(hdc);
|
|
BOOL Status;
|
|
|
|
if (!dco.bValid())
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
Status = FALSE;
|
|
|
|
} else {
|
|
|
|
// Store info into the DC. Turn off any flags that we don't support.
|
|
|
|
*dco.pColorAdjustment() = *pcaNew;
|
|
dco.pColorAdjustment()->caFlags &= (CA_NEGATIVE | CA_LOG_FILTER);
|
|
Status = TRUE;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HANDLE GreCreateClientObj()
|
|
*
|
|
* A ClientObj contains no data. It is purly to provide a handle to the
|
|
* client for objects such as metafiles that exist only on the client side.
|
|
*
|
|
* ulType is a client type.
|
|
*
|
|
* History:
|
|
* 17-Jan-1995 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HANDLE NtGdiCreateClientObj(
|
|
ULONG ulType)
|
|
{
|
|
HANDLE h = NULL;
|
|
|
|
// ClientObj handles should never have any INDEX bits set and have some
|
|
// ALT bits set. Also the type must be a LO_CLIENTOBJ_TYPE
|
|
|
|
if((ulType & (INDEX_MASK)) || !(ulType & (ALTTYPE_MASK)) || ((ulType & TYPE_MASK) != LO_CLIENTOBJ_TYPE))
|
|
{
|
|
WARNING("GreCreateClientObj: bad type\n");
|
|
return(h);
|
|
}
|
|
|
|
PVOID pv = ALLOCOBJ(sizeof(OBJECT), CLIENTOBJ_TYPE, FALSE);
|
|
|
|
if (pv)
|
|
{
|
|
h = HmgInsertObject(pv, 0, CLIENTOBJ_TYPE);
|
|
|
|
if (!h)
|
|
{
|
|
WARNING("GreCreateClientObj: HmgInsertObject failed\n");
|
|
FREEOBJ(pv, CLIENTOBJ_TYPE);
|
|
}
|
|
else
|
|
{
|
|
pv = HmgLock((HOBJ) h,CLIENTOBJ_TYPE);
|
|
|
|
if (pv != NULL)
|
|
{
|
|
h = MODIFY_HMGR_TYPE(h,ulType);
|
|
HmgModifyHandleType((HOBJ)h);
|
|
DEC_EXCLUSIVE_REF_CNT(pv);
|
|
}
|
|
else
|
|
{
|
|
RIP("GreCreateClientObj failed lock\n");
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("GreCreateClientObj(): ALLOCOBJ failed\n");
|
|
}
|
|
|
|
return(h);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
*
|
|
* History:
|
|
* 17-Jan-1995 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL GreDeleteClientObj(
|
|
HANDLE h)
|
|
{
|
|
PVOID pv = HmgRemoveObject((HOBJ)h, 0, 0, TRUE, CLIENTOBJ_TYPE);
|
|
|
|
if (pv != NULL)
|
|
{
|
|
FREEOBJ(pv, CLIENTOBJ_TYPE);
|
|
return(TRUE);
|
|
}
|
|
else
|
|
{
|
|
WARNING("GreDeleteClientObj: HmgRemoveObject failed\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* NtGdiDeleteClientObj()
|
|
*
|
|
* History:
|
|
* 01-Nov-1994 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
APIENTRY
|
|
NtGdiDeleteClientObj(
|
|
HANDLE h
|
|
)
|
|
{
|
|
return(GreDeleteClientObj(h));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreFreePool
|
|
*
|
|
* Private USER call to delete memory allocated by GDI.
|
|
*
|
|
* Only known use is to delete the MDEV structure returned by DrvCreateMDEV
|
|
* and cached by USER.
|
|
*
|
|
* History:
|
|
* 24-Feb-1998 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" VOID GreFreePool(PVOID pv)
|
|
{
|
|
GdiFreePool(pv);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* hdevEnumerate
|
|
*
|
|
* Enumerates all display PDEVs without keeping ghsemDriverMgmt, allowing
|
|
* the devlock to be taken on each. This function must be called until it
|
|
* returns NULL or proper cleanup will not occur.
|
|
*
|
|
* History:
|
|
* 02-Jul-1999 -by- John Stephens [johnstep]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HDEV
|
|
hdevEnumerate(
|
|
HDEV hdevPrevious
|
|
)
|
|
{
|
|
PDEV* ppdev;
|
|
|
|
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
|
|
|
|
// If we are called with NULL hdevPrevious then create the PDEVOBJ from
|
|
// gppdevList, else create it from hdevPrevious:
|
|
|
|
PDEVOBJ po(hdevPrevious ? hdevPrevious : (HDEV) gppdevList);
|
|
ASSERTGDI(po.bValid(), "Invalid HDEV");
|
|
|
|
// Search for the next display PDEV. If hdevPrevious is NULL, then
|
|
// we start with po, else start from the next:
|
|
|
|
for (ppdev = hdevPrevious ? po.ppdev->ppdevNext : po.ppdev;
|
|
ppdev;
|
|
ppdev = ppdev->ppdevNext)
|
|
{
|
|
// We're only interested in display PDEVs:
|
|
|
|
if (ppdev->fl & PDEV_DISPLAY)
|
|
{
|
|
// We found the next display PDEV, so take a reference count
|
|
// on it before releasing ghsemDriverMgmt and returning. This
|
|
// reference count will be removed next time through:
|
|
|
|
ppdev->cPdevRefs++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If hdevPrevious is not NULL then we need to remove the reference
|
|
// count we took, and we'll also release ghsemDriverMgmt here in the
|
|
// appropriate place:
|
|
|
|
if (hdevPrevious)
|
|
{
|
|
// If our reference count is not the last, just decrement, else we
|
|
// need to call vUnreferencePdev so the PDEV will actually be
|
|
// deleted:
|
|
|
|
ASSERTGDI(po.cPdevRefs() > 0,
|
|
"PDEV reference count is 0 but should be at least 1");
|
|
|
|
if (po.cPdevRefs() > 1)
|
|
{
|
|
po.ppdev->cPdevRefs--;
|
|
GreReleaseSemaphoreEx(ghsemDriverMgmt);
|
|
}
|
|
else
|
|
{
|
|
// Release ghsemDriverMgmt before calling vUnreferencePdev
|
|
// because the call may result in the devlock being taken:
|
|
|
|
GreReleaseSemaphoreEx(ghsemDriverMgmt);
|
|
po.vUnreferencePdev();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GreReleaseSemaphoreEx(ghsemDriverMgmt);
|
|
}
|
|
|
|
return (HDEV) ppdev;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vSynchronizeDriver
|
|
*
|
|
* Calls DrvSynchronize if the driver has set either GCAPS2_SYNCFLUSH
|
|
* or GCAPS2_SYNCTIMER, as appropriate.
|
|
*
|
|
* History:
|
|
* 15-Dec-1997 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vSynchronizeDriver(FLONG flSynchronizeType)
|
|
{
|
|
HDEV hdev;
|
|
|
|
//
|
|
// Note that we check the synchronize counts outside of a lock, which
|
|
// is okay.
|
|
//
|
|
|
|
//
|
|
// We just accumlate what needs to be synchronized when we are in the middle
|
|
// of a mode change.
|
|
//
|
|
|
|
if (CModeChangeInProgress::lInModeChange)
|
|
{
|
|
if(flSynchronizeType == GCAPS2_SYNCFLUSH && gcSynchronizeFlush != -1)
|
|
InterlockedCompareExchange(&CModeChangeInProgress::lNeedSyncFlush,1,0);
|
|
if(flSynchronizeType == GCAPS2_SYNCTIMER && gcSynchronizeTimer != -1)
|
|
InterlockedCompareExchange(&CModeChangeInProgress::lNeedTimerFlush,1,0);
|
|
return;
|
|
}
|
|
|
|
if (((flSynchronizeType == GCAPS2_SYNCFLUSH) && (gcSynchronizeFlush != -1)) ||
|
|
((flSynchronizeType == GCAPS2_SYNCTIMER) && (gcSynchronizeTimer != -1)))
|
|
{
|
|
for (hdev = hdevEnumerate(NULL); hdev; hdev = hdevEnumerate(hdev))
|
|
{
|
|
PDEVOBJ pdo(hdev);
|
|
|
|
ASSERTGDI(pdo.bValid(), "GreFlush: invalid PDEV");
|
|
ASSERTGDI(pdo.bDisplayPDEV(), "GreFlush: not a display PDEV");
|
|
|
|
if (pdo.flGraphicsCaps2NotDynamic() & flSynchronizeType)
|
|
{
|
|
GreAcquireSemaphoreEx(pdo.hsemDevLock(), SEMORDER_DEVLOCK, NULL);
|
|
GreEnterMonitoredSection(pdo.ppdev, WD_DEVLOCK);
|
|
|
|
if ((pdo.flGraphicsCaps2() & flSynchronizeType) &&
|
|
!(pdo.bDisabled()))
|
|
{
|
|
FLONG fl = 0;
|
|
|
|
if ((flSynchronizeType == GCAPS2_SYNCFLUSH) &&
|
|
(gcSynchronizeFlush != -1))
|
|
{
|
|
fl |= DSS_FLUSH_EVENT;
|
|
}
|
|
|
|
if ((flSynchronizeType == GCAPS2_SYNCTIMER) &&
|
|
(gcSynchronizeTimer != -1))
|
|
{
|
|
fl |= DSS_TIMER_EVENT;
|
|
}
|
|
|
|
pdo.vSync(pdo.pSurface()->pSurfobj(), NULL, fl);
|
|
}
|
|
|
|
GreExitMonitoredSection(pdo.ppdev, WD_DEVLOCK);
|
|
GreReleaseSemaphoreEx(pdo.hsemDevLock());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreFlush
|
|
*
|
|
* Called for GdiFlush.
|
|
*
|
|
* Calls DrvSynchronize if it is hooked and GCAPS2_SYNCFLUSH is set.
|
|
*
|
|
* History:
|
|
* 15-Dec-1997 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
APIENTRY
|
|
GreFlush()
|
|
{
|
|
vSynchronizeDriver(GCAPS2_SYNCFLUSH);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreSynchronizeTimer
|
|
*
|
|
* When the synchronization timer is enabled, this routine will be called
|
|
* by User's RIT. We, in turn, call any driver that has set GCAPS_SYNCTIMER.
|
|
*
|
|
* History:
|
|
* 2-Jun-1998 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID APIENTRY GreSynchronizeTimer(PVOID pwnd, UINT msg, UINT_PTR id, LPARAM lParam)
|
|
{
|
|
vSynchronizeDriver(GCAPS2_SYNCTIMER);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vEnableSynchronize
|
|
*
|
|
* This routine enables GCAPS2_SYNCFLUSH and GCAPS2_SYNCTIMER
|
|
* synchronization for the driver.
|
|
*
|
|
* History:
|
|
* 2-Jun-1998 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vEnableSynchronize(HDEV hdev)
|
|
{
|
|
GDIFunctionID(vEnableSynchronize);
|
|
|
|
PDEVOBJ po(hdev);
|
|
|
|
FLONG flCaps = po.flGraphicsCaps2();
|
|
|
|
if (flCaps & (GCAPS2_SYNCFLUSH | GCAPS2_SYNCTIMER))
|
|
{
|
|
BOOL AcquireUserCritSec;
|
|
|
|
//
|
|
// We will be calling User, which needs to acquire its critical
|
|
// section. The devlock must always be acquired after the User
|
|
// critical section; consequently, we cannot be holding a devlock
|
|
// at this point if we're not already holding the user lock.
|
|
//
|
|
|
|
AcquireUserCritSec = !UserIsUserCritSecIn();
|
|
if (AcquireUserCritSec)
|
|
{
|
|
po.vAssertNoDevLock();
|
|
UserEnterUserCritSec();
|
|
}
|
|
|
|
if (flCaps & GCAPS2_SYNCTIMER)
|
|
{
|
|
//
|
|
// It's the responsibility of the first thread to increment
|
|
// the count past -1 to create the timer.
|
|
//
|
|
|
|
if (++gcSynchronizeTimer == 0)
|
|
{
|
|
ASSERTGDI(gidSynchronizeTimer == 0,
|
|
"Expected no timer to have already been created.");
|
|
|
|
//
|
|
// Note that at boot time we actually expect this timer
|
|
// creation to fail, as User hasn't had a chance to
|
|
// create the RIT yet. GreSetTimers handles the actual
|
|
// timer creation for that case. Because of this case,
|
|
// we can't strictly fail here if the timer can't be
|
|
// created; however, it's not the end of the world --
|
|
// this will happen only in a degenerate case, and at
|
|
// worst the video will be very jerky.
|
|
//
|
|
|
|
gidSynchronizeTimer = UserSetTimer(SYNCTIMER_FREQUENCY,
|
|
GreSynchronizeTimer);
|
|
}
|
|
}
|
|
|
|
if (flCaps & GCAPS2_SYNCFLUSH)
|
|
{
|
|
gcSynchronizeFlush++;
|
|
}
|
|
|
|
po.vSynchronizeEnabled(TRUE);
|
|
|
|
if (AcquireUserCritSec)
|
|
{
|
|
UserLeaveUserCritSec();
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vDisableSynchronize(HDEV hdev)
|
|
*
|
|
* This routine disables GCAPS2_SYNCFLUSH and GCAPS2_SYNCTIMER
|
|
* synchronization for the driver.
|
|
*
|
|
* History:
|
|
* 2-Jun-1998 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vDisableSynchronize(HDEV hdev)
|
|
{
|
|
GDIFunctionID(vDisableSynchronize);
|
|
|
|
PDEVOBJ po(hdev);
|
|
BOOL AcquireUserCritSec;
|
|
|
|
//
|
|
// We will be calling User, which needs to acquire its critical
|
|
// section. The devlock must always be acquired after the User
|
|
// critical section; consequently, we cannot be holding a devlock
|
|
// at this point if we're not already holding the user lock.
|
|
//
|
|
|
|
AcquireUserCritSec = !UserIsUserCritSecIn();
|
|
if (AcquireUserCritSec)
|
|
{
|
|
po.vAssertNoDevLock();
|
|
UserEnterUserCritSec();
|
|
}
|
|
|
|
if (po.bSynchronizeEnabled())
|
|
{
|
|
FLONG flCaps = po.flGraphicsCaps2();
|
|
|
|
if (flCaps & GCAPS2_SYNCFLUSH)
|
|
{
|
|
ASSERTGDI(gcSynchronizeFlush > -1, "Unexpected flush count");
|
|
|
|
gcSynchronizeFlush--;
|
|
}
|
|
|
|
if (flCaps & GCAPS2_SYNCTIMER)
|
|
{
|
|
//
|
|
// It's the responsibility of the first thread to decrement
|
|
// the count to -1 to kill the timer.
|
|
//
|
|
|
|
ASSERTGDI(gcSynchronizeTimer > -1, "Unexpected timer count");
|
|
|
|
if (--gcSynchronizeTimer < 0)
|
|
{
|
|
if (gidSynchronizeTimer != 0)
|
|
{
|
|
UserKillTimer(gidSynchronizeTimer);
|
|
gidSynchronizeTimer = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
po.vSynchronizeEnabled(FALSE);
|
|
}
|
|
|
|
if (AcquireUserCritSec)
|
|
{
|
|
UserLeaveUserCritSec();
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreStartTimers()
|
|
*
|
|
* Called by User when the RIT thread is finally initialized, and we
|
|
* can set up timers. We need this because driver initialization
|
|
* occurs before the RIT is initialized, which would have been the
|
|
* natural place to put the timer initialization for us.
|
|
*
|
|
* History:
|
|
* 2-Jun-1998 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID GreStartTimers()
|
|
{
|
|
GDIFunctionID(GreStartTimers);
|
|
|
|
BOOL AcquireUserCritSec;
|
|
|
|
AcquireUserCritSec = !UserIsUserCritSecIn();
|
|
if (AcquireUserCritSec)
|
|
{
|
|
UserEnterUserCritSec();
|
|
}
|
|
|
|
if (gcSynchronizeTimer != -1)
|
|
{
|
|
ASSERTGDI(gidSynchronizeTimer == NULL,
|
|
"Expected no timer to have already been created.");
|
|
|
|
gidSynchronizeTimer = UserSetTimer(SYNCTIMER_FREQUENCY,
|
|
GreSynchronizeTimer);
|
|
}
|
|
|
|
if (AcquireUserCritSec)
|
|
{
|
|
UserLeaveUserCritSec();
|
|
}
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CmodeChangeInProgress::vDone().
|
|
*
|
|
* Called by DrvChangeDisplaySettings just before it realeases the
|
|
* ghsemShareDevLock so we may flush any pending vSynchronizeDriver calls.
|
|
*
|
|
* History:
|
|
* 18-Oct-2001 -by- Pravin Santiago [pravins]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
void CModeChangeInProgress::vDone()
|
|
{
|
|
InterlockedDecrement(&lInModeChange);
|
|
|
|
if (lNeedSyncFlush)
|
|
{
|
|
vSynchronizeDriver(GCAPS2_SYNCFLUSH);
|
|
InterlockedDecrement(&lNeedSyncFlush);
|
|
}
|
|
if (lNeedTimerFlush)
|
|
{
|
|
vSynchronizeDriver(GCAPS2_SYNCTIMER);
|
|
InterlockedDecrement(&lNeedTimerFlush);
|
|
}
|
|
}
|