windows-nt/Source/XPSP1/NT/enduser/netmeeting/as/cpi32/swl.cpp
2020-09-26 16:20:57 +08:00

2904 lines
92 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "precomp.h"
//
// SWL.CPP
// Shared Window List
//
// Copyright(c) Microsoft 1997-
//
#define MLZ_FILE_ZONE ZONE_CORE
//
// SWL strategy when network packets are not available
//
// The SWL only sends one type of message - the window structure message.
// When no network packets are available the SWL will drop its current
// packet and remember that the window structure has changed since it was
// last able to send a packet. SWL_Periodic will also return FALSE when
// this happens so that the DCS will know not to send any updates if it
// failed to send a window structure.
//
// This pending of window structure messages is integrated with the
// ignore envelopes where the SWL wants to ignore changes caused by itself
// (or other components if they call the SWL_Begin/EndIgnoreWindowChanges
// functions).
//
//
// SWL strategy for backward compatibility.
//
// The differences between the R2.0 and 3.0 SWL protocol are:
// 1. Tokenless packets.
// 2. No shadows.
//
//
// SWL_PartyLeftShare()
//
void ASShare::SWL_PartyLeftShare(ASPerson * pasPerson)
{
DebugEntry(ASShare::SWL_PartyLeftShare);
ValidatePerson(pasPerson);
//
// 2.x nodes will fake up a packet for a remote leaving with an empty
// window list. That's how they'd nuke shadows for that person, if he
// had been hosting. In so doing, they'd use a new token. We need to
// bump our token value up also so that the next window list we send
// is not dropped.
//
m_swlLastTokenSeen = SWL_CalculateNextToken(m_swlLastTokenSeen);
TRACE_OUT(("SWL_PartyLeftShare: bumped up token to 0x%08x", m_swlLastTokenSeen));
DebugExitVOID(ASShare::SWL_PartyLeftShare);
}
//
// SWL_SyncOutgoing
//
void ASHost::SWL_SyncOutgoing(void)
{
DebugEntry(ASHost::SWL_SyncOutgoing);
//
// Ensure that we send an SWL packet next time we need.
//
m_swlfForceSend = TRUE;
m_swlfSyncing = TRUE;
DebugExitVOID(ASHost::SWL_SyncOutgoing);
}
//
// SWL_HostStarting()
//
BOOL ASHost::SWL_HostStarting(void)
{
BOOL rc = FALSE;
DebugEntry(ASHost::SWL_HostStarting);
//
// Get an atom to use in getting and setting window properties (which
// will give us SWL information about the window).
//
m_swlPropAtom = GlobalAddAtom(SWL_ATOM_NAME);
if (!m_swlPropAtom)
{
ERROR_OUT(( "GlobalAddAtom error %#x", GetLastError()));
DC_QUIT;
}
//
// If this is NT, get the name of our startup desktop
//
if (!g_asWin95)
{
ASSERT(m_aswlOurDesktopName[0] == 0);
GetUserObjectInformation(GetThreadDesktop(g_asMainThreadId),
UOI_NAME, m_aswlOurDesktopName,
sizeof(m_aswlOurDesktopName), NULL);
TRACE_OUT(("Our desktop name is %s", m_aswlOurDesktopName));
}
if (!m_aswlOurDesktopName[0])
{
// Use default name
TRACE_OUT(("Couldn't get desktop name; using %s",
NAME_DESKTOP_DEFAULT));
lstrcpy(m_aswlOurDesktopName, NAME_DESKTOP_DEFAULT);
}
//
// Allocate memory for the window titles. We fix the maximum size of
// window title we will send - task list doesn't scroll horizontally so
// we truncate window titles at MAX_WINDOW_TITLE_SEND. However, we do
// not pad the titles so we try to send as little data as possible.
// Allocate all the segment but the rest of the code does not rely on
// this so we split them into more segments later if need be. The
// memory pointed to by winNames[0] etc looks like this:
//
// For each entry in the corresponding WinStruct which is a window from
// a shared task (and in the same order):
//
// either -
// (char)0xFF - not a `task window' - give it a NULL title
// or -
// a null terminated string up to MAX_WINDOW_TITLE_SEND characters
//
// Note that we don't need full and compact versions because only
// windows which will be in the compact WinStruct will have
// corresponding entries in this structure.
//
m_aswlWinNames[0] =
new char[2*SWL_MAX_WINDOWS*SWL_MAX_WINDOW_TITLE_SEND];
if (!m_aswlWinNames[0])
{
ERROR_OUT(( "failed to get memory for window title lists"));
DC_QUIT;
}
m_aswlWinNames[1] = m_aswlWinNames[0] +
SWL_MAX_WINDOWS*SWL_MAX_WINDOW_TITLE_SEND;
ASSERT(m_swlCurIndex == 0);
rc = TRUE;
DC_EXIT_POINT:
DebugExitBOOL(ASHost::SWL_HostStarting, rc);
return(rc);
}
//
// SWL_HostEnded()
//
void ASHost::SWL_HostEnded(void)
{
DebugEntry(ASHost::SWL_HostEnded);
//
// For 2.x nodes, we must send out one last packet so they kill
// their shadows.
//
//
// Remove the SWL properties for all existing windows.
//
EnumWindows(SWLDestroyWindowProperty, 0);
m_swlfSyncing = FALSE;
if (m_pShare->m_scShareVersion < CAPS_VERSION_30)
{
//
// SWL_Periodic() should NOT put properties on windows
// when we're not hosting anymore.
//
ASSERT(m_pShare->m_pasLocal->hetCount == 0);
TRACE_OUT(("SWL_HostEnded: Must send an empty window list for 2.x nodes"));
m_swlfForceSend = TRUE;
SWL_Periodic();
}
if (m_aswlNRInfo[0])
{
delete[] m_aswlNRInfo[0];
m_aswlNRInfo[0] = NULL;
}
if (m_aswlNRInfo[1])
{
delete[] m_aswlNRInfo[1];
m_aswlNRInfo[1] = NULL;
}
if (m_aswlWinNames[0])
{
delete[] m_aswlWinNames[0];
m_aswlWinNames[0] = NULL;
}
if (m_swlPropAtom)
{
GlobalDeleteAtom(m_swlPropAtom);
m_swlPropAtom = 0;
}
DebugExitVOID(ASHost::SWL_HostEnded);
}
//
// FUNCTION: SWL_GetSharedIDFromLocalID
//
// DESCRIPTION:
//
// Given a window ID from a shared application which is running locally
// this will return the top level parent. If this parent is invisible,
// we return NULL.
//
// the parent window nearest the desktop. If this parent window is
// invisible NULL is returned.
//
// PARAMETERS:
//
// window - the window in question
//
// RETURNS:
//
// a HWND or NULL if the window is not from a shared application
//
//
HWND ASHost::SWL_GetSharedIDFromLocalID(HWND window)
{
HWND hwnd;
HWND hwndParent;
HWND hwndDesktop;
DebugEntry(ASHost::SWL_GetSharedIDFromLocalID);
hwnd = window;
if (!hwnd)
{
DC_QUIT;
}
hwndDesktop = GetDesktopWindow();
//
// Get the real top level ancestor
//
while (GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD)
{
hwndParent = GetParent(hwnd);
if (hwndParent == hwndDesktop)
break;
hwnd = hwndParent;
}
//
// Is this a hosted guy?
//
if (m_pShare->HET_WindowIsHosted(hwnd))
{
if (!(GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE))
{
//
// This window does not have the visible style. But it may just
// be transiently invisible and SWL is still treating it as
// visible. RAID3074 requires that a window which is not yet
// believed to be invisible by SWL is treated as visible (since
// the remote has not been informed that it is invisible). We
// can determine whether SWL is traeting this window as visible
// by looking at the SWL window property. If no property exists
// then the window is new so the remote cannot know about it
// and we can assume it is indeed invisible.
//
if (! ((UINT_PTR)GetProp(hwnd, MAKEINTATOM(m_swlPropAtom)) & SWL_PROP_COUNTDOWN_MASK))
{
//
// SWL knows that the parent of a shared application is
// invisible so we just return NULL.
//
hwnd = NULL;
}
}
}
else
{
hwnd = NULL;
}
DC_EXIT_POINT:
DebugExitDWORD(ASHost::SWL_GetSharedIDFromLocalID, HandleToUlong(hwnd));
return(hwnd);
}
//
// SWL_UpdateCurrentDesktop()
//
// This checks what the current desktop is, and if it's changed, updates
// the NT input hooks for winlogon/screensaver for the service. But normal
// SWL and AWC also make use of this info.
//
void ASHost::SWL_UpdateCurrentDesktop(void)
{
HDESK hDeskCurrent = NULL;
UINT newCurrentDesktop;
char szName[SWL_DESKTOPNAME_MAX];
DebugEntry(ASHost::SWL_UpdateCurrentDesktop);
newCurrentDesktop = DESKTOP_OURS;
if (g_asWin95)
{
// Nothing to do
DC_QUIT;
}
//
// Get the current desktop. If we can't even get it, assume it's the
// winlogon desktop.
//
hDeskCurrent = OpenInputDesktop(0, TRUE, DESKTOP_READOBJECTS);
if (!hDeskCurrent)
{
TRACE_OUT(("OpenInputDesktop failed; must be WINLOGON"));
newCurrentDesktop = DESKTOP_WINLOGON;
DC_QUIT;
}
// Get the name of the current desktop
szName[0] = 0;
GetUserObjectInformation(hDeskCurrent, UOI_NAME, szName,
sizeof(szName), NULL);
TRACE_OUT(("GetUserObjectInformation returned %s for name", szName));
if (!lstrcmpi(szName, m_aswlOurDesktopName))
{
newCurrentDesktop = DESKTOP_OURS;
}
else if (!lstrcmpi(szName, NAME_DESKTOP_SCREENSAVER))
{
newCurrentDesktop = DESKTOP_SCREENSAVER;
}
else if (!lstrcmpi(szName, NAME_DESKTOP_WINLOGON))
{
newCurrentDesktop = DESKTOP_WINLOGON;
}
else
{
newCurrentDesktop = DESKTOP_OTHER;
}
DC_EXIT_POINT:
if (newCurrentDesktop != m_swlCurrentDesktop)
{
//
// If this is the service, adjust where we playback events
// and/or block local input.
//
OSI_DesktopSwitch(m_swlCurrentDesktop, newCurrentDesktop);
m_swlCurrentDesktop = newCurrentDesktop;
}
if (hDeskCurrent != NULL)
{
CloseDesktop(hDeskCurrent);
}
DebugExitVOID(ASHost::SWL_UpdateCurrentDesktop);
}
//
// SWL_IsOurDesktopActive()
//
BOOL ASHost::SWL_IsOurDesktopActive(void)
{
return(!g_asSharedMemory->fullScreen && (m_swlCurrentDesktop == DESKTOP_OURS));
}
//
// FUNCTION: SWLInitHostFullWinListEntry
//
// DESCRIPTION:
//
// Initializes a hosted window entry in the full window list.
//
// PARAMETERS: hwnd - Window ID of the hosted window
// windowProp - SWL window properties for hwnd
// ownerID - Window ID of hwnd's owner
// pFullWinEntry - pointer to the list entry to initialize
//
// RETURNS: Nothing
//
//
void ASHost::SWLInitHostFullWinListEntry
(
HWND hwnd,
UINT windowProp,
HWND hwndOwner,
PSWLWINATTRIBUTES pFullWinEntry
)
{
DebugEntry(ASHost::SWLInitHostFullWinListEntry);
//
// The window is a shared application hosted locally.
// These get the application id, the local window id and the owner
// window id.
//
// Note that the real owner of the window may be a child of a shared
// window, and therefore not known to the remote machine. We therefore
// pass the real owner to SWL_GetSharedIDFromLocalID() which will
// traverse up the owner's window tree until it finds a window that is
// shared and store the returned window handle in the window structure.
//
pFullWinEntry->flags = SWL_FLAG_WINDOW_HOSTED;
pFullWinEntry->winID = HandleToUlong(hwnd);
pFullWinEntry->extra = GetWindowThreadProcessId(hwnd, NULL);
// NOTE: ownerWinID is ignored by NM 3.0 and up.
pFullWinEntry->ownerWinID = HandleToUlong(SWL_GetSharedIDFromLocalID(hwndOwner));
//
// Check if the window is minimized.
//
if (IsIconic(hwnd))
{
pFullWinEntry->flags |= SWL_FLAG_WINDOW_MINIMIZED;
}
//
// TAGGABLE is for 2.x nodes only; 3.0 and up don't look at this.
//
if (windowProp & SWL_PROP_TAGGABLE)
{
pFullWinEntry->flags |= SWL_FLAG_WINDOW_TAGGABLE;
}
if (windowProp & SWL_PROP_TRANSPARENT)
{
//
// The window is transparent and (to have got this far) must be
// shared or the desktop is shared, ie we will be sending the
// window but need to fiddle the z-order. Flag the transparency so
// we can do the z-order later.
//
pFullWinEntry->flags |= SWL_FLAG_WINDOW_TRANSPARENT;
}
else if (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST)
{
//
// The window is not transparent and is topmost, so set the topmost
// flag.
//
pFullWinEntry->flags |= SWL_FLAG_WINDOW_TOPMOST;
}
//
// If this window is on the task bar then pass this info on
//
if (windowProp & SWL_PROP_TASKBAR)
{
pFullWinEntry->flags |= SWL_FLAG_WINDOW_TASKBAR;
}
else
{
pFullWinEntry->flags |= SWL_FLAG_WINDOW_NOTASKBAR;
}
DebugExitVOID(ASHost::SWLInitHostFullWinListEntry);
}
//
// FUNCTION: SWLAddHostWindowTitle
//
// DESCRIPTION:
//
// Adds a hosted window title (or blank entry) to our window titles list.
//
// PARAMETERS: winid - Window ID of the hosted window
// windowProp - SWL window properties for winid
// ownerID - Window ID of winid's owner
// ppWinNames - pointer to pointer to window names structure
//
// RETURNS: Nothing
//
//
void ASHost::SWLAddHostWindowTitle
(
HWND hwnd,
UINT windowProp,
HWND hwndOwner,
LPSTR *ppWinNames
)
{
int lenTitle;
DebugEntry(ASHost::SWLAddHostWindowTitle);
//
// This window gets an entry in our window titles data if it passes the
// following tests
//
// for Windows: it has no owner, or its owner is invisible
//
//
if ( (windowProp & SWL_PROP_TASKBAR) ||
hwndOwner == NULL ||
!IsWindowVisible(hwndOwner) )
{
//
// LAURABU 2.x COMPAT:
// 3.0 nodes only look at the text if TASKBAR is set. When 2.x
// compat is gone, don't send text in the other cases.
//
//
// Get the title - truncated and null terminated for us. First
// look for the desktop, which may have a special, configurable
// name.
//
lenTitle = GetWindowText(hwnd, *ppWinNames, SWL_MAX_WINDOW_TITLE_SEND);
//
// Check that the title has been null terminated.
//
(*ppWinNames)[lenTitle] = '\0';
*ppWinNames += lenTitle;
}
else
{
//
// This is not a task window - put a corresponding entry in the
// title info.
//
**ppWinNames = '\xff';
}
*ppWinNames += 1;
DebugExitVOID(ASHost::SWLAddHostWindowTitle);
}
//
// FUNCTION: SWL_InitFullWindowListEntry
//
// DESCRIPTION:
//
// Initialises an entry in the full window list.
//
// PARAMETERS: hwnd - Window ID of the window for which an entry is
// initialized
// windowProp - SWL window properties for hwnd
// ownerID - Window ID of hwnd's owner
// pFullWinEntry - pointer to the list entry to initialize
//
// RETURNS: Nothing
//
//
void ASHost::SWL_InitFullWindowListEntry
(
HWND hwnd,
UINT windowProp,
LPSTR * ppWinNames,
PSWLWINATTRIBUTES pFullWinEntry
)
{
HWND hwndOwner;
RECT rect;
DebugEntry(ASHost::SWL_InitFullWindowListEntry);
if (windowProp & SWL_PROP_HOSTED)
{
//
// The window is a shared application hosted locally.
// Set up an entry in our full window structure.
//
hwndOwner = GetWindow(hwnd, GW_OWNER);
SWLInitHostFullWinListEntry(hwnd,
windowProp,
hwndOwner,
pFullWinEntry);
SWLAddHostWindowTitle(hwnd, windowProp, hwndOwner, ppWinNames);
}
else
{
//
// The window is a local (non-shared) application
//
pFullWinEntry->flags = SWL_FLAG_WINDOW_LOCAL;
//
// We set the winID here because we may need this info
// again later, but we will NULL it out before we send the
// protocol packet out because it is not info that the
// remote needs
//
pFullWinEntry->winID = HandleToUlong(hwnd);
pFullWinEntry->extra = MCSID_NULL;
pFullWinEntry->ownerWinID = 0;
}
//
// Get the position and size of the window, in inclusive
// Virtual Desktop coordinates.
//
GetWindowRect(hwnd, &rect);
//
// TAGGABLE is for 2.x nodes only
//
if (IsRectEmpty(&rect))
{
pFullWinEntry->flags &= ~SWL_FLAG_WINDOW_TAGGABLE;
}
else
{
if (windowProp & SWL_PROP_TAGGABLE)
{
if (!SWLWindowIsTaggable(hwnd))
pFullWinEntry->flags &= ~SWL_FLAG_WINDOW_TAGGABLE;
}
}
//
// Make the rectangle inclusive.
//
rect.right -= 1;
rect.bottom -= 1;
TSHR_RECT16_FROM_RECT(&(pFullWinEntry->position), rect);
DebugExitVOID(ASHost::SWL_InitFullWindowListEntry);
}
//
// FUNCTION: SWLCompactWindowList
//
// DESCRIPTION:
//
// Compacts the full window list into one containng only those windows SWL
// needs to send (hosts and any locals overlapping hosts)
//
// PARAMETERS: numFullListEntries - number of entries in the full window
// list.
// pFullWinList - pointer to the full window list
// pCompactWinList - pointer to the compact window list
//
// RETURNS: Number of entries copied to the compact window list
//
//
UINT ASHost::SWLCompactWindowList
(
UINT numFullListEntries,
PSWLWINATTRIBUTES pFullWinList,
PSWLWINATTRIBUTES pCompactWinList
)
{
UINT fullIndex;
UINT compactIndex = 0;
UINT i;
DebugEntry(ASHost::SWLCompactWindowList);
//
// For each window in the full list...
//
for ( fullIndex = 0; fullIndex < numFullListEntries; fullIndex++ )
{
if (pFullWinList[fullIndex].flags & SWL_FLAG_WINDOW_LOCAL)
{
//
// This is a local window so we need to track it only if it
// overlaps a hosted window. Run through the remaining windows
// until we either find an overlapped hosted window (meaning we
// must track this local window) or reach the end of the list
// (meaning we don't need to track this local window).
//
for ( i = fullIndex + 1; i < numFullListEntries; i++ )
{
//
// If this window is hosted and intersects the local
// window then we need to track the local window.
//
if ( (pFullWinList[i].flags & SWL_FLAG_WINDOW_HOSTED) &&
(COM_Rect16sIntersect(&pFullWinList[fullIndex].position,
&pFullWinList[i].position)))
{
//
// Copy the local window to the compact array and
// break out the inner loop.
//
TRACE_OUT(("Add local hwnd 0x%08x to list at %u",
pFullWinList[fullIndex].winID, compactIndex));
pCompactWinList[compactIndex++] =
pFullWinList[fullIndex];
break;
}
}
}
else
{
//
// This is a shadow or hosted window so we must track it.
//
TRACE_OUT(("Add shared hwnd 0x%08x to list at %u",
pFullWinList[fullIndex].winID, compactIndex));
pCompactWinList[compactIndex++] = pFullWinList[fullIndex];
}
}
DebugExitDWORD(ASHost::SWLCompactWindowList, compactIndex);
return(compactIndex);
}
//
// FUNCTION: SWLAdjustZOrderForTransparency
//
// DESCRIPTION:
//
// Rearranges the window structure z-order to take account of a transparent
// window (winID). Must not be called if the transparent entry is the last
// in the compact list.
//
// PARAMETERS: pTransparentListEntry - pointer to the transparent entry
// pLastListEntry - pointer to the last compact window list
// entry
// winPosition - position of window in names array
// pWinNames - hosted window names
// sizeWinNames - number of bytes in winNames
//
// RETURNS: Nothing.
//
//
void ASHost::SWLAdjustZOrderForTransparency
(
PSWLWINATTRIBUTES pTransparentListEntry,
PSWLWINATTRIBUTES pLastListEntry,
UINT winPosition,
LPSTR pWinNames,
UINT sizeWinNames
)
{
SWLWINATTRIBUTES winCopyBuffer;
LPSTR pEndNames = &pWinNames[sizeWinNames - 1];
UINT nameLen;
char windowText[TSHR_MAX_PERSON_NAME_LEN + SWL_MAX_WINDOW_TITLE_SEND];
DebugEntry(ASHost::SWLAdjustZOrderForTransparency);
//
// - turn off the transparent flag (it's not part of the protocol)
// - move the window to the end of the structure, ie bottom of the
// z-order (unless the desktop is at the bottom, in which case
// the window becomes next to bottom).
//
TRACE_OUT(("Adjust z-order for transparent hwnd 0x%08x position %u",
pTransparentListEntry->winID,
winPosition));
pTransparentListEntry->flags &= ~SWL_FLAG_WINDOW_TRANSPARENT;
winCopyBuffer = *pTransparentListEntry;
//
// Shuffle the windows after the transparent entry one place toward the
// start of the list.
//
UT_MoveMemory(pTransparentListEntry,
&pTransparentListEntry[1],
(LPBYTE)pLastListEntry - (LPBYTE)pTransparentListEntry);
*pLastListEntry = winCopyBuffer;
//
// Now rearrange the window names in the same way. First, find the name
// for this window.
//
ASSERT((sizeWinNames != 0));
for ( ;winPosition != 0; winPosition-- )
{
if ( *pWinNames == '\xff' )
{
//
// No name exists for this window, so just advance past the
// 0xff placeholder.
//
TRACE_OUT(("No name for %u", winPosition-1));
pWinNames++;
}
else
{
//
// A name exists for this window, so skip past all the
// characters, including the NULL terminator.
//
TRACE_OUT(( "Ignore %s", pWinNames));
while ( *pWinNames != '\0' )
{
pWinNames++;
}
}
}
//
// winNames now points to the start of the name for the window being
// reordered.
//
if ( *pWinNames == '\xff' )
{
//
// This window has no name and simply has an 0xff placeholder in
// the name list. Move all the remaining names down by one and add
// the 0xff at the end.
//
TRACE_OUT(("Reorder nameless window"));
UT_MoveMemory(pWinNames, pWinNames + 1, pEndNames - pWinNames);
*pEndNames = (char)'\xff';
}
else
{
//
// Move as many bytes as there are characters in the window name
// then tack the name on the end.
//
TRACE_OUT(("Reorder %s", pWinNames));
lstrcpy(windowText, pWinNames);
nameLen = lstrlen(pWinNames);
UT_MoveMemory(pWinNames, pWinNames + nameLen + 1, pEndNames - pWinNames -
nameLen);
lstrcpy(pEndNames - nameLen, windowText);
}
DebugExitVOID(ASHost::SWLAdjustZOrderForTransparency);
}
//
// SWL_Periodic()
//
// DESCRIPTION:
//
// Called periodically. If the window structure has changed (such that it
// impacts remote systems) then send a new one if we can.
//
// PARAMETERS:
//
// fSend - TRUE if the caller really wants us to try to send the new
// structure.
//
// RETURNS: SWL_RC_ERROR : An error occurred
// SWL_RC_SENT : Window structure sent successfully
// SWL_RC_NOT_SENT : No need to send window structure
//
UINT ASHost::SWL_Periodic(void)
{
UINT fRC = SWL_RC_NOT_SENT;
UINT newIndex;
PSWLWINATTRIBUTES newFullWinStruct;
PSWLWINATTRIBUTES curFullWinStruct;
PSWLWINATTRIBUTES newCompactWinStruct;
PSWLWINATTRIBUTES curCompactWinStruct;
UINT i;
UINT k;
BOOL fNoTitlesChanged;
HWND hwnd;
SWLENUMSTRUCT swlEnumStruct;
int complexity;
UINT cNonRectData;
UINT size;
UINT ourSize;
HRGN hrgnNR;
HRGN hrgnRect;
LPRGNDATA pRgnData = NULL;
LPTSHR_INT16 pOurRgnData = NULL;
LPTSHR_INT16 pEndRgnData;
LPTSHR_INT16 pAllocRgnData = NULL;
BOOL fNonRectangularInfoChanged;
BOOL rgnOK;
RECT rectBound;
int left;
int top;
int right;
int bottom;
int lastleft;
int lasttop;
int lastright;
int lastbottom;
int deltaleft;
int deltatop;
int deltaright;
int deltabottom;
int lastdeltaleft;
int lastdeltatop;
int lastdeltaright;
int lastdeltabottom;
UINT numCompactWins;
UINT lastTransparency;
UINT winFlags;
UINT iHosted;
DebugEntry(ASSHost::SWL_Periodic);
SWL_UpdateCurrentDesktop();
//
// If this party isn't hosting apps (and isn't faking up an empty
// packet for 2.x nodes), there's nothing to do.
//
if (m_pShare->m_pasLocal->hetCount == HET_DESKTOPSHARED)
{
m_swlfForceSend = FALSE;
fRC = SWL_RC_NOT_SENT;
DC_QUIT;
}
//
// Get the window structure into the "new" array.
//
newIndex = (m_swlCurIndex+1)%2;
curFullWinStruct = &(m_aswlFullWinStructs[m_swlCurIndex * SWL_MAX_WINDOWS]);
newFullWinStruct = &(m_aswlFullWinStructs[newIndex * SWL_MAX_WINDOWS]);
//
// Free any previously allocated data.
//
if (m_aswlNRInfo[newIndex])
{
delete[] m_aswlNRInfo[newIndex];
m_aswlNRInfo[newIndex] = NULL;
}
m_aswlNRSize[newIndex] = 0;
//
// Start from the first child of the desktop - should be the top
// top-level window
//
ZeroMemory(&swlEnumStruct, sizeof(swlEnumStruct));
swlEnumStruct.pHost = this;
swlEnumStruct.newWinNames = m_aswlWinNames[newIndex];
swlEnumStruct.newFullWinStruct = newFullWinStruct;
//
// Before we consider the windows on the windows desktop we check for
// an active full-screen session. If there is one then we insert a
// local window the size of the physical screen first so that all
// applications which are hosted on this system will become obscured
// on the remote system.
//
ASSERT(swlEnumStruct.count == 0);
if (!SWL_IsOurDesktopActive())
{
newFullWinStruct[0].flags = SWL_FLAG_WINDOW_LOCAL;
newFullWinStruct[0].winID = 0;
newFullWinStruct[0].extra = MCSID_NULL;
newFullWinStruct[0].ownerWinID = 0;
newFullWinStruct[0].position.left = 0;
newFullWinStruct[0].position.top = 0;
newFullWinStruct[0].position.right = (TSHR_UINT16)(m_pShare->m_pasLocal->cpcCaps.screen.capsScreenWidth-1);
newFullWinStruct[0].position.bottom = (TSHR_UINT16)(m_pShare->m_pasLocal->cpcCaps.screen.capsScreenHeight-1);
swlEnumStruct.count++;
}
EnumWindows(SWLEnumProc, (LPARAM)&swlEnumStruct);
//
// Check if we should bail out because of visibility detection
//
if (swlEnumStruct.fBailOut)
{
TRACE_OUT(("SWL_MaybeSendWindowList: bailing out due to visibility detection"));
fRC = SWL_RC_ERROR;
DC_QUIT;
}
m_aswlWinNamesSize[newIndex] = (UINT)(swlEnumStruct.newWinNames - m_aswlWinNames[newIndex]);
m_aswlNumFullWins[newIndex] = swlEnumStruct.count;
//
// Check whether we found a transparent window.
//
lastTransparency = swlEnumStruct.count - 1;
k = 0;
iHosted = 0;
while ( (swlEnumStruct.transparentCount > 0) && (k < lastTransparency) )
{
//
// If the transparent flag is set then rearrange the z-order,
// providing the transparent window is not already at the
// bottom of the z-order.
//
if (newFullWinStruct[k].flags & SWL_FLAG_WINDOW_TRANSPARENT)
{
//
// Now continue with the non-rectangular check - but this will
// be on the window "shunted down" from what was the next
// position in newCompactWinStruct, ie same value of i. We will
// see the moved (transparent) window when we reach it
// again at the end of this for-loop (when it will have the
// transparent flag off, so we don't redo this bit).
//
SWLAdjustZOrderForTransparency(
&newFullWinStruct[k],
&newFullWinStruct[lastTransparency],
iHosted,
m_aswlWinNames[newIndex],
m_aswlWinNamesSize[newIndex]);
swlEnumStruct.transparentCount--;
}
else
{
if (newFullWinStruct[k].flags & SWL_FLAG_WINDOW_HOSTED)
{
iHosted++;
}
k++;
}
}
//
// Compare the current and new information - if they are identical then
// we can quit now.
//
fNoTitlesChanged = ((m_aswlWinNamesSize[0] == m_aswlWinNamesSize[1]) &&
(memcmp(m_aswlWinNames[0],
m_aswlWinNames[1],
m_aswlWinNamesSize[0]) == 0));
if ( fNoTitlesChanged &&
!m_swlfRegionalChanges &&
(m_aswlNumFullWins[0] == m_aswlNumFullWins[1]) &&
(memcmp(newFullWinStruct,
curFullWinStruct,
(m_aswlNumFullWins[0] * sizeof(SWLWINATTRIBUTES))) == 0) )
{
//
// We don't need to send a window structure if nothing has changed
// unless there has been a send override.
//
if (m_swlfForceSend)
{
//
// This is a normal call AND there are pending changes.
//
TRACE_OUT(( "NORMAL, pending changes - send"));
if (SWLSendPacket(&(m_aswlCompactWinStructs[m_swlCurIndex * SWL_MAX_WINDOWS]),
m_aswlNumCompactWins[m_swlCurIndex],
m_aswlWinNames[m_swlCurIndex],
m_aswlWinNamesSize[m_swlCurIndex],
m_aswlNRSize[m_swlCurIndex],
m_aswlNRInfo[m_swlCurIndex]) )
{
//
// Successfully sent this so reset the m_swlfForceSend
// flag.
//
m_swlfForceSend = FALSE;
fRC = SWL_RC_SENT;
}
else
{
//
// Failed to send this packet so don't reset
// m_swlfForceSend so that we retry next time and return
// an error.
//
fRC = SWL_RC_ERROR;
}
}
else
{
//
// This is a normal call and we don't have any changes pending
// so don't send anything.
//
TRACE_OUT(( "No changes - SWL not sent"));
}
DC_QUIT;
}
//
// We can reset the flag that alerted us to potential regional window
// changes now that we have gone and actually checked all the windows.
//
m_swlfRegionalChanges = FALSE;
//
// Something in the window structure has changed. Determine which
// windows in the full list are unnecessary (local ones not overlapping
// any hosted ones) and create a compact array of windows we really
// need.
//
curCompactWinStruct = &(m_aswlCompactWinStructs[m_swlCurIndex * SWL_MAX_WINDOWS]);
newCompactWinStruct = &(m_aswlCompactWinStructs[newIndex * SWL_MAX_WINDOWS]);
numCompactWins = SWLCompactWindowList(m_aswlNumFullWins[newIndex],
newFullWinStruct,
newCompactWinStruct);
m_aswlNumCompactWins[newIndex] = numCompactWins;
//
// Run through the compact window list to check for regional windows
//
cNonRectData = 0;
hrgnNR = CreateRectRgn(0, 0, 0, 0);
for (i = 0; i < numCompactWins; i++)
{
winFlags = newCompactWinStruct[i].flags;
hwnd = (HWND)newCompactWinStruct[i].winID;
//
// There are some "fake" windows for which we do not provide a
// winID - these will never be non-rectangular anyway.
//
if ( (hwnd != NULL) &&
(winFlags & (SWL_FLAG_WINDOW_LOCAL | SWL_FLAG_WINDOW_HOSTED)) )
{
//
// If any of the remote systems care, see if this window has a
// non rectangular region selected into it.
//
if (GetWindowRgn(hwnd, hrgnNR) != ERROR)
{
TRACE_OUT(("Regional window 0x%08x", hwnd));
//
// There is a region selected in.
//
// This region is exactly as the application passed it to
// Windows, and has not yet been clipped to the window
// rectangle itself.
// THE COORDS ARE INCLUSIVE, SO WE ADD ONE to BOTTOM-RIGHT
//
hrgnRect = CreateRectRgn(0, 0,
newCompactWinStruct[i].position.right -
newCompactWinStruct[i].position.left + 1,
newCompactWinStruct[i].position.bottom -
newCompactWinStruct[i].position.top + 1);
complexity = IntersectRgn(hrgnNR, hrgnNR, hrgnRect);
DeleteRgn(hrgnRect);
if (complexity == COMPLEXREGION)
{
//
// The intersection is still a non-rectangular region.
//
// See how big a buffer we need to get the data for
// this region.
//
size = GetRegionData(hrgnNR,
0,
NULL);
//
// The size we are returned is the size of a full
// RGNDATAHEADER plus the rectangles stored in DWORDS.
// We can get away with just a WORD as the count of the
// rectangles, plus using WORDs for each of the
// coordinates.
//
size = (size - sizeof(RGNDATAHEADER)) / 2 + 2;
// Max UINT16 check
if ((size <= SWL_MAX_NONRECT_SIZE) &&
(size + cNonRectData < 65535))
{
//
// We will be able to query this data later, so
// we can flag this as a non-rectangular window.
//
newCompactWinStruct[i].flags
|= SWL_FLAG_WINDOW_NONRECTANGLE;
cNonRectData += size;
TRACE_OUT(("Regional window region is %d bytes", size));
}
else
{
//
// This region is far too complex for us, so we
// pretend it is simple so we just consider its
// bounding box.
//
TRACE_OUT(("Region too big %d - use bounds", size));
complexity = SIMPLEREGION;
}
}
if (complexity == SIMPLEREGION)
{
//
// The resultant intersection region happens to be a
// rectangle so we can send this via the standard
// structure.
//
// Apply the virtual desktop adjustment, make it
// inclusive, and remember we were passed back window
// relative coords for the region.
//
TRACE_OUT(( "rectangular clipped regional window"));
// Since we are modifying the compact window struct here
// we need to call this so we don't falsely assume that
// there are no changes in the window struct based on
// comparisons of the old and new full window structs
m_swlfRegionalChanges = TRUE;
GetRgnBox(hrgnNR, &rectBound);
newCompactWinStruct[i].position.left = (TSHR_INT16)
(newCompactWinStruct[i].position.left +
rectBound.left);
newCompactWinStruct[i].position.top = (TSHR_INT16)
(newCompactWinStruct[i].position.top +
rectBound.top);
newCompactWinStruct[i].position.right = (TSHR_INT16)
(newCompactWinStruct[i].position.left +
rectBound.right - rectBound.left - 1);
newCompactWinStruct[i].position.bottom = (TSHR_INT16)
(newCompactWinStruct[i].position.top +
rectBound.bottom - rectBound.top - 1);
}
}
}
}
//
// Get any non-rectangular areas we need.
//
if (cNonRectData)
{
//
// There was some data needed - allocate some memory for it.
//
rgnOK = FALSE;
pAllocRgnData = (LPTSHR_INT16) new BYTE[cNonRectData];
if (pAllocRgnData)
{
pOurRgnData = pAllocRgnData;
pEndRgnData = (LPTSHR_INT16)((LPBYTE)pAllocRgnData + cNonRectData);
rgnOK = TRUE;
//
// Loop through the windows again, getting the data this time.
//
for ( i = 0; i < numCompactWins; i++ )
{
if (newCompactWinStruct[i].flags &
SWL_FLAG_WINDOW_NONRECTANGLE)
{
GetWindowRgn((HWND)newCompactWinStruct[i].winID, hrgnNR);
//
// Clip the region to the window once again.
// THE COORDS ARE INCLUSIVE, SO ADD ONE TO BOTTOM-RIGHT
//
hrgnRect = CreateRectRgn(0, 0,
newCompactWinStruct[i].position.right -
newCompactWinStruct[i].position.left + 1,
newCompactWinStruct[i].position.bottom -
newCompactWinStruct[i].position.top + 1);
IntersectRgn(hrgnNR, hrgnNR, hrgnRect);
DeleteRgn(hrgnRect);
//
// Get the clipped region data.
//
// We have already excluded windows above that will
// return too large a size here, so we know we are only
// working with reasonable sizes now.
//
size = GetRegionData(hrgnNR, 0, NULL);
//
// For the moment we allocate memory each time for the
// region. Perhaps a better idea would be to save the
// max size from when we previously queried the region
// sizes, and allocate just that size one outside the
// loop.
//
pRgnData = (LPRGNDATA) new BYTE[size];
if (pRgnData)
{
GetRegionData(hrgnNR, size, pRgnData);
//
// There is a possibility that regions will have
// changed since we calculated the amount of data
// required. Before updating our structure with
// this window's region, check
// - the window hasn't become normal (ie 0 rects)
// - there is still enough space for the rects.
//
//
// Make sure this window still has regions
//
if (pRgnData->rdh.nCount == 0)
{
WARNING_OUT(( "No rects for window %#x",
newCompactWinStruct[i].winID));
newCompactWinStruct[i].flags &=
~SWL_FLAG_WINDOW_NONRECTANGLE;
delete[] pRgnData;
//
// Move on to next window.
//
continue;
}
//
// Check we have enough space for the rects:
// - ourSize is the number of int16s required.
// - GetRegionData returns the number of
// rectangles.
//
// We need one extra int16 to contain the count of
// rectangles.
//
ourSize = (pRgnData->rdh.nCount * 4) + 1;
if ((pOurRgnData + ourSize) > pEndRgnData)
{
WARNING_OUT(( "Can't fit %d int16s of region data",
ourSize));
rgnOK = FALSE;
delete[] pRgnData;
//
// Give up processing regional windows.
//
break;
}
//
// Copy the data across to our SWL area in a more
// compact form.
//
// We take care to produce a compressible form
// because the raw data is essentially
// uncompressible via sliding window techniques.
// (Basically boils down to trying hard to make
// most values 0, or else of small magnitude).
//
//
// First we write the count of the number of
// rectangles.
//
*pOurRgnData++ = LOWORD(pRgnData->rdh.nCount);
//
// Now store the encoded rectangles.
//
lastleft = 0;
lasttop = 0;
lastright = 0;
lastbottom = 0;
lastdeltaleft = 0;
lastdeltatop = 0;
lastdeltaright = 0;
lastdeltabottom = 0;
for ( k = 0; k < (UINT)pRgnData->rdh.nCount; k++ )
{
//
// Extract 16bit quantities from the data we
// were returned.
//
// We also use inclusive coords whereas Windows
// gives us exclusive coords.
//
left = LOWORD(((LPRECT)(pRgnData->
Buffer))[k].left);
top = LOWORD(((LPRECT)(pRgnData->
Buffer))[k].top);
right = LOWORD(((LPRECT)(pRgnData->
Buffer))[k].right) - 1;
bottom = LOWORD(((LPRECT)(pRgnData->
Buffer))[k].bottom) - 1;
//
// The rectangles are ordered top to bottom,
// left to right, so the deltas are of smaller
// magnitude than the values themselves.
//
deltaleft = left - lastleft;
deltatop = top - lasttop;
deltaright = right - lastright;
deltabottom = bottom - lastbottom;
//
// In general, the left and right edges are
// connected lines, and the rectangles are of
// equal height so top/bottom are regular.
//
// Thus the values form a series which we can
// exploit to give a more compressible form.
//
// We already have the delta in each component,
// and these values themselves also form a
// series. For a straight line series all the
// deltas will be the same, so the "delta in
// the delta" will be zero. For a curve,
// although not all the deltas are the same,
// the "delta in the delta" is probably very
// small.
//
// A set of lots of zeros and small magnitude
// numbers is very compressible.
//
// Thus we store the "delta in the delta" for
// all components, rather than the values
// themselves. The receiver can undo all the
// deltaing to arive back at the original
// values.
//
*pOurRgnData++ =
(TSHR_UINT16)(deltaleft - lastdeltaleft);
*pOurRgnData++ =
(TSHR_UINT16)(deltatop - lastdeltatop);
*pOurRgnData++ =
(TSHR_UINT16)(deltaright - lastdeltaright);
*pOurRgnData++ =
(TSHR_UINT16)(deltabottom - lastdeltabottom);
//
// Update our last values.
//
lastleft = left;
lasttop = top;
lastright = right;
lastbottom = bottom;
lastdeltaleft = deltaleft;
lastdeltatop = deltatop;
lastdeltaright = deltaright;
lastdeltabottom = deltabottom;
}
//
// Free the data now we are finished with it.
//
delete[] pRgnData;
}
else
{
//
// Failed to get memory for the rectangles, so the
// best we can do is use the bounding rect
//
// Clear the nonrect flag.
//
TRACE_OUT(("Failed alloc %d - use bounds", i));
newCompactWinStruct[i].flags &=
~SWL_FLAG_WINDOW_NONRECTANGLE;
}
if (newCompactWinStruct[i].flags & SWL_FLAG_WINDOW_LOCAL)
{
//
// The protocol defines that we will send a NULL
// winID for local windows, so NULL it out, now
// that we have finished with it.
//
newCompactWinStruct[i].winID = 0;
}
}
}
}
if (!rgnOK)
{
//
// Something went wrong, one of:
// - we failed to allocate the memory we need to store the
// non-rectangular data
// - we allocated the memory but it turned out not to be large
// enough.
//
// Either way, best to act as if there is no such data for us.
//
if (pAllocRgnData == NULL)
{
WARNING_OUT(( "Failed to alloc %d for NRInfo", cNonRectData));
}
else
{
delete[] pAllocRgnData;
pAllocRgnData = NULL;
}
cNonRectData = 0;
//
// Clear all the nonrect flags since we will not be sending any
// data.
//
for ( i = 0; i < numCompactWins; i++)
{
newCompactWinStruct[i].flags &= ~SWL_FLAG_WINDOW_NONRECTANGLE;
}
}
}
//
// Store the NR information
//
m_aswlNRSize[newIndex] = cNonRectData;
m_aswlNRInfo[newIndex] = (LPTSHR_UINT16)pAllocRgnData;
//
// We have finished with the region now.
//
DeleteRgn(hrgnNR);
//
// Did the data we stored change from the last time?
//
fNonRectangularInfoChanged = ((m_aswlNRSize[0] != m_aswlNRSize[1]) ||
(memcmp(m_aswlNRInfo[0], m_aswlNRInfo[1],
m_aswlNRSize[0])));
TRACE_OUT(("Non-rectinfo changed %d", fNonRectangularInfoChanged));
//
// Check again for no changes - quit if we can.
//
if (fNoTitlesChanged &&
!fNonRectangularInfoChanged &&
(m_aswlNumCompactWins[0] == m_aswlNumCompactWins[1]) &&
(!memcmp(newCompactWinStruct,
curCompactWinStruct,
(numCompactWins*sizeof(SWLWINATTRIBUTES)))))
{
if (!m_swlfForceSend)
{
//
// This is a normal call and we don't have any changes pending
// so don't send anything.
//
TRACE_OUT(("NORMAL no changes, not sent"));
}
else
{
//
// This is a normal call AND there are pending changes.
//
TRACE_OUT(( "NORMAL pending changes, send"));
if (SWLSendPacket(&(m_aswlCompactWinStructs[m_swlCurIndex * SWL_MAX_WINDOWS]),
m_aswlNumCompactWins[m_swlCurIndex],
m_aswlWinNames[m_swlCurIndex],
m_aswlWinNamesSize[m_swlCurIndex],
m_aswlNRSize[m_swlCurIndex],
m_aswlNRInfo[m_swlCurIndex]) )
{
//
// Succesfully sent this so reset the m_swlfForceSend
// flag.
//
m_swlfForceSend = FALSE;
fRC = SWL_RC_SENT;
}
else
{
//
// Failed to send this packet so don't reset
// m_swlfForceSend so that we retry next time and return
// an error.
//
fRC = SWL_RC_ERROR;
}
}
//
// We can exit here with a changed full window structure but an
// unchanged compact window structure. By updating the current
// index we avoid having to compact the window structure next time
// if the full list doesn't change, ie we will exit on the full
// list comparison. If the compact structure subsequently changes
// then the full structure must also change, so we will detect this
// change.
//
m_swlCurIndex = newIndex;
DC_QUIT;
}
//
// Now the window structure has changed so decide what to do.
//
m_swlCurIndex = newIndex;
//
// The window structure has changed so try to send it.
//
if (SWLSendPacket(&(m_aswlCompactWinStructs[m_swlCurIndex * SWL_MAX_WINDOWS]),
m_aswlNumCompactWins[m_swlCurIndex],
m_aswlWinNames[m_swlCurIndex],
m_aswlWinNamesSize[m_swlCurIndex],
m_aswlNRSize[m_swlCurIndex],
m_aswlNRInfo[m_swlCurIndex]) )
{
//
// We have succesfully sent changes so reset the m_swlfForceSend
// flag.
//
m_swlfForceSend = FALSE;
fRC = SWL_RC_SENT;
}
else
{
//
// There were changes but we have failed to send them - set the
// m_swlfForceSend flag and return error.
// We must tell DCS scheduling that we need a callback BEFORE any
// more changes are sent out.
//
m_swlfForceSend = TRUE;
fRC = SWL_RC_ERROR;
}
DC_EXIT_POINT:
DebugExitDWORD(ASHost::SWL_Periodic, fRC);
return(fRC);
}
//
// SWLEnumProc()
// Callback for top level window enumeration
//
BOOL CALLBACK SWLEnumProc(HWND hwnd, LPARAM lParam)
{
PSWLENUMSTRUCT pswlEnum = (PSWLENUMSTRUCT)lParam;
UINT_PTR property;
UINT windowProp;
UINT storedWindowProp;
UINT visibleCount;
BOOL fVisible;
BOOL rc = TRUE;
DebugEntry(SWLEnumProc);
//
// FIRST, WE DETERMINE THE PROPERTIES FOR THE WINDOW.
// Get the SWL properties for this window.
//
windowProp = (UINT)pswlEnum->pHost->SWL_GetWindowProperty(hwnd);
//
// We'll modify windowProp as we go, so keep a copy of the original
// value as stored in the window as we may need it later.
//
storedWindowProp = windowProp;
//
// HET tracks whether a window is hosted. Find out now and add this
// info to our window properties for convenience.
//
if (pswlEnum->pHost->m_pShare->HET_WindowIsHosted(hwnd))
{
windowProp |= SWL_PROP_HOSTED;
}
//
// Find out whether this window is transparent.
// A transparent window overpaints the desktop only, ie it is
// overpainted by all other windows. In other words, we can
// forget about it (treat it as invisible) unless a toolbar itself
// is shared. The MSOffice95
// hidden toolbar is a topmost transparent window (SFR1083).
// Add a property flag if transparent.
//
if (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TRANSPARENT)
{
windowProp |= SWL_PROP_TRANSPARENT;
}
//
// If this window is one that we have identified as generating no
// remote shadows, then treat it as being invisible.
//
fVisible = FALSE;
if (IsWindowVisible(hwnd) &&
!(windowProp & SWL_PROP_IGNORE) &&
(!(windowProp & SWL_PROP_TRANSPARENT) || (windowProp & SWL_PROP_HOSTED)))
{
//
// SFR1083: if the window is transparent but it is hosted,
// we need to send it. In such a case we drop into here to do
// the normal visibility processing and will handle
// z-order issues later.
//
// We have been informed that a top level window is visible.
// Make sure its visible countdown value is reset.
//
if ((pswlEnum->pHost->m_pShare->m_pasLocal->hetCount != 0) &&
((windowProp & SWL_PROP_COUNTDOWN_MASK) != SWL_BELIEVE_INVISIBLE_COUNT))
{
//
// We were doing an invisibility countdown for this window
// but it has re-visibilized, so reset the counter.
//
TRACE_OUT(( "Reset visible countdown on hwnd 0x%08x", hwnd));
property = storedWindowProp;
property &= ~SWL_PROP_COUNTDOWN_MASK;
property |= SWL_BELIEVE_INVISIBLE_COUNT;
SetProp(hwnd, SWL_ATOM_NAME, (HANDLE)property);
}
//
// This window is visible
//
fVisible = TRUE;
}
else
{
//
// LAURABU BOGUS!
// With NM 3.0, who cares? It's only 2.x systems that will kill
// then recreate the shadow, causing flicker.
//
//
// We are told that this top level window is invisible.
// Check whether we're going to believe it.
// Some applications (ie WordPerfect, Freelance Graphics)
// upset AS-Shares window structure handling by doing something
// like this:
//
// Make a window invisible
// Do some processing which would not normally yield
// Make the window visible again
//
// There is a chance that DC-Share will get scheduled whilst
// the window is invisible (because of our cunning scheduling)
// and we will think the window is invisible when it is not.
//
// Also, 32bit tasks that use similar methods (Eg Word95,
// Freelance graphics and WM_SETREDRAW messages) may be
// interrupted while the window is (temporarily) marked as
// invisible. When the CORE is scheduled we may, again, think
// that the window is invisible when it is not.
//
// To overcome this the SWL window property contains a
// visibility count, initially set to
// SWL_BELIEVE_INVISIBLE_COUNT. Following a visible to
// invisible switch, the counter is decremented and only when
// it reaches zero does SWL believe that the window is
// invisible. The counter is reset when a window is detected as
// visible and the counter is not SWL_BELIEVE_INVISIBLE_COUNT.
//
// This would be fine but there are windows when we mistakenly
// pretend that a window which really has become invisible
// (rather than one which is transitionally invisible) is
// visible. This is exposed by menus and dialog boxes. To
// reduce this problem we will never pretend a window is
// visible if its class has a CS_SAVEBITS style which should
// be the case for windows which are transitionally
// visible like menus and dialog boxes.
//
// SFR1083: always treat a transparent window as invisible
//
if ( !(windowProp & SWL_PROP_TRANSPARENT) &&
!(windowProp & SWL_PROP_SAVEBITS) )
{
visibleCount = windowProp & SWL_PROP_COUNTDOWN_MASK;
if ((visibleCount != 0) && (pswlEnum->pHost->m_pShare->m_pasLocal->hetCount > 0))
{
//
// We are still treating this window as visible, ie we
// are doing a visibilty countdown. Update the count in
// the window property.
//
visibleCount--;
property = ~SWL_PROP_COUNTDOWN_MASK & storedWindowProp;
property |= visibleCount;
TRACE_OUT(( "Decrement visible countdown on window 0x%08x to %d",
hwnd, visibleCount));
SetProp(hwnd, SWL_ATOM_NAME, MAKEINTATOM(property));
//
// Delay sending of updates since the remote still
// has a window structure which includes this window
// but it is not on the local screen (so any updates
// sent may be for the area where this window was and
// the remote will not show them).
//
pswlEnum->fBailOut = TRUE;
rc = FALSE;
DC_QUIT;
}
}
}
//
// Only concerned about visible windows.
//
if (fVisible)
{
pswlEnum->pHost->SWL_InitFullWindowListEntry(hwnd, windowProp,
&(pswlEnum->newWinNames),
&(pswlEnum->newFullWinStruct[pswlEnum->count]));
//
// If we've added a transparent window then remember this.
//
if (windowProp & SWL_PROP_TRANSPARENT)
{
pswlEnum->transparentCount++;
}
//
// Update index
//
pswlEnum->count++;
if (pswlEnum->count == SWL_MAX_WINDOWS)
{
//
// We've reached our limit on # of top level windows, so bail
// out.
//
WARNING_OUT(("SWL_MAX_WINDOWS exceeded"));
rc = FALSE;
}
}
DC_EXIT_POINT:
DebugExitBOOL(SWLEnumProc, rc);
return(rc);
}
//
// SWLSendPacket()
//
// Called when the shared apps of this node have changed shape/text/position/
// zorder or there have been new windows created/old shared windows destroyed.
// We must send these updates out to the remote systems.
//
// RETURNS: TRUE or FALSE - success of failure.
//
//
BOOL ASHost::SWLSendPacket
(
PSWLWINATTRIBUTES pWindows,
UINT numWindows,
LPSTR pTitles,
UINT lenTitles,
UINT NRInfoSize,
LPTSHR_UINT16 pNRInfo
)
{
PSWLPACKET pSWLPacket;
UINT sizeWindowPkt;
UINT i;
LPSTR pString;
LPBYTE pCopyLocation;
UINT cCopySize;
SWLPACKETCHUNK chunk;
#ifdef _DEBUG
UINT sentSize;
#endif // _DEBUG
DebugEntry(ASHost::SWLSendPacket);
if (m_pShare->m_pasLocal->hetCount != 0)
{
//
// This is a real packet, not an empty one
//
if (!UP_MaybeSendSyncToken())
{
//
// We needed to send a sync token and couldn't so just return
// failure immediately.
//
TRACE_OUT(( "couldn't send sync token"));
return(FALSE);
}
}
//
// How big a packet do we need?
//
sizeWindowPkt = sizeof(SWLPACKET) + (numWindows - 1) * sizeof(SWLWINATTRIBUTES)
+ lenTitles;
//
// Add in the size of the regional window information, plus the
// size we need for the chunk header.
//
if (NRInfoSize)
{
if (lenTitles & 1)
{
//
// We need an extra byte for correct alignment
//
sizeWindowPkt++;
}
sizeWindowPkt += NRInfoSize + sizeof(SWLPACKETCHUNK);
}
//
// Allocate a packet for the windows data.
//
pSWLPacket = (PSWLPACKET)m_pShare->SC_AllocPkt(PROT_STR_UPDATES, g_s20BroadcastID,
sizeWindowPkt);
if (!pSWLPacket)
{
WARNING_OUT(("Failed to alloc SWL packet, size %u", sizeWindowPkt));
return(FALSE);
}
//
// Packet successfully allocated. Fill in the data and send it.
//
pSWLPacket->header.data.dataType = DT_SWL;
pSWLPacket->msg = SWL_MSG_WINSTRUCT;
pSWLPacket->flags = 0;
if (m_swlfSyncing)
{
pSWLPacket->flags |= SWL_FLAG_STATE_SYNCING;
m_swlfSyncing = FALSE;
}
pSWLPacket->numWindows = (TSHR_UINT16)numWindows;
pCopyLocation = (LPBYTE)pSWLPacket->aWindows;
cCopySize = numWindows*sizeof(SWLWINATTRIBUTES);
memcpy(pCopyLocation, pWindows, cCopySize);
//
// Copy the title information
//
pCopyLocation += cCopySize;
cCopySize = lenTitles;
memcpy(pCopyLocation, pTitles, cCopySize);
//
// Copy any non-rectangular window information.
//
if (NRInfoSize)
{
pCopyLocation += cCopySize;
//
// The chunk must be word aligned in the packet
//
if (lenTitles & 1)
{
//
// An odd number of bytes of window titles has misaligned us,
// so write a 0 (compresses best!) to realign the pointer.
//
*pCopyLocation++ = 0;
}
//
// Write the chunk header
//
chunk.size = (TSHR_INT16)(NRInfoSize + sizeof(chunk));
chunk.idChunk = SWL_PACKET_ID_NONRECT;
cCopySize = sizeof(chunk);
memcpy(pCopyLocation, &chunk, cCopySize);
//
// Now write the variable info itself
//
pCopyLocation += cCopySize;
cCopySize = NRInfoSize;
memcpy(pCopyLocation, pNRInfo, cCopySize);
TRACE_OUT(("Non rect data length %d",NRInfoSize));
}
//
// Backwards compatibility.
//
pSWLPacket->tick = (TSHR_UINT16)GetTickCount();
pSWLPacket->token = m_pShare->SWL_CalculateNextToken(m_pShare->m_swlLastTokenSeen);
TRACE_OUT(("Updating m_swlLastTokenSeen to 0x%08x for sent packet",
pSWLPacket->token));
m_pShare->m_swlLastTokenSeen = pSWLPacket->token;
pSWLPacket->reserved = 0;
#ifdef _DEBUG
{
int i;
int cWins;
PSWLWINATTRIBUTES pSwl;
// Trace out the entries
pSwl = pSWLPacket->aWindows;
cWins = pSWLPacket->numWindows;
TRACE_OUT(("SWLSendPacket: Sending packet with %d windows", cWins));
for (i = 0; i < cWins; i++, pSwl++)
{
TRACE_OUT(("SWLSendPacket: Entry %d", i));
TRACE_OUT(("SWLSendPacket: Flags %08x", pSwl->flags));
TRACE_OUT(("SWLSendPacket: Window %08x", pSwl->winID));
TRACE_OUT(("SWLSendPacket: Position {%04d, %04d, %04d, %04d}",
pSwl->position.left, pSwl->position.top,
pSwl->position.right, pSwl->position.bottom));
}
}
#endif // _DEBUG
//
// Send the windows packet on the UPDATE stream.
//
if (m_pShare->m_scfViewSelf)
m_pShare->SWL_ReceivedPacket(m_pShare->m_pasLocal, &pSWLPacket->header);
#ifdef _DEBUG
sentSize =
#endif // _DEBUG
m_pShare->DCS_CompressAndSendPacket(PROT_STR_UPDATES, g_s20BroadcastID,
&(pSWLPacket->header), sizeWindowPkt);
TRACE_OUT(("SWL packet size: %08d, sent %08d", sizeWindowPkt, sentSize));
DebugExitBOOL(ASHost::SWLSendPacket, TRUE);
return(TRUE);
}
//
// SWL_CalculateNextToken()
//
// This calculates the next token to put in an outgoing SWL packet. This is
// only looked at by backlevel systems (<= NM 2.1) who treat all incoming
// SWL streams in one big messy global fashion. So we need to put something
// there, something that won't scare them but ensure that our
// packets aren't ignored if at all possible.
//
TSHR_UINT16 ASShare::SWL_CalculateNextToken(TSHR_UINT16 currentToken)
{
UINT increment;
TSHR_UINT16 newToken;
DebugEntry(ASShare::SWL_CalculateNextToken);
//
// We use the highest priority increment to make sure our packets get
// through. But will this cause collisions with other 3.0 sharers?
// Try lowest priority if necessary.
//
increment = SWL_NEW_ZORDER_FAKE_WINDOW_INC;
//
// Return the new token
//
newToken = SWL_MAKE_TOKEN(
SWL_GET_INDEX(currentToken) + SWL_GET_INCREMENT(currentToken), increment);
DebugExitDWORD(ASShare::SWL_CalculateNextToken, newToken);
return(newToken);
}
//
// SWL_ReceivedPacket()
//
// DESCRIPTION:
//
// Processes a windows structure packet which has been received from the
// PR. This defines the position of the shared windows hosted on the
// remote system, any obscured regions, and the Z-order relative to the
// shared windows hosted locally.
//
// NOTE: We don't do any token stuff for _incoming_ packets; we never
// want to drop them since we aren't zordering anything locally. We are
// simply applying the zorder/region/position info to the client area
// drawing.
//
void ASShare::SWL_ReceivedPacket
(
ASPerson * pasFrom,
PS20DATAPACKET pPacket
)
{
PSWLPACKET pSWLPacket;
UINT i;
UINT j;
PSWLWINATTRIBUTES wins;
UINT numWins;
HRGN hrgnShared;
HRGN hrgnObscured;
HRGN hrgnThisWindow;
HRGN hrgnRect;
LPTSHR_INT16 pOurRgnData;
LPSTR pOurRgnChunk;
UINT cNonRectWindows;
BOOL viewAnyChanges;
DebugEntry(ASShare::SWL_ReceivedPacket);
ValidatePerson(pasFrom);
pSWLPacket = (PSWLPACKET)pPacket;
switch (pSWLPacket->msg)
{
//
// This is the only packet we currently recognize.
//
case SWL_MSG_WINSTRUCT:
break;
default:
WARNING_OUT(("Unknown SWL packet msg %d from [%d]",
pSWLPacket->msg, pasFrom->mcsID));
DC_QUIT;
}
//
// Update the last token we've seen, if it's greater than the last
// one we know about. Unlike 2.x, we don't drop this packet if it isn't.
//
if (pSWLPacket->token > m_swlLastTokenSeen)
{
TRACE_OUT(("Updating m_swlLastTokenSeen to 0x%08x, received packet from person [%d]",
pSWLPacket->token, pasFrom->mcsID));
m_swlLastTokenSeen = pSWLPacket->token;
}
else if (pasFrom->cpcCaps.general.version < CAPS_VERSION_30)
{
WARNING_OUT(("Received SWL packet from [%d] with stale token 0x%08x",
pasFrom->mcsID, pSWLPacket->token));
}
//
// Return immediately and ignore this baby if we aren't sharing. Back
// level systems may send us a SYNC packet with no windows before we've
// shared, and may send us one final SWL packet after we're done
// sharing.
//
if (!pasFrom->m_pView)
{
WARNING_OUT(("SWL_ReceivedPacket: Ignoring SWL packet from person [%d] not hosting",
pasFrom->mcsID));
DC_QUIT;
}
//
// Set up local variables to access the data in the packet
//
wins = pSWLPacket->aWindows;
numWins = pSWLPacket->numWindows;
pOurRgnChunk = (LPSTR)wins + numWins*sizeof(SWLWINATTRIBUTES);
TRACE_OUT(("SWL_ReceivedPacket: Received packet with %d windows from [%d]",
numWins, pasFrom->mcsID));
//
// We can't handle more than SWL_MAX_WINDOWS in the packet
// BOGUS:
// LauraBu -- We should negotiate this (make it a cap) on how many
// windows we can handle receiving. Then we have an easy path to
// increase this number.
//
if (numWins > SWL_MAX_WINDOWS)
{
ERROR_OUT(("SWL_ReceivedPacket: too many windows (%04d) in packet from [%08d]",
numWins, pasFrom->mcsID));
DC_QUIT;
}
cNonRectWindows = 0;
//
// The first pass over the arriving packet is to count the amount of
// region data and to update the window tray.
//
viewAnyChanges = FALSE;
//
// This part we process front to back, since that's the order of the
// strings and we use them for putting entries on the traybar.
//
for (i = 0; i < numWins; i++)
{
// Mask out bogus old bits that aren't OK to process
wins[i].flags &= SWL_FLAGS_VALIDPACKET;
TRACE_OUT(("SWL_ReceivedPacket: Entry %d", i));
TRACE_OUT(("SWL_ReceivedPacket: Flags %08x", wins[i].flags));
TRACE_OUT(("SWL_ReceivedPacket: Window %08x", wins[i].winID));
TRACE_OUT(("SWL_ReceivedPacket: Position {%04d, %04d, %04d, %04d}",
wins[i].position.left, wins[i].position.top,
wins[i].position.right, wins[i].position.bottom));
//
// NOTE:
// 2.x nodes may send us a packet with an entry for a shadow.
// Go look up the REAL shadow rect from its host.
//
// And fix up the SWL packet then.
//
if (wins[i].flags & SWL_FLAG_WINDOW_SHADOW)
{
ASPerson * pasRealHost;
TRACE_OUT(("SWLReceivedPacket: Entry is 2.x SHADOW for host [%d]",
wins[i].extra));
// This must be a back level dude, giving us an empty rect.
ASSERT(wins[i].position.left == 0);
ASSERT(wins[i].position.top == 0);
ASSERT(wins[i].position.right == 0);
ASSERT(wins[i].position.bottom == 0);
// Find the real host of this window
SC_ValidateNetID(wins[i].extra, &pasRealHost);
if (pasRealHost != NULL)
{
int cSwl = 0;
PSWLWINATTRIBUTES pSwl = NULL;
// Try to find this window's entry
if (pasRealHost == m_pasLocal)
{
//
// This was shared by US. We can just use the scratch
// arrays we already have. m_swlCurIndex has the last
// one we sent out to everybody in the share, so the
// info it has is most likely reflected on that 2x
// remote.
//
if (m_pHost != NULL)
{
cSwl = m_pHost->m_aswlNumCompactWins[m_pHost->m_swlCurIndex];
pSwl = &(m_pHost->m_aswlCompactWinStructs[m_pHost->m_swlCurIndex * SWL_MAX_WINDOWS]);
}
}
else
{
//
// This was shared by somebody else, not us and not
// the person who sent this SWL packet. So go use the
// last SWL info we received from them.
//
if (pasRealHost->m_pView)
{
cSwl = pasRealHost->m_pView->m_swlCount;
pSwl = pasRealHost->m_pView->m_aswlLast;
}
}
//
// Loop through the window list for the real host to
// find the entry--we'll use the last REAL rect we got
// for this window.
//
while (cSwl > 0)
{
if (wins[i].winID == pSwl->winID)
{
// Copy the _real_ position into the packet.
TRACE_OUT(("SWLReceivedPacket: Using real rect {%04d, %04d, %04d, %04d}",
pSwl->position.left, pSwl->position.top,
pSwl->position.right, pSwl->position.bottom));
wins[i].position = pSwl->position;
break;
}
cSwl--;
pSwl++;
}
if (cSwl == 0)
{
ERROR_OUT(("SWLReceivedPacket: Couldn't find real window %08x from host [%d]",
wins[i].winID, wins[i].extra));
}
}
}
//
// 2.x nodes send us VD coords, not screen coords. But that's what
// we display for them, so that's what we save away. Note that this
// works even in the 2.x shadow case above. Hosted and shadowed
// windows both get moved in a desktop scroll, so they stay in the
// same place in the virtual desktop, meaning that the coords sent
// from the host stay the same even if the windows move, meaning that
// we can use the coords of the real host to get the real shadow
// rect.
//
if (wins[i].flags & SWL_FLAG_WINDOW_HOSTED)
{
TRACE_OUT(("SWL_ReceivedPacket: Hosted Window 0x%08x", wins[i].winID));
TRACE_OUT(("SWL_ReceivedPacket: Text %s", ((*pOurRgnChunk == '\xff') ? "" : pOurRgnChunk)));
TRACE_OUT(("SWL_ReceivedPacket: Flags %08x", wins[i].flags));
TRACE_OUT(("SWL_ReceivedPacket: Owner %08x", wins[i].ownerWinID));
TRACE_OUT(("SWL_ReceivedPacket: Position {%04d, %04d, %04d, %04d}",
wins[i].position.left, wins[i].position.top,
wins[i].position.right, wins[i].position.bottom));
//
// We are stepping through the titles (which get sent from
// downlevel systems) which do not contain an
// explicit length) so that we can get to the data that follows
//
if (*pOurRgnChunk == '\xff')
{
//
// This is the title for a non-task window - there is just
// a single byte to ignore
//
pOurRgnChunk++;
}
else
{
//
// This is the title for a task window - there is a NULL
// terminated string to ignore.
//
if (wins[i].flags & SWL_FLAG_WINDOW_TASKBAR)
{
if (VIEW_WindowBarUpdateItem(pasFrom, &wins[i], pOurRgnChunk))
{
viewAnyChanges = TRUE;
}
}
pOurRgnChunk += lstrlen(pOurRgnChunk)+1;
}
}
if (wins[i].flags & SWL_FLAG_WINDOW_NONRECTANGLE)
{
//
// We need to know how many windows have non rectangular data
// provided.
//
cNonRectWindows++;
}
}
if (cNonRectWindows)
{
TRACE_OUT(( "%d non-rect windows", cNonRectWindows));
//
// The window title data is variable length bytes, so may end with
// incorrect alignment. Any data which follows (currently only
// non-rectangular windows data) is word aligned.
//
// So check if offset from beginning of data is not aligned. Note
// that the packet may start on an ODD boundary because we get
// a pointer to the data directly and don't allocate a copy.
//
if ((LOWORD(pSWLPacket) & 1) != (LOWORD(pOurRgnChunk) & 1))
{
TRACE_OUT(("SWL_ReceivedPacket: Aligning region data"));
pOurRgnChunk++;
}
//
// Loop through the tagged chunks that follow until we find the
// one we want.
//
while (((PSWLPACKETCHUNK)pOurRgnChunk)->idChunk != SWL_PACKET_ID_NONRECT)
{
ERROR_OUT(("SWL_ReceivedPacket: unknown chunk 0x%04x",
((PSWLPACKETCHUNK)pOurRgnChunk)->idChunk));
pOurRgnChunk += ((PSWLPACKETCHUNK)pOurRgnChunk)->size;
}
TRACE_OUT(("Total non rect data 0x%04x", ((PSWLPACKETCHUNK)pOurRgnChunk)->size));
}
//
// Now scan the wins array backwards (ie furthest away to closest
// window) to calculate the unshared region (obscured or nothing there).
// and the shared region.
//
hrgnShared = CreateRectRgn(0, 0, 0, 0);
hrgnObscured = CreateRectRgn(0, 0, 0, 0);
//
// Create a region we can make use of in the next bit of processing.
//
hrgnRect = CreateRectRgn(0, 0, 0, 0);
hrgnThisWindow = CreateRectRgn(0, 0, 0, 0);
//
// While we are building the shared/obscured regions, also fill in
// the host list. Note that this may contain references to local
// windows also if they obscure shared ones. Since we don't reference
// the list very often, it's easier to just copy the same stuff.
//
i = numWins;
while (i != 0)
{
i--;
//
// Consider whether this is a non rectangular window
//
if (wins[i].flags & SWL_FLAG_WINDOW_NONRECTANGLE)
{
UINT numRects;
UINT cStepOver;
int top;
int left;
int right;
int bottom;
int lasttop;
int lastleft;
int lastright;
int lastbottom;
int deltaleft;
int deltatop;
int deltaright;
int deltabottom;
int lastdeltaleft;
int lastdeltatop;
int lastdeltaright;
int lastdeltabottom;
//
// A non-rectangular region. We go ahead and create the region
// from the rectangles that describe it.
//
pOurRgnData = (LPTSHR_INT16)(pOurRgnChunk + sizeof(SWLPACKETCHUNK));
//
// We need to step through the non-rectangular data because we
// are processing windows in reverse z-order.
//
cStepOver = --cNonRectWindows;
while (cStepOver--)
{
//
// The next word in the chain contains the number of
// rectangles, so we multiply by 4 to get the number of
// words to advance.
//
pOurRgnData += *pOurRgnData++ * 4;
}
//
// Find the number of rectangles.
//
numRects = *pOurRgnData++;
//
// The encoding is based on a series of deltas, based on some
// initial assumptions
//
lastleft = 0;
lasttop = 0;
lastright = 0;
lastbottom = 0;
lastdeltaleft = 0;
lastdeltatop = 0;
lastdeltaright = 0;
lastdeltabottom = 0;
//
// Create the region from the first rectangle.
//
deltaleft = lastdeltaleft + *pOurRgnData++;
deltatop = lastdeltatop + *pOurRgnData++;
deltaright = lastdeltaright + *pOurRgnData++;
deltabottom = lastdeltabottom + *pOurRgnData++;
left = lastleft + deltaleft;
top = lasttop + deltatop;
right = lastright + deltaright;
bottom = lastbottom + deltabottom;
// THESE COORDS ARE INCLUSIVE, SO ADD ONE
SetRectRgn(hrgnThisWindow, left, top, right+1, bottom+1);
while (--numRects > 0)
{
//
// Move to the next rectangle.
//
lastleft = left;
lasttop = top;
lastright = right;
lastbottom = bottom;
lastdeltaleft = deltaleft;
lastdeltatop = deltatop;
lastdeltaright = deltaright;
lastdeltabottom = deltabottom;
deltaleft = lastdeltaleft + *pOurRgnData++;
deltatop = lastdeltatop + *pOurRgnData++;
deltaright = lastdeltaright + *pOurRgnData++;
deltabottom = lastdeltabottom + *pOurRgnData++;
left = lastleft + deltaleft;
top = lasttop + deltatop;
right = lastright + deltaright;
bottom = lastbottom + deltabottom;
//
// Get the current rectangle into a region.
// THESE COORDS ARE INCLUSIVE SO ADD ONE TO BOTTOM-RIGHT
//
SetRectRgn(hrgnRect, left, top, right+1, bottom+1);
//
// Add this region to the combined region.
//
UnionRgn(hrgnThisWindow, hrgnRect, hrgnThisWindow);
}
//
// Switch from window coords to desktop coords.
//
OffsetRgn(hrgnThisWindow,
wins[i].position.left,
wins[i].position.top);
}
else
{
//
// This window region is simply a rectangle.
SetRectRgn(hrgnThisWindow,
wins[i].position.left,
wins[i].position.top,
wins[i].position.right+1,
wins[i].position.bottom+1);
}
//
// Update the obscured region. As we are working from the back to
// the front of the Z-order we can simply add all local window
// entries in the incoming structure and subtract all hosted
// windows to arrive at the right answer.
//
if (wins[i].flags & SWL_FLAG_WINDOW_HOSTED)
{
//
// This is a hosted window, sitting above the previous ones.
// Add it to the shared region.
// Remove it from the obscured region.
//
UnionRgn(hrgnShared, hrgnShared, hrgnThisWindow);
SubtractRgn(hrgnObscured, hrgnObscured, hrgnThisWindow);
}
else
{
//
// Local windows
//
TRACE_OUT(( "Adding window %d (%d,%d):(%d,%d) to obscured rgn",
i,
wins[i].position.left,
wins[i].position.top,
wins[i].position.right,
wins[i].position.bottom ));
//
// This is a local window, sitting above the previous ones.
// We only care about what part of it intersects the current
// shared area of the windows behind it. If it doesn't
// intersect the shared area at all, it will add no new
// obscured bits.
//
// So figure out what part of the current shared area is now
// obscured. Add that piece to the obscured region, and
// subtract it from the shared region.
//
IntersectRgn(hrgnThisWindow, hrgnShared, hrgnThisWindow);
UnionRgn(hrgnObscured, hrgnObscured, hrgnThisWindow);
SubtractRgn(hrgnShared, hrgnShared, hrgnThisWindow);
}
}
//
// We can destroy the regions we created way back when.
//
DeleteRgn(hrgnRect);
DeleteRgn(hrgnThisWindow);
//
// Save the new host regions.
//
// Pass the newly calculated regions to the Shadow Window Presenter.
// The view code will take care of repainting the invalid parts. And
// will delete what was passed in if not kept.
//
VIEW_SetHostRegions(pasFrom, hrgnShared, hrgnObscured);
//
// Save the new window list as the current one.
//
pasFrom->m_pView->m_swlCount = numWins;
memcpy(pasFrom->m_pView->m_aswlLast, wins, numWins * sizeof(SWLWINATTRIBUTES));
//
// Finish updating the window list. This will repaint the tray bar. We
// do this now instead of earlier so that the visual changes and
// window bar changes appear together.
//
VIEW_WindowBarEndUpdateItems(pasFrom, viewAnyChanges);
if ((pSWLPacket->flags & SWL_FLAG_STATE_SYNCING) &&
(m_scShareVersion < CAPS_VERSION_30))
{
//
// With 2.x nodes in the picture, we need to do the old 2.x ping-
// pongy nonsense. We must force a packet if we're hosting when
// we receive a SYNC packet.
//
if (m_pHost)
{
m_pHost->m_swlfForceSend = TRUE;
}
}
DC_EXIT_POINT:
DebugExitVOID(ASShare::SWL_ReceivedPacket);
}
//
// Name: SWLWindowIsTaggable
//
// Purpose: Determine if a window would be taggable when hosted
//
// Returns: TRUE if the window would be taggable
// If the window is WS_EX_APPWINDOW or has a caption, it's tagged
//
// Params: winid - ID of window
//
//
BOOL ASHost::SWLWindowIsTaggable(HWND hwnd)
{
BOOL rc;
DebugEntry(ASHost::SWLWindowIsTaggable);
if (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_APPWINDOW)
rc = TRUE;
else if ((GetWindowLong(hwnd, GWL_STYLE) & WS_CAPTION) == WS_CAPTION)
rc = TRUE;
else
rc = FALSE;
DebugExitBOOL(ASHost::SWLWindowIsTaggable, rc);
return(rc);
}
//
// FUNCTION: SWLWindowIsOnTaskBar
//
// DESCRIPTION:
//
// Determines whether the given window is represented on the task bar
//
// PARAMETERS:
//
// hwnd - window to be queried
//
// RETURNS:
//
// TRUE - Window is represented on the task bar
//
// FALSE - Window is not represented on the task bar
//
//
BOOL ASHost::SWLWindowIsOnTaskBar(HWND hwnd)
{
BOOL rc = FALSE;
HWND owner;
RECT rect;
DebugEntry(ASHost::SWLWindowIsOnTaskBar);
//
// Our best understanding as to whether a window is on the task bar is
// the following:
//
// - it is a top level window (has no owner)
// AND - it does not have the WS_EX_TOOLWINDOW style
//
// Oprah1655: Visual Basic apps consist of a visible zero sized window
// with no owner and a window owned by the zero sized window. We do
// not want the zero sized window to be on the task bar, we do want the
// other window to be on the task bar.
//
//
owner = GetWindow(hwnd, GW_OWNER);
if (owner == NULL)
{
if (!(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW))
{
GetWindowRect(hwnd, &rect);
if ((rect.left < rect.right) &&
(rect.top < rect.bottom))
{
TRACE_OUT(("window 0x%08x allowed on task bar", hwnd));
rc = TRUE;
}
else
{
TRACE_OUT(( "window 0x%08x zero sized", hwnd));
}
}
}
else
{
//
// Is the owner window a top-level window of zero size?
//
if (GetWindow(owner, GW_OWNER) == NULL)
{
GetWindowRect(owner, &rect);
if (IsRectEmpty(&rect))
{
TRACE_OUT(("HWND 0x%08x has zero sized top-level owner",
hwnd));
rc = TRUE;
}
}
}
DebugExitDWORD(ASHost::SWLWindowIsOnTaskBar, rc);
return(rc);
}
//
// SWL_GetWindowProperty()
//
UINT_PTR ASHost::SWL_GetWindowProperty(HWND hwnd)
{
UINT_PTR properties;
char className[HET_CLASS_NAME_SIZE];
DebugEntry(ASHost::SWL_GetWindowProperty);
properties = (UINT_PTR)GetProp(hwnd, MAKEINTATOM(m_swlPropAtom));
if (properties != SWL_PROP_INVALID)
DC_QUIT;
//
// No property for this window - it must be new, so create its
// initial property state.
//
//
// Assign an initial value to the property, so we never set a property
// of zero (which we reserve to indicate invalid).
//
properties = SWL_PROP_INITIAL;
//
// TAGGABLE IS FOR < 3.0 nodes only.
//
if (SWLWindowIsTaggable(hwnd))
{
properties |= SWL_PROP_TAGGABLE;
}
//
// Get all the SWL info which is stored as a window property.
//
if (SWLWindowIsOnTaskBar(hwnd))
{
//
// This class of window gets tagged.
//
properties |= SWL_PROP_TASKBAR;
}
//
// Find out if the window class has the CS_SAVEBITS style.
//
if (GetClassLong(hwnd, GCL_STYLE) & CS_SAVEBITS)
{
//
// This window's class has the CS_SAVEBITS style.
//
properties |= SWL_PROP_SAVEBITS;
}
//
// Set the visibility count. This is 0 if the window is currently
// invisible, SWL_BELIEVE_INVISIBLE_COUNT if visible.
//
if (IsWindowVisible(hwnd))
{
properties |= SWL_BELIEVE_INVISIBLE_COUNT;
}
//
// Set the window property, which we will retrieve when SWL determines
// whether it needs to resend the window structure.
//
if (m_pShare->m_pasLocal->hetCount > 0)
{
SetProp(hwnd, SWL_ATOM_NAME, (HANDLE)properties);
}
DC_EXIT_POINT:
DebugExitDWORD(ASHost::SWL_GetWindowProperty, properties);
return(properties);
}
//
// FUNCTION: SWLDestroyWindowProperty
//
// DESCRIPTION:
//
// Destroys the window property for the supplied window.
//
// PARMETERS: winID - the window ID of the window for which the property is
// destroyed.
//
// RETURNS: Zero
//
//
BOOL CALLBACK SWLDestroyWindowProperty(HWND hwnd, LPARAM lParam)
{
//
// NOTE LAURABU:
// We set the property using a string, which bumps up the ref count,
// to work around a Win95 bug. We therefore want to remove it using a
// string, which bumps down the ref count. Otherwise we will quickly
// get a ref count overflow.
//
RemoveProp(hwnd, SWL_ATOM_NAME);
return(TRUE);
}