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