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