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