|
|
#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 iWin; int cWins; PSWLWINATTRIBUTES pSwl;
// Trace out the entries
pSwl = pSWLPacket->aWindows; cWins = pSWLPacket->numWindows;
TRACE_OUT(("SWLSendPacket: Sending packet with %d windows", cWins)); for (iWin = 0; iWin < cWins; iWin++, pSwl++) { TRACE_OUT(("SWLSendPacket: Entry %d", iWin)); 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); }
|