Revert "[SHELL32] SHChangeNotify: Use tree for CDirectoryList (#6784)" (#6800)
[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->ExStyle & WS_EX_APPWINDOW) ||
1908 (!(Window->ExStyle & WS_EX_TOOLWINDOW) && !Window->spwndOwner &&
1909 (!Window->spwndParent || UserIsDesktopWindow(Window->spwndParent))))
1910 {
1911 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)Window->head.h, 0);
1912 if (!(WinPos.flags & SWP_NOACTIVATE))
1913 UpdateShellHook(Window);
1914 }
1915
1916 Window->style |= WS_VISIBLE; //IntSetStyle( Window, WS_VISIBLE, 0 );
1917 Window->head.pti->cVisWindows++;
1918 IntNotifyWinEvent(EVENT_OBJECT_SHOW, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1919 }
1920
1921 if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != HRGN_WINDOW)
1922 {
1923 NtGdiOffsetRgn(Window->hrgnUpdate,
1924 NewWindowRect.left - OldWindowRect.left,
1925 NewWindowRect.top - OldWindowRect.top);
1926 }
1927
1928 DceResetActiveDCEs(Window); // For WS_VISIBLE changes.
1929
1930 // Change or update, set send non-client paint flag.
1931 if ( Window->style & WS_VISIBLE &&
1932 (WinPos.flags & SWP_STATECHANGED || (!(Window->state2 & WNDS2_WIN31COMPAT) && WinPos.flags & SWP_NOREDRAW ) ) )
1933 {
1934 TRACE("Set WNDS_SENDNCPAINT %p\n",Window);
1935 Window->state |= WNDS_SENDNCPAINT;
1936 }
1937
1938 if (!(WinPos.flags & SWP_NOREDRAW))
1939 {
1940 /* Determine the new visible region */
1941 VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1942 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1943
1944 if ( VisAfter != NULL &&
1945 REGION_Complexity(VisAfter) == NULLREGION )
1946 {
1947 REGION_Delete(VisAfter);
1948 VisAfter = NULL;
1949 }
1950 else if(VisAfter)
1951 {
1952 REGION_bOffsetRgn(VisAfter, -Window->rcWindow.left, -Window->rcWindow.top);
1953 }
1954
1955 /*
1956 * Determine which pixels can be copied from the old window position
1957 * to the new. Those pixels must be visible in both the old and new
1958 * position. Also, check the class style to see if the windows of this
1959 * class need to be completely repainted on (horizontal/vertical) size
1960 * change.
1961 */
1962 if ( ( VisBefore != NULL &&
1963 VisAfter != NULL &&
1964 !(WinPos.flags & SWP_NOCOPYBITS) &&
1965 ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) &&
1966 !(Window->ExStyle & WS_EX_TRANSPARENT) ) )
1967 {
1968
1969 /*
1970 * If this is (also) a window resize, the whole nonclient area
1971 * needs to be repainted. So we limit the copy to the client area,
1972 * 'cause there is no use in copying it (would possibly cause
1973 * "flashing" too). However, if the copy region is already empty,
1974 * we don't have to crop (can't take anything away from an empty
1975 * region...)
1976 */
1977
1978 CopyRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
1979 if ((WinPos.flags & SWP_NOSIZE) && (WinPos.flags & SWP_NOCLIENTSIZE))
1980 RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
1981 else if (VisBeforeJustClient != NULL)
1982 {
1983 RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBeforeJustClient, RGN_AND);
1984 }
1985
1986 if (VisBeforeJustClient != NULL)
1987 {
1988 REGION_Delete(VisBeforeJustClient);
1989 }
1990
1991 /* Now use in copying bits which are in the update region. */
1992 if (Window->hrgnUpdate != NULL)
1993 {
1994 PREGION RgnUpdate = REGION_LockRgn(Window->hrgnUpdate);
1995 if (RgnUpdate)
1996 {
1997 REGION_bOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1998 IntGdiCombineRgn(CopyRgn, CopyRgn, RgnUpdate, RGN_DIFF);
1999 REGION_bOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
2000 REGION_UnlockRgn(RgnUpdate);
2001 }
2002 }
2003
2004 /*
2005 * Now, get the bounding box of the copy region. If it's empty
2006 * there's nothing to copy. Also, it's no use copying bits onto
2007 * themselves.
2008 */
2009 if (REGION_GetRgnBox(CopyRgn, &CopyRect) == NULLREGION)
2010 {
2011 /* Nothing to copy, clean up */
2012 REGION_Delete(CopyRgn);
2013 CopyRgn = NULL;
2014 }
2015 else if ( OldWindowRect.left != NewWindowRect.left ||
2016 OldWindowRect.top != NewWindowRect.top ||
2017 (WinPos.flags & SWP_FRAMECHANGED) )
2018 {
2019 HRGN DcRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
2020 PREGION DcRgnObj = REGION_LockRgn(DcRgn);
2021
2022 /*
2023 * Small trick here: there is no function to bitblt a region. So
2024 * we set the region as the clipping region, take the bounding box
2025 * of the region and bitblt that. Since nothing outside the clipping
2026 * region is copied, this has the effect of bitblt'ing the region.
2027 *
2028 * Since NtUserGetDCEx takes ownership of the clip region, we need
2029 * to create a copy of CopyRgn and pass that. We need CopyRgn later
2030 */
2031 IntGdiCombineRgn(DcRgnObj, CopyRgn, NULL, RGN_COPY);
2032 REGION_bOffsetRgn(DcRgnObj, NewWindowRect.left, NewWindowRect.top);
2033 REGION_UnlockRgn(DcRgnObj);
2034 Dc = UserGetDCEx( Window,
2035 DcRgn,
2036 DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN); // DCX_WINDOW will set first, go read WinDC.c.
2037 NtGdiBitBlt( Dc,
2038 CopyRect.left, CopyRect.top,
2039 CopyRect.right - CopyRect.left,
2040 CopyRect.bottom - CopyRect.top,
2041 Dc,
2042 CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
2043 CopyRect.top + (OldWindowRect.top - NewWindowRect.top),
2044 SRCCOPY,
2045 0,
2046 0);
2047
2048 UserReleaseDC(Window, Dc, FALSE);
2049 IntValidateParent(Window, CopyRgn);
2050 GreDeleteObject(DcRgn);
2051 }
2052 }
2053 else
2054 {
2055 CopyRgn = NULL;
2056 }
2057
2058 /* We need to redraw what wasn't visible before or force a redraw */
2059 if (VisAfter != NULL)
2060 {
2061 PREGION DirtyRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
2062 if (DirtyRgn)
2063 {
2064 if (CopyRgn != NULL)
2065 {
2066 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
2067 }
2068 else
2069 {
2070 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
2071 }
2072
2073 if (RgnType != ERROR && RgnType != NULLREGION) // Regions moved.
2074 {
2075 /* old code
2076 NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2077 IntInvalidateWindows( Window,
2078 DirtyRgn,
2079 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2080 }
2081 GreDeleteObject(DirtyRgn);
2082 */
2083
2084 PWND Parent = Window->spwndParent;
2085
2086 REGION_bOffsetRgn( DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2087
2088 if ( (Window->style & WS_CHILD) && (Parent) && !(Parent->style & WS_CLIPCHILDREN))
2089 {
2090 IntInvalidateWindows( Parent, DirtyRgn, RDW_ERASE | RDW_INVALIDATE);
2091 co_IntPaintWindows(Parent, RDW_NOCHILDREN, FALSE);
2092 }
2093 else
2094 {
2095 IntInvalidateWindows( Window, DirtyRgn, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2096 }
2097 }
2098 else if ( RgnType != ERROR && RgnType == NULLREGION ) // Must be the same. See CORE-7166 & CORE-15934, NC HACK fix.
2099 {
2100 if ( !PosChanged &&
2101 !(WinPos.flags & SWP_DEFERERASE) &&
2102 (WinPos.flags & SWP_FRAMECHANGED) )
2103 {
2104 PWND pwnd = Window;
2105 PWND Parent = Window->spwndParent;
2106
2107 if ( pwnd->style & WS_CHILD ) // Fix ProgMan menu bar drawing.
2108 {
2109 TRACE("SWP_FRAMECHANGED win child %p Parent %p\n",pwnd,Parent);
2110 pwnd = Parent ? Parent : pwnd;
2111 }
2112
2113 if ( !(pwnd->style & WS_CHILD) )
2114 {
2115 /*
2116 * Check if we have these specific windows style bits set/reset.
2117 * FIXME: There may be other combinations of styles that need this handling as well.
2118 * This fixes the ReactOS Calculator buttons disappearing in CORE-16827.
2119 */
2120 if ((Window->style & WS_CLIPSIBLINGS) && !(Window->style & (WS_POPUP | WS_CLIPCHILDREN | WS_SIZEBOX)))
2121 {
2122 IntSendNCPaint(pwnd, HRGN_WINDOW); // Paint the whole frame.
2123 }
2124 else // Use region handling
2125 {
2126 HRGN DcRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
2127 PREGION DcRgnObj = REGION_LockRgn(DcRgn);
2128 TRACE("SWP_FRAMECHANGED win %p hRgn %p\n",pwnd, DcRgn);
2129 IntGdiCombineRgn(DcRgnObj, VisBefore, NULL, RGN_COPY);
2130 REGION_UnlockRgn(DcRgnObj);
2131 ForceNCPaintErase(pwnd, DcRgn, DcRgnObj);
2132 GreDeleteObject(DcRgn);
2133 }
2134 }
2135 }
2136 }
2137 REGION_Delete(DirtyRgn);
2138 }
2139 }
2140
2141 if (CopyRgn != NULL)
2142 {
2143 REGION_Delete(CopyRgn);
2144 }
2145
2146 /* Expose what was covered before but not covered anymore */
2147 if ( VisBefore != NULL )
2148 {
2149 PREGION ExposedRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
2150 if (ExposedRgn)
2151 {
2152 RgnType = IntGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
2153 REGION_bOffsetRgn(ExposedRgn,
2154 OldWindowRect.left - NewWindowRect.left,
2155 OldWindowRect.top - NewWindowRect.top);
2156
2157 if ( VisAfter != NULL )
2158 RgnType = IntGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
2159
2160 if (RgnType != ERROR && RgnType != NULLREGION)
2161 {
2162 co_VIS_WindowLayoutChanged(Window, ExposedRgn);
2163 }
2164 REGION_Delete(ExposedRgn);
2165 }
2166 REGION_Delete(VisBefore);
2167 }
2168
2169 if (VisAfter != NULL)
2170 {
2171 REGION_Delete(VisAfter);
2172 }
2173 }
2174
2175 if (!(WinPos.flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
2176 {
2177 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2178 {
2179 co_IntSendMessageNoWait(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
2180 }
2181 else
2182 {
2183 //ERR("SetWindowPos Set FG Window!\n");
2184 if ( pti->MessageQueue->spwndActive != Window ||
2185 pti->MessageQueue != gpqForeground )
2186 {
2187 //ERR("WPSWP : set active window\n");
2188 if (!(Window->state & WNDS_BEINGACTIVATED)) // Inside SAW?
2189 {
2190 co_IntSetForegroundWindow(Window); // Fixes SW_HIDE issues. Wine win test_SetActiveWindow & test_SetForegroundWindow.
2191 }
2192 }
2193 }
2194 }
2195
2196 if ( !PosChanged &&
2197 (WinPos.flags & SWP_FRAMECHANGED) &&
2198 !(WinPos.flags & SWP_DEFERERASE) && // Prevent sending WM_SYNCPAINT message.
2199 VisAfter )
2200 {
2201 PWND Parent = Window->spwndParent;
2202 if ( !(Window->style & WS_CHILD) && (Parent) && (Parent->style & WS_CLIPCHILDREN))
2203 {
2204 TRACE("SWP_FRAMECHANGED Parent %p WS_CLIPCHILDREN %p\n",Parent,Window);
2205 UserSyncAndPaintWindows( Parent, RDW_CLIPCHILDREN); // NC should redraw here, see NC HACK fix.
2206 }
2207 }
2208
2209 // Fix wine msg test_SetFocus, prevents sending WM_WINDOWPOSCHANGED.
2210 if ( VisBefore == NULL &&
2211 VisBeforeJustClient == NULL &&
2212 !(Window->ExStyle & WS_EX_TOPMOST) &&
2213 (WinPos.flags & SWP_AGG_STATUSFLAGS) == (SWP_AGG_NOPOSCHANGE & ~SWP_NOZORDER))
2214 {
2215 TRACE("No drawing, set no Z order and no redraw!\n");
2216 WinPos.flags |= SWP_NOZORDER|SWP_NOREDRAW;
2217 }
2218
2219 if(!(flags & SWP_DEFERERASE))
2220 {
2221 /* erase parent when hiding or resizing child */
2222 if ((flags & SWP_HIDEWINDOW) ||
2223 (!(flags & SWP_SHOWWINDOW) &&
2224 (WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOGEOMETRYCHANGE))
2225 {
2226 PWND Parent = Window->spwndParent;
2227 if (!Parent || UserIsDesktopWindow(Parent)) Parent = Window;
2228 UserSyncAndPaintWindows( Parent, RDW_ERASENOW);
2229 }
2230
2231 /* Give newly shown windows a chance to redraw */
2232 if(((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2233 && !(flags & SWP_AGG_NOCLIENTCHANGE) && (flags & SWP_SHOWWINDOW))
2234 {
2235 UserSyncAndPaintWindows( Window, RDW_ERASENOW);
2236 }
2237 }
2238
2239 /* And last, send the WM_WINDOWPOSCHANGED message */
2240
2241 TRACE("\tstatus hwnd %p flags = %04x\n",Window?Window->head.h:NULL,WinPos.flags & SWP_AGG_STATUSFLAGS);
2242
2243 if (((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2244 && !((flags & SWP_AGG_NOCLIENTCHANGE) && (flags & SWP_SHOWWINDOW)))
2245 {
2246 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
2247 and always contains final window position.
2248 */
2249 WinPos.x = NewWindowRect.left;
2250 WinPos.y = NewWindowRect.top;
2251 WinPos.cx = NewWindowRect.right - NewWindowRect.left;
2252 WinPos.cy = NewWindowRect.bottom - NewWindowRect.top;
2253 TRACE("WM_WINDOWPOSCHANGED hwnd %p Flags %04x\n",WinPos.hwnd,WinPos.flags);
2254 co_IntSendMessageNoWait(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
2255 }
2256
2257 if ( WinPos.flags & SWP_FRAMECHANGED || WinPos.flags & SWP_STATECHANGED ||
2258 !(WinPos.flags & SWP_NOCLIENTSIZE) || !(WinPos.flags & SWP_NOCLIENTMOVE) )
2259 {
2260 PWND pWnd = ValidateHwndNoErr(WinPos.hwnd);
2261 if (pWnd)
2262 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2263 }
2264
2265 if(bPointerInWindow != IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y))
2266 {
2267 /* Generate mouse move message */
2268 MSG msg;
2269 msg.message = WM_MOUSEMOVE;
2270 msg.wParam = UserGetMouseButtonsState();
2271 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2272 msg.pt = gpsi->ptCursor;
2273 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2274 }
2275
2276 return TRUE;
2277 }
2278
2279 LRESULT FASTCALL
2280 co_WinPosGetNonClientSize(PWND Window, RECT* WindowRect, RECT* ClientRect)
2281 {
2282 LRESULT Result;
2283
2284 ASSERT_REFS_CO(Window);
2285
2286 *ClientRect = *WindowRect;
2287 Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect);
2288
2289 FixClientRect(ClientRect, WindowRect);
2290
2291 return Result;
2292 }
2293
2294 void FASTCALL
2295 co_WinPosSendSizeMove(PWND Wnd)
2296 {
2297 RECTL Rect;
2298 LPARAM lParam;
2299 WPARAM wParam = SIZE_RESTORED;
2300
2301 IntGetClientRect(Wnd, &Rect);
2302 lParam = MAKELONG(Rect.right-Rect.left, Rect.bottom-Rect.top);
2303
2304 Wnd->state &= ~WNDS_SENDSIZEMOVEMSGS;
2305
2306 if (Wnd->style & WS_MAXIMIZE)
2307 {
2308 wParam = SIZE_MAXIMIZED;
2309 }
2310 else if (Wnd->style & WS_MINIMIZE)
2311 {
2312 wParam = SIZE_MINIMIZED;
2313 lParam = 0;
2314 }
2315
2316 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SIZE, wParam, lParam);
2317
2318 if (UserIsDesktopWindow(Wnd->spwndParent))
2319 lParam = MAKELONG(Wnd->rcClient.left, Wnd->rcClient.top);
2320 else
2321 lParam = MAKELONG(Wnd->rcClient.left-Wnd->spwndParent->rcClient.left, Wnd->rcClient.top-Wnd->spwndParent->rcClient.top);
2322
2323 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_MOVE, 0, lParam);
2324
2325 IntEngWindowChanged(Wnd, WOC_RGN_CLIENT);
2326 }
2327
2328 UINT FASTCALL
2329 co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos)
2330 {
2331 POINT Size;
2332 WINDOWPLACEMENT wpl;
2333 LONG old_style;
2334 UINT SwpFlags = 0;
2335
2336 ASSERT_REFS_CO(Wnd);
2337
2338 wpl.length = sizeof(wpl);
2339 IntGetWindowPlacement( Wnd, &wpl );
2340
2341 if (co_HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)Wnd->head.h, ShowFlag))
2342 {
2343 ERR("WinPosMinMaximize WH_CBT Call Hook return!\n");
2344 return SWP_NOSIZE | SWP_NOMOVE;
2345 }
2346 if (Wnd->style & WS_MINIMIZE)
2347 {
2348 switch (ShowFlag)
2349 {
2350 case SW_MINIMIZE:
2351 case SW_SHOWMINNOACTIVE:
2352 case SW_SHOWMINIMIZED:
2353 case SW_FORCEMINIMIZE:
2354 return SWP_NOSIZE | SWP_NOMOVE;
2355 }
2356 if (!co_IntSendMessageNoWait(Wnd->head.h, WM_QUERYOPEN, 0, 0))
2357 {
2358 return(SWP_NOSIZE | SWP_NOMOVE);
2359 }
2360 SwpFlags |= SWP_NOCOPYBITS;
2361 }
2362 switch (ShowFlag)
2363 {
2364 case SW_MINIMIZE:
2365 case SW_SHOWMINNOACTIVE:
2366 case SW_SHOWMINIMIZED:
2367 case SW_FORCEMINIMIZE:
2368 {
2369 //ERR("MinMaximize Minimize\n");
2370 if (Wnd->style & WS_MAXIMIZE)
2371 {
2372 Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED;
2373 }
2374 else
2375 {
2376 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2377 }
2378
2379 old_style = IntSetStyle( Wnd, WS_MINIMIZE, WS_MAXIMIZE );
2380
2381 co_UserRedrawWindow(Wnd, NULL, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOINTERNALPAINT);
2382
2383 if (!(Wnd->InternalPos.flags & WPF_SETMINPOSITION))
2384 Wnd->InternalPos.flags &= ~WPF_MININIT;
2385
2386 WinPosFindIconPos(Wnd, &wpl.ptMinPosition);
2387
2388 if (!(old_style & WS_MINIMIZE))
2389 {
2390 SwpFlags |= SWP_STATECHANGED;
2391 IntShowOwnedPopups(Wnd, FALSE);
2392 }
2393
2394 RECTL_vSetRect(NewPos, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
2395 wpl.ptMinPosition.x + UserGetSystemMetrics(SM_CXMINIMIZED),
2396 wpl.ptMinPosition.y + UserGetSystemMetrics(SM_CYMINIMIZED));
2397 SwpFlags |= SWP_NOCOPYBITS;
2398 break;
2399 }
2400
2401 case SW_MAXIMIZE:
2402 {
2403 //ERR("MinMaximize Maximize\n");
2404 if ((Wnd->style & WS_MAXIMIZE) && (Wnd->style & WS_VISIBLE))
2405 {
2406 SwpFlags = SWP_NOSIZE | SWP_NOMOVE;
2407 break;
2408 }
2409 co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
2410
2411 /*ERR("Maximize: %d,%d %dx%d\n",
2412 wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, Size.x, Size.y);
2413 */
2414 old_style = IntSetStyle( Wnd, WS_MAXIMIZE, WS_MINIMIZE );
2415 /*if (old_style & WS_MINIMIZE)
2416 {
2417 IntShowOwnedPopups(Wnd, TRUE);
2418 }*/
2419
2420 if (!(old_style & WS_MAXIMIZE)) SwpFlags |= SWP_STATECHANGED;
2421 RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
2422 //wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
2423 Size.x, Size.y);
2424 break;
2425 }
2426
2427 case SW_SHOWNOACTIVATE:
2428 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2429 /* fall through */
2430 case SW_SHOWNORMAL:
2431 case SW_RESTORE:
2432 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
2433 {
2434 //ERR("MinMaximize Restore\n");
2435 old_style = IntSetStyle( Wnd, 0, WS_MINIMIZE | WS_MAXIMIZE );
2436 if (old_style & WS_MINIMIZE)
2437 {
2438 IntShowOwnedPopups(Wnd, TRUE);
2439
2440 if (Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED)
2441 {
2442 co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
2443 IntSetStyle( Wnd, WS_MAXIMIZE, 0 );
2444 SwpFlags |= SWP_STATECHANGED;
2445 RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
2446 wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
2447 break;
2448 }
2449 else
2450 {
2451 *NewPos = wpl.rcNormalPosition;
2452 NewPos->right -= NewPos->left;
2453 NewPos->bottom -= NewPos->top;
2454 break;
2455 }
2456 }
2457 else
2458 {
2459 if (!(old_style & WS_MAXIMIZE))
2460 {
2461 break;
2462 }
2463 SwpFlags |= SWP_STATECHANGED;
2464 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2465 *NewPos = wpl.rcNormalPosition;
2466 NewPos->right -= NewPos->left;
2467 NewPos->bottom -= NewPos->top;
2468 break;
2469 }
2470 }
2471 }
2472 return SwpFlags;
2473 }
2474
2475 /*
2476 ShowWindow does not set SWP_FRAMECHANGED!!! Fix wine msg test_SetParent:WmSetParentSeq_2:23 wParam bits!
2477 */
2478 BOOLEAN FASTCALL
2479 co_WinPosShowWindow(PWND Wnd, INT Cmd)
2480 {
2481 BOOLEAN WasVisible;
2482 UINT Swp = 0, EventMsg = 0;
2483 RECTL NewPos = {0, 0, 0, 0};
2484 BOOLEAN ShowFlag;
2485 LONG style;
2486 PWND Parent;
2487 PTHREADINFO pti;
2488 //HRGN VisibleRgn;
2489 BOOL ShowOwned = FALSE;
2490 BOOL FirstTime = FALSE;
2491 ASSERT_REFS_CO(Wnd);
2492 //KeRosDumpStackFrames(NULL, 20);
2493 pti = PsGetCurrentThreadWin32Thread();
2494 WasVisible = (Wnd->style & WS_VISIBLE) != 0;
2495 style = Wnd->style;
2496
2497 TRACE("co_WinPosShowWindow START hwnd %p Cmd %d usicmd %u\n",
2498 Wnd->head.h, Cmd, pti->ppi->usi.wShowWindow);
2499
2500 if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW )
2501 {
2502 if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2503 {
2504 if ((Wnd->style & WS_CAPTION) == WS_CAPTION)
2505 {
2506 if (Wnd->spwndOwner == NULL)
2507 {
2508 if ( Cmd == SW_SHOWNORMAL || Cmd == SW_SHOW)
2509 {
2510 Cmd = SW_SHOWDEFAULT;
2511 }
2512 FirstTime = TRUE;
2513 TRACE("co_WPSW FT 1\n");
2514 }
2515 }
2516 }
2517 }
2518
2519 if ( Cmd == SW_SHOWDEFAULT )
2520 {
2521 if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW )
2522 {
2523 Cmd = pti->ppi->usi.wShowWindow;
2524 FirstTime = TRUE;
2525 TRACE("co_WPSW FT 2\n");
2526 }
2527 }
2528
2529 if (FirstTime)
2530 {
2531 pti->ppi->usi.dwFlags &= ~(STARTF_USEPOSITION|STARTF_USESIZE|STARTF_USESHOWWINDOW);
2532 }
2533
2534 switch (Cmd)
2535 {
2536 case SW_HIDE:
2537 {
2538 if (!WasVisible)
2539 {
2540 //ERR("co_WinPosShowWindow Exit Bad\n");
2541 return FALSE;
2542 }
2543 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2544 if (Wnd != pti->MessageQueue->spwndActive)
2545 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2546 break;
2547 }
2548
2549 case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
2550 case SW_SHOWMINNOACTIVE:
2551 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2552 /* Fall through. */
2553 case SW_SHOWMINIMIZED:
2554 Swp |= SWP_SHOWWINDOW;
2555 /* Fall through. */
2556 case SW_MINIMIZE:
2557 {
2558 Swp |= SWP_NOACTIVATE;
2559 if (!(style & WS_MINIMIZE))
2560 {
2561 IntShowOwnedPopups(Wnd, FALSE );
2562 // Fix wine Win test_SetFocus todo #1 & #2,
2563 if (Cmd == SW_SHOWMINIMIZED)
2564 {
2565 //ERR("co_WinPosShowWindow Set focus 1\n");
2566 if ((style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2567 co_UserSetFocus(Wnd->spwndParent);
2568 else
2569 co_UserSetFocus(0);
2570 }
2571
2572 Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos);
2573
2574 EventMsg = EVENT_SYSTEM_MINIMIZESTART;
2575 }
2576 else
2577 {
2578 if (WasVisible)
2579 {
2580 //ERR("co_WinPosShowWindow Exit Good\n");
2581 return TRUE;
2582 }
2583 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2584 }
2585 break;
2586 }
2587
2588 case SW_SHOWMAXIMIZED:
2589 {
2590 Swp |= SWP_SHOWWINDOW;
2591 if (!(style & WS_MAXIMIZE))
2592 {
2593 ShowOwned = TRUE;
2594
2595 Swp |= co_WinPosMinMaximize(Wnd, SW_MAXIMIZE, &NewPos);
2596
2597 EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2598 }
2599 else
2600 {
2601 if (WasVisible)
2602 {
2603 //ERR("co_WinPosShowWindow Exit Good 1\n");
2604 return TRUE;
2605 }
2606 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2607 }
2608 break;
2609 }
2610
2611 case SW_SHOWNA:
2612 Swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2613 if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOZORDER;
2614 break;
2615 case SW_SHOW:
2616 if (WasVisible) return(TRUE); // Nothing to do!
2617 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2618 /* Don't activate the topmost window. */
2619 if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2620 break;
2621
2622 case SW_SHOWNOACTIVATE:
2623 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2624 /* Fall through. */
2625 case SW_SHOWNORMAL:
2626 case SW_SHOWDEFAULT:
2627 case SW_RESTORE:
2628 if (!WasVisible) Swp |= SWP_SHOWWINDOW;
2629 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2630 {
2631 Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos);
2632 if (style & WS_MINIMIZE) EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2633 }
2634 else
2635 {
2636 if (WasVisible)
2637 {
2638 //ERR("co_WinPosShowWindow Exit Good 3\n");
2639 return TRUE;
2640 }
2641 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2642 }
2643 if ( style & WS_CHILD &&
2644 !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2645 !(Swp & SWP_STATECHANGED))
2646 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2647 break;
2648
2649 default:
2650 //ERR("co_WinPosShowWindow Exit Good 4\n");
2651 return WasVisible;
2652 }
2653
2654 ShowFlag = (Cmd != SW_HIDE);
2655
2656 if ((ShowFlag != WasVisible || Cmd == SW_SHOWNA) && Cmd != SW_SHOWMAXIMIZED && !(Swp & SWP_STATECHANGED))
2657 {
2658 co_IntSendMessageNoWait(Wnd->head.h, WM_SHOWWINDOW, ShowFlag, 0);
2659 #if 0 // Fix wine msg test_SetParent:WmSetParentSeq_1:2
2660 if (!(Wnd->state2 & WNDS2_WIN31COMPAT)) // <------------- XP sets this bit!
2661 co_IntSendMessageNoWait(Wnd->head.h, WM_SETVISIBLE, ShowFlag, 0);
2662 #endif
2663 if (!VerifyWnd(Wnd)) return WasVisible;
2664 }
2665
2666 /* We can't activate a child window */
2667 if ((Wnd->style & WS_CHILD) &&
2668 !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2669 Cmd != SW_SHOWNA)
2670 {
2671 //ERR("SWP Child No active and ZOrder\n");
2672 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2673 }
2674
2675 #if 0 // Explorer issues with common controls? Someone does not know how CS_SAVEBITS works.
2676 // Breaks startup and shutdown active window...
2677 if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
2678 Wnd->pcls->style & CS_SAVEBITS &&
2679 ((Cmd == SW_SHOW) || (Cmd == SW_NORMAL)))
2680 {
2681 ERR("WinPosShowWindow Set active\n");
2682 //UserSetActiveWindow(Wnd);
2683 co_IntSetForegroundWindow(Wnd); // HACK
2684 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2685 }
2686 #endif
2687
2688 if (IsChildVisible(Wnd) || Swp & SWP_STATECHANGED)
2689 {
2690 TRACE("Child is Vis %s or State changed %s. ShowFlag %s Swp %04x\n",
2691 (IsChildVisible(Wnd) ? "TRUE" : "FALSE"), (Swp & SWP_STATECHANGED ? "TRUE" : "FALSE"),
2692 (ShowFlag ? "TRUE" : "FALSE"),LOWORD(Swp));
2693 co_WinPosSetWindowPos( Wnd,
2694 0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP,
2695 NewPos.left,
2696 NewPos.top,
2697 NewPos.right, // NewPos.right - NewPos.left, when minimized and restore, the window becomes smaller.
2698 NewPos.bottom,// NewPos.bottom - NewPos.top,
2699 LOWORD(Swp));
2700 }
2701 else
2702 {
2703 TRACE("Parent Vis?\n");
2704 /* if parent is not visible simply toggle WS_VISIBLE and return */
2705 if (ShowFlag) IntSetStyle( Wnd, WS_VISIBLE, 0 );
2706 else IntSetStyle( Wnd, 0, WS_VISIBLE );
2707 }
2708
2709 if ( EventMsg ) IntNotifyWinEvent(EventMsg, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2710
2711 if ( ShowOwned ) IntShowOwnedPopups(Wnd, TRUE );
2712
2713 if ((Cmd == SW_HIDE) || (Cmd == SW_MINIMIZE))
2714 {
2715 if ( Wnd == pti->MessageQueue->spwndActive && pti->MessageQueue == IntGetFocusMessageQueue() )
2716 {
2717 if (UserIsDesktopWindow(Wnd->spwndParent))
2718 {
2719 if (!ActivateOtherWindowMin(Wnd))
2720 {
2721 co_WinPosActivateOtherWindow(Wnd);
2722 }
2723 }
2724 else
2725 {
2726 co_WinPosActivateOtherWindow(Wnd);
2727 }
2728 }
2729
2730 /* Revert focus to parent */
2731 if (Wnd == pti->MessageQueue->spwndFocus)
2732 {
2733 Parent = Wnd->spwndParent;
2734 if (UserIsDesktopWindow(Wnd->spwndParent))
2735 Parent = 0;
2736 co_UserSetFocus(Parent);
2737 }
2738 // Hide, just return.
2739 if (Cmd == SW_HIDE) return WasVisible;
2740 }
2741
2742 /* FIXME: Check for window destruction. */
2743
2744 if ((Wnd->state & WNDS_SENDSIZEMOVEMSGS) &&
2745 !(Wnd->state2 & WNDS2_INDESTROY))
2746 {
2747 co_WinPosSendSizeMove(Wnd);
2748 }
2749
2750 /* if previous state was minimized Windows sets focus to the window */
2751 if (style & WS_MINIMIZE)
2752 {
2753 co_UserSetFocus(Wnd);
2754 // Fix wine Win test_SetFocus todo #3,
2755 if (!(style & WS_CHILD)) co_IntSendMessage(UserHMGetHandle(Wnd), WM_ACTIVATE, WA_ACTIVE, 0);
2756 }
2757 //ERR("co_WinPosShowWindow EXIT\n");
2758 return WasVisible;
2759 }
2760
2761 static PWND
2762 co_WinPosSearchChildren(
2763 IN PWND ScopeWin,
2764 IN POINT *Point,
2765 IN OUT USHORT *HitTest,
2766 IN BOOL Ignore
2767 )
2768 {
2769 HWND *List, *phWnd;
2770 PWND pwndChild = NULL;
2771
2772 /* not visible */
2773 if (!(ScopeWin->style & WS_VISIBLE))
2774 {
2775 return NULL;
2776 }
2777
2778 /* not in window or in window region */
2779 if (!IntPtInWindow(ScopeWin, Point->x, Point->y))
2780 {
2781 return NULL;
2782 }
2783
2784 /* transparent */
2785 if ((ScopeWin->ExStyle & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT))
2786 {
2787 return NULL;
2788 }
2789
2790 if (!Ignore && (ScopeWin->style & WS_DISABLED))
2791 { /* disabled child */
2792 if ((ScopeWin->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return NULL;
2793 /* process the hit error */
2794 *HitTest = HTERROR;
2795 return ScopeWin;
2796 }
2797
2798 /* not minimized and check if point is inside the window */
2799 if (!(ScopeWin->style & WS_MINIMIZE) &&
2800 RECTL_bPointInRect(&ScopeWin->rcClient, Point->x, Point->y) )
2801 {
2802 UserReferenceObject(ScopeWin);
2803
2804 List = IntWinListChildren(ScopeWin);
2805 if (List)
2806 {
2807 for (phWnd = List; *phWnd; ++phWnd)
2808 {
2809 if (!(pwndChild = ValidateHwndNoErr(*phWnd)))
2810 {
2811 continue;
2812 }
2813
2814 pwndChild = co_WinPosSearchChildren(pwndChild, Point, HitTest, Ignore);
2815
2816 if (pwndChild != NULL)
2817 {
2818 /* We found a window. Don't send any more WM_NCHITTEST messages */
2819 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2820 UserDereferenceObject(ScopeWin);
2821 return pwndChild;
2822 }
2823 }
2824 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2825 }
2826 UserDereferenceObject(ScopeWin);
2827 }
2828
2829 if (ScopeWin->head.pti == PsGetCurrentThreadWin32Thread())
2830 {
2831 *HitTest = (USHORT)co_IntSendMessage(ScopeWin->head.h, WM_NCHITTEST, 0, MAKELONG(Point->x, Point->y));
2832
2833 if ((*HitTest) == (USHORT)HTTRANSPARENT)
2834 {
2835 return NULL;
2836 }
2837 }
2838 else
2839 {
2840 if (*HitTest == HTNOWHERE && pwndChild == NULL) *HitTest = HTCLIENT;
2841 }
2842
2843 return ScopeWin;
2844 }
2845
2846 PWND APIENTRY
2847 co_WinPosWindowFromPoint(
2848 IN PWND ScopeWin,
2849 IN POINT *WinPoint,
2850 IN OUT USHORT* HitTest,
2851 IN BOOL Ignore)
2852 {
2853 PWND Window;
2854 POINT Point = *WinPoint;
2855 USER_REFERENCE_ENTRY Ref;
2856
2857 if( ScopeWin == NULL )
2858 {
2859 ScopeWin = UserGetDesktopWindow();
2860 if(ScopeWin == NULL)
2861 return NULL;
2862 }
2863
2864 *HitTest = HTNOWHERE;
2865
2866 ASSERT_REFS_CO(ScopeWin);
2867 UserRefObjectCo(ScopeWin, &Ref);
2868
2869 Window = co_WinPosSearchChildren(ScopeWin, &Point, HitTest, Ignore);
2870
2871 UserDerefObjectCo(ScopeWin);
2872 if (Window)
2873 ASSERT_REFS_CO(Window);
2874 ASSERT_REFS_CO(ScopeWin);
2875
2876 return Window;
2877 }
2878
2879 PWND FASTCALL
2880 IntRealChildWindowFromPoint(PWND Parent, LONG x, LONG y)
2881 {
2882 POINTL Pt;
2883 HWND *List, *phWnd;
2884 PWND pwndHit = NULL;
2885
2886 Pt.x = x;
2887 Pt.y = y;
2888
2889 if (!UserIsDesktopWindow(Parent))
2890 {
2891 Pt.x += Parent->rcClient.left;
2892 Pt.y += Parent->rcClient.top;
2893 }
2894
2895 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2896
2897 if ((List = IntWinListChildren(Parent)))
2898 {
2899 for (phWnd = List; *phWnd; phWnd++)
2900 {
2901 PWND Child;
2902 if ((Child = ValidateHwndNoErr(*phWnd)))
2903 {
2904 if ( Child->style & WS_VISIBLE && IntPtInWindow(Child, Pt.x, Pt.y) )
2905 {
2906 if ( Child->pcls->atomClassName != gpsi->atomSysClass[ICLS_BUTTON] ||
2907 (Child->style & BS_TYPEMASK) != BS_GROUPBOX )
2908 {
2909 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2910 return Child;
2911 }
2912 pwndHit = Child;
2913 }
2914 }
2915 }
2916 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2917 }
2918 return pwndHit ? pwndHit : Parent;
2919 }
2920
2921 PWND APIENTRY
2922 IntChildWindowFromPointEx(PWND Parent, LONG x, LONG y, UINT uiFlags)
2923 {
2924 POINTL Pt;
2925 HWND *List, *phWnd;
2926 PWND pwndHit = NULL;
2927
2928 Pt.x = x;
2929 Pt.y = y;
2930
2931 if (!UserIsDesktopWindow(Parent))
2932 {
2933 if (Parent->ExStyle & WS_EX_LAYOUTRTL)
2934 Pt.x = Parent->rcClient.right - Pt.x;
2935 else
2936 Pt.x += Parent->rcClient.left;
2937 Pt.y += Parent->rcClient.top;
2938 }
2939
2940 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2941
2942 if ((List = IntWinListChildren(Parent)))
2943 {
2944 for (phWnd = List; *phWnd; phWnd++)
2945 {
2946 PWND Child;
2947 if ((Child = ValidateHwndNoErr(*phWnd)))
2948 {
2949 if (uiFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
2950 {
2951 if (!(Child->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE)) continue;
2952 if ((Child->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED)) continue;
2953 }
2954
2955 if (uiFlags & CWP_SKIPTRANSPARENT)
2956 {
2957 if (Child->ExStyle & WS_EX_TRANSPARENT) continue;
2958 }
2959
2960 if (IntPtInWindow(Child, Pt.x, Pt.y))
2961 {
2962 pwndHit = Child;
2963 break;
2964 }
2965 }
2966 }
2967 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2968 }
2969 return pwndHit ? pwndHit : Parent;
2970 }
2971
2972 HDWP
2973 FASTCALL
2974 IntDeferWindowPos( HDWP hdwp,
2975 HWND hwnd,
2976 HWND hwndAfter,
2977 INT x,
2978 INT y,
2979 INT cx,
2980 INT cy,
2981 UINT flags )
2982 {
2983 PSMWP pDWP;
2984 int i;
2985 HDWP retvalue = hdwp;
2986
2987 TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2988 hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
2989
2990 if (flags & ~(SWP_NOSIZE | SWP_NOMOVE |
2991 SWP_NOZORDER | SWP_NOREDRAW |
2992 SWP_NOACTIVATE | SWP_NOCOPYBITS |
2993 SWP_NOOWNERZORDER|SWP_SHOWWINDOW |
2994 SWP_HIDEWINDOW | SWP_FRAMECHANGED))
2995 {
2996 EngSetLastError(ERROR_INVALID_PARAMETER);
2997 return NULL;
2998 }
2999
3000 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
3001 {
3002 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
3003 return NULL;
3004 }
3005
3006 for (i = 0; i < pDWP->ccvr; i++)
3007 {
3008 if (pDWP->acvr[i].pos.hwnd == hwnd)
3009 {
3010 /* Merge with the other changes */
3011 if (!(flags & SWP_NOZORDER))
3012 {
3013 pDWP->acvr[i].pos.hwndInsertAfter = hwndAfter;
3014 }
3015 if (!(flags & SWP_NOMOVE))
3016 {
3017 pDWP->acvr[i].pos.x = x;
3018 pDWP->acvr[i].pos.y = y;
3019 }
3020 if (!(flags & SWP_NOSIZE))
3021 {
3022 pDWP->acvr[i].pos.cx = cx;
3023 pDWP->acvr[i].pos.cy = cy;
3024 }
3025 pDWP->acvr[i].pos.flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
3026 SWP_NOZORDER | SWP_NOREDRAW |
3027 SWP_NOACTIVATE | SWP_NOCOPYBITS|
3028 SWP_NOOWNERZORDER);
3029 pDWP->acvr[i].pos.flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
3030 SWP_FRAMECHANGED);
3031 goto END;
3032 }
3033 }
3034 if (pDWP->ccvr >= pDWP->ccvrAlloc)
3035 {
3036 PCVR newpos = ExAllocatePoolWithTag(PagedPool, pDWP->ccvrAlloc * 2 * sizeof(CVR), USERTAG_SWP);
3037 if (!newpos)
3038 {
3039 retvalue = NULL;
3040 goto END;
3041 }
3042 RtlZeroMemory(newpos, pDWP->ccvrAlloc * 2 * sizeof(CVR));
3043 RtlCopyMemory(newpos, pDWP->acvr, pDWP->ccvrAlloc * sizeof(CVR));
3044 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
3045 pDWP->ccvrAlloc *= 2;
3046 pDWP->acvr = newpos;
3047 }
3048 pDWP->acvr[pDWP->ccvr].pos.hwnd = hwnd;
3049 pDWP->acvr[pDWP->ccvr].pos.hwndInsertAfter = hwndAfter;
3050 pDWP->acvr[pDWP->ccvr].pos.x = x;
3051 pDWP->acvr[pDWP->ccvr].pos.y = y;
3052 pDWP->acvr[pDWP->ccvr].pos.cx = cx;
3053 pDWP->acvr[pDWP->ccvr].pos.cy = cy;
3054 pDWP->acvr[pDWP->ccvr].pos.flags = flags;
3055 pDWP->acvr[pDWP->ccvr].hrgnClip = NULL;
3056 pDWP->acvr[pDWP->ccvr].hrgnInterMonitor = NULL;
3057 pDWP->ccvr++;
3058 END:
3059 return retvalue;
3060 }
3061
3062 BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp, BOOL sAsync )
3063 {
3064 PSMWP pDWP;
3065 PCVR winpos;
3066 BOOL res = TRUE;
3067 int i;
3068
3069 TRACE("%p\n", hdwp);
3070
3071 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
3072 {
3073 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
3074 return FALSE;
3075 }
3076
3077 for (i = 0, winpos = pDWP->acvr; res && i < pDWP->ccvr; i++, winpos++)
3078 {
3079 PWND pwnd;
3080 USER_REFERENCE_ENTRY Ref;
3081
3082 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
3083 winpos->pos.hwnd, winpos->pos.hwndInsertAfter, winpos->pos.x, winpos->pos.y,
3084 winpos->pos.cx, winpos->pos.cy, winpos->pos.flags);
3085
3086 pwnd = ValidateHwndNoErr(winpos->pos.hwnd);
3087 if (!pwnd)
3088 continue;
3089
3090 UserRefObjectCo(pwnd, &Ref);
3091
3092 if ( sAsync )
3093 {
3094 LRESULT lRes;
3095 PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
3096 if ( ppos )
3097 {
3098 *ppos = winpos->pos;
3099 /* Yes it's a pointer inside Win32k! */
3100 lRes = co_IntSendMessageNoWait( winpos->pos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
3101 /* We handle this the same way as Event Hooks and Hooks. */
3102 if ( !lRes )
3103 {
3104 ExFreePoolWithTag(ppos, USERTAG_SWP);
3105 }
3106 }
3107 }
3108 else
3109 res = co_WinPosSetWindowPos( pwnd,
3110 winpos->pos.hwndInsertAfter,
3111 winpos->pos.x,
3112 winpos->pos.y,
3113 winpos->pos.cx,
3114 winpos->pos.cy,
3115 winpos->pos.flags);
3116
3117 // Hack to pass tests.... Must have some work to do so clear the error.
3118 if (res && (winpos->pos.flags & (SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER)) == SWP_NOZORDER )
3119 EngSetLastError(ERROR_SUCCESS);
3120
3121 UserDerefObjectCo(pwnd);
3122 }
3123 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
3124 UserDereferenceObject(pDWP);
3125 UserDeleteObject(hdwp, TYPE_SETWINDOWPOS);
3126 return res;
3127 }
3128
3129 /*
3130 * @implemented
3131 */
3132 HWND APIENTRY
3133 NtUserChildWindowFromPointEx(HWND hwndParent,
3134 LONG x,
3135 LONG y,
3136 UINT uiFlags)
3137 {
3138 PWND pwndParent;
3139 TRACE("Enter NtUserChildWindowFromPointEx\n");
3140 UserEnterExclusive();
3141 if ((pwndParent = UserGetWindowObject(hwndParent)))
3142 {
3143 pwndParent = IntChildWindowFromPointEx(pwndParent, x, y, uiFlags);
3144 }
3145 UserLeave();
3146 TRACE("Leave NtUserChildWindowFromPointEx\n");
3147 return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
3148 }
3149
3150 /*
3151 * @implemented
3152 */
3153 BOOL APIENTRY
3154 NtUserEndDeferWindowPosEx(HDWP WinPosInfo,
3155 DWORD Unknown1)
3156 {
3157 BOOL Ret;
3158 TRACE("Enter NtUserEndDeferWindowPosEx\n");
3159 UserEnterExclusive();
3160 Ret = IntEndDeferWindowPosEx(WinPosInfo, (BOOL)Unknown1);
3161 TRACE("Leave NtUserEndDeferWindowPosEx, ret=%i\n", Ret);
3162 UserLeave();
3163 return Ret;
3164 }
3165
3166 /*
3167 * @implemented
3168 */
3169 HDWP APIENTRY
3170 NtUserDeferWindowPos(HDWP WinPosInfo,
3171 HWND Wnd,
3172 HWND WndInsertAfter,
3173 int x,
3174 int y,
3175 int cx,
3176 int cy,
3177 UINT Flags)
3178 {
3179 PWND pWnd, pWndIA;
3180 HDWP Ret = NULL;
3181 UINT Tmp = ~(SWP_ASYNCWINDOWPOS|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_NOREPOSITION|
3182 SWP_NOCOPYBITS|SWP_HIDEWINDOW|SWP_SHOWWINDOW|SWP_FRAMECHANGED|
3183 SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE);
3184
3185 TRACE("Enter NtUserDeferWindowPos\n");
3186 UserEnterExclusive();
3187
3188 if ( Flags & Tmp )
3189 {
3190 EngSetLastError(ERROR_INVALID_FLAGS);
3191 goto Exit;
3192 }
3193
3194 pWnd = UserGetWindowObject(Wnd);
3195 if (!pWnd || UserIsDesktopWindow(pWnd) || UserIsMessageWindow(pWnd))
3196 {
3197 goto Exit;
3198 }
3199
3200 if ( WndInsertAfter &&
3201 WndInsertAfter != HWND_BOTTOM &&
3202 WndInsertAfter != HWND_TOPMOST &&
3203 WndInsertAfter != HWND_NOTOPMOST )
3204 {
3205 pWndIA = UserGetWindowObject(WndInsertAfter);
3206 if (!pWndIA || UserIsDesktopWindow(pWndIA) || UserIsMessageWindow(pWndIA))
3207 {
3208 goto Exit;
3209 }
3210 }
3211
3212 Ret = IntDeferWindowPos(WinPosInfo, Wnd, WndInsertAfter, x, y, cx, cy, Flags);
3213
3214 Exit:
3215 TRACE("Leave NtUserDeferWindowPos, ret=%p\n", Ret);
3216 UserLeave();
3217 return Ret;
3218 }
3219
3220 /*
3221 * @implemented
3222 */
3223 DWORD APIENTRY
3224 NtUserGetInternalWindowPos( HWND hWnd,
3225 LPRECT rectWnd,
3226 LPPOINT ptIcon)
3227 {
3228 PWND Window;
3229 DWORD Ret = 0;
3230 BOOL Hit = FALSE;
3231 WINDOWPLACEMENT wndpl;
3232
3233 UserEnterShared();
3234
3235 if (!(Window = UserGetWindowObject(hWnd)))
3236 {
3237 Hit = FALSE;
3238 goto Exit;
3239 }
3240
3241 _SEH2_TRY
3242 {
3243 if(rectWnd)
3244 {
3245 ProbeForWrite(rectWnd,
3246 sizeof(RECT),
3247 1);
3248 }
3249 if(ptIcon)
3250 {
3251 ProbeForWrite(ptIcon,
3252 sizeof(POINT),
3253 1);
3254 }
3255
3256 }
3257 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3258 {
3259 SetLastNtError(_SEH2_GetExceptionCode());
3260 Hit = TRUE;
3261 }
3262 _SEH2_END;
3263
3264 wndpl.length = sizeof(WINDOWPLACEMENT);
3265
3266 if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
3267 {
3268 _SEH2_TRY
3269 {
3270 if (rectWnd)
3271 {
3272 RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));
3273 }
3274 if (ptIcon)
3275 {
3276 RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT));
3277 }
3278
3279 }
3280 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3281 {
3282 SetLastNtError(_SEH2_GetExceptionCode());
3283 Hit = TRUE;
3284 }
3285 _SEH2_END;
3286
3287 if (!Hit) Ret = wndpl.showCmd;
3288 }
3289 Exit:
3290 UserLeave();
3291 return Ret;
3292 }
3293
3294 /*
3295 * @implemented
3296 */
3297 BOOL APIENTRY
3298 NtUserGetWindowPlacement(HWND hWnd,
3299 WINDOWPLACEMENT *lpwndpl)
3300 {
3301 PWND Wnd;
3302 WINDOWPLACEMENT Safepl;
3303 NTSTATUS Status;
3304 DECLARE_RETURN(BOOL);
3305
3306 TRACE("Enter NtUserGetWindowPlacement\n");
3307 UserEnterShared();
3308
3309 if (!(Wnd = UserGetWindowObject(hWnd)))
3310 {
3311 RETURN( FALSE);
3312 }
3313
3314 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3315 if (!NT_SUCCESS(Status))
3316 {
3317 SetLastNtError(Status);
3318 RETURN( FALSE);
3319 }
3320
3321 Safepl.length = sizeof(WINDOWPLACEMENT);
3322
3323 IntGetWindowPlacement(Wnd, &Safepl);
3324
3325 Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
3326 if (!NT_SUCCESS(Status))
3327 {
3328 SetLastNtError(Status);
3329 RETURN( FALSE);
3330 }
3331
3332 RETURN( TRUE);
3333
3334 CLEANUP:
3335 TRACE("Leave NtUserGetWindowPlacement, ret=%i\n",_ret_);
3336 UserLeave();
3337 END_CLEANUP;
3338 }
3339
3340 DWORD
3341 APIENTRY
3342 NtUserMinMaximize(
3343 HWND hWnd,
3344 UINT cmd, // Wine SW_ commands
3345 BOOL Hide)
3346 {
3347 PWND pWnd;
3348
3349 TRACE("Enter NtUserMinMaximize\n");
3350 UserEnterExclusive();
3351
3352 pWnd = UserGetWindowObject(hWnd);
3353 if (!pWnd || UserIsDesktopWindow(pWnd) || UserIsMessageWindow(pWnd))
3354 {
3355 goto Exit;
3356 }
3357
3358 if ( cmd > SW_MAX || pWnd->state2 & WNDS2_INDESTROY)
3359 {
3360 EngSetLastError(ERROR_INVALID_PARAMETER);
3361 goto Exit;
3362 }
3363
3364 cmd |= Hide ? SW_HIDE : 0;
3365
3366 co_WinPosShowWindow(pWnd, cmd);
3367
3368 Exit:
3369 TRACE("Leave NtUserMinMaximize\n");
3370 UserLeave();
3371 return 0; // Always NULL?
3372 }
3373
3374 /*
3375 * @implemented
3376 */
3377 BOOL APIENTRY
3378 NtUserMoveWindow(
3379 HWND hWnd,
3380 int X,
3381 int Y,
3382 int nWidth,
3383 int nHeight,
3384 BOOL bRepaint)
3385 {
3386 return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight,
3387 (bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE :
3388 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW));
3389 }
3390
3391 /*
3392 * @implemented
3393 */
3394 HWND APIENTRY
3395 NtUserRealChildWindowFromPoint(HWND Parent,
3396 LONG x,
3397 LONG y)
3398 {
3399 PWND pwndParent;
3400 TRACE("Enter NtUserRealChildWindowFromPoint\n");
3401 UserEnterShared();
3402 if ((pwndParent = UserGetWindowObject(Parent)))
3403 {
3404 pwndParent = IntRealChildWindowFromPoint(pwndParent, x, y);
3405 }
3406 UserLeave();
3407 TRACE("Leave NtUserRealChildWindowFromPoint\n");
3408 return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
3409 }
3410
3411 /*
3412 * @implemented
3413 */
3414 BOOL APIENTRY
3415 NtUserSetWindowPos(
3416 HWND hWnd,
3417 HWND hWndInsertAfter,
3418 int X,
3419 int Y,
3420 int cx,
3421 int cy,
3422 UINT uFlags)
3423 {
3424 DECLARE_RETURN(BOOL);
3425 PWND Window, pWndIA;
3426 BOOL ret;
3427 USER_REFERENCE_ENTRY Ref;
3428
3429 TRACE("Enter NtUserSetWindowPos\n");
3430 UserEnterExclusive();
3431
3432 if (!(Window = UserGetWindowObject(hWnd)) ||
3433 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3434 {
3435 ERR("NtUserSetWindowPos bad window handle!\n");
3436 RETURN(FALSE);
3437 }
3438
3439 if ( hWndInsertAfter != HWND_TOP &&
3440 hWndInsertAfter != HWND_BOTTOM &&
3441 hWndInsertAfter != HWND_TOPMOST &&
3442 hWndInsertAfter != HWND_NOTOPMOST )
3443 {
3444 if (!(pWndIA = UserGetWindowObject(hWndInsertAfter)) ||
3445 UserIsDesktopWindow(pWndIA) || UserIsMessageWindow(pWndIA))
3446 {
3447 ERR("NtUserSetWindowPos bad insert window handle!\n");
3448 RETURN(FALSE);
3449 }
3450 }
3451
3452 /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
3453 if (!(uFlags & SWP_NOMOVE))
3454 {
3455 if (X < -32768) X = -32768;
3456 else if (X > 32767) X = 32767;
3457 if (Y < -32768) Y = -32768;
3458 else if (Y > 32767) Y = 32767;
3459 }
3460 if (!(uFlags & SWP_NOSIZE))
3461 {
3462 if (cx < 0) cx = 0;
3463 else if (cx > 32767) cx = 32767;
3464 if (cy < 0) cy = 0;
3465 else if (cy > 32767) cy = 32767;
3466 }
3467
3468 UserRefObjectCo(Window, &Ref);
3469 ret = co_WinPosSetWindowPos(Window, hWndInsertAfter, X, Y, cx, cy, uFlags);
3470 UserDerefObjectCo(Window);
3471
3472 RETURN(ret);
3473
3474 CLEANUP:
3475 TRACE("Leave NtUserSetWindowPos, ret=%i\n",_ret_);
3476 UserLeave();
3477 END_CLEANUP;
3478 }
3479
3480 /*
3481 * @implemented
3482 */
3483 INT APIENTRY
3484 NtUserSetWindowRgn(
3485 HWND hWnd,
3486 HRGN hRgn,
3487 BOOL bRedraw)
3488 {
3489 HRGN hrgnCopy = NULL;
3490 PWND Window;
3491 INT flags = (SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE);
3492 BOOLEAN Ret = FALSE;
3493 DECLARE_RETURN(INT);
3494
3495 TRACE("Enter NtUserSetWindowRgn\n");
3496 UserEnterExclusive();
3497
3498 if (!(Window = UserGetWindowObject(hWnd)) ||
3499 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3500 {
3501 RETURN( 0);
3502 }
3503
3504 if (hRgn) // The region will be deleted in user32.
3505 {
3506 if (GreIsHandleValid(hRgn))
3507 {
3508 hrgnCopy = NtGdiCreateRectRgn(0, 0, 0, 0);
3509 /* The coordinates of a window's window region are relative to the
3510 upper-left corner of the window, not the client area of the window. */
3511 NtGdiCombineRgn( hrgnCopy, hRgn, 0, RGN_COPY);
3512 }
3513 else
3514 RETURN( 0);
3515 }
3516
3517 //// HACK 1 : Work around the lack of supporting DeferWindowPos.
3518 if (hrgnCopy)
3519 {
3520 Window->hrgnNewFrame = hrgnCopy; // Should be PSMWP->acvr->hrgnClip
3521 }
3522 else
3523 {
3524 Window->hrgnNewFrame = HRGN_WINDOW;
3525 }
3526 //// HACK 2
3527 Ret = co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, bRedraw ? flags : (flags|SWP_NOREDRAW) );
3528
3529 RETURN( (INT)Ret);
3530
3531 CLEANUP:
3532 TRACE("Leave NtUserSetWindowRgn, ret=%i\n",_ret_);
3533 UserLeave();
3534 END_CLEANUP;
3535 }
3536
3537 /*
3538 * @implemented
3539 */
3540 DWORD APIENTRY
3541 NtUserSetInternalWindowPos(
3542 HWND hwnd,
3543 UINT showCmd,
3544 LPRECT lprect,
3545 LPPOINT lppt)
3546 {
3547 WINDOWPLACEMENT wndpl;
3548 UINT flags;
3549 PWND Wnd;
3550 RECT rect;
3551 POINT pt = {0};
3552 DECLARE_RETURN(BOOL);
3553 USER_REFERENCE_ENTRY Ref;
3554
3555 TRACE("Enter NtUserSetWindowPlacement\n");
3556 UserEnterExclusive();
3557
3558 if (!(Wnd = UserGetWindowObject(hwnd)) || // FIXME:
3559 UserIsDesktopWindow(Wnd) || UserIsMessageWindow(Wnd))
3560 {
3561 RETURN( FALSE);
3562 }
3563
3564 _SEH2_TRY
3565 {
3566 if (lppt)
3567 {
3568 ProbeForRead(lppt, sizeof(POINT), 1);
3569 RtlCopyMemory(&pt, lppt, sizeof(POINT));
3570 }
3571 if (lprect)
3572 {
3573 ProbeForRead(lprect, sizeof(RECT), 1);
3574 RtlCopyMemory(&rect, lprect, sizeof(RECT));
3575 }
3576 }
3577 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3578 {
3579 SetLastNtError(_SEH2_GetExceptionCode());
3580 _SEH2_YIELD(RETURN( FALSE));
3581 }
3582 _SEH2_END
3583
3584 wndpl.length = sizeof(wndpl);
3585 wndpl.showCmd = showCmd;
3586 wndpl.flags = flags = 0;
3587
3588 if ( lppt )
3589 {
3590 flags |= PLACE_MIN;
3591 wndpl.flags |= WPF_SETMINPOSITION;
3592 wndpl.ptMinPosition = pt;
3593 }
3594 if ( lprect )
3595 {
3596 flags |= PLACE_RECT;
3597 wndpl.rcNormalPosition = rect;
3598 }
3599
3600 UserRefObjectCo(Wnd, &Ref);
3601 IntSetWindowPlacement(Wnd, &wndpl, flags);
3602 UserDerefObjectCo(Wnd);
3603 RETURN(TRUE);
3604
3605 CLEANUP:
3606 TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
3607 UserLeave();
3608 END_CLEANUP;
3609 }
3610
3611 /*
3612 * @implemented
3613 */
3614 BOOL APIENTRY
3615 NtUserSetWindowPlacement(HWND hWnd,
3616 WINDOWPLACEMENT *lpwndpl)
3617 {
3618 PWND Wnd;
3619 WINDOWPLACEMENT Safepl;
3620 UINT Flags;
3621 DECLARE_RETURN(BOOL);
3622 USER_REFERENCE_ENTRY Ref;
3623
3624 TRACE("Enter NtUserSetWindowPlacement\n");
3625 UserEnterExclusive();
3626
3627 if (!(Wnd = UserGetWindowObject(hWnd)) ||
3628 UserIsDesktopWindow(Wnd) || UserIsMessageWindow(Wnd))
3629 {
3630 RETURN( FALSE);
3631 }
3632
3633 _SEH2_TRY
3634 {
3635 ProbeForRead(lpwndpl, sizeof(WINDOWPLACEMENT), 1);
3636 RtlCopyMemory(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3637 }
3638 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3639 {
3640 SetLastNtError(_SEH2_GetExceptionCode());
3641 _SEH2_YIELD(RETURN( FALSE));
3642 }
3643 _SEH2_END
3644
3645 if(Safepl.length != sizeof(WINDOWPLACEMENT))
3646 {
3647 RETURN( FALSE);
3648 }
3649
3650 Flags = PLACE_MAX | PLACE_RECT;
3651 if (Safepl.flags & WPF_SETMINPOSITION) Flags |= PLACE_MIN;
3652 UserRefObjectCo(Wnd, &Ref);
3653 IntSetWindowPlacement(Wnd, &Safepl, Flags);
3654 UserDerefObjectCo(Wnd);
3655 RETURN(TRUE);
3656
3657 CLEANUP:
3658 TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
3659 UserLeave();
3660 END_CLEANUP;
3661 }
3662
3663 /*
3664 * @implemented
3665 */
3666 BOOL APIENTRY
3667 NtUserShowWindowAsync(HWND hWnd, LONG nCmdShow)
3668 {
3669 PWND Window;
3670 BOOL ret;
3671 DECLARE_RETURN(BOOL);
3672 USER_REFERENCE_ENTRY Ref;
3673
3674 TRACE("Enter NtUserShowWindowAsync\n");
3675 UserEnterExclusive();
3676
3677 if (!(Window = UserGetWindowObject(hWnd)) ||
3678 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3679 {
3680 RETURN(FALSE);
3681 }
3682
3683 if ( nCmdShow > SW_MAX )
3684 {
3685 EngSetLastError(ERROR_INVALID_PARAMETER);
3686 RETURN(FALSE);
3687 }
3688
3689 UserRefObjectCo(Window, &Ref);
3690 ret = co_IntSendMessageNoWait( hWnd, WM_ASYNC_SHOWWINDOW, nCmdShow, 0 );
3691 UserDerefObjectCo(Window);
3692 if (-1 == (int) ret || !ret) ret = FALSE;
3693
3694 RETURN(ret);
3695
3696 CLEANUP:
3697 TRACE("Leave NtUserShowWindowAsync, ret=%i\n",_ret_);
3698 UserLeave();
3699 END_CLEANUP;
3700 }
3701
3702 /*
3703 * @implemented
3704 */
3705 BOOL APIENTRY
3706 NtUserShowWindow(HWND hWnd, LONG nCmdShow)
3707 {
3708 PWND Window;
3709 BOOL ret;
3710 DECLARE_RETURN(BOOL);
3711 USER_REFERENCE_ENTRY Ref;
3712
3713 TRACE("Enter NtUserShowWindow hWnd %p SW_ %d\n",hWnd, nCmdShow);
3714 UserEnterExclusive();
3715
3716 if (!(Window = UserGetWindowObject(hWnd)) ||
3717 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3718 {
3719 RETURN(FALSE);
3720 }
3721
3722 if ( nCmdShow > SW_MAX || Window->state2 & WNDS2_INDESTROY)
3723 {
3724 EngSetLastError(ERROR_INVALID_PARAMETER);
3725 RETURN(FALSE);
3726 }
3727
3728 UserRefObjectCo(Window, &Ref);
3729 ret = co_WinPosShowWindow(Window, nCmdShow);
3730 UserDerefObjectCo(Window);
3731
3732 RETURN(ret);
3733
3734 CLEANUP:
3735 TRACE("Leave NtUserShowWindow, ret=%i\n",_ret_);
3736 UserLeave();
3737 END_CLEANUP;
3738 }
3739
3740
3741 /*
3742 * @implemented
3743 */
3744 HWND APIENTRY
3745 NtUserWindowFromPoint(LONG X, LONG Y)
3746 {
3747 POINT pt;
3748 HWND Ret;
3749 PWND DesktopWindow = NULL, Window = NULL;
3750 USHORT hittest;
3751 DECLARE_RETURN(HWND);
3752 USER_REFERENCE_ENTRY Ref;
3753
3754 TRACE("Enter NtUserWindowFromPoint\n");
3755 UserEnterExclusive();
3756
3757 if ((DesktopWindow = UserGetWindowObject(IntGetDesktopWindow())))
3758 {
3759 //PTHREADINFO pti;
3760
3761 pt.x = X;
3762 pt.y = Y;
3763
3764 // Hmm... Threads live on desktops thus we have a reference on the desktop and indirectly the desktop window.
3765 // It is possible this referencing is useless, though it should not hurt...
3766 UserRefObjectCo(DesktopWindow, &Ref);
3767
3768 //pti = PsGetCurrentThreadWin32Thread();
3769 Window = co_WinPosWindowFromPoint(DesktopWindow, &pt, &hittest, FALSE);
3770
3771 if (Window)
3772 {
3773 Ret = UserHMGetHandle(Window);
3774
3775 RETURN( Ret);
3776 }
3777 }
3778
3779 RETURN( NULL);
3780
3781 CLEANUP:
3782 if (DesktopWindow) UserDerefObjectCo(DesktopWindow);
3783
3784 TRACE("Leave NtUserWindowFromPoint, ret=%p\n", _ret_);
3785 UserLeave();
3786 END_CLEANUP;
3787 }
3788
3789 /* EOF */