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