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