mirror of https://github.com/lianthony/NT4.0
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.
2491 lines
74 KiB
2491 lines
74 KiB
|
|
/******************************Module*Header*******************************\
|
|
* Module Name: OPENDC.CXX
|
|
*
|
|
* Handles DC creation and driver loading.
|
|
*
|
|
* Copyright (c) 1990-1996 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
extern HBRUSH ghbrGrayPattern;
|
|
|
|
extern FLONG flRaster(ULONG, FLONG);
|
|
|
|
extern PTRACKOBJ gpto;
|
|
|
|
/******************************Private*Routine*****************************\
|
|
* hdcCreate (pr,iType, bAltType)
|
|
*
|
|
* Allocates space for a DC, fills in the defaults.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HDC
|
|
hdcCreate(
|
|
PDEVREF& pr,
|
|
ULONG iType,
|
|
BOOL bAltType)
|
|
{
|
|
HDC hdc = (HDC) NULL;
|
|
|
|
//
|
|
// We hold the devlock to protect against dynamic mode changes
|
|
// while we're copying mode specific information to the DC.
|
|
//
|
|
|
|
DEVLOCKOBJ dlo(pr);
|
|
|
|
DCMEMOBJ dcmo(iType, bAltType);
|
|
|
|
if (dcmo.bValid())
|
|
{
|
|
//
|
|
// Copy info from the PDEV into the DC.
|
|
//
|
|
|
|
dcmo.pdc->ppdev((PDEV *) pr.hdev());
|
|
dcmo.pdc->flGraphicsCaps(pr.flGraphicsCaps()); // cache it for later use by graphics output functions
|
|
dcmo.pdc->dhpdev(pr.dhpdev());
|
|
dcmo.pDcDevLock(pr.pDevLock());
|
|
|
|
if (iType == DCTYPE_MEMORY)
|
|
{
|
|
SIZEL sizlTemp;
|
|
|
|
sizlTemp.cx = 1;
|
|
sizlTemp.cy = 1;
|
|
|
|
dcmo.pdc->sizl(sizlTemp);
|
|
}
|
|
else
|
|
{
|
|
dcmo.pdc->sizl(pr.sizl());
|
|
|
|
//
|
|
// The info and direct DC's for the screen need to grab
|
|
// the semaphore before doing output, the memory DC's will
|
|
// grab the semaphore only if a DFB is selected.
|
|
//
|
|
|
|
if (iType == DCTYPE_DIRECT)
|
|
{
|
|
dcmo.bSynchronizeAccess(pr.bDisplayPDEV());
|
|
dcmo.pdc->vDisplay(pr.bDisplayPDEV());
|
|
dcmo.pdc->bInFullScreen(pr.bDisabled());
|
|
|
|
if (!pr.bPrinter())
|
|
dcmo.pdc->pSurface(pr.pSurface());
|
|
}
|
|
}
|
|
|
|
//
|
|
// Call the region code to set a default clip region.
|
|
//
|
|
|
|
if (dcmo.pdc->bSetDefaultRegion())
|
|
{
|
|
// If display PDEV, select in the System stock font.
|
|
|
|
dcmo.vSetDefaultFont(pr.bDisplayPDEV());
|
|
|
|
if (GreSetupDCAttributes((HDC)(dcmo.pdc->hGet())))
|
|
{
|
|
// Mark the DC as permanent, hold the PDEV reference.
|
|
|
|
dcmo.vKeepIt();
|
|
pr.vKeepIt();
|
|
|
|
// finish initializing the DC.
|
|
|
|
hdc = dcmo.hdc();
|
|
}
|
|
else
|
|
{
|
|
// DCMEMOBJ will be freed, delete vis region
|
|
|
|
dcmo.pdc->vReleaseVis();
|
|
|
|
// dec reference counts on brush and pen
|
|
|
|
DEC_SHARE_REF_CNT_LAZY0(dcmo.pdc->pbrushFill());
|
|
DEC_SHARE_REF_CNT_LAZY0(dcmo.pdc->pbrushLine());
|
|
DEC_SHARE_REF_CNT_LAZY_DEL_LOGFONT(dcmo.pdc->plfntNew());
|
|
}
|
|
}
|
|
|
|
// turn on the DC_PRIMARY_DISPLAY flag for primary dc's
|
|
|
|
if (pr.hdev() == UserGetHDEV())
|
|
{
|
|
dcmo.pdc->ulDirtyAdd(DC_PRIMARY_DISPLAY);
|
|
}
|
|
|
|
}
|
|
|
|
return hdc;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* NtGdiCreateMetafileDC()
|
|
*
|
|
* History:
|
|
* 01-Jun-1995 -by- Andre Vachon [andreva]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HDC
|
|
APIENTRY
|
|
NtGdiCreateMetafileDC(
|
|
HDC hdc
|
|
)
|
|
{
|
|
HDC hdcNew = NULL;
|
|
|
|
if (hdc)
|
|
{
|
|
//
|
|
// Lock down the given DC.
|
|
//
|
|
|
|
DCOBJ dco(hdc);
|
|
|
|
if (dco.bValid())
|
|
{
|
|
//
|
|
// Locate the PDEV.
|
|
//
|
|
|
|
PDEVREF pr((HDEV) dco.pdc->ppdev());
|
|
|
|
//
|
|
// Allocate the DC, fill it with defaults.
|
|
//
|
|
|
|
hdcNew = hdcCreate(pr, DCTYPE_INFO, TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We must call USER to get the current PDEV\HDEV for this thread
|
|
// This should end up right back in hdcCreateDC
|
|
//
|
|
|
|
hdcNew = UserGetDesktopDC(DCTYPE_INFO, TRUE);
|
|
}
|
|
|
|
return hdcNew;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* NtGdiCreateCompatibleDC()
|
|
*
|
|
* History:
|
|
* 01-Nov-1994 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HDC
|
|
APIENTRY
|
|
NtGdiCreateCompatibleDC(
|
|
HDC hdc
|
|
)
|
|
{
|
|
HDC hdcRet = GreCreateCompatibleDC(hdc);
|
|
|
|
//
|
|
// Make sure user attributes are added to this dc
|
|
//
|
|
|
|
#if DBG
|
|
|
|
if (hdcRet)
|
|
{
|
|
DCOBJ dco(hdcRet);
|
|
if (dco.bValid())
|
|
{
|
|
ASSERTGDI(((PENTRY)((POBJ)dco.pdc)->pEntry)->pUser != NULL,"NtGdiCreateCompatibleDC: pUser == NULL");
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
return(hdcRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HDC GreCreateCompatibleDC(hdc)
|
|
*
|
|
* History:
|
|
* 01-Jun-1995 -by- Andre Vachon [andreva]
|
|
* Wrote it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HDC APIENTRY GreCreateCompatibleDC(HDC hdc)
|
|
{
|
|
HDC hdcNew = NULL;
|
|
|
|
if (hdc)
|
|
{
|
|
//
|
|
// Lock down the given DC.
|
|
//
|
|
|
|
DCOBJ dco(hdc);
|
|
|
|
if (dco.bValid())
|
|
{
|
|
//
|
|
// Locate the PDEV.
|
|
//
|
|
|
|
PDEVREF pr((HDEV) dco.pdc->ppdev());
|
|
|
|
//
|
|
// Allocate the DC, fill it with defaults.
|
|
//
|
|
|
|
hdcNew = hdcCreate(pr, DCTYPE_MEMORY, FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hdcNew = UserGetDesktopDC(DCTYPE_MEMORY, FALSE);
|
|
}
|
|
|
|
return hdcNew;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// GreCreateHDEV
|
|
//
|
|
// Creates a PDEV that the window manager will use to open display DCs.
|
|
// This call is made by the window manager to open a new display surface
|
|
// for use. Any number of display surfaces may be open at one time.
|
|
//
|
|
// pwszDriver - Name of the Display driver to load.
|
|
//
|
|
// pdriv - Devmode containing mode in which display device should
|
|
// be set.
|
|
//
|
|
// hScreen - Handle to the miniport driver that controls the display
|
|
// device.
|
|
//
|
|
// bDefaultDisplay - Whether or not this is the inital display device (on
|
|
// which the default bitmap will be located).
|
|
//
|
|
// pDevLock - Pointer in which the devlock is returned.
|
|
//
|
|
//*****************************************************************************
|
|
|
|
HDEV
|
|
GreCreateHDEV
|
|
(
|
|
PWSZ pwszDriver,
|
|
PDEVMODEW pdriv,
|
|
HANDLE hScreen,
|
|
BOOL bDefaultDisplay,
|
|
PDEVICE_LOCK *pDevLock
|
|
)
|
|
{
|
|
// HANDLE hDup;
|
|
|
|
//
|
|
// Locate or load the device driver.
|
|
//
|
|
|
|
TRACE_INIT(("GreCreateHDEV: about to call LDEVREF::lr\n"));
|
|
|
|
LDEVREF lr(pwszDriver, LDEV_DEVICE_DISPLAY);
|
|
|
|
if (!lr.bValid())
|
|
{
|
|
TRACE_INIT(("GreCreateHDEV: failed LDEVREF::lr\n"));
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Hack to support a multi-display driver.
|
|
//
|
|
|
|
if ( *((PULONG)pdriv) == 'MDEV')
|
|
{
|
|
PMDEV pmdev = (PMDEV) pdriv;
|
|
ULONG i;
|
|
|
|
for (i = 0; i < pmdev->cmdev; i++)
|
|
{
|
|
//
|
|
// Transform all the PDEVs we are passing to the driver into
|
|
// DHPDEVs that it can use.
|
|
//
|
|
|
|
PDEVOBJ pdo(pmdev->mdevPos[i].hdev);
|
|
pmdev->mdevPos[i].hdev = (HDEV) pdo.dhpdevNotDynamic();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create a new PDEV.
|
|
//
|
|
|
|
TRACE_INIT(("GreCreateHDEV: about to call PDEVREF::pr\n"));
|
|
|
|
PDEVREF pr(lr,
|
|
pdriv,
|
|
NULL, // no logical address
|
|
NULL, // no data file
|
|
pwszDriver, // device name is the display driver name
|
|
// necessary for hook drivers.
|
|
hScreen);
|
|
|
|
if (!pr.bValid()) // PDEVREF logs error code.
|
|
{
|
|
|
|
TRACE_INIT(("GreCreateHDEV: PDEVREF::pr failed\n"));
|
|
|
|
return((HDEV) 0);
|
|
}
|
|
|
|
//
|
|
// The shell and USER end up really confused if these fields are
|
|
// set.
|
|
//
|
|
#if 0
|
|
//
|
|
// If we are running with a multi-display driver, properly set the default
|
|
// screen region to be the subset of the screen, as opposed to the whole
|
|
// screen. This will ensure pop-ups do not cross boundaries.
|
|
//
|
|
// Set this variable based on the primary device size.
|
|
// Entually, we will want it based on the primary screen location also.
|
|
//
|
|
|
|
if ( *((PULONG)pdriv) == 'MDEV')
|
|
{
|
|
PMDEV pmdev = (PMDEV) pdriv;
|
|
ULONG i;
|
|
|
|
for (i = 0; i < pmdev->cmdev; i++)
|
|
{
|
|
if (pmdev->mdevPos[i].flags) {
|
|
|
|
pr.GdiInfo()->ulHorzRes = pmdev->mdevPos[i].rcPos.right -
|
|
pmdev->mdevPos[i].rcPos.left;
|
|
pr.GdiInfo()->ulVertRes = pmdev->mdevPos[i].rcPos.bottom -
|
|
pmdev->mdevPos[i].rcPos.top;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Make a surface for it.
|
|
|
|
TRACE_INIT(("GreCreateHDEV: about to call pr:bMakeSurface\n"));
|
|
|
|
if (!pr.bMakeSurface())
|
|
{
|
|
TRACE_INIT(("GreCreateHDEV: pr:bMakeSurface failed\n"));
|
|
|
|
return((HDEV) 0);
|
|
}
|
|
|
|
TRACE_INIT(("GreCreateHDEV: about to call pr:bAddDisplay\n"));
|
|
|
|
//
|
|
// Realize the Gray pattern brush for USER.
|
|
//
|
|
|
|
pr.pbo()->vInit();
|
|
|
|
PBRUSH pbrGrayPattern;
|
|
|
|
pbrGrayPattern = (PBRUSH)HmgShareCheckLock((HOBJ)ghbrGrayPattern,
|
|
BRUSH_TYPE);
|
|
|
|
pr.pbo()->vInitBrush(pbrGrayPattern,
|
|
0,
|
|
0x00FFFFFF,
|
|
(XEPALOBJ) ppalDefault,
|
|
(XEPALOBJ) pr.ppdev->pSurface->ppal(),
|
|
pr.ppdev->pSurface);
|
|
|
|
DEC_SHARE_REF_CNT_LAZY0 (pbrGrayPattern);
|
|
|
|
//
|
|
// Now set the global default bitmaps pdev to equal that of our display
|
|
// device.
|
|
//
|
|
// NOTE:
|
|
// We only do this if this is the default display device.
|
|
// For secondary display devices, we do not do this.
|
|
//
|
|
|
|
if (bDefaultDisplay)
|
|
{
|
|
PSURFACE pSurfDefault = SURFACE::pdibDefault;
|
|
|
|
pSurfDefault->hdev(pr.hdev());
|
|
}
|
|
|
|
//
|
|
// Return a pointer to the device critical section to USER.
|
|
//
|
|
|
|
*pDevLock = pr.pDevLock();
|
|
|
|
//
|
|
// Note that USER holds a reference to the pdev.
|
|
//
|
|
|
|
pr.vKeepIt();
|
|
|
|
return(pr.hdev());
|
|
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// GreDestroyHDEV
|
|
//
|
|
// Deletes a display PDEV.
|
|
//
|
|
//*****************************************************************************
|
|
|
|
VOID
|
|
GreDestroyHDEV(
|
|
HDEV hdev
|
|
)
|
|
{
|
|
//
|
|
// Locate the PDEV.
|
|
//
|
|
|
|
PDEVOBJ po(hdev);
|
|
|
|
//
|
|
// Delete the PDEV.
|
|
//
|
|
|
|
po.vUnreferencePdev();
|
|
|
|
return;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// GreCreateHMDEV
|
|
//
|
|
// Creates a multi device PDEV (known as MDEV) that USER can create DCs on.
|
|
// This call is made by the window manager to open a new display surface
|
|
// for use. Any number of display surfaces may be open at one time.
|
|
//
|
|
// pmdev - List of HDEVs and rectnagle positions that the MDEV driver
|
|
// will use to determine the format of the large screen.
|
|
//
|
|
// pDevLock - Pointer in which the devlock is returned.
|
|
//
|
|
//*****************************************************************************
|
|
|
|
extern "C" BOOL MulDrvEnableDriver(ULONG,ULONG,PDRVENABLEDATA);
|
|
|
|
HMDEV
|
|
GreCreateHMDEV(
|
|
PMDEV pmdev,
|
|
PDEVICE_LOCK *pDevLock
|
|
)
|
|
{
|
|
ULONG i;
|
|
|
|
TRACE_INIT(("GreCreateHMDEV: about to call LDEVREF::lr\n"));
|
|
LDEVREF lr((PFN)MulDrvEnableDriver, LDEV_META_DEVICE);
|
|
|
|
if (!lr.bValid())
|
|
{
|
|
TRACE_INIT(("GreCreateHMDEV: failed LDEVREF::lr\n"));
|
|
return((HMDEV) 0);
|
|
}
|
|
|
|
//
|
|
// Create a new PDEV.
|
|
//
|
|
|
|
TRACE_INIT(("GreCreateHMDEV: about to call PDEVREF::pr\n"));
|
|
|
|
PDEVREF pr(lr,
|
|
(PDEVMODEW) pmdev,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (!pr.bValid()) // PDEVREF logs error code.
|
|
{
|
|
|
|
TRACE_INIT(("GreCreateHMDEV: PDEVREF::pr failed\n"));
|
|
|
|
return((HMDEV) 0);
|
|
}
|
|
|
|
// Make a surface for it.
|
|
|
|
TRACE_INIT(("GreCreateHMDEV: about to call pr:bMakeSurface\n"));
|
|
|
|
if (!pr.bMakeSurface())
|
|
{
|
|
TRACE_INIT(("GreCreateHMDEV: pr:bMakeSurface failed\n"));
|
|
|
|
return((HMDEV) 0);
|
|
}
|
|
|
|
TRACE_INIT(("GreCreateHMDEV: about to call pr:bAddDisplay\n"));
|
|
|
|
//
|
|
// Realize the Gray pattern brush for USER.
|
|
//
|
|
|
|
pr.pbo()->vInit();
|
|
|
|
PBRUSH pbrGrayPattern;
|
|
|
|
pbrGrayPattern = (PBRUSH)HmgShareCheckLock((HOBJ)ghbrGrayPattern,
|
|
BRUSH_TYPE);
|
|
|
|
pr.pbo()->vInitBrush(pbrGrayPattern,
|
|
0,
|
|
0x00FFFFFF,
|
|
(XEPALOBJ) ppalDefault,
|
|
(XEPALOBJ) pr.ppdev->pSurface->ppal(),
|
|
pr.ppdev->pSurface);
|
|
|
|
DEC_SHARE_REF_CNT_LAZY0 (pbrGrayPattern);
|
|
|
|
//
|
|
// Now set the global default bitmaps pdev to equal that of our display
|
|
// device.
|
|
//
|
|
// NOTE:
|
|
// We only do this if this is the default display device.
|
|
// For secondary display devices, we do not do this.
|
|
//
|
|
|
|
if (1 /* [!!!] bDefaultDisplay*/)
|
|
{
|
|
PSURFACE pSurfDefault = SURFACE::pdibDefault;
|
|
|
|
pSurfDefault->hdev(pr.hdev());
|
|
}
|
|
|
|
//
|
|
// Return a pointer to the device critical section to USER.
|
|
//
|
|
|
|
*pDevLock = pr.pDevLock();
|
|
KdPrint(("GreCreateHMDEV: pDevLock for DDML is %x.\n", *pDevLock));
|
|
|
|
//
|
|
// Note that USER holds a reference to the pdev.
|
|
//
|
|
|
|
pr.vKeepIt();
|
|
|
|
return(pr.hdev());
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// GreDestroyHMDEV
|
|
//
|
|
// Deletes a display MDEV.
|
|
//
|
|
//*****************************************************************************
|
|
|
|
VOID
|
|
GreDestroyHMDEV(
|
|
HMDEV hmdev
|
|
)
|
|
{
|
|
//
|
|
// Locate the PDEV.
|
|
//
|
|
|
|
PDEVOBJ po(hmdev);
|
|
|
|
//
|
|
// Delete the PDEV.
|
|
//
|
|
|
|
po.vUnreferencePdev();
|
|
|
|
return;
|
|
}
|
|
|
|
/******************************Exported*Routine****************************\
|
|
* GreCreateDisplayDC
|
|
*
|
|
* Opens a DC on the specified display PDEV.
|
|
*
|
|
* This call is only used by USER since it is the only one aware of the
|
|
* current desktop on which a thread is running
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HDC
|
|
GreCreateDisplayDC(
|
|
HDEV hdev,
|
|
ULONG iType,
|
|
BOOL bAltType)
|
|
{
|
|
HDC hdc;
|
|
|
|
//
|
|
// Locate the PDEV.
|
|
//
|
|
|
|
PDEVREF pr(hdev);
|
|
|
|
//
|
|
// Create the DC, fill it with defaults.
|
|
//
|
|
// If it is a metafile dc, it really is just an info dc with the handle munged
|
|
// to state that it is an alt DC type.
|
|
//
|
|
// hdcCreate does pr.vKeepIt.
|
|
//
|
|
|
|
hdc = hdcCreate(pr, iType, bAltType);
|
|
|
|
|
|
return (hdc);
|
|
}
|
|
|
|
|
|
/******************************Exported*Routine****************************\
|
|
* hdcOpenDCW
|
|
*
|
|
* Opens a DC for a device which is not a display. GDI should call this
|
|
* function from within DevOpenDC, in the case that an hdc is not passed
|
|
* in. This call locates the device and creates a new PDEV. The physical
|
|
* surface associated with this PDEV will be distinct from all other
|
|
* physical surfaces.
|
|
*
|
|
* The window manager should not call this routine unless it is providing
|
|
* printing services for an application.
|
|
*
|
|
* pwszDriver
|
|
*
|
|
* This points to a string which identifies the device driver.
|
|
* The given string must be a fully qualified path name.
|
|
*
|
|
* pdriv
|
|
*
|
|
* This is a pointer to the DEVMODEW block.
|
|
*
|
|
* Since a single driver, like PSCRIPT.DRV, may support multiple
|
|
* different devices, the szDeviceName field defines which device to
|
|
* use.
|
|
*
|
|
* This structure also contains device specific data in abGeneralData.
|
|
* This data is set by the device driver in bPostDeviceModes.
|
|
*
|
|
* If the pdriv pointer is NULL, the device driver assumes some default
|
|
* configuration.
|
|
*
|
|
* iType
|
|
*
|
|
* Identifies the type of the DC. Must be one of DCTYPE_DIRECT,
|
|
* DCTYPE_INFO, or DCTYPE_MEMORY.
|
|
*
|
|
* Returns:
|
|
*
|
|
* HDC - A handle to the DC.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
class PRINTER
|
|
{
|
|
public:
|
|
HANDLE hSpooler_;
|
|
BOOL bKeep;
|
|
|
|
public:
|
|
PRINTER(PWSZ pwszDevice,DEVMODEW *pdriv,HANDLE hspool );
|
|
~PRINTER()
|
|
{
|
|
if (!bKeep && (hSpooler_ != (HANDLE) NULL))
|
|
ClosePrinter(hSpooler_);
|
|
}
|
|
|
|
BOOL bValid() {return(hSpooler_ != (HANDLE) NULL);}
|
|
VOID vKeepIt() {bKeep = TRUE;}
|
|
HANDLE hSpooler() {return(hSpooler_);}
|
|
};
|
|
|
|
// PRINTER constructor -- Attempts to open a spooler connection to the
|
|
// printer.
|
|
|
|
PRINTER::PRINTER(
|
|
PWSZ pwszDevice,
|
|
DEVMODEW *pdriv,
|
|
HANDLE hspool )
|
|
{
|
|
bKeep = FALSE;
|
|
|
|
PRINTER_DEFAULTSW defaults;
|
|
|
|
defaults.pDevMode = pdriv;
|
|
defaults.DesiredAccess = PRINTER_ACCESS_USE;
|
|
|
|
//
|
|
// Attempt to open the printer for spooling journal files.
|
|
// NOTE: For debugging, a global flag disables journaling.
|
|
//
|
|
|
|
defaults.pDatatype = (LPWSTR) L"RAW";
|
|
|
|
if (hspool)
|
|
{
|
|
|
|
hSpooler_ = hspool;
|
|
|
|
// BUGBUG
|
|
// disabled for kernel mode
|
|
//
|
|
// hSpooler_ = hspool;
|
|
//
|
|
// if (!ResetPrinterW(hspool,&defaults))
|
|
// hSpooler_ = (HANDLE)NULL;
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
if (!OpenPrinterW(pwszDevice,&hSpooler_,&defaults))
|
|
{
|
|
//
|
|
// It's not a printer. OpenPrinterW doesn't guarantee the value
|
|
// of hSpooler in this case, so we have to clear it.
|
|
//
|
|
|
|
hSpooler_ = (HANDLE) NULL;
|
|
}
|
|
}
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* See comments above.
|
|
*
|
|
* History:
|
|
* Andre Vachon [andreva]
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HDC hdcOpenDCW(
|
|
PWSZ pwszDevice, // The device driver name.
|
|
DEVMODEW *pdriv, // Driver data.
|
|
ULONG iType, // Identifies the type of DC to create.
|
|
HANDLE hspool, // do we already have a spooler handle?
|
|
PREMOTETYPEONENODE prton)
|
|
{
|
|
HDC hdc = (HDC) 0; // Prepare for the worst.
|
|
DWORD cbNeeded = 0;
|
|
PVOID mDriverInfo;
|
|
|
|
TRACE_INIT(("\nhdcOpenDCW: ENTERING\n"));
|
|
|
|
|
|
//
|
|
// Attempt to open a display DC.
|
|
//
|
|
|
|
if (pwszDevice)
|
|
{
|
|
PDEVMODEW pdevmode = pdriv;
|
|
PVOID pDevice = NULL;
|
|
UNICODE_STRING usDevice;
|
|
DEVMODEW dm;
|
|
|
|
RtlInitUnicodeString(&usDevice,
|
|
pwszDevice);
|
|
|
|
if (pdevmode == NULL)
|
|
{
|
|
pdevmode = &dm;
|
|
RtlZeroMemory(pdevmode, sizeof(DEVMODEW));
|
|
pdevmode->dmSize = sizeof(DEVMODEW);
|
|
}
|
|
|
|
TRACE_INIT(("hdcOpenDCW: Trying to open as a second display device\n"));
|
|
|
|
hdc = UserCreateExclusiveDC(&usDevice,
|
|
pdevmode,
|
|
&pDevice);
|
|
if (hdc)
|
|
{
|
|
DCOBJ dco(hdc);
|
|
PDEVOBJ po(dco.hdev());
|
|
|
|
//
|
|
// Set up the destructor so that it calls USER when the PDEV needs
|
|
// to be destroyed.
|
|
//
|
|
|
|
po.SetPhysicalDevice(pDevice);
|
|
|
|
//
|
|
// Dereference the object since we want DeleteDC
|
|
// to automatically destroy the PDEV.
|
|
//
|
|
// This basically counteracts the extra reference that it done
|
|
// by Create HDEV.
|
|
//
|
|
|
|
po.vUnreferencePdev();
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Attempt to open a new printer DC.
|
|
//
|
|
|
|
if (hdc == NULL)
|
|
{
|
|
//
|
|
// Open the spooler connection to the printer.
|
|
// Allocate space for DRIVER_INFO.
|
|
//
|
|
|
|
PRINTER print(pwszDevice, pdriv, hspool);
|
|
|
|
if (print.bValid())
|
|
{
|
|
if (mDriverInfo = PALLOCMEM(512, 'pmtG'))
|
|
{
|
|
//
|
|
// Fill the DRIVER_INFO.
|
|
//
|
|
|
|
if (!GetPrinterDriverW(
|
|
print.hSpooler(),
|
|
NULL,
|
|
2,
|
|
(LPBYTE) mDriverInfo,
|
|
512,
|
|
&cbNeeded))
|
|
{
|
|
|
|
//
|
|
// Call failed - free the memory.
|
|
//
|
|
|
|
VFREEMEM(mDriverInfo);
|
|
mDriverInfo = NULL;
|
|
|
|
//
|
|
// Get more space if we need it.
|
|
//
|
|
|
|
if ((EngGetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
|
|
(cbNeeded > 0))
|
|
{
|
|
if (mDriverInfo = PALLOCMEM(cbNeeded, 'pmtG'))
|
|
{
|
|
|
|
if (!GetPrinterDriverW(print.hSpooler(),
|
|
NULL,
|
|
2,
|
|
(LPBYTE) mDriverInfo,
|
|
cbNeeded,
|
|
&cbNeeded))
|
|
{
|
|
VFREEMEM(mDriverInfo);
|
|
mDriverInfo = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (mDriverInfo != (PVOID) NULL)
|
|
{
|
|
|
|
//
|
|
// Reference the LDEV.
|
|
//
|
|
|
|
LDEVREF lr(((DRIVER_INFO_2W *)mDriverInfo)->pDriverPath,
|
|
LDEV_DEVICE_PRINTER);
|
|
|
|
if (!lr.bValid())
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_BAD_DRIVER_LEVEL);
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// Create a PDEV. If no DEVMODEW passed in from above,
|
|
// use the default from the printer structure.
|
|
//
|
|
|
|
PDEVREF pr(lr,
|
|
(PDEVMODEW) pdriv,
|
|
pwszDevice,
|
|
((DRIVER_INFO_2W *)mDriverInfo)->pDataFile,
|
|
((DRIVER_INFO_2W *)mDriverInfo)->pName,
|
|
print.hSpooler(),
|
|
prton);
|
|
|
|
if (pr.bValid()) // PDEVREF logs error code.
|
|
{
|
|
//
|
|
// Make a note that this is a printer.
|
|
//
|
|
|
|
pr.bPrinter(TRUE);
|
|
|
|
//
|
|
// Allocate the DC, fill it with defaults.
|
|
//
|
|
|
|
hdc = hdcCreate(pr,iType,TRUE); // hdcCreate does pr.vKeepIt.
|
|
if (hdc != (HDC) 0)
|
|
{
|
|
print.vKeepIt();
|
|
}
|
|
}
|
|
}
|
|
VFREEMEM(mDriverInfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hdc == (HDC) NULL)
|
|
{
|
|
WARNING("opendc.cxx: failed to create DC in hdcOpenDCW\n");
|
|
}
|
|
|
|
return(hdc);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreResetDCInternal
|
|
*
|
|
* Reset the mode of a DC. The DC returned will be a different DC than
|
|
* the original. The only common piece between the original DC and the
|
|
* new one is the hSpooler.
|
|
*
|
|
* There are a number of intresting problems to be carefull of. The
|
|
* original DC can be an info DC. The new one will always be a direct DC.
|
|
*
|
|
* Also, it is important to be carefull of the state of the DC when this
|
|
* function is called and the effects of journaling vs non journaling.
|
|
* In the case of journaling, the spooler is responsible for doing a CreateDC
|
|
* to play the journal file to. For this reason, the spooler must have the
|
|
* current DEVMODE. For this reason, ResetDC must call ResetPrinter for
|
|
* spooled DC's.
|
|
*
|
|
* ResetDC can happen at any time other than between StartPage-EndPage, even
|
|
* before StartDoc.
|
|
*
|
|
*
|
|
* History:
|
|
* 13-Jan-1994 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" BOOL GreResetDCInternal(
|
|
HDC hdc,
|
|
DEVMODEW *pdmw, // Driver data.
|
|
BOOL *pbBanding )
|
|
{
|
|
BOOL bSurf;
|
|
BOOL bTempInfoDC = FALSE;
|
|
HDC hdcNew;
|
|
BOOL bRet = FALSE;
|
|
|
|
// we need this set of brackets so the DC's get unlocked before we try to delete
|
|
// the dc>
|
|
|
|
{
|
|
DCOBJ dco(hdc);
|
|
|
|
if (!dco.bValid())
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
}
|
|
else
|
|
{
|
|
// if this has been made into a TempInfoDC for printing, undo it now
|
|
|
|
bTempInfoDC = dco.pdc->bTempInfoDC();
|
|
|
|
if (bTempInfoDC)
|
|
dco.pdc->bMakeInfoDC(FALSE);
|
|
|
|
PDEVOBJ po(dco.hdev());
|
|
|
|
// get list of Type1 remote type one fonts if there is one and transfer
|
|
// it accross PDEV's.
|
|
|
|
PREMOTETYPEONENODE prton = po.RemoteTypeOneGet();
|
|
po.RemoteTypeOneSet(NULL);
|
|
|
|
// This call only makes sense on RASTER technology printers.
|
|
|
|
if (!dco.bKillReset() &&
|
|
!(dco.dctp() == DCTYPE_MEMORY) &&
|
|
(po.GdiInfo()->ulTechnology == DT_RASPRINTER))
|
|
{
|
|
// First, remember if a surface needs to be created
|
|
|
|
bSurf = dco.bHasSurface();
|
|
|
|
// Now, clean up the DC
|
|
|
|
if (dco.bCleanDC())
|
|
{
|
|
// If there are any outstanding references to this PDEV, fail.
|
|
|
|
if (((PDEV *) po.hdev())->cPdevRefs == 1)
|
|
{
|
|
// create the new DC
|
|
|
|
hdcNew = hdcOpenDCW(L"",
|
|
pdmw,
|
|
DCTYPE_DIRECT,
|
|
po.hSpooler(),
|
|
prton);
|
|
|
|
if (hdcNew)
|
|
{
|
|
// don't want to delete the spooler handle since it
|
|
// is in the new DC
|
|
|
|
po.hSpooler(NULL);
|
|
|
|
// lock down the new DC and PDEV
|
|
|
|
DCOBJ dcoNew(hdcNew);
|
|
|
|
if (!dcoNew.bValid())
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
}
|
|
else
|
|
{
|
|
// Transfer any remote fonts
|
|
|
|
dcoNew.PFFListSet(dco.PFFListGet());
|
|
dco.PFFListSet(NULL);
|
|
|
|
PDEVOBJ poNew((HDEV) dcoNew.pdc->ppdev());
|
|
|
|
// let the driver know
|
|
|
|
PFN_DrvResetPDEV rfn = PPFNDRV(po,ResetPDEV);
|
|
|
|
if (rfn != NULL)
|
|
{
|
|
(*rfn)(po.dhpdev(),poNew.dhpdev());
|
|
}
|
|
|
|
// now swap the two handles
|
|
|
|
{
|
|
MLOCKFAST mlo;
|
|
|
|
BOOL bRes = HmgSwapLockedHandleContents((HOBJ)hdc,0,(HOBJ)hdcNew,0,DC_TYPE);
|
|
ASSERTGDI(bRes,"GreResetDC - SwapHandleContents failed\n");
|
|
}
|
|
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// DON'T DO ANYTHING HERE, the dcobj's don't match the handles, so
|
|
// unlock them first
|
|
}
|
|
|
|
if (bRet)
|
|
{
|
|
// got a new dc, get rid of the old one (remember the handles have
|
|
// been swapped)
|
|
|
|
bDeleteDCInternal(hdcNew,TRUE,FALSE);
|
|
|
|
// now deal with the new one
|
|
|
|
DCOBJ newdco(hdc);
|
|
|
|
if (!newdco.bValid())
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
bRet = FALSE;
|
|
}
|
|
else
|
|
{
|
|
PDEVOBJ newpo(newdco.hdev());
|
|
|
|
// Create a new surface for the DC.
|
|
|
|
if (bSurf)
|
|
{
|
|
if (!newpo.bMakeSurface())
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
else
|
|
{
|
|
newdco.pdc->pSurface(newpo.pSurface());
|
|
*pbBanding = newpo.pSurface()->bBanding();
|
|
|
|
if( *pbBanding )
|
|
{
|
|
// if banding set Clip rectangle to size of band
|
|
|
|
newdco.pdc->sizl((newpo.pSurface())->sizl());
|
|
newdco.pdc->bSetDefaultRegion();
|
|
}
|
|
|
|
PFN_DrvStartDoc pfnDrvStartDoc = PPFNDRV(newpo, StartDoc);
|
|
(*pfnDrvStartDoc)(newpo.pSurface()->pSurfobj(),NULL,0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// important to set this to FALSE is a surface has not yet been created
|
|
// ie StartDoc has not yet been called.
|
|
*pbBanding = FALSE;
|
|
}
|
|
|
|
// if the original was a tempinfo dc for printing, this one needs to be too.
|
|
|
|
if (bRet && bTempInfoDC)
|
|
{
|
|
newdco.pdc->bMakeInfoDC(TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bMatchEnoughForDynamicModeChange
|
|
*
|
|
* We can dynamically change modes only if the new mode matches the old
|
|
* in certain respects. This is because, for example, we don't have code
|
|
* written to track down all the places where flGraphicsCaps has been copied,
|
|
* and then change it asynchronously.
|
|
*
|
|
* History:
|
|
* 8-Feb-1996 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bMatchEnoughForDynamicModeChange(
|
|
PDEVOBJ& po,
|
|
DEVMODEW* pdm,
|
|
GDIINFO* pGdiInfoNew,
|
|
GDIINFO* pGdiInfoOld,
|
|
DEVINFO* pdevinfoNew,
|
|
DEVINFO* pdevinfoOld
|
|
)
|
|
{
|
|
BOOL b = TRUE;
|
|
|
|
// Make sure the new mode's colour depth is what we setup for:
|
|
|
|
if (pGdiInfoNew->cBitsPixel != pdm->dmBitsPerPel)
|
|
{
|
|
WARNING("bMatchEnoughForDynamicModeChange: Unexpected colour depth\n");
|
|
b = FALSE;
|
|
}
|
|
|
|
if (pGdiInfoNew->cBitsPixel != pGdiInfoOld->cBitsPixel)
|
|
{
|
|
// We may need to call the driver's DrvDitherColor function to
|
|
// dither at 8bpp even when the driver is no longer at 8bpp, to
|
|
// get the correct results with 8bpp DFBs. Because DrvDitherColor
|
|
// does not take a pixel depth, we ensure that the driver will
|
|
// expect only 8bpp dithers by verifying that it does not set
|
|
// GCAPS_COLORDITHER at any mode other than 8bpp:
|
|
|
|
if ((pGdiInfoNew->cBitsPixel == 8) &&
|
|
!(pdevinfoNew->flGraphicsCaps & GCAPS_COLOR_DITHER))
|
|
{
|
|
WARNING("bMatchEnoughForDynamicModeChange: Expect driver to set GCAPS_COLORDITHER at 8bpp\n");
|
|
b = FALSE;
|
|
}
|
|
else if ((pGdiInfoNew->cBitsPixel != 8) &&
|
|
(pdevinfoNew->flGraphicsCaps & GCAPS_COLOR_DITHER))
|
|
{
|
|
WARNING("bMatchEnoughForDynamicModeChange: Expect driver not to set GCAPS_COLORDITHER when not at 8bpp\n");
|
|
b = FALSE;
|
|
}
|
|
}
|
|
|
|
// Some random stuff must be the same between the old instance and
|
|
// the new:
|
|
//
|
|
// We impose the restriction that flGraphicsCaps must stay the same
|
|
// except for those GCAPS flags that we have specifically verified
|
|
// may be updated with no ill-effects. Some ones we've specifically
|
|
// can't do:
|
|
//
|
|
// o We don't allow GCAPS_BEZIERS to change because the font code
|
|
// cache.cxx may have cached Bezier paths, and we would have to
|
|
// invalidate them.
|
|
//
|
|
// o We don't allow GCAPS_ASYNCMOVE to change because GreMovePointer
|
|
// has to check the flag before deciding which locks to acquire.
|
|
//
|
|
// o We don't allow GCAPS_HIGHRESTEXT to change because ESTROBJ::
|
|
// vInit needs to look at it.
|
|
//
|
|
// o We don't check GCAPS_NO64BITMEMACCESS because I'm too lazy to
|
|
// add code for the unlikely event where a Mips driver changes the
|
|
// status of this depending on the mode.
|
|
|
|
if ((pdevinfoNew->flGraphicsCaps ^ pdevinfoOld->flGraphicsCaps)
|
|
& (GCAPS_BEZIERS |
|
|
GCAPS_ASYNCMOVE |
|
|
GCAPS_HIGHRESTEXT |
|
|
GCAPS_NO64BITMEMACCESS))
|
|
{
|
|
WARNING("bMatchEnoughForDynamicModeChange: Driver's flGraphicsCaps did not sufficiently match\n");
|
|
b = FALSE;
|
|
}
|
|
|
|
if ((pGdiInfoNew->ulLogPixelsX != pGdiInfoOld->ulLogPixelsX) ||
|
|
(pGdiInfoNew->ulLogPixelsY != pGdiInfoOld->ulLogPixelsY))
|
|
{
|
|
WARNING("bMatchEnoughForDynamicModeChange: Driver's ulLogPixels did not match\n");
|
|
b = FALSE;
|
|
}
|
|
|
|
// We can't handle font producers because I haven't bothered with
|
|
// code to traverse the font code's producer lists and Do The Right
|
|
// Thing (appropriate locks are the biggest pain). Fortunately,
|
|
// font producing video drivers should be extremely rare.
|
|
|
|
if (PPFNVALID(po, QueryFont))
|
|
{
|
|
WARNING("bMatchEnoughForDynamicModeChange: Driver can't be a font provider\n");
|
|
b = FALSE;
|
|
}
|
|
|
|
return(b);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vAssertNoDcHasOldSurface
|
|
*
|
|
* Some debug-only code to verify that the dynamic mode change was done
|
|
* properly.
|
|
*
|
|
* History:
|
|
* 8-Feb-1996 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
#if DBG
|
|
|
|
VOID
|
|
vAssertNoDcHasOldSurface(
|
|
SURFACE* pSurfaceOld,
|
|
BOOL bWait
|
|
)
|
|
{
|
|
HOBJ hobj;
|
|
DC* pdc;
|
|
LARGE_INTEGER ShortDelay;
|
|
|
|
// A danger is that we may not have properly updated all DC's with
|
|
// the new surface pointer (for example, because a new DC was in
|
|
// the process of being created -- something we should handle
|
|
// properly). So wait a second, then traverse all the DCs again to
|
|
// ensure that there is no pointer to the old surface hanging around.
|
|
|
|
if (bWait)
|
|
{
|
|
ShortDelay.LowPart = (ULONG) -10000000;
|
|
ShortDelay.HighPart = -1;
|
|
|
|
KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay);
|
|
}
|
|
|
|
hobj = 0;
|
|
while (pdc = (DC*) HmgSafeNextObjt(hobj, DC_TYPE))
|
|
{
|
|
hobj = (HOBJ) pdc->hGet();
|
|
|
|
if (pdc->pSurface() == pSurfaceOld)
|
|
{
|
|
KdPrint(("Bad pdc: %lx\n", pdc));
|
|
RIP("DynamicModeChange is incomplete!");
|
|
}
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
#define vAssertNoDcHasOldSurface(pSurfaceOld, bWait)
|
|
|
|
#endif
|
|
|
|
/******************************Public*Routine******************************\
|
|
* iBitmapFormat()
|
|
*
|
|
* Converts bits-per-pixel to iBitmapFormat. Returns 0 for an error.
|
|
*
|
|
* History:
|
|
* 8-Feb-1996 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
ULONG
|
|
iBitmapFormat(
|
|
ULONG cBitsPerPixel
|
|
)
|
|
{
|
|
ULONG iBitmapFormat;
|
|
|
|
if (cBitsPerPixel <= 1)
|
|
{
|
|
iBitmapFormat = BMF_1BPP;
|
|
}
|
|
else if (cBitsPerPixel <= 4)
|
|
{
|
|
iBitmapFormat = BMF_4BPP;
|
|
}
|
|
else if (cBitsPerPixel <= 8)
|
|
{
|
|
iBitmapFormat = BMF_8BPP;
|
|
}
|
|
else if (cBitsPerPixel <= 8)
|
|
{
|
|
iBitmapFormat = BMF_8BPP;
|
|
}
|
|
else if (cBitsPerPixel <= 16)
|
|
{
|
|
iBitmapFormat = BMF_16BPP;
|
|
}
|
|
else if (cBitsPerPixel <= 24)
|
|
{
|
|
iBitmapFormat = BMF_24BPP;
|
|
}
|
|
else if (cBitsPerPixel <= 32)
|
|
{
|
|
iBitmapFormat = BMF_32BPP;
|
|
}
|
|
else
|
|
{
|
|
iBitmapFormat = 0; // Error case
|
|
}
|
|
|
|
return(iBitmapFormat);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreDynamicModeChange
|
|
*
|
|
* Dynamically switches modes on a display device. The change is done
|
|
* by starting up a new instance of the display driver, and deleting the
|
|
* old. GDI's 'HDEV' and 'PDEV' stay the same; only the device's 'pSurface'
|
|
* and 'dhpdev' change.
|
|
*
|
|
* The caller is ChangeDisplaySettings in USER, which is reponsible for:
|
|
*
|
|
* o Calling us with a valid devmode of the same colour depth as the old;
|
|
* o Ensuring that the device is not currently in full-screen mode;
|
|
* o Invalidating all of its SaveScreenBits buffers;
|
|
* o Changing the VisRgn's on all DCs;
|
|
* o Resetting the pointer shape;
|
|
* o Sending the appropriate message to everyone;
|
|
* o Redrawing the desktop.
|
|
*
|
|
* Since CreateDC("DISPLAY") always gets mapped to GetDC(NULL), there are
|
|
* no DC's for which GDI is responsible for updating the VisRgn.
|
|
*
|
|
* Rules of This Routine
|
|
* ---------------------
|
|
*
|
|
* o An important precept is that no drawing by any threads to any
|
|
* application's bitmaps should be affected by this routine. This means,
|
|
* for example, that we cannot exclusive lock any DCs.
|
|
*
|
|
* o While we keep GDI's 'HDEV' and 'PDEV' in place, we do have to modify
|
|
* fields like 'dhpdev' and 'pSurface'. Because we also have to update
|
|
* copies of these fields that are stashed in DC's, it means that *all*
|
|
* accesses to mode-dependent fields such as 'dhpdev,' 'pSurface,' and
|
|
* 'sizl' must be protected by holding a resource that this routine
|
|
* acquires -- such as the devlock or handle-manager lock.
|
|
*
|
|
* o If the function fails for whatever reason, the mode MUST be restored
|
|
* back to its original state.
|
|
*
|
|
* History:
|
|
* 8-Feb-1996 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
ULONG gcModeChanges = 0; // Handy debugging information
|
|
|
|
BOOL
|
|
GreDynamicModeChange(
|
|
HDEV hdev,
|
|
HANDLE hDriver, // physinfo->pDeviceHandle in USER
|
|
DEVMODEW* pdm
|
|
)
|
|
{
|
|
BOOL bConversionSuccessful;
|
|
HSURF ahsurf[HS_DDI_MAX]; // HS_DDI_MAX is currently '6'
|
|
GDIINFO GdiInfoNew;
|
|
DEVINFO devinfoNew;
|
|
DHPDEV dhpdevOld;
|
|
DHPDEV dhpdevNew;
|
|
SURFACE* pSurfaceOld;
|
|
SURFACE* pSurfaceNew;
|
|
PALETTE* ppalOld;
|
|
PALETTE* ppalNew;
|
|
ULONG cBitsPixelOld;
|
|
ULONG cBitsPixelNew;
|
|
ULONG iBitmapFormatOld;
|
|
ULONG iBitmapFormatNew;
|
|
HSURF hsurfNew;
|
|
SIZEL sizlOld;
|
|
SIZEL sizlNew;
|
|
PDEV* ppdev;
|
|
SURFACE* pSurface; // Temporary surface pointer
|
|
RFONT* prfnt; // Temporary RFONT pointer
|
|
FONTOBJ* pfo; // Temporary FONTOBJ pointer
|
|
DC* pdc; // Temporary DC pointer
|
|
BRUSH* pbrush; // Temporary BRUSH pointer
|
|
HOBJ hobj; // Temporary object handle
|
|
PFN_DrvResetPDEV pfnDrvResetPDEV;
|
|
PFN_DrvDestroyFont pfnDrvDestroyFont;
|
|
BOOL bPermitModeChange;
|
|
LONG lSaveDepth;
|
|
HDC hdcSave;
|
|
BOOL bGoodPalette;
|
|
BOOL bHintCreated;
|
|
BRUSH* pbrGrayPattern;
|
|
TRACKOBJ* pto;
|
|
EWNDOBJ* pwo;
|
|
|
|
PDEVOBJ po(hdev);
|
|
if (po.bDisabled())
|
|
return(FALSE);
|
|
|
|
cBitsPixelOld = po.GdiInfo()->cBitsPixel;
|
|
cBitsPixelNew = pdm->dmBitsPerPel;
|
|
|
|
if (cBitsPixelOld != cBitsPixelNew)
|
|
{
|
|
// We don't support dynamic colour depth changes to or from any
|
|
// modes below 8bpp (resolution changes are okay, though):
|
|
|
|
if ((cBitsPixelOld < BMF_8BPP) || (cBitsPixelNew < BMF_8BPP))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
gcModeChanges++;
|
|
|
|
// This call must not occur under the devlock. TRUE indicates the
|
|
// mode will be changing. It's okay to indicate here that the mode
|
|
// will be changing as it's no big deal if we still wind up failing
|
|
// GreDynamicModeChange.
|
|
|
|
GreDisableDirectDraw(hdev, TRUE);
|
|
|
|
// The following lock rules must be abided, otherwise deadlocks may
|
|
// arise:
|
|
//
|
|
// o Pointer lock must be acquired after Devlock (GreSetPointer);
|
|
// o RFont list lock must be acquired after Devlock (TextOut);
|
|
// o Handle manager lock must be acquired after Devlock (old
|
|
// CvtDFB2DIB);
|
|
// o Handle manager lock must be acquired after Palette Semaphore
|
|
// (GreSetPaletteEntries)
|
|
// o Palette Semaphore must be acquired after Devlock (BitBlt)
|
|
//
|
|
// So we acquire locks in the following order (note that the
|
|
// vAssertDynaLock() routines should be modified if this list ever
|
|
// changes):
|
|
//
|
|
// 1. Devlock;
|
|
// 3. Pointer lock;
|
|
// 2. Palette semaphore;
|
|
// 4. Handle manager lock or RFont list lock.
|
|
|
|
ppdev = (PDEV*) hdev;
|
|
|
|
DEVLOCKOBJ dlo(po); // No drawing to any dynamic surfaces
|
|
MUTEXOBJ mutP(po.pfmPointer()); // No asynchronous pointer moves
|
|
SEMOBJ semo(gpsemPalette); // No SaveDC/RestoreDC
|
|
|
|
ASSERTGDI(ppdev->pSurface != NULL, "Must be called on a completed PDEV");
|
|
ASSERTGDI(po.bDisplayPDEV(), "Must be called on a display PDEV");
|
|
ASSERTGDI((prgnDefault->cScans == 1) && (prgnDefault->rcl.right == 0),
|
|
"Someone changed prgnDefault; could cause driver access violations");
|
|
|
|
if ((po.pfnSync() != NULL) &&
|
|
(po.pSurface()->flags() & HOOK_SYNCHRONIZE))
|
|
{
|
|
(po.pfnSync())(po.dhpdev(), NULL);
|
|
}
|
|
|
|
// We'll have to fail if we can't disable the driver here:
|
|
|
|
if ((PPFNDRV(po, AssertMode) == NULL) ||
|
|
(PPFNDRV(po, AssertMode))(po.dhpdev(), FALSE))
|
|
{
|
|
// Now traverse all the device bitmaps associated with this device,
|
|
// and convert any driver-owned bitmaps to DIBs.
|
|
|
|
bConversionSuccessful = TRUE;
|
|
|
|
{
|
|
// Hold the handle manager lock while traversing the handle
|
|
// tables. Among other things, this protects us against
|
|
// having the bitmap selected into a different DC, and to
|
|
// not allow DC deletion.
|
|
//
|
|
// NOTE: Since we may be looking at fields in a surface
|
|
// as soon as it's allocated, all surfaces must either be
|
|
// zero initialized or completely initialized before the
|
|
// object gets inserted into the handle manager!
|
|
|
|
MLOCKFAST mo;
|
|
|
|
hobj = 0;
|
|
while (pSurface = (SURFACE*) HmgSafeNextObjt(hobj, SURF_TYPE))
|
|
{
|
|
// Retrieve the handle to the next surface before we delete
|
|
// the current one:
|
|
|
|
hobj = (HOBJ) pSurface->hGet();
|
|
|
|
if ((pSurface->hdev() == hdev) &&
|
|
(pSurface->iType() == STYPE_DEVBITMAP))
|
|
{
|
|
// The surface cannot be converted if there is any
|
|
// outstanding lock other than those done to select
|
|
// a bitmap into a DC. We can't very well go and de-
|
|
// allocate 'pSurface' while someone is looking at it.
|
|
//
|
|
// However, we really shouldn't fail a dynamic mode
|
|
// change if some thread somewhere in the system should
|
|
// happen to be doing a bitmap operation with a DFB.
|
|
// For that reason, wherever a surface is locked,
|
|
// we endeavour to hold either the dynamic mode change
|
|
// lock or the devlock -- and since at this very moment
|
|
// we have both, that should mean that these conversions
|
|
// will never fail due to lock issues.
|
|
|
|
if (pSurface->hdc() != 0)
|
|
{
|
|
MDCOBJA dco(pSurface->hdc()); // Alt-lock
|
|
|
|
ASSERTGDI(dco.bValid(), "Surface DC is invalid");
|
|
|
|
if (bConvertDfbDcToDib(&dco))
|
|
{
|
|
vAssertNoDcHasOldSurface(pSurface, FALSE);
|
|
}
|
|
else
|
|
{
|
|
WARNING("Failed DC surface conversion (possibly from low memory)\n");
|
|
bConversionSuccessful = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No-one should have a lock on the bitmap:
|
|
|
|
if (pConvertDfbSurfaceToDib(hdev, pSurface, 0))
|
|
{
|
|
vAssertNoDcHasOldSurface(pSurface, FALSE);
|
|
}
|
|
else
|
|
{
|
|
WARNING("Failed surface conversion (possibly from low memory)\n");
|
|
bConversionSuccessful = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// We are safe from new DFBs being created right now because we're
|
|
// holding the devlock.
|
|
|
|
if (bConversionSuccessful)
|
|
{
|
|
dhpdevOld = ppdev->dhpdev;
|
|
dhpdevNew = (*PPFNDRV(po,EnablePDEV)) (
|
|
pdm, // New DEVMODE
|
|
NULL, // Logical address
|
|
HS_DDI_MAX, // Count of standard patterns
|
|
ahsurf, // We'll keep using the GDI supplied
|
|
// bitmaps and ignore what the driver
|
|
// gives us
|
|
sizeof(GDIINFO),
|
|
&GdiInfoNew,
|
|
sizeof(DEVINFO),
|
|
&devinfoNew,
|
|
hdev,
|
|
NULL, // Device name
|
|
hDriver); // Kernel driver handle
|
|
|
|
if (dhpdevNew)
|
|
{
|
|
(*PPFNDRV(po,CompletePDEV))(dhpdevNew, po.hdev());
|
|
|
|
// During its DrvEnableSurface, the driver will call
|
|
// EngAssociate to associate its surface, and that
|
|
// looks at the dhpdev field in our PDEV, so modify it
|
|
// now:
|
|
|
|
ppdev->dhpdev = dhpdevNew;
|
|
|
|
hsurfNew = (*PPFNDRV(po, EnableSurface))(dhpdevNew);
|
|
|
|
if (hsurfNew)
|
|
{
|
|
SURFREF srNew(hsurfNew);
|
|
|
|
ASSERTGDI(srNew.bValid(),
|
|
"Driver returned bad DrvEnableSurface handle");
|
|
|
|
pSurfaceNew = srNew.ps;
|
|
pSurfaceOld = ppdev->pSurface;
|
|
|
|
// Copy GDI's private flags to the new surface:
|
|
|
|
pSurfaceNew->SurfFlags |= (pSurfaceOld->SurfFlags & SURF_FLAGS);
|
|
|
|
// Make sure that units are in MicroMeters for HorzSize, VertSize:
|
|
|
|
ASSERTGDI((LONG)GdiInfoNew.ulVertSize >= 0, "negative ulVertsize");
|
|
ASSERTGDI((LONG)GdiInfoNew.ulHorzSize >= 0, "negative ulHorzsize");
|
|
|
|
GdiInfoNew.ulHorzSize *= 1000;
|
|
GdiInfoNew.ulVertSize *= 1000;
|
|
|
|
GdiInfoNew.flRaster = flRaster(GdiInfoNew.ulTechnology,
|
|
devinfoNew.flGraphicsCaps);
|
|
|
|
// Get some pointers to the old and new palettes:
|
|
|
|
EPALOBJ palNew(devinfoNew.hpalDefault);
|
|
ASSERTGDI(palNew.bValid(), "hpalDefault invalid");
|
|
|
|
ppalOld = ppdev->ppalSurf;
|
|
ppalNew = palNew.ppalGet();
|
|
|
|
bGoodPalette = TRUE;
|
|
if (GdiInfoNew.flRaster & RC_PALETTE)
|
|
{
|
|
// If CreateSurfacePal succeeds, but then we fail
|
|
// later on in this call, we don't have to worry
|
|
// about freeing the ppalOriginal palette created --
|
|
// it will automatically be freed when the driver
|
|
// calls EngDeletePalette on its default palette,
|
|
// which then invokes vUnrefPalette().
|
|
|
|
bGoodPalette = CreateSurfacePal(palNew,
|
|
PAL_MANAGED,
|
|
GdiInfoNew.ulNumColors,
|
|
GdiInfoNew.ulNumPalReg);
|
|
}
|
|
|
|
if (bGoodPalette)
|
|
{
|
|
// Verify that only the resolution has changed:
|
|
|
|
if (bMatchEnoughForDynamicModeChange(po,
|
|
pdm,
|
|
&GdiInfoNew,
|
|
&ppdev->GdiInfo,
|
|
&devinfoNew,
|
|
&ppdev->devinfo))
|
|
{
|
|
bPermitModeChange = TRUE;
|
|
|
|
sizlNew.cx = GdiInfoNew.ulHorzRes;
|
|
sizlNew.cy = GdiInfoNew.ulVertRes;
|
|
sizlOld.cx = po.GdiInfo()->ulHorzRes;
|
|
sizlOld.cy = po.GdiInfo()->ulVertRes;
|
|
|
|
// It is critical that we must be able to update all VisRgns
|
|
// if the new mode is smaller than the old. If this did
|
|
// not happen, we could allow GDI calls to the driver that
|
|
// are outside the bounds of the visible display, and as
|
|
// a result the driver would quite likely fall over.
|
|
//
|
|
// We don't entrust USER to always take care of this case
|
|
// because it updates the VisRgns after it knows that
|
|
// GreDynamicModeChange was successful -- which is too late
|
|
// if the VisRgn change should fail because of low memory.
|
|
// It's acceptable in low memory situations to temporarily
|
|
// draw incorrectly as a result of a wrong VisRgn, but it
|
|
// is *not* acceptable to crash.
|
|
//
|
|
// Doing this here also means that USER doesn't have to call
|
|
// us while holding the Devlock.
|
|
|
|
if ((sizlNew.cx < sizlOld.cx) || (sizlNew.cy < sizlOld.cy))
|
|
{
|
|
MLOCKFAST mo;
|
|
|
|
hobj = 0;
|
|
while (pdc = (DC*) HmgSafeNextObjt(hobj, DC_TYPE))
|
|
{
|
|
hobj = (HOBJ) pdc->hGet();
|
|
|
|
if ((pdc->pSurface() == pSurfaceOld) &&
|
|
(pdc->prgnVis() != NULL))
|
|
{
|
|
if (!GreIntersectVisRect((HDC) hobj, 0, 0,
|
|
sizlNew.cx, sizlNew.cy))
|
|
{
|
|
WARNING("GreDynamicModeChange: Failed reseting VisRect!\n");
|
|
|
|
// Note that if we fail here, we may have already
|
|
// shrunk some VisRgn's. However, we should have only
|
|
// failed in a very low-memory situation, in which case
|
|
// there will be plenty of other drawing problems. The
|
|
// regions will likely all be reset back to the correct
|
|
// dimensions by the owning applications, eventually.
|
|
|
|
bPermitModeChange = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Finally, let the driver know about the mode switch.
|
|
// This has to be the last step because we are implicitly
|
|
// telling the driver that it can transfer data from the
|
|
// old instance to the new instance with the assurance
|
|
// that the new instance won't later be abandoned.
|
|
|
|
pfnDrvResetPDEV = PPFNDRV(po, ResetPDEV);
|
|
if (pfnDrvResetPDEV != NULL)
|
|
{
|
|
// The driver can refuse the mode switch if it wants:
|
|
|
|
if (bPermitModeChange)
|
|
{
|
|
bPermitModeChange = pfnDrvResetPDEV(dhpdevOld, dhpdevNew);
|
|
}
|
|
}
|
|
|
|
if (bPermitModeChange)
|
|
{
|
|
// Now get rid of any font caches that the old instance
|
|
// of the driver may have.
|
|
//
|
|
// We're protected against having bDeleteRFONT call the
|
|
// driver at the same time because it has to grab the
|
|
// Devlock, and we're already holding it.
|
|
|
|
pfnDrvDestroyFont = PPFNDRV(po, DestroyFont);
|
|
if (pfnDrvDestroyFont != NULL)
|
|
{
|
|
// We must hold the RFONT list semaphore while we
|
|
// traverse the RFONT list. To avoid deadlocks,
|
|
// we have to acquire this while holding the
|
|
// devlock:
|
|
|
|
SEMOBJ so(gpsemRFONTList);
|
|
|
|
for (prfnt = ppdev->prfntInactive;
|
|
prfnt != NULL;
|
|
prfnt = prfnt->rflPDEV.prfntNext)
|
|
{
|
|
pfo = &prfnt->fobj;
|
|
pfnDrvDestroyFont(pfo);
|
|
pfo->pvConsumer = NULL;
|
|
}
|
|
|
|
for (prfnt = ppdev->prfntActive;
|
|
prfnt != NULL;
|
|
prfnt = prfnt->rflPDEV.prfntNext)
|
|
{
|
|
pfo = &prfnt->fobj;
|
|
pfnDrvDestroyFont(pfo);
|
|
pfo->pvConsumer = NULL;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
// At this point, we're committed to the mode change.
|
|
// Nothing below this point can be allowed to fail.
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
// Hold the handle manager lock while we traverse
|
|
// all our objects and update all our internal data
|
|
// structures. It also prevents a surface from
|
|
// being selected into a DC while we're traversing
|
|
// the DC's.
|
|
|
|
MLOCKFAST mo; // Also locks out miscellaneous stuff
|
|
|
|
// Traverse all DC's and update their surface
|
|
// information if they're associated with this
|
|
// device.
|
|
//
|
|
// Note that bDeleteDCInternal wipes some fields in
|
|
// the DC via bCleanDC before freeing the DC, but
|
|
// this is okay since the worst we'll do is update
|
|
// some fields just before the DC gets deleted.
|
|
|
|
hobj = 0;
|
|
while (pdc = (DC*) HmgSafeNextObjt(hobj, DC_TYPE))
|
|
{
|
|
hobj = (HOBJ) pdc->hGet();
|
|
|
|
if (pdc->pSurface() == pSurfaceOld)
|
|
{
|
|
// Note that we don't check that pdev->hdev()
|
|
// == hdev because the SaveDC stuff doesn't
|
|
// bother copying the hdev, but DOES copy the
|
|
// dclevel.
|
|
|
|
pdc->pSurface(pSurfaceNew);
|
|
pdc->sizl(sizlNew);
|
|
|
|
// Note that 'flbrushAdd()' is not an atomic
|
|
// operation. However, since we're holding
|
|
// the devlock and the palette lock, there
|
|
// shouldn't be any other threads alt-
|
|
// locking our DC and modifying these fields
|
|
// at the same time:
|
|
|
|
pdc->flbrushAdd(DIRTY_BRUSHES);
|
|
}
|
|
|
|
if (pdc->dhpdev() == dhpdevOld)
|
|
{
|
|
pdc->dhpdev(dhpdevNew);
|
|
pdc->flGraphicsCaps(devinfoNew.flGraphicsCaps);
|
|
}
|
|
}
|
|
|
|
// Make it so that any brush realizations are
|
|
// invalidated, because we don't want a new
|
|
// instance of the driver trying to use old
|
|
// instance 'pvRbrush' data.
|
|
//
|
|
// This also takes care of invalidating the
|
|
// brushes for all the DDB to DIB conversions.
|
|
//
|
|
// Note that we're actually invalidating the
|
|
// caches of all brushes in the system, because
|
|
// we don't store any 'hdev' information with
|
|
// the brush. Because dynamic mode changes
|
|
// should be relatively infrequent, and because
|
|
// realizations are reasonably cheap, I don't
|
|
// expect this to be a big hit.
|
|
|
|
hobj = 0;
|
|
while (pbrush = (BRUSH*) HmgSafeNextObjt(hobj, BRUSH_TYPE))
|
|
{
|
|
hobj = (HOBJ) pbrush->hGet();
|
|
|
|
// Mark as dirty by setting the cache ID to
|
|
// an invalid state.
|
|
|
|
pbrush->ulSurfTime((ULONG) -1);
|
|
|
|
// Set the uniqueness so the are-you-really-
|
|
// dirty check in vInitBrush will not think
|
|
// an old realization is still valid.
|
|
|
|
pbrush->ulBrushUnique(pbrush->ulGlobalBrushUnique());
|
|
}
|
|
|
|
vAssertNoDcHasOldSurface(pSurfaceOld, TRUE);
|
|
|
|
hobj = 0;
|
|
while (pSurface = (SURFACE*) HmgSafeNextObjt(hobj, SURF_TYPE))
|
|
{
|
|
hobj = (HOBJ) pSurface->hGet();
|
|
|
|
// Device Independent Bitmaps (DIBs) are great when switching
|
|
// colour depths because, by virtue of their attached colour
|
|
// table (also known as a 'palette'), they Just Work at any
|
|
// colour depth.
|
|
//
|
|
// Device Dependent Bitmaps (DDBs) are more problematic.
|
|
// They implicitly share their palette with the display --
|
|
// meaning that if the display's palette is dynamically
|
|
// changed, the old DDBs will not work. We get around this
|
|
// by dynamically creating palettes to convert them to DIBs.
|
|
// Unfortunately, at palettized 8bpp we sometimes have to
|
|
// guess at what the appropriate palette would be. For this
|
|
// reason, whenever we switch back to 8bpp we make sure we
|
|
// convert them back to DDBs by removing their palettes.
|
|
|
|
if ((cBitsPixelOld != cBitsPixelNew) &&
|
|
(pSurface->iType() == STYPE_BITMAP) &&
|
|
(pSurface->iFormat() == iBitmapFormat(cBitsPixelOld)) &&
|
|
((pSurface->hdev() == hdev) || (pSurface->hdev() == 0)))
|
|
{
|
|
// Device Format Bitmaps (DFBs) are DDBs that are created
|
|
// via CreateCompatibleBitmap, and so we know what device
|
|
// they're associated with.
|
|
//
|
|
// Unfortunately, non-DFB DDBs (created via CreateBitmap
|
|
// or CreateDiscardableBitmap) have no device assocation
|
|
// -- so we don't know whether or not they're really
|
|
// associated with the display.
|
|
//
|
|
// We'll simply assume any non-DFB DDBs are intended for
|
|
// the display, and add a palette to them. Non-DFB DDBs
|
|
// are pretty rare, and we're not actually changing the
|
|
// contents of the bits, just the palette, so this will
|
|
// usually be okay.
|
|
//
|
|
// Note that DFBs are synchronized by the Devlock, and
|
|
// we don't need a lock to change the palette for a
|
|
// non-DFB DDB (see PALETTE_SELECT_SET logic).
|
|
|
|
if (pSurface->ppal() == NULL)
|
|
{
|
|
// Mark the surface to note that we added a palette:
|
|
|
|
pSurface->vSetDynamicModePalette();
|
|
|
|
if (ppdev->GdiInfo.flRaster & RC_PALETTE)
|
|
{
|
|
bHintCreated = FALSE;
|
|
if (pSurface->hpalHint() != 0)
|
|
{
|
|
EPALOBJ palDC(pSurface->hpalHint());
|
|
if ((palDC.bValid()) &&
|
|
(palDC.bIsPalDC()) &&
|
|
(!palDC.bIsPalDefault()) &&
|
|
(palDC.ptransFore() != NULL))
|
|
{
|
|
PALMEMOBJ palPerm;
|
|
XEPALOBJ palSurf(ppalOld);
|
|
|
|
if (palPerm.bCreatePalette(PAL_INDEXED,
|
|
256,
|
|
(ULONG*) palSurf.apalColorGet(),
|
|
0,
|
|
0,
|
|
0,
|
|
PAL_FREE))
|
|
{
|
|
ULONG nPhysChanged = 0;
|
|
ULONG nTransChanged = 0;
|
|
|
|
palPerm.ulNumReserved(palSurf.ulNumReserved());
|
|
|
|
bHintCreated = TRUE;
|
|
vMatchAPal(NULL,
|
|
palPerm,
|
|
palDC,
|
|
&nPhysChanged,
|
|
&nTransChanged);
|
|
|
|
palPerm.vKeepIt();
|
|
pSurface->ppal(palPerm.ppalGet());
|
|
|
|
// Keep a reference active:
|
|
|
|
palPerm.ppalSet(NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bHintCreated)
|
|
{
|
|
INC_SHARE_REF_CNT(ppalDefaultSurface8bpp);
|
|
pSurface->ppal(ppalDefaultSurface8bpp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
INC_SHARE_REF_CNT(ppalOld);
|
|
pSurface->ppal(ppalOld);
|
|
}
|
|
}
|
|
else if ((pSurface->ppal() == ppalOld) &&
|
|
(pSurface->flags() & PALETTE_SELECT_SET))
|
|
{
|
|
ASSERTGDI((pSurface->hdc() != 0) &&
|
|
(pSurface->cRef() != 0),
|
|
"Expected bitmap to be selected into a DC");
|
|
|
|
INC_SHARE_REF_CNT(pSurface->ppal());
|
|
pSurface->flags(pSurface->flags() & ~PALETTE_SELECT_SET);
|
|
}
|
|
}
|
|
|
|
// When switching back to palettized 8bpp, remove any
|
|
// palettes we had to add to 8bpp DDBs:
|
|
|
|
if ((GdiInfoNew.flRaster & RC_PALETTE) &&
|
|
(cBitsPixelOld != 8))
|
|
{
|
|
if (pSurface->bDynamicModePalette())
|
|
{
|
|
ASSERTGDI(pSurface->ppal() != NULL,
|
|
"Should be a palette here");
|
|
|
|
XEPALOBJ pal(pSurface->ppal());
|
|
pal.vUnrefPalette();
|
|
|
|
pSurface->vClearDynamicModePalette();
|
|
pSurface->ppal(NULL);
|
|
}
|
|
}
|
|
|
|
// For special DirectDraw DIBSections, transfer the
|
|
// ownership of the colour table to the new palette.
|
|
|
|
if (pSurface->bDIBSection())
|
|
{
|
|
XEPALOBJ pal(pSurface->ppal());
|
|
|
|
if ((pal.bValid()) && (pal.ppalColor() == ppalOld))
|
|
{
|
|
pal.apalColorSet(ppalNew);
|
|
|
|
// The new palette may be something other than 8bpp.
|
|
// This DIBSection will be meaningless until we return
|
|
// to the original mode, but we need to do something
|
|
// with the colour table in the mean-time so that we
|
|
// wouldn't access violate if we were asked to draw
|
|
// on it. So simply point it back to its own colour
|
|
// table:
|
|
|
|
if (cBitsPixelNew != 8)
|
|
{
|
|
// This does not transfer ownership:
|
|
|
|
pal.apalResetColorTable();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update the PDEV and primary surface:
|
|
|
|
ppdev->ppalSurf = ppalNew;
|
|
pSurfaceNew->ppal(ppalNew);
|
|
|
|
// Keep two corresponding locks on the palette:
|
|
|
|
INC_SHARE_REF_CNT(ppalNew);
|
|
palNew.ppalSet(NULL);
|
|
|
|
// Undo the PDEV's reference to the old palette.
|
|
// The old surface's reference will be removed
|
|
// when the driver calls EngDeleteSurface, and
|
|
// it will be deleted when the driver calls
|
|
// EngDeletePalette.
|
|
//
|
|
// Note that there may still be active references
|
|
// to the old primary surface's palette via device
|
|
// dependent bitmaps created at RGB colour depths.
|
|
// If this is the case, the surface palette won't be
|
|
// deleted when the driver calls EngDeletePalette,
|
|
// but will be automatically deleted when the last
|
|
// DDB with this palette is deleted.
|
|
|
|
DEC_SHARE_REF_CNT(ppalOld);
|
|
|
|
// We must disable the halftone device information when
|
|
// changing colour depths because the GDIINFO data it was
|
|
// constructed with are no longer valid. It is always
|
|
// enabled lazily, so there's no need to reenable it here:
|
|
|
|
if ((cBitsPixelOld != cBitsPixelNew) &&
|
|
(ppdev->pDevHTInfo != NULL))
|
|
{
|
|
po.bDisableHalftone();
|
|
}
|
|
|
|
// Re-realize the gray pattern brush which is used for drag
|
|
// rectangles:
|
|
|
|
pbrGrayPattern = (BRUSH*) HmgShareLock((HOBJ)ghbrGrayPattern,
|
|
BRUSH_TYPE);
|
|
|
|
po.pbo()->vInitBrush(pbrGrayPattern,
|
|
0,
|
|
0x00FFFFFF,
|
|
(XEPALOBJ) ppalDefault,
|
|
(XEPALOBJ) ppalNew,
|
|
pSurfaceNew);
|
|
|
|
DEC_SHARE_REF_CNT(pbrGrayPattern);
|
|
|
|
// Switch the WNDOBJs, if any, to the new surface:
|
|
|
|
{
|
|
SEMOBJ so(gpsemWndobj);
|
|
|
|
pSurfaceNew->pwo(pSurfaceOld->pwo());
|
|
pSurfaceOld->pwo(NULL);
|
|
|
|
for (pto = gpto; pto != NULL; pto = pto->ptoNext)
|
|
{
|
|
if (pto->pSurface == pSurfaceOld)
|
|
{
|
|
pto->pSurface = pSurfaceNew;
|
|
|
|
if (pto->pwoSurf)
|
|
{
|
|
ASSERTGDI(pto->pwoSurf->psoOwner == pSurfaceOld->pSurfobj(),
|
|
"Expected surface WNDOBJ to match TRACKOBJ");
|
|
|
|
pto->pwoSurf->psoOwner = pSurfaceNew->pSurfobj();
|
|
}
|
|
|
|
for (pwo = pto->pwo; pwo != NULL; pwo = pwo->pwoNext)
|
|
{
|
|
ASSERTGDI(pwo->psoOwner == pSurfaceOld->pSurfobj(),
|
|
"Expected WNDOBJ to match TRACKOBJ");
|
|
|
|
pwo->psoOwner = pSurfaceNew->pSurfobj();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
// Update all our PDEV fields:
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
srNew.vKeepIt();
|
|
|
|
ppdev->pSurface = pSurfaceNew;
|
|
ppdev->GdiInfo = GdiInfoNew;
|
|
ppdev->devinfo = devinfoNew;
|
|
|
|
// Update the magic colours in the surface palette:
|
|
|
|
vResetSurfacePalette(hdev);
|
|
|
|
// Update the GetDeviceCaps for this DC:
|
|
|
|
GreUpdateSharedDevCaps(hdev);
|
|
|
|
// Allow DirectDraw to be started up again:
|
|
|
|
GreEnableDirectDraw(hdev);
|
|
|
|
// Remove our reference to the old surface so that
|
|
// the driver can delete it:
|
|
|
|
SURFREF srOld(pSurfaceOld);
|
|
|
|
srOld.vUnreference();
|
|
|
|
// Finally, call the driver to delete its old
|
|
// instance:
|
|
|
|
(*PPFNDRV(po, DisableSurface))(dhpdevOld);
|
|
|
|
(*PPFNDRV(po, DisablePDEV))(dhpdevOld);
|
|
|
|
return(TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
(*PPFNDRV(po, DisableSurface))(dhpdevNew);
|
|
}
|
|
|
|
(*PPFNDRV(po, DisablePDEV))(dhpdevNew);
|
|
|
|
ppdev->dhpdev = dhpdevOld;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("GreDynamicModeChange: couldn't convert DFBs\n");
|
|
}
|
|
|
|
// Reenable the display:
|
|
|
|
if (PPFNDRV(po, AssertMode) != NULL)
|
|
{
|
|
// As modeled after bEnableDisplay, we repeat the call
|
|
// until it works:
|
|
|
|
while (!PPFNDRV(po, AssertMode)(po.dhpdev(), TRUE))
|
|
;
|
|
}
|
|
|
|
if (po.bIsPalManaged())
|
|
{
|
|
XEPALOBJ pal(po.ppalSurf());
|
|
(*PPFNDRV(po, SetPalette))(po.dhpdev(),
|
|
(PALOBJ*) &pal,
|
|
0,
|
|
0,
|
|
pal.cEntries());
|
|
}
|
|
}
|
|
|
|
GreEnableDirectDraw(hdev);
|
|
|
|
WARNING("GreDynamicModeChange: failed\n");
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreGetDriverModes (pwszDriver,hDriver,cjSize,pdm)
|
|
*
|
|
* Loads the device driver long enough to pass the DrvGetModes call to it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG
|
|
GreGetDriverModes(
|
|
PWSZ pwszDriver,
|
|
HANDLE hDriver,
|
|
ULONG cjSize,
|
|
DEVMODEW *pdm
|
|
)
|
|
{
|
|
ULONG ulRet = 0;
|
|
|
|
TRACE_INIT(("GreGetDriverModes: Entering\n"));
|
|
|
|
//
|
|
// Temporarily locate and load the driver.
|
|
//
|
|
|
|
LDEVREF lr(pwszDriver, LDEV_DEVICE_DISPLAY);
|
|
|
|
//
|
|
// Log an error if we can't load it.
|
|
//
|
|
|
|
if (lr.bValid())
|
|
{
|
|
//
|
|
// Locate the function and call it.
|
|
//
|
|
|
|
PFN_DrvGetModes pfn = PFNDRV(lr,GetModes);
|
|
|
|
if (pfn != (PFN_DrvGetModes) NULL)
|
|
{
|
|
ulRet = (*pfn)(hDriver,cjSize,pdm);
|
|
}
|
|
}
|
|
|
|
#define MAPDEVMODE_FLAGS (DM_BITSPERPEL | DM_PELSWIDTH | \
|
|
DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS)
|
|
|
|
if (ulRet)
|
|
{
|
|
if ((pdm->dmFields & MAPDEVMODE_FLAGS) != MAPDEVMODE_FLAGS)
|
|
{
|
|
ASSERTGDI(FALSE,"DrvGetModes did not set the dmFields value!\n");
|
|
ulRet = 0;
|
|
}
|
|
}
|
|
|
|
TRACE_INIT(("GreGetDriverModes: Leaving\n"));
|
|
|
|
//
|
|
// Return the driver's result.
|
|
//
|
|
|
|
return(ulRet);
|
|
}
|
|
|
|
/******************************Exported*Routine****************************\
|
|
* bDisableDisplay(hdev)
|
|
*
|
|
* Disables I/O for the specified device
|
|
*
|
|
* hdev
|
|
*
|
|
* Identifies device to be disabled
|
|
*
|
|
* Error returns:
|
|
*
|
|
* FALSE if the device could not be disabled
|
|
*
|
|
* History:
|
|
* 29-Jan-1992 -by- Donald Sidoroff [donalds]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
ULONG gtmpAssertModeFailed;
|
|
|
|
BOOL bDisableDisplay(HDEV hdev)
|
|
{
|
|
TRACE_INIT(("bDisableDisplay\n"));
|
|
|
|
PDEVOBJ po(hdev);
|
|
|
|
if (!po.bValid())
|
|
return(FALSE);
|
|
|
|
//
|
|
// If this is not a DISPLAY, return error.
|
|
//
|
|
|
|
if (!po.bDisplayPDEV())
|
|
return(FALSE);
|
|
|
|
//
|
|
// Disable DirectDraw. FALSE means we didn't change the graphics mode
|
|
// from what it was before.
|
|
//
|
|
|
|
GreDisableDirectDraw(hdev, FALSE);
|
|
|
|
//
|
|
// Wait for the display to become available and lock it.
|
|
//
|
|
|
|
VACQUIREDEVLOCK(po.pDevLock());
|
|
{
|
|
MUTEXOBJ mutP(po.pfmPointer());
|
|
|
|
//
|
|
// The device may have something going on, synchronize with it first
|
|
//
|
|
|
|
if (po.pfnSync() != NULL)
|
|
{
|
|
if (po.pSurface()->flags() & HOOK_SYNCHRONIZE)
|
|
{
|
|
(po.pfnSync())(po.dhpdev(),NULL);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Mark the PDEV as disabled
|
|
//
|
|
|
|
po.bDisabled(TRUE);
|
|
|
|
//
|
|
// Disable the screen
|
|
// Repeat the call until it works.
|
|
//
|
|
|
|
gtmpAssertModeFailed = 0;
|
|
while (!((*PPFNDRV(po,AssertMode))(po.dhpdev(), FALSE)))
|
|
{
|
|
gtmpAssertModeFailed = 1;
|
|
}
|
|
}
|
|
VRELEASEDEVLOCK(po.pDevLock());
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Exported*Routine****************************\
|
|
* vEnableDisplay(hdev)
|
|
*
|
|
* Enables I/O for the specified device
|
|
*
|
|
* hdev
|
|
*
|
|
* Identifies device to be disabled
|
|
*
|
|
* History:
|
|
* Tue 15-Sep-1992 -by- Patrick Haluptzok [patrickh]
|
|
* Re-enable palette for palette managed devices.
|
|
*
|
|
* 29-Jan-1992 -by- Donald Sidoroff [donalds]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vEnableDisplay(HDEV hdev)
|
|
{
|
|
TRACE_INIT(("vEnableDisplay\n"));
|
|
|
|
PDEVOBJ po(hdev);
|
|
|
|
ASSERTGDI(po.bValid(), "HDEV failure\n");
|
|
ASSERTGDI(po.bDisplayPDEV(), "HDEV is not a display device\n");
|
|
|
|
//
|
|
// Wait for the display to become available and unlock it.
|
|
//
|
|
|
|
VACQUIREDEVLOCK(po.pDevLock());
|
|
{
|
|
MUTEXOBJ mutP(po.pfmPointer());
|
|
|
|
//
|
|
// Enable the screen
|
|
// Repeat the call until it works.
|
|
//
|
|
|
|
gtmpAssertModeFailed = 0;
|
|
while (!((*PPFNDRV(po,AssertMode))(po.dhpdev(), TRUE)))
|
|
{
|
|
gtmpAssertModeFailed = 1;
|
|
}
|
|
|
|
//
|
|
// Clear the PDEV for use
|
|
//
|
|
|
|
po.bDisabled(FALSE);
|
|
|
|
//
|
|
// Get the palette
|
|
//
|
|
|
|
XEPALOBJ pal(po.ppalSurf());
|
|
ASSERTGDI(pal.bValid(), "EPALOBJ failure\n");
|
|
|
|
if (pal.bIsPalManaged())
|
|
{
|
|
ASSERTGDI(PPFNVALID(po,SetPalette), "ERROR palette is not managed");
|
|
|
|
(*PPFNDRV(po,SetPalette))(po.dhpdev(),
|
|
(PALOBJ *) &pal,
|
|
0,
|
|
0,
|
|
pal.cEntries());
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allow DirectDraw to be reenabled.
|
|
//
|
|
|
|
GreEnableDirectDraw(hdev);
|
|
|
|
VRELEASEDEVLOCK(po.pDevLock());
|
|
}
|