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