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