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