VOID xxxSendNCPaint( PWND pwnd, HRGN hrgnUpdate) { CheckLock(pwnd); /* * Clear the WFSENDNCPAINT bit... */ ClrWF(pwnd, WFSENDNCPAINT); /* * If the window is active, but its FRAMEON bit hasn't * been set yet, set it and make sure that the entire frame * gets redrawn when we send the NCPAINT. */ if ((pwnd == PtiCurrent()->pq->spwndActive) && !TestWF(pwnd, WFFRAMEON)) { SetWF(pwnd, WFFRAMEON); hrgnUpdate = HRGN_FULL; ClrWF(pwnd, WFNONCPAINT); } /* * If PixieHack() has set the WM_NCPAINT bit, we must be sure * to send with hrgnClip == HRGN_FULL. (see PixieHack() in wmupdate.c) */ if (TestWF(pwnd, WFPIXIEHACK)) { ClrWF(pwnd, WFPIXIEHACK); hrgnUpdate = HRGN_FULL; } if (hrgnUpdate) xxxSendMessage(pwnd, WM_NCPAINT, (WPARAM)hrgnUpdate, 0L); }
BOOL xxxEndPaint( PWND pwnd, LPPAINTSTRUCT lpps) { CheckLock(pwnd); ReleaseCacheDC(lpps->hdc, TRUE); if (TestWF(pwnd, WFDONTVALIDATE)) { if (ghrgnUpdateSave != NULL) { InternalInvalidate3(pwnd, ghrgnUpdateSave, RDW_INVALIDATE | RDW_ERASE); if (--gnUpdateSave == 0) { GreDeleteObject(ghrgnUpdateSave); ghrgnUpdateSave = NULL; } } ClrWF(pwnd, WFDONTVALIDATE); } ClrWF(pwnd, WFWMPAINTSENT); /* * This used to check that the update-region was empty before * doing the clear. However, this caused a problem with WOW * amipro/approach hanging. They were invalidating rects in * their WM_PAINT handler, and allowing the defwindowproc to * perform the validation for them. Since we were blocking * the BeginPaint in this case, it sent them into a infinite * loop (see bug 19036). */ ClrWF(pwnd, WFSTARTPAINT); /* * Reshow the caret if needed, but AFTER we've released the DC. * This way ShowCaret() can reuse the DC we just released. */ if (pwnd == PtiCurrent()->pq->caret.spwnd) zzzInternalShowCaret(); return TRUE; }
BOOL xxxRemoveFullScreen(PWND pwnd) { PDESKTOP pdesk = pwnd->head.rpdesk; BOOL fYielded; fYielded = FALSE; if (pdesk == NULL) return fYielded; if (TestWF(pwnd, WFFULLSCREEN) && FCallTray(pdesk)) { ClrWF(pwnd, WFFULLSCREEN); if (!(--pdesk->cFullScreen)) { xxxSetTrayWindow(pdesk, STW_SAME); fYielded = TRUE; } UserAssert(pdesk->cFullScreen >= 0); } return(fYielded); }
VOID SetDialogPointer(PWND pwnd, LONG_PTR lPtr) { if ((pwnd->cbwndExtra < DLGWINDOWEXTRA) || TestWF(pwnd, WFSERVERSIDEPROC) || (PpiCurrent() != GETPTI(pwnd)->ppi)) { RIPMSG1(RIP_WARNING, "SetDialogPointer: Unexpected pwnd:%#p", pwnd); return; } ((PDIALOG)pwnd)->pdlg = (PDLG)lPtr; if (lPtr == 0) { pwnd->fnid |= FNID_CLEANEDUP_BIT; ClrWF(pwnd, WFDIALOGWINDOW); } else { if (pwnd->fnid == 0) { pwnd->fnid = FNID_DIALOG; } SetWF(pwnd, WFDIALOGWINDOW); } }
BOOL xxxShowWindow( PWND pwnd, DWORD cmdShowAnimate) { BOOL fVisOld, fVisNew; UINT swpFlags = SWP_NOMOVE | SWP_NOSIZE; PTHREADINFO pti; BOOL bFirstMain = FALSE; int cmdShow = LOWORD(cmdShowAnimate); CheckLock(pwnd); fVisOld = TestWF(pwnd, WFVISIBLE); pti = PtiCurrent(); /* * See if this is the first "main" top level * window being created by this application - if show, assume it * is showing with the SW_SHOWDEFAULT command. * * Checks for: * - cmdShow is a "default" show command * - we haven't done startupinfo yet (we only use it once) * - this is not a child (it is a top level window) * - this has a titlebar (indicator of the main window) * - it isn't owned (indicator of the main window) */ if ((pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW) && !TestwndChild(pwnd) && (TestWF(pwnd, WFBORDERMASK) == (BYTE)LOBYTE(WFCAPTION)) && (pwnd->spwndOwner == NULL)) { bFirstMain = TRUE; switch (cmdShow) { case SW_SHOWNORMAL: case SW_SHOW: /* * Then assume default! */ cmdShow = SW_SHOWDEFAULT; break; } } /* * If this application specified SW_SHOWDEFAULT, then we get the * real SW_* command from the application's STARTUPINFO structure * (STARTUPINFO is passed to CreateProcess() when this application * was launched). */ if (cmdShow == SW_SHOWDEFAULT) { /* * Call the client to get the SW_* command from the STARTUPINFO * for this process. */ if (pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW) { bFirstMain = TRUE; cmdShow = pti->ppi->usi.wShowWindow; #if 0 switch (cmdShow) { case SW_SHOWMINIMIZED: case SW_MINIMIZE: /* * If the default show was "minimized", then make sure it doesn't * become active. Minimized is effectively "background". */ cmdShow = SW_SHOWMINNOACTIVE; break; } #endif } } // // This is in case someone said SW_SHOWDEFAULT but has no startupinfo. // Or in case cmdShow inside of STARTUPINFO is SW_SHOWDEFAULT. // if (cmdShow == SW_SHOWDEFAULT) cmdShow = SW_SHOWNORMAL; /* * Turn off startup info. We turn this off after the first call to * ShowWindow. If we don't apps can be started by progman with * the start info being minimized and then be restored and then * call ShowWindow(SW_SHOW) and the app would minimize again. * Notepad had that problem 2985. */ if (bFirstMain) { pti->ppi->usi.dwFlags &= ~(STARTF_USESHOWWINDOW|STARTF_USESIZE \ | STARTF_USEPOSITION); } /* * Take care of all the OLD show commands with columns & iconslot. */ if (cmdShow & 0xFF00) { if ((cmdShow & 0xFF80) == (int)0xFF80) cmdShow = SW_SHOWMINNOACTIVE; else cmdShow = SW_SHOW; } /* * Change to new fullscreen if needed and in same desktop */ if ((pwnd->bFullScreen != WINDOWED) && (pwnd->head.rpdesk == grpdeskRitInput)) { if ((cmdShow == SW_SHOWNORMAL) || (cmdShow == SW_RESTORE) || (cmdShow == SW_MAXIMIZE) || (cmdShow == SW_SHOWMAXIMIZED)) { cmdShow = SW_SHOWMINIMIZED; if (pwnd->bFullScreen == FULLSCREENMIN) { pwnd->bFullScreen = FULLSCREEN; } if (gpqForeground != NULL && gpqForeground->spwndActive == pwnd) { xxxMakeWindowForegroundWithState(NULL, 0); } } } switch (cmdShow) { case SW_SHOWNOACTIVATE: case SW_SHOWNORMAL: case SW_RESTORE: /* * If min/max, let xxxMinMaximize() do all the work. */ if (TestWF(pwnd, WFMINIMIZED) || TestWF(pwnd, WFMAXIMIZED)) { xxxMinMaximize(pwnd, (UINT)cmdShow, cmdShowAnimate & MINMAX_ANIMATE); return fVisOld; } else { /* * Ignore if the window is already visible. */ if (fVisOld) { return fVisOld; } swpFlags |= SWP_SHOWWINDOW; if ( cmdShow == SW_SHOWNOACTIVATE) { swpFlags |= SWP_NOZORDER; #ifdef NEVER /* * This is what win3.1 does. On NT, since each "queue" has * its own active window, there is often no active window. * In this case, win3.1 turns a SHOWNOACTIVATE into a "SHOW * with activate". Since win3.1 almost always has an active * window, this almost never happens. So on NT, we're not * going to do this check - that way we'll be more compatible * with win3.1 because we'll usally not activate (like win3.1). * With this check, this causes FoxPro 2.5 for Windows to not * properly activate its command window when first coming up. */ if (pti->pq->spwndActive != NULL) swpFlags |= SWP_NOACTIVATE; #else swpFlags |= SWP_NOACTIVATE; #endif } } break; case SW_SHOWMINNOACTIVE: case SW_SHOWMINIMIZED: case SW_SHOWMAXIMIZED: case SW_MINIMIZE: xxxMinMaximize(pwnd, (UINT)cmdShow, cmdShowAnimate & MINMAX_ANIMATE); return fVisOld; case SW_SHOWNA: swpFlags |= SWP_SHOWWINDOW | SWP_NOACTIVATE; // LATER removed this to be compatible with SHOWNOACTIVATE //if (pti->pq->spwndActive != NULL) // swpFlags |= SWP_NOACTIVATE; break; case SW_SHOW: /* * Don't bother if it is already visible. */ if (fVisOld) return fVisOld; swpFlags |= SWP_SHOWWINDOW; if (cmdShow == SW_SHOWNOACTIVATE) { swpFlags |= SWP_NOZORDER | SWP_NOACTIVATE; } break; case SW_HIDE: /* * Don't bother if it is already hidden. */ if (!fVisOld) return fVisOld; swpFlags |= SWP_HIDEWINDOW; if (pwnd != pti->pq->spwndActive) swpFlags |= (SWP_NOACTIVATE | SWP_NOZORDER); break; default: RIPERR0(ERROR_INVALID_SHOWWIN_COMMAND, RIP_VERBOSE, ""); return fVisOld; } /* * If we're changing from visible to hidden or vise-versa, send * WM_SHOWWINDOW. */ fVisNew = !(cmdShow == SW_HIDE); if (fVisNew != fVisOld) { xxxSendMessage(pwnd, WM_SHOWWINDOW, fVisNew, 0L); if (!TestWF(pwnd, WFWIN31COMPAT)) { xxxSendMessage(pwnd, WM_SETVISIBLE, fVisNew, 0L); } } if (!TestwndChild(pwnd)) { if (TestCF(pwnd, CFSAVEBITS)) { /* * Activate to prevent discarding saved bits??? */ if (cmdShow == SW_SHOW || cmdShow == SW_SHOWNORMAL) { xxxActivateWindow(pwnd, AW_USE); swpFlags |= SWP_NOZORDER | SWP_NOACTIVATE; } } } else { /* * Children can't get activation... */ swpFlags |= (SWP_NOACTIVATE | SWP_NOZORDER); } /* * If our parent is hidden, don't bother to call xxxSetWindowPos. */ if (_FChildVisible(pwnd)) { xxxSetWindowPos(pwnd, (PWND)NULL, 0, 0, 0, 0, swpFlags); } else { if (cmdShow == SW_HIDE) ClrWF(pwnd, WFVISIBLE); else SetWF(pwnd, WFVISIBLE); } /* * Send size and move messages AFTER repainting */ if (TestWF(pwnd, WFSENDSIZEMOVE)) { ClrWF(pwnd, WFSENDSIZEMOVE); if (TestWF(pwnd, WFMINIMIZED)) { xxxSendSizeMessage(pwnd, SIZEICONIC); } else if (TestWF(pwnd, WFMAXIMIZED)) { xxxSendSizeMessage(pwnd, SIZEFULLSCREEN); } else { xxxSendSizeMessage(pwnd, SIZENORMAL); } if (pwnd->spwndParent) { xxxSendMessage(pwnd, WM_MOVE, 0, MAKELONG( pwnd->rcClient.left - pwnd->spwndParent->rcClient.left, pwnd->rcClient.top - pwnd->spwndParent->rcClient. top)); } else { /* * NULL parent implies this window is a zombie */ xxxSendMessage(pwnd, WM_MOVE, 0, MAKELONG( pwnd->rcClient.left, pwnd->rcClient.top)); } } /* * If hiding and is active-foreground window, activate someone else. * If hiding a active window make someone active. */ if (cmdShow == SW_HIDE) { if ((pwnd == pti->pq->spwndActive) && (pti->pq == gpqForeground)) { xxxActivateWindow(pwnd, AW_SKIP); } else { xxxCheckFocus(pwnd); } } return fVisOld; }
VOID xxxSimpleDoSyncPaint( PWND pwnd) { HRGN hrgnUpdate; DWORD flags = 0; CheckLock(pwnd); /* * Since we're taking care of the frame drawing, we can consider * this WM_PAINT message processed. */ ClrWF(pwnd, WFPAINTNOTPROCESSED); /* * Make copies of these flags, because their state might * change after we send a message, and we don't want * to "lose" them. */ if (TestWF(pwnd, WFSENDNCPAINT)) flags |= DSP_FRAME; if (TestWF(pwnd, WFSENDERASEBKGND)) flags |= DSP_ERASE; if (flags & (DSP_ERASE | DSP_FRAME)) { if (!TestWF(pwnd, WFVISIBLE)) { /* * If there is no update region, just clear the bits. */ ClrWF(pwnd, WFSENDNCPAINT); ClrWF(pwnd, WFSENDERASEBKGND); ClrWF(pwnd, WFPIXIEHACK); ClrWF(pwnd, WFERASEBKGND); ClearHungFlag(pwnd, WFREDRAWIFHUNG); } else { PTHREADINFO ptiCurrent = PtiCurrent(); /* * If there is no update region, we don't have to * do any erasing, but we may need to send an NCPAINT. */ if (pwnd->hrgnUpdate == NULL) { ClrWF(pwnd, WFSENDERASEBKGND); ClrWF(pwnd, WFERASEBKGND); flags &= ~DSP_ERASE; } /* * Only mess with windows owned by the current thread. * NOTE: This means that WM_NCPAINT and WM_ERASEBKGND are * only sent intra-thread. */ if (GETPTI(pwnd) == ptiCurrent) { hrgnUpdate = GetNCUpdateRgn(pwnd, TRUE); if (flags & DSP_FRAME) { /* * If the message got sent before we got here then do * nothing. */ if (TestWF(pwnd, WFSENDNCPAINT)) xxxSendNCPaint(pwnd, hrgnUpdate); } if (flags & DSP_ERASE) { if (TestWF(pwnd, WFSENDNCPAINT)) { /* * If we got another invalidate during the NCPAINT * callback get the new update region */ DeleteMaybeSpecialRgn(hrgnUpdate); hrgnUpdate = GetNCUpdateRgn(pwnd, FALSE); } /* * If the message got sent before we got here * (e.g.: an UpdateWindow() inside WM_NCPAINT handler, * for example), don't do anything. * * WINPROJ.EXE (version 1.0) calls UpdateWindow() in * the WM_NCPAINT handlers for its subclassed listboxes * in the open dialog. */ if (TestWF(pwnd, WFSENDERASEBKGND)) { ClrWF(pwnd, WFSENDERASEBKGND); ClrWF(pwnd, WFERASEBKGND); xxxSendEraseBkgnd(pwnd, NULL, hrgnUpdate); } /* * The erase and frame operation has occured. Clear the * WFREDRAWIFHUNG bit here. We don't want to clear it until we * know the erase and frame has occured, so we know we always * have a consistent looking window. */ ClearHungFlag(pwnd, WFREDRAWIFHUNG); } DeleteMaybeSpecialRgn(hrgnUpdate); } else if (!TestwndChild(pwnd) && (pwnd != grpdeskRitInput->pDeskInfo->spwnd) && FHungApp(GETPTI(pwnd), CMSHUNGAPPTIMEOUT) && TestWF(pwnd, WFREDRAWIFHUNG)) { ClearHungFlag(pwnd, WFREDRAWIFHUNG); xxxRedrawHungWindow(pwnd, NULL); } } } }
BOOL DoPaint( PWND pwndFilter, LPMSG lpMsg) { PWND pwnd; PWND pwndT; PTHREADINFO ptiCurrent = PtiCurrent(); #if 0 // CHRISWIL: WIN95 SPECIFIC /* * If there is a system modal up and it is attached to another task, * DON'T do paints. We don't want to return a message for a window in * another task! */ if (hwndSysModal && (hwndSysModal->hq != hqCurrent)) { /* * Poke this guy so he wakes up at some point in the future, * otherwise he may never wake up to realize he should paint. * Causes hangs - e.g. Photoshop installation program * PostThreadMessage32(Lpq(hqCurrent)->idThread, WM_NULL, 0, 0, 0); */ return FALSE; } #endif /* * If this is a system thread, then walk the windowstation desktop-list * to find the window which needs painting. For other threads, we * reference off the thread-desktop. */ if (ptiCurrent->TIF_flags & TIF_SYSTEMTHREAD) { PWINDOWSTATION pwinsta; PDESKTOP pdesk; if ((pwinsta = ptiCurrent->pwinsta) == NULL) { RIPMSG0(RIP_ERROR, "DoPaint: SYSTEMTHREAD does not have (pwinsta)"); return FALSE; } pwnd = NULL; for(pdesk = pwinsta->rpdeskList; pdesk; pdesk = pdesk->rpdeskNext) { if (pwnd = InternalDoPaint(pdesk->pDeskInfo->spwnd, ptiCurrent)) break; } } else { pwnd = InternalDoPaint(ptiCurrent->rpdesk->pDeskInfo->spwnd, ptiCurrent); } if (pwnd != NULL) { if (!CheckPwndFilter(pwnd, pwndFilter)) return FALSE; /* * We're returning a WM_PAINT message, so clear WFINTERNALPAINT so * it won't get sent again later. */ if (TestWF(pwnd, WFINTERNALPAINT)) { ClrWF(pwnd, WFINTERNALPAINT); /* * If there is no update region, then no more paint for this * window. */ if (pwnd->hrgnUpdate == NULL) DecPaintCount(pwnd); } /* * Set the STARTPAINT so that any other calls to BeginPaint while * painting is begin performed, will prevent painting on those * windows. * * Clear the UPDATEDIRTY since some apps (DBFast) don't call * GetUpdateRect, BeginPaint/EndPaint. */ ClrWF(pwnd, WFSTARTPAINT); ClrWF(pwnd, WFUPDATEDIRTY); /* * If we get an invalidate between now and the time the app calls * BeginPaint() and the windows parent is not CLIPCHILDREN, then * the parent will paint in the wrong order. So we are going to * cause the child to paint again. Look in beginpaint and internal * invalidate for other parts of this fix. * * Set a flag to signify that we are in the bad zone. * * Must go up the parent links to make sure all parents have * WFCLIPCHILDREN set otherwise set the WFWMPAINTSENT flag. * This is to fix Excel spreadsheet and fulldrag. The speadsheet * parent window (class XLDESK) has WFCLIPCHILDREN set but it's * parent (class XLMAIN) doesn't. So the main window erases the * background after the child window paints. * * JOHANNEC : 27-Jul-1994 */ /* * NT Bug 400167: As we walk up the tree, we need to stop short of * desktop windows and mother desktop windows. We can't do a test * for WFCLIPCHILDREN on the mother desktop window's parent because * it doesn't exist. This means that no desktop window will get * WFWMPAINTSENT set, but the message window will be able to get * WFWMPAINTSENT set. */ pwndT = pwnd; while (pwndT && (GETFNID(pwndT) != FNID_DESKTOP)) { if (!TestWF(pwndT->spwndParent, WFCLIPCHILDREN)) { SetWF(pwnd, WFWMPAINTSENT); break; } pwndT = pwndT->spwndParent; } /* * If the top level "tiled" owner/parent of this window is iconed, * send a WM_PAINTICON rather than a WM_PAINT. The wParam * is TRUE if this is the tiled window and FALSE if it is a * child/owned popup of the minimized window. * * BACKWARD COMPATIBILITY HACK * * 3.0 sent WM_PAINTICON with wParam == TRUE for no apparent * reason. Lotus Notes 2.1 depends on this for some reason * to properly change its icon when new mail arrives. */ if (!TestWF(pwnd, WFWIN40COMPAT) && TestWF(pwnd, WFMINIMIZED) && (pwnd->pcls->spicn != NULL)) { StoreMessage(lpMsg, pwnd, WM_PAINTICON, (DWORD)TRUE, 0L, 0L); } else { StoreMessage(lpMsg, pwnd, WM_PAINT, 0, 0L, 0L); } return TRUE; } return FALSE; }
HDC xxxBeginPaint( PWND pwnd, LPPAINTSTRUCT lpps) { HRGN hrgnUpdate; HDC hdc; BOOL fSendEraseBkgnd; CheckLock(pwnd); UserAssert(IsWinEventNotifyDeferredOK()); if (TEST_PUDF(PUDF_DRAGGINGFULLWINDOW)) SetWF(pwnd, WFSTARTPAINT); /* * We're processing a WM_PAINT message: clear this flag. */ ClrWF(pwnd, WFPAINTNOTPROCESSED); /* * If this bit gets set while we are drawing the frame we will need * to redraw it. * * If necessary, send our WM_NCPAINT message now. * * please heed these notes * * We have to send this message BEFORE we diddle hwnd->hrgnUpdate, * because an app may call ValidateRect or InvalidateRect in its * handler, and it expects what it does to affect what gets drawn * in the later WM_PAINT. * * It is possible to get an invalidate when we leave the critical * section below, therefore we loop until UPDATEDIRTY is clear * meaning there were no additional invalidates. */ if (TestWF(pwnd, WFSENDNCPAINT)) { do { ClrWF(pwnd, WFUPDATEDIRTY); hrgnUpdate = GetNCUpdateRgn(pwnd, FALSE); xxxSendNCPaint(pwnd, hrgnUpdate); DeleteMaybeSpecialRgn(hrgnUpdate); } while (TestWF(pwnd, WFUPDATEDIRTY)); } else { ClrWF(pwnd, WFUPDATEDIRTY); } /* * Hide the caret if needed. Do this before we get the DC so * that if HideCaret() gets and releases a DC we will be able * to reuse it later here. * No need to DeferWinEventNotify() since pwnd is locked. */ if (pwnd == PtiCurrent()->pq->caret.spwnd) zzzInternalHideCaret(); /* * Send the check for sending an WM_ERASEBKGND to the * window. */ if (fSendEraseBkgnd = TestWF(pwnd, WFSENDERASEBKGND)) { ClrWF(pwnd, WFERASEBKGND); ClrWF(pwnd, WFSENDERASEBKGND); } /* * Validate the entire window. */ if (NEEDSPAINT(pwnd)) DecPaintCount(pwnd); ClrWF(pwnd, WFINTERNALPAINT); hrgnUpdate = pwnd->hrgnUpdate; pwnd->hrgnUpdate = NULL; if (TestWF(pwnd, WFDONTVALIDATE)) { if (ghrgnUpdateSave == NULL) { ghrgnUpdateSave = CreateEmptyRgn(); } if (ghrgnUpdateSave != NULL) { UnionRgn(ghrgnUpdateSave, ghrgnUpdateSave, hrgnUpdate); gnUpdateSave++; } } /* * Clear these flags for backward compatibility */ lpps->fIncUpdate = lpps->fRestore = FALSE; lpps->hdc = hdc = _GetDCEx(pwnd, hrgnUpdate, DCX_USESTYLE | DCX_INTERSECTRGN); if (UT_GetParentDCClipBox(pwnd, hdc, &lpps->rcPaint)) { /* * If necessary, erase our background, and possibly deal with * our children's frames and backgrounds. */ if (fSendEraseBkgnd) xxxSendEraseBkgnd(pwnd, hdc, hrgnUpdate); } /* * Now that we're completely erased, see if there are any children * that couldn't draw their own frames because their update regions * got deleted. */ xxxSendChildNCPaint(pwnd); /* * The erase and frame operation has occured. Clear the WFREDRAWIFHUNG * bit here. We don't want to clear it until we know the erase and * frame has occured, so we know we always have a consistent looking * window. */ ClearHungFlag(pwnd, WFREDRAWIFHUNG); lpps->fErase = (TestWF(pwnd, WFERASEBKGND) != 0); return hdc; }
HRGN GetNCUpdateRgn( PWND pwnd, BOOL fValidateFrame) { HRGN hrgnUpdate; if (pwnd->hrgnUpdate > HRGN_FULL) { /* * We must make a copy of our update region, because * it could change if we send a message, and we want to * make sure the whole thing is used for drawing our * frame and background. We can't use a global * temporary region, because more than one app may * be calling this routine. */ hrgnUpdate = CreateEmptyRgnPublic(); if (hrgnUpdate == NULL) { hrgnUpdate = HRGN_FULL; } else if (CopyRgn(hrgnUpdate, pwnd->hrgnUpdate) == ERROR) { GreDeleteObject(hrgnUpdate); hrgnUpdate = HRGN_FULL; } if (fValidateFrame) { /* * Now that we've taken care of any frame drawing, * intersect the update region with the window's * client area. Otherwise, apps that do ValidateRects() * to draw themselves (e.g., WinWord) won't ever * subtract off the part of the update region that * overlaps the frame but not the client. */ CalcWindowRgn(pwnd, ghrgnInv2, TRUE); switch (IntersectRgn(pwnd->hrgnUpdate, pwnd->hrgnUpdate, ghrgnInv2)) { case ERROR: /* * If an error occured, we can't leave things as * they are: invalidate the whole window and let * BeginPaint() take care of it. */ GreDeleteObject(pwnd->hrgnUpdate); pwnd->hrgnUpdate = HRGN_FULL; break; case NULLREGION: /* * There is nothing in the client area to repaint. * Blow the region away, and decrement the paint count * if possible. */ GreDeleteObject(pwnd->hrgnUpdate); pwnd->hrgnUpdate = NULL; ClrWF(pwnd, WFUPDATEDIRTY); if (!TestWF(pwnd, WFINTERNALPAINT)) DecPaintCount(pwnd); break; } } } else { hrgnUpdate = pwnd->hrgnUpdate; } return hrgnUpdate; }
/* * Modal loop for when the user has selected the help icon from the titlebar * */ VOID xxxHelpLoop(PWND pwnd) { HWND hwndChild; PWND pwndChild; PWND pwndControl; MSG msg; RECT rc; int cBorders; PTHREADINFO ptiCurrent = PtiCurrent(); DLGENUMDATA DlgEnumData; TL tlpwndChild; CheckLock(pwnd); UserAssert(IsWinEventNotifyDeferredOK()); if (FWINABLE()) { xxxWindowEvent(EVENT_SYSTEM_CONTEXTHELPSTART, pwnd, OBJID_WINDOW, INDEXID_CONTAINER, 0); } zzzSetCursor(SYSCUR(HELP)); xxxCapture(ptiCurrent, pwnd, SCREEN_CAPTURE); cBorders = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, FALSE); CopyInflateRect(&rc, &pwnd->rcWindow, -cBorders * SYSMET(CXBORDER), -cBorders * SYSMET(CYBORDER)); while (ptiCurrent->pq->spwndCapture == pwnd) { if (!xxxPeekMessage(&msg, NULL, 0, 0, PM_NOYIELD | PM_NOREMOVE)) { xxxWaitMessage(); continue; } if (msg.message == WM_NCLBUTTONDOWN) { break; } else if (msg.message == WM_LBUTTONDOWN) { /* * If user clicked outside of window client, bail out now. */ if (!PtInRect(&rc, msg.pt)) break; /* * WindowHitTest() won't return a static control's handle */ hwndChild = xxxWindowHitTest(pwnd, msg.pt, NULL, 0); pwndChild = ValidateHwnd( hwndChild ); ThreadLock(pwndChild, &tlpwndChild); if (pwndChild && FIsParentDude(pwndChild)) { /* * If this is a dialog class, then one of three things has * happened: * * o This is a static text control * o This is the background of the dialog box. * * What we do is enumerate the child windows and see if * any of them contain the current cursor point. If they do, * change our window handle and continue on. Otherwise, * return doing nothing -- we don't want context-sensitive * help for a dialog background. * * If this is a group box, then we might have clicked on a * disabled control, so we enumerate child windows to see * if we get another control. */ /* * We're enumerating a dialog's children. So, if we don't * find any matches, hwndChild will be NULL and the check * below will drop out. */ DlgEnumData.pwndDialog = pwndChild; DlgEnumData.pwndControl = NULL; DlgEnumData.ptCurHelp = msg.pt; xxxInternalEnumWindow(pwndChild, EnumPwndDlgChildProc, (LPARAM)&DlgEnumData, BWL_ENUMCHILDREN); pwndControl = DlgEnumData.pwndControl; } else { pwndControl = pwndChild; } /* * If we click on nothing, just exit. */ if (pwndControl == pwnd) { pwndControl = NULL; } /* * HACK ALERT (Visual Basic 4.0) - they have their own non-window * based controls that draw directly on the main dialog. In order * to provide help for these controls, we pass along the WM_HELP * message iff the main dialog has a context id assigned. * * If the top level window has its own context help ID, * then pass it in the context help message. */ if (!pwndControl) { if (_GetProp(pwnd, MAKEINTATOM(gpsi->atomContextHelpIdProp), TRUE)) pwndControl = pwnd; } if (pwndControl) { PWND pwndSend; int id; TL tlpwndSend; TL tlpwndControl; ThreadLockAlways(pwndControl, &tlpwndControl); zzzSetCursor(SYSCUR(ARROW)); xxxReleaseCapture(); xxxRedrawTitle(pwnd, DC_BUTTONS); ClrWF(pwnd, WFHELPBUTTONDOWN); xxxGetMessage(&msg, NULL, 0, 0); if (FWINABLE()) { xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_TITLEBAR, INDEX_TITLEBAR_HELPBUTTON, FALSE); xxxWindowEvent(EVENT_SYSTEM_CONTEXTHELPEND, pwnd, OBJID_WINDOW, INDEXID_CONTAINER, FALSE); } /* * Determine the ID of the control * We used to always sign extend, but Win98 doesn't do that * so we only sign extend 0xffff. MCostea #218711 */ if (TestwndChild(pwndControl)) { id = PTR_TO_ID(pwndControl->spmenu); if (id == 0xffff) { id = -1; } } else { id = -1; } /* * Disabled controls and static controls won't pass this * on to their parent, so instead, we send the message to * their parent. */ if (TestWF(pwndControl, WFDISABLED)) { PWND pwndParent = _GetParent(pwndControl); if (!pwndParent) { ThreadUnlock( &tlpwndControl ); ThreadUnlock( &tlpwndChild ); return; } pwndSend = pwndParent; } else { pwndSend = pwndControl; } ThreadLockAlways(pwndSend, &tlpwndSend); xxxSendHelpMessage( pwndSend, HELPINFO_WINDOW, id, (HANDLE)HWq(pwndControl), GetContextHelpId(pwndControl)); ThreadUnlock(&tlpwndSend); ThreadUnlock(&tlpwndControl); ThreadUnlock(&tlpwndChild); return; } ThreadUnlock(&tlpwndChild); break; } else if ((msg.message == WM_RBUTTONDOWN) || (msg.message == WM_MBUTTONDOWN) || (msg.message == WM_XBUTTONDOWN)) { /* * fix bug 29852; break the loop for right and middle buttons * and pass along the messages to the control */ break; } else if (msg.message == WM_MOUSEMOVE) { if (PtInRect(&rc, msg.pt)) zzzSetCursor(SYSCUR(HELP)); else zzzSetCursor(SYSCUR(ARROW)); } else if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) { xxxGetMessage( &msg, NULL, 0, 0 ); break; } xxxGetMessage(&msg, NULL, 0, 0); xxxTranslateMessage(&msg, 0); xxxDispatchMessage(&msg); } xxxReleaseCapture(); zzzSetCursor(SYSCUR(ARROW)); xxxRedrawTitle(pwnd, DC_BUTTONS); ClrWF(pwnd, WFHELPBUTTONDOWN); if (FWINABLE()) { xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_TITLEBAR, INDEX_TITLEBAR_HELPBUTTON, 0); xxxWindowEvent(EVENT_SYSTEM_CONTEXTHELPEND, pwnd, OBJID_WINDOW, INDEXID_CONTAINER, 0); } }
void xxxCalcClientRect( PWND pwnd, LPRECT lprc, BOOL fHungRedraw) { int cxFrame, yTopOld; RECT rcTemp; PMENU pMenu; TL tlpmenu; int cBorders; BOOL fEmptyClient; CheckLock(pwnd); /* * Clear all the frame bits. NOTE: The HIBYTE of all these #defines * must stay the same for this line to work. */ ClrWF(pwnd, (WFHPRESENT | WFVPRESENT | WFCPRESENT | WFMPRESENT)); // // We need to clear the client border bits also. Otherwise, when the // window gets really small, the client border will draw over the menu // and caption. // ClrWF(pwnd, WFCEPRESENT); /* * If the window is iconic, the client area is empty. */ if (TestWF(pwnd, WFMINIMIZED)) { // SetRectEmpty(lprc); // We must make it an empty rectangle. // But, that empty rectangle should be at the top left corner of the // window rect. Else, ScreenToClient() will return bad values. lprc->right = lprc->left; lprc->bottom = lprc->top; return; } // Save rect into rcTemp for easy local calculations. CopyRect(&rcTemp, lprc); // Save the top so we'll know how tall the caption was yTopOld = rcTemp.top; // Adjustment for the caption if (TestWF(pwnd, WFBORDERMASK) == LOBYTE(WFCAPTION)) { SetWF(pwnd, WFCPRESENT); rcTemp.top += TestWF(pwnd, WEFTOOLWINDOW) ? SYSMET(CYSMCAPTION) : SYSMET(CYCAPTION); } // Subtract out window borders cBorders = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, FALSE); cxFrame = cBorders * SYSMET(CXBORDER); InflateRect(&rcTemp, -cxFrame, -cBorders*SYSMET(CYBORDER)); if (!TestwndChild(pwnd) && (pMenu = pwnd->spmenu)) { SetWF(pwnd, WFMPRESENT); if (!fHungRedraw) { ThreadLockAlways(pMenu, &tlpmenu); rcTemp.top += xxxMenuBarCompute(pMenu, pwnd, rcTemp.top - yTopOld, cxFrame, rcTemp.right - rcTemp.left); ThreadUnlock(&tlpmenu); } } // // Fix for B#1425 -- Sizing window really small used to move children's // rects because the client calculations were wrong. So we make the // bottom of the client match up with the top (the bottom of the menu // bar). // fEmptyClient = FALSE; if (rcTemp.top >= rcTemp.bottom) { rcTemp.bottom = rcTemp.top; fEmptyClient = TRUE; } // // BOGUS BOGUS BOGUS // Hack for Central Point PC Tools. // Possibly for M5 only. // B#8445 // // They check for div-by-zero all over, but they jump to the wrong place // if a zero divisor is encountered, and end up faulting anyway. So this // code path was never tested basically. There's a period when starting // up where the window rect of their drives ribbon is empty. In Win3.x, // the client would be shrunk to account for the border it had, and it // would look like it wasn't empty because the width would be negative, // signed! So we version-switch this code, since other apps have // reported the non-emptiness as an annoying bug. // if (TestWF(pwnd, WFWIN40COMPAT) && (rcTemp.left >= rcTemp.right)) { rcTemp.right = rcTemp.left; fEmptyClient = TRUE; } if (fEmptyClient) goto ClientCalcEnd; // // Subtract client edge if we have space // if (TestWF(pwnd, WEFCLIENTEDGE) && (rcTemp.right - rcTemp.left >= (2 * SYSMET(CXEDGE))) && (rcTemp.bottom - rcTemp.top >= (2 * SYSMET(CYEDGE))) ) { SetWF(pwnd, WFCEPRESENT); InflateRect(&rcTemp, -SYSMET(CXEDGE), -SYSMET(CYEDGE)); } // // Subtract scrollbars // Note compatibility with 3.1: // * You don't get a horizontal scrollbar unless you have MORE // space (> ) in your client than you need for one. // * You get a vertical scrollbar if you have AT LEAST ENOUGH // space (>=) in your client for one. // if (TestWF(pwnd, WFHSCROLL) && (rcTemp.bottom - rcTemp.top > SYSMET(CYHSCROLL))) { SetWF(pwnd, WFHPRESENT); if (!fHungRedraw) rcTemp.bottom -= SYSMET(CYHSCROLL); } if (TestWF(pwnd, WFVSCROLL) && (rcTemp.right - rcTemp.left >= SYSMET(CXVSCROLL))) { SetWF(pwnd, WFVPRESENT); if (!fHungRedraw) rcTemp.right -= SYSMET(CXVSCROLL); } ClientCalcEnd: CopyRect(lprc, &rcTemp); }