[win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / 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 /* FUNCTIONS *****************************************************************/
27
28 BOOL FASTCALL
29 IntGetClientOrigin(PWND Window OPTIONAL, LPPOINT Point)
30 {
31 Window = Window ? Window : UserGetWindowObject(IntGetDesktopWindow());
32 if (Window == NULL)
33 {
34 Point->x = Point->y = 0;
35 return FALSE;
36 }
37 Point->x = Window->rcClient.left;
38 Point->y = Window->rcClient.top;
39
40 return TRUE;
41 }
42
43
44 /*******************************************************************
45 * can_activate_window
46 *
47 * Check if we can activate the specified window.
48 */
49 static
50 BOOL FASTCALL can_activate_window( PWND Wnd OPTIONAL)
51 {
52 LONG style;
53
54 if (!Wnd) return FALSE;
55
56 style = Wnd->style;
57 if (!(style & WS_VISIBLE) &&
58 Wnd->head.pti->pEThread->ThreadsProcess != CsrProcess) return FALSE;
59 if ((style & WS_MINIMIZE) &&
60 Wnd->head.pti->pEThread->ThreadsProcess != CsrProcess) return FALSE;
61 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
62 return TRUE;
63 /* FIXME: This window could be disable because the child that closed
64 was a popup. */
65 //return !(style & WS_DISABLED);
66 }
67
68
69 /*******************************************************************
70 * WinPosActivateOtherWindow
71 *
72 * Activates window other than pWnd.
73 */
74 VOID FASTCALL
75 co_WinPosActivateOtherWindow(PWND Wnd)
76 {
77 PWND WndTo = NULL;
78 HWND Fg;
79 USER_REFERENCE_ENTRY Ref;
80
81 ASSERT_REFS_CO(Wnd);
82
83 if (IntIsDesktopWindow(Wnd))
84 {
85 IntSetFocusMessageQueue(NULL);
86 return;
87 }
88
89 /* If this is popup window, try to activate the owner first. */
90 if ((Wnd->style & WS_POPUP) && (WndTo = Wnd->spwndOwner))
91 {
92 WndTo = UserGetAncestor( WndTo, GA_ROOT );
93 if (can_activate_window(WndTo)) goto done;
94 }
95
96 /* Pick a next top-level window. */
97 /* FIXME: Search for non-tooltip windows first. */
98 WndTo = Wnd;
99 for (;;)
100 {
101 if (!(WndTo = WndTo->spwndNext)) break;
102 if (can_activate_window( WndTo )) break;
103 }
104
105 done:
106
107 if (WndTo) UserRefObjectCo(WndTo, &Ref);
108
109 Fg = UserGetForegroundWindow();
110 if ((!Fg || Wnd->head.h == Fg) && WndTo)//fixme: ok if WndTo is NULL??
111 {
112 /* fixme: wine can pass WndTo=NULL to co_IntSetForegroundWindow. hmm */
113 if (co_IntSetForegroundWindow(WndTo))
114 {
115 UserDerefObjectCo(WndTo);
116 return;
117 }
118 }
119
120 if (!co_IntSetActiveWindow(WndTo)) /* ok for WndTo to be NULL here */
121 co_IntSetActiveWindow(0);
122
123 if (WndTo) UserDerefObjectCo(WndTo);
124 }
125
126
127 UINT
128 FASTCALL
129 co_WinPosArrangeIconicWindows(PWND parent)
130 {
131 RECTL rectParent;
132 INT i, x, y, xspacing, yspacing;
133 HWND *List = IntWinListChildren(parent);
134
135 ASSERT_REFS_CO(parent);
136
137 /* Check if we found any children */
138 if(List == NULL)
139 {
140 return 0;
141 }
142
143 IntGetClientRect( parent, &rectParent );
144 x = rectParent.left;
145 y = rectParent.bottom;
146
147 xspacing = UserGetSystemMetrics(SM_CXICONSPACING);
148 yspacing = UserGetSystemMetrics(SM_CYICONSPACING);
149
150 TRACE("X:%d Y:%d XS:%d YS:%d\n",x,y,xspacing,yspacing);
151
152 for( i = 0; List[i]; i++)
153 {
154 PWND Child;
155
156 if (!(Child = UserGetWindowObject(List[i])))
157 continue;
158
159 if((Child->style & WS_MINIMIZE) != 0 )
160 {
161 USER_REFERENCE_ENTRY Ref;
162 UserRefObjectCo(Child, &Ref);
163
164 co_WinPosSetWindowPos(Child, 0, x + (xspacing - UserGetSystemMetrics(SM_CXICON)) / 2,
165 y - yspacing - UserGetSystemMetrics(SM_CYICON) / 2
166 , 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
167
168 UserDerefObjectCo(Child);
169
170 if (x <= rectParent.right - xspacing)
171 x += xspacing;
172 else
173 {
174 x = rectParent.left;
175 y -= yspacing;
176 }
177 }
178 }
179 ExFreePool(List);
180 return yspacing;
181 }
182
183
184 static VOID FASTCALL
185 WinPosFindIconPos(PWND Window, POINT *Pos)
186 {
187 ERR("WinPosFindIconPos FIXME!\n");
188 }
189
190 VOID FASTCALL
191 WinPosInitInternalPos(PWND Wnd, POINT *pt, RECTL *RestoreRect)
192 {
193 PWND Parent;
194 UINT XInc, YInc;
195
196 if (!Wnd->InternalPosInitialized)
197 {
198 RECTL WorkArea;
199
200 Parent = Wnd->spwndParent;
201 if(Parent)
202 {
203 if(IntIsDesktopWindow(Parent))
204 UserSystemParametersInfo(SPI_GETWORKAREA, 0, &WorkArea, 0);
205 else
206 WorkArea = Parent->rcClient;
207 }
208 else
209 UserSystemParametersInfo(SPI_GETWORKAREA, 0, &WorkArea, 0);
210
211 Wnd->InternalPos.NormalRect = Wnd->rcWindow;
212 IntGetWindowBorderMeasures(Wnd, &XInc, &YInc);
213 Wnd->InternalPos.MaxPos.x = WorkArea.left - XInc;
214 Wnd->InternalPos.MaxPos.y = WorkArea.top - YInc;
215 Wnd->InternalPos.IconPos.x = WorkArea.left;
216 Wnd->InternalPos.IconPos.y = WorkArea.bottom - UserGetSystemMetrics(SM_CYMINIMIZED);
217
218 Wnd->InternalPosInitialized = TRUE;
219 }
220 if (Wnd->style & WS_MINIMIZE)
221 {
222 Wnd->InternalPos.IconPos = *pt;
223 }
224 else if (Wnd->style & WS_MAXIMIZE)
225 {
226 Wnd->InternalPos.MaxPos = *pt;
227 }
228 else if (RestoreRect != NULL)
229 {
230 Wnd->InternalPos.NormalRect = *RestoreRect;
231 }
232 }
233
234 UINT FASTCALL
235 co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos)
236 {
237 POINT Size;
238 UINT SwpFlags = 0;
239
240 ASSERT_REFS_CO(Wnd);
241
242 Size.x = Wnd->rcWindow.left;
243 Size.y = Wnd->rcWindow.top;
244 WinPosInitInternalPos(Wnd, &Size, &Wnd->rcWindow);
245
246 if (co_HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)Wnd->head.h, ShowFlag))
247 {
248 ERR("WinPosMinMaximize WH_CBT Call Hook return!\n");
249 return SWP_NOSIZE | SWP_NOMOVE;
250 }
251 if (Wnd->style & WS_MINIMIZE)
252 {
253 if (!co_IntSendMessageNoWait(Wnd->head.h, WM_QUERYOPEN, 0, 0))
254 {
255 return(SWP_NOSIZE | SWP_NOMOVE);
256 }
257 SwpFlags |= SWP_NOCOPYBITS;
258 }
259 switch (ShowFlag)
260 {
261 case SW_MINIMIZE:
262 {
263 if (Wnd->style & WS_MAXIMIZE)
264 {
265 Wnd->state2 |= WNDS2_MAXIMIZEBUTTONDOWN;
266 Wnd->style &= ~WS_MAXIMIZE;
267 }
268 else
269 {
270 Wnd->state2 &= ~WNDS2_MAXIMIZEBUTTONDOWN;
271 }
272 co_UserRedrawWindow(Wnd, NULL, 0, RDW_VALIDATE | RDW_NOERASE |
273 RDW_NOINTERNALPAINT);
274 Wnd->style |= WS_MINIMIZE;
275 WinPosFindIconPos(Wnd, &Wnd->InternalPos.IconPos);
276 RECTL_vSetRect(NewPos, Wnd->InternalPos.IconPos.x, Wnd->InternalPos.IconPos.y,
277 UserGetSystemMetrics(SM_CXMINIMIZED),
278 UserGetSystemMetrics(SM_CYMINIMIZED));
279 SwpFlags |= SWP_NOCOPYBITS;
280 break;
281 }
282
283 case SW_MAXIMIZE:
284 {
285 co_WinPosGetMinMaxInfo(Wnd, &Size, &Wnd->InternalPos.MaxPos,
286 NULL, NULL);
287 TRACE("Maximize: %d,%d %dx%d\n",
288 Wnd->InternalPos.MaxPos.x, Wnd->InternalPos.MaxPos.y, Size.x, Size.y);
289 if (Wnd->style & WS_MINIMIZE)
290 {
291 Wnd->style &= ~WS_MINIMIZE;
292 }
293 Wnd->style |= WS_MAXIMIZE;
294 RECTL_vSetRect(NewPos, Wnd->InternalPos.MaxPos.x, Wnd->InternalPos.MaxPos.y,
295 Size.x, Size.y);
296 break;
297 }
298
299 case SW_RESTORE:
300 {
301 if (Wnd->style & WS_MINIMIZE)
302 {
303 Wnd->style &= ~WS_MINIMIZE;
304 if (Wnd->state2 & WNDS2_MAXIMIZEBUTTONDOWN)
305 {
306 co_WinPosGetMinMaxInfo(Wnd, &Size,
307 &Wnd->InternalPos.MaxPos, NULL, NULL);
308 Wnd->style |= WS_MAXIMIZE;
309 RECTL_vSetRect(NewPos, Wnd->InternalPos.MaxPos.x,
310 Wnd->InternalPos.MaxPos.y, Size.x, Size.y);
311 break;
312 }
313 else
314 {
315 *NewPos = Wnd->InternalPos.NormalRect;
316 NewPos->right -= NewPos->left;
317 NewPos->bottom -= NewPos->top;
318 break;
319 }
320 }
321 else
322 {
323 if (!(Wnd->style & WS_MAXIMIZE))
324 {
325 return 0;
326 }
327 Wnd->style &= ~WS_MAXIMIZE;
328 *NewPos = Wnd->InternalPos.NormalRect;
329 NewPos->right -= NewPos->left;
330 NewPos->bottom -= NewPos->top;
331 break;
332 }
333 }
334 }
335 return(SwpFlags);
336 }
337
338 BOOL
339 UserHasWindowEdge(DWORD Style, DWORD ExStyle)
340 {
341 if (Style & WS_MINIMIZE)
342 return TRUE;
343 if (ExStyle & WS_EX_DLGMODALFRAME)
344 return TRUE;
345 if (ExStyle & WS_EX_STATICEDGE)
346 return FALSE;
347 if (Style & WS_THICKFRAME)
348 return TRUE;
349 Style &= WS_CAPTION;
350 if (Style == WS_DLGFRAME || Style == WS_CAPTION)
351 return TRUE;
352 return FALSE;
353 }
354
355 VOID
356 UserGetWindowBorders(DWORD Style, DWORD ExStyle, SIZE *Size, BOOL WithClient)
357 {
358 DWORD Border = 0;
359
360 if (UserHasWindowEdge(Style, ExStyle))
361 Border += 2;
362 else if (ExStyle & WS_EX_STATICEDGE)
363 Border += 1;
364 if ((ExStyle & WS_EX_CLIENTEDGE) && WithClient)
365 Border += 2;
366 if (Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME)
367 Border ++;
368 Size->cx = Size->cy = Border;
369 if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
370 {
371 Size->cx += UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME);
372 Size->cy += UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME);
373 }
374 Size->cx *= UserGetSystemMetrics(SM_CXBORDER);
375 Size->cy *= UserGetSystemMetrics(SM_CYBORDER);
376 }
377
378 BOOL WINAPI
379 UserAdjustWindowRectEx(LPRECT lpRect,
380 DWORD dwStyle,
381 BOOL bMenu,
382 DWORD dwExStyle)
383 {
384 SIZE BorderSize;
385
386 if (bMenu)
387 {
388 lpRect->top -= UserGetSystemMetrics(SM_CYMENU);
389 }
390 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
391 {
392 if (dwExStyle & WS_EX_TOOLWINDOW)
393 lpRect->top -= UserGetSystemMetrics(SM_CYSMCAPTION);
394 else
395 lpRect->top -= UserGetSystemMetrics(SM_CYCAPTION);
396 }
397 UserGetWindowBorders(dwStyle, dwExStyle, &BorderSize, TRUE);
398 RECTL_vInflateRect(
399 lpRect,
400 BorderSize.cx,
401 BorderSize.cy);
402
403 return TRUE;
404 }
405
406 UINT FASTCALL
407 co_WinPosGetMinMaxInfo(PWND Window, POINT* MaxSize, POINT* MaxPos,
408 POINT* MinTrack, POINT* MaxTrack)
409 {
410 MINMAXINFO MinMax;
411 PMONITOR monitor;
412 INT xinc, yinc;
413 LONG style = Window->style;
414 LONG adjustedStyle;
415 LONG exstyle = Window->ExStyle;
416 RECT rc;
417
418 ASSERT_REFS_CO(Window);
419
420 /* Compute default values */
421
422 rc = Window->rcWindow;
423 MinMax.ptReserved.x = rc.left;
424 MinMax.ptReserved.y = rc.top;
425
426 if ((style & WS_CAPTION) == WS_CAPTION)
427 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
428 else
429 adjustedStyle = style;
430
431 if(Window->spwndParent)
432 IntGetClientRect(Window->spwndParent, &rc);
433 UserAdjustWindowRectEx(&rc, adjustedStyle, ((style & WS_POPUP) && Window->IDMenu), exstyle);
434
435 xinc = -rc.left;
436 yinc = -rc.top;
437
438 MinMax.ptMaxSize.x = rc.right - rc.left;
439 MinMax.ptMaxSize.y = rc.bottom - rc.top;
440 if (style & (WS_DLGFRAME | WS_BORDER))
441 {
442 MinMax.ptMinTrackSize.x = UserGetSystemMetrics(SM_CXMINTRACK);
443 MinMax.ptMinTrackSize.y = UserGetSystemMetrics(SM_CYMINTRACK);
444 }
445 else
446 {
447 MinMax.ptMinTrackSize.x = 2 * xinc;
448 MinMax.ptMinTrackSize.y = 2 * yinc;
449 }
450 MinMax.ptMaxTrackSize.x = UserGetSystemMetrics(SM_CXMAXTRACK);
451 MinMax.ptMaxTrackSize.y = UserGetSystemMetrics(SM_CYMAXTRACK);
452 MinMax.ptMaxPosition.x = -xinc;
453 MinMax.ptMaxPosition.y = -yinc;
454
455 //if (!EMPTYPOINT(win->max_pos)) MinMax.ptMaxPosition = win->max_pos;
456
457 co_IntSendMessage(Window->head.h, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax);
458
459 /* if the app didn't change the values, adapt them for the current monitor */
460 if ((monitor = IntGetPrimaryMonitor()))
461 {
462 RECT rc_work;
463
464 rc_work = monitor->rcMonitor;
465
466 if (style & WS_MAXIMIZEBOX)
467 {
468 if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP)))
469 rc_work = monitor->rcWork;
470 }
471
472 if (MinMax.ptMaxSize.x == UserGetSystemMetrics(SM_CXSCREEN) + 2 * xinc &&
473 MinMax.ptMaxSize.y == UserGetSystemMetrics(SM_CYSCREEN) + 2 * yinc)
474 {
475 MinMax.ptMaxSize.x = (rc_work.right - rc_work.left) + 2 * xinc;
476 MinMax.ptMaxSize.y = (rc_work.bottom - rc_work.top) + 2 * yinc;
477 }
478 if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc)
479 {
480 MinMax.ptMaxPosition.x = rc_work.left - xinc;
481 MinMax.ptMaxPosition.y = rc_work.top - yinc;
482 }
483 }
484
485
486 MinMax.ptMaxTrackSize.x = max(MinMax.ptMaxTrackSize.x,
487 MinMax.ptMinTrackSize.x);
488 MinMax.ptMaxTrackSize.y = max(MinMax.ptMaxTrackSize.y,
489 MinMax.ptMinTrackSize.y);
490
491 if (MaxSize)
492 *MaxSize = MinMax.ptMaxSize;
493 if (MaxPos)
494 *MaxPos = MinMax.ptMaxPosition;
495 if (MinTrack)
496 *MinTrack = MinMax.ptMinTrackSize;
497 if (MaxTrack)
498 *MaxTrack = MinMax.ptMaxTrackSize;
499
500 return 0; //FIXME: what does it return?
501 }
502
503 static
504 VOID FASTCALL
505 FixClientRect(PRECTL ClientRect, PRECTL WindowRect)
506 {
507 if (ClientRect->left < WindowRect->left)
508 {
509 ClientRect->left = WindowRect->left;
510 }
511 else if (WindowRect->right < ClientRect->left)
512 {
513 ClientRect->left = WindowRect->right;
514 }
515 if (ClientRect->right < WindowRect->left)
516 {
517 ClientRect->right = WindowRect->left;
518 }
519 else if (WindowRect->right < ClientRect->right)
520 {
521 ClientRect->right = WindowRect->right;
522 }
523 if (ClientRect->top < WindowRect->top)
524 {
525 ClientRect->top = WindowRect->top;
526 }
527 else if (WindowRect->bottom < ClientRect->top)
528 {
529 ClientRect->top = WindowRect->bottom;
530 }
531 if (ClientRect->bottom < WindowRect->top)
532 {
533 ClientRect->bottom = WindowRect->top;
534 }
535 else if (WindowRect->bottom < ClientRect->bottom)
536 {
537 ClientRect->bottom = WindowRect->bottom;
538 }
539 }
540
541 static
542 LONG FASTCALL
543 co_WinPosDoNCCALCSize(PWND Window, PWINDOWPOS WinPos,
544 RECT* WindowRect, RECT* ClientRect)
545 {
546 PWND Parent;
547 UINT wvrFlags = 0;
548
549 ASSERT_REFS_CO(Window);
550
551 /* Send WM_NCCALCSIZE message to get new client area */
552 if ((WinPos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE)
553 {
554 NCCALCSIZE_PARAMS params;
555 WINDOWPOS winposCopy;
556
557 params.rgrc[0] = *WindowRect;
558 params.rgrc[1] = Window->rcWindow;
559 params.rgrc[2] = Window->rcClient;
560 Parent = Window->spwndParent;
561 if (0 != (Window->style & WS_CHILD) && Parent)
562 {
563 RECTL_vOffsetRect(&(params.rgrc[0]), - Parent->rcClient.left,
564 - Parent->rcClient.top);
565 RECTL_vOffsetRect(&(params.rgrc[1]), - Parent->rcClient.left,
566 - Parent->rcClient.top);
567 RECTL_vOffsetRect(&(params.rgrc[2]), - Parent->rcClient.left,
568 - Parent->rcClient.top);
569 }
570 params.lppos = &winposCopy;
571 winposCopy = *WinPos;
572
573 wvrFlags = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, TRUE, (LPARAM) &params);
574
575 /* If the application send back garbage, ignore it */
576 if (params.rgrc[0].left <= params.rgrc[0].right &&
577 params.rgrc[0].top <= params.rgrc[0].bottom)
578 {
579 *ClientRect = params.rgrc[0];
580 if ((Window->style & WS_CHILD) && Parent)
581 {
582 RECTL_vOffsetRect(ClientRect, Parent->rcClient.left,
583 Parent->rcClient.top);
584 }
585 FixClientRect(ClientRect, WindowRect);
586 }
587
588 /* FIXME: WVR_ALIGNxxx */
589
590 if (ClientRect->left != Window->rcClient.left ||
591 ClientRect->top != Window->rcClient.top)
592 {
593 WinPos->flags &= ~SWP_NOCLIENTMOVE;
594 }
595
596 if ((ClientRect->right - ClientRect->left !=
597 Window->rcClient.right - Window->rcClient.left) ||
598 (ClientRect->bottom - ClientRect->top !=
599 Window->rcClient.bottom - Window->rcClient.top))
600 {
601 WinPos->flags &= ~SWP_NOCLIENTSIZE;
602 }
603 }
604 else
605 {
606 if (! (WinPos->flags & SWP_NOMOVE)
607 && (ClientRect->left != Window->rcClient.left ||
608 ClientRect->top != Window->rcClient.top))
609 {
610 WinPos->flags &= ~SWP_NOCLIENTMOVE;
611 }
612 }
613
614 return wvrFlags;
615 }
616
617 static
618 BOOL FASTCALL
619 co_WinPosDoWinPosChanging(PWND Window,
620 PWINDOWPOS WinPos,
621 PRECTL WindowRect,
622 PRECTL ClientRect)
623 {
624 INT X, Y;
625
626 ASSERT_REFS_CO(Window);
627
628 if (!(WinPos->flags & SWP_NOSENDCHANGING))
629 {
630 co_IntSendMessageNoWait(Window->head.h, WM_WINDOWPOSCHANGING, 0, (LPARAM) WinPos);
631 }
632
633 *WindowRect = Window->rcWindow;
634 *ClientRect = Window->rcClient;
635
636 if (!(WinPos->flags & SWP_NOSIZE))
637 {
638 WindowRect->right = WindowRect->left + WinPos->cx;
639 WindowRect->bottom = WindowRect->top + WinPos->cy;
640 }
641
642 if (!(WinPos->flags & SWP_NOMOVE))
643 {
644 PWND Parent;
645 X = WinPos->x;
646 Y = WinPos->y;
647 Parent = Window->spwndParent;
648 if ((0 != (Window->style & WS_CHILD)) && Parent)
649 {
650 X += Parent->rcClient.left;
651 Y += Parent->rcClient.top;
652 }
653
654 WindowRect->left = X;
655 WindowRect->top = Y;
656 WindowRect->right += X - Window->rcWindow.left;
657 WindowRect->bottom += Y - Window->rcWindow.top;
658 RECTL_vOffsetRect(ClientRect,
659 X - Window->rcWindow.left,
660 Y - Window->rcWindow.top);
661 }
662
663 WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
664
665 return TRUE;
666 }
667
668 /*
669 * Fix Z order taking into account owned popups -
670 * basically we need to maintain them above the window that owns them
671 */
672 static
673 HWND FASTCALL
674 WinPosDoOwnedPopups(PWND Window, HWND hWndInsertAfter)
675 {
676 HWND *List = NULL;
677 HWND Owner;
678 LONG Style;
679 PWND DesktopWindow, ChildObject;
680 int i;
681
682 Owner = Window->spwndOwner ? Window->spwndOwner->head.h : NULL;
683 Style = Window->style;
684
685 if ((Style & WS_POPUP) && Owner)
686 {
687 /* Make sure this popup stays above the owner */
688 HWND hWndLocalPrev = HWND_TOPMOST;
689
690 if (hWndInsertAfter != HWND_TOPMOST)
691 {
692 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
693 List = IntWinListChildren(DesktopWindow);
694
695 if (List != NULL)
696 {
697 for (i = 0; List[i]; i++)
698 {
699 if (List[i] == Owner)
700 break;
701 if (HWND_TOP == hWndInsertAfter)
702 {
703 ChildObject = UserGetWindowObject(List[i]);
704 if (NULL != ChildObject)
705 {
706 if (0 == (ChildObject->ExStyle & WS_EX_TOPMOST))
707 {
708 break;
709 }
710 }
711 }
712 if (List[i] != Window->head.h)
713 hWndLocalPrev = List[i];
714 if (hWndLocalPrev == hWndInsertAfter)
715 break;
716 }
717 hWndInsertAfter = hWndLocalPrev;
718 }
719 }
720 }
721 else if (Style & WS_CHILD)
722 {
723 return hWndInsertAfter;
724 }
725
726 if (!List)
727 {
728 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
729 List = IntWinListChildren(DesktopWindow);
730 }
731 if (List != NULL)
732 {
733 for (i = 0; List[i]; i++)
734 {
735 PWND Wnd;
736
737 if (List[i] == Window->head.h)
738 break;
739
740 if (!(Wnd = UserGetWindowObject(List[i])))
741 continue;
742
743 if (Wnd->style & WS_POPUP && Wnd->spwndOwner == Window)
744 {
745 USER_REFERENCE_ENTRY Ref;
746 UserRefObjectCo(Wnd, &Ref);
747
748 co_WinPosSetWindowPos(Wnd, hWndInsertAfter, 0, 0, 0, 0,
749 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
750
751 UserDerefObjectCo(Wnd);
752
753 hWndInsertAfter = List[i];
754 }
755 }
756 ExFreePool(List);
757 }
758
759 return hWndInsertAfter;
760 }
761
762 /***********************************************************************
763 * WinPosInternalMoveWindow
764 *
765 * Update WindowRect and ClientRect of Window and all of its children
766 * We keep both WindowRect and ClientRect in screen coordinates internally
767 */
768 static
769 VOID FASTCALL
770 WinPosInternalMoveWindow(PWND Window, INT MoveX, INT MoveY)
771 {
772 PWND Child;
773
774 ASSERT(Window != Window->spwndChild);
775
776 Window->rcWindow.left += MoveX;
777 Window->rcWindow.right += MoveX;
778 Window->rcWindow.top += MoveY;
779 Window->rcWindow.bottom += MoveY;
780
781 Window->rcClient.left += MoveX;
782 Window->rcClient.right += MoveX;
783 Window->rcClient.top += MoveY;
784 Window->rcClient.bottom += MoveY;
785
786 for(Child = Window->spwndChild; Child; Child = Child->spwndNext)
787 {
788 WinPosInternalMoveWindow(Child, MoveX, MoveY);
789 }
790 }
791
792 /*
793 * WinPosFixupSWPFlags
794 *
795 * Fix redundant flags and values in the WINDOWPOS structure.
796 */
797 static
798 BOOL FASTCALL
799 WinPosFixupFlags(WINDOWPOS *WinPos, PWND Wnd)
800 {
801 if (Wnd->style & WS_VISIBLE)
802 {
803 WinPos->flags &= ~SWP_SHOWWINDOW;
804 }
805 else
806 {
807 WinPos->flags &= ~SWP_HIDEWINDOW;
808 if (!(WinPos->flags & SWP_SHOWWINDOW))
809 WinPos->flags |= SWP_NOREDRAW;
810 }
811
812 WinPos->cx = max(WinPos->cx, 0);
813 WinPos->cy = max(WinPos->cy, 0);
814
815 /* Check for right size */
816 if (Wnd->rcWindow.right - Wnd->rcWindow.left == WinPos->cx &&
817 Wnd->rcWindow.bottom - Wnd->rcWindow.top == WinPos->cy)
818 {
819 WinPos->flags |= SWP_NOSIZE;
820 }
821
822 /* Check for right position */
823 if (Wnd->rcWindow.left == WinPos->x &&
824 Wnd->rcWindow.top == WinPos->y)
825 {
826 WinPos->flags |= SWP_NOMOVE;
827 }
828
829 if (WinPos->hwnd == UserGetForegroundWindow())
830 {
831 WinPos->flags |= SWP_NOACTIVATE; /* Already active */
832 }
833 else
834 if ((Wnd->style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
835 {
836 /* Bring to the top when activating */
837 if (!(WinPos->flags & SWP_NOACTIVATE))
838 {
839 WinPos->flags &= ~SWP_NOZORDER;
840 WinPos->hwndInsertAfter = (0 != (Wnd->ExStyle & WS_EX_TOPMOST) ?
841 HWND_TOPMOST : HWND_TOP);
842 return TRUE;
843 }
844 }
845
846 /* Check hwndInsertAfter */
847 if (!(WinPos->flags & SWP_NOZORDER))
848 {
849 /* Fix sign extension */
850 if (WinPos->hwndInsertAfter == (HWND)0xffff)
851 {
852 WinPos->hwndInsertAfter = HWND_TOPMOST;
853 }
854 else if (WinPos->hwndInsertAfter == (HWND)0xfffe)
855 {
856 WinPos->hwndInsertAfter = HWND_NOTOPMOST;
857 }
858
859 if (WinPos->hwndInsertAfter == HWND_NOTOPMOST)
860 {
861 WinPos->hwndInsertAfter = HWND_TOP;
862 }
863 else if (HWND_TOP == WinPos->hwndInsertAfter
864 && 0 != (Wnd->ExStyle & WS_EX_TOPMOST))
865 {
866 /* Keep it topmost when it's already topmost */
867 WinPos->hwndInsertAfter = HWND_TOPMOST;
868 }
869
870 /* hwndInsertAfter must be a sibling of the window */
871 if (HWND_TOPMOST != WinPos->hwndInsertAfter
872 && HWND_TOP != WinPos->hwndInsertAfter
873 && HWND_NOTOPMOST != WinPos->hwndInsertAfter
874 && HWND_BOTTOM != WinPos->hwndInsertAfter)
875 {
876 PWND InsAfterWnd;
877
878 InsAfterWnd = UserGetWindowObject(WinPos->hwndInsertAfter);
879 if(!InsAfterWnd)
880 {
881 return TRUE;
882 }
883
884 if (InsAfterWnd->spwndParent != Wnd->spwndParent)
885 {
886 return FALSE;
887 }
888 else
889 {
890 /*
891 * We don't need to change the Z order of hwnd if it's already
892 * inserted after hwndInsertAfter or when inserting hwnd after
893 * itself.
894 */
895 if ((WinPos->hwnd == WinPos->hwndInsertAfter) ||
896 ((InsAfterWnd->spwndNext) && (WinPos->hwnd == InsAfterWnd->spwndNext->head.h)))
897 {
898 WinPos->flags |= SWP_NOZORDER;
899 }
900 }
901 }
902 }
903
904 return TRUE;
905 }
906
907 /* x and y are always screen relative */
908 BOOLEAN FASTCALL
909 co_WinPosSetWindowPos(
910 PWND Window,
911 HWND WndInsertAfter,
912 INT x,
913 INT y,
914 INT cx,
915 INT cy,
916 UINT flags
917 )
918 {
919 WINDOWPOS WinPos;
920 RECTL NewWindowRect;
921 RECTL NewClientRect;
922 PROSRGNDATA VisRgn;
923 HRGN VisBefore = NULL;
924 HRGN VisAfter = NULL;
925 HRGN DirtyRgn = NULL;
926 HRGN ExposedRgn = NULL;
927 HRGN CopyRgn = NULL;
928 ULONG WvrFlags = 0;
929 RECTL OldWindowRect, OldClientRect;
930 int RgnType;
931 HDC Dc;
932 RECTL CopyRect;
933 PWND Ancestor;
934 BOOL bPointerInWindow;
935
936 ASSERT_REFS_CO(Window);
937
938 /* FIXME: Get current active window from active queue. */
939 /*
940 * Only allow CSRSS to mess with the desktop window
941 */
942
943 if ( Window->head.h == IntGetDesktopWindow() &&
944 Window->head.pti->pEThread->ThreadsProcess != PsGetCurrentProcess())
945 {
946 return FALSE;
947 }
948 bPointerInWindow = IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y);
949
950 WinPos.hwnd = Window->head.h;
951 WinPos.hwndInsertAfter = WndInsertAfter;
952 WinPos.x = x;
953 WinPos.y = y;
954 WinPos.cx = cx;
955 WinPos.cy = cy;
956 WinPos.flags = flags;
957
958 co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
959
960 /* Does the window still exist? */
961 if (!IntIsWindow(WinPos.hwnd))
962 {
963 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
964 return FALSE;
965 }
966
967 /* Fix up the flags. */
968 if (!WinPosFixupFlags(&WinPos, Window))
969 {
970 EngSetLastError(ERROR_INVALID_PARAMETER);
971 return FALSE;
972 }
973
974 Ancestor = UserGetAncestor(Window, GA_PARENT);
975 if ( (WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) !=
976 SWP_NOZORDER &&
977 Ancestor && Ancestor->head.h == IntGetDesktopWindow() )
978 {
979 WinPos.hwndInsertAfter = WinPosDoOwnedPopups(Window, WinPos.hwndInsertAfter);
980 }
981
982 if (!(WinPos.flags & SWP_NOREDRAW))
983 {
984 /* Compute the visible region before the window position is changed */
985 if (!(WinPos.flags & SWP_SHOWWINDOW) &&
986 (WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
987 SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
988 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
989 {
990 VisBefore = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
991 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
992 VisRgn = NULL;
993
994 if ( VisBefore != NULL &&
995 (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisBefore, NULL)) &&
996 REGION_Complexity(VisRgn) == NULLREGION )
997 {
998 RGNOBJAPI_Unlock(VisRgn);
999 GreDeleteObject(VisBefore);
1000 VisBefore = NULL;
1001 }
1002 else if(VisRgn)
1003 {
1004 RGNOBJAPI_Unlock(VisRgn);
1005 NtGdiOffsetRgn(VisBefore, -Window->rcWindow.left, -Window->rcWindow.top);
1006 }
1007 }
1008 }
1009
1010 WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect);
1011
1012 TRACE("co_WinPosDoNCCALCSize returned %d\n", WvrFlags);
1013
1014 /* Relink windows. (also take into account shell window in hwndShellWindow) */
1015 if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow())
1016 {
1017 IntLinkHwnd(Window, WndInsertAfter);
1018 }
1019
1020 OldWindowRect = Window->rcWindow;
1021 OldClientRect = Window->rcClient;
1022
1023 if (OldClientRect.bottom - OldClientRect.top ==
1024 NewClientRect.bottom - NewClientRect.top)
1025 {
1026 WvrFlags &= ~WVR_VREDRAW;
1027 }
1028
1029 if (OldClientRect.right - OldClientRect.left ==
1030 NewClientRect.right - NewClientRect.left)
1031 {
1032 WvrFlags &= ~WVR_HREDRAW;
1033 }
1034
1035 /* FIXME: Actually do something with WVR_VALIDRECTS */
1036
1037 if (NewClientRect.left != OldClientRect.left ||
1038 NewClientRect.top != OldClientRect.top)
1039 {
1040 WinPosInternalMoveWindow(Window,
1041 NewClientRect.left - OldClientRect.left,
1042 NewClientRect.top - OldClientRect.top);
1043 }
1044
1045 Window->rcWindow = NewWindowRect;
1046 Window->rcClient = NewClientRect;
1047
1048 if (WinPos.flags & SWP_HIDEWINDOW)
1049 {
1050 /* Clear the update region */
1051 co_UserRedrawWindow( Window,
1052 NULL,
1053 0,
1054 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
1055
1056 if (Window->spwndParent == UserGetDesktopWindow())
1057 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (LPARAM)Window->head.h);
1058
1059 Window->style &= ~WS_VISIBLE;
1060 }
1061 else if (WinPos.flags & SWP_SHOWWINDOW)
1062 {
1063 if (Window->spwndParent == UserGetDesktopWindow())
1064 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)Window->head.h);
1065
1066 Window->style |= WS_VISIBLE;
1067 }
1068
1069 if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != HRGN_WINDOW)
1070 {
1071 NtGdiOffsetRgn(Window->hrgnUpdate,
1072 NewWindowRect.left - OldWindowRect.left,
1073 NewWindowRect.top - OldWindowRect.top);
1074 }
1075
1076 DceResetActiveDCEs(Window);
1077
1078 if (!(WinPos.flags & SWP_NOREDRAW))
1079 {
1080 /* Determine the new visible region */
1081 VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1082 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1083 VisRgn = NULL;
1084
1085 if ( VisAfter != NULL &&
1086 (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisAfter, NULL)) &&
1087 REGION_Complexity(VisRgn) == NULLREGION )
1088 {
1089 RGNOBJAPI_Unlock(VisRgn);
1090 GreDeleteObject(VisAfter);
1091 VisAfter = NULL;
1092 }
1093 else if(VisRgn)
1094 {
1095 RGNOBJAPI_Unlock(VisRgn);
1096 NtGdiOffsetRgn(VisAfter, -Window->rcWindow.left, -Window->rcWindow.top);
1097 }
1098
1099 /*
1100 * Determine which pixels can be copied from the old window position
1101 * to the new. Those pixels must be visible in both the old and new
1102 * position. Also, check the class style to see if the windows of this
1103 * class need to be completely repainted on (horizontal/vertical) size
1104 * change.
1105 */
1106 if ( VisBefore != NULL &&
1107 VisAfter != NULL &&
1108 !(WinPos.flags & SWP_NOCOPYBITS) &&
1109 ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) &&
1110 !(Window->ExStyle & WS_EX_TRANSPARENT) )
1111 {
1112 CopyRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1113 RgnType = NtGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
1114
1115 /*
1116 * If this is (also) a window resize, the whole nonclient area
1117 * needs to be repainted. So we limit the copy to the client area,
1118 * 'cause there is no use in copying it (would possibly cause
1119 * "flashing" too). However, if the copy region is already empty,
1120 * we don't have to crop (can't take anything away from an empty
1121 * region...)
1122 */
1123 if (!(WinPos.flags & SWP_NOSIZE) &&
1124 RgnType != ERROR &&
1125 RgnType != NULLREGION )
1126 {
1127 PROSRGNDATA pCopyRgn;
1128 RECTL ORect = OldClientRect;
1129 RECTL NRect = NewClientRect;
1130 RECTL_vOffsetRect(&ORect, - OldWindowRect.left, - OldWindowRect.top);
1131 RECTL_vOffsetRect(&NRect, - NewWindowRect.left, - NewWindowRect.top);
1132 RECTL_bIntersectRect(&CopyRect, &ORect, &NRect);
1133 pCopyRgn = RGNOBJAPI_Lock(CopyRgn, NULL);
1134 REGION_CropAndOffsetRegion(pCopyRgn, pCopyRgn, &CopyRect, NULL);
1135 RGNOBJAPI_Unlock(pCopyRgn);
1136 }
1137
1138 /* No use in copying bits which are in the update region. */
1139 if (Window->hrgnUpdate != NULL)
1140 {
1141 NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1142 NtGdiCombineRgn(CopyRgn, CopyRgn, Window->hrgnUpdate, RGN_DIFF);
1143 NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1144 }
1145
1146 /*
1147 * Now, get the bounding box of the copy region. If it's empty
1148 * there's nothing to copy. Also, it's no use copying bits onto
1149 * themselves.
1150 */
1151 if ( (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(CopyRgn, NULL)) &&
1152 REGION_GetRgnBox(VisRgn, &CopyRect) == NULLREGION)
1153 {
1154 /* Nothing to copy, clean up */
1155 RGNOBJAPI_Unlock(VisRgn);
1156 GreDeleteObject(CopyRgn);
1157 CopyRgn = NULL;
1158 }
1159 else if (OldWindowRect.left != NewWindowRect.left ||
1160 OldWindowRect.top != NewWindowRect.top)
1161 {
1162 if(VisRgn)
1163 {
1164 RGNOBJAPI_Unlock(VisRgn);
1165 }
1166
1167 /*
1168 * Small trick here: there is no function to bitblt a region. So
1169 * we set the region as the clipping region, take the bounding box
1170 * of the region and bitblt that. Since nothing outside the clipping
1171 * region is copied, this has the effect of bitblt'ing the region.
1172 *
1173 * Since NtUserGetDCEx takes ownership of the clip region, we need
1174 * to create a copy of CopyRgn and pass that. We need CopyRgn later
1175 */
1176 NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1177 Dc = UserGetDCEx( Window,
1178 CopyRgn,
1179 DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN);
1180 NtGdiBitBlt( Dc,
1181 CopyRect.left, CopyRect.top,
1182 CopyRect.right - CopyRect.left,
1183 CopyRect.bottom - CopyRect.top,
1184 Dc,
1185 CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
1186 CopyRect.top + (OldWindowRect.top - NewWindowRect.top),
1187 SRCCOPY,
1188 0,
1189 0);
1190
1191 UserReleaseDC(Window, Dc, FALSE);
1192 IntValidateParent(Window, CopyRgn, FALSE);
1193 NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1194 }
1195 else if(VisRgn)
1196 {
1197 RGNOBJAPI_Unlock(VisRgn);
1198 }
1199 }
1200 else
1201 {
1202 CopyRgn = NULL;
1203 }
1204
1205 /* We need to redraw what wasn't visible before */
1206 if (VisAfter != NULL)
1207 {
1208 DirtyRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1209 if (CopyRgn != NULL)
1210 {
1211 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
1212 }
1213 else
1214 {
1215 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
1216 }
1217 if (RgnType != ERROR && RgnType != NULLREGION)
1218 {
1219 /* old code
1220 NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
1221 IntInvalidateWindows( Window,
1222 DirtyRgn,
1223 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
1224 }
1225 GreDeleteObject(DirtyRgn);
1226 */
1227
1228 PWND Parent = Window->spwndParent;
1229
1230 NtGdiOffsetRgn( DirtyRgn,
1231 Window->rcWindow.left,
1232 Window->rcWindow.top);
1233 if ( (Window->style & WS_CHILD) &&
1234 (Parent) &&
1235 !(Parent->style & WS_CLIPCHILDREN))
1236 {
1237 IntInvalidateWindows( Parent,
1238 DirtyRgn,
1239 RDW_ERASE | RDW_INVALIDATE);
1240 co_IntPaintWindows(Parent, RDW_ERASENOW, FALSE);
1241 }
1242 else
1243 {
1244 IntInvalidateWindows( Window,
1245 DirtyRgn,
1246 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
1247 }
1248 }
1249 GreDeleteObject(DirtyRgn);
1250 }
1251
1252 if (CopyRgn != NULL)
1253 {
1254 GreDeleteObject(CopyRgn);
1255 }
1256
1257 /* Expose what was covered before but not covered anymore */
1258 if (VisBefore != NULL)
1259 {
1260 ExposedRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1261 RgnType = NtGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
1262 NtGdiOffsetRgn( ExposedRgn,
1263 OldWindowRect.left - NewWindowRect.left,
1264 OldWindowRect.top - NewWindowRect.top);
1265
1266 if (VisAfter != NULL)
1267 RgnType = NtGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
1268
1269 if (RgnType != ERROR && RgnType != NULLREGION)
1270 {
1271 co_VIS_WindowLayoutChanged(Window, ExposedRgn);
1272 }
1273 GreDeleteObject(ExposedRgn);
1274 GreDeleteObject(VisBefore);
1275 }
1276
1277 if (VisAfter != NULL)
1278 {
1279 GreDeleteObject(VisAfter);
1280 }
1281
1282 if (!(WinPos.flags & SWP_NOACTIVATE))
1283 {
1284 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
1285 {
1286 co_IntSendMessageNoWait(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
1287 }
1288 else
1289 {
1290 co_IntSetForegroundWindow(Window);
1291 }
1292 }
1293 }
1294
1295 if ((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
1296 {
1297 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
1298 and always contains final window position.
1299 */
1300 WinPos.x = NewWindowRect.left;
1301 WinPos.y = NewWindowRect.top;
1302 WinPos.cx = NewWindowRect.right - NewWindowRect.left;
1303 WinPos.cy = NewWindowRect.bottom - NewWindowRect.top;
1304 co_IntSendMessageNoWait(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
1305 }
1306
1307 if ( WinPos.flags & SWP_FRAMECHANGED || WinPos.flags & SWP_STATECHANGED ||
1308 !(WinPos.flags & SWP_NOCLIENTSIZE) || !(WinPos.flags & SWP_NOCLIENTMOVE) )
1309 {
1310 PWND pWnd = UserGetWindowObject(WinPos.hwnd);
1311 if (pWnd)
1312 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1313 }
1314
1315 if(bPointerInWindow != IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y))
1316 {
1317 /* Generate mouse move message */
1318 MSG msg;
1319 msg.message = WM_MOUSEMOVE;
1320 msg.wParam = IntGetSysCursorInfo()->ButtonsDown;
1321 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
1322 msg.pt = gpsi->ptCursor;
1323 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
1324 }
1325
1326 return TRUE;
1327 }
1328
1329 LRESULT FASTCALL
1330 co_WinPosGetNonClientSize(PWND Window, RECT* WindowRect, RECT* ClientRect)
1331 {
1332 LRESULT Result;
1333
1334 ASSERT_REFS_CO(Window);
1335
1336 *ClientRect = *WindowRect;
1337 Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect);
1338
1339 FixClientRect(ClientRect, WindowRect);
1340
1341 return Result;
1342 }
1343
1344 void FASTCALL
1345 co_WinPosSendSizeMove(PWND Wnd)
1346 {
1347 WPARAM wParam = SIZE_RESTORED;
1348
1349 Wnd->state &= ~WNDS_SENDSIZEMOVEMSGS;
1350 if (Wnd->style & WS_MAXIMIZE)
1351 {
1352 wParam = SIZE_MAXIMIZED;
1353 }
1354 else if (Wnd->style & WS_MINIMIZE)
1355 {
1356 wParam = SIZE_MINIMIZED;
1357 }
1358
1359 co_IntSendMessageNoWait(Wnd->head.h, WM_SIZE, wParam,
1360 MAKELONG(Wnd->rcClient.right -
1361 Wnd->rcClient.left,
1362 Wnd->rcClient.bottom -
1363 Wnd->rcClient.top));
1364 co_IntSendMessageNoWait(Wnd->head.h, WM_MOVE, 0,
1365 MAKELONG(Wnd->rcClient.left,
1366 Wnd->rcClient.top));
1367 IntEngWindowChanged(Wnd, WOC_RGN_CLIENT);
1368 }
1369
1370 BOOLEAN FASTCALL
1371 co_WinPosShowWindow(PWND Wnd, INT Cmd)
1372 {
1373 BOOLEAN WasVisible;
1374 UINT Swp = 0;
1375 RECTL NewPos;
1376 BOOLEAN ShowFlag;
1377 // HRGN VisibleRgn;
1378
1379 ASSERT_REFS_CO(Wnd);
1380
1381 WasVisible = (Wnd->style & WS_VISIBLE) != 0;
1382
1383 switch (Cmd)
1384 {
1385 case SW_HIDE:
1386 {
1387 if (!WasVisible)
1388 {
1389 return(FALSE);
1390 }
1391 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1392 if (Wnd->head.h != UserGetActiveWindow())
1393 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1394 break;
1395 }
1396
1397 case SW_SHOWMINNOACTIVE:
1398 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1399 /* Fall through. */
1400 case SW_SHOWMINIMIZED:
1401 Swp |= SWP_SHOWWINDOW;
1402 /* Fall through. */
1403 case SW_MINIMIZE:
1404 {
1405 Swp |= SWP_NOACTIVATE;
1406 if (!(Wnd->style & WS_MINIMIZE))
1407 {
1408 Swp |= co_WinPosMinMaximize(Wnd, SW_MINIMIZE, &NewPos) |
1409 SWP_FRAMECHANGED;
1410 }
1411 else
1412 {
1413 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1414 if (! WasVisible)
1415 {
1416 Swp |= SWP_FRAMECHANGED;
1417 }
1418 }
1419 break;
1420 }
1421
1422 case SW_SHOWMAXIMIZED:
1423 {
1424 Swp |= SWP_SHOWWINDOW;
1425 if (!(Wnd->style & WS_MAXIMIZE))
1426 {
1427 Swp |= co_WinPosMinMaximize(Wnd, SW_MAXIMIZE, &NewPos) |
1428 SWP_FRAMECHANGED;
1429 }
1430 else
1431 {
1432 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1433 if (! WasVisible)
1434 {
1435 Swp |= SWP_FRAMECHANGED;
1436 }
1437 }
1438 break;
1439 }
1440
1441 case SW_SHOWNA:
1442 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1443 /* Fall through. */
1444 case SW_SHOW:
1445 if (WasVisible) return(TRUE); // Nothing to do!
1446 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1447 /* Don't activate the topmost window. */
1448 break;
1449
1450 case SW_SHOWNOACTIVATE:
1451 //Swp |= SWP_NOZORDER;
1452 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1453 /* Fall through. */
1454 case SW_SHOWNORMAL:
1455 case SW_SHOWDEFAULT:
1456 case SW_RESTORE:
1457 Swp |= SWP_SHOWWINDOW;
1458 if (Wnd->style & (WS_MINIMIZE | WS_MAXIMIZE))
1459 {
1460 Swp |= co_WinPosMinMaximize(Wnd, SW_RESTORE, &NewPos) |
1461 SWP_FRAMECHANGED;
1462 }
1463 else
1464 {
1465 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1466 if (! WasVisible)
1467 {
1468 Swp |= SWP_FRAMECHANGED;
1469 }
1470 }
1471 break;
1472 }
1473
1474 ShowFlag = (Cmd != SW_HIDE);
1475
1476 if (ShowFlag != WasVisible)
1477 {
1478 co_IntSendMessageNoWait(Wnd->head.h, WM_SHOWWINDOW, ShowFlag, 0);
1479 }
1480
1481 /* We can't activate a child window */
1482 if ((Wnd->style & WS_CHILD) &&
1483 !(Wnd->ExStyle & WS_EX_MDICHILD))
1484 {
1485 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1486 }
1487
1488 co_WinPosSetWindowPos(Wnd, 0 != (Wnd->ExStyle & WS_EX_TOPMOST)
1489 ? HWND_TOPMOST : HWND_TOP,
1490 NewPos.left, NewPos.top, NewPos.right, NewPos.bottom, LOWORD(Swp));
1491
1492 if ((Cmd == SW_HIDE) || (Cmd == SW_MINIMIZE))
1493 {
1494 PWND ThreadFocusWindow;
1495
1496 /* FIXME: This will cause the window to be activated irrespective
1497 * of whether it is owned by the same thread. Has to be done
1498 * asynchronously.
1499 */
1500
1501 if (Wnd->head.h == UserGetActiveWindow())
1502 {
1503 co_WinPosActivateOtherWindow(Wnd);
1504 }
1505
1506
1507 //temphack
1508 ThreadFocusWindow = UserGetWindowObject(IntGetThreadFocusWindow());
1509
1510 /* Revert focus to parent */
1511 if (ThreadFocusWindow && (Wnd == ThreadFocusWindow ||
1512 IntIsChildWindow(Wnd, ThreadFocusWindow)))
1513 {
1514 //faxme: as long as we have ref on Window, we also, indirectly, have ref on parent...
1515 co_UserSetFocus(Wnd->spwndParent);
1516 }
1517 }
1518
1519 /* FIXME: Check for window destruction. */
1520
1521 if ((Wnd->state & WNDS_SENDSIZEMOVEMSGS) &&
1522 !(Wnd->state2 & WNDS2_INDESTROY))
1523 {
1524 co_WinPosSendSizeMove(Wnd);
1525 }
1526
1527 /* Activate the window if activation is not requested and the window is not minimized */
1528 /*
1529 if (!(Swp & (SWP_NOACTIVATE | SWP_HIDEWINDOW)) && !(Window->style & WS_MINIMIZE))
1530 {
1531 WinPosChangeActiveWindow(Wnd, FALSE);
1532 }
1533 */
1534 return(WasVisible);
1535 }
1536
1537 static
1538 PWND FASTCALL
1539 co_WinPosSearchChildren(
1540 PWND ScopeWin,
1541 POINT *Point,
1542 USHORT *HitTest
1543 )
1544 {
1545 PWND pwndChild;
1546 HWND *List, *phWnd;
1547
1548 if (!(ScopeWin->style & WS_VISIBLE))
1549 {
1550 return NULL;
1551 }
1552
1553 if ((ScopeWin->style & WS_DISABLED))
1554 {
1555 return NULL;
1556 }
1557
1558 if (!IntPtInWindow(ScopeWin, Point->x, Point->y))
1559 {
1560 return NULL;
1561 }
1562
1563 UserReferenceObject(ScopeWin);
1564
1565 if (Point->x - ScopeWin->rcClient.left < ScopeWin->rcClient.right &&
1566 Point->y - ScopeWin->rcClient.top < ScopeWin->rcClient.bottom )
1567 {
1568 List = IntWinListChildren(ScopeWin);
1569 if(List)
1570 {
1571 for (phWnd = List; *phWnd; ++phWnd)
1572 {
1573 if (!(pwndChild = UserGetWindowObject(*phWnd)))
1574 {
1575 continue;
1576 }
1577
1578 pwndChild = co_WinPosSearchChildren(pwndChild, Point, HitTest);
1579
1580 if(pwndChild != NULL)
1581 {
1582 /* We found a window. Don't send any more WM_NCHITTEST messages */
1583 ExFreePool(List);
1584 UserDereferenceObject(ScopeWin);
1585 return pwndChild;
1586 }
1587 }
1588 ExFreePool(List);
1589 }
1590 }
1591
1592 *HitTest = co_IntSendMessage(ScopeWin->head.h, WM_NCHITTEST, 0,
1593 MAKELONG(Point->x, Point->y));
1594 if ((*HitTest) == (USHORT)HTTRANSPARENT)
1595 {
1596 UserDereferenceObject(ScopeWin);
1597 return NULL;
1598 }
1599
1600 return ScopeWin;
1601 }
1602
1603 PWND FASTCALL
1604 co_WinPosWindowFromPoint(PWND ScopeWin, POINT *WinPoint, USHORT* HitTest)
1605 {
1606 PWND Window;
1607 POINT Point = *WinPoint;
1608 USER_REFERENCE_ENTRY Ref;
1609
1610 if( ScopeWin == NULL )
1611 {
1612 ScopeWin = UserGetDesktopWindow();
1613 if(ScopeWin == NULL)
1614 return NULL;
1615 }
1616
1617 *HitTest = HTNOWHERE;
1618
1619 ASSERT_REFS_CO(ScopeWin);
1620 UserRefObjectCo(ScopeWin, &Ref);
1621
1622 Window = co_WinPosSearchChildren(ScopeWin, &Point, HitTest);
1623
1624 UserDerefObjectCo(ScopeWin);
1625 if(Window)
1626 ASSERT_REFS_CO(Window);
1627 ASSERT_REFS_CO(ScopeWin);
1628
1629 return Window;
1630 }
1631
1632 HDWP
1633 FASTCALL
1634 IntDeferWindowPos( HDWP hdwp,
1635 HWND hwnd,
1636 HWND hwndAfter,
1637 INT x,
1638 INT y,
1639 INT cx,
1640 INT cy,
1641 UINT flags )
1642 {
1643 PSMWP pDWP;
1644 int i;
1645 HDWP retvalue = hdwp;
1646
1647 TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
1648 hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
1649
1650 if (flags & ~(SWP_NOSIZE | SWP_NOMOVE |
1651 SWP_NOZORDER | SWP_NOREDRAW |
1652 SWP_NOACTIVATE | SWP_NOCOPYBITS |
1653 SWP_NOOWNERZORDER|SWP_SHOWWINDOW |
1654 SWP_HIDEWINDOW | SWP_FRAMECHANGED))
1655 {
1656 EngSetLastError(ERROR_INVALID_PARAMETER);
1657 return NULL;
1658 }
1659
1660 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, otSMWP)))
1661 {
1662 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
1663 return NULL;
1664 }
1665
1666 for (i = 0; i < pDWP->ccvr; i++)
1667 {
1668 if (pDWP->acvr[i].pos.hwnd == hwnd)
1669 {
1670 /* Merge with the other changes */
1671 if (!(flags & SWP_NOZORDER))
1672 {
1673 pDWP->acvr[i].pos.hwndInsertAfter = hwndAfter;
1674 }
1675 if (!(flags & SWP_NOMOVE))
1676 {
1677 pDWP->acvr[i].pos.x = x;
1678 pDWP->acvr[i].pos.y = y;
1679 }
1680 if (!(flags & SWP_NOSIZE))
1681 {
1682 pDWP->acvr[i].pos.cx = cx;
1683 pDWP->acvr[i].pos.cy = cy;
1684 }
1685 pDWP->acvr[i].pos.flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
1686 SWP_NOZORDER | SWP_NOREDRAW |
1687 SWP_NOACTIVATE | SWP_NOCOPYBITS|
1688 SWP_NOOWNERZORDER);
1689 pDWP->acvr[i].pos.flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
1690 SWP_FRAMECHANGED);
1691 goto END;
1692 }
1693 }
1694 if (pDWP->ccvr >= pDWP->ccvrAlloc)
1695 {
1696 PCVR newpos = ExAllocatePoolWithTag(PagedPool, pDWP->ccvrAlloc * 2 * sizeof(CVR), USERTAG_SWP);
1697 if (!newpos)
1698 {
1699 retvalue = NULL;
1700 goto END;
1701 }
1702 RtlZeroMemory(newpos, pDWP->ccvrAlloc * 2 * sizeof(CVR));
1703 RtlCopyMemory(newpos, pDWP->acvr, pDWP->ccvrAlloc * sizeof(CVR));
1704 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
1705 pDWP->ccvrAlloc *= 2;
1706 pDWP->acvr = newpos;
1707 }
1708 pDWP->acvr[pDWP->ccvr].pos.hwnd = hwnd;
1709 pDWP->acvr[pDWP->ccvr].pos.hwndInsertAfter = hwndAfter;
1710 pDWP->acvr[pDWP->ccvr].pos.x = x;
1711 pDWP->acvr[pDWP->ccvr].pos.y = y;
1712 pDWP->acvr[pDWP->ccvr].pos.cx = cx;
1713 pDWP->acvr[pDWP->ccvr].pos.cy = cy;
1714 pDWP->acvr[pDWP->ccvr].pos.flags = flags;
1715 pDWP->acvr[pDWP->ccvr].hrgnClip = NULL;
1716 pDWP->acvr[pDWP->ccvr].hrgnInterMonitor = NULL;
1717 pDWP->ccvr++;
1718 END:
1719 return retvalue;
1720 }
1721
1722 BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp )
1723 {
1724 PSMWP pDWP;
1725 PCVR winpos;
1726 BOOL res = TRUE;
1727 int i;
1728
1729 TRACE("%p\n", hdwp);
1730
1731 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, otSMWP)))
1732 {
1733 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
1734 return FALSE;
1735 }
1736
1737 for (i = 0, winpos = pDWP->acvr; res && i < pDWP->ccvr; i++, winpos++)
1738 {
1739 PWND pwnd;
1740 USER_REFERENCE_ENTRY Ref;
1741
1742 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
1743 winpos->pos.hwnd, winpos->pos.hwndInsertAfter, winpos->pos.x, winpos->pos.y,
1744 winpos->pos.cx, winpos->pos.cy, winpos->pos.flags);
1745
1746 pwnd = UserGetWindowObject(winpos->pos.hwnd);
1747 if(!pwnd)
1748 continue;
1749
1750 UserRefObjectCo(pwnd, &Ref);
1751
1752 res = co_WinPosSetWindowPos( pwnd,
1753 winpos->pos.hwndInsertAfter,
1754 winpos->pos.x,
1755 winpos->pos.y,
1756 winpos->pos.cx,
1757 winpos->pos.cy,
1758 winpos->pos.flags);
1759
1760 UserDerefObjectCo(pwnd);
1761 }
1762 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
1763 UserDereferenceObject(pDWP);
1764 UserDeleteObject(hdwp, otSMWP);
1765 return res;
1766 }
1767
1768 /*
1769 * @implemented
1770 */
1771 HWND APIENTRY
1772 NtUserChildWindowFromPointEx(HWND hwndParent,
1773 LONG x,
1774 LONG y,
1775 UINT uiFlags)
1776 {
1777 PWND Parent;
1778 POINTL Pt;
1779 HWND Ret;
1780 HWND *List, *phWnd;
1781
1782 if(!(Parent = UserGetWindowObject(hwndParent)))
1783 {
1784 return NULL;
1785 }
1786
1787 Pt.x = x;
1788 Pt.y = y;
1789
1790 if(Parent->head.h != IntGetDesktopWindow())
1791 {
1792 Pt.x += Parent->rcClient.left;
1793 Pt.y += Parent->rcClient.top;
1794 }
1795
1796 if(!IntPtInWindow(Parent, Pt.x, Pt.y))
1797 {
1798 return NULL;
1799 }
1800
1801 Ret = Parent->head.h;
1802 if((List = IntWinListChildren(Parent)))
1803 {
1804 for(phWnd = List; *phWnd; phWnd++)
1805 {
1806 PWND Child;
1807 if((Child = UserGetWindowObject(*phWnd)))
1808 {
1809 if(!(Child->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE))
1810 {
1811 continue;
1812 }
1813 if((Child->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED))
1814 {
1815 continue;
1816 }
1817 if((Child->ExStyle & WS_EX_TRANSPARENT) && (uiFlags & CWP_SKIPTRANSPARENT))
1818 {
1819 continue;
1820 }
1821 if(IntPtInWindow(Child, Pt.x, Pt.y))
1822 {
1823 Ret = Child->head.h;
1824 break;
1825 }
1826 }
1827 }
1828 ExFreePool(List);
1829 }
1830
1831 return Ret;
1832 }
1833
1834 /*
1835 * @implemented
1836 */
1837 BOOL APIENTRY
1838 NtUserEndDeferWindowPosEx(HDWP WinPosInfo,
1839 DWORD Unknown1)
1840 {
1841 BOOL Ret;
1842 TRACE("Enter NtUserEndDeferWindowPosEx\n");
1843 UserEnterExclusive();
1844 Ret = IntEndDeferWindowPosEx(WinPosInfo);
1845 TRACE("Leave NtUserEndDeferWindowPosEx, ret=%i\n", Ret);
1846 UserLeave();
1847 return Ret;
1848 }
1849
1850 /*
1851 * @implemented
1852 */
1853 HDWP APIENTRY
1854 NtUserDeferWindowPos(HDWP WinPosInfo,
1855 HWND Wnd,
1856 HWND WndInsertAfter,
1857 int x,
1858 int y,
1859 int cx,
1860 int cy,
1861 UINT Flags)
1862 {
1863 PWND pWnd, pWndIA;
1864 HDWP Ret = NULL;
1865 UINT Tmp = ~(SWP_ASYNCWINDOWPOS|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_NOREPOSITION|
1866 SWP_NOCOPYBITS|SWP_HIDEWINDOW|SWP_SHOWWINDOW|SWP_FRAMECHANGED|
1867 SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE);
1868
1869 TRACE("Enter NtUserDeferWindowPos\n");
1870 UserEnterExclusive();
1871
1872 if ( Flags & Tmp )
1873 {
1874 EngSetLastError(ERROR_INVALID_FLAGS);
1875 goto Exit;
1876 }
1877
1878 pWnd = UserGetWindowObject(Wnd);
1879 if ( !pWnd || // FIXME:
1880 pWnd == IntGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
1881 pWnd == IntGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
1882 {
1883 goto Exit;
1884 }
1885
1886 if ( WndInsertAfter &&
1887 WndInsertAfter != HWND_BOTTOM &&
1888 WndInsertAfter != HWND_TOPMOST &&
1889 WndInsertAfter != HWND_NOTOPMOST )
1890 {
1891 pWndIA = UserGetWindowObject(WndInsertAfter);
1892 if ( !pWndIA ||
1893 pWndIA == IntGetDesktopWindow() ||
1894 pWndIA == IntGetMessageWindow() )
1895 {
1896 goto Exit;
1897 }
1898 }
1899
1900 Ret = IntDeferWindowPos(WinPosInfo, Wnd, WndInsertAfter, x, y, cx, cy, Flags);
1901
1902 Exit:
1903 TRACE("Leave NtUserDeferWindowPos, ret=%i\n", Ret);
1904 UserLeave();
1905 return Ret;
1906 }
1907
1908 DWORD
1909 APIENTRY
1910 NtUserMinMaximize(
1911 HWND hWnd,
1912 UINT cmd, // Wine SW_ commands
1913 BOOL Hide)
1914 {
1915 RECTL NewPos;
1916 UINT SwFlags;
1917 PWND pWnd;
1918
1919 TRACE("Enter NtUserMinMaximize\n");
1920 UserEnterExclusive();
1921
1922 pWnd = UserGetWindowObject(hWnd);
1923 if ( !pWnd || // FIXME:
1924 pWnd == IntGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
1925 pWnd == IntGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
1926 {
1927 goto Exit;
1928 }
1929
1930 if ( cmd > SW_MAX || pWnd->state2 & WNDS2_INDESTROY)
1931 {
1932 EngSetLastError(ERROR_INVALID_PARAMETER);
1933 goto Exit;
1934 }
1935
1936 co_WinPosMinMaximize(pWnd, cmd, &NewPos);
1937
1938 SwFlags = Hide ? SWP_NOACTIVATE|SWP_NOZORDER|SWP_FRAMECHANGED : SWP_NOZORDER|SWP_FRAMECHANGED;
1939
1940 co_WinPosSetWindowPos( pWnd,
1941 NULL,
1942 NewPos.left,
1943 NewPos.top,
1944 NewPos.right,
1945 NewPos.bottom,
1946 SwFlags);
1947
1948 co_WinPosShowWindow(pWnd, cmd);
1949
1950 Exit:
1951 TRACE("Leave NtUserMinMaximize\n");
1952 UserLeave();
1953 return 0; // Always NULL?
1954 }
1955
1956 /*
1957 * @implemented
1958 */
1959 BOOL APIENTRY
1960 NtUserMoveWindow(
1961 HWND hWnd,
1962 int X,
1963 int Y,
1964 int nWidth,
1965 int nHeight,
1966 BOOL bRepaint)
1967 {
1968 return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight,
1969 (bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE :
1970 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW));
1971 }
1972
1973 /*
1974 * @implemented
1975 */
1976 BOOL APIENTRY
1977 NtUserSetWindowPos(
1978 HWND hWnd,
1979 HWND hWndInsertAfter,
1980 int X,
1981 int Y,
1982 int cx,
1983 int cy,
1984 UINT uFlags)
1985 {
1986 DECLARE_RETURN(BOOL);
1987 PWND Window, pWndIA;
1988 BOOL ret;
1989 USER_REFERENCE_ENTRY Ref;
1990
1991 TRACE("Enter NtUserSetWindowPos\n");
1992 UserEnterExclusive();
1993
1994 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
1995 Window == IntGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
1996 Window == IntGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
1997 {
1998 RETURN(FALSE);
1999 }
2000
2001 if ( hWndInsertAfter &&
2002 hWndInsertAfter != HWND_BOTTOM &&
2003 hWndInsertAfter != HWND_TOPMOST &&
2004 hWndInsertAfter != HWND_NOTOPMOST )
2005 {
2006 pWndIA = UserGetWindowObject(hWndInsertAfter);
2007 if ( !pWndIA ||
2008 pWndIA == IntGetDesktopWindow() ||
2009 pWndIA == IntGetMessageWindow() )
2010 {
2011 RETURN(FALSE);
2012 }
2013 }
2014
2015 /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
2016 if (!(uFlags & SWP_NOMOVE))
2017 {
2018 if (X < -32768) X = -32768;
2019 else if (X > 32767) X = 32767;
2020 if (Y < -32768) Y = -32768;
2021 else if (Y > 32767) Y = 32767;
2022 }
2023 if (!(uFlags & SWP_NOSIZE))
2024 {
2025 if (cx < 0) cx = 0;
2026 else if (cx > 32767) cx = 32767;
2027 if (cy < 0) cy = 0;
2028 else if (cy > 32767) cy = 32767;
2029 }
2030
2031 UserRefObjectCo(Window, &Ref);
2032 ret = co_WinPosSetWindowPos(Window, hWndInsertAfter, X, Y, cx, cy, uFlags);
2033 UserDerefObjectCo(Window);
2034
2035 RETURN(ret);
2036
2037 CLEANUP:
2038 TRACE("Leave NtUserSetWindowPos, ret=%i\n",_ret_);
2039 UserLeave();
2040 END_CLEANUP;
2041 }
2042
2043 /*
2044 * @implemented
2045 */
2046 INT APIENTRY
2047 NtUserSetWindowRgn(
2048 HWND hWnd,
2049 HRGN hRgn,
2050 BOOL bRedraw)
2051 {
2052 HRGN hrgnCopy;
2053 PWND Window;
2054 INT flags = (SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE);
2055 BOOLEAN Ret = FALSE;
2056 DECLARE_RETURN(INT);
2057
2058 TRACE("Enter NtUserSetWindowRgn\n");
2059 UserEnterExclusive();
2060
2061 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
2062 Window == IntGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2063 Window == IntGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2064 {
2065 RETURN( 0);
2066 }
2067
2068 if (hRgn) // The region will be deleted in user32.
2069 {
2070 if (GreIsHandleValid(hRgn))
2071 {
2072 hrgnCopy = IntSysCreateRectRgn(0, 0, 0, 0);
2073
2074 NtGdiCombineRgn(hrgnCopy, hRgn, 0, RGN_COPY);
2075 }
2076 else
2077 RETURN( 0);
2078 }
2079 else
2080 {
2081 hrgnCopy = NULL;
2082 }
2083
2084 /* Delete the region passed by the caller */
2085 GreDeleteObject(hRgn);
2086
2087 if (Window->hrgnClip)
2088 {
2089 /* Delete no longer needed region handle */
2090 IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED);
2091 GreDeleteObject(Window->hrgnClip);
2092 }
2093
2094 if (hrgnCopy)
2095 {
2096 /* Set public ownership */
2097 IntGdiSetRegionOwner(hrgnCopy, GDI_OBJ_HMGR_PUBLIC);
2098 }
2099 Window->hrgnClip = hrgnCopy;
2100
2101 Ret = co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, bRedraw ? flags : (flags|SWP_NOREDRAW) );
2102
2103 RETURN( (INT)Ret);
2104
2105 CLEANUP:
2106 TRACE("Leave NtUserSetWindowRgn, ret=%i\n",_ret_);
2107 UserLeave();
2108 END_CLEANUP;
2109 }
2110
2111 /*
2112 * @implemented
2113 */
2114 BOOL APIENTRY
2115 NtUserSetWindowPlacement(HWND hWnd,
2116 WINDOWPLACEMENT *lpwndpl)
2117 {
2118 PWND Wnd;
2119 WINDOWPLACEMENT Safepl;
2120 DECLARE_RETURN(BOOL);
2121 USER_REFERENCE_ENTRY Ref;
2122
2123 TRACE("Enter NtUserSetWindowPlacement\n");
2124 UserEnterExclusive();
2125
2126 if (!(Wnd = UserGetWindowObject(hWnd)) || // FIXME:
2127 Wnd == IntGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2128 Wnd == IntGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2129 {
2130 RETURN( FALSE);
2131 }
2132
2133 _SEH2_TRY
2134 {
2135 ProbeForRead(lpwndpl, sizeof(WINDOWPLACEMENT), 1);
2136 RtlCopyMemory(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
2137 }
2138 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2139 {
2140 SetLastNtError(_SEH2_GetExceptionCode());
2141 _SEH2_YIELD(RETURN( FALSE));
2142 }
2143 _SEH2_END
2144
2145 if(Safepl.length != sizeof(WINDOWPLACEMENT))
2146 {
2147 RETURN( FALSE);
2148 }
2149
2150 UserRefObjectCo(Wnd, &Ref);
2151
2152 if ((Wnd->style & (WS_MAXIMIZE | WS_MINIMIZE)) == 0)
2153 {
2154 co_WinPosSetWindowPos(Wnd, NULL,
2155 Safepl.rcNormalPosition.left, Safepl.rcNormalPosition.top,
2156 Safepl.rcNormalPosition.right - Safepl.rcNormalPosition.left,
2157 Safepl.rcNormalPosition.bottom - Safepl.rcNormalPosition.top,
2158 SWP_NOZORDER | SWP_NOACTIVATE);
2159 }
2160
2161 /* FIXME - change window status */
2162 co_WinPosShowWindow(Wnd, Safepl.showCmd);
2163
2164 Wnd->InternalPosInitialized = TRUE;
2165 Wnd->InternalPos.NormalRect = Safepl.rcNormalPosition;
2166 Wnd->InternalPos.IconPos = Safepl.ptMinPosition;
2167 Wnd->InternalPos.MaxPos = Safepl.ptMaxPosition;
2168
2169 UserDerefObjectCo(Wnd);
2170 RETURN(TRUE);
2171
2172 CLEANUP:
2173 TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
2174 UserLeave();
2175 END_CLEANUP;
2176 }
2177
2178 /*
2179 * @unimplemented
2180 */
2181 BOOL APIENTRY
2182 NtUserShowWindowAsync(HWND hWnd, LONG nCmdShow)
2183 {
2184 #if 0
2185 STUB
2186 return 0;
2187 #else
2188 return NtUserShowWindow(hWnd, nCmdShow);
2189 #endif
2190 }
2191
2192 /*
2193 * @implemented
2194 */
2195 BOOL APIENTRY
2196 NtUserShowWindow(HWND hWnd, LONG nCmdShow)
2197 {
2198 PWND Window;
2199 BOOL ret;
2200 DECLARE_RETURN(BOOL);
2201 USER_REFERENCE_ENTRY Ref;
2202
2203 TRACE("Enter NtUserShowWindow\n");
2204 UserEnterExclusive();
2205
2206 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
2207 Window == IntGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2208 Window == IntGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2209 {
2210 RETURN(FALSE);
2211 }
2212
2213 if ( nCmdShow > SW_MAX || Window->state2 & WNDS2_INDESTROY)
2214 {
2215 EngSetLastError(ERROR_INVALID_PARAMETER);
2216 RETURN(FALSE);
2217 }
2218
2219 UserRefObjectCo(Window, &Ref);
2220 ret = co_WinPosShowWindow(Window, nCmdShow);
2221 UserDerefObjectCo(Window);
2222
2223 RETURN(ret);
2224
2225 CLEANUP:
2226 TRACE("Leave NtUserShowWindow, ret=%i\n",_ret_);
2227 UserLeave();
2228 END_CLEANUP;
2229 }
2230
2231 //// Ugly NtUser API ////
2232 BOOL
2233 APIENTRY
2234 NtUserGetMinMaxInfo(
2235 HWND hWnd,
2236 MINMAXINFO *MinMaxInfo,
2237 BOOL SendMessage)
2238 {
2239 POINT Size;
2240 PWND Window = NULL;
2241 MINMAXINFO SafeMinMax;
2242 NTSTATUS Status;
2243 BOOL ret;
2244 USER_REFERENCE_ENTRY Ref;
2245
2246 TRACE("Enter NtUserGetMinMaxInfo\n");
2247 UserEnterExclusive();
2248
2249 if(!(Window = UserGetWindowObject(hWnd)))
2250 {
2251 ret = FALSE;
2252 goto cleanup;
2253 }
2254
2255 UserRefObjectCo(Window, &Ref);
2256
2257 Size.x = Window->rcWindow.left;
2258 Size.y = Window->rcWindow.top;
2259 WinPosInitInternalPos(Window, &Size,
2260 &Window->rcWindow);
2261
2262 co_WinPosGetMinMaxInfo(Window, &SafeMinMax.ptMaxSize, &SafeMinMax.ptMaxPosition,
2263 &SafeMinMax.ptMinTrackSize, &SafeMinMax.ptMaxTrackSize);
2264
2265 Status = MmCopyToCaller(MinMaxInfo, &SafeMinMax, sizeof(MINMAXINFO));
2266 if(!NT_SUCCESS(Status))
2267 {
2268 SetLastNtError(Status);
2269 ret = FALSE;
2270 goto cleanup;
2271 }
2272
2273 ret = TRUE;
2274
2275 cleanup:
2276 if (Window) UserDerefObjectCo(Window);
2277
2278 TRACE("Leave NtUserGetMinMaxInfo, ret=%i\n", ret);
2279 UserLeave();
2280 return ret;
2281 }
2282
2283 /* EOF */