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