0d9afbe025885d55809b5e3c56d555035b373b0f
[reactos.git] / reactos / win32ss / user / ntuser / winpos.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Windows
5 * FILE: win32ss/user/ntuser/winpos.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserWinpos);
11
12 /* GLOBALS *******************************************************************/
13
14 #define MINMAX_NOSWP (0x00010000)
15
16 #define SWP_EX_NOCOPY 0x0001
17 #define SWP_EX_PAINTSELF 0x0002
18
19 #define SWP_AGG_NOGEOMETRYCHANGE \
20 (SWP_NOSIZE | SWP_NOCLIENTSIZE | SWP_NOZORDER)
21 #define SWP_AGG_NOPOSCHANGE \
22 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER)
23 #define SWP_AGG_STATUSFLAGS \
24 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
25
26 #define EMPTYPOINT(pt) ((pt).x == -1 && (pt).y == -1)
27 #define PLACE_MIN 0x0001
28 #define PLACE_MAX 0x0002
29 #define PLACE_RECT 0x0004
30
31 VOID FASTCALL IntLinkWindow(PWND Wnd,PWND WndInsertAfter);
32
33 /* FUNCTIONS *****************************************************************/
34
35 BOOL FASTCALL
36 IntGetClientOrigin(PWND Window OPTIONAL, LPPOINT Point)
37 {
38 Window = Window ? Window : UserGetDesktopWindow();
39 if (Window == NULL)
40 {
41 Point->x = Point->y = 0;
42 return FALSE;
43 }
44 Point->x = Window->rcClient.left;
45 Point->y = Window->rcClient.top;
46
47 return TRUE;
48 }
49
50 /*!
51 * Internal function.
52 * Returns client window rectangle relative to the upper-left corner of client area.
53 *
54 * \note Does not check the validity of the parameters
55 */
56 VOID FASTCALL
57 IntGetClientRect(PWND Wnd, RECTL *Rect)
58 {
59 ASSERT( Wnd );
60 ASSERT( Rect );
61 if (Wnd->style & WS_MINIMIZED)
62 {
63 Rect->left = Rect->top = 0;
64 Rect->right = UserGetSystemMetrics(SM_CXMINIMIZED);
65 Rect->bottom = UserGetSystemMetrics(SM_CYMINIMIZED);
66 return;
67 }
68 if ( Wnd != UserGetDesktopWindow()) // Wnd->fnid != FNID_DESKTOP )
69 {
70 *Rect = Wnd->rcClient;
71 RECTL_vOffsetRect(Rect, -Wnd->rcClient.left, -Wnd->rcClient.top);
72 }
73 else
74 {
75 Rect->left = Rect->top = 0;
76 Rect->right = Wnd->rcClient.right;
77 Rect->bottom = Wnd->rcClient.bottom;
78 /* Do this until Init bug is fixed. This sets 640x480, see InitMetrics.
79 Rect->right = UserGetSystemMetrics(SM_CXSCREEN);
80 Rect->bottom = UserGetSystemMetrics(SM_CYSCREEN);
81 */
82 }
83 }
84
85 BOOL FASTCALL
86 IntGetWindowRect(PWND Wnd, RECTL *Rect)
87 {
88 ASSERT( Wnd );
89 ASSERT( Rect );
90 if (!Wnd) return FALSE;
91 if ( Wnd != UserGetDesktopWindow()) // Wnd->fnid != FNID_DESKTOP )
92 {
93 *Rect = Wnd->rcWindow;
94 }
95 else
96 {
97 Rect->left = Rect->top = 0;
98 Rect->right = Wnd->rcWindow.right;
99 Rect->bottom = Wnd->rcWindow.bottom;
100 /* Do this until Init bug is fixed. This sets 640x480, see InitMetrics.
101 Rect->right = GetSystemMetrics(SM_CXSCREEN);
102 Rect->bottom = GetSystemMetrics(SM_CYSCREEN);
103 */ }
104 return TRUE;
105 }
106
107
108 INT FASTCALL
109 IntMapWindowPoints(PWND FromWnd, PWND ToWnd, LPPOINT lpPoints, UINT cPoints)
110 {
111 BOOL mirror_from, mirror_to;
112 POINT Delta;
113 UINT i;
114 int Change = 1;
115
116 /* Note: Desktop Top and Left is always 0! */
117 Delta.x = Delta.y = 0;
118 mirror_from = mirror_to = FALSE;
119
120 if (FromWnd && FromWnd != UserGetDesktopWindow()) // FromWnd->fnid != FNID_DESKTOP)
121 {
122 if (FromWnd->ExStyle & WS_EX_LAYOUTRTL)
123 {
124 mirror_from = TRUE;
125 Change = -Change;
126 Delta.x = -FromWnd->rcClient.right;
127 }
128 else
129 Delta.x = FromWnd->rcClient.left;
130 Delta.y = FromWnd->rcClient.top;
131 }
132
133 if (ToWnd && ToWnd != UserGetDesktopWindow()) // ToWnd->fnid != FNID_DESKTOP)
134 {
135 if (ToWnd->ExStyle & WS_EX_LAYOUTRTL)
136 {
137 mirror_to = TRUE;
138 Change = -Change;
139 Delta.x += Change * ToWnd->rcClient.right;
140 }
141 else
142 Delta.x -= Change * ToWnd->rcClient.left;
143 Delta.y -= ToWnd->rcClient.top;
144 }
145
146 for (i = 0; i != cPoints; i++)
147 {
148 lpPoints[i].x += Delta.x;
149 lpPoints[i].x *= Change;
150 lpPoints[i].y += Delta.y;
151 }
152
153 if ((mirror_from || mirror_to) && cPoints == 2) /* special case for rectangle */
154 {
155 int tmp = min(lpPoints[0].x, lpPoints[1].x);
156 lpPoints[1].x = max(lpPoints[0].x, lpPoints[1].x);
157 lpPoints[0].x = tmp;
158 }
159
160 return MAKELONG(LOWORD(Delta.x), LOWORD(Delta.y));
161 }
162
163 BOOL FASTCALL
164 IntClientToScreen(PWND Wnd, LPPOINT lpPoint)
165 {
166 if (Wnd && Wnd->fnid != FNID_DESKTOP )
167 {
168 if (Wnd->ExStyle & WS_EX_LAYOUTRTL)
169 lpPoint->x = Wnd->rcClient.right - lpPoint->x;
170 else
171 lpPoint->x += Wnd->rcClient.left;
172 lpPoint->y += Wnd->rcClient.top;
173 }
174 return TRUE;
175 }
176
177 BOOL FASTCALL
178 IntScreenToClient(PWND Wnd, LPPOINT lpPoint)
179 {
180 if (Wnd && Wnd->fnid != FNID_DESKTOP )
181 {
182 if (Wnd->ExStyle & WS_EX_LAYOUTRTL)
183 lpPoint->x = Wnd->rcClient.right - lpPoint->x;
184 else
185 lpPoint->x -= Wnd->rcClient.left;
186 lpPoint->y -= Wnd->rcClient.top;
187 }
188 return TRUE;
189 }
190
191 BOOL FASTCALL IsChildVisible(PWND pWnd)
192 {
193 do
194 {
195 if ( (pWnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD ||
196 !(pWnd = pWnd->spwndParent) )
197 return TRUE;
198 }
199 while (pWnd->style & WS_VISIBLE);
200 return FALSE;
201 }
202
203 PWND FASTCALL IntGetLastTopMostWindow(VOID)
204 {
205 PWND pWnd;
206 PDESKTOP rpdesk = gptiCurrent->rpdesk;
207
208 if ( rpdesk &&
209 (pWnd = rpdesk->pDeskInfo->spwnd->spwndChild) &&
210 pWnd->ExStyle & WS_EX_TOPMOST)
211 {
212 for (;;)
213 {
214 if (!pWnd->spwndNext) break;
215 if (!(pWnd->spwndNext->ExStyle & WS_EX_TOPMOST)) break;
216 pWnd = pWnd->spwndNext;
217 }
218 return pWnd;
219 }
220 return NULL;
221 }
222
223 //
224 // This helps with CORE-6129 forcing modal dialog active when another app is minimized or closed.
225 //
226 BOOL FASTCALL ActivateOtherWindowMin(PWND Wnd)
227 {
228 BOOL ActivePrev, FindTopWnd;
229 PWND pWndTopMost, pWndChild, pWndSetActive, pWndTemp, pWndDesk;
230 USER_REFERENCE_ENTRY Ref;
231 PTHREADINFO pti = gptiCurrent;
232
233 //ERR("AOWM 1 %p\n",Wnd->head.h);
234 ActivePrev = (pti->MessageQueue->spwndActivePrev != NULL);
235 FindTopWnd = TRUE;
236
237 if ((pWndTopMost = IntGetLastTopMostWindow()))
238 pWndChild = pWndTopMost->spwndNext;
239 else
240 pWndChild = Wnd->spwndParent->spwndChild;
241
242 for (;;)
243 {
244 if ( ActivePrev )
245 pWndSetActive = pti->MessageQueue->spwndActivePrev;
246 else
247 pWndSetActive = pWndChild;
248
249 pWndTemp = NULL;
250
251 while(pWndSetActive)
252 {
253 if ( VerifyWnd(pWndSetActive) &&
254 !(pWndSetActive->ExStyle & WS_EX_NOACTIVATE) &&
255 (pWndSetActive->style & (WS_VISIBLE|WS_DISABLED)) == WS_VISIBLE &&
256 (!(pWndSetActive->style & WS_ICONIC) /* FIXME MinMax pos? */ ) )
257 {
258 if (!(pWndSetActive->ExStyle & WS_EX_TOOLWINDOW) )
259 {
260 UserRefObjectCo(pWndSetActive, &Ref);
261 //ERR("ActivateOtherWindowMin Set FG 1\n");
262 co_IntSetForegroundWindow(pWndSetActive);
263 UserDerefObjectCo(pWndSetActive);
264 //ERR("AOWM 2 Exit Good %p\n",pWndSetActive->head.h);
265 return TRUE;
266 }
267 if (!pWndTemp ) pWndTemp = pWndSetActive;
268 }
269 if ( ActivePrev )
270 {
271 ActivePrev = FALSE;
272 pWndSetActive = pWndChild;
273 }
274 else
275 pWndSetActive = pWndSetActive->spwndNext;
276 }
277
278 if ( !FindTopWnd ) break;
279 FindTopWnd = FALSE;
280
281 if ( pWndChild )
282 {
283 pWndChild = pWndChild->spwndParent->spwndChild;
284 continue;
285 }
286
287 if (!(pWndDesk = IntGetThreadDesktopWindow(pti)))
288 {
289 pWndChild = NULL;
290 continue;
291 }
292 pWndChild = pWndDesk->spwndChild;
293 }
294
295 if ((pWndSetActive = pWndTemp))
296 {
297 UserRefObjectCo(pWndSetActive, &Ref);
298 //ERR("ActivateOtherWindowMin Set FG 2\n");
299 co_IntSetForegroundWindow(pWndSetActive);
300 UserDerefObjectCo(pWndSetActive);
301 //ERR("AOWM 3 Exit Good %p\n",pWndSetActive->head.h);
302 return TRUE;
303 }
304 //ERR("AOWM 4 Bad\n");
305 return FALSE;
306 }
307
308 /*******************************************************************
309 * can_activate_window
310 *
311 * Check if we can activate the specified window.
312 */
313 static
314 BOOL FASTCALL can_activate_window( PWND Wnd OPTIONAL)
315 {
316 LONG style;
317
318 if (!Wnd) return FALSE;
319
320 style = Wnd->style;
321 if (!(style & WS_VISIBLE)) return FALSE;
322 if (style & WS_MINIMIZE) return FALSE;
323 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
324 return TRUE;
325 /* FIXME: This window could be disable because the child that closed
326 was a popup. */
327 //return !(style & WS_DISABLED);
328 }
329
330
331 /*******************************************************************
332 * WinPosActivateOtherWindow
333 *
334 * Activates window other than pWnd.
335 */
336 VOID FASTCALL
337 co_WinPosActivateOtherWindow(PWND Wnd)
338 {
339 PWND WndTo = NULL;
340 USER_REFERENCE_ENTRY Ref;
341
342 ASSERT_REFS_CO(Wnd);
343
344 if (IntIsDesktopWindow(Wnd))
345 {
346 IntSetFocusMessageQueue(NULL);
347 return;
348 }
349
350 /* If this is popup window, try to activate the owner first. */
351 if ((Wnd->style & WS_POPUP) && (WndTo = Wnd->spwndOwner))
352 {
353 TRACE("WPAOW Popup with Owner\n");
354 WndTo = UserGetAncestor( WndTo, GA_ROOT );
355 if (can_activate_window(WndTo)) goto done;
356 }
357
358 /* Pick a next top-level window. */
359 /* FIXME: Search for non-tooltip windows first. */
360 WndTo = Wnd;
361 for (;;)
362 {
363 if (!(WndTo = WndTo->spwndNext)) break;
364 if (can_activate_window( WndTo )) goto done;
365 }
366
367 /*
368 Fixes wine win.c:test_SetParent last ShowWindow test after popup dies.
369 Check for previous active window to bring to top.
370 */
371 if (Wnd)
372 {
373 WndTo = Wnd->head.pti->MessageQueue->spwndActivePrev;
374 if (can_activate_window( WndTo )) goto done;
375 }
376
377 // Find any window to bring to top. Works Okay for wine since it does not see X11 windows.
378 WndTo = UserGetDesktopWindow();
379 WndTo = WndTo->spwndChild;
380 if ( WndTo == NULL )
381 {
382 return;
383 }
384 for (;;)
385 {
386 if (WndTo == Wnd)
387 {
388 WndTo = NULL;
389 break;
390 }
391 if (can_activate_window( WndTo )) goto done;
392 if (!(WndTo = WndTo->spwndNext)) break;
393 }
394
395 done:
396 if (WndTo) UserRefObjectCo(WndTo, &Ref);
397
398 if (gpqForeground && (!gpqForeground->spwndActive || Wnd == gpqForeground->spwndActive))
399 {
400 /* ReactOS can pass WndTo = NULL to co_IntSetForegroundWindow and returns FALSE. */
401 //ERR("WinPosActivateOtherWindow Set FG 0x%p hWnd %p\n",WndTo, WndTo ? WndTo->head.h : 0);
402 if (co_IntSetForegroundWindow(WndTo))
403 {
404 if (WndTo) UserDerefObjectCo(WndTo);
405 return;
406 }
407 }
408 //ERR("WinPosActivateOtherWindow Set Active 0x%p\n",WndTo);
409 if (!co_IntSetActiveWindow(WndTo,FALSE,TRUE,FALSE)) /* Ok for WndTo to be NULL here */
410 {
411 //ERR("WPAOW SA 1\n");
412 co_IntSetActiveWindow(NULL,FALSE,TRUE,FALSE);
413 }
414 if (WndTo) UserDerefObjectCo(WndTo);
415 }
416
417 VOID FASTCALL
418 WinPosInitInternalPos(PWND Wnd, RECTL *RestoreRect)
419 {
420 POINT Size;
421 RECTL Rect = *RestoreRect;
422
423 if (Wnd->spwndParent && Wnd->spwndParent != UserGetDesktopWindow())
424 {
425 RECTL_vOffsetRect(&Rect,
426 -Wnd->spwndParent->rcClient.left,
427 -Wnd->spwndParent->rcClient.top);
428 }
429
430 Size.x = Rect.left;
431 Size.y = Rect.top;
432
433 if (!Wnd->InternalPosInitialized)
434 {
435 // FIXME: Use check point Atom..
436 Wnd->InternalPos.flags = 0;
437 Wnd->InternalPos.MaxPos.x = Wnd->InternalPos.MaxPos.y = -1;
438 Wnd->InternalPos.IconPos.x = Wnd->InternalPos.IconPos.y = -1;
439 Wnd->InternalPos.NormalRect = Rect;
440 Wnd->InternalPosInitialized = TRUE;
441 }
442
443 if (Wnd->style & WS_MINIMIZE)
444 {
445 Wnd->InternalPos.IconPos = Size;
446 Wnd->InternalPos.flags |= WPF_MININIT;
447 }
448 else if (Wnd->style & WS_MAXIMIZE)
449 {
450 Wnd->InternalPos.flags |= WPF_MAXINIT;
451
452 if ( Wnd->spwndParent == Wnd->head.rpdesk->pDeskInfo->spwnd )
453 {
454 if (Wnd->state & WNDS_MAXIMIZESTOMONITOR)
455 {
456 Wnd->InternalPos.flags &= ~WPF_MAXINIT;
457 Wnd->InternalPos.MaxPos.x = Wnd->InternalPos.MaxPos.y = -1;
458 }
459 else
460 {
461 RECTL WorkArea;
462 PMONITOR pmonitor = UserMonitorFromRect(&Rect, MONITOR_DEFAULTTOPRIMARY );
463 // FIXME: support DPI aware, rcWorkDPI/Real etc..
464 WorkArea = pmonitor->rcMonitor;
465
466 if (Wnd->style & WS_MAXIMIZEBOX)
467 { // Support (Wnd->state & WNDS_HASCAPTION) || pmonitor->cFullScreen too.
468 if ((Wnd->style & WS_CAPTION) == WS_CAPTION || !(Wnd->style & (WS_CHILD | WS_POPUP)))
469 {
470 WorkArea = pmonitor->rcWork;
471 //ERR("rcWork\n");
472 }
473 }
474
475 Wnd->InternalPos.MaxPos.x = Rect.left - WorkArea.left;
476 Wnd->InternalPos.MaxPos.y = Rect.top - WorkArea.top;
477
478 /*ERR("WinPosIP 2 X %d = R.l %d - W.l %d | Y %d = R.t %d - W.t %d\n",
479 Wnd->InternalPos.MaxPos.x,
480 Rect.left, WorkArea.left,
481 Wnd->InternalPos.MaxPos.y,
482 Rect.top, WorkArea.top);*/
483 }
484 }
485 else
486 Wnd->InternalPos.MaxPos = Size;
487 }
488 else
489 {
490 Wnd->InternalPos.NormalRect = Rect;
491 }
492 }
493
494 BOOL
495 FASTCALL
496 IntGetWindowPlacement(PWND Wnd, WINDOWPLACEMENT *lpwndpl)
497 {
498 if (!Wnd) return FALSE;
499
500 if(lpwndpl->length != sizeof(WINDOWPLACEMENT))
501 {
502 return FALSE;
503 }
504
505 lpwndpl->flags = 0;
506
507 WinPosInitInternalPos(Wnd, &Wnd->rcWindow);
508
509 lpwndpl->showCmd = SW_HIDE;
510
511 if ( Wnd->style & WS_MINIMIZE )
512 lpwndpl->showCmd = SW_SHOWMINIMIZED;
513 else
514 lpwndpl->showCmd = ( Wnd->style & WS_MAXIMIZE ) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL ;
515
516 lpwndpl->rcNormalPosition = Wnd->InternalPos.NormalRect;
517
518 if (Wnd->InternalPos.flags & WPF_MININIT) // Return if it was set!
519 {
520 lpwndpl->ptMinPosition.x = Wnd->InternalPos.IconPos.x;
521 lpwndpl->ptMinPosition.y = Wnd->InternalPos.IconPos.y;
522 }
523 else
524 lpwndpl->ptMinPosition.x = lpwndpl->ptMinPosition.y = -1;
525
526 if ( Wnd->InternalPos.flags & WPF_MAXINIT && // Return if set and not maximized to monitor!
527 !(Wnd->state & WNDS_MAXIMIZESTOMONITOR))
528 {
529 lpwndpl->ptMaxPosition.x = Wnd->InternalPos.MaxPos.x;
530 lpwndpl->ptMaxPosition.y = Wnd->InternalPos.MaxPos.y;
531 }
532 else
533 lpwndpl->ptMaxPosition.x = lpwndpl->ptMaxPosition.y = -1;
534
535 if ( Wnd->spwndParent == Wnd->head.rpdesk->pDeskInfo->spwnd &&
536 !(Wnd->ExStyle & WS_EX_TOOLWINDOW))
537 {
538 PMONITOR pmonitor = UserMonitorFromRect(&lpwndpl->rcNormalPosition, MONITOR_DEFAULTTOPRIMARY );
539
540 // FIXME: support DPI aware, rcWorkDPI/Real etc..
541 if (Wnd->InternalPos.flags & WPF_MININIT)
542 {
543 lpwndpl->ptMinPosition.x -= (pmonitor->rcWork.left - pmonitor->rcMonitor.left);
544 lpwndpl->ptMinPosition.y -= (pmonitor->rcWork.top - pmonitor->rcMonitor.top);
545 }
546 RECTL_vOffsetRect(&lpwndpl->rcNormalPosition,
547 pmonitor->rcMonitor.left - pmonitor->rcWork.left,
548 pmonitor->rcMonitor.top - pmonitor->rcWork.top);
549 }
550
551 if ( Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED || Wnd->style & WS_MAXIMIZE )
552 lpwndpl->flags |= WPF_RESTORETOMAXIMIZED;
553
554 if ( ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD) && Wnd->InternalPos.flags & WPF_SETMINPOSITION)
555 lpwndpl->flags |= WPF_SETMINPOSITION;
556
557 return TRUE;
558 }
559
560 /* make sure the specified rect is visible on screen */
561 static void make_rect_onscreen( RECT *rect )
562 {
563 PMONITOR pmonitor = UserMonitorFromRect( rect, MONITOR_DEFAULTTONEAREST ); // Wine uses this.
564
565 // FIXME: support DPI aware, rcWorkDPI/Real etc..
566 if (!pmonitor) return;
567 /* FIXME: map coordinates from rcWork to rcMonitor */
568 if (rect->right <= pmonitor->rcWork.left)
569 {
570 rect->right += pmonitor->rcWork.left - rect->left;
571 rect->left = pmonitor->rcWork.left;
572 }
573 else if (rect->left >= pmonitor->rcWork.right)
574 {
575 rect->left += pmonitor->rcWork.right - rect->right;
576 rect->right = pmonitor->rcWork.right;
577 }
578 if (rect->bottom <= pmonitor->rcWork.top)
579 {
580 rect->bottom += pmonitor->rcWork.top - rect->top;
581 rect->top = pmonitor->rcWork.top;
582 }
583 else if (rect->top >= pmonitor->rcWork.bottom)
584 {
585 rect->top += pmonitor->rcWork.bottom - rect->bottom;
586 rect->bottom = pmonitor->rcWork.bottom;
587 }
588 }
589
590 /* make sure the specified point is visible on screen */
591 static void make_point_onscreen( POINT *pt )
592 {
593 RECT rect;
594
595 RECTL_vSetRect( &rect, pt->x, pt->y, pt->x + 1, pt->y + 1 );
596 make_rect_onscreen( &rect );
597 pt->x = rect.left;
598 pt->y = rect.top;
599 }
600
601 BOOL FASTCALL
602 IntSetWindowPlacement(PWND Wnd, WINDOWPLACEMENT *wpl, UINT Flags)
603 {
604 BOOL sAsync;
605 UINT SWP_Flags;
606
607 if ( Flags & PLACE_MIN) make_point_onscreen( &wpl->ptMinPosition );
608 if ( Flags & PLACE_MAX) make_point_onscreen( &wpl->ptMaxPosition );
609 if ( Flags & PLACE_RECT) make_rect_onscreen( &wpl->rcNormalPosition );
610
611 if (!Wnd || Wnd == Wnd->head.rpdesk->pDeskInfo->spwnd) return FALSE;
612
613 if ( Flags & PLACE_MIN ) Wnd->InternalPos.IconPos = wpl->ptMinPosition;
614 if ( Flags & PLACE_MAX ) Wnd->InternalPos.MaxPos = wpl->ptMaxPosition;
615 if ( Flags & PLACE_RECT) Wnd->InternalPos.NormalRect = wpl->rcNormalPosition;
616
617 SWP_Flags = SWP_NOZORDER | SWP_NOACTIVATE | ((wpl->flags & WPF_ASYNCWINDOWPLACEMENT) ? SWP_ASYNCWINDOWPOS : 0);
618
619 if (Wnd->style & WS_MINIMIZE )
620 {
621 if (Flags & PLACE_MIN || Wnd->InternalPos.flags & WPF_SETMINPOSITION)
622 {
623 co_WinPosSetWindowPos(Wnd, HWND_TOP,
624 wpl->ptMinPosition.x, wpl->ptMinPosition.y, 0, 0,
625 SWP_NOSIZE | SWP_Flags);
626 Wnd->InternalPos.flags |= WPF_MININIT;
627 }
628 }
629 else if (Wnd->style & WS_MAXIMIZE )
630 {
631 if (Flags & PLACE_MAX)
632 {
633 co_WinPosSetWindowPos(Wnd, HWND_TOP,
634 wpl->ptMaxPosition.x, wpl->ptMaxPosition.y, 0, 0,
635 SWP_NOSIZE | SWP_Flags);
636 Wnd->InternalPos.flags |= WPF_MAXINIT;
637 }
638 }
639 else if (Flags & PLACE_RECT)
640 {
641 co_WinPosSetWindowPos(Wnd, HWND_TOP,
642 wpl->rcNormalPosition.left, wpl->rcNormalPosition.top,
643 wpl->rcNormalPosition.right - wpl->rcNormalPosition.left,
644 wpl->rcNormalPosition.bottom - wpl->rcNormalPosition.top,
645 SWP_Flags);
646 }
647
648 sAsync = (Wnd->head.pti->MessageQueue != gptiCurrent->MessageQueue && wpl->flags & WPF_ASYNCWINDOWPLACEMENT);
649
650 if ( sAsync )
651 co_IntSendMessageNoWait( UserHMGetHandle(Wnd), WM_ASYNC_SHOWWINDOW, wpl->showCmd, 0 );
652 else
653 co_WinPosShowWindow(Wnd, wpl->showCmd);
654
655 if ( Wnd->style & WS_MINIMIZE && !sAsync )
656 {
657 if ( wpl->flags & WPF_SETMINPOSITION )
658 Wnd->InternalPos.flags |= WPF_SETMINPOSITION;
659
660 if ( wpl->flags & WPF_RESTORETOMAXIMIZED )
661 Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED;
662 }
663 return TRUE;
664 }
665
666 UINT
667 FASTCALL
668 co_WinPosArrangeIconicWindows(PWND parent)
669 {
670 RECTL rectParent;
671 PWND Child;
672 INT x, y, xspacing, yspacing, sx, sy;
673
674 ASSERT_REFS_CO(parent);
675
676 IntGetClientRect( parent, &rectParent );
677 // FIXME: Support Minimize Metrics gspv.mm.iArrange.
678 // Default: ARW_BOTTOMLEFT
679 x = rectParent.left;
680 y = rectParent.bottom;
681
682 xspacing = UserGetSystemMetrics(SM_CXMINIMIZED);
683 yspacing = UserGetSystemMetrics(SM_CYMINIMIZED);
684
685 Child = parent->spwndChild;
686 while(Child)
687 {
688 if((Child->style & WS_MINIMIZE) != 0 )
689 {
690 USER_REFERENCE_ENTRY Ref;
691 UserRefObjectCo(Child, &Ref);
692
693 sx = x + UserGetSystemMetrics(SM_CXBORDER);
694 sy = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
695
696 Child->InternalPos.IconPos.x = sx;
697 Child->InternalPos.IconPos.y = sy;
698 Child->InternalPos.flags |= WPF_MININIT;
699
700 co_WinPosSetWindowPos( Child, 0, sx, sy, xspacing, yspacing, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_ASYNCWINDOWPOS);
701
702 UserDerefObjectCo(Child);
703
704 if (x <= rectParent.right - xspacing)
705 x += xspacing;
706 else
707 {
708 x = rectParent.left;
709 y -= yspacing;
710 }
711 }
712 Child = Child->spwndNext;
713 }
714 return yspacing;
715 }
716
717 static VOID FASTCALL
718 WinPosFindIconPos(PWND Window, POINT *Pos)
719 {
720 RECT rectParent;
721 PWND pwndChild, pwndParent;
722 int x, y, xspacing, yspacing;
723
724 pwndParent = Window->spwndParent;
725 if (pwndParent == UserGetDesktopWindow())
726 {
727 ERR("Parent is Desktop, Min off screen!\n");
728 /* ReactOS doesn't support iconic minimize to desktop */
729 Pos->x = Pos->y = -32000;
730 Window->InternalPos.flags |= WPF_MININIT;
731 Window->InternalPos.IconPos.x = Pos->x;
732 Window->InternalPos.IconPos.y = Pos->y;
733 return;
734 }
735
736 IntGetClientRect( pwndParent, &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 // Set to default position when minimized.
746 Pos->x = x + UserGetSystemMetrics(SM_CXBORDER);
747 Pos->y = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
748
749 for (pwndChild = pwndParent->spwndChild; pwndChild; pwndChild = pwndChild->spwndNext)
750 {
751 if (pwndChild == Window) continue;
752
753 if ((pwndChild->style & (WS_VISIBLE|WS_MINIMIZE)) != (WS_VISIBLE|WS_MINIMIZE) )
754 {
755 continue;
756 }
757
758 if ( pwndChild->InternalPos.IconPos.x != Pos->x && pwndChild->InternalPos.IconPos.y != Pos->y )
759 {
760 break;
761 }
762 if (x <= rectParent.right - xspacing)
763 x += xspacing;
764 else
765 {
766 x = rectParent.left;
767 y -= yspacing;
768 }
769 Pos->x = x + UserGetSystemMetrics(SM_CXBORDER);
770 Pos->y = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
771 }
772
773 Window->InternalPos.IconPos.x = Pos->x;
774 Window->InternalPos.IconPos.y = Pos->y;
775 Window->InternalPos.flags |= WPF_MININIT;
776 TRACE("Position is set! X:%d Y:%d\n",Pos->x,Pos->y);
777 return;
778 }
779
780 UINT FASTCALL
781 co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos)
782 {
783 POINT Size;
784 WINDOWPLACEMENT wpl;
785 LONG old_style;
786 UINT SwpFlags = 0;
787
788 ASSERT_REFS_CO(Wnd);
789
790 wpl.length = sizeof(wpl);
791 IntGetWindowPlacement( Wnd, &wpl );
792
793 if (co_HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)Wnd->head.h, ShowFlag))
794 {
795 ERR("WinPosMinMaximize WH_CBT Call Hook return!\n");
796 return SWP_NOSIZE | SWP_NOMOVE;
797 }
798 if (Wnd->style & WS_MINIMIZE)
799 {
800 switch (ShowFlag)
801 {
802 case SW_MINIMIZE:
803 case SW_SHOWMINNOACTIVE:
804 case SW_SHOWMINIMIZED:
805 case SW_FORCEMINIMIZE:
806 return SWP_NOSIZE | SWP_NOMOVE;
807 }
808 if (!co_IntSendMessageNoWait(Wnd->head.h, WM_QUERYOPEN, 0, 0))
809 {
810 return(SWP_NOSIZE | SWP_NOMOVE);
811 }
812 SwpFlags |= SWP_NOCOPYBITS;
813 }
814 switch (ShowFlag)
815 {
816 case SW_MINIMIZE:
817 case SW_SHOWMINNOACTIVE:
818 case SW_SHOWMINIMIZED:
819 case SW_FORCEMINIMIZE:
820 {
821 //ERR("MinMaximize Minimize\n");
822 if (Wnd->style & WS_MAXIMIZE)
823 {
824 Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED;
825 }
826 else
827 {
828 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
829 }
830
831 old_style = IntSetStyle( Wnd, WS_MINIMIZE, WS_MAXIMIZE );
832
833 co_UserRedrawWindow(Wnd, NULL, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOINTERNALPAINT);
834
835 if (!(Wnd->InternalPos.flags & WPF_SETMINPOSITION))
836 Wnd->InternalPos.flags &= ~WPF_MININIT;
837
838 WinPosFindIconPos(Wnd, &wpl.ptMinPosition);
839
840 /*if (!(old_style & WS_MINIMIZE))
841 {
842 SwpFlags |= SWP_STATECHANGED;
843 IntShowOwnedPopups(Wnd, FALSE);
844 }*/
845
846 RECTL_vSetRect(NewPos, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
847 wpl.ptMinPosition.x + UserGetSystemMetrics(SM_CXMINIMIZED),
848 wpl.ptMinPosition.y + UserGetSystemMetrics(SM_CYMINIMIZED));
849 SwpFlags |= SWP_NOCOPYBITS;
850 break;
851 }
852
853 case SW_MAXIMIZE:
854 {
855 //ERR("MinMaximize Maximize\n");
856 if ((Wnd->style & WS_MAXIMIZE) && (Wnd->style & WS_VISIBLE))
857 {
858 SwpFlags = SWP_NOSIZE | SWP_NOMOVE;
859 break;
860 }
861 co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
862
863 /*ERR("Maximize: %d,%d %dx%d\n",
864 wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, Size.x, Size.y);
865 */
866 old_style = IntSetStyle( Wnd, WS_MAXIMIZE, WS_MINIMIZE );
867 /*if (old_style & WS_MINIMIZE)
868 {
869 IntShowOwnedPopups(Wnd, TRUE);
870 }*/
871
872 if (!(old_style & WS_MAXIMIZE)) SwpFlags |= SWP_STATECHANGED;
873 RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
874 //wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
875 Size.x, Size.y);
876 break;
877 }
878
879 case SW_SHOWNOACTIVATE:
880 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
881 /* fall through */
882 case SW_SHOWNORMAL:
883 case SW_RESTORE:
884 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
885 {
886 //ERR("MinMaximize Restore\n");
887 old_style = IntSetStyle( Wnd, 0, WS_MINIMIZE | WS_MAXIMIZE );
888 if (old_style & WS_MINIMIZE)
889 {
890 //IntShowOwnedPopups(Wnd, TRUE);
891
892 if (Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED)
893 {
894 co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
895 IntSetStyle( Wnd, WS_MAXIMIZE, 0 );
896 SwpFlags |= SWP_STATECHANGED;
897 RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
898 wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
899 break;
900 }
901 else
902 {
903 *NewPos = wpl.rcNormalPosition;
904 NewPos->right -= NewPos->left;
905 NewPos->bottom -= NewPos->top;
906 break;
907 }
908 }
909 else
910 {
911 if (!(old_style & WS_MAXIMIZE))
912 {
913 break;
914 }
915 SwpFlags |= SWP_STATECHANGED;
916 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
917 *NewPos = wpl.rcNormalPosition;
918 NewPos->right -= NewPos->left;
919 NewPos->bottom -= NewPos->top;
920 break;
921 }
922 }
923 }
924 return SwpFlags;
925 }
926
927 BOOL
928 UserHasWindowEdge(DWORD Style, DWORD ExStyle)
929 {
930 if (Style & WS_MINIMIZE)
931 return TRUE;
932 if (ExStyle & WS_EX_DLGMODALFRAME)
933 return TRUE;
934 if (ExStyle & WS_EX_STATICEDGE)
935 return FALSE;
936 if (Style & WS_THICKFRAME)
937 return TRUE;
938 Style &= WS_CAPTION;
939 if (Style == WS_DLGFRAME || Style == WS_CAPTION)
940 return TRUE;
941 return FALSE;
942 }
943
944 VOID FASTCALL
945 IntGetWindowBorderMeasures(PWND Wnd, UINT *cx, UINT *cy)
946 {
947 if(HAS_DLGFRAME(Wnd->style, Wnd->ExStyle) && !(Wnd->style & WS_MINIMIZE))
948 {
949 *cx = UserGetSystemMetrics(SM_CXDLGFRAME);
950 *cy = UserGetSystemMetrics(SM_CYDLGFRAME);
951 }
952 else
953 {
954 if(HAS_THICKFRAME(Wnd->style, Wnd->ExStyle)&& !(Wnd->style & WS_MINIMIZE))
955 {
956 *cx = UserGetSystemMetrics(SM_CXFRAME);
957 *cy = UserGetSystemMetrics(SM_CYFRAME);
958 }
959 else if(HAS_THINFRAME(Wnd->style, Wnd->ExStyle))
960 {
961 *cx = UserGetSystemMetrics(SM_CXBORDER);
962 *cy = UserGetSystemMetrics(SM_CYBORDER);
963 }
964 else
965 {
966 *cx = *cy = 0;
967 }
968 }
969 }
970
971 VOID
972 UserGetWindowBorders(DWORD Style, DWORD ExStyle, SIZE *Size, BOOL WithClient)
973 {
974 DWORD Border = 0;
975
976 if (UserHasWindowEdge(Style, ExStyle))
977 Border += 2;
978 else if (ExStyle & WS_EX_STATICEDGE)
979 Border += 1;
980 if ((ExStyle & WS_EX_CLIENTEDGE) && WithClient)
981 Border += 2;
982 if (Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME)
983 Border ++;
984 Size->cx = Size->cy = Border;
985 if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
986 {
987 Size->cx += UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME);
988 Size->cy += UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME);
989 }
990 Size->cx *= UserGetSystemMetrics(SM_CXBORDER);
991 Size->cy *= UserGetSystemMetrics(SM_CYBORDER);
992 }
993
994 BOOL WINAPI
995 UserAdjustWindowRectEx(LPRECT lpRect,
996 DWORD dwStyle,
997 BOOL bMenu,
998 DWORD dwExStyle)
999 {
1000 SIZE BorderSize;
1001
1002 if (bMenu)
1003 {
1004 lpRect->top -= UserGetSystemMetrics(SM_CYMENU);
1005 }
1006 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1007 {
1008 if (dwExStyle & WS_EX_TOOLWINDOW)
1009 lpRect->top -= UserGetSystemMetrics(SM_CYSMCAPTION);
1010 else
1011 lpRect->top -= UserGetSystemMetrics(SM_CYCAPTION);
1012 }
1013 UserGetWindowBorders(dwStyle, dwExStyle, &BorderSize, TRUE);
1014 RECTL_vInflateRect(
1015 lpRect,
1016 BorderSize.cx,
1017 BorderSize.cy);
1018
1019 return TRUE;
1020 }
1021
1022 UINT FASTCALL
1023 co_WinPosGetMinMaxInfo(PWND Window, POINT* MaxSize, POINT* MaxPos,
1024 POINT* MinTrack, POINT* MaxTrack)
1025 {
1026 MINMAXINFO MinMax;
1027 PMONITOR monitor;
1028 INT xinc, yinc;
1029 LONG style = Window->style;
1030 LONG adjustedStyle;
1031 LONG exstyle = Window->ExStyle;
1032 RECT rc;
1033
1034 ASSERT_REFS_CO(Window);
1035
1036 /* Compute default values */
1037
1038 rc = Window->rcWindow;
1039 MinMax.ptReserved.x = rc.left;
1040 MinMax.ptReserved.y = rc.top;
1041
1042 if ((style & WS_CAPTION) == WS_CAPTION)
1043 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
1044 else
1045 adjustedStyle = style;
1046
1047 if(Window->spwndParent)
1048 IntGetClientRect(Window->spwndParent, &rc);
1049 UserAdjustWindowRectEx(&rc, adjustedStyle, ((style & WS_POPUP) && Window->IDMenu), exstyle);
1050
1051 xinc = -rc.left;
1052 yinc = -rc.top;
1053
1054 MinMax.ptMaxSize.x = rc.right - rc.left;
1055 MinMax.ptMaxSize.y = rc.bottom - rc.top;
1056 if (style & (WS_DLGFRAME | WS_BORDER))
1057 {
1058 MinMax.ptMinTrackSize.x = UserGetSystemMetrics(SM_CXMINTRACK);
1059 MinMax.ptMinTrackSize.y = UserGetSystemMetrics(SM_CYMINTRACK);
1060 }
1061 else
1062 {
1063 MinMax.ptMinTrackSize.x = 2 * xinc;
1064 MinMax.ptMinTrackSize.y = 2 * yinc;
1065 }
1066 MinMax.ptMaxTrackSize.x = UserGetSystemMetrics(SM_CXMAXTRACK);
1067 MinMax.ptMaxTrackSize.y = UserGetSystemMetrics(SM_CYMAXTRACK);
1068 MinMax.ptMaxPosition.x = -xinc;
1069 MinMax.ptMaxPosition.y = -yinc;
1070
1071 if (!EMPTYPOINT(Window->InternalPos.MaxPos)) MinMax.ptMaxPosition = Window->InternalPos.MaxPos;
1072
1073 co_IntSendMessage(Window->head.h, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax);
1074
1075 /* if the app didn't change the values, adapt them for the current monitor */
1076 if ((monitor = UserGetPrimaryMonitor()))
1077 {
1078 RECT rc_work;
1079
1080 rc_work = monitor->rcMonitor;
1081
1082 if (style & WS_MAXIMIZEBOX)
1083 {
1084 if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP)))
1085 rc_work = monitor->rcWork;
1086 }
1087
1088 if (MinMax.ptMaxSize.x == UserGetSystemMetrics(SM_CXSCREEN) + 2 * xinc &&
1089 MinMax.ptMaxSize.y == UserGetSystemMetrics(SM_CYSCREEN) + 2 * yinc)
1090 {
1091 MinMax.ptMaxSize.x = (rc_work.right - rc_work.left) + 2 * xinc;
1092 MinMax.ptMaxSize.y = (rc_work.bottom - rc_work.top) + 2 * yinc;
1093 }
1094 if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc)
1095 {
1096 MinMax.ptMaxPosition.x = rc_work.left - xinc;
1097 MinMax.ptMaxPosition.y = rc_work.top - yinc;
1098 }
1099 if (MinMax.ptMaxSize.x >= (monitor->rcMonitor.right - monitor->rcMonitor.left) &&
1100 MinMax.ptMaxSize.y >= (monitor->rcMonitor.bottom - monitor->rcMonitor.top) )
1101 Window->state |= WNDS_MAXIMIZESTOMONITOR;
1102 else
1103 Window->state &= ~WNDS_MAXIMIZESTOMONITOR;
1104 }
1105
1106
1107 MinMax.ptMaxTrackSize.x = max(MinMax.ptMaxTrackSize.x,
1108 MinMax.ptMinTrackSize.x);
1109 MinMax.ptMaxTrackSize.y = max(MinMax.ptMaxTrackSize.y,
1110 MinMax.ptMinTrackSize.y);
1111
1112 if (MaxSize)
1113 *MaxSize = MinMax.ptMaxSize;
1114 if (MaxPos)
1115 *MaxPos = MinMax.ptMaxPosition;
1116 if (MinTrack)
1117 *MinTrack = MinMax.ptMinTrackSize;
1118 if (MaxTrack)
1119 *MaxTrack = MinMax.ptMaxTrackSize;
1120
1121 return 0; // FIXME: What does it return?
1122 }
1123
1124 static
1125 BOOL
1126 IntValidateParent(PWND Child, PREGION ValidateRgn)
1127 {
1128 PWND ParentWnd = Child;
1129
1130 if (ParentWnd->style & WS_CHILD)
1131 {
1132 do
1133 ParentWnd = ParentWnd->spwndParent;
1134 while (ParentWnd->style & WS_CHILD);
1135 }
1136
1137 ParentWnd = Child->spwndParent;
1138 while (ParentWnd)
1139 {
1140 if (ParentWnd->style & WS_CLIPCHILDREN)
1141 break;
1142
1143 if (ParentWnd->hrgnUpdate != 0)
1144 {
1145 IntInvalidateWindows( ParentWnd,
1146 ValidateRgn,
1147 RDW_VALIDATE | RDW_NOCHILDREN);
1148 }
1149
1150 ParentWnd = ParentWnd->spwndParent;
1151 }
1152
1153 return TRUE;
1154 }
1155
1156 static
1157 VOID FASTCALL
1158 FixClientRect(PRECTL ClientRect, PRECTL WindowRect)
1159 {
1160 if (ClientRect->left < WindowRect->left)
1161 {
1162 ClientRect->left = WindowRect->left;
1163 }
1164 else if (WindowRect->right < ClientRect->left)
1165 {
1166 ClientRect->left = WindowRect->right;
1167 }
1168 if (ClientRect->right < WindowRect->left)
1169 {
1170 ClientRect->right = WindowRect->left;
1171 }
1172 else if (WindowRect->right < ClientRect->right)
1173 {
1174 ClientRect->right = WindowRect->right;
1175 }
1176 if (ClientRect->top < WindowRect->top)
1177 {
1178 ClientRect->top = WindowRect->top;
1179 }
1180 else if (WindowRect->bottom < ClientRect->top)
1181 {
1182 ClientRect->top = WindowRect->bottom;
1183 }
1184 if (ClientRect->bottom < WindowRect->top)
1185 {
1186 ClientRect->bottom = WindowRect->top;
1187 }
1188 else if (WindowRect->bottom < ClientRect->bottom)
1189 {
1190 ClientRect->bottom = WindowRect->bottom;
1191 }
1192 }
1193 /***********************************************************************
1194 * get_valid_rects
1195 *
1196 * Compute the valid rects from the old and new client rect and WVR_* flags.
1197 * Helper for WM_NCCALCSIZE handling.
1198 */
1199 static
1200 VOID FASTCALL
1201 get_valid_rects( RECTL *old_client, RECTL *new_client, UINT flags, RECTL *valid )
1202 {
1203 int cx, cy;
1204
1205 if (flags & WVR_REDRAW)
1206 {
1207 RECTL_vSetEmptyRect( &valid[0] );
1208 RECTL_vSetEmptyRect( &valid[1] );
1209 return;
1210 }
1211
1212 if (flags & WVR_VALIDRECTS)
1213 {
1214 if (!RECTL_bIntersectRect( &valid[0], &valid[0], new_client ) ||
1215 !RECTL_bIntersectRect( &valid[1], &valid[1], old_client ))
1216 {
1217 RECTL_vSetEmptyRect( &valid[0] );
1218 RECTL_vSetEmptyRect( &valid[1] );
1219 return;
1220 }
1221 flags = WVR_ALIGNLEFT | WVR_ALIGNTOP;
1222 }
1223 else
1224 {
1225 valid[0] = *new_client;
1226 valid[1] = *old_client;
1227 }
1228
1229 /* make sure the rectangles have the same size */
1230 cx = min( valid[0].right - valid[0].left, valid[1].right - valid[1].left );
1231 cy = min( valid[0].bottom - valid[0].top, valid[1].bottom - valid[1].top );
1232
1233 if (flags & WVR_ALIGNBOTTOM)
1234 {
1235 valid[0].top = valid[0].bottom - cy;
1236 valid[1].top = valid[1].bottom - cy;
1237 }
1238 else
1239 {
1240 valid[0].bottom = valid[0].top + cy;
1241 valid[1].bottom = valid[1].top + cy;
1242 }
1243 if (flags & WVR_ALIGNRIGHT)
1244 {
1245 valid[0].left = valid[0].right - cx;
1246 valid[1].left = valid[1].right - cx;
1247 }
1248 else
1249 {
1250 valid[0].right = valid[0].left + cx;
1251 valid[1].right = valid[1].left + cx;
1252 }
1253 }
1254
1255 static
1256 LONG FASTCALL
1257 co_WinPosDoNCCALCSize(PWND Window, PWINDOWPOS WinPos, RECTL* WindowRect, RECTL* ClientRect, RECTL* validRects)
1258 {
1259 PWND Parent;
1260 UINT wvrFlags = 0;
1261
1262 ASSERT_REFS_CO(Window);
1263
1264 /* Send WM_NCCALCSIZE message to get new client area */
1265 if ((WinPos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE)
1266 {
1267 NCCALCSIZE_PARAMS params;
1268 WINDOWPOS winposCopy;
1269
1270 params.rgrc[0] = *WindowRect; // new coordinates of a window that has been moved or resized
1271 params.rgrc[1] = Window->rcWindow; // window before it was moved or resized
1272 params.rgrc[2] = Window->rcClient; // client area before the window was moved or resized
1273
1274 Parent = Window->spwndParent;
1275 if (0 != (Window->style & WS_CHILD) && Parent)
1276 {
1277 RECTL_vOffsetRect(&(params.rgrc[0]), - Parent->rcClient.left, - Parent->rcClient.top);
1278 RECTL_vOffsetRect(&(params.rgrc[1]), - Parent->rcClient.left, - Parent->rcClient.top);
1279 RECTL_vOffsetRect(&(params.rgrc[2]), - Parent->rcClient.left, - Parent->rcClient.top);
1280 }
1281
1282 params.lppos = &winposCopy;
1283 winposCopy = *WinPos;
1284
1285 wvrFlags = co_IntSendMessage(Window->head.h, WM_NCCALCSIZE, TRUE, (LPARAM) &params);
1286
1287 /* If the application send back garbage, ignore it */
1288 if (params.rgrc[0].left <= params.rgrc[0].right &&
1289 params.rgrc[0].top <= params.rgrc[0].bottom)
1290 {
1291 *ClientRect = params.rgrc[0]; // First rectangle contains the coordinates of the new client rectangle resulting from the move or resize
1292 if ((Window->style & WS_CHILD) && Parent)
1293 {
1294 RECTL_vOffsetRect(ClientRect, Parent->rcClient.left, Parent->rcClient.top);
1295 }
1296 FixClientRect(ClientRect, WindowRect);
1297 }
1298
1299 if (ClientRect->left != Window->rcClient.left ||
1300 ClientRect->top != Window->rcClient.top)
1301 {
1302 WinPos->flags &= ~SWP_NOCLIENTMOVE;
1303 }
1304
1305 if (ClientRect->right - ClientRect->left != Window->rcClient.right - Window->rcClient.left)
1306 {
1307 WinPos->flags &= ~SWP_NOCLIENTSIZE;
1308 }
1309 else
1310 wvrFlags &= ~WVR_HREDRAW;
1311
1312 if (ClientRect->bottom - ClientRect->top != Window->rcClient.bottom - Window->rcClient.top)
1313 {
1314 WinPos->flags &= ~SWP_NOCLIENTSIZE;
1315 }
1316 else
1317 wvrFlags &= ~WVR_VREDRAW;
1318
1319 validRects[0] = params.rgrc[1]; // second rectangle contains the valid destination rectangle
1320 validRects[1] = params.rgrc[2]; // third rectangle contains the valid source rectangle
1321 }
1322 else
1323 {
1324 if (!(WinPos->flags & SWP_NOMOVE) &&
1325 (ClientRect->left != Window->rcClient.left ||
1326 ClientRect->top != Window->rcClient.top))
1327 {
1328 WinPos->flags &= ~SWP_NOCLIENTMOVE;
1329 }
1330 }
1331
1332 if (WinPos->flags & (SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_HIDEWINDOW))
1333 {
1334 RECTL_vSetEmptyRect( &validRects[0] );
1335 RECTL_vSetEmptyRect( &validRects[1] );
1336 }
1337 else get_valid_rects( &Window->rcClient, ClientRect, wvrFlags, validRects );
1338
1339 return wvrFlags;
1340 }
1341
1342 static
1343 BOOL FASTCALL
1344 co_WinPosDoWinPosChanging(PWND Window,
1345 PWINDOWPOS WinPos,
1346 PRECTL WindowRect,
1347 PRECTL ClientRect)
1348 {
1349 ASSERT_REFS_CO(Window);
1350
1351 /* Send WM_WINDOWPOSCHANGING message */
1352
1353 if (!(WinPos->flags & SWP_NOSENDCHANGING))
1354 {
1355 TRACE("Sending WM_WINDOWPOSCHANGING to hwnd %p flags %04x.\n", Window->head.h,WinPos->flags);
1356 co_IntSendMessage(Window->head.h, WM_WINDOWPOSCHANGING, 0, (LPARAM) WinPos);
1357 }
1358
1359 /* Calculate new position and size */
1360
1361 *WindowRect = Window->rcWindow;
1362 *ClientRect = (Window->style & WS_MINIMIZE) ? Window->rcWindow : Window->rcClient;
1363
1364 if (!(WinPos->flags & SWP_NOSIZE))
1365 {
1366 if (Window->style & WS_MINIMIZE)
1367 {
1368 WindowRect->right = WindowRect->left + UserGetSystemMetrics(SM_CXMINIMIZED);
1369 WindowRect->bottom = WindowRect->top + UserGetSystemMetrics(SM_CYMINIMIZED);
1370 }
1371 else
1372 {
1373 WindowRect->right = WindowRect->left + WinPos->cx;
1374 WindowRect->bottom = WindowRect->top + WinPos->cy;
1375 }
1376 }
1377
1378 if (!(WinPos->flags & SWP_NOMOVE))
1379 {
1380 INT X, Y;
1381 PWND Parent;
1382 X = WinPos->x;
1383 Y = WinPos->y;
1384
1385 Parent = Window->spwndParent;
1386
1387 // Parent child position issue is in here. SetParent_W7 test CORE-6651.
1388 if (//((Window->style & WS_CHILD) != 0) && <- Fixes wine msg test_SetParent: "rects do not match", the last test.
1389 Parent &&
1390 Parent != Window->head.rpdesk->pDeskInfo->spwnd)
1391 {
1392 TRACE("Not SWP_NOMOVE 1 Parent client offset X %d Y %d\n",X,Y);
1393 X += Parent->rcClient.left;
1394 Y += Parent->rcClient.top;
1395 TRACE("Not SWP_NOMOVE 2 Parent client offset X %d Y %d\n",X,Y);
1396 }
1397
1398 WindowRect->left = X;
1399 WindowRect->top = Y;
1400 WindowRect->right += X - Window->rcWindow.left;
1401 WindowRect->bottom += Y - Window->rcWindow.top;
1402
1403 RECTL_vOffsetRect(ClientRect, X - Window->rcWindow.left,
1404 Y - Window->rcWindow.top);
1405 }
1406 WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
1407
1408 TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
1409 WinPos->hwnd, WinPos->hwndInsertAfter, WinPos->x, WinPos->y,
1410 WinPos->cx, WinPos->cy, WinPos->flags );
1411 TRACE("WindowRect: %d %d %d %d\n", WindowRect->left,WindowRect->top,WindowRect->right,WindowRect->bottom);
1412 TRACE("ClientRect: %d %d %d %d\n", ClientRect->left,ClientRect->top,ClientRect->right,ClientRect->bottom);
1413
1414 return TRUE;
1415 }
1416
1417 /*
1418 * Fix Z order taking into account owned popups -
1419 * basically we need to maintain them above the window that owns them
1420 *
1421 * FIXME: hide/show owned popups when owner visibility changes.
1422 *
1423 * ReactOS: See bug CORE-6129 and CORE-6554.
1424 *
1425 */
1426 ////
1427 // Pass all the win:test_children/popup_zorder tests except "move hwnd_F and its popups down" which is if'ed out.
1428 // Side effect, breaks more of the DeferWindowPos api tests, but wine breaks more!!!!
1429 static
1430 HWND FASTCALL
1431 WinPosDoOwnedPopups(PWND Window, HWND hWndInsertAfter)
1432 {
1433 HWND *List = NULL;
1434 HWND Owner;
1435 LONG Style;
1436 PWND DesktopWindow, ChildObject;
1437 int i;
1438
1439 TRACE("(%p) hInsertAfter = %p\n", Window, hWndInsertAfter );
1440
1441 Style = Window->style;
1442
1443 if (Style & WS_CHILD)
1444 {
1445 TRACE("Window is child\n");
1446 return hWndInsertAfter;
1447 }
1448
1449 Owner = Window->spwndOwner ? Window->spwndOwner->head.h : NULL;
1450
1451 if (Owner)
1452 {
1453 /* Make sure this popup stays above the owner */
1454
1455 if (hWndInsertAfter != HWND_TOPMOST)
1456 {
1457 DesktopWindow = UserGetDesktopWindow();
1458 List = IntWinListChildren(DesktopWindow);
1459
1460 if (List != NULL)
1461 {
1462 for (i = 0; List[i]; i++)
1463 {
1464 BOOL topmost = FALSE;
1465
1466 ChildObject = ValidateHwndNoErr(List[i]);
1467 if (ChildObject)
1468 {
1469 topmost = (ChildObject->ExStyle & WS_EX_TOPMOST) != 0;
1470 }
1471
1472 if (List[i] == Owner)
1473 {
1474 if (i > 0) hWndInsertAfter = List[i-1];
1475 else hWndInsertAfter = topmost ? HWND_TOPMOST : HWND_TOP;
1476 break;
1477 }
1478
1479 if (hWndInsertAfter == HWND_TOP || hWndInsertAfter == HWND_NOTOPMOST)
1480 {
1481 if (!topmost) break;
1482 }
1483 else if (List[i] == hWndInsertAfter) break;
1484 }
1485 }
1486 else
1487 return hWndInsertAfter;
1488 }
1489 }
1490
1491 if (hWndInsertAfter == HWND_BOTTOM)
1492 {
1493 ERR("Window is HWND_BOTTOM hwnd %p\n",hWndInsertAfter);
1494 if (List) ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1495 goto done;
1496 }
1497
1498 if (!List)
1499 {
1500 DesktopWindow = UserGetDesktopWindow();
1501 List = IntWinListChildren(DesktopWindow);
1502 }
1503
1504 if (List != NULL)
1505 {
1506 i = 0;
1507
1508 if (hWndInsertAfter == HWND_TOP || hWndInsertAfter == HWND_NOTOPMOST)
1509 {
1510 if (hWndInsertAfter == HWND_NOTOPMOST || !(Window->ExStyle & WS_EX_TOPMOST))
1511 {
1512 TRACE("skip all the topmost windows\n");
1513 /* skip all the topmost windows */
1514 while (List[i] &&
1515 (ChildObject = ValidateHwndNoErr(List[i])) &&
1516 (ChildObject->ExStyle & WS_EX_TOPMOST)) i++;
1517 }
1518 }
1519 else if (hWndInsertAfter != HWND_TOPMOST)
1520 {
1521 /* skip windows that are already placed correctly */
1522 for (i = 0; List[i]; i++)
1523 {
1524 if (List[i] == hWndInsertAfter) break;
1525 if (List[i] == UserHMGetHandle(Window))
1526 {
1527 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1528 goto done; /* nothing to do if window is moving backwards in z-order */
1529 }
1530 }
1531 }
1532
1533 for (; List[i]; i++)
1534 {
1535 PWND Wnd;
1536 USER_REFERENCE_ENTRY Ref;
1537
1538 if (List[i] == UserHMGetHandle(Window))
1539 break;
1540
1541 if (!(Wnd = ValidateHwndNoErr(List[i])))
1542 continue;
1543
1544 Owner = Wnd->spwndOwner ? Wnd->spwndOwner->head.h : NULL;
1545
1546 if (Owner != UserHMGetHandle(Window)) continue;
1547
1548 UserRefObjectCo(Wnd, &Ref);
1549 TRACE( "moving %p owned by %p after %p\n", List[i], UserHMGetHandle(Window), hWndInsertAfter );
1550 co_WinPosSetWindowPos(Wnd, hWndInsertAfter, 0, 0, 0, 0,
1551 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING| SWP_DEFERERASE);
1552
1553 UserDerefObjectCo(Wnd);
1554 hWndInsertAfter = List[i];
1555 }
1556 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1557 }
1558 done:
1559 return hWndInsertAfter;
1560 }
1561 ////
1562
1563 /***********************************************************************
1564 * WinPosInternalMoveWindow
1565 *
1566 * Update WindowRect and ClientRect of Window and all of its children
1567 * We keep both WindowRect and ClientRect in screen coordinates internally
1568 */
1569 static
1570 VOID FASTCALL
1571 WinPosInternalMoveWindow(PWND Window, INT MoveX, INT MoveY)
1572 {
1573 PWND Child;
1574
1575 ASSERT(Window != Window->spwndChild);
1576 TRACE("InternalMoveWin X %d Y %d\n", MoveX, MoveY);
1577
1578 Window->rcWindow.left += MoveX;
1579 Window->rcWindow.right += MoveX;
1580 Window->rcWindow.top += MoveY;
1581 Window->rcWindow.bottom += MoveY;
1582
1583 Window->rcClient.left += MoveX;
1584 Window->rcClient.right += MoveX;
1585 Window->rcClient.top += MoveY;
1586 Window->rcClient.bottom += MoveY;
1587
1588 for(Child = Window->spwndChild; Child; Child = Child->spwndNext)
1589 {
1590 WinPosInternalMoveWindow(Child, MoveX, MoveY);
1591 }
1592 }
1593
1594 /*
1595 * WinPosFixupSWPFlags
1596 *
1597 * Fix redundant flags and values in the WINDOWPOS structure.
1598 */
1599 static
1600 BOOL FASTCALL
1601 WinPosFixupFlags(WINDOWPOS *WinPos, PWND Wnd)
1602 {
1603 PWND Parent;
1604 POINT pt;
1605
1606 /* Finally make sure that all coordinates are valid */
1607 if (WinPos->x < -32768) WinPos->x = -32768;
1608 else if (WinPos->x > 32767) WinPos->x = 32767;
1609 if (WinPos->y < -32768) WinPos->y = -32768;
1610 else if (WinPos->y > 32767) WinPos->y = 32767;
1611
1612 WinPos->cx = max(WinPos->cx, 0);
1613 WinPos->cy = max(WinPos->cy, 0);
1614
1615 Parent = UserGetAncestor( Wnd, GA_PARENT );
1616 if (!IntIsWindowVisible( Parent ) &&
1617 /* Fix B : wine msg test_SetParent:WmSetParentSeq_2:25 wParam bits! */
1618 (WinPos->flags & SWP_AGG_STATUSFLAGS) == SWP_AGG_NOPOSCHANGE) WinPos->flags |= SWP_NOREDRAW;
1619
1620 if (Wnd->style & WS_VISIBLE) WinPos->flags &= ~SWP_SHOWWINDOW;
1621 else
1622 {
1623 WinPos->flags &= ~SWP_HIDEWINDOW;
1624 if (!(WinPos->flags & SWP_SHOWWINDOW)) WinPos->flags |= SWP_NOREDRAW;
1625 }
1626
1627 /* Check for right size */
1628 if (Wnd->rcWindow.right - Wnd->rcWindow.left == WinPos->cx &&
1629 Wnd->rcWindow.bottom - Wnd->rcWindow.top == WinPos->cy)
1630 {
1631 WinPos->flags |= SWP_NOSIZE;
1632 }
1633
1634 pt.x = WinPos->x;
1635 pt.y = WinPos->y;
1636 IntClientToScreen( Parent, &pt );
1637 TRACE("WPFU C2S wpx %d wpy %d ptx %d pty %d\n",WinPos->x,WinPos->y,pt.x,pt.y);
1638 /* Check for right position */
1639 if (Wnd->rcWindow.left == pt.x && Wnd->rcWindow.top == pt.y)
1640 {
1641 //ERR("In right pos\n");
1642 WinPos->flags |= SWP_NOMOVE;
1643 }
1644
1645 if ( WinPos->hwnd != UserGetForegroundWindow() && (Wnd->style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
1646 {
1647 /* Bring to the top when activating */
1648 if (!(WinPos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)) &&
1649 (WinPos->flags & SWP_NOZORDER ||
1650 (WinPos->hwndInsertAfter != HWND_TOPMOST && WinPos->hwndInsertAfter != HWND_NOTOPMOST)))
1651 {
1652 WinPos->flags &= ~SWP_NOZORDER;
1653 WinPos->hwndInsertAfter = (0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP);
1654 }
1655 }
1656
1657 /* Check hwndInsertAfter */
1658 if (!(WinPos->flags & SWP_NOZORDER))
1659 {
1660 /* Fix sign extension */
1661 if (WinPos->hwndInsertAfter == (HWND)0xffff)
1662 {
1663 WinPos->hwndInsertAfter = HWND_TOPMOST;
1664 }
1665 else if (WinPos->hwndInsertAfter == (HWND)0xfffe)
1666 {
1667 WinPos->hwndInsertAfter = HWND_NOTOPMOST;
1668 }
1669
1670 if (WinPos->hwndInsertAfter == HWND_TOP)
1671 {
1672 /* Keep it topmost when it's already topmost */
1673 if ((Wnd->ExStyle & WS_EX_TOPMOST) != 0)
1674 WinPos->hwndInsertAfter = HWND_TOPMOST;
1675
1676 if (IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd)
1677 {
1678 WinPos->flags |= SWP_NOZORDER;
1679 }
1680 }
1681 else if (WinPos->hwndInsertAfter == HWND_BOTTOM)
1682 {
1683 if (!(Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDLAST) == WinPos->hwnd)
1684 WinPos->flags |= SWP_NOZORDER;
1685 }
1686 else if (WinPos->hwndInsertAfter == HWND_TOPMOST)
1687 {
1688 if ((Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd)
1689 WinPos->flags |= SWP_NOZORDER;
1690 }
1691 else if (WinPos->hwndInsertAfter == HWND_NOTOPMOST)
1692 {
1693 if (!(Wnd->ExStyle & WS_EX_TOPMOST))
1694 WinPos->flags |= SWP_NOZORDER;
1695 }
1696 else /* hwndInsertAfter must be a sibling of the window */
1697 {
1698 PWND InsAfterWnd;
1699
1700 InsAfterWnd = ValidateHwndNoErr(WinPos->hwndInsertAfter);
1701 if(!InsAfterWnd)
1702 {
1703 return TRUE;
1704 }
1705
1706 if (InsAfterWnd->spwndParent != Wnd->spwndParent)
1707 {
1708 /* Note from wine User32 Win test_SetWindowPos:
1709 "Returns TRUE also for windows that are not siblings"
1710 "Does not seem to do anything even without passing flags, still returns TRUE"
1711 "Same thing the other way around."
1712 ".. and with these windows."
1713 */
1714 return FALSE;
1715 }
1716 else
1717 {
1718 /*
1719 * We don't need to change the Z order of hwnd if it's already
1720 * inserted after hwndInsertAfter or when inserting hwnd after
1721 * itself.
1722 */
1723 if ((WinPos->hwnd == WinPos->hwndInsertAfter) ||
1724 ((InsAfterWnd->spwndNext) && (WinPos->hwnd == InsAfterWnd->spwndNext->head.h)))
1725 {
1726 WinPos->flags |= SWP_NOZORDER;
1727 }
1728 }
1729 }
1730 }
1731
1732 return TRUE;
1733 }
1734
1735 /* x and y are always screen relative */
1736 BOOLEAN FASTCALL
1737 co_WinPosSetWindowPos(
1738 PWND Window,
1739 HWND WndInsertAfter,
1740 INT x,
1741 INT y,
1742 INT cx,
1743 INT cy,
1744 UINT flags
1745 )
1746 {
1747 WINDOWPOS WinPos;
1748 RECTL NewWindowRect;
1749 RECTL NewClientRect;
1750 RECTL valid_rects[2];
1751 PREGION VisBefore = NULL;
1752 PREGION VisBeforeJustClient = NULL;
1753 PREGION VisAfter = NULL;
1754 PREGION CopyRgn = NULL;
1755 ULONG WvrFlags = 0;
1756 RECTL OldWindowRect, OldClientRect;
1757 int RgnType;
1758 HDC Dc;
1759 RECTL CopyRect;
1760 PWND Ancestor;
1761 BOOL bPointerInWindow;
1762 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1763
1764 ASSERT_REFS_CO(Window);
1765
1766 /* FIXME: Get current active window from active queue. Why? since r2915. */
1767
1768 bPointerInWindow = IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y);
1769
1770 WinPos.hwnd = Window->head.h;
1771 WinPos.hwndInsertAfter = WndInsertAfter;
1772 WinPos.x = x;
1773 WinPos.y = y;
1774 WinPos.cx = cx;
1775 WinPos.cy = cy;
1776 WinPos.flags = flags;
1777
1778 if ( flags & SWP_ASYNCWINDOWPOS )
1779 {
1780 LRESULT lRes;
1781 PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
1782 if ( ppos )
1783 {
1784 WinPos.flags &= ~SWP_ASYNCWINDOWPOS; // Clear flag.
1785 *ppos = WinPos;
1786 /* Yes it's a pointer inside Win32k! */
1787 lRes = co_IntSendMessageNoWait( WinPos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
1788 /* We handle this the same way as Event Hooks and Hooks. */
1789 if ( !lRes )
1790 {
1791 ExFreePoolWithTag(ppos, USERTAG_SWP);
1792 return FALSE;
1793 }
1794 return TRUE;
1795 }
1796 return FALSE;
1797 }
1798
1799 co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
1800
1801 /* Does the window still exist? */
1802 if (!IntIsWindow(WinPos.hwnd))
1803 {
1804 TRACE("WinPosSetWindowPos: Invalid handle 0x%p!\n",WinPos.hwnd);
1805 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
1806 return FALSE;
1807 }
1808
1809 /* Fix up the flags. */
1810 if (!WinPosFixupFlags(&WinPos, Window))
1811 {
1812 // See Note.
1813 return TRUE;
1814 }
1815
1816 Ancestor = UserGetAncestor(Window, GA_PARENT);
1817 if ( (WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER &&
1818 Ancestor && Ancestor->head.h == IntGetDesktopWindow() )
1819 {
1820 WinPos.hwndInsertAfter = WinPosDoOwnedPopups(Window, WinPos.hwndInsertAfter);
1821 }
1822
1823 if (!(WinPos.flags & SWP_NOREDRAW))
1824 {
1825 /* Compute the visible region before the window position is changed */
1826 if (!(WinPos.flags & SWP_SHOWWINDOW) &&
1827 (WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
1828 SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
1829 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
1830 {
1831 VisBefore = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1832 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1833
1834 if ( VisBefore != NULL &&
1835 REGION_Complexity(VisBefore) == NULLREGION )
1836 {
1837 REGION_Delete(VisBefore);
1838 VisBefore = NULL;
1839 }
1840 else if(VisBefore)
1841 {
1842 REGION_bOffsetRgn(VisBefore, -Window->rcWindow.left, -Window->rcWindow.top);
1843 }
1844
1845 /* Calculate the non client area for resizes, as this is used in the copy region */
1846 if (!(WinPos.flags & SWP_NOSIZE))
1847 {
1848 VisBeforeJustClient = VIS_ComputeVisibleRegion(Window, TRUE, FALSE,
1849 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1850
1851 if ( VisBeforeJustClient != NULL &&
1852 REGION_Complexity(VisBeforeJustClient) == NULLREGION )
1853 {
1854 REGION_Delete(VisBeforeJustClient);
1855 VisBeforeJustClient = NULL;
1856 }
1857 else if(VisBeforeJustClient)
1858 {
1859 REGION_bOffsetRgn(VisBeforeJustClient, -Window->rcWindow.left, -Window->rcWindow.top);
1860 }
1861 }
1862 }
1863 }
1864
1865 WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect, valid_rects);
1866
1867 // ERR("co_WinPosDoNCCALCSize returned 0x%x\n valid dest: %d %d %d %d\n valid src : %d %d %d %d\n", WvrFlags,
1868 // valid_rects[0].left,valid_rects[0].top,valid_rects[0].right,valid_rects[0].bottom,
1869 // valid_rects[1].left,valid_rects[1].top,valid_rects[1].right,valid_rects[1].bottom);
1870
1871 /* Validate link windows. (also take into account shell window in hwndShellWindow) */
1872 if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow())
1873 {
1874 IntLinkHwnd(Window, WinPos.hwndInsertAfter);
1875 }
1876
1877 OldWindowRect = Window->rcWindow;
1878 OldClientRect = Window->rcClient;
1879
1880 if (NewClientRect.left != OldClientRect.left ||
1881 NewClientRect.top != OldClientRect.top)
1882 {
1883 // Move child window if their parent is moved. Keep Child window relative to Parent...
1884 WinPosInternalMoveWindow(Window,
1885 NewClientRect.left - OldClientRect.left,
1886 NewClientRect.top - OldClientRect.top);
1887 }
1888
1889 Window->rcWindow = NewWindowRect;
1890 Window->rcClient = NewClientRect;
1891
1892 /* erase parent when hiding or resizing child */
1893 if (WinPos.flags & SWP_HIDEWINDOW)
1894 {
1895 /* Clear the update region */
1896 co_UserRedrawWindow( Window,
1897 NULL,
1898 0,
1899 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
1900
1901 if (Window->spwndParent == UserGetDesktopWindow())
1902 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM)Window->head.h, 0);
1903
1904 Window->style &= ~WS_VISIBLE; //IntSetStyle( Window, 0, WS_VISIBLE );
1905 Window->head.pti->cVisWindows--;
1906 IntNotifyWinEvent(EVENT_OBJECT_HIDE, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1907 }
1908 else if (WinPos.flags & SWP_SHOWWINDOW)
1909 {
1910 if (Window->spwndParent == UserGetDesktopWindow() &&
1911 Window->spwndOwner == NULL &&
1912 (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
1913 (Window->ExStyle & WS_EX_APPWINDOW)))
1914 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)Window->head.h, 0);
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 if (!(WinPos.flags & SWP_NOREDRAW))
1931 {
1932 /* Determine the new visible region */
1933 VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1934 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1935
1936 if ( VisAfter != NULL &&
1937 REGION_Complexity(VisAfter) == NULLREGION )
1938 {
1939 REGION_Delete(VisAfter);
1940 VisAfter = NULL;
1941 }
1942 else if(VisAfter)
1943 {
1944 REGION_bOffsetRgn(VisAfter, -Window->rcWindow.left, -Window->rcWindow.top);
1945 }
1946
1947 /*
1948 * Determine which pixels can be copied from the old window position
1949 * to the new. Those pixels must be visible in both the old and new
1950 * position. Also, check the class style to see if the windows of this
1951 * class need to be completely repainted on (horizontal/vertical) size
1952 * change.
1953 */
1954 if ( VisBefore != NULL &&
1955 VisAfter != NULL &&
1956 !(WinPos.flags & SWP_NOCOPYBITS) &&
1957 ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) &&
1958 !(Window->ExStyle & WS_EX_TRANSPARENT) )
1959 {
1960
1961 /*
1962 * If this is (also) a window resize, the whole nonclient area
1963 * needs to be repainted. So we limit the copy to the client area,
1964 * 'cause there is no use in copying it (would possibly cause
1965 * "flashing" too). However, if the copy region is already empty,
1966 * we don't have to crop (can't take anything away from an empty
1967 * region...)
1968 */
1969
1970 CopyRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
1971 if (WinPos.flags & SWP_NOSIZE)
1972 RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
1973 else if (VisBeforeJustClient != NULL)
1974 {
1975 RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBeforeJustClient, RGN_AND);
1976 REGION_Delete(VisBeforeJustClient);
1977 }
1978
1979 /* No use in copying bits which are in the update region. */
1980 if (Window->hrgnUpdate != NULL)
1981 {
1982 PREGION RgnUpdate = REGION_LockRgn(Window->hrgnUpdate);
1983 if (RgnUpdate)
1984 {
1985 REGION_bOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1986 IntGdiCombineRgn(CopyRgn, CopyRgn, RgnUpdate, RGN_DIFF);
1987 REGION_bOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1988 REGION_UnlockRgn(RgnUpdate);
1989 }
1990 }
1991
1992 /*
1993 * Now, get the bounding box of the copy region. If it's empty
1994 * there's nothing to copy. Also, it's no use copying bits onto
1995 * themselves.
1996 */
1997 if (REGION_GetRgnBox(CopyRgn, &CopyRect) == NULLREGION)
1998 {
1999 /* Nothing to copy, clean up */
2000 REGION_Delete(CopyRgn);
2001 CopyRgn = NULL;
2002 }
2003 else if (OldWindowRect.left != NewWindowRect.left ||
2004 OldWindowRect.top != NewWindowRect.top)
2005 {
2006 HRGN DcRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
2007 PREGION DcRgnObj = REGION_LockRgn(DcRgn);
2008
2009 /*
2010 * Small trick here: there is no function to bitblt a region. So
2011 * we set the region as the clipping region, take the bounding box
2012 * of the region and bitblt that. Since nothing outside the clipping
2013 * region is copied, this has the effect of bitblt'ing the region.
2014 *
2015 * Since NtUserGetDCEx takes ownership of the clip region, we need
2016 * to create a copy of CopyRgn and pass that. We need CopyRgn later
2017 */
2018 IntGdiCombineRgn(DcRgnObj, CopyRgn, NULL, RGN_COPY);
2019 REGION_bOffsetRgn(DcRgnObj, NewWindowRect.left, NewWindowRect.top);
2020 REGION_UnlockRgn(DcRgnObj);
2021 Dc = UserGetDCEx( Window,
2022 DcRgn,
2023 DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN);
2024 NtGdiBitBlt( Dc,
2025 CopyRect.left, CopyRect.top,
2026 CopyRect.right - CopyRect.left,
2027 CopyRect.bottom - CopyRect.top,
2028 Dc,
2029 CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
2030 CopyRect.top + (OldWindowRect.top - NewWindowRect.top),
2031 SRCCOPY,
2032 0,
2033 0);
2034
2035 UserReleaseDC(Window, Dc, FALSE);
2036 IntValidateParent(Window, CopyRgn);
2037 GreDeleteObject(DcRgn);
2038 }
2039 }
2040 else
2041 {
2042 CopyRgn = NULL;
2043 }
2044
2045 /* We need to redraw what wasn't visible before */
2046 if (VisAfter != NULL)
2047 {
2048 PREGION DirtyRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
2049 if (DirtyRgn)
2050 {
2051 if (CopyRgn != NULL)
2052 {
2053 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
2054 }
2055 else
2056 {
2057 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
2058 }
2059
2060 if (RgnType != ERROR && RgnType != NULLREGION)
2061 {
2062 /* old code
2063 NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2064 IntInvalidateWindows( Window,
2065 DirtyRgn,
2066 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2067 }
2068 GreDeleteObject(DirtyRgn);
2069 */
2070
2071 PWND Parent = Window->spwndParent;
2072
2073 REGION_bOffsetRgn( DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2074
2075 if ( (Window->style & WS_CHILD) && (Parent) && !(Parent->style & WS_CLIPCHILDREN))
2076 {
2077 IntInvalidateWindows( Parent, DirtyRgn, RDW_ERASE | RDW_INVALIDATE);
2078 co_IntPaintWindows(Parent, RDW_NOCHILDREN, FALSE);
2079 }
2080 else
2081 {
2082 IntInvalidateWindows( Window, DirtyRgn, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2083 }
2084 }
2085 REGION_Delete(DirtyRgn);
2086 }
2087 }
2088
2089 if (CopyRgn != NULL)
2090 {
2091 REGION_Delete(CopyRgn);
2092 }
2093
2094 /* Expose what was covered before but not covered anymore */
2095 if (VisBefore != NULL)
2096 {
2097 PREGION ExposedRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
2098 if (ExposedRgn)
2099 {
2100 RgnType = IntGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
2101 REGION_bOffsetRgn(ExposedRgn,
2102 OldWindowRect.left - NewWindowRect.left,
2103 OldWindowRect.top - NewWindowRect.top);
2104
2105 if (VisAfter != NULL)
2106 RgnType = IntGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
2107
2108 if (RgnType != ERROR && RgnType != NULLREGION)
2109 {
2110 co_VIS_WindowLayoutChanged(Window, ExposedRgn);
2111 }
2112 REGION_Delete(ExposedRgn);
2113 }
2114 REGION_Delete(VisBefore);
2115 }
2116
2117 if (VisAfter != NULL)
2118 {
2119 REGION_Delete(VisAfter);
2120 }
2121 }
2122
2123 if (!(WinPos.flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
2124 {
2125 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2126 {
2127 co_IntSendMessageNoWait(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
2128 }
2129 /* Do not allow setting if already active.
2130 Fix A : wine msg test_SetParent:WmSetParentSeq_2:25 msg!
2131 Recursion broke the tests.
2132 */
2133 else if ( pti->MessageQueue->spwndActive != Window ||
2134 pti->MessageQueue != gpqForeground ) // This fixes the breakage at boot time caused by the above line!
2135 {
2136 // Inside SAW? Fixes Api AttachThreadInput tests.
2137 TRACE("SetWindowPos Set FG Window! hWnd %p\n",WinPos.hwnd);
2138 if (!(Window->state & WNDS_BEINGACTIVATED))
2139 {
2140 TRACE("SetWindowPos Set FG Window!\n");
2141 // Fixes SW_HIDE issues. Wine win test_SetActiveWindow & test_SetForegroundWindow.
2142 co_IntSetForegroundWindow(Window);
2143 }
2144 }
2145 }
2146
2147 // Fix wine msg test_SetFocus, prevents sending WM_WINDOWPOSCHANGED.
2148 if ( VisBefore == NULL &&
2149 VisBeforeJustClient == NULL &&
2150 !(Window->ExStyle & WS_EX_TOPMOST) &&
2151 (WinPos.flags & SWP_AGG_STATUSFLAGS) == (SWP_AGG_NOPOSCHANGE & ~SWP_NOZORDER))
2152 {
2153 TRACE("No drawing, set no Z order and no redraw!\n");
2154 WinPos.flags |= SWP_NOZORDER|SWP_NOREDRAW;
2155 }
2156
2157 /* And last, send the WM_WINDOWPOSCHANGED message */
2158
2159 TRACE("\tstatus hwnd %p flags = %04x\n",Window?Window->head.h:NULL,WinPos.flags & SWP_AGG_STATUSFLAGS);
2160
2161 if ((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2162 {
2163 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
2164 and always contains final window position.
2165 */
2166 WinPos.x = NewWindowRect.left;
2167 WinPos.y = NewWindowRect.top;
2168 WinPos.cx = NewWindowRect.right - NewWindowRect.left;
2169 WinPos.cy = NewWindowRect.bottom - NewWindowRect.top;
2170 TRACE("WM_WINDOWPOSCHANGED hwnd %p Flags %04x\n",WinPos.hwnd,WinPos.flags);
2171 co_IntSendMessageNoWait(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
2172 }
2173
2174 if ( WinPos.flags & SWP_FRAMECHANGED || WinPos.flags & SWP_STATECHANGED ||
2175 !(WinPos.flags & SWP_NOCLIENTSIZE) || !(WinPos.flags & SWP_NOCLIENTMOVE) )
2176 {
2177 PWND pWnd = ValidateHwndNoErr(WinPos.hwnd);
2178 if (pWnd)
2179 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2180 }
2181
2182 if(bPointerInWindow != IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y))
2183 {
2184 /* Generate mouse move message */
2185 MSG msg;
2186 msg.message = WM_MOUSEMOVE;
2187 msg.wParam = UserGetMouseButtonsState();
2188 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2189 msg.pt = gpsi->ptCursor;
2190 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2191 }
2192
2193 return TRUE;
2194 }
2195
2196 LRESULT FASTCALL
2197 co_WinPosGetNonClientSize(PWND Window, RECT* WindowRect, RECT* ClientRect)
2198 {
2199 LRESULT Result;
2200
2201 ASSERT_REFS_CO(Window);
2202
2203 *ClientRect = *WindowRect;
2204 Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect);
2205
2206 FixClientRect(ClientRect, WindowRect);
2207
2208 return Result;
2209 }
2210
2211 void FASTCALL
2212 co_WinPosSendSizeMove(PWND Wnd)
2213 {
2214 RECTL Rect;
2215 LPARAM lParam;
2216 WPARAM wParam = SIZE_RESTORED;
2217
2218 IntGetClientRect(Wnd, &Rect);
2219 lParam = MAKELONG(Rect.right-Rect.left, Rect.bottom-Rect.top);
2220
2221 Wnd->state &= ~WNDS_SENDSIZEMOVEMSGS;
2222
2223 if (Wnd->style & WS_MAXIMIZE)
2224 {
2225 wParam = SIZE_MAXIMIZED;
2226 }
2227 else if (Wnd->style & WS_MINIMIZE)
2228 {
2229 wParam = SIZE_MINIMIZED;
2230 lParam = 0;
2231 }
2232
2233 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SIZE, wParam, lParam);
2234
2235 if (Wnd->spwndParent == UserGetDesktopWindow()) // Wnd->spwndParent->fnid == FNID_DESKTOP )
2236 lParam = MAKELONG(Wnd->rcClient.left, Wnd->rcClient.top);
2237 else
2238 lParam = MAKELONG(Wnd->rcClient.left-Wnd->spwndParent->rcClient.left, Wnd->rcClient.top-Wnd->spwndParent->rcClient.top);
2239
2240 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_MOVE, 0, lParam);
2241
2242 IntEngWindowChanged(Wnd, WOC_RGN_CLIENT);
2243 }
2244
2245 /*
2246 ShowWindow does not set SWP_FRAMECHANGED!!! Fix wine msg test_SetParent:WmSetParentSeq_2:23 wParam bits!
2247 */
2248 BOOLEAN FASTCALL
2249 co_WinPosShowWindow(PWND Wnd, INT Cmd)
2250 {
2251 BOOLEAN WasVisible;
2252 UINT Swp = 0, EventMsg = 0;
2253 RECTL NewPos = {0, 0, 0, 0};
2254 BOOLEAN ShowFlag;
2255 LONG style;
2256 PWND Parent;
2257 PTHREADINFO pti;
2258 //HRGN VisibleRgn;
2259 BOOL ShowOwned = FALSE;
2260 BOOL FirstTime = FALSE;
2261 ASSERT_REFS_CO(Wnd);
2262 //KeRosDumpStackFrames(NULL, 20);
2263 pti = PsGetCurrentThreadWin32Thread();
2264 WasVisible = (Wnd->style & WS_VISIBLE) != 0;
2265 style = Wnd->style;
2266
2267 TRACE("co_WinPosShowWindow START hwnd %p Cmd %d usicmd %u\n",
2268 Wnd->head.h, Cmd, pti->ppi->usi.wShowWindow);
2269
2270 if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW )
2271 {
2272 if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2273 {
2274 if ((Wnd->style & WS_CAPTION) == WS_CAPTION)
2275 {
2276 if (Wnd->spwndOwner == NULL)
2277 {
2278 if ( Cmd == SW_SHOWNORMAL || Cmd == SW_SHOW)
2279 {
2280 Cmd = SW_SHOWDEFAULT;
2281 }
2282 FirstTime = TRUE;
2283 TRACE("co_WPSW FT 1\n");
2284 }
2285 }
2286 }
2287 }
2288
2289 if ( Cmd == SW_SHOWDEFAULT )
2290 {
2291 if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW )
2292 {
2293 Cmd = pti->ppi->usi.wShowWindow;
2294 FirstTime = TRUE;
2295 TRACE("co_WPSW FT 2\n");
2296 }
2297 }
2298
2299 if (FirstTime)
2300 {
2301 pti->ppi->usi.dwFlags &= ~(STARTF_USEPOSITION|STARTF_USESIZE|STARTF_USESHOWWINDOW);
2302 }
2303
2304 switch (Cmd)
2305 {
2306 case SW_HIDE:
2307 {
2308 if (!WasVisible)
2309 {
2310 //ERR("co_WinPosShowWindow Exit Bad\n");
2311 return FALSE;
2312 }
2313 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2314 if (Wnd != pti->MessageQueue->spwndActive)
2315 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2316 break;
2317 }
2318
2319 case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
2320 case SW_SHOWMINNOACTIVE:
2321 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2322 /* Fall through. */
2323 case SW_SHOWMINIMIZED:
2324 Swp |= SWP_SHOWWINDOW;
2325 /* Fall through. */
2326 case SW_MINIMIZE:
2327 {
2328 Swp |= SWP_NOACTIVATE;
2329 if (!(style & WS_MINIMIZE))
2330 {
2331 IntShowOwnedPopups(Wnd, FALSE );
2332 // Fix wine Win test_SetFocus todo #1 & #2,
2333 if (Cmd == SW_SHOWMINIMIZED)
2334 {
2335 //ERR("co_WinPosShowWindow Set focus 1\n");
2336 if ((style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2337 co_UserSetFocus(Wnd->spwndParent);
2338 else
2339 co_UserSetFocus(0);
2340 }
2341
2342 Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos);
2343
2344 EventMsg = EVENT_SYSTEM_MINIMIZESTART;
2345 }
2346 else
2347 {
2348 if (WasVisible)
2349 {
2350 //ERR("co_WinPosShowWindow Exit Good\n");
2351 return TRUE;
2352 }
2353 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2354 }
2355 break;
2356 }
2357
2358 case SW_SHOWMAXIMIZED:
2359 {
2360 Swp |= SWP_SHOWWINDOW;
2361 if (!(style & WS_MAXIMIZE))
2362 {
2363 ShowOwned = TRUE;
2364
2365 Swp |= co_WinPosMinMaximize(Wnd, SW_MAXIMIZE, &NewPos);
2366
2367 EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2368 }
2369 else
2370 {
2371 if (WasVisible)
2372 {
2373 //ERR("co_WinPosShowWindow Exit Good 1\n");
2374 return TRUE;
2375 }
2376 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2377 }
2378 break;
2379 }
2380
2381 case SW_SHOWNA:
2382 Swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2383 if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOZORDER;
2384 break;
2385 case SW_SHOW:
2386 if (WasVisible) return(TRUE); // Nothing to do!
2387 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2388 /* Don't activate the topmost window. */
2389 if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2390 break;
2391
2392 case SW_SHOWNOACTIVATE:
2393 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2394 /* Fall through. */
2395 case SW_SHOWNORMAL:
2396 case SW_SHOWDEFAULT:
2397 case SW_RESTORE:
2398 if (!WasVisible) Swp |= SWP_SHOWWINDOW;
2399 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2400 {
2401 Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos);
2402 if (style & WS_MINIMIZE) EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2403 }
2404 else
2405 {
2406 if (WasVisible)
2407 {
2408 //ERR("co_WinPosShowWindow Exit Good 3\n");
2409 return TRUE;
2410 }
2411 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2412 }
2413 if ( style & WS_CHILD &&
2414 !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2415 !(Swp & SWP_STATECHANGED))
2416 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2417 break;
2418
2419 default:
2420 //ERR("co_WinPosShowWindow Exit Good 4\n");
2421 return WasVisible;
2422 }
2423
2424 ShowFlag = (Cmd != SW_HIDE);
2425
2426 if ((ShowFlag != WasVisible || Cmd == SW_SHOWNA) && Cmd != SW_SHOWMAXIMIZED && !(Swp & SWP_STATECHANGED))
2427 {
2428 co_IntSendMessageNoWait(Wnd->head.h, WM_SHOWWINDOW, ShowFlag, 0);
2429 #if 0 // Fix wine msg test_SetParent:WmSetParentSeq_1:2
2430 if (!(Wnd->state2 & WNDS2_WIN31COMPAT)) // <------------- XP sets this bit!
2431 co_IntSendMessageNoWait(Wnd->head.h, WM_SETVISIBLE, ShowFlag, 0);
2432 #endif
2433 if (!VerifyWnd(Wnd)) return WasVisible;
2434 }
2435
2436 /* We can't activate a child window */
2437 if ((Wnd->style & WS_CHILD) &&
2438 !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2439 Cmd != SW_SHOWNA)
2440 {
2441 //ERR("SWP Child No active and ZOrder\n");
2442 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2443 }
2444
2445 #if 0 // Explorer issues with common controls? Someone does not know how CS_SAVEBITS works.
2446 // Breaks startup and shutdown active window...
2447 if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
2448 Wnd->pcls->style & CS_SAVEBITS &&
2449 ((Cmd == SW_SHOW) || (Cmd == SW_NORMAL)))
2450 {
2451 ERR("WinPosShowWindow Set active\n");
2452 UserSetActiveWindow(Wnd);
2453 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2454 }
2455 #endif
2456
2457 if (IsChildVisible(Wnd) || Swp & SWP_STATECHANGED)
2458 {
2459 TRACE("Child is Vis %s or State changed %s. ShowFlag %s Swp %04x\n",
2460 (IsChildVisible(Wnd) ? "TRUE" : "FALSE"), (Swp & SWP_STATECHANGED ? "TRUE" : "FALSE"),
2461 (ShowFlag ? "TRUE" : "FALSE"),LOWORD(Swp));
2462 co_WinPosSetWindowPos( Wnd,
2463 0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP,
2464 NewPos.left,
2465 NewPos.top,
2466 NewPos.right, // NewPos.right - NewPos.left, when minimized and restore, the window becomes smaller.
2467 NewPos.bottom,// NewPos.bottom - NewPos.top,
2468 LOWORD(Swp));
2469 }
2470 else
2471 {
2472 TRACE("Parent Vis?\n");
2473 /* if parent is not visible simply toggle WS_VISIBLE and return */
2474 if (ShowFlag) IntSetStyle( Wnd, WS_VISIBLE, 0 );
2475 else IntSetStyle( Wnd, 0, WS_VISIBLE );
2476 }
2477
2478 if ( EventMsg ) IntNotifyWinEvent(EventMsg, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2479
2480 if ( ShowOwned ) IntShowOwnedPopups(Wnd, TRUE );
2481
2482 if ((Cmd == SW_HIDE) || (Cmd == SW_MINIMIZE))
2483 {
2484 if ( Wnd == pti->MessageQueue->spwndActive && pti->MessageQueue == IntGetFocusMessageQueue() )
2485 {
2486 if ( Wnd->spwndParent == UserGetDesktopWindow())
2487 {
2488 if (!ActivateOtherWindowMin(Wnd))
2489 {
2490 co_WinPosActivateOtherWindow(Wnd);
2491 }
2492 }
2493 else
2494 {
2495 co_WinPosActivateOtherWindow(Wnd);
2496 }
2497 }
2498
2499 /* Revert focus to parent */
2500 if (Wnd == pti->MessageQueue->spwndFocus)
2501 {
2502 Parent = Wnd->spwndParent;
2503 if (Wnd->spwndParent == UserGetDesktopWindow()) Parent = 0;
2504 co_UserSetFocus(Parent);
2505 }
2506 // Hide, just return.
2507 if (Cmd == SW_HIDE) return WasVisible;
2508 }
2509
2510 /* FIXME: Check for window destruction. */
2511
2512 if ((Wnd->state & WNDS_SENDSIZEMOVEMSGS) &&
2513 !(Wnd->state2 & WNDS2_INDESTROY))
2514 {
2515 co_WinPosSendSizeMove(Wnd);
2516 }
2517
2518 /* if previous state was minimized Windows sets focus to the window */
2519 if (style & WS_MINIMIZE)
2520 {
2521 co_UserSetFocus(Wnd);
2522 // Fix wine Win test_SetFocus todo #3,
2523 if (!(style & WS_CHILD)) co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_ACTIVATE, WA_ACTIVE, 0);
2524 }
2525 //ERR("co_WinPosShowWindow EXIT\n");
2526 return WasVisible;
2527 }
2528
2529 static PWND
2530 co_WinPosSearchChildren(
2531 IN PWND ScopeWin,
2532 IN POINT *Point,
2533 IN OUT USHORT *HitTest,
2534 IN BOOL Ignore
2535 )
2536 {
2537 HWND *List, *phWnd;
2538 PWND pwndChild = NULL;
2539
2540 /* not visible */
2541 if (!(ScopeWin->style & WS_VISIBLE))
2542 {
2543 return NULL;
2544 }
2545
2546 /* not in window or in window region */
2547 if (!IntPtInWindow(ScopeWin, Point->x, Point->y))
2548 {
2549 return NULL;
2550 }
2551
2552 /* transparent */
2553 if ((ScopeWin->ExStyle & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT))
2554 {
2555 return NULL;
2556 }
2557
2558 if (!Ignore && (ScopeWin->style & WS_DISABLED))
2559 { /* disabled child */
2560 if ((ScopeWin->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return NULL;
2561 /* process the hit error */
2562 *HitTest = HTERROR;
2563 return ScopeWin;
2564 }
2565
2566 /* not minimized and check if point is inside the window */
2567 if (!(ScopeWin->style & WS_MINIMIZE) &&
2568 RECTL_bPointInRect(&ScopeWin->rcClient, Point->x, Point->y) )
2569 {
2570 UserReferenceObject(ScopeWin);
2571
2572 List = IntWinListChildren(ScopeWin);
2573 if (List)
2574 {
2575 for (phWnd = List; *phWnd; ++phWnd)
2576 {
2577 if (!(pwndChild = ValidateHwndNoErr(*phWnd)))
2578 {
2579 continue;
2580 }
2581
2582 pwndChild = co_WinPosSearchChildren(pwndChild, Point, HitTest, Ignore);
2583
2584 if (pwndChild != NULL)
2585 {
2586 /* We found a window. Don't send any more WM_NCHITTEST messages */
2587 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2588 UserDereferenceObject(ScopeWin);
2589 return pwndChild;
2590 }
2591 }
2592 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2593 }
2594 UserDereferenceObject(ScopeWin);
2595 }
2596
2597 if (ScopeWin->head.pti == PsGetCurrentThreadWin32Thread())
2598 {
2599 *HitTest = (USHORT)co_IntSendMessage(ScopeWin->head.h, WM_NCHITTEST, 0, MAKELONG(Point->x, Point->y));
2600
2601 if ((*HitTest) == (USHORT)HTTRANSPARENT)
2602 {
2603 return NULL;
2604 }
2605 }
2606 else
2607 {
2608 if (*HitTest == HTNOWHERE && pwndChild == NULL) *HitTest = HTCLIENT;
2609 }
2610
2611 return ScopeWin;
2612 }
2613
2614 PWND APIENTRY
2615 co_WinPosWindowFromPoint(
2616 IN PWND ScopeWin,
2617 IN POINT *WinPoint,
2618 IN OUT USHORT* HitTest,
2619 IN BOOL Ignore)
2620 {
2621 PWND Window;
2622 POINT Point = *WinPoint;
2623 USER_REFERENCE_ENTRY Ref;
2624
2625 if( ScopeWin == NULL )
2626 {
2627 ScopeWin = UserGetDesktopWindow();
2628 if(ScopeWin == NULL)
2629 return NULL;
2630 }
2631
2632 *HitTest = HTNOWHERE;
2633
2634 ASSERT_REFS_CO(ScopeWin);
2635 UserRefObjectCo(ScopeWin, &Ref);
2636
2637 Window = co_WinPosSearchChildren(ScopeWin, &Point, HitTest, Ignore);
2638
2639 UserDerefObjectCo(ScopeWin);
2640 if (Window)
2641 ASSERT_REFS_CO(Window);
2642 ASSERT_REFS_CO(ScopeWin);
2643
2644 return Window;
2645 }
2646
2647 PWND FASTCALL
2648 IntRealChildWindowFromPoint(PWND Parent, LONG x, LONG y)
2649 {
2650 POINTL Pt;
2651 HWND *List, *phWnd;
2652 PWND pwndHit = NULL;
2653
2654 Pt.x = x;
2655 Pt.y = y;
2656
2657 if (Parent != UserGetDesktopWindow())
2658 {
2659 Pt.x += Parent->rcClient.left;
2660 Pt.y += Parent->rcClient.top;
2661 }
2662
2663 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2664
2665 if ((List = IntWinListChildren(Parent)))
2666 {
2667 for (phWnd = List; *phWnd; phWnd++)
2668 {
2669 PWND Child;
2670 if ((Child = ValidateHwndNoErr(*phWnd)))
2671 {
2672 if ( Child->style & WS_VISIBLE && IntPtInWindow(Child, Pt.x, Pt.y) )
2673 {
2674 if ( Child->pcls->atomClassName != gpsi->atomSysClass[ICLS_BUTTON] ||
2675 (Child->style & BS_TYPEMASK) != BS_GROUPBOX )
2676 {
2677 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2678 return Child;
2679 }
2680 pwndHit = Child;
2681 }
2682 }
2683 }
2684 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2685 }
2686 return pwndHit ? pwndHit : Parent;
2687 }
2688
2689 PWND APIENTRY
2690 IntChildWindowFromPointEx(PWND Parent, LONG x, LONG y, UINT uiFlags)
2691 {
2692 POINTL Pt;
2693 HWND *List, *phWnd;
2694 PWND pwndHit = NULL;
2695
2696 Pt.x = x;
2697 Pt.y = y;
2698
2699 if (Parent != UserGetDesktopWindow())
2700 {
2701 if (Parent->ExStyle & WS_EX_LAYOUTRTL)
2702 Pt.x = Parent->rcClient.right - Pt.x;
2703 else
2704 Pt.x += Parent->rcClient.left;
2705 Pt.y += Parent->rcClient.top;
2706 }
2707
2708 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2709
2710 if ((List = IntWinListChildren(Parent)))
2711 {
2712 for (phWnd = List; *phWnd; phWnd++)
2713 {
2714 PWND Child;
2715 if ((Child = ValidateHwndNoErr(*phWnd)))
2716 {
2717 if (uiFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
2718 {
2719 if (!(Child->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE)) continue;
2720 if ((Child->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED)) continue;
2721 }
2722
2723 if (uiFlags & CWP_SKIPTRANSPARENT)
2724 {
2725 if (Child->ExStyle & WS_EX_TRANSPARENT) continue;
2726 }
2727
2728 if (IntPtInWindow(Child, Pt.x, Pt.y))
2729 {
2730 pwndHit = Child;
2731 break;
2732 }
2733 }
2734 }
2735 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2736 }
2737 return pwndHit ? pwndHit : Parent;
2738 }
2739
2740 HDWP
2741 FASTCALL
2742 IntDeferWindowPos( HDWP hdwp,
2743 HWND hwnd,
2744 HWND hwndAfter,
2745 INT x,
2746 INT y,
2747 INT cx,
2748 INT cy,
2749 UINT flags )
2750 {
2751 PSMWP pDWP;
2752 int i;
2753 HDWP retvalue = hdwp;
2754
2755 TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2756 hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
2757
2758 if (flags & ~(SWP_NOSIZE | SWP_NOMOVE |
2759 SWP_NOZORDER | SWP_NOREDRAW |
2760 SWP_NOACTIVATE | SWP_NOCOPYBITS |
2761 SWP_NOOWNERZORDER|SWP_SHOWWINDOW |
2762 SWP_HIDEWINDOW | SWP_FRAMECHANGED))
2763 {
2764 EngSetLastError(ERROR_INVALID_PARAMETER);
2765 return NULL;
2766 }
2767
2768 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
2769 {
2770 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
2771 return NULL;
2772 }
2773
2774 for (i = 0; i < pDWP->ccvr; i++)
2775 {
2776 if (pDWP->acvr[i].pos.hwnd == hwnd)
2777 {
2778 /* Merge with the other changes */
2779 if (!(flags & SWP_NOZORDER))
2780 {
2781 pDWP->acvr[i].pos.hwndInsertAfter = hwndAfter;
2782 }
2783 if (!(flags & SWP_NOMOVE))
2784 {
2785 pDWP->acvr[i].pos.x = x;
2786 pDWP->acvr[i].pos.y = y;
2787 }
2788 if (!(flags & SWP_NOSIZE))
2789 {
2790 pDWP->acvr[i].pos.cx = cx;
2791 pDWP->acvr[i].pos.cy = cy;
2792 }
2793 pDWP->acvr[i].pos.flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
2794 SWP_NOZORDER | SWP_NOREDRAW |
2795 SWP_NOACTIVATE | SWP_NOCOPYBITS|
2796 SWP_NOOWNERZORDER);
2797 pDWP->acvr[i].pos.flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
2798 SWP_FRAMECHANGED);
2799 goto END;
2800 }
2801 }
2802 if (pDWP->ccvr >= pDWP->ccvrAlloc)
2803 {
2804 PCVR newpos = ExAllocatePoolWithTag(PagedPool, pDWP->ccvrAlloc * 2 * sizeof(CVR), USERTAG_SWP);
2805 if (!newpos)
2806 {
2807 retvalue = NULL;
2808 goto END;
2809 }
2810 RtlZeroMemory(newpos, pDWP->ccvrAlloc * 2 * sizeof(CVR));
2811 RtlCopyMemory(newpos, pDWP->acvr, pDWP->ccvrAlloc * sizeof(CVR));
2812 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
2813 pDWP->ccvrAlloc *= 2;
2814 pDWP->acvr = newpos;
2815 }
2816 pDWP->acvr[pDWP->ccvr].pos.hwnd = hwnd;
2817 pDWP->acvr[pDWP->ccvr].pos.hwndInsertAfter = hwndAfter;
2818 pDWP->acvr[pDWP->ccvr].pos.x = x;
2819 pDWP->acvr[pDWP->ccvr].pos.y = y;
2820 pDWP->acvr[pDWP->ccvr].pos.cx = cx;
2821 pDWP->acvr[pDWP->ccvr].pos.cy = cy;
2822 pDWP->acvr[pDWP->ccvr].pos.flags = flags;
2823 pDWP->acvr[pDWP->ccvr].hrgnClip = NULL;
2824 pDWP->acvr[pDWP->ccvr].hrgnInterMonitor = NULL;
2825 pDWP->ccvr++;
2826 END:
2827 return retvalue;
2828 }
2829
2830 BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp, BOOL sAsync )
2831 {
2832 PSMWP pDWP;
2833 PCVR winpos;
2834 BOOL res = TRUE;
2835 int i;
2836
2837 TRACE("%p\n", hdwp);
2838
2839 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
2840 {
2841 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
2842 return FALSE;
2843 }
2844
2845 for (i = 0, winpos = pDWP->acvr; res && i < pDWP->ccvr; i++, winpos++)
2846 {
2847 PWND pwnd;
2848 USER_REFERENCE_ENTRY Ref;
2849
2850 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2851 winpos->pos.hwnd, winpos->pos.hwndInsertAfter, winpos->pos.x, winpos->pos.y,
2852 winpos->pos.cx, winpos->pos.cy, winpos->pos.flags);
2853
2854 pwnd = ValidateHwndNoErr(winpos->pos.hwnd);
2855 if (!pwnd)
2856 continue;
2857
2858 UserRefObjectCo(pwnd, &Ref);
2859
2860 if ( sAsync )
2861 {
2862 LRESULT lRes;
2863 PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
2864 if ( ppos )
2865 {
2866 *ppos = winpos->pos;
2867 /* Yes it's a pointer inside Win32k! */
2868 lRes = co_IntSendMessageNoWait( winpos->pos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
2869 /* We handle this the same way as Event Hooks and Hooks. */
2870 if ( !lRes )
2871 {
2872 ExFreePoolWithTag(ppos, USERTAG_SWP);
2873 }
2874 }
2875 }
2876 else
2877 res = co_WinPosSetWindowPos( pwnd,
2878 winpos->pos.hwndInsertAfter,
2879 winpos->pos.x,
2880 winpos->pos.y,
2881 winpos->pos.cx,
2882 winpos->pos.cy,
2883 winpos->pos.flags);
2884
2885 // Hack to pass tests.... Must have some work to do so clear the error.
2886 if (res && (winpos->pos.flags & (SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER)) == SWP_NOZORDER )
2887 EngSetLastError(ERROR_SUCCESS);
2888
2889 UserDerefObjectCo(pwnd);
2890 }
2891 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
2892 UserDereferenceObject(pDWP);
2893 UserDeleteObject(hdwp, TYPE_SETWINDOWPOS);
2894 return res;
2895 }
2896
2897 /*
2898 * @implemented
2899 */
2900 HWND APIENTRY
2901 NtUserChildWindowFromPointEx(HWND hwndParent,
2902 LONG x,
2903 LONG y,
2904 UINT uiFlags)
2905 {
2906 PWND pwndParent;
2907 TRACE("Enter NtUserChildWindowFromPointEx\n");
2908 UserEnterExclusive();
2909 if ((pwndParent = UserGetWindowObject(hwndParent)))
2910 {
2911 pwndParent = IntChildWindowFromPointEx(pwndParent, x, y, uiFlags);
2912 }
2913 UserLeave();
2914 TRACE("Leave NtUserChildWindowFromPointEx\n");
2915 return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
2916 }
2917
2918 /*
2919 * @implemented
2920 */
2921 BOOL APIENTRY
2922 NtUserEndDeferWindowPosEx(HDWP WinPosInfo,
2923 DWORD Unknown1)
2924 {
2925 BOOL Ret;
2926 TRACE("Enter NtUserEndDeferWindowPosEx\n");
2927 UserEnterExclusive();
2928 Ret = IntEndDeferWindowPosEx(WinPosInfo, (BOOL)Unknown1);
2929 TRACE("Leave NtUserEndDeferWindowPosEx, ret=%i\n", Ret);
2930 UserLeave();
2931 return Ret;
2932 }
2933
2934 /*
2935 * @implemented
2936 */
2937 HDWP APIENTRY
2938 NtUserDeferWindowPos(HDWP WinPosInfo,
2939 HWND Wnd,
2940 HWND WndInsertAfter,
2941 int x,
2942 int y,
2943 int cx,
2944 int cy,
2945 UINT Flags)
2946 {
2947 PWND pWnd, pWndIA;
2948 HDWP Ret = NULL;
2949 UINT Tmp = ~(SWP_ASYNCWINDOWPOS|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_NOREPOSITION|
2950 SWP_NOCOPYBITS|SWP_HIDEWINDOW|SWP_SHOWWINDOW|SWP_FRAMECHANGED|
2951 SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE);
2952
2953 TRACE("Enter NtUserDeferWindowPos\n");
2954 UserEnterExclusive();
2955
2956 if ( Flags & Tmp )
2957 {
2958 EngSetLastError(ERROR_INVALID_FLAGS);
2959 goto Exit;
2960 }
2961
2962 pWnd = UserGetWindowObject(Wnd);
2963 if ( !pWnd || // FIXME:
2964 pWnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2965 pWnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2966 {
2967 goto Exit;
2968 }
2969
2970 if ( WndInsertAfter &&
2971 WndInsertAfter != HWND_BOTTOM &&
2972 WndInsertAfter != HWND_TOPMOST &&
2973 WndInsertAfter != HWND_NOTOPMOST )
2974 {
2975 pWndIA = UserGetWindowObject(WndInsertAfter);
2976 if ( !pWndIA ||
2977 pWndIA == UserGetDesktopWindow() ||
2978 pWndIA == UserGetMessageWindow() )
2979 {
2980 goto Exit;
2981 }
2982 }
2983
2984 Ret = IntDeferWindowPos(WinPosInfo, Wnd, WndInsertAfter, x, y, cx, cy, Flags);
2985
2986 Exit:
2987 TRACE("Leave NtUserDeferWindowPos, ret=%p\n", Ret);
2988 UserLeave();
2989 return Ret;
2990 }
2991
2992 /*
2993 * @implemented
2994 */
2995 DWORD APIENTRY
2996 NtUserGetInternalWindowPos( HWND hWnd,
2997 LPRECT rectWnd,
2998 LPPOINT ptIcon)
2999 {
3000 PWND Window;
3001 DWORD Ret = 0;
3002 BOOL Hit = FALSE;
3003 WINDOWPLACEMENT wndpl;
3004
3005 UserEnterShared();
3006
3007 if (!(Window = UserGetWindowObject(hWnd)))
3008 {
3009 Hit = FALSE;
3010 goto Exit;
3011 }
3012
3013 _SEH2_TRY
3014 {
3015 if(rectWnd)
3016 {
3017 ProbeForWrite(rectWnd,
3018 sizeof(RECT),
3019 1);
3020 }
3021 if(ptIcon)
3022 {
3023 ProbeForWrite(ptIcon,
3024 sizeof(POINT),
3025 1);
3026 }
3027
3028 }
3029 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3030 {
3031 SetLastNtError(_SEH2_GetExceptionCode());
3032 Hit = TRUE;
3033 }
3034 _SEH2_END;
3035
3036 wndpl.length = sizeof(WINDOWPLACEMENT);
3037
3038 if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
3039 {
3040 _SEH2_TRY
3041 {
3042 if (rectWnd)
3043 {
3044 RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));
3045 }
3046 if (ptIcon)
3047 {
3048 RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT));
3049 }
3050
3051 }
3052 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3053 {
3054 SetLastNtError(_SEH2_GetExceptionCode());
3055 Hit = TRUE;
3056 }
3057 _SEH2_END;
3058
3059 if (!Hit) Ret = wndpl.showCmd;
3060 }
3061 Exit:
3062 UserLeave();
3063 return Ret;
3064 }
3065
3066 /*
3067 * @implemented
3068 */
3069 BOOL APIENTRY
3070 NtUserGetWindowPlacement(HWND hWnd,
3071 WINDOWPLACEMENT *lpwndpl)
3072 {
3073 PWND Wnd;
3074 WINDOWPLACEMENT Safepl;
3075 NTSTATUS Status;
3076 DECLARE_RETURN(BOOL);
3077
3078 TRACE("Enter NtUserGetWindowPlacement\n");
3079 UserEnterShared();
3080
3081 if (!(Wnd = UserGetWindowObject(hWnd)))
3082 {
3083 RETURN( FALSE);
3084 }
3085
3086 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3087 if (!NT_SUCCESS(Status))
3088 {
3089 SetLastNtError(Status);
3090 RETURN( FALSE);
3091 }
3092
3093 Safepl.length = sizeof(WINDOWPLACEMENT);
3094
3095 IntGetWindowPlacement(Wnd, &Safepl);
3096
3097 Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
3098 if (!NT_SUCCESS(Status))
3099 {
3100 SetLastNtError(Status);
3101 RETURN( FALSE);
3102 }
3103
3104 RETURN( TRUE);
3105
3106 CLEANUP:
3107 TRACE("Leave NtUserGetWindowPlacement, ret=%i\n",_ret_);
3108 UserLeave();
3109 END_CLEANUP;
3110 }
3111
3112 DWORD
3113 APIENTRY
3114 NtUserMinMaximize(
3115 HWND hWnd,
3116 UINT cmd, // Wine SW_ commands
3117 BOOL Hide)
3118 {
3119 PWND pWnd;
3120
3121 TRACE("Enter NtUserMinMaximize\n");
3122 UserEnterExclusive();
3123
3124 pWnd = UserGetWindowObject(hWnd);
3125 if ( !pWnd || // FIXME:
3126 pWnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3127 pWnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3128 {
3129 goto Exit;
3130 }
3131
3132 if ( cmd > SW_MAX || pWnd->state2 & WNDS2_INDESTROY)
3133 {
3134 EngSetLastError(ERROR_INVALID_PARAMETER);
3135 goto Exit;
3136 }
3137
3138 cmd |= Hide ? SW_HIDE : 0;
3139
3140 co_WinPosShowWindow(pWnd, cmd);
3141
3142 Exit:
3143 TRACE("Leave NtUserMinMaximize\n");
3144 UserLeave();
3145 return 0; // Always NULL?
3146 }
3147
3148 /*
3149 * @implemented
3150 */
3151 BOOL APIENTRY
3152 NtUserMoveWindow(
3153 HWND hWnd,
3154 int X,
3155 int Y,
3156 int nWidth,
3157 int nHeight,
3158 BOOL bRepaint)
3159 {
3160 return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight,
3161 (bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE :
3162 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW));
3163 }
3164
3165 /*
3166 * @implemented
3167 */
3168 HWND APIENTRY
3169 NtUserRealChildWindowFromPoint(HWND Parent,
3170 LONG x,
3171 LONG y)
3172 {
3173 PWND pwndParent;
3174 TRACE("Enter NtUserRealChildWindowFromPoint\n");
3175 UserEnterShared();
3176 if ((pwndParent = UserGetWindowObject(Parent)))
3177 {
3178 pwndParent = IntRealChildWindowFromPoint(pwndParent, x, y);
3179 }
3180 UserLeave();
3181 TRACE("Leave NtUserRealChildWindowFromPoint\n");
3182 return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
3183 }
3184
3185 /*
3186 * @implemented
3187 */
3188 BOOL APIENTRY
3189 NtUserSetWindowPos(
3190 HWND hWnd,
3191 HWND hWndInsertAfter,
3192 int X,
3193 int Y,
3194 int cx,
3195 int cy,
3196 UINT uFlags)
3197 {
3198 DECLARE_RETURN(BOOL);
3199 PWND Window, pWndIA;
3200 BOOL ret;
3201 USER_REFERENCE_ENTRY Ref;
3202
3203 TRACE("Enter NtUserSetWindowPos\n");
3204 UserEnterExclusive();
3205
3206 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
3207 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3208 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3209 {
3210 ERR("NtUserSetWindowPos bad window handle!\n");
3211 RETURN(FALSE);
3212 }
3213
3214 if ( hWndInsertAfter &&
3215 hWndInsertAfter != HWND_BOTTOM &&
3216 hWndInsertAfter != HWND_TOPMOST &&
3217 hWndInsertAfter != HWND_NOTOPMOST )
3218 {
3219 if (!(pWndIA = UserGetWindowObject(hWndInsertAfter)) ||
3220 pWndIA == UserGetDesktopWindow() ||
3221 pWndIA == UserGetMessageWindow() )
3222 {
3223 ERR("NtUserSetWindowPos bad insert window handle!\n");
3224 RETURN(FALSE);
3225 }
3226 }
3227
3228 /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
3229 if (!(uFlags & SWP_NOMOVE))
3230 {
3231 if (X < -32768) X = -32768;
3232 else if (X > 32767) X = 32767;
3233 if (Y < -32768) Y = -32768;
3234 else if (Y > 32767) Y = 32767;
3235 }
3236 if (!(uFlags & SWP_NOSIZE))
3237 {
3238 if (cx < 0) cx = 0;
3239 else if (cx > 32767) cx = 32767;
3240 if (cy < 0) cy = 0;
3241 else if (cy > 32767) cy = 32767;
3242 }
3243
3244 UserRefObjectCo(Window, &Ref);
3245 ret = co_WinPosSetWindowPos(Window, hWndInsertAfter, X, Y, cx, cy, uFlags);
3246 UserDerefObjectCo(Window);
3247
3248 RETURN(ret);
3249
3250 CLEANUP:
3251 TRACE("Leave NtUserSetWindowPos, ret=%i\n",_ret_);
3252 UserLeave();
3253 END_CLEANUP;
3254 }
3255
3256 /*
3257 * @implemented
3258 */
3259 INT APIENTRY
3260 NtUserSetWindowRgn(
3261 HWND hWnd,
3262 HRGN hRgn,
3263 BOOL bRedraw)
3264 {
3265 HRGN hrgnCopy = NULL;
3266 PWND Window;
3267 INT flags = (SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE);
3268 BOOLEAN Ret = FALSE;
3269 DECLARE_RETURN(INT);
3270
3271 TRACE("Enter NtUserSetWindowRgn\n");
3272 UserEnterExclusive();
3273
3274 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
3275 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3276 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3277 {
3278 RETURN( 0);
3279 }
3280
3281 if (hRgn) // The region will be deleted in user32.
3282 {
3283 if (GreIsHandleValid(hRgn))
3284 {
3285 hrgnCopy = NtGdiCreateRectRgn(0, 0, 0, 0);
3286 /* The coordinates of a window's window region are relative to the
3287 upper-left corner of the window, not the client area of the window. */
3288 NtGdiCombineRgn( hrgnCopy, hRgn, 0, RGN_COPY);
3289 }
3290 else
3291 RETURN( 0);
3292 }
3293
3294 if (Window->hrgnClip)
3295 {
3296 /* Delete no longer needed region handle */
3297 IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED);
3298 GreDeleteObject(Window->hrgnClip);
3299 }
3300
3301 if (hrgnCopy)
3302 {
3303 /* Set public ownership */
3304 IntGdiSetRegionOwner(hrgnCopy, GDI_OBJ_HMGR_PUBLIC);
3305 }
3306 Window->hrgnClip = hrgnCopy;
3307
3308 Ret = co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, bRedraw ? flags : (flags|SWP_NOREDRAW) );
3309
3310 RETURN( (INT)Ret);
3311
3312 CLEANUP:
3313 TRACE("Leave NtUserSetWindowRgn, ret=%i\n",_ret_);
3314 UserLeave();
3315 END_CLEANUP;
3316 }
3317
3318 /*
3319 * @implemented
3320 */
3321 DWORD APIENTRY
3322 NtUserSetInternalWindowPos(
3323 HWND hwnd,
3324 UINT showCmd,
3325 LPRECT lprect,
3326 LPPOINT lppt)
3327 {
3328 WINDOWPLACEMENT wndpl;
3329 UINT flags;
3330 PWND Wnd;
3331 RECT rect;
3332 POINT pt = {0};
3333 DECLARE_RETURN(BOOL);
3334 USER_REFERENCE_ENTRY Ref;
3335
3336 TRACE("Enter NtUserSetWindowPlacement\n");
3337 UserEnterExclusive();
3338
3339 if (!(Wnd = UserGetWindowObject(hwnd)) || // FIXME:
3340 Wnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3341 Wnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3342 {
3343 RETURN( FALSE);
3344 }
3345
3346 _SEH2_TRY
3347 {
3348 if (lppt)
3349 {
3350 ProbeForRead(lppt, sizeof(POINT), 1);
3351 RtlCopyMemory(&pt, lppt, sizeof(POINT));
3352 }
3353 if (lprect)
3354 {
3355 ProbeForRead(lprect, sizeof(RECT), 1);
3356 RtlCopyMemory(&rect, lprect, sizeof(RECT));
3357 }
3358 }
3359 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3360 {
3361 SetLastNtError(_SEH2_GetExceptionCode());
3362 _SEH2_YIELD(RETURN( FALSE));
3363 }
3364 _SEH2_END
3365
3366 wndpl.length = sizeof(wndpl);
3367 wndpl.showCmd = showCmd;
3368 wndpl.flags = flags = 0;
3369
3370 if ( lppt )
3371 {
3372 flags |= PLACE_MIN;
3373 wndpl.flags |= WPF_SETMINPOSITION;
3374 wndpl.ptMinPosition = pt;
3375 }
3376 if ( lprect )
3377 {
3378 flags |= PLACE_RECT;
3379 wndpl.rcNormalPosition = rect;
3380 }
3381
3382 UserRefObjectCo(Wnd, &Ref);
3383 IntSetWindowPlacement(Wnd, &wndpl, flags);
3384 UserDerefObjectCo(Wnd);
3385 RETURN(TRUE);
3386
3387 CLEANUP:
3388 TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
3389 UserLeave();
3390 END_CLEANUP;
3391 }
3392
3393 /*
3394 * @implemented
3395 */
3396 BOOL APIENTRY
3397 NtUserSetWindowPlacement(HWND hWnd,
3398 WINDOWPLACEMENT *lpwndpl)
3399 {
3400 PWND Wnd;
3401 WINDOWPLACEMENT Safepl;
3402 UINT Flags;
3403 DECLARE_RETURN(BOOL);
3404 USER_REFERENCE_ENTRY Ref;
3405
3406 TRACE("Enter NtUserSetWindowPlacement\n");
3407 UserEnterExclusive();
3408
3409 if (!(Wnd = UserGetWindowObject(hWnd)) || // FIXME:
3410 Wnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3411 Wnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3412 {
3413 RETURN( FALSE);
3414 }
3415
3416 _SEH2_TRY
3417 {
3418 ProbeForRead(lpwndpl, sizeof(WINDOWPLACEMENT), 1);
3419 RtlCopyMemory(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3420 }
3421 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3422 {
3423 SetLastNtError(_SEH2_GetExceptionCode());
3424 _SEH2_YIELD(RETURN( FALSE));
3425 }
3426 _SEH2_END
3427
3428 if(Safepl.length != sizeof(WINDOWPLACEMENT))
3429 {
3430 RETURN( FALSE);
3431 }
3432
3433 Flags = PLACE_MAX | PLACE_RECT;
3434 if (Safepl.flags & WPF_SETMINPOSITION) Flags |= PLACE_MIN;
3435 UserRefObjectCo(Wnd, &Ref);
3436 IntSetWindowPlacement(Wnd, &Safepl, Flags);
3437 UserDerefObjectCo(Wnd);
3438 RETURN(TRUE);
3439
3440 CLEANUP:
3441 TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
3442 UserLeave();
3443 END_CLEANUP;
3444 }
3445
3446 /*
3447 * @implemented
3448 */
3449 BOOL APIENTRY
3450 NtUserShowWindowAsync(HWND hWnd, LONG nCmdShow)
3451 {
3452 PWND Window;
3453 BOOL ret;
3454 DECLARE_RETURN(BOOL);
3455 USER_REFERENCE_ENTRY Ref;
3456
3457 TRACE("Enter NtUserShowWindowAsync\n");
3458 UserEnterExclusive();
3459
3460 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
3461 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3462 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3463 {
3464 RETURN(FALSE);
3465 }
3466
3467 if ( nCmdShow > SW_MAX )
3468 {
3469 EngSetLastError(ERROR_INVALID_PARAMETER);
3470 RETURN(FALSE);
3471 }
3472
3473 UserRefObjectCo(Window, &Ref);
3474 ret = co_IntSendMessageNoWait( hWnd, WM_ASYNC_SHOWWINDOW, nCmdShow, 0 );
3475 UserDerefObjectCo(Window);
3476 if (-1 == (int) ret || !ret) ret = FALSE;
3477
3478 RETURN(ret);
3479
3480 CLEANUP:
3481 TRACE("Leave NtUserShowWindowAsync, ret=%i\n",_ret_);
3482 UserLeave();
3483 END_CLEANUP;
3484 }
3485
3486 /*
3487 * @implemented
3488 */
3489 BOOL APIENTRY
3490 NtUserShowWindow(HWND hWnd, LONG nCmdShow)
3491 {
3492 PWND Window;
3493 BOOL ret;
3494 DECLARE_RETURN(BOOL);
3495 USER_REFERENCE_ENTRY Ref;
3496
3497 TRACE("Enter NtUserShowWindow hWnd %p SW_ %d\n",hWnd, nCmdShow);
3498 UserEnterExclusive();
3499
3500 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
3501 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3502 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3503 {
3504 RETURN(FALSE);
3505 }
3506
3507 if ( nCmdShow > SW_MAX || Window->state2 & WNDS2_INDESTROY)
3508 {
3509 EngSetLastError(ERROR_INVALID_PARAMETER);
3510 RETURN(FALSE);
3511 }
3512
3513 UserRefObjectCo(Window, &Ref);
3514 ret = co_WinPosShowWindow(Window, nCmdShow);
3515 UserDerefObjectCo(Window);
3516
3517 RETURN(ret);
3518
3519 CLEANUP:
3520 TRACE("Leave NtUserShowWindow, ret=%i\n",_ret_);
3521 UserLeave();
3522 END_CLEANUP;
3523 }
3524
3525
3526 /*
3527 * @implemented
3528 */
3529 HWND APIENTRY
3530 NtUserWindowFromPoint(LONG X, LONG Y)
3531 {
3532 POINT pt;
3533 HWND Ret;
3534 PWND DesktopWindow = NULL, Window = NULL;
3535 USHORT hittest;
3536 DECLARE_RETURN(HWND);
3537 USER_REFERENCE_ENTRY Ref;
3538
3539 TRACE("Enter NtUserWindowFromPoint\n");
3540 UserEnterExclusive();
3541
3542 if ((DesktopWindow = UserGetWindowObject(IntGetDesktopWindow())))
3543 {
3544 //PTHREADINFO pti;
3545
3546 pt.x = X;
3547 pt.y = Y;
3548
3549 // Hmm... Threads live on desktops thus we have a reference on the desktop and indirectly the desktop window.
3550 // It is possible this referencing is useless, though it should not hurt...
3551 UserRefObjectCo(DesktopWindow, &Ref);
3552
3553 //pti = PsGetCurrentThreadWin32Thread();
3554 Window = co_WinPosWindowFromPoint(DesktopWindow, &pt, &hittest, FALSE);
3555
3556 if (Window)
3557 {
3558 Ret = UserHMGetHandle(Window);
3559
3560 RETURN( Ret);
3561 }
3562 }
3563
3564 RETURN( NULL);
3565
3566 CLEANUP:
3567 if (DesktopWindow) UserDerefObjectCo(DesktopWindow);
3568
3569 TRACE("Leave NtUserWindowFromPoint, ret=%p\n", _ret_);
3570 UserLeave();
3571 END_CLEANUP;
3572 }
3573
3574 /* EOF */