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