mirror of
https://github.com/reactos/reactos.git
synced 2024-09-06 19:02:32 +00:00
517 lines
16 KiB
C
517 lines
16 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Win32k subsystem
|
|
* PURPOSE: Miscellaneous User functions
|
|
* FILE: subsystems/win32/win32k/ntuser/defwnd.c
|
|
* PROGRAMER:
|
|
*/
|
|
|
|
#include <win32k.h>
|
|
DBG_DEFAULT_CHANNEL(UserDefwnd);
|
|
|
|
// Client Shutdown messages
|
|
#define MCS_SHUTDOWNTIMERS 1
|
|
#define MCS_QUERYENDSESSION 2
|
|
// Client Shutdown returns
|
|
#define MCSR_GOODFORSHUTDOWN 1
|
|
#define MCSR_SHUTDOWNFINISHED 2
|
|
#define MCSR_DONOTSHUTDOWN 3
|
|
|
|
/*
|
|
* Based on CSRSS and described in pages 1115 - 1118 "Windows Internals, Fifth Edition".
|
|
* Apparently CSRSS sends out messages to do this w/o going into win32k internals.
|
|
*/
|
|
static
|
|
LRESULT FASTCALL
|
|
IntClientShutdown(
|
|
PWND pWindow,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
LPARAM lParams;
|
|
BOOL KillTimers;
|
|
INT i;
|
|
LRESULT lResult = MCSR_GOODFORSHUTDOWN;
|
|
HWND *List;
|
|
|
|
lParams = wParam & (ENDSESSION_LOGOFF|ENDSESSION_CRITICAL|ENDSESSION_CLOSEAPP);
|
|
KillTimers = wParam & MCS_SHUTDOWNTIMERS ? TRUE : FALSE;
|
|
/*
|
|
First, send end sessions to children.
|
|
*/
|
|
List = IntWinListChildren(pWindow);
|
|
|
|
if (List)
|
|
{
|
|
for (i = 0; List[i]; i++)
|
|
{
|
|
PWND WndChild;
|
|
|
|
if (!(WndChild = UserGetWindowObject(List[i])))
|
|
continue;
|
|
|
|
if (wParam & MCS_QUERYENDSESSION)
|
|
{
|
|
if (!co_IntSendMessage(WndChild->head.h, WM_QUERYENDSESSION, 0, lParams))
|
|
{
|
|
lResult = MCSR_DONOTSHUTDOWN;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
co_IntSendMessage(WndChild->head.h, WM_ENDSESSION, KillTimers, lParams);
|
|
if (KillTimers)
|
|
{
|
|
DestroyTimersForWindow(WndChild->head.pti, WndChild);
|
|
}
|
|
lResult = MCSR_SHUTDOWNFINISHED;
|
|
}
|
|
}
|
|
ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
|
|
}
|
|
if (List && (lResult == MCSR_DONOTSHUTDOWN)) return lResult;
|
|
/*
|
|
Send to the caller.
|
|
*/
|
|
if (wParam & MCS_QUERYENDSESSION)
|
|
{
|
|
if (!co_IntSendMessage(pWindow->head.h, WM_QUERYENDSESSION, 0, lParams))
|
|
{
|
|
lResult = MCSR_DONOTSHUTDOWN;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
co_IntSendMessage(pWindow->head.h, WM_ENDSESSION, KillTimers, lParams);
|
|
if (KillTimers)
|
|
{
|
|
DestroyTimersForWindow(pWindow->head.pti, pWindow);
|
|
}
|
|
lResult = MCSR_SHUTDOWNFINISHED;
|
|
}
|
|
return lResult;
|
|
}
|
|
|
|
HBRUSH FASTCALL
|
|
DefWndControlColor(HDC hDC, UINT ctlType)
|
|
{
|
|
if (ctlType == CTLCOLOR_SCROLLBAR)
|
|
{
|
|
HBRUSH hb = IntGetSysColorBrush(COLOR_SCROLLBAR);
|
|
COLORREF bk = IntGetSysColor(COLOR_3DHILIGHT);
|
|
IntGdiSetTextColor(hDC, IntGetSysColor(COLOR_3DFACE));
|
|
IntGdiSetBkColor(hDC, bk);
|
|
|
|
/* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT
|
|
* we better use 0x55aa bitmap brush to make scrollbar's background
|
|
* look different from the window background.
|
|
*/
|
|
if ( bk == IntGetSysColor(COLOR_WINDOW))
|
|
return gpsi->hbrGray;
|
|
|
|
NtGdiUnrealizeObject( hb );
|
|
return hb;
|
|
}
|
|
|
|
IntGdiSetTextColor(hDC, IntGetSysColor(COLOR_WINDOWTEXT));
|
|
|
|
if ((ctlType == CTLCOLOR_EDIT) || (ctlType == CTLCOLOR_LISTBOX))
|
|
{
|
|
IntGdiSetBkColor(hDC, IntGetSysColor(COLOR_WINDOW));
|
|
}
|
|
else
|
|
{
|
|
IntGdiSetBkColor(hDC, IntGetSysColor(COLOR_3DFACE));
|
|
return IntGetSysColorBrush(COLOR_3DFACE);
|
|
}
|
|
|
|
return IntGetSysColorBrush(COLOR_WINDOW);
|
|
}
|
|
|
|
|
|
LRESULT FASTCALL
|
|
DefWndHandleSysCommand(PWND pWnd, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LRESULT lResult = 0;
|
|
BOOL Hook = FALSE;
|
|
|
|
if (ISITHOOKED(WH_CBT) || (pWnd->head.rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)))
|
|
{
|
|
Hook = TRUE;
|
|
lResult = co_HOOK_CallHooks(WH_CBT, HCBT_SYSCOMMAND, wParam, lParam);
|
|
|
|
if (lResult) return lResult;
|
|
}
|
|
|
|
switch (wParam & 0xfff0)
|
|
{
|
|
case SC_SCREENSAVE:
|
|
ERR("Screensaver Called!\n");
|
|
UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_START_SCREENSAVE, 0); // always lParam 0 == not Secure
|
|
break;
|
|
|
|
default:
|
|
// We do not support anything else here so we should return normal even when sending a hook.
|
|
return 0;
|
|
}
|
|
|
|
return(Hook ? 1 : 0); // Don't call us again from user space.
|
|
}
|
|
|
|
/*
|
|
Win32k counterpart of User DefWindowProc
|
|
*/
|
|
LRESULT FASTCALL
|
|
IntDefWindowProc(
|
|
PWND Wnd,
|
|
UINT Msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
BOOL Ansi)
|
|
{
|
|
LRESULT lResult = 0;
|
|
|
|
if (Msg > WM_USER) return 0;
|
|
|
|
switch (Msg)
|
|
{
|
|
case WM_SYSCOMMAND:
|
|
{
|
|
ERR("hwnd %p WM_SYSCOMMAND %lx %lx\n", Wnd->head.h, wParam, lParam );
|
|
lResult = DefWndHandleSysCommand(Wnd, wParam, lParam);
|
|
break;
|
|
}
|
|
case WM_SHOWWINDOW:
|
|
{
|
|
if ((Wnd->style & WS_VISIBLE) && wParam) break;
|
|
if (!(Wnd->style & WS_VISIBLE) && !wParam) break;
|
|
if (!Wnd->spwndOwner) break;
|
|
if (LOWORD(lParam))
|
|
{
|
|
if (wParam)
|
|
{
|
|
if (!(Wnd->state & WNDS_HIDDENPOPUP)) break;
|
|
Wnd->state &= ~WNDS_HIDDENPOPUP;
|
|
}
|
|
else
|
|
Wnd->state |= WNDS_HIDDENPOPUP;
|
|
|
|
co_WinPosShowWindow(Wnd, wParam ? SW_SHOWNOACTIVATE : SW_HIDE);
|
|
}
|
|
}
|
|
break;
|
|
case WM_CLIENTSHUTDOWN:
|
|
return IntClientShutdown(Wnd, wParam, lParam);
|
|
|
|
case WM_CTLCOLORMSGBOX:
|
|
case WM_CTLCOLOREDIT:
|
|
case WM_CTLCOLORLISTBOX:
|
|
case WM_CTLCOLORBTN:
|
|
case WM_CTLCOLORDLG:
|
|
case WM_CTLCOLORSTATIC:
|
|
case WM_CTLCOLORSCROLLBAR:
|
|
return (LRESULT) DefWndControlColor((HDC)wParam, Msg - WM_CTLCOLORMSGBOX);
|
|
|
|
case WM_CTLCOLOR:
|
|
return (LRESULT) DefWndControlColor((HDC)wParam, HIWORD(lParam));
|
|
|
|
case WM_GETHOTKEY:
|
|
return DefWndGetHotKey(UserHMGetHandle(Wnd));
|
|
case WM_SETHOTKEY:
|
|
return DefWndSetHotKey(Wnd, wParam);
|
|
|
|
case WM_NCHITTEST:
|
|
{
|
|
POINT Point;
|
|
Point.x = GET_X_LPARAM(lParam);
|
|
Point.y = GET_Y_LPARAM(lParam);
|
|
return GetNCHitEx(Wnd, Point);
|
|
}
|
|
|
|
case WM_SYNCPAINT:
|
|
{
|
|
HRGN hRgn;
|
|
Wnd->state &= ~WNDS_SYNCPAINTPENDING;
|
|
ERR("WM_SYNCPAINT\n");
|
|
hRgn = IntSysCreateRectRgn(0, 0, 0, 0);
|
|
if (co_UserGetUpdateRgn(Wnd, hRgn, FALSE) != NULLREGION)
|
|
{
|
|
if (!wParam) wParam = (RDW_ERASENOW | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN);
|
|
co_UserRedrawWindow(Wnd, NULL, hRgn, wParam);
|
|
}
|
|
GreDeleteObject(hRgn);
|
|
return 0;
|
|
}
|
|
|
|
case WM_SETREDRAW:
|
|
if (wParam)
|
|
{
|
|
if (!(Wnd->style & WS_VISIBLE))
|
|
{
|
|
IntSetStyle( Wnd, WS_VISIBLE, 0 );
|
|
Wnd->state |= WNDS_SENDNCPAINT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Wnd->style & WS_VISIBLE)
|
|
{
|
|
co_UserRedrawWindow( Wnd, NULL, NULL, RDW_ALLCHILDREN | RDW_VALIDATE );
|
|
IntSetStyle( Wnd, 0, WS_VISIBLE );
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
/* ReactOS only. */
|
|
case WM_CBT:
|
|
{
|
|
switch (wParam)
|
|
{
|
|
case HCBT_MOVESIZE:
|
|
{
|
|
RECTL rt;
|
|
|
|
if (lParam)
|
|
{
|
|
_SEH2_TRY
|
|
{
|
|
ProbeForRead((PVOID)lParam,
|
|
sizeof(RECT),
|
|
1);
|
|
|
|
RtlCopyMemory(&rt,
|
|
(PVOID)lParam,
|
|
sizeof(RECT));
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
lResult = 1;
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
if (!lResult)
|
|
lResult = co_HOOK_CallHooks(WH_CBT, HCBT_MOVESIZE, (WPARAM)Wnd->head.h, lParam ? (LPARAM)&rt : 0);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return lResult;
|
|
}
|
|
|
|
static HICON NC_IconForWindow( PWND pWnd )
|
|
{
|
|
HICON hIcon = 0;
|
|
|
|
if (!pWnd->pcls || pWnd->fnid == FNID_DESKTOP) return hIcon;
|
|
if (!hIcon) hIcon = pWnd->pcls->hIconSm;
|
|
if (!hIcon) hIcon = pWnd->pcls->hIcon;
|
|
|
|
if (!hIcon && pWnd->style & DS_MODALFRAME)
|
|
{ // Fake it out for now, we use it as a test.
|
|
hIcon = (HICON)1;
|
|
/* FIXME: Need to setup Registry System Cursor & Icons via Callbacks at init time! */
|
|
if (!hIcon) hIcon = gpsi->hIconSmWindows; // Both are IDI_WINLOGO Small
|
|
if (!hIcon) hIcon = gpsi->hIcoWindows; // Reg size.
|
|
}
|
|
return hIcon;
|
|
}
|
|
|
|
DWORD FASTCALL
|
|
GetNCHitEx(PWND pWnd, POINT pt)
|
|
{
|
|
RECT rcWindow, rcClient;
|
|
DWORD Style, ExStyle;
|
|
|
|
if (!pWnd) return HTNOWHERE;
|
|
|
|
if (pWnd == UserGetDesktopWindow()) // pWnd->fnid == FNID_DESKTOP)
|
|
{
|
|
rcClient.left = rcClient.top = rcWindow.left = rcWindow.top = 0;
|
|
rcWindow.right = UserGetSystemMetrics(SM_CXSCREEN);
|
|
rcWindow.bottom = UserGetSystemMetrics(SM_CYSCREEN);
|
|
rcClient.right = UserGetSystemMetrics(SM_CXSCREEN);
|
|
rcClient.bottom = UserGetSystemMetrics(SM_CYSCREEN);
|
|
}
|
|
else
|
|
{
|
|
rcClient = pWnd->rcClient;
|
|
rcWindow = pWnd->rcWindow;
|
|
}
|
|
|
|
if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y)) return HTNOWHERE;
|
|
|
|
Style = pWnd->style;
|
|
ExStyle = pWnd->ExStyle;
|
|
|
|
if (Style & WS_MINIMIZE) return HTCAPTION;
|
|
|
|
if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTCLIENT;
|
|
|
|
/* Check borders */
|
|
if (HAS_THICKFRAME( Style, ExStyle ))
|
|
{
|
|
RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) );
|
|
if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y ))
|
|
{
|
|
/* Check top sizing border */
|
|
if (pt.y < rcWindow.top)
|
|
{
|
|
if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
|
|
if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
|
|
return HTTOP;
|
|
}
|
|
/* Check bottom sizing border */
|
|
if (pt.y >= rcWindow.bottom)
|
|
{
|
|
if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
|
|
if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
|
|
return HTBOTTOM;
|
|
}
|
|
/* Check left sizing border */
|
|
if (pt.x < rcWindow.left)
|
|
{
|
|
if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
|
|
if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
|
|
return HTLEFT;
|
|
}
|
|
/* Check right sizing border */
|
|
if (pt.x >= rcWindow.right)
|
|
{
|
|
if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
|
|
if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
|
|
return HTRIGHT;
|
|
}
|
|
}
|
|
}
|
|
else /* No thick frame */
|
|
{
|
|
if (HAS_DLGFRAME( Style, ExStyle ))
|
|
RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
|
|
else if (HAS_THINFRAME( Style, ExStyle ))
|
|
RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
|
|
if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y )) return HTBORDER;
|
|
}
|
|
|
|
/* Check caption */
|
|
|
|
if ((Style & WS_CAPTION) == WS_CAPTION)
|
|
{
|
|
if (ExStyle & WS_EX_TOOLWINDOW)
|
|
rcWindow.top += UserGetSystemMetrics(SM_CYSMCAPTION) - 1;
|
|
else
|
|
rcWindow.top += UserGetSystemMetrics(SM_CYCAPTION) - 1;
|
|
if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y ))
|
|
{
|
|
BOOL min_or_max_box = (Style & WS_SYSMENU) && (Style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
|
|
if (ExStyle & WS_EX_LAYOUTRTL)
|
|
{
|
|
/* Check system menu */
|
|
if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd))
|
|
{
|
|
rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION) - 1;
|
|
if (pt.x > rcWindow.right) return HTSYSMENU;
|
|
}
|
|
|
|
/* Check close button */
|
|
if (Style & WS_SYSMENU)
|
|
{
|
|
rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION);
|
|
if (pt.x < rcWindow.left) return HTCLOSE;
|
|
}
|
|
|
|
/* Check maximize box */
|
|
/* In Win95 there is automatically a Maximize button when there is a minimize one */
|
|
if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
|
|
{
|
|
rcWindow.left += UserGetSystemMetrics(SM_CXSIZE);
|
|
if (pt.x < rcWindow.left) return HTMAXBUTTON;
|
|
}
|
|
|
|
/* Check minimize box */
|
|
if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
|
|
{
|
|
rcWindow.left += UserGetSystemMetrics(SM_CXSIZE);
|
|
if (pt.x < rcWindow.left) return HTMINBUTTON;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Check system menu */
|
|
if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd))
|
|
{
|
|
rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION) - 1;
|
|
if (pt.x < rcWindow.left) return HTSYSMENU;
|
|
}
|
|
|
|
/* Check close button */
|
|
if (Style & WS_SYSMENU)
|
|
{
|
|
rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION);
|
|
if (pt.x > rcWindow.right) return HTCLOSE;
|
|
}
|
|
|
|
/* Check maximize box */
|
|
/* In Win95 there is automatically a Maximize button when there is a minimize one */
|
|
if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
|
|
{
|
|
rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE);
|
|
if (pt.x > rcWindow.right) return HTMAXBUTTON;
|
|
}
|
|
|
|
/* Check minimize box */
|
|
if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
|
|
{
|
|
rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE);
|
|
if (pt.x > rcWindow.right) return HTMINBUTTON;
|
|
}
|
|
}
|
|
return HTCAPTION;
|
|
}
|
|
}
|
|
|
|
/* Check menu bar */
|
|
|
|
if (HAS_MENU( pWnd, Style ) && (pt.y < rcClient.top) &&
|
|
(pt.x >= rcClient.left) && (pt.x < rcClient.right))
|
|
return HTMENU;
|
|
|
|
/* Check vertical scroll bar */
|
|
|
|
if (ExStyle & WS_EX_LAYOUTRTL) ExStyle ^= WS_EX_LEFTSCROLLBAR;
|
|
if (Style & WS_VSCROLL)
|
|
{
|
|
if((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
|
|
rcClient.left -= UserGetSystemMetrics(SM_CXVSCROLL);
|
|
else
|
|
rcClient.right += UserGetSystemMetrics(SM_CXVSCROLL);
|
|
if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTVSCROLL;
|
|
}
|
|
|
|
/* Check horizontal scroll bar */
|
|
|
|
if (Style & WS_HSCROLL)
|
|
{
|
|
rcClient.bottom += UserGetSystemMetrics(SM_CYHSCROLL);
|
|
if (RECTL_bPointInRect( &rcClient, pt.x, pt.y ))
|
|
{
|
|
/* Check size box */
|
|
if ((Style & WS_VSCROLL) &&
|
|
((((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + UserGetSystemMetrics(SM_CXVSCROLL))) ||
|
|
(((ExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - UserGetSystemMetrics(SM_CXVSCROLL)))))
|
|
return HTSIZE;
|
|
return HTHSCROLL;
|
|
}
|
|
}
|
|
|
|
/* Has to return HTNOWHERE if nothing was found
|
|
Could happen when a window has a customized non client area */
|
|
return HTNOWHERE;
|
|
}
|
|
|
|
/* EOF */
|