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