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