Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2918 lines
82 KiB

  1. /****************************************************************************\
  2. *
  3. * MDIWIN.C -
  4. *
  5. * Copyright (c) 1985 - 1999, Microsoft Corporation
  6. *
  7. * MDI Child Windows Support
  8. *
  9. * History
  10. * 11-14-90 MikeHar Ported from windows
  11. * 14-Feb-1991 mikeke Added Revalidation code
  12. \****************************************************************************/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #define TITLE_EXTRA 5
  16. #define MAX_TITLE_LEN 160
  17. /***************************************************************************\
  18. * xxxSetFrameTitle
  19. *
  20. * if lpch == 1, we redraw the whole frame. If 2, we don't do any redraw. Any
  21. * other value, and we redraw just the caption of the frame.
  22. *
  23. * History:
  24. * 11-14-90 MikeHar Ported from windows
  25. * 04-16-91 MikeHar Win31 Merge
  26. \***************************************************************************/
  27. VOID xxxSetFrameTitle(
  28. PWND pwndFrame,
  29. PWND pwndMDI,
  30. LPWSTR lpch)
  31. {
  32. PWND pwnd;
  33. PMDI pmdi;
  34. WCHAR sz[MAX_TITLE_LEN];
  35. HWND hwndFrame = HW(pwndFrame);
  36. CheckLock(pwndFrame);
  37. CheckLock(pwndMDI);
  38. /*
  39. * Get a pointer to the MDI structure.
  40. */
  41. pmdi = ((PMDIWND)pwndMDI)->pmdi;
  42. if (IS_PTR(lpch) || lpch == NULL) {
  43. if (HTITLE(pmdi)) {
  44. UserLocalFree(HTITLE(pmdi));
  45. }
  46. HTITLE(pmdi) = TextAlloc(lpch);
  47. }
  48. if (HTITLE(pmdi)) {
  49. LARGE_UNICODE_STRING str;
  50. int cch;
  51. RtlInitLargeUnicodeString(&str, HTITLE(pmdi), (UINT)-1);
  52. TextCopy(&str, sz, sizeof(sz)/sizeof(WCHAR));
  53. if (MAXED(pmdi) && (pwnd = ValidateHwnd(MAXED(pmdi))) && pwnd->strName.Length) {
  54. cch = MAX_TITLE_LEN - ((str.Length / sizeof(WCHAR)) + TITLE_EXTRA);
  55. if (cch > 0) {
  56. wcscat(sz, TEXT(" - ["));
  57. wcsncat(sz, REBASE(pwnd, strName.Buffer), cch - 1);
  58. wcscat(sz, TEXT("]"));
  59. }
  60. }
  61. } else {
  62. sz[0] = 0;
  63. }
  64. _DefSetText(hwndFrame, sz, FALSE);
  65. if (lpch == (LPWSTR)1L)
  66. NtUserRedrawFrameAndHook(hwndFrame);
  67. else if (lpch != (LPWSTR)2L) {
  68. if (!NtUserRedrawTitle(hwndFrame, DC_TEXT))
  69. NtUserRedrawFrame(hwndFrame);
  70. }
  71. }
  72. /***************************************************************************\
  73. * TranslateMDISysAccel
  74. *
  75. * History:
  76. * 11-14-90 MikeHar Ported from windows
  77. \***************************************************************************/
  78. FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, TranslateMDISysAccel, HWND, hwnd, LPMSG, lpMsg)
  79. BOOL TranslateMDISysAccel(
  80. HWND hwnd,
  81. LPMSG lpMsg)
  82. {
  83. PWND pwnd;
  84. PMDI pmdi;
  85. int event;
  86. /*
  87. * Is this a message we care about?
  88. */
  89. if (lpMsg->message != WM_KEYDOWN && lpMsg->message != WM_SYSKEYDOWN) {
  90. return FALSE;
  91. }
  92. /*
  93. * This is called within a message loop. If the window gets destroyed,
  94. * there still may be other messages in the queue that get returned
  95. * after the window is destroyed. The app will call TranslateAccelerator()
  96. * on every one of these, causing RIPs.... Make it nice so it just
  97. * returns FALSE.
  98. */
  99. if ((pwnd = ValidateHwndNoRip(hwnd)) == NULL) {
  100. RIPERR0(ERROR_INVALID_WINDOW_HANDLE, RIP_VERBOSE, "");
  101. return FALSE;
  102. }
  103. CheckLock(pwnd);
  104. /*
  105. * Make sure this is really an MDIClient window. Harvard Graphics 2.0
  106. * calls this function with a different window class and caused us
  107. * to get an access violation.
  108. */
  109. if (GETFNID(pwnd) != FNID_MDICLIENT) {
  110. RIPMSG0(RIP_WARNING, "Window not of MDIClient class");
  111. return FALSE;
  112. }
  113. /*
  114. * Get a pointer to the MDI structure
  115. */
  116. pmdi = ((PMDIWND)pwnd)->pmdi;
  117. if (!ACTIVE(pmdi))
  118. return FALSE;
  119. if (!IsWindowEnabled(ACTIVE(pmdi)))
  120. return FALSE;
  121. switch (lpMsg->wParam) {
  122. case VK_F4:
  123. event = SC_CLOSE;
  124. break;
  125. case VK_F6:
  126. case VK_TAB:
  127. if (GetKeyState(VK_SHIFT) < 0)
  128. event = SC_PREVWINDOW;
  129. else
  130. event = SC_NEXTWINDOW;
  131. break;
  132. default:
  133. return FALSE;
  134. }
  135. /*
  136. * All of these have the control key down
  137. */
  138. if (GetKeyState(VK_CONTROL) >= 0)
  139. return FALSE;
  140. if (GetKeyState(VK_MENU) < 0)
  141. return FALSE;
  142. SendMessage(ACTIVE(pmdi), WM_SYSCOMMAND, event, MAKELONG(lpMsg->wParam, 0));
  143. return TRUE;
  144. }
  145. /***************************************************************************\
  146. *
  147. * CalcClientScrolling()
  148. *
  149. \***************************************************************************/
  150. #define SBJ_HORZ HAS_SBHORZ
  151. #define SBJ_VERT HAS_SBVERT
  152. #define SBJ_BOTH (SBJ_HORZ | SBJ_VERT)
  153. VOID ByteOutsetRect(
  154. LPRECT lprc)
  155. {
  156. int *pi;
  157. int i;
  158. for (i = 0, pi = (int*)lprc; i < 4; i++, pi++) {
  159. if (*pi > 0) {
  160. *pi += 7;
  161. } else if (*pi < 0) {
  162. *pi -= 7;
  163. }
  164. *pi /= 8;
  165. }
  166. }
  167. VOID CalcClientScrolling(
  168. HWND hwnd,
  169. UINT sbj,
  170. BOOL fIgnoreMin)
  171. {
  172. PWND pwnd;
  173. RECT rcScroll;
  174. RECT rcClient;
  175. RECT rcRange;
  176. RECT rcT;
  177. PWND pwndT;
  178. BOOL fVert;
  179. BOOL fHorz;
  180. BYTE fHadVert, fHadHorz;
  181. BOOL fCheckVert;
  182. BOOL fCheckHorz;
  183. BOOL fNeedScrolls;
  184. SCROLLINFO si;
  185. if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
  186. return;
  187. }
  188. CheckLock(pwnd);
  189. UserAssert(GETFNID(pwnd) != FNID_DESKTOP);
  190. // do nothing if the parent is iconic. This way, we don't add invisible
  191. // scrollbars which will paint and unpaint when restoring...
  192. if (TestWF(pwnd, WFMINIMIZED))
  193. return;
  194. fVert = FALSE;
  195. fHorz = FALSE;
  196. fNeedScrolls=FALSE;
  197. fCheckHorz = (sbj & SBJ_HORZ);
  198. fCheckVert = (sbj & SBJ_VERT);
  199. // find client area without scroll bars
  200. CopyRect(&rcClient, KPRECT_TO_PRECT(&pwnd->rcClient));
  201. fHadVert = TestWF(pwnd, WFVSCROLL);
  202. if (fCheckVert && fHadVert)
  203. if (TestWF(pwnd, WEFLAYOUTRTL)) {
  204. rcClient.left -= SYSMET(CXVSCROLL);
  205. } else {
  206. rcClient.right += SYSMET(CXVSCROLL);
  207. }
  208. fHadHorz = TestWF(pwnd, WFHSCROLL);
  209. if (fCheckHorz && fHadHorz)
  210. rcClient.bottom += SYSMET(CYHSCROLL);
  211. // find the rectangle that bounds all visible child windows
  212. SetRectEmpty(&rcScroll);
  213. for (pwndT = REBASEPWND(pwnd, spwndChild); pwndT;
  214. pwndT = REBASEPWND(pwndT, spwndNext)) {
  215. if (fIgnoreMin && TestWF(pwndT, WFMINIMIZED))
  216. continue;
  217. if (TestWF(pwndT,WFVISIBLE)) {
  218. if (TestWF(pwndT, WFMAXIMIZED)) {
  219. fNeedScrolls = FALSE;
  220. break;
  221. }
  222. /*
  223. * add this window to the area that has to be visible
  224. */
  225. UnionRect(&rcScroll, &rcScroll, KPRECT_TO_PRECT(&pwndT->rcWindow));
  226. /*
  227. * add scroll bars if its not contained in the
  228. * client area
  229. */
  230. UnionRect(&rcT, &rcClient, KPRECT_TO_PRECT(&pwndT->rcWindow));
  231. if (!EqualRect(&rcClient, &rcT)) {
  232. fNeedScrolls = TRUE;
  233. }
  234. }
  235. }
  236. SetRectEmpty(&rcRange);
  237. // offset rectangles such that rcClient's top & left are both 0
  238. // making rcClient's right & bottom be the page size
  239. _ScreenToClient(pwnd, (LPPOINT)&rcScroll.left);
  240. _ScreenToClient(pwnd, (LPPOINT)&rcScroll.right);
  241. /*
  242. * Swap the left and right if pwnd is a mirrored window.
  243. */
  244. if (TestWF(pwnd, WEFLAYOUTRTL)) {
  245. int nSaveLeft;
  246. nSaveLeft = rcScroll.left;
  247. rcScroll.left = rcScroll.right;
  248. rcScroll.right = nSaveLeft;
  249. }
  250. OffsetRect(&rcClient, -rcClient.left, -rcClient.top);
  251. if (!fNeedScrolls)
  252. rcClient.bottom = rcClient.right = 0;
  253. else do
  254. {
  255. /*
  256. * the range is the union of the parent client with all of its
  257. * children
  258. */
  259. CopyRect(&rcT, &rcRange);
  260. UnionRect(&rcRange, &rcScroll, &rcClient);
  261. if (fCheckVert) {
  262. // subtract off space for the vertical scroll if we need it
  263. if (((rcRange.bottom - rcRange.top) > rcClient.bottom) && !fVert) {
  264. fVert = TRUE;
  265. rcClient.right -= SYSMET(CXVSCROLL);
  266. }
  267. }
  268. if (fCheckHorz) {
  269. // subtract off space for the horizontal scroll if we need it
  270. if (((rcRange.right - rcRange.left) > rcClient.right) && !fHorz) {
  271. fHorz = TRUE;
  272. rcClient.bottom -= SYSMET(CYHSCROLL);
  273. }
  274. }
  275. }
  276. while (!EqualRect(&rcRange, &rcT));
  277. if (fNeedScrolls) {
  278. // HACK of death beginning
  279. if (rcRange.right == rcClient.right)
  280. rcRange.right -= 8;
  281. if (rcRange.bottom == rcClient.bottom)
  282. rcRange.bottom -= 8;
  283. // HACK of death ending
  284. }
  285. if (fCheckVert) {
  286. /*
  287. * check to see if we are changing the presence of the vertical
  288. * scrollbar
  289. */
  290. if ((rcRange.bottom - rcRange.top) <= rcClient.bottom) {
  291. ClearWindowState(pwnd, WFVSCROLL);
  292. } else {
  293. SetWindowState(pwnd, WFVSCROLL);
  294. }
  295. }
  296. if (fCheckHorz) {
  297. /*
  298. * same for horizontal scroll
  299. */
  300. if ((rcRange.right - rcRange.left) <= rcClient.right) {
  301. ClearWindowState(pwnd, WFHSCROLL);
  302. } else {
  303. SetWindowState(pwnd, WFHSCROLL);
  304. }
  305. }
  306. if (fNeedScrolls) {
  307. ByteOutsetRect(&rcClient);
  308. ByteOutsetRect(&rcRange);
  309. }
  310. si.cbSize = sizeof(SCROLLINFO);
  311. si.fMask = SIF_ALL;
  312. si.nPos = 0;
  313. si.nMin = rcRange.left;
  314. si.nMax = rcRange.right;
  315. si.nPage = rcClient.right;
  316. SetScrollInfo(hwnd, SB_HORZ, &si, FALSE);
  317. si.nMin = rcRange.top;
  318. si.nMax = rcRange.bottom;
  319. si.nPage = rcClient.bottom;
  320. SetScrollInfo(hwnd, SB_VERT, &si, FALSE);
  321. if ((fHadVert != TestWF(pwnd, WFVSCROLL)) ||
  322. (fHadHorz != TestWF(pwnd, WFHSCROLL)))
  323. NtUserRedrawFrame(hwnd);
  324. }
  325. /***************************************************************************\
  326. * ScrollChildren
  327. *
  328. * Handles WM_VSCROLL and WM_HSCROLL messages
  329. *
  330. * History:
  331. * 11-14-90 MikeHar Ported from windows
  332. \***************************************************************************/
  333. void ScrollMDIChildren(
  334. HWND hwnd,
  335. int nCtl,
  336. UINT wCmd,
  337. int iThumbPos)
  338. {
  339. SCROLLINFO si;
  340. int wInc;
  341. int wNewPos;
  342. //SHORT sPos;
  343. int x, y;
  344. wInc = (((nCtl == SB_VERT) ? SYSMET(CYSIZE) : SYSMET(CXSIZE)) + 7) / 8;
  345. si.cbSize = sizeof(SCROLLINFO);
  346. si.fMask = SIF_ALL;
  347. GetScrollInfo(hwnd, nCtl, &si);
  348. si.nPage--;
  349. si.nMax -= si.nPage;
  350. switch (wCmd) {
  351. case SB_BOTTOM:
  352. wNewPos = si.nMax;
  353. break;
  354. case SB_TOP:
  355. wNewPos = si.nMin;
  356. break;
  357. case SB_LINEDOWN:
  358. wNewPos = si.nPos + wInc;
  359. break;
  360. case SB_LINEUP:
  361. wNewPos = si.nPos - wInc;
  362. break;
  363. case SB_PAGEDOWN:
  364. wNewPos = si.nPos + si.nPage;
  365. break;
  366. case SB_PAGEUP:
  367. wNewPos = si.nPos - si.nPage;
  368. break;
  369. case SB_THUMBPOSITION:
  370. wNewPos = iThumbPos;
  371. break;
  372. case SB_ENDSCROLL:
  373. CalcClientScrolling(hwnd, (nCtl == SB_VERT) ? SBJ_VERT : SBJ_HORZ, FALSE);
  374. /*
  375. ** FALL THRU **
  376. */
  377. default:
  378. return;
  379. }
  380. if (wNewPos < si.nMin)
  381. wNewPos = si.nMin;
  382. else if (wNewPos > si.nMax)
  383. wNewPos = si.nMax;
  384. SetScrollPos(hwnd, nCtl, wNewPos, TRUE);
  385. // the "* 8" is because we need to scroll in bytes. The scrollbar
  386. // increments for MDI are bytes (this is due to the fact that we need to
  387. // not upset the brush origin of the app workspace brush that is used to
  388. // fill the MDI background)
  389. x = (si.nPos - wNewPos) * 8;
  390. if (nCtl == SB_VERT) {
  391. y = x;
  392. x = 0;
  393. } else
  394. // x is already set properly for this case
  395. y = 0;
  396. NtUserScrollWindowEx(hwnd, x, y, NULL, NULL, NULL, NULL,
  397. SW_SCROLLWINDOW | SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN);
  398. }
  399. FUNCLOGVOID3(LOG_GENERAL, DUMMYCALLINGTYPE, ScrollChildren, HWND, hwnd, UINT, wMsg, DWORD, wParam)
  400. VOID ScrollChildren(
  401. HWND hwnd,
  402. UINT wMsg,
  403. DWORD wParam)
  404. {
  405. ScrollMDIChildren(hwnd,
  406. wMsg == WM_VSCROLL ? SB_VERT : SB_HORZ,
  407. LOWORD(wParam),
  408. (short)(HIWORD(wParam)));
  409. }
  410. /***************************************************************************\
  411. * RecalculateScrollRanges
  412. *
  413. * History:
  414. * 11-14-90 MikeHar Ported from windows
  415. * 04-16-91 MikeHar Win31 Merge
  416. \***************************************************************************/
  417. VOID RecalculateScrollRanges(
  418. PWND pwndParent,
  419. BOOL fIgnoreMin)
  420. {
  421. PMDI pmdi = ((PMDIWND)pwndParent)->pmdi;
  422. if (!(SCROLL(pmdi) & (CALCSCROLL | SCROLLCOUNT))) {
  423. if (PostMessage(HWq(pwndParent), MM_CALCSCROLL, fIgnoreMin, 0L)) {
  424. SCROLL(pmdi) |= CALCSCROLL;
  425. }
  426. }
  427. }
  428. /***************************************************************************\
  429. * GetCascadeWindowPos
  430. *
  431. * History:
  432. * 11-14-90 MikeHar Ported from windows
  433. * 01-12-94 FritzS Ported from Chicago
  434. \***************************************************************************/
  435. VOID GetCascadeWindowPos(
  436. LPCRECT prcClient, /* area to arrange to */
  437. int iWindow, /* index of this window */
  438. LPRECT lprc) /* resulting rectangle */
  439. {
  440. int cStack;
  441. int xStep, yStep;
  442. int dxClient, dyClient;
  443. /*
  444. * Compute the width and breadth of the situation.
  445. */
  446. dxClient = prcClient->right - prcClient->left;
  447. UserAssert(dxClient >= 0);
  448. dyClient = prcClient->bottom - prcClient->top;
  449. UserAssert(dyClient >= 0);
  450. /*
  451. * Compute the width and breadth of the window steps.
  452. */
  453. xStep = SYSMET(CXSIZEFRAME) + SYSMET(CXSIZE);
  454. yStep = SYSMET(CYSIZEFRAME) + SYSMET(CYSIZE);
  455. /*
  456. * How many windows per stack?
  457. */
  458. cStack = dyClient / (3 * yStep);
  459. lprc->right = dxClient - (cStack * xStep);
  460. lprc->bottom = dyClient - (cStack * yStep);
  461. /*
  462. * HACK!: Mod by cStack+1 and make sure no div-by-zero
  463. * exception happens.
  464. */
  465. if (++cStack <= 0) {
  466. cStack = 1;
  467. }
  468. lprc->left = prcClient->left + (iWindow % cStack) * xStep;
  469. lprc->top = prcClient->top + (iWindow % cStack) * yStep;
  470. }
  471. /***************************************************************************\
  472. * MDICheckCascadeRect
  473. *
  474. * History:
  475. * 11-14-90 MikeHar Ported from windows
  476. * 04-16-91 MikeHar Win31 Merge
  477. \***************************************************************************/
  478. VOID MDICheckCascadeRect(
  479. PWND pwndClient,
  480. LPRECT lprc)
  481. {
  482. PMDI pmdi;
  483. RECT rc, rcClient;
  484. int iWindow;
  485. /*
  486. * Get a pointer to the MDI structure
  487. */
  488. pmdi = ((PMDIWND)pwndClient)->pmdi;
  489. iWindow = ITILELEVEL(pmdi);
  490. GetRect(pwndClient, &rcClient, GRECT_CLIENT | GRECT_CLIENTCOORDS);
  491. GetCascadeWindowPos(&rcClient, iWindow, &rc);
  492. if ((lprc->right == CW_USEDEFAULT || lprc->right == CW2_USEDEFAULT) ||
  493. !(lprc->right)) {
  494. lprc->right = rc.right;
  495. }
  496. if ((lprc->bottom == CW_USEDEFAULT || lprc->bottom == CW2_USEDEFAULT) ||
  497. !(lprc->bottom)) {
  498. lprc->bottom = rc.bottom;
  499. }
  500. if (lprc->left == CW_USEDEFAULT || lprc->left == CW2_USEDEFAULT) {
  501. lprc->left = rc.left;
  502. lprc->top = rc.top;
  503. }
  504. }
  505. /***************************************************************************\
  506. * UnMaximizeChildWindows
  507. *
  508. * effects: Helper routine used by TileChildWindows and CascadeChildWindows to
  509. * restore any maximized windows of the given parent. Returns TRUE if a
  510. * maximized window was restored.
  511. *
  512. * History:
  513. * 4-16-91 MikeHar Win31 Merge
  514. \***************************************************************************/
  515. BOOL UnmaximizeChildWindows(
  516. HWND hwndParent)
  517. {
  518. HWND hwndMove;
  519. PWND pwndMove;
  520. BOOL fFoundOne = FALSE;
  521. BOOL fAsync;
  522. UINT chwnd;
  523. HWND *phwndList;
  524. HWND *phwnd;
  525. HWND hwndChild = GetWindow(hwndParent, GW_CHILD);
  526. /*
  527. * Get the hwnd list. It is returned in a block of memory allocated with
  528. * UserLocalAlloc.
  529. */
  530. if (hwndChild == NULL ||
  531. (chwnd = BuildHwndList(NULL, GetWindow(hwndParent, GW_CHILD),
  532. FALSE, 0, &phwndList)) == 0) {
  533. return FALSE;
  534. }
  535. fAsync = (hwndParent == GetDesktopWindow());
  536. for (phwnd = phwndList; chwnd > 0; chwnd--, phwnd++) {
  537. if ((hwndMove = *phwnd) == NULL) {
  538. continue;
  539. }
  540. if ((pwndMove = ValidateHwnd(hwndMove)) == NULL) {
  541. continue;
  542. }
  543. if (TestWF(pwndMove, WFMAXIMIZED) && TestWF(pwndMove, WFVISIBLE)) {
  544. //
  545. // If we haven't done it yet, lock the screen to prevent sending
  546. // paints for a cleaner update.
  547. //
  548. if (!fFoundOne && fAsync) {
  549. NtUserLockWindowUpdate(hwndParent);
  550. }
  551. fFoundOne = TRUE;
  552. if (fAsync) {
  553. NtUserShowWindowAsync(hwndMove, SW_SHOWNOACTIVATE);
  554. } else {
  555. NtUserShowWindow(hwndMove, SW_SHOWNORMAL);
  556. }
  557. }
  558. }
  559. UserLocalFree(phwndList);
  560. if (fFoundOne && fAsync) {
  561. HWND hwndActive = NtUserGetForegroundWindow();
  562. if (hwndActive != NULL) {
  563. /*
  564. * Hack! Since the above showwindows cause zorder changes, we want
  565. * the active window to be in front. This makes sure...
  566. */
  567. NtUserSetWindowPos(hwndActive, HWND_TOP, 0, 0, 0, 0,
  568. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS);
  569. }
  570. NtUserLockWindowUpdate(NULL);
  571. RedrawWindow(hwndParent, NULL, NULL,
  572. RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE | RDW_FRAME);
  573. }
  574. return fFoundOne;
  575. }
  576. /***************************************************************************\
  577. *
  578. * ARRANGEWINDOWSDATA: passed to EnumDisplayMonitors enumeration functions.
  579. *
  580. \***************************************************************************/
  581. typedef struct tagARRANGEWINDOWSDATA {
  582. PWND pwndParent;
  583. UINT flags;
  584. LPRECT lprcParent;
  585. int chwnd;
  586. int chwndReal;
  587. HWND * phwnd;
  588. PWND pwndDesktop;
  589. HDWP hdwp;
  590. UINT uGRCFlags;
  591. int fVerifyParent;
  592. } ARRANGEWINDOWSDATA, *PARRANGEWINDOWSDATA;
  593. /***************************************************************************\
  594. * ArrangeWindows
  595. *
  596. * Called from CascadeWindows and TileWindows, it performs what
  597. * is common to both functions, and calls out to the enumeration
  598. * function to do the work of window arrangement.
  599. *
  600. * History:
  601. * 10-Jul-1997 adams Created.
  602. \***************************************************************************/
  603. WORD ArrangeWindows(
  604. HWND hwndParent,
  605. UINT flags,
  606. CONST RECT * lpRect,
  607. UINT chwnd,
  608. CONST HWND * ahwnd,
  609. MONITORENUMPROC lpfnEnum)
  610. {
  611. ARRANGEWINDOWSDATA awd;
  612. HWND * phwnd = NULL;
  613. /*
  614. * Get parent window
  615. */
  616. awd.pwndDesktop = _GetDesktopWindow();
  617. if (!hwndParent) {
  618. hwndParent = HW(awd.pwndDesktop);
  619. awd.pwndParent = awd.pwndDesktop;
  620. } else {
  621. awd.pwndParent = ValidateHwnd(hwndParent);
  622. if (awd.pwndParent == NULL) {
  623. return 0;
  624. }
  625. }
  626. UnmaximizeChildWindows(hwndParent);
  627. /*
  628. * If the rect passed in contains the desktop window,
  629. * arrange the windows on the desktop
  630. */
  631. if ( lpRect &&
  632. awd.pwndParent == awd.pwndDesktop &&
  633. lpRect->left <= awd.pwndDesktop->rcClient.left &&
  634. lpRect->top <= awd.pwndDesktop->rcClient.top &&
  635. lpRect->right >= awd.pwndDesktop->rcClient.right &&
  636. lpRect->bottom >= awd.pwndDesktop->rcClient.bottom ) {
  637. lpRect = NULL;
  638. }
  639. /*
  640. * Arrange iconic windows if appropriate, and determine flags
  641. * for getting the client rectangle if no rect is given.
  642. */
  643. if (lpRect == NULL) {
  644. if ( ( awd.pwndParent != awd.pwndDesktop ||
  645. !(SYSMET(ARRANGE) & ARW_HIDE)) &&
  646. NtUserArrangeIconicWindows(hwndParent) != 0) {
  647. awd.uGRCFlags = GRC_SCROLLS | GRC_MINWNDS;
  648. } else {
  649. awd.uGRCFlags = GRC_SCROLLS;
  650. }
  651. }
  652. /*
  653. * Get window list
  654. */
  655. if (ahwnd == NULL) {
  656. HWND hwndChild;
  657. PWND pwndChild;
  658. pwndChild = REBASEPWND(awd.pwndParent, spwndChild);
  659. hwndChild = HW(pwndChild);
  660. if ( hwndChild == NULL ||
  661. (chwnd = BuildHwndList(NULL, hwndChild, FALSE, 0, &phwnd)) == 0) {
  662. return 0;
  663. }
  664. }
  665. /*
  666. * Arrange windows
  667. */
  668. awd.hdwp = NtUserBeginDeferWindowPos(chwnd);
  669. if (awd.hdwp == NULL)
  670. goto Done;
  671. awd.flags = flags;
  672. awd.lprcParent = (LPRECT) lpRect;
  673. awd.chwnd = chwnd;
  674. awd.chwndReal = 0;
  675. awd.phwnd = ahwnd ? (HWND *) ahwnd : phwnd;
  676. awd.fVerifyParent = (ahwnd != NULL);
  677. /*
  678. * If the parent is the desktop and a rectangle is not provided,
  679. * arrange the windows on each monitor. Otherwise, arrange the
  680. * windows once by calling the enumeration function directly.
  681. */
  682. if (awd.pwndParent == awd.pwndDesktop && lpRect == NULL) {
  683. NtUserEnumDisplayMonitors(NULL, NULL, lpfnEnum, (LPARAM) &awd);
  684. } else {
  685. (*lpfnEnum)(NULL, NULL, NULL, (LPARAM) &awd);
  686. }
  687. /* Make this arrangement asynchronous so we don't hang */
  688. if (awd.hdwp != NULL) {
  689. NtUserEndDeferWindowPosEx(awd.hdwp, TRUE);
  690. }
  691. Done:
  692. if (phwnd) {
  693. UserLocalFree(phwnd);
  694. }
  695. return (awd.hdwp != NULL) ? awd.chwndReal : 0;
  696. }
  697. /***************************************************************************\
  698. * GetParentArrangeRect
  699. *
  700. * Returns the rect passed in pawd if provided, otherwise gets the client
  701. * rect of the parent window.
  702. *
  703. * History:
  704. * 10-Jul-1997 adams Created.
  705. \***************************************************************************/
  706. VOID GetParentArrangeRect(
  707. PARRANGEWINDOWSDATA pawd,
  708. PMONITOR pMonitor,
  709. LPRECT lprc)
  710. {
  711. UINT uGRCFlags;
  712. if (pawd->lprcParent) {
  713. *lprc = *pawd->lprcParent;
  714. } else {
  715. uGRCFlags = pawd->uGRCFlags;
  716. /*
  717. * If icons are shown on the desktop, then they are always
  718. * shown on the primary monitor. So remove the GRC_MINWNDS
  719. * flag for monitors other than the primary.
  720. */
  721. if (pMonitor && pMonitor != GetPrimaryMonitor()) {
  722. uGRCFlags &= ~GRC_MINWNDS;
  723. }
  724. GetRealClientRect(
  725. pawd->pwndParent, lprc, uGRCFlags, pMonitor);
  726. }
  727. }
  728. /***************************************************************************\
  729. * ValidatePositionableWindow
  730. *
  731. * Validates and returns a window if it is positionable, and sets
  732. * the appropriate sizing flags.
  733. *
  734. * History:
  735. * 10-Jul-1997 adams Created.
  736. \***************************************************************************/
  737. PWND
  738. ValidatePositionableWindow(
  739. HWND hwndChild,
  740. PWND pwndParent,
  741. PWND pwndDesktop,
  742. DWORD dwMDIFlags,
  743. PMONITOR pMonitor,
  744. DWORD * pdwSWPFlags)
  745. {
  746. PWND pwndChild;
  747. pwndChild = ValidateHwnd(hwndChild);
  748. if (pwndChild) {
  749. if (pwndParent && REBASEPWND(pwndChild, spwndParent) != pwndParent) {
  750. RIPMSG0(RIP_WARNING, "Cascade/Tile Windows: Windows in list must have same parent");
  751. } else if (
  752. /*
  753. * mikesch - removed the maximized check since the call
  754. * to restore maximized windows in unmaximizechildwindows occurs
  755. * asynchronously now.
  756. */
  757. TestWF(pwndChild, WFVISIBLE) &&
  758. TestWF(pwndChild, WFCPRESENT) &&
  759. !TestWF(pwndChild, WFMINIMIZED) &&
  760. !TestWF(pwndChild, WEFTOPMOST) &&
  761. (!(dwMDIFlags & MDITILE_SKIPDISABLED) || !TestWF(pwndChild, WFDISABLED)) &&
  762. !TestWF(pwndChild, WEFTOOLWINDOW) &&
  763. ((pMonitor) ?
  764. (pMonitor == _MonitorFromWindow(pwndChild, MONITOR_DEFAULTTONULL)) :
  765. (pwndParent != pwndDesktop || _MonitorFromWindow(pwndChild, MONITOR_DEFAULTTONULL)))) {
  766. if (pdwSWPFlags) {
  767. *pdwSWPFlags = SWP_NOACTIVATE | SWP_NOCOPYBITS;
  768. if (!TestWF(pwndChild, WFSIZEBOX)) {
  769. *pdwSWPFlags |= SWP_NOSIZE;
  770. }
  771. if (!(dwMDIFlags & MDITILE_ZORDER)) {
  772. *pdwSWPFlags |= SWP_NOZORDER;
  773. }
  774. }
  775. return pwndChild;
  776. }
  777. }
  778. return NULL;
  779. }
  780. /***************************************************************************\
  781. * CascadeWindowsEnum
  782. *
  783. * Cascades windows on the monitor.
  784. *
  785. * History:
  786. * 10-Jul-1997 adams Created.
  787. \***************************************************************************/
  788. BOOL CALLBACK
  789. CascadeWindowsEnum(
  790. HMONITOR hmonitor,
  791. HDC hdc,
  792. LPRECT lprc,
  793. LPARAM lparam)
  794. {
  795. PARRANGEWINDOWSDATA pawd = (PARRANGEWINDOWSDATA)lparam;
  796. PMONITOR pMonitor = hmonitor ? VALIDATEHMONITOR(hmonitor) : NULL;
  797. RECT rcParent;
  798. int i;
  799. int chwndReal = 0;
  800. RECT rc;
  801. HWND * phwnd, * phwndCopy;
  802. BOOL fRet = TRUE;
  803. UNREFERENCED_PARAMETER(hdc);
  804. UNREFERENCED_PARAMETER(lprc);
  805. /*
  806. * Get the parent rectangle if none is given.
  807. */
  808. GetParentArrangeRect(pawd, pMonitor, &rcParent);
  809. /*
  810. * New for NT5: MDITILE_ZORDER (for the SHELL guys)
  811. * Sort pawd->phwnd by z-order
  812. */
  813. if (pawd->flags & MDITILE_ZORDER) {
  814. PWND pwndChild;
  815. HWND * phwndFullList, * phwndNext, * phwndSort, * phwndSearch;
  816. int chwndFullList, chwndSort, chwndSearch;
  817. /*
  818. * Make a copy to leave their array alone (it's supposed to be const)
  819. */
  820. phwndCopy = UserLocalAlloc(0, pawd->chwnd * sizeof(HWND));
  821. if (phwndCopy == NULL) {
  822. return FALSE;
  823. }
  824. RtlCopyMemory(phwndCopy, pawd->phwnd, pawd->chwnd * sizeof(HWND));
  825. /*
  826. * Get the sibblings Z-Ordered list.
  827. */
  828. pwndChild = REBASEPWND(pawd->pwndParent, spwndChild);
  829. if (pwndChild == NULL) {
  830. fRet = FALSE;
  831. goto CleanUp;
  832. }
  833. chwndFullList = BuildHwndList(NULL, HWq(pwndChild), FALSE, 0, &phwndFullList);
  834. if (chwndFullList == 0) {
  835. fRet = FALSE;
  836. goto CleanUp;
  837. }
  838. /*
  839. * Loop through the Z-Ordered list looking for the windows in the array
  840. */
  841. for (phwndNext = phwndFullList, chwndSort = pawd->chwnd, phwndSort = phwndCopy;
  842. (chwndFullList > 0) && (chwndSort > 1);
  843. chwndFullList--, phwndNext++) {
  844. for (chwndSearch = chwndSort, phwndSearch = phwndSort;
  845. chwndSearch > 0;
  846. chwndSearch--, phwndSearch++) {
  847. /*
  848. * If it found a window, move it after the last sorted window.
  849. */
  850. if (*phwndNext == *phwndSearch) {
  851. HWND hwndFirst = *phwndSort;
  852. *phwndSort = *phwndSearch;
  853. *phwndSearch = hwndFirst;
  854. phwndSort++;
  855. chwndSort--;
  856. break;
  857. }
  858. }
  859. }
  860. UserLocalFree(phwndFullList);
  861. } else { /* if (pawd->flags & MDITILE_ZORDER) */
  862. phwndCopy = pawd->phwnd;
  863. }
  864. /*
  865. * Arrange the windows in the list, preserving z-order.
  866. */
  867. for (i = pawd->chwnd, phwnd = phwndCopy + i - 1; --i >= 0; phwnd--) {
  868. HWND hwndChild;
  869. PWND pwndChild = NULL;
  870. DWORD dwSWPFlags;
  871. hwndChild = *phwnd;
  872. pwndChild = ValidatePositionableWindow(
  873. hwndChild,
  874. pawd->fVerifyParent ? pawd->pwndParent : NULL,
  875. pawd->pwndDesktop,
  876. pawd->flags,
  877. pMonitor,
  878. &dwSWPFlags);
  879. if (!pwndChild)
  880. continue;
  881. GetCascadeWindowPos(&rcParent, chwndReal, &rc);
  882. pawd->hdwp = NtUserDeferWindowPos(
  883. pawd->hdwp,
  884. hwndChild,
  885. HWND_TOP,
  886. rc.left,
  887. rc.top,
  888. rc.right,
  889. rc.bottom,
  890. dwSWPFlags);
  891. chwndReal++;
  892. pawd->chwndReal++;
  893. }
  894. CleanUp:
  895. if (pawd->flags & MDITILE_ZORDER) {
  896. UserLocalFree(phwndCopy);
  897. }
  898. return fRet && (pawd->hdwp != NULL);
  899. }
  900. /***************************************************************************\
  901. *
  902. * CascadeWindows()
  903. *
  904. * Cascades a list of children within a parent, according to the flags and
  905. * the rectangle passed in.
  906. *
  907. \***************************************************************************/
  908. WORD CascadeWindows(
  909. HWND hwndParent,
  910. UINT flags,
  911. CONST RECT *lpRect,
  912. UINT chwnd,
  913. CONST HWND *ahwnd)
  914. {
  915. return ArrangeWindows(hwndParent, flags, lpRect, chwnd, ahwnd, CascadeWindowsEnum);
  916. }
  917. BOOL CALLBACK
  918. TileWindowsEnum(
  919. HMONITOR hmonitor,
  920. HDC hdc,
  921. LPRECT lprc,
  922. LPARAM lparam)
  923. {
  924. PARRANGEWINDOWSDATA pawd = (PARRANGEWINDOWSDATA)lparam;
  925. PMONITOR pMonitor = hmonitor ? VALIDATEHMONITOR(hmonitor) : NULL;
  926. RECT rcParent;
  927. int ihwnd;
  928. int chwndReal;
  929. int square;
  930. int iCol, iRow;
  931. int cCol, cRow;
  932. int cRem;
  933. int dx, dy;
  934. int xRes, yRes;
  935. UNREFERENCED_PARAMETER(hdc);
  936. UNREFERENCED_PARAMETER(lprc);
  937. /*
  938. * Get the parent rectangle if none is given.
  939. */
  940. GetParentArrangeRect(pawd, pMonitor, &rcParent);
  941. /*
  942. * Now, figure out how many REAL windows we have.
  943. */
  944. chwndReal = 0;
  945. for (ihwnd = pawd->chwnd; --ihwnd >= 0;) {
  946. if (ValidatePositionableWindow(
  947. pawd->phwnd[ihwnd],
  948. pawd->fVerifyParent ? pawd->pwndParent : NULL,
  949. pawd->pwndDesktop,
  950. pawd->flags,
  951. pMonitor,
  952. NULL)) {
  953. chwndReal++;
  954. }
  955. }
  956. if (chwndReal == 0)
  957. return TRUE;
  958. xRes = rcParent.right - rcParent.left;
  959. yRes = rcParent.bottom - rcParent.top;
  960. if (xRes <= 0 || yRes <= 0)
  961. return TRUE;
  962. /*
  963. * Compute nearest least square
  964. */
  965. for (square = 2; square * square <= chwndReal; square++) {
  966. /* do nothing */;
  967. }
  968. if (pawd->flags & MDITILE_HORIZONTAL) {
  969. cCol = square - 1;
  970. cRow = chwndReal / cCol;
  971. cRem = chwndReal % cCol;
  972. } else {
  973. cRow = square - 1;
  974. cCol = chwndReal / cRow;
  975. cRem = chwndReal % cRow;
  976. }
  977. chwndReal = 0;
  978. ihwnd = -1;
  979. for (iCol = 0; iCol < cCol; iCol++) {
  980. /*
  981. * Add one extra row to handle the remainders.
  982. */
  983. if (cCol - iCol <= cRem) {
  984. cRow++;
  985. }
  986. for (iRow = 0; iRow < cRow; iRow++) {
  987. HWND hwndChild;
  988. PWND pwndChild;
  989. DWORD dwSWPFlags;
  990. dx = xRes / cCol;
  991. dy = yRes / cRow;
  992. NextWindow:
  993. /*
  994. * Skip bogus and nonpositionable windows.
  995. */
  996. ihwnd++;
  997. if (ihwnd >= pawd->chwnd) {
  998. return TRUE;
  999. }
  1000. hwndChild = pawd->phwnd[ihwnd];
  1001. pwndChild = ValidatePositionableWindow(
  1002. hwndChild,
  1003. pawd->fVerifyParent ? pawd->pwndParent : NULL,
  1004. pawd->pwndDesktop,
  1005. pawd->flags,
  1006. pMonitor,
  1007. &dwSWPFlags);
  1008. if (!pwndChild) {
  1009. goto NextWindow;
  1010. }
  1011. /*
  1012. * Move, size the window.
  1013. */
  1014. pawd->hdwp = NtUserDeferWindowPos(pawd->hdwp,
  1015. hwndChild,
  1016. HWND_TOP,
  1017. rcParent.left + iCol*dx,
  1018. rcParent.top + iRow*dy,
  1019. dx,
  1020. dy,
  1021. dwSWPFlags);
  1022. if (pawd->hdwp == NULL) {
  1023. return FALSE;
  1024. }
  1025. chwndReal++;
  1026. pawd->chwndReal++;
  1027. }
  1028. if (cCol - iCol <= cRem) {
  1029. cRow--;
  1030. cRem--;
  1031. }
  1032. }
  1033. return TRUE;
  1034. }
  1035. /***************************************************************************\
  1036. *
  1037. * TileWindows()
  1038. *
  1039. * Tiles a list of children within a parent, according to the flags and
  1040. * the rectangle passed in.
  1041. *
  1042. \***************************************************************************/
  1043. WORD TileWindows(
  1044. HWND hwndParent,
  1045. UINT flags,
  1046. CONST RECT *lpRect,
  1047. UINT chwnd,
  1048. CONST HWND *ahwnd)
  1049. {
  1050. return ArrangeWindows(hwndParent, flags, lpRect, chwnd, ahwnd, TileWindowsEnum);
  1051. }
  1052. /***************************************************************************\
  1053. * xxxMDIActivate
  1054. *
  1055. * History:
  1056. * 11-14-90 MikeHar Ported from windows
  1057. * 4-16-91 MikeHar Win31 Merge
  1058. \***************************************************************************/
  1059. VOID xxxMDIActivate(
  1060. PWND pwnd,
  1061. PWND pwndActivate)
  1062. {
  1063. HWND hwndOld;
  1064. PWND pwndOld;
  1065. PMDI pmdi;
  1066. BOOL fShowActivate;
  1067. UINT nID;
  1068. TL tlpwnd;
  1069. TL tlpwndOld;
  1070. PWND pwndT;
  1071. HWND hwnd = HWq(pwnd);
  1072. HWND hwndActivate = HW(pwndActivate);
  1073. CheckLock(pwnd);
  1074. CheckLock(pwndActivate);
  1075. /*
  1076. * Get a pointer to the MDI structure
  1077. */
  1078. pmdi = ((PMDIWND)pwnd)->pmdi;
  1079. if (ACTIVE(pmdi) == hwndActivate)
  1080. return;
  1081. if ((pwndActivate != NULL) && (TestWF(pwndActivate, WFDISABLED))) {
  1082. /*
  1083. * Don't even try activating disabled or invisible windows.
  1084. */
  1085. return;
  1086. }
  1087. pwndT = REBASEPWND(pwnd, spwndParent);
  1088. fShowActivate = (HW(pwndT) ==
  1089. NtUserQueryWindow(hwnd, WindowActiveWindow));
  1090. hwndOld = ACTIVE(pmdi);
  1091. if (hwndOld && (pwndOld = ValidateHwnd(hwndOld)) == NULL) {
  1092. hwndOld = NULL;
  1093. }
  1094. ThreadLock(pwndOld, &tlpwndOld);
  1095. if (hwndOld) {
  1096. /*
  1097. * Attempt to deactivate the MDI child window.
  1098. * The MDI child window can fail deactivation by returning FALSE.
  1099. * But this only applies if the MDI frame is the active window
  1100. * and the app is a 3.1 app or later
  1101. */
  1102. if (!SendMessage(hwndOld, WM_NCACTIVATE, FALSE, 0L) && fShowActivate) {
  1103. if (TestWF(pwndOld, WFWIN31COMPAT))
  1104. goto UnlockOld;
  1105. }
  1106. if (!TestWF(pwndOld, WFWIN31COMPAT) && TestWF(pwndOld, WFFRAMEON)) {
  1107. /*
  1108. * Error: Quicken for Windows is sort of bogus. They try to fail
  1109. * the WM_NCACTIVATE of their newly created window by not passing
  1110. * it to DefWindowProc. Bug 6412. WM_NCACTIVATE sets/unsets the
  1111. * WFFRAMEON bit if passed to DWP so we can double check things
  1112. * here.
  1113. */
  1114. goto UnlockOld;
  1115. }
  1116. SendMessage(hwndOld, WM_MDIACTIVATE, (WPARAM)hwndOld, (LPARAM)hwndActivate);
  1117. /*
  1118. * Uncheck the old window menu entry.
  1119. */
  1120. if (WINDOW(pmdi))
  1121. CheckMenuItem(WINDOW(pmdi), PtrToUlong(pwndOld->spmenu),
  1122. MF_BYCOMMAND | MF_UNCHECKED);
  1123. }
  1124. //
  1125. // Handle switching to a new (or NO) maximized window. If NO window is
  1126. // to become maximized, because we're activating NULL or the window to
  1127. // become active doesn't have a WS_MAXIMIZEBOX, restore the old one to
  1128. // it's normal size to clean up the MDI maximized menubar mess
  1129. //
  1130. if (MAXED(pmdi) && MAXED(pmdi) != hwndActivate) {
  1131. HWND hwndMax;
  1132. int iShowCode;
  1133. // The MAXBOX check is a new thing for 4.0 dudes; it breaks 3.x apps.
  1134. // See comment in the WM_MDIMAXIMIZE handling.
  1135. if (pwndActivate && (TestWF(pwndActivate, WFMAXBOX) || !TestWF(pwndActivate, WFWIN40COMPAT))) {
  1136. hwndMax = hwndActivate;
  1137. iShowCode = SW_SHOWMAXIMIZED;
  1138. Lock(&ACTIVE(pmdi), hwndMax);
  1139. } else {
  1140. hwndMax = MAXED(pmdi);
  1141. iShowCode = SW_SHOWNORMAL;
  1142. }
  1143. // overload WFFULLSCREEN bit -- useless for child windows anyways
  1144. // use it to indicate to min/max code to not animate size change.
  1145. // NO -- no bit overloading. FritzS
  1146. NtUserCallHwndParam(hwndMax, WFNOANIMATE, SFI_SETWINDOWSTATE);
  1147. NtUserShowWindow(hwndMax, iShowCode);
  1148. NtUserCallHwndParam(hwndMax, WFNOANIMATE, SFI_CLEARWINDOWSTATE);
  1149. }
  1150. Lock(&ACTIVE(pmdi), hwndActivate);
  1151. /*
  1152. * We may be removing the activation entirely...
  1153. */
  1154. if (!pwndActivate) {
  1155. if (fShowActivate)
  1156. NtUserSetFocus(hwnd);
  1157. goto UnlockOld;
  1158. }
  1159. if (WINDOW(pmdi)) {
  1160. /*
  1161. * Check the new window menu entry.
  1162. */
  1163. nID = GetWindowID(ACTIVE(pmdi));
  1164. if (nID - FIRST(pmdi) < (MAXITEMS - 1)) {
  1165. CheckMenuItem(WINDOW(pmdi), nID, MF_BYCOMMAND | MFS_CHECKED);
  1166. } else {
  1167. /*
  1168. * the item is not in the menu at all! Swap it with number 9.
  1169. */
  1170. PWND pwndOther = FindPwndChild(pwnd, (UINT)(FIRST(pmdi) + MAXITEMS - 2));
  1171. SetWindowLongPtr(HW(pwndOther), GWLP_ID, PtrToLong(pwndActivate->spmenu));
  1172. SetWindowLongPtr(hwndActivate, GWLP_ID, FIRST(pmdi) + MAXITEMS - 2);
  1173. ModifyMenuItem(pwndActivate);
  1174. }
  1175. }
  1176. /*
  1177. * Bring the window to the top.
  1178. */
  1179. NtUserSetWindowPos(ACTIVE(pmdi), NULL, 0, 0, 0, 0,
  1180. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  1181. /*
  1182. * Update the Caption bar. Don't muck with styles for 3.1.
  1183. */
  1184. if (fShowActivate) {
  1185. SendMessage(ACTIVE(pmdi), WM_NCACTIVATE, TRUE, 0L);
  1186. ThreadLock(pwnd, &tlpwnd);
  1187. if (hwnd == NtUserQueryWindow(hwnd, WindowFocusWindow))
  1188. SendMessage(hwnd, WM_SETFOCUS, (WPARAM)hwnd, 0);
  1189. else
  1190. NtUserSetFocus(hwnd);
  1191. ThreadUnlock(&tlpwnd);
  1192. }
  1193. /*
  1194. * Notify the new active window of his activation.
  1195. */
  1196. SendMessage(ACTIVE(pmdi), WM_MDIACTIVATE, (WPARAM)hwndOld,
  1197. (LPARAM)hwndActivate);
  1198. UnlockOld:
  1199. ThreadUnlock(&tlpwndOld);
  1200. }
  1201. /***************************************************************************\
  1202. * xxxMDINext
  1203. *
  1204. * History:
  1205. * 11-14-90 MikeHar Ported from windows
  1206. * 4-16-91 MikeHar Win31 Merge
  1207. \***************************************************************************/
  1208. VOID xxxMDINext(
  1209. PWND pwndMDI,
  1210. PWND pwnd,
  1211. BOOL fPrevWindow)
  1212. {
  1213. PMDI pmdi;
  1214. PWND pwndNextGuy;
  1215. HDWP hdwp;
  1216. BOOL fHack = FALSE;
  1217. CheckLock(pwndMDI);
  1218. CheckLock(pwnd);
  1219. /*
  1220. * Get a pointer to the MDI structure
  1221. */
  1222. pmdi = ((PMDIWND)pwndMDI)->pmdi;
  1223. pwndNextGuy = pwnd;
  1224. while (TRUE) {
  1225. if (fPrevWindow)
  1226. pwndNextGuy = _GetWindow(pwndNextGuy, GW_HWNDPREV);
  1227. else
  1228. pwndNextGuy = REBASEPWND(pwndNextGuy, spwndNext);
  1229. if (!pwndNextGuy) {
  1230. if (fPrevWindow) {
  1231. pwndNextGuy = _GetWindow(pwnd, GW_HWNDLAST);
  1232. } else {
  1233. pwndNextGuy = REBASEPWND(pwndMDI, spwndChild);
  1234. }
  1235. }
  1236. if (pwndNextGuy == pwnd)
  1237. return;
  1238. //
  1239. // Ignore hidden and disabled windows.
  1240. //
  1241. if (TestWF(pwndNextGuy, WFVISIBLE) && !TestWF(pwndNextGuy, WFDISABLED))
  1242. break;
  1243. }
  1244. if (MAXED(pmdi)) {
  1245. NtUserSetVisible(HWq(pwndMDI), SV_UNSET | SV_CLRFTRUEVIS);
  1246. fHack = TRUE;
  1247. }
  1248. hdwp = NtUserBeginDeferWindowPos(2);
  1249. /*
  1250. * activate the new window (first, in case of maximized windows)
  1251. */
  1252. hdwp = NtUserDeferWindowPos(hdwp, HW(pwndNextGuy), HWND_TOP, 0, 0, 0, 0,
  1253. SWP_NOMOVE | SWP_NOSIZE);
  1254. // LATER 30-Mar-1992 mikeke
  1255. // this used to be _GetWindow(pwndMDI->spwndChild, GW_HWNDLAST)
  1256. // instead of HWND_BOTTOM
  1257. if (hdwp && !fPrevWindow && (pwnd != pwndNextGuy))
  1258. hdwp = NtUserDeferWindowPos(hdwp, HW(pwnd),
  1259. HWND_BOTTOM, 0, 0, 0, 0,
  1260. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE );
  1261. NtUserEndDeferWindowPosEx(hdwp, FALSE);
  1262. if (fHack) {
  1263. NtUserShowWindow(HWq(pwndMDI), SW_SHOW);
  1264. }
  1265. }
  1266. FUNCLOG10(LOG_GENERAL, HWND, DUMMYCALLINGTYPE, CreateMDIWindowA, LPCSTR, pClassName, LPCSTR, pWindowName, DWORD, dwStyle, int, x, int, y, int, nWidth, int, nHeight, HWND, hwndParent, HINSTANCE, hModule, LPARAM, lParam)
  1267. HWND
  1268. CreateMDIWindowA(
  1269. LPCSTR pClassName,
  1270. LPCSTR pWindowName,
  1271. DWORD dwStyle,
  1272. int x,
  1273. int y,
  1274. int nWidth,
  1275. int nHeight,
  1276. HWND hwndParent,
  1277. HINSTANCE hModule,
  1278. LPARAM lParam)
  1279. {
  1280. return CreateWindowExA(WS_EX_MDICHILD, pClassName, pWindowName,
  1281. dwStyle, x, y, nWidth, nHeight,
  1282. hwndParent, NULL, hModule, (LPVOID)lParam);
  1283. }
  1284. FUNCLOG10(LOG_GENERAL, HWND, DUMMYCALLINGTYPE, CreateMDIWindowW, LPCWSTR, pClassName, LPCWSTR, pWindowName, DWORD, dwStyle, int, x, int, y, int, nWidth, int, nHeight, HWND, hwndParent, HINSTANCE, hModule, LPARAM, lParam)
  1285. HWND
  1286. CreateMDIWindowW(
  1287. LPCWSTR pClassName,
  1288. LPCWSTR pWindowName,
  1289. DWORD dwStyle,
  1290. int x,
  1291. int y,
  1292. int nWidth,
  1293. int nHeight,
  1294. HWND hwndParent,
  1295. HINSTANCE hModule,
  1296. LPARAM lParam)
  1297. {
  1298. return CreateWindowExW(WS_EX_MDICHILD, pClassName, pWindowName,
  1299. dwStyle, x, y, nWidth, nHeight,
  1300. hwndParent, NULL, hModule, (LPVOID)lParam);
  1301. }
  1302. /***************************************************************************\
  1303. * xxxMDIDestroy
  1304. *
  1305. * History:
  1306. * 11-14-90 MikeHar Ported from windows
  1307. * 4-16-91 MikeHar Win31 Merge
  1308. \***************************************************************************/
  1309. VOID xxxMDIDestroy(
  1310. PWND pwnd,
  1311. HWND hwndVictim)
  1312. {
  1313. PWND pwndVictim;
  1314. TL tlpwndParent;
  1315. PMDI pmdi;
  1316. PWND pwndParent;
  1317. HWND hwnd;
  1318. CheckLock(pwnd);
  1319. if ((pwndVictim = ValidateHwnd(hwndVictim)) == NULL) {
  1320. return;
  1321. }
  1322. CheckLock(pwndVictim);
  1323. /*
  1324. * Get a pointer to the MDI structure
  1325. */
  1326. pmdi = ((PMDIWND)pwnd)->pmdi;
  1327. #ifdef NEVER
  1328. // don't do this validation - because it sometimes doesn't work! If an
  1329. // app passed in idFirstChild (through CLIENTCREATESTRUCT) as -1, this
  1330. // code fails because it treats the id comparisons as unsigned compares.
  1331. // Change them to signed compares and it still doesn't work. That is because
  1332. // when ShiftMenuIDs() is called, you'll shift mdi windows out of the signed
  1333. // comparison range and this check won't allow them to be destroyed. This
  1334. // is straight win3.1 code.
  1335. //
  1336. /*
  1337. * Validate that this is one of the mdi children we are keeping track
  1338. * of. If it isn't don't destroy it because it'll get mdi id tracking
  1339. * code all messed up.
  1340. */
  1341. if (((UINT)pwndVictim->spmenu) < FIRST(pmdi) ||
  1342. ((UINT)pwndVictim->spmenu) >= (UINT)(FIRST(pmdi) + CKIDS(pmdi)) ||
  1343. pwndVictim->spwndOwner != NULL) {
  1344. RIPERR0(ERROR_NON_MDICHILD_WINDOW, RIP_VERBOSE, "");
  1345. return;
  1346. }
  1347. #endif
  1348. ShiftMenuIDs(pwnd, pwndVictim);
  1349. /*
  1350. * First Activate another window.
  1351. */
  1352. if (SAMEWOWHANDLE(hwndVictim, ACTIVE(pmdi))) {
  1353. xxxMDINext(pwnd, pwndVictim, FALSE);
  1354. /*
  1355. * Destroying only child?
  1356. */
  1357. if (SAMEWOWHANDLE(hwndVictim, ACTIVE(pmdi))) {
  1358. NtUserShowWindow(hwndVictim, SW_HIDE);
  1359. /*
  1360. * If the window is maximized, we need to remove his sys menu
  1361. * now otherwise it may get deleted twice. Once when the child
  1362. * is destroyed and once when the frame is destroyed.
  1363. */
  1364. if (MAXED(pmdi)) {
  1365. pwndParent = REBASEPWND(pwnd, spwndParent);
  1366. MDIRemoveSysMenu(PtoH(REBASE(pwndParent,spmenu)), MAXED(pmdi));
  1367. Unlock(&MAXED(pmdi));
  1368. ThreadLock(pwndParent, &tlpwndParent);
  1369. xxxSetFrameTitle(pwndParent, pwnd, (LPWSTR)1L);
  1370. /*
  1371. * Redraw frame so menu bar shows the removed sys menu stuff
  1372. */
  1373. if (TestWF(pwndParent, WFVISIBLE))
  1374. NtUserRedrawFrame(HWq(pwndParent));
  1375. ThreadUnlock(&tlpwndParent);
  1376. }
  1377. xxxMDIActivate(pwnd, NULL);
  1378. }
  1379. }
  1380. /*
  1381. * Don't ever let this go negative or we'll get caught in long loops.
  1382. */
  1383. CKIDS(pmdi)--;
  1384. if ((int)CKIDS(pmdi) < 0)
  1385. CKIDS(pmdi) = 0;
  1386. hwnd = HWq(pwnd);
  1387. SendMessage(hwnd, WM_MDIREFRESHMENU, 0L, 0L);
  1388. /*
  1389. * Destroy the window.
  1390. */
  1391. NtUserDestroyWindow(hwndVictim);
  1392. /*
  1393. * During the DestroyWindow the parent may also have been deleted
  1394. * Remove revalidate if we get client side locking
  1395. */
  1396. if (ValidateHwnd(hwnd) == NULL)
  1397. return;
  1398. /*
  1399. * Deleting a window can change the scroll ranges.
  1400. */
  1401. RecalculateScrollRanges(pwnd, FALSE);
  1402. }
  1403. /***************************************************************************\
  1404. * MDIClientWndProc
  1405. *
  1406. * History:
  1407. * 11-14-90 MikeHar Ported from windows
  1408. \***************************************************************************/
  1409. LRESULT MDIClientWndProcWorker(
  1410. PWND pwnd,
  1411. UINT message,
  1412. WPARAM wParam,
  1413. LPARAM lParam,
  1414. DWORD fAnsi)
  1415. {
  1416. HWND hwnd = HWq(pwnd);
  1417. HWND hwndT;
  1418. PWND pwndT;
  1419. TL tlpwndT;
  1420. PMDI pmdi;
  1421. PWND pwndParent;
  1422. CheckLock(pwnd);
  1423. VALIDATECLASSANDSIZE(pwnd, FNID_MDICLIENT);
  1424. /*
  1425. * Get the pmdi for the given window now since we will use it a lot in
  1426. * various handlers. This was stored using SetWindowLong(hwnd,4,pmdi) when
  1427. * we initially created the MDI client window.
  1428. */
  1429. pmdi = ((PMDIWND)pwnd)->pmdi;
  1430. if (pmdi == NULL) {
  1431. switch (message) {
  1432. case WM_MDICREATE:
  1433. case WM_MDIMAXIMIZE:
  1434. case WM_PARENTNOTIFY:
  1435. case WM_CREATE:
  1436. /*
  1437. * These messages are safe to call, even when pmdi has not already
  1438. * been initialized.
  1439. */
  1440. break;
  1441. default:
  1442. /*
  1443. * Any message that is not listed above is not safe to call when
  1444. * pmdi has not been initialized. Instead, just directly call DWP.
  1445. */
  1446. goto CallDWP;
  1447. }
  1448. }
  1449. switch (message) {
  1450. case WM_NCACTIVATE:
  1451. /*
  1452. * We are changing app activation. Fix the active child's caption.
  1453. */
  1454. if (ACTIVE(pmdi) != NULL) {
  1455. SendMessage(ACTIVE(pmdi), WM_NCACTIVATE, wParam, lParam);
  1456. }
  1457. goto CallDWP;
  1458. case WM_MDIGETACTIVE:
  1459. if (lParam != 0) {
  1460. *((LPBOOL)lParam) = (MAXED(pmdi) != NULL);
  1461. }
  1462. return (LRESULT)ACTIVE(pmdi);
  1463. case WM_MDIACTIVATE:
  1464. hwndT = (HWND)wParam;
  1465. if ((pwndT = ValidateHwnd(hwndT)) == NULL)
  1466. return 0;
  1467. if (SAMEWOWHANDLE(hwndT, ACTIVE(pmdi)))
  1468. break;
  1469. NtUserSetWindowPos(hwndT, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
  1470. break;
  1471. case WM_MDICASCADE:
  1472. pmdi->wScroll |= SCROLLSUPPRESS;
  1473. NtUserShowScrollBar(hwnd, SB_BOTH, FALSE);
  1474. /*
  1475. * Unmaximize any maximized window.
  1476. */
  1477. #ifdef NEVER // Not in Chicago -- FritzS
  1478. if (MAXED(pmdi) != NULL) {
  1479. NtUserShowWindow(MAXED(pmdi), SW_SHOWNORMAL);
  1480. }
  1481. #endif
  1482. /*
  1483. * Save success/failure code to return to app
  1484. */
  1485. message = (UINT)CascadeWindows(hwnd, (UINT)wParam, NULL, 0, NULL);
  1486. pmdi->wScroll &= ~SCROLLCOUNT;
  1487. return (LONG)message;
  1488. break;
  1489. case WM_VSCROLL:
  1490. case WM_HSCROLL:
  1491. pmdi->wScroll |= SCROLLSUPPRESS;
  1492. ScrollMDIChildren(hwnd, (message == WM_VSCROLL) ? SB_VERT : SB_HORZ,
  1493. LOWORD(wParam), (short)(HIWORD(wParam)));
  1494. pmdi->wScroll &= ~SCROLLCOUNT;
  1495. break;
  1496. case WM_MDICREATE:
  1497. {
  1498. LPMDICREATESTRUCTA lpMCSA = (LPMDICREATESTRUCTA)lParam;
  1499. LPMDICREATESTRUCTW lpMCSW = (LPMDICREATESTRUCTW)lParam;
  1500. DWORD exStyle = WS_EX_MDICHILD;
  1501. /*
  1502. * inherit the right.to.leftness of the parent.
  1503. */
  1504. exStyle |= (pwnd->ExStyle & (WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR));
  1505. if (fAnsi) {
  1506. hwndT = CreateWindowExA(exStyle, lpMCSA->szClass, lpMCSA->szTitle,
  1507. lpMCSA->style, lpMCSA->x, lpMCSA->y, lpMCSA->cx, lpMCSA->cy,
  1508. hwnd, NULL, lpMCSA->hOwner, (LPSTR)lpMCSA->lParam);
  1509. } else {
  1510. hwndT = CreateWindowExW(exStyle, lpMCSW->szClass, lpMCSW->szTitle,
  1511. lpMCSW->style, lpMCSW->x, lpMCSW->y, lpMCSW->cx, lpMCSW->cy,
  1512. hwnd, NULL, lpMCSW->hOwner, (LPWSTR)lpMCSW->lParam);
  1513. }
  1514. return((LRESULT)hwndT);
  1515. }
  1516. case WM_MDIDESTROY:
  1517. xxxMDIDestroy(pwnd, (HWND)wParam);
  1518. break;
  1519. case WM_MDIMAXIMIZE:
  1520. hwndT = (HWND)wParam;
  1521. if ((pwndT = ValidateHwnd(hwndT)) == NULL)
  1522. return 0;
  1523. // Only maximize children with a MAXBOX. However, this introduces
  1524. // backwards-compatibility issues with VB apps (see#12211)
  1525. // So, we do this only for WIN40COMPAT apps and beyond.
  1526. //
  1527. if ((TestWF(pwndT, WFMAXBOX)) || !(TestWF(pwndT, WFWIN40COMPAT))) {
  1528. NtUserShowWindow(hwndT, SW_SHOWMAXIMIZED);
  1529. }
  1530. break;
  1531. case WM_MDIRESTORE:
  1532. hwndT = (HWND)wParam;
  1533. if ((pwndT = ValidateHwnd(hwndT)) == NULL)
  1534. return 0;
  1535. NtUserShowWindow(hwndT, SW_SHOWNORMAL);
  1536. break;
  1537. case WM_MDITILE:
  1538. pmdi->wScroll |= SCROLLSUPPRESS;
  1539. NtUserShowScrollBar(hwnd, SB_BOTH, FALSE);
  1540. /*
  1541. * Unmaximize any maximized window.
  1542. */
  1543. #ifdef NEVER //Not in Chicago
  1544. if (MAXED(pmdi) != NULL) {
  1545. NtUserShowWindow(MAXED(pmdi), SW_SHOWNORMAL);
  1546. }
  1547. #endif
  1548. /*
  1549. * Save success/failure code to return to app
  1550. */
  1551. message = (UINT)TileWindows(hwnd, (UINT)wParam, NULL, 0, NULL);
  1552. pmdi->wScroll &= ~SCROLLCOUNT;
  1553. return (LONG)message;
  1554. break;
  1555. case WM_MDIICONARRANGE:
  1556. pmdi->wScroll |= SCROLLSUPPRESS;
  1557. NtUserArrangeIconicWindows(hwnd);
  1558. pmdi->wScroll &= ~SCROLLCOUNT;
  1559. RecalculateScrollRanges(pwnd, TRUE);
  1560. break;
  1561. case WM_MDINEXT:
  1562. if (wParam) {
  1563. hwndT = (HWND)wParam;
  1564. } else {
  1565. hwndT = ACTIVE(pmdi);
  1566. }
  1567. if ((pwndT = ValidateHwnd(hwndT)) == NULL) {
  1568. return 0;
  1569. }
  1570. /*
  1571. * If lParam is 1, do a prev window instead of a next window
  1572. */
  1573. ThreadLockAlways(pwndT, &tlpwndT);
  1574. xxxMDINext(pwnd, pwndT, (lParam == 0 ? 0 : 1));
  1575. ThreadUnlock(&tlpwndT);
  1576. break;
  1577. case WM_MDIREFRESHMENU:
  1578. return (LRESULT)MDISetMenu(pwnd, TRUE, NULL, NULL);
  1579. case WM_MDISETMENU:
  1580. return (LRESULT)MDISetMenu(pwnd, FALSE, (HMENU)wParam, (HMENU)lParam);
  1581. case WM_PARENTNOTIFY:
  1582. if (wParam == WM_LBUTTONDOWN) {
  1583. HWND hwndChild;
  1584. POINT pt;
  1585. if ((pwndT = ValidateHwnd(hwnd)) == NULL) {
  1586. return 0;
  1587. }
  1588. /*
  1589. * Activate this child and bring it to the top.
  1590. */
  1591. pt.x = (int)MAKEPOINTS(lParam).x;
  1592. pt.y = (int)MAKEPOINTS(lParam).y;
  1593. /*
  1594. * Since pt is relative to the client MDI window,
  1595. * then the points should be mirrored if the MDI
  1596. * client window is mirrored so that Scrren Coord
  1597. * calculations are done properly in NtUserChildWindowFromPointEx.
  1598. * [samera]
  1599. */
  1600. if (TestWF(pwndT, WEFLAYOUTRTL)) {
  1601. pt.x = (pwndT->rcClient.right-pwndT->rcClient.left)-pt.x;
  1602. }
  1603. hwndChild = NtUserChildWindowFromPointEx(hwnd, pt,
  1604. CWP_SKIPDISABLED | CWP_SKIPINVISIBLE);
  1605. if ((hwndChild) && (hwndChild != hwnd)) {
  1606. if (hwndChild != ACTIVE(pmdi)) {
  1607. NtUserSetWindowPos(hwndChild, HWND_TOP, 0, 0, 0, 0,
  1608. SWP_NOMOVE | SWP_NOSIZE);
  1609. }
  1610. }
  1611. }
  1612. break;
  1613. case WM_SETFOCUS:
  1614. if (ACTIVE(pmdi) != NULL && !IsIconic(ACTIVE(pmdi))) {
  1615. NtUserSetFocus(ACTIVE(pmdi));
  1616. }
  1617. break;
  1618. case WM_SIZE:
  1619. if (ACTIVE(pmdi) && (pwndT = ValidateHwnd(ACTIVE(pmdi))) &&
  1620. TestWF(pwndT, WFMAXIMIZED)) {
  1621. RECT rc;
  1622. rc.top = rc.left = 0;
  1623. rc.right = (int)MAKEPOINTS(lParam).x;
  1624. rc.bottom = (int)MAKEPOINTS(lParam).y;
  1625. RealAdjustWindowRectEx(&rc, pwndT->style, FALSE,
  1626. pwndT->ExStyle);
  1627. NtUserMoveWindow(ACTIVE(pmdi), rc.left, rc.top,
  1628. rc.right - rc.left, rc.bottom - rc.top, TRUE);
  1629. } else {
  1630. RecalculateScrollRanges(pwnd, FALSE);
  1631. }
  1632. goto CallDWP;
  1633. case MM_CALCSCROLL: {
  1634. if (SCROLL(pmdi) & SCROLLCOUNT)
  1635. break;
  1636. {
  1637. WORD sbj = pmdi->wScroll & (HAS_SBVERT | HAS_SBHORZ);
  1638. if (sbj)
  1639. {
  1640. CalcClientScrolling(hwnd, sbj, (BOOL) wParam);
  1641. SCROLL(pmdi) &= ~CALCSCROLL;
  1642. }
  1643. }
  1644. break;
  1645. }
  1646. case WM_CREATE: {
  1647. LPCLIENTCREATESTRUCT pccs = ((LPCREATESTRUCT)lParam)->lpCreateParams;
  1648. /*
  1649. * Try to allocate space for the pmdi
  1650. */
  1651. if ((pmdi = (PMDI)UserLocalAlloc(HEAP_ZERO_MEMORY, sizeof(MDI)))) {
  1652. NtUserSetWindowLongPtr(hwnd, GWLP_MDIDATA, (LONG_PTR)pmdi, FALSE);
  1653. } else {
  1654. NtUserSetWindowFNID(hwnd, FNID_CLEANEDUP_BIT);
  1655. break;
  1656. }
  1657. pwndParent = REBASEPWND(pwnd, spwndParent);
  1658. ACTIVE(pmdi) = NULL;
  1659. MAXED(pmdi) = NULL;
  1660. CKIDS(pmdi) = 0;
  1661. WINDOW(pmdi) = pccs->hWindowMenu;
  1662. FIRST(pmdi) = pccs->idFirstChild;
  1663. SCROLL(pmdi) = 0;
  1664. HTITLE(pmdi) = TextAlloc(REBASE(pwndParent, strName.Buffer));
  1665. _DefSetText(HW(pwndParent), NULL, FALSE);
  1666. ThreadLock(pwndParent, &tlpwndT);
  1667. xxxSetFrameTitle(pwndParent, pwnd, (LPWSTR)2L);
  1668. ThreadUnlock(&tlpwndT);
  1669. if (TestWF(pwnd, WFVSCROLL))
  1670. SCROLL(pmdi) |= HAS_SBVERT;
  1671. if (TestWF(pwnd, WFHSCROLL))
  1672. SCROLL(pmdi) |= HAS_SBHORZ;
  1673. if (SCROLL(pmdi)) {
  1674. ClearWindowState(pwnd, WFVSCROLL | WFHSCROLL);
  1675. }
  1676. /*
  1677. * Set this dude's system menu.
  1678. */
  1679. NtUserGetSystemMenu(HW(pwndParent), FALSE);
  1680. /*
  1681. * make sure we have the correct window client area if scrolls are
  1682. * removed... hack to take care of small progman bug
  1683. */
  1684. if (SCROLL(pmdi)) {
  1685. NtUserUpdateClientRect(hwnd);
  1686. }
  1687. break;
  1688. }
  1689. case WM_DESTROY:
  1690. case WM_FINALDESTROY:
  1691. if (MAXED(pmdi)) {
  1692. PWND pwndParent;
  1693. PMENU pmenu;
  1694. pwndParent = REBASEPWND(pwnd, spwndParent);
  1695. pmenu = REBASE(pwndParent, spmenu);
  1696. MDIRemoveSysMenu(PtoH(pmenu), MAXED(pmdi));
  1697. }
  1698. /*
  1699. * delete the title
  1700. */
  1701. if (HTITLE(pmdi)) {
  1702. UserLocalFree(HTITLE(pmdi));
  1703. HTITLE(pmdi) = NULL;
  1704. }
  1705. /*
  1706. * Delete the menu items of the child windows in the frame.
  1707. * Chances are, this is called by destroying the frame, but
  1708. * one never knows, does one?
  1709. *
  1710. * Increase CKIDS by 1 after checking to delete the separator
  1711. */
  1712. if (IsMenu(WINDOW(pmdi)) && CKIDS(pmdi)++) {
  1713. UINT iPosition;
  1714. if (CKIDS(pmdi) > MAXITEMS + 1)
  1715. CKIDS(pmdi) = MAXITEMS + 1;
  1716. iPosition = GetMenuItemCount(WINDOW(pmdi));
  1717. while (CKIDS(pmdi)--) {
  1718. NtUserDeleteMenu(WINDOW(pmdi), --iPosition, MF_BYPOSITION);
  1719. }
  1720. }
  1721. /*
  1722. * Unlock those objects that are used by the MDI structure.
  1723. */
  1724. Unlock(&MAXED(pmdi));
  1725. Unlock(&ACTIVE(pmdi));
  1726. Unlock(&WINDOW(pmdi));
  1727. /*
  1728. * Free the MDI structure
  1729. */
  1730. UserLocalFree(pmdi);
  1731. NtUserSetWindowFNID(hwnd, FNID_CLEANEDUP_BIT);
  1732. break;
  1733. default:
  1734. CallDWP:
  1735. return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi);
  1736. }
  1737. return 0L;
  1738. }
  1739. /***************************************************************************\
  1740. *
  1741. \***************************************************************************/
  1742. LRESULT WINAPI MDIClientWndProcA(
  1743. HWND hwnd,
  1744. UINT message,
  1745. WPARAM wParam,
  1746. LPARAM lParam)
  1747. {
  1748. PWND pwnd;
  1749. if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
  1750. return 0;
  1751. }
  1752. return MDIClientWndProcWorker(pwnd, message, wParam, lParam, TRUE);
  1753. }
  1754. LRESULT WINAPI MDIClientWndProcW(
  1755. HWND hwnd,
  1756. UINT message,
  1757. WPARAM wParam,
  1758. LPARAM lParam)
  1759. {
  1760. PWND pwnd;
  1761. if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
  1762. return 0;
  1763. }
  1764. return MDIClientWndProcWorker(pwnd, message, wParam, lParam, FALSE);
  1765. }
  1766. /***************************************************************************\
  1767. * DefFrameProc
  1768. *
  1769. * History:
  1770. * 11-14-90 MikeHar Ported from windows
  1771. \***************************************************************************/
  1772. LRESULT DefFrameProcWorker(
  1773. HWND hwnd,
  1774. HWND hwndMDI,
  1775. UINT wMsg,
  1776. WPARAM wParam,
  1777. LPARAM lParam,
  1778. BOOL fAnsi)
  1779. {
  1780. PWND pwnd;
  1781. PWND pwndMDI;
  1782. PMDI pmdi;
  1783. TL tlpwndT;
  1784. HWND hwndT;
  1785. PWND pwndT;
  1786. PMDINEXTMENU pmnm;
  1787. WINDOWPLACEMENT wp;
  1788. if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
  1789. return (0L);
  1790. }
  1791. CheckLock(pwnd);
  1792. if (hwndMDI == NULL) {
  1793. goto CallDWP;
  1794. }
  1795. if ((pwndMDI = ValidateHwnd(hwndMDI)) == NULL) {
  1796. return (0L);
  1797. }
  1798. CheckLock(pwndMDI);
  1799. /*
  1800. * Get a pointer to the MDI structure
  1801. */
  1802. pmdi = ((PMDIWND)pwndMDI)->pmdi;
  1803. switch (wMsg) {
  1804. /*
  1805. * If there is a maximized child window, add it's window text...
  1806. */
  1807. case WM_SETTEXT: {
  1808. LPWSTR lpwsz = NULL;
  1809. if (fAnsi && lParam) {
  1810. if (!MBToWCS((LPSTR)lParam, -1, &lpwsz, -1, TRUE))
  1811. return 0;
  1812. lParam = (LPARAM)lpwsz;
  1813. }
  1814. xxxSetFrameTitle(pwnd, pwndMDI, (LPWSTR)lParam);
  1815. if (lpwsz) {
  1816. UserLocalFree(lpwsz);
  1817. }
  1818. break;
  1819. }
  1820. case WM_NCACTIVATE:
  1821. SendMessage(hwndMDI, WM_NCACTIVATE, wParam, lParam);
  1822. goto CallDWP;
  1823. case WM_COMMAND:
  1824. if ((UINT)LOWORD(wParam) == (FIRST(pmdi) + MAXITEMS -1)) {
  1825. /*
  1826. * selected the More... item
  1827. */
  1828. if (fAnsi) {
  1829. wParam = DialogBoxParamA(hmodUser,
  1830. MAKEINTRESOURCEA(IDD_MDI_ACTIVATE),
  1831. hwnd,
  1832. MDIActivateDlgProcA,
  1833. (LPARAM)pwndMDI);
  1834. } else {
  1835. wParam = DialogBoxParamW(hmodUser,
  1836. MAKEINTRESOURCEW(IDD_MDI_ACTIVATE),
  1837. hwnd,
  1838. MDIActivateDlgProcW,
  1839. (LPARAM)pwndMDI);
  1840. }
  1841. if ((int)wParam >= 0) {
  1842. wParam += FIRST(pmdi);
  1843. goto ActivateTheChild;
  1844. }
  1845. } else if (((UINT)LOWORD(wParam) >= FIRST(pmdi)) &&
  1846. ((UINT)LOWORD(wParam) < FIRST(pmdi) + CKIDS(pmdi))) {
  1847. ActivateTheChild:
  1848. pwndT = FindPwndChild(pwndMDI, (UINT)LOWORD(wParam));
  1849. ThreadLock(pwndT, &tlpwndT);
  1850. SendMessage(hwndMDI, WM_MDIACTIVATE, (WPARAM)HW(pwndT), 0L);
  1851. /*
  1852. * if minimized, restore it.
  1853. */
  1854. if (pwndT != NULL && TestWF(pwndT, WFMINIMIZED))
  1855. //
  1856. // Fix for B#1510. Don't restore directly. Send child
  1857. // a restore message.
  1858. //
  1859. SendMessage(HWq(pwndT), WM_SYSCOMMAND, (WPARAM)SC_RESTORE, 0L);
  1860. ThreadUnlock(&tlpwndT);
  1861. break;
  1862. }
  1863. switch (wParam & 0xFFF0) {
  1864. /*
  1865. * System menu commands on a maxed mdi child
  1866. */
  1867. case SC_SIZE:
  1868. case SC_MOVE:
  1869. case SC_RESTORE:
  1870. case SC_CLOSE:
  1871. case SC_NEXTWINDOW:
  1872. case SC_PREVWINDOW:
  1873. case SC_MINIMIZE:
  1874. case SC_MAXIMIZE:
  1875. hwndT = MAXED(pmdi);
  1876. if (hwndT != NULL) {
  1877. PWND pwndT = ValidateHwnd(hwndT);
  1878. if (pwndT == NULL)
  1879. break;
  1880. if ((wParam & 0xFFF0) == SC_CLOSE) {
  1881. /*
  1882. * Since the window is maxed, we've cleared WFSYSMENU (see
  1883. * MDIAddSysMenu). We need to set it back here so GetSysMenuHandle
  1884. * will do the right thing for _MNCanClose.
  1885. */
  1886. BOOL fCanClose;
  1887. UserAssert(!TestWF(pwndT, WFSYSMENU) && (pwndT->spmenuSys != NULL));
  1888. SetWindowState(pwndT, WFSYSMENU);
  1889. fCanClose = xxxMNCanClose(pwndT);
  1890. ClearWindowState(pwndT, WFSYSMENU);
  1891. if (!fCanClose) {
  1892. break;
  1893. }
  1894. } else if (((wParam & 0xFFF0) == SC_MINIMIZE) && !TestWF(pwndT, WFMINBOX)) {
  1895. break;
  1896. }
  1897. return SendMessage(hwndT, WM_SYSCOMMAND, wParam, lParam);
  1898. }
  1899. }
  1900. goto CallDWP;
  1901. case WM_SIZE:
  1902. if (wParam != SIZEICONIC) {
  1903. NtUserMoveWindow(hwndMDI, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
  1904. } else {
  1905. wp.length = sizeof(WINDOWPLACEMENT);
  1906. if (GetWindowPlacement(hwnd, &wp)) {
  1907. RECT rcT;
  1908. int clB;
  1909. /*
  1910. * If frame is iconic, size mdi win to be size of restored
  1911. * frame's client area. Thus mdi children etc created in here
  1912. * use the proper mdiclient size.
  1913. */
  1914. clB = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, TRUE);
  1915. CopyInflateRect(&rcT, &wp.rcNormalPosition,
  1916. -clB*SYSMET(CXBORDER), -clB*SYSMET(CYBORDER));
  1917. if (TestWF(pwnd, WFBORDERMASK) == LOBYTE(WFCAPTION))
  1918. rcT.top += SYSMET(CYCAPTION);
  1919. rcT.top += SYSMET(CYMENU);
  1920. NtUserMoveWindow(hwndMDI, 0, 0, rcT.right-rcT.left,
  1921. rcT.bottom-rcT.top, TRUE);
  1922. }
  1923. }
  1924. goto CallDWP;
  1925. case WM_SETFOCUS:
  1926. NtUserSetFocus(hwndMDI);
  1927. break;
  1928. case WM_NEXTMENU:
  1929. if (TestWF(pwnd, WFSYSMENU) && !TestWF(pwnd, WFMINIMIZED) &&
  1930. ACTIVE(pmdi) && !MAXED(pmdi))
  1931. {
  1932. PMENU pmenuIn;
  1933. /*
  1934. * Go to child system menu by wrapping to the left from
  1935. * the first popup in the menu bar or to the right from
  1936. * the frame sysmenu.
  1937. */
  1938. pmnm = (PMDINEXTMENU)lParam;
  1939. pmenuIn = RevalidateHmenu(pmnm->hmenuIn);
  1940. if (pmenuIn && ((wParam == VK_LEFT && pmenuIn == REBASE(pwnd, spmenu)) ||
  1941. (wParam == VK_RIGHT && pmnm->hmenuIn ==
  1942. NtUserGetSystemMenu(hwnd, FALSE)))) {
  1943. HMENU hmenu;
  1944. PWND pwndActive;
  1945. //
  1946. // Make sure the window is still valid
  1947. //
  1948. if ((pwndActive = ValidateHwnd(ACTIVE(pmdi))) == NULL) {
  1949. return 0;
  1950. }
  1951. //
  1952. // Make sure the child's system menu items are updated
  1953. // (i.e. the ones are enabled/disabled)
  1954. //
  1955. if (!TestWF(pwndActive,WFMAXIMIZED)) {
  1956. NtUserSetSysMenu(ACTIVE(pmdi));
  1957. }
  1958. hmenu = NtUserGetSystemMenu(ACTIVE(pmdi), FALSE);
  1959. pmnm->hmenuNext = hmenu;
  1960. pmnm->hwndNext = ACTIVE(pmdi);
  1961. return TRUE;
  1962. }
  1963. }
  1964. /*
  1965. * default behaviour
  1966. */
  1967. return 0L;
  1968. case WM_MENUCHAR:
  1969. if (!TestWF(pwnd, WFMINIMIZED) && LOWORD(wParam) == TEXT('-')) {
  1970. if (MAXED(pmdi))
  1971. return MAKELONG(0, 2);
  1972. else if (ACTIVE(pmdi)) {
  1973. PostMessage(ACTIVE(pmdi), WM_SYSCOMMAND,
  1974. SC_KEYMENU, MAKELONG(TEXT('-'), 0));
  1975. return MAKELONG(0, 1);
  1976. }
  1977. }
  1978. /*
  1979. ** FALL THRU **
  1980. */
  1981. default:
  1982. CallDWP:
  1983. return DefWindowProcWorker(pwnd, wMsg, wParam, lParam, fAnsi);
  1984. }
  1985. return 0L;
  1986. }
  1987. FUNCLOG5(LOG_GENERAL, LRESULT, WINAPI, DefFrameProcW, HWND, hwnd, HWND, hwndMDIClient, UINT, message, WPARAM, wParam, LPARAM, lParam)
  1988. LRESULT WINAPI DefFrameProcW(
  1989. HWND hwnd,
  1990. HWND hwndMDIClient,
  1991. UINT message,
  1992. WPARAM wParam,
  1993. LPARAM lParam)
  1994. {
  1995. return DefFrameProcWorker(hwnd, hwndMDIClient, message, wParam, lParam,
  1996. FALSE);
  1997. }
  1998. FUNCLOG5(LOG_GENERAL, LRESULT, WINAPI, DefFrameProcA, HWND, hwnd, HWND, hwndMDIClient, UINT, message, WPARAM, wParam, LPARAM, lParam)
  1999. LRESULT WINAPI DefFrameProcA(
  2000. HWND hwnd,
  2001. HWND hwndMDIClient,
  2002. UINT message,
  2003. WPARAM wParam,
  2004. LPARAM lParam)
  2005. {
  2006. return DefFrameProcWorker(hwnd, hwndMDIClient, message, wParam,
  2007. lParam, TRUE);
  2008. }
  2009. /***************************************************************************\
  2010. * ChildMinMaxInfo
  2011. *
  2012. * History:
  2013. * 11-14-90 MikeHar Ported from windows
  2014. \***************************************************************************/
  2015. VOID ChildMinMaxInfo(
  2016. PWND pwnd,
  2017. PMINMAXINFO pmmi)
  2018. {
  2019. PWND pwndParent = REBASEPWND(pwnd, spwndParent);
  2020. RECT rc;
  2021. UserAssert(GETFNID(pwnd) != FNID_DESKTOP);
  2022. CopyRect(&rc, KPRECT_TO_PRECT(&pwndParent->rcClient));
  2023. _ScreenToClient(pwndParent, (LPPOINT)&rc.left);
  2024. _ScreenToClient(pwndParent, (LPPOINT)&rc.right);
  2025. /*
  2026. * Swap the left and right if pwnd is a mirrored window.
  2027. */
  2028. if (TestWF(pwnd, WEFLAYOUTRTL)) {
  2029. int nSaveLeft;
  2030. nSaveLeft = rc.left;
  2031. rc.left = rc.right;
  2032. rc.right = nSaveLeft;
  2033. }
  2034. RealAdjustWindowRectEx(&rc, pwnd->style, FALSE, pwnd->ExStyle);
  2035. /*
  2036. * Position...
  2037. */
  2038. pmmi->ptMaxPosition.x = rc.left;
  2039. pmmi->ptMaxPosition.y = rc.top;
  2040. pmmi->ptMaxSize.x = rc.right - rc.left;
  2041. pmmi->ptMaxSize.y = rc.bottom - rc.top;
  2042. }
  2043. /***************************************************************************\
  2044. * xxxChildResize
  2045. *
  2046. * History:
  2047. * 11-14-90 MikeHar Ported from windows
  2048. \***************************************************************************/
  2049. VOID xxxChildResize(
  2050. PWND pwnd,
  2051. UINT wMode)
  2052. {
  2053. PWND pwndT;
  2054. PWND pwndMDI = REBASEPWND(pwnd, spwndParent);
  2055. PWND pwndFrame = REBASEPWND(pwndMDI, spwndParent);
  2056. HWND hwndOldActive;
  2057. PMDI pmdi;
  2058. HWND hwndActive;
  2059. TL tlpwndMDI;
  2060. TL tlpwndFrame;
  2061. TL tlpwndT;
  2062. PMENU pmenu;
  2063. HWND hwnd = HWq(pwnd);
  2064. CheckLock(pwnd);
  2065. NtUserSetSysMenu(hwnd);
  2066. ThreadLock(pwndMDI, &tlpwndMDI);
  2067. ThreadLock(pwndFrame, &tlpwndFrame);
  2068. /*
  2069. * Get a pointer to the MDI structure
  2070. */
  2071. pmdi = ((PMDIWND)pwndMDI)->pmdi;
  2072. pmenu = REBASE(pwndFrame, spmenu);
  2073. if (MAXED(pmdi) == hwnd && wMode != SIZEFULLSCREEN) {
  2074. /*
  2075. * Restoring the current maximized window...
  2076. * Remove the system menu from the Frame window.
  2077. */
  2078. if (!(SCROLL(pmdi) & OTHERMAXING)) {
  2079. Unlock(&MAXED(pmdi));
  2080. MDIRemoveSysMenu(PtoH(pmenu), hwnd);
  2081. Unlock(&MAXED(pmdi));
  2082. xxxSetFrameTitle(pwndFrame, pwndMDI, (LPWSTR)1L);
  2083. }
  2084. }
  2085. if (wMode == SIZEFULLSCREEN) {
  2086. /*
  2087. * Already maximized?
  2088. */
  2089. if (hwnd == MAXED(pmdi))
  2090. goto Exit;
  2091. /*
  2092. * Maximizing this window...
  2093. */
  2094. pmdi->wScroll |= OTHERMAXING | SCROLLCOUNT;
  2095. if (hwndOldActive = MAXED(pmdi)) {
  2096. SendMessage(hwndOldActive, WM_SETREDRAW, FALSE, 0L);
  2097. MDIRemoveSysMenu(PtoH(pmenu), hwndOldActive);
  2098. NtUserMinMaximize(hwndOldActive, SW_MDIRESTORE, FALSE);
  2099. SendMessage(hwndOldActive, WM_SETREDRAW, TRUE, 0L);
  2100. }
  2101. Lock(&MAXED(pmdi), hwnd);
  2102. /*
  2103. * Add the system menu to the Frame window.
  2104. */
  2105. MDIAddSysMenu(PtoH(pmenu), hwnd);
  2106. xxxSetFrameTitle(pwndFrame, pwndMDI, (LPWSTR)1L);
  2107. pmdi->wScroll &= ~(OTHERMAXING | SCROLLCOUNT);
  2108. }
  2109. if (wMode == SIZEICONIC) {
  2110. for (pwndT = REBASEPWND(pwndMDI, spwndChild); pwndT;
  2111. pwndT = REBASEPWND(pwndT, spwndNext)) {
  2112. if (!pwndT->spwndOwner && TestWF(pwndT, WFVISIBLE))
  2113. break;
  2114. }
  2115. hwndActive = NtUserQueryWindow(hwnd, WindowActiveWindow);
  2116. if ((pwndT != NULL) && (hwndActive != NULL) &&
  2117. IsChild(hwndActive, HWq(pwndMDI))) {
  2118. ThreadLockAlways(pwndT, &tlpwndT);
  2119. SendMessage(HWq(pwndT), WM_CHILDACTIVATE, 0, 0L);
  2120. ThreadUnlock(&tlpwndT);
  2121. }
  2122. }
  2123. if (!(SCROLL(pmdi) & SCROLLCOUNT))
  2124. RecalculateScrollRanges(pwndMDI, FALSE);
  2125. Exit:
  2126. ThreadUnlock(&tlpwndFrame);
  2127. ThreadUnlock(&tlpwndMDI);
  2128. }
  2129. /***************************************************************************\
  2130. * DefMDIChildProc
  2131. *
  2132. * History:
  2133. * 11-14-90 MikeHar Ported from windows
  2134. \***************************************************************************/
  2135. LRESULT DefMDIChildProcWorker(
  2136. HWND hwnd,
  2137. UINT wMsg,
  2138. WPARAM wParam,
  2139. LPARAM lParam,
  2140. BOOL fAnsi)
  2141. {
  2142. PWND pwnd;
  2143. PWND pwndParent;
  2144. PMDI pmdi;
  2145. PMDINEXTMENU pmnm;
  2146. HWND hwndT;
  2147. PWND pwndT;
  2148. TL tlpwndT;
  2149. TL tlpwndParent;
  2150. LRESULT lRet;
  2151. if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
  2152. return (0L);
  2153. }
  2154. CheckLock(pwnd);
  2155. /*
  2156. * Check to see if this is a real mdi child window
  2157. */
  2158. pwndParent = REBASEPWND(pwnd, spwndParent);
  2159. if (!pwndParent || GETFNID(pwndParent) != FNID_MDICLIENT) {
  2160. RIPERR0(ERROR_NON_MDICHILD_WINDOW, RIP_VERBOSE, "");
  2161. return DefWindowProcWorker(pwnd, wMsg, wParam, lParam, fAnsi);
  2162. }
  2163. /*
  2164. * Get a pointer to the MDI structure, if it still exists
  2165. */
  2166. pmdi = ((PMDIWND)pwndParent)->pmdi;
  2167. if ((ULONG_PTR)pmdi == (ULONG_PTR)-1) {
  2168. goto CallDWP;
  2169. }
  2170. switch (wMsg) {
  2171. case WM_SETFOCUS:
  2172. if (DIFFWOWHANDLE(hwnd, ACTIVE(pmdi))) {
  2173. ThreadLockAlways(pwndParent, &tlpwndParent);
  2174. xxxMDIActivate(pwndParent, pwnd);
  2175. ThreadUnlock(&tlpwndParent);
  2176. }
  2177. goto CallDWP;
  2178. case WM_NEXTMENU:
  2179. /*
  2180. * wrap to the frame menu bar, either left to the system menu,
  2181. * or right to the frame menu bar.
  2182. */
  2183. pmnm = (PMDINEXTMENU)lParam;
  2184. pwndT = REBASEPWND(pwndParent, spwndParent);
  2185. pmnm->hwndNext = HW(pwndT);
  2186. pmnm->hmenuNext = (wParam == VK_LEFT) ?
  2187. NtUserGetSystemMenu(pmnm->hwndNext, FALSE) :
  2188. GetMenu(pmnm->hwndNext);
  2189. return TRUE;
  2190. #if 0
  2191. hWnd->hwndParent->hwndParent
  2192. return (LONG)(((wParam == VK_LEFT) ?
  2193. NtUserGetSystemMenu(HW(pwndT), FALSE):
  2194. pwndT->spmenu)
  2195. );
  2196. // return MAKELONG(NtUserGetSystemMenu(ACTIVE(pwndMDI), FALSE),
  2197. // ACTIVE(pwndMDI));
  2198. #endif
  2199. case WM_CLOSE:
  2200. hwndT = GetParent(hwnd);
  2201. if (hwndT != NULL) {
  2202. SendMessage(hwndT, WM_MDIDESTROY, (WPARAM)hwnd, 0L);
  2203. }
  2204. break;
  2205. case WM_MENUCHAR:
  2206. PostMessage(GetParent(GetParent(hwnd)), WM_SYSCOMMAND,
  2207. (DWORD)SC_KEYMENU, (LONG)LOWORD(wParam));
  2208. return 0x10000;
  2209. case WM_SETTEXT:
  2210. DefWindowProcWorker(pwnd, wMsg, wParam, lParam, fAnsi);
  2211. if (WINDOW(pmdi))
  2212. ModifyMenuItem(pwnd);
  2213. if (TestWF(pwnd, WFMAXIMIZED)) {
  2214. /*
  2215. * Add the child's window text to the frame since it is
  2216. * maximized. But just redraw the caption so pass a 3L.
  2217. */
  2218. pwndT = REBASEPWND(pwndParent, spwndParent);
  2219. ThreadLock(pwndT, &tlpwndT);
  2220. ThreadLock(pwndParent, &tlpwndParent);
  2221. xxxSetFrameTitle(pwndT, pwndParent, (LPWSTR)3L);
  2222. ThreadUnlock(&tlpwndParent);
  2223. ThreadUnlock(&tlpwndT);
  2224. }
  2225. break;
  2226. case WM_GETMINMAXINFO:
  2227. ChildMinMaxInfo(pwnd, (PMINMAXINFO)lParam);
  2228. break;
  2229. case WM_SIZE:
  2230. xxxChildResize(pwnd, (UINT)wParam);
  2231. goto CallDWP;
  2232. case WM_MOVE:
  2233. if (!TestWF(pwnd, WFMAXIMIZED))
  2234. RecalculateScrollRanges(pwndParent, FALSE);
  2235. goto CallDWP;
  2236. case WM_CHILDACTIVATE:
  2237. ThreadLock(pwndParent, &tlpwndParent);
  2238. xxxMDIActivate(pwndParent, pwnd);
  2239. ThreadUnlock(&tlpwndParent);
  2240. break;
  2241. case WM_SYSCOMMAND:
  2242. switch (wParam & 0xFFF0) {
  2243. case SC_NEXTWINDOW:
  2244. case SC_PREVWINDOW:
  2245. hwndT = GetParent(hwnd);
  2246. SendMessage(hwndT, WM_MDINEXT, (WPARAM)hwnd,
  2247. (DWORD)((wParam & 0xFFF0) == SC_PREVWINDOW));
  2248. break;
  2249. case SC_SIZE:
  2250. case SC_MOVE:
  2251. if (SAMEWOWHANDLE(hwnd, MAXED(pmdi))) {
  2252. /*
  2253. * If a maxed child gets a size or move message, blow it
  2254. * off.
  2255. */
  2256. break;
  2257. } else
  2258. goto CallDWP;
  2259. case SC_MAXIMIZE:
  2260. if (SAMEWOWHANDLE(hwnd, MAXED(pmdi))) {
  2261. /*
  2262. * If a maxed child gets a maximize message, forward it
  2263. * to the frame. Useful if the maximized child has a
  2264. * size box so that clicking on it then maximizes the
  2265. * parent.
  2266. */
  2267. pwndT = REBASEPWND(pwndParent, spwndParent);
  2268. ThreadLock(pwndT, &tlpwndT);
  2269. lRet = SendMessage(HW(pwndT),
  2270. WM_SYSCOMMAND, SC_MAXIMIZE, lParam);
  2271. ThreadUnlock(&tlpwndT);
  2272. return lRet;
  2273. }
  2274. /*
  2275. * else fall through
  2276. */
  2277. default:
  2278. goto CallDWP;
  2279. }
  2280. break;
  2281. default:
  2282. CallDWP:
  2283. return DefWindowProcWorker(pwnd, wMsg, wParam, lParam, fAnsi);
  2284. }
  2285. return 0L;
  2286. }
  2287. /***************************************************************************\
  2288. * DefMDIChildProc
  2289. *
  2290. * Translates the message, calls DefMDIChildProc on server side.
  2291. *
  2292. * 04-11-91 ScottLu Created.
  2293. \***************************************************************************/
  2294. FUNCLOG4(LOG_GENERAL, LRESULT, WINAPI, DefMDIChildProcW, HWND, hwnd, UINT, message, WPARAM, wParam, LPARAM, lParam)
  2295. LRESULT WINAPI DefMDIChildProcW(
  2296. HWND hwnd,
  2297. UINT message,
  2298. WPARAM wParam,
  2299. LPARAM lParam)
  2300. {
  2301. return DefMDIChildProcWorker(hwnd, message, wParam, lParam, FALSE);
  2302. }
  2303. FUNCLOG4(LOG_GENERAL, LRESULT, WINAPI, DefMDIChildProcA, HWND, hwnd, UINT, message, WPARAM, wParam, LPARAM, lParam)
  2304. LRESULT WINAPI DefMDIChildProcA(
  2305. HWND hwnd,
  2306. UINT message,
  2307. WPARAM wParam,
  2308. LPARAM lParam)
  2309. {
  2310. return DefMDIChildProcWorker(hwnd, message, wParam, lParam, TRUE);
  2311. }
  2312. BOOL MDICompleteChildCreation(HWND hwndChild, HMENU hSysMenu, BOOL fVisible, BOOL fDisabled) {
  2313. PWND pwndChild;
  2314. PWND pwndClient;
  2315. HWND hwndClient;
  2316. BOOL fHasOwnSysMenu;
  2317. PMDI pmdi;
  2318. pwndChild = ValidateHwnd(hwndChild);
  2319. pwndClient = REBASEPWND(pwndChild,spwndParent);
  2320. hwndClient = HWq(pwndClient);
  2321. fHasOwnSysMenu = (pwndChild->spmenuSys) ? TRUE : FALSE;
  2322. pmdi = ((PMDIWND)(pwndClient))->pmdi;
  2323. CKIDS(pmdi)++;
  2324. ITILELEVEL(pmdi)++;
  2325. if (ITILELEVEL(pmdi) > 0x7ffe)
  2326. ITILELEVEL(pmdi) = 0;
  2327. // Update "Window" menu if this new window should be on it
  2328. if (fVisible && !fDisabled && (CKIDS(pmdi) <= MAXITEMS))
  2329. SendMessage(hwndClient, WM_MDIREFRESHMENU, 0, 0L);
  2330. //
  2331. // Add the MDI System Menu. Catch the case of not being able to add a
  2332. // system menu (EG, guy doesn't have WS_SYSMENU style), and delete the
  2333. // menu to avoid buildup in USER's heap.
  2334. //
  2335. if (hSysMenu && (fHasOwnSysMenu || !NtUserSetSystemMenu(hwndChild, hSysMenu)))
  2336. NtUserDestroyMenu(hSysMenu);
  2337. if (fVisible)
  2338. {
  2339. if (!TestWF(pwndChild, WFMINIMIZED) || !ACTIVE(pmdi))
  2340. {
  2341. NtUserSetWindowPos(hwndChild, HWND_TOP, 0, 0, 0, 0,
  2342. SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
  2343. if (TestWF(pwndChild, WFMAXIMIZED) && !fHasOwnSysMenu)
  2344. {
  2345. PWND pwndParent = REBASEPWND(pwndClient, spwndParent);
  2346. PMENU pmenu = REBASE(pwndParent, spmenu);
  2347. MDIAddSysMenu(PtoH(pmenu), hwndChild);
  2348. NtUserRedrawFrame(HW(pwndParent));
  2349. }
  2350. }
  2351. else
  2352. {
  2353. NtUserShowWindow(hwndChild, SW_SHOWMINNOACTIVE);
  2354. }
  2355. }
  2356. return TRUE;
  2357. }
  2358. BOOL
  2359. CreateMDIChild(
  2360. PSHORTCREATE psc,
  2361. LPMDICREATESTRUCT pmcs,
  2362. DWORD dwExpWinVerAndFlags,
  2363. HMENU * phSysMenu,
  2364. PWND pwndParent)
  2365. {
  2366. BOOL fVisible;
  2367. RECT rcT;
  2368. HMENU hSysMenu = NULL;
  2369. HWND hwndPrevMaxed;
  2370. PMDI pmdi;
  2371. /*
  2372. * Get a pointer to the MDI structure
  2373. */
  2374. pmdi = ((PMDIWND)(pwndParent))->pmdi;
  2375. pmcs->style = psc->style;
  2376. // Mask off ignored style bits and add required ones.
  2377. psc->style |= (WS_CHILD | WS_CLIPSIBLINGS);
  2378. if (!(pwndParent->style & MDIS_ALLCHILDSTYLES))
  2379. {
  2380. psc->style &= WS_MDIALLOWED;
  2381. psc->style |= (WS_MDISTYLE | WS_VISIBLE);
  2382. }
  2383. else if (psc->style & WS_POPUP)
  2384. {
  2385. RIPMSG0(RIP_ERROR, "CreateWindowEx: WS_POPUP not allowed on MDI children");
  2386. if (LOWORD(dwExpWinVerAndFlags) >= VER40)
  2387. return FALSE;
  2388. }
  2389. fVisible = ((psc->style & WS_VISIBLE) != 0L);
  2390. //
  2391. // Save ORIGINAL parameters in MDICREATESTRUCT. This is for
  2392. // compatibility with old WM_MDICREATE.
  2393. //
  2394. pmcs->x = rcT.left = psc->x;
  2395. pmcs->y = rcT.top = psc->y;
  2396. pmcs->cx = rcT.right = psc->cx;
  2397. pmcs->cy = rcT.bottom = psc->cy;
  2398. MDICheckCascadeRect(pwndParent, &rcT);
  2399. //
  2400. // Setup creation coords
  2401. //
  2402. psc->x = rcT.left;
  2403. psc->y = rcT.top;
  2404. psc->cx = rcT.right;
  2405. psc->cy = rcT.bottom;
  2406. // Load the system menu
  2407. if (psc->style & WS_SYSMENU) {
  2408. #ifdef LAME_BUTTON
  2409. hSysMenu = xxxLoadSysMenu(CHILDSYSMENU, NULL);
  2410. #else
  2411. hSysMenu = xxxLoadSysMenu(CHILDSYSMENU);
  2412. #endif // LAME_BUTTON
  2413. if (hSysMenu == NULL) {
  2414. return FALSE;
  2415. }
  2416. }
  2417. // The window got created ok: now restore the current maximized window
  2418. // so we can maximize ourself in its place.
  2419. hwndPrevMaxed = MAXED(pmdi);
  2420. if (fVisible && IsWindow(hwndPrevMaxed))
  2421. {
  2422. if (psc->style & WS_MAXIMIZE)
  2423. SendMessage(hwndPrevMaxed, WM_SETREDRAW, (WPARAM)FALSE, 0L);
  2424. // we could nuke the hwndPrevMaxed during the SendMessage32
  2425. // so recheck just in case, B#11122, [t-arthb]
  2426. if ( IsWindow(hwndPrevMaxed) )
  2427. {
  2428. NtUserMinMaximize(hwndPrevMaxed, SW_SHOWNORMAL, TRUE);
  2429. if ( psc->style & WS_MAXIMIZE )
  2430. SendMessage(hwndPrevMaxed, WM_SETREDRAW, (WPARAM)TRUE, 0L);
  2431. }
  2432. }
  2433. // Set the proper Child Window ID for this MDI child.
  2434. psc->hMenu = (HMENU)UIntToPtr( (FIRST(pmdi) + CKIDS(pmdi)) );
  2435. *phSysMenu = hSysMenu;
  2436. return TRUE;
  2437. }