[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 ( Wnd != UserGetDesktopWindow()) // Wnd->fnid != FNID_DESKTOP )
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 ( Wnd != UserGetDesktopWindow()) // Wnd->fnid != FNID_DESKTOP )
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 && FromWnd != UserGetDesktopWindow()) // FromWnd->fnid != FNID_DESKTOP)
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 && ToWnd != UserGetDesktopWindow()) // ToWnd->fnid != FNID_DESKTOP)
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 (Window != UserGetDesktopWindow()) // Window->fnid != FNID_DESKTOP)
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 IntSetFocusMessageQueue(NULL);
405 return;
406 }
407
408 /* If this is popup window, try to activate the owner first. */
409 if ((Wnd->style & WS_POPUP) && (WndTo = Wnd->spwndOwner))
410 {
411 TRACE("WPAOW Popup with Owner\n");
412 WndTo = UserGetAncestor( WndTo, GA_ROOT );
413 if (can_activate_window(WndTo)) goto done;
414 }
415
416 /* Pick a next top-level window. */
417 /* FIXME: Search for non-tooltip windows first. */
418 WndTo = Wnd;
419 for (;;)
420 {
421 if (!(WndTo = WndTo->spwndNext)) break;
422 if (can_activate_window( WndTo )) goto done;
423 }
424
425 /*
426 Fixes wine win.c:test_SetParent last ShowWindow test after popup dies.
427 Check for previous active window to bring to top.
428 */
429 if (Wnd)
430 {
431 WndTo = Wnd->head.pti->MessageQueue->spwndActivePrev;
432 if (can_activate_window( WndTo )) goto done;
433 }
434
435 // Find any window to bring to top. Works Okay for wine since it does not see X11 windows.
436 WndTo = UserGetDesktopWindow();
437 WndTo = WndTo->spwndChild;
438 if ( WndTo == NULL )
439 {
440 return;
441 }
442 for (;;)
443 {
444 if (WndTo == Wnd)
445 {
446 WndTo = NULL;
447 break;
448 }
449 if (can_activate_window( WndTo )) goto done;
450 if (!(WndTo = WndTo->spwndNext)) break;
451 }
452
453 done:
454 if (WndTo) UserRefObjectCo(WndTo, &Ref);
455
456 if (gpqForeground && (!gpqForeground->spwndActive || Wnd == gpqForeground->spwndActive))
457 {
458 /* ReactOS can pass WndTo = NULL to co_IntSetForegroundWindow and returns FALSE. */
459 //ERR("WinPosActivateOtherWindow Set FG 0x%p hWnd %p\n",WndTo, WndTo ? WndTo->head.h : 0);
460 if (co_IntSetForegroundWindow(WndTo))
461 {
462 if (WndTo) UserDerefObjectCo(WndTo);
463 return;
464 }
465 }
466 //ERR("WinPosActivateOtherWindow Set Active 0x%p\n",WndTo);
467 if (!co_IntSetActiveWindow(WndTo,FALSE,TRUE,FALSE)) /* Ok for WndTo to be NULL here */
468 {
469 //ERR("WPAOW SA 1\n");
470 co_IntSetActiveWindow(NULL,FALSE,TRUE,FALSE);
471 }
472 if (WndTo) UserDerefObjectCo(WndTo);
473 }
474
475 VOID FASTCALL
476 WinPosInitInternalPos(PWND Wnd, RECTL *RestoreRect)
477 {
478 POINT Size;
479 RECTL Rect = *RestoreRect;
480
481 if (Wnd->spwndParent && Wnd->spwndParent != UserGetDesktopWindow())
482 {
483 RECTL_vOffsetRect(&Rect,
484 -Wnd->spwndParent->rcClient.left,
485 -Wnd->spwndParent->rcClient.top);
486 }
487
488 Size.x = Rect.left;
489 Size.y = Rect.top;
490
491 if (!Wnd->InternalPosInitialized)
492 {
493 // FIXME: Use check point Atom..
494 Wnd->InternalPos.flags = 0;
495 Wnd->InternalPos.MaxPos.x = Wnd->InternalPos.MaxPos.y = -1;
496 Wnd->InternalPos.IconPos.x = Wnd->InternalPos.IconPos.y = -1;
497 Wnd->InternalPos.NormalRect = Rect;
498 Wnd->InternalPosInitialized = TRUE;
499 }
500
501 if (Wnd->style & WS_MINIMIZE)
502 {
503 Wnd->InternalPos.IconPos = Size;
504 Wnd->InternalPos.flags |= WPF_MININIT;
505 }
506 else if (Wnd->style & WS_MAXIMIZE)
507 {
508 Wnd->InternalPos.flags |= WPF_MAXINIT;
509
510 if ( Wnd->spwndParent == Wnd->head.rpdesk->pDeskInfo->spwnd )
511 {
512 if (Wnd->state & WNDS_MAXIMIZESTOMONITOR)
513 {
514 Wnd->InternalPos.flags &= ~WPF_MAXINIT;
515 Wnd->InternalPos.MaxPos.x = Wnd->InternalPos.MaxPos.y = -1;
516 }
517 else
518 {
519 RECTL WorkArea;
520 PMONITOR pmonitor = UserMonitorFromRect(&Rect, MONITOR_DEFAULTTOPRIMARY );
521 // FIXME: support DPI aware, rcWorkDPI/Real etc..
522 WorkArea = pmonitor->rcMonitor;
523
524 if (Wnd->style & WS_MAXIMIZEBOX)
525 { // Support (Wnd->state & WNDS_HASCAPTION) || pmonitor->cFullScreen too.
526 if ((Wnd->style & WS_CAPTION) == WS_CAPTION || !(Wnd->style & (WS_CHILD | WS_POPUP)))
527 {
528 WorkArea = pmonitor->rcWork;
529 //ERR("rcWork\n");
530 }
531 }
532
533 Wnd->InternalPos.MaxPos.x = Rect.left - WorkArea.left;
534 Wnd->InternalPos.MaxPos.y = Rect.top - WorkArea.top;
535
536 /*ERR("WinPosIP 2 X %d = R.l %d - W.l %d | Y %d = R.t %d - W.t %d\n",
537 Wnd->InternalPos.MaxPos.x,
538 Rect.left, WorkArea.left,
539 Wnd->InternalPos.MaxPos.y,
540 Rect.top, WorkArea.top);*/
541 }
542 }
543 else
544 Wnd->InternalPos.MaxPos = Size;
545 }
546 else
547 {
548 Wnd->InternalPos.NormalRect = Rect;
549 }
550 }
551
552 BOOL
553 FASTCALL
554 IntGetWindowPlacement(PWND Wnd, WINDOWPLACEMENT *lpwndpl)
555 {
556 if (!Wnd) return FALSE;
557
558 if(lpwndpl->length != sizeof(WINDOWPLACEMENT))
559 {
560 return FALSE;
561 }
562
563 lpwndpl->flags = 0;
564
565 WinPosInitInternalPos(Wnd, &Wnd->rcWindow);
566
567 lpwndpl->showCmd = SW_HIDE;
568
569 if ( Wnd->style & WS_MINIMIZE )
570 lpwndpl->showCmd = SW_SHOWMINIMIZED;
571 else
572 lpwndpl->showCmd = ( Wnd->style & WS_MAXIMIZE ) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL ;
573
574 lpwndpl->rcNormalPosition = Wnd->InternalPos.NormalRect;
575
576 if (Wnd->InternalPos.flags & WPF_MININIT) // Return if it was set!
577 {
578 lpwndpl->ptMinPosition.x = Wnd->InternalPos.IconPos.x;
579 lpwndpl->ptMinPosition.y = Wnd->InternalPos.IconPos.y;
580 }
581 else
582 lpwndpl->ptMinPosition.x = lpwndpl->ptMinPosition.y = -1;
583
584 if ( Wnd->InternalPos.flags & WPF_MAXINIT && // Return if set and not maximized to monitor!
585 !(Wnd->state & WNDS_MAXIMIZESTOMONITOR))
586 {
587 lpwndpl->ptMaxPosition.x = Wnd->InternalPos.MaxPos.x;
588 lpwndpl->ptMaxPosition.y = Wnd->InternalPos.MaxPos.y;
589 }
590 else
591 lpwndpl->ptMaxPosition.x = lpwndpl->ptMaxPosition.y = -1;
592
593 if ( Wnd->spwndParent == Wnd->head.rpdesk->pDeskInfo->spwnd &&
594 !(Wnd->ExStyle & WS_EX_TOOLWINDOW))
595 {
596 PMONITOR pmonitor = UserMonitorFromRect(&lpwndpl->rcNormalPosition, MONITOR_DEFAULTTOPRIMARY );
597
598 // FIXME: support DPI aware, rcWorkDPI/Real etc..
599 if (Wnd->InternalPos.flags & WPF_MININIT)
600 {
601 lpwndpl->ptMinPosition.x -= (pmonitor->rcWork.left - pmonitor->rcMonitor.left);
602 lpwndpl->ptMinPosition.y -= (pmonitor->rcWork.top - pmonitor->rcMonitor.top);
603 }
604 RECTL_vOffsetRect(&lpwndpl->rcNormalPosition,
605 pmonitor->rcMonitor.left - pmonitor->rcWork.left,
606 pmonitor->rcMonitor.top - pmonitor->rcWork.top);
607 }
608
609 if ( Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED || Wnd->style & WS_MAXIMIZE )
610 lpwndpl->flags |= WPF_RESTORETOMAXIMIZED;
611
612 if ( ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD) && Wnd->InternalPos.flags & WPF_SETMINPOSITION)
613 lpwndpl->flags |= WPF_SETMINPOSITION;
614
615 return TRUE;
616 }
617
618 /* make sure the specified rect is visible on screen */
619 static void make_rect_onscreen( RECT *rect )
620 {
621 PMONITOR pmonitor = UserMonitorFromRect( rect, MONITOR_DEFAULTTONEAREST ); // Wine uses this.
622
623 // FIXME: support DPI aware, rcWorkDPI/Real etc..
624 if (!pmonitor) return;
625 /* FIXME: map coordinates from rcWork to rcMonitor */
626 if (rect->right <= pmonitor->rcWork.left)
627 {
628 rect->right += pmonitor->rcWork.left - rect->left;
629 rect->left = pmonitor->rcWork.left;
630 }
631 else if (rect->left >= pmonitor->rcWork.right)
632 {
633 rect->left += pmonitor->rcWork.right - rect->right;
634 rect->right = pmonitor->rcWork.right;
635 }
636 if (rect->bottom <= pmonitor->rcWork.top)
637 {
638 rect->bottom += pmonitor->rcWork.top - rect->top;
639 rect->top = pmonitor->rcWork.top;
640 }
641 else if (rect->top >= pmonitor->rcWork.bottom)
642 {
643 rect->top += pmonitor->rcWork.bottom - rect->bottom;
644 rect->bottom = pmonitor->rcWork.bottom;
645 }
646 }
647
648 /* make sure the specified point is visible on screen */
649 static void make_point_onscreen( POINT *pt )
650 {
651 RECT rect;
652
653 RECTL_vSetRect( &rect, pt->x, pt->y, pt->x + 1, pt->y + 1 );
654 make_rect_onscreen( &rect );
655 pt->x = rect.left;
656 pt->y = rect.top;
657 }
658
659 BOOL FASTCALL
660 IntSetWindowPlacement(PWND Wnd, WINDOWPLACEMENT *wpl, UINT Flags)
661 {
662 BOOL sAsync;
663 UINT SWP_Flags;
664
665 if ( Flags & PLACE_MIN) make_point_onscreen( &wpl->ptMinPosition );
666 if ( Flags & PLACE_MAX) make_point_onscreen( &wpl->ptMaxPosition );
667 if ( Flags & PLACE_RECT) make_rect_onscreen( &wpl->rcNormalPosition );
668
669 if (!Wnd || Wnd == Wnd->head.rpdesk->pDeskInfo->spwnd) return FALSE;
670
671 if ( Flags & PLACE_MIN ) Wnd->InternalPos.IconPos = wpl->ptMinPosition;
672 if ( Flags & PLACE_MAX ) Wnd->InternalPos.MaxPos = wpl->ptMaxPosition;
673 if ( Flags & PLACE_RECT) Wnd->InternalPos.NormalRect = wpl->rcNormalPosition;
674
675 SWP_Flags = SWP_NOZORDER | SWP_NOACTIVATE | ((wpl->flags & WPF_ASYNCWINDOWPLACEMENT) ? SWP_ASYNCWINDOWPOS : 0);
676
677 if (Wnd->style & WS_MINIMIZE )
678 {
679 if (Flags & PLACE_MIN || Wnd->InternalPos.flags & WPF_SETMINPOSITION)
680 {
681 co_WinPosSetWindowPos(Wnd, HWND_TOP,
682 wpl->ptMinPosition.x, wpl->ptMinPosition.y, 0, 0,
683 SWP_NOSIZE | SWP_Flags);
684 Wnd->InternalPos.flags |= WPF_MININIT;
685 }
686 }
687 else if (Wnd->style & WS_MAXIMIZE )
688 {
689 if (Flags & PLACE_MAX)
690 {
691 co_WinPosSetWindowPos(Wnd, HWND_TOP,
692 wpl->ptMaxPosition.x, wpl->ptMaxPosition.y, 0, 0,
693 SWP_NOSIZE | SWP_Flags);
694 Wnd->InternalPos.flags |= WPF_MAXINIT;
695 }
696 }
697 else if (Flags & PLACE_RECT)
698 {
699 co_WinPosSetWindowPos(Wnd, HWND_TOP,
700 wpl->rcNormalPosition.left, wpl->rcNormalPosition.top,
701 wpl->rcNormalPosition.right - wpl->rcNormalPosition.left,
702 wpl->rcNormalPosition.bottom - wpl->rcNormalPosition.top,
703 SWP_Flags);
704 }
705
706 sAsync = (Wnd->head.pti->MessageQueue != gptiCurrent->MessageQueue && wpl->flags & WPF_ASYNCWINDOWPLACEMENT);
707
708 if ( sAsync )
709 co_IntSendMessageNoWait( UserHMGetHandle(Wnd), WM_ASYNC_SHOWWINDOW, wpl->showCmd, 0 );
710 else
711 co_WinPosShowWindow(Wnd, wpl->showCmd);
712
713 if ( Wnd->style & WS_MINIMIZE && !sAsync )
714 {
715 if ( wpl->flags & WPF_SETMINPOSITION )
716 Wnd->InternalPos.flags |= WPF_SETMINPOSITION;
717
718 if ( wpl->flags & WPF_RESTORETOMAXIMIZED )
719 Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED;
720 }
721 return TRUE;
722 }
723
724 UINT
725 FASTCALL
726 co_WinPosArrangeIconicWindows(PWND parent)
727 {
728 RECTL rectParent;
729 PWND Child;
730 INT x, y, xspacing, yspacing, sx, sy;
731
732 ASSERT_REFS_CO(parent);
733
734 IntGetClientRect( parent, &rectParent );
735 // FIXME: Support Minimize Metrics gspv.mm.iArrange.
736 // Default: ARW_BOTTOMLEFT
737 x = rectParent.left;
738 y = rectParent.bottom;
739
740 xspacing = UserGetSystemMetrics(SM_CXMINIMIZED);
741 yspacing = UserGetSystemMetrics(SM_CYMINIMIZED);
742
743 Child = parent->spwndChild;
744 while(Child)
745 {
746 if((Child->style & WS_MINIMIZE) != 0 )
747 {
748 USER_REFERENCE_ENTRY Ref;
749 UserRefObjectCo(Child, &Ref);
750
751 sx = x + UserGetSystemMetrics(SM_CXBORDER);
752 sy = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
753
754 Child->InternalPos.IconPos.x = sx;
755 Child->InternalPos.IconPos.y = sy;
756 Child->InternalPos.flags |= WPF_MININIT;
757
758 co_WinPosSetWindowPos( Child, 0, sx, sy, xspacing, yspacing, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_ASYNCWINDOWPOS);
759
760 UserDerefObjectCo(Child);
761
762 if (x <= rectParent.right - xspacing)
763 x += xspacing;
764 else
765 {
766 x = rectParent.left;
767 y -= yspacing;
768 }
769 }
770 Child = Child->spwndNext;
771 }
772 return yspacing;
773 }
774
775 static VOID FASTCALL
776 WinPosFindIconPos(PWND Window, POINT *Pos)
777 {
778 RECT rectParent;
779 PWND pwndChild, pwndParent;
780 int x, y, xspacing, yspacing;
781
782 pwndParent = Window->spwndParent;
783 if (pwndParent == UserGetDesktopWindow())
784 {
785 ERR("FIXME: Parent is Desktop, Min off screen!\n");
786 /* FIXME: ReactOS doesn't support iconic minimize to desktop */
787 Pos->x = Pos->y = -32000;
788 Window->InternalPos.flags |= WPF_MININIT;
789 Window->InternalPos.IconPos.x = Pos->x;
790 Window->InternalPos.IconPos.y = Pos->y;
791 return;
792 }
793
794 IntGetClientRect( pwndParent, &rectParent );
795 // FIXME: Support Minimize Metrics gspv.mm.iArrange.
796 // Default: ARW_BOTTOMLEFT
797 x = rectParent.left;
798 y = rectParent.bottom;
799
800 xspacing = UserGetSystemMetrics(SM_CXMINIMIZED);
801 yspacing = UserGetSystemMetrics(SM_CYMINIMIZED);
802
803 // Set to default position when minimized.
804 Pos->x = x + UserGetSystemMetrics(SM_CXBORDER);
805 Pos->y = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
806
807 for (pwndChild = pwndParent->spwndChild; pwndChild; pwndChild = pwndChild->spwndNext)
808 {
809 if (pwndChild == Window) continue;
810
811 if ((pwndChild->style & (WS_VISIBLE|WS_MINIMIZE)) != (WS_VISIBLE|WS_MINIMIZE) )
812 {
813 continue;
814 }
815
816 if ( pwndChild->InternalPos.IconPos.x != Pos->x && pwndChild->InternalPos.IconPos.y != Pos->y )
817 {
818 break;
819 }
820 if (x <= rectParent.right - xspacing)
821 x += xspacing;
822 else
823 {
824 x = rectParent.left;
825 y -= yspacing;
826 }
827 Pos->x = x + UserGetSystemMetrics(SM_CXBORDER);
828 Pos->y = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
829 }
830
831 Window->InternalPos.IconPos.x = Pos->x;
832 Window->InternalPos.IconPos.y = Pos->y;
833 Window->InternalPos.flags |= WPF_MININIT;
834 TRACE("Position is set! X:%d Y:%d\n",Pos->x,Pos->y);
835 return;
836 }
837
838 UINT FASTCALL
839 co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos)
840 {
841 POINT Size;
842 WINDOWPLACEMENT wpl;
843 LONG old_style;
844 UINT SwpFlags = 0;
845
846 ASSERT_REFS_CO(Wnd);
847
848 wpl.length = sizeof(wpl);
849 IntGetWindowPlacement( Wnd, &wpl );
850
851 if (co_HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)Wnd->head.h, ShowFlag))
852 {
853 ERR("WinPosMinMaximize WH_CBT Call Hook return!\n");
854 return SWP_NOSIZE | SWP_NOMOVE;
855 }
856 if (Wnd->style & WS_MINIMIZE)
857 {
858 switch (ShowFlag)
859 {
860 case SW_MINIMIZE:
861 case SW_SHOWMINNOACTIVE:
862 case SW_SHOWMINIMIZED:
863 case SW_FORCEMINIMIZE:
864 return SWP_NOSIZE | SWP_NOMOVE;
865 }
866 if (!co_IntSendMessageNoWait(Wnd->head.h, WM_QUERYOPEN, 0, 0))
867 {
868 return(SWP_NOSIZE | SWP_NOMOVE);
869 }
870 SwpFlags |= SWP_NOCOPYBITS;
871 }
872 switch (ShowFlag)
873 {
874 case SW_MINIMIZE:
875 case SW_SHOWMINNOACTIVE:
876 case SW_SHOWMINIMIZED:
877 case SW_FORCEMINIMIZE:
878 {
879 //ERR("MinMaximize Minimize\n");
880 if (Wnd->style & WS_MAXIMIZE)
881 {
882 Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED;
883 }
884 else
885 {
886 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
887 }
888
889 old_style = IntSetStyle( Wnd, WS_MINIMIZE, WS_MAXIMIZE );
890
891 co_UserRedrawWindow(Wnd, NULL, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOINTERNALPAINT);
892
893 if (!(Wnd->InternalPos.flags & WPF_SETMINPOSITION))
894 Wnd->InternalPos.flags &= ~WPF_MININIT;
895
896 WinPosFindIconPos(Wnd, &wpl.ptMinPosition);
897
898 /*if (!(old_style & WS_MINIMIZE))
899 {
900 SwpFlags |= SWP_STATECHANGED;
901 IntShowOwnedPopups(Wnd, FALSE);
902 }*/
903
904 RECTL_vSetRect(NewPos, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
905 wpl.ptMinPosition.x + UserGetSystemMetrics(SM_CXMINIMIZED),
906 wpl.ptMinPosition.y + UserGetSystemMetrics(SM_CYMINIMIZED));
907 SwpFlags |= SWP_NOCOPYBITS;
908 break;
909 }
910
911 case SW_MAXIMIZE:
912 {
913 //ERR("MinMaximize Maximize\n");
914 if ((Wnd->style & WS_MAXIMIZE) && (Wnd->style & WS_VISIBLE))
915 {
916 SwpFlags = SWP_NOSIZE | SWP_NOMOVE;
917 break;
918 }
919 co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
920
921 /*ERR("Maximize: %d,%d %dx%d\n",
922 wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, Size.x, Size.y);
923 */
924 old_style = IntSetStyle( Wnd, WS_MAXIMIZE, WS_MINIMIZE );
925 /*if (old_style & WS_MINIMIZE)
926 {
927 IntShowOwnedPopups(Wnd, TRUE);
928 }*/
929
930 if (!(old_style & WS_MAXIMIZE)) SwpFlags |= SWP_STATECHANGED;
931 RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
932 //wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
933 Size.x, Size.y);
934 break;
935 }
936
937 case SW_SHOWNOACTIVATE:
938 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
939 /* fall through */
940 case SW_SHOWNORMAL:
941 case SW_RESTORE:
942 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
943 {
944 //ERR("MinMaximize Restore\n");
945 old_style = IntSetStyle( Wnd, 0, WS_MINIMIZE | WS_MAXIMIZE );
946 if (old_style & WS_MINIMIZE)
947 {
948 //IntShowOwnedPopups(Wnd, TRUE);
949
950 if (Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED)
951 {
952 co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
953 IntSetStyle( Wnd, WS_MAXIMIZE, 0 );
954 SwpFlags |= SWP_STATECHANGED;
955 RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
956 wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
957 break;
958 }
959 else
960 {
961 *NewPos = wpl.rcNormalPosition;
962 NewPos->right -= NewPos->left;
963 NewPos->bottom -= NewPos->top;
964 break;
965 }
966 }
967 else
968 {
969 if (!(old_style & WS_MAXIMIZE))
970 {
971 break;
972 }
973 SwpFlags |= SWP_STATECHANGED;
974 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
975 *NewPos = wpl.rcNormalPosition;
976 NewPos->right -= NewPos->left;
977 NewPos->bottom -= NewPos->top;
978 break;
979 }
980 }
981 }
982 return SwpFlags;
983 }
984
985 BOOL
986 UserHasWindowEdge(DWORD Style, DWORD ExStyle)
987 {
988 if (Style & WS_MINIMIZE)
989 return TRUE;
990 if (ExStyle & WS_EX_DLGMODALFRAME)
991 return TRUE;
992 if (ExStyle & WS_EX_STATICEDGE)
993 return FALSE;
994 if (Style & WS_THICKFRAME)
995 return TRUE;
996 Style &= WS_CAPTION;
997 if (Style == WS_DLGFRAME || Style == WS_CAPTION)
998 return TRUE;
999 return FALSE;
1000 }
1001
1002 VOID FASTCALL
1003 IntGetWindowBorderMeasures(PWND Wnd, UINT *cx, UINT *cy)
1004 {
1005 if(HAS_DLGFRAME(Wnd->style, Wnd->ExStyle) && !(Wnd->style & WS_MINIMIZE))
1006 {
1007 *cx = UserGetSystemMetrics(SM_CXDLGFRAME);
1008 *cy = UserGetSystemMetrics(SM_CYDLGFRAME);
1009 }
1010 else
1011 {
1012 if(HAS_THICKFRAME(Wnd->style, Wnd->ExStyle)&& !(Wnd->style & WS_MINIMIZE))
1013 {
1014 *cx = UserGetSystemMetrics(SM_CXFRAME);
1015 *cy = UserGetSystemMetrics(SM_CYFRAME);
1016 }
1017 else if(HAS_THINFRAME(Wnd->style, Wnd->ExStyle))
1018 {
1019 *cx = UserGetSystemMetrics(SM_CXBORDER);
1020 *cy = UserGetSystemMetrics(SM_CYBORDER);
1021 }
1022 else
1023 {
1024 *cx = *cy = 0;
1025 }
1026 }
1027 }
1028
1029 VOID
1030 UserGetWindowBorders(DWORD Style, DWORD ExStyle, SIZE *Size, BOOL WithClient)
1031 {
1032 DWORD Border = 0;
1033
1034 if (UserHasWindowEdge(Style, ExStyle))
1035 Border += 2;
1036 else if (ExStyle & WS_EX_STATICEDGE)
1037 Border += 1;
1038 if ((ExStyle & WS_EX_CLIENTEDGE) && WithClient)
1039 Border += 2;
1040 if (Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME)
1041 Border ++;
1042 Size->cx = Size->cy = Border;
1043 if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
1044 {
1045 Size->cx += UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME);
1046 Size->cy += UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME);
1047 }
1048 Size->cx *= UserGetSystemMetrics(SM_CXBORDER);
1049 Size->cy *= UserGetSystemMetrics(SM_CYBORDER);
1050 }
1051
1052 BOOL WINAPI
1053 UserAdjustWindowRectEx(LPRECT lpRect,
1054 DWORD dwStyle,
1055 BOOL bMenu,
1056 DWORD dwExStyle)
1057 {
1058 SIZE BorderSize;
1059
1060 if (bMenu)
1061 {
1062 lpRect->top -= UserGetSystemMetrics(SM_CYMENU);
1063 }
1064 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1065 {
1066 if (dwExStyle & WS_EX_TOOLWINDOW)
1067 lpRect->top -= UserGetSystemMetrics(SM_CYSMCAPTION);
1068 else
1069 lpRect->top -= UserGetSystemMetrics(SM_CYCAPTION);
1070 }
1071 UserGetWindowBorders(dwStyle, dwExStyle, &BorderSize, TRUE);
1072 RECTL_vInflateRect(
1073 lpRect,
1074 BorderSize.cx,
1075 BorderSize.cy);
1076
1077 return TRUE;
1078 }
1079
1080 UINT FASTCALL
1081 co_WinPosGetMinMaxInfo(PWND Window, POINT* MaxSize, POINT* MaxPos,
1082 POINT* MinTrack, POINT* MaxTrack)
1083 {
1084 MINMAXINFO MinMax;
1085 PMONITOR monitor;
1086 INT xinc, yinc;
1087 LONG style = Window->style;
1088 LONG adjustedStyle;
1089 LONG exstyle = Window->ExStyle;
1090 RECT rc;
1091
1092 ASSERT_REFS_CO(Window);
1093
1094 /* Compute default values */
1095
1096 rc = Window->rcWindow;
1097 MinMax.ptReserved.x = rc.left;
1098 MinMax.ptReserved.y = rc.top;
1099
1100 if ((style & WS_CAPTION) == WS_CAPTION)
1101 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
1102 else
1103 adjustedStyle = style;
1104
1105 if(Window->spwndParent)
1106 IntGetClientRect(Window->spwndParent, &rc);
1107 UserAdjustWindowRectEx(&rc, adjustedStyle, ((style & WS_POPUP) && Window->IDMenu), exstyle);
1108
1109 xinc = -rc.left;
1110 yinc = -rc.top;
1111
1112 MinMax.ptMaxSize.x = rc.right - rc.left;
1113 MinMax.ptMaxSize.y = rc.bottom - rc.top;
1114 if (style & (WS_DLGFRAME | WS_BORDER))
1115 {
1116 MinMax.ptMinTrackSize.x = UserGetSystemMetrics(SM_CXMINTRACK);
1117 MinMax.ptMinTrackSize.y = UserGetSystemMetrics(SM_CYMINTRACK);
1118 }
1119 else
1120 {
1121 MinMax.ptMinTrackSize.x = 2 * xinc;
1122 MinMax.ptMinTrackSize.y = 2 * yinc;
1123 }
1124 MinMax.ptMaxTrackSize.x = UserGetSystemMetrics(SM_CXMAXTRACK);
1125 MinMax.ptMaxTrackSize.y = UserGetSystemMetrics(SM_CYMAXTRACK);
1126 MinMax.ptMaxPosition.x = -xinc;
1127 MinMax.ptMaxPosition.y = -yinc;
1128
1129 if (!EMPTYPOINT(Window->InternalPos.MaxPos)) MinMax.ptMaxPosition = Window->InternalPos.MaxPos;
1130
1131 co_IntSendMessage(Window->head.h, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax);
1132
1133 /* if the app didn't change the values, adapt them for the current monitor */
1134 if ((monitor = UserGetPrimaryMonitor()))
1135 {
1136 RECT rc_work;
1137
1138 rc_work = monitor->rcMonitor;
1139
1140 if (style & WS_MAXIMIZEBOX)
1141 {
1142 if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP)))
1143 rc_work = monitor->rcWork;
1144 }
1145
1146 if (MinMax.ptMaxSize.x == UserGetSystemMetrics(SM_CXSCREEN) + 2 * xinc &&
1147 MinMax.ptMaxSize.y == UserGetSystemMetrics(SM_CYSCREEN) + 2 * yinc)
1148 {
1149 MinMax.ptMaxSize.x = (rc_work.right - rc_work.left) + 2 * xinc;
1150 MinMax.ptMaxSize.y = (rc_work.bottom - rc_work.top) + 2 * yinc;
1151 }
1152 if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc)
1153 {
1154 MinMax.ptMaxPosition.x = rc_work.left - xinc;
1155 MinMax.ptMaxPosition.y = rc_work.top - yinc;
1156 }
1157 if (MinMax.ptMaxSize.x >= (monitor->rcMonitor.right - monitor->rcMonitor.left) &&
1158 MinMax.ptMaxSize.y >= (monitor->rcMonitor.bottom - monitor->rcMonitor.top) )
1159 Window->state |= WNDS_MAXIMIZESTOMONITOR;
1160 else
1161 Window->state &= ~WNDS_MAXIMIZESTOMONITOR;
1162 }
1163
1164
1165 MinMax.ptMaxTrackSize.x = max(MinMax.ptMaxTrackSize.x,
1166 MinMax.ptMinTrackSize.x);
1167 MinMax.ptMaxTrackSize.y = max(MinMax.ptMaxTrackSize.y,
1168 MinMax.ptMinTrackSize.y);
1169
1170 if (MaxSize)
1171 *MaxSize = MinMax.ptMaxSize;
1172 if (MaxPos)
1173 *MaxPos = MinMax.ptMaxPosition;
1174 if (MinTrack)
1175 *MinTrack = MinMax.ptMinTrackSize;
1176 if (MaxTrack)
1177 *MaxTrack = MinMax.ptMaxTrackSize;
1178
1179 return 0; // FIXME: What does it return?
1180 }
1181
1182 static
1183 BOOL
1184 IntValidateParent(PWND Child, PREGION ValidateRgn)
1185 {
1186 PWND ParentWnd = Child;
1187
1188 if (ParentWnd->style & WS_CHILD)
1189 {
1190 do
1191 ParentWnd = ParentWnd->spwndParent;
1192 while (ParentWnd->style & WS_CHILD);
1193 }
1194
1195 ParentWnd = Child->spwndParent;
1196 while (ParentWnd)
1197 {
1198 if (ParentWnd->style & WS_CLIPCHILDREN)
1199 break;
1200
1201 if (ParentWnd->hrgnUpdate != 0)
1202 {
1203 IntInvalidateWindows( ParentWnd,
1204 ValidateRgn,
1205 RDW_VALIDATE | RDW_NOCHILDREN);
1206 }
1207
1208 ParentWnd = ParentWnd->spwndParent;
1209 }
1210
1211 return TRUE;
1212 }
1213
1214 static
1215 VOID FASTCALL
1216 FixClientRect(PRECTL ClientRect, PRECTL WindowRect)
1217 {
1218 if (ClientRect->left < WindowRect->left)
1219 {
1220 ClientRect->left = WindowRect->left;
1221 }
1222 else if (WindowRect->right < ClientRect->left)
1223 {
1224 ClientRect->left = WindowRect->right;
1225 }
1226 if (ClientRect->right < WindowRect->left)
1227 {
1228 ClientRect->right = WindowRect->left;
1229 }
1230 else if (WindowRect->right < ClientRect->right)
1231 {
1232 ClientRect->right = WindowRect->right;
1233 }
1234 if (ClientRect->top < WindowRect->top)
1235 {
1236 ClientRect->top = WindowRect->top;
1237 }
1238 else if (WindowRect->bottom < ClientRect->top)
1239 {
1240 ClientRect->top = WindowRect->bottom;
1241 }
1242 if (ClientRect->bottom < WindowRect->top)
1243 {
1244 ClientRect->bottom = WindowRect->top;
1245 }
1246 else if (WindowRect->bottom < ClientRect->bottom)
1247 {
1248 ClientRect->bottom = WindowRect->bottom;
1249 }
1250 }
1251 /***********************************************************************
1252 * get_valid_rects
1253 *
1254 * Compute the valid rects from the old and new client rect and WVR_* flags.
1255 * Helper for WM_NCCALCSIZE handling.
1256 */
1257 static
1258 VOID FASTCALL
1259 get_valid_rects( RECTL *old_client, RECTL *new_client, UINT flags, RECTL *valid )
1260 {
1261 int cx, cy;
1262
1263 if (flags & WVR_REDRAW)
1264 {
1265 RECTL_vSetEmptyRect( &valid[0] );
1266 RECTL_vSetEmptyRect( &valid[1] );
1267 return;
1268 }
1269
1270 if (flags & WVR_VALIDRECTS)
1271 {
1272 if (!RECTL_bIntersectRect( &valid[0], &valid[0], new_client ) ||
1273 !RECTL_bIntersectRect( &valid[1], &valid[1], old_client ))
1274 {
1275 RECTL_vSetEmptyRect( &valid[0] );
1276 RECTL_vSetEmptyRect( &valid[1] );
1277 return;
1278 }
1279 flags = WVR_ALIGNLEFT | WVR_ALIGNTOP;
1280 }
1281 else
1282 {
1283 valid[0] = *new_client;
1284 valid[1] = *old_client;
1285 }
1286
1287 /* make sure the rectangles have the same size */
1288 cx = min( valid[0].right - valid[0].left, valid[1].right - valid[1].left );
1289 cy = min( valid[0].bottom - valid[0].top, valid[1].bottom - valid[1].top );
1290
1291 if (flags & WVR_ALIGNBOTTOM)
1292 {
1293 valid[0].top = valid[0].bottom - cy;
1294 valid[1].top = valid[1].bottom - cy;
1295 }
1296 else
1297 {
1298 valid[0].bottom = valid[0].top + cy;
1299 valid[1].bottom = valid[1].top + cy;
1300 }
1301 if (flags & WVR_ALIGNRIGHT)
1302 {
1303 valid[0].left = valid[0].right - cx;
1304 valid[1].left = valid[1].right - cx;
1305 }
1306 else
1307 {
1308 valid[0].right = valid[0].left + cx;
1309 valid[1].right = valid[1].left + cx;
1310 }
1311 }
1312
1313 static
1314 LONG FASTCALL
1315 co_WinPosDoNCCALCSize(PWND Window, PWINDOWPOS WinPos, RECTL* WindowRect, RECTL* ClientRect, RECTL* validRects)
1316 {
1317 PWND Parent;
1318 UINT wvrFlags = 0;
1319
1320 ASSERT_REFS_CO(Window);
1321
1322 /* Send WM_NCCALCSIZE message to get new client area */
1323 if ((WinPos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE)
1324 {
1325 NCCALCSIZE_PARAMS params;
1326 WINDOWPOS winposCopy;
1327
1328 params.rgrc[0] = *WindowRect; // new coordinates of a window that has been moved or resized
1329 params.rgrc[1] = Window->rcWindow; // window before it was moved or resized
1330 params.rgrc[2] = Window->rcClient; // client area before the window was moved or resized
1331
1332 Parent = Window->spwndParent;
1333 if (0 != (Window->style & WS_CHILD) && Parent)
1334 {
1335 RECTL_vOffsetRect(&(params.rgrc[0]), - Parent->rcClient.left, - Parent->rcClient.top);
1336 RECTL_vOffsetRect(&(params.rgrc[1]), - Parent->rcClient.left, - Parent->rcClient.top);
1337 RECTL_vOffsetRect(&(params.rgrc[2]), - Parent->rcClient.left, - Parent->rcClient.top);
1338 }
1339
1340 params.lppos = &winposCopy;
1341 winposCopy = *WinPos;
1342
1343 wvrFlags = co_IntSendMessage(Window->head.h, WM_NCCALCSIZE, TRUE, (LPARAM) &params);
1344
1345 /* If the application send back garbage, ignore it */
1346 if (params.rgrc[0].left <= params.rgrc[0].right &&
1347 params.rgrc[0].top <= params.rgrc[0].bottom)
1348 {
1349 *ClientRect = params.rgrc[0]; // First rectangle contains the coordinates of the new client rectangle resulting from the move or resize
1350 if ((Window->style & WS_CHILD) && Parent)
1351 {
1352 RECTL_vOffsetRect(ClientRect, Parent->rcClient.left, Parent->rcClient.top);
1353 }
1354 FixClientRect(ClientRect, WindowRect);
1355 }
1356
1357 if (ClientRect->left != Window->rcClient.left ||
1358 ClientRect->top != Window->rcClient.top)
1359 {
1360 WinPos->flags &= ~SWP_NOCLIENTMOVE;
1361 }
1362
1363 if (ClientRect->right - ClientRect->left != Window->rcClient.right - Window->rcClient.left)
1364 {
1365 WinPos->flags &= ~SWP_NOCLIENTSIZE;
1366 }
1367 else
1368 wvrFlags &= ~WVR_HREDRAW;
1369
1370 if (ClientRect->bottom - ClientRect->top != Window->rcClient.bottom - Window->rcClient.top)
1371 {
1372 WinPos->flags &= ~SWP_NOCLIENTSIZE;
1373 }
1374 else
1375 wvrFlags &= ~WVR_VREDRAW;
1376
1377 validRects[0] = params.rgrc[1]; // second rectangle contains the valid destination rectangle
1378 validRects[1] = params.rgrc[2]; // third rectangle contains the valid source rectangle
1379 }
1380 else
1381 {
1382 if (!(WinPos->flags & SWP_NOMOVE) &&
1383 (ClientRect->left != Window->rcClient.left ||
1384 ClientRect->top != Window->rcClient.top))
1385 {
1386 WinPos->flags &= ~SWP_NOCLIENTMOVE;
1387 }
1388 }
1389
1390 if (WinPos->flags & (SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_HIDEWINDOW))
1391 {
1392 RECTL_vSetEmptyRect( &validRects[0] );
1393 RECTL_vSetEmptyRect( &validRects[1] );
1394 }
1395 else get_valid_rects( &Window->rcClient, ClientRect, wvrFlags, validRects );
1396
1397 return wvrFlags;
1398 }
1399
1400 static
1401 BOOL FASTCALL
1402 co_WinPosDoWinPosChanging(PWND Window,
1403 PWINDOWPOS WinPos,
1404 PRECTL WindowRect,
1405 PRECTL ClientRect)
1406 {
1407 ASSERT_REFS_CO(Window);
1408
1409 /* Send WM_WINDOWPOSCHANGING message */
1410
1411 if (!(WinPos->flags & SWP_NOSENDCHANGING))
1412 {
1413 TRACE("Sending WM_WINDOWPOSCHANGING to hwnd %p flags %04x.\n", Window->head.h,WinPos->flags);
1414 co_IntSendMessage(Window->head.h, WM_WINDOWPOSCHANGING, 0, (LPARAM) WinPos);
1415 }
1416
1417 /* Calculate new position and size */
1418
1419 *WindowRect = Window->rcWindow;
1420 *ClientRect = (Window->style & WS_MINIMIZE) ? Window->rcWindow : Window->rcClient;
1421
1422 if (!(WinPos->flags & SWP_NOSIZE))
1423 {
1424 if (Window->style & WS_MINIMIZE)
1425 {
1426 WindowRect->right = WindowRect->left + UserGetSystemMetrics(SM_CXMINIMIZED);
1427 WindowRect->bottom = WindowRect->top + UserGetSystemMetrics(SM_CYMINIMIZED);
1428 }
1429 else
1430 {
1431 WindowRect->right = WindowRect->left + WinPos->cx;
1432 WindowRect->bottom = WindowRect->top + WinPos->cy;
1433 }
1434 }
1435
1436 if (!(WinPos->flags & SWP_NOMOVE))
1437 {
1438 INT X, Y;
1439 PWND Parent;
1440 X = WinPos->x;
1441 Y = WinPos->y;
1442
1443 Parent = Window->spwndParent;
1444
1445 // Parent child position issue is in here. SetParent_W7 test CORE-6651.
1446 if (//((Window->style & WS_CHILD) != 0) && <- Fixes wine msg test_SetParent: "rects do not match", the last test.
1447 Parent &&
1448 Parent != Window->head.rpdesk->pDeskInfo->spwnd)
1449 {
1450 TRACE("Not SWP_NOMOVE 1 Parent client offset X %d Y %d\n",X,Y);
1451 X += Parent->rcClient.left;
1452 Y += Parent->rcClient.top;
1453 TRACE("Not SWP_NOMOVE 2 Parent client offset X %d Y %d\n",X,Y);
1454 }
1455
1456 WindowRect->left = X;
1457 WindowRect->top = Y;
1458 WindowRect->right += X - Window->rcWindow.left;
1459 WindowRect->bottom += Y - Window->rcWindow.top;
1460
1461 RECTL_vOffsetRect(ClientRect, X - Window->rcWindow.left,
1462 Y - Window->rcWindow.top);
1463 }
1464 WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
1465
1466 TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
1467 WinPos->hwnd, WinPos->hwndInsertAfter, WinPos->x, WinPos->y,
1468 WinPos->cx, WinPos->cy, WinPos->flags );
1469 TRACE("WindowRect: %d %d %d %d\n", WindowRect->left,WindowRect->top,WindowRect->right,WindowRect->bottom);
1470 TRACE("ClientRect: %d %d %d %d\n", ClientRect->left,ClientRect->top,ClientRect->right,ClientRect->bottom);
1471
1472 return TRUE;
1473 }
1474
1475 /*
1476 * Fix Z order taking into account owned popups -
1477 * basically we need to maintain them above the window that owns them
1478 *
1479 * FIXME: hide/show owned popups when owner visibility changes.
1480 *
1481 * ReactOS: See bug CORE-6129 and CORE-6554.
1482 *
1483 */
1484 ////
1485 // Pass all the win:test_children/popup_zorder tests except "move hwnd_F and its popups down" which is if'ed out.
1486 // Side effect, breaks more of the DeferWindowPos api tests, but wine breaks more!!!!
1487 static
1488 HWND FASTCALL
1489 WinPosDoOwnedPopups(PWND Window, HWND hWndInsertAfter)
1490 {
1491 HWND *List = NULL;
1492 HWND Owner;
1493 LONG Style;
1494 PWND DesktopWindow, ChildObject;
1495 int i;
1496
1497 TRACE("(%p) hInsertAfter = %p\n", Window, hWndInsertAfter );
1498
1499 Style = Window->style;
1500
1501 if (Style & WS_CHILD)
1502 {
1503 TRACE("Window is child\n");
1504 return hWndInsertAfter;
1505 }
1506
1507 Owner = Window->spwndOwner ? Window->spwndOwner->head.h : NULL;
1508
1509 if (Owner)
1510 {
1511 /* Make sure this popup stays above the owner */
1512
1513 if (hWndInsertAfter != HWND_TOPMOST)
1514 {
1515 DesktopWindow = UserGetDesktopWindow();
1516 List = IntWinListChildren(DesktopWindow);
1517
1518 if (List != NULL)
1519 {
1520 for (i = 0; List[i]; i++)
1521 {
1522 BOOL topmost = FALSE;
1523
1524 ChildObject = ValidateHwndNoErr(List[i]);
1525 if (ChildObject)
1526 {
1527 topmost = (ChildObject->ExStyle & WS_EX_TOPMOST) != 0;
1528 }
1529
1530 if (List[i] == Owner)
1531 {
1532 if (i > 0) hWndInsertAfter = List[i-1];
1533 else hWndInsertAfter = topmost ? HWND_TOPMOST : HWND_TOP;
1534 break;
1535 }
1536
1537 if (hWndInsertAfter == HWND_TOP || hWndInsertAfter == HWND_NOTOPMOST)
1538 {
1539 if (!topmost) break;
1540 }
1541 else if (List[i] == hWndInsertAfter) break;
1542 }
1543 }
1544 else
1545 return hWndInsertAfter;
1546 }
1547 }
1548
1549 if (hWndInsertAfter == HWND_BOTTOM)
1550 {
1551 ERR("Window is HWND_BOTTOM hwnd %p\n",hWndInsertAfter);
1552 if (List) ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1553 goto done;
1554 }
1555
1556 if (!List)
1557 {
1558 DesktopWindow = UserGetDesktopWindow();
1559 List = IntWinListChildren(DesktopWindow);
1560 }
1561
1562 if (List != NULL)
1563 {
1564 i = 0;
1565
1566 if (hWndInsertAfter == HWND_TOP || hWndInsertAfter == HWND_NOTOPMOST)
1567 {
1568 if (hWndInsertAfter == HWND_NOTOPMOST || !(Window->ExStyle & WS_EX_TOPMOST))
1569 {
1570 TRACE("skip all the topmost windows\n");
1571 /* skip all the topmost windows */
1572 while (List[i] &&
1573 (ChildObject = ValidateHwndNoErr(List[i])) &&
1574 (ChildObject->ExStyle & WS_EX_TOPMOST)) i++;
1575 }
1576 }
1577 else if (hWndInsertAfter != HWND_TOPMOST)
1578 {
1579 /* skip windows that are already placed correctly */
1580 for (i = 0; List[i]; i++)
1581 {
1582 if (List[i] == hWndInsertAfter) break;
1583 if (List[i] == UserHMGetHandle(Window))
1584 {
1585 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1586 goto done; /* nothing to do if window is moving backwards in z-order */
1587 }
1588 }
1589 }
1590
1591 for (; List[i]; i++)
1592 {
1593 PWND Wnd;
1594 USER_REFERENCE_ENTRY Ref;
1595
1596 if (List[i] == UserHMGetHandle(Window))
1597 break;
1598
1599 if (!(Wnd = ValidateHwndNoErr(List[i])))
1600 continue;
1601
1602 Owner = Wnd->spwndOwner ? Wnd->spwndOwner->head.h : NULL;
1603
1604 if (Owner != UserHMGetHandle(Window)) continue;
1605
1606 UserRefObjectCo(Wnd, &Ref);
1607 TRACE( "moving %p owned by %p after %p\n", List[i], UserHMGetHandle(Window), hWndInsertAfter );
1608 co_WinPosSetWindowPos(Wnd, hWndInsertAfter, 0, 0, 0, 0,
1609 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING| SWP_DEFERERASE);
1610
1611 UserDerefObjectCo(Wnd);
1612 hWndInsertAfter = List[i];
1613 }
1614 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1615 }
1616 done:
1617 return hWndInsertAfter;
1618 }
1619 ////
1620
1621 /***********************************************************************
1622 * WinPosInternalMoveWindow
1623 *
1624 * Update WindowRect and ClientRect of Window and all of its children
1625 * We keep both WindowRect and ClientRect in screen coordinates internally
1626 */
1627 static
1628 VOID FASTCALL
1629 WinPosInternalMoveWindow(PWND Window, INT MoveX, INT MoveY)
1630 {
1631 PWND Child;
1632
1633 ASSERT(Window != Window->spwndChild);
1634 TRACE("InternalMoveWin X %d Y %d\n", MoveX, MoveY);
1635
1636 Window->rcWindow.left += MoveX;
1637 Window->rcWindow.right += MoveX;
1638 Window->rcWindow.top += MoveY;
1639 Window->rcWindow.bottom += MoveY;
1640
1641 Window->rcClient.left += MoveX;
1642 Window->rcClient.right += MoveX;
1643 Window->rcClient.top += MoveY;
1644 Window->rcClient.bottom += MoveY;
1645
1646 for(Child = Window->spwndChild; Child; Child = Child->spwndNext)
1647 {
1648 WinPosInternalMoveWindow(Child, MoveX, MoveY);
1649 }
1650 }
1651
1652 /*
1653 * WinPosFixupSWPFlags
1654 *
1655 * Fix redundant flags and values in the WINDOWPOS structure.
1656 */
1657 static
1658 BOOL FASTCALL
1659 WinPosFixupFlags(WINDOWPOS *WinPos, PWND Wnd)
1660 {
1661 PWND Parent;
1662 POINT pt;
1663
1664 /* Finally make sure that all coordinates are valid */
1665 if (WinPos->x < -32768) WinPos->x = -32768;
1666 else if (WinPos->x > 32767) WinPos->x = 32767;
1667 if (WinPos->y < -32768) WinPos->y = -32768;
1668 else if (WinPos->y > 32767) WinPos->y = 32767;
1669
1670 WinPos->cx = max(WinPos->cx, 0);
1671 WinPos->cy = max(WinPos->cy, 0);
1672
1673 Parent = UserGetAncestor( Wnd, GA_PARENT );
1674 if (!IntIsWindowVisible( Parent ) &&
1675 /* Fix B : wine msg test_SetParent:WmSetParentSeq_2:25 wParam bits! */
1676 (WinPos->flags & SWP_AGG_STATUSFLAGS) == SWP_AGG_NOPOSCHANGE) WinPos->flags |= SWP_NOREDRAW;
1677
1678 if (Wnd->style & WS_VISIBLE) WinPos->flags &= ~SWP_SHOWWINDOW;
1679 else
1680 {
1681 WinPos->flags &= ~SWP_HIDEWINDOW;
1682 if (!(WinPos->flags & SWP_SHOWWINDOW)) WinPos->flags |= SWP_NOREDRAW;
1683 }
1684
1685 /* Check for right size */
1686 if (Wnd->rcWindow.right - Wnd->rcWindow.left == WinPos->cx &&
1687 Wnd->rcWindow.bottom - Wnd->rcWindow.top == WinPos->cy)
1688 {
1689 WinPos->flags |= SWP_NOSIZE;
1690 }
1691
1692 pt.x = WinPos->x;
1693 pt.y = WinPos->y;
1694 IntClientToScreen( Parent, &pt );
1695 TRACE("WPFU C2S wpx %d wpy %d ptx %d pty %d\n",WinPos->x,WinPos->y,pt.x,pt.y);
1696 /* Check for right position */
1697 if (Wnd->rcWindow.left == pt.x && Wnd->rcWindow.top == pt.y)
1698 {
1699 //ERR("In right pos\n");
1700 WinPos->flags |= SWP_NOMOVE;
1701 }
1702
1703 if ( WinPos->hwnd != UserGetForegroundWindow() && (Wnd->style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
1704 {
1705 /* Bring to the top when activating */
1706 if (!(WinPos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)) &&
1707 (WinPos->flags & SWP_NOZORDER ||
1708 (WinPos->hwndInsertAfter != HWND_TOPMOST && WinPos->hwndInsertAfter != HWND_NOTOPMOST)))
1709 {
1710 WinPos->flags &= ~SWP_NOZORDER;
1711 WinPos->hwndInsertAfter = (0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP);
1712 }
1713 }
1714
1715 /* Check hwndInsertAfter */
1716 if (!(WinPos->flags & SWP_NOZORDER))
1717 {
1718 /* Fix sign extension */
1719 if (WinPos->hwndInsertAfter == (HWND)0xffff)
1720 {
1721 WinPos->hwndInsertAfter = HWND_TOPMOST;
1722 }
1723 else if (WinPos->hwndInsertAfter == (HWND)0xfffe)
1724 {
1725 WinPos->hwndInsertAfter = HWND_NOTOPMOST;
1726 }
1727
1728 if (WinPos->hwndInsertAfter == HWND_TOP)
1729 {
1730 /* Keep it topmost when it's already topmost */
1731 if ((Wnd->ExStyle & WS_EX_TOPMOST) != 0)
1732 WinPos->hwndInsertAfter = HWND_TOPMOST;
1733
1734 if (IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd)
1735 {
1736 WinPos->flags |= SWP_NOZORDER;
1737 }
1738 }
1739 else if (WinPos->hwndInsertAfter == HWND_BOTTOM)
1740 {
1741 if (!(Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDLAST) == WinPos->hwnd)
1742 WinPos->flags |= SWP_NOZORDER;
1743 }
1744 else if (WinPos->hwndInsertAfter == HWND_TOPMOST)
1745 {
1746 if ((Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd)
1747 WinPos->flags |= SWP_NOZORDER;
1748 }
1749 else if (WinPos->hwndInsertAfter == HWND_NOTOPMOST)
1750 {
1751 if (!(Wnd->ExStyle & WS_EX_TOPMOST))
1752 WinPos->flags |= SWP_NOZORDER;
1753 }
1754 else /* hwndInsertAfter must be a sibling of the window */
1755 {
1756 PWND InsAfterWnd;
1757
1758 InsAfterWnd = ValidateHwndNoErr(WinPos->hwndInsertAfter);
1759 if(!InsAfterWnd)
1760 {
1761 return TRUE;
1762 }
1763
1764 if (InsAfterWnd->spwndParent != Wnd->spwndParent)
1765 {
1766 /* Note from wine User32 Win test_SetWindowPos:
1767 "Returns TRUE also for windows that are not siblings"
1768 "Does not seem to do anything even without passing flags, still returns TRUE"
1769 "Same thing the other way around."
1770 ".. and with these windows."
1771 */
1772 return FALSE;
1773 }
1774 else
1775 {
1776 /*
1777 * We don't need to change the Z order of hwnd if it's already
1778 * inserted after hwndInsertAfter or when inserting hwnd after
1779 * itself.
1780 */
1781 if ((WinPos->hwnd == WinPos->hwndInsertAfter) ||
1782 ((InsAfterWnd->spwndNext) && (WinPos->hwnd == InsAfterWnd->spwndNext->head.h)))
1783 {
1784 WinPos->flags |= SWP_NOZORDER;
1785 }
1786 }
1787 }
1788 }
1789
1790 return TRUE;
1791 }
1792
1793 /* x and y are always screen relative */
1794 BOOLEAN FASTCALL
1795 co_WinPosSetWindowPos(
1796 PWND Window,
1797 HWND WndInsertAfter,
1798 INT x,
1799 INT y,
1800 INT cx,
1801 INT cy,
1802 UINT flags
1803 )
1804 {
1805 WINDOWPOS WinPos;
1806 RECTL NewWindowRect;
1807 RECTL NewClientRect;
1808 RECTL valid_rects[2];
1809 PREGION VisBefore = NULL;
1810 PREGION VisBeforeJustClient = NULL;
1811 PREGION VisAfter = NULL;
1812 PREGION CopyRgn = NULL;
1813 ULONG WvrFlags = 0;
1814 RECTL OldWindowRect, OldClientRect;
1815 int RgnType;
1816 HDC Dc;
1817 RECTL CopyRect;
1818 PWND Ancestor;
1819 BOOL bPointerInWindow, PosChanged = FALSE;
1820 //PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1821
1822 ASSERT_REFS_CO(Window);
1823
1824 TRACE("pwnd %p, after %p, %d,%d (%dx%d), flags %s",
1825 Window, WndInsertAfter, x, y, cx, cy, flags);
1826 #if DBG
1827 dump_winpos_flags(flags);
1828 #endif
1829
1830 /* FIXME: Get current active window from active queue. Why? since r2915. */
1831
1832 bPointerInWindow = IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y);
1833
1834 WinPos.hwnd = Window->head.h;
1835 WinPos.hwndInsertAfter = WndInsertAfter;
1836 WinPos.x = x;
1837 WinPos.y = y;
1838 WinPos.cx = cx;
1839 WinPos.cy = cy;
1840 WinPos.flags = flags;
1841
1842 if ( flags & SWP_ASYNCWINDOWPOS )
1843 {
1844 LRESULT lRes;
1845 PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
1846 if ( ppos )
1847 {
1848 WinPos.flags &= ~SWP_ASYNCWINDOWPOS; // Clear flag.
1849 *ppos = WinPos;
1850 /* Yes it's a pointer inside Win32k! */
1851 lRes = co_IntSendMessageNoWait( WinPos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
1852 /* We handle this the same way as Event Hooks and Hooks. */
1853 if ( !lRes )
1854 {
1855 ExFreePoolWithTag(ppos, USERTAG_SWP);
1856 return FALSE;
1857 }
1858 return TRUE;
1859 }
1860 return FALSE;
1861 }
1862
1863 co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
1864
1865 /* Does the window still exist? */
1866 if (!IntIsWindow(WinPos.hwnd))
1867 {
1868 TRACE("WinPosSetWindowPos: Invalid handle 0x%p!\n",WinPos.hwnd);
1869 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
1870 return FALSE;
1871 }
1872
1873 /* Fix up the flags. */
1874 if (!WinPosFixupFlags(&WinPos, Window))
1875 {
1876 // See Note.
1877 return TRUE;
1878 }
1879
1880 Ancestor = UserGetAncestor(Window, GA_PARENT);
1881 if ( (WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER &&
1882 Ancestor && Ancestor->head.h == IntGetDesktopWindow() )
1883 {
1884 WinPos.hwndInsertAfter = WinPosDoOwnedPopups(Window, WinPos.hwndInsertAfter);
1885 }
1886
1887 if (!(WinPos.flags & SWP_NOREDRAW))
1888 {
1889 /* Compute the visible region before the window position is changed */
1890 if (!(WinPos.flags & SWP_SHOWWINDOW) &&
1891 (WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
1892 SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
1893 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
1894 {
1895 VisBefore = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1896 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1897
1898 if ( VisBefore != NULL &&
1899 REGION_Complexity(VisBefore) == NULLREGION )
1900 {
1901 REGION_Delete(VisBefore);
1902 VisBefore = NULL;
1903 }
1904 else if(VisBefore)
1905 {
1906 REGION_bOffsetRgn(VisBefore, -Window->rcWindow.left, -Window->rcWindow.top);
1907 }
1908
1909 /* Calculate the non client area for resizes, as this is used in the copy region */
1910 if (!(WinPos.flags & SWP_NOSIZE))
1911 {
1912 VisBeforeJustClient = VIS_ComputeVisibleRegion(Window, TRUE, FALSE,
1913 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1914
1915 if ( VisBeforeJustClient != NULL &&
1916 REGION_Complexity(VisBeforeJustClient) == NULLREGION )
1917 {
1918 REGION_Delete(VisBeforeJustClient);
1919 VisBeforeJustClient = NULL;
1920 }
1921 else if(VisBeforeJustClient)
1922 {
1923 REGION_bOffsetRgn(VisBeforeJustClient, -Window->rcWindow.left, -Window->rcWindow.top);
1924 }
1925 }
1926 }
1927 }
1928
1929 //// HACK 3
1930 if (Window->hrgnNewFrame)
1931 {
1932 SelectWindowRgn( Window, Window->hrgnNewFrame ); // Should be PSMWP->acvr->hrgnClip
1933 Window->hrgnNewFrame = NULL;
1934 }
1935
1936 WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect, valid_rects);
1937
1938 // ERR("co_WinPosDoNCCALCSize returned 0x%x\n valid dest: %d %d %d %d\n valid src : %d %d %d %d\n", WvrFlags,
1939 // valid_rects[0].left,valid_rects[0].top,valid_rects[0].right,valid_rects[0].bottom,
1940 // valid_rects[1].left,valid_rects[1].top,valid_rects[1].right,valid_rects[1].bottom);
1941
1942 /* Validate link windows. (also take into account shell window in hwndShellWindow) */
1943 if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow())
1944 {
1945 IntLinkHwnd(Window, WinPos.hwndInsertAfter);
1946 }
1947
1948 OldWindowRect = Window->rcWindow;
1949 OldClientRect = Window->rcClient;
1950
1951 if (NewClientRect.left != OldClientRect.left ||
1952 NewClientRect.top != OldClientRect.top)
1953 {
1954 // Move child window if their parent is moved. Keep Child window relative to Parent...
1955 WinPosInternalMoveWindow(Window,
1956 NewClientRect.left - OldClientRect.left,
1957 NewClientRect.top - OldClientRect.top);
1958 PosChanged = TRUE;
1959 }
1960
1961 Window->rcWindow = NewWindowRect;
1962 Window->rcClient = NewClientRect;
1963
1964 /* erase parent when hiding or resizing child */
1965 if (WinPos.flags & SWP_HIDEWINDOW)
1966 {
1967 /* Clear the update region */
1968 co_UserRedrawWindow( Window,
1969 NULL,
1970 0,
1971 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
1972
1973 if (Window->spwndParent == UserGetDesktopWindow())
1974 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM)Window->head.h, 0);
1975
1976 Window->style &= ~WS_VISIBLE; //IntSetStyle( Window, 0, WS_VISIBLE );
1977 Window->head.pti->cVisWindows--;
1978 IntNotifyWinEvent(EVENT_OBJECT_HIDE, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1979 }
1980 else if (WinPos.flags & SWP_SHOWWINDOW)
1981 {
1982 if (Window->spwndParent == UserGetDesktopWindow() &&
1983 Window->spwndOwner == NULL &&
1984 (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
1985 (Window->ExStyle & WS_EX_APPWINDOW)))
1986 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)Window->head.h, 0);
1987
1988 Window->style |= WS_VISIBLE; //IntSetStyle( Window, WS_VISIBLE, 0 );
1989 Window->head.pti->cVisWindows++;
1990 IntNotifyWinEvent(EVENT_OBJECT_SHOW, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1991 }
1992
1993 if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != HRGN_WINDOW)
1994 {
1995 NtGdiOffsetRgn(Window->hrgnUpdate,
1996 NewWindowRect.left - OldWindowRect.left,
1997 NewWindowRect.top - OldWindowRect.top);
1998 }
1999
2000 DceResetActiveDCEs(Window); // For WS_VISIBLE changes.
2001
2002 if (!(WinPos.flags & SWP_NOREDRAW))
2003 {
2004 /* Determine the new visible region */
2005 VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
2006 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
2007
2008 if ( VisAfter != NULL &&
2009 REGION_Complexity(VisAfter) == NULLREGION )
2010 {
2011 REGION_Delete(VisAfter);
2012 VisAfter = NULL;
2013 }
2014 else if(VisAfter)
2015 {
2016 REGION_bOffsetRgn(VisAfter, -Window->rcWindow.left, -Window->rcWindow.top);
2017 }
2018
2019 /*
2020 * Determine which pixels can be copied from the old window position
2021 * to the new. Those pixels must be visible in both the old and new
2022 * position. Also, check the class style to see if the windows of this
2023 * class need to be completely repainted on (horizontal/vertical) size
2024 * change.
2025 */
2026 if ( ( VisBefore != NULL &&
2027 VisAfter != NULL &&
2028 !(WinPos.flags & SWP_NOCOPYBITS) &&
2029 ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) &&
2030 !(Window->ExStyle & WS_EX_TRANSPARENT) ) ||
2031 ( !PosChanged && (WinPos.flags & SWP_FRAMECHANGED) && VisBefore) )
2032 {
2033
2034 /*
2035 * If this is (also) a window resize, the whole nonclient area
2036 * needs to be repainted. So we limit the copy to the client area,
2037 * 'cause there is no use in copying it (would possibly cause
2038 * "flashing" too). However, if the copy region is already empty,
2039 * we don't have to crop (can't take anything away from an empty
2040 * region...)
2041 */
2042
2043 CopyRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
2044 if (WinPos.flags & SWP_NOSIZE)
2045 RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
2046 else if (VisBeforeJustClient != NULL)
2047 {
2048 RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBeforeJustClient, RGN_AND);
2049 REGION_Delete(VisBeforeJustClient);
2050 }
2051
2052 /* No use in copying bits which are in the update region. */
2053 if (Window->hrgnUpdate != NULL)
2054 {
2055 PREGION RgnUpdate = REGION_LockRgn(Window->hrgnUpdate);
2056 if (RgnUpdate)
2057 {
2058 REGION_bOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
2059 IntGdiCombineRgn(CopyRgn, CopyRgn, RgnUpdate, RGN_DIFF);
2060 REGION_bOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
2061 REGION_UnlockRgn(RgnUpdate);
2062 }
2063 }
2064
2065 /*
2066 * Now, get the bounding box of the copy region. If it's empty
2067 * there's nothing to copy. Also, it's no use copying bits onto
2068 * themselves.
2069 */
2070 if (REGION_GetRgnBox(CopyRgn, &CopyRect) == NULLREGION)
2071 {
2072 /* Nothing to copy, clean up */
2073 REGION_Delete(CopyRgn);
2074 CopyRgn = NULL;
2075 }
2076 else if ( OldWindowRect.left != NewWindowRect.left ||
2077 OldWindowRect.top != NewWindowRect.top ||
2078 (WinPos.flags & SWP_FRAMECHANGED) )
2079 {
2080 HRGN DcRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
2081 PREGION DcRgnObj = REGION_LockRgn(DcRgn);
2082
2083 /*
2084 * Small trick here: there is no function to bitblt a region. So
2085 * we set the region as the clipping region, take the bounding box
2086 * of the region and bitblt that. Since nothing outside the clipping
2087 * region is copied, this has the effect of bitblt'ing the region.
2088 *
2089 * Since NtUserGetDCEx takes ownership of the clip region, we need
2090 * to create a copy of CopyRgn and pass that. We need CopyRgn later
2091 */
2092 IntGdiCombineRgn(DcRgnObj, CopyRgn, NULL, RGN_COPY);
2093 REGION_bOffsetRgn(DcRgnObj, NewWindowRect.left, NewWindowRect.top);
2094 REGION_UnlockRgn(DcRgnObj);
2095 Dc = UserGetDCEx( Window,
2096 DcRgn,
2097 DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN);
2098 NtGdiBitBlt( Dc,
2099 CopyRect.left, CopyRect.top,
2100 CopyRect.right - CopyRect.left,
2101 CopyRect.bottom - CopyRect.top,
2102 Dc,
2103 CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
2104 CopyRect.top + (OldWindowRect.top - NewWindowRect.top),
2105 SRCCOPY,
2106 0,
2107 0);
2108
2109 UserReleaseDC(Window, Dc, FALSE);
2110 IntValidateParent(Window, CopyRgn);
2111 GreDeleteObject(DcRgn);
2112 }
2113 }
2114 else
2115 {
2116 CopyRgn = NULL;
2117 }
2118 #if 0
2119 /////// Fixes NoPopup tests but breaks msg_paint tests.
2120 if ( !PosChanged && (WinPos.flags & SWP_FRAMECHANGED) && VisBefore)
2121 {
2122 PWND Parent = Window->spwndParent;
2123 ERR("SWP_FRAMECHANGED no chg\n");
2124 if ( !(Window->style & WS_CHILD) && (Parent) && (Parent->style & WS_CLIPCHILDREN))
2125 {
2126 ERR("SWP_FRAMECHANGED Parent WS_CLIPCHILDREN\n");
2127 //IntInvalidateWindows( Window, VisBefore, /*RDW_ERASE |*/ RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2128 }
2129 }
2130 #endif
2131 /* We need to redraw what wasn't visible before */
2132 if (VisAfter != NULL)
2133 {
2134 PREGION DirtyRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
2135 if (DirtyRgn)
2136 {
2137 if (CopyRgn != NULL)
2138 {
2139 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
2140 }
2141 else
2142 {
2143 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
2144 }
2145
2146 if (RgnType != ERROR && RgnType != NULLREGION)
2147 {
2148 /* old code
2149 NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2150 IntInvalidateWindows( Window,
2151 DirtyRgn,
2152 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2153 }
2154 GreDeleteObject(DirtyRgn);
2155 */
2156
2157 PWND Parent = Window->spwndParent;
2158
2159 REGION_bOffsetRgn( DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2160
2161 if ( (Window->style & WS_CHILD) && (Parent) && !(Parent->style & WS_CLIPCHILDREN))
2162 {
2163 IntInvalidateWindows( Parent, DirtyRgn, RDW_ERASE | RDW_INVALIDATE);
2164 co_IntPaintWindows(Parent, RDW_NOCHILDREN, FALSE);
2165 }
2166 else
2167 {
2168 IntInvalidateWindows( Window, DirtyRgn, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2169 }
2170 }
2171 REGION_Delete(DirtyRgn);
2172 }
2173 }
2174
2175 if (CopyRgn != NULL)
2176 {
2177 REGION_Delete(CopyRgn);
2178 }
2179
2180 /* Expose what was covered before but not covered anymore */
2181 if (VisBefore != NULL)
2182 {
2183 PREGION ExposedRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
2184 if (ExposedRgn)
2185 {
2186 RgnType = IntGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
2187 REGION_bOffsetRgn(ExposedRgn,
2188 OldWindowRect.left - NewWindowRect.left,
2189 OldWindowRect.top - NewWindowRect.top);
2190
2191 if (VisAfter != NULL)
2192 RgnType = IntGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
2193
2194 if (RgnType != ERROR && RgnType != NULLREGION)
2195 {
2196 co_VIS_WindowLayoutChanged(Window, ExposedRgn);
2197 }
2198 REGION_Delete(ExposedRgn);
2199 }
2200 REGION_Delete(VisBefore);
2201 }
2202
2203 if (VisAfter != NULL)
2204 {
2205 REGION_Delete(VisAfter);
2206 }
2207 }
2208
2209 if (!(WinPos.flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
2210 {
2211 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2212 {
2213 co_IntSendMessageNoWait(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
2214 }
2215 else
2216 {
2217 //ERR("SetWindowPos Set FG Window!\n");
2218 if (Window->state & WNDS_BEINGACTIVATED) // Inside SAW?
2219 co_IntSetActiveWindow(Window, FALSE, TRUE, FALSE); // Fixes Api AttachThreadInput tests.
2220 else
2221 co_IntSetForegroundWindow(Window); // Fixes SW_HIDE issues. Wine win test_SetActiveWindow & test_SetForegroundWindow.
2222 }
2223 }
2224
2225 if ( !PosChanged &&
2226 (WinPos.flags & SWP_FRAMECHANGED) &&
2227 !(WinPos.flags & SWP_DEFERERASE) && // Prevent sending WM_SYNCPAINT message.
2228 VisAfter )
2229 {
2230 PWND Parent = Window->spwndParent;
2231 if ( !(Window->style & WS_CHILD) && (Parent) && (Parent->style & WS_CLIPCHILDREN))
2232 {
2233 TRACE("SWP_FRAMECHANGED Parent WS_CLIPCHILDREN\n");
2234 UserSyncAndPaintWindows( Parent, RDW_CLIPCHILDREN);
2235 }
2236 }
2237
2238 // Fix wine msg test_SetFocus, prevents sending WM_WINDOWPOSCHANGED.
2239 if ( VisBefore == NULL &&
2240 VisBeforeJustClient == NULL &&
2241 !(Window->ExStyle & WS_EX_TOPMOST) &&
2242 (WinPos.flags & SWP_AGG_STATUSFLAGS) == (SWP_AGG_NOPOSCHANGE & ~SWP_NOZORDER))
2243 {
2244 TRACE("No drawing, set no Z order and no redraw!\n");
2245 WinPos.flags |= SWP_NOZORDER|SWP_NOREDRAW;
2246 }
2247
2248 /* And last, send the WM_WINDOWPOSCHANGED message */
2249
2250 TRACE("\tstatus hwnd %p flags = %04x\n",Window?Window->head.h:NULL,WinPos.flags & SWP_AGG_STATUSFLAGS);
2251
2252 if ((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2253 {
2254 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
2255 and always contains final window position.
2256 */
2257 WinPos.x = NewWindowRect.left;
2258 WinPos.y = NewWindowRect.top;
2259 WinPos.cx = NewWindowRect.right - NewWindowRect.left;
2260 WinPos.cy = NewWindowRect.bottom - NewWindowRect.top;
2261 TRACE("WM_WINDOWPOSCHANGED hwnd %p Flags %04x\n",WinPos.hwnd,WinPos.flags);
2262 co_IntSendMessageNoWait(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
2263 }
2264
2265 if ( WinPos.flags & SWP_FRAMECHANGED || WinPos.flags & SWP_STATECHANGED ||
2266 !(WinPos.flags & SWP_NOCLIENTSIZE) || !(WinPos.flags & SWP_NOCLIENTMOVE) )
2267 {
2268 PWND pWnd = ValidateHwndNoErr(WinPos.hwnd);
2269 if (pWnd)
2270 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2271 }
2272
2273 if(bPointerInWindow != IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y))
2274 {
2275 /* Generate mouse move message */
2276 MSG msg;
2277 msg.message = WM_MOUSEMOVE;
2278 msg.wParam = UserGetMouseButtonsState();
2279 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2280 msg.pt = gpsi->ptCursor;
2281 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2282 }
2283
2284 return TRUE;
2285 }
2286
2287 LRESULT FASTCALL
2288 co_WinPosGetNonClientSize(PWND Window, RECT* WindowRect, RECT* ClientRect)
2289 {
2290 LRESULT Result;
2291
2292 ASSERT_REFS_CO(Window);
2293
2294 *ClientRect = *WindowRect;
2295 Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect);
2296
2297 FixClientRect(ClientRect, WindowRect);
2298
2299 return Result;
2300 }
2301
2302 void FASTCALL
2303 co_WinPosSendSizeMove(PWND Wnd)
2304 {
2305 RECTL Rect;
2306 LPARAM lParam;
2307 WPARAM wParam = SIZE_RESTORED;
2308
2309 IntGetClientRect(Wnd, &Rect);
2310 lParam = MAKELONG(Rect.right-Rect.left, Rect.bottom-Rect.top);
2311
2312 Wnd->state &= ~WNDS_SENDSIZEMOVEMSGS;
2313
2314 if (Wnd->style & WS_MAXIMIZE)
2315 {
2316 wParam = SIZE_MAXIMIZED;
2317 }
2318 else if (Wnd->style & WS_MINIMIZE)
2319 {
2320 wParam = SIZE_MINIMIZED;
2321 lParam = 0;
2322 }
2323
2324 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SIZE, wParam, lParam);
2325
2326 if (Wnd->spwndParent == UserGetDesktopWindow()) // Wnd->spwndParent->fnid == FNID_DESKTOP )
2327 lParam = MAKELONG(Wnd->rcClient.left, Wnd->rcClient.top);
2328 else
2329 lParam = MAKELONG(Wnd->rcClient.left-Wnd->spwndParent->rcClient.left, Wnd->rcClient.top-Wnd->spwndParent->rcClient.top);
2330
2331 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_MOVE, 0, lParam);
2332
2333 IntEngWindowChanged(Wnd, WOC_RGN_CLIENT);
2334 }
2335
2336 /*
2337 ShowWindow does not set SWP_FRAMECHANGED!!! Fix wine msg test_SetParent:WmSetParentSeq_2:23 wParam bits!
2338 */
2339 BOOLEAN FASTCALL
2340 co_WinPosShowWindow(PWND Wnd, INT Cmd)
2341 {
2342 BOOLEAN WasVisible;
2343 UINT Swp = 0, EventMsg = 0;
2344 RECTL NewPos = {0, 0, 0, 0};
2345 BOOLEAN ShowFlag;
2346 LONG style;
2347 PWND Parent;
2348 PTHREADINFO pti;
2349 //HRGN VisibleRgn;
2350 BOOL ShowOwned = FALSE;
2351 BOOL FirstTime = FALSE;
2352 ASSERT_REFS_CO(Wnd);
2353 //KeRosDumpStackFrames(NULL, 20);
2354 pti = PsGetCurrentThreadWin32Thread();
2355 WasVisible = (Wnd->style & WS_VISIBLE) != 0;
2356 style = Wnd->style;
2357
2358 TRACE("co_WinPosShowWindow START hwnd %p Cmd %d usicmd %u\n",
2359 Wnd->head.h, Cmd, pti->ppi->usi.wShowWindow);
2360
2361 if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW )
2362 {
2363 if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2364 {
2365 if ((Wnd->style & WS_CAPTION) == WS_CAPTION)
2366 {
2367 if (Wnd->spwndOwner == NULL)
2368 {
2369 if ( Cmd == SW_SHOWNORMAL || Cmd == SW_SHOW)
2370 {
2371 Cmd = SW_SHOWDEFAULT;
2372 }
2373 FirstTime = TRUE;
2374 TRACE("co_WPSW FT 1\n");
2375 }
2376 }
2377 }
2378 }
2379
2380 if ( Cmd == SW_SHOWDEFAULT )
2381 {
2382 if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW )
2383 {
2384 Cmd = pti->ppi->usi.wShowWindow;
2385 FirstTime = TRUE;
2386 TRACE("co_WPSW FT 2\n");
2387 }
2388 }
2389
2390 if (FirstTime)
2391 {
2392 pti->ppi->usi.dwFlags &= ~(STARTF_USEPOSITION|STARTF_USESIZE|STARTF_USESHOWWINDOW);
2393 }
2394
2395 switch (Cmd)
2396 {
2397 case SW_HIDE:
2398 {
2399 if (!WasVisible)
2400 {
2401 //ERR("co_WinPosShowWindow Exit Bad\n");
2402 return FALSE;
2403 }
2404 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2405 if (Wnd != pti->MessageQueue->spwndActive)
2406 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2407 break;
2408 }
2409
2410 case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
2411 case SW_SHOWMINNOACTIVE:
2412 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2413 /* Fall through. */
2414 case SW_SHOWMINIMIZED:
2415 Swp |= SWP_SHOWWINDOW;
2416 /* Fall through. */
2417 case SW_MINIMIZE:
2418 {
2419 Swp |= SWP_NOACTIVATE;
2420 if (!(style & WS_MINIMIZE))
2421 {
2422 IntShowOwnedPopups(Wnd, FALSE );
2423 // Fix wine Win test_SetFocus todo #1 & #2,
2424 if (Cmd == SW_SHOWMINIMIZED)
2425 {
2426 //ERR("co_WinPosShowWindow Set focus 1\n");
2427 if ((style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2428 co_UserSetFocus(Wnd->spwndParent);
2429 else
2430 co_UserSetFocus(0);
2431 }
2432
2433 Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos);
2434
2435 EventMsg = EVENT_SYSTEM_MINIMIZESTART;
2436 }
2437 else
2438 {
2439 if (WasVisible)
2440 {
2441 //ERR("co_WinPosShowWindow Exit Good\n");
2442 return TRUE;
2443 }
2444 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2445 }
2446 break;
2447 }
2448
2449 case SW_SHOWMAXIMIZED:
2450 {
2451 Swp |= SWP_SHOWWINDOW;
2452 if (!(style & WS_MAXIMIZE))
2453 {
2454 ShowOwned = TRUE;
2455
2456 Swp |= co_WinPosMinMaximize(Wnd, SW_MAXIMIZE, &NewPos);
2457
2458 EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2459 }
2460 else
2461 {
2462 if (WasVisible)
2463 {
2464 //ERR("co_WinPosShowWindow Exit Good 1\n");
2465 return TRUE;
2466 }
2467 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2468 }
2469 break;
2470 }
2471
2472 case SW_SHOWNA:
2473 Swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2474 if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOZORDER;
2475 break;
2476 case SW_SHOW:
2477 if (WasVisible) return(TRUE); // Nothing to do!
2478 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2479 /* Don't activate the topmost window. */
2480 if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2481 break;
2482
2483 case SW_SHOWNOACTIVATE:
2484 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2485 /* Fall through. */
2486 case SW_SHOWNORMAL:
2487 case SW_SHOWDEFAULT:
2488 case SW_RESTORE:
2489 if (!WasVisible) Swp |= SWP_SHOWWINDOW;
2490 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2491 {
2492 Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos);
2493 if (style & WS_MINIMIZE) EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2494 }
2495 else
2496 {
2497 if (WasVisible)
2498 {
2499 //ERR("co_WinPosShowWindow Exit Good 3\n");
2500 return TRUE;
2501 }
2502 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2503 }
2504 if ( style & WS_CHILD &&
2505 !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2506 !(Swp & SWP_STATECHANGED))
2507 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2508 break;
2509
2510 default:
2511 //ERR("co_WinPosShowWindow Exit Good 4\n");
2512 return WasVisible;
2513 }
2514
2515 ShowFlag = (Cmd != SW_HIDE);
2516
2517 if ((ShowFlag != WasVisible || Cmd == SW_SHOWNA) && Cmd != SW_SHOWMAXIMIZED && !(Swp & SWP_STATECHANGED))
2518 {
2519 co_IntSendMessageNoWait(Wnd->head.h, WM_SHOWWINDOW, ShowFlag, 0);
2520 #if 0 // Fix wine msg test_SetParent:WmSetParentSeq_1:2
2521 if (!(Wnd->state2 & WNDS2_WIN31COMPAT)) // <------------- XP sets this bit!
2522 co_IntSendMessageNoWait(Wnd->head.h, WM_SETVISIBLE, ShowFlag, 0);
2523 #endif
2524 if (!VerifyWnd(Wnd)) return WasVisible;
2525 }
2526
2527 /* We can't activate a child window */
2528 if ((Wnd->style & WS_CHILD) &&
2529 !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2530 Cmd != SW_SHOWNA)
2531 {
2532 //ERR("SWP Child No active and ZOrder\n");
2533 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2534 }
2535
2536 #if 0 // Explorer issues with common controls? Someone does not know how CS_SAVEBITS works.
2537 // Breaks startup and shutdown active window...
2538 if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
2539 Wnd->pcls->style & CS_SAVEBITS &&
2540 ((Cmd == SW_SHOW) || (Cmd == SW_NORMAL)))
2541 {
2542 ERR("WinPosShowWindow Set active\n");
2543 //UserSetActiveWindow(Wnd);
2544 co_IntSetForegroundWindow(Wnd); // HACK
2545 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2546 }
2547 #endif
2548
2549 if (IsChildVisible(Wnd) || Swp & SWP_STATECHANGED)
2550 {
2551 TRACE("Child is Vis %s or State changed %s. ShowFlag %s Swp %04x\n",
2552 (IsChildVisible(Wnd) ? "TRUE" : "FALSE"), (Swp & SWP_STATECHANGED ? "TRUE" : "FALSE"),
2553 (ShowFlag ? "TRUE" : "FALSE"),LOWORD(Swp));
2554 co_WinPosSetWindowPos( Wnd,
2555 0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP,
2556 NewPos.left,
2557 NewPos.top,
2558 NewPos.right, // NewPos.right - NewPos.left, when minimized and restore, the window becomes smaller.
2559 NewPos.bottom,// NewPos.bottom - NewPos.top,
2560 LOWORD(Swp));
2561 }
2562 else
2563 {
2564 TRACE("Parent Vis?\n");
2565 /* if parent is not visible simply toggle WS_VISIBLE and return */
2566 if (ShowFlag) IntSetStyle( Wnd, WS_VISIBLE, 0 );
2567 else IntSetStyle( Wnd, 0, WS_VISIBLE );
2568 }
2569
2570 if ( EventMsg ) IntNotifyWinEvent(EventMsg, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2571
2572 if ( ShowOwned ) IntShowOwnedPopups(Wnd, TRUE );
2573
2574 if ((Cmd == SW_HIDE) || (Cmd == SW_MINIMIZE))
2575 {
2576 if ( Wnd == pti->MessageQueue->spwndActive && pti->MessageQueue == IntGetFocusMessageQueue() )
2577 {
2578 if ( Wnd->spwndParent == UserGetDesktopWindow())
2579 {
2580 if (!ActivateOtherWindowMin(Wnd))
2581 {
2582 co_WinPosActivateOtherWindow(Wnd);
2583 }
2584 }
2585 else
2586 {
2587 co_WinPosActivateOtherWindow(Wnd);
2588 }
2589 }
2590
2591 /* Revert focus to parent */
2592 if (Wnd == pti->MessageQueue->spwndFocus)
2593 {
2594 Parent = Wnd->spwndParent;
2595 if (Wnd->spwndParent == UserGetDesktopWindow()) Parent = 0;
2596 co_UserSetFocus(Parent);
2597 }
2598 // Hide, just return.
2599 if (Cmd == SW_HIDE) return WasVisible;
2600 }
2601
2602 /* FIXME: Check for window destruction. */
2603
2604 if ((Wnd->state & WNDS_SENDSIZEMOVEMSGS) &&
2605 !(Wnd->state2 & WNDS2_INDESTROY))
2606 {
2607 co_WinPosSendSizeMove(Wnd);
2608 }
2609
2610 /* if previous state was minimized Windows sets focus to the window */
2611 if (style & WS_MINIMIZE)
2612 {
2613 co_UserSetFocus(Wnd);
2614 // Fix wine Win test_SetFocus todo #3,
2615 if (!(style & WS_CHILD)) co_IntSendMessage(UserHMGetHandle(Wnd), WM_ACTIVATE, WA_ACTIVE, 0);
2616 }
2617 //ERR("co_WinPosShowWindow EXIT\n");
2618 return WasVisible;
2619 }
2620
2621 static PWND
2622 co_WinPosSearchChildren(
2623 IN PWND ScopeWin,
2624 IN POINT *Point,
2625 IN OUT USHORT *HitTest,
2626 IN BOOL Ignore
2627 )
2628 {
2629 HWND *List, *phWnd;
2630 PWND pwndChild = NULL;
2631
2632 /* not visible */
2633 if (!(ScopeWin->style & WS_VISIBLE))
2634 {
2635 return NULL;
2636 }
2637
2638 /* not in window or in window region */
2639 if (!IntPtInWindow(ScopeWin, Point->x, Point->y))
2640 {
2641 return NULL;
2642 }
2643
2644 /* transparent */
2645 if ((ScopeWin->ExStyle & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT))
2646 {
2647 return NULL;
2648 }
2649
2650 if (!Ignore && (ScopeWin->style & WS_DISABLED))
2651 { /* disabled child */
2652 if ((ScopeWin->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return NULL;
2653 /* process the hit error */
2654 *HitTest = HTERROR;
2655 return ScopeWin;
2656 }
2657
2658 /* not minimized and check if point is inside the window */
2659 if (!(ScopeWin->style & WS_MINIMIZE) &&
2660 RECTL_bPointInRect(&ScopeWin->rcClient, Point->x, Point->y) )
2661 {
2662 UserReferenceObject(ScopeWin);
2663
2664 List = IntWinListChildren(ScopeWin);
2665 if (List)
2666 {
2667 for (phWnd = List; *phWnd; ++phWnd)
2668 {
2669 if (!(pwndChild = ValidateHwndNoErr(*phWnd)))
2670 {
2671 continue;
2672 }
2673
2674 pwndChild = co_WinPosSearchChildren(pwndChild, Point, HitTest, Ignore);
2675
2676 if (pwndChild != NULL)
2677 {
2678 /* We found a window. Don't send any more WM_NCHITTEST messages */
2679 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2680 UserDereferenceObject(ScopeWin);
2681 return pwndChild;
2682 }
2683 }
2684 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2685 }
2686 UserDereferenceObject(ScopeWin);
2687 }
2688
2689 if (ScopeWin->head.pti == PsGetCurrentThreadWin32Thread())
2690 {
2691 *HitTest = (USHORT)co_IntSendMessage(ScopeWin->head.h, WM_NCHITTEST, 0, MAKELONG(Point->x, Point->y));
2692
2693 if ((*HitTest) == (USHORT)HTTRANSPARENT)
2694 {
2695 return NULL;
2696 }
2697 }
2698 else
2699 {
2700 if (*HitTest == HTNOWHERE && pwndChild == NULL) *HitTest = HTCLIENT;
2701 }
2702
2703 return ScopeWin;
2704 }
2705
2706 PWND APIENTRY
2707 co_WinPosWindowFromPoint(
2708 IN PWND ScopeWin,
2709 IN POINT *WinPoint,
2710 IN OUT USHORT* HitTest,
2711 IN BOOL Ignore)
2712 {
2713 PWND Window;
2714 POINT Point = *WinPoint;
2715 USER_REFERENCE_ENTRY Ref;
2716
2717 if( ScopeWin == NULL )
2718 {
2719 ScopeWin = UserGetDesktopWindow();
2720 if(ScopeWin == NULL)
2721 return NULL;
2722 }
2723
2724 *HitTest = HTNOWHERE;
2725
2726 ASSERT_REFS_CO(ScopeWin);
2727 UserRefObjectCo(ScopeWin, &Ref);
2728
2729 Window = co_WinPosSearchChildren(ScopeWin, &Point, HitTest, Ignore);
2730
2731 UserDerefObjectCo(ScopeWin);
2732 if (Window)
2733 ASSERT_REFS_CO(Window);
2734 ASSERT_REFS_CO(ScopeWin);
2735
2736 return Window;
2737 }
2738
2739 PWND FASTCALL
2740 IntRealChildWindowFromPoint(PWND Parent, LONG x, LONG y)
2741 {
2742 POINTL Pt;
2743 HWND *List, *phWnd;
2744 PWND pwndHit = NULL;
2745
2746 Pt.x = x;
2747 Pt.y = y;
2748
2749 if (Parent != UserGetDesktopWindow())
2750 {
2751 Pt.x += Parent->rcClient.left;
2752 Pt.y += Parent->rcClient.top;
2753 }
2754
2755 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2756
2757 if ((List = IntWinListChildren(Parent)))
2758 {
2759 for (phWnd = List; *phWnd; phWnd++)
2760 {
2761 PWND Child;
2762 if ((Child = ValidateHwndNoErr(*phWnd)))
2763 {
2764 if ( Child->style & WS_VISIBLE && IntPtInWindow(Child, Pt.x, Pt.y) )
2765 {
2766 if ( Child->pcls->atomClassName != gpsi->atomSysClass[ICLS_BUTTON] ||
2767 (Child->style & BS_TYPEMASK) != BS_GROUPBOX )
2768 {
2769 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2770 return Child;
2771 }
2772 pwndHit = Child;
2773 }
2774 }
2775 }
2776 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2777 }
2778 return pwndHit ? pwndHit : Parent;
2779 }
2780
2781 PWND APIENTRY
2782 IntChildWindowFromPointEx(PWND Parent, LONG x, LONG y, UINT uiFlags)
2783 {
2784 POINTL Pt;
2785 HWND *List, *phWnd;
2786 PWND pwndHit = NULL;
2787
2788 Pt.x = x;
2789 Pt.y = y;
2790
2791 if (Parent != UserGetDesktopWindow())
2792 {
2793 if (Parent->ExStyle & WS_EX_LAYOUTRTL)
2794 Pt.x = Parent->rcClient.right - Pt.x;
2795 else
2796 Pt.x += Parent->rcClient.left;
2797 Pt.y += Parent->rcClient.top;
2798 }
2799
2800 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2801
2802 if ((List = IntWinListChildren(Parent)))
2803 {
2804 for (phWnd = List; *phWnd; phWnd++)
2805 {
2806 PWND Child;
2807 if ((Child = ValidateHwndNoErr(*phWnd)))
2808 {
2809 if (uiFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
2810 {
2811 if (!(Child->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE)) continue;
2812 if ((Child->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED)) continue;
2813 }
2814
2815 if (uiFlags & CWP_SKIPTRANSPARENT)
2816 {
2817 if (Child->ExStyle & WS_EX_TRANSPARENT) continue;
2818 }
2819
2820 if (IntPtInWindow(Child, Pt.x, Pt.y))
2821 {
2822 pwndHit = Child;
2823 break;
2824 }
2825 }
2826 }
2827 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2828 }
2829 return pwndHit ? pwndHit : Parent;
2830 }
2831
2832 HDWP
2833 FASTCALL
2834 IntDeferWindowPos( HDWP hdwp,
2835 HWND hwnd,
2836 HWND hwndAfter,
2837 INT x,
2838 INT y,
2839 INT cx,
2840 INT cy,
2841 UINT flags )
2842 {
2843 PSMWP pDWP;
2844 int i;
2845 HDWP retvalue = hdwp;
2846
2847 TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2848 hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
2849
2850 if (flags & ~(SWP_NOSIZE | SWP_NOMOVE |
2851 SWP_NOZORDER | SWP_NOREDRAW |
2852 SWP_NOACTIVATE | SWP_NOCOPYBITS |
2853 SWP_NOOWNERZORDER|SWP_SHOWWINDOW |
2854 SWP_HIDEWINDOW | SWP_FRAMECHANGED))
2855 {
2856 EngSetLastError(ERROR_INVALID_PARAMETER);
2857 return NULL;
2858 }
2859
2860 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
2861 {
2862 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
2863 return NULL;
2864 }
2865
2866 for (i = 0; i < pDWP->ccvr; i++)
2867 {
2868 if (pDWP->acvr[i].pos.hwnd == hwnd)
2869 {
2870 /* Merge with the other changes */
2871 if (!(flags & SWP_NOZORDER))
2872 {
2873 pDWP->acvr[i].pos.hwndInsertAfter = hwndAfter;
2874 }
2875 if (!(flags & SWP_NOMOVE))
2876 {
2877 pDWP->acvr[i].pos.x = x;
2878 pDWP->acvr[i].pos.y = y;
2879 }
2880 if (!(flags & SWP_NOSIZE))
2881 {
2882 pDWP->acvr[i].pos.cx = cx;
2883 pDWP->acvr[i].pos.cy = cy;
2884 }
2885 pDWP->acvr[i].pos.flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
2886 SWP_NOZORDER | SWP_NOREDRAW |
2887 SWP_NOACTIVATE | SWP_NOCOPYBITS|
2888 SWP_NOOWNERZORDER);
2889 pDWP->acvr[i].pos.flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
2890 SWP_FRAMECHANGED);
2891 goto END;
2892 }
2893 }
2894 if (pDWP->ccvr >= pDWP->ccvrAlloc)
2895 {
2896 PCVR newpos = ExAllocatePoolWithTag(PagedPool, pDWP->ccvrAlloc * 2 * sizeof(CVR), USERTAG_SWP);
2897 if (!newpos)
2898 {
2899 retvalue = NULL;
2900 goto END;
2901 }
2902 RtlZeroMemory(newpos, pDWP->ccvrAlloc * 2 * sizeof(CVR));
2903 RtlCopyMemory(newpos, pDWP->acvr, pDWP->ccvrAlloc * sizeof(CVR));
2904 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
2905 pDWP->ccvrAlloc *= 2;
2906 pDWP->acvr = newpos;
2907 }
2908 pDWP->acvr[pDWP->ccvr].pos.hwnd = hwnd;
2909 pDWP->acvr[pDWP->ccvr].pos.hwndInsertAfter = hwndAfter;
2910 pDWP->acvr[pDWP->ccvr].pos.x = x;
2911 pDWP->acvr[pDWP->ccvr].pos.y = y;
2912 pDWP->acvr[pDWP->ccvr].pos.cx = cx;
2913 pDWP->acvr[pDWP->ccvr].pos.cy = cy;
2914 pDWP->acvr[pDWP->ccvr].pos.flags = flags;
2915 pDWP->acvr[pDWP->ccvr].hrgnClip = NULL;
2916 pDWP->acvr[pDWP->ccvr].hrgnInterMonitor = NULL;
2917 pDWP->ccvr++;
2918 END:
2919 return retvalue;
2920 }
2921
2922 BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp, BOOL sAsync )
2923 {
2924 PSMWP pDWP;
2925 PCVR winpos;
2926 BOOL res = TRUE;
2927 int i;
2928
2929 TRACE("%p\n", hdwp);
2930
2931 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
2932 {
2933 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
2934 return FALSE;
2935 }
2936
2937 for (i = 0, winpos = pDWP->acvr; res && i < pDWP->ccvr; i++, winpos++)
2938 {
2939 PWND pwnd;
2940 USER_REFERENCE_ENTRY Ref;
2941
2942 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2943 winpos->pos.hwnd, winpos->pos.hwndInsertAfter, winpos->pos.x, winpos->pos.y,
2944 winpos->pos.cx, winpos->pos.cy, winpos->pos.flags);
2945
2946 pwnd = ValidateHwndNoErr(winpos->pos.hwnd);
2947 if (!pwnd)
2948 continue;
2949
2950 UserRefObjectCo(pwnd, &Ref);
2951
2952 if ( sAsync )
2953 {
2954 LRESULT lRes;
2955 PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
2956 if ( ppos )
2957 {
2958 *ppos = winpos->pos;
2959 /* Yes it's a pointer inside Win32k! */
2960 lRes = co_IntSendMessageNoWait( winpos->pos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
2961 /* We handle this the same way as Event Hooks and Hooks. */
2962 if ( !lRes )
2963 {
2964 ExFreePoolWithTag(ppos, USERTAG_SWP);
2965 }
2966 }
2967 }
2968 else
2969 res = co_WinPosSetWindowPos( pwnd,
2970 winpos->pos.hwndInsertAfter,
2971 winpos->pos.x,
2972 winpos->pos.y,
2973 winpos->pos.cx,
2974 winpos->pos.cy,
2975 winpos->pos.flags);
2976
2977 // Hack to pass tests.... Must have some work to do so clear the error.
2978 if (res && (winpos->pos.flags & (SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER)) == SWP_NOZORDER )
2979 EngSetLastError(ERROR_SUCCESS);
2980
2981 UserDerefObjectCo(pwnd);
2982 }
2983 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
2984 UserDereferenceObject(pDWP);
2985 UserDeleteObject(hdwp, TYPE_SETWINDOWPOS);
2986 return res;
2987 }
2988
2989 /*
2990 * @implemented
2991 */
2992 HWND APIENTRY
2993 NtUserChildWindowFromPointEx(HWND hwndParent,
2994 LONG x,
2995 LONG y,
2996 UINT uiFlags)
2997 {
2998 PWND pwndParent;
2999 TRACE("Enter NtUserChildWindowFromPointEx\n");
3000 UserEnterExclusive();
3001 if ((pwndParent = UserGetWindowObject(hwndParent)))
3002 {
3003 pwndParent = IntChildWindowFromPointEx(pwndParent, x, y, uiFlags);
3004 }
3005 UserLeave();
3006 TRACE("Leave NtUserChildWindowFromPointEx\n");
3007 return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
3008 }
3009
3010 /*
3011 * @implemented
3012 */
3013 BOOL APIENTRY
3014 NtUserEndDeferWindowPosEx(HDWP WinPosInfo,
3015 DWORD Unknown1)
3016 {
3017 BOOL Ret;
3018 TRACE("Enter NtUserEndDeferWindowPosEx\n");
3019 UserEnterExclusive();
3020 Ret = IntEndDeferWindowPosEx(WinPosInfo, (BOOL)Unknown1);
3021 TRACE("Leave NtUserEndDeferWindowPosEx, ret=%i\n", Ret);
3022 UserLeave();
3023 return Ret;
3024 }
3025
3026 /*
3027 * @implemented
3028 */
3029 HDWP APIENTRY
3030 NtUserDeferWindowPos(HDWP WinPosInfo,
3031 HWND Wnd,
3032 HWND WndInsertAfter,
3033 int x,
3034 int y,
3035 int cx,
3036 int cy,
3037 UINT Flags)
3038 {
3039 PWND pWnd, pWndIA;
3040 HDWP Ret = NULL;
3041 UINT Tmp = ~(SWP_ASYNCWINDOWPOS|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_NOREPOSITION|
3042 SWP_NOCOPYBITS|SWP_HIDEWINDOW|SWP_SHOWWINDOW|SWP_FRAMECHANGED|
3043 SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE);
3044
3045 TRACE("Enter NtUserDeferWindowPos\n");
3046 UserEnterExclusive();
3047
3048 if ( Flags & Tmp )
3049 {
3050 EngSetLastError(ERROR_INVALID_FLAGS);
3051 goto Exit;
3052 }
3053
3054 pWnd = UserGetWindowObject(Wnd);
3055 if ( !pWnd || // FIXME:
3056 pWnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3057 pWnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3058 {
3059 goto Exit;
3060 }
3061
3062 if ( WndInsertAfter &&
3063 WndInsertAfter != HWND_BOTTOM &&
3064 WndInsertAfter != HWND_TOPMOST &&
3065 WndInsertAfter != HWND_NOTOPMOST )
3066 {
3067 pWndIA = UserGetWindowObject(WndInsertAfter);
3068 if ( !pWndIA ||
3069 pWndIA == UserGetDesktopWindow() ||
3070 pWndIA == UserGetMessageWindow() )
3071 {
3072 goto Exit;
3073 }
3074 }
3075
3076 Ret = IntDeferWindowPos(WinPosInfo, Wnd, WndInsertAfter, x, y, cx, cy, Flags);
3077
3078 Exit:
3079 TRACE("Leave NtUserDeferWindowPos, ret=%p\n", Ret);
3080 UserLeave();
3081 return Ret;
3082 }
3083
3084 /*
3085 * @implemented
3086 */
3087 DWORD APIENTRY
3088 NtUserGetInternalWindowPos( HWND hWnd,
3089 LPRECT rectWnd,
3090 LPPOINT ptIcon)
3091 {
3092 PWND Window;
3093 DWORD Ret = 0;
3094 BOOL Hit = FALSE;
3095 WINDOWPLACEMENT wndpl;
3096
3097 UserEnterShared();
3098
3099 if (!(Window = UserGetWindowObject(hWnd)))
3100 {
3101 Hit = FALSE;
3102 goto Exit;
3103 }
3104
3105 _SEH2_TRY
3106 {
3107 if(rectWnd)
3108 {
3109 ProbeForWrite(rectWnd,
3110 sizeof(RECT),
3111 1);
3112 }
3113 if(ptIcon)
3114 {
3115 ProbeForWrite(ptIcon,
3116 sizeof(POINT),
3117 1);
3118 }
3119
3120 }
3121 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3122 {
3123 SetLastNtError(_SEH2_GetExceptionCode());
3124 Hit = TRUE;
3125 }
3126 _SEH2_END;
3127
3128 wndpl.length = sizeof(WINDOWPLACEMENT);
3129
3130 if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
3131 {
3132 _SEH2_TRY
3133 {
3134 if (rectWnd)
3135 {
3136 RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));
3137 }
3138 if (ptIcon)
3139 {
3140 RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT));
3141 }
3142
3143 }
3144 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3145 {
3146 SetLastNtError(_SEH2_GetExceptionCode());
3147 Hit = TRUE;
3148 }