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