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