[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)RGNOBJAPI_Lock(VisBefore, NULL)) &&
957 REGION_GetRgnBox(VisRgn, &TempRect) == NULLREGION)
958 {
959 RGNOBJAPI_Unlock(VisRgn);
960 GreDeleteObject(VisBefore);
961 VisBefore = NULL;
962 }
963 else if(VisRgn)
964 {
965 RGNOBJAPI_Unlock(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->spwndChild)
1006 {
1007 InsertAfterWindow = ParentWindow->spwndChild;
1008
1009 if(InsertAfterWindow)
1010 {
1011 while (InsertAfterWindow->spwndNext)
1012 InsertAfterWindow = InsertAfterWindow->spwndNext;
1013 }
1014
1015 UserReferenceObject(InsertAfterWindow);
1016 }
1017 else
1018 InsertAfterWindow = NULL;
1019 }
1020 else
1021 InsertAfterWindow = IntGetWindowObject(WinPos.hwndInsertAfter);
1022 /* Do nothing if hwndInsertAfter is HWND_BOTTOM and Window is already
1023 the last window */
1024 if (InsertAfterWindow != Window)
1025 {
1026 IntUnlinkWindow(Window);
1027 IntLinkWindow(Window, ParentWindow, InsertAfterWindow);
1028 }
1029 if (InsertAfterWindow != NULL)
1030 UserDereferenceObject(InsertAfterWindow);
1031 if ((HWND_TOPMOST == WinPos.hwndInsertAfter)
1032 || (0 != (Window->Wnd->ExStyle & WS_EX_TOPMOST)
1033 && NULL != Window->spwndPrev
1034 && 0 != (Window->spwndPrev->Wnd->ExStyle & WS_EX_TOPMOST))
1035 || (NULL != Window->spwndNext
1036 && 0 != (Window->spwndNext->Wnd->ExStyle & WS_EX_TOPMOST)))
1037 {
1038 Window->Wnd->ExStyle |= WS_EX_TOPMOST;
1039 }
1040 else
1041 {
1042 Window->Wnd->ExStyle &= ~ WS_EX_TOPMOST;
1043 }
1044
1045 }
1046 }
1047
1048 if (!Window->Wnd) return FALSE;
1049
1050 OldWindowRect = Window->Wnd->rcWindow;
1051 OldClientRect = Window->Wnd->rcClient;
1052
1053 if (OldClientRect.bottom - OldClientRect.top ==
1054 NewClientRect.bottom - NewClientRect.top)
1055 {
1056 WvrFlags &= ~WVR_VREDRAW;
1057 }
1058
1059 if (OldClientRect.right - OldClientRect.left ==
1060 NewClientRect.right - NewClientRect.left)
1061 {
1062 WvrFlags &= ~WVR_HREDRAW;
1063 }
1064
1065 /* FIXME: Actually do something with WVR_VALIDRECTS */
1066
1067 if (NewClientRect.left != OldClientRect.left ||
1068 NewClientRect.top != OldClientRect.top)
1069 {
1070 WinPosInternalMoveWindow(Window,
1071 NewClientRect.left - OldClientRect.left,
1072 NewClientRect.top - OldClientRect.top);
1073 }
1074
1075 Window->Wnd->rcWindow = NewWindowRect;
1076 Window->Wnd->rcClient = NewClientRect;
1077
1078 if (!(WinPos.flags & SWP_SHOWWINDOW) && (WinPos.flags & SWP_HIDEWINDOW))
1079 {
1080 /* Clear the update region */
1081 co_UserRedrawWindow(Window, NULL, 0, RDW_VALIDATE | RDW_NOFRAME |
1082 RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
1083 if ((Window->Wnd->style & WS_VISIBLE) &&
1084 Window->spwndParent == UserGetDesktopWindow())
1085 {
1086 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (LPARAM)Window->hSelf);
1087 }
1088 Window->Wnd->style &= ~WS_VISIBLE;
1089 }
1090 else if (WinPos.flags & SWP_SHOWWINDOW)
1091 {
1092 if (!(Window->Wnd->style & WS_VISIBLE) &&
1093 Window->spwndParent == UserGetDesktopWindow())
1094 {
1095 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)Window->hSelf);
1096 }
1097 Window->Wnd->style |= WS_VISIBLE;
1098 }
1099
1100 if (Window->UpdateRegion != NULL && Window->UpdateRegion != (HRGN)1)
1101 {
1102 NtGdiOffsetRgn(Window->UpdateRegion,
1103 NewWindowRect.left - OldWindowRect.left,
1104 NewWindowRect.top - OldWindowRect.top);
1105 }
1106
1107 DceResetActiveDCEs(Window);
1108
1109 if (!(WinPos.flags & SWP_NOREDRAW))
1110 {
1111 /* Determine the new visible region */
1112 VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE, TRUE);
1113 VisRgn = NULL;
1114
1115 if (VisAfter != NULL && (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisAfter, NULL)) &&
1116 REGION_GetRgnBox(VisRgn, &TempRect) == NULLREGION)
1117 {
1118 RGNOBJAPI_Unlock(VisRgn);
1119 GreDeleteObject(VisAfter);
1120 VisAfter = NULL;
1121 }
1122 else if(VisRgn)
1123 {
1124 RGNOBJAPI_Unlock(VisRgn);
1125 NtGdiOffsetRgn(VisAfter, -Window->Wnd->rcWindow.left, -Window->Wnd->rcWindow.top);
1126 }
1127
1128 /*
1129 * Determine which pixels can be copied from the old window position
1130 * to the new. Those pixels must be visible in both the old and new
1131 * position. Also, check the class style to see if the windows of this
1132 * class need to be completely repainted on (horizontal/vertical) size
1133 * change.
1134 */
1135 if (VisBefore != NULL && VisAfter != NULL && !(WinPos.flags & SWP_NOCOPYBITS) &&
1136 ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) &&
1137 !(Window->Wnd->ExStyle & WS_EX_TRANSPARENT))
1138 {
1139 CopyRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
1140 RgnType = NtGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
1141
1142 /*
1143 * If this is (also) a window resize, the whole nonclient area
1144 * needs to be repainted. So we limit the copy to the client area,
1145 * 'cause there is no use in copying it (would possibly cause
1146 * "flashing" too). However, if the copy region is already empty,
1147 * we don't have to crop (can't take anything away from an empty
1148 * region...)
1149 */
1150 if (!(WinPos.flags & SWP_NOSIZE) && RgnType != ERROR &&
1151 RgnType != NULLREGION)
1152 {
1153 PROSRGNDATA pCopyRgn;
1154 RECTL ORect = OldClientRect;
1155 RECTL NRect = NewClientRect;
1156 RECTL_vOffsetRect(&ORect, - OldWindowRect.left, - OldWindowRect.top);
1157 RECTL_vOffsetRect(&NRect, - NewWindowRect.left, - NewWindowRect.top);
1158 RECTL_bIntersectRect(&CopyRect, &ORect, &NRect);
1159 pCopyRgn = RGNOBJAPI_Lock(CopyRgn, NULL);
1160 REGION_CropAndOffsetRegion(pCopyRgn, pCopyRgn, &CopyRect, NULL);
1161 RGNOBJAPI_Unlock(pCopyRgn);
1162 }
1163
1164 /* No use in copying bits which are in the update region. */
1165 if (Window->UpdateRegion != NULL)
1166 {
1167 NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1168 NtGdiCombineRgn(CopyRgn, CopyRgn, Window->UpdateRegion, RGN_DIFF);
1169 NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1170 }
1171
1172 /*
1173 * Now, get the bounding box of the copy region. If it's empty
1174 * there's nothing to copy. Also, it's no use copying bits onto
1175 * themselves.
1176 */
1177 if ((VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(CopyRgn, NULL)) &&
1178 REGION_GetRgnBox(VisRgn, &CopyRect) == NULLREGION)
1179 {
1180 /* Nothing to copy, clean up */
1181 RGNOBJAPI_Unlock(VisRgn);
1182 GreDeleteObject(CopyRgn);
1183 CopyRgn = NULL;
1184 }
1185 else if (OldWindowRect.left != NewWindowRect.left ||
1186 OldWindowRect.top != NewWindowRect.top)
1187 {
1188 if(VisRgn)
1189 {
1190 RGNOBJAPI_Unlock(VisRgn);
1191 }
1192
1193 /*
1194 * Small trick here: there is no function to bitblt a region. So
1195 * we set the region as the clipping region, take the bounding box
1196 * of the region and bitblt that. Since nothing outside the clipping
1197 * region is copied, this has the effect of bitblt'ing the region.
1198 *
1199 * Since NtUserGetDCEx takes ownership of the clip region, we need
1200 * to create a copy of CopyRgn and pass that. We need CopyRgn later
1201 */
1202 NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1203 Dc = UserGetDCEx(Window, CopyRgn, DCX_WINDOW | DCX_CACHE |
1204 DCX_INTERSECTRGN | DCX_CLIPSIBLINGS |
1205 DCX_KEEPCLIPRGN);
1206 NtGdiBitBlt(Dc,
1207 CopyRect.left, CopyRect.top, CopyRect.right - CopyRect.left,
1208 CopyRect.bottom - CopyRect.top, Dc,
1209 CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
1210 CopyRect.top + (OldWindowRect.top - NewWindowRect.top), SRCCOPY, 0, 0);
1211 UserReleaseDC(Window, Dc, FALSE);
1212 IntValidateParent(Window, CopyRgn, FALSE);
1213 NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1214 }
1215 else if(VisRgn)
1216 {
1217 RGNOBJAPI_Unlock(VisRgn);
1218 }
1219 }
1220 else
1221 {
1222 CopyRgn = NULL;
1223 }
1224
1225 /* We need to redraw what wasn't visible before */
1226 if (VisAfter != NULL)
1227 {
1228 DirtyRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
1229 if (CopyRgn != NULL)
1230 {
1231 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
1232 }
1233 else
1234 {
1235 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
1236 }
1237 if (RgnType != ERROR && RgnType != NULLREGION)
1238 {
1239 /* old code
1240 NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
1241 IntInvalidateWindows(Window, DirtyRgn,
1242 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
1243 }
1244 GreDeleteObject(DirtyRgn);
1245 */
1246
1247 PWINDOW_OBJECT Parent = Window->spwndParent;
1248
1249 NtGdiOffsetRgn(DirtyRgn,
1250 Window->Wnd->rcWindow.left,
1251 Window->Wnd->rcWindow.top);
1252 if ((Window->Wnd->style & WS_CHILD) &&
1253 (Parent) &&
1254 !(Parent->Wnd->style & WS_CLIPCHILDREN))
1255 {
1256 IntInvalidateWindows(Parent, DirtyRgn,
1257 RDW_ERASE | RDW_INVALIDATE);
1258 co_IntPaintWindows(Parent, RDW_ERASENOW, FALSE);
1259 }
1260 else
1261 {
1262 IntInvalidateWindows(Window, DirtyRgn,
1263 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
1264 }
1265 }
1266 GreDeleteObject(DirtyRgn);
1267 }
1268
1269 if (CopyRgn != NULL)
1270 {
1271 GreDeleteObject(CopyRgn);
1272 }
1273
1274 /* Expose what was covered before but not covered anymore */
1275 if (VisBefore != NULL)
1276 {
1277 ExposedRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
1278 NtGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
1279 NtGdiOffsetRgn(ExposedRgn, OldWindowRect.left - NewWindowRect.left,
1280 OldWindowRect.top - NewWindowRect.top);
1281 if (VisAfter != NULL)
1282 RgnType = NtGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
1283 else
1284 RgnType = SIMPLEREGION;
1285
1286 if (RgnType != ERROR && RgnType != NULLREGION)
1287 {
1288 co_VIS_WindowLayoutChanged(Window, ExposedRgn);
1289 }
1290 GreDeleteObject(ExposedRgn);
1291 GreDeleteObject(VisBefore);
1292 }
1293
1294 if (VisAfter != NULL)
1295 {
1296 GreDeleteObject(VisAfter);
1297 }
1298
1299 if (!(WinPos.flags & SWP_NOACTIVATE))
1300 {
1301 if ((Window->Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
1302 {
1303 co_IntSendMessage(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
1304 }
1305 else
1306 {
1307 co_IntSetForegroundWindow(Window);
1308 }
1309 }
1310 }
1311
1312 if ((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
1313 co_IntPostOrSendMessage(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
1314
1315 return TRUE;
1316 }
1317
1318 LRESULT FASTCALL
1319 co_WinPosGetNonClientSize(PWINDOW_OBJECT Window, RECT* WindowRect, RECT* ClientRect)
1320 {
1321 LRESULT Result;
1322
1323 ASSERT_REFS_CO(Window);
1324
1325 *ClientRect = *WindowRect;
1326 Result = co_IntSendMessage(Window->hSelf, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect);
1327
1328 FixClientRect(ClientRect, WindowRect);
1329
1330 return Result;
1331 }
1332
1333 BOOLEAN FASTCALL
1334 co_WinPosShowWindow(PWINDOW_OBJECT Window, INT Cmd)
1335 {
1336 BOOLEAN WasVisible;
1337 UINT Swp = 0;
1338 RECTL NewPos;
1339 BOOLEAN ShowFlag;
1340 // HRGN VisibleRgn;
1341 PWND Wnd;
1342
1343 ASSERT_REFS_CO(Window);
1344 Wnd = Window->Wnd;
1345
1346 if (!Wnd) return FALSE;
1347
1348 WasVisible = (Wnd->style & WS_VISIBLE) != 0;
1349
1350 switch (Cmd)
1351 {
1352 case SW_HIDE:
1353 {
1354 if (!WasVisible)
1355 {
1356 return(FALSE);
1357 }
1358 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1359 if (Window->hSelf != UserGetActiveWindow())
1360 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1361 break;
1362 }
1363
1364 case SW_SHOWMINNOACTIVE:
1365 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1366 /* Fall through. */
1367 case SW_SHOWMINIMIZED:
1368 Swp |= SWP_SHOWWINDOW;
1369 /* Fall through. */
1370 case SW_MINIMIZE:
1371 {
1372 Swp |= SWP_NOACTIVATE;
1373 if (!(Wnd->style & WS_MINIMIZE))
1374 {
1375 Swp |= co_WinPosMinMaximize(Window, SW_MINIMIZE, &NewPos) |
1376 SWP_FRAMECHANGED;
1377 }
1378 else
1379 {
1380 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1381 if (! WasVisible)
1382 {
1383 Swp |= SWP_FRAMECHANGED;
1384 }
1385 }
1386 break;
1387 }
1388
1389 case SW_SHOWMAXIMIZED:
1390 {
1391 Swp |= SWP_SHOWWINDOW;
1392 if (!(Wnd->style & WS_MAXIMIZE))
1393 {
1394 Swp |= co_WinPosMinMaximize(Window, SW_MAXIMIZE, &NewPos) |
1395 SWP_FRAMECHANGED;
1396 }
1397 else
1398 {
1399 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1400 if (! WasVisible)
1401 {
1402 Swp |= SWP_FRAMECHANGED;
1403 }
1404 }
1405 break;
1406 }
1407
1408 case SW_SHOWNA:
1409 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1410 /* Fall through. */
1411 case SW_SHOW:
1412 if (WasVisible) return(TRUE); // Nothing to do!
1413 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1414 /* Don't activate the topmost window. */
1415 break;
1416
1417 case SW_SHOWNOACTIVATE:
1418 //Swp |= SWP_NOZORDER;
1419 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1420 /* Fall through. */
1421 case SW_SHOWNORMAL:
1422 case SW_SHOWDEFAULT:
1423 case SW_RESTORE:
1424 Swp |= SWP_SHOWWINDOW;
1425 if (Wnd->style & (WS_MINIMIZE | WS_MAXIMIZE))
1426 {
1427 Swp |= co_WinPosMinMaximize(Window, SW_RESTORE, &NewPos) |
1428 SWP_FRAMECHANGED;
1429 }
1430 else
1431 {
1432 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1433 if (! WasVisible)
1434 {
1435 Swp |= SWP_FRAMECHANGED;
1436 }
1437 }
1438 break;
1439 }
1440
1441 ShowFlag = (Cmd != SW_HIDE);
1442
1443 if (ShowFlag != WasVisible)
1444 {
1445 co_IntSendMessage(Window->hSelf, WM_SHOWWINDOW, ShowFlag, 0);
1446 }
1447
1448 /* We can't activate a child window */
1449 if ((Wnd->style & WS_CHILD) &&
1450 !(Wnd->ExStyle & WS_EX_MDICHILD))
1451 {
1452 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1453 }
1454
1455 co_WinPosSetWindowPos(Window, 0 != (Wnd->ExStyle & WS_EX_TOPMOST)
1456 ? HWND_TOPMOST : HWND_TOP,
1457 NewPos.left, NewPos.top, NewPos.right, NewPos.bottom, LOWORD(Swp));
1458
1459 if (Cmd == SW_HIDE)
1460 {
1461 PWINDOW_OBJECT ThreadFocusWindow;
1462
1463 /* FIXME: This will cause the window to be activated irrespective
1464 * of whether it is owned by the same thread. Has to be done
1465 * asynchronously.
1466 */
1467
1468 if (Window->hSelf == UserGetActiveWindow())
1469 {
1470 co_WinPosActivateOtherWindow(Window);
1471 }
1472
1473
1474 //temphack
1475 ThreadFocusWindow = UserGetWindowObject(IntGetThreadFocusWindow());
1476
1477 /* Revert focus to parent */
1478 if (ThreadFocusWindow && (Window == ThreadFocusWindow ||
1479 IntIsChildWindow(Window, ThreadFocusWindow)))
1480 {
1481 //faxme: as long as we have ref on Window, we also, indirectly, have ref on parent...
1482 co_UserSetFocus(Window->spwndParent);
1483 }
1484 }
1485
1486 /* FIXME: Check for window destruction. */
1487
1488 if ((Window->state & WINDOWOBJECT_NEED_SIZE) &&
1489 !(Window->state & WINDOWSTATUS_DESTROYING))
1490 {
1491 WPARAM wParam = SIZE_RESTORED;
1492
1493 Window->state &= ~WINDOWOBJECT_NEED_SIZE;
1494 if (Wnd->style & WS_MAXIMIZE)
1495 {
1496 wParam = SIZE_MAXIMIZED;
1497 }
1498 else if (Wnd->style & WS_MINIMIZE)
1499 {
1500 wParam = SIZE_MINIMIZED;
1501 }
1502
1503 co_IntSendMessage(Window->hSelf, WM_SIZE, wParam,
1504 MAKELONG(Wnd->rcClient.right -
1505 Wnd->rcClient.left,
1506 Wnd->rcClient.bottom -
1507 Wnd->rcClient.top));
1508 co_IntSendMessage(Window->hSelf, WM_MOVE, 0,
1509 MAKELONG(Wnd->rcClient.left,
1510 Wnd->rcClient.top));
1511 IntEngWindowChanged(Window, WOC_RGN_CLIENT);
1512
1513 }
1514
1515 /* Activate the window if activation is not requested and the window is not minimized */
1516 /*
1517 if (!(Swp & (SWP_NOACTIVATE | SWP_HIDEWINDOW)) && !(Window->style & WS_MINIMIZE))
1518 {
1519 WinPosChangeActiveWindow(Wnd, FALSE);
1520 }
1521 */
1522 return(WasVisible);
1523 }
1524
1525
1526 #if 0
1527
1528 /* find child of 'parent' that contains the given point (in parent-relative coords) */
1529 PWINDOW_OBJECT child_window_from_point(PWINDOW_OBJECT parent, int x, int y )
1530 {
1531 PWINDOW_OBJECT Wnd;// = parent->spwndChild;
1532
1533 // LIST_FOR_EACH_ENTRY( Wnd, &parent->children, struct window, entry )
1534 for (Wnd = parent->spwndChild; Wnd; Wnd = Wnd->spwndNext)
1535 {
1536 if (!IntPtInWindow( Wnd, x, y )) continue; /* skip it */
1537
1538 /* if window is minimized or disabled, return at once */
1539 if (Wnd->style & (WS_MINIMIZE|WS_DISABLED)) return Wnd;
1540
1541 /* if point is not in client area, return at once */
1542 if (x < Wnd->rcClient.left || x >= Wnd->rcClient.right ||
1543 y < Wnd->rcClient.top || y >= Wnd->rcClient.bottom)
1544 return Wnd;
1545
1546 return child_window_from_point( Wnd, x - Wnd->rcClient.left, y - Wnd->rcClient.top );
1547 }
1548 return parent; /* not found any child */
1549 }
1550 #endif
1551
1552 /* wine server: child_window_from_point
1553
1554 Caller must dereference the "returned" Window
1555 */
1556 static
1557 VOID FASTCALL
1558 co_WinPosSearchChildren(
1559 PWINDOW_OBJECT ScopeWin,
1560 PUSER_MESSAGE_QUEUE OnlyHitTests,
1561 POINT *Point,
1562 PWINDOW_OBJECT* Window,
1563 USHORT *HitTest
1564 )
1565 {
1566 PWINDOW_OBJECT Current;
1567 PWND CurrentWnd;
1568 HWND *List, *phWnd;
1569 USER_REFERENCE_ENTRY Ref;
1570
1571 ASSERT_REFS_CO(ScopeWin);
1572
1573 if ((List = IntWinListChildren(ScopeWin)))
1574 {
1575 for (phWnd = List; *phWnd; ++phWnd)
1576 {
1577 if (!(Current = UserGetWindowObject(*phWnd)))
1578 continue;
1579 CurrentWnd = Current->Wnd;
1580
1581 if (!(CurrentWnd->style & WS_VISIBLE))
1582 {
1583 continue;
1584 }
1585
1586 if ((CurrentWnd->style & (WS_POPUP | WS_CHILD | WS_DISABLED)) ==
1587 (WS_CHILD | WS_DISABLED))
1588 {
1589 continue;
1590 }
1591
1592 if (!IntPtInWindow(Current, Point->x, Point->y))
1593 {
1594 continue;
1595 }
1596
1597 if (*Window) UserDereferenceObject(*Window);
1598 *Window = Current;
1599 UserReferenceObject(*Window);
1600
1601 if (CurrentWnd->style & WS_MINIMIZE)
1602 {
1603 *HitTest = HTCAPTION;
1604 break;
1605 }
1606
1607 if (CurrentWnd->style & WS_DISABLED)
1608 {
1609 *HitTest = HTERROR;
1610 break;
1611 }
1612
1613 UserRefObjectCo(Current, &Ref);
1614
1615 if (OnlyHitTests && (Current->MessageQueue == OnlyHitTests))
1616 {
1617 *HitTest = co_IntSendMessage(Current->hSelf, WM_NCHITTEST, 0,
1618 MAKELONG(Point->x, Point->y));
1619 if ((*HitTest) == (USHORT)HTTRANSPARENT)
1620 {
1621 UserDerefObjectCo(Current);
1622 continue;
1623 }
1624 }
1625 else
1626 *HitTest = HTCLIENT;
1627
1628 if (Point->x >= CurrentWnd->rcClient.left &&
1629 Point->x < CurrentWnd->rcClient.right &&
1630 Point->y >= CurrentWnd->rcClient.top &&
1631 Point->y < CurrentWnd->rcClient.bottom)
1632 {
1633 co_WinPosSearchChildren(Current, OnlyHitTests, Point, Window, HitTest);
1634 }
1635
1636 UserDerefObjectCo(Current);
1637
1638 break;
1639 }
1640 ExFreePool(List);
1641 }
1642 }
1643
1644 /* wine: WINPOS_WindowFromPoint */
1645 USHORT FASTCALL
1646 co_WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin, PUSER_MESSAGE_QUEUE OnlyHitTests, POINT *WinPoint,
1647 PWINDOW_OBJECT* Window)
1648 {
1649 HWND DesktopWindowHandle;
1650 PWINDOW_OBJECT DesktopWindow;
1651 POINT Point = *WinPoint;
1652 USHORT HitTest;
1653
1654 ASSERT_REFS_CO(ScopeWin);
1655
1656 *Window = NULL;
1657
1658 if(!ScopeWin)
1659 {
1660 DPRINT1("WinPosWindowFromPoint(): ScopeWin == NULL!\n");
1661 return(HTERROR);
1662 }
1663
1664 if (ScopeWin->Wnd->style & WS_DISABLED)
1665 {
1666 return(HTERROR);
1667 }
1668
1669 /* Translate the point to the space of the scope window. */
1670 DesktopWindowHandle = IntGetDesktopWindow();
1671 if((DesktopWindowHandle != ScopeWin->hSelf) &&
1672 (DesktopWindow = UserGetWindowObject(DesktopWindowHandle)))
1673 {
1674 Point.x += ScopeWin->Wnd->rcClient.left - DesktopWindow->Wnd->rcClient.left;
1675 Point.y += ScopeWin->Wnd->rcClient.top - DesktopWindow->Wnd->rcClient.top;
1676 }
1677
1678 HitTest = HTNOWHERE;
1679
1680 co_WinPosSearchChildren(ScopeWin, OnlyHitTests, &Point, Window, &HitTest);
1681
1682 return ((*Window) ? HitTest : HTNOWHERE);
1683 }
1684
1685 BOOL
1686 APIENTRY
1687 NtUserGetMinMaxInfo(
1688 HWND hWnd,
1689 MINMAXINFO *MinMaxInfo,
1690 BOOL SendMessage)
1691 {
1692 POINT Size;
1693 PWINDOW_OBJECT Window = NULL;
1694 PWND Wnd;
1695 MINMAXINFO SafeMinMax;
1696 NTSTATUS Status;
1697 BOOL ret;
1698 USER_REFERENCE_ENTRY Ref;
1699
1700 DPRINT("Enter NtUserGetMinMaxInfo\n");
1701 UserEnterExclusive();
1702
1703 if(!(Window = UserGetWindowObject(hWnd)))
1704 {
1705 ret = FALSE;
1706 goto cleanup;
1707 }
1708
1709 UserRefObjectCo(Window, &Ref);
1710 Wnd = Window->Wnd;
1711
1712 Size.x = Window->Wnd->rcWindow.left;
1713 Size.y = Window->Wnd->rcWindow.top;
1714 WinPosInitInternalPos(Window, &Size,
1715 &Wnd->rcWindow);
1716
1717 if(SendMessage)
1718 {
1719 co_WinPosGetMinMaxInfo(Window, &SafeMinMax.ptMaxSize, &SafeMinMax.ptMaxPosition,
1720 &SafeMinMax.ptMinTrackSize, &SafeMinMax.ptMaxTrackSize);
1721 }
1722 else
1723 {
1724 WinPosFillMinMaxInfoStruct(Window, &SafeMinMax);
1725 }
1726 Status = MmCopyToCaller(MinMaxInfo, &SafeMinMax, sizeof(MINMAXINFO));
1727 if(!NT_SUCCESS(Status))
1728 {
1729 SetLastNtError(Status);
1730 ret = FALSE;
1731 goto cleanup;
1732 }
1733
1734 ret = TRUE;
1735
1736 cleanup:
1737 if (Window) UserDerefObjectCo(Window);
1738
1739 DPRINT("Leave NtUserGetMinMaxInfo, ret=%i\n", ret);
1740 UserLeave();
1741 return ret;
1742 }
1743
1744 /* EOF */