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

paint.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: paint.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * This module contains the APIs used to begin and end window painting. 00007 * 00008 * History: 00009 * 27-Oct-1990 DarrinM Created. 00010 * 12-Feb-1991 IanJa HWND revalidation added 00011 \***************************************************************************/ 00012 00013 #include "precomp.h" 00014 #pragma hdrstop 00015 00016 /***************************************************************************\ 00017 * xxxFillWindow (not an API) 00018 * 00019 * pwndBrush - The brush is aligned with with client rect of this window. 00020 * It is usually either pwndPaint or pwndPaint's parent. 00021 * 00022 * pwndPaint - The window to paint. 00023 * hdc - The DC to paint in. 00024 * hbr - The brush to use. 00025 * 00026 * Returns TRUE if successful, FALSE if not. 00027 * 00028 * History: 00029 * 15-Nov-1990 DarrinM Ported from Win 3.0 sources. 00030 * 21-Jan-1991 IanJa Prefix '_' denoting exported function. 00031 \***************************************************************************/ 00032 00033 BOOL xxxFillWindow( 00034 PWND pwndBrush, 00035 PWND pwndPaint, 00036 HDC hdc, 00037 HBRUSH hbr) 00038 { 00039 RECT rc; 00040 00041 CheckLock(pwndBrush); 00042 CheckLock(pwndPaint); 00043 00044 /* 00045 * If there is no pwndBrush (sometimes the parent), use pwndPaint. 00046 */ 00047 if (pwndBrush == NULL) 00048 pwndBrush = pwndPaint; 00049 00050 if (UT_GetParentDCClipBox(pwndPaint, hdc, &rc)) 00051 return xxxPaintRect(pwndBrush, pwndPaint, hdc, hbr, &rc); 00052 00053 return TRUE; 00054 } 00055 00056 /***************************************************************************\ 00057 * xxxPaintRect 00058 * 00059 * pwndBrush - The brush is aligned with with client rect of this window. 00060 * It is usually either pwndPaint or pwndPaint's parent. 00061 * 00062 * pwndPaint - The window to paint in. 00063 * hdc - The DC to paint in. 00064 * hbr - The brush to use. 00065 * lprc - The rectangle to paint. 00066 * 00067 * History: 00068 * 15-Nov-1990 DarrinM Ported from Win 3.0 sources. 00069 * 21-Jan-1991 IanJa Prefix '_' denoting exported function. 00070 \***************************************************************************/ 00071 00072 BOOL xxxPaintRect( 00073 PWND pwndBrush, 00074 PWND pwndPaint, 00075 HDC hdc, 00076 HBRUSH hbr, 00077 LPRECT lprc) 00078 { 00079 POINT ptOrg; 00080 00081 CheckLock(pwndBrush); 00082 CheckLock(pwndPaint); 00083 00084 if (pwndBrush == NULL) { 00085 pwndBrush = PtiCurrent()->rpdesk->pDeskInfo->spwnd; 00086 } 00087 00088 if (pwndBrush == PWNDDESKTOP(pwndBrush)) { 00089 GreSetBrushOrg( 00090 hdc, 00091 0, 00092 0, 00093 &ptOrg); 00094 } else { 00095 GreSetBrushOrg( 00096 hdc, 00097 pwndBrush->rcClient.left - pwndPaint->rcClient.left, 00098 pwndBrush->rcClient.top - pwndPaint->rcClient.top, 00099 &ptOrg); 00100 } 00101 00102 /* 00103 * If hbr < CTLCOLOR_MAX, it isn't really a brush but is one of our 00104 * special color values. Translate it to the appropriate WM_CTLCOLOR 00105 * message and send it off to get back a real brush. The translation 00106 * process assumes the CTLCOLOR*** and WM_CTLCOLOR*** values map directly. 00107 */ 00108 if (hbr < (HBRUSH)CTLCOLOR_MAX) { 00109 hbr = xxxGetControlColor(pwndBrush, 00110 pwndPaint, 00111 hdc, 00112 HandleToUlong(hbr) + WM_CTLCOLORMSGBOX); 00113 } 00114 00115 FillRect(hdc, lprc, hbr); 00116 00117 GreSetBrushOrg(hdc, ptOrg.x, ptOrg.y, NULL); 00118 00119 00120 return TRUE; 00121 } 00122 00123 /***************************************************************************\ 00124 * DeleteMaybeSpecialRgn 00125 * 00126 * Deletes a GDI region, making sure it is not a special region. 00127 * 00128 * History: 00129 * 26-Feb-1992 MikeKe from win3.1 00130 \***************************************************************************/ 00131 00132 VOID DeleteMaybeSpecialRgn( 00133 HRGN hrgn) 00134 { 00135 if (hrgn > HRGN_SPECIAL_LAST) { 00136 GreDeleteObject(hrgn); 00137 } 00138 } 00139 00140 00141 00142 /***************************************************************************\ 00143 * GetNCUpdateRgn 00144 * 00145 * Gets the update region which includes the non-client area. 00146 * 00147 * History: 00148 * 26-Feb-1992 MikeKe From win3.1 00149 \***************************************************************************/ 00150 00151 HRGN GetNCUpdateRgn( 00152 PWND pwnd, 00153 BOOL fValidateFrame) 00154 { 00155 HRGN hrgnUpdate; 00156 00157 if (pwnd->hrgnUpdate > HRGN_FULL) { 00158 00159 /* 00160 * We must make a copy of our update region, because 00161 * it could change if we send a message, and we want to 00162 * make sure the whole thing is used for drawing our 00163 * frame and background. We can't use a global 00164 * temporary region, because more than one app may 00165 * be calling this routine. 00166 */ 00167 hrgnUpdate = CreateEmptyRgnPublic(); 00168 00169 if (hrgnUpdate == NULL) { 00170 hrgnUpdate = HRGN_FULL; 00171 } else if (CopyRgn(hrgnUpdate, pwnd->hrgnUpdate) == ERROR) { 00172 GreDeleteObject(hrgnUpdate); 00173 hrgnUpdate = HRGN_FULL; 00174 } 00175 00176 if (fValidateFrame) { 00177 00178 /* 00179 * Now that we've taken care of any frame drawing, 00180 * intersect the update region with the window's 00181 * client area. Otherwise, apps that do ValidateRects() 00182 * to draw themselves (e.g., WinWord) won't ever 00183 * subtract off the part of the update region that 00184 * overlaps the frame but not the client. 00185 */ 00186 CalcWindowRgn(pwnd, ghrgnInv2, TRUE); 00187 00188 switch (IntersectRgn(pwnd->hrgnUpdate, 00189 pwnd->hrgnUpdate, 00190 ghrgnInv2)) { 00191 case ERROR: 00192 /* 00193 * If an error occured, we can't leave things as 00194 * they are: invalidate the whole window and let 00195 * BeginPaint() take care of it. 00196 */ 00197 GreDeleteObject(pwnd->hrgnUpdate); 00198 pwnd->hrgnUpdate = HRGN_FULL; 00199 break; 00200 00201 case NULLREGION: 00202 /* 00203 * There is nothing in the client area to repaint. 00204 * Blow the region away, and decrement the paint count 00205 * if possible. 00206 */ 00207 GreDeleteObject(pwnd->hrgnUpdate); 00208 pwnd->hrgnUpdate = NULL; 00209 ClrWF(pwnd, WFUPDATEDIRTY); 00210 if (!TestWF(pwnd, WFINTERNALPAINT)) 00211 DecPaintCount(pwnd); 00212 break; 00213 } 00214 } 00215 00216 } else { 00217 hrgnUpdate = pwnd->hrgnUpdate; 00218 } 00219 00220 return hrgnUpdate; 00221 } 00222 00223 /***************************************************************************\ 00224 * xxxSendNCPaint 00225 * 00226 * Sends a WM_NCPAINT message to a window. 00227 * 00228 * History: 00229 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 00230 \***************************************************************************/ 00231 00232 VOID xxxSendNCPaint( 00233 PWND pwnd, 00234 HRGN hrgnUpdate) 00235 { 00236 CheckLock(pwnd); 00237 00238 /* 00239 * Clear the WFSENDNCPAINT bit... 00240 */ 00241 ClrWF(pwnd, WFSENDNCPAINT); 00242 00243 /* 00244 * If the window is active, but its FRAMEON bit hasn't 00245 * been set yet, set it and make sure that the entire frame 00246 * gets redrawn when we send the NCPAINT. 00247 */ 00248 if ((pwnd == PtiCurrent()->pq->spwndActive) && !TestWF(pwnd, WFFRAMEON)) { 00249 SetWF(pwnd, WFFRAMEON); 00250 hrgnUpdate = HRGN_FULL; 00251 ClrWF(pwnd, WFNONCPAINT); 00252 } 00253 00254 /* 00255 * If PixieHack() has set the WM_NCPAINT bit, we must be sure 00256 * to send with hrgnClip == HRGN_FULL. (see PixieHack() in wmupdate.c) 00257 */ 00258 if (TestWF(pwnd, WFPIXIEHACK)) { 00259 ClrWF(pwnd, WFPIXIEHACK); 00260 hrgnUpdate = HRGN_FULL; 00261 } 00262 00263 if (hrgnUpdate) 00264 xxxSendMessage(pwnd, WM_NCPAINT, (WPARAM)hrgnUpdate, 0L); 00265 } 00266 00267 00268 00269 /***************************************************************************\ 00270 * xxxSendChildNCPaint 00271 * 00272 * Sends WM_NCPAINT message to the immediate children of a window. 00273 * 00274 * History: 00275 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 00276 \***************************************************************************/ 00277 00278 VOID xxxSendChildNCPaint( 00279 PWND pwnd) 00280 { 00281 TL tlpwnd; 00282 00283 CheckLock(pwnd); 00284 00285 ThreadLockNever(&tlpwnd); 00286 pwnd = pwnd->spwndChild; 00287 while (pwnd != NULL) { 00288 if ((pwnd->hrgnUpdate == NULL) && TestWF(pwnd, WFSENDNCPAINT)) { 00289 ThreadLockExchangeAlways(pwnd, &tlpwnd); 00290 xxxSendNCPaint(pwnd, HRGN_FULL); 00291 } 00292 00293 pwnd = pwnd->spwndNext; 00294 } 00295 00296 ThreadUnlock(&tlpwnd); 00297 } 00298 00299 /***************************************************************************\ 00300 * xxxBeginPaint 00301 * 00302 * Revalidation Note: 00303 * We MUST return NULL if the window is deleted during xxxBeginPaint because 00304 * its DCs are released upon deletion, and we shouldn't return a *released* DC! 00305 * 00306 * History: 00307 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 00308 \***************************************************************************/ 00309 00310 HDC xxxBeginPaint( 00311 PWND pwnd, 00312 LPPAINTSTRUCT lpps) 00313 { 00314 HRGN hrgnUpdate; 00315 HDC hdc; 00316 BOOL fSendEraseBkgnd; 00317 00318 CheckLock(pwnd); 00319 UserAssert(IsWinEventNotifyDeferredOK()); 00320 00321 if (TEST_PUDF(PUDF_DRAGGINGFULLWINDOW)) 00322 SetWF(pwnd, WFSTARTPAINT); 00323 00324 /* 00325 * We're processing a WM_PAINT message: clear this flag. 00326 */ 00327 ClrWF(pwnd, WFPAINTNOTPROCESSED); 00328 00329 /* 00330 * If this bit gets set while we are drawing the frame we will need 00331 * to redraw it. 00332 * 00333 * If necessary, send our WM_NCPAINT message now. 00334 * 00335 * please heed these notes 00336 * 00337 * We have to send this message BEFORE we diddle hwnd->hrgnUpdate, 00338 * because an app may call ValidateRect or InvalidateRect in its 00339 * handler, and it expects what it does to affect what gets drawn 00340 * in the later WM_PAINT. 00341 * 00342 * It is possible to get an invalidate when we leave the critical 00343 * section below, therefore we loop until UPDATEDIRTY is clear 00344 * meaning there were no additional invalidates. 00345 */ 00346 if (TestWF(pwnd, WFSENDNCPAINT)) { 00347 00348 do { 00349 ClrWF(pwnd, WFUPDATEDIRTY); 00350 hrgnUpdate = GetNCUpdateRgn(pwnd, FALSE); 00351 xxxSendNCPaint(pwnd, hrgnUpdate); 00352 DeleteMaybeSpecialRgn(hrgnUpdate); 00353 } while (TestWF(pwnd, WFUPDATEDIRTY)); 00354 00355 } else { 00356 ClrWF(pwnd, WFUPDATEDIRTY); 00357 } 00358 00359 /* 00360 * Hide the caret if needed. Do this before we get the DC so 00361 * that if HideCaret() gets and releases a DC we will be able 00362 * to reuse it later here. 00363 * No need to DeferWinEventNotify() since pwnd is locked. 00364 */ 00365 if (pwnd == PtiCurrent()->pq->caret.spwnd) 00366 zzzInternalHideCaret(); 00367 00368 /* 00369 * Send the check for sending an WM_ERASEBKGND to the 00370 * window. 00371 */ 00372 if (fSendEraseBkgnd = TestWF(pwnd, WFSENDERASEBKGND)) { 00373 ClrWF(pwnd, WFERASEBKGND); 00374 ClrWF(pwnd, WFSENDERASEBKGND); 00375 } 00376 00377 /* 00378 * Validate the entire window. 00379 */ 00380 if (NEEDSPAINT(pwnd)) 00381 DecPaintCount(pwnd); 00382 00383 ClrWF(pwnd, WFINTERNALPAINT); 00384 00385 hrgnUpdate = pwnd->hrgnUpdate; 00386 pwnd->hrgnUpdate = NULL; 00387 00388 if (TestWF(pwnd, WFDONTVALIDATE)) { 00389 00390 if (ghrgnUpdateSave == NULL) { 00391 ghrgnUpdateSave = CreateEmptyRgn(); 00392 } 00393 00394 if (ghrgnUpdateSave != NULL) { 00395 UnionRgn(ghrgnUpdateSave, ghrgnUpdateSave, hrgnUpdate); 00396 gnUpdateSave++; 00397 } 00398 } 00399 00400 /* 00401 * Clear these flags for backward compatibility 00402 */ 00403 lpps->fIncUpdate = 00404 lpps->fRestore = FALSE; 00405 00406 lpps->hdc = 00407 hdc = _GetDCEx(pwnd, 00408 hrgnUpdate, 00409 DCX_USESTYLE | DCX_INTERSECTRGN); 00410 00411 if (UT_GetParentDCClipBox(pwnd, hdc, &lpps->rcPaint)) { 00412 00413 /* 00414 * If necessary, erase our background, and possibly deal with 00415 * our children's frames and backgrounds. 00416 */ 00417 if (fSendEraseBkgnd) 00418 xxxSendEraseBkgnd(pwnd, hdc, hrgnUpdate); 00419 } 00420 00421 /* 00422 * Now that we're completely erased, see if there are any children 00423 * that couldn't draw their own frames because their update regions 00424 * got deleted. 00425 */ 00426 xxxSendChildNCPaint(pwnd); 00427 00428 /* 00429 * The erase and frame operation has occured. Clear the WFREDRAWIFHUNG 00430 * bit here. We don't want to clear it until we know the erase and 00431 * frame has occured, so we know we always have a consistent looking 00432 * window. 00433 */ 00434 ClearHungFlag(pwnd, WFREDRAWIFHUNG); 00435 00436 lpps->fErase = (TestWF(pwnd, WFERASEBKGND) != 0); 00437 00438 return hdc; 00439 } 00440 00441 /***************************************************************************\ 00442 * xxxEndPaint (API) 00443 * 00444 * 00445 * History: 00446 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 00447 \***************************************************************************/ 00448 00449 BOOL xxxEndPaint( 00450 PWND pwnd, 00451 LPPAINTSTRUCT lpps) 00452 { 00453 CheckLock(pwnd); 00454 00455 ReleaseCacheDC(lpps->hdc, TRUE); 00456 00457 if (TestWF(pwnd, WFDONTVALIDATE)) { 00458 00459 if (ghrgnUpdateSave != NULL) { 00460 00461 InternalInvalidate3(pwnd, 00462 ghrgnUpdateSave, 00463 RDW_INVALIDATE | RDW_ERASE); 00464 00465 if (--gnUpdateSave == 0) { 00466 GreDeleteObject(ghrgnUpdateSave); 00467 ghrgnUpdateSave = NULL; 00468 } 00469 } 00470 00471 ClrWF(pwnd, WFDONTVALIDATE); 00472 } 00473 00474 ClrWF(pwnd, WFWMPAINTSENT); 00475 00476 /* 00477 * This used to check that the update-region was empty before 00478 * doing the clear. However, this caused a problem with WOW 00479 * amipro/approach hanging. They were invalidating rects in 00480 * their WM_PAINT handler, and allowing the defwindowproc to 00481 * perform the validation for them. Since we were blocking 00482 * the BeginPaint in this case, it sent them into a infinite 00483 * loop (see bug 19036). 00484 */ 00485 ClrWF(pwnd, WFSTARTPAINT); 00486 00487 /* 00488 * Reshow the caret if needed, but AFTER we've released the DC. 00489 * This way ShowCaret() can reuse the DC we just released. 00490 */ 00491 if (pwnd == PtiCurrent()->pq->caret.spwnd) 00492 zzzInternalShowCaret(); 00493 00494 return TRUE; 00495 } 00496 00497 /***************************************************************************\ 00498 * InternalDoPaint 00499 * 00500 * Return a window equal to or below pwnd, created by the current thread, 00501 * which needs painting. 00502 * 00503 * pwnd - Window to start searching from. Search is depth first. 00504 * ptiCurrent - The current thread. 00505 * 00506 * History: 00507 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 00508 \***************************************************************************/ 00509 00510 PWND InternalDoPaint( 00511 PWND pwnd, 00512 PTHREADINFO ptiCurrent) 00513 { 00514 PWND pwndT; 00515 00516 /* 00517 * Enumerate all windows, top-down, looking for one that 00518 * needs repainting. Skip windows of other tasks. 00519 */ 00520 for ( ; pwnd != NULL; pwnd = pwnd->spwndNext) { 00521 00522 if (GETPTI(pwnd) == ptiCurrent) { 00523 00524 if (NEEDSPAINT(pwnd)) { 00525 00526 /* 00527 * If this window is transparent, we don't want to 00528 * send it a WM_PAINT until all its siblings below it 00529 * have been repainted. If we find an unpainted sibling 00530 * below, return it instead. 00531 */ 00532 if (TestWF(pwnd, WEFTRANSPARENT)) { 00533 00534 pwndT = pwnd; 00535 while ((pwndT = pwndT->spwndNext) != NULL) { 00536 00537 /* 00538 * Make sure sibling window belongs to same app 00539 */ 00540 if ((GETPTI(pwndT) == ptiCurrent) && NEEDSPAINT(pwndT)) { 00541 00542 if (TestWF(pwndT, WEFTRANSPARENT)) 00543 continue; 00544 00545 return pwndT; 00546 } 00547 } 00548 } 00549 00550 return pwnd; 00551 } 00552 } 00553 00554 if (pwnd->spwndChild && 00555 (pwndT = InternalDoPaint(pwnd->spwndChild, ptiCurrent))) { 00556 00557 return pwndT; 00558 } 00559 } 00560 00561 return pwnd; 00562 } 00563 00564 /***************************************************************************\ 00565 * DoPaint 00566 * 00567 * Looks at all the desktops for the window needing a paint and places a 00568 * WM_PAINT in its queue. 00569 * 00570 * History: 00571 * 16-Jul-91 DarrinM Ported from Win 3.1 sources. 00572 \***************************************************************************/ 00573 00574 BOOL DoPaint( 00575 PWND pwndFilter, 00576 LPMSG lpMsg) 00577 { 00578 PWND pwnd; 00579 PWND pwndT; 00580 PTHREADINFO ptiCurrent = PtiCurrent(); 00581 00582 00583 #if 0 // CHRISWIL: WIN95 SPECIFIC 00584 00585 /* 00586 * If there is a system modal up and it is attached to another task, 00587 * DON'T do paints. We don't want to return a message for a window in 00588 * another task! 00589 */ 00590 if (hwndSysModal && (hwndSysModal->hq != hqCurrent)) { 00591 00592 /* 00593 * Poke this guy so he wakes up at some point in the future, 00594 * otherwise he may never wake up to realize he should paint. 00595 * Causes hangs - e.g. Photoshop installation program 00596 * PostThreadMessage32(Lpq(hqCurrent)->idThread, WM_NULL, 0, 0, 0); 00597 */ 00598 return FALSE; 00599 } 00600 00601 #endif 00602 00603 /* 00604 * If this is a system thread, then walk the windowstation desktop-list 00605 * to find the window which needs painting. For other threads, we 00606 * reference off the thread-desktop. 00607 */ 00608 if (ptiCurrent->TIF_flags & TIF_SYSTEMTHREAD) { 00609 00610 PWINDOWSTATION pwinsta; 00611 PDESKTOP pdesk; 00612 00613 if ((pwinsta = ptiCurrent->pwinsta) == NULL) { 00614 RIPMSG0(RIP_ERROR, "DoPaint: SYSTEMTHREAD does not have (pwinsta)"); 00615 return FALSE; 00616 } 00617 00618 pwnd = NULL; 00619 for(pdesk = pwinsta->rpdeskList; pdesk; pdesk = pdesk->rpdeskNext) { 00620 00621 if (pwnd = InternalDoPaint(pdesk->pDeskInfo->spwnd, ptiCurrent)) 00622 break; 00623 } 00624 00625 } else { 00626 pwnd = InternalDoPaint(ptiCurrent->rpdesk->pDeskInfo->spwnd, 00627 ptiCurrent); 00628 } 00629 00630 if (pwnd != NULL) { 00631 00632 if (!CheckPwndFilter(pwnd, pwndFilter)) 00633 return FALSE; 00634 00635 /* 00636 * We're returning a WM_PAINT message, so clear WFINTERNALPAINT so 00637 * it won't get sent again later. 00638 */ 00639 if (TestWF(pwnd, WFINTERNALPAINT)) { 00640 00641 ClrWF(pwnd, WFINTERNALPAINT); 00642 00643 /* 00644 * If there is no update region, then no more paint for this 00645 * window. 00646 */ 00647 if (pwnd->hrgnUpdate == NULL) 00648 DecPaintCount(pwnd); 00649 } 00650 00651 /* 00652 * Set the STARTPAINT so that any other calls to BeginPaint while 00653 * painting is begin performed, will prevent painting on those 00654 * windows. 00655 * 00656 * Clear the UPDATEDIRTY since some apps (DBFast) don't call 00657 * GetUpdateRect, BeginPaint/EndPaint. 00658 */ 00659 ClrWF(pwnd, WFSTARTPAINT); 00660 ClrWF(pwnd, WFUPDATEDIRTY); 00661 00662 /* 00663 * If we get an invalidate between now and the time the app calls 00664 * BeginPaint() and the windows parent is not CLIPCHILDREN, then 00665 * the parent will paint in the wrong order. So we are going to 00666 * cause the child to paint again. Look in beginpaint and internal 00667 * invalidate for other parts of this fix. 00668 * 00669 * Set a flag to signify that we are in the bad zone. 00670 * 00671 * Must go up the parent links to make sure all parents have 00672 * WFCLIPCHILDREN set otherwise set the WFWMPAINTSENT flag. 00673 * This is to fix Excel spreadsheet and fulldrag. The speadsheet 00674 * parent window (class XLDESK) has WFCLIPCHILDREN set but it's 00675 * parent (class XLMAIN) doesn't. So the main window erases the 00676 * background after the child window paints. 00677 * 00678 * JOHANNEC : 27-Jul-1994 00679 */ 00680 00681 /* 00682 * NT Bug 400167: As we walk up the tree, we need to stop short of 00683 * desktop windows and mother desktop windows. We can't do a test 00684 * for WFCLIPCHILDREN on the mother desktop window's parent because 00685 * it doesn't exist. This means that no desktop window will get 00686 * WFWMPAINTSENT set, but the message window will be able to get 00687 * WFWMPAINTSENT set. 00688 */ 00689 00690 pwndT = pwnd; 00691 while (pwndT && (GETFNID(pwndT) != FNID_DESKTOP)) { 00692 00693 if (!TestWF(pwndT->spwndParent, WFCLIPCHILDREN)) { 00694 SetWF(pwnd, WFWMPAINTSENT); 00695 break; 00696 } 00697 00698 pwndT = pwndT->spwndParent; 00699 } 00700 00701 /* 00702 * If the top level "tiled" owner/parent of this window is iconed, 00703 * send a WM_PAINTICON rather than a WM_PAINT. The wParam 00704 * is TRUE if this is the tiled window and FALSE if it is a 00705 * child/owned popup of the minimized window. 00706 * 00707 * BACKWARD COMPATIBILITY HACK 00708 * 00709 * 3.0 sent WM_PAINTICON with wParam == TRUE for no apparent 00710 * reason. Lotus Notes 2.1 depends on this for some reason 00711 * to properly change its icon when new mail arrives. 00712 */ 00713 if (!TestWF(pwnd, WFWIN40COMPAT) && 00714 TestWF(pwnd, WFMINIMIZED) && 00715 (pwnd->pcls->spicn != NULL)) { 00716 00717 StoreMessage(lpMsg, pwnd, WM_PAINTICON, (DWORD)TRUE, 0L, 0L); 00718 00719 } else { 00720 00721 StoreMessage(lpMsg, pwnd, WM_PAINT, 0, 0L, 0L); 00722 } 00723 00724 return TRUE; 00725 } 00726 00727 return FALSE; 00728 } 00729 00730 /***************************************************************************\ 00731 * xxxSimpleDoSyncPaint 00732 * 00733 * Process the sync-paint for this window. This can send either a NCPAINT 00734 * or an ERASEBKGND. This assumes no recursion and flags == 0. 00735 * 00736 * History: 00737 * 26-Oct-1993 MikeKe Created 00738 \***************************************************************************/ 00739 00740 VOID xxxSimpleDoSyncPaint( 00741 PWND pwnd) 00742 { 00743 HRGN hrgnUpdate; 00744 DWORD flags = 0; 00745 00746 CheckLock(pwnd); 00747 00748 /* 00749 * Since we're taking care of the frame drawing, we can consider 00750 * this WM_PAINT message processed. 00751 */ 00752 ClrWF(pwnd, WFPAINTNOTPROCESSED); 00753 00754 /* 00755 * Make copies of these flags, because their state might 00756 * change after we send a message, and we don't want 00757 * to "lose" them. 00758 */ 00759 if (TestWF(pwnd, WFSENDNCPAINT)) 00760 flags |= DSP_FRAME; 00761 00762 if (TestWF(pwnd, WFSENDERASEBKGND)) 00763 flags |= DSP_ERASE; 00764 00765 if (flags & (DSP_ERASE | DSP_FRAME)) { 00766 00767 if (!TestWF(pwnd, WFVISIBLE)) { 00768 00769 /* 00770 * If there is no update region, just clear the bits. 00771 */ 00772 ClrWF(pwnd, WFSENDNCPAINT); 00773 ClrWF(pwnd, WFSENDERASEBKGND); 00774 ClrWF(pwnd, WFPIXIEHACK); 00775 ClrWF(pwnd, WFERASEBKGND); 00776 ClearHungFlag(pwnd, WFREDRAWIFHUNG); 00777 00778 } else { 00779 00780 PTHREADINFO ptiCurrent = PtiCurrent(); 00781 00782 /* 00783 * If there is no update region, we don't have to 00784 * do any erasing, but we may need to send an NCPAINT. 00785 */ 00786 if (pwnd->hrgnUpdate == NULL) { 00787 ClrWF(pwnd, WFSENDERASEBKGND); 00788 ClrWF(pwnd, WFERASEBKGND); 00789 flags &= ~DSP_ERASE; 00790 } 00791 00792 /* 00793 * Only mess with windows owned by the current thread. 00794 * NOTE: This means that WM_NCPAINT and WM_ERASEBKGND are 00795 * only sent intra-thread. 00796 */ 00797 if (GETPTI(pwnd) == ptiCurrent) { 00798 00799 hrgnUpdate = GetNCUpdateRgn(pwnd, TRUE); 00800 00801 if (flags & DSP_FRAME) { 00802 00803 /* 00804 * If the message got sent before we got here then do 00805 * nothing. 00806 */ 00807 if (TestWF(pwnd, WFSENDNCPAINT)) 00808 xxxSendNCPaint(pwnd, hrgnUpdate); 00809 } 00810 00811 if (flags & DSP_ERASE) { 00812 00813 if (TestWF(pwnd, WFSENDNCPAINT)) { 00814 /* 00815 * If we got another invalidate during the NCPAINT 00816 * callback get the new update region 00817 */ 00818 DeleteMaybeSpecialRgn(hrgnUpdate); 00819 hrgnUpdate = GetNCUpdateRgn(pwnd, FALSE); 00820 } 00821 00822 /* 00823 * If the message got sent before we got here 00824 * (e.g.: an UpdateWindow() inside WM_NCPAINT handler, 00825 * for example), don't do anything. 00826 * 00827 * WINPROJ.EXE (version 1.0) calls UpdateWindow() in 00828 * the WM_NCPAINT handlers for its subclassed listboxes 00829 * in the open dialog. 00830 */ 00831 if (TestWF(pwnd, WFSENDERASEBKGND)) { 00832 ClrWF(pwnd, WFSENDERASEBKGND); 00833 ClrWF(pwnd, WFERASEBKGND); 00834 xxxSendEraseBkgnd(pwnd, NULL, hrgnUpdate); 00835 } 00836 00837 /* 00838 * The erase and frame operation has occured. Clear the 00839 * WFREDRAWIFHUNG bit here. We don't want to clear it until we 00840 * know the erase and frame has occured, so we know we always 00841 * have a consistent looking window. 00842 */ 00843 ClearHungFlag(pwnd, WFREDRAWIFHUNG); 00844 } 00845 00846 DeleteMaybeSpecialRgn(hrgnUpdate); 00847 00848 } else if (!TestwndChild(pwnd) && 00849 (pwnd != grpdeskRitInput->pDeskInfo->spwnd) && 00850 FHungApp(GETPTI(pwnd), CMSHUNGAPPTIMEOUT) && 00851 TestWF(pwnd, WFREDRAWIFHUNG)) { 00852 00853 ClearHungFlag(pwnd, WFREDRAWIFHUNG); 00854 xxxRedrawHungWindow(pwnd, NULL); 00855 } 00856 } 00857 } 00858 } 00859 00860 /***************************************************************************\ 00861 * xxxInternalDoSyncPaint 00862 * 00863 * Mostly the same functionality as the old xxxDoSyncPaint. 00864 * 00865 * 00866 * This function is called to erase the background of a window, and 00867 * possibly frame and erase the children too. 00868 * 00869 * WM_SYNCPAINT(wParam)/DoSyncPaint(flags) values: 00870 * 00871 * DSP_ERASE - Erase background 00872 * DSP_FRAME - Draw child frames 00873 * DSP_ENUMCLIPPEDCHILDREN - Recurse if children are clipped 00874 * DSP_NOCHECKPARENTS - Don't check 00875 * 00876 * 00877 * Normally, only the DSP_ENUMCLIPPEDCHILDREN bit of flags is 00878 * significant on entry. If DSP_WM_SYNCPAINT is set, then hrgnUpdate 00879 * and the rest of the flags bits are valid. 00880 * 00881 * History: 00882 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 00883 \***************************************************************************/ 00884 00885 VOID xxxInternalDoSyncPaint( 00886 PWND pwnd, 00887 DWORD flags) 00888 { 00889 CheckLock(pwnd); 00890 00891 /* 00892 * Do the paint for this window. 00893 */ 00894 xxxSimpleDoSyncPaint(pwnd); 00895 00896 /* 00897 * Normally we like to enumerate all of this window's children and have 00898 * them erase their backgrounds synchronously. However, this is a bad 00899 * thing to do if the window is NOT CLIPCHLIDREN. Here's the scenario 00900 * we want to to avoid: 00901 * 00902 * 1) Window 'A' is invalidated 00903 * 2) 'A' erases itself (or not, doesn't matter) 00904 * 3) 'A's children are enumerated and they erase themselves. 00905 * 4) 'A' paints over its children (remember, 'A' isn't CLIPCHILDREN) 00906 * 5) 'A's children paint but their backgrounds aren't their ERASEBKND 00907 * color (because 'A' painted over them) and everything looks like 00908 * dirt. 00909 */ 00910 if ((flags & DSP_ALLCHILDREN) || 00911 ((flags & DSP_ENUMCLIPPEDCHILDREN) && TestWF(pwnd, WFCLIPCHILDREN))) { 00912 00913 TL tlpwnd; 00914 PBWL pbwl; 00915 HWND *phwnd; 00916 00917 if (pbwl = BuildHwndList(pwnd->spwndChild, BWL_ENUMLIST, NULL)) { 00918 00919 PTHREADINFO ptiCurrent = PtiCurrent(); 00920 HWND hwnd; 00921 00922 /* 00923 * If the client dies during a callback, the hwnd list 00924 * will be freed in xxxDestroyThreadInfo. 00925 */ 00926 for (phwnd = pbwl->rghwnd; (hwnd = *phwnd) != (HWND)1; phwnd++) { 00927 00928 if (hwnd == NULL) 00929 continue; 00930 00931 if ((pwnd = (PWND)RevalidateHwnd(hwnd)) == NULL) 00932 continue; 00933 00934 /* 00935 * Note: testing if a window is a child automatically 00936 * excludes the desktop window. 00937 */ 00938 if (TestWF(pwnd, WFCHILD) && (ptiCurrent != GETPTI(pwnd))) { 00939 00940 /* 00941 * Don't cause any more intertask sendmessages cause it 00942 * does bad things to cbt's windowproc hooks. (Due to 00943 * SetParent allowing child windows in the topwindow 00944 * hierarchy. 00945 */ 00946 continue; 00947 } 00948 00949 /* 00950 * Note that we pass only certain bits down as we recurse: 00951 * the other bits pertain to the current window only. 00952 */ 00953 ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd); 00954 xxxInternalDoSyncPaint(pwnd, flags); 00955 ThreadUnlock(&tlpwnd); 00956 } 00957 00958 FreeHwndList(pbwl); 00959 } 00960 } 00961 } 00962 00963 /***************************************************************************\ 00964 * DoQueuedSyncPaint 00965 * 00966 * Queues WM_SYNCPAINT messages for top level windows not of the specified 00967 * thread. 00968 * 00969 * History: 00970 \***************************************************************************/ 00971 00972 VOID DoQueuedSyncPaint( 00973 PWND pwnd, 00974 DWORD flags, 00975 PTHREADINFO pti) 00976 { 00977 PTHREADINFO ptiPwnd = GETPTI(pwnd); 00978 00979 if ((ptiPwnd != pti) && 00980 TestWF(pwnd, WFSENDNCPAINT) && 00981 TestWF(pwnd, WFSENDERASEBKGND) && 00982 TestWF(pwnd, WFVISIBLE)) { 00983 00984 PSMS psms = ptiPwnd->psmsReceiveList; 00985 00986 /* 00987 * If this window already has a WM_SYNCPAINT queue'd up, then there's 00988 * no need to send another one. Also protects our heap from getting 00989 * chewed up. 00990 */ 00991 while (psms != NULL) { 00992 00993 if ((psms->message == WM_SYNCPAINT) && (psms->spwnd == pwnd)) { 00994 break; 00995 } 00996 00997 psms = psms->psmsReceiveNext; 00998 } 00999 01000 if (psms == NULL) { 01001 /* 01002 * This will give this message the semantics of a notify 01003 * message (sendmessage no wait), without calling back 01004 * the WH_CALLWNDPROC hook. We don't want to do that 01005 * because that'll let all these processes with invalid 01006 * windows to process paint messages before they process 01007 * "synchronous" erasing or framing needs. 01008 * 01009 * Hi word of wParam must be zero or wow will drop it 01010 * 01011 * LATER mikeke 01012 * Do we need to send down the flags with DWP_ERASE and DSP_FRAME 01013 * in it? 01014 */ 01015 UserAssert(HIWORD(flags) == 0); 01016 QueueNotifyMessage(pwnd, WM_SYNCPAINT, flags, 0); 01017 01018 /* 01019 * Set our syncpaint-pending flag, since we queued one up. This 01020 * will be used to check when we validate-parents for windows 01021 * without clipchildren. 01022 */ 01023 SetWF(pwnd, WFSYNCPAINTPENDING); 01024 } 01025 01026 /* 01027 * If we posted a WM_SYNCPAINT for a top-level window that is not 01028 * of the current thread we're done; we'll pick up the children 01029 * when we process the message for real. If we're the desktop 01030 * however make sure we get all it children. 01031 */ 01032 if (pwnd != PWNDDESKTOP(pwnd)) 01033 return; 01034 } 01035 01036 /* 01037 * Normally we like to enumerate all of this window's children and have 01038 * them erase their backgrounds synchronously. However, this is a bad 01039 * thing to do if the window is NOT CLIPCHLIDREN. Here's the scenario 01040 * we want to to avoid: 01041 * 01042 * 1. Window 'A' is invalidated 01043 * 2. 'A' erases itself (or not, doesn't matter) 01044 * 3. 'A's children are enumerated and they erase themselves. 01045 * 4. 'A' paints over its children (remember, 'A' isn't CLIPCHILDREN) 01046 * 5. 'A's children paint but their backgrounds aren't their ERASEBKND 01047 * color (because 'A' painted over them) and everything looks like 01048 * dirt. 01049 */ 01050 if ((flags & DSP_ALLCHILDREN) || 01051 ((flags & DSP_ENUMCLIPPEDCHILDREN) && TestWF(pwnd, WFCLIPCHILDREN))) { 01052 01053 PWND pwndT; 01054 01055 for (pwndT = pwnd->spwndChild; pwndT; pwndT = pwndT->spwndNext) { 01056 01057 /* 01058 * Don't cause any more intertask sendmessages cause it does 01059 * bad things to cbt's windowproc hooks. (Due to SetParent 01060 * allowing child windows in the topwindow hierarchy. 01061 * The child bit also catches the desktop window; we want to 01062 */ 01063 if (TestWF(pwndT, WFCHILD) && (pti != GETPTI(pwndT))) 01064 continue; 01065 01066 /* 01067 * Note that we pass only certain bits down as we recurse: 01068 * the other bits pertain to the current window only. 01069 */ 01070 DoQueuedSyncPaint(pwndT, flags, pti); 01071 } 01072 } 01073 } 01074 01075 /***************************************************************************\ 01076 * xxxDoSyncPaint 01077 * 01078 * This funstion is only called for the initial syncpaint so we always 01079 * queue syncpaints to other threads in this funtion. 01080 * 01081 * History: 01082 \***************************************************************************/ 01083 01084 VOID xxxDoSyncPaint( 01085 PWND pwnd, 01086 DWORD flags) 01087 { 01088 CheckLock(pwnd); 01089 01090 /* 01091 * If any of our non-clipchildren parents have an update region, don't 01092 * do anything. This way we won't redraw our background or frame out 01093 * of order, only to have it get obliterated when our parent erases his 01094 * background. 01095 */ 01096 if (ParentNeedsPaint(pwnd)) 01097 return; 01098 01099 /* 01100 * First of all if we are going to be queueing any WM_SYNCPAINT messages 01101 * to windows of another thread do it first while the window's update 01102 * regions are still in sync. This way there is no chance the update 01103 * region will be incorrect (through window movement during callbacks of 01104 * the WM_ERASEBKGND|WM_NCPAINT messages). 01105 */ 01106 DoQueuedSyncPaint(pwnd, flags, PtiCurrent()); 01107 xxxInternalDoSyncPaint(pwnd, flags); 01108 } 01109 01110 /***************************************************************************\ 01111 * ParentNeedsPaint 01112 * 01113 * Return a non-zero PWND if a non-CLIPCHILDREN parent requires a WM_PAINT 01114 * message. 01115 * 01116 * History: 01117 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 01118 \***************************************************************************/ 01119 01120 PWND ParentNeedsPaint( 01121 PWND pwnd) 01122 { 01123 while ((pwnd = pwnd->spwndParent) != NULL) { 01124 01125 if (TestWF(pwnd, WFCLIPCHILDREN)) 01126 break; 01127 01128 if (NEEDSPAINT(pwnd)) 01129 return pwnd; 01130 } 01131 01132 return NULL; 01133 } 01134 01135 /***************************************************************************\ 01136 * xxxSendEraseBkgnd 01137 * 01138 * Sends a WM_ERASEBKGROUND event to the window. This contains the paintDC 01139 * with the update-region selected into it. If there's no update region 01140 * then we prevent this event from making it to the window. 01141 * 01142 * History: 01143 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 01144 * 15-Dec-1996 ChrisWil Merged Chicago Functionality (no erase on min). 01145 \***************************************************************************/ 01146 01147 BOOL xxxSendEraseBkgnd( 01148 PWND pwnd, 01149 HDC hdcBeginPaint, 01150 HRGN hrgnUpdate) 01151 { 01152 PTHREADINFO ptiCurrent; 01153 BOOL fErased; 01154 HDC hdc; 01155 01156 CheckLock(pwnd); 01157 01158 /* 01159 * For minimized dudes in win3.1, we would've sent an 01160 * WM_ICONERASEBKGND and cleared the erase bit. Now that min 01161 * windows in 4.0 are all nonclient, don't bother erasing at 01162 * all. Pretend like we did. 01163 * 01164 * NOTE: 01165 * For < 4.0 windows, we may have to send a fake WM_ICONERASEKBGND 01166 * to keep 'em happy. Saves time not to though. Getting a DC and 01167 * sending the message ain't speedy. 01168 */ 01169 if ((hrgnUpdate == NULL) || TestWF(pwnd, WFMINIMIZED)) 01170 return FALSE; 01171 01172 /* 01173 * If a DC to use was not passed in, get one. 01174 * We want one clipped to this window's update region. 01175 */ 01176 if (hdcBeginPaint == NULL) { 01177 01178 hdc = _GetDCEx(pwnd, 01179 hrgnUpdate, 01180 DCX_USESTYLE | DCX_INTERSECTRGN | DCX_NODELETERGN); 01181 } else { 01182 01183 hdc = hdcBeginPaint; 01184 } 01185 01186 /* 01187 * If we're send the WM_ERASEBKGND to another process 01188 * we need to change the DC owner. 01189 * 01190 * We'd like to change the owner to pwnd->pti->idProcess, but 01191 * GDI won't let us assign ownership back to ourselves later. 01192 */ 01193 ptiCurrent = PtiCurrent(); 01194 01195 if (GETPTI(pwnd)->ppi != ptiCurrent->ppi) 01196 GreSetDCOwner(hdc, OBJECT_OWNER_PUBLIC); 01197 01198 /* 01199 * Send the event to the window. This contains the DC clipped to 01200 * the update-region. 01201 */ 01202 fErased = (BOOL)xxxSendMessage(pwnd, WM_ERASEBKGND, (WPARAM)hdc, 0L); 01203 01204 /* 01205 * If we've changed the DC owner, change it back to 01206 * the current process. 01207 */ 01208 if (GETPTI(pwnd)->ppi != ptiCurrent->ppi) 01209 GreSetDCOwner(hdc, OBJECT_OWNER_CURRENT); 01210 01211 /* 01212 * If the WM_ERASEBKGND message did not erase the 01213 * background, then set this flag to let BeginPaint() 01214 * know to ask the caller to do it via the fErase 01215 * flag in the PAINTSTRUCT. 01216 */ 01217 if (!fErased) { 01218 SetWF(pwnd, WFERASEBKGND); 01219 if (!TestWF(pwnd, WFWIN31COMPAT)) 01220 SetWF(pwnd, WFSENDERASEBKGND); 01221 } 01222 01223 /* 01224 * If we got a cache DC in this routine, release it. 01225 */ 01226 if (hdcBeginPaint == NULL) { 01227 ReleaseCacheDC(hdc, TRUE); 01228 } 01229 01230 return fErased; 01231 } 01232 01233 /***************************************************************************\ 01234 * IncPaintCount 01235 * 01236 * EFFECTS: 01237 * If cPaintsReady changes from 0 to 1, the QS_PAINT bit is set for 01238 * associated queue and we wake up task so repaint will occur. 01239 * 01240 * IMPLEMENTATION: 01241 * Get the queue handle from the window handle, bump the paint count, and 01242 * if paint count is one, Set the wakebit. 01243 * 01244 * History: 01245 * 17-Jul-1991 DarrinM Translated Win 3.1 ASM code. 01246 \***************************************************************************/ 01247 01248 VOID IncPaintCount( 01249 PWND pwnd) 01250 { 01251 PTHREADINFO pti = GETPTI(pwnd); 01252 01253 if (pti->cPaintsReady++ == 0) 01254 SetWakeBit(pti, QS_PAINT); 01255 } 01256 01257 /***************************************************************************\ 01258 * DecPaintCount 01259 * 01260 * EFFECTS: 01261 * If cPaintsReady changes from 1 to 0, the QS_PAINT bit is cleared so 01262 * that no more paints will occur. 01263 * 01264 * IMPLEMENTATION: 01265 * Get the queue handle from the window handle, decrement the paint count, 01266 * and if paint count is zero, clear the wakebit. 01267 * 01268 * History: 01269 * 17-Jul-1991 DarrinM Translated Win 3.1 ASM code. 01270 \***************************************************************************/ 01271 01272 VOID DecPaintCount( 01273 PWND pwnd) 01274 { 01275 PTHREADINFO pti = GETPTI(pwnd); 01276 01277 if (--pti->cPaintsReady == 0) { 01278 pti->pcti->fsWakeBits &= ~QS_PAINT; 01279 pti->pcti->fsChangeBits &= ~QS_PAINT; 01280 } 01281 } 01282 01283 /***************************************************************************\ 01284 * UT_GetParentDCClipBox 01285 * 01286 * Return rectangle coordinates of the parent clip-rect. If the window 01287 * isn't using a parentDC for drawing then return normal clipbox. 01288 * 01289 * History: 01290 * 31-Oct-1990 DarrinM Ported from Win 3.0 sources. 01291 \***************************************************************************/ 01292 01293 int UT_GetParentDCClipBox( 01294 PWND pwnd, 01295 HDC hdc, 01296 LPRECT lprc) 01297 { 01298 RECT rc; 01299 01300 if (GreGetClipBox(hdc, lprc, TRUE) == NULLREGION) 01301 return FALSE; 01302 01303 if ((pwnd == NULL) || !TestCF(pwnd, CFPARENTDC)) 01304 return TRUE; 01305 01306 GetRect(pwnd, &rc, GRECT_CLIENT | GRECT_CLIENTCOORDS); 01307 01308 return IntersectRect(lprc, lprc, &rc); 01309 } 01310 01311 /***************************************************************************\ 01312 * UserRedrawDesktop 01313 * 01314 * Redraw the desktop and its children. This is called from GDI for DCI 01315 * related unlocks, so that all visrgns are recalculated for the apps. 01316 * 01317 * History: 01318 * 08-Jan-1996 ChrisWil Created. 01319 \***************************************************************************/ 01320 01321 VOID UserRedrawDesktop(VOID) 01322 { 01323 TL tlpwnd; 01324 PWND pwndDesk; 01325 01326 EnterCrit(); 01327 01328 pwndDesk = PtiCurrent()->rpdesk->pDeskInfo->spwnd; 01329 01330 ThreadLockAlways(pwndDesk, &tlpwnd); 01331 01332 xxxInternalInvalidate(pwndDesk, 01333 HRGN_FULL, 01334 RDW_INVALIDATE | 01335 RDW_ERASE | 01336 RDW_FRAME | 01337 RDW_ALLCHILDREN); 01338 01339 ThreadUnlock(&tlpwnd); 01340 01341 LeaveCrit(); 01342 }

Generated on Sat May 15 19:41:08 2004 for test by doxygen 1.3.7