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