3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
6 * FILE: subsys/win32k/ntuser/window.c
7 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
9 * 06-06-2001 CSH Created
11 /* INCLUDES ******************************************************************/
13 #include <ddk/ntddk.h>
14 #include <win32k/win32k.h>
15 #include <include/object.h>
16 #include <include/guicheck.h>
17 #include <include/window.h>
18 #include <include/class.h>
19 #include <include/error.h>
20 #include <include/winsta.h>
22 #include <include/winpos.h>
23 #include <include/rect.h>
24 #include <include/callback.h>
25 #include <include/painting.h>
30 /* GLOBALS *******************************************************************/
32 #define MINMAX_NOSWP (0x00010000)
34 #define SWP_EX_PAINTSELF 0x0002
36 ATOM AtomInternalPos = NULL;
38 /* FUNCTIONS *****************************************************************/
40 #define HAS_DLGFRAME(Style, ExStyle) \
41 (((ExStyle) & WS_EX_DLGMODALFRAME) || \
42 (((Style) & WS_DLGFRAME) && !((Style) & WS_BORDER)))
44 #define HAS_THICKFRAME(Style, ExStyle) \
45 (((Style) & WS_THICKFRAME) && \
46 !((Style) & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME)
49 WinPosSetupInternalPos(VOID)
51 AtomInternalPos = NtAddAtom(L"SysIP", (ATOM*)(PULONG)&AtomInternalPos);
55 NtUserGetClientOrigin(HWND hWnd, LPPOINT Point)
57 PWINDOW_OBJECT WindowObject;
59 WindowObject = W32kGetWindowObject(hWnd);
60 if (WindowObject == NULL)
62 Point->x = Point->y = 0;
65 Point->x = WindowObject->ClientRect.left;
66 Point->y = WindowObject->ClientRect.top;
71 WinPosActivateOtherWindow(PWINDOW_OBJECT Window)
76 WinPosFindIconPos(HWND hWnd, POINT Pos)
81 WinPosCreateIconTitle(PWINDOW_OBJECT WindowObject)
87 WinPosShowIconTitle(PWINDOW_OBJECT WindowObject, BOOL Show)
89 PINTERNALPOS InternalPos = NtUserGetProp(WindowObject->Self,
91 PWINDOW_OBJECT IconWindow;
96 HWND hWnd = InternalPos->IconTitle;
100 hWnd = WinPosCreateIconTitle(WindowObject);
105 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->
109 (PVOID*)&IconWindow);
110 if (NT_SUCCESS(Status))
112 if (!(IconWindow->Style & WS_VISIBLE))
114 NtUserSendMessage(hWnd, WM_SHOWWINDOW, TRUE, 0);
115 WinPosSetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE |
116 SWP_NOMOVE | SWP_NOACTIVATE |
117 SWP_NOZORDER | SWP_SHOWWINDOW);
119 ObmDereferenceObject(IconWindow);
124 WinPosShowWindow(hWnd, SW_HIDE);
131 WinPosInitInternalPos(PWINDOW_OBJECT WindowObject, POINT pt, PRECT RestoreRect)
133 PINTERNALPOS InternalPos = NtUserGetProp(WindowObject->Self,
135 if (InternalPos == NULL)
138 ExAllocatePool(NonPagedPool, sizeof(INTERNALPOS));
139 NtUserSetProp(WindowObject->Self, AtomInternalPos, InternalPos);
140 InternalPos->IconTitle = 0;
141 InternalPos->NormalRect = WindowObject->WindowRect;
142 InternalPos->IconPos.x = InternalPos->MaxPos.x = 0xFFFFFFFF;
143 InternalPos->IconPos.y = InternalPos->MaxPos.y = 0xFFFFFFFF;
145 if (WindowObject->Style & WS_MINIMIZE)
147 InternalPos->IconPos = pt;
149 else if (WindowObject->Style & WS_MAXIMIZE)
151 InternalPos->MaxPos = pt;
153 else if (RestoreRect != NULL)
155 InternalPos->NormalRect = *RestoreRect;
161 WinPosMinMaximize(PWINDOW_OBJECT WindowObject, UINT ShowFlag, RECT* NewPos)
164 PINTERNALPOS InternalPos;
167 Size.x = WindowObject->WindowRect.left;
168 Size.y = WindowObject->WindowRect.top;
169 InternalPos = WinPosInitInternalPos(WindowObject, Size,
170 &WindowObject->WindowRect);
174 if (WindowObject->Style & WS_MINIMIZE)
176 if (!NtUserSendMessage(WindowObject->Self, WM_QUERYOPEN, 0, 0))
178 return(SWP_NOSIZE | SWP_NOMOVE);
180 SwpFlags |= SWP_NOCOPYBITS;
186 if (WindowObject->Style & WS_MAXIMIZE)
188 WindowObject->Flags |= WINDOWOBJECT_RESTOREMAX;
189 WindowObject->Style &= ~WS_MAXIMIZE;
193 WindowObject->Style &= ~WINDOWOBJECT_RESTOREMAX;
195 WindowObject->Style |= WS_MINIMIZE;
196 InternalPos->IconPos = WinPosFindIconPos(WindowObject,
197 InternalPos->IconPos);
198 W32kSetRect(NewPos, InternalPos->IconPos.x, InternalPos->IconPos.y,
199 NtUserGetSystemMetrics(SM_CXICON),
200 NtUserGetSystemMetrics(SM_CYICON));
201 SwpFlags |= SWP_NOCOPYBITS;
207 WinPosGetMinMaxInfo(WindowObject, &Size, &InternalPos->MaxPos,
209 if (WindowObject->Style & WS_MINIMIZE)
211 WinPosShowIconTitle(WindowObject, FALSE);
212 WindowObject->Style &= ~WS_MINIMIZE;
214 WindowObject->Style |= WS_MINIMIZE;
215 W32kSetRect(NewPos, InternalPos->MaxPos.x, InternalPos->MaxPos.y,
222 if (WindowObject->Style & WS_MINIMIZE)
224 WindowObject->Style &= ~WS_MINIMIZE;
225 WinPosShowIconTitle(WindowObject, FALSE);
226 if (WindowObject->Flags & WINDOWOBJECT_RESTOREMAX)
228 WinPosGetMinMaxInfo(WindowObject, &Size,
229 &InternalPos->MaxPos, NULL, NULL);
230 WindowObject->Style |= WS_MAXIMIZE;
231 W32kSetRect(NewPos, InternalPos->MaxPos.x,
232 InternalPos->MaxPos.y, Size.x, Size.y);
238 if (!(WindowObject->Style & WS_MAXIMIZE))
244 WindowObject->Style &= ~WS_MAXIMIZE;
246 *NewPos = InternalPos->NormalRect;
247 NewPos->right -= NewPos->left;
248 NewPos->bottom -= NewPos->top;
256 SwpFlags |= SWP_NOSIZE | SWP_NOMOVE;
262 WinPosGetMinMaxInfo(PWINDOW_OBJECT Window, POINT* MaxSize, POINT* MaxPos,
263 POINT* MinTrack, POINT* MaxTrack)
269 /* Get default values. */
270 MinMax.ptMaxSize.x = NtUserGetSystemMetrics(SM_CXSCREEN);
271 MinMax.ptMaxSize.y = NtUserGetSystemMetrics(SM_CYSCREEN);
272 MinMax.ptMinTrackSize.x = NtUserGetSystemMetrics(SM_CXMINTRACK);
273 MinMax.ptMinTrackSize.y = NtUserGetSystemMetrics(SM_CYMINTRACK);
274 MinMax.ptMaxTrackSize.x = NtUserGetSystemMetrics(SM_CXSCREEN);
275 MinMax.ptMaxTrackSize.y = NtUserGetSystemMetrics(SM_CYSCREEN);
277 if (HAS_DLGFRAME(Window->Style, Window->ExStyle))
279 XInc = NtUserGetSystemMetrics(SM_CXDLGFRAME);
280 YInc = NtUserGetSystemMetrics(SM_CYDLGFRAME);
285 if (HAS_THICKFRAME(Window->Style, Window->ExStyle))
287 XInc += NtUserGetSystemMetrics(SM_CXFRAME);
288 YInc += NtUserGetSystemMetrics(SM_CYFRAME);
290 if (Window->Style & WS_BORDER)
292 XInc += NtUserGetSystemMetrics(SM_CXBORDER);
293 YInc += NtUserGetSystemMetrics(SM_CYBORDER);
296 MinMax.ptMaxSize.x += 2 * XInc;
297 MinMax.ptMaxSize.y += 2 * YInc;
299 Pos = NtUserGetProp(Window->Self, AtomInternalPos);
302 MinMax.ptMaxPosition = Pos->MaxPos;
306 MinMax.ptMaxPosition.x -= XInc;
307 MinMax.ptMaxPosition.y -= YInc;
310 W32kSendMessage(Window->Self, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax, TRUE);
312 MinMax.ptMaxTrackSize.x = max(MinMax.ptMaxTrackSize.x,
313 MinMax.ptMinTrackSize.x);
314 MinMax.ptMaxTrackSize.y = max(MinMax.ptMaxTrackSize.y,
315 MinMax.ptMinTrackSize.y);
317 if (MaxSize) *MaxSize = MinMax.ptMaxSize;
318 if (MaxPos) *MaxPos = MinMax.ptMaxPosition;
319 if (MinTrack) *MinTrack = MinMax.ptMinTrackSize;
320 if (MaxTrack) *MaxTrack = MinMax.ptMaxTrackSize;
324 WinPosChangeActiveWindow(HWND Wnd, BOOL MouseMsg)
329 WinPosDoNCCALCSize(PWINDOW_OBJECT Window, PWINDOWPOS WinPos,
330 RECT* WindowRect, RECT* ClientRect)
335 WinPosDoWinPosChanging(PWINDOW_OBJECT WindowObject,
340 if (!(WinPos->flags & SWP_NOSENDCHANGING))
342 NtUserSendMessage(WindowObject->Self, WM_WINDOWPOSCHANGING, 0,
346 *WindowRect = WindowObject->WindowRect;
348 (WindowObject->Style & WS_MINIMIZE) ? WindowObject->WindowRect :
349 WindowObject->ClientRect;
351 if (!(WinPos->flags & SWP_NOSIZE))
353 WindowRect->right = WindowRect->left + WinPos->cx;
354 WindowRect->bottom = WindowRect->top + WinPos->cy;
357 if (!(WinPos->flags & SWP_NOMOVE))
359 WindowRect->left = WinPos->x;
360 WindowRect->top = WinPos->y;
361 WindowRect->right += WinPos->x - WindowObject->WindowRect.left;
362 WindowRect->bottom += WinPos->y - WindowObject->WindowRect.top;
364 W32kOffsetRect(ClientRect, WinPos->x - WindowObject->WindowRect.left,
365 WinPos->y - WindowObject->WindowRect.top);
368 WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
373 WinPosSetWindowPos(HWND Wnd, HWND WndInsertAfter, INT x, INT y, INT cx,
376 PWINDOW_OBJECT Window;
384 /* FIXME: Get current active window from active queue. */
386 /* Check if the window is for a desktop. */
387 if (Wnd == PsGetWin32Thread()->Desktop->DesktopWindow)
393 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
397 if (!NT_SUCCESS(Status))
402 /* Fix up the flags. */
403 if (Window->Style & WS_VISIBLE)
405 flags &= ~SWP_SHOWWINDOW;
409 if (!(flags & SWP_SHOWWINDOW))
411 flags |= SWP_NOREDRAW;
413 flags &= ~SWP_HIDEWINDOW;
419 if ((Window->WindowRect.right - Window->WindowRect.left) == cx &&
420 (Window->WindowRect.bottom - Window->WindowRect.top) == cy)
424 if (Window->WindowRect.left == x && Window->WindowRect.top == y)
428 if (FALSE /* FIXME: Check if the window if already active. */)
430 flags |= SWP_NOACTIVATE;
432 else if ((Window->Style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
434 if (!(flags & SWP_NOACTIVATE))
436 flags &= ~SWP_NOZORDER;
437 WndInsertAfter = HWND_TOP;
441 if (WndInsertAfter == HWND_TOPMOST || WndInsertAfter == HWND_NOTOPMOST)
443 WndInsertAfter = HWND_TOP;
446 if (WndInsertAfter != HWND_TOP && WndInsertAfter != HWND_BOTTOM)
448 /* FIXME: Find the window to insert after. */
452 WinPos.hwndInsertAfter = WndInsertAfter;
457 WinPos.flags = flags;
459 WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
461 if ((WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) !=
464 /* FIXME: SWP_DoOwnedPopups. */
467 /* FIXME: Adjust flags based on WndInsertAfter */
469 if ((!(WinPos.flags & (SWP_NOREDRAW | SWP_SHOWWINDOW)) &&
470 WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
471 SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
472 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
474 if (Window->Style & WS_CLIPCHILDREN)
476 VisRgn = DceGetVisRgn(Wnd, DCX_WINDOW | DCX_CLIPSIBLINGS, 0, 0);
480 VisRgn = DceGetVisRgn(Wnd, DCX_WINDOW, 0, 0);
484 WvrFlags = WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect,
487 /* FIXME: Relink windows. */
489 /* FIXME: Reset active DCEs */
491 /* FIXME: Check for redrawing the whole client rect. */
493 if (WinPos.flags & SWP_SHOWWINDOW)
495 Window->Style |= WS_VISIBLE;
496 flags |= SWP_EX_PAINTSELF;
501 /* FIXME: Move the window bits */
504 if (WinPos.flags & SWP_HIDEWINDOW)
506 Window->Style &= ~WS_VISIBLE;
509 /* FIXME: Hide or show the claret */
513 if (!(WinPos.flags & SWP_NOREDRAW))
515 if (flags & SWP_EX_PAINTSELF)
517 PaintRedrawWindow(Window->Self, NULL,
518 (VisRgn == 1) ? 0 : VisRgn,
519 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE |
521 RDW_EX_XYWINDOW | RDW_EX_USEHRGN);
525 PaintRedrawWindow(Window->Self, NULL,
526 (VisRgn == 1) ? 0 : VisRgn,
527 RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN,
530 /* FIXME: Redraw the window parent. */
532 /* FIXME: Delete VisRgn */
535 if (!(flags & SWP_NOACTIVATE))
537 WinPosChangeActiveWindow(WinPos.hwnd, FALSE);
540 /* FIXME: Check some conditions before doing this. */
541 NtUserSendMessage(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&WinPos);
543 ObmDereferenceObject(Window);
548 WinPosGetNonClientSize(HWND Wnd, RECT* WindowRect, RECT* ClientRect)
550 *ClientRect = *WindowRect;
551 return(W32kSendNCCALCSIZEMessage(Wnd, FALSE, ClientRect, NULL));
555 WinPosShowWindow(HWND Wnd, INT Cmd)
558 PWINDOW_OBJECT Window;
565 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
569 if (!NT_SUCCESS(Status))
574 WasVisible = (Window->Style & WS_VISIBLE) != 0;
582 ObmDereferenceObject(Window);
585 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE |
590 case SW_SHOWMINNOACTIVE:
591 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
593 case SW_SHOWMINIMIZED:
594 Swp |= SWP_SHOWWINDOW;
598 Swp |= SWP_FRAMECHANGED;
599 if (!(Window->Style & WS_MINIMIZE))
601 Swp |= WinPosMinMaximize(Window, SW_MINIMIZE, &NewPos);
605 Swp |= SWP_NOSIZE | SWP_NOMOVE;
610 case SW_SHOWMAXIMIZED:
612 Swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
613 if (!(Window->Style & WS_MAXIMIZE))
615 Swp |= WinPosMinMaximize(Window, SW_MAXIMIZE, &NewPos);
619 Swp |= SWP_NOSIZE | SWP_NOMOVE;
625 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
628 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
629 /* Don't activate the topmost window. */
632 case SW_SHOWNOACTIVATE:
638 Swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
639 if (Window->Style & (WS_MINIMIZE | WS_MAXIMIZE))
641 Swp |= WinPosMinMaximize(Window, SW_RESTORE, &NewPos);
645 Swp |= SWP_NOSIZE | SWP_NOMOVE;
650 ShowFlag = (Cmd != SW_HIDE);
651 if (ShowFlag != WasVisible)
653 NtUserSendMessage(Wnd, WM_SHOWWINDOW, ShowFlag, 0);
655 * FIXME: Need to check the window wasn't destroyed during the
660 if (Window->Style & WS_CHILD &&
661 !W32kIsWindowVisible(Window->Parent->Self) &&
662 (Swp & (SWP_NOSIZE | SWP_NOMOVE)) == (SWP_NOSIZE | SWP_NOMOVE))
666 Window->Style &= ~WS_VISIBLE;
670 Window->Style |= WS_VISIBLE;
675 if (Window->Style & WS_CHILD &&
676 !(Window->ExStyle & WS_EX_MDICHILD))
678 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
680 if (!(Swp & MINMAX_NOSWP))
682 WinPosSetWindowPos(Wnd, HWND_TOP, NewPos.left, NewPos.top,
683 NewPos.right, NewPos.bottom, LOWORD(Swp));
686 /* Hide the window. */
687 if (Wnd == W32kGetActiveWindow())
689 WinPosActivateOtherWindow(Window);
691 /* Revert focus to parent. */
692 if (Wnd == W32kGetFocusWindow() ||
693 W32kIsChildWindow(Wnd, W32kGetFocusWindow()))
695 W32kSetFocusWindow(Window->Parent->Self);
699 /* FIXME: Check for window destruction. */
700 /* Show title for minimized windows. */
701 if (Window->Style & WS_MINIMIZE)
703 WinPosShowIconTitle(Window, TRUE);
707 if (Window->Flags & WINDOWOBJECT_NEED_SIZE)
709 WPARAM wParam = SIZE_RESTORED;
711 Window->Flags &= ~WINDOWOBJECT_NEED_SIZE;
712 if (Window->Style & WS_MAXIMIZE)
714 wParam = SIZE_MAXIMIZED;
716 else if (Window->Style & WS_MINIMIZE)
718 wParam = SIZE_MINIMIZED;
721 NtUserSendMessage(Wnd, WM_SIZE, wParam,
722 MAKELONG(Window->ClientRect.right -
723 Window->ClientRect.left,
724 Window->ClientRect.bottom -
725 Window->ClientRect.top));
726 NtUserSendMessage(Wnd, WM_MOVE, 0,
727 MAKELONG(Window->ClientRect.left,
728 Window->ClientRect.top));
730 ObmDereferenceObject(Window);
735 WinPosPtInWindow(PWINDOW_OBJECT Window, POINT Point)
737 return(Point.x >= Window->WindowRect.left &&
738 Point.x < Window->WindowRect.right &&
739 Point.y >= Window->WindowRect.top &&
740 Point.y < Window->WindowRect.bottom);
744 WinPosSearchChildren(PWINDOW_OBJECT ScopeWin, POINT Point,
745 PWINDOW_OBJECT* Window)
747 PLIST_ENTRY CurrentEntry;
748 PWINDOW_OBJECT Current;
750 CurrentEntry = ScopeWin->ChildrenListHead.Flink;
751 while (CurrentEntry != &ScopeWin->ChildrenListHead)
754 CONTAINING_RECORD(CurrentEntry, WINDOW_OBJECT, SiblingListEntry);
756 if (Current->Style & WS_VISIBLE &&
757 ((!(Current->Style & WS_DISABLED)) ||
758 (Current->Style & (WS_CHILD | WS_POPUP)) != WS_CHILD) &&
759 WinPosPtInWindow(Current, Point))
762 if (Current->Style & WS_DISABLED)
766 if (Current->Style & WS_MINIMIZE)
770 if (Point.x >= Current->ClientRect.left &&
771 Point.x < Current->ClientRect.right &&
772 Point.y >= Current->ClientRect.top &&
773 Point.y < Current->ClientRect.bottom)
775 Point.x -= Current->ClientRect.left;
776 Point.y -= Current->ClientRect.top;
778 return(WinPosSearchChildren(Current, Point, Window));
782 CurrentEntry = CurrentEntry->Flink;
788 WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin, POINT WinPoint,
789 PWINDOW_OBJECT* Window)
791 HWND DesktopWindowHandle;
792 PWINDOW_OBJECT DesktopWindow;
793 POINT Point = WinPoint;
798 if (ScopeWin->Style & WS_DISABLED)
803 /* Translate the point to the space of the scope window. */
804 DesktopWindowHandle = W32kGetDesktopWindow();
805 DesktopWindow = W32kGetWindowObject(DesktopWindowHandle);
806 Point.x += ScopeWin->ClientRect.left - DesktopWindow->ClientRect.left;
807 Point.y += ScopeWin->ClientRect.top - DesktopWindow->ClientRect.top;
808 W32kReleaseWindowObject(DesktopWindow);
810 HitTest = WinPosSearchChildren(ScopeWin, Point, Window);
816 if ((*Window)->MessageQueue == PsGetWin32Thread()->MessageQueue)
818 HitTest = W32kSendMessage((*Window)->Self, WM_NCHITTEST, 0,
819 MAKELONG(Point.x, Point.y), FALSE);
820 /* FIXME: Check for HTTRANSPARENT here. */