/****************************** 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; }