Source code of Windows XP (NT5)
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.

695 lines
17 KiB

  1. /*++
  2. Copyright (c) 1992-2001 Microsoft Corporation
  3. Module Name:
  4. arrange.cpp
  5. Abstract:
  6. This module contains the default MDI tiling (arrange) code for
  7. windowing arrangement.
  8. --*/
  9. #include "precomp.hxx"
  10. #pragma hdrstop
  11. #define AUTO_ARRANGE_WARNING_LIMIT 3
  12. // Multiple events closely together don't each get their own
  13. // count in order to prevent warnings on full-drag message
  14. // series. This delay should be relatively large to
  15. // avoid problems with people pausing during a full-drag move.
  16. #define AUTO_ARRANGE_WARNING_DELAY 2500
  17. // DeferWindowPos flags to restrict change to position only.
  18. #define POS_ONLY (SWP_NOACTIVATE | SWP_NOZORDER)
  19. ULONG g_AutoArrangeWarningCount;
  20. ULONG g_AutoArrangeWarningTime;
  21. BOOL
  22. IsAutoArranged(WIN_TYPES Type)
  23. {
  24. if (g_WinOptions & WOPT_AUTO_ARRANGE)
  25. {
  26. if (g_WinOptions & WOPT_ARRANGE_ALL)
  27. {
  28. return TRUE;
  29. }
  30. return Type != DOC_WINDOW && Type != DISASM_WINDOW;
  31. }
  32. return FALSE;
  33. }
  34. void
  35. DisplayAutoArrangeWarning(PCOMMONWIN_DATA CmnWin)
  36. {
  37. //
  38. // If this window is under automatic arrangement
  39. // control and has been rearranged a few times,
  40. // let the user know that auto-arrange may override
  41. // what the user has done.
  42. //
  43. // In order to prevent false positives we avoid
  44. // giving any warnings if the window is being
  45. // moved automatically or if we're getting a series
  46. // of changes in a short period of time, such as
  47. // if the user has full-drag enabled so that many
  48. // move or size events can occur rapidly.
  49. //
  50. // Display the warning only once per execution.
  51. //
  52. if (g_AutoArrangeWarningCount == 0xffffffff ||
  53. CmnWin == NULL ||
  54. CmnWin->m_InAutoOp > 0 ||
  55. !IsAutoArranged(CmnWin->m_enumType) ||
  56. g_AutoArrangeWarningTime >
  57. GetTickCount() - AUTO_ARRANGE_WARNING_DELAY)
  58. {
  59. return;
  60. }
  61. if (++g_AutoArrangeWarningCount >= AUTO_ARRANGE_WARNING_LIMIT)
  62. {
  63. InformationBox(STR_Auto_Arrange_Is_Enabled);
  64. g_AutoArrangeWarningCount = 0xffffffff;
  65. }
  66. else
  67. {
  68. g_AutoArrangeWarningTime = GetTickCount();
  69. }
  70. }
  71. void
  72. ArrangeInRect(HDWP Defer, int X, int Y, int Width, int Height,
  73. BOOL Vertical, ULONG Types, int Count, BOOL Overlay)
  74. {
  75. PLIST_ENTRY Entry;
  76. PCOMMONWIN_DATA Data;
  77. int PerWin, Remain, Extra;
  78. if (Overlay)
  79. {
  80. Remain = 0;
  81. }
  82. else if (Vertical)
  83. {
  84. PerWin = Height / Count;
  85. Remain = Height - PerWin * Count;
  86. Height = PerWin + (Remain ? 1 : 0);
  87. }
  88. else
  89. {
  90. PerWin = Width / Count;
  91. Remain = Width - PerWin * Count;
  92. Width = PerWin + (Remain ? 1 : 0);
  93. }
  94. for (Entry = g_ActiveWin.Flink;
  95. Entry != &g_ActiveWin;
  96. Entry = Entry->Flink)
  97. {
  98. Data = ACTIVE_WIN_ENTRY(Entry);
  99. if ((Types & (1 << Data->m_enumType)) == 0 ||
  100. IsIconic(Data->m_Win))
  101. {
  102. continue;
  103. }
  104. DeferWindowPos(Defer, Data->m_Win, NULL, X, Y,
  105. Width, Height, POS_ONLY);
  106. if (Overlay)
  107. {
  108. // All windows are stacked on top of each other.
  109. }
  110. else if (Vertical)
  111. {
  112. Y += Height;
  113. if (--Remain == 0)
  114. {
  115. Height--;
  116. }
  117. }
  118. else
  119. {
  120. X += Width;
  121. if (--Remain == 0)
  122. {
  123. Width--;
  124. }
  125. }
  126. }
  127. }
  128. void
  129. Arrange(void)
  130. {
  131. PLIST_ENTRY Entry;
  132. PCOMMONWIN_DATA pWinData;
  133. int NumDoc, NumMem, NumWatchLocals, NumWin;
  134. int NumLeft, NumRight;
  135. BOOL AnyIcon = FALSE;
  136. HWND hwndChild;
  137. HWND hwndCpu;
  138. HWND hwndWatch;
  139. HWND hwndLocals;
  140. HWND hwndCalls;
  141. HWND hwndCmd;
  142. HWND hwndDisasm;
  143. HWND hwndScratch;
  144. HWND hwndProcThread;
  145. // initialize to non-existent
  146. NumLeft = NumRight = 0;
  147. NumDoc = NumMem = NumWatchLocals = NumWin = 0;
  148. hwndWatch = hwndLocals = hwndCpu = hwndCalls = NULL;
  149. hwndCmd = hwndDisasm = hwndScratch = hwndProcThread = NULL;
  150. hwndChild = MDIGetActive(g_hwndMDIClient, NULL);
  151. if (hwndChild && IsZoomed(hwndChild))
  152. {
  153. // If there's a maximized window it covers the MDI
  154. // client area and arranging will have no visual effect.
  155. // Don't even bother to rearrange underlying windows
  156. // as this causes problems when switching between child
  157. // windows while a child is maximized.
  158. return;
  159. }
  160. //
  161. // Windows are either left-side windows or right-side windows.
  162. // Left-side windows are wider and can be relatively short,
  163. // while right-side windows are narrow but want height.
  164. // Left-side windows want to be 80 columns wide while
  165. // right side windows have both a minimum width and a desired
  166. // width.
  167. //
  168. // Right-side windows fill whatever space is left over to
  169. // the right of the left-side windows. If that space is
  170. // less than the minimum the left-side windows have to give up space.
  171. //
  172. // Vertically each side is split up according to the specific
  173. // windows present. On the right side the windows are
  174. // space equally top-to-bottom.
  175. // On the left side watch and locals windows are packed together
  176. // in one vertical area, as are memory windows. Calls,
  177. // disassembly, document and command windows each get their own band.
  178. //
  179. for (Entry = g_ActiveWin.Flink;
  180. Entry != &g_ActiveWin;
  181. Entry = Entry->Flink)
  182. {
  183. pWinData = ACTIVE_WIN_ENTRY(Entry);
  184. // This window is participating in an operation
  185. // which may cause window messages.
  186. pWinData->m_InAutoOp++;
  187. hwndChild = pWinData->m_Win;
  188. if (hwndChild == NULL)
  189. {
  190. continue;
  191. }
  192. if (IsIconic(hwndChild))
  193. {
  194. AnyIcon = TRUE;
  195. continue;
  196. }
  197. NumWin++;
  198. switch (pWinData->m_enumType)
  199. {
  200. default:
  201. Assert(!_T("Unknown window type"));
  202. break;
  203. case WATCH_WINDOW:
  204. hwndWatch = hwndChild;
  205. if (++NumWatchLocals == 1)
  206. {
  207. NumLeft++;
  208. }
  209. break;
  210. case LOCALS_WINDOW:
  211. hwndLocals = hwndChild;
  212. if (++NumWatchLocals == 1)
  213. {
  214. NumLeft++;
  215. }
  216. break;
  217. case CPU_WINDOW:
  218. hwndCpu = hwndChild;
  219. NumRight++;
  220. break;
  221. case CALLS_WINDOW:
  222. hwndCalls = hwndChild;
  223. NumLeft++;
  224. break;
  225. case DOC_WINDOW:
  226. if ((g_WinOptions & WOPT_ARRANGE_ALL) == 0)
  227. {
  228. break;
  229. }
  230. if (++NumDoc == 1)
  231. {
  232. NumLeft++;
  233. }
  234. break;
  235. case DISASM_WINDOW:
  236. if ((g_WinOptions & WOPT_ARRANGE_ALL) == 0)
  237. {
  238. break;
  239. }
  240. hwndDisasm = hwndChild;
  241. NumLeft++;
  242. break;
  243. case CMD_WINDOW:
  244. hwndCmd = hwndChild;
  245. NumLeft++;
  246. break;
  247. case SCRATCH_PAD_WINDOW:
  248. hwndScratch = hwndChild;
  249. NumRight++;
  250. break;
  251. case MEM_WINDOW:
  252. if (++NumMem == 1)
  253. {
  254. NumLeft++;
  255. }
  256. break;
  257. case PROCESS_THREAD_WINDOW:
  258. hwndProcThread = hwndChild;
  259. NumLeft++;
  260. break;
  261. }
  262. }
  263. HDWP Defer = BeginDeferWindowPos(NumWin);
  264. if (Defer == NULL)
  265. {
  266. goto EndAutoOp;
  267. }
  268. // Now we have a count of all multiple wins and existence of special cases
  269. int AvailWidth = (int)g_MdiWidth;
  270. int AvailHeight = (int)g_MdiHeight;
  271. int X, Y, Width, MaxWidth, Height, RemainY;
  272. //
  273. // If icons present, don't cover them
  274. //
  275. if (AnyIcon)
  276. {
  277. AvailHeight -= GetSystemMetrics(SM_CYCAPTION) +
  278. GetSystemMetrics(SM_CYFRAME);
  279. }
  280. int LeftWidth = NumLeft > 0 ? LEFT_SIDE_WIDTH : 0;
  281. if (NumRight > 0)
  282. {
  283. switch(g_ActualProcType)
  284. {
  285. default:
  286. Width = RIGHT_SIDE_MIN_WIDTH_32;
  287. MaxWidth = RIGHT_SIDE_DESIRED_WIDTH_32;
  288. break;
  289. case IMAGE_FILE_MACHINE_IA64:
  290. case IMAGE_FILE_MACHINE_AXP64:
  291. case IMAGE_FILE_MACHINE_AMD64:
  292. Width = RIGHT_SIDE_MIN_WIDTH_64;
  293. MaxWidth = RIGHT_SIDE_DESIRED_WIDTH_64;
  294. break;
  295. }
  296. if (AvailWidth < LeftWidth + Width)
  297. {
  298. // Not enough space for left side to be at
  299. // its desired width.
  300. if (NumLeft == 0)
  301. {
  302. // No left-side windows to take space from.
  303. Width = AvailWidth;
  304. }
  305. else
  306. {
  307. LeftWidth = AvailWidth - Width;
  308. if (LeftWidth < LEFT_SIDE_MIN_WIDTH)
  309. {
  310. // We stole too much space so neither
  311. // side can meet their minimum widths. Just
  312. // split the available space up.
  313. Width = AvailWidth / 2;
  314. LeftWidth = AvailWidth - Width;
  315. }
  316. }
  317. }
  318. else
  319. {
  320. // Take up space on the right side up to the
  321. // desired width but no more. This gives
  322. // any extra space to the left side as the right
  323. // side doesn't really need any more than its desired
  324. // width.
  325. Width = AvailWidth - LeftWidth;
  326. if (Width > MaxWidth)
  327. {
  328. Width = MaxWidth;
  329. LeftWidth = AvailWidth - Width;
  330. }
  331. }
  332. X = LeftWidth;
  333. Y = 0;
  334. Height = AvailHeight / NumRight;
  335. if (hwndCpu != NULL)
  336. {
  337. DeferWindowPos(Defer, hwndCpu, NULL, X, Y,
  338. Width, Height, POS_ONLY);
  339. Y += Height;
  340. Height = AvailHeight - Height;
  341. }
  342. if (hwndScratch != NULL)
  343. {
  344. DeferWindowPos(Defer, hwndScratch, NULL, X, Y,
  345. Width, Height, POS_ONLY);
  346. }
  347. }
  348. else
  349. {
  350. LeftWidth = AvailWidth;
  351. }
  352. if (NumLeft == 0)
  353. {
  354. goto EndDefer;
  355. }
  356. int CmdHeight;
  357. int BiasedNumLeft;
  358. // Compute the size of each vertical band within the left side.
  359. // When doing so bias things so the command window gets
  360. // a 2.0 share to account for the fact that it has both
  361. // output and input areas. Also give it any remainder
  362. // space left when dividing.
  363. BiasedNumLeft = NumLeft * 2 + (hwndCmd != NULL ? 2 : 0);
  364. Height = (AvailHeight * 2) / BiasedNumLeft;
  365. if (hwndCmd != NULL)
  366. {
  367. CmdHeight = AvailHeight - Height * (NumLeft - 1);
  368. RemainY = 0;
  369. }
  370. else
  371. {
  372. RemainY = Height * (NumLeft + 1) - AvailHeight;
  373. }
  374. Y = 0;
  375. // Place the watch and locals windows at the top.
  376. if (NumWatchLocals > 0)
  377. {
  378. if (RemainY-- == 1)
  379. {
  380. Height++;
  381. }
  382. X = 0;
  383. Width = LeftWidth / NumWatchLocals;
  384. if (hwndWatch != NULL)
  385. {
  386. DeferWindowPos(Defer, hwndWatch, NULL, X, Y,
  387. Width, Height, POS_ONLY);
  388. X += Width;
  389. Width = LeftWidth - X;
  390. }
  391. if (hwndLocals != NULL)
  392. {
  393. DeferWindowPos(Defer, hwndLocals, NULL, X, Y,
  394. Width, Height, POS_ONLY);
  395. X += Width;
  396. Width = LeftWidth - X;
  397. }
  398. Y += Height;
  399. }
  400. // Place all the memory windows next.
  401. if (NumMem > 0)
  402. {
  403. if (RemainY-- == 1)
  404. {
  405. Height++;
  406. }
  407. ArrangeInRect(Defer, 0, Y, LeftWidth, Height,
  408. FALSE, 1 << MEM_WINDOW, NumMem, FALSE);
  409. Y += Height;
  410. }
  411. // Disasm window.
  412. if (hwndDisasm != NULL)
  413. {
  414. if (RemainY-- == 1)
  415. {
  416. Height++;
  417. }
  418. DeferWindowPos(Defer, hwndDisasm, NULL, 0, Y,
  419. LeftWidth, Height, POS_ONLY);
  420. Y += Height;
  421. }
  422. // Doc windows.
  423. if (NumDoc > 0)
  424. {
  425. if (RemainY-- == 1)
  426. {
  427. Height++;
  428. }
  429. ArrangeInRect(Defer, 0, Y, LeftWidth, Height,
  430. FALSE, 1 << DOC_WINDOW, NumDoc,
  431. (g_WinOptions & WOPT_OVERLAY_SOURCE) != 0);
  432. Y += Height;
  433. }
  434. // Command window.
  435. if (hwndCmd != NULL)
  436. {
  437. if (RemainY-- == 1)
  438. {
  439. Height++;
  440. }
  441. DeferWindowPos(Defer, hwndCmd, NULL, 0, Y,
  442. LeftWidth, CmdHeight, POS_ONLY);
  443. Y += CmdHeight;
  444. }
  445. // Calls window.
  446. if (hwndCalls != NULL)
  447. {
  448. if (RemainY-- == 1)
  449. {
  450. Height++;
  451. }
  452. DeferWindowPos(Defer, hwndCalls, NULL, 0, Y,
  453. LeftWidth, Height, POS_ONLY);
  454. Y += Height;
  455. }
  456. // Processes and threads window.
  457. if (hwndProcThread != NULL)
  458. {
  459. if (RemainY-- == 1)
  460. {
  461. Height++;
  462. }
  463. DeferWindowPos(Defer, hwndProcThread, NULL, 0, Y,
  464. LeftWidth, Height, POS_ONLY);
  465. Y += Height;
  466. }
  467. EndDefer:
  468. EndDeferWindowPos(Defer);
  469. EndAutoOp:
  470. // The auto-op is finished.
  471. for (Entry = g_ActiveWin.Flink;
  472. Entry != &g_ActiveWin;
  473. Entry = Entry->Flink)
  474. {
  475. pWinData = ACTIVE_WIN_ENTRY(Entry);
  476. pWinData->m_InAutoOp--;
  477. }
  478. }
  479. void
  480. UpdateSourceOverlay(void)
  481. {
  482. // If we're turning off overlay just leave the windows
  483. // the way they are.
  484. if ((g_WinOptions & WOPT_OVERLAY_SOURCE) == 0)
  485. {
  486. return;
  487. }
  488. // If doc windows are auto-arranged just handle it
  489. // that way.
  490. if (IsAutoArranged(DOC_WINDOW))
  491. {
  492. Arrange();
  493. return;
  494. }
  495. // Source overlay was just turned on. Pile all source
  496. // windows on top of the first one.
  497. PLIST_ENTRY Entry;
  498. PCOMMONWIN_DATA WinData;
  499. int X, Y;
  500. X = -INT_MAX;
  501. for (Entry = g_ActiveWin.Flink;
  502. Entry != &g_ActiveWin;
  503. Entry = Entry->Flink)
  504. {
  505. WinData = ACTIVE_WIN_ENTRY(Entry);
  506. if (WinData->m_enumType == DOC_WINDOW &&
  507. !IsIconic(WinData->m_Win))
  508. {
  509. if (X == -INT_MAX)
  510. {
  511. RECT Rect;
  512. // First window, remember its position.
  513. GetWindowRect(WinData->m_Win, &Rect);
  514. MapWindowPoints(GetDesktopWindow(), g_hwndMDIClient,
  515. (LPPOINT)&Rect, 1);
  516. X = Rect.left;
  517. Y = Rect.top;
  518. }
  519. else
  520. {
  521. // Line up with the first window.
  522. SetWindowPos(WinData->m_Win, NULL, X, Y, 0, 0,
  523. SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
  524. }
  525. }
  526. }
  527. }
  528. void
  529. SetAllFonts(ULONG FontIndex)
  530. {
  531. PLIST_ENTRY Entry;
  532. PCOMMONWIN_DATA WinData;
  533. for (Entry = g_ActiveWin.Flink;
  534. Entry != &g_ActiveWin;
  535. Entry = Entry->Flink)
  536. {
  537. WinData = ACTIVE_WIN_ENTRY(Entry);
  538. if (WinData != NULL)
  539. {
  540. WinData->SetFont(FontIndex);
  541. // Treat this like a resize as the line height
  542. // may change.
  543. WinData->OnSize();
  544. }
  545. }
  546. if (g_WinOptions & WOPT_AUTO_ARRANGE)
  547. {
  548. Arrange();
  549. }
  550. }
  551. void
  552. CloseAllWindows(void)
  553. {
  554. HWND Win, Next;
  555. Win = MDIGetActive(g_hwndMDIClient, NULL);
  556. while (Win != NULL)
  557. {
  558. Next = GetNextWindow(Win, GW_HWNDNEXT);
  559. SendMessage(g_hwndMDIClient, WM_MDIDESTROY, (WPARAM)Win, 0);
  560. Win = Next;
  561. }
  562. }
  563. void
  564. UpdateAllColors(void)
  565. {
  566. PLIST_ENTRY Entry;
  567. PCOMMONWIN_DATA WinData;
  568. for (Entry = g_ActiveWin.Flink;
  569. Entry != &g_ActiveWin;
  570. Entry = Entry->Flink)
  571. {
  572. WinData = ACTIVE_WIN_ENTRY(Entry);
  573. if (WinData != NULL)
  574. {
  575. WinData->UpdateColors();
  576. }
  577. }
  578. }
  579. PCOMMONWIN_DATA
  580. FindNthWindow(ULONG Nth, ULONG Types)
  581. {
  582. PLIST_ENTRY Entry;
  583. PCOMMONWIN_DATA WinData;
  584. for (Entry = g_ActiveWin.Flink;
  585. Entry != &g_ActiveWin;
  586. Entry = Entry->Flink)
  587. {
  588. WinData = ACTIVE_WIN_ENTRY(Entry);
  589. if (WinData != NULL &&
  590. ((1 << WinData->m_enumType) & Types) &&
  591. Nth-- == 0)
  592. {
  593. return WinData;
  594. }
  595. }
  596. return NULL;
  597. }