update for HEAD-2003091401
[reactos.git] / subsys / win32k / ntuser / winpos.c
1 /*
2  *  ReactOS W32 Subsystem
3  *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /* $Id$
20  *
21  * COPYRIGHT:        See COPYING in the top level directory
22  * PROJECT:          ReactOS kernel
23  * PURPOSE:          Windows
24  * FILE:             subsys/win32k/ntuser/window.c
25  * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
26  * REVISION HISTORY:
27  *       06-06-2001  CSH  NtGdid
28  */
29 /* INCLUDES ******************************************************************/
30
31 #include <ddk/ntddk.h>
32 #include <win32k/win32k.h>
33 #include <include/object.h>
34 #include <include/guicheck.h>
35 #include <include/window.h>
36 #include <include/class.h>
37 #include <include/error.h>
38 #include <include/winsta.h>
39 #include <windows.h>
40 #include <include/winpos.h>
41 #include <include/rect.h>
42 #include <include/callback.h>
43 #include <include/painting.h>
44 #include <include/dce.h>
45 #include <include/vis.h>
46
47 #define NDEBUG
48 #include <debug.h>
49
50 /* GLOBALS *******************************************************************/
51
52 #define MINMAX_NOSWP  (0x00010000)
53
54 #define SWP_EX_NOCOPY 0x0001
55 #define SWP_EX_PAINTSELF 0x0002
56
57 #define  SWP_AGG_NOGEOMETRYCHANGE \
58     (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
59 #define  SWP_AGG_NOPOSCHANGE \
60     (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
61 #define  SWP_AGG_STATUSFLAGS \
62     (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
63
64 ATOM AtomInternalPos = (ATOM) NULL;
65
66 /* FUNCTIONS *****************************************************************/
67
68 #define HAS_DLGFRAME(Style, ExStyle) \
69        (((ExStyle) & WS_EX_DLGMODALFRAME) || \
70         (((Style) & WS_DLGFRAME) && !((Style) & WS_BORDER)))
71
72 #define HAS_THICKFRAME(Style, ExStyle) \
73        (((Style) & WS_THICKFRAME) && \
74         !((Style) & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME)
75
76 VOID FASTCALL
77 WinPosSetupInternalPos(VOID)
78 {
79   AtomInternalPos = NtAddAtom(L"SysIP", (ATOM*)(PULONG)&AtomInternalPos);
80 }
81
82 BOOL STDCALL
83 NtUserGetClientOrigin(HWND hWnd, LPPOINT Point)
84 {
85   PWINDOW_OBJECT WindowObject;
86
87   WindowObject = IntGetWindowObject(hWnd);
88   if (WindowObject == NULL)
89     {
90       Point->x = Point->y = 0;
91       return(TRUE);
92     }
93   Point->x = WindowObject->ClientRect.left;
94   Point->y = WindowObject->ClientRect.top;
95   return(TRUE);
96 }
97
98 BOOL FASTCALL
99 WinPosActivateOtherWindow(PWINDOW_OBJECT Window)
100 {
101         return FALSE;
102 }
103
104 POINT STATIC FASTCALL
105 WinPosFindIconPos(HWND hWnd, POINT Pos)
106 {
107   POINT point;
108   //FIXME
109   return point;
110 }
111
112 HWND STATIC FASTCALL
113 WinPosNtGdiIconTitle(PWINDOW_OBJECT WindowObject)
114 {
115   return(NULL);
116 }
117
118 BOOL STATIC FASTCALL
119 WinPosShowIconTitle(PWINDOW_OBJECT WindowObject, BOOL Show)
120 {
121   PINTERNALPOS InternalPos = (PINTERNALPOS)IntGetProp(WindowObject, AtomInternalPos);
122   PWINDOW_OBJECT IconWindow;
123   NTSTATUS Status;
124
125   if (InternalPos)
126     {
127       HWND hWnd = InternalPos->IconTitle;
128
129       if (hWnd == NULL)
130         {
131           hWnd = WinPosNtGdiIconTitle(WindowObject);
132         }
133       if (Show)
134         {
135           Status = 
136             ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->
137                                        HandleTable,
138                                        hWnd,
139                                        otWindow,
140                                        (PVOID*)&IconWindow);
141           if (NT_SUCCESS(Status))
142             {
143               if (!(IconWindow->Style & WS_VISIBLE))
144                 {
145                   NtUserSendMessage(hWnd, WM_SHOWWINDOW, TRUE, 0);
146                   WinPosSetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE |
147                                      SWP_NOMOVE | SWP_NOACTIVATE | 
148                                      SWP_NOZORDER | SWP_SHOWWINDOW);
149                 }
150               ObmDereferenceObject(IconWindow);
151             }
152         }
153       else
154         {
155           WinPosShowWindow(hWnd, SW_HIDE);
156         }
157     }
158   return(FALSE);
159 }
160
161 PINTERNALPOS STATIC STDCALL
162 WinPosInitInternalPos(PWINDOW_OBJECT WindowObject, POINT pt, PRECT RestoreRect)
163 {
164   PINTERNALPOS InternalPos = (PINTERNALPOS)IntGetProp(WindowObject, AtomInternalPos);
165   if (InternalPos == NULL)
166     {
167       InternalPos = 
168         ExAllocatePool(NonPagedPool, sizeof(INTERNALPOS));
169       IntSetProp(WindowObject, AtomInternalPos, InternalPos);
170       InternalPos->IconTitle = 0;
171       InternalPos->NormalRect = WindowObject->WindowRect;
172       InternalPos->IconPos.x = InternalPos->MaxPos.x = 0xFFFFFFFF;
173       InternalPos->IconPos.y = InternalPos->MaxPos.y = 0xFFFFFFFF;
174     }
175   if (WindowObject->Style & WS_MINIMIZE)
176     {
177       InternalPos->IconPos = pt;
178     }
179   else if (WindowObject->Style & WS_MAXIMIZE)
180     {
181       InternalPos->MaxPos = pt;
182     }
183   else if (RestoreRect != NULL)
184     {
185       InternalPos->NormalRect = *RestoreRect;
186     }
187   return(InternalPos);
188 }
189
190 UINT STDCALL
191 WinPosMinMaximize(PWINDOW_OBJECT WindowObject, UINT ShowFlag, RECT* NewPos)
192 {
193   POINT Size;
194   PINTERNALPOS InternalPos;
195   UINT SwpFlags = 0;
196
197   Size.x = WindowObject->WindowRect.left;
198   Size.y = WindowObject->WindowRect.top;
199   InternalPos = WinPosInitInternalPos(WindowObject, Size, 
200                                       &WindowObject->WindowRect); 
201
202   if (InternalPos)
203     {
204       if (WindowObject->Style & WS_MINIMIZE)
205         {
206           if (!NtUserSendMessage(WindowObject->Self, WM_QUERYOPEN, 0, 0))
207             {
208               return(SWP_NOSIZE | SWP_NOMOVE);
209             }
210           SwpFlags |= SWP_NOCOPYBITS;
211         }
212       switch (ShowFlag)
213         {
214         case SW_MINIMIZE:
215           {
216             if (WindowObject->Style & WS_MAXIMIZE)
217               {
218                 WindowObject->Flags |= WINDOWOBJECT_RESTOREMAX;
219                 WindowObject->Style &= ~WS_MAXIMIZE;
220               }
221             else
222               {
223                 WindowObject->Style &= ~WINDOWOBJECT_RESTOREMAX;
224               }
225             WindowObject->Style |= WS_MINIMIZE;
226             InternalPos->IconPos = WinPosFindIconPos(WindowObject,
227                                                      InternalPos->IconPos);
228             NtGdiSetRect(NewPos, InternalPos->IconPos.x, InternalPos->IconPos.y,
229                         NtUserGetSystemMetrics(SM_CXICON),
230                         NtUserGetSystemMetrics(SM_CYICON));
231             SwpFlags |= SWP_NOCOPYBITS;
232             break;
233           }
234
235         case SW_MAXIMIZE:
236           {
237             WinPosGetMinMaxInfo(WindowObject, &Size, &InternalPos->MaxPos, 
238                                 NULL, NULL);
239             if (WindowObject->Style & WS_MINIMIZE)
240               {
241                 WinPosShowIconTitle(WindowObject, FALSE);
242                 WindowObject->Style &= ~WS_MINIMIZE;
243               }
244             WindowObject->Style |= WS_MINIMIZE;
245             NtGdiSetRect(NewPos, InternalPos->MaxPos.x, InternalPos->MaxPos.y,
246                         Size.x, Size.y);
247             break;
248           }
249
250         case SW_RESTORE:
251           {
252             if (WindowObject->Style & WS_MINIMIZE)
253               {
254                 WindowObject->Style &= ~WS_MINIMIZE;
255                 WinPosShowIconTitle(WindowObject, FALSE);
256                 if (WindowObject->Flags & WINDOWOBJECT_RESTOREMAX)
257                   {
258                     WinPosGetMinMaxInfo(WindowObject, &Size,
259                                         &InternalPos->MaxPos, NULL, NULL);
260                     WindowObject->Style |= WS_MAXIMIZE;
261                     NtGdiSetRect(NewPos, InternalPos->MaxPos.x,
262                                 InternalPos->MaxPos.y, Size.x, Size.y);
263                     break;
264                   }
265               }
266             else
267               {
268                 if (!(WindowObject->Style & WS_MAXIMIZE))
269                   {
270                     return(-1);
271                   }
272                 else
273                   {
274                     WindowObject->Style &= ~WS_MAXIMIZE;
275                   }           
276                 *NewPos = InternalPos->NormalRect;
277                 NewPos->right -= NewPos->left;
278                 NewPos->bottom -= NewPos->top;
279                 break;
280               }
281           }
282         }
283     }
284   else
285     {
286       SwpFlags |= SWP_NOSIZE | SWP_NOMOVE;
287     }
288   return(SwpFlags);
289 }
290
291 UINT STDCALL
292 WinPosGetMinMaxInfo(PWINDOW_OBJECT Window, POINT* MaxSize, POINT* MaxPos,
293                     POINT* MinTrack, POINT* MaxTrack)
294 {
295   MINMAXINFO MinMax;
296   INT XInc, YInc;
297   INTERNALPOS* Pos;
298
299   /* Get default values. */
300   MinMax.ptMaxSize.x = NtUserGetSystemMetrics(SM_CXSCREEN);
301   MinMax.ptMaxSize.y = NtUserGetSystemMetrics(SM_CYSCREEN);
302   MinMax.ptMinTrackSize.x = NtUserGetSystemMetrics(SM_CXMINTRACK);
303   MinMax.ptMinTrackSize.y = NtUserGetSystemMetrics(SM_CYMINTRACK);
304   MinMax.ptMaxTrackSize.x = NtUserGetSystemMetrics(SM_CXSCREEN);
305   MinMax.ptMaxTrackSize.y = NtUserGetSystemMetrics(SM_CYSCREEN);
306
307   if (HAS_DLGFRAME(Window->Style, Window->ExStyle))
308     {
309       XInc = NtUserGetSystemMetrics(SM_CXDLGFRAME);
310       YInc = NtUserGetSystemMetrics(SM_CYDLGFRAME);
311     }
312   else
313     {
314       XInc = YInc = 0;
315       if (HAS_THICKFRAME(Window->Style, Window->ExStyle))
316         {
317           XInc += NtUserGetSystemMetrics(SM_CXFRAME);
318           YInc += NtUserGetSystemMetrics(SM_CYFRAME);
319         }
320       if (Window->Style & WS_BORDER)
321         {
322           XInc += NtUserGetSystemMetrics(SM_CXBORDER);
323           YInc += NtUserGetSystemMetrics(SM_CYBORDER);
324         }
325     }
326   MinMax.ptMaxSize.x += 2 * XInc;
327   MinMax.ptMaxSize.y += 2 * YInc;
328
329   Pos = (PINTERNALPOS)IntGetProp(Window, AtomInternalPos);
330   if (Pos != NULL)
331     {
332       MinMax.ptMaxPosition = Pos->MaxPos;
333     }
334   else
335     {
336       MinMax.ptMaxPosition.x -= XInc;
337       MinMax.ptMaxPosition.y -= YInc;
338     }
339
340   IntSendMessage(Window->Self, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax, TRUE);
341
342   MinMax.ptMaxTrackSize.x = max(MinMax.ptMaxTrackSize.x,
343                                 MinMax.ptMinTrackSize.x);
344   MinMax.ptMaxTrackSize.y = max(MinMax.ptMaxTrackSize.y,
345                                 MinMax.ptMinTrackSize.y);
346
347   if (MaxSize) *MaxSize = MinMax.ptMaxSize;
348   if (MaxPos) *MaxPos = MinMax.ptMaxPosition;
349   if (MinTrack) *MinTrack = MinMax.ptMinTrackSize;
350   if (MaxTrack) *MaxTrack = MinMax.ptMaxTrackSize;
351
352   return 0; //FIXME: what does it return?
353 }
354
355 BOOL STATIC FASTCALL
356 WinPosChangeActiveWindow(HWND hWnd, BOOL MouseMsg)
357 {
358   PWINDOW_OBJECT WindowObject;
359
360   WindowObject = IntGetWindowObject(hWnd);
361   if (WindowObject == NULL)
362     {
363       return FALSE;
364     }
365
366   NtUserSendMessage(hWnd,
367     WM_ACTIVATE,
368           MAKELONG(MouseMsg ? WA_CLICKACTIVE : WA_CLICKACTIVE,
369       (WindowObject->Style & WS_MINIMIZE) ? 1 : 0),
370       (LPARAM)IntGetDesktopWindow());  /* FIXME: Previous active window */
371
372   IntReleaseWindowObject(WindowObject);
373
374   return TRUE;
375 }
376
377 LONG STATIC STDCALL
378 WinPosDoNCCALCSize(PWINDOW_OBJECT Window, PWINDOWPOS WinPos,
379                    RECT* WindowRect, RECT* ClientRect)
380 {
381   UINT wvrFlags = 0;
382
383   /* Send WM_NCCALCSIZE message to get new client area */
384   if ((WinPos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE)
385     {
386       NCCALCSIZE_PARAMS params;
387       WINDOWPOS winposCopy;
388
389       params.rgrc[0] = *WindowRect;
390       params.rgrc[1] = Window->WindowRect;
391       params.rgrc[2] = Window->ClientRect;
392       if (Window->Style & WS_CHILD)
393         {
394           NtGdiOffsetRect(&(params.rgrc[2]), - Window->Parent->ClientRect.left,
395                               - Window->Parent->ClientRect.top);
396         }
397       params.lppos = &winposCopy;
398       winposCopy = *WinPos;
399
400       wvrFlags = IntSendNCCALCSIZEMessage(Window->Self, TRUE, NULL, &params);
401
402       /* If the application send back garbage, ignore it */
403       if (params.rgrc[0].left <= params.rgrc[0].right &&
404           params.rgrc[0].top <= params.rgrc[0].bottom)
405         {
406           *ClientRect = params.rgrc[0];
407           if (Window->Style & WS_CHILD)
408             {
409               NtGdiOffsetRect(ClientRect, Window->Parent->ClientRect.left,
410                               Window->Parent->ClientRect.top);
411             }
412         }
413
414        /* FIXME: WVR_ALIGNxxx */
415
416       if (ClientRect->left != Window->ClientRect.left ||
417           ClientRect->top != Window->ClientRect.top)
418         {
419           WinPos->flags &= ~SWP_NOCLIENTMOVE;
420         }
421
422       if ((ClientRect->right - ClientRect->left !=
423            Window->ClientRect.right - Window->ClientRect.left) ||
424           (ClientRect->bottom - ClientRect->top !=
425            Window->ClientRect.bottom - Window->ClientRect.top))
426         {
427           WinPos->flags &= ~SWP_NOCLIENTSIZE;
428         }
429     }
430   else
431     {
432       if (! (WinPos->flags & SWP_NOMOVE)
433           && (ClientRect->left != Window->ClientRect.left ||
434               ClientRect->top != Window->ClientRect.top))
435         {
436           WinPos->flags &= ~SWP_NOCLIENTMOVE;
437         }
438     }
439
440   return wvrFlags;
441 }
442
443 BOOL STDCALL
444 WinPosDoWinPosChanging(PWINDOW_OBJECT WindowObject,
445                        PWINDOWPOS WinPos,
446                        PRECT WindowRect,
447                        PRECT ClientRect)
448 {
449   if (!(WinPos->flags & SWP_NOSENDCHANGING))
450     {
451       IntSendWINDOWPOSCHANGINGMessage(WindowObject->Self, WinPos);
452     }
453   
454   *WindowRect = WindowObject->WindowRect;
455   *ClientRect = 
456     (WindowObject->Style & WS_MINIMIZE) ? WindowObject->WindowRect :
457     WindowObject->ClientRect;
458
459   if (!(WinPos->flags & SWP_NOSIZE))
460     {
461       WindowRect->right = WindowRect->left + WinPos->cx;
462       WindowRect->bottom = WindowRect->top + WinPos->cy;
463     }
464
465   if (!(WinPos->flags & SWP_NOMOVE))
466     {
467       WindowRect->left = WinPos->x;
468       WindowRect->top = WinPos->y;
469       WindowRect->right += WinPos->x - WindowObject->WindowRect.left;
470       WindowRect->bottom += WinPos->y - WindowObject->WindowRect.top;
471       NtGdiOffsetRect(ClientRect,
472         WinPos->x - WindowObject->WindowRect.left,
473         WinPos->y - WindowObject->WindowRect.top);
474     }
475
476   WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
477
478   return(TRUE);
479 }
480
481 /***********************************************************************
482  *           WinPosInternalMoveWindow
483  *
484  * Update WindowRect and ClientRect of Window and all of its children
485  * We keep both WindowRect and ClientRect in screen coordinates internally
486  */
487 static VOID
488 WinPosInternalMoveWindow(PWINDOW_OBJECT Window, INT MoveX, INT MoveY)
489 {
490   PWINDOW_OBJECT Child;
491
492   Window->WindowRect.left += MoveX;
493   Window->WindowRect.right += MoveX;
494   Window->WindowRect.top += MoveY;
495   Window->WindowRect.bottom += MoveY;
496
497   Window->ClientRect.left += MoveX;
498   Window->ClientRect.right += MoveX;
499   Window->ClientRect.top += MoveY;
500   Window->ClientRect.bottom += MoveY;
501
502   ExAcquireFastMutexUnsafe(&Window->ChildrenListLock);
503   Child = Window->FirstChild;
504   while (Child)
505     {
506       WinPosInternalMoveWindow(Child, MoveX, MoveY);
507       Child = Child->NextSibling;
508     }
509   ExReleaseFastMutexUnsafe(&Window->ChildrenListLock);
510 }
511
512
513 BOOLEAN STDCALL
514 WinPosSetWindowPos(HWND Wnd, HWND WndInsertAfter, INT x, INT y, INT cx,
515                    INT cy, UINT flags)
516 {
517   PWINDOW_OBJECT Window;
518   NTSTATUS Status;
519   WINDOWPOS WinPos;
520   RECT NewWindowRect;
521   RECT NewClientRect;
522   HRGN VisBefore = NULL;
523   HRGN VisAfter = NULL;
524   HRGN DirtyRgn = NULL;
525   HRGN ExposedRgn = NULL;
526   HRGN CopyRgn = NULL;
527   ULONG WvrFlags = 0;
528   RECT OldWindowRect, OldClientRect;
529   UINT FlagsEx = 0;
530   int RgnType;
531   HDC Dc;
532   RECT CopyRect;
533   RECT TempRect;
534
535   /* FIXME: Get current active window from active queue. */
536
537   /* Check if the window is for a desktop. */
538   if (Wnd == PsGetWin32Thread()->Desktop->DesktopWindow)
539     {
540       return(FALSE);
541     }
542
543   Status = 
544     ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
545                                Wnd,
546                                otWindow,
547                                (PVOID*)&Window);
548   if (!NT_SUCCESS(Status))
549     {
550       return(FALSE);
551     }
552   
553   /* Fix up the flags. */
554   if (Window->Style & WS_VISIBLE)
555     {
556       flags &= ~SWP_SHOWWINDOW;
557     }
558   else 
559     {
560       if (!(flags & SWP_SHOWWINDOW))
561         {
562           flags |= SWP_NOREDRAW;
563         }
564       flags &= ~SWP_HIDEWINDOW;
565     }
566
567   cx = max(cx, 0);
568   cy = max(cy, 0);
569
570   if ((Window->WindowRect.right - Window->WindowRect.left) == cx &&
571       (Window->WindowRect.bottom - Window->WindowRect.top) == cy)
572     {
573       flags |= SWP_NOSIZE;
574     }
575   if (Window->WindowRect.left == x && Window->WindowRect.top == y)
576     {
577       flags |= SWP_NOMOVE;
578     }
579   if (Window->Style & WIN_NCACTIVATED)
580     {
581       flags |= SWP_NOACTIVATE;
582     }
583   else if ((Window->Style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
584     {
585       if (!(flags & SWP_NOACTIVATE))
586         {
587           flags &= ~SWP_NOZORDER;
588           WndInsertAfter = HWND_TOP;
589         }
590     }
591
592   if (WndInsertAfter == HWND_TOPMOST || WndInsertAfter == HWND_NOTOPMOST)
593     {
594       WndInsertAfter = HWND_TOP;
595     }
596
597   if (WndInsertAfter != HWND_TOP && WndInsertAfter != HWND_BOTTOM)
598     {
599       /* FIXME: Find the window to insert after. */
600     }
601
602   WinPos.hwnd = Wnd;
603   WinPos.hwndInsertAfter = WndInsertAfter;
604   WinPos.x = x;
605   WinPos.y = y;
606   WinPos.cx = cx;
607   WinPos.cy = cy;
608   WinPos.flags = flags;
609
610   WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
611
612   if ((WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) !=
613       SWP_NOZORDER)
614     {
615       /* FIXME: SWP_DoOwnedPopups. */
616     }
617   
618   /* FIXME: Adjust flags based on WndInsertAfter */
619
620   /* Compute the visible region before the window position is changed */
621   if ((!(WinPos.flags & (SWP_NOREDRAW | SWP_SHOWWINDOW)) &&
622        WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | 
623                        SWP_HIDEWINDOW | SWP_FRAMECHANGED)) != 
624       (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
625     {
626       if (Window->Style & WS_CLIPCHILDREN)
627         {
628           VisBefore = VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop,
629                                                Window, FALSE, FALSE, TRUE);
630         }
631       else
632         {
633           VisBefore = VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop,
634                                                Window, FALSE, FALSE, FALSE);
635         }
636       if (NULLREGION == UnsafeIntGetRgnBox(VisBefore, &TempRect))
637         {
638           NtGdiDeleteObject(VisBefore);
639           VisBefore = NULL;
640         }
641     }
642
643   WvrFlags = WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect,
644                                 &NewClientRect);
645
646   /* FIXME: Relink windows. */
647
648   /* FIXME: Reset active DCEs */
649
650   OldWindowRect = Window->WindowRect;
651   OldClientRect = Window->ClientRect;
652
653   /* FIXME: Check for redrawing the whole client rect. */
654
655   if (! (WinPos.flags & SWP_NOMOVE))
656     {
657       WinPosInternalMoveWindow(Window,
658                                NewWindowRect.left - OldWindowRect.left,
659                                NewWindowRect.top - OldWindowRect.top);
660     }
661   Window->WindowRect = NewWindowRect;
662   Window->ClientRect = NewClientRect;
663
664   if (WinPos.flags & SWP_SHOWWINDOW)
665     {
666       Window->Style |= WS_VISIBLE;
667       FlagsEx |= SWP_EX_PAINTSELF;
668     }
669   else if (WinPos.flags & SWP_HIDEWINDOW)
670     {
671       Window->Style &= ~WS_VISIBLE;
672     }
673
674   if (!(WinPos.flags & SWP_NOREDRAW))
675     {
676       /* Determine the new visible region */
677       if (Window->Style & WS_CLIPCHILDREN)
678         {
679           VisAfter = VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop,
680                                               Window, FALSE, FALSE, TRUE);
681         }
682       else
683         {
684           VisAfter = VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop,
685                                               Window, FALSE, FALSE, FALSE);
686         }
687       if (NULLREGION == UnsafeIntGetRgnBox(VisAfter, &TempRect))
688         {
689           NtGdiDeleteObject(VisAfter);
690           VisAfter = NULL;
691         }
692
693       /* Determine which pixels can be copied from the old window position
694          to the new. Those pixels must be visible in both the old and new
695          position. */
696       if (NULL != VisBefore && NULL != VisAfter && ! (WinPos.flags & SWP_NOCOPYBITS))
697         {
698           CopyRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
699           RgnType = NtGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
700
701           /* If this is (also) a window resize, the whole nonclient area
702              needs to be repainted. So we limit the copy to the client area,
703              'cause there is no use in copying it (would possibly cause
704              "flashing" too). However, if the copy region is already empty,
705              we don't have to crop (can't take anything away from an empty
706              region...) */
707           if (! (WinPos.flags & SWP_NOSIZE)
708               && ERROR != RgnType && NULLREGION != RgnType)
709             {
710               RECT ORect = OldClientRect;
711               RECT NRect = NewClientRect;
712               NtGdiOffsetRect(&ORect, - OldWindowRect.left, - OldWindowRect.top);
713               NtGdiOffsetRect(&NRect, - NewWindowRect.left, - NewWindowRect.top);
714               NtGdiIntersectRect(&CopyRect, &ORect, &NRect);
715               REGION_CropRgn(CopyRgn, CopyRgn, &CopyRect, NULL);
716             }
717
718           /* No use in copying bits which are in the update region. */
719           if ((HRGN) 1 == Window->UpdateRegion)
720             {
721               /* The whole window is in the update region. No use
722                  copying anything, so set the copy region empty */
723               NtGdiSetRectRgn(CopyRgn, 0, 0, 0, 0);
724             }
725           else if (1 < (DWORD) Window->UpdateRegion)
726             {
727               NtGdiCombineRgn(CopyRgn, CopyRgn, Window->UpdateRegion, RGN_DIFF);
728             }
729                   
730
731           /* Now, get the bounding box of the copy region. If it's empty
732              there's nothing to copy. Also, it's no use copying bits onto
733              themselves */
734           UnsafeIntGetRgnBox(CopyRgn, &CopyRect);
735           if (NtGdiIsEmptyRect(&CopyRect))
736             {
737               /* Nothing to copy, clean up */
738               NtGdiDeleteObject(CopyRgn);
739               CopyRgn = NULL;
740             }
741           else if (OldWindowRect.left != NewWindowRect.left
742                    || OldWindowRect.top != NewWindowRect.top)
743             {
744               /* Small trick here: there is no function to bitblt a region. So
745                  we set the region as the clipping region, take the bounding box
746                  of the region and bitblt that. Since nothing outside the clipping
747                  region is copied, this has the effect of bitblt'ing the region.
748
749                  Since NtUserGetDCEx takes ownership of the clip region, we need
750                  to create a copy of CopyRgn and pass that. We need CopyRgn later */
751               HRGN ClipRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
752               NtGdiCombineRgn(ClipRgn, CopyRgn, NULL, RGN_COPY);
753               Dc = NtUserGetDCEx(Wnd, ClipRgn, DCX_WINDOW | DCX_CACHE |
754                             DCX_KEEPCLIPRGN | DCX_INTERSECTRGN | DCX_CLIPSIBLINGS );
755               NtGdiBitBlt(Dc, CopyRect.left, CopyRect.top, CopyRect.right - CopyRect.left,
756                           CopyRect.bottom - CopyRect.top, Dc,
757                           CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
758                           CopyRect.top + (OldWindowRect.top - NewWindowRect.top), SRCCOPY);
759               NtUserReleaseDC(Wnd, Dc);
760             }
761         }
762       else
763         {
764           CopyRgn = NULL;
765         }
766
767       /* We need to redraw what wasn't visible before */
768       if (NULL != VisAfter)
769         {
770           if (NULL != CopyRgn)
771             {
772               DirtyRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
773               RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
774               if (ERROR != RgnType && NULLREGION != RgnType)
775                 {
776                   PaintRedrawWindow(Window, NULL, DirtyRgn,
777                                     RDW_ERASE | RDW_FRAME | RDW_INVALIDATE |
778                                     RDW_ALLCHILDREN | RDW_ERASENOW, 
779                                     RDW_EX_XYWINDOW | RDW_EX_USEHRGN);
780                 }
781               NtGdiDeleteObject(DirtyRgn);
782             }
783           else
784             {
785               PaintRedrawWindow(Window, NULL, NULL,
786                                 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE |
787                                 RDW_ALLCHILDREN | RDW_ERASENOW, 
788                                 RDW_EX_XYWINDOW | RDW_EX_USEHRGN);
789             }
790         }
791
792       if (NULL != CopyRgn)
793         {
794           NtGdiDeleteObject(CopyRgn);
795         }
796     }
797
798   /* Expose what was covered before but not covered anymore */
799   if (NULL != VisBefore)
800     {
801       ExposedRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
802       NtGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
803       NtGdiOffsetRgn(ExposedRgn, OldWindowRect.left - NewWindowRect.left,
804                      OldWindowRect.top - NewWindowRect.top);
805       if (NULL != VisAfter)
806         {
807           RgnType = NtGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
808         }
809       else
810         {
811           RgnType = SIMPLEREGION;
812         }
813       if (ERROR != RgnType && NULLREGION != RgnType)
814         {
815           VIS_WindowLayoutChanged(PsGetWin32Thread()->Desktop, Window, ExposedRgn);
816         }
817       NtGdiDeleteObject(ExposedRgn);
818
819       NtGdiDeleteObject(VisBefore);
820     }
821
822   if (NULL != VisAfter)
823     {
824       NtGdiDeleteObject(VisAfter);
825     }
826
827   /* FIXME: Hide or show the claret */
828
829   if (!(flags & SWP_NOACTIVATE))
830     {
831       WinPosChangeActiveWindow(WinPos.hwnd, FALSE);
832     }
833
834   /* FIXME: Check some conditions before doing this. */
835   IntSendWINDOWPOSCHANGEDMessage(WinPos.hwnd, &WinPos);
836
837   ObmDereferenceObject(Window);
838   return(TRUE);
839 }
840
841 LRESULT STDCALL
842 WinPosGetNonClientSize(HWND Wnd, RECT* WindowRect, RECT* ClientRect)
843 {
844   *ClientRect = *WindowRect;
845   return(IntSendNCCALCSIZEMessage(Wnd, FALSE, ClientRect, NULL));
846 }
847
848 BOOLEAN FASTCALL
849 WinPosShowWindow(HWND Wnd, INT Cmd)
850 {
851   BOOLEAN WasVisible;
852   PWINDOW_OBJECT Window;
853   NTSTATUS Status;
854   UINT Swp = 0;
855   RECT NewPos;
856   BOOLEAN ShowFlag;
857   HRGN VisibleRgn;
858
859   Status = 
860     ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
861                                Wnd,
862                                otWindow,
863                                (PVOID*)&Window);
864   if (!NT_SUCCESS(Status))
865     {
866       return(FALSE);
867     }
868   
869   WasVisible = (Window->Style & WS_VISIBLE) != 0;
870
871   switch (Cmd)
872     {
873     case SW_HIDE:
874       {
875         if (!WasVisible)
876           {
877             ObmDereferenceObject(Window);
878             return(FALSE);
879           }
880         Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE |
881           SWP_NOZORDER;
882         break;
883       }
884
885     case SW_SHOWMINNOACTIVE:
886       Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
887       /* Fall through. */
888     case SW_SHOWMINIMIZED:
889       Swp |= SWP_SHOWWINDOW;
890       /* Fall through. */
891     case SW_MINIMIZE:
892       {
893         Swp |= SWP_FRAMECHANGED;
894         if (!(Window->Style & WS_MINIMIZE))
895           {
896             Swp |= WinPosMinMaximize(Window, SW_MINIMIZE, &NewPos);
897           }
898         else
899           {
900             Swp |= SWP_NOSIZE | SWP_NOMOVE;
901           }
902         break;
903       }
904
905     case SW_SHOWMAXIMIZED:
906       {
907         Swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
908         if (!(Window->Style & WS_MAXIMIZE))
909           {
910             Swp |= WinPosMinMaximize(Window, SW_MAXIMIZE, &NewPos);
911           }
912         else
913           {
914             Swp |= SWP_NOSIZE | SWP_NOMOVE;
915           }
916         break;
917       }
918
919     case SW_SHOWNA:
920       Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
921       /* Fall through. */
922     case SW_SHOW:
923       Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
924       /* Don't activate the topmost window. */
925       break;
926
927     case SW_SHOWNOACTIVATE:
928       Swp |= SWP_NOZORDER;
929       /* Fall through. */
930     case SW_SHOWNORMAL:
931     case SW_SHOWDEFAULT:
932     case SW_RESTORE:
933       Swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
934       if (Window->Style & (WS_MINIMIZE | WS_MAXIMIZE))
935         {
936           Swp |= WinPosMinMaximize(Window, SW_RESTORE, &NewPos);         
937         }
938       else
939         {
940           Swp |= SWP_NOSIZE | SWP_NOMOVE;
941         }
942       break;
943     }
944
945   ShowFlag = (Cmd != SW_HIDE);
946   if (ShowFlag != WasVisible)
947     {
948       NtUserSendMessage(Wnd, WM_SHOWWINDOW, ShowFlag, 0);
949       /* 
950        * FIXME: Need to check the window wasn't destroyed during the 
951        * window procedure. 
952        */
953     }
954
955   if (Window->Style & WS_CHILD &&
956       !IntIsWindowVisible(Window->Parent->Self) &&
957       (Swp & (SWP_NOSIZE | SWP_NOMOVE)) == (SWP_NOSIZE | SWP_NOMOVE))
958     {
959       if (Cmd == SW_HIDE)
960         {
961           VisibleRgn = VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop, Window,
962                                                 FALSE, FALSE, FALSE);
963           Window->Style &= ~WS_VISIBLE;
964           VIS_WindowLayoutChanged(PsGetWin32Thread()->Desktop, Window, VisibleRgn);
965           NtGdiDeleteObject(VisibleRgn);
966         }
967       else
968         {
969           Window->Style |= WS_VISIBLE;
970         }
971     }
972   else
973     {
974       if (Window->Style & WS_CHILD &&
975           !(Window->ExStyle & WS_EX_MDICHILD))
976         {
977           Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
978         }
979       if (!(Swp & MINMAX_NOSWP))
980         {
981           WinPosSetWindowPos(Wnd, HWND_TOP, NewPos.left, NewPos.top,
982                              NewPos.right, NewPos.bottom, LOWORD(Swp));
983           if (Cmd == SW_HIDE)
984             {
985               /* Hide the window. */
986               if (Wnd == IntGetActiveWindow())
987                 {
988                   WinPosActivateOtherWindow(Window);
989                 }
990               /* Revert focus to parent. */
991               if (Wnd == IntGetFocusWindow() ||
992                   IntIsChildWindow(Wnd, IntGetFocusWindow()))
993                 {
994                   IntSetFocusWindow(Window->Parent->Self);
995                 }
996             }
997         }
998       /* FIXME: Check for window destruction. */
999       /* Show title for minimized windows. */
1000       if (Window->Style & WS_MINIMIZE)
1001         {
1002           WinPosShowIconTitle(Window, TRUE);
1003         }
1004     }
1005
1006   if (Window->Flags & WINDOWOBJECT_NEED_SIZE)
1007     {
1008       WPARAM wParam = SIZE_RESTORED;
1009
1010       Window->Flags &= ~WINDOWOBJECT_NEED_SIZE;
1011       if (Window->Style & WS_MAXIMIZE)
1012         {
1013           wParam = SIZE_MAXIMIZED;
1014         }
1015       else if (Window->Style & WS_MINIMIZE)
1016         {
1017           wParam = SIZE_MINIMIZED;
1018         }
1019
1020       NtUserSendMessage(Wnd, WM_SIZE, wParam,
1021                         MAKELONG(Window->ClientRect.right - 
1022                                  Window->ClientRect.left,
1023                                  Window->ClientRect.bottom -
1024                                  Window->ClientRect.top));
1025       NtUserSendMessage(Wnd, WM_MOVE, 0,
1026                         MAKELONG(Window->ClientRect.left,
1027                                  Window->ClientRect.top));
1028     }
1029
1030   /* Activate the window if activation is not requested and the window is not minimized */
1031   if (!(Swp & (SWP_NOACTIVATE | SWP_HIDEWINDOW)) && !(Window->Style & WS_MINIMIZE))
1032     {
1033       WinPosChangeActiveWindow(Wnd, FALSE);
1034     }
1035
1036   ObmDereferenceObject(Window);
1037   return(WasVisible);
1038 }
1039
1040 BOOL STATIC FASTCALL
1041 WinPosPtInWindow(PWINDOW_OBJECT Window, POINT Point)
1042 {
1043   return(Point.x >= Window->WindowRect.left &&
1044          Point.x < Window->WindowRect.right &&
1045          Point.y >= Window->WindowRect.top &&
1046          Point.y < Window->WindowRect.bottom);
1047 }
1048
1049 USHORT STATIC STDCALL
1050 WinPosSearchChildren(PWINDOW_OBJECT ScopeWin, POINT Point,
1051                      PWINDOW_OBJECT* Window)
1052 {
1053   PWINDOW_OBJECT Current;
1054
1055   ExAcquireFastMutexUnsafe(&ScopeWin->ChildrenListLock);
1056   Current = ScopeWin->FirstChild;
1057   while (Current)
1058     {
1059       if (Current->Style & WS_VISIBLE &&
1060           ((!(Current->Style & WS_DISABLED)) ||
1061            (Current->Style & (WS_CHILD | WS_POPUP)) != WS_CHILD) &&
1062           WinPosPtInWindow(Current, Point))
1063         {
1064           *Window = Current;
1065           if (Current->Style & WS_DISABLED)
1066             {
1067                   ExReleaseFastMutexUnsafe(&ScopeWin->ChildrenListLock);
1068               return(HTERROR);
1069             }
1070           if (Current->Style & WS_MINIMIZE)
1071             {
1072                   ExReleaseFastMutexUnsafe(&ScopeWin->ChildrenListLock);
1073               return(HTCAPTION);
1074             }
1075           if (Point.x >= Current->ClientRect.left &&
1076               Point.x < Current->ClientRect.right &&
1077               Point.y >= Current->ClientRect.top &&
1078               Point.y < Current->ClientRect.bottom)
1079             {
1080
1081                   ExReleaseFastMutexUnsafe(&ScopeWin->ChildrenListLock);
1082               return(WinPosSearchChildren(Current, Point, Window));
1083             }
1084
1085           ExReleaseFastMutexUnsafe(&ScopeWin->ChildrenListLock);
1086           return(0);
1087         }
1088       Current = Current->NextSibling;
1089     }
1090                   
1091   ExReleaseFastMutexUnsafe(&ScopeWin->ChildrenListLock);
1092   return(0);
1093 }
1094
1095 USHORT STDCALL
1096 WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin, POINT WinPoint, 
1097                       PWINDOW_OBJECT* Window)
1098 {
1099   HWND DesktopWindowHandle;
1100   PWINDOW_OBJECT DesktopWindow;
1101   POINT Point = WinPoint;
1102   USHORT HitTest;
1103
1104   *Window = NULL;
1105
1106   if (ScopeWin->Style & WS_DISABLED)
1107     {
1108       return(HTERROR);
1109     }
1110
1111   /* Translate the point to the space of the scope window. */
1112   DesktopWindowHandle = IntGetDesktopWindow();
1113   DesktopWindow = IntGetWindowObject(DesktopWindowHandle);
1114   Point.x += ScopeWin->ClientRect.left - DesktopWindow->ClientRect.left;
1115   Point.y += ScopeWin->ClientRect.top - DesktopWindow->ClientRect.top;
1116   IntReleaseWindowObject(DesktopWindow);
1117
1118   HitTest = WinPosSearchChildren(ScopeWin, Point, Window);
1119   if (HitTest != 0)
1120     {
1121       return(HitTest);
1122     }
1123
1124   if ((*Window) == NULL)
1125     {
1126       return(HTNOWHERE);
1127     }
1128   if ((*Window)->MessageQueue == PsGetWin32Thread()->MessageQueue)
1129     {
1130       HitTest = IntSendMessage((*Window)->Self, WM_NCHITTEST, 0,
1131                                 MAKELONG(Point.x, Point.y), FALSE);
1132       /* FIXME: Check for HTTRANSPARENT here. */
1133     }
1134   else
1135     {
1136       HitTest = HTCLIENT;
1137     }
1138
1139   return(HitTest);
1140 }
1141
1142 BOOL
1143 WinPosSetActiveWindow(PWINDOW_OBJECT Window, BOOL Mouse, BOOL ChangeFocus)
1144 {
1145   PUSER_MESSAGE_QUEUE ActiveQueue;
1146   HWND PrevActive;
1147
1148   ActiveQueue = IntGetFocusMessageQueue();
1149   if (ActiveQueue != NULL)
1150     {
1151       PrevActive = ActiveQueue->ActiveWindow;
1152     }
1153   else
1154     {
1155       PrevActive = NULL;
1156     }
1157
1158   if (Window->Self == IntGetActiveDesktop() || Window->Self == PrevActive)
1159     {
1160       return(FALSE);
1161     }
1162   if (PrevActive != NULL)
1163     {
1164       PWINDOW_OBJECT PrevActiveWindow = IntGetWindowObject(PrevActive);
1165       WORD Iconised = HIWORD(PrevActiveWindow->Style & WS_MINIMIZE);
1166       if (!IntSendMessage(PrevActive, WM_NCACTIVATE, FALSE, 0, TRUE))
1167         {
1168           /* FIXME: Check if the new window is system modal. */
1169           return(FALSE);
1170         }
1171       IntSendMessage(PrevActive, 
1172                       WM_ACTIVATE, 
1173                       MAKEWPARAM(WA_INACTIVE, Iconised), 
1174                       (LPARAM)Window->Self,
1175                       TRUE);
1176       /* FIXME: Check if anything changed while processing the message. */
1177       IntReleaseWindowObject(PrevActiveWindow);
1178     }
1179
1180   if (Window != NULL)
1181     {
1182       Window->MessageQueue->ActiveWindow = Window->Self;
1183     }
1184   else if (ActiveQueue != NULL)
1185     {
1186       ActiveQueue->ActiveWindow = NULL;
1187     }
1188   /* FIXME:  Unset this flag for inactive windows */
1189   //if ((Window->Style) & WS_CHILD) Window->Flags |= WIN_NCACTIVATED;
1190
1191   /* FIXME: Send palette messages. */
1192
1193   /* FIXME: Redraw icon title of previously active window. */
1194
1195   /* FIXME: Bring the window to the top. */  
1196
1197   /* FIXME: Send WM_ACTIVATEAPP */
1198   
1199   IntSetFocusMessageQueue(Window->MessageQueue);
1200
1201   /* FIXME: Send activate messages. */
1202
1203   /* FIXME: Change focus. */
1204
1205   /* FIXME: Redraw new window icon title. */
1206
1207   return(TRUE);
1208 }
1209
1210 HWND STDCALL
1211 NtUserGetActiveWindow(VOID)
1212 {
1213   PUSER_MESSAGE_QUEUE ActiveQueue;
1214
1215   ActiveQueue = IntGetFocusMessageQueue();
1216   if (ActiveQueue == NULL)
1217     {
1218       return(NULL);
1219     }
1220   return(ActiveQueue->ActiveWindow);
1221 }
1222
1223 HWND STDCALL
1224 NtUserSetActiveWindow(HWND hWnd)
1225 {
1226   PWINDOW_OBJECT Window;
1227   PUSER_MESSAGE_QUEUE ThreadQueue;
1228   HWND Prev;
1229
1230   Window = IntGetWindowObject(hWnd);
1231   if (Window == NULL || (Window->Style & (WS_DISABLED | WS_CHILD)))
1232     {
1233       IntReleaseWindowObject(Window);
1234       return(0);
1235     }
1236   ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
1237   if (Window->MessageQueue != ThreadQueue)
1238     {
1239       IntReleaseWindowObject(Window);
1240       return(0);
1241     }
1242   Prev = Window->MessageQueue->ActiveWindow;
1243   WinPosSetActiveWindow(Window, FALSE, FALSE);
1244   IntReleaseWindowObject(Window);
1245   return(Prev);
1246 }
1247
1248
1249 /* EOF */