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.

498 lines
15 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: hungapp.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. *
  7. * History:
  8. * 03-10-92 DavidPe Created.
  9. \***************************************************************************/
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. /***************************************************************************\
  13. * SetHungFlag
  14. *
  15. * Sets the specified redraw-if-hung flag in the window and adds the
  16. * window to the list of windows to redraw if hung.
  17. * Windows that are not top-level get the bit set, but aren't added to the list
  18. *
  19. * 08-23-93 JimA Created.
  20. \***************************************************************************/
  21. #define CHRLINCR 10
  22. VOID SetHungFlag(
  23. PWND pwnd,
  24. WORD wFlag)
  25. {
  26. /*
  27. * If the window has no hung redraw bits set and it's a top-level
  28. * window, add it to the redraw list.
  29. */
  30. if (!TestWF(pwnd, WFANYHUNGREDRAW) && pwnd->spwndParent == PWNDDESKTOP(pwnd)) {
  31. /*
  32. * Add pwnd to the Hung Redraw Volatile Window Pointer List.
  33. */
  34. VWPLAdd(&gpvwplHungRedraw, pwnd, CHRLINCR);
  35. }
  36. SetWF(pwnd, wFlag);
  37. }
  38. /***************************************************************************\
  39. * ClearHungFlag
  40. *
  41. * Clears the specified redraw-if-hung flag in the window and if no other
  42. * redraw-if-hung flags remain, remove the window from list of windows
  43. * to be redrawn if hung.
  44. * Many windows have WFREDRAW* bits set, but aren't in the list (only those
  45. * that were top-level were added).
  46. *
  47. * 08-23-93 JimA Created.
  48. \***************************************************************************/
  49. VOID ClearHungFlag(
  50. PWND pwnd,
  51. WORD wFlag)
  52. {
  53. BOOL fInRedrawList = TestWF(pwnd, WFANYHUNGREDRAW);
  54. ClrWF(pwnd, wFlag);
  55. if (!TestWF(pwnd, WFANYHUNGREDRAW) && fInRedrawList) {
  56. /*
  57. * Remove the window from the redraw list and possibly compact it.
  58. */
  59. VWPLRemove(&gpvwplHungRedraw, pwnd);
  60. }
  61. }
  62. /***************************************************************************\
  63. * FHungApp
  64. *
  65. *
  66. * 02-28-92 DavidPe Created.
  67. \***************************************************************************/
  68. BOOL FHungApp(
  69. PTHREADINFO pti,
  70. DWORD dwTimeFromLastRead)
  71. {
  72. /*
  73. * An app is considered hung if it isn't waiting for input, isn't in
  74. * startup processing, and hasn't called PeekMessage() within the
  75. * specified timeout.
  76. */
  77. if (((NtGetTickCount() - GET_TIME_LAST_READ(pti)) > dwTimeFromLastRead) &&
  78. !((pti->pcti->fsWakeMask & QS_INPUT) && (PsGetThreadFreezeCount(pti->pEThread) == 0)) &&
  79. !(pti->ppi->W32PF_Flags & W32PF_APPSTARTING)) {
  80. return TRUE;
  81. }
  82. return FALSE;
  83. }
  84. /***************************************************************************\
  85. * xxxRedrawHungWindowFrame
  86. *
  87. *
  88. * 02-28-92 DavidPe Created.
  89. \***************************************************************************/
  90. VOID xxxRedrawHungWindowFrame(
  91. PWND pwnd,
  92. BOOL fActive)
  93. {
  94. HDC hdc;
  95. UINT wFlags = DC_NC | DC_NOSENDMSG;
  96. CheckLock(pwnd);
  97. #ifdef HUNGAPP_GHOSTING
  98. ClearHungFlag(pwnd, WFREDRAWFRAMEIFHUNG);
  99. SignalGhost(pwnd);
  100. return;
  101. #endif // HUNGAPP_GHOSTING
  102. if (IsInsideUserApiHook()) {
  103. return;
  104. }
  105. if (fActive) {
  106. wFlags |= DC_ACTIVE;
  107. }
  108. hdc = _GetDCEx(pwnd, NULL, DCX_USESTYLE | DCX_WINDOW);
  109. xxxDrawCaptionBar(pwnd, hdc, wFlags);
  110. _ReleaseDC(hdc);
  111. }
  112. /***************************************************************************\
  113. * xxxRedrawHungWindow
  114. *
  115. * If the hrgnFullDrag is NULL, redraw the hung window's entire update
  116. * region, otherwise, only redraw the intersection of the window's update
  117. * region with the FullDrag region.
  118. *
  119. * 02-28-92 DavidPe Created.
  120. \***************************************************************************/
  121. VOID xxxRedrawHungWindow(
  122. PWND pwnd,
  123. HRGN hrgnFullDrag)
  124. {
  125. HDC hdc;
  126. HBRUSH hbr;
  127. HRGN hrgnUpdate;
  128. RECT rc;
  129. TL tlpwnd;
  130. UINT flags;
  131. W32PID sid;
  132. DWORD dwColor;
  133. PWND pwndDesk;
  134. TL tlpwndDesk;
  135. CheckCritIn();
  136. CheckLock(pwnd);
  137. if (pwnd->hrgnUpdate == NULL) {
  138. return;
  139. }
  140. #ifdef HUNGAPP_GHOSTING
  141. /*
  142. * Don't bother doing anything here when the window isn't even visible.
  143. */
  144. if (!TestWF(pwnd, WFVISIBLE)) {
  145. return;
  146. }
  147. /*
  148. * This function can be called from the full-drag code to quick redraw
  149. * windows that aren't hung. In that case check if that thread is hung.
  150. */
  151. if ((hrgnFullDrag == NULL) || (hrgnFullDrag != NULL &&
  152. FHungApp(GETPTI(pwnd), CMSHUNGAPPTIMEOUT))) {
  153. SignalGhost(pwnd);
  154. return;
  155. }
  156. UserAssert(gptiCurrent != gptiRit);
  157. #endif
  158. /*
  159. * First calculate hrgnUpdate.
  160. */
  161. if (pwnd->hrgnUpdate > HRGN_FULL) {
  162. hrgnUpdate = CreateEmptyRgn();
  163. if (hrgnUpdate == NULL) {
  164. hrgnUpdate = HRGN_FULL;
  165. } else if (CopyRgn(hrgnUpdate, pwnd->hrgnUpdate) == ERROR) {
  166. GreDeleteObject(hrgnUpdate);
  167. hrgnUpdate = HRGN_FULL;
  168. }
  169. } else {
  170. /*
  171. * For our purposes, we need a real hrgnUpdate, so try and
  172. * create one if even if the entire window needs updating.
  173. */
  174. CopyRect(&rc, &pwnd->rcWindow);
  175. hrgnUpdate = GreCreateRectRgnIndirect(&rc);
  176. if (hrgnUpdate == NULL) {
  177. hrgnUpdate = HRGN_FULL;
  178. }
  179. }
  180. /*
  181. * If we're redrawing because we're full dragging and if the window's
  182. * update region does not intersect with the Full drag
  183. * update region, don't erase the hung window again. This is to prevent
  184. * flickering when a window has been invalidated by another window doing
  185. * full drag and hasn't received the paint message yet.
  186. * This way, only if there is a new region that has been invalidated will
  187. * we redraw the hung window.
  188. */
  189. if (hrgnFullDrag && hrgnUpdate != HRGN_FULL &&
  190. IntersectRgn(hrgnUpdate, hrgnUpdate, hrgnFullDrag) == NULLREGION) {
  191. GreDeleteObject(hrgnUpdate);
  192. return;
  193. }
  194. ThreadLock(pwnd, &tlpwnd);
  195. if (IsInsideUserApiHook()) {
  196. xxxInternalInvalidate(pwnd, hrgnUpdate, RDW_INVALIDATE |
  197. RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN);
  198. } else {
  199. hdc = _GetDCEx(pwnd, hrgnUpdate, DCX_USESTYLE | DCX_WINDOW |
  200. DCX_INTERSECTRGN | DCX_NODELETERGN | DCX_LOCKWINDOWUPDATE);
  201. xxxDrawWindowFrame(pwnd, hdc, DF_HUNGREDRAW | (TestwndFrameOn(pwnd) ? DF_ACTIVE : 0L));
  202. _ReleaseDC(hdc);
  203. }
  204. CopyRect(&rc, &pwnd->rcWindow);
  205. xxxCalcClientRect(pwnd, &rc, TRUE);
  206. SetRectRgnIndirect(ghrgnInv2, &rc);
  207. if (hrgnUpdate > HRGN_FULL) {
  208. switch (IntersectRgn(hrgnUpdate, hrgnUpdate, ghrgnInv2)) {
  209. case ERROR:
  210. GreDeleteObject(hrgnUpdate);
  211. hrgnUpdate = HRGN_FULL;
  212. break;
  213. case NULLREGION:
  214. /*
  215. * There is nothing in the client area to repaint.
  216. * Blow the region away, and decrement the paint count
  217. * if possible.
  218. */
  219. GreDeleteObject(hrgnUpdate);
  220. hrgnUpdate = NULL;
  221. break;
  222. }
  223. }
  224. /*
  225. * Erase the rest of the window.
  226. * When pwnd isn't WFCLIPCHILDREN, make sure valid children bits
  227. * don't get overwritten if the child is in the middle of BeginPaint
  228. * or just completed it's painting and it's hrgnUpdate is NULL.
  229. */
  230. if (hrgnUpdate != NULL && !TestWF(pwnd, WFCLIPCHILDREN)) {
  231. RECT rcT;
  232. PWND pwndT;
  233. if (hrgnUpdate == HRGN_FULL) {
  234. rc = pwnd->rcWindow;
  235. } else {
  236. GreGetRgnBox(hrgnUpdate, &rc);
  237. }
  238. for (pwndT = pwnd->spwndChild; pwndT != NULL;
  239. pwndT = pwndT->spwndNext) {
  240. if (TestWF(pwndT, WFVISIBLE) &&
  241. (TestWF(pwndT, WFSTARTPAINT) || pwndT->hrgnUpdate == NULL) &&
  242. IntersectRect(&rcT, &rc, &pwndT->rcWindow)) {
  243. /*
  244. * This invalidate call won't leave the critial section. In
  245. * reality the entire xxxRedrawHungWindow must not leave
  246. * the critical section.
  247. */
  248. BEGINATOMICCHECK();
  249. xxxInternalInvalidate(pwndT, hrgnUpdate, RDW_INVALIDATE |
  250. RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN);
  251. ENDATOMICCHECK();
  252. }
  253. }
  254. }
  255. /*
  256. * Get a window dc so that the menu and scroll bar areas are erased
  257. * appropriately. But make sure it is clipped so that the children
  258. * get clipped out correctly! If we don't do this, this we could erase
  259. * children that aren't invalid.
  260. *
  261. * Note: DCX_WINDOW and DCX_USESTYLE will never clip out children.
  262. * Need to pass the clipping styles in directly, instead of passing
  263. * DCX_USESTYLE.
  264. */
  265. flags = DCX_INTERSECTRGN | DCX_WINDOW | DCX_CACHE;
  266. if (TestWF(pwnd, WFCLIPSIBLINGS))
  267. flags |= DCX_CLIPSIBLINGS;
  268. if (TestWF(pwnd, WFCLIPCHILDREN))
  269. flags |= DCX_CLIPCHILDREN;
  270. hdc = _GetDCEx(pwnd, hrgnUpdate, flags);
  271. if (pwnd == pwnd->head.rpdesk->pDeskInfo->spwndBkGnd) {
  272. pwndDesk = PWNDDESKTOP(pwnd);
  273. ThreadLock(pwndDesk, &tlpwndDesk);
  274. xxxInternalPaintDesktop(PWNDDESKTOP(pwnd), hdc, TRUE);
  275. ThreadUnlock(&tlpwndDesk);
  276. } else {
  277. rc = pwnd->rcWindow;
  278. OffsetRect(&rc, -pwnd->rcWindow.left, -pwnd->rcWindow.top);
  279. /*
  280. * Erase the rest of the window using the window's class background
  281. * brush.
  282. */
  283. if ((hbr = pwnd->pcls->hbrBackground) != NULL) {
  284. if (hbr <= (HBRUSH)COLOR_ENDCOLORS + 1) {
  285. hbr = SYSHBRUSH((ULONG_PTR)hbr - 1);
  286. }
  287. } else {
  288. /*
  289. * Use the window brush for windows and 3.x dialogs, and use
  290. * the COLOR3D brush for 4.x dialogs.
  291. */
  292. if (TestWF(pwnd, WFDIALOGWINDOW) && TestWF(pwnd, WFWIN40COMPAT)) {
  293. hbr = SYSHBR(3DFACE);
  294. } else {
  295. hbr = SYSHBR(WINDOW);
  296. }
  297. }
  298. /*
  299. * If the window's class background brush is public, use it.
  300. */
  301. sid = (W32PID)GreGetObjectOwner((HOBJ)hbr, BRUSH_TYPE);
  302. if (sid == OBJECT_OWNER_PUBLIC ||
  303. sid == (W32PID)(ULONG_PTR)PsGetCurrentProcessId()) {
  304. FillRect(hdc, &rc, hbr);
  305. } else {
  306. /*
  307. * The window's class background brush is not public.
  308. *
  309. * We get its color and set the color of our own public brush
  310. * and use that for the background brush.
  311. */
  312. /*
  313. * If the window is a console window, get the console background brush.
  314. * This brush will be different than the console class brush if the user
  315. * changed the console background color.
  316. */
  317. if (gatomConsoleClass == pwnd->pcls->atomClassName) {
  318. dwColor = _GetWindowLong(pwnd, GWL_CONSOLE_BKCOLOR);
  319. } else {
  320. if ((dwColor = GreGetBrushColor(hbr)) == -1) {
  321. dwColor = GreGetBrushColor(SYSHBR(WINDOW));
  322. }
  323. }
  324. GreSetSolidBrush(ghbrHungApp, dwColor);
  325. FillRect(hdc, &rc, ghbrHungApp);
  326. }
  327. }
  328. _ReleaseDC(hdc);
  329. /*
  330. * The window has been erased and framed. It only did this because the
  331. * app hasn't done it yet:
  332. *
  333. * - the app hasn't erased and frame yet.
  334. * - the app is in the middle of erasing and framing.
  335. *
  336. * The app could not of completed erasing and framing, because the
  337. * WFREDRAWIFHUNG bit is cleared when this successfully completes.
  338. *
  339. * Given that the app may be in the middle of erasing and framing, we
  340. * need to set both the erase and frame bits *again* so it erasing and
  341. * frames over again (if we don't, it never will). If the app hasn't
  342. * done any erasing/framing yet, this is a nop.
  343. */
  344. SetWF(pwnd, WFSENDNCPAINT);
  345. SetWF(pwnd, WFSENDERASEBKGND);
  346. /*
  347. * Always set WFUPDATEDIRTY: we don't want the app to draw, then stop
  348. * and have the hung app thread draw, and then allow the app to validate
  349. * itself: Mark the update region dirty - cannot be validated until the
  350. * app calls a painting function and acknowledges the update region.
  351. */
  352. SetWF(pwnd, WFUPDATEDIRTY);
  353. ThreadUnlock(&tlpwnd);
  354. }
  355. /***************************************************************************\
  356. * xxxHungAppDemon
  357. *
  358. * NOTE: RIT timers (like this one) get called while inside the critical
  359. * section.
  360. *
  361. * We keep a list of redraw-if-hung windows in a list that remains in a
  362. * single page to avoid touching the windows themselves each time through
  363. * this routine. Touching the windows causes a bunch of unnecessary paging
  364. * and in effect keeps all of the pages that contain top-level windows
  365. * resident at all times; this is very wasteful.
  366. *
  367. * 02-28-92 DavidPe Created.
  368. \***************************************************************************/
  369. VOID xxxHungAppDemon(
  370. PWND pwnd,
  371. UINT message,
  372. UINT_PTR nID,
  373. LPARAM lParam)
  374. {
  375. TL tlpwnd;
  376. DWORD nPwndHungRedraw;
  377. PWND pwndHungRedraw;
  378. UNREFERENCED_PARAMETER(message);
  379. UNREFERENCED_PARAMETER(nID);
  380. UNREFERENCED_PARAMETER(lParam);
  381. UNREFERENCED_PARAMETER(pwnd);
  382. CheckLock(pwnd);
  383. /*
  384. * See if we should start the screen saver.
  385. */
  386. IdleTimerProc();
  387. /*
  388. * If it is time to hide the app starting cursor, do it.
  389. */
  390. if (NtGetTickCount() >= gtimeStartCursorHide) {
  391. /*
  392. * No need to DeferWinEventNotify()
  393. */
  394. zzzCalcStartCursorHide(NULL, 0);
  395. }
  396. /*
  397. * Now check to see if there are any top-level windows that need
  398. * redrawing.
  399. */
  400. if (grpdeskRitInput == NULL || grpdeskRitInput->pDeskInfo->spwnd == NULL) {
  401. return;
  402. }
  403. /*
  404. * Walk down the list of redraw-if-hung windows. Loop until we hit the
  405. * end of the array or find a NULL.
  406. */
  407. nPwndHungRedraw = 0;
  408. pwndHungRedraw = NULL;
  409. while (pwndHungRedraw = VWPLNext(gpvwplHungRedraw, pwndHungRedraw, &nPwndHungRedraw)) {
  410. /*
  411. * See if the app is hung. If so, do the appropriate redrawing.
  412. */
  413. if (FHungApp(GETPTI(pwndHungRedraw), CMSHUNGAPPTIMEOUT)) {
  414. ThreadLock(pwndHungRedraw, &tlpwnd);
  415. if (TestWF(pwndHungRedraw, WFREDRAWFRAMEIFHUNG)) {
  416. /*
  417. * WFREDRAWFRAMEIFHUNG will be cleared in the process of
  418. * drawing the frame, so no need to clear it here.
  419. */
  420. xxxRedrawHungWindowFrame(pwndHungRedraw,
  421. TestwndFrameOn(pwndHungRedraw));
  422. }
  423. if (TestWF(pwndHungRedraw, WFREDRAWIFHUNG)) {
  424. ClearHungFlag(pwndHungRedraw, WFREDRAWIFHUNG);
  425. xxxRedrawHungWindow(pwndHungRedraw, NULL);
  426. }
  427. ThreadUnlock(&tlpwnd);
  428. }
  429. }
  430. }