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

hungapp.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: hungapp.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * 00007 * History: 00008 * 03-10-92 DavidPe Created. 00009 \***************************************************************************/ 00010 00011 #include "precomp.h" 00012 #pragma hdrstop 00013 00014 00015 /***************************************************************************\ 00016 * SetHungFlag 00017 * 00018 * Sets the specified redraw-if-hung flag in the window and adds the 00019 * window to the list of windows to redraw if hung. 00020 * Windows that are not top-level get the bit set, but aren't added to the list 00021 * 00022 * 08-23-93 JimA Created. 00023 \***************************************************************************/ 00024 #define CHRLINCR 10 00025 00026 VOID SetHungFlag( 00027 PWND pwnd, 00028 WORD wFlag) 00029 { 00030 /* 00031 * If the window has no hung redraw bits set and it's a top-level 00032 * window, add it to the redraw list. 00033 */ 00034 if (!TestWF(pwnd, WFANYHUNGREDRAW) && pwnd->spwndParent == PWNDDESKTOP(pwnd)) { 00035 /* 00036 * Add pwnd to the Hung Redraw Volatile Window Pointer List. 00037 */ 00038 VWPLAdd(&gpvwplHungRedraw, pwnd, CHRLINCR); 00039 } 00040 00041 SetWF(pwnd, wFlag); 00042 } 00043 00044 00045 /***************************************************************************\ 00046 * ClearHungFlag 00047 * 00048 * Clears the specified redraw-if-hung flag in the window and if no other 00049 * redraw-if-hung flags remain, remove the window from list of windows 00050 * to be redrawn if hung. 00051 * Many windows have WFREDRAW* bits set, but aren't in the list (only those 00052 * that were top-level were added). 00053 * 00054 * 08-23-93 JimA Created. 00055 \***************************************************************************/ 00056 00057 VOID ClearHungFlag( 00058 PWND pwnd, 00059 WORD wFlag) 00060 { 00061 BOOL fInRedrawList = TestWF(pwnd, WFANYHUNGREDRAW); 00062 00063 ClrWF(pwnd, wFlag); 00064 if (!TestWF(pwnd, WFANYHUNGREDRAW) && fInRedrawList) { 00065 /* 00066 * Remove the window from the redraw list and possibly compact it. 00067 */ 00068 VWPLRemove(&gpvwplHungRedraw, pwnd); 00069 } 00070 } 00071 00072 00073 /***************************************************************************\ 00074 * FHungApp 00075 * 00076 * 00077 * 02-28-92 DavidPe Created. 00078 \***************************************************************************/ 00079 00080 BOOL FHungApp( 00081 PTHREADINFO pti, 00082 DWORD dwTimeFromLastRead) 00083 { 00084 00085 /* 00086 * An app is considered hung if it isn't waiting for input, isn't in 00087 * startup processing, and hasn't called PeekMessage() within the 00088 * specified timeout. 00089 */ 00090 if (((NtGetTickCount() - GET_TIME_LAST_READ(pti)) > dwTimeFromLastRead) && 00091 !((pti->pcti->fsWakeMask & QS_INPUT) && (pti->pEThread->Tcb.FreezeCount == 0)) && 00092 !(pti->ppi->W32PF_Flags & W32PF_APPSTARTING)) { 00093 return TRUE; 00094 } 00095 00096 return FALSE; 00097 } 00098 00099 00100 /***************************************************************************\ 00101 * xxxRedrawHungWindowFrame 00102 * 00103 * 00104 * 02-28-92 DavidPe Created. 00105 \***************************************************************************/ 00106 00107 VOID xxxRedrawHungWindowFrame( 00108 PWND pwnd, 00109 BOOL fActive) 00110 { 00111 HDC hdc; 00112 UINT wFlags = DC_NC | DC_NOSENDMSG; 00113 00114 CheckLock(pwnd); 00115 00116 if (fActive) 00117 wFlags |= DC_ACTIVE; 00118 00119 hdc = _GetDCEx(pwnd, NULL, DCX_USESTYLE | DCX_WINDOW); 00120 xxxDrawCaptionBar(pwnd, hdc, wFlags); 00121 _ReleaseDC(hdc); 00122 } 00123 00124 00125 /***************************************************************************\ 00126 * xxxRedrawHungWindow 00127 * 00128 * If the hrgnFullDrag is NULL, redraw the hung window's entire update region, 00129 * otherwise, only redraw the intersection of the window's update region 00130 * with the FullDrag region. 00131 * 00132 * 02-28-92 DavidPe Created. 00133 \***************************************************************************/ 00134 00135 VOID xxxRedrawHungWindow( 00136 PWND pwnd, 00137 HRGN hrgnFullDrag) 00138 { 00139 HDC hdc; 00140 HBRUSH hbr; 00141 HRGN hrgnUpdate; 00142 RECT rc; 00143 TL tlpwnd; // should remove (IanJa) 00144 UINT flags; 00145 W32PID sid; 00146 DWORD dwColor; 00147 PWND pwndDesk; 00148 TL tlpwndDesk; 00149 00150 CheckCritIn(); 00151 CheckLock(pwnd); 00152 00153 if (pwnd->hrgnUpdate == NULL) { 00154 return; 00155 } 00156 00157 #ifdef HUNGAPP_GHOSTING 00158 00159 /* 00160 * Don't bother doing anything here when the window isn't even visible. 00161 */ 00162 if (!TestWF(pwnd, WFVISIBLE)) { 00163 return; 00164 } 00165 00166 /* 00167 * This function can be called from the full-drag code to quick redraw 00168 * windows that aren't hung. In that case check if that thread is hung. 00169 */ 00170 if ((hrgnFullDrag == NULL) || (hrgnFullDrag != NULL && 00171 FHungApp(GETPTI(pwnd), CMSHUNGAPPTIMEOUT))) { 00172 SignalGhost(pwnd); 00173 } 00174 00175 #endif // HUNGAPP_GHOSTING 00176 00177 /* 00178 * First calculate hrgnUpdate. 00179 */ 00180 if (pwnd->hrgnUpdate > HRGN_FULL) { 00181 hrgnUpdate = CreateEmptyRgn(); 00182 if (hrgnUpdate == NULL) { 00183 hrgnUpdate = HRGN_FULL; 00184 00185 } else if (CopyRgn(hrgnUpdate, pwnd->hrgnUpdate) == ERROR) { 00186 GreDeleteObject(hrgnUpdate); 00187 hrgnUpdate = HRGN_FULL; 00188 } 00189 00190 } else { 00191 00192 /* 00193 * For our purposes, we need a real hrgnUpdate, so try and 00194 * create one if even if the entire window needs updating. 00195 */ 00196 CopyRect(&rc, &pwnd->rcWindow); 00197 hrgnUpdate = GreCreateRectRgnIndirect(&rc); 00198 if (hrgnUpdate == NULL) { 00199 hrgnUpdate = HRGN_FULL; 00200 } 00201 } 00202 00203 /* 00204 * If we're redrawing because we're full dragging and if the window's 00205 * update region does not intersect with the Full drag 00206 * update region, don't erase the hung window again. This is to prevent 00207 * flickering when a window has been invalidated by another window doing 00208 * full drag and hasn't received the paint message yet. 00209 * This way, only if there is a new region that has been invalidated will 00210 * we redraw the hung window. 00211 */ 00212 if (hrgnFullDrag && hrgnUpdate != HRGN_FULL && 00213 IntersectRgn(hrgnUpdate, hrgnUpdate, hrgnFullDrag) == NULLREGION) { 00214 GreDeleteObject(hrgnUpdate); 00215 return; 00216 } 00217 00218 ThreadLock(pwnd, &tlpwnd); // should remove (IanJa) 00219 00220 hdc = _GetDCEx(pwnd, hrgnUpdate, DCX_USESTYLE | DCX_WINDOW | 00221 DCX_INTERSECTRGN | DCX_NODELETERGN | DCX_LOCKWINDOWUPDATE); 00222 xxxDrawWindowFrame(pwnd, hdc, TRUE, TestwndFrameOn(pwnd)); 00223 _ReleaseDC(hdc); 00224 00225 CopyRect(&rc, &pwnd->rcWindow); 00226 xxxCalcClientRect(pwnd, &rc, TRUE); 00227 SetRectRgnIndirect(ghrgnInv2, &rc); 00228 00229 if (hrgnUpdate > HRGN_FULL) { 00230 switch (IntersectRgn(hrgnUpdate, hrgnUpdate, ghrgnInv2)) { 00231 00232 case ERROR: 00233 GreDeleteObject(hrgnUpdate); 00234 hrgnUpdate = HRGN_FULL; 00235 break; 00236 00237 case NULLREGION: 00238 /* 00239 * There is nothing in the client area to repaint. 00240 * Blow the region away, and decrement the paint count 00241 * if possible. 00242 */ 00243 GreDeleteObject(hrgnUpdate); 00244 hrgnUpdate = NULL; 00245 break; 00246 } 00247 } 00248 00249 /* 00250 * Erase the rest of the window. 00251 * When pwnd isn't WFCLIPCHILDREN, make sure valid children bits 00252 * don't get overwritten if the child is in the middle of BeginPaint 00253 * or just completed it's painting and it's hrgnUpdate is NULL. 00254 */ 00255 if (hrgnUpdate != NULL && !TestWF(pwnd, WFCLIPCHILDREN)) { 00256 RECT rcT; 00257 PWND pwndT; 00258 00259 if (hrgnUpdate == HRGN_FULL) { 00260 rc = pwnd->rcWindow; 00261 } else { 00262 GreGetRgnBox(hrgnUpdate, &rc); 00263 } 00264 00265 for (pwndT = pwnd->spwndChild; pwndT != NULL; 00266 pwndT = pwndT->spwndNext) { 00267 00268 if (TestWF(pwndT, WFVISIBLE) && 00269 (TestWF(pwndT, WFSTARTPAINT) || pwndT->hrgnUpdate == NULL) && 00270 IntersectRect(&rcT, &rc, &pwndT->rcWindow)) { 00271 00272 /* 00273 * This invalidate call won't leave the critial section. In 00274 * reality the entire xxxRedrawHungWindow must not leave 00275 * the critical section. 00276 */ 00277 BEGINATOMICCHECK(); 00278 xxxInternalInvalidate(pwndT, hrgnUpdate, RDW_INVALIDATE | 00279 RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN); 00280 ENDATOMICCHECK(); 00281 } 00282 } 00283 } 00284 00285 /* 00286 * Get a window dc so that the menu and scroll bar areas are erased 00287 * appropriately. But make sure it is clipped so that the children 00288 * get clipped out correctly! If we don't do this, this we could erase 00289 * children that aren't invalid. 00290 * 00291 * Note: DCX_WINDOW and DCX_USESTYLE will never clip out children. 00292 * Need to pass the clipping styles in directly, instead of passing 00293 * DCX_USESTYLE. 00294 */ 00295 flags = DCX_INTERSECTRGN | DCX_WINDOW | DCX_CACHE; 00296 if (TestWF(pwnd, WFCLIPSIBLINGS)) 00297 flags |= DCX_CLIPSIBLINGS; 00298 if (TestWF(pwnd, WFCLIPCHILDREN)) 00299 flags |= DCX_CLIPCHILDREN; 00300 00301 hdc = _GetDCEx(pwnd, hrgnUpdate, flags); 00302 00303 if (pwnd == pwnd->head.rpdesk->pDeskInfo->spwndBkGnd) { 00304 pwndDesk = PWNDDESKTOP(pwnd); 00305 ThreadLock(pwndDesk, &tlpwndDesk); 00306 xxxInternalPaintDesktop(PWNDDESKTOP(pwnd), hdc, TRUE); 00307 ThreadUnlock(&tlpwndDesk); 00308 00309 } else { 00310 00311 rc = pwnd->rcWindow; 00312 00313 OffsetRect(&rc, -pwnd->rcWindow.left, -pwnd->rcWindow.top); 00314 00315 /* 00316 * Erase the rest of the window using the window' class background 00317 * brush. 00318 */ 00319 if ((hbr = pwnd->pcls->hbrBackground) != NULL) { 00320 if (hbr <= (HBRUSH)COLOR_ENDCOLORS + 1) 00321 hbr = SYSHBRUSH((ULONG_PTR)hbr - 1); 00322 } else { 00323 /* 00324 * Use the window brush for windows and 3.x dialogs, 00325 * Use the COLOR3D brush for 4.x dialogs. 00326 */ 00327 if (TestWF(pwnd, WFDIALOGWINDOW) && TestWF(pwnd, WFWIN40COMPAT)) 00328 hbr = SYSHBR(3DFACE); 00329 else 00330 hbr = SYSHBR(WINDOW); 00331 } 00332 00333 /* 00334 * If the window's class background brush is public, use it. 00335 */ 00336 sid = (W32PID)GreGetObjectOwner((HOBJ)hbr, BRUSH_TYPE); 00337 if (sid == (W32PID)(ULONG_PTR)GetCurrentProcessId() || sid == OBJECT_OWNER_PUBLIC) { 00338 00339 FillRect(hdc, &rc, hbr); 00340 00341 } else { 00342 00343 /* 00344 * The window's class background brush is not public. 00345 * We get its color and set the color of our own public brush and use 00346 * that for the background brush. 00347 */ 00348 00349 /* 00350 * If the window is a console window, get the console background brush. 00351 * This brush will be different than the console class brush if the user 00352 * changed the console background color. 00353 */ 00354 if (gatomConsoleClass == pwnd->pcls->atomClassName) { 00355 00356 dwColor = _GetWindowLong(pwnd, GWL_CONSOLE_BKCOLOR); 00357 00358 } else { 00359 00360 if ((dwColor = GreGetBrushColor(hbr)) == -1) 00361 dwColor = GreGetBrushColor(SYSHBR(WINDOW)); 00362 } 00363 00364 GreSetSolidBrush(ghbrHungApp, dwColor); 00365 00366 FillRect(hdc, &rc, ghbrHungApp); 00367 } 00368 } 00369 _ReleaseDC(hdc); 00370 00371 /* 00372 * The window has been erased and framed. It only did this because the 00373 * app hasn't done it yet: 00374 * 00375 * - the app hasn't erased and frame yet. 00376 * - the app is in the middle of erasing and framing. 00377 * 00378 * The app could not of completed erasing and framing, because the 00379 * WFREDRAWIFHUNG bit is cleared when this successfully completes. 00380 * 00381 * Given that the app may be in the middle of erasing and framing, we 00382 * need to set both the erase and frame bits *again* so it erasing and 00383 * frames over again (if we don't, it never will). If the app hasn't 00384 * done any erasing/framing yet, this is a nop. 00385 */ 00386 SetWF(pwnd, WFSENDNCPAINT); 00387 SetWF(pwnd, WFSENDERASEBKGND); 00388 00389 /* 00390 * Always set WFUPDATEDIRTY: we don't want the app to draw, then stop 00391 * and have the hung app thread draw, and then allow the app to validate 00392 * itself: Mark the update region dirty - cannot be validated until the 00393 * app calls a painting function and acknowledges the update region. 00394 */ 00395 SetWF(pwnd, WFUPDATEDIRTY); 00396 00397 #ifdef WIN95DOESTHIS 00398 /* 00399 * Go through all the children and redraw hung ones too. 00400 */ 00401 if (hrgnFullDrag != NULL) { 00402 PWND pwndT; 00403 TL tlpwndT; 00404 00405 pwndT = pwnd->spwndChild; 00406 ThreadLockNever(&tlpwndT); 00407 while (pwndT) { 00408 00409 if ( TestWF(pwndT, WFREDRAWIFHUNG) && 00410 FHungApp(GETPTI(pwndT), CMSHUNGAPPTIMEOUT)) { 00411 00412 ClearHungFlag(pwndT, WFREDRAWIFHUNG); 00413 ThreadLockExchangeAlways(pwndT, &tlpwndT); 00414 xxxRedrawHungWindow(pwndT, NULL); 00415 } 00416 00417 if (TestWF(pwndT, WFDESTROYED)) { 00418 break; 00419 } 00420 00421 pwndT = pwndT->spwndNext; 00422 } 00423 00424 ThreadUnlock(&tlpwndT); 00425 } 00426 #endif 00427 00428 ThreadUnlock(&tlpwnd); // should remove (IanJa) 00429 } 00430 00431 00432 /***************************************************************************\ 00433 * xxxHungAppDemon 00434 * 00435 * NOTE: RIT timers (like this one) get called while inside an EnterCrit block. 00436 * 00437 * We keep a list of redraw-if-hung windows in a list that remains in a 00438 * single page to avoid touching the windows themselves each time through 00439 * this routine. Touching the windows causes a bunch of unnecessary paging 00440 * and in effect keeps all of the pages that contain top-level windows 00441 * resident at all times; this is very wasteful. 00442 * 00443 * 02-28-92 DavidPe Created. 00444 \***************************************************************************/ 00445 00446 VOID xxxHungAppDemon( 00447 PWND pwnd, 00448 UINT message, 00449 UINT_PTR nID, 00450 LPARAM lParam) 00451 { 00452 TL tlpwnd; 00453 #if DBG 00454 PWND pwndT; 00455 #endif 00456 DWORD nPwndHungRedraw; 00457 PWND pwndHungRedraw; 00458 00459 00460 00461 UNREFERENCED_PARAMETER(message); 00462 UNREFERENCED_PARAMETER(nID); 00463 00464 UNREFERENCED_PARAMETER(lParam); 00465 UNREFERENCED_PARAMETER(pwnd); 00466 CheckLock(pwnd); 00467 00468 /* 00469 * See if we should start the screen saver. 00470 */ 00471 IdleTimerProc(); 00472 00473 /* 00474 * If it is time to hide the app starting cursor, do it. 00475 */ 00476 if (NtGetTickCount() >= gtimeStartCursorHide) { 00477 /* 00478 * No need to DeferWinEventNotify() 00479 */ 00480 zzzCalcStartCursorHide(NULL, 0); 00481 } 00482 00483 /* 00484 * Now check to see if there are any top-level 00485 * windows that need redrawing. 00486 */ 00487 if (grpdeskRitInput == NULL || grpdeskRitInput->pDeskInfo->spwnd == NULL) 00488 return; 00489 00490 /* 00491 * Walk down the list of redraw-if-hung windows. Loop 00492 * until we hit the end of the array or find a NULL. 00493 */ 00494 nPwndHungRedraw = 0; 00495 pwndHungRedraw = NULL; 00496 while (pwndHungRedraw = VWPLNext(gpvwplHungRedraw, pwndHungRedraw, &nPwndHungRedraw)) { 00497 /* 00498 * See if the app is hung. If so, do the appropriate 00499 * redrawing. 00500 */ 00501 if (FHungApp(GETPTI(pwndHungRedraw), CMSHUNGAPPTIMEOUT)) { 00502 ThreadLock(pwndHungRedraw, &tlpwnd); 00503 if (TestWF(pwndHungRedraw, WFREDRAWFRAMEIFHUNG)) { 00504 00505 /* 00506 * WFREDRAWFRAMEIFHUNG will be cleared in the process 00507 * of drawing the frame, no need to clear it here. 00508 */ 00509 xxxRedrawHungWindowFrame(pwndHungRedraw, TestwndFrameOn(pwndHungRedraw)); 00510 } 00511 00512 if (TestWF(pwndHungRedraw, WFREDRAWIFHUNG)) { 00513 ClearHungFlag(pwndHungRedraw, WFREDRAWIFHUNG); 00514 xxxRedrawHungWindow(pwndHungRedraw, NULL); 00515 } 00516 #if DBG 00517 pwndT = 00518 #endif 00519 00520 ThreadUnlock(&tlpwnd); 00521 } 00522 } 00523 00524 return; 00525 }

Generated on Sat May 15 19:40:18 2004 for test by doxygen 1.3.7