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