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