[WIN32K:NTUSER]
[reactos.git] / reactos / win32ss / user / ntuser / winpos.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Windows
5 * FILE: win32ss/user/ntuser/winpos.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserWinpos);
11
12 /* GLOBALS *******************************************************************/
13
14 #define MINMAX_NOSWP (0x00010000)
15
16 #define SWP_EX_NOCOPY 0x0001
17 #define SWP_EX_PAINTSELF 0x0002
18
19 #define SWP_AGG_NOGEOMETRYCHANGE \
20 (SWP_NOSIZE | SWP_NOCLIENTSIZE | SWP_NOZORDER)
21 #define SWP_AGG_NOPOSCHANGE \
22 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER)
23 #define SWP_AGG_STATUSFLAGS \
24 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
25
26 #define EMPTYPOINT(pt) ((pt).x == -1 && (pt).y == -1)
27 #define PLACE_MIN 0x0001
28 #define PLACE_MAX 0x0002
29 #define PLACE_RECT 0x0004
30
31 VOID FASTCALL IntLinkWindow(PWND Wnd,PWND WndInsertAfter);
32
33 /* FUNCTIONS *****************************************************************/
34
35 #if DBG
36 /***********************************************************************
37 * dump_winpos_flags
38 */
39 static void dump_winpos_flags(UINT flags)
40 {
41 static const DWORD dumped_flags = (SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW |
42 SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_SHOWWINDOW |
43 SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOOWNERZORDER |
44 SWP_NOSENDCHANGING | SWP_DEFERERASE | SWP_ASYNCWINDOWPOS |
45 SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_STATECHANGED);
46 TRACE("flags:");
47 if(flags & SWP_NOSIZE) TRACE(" SWP_NOSIZE");
48 if(flags & SWP_NOMOVE) TRACE(" SWP_NOMOVE");
49 if(flags & SWP_NOZORDER) TRACE(" SWP_NOZORDER");
50 if(flags & SWP_NOREDRAW) TRACE(" SWP_NOREDRAW");
51 if(flags & SWP_NOACTIVATE) TRACE(" SWP_NOACTIVATE");
52 if(flags & SWP_FRAMECHANGED) TRACE(" SWP_FRAMECHANGED");
53 if(flags & SWP_SHOWWINDOW) TRACE(" SWP_SHOWWINDOW");
54 if(flags & SWP_HIDEWINDOW) TRACE(" SWP_HIDEWINDOW");
55 if(flags & SWP_NOCOPYBITS) TRACE(" SWP_NOCOPYBITS");
56 if(flags & SWP_NOOWNERZORDER) TRACE(" SWP_NOOWNERZORDER");
57 if(flags & SWP_NOSENDCHANGING) TRACE(" SWP_NOSENDCHANGING");
58 if(flags & SWP_DEFERERASE) TRACE(" SWP_DEFERERASE");
59 if(flags & SWP_ASYNCWINDOWPOS) TRACE(" SWP_ASYNCWINDOWPOS");
60 if(flags & SWP_NOCLIENTSIZE) TRACE(" SWP_NOCLIENTSIZE");
61 if(flags & SWP_NOCLIENTMOVE) TRACE(" SWP_NOCLIENTMOVE");
62 if(flags & SWP_STATECHANGED) TRACE(" SWP_STATECHANGED");
63
64 if(flags & ~dumped_flags) TRACE(" %08x", flags & ~dumped_flags);
65 TRACE("\n");
66 }
67 #endif
68
69 BOOL FASTCALL
70 IntGetClientOrigin(PWND Window OPTIONAL, LPPOINT Point)
71 {
72 Window = Window ? Window : UserGetDesktopWindow();
73 if (Window == NULL)
74 {
75 Point->x = Point->y = 0;
76 return FALSE;
77 }
78 Point->x = Window->rcClient.left;
79 Point->y = Window->rcClient.top;
80
81 return TRUE;
82 }
83
84 /*!
85 * Internal function.
86 * Returns client window rectangle relative to the upper-left corner of client area.
87 *
88 * \note Does not check the validity of the parameters
89 */
90 VOID FASTCALL
91 IntGetClientRect(PWND Wnd, RECTL *Rect)
92 {
93 ASSERT( Wnd );
94 ASSERT( Rect );
95 if (Wnd->style & WS_MINIMIZED)
96 {
97 Rect->left = Rect->top = 0;
98 Rect->right = UserGetSystemMetrics(SM_CXMINIMIZED);
99 Rect->bottom = UserGetSystemMetrics(SM_CYMINIMIZED);
100 return;
101 }
102 if (!UserIsDesktopWindow(Wnd))
103 {
104 *Rect = Wnd->rcClient;
105 RECTL_vOffsetRect(Rect, -Wnd->rcClient.left, -Wnd->rcClient.top);
106 }
107 else
108 {
109 Rect->left = Rect->top = 0;
110 Rect->right = Wnd->rcClient.right;
111 Rect->bottom = Wnd->rcClient.bottom;
112 /* Do this until Init bug is fixed. This sets 640x480, see InitMetrics.
113 Rect->right = UserGetSystemMetrics(SM_CXSCREEN);
114 Rect->bottom = UserGetSystemMetrics(SM_CYSCREEN);
115 */
116 }
117 }
118
119 BOOL FASTCALL
120 IntGetWindowRect(PWND Wnd, RECTL *Rect)
121 {
122 ASSERT( Wnd );
123 ASSERT( Rect );
124 if (!Wnd) return FALSE;
125 if (!UserIsDesktopWindow(Wnd))
126 {
127 *Rect = Wnd->rcWindow;
128 }
129 else
130 {
131 Rect->left = Rect->top = 0;
132 Rect->right = Wnd->rcWindow.right;
133 Rect->bottom = Wnd->rcWindow.bottom;
134 /* Do this until Init bug is fixed. This sets 640x480, see InitMetrics.
135 Rect->right = GetSystemMetrics(SM_CXSCREEN);
136 Rect->bottom = GetSystemMetrics(SM_CYSCREEN);
137 */ }
138 return TRUE;
139 }
140
141
142 INT FASTCALL
143 IntMapWindowPoints(PWND FromWnd, PWND ToWnd, LPPOINT lpPoints, UINT cPoints)
144 {
145 BOOL mirror_from, mirror_to;
146 POINT Delta;
147 UINT i;
148 int Change = 1;
149
150 /* Note: Desktop Top and Left is always 0! */
151 Delta.x = Delta.y = 0;
152 mirror_from = mirror_to = FALSE;
153
154 if (FromWnd && !UserIsDesktopWindow(FromWnd))
155 {
156 if (FromWnd->ExStyle & WS_EX_LAYOUTRTL)
157 {
158 mirror_from = TRUE;
159 Change = -Change;
160 Delta.x = -FromWnd->rcClient.right;
161 }
162 else
163 Delta.x = FromWnd->rcClient.left;
164 Delta.y = FromWnd->rcClient.top;
165 }
166
167 if (ToWnd && !UserIsDesktopWindow(ToWnd))
168 {
169 if (ToWnd->ExStyle & WS_EX_LAYOUTRTL)
170 {
171 mirror_to = TRUE;
172 Change = -Change;
173 Delta.x += Change * ToWnd->rcClient.right;
174 }
175 else
176 Delta.x -= Change * ToWnd->rcClient.left;
177 Delta.y -= ToWnd->rcClient.top;
178 }
179
180 for (i = 0; i != cPoints; i++)
181 {
182 lpPoints[i].x += Delta.x;
183 lpPoints[i].x *= Change;
184 lpPoints[i].y += Delta.y;
185 }
186
187 if ((mirror_from || mirror_to) && cPoints == 2) /* special case for rectangle */
188 {
189 int tmp = min(lpPoints[0].x, lpPoints[1].x);
190 lpPoints[1].x = max(lpPoints[0].x, lpPoints[1].x);
191 lpPoints[0].x = tmp;
192 }
193
194 return MAKELONG(LOWORD(Delta.x), LOWORD(Delta.y));
195 }
196
197 BOOL FASTCALL
198 IntClientToScreen(PWND Wnd, LPPOINT lpPoint)
199 {
200 if (Wnd && Wnd->fnid != FNID_DESKTOP )
201 {
202 if (Wnd->ExStyle & WS_EX_LAYOUTRTL)
203 lpPoint->x = Wnd->rcClient.right - lpPoint->x;
204 else
205 lpPoint->x += Wnd->rcClient.left;
206 lpPoint->y += Wnd->rcClient.top;
207 }
208 return TRUE;
209 }
210
211 BOOL FASTCALL
212 IntScreenToClient(PWND Wnd, LPPOINT lpPoint)
213 {
214 if (Wnd && Wnd->fnid != FNID_DESKTOP )
215 {
216 if (Wnd->ExStyle & WS_EX_LAYOUTRTL)
217 lpPoint->x = Wnd->rcClient.right - lpPoint->x;
218 else
219 lpPoint->x -= Wnd->rcClient.left;
220 lpPoint->y -= Wnd->rcClient.top;
221 }
222 return TRUE;
223 }
224
225 BOOL FASTCALL IsChildVisible(PWND pWnd)
226 {
227 do
228 {
229 if ( (pWnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD ||
230 !(pWnd = pWnd->spwndParent) )
231 return TRUE;
232 }
233 while (pWnd->style & WS_VISIBLE);
234 return FALSE;
235 }
236
237 PWND FASTCALL IntGetLastTopMostWindow(VOID)
238 {
239 PWND pWnd;
240 PDESKTOP rpdesk = gptiCurrent->rpdesk;
241
242 if ( rpdesk &&
243 (pWnd = rpdesk->pDeskInfo->spwnd->spwndChild) &&
244 pWnd->ExStyle & WS_EX_TOPMOST)
245 {
246 for (;;)
247 {
248 if (!pWnd->spwndNext) break;
249 if (!(pWnd->spwndNext->ExStyle & WS_EX_TOPMOST)) break;
250 pWnd = pWnd->spwndNext;
251 }
252 return pWnd;
253 }
254 return NULL;
255 }
256
257 VOID
258 SelectWindowRgn(PWND Window, HRGN hRgnClip)
259 {
260 if (Window->hrgnClip)
261 {
262 /* Delete no longer needed region handle */
263 IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED);
264 GreDeleteObject(Window->hrgnClip);
265 Window->hrgnClip = NULL;
266 }
267
268 if (hRgnClip > HRGN_WINDOW)
269 {
270 /*if (!UserIsDesktopWindow(Window))
271 {
272 NtGdiOffsetRgn(hRgnClip, Window->rcWindow.left, Window->rcWindow.top);
273 }*/
274 /* Set public ownership */
275 IntGdiSetRegionOwner(hRgnClip, GDI_OBJ_HMGR_PUBLIC);
276
277 Window->hrgnClip = hRgnClip;
278 }
279 }
280
281 //
282 // This helps with CORE-6129 forcing modal dialog active when another app is minimized or closed.
283 //
284 BOOL FASTCALL ActivateOtherWindowMin(PWND Wnd)
285 {
286 BOOL ActivePrev, FindTopWnd;
287 PWND pWndTopMost, pWndChild, pWndSetActive, pWndTemp, pWndDesk;
288 USER_REFERENCE_ENTRY Ref;
289 PTHREADINFO pti = gptiCurrent;
290
291 //ERR("AOWM 1 %p\n",Wnd->head.h);
292 ActivePrev = (pti->MessageQueue->spwndActivePrev != NULL);
293 FindTopWnd = TRUE;
294
295 if ((pWndTopMost = IntGetLastTopMostWindow()))
296 pWndChild = pWndTopMost->spwndNext;
297 else
298 pWndChild = Wnd->spwndParent->spwndChild;
299
300 for (;;)
301 {
302 if ( ActivePrev )
303 pWndSetActive = pti->MessageQueue->spwndActivePrev;
304 else
305 pWndSetActive = pWndChild;
306
307 pWndTemp = NULL;
308
309 while(pWndSetActive)
310 {
311 if ( VerifyWnd(pWndSetActive) &&
312 !(pWndSetActive->ExStyle & WS_EX_NOACTIVATE) &&
313 (pWndSetActive->style & (WS_VISIBLE|WS_DISABLED)) == WS_VISIBLE &&
314 (!(pWndSetActive->style & WS_ICONIC) /* FIXME MinMax pos? */ ) )
315 {
316 if (!(pWndSetActive->ExStyle & WS_EX_TOOLWINDOW) )
317 {
318 UserRefObjectCo(pWndSetActive, &Ref);
319 //ERR("ActivateOtherWindowMin Set FG 1\n");
320 co_IntSetForegroundWindow(pWndSetActive);
321 UserDerefObjectCo(pWndSetActive);
322 //ERR("AOWM 2 Exit Good %p\n",pWndSetActive->head.h);
323 return TRUE;
324 }
325 if (!pWndTemp ) pWndTemp = pWndSetActive;
326 }
327 if ( ActivePrev )
328 {
329 ActivePrev = FALSE;
330 pWndSetActive = pWndChild;
331 }
332 else
333 pWndSetActive = pWndSetActive->spwndNext;
334 }
335
336 if ( !FindTopWnd ) break;
337 FindTopWnd = FALSE;
338
339 if ( pWndChild )
340 {
341 pWndChild = pWndChild->spwndParent->spwndChild;
342 continue;
343 }
344
345 if (!(pWndDesk = IntGetThreadDesktopWindow(pti)))
346 {
347 pWndChild = NULL;
348 continue;
349 }
350 pWndChild = pWndDesk->spwndChild;
351 }
352
353 if ((pWndSetActive = pWndTemp))
354 {
355 UserRefObjectCo(pWndSetActive, &Ref);
356 //ERR("ActivateOtherWindowMin Set FG 2\n");
357 co_IntSetForegroundWindow(pWndSetActive);
358 UserDerefObjectCo(pWndSetActive);
359 //ERR("AOWM 3 Exit Good %p\n",pWndSetActive->head.h);
360 return TRUE;
361 }
362 //ERR("AOWM 4 Bad\n");
363 return FALSE;
364 }
365
366 /*******************************************************************
367 * can_activate_window
368 *
369 * Check if we can activate the specified window.
370 */
371 static
372 BOOL FASTCALL can_activate_window( PWND Wnd OPTIONAL)
373 {
374 LONG style;
375
376 if (!Wnd) return FALSE;
377
378 style = Wnd->style;
379 if (!(style & WS_VISIBLE)) return FALSE;
380 if (style & WS_MINIMIZE) return FALSE;
381 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
382 return TRUE;
383 /* FIXME: This window could be disable because the child that closed
384 was a popup. */
385 //return !(style & WS_DISABLED);
386 }
387
388
389 /*******************************************************************
390 * WinPosActivateOtherWindow
391 *
392 * Activates window other than pWnd.
393 */
394 VOID FASTCALL
395 co_WinPosActivateOtherWindow(PWND Wnd)
396 {
397 PWND WndTo = NULL;
398 USER_REFERENCE_ENTRY Ref;
399
400 ASSERT_REFS_CO(Wnd);
401
402 if (IntIsDesktopWindow(Wnd))
403 {
404 //ERR("WinPosActivateOtherWindow Set Focus Msg Q No window!\n");
405 IntSetFocusMessageQueue(NULL);
406 return;
407 }
408
409 /* If this is popup window, try to activate the owner first. */
410 if ((Wnd->style & WS_POPUP) && (WndTo = Wnd->spwndOwner))
411 {
412 TRACE("WPAOW Popup with Owner\n");
413 WndTo = UserGetAncestor( WndTo, GA_ROOT );
414 if (can_activate_window(WndTo)) goto done;
415 }
416
417 /* Pick a next top-level window. */
418 /* FIXME: Search for non-tooltip windows first. */
419 WndTo = Wnd;
420 for (;;)
421 {
422 if (!(WndTo = WndTo->spwndNext)) break;
423 if (can_activate_window( WndTo )) goto done;
424 }
425
426 /*
427 Fixes wine win.c:test_SetParent last ShowWindow test after popup dies.
428 Check for previous active window to bring to top.
429 */
430 if (Wnd)
431 {
432 WndTo = Wnd->head.pti->MessageQueue->spwndActivePrev;
433 if (can_activate_window( WndTo )) goto done;
434 }
435
436 // Find any window to bring to top. Works Okay for wine since it does not see X11 windows.
437 WndTo = UserGetDesktopWindow();
438 WndTo = WndTo->spwndChild;
439 if ( WndTo == NULL )
440 {
441 //ERR("WinPosActivateOtherWindow No window!\n");
442 return;
443 }
444 for (;;)
445 {
446 if (WndTo == Wnd)
447 {
448 WndTo = NULL;
449 break;
450 }
451 if (can_activate_window( WndTo )) goto done;
452 if (!(WndTo = WndTo->spwndNext)) break;
453 }
454
455 done:
456 if (WndTo) UserRefObjectCo(WndTo, &Ref);
457
458 if (gpqForeground && (!gpqForeground->spwndActive || Wnd == gpqForeground->spwndActive))
459 {
460 /* ReactOS can pass WndTo = NULL to co_IntSetForegroundWindow and returns FALSE. */
461 //ERR("WinPosActivateOtherWindow Set FG 0x%p hWnd %p\n",WndTo, WndTo ? WndTo->head.h : 0);
462 if (co_IntSetForegroundWindow(WndTo))
463 {
464 if (WndTo) UserDerefObjectCo(WndTo);
465 return;
466 }
467 }
468 //ERR("WinPosActivateOtherWindow Set Active 0x%p\n",WndTo);
469 if (!UserSetActiveWindow(WndTo)) /* Ok for WndTo to be NULL here */
470 {
471 //ERR("WPAOW SA 1\n");
472 UserSetActiveWindow(NULL);
473 }
474 if (WndTo) UserDerefObjectCo(WndTo);
475 }
476
477 VOID FASTCALL
478 WinPosInitInternalPos(PWND Wnd, RECTL *RestoreRect)
479 {
480 POINT Size;
481 RECTL Rect = *RestoreRect;
482
483 if (Wnd->spwndParent && !UserIsDesktopWindow(Wnd->spwndParent))
484 {
485 RECTL_vOffsetRect(&Rect,
486 -Wnd->spwndParent->rcClient.left,
487 -Wnd->spwndParent->rcClient.top);
488 }
489
490 Size.x = Rect.left;
491 Size.y = Rect.top;
492
493 if (!Wnd->InternalPosInitialized)
494 {
495 // FIXME: Use check point Atom..
496 Wnd->InternalPos.flags = 0;
497 Wnd->InternalPos.MaxPos.x = Wnd->InternalPos.MaxPos.y = -1;
498 Wnd->InternalPos.IconPos.x = Wnd->InternalPos.IconPos.y = -1;
499 Wnd->InternalPos.NormalRect = Rect;
500 Wnd->InternalPosInitialized = TRUE;
501 }
502
503 if (Wnd->style & WS_MINIMIZE)
504 {
505 Wnd->InternalPos.IconPos = Size;
506 Wnd->InternalPos.flags |= WPF_MININIT;
507 }
508 else if (Wnd->style & WS_MAXIMIZE)
509 {
510 Wnd->InternalPos.flags |= WPF_MAXINIT;
511
512 if ( Wnd->spwndParent == Wnd->head.rpdesk->pDeskInfo->spwnd )
513 {
514 if (Wnd->state & WNDS_MAXIMIZESTOMONITOR)
515 {
516 Wnd->InternalPos.flags &= ~WPF_MAXINIT;
517 Wnd->InternalPos.MaxPos.x = Wnd->InternalPos.MaxPos.y = -1;
518 }
519 else
520 {
521 RECTL WorkArea;
522 PMONITOR pmonitor = UserMonitorFromRect(&Rect, MONITOR_DEFAULTTOPRIMARY );
523 // FIXME: support DPI aware, rcWorkDPI/Real etc..
524 WorkArea = pmonitor->rcMonitor;
525
526 if (Wnd->style & WS_MAXIMIZEBOX)
527 { // Support (Wnd->state & WNDS_HASCAPTION) || pmonitor->cFullScreen too.
528 if ((Wnd->style & WS_CAPTION) == WS_CAPTION || !(Wnd->style & (WS_CHILD | WS_POPUP)))
529 {
530 WorkArea = pmonitor->rcWork;
531 //ERR("rcWork\n");
532 }
533 }
534
535 Wnd->InternalPos.MaxPos.x = Rect.left - WorkArea.left;
536 Wnd->InternalPos.MaxPos.y = Rect.top - WorkArea.top;
537
538 /*ERR("WinPosIP 2 X %d = R.l %d - W.l %d | Y %d = R.t %d - W.t %d\n",
539 Wnd->InternalPos.MaxPos.x,
540 Rect.left, WorkArea.left,
541 Wnd->InternalPos.MaxPos.y,
542 Rect.top, WorkArea.top);*/
543 }
544 }
545 else
546 Wnd->InternalPos.MaxPos = Size;
547 }
548 else
549 {
550 Wnd->InternalPos.NormalRect = Rect;
551 }
552 }
553
554 BOOL
555 FASTCALL
556 IntGetWindowPlacement(PWND Wnd, WINDOWPLACEMENT *lpwndpl)
557 {
558 if (!Wnd) return FALSE;
559
560 if(lpwndpl->length != sizeof(WINDOWPLACEMENT))
561 {
562 return FALSE;
563 }
564
565 lpwndpl->flags = 0;
566
567 WinPosInitInternalPos(Wnd, &Wnd->rcWindow);
568
569 lpwndpl->showCmd = SW_HIDE;
570
571 if ( Wnd->style & WS_MINIMIZE )
572 lpwndpl->showCmd = SW_SHOWMINIMIZED;
573 else
574 lpwndpl->showCmd = ( Wnd->style & WS_MAXIMIZE ) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL ;
575
576 lpwndpl->rcNormalPosition = Wnd->InternalPos.NormalRect;
577
578 if (Wnd->InternalPos.flags & WPF_MININIT) // Return if it was set!
579 {
580 lpwndpl->ptMinPosition.x = Wnd->InternalPos.IconPos.x;
581 lpwndpl->ptMinPosition.y = Wnd->InternalPos.IconPos.y;
582 }
583 else
584 lpwndpl->ptMinPosition.x = lpwndpl->ptMinPosition.y = -1;
585
586 if ( Wnd->InternalPos.flags & WPF_MAXINIT && // Return if set and not maximized to monitor!
587 !(Wnd->state & WNDS_MAXIMIZESTOMONITOR))
588 {
589 lpwndpl->ptMaxPosition.x = Wnd->InternalPos.MaxPos.x;
590 lpwndpl->ptMaxPosition.y = Wnd->InternalPos.MaxPos.y;
591 }
592 else
593 lpwndpl->ptMaxPosition.x = lpwndpl->ptMaxPosition.y = -1;
594
595 if ( Wnd->spwndParent == Wnd->head.rpdesk->pDeskInfo->spwnd &&
596 !(Wnd->ExStyle & WS_EX_TOOLWINDOW))
597 {
598 PMONITOR pmonitor = UserMonitorFromRect(&lpwndpl->rcNormalPosition, MONITOR_DEFAULTTOPRIMARY );
599
600 // FIXME: support DPI aware, rcWorkDPI/Real etc..
601 if (Wnd->InternalPos.flags & WPF_MININIT)
602 {
603 lpwndpl->ptMinPosition.x -= (pmonitor->rcWork.left - pmonitor->rcMonitor.left);
604 lpwndpl->ptMinPosition.y -= (pmonitor->rcWork.top - pmonitor->rcMonitor.top);
605 }
606 RECTL_vOffsetRect(&lpwndpl->rcNormalPosition,
607 pmonitor->rcMonitor.left - pmonitor->rcWork.left,
608 pmonitor->rcMonitor.top - pmonitor->rcWork.top);
609 }
610
611 if ( Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED || Wnd->style & WS_MAXIMIZE )
612 lpwndpl->flags |= WPF_RESTORETOMAXIMIZED;
613
614 if ( ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD) && Wnd->InternalPos.flags & WPF_SETMINPOSITION)
615 lpwndpl->flags |= WPF_SETMINPOSITION;
616
617 return TRUE;
618 }
619
620 /* make sure the specified rect is visible on screen */
621 static void make_rect_onscreen( RECT *rect )
622 {
623 PMONITOR pmonitor = UserMonitorFromRect( rect, MONITOR_DEFAULTTONEAREST ); // Wine uses this.
624
625 // FIXME: support DPI aware, rcWorkDPI/Real etc..
626 if (!pmonitor) return;
627 /* FIXME: map coordinates from rcWork to rcMonitor */
628 if (rect->right <= pmonitor->rcWork.left)
629 {
630 rect->right += pmonitor->rcWork.left - rect->left;
631 rect->left = pmonitor->rcWork.left;
632 }
633 else if (rect->left >= pmonitor->rcWork.right)
634 {
635 rect->left += pmonitor->rcWork.right - rect->right;
636 rect->right = pmonitor->rcWork.right;
637 }
638 if (rect->bottom <= pmonitor->rcWork.top)
639 {
640 rect->bottom += pmonitor->rcWork.top - rect->top;
641 rect->top = pmonitor->rcWork.top;
642 }
643 else if (rect->top >= pmonitor->rcWork.bottom)
644 {
645 rect->top += pmonitor->rcWork.bottom - rect->bottom;
646 rect->bottom = pmonitor->rcWork.bottom;
647 }
648 }
649
650 /* make sure the specified point is visible on screen */
651 static void make_point_onscreen( POINT *pt )
652 {
653 RECT rect;
654
655 RECTL_vSetRect( &rect, pt->x, pt->y, pt->x + 1, pt->y + 1 );
656 make_rect_onscreen( &rect );
657 pt->x = rect.left;
658 pt->y = rect.top;
659 }
660
661 BOOL FASTCALL
662 IntSetWindowPlacement(PWND Wnd, WINDOWPLACEMENT *wpl, UINT Flags)
663 {
664 BOOL sAsync;
665 UINT SWP_Flags;
666
667 if ( Flags & PLACE_MIN) make_point_onscreen( &wpl->ptMinPosition );
668 if ( Flags & PLACE_MAX) make_point_onscreen( &wpl->ptMaxPosition );
669 if ( Flags & PLACE_RECT) make_rect_onscreen( &wpl->rcNormalPosition );
670
671 if (!Wnd || Wnd == Wnd->head.rpdesk->pDeskInfo->spwnd) return FALSE;
672
673 if ( Flags & PLACE_MIN ) Wnd->InternalPos.IconPos = wpl->ptMinPosition;
674 if ( Flags & PLACE_MAX ) Wnd->InternalPos.MaxPos = wpl->ptMaxPosition;
675 if ( Flags & PLACE_RECT) Wnd->InternalPos.NormalRect = wpl->rcNormalPosition;
676
677 SWP_Flags = SWP_NOZORDER | SWP_NOACTIVATE | ((wpl->flags & WPF_ASYNCWINDOWPLACEMENT) ? SWP_ASYNCWINDOWPOS : 0);
678
679 if (Wnd->style & WS_MINIMIZE )
680 {
681 if (Flags & PLACE_MIN || Wnd->InternalPos.flags & WPF_SETMINPOSITION)
682 {
683 co_WinPosSetWindowPos(Wnd, HWND_TOP,
684 wpl->ptMinPosition.x, wpl->ptMinPosition.y, 0, 0,
685 SWP_NOSIZE | SWP_Flags);
686 Wnd->InternalPos.flags |= WPF_MININIT;
687 }
688 }
689 else if (Wnd->style & WS_MAXIMIZE )
690 {
691 if (Flags & PLACE_MAX)
692 {
693 co_WinPosSetWindowPos(Wnd, HWND_TOP,
694 wpl->ptMaxPosition.x, wpl->ptMaxPosition.y, 0, 0,
695 SWP_NOSIZE | SWP_Flags);
696 Wnd->InternalPos.flags |= WPF_MAXINIT;
697 }
698 }
699 else if (Flags & PLACE_RECT)
700 {
701 co_WinPosSetWindowPos(Wnd, HWND_TOP,
702 wpl->rcNormalPosition.left, wpl->rcNormalPosition.top,
703 wpl->rcNormalPosition.right - wpl->rcNormalPosition.left,
704 wpl->rcNormalPosition.bottom - wpl->rcNormalPosition.top,
705 SWP_Flags);
706 }
707
708 sAsync = (Wnd->head.pti->MessageQueue != gptiCurrent->MessageQueue && wpl->flags & WPF_ASYNCWINDOWPLACEMENT);
709
710 if ( sAsync )
711 co_IntSendMessageNoWait( UserHMGetHandle(Wnd), WM_ASYNC_SHOWWINDOW, wpl->showCmd, 0 );
712 else
713 co_WinPosShowWindow(Wnd, wpl->showCmd);
714
715 if ( Wnd->style & WS_MINIMIZE && !sAsync )
716 {
717 if ( wpl->flags & WPF_SETMINPOSITION )
718 Wnd->InternalPos.flags |= WPF_SETMINPOSITION;
719
720 if ( wpl->flags & WPF_RESTORETOMAXIMIZED )
721 Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED;
722 }
723 return TRUE;
724 }
725
726 UINT
727 FASTCALL
728 co_WinPosArrangeIconicWindows(PWND parent)
729 {
730 RECTL rectParent;
731 PWND Child;
732 INT x, y, xspacing, yspacing, sx, sy;
733
734 ASSERT_REFS_CO(parent);
735
736 IntGetClientRect( parent, &rectParent );
737 // FIXME: Support Minimize Metrics gspv.mm.iArrange.
738 // Default: ARW_BOTTOMLEFT
739 x = rectParent.left;
740 y = rectParent.bottom;
741
742 xspacing = UserGetSystemMetrics(SM_CXMINIMIZED);
743 yspacing = UserGetSystemMetrics(SM_CYMINIMIZED);
744
745 Child = parent->spwndChild;
746 while(Child)
747 {
748 if((Child->style & WS_MINIMIZE) != 0 )
749 {
750 USER_REFERENCE_ENTRY Ref;
751 UserRefObjectCo(Child, &Ref);
752
753 sx = x + UserGetSystemMetrics(SM_CXBORDER);
754 sy = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
755
756 Child->InternalPos.IconPos.x = sx;
757 Child->InternalPos.IconPos.y = sy;
758 Child->InternalPos.flags |= WPF_MININIT;
759
760 co_WinPosSetWindowPos( Child, 0, sx, sy, xspacing, yspacing, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_ASYNCWINDOWPOS);
761
762 UserDerefObjectCo(Child);
763
764 if (x <= rectParent.right - xspacing)
765 x += xspacing;
766 else
767 {
768 x = rectParent.left;
769 y -= yspacing;
770 }
771 }
772 Child = Child->spwndNext;
773 }
774 return yspacing;
775 }
776
777 static VOID FASTCALL
778 WinPosFindIconPos(PWND Window, POINT *Pos)
779 {
780 RECT rectParent;
781 PWND pwndChild, pwndParent;
782 int x, y, xspacing, yspacing;
783
784 pwndParent = Window->spwndParent;
785 if (UserIsDesktopWindow(pwndParent))
786 {
787 ERR("FIXME: Parent is Desktop, Min off screen!\n");
788 /* FIXME: ReactOS doesn't support iconic minimize to desktop */
789 Pos->x = Pos->y = -32000;
790 Window->InternalPos.flags |= WPF_MININIT;
791 Window->InternalPos.IconPos.x = Pos->x;
792 Window->InternalPos.IconPos.y = Pos->y;
793 return;
794 }
795
796 IntGetClientRect( pwndParent, &rectParent );
797 // FIXME: Support Minimize Metrics gspv.mm.iArrange.
798 // Default: ARW_BOTTOMLEFT
799 x = rectParent.left;
800 y = rectParent.bottom;
801
802 xspacing = UserGetSystemMetrics(SM_CXMINIMIZED);
803 yspacing = UserGetSystemMetrics(SM_CYMINIMIZED);
804
805 // Set to default position when minimized.
806 Pos->x = x + UserGetSystemMetrics(SM_CXBORDER);
807 Pos->y = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
808
809 for (pwndChild = pwndParent->spwndChild; pwndChild; pwndChild = pwndChild->spwndNext)
810 {
811 if (pwndChild == Window) continue;
812
813 if ((pwndChild->style & (WS_VISIBLE|WS_MINIMIZE)) != (WS_VISIBLE|WS_MINIMIZE) )
814 {
815 continue;
816 }
817
818 if ( pwndChild->InternalPos.IconPos.x != Pos->x && pwndChild->InternalPos.IconPos.y != Pos->y )
819 {
820 break;
821 }
822 if (x <= rectParent.right - xspacing)
823 x += xspacing;
824 else
825 {
826 x = rectParent.left;
827 y -= yspacing;
828 }
829 Pos->x = x + UserGetSystemMetrics(SM_CXBORDER);
830 Pos->y = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
831 }
832
833 Window->InternalPos.IconPos.x = Pos->x;
834 Window->InternalPos.IconPos.y = Pos->y;
835 Window->InternalPos.flags |= WPF_MININIT;
836 TRACE("Position is set! X:%d Y:%d\n",Pos->x,Pos->y);
837 return;
838 }
839
840 BOOL
841 UserHasWindowEdge(DWORD Style, DWORD ExStyle)
842 {
843 if (Style & WS_MINIMIZE)
844 return TRUE;
845 if (ExStyle & WS_EX_DLGMODALFRAME)
846 return TRUE;
847 if (ExStyle & WS_EX_STATICEDGE)
848 return FALSE;
849 if (Style & WS_THICKFRAME)
850 return TRUE;
851 Style &= WS_CAPTION;
852 if (Style == WS_DLGFRAME || Style == WS_CAPTION)
853 return TRUE;
854 return FALSE;
855 }
856
857 VOID FASTCALL
858 IntGetWindowBorderMeasures(PWND Wnd, UINT *cx, UINT *cy)
859 {
860 if(HAS_DLGFRAME(Wnd->style, Wnd->ExStyle) && !(Wnd->style & WS_MINIMIZE))
861 {
862 *cx = UserGetSystemMetrics(SM_CXDLGFRAME);
863 *cy = UserGetSystemMetrics(SM_CYDLGFRAME);
864 }
865 else
866 {
867 if(HAS_THICKFRAME(Wnd->style, Wnd->ExStyle)&& !(Wnd->style & WS_MINIMIZE))
868 {
869 *cx = UserGetSystemMetrics(SM_CXFRAME);
870 *cy = UserGetSystemMetrics(SM_CYFRAME);
871 }
872 else if(HAS_THINFRAME(Wnd->style, Wnd->ExStyle))
873 {
874 *cx = UserGetSystemMetrics(SM_CXBORDER);
875 *cy = UserGetSystemMetrics(SM_CYBORDER);
876 }
877 else
878 {
879 *cx = *cy = 0;
880 }
881 }
882 }
883
884 VOID
885 UserGetWindowBorders(DWORD Style, DWORD ExStyle, SIZE *Size, BOOL WithClient)
886 {
887 DWORD Border = 0;
888
889 if (UserHasWindowEdge(Style, ExStyle))
890 Border += 2;
891 else if (ExStyle & WS_EX_STATICEDGE)
892 Border += 1;
893 if ((ExStyle & WS_EX_CLIENTEDGE) && WithClient)
894 Border += 2;
895 if (Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME)
896 Border ++;
897 Size->cx = Size->cy = Border;
898 if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
899 {
900 Size->cx += UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME);
901 Size->cy += UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME);
902 }
903 Size->cx *= UserGetSystemMetrics(SM_CXBORDER);
904 Size->cy *= UserGetSystemMetrics(SM_CYBORDER);
905 }
906
907 BOOL WINAPI
908 UserAdjustWindowRectEx(LPRECT lpRect,
909 DWORD dwStyle,
910 BOOL bMenu,
911 DWORD dwExStyle)
912 {
913 SIZE BorderSize;
914
915 if (bMenu)
916 {
917 lpRect->top -= UserGetSystemMetrics(SM_CYMENU);
918 }
919 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
920 {
921 if (dwExStyle & WS_EX_TOOLWINDOW)
922 lpRect->top -= UserGetSystemMetrics(SM_CYSMCAPTION);
923 else
924 lpRect->top -= UserGetSystemMetrics(SM_CYCAPTION);
925 }
926 UserGetWindowBorders(dwStyle, dwExStyle, &BorderSize, TRUE);
927 RECTL_vInflateRect(
928 lpRect,
929 BorderSize.cx,
930 BorderSize.cy);
931
932 return TRUE;
933 }
934
935 UINT FASTCALL
936 co_WinPosGetMinMaxInfo(PWND Window, POINT* MaxSize, POINT* MaxPos,
937 POINT* MinTrack, POINT* MaxTrack)
938 {
939 MINMAXINFO MinMax;
940 PMONITOR monitor;
941 INT xinc, yinc;
942 LONG style = Window->style;
943 LONG adjustedStyle;
944 LONG exstyle = Window->ExStyle;
945 RECT rc;
946
947 ASSERT_REFS_CO(Window);
948
949 /* Compute default values */
950
951 rc = Window->rcWindow;
952 MinMax.ptReserved.x = rc.left;
953 MinMax.ptReserved.y = rc.top;
954
955 if ((style & WS_CAPTION) == WS_CAPTION)
956 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
957 else
958 adjustedStyle = style;
959
960 if(Window->spwndParent)
961 IntGetClientRect(Window->spwndParent, &rc);
962 UserAdjustWindowRectEx(&rc, adjustedStyle, ((style & WS_POPUP) && Window->IDMenu), exstyle);
963
964 xinc = -rc.left;
965 yinc = -rc.top;
966
967 MinMax.ptMaxSize.x = rc.right - rc.left;
968 MinMax.ptMaxSize.y = rc.bottom - rc.top;
969 if (style & (WS_DLGFRAME | WS_BORDER))
970 {
971 MinMax.ptMinTrackSize.x = UserGetSystemMetrics(SM_CXMINTRACK);
972 MinMax.ptMinTrackSize.y = UserGetSystemMetrics(SM_CYMINTRACK);
973 }
974 else
975 {
976 MinMax.ptMinTrackSize.x = 2 * xinc;
977 MinMax.ptMinTrackSize.y = 2 * yinc;
978 }
979 MinMax.ptMaxTrackSize.x = UserGetSystemMetrics(SM_CXMAXTRACK);
980 MinMax.ptMaxTrackSize.y = UserGetSystemMetrics(SM_CYMAXTRACK);
981 MinMax.ptMaxPosition.x = -xinc;
982 MinMax.ptMaxPosition.y = -yinc;
983
984 if (!EMPTYPOINT(Window->InternalPos.MaxPos)) MinMax.ptMaxPosition = Window->InternalPos.MaxPos;
985
986 co_IntSendMessage(Window->head.h, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax);
987
988 /* if the app didn't change the values, adapt them for the current monitor */
989 if ((monitor = UserGetPrimaryMonitor()))
990 {
991 RECT rc_work;
992
993 rc_work = monitor->rcMonitor;
994
995 if (style & WS_MAXIMIZEBOX)
996 {
997 if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP)))
998 rc_work = monitor->rcWork;
999 }
1000
1001 if (MinMax.ptMaxSize.x == UserGetSystemMetrics(SM_CXSCREEN) + 2 * xinc &&
1002 MinMax.ptMaxSize.y == UserGetSystemMetrics(SM_CYSCREEN) + 2 * yinc)
1003 {
1004 MinMax.ptMaxSize.x = (rc_work.right - rc_work.left) + 2 * xinc;
1005 MinMax.ptMaxSize.y = (rc_work.bottom - rc_work.top) + 2 * yinc;
1006 }
1007 if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc)
1008 {
1009 MinMax.ptMaxPosition.x = rc_work.left - xinc;
1010 MinMax.ptMaxPosition.y = rc_work.top - yinc;
1011 }
1012 if (MinMax.ptMaxSize.x >= (monitor->rcMonitor.right - monitor->rcMonitor.left) &&
1013 MinMax.ptMaxSize.y >= (monitor->rcMonitor.bottom - monitor->rcMonitor.top) )
1014 Window->state |= WNDS_MAXIMIZESTOMONITOR;
1015 else
1016 Window->state &= ~WNDS_MAXIMIZESTOMONITOR;
1017 }
1018
1019
1020 MinMax.ptMaxTrackSize.x = max(MinMax.ptMaxTrackSize.x,
1021 MinMax.ptMinTrackSize.x);
1022 MinMax.ptMaxTrackSize.y = max(MinMax.ptMaxTrackSize.y,
1023 MinMax.ptMinTrackSize.y);
1024
1025 if (MaxSize)
1026 *MaxSize = MinMax.ptMaxSize;
1027 if (MaxPos)
1028 *MaxPos = MinMax.ptMaxPosition;
1029 if (MinTrack)
1030 *MinTrack = MinMax.ptMinTrackSize;
1031 if (MaxTrack)
1032 *MaxTrack = MinMax.ptMaxTrackSize;
1033
1034 return 0; // FIXME: What does it return?
1035 }
1036
1037 static
1038 BOOL
1039 IntValidateParent(PWND Child, PREGION ValidateRgn)
1040 {
1041 PWND ParentWnd = Child;
1042
1043 if (ParentWnd->style & WS_CHILD)
1044 {
1045 do
1046 ParentWnd = ParentWnd->spwndParent;
1047 while (ParentWnd->style & WS_CHILD);
1048 }
1049
1050 ParentWnd = Child->spwndParent;
1051 while (ParentWnd)
1052 {
1053 if (ParentWnd->style & WS_CLIPCHILDREN)
1054 break;
1055
1056 if (ParentWnd->hrgnUpdate != 0)
1057 {
1058 IntInvalidateWindows( ParentWnd,
1059 ValidateRgn,
1060 RDW_VALIDATE | RDW_NOCHILDREN);
1061 }
1062
1063 ParentWnd = ParentWnd->spwndParent;
1064 }
1065
1066 return TRUE;
1067 }
1068
1069 static
1070 VOID FASTCALL
1071 FixClientRect(PRECTL ClientRect, PRECTL WindowRect)
1072 {
1073 if (ClientRect->left < WindowRect->left)
1074 {
1075 ClientRect->left = WindowRect->left;
1076 }
1077 else if (WindowRect->right < ClientRect->left)
1078 {
1079 ClientRect->left = WindowRect->right;
1080 }
1081 if (ClientRect->right < WindowRect->left)
1082 {
1083 ClientRect->right = WindowRect->left;
1084 }
1085 else if (WindowRect->right < ClientRect->right)
1086 {
1087 ClientRect->right = WindowRect->right;
1088 }
1089 if (ClientRect->top < WindowRect->top)
1090 {
1091 ClientRect->top = WindowRect->top;
1092 }
1093 else if (WindowRect->bottom < ClientRect->top)
1094 {
1095 ClientRect->top = WindowRect->bottom;
1096 }
1097 if (ClientRect->bottom < WindowRect->top)
1098 {
1099 ClientRect->bottom = WindowRect->top;
1100 }
1101 else if (WindowRect->bottom < ClientRect->bottom)
1102 {
1103 ClientRect->bottom = WindowRect->bottom;
1104 }
1105 }
1106 /***********************************************************************
1107 * get_valid_rects
1108 *
1109 * Compute the valid rects from the old and new client rect and WVR_* flags.
1110 * Helper for WM_NCCALCSIZE handling.
1111 */
1112 static
1113 VOID FASTCALL
1114 get_valid_rects( RECTL *old_client, RECTL *new_client, UINT flags, RECTL *valid )
1115 {
1116 int cx, cy;
1117
1118 if (flags & WVR_REDRAW)
1119 {
1120 RECTL_vSetEmptyRect( &valid[0] );
1121 RECTL_vSetEmptyRect( &valid[1] );
1122 return;
1123 }
1124
1125 if (flags & WVR_VALIDRECTS)
1126 {
1127 if (!RECTL_bIntersectRect( &valid[0], &valid[0], new_client ) ||
1128 !RECTL_bIntersectRect( &valid[1], &valid[1], old_client ))
1129 {
1130 RECTL_vSetEmptyRect( &valid[0] );
1131 RECTL_vSetEmptyRect( &valid[1] );
1132 return;
1133 }
1134 flags = WVR_ALIGNLEFT | WVR_ALIGNTOP;
1135 }
1136 else
1137 {
1138 valid[0] = *new_client;
1139 valid[1] = *old_client;
1140 }
1141
1142 /* make sure the rectangles have the same size */
1143 cx = min( valid[0].right - valid[0].left, valid[1].right - valid[1].left );
1144 cy = min( valid[0].bottom - valid[0].top, valid[1].bottom - valid[1].top );
1145
1146 if (flags & WVR_ALIGNBOTTOM)
1147 {
1148 valid[0].top = valid[0].bottom - cy;
1149 valid[1].top = valid[1].bottom - cy;
1150 }
1151 else
1152 {
1153 valid[0].bottom = valid[0].top + cy;
1154 valid[1].bottom = valid[1].top + cy;
1155 }
1156 if (flags & WVR_ALIGNRIGHT)
1157 {
1158 valid[0].left = valid[0].right - cx;
1159 valid[1].left = valid[1].right - cx;
1160 }
1161 else
1162 {
1163 valid[0].right = valid[0].left + cx;
1164 valid[1].right = valid[1].left + cx;
1165 }
1166 }
1167
1168 static
1169 LONG FASTCALL
1170 co_WinPosDoNCCALCSize(PWND Window, PWINDOWPOS WinPos, RECTL* WindowRect, RECTL* ClientRect, RECTL* validRects)
1171 {
1172 PWND Parent;
1173 UINT wvrFlags = 0;
1174
1175 ASSERT_REFS_CO(Window);
1176
1177 /* Send WM_NCCALCSIZE message to get new client area */
1178 if ((WinPos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE)
1179 {
1180 NCCALCSIZE_PARAMS params;
1181 WINDOWPOS winposCopy;
1182
1183 params.rgrc[0] = *WindowRect; // new coordinates of a window that has been moved or resized
1184 params.rgrc[1] = Window->rcWindow; // window before it was moved or resized
1185 params.rgrc[2] = Window->rcClient; // client area before the window was moved or resized
1186
1187 Parent = Window->spwndParent;
1188 if (0 != (Window->style & WS_CHILD) && Parent)
1189 {
1190 RECTL_vOffsetRect(&(params.rgrc[0]), - Parent->rcClient.left, - Parent->rcClient.top);
1191 RECTL_vOffsetRect(&(params.rgrc[1]), - Parent->rcClient.left, - Parent->rcClient.top);
1192 RECTL_vOffsetRect(&(params.rgrc[2]), - Parent->rcClient.left, - Parent->rcClient.top);
1193 }
1194
1195 params.lppos = &winposCopy;
1196 winposCopy = *WinPos;
1197
1198 wvrFlags = co_IntSendMessage(Window->head.h, WM_NCCALCSIZE, TRUE, (LPARAM) &params);
1199
1200 /* If the application send back garbage, ignore it */
1201 if (params.rgrc[0].left <= params.rgrc[0].right &&
1202 params.rgrc[0].top <= params.rgrc[0].bottom)
1203 {
1204 *ClientRect = params.rgrc[0]; // First rectangle contains the coordinates of the new client rectangle resulting from the move or resize
1205 if ((Window->style & WS_CHILD) && Parent)
1206 {
1207 RECTL_vOffsetRect(ClientRect, Parent->rcClient.left, Parent->rcClient.top);
1208 }
1209 FixClientRect(ClientRect, WindowRect);
1210 }
1211
1212 if (ClientRect->left != Window->rcClient.left ||
1213 ClientRect->top != Window->rcClient.top)
1214 {
1215 WinPos->flags &= ~SWP_NOCLIENTMOVE;
1216 }
1217
1218 if (ClientRect->right - ClientRect->left != Window->rcClient.right - Window->rcClient.left)
1219 {
1220 WinPos->flags &= ~SWP_NOCLIENTSIZE;
1221 }
1222 else
1223 wvrFlags &= ~WVR_HREDRAW;
1224
1225 if (ClientRect->bottom - ClientRect->top != Window->rcClient.bottom - Window->rcClient.top)
1226 {
1227 WinPos->flags &= ~SWP_NOCLIENTSIZE;
1228 }
1229 else
1230 wvrFlags &= ~WVR_VREDRAW;
1231
1232 validRects[0] = params.rgrc[1]; // second rectangle contains the valid destination rectangle
1233 validRects[1] = params.rgrc[2]; // third rectangle contains the valid source rectangle
1234 }
1235 else
1236 {
1237 if (!(WinPos->flags & SWP_NOMOVE) &&
1238 (ClientRect->left != Window->rcClient.left ||
1239 ClientRect->top != Window->rcClient.top))
1240 {
1241 WinPos->flags &= ~SWP_NOCLIENTMOVE;
1242 }
1243 }
1244
1245 if (WinPos->flags & (SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_HIDEWINDOW))
1246 {
1247 RECTL_vSetEmptyRect( &validRects[0] );
1248 RECTL_vSetEmptyRect( &validRects[1] );
1249 }
1250 else get_valid_rects( &Window->rcClient, ClientRect, wvrFlags, validRects );
1251
1252 return wvrFlags;
1253 }
1254
1255 static
1256 BOOL FASTCALL
1257 co_WinPosDoWinPosChanging(PWND Window,
1258 PWINDOWPOS WinPos,
1259 PRECTL WindowRect,
1260 PRECTL ClientRect)
1261 {
1262 ASSERT_REFS_CO(Window);
1263
1264 /* Send WM_WINDOWPOSCHANGING message */
1265
1266 if (!(WinPos->flags & SWP_NOSENDCHANGING))
1267 {
1268 TRACE("Sending WM_WINDOWPOSCHANGING to hwnd %p flags %04x.\n", Window->head.h,WinPos->flags);
1269 co_IntSendMessage(Window->head.h, WM_WINDOWPOSCHANGING, 0, (LPARAM) WinPos);
1270 }
1271
1272 /* Calculate new position and size */
1273
1274 *WindowRect = Window->rcWindow;
1275 *ClientRect = (Window->style & WS_MINIMIZE) ? Window->rcWindow : Window->rcClient;
1276
1277 if (!(WinPos->flags & SWP_NOSIZE))
1278 {
1279 if (Window->style & WS_MINIMIZE)
1280 {
1281 WindowRect->right = WindowRect->left + UserGetSystemMetrics(SM_CXMINIMIZED);
1282 WindowRect->bottom = WindowRect->top + UserGetSystemMetrics(SM_CYMINIMIZED);
1283 }
1284 else
1285 {
1286 WindowRect->right = WindowRect->left + WinPos->cx;
1287 WindowRect->bottom = WindowRect->top + WinPos->cy;
1288 }
1289 }
1290
1291 if (!(WinPos->flags & SWP_NOMOVE))
1292 {
1293 INT X, Y;
1294 PWND Parent;
1295 X = WinPos->x;
1296 Y = WinPos->y;
1297
1298 Parent = Window->spwndParent;
1299
1300 // Parent child position issue is in here. SetParent_W7 test CORE-6651.
1301 if (//((Window->style & WS_CHILD) != 0) && <- Fixes wine msg test_SetParent: "rects do not match", the last test.
1302 Parent &&
1303 Parent != Window->head.rpdesk->pDeskInfo->spwnd)
1304 {
1305 TRACE("Not SWP_NOMOVE 1 Parent client offset X %d Y %d\n",X,Y);
1306 X += Parent->rcClient.left;
1307 Y += Parent->rcClient.top;
1308 TRACE("Not SWP_NOMOVE 2 Parent client offset X %d Y %d\n",X,Y);
1309 }
1310
1311 WindowRect->left = X;
1312 WindowRect->top = Y;
1313 WindowRect->right += X - Window->rcWindow.left;
1314 WindowRect->bottom += Y - Window->rcWindow.top;
1315
1316 RECTL_vOffsetRect(ClientRect, X - Window->rcWindow.left,
1317 Y - Window->rcWindow.top);
1318 }
1319 WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
1320
1321 TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
1322 WinPos->hwnd, WinPos->hwndInsertAfter, WinPos->x, WinPos->y,
1323 WinPos->cx, WinPos->cy, WinPos->flags );
1324 TRACE("WindowRect: %d %d %d %d\n", WindowRect->left,WindowRect->top,WindowRect->right,WindowRect->bottom);
1325 TRACE("ClientRect: %d %d %d %d\n", ClientRect->left,ClientRect->top,ClientRect->right,ClientRect->bottom);
1326
1327 return TRUE;
1328 }
1329
1330 /*
1331 * Fix Z order taking into account owned popups -
1332 * basically we need to maintain them above the window that owns them
1333 *
1334 * FIXME: hide/show owned popups when owner visibility changes.
1335 *
1336 * ReactOS: See bug CORE-6129 and CORE-6554.
1337 *
1338 */
1339 ////
1340 // Pass all the win:test_children/popup_zorder tests except "move hwnd_F and its popups down" which is if'ed out.
1341 // Side effect, breaks more of the DeferWindowPos api tests, but wine breaks more!!!!
1342 static
1343 HWND FASTCALL
1344 WinPosDoOwnedPopups(PWND Window, HWND hWndInsertAfter)
1345 {
1346 HWND *List = NULL;
1347 HWND Owner;
1348 LONG Style;
1349 PWND DesktopWindow, ChildObject;
1350 int i;
1351
1352 TRACE("(%p) hInsertAfter = %p\n", Window, hWndInsertAfter );
1353
1354 Style = Window->style;
1355
1356 if (Style & WS_CHILD)
1357 {
1358 TRACE("Window is child\n");
1359 return hWndInsertAfter;
1360 }
1361
1362 Owner = Window->spwndOwner ? Window->spwndOwner->head.h : NULL;
1363
1364 if (Owner)
1365 {
1366 /* Make sure this popup stays above the owner */
1367
1368 if (hWndInsertAfter != HWND_TOPMOST)
1369 {
1370 DesktopWindow = UserGetDesktopWindow();
1371 List = IntWinListChildren(DesktopWindow);
1372
1373 if (List != NULL)
1374 {
1375 for (i = 0; List[i]; i++)
1376 {
1377 BOOL topmost = FALSE;
1378
1379 ChildObject = ValidateHwndNoErr(List[i]);
1380 if (ChildObject)
1381 {
1382 topmost = (ChildObject->ExStyle & WS_EX_TOPMOST) != 0;
1383 }
1384
1385 if (List[i] == Owner)
1386 {
1387 if (i > 0) hWndInsertAfter = List[i-1];
1388 else hWndInsertAfter = topmost ? HWND_TOPMOST : HWND_TOP;
1389 break;
1390 }
1391
1392 if (hWndInsertAfter == HWND_TOP || hWndInsertAfter == HWND_NOTOPMOST)
1393 {
1394 if (!topmost) break;
1395 }
1396 else if (List[i] == hWndInsertAfter) break;
1397 }
1398 }
1399 else
1400 return hWndInsertAfter;
1401 }
1402 }
1403
1404 if (hWndInsertAfter == HWND_BOTTOM)
1405 {
1406 ERR("Window is HWND_BOTTOM hwnd %p\n",hWndInsertAfter);
1407 if (List) ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1408 goto done;
1409 }
1410
1411 if (!List)
1412 {
1413 DesktopWindow = UserGetDesktopWindow();
1414 List = IntWinListChildren(DesktopWindow);
1415 }
1416
1417 if (List != NULL)
1418 {
1419 i = 0;
1420
1421 if (hWndInsertAfter == HWND_TOP || hWndInsertAfter == HWND_NOTOPMOST)
1422 {
1423 if (hWndInsertAfter == HWND_NOTOPMOST || !(Window->ExStyle & WS_EX_TOPMOST))
1424 {
1425 TRACE("skip all the topmost windows\n");
1426 /* skip all the topmost windows */
1427 while (List[i] &&
1428 (ChildObject = ValidateHwndNoErr(List[i])) &&
1429 (ChildObject->ExStyle & WS_EX_TOPMOST)) i++;
1430 }
1431 }
1432 else if (hWndInsertAfter != HWND_TOPMOST)
1433 {
1434 /* skip windows that are already placed correctly */
1435 for (i = 0; List[i]; i++)
1436 {
1437 if (List[i] == hWndInsertAfter) break;
1438 if (List[i] == UserHMGetHandle(Window))
1439 {
1440 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1441 goto done; /* nothing to do if window is moving backwards in z-order */
1442 }
1443 }
1444 }
1445
1446 for (; List[i]; i++)
1447 {
1448 PWND Wnd;
1449 USER_REFERENCE_ENTRY Ref;
1450
1451 if (List[i] == UserHMGetHandle(Window))
1452 break;
1453
1454 if (!(Wnd = ValidateHwndNoErr(List[i])))
1455 continue;
1456
1457 Owner = Wnd->spwndOwner ? Wnd->spwndOwner->head.h : NULL;
1458
1459 if (Owner != UserHMGetHandle(Window)) continue;
1460
1461 UserRefObjectCo(Wnd, &Ref);
1462 TRACE( "moving %p owned by %p after %p\n", List[i], UserHMGetHandle(Window), hWndInsertAfter );
1463 co_WinPosSetWindowPos(Wnd, hWndInsertAfter, 0, 0, 0, 0,
1464 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING| SWP_DEFERERASE);
1465
1466 UserDerefObjectCo(Wnd);
1467 hWndInsertAfter = List[i];
1468 }
1469 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1470 }
1471 done:
1472 return hWndInsertAfter;
1473 }
1474 ////
1475
1476 /***********************************************************************
1477 * WinPosInternalMoveWindow
1478 *
1479 * Update WindowRect and ClientRect of Window and all of its children
1480 * We keep both WindowRect and ClientRect in screen coordinates internally
1481 */
1482 static
1483 VOID FASTCALL
1484 WinPosInternalMoveWindow(PWND Window, INT MoveX, INT MoveY)
1485 {
1486 PWND Child;
1487
1488 ASSERT(Window != Window->spwndChild);
1489 TRACE("InternalMoveWin X %d Y %d\n", MoveX, MoveY);
1490
1491 Window->rcWindow.left += MoveX;
1492 Window->rcWindow.right += MoveX;
1493 Window->rcWindow.top += MoveY;
1494 Window->rcWindow.bottom += MoveY;
1495
1496 Window->rcClient.left += MoveX;
1497 Window->rcClient.right += MoveX;
1498 Window->rcClient.top += MoveY;
1499 Window->rcClient.bottom += MoveY;
1500
1501 for(Child = Window->spwndChild; Child; Child = Child->spwndNext)
1502 {
1503 WinPosInternalMoveWindow(Child, MoveX, MoveY);
1504 }
1505 }
1506
1507 /*
1508 * WinPosFixupSWPFlags
1509 *
1510 * Fix redundant flags and values in the WINDOWPOS structure.
1511 */
1512 static
1513 BOOL FASTCALL
1514 WinPosFixupFlags(WINDOWPOS *WinPos, PWND Wnd)
1515 {
1516 PWND Parent;
1517 POINT pt;
1518
1519 /* Finally make sure that all coordinates are valid */
1520 if (WinPos->x < -32768) WinPos->x = -32768;
1521 else if (WinPos->x > 32767) WinPos->x = 32767;
1522 if (WinPos->y < -32768) WinPos->y = -32768;
1523 else if (WinPos->y > 32767) WinPos->y = 32767;
1524
1525 WinPos->cx = max(WinPos->cx, 0);
1526 WinPos->cy = max(WinPos->cy, 0);
1527
1528 Parent = UserGetAncestor( Wnd, GA_PARENT );
1529 if (!IntIsWindowVisible( Parent ) &&
1530 /* Fix B : wine msg test_SetParent:WmSetParentSeq_2:25 wParam bits! */
1531 (WinPos->flags & SWP_AGG_STATUSFLAGS) == SWP_AGG_NOPOSCHANGE) WinPos->flags |= SWP_NOREDRAW;
1532
1533 if (Wnd->style & WS_VISIBLE) WinPos->flags &= ~SWP_SHOWWINDOW;
1534 else
1535 {
1536 WinPos->flags &= ~SWP_HIDEWINDOW;
1537 if (!(WinPos->flags & SWP_SHOWWINDOW)) WinPos->flags |= SWP_NOREDRAW;
1538 }
1539
1540 /* Check for right size */
1541 if (Wnd->rcWindow.right - Wnd->rcWindow.left == WinPos->cx &&
1542 Wnd->rcWindow.bottom - Wnd->rcWindow.top == WinPos->cy)
1543 {
1544 WinPos->flags |= SWP_NOSIZE;
1545 }
1546
1547 pt.x = WinPos->x;
1548 pt.y = WinPos->y;
1549 IntClientToScreen( Parent, &pt );
1550 TRACE("WPFU C2S wpx %d wpy %d ptx %d pty %d\n",WinPos->x,WinPos->y,pt.x,pt.y);
1551 /* Check for right position */
1552 if (Wnd->rcWindow.left == pt.x && Wnd->rcWindow.top == pt.y)
1553 {
1554 //ERR("In right pos\n");
1555 WinPos->flags |= SWP_NOMOVE;
1556 }
1557
1558 if ( WinPos->hwnd != UserGetForegroundWindow() && (Wnd->style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
1559 {
1560 /* Bring to the top when activating */
1561 if (!(WinPos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)) &&
1562 (WinPos->flags & SWP_NOZORDER ||
1563 (WinPos->hwndInsertAfter != HWND_TOPMOST && WinPos->hwndInsertAfter != HWND_NOTOPMOST)))
1564 {
1565 WinPos->flags &= ~SWP_NOZORDER;
1566 WinPos->hwndInsertAfter = (0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP);
1567 }
1568 }
1569
1570 /* Check hwndInsertAfter */
1571 if (!(WinPos->flags & SWP_NOZORDER))
1572 {
1573 /* Fix sign extension */
1574 if (WinPos->hwndInsertAfter == (HWND)0xffff)
1575 {
1576 WinPos->hwndInsertAfter = HWND_TOPMOST;
1577 }
1578 else if (WinPos->hwndInsertAfter == (HWND)0xfffe)
1579 {
1580 WinPos->hwndInsertAfter = HWND_NOTOPMOST;
1581 }
1582
1583 if (WinPos->hwndInsertAfter == HWND_TOP)
1584 {
1585 /* Keep it topmost when it's already topmost */
1586 if ((Wnd->ExStyle & WS_EX_TOPMOST) != 0)
1587 WinPos->hwndInsertAfter = HWND_TOPMOST;
1588
1589 if (IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd)
1590 {
1591 WinPos->flags |= SWP_NOZORDER;
1592 }
1593 }
1594 else if (WinPos->hwndInsertAfter == HWND_BOTTOM)
1595 {
1596 if (!(Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDLAST) == WinPos->hwnd)
1597 WinPos->flags |= SWP_NOZORDER;
1598 }
1599 else if (WinPos->hwndInsertAfter == HWND_TOPMOST)
1600 {
1601 if ((Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd)
1602 WinPos->flags |= SWP_NOZORDER;
1603 }
1604 else if (WinPos->hwndInsertAfter == HWND_NOTOPMOST)
1605 {
1606 if (!(Wnd->ExStyle & WS_EX_TOPMOST))
1607 WinPos->flags |= SWP_NOZORDER;
1608 }
1609 else /* hwndInsertAfter must be a sibling of the window */
1610 {
1611 PWND InsAfterWnd;
1612
1613 InsAfterWnd = ValidateHwndNoErr(WinPos->hwndInsertAfter);
1614 if(!InsAfterWnd)
1615 {
1616 return TRUE;
1617 }
1618
1619 if (InsAfterWnd->spwndParent != Wnd->spwndParent)
1620 {
1621 /* Note from wine User32 Win test_SetWindowPos:
1622 "Returns TRUE also for windows that are not siblings"
1623 "Does not seem to do anything even without passing flags, still returns TRUE"
1624 "Same thing the other way around."
1625 ".. and with these windows."
1626 */
1627 return FALSE;
1628 }
1629 else
1630 {
1631 /*
1632 * We don't need to change the Z order of hwnd if it's already
1633 * inserted after hwndInsertAfter or when inserting hwnd after
1634 * itself.
1635 */
1636 if ((WinPos->hwnd == WinPos->hwndInsertAfter) ||
1637 ((InsAfterWnd->spwndNext) && (WinPos->hwnd == InsAfterWnd->spwndNext->head.h)))
1638 {
1639 WinPos->flags |= SWP_NOZORDER;
1640 }
1641 }
1642 }
1643 }
1644
1645 return TRUE;
1646 }
1647
1648 /* x and y are always screen relative */
1649 BOOLEAN FASTCALL
1650 co_WinPosSetWindowPos(
1651 PWND Window,
1652 HWND WndInsertAfter,
1653 INT x,
1654 INT y,
1655 INT cx,
1656 INT cy,
1657 UINT flags
1658 )
1659 {
1660 WINDOWPOS WinPos;
1661 RECTL NewWindowRect;
1662 RECTL NewClientRect;
1663 RECTL valid_rects[2];
1664 PREGION VisBefore = NULL;
1665 PREGION VisBeforeJustClient = NULL;
1666 PREGION VisAfter = NULL;
1667 PREGION CopyRgn = NULL;
1668 ULONG WvrFlags = 0;
1669 RECTL OldWindowRect, OldClientRect;
1670 int RgnType;
1671 HDC Dc;
1672 RECTL CopyRect;
1673 PWND Ancestor;
1674 BOOL bPointerInWindow, PosChanged = FALSE;
1675 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1676
1677 ASSERT_REFS_CO(Window);
1678
1679 TRACE("pwnd %p, after %p, %d,%d (%dx%d), flags %s",
1680 Window, WndInsertAfter, x, y, cx, cy, flags);
1681 #if DBG
1682 dump_winpos_flags(flags);
1683 #endif
1684
1685 /* FIXME: Get current active window from active queue. Why? since r2915. */
1686
1687 bPointerInWindow = IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y);
1688
1689 WinPos.hwnd = Window->head.h;
1690 WinPos.hwndInsertAfter = WndInsertAfter;
1691 WinPos.x = x;
1692 WinPos.y = y;
1693 WinPos.cx = cx;
1694 WinPos.cy = cy;
1695 WinPos.flags = flags;
1696
1697 if ( flags & SWP_ASYNCWINDOWPOS )
1698 {
1699 LRESULT lRes;
1700 PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
1701 if ( ppos )
1702 {
1703 WinPos.flags &= ~SWP_ASYNCWINDOWPOS; // Clear flag.
1704 *ppos = WinPos;
1705 /* Yes it's a pointer inside Win32k! */
1706 lRes = co_IntSendMessageNoWait( WinPos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
1707 /* We handle this the same way as Event Hooks and Hooks. */
1708 if ( !lRes )
1709 {
1710 ExFreePoolWithTag(ppos, USERTAG_SWP);
1711 return FALSE;
1712 }
1713 return TRUE;
1714 }
1715 return FALSE;
1716 }
1717
1718 co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
1719
1720 /* Does the window still exist? */
1721 if (!IntIsWindow(WinPos.hwnd))
1722 {
1723 TRACE("WinPosSetWindowPos: Invalid handle 0x%p!\n",WinPos.hwnd);
1724 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
1725 return FALSE;
1726 }
1727
1728 /* Fix up the flags. */
1729 if (!WinPosFixupFlags(&WinPos, Window))
1730 {
1731 // See Note.
1732 return TRUE;
1733 }
1734
1735 Ancestor = UserGetAncestor(Window, GA_PARENT);
1736 if ( (WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER &&
1737 Ancestor && Ancestor->head.h == IntGetDesktopWindow() )
1738 {
1739 WinPos.hwndInsertAfter = WinPosDoOwnedPopups(Window, WinPos.hwndInsertAfter);
1740 }
1741
1742 if (!(WinPos.flags & SWP_NOREDRAW))
1743 {
1744 /* Compute the visible region before the window position is changed */
1745 if (!(WinPos.flags & SWP_SHOWWINDOW) &&
1746 (WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
1747 SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
1748 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
1749 {
1750 VisBefore = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1751 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1752
1753 if ( VisBefore != NULL &&
1754 REGION_Complexity(VisBefore) == NULLREGION )
1755 {
1756 REGION_Delete(VisBefore);
1757 VisBefore = NULL;
1758 }
1759 else if(VisBefore)
1760 {
1761 REGION_bOffsetRgn(VisBefore, -Window->rcWindow.left, -Window->rcWindow.top);
1762 }
1763
1764 /* Calculate the non client area for resizes, as this is used in the copy region */
1765 if (!(WinPos.flags & SWP_NOSIZE))
1766 {
1767 VisBeforeJustClient = VIS_ComputeVisibleRegion(Window, TRUE, FALSE,
1768 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1769
1770 if ( VisBeforeJustClient != NULL &&
1771 REGION_Complexity(VisBeforeJustClient) == NULLREGION )
1772 {
1773 REGION_Delete(VisBeforeJustClient);
1774 VisBeforeJustClient = NULL;
1775 }
1776 else if(VisBeforeJustClient)
1777 {
1778 REGION_bOffsetRgn(VisBeforeJustClient, -Window->rcWindow.left, -Window->rcWindow.top);
1779 }
1780 }
1781 }
1782 }
1783
1784 //// HACK 3
1785 if (Window->hrgnNewFrame)
1786 {
1787 SelectWindowRgn( Window, Window->hrgnNewFrame ); // Should be PSMWP->acvr->hrgnClip
1788 Window->hrgnNewFrame = NULL;
1789 }
1790
1791 WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect, valid_rects);
1792
1793 // ERR("co_WinPosDoNCCALCSize returned 0x%x\n valid dest: %d %d %d %d\n valid src : %d %d %d %d\n", WvrFlags,
1794 // valid_rects[0].left,valid_rects[0].top,valid_rects[0].right,valid_rects[0].bottom,
1795 // valid_rects[1].left,valid_rects[1].top,valid_rects[1].right,valid_rects[1].bottom);
1796
1797 /* Validate link windows. (also take into account shell window in hwndShellWindow) */
1798 if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow())
1799 {
1800 IntLinkHwnd(Window, WinPos.hwndInsertAfter);
1801 }
1802
1803 OldWindowRect = Window->rcWindow;
1804 OldClientRect = Window->rcClient;
1805
1806 if (NewClientRect.left != OldClientRect.left ||
1807 NewClientRect.top != OldClientRect.top)
1808 {
1809 // Move child window if their parent is moved. Keep Child window relative to Parent...
1810 WinPosInternalMoveWindow(Window,
1811 NewClientRect.left - OldClientRect.left,
1812 NewClientRect.top - OldClientRect.top);
1813 PosChanged = TRUE;
1814 }
1815
1816 Window->rcWindow = NewWindowRect;
1817 Window->rcClient = NewClientRect;
1818
1819 /* erase parent when hiding or resizing child */
1820 if (WinPos.flags & SWP_HIDEWINDOW)
1821 {
1822 /* Clear the update region */
1823 co_UserRedrawWindow( Window,
1824 NULL,
1825 0,
1826 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
1827
1828 if (UserIsDesktopWindow(Window->spwndParent))
1829 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM)Window->head.h, 0);
1830
1831 Window->style &= ~WS_VISIBLE; //IntSetStyle( Window, 0, WS_VISIBLE );
1832 Window->head.pti->cVisWindows--;
1833 IntNotifyWinEvent(EVENT_OBJECT_HIDE, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1834 }
1835 else if (WinPos.flags & SWP_SHOWWINDOW)
1836 {
1837 if (UserIsDesktopWindow(Window->spwndParent) &&
1838 Window->spwndOwner == NULL &&
1839 (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
1840 (Window->ExStyle & WS_EX_APPWINDOW)))
1841 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)Window->head.h, 0);
1842
1843 Window->style |= WS_VISIBLE; //IntSetStyle( Window, WS_VISIBLE, 0 );
1844 Window->head.pti->cVisWindows++;
1845 IntNotifyWinEvent(EVENT_OBJECT_SHOW, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1846 }
1847
1848 if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != HRGN_WINDOW)
1849 {
1850 NtGdiOffsetRgn(Window->hrgnUpdate,
1851 NewWindowRect.left - OldWindowRect.left,
1852 NewWindowRect.top - OldWindowRect.top);
1853 }
1854
1855 DceResetActiveDCEs(Window); // For WS_VISIBLE changes.
1856
1857 if (!(WinPos.flags & SWP_NOREDRAW))
1858 {
1859 /* Determine the new visible region */
1860 VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1861 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1862
1863 if ( VisAfter != NULL &&
1864 REGION_Complexity(VisAfter) == NULLREGION )
1865 {
1866 REGION_Delete(VisAfter);
1867 VisAfter = NULL;
1868 }
1869 else if(VisAfter)
1870 {
1871 REGION_bOffsetRgn(VisAfter, -Window->rcWindow.left, -Window->rcWindow.top);
1872 }
1873
1874 /*
1875 * Determine which pixels can be copied from the old window position
1876 * to the new. Those pixels must be visible in both the old and new
1877 * position. Also, check the class style to see if the windows of this
1878 * class need to be completely repainted on (horizontal/vertical) size
1879 * change.
1880 */
1881 if ( ( VisBefore != NULL &&
1882 VisAfter != NULL &&
1883 !(WinPos.flags & SWP_NOCOPYBITS) &&
1884 ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) &&
1885 !(Window->ExStyle & WS_EX_TRANSPARENT) ) ||
1886 ( !PosChanged && (WinPos.flags & SWP_FRAMECHANGED) && VisBefore) )
1887 {
1888
1889 /*
1890 * If this is (also) a window resize, the whole nonclient area
1891 * needs to be repainted. So we limit the copy to the client area,
1892 * 'cause there is no use in copying it (would possibly cause
1893 * "flashing" too). However, if the copy region is already empty,
1894 * we don't have to crop (can't take anything away from an empty
1895 * region...)
1896 */
1897
1898 CopyRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
1899 if (WinPos.flags & SWP_NOSIZE)
1900 RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
1901 else if (VisBeforeJustClient != NULL)
1902 {
1903 RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBeforeJustClient, RGN_AND);
1904 REGION_Delete(VisBeforeJustClient);
1905 }
1906
1907 /* Now use in copying bits which are in the update region. */
1908 if (Window->hrgnUpdate != NULL)
1909 {
1910 PREGION RgnUpdate = REGION_LockRgn(Window->hrgnUpdate);
1911 if (RgnUpdate)
1912 {
1913 REGION_bOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1914 IntGdiCombineRgn(CopyRgn, CopyRgn, RgnUpdate, RGN_DIFF);
1915 REGION_bOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1916 REGION_UnlockRgn(RgnUpdate);
1917 }
1918 }
1919
1920 /*
1921 * Now, get the bounding box of the copy region. If it's empty
1922 * there's nothing to copy. Also, it's no use copying bits onto
1923 * themselves.
1924 */
1925 if (REGION_GetRgnBox(CopyRgn, &CopyRect) == NULLREGION)
1926 {
1927 /* Nothing to copy, clean up */
1928 REGION_Delete(CopyRgn);
1929 CopyRgn = NULL;
1930 }
1931 else if ( OldWindowRect.left != NewWindowRect.left ||
1932 OldWindowRect.top != NewWindowRect.top ||
1933 (WinPos.flags & SWP_FRAMECHANGED) )
1934 {
1935 HRGN DcRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
1936 PREGION DcRgnObj = REGION_LockRgn(DcRgn);
1937
1938 /*
1939 * Small trick here: there is no function to bitblt a region. So
1940 * we set the region as the clipping region, take the bounding box
1941 * of the region and bitblt that. Since nothing outside the clipping
1942 * region is copied, this has the effect of bitblt'ing the region.
1943 *
1944 * Since NtUserGetDCEx takes ownership of the clip region, we need
1945 * to create a copy of CopyRgn and pass that. We need CopyRgn later
1946 */
1947 IntGdiCombineRgn(DcRgnObj, CopyRgn, NULL, RGN_COPY);
1948 REGION_bOffsetRgn(DcRgnObj, NewWindowRect.left, NewWindowRect.top);
1949 REGION_UnlockRgn(DcRgnObj);
1950 Dc = UserGetDCEx( Window,
1951 DcRgn,
1952 DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN);
1953 NtGdiBitBlt( Dc,
1954 CopyRect.left, CopyRect.top,
1955 CopyRect.right - CopyRect.left,
1956 CopyRect.bottom - CopyRect.top,
1957 Dc,
1958 CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
1959 CopyRect.top + (OldWindowRect.top - NewWindowRect.top),
1960 SRCCOPY,
1961 0,
1962 0);
1963
1964 UserReleaseDC(Window, Dc, FALSE);
1965 IntValidateParent(Window, CopyRgn);
1966 GreDeleteObject(DcRgn);
1967 }
1968 }
1969 else
1970 {
1971 CopyRgn = NULL;
1972 }
1973 #if 0
1974 /////// Fixes NoPopup tests but breaks msg_paint tests.
1975 if ( !PosChanged && (WinPos.flags & SWP_FRAMECHANGED) && VisBefore)
1976 {
1977 PWND Parent = Window->spwndParent;
1978 ERR("SWP_FRAMECHANGED no chg\n");
1979 if ( !(Window->style & WS_CHILD) && (Parent) && (Parent->style & WS_CLIPCHILDREN))
1980 {
1981 ERR("SWP_FRAMECHANGED Parent WS_CLIPCHILDREN\n");
1982 //IntInvalidateWindows( Window, VisBefore, /*RDW_ERASE |*/ RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
1983 }
1984 }
1985 #endif
1986 /* We need to redraw what wasn't visible before */
1987 if (VisAfter != NULL)
1988 {
1989 PREGION DirtyRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
1990 if (DirtyRgn)
1991 {
1992 if (CopyRgn != NULL)
1993 {
1994 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
1995 }
1996 else
1997 {
1998 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
1999 }
2000
2001 if (RgnType != ERROR && RgnType != NULLREGION)
2002 {
2003 /* old code
2004 NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2005 IntInvalidateWindows( Window,
2006 DirtyRgn,
2007 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2008 }
2009 GreDeleteObject(DirtyRgn);
2010 */
2011
2012 PWND Parent = Window->spwndParent;
2013
2014 REGION_bOffsetRgn( DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2015
2016 if ( (Window->style & WS_CHILD) && (Parent) && !(Parent->style & WS_CLIPCHILDREN))
2017 {
2018 IntInvalidateWindows( Parent, DirtyRgn, RDW_ERASE | RDW_INVALIDATE);
2019 co_IntPaintWindows(Parent, RDW_NOCHILDREN, FALSE);
2020 }
2021 else
2022 {
2023 IntInvalidateWindows( Window, DirtyRgn, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2024 }
2025 }
2026 REGION_Delete(DirtyRgn);
2027 }
2028 }
2029
2030 if (CopyRgn != NULL)
2031 {
2032 REGION_Delete(CopyRgn);
2033 }
2034
2035 /* Expose what was covered before but not covered anymore */
2036 if (VisBefore != NULL)
2037 {
2038 PREGION ExposedRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
2039 if (ExposedRgn)
2040 {
2041 RgnType = IntGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
2042 REGION_bOffsetRgn(ExposedRgn,
2043 OldWindowRect.left - NewWindowRect.left,
2044 OldWindowRect.top - NewWindowRect.top);
2045
2046 if (VisAfter != NULL)
2047 RgnType = IntGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
2048
2049 if (RgnType != ERROR && RgnType != NULLREGION)
2050 {
2051 co_VIS_WindowLayoutChanged(Window, ExposedRgn);
2052 }
2053 REGION_Delete(ExposedRgn);
2054 }
2055 REGION_Delete(VisBefore);
2056 }
2057
2058 if (VisAfter != NULL)
2059 {
2060 REGION_Delete(VisAfter);
2061 }
2062 }
2063
2064 if (!(WinPos.flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
2065 {
2066 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2067 {
2068 co_IntSendMessageNoWait(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
2069 }
2070 else
2071 {
2072 //ERR("SetWindowPos Set FG Window!\n");
2073 if ( pti->MessageQueue->spwndActive != Window ||
2074 pti->MessageQueue != gpqForeground )
2075 {
2076 //ERR("WPSWP : set active window\n");
2077 if (!(Window->state & WNDS_BEINGACTIVATED)) // Inside SAW?
2078 {
2079 co_IntSetForegroundWindow(Window); // Fixes SW_HIDE issues. Wine win test_SetActiveWindow & test_SetForegroundWindow.
2080 }
2081 }
2082 }
2083 }
2084
2085 if ( !PosChanged &&
2086 (WinPos.flags & SWP_FRAMECHANGED) &&
2087 !(WinPos.flags & SWP_DEFERERASE) && // Prevent sending WM_SYNCPAINT message.
2088 VisAfter )
2089 {
2090 PWND Parent = Window->spwndParent;
2091 if ( !(Window->style & WS_CHILD) && (Parent) && (Parent->style & WS_CLIPCHILDREN))
2092 {
2093 TRACE("SWP_FRAMECHANGED Parent WS_CLIPCHILDREN\n");
2094 UserSyncAndPaintWindows( Parent, RDW_CLIPCHILDREN);
2095 }
2096 }
2097
2098 // Fix wine msg test_SetFocus, prevents sending WM_WINDOWPOSCHANGED.
2099 if ( VisBefore == NULL &&
2100 VisBeforeJustClient == NULL &&
2101 !(Window->ExStyle & WS_EX_TOPMOST) &&
2102 (WinPos.flags & SWP_AGG_STATUSFLAGS) == (SWP_AGG_NOPOSCHANGE & ~SWP_NOZORDER))
2103 {
2104 TRACE("No drawing, set no Z order and no redraw!\n");
2105 WinPos.flags |= SWP_NOZORDER|SWP_NOREDRAW;
2106 }
2107
2108 /* And last, send the WM_WINDOWPOSCHANGED message */
2109
2110 TRACE("\tstatus hwnd %p flags = %04x\n",Window?Window->head.h:NULL,WinPos.flags & SWP_AGG_STATUSFLAGS);
2111
2112 if ((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2113 {
2114 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
2115 and always contains final window position.
2116 */
2117 WinPos.x = NewWindowRect.left;
2118 WinPos.y = NewWindowRect.top;
2119 WinPos.cx = NewWindowRect.right - NewWindowRect.left;
2120 WinPos.cy = NewWindowRect.bottom - NewWindowRect.top;
2121 TRACE("WM_WINDOWPOSCHANGED hwnd %p Flags %04x\n",WinPos.hwnd,WinPos.flags);
2122 co_IntSendMessageNoWait(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
2123 }
2124
2125 if ( WinPos.flags & SWP_FRAMECHANGED || WinPos.flags & SWP_STATECHANGED ||
2126 !(WinPos.flags & SWP_NOCLIENTSIZE) || !(WinPos.flags & SWP_NOCLIENTMOVE) )
2127 {
2128 PWND pWnd = ValidateHwndNoErr(WinPos.hwnd);
2129 if (pWnd)
2130 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2131 }
2132
2133 if(bPointerInWindow != IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y))
2134 {
2135 /* Generate mouse move message */
2136 MSG msg;
2137 msg.message = WM_MOUSEMOVE;
2138 msg.wParam = UserGetMouseButtonsState();
2139 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2140 msg.pt = gpsi->ptCursor;
2141 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2142 }
2143
2144 return TRUE;
2145 }
2146
2147 LRESULT FASTCALL
2148 co_WinPosGetNonClientSize(PWND Window, RECT* WindowRect, RECT* ClientRect)
2149 {
2150 LRESULT Result;
2151
2152 ASSERT_REFS_CO(Window);
2153
2154 *ClientRect = *WindowRect;
2155 Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect);
2156
2157 FixClientRect(ClientRect, WindowRect);
2158
2159 return Result;
2160 }
2161
2162 void FASTCALL
2163 co_WinPosSendSizeMove(PWND Wnd)
2164 {
2165 RECTL Rect;
2166 LPARAM lParam;
2167 WPARAM wParam = SIZE_RESTORED;
2168
2169 IntGetClientRect(Wnd, &Rect);
2170 lParam = MAKELONG(Rect.right-Rect.left, Rect.bottom-Rect.top);
2171
2172 Wnd->state &= ~WNDS_SENDSIZEMOVEMSGS;
2173
2174 if (Wnd->style & WS_MAXIMIZE)
2175 {
2176 wParam = SIZE_MAXIMIZED;
2177 }
2178 else if (Wnd->style & WS_MINIMIZE)
2179 {
2180 wParam = SIZE_MINIMIZED;
2181 lParam = 0;
2182 }
2183
2184 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SIZE, wParam, lParam);
2185
2186 if (UserIsDesktopWindow(Wnd->spwndParent))
2187 lParam = MAKELONG(Wnd->rcClient.left, Wnd->rcClient.top);
2188 else
2189 lParam = MAKELONG(Wnd->rcClient.left-Wnd->spwndParent->rcClient.left, Wnd->rcClient.top-Wnd->spwndParent->rcClient.top);
2190
2191 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_MOVE, 0, lParam);
2192
2193 IntEngWindowChanged(Wnd, WOC_RGN_CLIENT);
2194 }
2195
2196 UINT FASTCALL
2197 co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos)
2198 {
2199 POINT Size;
2200 WINDOWPLACEMENT wpl;
2201 LONG old_style;
2202 UINT SwpFlags = 0;
2203
2204 ASSERT_REFS_CO(Wnd);
2205
2206 wpl.length = sizeof(wpl);
2207 IntGetWindowPlacement( Wnd, &wpl );
2208
2209 if (co_HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)Wnd->head.h, ShowFlag))
2210 {
2211 ERR("WinPosMinMaximize WH_CBT Call Hook return!\n");
2212 return SWP_NOSIZE | SWP_NOMOVE;
2213 }
2214 if (Wnd->style & WS_MINIMIZE)
2215 {
2216 switch (ShowFlag)
2217 {
2218 case SW_MINIMIZE:
2219 case SW_SHOWMINNOACTIVE:
2220 case SW_SHOWMINIMIZED:
2221 case SW_FORCEMINIMIZE:
2222 return SWP_NOSIZE | SWP_NOMOVE;
2223 }
2224 if (!co_IntSendMessageNoWait(Wnd->head.h, WM_QUERYOPEN, 0, 0))
2225 {
2226 return(SWP_NOSIZE | SWP_NOMOVE);
2227 }
2228 SwpFlags |= SWP_NOCOPYBITS;
2229 }
2230 switch (ShowFlag)
2231 {
2232 case SW_MINIMIZE:
2233 case SW_SHOWMINNOACTIVE:
2234 case SW_SHOWMINIMIZED:
2235 case SW_FORCEMINIMIZE:
2236 {
2237 //ERR("MinMaximize Minimize\n");
2238 if (Wnd->style & WS_MAXIMIZE)
2239 {
2240 Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED;
2241 }
2242 else
2243 {
2244 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2245 }
2246
2247 old_style = IntSetStyle( Wnd, WS_MINIMIZE, WS_MAXIMIZE );
2248
2249 co_UserRedrawWindow(Wnd, NULL, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOINTERNALPAINT);
2250
2251 if (!(Wnd->InternalPos.flags & WPF_SETMINPOSITION))
2252 Wnd->InternalPos.flags &= ~WPF_MININIT;
2253
2254 WinPosFindIconPos(Wnd, &wpl.ptMinPosition);
2255
2256 /*if (!(old_style & WS_MINIMIZE))
2257 {
2258 SwpFlags |= SWP_STATECHANGED;
2259 IntShowOwnedPopups(Wnd, FALSE);
2260 }*/
2261
2262 RECTL_vSetRect(NewPos, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
2263 wpl.ptMinPosition.x + UserGetSystemMetrics(SM_CXMINIMIZED),
2264 wpl.ptMinPosition.y + UserGetSystemMetrics(SM_CYMINIMIZED));
2265 SwpFlags |= SWP_NOCOPYBITS;
2266 break;
2267 }
2268
2269 case SW_MAXIMIZE:
2270 {
2271 //ERR("MinMaximize Maximize\n");
2272 if ((Wnd->style & WS_MAXIMIZE) && (Wnd->style & WS_VISIBLE))
2273 {
2274 SwpFlags = SWP_NOSIZE | SWP_NOMOVE;
2275 break;
2276 }
2277 co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
2278
2279 /*ERR("Maximize: %d,%d %dx%d\n",
2280 wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, Size.x, Size.y);
2281 */
2282 old_style = IntSetStyle( Wnd, WS_MAXIMIZE, WS_MINIMIZE );
2283 /*if (old_style & WS_MINIMIZE)
2284 {
2285 IntShowOwnedPopups(Wnd, TRUE);
2286 }*/
2287
2288 if (!(old_style & WS_MAXIMIZE)) SwpFlags |= SWP_STATECHANGED;
2289 RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
2290 //wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
2291 Size.x, Size.y);
2292 break;
2293 }
2294
2295 case SW_SHOWNOACTIVATE:
2296 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2297 /* fall through */
2298 case SW_SHOWNORMAL:
2299 case SW_RESTORE:
2300 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
2301 {
2302 //ERR("MinMaximize Restore\n");
2303 old_style = IntSetStyle( Wnd, 0, WS_MINIMIZE | WS_MAXIMIZE );
2304 if (old_style & WS_MINIMIZE)
2305 {
2306 //IntShowOwnedPopups(Wnd, TRUE);
2307
2308 if (Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED)
2309 {
2310 co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
2311 IntSetStyle( Wnd, WS_MAXIMIZE, 0 );
2312 SwpFlags |= SWP_STATECHANGED;
2313 RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
2314 wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
2315 break;
2316 }
2317 else
2318 {
2319 *NewPos = wpl.rcNormalPosition;
2320 NewPos->right -= NewPos->left;
2321 NewPos->bottom -= NewPos->top;
2322 break;
2323 }
2324 }
2325 else
2326 {
2327 if (!(old_style & WS_MAXIMIZE))
2328 {
2329 break;
2330 }
2331 SwpFlags |= SWP_STATECHANGED;
2332 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2333 *NewPos = wpl.rcNormalPosition;
2334 NewPos->right -= NewPos->left;
2335 NewPos->bottom -= NewPos->top;
2336 break;
2337 }
2338 }
2339 }
2340 return SwpFlags;
2341 }
2342
2343 /*
2344 ShowWindow does not set SWP_FRAMECHANGED!!! Fix wine msg test_SetParent:WmSetParentSeq_2:23 wParam bits!
2345 */
2346 BOOLEAN FASTCALL
2347 co_WinPosShowWindow(PWND Wnd, INT Cmd)
2348 {
2349 BOOLEAN WasVisible;
2350 UINT Swp = 0, EventMsg = 0;
2351 RECTL NewPos = {0, 0, 0, 0};
2352 BOOLEAN ShowFlag;
2353 LONG style;
2354 PWND Parent;
2355 PTHREADINFO pti;
2356 //HRGN VisibleRgn;
2357 BOOL ShowOwned = FALSE;
2358 BOOL FirstTime = FALSE;
2359 ASSERT_REFS_CO(Wnd);
2360 //KeRosDumpStackFrames(NULL, 20);
2361 pti = PsGetCurrentThreadWin32Thread();
2362 WasVisible = (Wnd->style & WS_VISIBLE) != 0;
2363 style = Wnd->style;
2364
2365 TRACE("co_WinPosShowWindow START hwnd %p Cmd %d usicmd %u\n",
2366 Wnd->head.h, Cmd, pti->ppi->usi.wShowWindow);
2367
2368 if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW )
2369 {
2370 if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2371 {
2372 if ((Wnd->style & WS_CAPTION) == WS_CAPTION)
2373 {
2374 if (Wnd->spwndOwner == NULL)
2375 {
2376 if ( Cmd == SW_SHOWNORMAL || Cmd == SW_SHOW)
2377 {
2378 Cmd = SW_SHOWDEFAULT;
2379 }
2380 FirstTime = TRUE;
2381 TRACE("co_WPSW FT 1\n");
2382 }
2383 }
2384 }
2385 }
2386
2387 if ( Cmd == SW_SHOWDEFAULT )
2388 {
2389 if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW )
2390 {
2391 Cmd = pti->ppi->usi.wShowWindow;
2392 FirstTime = TRUE;
2393 TRACE("co_WPSW FT 2\n");
2394 }
2395 }
2396
2397 if (FirstTime)
2398 {
2399 pti->ppi->usi.dwFlags &= ~(STARTF_USEPOSITION|STARTF_USESIZE|STARTF_USESHOWWINDOW);
2400 }
2401
2402 switch (Cmd)
2403 {
2404 case SW_HIDE:
2405 {
2406 if (!WasVisible)
2407 {
2408 //ERR("co_WinPosShowWindow Exit Bad\n");
2409 return FALSE;
2410 }
2411 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2412 if (Wnd != pti->MessageQueue->spwndActive)
2413 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2414 break;
2415 }
2416
2417 case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
2418 case SW_SHOWMINNOACTIVE:
2419 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2420 /* Fall through. */
2421 case SW_SHOWMINIMIZED:
2422 Swp |= SWP_SHOWWINDOW;
2423 /* Fall through. */
2424 case SW_MINIMIZE:
2425 {
2426 Swp |= SWP_NOACTIVATE;
2427 if (!(style & WS_MINIMIZE))
2428 {
2429 IntShowOwnedPopups(Wnd, FALSE );
2430 // Fix wine Win test_SetFocus todo #1 & #2,
2431 if (Cmd == SW_SHOWMINIMIZED)
2432 {
2433 //ERR("co_WinPosShowWindow Set focus 1\n");
2434 if ((style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2435 co_UserSetFocus(Wnd->spwndParent);
2436 else
2437 co_UserSetFocus(0);
2438 }
2439
2440 Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos);
2441
2442 EventMsg = EVENT_SYSTEM_MINIMIZESTART;
2443 }
2444 else
2445 {
2446 if (WasVisible)
2447 {
2448 //ERR("co_WinPosShowWindow Exit Good\n");
2449 return TRUE;
2450 }
2451 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2452 }
2453 break;
2454 }
2455
2456 case SW_SHOWMAXIMIZED:
2457 {
2458 Swp |= SWP_SHOWWINDOW;
2459 if (!(style & WS_MAXIMIZE))
2460 {
2461 ShowOwned = TRUE;
2462
2463 Swp |= co_WinPosMinMaximize(Wnd, SW_MAXIMIZE, &NewPos);
2464
2465 EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2466 }
2467 else
2468 {
2469 if (WasVisible)
2470 {
2471 //ERR("co_WinPosShowWindow Exit Good 1\n");
2472 return TRUE;
2473 }
2474 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2475 }
2476 break;
2477 }
2478
2479 case SW_SHOWNA:
2480 Swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2481 if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOZORDER;
2482 break;
2483 case SW_SHOW:
2484 if (WasVisible) return(TRUE); // Nothing to do!
2485 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2486 /* Don't activate the topmost window. */
2487 if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2488 break;
2489
2490 case SW_SHOWNOACTIVATE:
2491 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2492 /* Fall through. */
2493 case SW_SHOWNORMAL:
2494 case SW_SHOWDEFAULT:
2495 case SW_RESTORE:
2496 if (!WasVisible) Swp |= SWP_SHOWWINDOW;
2497 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2498 {
2499 Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos);
2500 if (style & WS_MINIMIZE) EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2501 }
2502 else
2503 {
2504 if (WasVisible)
2505 {
2506 //ERR("co_WinPosShowWindow Exit Good 3\n");
2507 return TRUE;
2508 }
2509 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2510 }
2511 if ( style & WS_CHILD &&
2512 !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2513 !(Swp & SWP_STATECHANGED))
2514 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2515 break;
2516
2517 default:
2518 //ERR("co_WinPosShowWindow Exit Good 4\n");
2519 return WasVisible;
2520 }
2521
2522 ShowFlag = (Cmd != SW_HIDE);
2523
2524 if ((ShowFlag != WasVisible || Cmd == SW_SHOWNA) && Cmd != SW_SHOWMAXIMIZED && !(Swp & SWP_STATECHANGED))
2525 {
2526 co_IntSendMessageNoWait(Wnd->head.h, WM_SHOWWINDOW, ShowFlag, 0);
2527 #if 0 // Fix wine msg test_SetParent:WmSetParentSeq_1:2
2528 if (!(Wnd->state2 & WNDS2_WIN31COMPAT)) // <------------- XP sets this bit!
2529 co_IntSendMessageNoWait(Wnd->head.h, WM_SETVISIBLE, ShowFlag, 0);
2530 #endif
2531 if (!VerifyWnd(Wnd)) return WasVisible;
2532 }
2533
2534 /* We can't activate a child window */
2535 if ((Wnd->style & WS_CHILD) &&
2536 !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2537 Cmd != SW_SHOWNA)
2538 {
2539 //ERR("SWP Child No active and ZOrder\n");
2540 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2541 }
2542
2543 #if 0 // Explorer issues with common controls? Someone does not know how CS_SAVEBITS works.
2544 // Breaks startup and shutdown active window...
2545 if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
2546 Wnd->pcls->style & CS_SAVEBITS &&
2547 ((Cmd == SW_SHOW) || (Cmd == SW_NORMAL)))
2548 {
2549 ERR("WinPosShowWindow Set active\n");
2550 //UserSetActiveWindow(Wnd);
2551 co_IntSetForegroundWindow(Wnd); // HACK
2552 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2553 }
2554 #endif
2555
2556 if (IsChildVisible(Wnd) || Swp & SWP_STATECHANGED)
2557 {
2558 TRACE("Child is Vis %s or State changed %s. ShowFlag %s Swp %04x\n",
2559 (IsChildVisible(Wnd) ? "TRUE" : "FALSE"), (Swp & SWP_STATECHANGED ? "TRUE" : "FALSE"),
2560 (ShowFlag ? "TRUE" : "FALSE"),LOWORD(Swp));
2561 co_WinPosSetWindowPos( Wnd,
2562 0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP,
2563 NewPos.left,
2564 NewPos.top,
2565 NewPos.right, // NewPos.right - NewPos.left, when minimized and restore, the window becomes smaller.
2566 NewPos.bottom,// NewPos.bottom - NewPos.top,
2567 LOWORD(Swp));
2568 }
2569 else
2570 {
2571 TRACE("Parent Vis?\n");
2572 /* if parent is not visible simply toggle WS_VISIBLE and return */
2573 if (ShowFlag) IntSetStyle( Wnd, WS_VISIBLE, 0 );
2574 else IntSetStyle( Wnd, 0, WS_VISIBLE );
2575 }
2576
2577 if ( EventMsg ) IntNotifyWinEvent(EventMsg, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2578
2579 if ( ShowOwned ) IntShowOwnedPopups(Wnd, TRUE );
2580
2581 if ((Cmd == SW_HIDE) || (Cmd == SW_MINIMIZE))
2582 {
2583 if ( Wnd == pti->MessageQueue->spwndActive && pti->MessageQueue == IntGetFocusMessageQueue() )
2584 {
2585 if (UserIsDesktopWindow(Wnd->spwndParent))
2586 {
2587 if (!ActivateOtherWindowMin(Wnd))
2588 {
2589 co_WinPosActivateOtherWindow(Wnd);
2590 }
2591 }
2592 else
2593 {
2594 co_WinPosActivateOtherWindow(Wnd);
2595 }
2596 }
2597
2598 /* Revert focus to parent */
2599 if (Wnd == pti->MessageQueue->spwndFocus)
2600 {
2601 Parent = Wnd->spwndParent;
2602 if (UserIsDesktopWindow(Wnd->spwndParent))
2603 Parent = 0;
2604 co_UserSetFocus(Parent);
2605 }
2606 // Hide, just return.
2607 if (Cmd == SW_HIDE) return WasVisible;
2608 }
2609
2610 /* FIXME: Check for window destruction. */
2611
2612 if ((Wnd->state & WNDS_SENDSIZEMOVEMSGS) &&
2613 !(Wnd->state2 & WNDS2_INDESTROY))
2614 {
2615 co_WinPosSendSizeMove(Wnd);
2616 }
2617
2618 /* if previous state was minimized Windows sets focus to the window */
2619 if (style & WS_MINIMIZE)
2620 {
2621 co_UserSetFocus(Wnd);
2622 // Fix wine Win test_SetFocus todo #3,
2623 if (!(style & WS_CHILD)) co_IntSendMessage(UserHMGetHandle(Wnd), WM_ACTIVATE, WA_ACTIVE, 0);
2624 }
2625 //ERR("co_WinPosShowWindow EXIT\n");
2626 return WasVisible;
2627 }
2628
2629 static PWND
2630 co_WinPosSearchChildren(
2631 IN PWND ScopeWin,
2632 IN POINT *Point,
2633 IN OUT USHORT *HitTest,
2634 IN BOOL Ignore
2635 )
2636 {
2637 HWND *List, *phWnd;
2638 PWND pwndChild = NULL;
2639
2640 /* not visible */
2641 if (!(ScopeWin->style & WS_VISIBLE))
2642 {
2643 return NULL;
2644 }
2645
2646 /* not in window or in window region */
2647 if (!IntPtInWindow(ScopeWin, Point->x, Point->y))
2648 {
2649 return NULL;
2650 }
2651
2652 /* transparent */
2653 if ((ScopeWin->ExStyle & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT))
2654 {
2655 return NULL;
2656 }
2657
2658 if (!Ignore && (ScopeWin->style & WS_DISABLED))
2659 { /* disabled child */
2660 if ((ScopeWin->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return NULL;
2661 /* process the hit error */
2662 *HitTest = HTERROR;
2663 return ScopeWin;
2664 }
2665
2666 /* not minimized and check if point is inside the window */
2667 if (!(ScopeWin->style & WS_MINIMIZE) &&
2668 RECTL_bPointInRect(&ScopeWin->rcClient, Point->x, Point->y) )
2669 {
2670 UserReferenceObject(ScopeWin);
2671
2672 List = IntWinListChildren(ScopeWin);
2673 if (List)
2674 {
2675 for (phWnd = List; *phWnd; ++phWnd)
2676 {
2677 if (!(pwndChild = ValidateHwndNoErr(*phWnd)))
2678 {
2679 continue;
2680 }
2681
2682 pwndChild = co_WinPosSearchChildren(pwndChild, Point, HitTest, Ignore);
2683
2684 if (pwndChild != NULL)
2685 {
2686 /* We found a window. Don't send any more WM_NCHITTEST messages */
2687 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2688 UserDereferenceObject(ScopeWin);
2689 return pwndChild;
2690 }
2691 }
2692 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2693 }
2694 UserDereferenceObject(ScopeWin);
2695 }
2696
2697 if (ScopeWin->head.pti == PsGetCurrentThreadWin32Thread())
2698 {
2699 *HitTest = (USHORT)co_IntSendMessage(ScopeWin->head.h, WM_NCHITTEST, 0, MAKELONG(Point->x, Point->y));
2700
2701 if ((*HitTest) == (USHORT)HTTRANSPARENT)
2702 {
2703 return NULL;
2704 }
2705 }
2706 else
2707 {
2708 if (*HitTest == HTNOWHERE && pwndChild == NULL) *HitTest = HTCLIENT;
2709 }
2710
2711 return ScopeWin;
2712 }
2713
2714 PWND APIENTRY
2715 co_WinPosWindowFromPoint(
2716 IN PWND ScopeWin,
2717 IN POINT *WinPoint,
2718 IN OUT USHORT* HitTest,
2719 IN BOOL Ignore)
2720 {
2721 PWND Window;
2722 POINT Point = *WinPoint;
2723 USER_REFERENCE_ENTRY Ref;
2724
2725 if( ScopeWin == NULL )
2726 {
2727 ScopeWin = UserGetDesktopWindow();
2728 if(ScopeWin == NULL)
2729 return NULL;
2730 }
2731
2732 *HitTest = HTNOWHERE;
2733
2734 ASSERT_REFS_CO(ScopeWin);
2735 UserRefObjectCo(ScopeWin, &Ref);
2736
2737 Window = co_WinPosSearchChildren(ScopeWin, &Point, HitTest, Ignore);
2738
2739 UserDerefObjectCo(ScopeWin);
2740 if (Window)
2741 ASSERT_REFS_CO(Window);
2742 ASSERT_REFS_CO(ScopeWin);
2743
2744 return Window;
2745 }
2746
2747 PWND FASTCALL
2748 IntRealChildWindowFromPoint(PWND Parent, LONG x, LONG y)
2749 {
2750 POINTL Pt;
2751 HWND *List, *phWnd;
2752 PWND pwndHit = NULL;
2753
2754 Pt.x = x;
2755 Pt.y = y;
2756
2757 if (!UserIsDesktopWindow(Parent))
2758 {
2759 Pt.x += Parent->rcClient.left;
2760 Pt.y += Parent->rcClient.top;
2761 }
2762
2763 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2764
2765 if ((List = IntWinListChildren(Parent)))
2766 {
2767 for (phWnd = List; *phWnd; phWnd++)
2768 {
2769 PWND Child;
2770 if ((Child = ValidateHwndNoErr(*phWnd)))
2771 {
2772 if ( Child->style & WS_VISIBLE && IntPtInWindow(Child, Pt.x, Pt.y) )
2773 {
2774 if ( Child->pcls->atomClassName != gpsi->atomSysClass[ICLS_BUTTON] ||
2775 (Child->style & BS_TYPEMASK) != BS_GROUPBOX )
2776 {
2777 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2778 return Child;
2779 }
2780 pwndHit = Child;
2781 }
2782 }
2783 }
2784 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2785 }
2786 return pwndHit ? pwndHit : Parent;
2787 }
2788
2789 PWND APIENTRY
2790 IntChildWindowFromPointEx(PWND Parent, LONG x, LONG y, UINT uiFlags)
2791 {
2792 POINTL Pt;
2793 HWND *List, *phWnd;
2794 PWND pwndHit = NULL;
2795
2796 Pt.x = x;
2797 Pt.y = y;
2798
2799 if (!UserIsDesktopWindow(Parent))
2800 {
2801 if (Parent->ExStyle & WS_EX_LAYOUTRTL)
2802 Pt.x = Parent->rcClient.right - Pt.x;
2803 else
2804 Pt.x += Parent->rcClient.left;
2805 Pt.y += Parent->rcClient.top;
2806 }
2807
2808 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2809
2810 if ((List = IntWinListChildren(Parent)))
2811 {
2812 for (phWnd = List; *phWnd; phWnd++)
2813 {
2814 PWND Child;
2815 if ((Child = ValidateHwndNoErr(*phWnd)))
2816 {
2817 if (uiFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
2818 {
2819 if (!(Child->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE)) continue;
2820 if ((Child->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED)) continue;
2821 }
2822
2823 if (uiFlags & CWP_SKIPTRANSPARENT)
2824 {
2825 if (Child->ExStyle & WS_EX_TRANSPARENT) continue;
2826 }
2827
2828 if (IntPtInWindow(Child, Pt.x, Pt.y))
2829 {
2830 pwndHit = Child;
2831 break;
2832 }
2833 }
2834 }
2835 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2836 }
2837 return pwndHit ? pwndHit : Parent;
2838 }
2839
2840 HDWP
2841 FASTCALL
2842 IntDeferWindowPos( HDWP hdwp,
2843 HWND hwnd,
2844 HWND hwndAfter,
2845 INT x,
2846 INT y,
2847 INT cx,
2848 INT cy,
2849 UINT flags )
2850 {
2851 PSMWP pDWP;
2852 int i;
2853 HDWP retvalue = hdwp;
2854
2855 TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2856 hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
2857
2858 if (flags & ~(SWP_NOSIZE | SWP_NOMOVE |
2859 SWP_NOZORDER | SWP_NOREDRAW |
2860 SWP_NOACTIVATE | SWP_NOCOPYBITS |
2861 SWP_NOOWNERZORDER|SWP_SHOWWINDOW |
2862 SWP_HIDEWINDOW | SWP_FRAMECHANGED))
2863 {
2864 EngSetLastError(ERROR_INVALID_PARAMETER);
2865 return NULL;
2866 }
2867
2868 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
2869 {
2870 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
2871 return NULL;
2872 }
2873
2874 for (i = 0; i < pDWP->ccvr; i++)
2875 {
2876 if (pDWP->acvr[i].pos.hwnd == hwnd)
2877 {
2878 /* Merge with the other changes */
2879 if (!(flags & SWP_NOZORDER))
2880 {
2881 pDWP->acvr[i].pos.hwndInsertAfter = hwndAfter;
2882 }
2883 if (!(flags & SWP_NOMOVE))
2884 {
2885 pDWP->acvr[i].pos.x = x;
2886 pDWP->acvr[i].pos.y = y;
2887 }
2888 if (!(flags & SWP_NOSIZE))
2889 {
2890 pDWP->acvr[i].pos.cx = cx;
2891 pDWP->acvr[i].pos.cy = cy;
2892 }
2893 pDWP->acvr[i].pos.flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
2894 SWP_NOZORDER | SWP_NOREDRAW |
2895 SWP_NOACTIVATE | SWP_NOCOPYBITS|
2896 SWP_NOOWNERZORDER);
2897 pDWP->acvr[i].pos.flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
2898 SWP_FRAMECHANGED);
2899 goto END;
2900 }
2901 }
2902 if (pDWP->ccvr >= pDWP->ccvrAlloc)
2903 {
2904 PCVR newpos = ExAllocatePoolWithTag(PagedPool, pDWP->ccvrAlloc * 2 * sizeof(CVR), USERTAG_SWP);
2905 if (!newpos)
2906 {
2907 retvalue = NULL;
2908 goto END;
2909 }
2910 RtlZeroMemory(newpos, pDWP->ccvrAlloc * 2 * sizeof(CVR));
2911 RtlCopyMemory(newpos, pDWP->acvr, pDWP->ccvrAlloc * sizeof(CVR));
2912 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
2913 pDWP->ccvrAlloc *= 2;
2914 pDWP->acvr = newpos;
2915 }
2916 pDWP->acvr[pDWP->ccvr].pos.hwnd = hwnd;
2917 pDWP->acvr[pDWP->ccvr].pos.hwndInsertAfter = hwndAfter;
2918 pDWP->acvr[pDWP->ccvr].pos.x = x;
2919 pDWP->acvr[pDWP->ccvr].pos.y = y;
2920 pDWP->acvr[pDWP->ccvr].pos.cx = cx;
2921 pDWP->acvr[pDWP->ccvr].pos.cy = cy;
2922 pDWP->acvr[pDWP->ccvr].pos.flags = flags;
2923 pDWP->acvr[pDWP->ccvr].hrgnClip = NULL;
2924 pDWP->acvr[pDWP->ccvr].hrgnInterMonitor = NULL;
2925 pDWP->ccvr++;
2926 END:
2927 return retvalue;
2928 }
2929
2930 BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp, BOOL sAsync )
2931 {
2932 PSMWP pDWP;
2933 PCVR winpos;
2934 BOOL res = TRUE;
2935 int i;
2936
2937 TRACE("%p\n", hdwp);
2938
2939 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
2940 {
2941 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
2942 return FALSE;
2943 }
2944
2945 for (i = 0, winpos = pDWP->acvr; res && i < pDWP->ccvr; i++, winpos++)
2946 {
2947 PWND pwnd;
2948 USER_REFERENCE_ENTRY Ref;
2949
2950 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2951 winpos->pos.hwnd, winpos->pos.hwndInsertAfter, winpos->pos.x, winpos->pos.y,
2952 winpos->pos.cx, winpos->pos.cy, winpos->pos.flags);
2953
2954 pwnd = ValidateHwndNoErr(winpos->pos.hwnd);
2955 if (!pwnd)
2956 continue;
2957
2958 UserRefObjectCo(pwnd, &Ref);
2959
2960 if ( sAsync )
2961 {
2962 LRESULT lRes;
2963 PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
2964 if ( ppos )
2965 {
2966 *ppos = winpos->pos;
2967 /* Yes it's a pointer inside Win32k! */
2968 lRes = co_IntSendMessageNoWait( winpos->pos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
2969 /* We handle this the same way as Event Hooks and Hooks. */
2970 if ( !lRes )
2971 {
2972 ExFreePoolWithTag(ppos, USERTAG_SWP);
2973 }
2974 }
2975 }
2976 else
2977 res = co_WinPosSetWindowPos( pwnd,
2978 winpos->pos.hwndInsertAfter,
2979 winpos->pos.x,
2980 winpos->pos.y,
2981 winpos->pos.cx,
2982 winpos->pos.cy,
2983 winpos->pos.flags);
2984
2985 // Hack to pass tests.... Must have some work to do so clear the error.
2986 if (res && (winpos->pos.flags & (SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER)) == SWP_NOZORDER )
2987 EngSetLastError(ERROR_SUCCESS);
2988
2989 UserDerefObjectCo(pwnd);
2990 }
2991 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
2992 UserDereferenceObject(pDWP);
2993 UserDeleteObject(hdwp, TYPE_SETWINDOWPOS);
2994 return res;
2995 }
2996
2997 /*
2998 * @implemented
2999 */
3000 HWND APIENTRY
3001 NtUserChildWindowFromPointEx(HWND hwndParent,
3002 LONG x,
3003 LONG y,
3004 UINT uiFlags)
3005 {
3006 PWND pwndParent;
3007 TRACE("Enter NtUserChildWindowFromPointEx\n");
3008 UserEnterExclusive();
3009 if ((pwndParent = UserGetWindowObject(hwndParent)))
3010 {
3011 pwndParent = IntChildWindowFromPointEx(pwndParent, x, y, uiFlags);
3012 }
3013 UserLeave();
3014 TRACE("Leave NtUserChildWindowFromPointEx\n");
3015 return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
3016 }
3017
3018 /*
3019 * @implemented
3020 */
3021 BOOL APIENTRY
3022 NtUserEndDeferWindowPosEx(HDWP WinPosInfo,
3023 DWORD Unknown1)
3024 {
3025 BOOL Ret;
3026 TRACE("Enter NtUserEndDeferWindowPosEx\n");
3027 UserEnterExclusive();
3028 Ret = IntEndDeferWindowPosEx(WinPosInfo, (BOOL)Unknown1);
3029 TRACE("Leave NtUserEndDeferWindowPosEx, ret=%i\n", Ret);
3030 UserLeave();
3031 return Ret;
3032 }
3033
3034 /*
3035 * @implemented
3036 */
3037 HDWP APIENTRY
3038 NtUserDeferWindowPos(HDWP WinPosInfo,
3039 HWND Wnd,
3040 HWND WndInsertAfter,
3041 int x,
3042 int y,
3043 int cx,
3044 int cy,
3045 UINT Flags)
3046 {
3047 PWND pWnd, pWndIA;
3048 HDWP Ret = NULL;
3049 UINT Tmp = ~(SWP_ASYNCWINDOWPOS|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_NOREPOSITION|
3050 SWP_NOCOPYBITS|SWP_HIDEWINDOW|SWP_SHOWWINDOW|SWP_FRAMECHANGED|
3051 SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE);
3052
3053 TRACE("Enter NtUserDeferWindowPos\n");
3054 UserEnterExclusive();
3055
3056 if ( Flags & Tmp )
3057 {
3058 EngSetLastError(ERROR_INVALID_FLAGS);
3059 goto Exit;
3060 }
3061
3062 pWnd = UserGetWindowObject(Wnd);
3063 if (!pWnd || UserIsDesktopWindow(pWnd) || UserIsMessageWindow(pWnd))
3064 {
3065 goto Exit;
3066 }
3067
3068 if ( WndInsertAfter &&
3069 WndInsertAfter != HWND_BOTTOM &&
3070 WndInsertAfter != HWND_TOPMOST &&
3071 WndInsertAfter != HWND_NOTOPMOST )
3072 {
3073 pWndIA = UserGetWindowObject(WndInsertAfter);
3074 if (!pWndIA || UserIsDesktopWindow(pWndIA) || UserIsMessageWindow(pWndIA))
3075 {
3076 goto Exit;
3077 }
3078 }
3079
3080 Ret = IntDeferWindowPos(WinPosInfo, Wnd, WndInsertAfter, x, y, cx, cy, Flags);
3081
3082 Exit:
3083 TRACE("Leave NtUserDeferWindowPos, ret=%p\n", Ret);
3084 UserLeave();
3085 return Ret;
3086 }
3087
3088 /*
3089 * @implemented
3090 */
3091 DWORD APIENTRY
3092 NtUserGetInternalWindowPos( HWND hWnd,
3093 LPRECT rectWnd,
3094 LPPOINT ptIcon)
3095 {
3096 PWND Window;
3097 DWORD Ret = 0;
3098 BOOL Hit = FALSE;
3099 WINDOWPLACEMENT wndpl;
3100
3101 UserEnterShared();
3102
3103 if (!(Window = UserGetWindowObject(hWnd)))
3104 {
3105 Hit = FALSE;
3106 goto Exit;
3107 }
3108
3109 _SEH2_TRY
3110 {
3111 if(rectWnd)
3112 {
3113 ProbeForWrite(rectWnd,
3114 sizeof(RECT),
3115 1);
3116 }
3117 if(ptIcon)
3118 {
3119 ProbeForWrite(ptIcon,
3120 sizeof(POINT),
3121 1);
3122 }
3123
3124 }
3125 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3126 {
3127 SetLastNtError(_SEH2_GetExceptionCode());
3128 Hit = TRUE;
3129 }
3130 _SEH2_END;
3131
3132 wndpl.length = sizeof(WINDOWPLACEMENT);
3133
3134 if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
3135 {
3136 _SEH2_TRY
3137 {
3138 if (rectWnd)
3139 {
3140 RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));
3141 }
3142 if (ptIcon)
3143 {
3144 RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT));
3145 }
3146
3147 }
3148 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3149 {
3150 SetLastNtError(_SEH2_GetExceptionCode());
3151 Hit = TRUE;
3152 }
3153 _SEH2_END;
3154
3155 if (!Hit) Ret = wndpl.showCmd;
3156 }
3157 Exit:
3158 UserLeave();
3159 return Ret;
3160 }
3161
3162 /*
3163 * @implemented
3164 */
3165 BOOL APIENTRY
3166 NtUserGetWindowPlacement(HWND hWnd,
3167 WINDOWPLACEMENT *lpwndpl)
3168 {
3169 PWND Wnd;
3170 WINDOWPLACEMENT Safepl;
3171 NTSTATUS Status;
3172 DECLARE_RETURN(BOOL);
3173
3174 TRACE("Enter NtUserGetWindowPlacement\n");
3175 UserEnterShared();
3176
3177 if (!(Wnd = UserGetWindowObject(hWnd)))
3178 {
3179 RETURN( FALSE);
3180 }
3181
3182 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3183 if (!NT_SUCCESS(Status))
3184 {
3185 SetLastNtError(Status);
3186 RETURN( FALSE);
3187 }
3188
3189 Safepl.length = sizeof(WINDOWPLACEMENT);
3190
3191 IntGetWindowPlacement(Wnd, &Safepl);
3192
3193 Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
3194 if (!NT_SUCCESS(Status))
3195 {
3196 SetLastNtError(Status);
3197 RETURN( FALSE);
3198 }
3199
3200 RETURN( TRUE);
3201
3202 CLEANUP:
3203 TRACE("Leave NtUserGetWindowPlacement, ret=%i\n",_ret_);
3204 UserLeave();
3205 END_CLEANUP;
3206 }
3207
3208 DWORD
3209 APIENTRY
3210 NtUserMinMaximize(
3211 HWND hWnd,
3212 UINT cmd, // Wine SW_ commands
3213 BOOL Hide)
3214 {
3215 PWND pWnd;
3216
3217 TRACE("Enter NtUserMinMaximize\n");
3218 UserEnterExclusive();
3219
3220 pWnd = UserGetWindowObject(hWnd);
3221 if (!pWnd || UserIsDesktopWindow(pWnd) || UserIsMessageWindow(pWnd))
3222 {
3223 goto Exit;
3224 }
3225
3226 if ( cmd > SW_MAX || pWnd->state2 & WNDS2_INDESTROY)
3227 {
3228 EngSetLastError(ERROR_INVALID_PARAMETER);
3229 goto Exit;
3230 }
3231
3232 cmd |= Hide ? SW_HIDE : 0;
3233
3234 co_WinPosShowWindow(pWnd, cmd);
3235
3236 Exit:
3237 TRACE("Leave NtUserMinMaximize\n");
3238 UserLeave();
3239 return 0; // Always NULL?
3240 }
3241
3242 /*
3243 * @implemented
3244 */
3245 BOOL APIENTRY
3246 NtUserMoveWindow(
3247 HWND hWnd,
3248 int X,
3249 int Y,
3250 int nWidth,
3251 int nHeight,
3252 BOOL bRepaint)
3253 {
3254 return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight,
3255 (bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE :
3256 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW));
3257 }
3258
3259 /*
3260 * @implemented
3261 */
3262 HWND APIENTRY
3263 NtUserRealChildWindowFromPoint(HWND Parent,
3264 LONG x,
3265 LONG y)
3266 {
3267 PWND pwndParent;
3268 TRACE("Enter NtUserRealChildWindowFromPoint\n");
3269 UserEnterShared();
3270 if ((pwndParent = UserGetWindowObject(Parent)))
3271 {
3272 pwndParent = IntRealChildWindowFromPoint(pwndParent, x, y);
3273 }
3274 UserLeave();
3275 TRACE("Leave NtUserRealChildWindowFromPoint\n");
3276 return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
3277 }
3278
3279 /*
3280 * @implemented
3281 */
3282 BOOL APIENTRY
3283 NtUserSetWindowPos(
3284 HWND hWnd,
3285 HWND hWndInsertAfter,
3286 int X,
3287 int Y,
3288 int cx,
3289 int cy,
3290 UINT uFlags)
3291 {
3292 DECLARE_RETURN(BOOL);
3293 PWND Window, pWndIA;
3294 BOOL ret;
3295 USER_REFERENCE_ENTRY Ref;
3296
3297 TRACE("Enter NtUserSetWindowPos\n");
3298 UserEnterExclusive();
3299
3300 if (!(Window = UserGetWindowObject(hWnd)) ||
3301 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3302 {
3303 ERR("NtUserSetWindowPos bad window handle!\n");
3304 RETURN(FALSE);
3305 }
3306
3307 if ( hWndInsertAfter &&
3308 hWndInsertAfter != HWND_BOTTOM &&
3309 hWndInsertAfter != HWND_TOPMOST &&
3310 hWndInsertAfter != HWND_NOTOPMOST )
3311 {
3312 if (!(pWndIA = UserGetWindowObject(hWndInsertAfter)) ||
3313 UserIsDesktopWindow(pWndIA) || UserIsMessageWindow(pWndIA))
3314 {
3315 ERR("NtUserSetWindowPos bad insert window handle!\n");
3316 RETURN(FALSE);
3317 }
3318 }
3319
3320 /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
3321 if (!(uFlags & SWP_NOMOVE))
3322 {
3323 if (X < -32768) X = -32768;
3324 else if (X > 32767) X = 32767;
3325 if (Y < -32768) Y = -32768;
3326 else if (Y > 32767) Y = 32767;
3327 }
3328 if (!(uFlags & SWP_NOSIZE))
3329 {
3330 if (cx < 0) cx = 0;
3331 else if (cx > 32767) cx = 32767;
3332 if (cy < 0) cy = 0;
3333 else if (cy > 32767) cy = 32767;
3334 }
3335
3336 UserRefObjectCo(Window, &Ref);
3337 ret = co_WinPosSetWindowPos(Window, hWndInsertAfter, X, Y, cx, cy, uFlags);
3338 UserDerefObjectCo(Window);
3339
3340 RETURN(ret);
3341
3342 CLEANUP:
3343 TRACE("Leave NtUserSetWindowPos, ret=%i\n",_ret_);
3344 UserLeave();
3345 END_CLEANUP;
3346 }
3347
3348 /*
3349 * @implemented
3350 */
3351 INT APIENTRY
3352 NtUserSetWindowRgn(
3353 HWND hWnd,
3354 HRGN hRgn,
3355 BOOL bRedraw)
3356 {
3357 HRGN hrgnCopy = NULL;
3358 PWND Window;
3359 INT flags = (SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE);
3360 BOOLEAN Ret = FALSE;
3361 DECLARE_RETURN(INT);
3362
3363 TRACE("Enter NtUserSetWindowRgn\n");
3364 UserEnterExclusive();
3365
3366 if (!(Window = UserGetWindowObject(hWnd)) ||
3367 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3368 {
3369 RETURN( 0);
3370 }
3371
3372 if (hRgn) // The region will be deleted in user32.
3373 {
3374 if (GreIsHandleValid(hRgn))
3375 {
3376 hrgnCopy = NtGdiCreateRectRgn(0, 0, 0, 0);
3377 /* The coordinates of a window's window region are relative to the
3378 upper-left corner of the window, not the client area of the window. */
3379 NtGdiCombineRgn( hrgnCopy, hRgn, 0, RGN_COPY);
3380 }
3381 else
3382 RETURN( 0);
3383 }
3384
3385 //// HACK 1 : Work around the lack of supporting DeferWindowPos.
3386 if (hrgnCopy)
3387 {
3388 Window->hrgnNewFrame = hrgnCopy; // Should be PSMWP->acvr->hrgnClip
3389 }
3390 else
3391 {
3392 Window->hrgnNewFrame = HRGN_WINDOW;
3393 }
3394 //// HACK 2
3395 Ret = co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, bRedraw ? flags : (flags|SWP_NOREDRAW) );
3396
3397 RETURN( (INT)Ret);
3398
3399 CLEANUP:
3400 TRACE("Leave NtUserSetWindowRgn, ret=%i\n",_ret_);
3401 UserLeave();
3402 END_CLEANUP;
3403 }
3404
3405 /*
3406 * @implemented
3407 */
3408 DWORD APIENTRY
3409 NtUserSetInternalWindowPos(
3410 HWND hwnd,
3411 UINT showCmd,
3412 LPRECT lprect,
3413 LPPOINT lppt)
3414 {
3415 WINDOWPLACEMENT wndpl;
3416 UINT flags;
3417 PWND Wnd;
3418 RECT rect;
3419 POINT pt = {0};
3420 DECLARE_RETURN(BOOL);
3421 USER_REFERENCE_ENTRY Ref;
3422
3423 TRACE("Enter NtUserSetWindowPlacement\n");
3424 UserEnterExclusive();
3425
3426 if (!(Wnd = UserGetWindowObject(hwnd)) || // FIXME:
3427 UserIsDesktopWindow(Wnd) || UserIsMessageWindow(Wnd))
3428 {
3429 RETURN( FALSE);
3430 }
3431
3432 _SEH2_TRY
3433 {
3434 if (lppt)
3435 {
3436 ProbeForRead(lppt, sizeof(POINT), 1);
3437 RtlCopyMemory(&pt, lppt, sizeof(POINT));
3438 }
3439 if (lprect)
3440 {
3441 ProbeForRead(lprect, sizeof(RECT), 1);
3442 RtlCopyMemory(&rect, lprect, sizeof(RECT));
3443 }
3444 }
3445 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3446 {
3447 SetLastNtError(_SEH2_GetExceptionCode());
3448 _SEH2_YIELD(RETURN( FALSE));
3449 }
3450 _SEH2_END
3451
3452 wndpl.length = sizeof(wndpl);
3453 wndpl.showCmd = showCmd;
3454 wndpl.flags = flags = 0;
3455
3456 if ( lppt )
3457 {
3458 flags |= PLACE_MIN;
3459 wndpl.flags |= WPF_SETMINPOSITION;
3460 wndpl.ptMinPosition = pt;
3461 }
3462 if ( lprect )
3463 {
3464 flags |= PLACE_RECT;
3465 wndpl.rcNormalPosition = rect;
3466 }
3467
3468 UserRefObjectCo(Wnd, &Ref);
3469 IntSetWindowPlacement(Wnd, &wndpl, flags);
3470 UserDerefObjectCo(Wnd);
3471 RETURN(TRUE);
3472
3473 CLEANUP:
3474 TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
3475 UserLeave();
3476 END_CLEANUP;
3477 }
3478
3479 /*
3480 * @implemented
3481 */
3482 BOOL APIENTRY
3483 NtUserSetWindowPlacement(HWND hWnd,
3484 WINDOWPLACEMENT *lpwndpl)
3485 {
3486 PWND Wnd;
3487 WINDOWPLACEMENT Safepl;
3488 UINT Flags;
3489 DECLARE_RETURN(BOOL);
3490 USER_REFERENCE_ENTRY Ref;
3491
3492 TRACE("Enter NtUserSetWindowPlacement\n");
3493 UserEnterExclusive();
3494
3495 if (!(Wnd = UserGetWindowObject(hWnd)) ||
3496 UserIsDesktopWindow(Wnd) || UserIsMessageWindow(Wnd))
3497 {
3498 RETURN( FALSE);
3499 }
3500
3501 _SEH2_TRY
3502 {
3503 ProbeForRead(lpwndpl, sizeof(WINDOWPLACEMENT), 1);
3504 RtlCopyMemory(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3505 }
3506 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3507 {
3508 SetLastNtError(_SEH2_GetExceptionCode());
3509 _SEH2_YIELD(RETURN( FALSE));
3510 }
3511 _SEH2_END
3512
3513 if(Safepl.length != sizeof(WINDOWPLACEMENT))
3514 {
3515 RETURN( FALSE);
3516 }
3517
3518 Flags = PLACE_MAX | PLACE_RECT;
3519 if (Safepl.flags & WPF_SETMINPOSITION) Flags |= PLACE_MIN;
3520 UserRefObjectCo(Wnd, &Ref);
3521 IntSetWindowPlacement(Wnd, &Safepl, Flags);
3522 UserDerefObjectCo(Wnd);
3523 RETURN(TRUE);
3524
3525 CLEANUP:
3526 TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
3527 UserLeave();
3528 END_CLEANUP;
3529 }
3530
3531 /*
3532 * @implemented
3533 */
3534 BOOL APIENTRY
3535 NtUserShowWindowAsync(HWND hWnd, LONG nCmdShow)
3536 {
3537 PWND Window;
3538 BOOL ret;
3539 DECLARE_RETURN(BOOL);
3540 USER_REFERENCE_ENTRY Ref;
3541
3542 TRACE("Enter NtUserShowWindowAsync\n");
3543 UserEnterExclusive();
3544
3545 if (!(Window = UserGetWindowObject(hWnd)) ||
3546 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3547 {
3548 RETURN(FALSE);
3549 }
3550
3551 if ( nCmdShow > SW_MAX )
3552 {
3553 EngSetLastError(ERROR_INVALID_PARAMETER);
3554 RETURN(FALSE);
3555 }
3556
3557 UserRefObjectCo(Window, &Ref);
3558 ret = co_IntSendMessageNoWait( hWnd, WM_ASYNC_SHOWWINDOW, nCmdShow, 0 );
3559 UserDerefObjectCo(Window);
3560 if (-1 == (int) ret || !ret) ret = FALSE;
3561
3562 RETURN(ret);
3563
3564 CLEANUP:
3565 TRACE("Leave NtUserShowWindowAsync, ret=%i\n",_ret_);
3566 UserLeave();
3567 END_CLEANUP;
3568 }
3569
3570 /*
3571 * @implemented
3572 */
3573 BOOL APIENTRY
3574 NtUserShowWindow(HWND hWnd, LONG nCmdShow)
3575 {
3576 PWND Window;
3577 BOOL ret;
3578 DECLARE_RETURN(BOOL);
3579 USER_REFERENCE_ENTRY Ref;
3580
3581 TRACE("Enter NtUserShowWindow hWnd %p SW_ %d\n",hWnd, nCmdShow);
3582 UserEnterExclusive();
3583
3584 if (!(Window = UserGetWindowObject(hWnd)) ||
3585 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3586 {
3587 RETURN(FALSE);
3588 }
3589
3590 if ( nCmdShow > SW_MAX || Window->state2 & WNDS2_INDESTROY)
3591 {
3592 EngSetLastError(ERROR_INVALID_PARAMETER);
3593 RETURN(FALSE);
3594 }
3595
3596 UserRefObjectCo(Window, &Ref);
3597 ret = co_WinPosShowWindow(Window, nCmdShow);
3598 UserDerefObjectCo(Window);
3599
3600 RETURN(ret);
3601
3602 CLEANUP:
3603 TRACE("Leave NtUserShowWindow, ret=%i\n",_ret_);
3604 UserLeave();
3605 END_CLEANUP;
3606 }
3607
3608
3609 /*
3610 * @implemented
3611 */
3612 HWND APIENTRY
3613 NtUserWindowFromPoint(LONG X, LONG Y)
3614 {
3615 POINT pt;
3616 HWND Ret;
3617 PWND DesktopWindow = NULL, Window = NULL;
3618 USHORT hittest;
3619 DECLARE_RETURN(HWND);
3620 USER_REFERENCE_ENTRY Ref;
3621
3622 TRACE("Enter NtUserWindowFromPoint\n");
3623 UserEnterExclusive();
3624
3625 if ((DesktopWindow = UserGetWindowObject(IntGetDesktopWindow())))
3626 {
3627 //PTHREADINFO pti;
3628
3629 pt.x = X;
3630 pt.y = Y;
3631
3632 // Hmm... Threads live on desktops thus we have a reference on the desktop and indirectly the desktop window.
3633 // It is possible this referencing is useless, though it should not hurt...
3634 UserRefObjectCo(DesktopWindow, &Ref);
3635
3636 //pti = PsGetCurrentThreadWin32Thread();
3637 Window = co_WinPosWindowFromPoint(DesktopWindow, &pt, &hittest, FALSE);
3638
3639 if (Window)
3640 {
3641 Ret = UserHMGetHandle(Window);
3642
3643 RETURN( Ret);
3644 }
3645 }
3646
3647 RETURN( NULL);
3648
3649 CLEANUP:
3650 if (DesktopWindow) UserDerefObjectCo(DesktopWindow);
3651
3652 TRACE("Leave NtUserWindowFromPoint, ret=%p\n", _ret_);
3653 UserLeave();
3654 END_CLEANUP;
3655 }
3656
3657 /* EOF */