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