|
|
#include "precomp.h"
//
// SSI.C
// Save Screenbits Interceptor, display driver side
//
// Copyright(c) Microsoft 1997-
//
//
// SSI_DDProcessRequest - see ssi.h
//
BOOL SSI_DDProcessRequest ( UINT fnEscape, LPOSI_ESCAPE_HEADER pRequest, DWORD cbRequest ) { BOOL rc;
DebugEntry(SSI_DDProcessRequest);
switch (fnEscape) { case SSI_ESC_RESET_LEVEL: { if (cbRequest != sizeof(SSI_RESET_LEVEL)) { ERROR_OUT(("SSI_DDProcessRequest: Invalid size %d for SSI_ESC_RESET_LEVEL", cbRequest)); rc = FALSE; DC_QUIT; }
SSIResetSaveScreenBitmap(); rc = TRUE; } break;
case SSI_ESC_NEW_CAPABILITIES: { if (cbRequest != sizeof(SSI_NEW_CAPABILITIES)) { ERROR_OUT(("SSI_DDProcessRequest: Invalid size %d for SSI_ESC_NEW_CAPABILITIES", cbRequest)); rc = FALSE; DC_QUIT; }
SSISetNewCapabilities((LPSSI_NEW_CAPABILITIES)pRequest); rc = TRUE; } break;
default: { ERROR_OUT(("Unrecognized SSI_ escape")); rc = FALSE; } break; }
DC_EXIT_POINT: DebugExitBOOL(SSI_DDProcessRequest, rc); return(rc); }
//
// SSI_SaveScreenBitmap()
//
// see ssi.h for description.
//
BOOL SSI_SaveScreenBitmap(LPRECT lpRect, UINT wCommand) { BOOL rc;
DebugEntry(SSI_SaveScreenBitmap);
//
// Decide whether we can transmit this particular SaveBitmap command as
// an order.
//
switch (wCommand) { case ONBOARD_SAVE: { //
// Save the bits.
//
rc = SSISaveBits(lpRect); } break;
case ONBOARD_RESTORE: { //
// Restore the bits.
//
rc = SSIRestoreBits(lpRect); } break;
case ONBOARD_DISCARD: { //
// Discard the saved bits.
//
rc = SSIDiscardBits(lpRect); } break;
default: { ERROR_OUT(( "Unexpected wCommand(%d)", wCommand)); rc = FALSE; } }
if (g_ssiLocalSSBState.saveLevel == 0) { ASSERT(g_ssiRemoteSSBState.pelsSaved == 0); }
DebugExitBOOL(SSI_SaveScreenBitmap, rc); return(rc); }
//
// FUNCTION: SSIResetSaveScreenBitmap.
//
// DESCRIPTION:
//
// Resets the SaveScreenBitmap state.
//
// PARAMETERS: None.
//
// RETURNS: Nothing.
//
//
void SSIResetSaveScreenBitmap(void) { DebugEntry(SSIResetSaveScreenBitmap);
//
// Discard all currently saved bits.
//
g_ssiLocalSSBState.saveLevel = 0;
//
// Reset the number of remote pels saved.
//
g_ssiRemoteSSBState.pelsSaved = 0;
DebugExitVOID(SSIResetSaveScreenBitmap); }
//
// FUNCTION: SSISendSaveBitmapOrder
//
// DESCRIPTION:
//
// Attempts to send a SaveBitmap order matching the supplied parameters.
//
//
// PARAMETERS:
//
// lpRect - pointer to the rectangle coords (EXCLUSIVE screen coords)
//
// RETURNS:
//
// TRUE if order successfully sent FALSE if order not sent
//
//
BOOL SSISendSaveBitmapOrder ( LPRECT lpRect, UINT wCommand ) { DWORD cRemotePelsRequired; LPSAVEBITMAP_ORDER pSaveBitmapOrder; LPINT_ORDER pOrder; BOOL rc = FALSE;
DebugEntry(SSISendSaveBitmapOrder);
//
// If the SaveBitmap order is not supported then return FALSE
// immediately.
//
if (!OE_SendAsOrder(ORD_SAVEBITMAP)) { WARNING_OUT(("SSISendSaveBitmapOrder failing; save bits orders not supported")); DC_QUIT; }
switch (wCommand) { case ONBOARD_DISCARD: //
// We don't transmit DISCARD orders, there's no need since
// saves/restores are paired.
//
g_ssiRemoteSSBState.pelsSaved -= CURRENT_LOCAL_SSB_STATE.remotePelsRequired; rc = TRUE; DC_QUIT;
case ONBOARD_SAVE: //
// Calculate the number of pels required in the remote Save
// Bitmap to handle this rectangle.
//
cRemotePelsRequired = SSIRemotePelsRequired(lpRect);
//
// If there aren't enough pels in the remote Save Bitmap to
// handle this rectangle then return immediately.
//
if ((g_ssiRemoteSSBState.pelsSaved + cRemotePelsRequired) > g_ssiSaveBitmapSize) { TRACE_OUT(("SSISendSaveBitmapOrder: ONBOARD_SAVE is failing; not enough space for %08d pels", cRemotePelsRequired)); DC_QUIT; }
//
// Allocate memory for the order.
//
pOrder = OA_DDAllocOrderMem(sizeof(SAVEBITMAP_ORDER), 0); if (!pOrder) DC_QUIT;
//
// Store the drawing order data.
//
pSaveBitmapOrder = (LPSAVEBITMAP_ORDER)pOrder->abOrderData;
pSaveBitmapOrder->type = LOWORD(ORD_SAVEBITMAP); pSaveBitmapOrder->Operation = SV_SAVEBITS;
//
// SAVEBITS is a BLOCKER order i.e. it prevents any earlier
// orders from being spoilt by subsequent orders or Screen
// Data.
//
pOrder->OrderHeader.Common.fOrderFlags = OF_BLOCKER;
//
// Copy the rect, converting to inclusive Virtual Desktop
// coords.
//
pSaveBitmapOrder->nLeftRect = lpRect->left; pSaveBitmapOrder->nTopRect = lpRect->top; pSaveBitmapOrder->nRightRect = lpRect->right - 1; pSaveBitmapOrder->nBottomRect = lpRect->bottom - 1;
pSaveBitmapOrder->SavedBitmapPosition = g_ssiRemoteSSBState.pelsSaved;
//
// Store the relevant details in the current entry of the
// local SSB structure.
//
CURRENT_LOCAL_SSB_STATE.remoteSavedPosition = pSaveBitmapOrder->SavedBitmapPosition;
CURRENT_LOCAL_SSB_STATE.remotePelsRequired = cRemotePelsRequired;
//
// Update the count of remote pels saved.
//
g_ssiRemoteSSBState.pelsSaved += cRemotePelsRequired;
//
// The operation rectangle is NULL.
//
pOrder->OrderHeader.Common.rcsDst.left = 1; pOrder->OrderHeader.Common.rcsDst.right = 0; pOrder->OrderHeader.Common.rcsDst.top = 1; pOrder->OrderHeader.Common.rcsDst.bottom = 0;
break;
case ONBOARD_RESTORE: //
// Update the remote pel count first. Even if we fail to send
// the order we want to free up the remote pels.
//
g_ssiRemoteSSBState.pelsSaved -= CURRENT_LOCAL_SSB_STATE.remotePelsRequired;
//
// Allocate memory for the order.
//
pOrder = OA_DDAllocOrderMem(sizeof(SAVEBITMAP_ORDER), 0); if (!pOrder) DC_QUIT;
//
// Store the drawing order data.
//
pSaveBitmapOrder = (LPSAVEBITMAP_ORDER)pOrder->abOrderData;
pSaveBitmapOrder->type = LOWORD(ORD_SAVEBITMAP); pSaveBitmapOrder->Operation = SV_RESTOREBITS;
//
// The order can spoil others (it is opaque).
// It is not SPOILABLE because we want to keep the remote
// save level in a consistent state.
//
pOrder->OrderHeader.Common.fOrderFlags = OF_SPOILER;
//
// Copy the rect, converting to inclusive Virtual Desktop
// coords.
//
pSaveBitmapOrder->nLeftRect = lpRect->left; pSaveBitmapOrder->nTopRect = lpRect->top; pSaveBitmapOrder->nRightRect = lpRect->right - 1; pSaveBitmapOrder->nBottomRect = lpRect->bottom - 1;
pSaveBitmapOrder->SavedBitmapPosition = CURRENT_LOCAL_SSB_STATE.remoteSavedPosition;
//
// The operation rectangle is also the bounding rectangle of
// the order.
//
pOrder->OrderHeader.Common.rcsDst.left = (TSHR_INT16)pSaveBitmapOrder->nLeftRect; pOrder->OrderHeader.Common.rcsDst.right = (TSHR_INT16)pSaveBitmapOrder->nRightRect; pOrder->OrderHeader.Common.rcsDst.top = (TSHR_INT16)pSaveBitmapOrder->nTopRect; pOrder->OrderHeader.Common.rcsDst.bottom = (TSHR_INT16)pSaveBitmapOrder->nBottomRect; break;
default: ERROR_OUT(( "Unexpected wCommand(%d)", wCommand)); DC_QUIT; }
TRACE_OUT(( "SaveBitmap op %d pos %ld rect %d %d %d %d", pSaveBitmapOrder->Operation, pSaveBitmapOrder->SavedBitmapPosition, pSaveBitmapOrder->nLeftRect, pSaveBitmapOrder->nTopRect, pSaveBitmapOrder->nRightRect, pSaveBitmapOrder->nBottomRect ));
//
// Add the order to the order list.
// We deliberately do not call OA_DDClipAndAddOrder() because the
// SaveBitmap order is never clipped.
//
OA_DDAddOrder(pOrder, NULL); rc = TRUE;
DC_EXIT_POINT: DebugExitBOOL(SSISendSaveBitmapOrder, rc); return(rc); }
//
// SSISaveBits()
//
// This attemps to save the SPB into our stack. If we can't save it, no
// big deal--we'll fail the restore and that info will go as screen data.
//
// NOTE THAT THIS ROUTINE IS IN OPPOSITE FROM WIN95. In Win95, we always
// return FALSE from save so that USER always uses bitmaps for save bits and
// we can track them. In NT we always return TRUE from save because we
// can't track USER bitmaps.
//
// ALWAYS RETURN TRUE FROM THIS FUNCTION
//
// If FALSE is returned on a Display Driver SaveBits operation then Windows
// (USER) simulates the SaveBits call using BitBlts and DOES NOT make a
// corresponding RestoreBits call. This makes it impossible for us to
// correctly track the drawing operations (the restore operation is a
// bitblt on a task that may not have been tracked) - and we can end up
// with unrestored areas on the remote.
//
// Therefore this routine should always return TRUE (apart from when
// something very very unexpected happens). In the cases where we haven't
// saved the data we simply note the fact by storing ST_FAILED_TO_SAVE in
// our local SSB state structure. Because we return TRUE, we get a
// RestoreBits call and, seeing that the Save failed (by looking in the
// local SSB state structure), we _then_ return FALSE to indicate that the
// Restore failed which causes Windows to invalidate and repaint the
// affected area.
//
//
BOOL SSISaveBits(LPRECT lpRect) { DebugEntry(SSISaveBits);
//
// We should never have unbalanced save/restore operations
//
ASSERT(g_ssiLocalSSBState.saveLevel >= 0);
//
// Are we out of space?
//
if (g_ssiLocalSSBState.saveLevel >= SSB_MAX_SAVE_LEVEL) { TRACE_OUT(( "saveLevel(%d) exceeds maximum", g_ssiLocalSSBState.saveLevel)); DC_QUIT; }
//
// If the rectangle to be saved intersects the current SDA then we will
// have to force a repaint on the restore. This is because orders are
// always sent before Screen Data, so if we sent a SAVEBITS order at
// this point, we would not save the intersecting Screen Data.
//
// Otherwise mark the bits as saved (we don't have to do anything since
// we are a chained display driver).
//
if (OE_RectIntersectsSDA(lpRect)) { CURRENT_LOCAL_SSB_STATE.saveType = ST_FAILED_TO_SAVE; } else { CURRENT_LOCAL_SSB_STATE.saveType = ST_SAVED_BY_DISPLAY_DRIVER; }
//
// Store the rectangle saved
//
CURRENT_LOCAL_SSB_STATE.hbmpSave = NULL; CURRENT_LOCAL_SSB_STATE.rect = *lpRect;
//
// If the bits were successfully saved then we can try to send the
// SaveBits command as an order.
//
if (CURRENT_LOCAL_SSB_STATE.saveType != ST_FAILED_TO_SAVE) { CURRENT_LOCAL_SSB_STATE.fSavedRemotely = SSISendSaveBitmapOrder(lpRect, ONBOARD_SAVE); } else { //
// We didn't manage to save it. No point in trying to save the
// bitmap remotely.
//
TRACE_OUT(( "Keep track of failed save for restore later")); CURRENT_LOCAL_SSB_STATE.fSavedRemotely = FALSE; }
//
// Update the save level
// NOTE this now points to the NEXT free slot
//
g_ssiLocalSSBState.saveLevel++; TRACE_OUT(("SSISaveBits:")); TRACE_OUT((" saveLevel is %d", g_ssiLocalSSBState.saveLevel)); TRACE_OUT((" pelsSaved is %d", g_ssiRemoteSSBState.pelsSaved));
DC_EXIT_POINT: DebugExitBOOL(SSISaveBits, TRUE); return(TRUE); }
//
// FUNCTION: SSIFindSlotAndDiscardAbove
//
// DESCRIPTION:
//
// Finds the top slot in the SSB stack which matches lpRect and updates
// g_ssiLocalSSBState.saveLevel to index it.
//
// PARAMETERS:
//
// lpRect - the SSB rectangle
//
// RETURNS: TRUE if a match was found, FALSE otherwise
//
//
BOOL SSIFindSlotAndDiscardAbove(LPRECT lpRect) { int i; int iNewSaveLevel; BOOL rc = FALSE;
DebugEntry(SSIFindSlotAndDiscardAbove);
//
// Look for this SPB. If we find it, then discard the entries after
// it in our stack.
//
iNewSaveLevel = g_ssiLocalSSBState.saveLevel;
//
// Find the bits we are trying to restore
//
for (i = 0; i < g_ssiLocalSSBState.saveLevel; i++) { if (rc) { //
// We found this SPB, so we are discarding all entries after
// it in the stack. Subtract the saved pixels count for this
// dude.
//
g_ssiRemoteSSBState.pelsSaved -= g_ssiLocalSSBState.saveState[i].remotePelsRequired; } else if ((g_ssiLocalSSBState.saveState[i].rect.left == lpRect->left) && (g_ssiLocalSSBState.saveState[i].rect.right == lpRect->right) && (g_ssiLocalSSBState.saveState[i].rect.top == lpRect->top) && (g_ssiLocalSSBState.saveState[i].rect.bottom == lpRect->bottom) ) { //
// Found the one we were looking for
//
TRACE_OUT(("Found SPB at slot %d", i));
iNewSaveLevel = i; rc = TRUE; } }
g_ssiLocalSSBState.saveLevel = iNewSaveLevel;
TRACE_OUT(("SSIFindSlotAndDiscardAbove:")); TRACE_OUT((" saveLevel is %d", iNewSaveLevel)); TRACE_OUT((" pelsSaved is %d", g_ssiRemoteSSBState.pelsSaved));
DebugExitBOOL(SSIFindSlotAndDiscardAbove, rc); return(rc); }
//
// FUNCTION: SSIRestoreBits
//
// DESCRIPTION:
//
// Attempts to restore the specified screen rectangle bits (using the same
// scheme as we previously used to save the bits: either the Display Driver
// our SaveBitmap simulation).
//
// If the bits were saved remotely then a RestoreBits order is sent to
// restore the remote bits.
//
// PARAMETERS:
//
// lpRect - pointer to the rectangle coords (EXCLUSIVE screen coords).
//
// RETURNS:
//
// TRUE or FALSE - this will be returned to Windows as the return code of
// the SaveScreenBitmap call.
//
// Note: if FALSE is returned on a RestoreBits operation then Windows will
// restore the screen by invalidating the area to be restored.
//
//
BOOL SSIRestoreBits(LPRECT lpRect) { BOOL rc = FALSE;
DebugEntry(SSIRestoreBits);
ASSERT(g_ssiLocalSSBState.saveLevel >= 0);
//
// Can we find the SPB?
//
if (SSIFindSlotAndDiscardAbove(lpRect)) { if (CURRENT_LOCAL_SSB_STATE.fSavedRemotely) { //
// The bits were saved remotely, so send and order.
//
rc = SSISendSaveBitmapOrder(lpRect, ONBOARD_RESTORE); } else { //
// We failed to save the bitmap remotely originally, so now
// we need to return FALSE so that BitBlt() will accumulate
// screen data in the area.
//
TRACE_OUT(( "No remote save, force repaint")); }
if (g_ssiLocalSSBState.saveLevel == 0) { g_ssiRemoteSSBState.pelsSaved = 0; }
TRACE_OUT(("SSIRestoreBits:")); TRACE_OUT((" saveLevel is %d", g_ssiLocalSSBState.saveLevel)); TRACE_OUT((" pelsSaved is %d", g_ssiRemoteSSBState.pelsSaved)); }
DebugExitBOOL(SSIRestoreBits, rc); return(rc); }
//
// FUNCTION: SSIDiscardBits
//
// DESCRIPTION:
//
// Attempts to discard the specified screen rectangle bits (using the same
// scheme as we previously used to save the bits: either the Display Driver
// our SaveBitmap simulation).
//
// PARAMETERS:
//
// lpRect - pointer to the rectangle coords (EXCLUSIVE screen coords).
//
// RETURNS:
//
// TRUE or FALSE - this will be returned to Windows as the return code of
// the SaveScreenBitmap call.
//
//
BOOL SSIDiscardBits(LPRECT lpRect) { BOOL rc = TRUE;
DebugEntry(SSIDiscardBits);
//
// SS_FREE (discard) isn't called with a rectangle. It is used to
// discard the most recent save.
//
if (g_ssiLocalSSBState.saveLevel > 0) { --g_ssiLocalSSBState.saveLevel;
//
// The save level is now the index to this entry. Since we are
// about to free it, this will be the place the next SAVE goes
// into.
//
//
// If the bits were saved remotely then send a DISCARDBITS order.
//
if (CURRENT_LOCAL_SSB_STATE.fSavedRemotely) { //
// NOTE that SSISendSaveBitmapOrder() for DISCARD doesn't have
// a side effect, we can just pass in the address of the rect
// of the SPB we stored.
//
SSISendSaveBitmapOrder(lpRect, ONBOARD_DISCARD); }
if (g_ssiLocalSSBState.saveLevel == 0) { g_ssiRemoteSSBState.pelsSaved = 0; }
TRACE_OUT(("SSIDiscardBits:")); TRACE_OUT((" saveLevel is %d", g_ssiLocalSSBState.saveLevel)); TRACE_OUT((" pelsSaved is %d", g_ssiRemoteSSBState.pelsSaved)); }
DebugExitBOOL(SSIDiscardBits, rc); return(rc); }
//
// FUNCTION: SSIRemotePelsRequired
//
// DESCRIPTION:
//
// Returns the number of remote pels required to store the supplied
// rectangle, taking account of the Save Bitmap granularity.
//
// PARAMETERS:
//
// lpRect - pointer to rectangle position in EXCLUSIVE screen coordinates.
//
// RETURNS: Number of remote pels required.
//
//
DWORD SSIRemotePelsRequired(LPRECT lpRect) { UINT rectWidth = 0; UINT rectHeight = 0; UINT xGranularity = 1; UINT yGranularity = 1; DWORD rc;
DebugEntry(SSIRemotePelsRequired);
ASSERT(lpRect != NULL);
//
// Calculate the supplied rectangle size (it is in EXCLUSIVE coords).
//
rectWidth = lpRect->right - lpRect->left; rectHeight = lpRect->bottom - lpRect->top;
xGranularity = g_ssiLocalSSBState.xGranularity; yGranularity = g_ssiLocalSSBState.yGranularity;
rc = ((DWORD)(rectWidth + (xGranularity-1))/xGranularity * xGranularity) * ((DWORD)(rectHeight + (yGranularity-1))/yGranularity * yGranularity);
//
// Return the pels required in the remote SaveBits bitmap to handle
// this rectangle, taking account of its granularity.
//
DebugExitDWORD(SSIRemotePelsRequired, rc); return(rc); }
//
// FUNCTION: SSISetNewCapabilities
//
// DESCRIPTION:
//
// Set the new SSI related capabilities
//
// RETURNS:
//
// NONE
//
// PARAMETERS:
//
// pDataIn - pointer to the input buffer
//
//
void SSISetNewCapabilities(LPSSI_NEW_CAPABILITIES pCapabilities) { DebugEntry(SSISetNewCapabilities);
//
// Copy the data from the Share Core.
//
g_ssiSaveBitmapSize = pCapabilities->sendSaveBitmapSize;
g_ssiLocalSSBState.xGranularity = pCapabilities->xGranularity;
g_ssiLocalSSBState.yGranularity = pCapabilities->yGranularity;
TRACE_OUT(( "SSI caps: Size %ld X gran %hd Y gran %hd", g_ssiSaveBitmapSize, g_ssiLocalSSBState.xGranularity, g_ssiLocalSSBState.yGranularity));
DebugExitVOID(SSISetNewCapabilities); }
|