5ad490abfb69ed61a959b7be807781cc67535350
[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 CORE-6129 and CORE-6554.
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 ERR("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
1725 ASSERT_REFS_CO(Window);
1726
1727 /* FIXME: Get current active window from active queue. Why? since r2915. */
1728
1729 bPointerInWindow = IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y);
1730
1731 WinPos.hwnd = Window->head.h;
1732 WinPos.hwndInsertAfter = WndInsertAfter;
1733 WinPos.x = x;
1734 WinPos.y = y;
1735 WinPos.cx = cx;
1736 WinPos.cy = cy;
1737 WinPos.flags = flags;
1738
1739 if ( flags & SWP_ASYNCWINDOWPOS )
1740 {
1741 LRESULT lRes;
1742 PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
1743 if ( ppos )
1744 {
1745 WinPos.flags &= ~SWP_ASYNCWINDOWPOS; // Clear flag.
1746 *ppos = WinPos;
1747 /* Yes it's a pointer inside Win32k! */
1748 lRes = co_IntSendMessageNoWait( WinPos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
1749 /* We handle this the same way as Event Hooks and Hooks. */
1750 if ( !lRes )
1751 {
1752 ExFreePoolWithTag(ppos, USERTAG_SWP);
1753 return FALSE;
1754 }
1755 return TRUE;
1756 }
1757 return FALSE;
1758 }
1759
1760 co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
1761
1762 /* Does the window still exist? */
1763 if (!IntIsWindow(WinPos.hwnd))
1764 {
1765 TRACE("WinPosSetWindowPos: Invalid handle 0x%p!\n",WinPos.hwnd);
1766 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
1767 return FALSE;
1768 }
1769
1770 /* Fix up the flags. */
1771 if (!WinPosFixupFlags(&WinPos, Window))
1772 {
1773 // See Note.
1774 return TRUE;
1775 }
1776
1777 Ancestor = UserGetAncestor(Window, GA_PARENT);
1778 if ( (WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER &&
1779 Ancestor && Ancestor->head.h == IntGetDesktopWindow() )
1780 {
1781 WinPos.hwndInsertAfter = WinPosDoOwnedPopups(Window, WinPos.hwndInsertAfter);
1782 }
1783
1784 if (!(WinPos.flags & SWP_NOREDRAW))
1785 {
1786 /* Compute the visible region before the window position is changed */
1787 if (!(WinPos.flags & SWP_SHOWWINDOW) &&
1788 (WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
1789 SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
1790 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
1791 {
1792 VisBefore = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1793 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1794 VisRgn = NULL;
1795
1796 if ( VisBefore != NULL &&
1797 (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisBefore, NULL)) &&
1798 REGION_Complexity(VisRgn) == NULLREGION )
1799 {
1800 RGNOBJAPI_Unlock(VisRgn);
1801 GreDeleteObject(VisBefore);
1802 VisBefore = NULL;
1803 }
1804 else if(VisRgn)
1805 {
1806 RGNOBJAPI_Unlock(VisRgn);
1807 NtGdiOffsetRgn(VisBefore, -Window->rcWindow.left, -Window->rcWindow.top);
1808 }
1809 }
1810 }
1811
1812 WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect, valid_rects);
1813
1814 // ERR("co_WinPosDoNCCALCSize returned 0x%x\n valid dest: %d %d %d %d\n valid src : %d %d %d %d\n", WvrFlags,
1815 // valid_rects[0].left,valid_rects[0].top,valid_rects[0].right,valid_rects[0].bottom,
1816 // valid_rects[1].left,valid_rects[1].top,valid_rects[1].right,valid_rects[1].bottom);
1817
1818 /* Validate link windows. (also take into account shell window in hwndShellWindow) */
1819 if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow())
1820 {
1821 IntLinkHwnd(Window, WinPos.hwndInsertAfter);
1822 }
1823
1824 OldWindowRect = Window->rcWindow;
1825 OldClientRect = Window->rcClient;
1826 //ERR("SetWindowPos OldWindowRect: %d %d %d %d\n", OldWindowRect.left,OldWindowRect.top,OldWindowRect.right,OldWindowRect.bottom);
1827 //ERR("SetWindowPos OldClientRect: %d %d %d %d\n", OldClientRect.left,OldClientRect.top,OldClientRect.right,OldClientRect.bottom);
1828
1829 if (NewClientRect.left != OldClientRect.left ||
1830 NewClientRect.top != OldClientRect.top)
1831 {
1832 WinPosInternalMoveWindow(Window,
1833 NewClientRect.left - OldClientRect.left,
1834 NewClientRect.top - OldClientRect.top);
1835 }
1836
1837 Window->rcWindow = NewWindowRect;
1838 Window->rcClient = NewClientRect;
1839
1840 //ERR("SetWindowPos NewWindowRect: %d %d %d %d\n", NewWindowRect.left,NewWindowRect.top,NewWindowRect.right,NewWindowRect.bottom);
1841 //ERR("SetWindowPos NewClientRect: %d %d %d %d\n", NewClientRect.left,NewClientRect.top,NewClientRect.right,NewClientRect.bottom);
1842
1843 /* erase parent when hiding or resizing child */
1844 if (WinPos.flags & SWP_HIDEWINDOW)
1845 {
1846 /* Clear the update region */
1847 co_UserRedrawWindow( Window,
1848 NULL,
1849 0,
1850 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
1851
1852 if (Window->spwndParent == UserGetDesktopWindow())
1853 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM)Window->head.h, 0);
1854
1855 Window->style &= ~WS_VISIBLE; //IntSetStyle( Window, 0, WS_VISIBLE );
1856 Window->head.pti->cVisWindows--;
1857 IntNotifyWinEvent(EVENT_OBJECT_HIDE, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1858 }
1859 else if (WinPos.flags & SWP_SHOWWINDOW)
1860 {
1861 if (Window->spwndParent == UserGetDesktopWindow())
1862 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)Window->head.h, 0);
1863
1864 Window->style |= WS_VISIBLE; //IntSetStyle( Window, WS_VISIBLE, 0 );
1865 Window->head.pti->cVisWindows++;
1866 IntNotifyWinEvent(EVENT_OBJECT_SHOW, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1867 }
1868
1869 if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != HRGN_WINDOW)
1870 {
1871 NtGdiOffsetRgn(Window->hrgnUpdate,
1872 NewWindowRect.left - OldWindowRect.left,
1873 NewWindowRect.top - OldWindowRect.top);
1874 }
1875
1876 DceResetActiveDCEs(Window); // For WS_VISIBLE changes.
1877
1878 if (!(WinPos.flags & SWP_NOREDRAW))
1879 {
1880 /* Determine the new visible region */
1881 VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1882 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1883 VisRgn = NULL;
1884
1885 if ( VisAfter != NULL &&
1886 (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisAfter, NULL)) &&
1887 REGION_Complexity(VisRgn) == NULLREGION )
1888 {
1889 RGNOBJAPI_Unlock(VisRgn);
1890 GreDeleteObject(VisAfter);
1891 VisAfter = NULL;
1892 }
1893 else if(VisRgn)
1894 {
1895 RGNOBJAPI_Unlock(VisRgn);
1896 NtGdiOffsetRgn(VisAfter, -Window->rcWindow.left, -Window->rcWindow.top);
1897 }
1898
1899 /*
1900 * Determine which pixels can be copied from the old window position
1901 * to the new. Those pixels must be visible in both the old and new
1902 * position. Also, check the class style to see if the windows of this
1903 * class need to be completely repainted on (horizontal/vertical) size
1904 * change.
1905 */
1906 if ( VisBefore != NULL &&
1907 VisAfter != NULL &&
1908 !(WinPos.flags & SWP_NOCOPYBITS) &&
1909 ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) &&
1910 !(Window->ExStyle & WS_EX_TRANSPARENT) )
1911 {
1912 CopyRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1913 RgnType = NtGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
1914
1915 /*
1916 * If this is (also) a window resize, the whole nonclient area
1917 * needs to be repainted. So we limit the copy to the client area,
1918 * 'cause there is no use in copying it (would possibly cause
1919 * "flashing" too). However, if the copy region is already empty,
1920 * we don't have to crop (can't take anything away from an empty
1921 * region...)
1922 */
1923 if (!(WinPos.flags & SWP_NOSIZE) &&
1924 RgnType != ERROR &&
1925 RgnType != NULLREGION )
1926 {
1927 PROSRGNDATA pCopyRgn;
1928 RECTL ORect = OldClientRect;
1929 RECTL NRect = NewClientRect;
1930 RECTL_vOffsetRect(&ORect, - OldWindowRect.left, - OldWindowRect.top);
1931 RECTL_vOffsetRect(&NRect, - NewWindowRect.left, - NewWindowRect.top);
1932 RECTL_bIntersectRect(&CopyRect, &ORect, &NRect);
1933 pCopyRgn = RGNOBJAPI_Lock(CopyRgn, NULL);
1934 REGION_CropAndOffsetRegion(pCopyRgn, pCopyRgn, &CopyRect, NULL);
1935 RGNOBJAPI_Unlock(pCopyRgn);
1936 }
1937
1938 /* No use in copying bits which are in the update region. */
1939 if (Window->hrgnUpdate != NULL)
1940 {
1941 NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1942 NtGdiCombineRgn(CopyRgn, CopyRgn, Window->hrgnUpdate, RGN_DIFF);
1943 NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1944 }
1945
1946 /*
1947 * Now, get the bounding box of the copy region. If it's empty
1948 * there's nothing to copy. Also, it's no use copying bits onto
1949 * themselves.
1950 */
1951 if ( (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(CopyRgn, NULL)) &&
1952 REGION_GetRgnBox(VisRgn, &CopyRect) == NULLREGION)
1953 {
1954 /* Nothing to copy, clean up */
1955 RGNOBJAPI_Unlock(VisRgn);
1956 GreDeleteObject(CopyRgn);
1957 CopyRgn = NULL;
1958 }
1959 else if (OldWindowRect.left != NewWindowRect.left ||
1960 OldWindowRect.top != NewWindowRect.top)
1961 {
1962 if(VisRgn)
1963 {
1964 RGNOBJAPI_Unlock(VisRgn);
1965 }
1966
1967 /*
1968 * Small trick here: there is no function to bitblt a region. So
1969 * we set the region as the clipping region, take the bounding box
1970 * of the region and bitblt that. Since nothing outside the clipping
1971 * region is copied, this has the effect of bitblt'ing the region.
1972 *
1973 * Since NtUserGetDCEx takes ownership of the clip region, we need
1974 * to create a copy of CopyRgn and pass that. We need CopyRgn later
1975 */
1976 NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1977 Dc = UserGetDCEx( Window,
1978 CopyRgn,
1979 DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN);
1980 NtGdiBitBlt( Dc,
1981 CopyRect.left, CopyRect.top,
1982 CopyRect.right - CopyRect.left,
1983 CopyRect.bottom - CopyRect.top,
1984 Dc,
1985 CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
1986 CopyRect.top + (OldWindowRect.top - NewWindowRect.top),
1987 SRCCOPY,
1988 0,
1989 0);
1990
1991 UserReleaseDC(Window, Dc, FALSE);
1992 IntValidateParent(Window, CopyRgn, FALSE);
1993 NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1994 }
1995 else if(VisRgn)
1996 {
1997 RGNOBJAPI_Unlock(VisRgn);
1998 }
1999 }
2000 else
2001 {
2002 CopyRgn = NULL;
2003 }
2004
2005 /* We need to redraw what wasn't visible before */
2006 if (VisAfter != NULL)
2007 {
2008 DirtyRgn = IntSysCreateRectRgn(0, 0, 0, 0);
2009 if (CopyRgn != NULL)
2010 {
2011 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
2012 }
2013 else
2014 {
2015 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
2016 }
2017 if (RgnType != ERROR && RgnType != NULLREGION)
2018 {
2019 /* old code
2020 NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2021 IntInvalidateWindows( Window,
2022 DirtyRgn,
2023 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2024 }
2025 GreDeleteObject(DirtyRgn);
2026 */
2027
2028 PWND Parent = Window->spwndParent;
2029
2030 NtGdiOffsetRgn( DirtyRgn,
2031 Window->rcWindow.left,
2032 Window->rcWindow.top);
2033 if ( (Window->style & WS_CHILD) &&
2034 (Parent) &&
2035 !(Parent->style & WS_CLIPCHILDREN))
2036 {
2037 IntInvalidateWindows( Parent,
2038 DirtyRgn,
2039 RDW_ERASE | RDW_INVALIDATE);
2040 co_IntPaintWindows(Parent, RDW_ERASENOW, FALSE);
2041 }
2042 else
2043 {
2044 IntInvalidateWindows( Window,
2045 DirtyRgn,
2046 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2047 }
2048 }
2049 GreDeleteObject(DirtyRgn);
2050 }
2051
2052 if (CopyRgn != NULL)
2053 {
2054 GreDeleteObject(CopyRgn);
2055 }
2056
2057 /* Expose what was covered before but not covered anymore */
2058 if (VisBefore != NULL)
2059 {
2060 ExposedRgn = IntSysCreateRectRgn(0, 0, 0, 0);
2061 RgnType = NtGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
2062 NtGdiOffsetRgn( ExposedRgn,
2063 OldWindowRect.left - NewWindowRect.left,
2064 OldWindowRect.top - NewWindowRect.top);
2065
2066 if (VisAfter != NULL)
2067 RgnType = NtGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
2068
2069 if (RgnType != ERROR && RgnType != NULLREGION)
2070 {
2071 co_VIS_WindowLayoutChanged(Window, ExposedRgn);
2072 }
2073 GreDeleteObject(ExposedRgn);
2074 GreDeleteObject(VisBefore);
2075 }
2076
2077 if (VisAfter != NULL)
2078 {
2079 GreDeleteObject(VisAfter);
2080 }
2081 }
2082
2083 if (!(WinPos.flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
2084 {
2085 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2086 {
2087 co_IntSendMessageNoWait(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
2088 }
2089 else
2090 {
2091 //ERR("SetWindowPos Set FG Window!\n");
2092 if (Window->state & WNDS_BEINGACTIVATED) // Inside SAW?
2093 co_IntSetActiveWindow(Window, FALSE, TRUE, FALSE); // Fixes Api AttachThreadInput tests.
2094 else
2095 co_IntSetForegroundWindow(Window); // Fixes SW_HIDE issues. Wine win test_SetActiveWindow & test_SetForegroundWindow.
2096 }
2097 }
2098
2099 /* And last, send the WM_WINDOWPOSCHANGED message */
2100
2101 TRACE("\tstatus flags = %04x\n", WinPos.flags & SWP_AGG_STATUSFLAGS);
2102
2103 if ((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2104 {
2105 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
2106 and always contains final window position.
2107 */
2108 WinPos.x = NewWindowRect.left;
2109 WinPos.y = NewWindowRect.top;
2110 WinPos.cx = NewWindowRect.right - NewWindowRect.left;
2111 WinPos.cy = NewWindowRect.bottom - NewWindowRect.top;
2112 co_IntSendMessageNoWait(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
2113 }
2114
2115 if ( WinPos.flags & SWP_FRAMECHANGED || WinPos.flags & SWP_STATECHANGED ||
2116 !(WinPos.flags & SWP_NOCLIENTSIZE) || !(WinPos.flags & SWP_NOCLIENTMOVE) )
2117 {
2118 PWND pWnd = ValidateHwndNoErr(WinPos.hwnd);
2119 if (pWnd)
2120 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2121 }
2122
2123 if(bPointerInWindow != IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y))
2124 {
2125 /* Generate mouse move message */
2126 MSG msg;
2127 msg.message = WM_MOUSEMOVE;
2128 msg.wParam = UserGetMouseButtonsState();
2129 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2130 msg.pt = gpsi->ptCursor;
2131 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2132 }
2133
2134 return TRUE;
2135 }
2136
2137 LRESULT FASTCALL
2138 co_WinPosGetNonClientSize(PWND Window, RECT* WindowRect, RECT* ClientRect)
2139 {
2140 LRESULT Result;
2141
2142 ASSERT_REFS_CO(Window);
2143
2144 *ClientRect = *WindowRect;
2145 Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect);
2146
2147 FixClientRect(ClientRect, WindowRect);
2148
2149 return Result;
2150 }
2151
2152 void FASTCALL
2153 co_WinPosSendSizeMove(PWND Wnd)
2154 {
2155 RECTL Rect;
2156 LPARAM lParam;
2157 WPARAM wParam = SIZE_RESTORED;
2158
2159 IntGetClientRect(Wnd, &Rect);
2160 lParam = MAKELONG(Rect.right-Rect.left, Rect.bottom-Rect.top);
2161
2162 Wnd->state &= ~WNDS_SENDSIZEMOVEMSGS;
2163
2164 if (Wnd->style & WS_MAXIMIZE)
2165 {
2166 wParam = SIZE_MAXIMIZED;
2167 }
2168 else if (Wnd->style & WS_MINIMIZE)
2169 {
2170 wParam = SIZE_MINIMIZED;
2171 lParam = 0;
2172 }
2173
2174 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SIZE, wParam, lParam);
2175
2176 if (Wnd->spwndParent == UserGetDesktopWindow()) // Wnd->spwndParent->fnid == FNID_DESKTOP )
2177 lParam = MAKELONG(Wnd->rcClient.left, Wnd->rcClient.top);
2178 else
2179 lParam = MAKELONG(Wnd->rcClient.left-Wnd->spwndParent->rcClient.left, Wnd->rcClient.top-Wnd->spwndParent->rcClient.top);
2180
2181 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_MOVE, 0, lParam);
2182
2183 IntEngWindowChanged(Wnd, WOC_RGN_CLIENT);
2184 }
2185
2186 BOOLEAN FASTCALL
2187 co_WinPosShowWindow(PWND Wnd, INT Cmd)
2188 {
2189 BOOLEAN WasVisible;
2190 UINT Swp = 0, EventMsg = 0;
2191 RECTL NewPos = {0, 0, 0, 0};
2192 BOOLEAN ShowFlag;
2193 LONG style;
2194 PWND Parent;
2195 PTHREADINFO pti;
2196 // HRGN VisibleRgn;
2197 //ERR("co_WinPosShowWindow START\n");
2198 BOOL ShowOwned = FALSE;
2199 ASSERT_REFS_CO(Wnd);
2200
2201 pti = PsGetCurrentThreadWin32Thread();
2202 WasVisible = (Wnd->style & WS_VISIBLE) != 0;
2203 style = Wnd->style;
2204
2205 switch (Cmd)
2206 {
2207 case SW_HIDE:
2208 {
2209 if (!WasVisible)
2210 {
2211 //ERR("co_WinPosShowWindow Exit Bad\n");
2212 return(FALSE);
2213 }
2214 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2215 if (Wnd != pti->MessageQueue->spwndActive)
2216 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2217 break;
2218 }
2219
2220 case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
2221 case SW_SHOWMINNOACTIVE:
2222 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2223 /* Fall through. */
2224 case SW_SHOWMINIMIZED:
2225 Swp |= SWP_SHOWWINDOW;
2226 /* Fall through. */
2227 case SW_MINIMIZE:
2228 {
2229 Swp |= SWP_NOACTIVATE;
2230 if (!(style & WS_MINIMIZE))
2231 {
2232 IntShowOwnedPopups(Wnd, FALSE );
2233
2234 // Fix wine Win test_SetFocus todo #1 & #2,
2235 if (Cmd == SW_SHOWMINIMIZED)
2236 {
2237 //ERR("co_WinPosShowWindow Set focus 1\n");
2238 if ((style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2239 co_UserSetFocus(Wnd->spwndParent);
2240 else
2241 co_UserSetFocus(0);
2242 }
2243
2244 Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos) |
2245 SWP_FRAMECHANGED;
2246
2247 EventMsg = EVENT_SYSTEM_MINIMIZESTART;
2248 }
2249 else
2250 {
2251 if (!WasVisible)
2252 {
2253 Swp |= SWP_FRAMECHANGED;
2254 }
2255 else ////
2256 {
2257 //ERR("co_WinPosShowWindow Exit Good\n");
2258 return TRUE;
2259 }
2260 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2261 }
2262 break;
2263 }
2264
2265 case SW_SHOWMAXIMIZED:
2266 {
2267 Swp |= SWP_SHOWWINDOW;
2268 if (!(style & WS_MAXIMIZE))
2269 {
2270 ShowOwned = TRUE;
2271
2272 Swp |= co_WinPosMinMaximize(Wnd, SW_MAXIMIZE, &NewPos) |
2273 SWP_FRAMECHANGED;
2274
2275 EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2276 }
2277 else
2278 {
2279 if (!WasVisible)
2280 {
2281 Swp |= SWP_FRAMECHANGED;
2282 }
2283 else ////
2284 {
2285 //ERR("co_WinPosShowWindow Exit Good 1\n");
2286 return TRUE;
2287 }
2288 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2289 }
2290 break;
2291 }
2292
2293 case SW_SHOWNA:
2294 Swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2295 if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOZORDER;
2296 break;
2297 case SW_SHOW:
2298 if (WasVisible) return(TRUE); // Nothing to do!
2299 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2300 /* Don't activate the topmost window. */
2301 if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2302 break;
2303
2304 case SW_SHOWNOACTIVATE:
2305 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2306 /* Fall through. */
2307 case SW_SHOWNORMAL:
2308 case SW_SHOWDEFAULT:
2309 case SW_RESTORE:
2310 if (!WasVisible) Swp |= SWP_SHOWWINDOW;
2311 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2312 {
2313 Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos) |
2314 SWP_FRAMECHANGED;
2315
2316 if (style & WS_MINIMIZE) EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2317 }
2318 else
2319 {
2320 if (!WasVisible)
2321 {
2322 Swp |= SWP_FRAMECHANGED;
2323 }
2324 else ////
2325 {
2326 //ERR("co_WinPosShowWindow Exit Good 3\n");
2327 return TRUE;
2328 }
2329 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2330 }
2331 if ( style & WS_CHILD &&
2332 !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2333 !(Swp & SWP_STATECHANGED))
2334 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2335 break;
2336
2337 default:
2338 //ERR("co_WinPosShowWindow Exit Good 4\n");
2339 return WasVisible;
2340 }
2341
2342 ShowFlag = (Cmd != SW_HIDE);
2343
2344 if ((ShowFlag != WasVisible || Cmd == SW_SHOWNA) && Cmd != SW_SHOWMAXIMIZED && !(Swp & SWP_STATECHANGED))
2345 {
2346 co_IntSendMessageNoWait(Wnd->head.h, WM_SHOWWINDOW, ShowFlag, 0);
2347 if (!(Wnd->state2 & WNDS2_WIN31COMPAT))
2348 co_IntSendMessageNoWait(Wnd->head.h, WM_SETVISIBLE, ShowFlag, 0);
2349 if (!VerifyWnd(Wnd)) return WasVisible;
2350 }
2351
2352 /* We can't activate a child window */
2353 if ((Wnd->style & WS_CHILD) &&
2354 !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2355 Cmd != SW_SHOWNA)
2356 {
2357 //ERR("SWP Child No active and ZOrder\n");
2358 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2359 }
2360
2361 #if 0 // Explorer issues with common controls. Someone does not know how CS_SAVEBITS works.
2362 if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
2363 Wnd->pcls->style & CS_SAVEBITS &&
2364 ((Cmd == SW_SHOW) || (Cmd == SW_NORMAL)))
2365 {
2366 ERR("WinPosShowWindow Set active\n");
2367 UserSetActiveWindow(Wnd);
2368 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2369 }
2370 #endif
2371
2372 if (IsChildVisible(Wnd) || Swp & SWP_STATECHANGED)
2373 {
2374 TRACE("Child is Vis %s or State changed %s. ShowFlag %s\n",
2375 (IsChildVisible(Wnd) ? "TRUE" : "FALSE"), (Swp & SWP_STATECHANGED ? "TRUE" : "FALSE"),
2376 (ShowFlag ? "TRUE" : "FALSE"));
2377 co_WinPosSetWindowPos( Wnd,
2378 0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP,
2379 NewPos.left,
2380 NewPos.top,
2381 NewPos.right, //NewPos.right - NewPos.left,
2382 NewPos.bottom, //NewPos.bottom - NewPos.top,
2383 LOWORD(Swp));
2384 }
2385 else
2386 {
2387 TRACE("Parent Vis?\n");
2388 /* if parent is not visible simply toggle WS_VISIBLE and return */
2389 if (ShowFlag) IntSetStyle( Wnd, WS_VISIBLE, 0 );
2390 else IntSetStyle( Wnd, 0, WS_VISIBLE );
2391 }
2392
2393 if ( EventMsg ) IntNotifyWinEvent(EventMsg, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2394
2395 if ( ShowOwned ) IntShowOwnedPopups(Wnd, TRUE );
2396
2397 if ((Cmd == SW_HIDE) || (Cmd == SW_MINIMIZE))
2398 {
2399 if ( Wnd == pti->MessageQueue->spwndActive && pti->MessageQueue == IntGetFocusMessageQueue() )
2400 {
2401 if ( Wnd->spwndParent == UserGetDesktopWindow())
2402 {
2403 if(!ActivateOtherWindowMin(Wnd))
2404 co_WinPosActivateOtherWindow(Wnd);
2405 }
2406 else
2407 co_WinPosActivateOtherWindow(Wnd);
2408 }
2409
2410 /* Revert focus to parent */
2411 if (Wnd == pti->MessageQueue->spwndFocus)
2412 {
2413 Parent = Wnd->spwndParent;
2414 if (Wnd->spwndParent == UserGetDesktopWindow()) Parent = 0;
2415 co_UserSetFocus(Parent);
2416 }
2417 }
2418
2419 /* FIXME: Check for window destruction. */
2420
2421 if ((Wnd->state & WNDS_SENDSIZEMOVEMSGS) &&
2422 !(Wnd->state2 & WNDS2_INDESTROY))
2423 {
2424 co_WinPosSendSizeMove(Wnd);
2425 }
2426
2427 /* if previous state was minimized Windows sets focus to the window */
2428 if (style & WS_MINIMIZE)
2429 {
2430 co_UserSetFocus(Wnd);
2431 // Fix wine Win test_SetFocus todo #3,
2432 if (!(style & WS_CHILD)) co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_ACTIVATE, WA_ACTIVE, 0);
2433 }
2434 //ERR("co_WinPosShowWindow EXIT\n");
2435 return(WasVisible);
2436 }
2437
2438 static
2439 PWND FASTCALL
2440 co_WinPosSearchChildren(
2441 PWND ScopeWin,
2442 POINT *Point,
2443 USHORT *HitTest,
2444 BOOL Ignore
2445 )
2446 {
2447 PWND pwndChild;
2448 HWND *List, *phWnd;
2449
2450 if (!(ScopeWin->style & WS_VISIBLE))
2451 {
2452 return NULL;
2453 }
2454
2455 if (!Ignore && (ScopeWin->style & WS_DISABLED))
2456 {
2457 return NULL;
2458 }
2459
2460 if (!IntPtInWindow(ScopeWin, Point->x, Point->y))
2461 {
2462 return NULL;
2463 }
2464
2465 UserReferenceObject(ScopeWin);
2466
2467 if ( RECTL_bPointInRect(&ScopeWin->rcClient, Point->x, Point->y) )
2468 {
2469 List = IntWinListChildren(ScopeWin);
2470 if(List)
2471 {
2472 for (phWnd = List; *phWnd; ++phWnd)
2473 {
2474 if (!(pwndChild = ValidateHwndNoErr(*phWnd)))
2475 {
2476 continue;
2477 }
2478
2479 pwndChild = co_WinPosSearchChildren(pwndChild, Point, HitTest, Ignore);
2480
2481 if(pwndChild != NULL)
2482 {
2483 /* We found a window. Don't send any more WM_NCHITTEST messages */
2484 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2485 UserDereferenceObject(ScopeWin);
2486 return pwndChild;
2487 }
2488 }
2489 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2490 }
2491 }
2492
2493 if (ScopeWin->head.pti == PsGetCurrentThreadWin32Thread())
2494 {
2495 *HitTest = (USHORT)co_IntSendMessage(ScopeWin->head.h, WM_NCHITTEST, 0,
2496 MAKELONG(Point->x, Point->y));
2497 if ((*HitTest) == (USHORT)HTTRANSPARENT)
2498 {
2499 UserDereferenceObject(ScopeWin);
2500 return NULL;
2501 }
2502 }
2503 else
2504 *HitTest = HTCLIENT;
2505
2506 return ScopeWin;
2507 }
2508
2509 PWND FASTCALL
2510 co_WinPosWindowFromPoint(PWND ScopeWin, POINT *WinPoint, USHORT* HitTest, BOOL Ignore)
2511 {
2512 PWND Window;
2513 POINT Point = *WinPoint;
2514 USER_REFERENCE_ENTRY Ref;
2515
2516 if( ScopeWin == NULL )
2517 {
2518 ScopeWin = UserGetDesktopWindow();
2519 if(ScopeWin == NULL)
2520 return NULL;
2521 }
2522
2523 *HitTest = HTNOWHERE;
2524
2525 ASSERT_REFS_CO(ScopeWin);
2526 UserRefObjectCo(ScopeWin, &Ref);
2527
2528 Window = co_WinPosSearchChildren(ScopeWin, &Point, HitTest, Ignore);
2529
2530 UserDerefObjectCo(ScopeWin);
2531 if (Window)
2532 ASSERT_REFS_CO(Window);
2533 ASSERT_REFS_CO(ScopeWin);
2534
2535 return Window;
2536 }
2537
2538 PWND FASTCALL
2539 IntRealChildWindowFromPoint(PWND Parent, LONG x, LONG y)
2540 {
2541 POINTL Pt;
2542 HWND *List, *phWnd;
2543 PWND pwndHit = NULL;
2544
2545 Pt.x = x;
2546 Pt.y = y;
2547
2548 if (Parent != UserGetDesktopWindow())
2549 {
2550 Pt.x += Parent->rcClient.left;
2551 Pt.y += Parent->rcClient.top;
2552 }
2553
2554 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2555
2556 if ((List = IntWinListChildren(Parent)))
2557 {
2558 for (phWnd = List; *phWnd; phWnd++)
2559 {
2560 PWND Child;
2561 if ((Child = ValidateHwndNoErr(*phWnd)))
2562 {
2563 if ( Child->style & WS_VISIBLE && IntPtInWindow(Child, Pt.x, Pt.y) )
2564 {
2565 if ( Child->pcls->atomClassName != gpsi->atomSysClass[ICLS_BUTTON] ||
2566 (Child->style & BS_TYPEMASK) != BS_GROUPBOX )
2567 {
2568 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2569 return Child;
2570 }
2571 pwndHit = Child;
2572 }
2573 }
2574 }
2575 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2576 }
2577 return pwndHit ? pwndHit : Parent;
2578 }
2579
2580 PWND APIENTRY
2581 IntChildWindowFromPointEx(PWND Parent, LONG x, LONG y, UINT uiFlags)
2582 {
2583 POINTL Pt;
2584 HWND *List, *phWnd;
2585 PWND pwndHit = NULL;
2586
2587 Pt.x = x;
2588 Pt.y = y;
2589
2590 if (Parent != UserGetDesktopWindow())
2591 {
2592 if (Parent->ExStyle & WS_EX_LAYOUTRTL)
2593 Pt.x = Parent->rcClient.right - Pt.x;
2594 else
2595 Pt.x += Parent->rcClient.left;
2596 Pt.y += Parent->rcClient.top;
2597 }
2598
2599 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2600
2601 if ((List = IntWinListChildren(Parent)))
2602 {
2603 for (phWnd = List; *phWnd; phWnd++)
2604 {
2605 PWND Child;
2606 if ((Child = ValidateHwndNoErr(*phWnd)))
2607 {
2608 if (uiFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
2609 {
2610 if (!(Child->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE)) continue;
2611 if ((Child->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED)) continue;
2612 }
2613
2614 if (uiFlags & CWP_SKIPTRANSPARENT)
2615 {
2616 if (Child->ExStyle & WS_EX_TRANSPARENT) continue;
2617 }
2618
2619 if (IntPtInWindow(Child, Pt.x, Pt.y))
2620 {
2621 pwndHit = Child;
2622 break;
2623 }
2624 }
2625 }
2626 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2627 }
2628 return pwndHit ? pwndHit : Parent;
2629 }
2630
2631 HDWP
2632 FASTCALL
2633 IntDeferWindowPos( HDWP hdwp,
2634 HWND hwnd,
2635 HWND hwndAfter,
2636 INT x,
2637 INT y,
2638 INT cx,
2639 INT cy,
2640 UINT flags )
2641 {
2642 PSMWP pDWP;
2643 int i;
2644 HDWP retvalue = hdwp;
2645
2646 TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2647 hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
2648
2649 if (flags & ~(SWP_NOSIZE | SWP_NOMOVE |
2650 SWP_NOZORDER | SWP_NOREDRAW |
2651 SWP_NOACTIVATE | SWP_NOCOPYBITS |
2652 SWP_NOOWNERZORDER|SWP_SHOWWINDOW |
2653 SWP_HIDEWINDOW | SWP_FRAMECHANGED))
2654 {
2655 EngSetLastError(ERROR_INVALID_PARAMETER);
2656 return NULL;
2657 }
2658
2659 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
2660 {
2661 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
2662 return NULL;
2663 }
2664
2665 for (i = 0; i < pDWP->ccvr; i++)
2666 {
2667 if (pDWP->acvr[i].pos.hwnd == hwnd)
2668 {
2669 /* Merge with the other changes */
2670 if (!(flags & SWP_NOZORDER))
2671 {
2672 pDWP->acvr[i].pos.hwndInsertAfter = hwndAfter;
2673 }
2674 if (!(flags & SWP_NOMOVE))
2675 {
2676 pDWP->acvr[i].pos.x = x;
2677 pDWP->acvr[i].pos.y = y;
2678 }
2679 if (!(flags & SWP_NOSIZE))
2680 {
2681 pDWP->acvr[i].pos.cx = cx;
2682 pDWP->acvr[i].pos.cy = cy;
2683 }
2684 pDWP->acvr[i].pos.flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
2685 SWP_NOZORDER | SWP_NOREDRAW |
2686 SWP_NOACTIVATE | SWP_NOCOPYBITS|
2687 SWP_NOOWNERZORDER);
2688 pDWP->acvr[i].pos.flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
2689 SWP_FRAMECHANGED);
2690 goto END;
2691 }
2692 }
2693 if (pDWP->ccvr >= pDWP->ccvrAlloc)
2694 {
2695 PCVR newpos = ExAllocatePoolWithTag(PagedPool, pDWP->ccvrAlloc * 2 * sizeof(CVR), USERTAG_SWP);
2696 if (!newpos)
2697 {
2698 retvalue = NULL;
2699 goto END;
2700 }
2701 RtlZeroMemory(newpos, pDWP->ccvrAlloc * 2 * sizeof(CVR));
2702 RtlCopyMemory(newpos, pDWP->acvr, pDWP->ccvrAlloc * sizeof(CVR));
2703 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
2704 pDWP->ccvrAlloc *= 2;
2705 pDWP->acvr = newpos;
2706 }
2707 pDWP->acvr[pDWP->ccvr].pos.hwnd = hwnd;
2708 pDWP->acvr[pDWP->ccvr].pos.hwndInsertAfter = hwndAfter;
2709 pDWP->acvr[pDWP->ccvr].pos.x = x;
2710 pDWP->acvr[pDWP->ccvr].pos.y = y;
2711 pDWP->acvr[pDWP->ccvr].pos.cx = cx;
2712 pDWP->acvr[pDWP->ccvr].pos.cy = cy;
2713 pDWP->acvr[pDWP->ccvr].pos.flags = flags;
2714 pDWP->acvr[pDWP->ccvr].hrgnClip = NULL;
2715 pDWP->acvr[pDWP->ccvr].hrgnInterMonitor = NULL;
2716 pDWP->ccvr++;
2717 END:
2718 return retvalue;
2719 }
2720
2721 BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp, BOOL sAsync )
2722 {
2723 PSMWP pDWP;
2724 PCVR winpos;
2725 BOOL res = TRUE;
2726 int i;
2727
2728 TRACE("%p\n", hdwp);
2729
2730 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
2731 {
2732 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
2733 return FALSE;
2734 }
2735
2736 for (i = 0, winpos = pDWP->acvr; res && i < pDWP->ccvr; i++, winpos++)
2737 {
2738 PWND pwnd;
2739 USER_REFERENCE_ENTRY Ref;
2740
2741 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2742 winpos->pos.hwnd, winpos->pos.hwndInsertAfter, winpos->pos.x, winpos->pos.y,
2743 winpos->pos.cx, winpos->pos.cy, winpos->pos.flags);
2744
2745 pwnd = ValidateHwndNoErr(winpos->pos.hwnd);
2746 if (!pwnd)
2747 continue;
2748
2749 UserRefObjectCo(pwnd, &Ref);
2750
2751 if ( sAsync )
2752 {
2753 LRESULT lRes;
2754 PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
2755 if ( ppos )
2756 {
2757 *ppos = winpos->pos;
2758 /* Yes it's a pointer inside Win32k! */
2759 lRes = co_IntSendMessageNoWait( winpos->pos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
2760 /* We handle this the same way as Event Hooks and Hooks. */
2761 if ( !lRes )
2762 {
2763 ExFreePoolWithTag(ppos, USERTAG_SWP);
2764 }
2765 }
2766 }
2767 else
2768 res = co_WinPosSetWindowPos( pwnd,
2769 winpos->pos.hwndInsertAfter,
2770 winpos->pos.x,
2771 winpos->pos.y,
2772 winpos->pos.cx,
2773 winpos->pos.cy,
2774 winpos->pos.flags);
2775
2776 // Hack to pass tests.... Must have some work to do so clear the error.
2777 if (res && (winpos->pos.flags & (SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER)) == SWP_NOZORDER )
2778 EngSetLastError(ERROR_SUCCESS);
2779
2780 UserDerefObjectCo(pwnd);
2781 }
2782 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
2783 UserDereferenceObject(pDWP);
2784 UserDeleteObject(hdwp, TYPE_SETWINDOWPOS);
2785 return res;
2786 }
2787
2788 /*
2789 * @implemented
2790 */
2791 HWND APIENTRY
2792 NtUserChildWindowFromPointEx(HWND hwndParent,
2793 LONG x,
2794 LONG y,
2795 UINT uiFlags)
2796 {
2797 PWND pwndParent;
2798 TRACE("Enter NtUserChildWindowFromPointEx\n");
2799 UserEnterExclusive();
2800 if ((pwndParent = UserGetWindowObject(hwndParent)))
2801 {
2802 pwndParent = IntChildWindowFromPointEx(pwndParent, x, y, uiFlags);
2803 }
2804 UserLeave();
2805 TRACE("Leave NtUserChildWindowFromPointEx\n");
2806 return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
2807 }
2808
2809 /*
2810 * @implemented
2811 */
2812 BOOL APIENTRY
2813 NtUserEndDeferWindowPosEx(HDWP WinPosInfo,
2814 DWORD Unknown1)
2815 {
2816 BOOL Ret;
2817 TRACE("Enter NtUserEndDeferWindowPosEx\n");
2818 UserEnterExclusive();
2819 Ret = IntEndDeferWindowPosEx(WinPosInfo, (BOOL)Unknown1);
2820 TRACE("Leave NtUserEndDeferWindowPosEx, ret=%i\n", Ret);
2821 UserLeave();
2822 return Ret;
2823 }
2824
2825 /*
2826 * @implemented
2827 */
2828 HDWP APIENTRY
2829 NtUserDeferWindowPos(HDWP WinPosInfo,
2830 HWND Wnd,
2831 HWND WndInsertAfter,
2832 int x,
2833 int y,
2834 int cx,
2835 int cy,
2836 UINT Flags)
2837 {
2838 PWND pWnd, pWndIA;
2839 HDWP Ret = NULL;
2840 UINT Tmp = ~(SWP_ASYNCWINDOWPOS|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_NOREPOSITION|
2841 SWP_NOCOPYBITS|SWP_HIDEWINDOW|SWP_SHOWWINDOW|SWP_FRAMECHANGED|
2842 SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE);
2843
2844 TRACE("Enter NtUserDeferWindowPos\n");
2845 UserEnterExclusive();
2846
2847 if ( Flags & Tmp )
2848 {
2849 EngSetLastError(ERROR_INVALID_FLAGS);
2850 goto Exit;
2851 }
2852
2853 pWnd = UserGetWindowObject(Wnd);
2854 if ( !pWnd || // FIXME:
2855 pWnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2856 pWnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2857 {
2858 goto Exit;
2859 }
2860
2861 if ( WndInsertAfter &&
2862 WndInsertAfter != HWND_BOTTOM &&
2863 WndInsertAfter != HWND_TOPMOST &&
2864 WndInsertAfter != HWND_NOTOPMOST )
2865 {
2866 pWndIA = UserGetWindowObject(WndInsertAfter);
2867 if ( !pWndIA ||
2868 pWndIA == UserGetDesktopWindow() ||
2869 pWndIA == UserGetMessageWindow() )
2870 {
2871 goto Exit;
2872 }
2873 }
2874
2875 Ret = IntDeferWindowPos(WinPosInfo, Wnd, WndInsertAfter, x, y, cx, cy, Flags);
2876
2877 Exit:
2878 TRACE("Leave NtUserDeferWindowPos, ret=%p\n", Ret);
2879 UserLeave();
2880 return Ret;
2881 }
2882
2883 /*
2884 * @implemented
2885 */
2886 DWORD APIENTRY
2887 NtUserGetInternalWindowPos( HWND hWnd,
2888 LPRECT rectWnd,
2889 LPPOINT ptIcon)
2890 {
2891 PWND Window;
2892 DWORD Ret = 0;
2893 BOOL Hit = FALSE;
2894 WINDOWPLACEMENT wndpl;
2895
2896 UserEnterShared();
2897
2898 if (!(Window = UserGetWindowObject(hWnd)))
2899 {
2900 Hit = FALSE;
2901 goto Exit;
2902 }
2903
2904 _SEH2_TRY
2905 {
2906 if(rectWnd)
2907 {
2908 ProbeForWrite(rectWnd,
2909 sizeof(RECT),
2910 1);
2911 }
2912 if(ptIcon)
2913 {
2914 ProbeForWrite(ptIcon,
2915 sizeof(POINT),
2916 1);
2917 }
2918
2919 }
2920 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2921 {
2922 SetLastNtError(_SEH2_GetExceptionCode());
2923 Hit = TRUE;
2924 }
2925 _SEH2_END;
2926
2927 wndpl.length = sizeof(WINDOWPLACEMENT);
2928
2929 if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
2930 {
2931 _SEH2_TRY
2932 {
2933 if (rectWnd)
2934 {
2935 RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));
2936 }
2937 if (ptIcon)
2938 {
2939 RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT));
2940 }
2941
2942 }
2943 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2944 {
2945 SetLastNtError(_SEH2_GetExceptionCode());
2946 Hit = TRUE;
2947 }
2948 _SEH2_END;
2949
2950 if (!Hit) Ret = wndpl.showCmd;
2951 }
2952 Exit:
2953 UserLeave();
2954 return Ret;
2955 }
2956
2957 /*
2958 * @implemented
2959 */
2960 BOOL APIENTRY
2961 NtUserGetWindowPlacement(HWND hWnd,
2962 WINDOWPLACEMENT *lpwndpl)
2963 {
2964 PWND Wnd;
2965 WINDOWPLACEMENT Safepl;
2966 NTSTATUS Status;
2967 DECLARE_RETURN(BOOL);
2968
2969 TRACE("Enter NtUserGetWindowPlacement\n");
2970 UserEnterShared();
2971
2972 if (!(Wnd = UserGetWindowObject(hWnd)))
2973 {
2974 RETURN( FALSE);
2975 }
2976
2977 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
2978 if(!NT_SUCCESS(Status))
2979 {
2980 SetLastNtError(Status);
2981 RETURN( FALSE);
2982 }
2983 if(Safepl.length != sizeof(WINDOWPLACEMENT))
2984 {
2985 RETURN( FALSE);
2986 }
2987
2988 IntGetWindowPlacement(Wnd, &Safepl);
2989
2990 Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
2991 if(!NT_SUCCESS(Status))
2992 {
2993 SetLastNtError(Status);
2994 RETURN( FALSE);
2995 }
2996
2997 RETURN( TRUE);
2998
2999 CLEANUP:
3000 TRACE("Leave NtUserGetWindowPlacement, ret=%i\n",_ret_);
3001 UserLeave();
3002 END_CLEANUP;
3003 }
3004
3005 DWORD
3006 APIENTRY
3007 NtUserMinMaximize(
3008 HWND hWnd,
3009 UINT cmd, // Wine SW_ commands
3010 BOOL Hide)
3011 {
3012 PWND pWnd;
3013
3014 TRACE("Enter NtUserMinMaximize\n");
3015 UserEnterExclusive();
3016
3017 pWnd = UserGetWindowObject(hWnd);
3018 if ( !pWnd || // FIXME:
3019 pWnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3020 pWnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3021 {
3022 goto Exit;
3023 }
3024
3025 if ( cmd > SW_MAX || pWnd->state2 & WNDS2_INDESTROY)
3026 {
3027 EngSetLastError(ERROR_INVALID_PARAMETER);
3028 goto Exit;
3029 }
3030
3031 cmd |= Hide ? SW_HIDE : 0;
3032
3033 co_WinPosShowWindow(pWnd, cmd);
3034
3035 Exit:
3036 TRACE("Leave NtUserMinMaximize\n");
3037 UserLeave();
3038 return 0; // Always NULL?
3039 }
3040
3041 /*
3042 * @implemented
3043 */
3044 BOOL APIENTRY
3045 NtUserMoveWindow(
3046 HWND hWnd,
3047 int X,
3048 int Y,
3049 int nWidth,
3050 int nHeight,
3051 BOOL bRepaint)
3052 {
3053 return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight,
3054 (bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE :
3055 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW));
3056 }
3057
3058 /*
3059 * @implemented
3060 */
3061 HWND APIENTRY
3062 NtUserRealChildWindowFromPoint(HWND Parent,
3063 LONG x,
3064 LONG y)
3065 {
3066 PWND pwndParent;
3067 TRACE("Enter NtUserRealChildWindowFromPoint\n");
3068 UserEnterShared();
3069 if ((pwndParent = UserGetWindowObject(Parent)))
3070 {
3071 pwndParent = IntRealChildWindowFromPoint(pwndParent, x, y);
3072 }
3073 UserLeave();
3074 TRACE("Leave NtUserRealChildWindowFromPoint\n");
3075 return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
3076 }
3077
3078 /*
3079 * @implemented
3080 */
3081 BOOL APIENTRY
3082 NtUserSetWindowPos(
3083 HWND hWnd,
3084 HWND hWndInsertAfter,
3085 int X,
3086 int Y,
3087 int cx,
3088 int cy,
3089 UINT uFlags)
3090 {
3091 DECLARE_RETURN(BOOL);
3092 PWND Window, pWndIA;
3093 BOOL ret;
3094 USER_REFERENCE_ENTRY Ref;
3095
3096 TRACE("Enter NtUserSetWindowPos\n");
3097 UserEnterExclusive();
3098
3099 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
3100 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3101 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3102 {
3103 ERR("NtUserSetWindowPos bad window handle!\n");
3104 RETURN(FALSE);
3105 }
3106
3107 if ( hWndInsertAfter &&
3108 hWndInsertAfter != HWND_BOTTOM &&
3109 hWndInsertAfter != HWND_TOPMOST &&
3110 hWndInsertAfter != HWND_NOTOPMOST )
3111 {
3112 if (!(pWndIA = UserGetWindowObject(hWndInsertAfter)) ||
3113 pWndIA == UserGetDesktopWindow() ||
3114 pWndIA == UserGetMessageWindow() )
3115 {
3116 ERR("NtUserSetWindowPos bad insert window handle!\n");
3117 RETURN(FALSE);
3118 }
3119 }
3120
3121 /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
3122 if (!(uFlags & SWP_NOMOVE))
3123 {
3124 if (X < -32768) X = -32768;
3125 else if (X > 32767) X = 32767;
3126 if (Y < -32768) Y = -32768;
3127 else if (Y > 32767) Y = 32767;
3128 }
3129 if (!(uFlags & SWP_NOSIZE))
3130 {
3131 if (cx < 0) cx = 0;
3132 else if (cx > 32767) cx = 32767;
3133 if (cy < 0) cy = 0;
3134 else if (cy > 32767) cy = 32767;
3135 }
3136
3137 UserRefObjectCo(Window, &Ref);
3138 ret = co_WinPosSetWindowPos(Window, hWndInsertAfter, X, Y, cx, cy, uFlags);
3139 UserDerefObjectCo(Window);
3140
3141 RETURN(ret);
3142
3143 CLEANUP:
3144 TRACE("Leave NtUserSetWindowPos, ret=%i\n",_ret_);
3145 UserLeave();
3146 END_CLEANUP;
3147 }
3148
3149 /*
3150 * @implemented
3151 */
3152 INT APIENTRY
3153 NtUserSetWindowRgn(
3154 HWND hWnd,
3155 HRGN hRgn,
3156 BOOL bRedraw)
3157 {
3158 HRGN hrgnCopy;
3159 PWND Window;
3160 INT flags = (SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE);
3161 BOOLEAN Ret = FALSE;
3162 DECLARE_RETURN(INT);
3163
3164 TRACE("Enter NtUserSetWindowRgn\n");
3165 UserEnterExclusive();
3166
3167 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
3168 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3169 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3170 {
3171 RETURN( 0);
3172 }
3173
3174 if (hRgn) // The region will be deleted in user32.
3175 {
3176 if (GreIsHandleValid(hRgn))
3177 {
3178 hrgnCopy = IntSysCreateRectRgn(0, 0, 0, 0);
3179 /* The coordinates of a window's window region are relative to the
3180 upper-left corner of the window, not the client area of the window. */
3181 NtGdiCombineRgn( hrgnCopy, hRgn, 0, RGN_COPY);
3182 }
3183 else
3184 RETURN( 0);
3185 }
3186 else
3187 {
3188 hrgnCopy = NULL;
3189 }
3190
3191 if (Window->hrgnClip)
3192 {
3193 /* Delete no longer needed region handle */
3194 IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED);
3195 GreDeleteObject(Window->hrgnClip);
3196 }
3197
3198 if (hrgnCopy)
3199 {
3200 /* Set public ownership */
3201 IntGdiSetRegionOwner(hrgnCopy, GDI_OBJ_HMGR_PUBLIC);
3202 }
3203 Window->hrgnClip = hrgnCopy;
3204
3205 Ret = co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, bRedraw ? flags : (flags|SWP_NOREDRAW) );
3206
3207 RETURN( (INT)Ret);
3208
3209 CLEANUP:
3210 TRACE("Leave NtUserSetWindowRgn, ret=%i\n",_ret_);
3211 UserLeave();
3212 END_CLEANUP;
3213 }
3214
3215 /*
3216 * @implemented
3217 */
3218 DWORD APIENTRY
3219 NtUserSetInternalWindowPos(
3220 HWND hwnd,
3221 UINT showCmd,
3222 LPRECT lprect,
3223 LPPOINT lppt)
3224 {
3225 WINDOWPLACEMENT wndpl;
3226 UINT flags;
3227 PWND Wnd;
3228 RECT rect;
3229 POINT pt = {0};
3230 DECLARE_RETURN(BOOL);
3231 USER_REFERENCE_ENTRY Ref;
3232
3233 TRACE("Enter NtUserSetWindowPlacement\n");
3234 UserEnterExclusive();
3235
3236 if (!(Wnd = UserGetWindowObject(hwnd)) || // FIXME:
3237 Wnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3238 Wnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3239 {
3240 RETURN( FALSE);
3241 }
3242
3243 _SEH2_TRY
3244 {
3245 if (lppt)
3246 {
3247 ProbeForRead(lppt, sizeof(POINT), 1);
3248 RtlCopyMemory(&pt, lppt, sizeof(POINT));
3249 }
3250 if (lprect)
3251 {
3252 ProbeForRead(lprect, sizeof(RECT), 1);
3253 RtlCopyMemory(&rect, lprect, sizeof(RECT));
3254 }
3255 }
3256 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3257 {
3258 SetLastNtError(_SEH2_GetExceptionCode());
3259 _SEH2_YIELD(RETURN( FALSE));
3260 }
3261 _SEH2_END
3262
3263 wndpl.length = sizeof(wndpl);
3264 wndpl.showCmd = showCmd;
3265 wndpl.flags = flags = 0;
3266
3267 if ( lppt )
3268 {
3269 flags |= PLACE_MIN;
3270 wndpl.flags |= WPF_SETMINPOSITION;
3271 wndpl.ptMinPosition = pt;
3272 }
3273 if ( lprect )
3274 {
3275 flags |= PLACE_RECT;
3276 wndpl.rcNormalPosition = rect;
3277 }
3278
3279 UserRefObjectCo(Wnd, &Ref);
3280 IntSetWindowPlacement(Wnd, &wndpl, flags);
3281 UserDerefObjectCo(Wnd);
3282 RETURN(TRUE);
3283
3284 CLEANUP:
3285 TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
3286 UserLeave();
3287 END_CLEANUP;
3288 }
3289
3290 /*
3291 * @implemented
3292 */
3293 BOOL APIENTRY
3294 NtUserSetWindowPlacement(HWND hWnd,
3295 WINDOWPLACEMENT *lpwndpl)
3296 {
3297 PWND Wnd;
3298 WINDOWPLACEMENT Safepl;
3299 UINT Flags;
3300 DECLARE_RETURN(BOOL);
3301 USER_REFERENCE_ENTRY Ref;
3302
3303 TRACE("Enter NtUserSetWindowPlacement\n");
3304 UserEnterExclusive();
3305
3306 if (!(Wnd = UserGetWindowObject(hWnd)) || // FIXME:
3307 Wnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3308 Wnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3309 {
3310 RETURN( FALSE);
3311 }
3312
3313 _SEH2_TRY
3314 {
3315 ProbeForRead(lpwndpl, sizeof(WINDOWPLACEMENT), 1);
3316 RtlCopyMemory(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3317 }
3318 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3319 {
3320 SetLastNtError(_SEH2_GetExceptionCode());
3321 _SEH2_YIELD(RETURN( FALSE));
3322 }
3323 _SEH2_END
3324
3325 if(Safepl.length != sizeof(WINDOWPLACEMENT))
3326 {
3327 RETURN( FALSE);
3328 }
3329
3330 Flags = PLACE_MAX | PLACE_RECT;
3331 if (Safepl.flags & WPF_SETMINPOSITION) Flags |= PLACE_MIN;
3332 UserRefObjectCo(Wnd, &Ref);
3333 IntSetWindowPlacement(Wnd, &Safepl, Flags);
3334 UserDerefObjectCo(Wnd);
3335 RETURN(TRUE);
3336
3337 CLEANUP:
3338 TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
3339 UserLeave();
3340 END_CLEANUP;
3341 }
3342
3343 /*
3344 * @implemented
3345 */
3346 BOOL APIENTRY
3347 NtUserShowWindowAsync(HWND hWnd, LONG nCmdShow)
3348 {
3349 PWND Window;
3350 BOOL ret;
3351 DECLARE_RETURN(BOOL);
3352 USER_REFERENCE_ENTRY Ref;
3353
3354 TRACE("Enter NtUserShowWindowAsync\n");
3355 UserEnterExclusive();
3356
3357 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
3358 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3359 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3360 {
3361 RETURN(FALSE);
3362 }
3363
3364 if ( nCmdShow > SW_MAX )
3365 {
3366 EngSetLastError(ERROR_INVALID_PARAMETER);
3367 RETURN(FALSE);
3368 }
3369
3370 UserRefObjectCo(Window, &Ref);
3371 ret = co_IntSendMessageNoWait( hWnd, WM_ASYNC_SHOWWINDOW, nCmdShow, 0 );
3372 UserDerefObjectCo(Window);
3373 if (-1 == (int) ret || !ret) ret = FALSE;
3374
3375 RETURN(ret);
3376
3377 CLEANUP:
3378 TRACE("Leave NtUserShowWindowAsync, ret=%i\n",_ret_);
3379 UserLeave();
3380 END_CLEANUP;
3381 }
3382
3383 /*
3384 * @implemented
3385 */
3386 BOOL APIENTRY
3387 NtUserShowWindow(HWND hWnd, LONG nCmdShow)
3388 {
3389 PWND Window;
3390 BOOL ret;
3391 DECLARE_RETURN(BOOL);
3392 USER_REFERENCE_ENTRY Ref;
3393
3394 TRACE("Enter NtUserShowWindow\n");
3395 UserEnterExclusive();
3396
3397 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
3398 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3399 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3400 {
3401 RETURN(FALSE);
3402 }
3403
3404 if ( nCmdShow > SW_MAX || Window->state2 & WNDS2_INDESTROY)
3405 {
3406 EngSetLastError(ERROR_INVALID_PARAMETER);
3407 RETURN(FALSE);
3408 }
3409
3410 UserRefObjectCo(Window, &Ref);
3411 ret = co_WinPosShowWindow(Window, nCmdShow);
3412 UserDerefObjectCo(Window);
3413
3414 RETURN(ret);
3415
3416 CLEANUP:
3417 TRACE("Leave NtUserShowWindow, ret=%i\n",_ret_);
3418 UserLeave();
3419 END_CLEANUP;
3420 }
3421
3422
3423 /*
3424 * @implemented
3425 */
3426 HWND APIENTRY
3427 NtUserWindowFromPoint(LONG X, LONG Y)
3428 {
3429 POINT pt;
3430 HWND Ret;
3431 PWND DesktopWindow = NULL, Window = NULL;
3432 USHORT hittest;
3433 DECLARE_RETURN(HWND);
3434 USER_REFERENCE_ENTRY Ref;
3435
3436 TRACE("Enter NtUserWindowFromPoint\n");
3437 UserEnterExclusive();
3438
3439 if ((DesktopWindow = UserGetWindowObject(IntGetDesktopWindow())))
3440 {
3441 //PTHREADINFO pti;
3442
3443 pt.x = X;
3444 pt.y = Y;
3445
3446 // Hmm... Threads live on desktops thus we have a reference on the desktop and indirectly the desktop window.
3447 // It is possible this referencing is useless, though it should not hurt...
3448 UserRefObjectCo(DesktopWindow, &Ref);
3449
3450 //pti = PsGetCurrentThreadWin32Thread();
3451 Window = co_WinPosWindowFromPoint(DesktopWindow, &pt, &hittest, FALSE);
3452
3453 if (Window)
3454 {
3455 Ret = UserHMGetHandle(Window);
3456
3457 RETURN( Ret);
3458 }
3459 }
3460
3461 RETURN( NULL);
3462
3463 CLEANUP:
3464 if (Window) UserDereferenceObject(Window);
3465 if (DesktopWindow) UserDerefObjectCo(DesktopWindow);
3466
3467 TRACE("Leave NtUserWindowFromPoint, ret=%p\n", _ret_);
3468 UserLeave();
3469 END_CLEANUP;
3470 }
3471
3472 /* EOF */