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.
2266 lines
74 KiB
2266 lines
74 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: OPENDC.CXX
|
|
*
|
|
* Handles DC creation and driver loading.
|
|
*
|
|
* Copyright (c) 1990-1999 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
extern FLONG flRaster(ULONG, FLONG);
|
|
|
|
/******************************Exported*Routine****************************\
|
|
* GreCreateDisplayDC
|
|
*
|
|
* Opens a DC on the specified display PDEV.
|
|
* Allocates space for a DC, fills in the defaults.
|
|
* If successfull, increments the PDEV reference count.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HDC
|
|
GreCreateDisplayDC(
|
|
HDEV hdev,
|
|
ULONG iType,
|
|
BOOL bAltType)
|
|
{
|
|
GDIFunctionID(GreCreateDisplayDC);
|
|
|
|
HDC hdc = (HDC) NULL;
|
|
|
|
//
|
|
// We hold the devlock to protect against dynamic mode changes
|
|
// while we're copying mode specific information to the DC.
|
|
//
|
|
|
|
PDEVOBJ pdo(hdev);
|
|
DEVLOCKOBJ dlo(pdo);
|
|
|
|
DCMEMOBJ dcmo(iType, bAltType);
|
|
|
|
if (dcmo.bValid())
|
|
{
|
|
//
|
|
// Copy info from the PDEV into the DC.
|
|
//
|
|
|
|
dcmo.pdc->ppdev((PDEV *) pdo.hdev());
|
|
dcmo.pdc->flGraphicsCaps(pdo.flGraphicsCaps()); // cache it for later use by graphics output functions
|
|
dcmo.pdc->flGraphicsCaps2(pdo.flGraphicsCaps2()); // cache it for later use by graphics output functions
|
|
dcmo.pdc->dhpdev(pdo.dhpdev());
|
|
dcmo.hsemDcDevLock(pdo.hsemDevLock());
|
|
|
|
if (iType == DCTYPE_MEMORY)
|
|
{
|
|
SIZEL sizlTemp;
|
|
|
|
sizlTemp.cx = 1;
|
|
sizlTemp.cy = 1;
|
|
|
|
dcmo.pdc->sizl(sizlTemp);
|
|
}
|
|
else
|
|
{
|
|
dcmo.pdc->sizl(pdo.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(pdo.bDisplayPDEV());
|
|
dcmo.pdc->vDisplay(pdo.bDisplayPDEV());
|
|
|
|
//
|
|
// If this DC is created against with disabled PDEV,
|
|
// mark it as full screen mode. All hdc on disbaled
|
|
// PDEV should be marked as 'in fullscreen'.
|
|
// (see PDEVOBJ::bDisabled(BOOL bDisable))
|
|
//
|
|
|
|
dcmo.pdc->bInFullScreen(pdo.bDisabled());
|
|
|
|
if (!pdo.bPrinter())
|
|
dcmo.pdc->pSurface(pdo.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(pdo.bDisplayPDEV());
|
|
|
|
// set user mode VisRect
|
|
dcmo.pdc->vUpdate_VisRect(dcmo.pdc->prgnVis());
|
|
|
|
if (GreSetupDCAttributes((HDC)(dcmo.pdc->hGet())))
|
|
{
|
|
// Mark the DC as permanent, hold the PDEV reference.
|
|
|
|
dcmo.vKeepIt();
|
|
|
|
// This will permanently increase the ref count to indicate
|
|
// a new DC has been created.
|
|
|
|
pdo.vReferencePdev();
|
|
|
|
// turn on the DC_PRIMARY_DISPLAY flag for primary dc's
|
|
|
|
if (hdev == UserGetHDEV())
|
|
{
|
|
dcmo.pdc->ulDirtyAdd(DC_PRIMARY_DISPLAY);
|
|
}
|
|
|
|
// finish initializing the DC.
|
|
|
|
hdc = dcmo.hdc();
|
|
}
|
|
else
|
|
{
|
|
// DCMEMOBJ will be freed, delete vis region
|
|
|
|
dcmo.pdc->vReleaseVis();
|
|
|
|
// delete LOGFONT in DC which set by dcmo.vSetDefaultFont() in above.
|
|
|
|
DEC_SHARE_REF_CNT_LAZY_DEL_LOGFONT(dcmo.pdc->plfntNew());
|
|
}
|
|
}
|
|
|
|
if (hdc == NULL)
|
|
{
|
|
// dec reference counts on brush, pen and others
|
|
// (which incremented in DCOBJ::DCOBJ())
|
|
|
|
DEC_SHARE_REF_CNT_LAZY0(dcmo.pdc->pbrushFill());
|
|
DEC_SHARE_REF_CNT_LAZY0(dcmo.pdc->pbrushLine());
|
|
DEC_SHARE_REF_CNT_LAZY_DEL_COLORSPACE(dcmo.pdc->pColorSpace());
|
|
}
|
|
#if DBG
|
|
else
|
|
{
|
|
// Enable visrgn validation from this point
|
|
|
|
GreValidateVisrgn(hdc, TRUE);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
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())
|
|
{
|
|
//
|
|
// Allocate the DC, fill it with defaults.
|
|
//
|
|
|
|
hdcNew = GreCreateDisplayDC((HDEV) dco.pdc->ppdev(), DCTYPE_INFO, TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We must call USER to get the current PDEV\HDEV for this thread
|
|
// This should end up right back in GreCreateDisplayDC
|
|
//
|
|
|
|
hdcNew = UserGetDesktopDC(DCTYPE_INFO, TRUE, FALSE);
|
|
}
|
|
|
|
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_FROM_POBJ((POBJ)dco.pdc))->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())
|
|
{
|
|
//
|
|
// Allocate the DC, fill it with defaults.
|
|
//
|
|
|
|
hdcNew = GreCreateDisplayDC((HDEV) dco.pdc->ppdev(),
|
|
DCTYPE_MEMORY,
|
|
FALSE);
|
|
//
|
|
// If the compatible DC for a mirrored DC then mirror it.
|
|
//
|
|
|
|
if (hdcNew)
|
|
{
|
|
DWORD dwLayout = dco.pdc->dwLayout();
|
|
|
|
if (dwLayout & LAYOUT_ORIENTATIONMASK)
|
|
{
|
|
GreSetLayout(hdcNew, -1, dwLayout);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hdcNew = UserGetDesktopDC(DCTYPE_MEMORY, FALSE, FALSE);
|
|
}
|
|
|
|
return hdcNew;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL GreSelectRedirectionBitmap
|
|
*
|
|
* This routine selects a redirection bitmap into a redirection DC. A single
|
|
* redirection bitmap can be selected into multiple redirection DCs.
|
|
* Note: The caller needs to hold the devlock.
|
|
* Note: The redirection bitmap must be in system memory because GDI may
|
|
* attempt to convert it to a memory bitmap in the future (mode change,
|
|
* speed optimizations in some code paths, etc.) and we cannot do that
|
|
* here because there's no easy way of getting the list of redirection
|
|
* DCs on that surface.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* hdc -- The redirection DC as created by GreCreateRedirectionDC.
|
|
*
|
|
* hbitmap -- The redirection bitmap to be selected into hdc. This needs
|
|
* to be a memory bitmap (but not DIB-section) which is compatible with
|
|
* the display pdev.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* True upon success
|
|
*
|
|
* History:
|
|
* 21-Sep-1998 -by- Ori Gershony [orig]
|
|
* Wrote it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
APIENTRY
|
|
GreSelectRedirectionBitmap(
|
|
HDC hdc,
|
|
HBITMAP hBitmap
|
|
)
|
|
{
|
|
ULONG ulRet=TRUE;
|
|
|
|
DCOBJA dco(hdc);
|
|
if (dco.bValid())
|
|
{
|
|
SURFACE* pSurface = NULL;
|
|
PDEVOBJ po(dco.hdev());
|
|
|
|
#if DBG
|
|
po.vAssertDevLock();
|
|
#endif
|
|
|
|
if (hBitmap == NULL)
|
|
{
|
|
dco.pdc->bRedirection(FALSE);
|
|
|
|
pSurface = po.pSurface();
|
|
}
|
|
else
|
|
{
|
|
dco.pdc->bRedirection(TRUE);
|
|
|
|
SURFREF surfref((HSURF) hBitmap);
|
|
if (surfref.bValid())
|
|
{
|
|
pSurface = surfref.ps;
|
|
|
|
ASSERTGDI((pSurface->iType() == STYPE_BITMAP) && (!(pSurface->fjBitmap() & BMF_NOTSYSMEM)),
|
|
"GreSelectRedirectionBitmap: bitmap must be in system memory");
|
|
|
|
ASSERTGDI(!pSurface->hDIBSection(),
|
|
"GreSelectRedirectionBitmap: cannot select DIB-section into a redirection DC");
|
|
|
|
PPALETTE ppalReference;
|
|
ASSERTGDI(bIsCompatible(&ppalReference, NULL, pSurface, dco.hdev()),
|
|
"GreSelectRedirectionBitmap: hBitmap not compatible with display hdev");
|
|
|
|
//
|
|
// Mark bitmap as redirection bitmap if not one already
|
|
//
|
|
if (!pSurface->bRedirection())
|
|
{
|
|
pSurface->vSetRedirection();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pSurface != NULL)
|
|
{
|
|
//
|
|
// Replace the surface in all the saved DCs too.
|
|
//
|
|
if (dco.lSaveDepth() > 1)
|
|
{
|
|
ulRet = GreSelectRedirectionBitmap (dco.hdcSave(), hBitmap);
|
|
|
|
//
|
|
// The recursive call above should never fail, and we are not
|
|
// setup to deal with failure correctly (need to undo change
|
|
// to DC redirection flag, etc.). We can add code to do that,
|
|
// but user (who calls us) cannot deal with failure either. So
|
|
// instead we assert that this call succeeded.
|
|
//
|
|
ASSERTGDI(ulRet == TRUE,
|
|
"GreSelectRedirectionBitmap: Recursive call on hdcSave failed");
|
|
}
|
|
|
|
if (ulRet)
|
|
{
|
|
//
|
|
// Replace the pSurf reference in the DCLEVEL
|
|
//
|
|
dco.pdc->pSurface(pSurface);
|
|
|
|
//
|
|
// Set the size to that of the new surface
|
|
//
|
|
dco.pdc->sizl(pSurface->sizl());
|
|
|
|
//
|
|
// Make sure that the surface pointers in any EBRUSHOBJ's get
|
|
// updated, by ensuring that vInitBrush() gets called the next
|
|
// time any brush is used in this DC.
|
|
//
|
|
dco.pdc->flbrushAdd(DIRTY_BRUSHES);
|
|
|
|
//
|
|
// Note: we don't set the visrgn so that if user wants to reuse this dc over
|
|
// the same redirection bitmap it won't have to recompute the visrgn (though it
|
|
// will have to recompute it if it will be reused for a different redirection
|
|
// bitmap).
|
|
//
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ulRet = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ulRet = FALSE;
|
|
}
|
|
|
|
return ulRet;
|
|
}
|
|
|
|
/******************************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;
|
|
|
|
}
|
|
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,
|
|
DRIVER_INFO_2W *pDriverInfo2, // we pass in pDriverInfo for UMPD, NULL otherwise
|
|
PVOID pUMdhpdev
|
|
)
|
|
{
|
|
HDC hdc = (HDC) 0; // Prepare for the worst.
|
|
DWORD cbNeeded = 0;
|
|
PVOID mDriverInfo;
|
|
BOOL bUMPD = pDriverInfo2 ? TRUE: FALSE; // TRUE if User Mode driver
|
|
|
|
TRACE_INIT(("\nhdcOpenDCW: ENTERING\n"));
|
|
|
|
//
|
|
// Attempt to open a display DC.
|
|
//
|
|
|
|
if (pwszDevice && !bUMPD)
|
|
{
|
|
PMDEV pmdev = NULL;
|
|
HDEV hdev = NULL;
|
|
UNICODE_STRING usDevice;
|
|
|
|
RtlInitUnicodeString(&usDevice,
|
|
pwszDevice);
|
|
|
|
if (pdriv == NULL)
|
|
{
|
|
//
|
|
// If no DEVMODE is present, then we just want to create a DC on
|
|
// the specific device.
|
|
// This will allow an application to make some escape calls to a
|
|
// specific device\driver.
|
|
//
|
|
|
|
hdev = DrvGetHDEV(&usDevice);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We have to acquire the USER lock to synchronize with
|
|
// ChangeDisplaySettings.
|
|
//
|
|
|
|
UserEnterUserCritSec();
|
|
|
|
TRACE_INIT(("hdcOpenDCW: Trying to open as a second display device\n"));
|
|
|
|
//
|
|
// Only let the user do this if the device is not part of the
|
|
// desktop.
|
|
//
|
|
|
|
pmdev = DrvCreateMDEV(&usDevice,
|
|
pdriv,
|
|
(PVOID) (ULONG_PTR)0xFFFFFFFF,
|
|
GRE_DISP_CREATE_NODISABLE |
|
|
GRE_DISP_NOT_APARTOF_DESKTOP,
|
|
NULL,
|
|
KernelMode,
|
|
GRE_RAWMODE,
|
|
FALSE); // buffer is captured in NtGdiOpenDCW()
|
|
|
|
if (!pmdev)
|
|
{
|
|
DWORD dwDesktopId;
|
|
|
|
if (UserGetCurrentDesktopId(&dwDesktopId))
|
|
{
|
|
//
|
|
// Try match from current desktop display.
|
|
// but don't create new display instance.
|
|
//
|
|
|
|
pmdev = DrvCreateMDEV(&usDevice,
|
|
pdriv,
|
|
(PVOID) (ULONG_PTR) dwDesktopId,
|
|
GRE_DISP_CREATE_NODISABLE |
|
|
GRE_DISP_NOT_APARTOF_DESKTOP,
|
|
|
|
NULL,
|
|
KernelMode,
|
|
GRE_RAWMODE,
|
|
FALSE);
|
|
}
|
|
}
|
|
|
|
UserLeaveUserCritSec();
|
|
|
|
if (pmdev)
|
|
{
|
|
TRACE_INIT(("Drv_Trace: CreateExclusiveDC: We have an hdev\n"));
|
|
ASSERTGDI(pmdev->chdev == 1,"hdcOpenDCW(): pmdev->chdev != 1");
|
|
|
|
hdev = pmdev->Dev[0].hdev;
|
|
}
|
|
}
|
|
|
|
if (hdev)
|
|
{
|
|
hdc = GreCreateDisplayDC(hdev, DCTYPE_DIRECT, FALSE);
|
|
|
|
if (hdc)
|
|
{
|
|
if (pmdev || hdev)
|
|
{
|
|
DCOBJ dco(hdc);
|
|
PDEVOBJ po(dco.hdev());
|
|
|
|
//
|
|
// Dereference the object since we want DeleteDC
|
|
// to automatically destroy the PDEV.
|
|
//
|
|
// This basically counteracts the extra reference that it done
|
|
// by DrvCreateMDEV(), or DrvGetHDEV().
|
|
//
|
|
po.vUnreferencePdev();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE_INIT(("hdcOpenDCW: Failed to get DC\n"));
|
|
if (pmdev)
|
|
{
|
|
DrvDestroyMDEV(pmdev);
|
|
}
|
|
else
|
|
{
|
|
PDEVOBJ po(hdev);
|
|
po.vUnreferencePdev();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pmdev)
|
|
{
|
|
VFREEMEM(pmdev);
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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 (!bUMPD)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// we have a pDriverInfo2 passed in for UMPD
|
|
//
|
|
mDriverInfo = pDriverInfo2;
|
|
}
|
|
|
|
if (mDriverInfo != (PVOID) NULL)
|
|
{
|
|
PLDEV pldev;
|
|
|
|
if ( bUMPD)
|
|
{
|
|
//
|
|
// we fake a pldev for each LoadDriver call.
|
|
// the real driver list is kept at the client side as a pUMPD list
|
|
//
|
|
pldev = UMPD_ldevLoadDriver(((DRIVER_INFO_2W *)mDriverInfo)->pDriverPath,
|
|
LDEV_DEVICE_PRINTER);
|
|
}
|
|
else
|
|
{
|
|
pldev = ldevLoadDriver(((DRIVER_INFO_2W *)mDriverInfo)->pDriverPath,
|
|
LDEV_DEVICE_PRINTER);
|
|
}
|
|
|
|
if (pldev == NULL)
|
|
{
|
|
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.
|
|
//
|
|
PDEVOBJ po(pldev,
|
|
(PDEVMODEW) pdriv,
|
|
pwszDevice,
|
|
((DRIVER_INFO_2W *)mDriverInfo)->pDataFile,
|
|
((DRIVER_INFO_2W *)mDriverInfo)->pName,
|
|
print.hSpooler(),
|
|
prton,
|
|
NULL,
|
|
NULL,
|
|
bUMPD);
|
|
|
|
if (po.bValid())
|
|
{
|
|
//
|
|
// Make a note that this is a printer.
|
|
//
|
|
|
|
po.bPrinter(TRUE);
|
|
|
|
//
|
|
// Allocate the DC, fill it with defaults.
|
|
//
|
|
|
|
hdc = GreCreateDisplayDC(po.hdev(),
|
|
iType,
|
|
TRUE);
|
|
|
|
//
|
|
// If the DC was properly create, keep the printer
|
|
// object so the printer stays open
|
|
|
|
if (hdc)
|
|
{
|
|
print.vKeepIt();
|
|
|
|
if (bUMPD && pUMdhpdev)
|
|
{
|
|
__try
|
|
{
|
|
ProbeForWritePointer(pUMdhpdev);
|
|
*(PUMDHPDEV *)pUMdhpdev = (PUMDHPDEV)po.dhpdev();
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
bDeleteDCInternal(hdc, FALSE, FALSE);
|
|
hdc = 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Always delete the PEV reference count.
|
|
// If the DC was created, the DC keeps the ref count
|
|
// at 1, and the PDEV will get destroyed when the
|
|
// DC gets destroyed.
|
|
// If the DC was not created properly, this will cause
|
|
// the PDEV to get destroyed immediately.
|
|
//
|
|
|
|
po.vUnreferencePdev();
|
|
|
|
}
|
|
else
|
|
{
|
|
if (!bUMPD)
|
|
{
|
|
ldevUnloadImage(pldev);
|
|
}
|
|
else
|
|
{
|
|
UMPD_ldevUnloadImage(pldev);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bUMPD)
|
|
{
|
|
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,
|
|
DRIVER_INFO_2W *pDriverInfo2,
|
|
PVOID ppUMdhpdev)
|
|
{
|
|
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.bPrinter()))
|
|
{
|
|
// 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,
|
|
pDriverInfo2,
|
|
ppUMdhpdev);
|
|
|
|
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);
|
|
|
|
// Transfer any color transform
|
|
|
|
dcoNew.CXFListSet(dco.CXFListGet());
|
|
dco.CXFListSet(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******************************\
|
|
* bDynamicMatchEnoughForModeChange
|
|
*
|
|
* 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
|
|
bDynamicMatchEnoughForModeChange(
|
|
HDEV hdevOld,
|
|
HDEV hdevNew
|
|
)
|
|
{
|
|
PDEVOBJ poOld(hdevOld);
|
|
PDEVOBJ poNew(hdevNew);
|
|
BOOL b = TRUE;
|
|
|
|
// We would get quite confused with converting monochrome bitmaps if
|
|
// we were to handle 1bpp:
|
|
|
|
if ((poOld.iDitherFormat() == BMF_1BPP) ||
|
|
(poNew.iDitherFormat() == BMF_1BPP))
|
|
{
|
|
WARNING("bDynamicMatchEnoughForModeChange: Can't handle 1bpp");
|
|
b = FALSE;
|
|
}
|
|
|
|
// Some random stuff must be the same between the old instance and
|
|
// the new:
|
|
//
|
|
// We impose the restriction that some flGraphicsCaps flags must stay
|
|
// the same with the new mode. Specifically, we can't allow the
|
|
// following to change:
|
|
//
|
|
// o We don't allow GCAPS_HIGHRESTEXT to change because ESTROBJ::
|
|
// vInit needs to look at it sometimes without acquiring a lock,
|
|
// and it's pretty much a printer specific feature anyway.
|
|
// o We don't allow GCAPS_FORCEDITHER to change because vInitBrush
|
|
// needs to look for this flag without holding a lock, and because
|
|
// this flag is intended to be used only by printer drivers.
|
|
|
|
if ((poNew.flGraphicsCaps() ^ poOld.flGraphicsCaps())
|
|
& (GCAPS_HIGHRESTEXT | GCAPS_FORCEDITHER))
|
|
{
|
|
WARNING("bDynamicMatchEnoughForModeChange: Driver's flGraphicsCaps did");
|
|
WARNING(" not match for GCAPS_HIGHRESTEXT and GCAPS_FORCEDITHER\n");
|
|
b = FALSE;
|
|
}
|
|
|
|
if ((poNew.ulLogPixelsX() != poOld.ulLogPixelsX()) ||
|
|
(poNew.ulLogPixelsY() != poOld.ulLogPixelsY()))
|
|
{
|
|
WARNING("bDynamicMatchEnoughForModeChange: 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 (PPFNDRV(poNew, QueryFont) ||
|
|
PPFNDRV(poNew, QueryFontCaps) ||
|
|
PPFNDRV(poNew, LoadFontFile) ||
|
|
PPFNDRV(poNew, QueryFontFile) ||
|
|
PPFNDRV(poNew, GetGlyphMode))
|
|
{
|
|
WARNING("bDynamicMatchEnoughForModeChange: New driver can't be a font provider\n");
|
|
b = FALSE;
|
|
}
|
|
|
|
if (PPFNDRV(poOld, QueryFont) ||
|
|
PPFNDRV(poOld, QueryFontCaps) ||
|
|
PPFNDRV(poOld, LoadFontFile) ||
|
|
PPFNDRV(poOld, QueryFontFile) ||
|
|
PPFNDRV(poOld, GetGlyphMode))
|
|
{
|
|
WARNING("bDynamicMatchEnoughForModeChange: Old driver can't be a font provider\n");
|
|
b = FALSE;
|
|
}
|
|
|
|
ASSERTGDI((poNew.ulTechnology() == DT_RASDISPLAY) &&
|
|
(poOld.ulTechnology() == DT_RASDISPLAY),
|
|
"Display drivers must specify DT_RASDISPLAY for ulTechnology");
|
|
|
|
ASSERTGDI((poNew.flTextCaps() & ~TC_SCROLLBLT) ==
|
|
(poOld.flTextCaps() & ~TC_SCROLLBLT),
|
|
"Display drivers should set only TC_RA_ABLE in flTextCaps");
|
|
|
|
return(b);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vAssertPaletteRefCountCorrect
|
|
*
|
|
* Validates the reference count for a palette by counting all the surfaces
|
|
* that use it.
|
|
*
|
|
* History:
|
|
* 14-Oct-1996 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
#if DBG
|
|
|
|
VOID
|
|
vAssertPaletteRefCountCorrect(
|
|
PALETTE* ppalOld
|
|
)
|
|
{
|
|
LONG cAltLocks;
|
|
LONG cSurfaces;
|
|
HOBJ hobj;
|
|
SURFACE* pSurface;
|
|
PALETTE* ppalSurface;
|
|
|
|
MLOCKFAST mo;
|
|
|
|
cSurfaces = 0;
|
|
hobj = 0;
|
|
while (pSurface = (SURFACE*) HmgSafeNextObjt(hobj, SURF_TYPE))
|
|
{
|
|
hobj = (HOBJ) pSurface->hGet();
|
|
|
|
ppalSurface = pSurface->ppal();
|
|
|
|
if (ppalSurface == ppalOld)
|
|
{
|
|
cSurfaces++;
|
|
}
|
|
else if ((ppalSurface != NULL) && (ppalSurface->ppalColor == ppalOld))
|
|
{
|
|
cSurfaces++;
|
|
}
|
|
}
|
|
|
|
cAltLocks = ((POBJ) ppalOld)->ulShareCount;
|
|
|
|
// The PDEV keeps a reference count on the palette, as does the
|
|
// EngCreatePalette call. So the number of Alt-locks should be
|
|
// two more than the number of surfaces with this palette:
|
|
|
|
if (cAltLocks < cSurfaces + 2)
|
|
{
|
|
KdPrint(("vAssertPaletteRefCountCorrect cAltLocks: %li != cSurfaces: %li.\n",
|
|
cAltLocks - 2, cSurfaces));
|
|
|
|
hobj = 0;
|
|
while (pSurface = (SURFACE*) HmgSafeNextObjt(hobj, SURF_TYPE))
|
|
{
|
|
hobj = (HOBJ) pSurface->hGet();
|
|
|
|
ppalSurface = pSurface->ppal();
|
|
|
|
if (ppalSurface == ppalOld)
|
|
{
|
|
KdPrint((" %p\n", pSurface));
|
|
}
|
|
else if ((ppalSurface != NULL) && (ppalSurface->ppalColor == ppalOld))
|
|
{
|
|
KdPrint((" -%p\n", pSurface));
|
|
}
|
|
}
|
|
|
|
RIP("Breaking to debugger...");
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
#define vAssertPaletteRefCountCorrect(ppalOld)
|
|
|
|
#endif
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bDynamicRemoveAllDriverRealizations
|
|
*
|
|
* Cleanses a PDEV of all state that is specific to the device, such as
|
|
* device format bitmaps, and brush and font realizations.
|
|
*
|
|
* NOTE: The following locks must be held:
|
|
*
|
|
* 1. Devlock;
|
|
* 2. RFont list lock;
|
|
* 3. Handle manager lock.
|
|
*
|
|
* History:
|
|
* 8-Feb-1996 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDynamicRemoveAllDriverRealizations(
|
|
HDEV hdev
|
|
)
|
|
{
|
|
BOOL bConversionSuccessful;
|
|
HOBJ hobj; // Temporary object handle
|
|
SURFACE* pSurface; // Temporary surface pointer
|
|
RFONT* prfnt; // Temporary RFONT pointer
|
|
FONTOBJ* pfo; // Temporary FONTOBJ pointer
|
|
BRUSH* pbrush; // Temporary BRUSH pointer
|
|
PFN_DrvDestroyFont pfnDrvDestroyFont;
|
|
PDEV* ppdev;
|
|
|
|
PDEVOBJ po(hdev);
|
|
|
|
ppdev = po.ppdev;
|
|
|
|
// Now traverse all the device bitmaps associated with this device,
|
|
// and convert any driver-owned bitmaps to DIBs.
|
|
|
|
bConversionSuccessful = TRUE;
|
|
|
|
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();
|
|
|
|
// Note that the sprite code handles mode changes for sprite
|
|
// surfaces.
|
|
|
|
if ((pSurface->hdev() == hdev) &&
|
|
(pSurface->bDeviceDependentBitmap()) &&
|
|
(pSurface->dhpdev() != NULL))
|
|
{
|
|
// 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)
|
|
{
|
|
// WinBug #242572 3-13-2001 jasonha Surface not selected by DC it thinks it is
|
|
//
|
|
// When a DC is saved while a DFB is selected, but then another
|
|
// surface or no surface is selected, bConvertDfbDcToDib will
|
|
// try to convert the top-level DC's surface to a DIB.
|
|
//
|
|
// Walk the saved DC chain until the first DC actually referencing
|
|
// this surface is found.
|
|
//
|
|
|
|
HDC hdc = pSurface->hdc();
|
|
|
|
while (1)
|
|
{
|
|
MDCOBJA dco(hdc); // Alt-lock
|
|
|
|
ASSERTGDI(dco.bValid(), "Surface DC is invalid");
|
|
|
|
if (dco.pSurface() == pSurface)
|
|
{
|
|
if (!bConvertDfbDcToDib(&dco))
|
|
{
|
|
WARNING("Failed DC surface conversion (possibly from low memory)\n");
|
|
bConversionSuccessful = FALSE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
ASSERTGDI(dco.lSaveDepth() > 1, "DC selected surface not found in DC stack.");
|
|
|
|
hdc = dco.hdcSave();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Handle Compatible Stock Surfaces
|
|
if (pSurface->bStockSurface())
|
|
{
|
|
|
|
if (!pConvertDfbSurfaceToDib(hdev, pSurface, pSurface->cRef()))
|
|
{
|
|
WARNING("Failed stock surface conversion in bConvertStockDfbToDib()\n");
|
|
bConversionSuccessful = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// No-one should have a lock on the bitmap:
|
|
|
|
if (!pConvertDfbSurfaceToDib(hdev, pSurface, 0))
|
|
{
|
|
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)
|
|
{
|
|
// 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!
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
// 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 'hdevOld' 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());
|
|
}
|
|
|
|
// 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 (ppdev->pDevHTInfo != NULL)
|
|
{
|
|
po.bDisableHalftone();
|
|
}
|
|
}
|
|
|
|
return(bConversionSuccessful);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bDynamicIntersectVisRect
|
|
*
|
|
* 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 bDynamicModeChange 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.
|
|
*
|
|
* History:
|
|
* 8-Feb-1996 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDynamicIntersectVisRect(
|
|
SURFACE* pSurfaceOld,
|
|
SIZEL sizlNew
|
|
)
|
|
{
|
|
HOBJ hobj;
|
|
DC* pdc;
|
|
|
|
hobj = 0;
|
|
while (pdc = (DC*) HmgSafeNextObjt(hobj, DC_TYPE))
|
|
{
|
|
hobj = (HOBJ) pdc->hGet();
|
|
|
|
if ((!(pdc->fs() & DC_IN_CLONEPDEV)) &&
|
|
(pdc->pSurface() == pSurfaceOld) &&
|
|
(pdc->prgnVis() != NULL))
|
|
{
|
|
if (!GreIntersectVisRect((HDC) hobj, 0, 0,
|
|
sizlNew.cx, sizlNew.cy))
|
|
{
|
|
WARNING("bDynamicModeChange: 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.
|
|
|
|
return(FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vDynamicSwitchPalettes
|
|
*
|
|
* 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.
|
|
*
|
|
* History:
|
|
* 8-Feb-1996 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDynamicSwitchPalettes(
|
|
SURFACE* pSurface,
|
|
PDEV* ppdevOld,
|
|
PDEV* ppdevNew
|
|
)
|
|
{
|
|
PALETTE* ppalOld;
|
|
HOBJ hobj;
|
|
BOOL bHintCreated;
|
|
|
|
ASSERTGDI(pSurface->iType() == STYPE_BITMAP,
|
|
"Unexpected bitmap type");
|
|
ASSERTGDI(pSurface->iFormat() == ppdevOld->devinfo.iDitherFormat,
|
|
"Unexpected bitmap format");
|
|
|
|
// 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.
|
|
//
|
|
// If a non-DFB DDB is currently selected into a DC owned by the
|
|
// display, we will add a palette to it. If a non-DFB DDB is
|
|
// not currently selected into a DC owned by the display (implied
|
|
// by having its surface 'hdev' as zero), we will not convert it.
|
|
// SelectBitmap will refuse to load it into a DC. (In 4.0 we used
|
|
// to always assume that any such bitmap was intended for the
|
|
// display, but that's not always a valid assumption, and doesn't
|
|
// make much sense in a multiple-monitor or multi-user environment
|
|
// anyway.) Fortunately, non-DFB DDBs are increasingly rare.
|
|
//
|
|
// 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).
|
|
|
|
ppalOld = ppdevOld->ppalSurf;
|
|
|
|
if (pSurface->ppal() == NULL)
|
|
{
|
|
// Mark the surface to note that we added a palette:
|
|
|
|
pSurface->vSetDynamicModePalette();
|
|
|
|
if (ppdevOld->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 (ppdevNew->GdiInfo.flRaster & RC_PALETTE)
|
|
{
|
|
if (pSurface->bDynamicModePalette())
|
|
{
|
|
ASSERTGDI(pSurface->ppal() != NULL,
|
|
"Should be a palette here");
|
|
|
|
XEPALOBJ pal(pSurface->ppal());
|
|
pal.vUnrefPalette();
|
|
|
|
pSurface->vClearDynamicModePalette();
|
|
pSurface->ppal(NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bDynamicModeChange
|
|
*
|
|
* USER callable function that switches driver instances between two PDEVs.
|
|
*
|
|
* GDI's 'HDEV' and 'PDEV' stay the same; only the device's 'pSurface',
|
|
* 'dhpdev', GDIINFO, DEVINFO, and palette information change.
|
|
*
|
|
* The caller is ChangeDisplaySettings in USER, which is reponsible for:
|
|
*
|
|
* o Calling us with a valid devmode;
|
|
* 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 messages 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.
|
|
*
|
|
* Dynamically changes a display driver or mode.
|
|
*
|
|
* 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.
|
|
*
|
|
* Returns: TRUE if successful, FALSE if the two PDEVs didn't match enough,
|
|
* or if we're out of memory.
|
|
*
|
|
* History:
|
|
* 8-Feb-1996 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
*
|
|
* 27-Aug-1996 -by- J. Andrew Goossen [andrewgo]
|
|
* Added support for dynamic display driver changes.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG gcModeChanges; // # of mode changes, for debugging even on free builds
|
|
|
|
#define SWAP(x, y, tmp) { (tmp) = (x); (x) = (y); (y) = (tmp); }
|
|
|
|
typedef union {
|
|
GDIINFO GdiInfo;
|
|
DEVINFO devinfo;
|
|
PFN apfn[INDEX_LAST];
|
|
LDEV* pldev;
|
|
HANDLE hSpooler;
|
|
PVOID pDesktopId;
|
|
PGRAPHICS_DEVICE pGraphicsDevice;
|
|
POINTL ptlOrigin;
|
|
PDEVMODEW ppdevDevmode;
|
|
PFN_DrvSetPointerShape pfnSet;
|
|
PFN_DrvMovePointer pfnMove;
|
|
PFN_DrvSynchronize pfnSync;
|
|
PFN_DrvSynchronizeSurface pfnSyncSurface;
|
|
PFN_DrvSetPalette pfnSetPalette;
|
|
PFN_DrvBitBlt pfnUnfilteredBitBlt;
|
|
PFN_DrvNotify pfnNotify;
|
|
BYTE dc[sizeof(DC)];
|
|
SIZEL sizlMeta;
|
|
HSURF ahsurf[HS_DDI_MAX];
|
|
HLFONT hlfnt;
|
|
DWORD dwDriverAccelerationLevel;
|
|
DWORD dwDriverCapableOverride;
|
|
#ifdef DDI_WATCHDOG
|
|
PWATCHDOG_DATA pWatchdogData;
|
|
#endif
|
|
} SWAPBUFFER;
|
|
|
|
BOOL
|
|
bDynamicModeChange(
|
|
HDEV hdevOld,
|
|
HDEV hdevNew
|
|
)
|
|
{
|
|
BOOL bRet;
|
|
BOOL bFormatChange;
|
|
PDEV* ppdevOld;
|
|
PDEV* ppdevNew;
|
|
DHPDEV dhpdevOld;
|
|
DHPDEV dhpdevNew;
|
|
SURFACE* pSurfaceOld;
|
|
SURFACE* pSurfaceNew;
|
|
PALETTE* ppalOld;
|
|
PALETTE* ppalNew;
|
|
ULONG cBppOld;
|
|
ULONG cBppNew;
|
|
SIZEL sizlOld;
|
|
SIZEL sizlNew;
|
|
SURFACE* pSurface; // Temporary surface pointer
|
|
DC* pdc; // Temporary DC pointer
|
|
DRVOBJ* pdo; // Temporary DRVOBJ pointer
|
|
HOBJ hobj; // Temporary object handle
|
|
BOOL bPermitModeChange;
|
|
BRUSH* pbrGrayPattern;
|
|
DC* pdcBuffer; // Points to temporary DC buffer
|
|
SWAPBUFFER* pswap;
|
|
BOOL bDisabledOld;
|
|
BOOL bDisabledNew;
|
|
PFN_DrvResetPDEV pfnDrvResetPDEV;
|
|
|
|
bRet = FALSE; // Assume failure
|
|
|
|
// We impose some restrictions upon what capabilities may change
|
|
// between drivers:
|
|
|
|
if (bDynamicMatchEnoughForModeChange(hdevOld, hdevNew))
|
|
{
|
|
|
|
ASSERTGDI(GreIsSemaphoreOwnedByCurrentThread(ghsemShareDevLock),
|
|
"ShareDevlock must held be before calling bDynamicModeChange");
|
|
|
|
// Allocate a temporary buffer for use swapping data:
|
|
|
|
pswap = (SWAPBUFFER*) PALLOCNOZ(sizeof(SWAPBUFFER), 'pmtG');
|
|
if (pswap)
|
|
{
|
|
PDEVOBJ poOld(hdevOld);
|
|
PDEVOBJ poNew(hdevNew);
|
|
|
|
bDisabledNew = poNew.bDisabled();
|
|
bDisabledOld = poOld.bDisabled();
|
|
|
|
// Disable timer-based synchronization for these PDEVs for now.
|
|
// This is mainly so that the PDEV_SYNCHRONIZE_ENABLED is set
|
|
// correctly.
|
|
|
|
vDisableSynchronize(hdevNew);
|
|
vDisableSynchronize(hdevOld);
|
|
|
|
cBppOld = poOld.GdiInfo()->cBitsPixel * poOld.GdiInfo()->cPlanes;
|
|
cBppNew = poNew.GdiInfo()->cBitsPixel * poNew.GdiInfo()->cPlanes;
|
|
|
|
// Ideally, we would check the palettes here, too:
|
|
|
|
bFormatChange = (cBppOld != cBppNew);
|
|
|
|
ppdevOld = (PDEV*) hdevOld;
|
|
ppdevNew = (PDEV*) hdevNew;
|
|
|
|
// PDEV shouldn't be clone
|
|
|
|
ASSERTGDI(!poOld.bCloneDriver(),"pdevOld is clone!");
|
|
ASSERTGDI(!poNew.bCloneDriver(),"pdevNew is clone!");
|
|
|
|
// The following lock rules must be abided, otherwise deadlocks may
|
|
// arise:
|
|
//
|
|
// o Pointer lock must be acquired after Devlock (GreSetPointer);
|
|
//
|
|
// And see drvsup.cxx, too.
|
|
//
|
|
// So we acquire locks in the following order (note that the
|
|
// vAssertDynaLock() routines should be modified if this list ever
|
|
// changes):
|
|
|
|
ASSERTGDI(GreIsSemaphoreOwnedByCurrentThread(poOld.hsemDevLock()),
|
|
"Devlock must be held before acquiring the pointer semaphore");
|
|
|
|
SEMOBJ soPointer(poOld.hsemPointer()); // No asynchronous pointer moves
|
|
|
|
ASSERTGDI(ppdevOld->pSurface != NULL, "Must be called on a completed PDEV");
|
|
ASSERTGDI(poOld.bDisplayPDEV(), "Must be called on a display PDEV");
|
|
ASSERTGDI((prgnDefault->cScans == 1) && (prgnDefault->rcl.right == 0),
|
|
"Someone changed prgnDefault; could cause driver access violations");
|
|
|
|
// Free all PDEV state that is dependent on or cached by the driver:
|
|
|
|
if (bDynamicRemoveAllDriverRealizations(hdevOld) &&
|
|
bDynamicRemoveAllDriverRealizations(hdevNew))
|
|
{
|
|
bPermitModeChange = TRUE;
|
|
|
|
sizlOld = poOld.sizl();
|
|
pSurfaceOld = ppdevOld->pSurface;
|
|
ppalOld = ppdevOld->ppalSurf;
|
|
dhpdevOld = ppdevOld->dhpdev;
|
|
|
|
sizlNew = poNew.sizl();
|
|
pSurfaceNew = ppdevNew->pSurface;
|
|
ppalNew = ppdevNew->ppalSurf;
|
|
dhpdevNew = ppdevNew->dhpdev;
|
|
|
|
// Make sure the VisRgns are immediately shrunk if necessary:
|
|
|
|
if ((sizlNew.cx < sizlOld.cx) || (sizlNew.cy < sizlOld.cy))
|
|
{
|
|
bPermitModeChange &= bDynamicIntersectVisRect(pSurfaceOld, sizlNew);
|
|
}
|
|
if ((sizlOld.cx < sizlNew.cx) || (sizlOld.cy < sizlNew.cy))
|
|
{
|
|
bPermitModeChange &= bDynamicIntersectVisRect(pSurfaceNew, sizlOld);
|
|
}
|
|
|
|
// Finally, if we're not switching drivers then 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(poNew, ResetPDEV);
|
|
if ((pfnDrvResetPDEV != NULL) &&
|
|
(pfnDrvResetPDEV == PPFNDRV(poOld, ResetPDEV)) &&
|
|
(poNew.pldev() == poOld.pldev()))
|
|
{
|
|
// The driver can refuse the mode switch if it wants:
|
|
|
|
if (bPermitModeChange)
|
|
{
|
|
GreEnterMonitoredSection(poOld.ppdev, WD_DEVLOCK);
|
|
bPermitModeChange = pfnDrvResetPDEV(dhpdevOld, dhpdevNew);
|
|
GreExitMonitoredSection(poOld.ppdev, WD_DEVLOCK);
|
|
}
|
|
}
|
|
|
|
if (bPermitModeChange)
|
|
{
|
|
/////////////////////////////////////////////////////////////
|
|
// At this point, we're committed to the mode change.
|
|
// Nothing below this point can be allowed to fail.
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
// 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->fs() & DC_IN_CLONEPDEV))
|
|
{
|
|
// Note that we don't check that pdc->hdevOld() == hdevOld
|
|
// because the SaveDC stuff doesn't bother copying the hdevOld,
|
|
// but DOES copy the dclevel.
|
|
//
|
|
// 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:
|
|
|
|
if (pdc->pSurface() == pSurfaceOld)
|
|
{
|
|
pdc->pSurface(pSurfaceNew);
|
|
pdc->sizl(sizlNew);
|
|
pdc->flbrushAdd(DIRTY_BRUSHES);
|
|
}
|
|
else if (pdc->pSurface() == pSurfaceNew)
|
|
{
|
|
pdc->pSurface(pSurfaceOld);
|
|
pdc->sizl(sizlOld);
|
|
pdc->flbrushAdd(DIRTY_BRUSHES);
|
|
}
|
|
|
|
if (pdc->dhpdev() == dhpdevOld)
|
|
{
|
|
pdc->dhpdev(dhpdevNew);
|
|
pdc->flGraphicsCaps(poNew.flGraphicsCaps());
|
|
pdc->flGraphicsCaps2(poNew.flGraphicsCaps2());
|
|
}
|
|
else if (pdc->dhpdev() == dhpdevNew)
|
|
{
|
|
pdc->dhpdev(dhpdevOld);
|
|
pdc->flGraphicsCaps(poOld.flGraphicsCaps());
|
|
pdc->flGraphicsCaps2(poOld.flGraphicsCaps2());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Compatible bitmap palettes may have to be changed if the
|
|
// mode changes. Note that the sprite code handles any
|
|
// sprite surfaces:
|
|
|
|
hobj = 0;
|
|
while (pSurface = (SURFACE*) HmgSafeNextObjt(hobj, SURF_TYPE))
|
|
{
|
|
hobj = (HOBJ) pSurface->hGet();
|
|
|
|
if (pSurface->hdev() == hdevOld)
|
|
{
|
|
if (pSurface->bApiBitmap())
|
|
{
|
|
if ((bFormatChange) &&
|
|
(pSurface->iFormat() == pSurfaceOld->iFormat()))
|
|
{
|
|
vDynamicSwitchPalettes(pSurface, ppdevOld, ppdevNew);
|
|
}
|
|
}
|
|
|
|
// Surfaces private to the driver should be transferred
|
|
// along with the driver instance.
|
|
|
|
else if (pSurface->bDriverCreated() && !pSurface->bDirectDraw())
|
|
{
|
|
pSurface->hdev(hdevNew);
|
|
}
|
|
}
|
|
else if (pSurface->hdev() == hdevNew)
|
|
{
|
|
if (pSurface->bApiBitmap())
|
|
{
|
|
if ((bFormatChange) &&
|
|
(pSurface->iFormat() == pSurfaceNew->iFormat()))
|
|
{
|
|
vDynamicSwitchPalettes(pSurface, ppdevNew, ppdevOld);
|
|
}
|
|
}
|
|
|
|
// Surfaces private to the driver should be transferred
|
|
// along with the driver instance.
|
|
|
|
else if (pSurface->bDriverCreated() && !pSurface->bDirectDraw())
|
|
{
|
|
pSurface->hdev(hdevOld);
|
|
}
|
|
}
|
|
}
|
|
|
|
// DRIVEROBJs are transferred with the driver to the new PDEV:
|
|
|
|
hobj = 0;
|
|
while (pdo = (DRVOBJ*) HmgSafeNextObjt(hobj, DRVOBJ_TYPE))
|
|
{
|
|
hobj = (HOBJ) pdo->hGet();
|
|
|
|
if (pdo->hdev == hdevOld)
|
|
{
|
|
pdo->hdev = hdevNew;
|
|
poNew.vReferencePdev();
|
|
poOld.vUnreferencePdev();
|
|
}
|
|
else if (pdo->hdev == hdevNew)
|
|
{
|
|
pdo->hdev = hdevOld;
|
|
poOld.vReferencePdev();
|
|
poNew.vUnreferencePdev();
|
|
}
|
|
}
|
|
|
|
// Same with WNDOBJs:
|
|
|
|
vChangeWndObjs(pSurfaceOld, hdevOld, pSurfaceNew, hdevNew);
|
|
|
|
// Re-realize the gray pattern brush which is used for drag
|
|
// rectangles:
|
|
|
|
pbrGrayPattern = (BRUSH*) HmgShareLock((HOBJ)ghbrGrayPattern,
|
|
BRUSH_TYPE);
|
|
|
|
pdcBuffer = (DC*) &pswap->dc;
|
|
pdcBuffer->pDCAttr = &pdcBuffer->dcattr;
|
|
pdcBuffer->crTextClr(0x00000000);
|
|
pdcBuffer->crBackClr(0x00FFFFFF);
|
|
pdcBuffer->lIcmMode(DC_ICM_OFF);
|
|
pdcBuffer->hcmXform(NULL);
|
|
|
|
poOld.pbo()->vInitBrush(pdcBuffer,
|
|
pbrGrayPattern,
|
|
(XEPALOBJ) ppalDefault,
|
|
(XEPALOBJ) ppalNew,
|
|
pSurfaceNew);
|
|
poNew.pbo()->vInitBrush(pdcBuffer,
|
|
pbrGrayPattern,
|
|
(XEPALOBJ) ppalDefault,
|
|
(XEPALOBJ) ppalOld,
|
|
pSurfaceOld);
|
|
|
|
DEC_SHARE_REF_CNT(pbrGrayPattern);
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
// Update all our PDEV fields:
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
// Swap surface data between the two PDEVs:
|
|
|
|
ppdevNew->pSurface = pSurfaceOld;
|
|
ppdevNew->ppalSurf = ppalOld;
|
|
ppdevNew->dhpdev = dhpdevOld;
|
|
|
|
ppdevOld->pSurface = pSurfaceNew;
|
|
ppdevOld->ppalSurf = ppalNew;
|
|
ppdevOld->dhpdev = dhpdevNew;
|
|
|
|
if (!pSurfaceOld->bReadable())
|
|
{
|
|
pSurfaceNew->flags(pSurfaceNew->flags() | UNREADABLE_SURFACE);
|
|
|
|
SPRITESTATE *pStateOld = poOld.pSpriteState();
|
|
if (pStateOld)
|
|
{
|
|
if (pStateOld->flOriginalSurfFlags & UNREADABLE_SURFACE ||
|
|
pStateOld->flSpriteSurfFlags & UNREADABLE_SURFACE)
|
|
{
|
|
SPRITESTATE *pStateNew = poNew.pSpriteState();
|
|
if (pStateNew)
|
|
{
|
|
pStateNew->flOriginalSurfFlags |= UNREADABLE_SURFACE;
|
|
pStateNew->flSpriteSurfFlags |= UNREADABLE_SURFACE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (!pSurfaceNew->bReadable())
|
|
{
|
|
pSurfaceOld->flags(pSurfaceOld->flags() | UNREADABLE_SURFACE);
|
|
|
|
SPRITESTATE *pStateNew = poNew.pSpriteState();
|
|
if (pStateNew)
|
|
{
|
|
if (pStateNew->flOriginalSurfFlags & UNREADABLE_SURFACE ||
|
|
pStateNew->flSpriteSurfFlags & UNREADABLE_SURFACE)
|
|
{
|
|
SPRITESTATE *pStateOld = poOld.pSpriteState();
|
|
if (pStateOld)
|
|
{
|
|
pStateOld->flOriginalSurfFlags |= UNREADABLE_SURFACE;
|
|
pStateOld->flSpriteSurfFlags |= UNREADABLE_SURFACE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// WINBUG #365395 4-10-2001 jasonha Need to investigate old comments in bDynamicModeChange
|
|
//
|
|
// Old Comments:
|
|
// - vUnrefPalette of old palette for mirrored drivers?
|
|
// - Secondary palette fix?
|
|
|
|
SWAP(ppdevNew->pldev ,ppdevOld->pldev ,pswap->pldev );
|
|
SWAP(ppdevNew->devinfo ,ppdevOld->devinfo ,pswap->devinfo );
|
|
SWAP(ppdevNew->GdiInfo ,ppdevOld->GdiInfo ,pswap->GdiInfo );
|
|
SWAP(ppdevNew->hSpooler ,ppdevOld->hSpooler ,pswap->hSpooler );
|
|
SWAP(ppdevNew->pDesktopId ,ppdevOld->pDesktopId ,pswap->pDesktopId );
|
|
SWAP(ppdevNew->pGraphicsDevice,ppdevOld->pGraphicsDevice,pswap->pGraphicsDevice);
|
|
SWAP(ppdevNew->ptlOrigin ,ppdevOld->ptlOrigin ,pswap->ptlOrigin );
|
|
SWAP(ppdevNew->ppdevDevmode ,ppdevOld->ppdevDevmode ,pswap->ppdevDevmode );
|
|
|
|
SWAP(ppdevNew->pfnUnfilteredBitBlt,
|
|
ppdevOld->pfnUnfilteredBitBlt,
|
|
pswap->pfnUnfilteredBitBlt);
|
|
|
|
SWAP(ppdevNew->dwDriverCapableOverride,
|
|
ppdevOld->dwDriverCapableOverride,
|
|
pswap->dwDriverCapableOverride);
|
|
|
|
SWAP(ppdevNew->dwDriverAccelerationLevel,
|
|
ppdevOld->dwDriverAccelerationLevel,
|
|
pswap->dwDriverAccelerationLevel);
|
|
|
|
// Swap multimon data between the two PDEVs:
|
|
|
|
if (poOld.bMetaDriver() != poNew.bMetaDriver())
|
|
{
|
|
BOOL bMetaDriver = poOld.bMetaDriver();
|
|
poOld.bMetaDriver(poNew.bMetaDriver());
|
|
poNew.bMetaDriver(bMetaDriver);
|
|
}
|
|
|
|
SWAP(ppdevNew->sizlMeta, ppdevOld->sizlMeta, pswap->sizlMeta);
|
|
|
|
// Swap pattern brushes
|
|
|
|
RtlCopyMemory(pswap->ahsurf, ppdevNew->ahsurf, sizeof(HSURF)*HS_DDI_MAX);
|
|
RtlCopyMemory(ppdevNew->ahsurf, ppdevOld->ahsurf, sizeof(HSURF)*HS_DDI_MAX);
|
|
RtlCopyMemory(ppdevOld->ahsurf, pswap->ahsurf, sizeof(HSURF)*HS_DDI_MAX);
|
|
|
|
// Swap log fonts.
|
|
|
|
SWAP(ppdevNew->hlfntDefault, ppdevOld->hlfntDefault, pswap->hlfnt);
|
|
SWAP(ppdevNew->hlfntAnsiVariable, ppdevOld->hlfntAnsiVariable, pswap->hlfnt);
|
|
SWAP(ppdevNew->hlfntAnsiFixed, ppdevOld->hlfntAnsiFixed, pswap->hlfnt);
|
|
|
|
// Swap the dispatch tables and accelerators:
|
|
|
|
RtlCopyMemory(pswap->apfn, ppdevNew->apfn, sizeof(PFN)*INDEX_LAST);
|
|
RtlCopyMemory(ppdevNew->apfn, ppdevOld->apfn, sizeof(PFN)*INDEX_LAST);
|
|
RtlCopyMemory(ppdevOld->apfn, pswap->apfn, sizeof(PFN)*INDEX_LAST);
|
|
|
|
SWAP(ppdevNew->pfnDrvSetPointerShape, ppdevOld->pfnDrvSetPointerShape, pswap->pfnSet);
|
|
SWAP(ppdevNew->pfnDrvMovePointer, ppdevOld->pfnDrvMovePointer, pswap->pfnMove);
|
|
SWAP(ppdevNew->pfnSync, ppdevOld->pfnSync, pswap->pfnSync);
|
|
SWAP(ppdevNew->pfnSyncSurface, ppdevOld->pfnSyncSurface, pswap->pfnSyncSurface);
|
|
SWAP(ppdevNew->pfnSetPalette, ppdevOld->pfnSetPalette, pswap->pfnSetPalette);
|
|
SWAP(ppdevNew->pfnNotify, ppdevOld->pfnNotify, pswap->pfnNotify);
|
|
#ifdef DDI_WATCHDOG
|
|
SWAP(ppdevNew->pWatchdogData, ppdevOld->pWatchdogData, pswap->pWatchdogData);
|
|
#endif
|
|
|
|
// Inform the drivers of their new PDEVs:
|
|
|
|
(*PPFNDRV(poNew, CompletePDEV))(poNew.dhpdev(), poNew.hdev());
|
|
(*PPFNDRV(poOld, CompletePDEV))(poOld.dhpdev(), poOld.hdev());
|
|
|
|
// Transfer all the DirectDraw state:
|
|
|
|
DxDdDynamicModeChange(hdevOld, hdevNew, 0);
|
|
|
|
// Transfer the disabled state:
|
|
|
|
poOld.bDisabled(bDisabledNew);
|
|
poNew.bDisabled(bDisabledOld);
|
|
|
|
// Update the magic colours in the surface palette:
|
|
|
|
vResetSurfacePalette(hdevOld);
|
|
vResetSurfacePalette(hdevNew);
|
|
|
|
// Transfer all the sprites between the two PDEVs:
|
|
|
|
vSpDynamicModeChange(hdevOld, hdevNew);
|
|
|
|
// Update the gamma-ramp on the device only if a gamma-ramp
|
|
// existed in the old (but at this moment, old is "new") PDEV:
|
|
|
|
UpdateGammaRampOnDevice(hdevOld, FALSE);
|
|
|
|
// Update some handy debug information:
|
|
|
|
gcModeChanges++;
|
|
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
VFREEMEM(pswap);
|
|
|
|
vEnableSynchronize(hdevNew);
|
|
vEnableSynchronize(hdevOld);
|
|
}
|
|
}
|
|
|
|
return(bRet);
|
|
}
|