/*****************************************************************************\ * GetAncestor() * * This gets one of: * * The _real_ parent. This does NOT include the owner, unlike * GetParent(). Stops at a top level window unless we start with * the desktop. In which case, we return the desktop. * * The _real_ root, caused by walking up the chain getting the * ancestor. * * The _real_ owned root, caused by GetParent()ing up. \*****************************************************************************/ PWND WINAPI _GetAncestor(PWND pwnd, UINT gaFlags) { PWND pwndParent; /* * If we start with the desktop return NULL. */ if (pwnd == PWNDDESKTOP(pwnd)) return NULL; switch (gaFlags) { case GA_PARENT: pwnd = pwnd->spwndParent; break; case GA_ROOT: while ((pwnd->spwndParent != PWNDDESKTOP(pwnd)) && (pwnd->spwndParent != PWNDMESSAGE(pwnd))) { pwnd = pwnd->spwndParent; } break; case GA_ROOTOWNER: while (pwndParent = _GetParent(pwnd)) { pwnd = pwndParent; } break; } return pwnd; }
/*****************************************************************************\ * * RealChildWindowFromPoint() * * This returns the REAL child window at a point. The problem is that * ChildWindowFromPoint() doesn't deal with HTTRANSPARENT areas of * standard controls. We want to return a child behind a groupbox if it * is in the "clear" area. But we want to return a static field always * even though it too returns HTTRANSPARENT. * \*****************************************************************************/ PWND WINAPI _RealChildWindowFromPoint(PWND pwndParent, POINT pt) { PWND pwndChild; PWND pwndSave; if (pwndParent != PWNDDESKTOP(pwndParent)) { pt.x += pwndParent->rcClient.left; pt.y += pwndParent->rcClient.top; } /* * Is this point even in the parent? */ if (!PtInRect(&pwndParent->rcClient, pt) || (pwndParent->hrgnClip && !GrePtInRegion(pwndParent->hrgnClip, pt.x, pt.y))) { // Nope return NULL; } pwndSave = NULL; /* * Loop through the children. */ for (pwndChild = pwndParent->spwndChild; pwndChild; pwndChild = pwndChild->spwndNext) { if (!TestWF(pwndChild, WFVISIBLE)) continue; /* * Is this point in the child's window? */ if (!PtInRect(&pwndChild->rcWindow, pt) || (pwndChild->hrgnClip && !GrePtInRegion(pwndChild->hrgnClip, pt.x, pt.y))) continue; /* * OK, we are in somebody's window. Is this by chance a group box? */ if ((pwndChild->pcls->atomClassName == gpsi->atomSysClass[ICLS_BUTTON]) || (GETFNID(pwndChild) == FNID_BUTTON)) { if (TestWF(pwndChild, BFTYPEMASK) == LOBYTE(BS_GROUPBOX)) { pwndSave = pwndChild; continue; } } return pwndChild; } /* * Did we save a groupbox which turned out to have nothing behind it * at that point? */ if (pwndSave) { return pwndSave; } else { return pwndParent; } }
BOOL xxxPaintRect( PWND pwndBrush, PWND pwndPaint, HDC hdc, HBRUSH hbr, LPRECT lprc) { POINT ptOrg; CheckLock(pwndBrush); CheckLock(pwndPaint); if (pwndBrush == NULL) { pwndBrush = PtiCurrent()->rpdesk->pDeskInfo->spwnd; } if (pwndBrush == PWNDDESKTOP(pwndBrush)) { GreSetBrushOrg( hdc, 0, 0, &ptOrg); } else { GreSetBrushOrg( hdc, pwndBrush->rcClient.left - pwndPaint->rcClient.left, pwndBrush->rcClient.top - pwndPaint->rcClient.top, &ptOrg); } /* * If hbr < CTLCOLOR_MAX, it isn't really a brush but is one of our * special color values. Translate it to the appropriate WM_CTLCOLOR * message and send it off to get back a real brush. The translation * process assumes the CTLCOLOR*** and WM_CTLCOLOR*** values map directly. */ if (hbr < (HBRUSH)CTLCOLOR_MAX) { hbr = xxxGetControlColor(pwndBrush, pwndPaint, hdc, HandleToUlong(hbr) + WM_CTLCOLORMSGBOX); } FillRect(hdc, lprc, hbr); GreSetBrushOrg(hdc, ptOrg.x, ptOrg.y, NULL); return TRUE; }
void xxxTooltipHandleTimer(PTOOLTIPWND pttwnd, UINT uTID) { switch(uTID) { case TTT_SHOW: { /* * Move the tooltip window to the desktop so it can * be shown. Then show it. */ PWND pwndDesktop = PWNDDESKTOP(pttwnd); TL tlpwnd; ThreadLockAlways(pwndDesktop, &tlpwnd); xxxSetParent((PWND)pttwnd, pwndDesktop); ThreadUnlock(&tlpwnd); xxxShowTooltip(pttwnd); break; } case TTT_ANIMATE: /* * If animation is completed, set timer to hide */ if (TooltipAnimate(pttwnd)) { SetTooltipTimer(pttwnd, TTT_HIDE, pttwnd->dwHideDelay); } break; case TTT_HIDE: /* * Hide it */ xxxResetTooltip(pttwnd); break; } }
void xxxShowOwnedWindows( PWND pwndOwner, UINT cmdShow) { BOOL fShow; int cmdZoom; HWND *phwnd; PBWL pbwl; PWND pwnd, pwndTopOwner; TL tlpwnd; CheckLock(pwndOwner); /* * Not interested in child windows */ if (TestwndChild(pwndOwner)) return; if ((pbwl = BuildHwndList(PWNDDESKTOP(pwndOwner)->spwndChild, BWL_ENUMLIST, NULL)) == NULL) return; /* * NOTE: The following code assumes the values of SW_* are 1, 2, 3, and 4 */ fShow = (cmdShow >= SW_PARENTOPENING); cmdZoom = 0; if (cmdShow == SW_OTHERZOOM) cmdZoom = SIZEZOOMHIDE; if (cmdShow == SW_OTHERUNZOOM) cmdZoom = SIZEZOOMSHOW; /* * If zoom/unzoom, then open/close all popups owned by all other * windows. Otherwise, open/close popups owned by pwndOwner. */ for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) { /* * Lock the window before we play with it. * If the window handle is invalid, skip it */ if ((pwnd = RevalidateHwnd(*phwnd)) == NULL) continue; /* * Kanji windows can't be owned, so skip it. */ if (TestCF(pwnd, CFKANJIWINDOW)) continue; /* * If same as window passed in, skip it. */ if (pwnd == pwndOwner) continue; /* * Find ultimate owner of popup, but only go up as far as pwndOwner. */ if ((pwndTopOwner = pwnd->spwndOwner) != NULL) { /* * The TestwndHI is needed since if it has an icon, pwndOwner * is invalid. */ while (!TestwndHI(pwndTopOwner) && pwndTopOwner != pwndOwner && pwndTopOwner->spwndOwner != NULL) pwndTopOwner = pwndTopOwner->spwndOwner; } /* * Zoom/Unzoom case. */ if (cmdZoom != 0) { /* * If no parent, or parents are the same, skip. */ if (pwndTopOwner == NULL || pwndTopOwner == pwndOwner) continue; /* * If owner is iconic, then this window should stay hidden, * UNLESS the minimized window is disabled, in which case we'd * better show the window. */ if ( cmdShow == SW_OTHERUNZOOM && pwndTopOwner != NULL && TestWF(pwndTopOwner, WFMINIMIZED) && !TestWF(pwndTopOwner, WFDISABLED) ) continue; } else { /* * Hide/Iconize/Show/Open case. */ /* * If parents aren't the same, skip. */ if (pwndTopOwner != pwndOwner) continue; } /* * Hide or show if: * Showing & this is a hidden popup * OR * Hiding & this is a visible window */ if ((fShow && TestWF(pwnd, WFHIDDENPOPUP)) || (!fShow && TestWF(pwnd, WFVISIBLE))) { ThreadLockAlways(pwnd, &tlpwnd); xxxSendMessage(pwnd, WM_SHOWWINDOW, fShow, (LONG)cmdShow); ThreadUnlock(&tlpwnd); } } /* * Free the window list. */ FreeHwndList(pbwl); }
VOID DoQueuedSyncPaint( PWND pwnd, DWORD flags, PTHREADINFO pti) { PTHREADINFO ptiPwnd = GETPTI(pwnd); if ((ptiPwnd != pti) && TestWF(pwnd, WFSENDNCPAINT) && TestWF(pwnd, WFSENDERASEBKGND) && TestWF(pwnd, WFVISIBLE)) { PSMS psms = ptiPwnd->psmsReceiveList; /* * If this window already has a WM_SYNCPAINT queue'd up, then there's * no need to send another one. Also protects our heap from getting * chewed up. */ while (psms != NULL) { if ((psms->message == WM_SYNCPAINT) && (psms->spwnd == pwnd)) { break; } psms = psms->psmsReceiveNext; } if (psms == NULL) { /* * This will give this message the semantics of a notify * message (sendmessage no wait), without calling back * the WH_CALLWNDPROC hook. We don't want to do that * because that'll let all these processes with invalid * windows to process paint messages before they process * "synchronous" erasing or framing needs. * * Hi word of wParam must be zero or wow will drop it * * LATER mikeke * Do we need to send down the flags with DWP_ERASE and DSP_FRAME * in it? */ UserAssert(HIWORD(flags) == 0); QueueNotifyMessage(pwnd, WM_SYNCPAINT, flags, 0); /* * Set our syncpaint-pending flag, since we queued one up. This * will be used to check when we validate-parents for windows * without clipchildren. */ SetWF(pwnd, WFSYNCPAINTPENDING); } /* * If we posted a WM_SYNCPAINT for a top-level window that is not * of the current thread we're done; we'll pick up the children * when we process the message for real. If we're the desktop * however make sure we get all it children. */ if (pwnd != PWNDDESKTOP(pwnd)) return; } /* * Normally we like to enumerate all of this window's children and have * them erase their backgrounds synchronously. However, this is a bad * thing to do if the window is NOT CLIPCHLIDREN. Here's the scenario * we want to to avoid: * * 1. Window 'A' is invalidated * 2. 'A' erases itself (or not, doesn't matter) * 3. 'A's children are enumerated and they erase themselves. * 4. 'A' paints over its children (remember, 'A' isn't CLIPCHILDREN) * 5. 'A's children paint but their backgrounds aren't their ERASEBKND * color (because 'A' painted over them) and everything looks like * dirt. */ if ((flags & DSP_ALLCHILDREN) || ((flags & DSP_ENUMCLIPPEDCHILDREN) && TestWF(pwnd, WFCLIPCHILDREN))) { PWND pwndT; for (pwndT = pwnd->spwndChild; pwndT; pwndT = pwndT->spwndNext) { /* * Don't cause any more intertask sendmessages cause it does * bad things to cbt's windowproc hooks. (Due to SetParent * allowing child windows in the topwindow hierarchy. * The child bit also catches the desktop window; we want to */ if (TestWF(pwndT, WFCHILD) && (pti != GETPTI(pwndT))) continue; /* * Note that we pass only certain bits down as we recurse: * the other bits pertain to the current window only. */ DoQueuedSyncPaint(pwndT, flags, pti); } } }
BOOL xxxSnapWindow( PWND pwnd) { PTHREADINFO ptiCurrent; RECT rc; HDC hdcScr = NULL; HDC hdcMem = NULL; BOOL fRet; HBITMAP hbmOld; HBITMAP hbm; HANDLE hPal; LPLOGPALETTE lppal; int palsize; int iFixedPaletteEntries; BOOL fSuccess; PWND pwndT; TL tlpwndT; PWINDOWSTATION pwinsta; TL tlpwinsta; CheckLock(pwnd); UserAssert(pwnd); ptiCurrent = PtiCurrent(); /* * If this is a thread of winlogon, don't do the snapshot. */ if (GetCurrentProcessId() == gpidLogon) return FALSE; /* * Get the affected windowstation */ if (!NT_SUCCESS(ReferenceWindowStation( PsGetCurrentThread(), NULL, WINSTA_READSCREEN, &pwinsta, TRUE)) || pwinsta->dwWSF_Flags & WSF_NOIO) { return FALSE; } /* * If the window is on another windowstation, do nothing */ if (pwnd->head.rpdesk->rpwinstaParent != pwinsta) return FALSE; /* * Get the parent of any child windows. */ while ((pwnd != NULL) && TestWF(pwnd, WFCHILD)) { pwnd = pwnd->spwndParent; } /* * Lock the windowstation before we leave the critical section */ ThreadLockWinSta(ptiCurrent, pwinsta, &tlpwinsta); /* * Open the clipboard and empty it. * * pwndDesktop is made the owner of the clipboard, instead of the * currently active window; -- SANKAR -- 20th July, 1989 -- */ pwndT = ptiCurrent->rpdesk->pDeskInfo->spwnd; ThreadLockWithPti(ptiCurrent, pwndT, &tlpwndT); fSuccess = xxxOpenClipboard(pwndT, NULL); ThreadUnlock(&tlpwndT); if (!fSuccess) { ThreadUnlockWinSta(ptiCurrent, &tlpwinsta); return FALSE; } xxxEmptyClipboard(pwinsta); /* * Use the whole window. */ CopyRect(&rc, &pwnd->rcWindow); /* * Only snap what is on the screen. */ if (!IntersectRect(&rc, &rc, &gpDispInfo->rcScreen)) { fRet = FALSE; goto SnapExit; } rc.right -= rc.left; rc.bottom -= rc.top; /* * Figure out how far offset from window origin visible part is */ if (pwnd != PWNDDESKTOP(pwnd)) { rc.left -= pwnd->rcWindow.left; rc.top -= pwnd->rcWindow.top; } /* * Get the entire window's DC. */ hdcScr = _GetWindowDC(pwnd); if (!hdcScr) goto MemoryError; /* * Create the memory DC. */ hdcMem = GreCreateCompatibleDC(hdcScr); if (!hdcMem) goto MemoryError; /* * Create the destination bitmap. If it fails, then attempt * to create a monochrome bitmap. * Did we have enough memory? */ if (SYSMET(SAMEDISPLAYFORMAT)) { hbm = GreCreateCompatibleBitmap(hdcScr, rc.right, rc.bottom); } else { hbm = GreCreateBitmap(rc.right, rc.bottom, 1, gpDispInfo->BitCountMax, NULL); } if (!hbm) { hbm = GreCreateBitmap(rc.right, rc.bottom, 1, 1, NULL); if (!hbm) goto MemoryError; } /* * Select the bitmap into the memory DC. */ hbmOld = GreSelectBitmap(hdcMem, hbm); /* * Snap!!! * Check the return value because the process taking the snapshot * may not have access to read the screen. */ fRet = GreBitBlt(hdcMem, 0, 0, rc.right, rc.bottom, hdcScr, rc.left, rc.top, SRCCOPY | CAPTUREBLT, 0); /* * Restore the old bitmap into the memory DC. */ GreSelectBitmap(hdcMem, hbmOld); /* * If the blt failed, leave now. */ if (!fRet) goto SnapExit; _SetClipboardData(CF_BITMAP, hbm, FALSE, TRUE); /* * If this is a palette device, let's throw the current system palette * into the clipboard also. Useful if the user just snapped a window * containing palette colors... */ if (TEST_PUSIF(PUSIF_PALETTEDISPLAY)) { int i; int iPalSize; palsize = GreGetDeviceCaps(hdcScr, SIZEPALETTE); /* * Determine the number of system colors. */ if (GreGetSystemPaletteUse(hdcScr) == SYSPAL_STATIC) iFixedPaletteEntries = GreGetDeviceCaps(hdcScr, NUMRESERVED); else iFixedPaletteEntries = 2; lppal = (LPLOGPALETTE)UserAllocPoolWithQuota( (LONG)(sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * palsize), TAG_CLIPBOARD); if (lppal != NULL) { lppal->palVersion = 0x300; lppal->palNumEntries = (WORD)palsize; if (GreGetSystemPaletteEntries(hdcScr, 0, palsize, lppal->palPalEntry)) { iPalSize = palsize - iFixedPaletteEntries / 2; for (i = iFixedPaletteEntries / 2; i < iPalSize; i++) { /* * Any non system palette enteries need to have the NOCOLLAPSE * flag set otherwise bitmaps containing different palette * indices but same colors get messed up. */ lppal->palPalEntry[i].peFlags = PC_NOCOLLAPSE; } if (hPal = GreCreatePalette(lppal)) _SetClipboardData(CF_PALETTE, hPal, FALSE, TRUE); } UserFreePool(lppal); } } PlayEventSound(USER_SOUND_SNAPSHOT); fRet = TRUE; SnapExit: /* * Release the window/client DC. */ if (hdcScr) { _ReleaseDC(hdcScr); } xxxCloseClipboard(pwinsta); Unlock(&pwinsta->spwndClipOwner); /* * Delete the memory DC. */ if (hdcMem) { GreDeleteDC(hdcMem); } ThreadUnlockWinSta(ptiCurrent, &tlpwinsta); return fRet; MemoryError: /* * Display an error message box. */ ClientNoMemoryPopup(); fRet = FALSE; goto SnapExit; }