Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2488 lines
79 KiB

/****************************** Module Header ******************************\
* Module Name: dwp.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* This module contains xxxDefWindowProc and related functions.
*
* History:
* 10-22-90 DarrinM Created stubs.
* 13-Feb-1991 mikeke Added Revalidation code
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/***************************************************************************\
*
* DWP_DrawItem()
*
* Does default WM_DRAWITEM handling.
*
\***************************************************************************/
void DWP_DrawItem(
LPDRAWITEMSTRUCT lpdis)
{
if (lpdis->CtlType == ODT_LISTBOX) {
/*
* Default OwnerDraw Listbox Item Drawing
*/
if ( (lpdis->itemAction == ODA_FOCUS)
|| ( lpdis->itemAction == ODA_DRAWENTIRE
&& lpdis->itemState & ODS_FOCUS)
) {
ClientFrame(lpdis->hDC, &lpdis->rcItem, gpsi->hbrGray, PATINVERT, 1, 1);
}
}
}
/***************************************************************************\
* xxxDWP_SetRedraw
*
* This routine sets/resets the VISIBLE flag for windows who don't want any
* redrawing. Although a fast way of preventing paints, it is the apps
* responsibility to reset this flag once they need painting. Otherwise,
* the window will be rendered transparent (could leave turds on the
* screen).
*
*
* History:
* 07-24-91 darrinm Ported from Win 3.1 sources.
\***************************************************************************/
void xxxDWP_SetRedraw(
PWND pwnd,
BOOL fRedraw)
{
CheckLock(pwnd);
UserAssert(IsWinEventNotifyDeferredOK());
if (fRedraw) {
if (!TestWF(pwnd, WFVISIBLE)) {
SetVisible(pwnd, SV_SET);
/*
* We made this window visible - if it is behind any SPBs,
* then we need to go invalidate them.
*
* We do this AFTER we make the window visible, so that
* SpbCheckHwnd won't ignore it.
*/
if (AnySpbs())
SpbCheckPwnd(pwnd);
/*
* Now we need to invalidate/recalculate any affected cache entries
* This call must be AFTER the window state change
* No need to DeferWinEventNotify() since pwnd is threadlocked.
*/
zzzInvalidateDCCache(pwnd, IDC_DEFAULT);
/*
* Because 3.1 sometimes doesn't draw window frames when 3.0 did,
* we need to ensure that the frame gets drawn if the window is
* later invalidated after a WM_SETREDRAW(TRUE)
*/
SetWF(pwnd, WFSENDNCPAINT);
}
} else {
if (TestWF(pwnd, WFVISIBLE)) {
/*
* Invalidate any SPBs.
*
* We do this BEFORE we make the window invisible, so
* SpbCheckHwnd() won't ignore it.
*/
if (AnySpbs())
SpbCheckPwnd(pwnd);
/*
* Clear WFVISIBLE and delete any update regions lying around.
*/
SetVisible(pwnd, SV_UNSET | (TestWF(pwnd, WFWIN31COMPAT) ? SV_CLRFTRUEVIS : 0));
/*
* Now we need to invalidate/recalc affected cache entries
* This call must be AFTER the window state change
* No need to DeferWinEventNotify() since we're about to return.
*/
zzzInvalidateDCCache(pwnd, IDC_DEFAULT);
}
}
}
/***************************************************************************\
* DWP_GetEnabledPopup
*
* History:
* 10-28-90 MikeHar Ported from Windows.
\***************************************************************************/
PWND DWP_GetEnabledPopup(
PWND pwndStart)
{
PWND pwndT, pwnd;
PTHREADINFO ptiStart;
BOOL fVisitedFirstChild = FALSE;
ptiStart = GETPTI(pwndStart);
pwnd = pwndStart->spwndNext;
#ifdef SYSMODALWINDOWS
if (gspwndSysModal)
return NULL;
#endif
/*
* The user clicked on a window that is disabled. That window is pwndStart.
* This loop is designed to evaluate what application this window is
* associated with, and activate that "application", by finding what window
* associated with that application can be activated. This is done by
* enumerating top level windows, searching for a top level enabled
* and visible ownee associated with this application.
*/
while (pwnd != pwndStart) {
if (pwnd == NULL) {
/*
* Warning! Win 3.1 had PWNDDESKTOP(pwndStart)->spwndChild
* which could loop forever if pwndStart was a child window
*/
if (fVisitedFirstChild) {
/*
* If we visited the first child before then do not loop
* for ever, it is time to return.
*/
return NULL;
}
pwnd = pwndStart->spwndParent->spwndChild;
fVisitedFirstChild = TRUE;
continue;
}
/*
* We have two cases we need to watch out for here. The first is when
* applications call AssociateThreadInput() to tie two threads
* together to share input state. If the threads own the same queue,
* then associate them together: this way, when two threads call
* AttachThreadInput(), one created the main window, one created the
* dialog window, when you click on the main window, they'll both
* come to the top (rather than beeping). In this case we want to
* compare queues. When Control Panel starts Setup in the Network
* applet is one type of example of attached input.
*
* The second case is WOW apps. All wow apps have the same queue
* so to retain Win 3.1 compatibility, we want to treat each app
* as an individual task (Win 3.1 tests hqs), so we will compare
* PTI's for WOW apps.
*
* To see this case start 16 bit notepad and 16 bit write. Do file
* open on write and then give notepad the focus now click on write's
* main window and the write file open dialog should activate.
*
* Another related case is powerpnt. This case is interesting because
* it tests that we do not find another window to activate when nested
* windows are up and you click on a owner's owner. Run Powerpnt, do
* Edit-Insert-Picture and Object-Recolor Picture will bring up a
* dialog with combos, drop down one of the color combo and then click
* on powerpnt's main window - focus should stay with the dialogs
* combo and it should stay dropped down.
*/
if (((ptiStart->TIF_flags & TIF_16BIT) && (GETPTI(pwnd) == ptiStart)) ||
(!(ptiStart->TIF_flags & TIF_16BIT) && (GETPTI(pwnd)->pq == ptiStart->pq))) {
if (!TestWF(pwnd, WFDISABLED) && TestWF(pwnd, WFVISIBLE)) {
pwndT = pwnd->spwndOwner;
/*
* If this window is the parent of a popup window,
* bring up only one.
*/
while (pwndT) {
if (pwndT == pwndStart)
return pwnd;
pwndT = pwndT->spwndOwner;
}
/*
* Win9x continues looping only if pwnd is WEFTOPMOST. NT4 just returns, like Win3.1
* As soon as we find a window on the queue, we stop. So if the queue owns
* multiple top level unowned windows, then this code will probably not find
* the enabled popup. Note that owned windows are supposed to be on top of the
* owner, usally right on top of it (ie, pwnd->spwndNext == pwnd->spwndOwner)
* so this code used to find any other top level unowned windows before the enabled
* popup and bail. Odd.
* So let's continue looping. Hopefully this won't cause any compatibility problems
*/
// return NULL;
}
}
pwnd = pwnd->spwndNext;
}
return NULL;
}
/***************************************************************************\
* xxxDWP_ProcessVirtKey
*
* History:
* 10-28-90 MikeHar Ported from Windows.
\***************************************************************************/
void xxxDWP_ProcessVirtKey(
UINT wKey)
{
PTHREADINFO pti;
TL tlpwndActive;
pti = PtiCurrent();
if (pti->pq->spwndActive == NULL)
return;
switch (wKey) {
case VK_F4:
if (TestCF(pti->pq->spwndActive, CFNOCLOSE))
break;
/*
* Don't change the focus if the child window has it.
*/
if (pti->pq->spwndFocus == NULL ||
GetTopLevelWindow(pti->pq->spwndFocus) !=
pti->pq->spwndActive) {
ThreadLockAlwaysWithPti(pti, pti->pq->spwndActive, &tlpwndActive);
xxxSetFocus(pti->pq->spwndActive);
ThreadUnlock(&tlpwndActive);
}
_PostMessage(pti->pq->spwndActive, WM_SYSCOMMAND, SC_CLOSE, 0L);
break;
case VK_TAB:
/*
* If alt-tab is reserved by console, don't bring up the alt-tab
* window.
*/
if (GETPTI(pti->pq->spwndActive)->fsReserveKeys & CONSOLE_ALTTAB)
break;
case VK_ESCAPE:
case VK_F6:
ThreadLockAlwaysWithPti(pti, pti->pq->spwndActive, &tlpwndActive);
xxxSendMessage(pti->pq->spwndActive, WM_SYSCOMMAND,
(UINT)(_GetKeyState(VK_SHIFT) < 0 ? SC_NEXTWINDOW : SC_PREVWINDOW),
(LONG)(DWORD)(WORD)wKey);
ThreadUnlock(&tlpwndActive);
break;
}
}
/***************************************************************************\
* xxxDWP_Paint
*
* Handle WM_PAINT and WM_PAINTICON messages.
*
* History:
* 07-24-91 darrinm Ported from Win 3.1 sources.
\***************************************************************************/
void xxxDWP_Paint(
PWND pwnd)
{
PAINTSTRUCT ps;
CheckLock(pwnd);
/*
* Bad handling of a WM_PAINT message, the application called
* BeginPaint/EndPaint and is now calling DefWindowProc for the same
* WM_PAINT message. Just return so we don't get full drag problems.
* (Word and Excel do this).
*
* Added the check for empty-client-rects. ObjectVision has a problem
* with empty-windows being invalidated during a full-drag. They used
* to get blocked at the STARTPAINT and couldn't get through to
* xxxBeginPaint to validate their update-rgn.
*
* i.e.
* a) Parent has a child-window with an empty rect. On a full
* drag of the parent, we process SetWindowPos() to paint
* the new position.
*
* b) During the parents processing of WM_PAINT, it calls
* GetUpdateRect() on the empty-child, which sets the STARTPAINT
* on its window.
*
* c) On return to the parent WM_PAINT handler, it calls
* UpdateWindow() on the child, and used to get blocked here
* because the STARTPAINT bit was set. The Child never gets
* updated, causing an infinite loop.
*
* *) By checking for an empty-rectangle, we will let it through
* to validate.
*
*/
if (TestWF(pwnd, WFSTARTPAINT) && !IsRectEmpty(&(pwnd->rcClient))) {
return;
}
if (xxxBeginPaint(pwnd, &ps)) {
xxxEndPaint(pwnd, &ps);
}
}
/***************************************************************************\
* xxxDWP_EraseBkgnd
*
*
* History:
* 07-24-91 darrinm Ported from Win 3.1 sources.
\***************************************************************************/
BOOL xxxDWP_EraseBkgnd(
PWND pwnd,
UINT msg,
HDC hdc)
{
HBRUSH hbr;
CheckLock(pwnd);
switch (msg) {
case WM_ICONERASEBKGND:
//
// Old compatibility: Many hack apps use this to paint the
// desktop wallpaper. We never send WM_ICONERASEBKGND anymore
// because we don't have client areas in our minimized windows.
//
if (!TestWF(pwnd, WFCHILD)) {
xxxInternalPaintDesktop(pwnd, hdc, TRUE);
} else {
return FALSE;
}
break;
case WM_ERASEBKGND:
if (hbr = pwnd->pcls->hbrBackground) {
// Convert sys colors to proper brush
if (hbr <= (HBRUSH)COLOR_MAX)
hbr = SYSHBRUSH((ULONG_PTR)hbr - 1);
/*
* Remove call to UnrealizeObject. GDI handles this
* for brushes on NT.
*
* if (hbr != SYSHBR(DESKTOP))
* GreUnrealizeObject(hbr);
*/
xxxFillWindow(pwnd, pwnd, hdc, hbr);
} else {
return FALSE;
}
}
return TRUE;
}
/***************************************************************************\
* xxxDWP_SetCursorInfo
*
*
* History:
* 26-Apr-1994 mikeke Created
\***************************************************************************/
/***************************************************************************\
* xxxDWP_SetCursor
*
*
* History:
* 07-24-91 darrinm Ported from Win 3.1 sources.
\***************************************************************************/
BOOL xxxDWP_SetCursor(
PWND pwnd,
HWND hwndHit,
int codeHT,
UINT msg)
{
PWND pwndParent, pwndPopup, pwndHit;
PCURSOR pcur;
LRESULT lt;
TL tlpwndParent;
TL tlpwndPopup;
CheckLock(pwnd);
UserAssert(IsWinEventNotifyDeferredOK());
/*
* wParam == pwndHit == pwnd that cursor is over
* lParamL == ht == Hit test area code (result of WM_NCHITTEST)
* lParamH == msg == Mouse message number
*/
if (msg)
{
switch (codeHT)
{
case HTLEFT:
case HTRIGHT:
pcur = SYSCUR(SIZEWE);
break;
case HTTOP:
case HTBOTTOM:
pcur = SYSCUR(SIZENS);
break;
case HTTOPLEFT:
case HTBOTTOMRIGHT:
pcur = SYSCUR(SIZENWSE);
break;
case HTTOPRIGHT:
case HTBOTTOMLEFT:
pcur = SYSCUR(SIZENESW);
break;
default:
goto NotSize;
}
pwndHit = RevalidateHwnd(hwndHit);
if (pwndHit == NULL)
return FALSE;
if (TestWF(pwndHit, WFSYSMENU)) {
TL tlpwndHit;
DWORD dwState;
ThreadLockAlways(pwndHit, &tlpwndHit);
dwState = _GetMenuState(
xxxGetSysMenu(pwndHit, TRUE), SC_SIZE, MF_BYCOMMAND);
ThreadUnlock(&tlpwndHit);
if ((dwState != (DWORD) -1) && (dwState & MFS_GRAYED))
goto UseNormalCursor;
}
/*
* No need to DeferWinEventNotify() - we're about to return
*/
zzzSetCursor(pcur);
return TRUE;
}
NotSize:
pwndParent = GetChildParent(pwnd);
/*
* Some windows (like the list boxes of comboboxes), are marked with
* the child bit but are actually child of the desktop (can happen
* if you call SetParent()). Make this special case check for
* the desktop here.
*/
if (pwndParent == PWNDDESKTOP(pwnd))
pwndParent = NULL;
if (pwndParent != NULL) {
ThreadLockAlways(pwndParent, &tlpwndParent);
lt = xxxSendMessage(pwndParent, WM_SETCURSOR, (WPARAM)hwndHit,
MAKELONG(codeHT, msg));
ThreadUnlock(&tlpwndParent);
if (lt != 0)
return TRUE;
}
if (msg == 0) {
/*
* No need to DeferWinEventNotify() - we're about to return
*/
zzzSetCursor(SYSCUR(ARROW));
} else {
pwndHit = RevalidateHwnd(hwndHit);
if (pwndHit == NULL)
return FALSE;
switch (codeHT) {
case HTCLIENT:
if (pwndHit->pcls->spcur != NULL) {
/*
* No need to DeferWinEventNotify() - we're about to return
*/
zzzSetCursor(pwndHit->pcls->spcur);
}
break;
#ifdef LAME_BUTTON
case HTLAMEBUTTON:
/*
* Show the hand cursor if we are over the Lame! text
* in the caption.
*/
zzzSetCursor(SYSCUR(HAND));
break;
#endif // LAME_BUTTON
case HTERROR:
switch (msg) {
case WM_MOUSEMOVE:
if (TestUP(ACTIVEWINDOWTRACKING)) {
xxxActiveWindowTracking(pwnd, WM_SETCURSOR, codeHT);
}
break;
case WM_LBUTTONDOWN:
if ((pwndPopup = DWP_GetEnabledPopup(pwnd)) != NULL) {
if (pwndPopup != PWNDDESKTOP(pwnd)->spwndChild) {
PWND pwndActiveOld;
pwndActiveOld = PtiCurrent()->pq->spwndActive;
ThreadLockAlways(pwndPopup, &tlpwndPopup);
xxxSetWindowPos(pwnd, NULL, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
xxxSetActiveWindow(pwndPopup);
ThreadUnlock(&tlpwndPopup);
if (pwndActiveOld != PtiCurrent()->pq->spwndActive)
break;
/*
*** ELSE FALL THRU **
*/
}
}
/*
*** FALL THRU **
*/
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_XBUTTONDOWN:
{
PWND pwndDlg;
pwndDlg = DWP_GetEnabledPopup(pwnd);
if (pwndDlg != NULL) {
ThreadLockAlways(pwndDlg, &tlpwndPopup);
xxxFlashWindow(pwndDlg,
MAKELONG(FLASHW_ALL, UP(FOREGROUNDFLASHCOUNT)),
(gpsi->dtCaretBlink >> 3));
ThreadUnlock(&tlpwndPopup);
}
xxxMessageBeep(0);
break;
}
}
/*
*** FALL THRU **
*/
default:
UseNormalCursor:
/*
* No need to DeferWinEventNotify() - we're about to return
*/
zzzSetCursor(SYSCUR(ARROW));
break;
}
}
return FALSE;
}
/***************************************************************************\
* xxxDWP_NCMouse
*
*
* History:
* 07-24-91 darrinm Ported from Win 3.1 sources.
\***************************************************************************/
void xxxDWP_NCMouse(
PWND pwnd,
UINT msg,
UINT ht,
LPARAM lParam)
{
UINT cmd;
CheckLock(pwnd);
cmd = 0;
switch (msg) {
case WM_NCLBUTTONDOWN:
switch (ht) {
case HTZOOM:
case HTREDUCE:
case HTCLOSE:
case HTHELP:
cmd = xxxTrackCaptionButton(pwnd, ht);
break;
default:
// Change into a MV/SZ command
if (ht >= HTSIZEFIRST && ht <= HTSIZELAST)
cmd = SC_SIZE + (ht - HTSIZEFIRST + WMSZ_SIZEFIRST);
break;
}
if (cmd != 0) {
//
// For SysCommands on system menu, don't do if menu item is
// disabled.
//
if ( cmd != SC_CONTEXTHELP
&& TestWF(pwnd, WFSYSMENU)
&& !TestwndChild(pwnd)
) {
if (_GetMenuState(xxxGetSysMenu(pwnd, TRUE), cmd & 0xFFF0,
MF_BYCOMMAND) & MFS_GRAYED)
break;
}
xxxSendMessage(pwnd, WM_SYSCOMMAND, cmd, lParam);
break;
}
// FALL THRU
case WM_NCLBUTTONUP:
case WM_NCLBUTTONDBLCLK:
xxxHandleNCMouseGuys(pwnd, msg, ht, lParam);
break;
}
}
/***************************************************************************\
*
* History:
* 09-Mar-1992 mikeke From win3.1
\***************************************************************************/
UINT AreNonClientAreasToBePainted(
PWND pwnd)
{
WORD wRetValue = 0;
/*
* Check if Active and Inactive captions have same color
*/
if (SYSRGB(ACTIVECAPTION) != SYSRGB(INACTIVECAPTION) ||
SYSRGB(CAPTIONTEXT) != SYSRGB(INACTIVECAPTIONTEXT)) {
wRetValue = DC_CAPTION;
}
/*
* We want to repaint the borders if we're not minimized and
* we have a sizing border and the active/inactive colors are
* different.
*/
if (!TestWF(pwnd, WFMINIMIZED) && TestWF(pwnd, WFSIZEBOX) &&
(SYSRGB(ACTIVEBORDER) != SYSRGB(INACTIVEBORDER))) {
// We need to redraw the sizing border.
wRetValue |= DC_FRAME;
}
return wRetValue;
}
/***************************************************************************\
*
* History:
* 09-Mar-1992 mikeke From win3.1
* 07-Aug-1996 vadimg Added menu grayout and underline code
\***************************************************************************/
VOID xxxDWP_DoNCActivate(
PWND pwnd,
DWORD dwFlags,
HRGN hrgnClip)
{
UINT wFlags = DC_CAPTION;
CheckLock(pwnd);
/*
* Later5.0 Gerardob. Since activation must follow focus, modeless
* menu windows are activated so they can receive keyboard input;
* however, we want the notification frame on, even when inactive.
* (so it looks just like regular menus).
* There are other scenarios when we want focus and activation on
* different parent-child chains so we should consider allowing this.
*/
if ((dwFlags & NCA_ACTIVE)
|| (!(dwFlags & NCA_FORCEFRAMEOFF)
&& IsModelessMenuNotificationWindow(pwnd))) {
SetWF(pwnd, WFFRAMEON);
wFlags |= DC_ACTIVE;
} else {
ClrWF(pwnd, WFFRAMEON);
}
if ((hrgnClip != HRGN_NONE) && TestWF(pwnd, WFVISIBLE) && !TestWF(pwnd, WFNONCPAINT)) {
HDC hdc;
WORD wBorderOrCap = (WORD)AreNonClientAreasToBePainted(pwnd);
if (wBorderOrCap) {
/*
* Validate and Copy the region for our use. Since we
* hand this off to GetWindowDC() we won't have to delete
* the region (done in ReleaseDC()). Regardless, the region
* passed in from the user is its responsibility to delete.
*/
hrgnClip = UserValidateCopyRgn(hrgnClip);
if (hdc = _GetDCEx(pwnd, hrgnClip, DCX_WINDOW | DCX_USESTYLE)) {
/*
* Draw the menu for grayout and underlines
*/
if (TestWF(pwnd, WFMPRESENT)) {
int cxFrame, cyFrame;
cxFrame = cyFrame = GetWindowBorders(pwnd->style,
pwnd->ExStyle, TRUE, FALSE);
cxFrame *= SYSMET(CXBORDER);
cyFrame *= SYSMET(CYBORDER);
xxxMenuBarDraw(pwnd, hdc, cxFrame, cyFrame);
}
xxxDrawCaptionBar(pwnd, hdc, wBorderOrCap | wFlags);
_ReleaseDC(hdc);
} else {
GreDeleteObject(hrgnClip);
}
}
}
}
/***************************************************************************\
*
* History:
* 09-Mar-1992 mikeke From win3.1
\***************************************************************************/
BOOL xxxRedrawTitle(
PWND pwnd, UINT wFlags)
{
BOOL fDrawn = TRUE;
CheckLock(pwnd);
if (TestWF(pwnd, WFVISIBLE)) {
if (TestWF(pwnd, WFBORDERMASK) == (BYTE)LOBYTE(WFCAPTION)) {
if (TestwndFrameOn(pwnd)) {
wFlags |= DC_ACTIVE;
}
if (IsInsideUserApiHook()) {
xxxSendMessage(pwnd, WM_NCUAHDRAWCAPTION, wFlags, 0);
} else {
HDC hdc = _GetWindowDC(pwnd);
xxxDrawCaptionBar(pwnd, hdc, wFlags);
_ReleaseDC(hdc);
}
} else {
fDrawn = FALSE;
}
}
if ( IsTrayWindow(pwnd) && (wFlags & (DC_ICON | DC_TEXT)) ) {
HWND hw = HWq(pwnd);
xxxCallHook(HSHELL_REDRAW, (WPARAM)hw, 0L, WH_SHELL);
PostShellHookMessages(HSHELL_REDRAW, (LPARAM)hw);
}
return(fDrawn);
}
/***************************************************************************\
*
* History:
* 09-Mar-1992 mikeke From win3.1
\***************************************************************************/
void xxxDWP_DoCancelMode(
PWND pwnd)
{
PTHREADINFO pti = PtiCurrent();
PWND pwndCapture = pti->pq->spwndCapture;
PMENUSTATE pMenuState;
/*
* If the below menu lines are changed in any way, then SQLWin
* won't work if in design mode you drop some text, double click on
* it, then try to use the heirarchical menus.
*/
pMenuState = GetpMenuState(pwnd);
if ((pMenuState != NULL)
&& (pwnd == pMenuState->pGlobalPopupMenu->spwndNotify)
&& !pMenuState->fModelessMenu) {
xxxEndMenu(pMenuState);
}
if (pwndCapture == pwnd) {
PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd);
if (pSBTrack && (pSBTrack->xxxpfnSB != NULL))
xxxEndScroll(pwnd, TRUE);
if (pti->pmsd != NULL) {
pti->pmsd->fTrackCancelled = TRUE;
pti->TIF_flags &= ~TIF_MOVESIZETRACKING;
/*
* Also clip the cursor back to the whole screen
* so we don't get confused in xxxMoveSize.
* This fix bug 64166.
*/
zzzClipCursor((LPRECT)NULL);
}
/*
* If the capture is still set, just release at this point.
*/
xxxReleaseCapture();
}
}
BOOL xxxDWPPrint(
PWND pwnd,
HDC hdc,
LPARAM lParam)
{
POINT pt;
int iDC;
LPRECT lprc;
PWND pwndSave = pwnd;
LPARAM lParamSave = lParam;
BOOL fNotVisible;
PBWL pbwl;
HWND *phwnd;
TL tlpwnd;
DWORD dwOldLayout;
BOOL bMirrorDC;
CheckLock(pwnd);
if ((lParam & PRF_CHECKVISIBLE) && !_IsWindowVisible(pwnd))
return(FALSE);
bMirrorDC = (TestWF(pwnd, WEFLAYOUTRTL) && !MIRRORED_HDC(hdc));
if (lParam & PRF_NONCLIENT) {
/*
* draw non-client area first
*/
if (fNotVisible = !TestWF(pwnd, WFVISIBLE))
SetVisible(pwnd, SV_SET);
SetWF(pwnd, WFMENUDRAW);
if (bMirrorDC) {
LONG wox = pwnd->rcWindow.right - pwnd->rcWindow.left - 1;
dwOldLayout = GreSetLayout(hdc, wox, LAYOUT_RTL);
if(IsInsideUserApiHook()) {
xxxSendMessage(pwnd, WM_NCUAHDRAWFRAME, (WPARAM)hdc, TestWF(pwnd, WFFRAMEON) ? DF_ACTIVE : 0L);
} else {
xxxDrawWindowFrame(pwnd, hdc, TestWF(pwnd, WFFRAMEON) ? DF_ACTIVE : 0L);
}
GreSetLayout(hdc, wox, dwOldLayout);
} else {
if(IsInsideUserApiHook()) {
xxxSendMessage(pwnd, WM_NCUAHDRAWFRAME, (WPARAM)hdc, TestWF(pwnd, WFFRAMEON) ? DF_ACTIVE : 0L);
} else {
xxxDrawWindowFrame(pwnd, hdc, TestWF(pwnd, WFFRAMEON) ? DF_ACTIVE : 0L);
}
}
ClrWF(pwnd, WFMENUDRAW);
if (fNotVisible)
SetVisible(pwnd, SV_UNSET);
}
if (lParam & PRF_CLIENT) {
/*
* draw client area second
*/
iDC = GreSaveDC(hdc);
GreGetWindowOrg(hdc, &pt);
if (lParam & PRF_NONCLIENT) {
int xBorders, yBorders;
/*
* adjust for non-client area
*/
xBorders = pwnd->rcClient.left - pwnd->rcWindow.left;
yBorders = pwnd->rcClient.top - pwnd->rcWindow.top;
GreSetWindowOrg(hdc, pt.x - xBorders, pt.y - yBorders, NULL);
}
lprc = &pwnd->rcClient;
GreIntersectClipRect(hdc, 0, 0, lprc->right - lprc->left, lprc->bottom - lprc->top);
if (bMirrorDC) {
LONG wox = pwnd->rcClient.right - pwnd->rcClient.left - 1;
dwOldLayout = GreSetLayout(hdc, wox, LAYOUT_RTL);
if (lParam & PRF_ERASEBKGND)
xxxSendMessage(pwnd, WM_ERASEBKGND, (WPARAM) hdc, 0L);
xxxSendMessage(pwnd, WM_PRINTCLIENT, (WPARAM) hdc, lParam);
GreSetLayout(hdc, wox, dwOldLayout);
} else {
if (lParam & PRF_ERASEBKGND)
xxxSendMessage(pwnd, WM_ERASEBKGND, (WPARAM) hdc, 0L);
xxxSendMessage(pwnd, WM_PRINTCLIENT, (WPARAM) hdc, lParam);
}
GreRestoreDC(hdc, iDC);
pt.x += pwnd->rcWindow.left;
pt.y += pwnd->rcWindow.top;
if (lParam & PRF_CHILDREN) {
/*
* when drawing children, always include nonclient area
*/
lParam |= PRF_NONCLIENT | PRF_ERASEBKGND;
lParam &= ~PRF_CHECKVISIBLE;
/*
* draw children last
*/
pbwl = BuildHwndList(pwnd->spwndChild, BWL_ENUMLIST, NULL);
if (pbwl != NULL) {
for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
if ((pwnd = RevalidateHwnd(*phwnd)) == NULL)
continue;
if (TestWF(pwnd, WFVISIBLE)) {
lprc = &pwnd->rcWindow;
iDC = GreSaveDC(hdc);
GreSetWindowOrg(hdc, pt.x - lprc->left, pt.y - lprc->top, NULL);
if (!TestCF(pwnd, CFPARENTDC)) {
GreIntersectClipRect(hdc, 0, 0, lprc->right - lprc->left, lprc->bottom - lprc->top);
}
ThreadLockAlways(pwnd, &tlpwnd);
xxxSendMessage(pwnd, WM_PRINT, (WPARAM) hdc, lParam);
ThreadUnlock(&tlpwnd);
GreRestoreDC(hdc, iDC);
}
}
FreeHwndList(pbwl);
}
}
if (lParam & PRF_OWNED) {
pbwl = BuildHwndList((PWNDDESKTOP(pwnd))->spwndChild, BWL_ENUMLIST, NULL);
if (pbwl != NULL) {
for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
if ((pwnd = RevalidateHwnd(*phwnd)) == NULL)
continue;
if ((pwnd->spwndOwner == pwndSave) && TestWF(pwnd, WFVISIBLE)) {
iDC = GreSaveDC(hdc);
GreSetWindowOrg(hdc, pt.x - pwnd->rcWindow.left, pt.y - pwnd->rcWindow.top, NULL);
ThreadLockAlways(pwnd, &tlpwnd);
xxxSendMessage(pwnd, WM_PRINT, (WPARAM) hdc, lParamSave);
ThreadUnlock(&tlpwnd);
GreRestoreDC(hdc, iDC);
}
}
FreeHwndList(pbwl);
}
}
}
return TRUE;
}
/***************************************************************************\
*
* DWP_GetIcon()
*
* Gets the small or big icon for a window. For small icons, if we created
* the thing, we don't let the app see it.
*
\***************************************************************************/
HICON DWP_GetIcon(
PWND pwnd,
UINT uType)
{
HICON hicoTemp;
ATOM atom;
if (uType > ICON_SMALL2) {
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "WM_GETICON: Invalid wParam value (0x%X)", uType);
return (HICON)NULL;
}
if (uType == ICON_BIG) {
atom = gpsi->atomIconProp;
} else {
UserAssert(uType == ICON_SMALL || uType == ICON_SMALL2);
atom = gpsi->atomIconSmProp;
}
/*
* Get the icon from the window
*/
hicoTemp = (HICON)_GetProp(pwnd, MAKEINTATOM(atom), PROPF_INTERNAL);
/*
* If it's a USER created small icon don't return it.
*/
if (uType == ICON_SMALL && hicoTemp) {
PCURSOR pcurTemp;
pcurTemp = (PCURSOR)HMValidateHandleNoRip((HCURSOR)hicoTemp, TYPE_CURSOR);
if (pcurTemp != NULL && (pcurTemp->CURSORF_flags & CURSORF_SECRET)) {
hicoTemp = (HICON)NULL;
}
}
return hicoTemp;
}
/***************************************************************************\
*
* DestroyWindowSmIcon()
*
* Destroys the small icon of a window if we've created a cached one.
* This is because it's called in winrare.c when the caption height
* changes.
*
\***************************************************************************/
BOOL DestroyWindowSmIcon(
PWND pwnd)
{
HCURSOR hcursor;
PCURSOR pcursor;
//
// Get the small icon property first...
//
hcursor = (HCURSOR)_GetProp(pwnd, MAKEINTATOM(gpsi->atomIconSmProp), PROPF_INTERNAL);
if (hcursor == NULL)
return FALSE;
pcursor = (PCURSOR)HMValidateHandleNoRip(hcursor, TYPE_CURSOR);
if (pcursor == NULL)
return FALSE;
//
// Remove it if it's a secretly created one
//
if (pcursor->CURSORF_flags & CURSORF_SECRET)
{
ClrWF(pwnd, WFSMQUERYDRAGICON);
InternalRemoveProp(pwnd, MAKEINTATOM(gpsi->atomIconSmProp), PROPF_INTERNAL);
_DestroyCursor(pcursor, CURSOR_ALWAYSDESTROY);
return(TRUE);
}
else
return(FALSE);
}
/***************************************************************************\
*
* xxxDWP_SetIcon()
*
* Sets the small or big icon for a window, and returns back the previous
* one.
*
\***************************************************************************/
HICON xxxDWP_SetIcon(
PWND pwnd,
WPARAM wType,
HICON hicoNew)
{
HICON hIcon;
HICON hIconSm;
HICON hOld;
BOOL fRedraw;
CheckLock(pwnd);
#if DBG
if (hicoNew && !IS_PTR(hicoNew)) {
RIPMSG1(RIP_WARNING, "WM_SETICON: Icon handle missing HIWORD (0x%08X)", hicoNew);
}
#endif
if (wType > ICON_RECREATE)
{
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "WM_SETICON: Invalid wParam value (0x%0X)", wType);
return (HICON)NULL;
}
/*
* Regenerate small icons if requested.
*/
if (wType == ICON_RECREATE) {
xxxRecreateSmallIcons(pwnd);
return 0L;
}
/*
* Save old icon
*/
hIcon = (HICON)_GetProp(pwnd, MAKEINTATOM(gpsi->atomIconProp), PROPF_INTERNAL);
hIconSm = (HICON)_GetProp(pwnd, MAKEINTATOM(gpsi->atomIconSmProp), PROPF_INTERNAL);
hOld = ((wType == ICON_SMALL) ? hIconSm : hIcon);
/*
* Only update the icons if they have changed
*/
if (hOld != hicoNew)
{
PCURSOR pcursor;
BOOL fWasCache = FALSE;
fRedraw = TRUE;
/*
* Always remove the small icon because it is either being replaced or
* will be recreated if the big icon is being set.
*/
pcursor = (PCURSOR)HMValidateHandleNoRip(hIconSm, TYPE_CURSOR);
if (pcursor && (pcursor->CURSORF_flags & CURSORF_SECRET)) {
fWasCache = TRUE;
_DestroyCursor(pcursor, CURSOR_ALWAYSDESTROY);
}
if (wType == ICON_SMALL) {
/*
* Apps never see the icons that USER creates behind their backs
* from big icons.
*/
if (fWasCache)
hOld = NULL;
hIconSm = hicoNew;
} else {
if (fWasCache) {
/*
* Force us to recalc the small icon to match the new big icon
*/
hIconSm = NULL;
} else if (hIconSm) {
/*
* Redraw of the caption isn't needed because the small icon
* didn't change.
*/
fRedraw = FALSE;
}
hIcon = hicoNew;
}
/*
* Store the icons off the window as properties
*/
InternalSetProp(pwnd, MAKEINTATOM(gpsi->atomIconProp), (HANDLE)hIcon, PROPF_INTERNAL | PROPF_NOPOOL);
InternalSetProp(pwnd, MAKEINTATOM(gpsi->atomIconSmProp), (HANDLE)hIconSm, PROPF_INTERNAL | PROPF_NOPOOL);
/*
* Create the small icon if it doesn't exist.
*/
if (hIcon && !hIconSm)
xxxCreateWindowSmIcon(pwnd, hIcon, TRUE);
/*
* Redraw caption if the small icon has changed
*/
if (fRedraw)
xxxRedrawTitle(pwnd, DC_ICON);
}
return hOld;
}
// --------------------------------------------------------------------------
//
// CreateWindowSmIcon()
//
// Makes a per-window small icon copy of a big icon.
//
// --------------------------------------------------------------------------
HICON xxxCreateWindowSmIcon(
PWND pwnd,
HICON hIconBig,
BOOL fNotQueryDrag)
{
HICON hIconSm = NULL;
PCURSOR pcurs = NULL,pcursBig;
CheckLock(pwnd);
UserAssert(hIconBig);
pcursBig = (PCURSOR)HMValidateHandleNoRip(hIconBig, TYPE_CURSOR);
if (pcursBig) {
pcurs = xxxClientCopyImage(PtoHq(pcursBig),
pcursBig->rt == PTR_TO_ID(RT_ICON) ? IMAGE_ICON : IMAGE_CURSOR,
SYSMET(CXSMICON),
SYSMET(CYSMICON),
LR_DEFAULTCOLOR | (fNotQueryDrag ? LR_COPYFROMRESOURCE : 0));
if (pcurs != NULL)
hIconSm = PtoHq(pcurs);
}
if (hIconSm) {
pcurs->CURSORF_flags |= CURSORF_SECRET;
InternalSetProp(pwnd, MAKEINTATOM(gpsi->atomIconSmProp), (HANDLE)hIconSm, PROPF_INTERNAL | PROPF_NOPOOL);
if (!fNotQueryDrag)
SetWF(pwnd, WFSMQUERYDRAGICON);
}
return(hIconSm);
}
/***************************************************************************\
* xxxDefWindowProc (API)
*
* History:
* 10-23-90 MikeHar Ported from WaWaWaWindows.
* 12-07-90 IanJa CTLCOLOR handling round right way
\***************************************************************************/
LRESULT xxxDefWindowProc(
PWND pwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
/*
* If we've got a registered UserApiHook handler loaded in this process,
* pass the message off to it. For server side wndproc, we need to make an exception
* passing WM_NCDESTROY so that themes can get a chance to do cleanup since they will not
* see if in the post hook for those type of windows
*/
if (IsInsideUserApiHook() &&
(!TestWF(pwnd, WFDESTROYED) || ((message == WM_NCDESTROY) && TestWF(pwnd, WFSERVERSIDEPROC) && !(pwnd->fnid & FNID_DELETED_BIT))) &&
(!(PtiCurrent()->TIF_flags & TIF_INCLEANUP)) &&
xxxLoadUserApiHook()) {
/*
* Call back to the appropriate DefWindowProc handler.
*/
if (TestWF(pwnd, WFANSIPROC)) {
return ScSendMessage(pwnd,
message,
wParam,
lParam,
0,
gpsi->apfnClientA.pfnDispatchDefWindowProc,
SCMS_FLAGS_ANSI);
} else {
return ScSendMessage(pwnd,
message,
wParam,
lParam,
0,
gpsi->apfnClientW.pfnDispatchDefWindowProc,
0);
}
}
return xxxRealDefWindowProc(pwnd, message, wParam, lParam);
}
LRESULT xxxRealDefWindowProc(
PWND pwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
LRESULT lt;
PWND pwndT;
TL tlpwndParent;
TL tlpwndT;
int icolBack;
int icolFore;
int i;
CheckLock(pwnd);
if (pwnd == (PWND)-1) {
return 0;
}
if (message > WM_USER) {
return 0;
}
/*
* Important: If you add cases to the switch statement below,
* and those messages can originate on the client
* side, add the messages to server.c's gawDefWindowMsgs
* array or else the client will short-circuit the call
* and return 0.
*/
switch (message) {
case WM_CLIENTSHUTDOWN:
return xxxClientShutdown(pwnd, wParam);
case WM_NCACTIVATE:
xxxDWP_DoNCActivate(pwnd, (LOWORD(wParam) ? NCA_ACTIVE : 0), (HRGN)lParam);
return (LONG)TRUE;
case WM_NCHITTEST:
return FindNCHit(pwnd, (LONG)lParam);
case WM_NCCALCSIZE:
/*
* wParam = fCalcValidRects
* lParam = LPRECT rgrc[3]:
* lprc[0] = rcWindowNew = New window rectangle
* if fCalcValidRects:
* lprc[1] = rcWindowOld = Old window rectangle
* lprc[2] = rcClientOld = Old client rectangle
*
* On return:
* rgrc[0] = rcClientNew = New client rect
* if fCalcValidRects:
* rgrc[1] = rcValidDst = Destination valid rectangle
* rgrc[2] = rcValidSrc = Source valid rectangle
*/
xxxCalcClientRect(pwnd, (LPRECT)lParam, FALSE);
break;
case WM_NCLBUTTONDOWN:
case WM_NCLBUTTONUP:
case WM_NCLBUTTONDBLCLK:
xxxDWP_NCMouse(pwnd, message, (UINT)wParam, lParam);
break;
case WM_CANCELMODE:
{
/*
* Terminate any modes the system might
* be in, such as scrollbar tracking, menu mode,
* button capture, etc.
*/
xxxDWP_DoCancelMode(pwnd);
}
break;
case WM_NCCREATE:
if (TestWF(pwnd, (WFHSCROLL | WFVSCROLL))) {
if (_InitPwSB(pwnd) == NULL)
return (LONG)FALSE;
}
#ifdef FE_SB // xxxDefWindowProc()
/*
* If CREATESTRUCTEX.strName contains resource id, we don't
* need to call DefSetText(). because it is a numeric number,
* it does not need Ansi <-> Unicode translation.
*/
if (lParam) {
PLARGE_STRING pstr = &((PCREATESTRUCTEX)lParam)->strName;
if (pwnd->head.rpdesk == NULL || pstr == NULL || pstr->Buffer == NULL) {
pwnd->strName.Length = 0;
return TRUE;
}
if ((pstr->bAnsi && (pstr->Length >= sizeof(BYTE)) &&
(*(PBYTE)(pstr->Buffer) == 0xff)) ||
(!pstr->bAnsi && (pstr->Length >= sizeof(WCHAR)) &&
(*(PWCHAR)(pstr->Buffer) == 0xffff))) {
/*
* This is Resource ID, we just return here with TRUE.
*/
return (LONG)TRUE;
}
}
#endif // FE_SB
SetWF(pwnd, WFTITLESET);
return (LONG)DefSetText(pwnd, &((PCREATESTRUCTEX)lParam)->strName);
case WM_PRINT:
return((LRESULT)xxxDWPPrint(pwnd, (HDC) wParam, lParam));
case WM_NCPAINT:
{
HDC hdc;
/*
* Force the drawing of the menu.
*/
SetWF(pwnd, WFMENUDRAW);
/*
* Get a window DC intersected with hrgnClip,
* but make sure that hrgnClip doesn't get deleted.
*/
hdc = _GetDCEx(pwnd,
(HRGN)wParam,
DCX_USESTYLE |
DCX_WINDOW |
DCX_INTERSECTRGN |
DCX_NODELETERGN |
DCX_LOCKWINDOWUPDATE);
xxxDrawWindowFrame(pwnd,
hdc,
(TestWF(pwnd, WFFRAMEON) &&
(GETPTI(pwnd)->pq == gpqForeground)) ? DF_ACTIVE : 0L);
_ReleaseDC(hdc);
ClrWF(pwnd, WFMENUDRAW);
}
break;
case WM_UAHINIT:
/*
* If the theme is becoming active, we need to "prime" the UAH's to
* ensure that they get loaded. This can happen if an existing app
* becomes themed but doesn't call xxxCreateWindow() or
* xxxDefWindowProc()
*/
if (IsInsideUserApiHook()) {
if (!(PtiCurrent()->TIF_flags & TIF_INCLEANUP)) {
return xxxLoadUserApiHook();
}
}
break;
case WM_NCUAHDRAWCAPTION:
{
HDC hdc = _GetWindowDC(pwnd);
xxxDrawCaptionBar(pwnd, hdc, (UINT) wParam);
_ReleaseDC(hdc);
}
break;
case WM_NCUAHDRAWFRAME:
{
xxxDrawWindowFrame(pwnd,(HDC)wParam, (UINT)lParam);
}
break;
case WM_ISACTIVEICON:
return TestWF(pwnd, WFFRAMEON) != 0;
case WM_SETTEXT:
/*
* At one time we added an optimization to do nothing if the new
* text was the same as the old text but found that QCcase does not work
* because it calls SetWindowText not to change the text but
* cause the title bar to redraw after it had added the sysmenu
* through SetWindowLong
*/
if (lt = DefSetText(pwnd, (PLARGE_STRING)lParam)) {
/*
* Text was set, so redraw title bar
*/
xxxRedrawTitle(pwnd, DC_TEXT);
xxxWindowEvent(EVENT_OBJECT_NAMECHANGE, pwnd, OBJID_WINDOW, INDEXID_CONTAINER, 0);
}
return lt;
case WM_GETTEXT:
if (wParam != 0) {
PLARGE_STRING pstr = (PLARGE_STRING)lParam;
if (pwnd->strName.Length) {
if (pstr->bAnsi) {
i = WCSToMB(pwnd->strName.Buffer,
pwnd->strName.Length / sizeof(WCHAR),
(LPSTR *)&pstr->Buffer, pstr->MaximumLength - 1, FALSE);
((LPSTR)pstr->Buffer)[i] = 0;
pstr->Length = i;
} else {
i = TextCopy(&pwnd->strName, pstr->Buffer, (UINT)wParam);
pstr->Length = i * sizeof(WCHAR);
}
return i;
}
/*
* else Null terminate the text buffer since there is no text.
*/
if (pstr->bAnsi) {
*(LPSTR)pstr->Buffer = 0;
} else {
*(LPWSTR)pstr->Buffer = 0;
}
}
return 0L;
case WM_GETTEXTLENGTH:
if (pwnd->strName.Length) {
UINT cch;
if (lParam) {
RtlUnicodeToMultiByteSize(&cch,
pwnd->strName.Buffer,
pwnd->strName.Length);
} else {
cch = pwnd->strName.Length / sizeof(WCHAR);
}
return cch;
}
return 0L;
case WM_CLOSE:
xxxDestroyWindow(pwnd);
break;
case WM_PAINT:
case WM_PAINTICON:
xxxDWP_Paint(pwnd);
break;
case WM_ERASEBKGND:
case WM_ICONERASEBKGND:
return (LONG)xxxDWP_EraseBkgnd(pwnd, message, (HDC)wParam);
case WM_SYNCPAINT:
/*
* Clear our sync-paint pending flag.
*/
ClrWF(pwnd, WFSYNCPAINTPENDING);
/*
* This message is sent when SetWindowPos() is trying
* to get the screen looking nice after window rearrangement,
* and one of the windows involved is of another task.
* This message avoids lots of inter-app message traffic
* by switching to the other task and continuing the
* recursion there.
*
* wParam = flags
* LOWORD(lParam) = hrgnClip
* HIWORD(lParam) = pwndSkip (not used; always NULL)
*
* pwndSkip is now always NULL.
*
* NOTE: THIS MESSAGE IS FOR INTERNAL USE ONLY! ITS BEHAVIOR
* IS DIFFERENT IN 3.1 THAN IN 3.0!!
*/
xxxInternalDoSyncPaint(pwnd, (DWORD)wParam);
break;
case WM_QUERYOPEN:
case WM_QUERYENDSESSION:
case WM_DEVICECHANGE:
case WM_POWERBROADCAST:
return (LONG)TRUE;
// Default handling for WM_CONTEXTMENU support
case WM_RBUTTONUP:
if (TestWF(pwnd, WEFLAYOUTRTL)) {
lParam = MAKELPARAM(pwnd->rcClient.right - GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) + pwnd->rcClient.top);
} else {
lParam = MAKELONG(GET_X_LPARAM(lParam) + pwnd->rcClient.left, GET_Y_LPARAM(lParam) + pwnd->rcClient.top);
}
xxxSendMessage(pwnd, WM_CONTEXTMENU, (WPARAM) HWq(pwnd), lParam);
break;
case WM_NCRBUTTONDOWN:
{
int nHit;
MSG msg;
LONG spt;
PTHREADINFO pti = PtiCurrent();
nHit = FindNCHit(pwnd, (LONG)lParam);
if (nHit == HTVSCROLL || nHit == HTHSCROLL) {
if (!_IsDescendant(pti->pq->spwndActive, pwnd)) {
break;
}
} else if (nHit == HTCAPTION || nHit == HTSYSMENU) {
if (pwnd != pti->pq->spwndActive) {
break;
}
} else {
break;
}
xxxSetCapture(pwnd);
while (TRUE)
{
if (xxxPeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
{
if (msg.message == WM_RBUTTONUP)
{
xxxReleaseCapture();
spt = POINTTOPOINTS(msg.pt);
nHit = FindNCHit(pwnd, spt);
if ((nHit == HTCAPTION) || (nHit == HTSYSMENU) ||
(nHit == HTVSCROLL) || (nHit == HTHSCROLL)) {
xxxSendMessage(pwnd, WM_CONTEXTMENU, (WPARAM) HWq(pwnd), spt);
}
break;
}
}
if (pwnd != pti->pq->spwndCapture)
// Someone else grabbed the capture. Bail out.
break;
// xxxWaitMessage();
if (!xxxSleepThread(QS_MOUSE, 0, TRUE))
break;
}
}
break;
/*
* Default handling for WM_APPCOMMAND support
*/
case WM_NCXBUTTONUP:
case WM_XBUTTONUP:
{
WORD cmd;
WORD keystate;
LPARAM lParamAppCommand;
cmd = 0;
switch (GET_XBUTTON_WPARAM(wParam)) {
case XBUTTON1:
cmd = APPCOMMAND_BROWSER_BACKWARD;
break;
case XBUTTON2:
cmd = APPCOMMAND_BROWSER_FORWARD;
break;
default:
break;
}
if (cmd == 0) {
break;
}
cmd |= FAPPCOMMAND_MOUSE;
if (message == WM_XBUTTONUP) {
keystate = GET_KEYSTATE_WPARAM(wParam);
} else {
keystate = (WORD)GetMouseKeyFlags(PtiCurrent()->pq);
}
lParamAppCommand = MAKELPARAM(keystate, cmd);
xxxSendMessage(pwnd, WM_APPCOMMAND, (WPARAM) HWq(pwnd), lParamAppCommand);
break;
}
case WM_MOUSEWHEEL:
if (TestwndChild(pwnd)) {
ThreadLockAlways(pwnd->spwndParent, &tlpwndParent);
xxxSendMessage(pwnd->spwndParent, WM_MOUSEWHEEL, wParam, lParam);
ThreadUnlock(&tlpwndParent);
}
break;
case WM_CONTEXTMENU:
{
int nHit;
nHit = FindNCHit(pwnd, (LONG)lParam);
/*
* Put up a context menu if we clicked on a scroll bar
*/
if ((nHit == HTVSCROLL) || (nHit == HTHSCROLL)) {
if (_IsDescendant(PtiCurrent()->pq->spwndActive, pwnd)) {
xxxDoScrollMenu(pwnd, NULL, nHit - HTHSCROLL, lParam);
}
break;
}
if (TestwndChild(pwnd)) {
ThreadLockAlways(pwnd->spwndParent, &tlpwndParent);
xxxSendMessage(pwnd->spwndParent, WM_CONTEXTMENU, (WPARAM) HWq(pwnd), lParam);
ThreadUnlock(&tlpwndParent);
} else {
/*
* Do default context menu if right clicked on caption
*/
if (pwnd == PtiCurrent()->pq->spwndActive)
{
if (nHit == HTCAPTION)
goto DoTheDefaultThang;
else if (nHit == HTSYSMENU)
{
i = SC_CLOSE;
goto DoTheSysMenuThang;
}
/*
* If this was generated by the keyboard (apps key), then simulate a shift-f10
* for old apps so they get a crack at putting up their context menu.
*/
if (lParam == KEYBOARD_MENU && !TestWF(pwnd, WFWIN40COMPAT))
xxxSimulateShiftF10();
}
}
}
break;
case WM_APPCOMMAND:
/*
* Bubble the message to the parent
*/
if (TestwndChild(pwnd)) {
ThreadLockAlways(pwnd->spwndParent, &tlpwndParent);
lt = xxxSendMessage(pwnd->spwndParent, WM_APPCOMMAND, wParam, lParam);
ThreadUnlock(&tlpwndParent);
return lt;
} else if (pwnd != PWNDDESKTOP(pwnd) ) {
BOOL bEatMe = FALSE;
/*
* Notify listeners on the SHELLHOOK that a WM_APPCOMMAND message was not handled
* We also post this message to the shell queue so they don't need to load themselves
* into every process with a hook.
* We don't bother about the desktop since csrss services it and it doesn't accept
* shell hooks so there is no point.
*/
if (IsHooked(PtiCurrent(), WHF_SHELL))
bEatMe = (xxxCallHook(HSHELL_APPCOMMAND, wParam, lParam, WH_SHELL) != 0);
/*
* The shell only wants to get this notification if no one in
* the hook chain handled this WM_APPCOMMAND, so we check the
* return value of the hook (if there was one). See RAID #54863.
*/
if(!bEatMe)
PostShellHookMessages(HSHELL_APPCOMMAND, lParam);
}
break;
case WM_KEYF1:
xxxSendHelpMessage(pwnd, HELPINFO_WINDOW,
(int) (TestwndChild(pwnd) ? PTR_TO_ID(pwnd->spmenu) : 0),
HWq(pwnd), GetContextHelpId(pwnd));
break;
case WM_SYSCOMMAND:
xxxSysCommand(pwnd, (UINT)wParam, lParam);
break;
case WM_KEYDOWN:
if (wParam == VK_F10) {
PtiCurrent()->pq->QF_flags |= QF_FF10STATUS;
HandleF10:
/*
* Generate a WM_CONTEXTMENU for new apps for shift-f10.
*/
if (_GetKeyState(VK_SHIFT) < 0 && TestWF(pwnd, WFWIN40COMPAT)) {
xxxSendMessage(pwnd, WM_CONTEXTMENU, (WPARAM)HWq(pwnd), KEYBOARD_MENU);
}
}
break;
case WM_HELP:
// If this window is a child window, Help message must be passed on
// to it's parent; Else, this must be passed on to the owner window.
pwndT = (TestwndChild(pwnd)? pwnd->spwndParent : pwnd->spwndOwner);
if (pwndT && (pwndT != _GetDesktopWindow())) {
ThreadLockAlways(pwndT, &tlpwndT);
lt = xxxSendMessage(pwndT, WM_HELP, wParam, lParam);
ThreadUnlock(&tlpwndT);
return lt;
}
return 0L;
case WM_SYSKEYDOWN:
{
PTHREADINFO pti = PtiCurrent();
/*
* Is the ALT key down?
*/
if (HIWORD(lParam) & SYS_ALTERNATE) {
/*
* Toggle QF_FMENUSTATUS iff this is NOT a repeat KEYDOWN
* message; Only if the prev key state was 0, then this is the
* first KEYDOWN message and then we consider toggling menu
* status; Fix for Bugs #4531 & #4566 --SANKAR-- 10-02-89.
*/
if ((HIWORD(lParam) & SYS_PREVKEYSTATE) == 0) {
/*
* Don't have to lock pwndActive because it's
* processing this key.
*/
if ((wParam == VK_MENU) &&
!(pti->pq->QF_flags & QF_FMENUSTATUS)) {
pti->pq->QF_flags |= QF_FMENUSTATUS;
xxxDrawMenuBarUnderlines(pwnd, TRUE);
} else {
pti->pq->QF_flags &= ~(QF_FMENUSTATUS|QF_FMENUSTATUSBREAK);
}
}
pti->pq->QF_flags &= ~QF_FF10STATUS;
xxxDWP_ProcessVirtKey((UINT)wParam);
} else {
if (wParam == VK_F10) {
pti->pq->QF_flags |= QF_FF10STATUS;
goto HandleF10;
}
}
}
break;
case WM_SYSKEYUP:
case WM_KEYUP:
{
PTHREADINFO pti = PtiCurrent();
/*
* press and release F10 or ALT. Send this only to top-level windows,
* otherwise MDI gets confused. The fix in which DefMDIChildProc()
* passed up the message was insufficient in the case a child window
* of the MDI child had the focus.
* Also make sure the sys-menu activation wasn't broken by a mouse
* up or down when the Alt was down (QF_MENUSTATUSBREAK).
*/
if ((wParam == VK_MENU && !(pti->pq->QF_flags & QF_TABSWITCHING) && ((pti->pq->QF_flags &
(QF_FMENUSTATUS | QF_FMENUSTATUSBREAK)) == QF_FMENUSTATUS)) ||
(wParam == VK_F10 && (pti->pq->QF_flags & QF_FF10STATUS ))) {
pwndT = GetTopLevelWindow(pwnd);
if (gspwndFullScreen != pwndT) {
ThreadLockWithPti(pti, pwndT, &tlpwndT);
/*
* Draw the underlines for F10. This was already down for ALT
* when the key went down.
*/
if (wParam == VK_F10) {
xxxDrawMenuBarUnderlines(pwnd, TRUE);
}
xxxSendMessage(pwndT, WM_SYSCOMMAND, SC_KEYMENU, 0);
ThreadUnlock(&tlpwndT);
}
}
/*
* Turn off bit for tab-switching. This is set in the _KeyEvent()
* routine when it's been determined we're doing switching. This
* is necessary for cases where the ALT-KEY is release before the
* TAB-KEY. In which case, the FMENUSTATUS bit would be cleared
* by the ALT-KEY-UP and would have forced us into a syscommand
* loop. This guarentees that we don't enter that condition.
*/
if (wParam == VK_MENU) {
pti->pq->QF_flags &= ~QF_TABSWITCHING;
xxxDrawMenuBarUnderlines(pwnd, FALSE);
}
pti->pq->QF_flags &= ~(QF_FMENUSTATUS | QF_FMENUSTATUSBREAK | QF_FF10STATUS);
}
break;
case WM_SYSCHAR:
{
PTHREADINFO pti = PtiCurrent();
/*
* If syskey is down and we have a char...
*/
pti->pq->QF_flags &= ~(QF_FMENUSTATUS | QF_FMENUSTATUSBREAK);
if (wParam == VK_RETURN && TestWF(pwnd, WFMINIMIZED)) {
/*
* If the window is iconic and user hits RETURN, we want to
* restore this window.
*/
_PostMessage(pwnd, WM_SYSCOMMAND, SC_RESTORE, 0L);
break;
}
if ((HIWORD(lParam) & SYS_ALTERNATE) && wParam) {
if (wParam == VK_TAB || wParam == VK_ESCAPE)
break;
/*
* Send ALT-SPACE only to top-level windows.
*/
if ((wParam == MENUSYSMENU) && (TestwndChild(pwnd))) {
ThreadLockAlwaysWithPti(pti, pwnd->spwndParent, &tlpwndParent);
xxxSendMessage(pwnd->spwndParent, message, wParam, lParam);
ThreadUnlock(&tlpwndParent);
} else {
xxxSendMessage(pwnd, WM_SYSCOMMAND, SC_KEYMENU, (DWORD)wParam);
}
} else {
/*
* Ctrl-Esc produces a WM_SYSCHAR, But should not beep;
*/
if (wParam != VK_ESCAPE)
xxxMessageBeep(0);
}
}
break;
case WM_UNICHAR:
if (wParam == UNICODE_NOCHAR) {
return FALSE;
} else {
_PostMessage(pwnd, WM_CHAR, wParam, lParam);
}
break;
case WM_CHARTOITEM:
case WM_VKEYTOITEM:
/*
* Do default processing for keystrokes into owner draw listboxes.
*/
return -1L;
case WM_ACTIVATE:
if (wParam)
xxxSetFocus(pwnd);
break;
case WM_INPUTLANGCHANGEREQUEST:
{
PWND pwndFocus = PtiCurrent()->pq->spwndFocus;
/*
* #115190
* Dialog does not forward I.L.Reqest to the focused window.
* (Memphis compatible issue)
*/
if (pwndFocus && (pwndFocus != pwnd) &&
pwnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_DIALOG]) {
/*
* pass message to focus'ed window. Old app, pass on to
* focus'ed window which may be ML aware. (edit class
* for example).
*/
ThreadLockAlways(pwndFocus, &tlpwndT);
xxxSendMessage(pwndFocus, message, wParam, lParam);
ThreadUnlock(&tlpwndT);
} else if (!xxxActivateKeyboardLayout(_GetProcessWindowStation(NULL),
(HKL)lParam, KLF_SETFORPROCESS, pwnd)) {
RIPERR1(ERROR_INVALID_KEYBOARD_HANDLE, RIP_WARNING, "WM_INPUTLANGCHANGEREQUEST: Invalid keyboard handle (0x%08lx)", lParam);
}
break;
}
case WM_INPUTLANGCHANGE:
{
PBWL pbwl;
HWND *phwnd;
TL tlpwnd;
pbwl = BuildHwndList(pwnd->spwndChild, BWL_ENUMLIST, NULL);
if (pbwl == NULL)
return 0;
for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
/*
* Make sure this hwnd is still around.
*/
if ((pwnd = RevalidateHwnd(*phwnd)) == NULL)
continue;
ThreadLockAlways(pwnd, &tlpwnd);
RIPMSG1(RIP_VERBOSE, "WM_INPUTLANGCHANGE: Sending message to pwnd %#p", pwnd);
xxxSendMessage(pwnd, message, wParam, lParam);
ThreadUnlock(&tlpwnd);
}
FreeHwndList(pbwl);
break;
}
case WM_SETREDRAW:
xxxDWP_SetRedraw(pwnd, wParam != 0);
break;
case WM_WINDOWPOSCHANGING:
{
/*
* If the window's size is changing, adjust the passed-in size
*/
WINDOWPOS *ppos = ((WINDOWPOS *)lParam);
if (!(ppos->flags & SWP_NOSIZE)) {
xxxAdjustSize(pwnd, &ppos->cx, &ppos->cy);
}
}
break;
case WM_WINDOWPOSCHANGED:
xxxHandleWindowPosChanged(pwnd, (PWINDOWPOS)lParam);
break;
case WM_CTLCOLORSCROLLBAR:
if (gpsi->BitCount < 8 ||
SYSRGB(3DHILIGHT) != SYSRGB(SCROLLBAR) ||
SYSRGB(3DHILIGHT) == SYSRGB(WINDOW))
{
/*
* Remove call to UnrealizeObject. GDI handles this
* for brushes on NT.
*
* GreUnrealizeObject(ghbrGray);
*/
GreSetBkColor((HDC)wParam, SYSRGB(3DHILIGHT));
GreSetTextColor((HDC)wParam, SYSRGB(3DFACE));
return((LRESULT)gpsi->hbrGray);
}
icolBack = COLOR_3DHILIGHT;
icolFore = COLOR_BTNTEXT;
goto SetColor;
case WM_CTLCOLORBTN:
if (TestWF(pwnd, WFWIN40COMPAT)) {
icolBack = COLOR_3DFACE;
icolFore = COLOR_BTNTEXT;
} else {
goto ColorDefault;
}
goto SetColor;
case WM_CTLCOLORSTATIC:
case WM_CTLCOLORDLG:
case WM_CTLCOLORMSGBOX:
// We want static controls in dialogs to have the 3D
// background color, but statics in windows to inherit
// their parents' background.
if (TestWF(pwnd, WFWIN40COMPAT)
) {
icolBack = COLOR_3DFACE;
icolFore = COLOR_WINDOWTEXT;
goto SetColor;
}
// ELSE FALL THRU...
case WM_CTLCOLOR: // here for WOW only
case WM_CTLCOLORLISTBOX:
case WM_CTLCOLOREDIT:
ColorDefault:
icolBack = COLOR_WINDOW;
icolFore = COLOR_WINDOWTEXT;
SetColor:
GreSetBkColor((HDC)wParam, gpsi->argbSystem[icolBack]);
GreSetTextColor((HDC)wParam, gpsi->argbSystem[icolFore]);
return (LRESULT)(SYSHBRUSH(icolBack));
case WM_SETCURSOR:
/*
* wParam == pwndHit == pwnd that cursor is over
* lParamL == ht == Hit test area code (result of WM_NCHITTEST)
* lParamH == msg == Mouse message number
*/
return (LONG)xxxDWP_SetCursor(pwnd, (HWND)wParam, (int)(SHORT)lParam,
HIWORD(lParam));
case WM_MOUSEACTIVATE:
pwndT = GetChildParent(pwnd);
if (pwndT != NULL) {
ThreadLockAlways(pwndT, &tlpwndT);
lt = xxxSendMessage(pwndT, WM_MOUSEACTIVATE, wParam, lParam);
ThreadUnlock(&tlpwndT);
if (lt != 0)
return lt;
}
/*
* Moving, sizing or minimizing? Activate AFTER we take action.
* If the user LEFT clicked in the title bar, don't activate now:
*/
return ( (LOWORD(lParam) == HTCAPTION)
&& (HIWORD(lParam) == WM_LBUTTONDOWN)
)
? (LONG)MA_NOACTIVATE
: (LONG)MA_ACTIVATE;
case WM_SHOWWINDOW:
/*
* If we are being called because our owner window is being shown,
* hidden, minimized, or un-minimized, then we must hide or show
* show ourself as appropriate.
*
* This behavior occurs for popup windows or owned windows only.
* It's not designed for use with child windows.
*/
if (LOWORD(lParam) != 0 && (TestwndPopup(pwnd) || pwnd->spwndOwner)) {
/*
* The WFHIDDENPOPUP flag is an internal flag that indicates
* that the window was hidden because its owner was hidden.
* This way we only show windows that were hidden by this code,
* not intentionally by the application.
*
* Go ahead and hide or show this window, but only if:
*
* a) we need to be hidden, or
* b) we need to be shown, and we were hidden by
* an earlier WM_SHOWWINDOW message
*/
if ((!wParam && TestWF(pwnd, WFVISIBLE)) ||
(wParam && !TestWF(pwnd, WFVISIBLE) &&
TestWF(pwnd, WFHIDDENPOPUP))) {
/*
* Remember that we were hidden by WM_SHOWWINDOW processing
*/
ClrWF(pwnd, WFHIDDENPOPUP);
if (!wParam)
SetWF(pwnd, WFHIDDENPOPUP);
xxxShowWindow(
pwnd,
(wParam ? SW_SHOWNOACTIVATE : SW_HIDE) | TEST_PUDF(PUDF_ANIMATE));
}
}
break;
case WM_SYSMENU:
if ( !TestWF(pwnd, WFDISABLED)
&& ( (GETPTI(pwnd)->pq == gpqForeground)
|| xxxSetForegroundWindow(pwnd, FALSE))
)
{
PMENU pMenu;
TL tpmenu;
DoTheDefaultThang:
if (TestWF(pwnd, WFMAXIMIZED) || TestWF(pwnd, WFMINIMIZED))
i = SC_RESTORE;
else
i = SC_MAXIMIZE;
DoTheSysMenuThang:
if ((pMenu = xxxGetSysMenu(pwnd, TRUE)) != NULL)
{
_SetMenuDefaultItem(pMenu, i, MF_BYCOMMAND);
// Tell the shell we are bringing it up the system menu
PostShellHookMessages(HSHELL_SYSMENU, (LPARAM)HWq(pwnd));
ThreadLockAlways(pMenu, &tpmenu);
if (lParam == 0xFFFFFFFF)
{
// this is a keyboard generated WM_SYSMENU
if (FDoTray())
{
TPMPARAMS tpm;
tpm.cbSize = sizeof(TPMPARAMS);
if (xxxSendMinRectMessages(pwnd, &tpm.rcExclude)) {
xxxTrackPopupMenuEx(pMenu, TPM_SYSMENU | TPM_VERTICAL,
tpm.rcExclude.left, tpm.rcExclude.top, pwnd, &tpm);
}
}
}
else
{
xxxTrackPopupMenuEx(pMenu, TPM_RIGHTBUTTON | TPM_SYSMENU,
GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pwnd, NULL);
}
ThreadUnlock(&tpmenu);
}
}
break;
case WM_DRAWITEM:
DWP_DrawItem((LPDRAWITEMSTRUCT)lParam);
break;
case WM_GETHOTKEY:
return (LONG)DWP_GetHotKey(pwnd);
break;
case WM_SETHOTKEY:
return (LONG)DWP_SetHotKey(pwnd, (DWORD)wParam);
break;
case WM_GETICON:
return (LRESULT)DWP_GetIcon(pwnd, (BOOL)wParam);
case WM_SETICON:
return (LRESULT)xxxDWP_SetIcon(pwnd, wParam, (HICON)lParam);
case WM_COPYGLOBALDATA:
/*
* This message is used to thunk WM_DROPFILES messages along
* with other things. If we end up here with it, directly
* call the client back to finish processing of this message.
* This assumes that the ultimate destination of the
* WM_DROPFILES message is in the client side's process context.
*/
return(SfnCOPYGLOBALDATA(NULL, 0, wParam, lParam, 0, 0, 0, NULL));
case WM_QUERYDROPOBJECT:
/*
* if the app has registered interest in drops, return TRUE
*/
return (LRESULT)(TestWF(pwnd, WEFACCEPTFILES) ? TRUE : FALSE);
case WM_DROPOBJECT:
return DO_DROPFILE;
case WM_ACCESS_WINDOW:
if (ValidateHwnd((HWND)wParam)) {
// SECURITY: set ACL for this window to no-access
return TRUE;
}
return FALSE;
case WM_NOTIFYFORMAT:
if(lParam == NF_QUERY)
return(TestWF(pwnd, WFANSICREATOR) ? NFR_ANSI : NFR_UNICODE);
break;
case WM_CHANGEUISTATE:
{
WORD wAction = LOWORD(wParam);
WORD wFlags = HIWORD(wParam);
BOOL bRealChange = FALSE;
/*
* Validate parameters and determine the flags that should actually be changed.
*/
if ((wFlags & ~UISF_VALID) || (wAction > UIS_LASTVALID) || lParam) {
return 0;
}
if (wAction == UIS_INITIALIZE) {
wFlags = 0;
if (TEST_KbdCuesPUSIF) {
if (TEST_SRVIF(SRVIF_LASTRITWASKEYBOARD)) {
wAction = UIS_CLEAR;
} else {
wAction = UIS_SET;
}
wFlags = UISF_HIDEFOCUS | UISF_HIDEACCEL;
wParam = MAKEWPARAM(wAction, wFlags);
}
} else if (!TEST_KbdCuesPUSIF) {
wFlags &= ~(UISF_HIDEFOCUS | UISF_HIDEACCEL);
}
if (wFlags == 0) {
return 0;
}
UserAssert(wAction == UIS_SET || wAction == UIS_CLEAR);
/*
* If the state is not going to change, there's nothing to do here
*/
if (wFlags & UISF_HIDEFOCUS) {
bRealChange = (!!TestWF(pwnd, WEFPUIFOCUSHIDDEN)) ^ (wAction == UIS_SET);
}
if (wFlags & UISF_HIDEACCEL) {
bRealChange |= (!!TestWF(pwnd, WEFPUIACCELHIDDEN)) ^ (wAction == UIS_SET);
}
if (wFlags & UISF_ACTIVE) {
bRealChange |= (!!TestWF(pwnd, WEFPUIACTIVE)) ^ (wAction == UIS_SET);
}
if (!bRealChange) {
break;
}
/*
* Children pass this message up
* Top level windows update their children's state and
* send down to their imediate children WM_UPDATEUISTATE.
*/
if (TestwndChild(pwnd)) {
ThreadLockAlways(pwnd->spwndParent, &tlpwndParent);
lt = xxxSendMessage(pwnd->spwndParent, WM_CHANGEUISTATE, wParam, lParam);
ThreadUnlock(&tlpwndParent);
return lt;
} else {
return xxxSendMessage(pwnd, WM_UPDATEUISTATE, wParam, lParam);
}
}
break;
case WM_QUERYUISTATE:
return (TestWF(pwnd, WEFPUIFOCUSHIDDEN) ? UISF_HIDEFOCUS : 0) |
(TestWF(pwnd, WEFPUIACCELHIDDEN) ? UISF_HIDEACCEL : 0) |
(TestWF(pwnd, WEFPUIACTIVE) ? UISF_ACTIVE : 0);
break;
case WM_UPDATEUISTATE:
{
WORD wAction = LOWORD(wParam);
WORD wFlags = HIWORD(wParam);
/*
* Validate parameters and determine the flags that should actually be changed.
*/
if ((wFlags & ~UISF_VALID) || (wAction > UIS_LASTVALID) || lParam) {
return 0;
}
if (wAction == UIS_INITIALIZE) {
wFlags = 0;
if (TEST_KbdCuesPUSIF) {
if (TEST_SRVIF(SRVIF_LASTRITWASKEYBOARD)) {
wAction = UIS_CLEAR;
} else {
wAction = UIS_SET;
}
wFlags = UISF_HIDEFOCUS | UISF_HIDEACCEL;
wParam = MAKEWPARAM(wAction, wFlags);
}
} else if (!TEST_KbdCuesPUSIF) {
wFlags &= ~(UISF_HIDEFOCUS | UISF_HIDEACCEL);
}
if (wFlags == 0) {
return 0;
}
switch (wAction) {
case UIS_INITIALIZE:
/*
* UISTATE: UIS_INITIALIZE sets the UIState bits for
* HIDEACCEL AND HIDEFOCUS based on the last input type.
*
* ACTIVE will not be changed.
*/
if (!TEST_SRVIF(SRVIF_LASTRITWASKEYBOARD)) {
SetWF(pwnd, WEFPUIFOCUSHIDDEN);
SetWF(pwnd, WEFPUIACCELHIDDEN);
wParam = MAKEWPARAM(UIS_SET, UISF_HIDEACCEL | UISF_HIDEFOCUS);
} else {
ClrWF(pwnd, WEFPUIFOCUSHIDDEN);
ClrWF(pwnd, WEFPUIACCELHIDDEN);
wParam = MAKEWPARAM(UIS_CLEAR, UISF_HIDEACCEL | UISF_HIDEFOCUS);
}
break;
case UIS_SET:
if (wFlags & UISF_HIDEACCEL) {
SetWF(pwnd, WEFPUIACCELHIDDEN);
}
if (wFlags & UISF_HIDEFOCUS) {
SetWF(pwnd, WEFPUIFOCUSHIDDEN);
}
if (wFlags & UISF_ACTIVE) {
SetWF(pwnd, WEFPUIACTIVE);
}
break;
case UIS_CLEAR:
if (wFlags & UISF_HIDEACCEL) {
ClrWF(pwnd, WEFPUIACCELHIDDEN);
}
if (wFlags & UISF_HIDEFOCUS) {
ClrWF(pwnd, WEFPUIFOCUSHIDDEN);
}
if (wFlags & UISF_ACTIVE) {
ClrWF(pwnd, WEFPUIACTIVE);
}
break;
default:
break;
}
/*
* Send it down to its immediate children if any
*/
if (pwnd->spwndChild) {
PBWL pbwl;
HWND *phwnd;
TL tlpwnd;
pbwl = BuildHwndList(pwnd->spwndChild, BWL_ENUMLIST, NULL);
if (pbwl == NULL)
return 0;
for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
/*
* Make sure this hwnd is still around.
*/
if ((pwnd = RevalidateHwnd(*phwnd)) == NULL)
continue;
ThreadLockAlways(pwnd, &tlpwnd);
xxxSendMessage(pwnd, message, wParam, lParam);
ThreadUnlock(&tlpwnd);
}
FreeHwndList(pbwl);
}
}
break;
#ifdef PENWIN20
// LATER mikeke
default:
// BOGUS
// 32-bit ize DefPenWindowProc
//
// call DefPenWindowProc if penwin is loaded
if ( (message >= WM_HANDHELDFIRST)
&& (message <= WM_HANDHELDLAST)
) {
if (lpfnHandHeld != NULL)
return (*lpfnHandHeld)(HW16(pwnd), message, wParamLo, lParam);
} else if ( (message >= WM_PENWINFIRST)
&& (message <= WM_PENWINLAST)
) {
if (SYSMET(PENWINDOWS))
return DefPenWindowProc(pwnd, message, wParamLo, lParam);
}
#endif // PENWIN20
}
return 0;
}