Branching for 0.3.15 release after two days of no response from a certain sphere...
[reactos.git] / win32ss / user / ntuser / defwnd.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Miscellaneous User functions
5 * FILE: subsystems/win32/win32k/ntuser/defwnd.c
6 * PROGRAMER:
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserDefwnd);
11
12 // Client Shutdown messages
13 #define MCS_SHUTDOWNTIMERS 1
14 #define MCS_QUERYENDSESSION 2
15 // Client Shutdown returns
16 #define MCSR_GOODFORSHUTDOWN 1
17 #define MCSR_SHUTDOWNFINISHED 2
18 #define MCSR_DONOTSHUTDOWN 3
19
20 /*
21 * Based on CSRSS and described in pages 1115 - 1118 "Windows Internals, Fifth Edition".
22 * Apparently CSRSS sends out messages to do this w/o going into win32k internals.
23 */
24 static
25 LRESULT FASTCALL
26 IntClientShutdown(
27 PWND pWindow,
28 WPARAM wParam,
29 LPARAM lParam
30 )
31 {
32 LPARAM lParams;
33 BOOL KillTimers;
34 INT i;
35 LRESULT lResult = MCSR_GOODFORSHUTDOWN;
36 HWND *List;
37
38 lParams = wParam & (ENDSESSION_LOGOFF|ENDSESSION_CRITICAL|ENDSESSION_CLOSEAPP);
39 KillTimers = wParam & MCS_SHUTDOWNTIMERS ? TRUE : FALSE;
40 /*
41 First, send end sessions to children.
42 */
43 List = IntWinListChildren(pWindow);
44
45 if (List)
46 {
47 for (i = 0; List[i]; i++)
48 {
49 PWND WndChild;
50
51 if (!(WndChild = UserGetWindowObject(List[i])))
52 continue;
53
54 if (wParam & MCS_QUERYENDSESSION)
55 {
56 if (!co_IntSendMessage(WndChild->head.h, WM_QUERYENDSESSION, 0, lParams))
57 {
58 lResult = MCSR_DONOTSHUTDOWN;
59 break;
60 }
61 }
62 else
63 {
64 co_IntSendMessage(WndChild->head.h, WM_ENDSESSION, KillTimers, lParams);
65 if (KillTimers)
66 {
67 DestroyTimersForWindow(WndChild->head.pti, WndChild);
68 }
69 lResult = MCSR_SHUTDOWNFINISHED;
70 }
71 }
72 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
73 }
74 if (List && (lResult == MCSR_DONOTSHUTDOWN)) return lResult;
75 /*
76 Send to the caller.
77 */
78 if (wParam & MCS_QUERYENDSESSION)
79 {
80 if (!co_IntSendMessage(pWindow->head.h, WM_QUERYENDSESSION, 0, lParams))
81 {
82 lResult = MCSR_DONOTSHUTDOWN;
83 }
84 }
85 else
86 {
87 co_IntSendMessage(pWindow->head.h, WM_ENDSESSION, KillTimers, lParams);
88 if (KillTimers)
89 {
90 DestroyTimersForWindow(pWindow->head.pti, pWindow);
91 }
92 lResult = MCSR_SHUTDOWNFINISHED;
93 }
94 return lResult;
95 }
96
97 HBRUSH FASTCALL
98 DefWndControlColor(HDC hDC, UINT ctlType)
99 {
100 if (ctlType == CTLCOLOR_SCROLLBAR)
101 {
102 HBRUSH hb = IntGetSysColorBrush(COLOR_SCROLLBAR);
103 COLORREF bk = IntGetSysColor(COLOR_3DHILIGHT);
104 IntGdiSetTextColor(hDC, IntGetSysColor(COLOR_3DFACE));
105 IntGdiSetBkColor(hDC, bk);
106
107 /* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT
108 * we better use 0x55aa bitmap brush to make scrollbar's background
109 * look different from the window background.
110 */
111 if ( bk == IntGetSysColor(COLOR_WINDOW))
112 return gpsi->hbrGray;
113
114 NtGdiUnrealizeObject( hb );
115 return hb;
116 }
117
118 IntGdiSetTextColor(hDC, IntGetSysColor(COLOR_WINDOWTEXT));
119
120 if ((ctlType == CTLCOLOR_EDIT) || (ctlType == CTLCOLOR_LISTBOX))
121 {
122 IntGdiSetBkColor(hDC, IntGetSysColor(COLOR_WINDOW));
123 }
124 else
125 {
126 IntGdiSetBkColor(hDC, IntGetSysColor(COLOR_3DFACE));
127 return IntGetSysColorBrush(COLOR_3DFACE);
128 }
129
130 return IntGetSysColorBrush(COLOR_WINDOW);
131 }
132
133
134 LRESULT FASTCALL
135 DefWndHandleSysCommand(PWND pWnd, WPARAM wParam, LPARAM lParam)
136 {
137 LRESULT lResult = 0;
138 BOOL Hook = FALSE;
139
140 if (ISITHOOKED(WH_CBT) || (pWnd->head.rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)))
141 {
142 Hook = TRUE;
143 lResult = co_HOOK_CallHooks(WH_CBT, HCBT_SYSCOMMAND, wParam, lParam);
144
145 if (lResult) return lResult;
146 }
147
148 switch (wParam & 0xfff0)
149 {
150 case SC_SCREENSAVE:
151 ERR("Screensaver Called!\n");
152 UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_START_SCREENSAVE, 0); // always lParam 0 == not Secure
153 break;
154
155 default:
156 // We do not support anything else here so we should return normal even when sending a hook.
157 return 0;
158 }
159
160 return(Hook ? 1 : 0); // Don't call us again from user space.
161 }
162
163 /*
164 Win32k counterpart of User DefWindowProc
165 */
166 LRESULT FASTCALL
167 IntDefWindowProc(
168 PWND Wnd,
169 UINT Msg,
170 WPARAM wParam,
171 LPARAM lParam,
172 BOOL Ansi)
173 {
174 LRESULT lResult = 0;
175
176 if (Msg > WM_USER) return 0;
177
178 switch (Msg)
179 {
180 case WM_SYSCOMMAND:
181 {
182 ERR("hwnd %p WM_SYSCOMMAND %lx %lx\n", Wnd->head.h, wParam, lParam );
183 lResult = DefWndHandleSysCommand(Wnd, wParam, lParam);
184 break;
185 }
186 case WM_SHOWWINDOW:
187 {
188 if ((Wnd->style & WS_VISIBLE) && wParam) break;
189 if (!(Wnd->style & WS_VISIBLE) && !wParam) break;
190 if (!Wnd->spwndOwner) break;
191 if (LOWORD(lParam))
192 {
193 if (wParam)
194 {
195 if (!(Wnd->state & WNDS_HIDDENPOPUP)) break;
196 Wnd->state &= ~WNDS_HIDDENPOPUP;
197 }
198 else
199 Wnd->state |= WNDS_HIDDENPOPUP;
200
201 co_WinPosShowWindow(Wnd, wParam ? SW_SHOWNOACTIVATE : SW_HIDE);
202 }
203 }
204 break;
205 case WM_CLIENTSHUTDOWN:
206 return IntClientShutdown(Wnd, wParam, lParam);
207
208 case WM_CTLCOLORMSGBOX:
209 case WM_CTLCOLOREDIT:
210 case WM_CTLCOLORLISTBOX:
211 case WM_CTLCOLORBTN:
212 case WM_CTLCOLORDLG:
213 case WM_CTLCOLORSTATIC:
214 case WM_CTLCOLORSCROLLBAR:
215 return (LRESULT) DefWndControlColor((HDC)wParam, Msg - WM_CTLCOLORMSGBOX);
216
217 case WM_CTLCOLOR:
218 return (LRESULT) DefWndControlColor((HDC)wParam, HIWORD(lParam));
219
220 case WM_GETHOTKEY:
221 return DefWndGetHotKey(UserHMGetHandle(Wnd));
222 case WM_SETHOTKEY:
223 return DefWndSetHotKey(Wnd, wParam);
224
225 case WM_NCHITTEST:
226 {
227 POINT Point;
228 Point.x = GET_X_LPARAM(lParam);
229 Point.y = GET_Y_LPARAM(lParam);
230 return GetNCHitEx(Wnd, Point);
231 }
232
233 case WM_SYNCPAINT:
234 {
235 HRGN hRgn;
236 Wnd->state &= ~WNDS_SYNCPAINTPENDING;
237 ERR("WM_SYNCPAINT\n");
238 hRgn = IntSysCreateRectRgn(0, 0, 0, 0);
239 if (co_UserGetUpdateRgn(Wnd, hRgn, FALSE) != NULLREGION)
240 {
241 if (!wParam) wParam = (RDW_ERASENOW | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN);
242 co_UserRedrawWindow(Wnd, NULL, hRgn, wParam);
243 }
244 GreDeleteObject(hRgn);
245 return 0;
246 }
247
248 case WM_SETREDRAW:
249 if (wParam)
250 {
251 if (!(Wnd->style & WS_VISIBLE))
252 {
253 IntSetStyle( Wnd, WS_VISIBLE, 0 );
254 Wnd->state |= WNDS_SENDNCPAINT;
255 }
256 }
257 else
258 {
259 if (Wnd->style & WS_VISIBLE)
260 {
261 co_UserRedrawWindow( Wnd, NULL, NULL, RDW_ALLCHILDREN | RDW_VALIDATE );
262 IntSetStyle( Wnd, 0, WS_VISIBLE );
263 }
264 }
265 return 0;
266
267 /* ReactOS only. */
268 case WM_CBT:
269 {
270 switch (wParam)
271 {
272 case HCBT_MOVESIZE:
273 {
274 RECTL rt;
275
276 if (lParam)
277 {
278 _SEH2_TRY
279 {
280 ProbeForRead((PVOID)lParam,
281 sizeof(RECT),
282 1);
283
284 RtlCopyMemory(&rt,
285 (PVOID)lParam,
286 sizeof(RECT));
287 }
288 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
289 {
290 lResult = 1;
291 }
292 _SEH2_END;
293 }
294 if (!lResult)
295 lResult = co_HOOK_CallHooks(WH_CBT, HCBT_MOVESIZE, (WPARAM)Wnd->head.h, lParam ? (LPARAM)&rt : 0);
296 }
297 break;
298 }
299 break;
300 }
301 break;
302 }
303 return lResult;
304 }
305
306 static HICON NC_IconForWindow( PWND pWnd )
307 {
308 HICON hIcon = 0;
309
310 if (!pWnd->pcls || pWnd->fnid == FNID_DESKTOP) return hIcon;
311 if (!hIcon) hIcon = pWnd->pcls->hIconSm;
312 if (!hIcon) hIcon = pWnd->pcls->hIcon;
313
314 if (!hIcon && pWnd->style & DS_MODALFRAME)
315 { // Fake it out for now, we use it as a test.
316 hIcon = (HICON)1;
317 /* FIXME: Need to setup Registry System Cursor & Icons via Callbacks at init time! */
318 if (!hIcon) hIcon = gpsi->hIconSmWindows; // Both are IDI_WINLOGO Small
319 if (!hIcon) hIcon = gpsi->hIcoWindows; // Reg size.
320 }
321 return hIcon;
322 }
323
324 DWORD FASTCALL
325 GetNCHitEx(PWND pWnd, POINT pt)
326 {
327 RECT rcWindow, rcClient;
328 DWORD Style, ExStyle;
329
330 if (!pWnd) return HTNOWHERE;
331
332 if (pWnd == UserGetDesktopWindow()) // pWnd->fnid == FNID_DESKTOP)
333 {
334 rcClient.left = rcClient.top = rcWindow.left = rcWindow.top = 0;
335 rcWindow.right = UserGetSystemMetrics(SM_CXSCREEN);
336 rcWindow.bottom = UserGetSystemMetrics(SM_CYSCREEN);
337 rcClient.right = UserGetSystemMetrics(SM_CXSCREEN);
338 rcClient.bottom = UserGetSystemMetrics(SM_CYSCREEN);
339 }
340 else
341 {
342 rcClient = pWnd->rcClient;
343 rcWindow = pWnd->rcWindow;
344 }
345
346 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y)) return HTNOWHERE;
347
348 Style = pWnd->style;
349 ExStyle = pWnd->ExStyle;
350
351 if (Style & WS_MINIMIZE) return HTCAPTION;
352
353 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTCLIENT;
354
355 /* Check borders */
356 if (HAS_THICKFRAME( Style, ExStyle ))
357 {
358 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) );
359 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y ))
360 {
361 /* Check top sizing border */
362 if (pt.y < rcWindow.top)
363 {
364 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
365 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
366 return HTTOP;
367 }
368 /* Check bottom sizing border */
369 if (pt.y >= rcWindow.bottom)
370 {
371 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
372 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
373 return HTBOTTOM;
374 }
375 /* Check left sizing border */
376 if (pt.x < rcWindow.left)
377 {
378 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
379 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
380 return HTLEFT;
381 }
382 /* Check right sizing border */
383 if (pt.x >= rcWindow.right)
384 {
385 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
386 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
387 return HTRIGHT;
388 }
389 }
390 }
391 else /* No thick frame */
392 {
393 if (HAS_DLGFRAME( Style, ExStyle ))
394 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
395 else if (HAS_THINFRAME( Style, ExStyle ))
396 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
397 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y )) return HTBORDER;
398 }
399
400 /* Check caption */
401
402 if ((Style & WS_CAPTION) == WS_CAPTION)
403 {
404 if (ExStyle & WS_EX_TOOLWINDOW)
405 rcWindow.top += UserGetSystemMetrics(SM_CYSMCAPTION) - 1;
406 else
407 rcWindow.top += UserGetSystemMetrics(SM_CYCAPTION) - 1;
408 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y ))
409 {
410 BOOL min_or_max_box = (Style & WS_SYSMENU) && (Style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
411 if (ExStyle & WS_EX_LAYOUTRTL)
412 {
413 /* Check system menu */
414 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd))
415 {
416 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION) - 1;
417 if (pt.x > rcWindow.right) return HTSYSMENU;
418 }
419
420 /* Check close button */
421 if (Style & WS_SYSMENU)
422 {
423 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION);
424 if (pt.x < rcWindow.left) return HTCLOSE;
425 }
426
427 /* Check maximize box */
428 /* In Win95 there is automatically a Maximize button when there is a minimize one */
429 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
430 {
431 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE);
432 if (pt.x < rcWindow.left) return HTMAXBUTTON;
433 }
434
435 /* Check minimize box */
436 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
437 {
438 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE);
439 if (pt.x < rcWindow.left) return HTMINBUTTON;
440 }
441 }
442 else
443 {
444 /* Check system menu */
445 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd))
446 {
447 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION) - 1;
448 if (pt.x < rcWindow.left) return HTSYSMENU;
449 }
450
451 /* Check close button */
452 if (Style & WS_SYSMENU)
453 {
454 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION);
455 if (pt.x > rcWindow.right) return HTCLOSE;
456 }
457
458 /* Check maximize box */
459 /* In Win95 there is automatically a Maximize button when there is a minimize one */
460 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
461 {
462 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE);
463 if (pt.x > rcWindow.right) return HTMAXBUTTON;
464 }
465
466 /* Check minimize box */
467 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
468 {
469 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE);
470 if (pt.x > rcWindow.right) return HTMINBUTTON;
471 }
472 }
473 return HTCAPTION;
474 }
475 }
476
477 /* Check menu bar */
478
479 if (HAS_MENU( pWnd, Style ) && (pt.y < rcClient.top) &&
480 (pt.x >= rcClient.left) && (pt.x < rcClient.right))
481 return HTMENU;
482
483 /* Check vertical scroll bar */
484
485 if (ExStyle & WS_EX_LAYOUTRTL) ExStyle ^= WS_EX_LEFTSCROLLBAR;
486 if (Style & WS_VSCROLL)
487 {
488 if((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
489 rcClient.left -= UserGetSystemMetrics(SM_CXVSCROLL);
490 else
491 rcClient.right += UserGetSystemMetrics(SM_CXVSCROLL);
492 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTVSCROLL;
493 }
494
495 /* Check horizontal scroll bar */
496
497 if (Style & WS_HSCROLL)
498 {
499 rcClient.bottom += UserGetSystemMetrics(SM_CYHSCROLL);
500 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y ))
501 {
502 /* Check size box */
503 if ((Style & WS_VSCROLL) &&
504 ((((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + UserGetSystemMetrics(SM_CXVSCROLL))) ||
505 (((ExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - UserGetSystemMetrics(SM_CXVSCROLL)))))
506 return HTSIZE;
507 return HTHSCROLL;
508 }
509 }
510
511 /* Has to return HTNOWHERE if nothing was found
512 Could happen when a window has a customized non client area */
513 return HTNOWHERE;
514 }
515
516 /* EOF */