Sync with trunk revision 64099.
[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 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 co_IntSendMessageNoWait(Window->head.h, WM_WINDOWPOSCHANGING, 0, (LPARAM) WinPos);
1262 }
1263
1264 /* Calculate new position and size */
1265
1266 *WindowRect = Window->rcWindow;
1267 *ClientRect = (Window->style & WS_MINIMIZE) ? Window->rcWindow : Window->rcClient;
1268
1269 if (!(WinPos->flags & SWP_NOSIZE))
1270 {
1271 if (Window->style & WS_MINIMIZE)
1272 {
1273 WindowRect->right = WindowRect->left + UserGetSystemMetrics(SM_CXMINIMIZED);
1274 WindowRect->bottom = WindowRect->top + UserGetSystemMetrics(SM_CYMINIMIZED);
1275 }
1276 else
1277 {
1278 WindowRect->right = WindowRect->left + WinPos->cx;
1279 WindowRect->bottom = WindowRect->top + WinPos->cy;
1280 }
1281 }
1282
1283 if (!(WinPos->flags & SWP_NOMOVE))
1284 {
1285 INT X, Y;
1286 PWND Parent;
1287 X = WinPos->x;
1288 Y = WinPos->y;
1289
1290 Parent = Window->spwndParent;
1291
1292 if (((Window->style & WS_CHILD) != 0) &&
1293 Parent &&
1294 Parent != Window->head.rpdesk->pDeskInfo->spwnd)
1295 {
1296 TRACE("Not SWP_NOMOVE 1 Parent client offset X %d Y %d\n",X,Y);
1297 X += Parent->rcClient.left;
1298 Y += Parent->rcClient.top;
1299 TRACE("Not SWP_NOMOVE 2 Parent client offset X %d Y %d\n",X,Y);
1300 }
1301
1302 WindowRect->left = X;
1303 WindowRect->top = Y;
1304 WindowRect->right += X - Window->rcWindow.left;
1305 WindowRect->bottom += Y - Window->rcWindow.top;
1306
1307 RECTL_vOffsetRect(ClientRect, X - Window->rcWindow.left,
1308 Y - Window->rcWindow.top);
1309 }
1310 WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
1311
1312 TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
1313 WinPos->hwnd, WinPos->hwndInsertAfter, WinPos->x, WinPos->y,
1314 WinPos->cx, WinPos->cy, WinPos->flags );
1315 TRACE("WindowRect: %d %d %d %d\n", WindowRect->left,WindowRect->top,WindowRect->right,WindowRect->bottom);
1316 TRACE("ClientRect: %d %d %d %d\n", ClientRect->left,ClientRect->top,ClientRect->right,ClientRect->bottom);
1317
1318 return TRUE;
1319 }
1320
1321 /*
1322 * Fix Z order taking into account owned popups -
1323 * basically we need to maintain them above the window that owns them
1324 *
1325 * FIXME: hide/show owned popups when owner visibility changes.
1326 *
1327 * ReactOS: See bug CORE-6129 and CORE-6554.
1328 *
1329 */
1330 ////
1331 // Pass all the win:test_children/popup_zorder tests except "move hwnd_F and its popups down" which is if'ed out.
1332 // Side effect, breaks more of the DeferWindowPos api tests, but wine breaks more!!!!
1333 static
1334 HWND FASTCALL
1335 WinPosDoOwnedPopups(PWND Window, HWND hWndInsertAfter)
1336 {
1337 HWND *List = NULL;
1338 HWND Owner;
1339 LONG Style;
1340 PWND DesktopWindow, ChildObject;
1341 int i;
1342
1343 TRACE("(%p) hInsertAfter = %p\n", Window, hWndInsertAfter );
1344
1345 Owner = Window->spwndOwner ? Window->spwndOwner->head.h : NULL;
1346 Style = Window->style;
1347
1348 if (Style & WS_CHILD)
1349 {
1350 TRACE("Window is child\n");
1351 return hWndInsertAfter;
1352 }
1353
1354 if (Owner)
1355 {
1356 /* Make sure this popup stays above the owner */
1357
1358 if (hWndInsertAfter != HWND_TOPMOST)
1359 {
1360 DesktopWindow = UserGetDesktopWindow();
1361 List = IntWinListChildren(DesktopWindow);
1362
1363 if (List != NULL)
1364 {
1365 for (i = 0; List[i]; i++)
1366 {
1367 BOOL topmost = FALSE;
1368
1369 ChildObject = ValidateHwndNoErr(List[i]);
1370 if (ChildObject)
1371 {
1372 topmost = (ChildObject->ExStyle & WS_EX_TOPMOST) != 0;
1373 }
1374
1375 if (List[i] == Owner)
1376 {
1377 if (i > 0) hWndInsertAfter = List[i-1];
1378 else hWndInsertAfter = topmost ? HWND_TOPMOST : HWND_TOP;
1379 break;
1380 }
1381
1382 if (hWndInsertAfter == HWND_TOP || hWndInsertAfter == HWND_NOTOPMOST)
1383 {
1384 if (!topmost) break;
1385 }
1386 else if (List[i] == hWndInsertAfter) break;
1387 }
1388 }
1389 else
1390 return hWndInsertAfter;
1391 }
1392 }
1393
1394 if (hWndInsertAfter == HWND_BOTTOM)
1395 {
1396 ERR("Window is HWND_BOTTOM\n");
1397 if (List) ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1398 goto done;
1399 }
1400
1401 if (!List)
1402 {
1403 DesktopWindow = UserGetDesktopWindow();
1404 List = IntWinListChildren(DesktopWindow);
1405 }
1406
1407 if (List != NULL)
1408 {
1409 i = 0;
1410
1411 if (hWndInsertAfter == HWND_TOP || hWndInsertAfter == HWND_NOTOPMOST)
1412 {
1413 if (hWndInsertAfter == HWND_NOTOPMOST || !(Window->ExStyle & WS_EX_TOPMOST))
1414 {
1415 TRACE("skip all the topmost windows\n");
1416 /* skip all the topmost windows */
1417 while (List[i] &&
1418 (ChildObject = ValidateHwndNoErr(List[i])) &&
1419 (ChildObject->ExStyle & WS_EX_TOPMOST)) i++;
1420 }
1421 }
1422 else if (hWndInsertAfter != HWND_TOPMOST)
1423 {
1424 /* skip windows that are already placed correctly */
1425 for (i = 0; List[i]; i++)
1426 {
1427 if (List[i] == hWndInsertAfter) break;
1428 if (List[i] == UserHMGetHandle(Window))
1429 {
1430 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1431 goto done; /* nothing to do if window is moving backwards in z-order */
1432 }
1433 }
1434 }
1435
1436 for (; List[i]; i++)
1437 {
1438 PWND Wnd;
1439 USER_REFERENCE_ENTRY Ref;
1440
1441 if (List[i] == UserHMGetHandle(Window))
1442 break;
1443
1444 if (!(Wnd = ValidateHwndNoErr(List[i])))
1445 continue;
1446
1447 Owner = Wnd->spwndOwner ? Wnd->spwndOwner->head.h : NULL;
1448
1449 if (Owner != UserHMGetHandle(Window)) continue;
1450
1451 UserRefObjectCo(Wnd, &Ref);
1452 TRACE( "moving %p owned by %p after %p\n", List[i], UserHMGetHandle(Window), hWndInsertAfter );
1453 co_WinPosSetWindowPos(Wnd, hWndInsertAfter, 0, 0, 0, 0,
1454 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING| SWP_DEFERERASE);
1455
1456 UserDerefObjectCo(Wnd);
1457 hWndInsertAfter = List[i];
1458 }
1459 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1460 }
1461 done:
1462 return hWndInsertAfter;
1463 }
1464 ////
1465
1466 /***********************************************************************
1467 * WinPosInternalMoveWindow
1468 *
1469 * Update WindowRect and ClientRect of Window and all of its children
1470 * We keep both WindowRect and ClientRect in screen coordinates internally
1471 */
1472 static
1473 VOID FASTCALL
1474 WinPosInternalMoveWindow(PWND Window, INT MoveX, INT MoveY)
1475 {
1476 PWND Child;
1477
1478 ASSERT(Window != Window->spwndChild);
1479 TRACE("InternalMoveWin X %d Y %d\n", MoveX, MoveY);
1480
1481 Window->rcWindow.left += MoveX;
1482 Window->rcWindow.right += MoveX;
1483 Window->rcWindow.top += MoveY;
1484 Window->rcWindow.bottom += MoveY;
1485
1486 Window->rcClient.left += MoveX;
1487 Window->rcClient.right += MoveX;
1488 Window->rcClient.top += MoveY;
1489 Window->rcClient.bottom += MoveY;
1490
1491 for(Child = Window->spwndChild; Child; Child = Child->spwndNext)
1492 {
1493 WinPosInternalMoveWindow(Child, MoveX, MoveY);
1494 }
1495 }
1496
1497 /*
1498 * WinPosFixupSWPFlags
1499 *
1500 * Fix redundant flags and values in the WINDOWPOS structure.
1501 */
1502 static
1503 BOOL FASTCALL
1504 WinPosFixupFlags(WINDOWPOS *WinPos, PWND Wnd)
1505 {
1506 PWND Parent;
1507 POINT pt;
1508
1509 /* Finally make sure that all coordinates are valid */
1510 if (WinPos->x < -32768) WinPos->x = -32768;
1511 else if (WinPos->x > 32767) WinPos->x = 32767;
1512 if (WinPos->y < -32768) WinPos->y = -32768;
1513 else if (WinPos->y > 32767) WinPos->y = 32767;
1514
1515 WinPos->cx = max(WinPos->cx, 0);
1516 WinPos->cy = max(WinPos->cy, 0);
1517
1518 Parent = UserGetAncestor( Wnd, GA_PARENT );
1519 if (!IntIsWindowVisible( Parent )) WinPos->flags |= SWP_NOREDRAW;
1520
1521 if (Wnd->style & WS_VISIBLE) WinPos->flags &= ~SWP_SHOWWINDOW;
1522 else
1523 {
1524 WinPos->flags &= ~SWP_HIDEWINDOW;
1525 if (!(WinPos->flags & SWP_SHOWWINDOW)) WinPos->flags |= SWP_NOREDRAW;
1526 }
1527
1528 /* Check for right size */
1529 if (Wnd->rcWindow.right - Wnd->rcWindow.left == WinPos->cx &&
1530 Wnd->rcWindow.bottom - Wnd->rcWindow.top == WinPos->cy)
1531 {
1532 WinPos->flags |= SWP_NOSIZE;
1533 }
1534
1535 pt.x = WinPos->x;
1536 pt.y = WinPos->y;
1537 IntClientToScreen( Parent, &pt );
1538 TRACE("WPFU C2S wpx %d wpy %d ptx %d pty %d\n",WinPos->x,WinPos->y,pt.x,pt.y);
1539 /* Check for right position */
1540 if (Wnd->rcWindow.left == pt.x && Wnd->rcWindow.top == pt.y)
1541 {
1542 //ERR("In right pos\n");
1543 WinPos->flags |= SWP_NOMOVE;
1544 }
1545
1546 if (WinPos->hwnd == UserGetForegroundWindow())
1547 {
1548 WinPos->flags |= SWP_NOACTIVATE; /* Already active */
1549 }
1550 else
1551 if ((Wnd->style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
1552 {
1553 /* Bring to the top when activating */
1554 if (!(WinPos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)) &&
1555 (WinPos->flags & SWP_NOZORDER ||
1556 (WinPos->hwndInsertAfter != HWND_TOPMOST && WinPos->hwndInsertAfter != HWND_NOTOPMOST)))
1557 {
1558 WinPos->flags &= ~SWP_NOZORDER;
1559 WinPos->hwndInsertAfter = (0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP);
1560 }
1561 }
1562
1563 /* Check hwndInsertAfter */
1564 if (!(WinPos->flags & SWP_NOZORDER))
1565 {
1566 /* Fix sign extension */
1567 if (WinPos->hwndInsertAfter == (HWND)0xffff)
1568 {
1569 WinPos->hwndInsertAfter = HWND_TOPMOST;
1570 }
1571 else if (WinPos->hwndInsertAfter == (HWND)0xfffe)
1572 {
1573 WinPos->hwndInsertAfter = HWND_NOTOPMOST;
1574 }
1575
1576 if (WinPos->hwndInsertAfter == HWND_TOP)
1577 {
1578 /* Keep it topmost when it's already topmost */
1579 if ((Wnd->ExStyle & WS_EX_TOPMOST) != 0)
1580 WinPos->hwndInsertAfter = HWND_TOPMOST;
1581
1582 if (IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd)
1583 WinPos->flags |= SWP_NOZORDER;
1584 }
1585 else if (WinPos->hwndInsertAfter == HWND_BOTTOM)
1586 {
1587 if (!(Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDLAST) == WinPos->hwnd)
1588 WinPos->flags |= SWP_NOZORDER;
1589 }
1590 else if (WinPos->hwndInsertAfter == HWND_TOPMOST)
1591 {
1592 if ((Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd)
1593 WinPos->flags |= SWP_NOZORDER;
1594 }
1595 else if (WinPos->hwndInsertAfter == HWND_NOTOPMOST)
1596 {
1597 if (!(Wnd->ExStyle & WS_EX_TOPMOST))
1598 WinPos->flags |= SWP_NOZORDER;
1599 }
1600 else /* hwndInsertAfter must be a sibling of the window */
1601 {
1602 PWND InsAfterWnd;
1603
1604 InsAfterWnd = ValidateHwndNoErr(WinPos->hwndInsertAfter);
1605 if(!InsAfterWnd)
1606 {
1607 return TRUE;
1608 }
1609
1610 if (InsAfterWnd->spwndParent != Wnd->spwndParent)
1611 {
1612 /* Note from wine User32 Win test_SetWindowPos:
1613 "Returns TRUE also for windows that are not siblings"
1614 "Does not seem to do anything even without passing flags, still returns TRUE"
1615 "Same thing the other way around."
1616 ".. and with these windows."
1617 */
1618 return FALSE;
1619 }
1620 else
1621 {
1622 /*
1623 * We don't need to change the Z order of hwnd if it's already
1624 * inserted after hwndInsertAfter or when inserting hwnd after
1625 * itself.
1626 */
1627 if ((WinPos->hwnd == WinPos->hwndInsertAfter) ||
1628 ((InsAfterWnd->spwndNext) && (WinPos->hwnd == InsAfterWnd->spwndNext->head.h)))
1629 {
1630 WinPos->flags |= SWP_NOZORDER;
1631 }
1632 }
1633 }
1634 }
1635
1636 return TRUE;
1637 }
1638
1639 /* x and y are always screen relative */
1640 BOOLEAN FASTCALL
1641 co_WinPosSetWindowPos(
1642 PWND Window,
1643 HWND WndInsertAfter,
1644 INT x,
1645 INT y,
1646 INT cx,
1647 INT cy,
1648 UINT flags
1649 )
1650 {
1651 WINDOWPOS WinPos;
1652 RECTL NewWindowRect;
1653 RECTL NewClientRect;
1654 RECTL valid_rects[2];
1655 PROSRGNDATA VisRgn;
1656 HRGN VisBefore = NULL;
1657 HRGN VisBeforeJustClient = NULL;
1658 HRGN VisAfter = NULL;
1659 HRGN DirtyRgn = NULL;
1660 HRGN ExposedRgn = NULL;
1661 HRGN CopyRgn = NULL;
1662 ULONG WvrFlags = 0;
1663 RECTL OldWindowRect, OldClientRect;
1664 int RgnType;
1665 HDC Dc;
1666 RECTL CopyRect;
1667 PWND Ancestor;
1668 BOOL bPointerInWindow;
1669
1670 ASSERT_REFS_CO(Window);
1671
1672 /* FIXME: Get current active window from active queue. Why? since r2915. */
1673
1674 bPointerInWindow = IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y);
1675
1676 WinPos.hwnd = Window->head.h;
1677 WinPos.hwndInsertAfter = WndInsertAfter;
1678 WinPos.x = x;
1679 WinPos.y = y;
1680 WinPos.cx = cx;
1681 WinPos.cy = cy;
1682 WinPos.flags = flags;
1683
1684 if ( flags & SWP_ASYNCWINDOWPOS )
1685 {
1686 LRESULT lRes;
1687 PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
1688 if ( ppos )
1689 {
1690 WinPos.flags &= ~SWP_ASYNCWINDOWPOS; // Clear flag.
1691 *ppos = WinPos;
1692 /* Yes it's a pointer inside Win32k! */
1693 lRes = co_IntSendMessageNoWait( WinPos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
1694 /* We handle this the same way as Event Hooks and Hooks. */
1695 if ( !lRes )
1696 {
1697 ExFreePoolWithTag(ppos, USERTAG_SWP);
1698 return FALSE;
1699 }
1700 return TRUE;
1701 }
1702 return FALSE;
1703 }
1704
1705 co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
1706
1707 /* Does the window still exist? */
1708 if (!IntIsWindow(WinPos.hwnd))
1709 {
1710 TRACE("WinPosSetWindowPos: Invalid handle 0x%p!\n",WinPos.hwnd);
1711 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
1712 return FALSE;
1713 }
1714
1715 /* Fix up the flags. */
1716 if (!WinPosFixupFlags(&WinPos, Window))
1717 {
1718 // See Note.
1719 return TRUE;
1720 }
1721
1722 Ancestor = UserGetAncestor(Window, GA_PARENT);
1723 if ( (WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER &&
1724 Ancestor && Ancestor->head.h == IntGetDesktopWindow() )
1725 {
1726 WinPos.hwndInsertAfter = WinPosDoOwnedPopups(Window, WinPos.hwndInsertAfter);
1727 }
1728
1729 if (!(WinPos.flags & SWP_NOREDRAW))
1730 {
1731 /* Compute the visible region before the window position is changed */
1732 if (!(WinPos.flags & SWP_SHOWWINDOW) &&
1733 (WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
1734 SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
1735 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
1736 {
1737 VisBefore = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1738 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1739 VisRgn = NULL;
1740
1741 if ( VisBefore != NULL &&
1742 (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisBefore, NULL)) &&
1743 REGION_Complexity(VisRgn) == NULLREGION )
1744 {
1745 RGNOBJAPI_Unlock(VisRgn);
1746 GreDeleteObject(VisBefore);
1747 VisBefore = NULL;
1748 }
1749 else if(VisRgn)
1750 {
1751 RGNOBJAPI_Unlock(VisRgn);
1752 NtGdiOffsetRgn(VisBefore, -Window->rcWindow.left, -Window->rcWindow.top);
1753 }
1754
1755 /* Calculate the non client area for resizes, as this is used in the copy region */
1756 if (!(WinPos.flags & SWP_NOSIZE))
1757 {
1758 VisBeforeJustClient = VIS_ComputeVisibleRegion(Window, TRUE, FALSE,
1759 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1760 VisRgn = NULL;
1761
1762 if ( VisBeforeJustClient != NULL &&
1763 (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisBeforeJustClient, NULL)) &&
1764 REGION_Complexity(VisRgn) == NULLREGION )
1765 {
1766 RGNOBJAPI_Unlock(VisRgn);
1767 GreDeleteObject(VisBeforeJustClient);
1768 VisBeforeJustClient = NULL;
1769 }
1770 else if(VisRgn)
1771 {
1772 RGNOBJAPI_Unlock(VisRgn);
1773 NtGdiOffsetRgn(VisBeforeJustClient, -Window->rcWindow.left, -Window->rcWindow.top);
1774 }
1775 }
1776 }
1777 }
1778
1779 WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect, valid_rects);
1780
1781 // ERR("co_WinPosDoNCCALCSize returned 0x%x\n valid dest: %d %d %d %d\n valid src : %d %d %d %d\n", WvrFlags,
1782 // valid_rects[0].left,valid_rects[0].top,valid_rects[0].right,valid_rects[0].bottom,
1783 // valid_rects[1].left,valid_rects[1].top,valid_rects[1].right,valid_rects[1].bottom);
1784
1785 /* Validate link windows. (also take into account shell window in hwndShellWindow) */
1786 if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow())
1787 {
1788 IntLinkHwnd(Window, WinPos.hwndInsertAfter);
1789 }
1790
1791 OldWindowRect = Window->rcWindow;
1792 OldClientRect = Window->rcClient;
1793
1794 if (NewClientRect.left != OldClientRect.left ||
1795 NewClientRect.top != OldClientRect.top)
1796 {
1797 // Move child window if their parent is moved. Keep Child window relative to Parent...
1798 WinPosInternalMoveWindow(Window,
1799 NewClientRect.left - OldClientRect.left,
1800 NewClientRect.top - OldClientRect.top);
1801 }
1802
1803 Window->rcWindow = NewWindowRect;
1804 Window->rcClient = NewClientRect;
1805
1806 /* erase parent when hiding or resizing child */
1807 if (WinPos.flags & SWP_HIDEWINDOW)
1808 {
1809 /* Clear the update region */
1810 co_UserRedrawWindow( Window,
1811 NULL,
1812 0,
1813 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
1814
1815 if (Window->spwndParent == UserGetDesktopWindow())
1816 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM)Window->head.h, 0);
1817
1818 Window->style &= ~WS_VISIBLE; //IntSetStyle( Window, 0, WS_VISIBLE );
1819 Window->head.pti->cVisWindows--;
1820 IntNotifyWinEvent(EVENT_OBJECT_HIDE, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1821 }
1822 else if (WinPos.flags & SWP_SHOWWINDOW)
1823 {
1824 if (Window->spwndParent == UserGetDesktopWindow())
1825 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)Window->head.h, 0);
1826
1827 Window->style |= WS_VISIBLE; //IntSetStyle( Window, WS_VISIBLE, 0 );
1828 Window->head.pti->cVisWindows++;
1829 IntNotifyWinEvent(EVENT_OBJECT_SHOW, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1830 }
1831
1832 if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != HRGN_WINDOW)
1833 {
1834 NtGdiOffsetRgn(Window->hrgnUpdate,
1835 NewWindowRect.left - OldWindowRect.left,
1836 NewWindowRect.top - OldWindowRect.top);
1837 }
1838
1839 DceResetActiveDCEs(Window); // For WS_VISIBLE changes.
1840
1841 if (!(WinPos.flags & SWP_NOREDRAW))
1842 {
1843 /* Determine the new visible region */
1844 VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1845 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1846 VisRgn = NULL;
1847
1848 if ( VisAfter != NULL &&
1849 (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisAfter, NULL)) &&
1850 REGION_Complexity(VisRgn) == NULLREGION )
1851 {
1852 RGNOBJAPI_Unlock(VisRgn);
1853 GreDeleteObject(VisAfter);
1854 VisAfter = NULL;
1855 }
1856 else if(VisRgn)
1857 {
1858 RGNOBJAPI_Unlock(VisRgn);
1859 NtGdiOffsetRgn(VisAfter, -Window->rcWindow.left, -Window->rcWindow.top);
1860 }
1861
1862 /*
1863 * Determine which pixels can be copied from the old window position
1864 * to the new. Those pixels must be visible in both the old and new
1865 * position. Also, check the class style to see if the windows of this
1866 * class need to be completely repainted on (horizontal/vertical) size
1867 * change.
1868 */
1869 if ( VisBefore != NULL &&
1870 VisAfter != NULL &&
1871 !(WinPos.flags & SWP_NOCOPYBITS) &&
1872 ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) &&
1873 !(Window->ExStyle & WS_EX_TRANSPARENT) )
1874 {
1875
1876 /*
1877 * If this is (also) a window resize, the whole nonclient area
1878 * needs to be repainted. So we limit the copy to the client area,
1879 * 'cause there is no use in copying it (would possibly cause
1880 * "flashing" too). However, if the copy region is already empty,
1881 * we don't have to crop (can't take anything away from an empty
1882 * region...)
1883 */
1884
1885 CopyRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1886 if (WinPos.flags & SWP_NOSIZE)
1887 RgnType = NtGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
1888 else if (VisBeforeJustClient != NULL)
1889 {
1890 RgnType = NtGdiCombineRgn(CopyRgn, VisAfter, VisBeforeJustClient, RGN_AND);
1891 GreDeleteObject(VisBeforeJustClient);
1892 }
1893
1894 /* No use in copying bits which are in the update region. */
1895 if (Window->hrgnUpdate != NULL)
1896 {
1897 NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1898 NtGdiCombineRgn(CopyRgn, CopyRgn, Window->hrgnUpdate, RGN_DIFF);
1899 NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1900 }
1901
1902 /*
1903 * Now, get the bounding box of the copy region. If it's empty
1904 * there's nothing to copy. Also, it's no use copying bits onto
1905 * themselves.
1906 */
1907 if ( (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(CopyRgn, NULL)) &&
1908 REGION_GetRgnBox(VisRgn, &CopyRect) == NULLREGION)
1909 {
1910 /* Nothing to copy, clean up */
1911 RGNOBJAPI_Unlock(VisRgn);
1912 GreDeleteObject(CopyRgn);
1913 CopyRgn = NULL;
1914 }
1915 else if (OldWindowRect.left != NewWindowRect.left ||
1916 OldWindowRect.top != NewWindowRect.top)
1917 {
1918 if(VisRgn)
1919 {
1920 RGNOBJAPI_Unlock(VisRgn);
1921 }
1922
1923 /*
1924 * Small trick here: there is no function to bitblt a region. So
1925 * we set the region as the clipping region, take the bounding box
1926 * of the region and bitblt that. Since nothing outside the clipping
1927 * region is copied, this has the effect of bitblt'ing the region.
1928 *
1929 * Since NtUserGetDCEx takes ownership of the clip region, we need
1930 * to create a copy of CopyRgn and pass that. We need CopyRgn later
1931 */
1932 NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1933 Dc = UserGetDCEx( Window,
1934 CopyRgn,
1935 DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN);
1936 NtGdiBitBlt( Dc,
1937 CopyRect.left, CopyRect.top,
1938 CopyRect.right - CopyRect.left,
1939 CopyRect.bottom - CopyRect.top,
1940 Dc,
1941 CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
1942 CopyRect.top + (OldWindowRect.top - NewWindowRect.top),
1943 SRCCOPY,
1944 0,
1945 0);
1946
1947 UserReleaseDC(Window, Dc, FALSE);
1948 IntValidateParent(Window, CopyRgn, FALSE);
1949 NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1950 }
1951 else if(VisRgn)
1952 {
1953 RGNOBJAPI_Unlock(VisRgn);
1954 }
1955 }
1956 else
1957 {
1958 CopyRgn = NULL;
1959 }
1960
1961 /* We need to redraw what wasn't visible before */
1962 if (VisAfter != NULL)
1963 {
1964 DirtyRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1965 if (CopyRgn != NULL)
1966 {
1967 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
1968 }
1969 else
1970 {
1971 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
1972 }
1973 if (RgnType != ERROR && RgnType != NULLREGION)
1974 {
1975 /* old code
1976 NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
1977 IntInvalidateWindows( Window,
1978 DirtyRgn,
1979 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
1980 }
1981 GreDeleteObject(DirtyRgn);
1982 */
1983
1984 PWND Parent = Window->spwndParent;
1985
1986 NtGdiOffsetRgn( DirtyRgn,
1987 Window->rcWindow.left,
1988 Window->rcWindow.top);
1989 if ( (Window->style & WS_CHILD) &&
1990 (Parent) &&
1991 !(Parent->style & WS_CLIPCHILDREN))
1992 {
1993 IntInvalidateWindows( Parent,
1994 DirtyRgn,
1995 RDW_ERASE | RDW_INVALIDATE);
1996 co_IntPaintWindows(Parent, RDW_ERASENOW, FALSE);
1997 }
1998 else
1999 {
2000 IntInvalidateWindows( Window,
2001 DirtyRgn,
2002 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2003 }
2004 }
2005 GreDeleteObject(DirtyRgn);
2006 }
2007
2008 if (CopyRgn != NULL)
2009 {
2010 GreDeleteObject(CopyRgn);
2011 }
2012
2013 /* Expose what was covered before but not covered anymore */
2014 if (VisBefore != NULL)
2015 {
2016 ExposedRgn = IntSysCreateRectRgn(0, 0, 0, 0);
2017 RgnType = NtGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
2018 NtGdiOffsetRgn( ExposedRgn,
2019 OldWindowRect.left - NewWindowRect.left,
2020 OldWindowRect.top - NewWindowRect.top);
2021
2022 if (VisAfter != NULL)
2023 RgnType = NtGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
2024
2025 if (RgnType != ERROR && RgnType != NULLREGION)
2026 {
2027 co_VIS_WindowLayoutChanged(Window, ExposedRgn);
2028 }
2029 GreDeleteObject(ExposedRgn);
2030 GreDeleteObject(VisBefore);
2031 }
2032
2033 if (VisAfter != NULL)
2034 {
2035 GreDeleteObject(VisAfter);
2036 }
2037 }
2038
2039 if (!(WinPos.flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
2040 {
2041 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2042 {
2043 co_IntSendMessageNoWait(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
2044 }
2045 else
2046 {
2047 //ERR("SetWindowPos Set FG Window!\n");
2048 if (Window->state & WNDS_BEINGACTIVATED) // Inside SAW?
2049 co_IntSetActiveWindow(Window, FALSE, TRUE, FALSE); // Fixes Api AttachThreadInput tests.
2050 else
2051 co_IntSetForegroundWindow(Window); // Fixes SW_HIDE issues. Wine win test_SetActiveWindow & test_SetForegroundWindow.
2052 }
2053 }
2054
2055 /* And last, send the WM_WINDOWPOSCHANGED message */
2056
2057 TRACE("\tstatus flags = %04x\n", WinPos.flags & SWP_AGG_STATUSFLAGS);
2058
2059 if ((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2060 {
2061 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
2062 and always contains final window position.
2063 */
2064 WinPos.x = NewWindowRect.left;
2065 WinPos.y = NewWindowRect.top;
2066 WinPos.cx = NewWindowRect.right - NewWindowRect.left;
2067 WinPos.cy = NewWindowRect.bottom - NewWindowRect.top;
2068 co_IntSendMessageNoWait(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
2069 }
2070
2071 if ( WinPos.flags & SWP_FRAMECHANGED || WinPos.flags & SWP_STATECHANGED ||
2072 !(WinPos.flags & SWP_NOCLIENTSIZE) || !(WinPos.flags & SWP_NOCLIENTMOVE) )
2073 {
2074 PWND pWnd = ValidateHwndNoErr(WinPos.hwnd);
2075 if (pWnd)
2076 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2077 }
2078
2079 if(bPointerInWindow != IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y))
2080 {
2081 /* Generate mouse move message */
2082 MSG msg;
2083 msg.message = WM_MOUSEMOVE;
2084 msg.wParam = UserGetMouseButtonsState();
2085 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2086 msg.pt = gpsi->ptCursor;
2087 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2088 }
2089
2090 return TRUE;
2091 }
2092
2093 LRESULT FASTCALL
2094 co_WinPosGetNonClientSize(PWND Window, RECT* WindowRect, RECT* ClientRect)
2095 {
2096 LRESULT Result;
2097
2098 ASSERT_REFS_CO(Window);
2099
2100 *ClientRect = *WindowRect;
2101 Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect);
2102
2103 FixClientRect(ClientRect, WindowRect);
2104
2105 return Result;
2106 }
2107
2108 void FASTCALL
2109 co_WinPosSendSizeMove(PWND Wnd)
2110 {
2111 RECTL Rect;
2112 LPARAM lParam;
2113 WPARAM wParam = SIZE_RESTORED;
2114
2115 IntGetClientRect(Wnd, &Rect);
2116 lParam = MAKELONG(Rect.right-Rect.left, Rect.bottom-Rect.top);
2117
2118 Wnd->state &= ~WNDS_SENDSIZEMOVEMSGS;
2119
2120 if (Wnd->style & WS_MAXIMIZE)
2121 {
2122 wParam = SIZE_MAXIMIZED;
2123 }
2124 else if (Wnd->style & WS_MINIMIZE)
2125 {
2126 wParam = SIZE_MINIMIZED;
2127 lParam = 0;
2128 }
2129
2130 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SIZE, wParam, lParam);
2131
2132 if (Wnd->spwndParent == UserGetDesktopWindow()) // Wnd->spwndParent->fnid == FNID_DESKTOP )
2133 lParam = MAKELONG(Wnd->rcClient.left, Wnd->rcClient.top);
2134 else
2135 lParam = MAKELONG(Wnd->rcClient.left-Wnd->spwndParent->rcClient.left, Wnd->rcClient.top-Wnd->spwndParent->rcClient.top);
2136
2137 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_MOVE, 0, lParam);
2138
2139 IntEngWindowChanged(Wnd, WOC_RGN_CLIENT);
2140 }
2141
2142 BOOLEAN FASTCALL
2143 co_WinPosShowWindow(PWND Wnd, INT Cmd)
2144 {
2145 BOOLEAN WasVisible;
2146 UINT Swp = 0, EventMsg = 0;
2147 RECTL NewPos = {0, 0, 0, 0};
2148 BOOLEAN ShowFlag;
2149 LONG style;
2150 PWND Parent;
2151 PTHREADINFO pti;
2152 //HRGN VisibleRgn;
2153 BOOL ShowOwned = FALSE;
2154 ASSERT_REFS_CO(Wnd);
2155 //ERR("co_WinPosShowWindow START\n");
2156
2157 pti = PsGetCurrentThreadWin32Thread();
2158 WasVisible = (Wnd->style & WS_VISIBLE) != 0;
2159 style = Wnd->style;
2160
2161 switch (Cmd)
2162 {
2163 case SW_HIDE:
2164 {
2165 if (!WasVisible)
2166 {
2167 //ERR("co_WinPosShowWindow Exit Bad\n");
2168 return(FALSE);
2169 }
2170 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2171 if (Wnd != pti->MessageQueue->spwndActive)
2172 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2173 break;
2174 }
2175
2176 case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
2177 case SW_SHOWMINNOACTIVE:
2178 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2179 /* Fall through. */
2180 case SW_SHOWMINIMIZED:
2181 Swp |= SWP_SHOWWINDOW;
2182 /* Fall through. */
2183 case SW_MINIMIZE:
2184 {
2185 Swp |= SWP_NOACTIVATE;
2186 if (!(style & WS_MINIMIZE))
2187 {
2188 IntShowOwnedPopups(Wnd, FALSE );
2189
2190 // Fix wine Win test_SetFocus todo #1 & #2,
2191 if (Cmd == SW_SHOWMINIMIZED)
2192 {
2193 //ERR("co_WinPosShowWindow Set focus 1\n");
2194 if ((style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2195 co_UserSetFocus(Wnd->spwndParent);
2196 else
2197 co_UserSetFocus(0);
2198 }
2199
2200 Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos) |
2201 SWP_FRAMECHANGED;
2202
2203 EventMsg = EVENT_SYSTEM_MINIMIZESTART;
2204 }
2205 else
2206 {
2207 if (!WasVisible)
2208 {
2209 Swp |= SWP_FRAMECHANGED;
2210 }
2211 else ////
2212 {
2213 //ERR("co_WinPosShowWindow Exit Good\n");
2214 return TRUE;
2215 }
2216 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2217 }
2218 break;
2219 }
2220
2221 case SW_SHOWMAXIMIZED:
2222 {
2223 Swp |= SWP_SHOWWINDOW;
2224 if (!(style & WS_MAXIMIZE))
2225 {
2226 ShowOwned = TRUE;
2227
2228 Swp |= co_WinPosMinMaximize(Wnd, SW_MAXIMIZE, &NewPos) |
2229 SWP_FRAMECHANGED;
2230
2231 EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2232 }
2233 else
2234 {
2235 if (!WasVisible)
2236 {
2237 Swp |= SWP_FRAMECHANGED;
2238 }
2239 else ////
2240 {
2241 //ERR("co_WinPosShowWindow Exit Good 1\n");
2242 return TRUE;
2243 }
2244 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2245 }
2246 break;
2247 }
2248
2249 case SW_SHOWNA:
2250 Swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2251 if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOZORDER;
2252 break;
2253 case SW_SHOW:
2254 if (WasVisible) return(TRUE); // Nothing to do!
2255 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2256 /* Don't activate the topmost window. */
2257 if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2258 break;
2259
2260 case SW_SHOWNOACTIVATE:
2261 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2262 /* Fall through. */
2263 case SW_SHOWNORMAL:
2264 case SW_SHOWDEFAULT:
2265 case SW_RESTORE:
2266 if (!WasVisible) Swp |= SWP_SHOWWINDOW;
2267 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2268 {
2269 Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos) |
2270 SWP_FRAMECHANGED;
2271
2272 if (style & WS_MINIMIZE) EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2273 }
2274 else
2275 {
2276 if (!WasVisible)
2277 {
2278 Swp |= SWP_FRAMECHANGED;
2279 }
2280 else ////
2281 {
2282 //ERR("co_WinPosShowWindow Exit Good 3\n");
2283 return TRUE;
2284 }
2285 Swp |= SWP_NOSIZE | SWP_NOMOVE;
2286 }
2287 if ( style & WS_CHILD &&
2288 !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2289 !(Swp & SWP_STATECHANGED))
2290 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2291 break;
2292
2293 default:
2294 //ERR("co_WinPosShowWindow Exit Good 4\n");
2295 return WasVisible;
2296 }
2297
2298 ShowFlag = (Cmd != SW_HIDE);
2299
2300 if ((ShowFlag != WasVisible || Cmd == SW_SHOWNA) && Cmd != SW_SHOWMAXIMIZED && !(Swp & SWP_STATECHANGED))
2301 {
2302 co_IntSendMessageNoWait(Wnd->head.h, WM_SHOWWINDOW, ShowFlag, 0);
2303 if (!(Wnd->state2 & WNDS2_WIN31COMPAT))
2304 co_IntSendMessageNoWait(Wnd->head.h, WM_SETVISIBLE, ShowFlag, 0);
2305 if (!VerifyWnd(Wnd)) return WasVisible;
2306 }
2307
2308 /* We can't activate a child window */
2309 if ((Wnd->style & WS_CHILD) &&
2310 !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2311 Cmd != SW_SHOWNA)
2312 {
2313 //ERR("SWP Child No active and ZOrder\n");
2314 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2315 }
2316
2317 #if 0 // Explorer issues with common controls? Someone does not know how CS_SAVEBITS works.
2318 // Breaks startup and shutdown active window...
2319 if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
2320 Wnd->pcls->style & CS_SAVEBITS &&
2321 ((Cmd == SW_SHOW) || (Cmd == SW_NORMAL)))
2322 {
2323 ERR("WinPosShowWindow Set active\n");
2324 UserSetActiveWindow(Wnd);
2325 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2326 }
2327 #endif
2328
2329 if (IsChildVisible(Wnd) || Swp & SWP_STATECHANGED)
2330 {
2331 TRACE("Child is Vis %s or State changed %s. ShowFlag %s\n",
2332 (IsChildVisible(Wnd) ? "TRUE" : "FALSE"), (Swp & SWP_STATECHANGED ? "TRUE" : "FALSE"),
2333 (ShowFlag ? "TRUE" : "FALSE"));
2334 co_WinPosSetWindowPos( Wnd,
2335 0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP,
2336 NewPos.left,
2337 NewPos.top,
2338 NewPos.right, //NewPos.right - NewPos.left,
2339 NewPos.bottom, //NewPos.bottom - NewPos.top,
2340 LOWORD(Swp));
2341 }
2342 else
2343 {
2344 TRACE("Parent Vis?\n");
2345 /* if parent is not visible simply toggle WS_VISIBLE and return */
2346 if (ShowFlag) IntSetStyle( Wnd, WS_VISIBLE, 0 );
2347 else IntSetStyle( Wnd, 0, WS_VISIBLE );
2348 }
2349
2350 if ( EventMsg ) IntNotifyWinEvent(EventMsg, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2351
2352 if ( ShowOwned ) IntShowOwnedPopups(Wnd, TRUE );
2353
2354 if ((Cmd == SW_HIDE) || (Cmd == SW_MINIMIZE))
2355 {
2356 if ( Wnd == pti->MessageQueue->spwndActive && pti->MessageQueue == IntGetFocusMessageQueue() )
2357 {
2358 if ( Wnd->spwndParent == UserGetDesktopWindow())
2359 {
2360 if(!ActivateOtherWindowMin(Wnd))
2361 co_WinPosActivateOtherWindow(Wnd);
2362 }
2363 else
2364 co_WinPosActivateOtherWindow(Wnd);
2365 }
2366
2367 /* Revert focus to parent */
2368 if (Wnd == pti->MessageQueue->spwndFocus)
2369 {
2370 Parent = Wnd->spwndParent;
2371 if (Wnd->spwndParent == UserGetDesktopWindow()) Parent = 0;
2372 co_UserSetFocus(Parent);
2373 }
2374 }
2375
2376 /* FIXME: Check for window destruction. */
2377
2378 if ((Wnd->state & WNDS_SENDSIZEMOVEMSGS) &&
2379 !(Wnd->state2 & WNDS2_INDESTROY))
2380 {
2381 co_WinPosSendSizeMove(Wnd);
2382 }
2383
2384 /* if previous state was minimized Windows sets focus to the window */
2385 if (style & WS_MINIMIZE)
2386 {
2387 co_UserSetFocus(Wnd);
2388 // Fix wine Win test_SetFocus todo #3,
2389 if (!(style & WS_CHILD)) co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_ACTIVATE, WA_ACTIVE, 0);
2390 }
2391 //ERR("co_WinPosShowWindow EXIT\n");
2392 return(WasVisible);
2393 }
2394
2395 static
2396 PWND FASTCALL
2397 co_WinPosSearchChildren(
2398 PWND ScopeWin,
2399 POINT *Point,
2400 USHORT *HitTest,
2401 BOOL Ignore
2402 )
2403 {
2404 PWND pwndChild;
2405 HWND *List, *phWnd;
2406
2407 if (!(ScopeWin->style & WS_VISIBLE))
2408 {
2409 return NULL;
2410 }
2411
2412 if (!Ignore && (ScopeWin->style & WS_DISABLED))
2413 {
2414 return NULL;
2415 }
2416
2417 if (!IntPtInWindow(ScopeWin, Point->x, Point->y))
2418 {
2419 return NULL;
2420 }
2421
2422 UserReferenceObject(ScopeWin);
2423
2424 if ( RECTL_bPointInRect(&ScopeWin->rcClient, Point->x, Point->y) )
2425 {
2426 List = IntWinListChildren(ScopeWin);
2427 if(List)
2428 {
2429 for (phWnd = List; *phWnd; ++phWnd)
2430 {
2431 if (!(pwndChild = ValidateHwndNoErr(*phWnd)))
2432 {
2433 continue;
2434 }
2435
2436 pwndChild = co_WinPosSearchChildren(pwndChild, Point, HitTest, Ignore);
2437
2438 if(pwndChild != NULL)
2439 {
2440 /* We found a window. Don't send any more WM_NCHITTEST messages */
2441 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2442 UserDereferenceObject(ScopeWin);
2443 return pwndChild;
2444 }
2445 }
2446 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2447 }
2448 }
2449
2450 if (ScopeWin->head.pti == PsGetCurrentThreadWin32Thread())
2451 {
2452 *HitTest = (USHORT)co_IntSendMessage(ScopeWin->head.h, WM_NCHITTEST, 0,
2453 MAKELONG(Point->x, Point->y));
2454 if ((*HitTest) == (USHORT)HTTRANSPARENT)
2455 {
2456 UserDereferenceObject(ScopeWin);
2457 return NULL;
2458 }
2459 }
2460 else
2461 *HitTest = HTCLIENT;
2462
2463 return ScopeWin;
2464 }
2465
2466 PWND FASTCALL
2467 co_WinPosWindowFromPoint(PWND ScopeWin, POINT *WinPoint, USHORT* HitTest, BOOL Ignore)
2468 {
2469 PWND Window;
2470 POINT Point = *WinPoint;
2471 USER_REFERENCE_ENTRY Ref;
2472
2473 if( ScopeWin == NULL )
2474 {
2475 ScopeWin = UserGetDesktopWindow();
2476 if(ScopeWin == NULL)
2477 return NULL;
2478 }
2479
2480 *HitTest = HTNOWHERE;
2481
2482 ASSERT_REFS_CO(ScopeWin);
2483 UserRefObjectCo(ScopeWin, &Ref);
2484
2485 Window = co_WinPosSearchChildren(ScopeWin, &Point, HitTest, Ignore);
2486
2487 UserDerefObjectCo(ScopeWin);
2488 if (Window)
2489 ASSERT_REFS_CO(Window);
2490 ASSERT_REFS_CO(ScopeWin);
2491
2492 return Window;
2493 }
2494
2495 PWND FASTCALL
2496 IntRealChildWindowFromPoint(PWND Parent, LONG x, LONG y)
2497 {
2498 POINTL Pt;
2499 HWND *List, *phWnd;
2500 PWND pwndHit = NULL;
2501
2502 Pt.x = x;
2503 Pt.y = y;
2504
2505 if (Parent != UserGetDesktopWindow())
2506 {
2507 Pt.x += Parent->rcClient.left;
2508 Pt.y += Parent->rcClient.top;
2509 }
2510
2511 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2512
2513 if ((List = IntWinListChildren(Parent)))
2514 {
2515 for (phWnd = List; *phWnd; phWnd++)
2516 {
2517 PWND Child;
2518 if ((Child = ValidateHwndNoErr(*phWnd)))
2519 {
2520 if ( Child->style & WS_VISIBLE && IntPtInWindow(Child, Pt.x, Pt.y) )
2521 {
2522 if ( Child->pcls->atomClassName != gpsi->atomSysClass[ICLS_BUTTON] ||
2523 (Child->style & BS_TYPEMASK) != BS_GROUPBOX )
2524 {
2525 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2526 return Child;
2527 }
2528 pwndHit = Child;
2529 }
2530 }
2531 }
2532 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2533 }
2534 return pwndHit ? pwndHit : Parent;
2535 }
2536
2537 PWND APIENTRY
2538 IntChildWindowFromPointEx(PWND Parent, LONG x, LONG y, UINT uiFlags)
2539 {
2540 POINTL Pt;
2541 HWND *List, *phWnd;
2542 PWND pwndHit = NULL;
2543
2544 Pt.x = x;
2545 Pt.y = y;
2546
2547 if (Parent != UserGetDesktopWindow())
2548 {
2549 if (Parent->ExStyle & WS_EX_LAYOUTRTL)
2550 Pt.x = Parent->rcClient.right - Pt.x;
2551 else
2552 Pt.x += Parent->rcClient.left;
2553 Pt.y += Parent->rcClient.top;
2554 }
2555
2556 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2557
2558 if ((List = IntWinListChildren(Parent)))
2559 {
2560 for (phWnd = List; *phWnd; phWnd++)
2561 {
2562 PWND Child;
2563 if ((Child = ValidateHwndNoErr(*phWnd)))
2564 {
2565 if (uiFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
2566 {
2567 if (!(Child->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE)) continue;
2568 if ((Child->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED)) continue;
2569 }
2570
2571 if (uiFlags & CWP_SKIPTRANSPARENT)
2572 {
2573 if (Child->ExStyle & WS_EX_TRANSPARENT) continue;
2574 }
2575
2576 if (IntPtInWindow(Child, Pt.x, Pt.y))
2577 {
2578 pwndHit = Child;
2579 break;
2580 }
2581 }
2582 }
2583 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2584 }
2585 return pwndHit ? pwndHit : Parent;
2586 }
2587
2588 HDWP
2589 FASTCALL
2590 IntDeferWindowPos( HDWP hdwp,
2591 HWND hwnd,
2592 HWND hwndAfter,
2593 INT x,
2594 INT y,
2595 INT cx,
2596 INT cy,
2597 UINT flags )
2598 {
2599 PSMWP pDWP;
2600 int i;
2601 HDWP retvalue = hdwp;
2602
2603 TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2604 hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
2605
2606 if (flags & ~(SWP_NOSIZE | SWP_NOMOVE |
2607 SWP_NOZORDER | SWP_NOREDRAW |
2608 SWP_NOACTIVATE | SWP_NOCOPYBITS |
2609 SWP_NOOWNERZORDER|SWP_SHOWWINDOW |
2610 SWP_HIDEWINDOW | SWP_FRAMECHANGED))
2611 {
2612 EngSetLastError(ERROR_INVALID_PARAMETER);
2613 return NULL;
2614 }
2615
2616 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
2617 {
2618 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
2619 return NULL;
2620 }
2621
2622 for (i = 0; i < pDWP->ccvr; i++)
2623 {
2624 if (pDWP->acvr[i].pos.hwnd == hwnd)
2625 {
2626 /* Merge with the other changes */
2627 if (!(flags & SWP_NOZORDER))
2628 {
2629 pDWP->acvr[i].pos.hwndInsertAfter = hwndAfter;
2630 }
2631 if (!(flags & SWP_NOMOVE))
2632 {
2633 pDWP->acvr[i].pos.x = x;
2634 pDWP->acvr[i].pos.y = y;
2635 }
2636 if (!(flags & SWP_NOSIZE))
2637 {
2638 pDWP->acvr[i].pos.cx = cx;
2639 pDWP->acvr[i].pos.cy = cy;
2640 }
2641 pDWP->acvr[i].pos.flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
2642 SWP_NOZORDER | SWP_NOREDRAW |
2643 SWP_NOACTIVATE | SWP_NOCOPYBITS|
2644 SWP_NOOWNERZORDER);
2645 pDWP->acvr[i].pos.flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
2646 SWP_FRAMECHANGED);
2647 goto END;
2648 }
2649 }
2650 if (pDWP->ccvr >= pDWP->ccvrAlloc)
2651 {
2652 PCVR newpos = ExAllocatePoolWithTag(PagedPool, pDWP->ccvrAlloc * 2 * sizeof(CVR), USERTAG_SWP);
2653 if (!newpos)
2654 {
2655 retvalue = NULL;
2656 goto END;
2657 }
2658 RtlZeroMemory(newpos, pDWP->ccvrAlloc * 2 * sizeof(CVR));
2659 RtlCopyMemory(newpos, pDWP->acvr, pDWP->ccvrAlloc * sizeof(CVR));
2660 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
2661 pDWP->ccvrAlloc *= 2;
2662 pDWP->acvr = newpos;
2663 }
2664 pDWP->acvr[pDWP->ccvr].pos.hwnd = hwnd;
2665 pDWP->acvr[pDWP->ccvr].pos.hwndInsertAfter = hwndAfter;
2666 pDWP->acvr[pDWP->ccvr].pos.x = x;
2667 pDWP->acvr[pDWP->ccvr].pos.y = y;
2668 pDWP->acvr[pDWP->ccvr].pos.cx = cx;
2669 pDWP->acvr[pDWP->ccvr].pos.cy = cy;
2670 pDWP->acvr[pDWP->ccvr].pos.flags = flags;
2671 pDWP->acvr[pDWP->ccvr].hrgnClip = NULL;
2672 pDWP->acvr[pDWP->ccvr].hrgnInterMonitor = NULL;
2673 pDWP->ccvr++;
2674 END:
2675 return retvalue;
2676 }
2677
2678 BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp, BOOL sAsync )
2679 {
2680 PSMWP pDWP;
2681 PCVR winpos;
2682 BOOL res = TRUE;
2683 int i;
2684
2685 TRACE("%p\n", hdwp);
2686
2687 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
2688 {
2689 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
2690 return FALSE;
2691 }
2692
2693 for (i = 0, winpos = pDWP->acvr; res && i < pDWP->ccvr; i++, winpos++)
2694 {
2695 PWND pwnd;
2696 USER_REFERENCE_ENTRY Ref;
2697
2698 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2699 winpos->pos.hwnd, winpos->pos.hwndInsertAfter, winpos->pos.x, winpos->pos.y,
2700 winpos->pos.cx, winpos->pos.cy, winpos->pos.flags);
2701
2702 pwnd = ValidateHwndNoErr(winpos->pos.hwnd);
2703 if (!pwnd)
2704 continue;
2705
2706 UserRefObjectCo(pwnd, &Ref);
2707
2708 if ( sAsync )
2709 {
2710 LRESULT lRes;
2711 PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
2712 if ( ppos )
2713 {
2714 *ppos = winpos->pos;
2715 /* Yes it's a pointer inside Win32k! */
2716 lRes = co_IntSendMessageNoWait( winpos->pos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
2717 /* We handle this the same way as Event Hooks and Hooks. */
2718 if ( !lRes )
2719 {
2720 ExFreePoolWithTag(ppos, USERTAG_SWP);
2721 }
2722 }
2723 }
2724 else
2725 res = co_WinPosSetWindowPos( pwnd,
2726 winpos->pos.hwndInsertAfter,
2727 winpos->pos.x,
2728 winpos->pos.y,
2729 winpos->pos.cx,
2730 winpos->pos.cy,
2731 winpos->pos.flags);
2732
2733 // Hack to pass tests.... Must have some work to do so clear the error.
2734 if (res && (winpos->pos.flags & (SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER)) == SWP_NOZORDER )
2735 EngSetLastError(ERROR_SUCCESS);
2736
2737 UserDerefObjectCo(pwnd);
2738 }
2739 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
2740 UserDereferenceObject(pDWP);
2741 UserDeleteObject(hdwp, TYPE_SETWINDOWPOS);
2742 return res;
2743 }
2744
2745 /*
2746 * @implemented
2747 */
2748 HWND APIENTRY
2749 NtUserChildWindowFromPointEx(HWND hwndParent,
2750 LONG x,
2751 LONG y,
2752 UINT uiFlags)
2753 {
2754 PWND pwndParent;
2755 TRACE("Enter NtUserChildWindowFromPointEx\n");
2756 UserEnterExclusive();
2757 if ((pwndParent = UserGetWindowObject(hwndParent)))
2758 {
2759 pwndParent = IntChildWindowFromPointEx(pwndParent, x, y, uiFlags);
2760 }
2761 UserLeave();
2762 TRACE("Leave NtUserChildWindowFromPointEx\n");
2763 return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
2764 }
2765
2766 /*
2767 * @implemented
2768 */
2769 BOOL APIENTRY
2770 NtUserEndDeferWindowPosEx(HDWP WinPosInfo,
2771 DWORD Unknown1)
2772 {
2773 BOOL Ret;
2774 TRACE("Enter NtUserEndDeferWindowPosEx\n");
2775 UserEnterExclusive();
2776 Ret = IntEndDeferWindowPosEx(WinPosInfo, (BOOL)Unknown1);
2777 TRACE("Leave NtUserEndDeferWindowPosEx, ret=%i\n", Ret);
2778 UserLeave();
2779 return Ret;
2780 }
2781
2782 /*
2783 * @implemented
2784 */
2785 HDWP APIENTRY
2786 NtUserDeferWindowPos(HDWP WinPosInfo,
2787 HWND Wnd,
2788 HWND WndInsertAfter,
2789 int x,
2790 int y,
2791 int cx,
2792 int cy,
2793 UINT Flags)
2794 {
2795 PWND pWnd, pWndIA;
2796 HDWP Ret = NULL;
2797 UINT Tmp = ~(SWP_ASYNCWINDOWPOS|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_NOREPOSITION|
2798 SWP_NOCOPYBITS|SWP_HIDEWINDOW|SWP_SHOWWINDOW|SWP_FRAMECHANGED|
2799 SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE);
2800
2801 TRACE("Enter NtUserDeferWindowPos\n");
2802 UserEnterExclusive();
2803
2804 if ( Flags & Tmp )
2805 {
2806 EngSetLastError(ERROR_INVALID_FLAGS);
2807 goto Exit;
2808 }
2809
2810 pWnd = UserGetWindowObject(Wnd);
2811 if ( !pWnd || // FIXME:
2812 pWnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2813 pWnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2814 {
2815 goto Exit;
2816 }
2817
2818 if ( WndInsertAfter &&
2819 WndInsertAfter != HWND_BOTTOM &&
2820 WndInsertAfter != HWND_TOPMOST &&
2821 WndInsertAfter != HWND_NOTOPMOST )
2822 {
2823 pWndIA = UserGetWindowObject(WndInsertAfter);
2824 if ( !pWndIA ||
2825 pWndIA == UserGetDesktopWindow() ||
2826 pWndIA == UserGetMessageWindow() )
2827 {
2828 goto Exit;
2829 }
2830 }
2831
2832 Ret = IntDeferWindowPos(WinPosInfo, Wnd, WndInsertAfter, x, y, cx, cy, Flags);
2833
2834 Exit:
2835 TRACE("Leave NtUserDeferWindowPos, ret=%p\n", Ret);
2836 UserLeave();
2837 return Ret;
2838 }
2839
2840 /*
2841 * @implemented
2842 */
2843 DWORD APIENTRY
2844 NtUserGetInternalWindowPos( HWND hWnd,
2845 LPRECT rectWnd,
2846 LPPOINT ptIcon)
2847 {
2848 PWND Window;
2849 DWORD Ret = 0;
2850 BOOL Hit = FALSE;
2851 WINDOWPLACEMENT wndpl;
2852
2853 UserEnterShared();
2854
2855 if (!(Window = UserGetWindowObject(hWnd)))
2856 {
2857 Hit = FALSE;
2858 goto Exit;
2859 }
2860
2861 _SEH2_TRY
2862 {
2863 if(rectWnd)
2864 {
2865 ProbeForWrite(rectWnd,
2866 sizeof(RECT),
2867 1);
2868 }
2869 if(ptIcon)
2870 {
2871 ProbeForWrite(ptIcon,
2872 sizeof(POINT),
2873 1);
2874 }
2875
2876 }
2877 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2878 {
2879 SetLastNtError(_SEH2_GetExceptionCode());
2880 Hit = TRUE;
2881 }
2882 _SEH2_END;
2883
2884 wndpl.length = sizeof(WINDOWPLACEMENT);
2885
2886 if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
2887 {
2888 _SEH2_TRY
2889 {
2890 if (rectWnd)
2891 {
2892 RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));
2893 }
2894 if (ptIcon)
2895 {
2896 RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT));
2897 }
2898
2899 }
2900 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2901 {
2902 SetLastNtError(_SEH2_GetExceptionCode());
2903 Hit = TRUE;
2904 }
2905 _SEH2_END;
2906
2907 if (!Hit) Ret = wndpl.showCmd;
2908 }
2909 Exit:
2910 UserLeave();
2911 return Ret;
2912 }
2913
2914 /*
2915 * @implemented
2916 */
2917 BOOL APIENTRY
2918 NtUserGetWindowPlacement(HWND hWnd,
2919 WINDOWPLACEMENT *lpwndpl)
2920 {
2921 PWND Wnd;
2922 WINDOWPLACEMENT Safepl;
2923 NTSTATUS Status;
2924 DECLARE_RETURN(BOOL);
2925
2926 TRACE("Enter NtUserGetWindowPlacement\n");
2927 UserEnterShared();
2928
2929 if (!(Wnd = UserGetWindowObject(hWnd)))
2930 {
2931 RETURN( FALSE);
2932 }
2933
2934 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
2935 if(!NT_SUCCESS(Status))
2936 {
2937 SetLastNtError(Status);
2938 RETURN( FALSE);
2939 }
2940 if(Safepl.length != sizeof(WINDOWPLACEMENT))
2941 {
2942 RETURN( FALSE);
2943 }
2944
2945 IntGetWindowPlacement(Wnd, &Safepl);
2946
2947 Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
2948 if(!NT_SUCCESS(Status))
2949 {
2950 SetLastNtError(Status);
2951 RETURN( FALSE);
2952 }
2953
2954 RETURN( TRUE);
2955
2956 CLEANUP:
2957 TRACE("Leave NtUserGetWindowPlacement, ret=%i\n",_ret_);
2958 UserLeave();
2959 END_CLEANUP;
2960 }
2961
2962 DWORD
2963 APIENTRY
2964 NtUserMinMaximize(
2965 HWND hWnd,
2966 UINT cmd, // Wine SW_ commands
2967 BOOL Hide)
2968 {
2969 PWND pWnd;
2970
2971 TRACE("Enter NtUserMinMaximize\n");
2972 UserEnterExclusive();
2973
2974 pWnd = UserGetWindowObject(hWnd);
2975 if ( !pWnd || // FIXME:
2976 pWnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2977 pWnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2978 {
2979 goto Exit;
2980 }
2981
2982 if ( cmd > SW_MAX || pWnd->state2 & WNDS2_INDESTROY)
2983 {
2984 EngSetLastError(ERROR_INVALID_PARAMETER);
2985 goto Exit;
2986 }
2987
2988 cmd |= Hide ? SW_HIDE : 0;
2989
2990 co_WinPosShowWindow(pWnd, cmd);
2991
2992 Exit:
2993 TRACE("Leave NtUserMinMaximize\n");
2994 UserLeave();
2995 return 0; // Always NULL?
2996 }
2997
2998 /*
2999 * @implemented
3000 */
3001 BOOL APIENTRY
3002 NtUserMoveWindow(
3003 HWND hWnd,
3004 int X,
3005 int Y,
3006 int nWidth,
3007 int nHeight,
3008 BOOL bRepaint)
3009 {
3010 return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight,
3011 (bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE :
3012 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW));
3013 }
3014
3015 /*
3016 * @implemented
3017 */
3018 HWND APIENTRY
3019 NtUserRealChildWindowFromPoint(HWND Parent,
3020 LONG x,
3021 LONG y)
3022 {
3023 PWND pwndParent;
3024 TRACE("Enter NtUserRealChildWindowFromPoint\n");
3025 UserEnterShared();
3026 if ((pwndParent = UserGetWindowObject(Parent)))
3027 {
3028 pwndParent = IntRealChildWindowFromPoint(pwndParent, x, y);
3029 }
3030 UserLeave();
3031 TRACE("Leave NtUserRealChildWindowFromPoint\n");
3032 return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
3033 }
3034
3035 /*
3036 * @implemented
3037 */
3038 BOOL APIENTRY
3039 NtUserSetWindowPos(
3040 HWND hWnd,
3041 HWND hWndInsertAfter,
3042 int X,
3043 int Y,
3044 int cx,
3045 int cy,
3046 UINT uFlags)
3047 {
3048 DECLARE_RETURN(BOOL);
3049 PWND Window, pWndIA;
3050 BOOL ret;
3051 USER_REFERENCE_ENTRY Ref;
3052
3053 TRACE("Enter NtUserSetWindowPos\n");
3054 UserEnterExclusive();
3055
3056 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
3057 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3058 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3059 {
3060 ERR("NtUserSetWindowPos bad window handle!\n");
3061 RETURN(FALSE);
3062 }
3063
3064 if ( hWndInsertAfter &&
3065 hWndInsertAfter != HWND_BOTTOM &&
3066 hWndInsertAfter != HWND_TOPMOST &&
3067 hWndInsertAfter != HWND_NOTOPMOST )
3068 {
3069 if (!(pWndIA = UserGetWindowObject(hWndInsertAfter)) ||
3070 pWndIA == UserGetDesktopWindow() ||
3071 pWndIA == UserGetMessageWindow() )
3072 {
3073 ERR("NtUserSetWindowPos bad insert window handle!\n");
3074 RETURN(FALSE);
3075 }
3076 }
3077
3078 /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
3079 if (!(uFlags & SWP_NOMOVE))
3080 {
3081 if (X < -32768) X = -32768;
3082 else if (X > 32767) X = 32767;
3083 if (Y < -32768) Y = -32768;
3084 else if (Y > 32767) Y = 32767;
3085 }
3086 if (!(uFlags & SWP_NOSIZE))
3087 {
3088 if (cx < 0) cx = 0;
3089 else if (cx > 32767) cx = 32767;
3090 if (cy < 0) cy = 0;
3091 else if (cy > 32767) cy = 32767;
3092 }
3093
3094 UserRefObjectCo(Window, &Ref);
3095 ret = co_WinPosSetWindowPos(Window, hWndInsertAfter, X, Y, cx, cy, uFlags);
3096 UserDerefObjectCo(Window);
3097
3098 RETURN(ret);
3099
3100 CLEANUP:
3101 TRACE("Leave NtUserSetWindowPos, ret=%i\n",_ret_);
3102 UserLeave();
3103 END_CLEANUP;
3104 }
3105
3106 /*
3107 * @implemented
3108 */
3109 INT APIENTRY
3110 NtUserSetWindowRgn(
3111 HWND hWnd,
3112 HRGN hRgn,
3113 BOOL bRedraw)
3114 {
3115 HRGN hrgnCopy;
3116 PWND Window;
3117 INT flags = (SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE);
3118 BOOLEAN Ret = FALSE;
3119 DECLARE_RETURN(INT);
3120
3121 TRACE("Enter NtUserSetWindowRgn\n");
3122 UserEnterExclusive();
3123
3124 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
3125 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3126 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3127 {
3128 RETURN( 0);
3129 }
3130
3131 if (hRgn) // The region will be deleted in user32.
3132 {
3133 if (GreIsHandleValid(hRgn))
3134 {
3135 hrgnCopy = IntSysCreateRectRgn(0, 0, 0, 0);
3136 /* The coordinates of a window's window region are relative to the
3137 upper-left corner of the window, not the client area of the window. */
3138 NtGdiCombineRgn( hrgnCopy, hRgn, 0, RGN_COPY);
3139 }
3140 else
3141 RETURN( 0);
3142 }
3143 else
3144 {
3145 hrgnCopy = NULL;
3146 }
3147
3148 if (Window->hrgnClip)
3149 {
3150 /* Delete no longer needed region handle */
3151 IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED);
3152 GreDeleteObject(Window->hrgnClip);
3153 }
3154
3155 if (hrgnCopy)
3156 {
3157 /* Set public ownership */
3158 IntGdiSetRegionOwner(hrgnCopy, GDI_OBJ_HMGR_PUBLIC);
3159 }
3160 Window->hrgnClip = hrgnCopy;
3161
3162 Ret = co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, bRedraw ? flags : (flags|SWP_NOREDRAW) );
3163
3164 RETURN( (INT)Ret);
3165
3166 CLEANUP:
3167 TRACE("Leave NtUserSetWindowRgn, ret=%i\n",_ret_);
3168 UserLeave();
3169 END_CLEANUP;
3170 }
3171
3172 /*
3173 * @implemented
3174 */
3175 DWORD APIENTRY
3176 NtUserSetInternalWindowPos(
3177 HWND hwnd,
3178 UINT showCmd,
3179 LPRECT lprect,
3180 LPPOINT lppt)
3181 {
3182 WINDOWPLACEMENT wndpl;
3183 UINT flags;
3184 PWND Wnd;
3185 RECT rect;
3186 POINT pt = {0};
3187 DECLARE_RETURN(BOOL);
3188 USER_REFERENCE_ENTRY Ref;
3189
3190 TRACE("Enter NtUserSetWindowPlacement\n");
3191 UserEnterExclusive();
3192
3193 if (!(Wnd = UserGetWindowObject(hwnd)) || // FIXME:
3194 Wnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3195 Wnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3196 {
3197 RETURN( FALSE);
3198 }
3199
3200 _SEH2_TRY
3201 {
3202 if (lppt)
3203 {
3204 ProbeForRead(lppt, sizeof(POINT), 1);
3205 RtlCopyMemory(&pt, lppt, sizeof(POINT));
3206 }
3207 if (lprect)
3208 {
3209 ProbeForRead(lprect, sizeof(RECT), 1);
3210 RtlCopyMemory(&rect, lprect, sizeof(RECT));
3211 }
3212 }
3213 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3214 {
3215 SetLastNtError(_SEH2_GetExceptionCode());
3216 _SEH2_YIELD(RETURN( FALSE));
3217 }
3218 _SEH2_END
3219
3220 wndpl.length = sizeof(wndpl);
3221 wndpl.showCmd = showCmd;
3222 wndpl.flags = flags = 0;
3223
3224 if ( lppt )
3225 {
3226 flags |= PLACE_MIN;
3227 wndpl.flags |= WPF_SETMINPOSITION;
3228 wndpl.ptMinPosition = pt;
3229 }
3230 if ( lprect )
3231 {
3232 flags |= PLACE_RECT;
3233 wndpl.rcNormalPosition = rect;
3234 }
3235
3236 UserRefObjectCo(Wnd, &Ref);
3237 IntSetWindowPlacement(Wnd, &wndpl, flags);
3238 UserDerefObjectCo(Wnd);
3239 RETURN(TRUE);
3240
3241 CLEANUP:
3242 TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
3243 UserLeave();
3244 END_CLEANUP;
3245 }
3246
3247 /*
3248 * @implemented
3249 */
3250 BOOL APIENTRY
3251 NtUserSetWindowPlacement(HWND hWnd,
3252 WINDOWPLACEMENT *lpwndpl)
3253 {
3254 PWND Wnd;
3255 WINDOWPLACEMENT Safepl;
3256 UINT Flags;
3257 DECLARE_RETURN(BOOL);
3258 USER_REFERENCE_ENTRY Ref;
3259
3260 TRACE("Enter NtUserSetWindowPlacement\n");
3261 UserEnterExclusive();
3262
3263 if (!(Wnd = UserGetWindowObject(hWnd)) || // FIXME:
3264 Wnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3265 Wnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3266 {
3267 RETURN( FALSE);
3268 }
3269
3270 _SEH2_TRY
3271 {
3272 ProbeForRead(lpwndpl, sizeof(WINDOWPLACEMENT), 1);
3273 RtlCopyMemory(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3274 }
3275 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3276 {
3277 SetLastNtError(_SEH2_GetExceptionCode());
3278 _SEH2_YIELD(RETURN( FALSE));
3279 }
3280 _SEH2_END
3281
3282 if(Safepl.length != sizeof(WINDOWPLACEMENT))
3283 {
3284 RETURN( FALSE);
3285 }
3286
3287 Flags = PLACE_MAX | PLACE_RECT;
3288 if (Safepl.flags & WPF_SETMINPOSITION) Flags |= PLACE_MIN;
3289 UserRefObjectCo(Wnd, &Ref);
3290 IntSetWindowPlacement(Wnd, &Safepl, Flags);
3291 UserDerefObjectCo(Wnd);
3292 RETURN(TRUE);
3293
3294 CLEANUP:
3295 TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
3296 UserLeave();
3297 END_CLEANUP;
3298 }
3299
3300 /*
3301 * @implemented
3302 */
3303 BOOL APIENTRY
3304 NtUserShowWindowAsync(HWND hWnd, LONG nCmdShow)
3305 {
3306 PWND Window;
3307 BOOL ret;
3308 DECLARE_RETURN(BOOL);
3309 USER_REFERENCE_ENTRY Ref;
3310
3311 TRACE("Enter NtUserShowWindowAsync\n");
3312 UserEnterExclusive();
3313
3314 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
3315 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3316 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3317 {
3318 RETURN(FALSE);
3319 }
3320
3321 if ( nCmdShow > SW_MAX )
3322 {
3323 EngSetLastError(ERROR_INVALID_PARAMETER);
3324 RETURN(FALSE);
3325 }
3326
3327 UserRefObjectCo(Window, &Ref);
3328 ret = co_IntSendMessageNoWait( hWnd, WM_ASYNC_SHOWWINDOW, nCmdShow, 0 );
3329 UserDerefObjectCo(Window);
3330 if (-1 == (int) ret || !ret) ret = FALSE;
3331
3332 RETURN(ret);
3333
3334 CLEANUP:
3335 TRACE("Leave NtUserShowWindowAsync, ret=%i\n",_ret_);
3336 UserLeave();
3337 END_CLEANUP;
3338 }
3339
3340 /*
3341 * @implemented
3342 */
3343 BOOL APIENTRY
3344 NtUserShowWindow(HWND hWnd, LONG nCmdShow)
3345 {
3346 PWND Window;
3347 BOOL ret;
3348 DECLARE_RETURN(BOOL);
3349 USER_REFERENCE_ENTRY Ref;
3350
3351 TRACE("Enter NtUserShowWindow\n");
3352 UserEnterExclusive();
3353
3354 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
3355 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
3356 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
3357 {
3358 RETURN(FALSE);
3359 }
3360
3361 if ( nCmdShow > SW_MAX || Window->state2 & WNDS2_INDESTROY)
3362 {
3363 EngSetLastError(ERROR_INVALID_PARAMETER);
3364 RETURN(FALSE);
3365 }
3366
3367 UserRefObjectCo(Window, &Ref);
3368 ret = co_WinPosShowWindow(Window, nCmdShow);
3369 UserDerefObjectCo(Window);
3370
3371 RETURN(ret);
3372
3373 CLEANUP:
3374 TRACE("Leave NtUserShowWindow, ret=%i\n",_ret_);
3375 UserLeave();
3376 END_CLEANUP;
3377 }
3378
3379
3380 /*
3381 * @implemented
3382 */
3383 HWND APIENTRY
3384 NtUserWindowFromPoint(LONG X, LONG Y)
3385 {
3386 POINT pt;
3387 HWND Ret;
3388 PWND DesktopWindow = NULL, Window = NULL;
3389 USHORT hittest;
3390 DECLARE_RETURN(HWND);
3391 USER_REFERENCE_ENTRY Ref;
3392
3393 TRACE("Enter NtUserWindowFromPoint\n");
3394 UserEnterExclusive();
3395
3396 if ((DesktopWindow = UserGetWindowObject(IntGetDesktopWindow())))
3397 {
3398 //PTHREADINFO pti;
3399
3400 pt.x = X;
3401 pt.y = Y;
3402
3403 // Hmm... Threads live on desktops thus we have a reference on the desktop and indirectly the desktop window.
3404 // It is possible this referencing is useless, though it should not hurt...
3405 UserRefObjectCo(DesktopWindow, &Ref);
3406
3407 //pti = PsGetCurrentThreadWin32Thread();
3408 Window = co_WinPosWindowFromPoint(DesktopWindow, &pt, &hittest, FALSE);
3409
3410 if (Window)
3411 {
3412 Ret = UserHMGetHandle(Window);
3413
3414 RETURN( Ret);
3415 }
3416 }
3417
3418 RETURN( NULL);
3419
3420 CLEANUP:
3421 if (Window) UserDereferenceObject(Window);
3422 if (DesktopWindow) UserDerefObjectCo(DesktopWindow);
3423
3424 TRACE("Leave NtUserWindowFromPoint, ret=%p\n", _ret_);
3425 UserLeave();
3426 END_CLEANUP;
3427 }
3428
3429 /* EOF */