Try harder to find another window to activate, fixes bug #127
[reactos.git] / reactos / subsys / win32k / ntuser / winpos.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: winpos.c,v 1.79 2004/01/12 22:26:00 gvg Exp $
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 <ddk/ntddk.h>
32 #include <internal/safe.h>
33 #include <win32k/win32k.h>
34 #include <include/object.h>
35 #include <include/guicheck.h>
36 #include <include/window.h>
37 #include <include/class.h>
38 #include <include/error.h>
39 #include <include/winsta.h>
40 #include <include/desktop.h>
41 #include <include/winpos.h>
42 #include <include/rect.h>
43 #include <include/callback.h>
44 #include <include/painting.h>
45 #include <include/dce.h>
46 #include <include/vis.h>
47 #include <include/focus.h>
48
49 #define NDEBUG
50 #include <debug.h>
51
52 /* GLOBALS *******************************************************************/
53
54 #define MINMAX_NOSWP (0x00010000)
55
56 #define SWP_EX_NOCOPY 0x0001
57 #define SWP_EX_PAINTSELF 0x0002
58
59 #define SWP_AGG_NOGEOMETRYCHANGE \
60 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
61 #define SWP_AGG_NOPOSCHANGE \
62 (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
63 #define SWP_AGG_STATUSFLAGS \
64 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
65
66 /* FUNCTIONS *****************************************************************/
67
68 #define HAS_DLGFRAME(Style, ExStyle) \
69 (((ExStyle) & WS_EX_DLGMODALFRAME) || \
70 (((Style) & WS_DLGFRAME) && (!((Style) & WS_THICKFRAME))))
71
72 #define HAS_THICKFRAME(Style, ExStyle) \
73 (((Style) & WS_THICKFRAME) && \
74 (!(((Style) & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME)))
75
76 #define HAS_THINFRAME(Style, ExStyle) \
77 (((Style) & WS_BORDER) || (!((Style) & (WS_CHILD | WS_POPUP))))
78
79 BOOL FASTCALL
80 IntGetClientOrigin(HWND hWnd, LPPOINT Point)
81 {
82 PWINDOW_OBJECT WindowObject;
83
84 WindowObject = IntGetWindowObject(hWnd);
85 if (WindowObject == NULL)
86 {
87 Point->x = Point->y = 0;
88 return FALSE;
89 }
90 Point->x = WindowObject->ClientRect.left;
91 Point->y = WindowObject->ClientRect.top;
92
93 IntReleaseWindowObject(WindowObject);
94 return TRUE;
95 }
96
97 BOOL STDCALL
98 NtUserGetClientOrigin(HWND hWnd, LPPOINT Point)
99 {
100 BOOL Ret;
101 POINT pt;
102 NTSTATUS Status;
103
104 Ret = IntGetClientOrigin(hWnd, &pt);
105
106 Status = MmCopyToCaller(Point, &pt, sizeof(POINT));
107 if(!NT_SUCCESS(Status))
108 {
109 SetLastNtError(Status);
110 return FALSE;
111 }
112
113 return Ret;
114 }
115
116 /*******************************************************************
117 * WinPosActivateOtherWindow
118 *
119 * Activates window other than pWnd.
120 */
121 VOID FASTCALL
122 WinPosActivateOtherWindow(PWINDOW_OBJECT Window)
123 {
124 PWINDOW_OBJECT Child;
125 PWINDOW_OBJECT TabooWindow = Window;
126
127 for (;;)
128 {
129 if (NULL == Window || IntIsDesktopWindow(Window))
130 {
131 IntSetFocusMessageQueue(NULL);
132 return;
133 }
134 Window = Window->Parent;
135 ExAcquireFastMutex(&(Window->ChildrenListLock));
136 Child = Window->FirstChild;
137 while (NULL != Child)
138 {
139 if (Child != TabooWindow)
140 {
141 ExReleaseFastMutex(&(Window->ChildrenListLock));
142 if (IntSetForegroundWindow(Child))
143 {
144 return;
145 }
146 ExAcquireFastMutex(&(Window->ChildrenListLock));
147 }
148 Child = Child->NextSibling;
149 }
150 ExReleaseFastMutex(&(Window->ChildrenListLock));
151 }
152 }
153
154 VOID STATIC FASTCALL
155 WinPosFindIconPos(HWND hWnd, POINT *Pos)
156 {
157 /* FIXME */
158 }
159
160 PINTERNALPOS FASTCALL
161 WinPosInitInternalPos(PWINDOW_OBJECT WindowObject, POINT pt, PRECT RestoreRect)
162 {
163 INT XInc, YInc;
164
165 if (WindowObject->InternalPos == NULL)
166 {
167 RECT WorkArea;
168 PDESKTOP_OBJECT Desktop = PsGetWin32Thread()->Desktop; /* Or rather get it from the window? */
169
170 if(WindowObject->Parent == NULL)
171 WorkArea = *IntGetDesktopWorkArea(Desktop);
172 else
173 WorkArea = WindowObject->Parent->ClientRect;
174
175 WindowObject->InternalPos = ExAllocatePool(NonPagedPool, sizeof(INTERNALPOS));
176 if(!WindowObject->InternalPos)
177 {
178 DPRINT1("Failed to allocate INTERNALPOS structure for window 0x%x\n", WindowObject->Self);
179 return NULL;
180 }
181 WindowObject->InternalPos->NormalRect = WindowObject->WindowRect;
182 if (HAS_DLGFRAME(WindowObject->Style, WindowObject->ExStyle) && !(WindowObject->Style & WS_MINIMIZE))
183 {
184 XInc = NtUserGetSystemMetrics(SM_CXDLGFRAME);
185 YInc = NtUserGetSystemMetrics(SM_CYDLGFRAME);
186 }
187 else
188 {
189 XInc = YInc = 0;
190 if (HAS_THICKFRAME(WindowObject->Style, WindowObject->ExStyle)&& !(WindowObject->Style & WS_MINIMIZE))
191 {
192 XInc += NtUserGetSystemMetrics(SM_CXFRAME);
193 YInc += NtUserGetSystemMetrics(SM_CYFRAME);
194 }
195 else if (HAS_THINFRAME(WindowObject->Style, WindowObject->ExStyle))
196 {
197 XInc += NtUserGetSystemMetrics(SM_CXBORDER);
198 YInc += NtUserGetSystemMetrics(SM_CYBORDER);
199 }
200 }
201 WindowObject->InternalPos->MaxPos.x = WorkArea.left - XInc;
202 WindowObject->InternalPos->MaxPos.y = WorkArea.top - YInc;
203 WindowObject->InternalPos->IconPos.x = WorkArea.left;
204 WindowObject->InternalPos->IconPos.y = WorkArea.bottom - NtUserGetSystemMetrics(SM_CYMINIMIZED);
205 }
206 if (WindowObject->Style & WS_MINIMIZE)
207 {
208 WindowObject->InternalPos->IconPos = pt;
209 }
210 else if (WindowObject->Style & WS_MAXIMIZE)
211 {
212 WindowObject->InternalPos->MaxPos = pt;
213 }
214 else if (RestoreRect != NULL)
215 {
216 WindowObject->InternalPos->NormalRect = *RestoreRect;
217 }
218 return(WindowObject->InternalPos);
219 }
220
221 UINT FASTCALL
222 WinPosMinMaximize(PWINDOW_OBJECT WindowObject, UINT ShowFlag, RECT* NewPos)
223 {
224 POINT Size;
225 PINTERNALPOS InternalPos;
226 UINT SwpFlags = 0;
227
228 Size.x = WindowObject->WindowRect.left;
229 Size.y = WindowObject->WindowRect.top;
230 InternalPos = WinPosInitInternalPos(WindowObject, Size,
231 &WindowObject->WindowRect);
232
233 if (InternalPos)
234 {
235 if (WindowObject->Style & WS_MINIMIZE)
236 {
237 if (!IntSendMessage(WindowObject->Self, WM_QUERYOPEN, 0, 0))
238 {
239 return(SWP_NOSIZE | SWP_NOMOVE);
240 }
241 SwpFlags |= SWP_NOCOPYBITS;
242 }
243 switch (ShowFlag)
244 {
245 case SW_MINIMIZE:
246 {
247 if (WindowObject->Style & WS_MAXIMIZE)
248 {
249 WindowObject->Flags |= WINDOWOBJECT_RESTOREMAX;
250 WindowObject->Style &= ~WS_MAXIMIZE;
251 }
252 else
253 {
254 WindowObject->Flags &= ~WINDOWOBJECT_RESTOREMAX;
255 }
256 IntRedrawWindow(WindowObject, NULL, 0, RDW_VALIDATE | RDW_NOERASE |
257 RDW_NOINTERNALPAINT);
258 WindowObject->Style |= WS_MINIMIZE;
259 WinPosFindIconPos(WindowObject, &InternalPos->IconPos);
260 NtGdiSetRect(NewPos, InternalPos->IconPos.x, InternalPos->IconPos.y,
261 NtUserGetSystemMetrics(SM_CXMINIMIZED),
262 NtUserGetSystemMetrics(SM_CYMINIMIZED));
263 SwpFlags |= SWP_NOCOPYBITS;
264 break;
265 }
266
267 case SW_MAXIMIZE:
268 {
269 WinPosGetMinMaxInfo(WindowObject, &Size, &InternalPos->MaxPos,
270 NULL, NULL);
271 if (WindowObject->Style & WS_MINIMIZE)
272 {
273 WindowObject->Style &= ~WS_MINIMIZE;
274 }
275 WindowObject->Style |= WS_MAXIMIZE;
276 NtGdiSetRect(NewPos, InternalPos->MaxPos.x, InternalPos->MaxPos.y,
277 Size.x, Size.y);
278 break;
279 }
280
281 case SW_RESTORE:
282 {
283 if (WindowObject->Style & WS_MINIMIZE)
284 {
285 WindowObject->Style &= ~WS_MINIMIZE;
286 if (WindowObject->Flags & WINDOWOBJECT_RESTOREMAX)
287 {
288 WinPosGetMinMaxInfo(WindowObject, &Size,
289 &InternalPos->MaxPos, NULL, NULL);
290 WindowObject->Style |= WS_MAXIMIZE;
291 NtGdiSetRect(NewPos, InternalPos->MaxPos.x,
292 InternalPos->MaxPos.y, Size.x, Size.y);
293 break;
294 }
295 else
296 {
297 *NewPos = InternalPos->NormalRect;
298 NewPos->right -= NewPos->left;
299 NewPos->bottom -= NewPos->top;
300 break;
301 }
302 }
303 else
304 {
305 if (!(WindowObject->Style & WS_MAXIMIZE))
306 {
307 return 0;
308 }
309 WindowObject->Style &= ~WS_MAXIMIZE;
310 *NewPos = InternalPos->NormalRect;
311 NewPos->right -= NewPos->left;
312 NewPos->bottom -= NewPos->top;
313 break;
314 }
315 }
316 }
317 }
318 else
319 {
320 SwpFlags |= SWP_NOSIZE | SWP_NOMOVE;
321 }
322 return(SwpFlags);
323 }
324
325 VOID FASTCALL
326 WinPosFillMinMaxInfoStruct(PWINDOW_OBJECT Window, MINMAXINFO *Info)
327 {
328 INT XInc, YInc;
329 RECT WorkArea;
330 PDESKTOP_OBJECT Desktop = PsGetWin32Thread()->Desktop; /* Or rather get it from the window? */
331
332 if(Window->Parent == NULL)
333 WorkArea = *IntGetDesktopWorkArea(Desktop);
334 else
335 WorkArea = Window->Parent->ClientRect;
336
337 /* Get default values. */
338 Info->ptMaxSize.x = WorkArea.right - WorkArea.left;
339 Info->ptMaxSize.y = WorkArea.bottom - WorkArea.top;
340 Info->ptMinTrackSize.x = NtUserGetSystemMetrics(SM_CXMINTRACK);
341 Info->ptMinTrackSize.y = NtUserGetSystemMetrics(SM_CYMINTRACK);
342 Info->ptMaxTrackSize.x = Info->ptMaxSize.x;
343 Info->ptMaxTrackSize.y = Info->ptMaxSize.y;
344
345 if (HAS_DLGFRAME(Window->Style, Window->ExStyle))
346 {
347 XInc = NtUserGetSystemMetrics(SM_CXDLGFRAME);
348 YInc = NtUserGetSystemMetrics(SM_CYDLGFRAME);
349 }
350 else
351 {
352 XInc = YInc = 0;
353 if (HAS_THICKFRAME(Window->Style, Window->ExStyle))
354 {
355 XInc += NtUserGetSystemMetrics(SM_CXFRAME);
356 YInc += NtUserGetSystemMetrics(SM_CYFRAME);
357 }
358 else if (HAS_THINFRAME(Window->Style, Window->ExStyle))
359 {
360 XInc += NtUserGetSystemMetrics(SM_CXBORDER);
361 YInc += NtUserGetSystemMetrics(SM_CYBORDER);
362 }
363 }
364 Info->ptMaxSize.x += 2 * XInc;
365 Info->ptMaxSize.y += 2 * YInc;
366
367 if (Window->InternalPos != NULL)
368 {
369 Info->ptMaxPosition = Window->InternalPos->MaxPos;
370 }
371 else
372 {
373 Info->ptMaxPosition.x -= WorkArea.left + XInc;
374 Info->ptMaxPosition.y -= WorkArea.top + YInc;
375 }
376 }
377
378 UINT FASTCALL
379 WinPosGetMinMaxInfo(PWINDOW_OBJECT Window, POINT* MaxSize, POINT* MaxPos,
380 POINT* MinTrack, POINT* MaxTrack)
381 {
382 MINMAXINFO MinMax;
383
384 WinPosFillMinMaxInfoStruct(Window, &MinMax);
385
386 IntSendMessage(Window->Self, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax);
387
388 MinMax.ptMaxTrackSize.x = max(MinMax.ptMaxTrackSize.x,
389 MinMax.ptMinTrackSize.x);
390 MinMax.ptMaxTrackSize.y = max(MinMax.ptMaxTrackSize.y,
391 MinMax.ptMinTrackSize.y);
392
393 if (MaxSize) *MaxSize = MinMax.ptMaxSize;
394 if (MaxPos) *MaxPos = MinMax.ptMaxPosition;
395 if (MinTrack) *MinTrack = MinMax.ptMinTrackSize;
396 if (MaxTrack) *MaxTrack = MinMax.ptMaxTrackSize;
397
398 return 0; //FIXME: what does it return?
399 }
400
401 LONG STATIC FASTCALL
402 WinPosDoNCCALCSize(PWINDOW_OBJECT Window, PWINDOWPOS WinPos,
403 RECT* WindowRect, RECT* ClientRect)
404 {
405 UINT wvrFlags = 0;
406
407 /* Send WM_NCCALCSIZE message to get new client area */
408 if ((WinPos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE)
409 {
410 NCCALCSIZE_PARAMS params;
411 WINDOWPOS winposCopy;
412
413 params.rgrc[0] = *WindowRect;
414 params.rgrc[1] = Window->WindowRect;
415 params.rgrc[2] = Window->ClientRect;
416 if (0 != (Window->Style & WS_CHILD))
417 {
418 NtGdiOffsetRect(&(params.rgrc[0]), - Window->Parent->ClientRect.left,
419 - Window->Parent->ClientRect.top);
420 NtGdiOffsetRect(&(params.rgrc[1]), - Window->Parent->ClientRect.left,
421 - Window->Parent->ClientRect.top);
422 NtGdiOffsetRect(&(params.rgrc[2]), - Window->Parent->ClientRect.left,
423 - Window->Parent->ClientRect.top);
424 }
425 params.lppos = &winposCopy;
426 winposCopy = *WinPos;
427
428 wvrFlags = IntSendMessage(Window->Self, WM_NCCALCSIZE, TRUE, (LPARAM) &params);
429
430 /* If the application send back garbage, ignore it */
431 if (params.rgrc[0].left <= params.rgrc[0].right &&
432 params.rgrc[0].top <= params.rgrc[0].bottom)
433 {
434 *ClientRect = params.rgrc[0];
435 if (Window->Style & WS_CHILD)
436 {
437 NtGdiOffsetRect(ClientRect, Window->Parent->ClientRect.left,
438 Window->Parent->ClientRect.top);
439 }
440 }
441
442 /* FIXME: WVR_ALIGNxxx */
443
444 if (ClientRect->left != Window->ClientRect.left ||
445 ClientRect->top != Window->ClientRect.top)
446 {
447 WinPos->flags &= ~SWP_NOCLIENTMOVE;
448 }
449
450 if ((ClientRect->right - ClientRect->left !=
451 Window->ClientRect.right - Window->ClientRect.left) ||
452 (ClientRect->bottom - ClientRect->top !=
453 Window->ClientRect.bottom - Window->ClientRect.top))
454 {
455 WinPos->flags &= ~SWP_NOCLIENTSIZE;
456 }
457 }
458 else
459 {
460 if (! (WinPos->flags & SWP_NOMOVE)
461 && (ClientRect->left != Window->ClientRect.left ||
462 ClientRect->top != Window->ClientRect.top))
463 {
464 WinPos->flags &= ~SWP_NOCLIENTMOVE;
465 }
466 }
467
468 return wvrFlags;
469 }
470
471 BOOL FASTCALL
472 WinPosDoWinPosChanging(PWINDOW_OBJECT WindowObject,
473 PWINDOWPOS WinPos,
474 PRECT WindowRect,
475 PRECT ClientRect)
476 {
477 INT X, Y;
478
479 if (!(WinPos->flags & SWP_NOSENDCHANGING))
480 {
481 IntSendMessage(WindowObject->Self, WM_WINDOWPOSCHANGING, 0, (LPARAM) WinPos);
482 }
483
484 *WindowRect = WindowObject->WindowRect;
485 *ClientRect = WindowObject->ClientRect;
486
487 if (!(WinPos->flags & SWP_NOSIZE))
488 {
489 WindowRect->right = WindowRect->left + WinPos->cx;
490 WindowRect->bottom = WindowRect->top + WinPos->cy;
491 }
492
493 if (!(WinPos->flags & SWP_NOMOVE))
494 {
495 X = WinPos->x;
496 Y = WinPos->y;
497 if (0 != (WindowObject->Style & WS_CHILD))
498 {
499 X += WindowObject->Parent->ClientRect.left;
500 Y += WindowObject->Parent->ClientRect.top;
501 }
502 WindowRect->left = X;
503 WindowRect->top = Y;
504 WindowRect->right += X - WindowObject->WindowRect.left;
505 WindowRect->bottom += Y - WindowObject->WindowRect.top;
506 NtGdiOffsetRect(ClientRect,
507 X - WindowObject->WindowRect.left,
508 Y - WindowObject->WindowRect.top);
509 }
510
511 WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
512
513 return TRUE;
514 }
515
516 /*
517 * Fix Z order taking into account owned popups -
518 * basically we need to maintain them above the window that owns them
519 */
520 HWND FASTCALL
521 WinPosDoOwnedPopups(HWND hWnd, HWND hWndInsertAfter)
522 {
523 HWND *List = NULL;
524 HWND Owner = NtUserGetWindow(hWnd, GW_OWNER);
525 LONG Style = NtUserGetWindowLong(hWnd, GWL_STYLE, FALSE);
526 PWINDOW_OBJECT DesktopWindow;
527 int i;
528
529 if ((Style & WS_POPUP) && Owner)
530 {
531 /* Make sure this popup stays above the owner */
532 HWND hWndLocalPrev = HWND_TOP;
533
534 if (hWndInsertAfter != HWND_TOP)
535 {
536 DesktopWindow = IntGetWindowObject(IntGetDesktopWindow());
537 List = IntWinListChildren(DesktopWindow);
538 IntReleaseWindowObject(DesktopWindow);
539 if (List != NULL)
540 {
541 for (i = 0; List[i]; i++)
542 {
543 if (List[i] == Owner) break;
544 if (List[i] != hWnd) hWndLocalPrev = List[i];
545 if (hWndLocalPrev == hWndInsertAfter) break;
546 }
547 hWndInsertAfter = hWndLocalPrev;
548 }
549 }
550 }
551 else if (Style & WS_CHILD)
552 {
553 return hWndInsertAfter;
554 }
555
556 if (!List)
557 {
558 DesktopWindow = IntGetWindowObject(IntGetDesktopWindow());
559 List = IntWinListChildren(DesktopWindow);
560 IntReleaseWindowObject(DesktopWindow);
561 }
562 if (List != NULL)
563 {
564 for (i = 0; List[i]; i++)
565 {
566 if (List[i] == hWnd)
567 break;
568 if ((NtUserGetWindowLong(List[i], GWL_STYLE, FALSE) & WS_POPUP) &&
569 NtUserGetWindow(List[i], GW_OWNER) == hWnd)
570 {
571 WinPosSetWindowPos(List[i], hWndInsertAfter, 0, 0, 0, 0,
572 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
573 hWndInsertAfter = List[i];
574 }
575 }
576 ExFreePool(List);
577 }
578
579 return hWndInsertAfter;
580 }
581
582 /***********************************************************************
583 * WinPosInternalMoveWindow
584 *
585 * Update WindowRect and ClientRect of Window and all of its children
586 * We keep both WindowRect and ClientRect in screen coordinates internally
587 */
588 VOID STATIC FASTCALL
589 WinPosInternalMoveWindow(PWINDOW_OBJECT Window, INT MoveX, INT MoveY)
590 {
591 PWINDOW_OBJECT Child;
592
593 Window->WindowRect.left += MoveX;
594 Window->WindowRect.right += MoveX;
595 Window->WindowRect.top += MoveY;
596 Window->WindowRect.bottom += MoveY;
597
598 Window->ClientRect.left += MoveX;
599 Window->ClientRect.right += MoveX;
600 Window->ClientRect.top += MoveY;
601 Window->ClientRect.bottom += MoveY;
602
603 ExAcquireFastMutexUnsafe(&Window->ChildrenListLock);
604 Child = Window->FirstChild;
605 while (Child)
606 {
607 WinPosInternalMoveWindow(Child, MoveX, MoveY);
608 Child = Child->NextSibling;
609 }
610 ExReleaseFastMutexUnsafe(&Window->ChildrenListLock);
611 }
612
613 /*
614 * WinPosFixupSWPFlags
615 *
616 * Fix redundant flags and values in the WINDOWPOS structure.
617 */
618
619 BOOL FASTCALL
620 WinPosFixupFlags(WINDOWPOS *WinPos, PWINDOW_OBJECT Window)
621 {
622 if (Window->Style & WS_VISIBLE)
623 {
624 WinPos->flags &= ~SWP_SHOWWINDOW;
625 }
626 else
627 {
628 WinPos->flags &= ~SWP_HIDEWINDOW;
629 if (!(WinPos->flags & SWP_SHOWWINDOW))
630 WinPos->flags |= SWP_NOREDRAW;
631 }
632
633 WinPos->cx = max(WinPos->cx, 0);
634 WinPos->cy = max(WinPos->cy, 0);
635
636 /* Check for right size */
637 if (Window->WindowRect.right - Window->WindowRect.left == WinPos->cx &&
638 Window->WindowRect.bottom - Window->WindowRect.top == WinPos->cy)
639 {
640 WinPos->flags |= SWP_NOSIZE;
641 }
642
643 /* Check for right position */
644 if (Window->WindowRect.left == WinPos->x &&
645 Window->WindowRect.top == WinPos->y)
646 {
647 WinPos->flags |= SWP_NOMOVE;
648 }
649
650 if (WinPos->hwnd == NtUserGetForegroundWindow())
651 {
652 WinPos->flags |= SWP_NOACTIVATE; /* Already active */
653 }
654 else
655 if ((Window->Style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
656 {
657 /* Bring to the top when activating */
658 if (!(WinPos->flags & SWP_NOACTIVATE))
659 {
660 WinPos->flags &= ~SWP_NOZORDER;
661 WinPos->hwndInsertAfter = HWND_TOP;
662 return TRUE;
663 }
664 }
665
666 /* Check hwndInsertAfter */
667 if (!(WinPos->flags & SWP_NOZORDER))
668 {
669 /* Fix sign extension */
670 if (WinPos->hwndInsertAfter == (HWND)0xffff)
671 {
672 WinPos->hwndInsertAfter = HWND_TOPMOST;
673 }
674 else if (WinPos->hwndInsertAfter == (HWND)0xfffe)
675 {
676 WinPos->hwndInsertAfter = HWND_NOTOPMOST;
677 }
678
679 /* FIXME: TOPMOST not supported yet */
680 if ((WinPos->hwndInsertAfter == HWND_TOPMOST) ||
681 (WinPos->hwndInsertAfter == HWND_NOTOPMOST))
682 {
683 WinPos->hwndInsertAfter = HWND_TOP;
684 }
685
686 /* hwndInsertAfter must be a sibling of the window */
687 if ((WinPos->hwndInsertAfter != HWND_TOP) &&
688 (WinPos->hwndInsertAfter != HWND_BOTTOM))
689 {
690 if (NtUserGetAncestor(WinPos->hwndInsertAfter, GA_PARENT) !=
691 Window->Parent)
692 {
693 return FALSE;
694 }
695 else
696 {
697 /*
698 * We don't need to change the Z order of hwnd if it's already
699 * inserted after hwndInsertAfter or when inserting hwnd after
700 * itself.
701 */
702 if ((WinPos->hwnd == WinPos->hwndInsertAfter) ||
703 (WinPos->hwnd == NtUserGetWindow(WinPos->hwndInsertAfter, GW_HWNDNEXT)))
704 {
705 WinPos->flags |= SWP_NOZORDER;
706 }
707 }
708 }
709 }
710
711 return TRUE;
712 }
713
714 /* x and y are always screen relative */
715 BOOLEAN FASTCALL
716 WinPosSetWindowPos(HWND Wnd, HWND WndInsertAfter, INT x, INT y, INT cx,
717 INT cy, UINT flags)
718 {
719 PWINDOW_OBJECT Window;
720 WINDOWPOS WinPos;
721 RECT NewWindowRect;
722 RECT NewClientRect;
723 HRGN VisBefore = NULL;
724 HRGN VisAfter = NULL;
725 HRGN DirtyRgn = NULL;
726 HRGN ExposedRgn = NULL;
727 HRGN CopyRgn = NULL;
728 ULONG WvrFlags = 0;
729 RECT OldWindowRect, OldClientRect;
730 int RgnType;
731 HDC Dc;
732 RECT CopyRect;
733 RECT TempRect;
734
735 /* FIXME: Get current active window from active queue. */
736
737 Window = IntGetWindowObject(Wnd);
738 if (!Window)
739 {
740 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
741 return FALSE;
742 }
743
744 /*
745 * Only allow CSRSS to mess with the desktop window
746 */
747 if (Wnd == IntGetDesktopWindow() &&
748 Window->OwnerThread->ThreadsProcess != PsGetCurrentProcess())
749 {
750 return FALSE;
751 }
752
753 WinPos.hwnd = Wnd;
754 WinPos.hwndInsertAfter = WndInsertAfter;
755 WinPos.x = x;
756 WinPos.y = y;
757 WinPos.cx = cx;
758 WinPos.cy = cy;
759 WinPos.flags = flags;
760 if (Window->Style & WS_CHILD)
761 {
762 WinPos.x -= Window->Parent->ClientRect.left;
763 WinPos.y -= Window->Parent->ClientRect.top;
764 }
765
766 WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
767
768 /* Fix up the flags. */
769 if (!WinPosFixupFlags(&WinPos, Window))
770 {
771 SetLastWin32Error(ERROR_INVALID_PARAMETER);
772 IntReleaseWindowObject(Window);
773 return FALSE;
774 }
775
776 /* Does the window still exist? */
777 if (!IntIsWindow(WinPos.hwnd))
778 {
779 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
780 return FALSE;
781 }
782
783 if ((WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) !=
784 SWP_NOZORDER &&
785 NtUserGetAncestor(WinPos.hwnd, GA_PARENT) == IntGetDesktopWindow())
786 {
787 WinPos.hwndInsertAfter = WinPosDoOwnedPopups(WinPos.hwnd, WinPos.hwndInsertAfter);
788 }
789
790 /* Compute the visible region before the window position is changed */
791 if (!(WinPos.flags & (SWP_NOREDRAW | SWP_SHOWWINDOW)) &&
792 (WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
793 SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
794 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
795 {
796 VisBefore = VIS_ComputeVisibleRegion(
797 PsGetWin32Thread()->Desktop, Window, FALSE, FALSE, TRUE);
798
799 if (UnsafeIntGetRgnBox(VisBefore, &TempRect) == NULLREGION)
800 {
801 NtGdiDeleteObject(VisBefore);
802 VisBefore = NULL;
803 }
804 }
805
806 WvrFlags = WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect);
807
808 /* Relink windows. (also take into account shell window in hwndShellWindow) */
809 if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != NtUserGetShellWindow())
810 {
811 PWINDOW_OBJECT ParentWindow;
812 PWINDOW_OBJECT InsertAfterWindow;
813
814 ParentWindow = Window->Parent;
815 if (ParentWindow)
816 {
817 if (WinPos.hwndInsertAfter == HWND_TOP)
818 InsertAfterWindow = NULL;
819 else if (WinPos.hwndInsertAfter == HWND_BOTTOM)
820 InsertAfterWindow = ParentWindow->LastChild;
821 else
822 InsertAfterWindow = IntGetWindowObject(WinPos.hwndInsertAfter);
823 /* Do nothing if hwndInsertAfter is HWND_BOTTOM and Window is already
824 the last window */
825 if (InsertAfterWindow != Window)
826 {
827 ExAcquireFastMutexUnsafe(&ParentWindow->ChildrenListLock);
828 IntUnlinkWindow(Window);
829 IntLinkWindow(Window, ParentWindow, InsertAfterWindow);
830 ExReleaseFastMutexUnsafe(&ParentWindow->ChildrenListLock);
831 }
832 if (InsertAfterWindow != NULL)
833 IntReleaseWindowObject(InsertAfterWindow);
834 }
835 }
836
837 /* FIXME: Reset active DCEs */
838
839 OldWindowRect = Window->WindowRect;
840 OldClientRect = Window->ClientRect;
841
842 if (OldClientRect.bottom - OldClientRect.top ==
843 NewClientRect.bottom - NewClientRect.top)
844 {
845 WvrFlags &= ~WVR_VREDRAW;
846 }
847
848 if (OldClientRect.right - OldClientRect.left ==
849 NewClientRect.right - NewClientRect.left)
850 {
851 WvrFlags &= ~WVR_HREDRAW;
852 }
853
854 /* FIXME: Actually do something with WVR_VALIDRECTS */
855
856 if (! (WinPos.flags & SWP_NOMOVE)
857 && (NewWindowRect.left != OldWindowRect.left
858 || NewWindowRect.top != OldWindowRect.top))
859 {
860 WinPosInternalMoveWindow(Window,
861 NewWindowRect.left - OldWindowRect.left,
862 NewWindowRect.top - OldWindowRect.top);
863 }
864
865 Window->WindowRect = NewWindowRect;
866 Window->ClientRect = NewClientRect;
867
868 if (!(WinPos.flags & SWP_SHOWWINDOW) && (WinPos.flags & SWP_HIDEWINDOW))
869 {
870 /* Clear the update region */
871 IntRedrawWindow(Window, NULL, 0, RDW_VALIDATE | RDW_NOFRAME |
872 RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
873 Window->Style &= ~WS_VISIBLE;
874 }
875 else if (WinPos.flags & SWP_SHOWWINDOW)
876 {
877 Window->Style |= WS_VISIBLE;
878 }
879
880 /* Determine the new visible region */
881 VisAfter = VIS_ComputeVisibleRegion(
882 PsGetWin32Thread()->Desktop, Window, FALSE, FALSE, TRUE);
883
884 if (UnsafeIntGetRgnBox(VisAfter, &TempRect) == NULLREGION)
885 {
886 NtGdiDeleteObject(VisAfter);
887 VisAfter = NULL;
888 }
889
890 /*
891 * Determine which pixels can be copied from the old window position
892 * to the new. Those pixels must be visible in both the old and new
893 * position. Also, check the class style to see if the windows of this
894 * class need to be completely repainted on (horizontal/vertical) size
895 * change.
896 */
897 if (VisBefore != NULL && VisAfter != NULL && !(WinPos.flags & SWP_NOCOPYBITS) &&
898 ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)))
899 {
900 CopyRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
901 RgnType = NtGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
902
903 /*
904 * If this is (also) a window resize, the whole nonclient area
905 * needs to be repainted. So we limit the copy to the client area,
906 * 'cause there is no use in copying it (would possibly cause
907 * "flashing" too). However, if the copy region is already empty,
908 * we don't have to crop (can't take anything away from an empty
909 * region...)
910 */
911 if (!(WinPos.flags & SWP_NOSIZE) && RgnType != ERROR &&
912 RgnType != NULLREGION)
913 {
914 RECT ORect = OldClientRect;
915 RECT NRect = NewClientRect;
916 NtGdiOffsetRect(&ORect, - OldWindowRect.left, - OldWindowRect.top);
917 NtGdiOffsetRect(&NRect, - NewWindowRect.left, - NewWindowRect.top);
918 NtGdiIntersectRect(&CopyRect, &ORect, &NRect);
919 REGION_CropRgn(CopyRgn, CopyRgn, &CopyRect, NULL);
920 }
921
922 /* No use in copying bits which are in the update region. */
923 if (Window->UpdateRegion != NULL)
924 {
925 NtGdiCombineRgn(CopyRgn, CopyRgn, Window->UpdateRegion, RGN_DIFF);
926 }
927 if (Window->NCUpdateRegion != NULL)
928 {
929 NtGdiCombineRgn(CopyRgn, CopyRgn, Window->NCUpdateRegion, RGN_DIFF);
930 }
931
932 /*
933 * Now, get the bounding box of the copy region. If it's empty
934 * there's nothing to copy. Also, it's no use copying bits onto
935 * themselves.
936 */
937 if (UnsafeIntGetRgnBox(CopyRgn, &CopyRect) == NULLREGION)
938 {
939 /* Nothing to copy, clean up */
940 NtGdiDeleteObject(CopyRgn);
941 CopyRgn = NULL;
942 }
943 else if (OldWindowRect.left != NewWindowRect.left ||
944 OldWindowRect.top != NewWindowRect.top)
945 {
946 /*
947 * Small trick here: there is no function to bitblt a region. So
948 * we set the region as the clipping region, take the bounding box
949 * of the region and bitblt that. Since nothing outside the clipping
950 * region is copied, this has the effect of bitblt'ing the region.
951 *
952 * Since NtUserGetDCEx takes ownership of the clip region, we need
953 * to create a copy of CopyRgn and pass that. We need CopyRgn later
954 */
955 HRGN ClipRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
956
957 NtGdiCombineRgn(ClipRgn, CopyRgn, NULL, RGN_COPY);
958 Dc = NtUserGetDCEx(Wnd, ClipRgn, DCX_WINDOW | DCX_CACHE |
959 DCX_INTERSECTRGN | DCX_CLIPSIBLINGS);
960 NtGdiBitBlt(Dc,
961 CopyRect.left, CopyRect.top, CopyRect.right - CopyRect.left,
962 CopyRect.bottom - CopyRect.top, Dc,
963 CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
964 CopyRect.top + (OldWindowRect.top - NewWindowRect.top), SRCCOPY);
965 NtUserReleaseDC(Wnd, Dc);
966 IntValidateParent(Window, CopyRgn);
967 }
968 }
969 else
970 {
971 CopyRgn = NULL;
972 }
973
974 /* We need to redraw what wasn't visible before */
975 if (VisAfter != NULL)
976 {
977 if (CopyRgn != NULL)
978 {
979 DirtyRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
980 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
981 if (RgnType != ERROR && RgnType != NULLREGION)
982 {
983 NtGdiOffsetRgn(DirtyRgn,
984 Window->WindowRect.left - Window->ClientRect.left,
985 Window->WindowRect.top - Window->ClientRect.top);
986 IntRedrawWindow(Window, NULL, DirtyRgn,
987 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
988 }
989 NtGdiDeleteObject(DirtyRgn);
990 }
991 else
992 {
993 IntRedrawWindow(Window, NULL, 0,
994 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
995 }
996 }
997
998 if (CopyRgn != NULL)
999 {
1000 NtGdiDeleteObject(CopyRgn);
1001 }
1002
1003 /* Expose what was covered before but not covered anymore */
1004 if (VisBefore != NULL)
1005 {
1006 ExposedRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
1007 NtGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
1008 NtGdiOffsetRgn(ExposedRgn, OldWindowRect.left - NewWindowRect.left,
1009 OldWindowRect.top - NewWindowRect.top);
1010 if (VisAfter != NULL)
1011 RgnType = NtGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
1012 else
1013 RgnType = SIMPLEREGION;
1014
1015 if (RgnType != ERROR && RgnType != NULLREGION)
1016 {
1017 VIS_WindowLayoutChanged(PsGetWin32Thread()->Desktop, Window,
1018 ExposedRgn);
1019 }
1020 NtGdiDeleteObject(ExposedRgn);
1021 NtGdiDeleteObject(VisBefore);
1022 }
1023
1024 if (VisAfter != NULL)
1025 {
1026 NtGdiDeleteObject(VisAfter);
1027 }
1028
1029 if (!(WinPos.flags & SWP_NOREDRAW))
1030 {
1031 IntRedrawWindow(Window, NULL, 0, RDW_ALLCHILDREN | RDW_ERASENOW);
1032 }
1033
1034 if (!(WinPos.flags & SWP_NOACTIVATE))
1035 {
1036 if ((Window->Style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
1037 {
1038 IntSendMessage(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
1039 }
1040 else
1041 {
1042 IntSetForegroundWindow(Window);
1043 }
1044 }
1045
1046 if ((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
1047 IntSendMessage(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
1048
1049 IntReleaseWindowObject(Window);
1050
1051 return TRUE;
1052 }
1053
1054 LRESULT FASTCALL
1055 WinPosGetNonClientSize(HWND Wnd, RECT* WindowRect, RECT* ClientRect)
1056 {
1057 *ClientRect = *WindowRect;
1058 return(IntSendMessage(Wnd, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect));
1059 }
1060
1061 BOOLEAN FASTCALL
1062 WinPosShowWindow(HWND Wnd, INT Cmd)
1063 {
1064 BOOLEAN WasVisible;
1065 PWINDOW_OBJECT Window;
1066 NTSTATUS Status;
1067 UINT Swp = 0;
1068 RECT NewPos;
1069 BOOLEAN ShowFlag;
1070 // HRGN VisibleRgn;
1071
1072 Status =
1073 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
1074 Wnd,
1075 otWindow,
1076 (PVOID*)&Window);
1077 if (!NT_SUCCESS(Status))
1078 {
1079 return(FALSE);
1080 }
1081
1082 WasVisible = (Window->Style & WS_VISIBLE) != 0;
1083
1084 switch (Cmd)
1085 {
1086 case SW_HIDE:
1087 {
1088 if (!WasVisible)
1089 {
1090 ObmDereferenceObject(Window);
1091 return(FALSE);
1092 }
1093 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE |
1094 SWP_NOZORDER;
1095 break;
1096 }
1097
1098 case SW_SHOWMINNOACTIVE:
1099 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1100 /* Fall through. */
1101 case SW_SHOWMINIMIZED:
1102 Swp |= SWP_SHOWWINDOW;
1103 /* Fall through. */
1104 case SW_MINIMIZE:
1105 {
1106 Swp |= SWP_FRAMECHANGED | SWP_NOACTIVATE;
1107 if (!(Window->Style & WS_MINIMIZE))
1108 {
1109 Swp |= WinPosMinMaximize(Window, SW_MINIMIZE, &NewPos);
1110 }
1111 else
1112 {
1113 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1114 }
1115 break;
1116 }
1117
1118 case SW_SHOWMAXIMIZED:
1119 {
1120 Swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1121 if (!(Window->Style & WS_MAXIMIZE))
1122 {
1123 Swp |= WinPosMinMaximize(Window, SW_MAXIMIZE, &NewPos);
1124 }
1125 else
1126 {
1127 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1128 }
1129 break;
1130 }
1131
1132 case SW_SHOWNA:
1133 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1134 /* Fall through. */
1135 case SW_SHOW:
1136 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1137 /* Don't activate the topmost window. */
1138 break;
1139
1140 case SW_SHOWNOACTIVATE:
1141 Swp |= SWP_NOZORDER;
1142 /* Fall through. */
1143 case SW_SHOWNORMAL:
1144 case SW_SHOWDEFAULT:
1145 case SW_RESTORE:
1146 Swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1147 if (Window->Style & (WS_MINIMIZE | WS_MAXIMIZE))
1148 {
1149 Swp |= WinPosMinMaximize(Window, SW_RESTORE, &NewPos);
1150 }
1151 else
1152 {
1153 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1154 }
1155 break;
1156 }
1157
1158 ShowFlag = (Cmd != SW_HIDE);
1159 if (ShowFlag != WasVisible)
1160 {
1161 IntSendMessage(Wnd, WM_SHOWWINDOW, ShowFlag, 0);
1162 /*
1163 * FIXME: Need to check the window wasn't destroyed during the
1164 * window procedure.
1165 */
1166 }
1167
1168 /* We can't activate a child window */
1169 if ((Window->Style & WS_CHILD) &&
1170 !(Window->ExStyle & WS_EX_MDICHILD))
1171 {
1172 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1173 }
1174
1175 WinPosSetWindowPos(Window->Self, HWND_TOP, NewPos.left, NewPos.top,
1176 NewPos.right, NewPos.bottom, LOWORD(Swp));
1177
1178 if (Cmd == SW_HIDE)
1179 {
1180 /* FIXME: This will cause the window to be activated irrespective
1181 * of whether it is owned by the same thread. Has to be done
1182 * asynchronously.
1183 */
1184
1185 if (Window->Self == NtUserGetActiveWindow())
1186 {
1187 WinPosActivateOtherWindow(Window);
1188 }
1189
1190 /* Revert focus to parent */
1191 if (Wnd == IntGetThreadFocusWindow() ||
1192 IntIsChildWindow(Wnd, IntGetThreadFocusWindow()))
1193 {
1194 NtUserSetFocus(Window->Parent->Self);
1195 }
1196 }
1197
1198 /* FIXME: Check for window destruction. */
1199
1200 if (Window->Flags & WINDOWOBJECT_NEED_SIZE)
1201 {
1202 WPARAM wParam = SIZE_RESTORED;
1203
1204 Window->Flags &= ~WINDOWOBJECT_NEED_SIZE;
1205 if (Window->Style & WS_MAXIMIZE)
1206 {
1207 wParam = SIZE_MAXIMIZED;
1208 }
1209 else if (Window->Style & WS_MINIMIZE)
1210 {
1211 wParam = SIZE_MINIMIZED;
1212 }
1213
1214 IntSendMessage(Wnd, WM_SIZE, wParam,
1215 MAKELONG(Window->ClientRect.right -
1216 Window->ClientRect.left,
1217 Window->ClientRect.bottom -
1218 Window->ClientRect.top));
1219 IntSendMessage(Wnd, WM_MOVE, 0,
1220 MAKELONG(Window->ClientRect.left,
1221 Window->ClientRect.top));
1222 }
1223
1224 /* Activate the window if activation is not requested and the window is not minimized */
1225 /*
1226 if (!(Swp & (SWP_NOACTIVATE | SWP_HIDEWINDOW)) && !(Window->Style & WS_MINIMIZE))
1227 {
1228 WinPosChangeActiveWindow(Wnd, FALSE);
1229 }
1230 */
1231
1232 ObmDereferenceObject(Window);
1233 return(WasVisible);
1234 }
1235
1236 BOOL STATIC FASTCALL
1237 WinPosPtInWindow(PWINDOW_OBJECT Window, POINT Point)
1238 {
1239 return(Point.x >= Window->WindowRect.left &&
1240 Point.x < Window->WindowRect.right &&
1241 Point.y >= Window->WindowRect.top &&
1242 Point.y < Window->WindowRect.bottom);
1243 }
1244
1245 USHORT STATIC FASTCALL
1246 WinPosSearchChildren(PWINDOW_OBJECT ScopeWin, POINT Point,
1247 PWINDOW_OBJECT* Window)
1248 {
1249 PWINDOW_OBJECT Current;
1250
1251 ExAcquireFastMutexUnsafe(&ScopeWin->ChildrenListLock);
1252 Current = ScopeWin->FirstChild;
1253 while (Current)
1254 {
1255 if (Current->Style & WS_VISIBLE &&
1256 ((!(Current->Style & WS_DISABLED)) ||
1257 (Current->Style & (WS_CHILD | WS_POPUP)) != WS_CHILD) &&
1258 WinPosPtInWindow(Current, Point))
1259 {
1260 if(*Window)
1261 ObmDereferenceObject(*Window);
1262 ObmReferenceObjectByPointer(Current, otWindow);
1263
1264 *Window = Current;
1265
1266 if (Current->Style & WS_DISABLED)
1267 {
1268 ExReleaseFastMutexUnsafe(&ScopeWin->ChildrenListLock);
1269 return(HTERROR);
1270 }
1271 if (Point.x >= Current->ClientRect.left &&
1272 Point.x < Current->ClientRect.right &&
1273 Point.y >= Current->ClientRect.top &&
1274 Point.y < Current->ClientRect.bottom)
1275 {
1276
1277 ExReleaseFastMutexUnsafe(&ScopeWin->ChildrenListLock);
1278 return(WinPosSearchChildren(Current, Point, Window));
1279 }
1280
1281 ExReleaseFastMutexUnsafe(&ScopeWin->ChildrenListLock);
1282 return(0);
1283 }
1284 Current = Current->NextSibling;
1285 }
1286
1287 ExReleaseFastMutexUnsafe(&ScopeWin->ChildrenListLock);
1288 return(0);
1289 }
1290
1291 USHORT FASTCALL
1292 WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin, POINT WinPoint,
1293 PWINDOW_OBJECT* Window)
1294 {
1295 HWND DesktopWindowHandle;
1296 PWINDOW_OBJECT DesktopWindow;
1297 POINT Point = WinPoint;
1298 USHORT HitTest;
1299
1300 *Window = NULL;
1301
1302 if(!ScopeWin)
1303 {
1304 DPRINT1("WinPosWindowFromPoint(): ScopeWin == NULL!\n");
1305 return(HTERROR);
1306 }
1307
1308 if (ScopeWin->Style & WS_DISABLED)
1309 {
1310 return(HTERROR);
1311 }
1312
1313 /* Translate the point to the space of the scope window. */
1314 DesktopWindowHandle = IntGetDesktopWindow();
1315 DesktopWindow = IntGetWindowObject(DesktopWindowHandle);
1316 Point.x += ScopeWin->ClientRect.left - DesktopWindow->ClientRect.left;
1317 Point.y += ScopeWin->ClientRect.top - DesktopWindow->ClientRect.top;
1318 IntReleaseWindowObject(DesktopWindow);
1319
1320 HitTest = WinPosSearchChildren(ScopeWin, Point, Window);
1321 if (HitTest != 0)
1322 {
1323 return(HitTest);
1324 }
1325
1326 if ((*Window) == NULL)
1327 {
1328 return(HTNOWHERE);
1329 }
1330 if ((*Window)->MessageQueue == PsGetWin32Thread()->MessageQueue)
1331 {
1332 HitTest = IntSendMessage((*Window)->Self, WM_NCHITTEST, 0,
1333 MAKELONG(Point.x, Point.y));
1334 /* FIXME: Check for HTTRANSPARENT here. */
1335 }
1336 else
1337 {
1338 HitTest = HTCLIENT;
1339 }
1340
1341 return(HitTest);
1342 }
1343
1344 BOOL
1345 STDCALL
1346 NtUserGetMinMaxInfo(
1347 HWND hwnd,
1348 MINMAXINFO *MinMaxInfo,
1349 BOOL SendMessage)
1350 {
1351 POINT Size;
1352 PINTERNALPOS InternalPos;
1353 PWINDOW_OBJECT Window;
1354 MINMAXINFO SafeMinMax;
1355 NTSTATUS Status;
1356
1357 Window = IntGetWindowObject(hwnd);
1358 if(!Window)
1359 {
1360 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1361 return FALSE;
1362 }
1363
1364 Size.x = Window->WindowRect.left;
1365 Size.y = Window->WindowRect.top;
1366 InternalPos = WinPosInitInternalPos(Window, Size,
1367 &Window->WindowRect);
1368 if(InternalPos)
1369 {
1370 if(SendMessage)
1371 {
1372 WinPosGetMinMaxInfo(Window, &SafeMinMax.ptMaxSize, &SafeMinMax.ptMaxPosition,
1373 &SafeMinMax.ptMinTrackSize, &SafeMinMax.ptMaxTrackSize);
1374 }
1375 else
1376 {
1377 WinPosFillMinMaxInfoStruct(Window, &SafeMinMax);
1378 }
1379 Status = MmCopyToCaller(MinMaxInfo, &SafeMinMax, sizeof(MINMAXINFO));
1380 if(!NT_SUCCESS(Status))
1381 {
1382 IntReleaseWindowObject(Window);
1383 SetLastNtError(Status);
1384 return FALSE;
1385 }
1386 IntReleaseWindowObject(Window);
1387 return TRUE;
1388 }
1389
1390 IntReleaseWindowObject(Window);
1391 return FALSE;
1392 }
1393
1394 /* EOF */