2 * PROJECT: ReactOS Win32k subsystem
3 * LICENSE: See COPYING in the top level directory
4 * PURPOSE: Miscellaneous User functions
5 * COPYRIGHT: 2008-2020 James Tabor <james.tabor@reactos.org>
11 DBG_DEFAULT_CHANNEL(UserDefwnd
);
13 INT WINAPI
DrawTextExWorker( HDC hdc
, LPWSTR str
, INT i_count
,
14 LPRECT rect
, UINT flags
, LPDRAWTEXTPARAMS dtp
);
16 INT WINAPI
DrawTextW( HDC hdc
, LPCWSTR str
, INT count
, LPRECT rect
, UINT flags
)
20 memset (&dtp
, 0, sizeof(dtp
));
21 dtp
.cbSize
= sizeof(dtp
);
22 if (flags
& DT_TABSTOP
)
24 dtp
.iTabLength
= (flags
>> 8) & 0xff;
27 return DrawTextExWorker(hdc
, (LPWSTR
)str
, count
, rect
, flags
, &dtp
);
32 DefWndControlColor(HDC hDC
, UINT ctlType
)
34 if (ctlType
== CTLCOLOR_SCROLLBAR
)
36 HBRUSH hb
= IntGetSysColorBrush(COLOR_SCROLLBAR
);
37 COLORREF bk
= IntGetSysColor(COLOR_3DHILIGHT
);
38 IntGdiSetTextColor(hDC
, IntGetSysColor(COLOR_3DFACE
));
39 IntGdiSetBkColor(hDC
, bk
);
41 /* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT
42 * we better use 0x55aa bitmap brush to make scrollbar's background
43 * look different from the window background.
45 if ( bk
== IntGetSysColor(COLOR_WINDOW
))
48 NtGdiUnrealizeObject( hb
);
52 IntGdiSetTextColor(hDC
, IntGetSysColor(COLOR_WINDOWTEXT
));
54 if ((ctlType
== CTLCOLOR_EDIT
) || (ctlType
== CTLCOLOR_LISTBOX
))
56 IntGdiSetBkColor(hDC
, IntGetSysColor(COLOR_WINDOW
));
60 IntGdiSetBkColor(hDC
, IntGetSysColor(COLOR_3DFACE
));
61 return IntGetSysColorBrush(COLOR_3DFACE
);
64 return IntGetSysColorBrush(COLOR_WINDOW
);
68 DefWndHandleWindowPosChanging(PWND pWnd
, WINDOWPOS
* Pos
)
70 POINT maxTrack
, minTrack
;
71 LONG style
= pWnd
->style
;
73 if (Pos
->flags
& SWP_NOSIZE
) return 0;
74 if ((style
& WS_THICKFRAME
) || ((style
& (WS_POPUP
| WS_CHILD
)) == 0))
76 co_WinPosGetMinMaxInfo(pWnd
, NULL
, NULL
, &minTrack
, &maxTrack
);
77 Pos
->cx
= min(Pos
->cx
, maxTrack
.x
);
78 Pos
->cy
= min(Pos
->cy
, maxTrack
.y
);
79 if (!(style
& WS_MINIMIZE
))
81 if (Pos
->cx
< minTrack
.x
) Pos
->cx
= minTrack
.x
;
82 if (Pos
->cy
< minTrack
.y
) Pos
->cy
= minTrack
.y
;
87 Pos
->cx
= max(Pos
->cx
, 0);
88 Pos
->cy
= max(Pos
->cy
, 0);
93 /* Win: xxxHandleWindowPosChanged */
95 DefWndHandleWindowPosChanged(PWND pWnd
, WINDOWPOS
* Pos
)
98 LONG style
= pWnd
->style
;
100 IntGetClientRect(pWnd
, &Rect
);
101 IntMapWindowPoints(pWnd
, (style
& WS_CHILD
? IntGetParent(pWnd
) : NULL
), (LPPOINT
) &Rect
, 2);
103 if (!(Pos
->flags
& SWP_NOCLIENTMOVE
))
105 co_IntSendMessage(UserHMGetHandle(pWnd
), WM_MOVE
, 0, MAKELONG(Rect
.left
, Rect
.top
));
108 if (!(Pos
->flags
& SWP_NOCLIENTSIZE
) || (Pos
->flags
& SWP_STATECHANGED
))
110 if (style
& WS_MINIMIZE
) co_IntSendMessage(UserHMGetHandle(pWnd
), WM_SIZE
, SIZE_MINIMIZED
, 0 );
113 WPARAM wp
= (style
& WS_MAXIMIZE
) ? SIZE_MAXIMIZED
: SIZE_RESTORED
;
114 co_IntSendMessage(UserHMGetHandle(pWnd
), WM_SIZE
, wp
, MAKELONG(Rect
.right
- Rect
.left
, Rect
.bottom
- Rect
.top
));
121 // Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
123 // Win: xxxSysCommand
125 DefWndHandleSysCommand(PWND pWnd
, WPARAM wParam
, LPARAM lParam
)
130 if (ISITHOOKED(WH_CBT
) || (pWnd
->head
.rpdesk
->pDeskInfo
->fsHooks
& HOOKID_TO_FLAG(WH_CBT
)))
133 lResult
= co_HOOK_CallHooks(WH_CBT
, HCBT_SYSCOMMAND
, wParam
, lParam
);
135 if (lResult
) return lResult
;
138 switch (wParam
& 0xfff0)
142 DefWndDoSizeMove(pWnd
, wParam
);
146 if (UserHMGetHandle(pWnd
) == UserGetActiveWindow())
147 IntShowOwnedPopups(pWnd
,FALSE
); // This is done in ShowWindow! Need to retest!
148 co_WinPosShowWindow( pWnd
, SW_MINIMIZE
);
152 if (((pWnd
->style
& WS_MINIMIZE
) != 0) && UserHMGetHandle(pWnd
) == UserGetActiveWindow())
153 IntShowOwnedPopups(pWnd
,TRUE
);
154 co_WinPosShowWindow( pWnd
, SW_MAXIMIZE
);
158 if (((pWnd
->style
& WS_MINIMIZE
) != 0) && UserHMGetHandle(pWnd
) == UserGetActiveWindow())
159 IntShowOwnedPopups(pWnd
,TRUE
);
160 co_WinPosShowWindow( pWnd
, SW_RESTORE
);
164 return co_IntSendMessage(UserHMGetHandle(pWnd
), WM_CLOSE
, 0, 0);
167 ERR("Screensaver Called!\n");
168 UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_START_SCREENSAVE
, 0); // always lParam 0 == not Secure
173 USER_REFERENCE_ENTRY Ref
;
175 pWnd
= ValidateHwndNoErr((HWND
)lParam
);
178 if (pWnd
->spwndLastActive
)
180 pWnd
= pWnd
->spwndLastActive
;
182 UserRefObjectCo(pWnd
, &Ref
);
183 co_IntSetForegroundWindow(pWnd
);
184 UserDerefObjectCo(pWnd
);
185 if (pWnd
->style
& WS_MINIMIZE
)
187 UserPostMessage(UserHMGetHandle(pWnd
), WM_SYSCOMMAND
, SC_RESTORE
, 0);
196 Pt
.x
= (short)LOWORD(lParam
);
197 Pt
.y
= (short)HIWORD(lParam
);
198 MENU_TrackMouseMenuBar(pWnd
, wParam
& 0x000f, Pt
);
203 MENU_TrackKbdMenuBar(pWnd
, wParam
, (WCHAR
)lParam
);
208 // We do not support anything else here so we should return normal even when sending a hook.
212 return(Hook
? 1 : 0); // Don't call us again from user space.
216 co_IntFindChildWindowToOwner(PWND Root
, PWND Owner
)
219 PWND Child
, OwnerWnd
;
221 for(Child
= Root
->spwndChild
; Child
; Child
= Child
->spwndNext
)
223 OwnerWnd
= Child
->spwndOwner
;
227 if (!(Child
->style
& WS_POPUP
) ||
228 !(Child
->style
& WS_VISIBLE
) ||
229 /* Fixes CMD pop up properties window from having foreground. */
230 Owner
->head
.pti
->MessageQueue
!= Child
->head
.pti
->MessageQueue
)
233 if(OwnerWnd
== Owner
)
243 DefWndHandleSetCursor(PWND pWnd
, WPARAM wParam
, LPARAM lParam
)
245 PWND pwndPopUP
= NULL
;
246 WORD Msg
= HIWORD(lParam
);
248 /* Not for child windows. */
249 if (UserHMGetHandle(pWnd
) != (HWND
)wParam
)
254 switch((short)LOWORD(lParam
))
258 //// This is the real fix for CORE-6129! This was a "Code hole".
259 USER_REFERENCE_ENTRY Ref
;
261 if (Msg
== WM_LBUTTONDOWN
)
263 // Find a pop up window to bring active.
264 pwndPopUP
= co_IntFindChildWindowToOwner(UserGetDesktopWindow(), pWnd
);
267 // Not a child pop up from desktop.
268 if ( pwndPopUP
!= UserGetDesktopWindow()->spwndChild
)
270 // Get original active window.
271 PWND pwndOrigActive
= gpqForeground
->spwndActive
;
273 co_WinPosSetWindowPos(pWnd
, NULL
, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
275 UserRefObjectCo(pwndPopUP
, &Ref
);
276 //UserSetActiveWindow(pwndPopUP);
277 co_IntSetForegroundWindow(pwndPopUP
); // HACK
278 UserDerefObjectCo(pwndPopUP
);
280 // If the change was made, break out.
281 if (pwndOrigActive
!= gpqForeground
->spwndActive
)
287 if (Msg
== WM_LBUTTONDOWN
|| Msg
== WM_MBUTTONDOWN
||
288 Msg
== WM_RBUTTONDOWN
|| Msg
== WM_XBUTTONDOWN
)
294 UserHMGetHandle(pwndPopUP
),
296 gspv
.dwForegroundFlashCount
,
297 (gpsi
->dtCaretBlink
>> 3)};
299 // Now shake that window!
300 IntFlashWindowEx(pwndPopUP
, &fwi
);
302 UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0);
309 if (pWnd
->pcls
->spcur
)
311 IntSystemSetCursor(pWnd
->pcls
->spcur
);
319 if (pWnd
->style
& WS_MAXIMIZE
)
323 IntSystemSetCursor(SYSTEMCUR(SIZEWE
));
330 if (pWnd
->style
& WS_MAXIMIZE
)
334 IntSystemSetCursor(SYSTEMCUR(SIZENS
));
341 if (pWnd
->style
& WS_MAXIMIZE
)
345 IntSystemSetCursor(SYSTEMCUR(SIZENWSE
));
352 if (pWnd
->style
& WS_MAXIMIZE
)
356 IntSystemSetCursor(SYSTEMCUR(SIZENESW
));
360 IntSystemSetCursor(SYSTEMCUR(ARROW
));
364 /* Win: xxxDWPPrint */
365 VOID FASTCALL
DefWndPrint( PWND pwnd
, HDC hdc
, ULONG uFlags
)
370 if ( (uFlags
& PRF_CHECKVISIBLE
) &&
371 !IntIsWindowVisible(pwnd
) )
375 * Unimplemented flags.
377 if ( (uFlags
& PRF_CHILDREN
) ||
378 (uFlags
& PRF_OWNED
) ||
379 (uFlags
& PRF_NONCLIENT
) )
381 FIXME("WM_PRINT message with unsupported flags\n");
387 if ( uFlags
& PRF_ERASEBKGND
)
388 co_IntSendMessage(UserHMGetHandle(pwnd
), WM_ERASEBKGND
, (WPARAM
)hdc
, 0);
393 if ( uFlags
& PRF_CLIENT
)
394 co_IntSendMessage(UserHMGetHandle(pwnd
), WM_PRINTCLIENT
, (WPARAM
)hdc
, uFlags
);
398 UserPaintCaption(PWND pWnd
, INT Flags
)
402 if ( (pWnd
->style
& WS_VISIBLE
) && ((pWnd
->style
& WS_CAPTION
) == WS_CAPTION
) )
404 if (pWnd
->state
& WNDS_HASCAPTION
&& pWnd
->head
.pti
->MessageQueue
== gpqForeground
)
407 * When themes are not enabled we can go on and paint the non client area.
408 * However if we do that with themes enabled we will draw a classic frame.
409 * This is solved by sending a themes specific message to notify the themes
410 * engine that the caption needs to be redrawn.
412 if (gpsi
->dwSRVIFlags
& SRVINFO_APIHOOK
)
415 * This will cause uxtheme to either paint the themed caption or call
416 * RealUserDrawCaption in order to draw the classic caption when themes
417 * are disabled but the themes service is enabled.
419 TRACE("UDCB Flags %08x\n", Flags
);
420 co_IntSendMessage(UserHMGetHandle(pWnd
), WM_NCUAHDRAWCAPTION
, Flags
, 0);
424 HDC hDC
= UserGetDCEx(pWnd
, NULL
, DCX_WINDOW
|DCX_USESTYLE
);
425 UserDrawCaptionBar(pWnd
, hDC
, Flags
| DC_FRAME
); // DCFRAME added as fix for CORE-10855.
426 UserReleaseDC(pWnd
, hDC
, FALSE
);
430 // Support window tray
435 /* Win: xxxDWP_SetIcon */
437 DefWndSetIcon(PWND pWnd
, WPARAM wParam
, LPARAM lParam
)
439 HICON hIcon
, hIconSmall
, hIconOld
;
441 if ( wParam
> ICON_SMALL2
)
443 EngSetLastError(ERROR_INVALID_PARAMETER
);
446 hIconSmall
= UserGetProp(pWnd
, gpsi
->atomIconSmProp
, TRUE
);
447 hIcon
= UserGetProp(pWnd
, gpsi
->atomIconProp
, TRUE
);
449 hIconOld
= wParam
== ICON_BIG
? hIcon
: hIconSmall
;
454 hIcon
= (HICON
)lParam
;
457 hIconSmall
= (HICON
)lParam
;
460 ERR("FIXME: Set ICON_SMALL2 support!\n");
465 UserSetProp(pWnd
, gpsi
->atomIconProp
, hIcon
, TRUE
);
466 UserSetProp(pWnd
, gpsi
->atomIconSmProp
, hIconSmall
, TRUE
);
468 if ((pWnd
->style
& WS_CAPTION
) == WS_CAPTION
)
469 UserPaintCaption(pWnd
, DC_ICON
);
471 return (LRESULT
)hIconOld
;
474 /* Win: DWP_GetIcon */
476 DefWndGetIcon(PWND pWnd
, WPARAM wParam
, LPARAM lParam
)
479 if ( wParam
> ICON_SMALL2
)
481 EngSetLastError(ERROR_INVALID_PARAMETER
);
487 hIconRet
= UserGetProp(pWnd
, gpsi
->atomIconProp
, TRUE
);
491 hIconRet
= UserGetProp(pWnd
, gpsi
->atomIconSmProp
, TRUE
);
495 return (LRESULT
)hIconRet
;
499 DefWndScreenshot(PWND pWnd
)
507 SETCLIPBDATA scd
= {FALSE
, FALSE
};
509 UserOpenClipboard(UserHMGetHandle(pWnd
));
510 UserEmptyClipboard();
512 hdc
= UserGetWindowDC(pWnd
);
513 IntGetWindowRect(pWnd
, &rect
);
514 w
= rect
.right
- rect
.left
;
515 h
= rect
.bottom
- rect
.top
;
517 hbitmap
= NtGdiCreateCompatibleBitmap(hdc
, w
, h
);
518 hdc2
= NtGdiCreateCompatibleDC(hdc
);
519 NtGdiSelectBitmap(hdc2
, hbitmap
);
521 NtGdiBitBlt(hdc2
, 0, 0, w
, h
, hdc
, 0, 0, SRCCOPY
, 0, 0);
523 UserSetClipboardData(CF_BITMAP
, hbitmap
, &scd
);
525 UserReleaseDC(pWnd
, hdc
, FALSE
);
526 UserReleaseDC(pWnd
, hdc2
, FALSE
);
528 UserCloseClipboard();
532 Win32k counterpart of User DefWindowProc
542 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
544 USER_REFERENCE_ENTRY Ref
;
546 if (Msg
> WM_USER
) return 0;
550 case WM_DEVICECHANGE
:
553 case WM_GETTEXTLENGTH
:
558 if (Wnd
!= NULL
&& Wnd
->strName
.Length
!= 0)
560 buf
= Wnd
->strName
.Buffer
;
562 NT_SUCCESS(RtlUnicodeToMultiByteSize(&len
,
564 Wnd
->strName
.Length
)))
566 lResult
= (LRESULT
) (Wnd
->strName
.Length
/ sizeof(WCHAR
));
574 case WM_GETTEXT
: // FIXME: Handle Ansi
577 PWSTR outbuf
= (PWSTR
)lParam
;
579 if (Wnd
!= NULL
&& wParam
!= 0)
581 if (Wnd
->strName
.Buffer
!= NULL
)
582 buf
= Wnd
->strName
.Buffer
;
588 if (Wnd
->strName
.Length
!= 0)
590 lResult
= min(Wnd
->strName
.Length
/ sizeof(WCHAR
), wParam
- 1);
591 RtlCopyMemory(outbuf
,
593 lResult
* sizeof(WCHAR
));
594 outbuf
[lResult
] = L
'\0';
603 case WM_SETTEXT
: // FIXME: Handle Ansi
605 DefSetText(Wnd
, (PCWSTR
)lParam
);
607 if ((Wnd
->style
& WS_CAPTION
) == WS_CAPTION
)
608 UserPaintCaption(Wnd
, DC_TEXT
);
609 IntNotifyWinEvent(EVENT_OBJECT_NAMECHANGE
, Wnd
, OBJID_WINDOW
, CHILDID_SELF
, 0);
616 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", UserHMGetHandle(Wnd
), wParam
, lParam
);
617 lResult
= DefWndHandleSysCommand(Wnd
, wParam
, lParam
);
623 if ((Wnd
->style
& WS_VISIBLE
) && wParam
) break;
624 if (!(Wnd
->style
& WS_VISIBLE
) && !wParam
) break;
625 if (!Wnd
->spwndOwner
) break;
628 co_WinPosShowWindow(Wnd
, wParam
? SW_SHOWNOACTIVATE
: SW_HIDE
);
633 case WM_CLIENTSHUTDOWN
:
634 return IntClientShutdown(Wnd
, wParam
, lParam
);
637 if ( (Wnd
->style
& (WS_POPUP
|WS_CHILD
)) != WS_CHILD
&&
638 Wnd
!= co_GetDesktopWindow(Wnd
) )
640 if (!co_HOOK_CallHooks(WH_SHELL
, HSHELL_APPCOMMAND
, wParam
, lParam
))
641 co_IntShellHookNotify(HSHELL_APPCOMMAND
, wParam
, lParam
);
644 UserRefObjectCo(Wnd
->spwndParent
, &Ref
);
645 lResult
= co_IntSendMessage(UserHMGetHandle(Wnd
->spwndParent
), WM_APPCOMMAND
, wParam
, lParam
);
646 UserDerefObjectCo(Wnd
->spwndParent
);
652 HMENU hMenu
= UlongToHandle(Wnd
->IDMenu
);
653 PWND pwndActive
= MENU_IsMenuActive();
654 hi
.cbSize
= sizeof(HELPINFO
);
655 hi
.MousePos
= gpsi
->ptCursor
;
656 hi
.iContextType
= HELPINFO_MENUITEM
;
657 hi
.hItemHandle
= pwndActive
? UserHMGetHandle(pwndActive
) : UserHMGetHandle(Wnd
);
658 hi
.iCtrlId
= (Wnd
->style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
? IntMenuItemFromPoint(Wnd
, hMenu
, hi
.MousePos
) : 0;
659 hi
.dwContextId
= IntGetWindowContextHelpId(Wnd
);
661 co_IntSendMessage( UserHMGetHandle(Wnd
), WM_HELP
, 0, (LPARAM
)&hi
);
667 return DefWndSetIcon(Wnd
, wParam
, lParam
);
672 return DefWndGetIcon(Wnd
, wParam
, lParam
);
677 PWND Parent
= IntGetParent(Wnd
);
678 co_IntSendMessage(UserHMGetHandle(Parent
), Msg
, wParam
, lParam
);
685 pti
->MessageQueue
->QF_flags
&= ~(QF_FMENUSTATUS
|QF_FMENUSTATUSBREAK
);
688 case WM_NCLBUTTONDOWN
:
689 return NC_HandleNCLButtonDown(Wnd
, wParam
, lParam
);
691 case WM_NCRBUTTONDOWN
:
692 return NC_HandleNCRButtonDown(Wnd
, wParam
, lParam
);
694 case WM_LBUTTONDBLCLK
:
695 return NC_HandleNCLButtonDblClk(Wnd
, HTCLIENT
, lParam
);
697 case WM_NCLBUTTONDBLCLK
:
698 return NC_HandleNCLButtonDblClk(Wnd
, wParam
, lParam
);
704 Pt
.x
= GET_X_LPARAM(lParam
);
705 Pt
.y
= GET_Y_LPARAM(lParam
);
706 IntClientToScreen(Wnd
, &Pt
);
707 lParam
= MAKELPARAM(Pt
.x
, Pt
.y
);
708 co_IntSendMessage(UserHMGetHandle(Wnd
), WM_CONTEXTMENU
, (WPARAM
)UserHMGetHandle(Wnd
), lParam
);
714 * FIXME : we must NOT send WM_CONTEXTMENU on a WM_NCRBUTTONUP (checked
715 * in Windows), but what _should_ we do? According to MSDN :
716 * "If it is appropriate to do so, the system sends the WM_SYSCOMMAND
717 * message to the window". When is it appropriate?
719 ERR("WM_NCRBUTTONUP\n");
724 if (HIWORD(wParam
) == XBUTTON1
|| HIWORD(wParam
) == XBUTTON2
)
726 co_IntSendMessage(UserHMGetHandle(Wnd
), WM_APPCOMMAND
, (WPARAM
)UserHMGetHandle(Wnd
),
727 MAKELPARAM(LOWORD(wParam
), FAPPCOMMAND_MOUSE
| HIWORD(wParam
)));
734 if (Wnd
->style
& WS_CHILD
)
736 co_IntSendMessage(UserHMGetHandle(IntGetParent(Wnd
)), Msg
, (WPARAM
)UserHMGetHandle(Wnd
), lParam
);
746 Pt
.x
= GET_X_LPARAM(lParam
);
747 Pt
.y
= GET_Y_LPARAM(lParam
);
748 if (Style
& WS_CHILD
)
750 IntScreenToClient(IntGetParent(Wnd
), &Pt
);
753 HitCode
= GetNCHitEx(Wnd
, Pt
);
755 if (HitCode
== HTCAPTION
|| HitCode
== HTSYSMENU
)
760 if((SystemMenu
= IntGetSystemMenu(Wnd
, FALSE
)))
762 MENU_InitSysMenuPopup(SystemMenu
, Wnd
->style
, Wnd
->pcls
->style
, HitCode
);
764 if(HitCode
== HTCAPTION
)
765 Flags
= TPM_LEFTBUTTON
| TPM_RIGHTBUTTON
;
767 Flags
= TPM_LEFTBUTTON
;
769 IntTrackPopupMenuEx(SystemMenu
, Flags
|TPM_SYSTEM_MENU
, Pt
.x
, Pt
.y
, Wnd
, NULL
);
772 if (HitCode
== HTHSCROLL
|| HitCode
== HTVSCROLL
)
774 WARN("Scroll Menu Not Supported\n");
781 if (wParam
== VK_F10
)
783 pti
->MessageQueue
->QF_flags
|= QF_FF10STATUS
;
785 if (UserGetKeyState(VK_SHIFT
) & 0x8000)
787 co_IntSendMessage(UserHMGetHandle(Wnd
), WM_CONTEXTMENU
, (WPARAM
)UserHMGetHandle(Wnd
), MAKELPARAM(-1, -1));
790 if (g_bWindowSnapEnabled
&& (IS_KEY_DOWN(gafAsyncKeyState
, VK_LWIN
) || IS_KEY_DOWN(gafAsyncKeyState
, VK_RWIN
)))
795 HWND hwndTop
= UserGetForegroundWindow();
796 PWND topWnd
= UserGetWindowObject(hwndTop
);
798 // MS Doc: foreground window can be NULL, e.g. when window is losing activation
802 // We want to forbid snapping operations on the TaskBar
803 // We use a heuristic for detecting the TaskBar Wnd by its typical Style & ExStyle Values
804 ExStyleTB
= (topWnd
->ExStyle
& WS_EX_TOOLWINDOW
);
805 StyleTB
= (topWnd
->style
& (WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
));
806 IsTaskBar
= (StyleTB
== (WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
))
807 && (ExStyleTB
== WS_EX_TOOLWINDOW
);
808 TRACE("ExStyle=%x Style=%x IsTaskBar=%d\n", ExStyleTB
, StyleTB
, IsTaskBar
);
812 if ((topWnd
->style
& WS_THICKFRAME
) == 0)
815 if (wParam
== VK_DOWN
)
817 if (topWnd
->style
& WS_MAXIMIZE
)
819 co_IntSendMessage(hwndTop
, WM_SYSCOMMAND
, SC_RESTORE
, lParam
);
821 /* "Normal size" must be erased after restoring, otherwise it will block next side snap actions */
822 RECTL_vSetEmptyRect(&topWnd
->InternalPos
.NormalRect
);
826 co_IntSendMessage(hwndTop
, WM_SYSCOMMAND
, SC_MINIMIZE
, lParam
);
829 else if (wParam
== VK_UP
)
832 if ((topWnd
->InternalPos
.NormalRect
.right
== topWnd
->InternalPos
.NormalRect
.left
) ||
833 (topWnd
->InternalPos
.NormalRect
.top
== topWnd
->InternalPos
.NormalRect
.bottom
))
835 currentRect
= topWnd
->rcWindow
;
839 currentRect
= topWnd
->InternalPos
.NormalRect
;
841 co_IntSendMessage(hwndTop
, WM_SYSCOMMAND
, SC_MAXIMIZE
, 0);
843 // save normal rect if maximazing snapped window
844 topWnd
->InternalPos
.NormalRect
= currentRect
;
846 else if (wParam
== VK_LEFT
|| wParam
== VK_RIGHT
)
848 RECT snapRect
, normalRect
, windowRect
;
850 normalRect
= topWnd
->InternalPos
.NormalRect
;
851 snapped
= (normalRect
.left
!= 0 && normalRect
.right
!= 0 &&
852 normalRect
.top
!= 0 && normalRect
.bottom
!= 0);
854 if (topWnd
->style
& WS_MAXIMIZE
)
856 co_IntSendMessage(hwndTop
, WM_SYSCOMMAND
, SC_RESTORE
, lParam
);
859 windowRect
= topWnd
->rcWindow
;
861 UserSystemParametersInfo(SPI_GETWORKAREA
, 0, &snapRect
, 0);
862 if (wParam
== VK_LEFT
)
864 snapRect
.right
= (snapRect
.left
+ snapRect
.right
) / 2;
868 snapRect
.left
= (snapRect
.left
+ snapRect
.right
) / 2;
873 // if window was snapped but moved to other location - restore normal size
874 if (!IntEqualRect(&snapRect
, &windowRect
))
876 RECT empty
= {0, 0, 0, 0};
877 co_WinPosSetWindowPos(topWnd
,
881 normalRect
.right
- normalRect
.left
,
882 normalRect
.bottom
- normalRect
.top
,
884 topWnd
->InternalPos
.NormalRect
= empty
;
889 co_WinPosSetWindowPos(topWnd
,
893 snapRect
.right
- snapRect
.left
,
894 snapRect
.bottom
- snapRect
.top
,
896 topWnd
->InternalPos
.NormalRect
= windowRect
;
905 if (HIWORD(lParam
) & KF_ALTDOWN
)
906 { /* Previous state, if the key was down before this message,
907 this is a cheap way to ignore autorepeat keys. */
908 if ( !(HIWORD(lParam
) & KF_REPEAT
) )
910 if ( ( wParam
== VK_MENU
||
911 wParam
== VK_LMENU
||
912 wParam
== VK_RMENU
) && !(pti
->MessageQueue
->QF_flags
& QF_FMENUSTATUS
)) //iMenuSysKey )
913 pti
->MessageQueue
->QF_flags
|= QF_FMENUSTATUS
; //iMenuSysKey = 1;
915 pti
->MessageQueue
->QF_flags
&= ~QF_FMENUSTATUS
; //iMenuSysKey = 0;
918 pti
->MessageQueue
->QF_flags
&= ~QF_FF10STATUS
; //iF10Key = 0;
920 if (wParam
== VK_F4
) /* Try to close the window */
922 PWND top
= UserGetAncestor(Wnd
, GA_ROOT
);
923 if (!(top
->style
& CS_NOCLOSE
))
924 UserPostMessage(UserHMGetHandle(top
), WM_SYSCOMMAND
, SC_CLOSE
, 0);
926 else if (wParam
== VK_SNAPSHOT
) // Alt-VK_SNAPSHOT?
929 while (IntGetParent(pwnd
) != NULL
)
931 pwnd
= IntGetParent(pwnd
);
933 ERR("DefWndScreenshot\n");
934 DefWndScreenshot(pwnd
);
936 else if ( wParam
== VK_ESCAPE
|| wParam
== VK_TAB
) // Alt-Tab/ESC Alt-Shift-Tab/ESC
939 HWND Active
= UserGetActiveWindow(); // Noticed MDI problem.
942 FIXME("WM_SYSKEYDOWN VK_ESCAPE no active\n");
945 wParamTmp
= UserGetKeyState(VK_SHIFT
) & 0x8000 ? SC_PREVWINDOW
: SC_NEXTWINDOW
;
946 co_IntSendMessage( Active
, WM_SYSCOMMAND
, wParamTmp
, wParam
);
949 else if( wParam
== VK_F10
)
951 if (UserGetKeyState(VK_SHIFT
) & 0x8000)
952 co_IntSendMessage( UserHMGetHandle(Wnd
), WM_CONTEXTMENU
, (WPARAM
)UserHMGetHandle(Wnd
), MAKELPARAM(-1, -1) );
953 pti
->MessageQueue
->QF_flags
|= QF_FF10STATUS
; //iF10Key = 1;
955 else if( wParam
== VK_ESCAPE
&& (UserGetKeyState(VK_SHIFT
) & 0x8000))
956 co_IntSendMessage( UserHMGetHandle(Wnd
), WM_SYSCOMMAND
, SC_KEYMENU
, ' ' );
963 /* Press and release F10 or ALT */
964 if (((wParam
== VK_MENU
|| wParam
== VK_LMENU
|| wParam
== VK_RMENU
)
965 && (pti
->MessageQueue
->QF_flags
& (QF_FMENUSTATUS
|QF_FMENUSTATUSBREAK
)) == QF_FMENUSTATUS
/*iMenuSysKey*/) ||
966 ((wParam
== VK_F10
) && pti
->MessageQueue
->QF_flags
& QF_FF10STATUS
/*iF10Key*/))
967 co_IntSendMessage( UserHMGetHandle(UserGetAncestor( Wnd
, GA_ROOT
)), WM_SYSCOMMAND
, SC_KEYMENU
, 0L );
968 pti
->MessageQueue
->QF_flags
&= ~(QF_FMENUSTATUS
|QF_FMENUSTATUSBREAK
|QF_FF10STATUS
); //iMenuSysKey = iF10Key = 0;
974 pti
->MessageQueue
->QF_flags
&= ~(QF_FMENUSTATUS
|QF_FMENUSTATUSBREAK
); //iMenuSysKey = 0;
975 if (wParam
== VK_RETURN
&& (Wnd
->style
& WS_MINIMIZE
) != 0)
977 UserPostMessage( UserHMGetHandle(Wnd
), WM_SYSCOMMAND
, SC_RESTORE
, 0L );
980 if ((HIWORD(lParam
) & KF_ALTDOWN
) && wParam
)
982 if (wParam
== VK_TAB
|| wParam
== VK_ESCAPE
) break;
983 if (wParam
== VK_SPACE
&& Wnd
->style
& WS_CHILD
)
984 co_IntSendMessage( UserHMGetHandle(IntGetParent(Wnd
)), Msg
, wParam
, lParam
);
986 co_IntSendMessage( UserHMGetHandle(Wnd
), WM_SYSCOMMAND
, SC_KEYMENU
, wParam
);
988 else /* check for Ctrl-Esc */
989 if (wParam
!= VK_ESCAPE
) UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_MESSAGE_BEEP
, 0); //MessageBeep(0);
995 pti
->MessageQueue
->QF_flags
&= ~(QF_FMENUSTATUS
|QF_FMENUSTATUSBREAK
);
998 if (IntGetCaptureWindow() == UserHMGetHandle(Wnd
))
1000 IntReleaseCapture();
1006 co_UserDestroyWindow(Wnd
);
1009 case WM_CTLCOLORMSGBOX
:
1010 case WM_CTLCOLOREDIT
:
1011 case WM_CTLCOLORLISTBOX
:
1012 case WM_CTLCOLORBTN
:
1013 case WM_CTLCOLORDLG
:
1014 case WM_CTLCOLORSTATIC
:
1015 case WM_CTLCOLORSCROLLBAR
:
1016 return (LRESULT
) DefWndControlColor((HDC
)wParam
, Msg
- WM_CTLCOLORMSGBOX
);
1019 return (LRESULT
) DefWndControlColor((HDC
)wParam
, HIWORD(lParam
));
1023 if (Wnd
->style
& WS_CHILD
)
1025 /* with the exception of the border around a resizable wnd,
1026 * give the parent first chance to set the cursor */
1027 if (LOWORD(lParam
) < HTLEFT
|| LOWORD(lParam
) > HTBOTTOMRIGHT
)
1029 PWND parent
= Wnd
->spwndParent
;//IntGetParent( Wnd );
1030 if (parent
!= UserGetDesktopWindow() &&
1031 co_IntSendMessage( UserHMGetHandle(parent
), WM_SETCURSOR
, wParam
, lParam
))
1035 return DefWndHandleSetCursor(Wnd
, wParam
, lParam
);
1038 case WM_MOUSEACTIVATE
:
1039 if (Wnd
->style
& WS_CHILD
)
1043 PWND pwndParent
= IntGetParent(Wnd
);
1044 hwndParent
= pwndParent
? UserHMGetHandle(pwndParent
) : NULL
;
1045 if (hwndParent
) Ret
= co_IntSendMessage(hwndParent
, WM_MOUSEACTIVATE
, wParam
, lParam
);
1046 if (Ret
) return (Ret
);
1048 return ( (HIWORD(lParam
) == WM_LBUTTONDOWN
&& LOWORD(lParam
) == HTCAPTION
) ? MA_NOACTIVATE
: MA_ACTIVATE
);
1051 /* The default action in Windows is to set the keyboard focus to
1052 * the window, if it's being activated and not minimized */
1053 if (LOWORD(wParam
) != WA_INACTIVE
&&
1054 !(Wnd
->style
& WS_MINIMIZE
))
1056 //ERR("WM_ACTIVATE %p\n",hWnd);
1057 co_UserSetFocus(Wnd
);
1062 if (Wnd
->style
& WS_CHILD
)
1065 PWND pwndParent
= IntGetParent(Wnd
);
1066 hwndParent
= pwndParent
? UserHMGetHandle(pwndParent
) : NULL
;
1067 return co_IntSendMessage( hwndParent
, WM_MOUSEWHEEL
, wParam
, lParam
);
1072 case WM_ICONERASEBKGND
:
1075 HBRUSH hBrush
= Wnd
->pcls
->hbrBackground
;
1076 if (!hBrush
) return 0;
1077 if (hBrush
<= (HBRUSH
)COLOR_MENUBAR
)
1079 hBrush
= IntGetSysColorBrush(HandleToUlong(hBrush
));
1081 if (Wnd
->pcls
->style
& CS_PARENTDC
)
1083 /* can't use GetClipBox with a parent DC or we fill the whole parent */
1084 IntGetClientRect(Wnd
, &Rect
);
1085 GreDPtoLP((HDC
)wParam
, (LPPOINT
)&Rect
, 2);
1089 GdiGetClipBox((HDC
)wParam
, &Rect
);
1091 FillRect((HDC
)wParam
, &Rect
, hBrush
);
1096 //ERR("WM_GETHOTKEY\n");
1097 return DefWndGetHotKey(Wnd
);
1099 //ERR("WM_SETHOTKEY\n");
1100 return DefWndSetHotKey(Wnd
, wParam
);
1105 Point
.x
= GET_X_LPARAM(lParam
);
1106 Point
.y
= GET_Y_LPARAM(lParam
);
1107 return GetNCHitEx(Wnd
, Point
);
1112 DefWndPrint(Wnd
, (HDC
)wParam
, lParam
);
1116 case WM_SYSCOLORCHANGE
:
1118 /* force to redraw non-client area */
1119 UserPaintCaption(Wnd
, DC_NC
);
1120 /* Use InvalidateRect to redraw client area, enable
1121 * erase to redraw all subcontrols otherwise send the
1122 * WM_SYSCOLORCHANGE to child windows/controls is required
1124 co_UserRedrawWindow( Wnd
, NULL
, NULL
, RDW_ALLCHILDREN
|RDW_INVALIDATE
|RDW_ERASE
);
1134 /* If already in Paint and Client area is not empty just return. */
1135 if (Wnd
->state2
& WNDS2_STARTPAINT
&& !RECTL_bIsEmptyRect(&Wnd
->rcClient
))
1137 ERR("In Paint and Client area is not empty!\n");
1141 hDC
= IntBeginPaint(Wnd
, &Ps
);
1144 if (((Wnd
->style
& WS_MINIMIZE
) != 0) && (Wnd
->pcls
->spicn
))
1149 ERR("Doing Paint and Client area is empty!\n");
1150 IntGetClientRect(Wnd
, &ClientRect
);
1151 x
= (ClientRect
.right
- ClientRect
.left
- UserGetSystemMetrics(SM_CXICON
)) / 2;
1152 y
= (ClientRect
.bottom
- ClientRect
.top
- UserGetSystemMetrics(SM_CYICON
)) / 2;
1153 UserReferenceObject(Wnd
->pcls
->spicn
);
1154 UserDrawIconEx(hDC
, x
, y
, Wnd
->pcls
->spicn
, 0, 0, 0, 0, DI_NORMAL
| DI_COMPAT
| DI_DEFAULTSIZE
);
1155 UserDereferenceObject(Wnd
->pcls
->spicn
);
1158 IntEndPaint(Wnd
, &Ps
);
1166 Wnd
->state
&= ~WNDS_SYNCPAINTPENDING
;
1167 TRACE("WM_SYNCPAINT\n");
1168 hRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
1171 if (co_UserGetUpdateRgn(Wnd
, hRgn
, FALSE
) != NULLREGION
)
1173 PREGION pRgn
= REGION_LockRgn(hRgn
);
1174 if (pRgn
) REGION_UnlockRgn(pRgn
);
1176 wParam
= (RDW_ERASENOW
| RDW_ERASE
| RDW_FRAME
| RDW_ALLCHILDREN
);
1177 co_UserRedrawWindow(Wnd
, NULL
, pRgn
, wParam
);
1179 GreDeleteObject(hRgn
);
1187 if (!(Wnd
->style
& WS_VISIBLE
))
1189 IntSetStyle( Wnd
, WS_VISIBLE
, 0 );
1190 Wnd
->state
|= WNDS_SENDNCPAINT
;
1195 if (Wnd
->style
& WS_VISIBLE
)
1197 co_UserRedrawWindow( Wnd
, NULL
, NULL
, RDW_ALLCHILDREN
| RDW_VALIDATE
);
1198 IntSetStyle( Wnd
, 0, WS_VISIBLE
);
1203 case WM_WINDOWPOSCHANGING
:
1205 return (DefWndHandleWindowPosChanging(Wnd
, (WINDOWPOS
*)lParam
));
1208 case WM_WINDOWPOSCHANGED
:
1210 return (DefWndHandleWindowPosChanged(Wnd
, (WINDOWPOS
*)lParam
));
1215 return NC_HandleNCCalcSize( Wnd
, wParam
, (RECTL
*)lParam
, FALSE
);
1220 return NC_HandleNCActivate( Wnd
, wParam
, lParam
);
1228 HDC hDC
= UserGetDCEx(Wnd
, (HRGN
)wParam
, DCX_WINDOW
| DCX_INTERSECTRGN
| DCX_USESTYLE
| DCX_KEEPCLIPRGN
);
1229 Wnd
->state
|= WNDS_FORCEMENUDRAW
;
1230 NC_DoNCPaint(Wnd
, hDC
, -1);
1231 Wnd
->state
&= ~WNDS_FORCEMENUDRAW
;
1232 UserReleaseDC(Wnd
, hDC
, FALSE
);
1236 // Draw Caption mode.
1238 // wParam are DC_* flags.
1240 case WM_NCUAHDRAWCAPTION
:
1242 HDC hDC
= UserGetDCEx(Wnd
, NULL
, DCX_WINDOW
|DCX_USESTYLE
);
1243 TRACE("WM_NCUAHDRAWCAPTION: wParam DC_ flags %08x\n",wParam
);
1244 UserDrawCaptionBar(Wnd
, hDC
, wParam
| DC_FRAME
); // Include DC_FRAME to comp for drawing glitch.
1245 UserReleaseDC(Wnd
, hDC
, FALSE
);
1251 // wParam is HDC, lParam are DC_ACTIVE and or DC_REDRAWHUNGWND.
1253 case WM_NCUAHDRAWFRAME
:
1255 TRACE("WM_NCUAHDRAWFRAME: wParam hDC %p lParam DC_ flags %08x\n",wParam
,lParam
);
1256 NC_DoNCPaint(Wnd
, (HDC
)wParam
, lParam
|DC_NC
);
1273 ProbeForRead((PVOID
)lParam
,
1281 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1288 lResult
= co_HOOK_CallHooks(WH_CBT
, HCBT_MOVESIZE
, (WPARAM
)UserHMGetHandle(Wnd
), lParam
? (LPARAM
)&rt
: 0);