test: mdiwin.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# mdiwin.c

Go to the documentation of this file.

    00001 /****************************************************************************\
    00002 *
    00003 *  MDIWIN.C -
    00004 *
    00005 * Copyright (c) 1985 - 1999, Microsoft Corporation
    00006 *
    00007 *      MDI Child Windows Support
    00008 *
    00009 * History
    00010 * 11-14-90 MikeHar     Ported from windows
    00011 * 14-Feb-1991 mikeke   Added Revalidation code
    00012 \****************************************************************************/
    00013
    00014 #include "precomp.h"
    00015 #pragma hdrstop
    00016
    00017 #define TITLE_EXTRA 5
    00018 #define MAX_TITLE_LEN 160
    00019
    00020
    00021 /***************************************************************************\
    00022 * xxxSetFrameTitle
    00023 *
    00024 * if lpch == 1, we redraw the whole frame. If 2, we don't do any redraw. Any
    00025 * other value, and we redraw just the caption of the frame.
    00026 *
    00027 * History:
    00028 * 11-14-90 MikeHar Ported from windows
    00029 * 04-16-91 MikeHar Win31 Merge
    00030 \***************************************************************************/
    00031
    00032 void xxxSetFrameTitle(
    00033     PWND pwndFrame,
    00034     PWND pwndMDI,
    00035     LPWSTR lpch)
    00036 {
    00037     PWND pwnd;
    00038     PMDI pmdi;
    00039     WCHAR sz[MAX_TITLE_LEN];
    00040     HWND  hwndFrame = HW(pwndFrame);
    00041
    00042     CheckLock(pwndFrame);
    00043     CheckLock(pwndMDI);
    00044
    00045     /*
    00046      * Get a pointer to the MDI structure
    00047      */
    00048     pmdi = ((PMDIWND)pwndMDI)->pmdi;
    00049
    00050     if (IS_PTR(lpch) || lpch == NULL) {
    00051         if (HTITLE(pmdi)) {
    00052             UserLocalFree(HTITLE(pmdi));
    00053         }
    00054         HTITLE(pmdi) = TextAlloc(lpch);
    00055     }
    00056
    00057     if (HTITLE(pmdi)) {
    00058         LARGE_UNICODE_STRING str;
    00059         int cch;
    00060
    00061         RtlInitLargeUnicodeString(&str, HTITLE(pmdi), (UINT)-1);
    00062         TextCopy(&str, sz, sizeof(sz)/sizeof(WCHAR));
    00063
    00064         if (MAXED(pmdi) && (pwnd = ValidateHwnd(MAXED(pmdi))) && pwnd->strName.Length) {
    00065
    00066             cch = MAX_TITLE_LEN - ((str.Length / sizeof(WCHAR)) + TITLE_EXTRA);
    00067             if (cch > 0) {
    00068                 wcscat(sz, TEXT(" - ["));
    00069                 wcsncat(sz, REBASE(pwnd, strName.Buffer), cch - 1);
    00070                 wcscat(sz, TEXT("]"));
    00071             }
    00072         }
    00073     } else {
    00074         sz[0] = 0;
    00075     }
    00076
    00077     _DefSetText(hwndFrame, sz, FALSE);
    00078
    00079     if (lpch == (LPWSTR)1L)
    00080         NtUserRedrawFrameAndHook(hwndFrame);
    00081
    00082     else if (lpch != (LPWSTR)2L) {
    00083         if (!NtUserRedrawTitle(hwndFrame, DC_TEXT))
    00084             NtUserRedrawFrame(hwndFrame);
    00085     }
    00086 }
    00087
    00088
    00089 /***************************************************************************\
    00090 * TranslateMDISysAccel
    00091 *
    00092 * History:
    00093 * 11-14-90 MikeHar Ported from windows
    00094 \***************************************************************************/
    00095
    00096 BOOL TranslateMDISysAccel(
    00097     HWND hwnd,
    00098     LPMSG lpMsg)
    00099 {
    00100     PWND pwnd;
    00101     PMDI pmdi;
    00102     int event;
    00103
    00104     /*
    00105      * Is this a message we care about?
    00106      */
    00107     if (lpMsg->message != WM_KEYDOWN && lpMsg->message != WM_SYSKEYDOWN) {
    00108         return FALSE;
    00109     }
    00110
    00111     /*
    00112      * This is called within a message loop. If the window gets destroyed,
    00113      * there still may be other messages in the queue that get returned
    00114      * after the window is destroyed. The app will call TranslateAccelerator()
    00115      * on every one of these, causing RIPs.... Make it nice so it just
    00116      * returns FALSE.
    00117      */
    00118     if ((pwnd = ValidateHwndNoRip(hwnd)) == NULL) {
    00119         RIPERR0(ERROR_INVALID_WINDOW_HANDLE, RIP_VERBOSE, "");
    00120         return FALSE;
    00121     }
    00122
    00123     CheckLock(pwnd);
    00124
    00125     /*
    00126      * Make sure this is really an MDIClient window. Harvard Graphics 2.0
    00127      * calls this function with a different window class and caused us
    00128      * to get an access violation.
    00129      */
    00130     if (GETFNID(pwnd) != FNID_MDICLIENT) {
    00131         RIPMSG0(RIP_WARNING, "Window not of MDIClient class");
    00132         return FALSE;
    00133     }
    00134
    00135     /*
    00136      * Get a pointer to the MDI structure
    00137      */
    00138     pmdi = ((PMDIWND)pwnd)->pmdi;
    00139
    00140     if (!ACTIVE(pmdi))
    00141         return FALSE;
    00142
    00143     if (!IsWindowEnabled(ACTIVE(pmdi)))
    00144         return FALSE;
    00145
    00146     switch (lpMsg->wParam) {
    00147     case VK_F4:
    00148         event = SC_CLOSE;
    00149         break;
    00150     case VK_F6:
    00151     case VK_TAB:
    00152         if (GetKeyState(VK_SHIFT) < 0)
    00153             event = SC_PREVWINDOW;
    00154         else
    00155             event = SC_NEXTWINDOW;
    00156         break;
    00157     default:
    00158         return FALSE;
    00159     }
    00160
    00161     /*
    00162      * All of these have the control key down
    00163      */
    00164     if (GetKeyState(VK_CONTROL) >= 0)
    00165         return FALSE;
    00166
    00167     if (GetKeyState(VK_MENU) < 0)
    00168         return FALSE;
    00169
    00170     SendMessage(ACTIVE(pmdi), WM_SYSCOMMAND, event, MAKELONG(lpMsg->wParam, 0));
    00171
    00172     return TRUE;
    00173 }
    00174
    00175 /***************************************************************************\
    00176 *
    00177 *  CalcClientScrolling()
    00178 *
    00179 \***************************************************************************/
    00180
    00181 #define SBJ_HORZ  HAS_SBHORZ
    00182 #define SBJ_VERT  HAS_SBVERT
    00183 #define SBJ_BOTH  (SBJ_HORZ | SBJ_VERT)
    00184
    00185 void ByteOutsetRect(LPRECT lprc)
    00186 {
    00187     int FAR *pi;
    00188     int i;
    00189
    00190     for (i = 0, pi = (int FAR *) lprc; i < 4; i++, pi++) {
    00191         if (*pi > 0)
    00192             *pi += 7;
    00193         else if (*pi < 0)
    00194             *pi -= 7;
    00195
    00196         *pi /= 8;
    00197     }
    00198 }
    00199
    00200 void CalcClientScrolling(HWND hwnd, UINT sbj, BOOL fIgnoreMin)
    00201 {
    00202     PWND pwnd;
    00203     RECT rcScroll;
    00204     RECT rcClient;
    00205     RECT rcRange;
    00206     RECT rcT;
    00207     PWND pwndT;
    00208     BOOL fVert;
    00209     BOOL fHorz;
    00210     BYTE fHadVert, fHadHorz;
    00211     BOOL fCheckVert;
    00212     BOOL fCheckHorz;
    00213     BOOL fNeedScrolls;
    00214     SCROLLINFO si;
    00215
    00216     if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
    00217         return;
    00218     }
    00219     CheckLock(pwnd);
    00220
    00221     UserAssert(GETFNID(pwnd) != FNID_DESKTOP);
    00222
    00223     // do nothing if the parent is iconic.  This way, we don't add invisible
    00224     // scrollbars which will paint and unpaint when restoring...
    00225     if (TestWF(pwnd, WFMINIMIZED))
    00226         return;
    00227
    00228     fVert = FALSE;
    00229     fHorz = FALSE;
    00230     fNeedScrolls=FALSE;
    00231
    00232     fCheckHorz = (sbj & SBJ_HORZ);
    00233     fCheckVert = (sbj & SBJ_VERT);
    00234
    00235     // find client area without scroll bars
    00236     CopyRect(&rcClient, &pwnd->rcClient);
    00237
    00238     fHadVert = TestWF(pwnd, WFVSCROLL);
    00239     if (fCheckVert && fHadVert)
    00240         rcClient.right += SYSMET(CXVSCROLL);
    00241
    00242     fHadHorz = TestWF(pwnd, WFHSCROLL);
    00243     if (fCheckHorz && fHadHorz)
    00244         rcClient.bottom += SYSMET(CYHSCROLL);
    00245
    00246     // find the rectangle that bounds all visible child windows
    00247     SetRectEmpty(&rcScroll);
    00248
    00249     for (pwndT = REBASEPWND(pwnd, spwndChild); pwndT;
    00250             pwndT = REBASEPWND(pwndT, spwndNext)) {
    00251         if (fIgnoreMin && TestWF(pwndT, WFMINIMIZED))
    00252             continue;
    00253
    00254         if (TestWF(pwndT,WFVISIBLE)) {
    00255             if (TestWF(pwndT, WFMAXIMIZED)) {
    00256                 fNeedScrolls = FALSE;
    00257                 break;
    00258             }
    00259
    00260             /*
    00261              * add this window to the area that has to be visible
    00262              */
    00263             UnionRect(&rcScroll, &rcScroll, &pwndT->rcWindow);
    00264
    00265             /*
    00266              * add scroll bars if its not contained in the
    00267              * client area
    00268              */
    00269             UnionRect(&rcT, &rcClient, &pwndT->rcWindow);
    00270             if (!EqualRect(&rcClient, &rcT)) {
    00271                 fNeedScrolls = TRUE;
    00272             }
    00273         }
    00274     }
    00275
    00276     SetRectEmpty(&rcRange);
    00277
    00278     // offset rectangles such that rcClient's top & left are both 0
    00279     // making rcClient's right & bottom be the page size
    00280     OffsetRect(&rcScroll, -rcClient.left, -rcClient.top);
    00281     OffsetRect(&rcClient, -rcClient.left, -rcClient.top);
    00282
    00283     if (!fNeedScrolls)
    00284         rcClient.bottom = rcClient.right = 0;
    00285     else do
    00286     {
    00287             /*
    00288              * the range is the union of the parent client with all of its
    00289              * children
    00290              */
    00291         CopyRect(&rcT, &rcRange);
    00292         UnionRect(&rcRange, &rcScroll, &rcClient);
    00293
    00294         if (fCheckVert) {
    00295             // subtract off space for the vertical scroll if we need it
    00296             if (((rcRange.bottom - rcRange.top) > rcClient.bottom) && !fVert) {
    00297                 fVert = TRUE;
    00298                 rcClient.right -= SYSMET(CXVSCROLL);
    00299             }
    00300         }
    00301
    00302         if (fCheckHorz) {
    00303             // subtract off space for the horizontal scroll if we need it
    00304             if (((rcRange.right - rcRange.left) > rcClient.right) && !fHorz) {
    00305                 fHorz = TRUE;
    00306                 rcClient.bottom -= SYSMET(CYHSCROLL);
    00307             }
    00308         }
    00309     }
    00310     while (!EqualRect(&rcRange, &rcT));
    00311
    00312     if (fNeedScrolls) {
    00313         // HACK of death beginning
    00314         if (rcRange.right == rcClient.right)
    00315             rcRange.right -= 8;
    00316
    00317         if (rcRange.bottom == rcClient.bottom)
    00318             rcRange.bottom -= 8;
    00319         // HACK of death ending
    00320     }
    00321
    00322     if (fCheckVert) {
    00323
    00324         /*
    00325          * check to see if we are changing the presence of the vertical
    00326          * scrollbar
    00327          */
    00328         if ((rcRange.bottom - rcRange.top) <= rcClient.bottom) {
    00329             ClearWindowState(pwnd, WFVSCROLL);
    00330         } else {
    00331             SetWindowState(pwnd, WFVSCROLL);
    00332        }
    00333     }
    00334
    00335     if (fCheckHorz) {
    00336
    00337         /*
    00338          * same for horizontal scroll
    00339          */
    00340         if ((rcRange.right - rcRange.left) <= rcClient.right) {
    00341             ClearWindowState(pwnd, WFHSCROLL);
    00342         } else {
    00343             SetWindowState(pwnd, WFHSCROLL);
    00344         }
    00345     }
    00346
    00347     if (fNeedScrolls) {
    00348         ByteOutsetRect(&rcClient);
    00349         ByteOutsetRect(&rcRange);
    00350     }
    00351
    00352     si.cbSize   = sizeof(SCROLLINFO);
    00353     si.fMask    = SIF_ALL;
    00354     si.nPos     = 0;
    00355
    00356     si.nMin     = rcRange.left;
    00357     si.nMax     = rcRange.right;
    00358     si.nPage    = rcClient.right;
    00359
    00360     NtUserSetScrollInfo(hwnd, SB_HORZ, &si, FALSE);
    00361
    00362     si.nMin     = rcRange.top;
    00363     si.nMax     = rcRange.bottom;
    00364     si.nPage    = rcClient.bottom;
    00365
    00366     NtUserSetScrollInfo(hwnd, SB_VERT, &si, FALSE);
    00367
    00368     if ((fHadVert != TestWF(pwnd, WFVSCROLL)) ||
    00369         (fHadHorz != TestWF(pwnd, WFHSCROLL)))
    00370     NtUserRedrawFrame(hwnd);
    00371 }
    00372
    00373
    00374 /***************************************************************************\
    00375 * ScrollChildren
    00376 *
    00377 *  Handles WM_VSCROLL and WM_HSCROLL messages
    00378 *
    00379 * History:
    00380 * 11-14-90 MikeHar Ported from windows
    00381 \***************************************************************************/
    00382
    00383 void ScrollMDIChildren(
    00384     HWND hwnd,
    00385     int nCtl,
    00386     UINT wCmd,
    00387     int iThumbPos)
    00388 {
    00389     SCROLLINFO  si;
    00390     int wInc;
    00391     int wNewPos;
    00392     //SHORT sPos;
    00393     int          x, y;
    00394
    00395     wInc = (((nCtl == SB_VERT) ? SYSMET(CYSIZE) : SYSMET(CXSIZE)) + 7) / 8;
    00396
    00397     si.cbSize   = sizeof(SCROLLINFO);
    00398     si.fMask    = SIF_ALL;
    00399     GetScrollInfo(hwnd, nCtl, &si);
    00400
    00401     si.nPage--;
    00402     si.nMax -= si.nPage;
    00403
    00404     switch (wCmd) {
    00405     case SB_BOTTOM:
    00406         wNewPos = si.nMax;
    00407         break;
    00408     case SB_TOP:
    00409         wNewPos = si.nMin;
    00410         break;
    00411     case SB_LINEDOWN:
    00412         wNewPos = si.nPos + wInc;
    00413         break;
    00414     case SB_LINEUP:
    00415         wNewPos = si.nPos - wInc;
    00416         break;
    00417     case SB_PAGEDOWN:
    00418         wNewPos = si.nPos + si.nPage;
    00419         break;
    00420     case SB_PAGEUP:
    00421         wNewPos = si.nPos - si.nPage;
    00422         break;
    00423     case SB_THUMBPOSITION:
    00424
    00425         wNewPos = iThumbPos;
    00426         break;
    00427     case SB_ENDSCROLL:
    00428         CalcClientScrolling(hwnd, (nCtl == SB_VERT) ? SBJ_VERT : SBJ_HORZ, FALSE);
    00429
    00430     /*
    00431      ** FALL THRU **
    00432      */
    00433     default:
    00434         return;
    00435     }
    00436
    00437     if (wNewPos < si.nMin)
    00438         wNewPos = si.nMin;
    00439     else if (wNewPos > si.nMax)
    00440         wNewPos = si.nMax;
    00441
    00442     SetScrollPos(hwnd, nCtl, wNewPos, TRUE);
    00443
    00444     // the "* 8" is because we need to scroll in bytes.  The scrollbar
    00445     // increments for MDI are bytes (this is due to the fact that we need to
    00446     // not upset the brush origin of the app workspace brush that is used to
    00447     // fill the MDI background)
    00448
    00449     x = (si.nPos - wNewPos) * 8;
    00450
    00451     if (nCtl == SB_VERT) {
    00452         y = x;
    00453         x = 0;
    00454     } else
    00455         // x is already set properly for this case
    00456         y = 0;
    00457
    00458     NtUserScrollWindowEx(hwnd, x, y, NULL, NULL, NULL, NULL,
    00459            SW_SCROLLWINDOW | SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN);
    00460 }
    00461
    00462
    00463 VOID ScrollChildren(
    00464     HWND hwnd,
    00465     UINT wMsg,
    00466     DWORD wParam)
    00467 {
    00468     ScrollMDIChildren(hwnd,
    00469                       wMsg == WM_VSCROLL ? SB_VERT : SB_HORZ,
    00470                       LOWORD(wParam),
    00471                       (short)(HIWORD(wParam)));
    00472 }
    00473
    00474
    00475 /***************************************************************************\
    00476 * RecalculateScrollRanges
    00477 *
    00478 * History:
    00479 * 11-14-90 MikeHar Ported from windows
    00480 * 04-16-91 MikeHar Win31 Merge
    00481 \***************************************************************************/
    00482
    00483 void RecalculateScrollRanges(
    00484     PWND pwndParent,
    00485     BOOL fIgnoreMin)
    00486 {
    00487     PMDI pmdi = ((PMDIWND)pwndParent)->pmdi;
    00488
    00489     if (!(SCROLL(pmdi) & (CALCSCROLL | SCROLLCOUNT))) {
    00490         if (PostMessage(HWq(pwndParent), MM_CALCSCROLL, fIgnoreMin, 0L)) {
    00491             SCROLL(pmdi) |= CALCSCROLL;
    00492         }
    00493     }
    00494 }
    00495
    00496
    00497 /***************************************************************************\
    00498 * GetCascadeWindowPos
    00499 *
    00500 * History:
    00501 * 11-14-90 MikeHar Ported from windows
    00502 * 01-12-94 FritzS  Ported from Chicago
    00503 \***************************************************************************/
    00504
    00505 void GetCascadeWindowPos(
    00506     LPCRECT prcClient,  /* area to arrange to */
    00507     int     iWindow,    /* index of this window */
    00508     LPRECT  lprc)       /* resulting rectangle */
    00509 {
    00510     int cStack;
    00511     int xStep, yStep;
    00512     int dxClient, dyClient;
    00513
    00514     /*
    00515      * Compute the width and breadth of the situation.
    00516      */
    00517     dxClient = prcClient->right - prcClient->left;
    00518     UserAssert(dxClient >= 0);
    00519     dyClient = prcClient->bottom - prcClient->top;
    00520     UserAssert(dyClient >= 0);
    00521
    00522     /*
    00523      * Compute the width and breadth of the window steps.
    00524      */
    00525     xStep = SYSMET(CXSIZEFRAME) + SYSMET(CXSIZE);
    00526     yStep = SYSMET(CYSIZEFRAME) + SYSMET(CYSIZE);
    00527
    00528     /*
    00529      * How many windows per stack?
    00530      */
    00531     cStack = dyClient / (3 * yStep);
    00532
    00533     lprc->right = dxClient - (cStack * xStep);
    00534     lprc->bottom = dyClient - (cStack * yStep);
    00535
    00536     /*
    00537      * HACK!: Mod by cStack+1 and make sure no div-by-zero
    00538      * exception happens.
    00539      */
    00540     if (++cStack <= 0) {
    00541         cStack = 1;
    00542     }
    00543
    00544     lprc->left = prcClient->left + (iWindow % cStack) * xStep;
    00545     lprc->top = prcClient->top + (iWindow % cStack) * yStep;
    00546 }
    00547
    00548
    00549 /***************************************************************************\
    00550 * MDICheckCascadeRect
    00551 *
    00552 * History:
    00553 * 11-14-90 MikeHar Ported from windows
    00554 * 04-16-91 MikeHar Win31 Merge
    00555 \***************************************************************************/
    00556
    00557 void MDICheckCascadeRect(
    00558     PWND pwndClient,
    00559     LPRECT lprc)
    00560 {
    00561     PMDI pmdi;
    00562     RECT rc, rcClient;
    00563     int         iWindow;
    00564
    00565     /*
    00566      * Get a pointer to the MDI structure
    00567      */
    00568     pmdi = ((PMDIWND)pwndClient)->pmdi;
    00569
    00570     iWindow = ITILELEVEL(pmdi);
    00571
    00572     GetRect(pwndClient, &rcClient, GRECT_CLIENT | GRECT_CLIENTCOORDS);
    00573     GetCascadeWindowPos(&rcClient, iWindow, &rc);
    00574
    00575     if ((lprc->right == CW_USEDEFAULT || lprc->right == CW2_USEDEFAULT) ||
    00576             !(lprc->right)) {
    00577         lprc->right = rc.right;
    00578     }
    00579
    00580     if ((lprc->bottom == CW_USEDEFAULT || lprc->bottom == CW2_USEDEFAULT) ||
    00581             !(lprc->bottom)) {
    00582         lprc->bottom = rc.bottom;
    00583     }
    00584
    00585     if (lprc->left == CW_USEDEFAULT || lprc->left == CW2_USEDEFAULT) {
    00586         lprc->left = rc.left;
    00587         lprc->top = rc.top;
    00588     }
    00589 }
    00590
    00591
    00592 /***************************************************************************\
    00593 * UnMaximizeChildWindows
    00594 *
    00595 * effects: Helper routine used by TileChildWindows and CascadeChildWindows to
    00596 * restore any maximized windows of the given parent. Returns TRUE if a
    00597 * maximized window was restored.
    00598 *
    00599 * History:
    00600 * 4-16-91 MikeHar       Win31 Merge
    00601 \***************************************************************************/
    00602
    00603 BOOL UnmaximizeChildWindows(
    00604     HWND hwndParent)
    00605 {
    00606     HWND hwndMove;
    00607     PWND pwndMove;
    00608     BOOL fFoundOne = FALSE;
    00609     BOOL fAsync;
    00610     UINT chwnd;
    00611     HWND *phwndList;
    00612     HWND *phwnd;
    00613     HWND hwndChild = GetWindow(hwndParent, GW_CHILD);
    00614
    00615     /*
    00616      * Get the hwnd list.  It is returned in a block of memory
    00617      * allocated with LocalAlloc.
    00618      */
    00619     if (hwndChild == NULL ||
    00620             (chwnd = BuildHwndList(NULL, GetWindow(hwndParent, GW_CHILD),
    00621                                    FALSE, 0, &phwndList)) == 0) {
    00622         return FALSE;
    00623     }
    00624
    00625     fAsync = (hwndParent == GetDesktopWindow());
    00626
    00627     for (phwnd = phwndList; chwnd > 0; chwnd--, phwnd++) {
    00628         if ((hwndMove = *phwnd) == NULL)
    00629             continue;
    00630
    00631         if ((pwndMove = ValidateHwnd(hwndMove)) == NULL)
    00632             continue;
    00633
    00634 // Not in Chicago -- FritzS
    00635 //        if (pwndMove->spwndOwner != NULL)
    00636 //            continue;
    00637
    00638         if (TestWF(pwndMove, WFMAXIMIZED) && TestWF(pwndMove, WFVISIBLE)) {
    00639             //
    00640             // If we haven't done it yet, lock the screen to prevent sending
    00641             // paints for a cleaner update.
    00642             //
    00643             if (!fFoundOne && fAsync)
    00644                 NtUserLockWindowUpdate(hwndParent);
    00645
    00646             fFoundOne = TRUE;
    00647
    00648             if (fAsync)
    00649                 NtUserShowWindowAsync(hwndMove, SW_SHOWNOACTIVATE);
    00650             else
    00651                 NtUserShowWindow(hwndMove, SW_SHOWNORMAL);
    00652         }
    00653     }
    00654
    00655     UserLocalFree(phwndList);
    00656
    00657     if (fFoundOne && fAsync) {
    00658
    00659         HWND hwndActive = NtUserGetForegroundWindow();
    00660         if (hwndActive != NULL) {
    00661
    00662             /*
    00663              * Hack! Since the above showwindows cause zorder changes, we want
    00664              * the active window to be in front.  This makes sure...
    00665              */
    00666             NtUserSetWindowPos(hwndActive, HWND_TOP, 0, 0, 0, 0,
    00667                 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS);
    00668
    00669         }
    00670         NtUserLockWindowUpdate(NULL);
    00671         RedrawWindow(hwndParent, NULL, NULL,
    00672                 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE | RDW_FRAME);
    00673     }
    00674
    00675     return fFoundOne;
    00676 }
    00677
    00678
    00679 /***************************************************************************\
    00680 *
    00681 * ARRANGEWINDOWSDATA: passed to EnumDisplayMonitors enumeration functions.
    00682 *
    00683 \***************************************************************************/
    00684
    00685 typedef struct tagARRANGEWINDOWSDATA {
    00686     PWND    pwndParent;
    00687     UINT    flags;
    00688     LPRECT  lprcParent;
    00689     int     chwnd;
    00690     int     chwndReal;
    00691     HWND *  phwnd;
    00692     PWND    pwndDesktop;
    00693     HDWP    hdwp;
    00694     UINT    uGRCFlags;
    00695     int     fVerifyParent;
    00696 } ARRANGEWINDOWSDATA, *PARRANGEWINDOWSDATA;
    00697
    00698
    00699
    00700 /***************************************************************************\
    00701 * ArrangeWindows
    00702 *
    00703 * Called from CascadeWindows and TileWindows, it performs what
    00704 * is common to both functions, and calls out to the enumeration
    00705 * function to do the work of window arrangement.
    00706 *
    00707 * History:
    00708 * 10-Jul-1997 adams     Created.
    00709 \***************************************************************************/
    00710
    00711 WORD ArrangeWindows(
    00712     HWND            hwndParent,
    00713     UINT            flags,
    00714     CONST RECT *    lpRect,
    00715     UINT            chwnd,
    00716     CONST HWND *    ahwnd,
    00717     MONITORENUMPROC lpfnEnum)
    00718 {
    00719     ARRANGEWINDOWSDATA  awd;
    00720     HWND *              phwnd = NULL;
    00721
    00722     /*
    00723      * Get parent window
    00724      */
    00725     awd.pwndDesktop = _GetDesktopWindow();
    00726     if (!hwndParent) {
    00727         hwndParent = HW(awd.pwndDesktop);
    00728         awd.pwndParent = awd.pwndDesktop;
    00729     } else {
    00730         awd.pwndParent = ValidateHwnd(hwndParent);
    00731         if (awd.pwndParent == NULL) {
    00732             return 0;
    00733         }
    00734     }
    00735
    00736     UnmaximizeChildWindows(hwndParent);
    00737
    00738     /*
    00739      * If the rect passed in contains the desktop window,
    00740      * arrange the windows on the desktop
    00741      */
    00742     if ( lpRect &&
    00743          awd.pwndParent == awd.pwndDesktop   &&
    00744          lpRect->left   <= awd.pwndDesktop->rcClient.left   &&
    00745          lpRect->top    <= awd.pwndDesktop->rcClient.top    &&
    00746          lpRect->right  >= awd.pwndDesktop->rcClient.right  &&
    00747          lpRect->bottom >= awd.pwndDesktop->rcClient.bottom ) {
    00748
    00749         lpRect = NULL;
    00750     }
    00751
    00752     /*
    00753      * Arrange iconic windows if appropriate, and determine flags
    00754      * for getting the client rectangle if no rect is given.
    00755      */
    00756     if (lpRect == NULL) {
    00757         if (    (   awd.pwndParent != awd.pwndDesktop ||
    00758                     !(SYSMET(ARRANGE) & ARW_HIDE)) &&
    00759                 NtUserArrangeIconicWindows(hwndParent) != 0) {
    00760
    00761             awd.uGRCFlags = GRC_SCROLLS | GRC_MINWNDS;
    00762         } else {
    00763             awd.uGRCFlags = GRC_SCROLLS;
    00764         }
    00765     }
    00766
    00767     /*
    00768      * Get window list
    00769      */
    00770     if (ahwnd == NULL) {
    00771         HWND hwndChild;
    00772         PWND pwndChild;
    00773
    00774         pwndChild = REBASEPWND(awd.pwndParent, spwndChild);
    00775         hwndChild = HW(pwndChild);
    00776         if (    hwndChild == NULL ||
    00777                 (chwnd = BuildHwndList(NULL, hwndChild, FALSE, 0, &phwnd)) == 0) {
    00778             return 0;
    00779         }
    00780     }
    00781
    00782     /*
    00783      * Arrange windows
    00784      */
    00785     awd.hdwp = NtUserBeginDeferWindowPos(chwnd);
    00786     if (awd.hdwp == NULL)
    00787         goto Done;
    00788
    00789     awd.flags = flags;
    00790     awd.lprcParent = (LPRECT) lpRect;
    00791     awd.chwnd = chwnd;
    00792     awd.chwndReal = 0;
    00793     awd.phwnd = ahwnd ? (HWND *) ahwnd : phwnd;
    00794     awd.fVerifyParent = (ahwnd != NULL);
    00795
    00796     /*
    00797      * If the parent is the desktop and a rectangle is not provided,
    00798      * arrange the windows on each monitor. Otherwise, arrange the
    00799      * windows once by calling the enumeration function directly.
    00800      */
    00801     if (awd.pwndParent == awd.pwndDesktop && lpRect == NULL) {
    00802             NtUserEnumDisplayMonitors(NULL, NULL, lpfnEnum, (LPARAM) &awd);
    00803     } else {
    00804         (*lpfnEnum)(NULL, NULL, NULL, (LPARAM) &awd);
    00805     }
    00806
    00807     /* Make this arrangement asynchronous so we don't hang */
    00808     if (awd.hdwp != NULL) {
    00809         NtUserEndDeferWindowPosEx(awd.hdwp, TRUE);
    00810     }
    00811
    00812 Done:
    00813     if (phwnd) {
    00814         UserLocalFree(phwnd);
    00815     }
    00816
    00817     return (awd.hdwp != NULL) ? awd.chwndReal : 0;
    00818 }
    00819
    00820
    00821
    00822 /***************************************************************************\
    00823 * GetParentArrangeRect
    00824 *
    00825 * Returns the rect passed in pawd if provided, otherwise gets the client
    00826 * rect of the parent window.
    00827 *
    00828 * History:
    00829 * 10-Jul-1997 adams     Created.
    00830 \***************************************************************************/
    00831
    00832 void
    00833 GetParentArrangeRect(PARRANGEWINDOWSDATA pawd, PMONITOR pMonitor, LPRECT lprc)
    00834 {
    00835     UINT    uGRCFlags;
    00836
    00837     if (pawd->lprcParent) {
    00838         *lprc = *pawd->lprcParent;
    00839     } else {
    00840         uGRCFlags = pawd->uGRCFlags;
    00841
    00842         /*
    00843          * If icons are shown on the desktop, then they are always
    00844          * shown on the primary monitor. So remove the GRC_MINWNDS
    00845          * flag for monitors other than the primary.
    00846          */
    00847         if (pMonitor && pMonitor != GetPrimaryMonitor()) {
    00848             uGRCFlags &= ~GRC_MINWNDS;
    00849         }
    00850
    00851         GetRealClientRect(
    00852                 pawd->pwndParent, lprc, uGRCFlags, pMonitor);
    00853     }
    00854 }
    00855
    00856
    00857
    00858 /***************************************************************************\
    00859 * ValidatePositionableWindow
    00860 *
    00861 * Validates and returns a window if it is positionable, and sets
    00862 * the appropriate sizing flags.
    00863 *
    00864 * History:
    00865 * 10-Jul-1997 adams     Created.
    00866 \***************************************************************************/
    00867
    00868 PWND
    00869 ValidatePositionableWindow(
    00870         HWND        hwndChild,
    00871         PWND        pwndParent,
    00872         PWND        pwndDesktop,
    00873         DWORD       dwMDIFlags,
    00874         PMONITOR    pMonitor,
    00875         DWORD *     pdwSWPFlags)
    00876 {
    00877     PWND    pwndChild;
    00878
    00879     pwndChild = ValidateHwnd(hwndChild);
    00880     if (pwndChild) {
    00881         if (pwndParent && REBASEPWND(pwndChild, spwndParent) != pwndParent) {
    00882             RIPMSG0(RIP_WARNING, "Cascade/Tile Windows: Windows in list must have same parent");
    00883         } else if (
    00884                 /*
    00885                  * mikesch - removed the maximized check since the call
    00886                  * to restore maximized windows in unmaximizechildwindows occurs
    00887                  * asynchronously now.
    00888                  */
    00889                 TestWF(pwndChild, WFVISIBLE) &&
    00890                 TestWF(pwndChild, WFCPRESENT) &&
    00891                 !TestWF(pwndChild, WFMINIMIZED) &&
    00892                 !TestWF(pwndChild, WEFTOPMOST) &&
    00893                 (!(dwMDIFlags & MDITILE_SKIPDISABLED) || !TestWF(pwndChild, WFDISABLED)) &&
    00894                 !TestWF(pwndChild, WEFTOOLWINDOW) &&
    00895                 ((pMonitor) ?
    00896                     (pMonitor == _MonitorFromWindow(pwndChild, MONITOR_DEFAULTTONULL)) :
    00897                     (pwndParent != pwndDesktop || _MonitorFromWindow(pwndChild, MONITOR_DEFAULTTONULL)))) {
    00898
    00899                     if (pdwSWPFlags) {
    00900                         *pdwSWPFlags = SWP_NOACTIVATE | SWP_NOCOPYBITS;
    00901                         if (!TestWF(pwndChild, WFSIZEBOX)) {
    00902                             *pdwSWPFlags |= SWP_NOSIZE;
    00903                         }
    00904                         if (!(dwMDIFlags & MDITILE_ZORDER)) {
    00905                             *pdwSWPFlags |= SWP_NOZORDER;
    00906                         }
    00907                     }
    00908             return pwndChild;
    00909         }
    00910     }
    00911
    00912     return NULL;
    00913 }
    00914
    00915
    00916
    00917 /***************************************************************************\
    00918 * CascadeWindowsEnum
    00919 *
    00920 * Cascades windows on the monitor.
    00921 *
    00922 * History:
    00923 * 10-Jul-1997 adams     Created.
    00924 \***************************************************************************/
    00925
    00926 BOOL CALLBACK
    00927 CascadeWindowsEnum(
    00928         HMONITOR    hmonitor,
    00929         HDC         hdc,
    00930         LPRECT      lprc,
    00931         LPARAM      lparam)
    00932 {
    00933     PARRANGEWINDOWSDATA pawd = (PARRANGEWINDOWSDATA)lparam;
    00934     PMONITOR    pMonitor = hmonitor ? VALIDATEHMONITOR(hmonitor) : NULL;
    00935     RECT        rcParent;
    00936     int         i;
    00937     int         chwndReal = 0;
    00938     RECT        rc;
    00939     HWND        * phwnd, * phwndCopy;
    00940     BOOL        fRet = TRUE;
    00941
    00942     UNREFERENCED_PARAMETER(hdc);
    00943     UNREFERENCED_PARAMETER(lprc);
    00944
    00945     /*
    00946      * Get the parent rectangle if none is given.
    00947      */
    00948     GetParentArrangeRect(pawd, pMonitor, &rcParent);
    00949
    00950     /*
    00951      * New for NT5: MDITILE_ZORDER (for the SHELL guys)
    00952      * Sort pawd->phwnd by z-order
    00953      */
    00954     if (pawd->flags & MDITILE_ZORDER) {
    00955         PWND pwndChild;
    00956         HWND * phwndFullList, * phwndNext, * phwndSort, * phwndSearch;
    00957         int chwndFullList, chwndSort, chwndSearch;
    00958         /*
    00959          * Make a copy to leave their array alone (it's supposed to be const)
    00960          */
    00961         phwndCopy = UserLocalAlloc(0, pawd->chwnd * sizeof(HWND));
    00962         if (phwndCopy == NULL) {
    00963             return FALSE;
    00964         }
    00965         RtlCopyMemory(phwndCopy, pawd->phwnd, pawd->chwnd * sizeof(HWND));
    00966         /*
    00967          * Get the sibblings Z-Ordered list.
    00968          */
    00969         pwndChild = REBASEPWND(pawd->pwndParent, spwndChild);
    00970         if (pwndChild == NULL) {
    00971             fRet = FALSE;
    00972             goto CleanUp;
    00973         }
    00974         chwndFullList = BuildHwndList(NULL, HWq(pwndChild), FALSE, 0, &phwndFullList);
    00975         if (chwndFullList == 0) {
    00976             fRet = FALSE;
    00977             goto CleanUp;
    00978         }
    00979         /*
    00980          * Loop through the Z-Ordered list looking for the windows in the array
    00981          */
    00982         for (phwndNext = phwndFullList, chwndSort = pawd->chwnd, phwndSort = phwndCopy;
    00983                 (chwndFullList > 0) && (chwndSort > 1);
    00984                 chwndFullList--, phwndNext++) {
    00985
    00986             for (chwndSearch = chwndSort, phwndSearch = phwndSort;
    00987                     chwndSearch > 0;
    00988                     chwndSearch--, phwndSearch++) {
    00989                 /*
    00990                  * If it found a window, move it after the last sorted window.
    00991                  */
    00992                 if (*phwndNext == *phwndSearch) {
    00993                     HWND hwndFirst = *phwndSort;
    00994                     *phwndSort = *phwndSearch;
    00995                     *phwndSearch = hwndFirst;
    00996                     phwndSort++;
    00997                     chwndSort--;
    00998                     break;
    00999                 }
    01000             }
    01001         }
    01002         UserLocalFree(phwndFullList);
    01003     } else { /* if (pawd->flags & MDITILE_ZORDER) */
    01004         phwndCopy = pawd->phwnd;
    01005     }
    01006
    01007     /*
    01008      * Arrange the windows in the list, preserving z-order.
    01009      */
    01010     for (i = pawd->chwnd, phwnd = phwndCopy + i - 1; --i >= 0; phwnd--) {
    01011         HWND    hwndChild;
    01012         PWND    pwndChild = NULL;
    01013         DWORD   dwSWPFlags;
    01014
    01015         hwndChild = *phwnd;
    01016         pwndChild = ValidatePositionableWindow(
    01017                 hwndChild,
    01018                 pawd->fVerifyParent ? pawd->pwndParent : NULL,
    01019                 pawd->pwndDesktop,
    01020                 pawd->flags,
    01021                 pMonitor,
    01022                 &dwSWPFlags);
    01023
    01024         if (!pwndChild)
    01025             continue;
    01026
    01027         GetCascadeWindowPos(&rcParent, chwndReal, &rc);
    01028
    01029         pawd->hdwp = NtUserDeferWindowPos(
    01030                 pawd->hdwp,
    01031                 hwndChild,
    01032                 HWND_TOP,
    01033                 rc.left,
    01034                 rc.top,
    01035                 rc.right,
    01036                 rc.bottom,
    01037                 dwSWPFlags);
    01038
    01039         chwndReal++;
    01040         pawd->chwndReal++;
    01041     }
    01042
    01043 CleanUp:
    01044     if (pawd->flags & MDITILE_ZORDER) {
    01045         UserLocalFree(phwndCopy);
    01046     }
    01047
    01048     return fRet && (pawd->hdwp != NULL);
    01049 }
    01050
    01051
    01052
    01053 /***************************************************************************\
    01054 *
    01055 *  CascadeWindows()
    01056 *
    01057 *  Cascades a list of children within a parent, according to the flags and
    01058 *  the rectangle passed in.
    01059 *
    01060 \***************************************************************************/
    01061 WORD CascadeWindows(
    01062     HWND hwndParent,
    01063     UINT flags,
    01064     CONST RECT *lpRect,
    01065     UINT chwnd,
    01066     CONST HWND *ahwnd)
    01067 {
    01068     return ArrangeWindows(hwndParent, flags, lpRect, chwnd, ahwnd, CascadeWindowsEnum);
    01069 }
    01070
    01071 BOOL CALLBACK
    01072 TileWindowsEnum(
    01073         HMONITOR    hmonitor,
    01074         HDC         hdc,
    01075         LPRECT      lprc,
    01076         LPARAM      lparam)
    01077 {
    01078     PARRANGEWINDOWSDATA pawd = (PARRANGEWINDOWSDATA)lparam;
    01079     PMONITOR    pMonitor = hmonitor ? VALIDATEHMONITOR(hmonitor) : NULL;
    01080     RECT        rcParent;
    01081     int         ihwnd;
    01082     int         chwndReal;
    01083     int         square;
    01084     int         iCol, iRow;
    01085     int         cCol, cRow;
    01086     int         cRem;
    01087     int         dx, dy;
    01088     int         xRes, yRes;
    01089
    01090     UNREFERENCED_PARAMETER(hdc);
    01091     UNREFERENCED_PARAMETER(lprc);
    01092
    01093     /*
    01094      * Get the parent rectangle if none is given.
    01095      */
    01096     GetParentArrangeRect(pawd, pMonitor, &rcParent);
    01097
    01098     /*
    01099      * Now, figure out how many REAL windows we have.
    01100      */
    01101     chwndReal = 0;
    01102     for (ihwnd = pawd->chwnd; --ihwnd >= 0;) {
    01103         if (ValidatePositionableWindow(
    01104                 pawd->phwnd[ihwnd],
    01105                 pawd->fVerifyParent ? pawd->pwndParent : NULL,
    01106                 pawd->pwndDesktop,
    01107                 pawd->flags,
    01108                 pMonitor,
    01109                 NULL)) {
    01110
    01111             chwndReal++;
    01112         }
    01113     }
    01114
    01115     if (chwndReal == 0)
    01116         return TRUE;
    01117
    01118     xRes = rcParent.right - rcParent.left;
    01119     yRes = rcParent.bottom - rcParent.top;
    01120     if (xRes <= 0 || yRes <= 0)
    01121         return TRUE;
    01122
    01123     /*
    01124      * Compute nearest least square
    01125      */
    01126     for (square = 2; square * square <= chwndReal; square++) {
    01127         ;
    01128     }
    01129
    01130     if (pawd->flags & MDITILE_HORIZONTAL) {
    01131         cCol = square - 1;
    01132         cRow = chwndReal / cCol;
    01133         cRem = chwndReal % cCol;
    01134     } else {
    01135         cRow = square - 1;
    01136         cCol = chwndReal / cRow;
    01137         cRem = chwndReal % cRow;
    01138     }
    01139
    01140     chwndReal = 0;
    01141     ihwnd = -1;
    01142     for (iCol = 0; iCol < cCol; iCol++) {
    01143         /*
    01144          * Add one extra row to handle the remainders.
    01145          */
    01146         if (cCol - iCol <= cRem) {
    01147             cRow++;
    01148         }
    01149
    01150         for (iRow = 0; iRow < cRow; iRow++) {
    01151             HWND    hwndChild;
    01152             PWND    pwndChild;
    01153             DWORD   dwSWPFlags;
    01154
    01155             dx = xRes / cCol;
    01156             dy = yRes / cRow;
    01157
    01158 NextWindow:
    01159             /*
    01160              * Skip bogus and nonpositionable windows
    01161              */
    01162             ihwnd++;
    01163             if (ihwnd >= pawd->chwnd)
    01164                 return TRUE;
    01165
    01166             hwndChild = pawd->phwnd[ihwnd];
    01167             pwndChild = ValidatePositionableWindow(
    01168                     hwndChild,
    01169                     pawd->fVerifyParent ? pawd->pwndParent : NULL,
    01170                     pawd->pwndDesktop,
    01171                     pawd->flags,
    01172                     pMonitor,
    01173                     &dwSWPFlags);
    01174
    01175             if (!pwndChild)
    01176                 goto NextWindow;
    01177
    01178             /*
    01179              * Move, size the window
    01180              */
    01181             pawd->hdwp = NtUserDeferWindowPos(
    01182                     pawd->hdwp,
    01183                     hwndChild,
    01184                     HWND_TOP,
    01185                     rcParent.left + iCol*dx,
    01186                     rcParent.top + iRow*dy,
    01187                     dx,
    01188                     dy,
    01189                     dwSWPFlags);
    01190
    01191             if (pawd->hdwp == NULL)
    01192                 return FALSE;
    01193
    01194             chwndReal++;
    01195             pawd->chwndReal++;
    01196         }
    01197
    01198         if (cCol - iCol <= cRem) {
    01199             cRow--;
    01200             cRem--;
    01201         }
    01202     }
    01203
    01204     return TRUE;
    01205 }
    01206
    01207
    01208
    01209 /***************************************************************************\
    01210 *
    01211 *  TileWindows()
    01212 *
    01213 *  Tiles a list of children within a parent, according to the flags and
    01214 *  the rectangle passed in.
    01215 *
    01216 \***************************************************************************/
    01217 WORD TileWindows(
    01218     HWND        hwndParent,
    01219     UINT        flags,
    01220     CONST RECT *lpRect,
    01221     UINT        chwnd,
    01222     CONST HWND *ahwnd)
    01223 {
    01224     return ArrangeWindows(hwndParent, flags, lpRect, chwnd, ahwnd, TileWindowsEnum);
    01225 }
    01226
    01227
    01228
    01229 /***************************************************************************\
    01230 * xxxMDIActivate
    01231 *
    01232 * History:
    01233 * 11-14-90 MikeHar Ported from windows
    01234 *  4-16-91 MikeHar Win31 Merge
    01235 \***************************************************************************/
    01236
    01237 void xxxMDIActivate(
    01238     PWND pwnd,
    01239     PWND pwndActivate)
    01240 {
    01241     HWND hwndOld;
    01242     PWND pwndOld;
    01243
    01244     PMDI pmdi;
    01245     BOOL fShowActivate;
    01246     UINT nID;
    01247     TL tlpwnd;
    01248     TL tlpwndOld;
    01249     PWND pwndT;
    01250     HWND hwnd = HWq(pwnd);
    01251     HWND hwndActivate = HW(pwndActivate);
    01252
    01253     CheckLock(pwnd);
    01254     CheckLock(pwndActivate);
    01255
    01256     /*
    01257      * Get a pointer to the MDI structure
    01258      */
    01259     pmdi = ((PMDIWND)pwnd)->pmdi;
    01260
    01261     if (ACTIVE(pmdi) == hwndActivate)
    01262         return;
    01263
    01264     if ((pwndActivate != NULL) && (TestWF(pwndActivate, WFDISABLED))) {
    01265         /*
    01266          * Don't even try activating disabled or invisible windows.
    01267          */
    01268         return;
    01269     }
    01270
    01271     pwndT = REBASEPWND(pwnd, spwndParent);
    01272     fShowActivate = (HW(pwndT) ==
    01273             NtUserQueryWindow(hwnd, WindowActiveWindow));
    01274
    01275     hwndOld = ACTIVE(pmdi);
    01276     if (hwndOld && (pwndOld = ValidateHwnd(hwndOld)) == NULL) {
    01277         hwndOld = NULL;
    01278     }
    01279     ThreadLock(pwndOld, &tlpwndOld);
    01280
    01281     if (hwndOld) {
    01282
    01283         /*
    01284          * Attempt to deactivate the MDI child window.
    01285          * The MDI child window can fail deactivation by returning FALSE.
    01286          * But this only applies if the MDI frame is the active window
    01287          * and the app is a 3.1 app or later
    01288          */
    01289         if (!SendMessage(hwndOld, WM_NCACTIVATE, FALSE, 0L) && fShowActivate) {
    01290             if (TestWF(pwndOld, WFWIN31COMPAT))
    01291                 goto UnlockOld;
    01292         }
    01293
    01294         if (!TestWF(pwndOld, WFWIN31COMPAT) && TestWF(pwndOld, WFFRAMEON)) {
    01295
    01296             /*
    01297              * Error: Quicken for Windows is sort of bogus.  They try to fail
    01298              * the WM_NCACTIVATE of their newly created window by not passing
    01299              * it to DefWindowProc.  Bug 6412.  WM_NCACTIVATE sets/unsets the
    01300              * WFFRAMEON bit if passed to DWP so we can double check things
    01301              * here.
    01302              */
    01303             goto UnlockOld;
    01304         }
    01305
    01306         SendMessage(hwndOld, WM_MDIACTIVATE, (WPARAM)hwndOld, (LPARAM)hwndActivate);
    01307
    01308         /*
    01309          * Uncheck the old window menu entry.
    01310          */
    01311         if (WINDOW(pmdi))
    01312             CheckMenuItem(WINDOW(pmdi), PtrToUlong(pwndOld->spmenu),
    01313                 MF_BYCOMMAND | MF_UNCHECKED);
    01314     }
    01315
    01316     //
    01317     // Handle switching to a new (or NO) maximized window.  If NO window is
    01318     // to become maximized, because we're activating NULL or the window to
    01319     // become active doesn't have a WS_MAXIMIZEBOX, restore the old one to
    01320     // it's normal size to clean up the MDI maximized menubar mess
    01321     //
    01322     if (MAXED(pmdi) && MAXED(pmdi) != hwndActivate) {
    01323         HWND hwndMax;
    01324         int  iShowCode;
    01325
    01326         // The MAXBOX check is a new thing for 4.0 dudes; it breaks 3.x apps.
    01327         // See comment in the WM_MDIMAXIMIZE handling.
    01328
    01329         if (pwndActivate && (TestWF(pwndActivate, WFMAXBOX) || !TestWF(pwndActivate, WFWIN40COMPAT))) {
    01330             hwndMax = hwndActivate;
    01331             iShowCode = SW_SHOWMAXIMIZED;
    01332             Lock(&ACTIVE(pmdi), hwndMax);
    01333         } else {
    01334             hwndMax = MAXED(pmdi);
    01335             iShowCode = SW_SHOWNORMAL;
    01336         }
    01337
    01338         // overload WFFULLSCREEN bit -- useless for child windows anyways
    01339         // use it to indicate to min/max code to not animate size change.
    01340
    01341         // NO -- no bit overloading, damn it.  FritzS
    01342         NtUserCallHwndParam(hwndMax, WFNOANIMATE, SFI_SETWINDOWSTATE);
    01343         NtUserShowWindow(hwndMax, iShowCode);
    01344         NtUserCallHwndParam(hwndMax, WFNOANIMATE, SFI_CLEARWINDOWSTATE);
    01345     }
    01346
    01347     Lock(&ACTIVE(pmdi), hwndActivate);
    01348
    01349     /*
    01350      * We may be removing the activation entirely...
    01351      */
    01352     if (!pwndActivate) {
    01353         if (fShowActivate)
    01354             NtUserSetFocus(hwnd);
    01355         goto UnlockOld;
    01356     }
    01357
    01358     if (WINDOW(pmdi)) {
    01359
    01360         /*
    01361          * Check the new window menu entry.
    01362          */
    01363         nID = GetWindowID(ACTIVE(pmdi));
    01364         if (nID - FIRST(pmdi) < (MAXITEMS - 1)) {
    01365             CheckMenuItem(WINDOW(pmdi), nID, MF_BYCOMMAND | MFS_CHECKED);
    01366         } else {
    01367             /*
    01368              * the item is not in the menu at all!  Swap it with number 9.
    01369              */
    01370             PWND pwndOther = FindPwndChild(pwnd, (UINT)(FIRST(pmdi) + MAXITEMS - 2));
    01371
    01372             SetWindowLongPtr(HW(pwndOther), GWLP_ID, PtrToLong(pwndActivate->spmenu));
    01373             SetWindowLongPtr(hwndActivate, GWLP_ID, FIRST(pmdi) + MAXITEMS - 2);
    01374
    01375             ModifyMenuItem(pwndActivate);
    01376         }
    01377     }
    01378
    01379     /*
    01380      * Bring the window to the top.
    01381      */
    01382     NtUserSetWindowPos(ACTIVE(pmdi), NULL, 0, 0, 0, 0,
    01383         SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
    01384
    01385     /*
    01386      * Update the Caption bar.  Don't muck with styles for 3.1.
    01387      */
    01388     if (fShowActivate) {
    01389         SendMessage(ACTIVE(pmdi), WM_NCACTIVATE, TRUE, 0L);
    01390
    01391         ThreadLock(pwnd, &tlpwnd);
    01392
    01393         if (hwnd == NtUserQueryWindow(hwnd, WindowFocusWindow))
    01394             SendMessage(hwnd, WM_SETFOCUS, (WPARAM)hwnd, 0);
    01395         else
    01396             NtUserSetFocus(hwnd);
    01397
    01398         ThreadUnlock(&tlpwnd);
    01399     }
    01400
    01401     /*
    01402      * Notify the new active window of his activation.
    01403      */
    01404     SendMessage(ACTIVE(pmdi), WM_MDIACTIVATE, (WPARAM)hwndOld,
    01405                 (LPARAM)hwndActivate);
    01406
    01407 UnlockOld:
    01408     ThreadUnlock(&tlpwndOld);
    01409 }
    01410
    01411
    01412 /***************************************************************************\
    01413 * xxxMDINext
    01414 *
    01415 * History:
    01416 * 11-14-90 MikeHar Ported from windows
    01417 *  4-16-91 MikeHar Win31 Merge
    01418 \***************************************************************************/
    01419
    01420 void xxxMDINext(
    01421     PWND pwndMDI,
    01422     PWND pwnd,
    01423     BOOL fPrevWindow)
    01424 {
    01425     PMDI pmdi;
    01426     PWND pwndNextGuy;
    01427     HDWP hdwp;
    01428     BOOL fHack = FALSE;
    01429
    01430     CheckLock(pwndMDI);
    01431     CheckLock(pwnd);
    01432
    01433     /*
    01434      * Get a pointer to the MDI structure
    01435      */
    01436     pmdi = ((PMDIWND)pwndMDI)->pmdi;
    01437
    01438     pwndNextGuy = pwnd;
    01439
    01440     while (TRUE) {
    01441         if (fPrevWindow)
    01442             pwndNextGuy = _GetWindow(pwndNextGuy, GW_HWNDPREV);
    01443         else
    01444             pwndNextGuy = REBASEPWND(pwndNextGuy, spwndNext);
    01445
    01446         if (!pwndNextGuy) {
    01447             if (fPrevWindow) {
    01448                 pwndNextGuy = _GetWindow(pwnd, GW_HWNDLAST);
    01449             } else {
    01450                 pwndNextGuy =  REBASEPWND(pwndMDI, spwndChild);
    01451             }
    01452         }
    01453
    01454         if (pwndNextGuy == pwnd)
    01455             return;
    01456
    01457
    01458         //
    01459         // Ignore hidden and disabled windows.
    01460         //
    01461         if (TestWF(pwndNextGuy, WFVISIBLE) && !TestWF(pwndNextGuy, WFDISABLED))
    01462             break;
    01463     }
    01464
    01465     if (MAXED(pmdi)) {
    01466         NtUserSetVisible(HWq(pwndMDI), SV_UNSET | SV_CLRFTRUEVIS);
    01467         fHack = TRUE;
    01468     }
    01469
    01470     hdwp = NtUserBeginDeferWindowPos(2);
    01471
    01472     /*
    01473      * activate the new window (first, in case of maximized windows)
    01474      */
    01475     hdwp = NtUserDeferWindowPos(hdwp, HW(pwndNextGuy), HWND_TOP, 0, 0, 0, 0,
    01476         SWP_NOMOVE | SWP_NOSIZE);
    01477
    01478 // LATER 30-Mar-1992 mikeke
    01479 // this used to be _GetWindow(pwndMDI->spwndChild, GW_HWNDLAST)
    01480 // instead of HWND_BOTTOM
    01481    if (hdwp && !fPrevWindow && (pwnd != pwndNextGuy))
    01482        hdwp = NtUserDeferWindowPos(hdwp, HW(pwnd),
    01483             HWND_BOTTOM, 0, 0, 0, 0,
    01484             SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE );
    01485
    01486     NtUserEndDeferWindowPosEx(hdwp, FALSE);
    01487
    01488     if (fHack) {
    01489         NtUserShowWindow(HWq(pwndMDI), SW_SHOW);
    01490     }
    01491 }
    01492
    01493
    01494 HWND
    01495 CreateMDIWindowA(
    01496     LPCSTR pClassName,
    01497     LPCSTR pWindowName,
    01498     DWORD dwStyle,
    01499     int x,
    01500     int y,
    01501     int nWidth,
    01502     int nHeight,
    01503     HWND hwndParent,
    01504     HINSTANCE hModule,
    01505     LPARAM lParam)
    01506 {
    01507     return CreateWindowExA(WS_EX_MDICHILD, pClassName, pWindowName,
    01508                                  dwStyle, x, y, nWidth, nHeight,
    01509                                  hwndParent, NULL, hModule, (LPVOID)lParam);
    01510 }
    01511
    01512
    01513 HWND
    01514 CreateMDIWindowW(
    01515     LPCWSTR pClassName,
    01516     LPCWSTR pWindowName,
    01517     DWORD dwStyle,
    01518     int x,
    01519     int y,
    01520     int nWidth,
    01521     int nHeight,
    01522     HWND hwndParent,
    01523     HINSTANCE hModule,
    01524     LPARAM lParam)
    01525 {
    01526     return CreateWindowExW(WS_EX_MDICHILD, pClassName, pWindowName,
    01527                                  dwStyle, x, y, nWidth, nHeight,
    01528                                  hwndParent, NULL, hModule, (LPVOID)lParam);
    01529 }
    01530
    01531
    01532 /***************************************************************************\
    01533 * xxxMDIDestroy
    01534 *
    01535 * History:
    01536 * 11-14-90 MikeHar Ported from windows
    01537 *  4-16-91 MikeHar Win31 Merge
    01538 \***************************************************************************/
    01539
    01540 void xxxMDIDestroy(
    01541     PWND pwnd,
    01542     HWND hwndVictim)
    01543 {
    01544     PWND pwndVictim;
    01545     TL tlpwndParent;
    01546     PMDI pmdi;
    01547     PWND pwndParent;
    01548     HWND hwnd;
    01549
    01550     CheckLock(pwnd);
    01551
    01552     if ((pwndVictim = ValidateHwnd(hwndVictim)) == NULL) {
    01553         return;
    01554     }
    01555     CheckLock(pwndVictim);
    01556
    01557     /*
    01558      * Get a pointer to the MDI structure
    01559      */
    01560     pmdi = ((PMDIWND)pwnd)->pmdi;
    01561
    01562 #ifdef NEVER
    01563 // don't do this validation - because it sometimes doesn't work! If an
    01564 // app passed in idFirstChild (through CLIENTCREATESTRUCT) as -1, this
    01565 // code fails because it treats the id comparisons as unsigned compares.
    01566 // Change them to signed compares and it still doesn't work. That is because
    01567 // when ShiftMenuIDs() is called, you'll shift mdi windows out of the signed
    01568 // comparison range and this check won't allow them to be destroyed. This
    01569 // is straight win3.1 code.
    01570 //
    01571     /*
    01572      * Validate that this is one of the mdi children we are keeping track
    01573      * of. If it isn't don't destroy it because it'll get mdi id tracking
    01574      * code all screwed up.
    01575      */
    01576     if (((UINT)pwndVictim->spmenu) < FIRST(pmdi) ||
    01577             ((UINT)pwndVictim->spmenu) >= (UINT)(FIRST(pmdi) + CKIDS(pmdi)) ||
    01578             pwndVictim->spwndOwner != NULL) {
    01579         RIPERR0(ERROR_NON_MDICHILD_WINDOW, RIP_VERBOSE, "");
    01580         return;
    01581     }
    01582 #endif
    01583
    01584     ShiftMenuIDs(pwnd, pwndVictim);
    01585
    01586     /*
    01587      * First Activate another window.
    01588      */
    01589     if (SAMEWOWHANDLE(hwndVictim, ACTIVE(pmdi))) {
    01590         xxxMDINext(pwnd, pwndVictim, FALSE);
    01591
    01592         /*
    01593          * Destroying only child?
    01594          */
    01595         if (SAMEWOWHANDLE(hwndVictim, ACTIVE(pmdi))) {
    01596             NtUserShowWindow(hwndVictim, SW_HIDE);
    01597
    01598             /*
    01599              * If the window is maximized, we need to remove his sys menu
    01600              * now otherwise it may get deleted twice.  Once when the child
    01601              * is destroyed and once when the frame is destroyed.
    01602              */
    01603             if (MAXED(pmdi)) {
    01604                 pwndParent = REBASEPWND(pwnd, spwndParent);
    01605                 MDIRemoveSysMenu(PtoH(REBASE(pwndParent,spmenu)), MAXED(pmdi));
    01606                 Unlock(&MAXED(pmdi));
    01607                 ThreadLock(pwndParent, &tlpwndParent);
    01608                 xxxSetFrameTitle(pwndParent, pwnd, (LPWSTR)1L);
    01609
    01610                 /*
    01611                  * Redraw frame so menu bar shows the removed sys menu stuff
    01612                  */
    01613                 if (TestWF(pwndParent, WFVISIBLE))
    01614                     NtUserRedrawFrame(HWq(pwndParent));
    01615                 ThreadUnlock(&tlpwndParent);
    01616             }
    01617             xxxMDIActivate(pwnd, NULL);
    01618         }
    01619     }
    01620
    01621     /*
    01622      * Don't ever let this go negative or we'll get caught in long loops.
    01623      */
    01624     CKIDS(pmdi)--;
    01625     if ((int)CKIDS(pmdi) < 0)
    01626         CKIDS(pmdi) = 0;
    01627
    01628     hwnd = HWq(pwnd);
    01629     SendMessage(hwnd, WM_MDIREFRESHMENU, 0L, 0L);
    01630
    01631     /*
    01632      * Destroy the window.
    01633      */
    01634     NtUserDestroyWindow(hwndVictim);
    01635
    01636
    01637     /*
    01638      * During the DestroyWindow the parent may also have been deleted
    01639      * Remove revalidate if we get client side locking
    01640      */
    01641     if (ValidateHwnd(hwnd) == NULL)
    01642        return;
    01643
    01644     /*
    01645      * Deleting a window can change the scroll ranges.
    01646      */
    01647     RecalculateScrollRanges(pwnd, FALSE);
    01648 }
    01649
    01650 /***************************************************************************\
    01651 * MDIClientWndProc
    01652 *
    01653 * History:
    01654 * 11-14-90 MikeHar Ported from windows
    01655 \***************************************************************************/
    01656
    01657 LRESULT MDIClientWndProcWorker(
    01658     PWND pwnd,
    01659     UINT message,
    01660     WPARAM wParam,
    01661     LPARAM lParam,
    01662     DWORD fAnsi)
    01663 {
    01664     HWND hwnd = HWq(pwnd);
    01665     HWND hwndT;
    01666     PWND pwndT;
    01667     TL tlpwndT;
    01668     PMDI pmdi;
    01669     PWND pwndParent;
    01670
    01671     CheckLock(pwnd);
    01672
    01673     VALIDATECLASSANDSIZE(pwnd, FNID_MDICLIENT);
    01674
    01675     /*
    01676      * Get the pmdi for the given window now since we will use it a lot in
    01677      * various handlers. This was stored using SetWindowLong(hwnd,4,pmdi) when
    01678      * we initially created the MDI client window.
    01679      */
    01680     pmdi = ((PMDIWND)pwnd)->pmdi;
    01681
    01682     if (pmdi == NULL) {
    01683         switch (message) {
    01684         case WM_MDICREATE:
    01685         case WM_MDIMAXIMIZE:
    01686         case WM_PARENTNOTIFY:
    01687         case WM_CREATE:
    01688             /*
    01689              * These messages are safe to call, even when pmdi has not already
    01690              * been initialized.
    01691              */
    01692             break;
    01693
    01694         default:
    01695             /*
    01696              * Any message that is not listed above is not safe to call when
    01697              * pmdi has not been initialized.  Instead, just directly call DWP.
    01698              */
    01699             goto CallDWP;
    01700         }
    01701     }
    01702
    01703     switch (message) {
    01704     case WM_NCACTIVATE:
    01705
    01706         /*
    01707          * We are changing app activation.  Fix the active child's caption.
    01708          */
    01709         if (ACTIVE(pmdi) != NULL) {
    01710             SendMessage(ACTIVE(pmdi), WM_NCACTIVATE, wParam, lParam);
    01711         }
    01712         goto CallDWP;
    01713
    01714     case WM_MDIGETACTIVE:
    01715         if (lParam != 0) {
    01716             *((LPBOOL)lParam) = (MAXED(pmdi) != NULL);
    01717         }
    01718
    01719         return (LRESULT)ACTIVE(pmdi);
    01720
    01721     case WM_MDIACTIVATE:
    01722         hwndT = (HWND)wParam;
    01723         if ((pwndT = ValidateHwnd(hwndT)) == NULL)
    01724             return 0;
    01725
    01726         if (SAMEWOWHANDLE(hwndT, ACTIVE(pmdi)))
    01727               break;
    01728
    01729         NtUserSetWindowPos(hwndT, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
    01730         break;
    01731
    01732     case WM_MDICASCADE:
    01733         pmdi->wScroll |= SCROLLSUPPRESS;
    01734         NtUserShowScrollBar(hwnd, SB_BOTH, FALSE);
    01735
    01736         /*
    01737          * Unmaximize any maximized window.
    01738          */
    01739 #ifdef NEVER  // Not in Chicago -- FritzS
    01740         if (MAXED(pmdi) != NULL) {
    01741             NtUserShowWindow(MAXED(pmdi), SW_SHOWNORMAL);
    01742         }
    01743 #endif
    01744         /*
    01745          * Save success/failure code to return to app
    01746          */
    01747         message = (UINT)CascadeWindows(hwnd, (UINT)wParam, NULL, 0, NULL);
    01748         pmdi->wScroll &= ~SCROLLCOUNT;
    01749         return (LONG)message;
    01750         break;
    01751
    01752     case WM_VSCROLL:
    01753     case WM_HSCROLL:
    01754         pmdi->wScroll |= SCROLLSUPPRESS;
    01755         ScrollMDIChildren(hwnd, (message == WM_VSCROLL) ? SB_VERT : SB_HORZ,
    01756               LOWORD(wParam), (short)(HIWORD(wParam)));
    01757         pmdi->wScroll &= ~SCROLLCOUNT;
    01758         break;
    01759
    01760     case WM_MDICREATE:
    01761         {
    01762         LPMDICREATESTRUCTA lpMCSA = (LPMDICREATESTRUCTA)lParam;
    01763         LPMDICREATESTRUCTW lpMCSW = (LPMDICREATESTRUCTW)lParam;
    01764         DWORD exStyle = WS_EX_MDICHILD;
    01765
    01766         /*
    01767          * inherit the right.to.leftness of the parent.
    01768          */
    01769         exStyle |= (pwnd->ExStyle & (WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR));
    01770
    01771         if (fAnsi) {
    01772             hwndT = CreateWindowExA(exStyle, lpMCSA->szClass, lpMCSA->szTitle,
    01773                 lpMCSA->style, lpMCSA->x, lpMCSA->y, lpMCSA->cx, lpMCSA->cy,
    01774                 hwnd, NULL, lpMCSA->hOwner, (LPSTR)lpMCSA->lParam);
    01775         } else {
    01776             hwndT = CreateWindowExW(exStyle, lpMCSW->szClass, lpMCSW->szTitle,
    01777                 lpMCSW->style, lpMCSW->x, lpMCSW->y, lpMCSW->cx, lpMCSW->cy,
    01778                 hwnd, NULL, lpMCSW->hOwner, (LPWSTR)lpMCSW->lParam);
    01779         }
    01780
    01781         return((LRESULT)hwndT);
    01782
    01783         }
    01784
    01785     case WM_MDIDESTROY:
    01786         xxxMDIDestroy(pwnd, (HWND)wParam);
    01787         break;
    01788
    01789     case WM_MDIMAXIMIZE:
    01790         hwndT = (HWND)wParam;
    01791         if ((pwndT = ValidateHwnd(hwndT)) == NULL)
    01792             return 0;
    01793
    01794         // Only maximize children with a MAXBOX.  However, this introduces
    01795         // backwards-compatibility issues with VB apps (see#12211)
    01796         // So, we do this only for WIN40COMPAT apps and beyond.
    01797         //
    01798         if ((TestWF(pwndT, WFMAXBOX)) || !(TestWF(pwndT, WFWIN40COMPAT))) {
    01799             NtUserShowWindow(hwndT, SW_SHOWMAXIMIZED);
    01800         }
    01801         break;
    01802
    01803     case WM_MDIRESTORE:
    01804         hwndT = (HWND)wParam;
    01805         if ((pwndT = ValidateHwnd(hwndT)) == NULL)
    01806             return 0;
    01807
    01808         NtUserShowWindow(hwndT, SW_SHOWNORMAL);
    01809         break;
    01810
    01811     case WM_MDITILE:
    01812         pmdi->wScroll |= SCROLLSUPPRESS;
    01813         NtUserShowScrollBar(hwnd, SB_BOTH, FALSE);
    01814
    01815         /*
    01816          * Unmaximize any maximized window.
    01817          */
    01818 #ifdef NEVER  //Not in Chicago
    01819         if (MAXED(pmdi) != NULL) {
    01820             NtUserShowWindow(MAXED(pmdi), SW_SHOWNORMAL);
    01821         }
    01822 #endif
    01823         /*
    01824          * Save success/failure code to return to app
    01825          */
    01826         message = (UINT)TileWindows(hwnd, (UINT)wParam, NULL, 0, NULL);
    01827         pmdi->wScroll &= ~SCROLLCOUNT;
    01828         return (LONG)message;
    01829         break;
    01830
    01831     case WM_MDIICONARRANGE:
    01832         pmdi->wScroll |= SCROLLSUPPRESS;
    01833         NtUserArrangeIconicWindows(hwnd);
    01834         pmdi->wScroll &= ~SCROLLCOUNT;
    01835         RecalculateScrollRanges(pwnd, TRUE);
    01836         break;
    01837
    01838     case WM_MDINEXT:
    01839         if (wParam) {
    01840             hwndT = (HWND)wParam;
    01841         } else {
    01842             hwndT = ACTIVE(pmdi);
    01843         }
    01844
    01845         if ((pwndT = ValidateHwnd(hwndT)) == NULL) {
    01846             return 0;
    01847         }
    01848
    01849         /*
    01850          * If lParam is 1, do a prev window instead of a next window
    01851          */
    01852         ThreadLockAlways(pwndT, &tlpwndT);
    01853         xxxMDINext(pwnd, pwndT, (lParam == 0 ? 0 : 1));
    01854         ThreadUnlock(&tlpwndT);
    01855         break;
    01856
    01857     case WM_MDIREFRESHMENU:
    01858             return (LRESULT)MDISetMenu(pwnd, TRUE, NULL, NULL);
    01859
    01860     case WM_MDISETMENU:
    01861             return (LRESULT)MDISetMenu(pwnd, FALSE, (HMENU)wParam, (HMENU)lParam);
    01862
    01863     case WM_PARENTNOTIFY:
    01864         if (wParam == WM_LBUTTONDOWN) {
    01865             HWND hwndChild;
    01866             POINT pt;
    01867
    01868 #ifdef USE_MIRRORING
    01869             if ((pwndT = ValidateHwnd(hwnd)) == NULL)
    01870                 return 0;
    01871 #endif
    01872
    01873             /*
    01874              * Activate this child and bring it to the top.
    01875              */
    01876             pt.x = (int)MAKEPOINTS(lParam).x;
    01877             pt.y = (int)MAKEPOINTS(lParam).y;
    01878
    01879 #ifdef USE_MIRRORING
    01880             /*
    01881              * Since pt is relative to the client MDI window,
    01882              * then the points should be mirrored if the MDI
    01883              * client window is mirrored so that Scrren Coord
    01884              * calculations are done properly in NtUserChildWindowFromPointEx.
    01885              * [samera]
    01886              */
    01887             if (TestWF(pwndT,WEFLAYOUTRTL)) {
    01888                 pt.x = (pwndT->rcClient.right-pwndT->rcClient.left)-pt.x;
    01889             }
    01890 #endif
    01891
    01892             hwndChild = NtUserChildWindowFromPointEx(hwnd, pt,
    01893                 CWP_SKIPDISABLED | CWP_SKIPINVISIBLE);
    01894
    01895             if ((hwndChild) && (hwndChild != hwnd)) {
    01896
    01897                 if (hwndChild != ACTIVE(pmdi)) {
    01898                     NtUserSetWindowPos(hwndChild, HWND_TOP, 0, 0, 0, 0,
    01899                                  SWP_NOMOVE | SWP_NOSIZE);
    01900                 }
    01901             }
    01902         }
    01903         break;
    01904
    01905     case WM_SETFOCUS:
    01906         if (ACTIVE(pmdi) != NULL && !IsIconic(ACTIVE(pmdi))) {
    01907             NtUserSetFocus(ACTIVE(pmdi));
    01908         }
    01909         break;
    01910
    01911     case WM_SIZE:
    01912         if (ACTIVE(pmdi) && (pwndT = ValidateHwnd(ACTIVE(pmdi))) &&
    01913             TestWF(pwndT, WFMAXIMIZED)) {
    01914
    01915             RECT rc;
    01916
    01917             rc.top = rc.left = 0;
    01918             rc.right = (int)MAKEPOINTS(lParam).x;
    01919             rc.bottom = (int)MAKEPOINTS(lParam).y;
    01920             _AdjustWindowRectEx(&rc, pwndT->style, FALSE,
    01921                     pwndT->ExStyle);
    01922             NtUserMoveWindow(ACTIVE(pmdi), rc.left, rc.top,
    01923                     rc.right - rc.left, rc.bottom - rc.top, TRUE);
    01924         } else {
    01925             RecalculateScrollRanges(pwnd, FALSE);
    01926         }
    01927         goto CallDWP;
    01928
    01929     case MM_CALCSCROLL: {
    01930
    01931         if (SCROLL(pmdi) & SCROLLCOUNT)
    01932             break;
    01933
    01934         {
    01935             WORD sbj = pmdi->wScroll & (HAS_SBVERT | HAS_SBHORZ);
    01936
    01937             if (sbj)
    01938             {
    01939                 CalcClientScrolling(hwnd, sbj, (BOOL) wParam);
    01940
    01941                 SCROLL(pmdi) &= ~CALCSCROLL;
    01942             }
    01943         }
    01944         break;
    01945     }
    01946
    01947     case WM_CREATE: {
    01948         LPCLIENTCREATESTRUCT pccs = ((LPCREATESTRUCT)lParam)->lpCreateParams;
    01949
    01950         /*
    01951          * Try to allocate space for the pmdi
    01952          */
    01953         if ((pmdi = (PMDI)UserLocalAlloc(HEAP_ZERO_MEMORY, sizeof(MDI)))) {
    01954             NtUserSetWindowLongPtr(hwnd, GWLP_MDIDATA, (LONG_PTR)pmdi, FALSE);
    01955         } else {
    01956             NtUserSetWindowFNID(hwnd, FNID_CLEANEDUP_BIT);
    01957             break;
    01958         }
    01959
    01960         pwndParent = REBASEPWND(pwnd, spwndParent);
    01961         ACTIVE(pmdi) = NULL;
    01962         MAXED(pmdi)  = NULL;
    01963         CKIDS(pmdi)  = 0;
    01964         WINDOW(pmdi) = pccs->hWindowMenu;
    01965
    01966         FIRST(pmdi)  = pccs->idFirstChild;
    01967         SCROLL(pmdi) = 0;
    01968         HTITLE(pmdi) = TextAlloc(REBASE(pwndParent, strName.Buffer));
    01969
    01970         _DefSetText(HW(pwndParent), NULL, FALSE);
    01971
    01972         ThreadLock(pwndParent, &tlpwndT);
    01973         xxxSetFrameTitle(pwndParent, pwnd, (LPWSTR)2L);
    01974         ThreadUnlock(&tlpwndT);
    01975
    01976         if (TestWF(pwnd, WFVSCROLL))
    01977             SCROLL(pmdi) |= HAS_SBVERT;
    01978         if (TestWF(pwnd, WFHSCROLL))
    01979             SCROLL(pmdi) |= HAS_SBHORZ;
    01980         if (SCROLL(pmdi)) {
    01981             ClearWindowState(pwnd, WFVSCROLL | WFHSCROLL);
    01982         }
    01983
    01984         /*
    01985          * Set this dude's system menu.
    01986          */
    01987         NtUserGetSystemMenu(HW(pwndParent), FALSE);
    01988
    01989         /*
    01990          * make sure we have the correct window client area if scrolls are
    01991          * removed...  hack to take care of small progman bug
    01992          */
    01993         if (SCROLL(pmdi)) {
    01994             NtUserUpdateClientRect(hwnd);
    01995         }
    01996         break;
    01997     }
    01998
    01999     case WM_DESTROY:
    02000     case WM_FINALDESTROY:
    02001         if (MAXED(pmdi)) {
    02002             PWND pwndParent;
    02003             PMENU pmenu;
    02004
    02005             pwndParent = REBASEPWND(pwnd, spwndParent);
    02006             pmenu = REBASE(pwndParent, spmenu);
    02007             MDIRemoveSysMenu(PtoH(pmenu), MAXED(pmdi));
    02008         }
    02009
    02010         /*
    02011          * delete the title
    02012          */
    02013         if (HTITLE(pmdi)) {
    02014             UserLocalFree(HTITLE(pmdi));
    02015             HTITLE(pmdi) = NULL;
    02016         }
    02017
    02018         /*
    02019          * Delete the menu items of the child windows in the frame.
    02020          * Chances are, this is called by destroying the frame, but
    02021          * one never knows, does one?
    02022          *
    02023          * Increase CKIDS by 1 after checking to delete the separator
    02024          */
    02025         if (IsMenu(WINDOW(pmdi)) && CKIDS(pmdi)++) {
    02026             UINT iPosition;
    02027
    02028             if (CKIDS(pmdi) > MAXITEMS + 1)
    02029                 CKIDS(pmdi) = MAXITEMS + 1;
    02030
    02031             iPosition = GetMenuItemCount(WINDOW(pmdi));
    02032             while (CKIDS(pmdi)--) {
    02033                 NtUserDeleteMenu(WINDOW(pmdi), --iPosition, MF_BYPOSITION);
    02034             }
    02035         }
    02036
    02037         /*
    02038          * Unlock those objects that are used by the MDI structure.
    02039          */
    02040         Unlock(&MAXED(pmdi));
    02041         Unlock(&ACTIVE(pmdi));
    02042         Unlock(&WINDOW(pmdi));
    02043
    02044         /*
    02045          * Free the MDI structure
    02046          */
    02047         UserLocalFree(pmdi);
    02048         NtUserSetWindowFNID(hwnd, FNID_CLEANEDUP_BIT);
    02049
    02050         break;
    02051
    02052     default:
    02053 CallDWP:
    02054         return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi);
    02055     }
    02056     return 0L;
    02057 }
    02058
    02059 /***************************************************************************\
    02060 *
    02061 \***************************************************************************/
    02062
    02063 LRESULT WINAPI MDIClientWndProcA(
    02064     HWND hwnd,
    02065     UINT message,
    02066     WPARAM wParam,
    02067     LPARAM lParam)
    02068 {
    02069     PWND pwnd;
    02070
    02071     if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
    02072         return 0;
    02073     }
    02074
    02075     return MDIClientWndProcWorker(pwnd, message, wParam, lParam, TRUE);
    02076 }
    02077
    02078 LRESULT WINAPI MDIClientWndProcW(
    02079     HWND hwnd,
    02080     UINT message,
    02081     WPARAM wParam,
    02082     LPARAM lParam)
    02083 {
    02084     PWND pwnd;
    02085
    02086     if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
    02087         return 0;
    02088     }
    02089
    02090     return MDIClientWndProcWorker(pwnd, message, wParam, lParam, FALSE);
    02091 }
    02092
    02093
    02094 /***************************************************************************\
    02095 * DefFrameProc
    02096 *
    02097 * History:
    02098 * 11-14-90 MikeHar      Ported from windows
    02099 \***************************************************************************/
    02100
    02101 LRESULT DefFrameProcWorker(
    02102     HWND hwnd,
    02103     HWND hwndMDI,
    02104     UINT wMsg,
    02105     WPARAM wParam,
    02106     LPARAM lParam,
    02107     BOOL fAnsi)
    02108 {
    02109     PWND pwnd;
    02110     PWND pwndMDI;
    02111     PMDI pmdi;
    02112     TL tlpwndT;
    02113     HWND hwndT;
    02114     PWND pwndT;
    02115     PMDINEXTMENU pmnm;
    02116     WINDOWPLACEMENT wp;
    02117
    02118     if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
    02119         return (0L);
    02120     }
    02121     CheckLock(pwnd);
    02122
    02123     if (hwndMDI == NULL) {
    02124         goto CallDWP;
    02125     }
    02126
    02127     if ((pwndMDI = ValidateHwnd(hwndMDI)) == NULL) {
    02128         return (0L);
    02129     }
    02130     CheckLock(pwndMDI);
    02131
    02132     /*
    02133      * Get a pointer to the MDI structure
    02134      */
    02135     pmdi = ((PMDIWND)pwndMDI)->pmdi;
    02136
    02137     switch (wMsg) {
    02138
    02139     /*
    02140      * If there is a maximized child window, add it's window text...
    02141      */
    02142     case WM_SETTEXT: {
    02143         LPWSTR lpwsz = NULL;
    02144
    02145         if (fAnsi && lParam) {
    02146             if (!MBToWCS((LPSTR)lParam, -1, &lpwsz, -1, TRUE))
    02147                 return 0;
    02148             lParam = (LPARAM)lpwsz;
    02149         }
    02150         xxxSetFrameTitle(pwnd, pwndMDI, (LPWSTR)lParam);
    02151
    02152         if (lpwsz)
    02153             UserLocalFree(lpwsz);
    02154         break;
    02155     }
    02156     case WM_NCACTIVATE:
    02157         SendMessage(hwndMDI, WM_NCACTIVATE, wParam, lParam);
    02158         goto CallDWP;
    02159
    02160     case WM_COMMAND:
    02161         if ((UINT)LOWORD(wParam) == (FIRST(pmdi) + MAXITEMS -1)) {
    02162
    02163             /*
    02164              * selected the More...  item
    02165              */
    02166             if (fAnsi) {
    02167                 wParam = DialogBoxParamA(hmodUser,
    02168                                          MAKEINTRESOURCEA(IDD_MDI_ACTIVATE),
    02169                                          hwnd,
    02170                                          MDIActivateDlgProcA,
    02171                                          (LPARAM)pwndMDI);
    02172             } else {
    02173                 wParam = DialogBoxParamW(hmodUser,
    02174                                          MAKEINTRESOURCEW(IDD_MDI_ACTIVATE),
    02175                                          hwnd,
    02176                                          MDIActivateDlgProcW,
    02177                                          (LPARAM)pwndMDI);
    02178             }
    02179             if ((int)wParam >= 0) {
    02180                 wParam += FIRST(pmdi);
    02181                 goto ActivateTheChild;
    02182             }
    02183         } else if (((UINT)LOWORD(wParam) >= FIRST(pmdi)) &&
    02184                 ((UINT)LOWORD(wParam) < FIRST(pmdi) + CKIDS(pmdi))) {
    02185 ActivateTheChild:
    02186             pwndT = FindPwndChild(pwndMDI, (UINT)LOWORD(wParam));
    02187             ThreadLock(pwndT, &tlpwndT);
    02188
    02189             SendMessage(hwndMDI, WM_MDIACTIVATE, (WPARAM)HW(pwndT), 0L);
    02190
    02191             /*
    02192              * if minimized, restore it.
    02193              */
    02194             if (pwndT != NULL && TestWF(pwndT, WFMINIMIZED))
    02195                     //
    02196                     // Fix for B#1510.  Don't restore directly.  Send child
    02197                     // a restore message.
    02198                     //
    02199                 SendMessage(HWq(pwndT), WM_SYSCOMMAND, (WPARAM)SC_RESTORE, 0L);
    02200             ThreadUnlock(&tlpwndT);
    02201             break;
    02202         }
    02203
    02204         switch (wParam & 0xFFF0) {
    02205
    02206         /*
    02207          * System menu commands on a maxed mdi child
    02208          */
    02209         case SC_SIZE:
    02210         case SC_MOVE:
    02211         case SC_RESTORE:
    02212         case SC_CLOSE:
    02213         case SC_NEXTWINDOW:
    02214         case SC_PREVWINDOW:
    02215         case SC_MINIMIZE:
    02216         case SC_MAXIMIZE:
    02217             hwndT = MAXED(pmdi);
    02218             if (hwndT != NULL) {
    02219                 PWND pwndT = ValidateHwnd(hwndT);
    02220                 if (pwndT == NULL)
    02221                     break;
    02222                 if ((wParam & 0xFFF0) == SC_CLOSE) {
    02223                     /*
    02224                      * Since the window is maxed, we've cleared WFSYSMENU (see
    02225                      *  MDIAddSysMenu). We need to set it back here so GetSysMenuHandle
    02226                      *  will do the right thing for _MNCanClose.
    02227                      */
    02228                     BOOL fCanClose;
    02229                     UserAssert(!TestWF(pwndT, WFSYSMENU) && (pwndT->spmenuSys != NULL));
    02230                     SetWindowState(pwndT, WFSYSMENU);
    02231                     fCanClose = xxxMNCanClose(pwndT);
    02232                     ClearWindowState(pwndT, WFSYSMENU);
    02233                     if (!fCanClose) {
    02234                         break;
    02235                     }
    02236                 } else if (((wParam & 0xFFF0) == SC_MINIMIZE) && !TestWF(pwndT, WFMINBOX)) {
    02237                     break;
    02238                 }
    02239
    02240                 return SendMessage(hwndT, WM_SYSCOMMAND, wParam, lParam);
    02241             }
    02242         }
    02243         goto CallDWP;
    02244
    02245     case WM_SIZE:
    02246         if (wParam != SIZEICONIC) {
    02247             NtUserMoveWindow(hwndMDI, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
    02248         } else {
    02249             wp.length = sizeof(WINDOWPLACEMENT);
    02250             if (GetWindowPlacement(hwnd, &wp)) {
    02251                 RECT rcT;
    02252                 int  clB;
    02253
    02254                /*
    02255                 * If frame is iconic, size mdi win to be size of restored
    02256                 * frame's client area.  Thus mdi children etc created in here
    02257                 * use the proper mdiclient size.
    02258                 */
    02259                clB = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, TRUE);
    02260
    02261                CopyInflateRect(&rcT, &wp.rcNormalPosition,
    02262                         -clB*SYSMET(CXBORDER), -clB*SYSMET(CYBORDER));
    02263
    02264                if (TestWF(pwnd, WFBORDERMASK) == LOBYTE(WFCAPTION))
    02265                        rcT.top += SYSMET(CYCAPTION);
    02266                rcT.top += SYSMET(CYMENU);
    02267
    02268                NtUserMoveWindow(hwndMDI, 0, 0, rcT.right-rcT.left,
    02269                        rcT.bottom-rcT.top, TRUE);
    02270             }
    02271         }
    02272         goto CallDWP;
    02273
    02274     case WM_SETFOCUS:
    02275         NtUserSetFocus(hwndMDI);
    02276         break;
    02277
    02278     case WM_NEXTMENU:
    02279         if (TestWF(pwnd, WFSYSMENU) && !TestWF(pwnd, WFMINIMIZED) &&
    02280             ACTIVE(pmdi) && !MAXED(pmdi))
    02281         {
    02282             PMENU pmenuIn;
    02283             /*
    02284              * Go to child system menu by wrapping to the left from
    02285              * the first popup in the menu bar or to the right from
    02286              * the frame sysmenu.
    02287              */
    02288             pmnm = (PMDINEXTMENU)lParam;
    02289             pmenuIn = RevalidateHmenu(pmnm->hmenuIn);
    02290
    02291             if (pmenuIn && ((wParam == VK_LEFT && pmenuIn == REBASE(pwnd, spmenu)) ||
    02292                     (wParam == VK_RIGHT && pmnm->hmenuIn ==
    02293                     NtUserGetSystemMenu(hwnd, FALSE)))) {
    02294
    02295                 HMENU hmenu;
    02296                 PWND pwndActive;
    02297
    02298                 //
    02299                 // Make sure the window is still valid
    02300                 //
    02301                 if ((pwndActive = ValidateHwnd(ACTIVE(pmdi))) == NULL) {
    02302                     return 0;
    02303                 }
    02304
    02305                 //
    02306                 // Make sure the child's system menu items are updated
    02307                 // (i.e. the ones are enabled/disabled)
    02308                 //
    02309                 if (!TestWF(pwndActive,WFMAXIMIZED)) {
    02310                     NtUserSetSysMenu(ACTIVE(pmdi));
    02311                 }
    02312
    02313                 hmenu = NtUserGetSystemMenu(ACTIVE(pmdi), FALSE);
    02314                 pmnm->hmenuNext = hmenu;
    02315                 pmnm->hwndNext = ACTIVE(pmdi);
    02316
    02317                 return TRUE;
    02318             }
    02319         }
    02320
    02321         /*
    02322          * default behaviour
    02323          */
    02324         return 0L;
    02325
    02326     case WM_MENUCHAR:
    02327         if (!TestWF(pwnd, WFMINIMIZED) && LOWORD(wParam) == TEXT('-')) {
    02328             if (MAXED(pmdi))
    02329                 return MAKELONG(0, 2);
    02330             else if (ACTIVE(pmdi)) {
    02331               PostMessage(ACTIVE(pmdi), WM_SYSCOMMAND,
    02332                     SC_KEYMENU, MAKELONG(TEXT('-'), 0));
    02333               return MAKELONG(0, 1);
    02334           }
    02335         }
    02336
    02337         /*
    02338          ** FALL THRU **
    02339          */
    02340
    02341     default:
    02342 CallDWP:
    02343         return DefWindowProcWorker(pwnd, wMsg, wParam, lParam, fAnsi);
    02344     }
    02345
    02346     return 0L;
    02347 }
    02348
    02349
    02350 LRESULT WINAPI DefFrameProcW(
    02351     HWND hwnd,
    02352     HWND hwndMDIClient,
    02353     UINT message,
    02354     WPARAM wParam,
    02355     LPARAM lParam)
    02356 {
    02357     return DefFrameProcWorker(hwnd, hwndMDIClient, message, wParam, lParam,
    02358                               FALSE);
    02359 }
    02360
    02361 LRESULT WINAPI DefFrameProcA(
    02362     HWND hwnd,
    02363     HWND hwndMDIClient,
    02364     UINT message,
    02365     WPARAM wParam,
    02366     LPARAM lParam)
    02367 {
    02368     return DefFrameProcWorker(hwnd, hwndMDIClient, message, wParam,
    02369                               lParam, TRUE);
    02370 }
    02371
    02372
    02373 /***************************************************************************\
    02374 * ChildMinMaxInfo
    02375 *
    02376 * History:
    02377 * 11-14-90 MikeHar Ported from windows
    02378 \***************************************************************************/
    02379
    02380 void ChildMinMaxInfo(
    02381     PWND pwnd,
    02382     PMINMAXINFO pmmi)
    02383 {
    02384     PWND pwndParent = REBASEPWND(pwnd, spwndParent);
    02385     RECT rc;
    02386 #ifdef USE_MIRRORING
    02387     int SaveLeft;
    02388 #endif
    02389     UserAssert(GETFNID(pwnd) != FNID_DESKTOP);
    02390
    02391     CopyRect(&rc, &pwndParent->rcClient);
    02392     _ScreenToClient(pwndParent, (LPPOINT)&rc.left);
    02393     _ScreenToClient(pwndParent, (LPPOINT)&rc.right);
    02394
    02395 #ifdef USE_MIRRORING
    02396     /*
    02397      * Swap the left and right if pwnd is a mirrored window.
    02398      */
    02399     if (TestWF(pwnd,WEFLAYOUTRTL)) {
    02400        SaveLeft = rc.left;
    02401        rc.left  = rc.right;
    02402        rc.right = SaveLeft;
    02403     }
    02404 #endif
    02405
    02406     _AdjustWindowRectEx(&rc, pwnd->style, FALSE, pwnd->ExStyle);
    02407
    02408     /*
    02409      * Position...
    02410      */
    02411     pmmi->ptMaxPosition.x = rc.left;
    02412     pmmi->ptMaxPosition.y = rc.top;
    02413     pmmi->ptMaxSize.x = rc.right - rc.left;
    02414     pmmi->ptMaxSize.y = rc.bottom - rc.top;
    02415 }
    02416
    02417
    02418 /***************************************************************************\
    02419 * xxxChildResize
    02420 *
    02421 * History:
    02422 * 11-14-90 MikeHar Ported from windows
    02423 \***************************************************************************/
    02424
    02425 void xxxChildResize(
    02426     PWND pwnd,
    02427     UINT wMode)
    02428 {
    02429     PWND pwndT;
    02430     PWND pwndMDI = REBASEPWND(pwnd, spwndParent);
    02431     PWND pwndFrame = REBASEPWND(pwndMDI, spwndParent);
    02432     HWND hwndOldActive;
    02433     PMDI pmdi;
    02434     HWND hwndActive;
    02435     TL tlpwndMDI;
    02436     TL tlpwndFrame;
    02437     TL tlpwndT;
    02438     PMENU pmenu;
    02439     HWND hwnd = HWq(pwnd);
    02440
    02441     CheckLock(pwnd);
    02442
    02443     NtUserSetSysMenu(hwnd);
    02444
    02445     ThreadLock(pwndMDI, &tlpwndMDI);
    02446     ThreadLock(pwndFrame, &tlpwndFrame);
    02447
    02448     /*
    02449      * Get a pointer to the MDI structure
    02450      */
    02451     pmdi = ((PMDIWND)pwndMDI)->pmdi;
    02452     pmenu = REBASE(pwndFrame, spmenu);
    02453
    02454     if (MAXED(pmdi) == hwnd && wMode != SIZEFULLSCREEN) {
    02455         /*
    02456          * Restoring the current maximized window...
    02457          * Remove the system menu from the Frame window.
    02458          */
    02459         if (!(SCROLL(pmdi) & OTHERMAXING)) {
    02460             Unlock(&MAXED(pmdi));
    02461             MDIRemoveSysMenu(PtoH(pmenu), hwnd);
    02462             Unlock(&MAXED(pmdi));
    02463             xxxSetFrameTitle(pwndFrame, pwndMDI, (LPWSTR)1L);
    02464         }
    02465     }
    02466
    02467     if (wMode == SIZEFULLSCREEN) {
    02468
    02469         /*
    02470          * Already maximized?
    02471          */
    02472         if (hwnd == MAXED(pmdi))
    02473             goto Exit;
    02474
    02475         /*
    02476          * Maximizing this window...
    02477          */
    02478
    02479         pmdi->wScroll |= OTHERMAXING | SCROLLCOUNT;
    02480
    02481         if (hwndOldActive = MAXED(pmdi)) {
    02482             SendMessage(hwndOldActive, WM_SETREDRAW, FALSE, 0L);
    02483             MDIRemoveSysMenu(PtoH(pmenu), hwndOldActive);
    02484             NtUserMinMaximize(hwndOldActive, SW_MDIRESTORE, FALSE);
    02485             SendMessage(hwndOldActive, WM_SETREDRAW, TRUE, 0L);
    02486         }
    02487
    02488         Lock(&MAXED(pmdi), hwnd);
    02489
    02490         /*
    02491          * Add the system menu to the Frame window.
    02492          */
    02493         MDIAddSysMenu(PtoH(pmenu), hwnd);
    02494         xxxSetFrameTitle(pwndFrame, pwndMDI, (LPWSTR)1L);
    02495
    02496         pmdi->wScroll &= ~(OTHERMAXING | SCROLLCOUNT);
    02497     }
    02498
    02499     if (wMode == SIZEICONIC) {
    02500         for (pwndT = REBASEPWND(pwndMDI, spwndChild); pwndT;
    02501                 pwndT = REBASEPWND(pwndT, spwndNext)) {
    02502             if (!pwndT->spwndOwner && TestWF(pwndT, WFVISIBLE))
    02503                 break;
    02504         }
    02505
    02506         hwndActive = NtUserQueryWindow(hwnd, WindowActiveWindow);
    02507         if ((pwndT != NULL) && (hwndActive != NULL) &&
    02508                 IsChild(hwndActive, HWq(pwndMDI))) {
    02509             ThreadLockAlways(pwndT, &tlpwndT);
    02510             SendMessage(HWq(pwndT), WM_CHILDACTIVATE, 0, 0L);
    02511             ThreadUnlock(&tlpwndT);
    02512         }
    02513     }
    02514
    02515     if (!(SCROLL(pmdi) & SCROLLCOUNT))
    02516         RecalculateScrollRanges(pwndMDI, FALSE);
    02517
    02518 Exit:
    02519     ThreadUnlock(&tlpwndFrame);
    02520     ThreadUnlock(&tlpwndMDI);
    02521 }
    02522
    02523
    02524 /***************************************************************************\
    02525 * DefMDIChildProc
    02526 *
    02527 * History:
    02528 * 11-14-90 MikeHar Ported from windows
    02529 \***************************************************************************/
    02530
    02531 LRESULT DefMDIChildProcWorker(
    02532     HWND hwnd,
    02533     UINT wMsg,
    02534     WPARAM wParam,
    02535     LPARAM lParam,
    02536     BOOL fAnsi)
    02537 {
    02538     PWND pwnd;
    02539     PWND pwndParent;
    02540     PMDI pmdi;
    02541     PMDINEXTMENU pmnm;
    02542     HWND hwndT;
    02543     PWND pwndT;
    02544     TL tlpwndT;
    02545     TL tlpwndParent;
    02546     LRESULT lRet;
    02547
    02548     if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
    02549         return (0L);
    02550     }
    02551
    02552     CheckLock(pwnd);
    02553
    02554     /*
    02555      * Check to see if this is a real mdi child window
    02556      */
    02557     pwndParent = REBASEPWND(pwnd, spwndParent);
    02558     if (!pwndParent || GETFNID(pwndParent) != FNID_MDICLIENT) {
    02559         RIPERR0(ERROR_NON_MDICHILD_WINDOW, RIP_VERBOSE, "");
    02560         return DefWindowProcWorker(pwnd, wMsg, wParam, lParam, fAnsi);
    02561     }
    02562
    02563     /*
    02564      * Get a pointer to the MDI structure, if it still exists
    02565      */
    02566     pmdi = ((PMDIWND)pwndParent)->pmdi;
    02567     if ((ULONG_PTR)pmdi == (ULONG_PTR)-1) {
    02568         goto CallDWP;
    02569     }
    02570
    02571     switch (wMsg) {
    02572     case WM_SETFOCUS:
    02573         if (DIFFWOWHANDLE(hwnd, ACTIVE(pmdi))) {
    02574             ThreadLockAlways(pwndParent, &tlpwndParent);
    02575             xxxMDIActivate(pwndParent, pwnd);
    02576             ThreadUnlock(&tlpwndParent);
    02577         }
    02578         goto CallDWP;
    02579
    02580     case WM_NEXTMENU:
    02581
    02582         /*
    02583          * wrap to the frame menu bar, either left to the system menu,
    02584          * or right to the frame menu bar.
    02585          */
    02586         pmnm = (PMDINEXTMENU)lParam;
    02587         pwndT = REBASEPWND(pwndParent, spwndParent);
    02588         pmnm->hwndNext = HW(pwndT);
    02589         pmnm->hmenuNext = (wParam == VK_LEFT) ?
    02590                 NtUserGetSystemMenu(pmnm->hwndNext, FALSE) :
    02591                 GetMenu(pmnm->hwndNext);
    02592         return TRUE;
    02593 #if 0
    02594              hWnd->hwndParent->hwndParent
    02595         return (LONG)(((wParam == VK_LEFT) ?
    02596                 NtUserGetSystemMenu(HW(pwndT), FALSE):
    02597                 pwndT->spmenu)
    02598           );
    02599 // return MAKELONG(NtUserGetSystemMenu(ACTIVE(pwndMDI), FALSE),
    02600 // ACTIVE(pwndMDI));
    02601 #endif
    02602     case WM_CLOSE:
    02603         hwndT = GetParent(hwnd);
    02604         if (hwndT != NULL) {
    02605             SendMessage(hwndT, WM_MDIDESTROY, (WPARAM)hwnd, 0L);
    02606         }
    02607         break;
    02608
    02609     case WM_MENUCHAR:
    02610         PostMessage(GetParent(GetParent(hwnd)), WM_SYSCOMMAND,
    02611                 (DWORD)SC_KEYMENU, (LONG)LOWORD(wParam));
    02612         return 0x10000;
    02613
    02614     case WM_SETTEXT:
    02615         DefWindowProcWorker(pwnd, wMsg, wParam, lParam, fAnsi);
    02616         if (WINDOW(pmdi))
    02617             ModifyMenuItem(pwnd);
    02618
    02619         if (TestWF(pwnd, WFMAXIMIZED)) {
    02620
    02621             /*
    02622              * Add the child's window text to the frame since it is
    02623              * maximized.  But just redraw the caption so pass a 3L.
    02624              */
    02625             pwndT = REBASEPWND(pwndParent, spwndParent);
    02626             ThreadLock(pwndT, &tlpwndT);
    02627             ThreadLock(pwndParent, &tlpwndParent);
    02628             xxxSetFrameTitle(pwndT, pwndParent, (LPWSTR)3L);
    02629             ThreadUnlock(&tlpwndParent);
    02630             ThreadUnlock(&tlpwndT);
    02631         }
    02632         break;
    02633
    02634     case WM_GETMINMAXINFO:
    02635         ChildMinMaxInfo(pwnd, (PMINMAXINFO)lParam);
    02636         break;
    02637
    02638     case WM_SIZE:
    02639         xxxChildResize(pwnd, (UINT)wParam);
    02640         goto CallDWP;
    02641
    02642     case WM_MOVE:
    02643         if (!TestWF(pwnd, WFMAXIMIZED))
    02644             RecalculateScrollRanges(pwndParent, FALSE);
    02645         goto CallDWP;
    02646
    02647     case WM_CHILDACTIVATE:
    02648         ThreadLock(pwndParent, &tlpwndParent);
    02649         xxxMDIActivate(pwndParent, pwnd);
    02650         ThreadUnlock(&tlpwndParent);
    02651         break;
    02652
    02653     case WM_SYSCOMMAND:
    02654         switch (wParam & 0xFFF0) {
    02655         case SC_NEXTWINDOW:
    02656         case SC_PREVWINDOW:
    02657             hwndT = GetParent(hwnd);
    02658             SendMessage(hwndT, WM_MDINEXT, (WPARAM)hwnd,
    02659                     (DWORD)((wParam & 0xFFF0) == SC_PREVWINDOW));
    02660             break;
    02661
    02662         case SC_SIZE:
    02663         case SC_MOVE:
    02664             if (SAMEWOWHANDLE(hwnd, MAXED(pmdi))) {
    02665
    02666                 /*
    02667                  * If a maxed child gets a size or move message, blow it
    02668                  * off.
    02669                  */
    02670                 break;
    02671             } else
    02672                 goto CallDWP;
    02673
    02674         case SC_MAXIMIZE:
    02675             if (SAMEWOWHANDLE(hwnd, MAXED(pmdi))) {
    02676
    02677                 /*
    02678                  * If a maxed child gets a maximize message, forward it
    02679                  * to the frame.  Useful if the maximized child has a
    02680                  * size box so that clicking on it then maximizes the
    02681                  * parent.
    02682                  */
    02683                 pwndT = REBASEPWND(pwndParent, spwndParent);
    02684                 ThreadLock(pwndT, &tlpwndT);
    02685                 lRet = SendMessage(HW(pwndT),
    02686                         WM_SYSCOMMAND, SC_MAXIMIZE, lParam);
    02687                 ThreadUnlock(&tlpwndT);
    02688                 return lRet;
    02689             }
    02690
    02691             /*
    02692              * else fall through
    02693              */
    02694
    02695         default:
    02696             goto CallDWP;
    02697         }
    02698         break;
    02699
    02700     default:
    02701 CallDWP:
    02702         return DefWindowProcWorker(pwnd, wMsg, wParam, lParam, fAnsi);
    02703     }
    02704
    02705     return 0L;
    02706 }
    02707
    02708
    02709 /***************************************************************************\
    02710 * DefMDIChildProc
    02711 *
    02712 * Translates the message, calls DefMDIChildProc on server side.
    02713 *
    02714 * 04-11-91 ScottLu Created.
    02715 \***************************************************************************/
    02716
    02717 LRESULT WINAPI DefMDIChildProcW(
    02718     HWND hwnd,
    02719     UINT message,
    02720     WPARAM wParam,
    02721     LPARAM lParam)
    02722 {
    02723     return DefMDIChildProcWorker(hwnd, message, wParam, lParam, FALSE);
    02724 }
    02725
    02726 LRESULT WINAPI DefMDIChildProcA(
    02727     HWND hwnd,
    02728     UINT message,
    02729     WPARAM wParam,
    02730     LPARAM lParam)
    02731 {
    02732     return DefMDIChildProcWorker(hwnd, message, wParam, lParam, TRUE);
    02733 }
    02734
    02735 BOOL MDICompleteChildCreation(HWND hwndChild, HMENU hSysMenu, BOOL fVisible, BOOL fDisabled) {
    02736     PWND pwndChild;
    02737     PWND  pwndClient;
    02738     HWND  hwndClient;
    02739     BOOL  fHasOwnSysMenu;
    02740     PMDI pmdi;
    02741
    02742     pwndChild = ValidateHwnd(hwndChild);
    02743     pwndClient = REBASEPWND(pwndChild,spwndParent);
    02744     hwndClient = HWq(pwndClient);
    02745
    02746     fHasOwnSysMenu = (pwndChild->spmenuSys) ? TRUE : FALSE;
    02747
    02748     pmdi = ((PMDIWND)(pwndClient))->pmdi;
    02749
    02750     CKIDS(pmdi)++;
    02751     ITILELEVEL(pmdi)++;
    02752     if (ITILELEVEL(pmdi) > 0x7ffe)
    02753         ITILELEVEL(pmdi) = 0;
    02754
    02755     // Update "Window" menu if this new window should be on it
    02756     if (fVisible && !fDisabled && (CKIDS(pmdi) <= MAXITEMS))
    02757         SendMessage(hwndClient, WM_MDIREFRESHMENU, 0, 0L);
    02758
    02759     //
    02760     // Add the MDI System Menu.  Catch the case of not being able to add a
    02761     // system menu (EG, guy doesn't have WS_SYSMENU style), and delete the
    02762     // menu to avoid buildup in USER's heap.
    02763     //
    02764     if (hSysMenu && (fHasOwnSysMenu || !NtUserSetSystemMenu(hwndChild, hSysMenu)))
    02765         NtUserDestroyMenu(hSysMenu);
    02766
    02767     if (fVisible)
    02768     {
    02769         if (!TestWF(pwndChild, WFMINIMIZED) || !ACTIVE(pmdi))
    02770         {
    02771             NtUserSetWindowPos(hwndChild, HWND_TOP, 0, 0, 0, 0,
    02772                     SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
    02773
    02774             if (TestWF(pwndChild, WFMAXIMIZED) && !fHasOwnSysMenu)
    02775             {
    02776                 PWND pwndParent = REBASEPWND(pwndClient, spwndParent);
    02777                 PMENU pmenu = REBASE(pwndParent, spmenu);
    02778                 MDIAddSysMenu(PtoH(pmenu), hwndChild);
    02779                 NtUserRedrawFrame(HW(pwndParent));
    02780             }
    02781         }
    02782         else
    02783         {
    02784             NtUserShowWindow(hwndChild, SW_SHOWMINNOACTIVE);
    02785         }
    02786     }
    02787
    02788
    02789     return TRUE;
    02790 }
    02791
    02792
    02793 BOOL
    02794 CreateMDIChild(
    02795         PSHORTCREATE        psc,
    02796         LPMDICREATESTRUCT   pmcs,
    02797         DWORD               dwExpWinVerAndFlags,
    02798         HMENU *             phSysMenu,
    02799         PWND                pwndParent)
    02800 {
    02801     BOOL fVisible;
    02802     RECT rcT;
    02803     HMENU hSysMenu = NULL;
    02804     HWND hwndPrevMaxed;
    02805     PMDI pmdi;
    02806
    02807     /*
    02808      * Get a pointer to the MDI structure
    02809      */
    02810     pmdi = ((PMDIWND)(pwndParent))->pmdi;
    02811
    02812     pmcs->style = psc->style;
    02813
    02814     // Mask off ignored style bits and add required ones.
    02815     psc->style |= (WS_CHILD | WS_CLIPSIBLINGS);
    02816     if (!(pwndParent->style & MDIS_ALLCHILDSTYLES))
    02817     {
    02818         psc->style &= WS_MDIALLOWED;
    02819         psc->style |= (WS_MDISTYLE | WS_VISIBLE);
    02820     }
    02821     else if (psc->style & WS_POPUP)
    02822     {
    02823         RIPMSG0(RIP_ERROR, "CreateWindowEx: WS_POPUP not allowed on MDI children");
    02824         if (LOWORD(dwExpWinVerAndFlags) >= VER40)
    02825             return FALSE;
    02826     }
    02827
    02828     fVisible = ((psc->style & WS_VISIBLE) != 0L);
    02829
    02830     //
    02831     // Save ORIGINAL parameters in MDICREATESTRUCT.  This is for
    02832     // compatibility with old WM_MDICREATE.
    02833     //
    02834     pmcs->x   = rcT.left   = psc->x;
    02835     pmcs->y   = rcT.top    = psc->y;
    02836     pmcs->cx  = rcT.right  = psc->cx;
    02837     pmcs->cy  = rcT.bottom = psc->cy;
    02838
    02839     MDICheckCascadeRect(pwndParent, &rcT);
    02840
    02841     //
    02842     // Setup creation coords
    02843     //
    02844     psc->x       = rcT.left;
    02845     psc->y       = rcT.top;
    02846     psc->cx      = rcT.right;
    02847     psc->cy      = rcT.bottom;
    02848
    02849     // Load the system menu
    02850     if (psc->style & WS_SYSMENU) {
    02851         hSysMenu = xxxLoadSysMenu(CHILDSYSMENU);
    02852         if (hSysMenu == NULL) {
    02853             return FALSE;
    02854         }
    02855     }
    02856
    02857
    02858     // The window got created ok: now restore the current maximized window
    02859     // so we can maximize ourself in its place.
    02860     hwndPrevMaxed = MAXED(pmdi);
    02861     if (fVisible && IsWindow(hwndPrevMaxed))
    02862     {
    02863         if (psc->style & WS_MAXIMIZE)
    02864             SendMessage(hwndPrevMaxed, WM_SETREDRAW, (WPARAM)FALSE, 0L);
    02865
    02866         // we could nuke the hwndPrevMaxed during the SendMessage32
    02867         // so recheck just in case, B#11122, [t-arthb]
    02868
    02869         if ( IsWindow(hwndPrevMaxed) )
    02870         {
    02871             NtUserMinMaximize(hwndPrevMaxed, SW_SHOWNORMAL, TRUE);
    02872
    02873             if ( psc->style & WS_MAXIMIZE )
    02874                SendMessage(hwndPrevMaxed, WM_SETREDRAW, (WPARAM)TRUE, 0L);
    02875         }
    02876
    02877     }
    02878
    02879     // Set the proper Child Window ID for this MDI child.
    02880     psc->hMenu = (HMENU)UIntToPtr( (FIRST(pmdi) + CKIDS(pmdi)) );
    02881
    02882     *phSysMenu = hSysMenu;
    02883
    02884     return TRUE;
    02885 }