2083526ee3bc9ed622b0db6d303fc65238c1ab02
[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|WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE)
892 Border += 1; /* for the outer frame always present */
893 if ((ExStyle & WS_EX_CLIENTEDGE) && WithClient)
894 Border += 2;
895 if (Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME)
896 Border ++; /* The other border */
897 Size->cx = Size->cy = Border;
898 if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE)) /* The resize border */
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 //
908 // Fix CORE-5177
909 // See winetests:user32:win.c:wine_AdjustWindowRectEx,
910 // Simplified version.
911 //
912 DWORD IntGetWindowBorders(DWORD Style, DWORD ExStyle)
913 {
914 DWORD adjust = 0;
915
916 if ( ExStyle & WS_EX_WINDOWEDGE ) // 1st
917 adjust = 2; /* outer */
918 else if ( ExStyle & WS_EX_STATICEDGE ) // 2nd
919 adjust = 1; /* for the outer frame always present */
920
921 if (ExStyle & WS_EX_CLIENTEDGE)
922 adjust += 2;
923
924 if ( Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME )
925 adjust++; /* The other border */
926
927 return adjust;
928 }
929
930 UINT FASTCALL
931 co_WinPosGetMinMaxInfo(PWND Window, POINT* MaxSize, POINT* MaxPos,
932 POINT* MinTrack, POINT* MaxTrack)
933 {
934 MINMAXINFO MinMax;
935 PMONITOR monitor;
936 INT xinc, yinc;
937 LONG style = Window->style;
938 LONG adjustedStyle;
939 LONG exstyle = Window->ExStyle;
940 RECT rc;
941 DWORD adjust;
942
943 ASSERT_REFS_CO(Window);
944
945 /* Compute default values */
946
947 rc = Window->rcWindow;
948 MinMax.ptReserved.x = rc.left;
949 MinMax.ptReserved.y = rc.top;
950
951 if ((style & WS_CAPTION) == WS_CAPTION)
952 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
953 else
954 adjustedStyle = style;
955
956 if (Window->spwndParent)
957 IntGetClientRect(Window->spwndParent, &rc);
958
959 adjust = IntGetWindowBorders(adjustedStyle, exstyle);
960
961 xinc = yinc = adjust;
962
963 if ((adjustedStyle & WS_THICKFRAME) && (adjustedStyle & WS_CHILD) && !(adjustedStyle & WS_MINIMIZE))
964 {
965 xinc += UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME);
966 yinc += UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME);
967 }
968
969 RECTL_vInflateRect( &rc,
970 xinc * UserGetSystemMetrics(SM_CXBORDER),
971 yinc * UserGetSystemMetrics(SM_CYBORDER) );
972
973 xinc = -rc.left;
974 yinc = -rc.top;
975
976 MinMax.ptMaxSize.x = rc.right - rc.left;
977 MinMax.ptMaxSize.y = rc.bottom - rc.top;
978 if (style & (WS_DLGFRAME | WS_BORDER))
979 {
980 MinMax.ptMinTrackSize.x = UserGetSystemMetrics(SM_CXMINTRACK);
981 MinMax.ptMinTrackSize.y = UserGetSystemMetrics(SM_CYMINTRACK);
982 }
983 else
984 {
985 MinMax.ptMinTrackSize.x = 2 * xinc;
986 MinMax.ptMinTrackSize.y = 2 * yinc;
987 }
988 MinMax.ptMaxTrackSize.x = UserGetSystemMetrics(SM_CXMAXTRACK);
989 MinMax.ptMaxTrackSize.y = UserGetSystemMetrics(SM_CYMAXTRACK);
990 MinMax.ptMaxPosition.x = -xinc;
991 MinMax.ptMaxPosition.y = -yinc;
992
993 if (!EMPTYPOINT(Window->InternalPos.MaxPos)) MinMax.ptMaxPosition = Window->InternalPos.MaxPos;
994
995 co_IntSendMessage(Window->head.h, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax);
996
997 /* if the app didn't change the values, adapt them for the current monitor */
998 if ((monitor = UserGetPrimaryMonitor()))
999 {
1000 RECT rc_work;
1001
1002 rc_work = monitor->rcMonitor;
1003
1004 if (style & WS_MAXIMIZEBOX)
1005 {
1006 if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP)))
1007 rc_work = monitor->rcWork;
1008 }
1009
1010 if (MinMax.ptMaxSize.x == UserGetSystemMetrics(SM_CXSCREEN) + 2 * xinc &&
1011 MinMax.ptMaxSize.y == UserGetSystemMetrics(SM_CYSCREEN) + 2 * yinc)
1012 {
1013 MinMax.ptMaxSize.x = (rc_work.right - rc_work.left) + 2 * xinc;
1014 MinMax.ptMaxSize.y = (rc_work.bottom - rc_work.top) + 2 * yinc;
1015 }
1016 if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc)
1017 {
1018 MinMax.ptMaxPosition.x = rc_work.left - xinc;
1019 MinMax.ptMaxPosition.y = rc_work.top - yinc;
1020 }
1021 if (MinMax.ptMaxSize.x >= (monitor->rcMonitor.right - monitor->rcMonitor.left) &&
1022 MinMax.ptMaxSize.y >= (monitor->rcMonitor.bottom - monitor->rcMonitor.top) )
1023 {
1024 Window->state |= WNDS_MAXIMIZESTOMONITOR;
1025 }
1026 else
1027 Window->state &= ~WNDS_MAXIMIZESTOMONITOR;
1028 }
1029
1030
1031 MinMax.ptMaxTrackSize.x = max(MinMax.ptMaxTrackSize.x,
1032 MinMax.ptMinTrackSize.x);
1033 MinMax.ptMaxTrackSize.y = max(MinMax.ptMaxTrackSize.y,
1034 MinMax.ptMinTrackSize.y);
1035
1036 if (MaxSize)
1037 *MaxSize = MinMax.ptMaxSize;
1038 if (MaxPos)
1039 *MaxPos = MinMax.ptMaxPosition;
1040 if (MinTrack)
1041 *MinTrack = MinMax.ptMinTrackSize;
1042 if (MaxTrack)
1043 *MaxTrack = MinMax.ptMaxTrackSize;
1044
1045 return 0; // FIXME: What does it return? Wine returns MINMAXINFO.
1046 }
1047
1048 static
1049 BOOL
1050 IntValidateParent(PWND Child, PREGION ValidateRgn)
1051 {
1052 PWND ParentWnd = Child;
1053
1054 if (ParentWnd->style & WS_CHILD)
1055 {
1056 do
1057 ParentWnd = ParentWnd->spwndParent;
1058 while (ParentWnd->style & WS_CHILD);
1059 }
1060
1061 ParentWnd = Child->spwndParent;
1062 while (ParentWnd)
1063 {
1064 if (ParentWnd->style & WS_CLIPCHILDREN)
1065 break;
1066
1067 if (ParentWnd->hrgnUpdate != 0)
1068 {
1069 IntInvalidateWindows( ParentWnd,
1070 ValidateRgn,
1071 RDW_VALIDATE | RDW_NOCHILDREN);
1072 }
1073
1074 ParentWnd = ParentWnd->spwndParent;
1075 }
1076
1077 return TRUE;
1078 }
1079
1080 static
1081 VOID FASTCALL
1082 FixClientRect(PRECTL ClientRect, PRECTL WindowRect)
1083 {
1084 if (ClientRect->left < WindowRect->left)
1085 {
1086 ClientRect->left = WindowRect->left;
1087 }
1088 else if (WindowRect->right < ClientRect->left)
1089 {
1090 ClientRect->left = WindowRect->right;
1091 }
1092 if (ClientRect->right < WindowRect->left)
1093 {
1094 ClientRect->right = WindowRect->left;
1095 }
1096 else if (WindowRect->right < ClientRect->right)
1097 {
1098 ClientRect->right = WindowRect->right;
1099 }
1100 if (ClientRect->top < WindowRect->top)
1101 {
1102 ClientRect->top = WindowRect->top;
1103 }
1104 else if (WindowRect->bottom < ClientRect->top)
1105 {
1106 ClientRect->top = WindowRect->bottom;
1107 }
1108 if (ClientRect->bottom < WindowRect->top)
1109 {
1110 ClientRect->bottom = WindowRect->top;
1111 }
1112 else if (WindowRect->bottom < ClientRect->bottom)
1113 {
1114 ClientRect->bottom = WindowRect->bottom;
1115 }
1116 }
1117 /***********************************************************************
1118 * get_valid_rects
1119 *
1120 * Compute the valid rects from the old and new client rect and WVR_* flags.
1121 * Helper for WM_NCCALCSIZE handling.
1122 */
1123 static
1124 VOID FASTCALL
1125 get_valid_rects( RECTL *old_client, RECTL *new_client, UINT flags, RECTL *valid )
1126 {
1127 int cx, cy;
1128
1129 if (flags & WVR_REDRAW)
1130 {
1131 RECTL_vSetEmptyRect( &valid[0] );
1132 RECTL_vSetEmptyRect( &valid[1] );
1133 return;
1134 }
1135
1136 if (flags & WVR_VALIDRECTS)
1137 {
1138 if (!RECTL_bIntersectRect( &valid[0], &valid[0], new_client ) ||
1139 !RECTL_bIntersectRect( &valid[1], &valid[1], old_client ))
1140 {
1141 RECTL_vSetEmptyRect( &valid[0] );
1142 RECTL_vSetEmptyRect( &valid[1] );
1143 return;
1144 }
1145 flags = WVR_ALIGNLEFT | WVR_ALIGNTOP;
1146 }
1147 else
1148 {
1149 valid[0] = *new_client;
1150 valid[1] = *old_client;
1151 }
1152
1153 /* make sure the rectangles have the same size */
1154 cx = min( valid[0].right - valid[0].left, valid[1].right - valid[1].left );
1155 cy = min( valid[0].bottom - valid[0].top, valid[1].bottom - valid[1].top );
1156
1157 if (flags & WVR_ALIGNBOTTOM)
1158 {
1159 valid[0].top = valid[0].bottom - cy;
1160 valid[1].top = valid[1].bottom - cy;
1161 }
1162 else
1163 {
1164 valid[0].bottom = valid[0].top + cy;
1165 valid[1].bottom = valid[1].top + cy;
1166 }
1167 if (flags & WVR_ALIGNRIGHT)
1168 {
1169 valid[0].left = valid[0].right - cx;
1170 valid[1].left = valid[1].right - cx;
1171 }
1172 else
1173 {
1174 valid[0].right = valid[0].left + cx;
1175 valid[1].right = valid[1].left + cx;
1176 }
1177 }
1178
1179 static
1180 LONG FASTCALL
1181 co_WinPosDoNCCALCSize(PWND Window, PWINDOWPOS WinPos, RECTL* WindowRect, RECTL* ClientRect, RECTL* validRects)
1182 {
1183 PWND Parent;
1184 UINT wvrFlags = 0;
1185
1186 ASSERT_REFS_CO(Window);
1187
1188 /* Send WM_NCCALCSIZE message to get new client area */
1189 if ((WinPos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE)
1190 {
1191 NCCALCSIZE_PARAMS params;
1192 WINDOWPOS winposCopy;
1193
1194 params.rgrc[0] = *WindowRect; // new coordinates of a window that has been moved or resized
1195 params.rgrc[1] = Window->rcWindow; // window before it was moved or resized
1196 params.rgrc[2] = Window->rcClient; // client area before the window was moved or resized
1197
1198 Parent = Window->spwndParent;
1199 if (0 != (Window->style & WS_CHILD) && Parent)
1200 {
1201 RECTL_vOffsetRect(&(params.rgrc[0]), - Parent->rcClient.left, - Parent->rcClient.top);
1202 RECTL_vOffsetRect(&(params.rgrc[1]), - Parent->rcClient.left, - Parent->rcClient.top);
1203 RECTL_vOffsetRect(&(params.rgrc[2]), - Parent->rcClient.left, - Parent->rcClient.top);
1204 }
1205
1206 params.lppos = &winposCopy;
1207 winposCopy = *WinPos;
1208
1209 wvrFlags = co_IntSendMessage(Window->head.h, WM_NCCALCSIZE, TRUE, (LPARAM) &params);
1210
1211 /* If the application send back garbage, ignore it */
1212 if (params.rgrc[0].left <= params.rgrc[0].right &&
1213 params.rgrc[0].top <= params.rgrc[0].bottom)
1214 {
1215 *ClientRect = params.rgrc[0]; // First rectangle contains the coordinates of the new client rectangle resulting from the move or resize
1216 if ((Window->style & WS_CHILD) && Parent)
1217 {
1218 RECTL_vOffsetRect(ClientRect, Parent->rcClient.left, Parent->rcClient.top);
1219 }
1220 FixClientRect(ClientRect, WindowRect);
1221 }
1222
1223 if (ClientRect->left != Window->rcClient.left ||
1224 ClientRect->top != Window->rcClient.top)
1225 {
1226 WinPos->flags &= ~SWP_NOCLIENTMOVE;
1227 }
1228
1229 if (ClientRect->right - ClientRect->left != Window->rcClient.right - Window->rcClient.left)
1230 {
1231 WinPos->flags &= ~SWP_NOCLIENTSIZE;
1232 }
1233 else
1234 wvrFlags &= ~WVR_HREDRAW;
1235
1236 if (ClientRect->bottom - ClientRect->top != Window->rcClient.bottom - Window->rcClient.top)
1237 {
1238 WinPos->flags &= ~SWP_NOCLIENTSIZE;
1239 }
1240 else
1241 wvrFlags &= ~WVR_VREDRAW;
1242
1243 validRects[0] = params.rgrc[1]; // second rectangle contains the valid destination rectangle
1244 validRects[1] = params.rgrc[2]; // third rectangle contains the valid source rectangle
1245 }
1246 else
1247 {
1248 if (!(WinPos->flags & SWP_NOMOVE) &&
1249 (ClientRect->left != Window->rcClient.left ||
1250 ClientRect->top != Window->rcClient.top))
1251 {
1252 WinPos->flags &= ~SWP_NOCLIENTMOVE;
1253 }
1254 }
1255
1256 if (WinPos->flags & (SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_HIDEWINDOW))
1257 {
1258 RECTL_vSetEmptyRect( &validRects[0] );
1259 RECTL_vSetEmptyRect( &validRects[1] );
1260 }
1261 else get_valid_rects( &Window->rcClient, ClientRect, wvrFlags, validRects );
1262
1263 return wvrFlags;
1264 }
1265
1266 static
1267 BOOL FASTCALL
1268 co_WinPosDoWinPosChanging(PWND Window,
1269 PWINDOWPOS WinPos,
1270 PRECTL WindowRect,
1271 PRECTL ClientRect)
1272 {
1273 ASSERT_REFS_CO(Window);
1274
1275 /* Send WM_WINDOWPOSCHANGING message */
1276
1277 if (!(WinPos->flags & SWP_NOSENDCHANGING)
1278 && !((WinPos->flags & SWP_AGG_NOCLIENTCHANGE) && (WinPos->flags & SWP_SHOWWINDOW)))
1279 {
1280 TRACE("Sending WM_WINDOWPOSCHANGING to hwnd %p flags %04x.\n", Window->head.h,WinPos->flags);
1281 co_IntSendMessage(Window->head.h, WM_WINDOWPOSCHANGING, 0, (LPARAM) WinPos);
1282 }
1283
1284 /* Calculate new position and size */
1285
1286 *WindowRect = Window->rcWindow;
1287 *ClientRect = (Window->style & WS_MINIMIZE) ? Window->rcWindow : Window->rcClient;
1288
1289 if (!(WinPos->flags & SWP_NOSIZE))
1290 {
1291 if (Window->style & WS_MINIMIZE)
1292 {
1293 WindowRect->right = WindowRect->left + UserGetSystemMetrics(SM_CXMINIMIZED);
1294 WindowRect->bottom = WindowRect->top + UserGetSystemMetrics(SM_CYMINIMIZED);
1295 }
1296 else
1297 {
1298 WindowRect->right = WindowRect->left + WinPos->cx;
1299 WindowRect->bottom = WindowRect->top + WinPos->cy;
1300 }
1301 }
1302
1303 if (!(WinPos->flags & SWP_NOMOVE))
1304 {
1305 INT X, Y;
1306 PWND Parent;
1307 X = WinPos->x;
1308 Y = WinPos->y;
1309
1310 Parent = Window->spwndParent;
1311
1312 // Parent child position issue is in here. SetParent_W7 test CORE-6651.
1313 if (//((Window->style & WS_CHILD) != 0) && <- Fixes wine msg test_SetParent: "rects do not match", the last test.
1314 Parent &&
1315 Parent != Window->head.rpdesk->pDeskInfo->spwnd)
1316 {
1317 TRACE("Not SWP_NOMOVE 1 Parent client offset X %d Y %d\n",X,Y);
1318 X += Parent->rcClient.left;
1319 Y += Parent->rcClient.top;
1320 TRACE("Not SWP_NOMOVE 2 Parent client offset X %d Y %d\n",X,Y);
1321 }
1322
1323 WindowRect->left = X;
1324 WindowRect->top = Y;
1325 WindowRect->right += X - Window->rcWindow.left;
1326 WindowRect->bottom += Y - Window->rcWindow.top;
1327
1328 RECTL_vOffsetRect(ClientRect, X - Window->rcWindow.left,
1329 Y - Window->rcWindow.top);
1330 }
1331 WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
1332
1333 TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
1334 WinPos->hwnd, WinPos->hwndInsertAfter, WinPos->x, WinPos->y,
1335 WinPos->cx, WinPos->cy, WinPos->flags );
1336 TRACE("WindowRect: %d %d %d %d\n", WindowRect->left,WindowRect->top,WindowRect->right,WindowRect->bottom);
1337 TRACE("ClientRect: %d %d %d %d\n", ClientRect->left,ClientRect->top,ClientRect->right,ClientRect->bottom);
1338
1339 return TRUE;
1340 }
1341
1342 /*
1343 * Fix Z order taking into account owned popups -
1344 * basically we need to maintain them above the window that owns them
1345 *
1346 * FIXME: hide/show owned popups when owner visibility changes.
1347 *
1348 * ReactOS: See bug CORE-6129 and CORE-6554.
1349 *
1350 */
1351 ////
1352 // Pass all the win:test_children/popup_zorder tests except "move hwnd_F and its popups down" which is if'ed out.
1353 // Side effect, breaks more of the DeferWindowPos api tests, but wine breaks more!!!!
1354 static
1355 HWND FASTCALL
1356 WinPosDoOwnedPopups(PWND Window, HWND hWndInsertAfter)
1357 {
1358 HWND *List = NULL;
1359 HWND Owner;
1360 LONG Style;
1361 PWND DesktopWindow, ChildObject;
1362 int i;
1363
1364 TRACE("(%p) hInsertAfter = %p\n", Window, hWndInsertAfter );
1365
1366 Style = Window->style;
1367
1368 if (Style & WS_CHILD)
1369 {
1370 TRACE("Window is child\n");
1371 return hWndInsertAfter;
1372 }
1373
1374 Owner = Window->spwndOwner ? Window->spwndOwner->head.h : NULL;
1375
1376 if (Owner)
1377 {
1378 /* Make sure this popup stays above the owner */
1379
1380 if (hWndInsertAfter != HWND_TOPMOST)
1381 {
1382 DesktopWindow = UserGetDesktopWindow();
1383 List = IntWinListChildren(DesktopWindow);
1384
1385 if (List != NULL)
1386 {
1387 for (i = 0; List[i]; i++)
1388 {
1389 BOOL topmost = FALSE;
1390
1391 ChildObject = ValidateHwndNoErr(List[i]);
1392 if (ChildObject)
1393 {
1394 topmost = (ChildObject->ExStyle & WS_EX_TOPMOST) != 0;
1395 }
1396
1397 if (List[i] == Owner)
1398 {
1399 if (i > 0) hWndInsertAfter = List[i-1];
1400 else hWndInsertAfter = topmost ? HWND_TOPMOST : HWND_TOP;
1401 break;
1402 }
1403
1404 if (hWndInsertAfter == HWND_TOP || hWndInsertAfter == HWND_NOTOPMOST)
1405 {
1406 if (!topmost) break;
1407 }
1408 else if (List[i] == hWndInsertAfter) break;
1409 }
1410 }
1411 else
1412 return hWndInsertAfter;
1413 }
1414 }
1415
1416 if (hWndInsertAfter == HWND_BOTTOM)
1417 {
1418 ERR("Window is HWND_BOTTOM hwnd %p\n",hWndInsertAfter);
1419 if (List) ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1420 goto done;
1421 }
1422
1423 if (!List)
1424 {
1425 DesktopWindow = UserGetDesktopWindow();
1426 List = IntWinListChildren(DesktopWindow);
1427 }
1428
1429 if (List != NULL)
1430 {
1431 i = 0;
1432
1433 if (hWndInsertAfter == HWND_TOP || hWndInsertAfter == HWND_NOTOPMOST)
1434 {
1435 if (hWndInsertAfter == HWND_NOTOPMOST || !(Window->ExStyle & WS_EX_TOPMOST))
1436 {
1437 TRACE("skip all the topmost windows\n");
1438 /* skip all the topmost windows */
1439 while (List[i] &&
1440 (ChildObject = ValidateHwndNoErr(List[i])) &&
1441 (ChildObject->ExStyle & WS_EX_TOPMOST)) i++;
1442 }
1443 }
1444 else if (hWndInsertAfter != HWND_TOPMOST)
1445 {
1446 /* skip windows that are already placed correctly */
1447 for (i = 0; List[i]; i++)
1448 {
1449 if (List[i] == hWndInsertAfter) break;
1450 if (List[i] == UserHMGetHandle(Window))
1451 {
1452 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1453 goto done; /* nothing to do if window is moving backwards in z-order */
1454 }
1455 }
1456 }
1457
1458 for (; List[i]; i++)
1459 {
1460 PWND Wnd;
1461 USER_REFERENCE_ENTRY Ref;
1462
1463 if (List[i] == UserHMGetHandle(Window))
1464 break;
1465
1466 if (!(Wnd = ValidateHwndNoErr(List[i])))
1467 continue;
1468
1469 Owner = Wnd->spwndOwner ? Wnd->spwndOwner->head.h : NULL;
1470
1471 if (Owner != UserHMGetHandle(Window)) continue;
1472
1473 UserRefObjectCo(Wnd, &Ref);
1474 TRACE( "moving %p owned by %p after %p\n", List[i], UserHMGetHandle(Window), hWndInsertAfter );
1475 co_WinPosSetWindowPos(Wnd, hWndInsertAfter, 0, 0, 0, 0,
1476 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING| SWP_DEFERERASE);
1477
1478 UserDerefObjectCo(Wnd);
1479 hWndInsertAfter = List[i];
1480 }
1481 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1482 }
1483 done:
1484 return hWndInsertAfter;
1485 }
1486 ////
1487
1488 /***********************************************************************
1489 * WinPosInternalMoveWindow
1490 *
1491 * Update WindowRect and ClientRect of Window and all of its children
1492 * We keep both WindowRect and ClientRect in screen coordinates internally
1493 */
1494 static
1495 VOID FASTCALL
1496 WinPosInternalMoveWindow(PWND Window, INT MoveX, INT MoveY)
1497 {
1498 PWND Child;
1499
1500 ASSERT(Window != Window->spwndChild);
1501 TRACE("InternalMoveWin X %d Y %d\n", MoveX, MoveY);
1502
1503 Window->rcWindow.left += MoveX;
1504 Window->rcWindow.right += MoveX;
1505 Window->rcWindow.top += MoveY;
1506 Window->rcWindow.bottom += MoveY;
1507
1508 Window->rcClient.left += MoveX;
1509 Window->rcClient.right += MoveX;
1510 Window->rcClient.top += MoveY;
1511 Window->rcClient.bottom += MoveY;
1512
1513 for(Child = Window->spwndChild; Child; Child = Child->spwndNext)
1514 {
1515 WinPosInternalMoveWindow(Child, MoveX, MoveY);
1516 }
1517 }
1518
1519 /*
1520 * WinPosFixupSWPFlags
1521 *
1522 * Fix redundant flags and values in the WINDOWPOS structure.
1523 */
1524 static
1525 BOOL FASTCALL
1526 WinPosFixupFlags(WINDOWPOS *WinPos, PWND Wnd)
1527 {
1528 PWND Parent;
1529 POINT pt;
1530
1531 /* Finally make sure that all coordinates are valid */
1532 if (WinPos->x < -32768) WinPos->x = -32768;
1533 else if (WinPos->x > 32767) WinPos->x = 32767;
1534 if (WinPos->y < -32768) WinPos->y = -32768;
1535 else if (WinPos->y > 32767) WinPos->y = 32767;
1536
1537 WinPos->cx = max(WinPos->cx, 0);
1538 WinPos->cy = max(WinPos->cy, 0);
1539
1540 Parent = UserGetAncestor( Wnd, GA_PARENT );
1541 if (!IntIsWindowVisible( Parent ) &&
1542 /* Fix B : wine msg test_SetParent:WmSetParentSeq_2:25 wParam bits! */
1543 (WinPos->flags & SWP_AGG_STATUSFLAGS) == SWP_AGG_NOPOSCHANGE) WinPos->flags |= SWP_NOREDRAW;
1544
1545 if (Wnd->style & WS_VISIBLE) WinPos->flags &= ~SWP_SHOWWINDOW;
1546 else
1547 {
1548 WinPos->flags &= ~SWP_HIDEWINDOW;
1549 if (!(WinPos->flags & SWP_SHOWWINDOW)) WinPos->flags |= SWP_NOREDRAW;
1550 }
1551
1552 /* Check for right size */
1553 if (Wnd->rcWindow.right - Wnd->rcWindow.left == WinPos->cx &&
1554 Wnd->rcWindow.bottom - Wnd->rcWindow.top == WinPos->cy)
1555 {
1556 WinPos->flags |= SWP_NOSIZE;
1557 }
1558
1559 pt.x = WinPos->x;
1560 pt.y = WinPos->y;
1561 IntClientToScreen( Parent, &pt );
1562 TRACE("WPFU C2S wpx %d wpy %d ptx %d pty %d\n",WinPos->x,WinPos->y,pt.x,pt.y);
1563 /* Check for right position */
1564 if (Wnd->rcWindow.left == pt.x && Wnd->rcWindow.top == pt.y)
1565 {
1566 //ERR("In right pos\n");
1567 WinPos->flags |= SWP_NOMOVE;
1568 }
1569
1570 if ( WinPos->hwnd != UserGetForegroundWindow() && (Wnd->style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
1571 {
1572 /* Bring to the top when activating */
1573 if (!(WinPos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)) &&
1574 (WinPos->flags & SWP_NOZORDER ||
1575 (WinPos->hwndInsertAfter != HWND_TOPMOST && WinPos->hwndInsertAfter != HWND_NOTOPMOST)))
1576 {
1577 WinPos->flags &= ~SWP_NOZORDER;
1578 WinPos->hwndInsertAfter = (0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP);
1579 }
1580 }
1581
1582 /* Check hwndInsertAfter */
1583 if (!(WinPos->flags & SWP_NOZORDER))
1584 {
1585 /* Fix sign extension */
1586 if (WinPos->hwndInsertAfter == (HWND)0xffff)
1587 {
1588 WinPos->hwndInsertAfter = HWND_TOPMOST;
1589 }
1590 else if (WinPos->hwndInsertAfter == (HWND)0xfffe)
1591 {
1592 WinPos->hwndInsertAfter = HWND_NOTOPMOST;
1593 }
1594
1595 if (WinPos->hwndInsertAfter == HWND_TOP)
1596 {
1597 /* Keep it topmost when it's already topmost */
1598 if ((Wnd->ExStyle & WS_EX_TOPMOST) != 0)
1599 WinPos->hwndInsertAfter = HWND_TOPMOST;
1600
1601 if (IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd)
1602 {
1603 WinPos->flags |= SWP_NOZORDER;
1604 }
1605 }
1606 else if (WinPos->hwndInsertAfter == HWND_BOTTOM)
1607 {
1608 if (!(Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDLAST) == WinPos->hwnd)
1609 WinPos->flags |= SWP_NOZORDER;
1610 }
1611 else if (WinPos->hwndInsertAfter == HWND_TOPMOST)
1612 {
1613 if ((Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd)
1614 WinPos->flags |= SWP_NOZORDER;
1615 }
1616 else if (WinPos->hwndInsertAfter == HWND_NOTOPMOST)
1617 {
1618 if (!(Wnd->ExStyle & WS_EX_TOPMOST))
1619 WinPos->flags |= SWP_NOZORDER;
1620 }
1621 else /* hwndInsertAfter must be a sibling of the window */
1622 {
1623 PWND InsAfterWnd;
1624
1625 InsAfterWnd = ValidateHwndNoErr(WinPos->hwndInsertAfter);
1626 if(!InsAfterWnd)
1627 {
1628 return TRUE;
1629 }
1630
1631 if (InsAfterWnd->spwndParent != Wnd->spwndParent)
1632 {
1633 /* Note from wine User32 Win test_SetWindowPos:
1634 "Returns TRUE also for windows that are not siblings"
1635 "Does not seem to do anything even without passing flags, still returns TRUE"
1636 "Same thing the other way around."
1637 ".. and with these windows."
1638 */
1639 return FALSE;
1640 }
1641 else
1642 {
1643 /*
1644 * We don't need to change the Z order of hwnd if it's already
1645 * inserted after hwndInsertAfter or when inserting hwnd after
1646 * itself.
1647 */
1648 if ((WinPos->hwnd == WinPos->hwndInsertAfter) ||
1649 ((InsAfterWnd->spwndNext) && (WinPos->hwnd == InsAfterWnd->spwndNext->head.h)))
1650 {
1651 WinPos->flags |= SWP_NOZORDER;
1652 }
1653 }
1654 }
1655 }
1656
1657 return TRUE;
1658 }
1659
1660 /* x and y are always screen relative */
1661 BOOLEAN FASTCALL
1662 co_WinPosSetWindowPos(
1663 PWND Window,
1664 HWND WndInsertAfter,
1665 INT x,
1666 INT y,
1667 INT cx,
1668 INT cy,
1669 UINT flags
1670 )
1671 {
1672 WINDOWPOS WinPos;
1673 RECTL NewWindowRect;
1674 RECTL NewClientRect;
1675 RECTL valid_rects[2];
1676 PREGION VisBefore = NULL;
1677 PREGION VisBeforeJustClient = NULL;
1678 PREGION VisAfter = NULL;
1679 PREGION CopyRgn = NULL;
1680 ULONG WvrFlags = 0;
1681 RECTL OldWindowRect, OldClientRect;
1682 int RgnType;
1683 HDC Dc;
1684 RECTL CopyRect;
1685 PWND Ancestor;
1686 BOOL bPointerInWindow, PosChanged = FALSE;
1687 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1688
1689 ASSERT_REFS_CO(Window);
1690
1691 TRACE("pwnd %p, after %p, %d,%d (%dx%d), flags %s",
1692 Window, WndInsertAfter, x, y, cx, cy, flags);
1693 #if DBG
1694 dump_winpos_flags(flags);
1695 #endif
1696
1697 /* FIXME: Get current active window from active queue. Why? since r2915. */
1698
1699 bPointerInWindow = IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y);
1700
1701 WinPos.hwnd = Window->head.h;
1702 WinPos.hwndInsertAfter = WndInsertAfter;
1703 WinPos.x = x;
1704 WinPos.y = y;
1705 WinPos.cx = cx;
1706 WinPos.cy = cy;
1707 WinPos.flags = flags;
1708
1709 if ( flags & SWP_ASYNCWINDOWPOS )
1710 {
1711 LRESULT lRes;
1712 PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
1713 if ( ppos )
1714 {
1715 WinPos.flags &= ~SWP_ASYNCWINDOWPOS; // Clear flag.
1716 *ppos = WinPos;
1717 /* Yes it's a pointer inside Win32k! */
1718 lRes = co_IntSendMessageNoWait( WinPos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
1719 /* We handle this the same way as Event Hooks and Hooks. */
1720 if ( !lRes )
1721 {
1722 ExFreePoolWithTag(ppos, USERTAG_SWP);
1723 return FALSE;
1724 }
1725 return TRUE;
1726 }
1727 return FALSE;
1728 }
1729
1730 co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
1731
1732 /* Does the window still exist? */
1733 if (!IntIsWindow(WinPos.hwnd))
1734 {
1735 TRACE("WinPosSetWindowPos: Invalid handle 0x%p!\n",WinPos.hwnd);
1736 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
1737 return FALSE;
1738 }
1739
1740 /* Fix up the flags. */
1741 if (!WinPosFixupFlags(&WinPos, Window))
1742 {
1743 // See Note.
1744 return TRUE;
1745 }
1746
1747 Ancestor = UserGetAncestor(Window, GA_PARENT);
1748 if ( (WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER &&
1749 Ancestor && Ancestor->head.h == IntGetDesktopWindow() )
1750 {
1751 WinPos.hwndInsertAfter = WinPosDoOwnedPopups(Window, WinPos.hwndInsertAfter);
1752 }
1753
1754 if (!(WinPos.flags & SWP_NOREDRAW))
1755 {
1756 /* Compute the visible region before the window position is changed */
1757 if (!(WinPos.flags & SWP_SHOWWINDOW) &&
1758 (WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
1759 SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
1760 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
1761 {
1762 VisBefore = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1763 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1764
1765 if ( VisBefore != NULL &&
1766 REGION_Complexity(VisBefore) == NULLREGION )
1767 {
1768 REGION_Delete(VisBefore);
1769 VisBefore = NULL;
1770 }
1771 else if(VisBefore)
1772 {
1773 REGION_bOffsetRgn(VisBefore, -Window->rcWindow.left, -Window->rcWindow.top);
1774 }
1775
1776 /* Calculate the non client area for resizes, as this is used in the copy region */
1777 if (!(WinPos.flags & SWP_NOSIZE))
1778 {
1779 VisBeforeJustClient = VIS_ComputeVisibleRegion(Window, TRUE, FALSE,
1780 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1781
1782 if ( VisBeforeJustClient != NULL &&
1783 REGION_Complexity(VisBeforeJustClient) == NULLREGION )
1784 {
1785 REGION_Delete(VisBeforeJustClient);
1786 VisBeforeJustClient = NULL;
1787 }
1788 else if(VisBeforeJustClient)
1789 {
1790 REGION_bOffsetRgn(VisBeforeJustClient, -Window->rcWindow.left, -Window->rcWindow.top);
1791 }
1792 }
1793 }
1794 }
1795
1796 //// HACK 3
1797 if (Window->hrgnNewFrame)
1798 {
1799 SelectWindowRgn( Window, Window->hrgnNewFrame ); // Should be PSMWP->acvr->hrgnClip
1800 Window->hrgnNewFrame = NULL;
1801 }
1802
1803 WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect, valid_rects);
1804
1805 // ERR("co_WinPosDoNCCALCSize returned 0x%x\n valid dest: %d %d %d %d\n valid src : %d %d %d %d\n", WvrFlags,
1806 // valid_rects[0].left,valid_rects[0].top,valid_rects[0].right,valid_rects[0].bottom,
1807 // valid_rects[1].left,valid_rects[1].top,valid_rects[1].right,valid_rects[1].bottom);
1808
1809 /* Validate link windows. (also take into account shell window in hwndShellWindow) */
1810 if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow())
1811 {
1812 IntLinkHwnd(Window, WinPos.hwndInsertAfter);
1813 }
1814
1815 OldWindowRect = Window->rcWindow;
1816 OldClientRect = Window->rcClient;
1817
1818 if (NewClientRect.left != OldClientRect.left ||
1819 NewClientRect.top != OldClientRect.top)
1820 {
1821 // Move child window if their parent is moved. Keep Child window relative to Parent...
1822 WinPosInternalMoveWindow(Window,
1823 NewClientRect.left - OldClientRect.left,
1824 NewClientRect.top - OldClientRect.top);
1825 PosChanged = TRUE;
1826 }
1827
1828 Window->rcWindow = NewWindowRect;
1829 Window->rcClient = NewClientRect;
1830
1831 /* erase parent when hiding or resizing child */
1832 if (WinPos.flags & SWP_HIDEWINDOW)
1833 {
1834 /* Clear the update region */
1835 co_UserRedrawWindow( Window,
1836 NULL,
1837 0,
1838 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
1839
1840 if (UserIsDesktopWindow(Window->spwndParent))
1841 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM)Window->head.h, 0);
1842
1843 Window->style &= ~WS_VISIBLE; //IntSetStyle( Window, 0, WS_VISIBLE );
1844 Window->head.pti->cVisWindows--;
1845 IntNotifyWinEvent(EVENT_OBJECT_HIDE, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1846 }
1847 else if (WinPos.flags & SWP_SHOWWINDOW)
1848 {
1849 if (UserIsDesktopWindow(Window->spwndParent) &&
1850 Window->spwndOwner == NULL &&
1851 (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
1852 (Window->ExStyle & WS_EX_APPWINDOW)))
1853 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)Window->head.h, 0);
1854
1855 Window->style |= WS_VISIBLE; //IntSetStyle( Window, WS_VISIBLE, 0 );
1856 Window->head.pti->cVisWindows++;
1857 IntNotifyWinEvent(EVENT_OBJECT_SHOW, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1858 }
1859
1860 if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != HRGN_WINDOW)
1861 {
1862 NtGdiOffsetRgn(Window->hrgnUpdate,
1863 NewWindowRect.left - OldWindowRect.left,
1864 NewWindowRect.top - OldWindowRect.top);
1865 }
1866
1867 DceResetActiveDCEs(Window); // For WS_VISIBLE changes.
1868
1869 if (!(WinPos.flags & SWP_NOREDRAW))
1870 {
1871 /* Determine the new visible region */
1872 VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1873 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1874
1875 if ( VisAfter != NULL &&
1876 REGION_Complexity(VisAfter) == NULLREGION )
1877 {
1878 REGION_Delete(VisAfter);
1879 VisAfter = NULL;
1880 }
1881 else if(VisAfter)
1882 {
1883 REGION_bOffsetRgn(VisAfter, -Window->rcWindow.left, -Window->rcWindow.top);
1884 }
1885
1886 /*
1887 * Determine which pixels can be copied from the old window position
1888 * to the new. Those pixels must be visible in both the old and new
1889 * position. Also, check the class style to see if the windows of this
1890 * class need to be completely repainted on (horizontal/vertical) size
1891 * change.
1892 */
1893 if ( ( VisBefore != NULL &&
1894 VisAfter != NULL &&
1895 !(WinPos.flags & SWP_NOCOPYBITS) &&
1896 ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) &&
1897 !(Window->ExStyle & WS_EX_TRANSPARENT) ) ||
1898 ( !PosChanged && (WinPos.flags & SWP_FRAMECHANGED) && VisBefore) )
1899 {
1900
1901 /*
1902 * If this is (also) a window resize, the whole nonclient area
1903 * needs to be repainted. So we limit the copy to the client area,
1904 * 'cause there is no use in copying it (would possibly cause
1905 * "flashing" too). However, if the copy region is already empty,
1906 * we don't have to crop (can't take anything away from an empty
1907 * region...)
1908 */
1909
1910 CopyRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
1911 if (WinPos.flags & SWP_NOSIZE)
1912 RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
1913 else if (VisBeforeJustClient != NULL)
1914 {
1915 RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBeforeJustClient, RGN_AND);
1916 REGION_Delete(VisBeforeJustClient);
1917 }
1918
1919 /* Now use in copying bits which are in the update region. */
1920 if (Window->hrgnUpdate != NULL)
1921 {
1922 PREGION RgnUpdate = REGION_LockRgn(Window->hrgnUpdate);
1923 if (RgnUpdate)
1924 {
1925 REGION_bOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1926 IntGdiCombineRgn(CopyRgn, CopyRgn, RgnUpdate, RGN_DIFF);
1927 REGION_bOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1928 REGION_UnlockRgn(RgnUpdate);
1929 }
1930 }
1931
1932 /*
1933 * Now, get the bounding box of the copy region. If it's empty
1934 * there's nothing to copy. Also, it's no use copying bits onto
1935 * themselves.
1936 */
1937 if (REGION_GetRgnBox(CopyRgn, &CopyRect) == NULLREGION)
1938 {
1939 /* Nothing to copy, clean up */
1940 REGION_Delete(CopyRgn);
1941 CopyRgn = NULL;
1942 }
1943 else if ( OldWindowRect.left != NewWindowRect.left ||
1944 OldWindowRect.top != NewWindowRect.top ||
1945 (WinPos.flags & SWP_FRAMECHANGED) )
1946 {
1947 HRGN DcRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
1948 PREGION DcRgnObj = REGION_LockRgn(DcRgn);
1949
1950 /*
1951 * Small trick here: there is no function to bitblt a region. So
1952 * we set the region as the clipping region, take the bounding box
1953 * of the region and bitblt that. Since nothing outside the clipping
1954 * region is copied, this has the effect of bitblt'ing the region.
1955 *
1956 * Since NtUserGetDCEx takes ownership of the clip region, we need
1957 * to create a copy of CopyRgn and pass that. We need CopyRgn later
1958 */
1959 IntGdiCombineRgn(DcRgnObj, CopyRgn, NULL, RGN_COPY);
1960 REGION_bOffsetRgn(DcRgnObj, NewWindowRect.left, NewWindowRect.top);
1961 REGION_UnlockRgn(DcRgnObj);
1962 Dc = UserGetDCEx( Window,
1963 DcRgn,
1964 DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN); // DCX_WINDOW will set first, go read WinDC.c.
1965 NtGdiBitBlt( Dc,
1966 CopyRect.left, CopyRect.top,
1967 CopyRect.right - CopyRect.left,
1968 CopyRect.bottom - CopyRect.top,
1969 Dc,
1970 CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
1971 CopyRect.top + (OldWindowRect.top - NewWindowRect.top),
1972 SRCCOPY,
1973 0,
1974 0);
1975
1976 UserReleaseDC(Window, Dc, FALSE);
1977 IntValidateParent(Window, CopyRgn);
1978 GreDeleteObject(DcRgn);
1979 }
1980 }
1981 else
1982 {
1983 CopyRgn = NULL;
1984 }
1985
1986 if ( !PosChanged && (WinPos.flags & SWP_FRAMECHANGED) && VisBefore )
1987 {
1988 PWND pwnd = Window;
1989 PWND Parent = pwnd->spwndParent;
1990
1991 TRACE("SWP_FRAMECHANGED no chg\n");
1992
1993 if ( pwnd->style & WS_CHILD ) // Fix ProgMan menu bar drawing.
1994 {
1995 TRACE("SWP_FRAMECHANGED win child %p Parent %p\n",pwnd,Parent);
1996 pwnd = Parent ? Parent : pwnd;
1997 }
1998
1999 if ( !(pwnd->style & WS_CHILD) )
2000 {
2001 HDC hdc;
2002 HRGN DcRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
2003 PREGION DcRgnObj = REGION_LockRgn(DcRgn);
2004
2005 TRACE("SWP_FRAMECHANGED Draw\n");
2006
2007 IntGdiCombineRgn(DcRgnObj, VisBefore, NULL, RGN_COPY);
2008 REGION_UnlockRgn(DcRgnObj);
2009
2010 hdc = UserGetDCEx( pwnd,
2011 DcRgn,
2012 DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN); // DCX_WINDOW, see note above....
2013
2014 NC_DoNCPaint(pwnd, hdc, -1); // Force full redraw of nonclient area.
2015
2016 UserReleaseDC(pwnd, hdc, FALSE);
2017 IntValidateParent(pwnd, DcRgnObj);
2018 GreDeleteObject(DcRgn);
2019 }
2020 }
2021
2022 /* We need to redraw what wasn't visible before */
2023 if (VisAfter != NULL)
2024 {
2025 PREGION DirtyRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
2026 if (DirtyRgn)
2027 {
2028 if (CopyRgn != NULL)
2029 {
2030 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
2031 }
2032 else
2033 {
2034 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
2035 }
2036
2037 if (RgnType != ERROR && RgnType != NULLREGION)
2038 {
2039 /* old code
2040 NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2041 IntInvalidateWindows( Window,
2042 DirtyRgn,
2043 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2044 }
2045 GreDeleteObject(DirtyRgn);
2046 */
2047
2048 PWND Parent = Window->spwndParent;
2049
2050 REGION_bOffsetRgn( DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2051
2052 if ( (Window->style & WS_CHILD) && (Parent) && !(Parent->style & WS_CLIPCHILDREN))
2053 {
2054 IntInvalidateWindows( Parent, DirtyRgn, RDW_ERASE | RDW_INVALIDATE);
2055 co_IntPaintWindows(Parent, RDW_NOCHILDREN, FALSE);
2056 }
2057 else
2058 {
2059 IntInvalidateWindows( Window, DirtyRgn, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2060 }
2061 }
2062 REGION_Delete(DirtyRgn);
2063 }
2064 }
2065
2066 if (CopyRgn != NULL)
2067 {
2068 REGION_Delete(CopyRgn);
2069 }
2070
2071 /* Expose what was covered before but not covered anymore */
2072 if (VisBefore != NULL)
2073 {
2074 PREGION ExposedRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
2075 if (ExposedRgn)
2076 {
2077 RgnType = IntGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
2078 REGION_bOffsetRgn(ExposedRgn,
2079 OldWindowRect.left - NewWindowRect.left,
2080 OldWindowRect.top - NewWindowRect.top);
2081
2082 if (VisAfter != NULL)
2083 RgnType = IntGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
2084
2085 if (RgnType != ERROR && RgnType != NULLREGION)
2086 {
2087 co_VIS_WindowLayoutChanged(Window, ExposedRgn);
2088 }
2089 REGION_Delete(ExposedRgn);
2090 }
2091 REGION_Delete(VisBefore);
2092 }
2093
2094 if (VisAfter != NULL)
2095 {
2096 REGION_Delete(VisAfter);
2097 }
2098 }
2099
2100 if (!(WinPos.flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
2101 {
2102 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2103 {
2104 co_IntSendMessageNoWait(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
2105 }
2106 else
2107 {
2108 //ERR("SetWindowPos Set FG Window!\n");
2109 if ( pti->MessageQueue->spwndActive != Window ||
2110 pti->MessageQueue != gpqForeground )
2111 {
2112 //ERR("WPSWP : set active window\n");
2113 if (!(Window->state & WNDS_BEINGACTIVATED)) // Inside SAW?
2114 {
2115 co_IntSetForegroundWindow(Window); // Fixes SW_HIDE issues. Wine win test_SetActiveWindow & test_SetForegroundWindow.
2116 }
2117 }
2118 }
2119 }
2120
2121 if ( !PosChanged &&
2122 (WinPos.flags & SWP_FRAMECHANGED) &&
2123 !(WinPos.flags & SWP_DEFERERASE) && // Prevent sending WM_SYNCPAINT message.
2124 VisAfter )
2125 {
2126 PWND Parent = Window->spwndParent;
2127 if ( !(Window->style & WS_CHILD) && (Parent) && (Parent->style & WS_CLIPCHILDREN))
2128 {
2129 TRACE("SWP_FRAMECHANGED Parent WS_CLIPCHILDREN\n");
2130 UserSyncAndPaintWindows( Parent, RDW_CLIPCHILDREN);
2131 }
2132 }
2133
2134 // Fix wine msg test_SetFocus, prevents sending WM_WINDOWPOSCHANGED.
2135 if ( VisBefore == NULL &&
2136 VisBeforeJustClient == NULL &&
2137 !(Window->ExStyle & WS_EX_TOPMOST) &&
2138 (WinPos.flags & SWP_AGG_STATUSFLAGS) == (SWP_AGG_NOPOSCHANGE & ~SWP_NOZORDER))
2139 {
2140 TRACE("No drawing, set no Z order and no redraw!\n");
2141 WinPos.flags |= SWP_NOZORDER|SWP_NOREDRAW;
2142 }
2143
2144 if(!(flags & SWP_DEFERERASE))
2145 {
2146 /* erase parent when hiding or resizing child */
2147 if ((flags & SWP_HIDEWINDOW) ||
2148 (!(flags & SWP_SHOWWINDOW) &&
2149 (WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOGEOMETRYCHANGE))
2150 {
2151 PWND Parent = Window->spwndParent;
2152 if (!Parent || UserIsDesktopWindow(Parent)) Parent = Window;
2153 UserSyncAndPaintWindows( Parent, RDW_ERASENOW);
2154 }
2155
2156 /* Give newly shown windows a chance to redraw */
2157 if(((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2158 && !(flags & SWP_AGG_NOCLIENTCHANGE) && (flags & SWP_SHOWWINDOW))
2159 {
2160 UserSyncAndPaintWindows( Window, RDW_ERASENOW);
2161 }
2162 }
2163
2164 /* And last, send the WM_WINDOWPOSCHANGED message */
2165
2166 TRACE("\tstatus hwnd %p flags = %04x\n",Window?Window->head.h:NULL,WinPos.flags & SWP_AGG_STATUSFLAGS);
2167
2168 if (((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2169 && !((flags & SWP_AGG_NOCLIENTCHANGE) && (flags & SWP_SHOWWINDOW)))
2170 {
2171 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
2172 and always contains final window position.
2173 */
2174 WinPos.x = NewWindowRect.left;
2175 WinPos.y = NewWindowRect.top;
2176 WinPos.cx = NewWindowRect.right - NewWindowRect.left;
2177 WinPos.cy = NewWindowRect.bottom - NewWindowRect.top;
2178 TRACE("WM_WINDOWPOSCHANGED hwnd %p Flags %04x\n",WinPos.hwnd,WinPos.flags);
2179 co_IntSendMessageNoWait(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
2180 }
2181
2182 if ( WinPos.flags & SWP_FRAMECHANGED || WinPos.flags & SWP_STATECHANGED ||
2183 !(WinPos.flags & SWP_NOCLIENTSIZE) || !(WinPos.flags & SWP_NOCLIENTMOVE) )
2184 {
2185 PWND pWnd = ValidateHwndNoErr(WinPos.hwnd);
2186 if (pWnd)
2187 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2188 }
2189
2190 if(bPointerInWindow != IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y))
2191 {
2192 /* Generate mouse move message */
2193 MSG msg;
2194 msg.message = WM_MOUSEMOVE;
2195 msg.wParam = UserGetMouseButtonsState();
2196 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2197 msg.pt = gpsi->ptCursor;
2198 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2199 }
2200
2201 return TRUE;
2202 }
2203
2204 LRESULT FASTCALL
2205 co_WinPosGetNonClientSize(PWND Window, RECT* WindowRect, RECT* ClientRect)
2206 {
2207 LRESULT Result;
2208
2209 ASSERT_REFS_CO(Window);
2210
2211 *ClientRect = *WindowRect;
2212 Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect);
2213
2214 FixClientRect(ClientRect, WindowRect);
2215
2216 return Result;
2217 }
2218
2219 void FASTCALL
2220 co_WinPosSendSizeMove(PWND Wnd)
2221 {
2222 RECTL Rect;
2223 LPARAM lParam;
2224 WPARAM wParam = SIZE_RESTORED;
2225
2226 IntGetClientRect(Wnd, &Rect);
2227 lParam = MAKELONG(Rect.right-Rect.left, Rect.bottom-Rect.top);
2228
2229 Wnd->state &= ~WNDS_SENDSIZEMOVEMSGS;
2230
2231 if (Wnd->style & WS_MAXIMIZE)
2232 {
2233 wParam = SIZE_MAXIMIZED;
2234 }
2235 else if (Wnd->style & WS_MINIMIZE)
2236 {
2237 wParam = SIZE_MINIMIZED;
2238 lParam = 0;
2239 }
2240
2241 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SIZE, wParam, lParam);
2242
2243 if (UserIsDesktopWindow(Wnd->spwndParent))
2244 lParam = MAKELONG(Wnd->rcClient.left, Wnd->rcClient.top);
2245 else
2246 lParam = MAKELONG(Wnd->rcClient.left-Wnd->spwndParent->rcClient.left, Wnd->rcClient.top-Wnd->spwndParent->rcClient.top);
2247
2248 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_MOVE, 0, lParam);
2249
2250 IntEngWindowChanged(Wnd, WOC_RGN_CLIENT);
2251 }
2252
2253 UINT FASTCALL
2254 co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos)
2255 {
2256 POINT Size;
2257 WINDOWPLACEMENT wpl;
2258 LONG old_style;
2259 UINT SwpFlags = 0;
2260
2261 ASSERT_REFS_CO(Wnd);
2262
2263 wpl.length = sizeof(wpl);
2264 IntGetWindowPlacement( Wnd, &wpl );
2265
2266 if (co_HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)Wnd->head.h, ShowFlag))
2267 {
2268 ERR("WinPosMinMaximize WH_CBT Call Hook return!\n");
2269 return SWP_NOSIZE | SWP_NOMOVE;
2270 }
2271 if (Wnd->style & WS_MINIMIZE)
2272 {
2273 switch (ShowFlag)
2274 {
2275 case SW_MINIMIZE:
2276 case SW_SHOWMINNOACTIVE:
2277 case SW_SHOWMINIMIZED:
2278 case SW_FORCEMINIMIZE:
2279 return SWP_NOSIZE | SWP_NOMOVE;
2280 }
2281 if (!co_IntSendMessageNoWait(Wnd->head.h, WM_QUERYOPEN, 0, 0))
2282 {
2283 return(SWP_NOSIZE | SWP_NOMOVE);
2284 }
2285 SwpFlags |= SWP_NOCOPYBITS;
2286 }
2287 switch (ShowFlag)
2288 {
2289 case SW_MINIMIZE:
2290 case SW_SHOWMINNOACTIVE:
2291 case SW_SHOWMINIMIZED:
2292 case SW_FORCEMINIMIZE:
2293 {
2294 //ERR("MinMaximize Minimize\n");
2295 if (Wnd->style & WS_MAXIMIZE)
2296 {
2297 Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED;
2298 }
2299 else
2300 {
2301 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2302 }
2303
2304 old_style = IntSetStyle( Wnd, WS_MINIMIZE, WS_MAXIMIZE );
2305
2306 co_UserRedrawWindow(Wnd, NULL, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOINTERNALPAINT);
2307
2308 if (!(Wnd->InternalPos.flags & WPF_SETMINPOSITION))
2309 Wnd->InternalPos.flags &= ~WPF_MININIT;
2310
2311 WinPosFindIconPos(Wnd, &wpl.ptMinPosition);
2312
2313 if (!(old_style & WS_MINIMIZE))
2314 {
2315 SwpFlags |= SWP_STATECHANGED;
2316 IntShowOwnedPopups(Wnd, FALSE);
2317 }
2318
2319 RECTL_vSetRect(NewPos, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
2320 wpl.ptMinPosition.x + UserGetSystemMetrics(SM_CXMINIMIZED),
2321 wpl.ptMinPosition.y + UserGetSystemMetrics(SM_CYMINIMIZED));
2322 SwpFlags |= SWP_NOCOPYBITS;
2323 break;
2324 }
2325
2326 case SW_MAXIMIZE:
2327 {
2328 //ERR("MinMaximize Maximize\n");
2329 if ((Wnd->style & WS_MAXIMIZE) && (Wnd->style & WS_VISIBLE))
2330 {
2331 SwpFlags = SWP_NOSIZE | SWP_NOMOVE;
2332 break;
2333 }
2334 co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
2335
2336 /*ERR("Maximize: %d,%d %dx%d\n",
2337 wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, Size.x, Size.y);
2338 */
2339 old_style = IntSetStyle( Wnd, WS_MAXIMIZE, WS_MINIMIZE );
2340 /*if (old_style & WS_MINIMIZE)
2341 {
2342 IntShowOwnedPopups(Wnd, TRUE);
2343 }*/
2344
2345 if (!(old_style & WS_MAXIMIZE)) SwpFlags |= SWP_STATECHANGED;
2346 RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
2347 //wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
2348 Size.x, Size.y);
2349 break;
2350 }
2351
2352 case SW_SHOWNOACTIVATE:
2353 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2354 /* fall through */
2355 case SW_SHOWNORMAL:
2356 case SW_RESTORE:
2357 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
2358 {
2359 //ERR("MinMaximize Restore\n");
2360 old_style = IntSetStyle( Wnd, 0, WS_MINIMIZE | WS_MAXIMIZE );
2361 if (old_style & WS_MINIMIZE)
2362 {
2363 IntShowOwnedPopups(Wnd, TRUE);
2364
2365 if (Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED)
2366 {
2367 co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
2368 IntSetStyle( Wnd, WS_MAXIMIZE, 0 );
2369 SwpFlags |= SWP_STATECHANGED;
2370 RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
2371 wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
2372 break;
2373 }
2374 else
2375 {
2376 *NewPos = wpl.rcNormalPosition;
2377 NewPos->right -= NewPos->left;
2378 NewPos->bottom -= NewPos->top;
2379 break;
2380 }
2381 }
2382 else
2383 {
2384 if (!(old_style & WS_MAXIMIZE))
2385 {
2386 break;
2387 }
2388 SwpFlags |= SWP_STATECHANGED;
2389 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2390 *NewPos = wpl.rcNormalPosition;
2391 NewPos->right -= NewPos->left;
2392 NewPos->bottom -= NewPos->top;
2393 break;
2394 }
2395 }
2396 }
2397 return SwpFlags;
2398 }
2399
2400 /*
2401 ShowWindow does not set SWP_FRAMECHANGED!!! Fix wine msg test_SetParent:WmSetParentSeq_2:23 wParam bits!
2402 */
2403 BOOLEAN FASTCALL
2404 co_WinPosShowWindow(PWND Wnd, INT Cmd)
2405 {
2406 BOOLEAN WasVisible;
2407 UINT Swp = 0, EventMsg = 0;
2408 RECTL NewPos = {0, 0, 0, 0};
2409 BOOLEAN ShowFlag;
2410 LONG style;
2411 PWND Parent;
2412 PTHREADINFO pti;
2413 //HRGN VisibleRgn;
2414 BOOL ShowOwned = FALSE;
2415 BOOL FirstTime = FALSE;
2416 ASSERT_REFS_CO(Wnd);
2417 //KeRosDumpStackFrames(NULL, 20);
2418 pti = PsGetCurrentThreadWin32Thread();
2419 WasVisible = (Wnd->style & WS_VISIBLE) != 0;
2420 style = Wnd->style;
2421
2422 TRACE("co_WinPosShowWindow START hwnd %p Cmd %d usicmd %u\n",
2423 Wnd->head.h, Cmd, pti->ppi->usi.wShowWindow);
2424
2425 if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW )
2426 {
2427 if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2428 {
2429 if ((Wnd->style & WS_CAPTION) == WS_CAPTION)
2430 {
2431 if (Wnd->spwndOwner == NULL)
2432 {
2433 if ( Cmd == SW_SHOWNORMAL || Cmd == SW_SHOW)
2434 {
2435 Cmd = SW_SHOWDEFAULT;
2436 }
2437 FirstTime = TRUE;
2438 TRACE("co_WPSW FT 1\n");
2439 }
2440 }
2441 }
2442 }
2443
2444 if ( Cmd == SW_SHOWDEFAULT )
2445 {
2446 if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW )
2447 {
2448 Cmd = pti->ppi->usi.wShowWindow;
2449 FirstTime = TRUE;
2450 TRACE("co_WPSW FT 2\n");
2451 }
2452 }
2453
2454 if (FirstTime)
2455 {
2456 pti->ppi->usi.dwFlags &= ~(STARTF_USEPOSITION|STARTF_USESIZE|STARTF_USESHOWWINDOW);
2457 }
2458
2459 switch (Cmd)
2460 {
2461 case SW_HIDE:
2462 {
2463 if (!WasVisible)
2464 {
2465 //ERR("co_WinPosShowWindow Exit Bad\n");
2466 return FALSE;
2467 }
2468 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2469 if (Wnd != pti->MessageQueue->spwndActive)
2470 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2471 break;
2472 }
2473
2474 case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
2475 case SW_SHOWMINNOACTIVE:
2476 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2477 /* Fall through. */
2478 case SW_SHOWMINIMIZED:
2479 Swp |= SWP_SHOWWINDOW;
2480 /* Fall through. */
2481 case SW_MINIMIZE:
2482 {
2483 Swp |= SWP_NOACTIVATE;
2484 if (!(style & WS_MINIMIZE))
2485 {
2486 IntShowOwnedPopups(Wnd, FALSE );
2487 // Fix wine Win test_SetFocus todo #1 & #2,
2488 if (Cmd == SW_SHOWMINIMIZED)
2489 {
2490 //ERR("co_WinPosShowWindow Set focus 1\n");
2491 if ((style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2492 co_UserSetFocus(Wnd->spwndParent);
2493 else
2494 co_UserSetFocus(0);
2495 }
2496
2497 Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos);
2498
2499 EventMsg = EVENT_SYSTEM_MINIMIZESTART;
2500 }
2501 else
2502 {
2503 if (WasVisible)
2504 {
2505 //ERR("co_WinPosShowWindow Exit Good\n");
2506 return TRUE;
2507 }
2508 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2509 }
2510 break;
2511 }
2512
2513 case SW_SHOWMAXIMIZED:
2514 {
2515 Swp |= SWP_SHOWWINDOW;
2516 if (!(style & WS_MAXIMIZE))
2517 {
2518 ShowOwned = TRUE;
2519
2520 Swp |= co_WinPosMinMaximize(Wnd, SW_MAXIMIZE, &NewPos);
2521
2522 EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2523 }
2524 else
2525 {
2526 if (WasVisible)
2527 {
2528 //ERR("co_WinPosShowWindow Exit Good 1\n");
2529 return TRUE;
2530 }
2531 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2532 }
2533 break;
2534 }
2535
2536 case SW_SHOWNA:
2537 Swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2538 if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOZORDER;
2539 break;
2540 case SW_SHOW:
2541 if (WasVisible) return(TRUE); // Nothing to do!
2542 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2543 /* Don't activate the topmost window. */
2544 if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2545 break;
2546
2547 case SW_SHOWNOACTIVATE:
2548 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2549 /* Fall through. */
2550 case SW_SHOWNORMAL:
2551 case SW_SHOWDEFAULT:
2552 case SW_RESTORE:
2553 if (!WasVisible) Swp |= SWP_SHOWWINDOW;
2554 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2555 {
2556 Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos);
2557 if (style & WS_MINIMIZE) EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2558 }
2559 else
2560 {
2561 if (WasVisible)
2562 {
2563 //ERR("co_WinPosShowWindow Exit Good 3\n");
2564 return TRUE;
2565 }
2566 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2567 }
2568 if ( style & WS_CHILD &&
2569 !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2570 !(Swp & SWP_STATECHANGED))
2571 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2572 break;
2573
2574 default:
2575 //ERR("co_WinPosShowWindow Exit Good 4\n");
2576 return WasVisible;
2577 }
2578
2579 ShowFlag = (Cmd != SW_HIDE);
2580
2581 if ((ShowFlag != WasVisible || Cmd == SW_SHOWNA) && Cmd != SW_SHOWMAXIMIZED && !(Swp & SWP_STATECHANGED))
2582 {
2583 co_IntSendMessageNoWait(Wnd->head.h, WM_SHOWWINDOW, ShowFlag, 0);
2584 #if 0 // Fix wine msg test_SetParent:WmSetParentSeq_1:2
2585 if (!(Wnd->state2 & WNDS2_WIN31COMPAT)) // <------------- XP sets this bit!
2586 co_IntSendMessageNoWait(Wnd->head.h, WM_SETVISIBLE, ShowFlag, 0);
2587 #endif
2588 if (!VerifyWnd(Wnd)) return WasVisible;
2589 }
2590
2591 /* We can't activate a child window */
2592 if ((Wnd->style & WS_CHILD) &&
2593 !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2594 Cmd != SW_SHOWNA)
2595 {
2596 //ERR("SWP Child No active and ZOrder\n");
2597 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2598 }
2599
2600 #if 0 // Explorer issues with common controls? Someone does not know how CS_SAVEBITS works.
2601 // Breaks startup and shutdown active window...
2602 if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
2603 Wnd->pcls->style & CS_SAVEBITS &&
2604 ((Cmd == SW_SHOW) || (Cmd == SW_NORMAL)))
2605 {
2606 ERR("WinPosShowWindow Set active\n");
2607 //UserSetActiveWindow(Wnd);
2608 co_IntSetForegroundWindow(Wnd); // HACK
2609 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2610 }
2611 #endif
2612
2613 if (IsChildVisible(Wnd) || Swp & SWP_STATECHANGED)
2614 {
2615 TRACE("Child is Vis %s or State changed %s. ShowFlag %s Swp %04x\n",
2616 (IsChildVisible(Wnd) ? "TRUE" : "FALSE"), (Swp & SWP_STATECHANGED ? "TRUE" : "FALSE"),
2617 (ShowFlag ? "TRUE" : "FALSE"),LOWORD(Swp));
2618 co_WinPosSetWindowPos( Wnd,
2619 0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP,
2620 NewPos.left,
2621 NewPos.top,
2622 NewPos.right, // NewPos.right - NewPos.left, when minimized and restore, the window becomes smaller.
2623 NewPos.bottom,// NewPos.bottom - NewPos.top,
2624 LOWORD(Swp));
2625 }
2626 else
2627 {
2628 TRACE("Parent Vis?\n");
2629 /* if parent is not visible simply toggle WS_VISIBLE and return */
2630 if (ShowFlag) IntSetStyle( Wnd, WS_VISIBLE, 0 );
2631 else IntSetStyle( Wnd, 0, WS_VISIBLE );
2632 }
2633
2634 if ( EventMsg ) IntNotifyWinEvent(EventMsg, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2635
2636 if ( ShowOwned ) IntShowOwnedPopups(Wnd, TRUE );
2637
2638 if ((Cmd == SW_HIDE) || (Cmd == SW_MINIMIZE))
2639 {
2640 if ( Wnd == pti->MessageQueue->spwndActive && pti->MessageQueue == IntGetFocusMessageQueue() )
2641 {
2642 if (UserIsDesktopWindow(Wnd->spwndParent))
2643 {
2644 if (!ActivateOtherWindowMin(Wnd))
2645 {
2646 co_WinPosActivateOtherWindow(Wnd);
2647 }
2648 }
2649 else
2650 {
2651 co_WinPosActivateOtherWindow(Wnd);
2652 }
2653 }
2654
2655 /* Revert focus to parent */
2656 if (Wnd == pti->MessageQueue->spwndFocus)
2657 {
2658 Parent = Wnd->spwndParent;
2659 if (UserIsDesktopWindow(Wnd->spwndParent))
2660 Parent = 0;
2661 co_UserSetFocus(Parent);
2662 }
2663 // Hide, just return.
2664 if (Cmd == SW_HIDE) return WasVisible;
2665 }
2666
2667 /* FIXME: Check for window destruction. */
2668
2669 if ((Wnd->state & WNDS_SENDSIZEMOVEMSGS) &&
2670 !(Wnd->state2 & WNDS2_INDESTROY))
2671 {
2672 co_WinPosSendSizeMove(Wnd);
2673 }
2674
2675 /* if previous state was minimized Windows sets focus to the window */
2676 if (style & WS_MINIMIZE)
2677 {
2678 co_UserSetFocus(Wnd);
2679 // Fix wine Win test_SetFocus todo #3,
2680 if (!(style & WS_CHILD)) co_IntSendMessage(UserHMGetHandle(Wnd), WM_ACTIVATE, WA_ACTIVE, 0);
2681 }
2682 //ERR("co_WinPosShowWindow EXIT\n");
2683 return WasVisible;
2684 }
2685
2686 static PWND
2687 co_WinPosSearchChildren(
2688 IN PWND ScopeWin,
2689 IN POINT *Point,
2690 IN OUT USHORT *HitTest,
2691 IN BOOL Ignore
2692 )
2693 {
2694 HWND *List, *phWnd;
2695 PWND pwndChild = NULL;
2696
2697 /* not visible */
2698 if (!(ScopeWin->style & WS_VISIBLE))
2699 {
2700 return NULL;
2701 }
2702
2703 /* not in window or in window region */
2704 if (!IntPtInWindow(ScopeWin, Point->x, Point->y))
2705 {
2706 return NULL;
2707 }
2708
2709 /* transparent */
2710 if ((ScopeWin->ExStyle & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT))
2711 {
2712 return NULL;
2713 }
2714
2715 if (!Ignore && (ScopeWin->style & WS_DISABLED))
2716 { /* disabled child */
2717 if ((ScopeWin->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return NULL;
2718 /* process the hit error */
2719 *HitTest = HTERROR;
2720 return ScopeWin;
2721 }
2722
2723 /* not minimized and check if point is inside the window */
2724 if (!(ScopeWin->style & WS_MINIMIZE) &&
2725 RECTL_bPointInRect(&ScopeWin->rcClient, Point->x, Point->y) )
2726 {
2727 UserReferenceObject(ScopeWin);
2728
2729 List = IntWinListChildren(ScopeWin);
2730 if (List)
2731 {
2732 for (phWnd = List; *phWnd; ++phWnd)
2733 {
2734 if (!(pwndChild = ValidateHwndNoErr(*phWnd)))
2735 {
2736 continue;
2737 }
2738
2739 pwndChild = co_WinPosSearchChildren(pwndChild, Point, HitTest, Ignore);
2740
2741 if (pwndChild != NULL)
2742 {
2743 /* We found a window. Don't send any more WM_NCHITTEST messages */
2744 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2745 UserDereferenceObject(ScopeWin);
2746 return pwndChild;
2747 }
2748 }
2749 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2750 }
2751 UserDereferenceObject(ScopeWin);
2752 }
2753
2754 if (ScopeWin->head.pti == PsGetCurrentThreadWin32Thread())
2755 {
2756 *HitTest = (USHORT)co_IntSendMessage(ScopeWin->head.h, WM_NCHITTEST, 0, MAKELONG(Point->x, Point->y));
2757
2758 if ((*HitTest) == (USHORT)HTTRANSPARENT)
2759 {
2760 return NULL;
2761 }
2762 }
2763 else
2764 {
2765 if (*HitTest == HTNOWHERE && pwndChild == NULL) *HitTest = HTCLIENT;
2766 }
2767
2768 return ScopeWin;
2769 }
2770
2771 PWND APIENTRY
2772 co_WinPosWindowFromPoint(
2773 IN PWND ScopeWin,
2774 IN POINT *WinPoint,
2775 IN OUT USHORT* HitTest,
2776 IN BOOL Ignore)
2777 {
2778 PWND Window;
2779 POINT Point = *WinPoint;
2780 USER_REFERENCE_ENTRY Ref;
2781
2782 if( ScopeWin == NULL )
2783 {
2784 ScopeWin = UserGetDesktopWindow();
2785 if(ScopeWin == NULL)
2786 return NULL;
2787 }
2788
2789 *HitTest = HTNOWHERE;
2790
2791 ASSERT_REFS_CO(ScopeWin);
2792 UserRefObjectCo(ScopeWin, &Ref);
2793
2794 Window = co_WinPosSearchChildren(ScopeWin, &Point, HitTest, Ignore);
2795
2796 UserDerefObjectCo(ScopeWin);
2797 if (Window)
2798 ASSERT_REFS_CO(Window);
2799 ASSERT_REFS_CO(ScopeWin);
2800
2801 return Window;
2802 }
2803
2804 PWND FASTCALL
2805 IntRealChildWindowFromPoint(PWND Parent, LONG x, LONG y)
2806 {
2807 POINTL Pt;
2808 HWND *List, *phWnd;
2809 PWND pwndHit = NULL;
2810
2811 Pt.x = x;
2812 Pt.y = y;
2813
2814 if (!UserIsDesktopWindow(Parent))
2815 {
2816 Pt.x += Parent->rcClient.left;
2817 Pt.y += Parent->rcClient.top;
2818 }
2819
2820 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2821
2822 if ((List = IntWinListChildren(Parent)))
2823 {
2824 for (phWnd = List; *phWnd; phWnd++)
2825 {
2826 PWND Child;
2827 if ((Child = ValidateHwndNoErr(*phWnd)))
2828 {
2829 if ( Child->style & WS_VISIBLE && IntPtInWindow(Child, Pt.x, Pt.y) )
2830 {
2831 if ( Child->pcls->atomClassName != gpsi->atomSysClass[ICLS_BUTTON] ||
2832 (Child->style & BS_TYPEMASK) != BS_GROUPBOX )
2833 {
2834 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2835 return Child;
2836 }
2837 pwndHit = Child;
2838 }
2839 }
2840 }
2841 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2842 }
2843 return pwndHit ? pwndHit : Parent;
2844 }
2845
2846 PWND APIENTRY
2847 IntChildWindowFromPointEx(PWND Parent, LONG x, LONG y, UINT uiFlags)
2848 {
2849 POINTL Pt;
2850 HWND *List, *phWnd;
2851 PWND pwndHit = NULL;
2852
2853 Pt.x = x;
2854 Pt.y = y;
2855
2856 if (!UserIsDesktopWindow(Parent))
2857 {
2858 if (Parent->ExStyle & WS_EX_LAYOUTRTL)
2859 Pt.x = Parent->rcClient.right - Pt.x;
2860 else
2861 Pt.x += Parent->rcClient.left;
2862 Pt.y += Parent->rcClient.top;
2863 }
2864
2865 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2866
2867 if ((List = IntWinListChildren(Parent)))
2868 {
2869 for (phWnd = List; *phWnd; phWnd++)
2870 {
2871 PWND Child;
2872 if ((Child = ValidateHwndNoErr(*phWnd)))
2873 {
2874 if (uiFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
2875 {
2876 if (!(Child->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE)) continue;
2877 if ((Child->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED)) continue;
2878 }
2879
2880 if (uiFlags & CWP_SKIPTRANSPARENT)
2881 {
2882 if (Child->ExStyle & WS_EX_TRANSPARENT) continue;
2883 }
2884
2885 if (IntPtInWindow(Child, Pt.x, Pt.y))
2886 {
2887 pwndHit = Child;
2888 break;
2889 }
2890 }
2891 }
2892 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2893 }
2894 return pwndHit ? pwndHit : Parent;
2895 }
2896
2897 HDWP
2898 FASTCALL
2899 IntDeferWindowPos( HDWP hdwp,
2900 HWND hwnd,
2901 HWND hwndAfter,
2902 INT x,
2903 INT y,
2904 INT cx,
2905 INT cy,
2906 UINT flags )
2907 {
2908 PSMWP pDWP;
2909 int i;
2910 HDWP retvalue = hdwp;
2911
2912 TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2913 hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
2914
2915 if (flags & ~(SWP_NOSIZE | SWP_NOMOVE |
2916 SWP_NOZORDER | SWP_NOREDRAW |
2917 SWP_NOACTIVATE | SWP_NOCOPYBITS |
2918 SWP_NOOWNERZORDER|SWP_SHOWWINDOW |
2919 SWP_HIDEWINDOW | SWP_FRAMECHANGED))
2920 {
2921 EngSetLastError(ERROR_INVALID_PARAMETER);
2922 return NULL;
2923 }
2924
2925 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
2926 {
2927 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
2928 return NULL;
2929 }
2930
2931 for (i = 0; i < pDWP->ccvr; i++)
2932 {
2933 if (pDWP->acvr[i].pos.hwnd == hwnd)
2934 {
2935 /* Merge with the other changes */
2936 if (!(flags & SWP_NOZORDER))
2937 {
2938 pDWP->acvr[i].pos.hwndInsertAfter = hwndAfter;
2939 }
2940 if (!(flags & SWP_NOMOVE))
2941 {
2942 pDWP->acvr[i].pos.x = x;
2943 pDWP->acvr[i].pos.y = y;
2944 }
2945 if (!(flags & SWP_NOSIZE))
2946 {
2947 pDWP->acvr[i].pos.cx = cx;
2948 pDWP->acvr[i].pos.cy = cy;
2949 }
2950 pDWP->acvr[i].pos.flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
2951 SWP_NOZORDER | SWP_NOREDRAW |
2952 SWP_NOACTIVATE | SWP_NOCOPYBITS|
2953 SWP_NOOWNERZORDER);
2954 pDWP->acvr[i].pos.flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
2955 SWP_FRAMECHANGED);
2956 goto END;
2957 }
2958 }
2959 if (pDWP->ccvr >= pDWP->ccvrAlloc)
2960 {
2961 PCVR newpos = ExAllocatePoolWithTag(PagedPool, pDWP->ccvrAlloc * 2 * sizeof(CVR), USERTAG_SWP);
2962 if (!newpos)
2963 {
2964 retvalue = NULL;
2965 goto END;
2966 }
2967 RtlZeroMemory(newpos, pDWP->ccvrAlloc * 2 * sizeof(CVR));
2968 RtlCopyMemory(newpos, pDWP->acvr, pDWP->ccvrAlloc * sizeof(CVR));
2969 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
2970 pDWP->ccvrAlloc *= 2;
2971 pDWP->acvr = newpos;
2972 }
2973 pDWP->acvr[pDWP->ccvr].pos.hwnd = hwnd;
2974 pDWP->acvr[pDWP->ccvr].pos.hwndInsertAfter = hwndAfter;
2975 pDWP->acvr[pDWP->ccvr].pos.x = x;
2976 pDWP->acvr[pDWP->ccvr].pos.y = y;
2977 pDWP->acvr[pDWP->ccvr].pos.cx = cx;
2978 pDWP->acvr[pDWP->ccvr].pos.cy = cy;
2979 pDWP->acvr[pDWP->ccvr].pos.flags = flags;
2980 pDWP->acvr[pDWP->ccvr].hrgnClip = NULL;
2981 pDWP->acvr[pDWP->ccvr].hrgnInterMonitor = NULL;
2982 pDWP->ccvr++;
2983 END:
2984 return retvalue;
2985 }
2986
2987 BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp, BOOL sAsync )
2988 {
2989 PSMWP pDWP;
2990 PCVR winpos;
2991 BOOL res = TRUE;
2992 int i;
2993
2994 TRACE("%p\n", hdwp);
2995
2996 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
2997 {
2998 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
2999 return FALSE;
3000 }
3001
3002 for (i = 0, winpos = pDWP->acvr; res && i < pDWP->ccvr; i++, winpos++)
3003 {
3004 PWND pwnd;
3005 USER_REFERENCE_ENTRY Ref;
3006
3007 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
3008 winpos->pos.hwnd, winpos->pos.hwndInsertAfter, winpos->pos.x, winpos->pos.y,
3009 winpos->pos.cx, winpos->pos.cy, winpos->pos.flags);
3010
3011 pwnd = ValidateHwndNoErr(winpos->pos.hwnd);
3012 if (!pwnd)
3013 continue;
3014
3015 UserRefObjectCo(pwnd, &Ref);
3016
3017 if ( sAsync )
3018 {
3019 LRESULT lRes;
3020 PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
3021 if ( ppos )
3022 {
3023 *ppos = winpos->pos;
3024 /* Yes it's a pointer inside Win32k! */
3025 lRes = co_IntSendMessageNoWait( winpos->pos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
3026 /* We handle this the same way as Event Hooks and Hooks. */
3027 if ( !lRes )
3028 {
3029 ExFreePoolWithTag(ppos, USERTAG_SWP);
3030 }
3031 }
3032 }
3033 else
3034 res = co_WinPosSetWindowPos( pwnd,
3035 winpos->pos.hwndInsertAfter,
3036 winpos->pos.x,
3037 winpos->pos.y,
3038 winpos->pos.cx,
3039 winpos->pos.cy,
3040 winpos->pos.flags);
3041
3042 // Hack to pass tests.... Must have some work to do so clear the error.
3043 if (res && (winpos->pos.flags & (SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER)) == SWP_NOZORDER )
3044 EngSetLastError(ERROR_SUCCESS);
3045
3046 UserDerefObjectCo(pwnd);
3047 }
3048 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
3049 UserDereferenceObject(pDWP);
3050 UserDeleteObject(hdwp, TYPE_SETWINDOWPOS);
3051 return res;
3052 }
3053
3054 /*
3055 * @implemented
3056 */
3057 HWND APIENTRY
3058 NtUserChildWindowFromPointEx(HWND hwndParent,
3059 LONG x,
3060 LONG y,
3061 UINT uiFlags)
3062 {
3063 PWND pwndParent;
3064 TRACE("Enter NtUserChildWindowFromPointEx\n");
3065 UserEnterExclusive();
3066 if ((pwndParent = UserGetWindowObject(hwndParent)))
3067 {
3068 pwndParent = IntChildWindowFromPointEx(pwndParent, x, y, uiFlags);
3069 }
3070 UserLeave();
3071 TRACE("Leave NtUserChildWindowFromPointEx\n");
3072 return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
3073 }
3074
3075 /*
3076 * @implemented
3077 */
3078 BOOL APIENTRY
3079 NtUserEndDeferWindowPosEx(HDWP WinPosInfo,
3080 DWORD Unknown1)
3081 {
3082 BOOL Ret;
3083 TRACE("Enter NtUserEndDeferWindowPosEx\n");
3084 UserEnterExclusive();
3085 Ret = IntEndDeferWindowPosEx(WinPosInfo, (BOOL)Unknown1);
3086 TRACE("Leave NtUserEndDeferWindowPosEx, ret=%i\n", Ret);
3087 UserLeave();
3088 return Ret;
3089 }
3090
3091 /*
3092 * @implemented
3093 */
3094 HDWP APIENTRY
3095 NtUserDeferWindowPos(HDWP WinPosInfo,
3096 HWND Wnd,
3097 HWND WndInsertAfter,
3098 int x,
3099 int y,
3100 int cx,
3101 int cy,
3102 UINT Flags)
3103 {
3104 PWND pWnd, pWndIA;
3105 HDWP Ret = NULL;
3106 UINT Tmp = ~(SWP_ASYNCWINDOWPOS|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_NOREPOSITION|
3107 SWP_NOCOPYBITS|SWP_HIDEWINDOW|SWP_SHOWWINDOW|SWP_FRAMECHANGED|
3108 SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE);
3109
3110 TRACE("Enter NtUserDeferWindowPos\n");
3111 UserEnterExclusive();
3112
3113 if ( Flags & Tmp )
3114 {
3115 EngSetLastError(ERROR_INVALID_FLAGS);
3116 goto Exit;
3117 }
3118
3119 pWnd = UserGetWindowObject(Wnd);
3120 if (!pWnd || UserIsDesktopWindow(pWnd) || UserIsMessageWindow(pWnd))
3121 {
3122 goto Exit;
3123 }
3124
3125 if ( WndInsertAfter &&
3126 WndInsertAfter != HWND_BOTTOM &&
3127 WndInsertAfter != HWND_TOPMOST &&
3128 WndInsertAfter != HWND_NOTOPMOST )
3129 {
3130 pWndIA = UserGetWindowObject(WndInsertAfter);
3131 if (!pWndIA || UserIsDesktopWindow(pWndIA) || UserIsMessageWindow(pWndIA))
3132 {
3133 goto Exit;
3134 }
3135 }
3136
3137 Ret = IntDeferWindowPos(WinPosInfo, Wnd, WndInsertAfter, x, y, cx, cy, Flags);
3138
3139 Exit:
3140 TRACE("Leave NtUserDeferWindowPos, ret=%p\n", Ret);
3141 UserLeave();
3142 return Ret;
3143 }
3144
3145 /*
3146 * @implemented
3147 */
3148 DWORD APIENTRY
3149 NtUserGetInternalWindowPos( HWND hWnd,
3150 LPRECT rectWnd,
3151 LPPOINT ptIcon)
3152 {
3153 PWND Window;
3154 DWORD Ret = 0;
3155 BOOL Hit = FALSE;
3156 WINDOWPLACEMENT wndpl;
3157
3158 UserEnterShared();
3159
3160 if (!(Window = UserGetWindowObject(hWnd)))
3161 {
3162 Hit = FALSE;
3163 goto Exit;
3164 }
3165
3166 _SEH2_TRY
3167 {
3168 if(rectWnd)
3169 {
3170 ProbeForWrite(rectWnd,
3171 sizeof(RECT),
3172 1);
3173 }
3174 if(ptIcon)
3175 {
3176 ProbeForWrite(ptIcon,
3177 sizeof(POINT),
3178 1);
3179 }
3180
3181 }
3182 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3183 {
3184 SetLastNtError(_SEH2_GetExceptionCode());
3185 Hit = TRUE;
3186 }
3187 _SEH2_END;
3188
3189 wndpl.length = sizeof(WINDOWPLACEMENT);
3190
3191 if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
3192 {
3193 _SEH2_TRY
3194 {
3195 if (rectWnd)
3196 {
3197 RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));
3198 }
3199 if (ptIcon)
3200 {
3201 RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT));
3202 }
3203
3204 }
3205 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3206 {
3207 SetLastNtError(_SEH2_GetExceptionCode());
3208 Hit = TRUE;
3209 }
3210 _SEH2_END;
3211
3212 if (!Hit) Ret = wndpl.showCmd;
3213 }
3214 Exit:
3215 UserLeave();
3216 return Ret;
3217 }
3218
3219 /*
3220 * @implemented
3221 */
3222 BOOL APIENTRY
3223 NtUserGetWindowPlacement(HWND hWnd,
3224 WINDOWPLACEMENT *lpwndpl)
3225 {
3226 PWND Wnd;
3227 WINDOWPLACEMENT Safepl;
3228 NTSTATUS Status;
3229 DECLARE_RETURN(BOOL);
3230
3231 TRACE("Enter NtUserGetWindowPlacement\n");
3232 UserEnterShared();
3233
3234 if (!(Wnd = UserGetWindowObject(hWnd)))
3235 {
3236 RETURN( FALSE);
3237 }
3238
3239 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3240 if (!NT_SUCCESS(Status))
3241 {
3242 SetLastNtError(Status);
3243 RETURN( FALSE);
3244 }
3245
3246 Safepl.length = sizeof(WINDOWPLACEMENT);
3247
3248 IntGetWindowPlacement(Wnd, &Safepl);
3249
3250 Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
3251 if (!NT_SUCCESS(Status))
3252 {
3253 SetLastNtError(Status);
3254 RETURN( FALSE);
3255 }
3256
3257 RETURN( TRUE);
3258
3259 CLEANUP:
3260 TRACE("Leave NtUserGetWindowPlacement, ret=%i\n",_ret_);
3261 UserLeave();
3262 END_CLEANUP;
3263 }
3264
3265 DWORD
3266 APIENTRY
3267 NtUserMinMaximize(
3268 HWND hWnd,
3269 UINT cmd, // Wine SW_ commands
3270 BOOL Hide)
3271 {
3272 PWND pWnd;
3273
3274 TRACE("Enter NtUserMinMaximize\n");
3275 UserEnterExclusive();
3276
3277 pWnd = UserGetWindowObject(hWnd);
3278 if (!pWnd || UserIsDesktopWindow(pWnd) || UserIsMessageWindow(pWnd))
3279 {
3280 goto Exit;
3281 }
3282
3283 if ( cmd > SW_MAX || pWnd->state2 & WNDS2_INDESTROY)
3284 {
3285 EngSetLastError(ERROR_INVALID_PARAMETER);
3286 goto Exit;
3287 }
3288
3289 cmd |= Hide ? SW_HIDE : 0;
3290
3291 co_WinPosShowWindow(pWnd, cmd);
3292
3293 Exit:
3294 TRACE("Leave NtUserMinMaximize\n");
3295 UserLeave();
3296 return 0; // Always NULL?
3297 }
3298
3299 /*
3300 * @implemented
3301 */
3302 BOOL APIENTRY
3303 NtUserMoveWindow(
3304 HWND hWnd,
3305 int X,
3306 int Y,
3307 int nWidth,
3308 int nHeight,
3309 BOOL bRepaint)
3310 {
3311 return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight,
3312 (bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE :
3313 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW));
3314 }
3315
3316 /*
3317 * @implemented
3318 */
3319 HWND APIENTRY
3320 NtUserRealChildWindowFromPoint(HWND Parent,
3321 LONG x,
3322 LONG y)
3323 {
3324 PWND pwndParent;
3325 TRACE("Enter NtUserRealChildWindowFromPoint\n");
3326 UserEnterShared();
3327 if ((pwndParent = UserGetWindowObject(Parent)))
3328 {
3329 pwndParent = IntRealChildWindowFromPoint(pwndParent, x, y);
3330 }
3331 UserLeave();
3332 TRACE("Leave NtUserRealChildWindowFromPoint\n");
3333 return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
3334 }
3335
3336 /*
3337 * @implemented
3338 */
3339 BOOL APIENTRY
3340 NtUserSetWindowPos(
3341 HWND hWnd,
3342 HWND hWndInsertAfter,
3343 int X,
3344 int Y,
3345 int cx,
3346 int cy,
3347 UINT uFlags)
3348 {
3349 DECLARE_RETURN(BOOL);
3350 PWND Window, pWndIA;
3351 BOOL ret;
3352 USER_REFERENCE_ENTRY Ref;
3353
3354 TRACE("Enter NtUserSetWindowPos\n");
3355 UserEnterExclusive();
3356
3357 if (!(Window = UserGetWindowObject(hWnd)) ||
3358 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3359 {
3360 ERR("NtUserSetWindowPos bad window handle!\n");
3361 RETURN(FALSE);
3362 }
3363
3364 if ( hWndInsertAfter != HWND_TOP &&
3365 hWndInsertAfter != HWND_BOTTOM &&
3366 hWndInsertAfter != HWND_TOPMOST &&
3367 hWndInsertAfter != HWND_NOTOPMOST )
3368 {
3369 if (!(pWndIA = UserGetWindowObject(hWndInsertAfter)) ||
3370 UserIsDesktopWindow(pWndIA) || UserIsMessageWindow(pWndIA))
3371 {
3372 ERR("NtUserSetWindowPos bad insert window handle!\n");
3373 RETURN(FALSE);
3374 }
3375 }
3376
3377 /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
3378 if (!(uFlags & SWP_NOMOVE))
3379 {
3380 if (X < -32768) X = -32768;
3381 else if (X > 32767) X = 32767;
3382 if (Y < -32768) Y = -32768;
3383 else if (Y > 32767) Y = 32767;
3384 }
3385 if (!(uFlags & SWP_NOSIZE))
3386 {
3387 if (cx < 0) cx = 0;
3388 else if (cx > 32767) cx = 32767;
3389 if (cy < 0) cy = 0;
3390 else if (cy > 32767) cy = 32767;
3391 }
3392
3393 UserRefObjectCo(Window, &Ref);
3394 ret = co_WinPosSetWindowPos(Window, hWndInsertAfter, X, Y, cx, cy, uFlags);
3395 UserDerefObjectCo(Window);
3396
3397 RETURN(ret);
3398
3399 CLEANUP:
3400 TRACE("Leave NtUserSetWindowPos, ret=%i\n",_ret_);
3401 UserLeave();
3402 END_CLEANUP;
3403 }
3404
3405 /*
3406 * @implemented
3407 */
3408 INT APIENTRY
3409 NtUserSetWindowRgn(
3410 HWND hWnd,
3411 HRGN hRgn,
3412 BOOL bRedraw)
3413 {
3414 HRGN hrgnCopy = NULL;
3415 PWND Window;
3416 INT flags = (SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE);
3417 BOOLEAN Ret = FALSE;
3418 DECLARE_RETURN(INT);
3419
3420 TRACE("Enter NtUserSetWindowRgn\n");
3421 UserEnterExclusive();
3422
3423 if (!(Window = UserGetWindowObject(hWnd)) ||
3424 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3425 {
3426 RETURN( 0);
3427 }
3428
3429 if (hRgn) // The region will be deleted in user32.
3430 {
3431 if (GreIsHandleValid(hRgn))
3432 {
3433 hrgnCopy = NtGdiCreateRectRgn(0, 0, 0, 0);
3434 /* The coordinates of a window's window region are relative to the
3435 upper-left corner of the window, not the client area of the window. */
3436 NtGdiCombineRgn( hrgnCopy, hRgn, 0, RGN_COPY);
3437 }
3438 else
3439 RETURN( 0);
3440 }
3441
3442 //// HACK 1 : Work around the lack of supporting DeferWindowPos.
3443 if (hrgnCopy)
3444 {
3445 Window->hrgnNewFrame = hrgnCopy; // Should be PSMWP->acvr->hrgnClip
3446 }
3447 else
3448 {
3449 Window->hrgnNewFrame = HRGN_WINDOW;
3450 }
3451 //// HACK 2
3452 Ret = co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, bRedraw ? flags : (flags|SWP_NOREDRAW) );
3453
3454 RETURN( (INT)Ret);
3455
3456 CLEANUP:
3457 TRACE("Leave NtUserSetWindowRgn, ret=%i\n",_ret_);
3458 UserLeave();
3459 END_CLEANUP;
3460 }
3461
3462 /*
3463 * @implemented
3464 */
3465 DWORD APIENTRY
3466 NtUserSetInternalWindowPos(
3467 HWND hwnd,
3468 UINT showCmd,
3469 LPRECT lprect,
3470 LPPOINT lppt)
3471 {
3472 WINDOWPLACEMENT wndpl;
3473 UINT flags;
3474 PWND Wnd;
3475 RECT rect;
3476 POINT pt = {0};
3477 DECLARE_RETURN(BOOL);
3478 USER_REFERENCE_ENTRY Ref;
3479
3480 TRACE("Enter NtUserSetWindowPlacement\n");
3481 UserEnterExclusive();
3482
3483 if (!(Wnd = UserGetWindowObject(hwnd)) || // FIXME:
3484 UserIsDesktopWindow(Wnd) || UserIsMessageWindow(Wnd))
3485 {
3486 RETURN( FALSE);
3487 }
3488
3489 _SEH2_TRY
3490 {
3491 if (lppt)
3492 {
3493 ProbeForRead(lppt, sizeof(POINT), 1);
3494 RtlCopyMemory(&pt, lppt, sizeof(POINT));
3495 }
3496 if (lprect)
3497 {
3498 ProbeForRead(lprect, sizeof(RECT), 1);
3499 RtlCopyMemory(&rect, lprect, sizeof(RECT));
3500 }
3501 }
3502 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3503 {
3504 SetLastNtError(_SEH2_GetExceptionCode());
3505 _SEH2_YIELD(RETURN( FALSE));
3506 }
3507 _SEH2_END
3508
3509 wndpl.length = sizeof(wndpl);
3510 wndpl.showCmd = showCmd;
3511 wndpl.flags = flags = 0;
3512
3513 if ( lppt )
3514 {
3515 flags |= PLACE_MIN;
3516 wndpl.flags |= WPF_SETMINPOSITION;
3517 wndpl.ptMinPosition = pt;
3518 }
3519 if ( lprect )
3520 {
3521 flags |= PLACE_RECT;
3522 wndpl.rcNormalPosition = rect;
3523 }
3524
3525 UserRefObjectCo(Wnd, &Ref);
3526 IntSetWindowPlacement(Wnd, &wndpl, flags);
3527 UserDerefObjectCo(Wnd);
3528 RETURN(TRUE);
3529
3530 CLEANUP:
3531 TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
3532 UserLeave();
3533 END_CLEANUP;
3534 }
3535
3536 /*
3537 * @implemented
3538 */
3539 BOOL APIENTRY
3540 NtUserSetWindowPlacement(HWND hWnd,
3541 WINDOWPLACEMENT *lpwndpl)
3542 {
3543 PWND Wnd;
3544 WINDOWPLACEMENT Safepl;
3545 UINT Flags;
3546 DECLARE_RETURN(BOOL);
3547 USER_REFERENCE_ENTRY Ref;
3548
3549 TRACE("Enter NtUserSetWindowPlacement\n");
3550 UserEnterExclusive();
3551
3552 if (!(Wnd = UserGetWindowObject(hWnd)) ||
3553 UserIsDesktopWindow(Wnd) || UserIsMessageWindow(Wnd))
3554 {
3555 RETURN( FALSE);
3556 }
3557
3558 _SEH2_TRY
3559 {
3560 ProbeForRead(lpwndpl, sizeof(WINDOWPLACEMENT), 1);
3561 RtlCopyMemory(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3562 }
3563 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3564 {
3565 SetLastNtError(_SEH2_GetExceptionCode());
3566 _SEH2_YIELD(RETURN( FALSE));
3567 }
3568 _SEH2_END
3569
3570 if(Safepl.length != sizeof(WINDOWPLACEMENT))
3571 {
3572 RETURN( FALSE);
3573 }
3574
3575 Flags = PLACE_MAX | PLACE_RECT;
3576 if (Safepl.flags & WPF_SETMINPOSITION) Flags |= PLACE_MIN;
3577 UserRefObjectCo(Wnd, &Ref);
3578 IntSetWindowPlacement(Wnd, &Safepl, Flags);
3579 UserDerefObjectCo(Wnd);
3580 RETURN(TRUE);
3581
3582 CLEANUP:
3583 TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
3584 UserLeave();
3585 END_CLEANUP;
3586 }
3587
3588 /*
3589 * @implemented
3590 */
3591 BOOL APIENTRY
3592 NtUserShowWindowAsync(HWND hWnd, LONG nCmdShow)
3593 {
3594 PWND Window;
3595 BOOL ret;
3596 DECLARE_RETURN(BOOL);
3597 USER_REFERENCE_ENTRY Ref;
3598
3599 TRACE("Enter NtUserShowWindowAsync\n");
3600 UserEnterExclusive();
3601
3602 if (!(Window = UserGetWindowObject(hWnd)) ||
3603 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3604 {
3605 RETURN(FALSE);
3606 }
3607
3608 if ( nCmdShow > SW_MAX )
3609 {
3610 EngSetLastError(ERROR_INVALID_PARAMETER);
3611 RETURN(FALSE);
3612 }
3613
3614 UserRefObjectCo(Window, &Ref);
3615 ret = co_IntSendMessageNoWait( hWnd, WM_ASYNC_SHOWWINDOW, nCmdShow, 0 );
3616 UserDerefObjectCo(Window);
3617 if (-1 == (int) ret || !ret) ret = FALSE;
3618
3619 RETURN(ret);
3620
3621 CLEANUP:
3622 TRACE("Leave NtUserShowWindowAsync, ret=%i\n",_ret_);
3623 UserLeave();
3624 END_CLEANUP;
3625 }
3626
3627 /*
3628 * @implemented
3629 */
3630 BOOL APIENTRY
3631 NtUserShowWindow(HWND hWnd, LONG nCmdShow)
3632 {
3633 PWND Window;
3634 BOOL ret;
3635 DECLARE_RETURN(BOOL);
3636 USER_REFERENCE_ENTRY Ref;
3637
3638 TRACE("Enter NtUserShowWindow hWnd %p SW_ %d\n",hWnd, nCmdShow);
3639 UserEnterExclusive();
3640
3641 if (!(Window = UserGetWindowObject(hWnd)) ||
3642 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3643 {
3644 RETURN(FALSE);
3645 }
3646
3647 if ( nCmdShow > SW_MAX || Window->state2 & WNDS2_INDESTROY)
3648 {
3649 EngSetLastError(ERROR_INVALID_PARAMETER);
3650 RETURN(FALSE);
3651 }
3652
3653 UserRefObjectCo(Window, &Ref);
3654 ret = co_WinPosShowWindow(Window, nCmdShow);
3655 UserDerefObjectCo(Window);
3656
3657 RETURN(ret);
3658
3659 CLEANUP:
3660 TRACE("Leave NtUserShowWindow, ret=%i\n",_ret_);
3661 UserLeave();
3662 END_CLEANUP;
3663 }
3664
3665
3666 /*
3667 * @implemented
3668 */
3669 HWND APIENTRY
3670 NtUserWindowFromPoint(LONG X, LONG Y)
3671 {
3672 POINT pt;
3673 HWND Ret;
3674 PWND DesktopWindow = NULL, Window = NULL;
3675 USHORT hittest;
3676 DECLARE_RETURN(HWND);
3677 USER_REFERENCE_ENTRY Ref;
3678
3679 TRACE("Enter NtUserWindowFromPoint\n");
3680 UserEnterExclusive();
3681
3682 if ((DesktopWindow = UserGetWindowObject(IntGetDesktopWindow())))
3683 {
3684 //PTHREADINFO pti;
3685
3686 pt.x = X;
3687 pt.y = Y;
3688
3689 // Hmm... Threads live on desktops thus we have a reference on the desktop and indirectly the desktop window.
3690 // It is possible this referencing is useless, though it should not hurt...
3691 UserRefObjectCo(DesktopWindow, &Ref);
3692
3693 //pti = PsGetCurrentThreadWin32Thread();
3694 Window = co_WinPosWindowFromPoint(DesktopWindow, &pt, &hittest, FALSE);
3695
3696 if (Window)
3697 {
3698 Ret = UserHMGetHandle(Window);
3699
3700 RETURN( Ret);
3701 }
3702 }
3703
3704 RETURN( NULL);
3705
3706 CLEANUP:
3707 if (DesktopWindow) UserDerefObjectCo(DesktopWindow);
3708
3709 TRACE("Leave NtUserWindowFromPoint, ret=%p\n", _ret_);
3710 UserLeave();
3711 END_CLEANUP;
3712 }
3713
3714 /* EOF */