175ae5d84c398a99262d565a4fa7ed44201ad572
[reactos.git] / reactos / 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 <w32k.h>
32
33 #define NDEBUG
34 #include <debug.h>
35
36 /* GLOBALS *******************************************************************/
37
38 #define MINMAX_NOSWP (0x00010000)
39
40 #define SWP_EX_NOCOPY 0x0001
41 #define SWP_EX_PAINTSELF 0x0002
42
43 #define SWP_AGG_NOGEOMETRYCHANGE \
44 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
45 #define SWP_AGG_NOPOSCHANGE \
46 (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
47 #define SWP_AGG_STATUSFLAGS \
48 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
49
50 /* FUNCTIONS *****************************************************************/
51
52 BOOL FASTCALL
53 IntGetClientOrigin(HWND hWnd, LPPOINT Point)
54 {
55 PWINDOW_OBJECT Window;
56
57 Window = IntGetWindowObject((hWnd ? hWnd : IntGetDesktopWindow()));
58 if (Window == NULL)
59 {
60 Point->x = Point->y = 0;
61 return FALSE;
62 }
63 Point->x = Window->ClientRect.left;
64 Point->y = Window->ClientRect.top;
65
66 IntReleaseWindowObject(Window);
67 return TRUE;
68 }
69
70
71
72
73 BOOL FASTCALL
74 UserGetClientOrigin(HWND hWnd, LPPOINT Point)
75 {
76 BOOL Ret;
77 POINT pt;
78 NTSTATUS Status;
79
80 if(!Point)
81 {
82 SetLastWin32Error(ERROR_INVALID_PARAMETER);
83 return FALSE;
84 }
85
86 Ret = IntGetClientOrigin(hWnd, &pt);
87
88 if(!Ret)
89 {
90 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
91 return FALSE;
92 }
93
94 Status = MmCopyToCaller(Point, &pt, sizeof(POINT));
95 if(!NT_SUCCESS(Status))
96 {
97 SetLastNtError(Status);
98 return FALSE;
99 }
100
101 return Ret;
102 }
103
104
105
106 BOOL STDCALL
107 NtUserGetClientOrigin(HWND hWnd, LPPOINT Point)
108 {
109 DECLARE_RETURN(BOOL);
110
111 DPRINT("Enter NtUserGetClientOrigin\n");
112 UserEnterShared();
113
114 RETURN(UserGetClientOrigin(hWnd, Point));
115
116 CLEANUP:
117 DPRINT("Leave NtUserGetClientOrigin, ret=%i\n",_ret_);
118 UserLeave();
119 END_CLEANUP;
120 }
121
122 /*******************************************************************
123 * WinPosActivateOtherWindow
124 *
125 * Activates window other than pWnd.
126 */
127 VOID FASTCALL
128 co_WinPosActivateOtherWindow(PWINDOW_OBJECT Window)
129 {
130 PWINDOW_OBJECT Wnd, Old;
131 HWND Fg;
132
133 if (!Window || IntIsDesktopWindow(Window))
134 {
135 IntSetFocusMessageQueue(NULL);
136 return;
137 }
138
139 /* If this is popup window, try to activate the owner first. */
140 if ((Window->Style & WS_POPUP) && (Wnd = IntGetOwner(Window)))
141 {
142 for(;;)
143 {
144 Old = Wnd;
145 Wnd = IntGetParentObject(Wnd);
146 if(IntIsDesktopWindow(Wnd))
147 {
148 IntReleaseWindowObject(Wnd);
149 Wnd = Old;
150 break;
151 }
152 IntReleaseWindowObject(Old);
153 }
154
155 if ((Wnd->Style & (WS_DISABLED | WS_VISIBLE)) == WS_VISIBLE &&
156 (Wnd->Style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
157 goto done;
158
159 IntReleaseWindowObject(Wnd);
160 }
161
162 /* Pick a next top-level window. */
163 /* FIXME: Search for non-tooltip windows first. */
164 Wnd = Window;
165 while (Wnd != NULL)
166 {
167 Old = Wnd;
168 if (Old->NextSibling == NULL)
169 {
170 Wnd = NULL;
171 if (Old != Window)
172 IntReleaseWindowObject(Old);
173 break;
174 }
175 Wnd = IntGetWindowObject(Old->NextSibling->hSelf);
176 if (Old != Window)
177 IntReleaseWindowObject(Old);
178 if ((Wnd->Style & (WS_DISABLED | WS_VISIBLE)) == WS_VISIBLE &&
179 (Wnd->Style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
180 break;
181 }
182
183 done:
184 Fg = UserGetForegroundWindow();
185 if (Wnd && (!Fg || Window->hSelf == Fg))
186 {
187 if (co_IntSetForegroundWindow(Wnd))
188 {
189 IntReleaseWindowObject(Wnd);
190 return;
191 }
192 }
193 if (!co_IntSetActiveWindow(Wnd))
194 co_IntSetActiveWindow(0);
195 if (Wnd)
196 IntReleaseWindowObject(Wnd);
197 }
198
199
200 UINT
201 FASTCALL
202 co_WinPosArrangeIconicWindows(PWINDOW_OBJECT parent)
203 {
204 RECT rectParent;
205 HWND hwndChild;
206 INT i, x, y, xspacing, yspacing;
207 HWND *List = IntWinListChildren(parent);
208
209 IntGetClientRect( parent, &rectParent );
210 x = rectParent.left;
211 y = rectParent.bottom;
212
213 xspacing = UserGetSystemMetrics(SM_CXMINSPACING);
214 yspacing = UserGetSystemMetrics(SM_CYMINSPACING);
215
216 DPRINT("X:%d Y:%d XS:%d YS:%d\n",x,y,xspacing,yspacing);
217
218 for( i = 0; List[i]; i++)
219 {
220 hwndChild = List[i];
221
222 if((UserGetWindowLong( hwndChild, GWL_STYLE, FALSE) & WS_MINIMIZE) != 0 )
223 {
224 co_WinPosSetWindowPos( hwndChild, 0, x + UserGetSystemMetrics(SM_CXBORDER),
225 y - yspacing - UserGetSystemMetrics(SM_CYBORDER)
226 , 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
227 if (x <= rectParent.right - xspacing) x += xspacing;
228 else
229 {
230 x = rectParent.left;
231 y -= yspacing;
232 }
233 }
234 }
235 ExFreePool(List);
236 return yspacing;
237 }
238
239
240 VOID STATIC FASTCALL
241 WinPosFindIconPos(PWINDOW_OBJECT Window, POINT *Pos)
242 {
243 /* FIXME */
244 }
245
246 PINTERNALPOS FASTCALL
247 WinPosInitInternalPos(PWINDOW_OBJECT Window, POINT *pt, PRECT RestoreRect)
248 {
249 PWINDOW_OBJECT Parent;
250 UINT XInc, YInc;
251
252 if (Window->InternalPos == NULL)
253 {
254 RECT WorkArea;
255 PDESKTOP_OBJECT Desktop = PsGetWin32Thread()->Desktop; /* Or rather get it from the window? */
256
257 Parent = IntGetParentObject(Window);
258 if(Parent)
259 {
260 if(IntIsDesktopWindow(Parent))
261 IntGetDesktopWorkArea(Desktop, &WorkArea);
262 else
263 WorkArea = Parent->ClientRect;
264 IntReleaseWindowObject(Parent);
265 }
266 else
267 IntGetDesktopWorkArea(Desktop, &WorkArea);
268
269 Window->InternalPos = ExAllocatePoolWithTag(PagedPool, sizeof(INTERNALPOS), TAG_WININTLIST);
270 if(!Window->InternalPos)
271 {
272 DPRINT1("Failed to allocate INTERNALPOS structure for window 0x%x\n", Window->hSelf);
273 return NULL;
274 }
275 Window->InternalPos->NormalRect = Window->WindowRect;
276 IntGetWindowBorderMeasures(Window, &XInc, &YInc);
277 Window->InternalPos->MaxPos.x = WorkArea.left - XInc;
278 Window->InternalPos->MaxPos.y = WorkArea.top - YInc;
279 Window->InternalPos->IconPos.x = WorkArea.left;
280 Window->InternalPos->IconPos.y = WorkArea.bottom - UserGetSystemMetrics(SM_CYMINIMIZED);
281 }
282 if (Window->Style & WS_MINIMIZE)
283 {
284 Window->InternalPos->IconPos = *pt;
285 }
286 else if (Window->Style & WS_MAXIMIZE)
287 {
288 Window->InternalPos->MaxPos = *pt;
289 }
290 else if (RestoreRect != NULL)
291 {
292 Window->InternalPos->NormalRect = *RestoreRect;
293 }
294 return(Window->InternalPos);
295 }
296
297 UINT FASTCALL
298 co_WinPosMinMaximize(PWINDOW_OBJECT Window, UINT ShowFlag, RECT* NewPos)
299 {
300 POINT Size;
301 PINTERNALPOS InternalPos;
302 UINT SwpFlags = 0;
303
304 Size.x = Window->WindowRect.left;
305 Size.y = Window->WindowRect.top;
306 InternalPos = WinPosInitInternalPos(Window, &Size, &Window->WindowRect);
307
308 if (InternalPos)
309 {
310 if (Window->Style & WS_MINIMIZE)
311 {
312 if (!co_IntSendMessage(Window->hSelf, WM_QUERYOPEN, 0, 0))
313 {
314 return(SWP_NOSIZE | SWP_NOMOVE);
315 }
316 SwpFlags |= SWP_NOCOPYBITS;
317 }
318 switch (ShowFlag)
319 {
320 case SW_MINIMIZE:
321 {
322 if (Window->Style & WS_MAXIMIZE)
323 {
324 Window->Flags |= WINDOWOBJECT_RESTOREMAX;
325 Window->Style &= ~WS_MAXIMIZE;
326 }
327 else
328 {
329 Window->Flags &= ~WINDOWOBJECT_RESTOREMAX;
330 }
331 co_UserRedrawWindow(Window, NULL, 0, RDW_VALIDATE | RDW_NOERASE |
332 RDW_NOINTERNALPAINT);
333 Window->Style |= WS_MINIMIZE;
334 WinPosFindIconPos(Window, &InternalPos->IconPos);
335 IntGdiSetRect(NewPos, InternalPos->IconPos.x, InternalPos->IconPos.y,
336 UserGetSystemMetrics(SM_CXMINIMIZED),
337 UserGetSystemMetrics(SM_CYMINIMIZED));
338 SwpFlags |= SWP_NOCOPYBITS;
339 break;
340 }
341
342 case SW_MAXIMIZE:
343 {
344 co_WinPosGetMinMaxInfo(Window, &Size, &InternalPos->MaxPos,
345 NULL, NULL);
346 DPRINT("Maximize: %d,%d %dx%d\n",
347 InternalPos->MaxPos.x, InternalPos->MaxPos.y, Size.x, Size.y);
348 if (Window->Style & WS_MINIMIZE)
349 {
350 Window->Style &= ~WS_MINIMIZE;
351 }
352 Window->Style |= WS_MAXIMIZE;
353 IntGdiSetRect(NewPos, InternalPos->MaxPos.x, InternalPos->MaxPos.y,
354 Size.x, Size.y);
355 break;
356 }
357
358 case SW_RESTORE:
359 {
360 if (Window->Style & WS_MINIMIZE)
361 {
362 Window->Style &= ~WS_MINIMIZE;
363 if (Window->Flags & WINDOWOBJECT_RESTOREMAX)
364 {
365 co_WinPosGetMinMaxInfo(Window, &Size,
366 &InternalPos->MaxPos, NULL, NULL);
367 Window->Style |= WS_MAXIMIZE;
368 IntGdiSetRect(NewPos, InternalPos->MaxPos.x,
369 InternalPos->MaxPos.y, Size.x, Size.y);
370 break;
371 }
372 else
373 {
374 *NewPos = InternalPos->NormalRect;
375 NewPos->right -= NewPos->left;
376 NewPos->bottom -= NewPos->top;
377 break;
378 }
379 }
380 else
381 {
382 if (!(Window->Style & WS_MAXIMIZE))
383 {
384 return 0;
385 }
386 Window->Style &= ~WS_MAXIMIZE;
387 *NewPos = InternalPos->NormalRect;
388 NewPos->right -= NewPos->left;
389 NewPos->bottom -= NewPos->top;
390 break;
391 }
392 }
393 }
394 }
395 else
396 {
397 SwpFlags |= SWP_NOSIZE | SWP_NOMOVE;
398 }
399 return(SwpFlags);
400 }
401
402 VOID FASTCALL
403 WinPosFillMinMaxInfoStruct(PWINDOW_OBJECT Window, MINMAXINFO *Info)
404 {
405 UINT XInc, YInc;
406 RECT WorkArea;
407 PDESKTOP_OBJECT Desktop = PsGetWin32Thread()->Desktop; /* Or rather get it from the window? */
408
409 IntGetDesktopWorkArea(Desktop, &WorkArea);
410
411 /* Get default values. */
412 Info->ptMaxSize.x = WorkArea.right - WorkArea.left;
413 Info->ptMaxSize.y = WorkArea.bottom - WorkArea.top;
414 Info->ptMinTrackSize.x = UserGetSystemMetrics(SM_CXMINTRACK);
415 Info->ptMinTrackSize.y = UserGetSystemMetrics(SM_CYMINTRACK);
416 Info->ptMaxTrackSize.x = Info->ptMaxSize.x;
417 Info->ptMaxTrackSize.y = Info->ptMaxSize.y;
418
419 IntGetWindowBorderMeasures(Window, &XInc, &YInc);
420 Info->ptMaxSize.x += 2 * XInc;
421 Info->ptMaxSize.y += 2 * YInc;
422
423 if (Window->InternalPos != NULL)
424 {
425 Info->ptMaxPosition = Window->InternalPos->MaxPos;
426 }
427 else
428 {
429 Info->ptMaxPosition.x -= WorkArea.left + XInc;
430 Info->ptMaxPosition.y -= WorkArea.top + YInc;
431 }
432 }
433
434 UINT FASTCALL
435 co_WinPosGetMinMaxInfo(PWINDOW_OBJECT Window, POINT* MaxSize, POINT* MaxPos,
436 POINT* MinTrack, POINT* MaxTrack)
437 {
438 MINMAXINFO MinMax;
439
440 WinPosFillMinMaxInfoStruct(Window, &MinMax);
441
442 co_IntSendMessage(Window->hSelf, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax);
443
444 MinMax.ptMaxTrackSize.x = max(MinMax.ptMaxTrackSize.x,
445 MinMax.ptMinTrackSize.x);
446 MinMax.ptMaxTrackSize.y = max(MinMax.ptMaxTrackSize.y,
447 MinMax.ptMinTrackSize.y);
448
449 if (MaxSize) *MaxSize = MinMax.ptMaxSize;
450 if (MaxPos) *MaxPos = MinMax.ptMaxPosition;
451 if (MinTrack) *MinTrack = MinMax.ptMinTrackSize;
452 if (MaxTrack) *MaxTrack = MinMax.ptMaxTrackSize;
453
454 return 0; //FIXME: what does it return?
455 }
456
457 STATIC VOID FASTCALL
458 FixClientRect(PRECT ClientRect, PRECT WindowRect)
459 {
460 if (ClientRect->left < WindowRect->left)
461 {
462 ClientRect->left = WindowRect->left;
463 }
464 else if (WindowRect->right < ClientRect->left)
465 {
466 ClientRect->left = WindowRect->right;
467 }
468 if (ClientRect->right < WindowRect->left)
469 {
470 ClientRect->right = WindowRect->left;
471 }
472 else if (WindowRect->right < ClientRect->right)
473 {
474 ClientRect->right = WindowRect->right;
475 }
476 if (ClientRect->top < WindowRect->top)
477 {
478 ClientRect->top = WindowRect->top;
479 }
480 else if (WindowRect->bottom < ClientRect->top)
481 {
482 ClientRect->top = WindowRect->bottom;
483 }
484 if (ClientRect->bottom < WindowRect->top)
485 {
486 ClientRect->bottom = WindowRect->top;
487 }
488 else if (WindowRect->bottom < ClientRect->bottom)
489 {
490 ClientRect->bottom = WindowRect->bottom;
491 }
492 }
493
494 LONG STATIC FASTCALL
495 co_WinPosDoNCCALCSize(PWINDOW_OBJECT Window, PWINDOWPOS WinPos,
496 RECT* WindowRect, RECT* ClientRect)
497 {
498 PWINDOW_OBJECT Parent;
499 UINT wvrFlags = 0;
500
501 /* Send WM_NCCALCSIZE message to get new client area */
502 if ((WinPos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE)
503 {
504 NCCALCSIZE_PARAMS params;
505 WINDOWPOS winposCopy;
506
507 params.rgrc[0] = *WindowRect;
508 params.rgrc[1] = Window->WindowRect;
509 params.rgrc[2] = Window->ClientRect;
510 Parent = IntGetParentObject(Window);
511 if (0 != (Window->Style & WS_CHILD) && Parent)
512 {
513 IntGdiOffsetRect(&(params.rgrc[0]), - Parent->ClientRect.left,
514 - Parent->ClientRect.top);
515 IntGdiOffsetRect(&(params.rgrc[1]), - Parent->ClientRect.left,
516 - Parent->ClientRect.top);
517 IntGdiOffsetRect(&(params.rgrc[2]), - Parent->ClientRect.left,
518 - Parent->ClientRect.top);
519 }
520 params.lppos = &winposCopy;
521 winposCopy = *WinPos;
522
523 wvrFlags = co_IntSendMessage(Window->hSelf, WM_NCCALCSIZE, TRUE, (LPARAM) &params);
524
525 /* If the application send back garbage, ignore it */
526 if (params.rgrc[0].left <= params.rgrc[0].right &&
527 params.rgrc[0].top <= params.rgrc[0].bottom)
528 {
529 *ClientRect = params.rgrc[0];
530 if ((Window->Style & WS_CHILD) && Parent)
531 {
532 IntGdiOffsetRect(ClientRect, Parent->ClientRect.left,
533 Parent->ClientRect.top);
534 }
535 FixClientRect(ClientRect, WindowRect);
536 }
537
538 /* FIXME: WVR_ALIGNxxx */
539
540 if (ClientRect->left != Window->ClientRect.left ||
541 ClientRect->top != Window->ClientRect.top)
542 {
543 WinPos->flags &= ~SWP_NOCLIENTMOVE;
544 }
545
546 if ((ClientRect->right - ClientRect->left !=
547 Window->ClientRect.right - Window->ClientRect.left) ||
548 (ClientRect->bottom - ClientRect->top !=
549 Window->ClientRect.bottom - Window->ClientRect.top))
550 {
551 WinPos->flags &= ~SWP_NOCLIENTSIZE;
552 }
553 if(Parent)
554 IntReleaseWindowObject(Parent);
555 }
556 else
557 {
558 if (! (WinPos->flags & SWP_NOMOVE)
559 && (ClientRect->left != Window->ClientRect.left ||
560 ClientRect->top != Window->ClientRect.top))
561 {
562 WinPos->flags &= ~SWP_NOCLIENTMOVE;
563 }
564 }
565
566 return wvrFlags;
567 }
568
569 BOOL FASTCALL
570 co_WinPosDoWinPosChanging(PWINDOW_OBJECT Window,
571 PWINDOWPOS WinPos,
572 PRECT WindowRect,
573 PRECT ClientRect)
574 {
575 INT X, Y;
576
577 if (!(WinPos->flags & SWP_NOSENDCHANGING))
578 {
579 co_IntSendMessage(Window->hSelf, WM_WINDOWPOSCHANGING, 0, (LPARAM) WinPos);
580 }
581
582 *WindowRect = Window->WindowRect;
583 *ClientRect = Window->ClientRect;
584
585 if (!(WinPos->flags & SWP_NOSIZE))
586 {
587 WindowRect->right = WindowRect->left + WinPos->cx;
588 WindowRect->bottom = WindowRect->top + WinPos->cy;
589 }
590
591 if (!(WinPos->flags & SWP_NOMOVE))
592 {
593 PWINDOW_OBJECT Parent;
594 X = WinPos->x;
595 Y = WinPos->y;
596 Parent = IntGetParentObject(Window);
597 if ((0 != (Window->Style & WS_CHILD)) && Parent)
598 {
599 X += Parent->ClientRect.left;
600 Y += Parent->ClientRect.top;
601 }
602 if(Parent)
603 IntReleaseWindowObject(Parent);
604 WindowRect->left = X;
605 WindowRect->top = Y;
606 WindowRect->right += X - Window->WindowRect.left;
607 WindowRect->bottom += Y - Window->WindowRect.top;
608 IntGdiOffsetRect(ClientRect,
609 X - Window->WindowRect.left,
610 Y - Window->WindowRect.top);
611 }
612
613 WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
614
615 return TRUE;
616 }
617
618 /*
619 * Fix Z order taking into account owned popups -
620 * basically we need to maintain them above the window that owns them
621 */
622 HWND FASTCALL
623 WinPosDoOwnedPopups(HWND hWnd, HWND hWndInsertAfter)
624 {
625 HWND *List = NULL;
626 HWND Owner = UserGetWindow(hWnd, GW_OWNER);
627 LONG Style = UserGetWindowLong(hWnd, GWL_STYLE, FALSE);
628 PWINDOW_OBJECT DesktopWindow, ChildObject;
629 int i;
630
631 if ((Style & WS_POPUP) && Owner)
632 {
633 /* Make sure this popup stays above the owner */
634 HWND hWndLocalPrev = HWND_TOPMOST;
635
636 if (hWndInsertAfter != HWND_TOPMOST)
637 {
638 DesktopWindow = IntGetWindowObject(IntGetDesktopWindow());
639 List = IntWinListChildren(DesktopWindow);
640 IntReleaseWindowObject(DesktopWindow);
641 if (List != NULL)
642 {
643 for (i = 0; List[i]; i++)
644 {
645 if (List[i] == Owner) break;
646 if (HWND_TOP == hWndInsertAfter)
647 {
648 ChildObject = IntGetWindowObject(List[i]);
649 if (NULL != ChildObject)
650 {
651 if (0 == (ChildObject->ExStyle & WS_EX_TOPMOST))
652 {
653 IntReleaseWindowObject(ChildObject);
654 break;
655 }
656 IntReleaseWindowObject(ChildObject);
657 }
658 }
659 if (List[i] != hWnd) hWndLocalPrev = List[i];
660 if (hWndLocalPrev == hWndInsertAfter) break;
661 }
662 hWndInsertAfter = hWndLocalPrev;
663 }
664 }
665 }
666 else if (Style & WS_CHILD)
667 {
668 return hWndInsertAfter;
669 }
670
671 if (!List)
672 {
673 DesktopWindow = IntGetWindowObject(IntGetDesktopWindow());
674 List = IntWinListChildren(DesktopWindow);
675 IntReleaseWindowObject(DesktopWindow);
676 }
677 if (List != NULL)
678 {
679 for (i = 0; List[i]; i++)
680 {
681 if (List[i] == hWnd)
682 break;
683 if ((UserGetWindowLong(List[i], GWL_STYLE, FALSE) & WS_POPUP) &&
684 UserGetWindow(List[i], GW_OWNER) == hWnd)
685 {
686 co_WinPosSetWindowPos(List[i], hWndInsertAfter, 0, 0, 0, 0,
687 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
688 hWndInsertAfter = List[i];
689 }
690 }
691 ExFreePool(List);
692 }
693
694 return hWndInsertAfter;
695 }
696
697 /***********************************************************************
698 * WinPosInternalMoveWindow
699 *
700 * Update WindowRect and ClientRect of Window and all of its children
701 * We keep both WindowRect and ClientRect in screen coordinates internally
702 */
703 VOID STATIC FASTCALL
704 WinPosInternalMoveWindow(PWINDOW_OBJECT Window, INT MoveX, INT MoveY)
705 {
706 PWINDOW_OBJECT Child;
707
708 Window->WindowRect.left += MoveX;
709 Window->WindowRect.right += MoveX;
710 Window->WindowRect.top += MoveY;
711 Window->WindowRect.bottom += MoveY;
712
713 Window->ClientRect.left += MoveX;
714 Window->ClientRect.right += MoveX;
715 Window->ClientRect.top += MoveY;
716 Window->ClientRect.bottom += MoveY;
717
718 for(Child = Window->FirstChild; Child; Child = Child->NextSibling)
719 {
720 WinPosInternalMoveWindow(Child, MoveX, MoveY);
721 }
722 }
723
724 /*
725 * WinPosFixupSWPFlags
726 *
727 * Fix redundant flags and values in the WINDOWPOS structure.
728 */
729
730 BOOL FASTCALL
731 WinPosFixupFlags(WINDOWPOS *WinPos, PWINDOW_OBJECT Window)
732 {
733 if (Window->Style & WS_VISIBLE)
734 {
735 WinPos->flags &= ~SWP_SHOWWINDOW;
736 }
737 else
738 {
739 WinPos->flags &= ~SWP_HIDEWINDOW;
740 if (!(WinPos->flags & SWP_SHOWWINDOW))
741 WinPos->flags |= SWP_NOREDRAW;
742 }
743
744 WinPos->cx = max(WinPos->cx, 0);
745 WinPos->cy = max(WinPos->cy, 0);
746
747 /* Check for right size */
748 if (Window->WindowRect.right - Window->WindowRect.left == WinPos->cx &&
749 Window->WindowRect.bottom - Window->WindowRect.top == WinPos->cy)
750 {
751 WinPos->flags |= SWP_NOSIZE;
752 }
753
754 /* Check for right position */
755 if (Window->WindowRect.left == WinPos->x &&
756 Window->WindowRect.top == WinPos->y)
757 {
758 WinPos->flags |= SWP_NOMOVE;
759 }
760
761 if (WinPos->hwnd == UserGetForegroundWindow())
762 {
763 WinPos->flags |= SWP_NOACTIVATE; /* Already active */
764 }
765 else
766 if ((Window->Style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
767 {
768 /* Bring to the top when activating */
769 if (!(WinPos->flags & SWP_NOACTIVATE))
770 {
771 WinPos->flags &= ~SWP_NOZORDER;
772 WinPos->hwndInsertAfter = (0 != (Window->ExStyle & WS_EX_TOPMOST) ?
773 HWND_TOPMOST : HWND_TOP);
774 return TRUE;
775 }
776 }
777
778 /* Check hwndInsertAfter */
779 if (!(WinPos->flags & SWP_NOZORDER))
780 {
781 /* Fix sign extension */
782 if (WinPos->hwndInsertAfter == (HWND)0xffff)
783 {
784 WinPos->hwndInsertAfter = HWND_TOPMOST;
785 }
786 else if (WinPos->hwndInsertAfter == (HWND)0xfffe)
787 {
788 WinPos->hwndInsertAfter = HWND_NOTOPMOST;
789 }
790
791 if (WinPos->hwndInsertAfter == HWND_NOTOPMOST)
792 {
793 WinPos->hwndInsertAfter = HWND_TOP;
794 }
795 else if (HWND_TOP == WinPos->hwndInsertAfter
796 && 0 != (Window->ExStyle & WS_EX_TOPMOST))
797 {
798 /* Keep it topmost when it's already topmost */
799 WinPos->hwndInsertAfter = HWND_TOPMOST;
800 }
801
802 /* hwndInsertAfter must be a sibling of the window */
803 if (HWND_TOPMOST != WinPos->hwndInsertAfter
804 && HWND_TOP != WinPos->hwndInsertAfter
805 && HWND_NOTOPMOST != WinPos->hwndInsertAfter
806 && HWND_BOTTOM != WinPos->hwndInsertAfter)
807 {
808 PWINDOW_OBJECT Parent = IntGetParentObject(Window);
809 if (UserGetAncestor(WinPos->hwndInsertAfter, GA_PARENT) !=
810 (Parent ? Parent->hSelf : NULL))
811 {
812 if(Parent)
813 IntReleaseWindowObject(Parent);
814 return FALSE;
815 }
816 else
817 {
818 if(Parent)
819 IntReleaseWindowObject(Parent);
820 /*
821 * We don't need to change the Z order of hwnd if it's already
822 * inserted after hwndInsertAfter or when inserting hwnd after
823 * itself.
824 */
825 if ((WinPos->hwnd == WinPos->hwndInsertAfter) ||
826 (WinPos->hwnd == UserGetWindow(WinPos->hwndInsertAfter, GW_HWNDNEXT)))
827 {
828 WinPos->flags |= SWP_NOZORDER;
829 }
830 }
831 }
832 }
833
834 return TRUE;
835 }
836
837 /* x and y are always screen relative */
838 BOOLEAN FASTCALL
839 co_WinPosSetWindowPos(HWND Wnd, HWND WndInsertAfter, INT x, INT y, INT cx,
840 INT cy, UINT flags)
841 {
842 PWINDOW_OBJECT Window;
843 WINDOWPOS WinPos;
844 RECT NewWindowRect;
845 RECT NewClientRect;
846 PROSRGNDATA VisRgn;
847 HRGN VisBefore = NULL;
848 HRGN VisAfter = NULL;
849 HRGN DirtyRgn = NULL;
850 HRGN ExposedRgn = NULL;
851 HRGN CopyRgn = NULL;
852 ULONG WvrFlags = 0;
853 RECT OldWindowRect, OldClientRect;
854 int RgnType;
855 HDC Dc;
856 RECT CopyRect;
857 RECT TempRect;
858
859 /* FIXME: Get current active window from active queue. */
860
861 Window = IntGetWindowObject(Wnd);
862 if (!Window)
863 {
864 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
865 return FALSE;
866 }
867
868 /*
869 * Only allow CSRSS to mess with the desktop window
870 */
871 if (Wnd == IntGetDesktopWindow() &&
872 Window->OwnerThread->ThreadsProcess != PsGetCurrentProcess())
873 {
874 IntReleaseWindowObject(Window);
875 return FALSE;
876 }
877
878 WinPos.hwnd = Wnd;
879 WinPos.hwndInsertAfter = WndInsertAfter;
880 WinPos.x = x;
881 WinPos.y = y;
882 WinPos.cx = cx;
883 WinPos.cy = cy;
884 WinPos.flags = flags;
885
886 co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
887
888 /* Fix up the flags. */
889 if (!WinPosFixupFlags(&WinPos, Window))
890 {
891 IntReleaseWindowObject(Window);
892 SetLastWin32Error(ERROR_INVALID_PARAMETER);
893 return FALSE;
894 }
895
896 /* Does the window still exist? */
897 if (!IntIsWindow(WinPos.hwnd))
898 {
899 IntReleaseWindowObject(Window);
900 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
901 return FALSE;
902 }
903
904 if ((WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) !=
905 SWP_NOZORDER &&
906 UserGetAncestor(WinPos.hwnd, GA_PARENT) == IntGetDesktopWindow())
907 {
908 WinPos.hwndInsertAfter = WinPosDoOwnedPopups(WinPos.hwnd, WinPos.hwndInsertAfter);
909 }
910
911 if (!(WinPos.flags & SWP_NOREDRAW))
912 {
913 /* Compute the visible region before the window position is changed */
914 if (!(WinPos.flags & (SWP_NOREDRAW | SWP_SHOWWINDOW)) &&
915 (WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
916 SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
917 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
918 {
919 VisBefore = VIS_ComputeVisibleRegion(Window, FALSE, FALSE, TRUE);
920 VisRgn = NULL;
921
922 if (VisBefore != NULL && (VisRgn = (PROSRGNDATA)RGNDATA_LockRgn(VisBefore)) &&
923 UnsafeIntGetRgnBox(VisRgn, &TempRect) == NULLREGION)
924 {
925 RGNDATA_UnlockRgn(VisRgn);
926 NtGdiDeleteObject(VisBefore);
927 VisBefore = NULL;
928 }
929 else if(VisRgn)
930 {
931 RGNDATA_UnlockRgn(VisRgn);
932 }
933 }
934 }
935
936 WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect);
937
938 /* Relink windows. (also take into account shell window in hwndShellWindow) */
939 if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow())
940 {
941 PWINDOW_OBJECT ParentWindow;
942 PWINDOW_OBJECT Sibling;
943 PWINDOW_OBJECT InsertAfterWindow;
944
945 if ((ParentWindow = IntGetParentObject(Window)))
946 {
947 if (HWND_TOPMOST == WinPos.hwndInsertAfter)
948 {
949 InsertAfterWindow = NULL;
950 }
951 else if (HWND_TOP == WinPos.hwndInsertAfter
952 || HWND_NOTOPMOST == WinPos.hwndInsertAfter)
953 {
954 InsertAfterWindow = NULL;
955 Sibling = ParentWindow->FirstChild;
956 while (NULL != Sibling && 0 != (Sibling->ExStyle & WS_EX_TOPMOST))
957 {
958 InsertAfterWindow = Sibling;
959 Sibling = Sibling->NextSibling;
960 }
961 if (NULL != InsertAfterWindow)
962 {
963 IntReferenceWindowObject(InsertAfterWindow);
964 }
965 }
966 else if (WinPos.hwndInsertAfter == HWND_BOTTOM)
967 {
968 if(ParentWindow->LastChild)
969 {
970 IntReferenceWindowObject(ParentWindow->LastChild);
971 InsertAfterWindow = ParentWindow->LastChild;
972 }
973 else
974 InsertAfterWindow = NULL;
975 }
976 else
977 InsertAfterWindow = IntGetWindowObject(WinPos.hwndInsertAfter);
978 /* Do nothing if hwndInsertAfter is HWND_BOTTOM and Window is already
979 the last window */
980 if (InsertAfterWindow != Window)
981 {
982 IntUnlinkWindow(Window);
983 IntLinkWindow(Window, ParentWindow, InsertAfterWindow);
984 }
985 if (InsertAfterWindow != NULL)
986 IntReleaseWindowObject(InsertAfterWindow);
987 if ((HWND_TOPMOST == WinPos.hwndInsertAfter)
988 || (0 != (Window->ExStyle & WS_EX_TOPMOST)
989 && NULL != Window->PrevSibling
990 && 0 != (Window->PrevSibling->ExStyle & WS_EX_TOPMOST))
991 || (NULL != Window->NextSibling
992 && 0 != (Window->NextSibling->ExStyle & WS_EX_TOPMOST)))
993 {
994 Window->ExStyle |= WS_EX_TOPMOST;
995 }
996 else
997 {
998 Window->ExStyle &= ~ WS_EX_TOPMOST;
999 }
1000
1001 IntReleaseWindowObject(ParentWindow);
1002 }
1003 }
1004
1005 OldWindowRect = Window->WindowRect;
1006 OldClientRect = Window->ClientRect;
1007
1008 if (OldClientRect.bottom - OldClientRect.top ==
1009 NewClientRect.bottom - NewClientRect.top)
1010 {
1011 WvrFlags &= ~WVR_VREDRAW;
1012 }
1013
1014 if (OldClientRect.right - OldClientRect.left ==
1015 NewClientRect.right - NewClientRect.left)
1016 {
1017 WvrFlags &= ~WVR_HREDRAW;
1018 }
1019
1020 /* FIXME: Actually do something with WVR_VALIDRECTS */
1021
1022 if (NewClientRect.left != OldClientRect.left ||
1023 NewClientRect.top != OldClientRect.top)
1024 {
1025 WinPosInternalMoveWindow(Window,
1026 NewClientRect.left - OldClientRect.left,
1027 NewClientRect.top - OldClientRect.top);
1028 }
1029
1030 Window->WindowRect = NewWindowRect;
1031 Window->ClientRect = NewClientRect;
1032
1033 if (!(WinPos.flags & SWP_SHOWWINDOW) && (WinPos.flags & SWP_HIDEWINDOW))
1034 {
1035 /* Clear the update region */
1036 co_UserRedrawWindow(Window, NULL, 0, RDW_VALIDATE | RDW_NOFRAME |
1037 RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
1038 Window->Style &= ~WS_VISIBLE;
1039 }
1040 else if (WinPos.flags & SWP_SHOWWINDOW)
1041 {
1042 Window->Style |= WS_VISIBLE;
1043 }
1044
1045 DceResetActiveDCEs(Window);
1046
1047 if (!(WinPos.flags & SWP_NOREDRAW))
1048 {
1049 /* Determine the new visible region */
1050 VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE, TRUE);
1051 VisRgn = NULL;
1052
1053 if (VisAfter != NULL && (VisRgn = (PROSRGNDATA)RGNDATA_LockRgn(VisAfter)) &&
1054 UnsafeIntGetRgnBox(VisRgn, &TempRect) == NULLREGION)
1055 {
1056 RGNDATA_UnlockRgn(VisRgn);
1057 NtGdiDeleteObject(VisAfter);
1058 VisAfter = NULL;
1059 }
1060 else if(VisRgn)
1061 {
1062 RGNDATA_UnlockRgn(VisRgn);
1063 }
1064
1065 /*
1066 * Determine which pixels can be copied from the old window position
1067 * to the new. Those pixels must be visible in both the old and new
1068 * position. Also, check the class style to see if the windows of this
1069 * class need to be completely repainted on (horizontal/vertical) size
1070 * change.
1071 */
1072 if (VisBefore != NULL && VisAfter != NULL && !(WinPos.flags & SWP_NOCOPYBITS) &&
1073 ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)))
1074 {
1075 CopyRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
1076 RgnType = NtGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
1077
1078 /*
1079 * If this is (also) a window resize, the whole nonclient area
1080 * needs to be repainted. So we limit the copy to the client area,
1081 * 'cause there is no use in copying it (would possibly cause
1082 * "flashing" too). However, if the copy region is already empty,
1083 * we don't have to crop (can't take anything away from an empty
1084 * region...)
1085 */
1086 if (!(WinPos.flags & SWP_NOSIZE) && RgnType != ERROR &&
1087 RgnType != NULLREGION)
1088 {
1089 RECT ORect = OldClientRect;
1090 RECT NRect = NewClientRect;
1091 IntGdiOffsetRect(&ORect, - OldWindowRect.left, - OldWindowRect.top);
1092 IntGdiOffsetRect(&NRect, - NewWindowRect.left, - NewWindowRect.top);
1093 IntGdiIntersectRect(&CopyRect, &ORect, &NRect);
1094 REGION_CropRgn(CopyRgn, CopyRgn, &CopyRect, NULL);
1095 }
1096
1097 /* No use in copying bits which are in the update region. */
1098 if (Window->UpdateRegion != NULL)
1099 {
1100 NtGdiCombineRgn(CopyRgn, CopyRgn, Window->UpdateRegion, RGN_DIFF);
1101 }
1102 if (Window->NCUpdateRegion != NULL)
1103 {
1104 NtGdiCombineRgn(CopyRgn, CopyRgn, Window->NCUpdateRegion, RGN_DIFF);
1105 }
1106
1107 /*
1108 * Now, get the bounding box of the copy region. If it's empty
1109 * there's nothing to copy. Also, it's no use copying bits onto
1110 * themselves.
1111 */
1112 if ((VisRgn = (PROSRGNDATA)RGNDATA_LockRgn(CopyRgn)) &&
1113 UnsafeIntGetRgnBox(VisRgn, &CopyRect) == NULLREGION)
1114 {
1115 /* Nothing to copy, clean up */
1116 RGNDATA_UnlockRgn(VisRgn);
1117 NtGdiDeleteObject(CopyRgn);
1118 CopyRgn = NULL;
1119 }
1120 else if (OldWindowRect.left != NewWindowRect.left ||
1121 OldWindowRect.top != NewWindowRect.top)
1122 {
1123 if(VisRgn)
1124 {
1125 RGNDATA_UnlockRgn(VisRgn);
1126 }
1127 /*
1128 * Small trick here: there is no function to bitblt a region. So
1129 * we set the region as the clipping region, take the bounding box
1130 * of the region and bitblt that. Since nothing outside the clipping
1131 * region is copied, this has the effect of bitblt'ing the region.
1132 *
1133 * Since NtUserGetDCEx takes ownership of the clip region, we need
1134 * to create a copy of CopyRgn and pass that. We need CopyRgn later
1135 */
1136 HRGN ClipRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
1137
1138 NtGdiCombineRgn(ClipRgn, CopyRgn, NULL, RGN_COPY);
1139 Dc = UserGetDCEx(Window, ClipRgn, DCX_WINDOW | DCX_CACHE |
1140 DCX_INTERSECTRGN | DCX_CLIPSIBLINGS);
1141 NtGdiBitBlt(Dc,
1142 CopyRect.left, CopyRect.top, CopyRect.right - CopyRect.left,
1143 CopyRect.bottom - CopyRect.top, Dc,
1144 CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
1145 CopyRect.top + (OldWindowRect.top - NewWindowRect.top), SRCCOPY);
1146 UserReleaseDC(Window, Dc);
1147 IntValidateParent(Window, CopyRgn);
1148 }
1149 else if(VisRgn)
1150 {
1151 RGNDATA_UnlockRgn(VisRgn);
1152 }
1153 }
1154 else
1155 {
1156 CopyRgn = NULL;
1157 }
1158
1159 /* We need to redraw what wasn't visible before */
1160 if (VisAfter != NULL)
1161 {
1162 DirtyRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
1163 if (CopyRgn != NULL)
1164 {
1165 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
1166 }
1167 else
1168 {
1169 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
1170 }
1171 if (RgnType != ERROR && RgnType != NULLREGION)
1172 {
1173 NtGdiOffsetRgn(DirtyRgn,
1174 Window->WindowRect.left - Window->ClientRect.left,
1175 Window->WindowRect.top - Window->ClientRect.top);
1176 co_UserRedrawWindow(Window, NULL, DirtyRgn,
1177 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
1178 }
1179 NtGdiDeleteObject(DirtyRgn);
1180 }
1181
1182 if (CopyRgn != NULL)
1183 {
1184 NtGdiDeleteObject(CopyRgn);
1185 }
1186
1187 /* Expose what was covered before but not covered anymore */
1188 if (VisBefore != NULL)
1189 {
1190 ExposedRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
1191 NtGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
1192 NtGdiOffsetRgn(ExposedRgn, OldWindowRect.left - NewWindowRect.left,
1193 OldWindowRect.top - NewWindowRect.top);
1194 if (VisAfter != NULL)
1195 RgnType = NtGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
1196 else
1197 RgnType = SIMPLEREGION;
1198
1199 if (RgnType != ERROR && RgnType != NULLREGION)
1200 {
1201 co_VIS_WindowLayoutChanged(Window, ExposedRgn);
1202 }
1203 NtGdiDeleteObject(ExposedRgn);
1204 NtGdiDeleteObject(VisBefore);
1205 }
1206
1207 if (VisAfter != NULL)
1208 {
1209 NtGdiDeleteObject(VisAfter);
1210 }
1211
1212 if (!(WinPos.flags & SWP_NOACTIVATE))
1213 {
1214 if ((Window->Style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
1215 {
1216 co_IntSendMessage(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
1217 }
1218 else
1219 {
1220 co_IntSetForegroundWindow(Window);
1221 }
1222 }
1223 }
1224
1225 if ((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
1226 co_IntSendMessage(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
1227
1228 IntReleaseWindowObject(Window);
1229
1230 return TRUE;
1231 }
1232
1233 LRESULT FASTCALL
1234 co_WinPosGetNonClientSize(HWND Wnd, RECT* WindowRect, RECT* ClientRect)
1235 {
1236 LRESULT Result;
1237
1238 *ClientRect = *WindowRect;
1239 Result = co_IntSendMessage(Wnd, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect);
1240
1241 FixClientRect(ClientRect, WindowRect);
1242
1243 return Result;
1244 }
1245
1246 BOOLEAN FASTCALL
1247 co_WinPosShowWindow(HWND Wnd, INT Cmd)
1248 {
1249 BOOLEAN WasVisible;
1250 PWINDOW_OBJECT Window;
1251 NTSTATUS Status;
1252 UINT Swp = 0;
1253 RECT NewPos;
1254 BOOLEAN ShowFlag;
1255 // HRGN VisibleRgn;
1256
1257 Status =
1258 ObmReferenceObjectByHandle(gHandleTable,
1259 Wnd,
1260 otWindow,
1261 (PVOID*)&Window);
1262 if (!NT_SUCCESS(Status))
1263 {
1264 return(FALSE);
1265 }
1266
1267 WasVisible = (Window->Style & WS_VISIBLE) != 0;
1268
1269 switch (Cmd)
1270 {
1271 case SW_HIDE:
1272 {
1273 if (!WasVisible)
1274 {
1275 ObmDereferenceObject(Window);
1276 return(FALSE);
1277 }
1278 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1279 if (Window->hSelf != UserGetActiveWindow())
1280 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1281 break;
1282 }
1283
1284 case SW_SHOWMINNOACTIVE:
1285 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1286 /* Fall through. */
1287 case SW_SHOWMINIMIZED:
1288 Swp |= SWP_SHOWWINDOW;
1289 /* Fall through. */
1290 case SW_MINIMIZE:
1291 {
1292 Swp |= SWP_FRAMECHANGED | SWP_NOACTIVATE;
1293 if (!(Window->Style & WS_MINIMIZE))
1294 {
1295 Swp |= co_WinPosMinMaximize(Window, SW_MINIMIZE, &NewPos);
1296 }
1297 else
1298 {
1299 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1300 }
1301 break;
1302 }
1303
1304 case SW_SHOWMAXIMIZED:
1305 {
1306 Swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1307 if (!(Window->Style & WS_MAXIMIZE))
1308 {
1309 Swp |= co_WinPosMinMaximize(Window, SW_MAXIMIZE, &NewPos);
1310 }
1311 else
1312 {
1313 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1314 }
1315 break;
1316 }
1317
1318 case SW_SHOWNA:
1319 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1320 /* Fall through. */
1321 case SW_SHOW:
1322 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1323 /* Don't activate the topmost window. */
1324 break;
1325
1326 case SW_SHOWNOACTIVATE:
1327 Swp |= SWP_NOZORDER;
1328 /* Fall through. */
1329 case SW_SHOWNORMAL:
1330 case SW_SHOWDEFAULT:
1331 case SW_RESTORE:
1332 Swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1333 if (Window->Style & (WS_MINIMIZE | WS_MAXIMIZE))
1334 {
1335 Swp |= co_WinPosMinMaximize(Window, SW_RESTORE, &NewPos);
1336 }
1337 else
1338 {
1339 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1340 }
1341 break;
1342 }
1343
1344 ShowFlag = (Cmd != SW_HIDE);
1345 if (ShowFlag != WasVisible)
1346 {
1347 co_IntSendMessage(Wnd, WM_SHOWWINDOW, ShowFlag, 0);
1348 /*
1349 * FIXME: Need to check the window wasn't destroyed during the
1350 * window procedure.
1351 */
1352 if (!(Window->Parent))
1353 {
1354 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)Wnd);
1355 }
1356 }
1357
1358 /* We can't activate a child window */
1359 if ((Window->Style & WS_CHILD) &&
1360 !(Window->ExStyle & WS_EX_MDICHILD))
1361 {
1362 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1363 }
1364
1365 co_WinPosSetWindowPos(Window->hSelf, 0 != (Window->ExStyle & WS_EX_TOPMOST)
1366 ? HWND_TOPMOST : HWND_TOP,
1367 NewPos.left, NewPos.top, NewPos.right, NewPos.bottom, LOWORD(Swp));
1368
1369 if (Cmd == SW_HIDE)
1370 {
1371 /* FIXME: This will cause the window to be activated irrespective
1372 * of whether it is owned by the same thread. Has to be done
1373 * asynchronously.
1374 */
1375
1376 if (Window->hSelf == UserGetActiveWindow())
1377 {
1378 co_WinPosActivateOtherWindow(Window);
1379 }
1380
1381 /* Revert focus to parent */
1382 if (Wnd == IntGetThreadFocusWindow() ||
1383 IntIsChildWindow(Wnd, IntGetThreadFocusWindow()))
1384 {
1385 UserSetFocus(Window->Parent);
1386 }
1387
1388 if (!(Window->Parent))
1389 {
1390 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (LPARAM)Wnd);
1391 }
1392 }
1393
1394 /* FIXME: Check for window destruction. */
1395
1396 if ((Window->Flags & WINDOWOBJECT_NEED_SIZE) &&
1397 !(Window->Status & WINDOWSTATUS_DESTROYING))
1398 {
1399 WPARAM wParam = SIZE_RESTORED;
1400
1401 Window->Flags &= ~WINDOWOBJECT_NEED_SIZE;
1402 if (Window->Style & WS_MAXIMIZE)
1403 {
1404 wParam = SIZE_MAXIMIZED;
1405 }
1406 else if (Window->Style & WS_MINIMIZE)
1407 {
1408 wParam = SIZE_MINIMIZED;
1409 }
1410
1411 co_IntSendMessage(Wnd, WM_SIZE, wParam,
1412 MAKELONG(Window->ClientRect.right -
1413 Window->ClientRect.left,
1414 Window->ClientRect.bottom -
1415 Window->ClientRect.top));
1416 co_IntSendMessage(Wnd, WM_MOVE, 0,
1417 MAKELONG(Window->ClientRect.left,
1418 Window->ClientRect.top));
1419 IntEngWindowChanged(Window, WOC_RGN_CLIENT);
1420 }
1421
1422 /* Activate the window if activation is not requested and the window is not minimized */
1423 /*
1424 if (!(Swp & (SWP_NOACTIVATE | SWP_HIDEWINDOW)) && !(Window->Style & WS_MINIMIZE))
1425 {
1426 WinPosChangeActiveWindow(Wnd, FALSE);
1427 }
1428 */
1429
1430 ObmDereferenceObject(Window);
1431 return(WasVisible);
1432 }
1433
1434 STATIC VOID FASTCALL
1435 co_WinPosSearchChildren(
1436 PWINDOW_OBJECT ScopeWin, PUSER_MESSAGE_QUEUE OnlyHitTests, POINT *Point,
1437 PWINDOW_OBJECT* Window, USHORT *HitTest)
1438 {
1439 PWINDOW_OBJECT Current;
1440 HWND *List, *phWnd;
1441
1442 if ((List = IntWinListChildren(ScopeWin)))
1443 {
1444 for (phWnd = List; *phWnd; ++phWnd)
1445 {
1446 if (!(Current = IntGetWindowObject(*phWnd)))
1447 continue;
1448
1449 if (!(Current->Style & WS_VISIBLE))
1450 {
1451 IntReleaseWindowObject(Current);
1452 continue;
1453 }
1454
1455 if ((Current->Style & (WS_POPUP | WS_CHILD | WS_DISABLED)) ==
1456 (WS_CHILD | WS_DISABLED))
1457 {
1458 IntReleaseWindowObject(Current);
1459 continue;
1460 }
1461
1462 if (!IntPtInWindow(Current, Point->x, Point->y))
1463 {
1464 IntReleaseWindowObject(Current);
1465 continue;
1466 }
1467
1468 if (*Window)
1469 IntReleaseWindowObject(*Window);
1470 *Window = Current;
1471
1472 if (Current->Style & WS_MINIMIZE)
1473 {
1474 *HitTest = HTCAPTION;
1475 break;
1476 }
1477
1478 if (Current->Style & WS_DISABLED)
1479 {
1480 *HitTest = HTERROR;
1481 break;
1482 }
1483
1484 if (OnlyHitTests && (Current->MessageQueue == OnlyHitTests))
1485 {
1486 *HitTest = co_IntSendMessage(Current->hSelf, WM_NCHITTEST, 0,
1487 MAKELONG(Point->x, Point->y));
1488 if ((*HitTest) == (USHORT)HTTRANSPARENT)
1489 continue;
1490 }
1491 else
1492 *HitTest = HTCLIENT;
1493
1494 if (Point->x >= Current->ClientRect.left &&
1495 Point->x < Current->ClientRect.right &&
1496 Point->y >= Current->ClientRect.top &&
1497 Point->y < Current->ClientRect.bottom)
1498 {
1499 co_WinPosSearchChildren(Current, OnlyHitTests, Point, Window, HitTest);
1500 }
1501
1502 break;
1503 }
1504 ExFreePool(List);
1505 }
1506 }
1507
1508 USHORT FASTCALL
1509 co_WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin, PUSER_MESSAGE_QUEUE OnlyHitTests, POINT *WinPoint,
1510 PWINDOW_OBJECT* Window)
1511 {
1512 HWND DesktopWindowHandle;
1513 PWINDOW_OBJECT DesktopWindow;
1514 POINT Point = *WinPoint;
1515 USHORT HitTest;
1516
1517 *Window = NULL;
1518
1519 if(!ScopeWin)
1520 {
1521 DPRINT1("WinPosWindowFromPoint(): ScopeWin == NULL!\n");
1522 return(HTERROR);
1523 }
1524
1525 if (ScopeWin->Style & WS_DISABLED)
1526 {
1527 return(HTERROR);
1528 }
1529
1530 /* Translate the point to the space of the scope window. */
1531 DesktopWindowHandle = IntGetDesktopWindow();
1532 if((DesktopWindowHandle != ScopeWin->hSelf) &&
1533 (DesktopWindow = IntGetWindowObject(DesktopWindowHandle)))
1534 {
1535 Point.x += ScopeWin->ClientRect.left - DesktopWindow->ClientRect.left;
1536 Point.y += ScopeWin->ClientRect.top - DesktopWindow->ClientRect.top;
1537 IntReleaseWindowObject(DesktopWindow);
1538 }
1539
1540 HitTest = HTNOWHERE;
1541
1542 co_WinPosSearchChildren(ScopeWin, OnlyHitTests, &Point, Window, &HitTest);
1543
1544 return ((*Window) ? HitTest : HTNOWHERE);
1545 }
1546
1547 BOOL
1548 STDCALL
1549 NtUserGetMinMaxInfo(
1550 HWND hwnd,
1551 MINMAXINFO *MinMaxInfo,
1552 BOOL SendMessage)
1553 {
1554 POINT Size;
1555 PINTERNALPOS InternalPos;
1556 PWINDOW_OBJECT Window;
1557 MINMAXINFO SafeMinMax;
1558 NTSTATUS Status;
1559 DECLARE_RETURN(BOOL);
1560
1561 DPRINT("Enter NtUserGetMinMaxInfo\n");
1562 UserEnterExclusive();
1563
1564 Window = IntGetWindowObject(hwnd);
1565 if(!Window)
1566 {
1567 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1568 RETURN( FALSE);
1569 }
1570
1571 Size.x = Window->WindowRect.left;
1572 Size.y = Window->WindowRect.top;
1573 InternalPos = WinPosInitInternalPos(Window, &Size,
1574 &Window->WindowRect);
1575 if(InternalPos)
1576 {
1577 if(SendMessage)
1578 {
1579 co_WinPosGetMinMaxInfo(Window, &SafeMinMax.ptMaxSize, &SafeMinMax.ptMaxPosition,
1580 &SafeMinMax.ptMinTrackSize, &SafeMinMax.ptMaxTrackSize);
1581 }
1582 else
1583 {
1584 WinPosFillMinMaxInfoStruct(Window, &SafeMinMax);
1585 }
1586 Status = MmCopyToCaller(MinMaxInfo, &SafeMinMax, sizeof(MINMAXINFO));
1587 if(!NT_SUCCESS(Status))
1588 {
1589 IntReleaseWindowObject(Window);
1590 SetLastNtError(Status);
1591 RETURN( FALSE);
1592 }
1593 IntReleaseWindowObject(Window);
1594 RETURN( TRUE);
1595 }
1596
1597 IntReleaseWindowObject(Window);
1598 RETURN( FALSE);
1599
1600 CLEANUP:
1601 DPRINT("Leave NtUserGetMinMaxInfo, ret=%i\n",_ret_);
1602 UserLeave();
1603 END_CLEANUP;
1604 }
1605
1606 /* EOF */