[Win32SS]
[reactos.git] / reactos / 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: win32ss/user/ntuser/defwnd.c
6 * PROGRAMER:
7 */
8
9 #include <win32k.h>
10 #include <windowsx.h>
11
12 DBG_DEFAULT_CHANNEL(UserDefwnd);
13
14
15 HBRUSH FASTCALL
16 DefWndControlColor(HDC hDC, UINT ctlType)
17 {
18 if (ctlType == CTLCOLOR_SCROLLBAR)
19 {
20 HBRUSH hb = IntGetSysColorBrush(COLOR_SCROLLBAR);
21 COLORREF bk = IntGetSysColor(COLOR_3DHILIGHT);
22 IntGdiSetTextColor(hDC, IntGetSysColor(COLOR_3DFACE));
23 IntGdiSetBkColor(hDC, bk);
24
25 /* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT
26 * we better use 0x55aa bitmap brush to make scrollbar's background
27 * look different from the window background.
28 */
29 if ( bk == IntGetSysColor(COLOR_WINDOW))
30 return gpsi->hbrGray;
31
32 NtGdiUnrealizeObject( hb );
33 return hb;
34 }
35
36 IntGdiSetTextColor(hDC, IntGetSysColor(COLOR_WINDOWTEXT));
37
38 if ((ctlType == CTLCOLOR_EDIT) || (ctlType == CTLCOLOR_LISTBOX))
39 {
40 IntGdiSetBkColor(hDC, IntGetSysColor(COLOR_WINDOW));
41 }
42 else
43 {
44 IntGdiSetBkColor(hDC, IntGetSysColor(COLOR_3DFACE));
45 return IntGetSysColorBrush(COLOR_3DFACE);
46 }
47
48 return IntGetSysColorBrush(COLOR_WINDOW);
49 }
50
51 LRESULT FASTCALL
52 DefWndHandleWindowPosChanging(PWND pWnd, WINDOWPOS* Pos)
53 {
54 POINT maxTrack, minTrack;
55 LONG style = pWnd->style;
56
57 if (Pos->flags & SWP_NOSIZE) return 0;
58 if ((style & WS_THICKFRAME) || ((style & (WS_POPUP | WS_CHILD)) == 0))
59 {
60 co_WinPosGetMinMaxInfo(pWnd, NULL, NULL, &minTrack, &maxTrack);
61 Pos->cx = min(Pos->cx, maxTrack.x);
62 Pos->cy = min(Pos->cy, maxTrack.y);
63 if (!(style & WS_MINIMIZE))
64 {
65 if (Pos->cx < minTrack.x) Pos->cx = minTrack.x;
66 if (Pos->cy < minTrack.y) Pos->cy = minTrack.y;
67 }
68 }
69 else
70 {
71 Pos->cx = max(Pos->cx, 0);
72 Pos->cy = max(Pos->cy, 0);
73 }
74 return 0;
75 }
76
77 LRESULT FASTCALL
78 DefWndHandleWindowPosChanged(PWND pWnd, WINDOWPOS* Pos)
79 {
80 RECT Rect;
81 LONG style = pWnd->style;
82
83 IntGetClientRect(pWnd, &Rect);
84 IntMapWindowPoints(pWnd, (style & WS_CHILD ? IntGetParent(pWnd) : NULL), (LPPOINT) &Rect, 2);
85
86 if (!(Pos->flags & SWP_NOCLIENTMOVE))
87 {
88 co_IntSendMessage(UserHMGetHandle(pWnd), WM_MOVE, 0, MAKELONG(Rect.left, Rect.top));
89 }
90
91 if (!(Pos->flags & SWP_NOCLIENTSIZE) || (Pos->flags & SWP_STATECHANGED))
92 {
93 if (style & WS_MINIMIZE) co_IntSendMessage(UserHMGetHandle(pWnd), WM_SIZE, SIZE_MINIMIZED, 0 );
94 else
95 {
96 WPARAM wp = (style & WS_MAXIMIZE) ? SIZE_MAXIMIZED : SIZE_RESTORED;
97 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SIZE, wp, MAKELONG(Rect.right - Rect.left, Rect.bottom - Rect.top));
98 }
99 }
100 return 0;
101 }
102
103 //
104 // Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
105 //
106 LRESULT FASTCALL
107 DefWndHandleSysCommand(PWND pWnd, WPARAM wParam, LPARAM lParam)
108 {
109 LRESULT lResult = 0;
110 BOOL Hook = FALSE;
111
112 if (ISITHOOKED(WH_CBT) || (pWnd->head.rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)))
113 {
114 Hook = TRUE;
115 lResult = co_HOOK_CallHooks(WH_CBT, HCBT_SYSCOMMAND, wParam, lParam);
116
117 if (lResult) return lResult;
118 }
119
120 switch (wParam & 0xfff0)
121 {
122 case SC_MOVE:
123 case SC_SIZE:
124 DefWndDoSizeMove(pWnd, wParam);
125 break;
126
127 case SC_MINIMIZE:
128 if (UserHMGetHandle(pWnd) == UserGetActiveWindow())
129 IntShowOwnedPopups(pWnd,FALSE); // This is done in ShowWindow! Need to retest!
130 co_WinPosShowWindow( pWnd, SW_MINIMIZE );
131 break;
132
133 case SC_MAXIMIZE:
134 if (((pWnd->style & WS_MINIMIZE) != 0) && UserHMGetHandle(pWnd) == UserGetActiveWindow())
135 IntShowOwnedPopups(pWnd,TRUE);
136 co_WinPosShowWindow( pWnd, SW_MAXIMIZE );
137 break;
138
139 case SC_RESTORE:
140 if (((pWnd->style & WS_MINIMIZE) != 0) && UserHMGetHandle(pWnd) == UserGetActiveWindow())
141 IntShowOwnedPopups(pWnd,TRUE);
142 co_WinPosShowWindow( pWnd, SW_RESTORE );
143 break;
144
145 case SC_CLOSE:
146 return co_IntSendMessage(UserHMGetHandle(pWnd), WM_CLOSE, 0, 0);
147
148 case SC_SCREENSAVE:
149 ERR("Screensaver Called!\n");
150 UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_START_SCREENSAVE, 0); // always lParam 0 == not Secure
151 break;
152
153 case SC_HOTKEY:
154 {
155 USER_REFERENCE_ENTRY Ref;
156
157 pWnd = ValidateHwndNoErr((HWND)lParam);
158 if (pWnd)
159 {
160 if (pWnd->spwndLastActive)
161 {
162 pWnd = pWnd->spwndLastActive;
163 }
164 UserRefObjectCo(pWnd, &Ref);
165 co_IntSetForegroundWindow(pWnd);
166 UserDerefObjectCo(pWnd);
167 if (pWnd->style & WS_MINIMIZE)
168 {
169 UserPostMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_RESTORE, 0);
170 }
171 }
172 }
173 break;
174
175
176 default:
177 // We do not support anything else here so we should return normal even when sending a hook.
178 return 0;
179 }
180
181 return(Hook ? 1 : 0); // Don't call us again from user space.
182 }
183
184 PWND FASTCALL
185 co_IntFindChildWindowToOwner(PWND Root, PWND Owner)
186 {
187 PWND Ret;
188 PWND Child, OwnerWnd;
189
190 for(Child = Root->spwndChild; Child; Child = Child->spwndNext)
191 {
192 OwnerWnd = Child->spwndOwner;
193 if(!OwnerWnd)
194 continue;
195
196 if (!(Child->style & WS_POPUP) ||
197 !(Child->style & WS_VISIBLE) ||
198 /* Fixes CMD pop up properties window from having foreground. */
199 Owner->head.pti->MessageQueue != Child->head.pti->MessageQueue)
200 continue;
201
202 if(OwnerWnd == Owner)
203 {
204 Ret = Child;
205 return Ret;
206 }
207 }
208 return NULL;
209 }
210
211 LRESULT
212 DefWndHandleSetCursor(PWND pWnd, WPARAM wParam, LPARAM lParam)
213 {
214 PWND pwndPopUP = NULL;
215 WORD Msg = HIWORD(lParam);
216
217 /* Not for child windows. */
218 if (UserHMGetHandle(pWnd) != (HWND)wParam)
219 {
220 return FALSE;
221 }
222
223 switch((short)LOWORD(lParam))
224 {
225 case HTERROR:
226 {
227 //// This is the real fix for CORE-6129! This was a "Code hole".
228 USER_REFERENCE_ENTRY Ref;
229
230 if (Msg == WM_LBUTTONDOWN)
231 {
232 // Find a pop up window to bring active.
233 pwndPopUP = co_IntFindChildWindowToOwner(UserGetDesktopWindow(), pWnd);
234 if (pwndPopUP)
235 {
236 // Not a child pop up from desktop.
237 if ( pwndPopUP != UserGetDesktopWindow()->spwndChild )
238 {
239 // Get original active window.
240 PWND pwndOrigActive = gpqForeground->spwndActive;
241
242 co_WinPosSetWindowPos(pWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
243
244 UserRefObjectCo(pwndPopUP, &Ref);
245 //UserSetActiveWindow(pwndPopUP);
246 co_IntSetForegroundWindow(pwndPopUP); // HACK
247 UserDerefObjectCo(pwndPopUP);
248
249 // If the change was made, break out.
250 if (pwndOrigActive != gpqForeground->spwndActive)
251 break;
252 }
253 }
254 }
255 ////
256 if (Msg == WM_LBUTTONDOWN || Msg == WM_MBUTTONDOWN ||
257 Msg == WM_RBUTTONDOWN || Msg == WM_XBUTTONDOWN)
258 {
259 if (pwndPopUP)
260 {
261 FLASHWINFO fwi =
262 {sizeof(FLASHWINFO),
263 UserHMGetHandle(pwndPopUP),
264 FLASHW_ALL,
265 gspv.dwForegroundFlashCount,
266 (gpsi->dtCaretBlink >> 3)};
267
268 // Now shake that window!
269 IntFlashWindowEx(pwndPopUP, &fwi);
270 }
271 UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_MESSAGE_BEEP, 0);
272 }
273 break;
274 }
275
276 case HTCLIENT:
277 {
278 if (pWnd->pcls->spcur)
279 {
280 UserSetCursor(pWnd->pcls->spcur, FALSE);
281 }
282 return FALSE;
283 }
284
285 case HTLEFT:
286 case HTRIGHT:
287 {
288 if (pWnd->style & WS_MAXIMIZE)
289 {
290 break;
291 }
292 UserSetCursor(SYSTEMCUR(SIZEWE), FALSE);
293 return TRUE;
294 }
295
296 case HTTOP:
297 case HTBOTTOM:
298 {
299 if (pWnd->style & WS_MAXIMIZE)
300 {
301 break;
302 }
303 UserSetCursor(SYSTEMCUR(SIZENS), FALSE);
304 return TRUE;
305 }
306
307 case HTTOPLEFT:
308 case HTBOTTOMRIGHT:
309 {
310 if (pWnd->style & WS_MAXIMIZE)
311 {
312 break;
313 }
314 UserSetCursor(SYSTEMCUR(SIZENWSE), FALSE);
315 return TRUE;
316 }
317
318 case HTBOTTOMLEFT:
319 case HTTOPRIGHT:
320 {
321 if (pWnd->style & WS_MAXIMIZE)
322 {
323 break;
324 }
325 UserSetCursor(SYSTEMCUR(SIZENESW), FALSE);
326 return TRUE;
327 }
328 }
329 UserSetCursor(SYSTEMCUR(ARROW), FALSE);
330 return FALSE;
331 }
332
333 VOID FASTCALL DefWndPrint( PWND pwnd, HDC hdc, ULONG uFlags)
334 {
335 /*
336 * Visibility flag.
337 */
338 if ( (uFlags & PRF_CHECKVISIBLE) &&
339 !IntIsWindowVisible(pwnd) )
340 return;
341
342 /*
343 * Unimplemented flags.
344 */
345 if ( (uFlags & PRF_CHILDREN) ||
346 (uFlags & PRF_OWNED) ||
347 (uFlags & PRF_NONCLIENT) )
348 {
349 FIXME("WM_PRINT message with unsupported flags\n");
350 }
351
352 /*
353 * Background
354 */
355 if ( uFlags & PRF_ERASEBKGND)
356 co_IntSendMessage(UserHMGetHandle(pwnd), WM_ERASEBKGND, (WPARAM)hdc, 0);
357
358 /*
359 * Client area
360 */
361 if ( uFlags & PRF_CLIENT)
362 co_IntSendMessage(UserHMGetHandle(pwnd), WM_PRINTCLIENT, (WPARAM)hdc, uFlags);
363 }
364
365
366 /*
367 Win32k counterpart of User DefWindowProc
368 */
369 LRESULT FASTCALL
370 IntDefWindowProc(
371 PWND Wnd,
372 UINT Msg,
373 WPARAM wParam,
374 LPARAM lParam,
375 BOOL Ansi)
376 {
377 LRESULT lResult = 0;
378 USER_REFERENCE_ENTRY Ref;
379
380 if (Msg > WM_USER) return 0;
381
382 switch (Msg)
383 {
384 case WM_SYSCOMMAND:
385 {
386 ERR("hwnd %p WM_SYSCOMMAND %lx %lx\n", Wnd->head.h, wParam, lParam );
387 lResult = DefWndHandleSysCommand(Wnd, wParam, lParam);
388 break;
389 }
390 case WM_SHOWWINDOW:
391 {
392 if ((Wnd->style & WS_VISIBLE) && wParam) break;
393 if (!(Wnd->style & WS_VISIBLE) && !wParam) break;
394 if (!Wnd->spwndOwner) break;
395 if (LOWORD(lParam))
396 {
397 if (wParam)
398 {
399 if (!(Wnd->state & WNDS_HIDDENPOPUP)) break;
400 Wnd->state &= ~WNDS_HIDDENPOPUP;
401 }
402 else
403 Wnd->state |= WNDS_HIDDENPOPUP;
404
405 co_WinPosShowWindow(Wnd, wParam ? SW_SHOWNOACTIVATE : SW_HIDE);
406 }
407 }
408 break;
409
410 case WM_CLIENTSHUTDOWN:
411 return IntClientShutdown(Wnd, wParam, lParam);
412
413 case WM_APPCOMMAND:
414 ERR("WM_APPCOMMAND\n");
415 if ( (Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
416 Wnd != co_GetDesktopWindow(Wnd) )
417 {
418 if (!co_HOOK_CallHooks(WH_SHELL, HSHELL_APPCOMMAND, wParam, lParam))
419 co_IntShellHookNotify(HSHELL_APPCOMMAND, wParam, lParam);
420 break;
421 }
422 UserRefObjectCo(Wnd->spwndParent, &Ref);
423 lResult = co_IntSendMessage(UserHMGetHandle(Wnd->spwndParent), WM_APPCOMMAND, wParam, lParam);
424 UserDerefObjectCo(Wnd->spwndParent);
425 break;
426
427 case WM_CLOSE:
428 co_UserDestroyWindow(Wnd);
429 break;
430
431 case WM_CTLCOLORMSGBOX:
432 case WM_CTLCOLOREDIT:
433 case WM_CTLCOLORLISTBOX:
434 case WM_CTLCOLORBTN:
435 case WM_CTLCOLORDLG:
436 case WM_CTLCOLORSTATIC:
437 case WM_CTLCOLORSCROLLBAR:
438 return (LRESULT) DefWndControlColor((HDC)wParam, Msg - WM_CTLCOLORMSGBOX);
439
440 case WM_CTLCOLOR:
441 return (LRESULT) DefWndControlColor((HDC)wParam, HIWORD(lParam));
442
443 case WM_SETCURSOR:
444 {
445 if (Wnd->style & WS_CHILD)
446 {
447 /* with the exception of the border around a resizable wnd,
448 * give the parent first chance to set the cursor */
449 if (LOWORD(lParam) < HTLEFT || LOWORD(lParam) > HTBOTTOMRIGHT)
450 {
451 PWND parent = Wnd->spwndParent;//IntGetParent( Wnd );
452 if (parent != UserGetDesktopWindow() &&
453 co_IntSendMessage( UserHMGetHandle(parent), WM_SETCURSOR, wParam, lParam))
454 return TRUE;
455 }
456 }
457 return DefWndHandleSetCursor(Wnd, wParam, lParam);
458 }
459
460 case WM_ACTIVATE:
461 /* The default action in Windows is to set the keyboard focus to
462 * the window, if it's being activated and not minimized */
463 if (LOWORD(wParam) != WA_INACTIVE &&
464 !(Wnd->style & WS_MINIMIZE))
465 {
466 //ERR("WM_ACTIVATE %p\n",hWnd);
467 co_UserSetFocus(Wnd);
468 }
469 break;
470
471 case WM_MOUSEWHEEL:
472 if (Wnd->style & WS_CHILD)
473 {
474 HWND hwndParent;
475 PWND pwndParent = IntGetParent(Wnd);
476 hwndParent = pwndParent ? UserHMGetHandle(pwndParent) : NULL;
477 return co_IntSendMessage( hwndParent, WM_MOUSEWHEEL, wParam, lParam);
478 }
479 break;
480
481 case WM_ERASEBKGND:
482 case WM_ICONERASEBKGND:
483 {
484 RECT Rect;
485 HBRUSH hBrush = Wnd->pcls->hbrBackground;
486 if (!hBrush) return 0;
487 if (hBrush <= (HBRUSH)COLOR_MENUBAR)
488 {
489 hBrush = IntGetSysColorBrush((INT)hBrush);
490 }
491 if (Wnd->pcls->style & CS_PARENTDC)
492 {
493 /* can't use GetClipBox with a parent DC or we fill the whole parent */
494 IntGetClientRect(Wnd, &Rect);
495 GreDPtoLP((HDC)wParam, (LPPOINT)&Rect, 2);
496 }
497 else
498 {
499 GdiGetClipBox((HDC)wParam, &Rect);
500 }
501 FillRect((HDC)wParam, &Rect, hBrush);
502 return (1);
503 }
504
505 case WM_GETHOTKEY:
506 //ERR("WM_GETHOTKEY\n");
507 return DefWndGetHotKey(Wnd);
508 case WM_SETHOTKEY:
509 //ERR("WM_SETHOTKEY\n");
510 return DefWndSetHotKey(Wnd, wParam);
511
512 case WM_NCHITTEST:
513 {
514 POINT Point;
515 Point.x = GET_X_LPARAM(lParam);
516 Point.y = GET_Y_LPARAM(lParam);
517 return GetNCHitEx(Wnd, Point);
518 }
519
520 case WM_PRINT:
521 {
522 DefWndPrint(Wnd, (HDC)wParam, lParam);
523 return (0);
524 }
525
526 case WM_PAINTICON:
527 case WM_PAINT:
528 {
529 PAINTSTRUCT Ps;
530 HDC hDC;
531
532 /* If already in Paint and Client area is not empty just return. */
533 if (Wnd->state2 & WNDS2_STARTPAINT && !RECTL_bIsEmptyRect(&Wnd->rcClient))
534 {
535 ERR("In Paint and Client area is not empty!\n");
536 return 0;
537 }
538
539 hDC = IntBeginPaint(Wnd, &Ps);
540 if (hDC)
541 {
542 if (((Wnd->style & WS_MINIMIZE) != 0) && (Wnd->pcls->spicn))
543 {
544 RECT ClientRect;
545 INT x, y;
546
547 ERR("Doing Paint and Client area is empty!\n");
548 IntGetClientRect(Wnd, &ClientRect);
549 x = (ClientRect.right - ClientRect.left - UserGetSystemMetrics(SM_CXICON)) / 2;
550 y = (ClientRect.bottom - ClientRect.top - UserGetSystemMetrics(SM_CYICON)) / 2;
551 UserDrawIconEx(hDC, x, y, Wnd->pcls->spicn, 0, 0, 0, 0, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE);
552 }
553
554 IntEndPaint(Wnd, &Ps);
555 }
556 return (0);
557 }
558
559 case WM_SYNCPAINT:
560 {
561 HRGN hRgn;
562 Wnd->state &= ~WNDS_SYNCPAINTPENDING;
563 TRACE("WM_SYNCPAINT\n");
564 hRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
565 if (hRgn)
566 {
567 if (co_UserGetUpdateRgn(Wnd, hRgn, FALSE) != NULLREGION)
568 {
569 PREGION pRgn = REGION_LockRgn(hRgn);
570 if (pRgn) REGION_UnlockRgn(pRgn);
571 if (!wParam)
572 wParam = (RDW_ERASENOW | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN);
573 co_UserRedrawWindow(Wnd, NULL, pRgn, wParam);
574 }
575 GreDeleteObject(hRgn);
576 }
577 return 0;
578 }
579
580 case WM_SETREDRAW:
581 ERR("WM_SETREDRAW\n");
582 if (wParam)
583 {
584 if (!(Wnd->style & WS_VISIBLE))
585 {
586 IntSetStyle( Wnd, WS_VISIBLE, 0 );
587 Wnd->state |= WNDS_SENDNCPAINT;
588 }
589 }
590 else
591 {
592 if (Wnd->style & WS_VISIBLE)
593 {
594 co_UserRedrawWindow( Wnd, NULL, NULL, RDW_ALLCHILDREN | RDW_VALIDATE );
595 IntSetStyle( Wnd, 0, WS_VISIBLE );
596 }
597 }
598 return 0;
599
600 case WM_WINDOWPOSCHANGING:
601 {
602 return (DefWndHandleWindowPosChanging(Wnd, (WINDOWPOS*)lParam));
603 }
604
605 case WM_WINDOWPOSCHANGED:
606 {
607 return (DefWndHandleWindowPosChanged(Wnd, (WINDOWPOS*)lParam));
608 }
609
610 /* ReactOS only. */
611 case WM_CBT:
612 {
613 switch (wParam)
614 {
615 case HCBT_MOVESIZE:
616 {
617 RECTL rt;
618
619 if (lParam)
620 {
621 _SEH2_TRY
622 {
623 ProbeForRead((PVOID)lParam,
624 sizeof(RECT),
625 1);
626
627 RtlCopyMemory(&rt,
628 (PVOID)lParam,
629 sizeof(RECT));
630 }
631 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
632 {
633 lResult = 1;
634 }
635 _SEH2_END;
636 }
637 if (!lResult)
638 lResult = co_HOOK_CallHooks(WH_CBT, HCBT_MOVESIZE, (WPARAM)Wnd->head.h, lParam ? (LPARAM)&rt : 0);
639 }
640 break;
641 }
642 break;
643 }
644 break;
645 }
646 return lResult;
647 }
648
649 /* EOF */