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