953 lines
24 KiB
C++
953 lines
24 KiB
C++
#include "precomp.h"
|
||
|
||
|
||
//
|
||
// USR.CPP
|
||
// Update Sender/Receiver
|
||
//
|
||
// Copyright(c) Microsoft 1997-
|
||
//
|
||
|
||
#define MLZ_FILE_ZONE ZONE_NET
|
||
|
||
//
|
||
// USR strategy when network packets cannot be allocated.
|
||
//
|
||
// The USR sends three different types of packets:
|
||
//
|
||
// - font negotiation packets
|
||
// - order packets
|
||
// - screen data packets
|
||
//
|
||
// Font negotiation packets are sent by the USR_Periodic function. If the
|
||
// packet cannot be sent first time then the USR will retry (on each call
|
||
// to the USR_Periodic function) until it has succesfully sent the packet.
|
||
// The only dependency on font packets is that until the systems in a share
|
||
// have been able to exchange font negotiation packets they will not be
|
||
// able to send text output as orders - they will simply send text as
|
||
// screen data.
|
||
//
|
||
// The USR function UP_SendUpdates sends all update packets (both order
|
||
// packets and screen data packets). Order packets must be sent first and
|
||
// screen data packets are only sent if all the orders have been
|
||
// succesfully sent. When sending screen data packets they are only sent
|
||
// if the corresponding palette packets have been sent - otherwise they are
|
||
// re-absorbed into the screen data to be transmitted later.
|
||
//
|
||
//
|
||
|
||
|
||
|
||
//
|
||
// USR_ShareStarting()
|
||
// Creates share resources
|
||
//
|
||
BOOL ASShare::USR_ShareStarting(void)
|
||
{
|
||
BOOL rc = FALSE;
|
||
BITMAPINFOHEADER bitmapInfo;
|
||
HDC hdcDesktop = NULL;
|
||
|
||
DebugEntry(ASShare::USR_ShareStarting);
|
||
|
||
//
|
||
// Set the black bitmap data and hatch bitmap data flags which can be
|
||
// used as an aid for debugging. These are false unless there is an
|
||
// entry in the ini file to override them.
|
||
//
|
||
COM_ReadProfInt(DBG_INI_SECTION_NAME, USR_INI_HATCHSCREENDATA, FALSE,
|
||
&m_usrHatchScreenData);
|
||
|
||
COM_ReadProfInt(DBG_INI_SECTION_NAME, USR_INI_HATCHBMPORDERS, FALSE,
|
||
&m_usrHatchBitmaps);
|
||
|
||
//
|
||
// Double-check the order packet sizes are OK
|
||
//
|
||
ASSERT(SMALL_ORDER_PACKET_SIZE < LARGE_ORDER_PACKET_SIZE);
|
||
ASSERT(LARGE_ORDER_PACKET_SIZE <= TSHR_MAX_SEND_PKT);
|
||
|
||
//
|
||
// Allocate a chunk of memory big enough to contain the largest packet
|
||
// an application can receive from the network. This is required to
|
||
// store uncompressed bitmaps and repeated general use by the USR.
|
||
//
|
||
m_usrPBitmapBuffer = new BYTE[TSHR_MAX_SEND_PKT];
|
||
if (!m_usrPBitmapBuffer)
|
||
{
|
||
ERROR_OUT(("USR_ShareStarted: failed to alloc memory m_usrPBitmapBuffer"));
|
||
|
||
//
|
||
// To continue the share would cause a GP fault as soon as anything
|
||
// tries to use this buffer so delete this person from the share.
|
||
// The reason is lack of resources.
|
||
//
|
||
DC_QUIT;
|
||
}
|
||
|
||
//
|
||
// Create the transfer bitmaps for screen data and bitmap orders
|
||
//
|
||
|
||
USR_InitDIBitmapHeader(&bitmapInfo, g_usrScreenBPP);
|
||
|
||
//
|
||
// Create the transfer bitmaps. These are used for both outgoing and
|
||
// incoming data.
|
||
//
|
||
// To avoid having to recreate the bitmaps whenever the parties in the
|
||
// share change, (and hence the various bpp may change) from r2.0 we
|
||
// now use a fixed vertical size and if necessary can handle incoming
|
||
// bitmaps in multiple bands.
|
||
//
|
||
// These are the resulting heights for 256 pixel wide segments.
|
||
//
|
||
// TSHR_MAX_SEND_PKT - sizeof(DATAPACKETHEADER) / bytes per scan line
|
||
//
|
||
// 4bpp --> (32000 - 4) / 128 = 249
|
||
// 8bpp --> (32000 - 4) / 256 = 124
|
||
// 24bpp --> (32000 - 4) / 768 = 41
|
||
//
|
||
//
|
||
|
||
//
|
||
// NOTE:
|
||
// The VGA driver has a problem when the bitmap ends exactly on a 4K
|
||
// (page) boundary. So we create the bitmaps one pixel taller.
|
||
//
|
||
// BOGUS BUGBUG LAURABU
|
||
// Is this really true anymore? If not, save some memory and make these
|
||
// the right size.
|
||
//
|
||
|
||
hdcDesktop = GetDC(NULL);
|
||
if (!hdcDesktop)
|
||
{
|
||
ERROR_OUT(("USR_ShareStarting: can't get screen DC"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
// The large bitmap is short. The rest are medium height.
|
||
bitmapInfo.biWidth = 1024;
|
||
bitmapInfo.biHeight = MaxBitmapHeight(MEGA_WIDE_X_SIZE, 8) + 1;
|
||
m_usrBmp1024 = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
|
||
DIB_RGB_COLORS);
|
||
if (!m_usrBmp1024)
|
||
{
|
||
ERROR_OUT(("USR_ShareStarting: failed to reate m_usrBmp1024"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
bitmapInfo.biHeight = MaxBitmapHeight(MEGA_X_SIZE, 8) + 1;
|
||
|
||
bitmapInfo.biWidth = 256;
|
||
m_usrBmp256 = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
|
||
DIB_RGB_COLORS);
|
||
if (!m_usrBmp256)
|
||
{
|
||
ERROR_OUT(("USR_ShareStarting: failed to create m_usrBmp256"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
bitmapInfo.biWidth = 128;
|
||
m_usrBmp128 = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
|
||
DIB_RGB_COLORS);
|
||
if (!m_usrBmp128)
|
||
{
|
||
ERROR_OUT(("USR_ShareStarting: failed to create m_usrBmp128"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
bitmapInfo.biWidth = 112;
|
||
m_usrBmp112 = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
|
||
DIB_RGB_COLORS);
|
||
if (!m_usrBmp112)
|
||
{
|
||
ERROR_OUT(("USR_ShareStarting: failed to create m_usrBmp112"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
bitmapInfo.biWidth = 96;
|
||
m_usrBmp96 = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
|
||
DIB_RGB_COLORS);
|
||
if (!m_usrBmp96)
|
||
{
|
||
ERROR_OUT(("USR_ShareStarting: failed to create m_usrBmp96"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
bitmapInfo.biWidth = 80;
|
||
m_usrBmp80 = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
|
||
DIB_RGB_COLORS);
|
||
if (!m_usrBmp80)
|
||
{
|
||
ERROR_OUT(("USR_ShareStarting: failed to create m_usrBmp80"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
bitmapInfo.biWidth = 64;
|
||
m_usrBmp64 = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
|
||
DIB_RGB_COLORS);
|
||
if (!m_usrBmp64)
|
||
{
|
||
ERROR_OUT(("USR_ShareStarting: failed to create m_usrBmp64"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
bitmapInfo.biWidth = 48;
|
||
m_usrBmp48 = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
|
||
DIB_RGB_COLORS);
|
||
if (!m_usrBmp48)
|
||
{
|
||
ERROR_OUT(("USR_ShareStarting: failed to create m_usrBmp48"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
bitmapInfo.biWidth = 32;
|
||
m_usrBmp32 = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
|
||
DIB_RGB_COLORS);
|
||
if (!m_usrBmp32)
|
||
{
|
||
ERROR_OUT(("USR_ShareStarting: failed to create m_usrBmp32"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
bitmapInfo.biWidth = 16;
|
||
m_usrBmp16 = CreateDIBitmap(hdcDesktop, &bitmapInfo, 0, NULL, NULL,
|
||
DIB_RGB_COLORS);
|
||
if (!m_usrBmp16)
|
||
{
|
||
ERROR_OUT(("USR_ShareStarting: failed to create m_usrBmp16"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
rc = TRUE;
|
||
|
||
DC_EXIT_POINT:
|
||
if (hdcDesktop)
|
||
{
|
||
ReleaseDC(NULL, hdcDesktop);
|
||
}
|
||
|
||
DebugExitBOOL(ASShare::USR_ShareStarting, rc);
|
||
return(rc);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// USR_ShareEnded()
|
||
// Cleans up share resources
|
||
//
|
||
void ASShare::USR_ShareEnded(void)
|
||
{
|
||
DebugEntry(ASShare::USR_ShareEnded);
|
||
|
||
//
|
||
// Delete Transfer Bitmaps.
|
||
//
|
||
if (m_usrBmp1024)
|
||
{
|
||
DeleteBitmap(m_usrBmp1024);
|
||
m_usrBmp1024= NULL;
|
||
}
|
||
|
||
if (m_usrBmp256)
|
||
{
|
||
DeleteBitmap(m_usrBmp256);
|
||
m_usrBmp256 = NULL;
|
||
}
|
||
|
||
if (m_usrBmp128)
|
||
{
|
||
DeleteBitmap(m_usrBmp128);
|
||
m_usrBmp128 = NULL;
|
||
}
|
||
|
||
if (m_usrBmp112)
|
||
{
|
||
DeleteBitmap(m_usrBmp112);
|
||
m_usrBmp112 = NULL;
|
||
}
|
||
|
||
if (m_usrBmp96)
|
||
{
|
||
DeleteBitmap(m_usrBmp96);
|
||
m_usrBmp96 = NULL;
|
||
}
|
||
|
||
if (m_usrBmp80)
|
||
{
|
||
DeleteBitmap(m_usrBmp80);
|
||
m_usrBmp80 = NULL;
|
||
}
|
||
|
||
if (m_usrBmp64)
|
||
{
|
||
DeleteBitmap(m_usrBmp64);
|
||
m_usrBmp64 = NULL;
|
||
}
|
||
|
||
if (m_usrBmp48)
|
||
{
|
||
DeleteBitmap(m_usrBmp48);
|
||
m_usrBmp48 = NULL;
|
||
}
|
||
|
||
if (m_usrBmp32)
|
||
{
|
||
DeleteBitmap(m_usrBmp32);
|
||
m_usrBmp32 = NULL;
|
||
}
|
||
|
||
if (m_usrBmp16)
|
||
{
|
||
DeleteBitmap(m_usrBmp16);
|
||
m_usrBmp16 = NULL;
|
||
}
|
||
|
||
//
|
||
// Free Bitmap Buffer.
|
||
//
|
||
if (m_usrPBitmapBuffer != NULL)
|
||
{
|
||
delete[] m_usrPBitmapBuffer;
|
||
m_usrPBitmapBuffer = NULL;
|
||
}
|
||
|
||
DebugExitVOID(ASShare::USR_ShareEnded);
|
||
}
|
||
|
||
|
||
|
||
|
||
//
|
||
// USR_RecalcCaps()
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Enumerates the bitmap capabilities of all parties currently in the
|
||
// share, and determines the common capabilities.
|
||
//
|
||
// PARAMETERS: None.
|
||
//
|
||
// RETURNS: TRUE if there are good common caps, or false on failure (which
|
||
// has the effect of rejecting a new party from joining the share).
|
||
//
|
||
//
|
||
void ASShare::USR_RecalcCaps(BOOL fJoiner)
|
||
{
|
||
ASPerson * pasT;
|
||
UINT capsMaxBPP;
|
||
UINT capsMinBPP;
|
||
UINT capsSupports4BPP;
|
||
UINT capsSupports8BPP;
|
||
UINT capsSupports24BPP;
|
||
UINT capsOldBPP;
|
||
|
||
DebugEntry(ASShare::USR_RecalcCaps);
|
||
|
||
if (!m_pHost)
|
||
{
|
||
// Nothing to do
|
||
DC_QUIT;
|
||
}
|
||
|
||
ValidatePerson(m_pasLocal);
|
||
|
||
capsOldBPP = m_pHost->m_usrSendingBPP;
|
||
|
||
//
|
||
// Init the caps
|
||
//
|
||
capsSupports4BPP = m_pasLocal->cpcCaps.screen.capsSupports4BPP;
|
||
capsSupports8BPP = m_pasLocal->cpcCaps.screen.capsSupports8BPP;
|
||
capsSupports24BPP = m_pasLocal->cpcCaps.screen.capsSupports24BPP;
|
||
capsMaxBPP = 0;
|
||
capsMinBPP = 0xFFFFFFFF;
|
||
|
||
for (pasT = m_pasLocal->pasNext; pasT != NULL; pasT = pasT->pasNext)
|
||
{
|
||
//
|
||
// Check the bpps supported.
|
||
//
|
||
if (pasT->cpcCaps.screen.capsSupports4BPP != CAPS_SUPPORTED)
|
||
{
|
||
capsSupports4BPP = CAPS_UNSUPPORTED;
|
||
}
|
||
if (pasT->cpcCaps.screen.capsSupports8BPP != CAPS_SUPPORTED)
|
||
{
|
||
capsSupports8BPP = CAPS_UNSUPPORTED;
|
||
}
|
||
if (pasT->cpcCaps.screen.capsSupports24BPP != CAPS_SUPPORTED)
|
||
{
|
||
capsSupports24BPP = CAPS_UNSUPPORTED;
|
||
}
|
||
|
||
//
|
||
// Set the combined bpp to the maximum so far found.
|
||
// (If we send data at this bpp then one of the remote systems can
|
||
// usefully process this number of colors).
|
||
//
|
||
capsMaxBPP = max(capsMaxBPP, pasT->cpcCaps.screen.capsBPP);
|
||
capsMinBPP = min(capsMinBPP, pasT->cpcCaps.screen.capsBPP);
|
||
}
|
||
|
||
//
|
||
// Now figure out what BPP we will transmit at.
|
||
//
|
||
//
|
||
// Limit the combined caps bpp (which is currently the maximum bpp that
|
||
// any system in the share wants) to the local bpp, since there is no
|
||
// point sending at higher bpp than the local machine has.
|
||
//
|
||
capsMaxBPP = min(capsMaxBPP, g_usrScreenBPP);
|
||
if (!capsMaxBPP)
|
||
capsMaxBPP = g_usrScreenBPP;
|
||
|
||
capsMinBPP = min(capsMinBPP, g_usrScreenBPP);
|
||
|
||
//
|
||
// m_usrSendingBPP is most often going to be 8. So it's easier to assume
|
||
// it, then check for cases where it won't be.
|
||
//
|
||
m_pHost->m_usrSendingBPP = 8;
|
||
|
||
if ((capsMaxBPP <= 4) && (capsSupports4BPP == CAPS_SUPPORTED))
|
||
{
|
||
m_pHost->m_usrSendingBPP = 4;
|
||
}
|
||
else if ((capsMinBPP >= 24) &&
|
||
(g_asSettings & SHP_SETTING_TRUECOLOR) &&
|
||
(capsSupports24BPP == CAPS_SUPPORTED))
|
||
{
|
||
m_pHost->m_usrSendingBPP = 24;
|
||
}
|
||
|
||
if (capsOldBPP != m_pHost->m_usrSendingBPP)
|
||
{
|
||
//
|
||
// If switching to/from palettized, we need to update the
|
||
// "need to send palette" flag. Note that 4bpp is also a
|
||
// palettized color depth.
|
||
//
|
||
if ((capsOldBPP <= 8) && (m_pHost->m_usrSendingBPP > 8))
|
||
m_pHost->m_pmMustSendPalette = FALSE;
|
||
else if ((capsOldBPP > 8) && (m_pHost->m_usrSendingBPP <= 8))
|
||
m_pHost->m_pmMustSendPalette = TRUE;
|
||
|
||
#ifdef _DEBUG
|
||
if (capsOldBPP == 24)
|
||
{
|
||
WARNING_OUT(("TRUE COLOR SHARING is now FINISHED"));
|
||
}
|
||
else if (m_pHost->m_usrSendingBPP == 24)
|
||
{
|
||
WARNING_OUT(("TRUE COLOR SHARING is now STARTING"));
|
||
}
|
||
#endif
|
||
|
||
if (!fJoiner)
|
||
{
|
||
//
|
||
// Sending BPP changed. Repaint all shared stuff.
|
||
// NOTE:
|
||
// We recalc the sendBPP at three points:
|
||
// * When we start to share
|
||
// * When a person joins
|
||
// * When a person leaves
|
||
//
|
||
// In the first two cases, shared stuff is repainted,
|
||
// so everybody gets the new sendBPP data. Only in the
|
||
// leave case do we need to force this.
|
||
//
|
||
m_pHost->HET_RepaintAll();
|
||
}
|
||
}
|
||
|
||
DC_EXIT_POINT:
|
||
DebugExitVOID(ASShare::USR_RecalcCaps);
|
||
}
|
||
|
||
|
||
//
|
||
// USR_HostStarting()
|
||
//
|
||
BOOL ASHost::USR_HostStarting(void)
|
||
{
|
||
BOOL rc = FALSE;
|
||
HDC hdc;
|
||
|
||
DebugEntry(ASHost::USR_HostStarting);
|
||
|
||
//
|
||
// Create scratch DC
|
||
//
|
||
hdc = GetDC(NULL);
|
||
if (!hdc)
|
||
{
|
||
ERROR_OUT(("USR_HostStarting: can't get screen DC"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
m_usrWorkDC = CreateCompatibleDC(hdc);
|
||
ReleaseDC(NULL, hdc);
|
||
|
||
if (!m_usrWorkDC)
|
||
{
|
||
ERROR_OUT(("USR_HostStarting: can't create m_usrWorkDC"));
|
||
DC_QUIT;
|
||
}
|
||
|
||
m_pShare->USR_RecalcCaps(TRUE);
|
||
|
||
rc = TRUE;
|
||
|
||
DC_EXIT_POINT:
|
||
DebugExitBOOL(ASHost::USR_HostStarting, rc);
|
||
return(rc);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// USR_HostEnded()
|
||
//
|
||
void ASHost::USR_HostEnded(void)
|
||
{
|
||
DebugEntry(ASHost::USR_HostEnded);
|
||
|
||
if (m_usrWorkDC != NULL)
|
||
{
|
||
DeleteDC(m_usrWorkDC);
|
||
m_usrWorkDC = NULL;
|
||
}
|
||
|
||
DebugExitVOID(ASHost::USR_HostEnded);
|
||
}
|
||
|
||
|
||
|
||
|
||
//
|
||
// USR_ScrollDesktop
|
||
//
|
||
void ASShare::USR_ScrollDesktop
|
||
(
|
||
ASPerson * pasPerson,
|
||
int xNew,
|
||
int yNew
|
||
)
|
||
{
|
||
int xOld;
|
||
int yOld;
|
||
|
||
DebugEntry(ASShare::USR_ScrollDesktop);
|
||
|
||
ValidateView(pasPerson);
|
||
|
||
//
|
||
// If the origin has changed then do the update.
|
||
//
|
||
xOld = pasPerson->m_pView->m_dsScreenOrigin.x;
|
||
yOld = pasPerson->m_pView->m_dsScreenOrigin.y;
|
||
|
||
if ((xOld != xNew) || (yOld != yNew))
|
||
{
|
||
pasPerson->m_pView->m_dsScreenOrigin.x = xNew;
|
||
pasPerson->m_pView->m_dsScreenOrigin.y = yNew;
|
||
|
||
//
|
||
// We must ensure that data written to the ScreenBitmap is not
|
||
// clipped
|
||
//
|
||
OD_ResetRectRegion(pasPerson);
|
||
|
||
//
|
||
// Offset the existing bitmap by the change in desktop origins.
|
||
//
|
||
|
||
BitBlt(pasPerson->m_pView->m_usrDC,
|
||
0,
|
||
0,
|
||
pasPerson->cpcCaps.screen.capsScreenWidth,
|
||
pasPerson->cpcCaps.screen.capsScreenHeight,
|
||
pasPerson->m_pView->m_usrDC,
|
||
xNew - xOld,
|
||
yNew - yOld,
|
||
SRCCOPY);
|
||
|
||
//
|
||
// Offset the shadow cursor pos -- same place on remote screen
|
||
// but now different place in VD
|
||
//
|
||
pasPerson->cmPos.x += xNew - xOld;
|
||
pasPerson->cmPos.y += yNew - yOld;
|
||
|
||
//
|
||
// Repaint the view
|
||
//
|
||
VIEW_InvalidateRgn(pasPerson, NULL);
|
||
}
|
||
|
||
DebugExitVOID(ASShare::USR_ScrollDesktop);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// FUNCTION: USR_InitDIBitmapHeader
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Initialises a Device Independent bitmap header to be the given bits per
|
||
// pel.
|
||
//
|
||
// PARAMETERS:
|
||
//
|
||
// pbh - pointer to the bitmap header to be initialised.
|
||
// bpp - bpp to be used for the bitmap
|
||
//
|
||
// RETURNS: VOID
|
||
//
|
||
//
|
||
void ASShare::USR_InitDIBitmapHeader
|
||
(
|
||
BITMAPINFOHEADER * pbh,
|
||
UINT bpp
|
||
)
|
||
{
|
||
DebugEntry(ASShare::USR_InitDIBitmapHeader);
|
||
|
||
pbh->biSize = sizeof(BITMAPINFOHEADER);
|
||
pbh->biPlanes = 1;
|
||
pbh->biBitCount = (WORD)bpp;
|
||
pbh->biCompression = BI_RGB;
|
||
pbh->biSizeImage = 0;
|
||
pbh->biXPelsPerMeter = 10000;
|
||
pbh->biYPelsPerMeter = 10000;
|
||
pbh->biClrUsed = 0;
|
||
pbh->biClrImportant = 0;
|
||
|
||
DebugExitVOID(ASShare::USR_InitDIBitmapHeader);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// USR_ViewStarting()
|
||
//
|
||
// Called when someone we're viewing starts to host. We create the desktop
|
||
// bitmap for them plus scratch objects
|
||
//
|
||
BOOL ASShare::USR_ViewStarting(ASPerson * pasPerson)
|
||
{
|
||
BOOL rc;
|
||
|
||
DebugEntry(ASShare::USR_ViewStarting);
|
||
|
||
ValidateView(pasPerson);
|
||
|
||
//
|
||
// Create a bitmap for this new party
|
||
//
|
||
rc = USRCreateRemoteDesktop(pasPerson);
|
||
|
||
DebugExitBOOL(ASShare::USR_ViewStarting, rc);
|
||
return(rc);
|
||
}
|
||
|
||
|
||
//
|
||
// FUNCTION: USRCreateRemoteDesktop
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Creates the shadow bitmap for a remote party.
|
||
//
|
||
// PARAMETERS:
|
||
//
|
||
// personID - person to create the shadow bitmap for.
|
||
//
|
||
// RETURNS: TRUE if successful, FALSE otherwise.
|
||
//
|
||
//
|
||
BOOL ASShare::USRCreateRemoteDesktop(ASPerson * pasPerson)
|
||
{
|
||
BOOL rc = FALSE;
|
||
HDC hdcDesktop = NULL;
|
||
RECT desktopRect;
|
||
|
||
DebugEntry(ASShare::USRCreateRemoteDesktop);
|
||
|
||
ValidateView(pasPerson);
|
||
|
||
ASSERT(pasPerson->m_pView->m_usrDC == NULL);
|
||
ASSERT(pasPerson->m_pView->m_usrBitmap == NULL);
|
||
ASSERT(pasPerson->m_pView->m_usrOldBitmap == NULL);
|
||
|
||
hdcDesktop = GetDC(NULL);
|
||
|
||
//
|
||
// Create the scratch DC
|
||
//
|
||
pasPerson->m_pView->m_usrWorkDC = CreateCompatibleDC(hdcDesktop);
|
||
if (!pasPerson->m_pView->m_usrWorkDC)
|
||
{
|
||
ERROR_OUT(("Couldn't create workDC for person [%d]", pasPerson->mcsID));
|
||
DC_QUIT;
|
||
}
|
||
|
||
//
|
||
// Create the DC that keeps the screen bitmap for this party
|
||
//
|
||
pasPerson->m_pView->m_usrDC = CreateCompatibleDC(hdcDesktop);
|
||
if (!pasPerson->m_pView->m_usrDC)
|
||
{
|
||
ERROR_OUT(("Couldn't create usrDC for person [%d]", pasPerson->mcsID));
|
||
DC_QUIT;
|
||
}
|
||
|
||
//
|
||
// We can't use this person's usrDC, since that currently has a MONO
|
||
// bitmap selected into it.
|
||
//
|
||
pasPerson->m_pView->m_usrBitmap = CreateCompatibleBitmap(hdcDesktop, pasPerson->cpcCaps.screen.capsScreenWidth, pasPerson->cpcCaps.screen.capsScreenHeight);
|
||
if (pasPerson->m_pView->m_usrBitmap == NULL)
|
||
{
|
||
ERROR_OUT(("Couldn't create screen bitmap for [%d]", pasPerson->mcsID));
|
||
DC_QUIT;
|
||
}
|
||
|
||
//
|
||
// Select the screen bitmap into the person's DC, and save the previous
|
||
// 1x1 bitmap away, so we can deselect it when done.
|
||
//
|
||
pasPerson->m_pView->m_usrOldBitmap = SelectBitmap(pasPerson->m_pView->m_usrDC, pasPerson->m_pView->m_usrBitmap);
|
||
|
||
//
|
||
// Fill the Screen Bitmap with grey.
|
||
//
|
||
// In practice the Shadow Window Presenter(SWP) should never display
|
||
// any area of the Screen Bitmap that has not been updated with data
|
||
// from a remote system.
|
||
//
|
||
// Therefore this operation is just "insurance" in case the SWP goes
|
||
// wrong and momentarily displays a non-updated area - a flash of grey
|
||
// is better than a flash of garbage.
|
||
//
|
||
desktopRect.left = 0;
|
||
desktopRect.top = 0;
|
||
desktopRect.right = pasPerson->cpcCaps.screen.capsScreenWidth;
|
||
desktopRect.bottom = pasPerson->cpcCaps.screen.capsScreenHeight;
|
||
|
||
FillRect(pasPerson->m_pView->m_usrDC, &desktopRect, GetSysColorBrush(COLOR_APPWORKSPACE));
|
||
rc = TRUE;
|
||
|
||
DC_EXIT_POINT:
|
||
|
||
if (hdcDesktop != NULL)
|
||
{
|
||
ReleaseDC(NULL, hdcDesktop);
|
||
}
|
||
|
||
DebugExitBOOL(ASShare::USRCreateRemoteDesktop, rc);
|
||
return(rc);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// USR_ViewEnded()
|
||
//
|
||
// Called when person we're viewing stops hosting. We get rid of their
|
||
// desktop bitmap.
|
||
//
|
||
void ASShare::USR_ViewEnded(ASPerson * pasPerson)
|
||
{
|
||
ValidateView(pasPerson);
|
||
|
||
//
|
||
// Delete the desktop bitmap for the party that has left
|
||
//
|
||
USRDeleteRemoteDesktop(pasPerson);
|
||
}
|
||
|
||
|
||
//
|
||
// FUNCTION: USRDeleteRemoteDesktop
|
||
//
|
||
// DESCRIPTION:
|
||
//
|
||
// Deletes a remote party's shadow bitmap.
|
||
//
|
||
// PARAMETERS:
|
||
//
|
||
// personID - party whose shadow bitmap is to be deleted.
|
||
//
|
||
// RETURNS: Nothing.
|
||
//
|
||
//
|
||
void ASShare::USRDeleteRemoteDesktop(ASPerson * pasPerson)
|
||
{
|
||
DebugEntry(ASShare::USRDeleteRemoteDesktop);
|
||
|
||
ValidateView(pasPerson);
|
||
|
||
if (pasPerson->m_pView->m_usrOldBitmap != NULL)
|
||
{
|
||
// Deselect screen bitmap
|
||
SelectBitmap(pasPerson->m_pView->m_usrDC, pasPerson->m_pView->m_usrOldBitmap);
|
||
pasPerson->m_pView->m_usrOldBitmap = NULL;
|
||
}
|
||
|
||
if (pasPerson->m_pView->m_usrBitmap != NULL)
|
||
{
|
||
// Delete the screen bitmap
|
||
DeleteBitmap(pasPerson->m_pView->m_usrBitmap);
|
||
pasPerson->m_pView->m_usrBitmap = NULL;
|
||
}
|
||
|
||
if (pasPerson->m_pView->m_usrDC != NULL)
|
||
{
|
||
//
|
||
// Delete the screen DC. Created objects should have
|
||
// been selected out of it before now.
|
||
//
|
||
DeleteDC(pasPerson->m_pView->m_usrDC);
|
||
pasPerson->m_pView->m_usrDC = NULL;
|
||
}
|
||
|
||
if (pasPerson->m_pView->m_usrWorkDC != NULL)
|
||
{
|
||
DeleteDC(pasPerson->m_pView->m_usrWorkDC);
|
||
pasPerson->m_pView->m_usrWorkDC = NULL;
|
||
}
|
||
|
||
DebugExitVOID(ASShare::USRDeleteRemoteDesktop);
|
||
}
|
||
|
||
|
||
|
||
|
||
//
|
||
// This function is a mess! First because it ought to be an FH API
|
||
// function, and secondly because it mixes portable code and Windows API
|
||
// calls. The details of what is to be done with it are deferred until the
|
||
// UNIX port of FH is designed, though. STOPPRESS! Function replaced by new
|
||
// FH_CreateAndSelectFont, which combines old USR_UseFont and
|
||
// FH_CreateAndSelectFont - you have to write an NT version.
|
||
//
|
||
//
|
||
// USR_UseFont()
|
||
//
|
||
BOOL ASShare::USR_UseFont
|
||
(
|
||
HDC surface,
|
||
HFONT* pHFont,
|
||
TEXTMETRIC* pFontMetrics,
|
||
LPSTR pName,
|
||
UINT codePage,
|
||
UINT MaxHeight,
|
||
UINT Height,
|
||
UINT Width,
|
||
UINT Weight,
|
||
UINT flags
|
||
)
|
||
{
|
||
BOOL rc = FALSE;
|
||
HFONT hNewFont;
|
||
HFONT hOldFont;
|
||
|
||
DebugEntry(ASShare::USR_UseFont);
|
||
|
||
rc = FH_CreateAndSelectFont(surface,
|
||
&hNewFont,
|
||
&hOldFont,
|
||
pName,
|
||
codePage,
|
||
MaxHeight,
|
||
Height,
|
||
Width,
|
||
Weight,
|
||
flags);
|
||
|
||
if (rc == FALSE)
|
||
{
|
||
//
|
||
// Failed to create or select the font.
|
||
//
|
||
DC_QUIT;
|
||
}
|
||
|
||
//
|
||
// Select in the new font which ensures that the old one is deselected.
|
||
//
|
||
// NB. We do not delete the font we are deselecting, rather the old
|
||
// one that was passed to us. This is beacuse multiple components use
|
||
// "surface", and so the deselected font may not be the current
|
||
// component's last font at all - the important thing is that by
|
||
// selecting in the new font we are ensuring that the old font is not
|
||
// the selected one.
|
||
//
|
||
SelectFont(surface, hNewFont);
|
||
if (*pHFont)
|
||
{
|
||
DeleteFont(*pHFont);
|
||
}
|
||
|
||
//
|
||
// If a pointer to font metrics was passed in then we need to query
|
||
// the metrics now.
|
||
//
|
||
if (pFontMetrics)
|
||
GetTextMetrics(surface, pFontMetrics);
|
||
|
||
//
|
||
// Update the record of the last font we selected.
|
||
//
|
||
*pHFont = hNewFont;
|
||
rc = TRUE;
|
||
|
||
DC_EXIT_POINT:
|
||
DebugExitDWORD(ASShare::USR_UseFont, rc);
|
||
return(rc);
|
||
}
|
||
|
||
//
|
||
// USR_ScreenChanged()
|
||
//
|
||
void ASShare::USR_ScreenChanged(ASPerson * pasPerson)
|
||
{
|
||
DebugEntry(ASShare::USR_ScreenChanged);
|
||
|
||
ValidatePerson(pasPerson);
|
||
|
||
pasPerson->cpcCaps.screen.capsScreenWidth = pasPerson->cpcCaps.screen.capsScreenWidth;
|
||
pasPerson->cpcCaps.screen.capsScreenHeight = pasPerson->cpcCaps.screen.capsScreenHeight;
|
||
|
||
if (pasPerson->m_pView)
|
||
{
|
||
//
|
||
// Recreate screen bitmap
|
||
//
|
||
|
||
//
|
||
// Discard the remote users current shadow bitmap
|
||
//
|
||
USRDeleteRemoteDesktop(pasPerson);
|
||
|
||
//
|
||
// Create a new shadow bitmap for remote user that is of the new size
|
||
//
|
||
USRCreateRemoteDesktop(pasPerson);
|
||
}
|
||
|
||
VIEW_ScreenChanged(pasPerson);
|
||
|
||
DebugExitVOID(ASShare::USR_ScreenChanged);
|
||
}
|
||
|
||
|
||
|
||
|