[NtUser] Support SWP_FRAMECHANGED
[reactos.git] / 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 #define SWP_AGG_NOCLIENTCHANGE \
26 (SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
27
28 #define EMPTYPOINT(pt) ((pt).x == -1 && (pt).y == -1)
29 #define PLACE_MIN 0x0001
30 #define PLACE_MAX 0x0002
31 #define PLACE_RECT 0x0004
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 && !((WinPos->flags & SWP_AGG_NOCLIENTCHANGE) && (WinPos->flags & SWP_SHOWWINDOW)))
1268 {
1269 TRACE("Sending WM_WINDOWPOSCHANGING to hwnd %p flags %04x.\n", Window->head.h,WinPos->flags);
1270 co_IntSendMessage(Window->head.h, WM_WINDOWPOSCHANGING, 0, (LPARAM) WinPos);
1271 }
1272
1273 /* Calculate new position and size */
1274
1275 *WindowRect = Window->rcWindow;
1276 *ClientRect = (Window->style & WS_MINIMIZE) ? Window->rcWindow : Window->rcClient;
1277
1278 if (!(WinPos->flags & SWP_NOSIZE))
1279 {
1280 if (Window->style & WS_MINIMIZE)
1281 {
1282 WindowRect->right = WindowRect->left + UserGetSystemMetrics(SM_CXMINIMIZED);
1283 WindowRect->bottom = WindowRect->top + UserGetSystemMetrics(SM_CYMINIMIZED);
1284 }
1285 else
1286 {
1287 WindowRect->right = WindowRect->left + WinPos->cx;
1288 WindowRect->bottom = WindowRect->top + WinPos->cy;
1289 }
1290 }
1291
1292 if (!(WinPos->flags & SWP_NOMOVE))
1293 {
1294 INT X, Y;
1295 PWND Parent;
1296 X = WinPos->x;
1297 Y = WinPos->y;
1298
1299 Parent = Window->spwndParent;
1300
1301 // Parent child position issue is in here. SetParent_W7 test CORE-6651.
1302 if (//((Window->style & WS_CHILD) != 0) && <- Fixes wine msg test_SetParent: "rects do not match", the last test.
1303 Parent &&
1304 Parent != Window->head.rpdesk->pDeskInfo->spwnd)
1305 {
1306 TRACE("Not SWP_NOMOVE 1 Parent client offset X %d Y %d\n",X,Y);
1307 X += Parent->rcClient.left;
1308 Y += Parent->rcClient.top;
1309 TRACE("Not SWP_NOMOVE 2 Parent client offset X %d Y %d\n",X,Y);
1310 }
1311
1312 WindowRect->left = X;
1313 WindowRect->top = Y;
1314 WindowRect->right += X - Window->rcWindow.left;
1315 WindowRect->bottom += Y - Window->rcWindow.top;
1316
1317 RECTL_vOffsetRect(ClientRect, X - Window->rcWindow.left,
1318 Y - Window->rcWindow.top);
1319 }
1320 WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
1321
1322 TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
1323 WinPos->hwnd, WinPos->hwndInsertAfter, WinPos->x, WinPos->y,
1324 WinPos->cx, WinPos->cy, WinPos->flags );
1325 TRACE("WindowRect: %d %d %d %d\n", WindowRect->left,WindowRect->top,WindowRect->right,WindowRect->bottom);
1326 TRACE("ClientRect: %d %d %d %d\n", ClientRect->left,ClientRect->top,ClientRect->right,ClientRect->bottom);
1327
1328 return TRUE;
1329 }
1330
1331 /*
1332 * Fix Z order taking into account owned popups -
1333 * basically we need to maintain them above the window that owns them
1334 *
1335 * FIXME: hide/show owned popups when owner visibility changes.
1336 *
1337 * ReactOS: See bug CORE-6129 and CORE-6554.
1338 *
1339 */
1340 ////
1341 // Pass all the win:test_children/popup_zorder tests except "move hwnd_F and its popups down" which is if'ed out.
1342 // Side effect, breaks more of the DeferWindowPos api tests, but wine breaks more!!!!
1343 static
1344 HWND FASTCALL
1345 WinPosDoOwnedPopups(PWND Window, HWND hWndInsertAfter)
1346 {
1347 HWND *List = NULL;
1348 HWND Owner;
1349 LONG Style;
1350 PWND DesktopWindow, ChildObject;
1351 int i;
1352
1353 TRACE("(%p) hInsertAfter = %p\n", Window, hWndInsertAfter );
1354
1355 Style = Window->style;
1356
1357 if (Style & WS_CHILD)
1358 {
1359 TRACE("Window is child\n");
1360 return hWndInsertAfter;
1361 }
1362
1363 Owner = Window->spwndOwner ? Window->spwndOwner->head.h : NULL;
1364
1365 if (Owner)
1366 {
1367 /* Make sure this popup stays above the owner */
1368
1369 if (hWndInsertAfter != HWND_TOPMOST)
1370 {
1371 DesktopWindow = UserGetDesktopWindow();
1372 List = IntWinListChildren(DesktopWindow);
1373
1374 if (List != NULL)
1375 {
1376 for (i = 0; List[i]; i++)
1377 {
1378 BOOL topmost = FALSE;
1379
1380 ChildObject = ValidateHwndNoErr(List[i]);
1381 if (ChildObject)
1382 {
1383 topmost = (ChildObject->ExStyle & WS_EX_TOPMOST) != 0;
1384 }
1385
1386 if (List[i] == Owner)
1387 {
1388 if (i > 0) hWndInsertAfter = List[i-1];
1389 else hWndInsertAfter = topmost ? HWND_TOPMOST : HWND_TOP;
1390 break;
1391 }
1392
1393 if (hWndInsertAfter == HWND_TOP || hWndInsertAfter == HWND_NOTOPMOST)
1394 {
1395 if (!topmost) break;
1396 }
1397 else if (List[i] == hWndInsertAfter) break;
1398 }
1399 }
1400 else
1401 return hWndInsertAfter;
1402 }
1403 }
1404
1405 if (hWndInsertAfter == HWND_BOTTOM)
1406 {
1407 ERR("Window is HWND_BOTTOM hwnd %p\n",hWndInsertAfter);
1408 if (List) ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1409 goto done;
1410 }
1411
1412 if (!List)
1413 {
1414 DesktopWindow = UserGetDesktopWindow();
1415 List = IntWinListChildren(DesktopWindow);
1416 }
1417
1418 if (List != NULL)
1419 {
1420 i = 0;
1421
1422 if (hWndInsertAfter == HWND_TOP || hWndInsertAfter == HWND_NOTOPMOST)
1423 {
1424 if (hWndInsertAfter == HWND_NOTOPMOST || !(Window->ExStyle & WS_EX_TOPMOST))
1425 {
1426 TRACE("skip all the topmost windows\n");
1427 /* skip all the topmost windows */
1428 while (List[i] &&
1429 (ChildObject = ValidateHwndNoErr(List[i])) &&
1430 (ChildObject->ExStyle & WS_EX_TOPMOST)) i++;
1431 }
1432 }
1433 else if (hWndInsertAfter != HWND_TOPMOST)
1434 {
1435 /* skip windows that are already placed correctly */
1436 for (i = 0; List[i]; i++)
1437 {
1438 if (List[i] == hWndInsertAfter) break;
1439 if (List[i] == UserHMGetHandle(Window))
1440 {
1441 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1442 goto done; /* nothing to do if window is moving backwards in z-order */
1443 }
1444 }
1445 }
1446
1447 for (; List[i]; i++)
1448 {
1449 PWND Wnd;
1450 USER_REFERENCE_ENTRY Ref;
1451
1452 if (List[i] == UserHMGetHandle(Window))
1453 break;
1454
1455 if (!(Wnd = ValidateHwndNoErr(List[i])))
1456 continue;
1457
1458 Owner = Wnd->spwndOwner ? Wnd->spwndOwner->head.h : NULL;
1459
1460 if (Owner != UserHMGetHandle(Window)) continue;
1461
1462 UserRefObjectCo(Wnd, &Ref);
1463 TRACE( "moving %p owned by %p after %p\n", List[i], UserHMGetHandle(Window), hWndInsertAfter );
1464 co_WinPosSetWindowPos(Wnd, hWndInsertAfter, 0, 0, 0, 0,
1465 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING| SWP_DEFERERASE);
1466
1467 UserDerefObjectCo(Wnd);
1468 hWndInsertAfter = List[i];
1469 }
1470 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1471 }
1472 done:
1473 return hWndInsertAfter;
1474 }
1475 ////
1476
1477 /***********************************************************************
1478 * WinPosInternalMoveWindow
1479 *
1480 * Update WindowRect and ClientRect of Window and all of its children
1481 * We keep both WindowRect and ClientRect in screen coordinates internally
1482 */
1483 static
1484 VOID FASTCALL
1485 WinPosInternalMoveWindow(PWND Window, INT MoveX, INT MoveY)
1486 {
1487 PWND Child;
1488
1489 ASSERT(Window != Window->spwndChild);
1490 TRACE("InternalMoveWin X %d Y %d\n", MoveX, MoveY);
1491
1492 Window->rcWindow.left += MoveX;
1493 Window->rcWindow.right += MoveX;
1494 Window->rcWindow.top += MoveY;
1495 Window->rcWindow.bottom += MoveY;
1496
1497 Window->rcClient.left += MoveX;
1498 Window->rcClient.right += MoveX;
1499 Window->rcClient.top += MoveY;
1500 Window->rcClient.bottom += MoveY;
1501
1502 for(Child = Window->spwndChild; Child; Child = Child->spwndNext)
1503 {
1504 WinPosInternalMoveWindow(Child, MoveX, MoveY);
1505 }
1506 }
1507
1508 /*
1509 * WinPosFixupSWPFlags
1510 *
1511 * Fix redundant flags and values in the WINDOWPOS structure.
1512 */
1513 static
1514 BOOL FASTCALL
1515 WinPosFixupFlags(WINDOWPOS *WinPos, PWND Wnd)
1516 {
1517 PWND Parent;
1518 POINT pt;
1519
1520 /* Finally make sure that all coordinates are valid */
1521 if (WinPos->x < -32768) WinPos->x = -32768;
1522 else if (WinPos->x > 32767) WinPos->x = 32767;
1523 if (WinPos->y < -32768) WinPos->y = -32768;
1524 else if (WinPos->y > 32767) WinPos->y = 32767;
1525
1526 WinPos->cx = max(WinPos->cx, 0);
1527 WinPos->cy = max(WinPos->cy, 0);
1528
1529 Parent = UserGetAncestor( Wnd, GA_PARENT );
1530 if (!IntIsWindowVisible( Parent ) &&
1531 /* Fix B : wine msg test_SetParent:WmSetParentSeq_2:25 wParam bits! */
1532 (WinPos->flags & SWP_AGG_STATUSFLAGS) == SWP_AGG_NOPOSCHANGE) WinPos->flags |= SWP_NOREDRAW;
1533
1534 if (Wnd->style & WS_VISIBLE) WinPos->flags &= ~SWP_SHOWWINDOW;
1535 else
1536 {
1537 WinPos->flags &= ~SWP_HIDEWINDOW;
1538 if (!(WinPos->flags & SWP_SHOWWINDOW)) WinPos->flags |= SWP_NOREDRAW;
1539 }
1540
1541 /* Check for right size */
1542 if (Wnd->rcWindow.right - Wnd->rcWindow.left == WinPos->cx &&
1543 Wnd->rcWindow.bottom - Wnd->rcWindow.top == WinPos->cy)
1544 {
1545 WinPos->flags |= SWP_NOSIZE;
1546 }
1547
1548 pt.x = WinPos->x;
1549 pt.y = WinPos->y;
1550 IntClientToScreen( Parent, &pt );
1551 TRACE("WPFU C2S wpx %d wpy %d ptx %d pty %d\n",WinPos->x,WinPos->y,pt.x,pt.y);
1552 /* Check for right position */
1553 if (Wnd->rcWindow.left == pt.x && Wnd->rcWindow.top == pt.y)
1554 {
1555 //ERR("In right pos\n");
1556 WinPos->flags |= SWP_NOMOVE;
1557 }
1558
1559 if ( WinPos->hwnd != UserGetForegroundWindow() && (Wnd->style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
1560 {
1561 /* Bring to the top when activating */
1562 if (!(WinPos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)) &&
1563 (WinPos->flags & SWP_NOZORDER ||
1564 (WinPos->hwndInsertAfter != HWND_TOPMOST && WinPos->hwndInsertAfter != HWND_NOTOPMOST)))
1565 {
1566 WinPos->flags &= ~SWP_NOZORDER;
1567 WinPos->hwndInsertAfter = (0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP);
1568 }
1569 }
1570
1571 /* Check hwndInsertAfter */
1572 if (!(WinPos->flags & SWP_NOZORDER))
1573 {
1574 /* Fix sign extension */
1575 if (WinPos->hwndInsertAfter == (HWND)0xffff)
1576 {
1577 WinPos->hwndInsertAfter = HWND_TOPMOST;
1578 }
1579 else if (WinPos->hwndInsertAfter == (HWND)0xfffe)
1580 {
1581 WinPos->hwndInsertAfter = HWND_NOTOPMOST;
1582 }
1583
1584 if (WinPos->hwndInsertAfter == HWND_TOP)
1585 {
1586 /* Keep it topmost when it's already topmost */
1587 if ((Wnd->ExStyle & WS_EX_TOPMOST) != 0)
1588 WinPos->hwndInsertAfter = HWND_TOPMOST;
1589
1590 if (IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd)
1591 {
1592 WinPos->flags |= SWP_NOZORDER;
1593 }
1594 }
1595 else if (WinPos->hwndInsertAfter == HWND_BOTTOM)
1596 {
1597 if (!(Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDLAST) == WinPos->hwnd)
1598 WinPos->flags |= SWP_NOZORDER;
1599 }
1600 else if (WinPos->hwndInsertAfter == HWND_TOPMOST)
1601 {
1602 if ((Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd)
1603 WinPos->flags |= SWP_NOZORDER;
1604 }
1605 else if (WinPos->hwndInsertAfter == HWND_NOTOPMOST)
1606 {
1607 if (!(Wnd->ExStyle & WS_EX_TOPMOST))
1608 WinPos->flags |= SWP_NOZORDER;
1609 }
1610 else /* hwndInsertAfter must be a sibling of the window */
1611 {
1612 PWND InsAfterWnd;
1613
1614 InsAfterWnd = ValidateHwndNoErr(WinPos->hwndInsertAfter);
1615 if(!InsAfterWnd)
1616 {
1617 return TRUE;
1618 }
1619
1620 if (InsAfterWnd->spwndParent != Wnd->spwndParent)
1621 {
1622 /* Note from wine User32 Win test_SetWindowPos:
1623 "Returns TRUE also for windows that are not siblings"
1624 "Does not seem to do anything even without passing flags, still returns TRUE"
1625 "Same thing the other way around."
1626 ".. and with these windows."
1627 */
1628 return FALSE;
1629 }
1630 else
1631 {
1632 /*
1633 * We don't need to change the Z order of hwnd if it's already
1634 * inserted after hwndInsertAfter or when inserting hwnd after
1635 * itself.
1636 */
1637 if ((WinPos->hwnd == WinPos->hwndInsertAfter) ||
1638 ((InsAfterWnd->spwndNext) && (WinPos->hwnd == InsAfterWnd->spwndNext->head.h)))
1639 {
1640 WinPos->flags |= SWP_NOZORDER;
1641 }
1642 }
1643 }
1644 }
1645
1646 return TRUE;
1647 }
1648
1649 /* x and y are always screen relative */
1650 BOOLEAN FASTCALL
1651 co_WinPosSetWindowPos(
1652 PWND Window,
1653 HWND WndInsertAfter,
1654 INT x,
1655 INT y,
1656 INT cx,
1657 INT cy,
1658 UINT flags
1659 )
1660 {
1661 WINDOWPOS WinPos;
1662 RECTL NewWindowRect;
1663 RECTL NewClientRect;
1664 RECTL valid_rects[2];
1665 PREGION VisBefore = NULL;
1666 PREGION VisBeforeJustClient = NULL;
1667 PREGION VisAfter = NULL;
1668 PREGION CopyRgn = NULL;
1669 ULONG WvrFlags = 0;
1670 RECTL OldWindowRect, OldClientRect;
1671 int RgnType;
1672 HDC Dc;
1673 RECTL CopyRect;
1674 PWND Ancestor;
1675 BOOL bPointerInWindow, PosChanged = FALSE;
1676 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1677
1678 ASSERT_REFS_CO(Window);
1679
1680 TRACE("pwnd %p, after %p, %d,%d (%dx%d), flags %s",
1681 Window, WndInsertAfter, x, y, cx, cy, flags);
1682 #if DBG
1683 dump_winpos_flags(flags);
1684 #endif
1685
1686 /* FIXME: Get current active window from active queue. Why? since r2915. */
1687
1688 bPointerInWindow = IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y);
1689
1690 WinPos.hwnd = Window->head.h;
1691 WinPos.hwndInsertAfter = WndInsertAfter;
1692 WinPos.x = x;
1693 WinPos.y = y;
1694 WinPos.cx = cx;
1695 WinPos.cy = cy;
1696 WinPos.flags = flags;
1697
1698 if ( flags & SWP_ASYNCWINDOWPOS )
1699 {
1700 LRESULT lRes;
1701 PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
1702 if ( ppos )
1703 {
1704 WinPos.flags &= ~SWP_ASYNCWINDOWPOS; // Clear flag.
1705 *ppos = WinPos;
1706 /* Yes it's a pointer inside Win32k! */
1707 lRes = co_IntSendMessageNoWait( WinPos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
1708 /* We handle this the same way as Event Hooks and Hooks. */
1709 if ( !lRes )
1710 {
1711 ExFreePoolWithTag(ppos, USERTAG_SWP);
1712 return FALSE;
1713 }
1714 return TRUE;
1715 }
1716 return FALSE;
1717 }
1718
1719 co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
1720
1721 /* Does the window still exist? */
1722 if (!IntIsWindow(WinPos.hwnd))
1723 {
1724 TRACE("WinPosSetWindowPos: Invalid handle 0x%p!\n",WinPos.hwnd);
1725 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
1726 return FALSE;
1727 }
1728
1729 /* Fix up the flags. */
1730 if (!WinPosFixupFlags(&WinPos, Window))
1731 {
1732 // See Note.
1733 return TRUE;
1734 }
1735
1736 Ancestor = UserGetAncestor(Window, GA_PARENT);
1737 if ( (WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER &&
1738 Ancestor && Ancestor->head.h == IntGetDesktopWindow() )
1739 {
1740 WinPos.hwndInsertAfter = WinPosDoOwnedPopups(Window, WinPos.hwndInsertAfter);
1741 }
1742
1743 if (!(WinPos.flags & SWP_NOREDRAW))
1744 {
1745 /* Compute the visible region before the window position is changed */
1746 if (!(WinPos.flags & SWP_SHOWWINDOW) &&
1747 (WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
1748 SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
1749 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
1750 {
1751 VisBefore = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1752 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1753
1754 if ( VisBefore != NULL &&
1755 REGION_Complexity(VisBefore) == NULLREGION )
1756 {
1757 REGION_Delete(VisBefore);
1758 VisBefore = NULL;
1759 }
1760 else if(VisBefore)
1761 {
1762 REGION_bOffsetRgn(VisBefore, -Window->rcWindow.left, -Window->rcWindow.top);
1763 }
1764
1765 /* Calculate the non client area for resizes, as this is used in the copy region */
1766 if (!(WinPos.flags & SWP_NOSIZE))
1767 {
1768 VisBeforeJustClient = VIS_ComputeVisibleRegion(Window, TRUE, FALSE,
1769 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1770
1771 if ( VisBeforeJustClient != NULL &&
1772 REGION_Complexity(VisBeforeJustClient) == NULLREGION )
1773 {
1774 REGION_Delete(VisBeforeJustClient);
1775 VisBeforeJustClient = NULL;
1776 }
1777 else if(VisBeforeJustClient)
1778 {
1779 REGION_bOffsetRgn(VisBeforeJustClient, -Window->rcWindow.left, -Window->rcWindow.top);
1780 }
1781 }
1782 }
1783 }
1784
1785 //// HACK 3
1786 if (Window->hrgnNewFrame)
1787 {
1788 SelectWindowRgn( Window, Window->hrgnNewFrame ); // Should be PSMWP->acvr->hrgnClip
1789 Window->hrgnNewFrame = NULL;
1790 }
1791
1792 WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect, valid_rects);
1793
1794 // ERR("co_WinPosDoNCCALCSize returned 0x%x\n valid dest: %d %d %d %d\n valid src : %d %d %d %d\n", WvrFlags,
1795 // valid_rects[0].left,valid_rects[0].top,valid_rects[0].right,valid_rects[0].bottom,
1796 // valid_rects[1].left,valid_rects[1].top,valid_rects[1].right,valid_rects[1].bottom);
1797
1798 /* Validate link windows. (also take into account shell window in hwndShellWindow) */
1799 if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow())
1800 {
1801 IntLinkHwnd(Window, WinPos.hwndInsertAfter);
1802 }
1803
1804 OldWindowRect = Window->rcWindow;
1805 OldClientRect = Window->rcClient;
1806
1807 if (NewClientRect.left != OldClientRect.left ||
1808 NewClientRect.top != OldClientRect.top)
1809 {
1810 // Move child window if their parent is moved. Keep Child window relative to Parent...
1811 WinPosInternalMoveWindow(Window,
1812 NewClientRect.left - OldClientRect.left,
1813 NewClientRect.top - OldClientRect.top);
1814 PosChanged = TRUE;
1815 }
1816
1817 Window->rcWindow = NewWindowRect;
1818 Window->rcClient = NewClientRect;
1819
1820 /* erase parent when hiding or resizing child */
1821 if (WinPos.flags & SWP_HIDEWINDOW)
1822 {
1823 /* Clear the update region */
1824 co_UserRedrawWindow( Window,
1825 NULL,
1826 0,
1827 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
1828
1829 if (UserIsDesktopWindow(Window->spwndParent))
1830 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM)Window->head.h, 0);
1831
1832 Window->style &= ~WS_VISIBLE; //IntSetStyle( Window, 0, WS_VISIBLE );
1833 Window->head.pti->cVisWindows--;
1834 IntNotifyWinEvent(EVENT_OBJECT_HIDE, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1835 }
1836 else if (WinPos.flags & SWP_SHOWWINDOW)
1837 {
1838 if (UserIsDesktopWindow(Window->spwndParent) &&
1839 Window->spwndOwner == NULL &&
1840 (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
1841 (Window->ExStyle & WS_EX_APPWINDOW)))
1842 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)Window->head.h, 0);
1843
1844 Window->style |= WS_VISIBLE; //IntSetStyle( Window, WS_VISIBLE, 0 );
1845 Window->head.pti->cVisWindows++;
1846 IntNotifyWinEvent(EVENT_OBJECT_SHOW, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1847 }
1848
1849 if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != HRGN_WINDOW)
1850 {
1851 NtGdiOffsetRgn(Window->hrgnUpdate,
1852 NewWindowRect.left - OldWindowRect.left,
1853 NewWindowRect.top - OldWindowRect.top);
1854 }
1855
1856 DceResetActiveDCEs(Window); // For WS_VISIBLE changes.
1857
1858 if (!(WinPos.flags & SWP_NOREDRAW))
1859 {
1860 /* Determine the new visible region */
1861 VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1862 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1863
1864 if ( VisAfter != NULL &&
1865 REGION_Complexity(VisAfter) == NULLREGION )
1866 {
1867 REGION_Delete(VisAfter);
1868 VisAfter = NULL;
1869 }
1870 else if(VisAfter)
1871 {
1872 REGION_bOffsetRgn(VisAfter, -Window->rcWindow.left, -Window->rcWindow.top);
1873 }
1874
1875 /*
1876 * Determine which pixels can be copied from the old window position
1877 * to the new. Those pixels must be visible in both the old and new
1878 * position. Also, check the class style to see if the windows of this
1879 * class need to be completely repainted on (horizontal/vertical) size
1880 * change.
1881 */
1882 if ( ( VisBefore != NULL &&
1883 VisAfter != NULL &&
1884 !(WinPos.flags & SWP_NOCOPYBITS) &&
1885 ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) &&
1886 !(Window->ExStyle & WS_EX_TRANSPARENT) ) ||
1887 ( !PosChanged && (WinPos.flags & SWP_FRAMECHANGED) && VisBefore) )
1888 {
1889
1890 /*
1891 * If this is (also) a window resize, the whole nonclient area
1892 * needs to be repainted. So we limit the copy to the client area,
1893 * 'cause there is no use in copying it (would possibly cause
1894 * "flashing" too). However, if the copy region is already empty,
1895 * we don't have to crop (can't take anything away from an empty
1896 * region...)
1897 */
1898
1899 CopyRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
1900 if (WinPos.flags & SWP_NOSIZE)
1901 RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
1902 else if (VisBeforeJustClient != NULL)
1903 {
1904 RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBeforeJustClient, RGN_AND);
1905 REGION_Delete(VisBeforeJustClient);
1906 }
1907
1908 /* Now use in copying bits which are in the update region. */
1909 if (Window->hrgnUpdate != NULL)
1910 {
1911 PREGION RgnUpdate = REGION_LockRgn(Window->hrgnUpdate);
1912 if (RgnUpdate)
1913 {
1914 REGION_bOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1915 IntGdiCombineRgn(CopyRgn, CopyRgn, RgnUpdate, RGN_DIFF);
1916 REGION_bOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1917 REGION_UnlockRgn(RgnUpdate);
1918 }
1919 }
1920
1921 /*
1922 * Now, get the bounding box of the copy region. If it's empty
1923 * there's nothing to copy. Also, it's no use copying bits onto
1924 * themselves.
1925 */
1926 if (REGION_GetRgnBox(CopyRgn, &CopyRect) == NULLREGION)
1927 {
1928 /* Nothing to copy, clean up */
1929 REGION_Delete(CopyRgn);
1930 CopyRgn = NULL;
1931 }
1932 else if ( OldWindowRect.left != NewWindowRect.left ||
1933 OldWindowRect.top != NewWindowRect.top ||
1934 (WinPos.flags & SWP_FRAMECHANGED) )
1935 {
1936 HRGN DcRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
1937 PREGION DcRgnObj = REGION_LockRgn(DcRgn);
1938
1939 /*
1940 * Small trick here: there is no function to bitblt a region. So
1941 * we set the region as the clipping region, take the bounding box
1942 * of the region and bitblt that. Since nothing outside the clipping
1943 * region is copied, this has the effect of bitblt'ing the region.
1944 *
1945 * Since NtUserGetDCEx takes ownership of the clip region, we need
1946 * to create a copy of CopyRgn and pass that. We need CopyRgn later
1947 */
1948 IntGdiCombineRgn(DcRgnObj, CopyRgn, NULL, RGN_COPY);
1949 REGION_bOffsetRgn(DcRgnObj, NewWindowRect.left, NewWindowRect.top);
1950 REGION_UnlockRgn(DcRgnObj);
1951 Dc = UserGetDCEx( Window,
1952 DcRgn,
1953 DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN); // DCX_WINDOW will set first, go read WinDC.c.
1954 NtGdiBitBlt( Dc,
1955 CopyRect.left, CopyRect.top,
1956 CopyRect.right - CopyRect.left,
1957 CopyRect.bottom - CopyRect.top,
1958 Dc,
1959 CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
1960 CopyRect.top + (OldWindowRect.top - NewWindowRect.top),
1961 SRCCOPY,
1962 0,
1963 0);
1964
1965 UserReleaseDC(Window, Dc, FALSE);
1966 IntValidateParent(Window, CopyRgn);
1967 GreDeleteObject(DcRgn);
1968 }
1969 }
1970 else
1971 {
1972 CopyRgn = NULL;
1973 }
1974
1975 if ( !PosChanged && (WinPos.flags & SWP_FRAMECHANGED) && VisBefore )
1976 {
1977 PWND pwnd = Window;
1978 PWND Parent = pwnd->spwndParent;
1979
1980 TRACE("SWP_FRAMECHANGED no chg\n");
1981
1982 if ( pwnd->style & WS_CHILD ) // Fix ProgMan menu bar drawing.
1983 {
1984 TRACE("SWP_FRAMECHANGED win child %p Parent %p\n",pwnd,Parent);
1985 pwnd = Parent ? Parent : pwnd;
1986 }
1987
1988 if ( !(pwnd->style & WS_CHILD) )
1989 {
1990 HDC hdc;
1991 HRGN DcRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
1992 PREGION DcRgnObj = REGION_LockRgn(DcRgn);
1993
1994 TRACE("SWP_FRAMECHANGED Draw\n");
1995
1996 IntGdiCombineRgn(DcRgnObj, VisBefore, NULL, RGN_COPY);
1997 REGION_UnlockRgn(DcRgnObj);
1998
1999 hdc = UserGetDCEx( pwnd,
2000 DcRgn,
2001 DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN); // DCX_WINDOW, see note above....
2002
2003 NC_DoNCPaint(pwnd, hdc, -1); // Force full redraw of nonclient area.
2004
2005 UserReleaseDC(pwnd, hdc, FALSE);
2006 IntValidateParent(pwnd, DcRgnObj);
2007 GreDeleteObject(DcRgn);
2008 }
2009 }
2010
2011 /* We need to redraw what wasn't visible before */
2012 if (VisAfter != NULL)
2013 {
2014 PREGION DirtyRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
2015 if (DirtyRgn)
2016 {
2017 if (CopyRgn != NULL)
2018 {
2019 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
2020 }
2021 else
2022 {
2023 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
2024 }
2025
2026 if (RgnType != ERROR && RgnType != NULLREGION)
2027 {
2028 /* old code
2029 NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2030 IntInvalidateWindows( Window,
2031 DirtyRgn,
2032 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2033 }
2034 GreDeleteObject(DirtyRgn);
2035 */
2036
2037 PWND Parent = Window->spwndParent;
2038
2039 REGION_bOffsetRgn( DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2040
2041 if ( (Window->style & WS_CHILD) && (Parent) && !(Parent->style & WS_CLIPCHILDREN))
2042 {
2043 IntInvalidateWindows( Parent, DirtyRgn, RDW_ERASE | RDW_INVALIDATE);
2044 co_IntPaintWindows(Parent, RDW_NOCHILDREN, FALSE);
2045 }
2046 else
2047 {
2048 IntInvalidateWindows( Window, DirtyRgn, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2049 }
2050 }
2051 REGION_Delete(DirtyRgn);
2052 }
2053 }
2054
2055 if (CopyRgn != NULL)
2056 {
2057 REGION_Delete(CopyRgn);
2058 }
2059
2060 /* Expose what was covered before but not covered anymore */
2061 if (VisBefore != NULL)
2062 {
2063 PREGION ExposedRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
2064 if (ExposedRgn)
2065 {
2066 RgnType = IntGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
2067 REGION_bOffsetRgn(ExposedRgn,
2068 OldWindowRect.left - NewWindowRect.left,
2069 OldWindowRect.top - NewWindowRect.top);
2070
2071 if (VisAfter != NULL)
2072 RgnType = IntGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
2073
2074 if (RgnType != ERROR && RgnType != NULLREGION)
2075 {
2076 co_VIS_WindowLayoutChanged(Window, ExposedRgn);
2077 }
2078 REGION_Delete(ExposedRgn);
2079 }
2080 REGION_Delete(VisBefore);
2081 }
2082
2083 if (VisAfter != NULL)
2084 {
2085 REGION_Delete(VisAfter);
2086 }
2087 }
2088
2089 if (!(WinPos.flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
2090 {
2091 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2092 {
2093 co_IntSendMessageNoWait(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
2094 }
2095 else
2096 {
2097 //ERR("SetWindowPos Set FG Window!\n");
2098 if ( pti->MessageQueue->spwndActive != Window ||
2099 pti->MessageQueue != gpqForeground )
2100 {
2101 //ERR("WPSWP : set active window\n");
2102 if (!(Window->state & WNDS_BEINGACTIVATED)) // Inside SAW?
2103 {
2104 co_IntSetForegroundWindow(Window); // Fixes SW_HIDE issues. Wine win test_SetActiveWindow & test_SetForegroundWindow.
2105 }
2106 }
2107 }
2108 }
2109
2110 if ( !PosChanged &&
2111 (WinPos.flags & SWP_FRAMECHANGED) &&
2112 !(WinPos.flags & SWP_DEFERERASE) && // Prevent sending WM_SYNCPAINT message.
2113 VisAfter )
2114 {
2115 PWND Parent = Window->spwndParent;
2116 if ( !(Window->style & WS_CHILD) && (Parent) && (Parent->style & WS_CLIPCHILDREN))
2117 {
2118 TRACE("SWP_FRAMECHANGED Parent WS_CLIPCHILDREN\n");
2119 UserSyncAndPaintWindows( Parent, RDW_CLIPCHILDREN);
2120 }
2121 }
2122
2123 // Fix wine msg test_SetFocus, prevents sending WM_WINDOWPOSCHANGED.
2124 if ( VisBefore == NULL &&
2125 VisBeforeJustClient == NULL &&
2126 !(Window->ExStyle & WS_EX_TOPMOST) &&
2127 (WinPos.flags & SWP_AGG_STATUSFLAGS) == (SWP_AGG_NOPOSCHANGE & ~SWP_NOZORDER))
2128 {
2129 TRACE("No drawing, set no Z order and no redraw!\n");
2130 WinPos.flags |= SWP_NOZORDER|SWP_NOREDRAW;
2131 }
2132
2133 if(!(flags & SWP_DEFERERASE))
2134 {
2135 /* erase parent when hiding or resizing child */
2136 if ((flags & SWP_HIDEWINDOW) ||
2137 (!(flags & SWP_SHOWWINDOW) &&
2138 (WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOGEOMETRYCHANGE))
2139 {
2140 PWND Parent = Window->spwndParent;
2141 if (!Parent || UserIsDesktopWindow(Parent)) Parent = Window;
2142 UserSyncAndPaintWindows( Parent, RDW_ERASENOW);
2143 }
2144
2145 /* Give newly shown windows a chance to redraw */
2146 if(((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2147 && !(flags & SWP_AGG_NOCLIENTCHANGE) && (flags & SWP_SHOWWINDOW))
2148 {
2149 UserSyncAndPaintWindows( Window, RDW_ERASENOW);
2150 }
2151 }
2152
2153 /* And last, send the WM_WINDOWPOSCHANGED message */
2154
2155 TRACE("\tstatus hwnd %p flags = %04x\n",Window?Window->head.h:NULL,WinPos.flags & SWP_AGG_STATUSFLAGS);
2156
2157 if (((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2158 && !((flags & SWP_AGG_NOCLIENTCHANGE) && (flags & SWP_SHOWWINDOW)))
2159 {
2160 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
2161 and always contains final window position.
2162 */
2163 WinPos.x = NewWindowRect.left;
2164 WinPos.y = NewWindowRect.top;
2165 WinPos.cx = NewWindowRect.right - NewWindowRect.left;
2166 WinPos.cy = NewWindowRect.bottom - NewWindowRect.top;
2167 TRACE("WM_WINDOWPOSCHANGED hwnd %p Flags %04x\n",WinPos.hwnd,WinPos.flags);
2168 co_IntSendMessageNoWait(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
2169 }
2170
2171 if ( WinPos.flags & SWP_FRAMECHANGED || WinPos.flags & SWP_STATECHANGED ||
2172 !(WinPos.flags & SWP_NOCLIENTSIZE) || !(WinPos.flags & SWP_NOCLIENTMOVE) )
2173 {
2174 PWND pWnd = ValidateHwndNoErr(WinPos.hwnd);
2175 if (pWnd)
2176 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2177 }
2178
2179 if(bPointerInWindow != IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y))
2180 {
2181 /* Generate mouse move message */
2182 MSG msg;
2183 msg.message = WM_MOUSEMOVE;
2184 msg.wParam = UserGetMouseButtonsState();
2185 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2186 msg.pt = gpsi->ptCursor;
2187 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2188 }
2189
2190 return TRUE;
2191 }
2192
2193 LRESULT FASTCALL
2194 co_WinPosGetNonClientSize(PWND Window, RECT* WindowRect, RECT* ClientRect)
2195 {
2196 LRESULT Result;
2197
2198 ASSERT_REFS_CO(Window);
2199
2200 *ClientRect = *WindowRect;
2201 Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect);
2202
2203 FixClientRect(ClientRect, WindowRect);
2204
2205 return Result;
2206 }
2207
2208 void FASTCALL
2209 co_WinPosSendSizeMove(PWND Wnd)
2210 {
2211 RECTL Rect;
2212 LPARAM lParam;
2213 WPARAM wParam = SIZE_RESTORED;
2214
2215 IntGetClientRect(Wnd, &Rect);
2216 lParam = MAKELONG(Rect.right-Rect.left, Rect.bottom-Rect.top);
2217
2218 Wnd->state &= ~WNDS_SENDSIZEMOVEMSGS;
2219
2220 if (Wnd->style & WS_MAXIMIZE)
2221 {
2222 wParam = SIZE_MAXIMIZED;
2223 }
2224 else if (Wnd->style & WS_MINIMIZE)
2225 {
2226 wParam = SIZE_MINIMIZED;
2227 lParam = 0;
2228 }
2229
2230 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SIZE, wParam, lParam);
2231
2232 if (UserIsDesktopWindow(Wnd->spwndParent))
2233 lParam = MAKELONG(Wnd->rcClient.left, Wnd->rcClient.top);
2234 else
2235 lParam = MAKELONG(Wnd->rcClient.left-Wnd->spwndParent->rcClient.left, Wnd->rcClient.top-Wnd->spwndParent->rcClient.top);
2236
2237 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_MOVE, 0, lParam);
2238
2239 IntEngWindowChanged(Wnd, WOC_RGN_CLIENT);
2240 }
2241
2242 UINT FASTCALL
2243 co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos)
2244 {
2245 POINT Size;
2246 WINDOWPLACEMENT wpl;
2247 LONG old_style;
2248 UINT SwpFlags = 0;
2249
2250 ASSERT_REFS_CO(Wnd);
2251
2252 wpl.length = sizeof(wpl);
2253 IntGetWindowPlacement( Wnd, &wpl );
2254
2255 if (co_HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)Wnd->head.h, ShowFlag))
2256 {
2257 ERR("WinPosMinMaximize WH_CBT Call Hook return!\n");
2258 return SWP_NOSIZE | SWP_NOMOVE;
2259 }
2260 if (Wnd->style & WS_MINIMIZE)
2261 {
2262 switch (ShowFlag)
2263 {
2264 case SW_MINIMIZE:
2265 case SW_SHOWMINNOACTIVE:
2266 case SW_SHOWMINIMIZED:
2267 case SW_FORCEMINIMIZE:
2268 return SWP_NOSIZE | SWP_NOMOVE;
2269 }
2270 if (!co_IntSendMessageNoWait(Wnd->head.h, WM_QUERYOPEN, 0, 0))
2271 {
2272 return(SWP_NOSIZE | SWP_NOMOVE);
2273 }
2274 SwpFlags |= SWP_NOCOPYBITS;
2275 }
2276 switch (ShowFlag)
2277 {
2278 case SW_MINIMIZE:
2279 case SW_SHOWMINNOACTIVE:
2280 case SW_SHOWMINIMIZED:
2281 case SW_FORCEMINIMIZE:
2282 {
2283 //ERR("MinMaximize Minimize\n");
2284 if (Wnd->style & WS_MAXIMIZE)
2285 {
2286 Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED;
2287 }
2288 else
2289 {
2290 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2291 }
2292
2293 old_style = IntSetStyle( Wnd, WS_MINIMIZE, WS_MAXIMIZE );
2294
2295 co_UserRedrawWindow(Wnd, NULL, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOINTERNALPAINT);
2296
2297 if (!(Wnd->InternalPos.flags & WPF_SETMINPOSITION))
2298 Wnd->InternalPos.flags &= ~WPF_MININIT;
2299
2300 WinPosFindIconPos(Wnd, &wpl.ptMinPosition);
2301
2302 if (!(old_style & WS_MINIMIZE))
2303 {
2304 SwpFlags |= SWP_STATECHANGED;
2305 IntShowOwnedPopups(Wnd, FALSE);
2306 }
2307
2308 RECTL_vSetRect(NewPos, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
2309 wpl.ptMinPosition.x + UserGetSystemMetrics(SM_CXMINIMIZED),
2310 wpl.ptMinPosition.y + UserGetSystemMetrics(SM_CYMINIMIZED));
2311 SwpFlags |= SWP_NOCOPYBITS;
2312 break;
2313 }
2314
2315 case SW_MAXIMIZE:
2316 {
2317 //ERR("MinMaximize Maximize\n");
2318 if ((Wnd->style & WS_MAXIMIZE) && (Wnd->style & WS_VISIBLE))
2319 {
2320 SwpFlags = SWP_NOSIZE | SWP_NOMOVE;
2321 break;
2322 }
2323 co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
2324
2325 /*ERR("Maximize: %d,%d %dx%d\n",
2326 wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, Size.x, Size.y);
2327 */
2328 old_style = IntSetStyle( Wnd, WS_MAXIMIZE, WS_MINIMIZE );
2329 /*if (old_style & WS_MINIMIZE)
2330 {
2331 IntShowOwnedPopups(Wnd, TRUE);
2332 }*/
2333
2334 if (!(old_style & WS_MAXIMIZE)) SwpFlags |= SWP_STATECHANGED;
2335 RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
2336 //wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
2337 Size.x, Size.y);
2338 break;
2339 }
2340
2341 case SW_SHOWNOACTIVATE:
2342 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2343 /* fall through */
2344 case SW_SHOWNORMAL:
2345 case SW_RESTORE:
2346 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
2347 {
2348 //ERR("MinMaximize Restore\n");
2349 old_style = IntSetStyle( Wnd, 0, WS_MINIMIZE | WS_MAXIMIZE );
2350 if (old_style & WS_MINIMIZE)
2351 {
2352 IntShowOwnedPopups(Wnd, TRUE);
2353
2354 if (Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED)
2355 {
2356 co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
2357 IntSetStyle( Wnd, WS_MAXIMIZE, 0 );
2358 SwpFlags |= SWP_STATECHANGED;
2359 RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
2360 wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
2361 break;
2362 }
2363 else
2364 {
2365 *NewPos = wpl.rcNormalPosition;
2366 NewPos->right -= NewPos->left;
2367 NewPos->bottom -= NewPos->top;
2368 break;
2369 }
2370 }
2371 else
2372 {
2373 if (!(old_style & WS_MAXIMIZE))
2374 {
2375 break;
2376 }
2377 SwpFlags |= SWP_STATECHANGED;
2378 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2379 *NewPos = wpl.rcNormalPosition;
2380 NewPos->right -= NewPos->left;
2381 NewPos->bottom -= NewPos->top;
2382 break;
2383 }
2384 }
2385 }
2386 return SwpFlags;
2387 }
2388
2389 /*
2390 ShowWindow does not set SWP_FRAMECHANGED!!! Fix wine msg test_SetParent:WmSetParentSeq_2:23 wParam bits!
2391 */
2392 BOOLEAN FASTCALL
2393 co_WinPosShowWindow(PWND Wnd, INT Cmd)
2394 {
2395 BOOLEAN WasVisible;
2396 UINT Swp = 0, EventMsg = 0;
2397 RECTL NewPos = {0, 0, 0, 0};
2398 BOOLEAN ShowFlag;
2399 LONG style;
2400 PWND Parent;
2401 PTHREADINFO pti;
2402 //HRGN VisibleRgn;
2403 BOOL ShowOwned = FALSE;
2404 BOOL FirstTime = FALSE;
2405 ASSERT_REFS_CO(Wnd);
2406 //KeRosDumpStackFrames(NULL, 20);
2407 pti = PsGetCurrentThreadWin32Thread();
2408 WasVisible = (Wnd->style & WS_VISIBLE) != 0;
2409 style = Wnd->style;
2410
2411 TRACE("co_WinPosShowWindow START hwnd %p Cmd %d usicmd %u\n",
2412 Wnd->head.h, Cmd, pti->ppi->usi.wShowWindow);
2413
2414 if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW )
2415 {
2416 if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2417 {
2418 if ((Wnd->style & WS_CAPTION) == WS_CAPTION)
2419 {
2420 if (Wnd->spwndOwner == NULL)
2421 {
2422 if ( Cmd == SW_SHOWNORMAL || Cmd == SW_SHOW)
2423 {
2424 Cmd = SW_SHOWDEFAULT;
2425 }
2426 FirstTime = TRUE;
2427 TRACE("co_WPSW FT 1\n");
2428 }
2429 }
2430 }
2431 }
2432
2433 if ( Cmd == SW_SHOWDEFAULT )
2434 {
2435 if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW )
2436 {
2437 Cmd = pti->ppi->usi.wShowWindow;
2438 FirstTime = TRUE;
2439 TRACE("co_WPSW FT 2\n");
2440 }
2441 }
2442
2443 if (FirstTime)
2444 {
2445 pti->ppi->usi.dwFlags &= ~(STARTF_USEPOSITION|STARTF_USESIZE|STARTF_USESHOWWINDOW);
2446 }
2447
2448 switch (Cmd)
2449 {
2450 case SW_HIDE:
2451 {
2452 if (!WasVisible)
2453 {
2454 //ERR("co_WinPosShowWindow Exit Bad\n");
2455 return FALSE;
2456 }
2457 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2458 if (Wnd != pti->MessageQueue->spwndActive)
2459 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2460 break;
2461 }
2462
2463 case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
2464 case SW_SHOWMINNOACTIVE:
2465 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2466 /* Fall through. */
2467 case SW_SHOWMINIMIZED:
2468 Swp |= SWP_SHOWWINDOW;
2469 /* Fall through. */
2470 case SW_MINIMIZE:
2471 {
2472 Swp |= SWP_NOACTIVATE;
2473 if (!(style & WS_MINIMIZE))
2474 {
2475 IntShowOwnedPopups(Wnd, FALSE );
2476 // Fix wine Win test_SetFocus todo #1 & #2,
2477 if (Cmd == SW_SHOWMINIMIZED)
2478 {
2479 //ERR("co_WinPosShowWindow Set focus 1\n");
2480 if ((style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2481 co_UserSetFocus(Wnd->spwndParent);
2482 else
2483 co_UserSetFocus(0);
2484 }
2485
2486 Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos);
2487
2488 EventMsg = EVENT_SYSTEM_MINIMIZESTART;
2489 }
2490 else
2491 {
2492 if (WasVisible)
2493 {
2494 //ERR("co_WinPosShowWindow Exit Good\n");
2495 return TRUE;
2496 }
2497 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2498 }
2499 break;
2500 }
2501
2502 case SW_SHOWMAXIMIZED:
2503 {
2504 Swp |= SWP_SHOWWINDOW;
2505 if (!(style & WS_MAXIMIZE))
2506 {
2507 ShowOwned = TRUE;
2508
2509 Swp |= co_WinPosMinMaximize(Wnd, SW_MAXIMIZE, &NewPos);
2510
2511 EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2512 }
2513 else
2514 {
2515 if (WasVisible)
2516 {
2517 //ERR("co_WinPosShowWindow Exit Good 1\n");
2518 return TRUE;
2519 }
2520 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2521 }
2522 break;
2523 }
2524
2525 case SW_SHOWNA:
2526 Swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2527 if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOZORDER;
2528 break;
2529 case SW_SHOW:
2530 if (WasVisible) return(TRUE); // Nothing to do!
2531 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2532 /* Don't activate the topmost window. */
2533 if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2534 break;
2535
2536 case SW_SHOWNOACTIVATE:
2537 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2538 /* Fall through. */
2539 case SW_SHOWNORMAL:
2540 case SW_SHOWDEFAULT:
2541 case SW_RESTORE:
2542 if (!WasVisible) Swp |= SWP_SHOWWINDOW;
2543 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2544 {
2545 Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos);
2546 if (style & WS_MINIMIZE) EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2547 }
2548 else
2549 {
2550 if (WasVisible)
2551 {
2552 //ERR("co_WinPosShowWindow Exit Good 3\n");
2553 return TRUE;
2554 }
2555 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2556 }
2557 if ( style & WS_CHILD &&
2558 !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2559 !(Swp & SWP_STATECHANGED))
2560 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2561 break;
2562
2563 default:
2564 //ERR("co_WinPosShowWindow Exit Good 4\n");
2565 return WasVisible;
2566 }
2567
2568 ShowFlag = (Cmd != SW_HIDE);
2569
2570 if ((ShowFlag != WasVisible || Cmd == SW_SHOWNA) && Cmd != SW_SHOWMAXIMIZED && !(Swp & SWP_STATECHANGED))
2571 {
2572 co_IntSendMessageNoWait(Wnd->head.h, WM_SHOWWINDOW, ShowFlag, 0);
2573 #if 0 // Fix wine msg test_SetParent:WmSetParentSeq_1:2
2574 if (!(Wnd->state2 & WNDS2_WIN31COMPAT)) // <------------- XP sets this bit!
2575 co_IntSendMessageNoWait(Wnd->head.h, WM_SETVISIBLE, ShowFlag, 0);
2576 #endif
2577 if (!VerifyWnd(Wnd)) return WasVisible;
2578 }
2579
2580 /* We can't activate a child window */
2581 if ((Wnd->style & WS_CHILD) &&
2582 !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2583 Cmd != SW_SHOWNA)
2584 {
2585 //ERR("SWP Child No active and ZOrder\n");
2586 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2587 }
2588
2589 #if 0 // Explorer issues with common controls? Someone does not know how CS_SAVEBITS works.
2590 // Breaks startup and shutdown active window...
2591 if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
2592 Wnd->pcls->style & CS_SAVEBITS &&
2593 ((Cmd == SW_SHOW) || (Cmd == SW_NORMAL)))
2594 {
2595 ERR("WinPosShowWindow Set active\n");
2596 //UserSetActiveWindow(Wnd);
2597 co_IntSetForegroundWindow(Wnd); // HACK
2598 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2599 }
2600 #endif
2601
2602 if (IsChildVisible(Wnd) || Swp & SWP_STATECHANGED)
2603 {
2604 TRACE("Child is Vis %s or State changed %s. ShowFlag %s Swp %04x\n",
2605 (IsChildVisible(Wnd) ? "TRUE" : "FALSE"), (Swp & SWP_STATECHANGED ? "TRUE" : "FALSE"),
2606 (ShowFlag ? "TRUE" : "FALSE"),LOWORD(Swp));
2607 co_WinPosSetWindowPos( Wnd,
2608 0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP,
2609 NewPos.left,
2610 NewPos.top,
2611 NewPos.right, // NewPos.right - NewPos.left, when minimized and restore, the window becomes smaller.
2612 NewPos.bottom,// NewPos.bottom - NewPos.top,
2613 LOWORD(Swp));
2614 }
2615 else
2616 {
2617 TRACE("Parent Vis?\n");
2618 /* if parent is not visible simply toggle WS_VISIBLE and return */
2619 if (ShowFlag) IntSetStyle( Wnd, WS_VISIBLE, 0 );
2620 else IntSetStyle( Wnd, 0, WS_VISIBLE );
2621 }
2622
2623 if ( EventMsg ) IntNotifyWinEvent(EventMsg, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2624
2625 if ( ShowOwned ) IntShowOwnedPopups(Wnd, TRUE );
2626
2627 if ((Cmd == SW_HIDE) || (Cmd == SW_MINIMIZE))
2628 {
2629 if ( Wnd == pti->MessageQueue->spwndActive && pti->MessageQueue == IntGetFocusMessageQueue() )
2630 {
2631 if (UserIsDesktopWindow(Wnd->spwndParent))
2632 {
2633 if (!ActivateOtherWindowMin(Wnd))
2634 {
2635 co_WinPosActivateOtherWindow(Wnd);
2636 }
2637 }
2638 else
2639 {
2640 co_WinPosActivateOtherWindow(Wnd);
2641 }
2642 }
2643
2644 /* Revert focus to parent */
2645 if (Wnd == pti->MessageQueue->spwndFocus)
2646 {
2647 Parent = Wnd->spwndParent;
2648 if (UserIsDesktopWindow(Wnd->spwndParent))
2649 Parent = 0;
2650 co_UserSetFocus(Parent);
2651 }
2652 // Hide, just return.
2653 if (Cmd == SW_HIDE) return WasVisible;
2654 }
2655
2656 /* FIXME: Check for window destruction. */
2657
2658 if ((Wnd->state & WNDS_SENDSIZEMOVEMSGS) &&
2659 !(Wnd->state2 & WNDS2_INDESTROY))
2660 {
2661 co_WinPosSendSizeMove(Wnd);
2662 }
2663
2664 /* if previous state was minimized Windows sets focus to the window */
2665 if (style & WS_MINIMIZE)
2666 {
2667 co_UserSetFocus(Wnd);
2668 // Fix wine Win test_SetFocus todo #3,
2669 if (!(style & WS_CHILD)) co_IntSendMessage(UserHMGetHandle(Wnd), WM_ACTIVATE, WA_ACTIVE, 0);
2670 }
2671 //ERR("co_WinPosShowWindow EXIT\n");
2672 return WasVisible;
2673 }
2674
2675 static PWND
2676 co_WinPosSearchChildren(
2677 IN PWND ScopeWin,
2678 IN POINT *Point,
2679 IN OUT USHORT *HitTest,
2680 IN BOOL Ignore
2681 )
2682 {
2683 HWND *List, *phWnd;
2684 PWND pwndChild = NULL;
2685
2686 /* not visible */
2687 if (!(ScopeWin->style & WS_VISIBLE))
2688 {
2689 return NULL;
2690 }
2691
2692 /* not in window or in window region */
2693 if (!IntPtInWindow(ScopeWin, Point->x, Point->y))
2694 {
2695 return NULL;
2696 }
2697
2698 /* transparent */
2699 if ((ScopeWin->ExStyle & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT))
2700 {
2701 return NULL;
2702 }
2703
2704 if (!Ignore && (ScopeWin->style & WS_DISABLED))
2705 { /* disabled child */
2706 if ((ScopeWin->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return NULL;
2707 /* process the hit error */
2708 *HitTest = HTERROR;
2709 return ScopeWin;
2710 }
2711
2712 /* not minimized and check if point is inside the window */
2713 if (!(ScopeWin->style & WS_MINIMIZE) &&
2714 RECTL_bPointInRect(&ScopeWin->rcClient, Point->x, Point->y) )
2715 {
2716 UserReferenceObject(ScopeWin);
2717
2718 List = IntWinListChildren(ScopeWin);
2719 if (List)
2720 {
2721 for (phWnd = List; *phWnd; ++phWnd)
2722 {
2723 if (!(pwndChild = ValidateHwndNoErr(*phWnd)))
2724 {
2725 continue;
2726 }
2727
2728 pwndChild = co_WinPosSearchChildren(pwndChild, Point, HitTest, Ignore);
2729
2730 if (pwndChild != NULL)
2731 {
2732 /* We found a window. Don't send any more WM_NCHITTEST messages */
2733 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2734 UserDereferenceObject(ScopeWin);
2735 return pwndChild;
2736 }
2737 }
2738 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2739 }
2740 UserDereferenceObject(ScopeWin);
2741 }
2742
2743 if (ScopeWin->head.pti == PsGetCurrentThreadWin32Thread())
2744 {
2745 *HitTest = (USHORT)co_IntSendMessage(ScopeWin->head.h, WM_NCHITTEST, 0, MAKELONG(Point->x, Point->y));
2746
2747 if ((*HitTest) == (USHORT)HTTRANSPARENT)
2748 {
2749 return NULL;
2750 }
2751 }
2752 else
2753 {
2754 if (*HitTest == HTNOWHERE && pwndChild == NULL) *HitTest = HTCLIENT;
2755 }
2756
2757 return ScopeWin;
2758 }
2759
2760 PWND APIENTRY
2761 co_WinPosWindowFromPoint(
2762 IN PWND ScopeWin,
2763 IN POINT *WinPoint,
2764 IN OUT USHORT* HitTest,
2765 IN BOOL Ignore)
2766 {
2767 PWND Window;
2768 POINT Point = *WinPoint;
2769 USER_REFERENCE_ENTRY Ref;
2770
2771 if( ScopeWin == NULL )
2772 {
2773 ScopeWin = UserGetDesktopWindow();
2774 if(ScopeWin == NULL)
2775 return NULL;
2776 }
2777
2778 *HitTest = HTNOWHERE;
2779
2780 ASSERT_REFS_CO(ScopeWin);
2781 UserRefObjectCo(ScopeWin, &Ref);
2782
2783 Window = co_WinPosSearchChildren(ScopeWin, &Point, HitTest, Ignore);
2784
2785 UserDerefObjectCo(ScopeWin);
2786 if (Window)
2787 ASSERT_REFS_CO(Window);
2788 ASSERT_REFS_CO(ScopeWin);
2789
2790 return Window;
2791 }
2792
2793 PWND FASTCALL
2794 IntRealChildWindowFromPoint(PWND Parent, LONG x, LONG y)
2795 {
2796 POINTL Pt;
2797 HWND *List, *phWnd;
2798 PWND pwndHit = NULL;
2799
2800 Pt.x = x;
2801 Pt.y = y;
2802
2803 if (!UserIsDesktopWindow(Parent))
2804 {
2805 Pt.x += Parent->rcClient.left;
2806 Pt.y += Parent->rcClient.top;
2807 }
2808
2809 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2810
2811 if ((List = IntWinListChildren(Parent)))
2812 {
2813 for (phWnd = List; *phWnd; phWnd++)
2814 {
2815 PWND Child;
2816 if ((Child = ValidateHwndNoErr(*phWnd)))
2817 {
2818 if ( Child->style & WS_VISIBLE && IntPtInWindow(Child, Pt.x, Pt.y) )
2819 {
2820 if ( Child->pcls->atomClassName != gpsi->atomSysClass[ICLS_BUTTON] ||
2821 (Child->style & BS_TYPEMASK) != BS_GROUPBOX )
2822 {
2823 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2824 return Child;
2825 }
2826 pwndHit = Child;
2827 }
2828 }
2829 }
2830 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2831 }
2832 return pwndHit ? pwndHit : Parent;
2833 }
2834
2835 PWND APIENTRY
2836 IntChildWindowFromPointEx(PWND Parent, LONG x, LONG y, UINT uiFlags)
2837 {
2838 POINTL Pt;
2839 HWND *List, *phWnd;
2840 PWND pwndHit = NULL;
2841
2842 Pt.x = x;
2843 Pt.y = y;
2844
2845 if (!UserIsDesktopWindow(Parent))
2846 {
2847 if (Parent->ExStyle & WS_EX_LAYOUTRTL)
2848 Pt.x = Parent->rcClient.right - Pt.x;
2849 else
2850 Pt.x += Parent->rcClient.left;
2851 Pt.y += Parent->rcClient.top;
2852 }
2853
2854 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2855
2856 if ((List = IntWinListChildren(Parent)))
2857 {
2858 for (phWnd = List; *phWnd; phWnd++)
2859 {
2860 PWND Child;
2861 if ((Child = ValidateHwndNoErr(*phWnd)))
2862 {
2863 if (uiFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
2864 {
2865 if (!(Child->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE)) continue;
2866 if ((Child->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED)) continue;
2867 }
2868
2869 if (uiFlags & CWP_SKIPTRANSPARENT)
2870 {
2871 if (Child->ExStyle & WS_EX_TRANSPARENT) continue;
2872 }
2873
2874 if (IntPtInWindow(Child, Pt.x, Pt.y))
2875 {
2876 pwndHit = Child;
2877 break;
2878 }
2879 }
2880 }
2881 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2882 }
2883 return pwndHit ? pwndHit : Parent;
2884 }
2885
2886 HDWP
2887 FASTCALL
2888 IntDeferWindowPos( HDWP hdwp,
2889 HWND hwnd,
2890 HWND hwndAfter,
2891 INT x,
2892 INT y,
2893 INT cx,
2894 INT cy,
2895 UINT flags )
2896 {
2897 PSMWP pDWP;
2898 int i;
2899 HDWP retvalue = hdwp;
2900
2901 TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2902 hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
2903
2904 if (flags & ~(SWP_NOSIZE | SWP_NOMOVE |
2905 SWP_NOZORDER | SWP_NOREDRAW |
2906 SWP_NOACTIVATE | SWP_NOCOPYBITS |
2907 SWP_NOOWNERZORDER|SWP_SHOWWINDOW |
2908 SWP_HIDEWINDOW | SWP_FRAMECHANGED))
2909 {
2910 EngSetLastError(ERROR_INVALID_PARAMETER);
2911 return NULL;
2912 }
2913
2914 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
2915 {
2916 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
2917 return NULL;
2918 }
2919
2920 for (i = 0; i < pDWP->ccvr; i++)
2921 {
2922 if (pDWP->acvr[i].pos.hwnd == hwnd)
2923 {
2924 /* Merge with the other changes */
2925 if (!(flags & SWP_NOZORDER))
2926 {
2927 pDWP->acvr[i].pos.hwndInsertAfter = hwndAfter;
2928 }
2929 if (!(flags & SWP_NOMOVE))
2930 {
2931 pDWP->acvr[i].pos.x = x;
2932 pDWP->acvr[i].pos.y = y;
2933 }
2934 if (!(flags & SWP_NOSIZE))
2935 {
2936 pDWP->acvr[i].pos.cx = cx;
2937 pDWP->acvr[i].pos.cy = cy;
2938 }
2939 pDWP->acvr[i].pos.flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
2940 SWP_NOZORDER | SWP_NOREDRAW |
2941 SWP_NOACTIVATE | SWP_NOCOPYBITS|
2942 SWP_NOOWNERZORDER);
2943 pDWP->acvr[i].pos.flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
2944 SWP_FRAMECHANGED);
2945 goto END;
2946 }
2947 }
2948 if (pDWP->ccvr >= pDWP->ccvrAlloc)
2949 {
2950 PCVR newpos = ExAllocatePoolWithTag(PagedPool, pDWP->ccvrAlloc * 2 * sizeof(CVR), USERTAG_SWP);
2951 if (!newpos)
2952 {
2953 retvalue = NULL;
2954 goto END;
2955 }
2956 RtlZeroMemory(newpos, pDWP->ccvrAlloc * 2 * sizeof(CVR));
2957 RtlCopyMemory(newpos, pDWP->acvr, pDWP->ccvrAlloc * sizeof(CVR));
2958 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
2959 pDWP->ccvrAlloc *= 2;
2960 pDWP->acvr = newpos;
2961 }
2962 pDWP->acvr[pDWP->ccvr].pos.hwnd = hwnd;
2963 pDWP->acvr[pDWP->ccvr].pos.hwndInsertAfter = hwndAfter;
2964 pDWP->acvr[pDWP->ccvr].pos.x = x;
2965 pDWP->acvr[pDWP->ccvr].pos.y = y;
2966 pDWP->acvr[pDWP->ccvr].pos.cx = cx;
2967 pDWP->acvr[pDWP->ccvr].pos.cy = cy;
2968 pDWP->acvr[pDWP->ccvr].pos.flags = flags;
2969 pDWP->acvr[pDWP->ccvr].hrgnClip = NULL;
2970 pDWP->acvr[pDWP->ccvr].hrgnInterMonitor = NULL;
2971 pDWP->ccvr++;
2972 END:
2973 return retvalue;
2974 }
2975
2976 BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp, BOOL sAsync )
2977 {
2978 PSMWP pDWP;
2979 PCVR winpos;
2980 BOOL res = TRUE;
2981 int i;
2982
2983 TRACE("%p\n", hdwp);
2984
2985 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
2986 {
2987 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
2988 return FALSE;
2989 }
2990
2991 for (i = 0, winpos = pDWP->acvr; res && i < pDWP->ccvr; i++, winpos++)
2992 {
2993 PWND pwnd;
2994 USER_REFERENCE_ENTRY Ref;
2995
2996 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2997 winpos->pos.hwnd, winpos->pos.hwndInsertAfter, winpos->pos.x, winpos->pos.y,
2998 winpos->pos.cx, winpos->pos.cy, winpos->pos.flags);
2999
3000 pwnd = ValidateHwndNoErr(winpos->pos.hwnd);
3001 if (!pwnd)
3002 continue;
3003
3004 UserRefObjectCo(pwnd, &Ref);
3005
3006 if ( sAsync )
3007 {
3008 LRESULT lRes;
3009 PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
3010 if ( ppos )
3011 {
3012 *ppos = winpos->pos;
3013 /* Yes it's a pointer inside Win32k! */
3014 lRes = co_IntSendMessageNoWait( winpos->pos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
3015 /* We handle this the same way as Event Hooks and Hooks. */
3016 if ( !lRes )
3017 {
3018 ExFreePoolWithTag(ppos, USERTAG_SWP);
3019 }
3020 }
3021 }
3022 else
3023 res = co_WinPosSetWindowPos( pwnd,
3024 winpos->pos.hwndInsertAfter,
3025 winpos->pos.x,
3026 winpos->pos.y,
3027 winpos->pos.cx,
3028 winpos->pos.cy,
3029 winpos->pos.flags);
3030
3031 // Hack to pass tests.... Must have some work to do so clear the error.
3032 if (res && (winpos->pos.flags & (SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER)) == SWP_NOZORDER )
3033 EngSetLastError(ERROR_SUCCESS);
3034
3035 UserDerefObjectCo(pwnd);
3036 }
3037 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
3038 UserDereferenceObject(pDWP);
3039 UserDeleteObject(hdwp, TYPE_SETWINDOWPOS);
3040 return res;
3041 }
3042
3043 /*
3044 * @implemented
3045 */
3046 HWND APIENTRY
3047 NtUserChildWindowFromPointEx(HWND hwndParent,
3048 LONG x,
3049 LONG y,
3050 UINT uiFlags)
3051 {
3052 PWND pwndParent;
3053 TRACE("Enter NtUserChildWindowFromPointEx\n");
3054 UserEnterExclusive();
3055 if ((pwndParent = UserGetWindowObject(hwndParent)))
3056 {
3057 pwndParent = IntChildWindowFromPointEx(pwndParent, x, y, uiFlags);
3058 }
3059 UserLeave();
3060 TRACE("Leave NtUserChildWindowFromPointEx\n");
3061 return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
3062 }
3063
3064 /*
3065 * @implemented
3066 */
3067 BOOL APIENTRY
3068 NtUserEndDeferWindowPosEx(HDWP WinPosInfo,
3069 DWORD Unknown1)
3070 {
3071 BOOL Ret;
3072 TRACE("Enter NtUserEndDeferWindowPosEx\n");
3073 UserEnterExclusive();
3074 Ret = IntEndDeferWindowPosEx(WinPosInfo, (BOOL)Unknown1);
3075 TRACE("Leave NtUserEndDeferWindowPosEx, ret=%i\n", Ret);
3076 UserLeave();
3077 return Ret;
3078 }
3079
3080 /*
3081 * @implemented
3082 */
3083 HDWP APIENTRY
3084 NtUserDeferWindowPos(HDWP WinPosInfo,
3085 HWND Wnd,
3086 HWND WndInsertAfter,
3087 int x,
3088 int y,
3089 int cx,
3090 int cy,
3091 UINT Flags)
3092 {
3093 PWND pWnd, pWndIA;
3094 HDWP Ret = NULL;
3095 UINT Tmp = ~(SWP_ASYNCWINDOWPOS|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_NOREPOSITION|
3096 SWP_NOCOPYBITS|SWP_HIDEWINDOW|SWP_SHOWWINDOW|SWP_FRAMECHANGED|
3097 SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE);
3098
3099 TRACE("Enter NtUserDeferWindowPos\n");
3100 UserEnterExclusive();
3101
3102 if ( Flags & Tmp )
3103 {
3104 EngSetLastError(ERROR_INVALID_FLAGS);
3105 goto Exit;
3106 }
3107
3108 pWnd = UserGetWindowObject(Wnd);
3109 if (!pWnd || UserIsDesktopWindow(pWnd) || UserIsMessageWindow(pWnd))
3110 {
3111 goto Exit;
3112 }
3113
3114 if ( WndInsertAfter &&
3115 WndInsertAfter != HWND_BOTTOM &&
3116 WndInsertAfter != HWND_TOPMOST &&
3117 WndInsertAfter != HWND_NOTOPMOST )
3118 {
3119 pWndIA = UserGetWindowObject(WndInsertAfter);
3120 if (!pWndIA || UserIsDesktopWindow(pWndIA) || UserIsMessageWindow(pWndIA))
3121 {
3122 goto Exit;
3123 }
3124 }
3125
3126 Ret = IntDeferWindowPos(WinPosInfo, Wnd, WndInsertAfter, x, y, cx, cy, Flags);
3127
3128 Exit:
3129 TRACE("Leave NtUserDeferWindowPos, ret=%p\n", Ret);
3130 UserLeave();
3131 return Ret;
3132 }
3133
3134 /*
3135 * @implemented
3136 */
3137 DWORD APIENTRY
3138 NtUserGetInternalWindowPos( HWND hWnd,
3139 LPRECT rectWnd,
3140 LPPOINT ptIcon)
3141 {
3142 PWND Window;
3143 DWORD Ret = 0;
3144 BOOL Hit = FALSE;
3145 WINDOWPLACEMENT wndpl;
3146
3147 UserEnterShared();
3148
3149 if (!(Window = UserGetWindowObject(hWnd)))
3150 {
3151 Hit = FALSE;
3152 goto Exit;
3153 }
3154
3155 _SEH2_TRY
3156 {
3157 if(rectWnd)
3158 {
3159 ProbeForWrite(rectWnd,
3160 sizeof(RECT),
3161 1);
3162 }
3163 if(ptIcon)
3164 {
3165 ProbeForWrite(ptIcon,
3166 sizeof(POINT),
3167 1);
3168 }
3169
3170 }
3171 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3172 {
3173 SetLastNtError(_SEH2_GetExceptionCode());
3174 Hit = TRUE;
3175 }
3176 _SEH2_END;
3177
3178 wndpl.length = sizeof(WINDOWPLACEMENT);
3179
3180 if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
3181 {
3182 _SEH2_TRY
3183 {
3184 if (rectWnd)
3185 {
3186 RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));
3187 }
3188 if (ptIcon)
3189 {
3190 RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT));
3191 }
3192
3193 }
3194 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3195 {
3196 SetLastNtError(_SEH2_GetExceptionCode());
3197 Hit = TRUE;
3198 }
3199 _SEH2_END;
3200
3201 if (!Hit) Ret = wndpl.showCmd;
3202 }
3203 Exit:
3204 UserLeave();
3205 return Ret;
3206 }
3207
3208 /*
3209 * @implemented
3210 */
3211 BOOL APIENTRY
3212 NtUserGetWindowPlacement(HWND hWnd,
3213 WINDOWPLACEMENT *lpwndpl)
3214 {
3215 PWND Wnd;
3216 WINDOWPLACEMENT Safepl;
3217 NTSTATUS Status;
3218 DECLARE_RETURN(BOOL);
3219
3220 TRACE("Enter NtUserGetWindowPlacement\n");
3221 UserEnterShared();
3222
3223 if (!(Wnd = UserGetWindowObject(hWnd)))
3224 {
3225 RETURN( FALSE);
3226 }
3227
3228 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3229 if (!NT_SUCCESS(Status))
3230 {