|
|
/****************************** Module Header ******************************\
* Module Name: dlgmgrc.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * This module contains client side dialog functionality * * History: * 15-Dec-1993 JohnC Pulled functions from user\server. \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/***************************************************************************\
* UT_PrevGroupItem * * History: \***************************************************************************/
PWND UT_PrevGroupItem( PWND pwndDlg, PWND pwndCurrent) { PWND pwnd, pwndPrev;
if (pwndCurrent == NULL || !TestWF(pwndCurrent, WFGROUP)) return _PrevControl(pwndDlg, pwndCurrent, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED);
pwndPrev = pwndCurrent;
while (TRUE) { pwnd = _NextControl(pwndDlg, pwndPrev, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED);
if (TestWF(pwnd, WFGROUP) || pwnd == pwndCurrent) return pwndPrev;
pwndPrev = pwnd; } }
/***************************************************************************\
* UT_NextGroupItem * * History: \***************************************************************************/
PWND UT_NextGroupItem( PWND pwndDlg, PWND pwndCurrent) { PWND pwnd, pwndNext;
pwnd = _NextControl(pwndDlg, pwndCurrent, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED);
if (pwndCurrent == NULL || !TestWF(pwnd, WFGROUP)) return pwnd;
pwndNext = pwndCurrent;
while (!TestWF(pwndNext, WFGROUP)) { pwnd = _PrevControl(pwndDlg, pwndNext, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED); if (pwnd == pwndCurrent) return pwndNext; pwndNext = pwnd; }
return pwndNext; }
/***************************************************************************\
* _PrevControl * * History: \***************************************************************************/ PWND _PrevControl( PWND pwndRoot, PWND pwndStart, UINT uFlags) { BOOL fFirstFound; PWND pwndNext; PWND pwnd, pwndFirst;
if (!pwndStart) return(NULL);
UserAssert(pwndRoot != pwndStart); UserAssert(!TestWF(pwndStart, WEFCONTROLPARENT));
pwnd = _NextControl(pwndRoot, NULL, uFlags);
pwndFirst = pwnd; fFirstFound = FALSE; while (pwndNext = _NextControl(pwndRoot, pwnd, uFlags)) {
if (pwndNext == pwndStart) break;
if (pwndNext == pwndFirst) { if (fFirstFound) { RIPMSG0(RIP_WARNING, "_PrevControl: Loop Detected"); break; } else { fFirstFound = TRUE; } }
pwnd = pwndNext; }
return pwnd; } /***************************************************************************\
* * GetChildControl() * * Gets valid ancestor of given window. * A valid dialog control is a direct descendant of a "form" control. * \***************************************************************************/
PWND _GetChildControl(PWND pwndRoot, PWND pwndChild) { PWND pwndControl = NULL;
while (pwndChild && TestwndChild(pwndChild) && (pwndChild != pwndRoot)) { pwndControl = pwndChild; pwndChild = REBASEPWND(pwndChild, spwndParent);
if (TestWF(pwndChild, WEFCONTROLPARENT)) break; }
return(pwndControl); }
/***************************************************************************\
* * _NextSibblingOrAncestor * * Called by _NextControl. It returns the next control to pwndStart. If there * is a next window (pwndStart->spwndNext), then that is it. * Otherwise, the next control is up the parent chain. However, if it's already * at the top of the chain (pwndRoot == pwndStart->spwndParent), then the next * control is the first child of pwndRoot. But if it's not at the top of the chain, * then the next control is pwndStart->spwndParent or an ancestor. * \***************************************************************************/ PWND _NextSibblingOrAncestor (PWND pwndRoot, PWND pwndStart) { PWND pwndParent; #if DBG
PWND pwndNext; #endif
// If there is a sibbling, go for it
if (pwndStart->spwndNext != NULL) { return (REBASEALWAYS(pwndStart, spwndNext)); }
// If it cannot go up the parent chain, then return the first sibbling.
pwndParent = REBASEALWAYS(pwndStart, spwndParent); if (pwndParent == pwndRoot) { // Note that if pwndStart doesn't have any sibblings,
// this will return pwndStart again
return (REBASEALWAYS(pwndParent, spwndChild)); }
// Otherwise walk up the parent chain looking for the first window with
// a WS_EX_CONTROLPARENT parent.
#if DBG
pwndNext = #else
return #endif
_GetChildControl(pwndRoot, pwndParent);
#if DBG
if ((pwndNext != pwndParent) || !TestWF(pwndParent, WEFCONTROLPARENT)) { // Code looping through the controls in a dialog might go into an infinite
// loop because of this (i.e., xxxRemoveDefaultButton, _GetNextDlgTabItem,..)
// We've walked up the parent chain but will never walk down the child chain again
// because there is a NON WS_EX_CONTROLPARENT parent window somewhere in the chain.
RIPMSG0 (RIP_ERROR, "_NextSibblingOrAncestor: Non WS_EX_CONTROLPARENT window in parent chain"); } return pwndNext; #endif
} /***************************************************************************\
* * _NextControl() * * It searches for the next NON WS_EX_CONTROLPARENT control following pwndStart. * If pwndStart is NULL, the search begins with pwndRoot's first child; * otherwise, it starts with the control next to pwndStart. * This is a depth-first search that can start anywhere in the window tree. * uFlags determine what WS_EX_CONTROLPARENT windows should be skipped or recursed into. * If skipping a window, the search moves to the next control (see _NextSibblingOrAncestor); * otherwise, the search walks down the child chain (recursive call). * If the search fails, it returns pwndRoot. * \***************************************************************************/ PWND _NextControl( PWND pwndRoot, PWND pwndStart, UINT uFlags) { BOOL fSkip, fAncestor; PWND pwndLast, pwndSibblingLoop; /* Bug 272874 - joejo
* * Stop infinite loop by only looping a finite number of times and * then bailing. */ int nLoopCount = 0; UserAssert (pwndRoot != NULL);
if (pwndStart == NULL) { // Start with pwndRoot's first child
pwndStart = REBASEPWND(pwndRoot, spwndChild); pwndLast = pwndStart; fAncestor = FALSE; } else { UserAssert ((pwndRoot != pwndStart) && _IsDescendant(pwndRoot, pwndStart));
// Save starting handle and get next one
pwndLast = pwndStart; pwndSibblingLoop = pwndStart; fAncestor = TRUE; goto TryNextOne; }
// If no more controls, game over
if (pwndStart == NULL) { return pwndRoot; }
// Search for a non WS_EX_CONTROLPARENT window; if a window should be skipped,
// try its spwndNext; otherwise, walk down its child chain.
pwndSibblingLoop = pwndStart; do { //If not WS_EX_CONTROLPARENT parent, done.
if (!TestWF(pwndStart, WEFCONTROLPARENT)) { return pwndStart; }
// Do they want to skip this window?
fSkip = ((uFlags & CWP_SKIPINVISIBLE) && !TestWF(pwndStart, WFVISIBLE)) || ((uFlags & CWP_SKIPDISABLED) && TestWF(pwndStart, WFDISABLED));
// Remember the current window
pwndLast = pwndStart;
// Walk down child chain?
if (!fSkip && !fAncestor) { pwndStart = _NextControl (pwndStart, NULL, uFlags); // If it found one, done.
if (pwndStart != pwndLast) { return pwndStart; } }
TryNextOne: // Try the next one.
pwndStart = _NextSibblingOrAncestor (pwndRoot, pwndStart); if (pwndStart == NULL) { break; }
// If parents are the same, we are still in the same sibbling chain
if (pwndLast->spwndParent == pwndStart->spwndParent) { // If we had just moved up the parent chain last time around,
// mark this as the beginning of the new sibbling chain.
// Otherwise, check if we've looped through all sibblings already.
if (fAncestor) { // Beggining of new sibbling chain.
pwndSibblingLoop = pwndStart; } else if (pwndStart == pwndSibblingLoop) { // Already visited all sibblings, so done.
break; } fAncestor = FALSE; } else { // We must have moved up the parent chain, so don't
// walk down the child chain right away (try the next window first)
// Eventhough we are on a new sibbling chain, we don't update
// pwndSibblingLoop yet; this is because we must walk down this
// child chain again to make sure we visit all the descendents
fAncestor = TRUE; }
/* Bug 272874 - joejo
* * Stop infinite loop by only looping a finite number of times and * then bailing. */ } while (nLoopCount++ < 256 * 4);
// It couldn't find one...
return pwndRoot; }
/***************************************************************************\
* GetNextDlgTabItem * * History: * 19-Feb-1991 JimA Added access check \***************************************************************************/
FUNCLOG3(LOG_GENERAL, HWND, WINAPI, GetNextDlgTabItem, HWND, hwndDlg, HWND, hwnd, BOOL, fPrev) HWND WINAPI GetNextDlgTabItem( HWND hwndDlg, HWND hwnd, BOOL fPrev) {
PWND pwnd; PWND pwndDlg; PWND pwndNext;
pwndDlg = ValidateHwnd(hwndDlg);
if (pwndDlg == NULL) return NULL;
if (hwnd != (HWND)0) { pwnd = ValidateHwnd(hwnd);
if (pwnd == NULL) return NULL;
} else { pwnd = (PWND)NULL; }
pwndNext = _GetNextDlgTabItem(pwndDlg, pwnd, fPrev);
return (HW(pwndNext)); }
PWND _GetNextDlgTabItem( PWND pwndDlg, PWND pwnd, BOOL fPrev) { PWND pwndSave;
if (pwnd == pwndDlg) pwnd = NULL; else { pwnd = _GetChildControl(pwndDlg, pwnd); if (pwnd && !_IsDescendant(pwndDlg, pwnd)) return(NULL); }
//
// BACKWARD COMPATIBILITY
//
// Note that the result when there are no tabstops of
// IGetNextDlgTabItem(pwndDlg, NULL, FALSE) was the last item, now
// will be the first item. We could put a check for fRecurse here
// and do the old thing if not set.
//
// We are going to bug out if we hit the first child a second time.
pwndSave = pwnd;
pwnd = (fPrev ? _PrevControl(pwndDlg, pwnd, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED) : _NextControl(pwndDlg, pwnd, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED));
if (!pwnd) goto AllOver;
while ((pwnd != pwndSave) && (pwnd != pwndDlg)) { UserAssert(pwnd);
if (!pwndSave) pwndSave = pwnd;
if ((pwnd->style & (WS_TABSTOP | WS_VISIBLE | WS_DISABLED)) == (WS_TABSTOP | WS_VISIBLE)) // Found it.
break;
pwnd = (fPrev ? _PrevControl(pwndDlg, pwnd, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED) : _NextControl(pwndDlg, pwnd, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED)); }
AllOver: return pwnd; }
/***************************************************************************\
* * _GetNextDlgGroupItem() * \***************************************************************************/
FUNCLOG3(LOG_GENERAL, HWND, DUMMYCALLINGTYPE, GetNextDlgGroupItem, HWND, hwndDlg, HWND, hwndCtl, BOOL, bPrevious) HWND GetNextDlgGroupItem( HWND hwndDlg, HWND hwndCtl, BOOL bPrevious) { PWND pwndDlg; PWND pwndCtl; PWND pwndNext;
pwndDlg = ValidateHwnd(hwndDlg);
if (pwndDlg == NULL) return 0;
if (hwndCtl != (HWND)0) { pwndCtl = ValidateHwnd(hwndCtl);
if (pwndCtl == NULL) return 0; } else { pwndCtl = (PWND)NULL; }
if (pwndCtl == pwndDlg) pwndCtl = pwndDlg;
pwndNext = _GetNextDlgGroupItem(pwndDlg, pwndCtl, bPrevious);
return (HW(pwndNext)); }
PWND _GetNextDlgGroupItem( PWND pwndDlg, PWND pwnd, BOOL fPrev) { PWND pwndCurrent; BOOL fOnceAround = FALSE;
pwnd = pwndCurrent = _GetChildControl(pwndDlg, pwnd);
do { pwnd = (fPrev ? UT_PrevGroupItem(pwndDlg, pwnd) : UT_NextGroupItem(pwndDlg, pwnd));
if (pwnd == pwndCurrent) fOnceAround = TRUE;
if (!pwndCurrent) pwndCurrent = pwnd; } while (!fOnceAround && ((TestWF(pwnd, WFDISABLED) || !TestWF(pwnd, WFVISIBLE))));
return pwnd; }
|