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.

703 lines
18 KiB

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